Spaces:
Sleeping
Sleeping
import json | |
import os | |
import re | |
import copy | |
import pandas as pd | |
## 半衰期单位转换字典 | |
HL_UNITS = {"fs": 1e-15, "ps": 1e-12, "ns": 1e-9, "us": 1e-6, "ms": 1e-3, "s": 1, "m": 60, "h": 3600, "d": 86400, "y": 31557600, "ky": 31557600e3, "My": 31557600e6, "Gy": 31557600e9} | |
nuclides_data_path = "data/nndc_nudat_data_export.json" | |
def nuclidesFilterZNA(nuclides_data, Z_min=None, Z_max=None, Z_oe_idx=0, N_min=None, N_max=None, N_oe_idx=0, A_min=None, A_max=None, A_oe_idx=0): | |
filtered = {} | |
for name, data in nuclides_data.items(): | |
fh = True | |
if not (Z_min is None or data['z'] >= Z_min): | |
fh = False | |
if not (Z_max is None or data['z'] <= Z_max): | |
fh = False | |
if not (N_min is None or data['n'] >= N_min): | |
fh = False | |
if not (N_max is None or data['n'] <= N_max): | |
fh = False | |
if not (A_min is None or data['a'] >= A_min): | |
fh = False | |
if not (A_max is None or data['a'] <= A_max): | |
fh = False | |
if Z_oe_idx == 1: | |
if data['z'] % 2 == 0: | |
fh = False | |
elif Z_oe_idx == 2: | |
if data['z'] % 2 == 1: | |
fh = False | |
if N_oe_idx == 1: | |
if data['n'] % 2 == 0: | |
fh = False | |
elif N_oe_idx == 2: | |
if data['n'] % 2 == 1: | |
fh = False | |
if A_oe_idx == 1: | |
if data['a'] % 2 == 0: | |
fh = False | |
elif A_oe_idx == 2: | |
if data['a'] % 2 == 1: | |
fh = False | |
if fh: | |
filtered[name] = data | |
return filtered | |
def nuclidesFilterHalflife(nuclides_data, hl_min_sec=0, hl_max_sec=None): | |
filtered = {} | |
if hl_min_sec == None: | |
if hl_max_sec == None: | |
for name, data in nuclides_data.items(): | |
if "levels" in data: | |
for level in data["levels"]: | |
if "halflife" in level: | |
if level["halflife"]["value"] == "STABLE": | |
filtered[name] = data | |
break | |
else: | |
if hl_max_sec == None: | |
for name, data in nuclides_data.items(): | |
if "levels" in data: | |
for level in data["levels"]: | |
if "halflife" in level: | |
if level["halflife"]["value"] == "STABLE": | |
filtered[name] = data | |
break | |
else: | |
if not level["halflife"]["unit"] in HL_UNITS: | |
break | |
hl_sec = level["halflife"]["value"] * HL_UNITS[level["halflife"]["unit"]] | |
if hl_sec > hl_min_sec: | |
filtered[name] = data | |
break | |
else: | |
for name, data in nuclides_data.items(): | |
if "levels" in data: | |
for level in data["levels"]: | |
if "halflife" in level: | |
if level["halflife"]["value"] == "STABLE": | |
pass | |
else: | |
if not level["halflife"]["unit"] in HL_UNITS: | |
break | |
hl_sec = level["halflife"]["value"] * HL_UNITS[level["halflife"]["unit"]] | |
if hl_sec > hl_min_sec and hl_sec < hl_max_sec: | |
filtered[name] = data | |
break | |
return filtered | |
def nuclidesFilterDecayModes(nuclides_data, dm_enable_idx, decay_modes): | |
filtered = {} | |
nuclides_decayModes = {} | |
for name, data in nuclides_data.items(): | |
decayModes = [] | |
if "levels" in data: | |
for level in data["levels"]: | |
if "decayModes" in level: | |
for decayData in level["decayModes"]["observed"]: | |
if not decayData["mode"] in decayModes: | |
decayModes.append(decayData["mode"]) | |
nuclides_decayModes[name] = copy.deepcopy(decayModes) | |
decay_modes_series = pd.Series(decay_modes) | |
## nndc导出的数据里有两处写作"β⁻"了 | |
replace_dict = {"β⁻": "B-"} | |
for name, decayModes in nuclides_decayModes.items(): | |
nuclide_decayModes_series = pd.Series(decayModes) | |
nuclide_decayModes_series = nuclide_decayModes_series.replace(replace_dict) | |
if dm_enable_idx == 1: | |
if decay_modes_series.isin(nuclide_decayModes_series).all(): | |
filtered[name] = nuclides_data[name] | |
elif dm_enable_idx == 2: | |
if decay_modes_series.isin(nuclide_decayModes_series).any(): | |
filtered[name] = nuclides_data[name] | |
return filtered | |
def nuclidesSearchingNom(nuclides_data, nuclide_nom): | |
nuclide = None | |
element = None | |
nuclide_A = None | |
if not re.fullmatch(rf"([A-Za-z]+)([-_|]*)([0-9]+)", nuclide_nom) == None: | |
match00 = re.fullmatch(rf"([A-Za-z]+)([-_|]*)([0-9]+)", nuclide_nom) | |
element = match00.group(1) | |
nuclide_A = match00.group(3) | |
elif not re.fullmatch(rf"([0-9]+)([-_|]*)([A-Za-z]+)", nuclide_nom) == None: | |
match00 = re.fullmatch(rf"([0-9]+)([-_|]*)([A-Za-z]+)", nuclide_nom) | |
element = match00.group(3) | |
nuclide_A = match00.group(1) | |
if not (element == None or nuclide_A == None): | |
if not element in ("n", "N"): | |
if len(element) == 1: | |
element = element.upper() | |
else: | |
element = element[:1].upper() + element[1:].lower() | |
while nuclide_A.startswith("0"): | |
nuclide_A = nuclide_A[1:] | |
nom = nuclide_A + element | |
if nom in nuclides_data: | |
nuclide = nuclides_data[nom] | |
return nuclide | |
def nuclidesSearchingZN(nuclides_data, Z_in=0, N_in=0): | |
nuclide = None | |
for nom, data in nuclides_data.items(): | |
if data["z"] == Z_in and data["n"] == N_in: | |
nuclide = data | |
break | |
return nuclide | |
def nuclidesSearchingZA(nuclides_data, Z_in=0, A_in=0): | |
nuclide = None | |
for nom, data in nuclides_data.items(): | |
if data["z"] == Z_in and data["a"] == A_in: | |
nuclide = data | |
break | |
return nuclide | |
def nuclidesSearchingNA(nuclides_data, N_in=0, A_in=0): | |
nuclide = None | |
for nom, data in nuclides_data.items(): | |
if data["n"] == N_in and data["a"] == A_in: | |
nuclide = data | |
break | |
return nuclide | |
def nuclideData_dict2dataframe(nuclideData_dict): | |
nom = nuclideData_dict["name"] | |
z = nuclideData_dict["z"] | |
n = nuclideData_dict["n"] | |
a = nuclideData_dict["a"] | |
data = [] | |
for level in nuclideData_dict["levels"]: | |
## 自旋宇称 | |
spinParity = None | |
if "spinParity" in level: | |
spinParity = level["spinParity"] | |
## 质量过剩 | |
massExcess = None | |
massExcess_unit = None | |
massExcess_unc = None | |
if not "massExcess" in level: | |
pass | |
else: | |
massExcess = level["massExcess"]["unit"] | |
massExcess_unit = level["massExcess"]["value"] | |
massExcess_unc = level["massExcess"]["uncertainty"] | |
## 半衰期 | |
hl = None | |
hl_unit = None | |
hl_unc = None | |
if not "halflife" in level: | |
pass | |
elif level["halflife"]["value"] == "STABLE": | |
pass | |
else: | |
hl = level["halflife"]["value"] | |
hl_unit = level["halflife"]["unit"] | |
if level["halflife"]["uncertainty"]["type"] == "asymmetric": | |
hl_unc = "+" + str(level["halflife"]["uncertainty"]["upperLimit"]) + " -" + str(level["halflife"]["uncertainty"]["lowerLimit"]) | |
elif level["halflife"]["uncertainty"]["type"] == "approximation": | |
hl_unc = "≈" | |
elif level["halflife"]["uncertainty"]["type"] == "limit": | |
if level["halflife"]["uncertainty"]["limitType"] == "lower": | |
if level["halflife"]["uncertainty"]["isInclusive"] == True: | |
hl_unc = "≥" | |
else: | |
hl_unc = ">" | |
elif level["halflife"]["uncertainty"]["limitType"] == "upper": | |
if level["halflife"]["uncertainty"]["isInclusive"] == True: | |
hl_unc = "≤" | |
else: | |
hl_unc = "<" | |
else: | |
hl_unc = level["halflife"]["uncertainty"]["value"] | |
## 衰变模式 | |
if not "decayModes" in level: | |
data.append((nom, z, n, a, level["energy"]["value"], level["energy"]["unit"], spinParity, massExcess, massExcess_unit, massExcess_unc, hl, hl_unit, hl_unc, None, None)) | |
elif len(level["decayModes"]["observed"]) == 0: | |
data.append((nom, z, n, a, level["energy"]["value"], level["energy"]["unit"], spinParity, massExcess, massExcess_unit, massExcess_unc, hl, hl_unit, hl_unc, None, None)) | |
else: | |
for decayMode in level["decayModes"]["observed"]: | |
data.append((nom, z, n, a, level["energy"]["value"], level["energy"]["unit"], spinParity, massExcess, massExcess_unit, massExcess_unc, hl, hl_unit, hl_unc, decayMode["mode"], decayMode["value"])) | |
nuclideDataframe = pd.DataFrame(data, columns=["Nuclide", "Z", "N", "A", "E(level)", "E(level) unit", "Spin Parity", "Mass Excess", "Mass Excess unit", "Mass Excess uncertainty", "Halflife", "Halflife unit", "Halflife uncertainty", "Decay Mode", "Branch Ratio"]) | |
return nuclideDataframe | |
def nuclideData_dict2dataframeCompact(nuclideData_dict): | |
data = [] | |
for level in nuclideData_dict["levels"]: | |
## 自旋宇称 | |
spinParity = None | |
if "spinParity" in level: | |
spinParity = level["spinParity"] | |
## 质量过剩 | |
massExcess = None | |
if not "massExcess" in level: | |
pass | |
else: | |
massExcess = level["massExcess"]["formats"]["NDS"]+" "+level["massExcess"]["unit"] | |
## 半衰期 | |
hl = None | |
if not "halflife" in level: | |
pass | |
elif level["halflife"]["value"] == "STABLE": | |
hl = "STABLE" | |
else: | |
hl = level["halflife"]["formats"]["NDS"]+" "+level["halflife"]["unit"] | |
## 衰变模式 | |
if not "decayModes" in level: | |
data.append((str(level["energy"]["value"])+" "+level["energy"]["unit"], spinParity, massExcess, hl, None)) | |
elif len(level["decayModes"]["observed"]) == 0: | |
data.append((str(level["energy"]["value"])+" "+level["energy"]["unit"], spinParity, massExcess, hl, None)) | |
else: | |
decayModes = [] | |
for decayMode in level["decayModes"]["observed"]: | |
decayModes.append((decayMode["mode"], decayMode["value"])) | |
decayModeDF = pd.DataFrame(decayModes, columns=["Decay Mode", "Branch Ratio"]) | |
data.append((str(level["energy"]["value"])+" "+level["energy"]["unit"], spinParity, massExcess, hl, decayModeDF)) | |
nuclideDataframe = pd.DataFrame(data, columns=["E(level)", "Spin Parity", "Mass Excess", "Halflife", "Decay Modes"]) | |
return nuclideDataframe | |
def nuclidesClassifyHalflife(data_path): | |
with open (data_path,'r', encoding='utf-8') as file: | |
nuclides_data = json.load(file) | |
classified = [] | |
for nom, data in nuclides_data.items(): | |
z = data["z"] | |
n = data["n"] | |
hl_type = "UN" | |
if len(data["levels"]) == 0: | |
hl_type = "UN" | |
elif not "halflife" in data["levels"][0]: | |
hl_type = "UN" | |
elif data["levels"][0]["halflife"]["value"] == "STABLE": | |
hl_type = "ST" | |
elif not data["levels"][0]["halflife"]["unit"] in HL_UNITS: | |
hl_type = "SU" | |
else: | |
hl_sec = data["levels"][0]["halflife"]["value"] * HL_UNITS[data["levels"][0]["halflife"]["unit"]] | |
if hl_sec < 1e-7: | |
hl_type = "l100ns" | |
elif hl_sec < 1e-6: | |
hl_type = "100ns" | |
elif hl_sec < 1e-5: | |
hl_type = "1us" | |
elif hl_sec < 1e-4: | |
hl_type = "10us" | |
elif hl_sec < 1e-3: | |
hl_type = "100us" | |
elif hl_sec < 1e-2: | |
hl_type = "1ms" | |
elif hl_sec < 1e-1: | |
hl_type = "10ms" | |
elif hl_sec < 1: | |
hl_type = "100ms" | |
elif hl_sec < 10: | |
hl_type = "1s" | |
elif hl_sec < 100: | |
hl_type = "10s" | |
elif hl_sec < 1e3: | |
hl_type = "100s" | |
elif hl_sec < 1e4: | |
hl_type = "1ks" | |
elif hl_sec < 1e5: | |
hl_type = "10ks" | |
elif hl_sec < 1e7: | |
hl_type = "100ks" | |
elif hl_sec < 1e10: | |
hl_type = "10Ms" | |
elif hl_sec < 1e15: | |
hl_type = "1e10s" | |
else: | |
hl_type = "1e15s" | |
classified.append({"z":z, "n":n, "type":hl_type}) | |
return classified | |
def nuclidesClassifyDecayMode(data_path): | |
with open (data_path,'r', encoding='utf-8') as file: | |
nuclides_data = json.load(file) | |
classified = [] | |
for nom, data in nuclides_data.items(): | |
z = data["z"] | |
n = data["n"] | |
dm_type = "UNKNOWN" | |
if len(data["levels"]) == 0: | |
dm_type = "UNKNOWN" | |
elif not "decayModes" in data["levels"][0]: | |
dm_type = "UNKNOWN" | |
if "halflife" in data["levels"][0]: | |
if data["levels"][0]["halflife"]["value"] == "STABLE": | |
dm_type = "STABLE" | |
else: | |
decay_modes = data["levels"][0]["decayModes"]["observed"] + data["levels"][0]["decayModes"]["predicted"] | |
if len(decay_modes) == 0: | |
dm_type = "UNKNOWN" | |
else: | |
## 据分支比排序 | |
dms1 = [] | |
dms2 = [] | |
dmsd = {} | |
dmsd1 = [] | |
for decay_mode in decay_modes: | |
if not "value" in decay_mode: | |
dms2.append(decay_mode) | |
else: | |
dmsd[decay_mode["mode"]] = decay_mode | |
dmsd1.append((decay_mode["value"], decay_mode["mode"])) | |
dmsdf = pd.DataFrame(dmsd1, columns=["value", "mode"]) | |
dmsdf.sort_values(by="value", ascending=False, inplace=True) | |
for mode in dmsdf["mode"]: | |
dms1.append(dmsd[mode]) | |
dms = dms1 + dms2 | |
dm_type = dms[0]["mode"] | |
classified.append({"z":z, "n":n, "type":dm_type}) | |
return classified | |
##test | |