Skip to content

Commit fe8fd70

Browse files
authored
Merge branch 'main' into main
2 parents 39ca4af + 5d83fe7 commit fe8fd70

File tree

16 files changed

+287
-95
lines changed

16 files changed

+287
-95
lines changed

CHANGELOG.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,55 @@
11
# Change log
22

3+
## v0.0.21
4+
5+
### Bug Fixes 🐛
6+
* switch to CONTCAR read for LOBSTERTaskDoc by @naik-aakash in https://github.com/materialsproject/atomate2/pull/1204
7+
* cover cases where optimizer does additional steps even though step is set to 0 or 1 for writing xyz files by @JaGeo in https://github.com/materialsproject/atomate2/pull/1207
8+
* Remove walrus operator to avoid unassigned vmax by @Jonas-Finkler in https://github.com/materialsproject/atomate2/pull/1203
9+
### Enhancements 🛠
10+
* add file output xyz file including final atoms object to ase and forcefield jobs by @JaGeo in https://github.com/materialsproject/atomate2/pull/1206
11+
### Documentation 📖
12+
* Add video tutorials to README by @JaGeo in https://github.com/materialsproject/atomate2/pull/1191
13+
* be more concrete for tutorial video names in readme by @JaGeo in https://github.com/materialsproject/atomate2/pull/1192
14+
* Adding download statistics to readme by @JaGeo in https://github.com/materialsproject/atomate2/pull/1209
15+
16+
## New Contributors
17+
* @Jonas-Finkler made their first contribution in https://github.com/materialsproject/atomate2/pull/1203
18+
19+
**Full Changelog**: https://github.com/materialsproject/atomate2/compare/v0.0.20...v0.0.21
20+
21+
## v0.0.20
22+
23+
### Enhancements 🛠
24+
* Add MatPES forcefields by @esoteric-ephemera in https://github.com/materialsproject/atomate2/pull/1158
25+
* Add `DynamicOpenMMFlowMaker` for dynamic OpenMM Simulations by @shehan807 in https://github.com/materialsproject/atomate2/pull/1115
26+
* atomate2 / OpenMM OPLS-AA Enhancements by @shehan807 in https://github.com/materialsproject/atomate2/pull/1111
27+
* Add updated MP workflows + cleanup by @esoteric-ephemera in https://github.com/materialsproject/atomate2/pull/1139
28+
### Documentation 📖
29+
* Improve documentation LOBSTER and PHONON workflow by @JaGeo in https://github.com/materialsproject/atomate2/pull/1117
30+
* Add key concept tutorial to tutorial list in README by @QuantumChemist in https://github.com/materialsproject/atomate2/pull/1120
31+
* Fixing headline levels in key_concepts_overview.md by @QuantumChemist in https://github.com/materialsproject/atomate2/pull/1121
32+
* try to fix the doc by @JaGeo in https://github.com/materialsproject/atomate2/pull/1125
33+
* Added code snippets for Grüneisen, QHA and EOS wfs documentation by @QuantumChemist in https://github.com/materialsproject/atomate2/pull/1130
34+
* a few improvements for the tutorials by @QuantumChemist in https://github.com/materialsproject/atomate2/pull/1132
35+
* Update tutorials.md by @JaGeo in https://github.com/materialsproject/atomate2/pull/1138
36+
* Electrode workflow and documentation improvements by @esoteric-ephemera in https://github.com/materialsproject/atomate2/pull/1055
37+
* Update index.md by @JaGeo in https://github.com/materialsproject/atomate2/pull/1155
38+
### House-Keeping 🧹
39+
* More CI fixes by @esoteric-ephemera in https://github.com/materialsproject/atomate2/pull/1141
40+
### Other Changes
41+
* Pin MACE calculator version, add missing metadata to AseStructureTaskDoc by @esoteric-ephemera in https://github.com/materialsproject/atomate2/pull/1119
42+
* Tutorials for QHA and Grüneisen workflows by @JaGeo in https://github.com/materialsproject/atomate2/pull/1122
43+
* add more headlines to tutorials and fix a typo by @JaGeo in https://github.com/materialsproject/atomate2/pull/1126
44+
* Minor update to tutorials by @naik-aakash in https://github.com/materialsproject/atomate2/pull/1128
45+
* adjust example flow names by @QuantumChemist in https://github.com/materialsproject/atomate2/pull/1131
46+
* Aims phonon tutorials by @tpurcell90 in https://github.com/materialsproject/atomate2/pull/1136
47+
* fix gruneisen tutorial by @JaGeo in https://github.com/materialsproject/atomate2/pull/1142
48+
* fix link again for aims tutorial by @JaGeo in https://github.com/materialsproject/atomate2/pull/1143
49+
* Append name relax by @JaGeo in https://github.com/materialsproject/atomate2/pull/1150
50+
* add more info on jobflow-remote by @JaGeo in https://github.com/materialsproject/atomate2/pull/1154
51+
* Add example MP-compatible phase diagram tutorial by @esoteric-ephemera in https://github.com/materialsproject/atomate2/pull/1159
52+
353
## v0.0.19
454

555
### Bug Fixes 🐛

README.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44
[![code coverage](https://img.shields.io/codecov/c/gh/materialsproject/atomate2)](https://codecov.io/gh/materialsproject/atomate2)
55
[![pypi version](https://img.shields.io/pypi/v/atomate2?color=blue)](https://pypi.org/project/atomate2)
66
![supported python versions](https://img.shields.io/pypi/pyversions/atomate2)
7-
[![Zenodo](https://img.shields.io/badge/DOI-10.5281/zenodo.10677081-blue?logo=Zenodo&logoColor=white)](https://zenodo.org/records/10677081)
7+
[![Zenodo](https://img.shields.io/badge/DOI-10.5281/zenodo.10677080-blue?logo=Zenodo&logoColor=white)](https://doi.org/10.5281/zenodo.15603088)
88
[![This project supports Python 3.10+](https://img.shields.io/badge/Python-3.10+-blue.svg?logo=python&logoColor=white)](https://python.org/downloads)
9+
[![PyPI](https://img.shields.io/pypi/dm/atomate2.svg?maxAge=2592000)](https://pypi.python.org/pypi/atomate2)
910

1011
[Documentation][docs] | [PyPI][pypi] | [GitHub][github]
1112

@@ -98,6 +99,14 @@ started:
9899
- [Using atomate2 with FireWorks][atomate2_fireworks]
99100
- [Overview of key concepts][key-concepts]
100101
- [List of VASP workflows][vasp_workflows]
102+
- [Executable tutorials for different workflows][tutorials]
103+
104+
In March 2025, the first dedicated school on atomate2 (including the workflow language jobflow and the workflow manager jobflow-remote) took place, and one can access the video material here:
105+
106+
- [Jobflow and Jobflow-remote][videotutorial1]
107+
- [atomate2][videotutorial2]
108+
- [Advanced Workflows in atomate2: Part 1][videotutorial3]
109+
- [Advanced Workflows in atomate2: Part 2][videotutorial4]
101110

102111
## Need help?
103112

@@ -157,10 +166,15 @@ A journal submission of `atomate2` is undergoing peer review. In the meantime, p
157166
[atomate2_fireworks]: https://materialsproject.github.io/atomate2/user/fireworks.html
158167
[atomate2-jobflow-remote]: https://materialsproject.github.io/atomate2/user/jobflow-remote.html
159168
[vasp_workflows]: https://materialsproject.github.io/atomate2/user/codes/vasp.html
169+
[tutorials]: https://materialsproject.github.io/atomate2/tutorials/tutorials.html
160170
[RelaxBandStructure]: https://materialsproject.github.io/atomate2/user/codes/vasp.html#relax-and-band-structure
161171
[Lobster]: http://www.cohp.de
162172
[lobsterpy]: https://github.com/JaGeo/LobsterPy
163173
[phonopy]: https://github.com/phonopy/phonopy
164174
[docs]: https://materialsproject.github.io/atomate2/
165175
[github]: https://github.com/materialsproject/atomate2
166176
[pypi]: https://pypi.org/project/atomate2
177+
[videotutorial1]: https://lhumos.org/collection/0/680bb4d7e4b0f0d2028027ce
178+
[videotutorial2]: https://lhumos.org/collection/0/680bb4d3e4b0f0d2028027c9
179+
[videotutorial3]: https://lhumos.org/collection/0/680bb4d0e4b0f0d2028027c5
180+
[videotutorial4]: https://lhumos.org/collection/0/680bb4c7e4b0f0d2028027c1

pyproject.toml

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ dependencies = [
2828
"PyYAML",
2929
"click",
3030
"custodian>=2025.4.14",
31-
"emmet-core>=0.84.3rc3",
31+
"emmet-core>=0.84.8",
3232
"jobflow>=0.1.11",
3333
"monty>=2024.12.10",
3434
"numpy",
@@ -51,7 +51,7 @@ defects = [
5151
"python-ulid>=2.7",
5252
]
5353
forcefields = [
54-
"ase>=3.23.0",
54+
"ase>=3.25.0",
5555
"calorine>=3.0",
5656
"chgnet>=0.2.2",
5757
"mace-torch>=0.3.3",
@@ -62,7 +62,7 @@ forcefields = [
6262
"sevenn>=0.9.3",
6363
"torchdata<=0.7.1", # TODO: remove when issue fixed
6464
]
65-
ase = ["ase>=3.23.0"]
65+
ase = ["ase>=3.25.0"]
6666
ase-ext = ["tblite>=0.3.0; platform_system=='Linux'"]
6767
openmm = [
6868
"mdanalysis>=2.8.0",
@@ -81,7 +81,7 @@ docs = [
8181
"sphinx-copybutton==0.5.2",
8282
"sphinx==8.1.3",
8383
"sphinx_design==0.6.1",
84-
"jupyterlab==4.3.6",
84+
"jupyterlab==4.4.2",
8585
]
8686
dev = ["pre-commit>=2.12.1"]
8787
tests = [
@@ -94,20 +94,20 @@ tests = [
9494
]
9595
strict = [
9696
"PyYAML==6.0.2",
97-
"ase==3.24.0",
97+
"ase==3.25.0",
9898
"cclib==1.8.1",
99-
"click==8.1.7",
99+
"click==8.2.0",
100100
"custodian==2025.4.14",
101101
"dscribe==2.1.1",
102-
"emmet-core==0.84.5",
103-
"ijson==3.3.0",
102+
"emmet-core==0.84.8",
103+
"ijson==3.4.0",
104104
"jobflow==0.1.19",
105105
"lobsterpy==0.4.9",
106106
"monty==2025.3.3",
107-
"mp-api==0.45.4",
107+
"mp-api==0.45.7",
108108
"numpy",
109109
"phonopy==2.30.1",
110-
"pydantic-settings==2.8.1",
110+
"pydantic-settings==2.9.1",
111111
"pydantic==2.11.3",
112112
"pymatgen-analysis-defects==2025.1.18",
113113
"pymatgen==2025.2.18",

src/atomate2/ase/jobs.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ def run_ase(
254254
if self.steps < 0:
255255
logger.warning(
256256
"WARNING: A negative number of steps is not possible. "
257-
"Behavior may vary..."
257+
"Defaulting to a static calculation."
258258
)
259259

260260
relaxer = AseRelaxer(

src/atomate2/ase/utils.py

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
from ase.constraints import FixSymmetry
1717
from ase.filters import FrechetCellFilter
1818
from ase.io import Trajectory as AseTrajectory
19+
from ase.io import write as ase_write
1920
from ase.optimize import BFGS, FIRE, LBFGS, BFGSLineSearch, LBFGSLineSearch, MDMin
2021
from ase.optimize.sciopt import SciPyFminBFGS, SciPyFminCG
2122
from monty.serialization import dumpfn
@@ -328,14 +329,18 @@ def relax(
328329
fmax: float = 0.1,
329330
steps: int = 500,
330331
traj_file: str = None,
332+
final_atoms_object_file: str | os.PathLike[str] = "final_atoms_object.xyz",
331333
interval: int = 1,
332334
verbose: bool = False,
333335
cell_filter: Filter = FrechetCellFilter,
336+
filter_kwargs: dict | None = None,
334337
**kwargs,
335338
) -> AseResult:
336339
"""
337340
Relax the molecule or structure.
338341
342+
If steps <= 1, this will perform a single-point calculation.
343+
339344
Parameters
340345
----------
341346
atoms : ASE Atoms, pymatgen Structure, or pymatgen Molecule
@@ -346,6 +351,8 @@ def relax(
346351
Max number of steps for relaxation.
347352
traj_file : str
348353
The trajectory file for saving.
354+
final_atoms_object_file: str | os.PathLike
355+
The final atoms object file for saving.
349356
interval : int
350357
The step interval for saving the trajectories.
351358
verbose : bool
@@ -363,19 +370,23 @@ def relax(
363370

364371
if isinstance(atoms, Structure | Molecule):
365372
atoms = self.ase_adaptor.get_atoms(atoms)
373+
374+
input_atoms = atoms.copy()
366375
if self.fix_symmetry:
367376
atoms.set_constraint(FixSymmetry(atoms, symprec=self.symprec))
368377
atoms.calc = self.calculator
369378
with contextlib.redirect_stdout(sys.stdout if verbose else io.StringIO()):
370379
obs = TrajectoryObserver(atoms)
371-
if self.relax_cell and (not is_mol):
372-
atoms = cell_filter(atoms)
373-
optimizer = self.opt_class(atoms, **kwargs)
374-
optimizer.attach(obs, interval=interval)
375380
t_i = time.perf_counter()
376-
optimizer.run(fmax=fmax, steps=steps)
377-
t_f = time.perf_counter()
381+
if steps > 1:
382+
if self.relax_cell and (not is_mol):
383+
atoms = cell_filter(atoms, **(filter_kwargs or {}))
384+
optimizer = self.opt_class(atoms, **kwargs)
385+
optimizer.attach(obs, interval=interval)
386+
optimizer.run(fmax=fmax, steps=steps)
378387
obs()
388+
t_f = time.perf_counter()
389+
379390
if traj_file is not None:
380391
obs.save(traj_file)
381392
if isinstance(atoms, cell_filter):
@@ -389,6 +400,17 @@ def relax(
389400
np.linalg.norm(traj.frame_properties[-1]["forces"][idx]) < abs(fmax)
390401
for idx in range(len(struct))
391402
)
403+
404+
if final_atoms_object_file is not None:
405+
if steps <= 1:
406+
write_atoms = input_atoms
407+
write_atoms.calc = self.calculator
408+
else:
409+
write_atoms = atoms
410+
ase_write(
411+
final_atoms_object_file, write_atoms, format="extxyz", append=True
412+
)
413+
392414
return AseResult(
393415
final_mol_or_struct=struct,
394416
trajectory=traj,

src/atomate2/common/flows/mpmorph.py

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -112,29 +112,24 @@ def make(
112112
*self.initial_strain, self.postprocessor.min_data_points
113113
)
114114
working_outputs = {
115-
"relax": {
116-
key: [] for key in ("energies", "volume", "stress", "pressure")
117-
}
115+
"relax": {key: [] for key in ("energy", "volume", "stress", "pressure")}
118116
}
119117

120118
else:
121119
# Fit EOS to running list of energies and volumes
122120
self.postprocessor.fit(working_outputs)
123121
working_outputs = dict(self.postprocessor.results)
124122
flow_output = {"working_outputs": working_outputs.copy(), "structure": None}
125-
for k in ("pressure", "energy"):
123+
for k in ("pressure",):
126124
working_outputs["relax"].pop(k, None)
127125

128126
# Stop flow here if EOS cannot be fit
129127
if (v0 := working_outputs.get("V0")) is None:
130128
return Response(output=flow_output, stop_children=True)
131129

132130
# Check if equilibrium volume is in range of attempted volumes
133-
v0_in_range = (
134-
(vmin := working_outputs.get("Vmin"))
135-
<= v0
136-
<= (vmax := working_outputs.get("Vmax"))
137-
)
131+
vmin = working_outputs.get("Vmin")
132+
vmax = working_outputs.get("Vmax")
138133

139134
# Check if maximum number of refinement NVT runs is set,
140135
# and if so, if that limit has been reached
@@ -143,7 +138,7 @@ def make(
143138
)
144139

145140
# Successful fit: return structure at estimated equilibrium volume
146-
if v0_in_range or max_attempts_reached:
141+
if (vmin <= v0 <= vmax) or max_attempts_reached:
147142
flow_output["structure"] = structure.copy()
148143
flow_output["structure"].scale_lattice(v0) # type: ignore[attr-defined]
149144
return flow_output
@@ -162,19 +157,19 @@ def make(
162157
eos_jobs = []
163158
for index in range(len(deformation_matrices)):
164159
md_job = self.md_maker.make(
165-
structure=deformed_structures[index].final_structure,
160+
deformed_structures[index].final_structure,
166161
prev_dir=None,
167162
)
168163
relaxed_vol = len(working_outputs["relax"]["volume"])
169164
md_job.name = f"{self.name} {md_job.name} {relaxed_vol + 1}"
170165

171-
working_outputs["relax"]["energies"].append(md_job.output.output.energy)
166+
working_outputs["relax"]["energy"].append(md_job.output.output.energy)
172167
working_outputs["relax"]["volume"].append(md_job.output.structure.volume)
173168
working_outputs["relax"]["stress"].append(md_job.output.output.stress)
174169
eos_jobs.append(md_job)
175170

176171
recursive = self.make(
177-
structure=structure,
172+
structure,
178173
prev_dir=None,
179174
working_outputs=working_outputs,
180175
)
@@ -262,14 +257,12 @@ def make(
262257
structure = convergence_flow.output["structure"]
263258

264259
self.production_md_maker.name = self.name + " production run"
265-
production_run = self.production_md_maker.make(
266-
structure=structure, prev_dir=prev_dir
267-
)
260+
production_run = self.production_md_maker.make(structure, prev_dir=prev_dir)
268261
flow_jobs.append(production_run)
269262

270263
if self.quench_maker:
271264
quench_flow = self.quench_maker.make(
272-
structure=production_run.output.structure,
265+
production_run.output.structure,
273266
prev_dir=production_run.output.dir_name,
274267
)
275268
flow_jobs += [quench_flow]
@@ -469,7 +462,7 @@ def make(self, structure: Structure, prev_dir: str | Path | None = None) -> Flow
469462
)
470463
if self.descent_method == "stepwise":
471464
md_job = self.call_md_maker(
472-
structure=structure,
465+
structure,
473466
temp=temp,
474467
prev_dir=prev_dir,
475468
)
@@ -478,13 +471,13 @@ def make(self, structure: Structure, prev_dir: str | Path | None = None) -> Flow
478471
self.descent_method == "linear with hold"
479472
): # TODO: Work in Progress; needs testing
480473
md_job_linear = self.call_md_maker(
481-
structure=structure,
474+
structure,
482475
temp=[temp, temp - self.quench_temperature_step], # type: ignore[arg-type]
483476
prev_dir=prev_dir,
484477
)
485478

486479
md_job = self.call_md_maker(
487-
structure=md_job_linear.output.structure,
480+
md_job_linear.output.structure,
488481
temp=temp - self.quench_temperature_step,
489482
prev_dir=md_job_linear.output.dir_name,
490483
)

src/atomate2/forcefields/jobs.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,16 @@
3838
MLFF.MACE_MP_0: {"model": "medium"},
3939
MLFF.MACE_MPA_0: {"model": "medium-mpa-0"},
4040
MLFF.MACE_MP_0B3: {"model": "medium-0b3"},
41-
MLFF.MATPES_PBE: {"architecture": "TensorNet", "version": "2025.1"},
42-
MLFF.MATPES_R2SCAN: {"architecture": "TensorNet", "version": "2025.1"},
41+
MLFF.MATPES_PBE: {
42+
"architecture": "TensorNet",
43+
"version": "2025.1",
44+
"stress_unit": "eV/A3",
45+
},
46+
MLFF.MATPES_R2SCAN: {
47+
"architecture": "TensorNet",
48+
"version": "2025.1",
49+
"stress_unit": "eV/A3",
50+
},
4351
}
4452

4553

0 commit comments

Comments
 (0)