Source code for masci_tools.util.econfig

"""
Functions for expanding/splitting or converting electron configuration strings
"""
from __future__ import annotations

from masci_tools.util.constants import PERIODIC_TABLE_ELEMENTS, ATOMIC_NUMBERS

all_econfig = [
    '1s2', '2s2', '2p6', '3s2', '3p6', '4s2', '3d10', '4p6', '5s2', '4d10', '5p6', '6s2', '4f14', '5d10', '6p6', '7s2',
    '5f14', '6d10', '7p6', '8s2', '6f14'
]
states_spin = {'s': ['1/2'], 'p': ['1/2', '3/2'], 'd': ['3/2', '5/2'], 'f': ['5/2', '7/2']}
max_state_occ = {'s': 2., 'p': 6., 'd': 10., 'f': 14.}
max_state_occ_spin = {'1/2': 2., '3/2': 4., '5/2': 6., '7/2': 8.}


[docs]def get_econfig(element: str | int, full: bool = False) -> str | None: """ returns the econfiguration as a string of an element. :param element: element string :param full: a bool if True the econfig without [He]... is returned :returns: a econfig string """ if isinstance(element, int): econ: str | None = PERIODIC_TABLE_ELEMENTS.get(element, {}).get('econfig') #type:ignore elif isinstance(element, str): element_num = ATOMIC_NUMBERS.get(element, None) if element_num is None: raise ValueError(f'No element available called {element}') econ: str = PERIODIC_TABLE_ELEMENTS.get(element_num, {}).get('econfig') #type:ignore else: raise ValueError('element has to be and int or string') if full and econ is not None: econ = rek_econ(econ) return econ
[docs]def get_coreconfig(element: str | int, full: bool = False) -> str | None: """ returns the econfiguration as a string of an element. :param element: element string :param full: a bool if True the econfig without [He]... is returned :return: coreconfig string """ econ = get_econfig(element, full=full) return econ.split('|', maxsplit=1)[0].rstrip() if econ is not None else None
[docs]def rek_econ(econfigstr: str) -> str | None: """ recursive routine to return a full econfig '[Xe] 4f14 | 5d10 6s2 6p4' -> '1s 2s ... 4f14 | 5d10 6s2 6p4' :param econfigstr: electron config string to expand :returns: expanded econfig string """ split_econ = econfigstr.strip('[').split(']') if len(split_econ) == 1: return econfigstr rest = split_econ[1] elem = split_econ[0] econfig = get_econfig(elem) if econfig is not None: econ = econfig.replace(' |', '') return rek_econ(econ + rest) # for now return None
[docs]def convert_fleur_config_to_econfig(fleurconf_str: str, keep_spin: bool = False) -> str: """ '[Kr] (4d3/2) (4d5/2) (4f5/2) (4f7/2)' -> '[Kr] 4d10 4f14', or '[Kr] 4d3/2 4d5/2 4f5/2 4f7/2' # for now only use for coreconfig, it will fill all orbitals, since it has no information on the filling. :param fleurconf_str: string of the electron config like it is read from the inp.xml :param keep_spin: bool if True the spin indices will be kept in the converted string :returns: string of the electron config to be used in the inpgen """ econfstring = fleurconf_str.replace('(', '').replace(')', '') if keep_spin: econfstring.split() else: elist = econfstring.split() econfstring_new = '' for state in elist: if '/' in state: # check if nl was added before if not add it with full occ base = state[:2] spin = state[2:] occ = max_state_occ_spin.get(spin) if occ is None: raise ValueError(f'Failed to get maximum occupation for spin {spin}') if base not in econfstring_new: econfstring_new = f'{econfstring_new}{base}{int(occ)} ' else: max_occ = max_state_occ.get(base[1]) if max_occ is None: raise ValueError(f'Failed to get maximum occupation for orbital {base[1]}') econfstring_new = econfstring_new.split(base, maxsplit=1)[0] + f'{base}{int(max_occ)} ' # we assume here that the two states come behind each other, ... rather bad #econfstring_new.replace('{}'.format(base) else: econfstring_new = econfstring_new + state + ' ' econfstring = econfstring_new return econfstring.strip()