Skip to content

Commit

Permalink
updated density behavior of sample config
Browse files Browse the repository at this point in the history
  • Loading branch information
CPrescher committed Jul 29, 2024
1 parent 4370284 commit 0137330
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 25 deletions.
53 changes: 36 additions & 17 deletions glassure/configuration.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,42 @@
# -*- coding: utf-8 -*/:

from typing import Optional, Literal
from pydantic import BaseModel, Field
from dataclasses import dataclass, field
from pydantic import BaseModel, Field, computed_field

from .utility import Composition, convert_density_to_atoms_per_cubic_angstrom
from .utility import (
Composition,
convert_density_to_atoms_per_cubic_angstrom,
convert_density_to_grams_per_cubic_centimeter,
)
from .pattern import Pattern
from .methods import FourierTransformMethod, NormalizationMethod, ExtrapolationMethod


class SampleConfig(BaseModel):
composition: Composition = field(default_factory=dict)
density: Optional[float] = field(
composition: Composition = Field(default_factory=dict)
density: Optional[float] = Field(
default=None,
)
atomic_density: Optional[float] = field(
default=None,
)

def model_post_init(self, __context):
if self.density is not None:
self.atomic_density = convert_density_to_atoms_per_cubic_angstrom(
self.composition, self.density
description="Density in g/cm^3. Will be automatically updated when the atomic density is set",
)

@computed_field(
description="The atomic density in atoms per cubic Angstrom. Will be automatically updated when density is set."
)
@property
def atomic_density(self) -> Optional[float]:
if self.composition == {}: # empty composition
return None
return convert_density_to_atoms_per_cubic_angstrom(
self.composition, self.density
)

@atomic_density.setter
def atomic_density(self, value: Optional[float]):
if self.composition == {}:
self.density = None
else:
self.density = convert_density_to_grams_per_cubic_centimeter(
self.composition, value
)


Expand Down Expand Up @@ -127,7 +142,8 @@ class TransformConfig(BaseModel):
)

extrapolation: ExtrapolationConfig = Field(
default_factory=ExtrapolationConfig, description="Extrapolation configuration model."
default_factory=ExtrapolationConfig,
description="Extrapolation configuration model.",
)

use_modification_fcn: bool = Field(
Expand All @@ -138,8 +154,11 @@ class TransformConfig(BaseModel):
description="Whether to apply the Klein-Nishima correction to the Compton scattering of the sample and the"
+ "container (defined in normalization).",
)
wavelength: Optional[float] = Field(default=None, description="Wavelength in Angstrom. Needs to be set for the "
+ "Klein-Nishima correction.")
wavelength: Optional[float] = Field(
default=None,
description="Wavelength in Angstrom. Needs to be set for the "
+ "Klein-Nishima correction.",
)

fourier_transform_method: FourierTransformMethod = FourierTransformMethod.FFT

Expand Down
22 changes: 21 additions & 1 deletion glassure/utility.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@

def parse_str_to_composition(formula: str) -> Composition:
"""
Parses a chemical formula string into a dictionary with elements as keys and abundances as relative numbers.
Parses a chemical formula string into a dictionary with elements as keys and abundances as relative numbers.
Typical examples are 'SiO2'-> {'Si': 1, 'O': 2} or 'Na2Si2O5' -> {'Na': 2, 'Si': 2, 'O': 5}
:param formula: chemical formula string
Expand Down Expand Up @@ -291,6 +291,26 @@ def convert_density_to_atoms_per_cubic_angstrom(
return density / mean_z * 0.602214129


def convert_density_to_grams_per_cubic_centimeter(
composition: Composition, atomic_density: float
) -> float:
"""
Converts densities given in atoms/A^3 into g/cm3
:param composition: dictionary with elements as key and abundances as relative numbers
:param atomic_density: density in atoms/A^3
:return: density in g/cm^3
"""

# get_smallest abundance
norm_elemental_abundances = normalize_composition(composition)
mean_z = 0.0
for element, concentration in norm_elemental_abundances.items():
element = re.findall("[A-zA-Z]*", element)[0]
mean_z += concentration * scattering_factors.atomic_weights["AW"][element]
return atomic_density * mean_z / 0.602214129


def extrapolate_to_zero_step(pattern: Pattern, y0: float = 0) -> Pattern:
"""
Extrapolates a pattern to (0, y0) by setting everything below the q_min of the pattern to y0 (default=0)
Expand Down
15 changes: 8 additions & 7 deletions tests/test_configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,24 @@


def test_sample_config():
c = SampleConfig()
c_dict = vars(c)
assert c_dict == {"composition": {}, "density": None, "atomic_density": None}

c = SampleConfig(composition={"Si": 1, "O": 2}, density=2.2)

assert c.atomic_density == approx(0.0662, abs=1e-4)

c_dict = vars(c)
c_dict = c.model_dump()
assert c_dict == {
"composition": {"Si": 1, "O": 2},
"density": 2.2,
"atomic_density": approx(0.0662, abs=1e-4),
}

c = SampleConfig(composition={"Si": 1, "O": 2}, atomic_density=0.0662)
assert c.density == None

def test_sample_density_update():
s = SampleConfig(composition={"Si": 1, "O": 2}, density=2.2)
atomic_density = s.atomic_density
s.density = 2.4

assert s.atomic_density != atomic_density


def test_fit_normalization_config():
Expand Down
9 changes: 9 additions & 0 deletions tests/test_utility.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from glassure.utility import (
normalize_composition,
convert_density_to_atoms_per_cubic_angstrom,
convert_density_to_grams_per_cubic_centimeter,
calculate_f_mean_squared,
calculate_f_squared_mean,
calculate_incoherent_scattering,
Expand Down Expand Up @@ -38,6 +39,14 @@ def test_convert_density_to_atoms_per_cubic_angstrom(self):

self.assertAlmostEqual(density_au, 0.0662, places=4)


def test_convert_density_to_grams_per_cubic_centimeter(self):
composition = {"Si": 1, "O": 2}
density_au = convert_density_to_atoms_per_cubic_angstrom(composition, 2.2)
density = convert_density_to_grams_per_cubic_centimeter(composition, density_au)
self.assertAlmostEqual(density, 2.2, places=4)


def test_calculate_f_mean_squared(self):
q = np.linspace(0, 10)
composition = {"Si": 1, "O": 2}
Expand Down

0 comments on commit 0137330

Please sign in to comment.