Skip to content

Commit

Permalink
Fix floating point imprecision error in ordering property of Collinea…
Browse files Browse the repository at this point in the history
…rMagneticStructureAnalyzer (#3574)

* Modified ordering property of CollinearMagneticStructureAnalyzer to account for floating point imprecision, added test for that.

* improve CollinearMagneticStructureAnalyzer.ordering doc str, drop isclose in favor abs(tot_mag) > 1e-8

* compress tests/files/magnetic.example.CuO.mcif

* add comment with source DOI for mcif file

* link PR that added CuO AFM test

---------

Co-authored-by: kueltzen <kueltzen@sv2218.zit.bam.de>
Co-authored-by: Janosh Riebesell <janosh.riebesell@gmail.com>
  • Loading branch information
3 people authored Jan 23, 2024
1 parent b5c7d06 commit f392c8d
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 17 deletions.
13 changes: 9 additions & 4 deletions pymatgen/analysis/magnetism/analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -481,10 +481,15 @@ def number_of_unique_magnetic_sites(self, symprec: float = 1e-3, angle_tolerance
@property
def ordering(self) -> Ordering:
"""Applies heuristics to return a magnetic ordering for a collinear
magnetic structure. Result is not guaranteed for correctness.
magnetic structure. Result is not guaranteed to be correct, just a best
guess. Tolerance for minimum total magnetization to be considered
ferro/ferrimagnetic is 1e-8.
Returns:
Ordering: Enum ('FiM' is used as the abbreviation for ferrimagnetic)
Ordering: Enum with values FM: ferromagnetic, FiM: ferrimagnetic,
AFM: antiferromagnetic, NM: non-magnetic or Unknown. Unknown is
returned if magnetic moments are not defined or structure is not collinear
(in which case a warning is issued).
"""
if not self.is_collinear:
warnings.warn("Detecting ordering in non-collinear structures not yet implemented.")
Expand All @@ -503,9 +508,9 @@ def ordering(self) -> Ordering:

is_potentially_ferromagnetic = np.all(magmoms >= 0) or np.all(magmoms <= 0)

if total_magnetization > 0 and is_potentially_ferromagnetic:
if abs(total_magnetization) > 1e-8 and is_potentially_ferromagnetic:
return Ordering.FM
if total_magnetization > 0:
if abs(total_magnetization) > 1e-8:
return Ordering.FiM
if max_magmom > 0:
return Ordering.AFM
Expand Down
34 changes: 21 additions & 13 deletions tests/analysis/magnetism/test_analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ def setUp(self):

self.NiO_expt = Structure.from_file(f"{TEST_FILES_DIR}/magnetic.example.NiO.mcif", primitive=True)

# CuO.mcif sourced from https://www.cryst.ehu.es/magndata/index.php?index=1.62
# doi: 10.1088/0022-3719/21/15/023
self.CuO_expt = Structure.from_file(f"{TEST_FILES_DIR}/magnetic.example.CuO.mcif.gz", primitive=True)

lattice = Lattice.cubic(4.17)
species = ["Ni", "O"]
coords = [[0, 0, 0], [0.5, 0.5, 0.5]]
Expand Down Expand Up @@ -161,28 +165,32 @@ def test_get_ferromagnetic_structure(self):
assert CollinearMagneticStructureAnalyzer(s1).matches_ordering(s2_prim)

def test_magnetic_properties(self):
msa = CollinearMagneticStructureAnalyzer(self.GdB4)
assert not msa.is_collinear
mag_struct_analyzer = CollinearMagneticStructureAnalyzer(self.GdB4)
assert not mag_struct_analyzer.is_collinear

msa = CollinearMagneticStructureAnalyzer(self.Fe)
assert not msa.is_magnetic
mag_struct_analyzer = CollinearMagneticStructureAnalyzer(self.Fe)
assert not mag_struct_analyzer.is_magnetic

self.Fe.add_site_property("magmom", [5])

msa = CollinearMagneticStructureAnalyzer(self.Fe)
assert msa.is_magnetic
assert msa.is_collinear
assert msa.ordering == Ordering.FM
mag_struct_analyzer = CollinearMagneticStructureAnalyzer(self.Fe)
assert mag_struct_analyzer.is_magnetic
assert mag_struct_analyzer.is_collinear
assert mag_struct_analyzer.ordering == Ordering.FM

msa = CollinearMagneticStructureAnalyzer(
mag_struct_analyzer = CollinearMagneticStructureAnalyzer(
self.NiO,
make_primitive=False,
overwrite_magmom_mode="replace_all_if_undefined",
)
assert msa.number_of_magnetic_sites == 4
assert msa.number_of_unique_magnetic_sites() == 1
assert msa.types_of_magnetic_species == (Element.Ni,)
assert msa.get_exchange_group_info() == ("Fm-3m", 225)
assert mag_struct_analyzer.number_of_magnetic_sites == 4
assert mag_struct_analyzer.number_of_unique_magnetic_sites() == 1
assert mag_struct_analyzer.types_of_magnetic_species == (Element.Ni,)
assert mag_struct_analyzer.get_exchange_group_info() == ("Fm-3m", 225)

# https://github.com/materialsproject/pymatgen/pull/3574
mag_struct_analyzer = CollinearMagneticStructureAnalyzer(self.CuO_expt)
assert mag_struct_analyzer.ordering == Ordering.AFM

def test_str(self):
msa = CollinearMagneticStructureAnalyzer(self.NiO_AFM_001)
Expand Down
Binary file added tests/files/magnetic.example.CuO.mcif.gz
Binary file not shown.

0 comments on commit f392c8d

Please sign in to comment.