Source code for ndlaborm

"""
Defines the grammar to query the database, and its translation into sql
"""

#%config IPCompleter.greedy = True

import json
import inspect,sys

[docs]class Sqlbuilder: """Parses a string with nuclear data model tokens Attributes: force_clean (bool): whether fields and conditions of the query will be "cleaned", e.g. (NUCLIDE.Z -> ( NUCLIDE.Z. When false, the cleaning is done only if the query execution raises an exception _classes (Object[]): the classes of this module, used in clean_token() to find their place in a string """ # if fields and conditions of the query will be "cleaned", e.g. (NUCLIDE.Z -> ( NUCLIDE.Z # when false, the cleaning is done only if the query execution raises an exception force_clean = False # the classes of this module, used in clean_token to find where are placed in a string _classes = [] # a string token is evaluated to convert it into an object # then it will be checked if it is an orm piece def interrogate(self,tk): try: ret = eval(tk) # '241AM' : when the string is between '' if ret.__class__.__name__ == "str": return tk else: # this is a string without '' return ret except: return eval("tk") # checks if an object is a class of this module def is_datamodel(self,piece): if(piece.__class__.__module__ == __name__ or piece == _Base.ALL): return True return False # fills the _classes list def get_classes(self): # lazy if(len(self._classes) > 0 ): return self._classes for name, obj in inspect.getmembers(sys.modules["ndlaborm"]): if inspect.isclass(obj): self._classes.append(obj) #print('print(description(' + name + '))') return self._classes # attributes of a class def get_attributes(self,cls): attr = [] dump = dir(type('dump', (object,), {})) for item in inspect.getmembers(cls): if(item[0] not in dump and item[0] != 'ALL'): attr.append(item[0]) return attr # adds blanks where needed: '(GAMMA.ENERGY=' --> '( GAMMA.ENERGY =' def before_after_class(self,tk, idx, mclass): """ tk the token idx the starting of the class name within the token mclass the class found in this token """ length = len(mclass.__name__) char_before = tk[idx-1: idx] if(idx > 0 and char_before != '.' and char_before != '_'): # before: cases like "(GAMMA.ENERGY ..." tk = tk[:idx] + ' ' + tk[idx:] length = length + 1 # after the class there is "." and the fields tks = tk.split(".") # only the last sub-token. # for "GAMMA.END_LEVEL.JP" the last token is not a field of the GAMMA class # and will go unchecked now. It will be picked up when clean_tk finds END_LEVEL and passes it back here last_tk = tks[len(tks)-1] attribs = self.get_attributes(mclass) idx_max = 0 len_max = 0 # check all the possible fields, take the longest name to avoid errors in cases like "J" and "JP" for attr in attribs: idx = last_tk.find(attr) if(idx == -1): continue char_after = "" if len(last_tk) == len(attr) else last_tk[idx + len(attr): idx+ len(attr)+1] # this is a bit ad hoc, it is to deal with : # 1 - NUCLIDE.NUC_ID , where also N is a field of nuclide # 2 - LEVEL.NUC.NUC_ID where NUC is a class and needs to be separated from NUC_ID if(char_after == "_" or ( attr != last_tk and last_tk.startswith('NUC_ID') and attr != 'NUC_ID' )): continue mlen = len(attr) len_max = mlen if mlen > len_max else len_max idx_max = idx if mlen > len_max else idx_max if(len_max > 0 and len(last_tk) > len_max): last_tk = last_tk[:idx_max + len_max] + ' ' + last_tk[idx_max + len_max:] tks[len(tks)-1] = last_tk return ".".join(tks) # take one token (string with no blanks), look for classes and process the token def clean_tk(self,tk): classes = self.get_classes() for mclass in classes: idx = tk.find(mclass.__name__) #the token contains a class name if(idx > -1): tk = self.before_after_class(tk,idx, mclass) # place blanks if needed return tk def clean_query(self,str): tks_a = str.split() # put blanks where needed: 'GAMMA.ENERGY=' --> 'GAMMA.ENERGY =' clean_string = '' for tk_a in tks_a: clean_string += ' ' + self.clean_tk(tk_a) return clean_string #tks_a = clean_string.split() #string should have datamodel tokens separated by ' ' def parse(self,string): # string should be like '( Gamma.start_level.energy - Gamma.end_level.energy ) = 100' fields = [] tables = [] fks = [] tables_nofks = [] # "true" tables, not from a fk addition # table.* will be prefixed with DISTINCT if(string.endswith(".*")): string = string.replace(".*",".ALL") tks_a = string.split() # datamodel must have blank spaces. Use clean_query to pre-process for tk_a in tks_a: try: # check what kind of staff is tk_a piece = (self.interrogate(tk_a)) # it is not part of the datamodel: leave as it is if not self.is_datamodel(piece): fields.append(str(piece)) else: # it is data model tks_b = tk_a.split(".") tot = len(tks_b) #print("tot", tot) # from GAMMA.START_LEVEL.ENERGY build the array [GAMMA.START_LEVEL.ENERGY, GAMMA.START_LEVEL, GAMMA] tks_c = [] for i in range(0, tot): dm = ".".join(tks_b[0:tot -i]) tks_c.append(eval(dm)) # process the pieces, so far only 3 levels are dealt with. Remeber: the pieces go backward for i in range(0, tot): tk = tks_c[i] if(i == 0): # this is a column if(tk == _Base.ALL): column = "*" else: column = (tk.data["column"]) if(i == 1 ): # this can be a table, or a foreign key if 'table' not in tk.data: # this is fk tblnm = self.table_name(tk) # tk.data["fk"]["table"] + (( " as " + tk.data["fk"]["alias"]) if "alias" in tk.data["fk"].keys() else "") tables.append(tblnm) for col in tk.data["fk"]["column"]: fks.append( tks_c[i+1].data["table"] + "." + col) tblnm = tk.data["fk"]["alias"] if "alias" in tk.data["fk"].keys() else tk.data["fk"]["table"] fields.append(tblnm + "." + column) else: # this is a table if(column == "*"): fields.append("distinct " + tk.data["table"] + "." + column) else: fields.append(tk.data["table"] + "." + column) tables.append(tk.data["table"]) tables_nofks.append(tk.data["table"]) if 'where' in tk.data: fks.append(tk.data["where"]) if( i == 2 ): # it is a table tables.append(tk.data["table"]) tables_nofks.append(tk.data["table"]) if 'where' in tk.data: fks.append(tk.data["where"]) except Exception as e: print(e) tables = list(set(tables)) return {"tables":tables, "fks":fks, "fields":fields, "tables_nofks" : tables_nofks} def table_name(self, tk): """ Table name for a foreign key """ return tk.data["fk"]["table"] + (( " as " + tk.data["fk"]["alias"]) if "alias" in tk.data["fk"].keys() else "") def query_check(self,fields, conditions=""): """No more than one table (excluding fks) """ select = self.parse(fields) where = self.parse(conditions) tables = select["tables_nofks"] + where["tables_nofks"] tables = list(set(tables)) if(len(tables) != 1): return False return True def query_desc(self,fields, conditions=""): if(self.force_clean ): fields = self.clean_query(fields) conditions = self.clean_query(conditions) select = self.parse(fields) where = self.parse(conditions) tables = select["tables"] + where["tables"] fks = select["fks"] + where["fks"] desc = self.foreign_keys(tables, fks)["desc"] return "\n".join(desc) def foreign_keys(self, tables, fks): desc = [] return { "fks":fks, "desc":desc} # force fk for queries on multiple tables. In case of multiple insertions, the doublers are removed below # PARENT_LEVEL = LEVEL('{"column" : "parent_l_seqno", "fk": {"table" : "levels", "alias" : "levels_s" , "column" : ["parent_l_seqno = levels_s.l_seqno", "parent_nucid = levels_s.nucid"]}}') if LEVEL.data["table"] in tables and NUCLIDE.data["table"] in tables: fks.append("nuclides.nucid = levels.nucid") desc.append(" nuclide having the level") # think more about if (self.table_name(DR_GAMMA.END_LEVEL)) in tables and NUCLIDE.data["table"] in tables: fks.append("gammas.nucid = "+ DR_GAMMA.END_LEVEL.data["fk"]["alias"] + ".nucid") # this is ambiguous, it could link to the daughter if DR_GAMMA.data["table"] in tables and NUCLIDE.data["table"] in tables: fks.append("nuclides.nucid = dr_gammas.parent_nucid") desc.append(" the parent of the nuclide emitting the radiation") if GAMMA.data["table"] in tables and NUCLIDE.data["table"] in tables: print("found") fks.append("nuclides.nucid = gammas.nucid") desc.append(" nuclide having the gamma transition") if GAMMA.data["table"] in tables and LEVEL.data["table"] in tables: fks.append("levels.nucid = gammas.nucid") fks.append("levels.l_seqno = gammas.l_seqno") desc.append(" level emitting the gamma") # consider whether to add the level if GAMMA.data["table"] in tables and L_DECAY.data["table"] in tables: fks.append("l_decays.nucid = gammas.nucid") desc.append(" parent nuclide having the gamma") #fks.append("l_decays.l_seqno = gammas.l_seqno") if GAMMA.data["table"] in tables and _DECAY_RADIATION.data["table"] in tables: fks.append("decay_radiations.daughter_nucid = gammas.nucid") fks.append("decay_radiations.adopted_daughter_l_seqno = gammas.l_seqno") desc.append(" daughter having the gamma ") # link to parent or daughter ? # if L_DECAY.data["table"] in tables and NUCLIDE.data["table"] in tables: # fks.append("nuclides.nucid = l_decays.nucid") # desc.append(" parent nuclide of the decay") # link to parent or daughter ? # if L_DECAY.data["table"] in tables and LEVEL.data["table"] in tables: # fks.append("levels.nucid = l_decays.nucid") # fks.append("levels.l_seqno = l_decays.l_seqno") # desc.append(" parent level of the decay") # in the dr there are two possible reference : parent or daughter # if _DR_BASE.data["table"] in tables and NUCLIDE.data["table"] in tables: # fks.append("nuclides.nucid = decay_radiations.parent_nucid") # desc.append(" parent nuclide of the decay") if CUM_FY.data["table"] in tables and DR_GAMMA.data["table"] in tables: fks.append("cum_fy.daughter_nucid = dr_gammas.parent_nucid") desc.append(" product nuclide whose decay daughter emits the gamma") return { "fks":fks, "desc":desc} def query_build(self,fields, conditions=""): if(self.force_clean ): # place spaces around orm tokens print('celan') fields = self.clean_query(fields) conditions = self.clean_query(conditions) select = self.parse(fields) fields_str = " ".join(select["fields"]) where = self.parse(conditions) tables = select["tables"] + where["tables"] fks = select["fks"] + where["fks"] fks = self.foreign_keys(tables, fks)["fks"] tables = list(set(tables)) # remove doublers tables_str = ",".join(tables) fks = list(set(fks)) fks_str = " and ".join(fks) where_str = " ".join(where["fields"]) if ( len(where_str) > 0 and len(fks_str) > 0 ): where_str = fks_str + " and " + where_str elif (len(fks_str) > 0): where_str = fks_str where_str = where_str.strip(); if ( (not any([where_str.startswith(s) for s in ["order","group","having"]]) ) and (len(where_str) > 0 )) : where_str = "where " + where_str qry = "select " + fields_str + " from " + tables_str + " " + where_str return qry
def description(obj): #classfact = getattr(sys.modules[__name__], name) #obj = classfact() s = obj.__name__ + ": " + obj.desc + '\n\n' lst = dir(obj) lst.sort() for att in lst: #if(att.upper() == att): try: try: dsc = getattr(obj, att).data["desc"] except: dsc = getattr(obj, att).desc if(dsc != ''): s += att + (' \t\t' if len(att) < 7 else ' \t')+ dsc + '\n' except: None return s def description_html(obj): #classfact = getattr(sys.modules[__name__], name) #obj = classfact() s = '<table><tr><th colspan=2>' + obj.__name__ + ": " + obj.desc + '</th></tr> \n' lst = dir(obj) lst.sort() for att in lst: #if(att.upper() == att): try: try: dsc = getattr(obj, att).data["desc"] except: dsc = getattr(obj, att).desc if(dsc != ''): s += '<tr><td>' + att + '</td><td>'+ dsc + '</td></tr>\n' except: None return (s + '</table>') def description_sphinx(obj): nl = "| " nlb = "| **" eb = "** |nbspc| |nbspc| " s = obj.__name__ + '\n' + '------------------' + '\n\n' s += nl + obj.desc + '\n\n' lst = dir(obj) lst.sort() for att in lst: try: try: dsc = getattr(obj, att).data["desc"] except: dsc = getattr(obj, att).desc if(dsc != ''): s += nlb + att + eb + (' \t\t' if len(att) < 7 else ' \t')+ dsc + '\n' except: None return s def sphinx_guide(): print(description_sphinx(NUCLIDE)) print(description_sphinx(LEVEL)) print(description_sphinx(GAMMA)) print(description_sphinx(L_DECAY)) print(description_sphinx(DR_ALPHA)) # print(description_sphinx(DR_BETA)) print(description_sphinx(DR_BETAM)) print(description_sphinx(DR_BETAP)) print(description_sphinx(DR_ANTI_NU)) print(description_sphinx(DR_NU)) print(description_sphinx(DR_DELAYED)) print(description_sphinx(DR_GAMMA)) print(description_sphinx(DR_PHOTON_TOTAL)) print(description_sphinx(DR_X)) print(description_sphinx(DR_AUGER)) print(description_sphinx(DR_ANNHIL)) print(description_sphinx(DR_CONV_EL)) print(description_sphinx(CUM_FY)) print(description_sphinx(IND_FY)) _STR = '*(S)* ' _QTT = '*(Q)* ' _QTTL = '*(q)* ' _LNK = '*(L)* ' class _Base: ALL = json.loads('{"column" : "*"}') def __init__(self, data): if data == "": self.data = "{}" self.data = json.loads(data) class Column(_Base): def __init__(self,name, description = ''): super().__init__('{"column" : "' + name + '", "desc" : "' + description + '"}') @property def desc(self): try: #if self.data['column'].endswith('unc'): return 'uncertainty' #if self.data['column'].endswith('limit'): return 'GT for >, LE for <, ... ' if(self.data['desc'] != ''): return self.data['desc'] except: return 'no' + self.data class NUCLIDE(_Base): desc = "properties of the nuclide in its ground state" data = json.loads('{"table" : "nuclides"}') Z = Column('z','number of protons') N = Column('n', 'number of neutrons') NUC_ID = Column('nucid', _STR + 'identifier, e.g. 135XE') ELEM_SYMBOL = Column('elem_symbol' , _STR + 'symbol of the element') CHARGE_RADIUS = Column('charge_radius', _QTT + 'Root-mean-square of the nuclear charge radius, expressed in fm. ') CHARGE_RADIUS_UNC = Column('charge_radius_unc') CHARGE_RADIUS_LIMIT = Column('charge_radius_limit') ATOMIC_MASS = Column('atomic_mass', _QTT + 'atomic mass, in micro AMU') ATOMIC_MASS_UNC = Column('atomic_mass_unc') ATOMIC_MASS_LIMIT = Column('atomic_mass_limit') MASS_EXCESS = Column('mass_excess', _QTT + 'mass excess [keV]') MASS_EXCESS_UNC = Column('mass_excess_unc') MASS_EXCESS_LIMIT = Column('mass_excess_limit') BINDING_EN = Column('binding_en',_QTT + 'binding energy per nucleon [keV]') BINDING_EN_UNC = Column('binding_en_unc') BINDING_EN_LIMIT = Column('binding_en_limit') BETA_DECAY_EN = Column('beta_decay_en', _QTT + 'energy available for beta decay [keV]') BETA_DECAY_EN_UNC = Column('beta_decay_en_unc') BETA_DECAY_EN_LIMIT = Column('beta_decay_en_limit') S2N = Column('s2n',_QTT + '2-neutron separation energy [keV]') S2N_UNC = Column('s2n_unc') S2N_LIMIT = Column('s2n_limit') S2P = Column('s2p',_QTT + '2-proton separation energy [keV]') S2P_UNC = Column('s2p_unc') S2P_LIMIT = Column('s2p_limit') QA = Column('qa',_QTT + 'alpha decay Q energy [keV]') QA_UNC = Column('qa_unc') QA_LIMIT = Column('qa_limit') QBMN = Column('qbmn',_QTT + 'beta- + n decay energy [keV]') QBMN_UNC = Column('qbmn_unc') QBMN_LIMIT = Column('qbmn_limit') SN = Column('sn',_QTT + 'neutron separation energy [keV]') SN_UNC = Column('sn_unc') SN_LIMIT = Column('sn_limit') SP = Column('sp',_QTT + 'proton separation energy [keV]') SP_UNC = Column('sp_unc') SP_LIMIT = Column('sp_limit') QEC = Column('qec',_QTT + 'electron capture Q-value [keV]') QEC_UNC = Column('qec_unc') QEC_LIMIT = Column('qec_limit') ABUNDANCE = Column('abundance',_QTTL + 'natural abundance, in mole fraction') ABUNDANCE_UNC = Column('abundance_unc') def __init__(self,name): super().__init__(name) class LEVEL(_Base): desc = "properties of the energy states of a nuclide" data = json.loads('{"table" : "levels"}') NUC = NUCLIDE('{ "column" : "nucid", "fk": {"table" : "nuclides", "alias" : "lev_nuc" , "column" : ["nucid = lev_nuc.nucid"]}, "desc" : "' + _LNK + ' access to the properties of the nuclide , e.g. LEVEL.NUC.Z "}') SEQNO = Column('l_seqno','sequential number of the level, G.S. = 0') ENERGY = Column('energy',_QTT + 'level energy [keV]') ENERGY_UNC = Column('energy_unc') ENERGY_LIMIT = Column('energy_limit') HALF_LIFE = Column('half_life',_QTT + 'Half-life value as given in the evaluation, see HALF_LIFE_UNITS for the units. Use HALF_LIFE_SEC for calculations ') HALF_LIFE_UNC = Column('half_life_unc') HALF_LIFE_UNITS = Column('half_life_units', _STR +' the HALF-LIFE field units') HALF_LIFE_LIMIT = Column('half_life_limit', _STR +' - > , <, >=, etc..') HALF_LIFE_SEC = Column('half_life_sec',_QTT + 'H-l [s]') HALF_LIFE_SEC_UNC = Column('half_life_sec_unc') JP = Column('jp_str', _STR + 'Jp as given in the evaluation') J = Column('j','J value as assigned in RIPL') P = Column('parity','parity as assigned in RIPL') JP_ORDER = Column('jp_order','order of the Jp: 1 is the first occurence ') JP_METHOD = Column('jp_method','method for assigning the Jp, see the J_ASSIGNMENT_CODE') QUADRUPOLE_EM = Column('quadrupole_em',_QTT + 'Electrinc quadrupole moment [b]') QUADRUPOLE_EM_UNC = Column('quadrupole_em_unc') QUADRUPOLE_EM_LIMIT = Column('quadrupole_em_limit') DIPOLE_MM = Column('dipole_mm',_QTT + 'magnetic dipole moment [Bohr magnetons]') DIPOLE_MM_UNC = Column('dipole_mm_unc') DIPOLE_MM_LIMIT = Column('dipole_mm_limit') METASTABLE = Column('metastable', _STR + 'whether there is an evaluated decay mode with the list of radiations') QUESTIONABLE = Column('questionable', _STR + 'the existence of the level is questionable') CONFIGURATION = Column('configuration', _STR + 'the nuclear configuration') ISOSPIN = Column('isospin', _STR + 'Isospin') def __init__(self,name): super().__init__(name) class DECAY_MODE(_Base): data = json.loads('{"table" : "decay_modes"}') NAME = Column('mode') CODE = Column('code') DESC = Column('desc') def __init__(self,name): super().__init__(name) # extend to add the decay decode, decay group class L_DECAY(_Base): desc = "properties of a decay mode of a level" data = json.loads('{"table" : "l_decays"}') NUC = NUCLIDE('{ "column" : "nucid", "fk": {"table" : "nuclides", "alias": "dec_p_nuc" , "column" : ["nucid = dec_p_nuc.nucid"]}, "desc" : "' + _LNK + ' access to parent nuclide properties , e.g. L_DECAY.NUC.Z "}') LEVEL = LEVEL('{"column" : "l_seqno", "fk": {"table" : "levels", "alias": "dec_p_lev" ,"column" : ["l_seqno = dec_p_lev.l_seqno", "nucid = dec_p_lev.nucid"]} , "desc" : "' + _LNK + ' access to the properties of the level, e.g. L_DECAY.LEVEL.ENERGY "}') MODE = Column('decay_code','code of the decay, specify it using one of the DECAY_* constants') # MODE = DECAY_MODE('{"column" : "decay_code", "fk": {"table" : "decay_modes", "column" : ["decay_code = decay_modes.code "]}, "desc" : "decay mode"}') # MODE = _Base('{"column" : "decay_code", "fk": {"table" : "decay_codes", "column" : ["decay_codes.decay_code = decay_code"]}, "desc" : "decay mode code"}') DAUGHTER = NUCLIDE('{ "column" : "daughter_nucid", "fk": {"table" : "nuclides", "alias": "dec_d_nuc" , "column" : ["daughter_nucid = dec_d_nuc.nucid"]}, "desc" : "' + _LNK + ' access to daughter nuclide properties , e.g. L_DECAY.DAUGHTER.Z "}') PERC = Column('perc',_QTT + 'decay probability per 100 decays of the parent') PERC_UNC = Column('perc_unc') PERC_LIMIT = Column('perc_limit') Q_TOGS = Column('q_togs',_QTTL + 'Q-value of the decay. For decay of metastable sates, it includes the parent energy level') Q_TOGS_UNC = Column('q_togs_unc') def __init__(self,name): super().__init__(name) class _GM(_Base): data = json.loads('{"table" : ""}') START_LEVEL = LEVEL('{"column" : "l_seqno", "fk": {"table" : "levels", "alias" : "gam_lev_s" , "column" : ["l_seqno = gam_lev_s.l_seqno", "nucid = gam_lev_s.nucid"]}, "desc" : "' + _LNK + ' access to the properties of the start level, e.g. GAMMA.START_LEVEL.ENERGY "}') END_LEVEL = LEVEL('{"column" : "final_l_seqno", "fk": {"table" : "levels", "alias" : "gam_lev_e" , "column" : ["final_l_seqno = gam_lev_e.l_seqno", "nucid = gam_lev_e.nucid"]}, "desc" : "' + _LNK + ' access to the properties of the end level, e.g. GAMMA.END_LEVEL.ENERGY "}') SEQNO = Column('g_seqno', 'sequential number of the gamma with respect to the start level, 0 being the gamma with the lowest energy') ENERGY = Column('energy', _QTT + ' energy [keV]') ENERGY_UNC = Column('energy_unc') ENERGY_LIMIT = Column('energy_limit') REL_PHOTON_INTENS = Column('rel_photon_intens', _QTT + 'relative photon intensity [%]') REL_PHOTON_INTENS_UNC = Column('rel_photon_intens_unc') REL_PHOTON_INTENS_LIMIT = Column('rel_photon_intens_limit') MULTIPOLARITY = Column('multipolarity','String - multipolarity') MIXING_RATIO = Column('mixing_ratio', _QTT + 'mixing ratio') MIXING_RATIO_UNC = Column('mixing_ratio_unc') MIXING_RATIO_LIMIT = Column('mixing_ratio_limit') TOT_CONV_COEFF = Column('tot_conv_coeff', _QTT + 'total conversion coefficient') TOT_CONV_COEFF_UNC = Column('tot_conv_coeff_unc') TOT_CONV_COEFF_LIMIT = Column('tot_conv_coeff_limit') BEW = Column('bew', _QTT + 'reduced electric transition probabilities in Weisskopf units') BEW_UNC = Column('bew_unc') BEW_LIMIT = Column('bew_limit') BEW_ORDER = Column('bew_order','order of the transition') BMW = Column('bmw', _QTT + 'reduced magnetic transition probabilities in Weisskopf units') BMW_UNC = Column('bmw_unc') BMW_LIMIT = Column('bmw_limit') BMW_ORDER = Column('bmw_order','order of the transition') QUESTIONABLE = Column('questionable', _STR + 'the existence is questionable') class GAMMA(_GM): desc = "properties of a nuclide electromagnetic transition" data = json.loads('{"table" : "gammas"}') NUC = NUCLIDE( '{"column" : "nucid", "fk":{"table" : "nuclides", "alias" : "gam_nuc" , "column" : ["nucid=gam_nuc.nucid"]}, "desc" : "* Link - access to the properties of the nuclide, e.g. GAMMA.NUC.Z "}') # def __init__(self,name): # super().__init__(name) class _DR_BASE(_Base): desc = "properties the decay radiation" data = json.loads('{"table" : "decay_radiations"}') PARENT = NUCLIDE( '{"column" : "parent_nucid", "fk":{"table" : "nuclides", "alias" : "dr_nuc_p","column" : ["parent_nucid=dr_nuc_p.nucid"]}, "desc" : "' + _LNK + ' access to the properties of the parent nuclide, e.g. DR_*.PARENT.Z "}') PARENT_LEVEL = LEVEL('{"column" : "parent_l_seqno", "fk": {"table" : "levels", "alias" : "dr_lev_p" , "column" : ["parent_l_seqno = dr_lev_p.l_seqno", "parent_nucid = dr_lev_p.nucid"]}, "desc" : "' + _LNK + ' access to the properties of the parent level, e.g. DR_*.PARENT_LEVEL.ENERGY "}') DAUGHTER = NUCLIDE( '{"column" : "daughter_nucid", "fk":{"table" : "nuclides", "alias" : "dr_nuc_d" , "column" : ["daughter_nucid=dr_nuc_d.nucid"]}, "desc" : "' + _LNK + ' access to the properties of the daughter nuclide, e.g. DR_*.DAUGHTER.ENERGY "}') DAUGHTER_FED_LEVEL = LEVEL('{"column" : "adopted_daughter_l_seqno", "fk": {"table" : "levels", "alias" : "dr_lev_d" , "column" : ["adopted_daughter_l_seqno = dr_lev_d.l_seqno", "parent_nucid = dr_lev_d.nucid"]}, "desc" : "' + _LNK + ' access to the properties of the level in which the daughter nuclide is created , e.g. DR_*.DAUGHTER_FED_LEVEL.ENERGY "}') MODE = Column('decay_code','code of the decay, specify it using one of the DECAY_* constants') INTENSITY_= Column('intensity', _QTT + 'absolute intensity of the radiation per 100 decays of the parent') INTENSITY_UNC = Column('intensity_unc') INTENSITY_LIMIT = Column('intensity_limit') ENERGY = Column('energy', _QTT + 'energy of the radiation [keV]') ENERGY_UNC = Column('energy_unc') ENERGY_LIMIT = Column('energy_limit') class _FY(_Base): data = json.loads('{"table" : "cum_fy"}') THER_YIELD = Column('ther_yield', _QTTL + 'thermal neutron yield') THER_YIELD_UNC = Column('ther_yield_unc') FAST_YIELD = Column('fast_yield_num', _QTTL + 'fast neutron yield') FAST_YIELD_UNC = Column('fast_yield_unc') MEV_14_YIELD = Column('mev_14_yield', _QTTL + '14 MeV neutron yield') MEV_14_YIELD_UNC = Column('mev_14_yield_unc') class CUM_FY(_FY): desc = "cumulative fission yields" PARENT = NUCLIDE( '{"column" : "parent_nucid", "fk":{"table" : "nuclides", "alias" : "cfy_nuc_p", "column" : ["parent_nucid=cfy_nuc_p.nucid"]}, "desc" : "' + _LNK + ' access to the properties of the fissioning nuclide, e.g. CUM_FY.PARENT.Z "}') PRODUCT = NUCLIDE( '{"column" : "daughter_nucid", "fk":{"table" : "nuclides", "alias" : "cfy_nuc_d", "column" : ["daughter_nucid=cfy_nuc_d.nucid"]}, "desc" : "' + _LNK + ' access to the properties of the product nuclide, e.g. CUM_FY.PRODUCT.Z "}') PARENT_LEVEL = LEVEL('{"column" : "l_seqno", "fk": {"table" : "levels", "alias" : "cfy_lev_p" , "column" : ["parent_l_seqno = cfy_lev_p.l_seqno", "parent_nucid = cfy_lev_p.nucid"]}, "desc" : "' + _LNK + ' access to the properties of the parent level, e.g. CUM_FY.PARENT_LEVEL.ENERGY "}') def __init__(self,name): super().__init__(name) class IND_FY(_FY): desc = "independent fission yields" data = json.loads('{"table" : "ind_fy"}') PARENT = NUCLIDE( '{"column" : "parent_nucid", "fk":{"table" : "nuclides", "alias" : "ify_nuc_p", "column" : ["parent_nucid=ify_nuc_p.nucid"]}, "desc" : "' + _LNK + ' access to the properties of the fissioning nuclide, e.g. IND_FY.PARENT.Z "}') PRODUCT = NUCLIDE( '{"column" : "daughter_nucid", "fk":{"table" : "nuclides", "alias" : "ify_nuc_d","column" : ["daughter_nucid=ify_nuc_d.nucid"]}, "desc" : "' + _LNK + ' access to the properties of the product nuclide, e.g. IND_FY.PRODUCT.Z "}') PARENT_LEVEL = LEVEL('{"column" : "l_seqno", "fk": {"table" : "levels", "alias" : "ify_lev_p" , "column" : ["parent_l_seqno = ify_lev_p.l_seqno", "parent_nucid = ify_lev_p.nucid"]}, "desc" : "' + _LNK + ' access to the properties of the parent level, e.g. IND_FY.PARENT_LEVEL.ENERGY "}') def __init__(self,name): super().__init__(name) class DR_ALPHA(_DR_BASE): desc = "alpha decay radiation" data = json.loads('{"table" : "decay_radiations", "where" :"type_a=\'A\'"}') HINDRANCE = Column('a_hindrance', _QTT + 'hindrance factor') HINDRANCE_UNC = Column('a_hindrance_unc') HINDRANCE_LIMIT = Column('a_hindrance_limit') def __init__(self,name): super().__init__(name) class DR_BETA(_DR_BASE): """docstring for .""" data = json.loads('{"table" : "decay_radiations", "where" :"(type_a=\'B+\' or type_a=\'B-\')"}') LOGFT = Column('b_logft', _QTT + 'log ft') LOGFT_UNC = Column('b_logft_unc') LOGFT_LIMIT = Column('b_logft_limit') TRANS_TYPE = Column('b_trans_type', _STR + "transition type, specfy it using one of the TRANS_TYPE_* constants") ENDPOINT = Column('b_endpoint', _QTT + 'end-point energy [keV]') ENDPOINT_UNC = Column('b_endpoint_unc') ENDPOINT_LIMIT = Column('b_endpoint_limit') def __init__(self, name): super().__init__(name) class DR_BETAP(DR_BETA): desc = "beta+ decay radiation" data = json.loads('{"table" : "decay_radiations", "where" :"type_a=\'B+\'"}') EC_ENERGY = Column('ec_energy', _QTT + 'energy available for electron capture') EC_ENERGY_UNC = Column('ec_energy_unc') EC_ENERGY_LIMIT = Column('ec_energy_limit') BPEC_INTENSITY = Column('bpec_intensity', _QTT + 'sum of electron capture and beta+ intensites per 100 decays of the parent') BPEC_INTENSITY_UNC = Column('bpec_intensity_unc') BPEC_INTENSITY_LIMIT = Column('bpec_intensity_limit') EC_INTENSITY = Column('ec_intensity', _QTT + 'electron capture intensity per 100 decays of the parent') EC_INTENSITY_UNC = Column('ec_intensity_unc') EC_INTENSITY_LIMIT = Column('ec_intensity_limit') def __init__(self,name): super().__init__(name) class DR_BETAM(DR_BETA): desc = "beta- decay radiation" data = json.loads('{"table" : "decay_radiations", "where" :"type_a=\'B-\'"}') def __init__(self,name): super().__init__(name) class DR_ANTI_NU(_DR_BASE): desc = "anti neutrino decay radiation" data = json.loads('{"table" : "decay_radiations", "where" :"type_a=\'B-\'"}') ENERGY_LIMIT = Column('energy_nu_limit') ENERGY = Column('energy_nu', _QTT + 'energy [keV]') ENERGY_UNC = Column('energy_nu_unc') def __init__(self,name): super().__init__(name) class DR_NU(DR_ANTI_NU): desc = " neutrino decay radiation" data = json.loads('{"table" : "decay_radiations", "where" :"type_a=\'B+\'"}') def __init__(self,name): super().__init__(name) class DR_DELAYED(_DR_BASE): desc = "delayed particle emission" data = json.loads('{"table" : "decay_radiations", "where" :"type_a in (\'DN\',\'DP\',\'DA\')"}') TYPE = Column('type_a', _STR + 'delayed particle: DN, DP, or DA') ENERGY_X = Column('d_energy_x', _QTT + 'energy of the intermediate state after beta decay and before emetting the particle [keV]') ENERGY_X_UNC = Column('d_energy_x_unc') ENERGY_X_LIMIT = Column('d_energy_x_limit') def __init__(self,name): super().__init__(name) class DR_PHOTON_TOTAL(_Base): desc = "photon decay radiation (regardless whether gamma or X)" data = json.loads('{"table" : "dr_photon_totals"}') PARENT = NUCLIDE( '{"column" : "parent_nucid", "fk":{"table" : "nuclides","alias" : "pt_nuc_p" , "column" : ["parent_nucid=pt_nuc_p.nucid"]},"desc": "' + _LNK + ' access to the properties of the parent nuclide, e.g. DR_*.PARENT.Z "}') PARENT_LEVEL = LEVEL('{"column" : "parent_l_seqno", "fk": {"table" : "levels", "alias" : "pt_lev_p" , "column" : ["parent_l_seqno = pt_lev_p.l_seqno", "parent_nucid = pt_lev_p.nucid"]}, "desc" : "' + _LNK + ' access to the properties of the parent level, e.g. DR_*.PARENT_LEVEL.ENERGY "}') ENERGY = Column('energy', _QTTL + 'energy [keV]') ENERGY_UNC = Column('energy_unc') INTENSITY = Column('intensity', _QTTL + 'intensity per 100 dcay of the parent') INTENSITY_UNC = Column('intensity_unc') COUNT = Column('cnt','number of parent decay mode is which the line is present ') TYPE = Column('type', _STR + 'whether X or G') def __init__(self,name): super().__init__(name) class DR_GAMMA(_GM): desc = "gamma decay radiation" data = json.loads('{"table" : "dr_gammas"}') PARENT = NUCLIDE( '{"column" : "parent_nucid", "fk":{"table" : "nuclides","alias" : "drg_nuc_p" , "column" : ["parent_nucid=drg_nuc_p.nucid"]} ,"desc": "' + _LNK + ' access to the properties of the parent nuclide, e.g. DR_GAMMA.PARENT.Z "}') PARENT_LEVEL = LEVEL('{"column" : "parent_l_seqno", "fk": {"table" : "levels", "alias" : "drg_lev_p" , "column" : ["parent_l_seqno = drg_lev_p.l_seqno", "parent_nucid = drg_lev_p.nucid"]},"desc": "' + _LNK + ' access to the properties of the parent level, e.g. DR_GAMMA.PARENT_LEVEL.ENERGY "}') MODE = Column('decay_code','code of the decay, specify it using one of the DECAY_* constants') INTENSITY = Column('intensity', _QTT + 'intensity per 100 dcay of the parent') INTENSITY_UNC = Column('intensity_unc') INTENSITY_LIMIT = Column('intensity_limit') def __init__(self,name): super().__init__(name) class _DR_ATOMIC(_DR_BASE): desc = '' SHELL = Column('type_c', _STR + 'Atomic shell IUPAC notation, use one of the SHELL_* constants' ) class DR_X(_DR_ATOMIC): desc = "X decay radiation" data = json.loads('{"table" : "decay_radiations", "where" :"type_a = \'G\' and type_b=\'X\'"}') def __init__(self,name): super().__init__(name) class DR_CONV_EL(_DR_ATOMIC): desc = "conversion electron radiation" data = json.loads('{"table" : "decay_radiations", "where" :"type_a = \'E\' and type_b=\'CE\'"}') def __init__(self,name): super().__init__(name) class DR_AUGER(_DR_ATOMIC): desc = "Auger electron radiation" data = json.loads('{"table" : "decay_radiations", "where" :"type_a = \'E\' and type_b=\'AU\'"}') def __init__(self,name): super().__init__(name) class DR_ANNHIL(_DR_BASE): desc = "gamma from annihilation " data = json.loads('{"table" : "decay_radiations", "where" :"type_a = \'G\' and type_b=\'AN\'"}') def __init__(self,name): super().__init__(name) # decay codes DECAY_A = 0 DECAY_Bp = 1 DECAY_Bm = 2 DECAY_IT = 3 DECAY_P = 4 DECAY_N = 5 DECAY_BmN = 6 DECAY_EC = 7 DECAY_SF = 8 DECAY_D = 9 DECAY_ECP = 10 DECAY_3HE = 11 DECAY_BpP = 12 DECAY_3H = 13 DECAY_G = 14 DECAY_Bp = 15 DECAY_ECA = 16 DECAY_Bm2N = 17 DECAY_8BE = 18 DECAY_BpA = 19 DECAY_2Bm = 20 DECAY_2P = 21 DECAY_BmA = 22 DECAY_14C = 23 DECAY_EC2P = 24 DECAY_Bp2P = 25 DECAY_2Bp = 26 DECAY_28MG = 27 DECAY_ECSF = 28 DECAY_Bm3N = 29 DECAY_2EC = 30 DECAY_24NE = 31 DECAY_ECF = 32 DECAY_NE = 33 DECAY_ECP_EC2P = 34 DECAY_22NE = 35 DECAY_34SI = 36 DECAY_EC_SF = 37 DECAY_24NE = 38 DECAY_BF = 39 DECAY_SF_EC_Bp = 40 DECAY_SF_Bm = 41 DECAY_Bm4N = 42 DECAY_SF_EC_Bm = 44 DECAY_IT_EC_Bp = 45 DECAY_EC3P = 46 DECAY_20NE = 47 DECAY_BmF = 49 DECAY_BpEC = 50 DECAY_20O = 51 DECAY_MG = 52 DECAY_ECAP = 53 DECAY_2e = 54 DECAY_BmP = 55 DECAY_12C = 57 DECAY_25NE = 58 DECAY_34SI = 59 DECAY_22NE = 60 DECAY_2N = 61 DECAY_EC_SF = 62 DECAY_SF_EC_Bp = 63 DECAY_Bp3P = 46 DECAY_BmSF = 64 DECAY_Bm5N = 65 DECAY_BpF = 66 DECAY_28MG = 67 DECAY_Bm6N = 68 DECAY_Bm7N = 69 # delayed particle DELAY_N = 'DN' DELAY_A = 'DA' DELAY_P = 'DP' # ripl J assignment methods RIPL_J_UNKNOWN = -1 RIPL_J_UNIQUE = 0 RIPL_J_DISTRIBUTION_GAMMA = 1 RIPL_J_DISTRIBUTION = 2 RIPL_J_DISTRIBUTION_CONSTRAIN = 3 # ripl parity codes RIPL_P_PLUS = 1 RIPL_P_MINUS = 0 # beta transition types TRANS_1NU = '1NU' TRANS_1U = '1U' TRANS_2NU = '2NU' TRANS_2U = '2U' TRANS_3NU = '3NU' TRANS_3U = '3U' TRANS_4NU = '4NU' TRANS_4U = '4U' TRANS_5NU = '5NU' TRANS_5U = '5U' TRANS_7NU = '7NU' TRANS_8U = '8U' TRANS_A = 'A' TRANS_S = 'S' SHELL_K = 'K' SHELL_KA1 = 'KA1' SHELL_KA2 = 'KA2' SHELL_KB = 'KB' SHELL_KLL = 'KLL' SHELL_KLX = 'KLX' SHELL_KXY = 'KXY' SHELL_KpB1 = 'KpB1' SHELL_KpB2 = 'KpB2' SHELL_L = 'L' SHELL_L1 = 'L1' SHELL_L1M2 = 'L1M2' SHELL_L1M3 = 'L1M3' SHELL_L1N2 = 'L1N2' SHELL_L1N3 = 'L1N3' SHELL_L1O23 = 'L1O23' SHELL_L2 = 'L2' SHELL_L2M1 = 'L2M1' SHELL_L2M4 = 'L2M4' SHELL_L2N1 = 'L2N1' SHELL_L2N4 = 'L2N4' SHELL_L2O1 = 'L2O1' SHELL_L2O4 = 'L2O4' SHELL_L3 = 'L3' SHELL_L3M1 = 'L3M1' SHELL_L3M4 = 'L3M4' SHELL_L3M5 = 'L3M5' SHELL_L3N1 = 'L3N1' SHELL_L3N45 = 'L3N45' SHELL_L3O1 = 'L3O1' SHELL_L3P1 = 'L3P1' SHELL_M = 'M' SHELL_N = 'N' SHELL_NPLUS = 'N+' SHELL_O = 'O' def get_const(): import ndlabdblink as dl dbl = dl.Dblink('ndlab_db.s3db') lst = [] for i in range(0,70): lst.append('') for name, obj in inspect.getmembers(sys.modules["ndlaborm"]): if name.startswith('DECAY') and not name.startswith('DECAY_MODE'): property = getattr(sys.modules[__name__],name) print(name, property) sql = ("select '" + name + "', desc from decay_modes where code="+str(property)) rs = dbl._cur_lite.execute(sql) for r in rs: print('| **' +r[0]+'**' + ' = ' + str(property) + ' ' + r[1]) lst[property] = '| **' +r[0]+'**' + ' = ' + str(property) + ' ' + r[1] for l in lst: print(l)