Source code for ase2sprkkr.sprkkr.atomic_types

""" Atomic could be placed at the atomic site. """

from ..common.decorators import cached_property
import copy


[docs] class AtomicType: """ Atomic type represent a type of atom, that could be placed at the atomic site. It can be either a real chemical element, or vacuum pseudoelement. It also determine the number of electrons and valence electrons. """ _mendeleev_module = None @cached_property def mendeleev(self): if self.atomic_number == 0: raise Exception("Vaccuum (pseudo)atom is not in Mendeleev package database") if not AtomicType._mendeleev_module: try: import mendeleev except ImportError as e: raise ImportError("Cannot import Mendeleev package to guess the atomic type properties") from e AtomicType._mendeleev_module = mendeleev return AtomicType._mendeleev_module.element(self.atomic_number or self.symbol)
[docs] def __init__(self, symbol, atomic_number=None, n_core=None, n_valence=None, n_semicore=None, n_electrons=None): """ Parameters ---------- symbol: str or int Chemical symbol, e.g. Fe, N, .... If int is given, attempt to guess the symbol using third party library is done atomic_number: int Atomic number If it's zero, an attempt to guess it from the chemical symbol is done. n_core: int Number of core electrons If it's zero, an attempt to guess it from the chemical symbol/atomic number is done. n_valence: int Number of valence electrons If it's zero, an attempt to guess it from the chemical symbol/atomic_number is done. n_semicore: int Number of semicore electrons If it's zero, an attempt to guess it from the chemical symbol/atomic_number is done. n_electrons: int """ if isinstance(symbol, int): if atomic_number is not None and atomic_number != symbol: raise ValueError(f'Number of electrons in symbol ({symbol}) and atomic_number ({atomic_number}) differ') atomic_number = symbol symbol = None else: symbol = symbol atomic_number = atomic_number if atomic_number is None and symbol is None: raise ValueError("Unknown atomic type") if symbol == 'Vc' or atomic_number == 0 or \ (symbol == 'X' and atomic_number is None): self._symbol = 'Vc' self._atomic_number = 0 else: if symbol is None: self._atomic_number = atomic_number self._symbol = symbol if symbol is not None else self.mendeleev.symbol else: self._symbol = symbol self._atomic_number = None self._atomic_number = atomic_number if atomic_number is not None else self.mendeleev.atomic_number self._n_electrons = n_electrons self._n_valence = n_valence self._n_core = n_core self._n_semicore = n_semicore self._check_n_electrons()
[docs] def _check_n_electrons(self): if ( self._n_core is not None and self._n_valence is not None and self._n_semicore is not None and self._n_electrons is not None and self._n_core + self._n_valence + self._n_semicore != self._n_electrons ): raise ValueError(f"""The following atom setup is inconsistent: n_electrons: {self._n_electrons}, n_core: {self._n_core}, n_valence: {self._n_valence}, n_semicore: {self._n_semicore}""")
@property def atomic_number(self): return self._atomic_number
[docs] def _clear_symbol_cache(self): try: del self.mendeleev except AttributeError: pass try: del self.atomic_number except AttributeError: pass try: del self.symbol except AttributeError: pass
@atomic_number.setter def atomic_number(self, v): self._atomic_number = v self._clear_symbol_cache() self._symbol = self.mendeleev.symbol if v else 'Vc' @property def symbol(self): return self._symbol @symbol.setter def symbol(self, v): self._symbol = v self._atomic_number = None self._clear_symbol_cache() self._atomic_number = self.mendeleev.atomic_number if v not in ['X', 'Vc'] else 0 @property def n_electrons(self): if self._n_electrons is not None: return self._n_electrons if self._n_valence is not None and self._n_core is not None and self._n_semicore is not None: return self._n_valence + self._n_core + self._n_semicore return self.atomic_number @n_electrons.setter def n_electrons(self, v): self._n_electrons = v self.__check_n_electrons() @property def n_valence(self): if self._n_valence is not None: return self._n_valence if self._n_core is not None: return self.n_electrons - self._n_core if self.n_electrons == 0: return 0 return self.mendeleev.nvalence() @n_valence.setter def n_valence(self, v): self._n_valence = v self.__check_n_electrons() @property def n_core(self): if self._n_core is not None: self._n_core return self.n_electrons - self.n_valence - self.n_semicore @n_core.setter def n_core(self, v): self._n_core = v self.__check_n_electrons() @property def n_semicore(self): if self._n_semicore is not None: return self._n_semicore if self._n_core is not None and self._n_valence is not None: return self.n_electrons - self._n_core - self._n_valence return 0 @n_semicore.setter def n_semicore(self, v): self._n_semicore = v self.__check_n_electrons()
[docs] def copy(self): return copy.copy(self)
def __repr__(self): return f"({self.atomic_number})" if self.symbol == 'X' else self.symbol def __str__(self): return self.__repr__()
[docs] def to_tuple(self): return (self.symbol, self.n_electrons, self.n_core, self.n_valence, self.n_semicore)
[docs] @classmethod def to_atomic_type(cls, value): if isinstance(value, cls): return value return cls(value)
[docs] def is_vacuum(self): return self.atomic_number == 0