Skip to content

Commit 0c04d1b

Browse files
Bump chgnet from 0.3.8 to 0.4.0 (#990)
* Bump chgnet from 0.3.8 to 0.4.0 Bumps [chgnet](https://github.com/CederGroupHub/chgnet) from 0.3.8 to 0.4.0. - [Release notes](https://github.com/CederGroupHub/chgnet/releases) - [Commits](CederGroupHub/chgnet@v0.3.8...v0.4.0) --- updated-dependencies: - dependency-name: chgnet dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <[email protected]> * strict-forcefields bump torch==2.2.1 -> 2.4.1 for chgnet compat --------- Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Janosh Riebesell <[email protected]>
1 parent 00a5405 commit 0c04d1b

File tree

11 files changed

+71
-70
lines changed

11 files changed

+71
-70
lines changed

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,12 +118,12 @@ strict = [
118118
]
119119
strict-forcefields = [
120120
"calorine==2.2.1",
121-
"chgnet==0.3.8",
121+
"chgnet==0.4.0",
122122
"mace-torch>=0.3.3",
123123
"matgl==1.1.3",
124124
"quippy-ase==0.9.14; python_version < '3.12'",
125125
"sevenn==0.9.3.post1",
126-
"torch==2.2.1",
126+
"torch==2.4.1",
127127
"torchdata==0.7.1", # TODO: remove when issue fixed
128128
]
129129

src/atomate2/forcefields/utils.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def ase_calculator(calculator_meta: str | dict, **kwargs: Any) -> Calculator | N
4242
"""
4343
calculator = None
4444

45-
if isinstance(calculator_meta, str) and calculator_meta in map(str, MLFF):
45+
if isinstance(calculator_meta, str | MLFF) and calculator_meta in map(str, MLFF):
4646
calculator_name = MLFF(calculator_meta.split("MLFF.")[-1])
4747

4848
if calculator_name == MLFF.CHGNet:
@@ -88,7 +88,7 @@ def ase_calculator(calculator_meta: str | dict, **kwargs: Any) -> Calculator | N
8888
calculator = calc_cls(**kwargs)
8989

9090
if calculator is None:
91-
raise ValueError("Could not create ASE calculator.")
91+
raise ValueError(f"Could not create ASE calculator for {calculator_meta}.")
9292

9393
return calculator
9494

src/atomate2/qchem/drones.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
"""Drones for parsing VASP calculations and realtd outputs."""
1+
"""Drones for parsing VASP calculations and related outputs."""
22

33
from __future__ import annotations
44

@@ -69,15 +69,15 @@ def get_valid_paths(self, path: tuple[str, list[str], list[str]]) -> list[str]:
6969
parent, subdirs, _ = path
7070
task_names = ["mol.qout.*"]
7171
combined_paths = [parent + os.sep + sdir for sdir in subdirs]
72-
rpath = []
73-
for cpath in combined_paths:
74-
fnames = os.listdir(cpath)
75-
if any(name.startswith("mol.qout.") for name in fnames):
76-
rpath.append(parent)
72+
valid_paths = []
73+
for sub_dir in combined_paths:
74+
file_names = os.listdir(sub_dir)
75+
if any(name.startswith("mol.qout.") for name in file_names):
76+
valid_paths.append(parent)
7777

7878
if (
7979
not any(parent.endswith(os.sep + r) for r in task_names)
8080
and len(list(Path(parent).glob("mol.qout*"))) > 0
8181
):
82-
rpath.append(parent)
83-
return rpath
82+
valid_paths.append(parent)
83+
return valid_paths

tests/aims/test_flows/test_anharmonic_quantification.py

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,7 @@ def test_anharmonic_quantification_oneshot(si, clean_dir, mock_aims, species_dir
6060
phonon_maker=phonon_maker,
6161
)
6262
maker.name = "anharmonicity"
63-
flow = maker.make(
64-
si,
65-
supercell_matrix=np.array([-1, 1, 1, 1, -1, 1, 1, 1, -1]).reshape((3, 3)),
66-
)
63+
flow = maker.make(si, supercell_matrix=np.ones((3, 3)) - 2 * np.eye(3))
6764

6865
# run the flow or job and ensure that it finished running successfully
6966
responses = run_locally(flow, create_folders=True, ensure_success=True)
@@ -120,7 +117,7 @@ def test_anharmonic_quantification_full(si, clean_dir, mock_aims, species_dir):
120117
maker.name = "anharmonicity"
121118
flow = maker.make(
122119
si,
123-
supercell_matrix=np.array([-1, 1, 1, 1, -1, 1, 1, 1, -1]).reshape((3, 3)),
120+
supercell_matrix=np.ones((3, 3)) - 2 * np.eye(3),
124121
one_shot_approx=False,
125122
seed=1234,
126123
)
@@ -254,9 +251,7 @@ def test_site_resolved_anharmonic_quantification(
254251
)
255252
maker.name = "anharmonicity"
256253
flow = maker.make(
257-
nacl,
258-
supercell_matrix=np.array([-1, 1, 1, 1, -1, 1, 1, 1, -1]).reshape((3, 3)),
259-
site_resolved=True,
254+
nacl, supercell_matrix=np.ones((3, 3)) - 2 * np.eye(3), site_resolved=True
260255
)
261256

262257
# run the flow or job and ensure that it finished running successfully
@@ -323,7 +318,7 @@ def test_element_resolved_anharmonic_quantification(
323318
maker.name = "anharmonicity"
324319
flow = maker.make(
325320
nacl,
326-
supercell_matrix=np.array([-1, 1, 1, 1, -1, 1, 1, 1, -1]).reshape((3, 3)),
321+
supercell_matrix=np.ones((3, 3)) - 2 * np.eye(3),
327322
element_resolved=True,
328323
)
329324

@@ -372,10 +367,7 @@ def test_anharmonic_quantification_socket_oneshot(si, clean_dir, species_dir):
372367
phonon_maker=phonon_maker,
373368
)
374369
maker.name = "anharmonicity"
375-
flow = maker.make(
376-
si,
377-
supercell_matrix=np.array([-1, 1, 1, 1, -1, 1, 1, 1, -1]).reshape((3, 3)),
378-
)
370+
flow = maker.make(si, supercell_matrix=np.ones((3, 3)) - 2 * np.eye(3))
379371

380372
# run the flow or job and ensure that it finished running successfully
381373
responses = run_locally(flow, create_folders=True, ensure_success=True)

tests/aims/test_flows/test_phonon_workflow.py

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,7 @@ def test_phonon_flow(si, clean_dir, mock_aims, species_dir):
4848
),
4949
)
5050
maker.name = "phonons"
51-
flow = maker.make(
52-
si,
53-
supercell_matrix=np.array([-1, 1, 1, 1, -1, 1, 1, 1, -1]).reshape((3, 3)),
54-
)
51+
flow = maker.make(si, supercell_matrix=np.ones((3, 3)) - 2 * np.eye(3))
5552

5653
# run the flow or job and ensure that it finished running successfully
5754
responses = run_locally(flow, create_folders=True, ensure_success=True)
@@ -142,10 +139,7 @@ def test_phonon_socket_flow(si, clean_dir, mock_aims, species_dir):
142139
),
143140
)
144141
maker.name = "phonons"
145-
flow = maker.make(
146-
si,
147-
supercell_matrix=np.array([-1, 1, 1, 1, -1, 1, 1, 1, -1]).reshape((3, 3)),
148-
)
142+
flow = maker.make(si, supercell_matrix=np.ones((3, 3)) - 2 * np.eye(3))
149143

150144
# run the flow or job and ensure that it finished running successfully
151145
responses = run_locally(flow, create_folders=True, ensure_success=True)
@@ -212,10 +206,8 @@ def test_phonon_default_flow(si, clean_dir, mock_aims, species_dir):
212206

213207
maker = PhononMaker()
214208
maker.name = "phonons"
215-
flow = maker.make(
216-
si,
217-
supercell_matrix=np.array([-1, 1, 1, 1, -1, 1, 1, 1, -1]).reshape((3, 3)),
218-
)
209+
supercell_matrix = np.ones((3, 3)) - 2 * np.eye(3)
210+
flow = maker.make(si, supercell_matrix=supercell_matrix)
219211

220212
# run the flow or job and ensure that it finished running successfully
221213
responses = run_locally(flow, create_folders=True, ensure_success=True)
@@ -288,10 +280,7 @@ def test_phonon_default_socket_flow(si, clean_dir, mock_aims, species_dir):
288280

289281
maker = PhononMaker(socket=True)
290282
maker.name = "phonons"
291-
flow = maker.make(
292-
si,
293-
supercell_matrix=np.array([-1, 1, 1, 1, -1, 1, 1, 1, -1]).reshape((3, 3)),
294-
)
283+
flow = maker.make(si, supercell_matrix=np.ones((3, 3)) - 2 * np.eye(3))
295284

296285
# run the flow or job and ensure that it finished running successfully
297286
responses = run_locally(flow, create_folders=True, ensure_success=True)

tests/ase/test_jobs.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ def test_lennard_jones_relax_maker(lj_fcc_ne_pars, fcc_ne_structure):
3333
assert output.structure.volume == pytest.approx(22.304245)
3434
assert output.output.energy == pytest.approx(-0.018494767)
3535
assert isinstance(output, AseStructureTaskDoc)
36+
assert fcc_ne_structure.matches(
37+
output.structure
38+
), f"{output.structure} != {fcc_ne_structure}"
3639

3740

3841
def test_lennard_jones_static_maker(lj_fcc_ne_pars, fcc_ne_structure):
@@ -46,8 +49,12 @@ def test_lennard_jones_static_maker(lj_fcc_ne_pars, fcc_ne_structure):
4649
assert output.structure.volume == pytest.approx(24.334)
4750
assert isinstance(output, AseStructureTaskDoc)
4851

52+
# Structure.__eq__ checks properties which contains 'energy', 'forces', 'stress'
53+
# so need to reset properties to ensure equality
4954
output.structure.properties = fcc_ne_structure.properties
50-
assert output.structure == fcc_ne_structure
55+
assert (
56+
output.structure == fcc_ne_structure
57+
), f"{output.structure} != {fcc_ne_structure}"
5158

5259

5360
@pytest.mark.skipif(condition=TBLite is None, reason="TBLite must be installed.")
@@ -94,9 +101,7 @@ def test_gfn_xtb_relax_maker(h2o_3uud_trimer):
94101
def test_gfn_xtb_static_maker(h2o_3uud_trimer):
95102
os.environ["OMP_NUM_THREADS"] = "1"
96103
job = GFNxTBStaticMaker(
97-
calculator_kwargs={
98-
"method": "GFN2-xTB",
99-
},
104+
calculator_kwargs={"method": "GFN2-xTB"},
100105
).make(h2o_3uud_trimer)
101106

102107
response = run_locally(job)
@@ -105,5 +110,7 @@ def test_gfn_xtb_static_maker(h2o_3uud_trimer):
105110
assert output.output.energy_per_atom == pytest.approx(-46.05920227158222)
106111
assert isinstance(output, AseMoleculeTaskDoc)
107112

113+
# Molecule.__eq__ checks properties which contains 'energy', 'forces', 'stress'
114+
# so need to reset properties to ensure equality
108115
output.molecule.properties = h2o_3uud_trimer.properties
109116
assert output.molecule == h2o_3uud_trimer

tests/forcefields/flows/test_eos.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@
66
from atomate2.forcefields.flows.eos import (
77
CHGNetEosMaker,
88
ForceFieldEosMaker,
9-
M3GNetEosMaker,
9+
# M3GNetEosMaker,
1010
MACEEosMaker,
1111
)
1212

1313
ff_maker_map = {
1414
MLFF.CHGNet.value: CHGNetEosMaker,
15-
MLFF.M3GNet.value: M3GNetEosMaker,
15+
# skip m3gnet due M3GNet requiring DGL which is PyTorch 2.4 incompatible
16+
# raises "FileNotFoundError: Cannot find DGL C++ libgraphbolt_pytorch_2.4.1.so"
17+
# MLFF.M3GNet.value: M3GNetEosMaker,
1618
MLFF.MACE.value: MACEEosMaker,
1719
}
1820

tests/forcefields/test_jobs.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ def test_chgnet_relax_maker(si_structure: Structure, relax_cell: bool):
132132
CHGNetRelaxMaker()
133133

134134

135+
@pytest.mark.skip(reason="M3GNet requires DGL which is PyTorch 2.4 incompatible")
135136
def test_m3gnet_static_maker(si_structure):
136137
# generate job
137138
job = ForceFieldStaticMaker(
@@ -154,6 +155,7 @@ def test_m3gnet_static_maker(si_structure):
154155
M3GNetStaticMaker()
155156

156157

158+
@pytest.mark.skip(reason="M3GNet requires DGL which is PyTorch 2.4 incompatible")
157159
def test_m3gnet_relax_maker(si_structure):
158160
# translate one atom to ensure a small number of relaxation steps are taken
159161
si_structure.translate_sites(0, [0, 0, 0.1])

tests/forcefields/test_md.py

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from pymatgen.analysis.structure_matcher import StructureMatcher
1414
from pymatgen.core import Structure
1515

16+
from atomate2.forcefields import MLFF
1617
from atomate2.forcefields.md import (
1718
CHGNetMDMaker,
1819
ForceFieldMDMaker,
@@ -24,12 +25,12 @@
2425
)
2526

2627
name_to_maker = {
27-
"CHGNet": CHGNetMDMaker,
28-
"M3GNet": M3GNetMDMaker,
29-
"MACE": MACEMDMaker,
30-
"GAP": GAPMDMaker,
31-
"NEP": NEPMDMaker,
32-
"Nequip": NequipMDMaker,
28+
MLFF.CHGNet: CHGNetMDMaker,
29+
MLFF.M3GNet: M3GNetMDMaker,
30+
MLFF.MACE: MACEMDMaker,
31+
MLFF.GAP: GAPMDMaker,
32+
MLFF.NEP: NEPMDMaker,
33+
MLFF.Nequip: NequipMDMaker,
3334
}
3435

3536

@@ -47,40 +48,42 @@ def test_maker_initialization():
4748
)
4849

4950

50-
@pytest.mark.parametrize(
51-
"ff_name",
52-
["CHGNet", "M3GNet", "MACE", "GAP", "NEP", "Nequip"],
53-
)
51+
@pytest.mark.parametrize("ff_name", MLFF)
5452
def test_ml_ff_md_maker(
5553
ff_name, si_structure, sr_ti_o3_structure, al2_au_structure, test_dir, clean_dir
5654
):
57-
if ff_name == "GAP" and sys.version_info >= (3, 12):
55+
if ff_name == MLFF.Forcefield:
56+
return # nothing to test here, MLFF.Forcefield is just a generic placeholder
57+
if ff_name == MLFF.GAP and sys.version_info >= (3, 12):
5858
pytest.skip(
5959
"GAP model not compatible with Python 3.12, waiting on https://github.com/libAtoms/QUIP/issues/645"
6060
)
61+
if ff_name == MLFF.M3GNet:
62+
pytest.skip("M3GNet requires DGL which is PyTorch 2.4 incompatible")
6163

6264
n_steps = 5
6365

6466
ref_energies_per_atom = {
65-
"CHGNet": -5.280157089233398,
66-
"M3GNet": -5.387282371520996,
67-
"MACE": -5.311369895935059,
68-
"GAP": -5.391255755606209,
69-
"NEP": -3.966232215741286,
70-
"Nequip": -8.84670181274414,
67+
MLFF.CHGNet: -5.280157089233398,
68+
MLFF.M3GNet: -5.387282371520996,
69+
MLFF.MACE: -5.311369895935059,
70+
MLFF.GAP: -5.391255755606209,
71+
MLFF.NEP: -3.966232215741286,
72+
MLFF.Nequip: -8.84670181274414,
73+
MLFF.SevenNet: -5.394115447998047,
7174
}
7275

7376
# ASE can slightly change tolerances on structure positions
7477
matcher = StructureMatcher()
7578

7679
calculator_kwargs = {}
7780
unit_cell_structure = si_structure.copy()
78-
if ff_name == "GAP":
81+
if ff_name == MLFF.GAP:
7982
calculator_kwargs = {
8083
"args_str": "IP GAP",
8184
"param_filename": str(test_dir / "forcefields" / "gap" / "gap_file.xml"),
8285
}
83-
elif ff_name == "NEP":
86+
elif ff_name == MLFF.NEP:
8487
# NOTE: The test NEP model is specifically trained on 16 elemental metals
8588
# thus a new Al2Au structure is added.
8689
# The NEP model used for the tests is licensed under a
@@ -91,7 +94,7 @@ def test_ml_ff_md_maker(
9194
"model_filename": test_dir / "forcefields" / "nep" / "nep.txt"
9295
}
9396
unit_cell_structure = al2_au_structure.copy()
94-
elif ff_name == "Nequip":
97+
elif ff_name == MLFF.Nequip:
9598
calculator_kwargs = {
9699
"model_path": test_dir / "forcefields" / "nequip" / "nequip_ff_sr_ti_o3.pth"
97100
}
@@ -137,9 +140,9 @@ def test_ml_ff_md_maker(
137140
for key in ("energy", "forces", "stress", "velocities", "temperature")
138141
for step in task_doc.objects["trajectory"].frame_properties
139142
)
140-
141-
with pytest.warns(FutureWarning):
142-
name_to_maker[ff_name]()
143+
if ff_maker := name_to_maker.get(ff_name):
144+
with pytest.warns(FutureWarning):
145+
ff_maker()
143146

144147

145148
@pytest.mark.parametrize("traj_file", ["trajectory.json.gz", "atoms.traj"])

tests/forcefields/test_phonon.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,11 @@ def test_phonon_maker_initialization_with_all_mlff(
6464
if mlff in {MLFF.GAP, MLFF.Forcefield}:
6565
continue # TODO fix GAP, currently fails with RuntimeError, see
6666
# https://github.com/materialsproject/atomate2/pull/918#issuecomment-2253659694
67+
# skip m3gnet due M3GNet requiring DGL which is PyTorch 2.4 incompatible
68+
# raises "FileNotFoundError: Cannot find DGL C++ libgraphbolt_pytorch_2.4.1.so"
69+
if mlff == MLFF.M3GNet:
70+
continue
71+
6772
calc_kwargs = {
6873
MLFF.Nequip: {"model_path": f"{chk_pt_dir}/nequip/nequip_ff_sr_ti_o3.pth"},
6974
MLFF.NEP: {"model_filename": f"{test_dir}/forcefields/nep/nep.txt"},

0 commit comments

Comments
 (0)