Source code for easyreflectometry.sample.elements.materials.material_density

from typing import Optional
from typing import Union

import numpy as np
from easyscience import global_object
from easyscience.Constraints import FunctionalConstraint
from easyscience.Objects.new_variable import Parameter

from easyreflectometry.special.calculations import density_to_sld
from easyreflectometry.special.calculations import molecular_weight
from easyreflectometry.special.calculations import neutron_scattering_length
from easyreflectometry.utils import get_as_parameter

from .material import DEFAULTS as MATERIAL_DEFAULTS
from .material import Material

DEFAULTS = {
    'chemical_structure': 'Si',
    'density': {
        'description': 'The mass density of the material.',
        'url': 'https://en.wikipedia.org/wiki/Density',
        'value': 2.33,
        'unit': 'gram / centimeter ** 3',
        'min': 0,
        'max': np.Inf,
        'fixed': True,
    },
    'molecular_weight': {
        'description': 'The molecular weight of a material.',
        'url': 'https://en.wikipedia.org/wiki/Molecular_mass',
        'value': 28.02,
        'unit': 'g / mole',
        'min': -np.Inf,
        'max': np.Inf,
        'fixed': True,
    },
}
DEFAULTS.update(MATERIAL_DEFAULTS)


[docs] class MaterialDensity(Material): # Added in __init__ scattering_length_real: Parameter scattering_length_imag: Parameter molecular_weight: Parameter density: Parameter
[docs] def __init__( self, chemical_structure: Union[str, None] = None, density: Union[Parameter, float, None] = None, name: str = 'EasyMaterialDensity', unique_name: Optional[str] = None, interface=None, ): """Constructor. :param chemical_structure: Chemical formula for the material. :param density: Mass density for the material. :param name: Identifier, defaults to `EasyMaterialDensity`. :param interface: Interface object, defaults to `None`. """ if unique_name is None: unique_name = global_object.generate_unique_name(self.__class__.__name__) if chemical_structure is None: chemical_structure = DEFAULTS['chemical_structure'] density = get_as_parameter( name='density', value=density, default_dict=DEFAULTS, unique_name_prefix=f'{unique_name}_Density', ) scattering_length = neutron_scattering_length(chemical_structure) mw = get_as_parameter( name='molecular_weight', value=molecular_weight(chemical_structure), default_dict=DEFAULTS, unique_name_prefix=f'{unique_name}_Mw', ) scattering_length_real = get_as_parameter( name='scattering_length_real', value=scattering_length.real, default_dict=DEFAULTS['sld'], unique_name_prefix=f'{unique_name}_ScatteringLengthReal', ) scattering_length_imag = get_as_parameter( name='scattering_length_imag', value=scattering_length.imag, default_dict=DEFAULTS['isld'], unique_name_prefix=f'{unique_name}_ScatteringLengthImag', ) sld = get_as_parameter( name='sld', value=density_to_sld(scattering_length_real.value, mw.value, density.value), default_dict=DEFAULTS, unique_name_prefix=f'{unique_name}_Sld', ) isld = get_as_parameter( name='isld', value=density_to_sld(scattering_length_imag.value, mw.value, density.value), default_dict=DEFAULTS, unique_name_prefix=f'{unique_name}_Isld', ) constraint = FunctionalConstraint(sld, density_to_sld, [scattering_length_real, mw, density]) scattering_length_real.user_constraints['sld'] = constraint mw.user_constraints['sld'] = constraint density.user_constraints['sld'] = constraint iconstraint = FunctionalConstraint(isld, density_to_sld, [scattering_length_imag, mw, density]) scattering_length_imag.user_constraints['isld'] = iconstraint mw.user_constraints['isld'] = iconstraint density.user_constraints['isld'] = iconstraint super().__init__(sld, isld, name=name, interface=interface) self._add_component('scattering_length_real', scattering_length_real) self._add_component('scattering_length_imag', scattering_length_imag) self._add_component('molecular_weight', mw) self._add_component('density', density) self._chemical_structure = chemical_structure self.interface = interface
@property def chemical_structure(self) -> str: """Get the chemical structure string.""" return self._chemical_structure @chemical_structure.setter def chemical_structure(self, structure_string: str) -> None: """Set the chemical structure string. :param structure_string: String that defines the chemical structure. """ self._chemical_structure = structure_string scattering_length = neutron_scattering_length(structure_string) self.scattering_length_real.value = scattering_length.real self.scattering_length_imag.value = scattering_length.imag @property def _dict_repr(self) -> dict[str, str]: """Dictionary representation of the instance.""" mat_dict = super()._dict_repr mat_dict['chemical_structure'] = self._chemical_structure mat_dict['density'] = f'{self.density.value:.2e} {self.density.unit}' return mat_dict
[docs] def as_dict(self, skip: list = []) -> dict[str, str]: """Produces a cleaned dict using a custom as_dict method to skip necessary things. The resulting dict matches the parameters in __init__ :param skip: List of keys to skip, defaults to `None`. """ this_dict = super().as_dict(skip=skip) # From Material del this_dict['sld'] del this_dict['isld'] # Determined in __init__ del this_dict['scattering_length_real'] del this_dict['scattering_length_imag'] del this_dict['molecular_weight'] return this_dict