Source code for pyatomdb.atomic

"""
atomic.py contains routines related to basic atomic data, e.g. converting
integer nuclear charge to element symbols, etc.

Version -.1 - initial release
Adam Foster July 17th 2015
"""
llist = 'spdfghiklmnoqrtuvwxyzABCDEFGHIJKLMNOP'

import re, numpy
################################################################################
#
#  Python Module
#
#  Name:        adbatomic.py
#
#  Decription:  Codes for simple atomic data related tasks
#
#  Module contcents (and 1 line description: see individual modules for more):
#
#     z0toelsymb
#          Converts z0 to element symbol (eg 6 -> C)
#
#     z0toelname
#          Converts z0 to element name (eg 6 -> Carbon)
#
#     int2roman
#          Converts integer to Roman Numerals (eg 6 -> VI)
#
#     spectroscopic_name
#          Converts z0,ionstage to spectroscopic name (eg 6,3 -> C IV)
#
#  Check individual codes for author and update details
#
#
#  First Version:
#       Adam Foster, 28-Jul-2009
#
################################################################################


#*******************************************************************************
#
#  Routine z0toelsymb
#
#  Converts z0 to element symbol
#
#  input: z0 (integer)
#
#  returns: Element symbol (first letter capitalised)
#
#  First Version:
#       Adam Foster, 28-Jul-2009
#
#*******************************************************************************

[docs] def Ztoelsymb(Z) : """ Returns element symbol of element with nuclear charge Z. PARAMETERS ---------- Z - nuclear charge of element (e.g. 6 for carbon) RETURNS ------- element symbol (e.g. "C" for carbon) Version 0.1 28 July 2009 Adam Foster """ elsymb=('H' , 'He', 'Li', 'Be', 'B' , 'C' , 'N' , 'O' , 'F' , 'Ne', 'Na', 'Mg', 'Al', 'Si', 'P' , 'S' , 'Cl', 'Ar', 'K' , 'Ca', 'Sc', 'Ti', 'V' , 'Cr', 'Mn', 'Fe', 'Co', 'Ni', 'Cu', 'Zn', 'Ga', 'Ge', 'As', 'Se', 'Br', 'Kr', 'Rb', 'Sr', 'Y' , 'Zr', 'Nb', 'Mo', 'Tc', 'Ru', 'Rh', 'Pd', 'Ag', 'Cd', 'In', 'Sn', 'Sb', 'Te', 'I' , 'Xe', 'Cs', 'Ba', 'La', 'Ce', 'Pr', 'Nd', 'Pm', 'Sm', 'Eu', 'Gd', 'Tb', 'Dy', 'Ho', 'Er', 'Tm', 'Yb', 'Lu', 'Hf', 'Ta', 'W' , 'Re', 'Os', 'Ir', 'Pt', 'Au', 'Hg', 'Tl', 'Pb', 'Bi', 'Po', 'At', 'Rn', 'Fr', 'Ra', 'Ac', 'Th', 'Pa', 'U') if Z < 1 : print("Z must be between 1 and 92. You have given Z= " + repr(z0)) ret=-1 elif Z > 92 : print("Z must be between 1 and 92. You have given Z= " + repr(z0)) ret=-1 else : ret=elsymb[Z-1] return ret
#******************************************************************************* #******************************************************************************* #*******************************************************************************
[docs] def z0toelsymb(z0): """ Returns element symbol of element with nuclear charge z0. (wrapper to Ztoelsymb for compatibility purposes) Parameters ---------- z0 : int nuclear charge of element (e.g. 6 for carbon) Returns ------- str element symbol (e.g. "C" for carbon) """ # # Version 0.1 28 July 2009 # Adam Foster # ret = Ztoelsymb(z0) return ret
#******************************************************************************* #******************************************************************************* #******************************************************************************* #******************************************************************************* # # Routine z0toelname # # Converts z0 to element name # # input: z0 (integer) # # returns: Element name (first letter capitalised) # # First Version: # Adam Foster, 28-Jul-2009 # #*******************************************************************************
[docs] def z0toelname(z0): """ Returns element name of element with nuclear charge z0. (wrapper to Ztoelname for compatibility purposes) Parameters ---------- z0 : int nuclear charge of element (e.g. 6 for carbon) Returns ------- str element name (e.g. "Carbon" for carbon) """ # # Version 0.1 28 July 2009 # Adam Foster # ret = Ztoelname(Z) return ret
[docs] def Ztoelname(Z): """ Returns element name of element with nuclear charge Z. Parameters ---------- Z : int nuclear charge of element (e.g. 6 for carbon) Returns ------- str element name (e.g. "Carbon" for carbon) """ # # Version 0.1 28 July 2009 # Adam Foster # elname=('Hydrogen' , 'Helium' , 'Lithium' , 'Beryllium' , 'Boron' , 'Carbon' , 'Nitrogen' , 'Oxygen' , 'Fluorine' , 'Neon' , 'Sodium' , 'Magnesium' , 'Aluminum' , 'Silicon' , 'Phosphorus' , 'Sulfur' , 'Chlorine' , 'Argon' , 'Potassium' , 'Calcium' , 'Scandium' , 'Titanium' , 'Vanadium' , 'Chromium' , 'Manganese' , 'Iron' , 'Cobalt' , 'Nickel' , 'Copper' , 'Zinc' , 'Gallium' , 'Germanium' , 'Arsenic' , 'Selenium' , 'Bromine' , 'Krypton' , 'Rubidium' , 'Strontium' , 'Yttrium' , 'Zirconium' , 'Niobium' , 'Molybdenum' , 'Technetium' , 'Ruthenium' , 'Rhodium' , 'Palladium' , 'Silver' , 'Cadmium' , 'Indium' , 'Tin' , 'Antimony' , 'Tellurium' , 'Iodine' , 'Xenon' , 'Cesium' , 'Barium' , 'Lanthanum' , 'Cerium' , 'Praseodymium', 'Neodymium' , 'Promethium' , 'Samarium' , 'Europium' , 'Gadolinium' , 'Terbium' , 'Dysprosium' , 'Holmium' , 'Erbium' , 'Thulium' , 'Ytterbium' , 'Lutetium' , 'Hafnium' , 'Tantalum' , 'Tungsten' , 'Rhenium' , 'Osmium' , 'Iridium' , 'Platinum' , 'Gold' , 'Mercury' , 'Thallium' , 'Lead' , 'Bismuth' , 'Polonium' , 'Astatine' , 'Radon' , 'Francium' , 'Radium' , 'Actinium' , 'Thorium' , 'Protactinium', 'Uranium') if Z < 1 : print("Z must be between 1 and 92. You have given Z= " + repr(Z)) ret=-1 elif Z > 92 : print("Z must be between 1 and 92. You have given Z= " + repr(Z)) ret=-1 else : ret=elname[Z-1] return ret
#******************************************************************************* #******************************************************************************* #******************************************************************************* #******************************************************************************* # # Routine int2roman # # Converts a number to roman numeral (pilfered off the internet) # # input: number (integer) # # returns: Roman numeral (string) # # First Version: # Adam Foster, 28-Jul-2009 # #*******************************************************************************
[docs] def int2roman(number): numerals = { 1 : "I" , 4 : "IV", 5 : "V" , 9 : "IX", 10 : "X" , 40 : "XL", 50 : "L" , 90 : "XC", 100 : "C" , 400 : "CD", 500 : "D" , 900 : "CM", 1000 : "M" } result = "" for value, numeral in sorted(list(numerals.items()), reverse=True): while number >= value: result += numeral number -= value return result
#******************************************************************************* #******************************************************************************* #******************************************************************************* #******************************************************************************* # # Routine int_to_roman # # Converts a integer to a roman numeral (pilfered off the internet) # # input: Roman numeral (string) # # returns: number (integer) # # First Version: # Adam Foster, 03-Nov-2011 # #*******************************************************************************
[docs] def int_to_roman(input): """ Convert an integer to Roman numerals. """ if type(input) != type(1): raise TypeError("expected integer, got %s" % type(input)) if not 0 < input < 4000: raise ValueError("Argument must be between 1 and 3999") ints = (1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1) nums = ('M', 'CM', 'D', 'CD','C', 'XC','L','XL','X','IX','V','IV','I') result = "" for i in range(len(ints)): count = int(input / ints[i]) result += nums[i] * count input -= ints[i] * count return result
#******************************************************************************* #******************************************************************************* #******************************************************************************* #******************************************************************************* # # Routine roman2int # # Converts a roman numeral to an integer (pilfered off the internet) # # input: Roman numeral (string) # # returns: number (integer) # # First Version: # Adam Foster, 03-Nov-2011 # #*******************************************************************************
[docs] def roman_to_int(input): """ Convert a roman numeral to an integer. """ if type(input) != type(""): raise TypeError("expected string, got %s" % type(input)) input = input.upper() nums = ['M', 'D', 'C', 'L', 'X', 'V', 'I'] ints = [1000, 500, 100, 50, 10, 5, 1] places = [] for c in input: if not c in nums: raise ValueError("input is not a valid roman numeral: %s" % input) for i in range(len(input)): c = input[i] value = ints[nums.index(c)] # If the next place holds a larger number, this value is negative. try: nextvalue = ints[nums.index(input[i +1])] if nextvalue > value: value *= -1 except IndexError: # there is no next place. pass places.append(value) sum = 0 for n in places: sum += n # Easiest test for validity... if int_to_roman(sum) == input: return sum else: raise ValueError('input is not a valid roman numeral: %s' % input)
#******************************************************************************* # # Routine spectroscopic_name # # Converts z0, ioncharge to element symbol # # input: z0 (integer), ioncharge (integer) # # returns: Spectroscopic name (e.g. C IV or Mg XI) # # First Version: # Adam Foster, 28-Jul-2009 # #*******************************************************************************
[docs] def spectroscopic_name(Z,z1) : """ Converts Z,z1 to spectroscopic name, e.g. 6,5 to "C V" Parameters ---------- Z : int nuclear charge (e.g. 6 for C) z1 : int ion charge +1 (e.g. 5 for C4+) Returns ------- str spectroscopic symbol for ion (e.g. "C V" for C+4) """ # # Version 0.1 28 July 2009 # Adam Foster # # get element symbol elsymb = Ztoelsymb(Z) # convert z1 to spectroscopic roman = int2roman(z1) ret = elsymb + ' ' + roman return ret
#******************************************************************************* #******************************************************************************* #******************************************************************************* #******************************************************************************* # # Routine spectroscopictoz0 # # Converts z0, ioncharge to element symbol # # input: z0 (integer), ioncharge (integer) # # returns: Spectroscopic name (e.g. C IV or Mg XI) # # First Version: # Adam Foster, 28-Jul-2009 # #*******************************************************************************
[docs] def spectroscopictoz0(name): """ Converts spectroscopic name to Z, z1, e.g. "C V" to 6,5 Parameters ---------- name : str Ion name, e.g. "C V" Returns ------- int, int Z, z1 for the ion. (e.g. 6,5 for C V) """ # # Version 0.1 28 July 2009 # Adam Foster # # convert name (e.g. Fe VIII) to z0 & ioncharge (=0 for neutral) # get element symbol d = name.split() elsymb = d[0] chargesymb = d[1] z0 = elsymb_to_z0(elsymb) z1 = roman_to_int(chargesymb) z=z1-1 return z0,z
#******************************************************************************* #******************************************************************************* #******************************************************************************* #******************************************************************************* # # Routine occup_to_cfg # # Converts occupancy vector to configuration string # (e.g. [2,1,0,1] -> 1s2 2s1 3s1) # # input: occupancy (list) # # returns: configuration string # # First Version: # Adam Foster, 24-Nov-2009 # #*******************************************************************************
[docs] def occup_to_cfg(occlist) : # l_list = ['s','p','d','f','g','h','i','k','l','m','n','o','q','r', # 't','u','v','w','x','y','z', 'A','B','C','D','E','F','G','H','I','J'] cfgstr='' l=0 n=0 for j, i in enumerate(occlist) : if (l+1 >= n): l = 0 n += 1 else: l += 1 if (i > 0): cfgstr = cfgstr+' '+repr(n)+llist[l]+repr(i) # return minus leading blank return cfgstr.strip()
#******************************************************************************* #******************************************************************************* #******************************************************************************* #******************************************************************************* # # Routine elsymb_to_z0 # # Converts occupancy element symbol to z0 # (e.g. 'He' -> 2) (case insensitive) # # input: occupancy (list) # # returns: configuration string # # First Version: # Adam Foster, 24-Nov-2009 # #*******************************************************************************
[docs] def elsymb_to_Z(elsymb) : """ Converts element symbol to nuclear charge, e.g. "C" -> 6 Parameters ---------- elsymb : str Element symbol, e.g. "C". Case insensitive. Returns ------- int Z for the ion. (e.g. 6 for C) """ # # Version 0.1 28 July 2009 # Adam Foster # ellist=('h' , 'he', 'li', 'be', 'b' , 'c' , 'n' , 'o' , 'f' , 'ne', 'na', 'mg', 'al', 'si', 'p' , 's' , 'cl', 'ar', 'k' , 'ca', 'sc', 'ti', 'v' , 'cr', 'mn', 'fe', 'co', 'ni', 'cu', 'zn', 'ga', 'ge', 'as', 'se', 'br', 'kr', 'rb', 'sr', 'y' , 'zr', 'nb', 'mo', 'tc', 'ru', 'rh', 'pd', 'ag', 'cd', 'in', 'sn', 'sb', 'te', 'i' , 'xe', 'cs', 'ba', 'la', 'ce', 'pr', 'nd', 'pm', 'sm', 'eu', 'gd', 'tb', 'dy', 'ho', 'er', 'tm', 'yb', 'lu', 'hf', 'ta', 'w' , 're', 'os', 'ir', 'pt', 'au', 'hg', 'tl', 'pb', 'bi', 'po', 'at', 'rn', 'fr', 'ra', 'ac', 'th', 'pa', 'u') try: ind=ellist.index(elsymb.lower().strip()) except ValueError: print("elsymb_to_z0 error: invalid element symbol '"+elsymb+"', returning -1") ind=-1 return ind+1
[docs] def elsymb_to_z0(elsymb) : """ Converts element symbol to nuclear charge, e.g. "C" -> 6 (wrapper to elsymb_to_Z, retained for consistency) Parameters ---------- elsymb : str Element symbol, e.g. "C". Case insensitive. Returns ------- int Z for the ion. (e.g. 6 for C) """ ret= elsymb_to_Z(elsymb) return ret
#******************************************************************************* #******************************************************************************* #******************************************************************************* #******************************************************************************* # # Routine z0_to_mass # # Return atomic mass of element with atomic number z0 # # input: z0 # # returns: atomic mass (float) # # First Version: # Adam Foster, 4-Apr-2010 # #*******************************************************************************
[docs] def z0_to_mass(z0): """ Converts element symbol to atomic mass, e.g. "C" -> 12.0107 (wrapper to Z_to_mass, retained for consistency) Isotope fractions based on those found in earth's crust samples, your astrophysical object may vary. Parameters ---------- z0 : int nuclear charge, e.g 6 for C Returns ------- float mass in a.m.u. for the element. (e.g. 12.0107 for C) References ---------- Atomic masses are taken from: Pure Appl. Chem. 81 NO 11, 2131-2156 (2009) Masses for Technetium, Promethium, Polonium, Astatine, Radon, Francium, Radium & Actinum are estimates. If you need these you probably aren't doing astronomy... """ # # Version 0.1 28 July 2009 # Adam Foster # ret = Z_to_mass(z0) return ret
[docs] def Z_to_mass(Z, raw = False): """ Converts element symbol to atomic mass, e.g. "C" -> 12.0107 Isotope fractions based on those found in earth's crust samples, your astrophysical object may vary. Parameters ---------- Z : int nuclear charge, e.g 6 for C raw : bool if true, ignore Z, and return the entire mass list as an array with a 0 at the beginning so ret[12] = mass of carbon. Returns ------- float mass in a.m.u. for the element. (e.g. 12.0107 for C) References ---------- Atomic masses are taken from: Pure Appl. Chem. 81 NO 11, 2131-2156 (2009) Masses for Technetium, Promethium, Polonium, Astatine, Radon, Francium, Radium & Actinum are estimates. If you need these you probably aren't doing astronomy... """ # Version 0.1 28 July 2009 # Adam Foster # masslist=( 1.00794 , 4.002602, 6.941 , 9.012182 , 10.811 , 12.0107 , 14.0067 , 15.9994 , 18.9984032, 20.1797 , 22.98976928, 24.3050 , 26.9815386, 28.0855 , 30.973762 , 32.065 , 35.453 , 39.948 , 39.0983 , 40.078 , 44.955912 , 47.867 , 50.9415 , 51.9961 , 54.938045 , 55.845 , 58.933195, 58.6934 , 63.546 , 65.38 , 69.723 , 72.64 , 74.92160 , 78.96 , 79.904 , 83.798 , 85.4678 , 87.62 , 88.90585 , 91.224 , 92.90638 , 95.96 , 98.000 , 101.07 , 102.90550 , 106.42 , 107.8682 , 112.411 , 114.818 , 118.710 , 121.760 , 127.60 , 126.90447 , 131.293 , 132.9054519, 137.327 , 138.90547 , 140.116 , 140.90765 , 144.242 , 145.000 , 150.36 , 151.964 , 157.25 , 158.92535 , 162.500 , 164.93032 , 167.259 , 168.93421 , 173.054 , 174.9668 , 178.49 , 180.94788 , 183.84 , 186.207 , 190.23 , 192.217 , 195.084 , 196.966569 , 200.59 , 204.3833 , 207.2 , 208.98040 , 209.000 , 210.000 , 222.000 , 223.000 , 226.000 , 227.00 , 232.03806 , 231.03588 , 238.02891) if raw==True: n = numpy.append(0,numpy.array(masslist)) return n if Z < 1 : print("Z must be between 1 and 92. You have given Z= " + repr(Z)) ret=-1 elif Z > 92 : print("Z must be between 1 and 92. You have given Z= " + repr(Z)) ret=-1 else : ret=masslist[Z-1] return ret
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------ #------------------------------------------------------------------------------
[docs] def config_to_occup(cfgstr, nel=-1, shlmax=-1, noccup=[-1]): if len(cfgstr)==0: cfgstr = '1s2' cfgsplit = cfgstr.split(' ') n = [] l = [] o = [] for cfg in cfgsplit: ntmp = re.search("^[0-9]+",cfg) n.append(int(ntmp.group(0))) ltmp = re.search("[a-zA-Z]",cfg) l.append(llist.index(ltmp.group(0))) otmp = re.search("[0-9]+$",cfg) o.append(int(otmp.group(0))) # find the max nl shell if shlmax == -1: maxshl = -1 for i in range(len(n)): shlind = 0 shlind=sum(range(1,n[i]+1)) maxshl = max([maxshl, shlind]) else: maxshl=shlmax occup = numpy.zeros(maxshl, dtype=int) for i in range(len(n)): shlind = 0 if n[i] > 1: for iin in range(1,n[i]): shlind = shlind + iin shlind = shlind + l[i] occup[shlind] = occup[shlind] + o[i] inext = 0 lnext = 0 nnext = 1 onext = 2 if noccup[0]==-1: firstoccup = min(numpy.where(occup>0)[0]) if firstoccup > 0: for i in range(len(occup)): if ((occup[i] == 0) &(occup.sum() < nel)): if (nel-occup.sum()==6) &\ (4*lnext+2 != 6): pass elif (occup.sum()+4*lnext+2 <= nel): occup[i] = occup[i] + 4*lnext+2 else: break if nnext-lnext == 1: nnext += 1 lnext = 0 else: lnext += 1 inext = 0 lnext = 0 nnext = 1 onext = 2 while (sum(occup) < nel): if occup[inext] == 0: if (onext > (nel-sum(occup))): occup[inext] += nel-sum(occup) else: occup[inext] += onext if nnext-lnext == 1: nnext += 1 lnext = 0 else: lnext += 1 onext = 4*lnext+2 inext += 1 else: # we have an array defining the number of electrons total in each N shell # such as in FAC inext = 0 nnext = 1 shell_n = numpy.zeros(len(occup), dtype=int) shell_l = numpy.zeros(len(occup), dtype=int) while inext < len(shell_n): shell_n[inext:inext+nnext]=nnext shell_l[inext:inext+nnext]=numpy.arange(nnext) inext += nnext nnext += 1 for i_n in range(len(noccup)): nnext = i_n+1 i = numpy.where(shell_n == nnext)[0] nel_tot = sum(occup[i]) nel_targ = noccup[i_n] # if the number of electrons match if nel_tot == nel_targ: continue if nel_tot > nel_targ: print("ERROR: more electron in n=%i shell than there should be for %s" %\ (nnext, cfgstr)) print(" %i vs %i" %(nel_tot, nel_targ)) while nel_tot< nel_targ: #find empty l shells lposs = [] for il in i: if ((occup[il]==0) &(shell_l[il]*4+2 <= (nel_targ-nel_tot))): lposs.append(shell_l[il]) # get number of occupancies shell_occup = numpy.array(lposs)*4+2 delta_nel = nel_targ - nel_tot k = numpy.where(shell_occup == delta_nel)[0] if len(k) ==1: k = k[0] ind = numpy.where((shell_n==nnext) & (shell_l==lposs[k]))[0][0] occup[ind] =shell_occup[k] else: ind = numpy.where((shell_n==nnext) & (shell_l==lposs[0]))[0][0] occup[ind] = shell_occup[0] nel_tot = sum(occup[i]) if ((nel > 0) & (sum(occup) != nel)): return occup,False else: return occup, True
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------ #------------------------------------------------------------------------------
[docs] def occup_to_config(occup): s = '' lnext = 0 nnext = 1 for i,j in enumerate(occup): if j > 0: s = s+ repr(nnext)+llist[lnext]+repr(j)+' ' if nnext-lnext==1: lnext = 0 nnext += 1 else: lnext=lnext+1 s = s[:-1] return s
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------ #------------------------------------------------------------------------------
[docs] def parse_config(cfgstr): # returns n shell, l shell and occupancy for each part of the configuration # e.g. [[1,0,2],[2,1,1]] for 1s2 2p1 #split on space try: c = cfgstr.decode('ascii').split() except AttributeError: c = cfgstr.split() ret=[] for ic in c: cfg = [] ntmp = re.search("^[0-9]+",ic) cfg.append(int(ntmp.group(0))) ltmp = re.search("[a-zA-Z]",ic) cfg.append(llist.index(ltmp.group(0))) otmp = re.search("[0-9]+$",ic) cfg.append(int(otmp.group(0))) ret.append(cfg) return ret
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------ #------------------------------------------------------------------------------
[docs] def get_parity(cfgstr): d = parse_config(cfgstr) evenparity = True for i in d: if i[1]*i[2] % 2 == 1: evenparity = not(evenparity) if evenparity: return 0 else: return 1
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------ #------------------------------------------------------------------------------
[docs] def get_maxn(cfgstr): d = parse_config(cfgstr) maxn = max([c[0] for c in d]) return maxn
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------ #------------------------------------------------------------------------------
[docs] def parse_eissner(cfgstr, nel=0, levelmap=None, lmax_set=None): if levelmap is not None: # levelmap is a list of n, l for each level # with i['N'] and i['L'] giving the infos shelllist='123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' cfg = cfgstr.strip() try: cfg = cfg.decode('ascii') except AttributeError: pass cfgcopy = cfg+' ' cfgcopy = cfgcopy[:-1] if len(cfg)%3 == 0: # find the initial split. Want configuration to start with 5 (or 6, or 7) if cfg[0] in['5','6','7']: pass elif cfg[-1] in ['5','6','7']: cfg='5'+cfg[:-1] elif (cfg[-1].islower() and cfg[-2].islower()): cfg='5'+cfg else: print("Invalid configuration (1) %s" %(cfg)) elif len(cfg)%3 == 2: if not cfg[0] in ['5','6','7']: cfg = '5'+cfg else: print("Invalid configuration (2) %s" %(cfg)) elif len(cfg)%3 == 1: if not (cfg[-2].islower() and cfg[-1].islower()): print("Invalid configuration (3) %s" %(cfg)) ret = "" i=0 while i < len(cfg): cfgtmp = cfg[i:i+3] if cfgtmp[-1].islower(): if len(cfg)>=i+4: if cfg[i+3].islower(): cfgtmp=cfg[i:i+4] #if re.search('[a-z][a-zA-Z]',''): # cfgtmp = cfg[i:i+4] i += len(cfgtmp) nelec = int(cfgtmp[:2])-50 if len(cfgtmp)==3: ishell = shelllist.index(cfgtmp[2]) else: ishell = shelllist.index(cfgtmp[3])-35+len(shelllist)+(26*(shelllist.index(cfgtmp[2])-35)) try: n = levelmap[ishell]['N'] l = levelmap[ishell]['L'] except IndexError: # too many shells? if ishell >= len(levelmap): last_n = levelmap[-1]['N'] last_l = levelmap[-1]['L'] if last_l < last_n -1: n=last_n l=last_l+1 else: n=last_n+1 l=0 levelmap= numpy.append(levelmap, \ numpy.zeros(1, \ dtype=numpy.dtype({'names':['N','L'],\ 'formats':[int, int]}))) levelmap[-1]['N'] = n levelmap[-1]['L'] = l lsymb = llist[l] ret += "%i%s%i "%(n,lsymb,nelec) ret = ret[:-1] else: shelllist='123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' cfg = cfgstr.strip() try: cfg = cfg.decode('ascii') except AttributeError: pass cfgcopy = cfg+' ' cfgcopy = cfgcopy[:-1] # now deal with double letters # for i in range(len(cfg)-1): # if cfg[i].islower() and cfg[i+1].islower(): # cfg=cfg[:i]+'$^'+cfg[i+1:] # cfg = re.sub('^', '', cfgcopy) if len(cfg)%3 == 0: # find the initial split. Want configuration to start with 5 (or 6, or 7) if cfg[0] in['5','6','7']: pass elif cfg[-1] in ['5','6','7']: cfg='5'+cfg[:-1] elif (cfg[-1].islower() and cfg[-2].islower()): cfg='5'+cfg else: print("Invalid configuration (1) %s" %(cfg)) elif len(cfg)%3 == 2: if not cfg[0] in ['5','6','7']: cfg = '5'+cfg else: print("Invalid configuration (2) %s" %(cfg)) elif len(cfg)%3 == 1: if not (cfg[-2].islower() and cfg[-1].islower()): print("Invalid configuration (3) %s" %(cfg)) ret = "" i=0 while i < len(cfg): cfgtmp = cfg[i:i+3] if cfgtmp[-1].islower(): if len(cfg)>=i+4: if cfg[i+3].islower(): cfgtmp=cfg[i:i+4] #if re.search('[a-z][a-zA-Z]',''): # cfgtmp = cfg[i:i+4] i += len(cfgtmp) nelec = int(cfgtmp[:2])-50 if len(cfgtmp)==3: ishell = shelllist.index(cfgtmp[2]) else: ishell = shelllist.index(cfgtmp[3])-35+len(shelllist)+(26*(shelllist.index(cfgtmp[2])-35)) n=1 l=0 for ii in range(ishell): if l < n-1: l+=1 else: n+=1 l=0 lsymb = llist[l] ret += "%i%s%i "%(n,lsymb,nelec) ret = ret[:-1] return ret
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------ #------------------------------------------------------------------------------
[docs] def shorten_config(cfgstr, nel=0): """ Shorten the configuration as required PARAMETERS ---------- cfgstr : string configuration string. Should be simplified already e.g. '1s2 2s2 3p1' RETURNS ------- cfgshrt : string shortened configuration, e.g. '3p1' """ # get n, l, occupancy for each shell cfglist = parse_config(cfgstr) status = numpy.zeros(len(cfglist), dtype=int) # 1 = empty # 2 = partial # 3 = full for i in range(len(cfglist)): if cfglist[i][2] == 0: status[i] = 1 elif cfglist[i][2] == cfglist[i][1]*4+2: status[i] = 3 else: status[i] = 2 # find the first shell which isn't full or empty i = numpy.where(status==2)[0] if len(i)==0: # We have nothing! # find the first empty shell ii = numpy.where(status==1)[0] if len(ii) == 0: # none! # blank out everything else except the last shell status[:-1]= 0 else: i = i[i<=ii[0]]=0 i[ii] = 0 else: pass