File: xrd.py

package info (click to toggle)
python-emmet-core 0.84.2-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 77,220 kB
  • sloc: python: 16,355; makefile: 30
file content (120 lines) | stat: -rw-r--r-- 3,409 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
from typing import Dict, Optional

import numpy as np
from pydantic import model_validator, Field
from pymatgen.analysis.diffraction.xrd import (
    WAVELENGTHS,
    DiffractionPattern,
    XRDCalculator,
)
from pymatgen.core import Structure
from pymatgen.core.periodic_table import Element

from emmet.core.mpid import MPID
from emmet.core.spectrum import SpectrumDoc
from emmet.core.utils import ValueEnum


class Edge(ValueEnum):
    K_Alpha = "Ka"
    K_Alpha1 = "Ka1"
    K_Alpha2 = "Ka2"
    K_Beta = "Kb"
    K_Beta1 = "Kb1"
    K_Beta2 = "Kb2"


class XRDDoc(SpectrumDoc):
    """
    Document describing a XRD Diffraction Pattern
    """

    spectrum_name: str = "XRD"

    spectrum: DiffractionPattern
    min_two_theta: float
    max_two_theta: float
    wavelength: float = Field(..., description="Wavelength for the diffraction source.")
    target: Optional[Element] = Field(
        None, description="Target element for the diffraction source."
    )
    edge: Optional[Edge] = Field(
        None, description="Atomic edge for the diffraction source."
    )

    @model_validator(mode="before")
    @classmethod
    def get_target_and_edge(cls, values: Dict):
        print("Validations")
        # Only do this if neither target not edge is defined
        if "target" not in values and "edge" not in values:
            try:
                pymatgen_wavelength = next(
                    k
                    for k, v in WAVELENGTHS.items()
                    if np.allclose(values["wavelength"], v)
                )
                values["target"] = pymatgen_wavelength[:2]
                values["edge"] = pymatgen_wavelength[2:]

            except Exception:
                return values
        return values

    @classmethod
    def from_structure(  # type: ignore[override]
        cls,
        material_id: MPID,
        spectrum_id: str,
        structure: Structure,
        wavelength: float,
        min_two_theta=0,
        max_two_theta=180,
        symprec=0.1,
        **kwargs,
    ) -> "XRDDoc":
        calc = XRDCalculator(wavelength=wavelength, symprec=symprec)
        pattern = calc.get_pattern(
            structure, two_theta_range=(min_two_theta, max_two_theta)
        )

        return super().from_structure(
            material_id=material_id,
            spectrum_id=spectrum_id,
            meta_structure=structure,
            spectrum=pattern,
            wavelength=wavelength,
            min_two_theta=min_two_theta,
            max_two_theta=max_two_theta,
            **kwargs,
        )

    @classmethod
    def from_target(
        cls,
        material_id: MPID,
        structure: Structure,
        target: Element,
        edge: Edge,
        min_two_theta=0,
        max_two_theta=180,
        symprec=0.1,
        **kwargs,
    ) -> "XRDDoc":
        if f"{target}{edge}" not in WAVELENGTHS:
            raise ValueError(f"{target}{edge} not in pymatgen wavelenghts dictionarty")

        wavelength = WAVELENGTHS[f"{target}{edge}"]
        spectrum_id = f"{material_id}-{target}{edge}"

        return cls.from_structure(
            material_id=material_id,
            spectrum_id=spectrum_id,
            structure=structure,
            wavelength=wavelength,
            target=target,
            edge=edge,
            min_two_theta=min_two_theta,
            max_two_theta=max_two_theta,
            **kwargs,
        )