Source code for viperleed.calc.classes.sitetype

"""Module sitetype of viperleed.calc.classes."""

__authors__ = (
    'Florian Kraushofer (@fkraushofer)',
    )
__copyright__ = 'Copyright (c) 2019-2024 ViPErLEED developers'
__created__ = '2019-06-13'
__license__ = 'GPLv3+'

import logging
import re

import numpy as np

from viperleed.calc.lib.periodic_table import ATOMIC_MASS
from viperleed.calc.lib.periodic_table import COVALENT_RADIUS
from viperleed.calc.lib.periodic_table import PERIODIC_TABLE

logger = logging.getLogger(__name__)


[docs]class Sitetype: """Class storing properties of a site. Site types are identified by (main) element and name, and store vibrational amplitude and occupation"""
[docs] def __init__(self, el, name): self.el = el.capitalize() # Element self.name = name self.label = self.el + '_' + self.name self.vibamp = {} # vibrational amplitude per element self.occ = {} # occupation per element self.oriState = None # deep copy of self before a search is applied self.mixedEls = [] # stores the relevant rparams.ELEMENT_MIX
def __str__(self): return self.label def isEquivalent(self, site2): """Checks whether two sites are equivalent, i.e. have the same label and the same values for vibrational amplitudes and occupations.""" if (self.label == site2.label and self.vibamp == site2.vibamp and self.occ == site2.occ): return True return False def getVibAmp(self, rp, chemel): """Calculates a default vibrational amplitude for this site for the given chemical element from the element atomic mass, the experimental temperature and the material's Debye temperature.""" if rp.T_DEBYE is None or rp.T_EXPERIMENT is None: logger.error("Cannot generate default vibrational amplitudes: " "Temperature or Debye temperature undefined.") raise ValueError("Temperature and Debye temperature must be float") if chemel in rp.ELEMENT_RENAME: el = rp.ELEMENT_RENAME[chemel].capitalize() else: el = chemel.capitalize() if el not in PERIODIC_TABLE: logger.error( "Cannot generate default vibrational amplitude for site " + self.label + ": Element " + el + " not recognized.") raise ValueError("Element " + el + " not recognized.") if el not in ATOMIC_MASS: logger.error( "Cannot generate default vibrational amplitude for site " + self.label + ": Element" + el + " atomic mass unknown.") raise NotImplementedError("Element" + el + " atomic mass unknown.") scaling = 1.0 for s in rp.VIBR_AMP_SCALE: try: label = s.split()[0] value = float(s.split()[1]) except (ValueError, IndexError): logger.error("Failed to interpret VIBR_AMP_SCALE parameter " "part, ignoring input: " + s) continue if value <= 0: logger.warning( "VIBR_AMP_SCALE parameter: scaling values have " "to be positive floats, ignoring input: " + s) continue mstr = re.escape(label) mstr = mstr.replace('\\*', '.*') m = re.match(mstr, self.label) if m: if m.end(0) == len(self.label): # real match scaling = value self.vibamp[chemel] = round( scaling * (np.sqrt(np.sqrt(1+16*((rp.T_EXPERIMENT / rp.T_DEBYE)**2)) * 109.15 / (ATOMIC_MASS[el] * rp.T_DEBYE))), 3) return
[docs]class Atom_type(Sitetype): """ Collection of atoms with the same element and same site; inherited fromm Sitetype. Used for EEASiSSS input. """
[docs] def __init__(self, el, name, new_bulk, layer = None): super().__init__(el, name) self.label = self.el + '_in_' + self.name self.covalent_radius = COVALENT_RADIUS[el.capitalize()] self.S = 0.32 self.fxc = 1.0 self.smallest_NN_dist = 1e10 # smallest NN distance of any atom of this type self.atoms = [] self.bulk_layer = layer try: self.atomic_number = PERIODIC_TABLE.index(el.capitalize())+1 except ValueError: logger.error('Invalid element symbol during Atom type assignment') raise ValueError('Invalid element symbol: ' + el.capitalize()) self.new_bulk = new_bulk # attribute used in psgen; distinguishes if this atom is part of the auto-added bulk
@property def getVibAmp(self, rp, chemel): raise AttributeError("Atom_type class objects are not intended to give a vibration amplitude. Use Site instead.") @property def isEquivalent(self, site2): #TODO: remove, not needed (I think) """Checks whether two sites are equivalent, i.e. have the same label and the same values for vibrational amplitudes and occupations.""" if (self.label == site2.label and self.vibamp == site2.vibamp and self.occ == site2.occ and self.el == site2.el and self.new_bulk == site2.new_bulk): return True return False def set_MT_params(self, rmtmin, rmtmax, S): self.rmtmin = rmtmin self.rmtmax = rmtmax self.S = S def add_atom(self, atom, NN_dist): self.atoms.append(atom) if NN_dist < self.smallest_NN_dist: self.smallest_NN_dist = NN_dist def get_atomic_number(self): return self.atomic_number def get_type_NN_dist(self): return self.smallest_NN_dist def get_layer(self): return self.bulk_layer