Skip to content

Commit fcea4a6

Browse files
authored
Merge branch 'main' into mol_for_forcefield
2 parents 95fd127 + 5d83fe7 commit fcea4a6

File tree

26 files changed

+410
-167
lines changed

26 files changed

+410
-167
lines changed

.github/workflows/testing.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ jobs:
199199
micromamba activate a2
200200
python -m pip install --upgrade pip
201201
uv pip install .[strict,tests]
202+
uv pip install tblite>=0.4.0
202203
203204
- name: Install pymatgen from master if triggered by pymatgen repo dispatch
204205
if: github.event_name == 'repository_dispatch' && github.event.action == 'pymatgen-ci-trigger'

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

docs/user/codes/vasp.md

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,25 @@ functional. Full structural relaxation is performed.
9797
### Double Relax
9898

9999
Perform two back-to-back relaxations. This can often help avoid errors arising from
100-
Pulay stress.
100+
[Pulay stress](https://www.vasp.at/wiki/index.php/Pulay_stress).
101+
102+
In short: While the cell size, shape, symmetry, etc. can change during a relaxation, the *k* point grid does not change with it.
103+
Additionally, the number of plane waves is held constant during a relaxation.
104+
Both features lead to artificial (numerical) stress due to under-convergence of a relaxation with respect to the basis set.
105+
To avoid this, we perform a single relaxation, and input its final structure to another relaxation calculation.
106+
At the start of the second relaxation, the *k*-point mesh and plane waves are adjusted to reflect the new symmetry of the cell.
107+
108+
### Materials Project structure optimization
109+
110+
The Materials Project hosts a large database of, among other physical properties, optimized structures and their associated total energy, formation enthalpy, and basic electronic structure properties.
111+
To generate this data, the Materials Project uses a simple double-relaxation followed by a final static calculation.
112+
While in principle, if the second relaxation calculation is converged, a final static calculation would not be needed.
113+
However, the second relaxation may have residual Pulay stress, and VASP averages some electronic structure data ([like the density of states](https://www.vasp.at/wiki/index.php/DOSCAR)) during a relaxation.
114+
Thus we need to perform a final single-point (static) calculation, usually using the corrected tetrahedron method (`ISMEAR=-5`) to ensure accurate electronic structure properties.
115+
116+
The workflows used to produce PBE GGA or GGA+*U* and r<sup>2</sup>SCAN thermodynamic data are, respectively, `MPGGADoubleRelaxStaticMaker` and `MPMetaGGADoubleRelaxStaticMaker` in `atomate2.vasp.flows.mp`.
117+
Moving forward, the Materials Project prefers r<sup>2</sup>SCAN calculations, but maintains its older set of GGA-level data which currently has wider coverage.
118+
For documentation about the calculation parameters used, see the [Materials Project documentation.](https://docs.materialsproject.org/methodology/materials-methodology/calculation-details)
101119

102120
### Band Structure
103121

@@ -616,6 +634,33 @@ written:
616634
static_job.maker.input_set_generator.user_incar_settings["LOPTICS"] = True
617635
```
618636

637+
To update *k*-points, use the `user_kpoints_settings` keyword argument of an input set generator.
638+
You can supply either a `pymatgen.io.vasp.inputs.Kpoints` object, or a `dict` containing certain [keys](https://github.com/materialsproject/pymatgen/blob/b54ac3e65e46b876de40402e8da59f551fb7d005/src/pymatgen/io/vasp/sets.py#L812).
639+
We generally recommend the former approach unless the user is familiar with the specific style of *k*-point updates used by `pymatgen`.
640+
For example, to use just the $\Gamma$ point:
641+
642+
```py
643+
from pymatgen.io.vasp.inputs import Kpoints
644+
from atomate2.vasp.sets.core import StaticSetGenerator
645+
from atomate2.vasp.jobs.core import StaticMaker
646+
647+
custom_gamma_only_set = StaticSetGenerator(user_kpoints_settings=Kpoints())
648+
gamma_only_static_maker = StaticMaker(input_set_generator=custom_gamma_only_set)
649+
```
650+
651+
For those who are more familiar with manual *k*-point generation, you can use a VASP-style KPOINTS file or string to set the *k*-points as well:
652+
653+
```py
654+
kpoints = Kpoints.from_str(
655+
"""Uniform density Monkhorst-Pack mesh
656+
0
657+
Monkhorst-pack
658+
5 5 5
659+
"""
660+
)
661+
custom_static_set = StaticSetGenerator(user_kpoints_settings=kpoints)
662+
```
663+
619664
Finally, sometimes you have a workflow containing many VASP jobs. In this case it can be
620665
tedious to update the input sets for each job individually. Atomate2 provides helper
621666
functions called "powerups" that can apply settings updates to all VASP jobs in a flow.
@@ -663,8 +708,7 @@ modification of several additional VASP settings, such as the k-points
663708

664709
If a greater degree of flexibility is needed, the user can define a default set of input
665710
arguments (`config_dict`) that can be provided to the {obj}`.VaspInputGenerator`.
666-
By default, the {obj}`.VaspInputGenerator` uses a base set of VASP input parameters
667-
from {obj}`.BaseVaspSet.yaml`, which each `Maker` is built upon. If desired, the user can
711+
By default, the {obj}`.VaspInputGenerator` uses a base set of VASP input parameters (`atomate2.vasp.sets.base._BASE_VASP_SET`), which each `Maker` is built upon. If desired, the user can
668712
define a custom `.yaml` file that contains a different base set of VASP settings to use.
669713
An example of how this can be done is shown below for a representative static
670714
calculation.

pyproject.toml

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ dependencies = [
2828
"PyYAML",
2929
"click",
3030
"custodian>=2024.4.18",
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,11 +62,10 @@ forcefields = [
6262
"sevenn>=0.9.3",
6363
"torchdata<=0.7.1", # TODO: remove when issue fixed
6464
]
65-
ase = ["ase>=3.23.0"]
66-
# tblite py3.12 support tracked in https://github.com/tblite/tblite/issues/198
67-
ase-ext = ["tblite>=0.3.0; python_version < '3.12'"]
65+
ase = ["ase>=3.25.0"]
66+
ase-ext = ["tblite>=0.3.0; platform_system=='Linux'"]
6867
openmm = [
69-
"mdanalysis>=2.7.0",
68+
"mdanalysis>=2.8.0",
7069
"openmm-mdanalysis-reporter>=0.1.0",
7170
"openmm>=8.1.0",
7271
]
@@ -82,7 +81,7 @@ docs = [
8281
"sphinx-copybutton==0.5.2",
8382
"sphinx==8.1.3",
8483
"sphinx_design==0.6.1",
85-
"jupyterlab==4.3.6",
84+
"jupyterlab==4.4.2",
8685
]
8786
dev = ["pre-commit>=2.12.1"]
8887
tests = [
@@ -95,27 +94,26 @@ tests = [
9594
]
9695
strict = [
9796
"PyYAML==6.0.2",
98-
"ase==3.24.0",
97+
"ase==3.25.0",
9998
"cclib==1.8.1",
100-
"click==8.1.7",
99+
"click==8.2.0",
101100
"custodian==2025.4.14",
102101
"dscribe==2.1.1",
103-
"emmet-core==0.84.5",
104-
"ijson==3.3.0",
102+
"emmet-core==0.84.8",
103+
"ijson==3.4.0",
105104
"jobflow==0.1.19",
106105
"lobsterpy==0.4.9",
107106
"monty==2025.3.3",
108-
"mp-api==0.45.4",
107+
"mp-api==0.45.7",
109108
"numpy",
110109
"phonopy==2.30.1",
111-
"pydantic-settings==2.8.1",
110+
"pydantic-settings==2.9.1",
112111
"pydantic==2.11.3",
113112
"pymatgen-analysis-defects==2025.1.18",
114113
"pymatgen==2025.2.18",
115114
"pymongo==4.10.1",
116115
"python-ulid==3.0.0",
117116
"seekpath==2.1.0",
118-
"tblite==0.3.0; python_version < '3.12'",
119117
"typing-extensions==4.13.2",
120118
]
121119
strict-openff = [
@@ -125,8 +123,7 @@ strict-openff = [
125123
"mdareporter @ git+https://github.com/sef43/openmm-mdanalysis-reporter.git@86e8bdffb63bbe9b13430ba97e2a67b85c996048",
126124
"h5py==3.13",
127125
"openmm==8.1.1",
128-
"pymatgen==2025.4.20", # TODO: open ff is extremely sensitive to pymatgen version
129-
"mdanalysis==2.9.0"
126+
"pymatgen==2024.11.13", # TODO: open ff is extremely sensitive to pymatgen version
130127
]
131128
strict-forcefields = [
132129
"calorine==3.0",
@@ -187,6 +184,7 @@ exclude_lines = [
187184
'^\s*@overload( |$)',
188185
'^\s*assert False(,|$)',
189186
'if typing.TYPE_CHECKING:',
187+
'if TYPE_CHECKING:',
190188
]
191189

192190
[tool.ruff]

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/electrode.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,10 @@ def make(
120120
relax = self.bulk_relax_maker.make(structure)
121121
else:
122122
relax = self.relax_maker.make(structure)
123+
124+
_shown_steps = str(n_steps) if n_steps else "inf"
125+
relax.append_name(f" 0/{_shown_steps}")
126+
123127
# add ignored_species to the structure matcher
124128
sm = _add_ignored_species(self.structure_matcher, inserted_element)
125129
# Get the inserted structure
@@ -132,6 +136,7 @@ def make(
132136
get_charge_density=self.get_charge_density,
133137
n_steps=n_steps,
134138
insertions_per_step=insertions_per_step,
139+
n_inserted=1,
135140
)
136141
relaxed_summary = RelaxJobSummary(
137142
structure=relax.output.structure,

0 commit comments

Comments
 (0)