Source code for xrayutilities.materials.atom

# This file is part of xrayutilities.
#
# xrayutilities is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>.
#
# Copyright (c) 2015-2023 Dominik Kriegner <dominik.kriegner@gmail.com>

"""
module containing the Atom class which handles the database access for atomic
scattering factors and the atomic mass.
"""
import hashlib
import os.path
import re

import numpy

from .. import config, utilities
from . import __path__, database

_db = database.DataBase(os.path.join(__path__[0], "data", config.DBNAME))
_db.Open()


[docs] def get_key(*args): """ generate a hash key for several possible types of arguments """ tup = [] for a in args: if isinstance(a, numpy.ndarray): tup.append(hashlib.md5(a).digest()) elif isinstance(a, list): tup.append(hash(tuple(a))) else: tup.append(hash(a)) return hash(tuple(tup))
[docs] class Atom: max_cache_length = 1000
[docs] def __init__(self, name, num): self.name = name self.ostate = re.sub('[A-Za-z]', '', name) for r, o in zip(('dot', 'p', 'm'), ('.', '+', '-')): self.ostate = self.ostate.replace(o, r) self.basename = re.sub('[^A-Za-z]', '', name) self.num = num self.__weight = None self.__color = None self.__radius = numpy.nan self._dbcache = {prop: [] for prop in ('f0', 'f1', 'f2', 'f')}
def __key__(self): """ key function to return the elements number """ return self.num def __lt__(self, other_el): """ make elements sortable by their key """ return self.__key__() < other_el.__key__() @property def weight(self): if not self.__weight: _db.SetMaterial(self.basename) self.__weight = _db.weight return self.__weight @property def color(self): if self.__color is None: _db.SetMaterial(self.basename) self.__color = _db.color return self.__color @property def radius(self): if self.__radius is numpy.nan: _db.SetMaterial(self.basename) self.__radius = _db.radius return self.__radius
[docs] def get_cache(self, prop, key): """ check if a cached value exists to speed up repeated database requests Returns ------- bool True then result contains the cached otherwise False and result is None result : database value """ history = self._dbcache[prop] for idx, (k, result) in enumerate(history): if k == key: history.insert(0, history.pop(idx)) # move to front return True, result return False, None
[docs] def set_cache(self, prop, key, result): """ set result to be cached to speed up future calls """ history = self._dbcache[prop] if len(history) == self.max_cache_length: history.pop(-1) history.insert(0, (key, result))
[docs] def f0(self, q): key = get_key(q) f, res = self.get_cache('f0', key) if f: return res _db.SetMaterial(self.basename) res = _db.GetF0(q, self.ostate) self.set_cache('f0', key, res) return res
[docs] def f1(self, en='config'): key = get_key(en) f, res = self.get_cache('f1', key) if f: return res if isinstance(en, str) and en == 'config': en = utilities.energy(config.ENERGY) _db.SetMaterial(self.basename) res = _db.GetF1(utilities.energy(en)) self.set_cache('f1', key, res) return res
[docs] def f2(self, en='config'): key = get_key(en) f, res = self.get_cache('f2', key) if f: return res if isinstance(en, str) and en == 'config': en = utilities.energy(config.ENERGY) _db.SetMaterial(self.basename) res = _db.GetF2(utilities.energy(en)) self.set_cache('f2', key, res) return res
[docs] def f(self, q, en='config'): """ function to calculate the atomic structure factor F Parameters ---------- q : float, array-like momentum transfer en : float or str, optional energy for which F should be calculated, if omitted the value from the xrayutilities configuration is used Returns ------- float or array-like value(s) of the atomic structure factor """ key = get_key(q, en) f, res = self.get_cache('f', key) if f: return res res = self.f0(q) + self.f1(en) + 1.j * self.f2(en) self.set_cache('f2', key, res) return res
def __str__(self): ostr = self.name ostr += f" ({self.num:2d})" return ostr def __repr__(self): return self.__str__()