Skip to content

Commit f8f2d21

Browse files
Change XAS behavior under negative frequencies (#4176)
* revert behavior of xas spectra to only warn user when intensities are negative * esure that absorbing element is an Element
1 parent 5525a0c commit f8f2d21

File tree

2 files changed

+40
-15
lines changed

2 files changed

+40
-15
lines changed

src/pymatgen/analysis/xas/spectrum.py

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,16 @@
1010
from scipy.interpolate import interp1d
1111

1212
from pymatgen.analysis.structure_matcher import StructureMatcher
13+
from pymatgen.core import Element
1314
from pymatgen.core.spectrum import Spectrum
1415
from pymatgen.symmetry.analyzer import SpacegroupAnalyzer
1516

1617
if TYPE_CHECKING:
18+
from collections.abc import Sequence
1719
from typing import Literal
1820

21+
from pymatgen.core import Structure
22+
1923
__author__ = "Chen Zheng, Yiming Chen"
2024
__copyright__ = "Copyright 2012, The Materials Project"
2125
__version__ = "3.0"
@@ -42,29 +46,31 @@ class XAS(Spectrum):
4246
Attributes:
4347
x (Sequence[float]): The sequence of energies.
4448
y (Sequence[float]): The sequence of mu(E).
45-
absorbing_element (str): The absorbing element of the spectrum.
49+
absorbing_element (str or .Element): The absorbing element of the spectrum.
4650
edge (str): The edge of the spectrum.
4751
spectrum_type (str): The type of the spectrum (XANES or EXAFS).
4852
absorbing_index (int): The absorbing index of the spectrum.
53+
zero_negative_intensity (bool) : Whether to set unphysical negative intensities to zero
4954
"""
5055

5156
XLABEL = "Energy"
5257
YLABEL = "Intensity"
5358

5459
def __init__(
5560
self,
56-
x,
57-
y,
58-
structure,
59-
absorbing_element,
60-
edge="K",
61-
spectrum_type="XANES",
62-
absorbing_index=None,
61+
x: Sequence,
62+
y: Sequence,
63+
structure: Structure,
64+
absorbing_element: str | Element,
65+
edge: str = "K",
66+
spectrum_type: str = "XANES",
67+
absorbing_index: int | None = None,
68+
zero_negative_intensity: bool = False,
6369
):
6470
"""Initialize a spectrum object."""
6571
super().__init__(x, y, structure, absorbing_element, edge)
6672
self.structure = structure
67-
self.absorbing_element = absorbing_element
73+
self.absorbing_element = Element(absorbing_element)
6874
self.edge = edge
6975
self.spectrum_type = spectrum_type
7076
self.e0 = self.x[np.argmax(np.gradient(self.y) / np.gradient(self.x))]
@@ -75,8 +81,16 @@ def __init__(
7581
]
7682
self.absorbing_index = absorbing_index
7783
# check for empty spectra and negative intensities
78-
if sum(1 for i in self.y if i <= 0) / len(self.y) > 0.05:
79-
raise ValueError("Double check the intensities. Most of them are non-positive.")
84+
neg_intens_mask = self.y < 0.0
85+
if len(self.y[neg_intens_mask]) / len(self.y) > 0.05:
86+
warnings.warn(
87+
"Double check the intensities. More than 5% of them are negative.",
88+
UserWarning,
89+
stacklevel=2,
90+
)
91+
self.zero_negative_intensity = zero_negative_intensity
92+
if self.zero_negative_intensity:
93+
self.y[neg_intens_mask] = 0.0
8094

8195
def __str__(self):
8296
return (

tests/analysis/xas/test_spectrum.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,10 @@ def test_str(self):
6767
assert str(self.k_xanes) == "Co K Edge XANES for LiCoO2: <super: <class 'XAS'>, <XAS object>>"
6868

6969
def test_validate(self):
70-
y_zeros = np.zeros(len(self.k_xanes.x))
71-
with pytest.raises(
72-
ValueError,
73-
match="Double check the intensities. Most of them are non-positive",
70+
y_zeros = -np.ones(len(self.k_xanes.x))
71+
with pytest.warns(
72+
UserWarning,
73+
match="Double check the intensities. More than 5% of them are negative.",
7474
):
7575
XAS(
7676
self.k_xanes.x,
@@ -79,6 +79,17 @@ def test_validate(self):
7979
self.k_xanes.absorbing_element,
8080
)
8181

82+
def test_zero_negative_intensity(self):
83+
y_w_neg_intens = [(-1) ** i * v for i, v in enumerate(self.k_xanes.y)]
84+
spectrum = XAS(
85+
self.k_xanes.x,
86+
y_w_neg_intens,
87+
self.k_xanes.structure,
88+
self.k_xanes.absorbing_element,
89+
zero_negative_intensity=True,
90+
)
91+
assert all(v == 0.0 for i, v in enumerate(spectrum.y) if i % 2 == 1)
92+
8293
def test_stitch_xafs(self):
8394
with pytest.raises(ValueError, match="Invalid mode. Only XAFS and L23 are supported"):
8495
XAS.stitch(self.k_xanes, self.k_exafs, mode="invalid")

0 commit comments

Comments
 (0)