-
Notifications
You must be signed in to change notification settings - Fork 11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Generate Aflow structure prototype labels with moyopy
#96
base: main
Are you sure you want to change the base?
Conversation
…mmetry detection moyopy is faster and potentially safer since written in rust
…atch still seems wrong for moyopy. Remove fallback from moyopy as without spglib structure refinement it won't do anything.
- refactor moyopy import handling - print offending structure in error messages test_wyckoff_ops assert messages
9 out of 11 tests passing after 57372af. of the 2 still failing, the first still seems to have differently ordered Wyckoff letters despite my "fix". the 2nd seems more concerning as it gives an unexpected letter. pinging @lan496 in case you notice some misuse of @pytest.mark.parametrize("structure, expected", zip(TEST_STRUCTS, TEST_PROTOSTRUCTURES))
def test_get_protostructure_label_from_moyopy(structure, expected):
"""Check that moyopy gives correct protostructure label simple cases."""
> assert get_protostructure_label_from_moyopy(structure) == expected, (
f"unexpected moyopy protostructure for {structure=}"
)
E AssertionError: unexpected moyopy protostructure for structure=Structure Summary
E Lattice
E abc : 3.9 3.9 3.9
E angles : 90.0 90.0 90.0
E volume : 59.318999999999996
E A : 3.9 0.0 0.0
E B : 0.0 3.9 0.0
E C : 0.0 0.0 3.9
E pbc : True True True
E PeriodicSite: Sr (0.0, 0.0, 0.0) [0.0, 0.0, 0.0]
E PeriodicSite: Ti (1.95, 1.95, 1.95) [0.5, 0.5, 0.5]
E PeriodicSite: O (1.95, 1.95, 0.0) [0.5, 0.5, 0.0]
E PeriodicSite: O (1.95, 0.0, 1.95) [0.5, 0.0, 0.5]
E PeriodicSite: O (0.0, 1.95, 1.95) [0.0, 0.5, 0.5]
E assert 'A3BC_cP5_221_c_a_b:O-Sr-Ti' == 'AB3C_cP5_221_a_c_b:O-Sr-Ti'
E
E - AB3C_cP5_221_a_c_b:O-Sr-Ti
E ? - --
E + A3BC_cP5_221_c_a_b:O-Sr-Ti
E ? + ++
tests/test_wyckoff_ops.py:370: AssertionError
_ test_moyopy_spglib_consistency[ABC6D2_mC40_15_e_a_3f_f:Ca-Fe-O-Si] _
protostructure = 'ABC6D2_mC40_15_e_a_3f_f:Ca-Fe-O-Si'
@pytest.mark.parametrize(
"protostructure",
PROTOSTRUCTURE_SET,
)
def test_moyopy_spglib_consistency(protostructure):
"""Check that moyopy and spglib give consistent results."""
struct = get_random_structure_for_protostructure(protostructure)
moyopy_label = get_protostructure_label_from_moyopy(struct)
spglib_label = get_protostructure_label_from_spglib(struct)
> assert moyopy_label == spglib_label, (
f"spglib moyopy protostructure mismatch for {protostructure}"
)
E AssertionError: spglib moyopy protostructure mismatch for ABC6D2_mC40_15_e_a_3f_f:Ca-Fe-O-Si
E assert 'ABC6D2_mC40_..._f:Ca-Fe-O-Si' == 'ABC6D2_mC40_..._f:Ca-Fe-O-Si'
E
E - ABC6D2_mC40_15_e_a_3f_f:Ca-Fe-O-Si
E ? ^
E + ABC6D2_mC40_15_e_c_3f_f:Ca-Fe-O-Si
E ? ^
tests/test_wyckoff_ops.py:386: AssertionError |
@janosh Thank you for letting me know! LGTM for moyopy usage. For STO (Pm-3m) case, Wyckoff positions 4a and 4b are equivalent, which may related to the failed test. For monoclinic CaMgO6Si2 (C2/c) case, Wyckoff positions 4a, 4b, 4c, and 4d belong to the same Wyckoff set |
The protostructure label here is a superset of the aflow label, it's constructed as
We have this |
on the topic of upstreaming things into def get_crystal_system(n: int) -> str:
"""Get the crystal system for the structure, e.g. (triclinic, orthorhombic,
cubic, etc.).
Mirrors method of SpacegroupAnalyzer.get_crystal_system().
Args:
n (int): Space group number
Raises:
ValueError: on invalid space group numbers < 1 or > 230.
Returns:
str: Crystal system for structure
"""
# Not using isinstance(n, int) to allow 0-decimal floats
if n != int(n) or not 0 < n < 231:
raise ValueError(f"Received invalid space group {n}")
if 0 < n < 3:
return "triclinic"
if n < 16:
return "monoclinic"
if n < 75:
return "orthorhombic"
if n < 143:
return "tetragonal"
if n < 168:
return "trigonal"
if n < 195:
return "hexagonal"
return "cubic" |
I got the same Wyckoff positions from spglib and moyopy for AB3C_cP5_221_a_c_b and ABC6D2_mC40_15_e_e_3f_f 🤔 Your tests seem to use pyxtal to randomly generate structures from Aflow's prototype label. Do you have a generated structure whose results of Wyckoff position assignment change in spglib and moyopy? from pymatgen.core import Structure
from pymatgen.symmetry.analyzer import SpacegroupAnalyzer
from spglib import get_symmetry_dataset
from moyopy import MoyoDataset
from moyopy.interface import MoyoAdapter
def main(structure: Structure) -> None:
for symprec in [1e-2, 1e-3, 1e-4, 1e-5]:
sga = SpacegroupAnalyzer(structure)
spglib_cell = sga._cell
spglib_dataset = get_symmetry_dataset(spglib_cell, symprec=symprec)
print(spglib_dataset.wyckoffs)
moyo_cell = MoyoAdapter.from_structure(structure)
moyo_dataset = MoyoDataset(moyo_cell, symprec=symprec)
print(moyo_dataset.wyckoffs)
assert spglib_dataset.wyckoffs == moyo_dataset.wyckoffs
if __name__ == '__main__':
# https://aflowlib.org/prototype-encyclopedia/AB3C_cP5_221_a_c_b-001/
# Pm-3m (No. 221)
# Ca (1a)
# O (3c)
# Ti (1b)
# structure = Structure.from_file('AB3C_cP5_221_a_c_b-001.cif')
# https://aflowlib.org/prototype-encyclopedia/ABC6D2_mC40_15_e_e_3f_f-001/
# C2/c (No. 15)
# Ca (4e)
# Fe (4e)
# O1 (8f)
# O2 (8f)
# O3 (8f)
# Si (8f)
structure = Structure.from_file('ABC6D2_mC40_15_e_e_3f_f-001.cif')
print(structure)
main(structure) |
@lan496 thanks for taking a look. really appreciate your help. 👍 here are 2 CIF files that currently yield different results for import os
import warnings
from collections import Counter
from glob import glob
import moyopy
import spglib
from moyopy.interface import MoyoAdapter
from pymatgen.core import Structure
from aviary.wren.utils import (
get_protostructure_label_from_moyopy,
get_protostructure_label_from_spglib,
)
warnings.filterwarnings("ignore", category=DeprecationWarning, module="spglib")
# Directory containing debug structures
debug_dir = "tests/debug_structures"
# Load and analyze all CIF files
for cif_path in glob(os.path.join(debug_dir, "*.cif")):
# Load structure
structure = Structure.from_file(cif_path)
# Get labels from both methods
moyopy_label = get_protostructure_label_from_moyopy(structure)
spglib_label = get_protostructure_label_from_spglib(structure)
# Get detailed moyopy info
symprec = 1e-4
moyo_cell = MoyoAdapter.from_structure(structure)
moyo_data = moyopy.MoyoDataset(moyo_cell, symprec=symprec)
spglib_cell = (
structure.lattice.matrix,
structure.frac_coords,
structure.atomic_numbers,
)
spglib_data = spglib.get_symmetry_dataset(spglib_cell, symprec=symprec)
# Print results if they differ, delete file if they agree
if moyopy_label != spglib_label:
print(f"Structure: {structure.composition.reduced_formula}")
spglib_wyckoff_counts = Counter(spglib_data.wyckoffs)
spglib_wyckoff_str = " ".join(
f"{letter}{count}" for letter, count in spglib_wyckoff_counts.items()
)
print(f"{spglib_wyckoff_str=}")
moyo_wyckoff_counts = Counter(moyo_data.wyckoffs)
moyo_wyckoff_str = " ".join(
f"{letter}{count}" for letter, count in moyo_wyckoff_counts.items()
)
print(f"{moyo_wyckoff_str=}")
diff1 = dict(moyo_wyckoff_counts - spglib_wyckoff_counts)
diff2 = dict(spglib_wyckoff_counts - moyo_wyckoff_counts)
print(f"differences: + {diff1} - {diff2}")
print("Aflow labels:")
print(f"Moyopy: {moyopy_label}")
print(f"Spglib: {spglib_label}")
print("-" * 80)
else:
os.remove(cif_path)
print(f"Deleted {os.path.basename(cif_path)} - labels match") |
Thank you! I've reproduced the mC40 structure gives difference wyckoff positions by spglib and moyopy (although they may still be equivalent up to Wyckoff sets). I'll look into what is happening. |
Can you try |
i bumped to 0.3.1 in CI 4d885bc
|
For Wurtzite ZnO case, For ABC6D2_mC40_15.cif, spglib and moyopy return the same wyckoff sequences in my environment.
Hmm..., moyopy still has some edge cases for monoclinic. |
I see. Some random structure by pyxtal gives an edge case
this structure results in different labels:
In this case, moyopy looks to be correct: Ca (4e, y=0.57414) and Fe (4a). Things become complicated... |
adds new function
get_protostructure_label_from_moyopy
inaviary/wren/utils.py
(followingget_protostructure_label_from_spglib
signature)