From 712f9a01f07513242becf43a1ed38014add0f26e Mon Sep 17 00:00:00 2001 From: esoteric-ephemera Date: Fri, 27 Mar 2026 10:27:09 -0700 Subject: [PATCH 1/5] add major refs --- docs/dev/forcefields.md | 2 +- src/atomate2/abinit/jobs/base.py | 2 ++ src/atomate2/aims/jobs/base.py | 2 ++ src/atomate2/ase/jobs.py | 4 ++++ src/atomate2/common/flows/approx_neb.py | 2 ++ src/atomate2/cp2k/jobs/base.py | 8 ++++++++ src/atomate2/jdftx/jobs/base.py | 2 ++ src/atomate2/lobster/jobs.py | 2 ++ src/atomate2/openff/core.py | 2 ++ src/atomate2/openmm/jobs/base.py | 2 ++ src/atomate2/torchsim/core.py | 2 ++ src/atomate2/vasp/jobs/base.py | 5 +++++ 12 files changed, 34 insertions(+), 1 deletion(-) diff --git a/docs/dev/forcefields.md b/docs/dev/forcefields.md index 484d495508..a4b1230241 100644 --- a/docs/dev/forcefields.md +++ b/docs/dev/forcefields.md @@ -10,7 +10,7 @@ There is both an `ase` module in `atomate2`, based around general `ase` `Calcula The `ase` module should be used to manage high-level tasks, such as geometry optimization, molecular dynamics, and nudged elastic band. Any further developments to these tools in `ase` should also warrant updates in this module in `atomate2`. For example, when `ase` rolled out the `MTKNPT` NPT MD barostat as a replacement for the default barostat, this was also made the default in `atomate2`. -The `forcefields` library should be used to develop concrete implementations of workflows, e.g., harmonic phonon, Grüneisen parameter, ApproxNEB. +The `forcefields` library should be used to develop concrete implementations of workflows, e.g., harmonic phonon, Grüneisen parameter, [ApproxNEB](https://doi.org/10.1063/1.4960790). ## Dependency Chaos diff --git a/src/atomate2/abinit/jobs/base.py b/src/atomate2/abinit/jobs/base.py index 2a21837ba5..863f2d8135 100644 --- a/src/atomate2/abinit/jobs/base.py +++ b/src/atomate2/abinit/jobs/base.py @@ -11,6 +11,7 @@ import jobflow from jobflow import Maker, Response, job +from pymatgen.util.due import Doi, due from atomate2 import SETTINGS from atomate2.abinit.files import write_abinit_input_set @@ -98,6 +99,7 @@ def setup_job( ) +@due.dcite(Doi("10.1063/5.028827"), description="Most recent Abinit paper") @dataclass class BaseAbinitMaker(Maker): """ diff --git a/src/atomate2/aims/jobs/base.py b/src/atomate2/aims/jobs/base.py index e2a190b0fd..8a60bffcca 100644 --- a/src/atomate2/aims/jobs/base.py +++ b/src/atomate2/aims/jobs/base.py @@ -10,6 +10,7 @@ from jobflow import Maker, Response, job from monty.serialization import dumpfn from pymatgen.io.aims.sets.base import AimsInputGenerator +from pymatgen.util.due import Doi, due from atomate2 import SETTINGS from atomate2.aims.files import ( @@ -40,6 +41,7 @@ _FILES_TO_ZIP = _INPUT_FILES + _OUTPUT_FILES +@due.dcite(Doi("10.1016/j.cpc.2009.06.022"), description="FHI-AIMS") @dataclass class BaseAimsMaker(Maker): """ diff --git a/src/atomate2/ase/jobs.py b/src/atomate2/ase/jobs.py index 12c7c909c4..362e566869 100644 --- a/src/atomate2/ase/jobs.py +++ b/src/atomate2/ase/jobs.py @@ -12,6 +12,7 @@ from jobflow import Maker, job from pymatgen.core import Molecule, Structure from pymatgen.io.ase import AseAtomsAdaptor +from pymatgen.util.due import Doi, due from atomate2.ase.schemas import AseResult, AseTaskDoc from atomate2.ase.utils import AseRelaxer @@ -28,6 +29,9 @@ _ASE_DATA_OBJECTS = ["trajectory"] +@due.dcite( + Doi("10.1088/1361-648X/aa680e"), description="Atomic simulation environment." +) @dataclass class AseMaker(Maker, ABC): """ diff --git a/src/atomate2/common/flows/approx_neb.py b/src/atomate2/common/flows/approx_neb.py index b9d325da1a..618c953c74 100644 --- a/src/atomate2/common/flows/approx_neb.py +++ b/src/atomate2/common/flows/approx_neb.py @@ -7,6 +7,7 @@ from emmet.core.mobility.migrationgraph import MigrationGraphDoc from jobflow import Flow, Maker, OnMissing +from pymatgen.util.due import Doi, due from atomate2.common.jobs.approx_neb import ( collate_images_single_hop, @@ -25,6 +26,7 @@ from pymatgen.util.typing import CompositionLike +@due.dcite(Doi("https://doi.org/10.1063/1.4960790"), description="ApproxNEB") @dataclass class CommonApproxNebMaker(Maker): """Run an ApproxNEB workflow. diff --git a/src/atomate2/cp2k/jobs/base.py b/src/atomate2/cp2k/jobs/base.py index 40bfe1083b..37d18b7e06 100644 --- a/src/atomate2/cp2k/jobs/base.py +++ b/src/atomate2/cp2k/jobs/base.py @@ -17,6 +17,7 @@ ) from pymatgen.electronic_structure.dos import DOS, CompleteDos, Dos from pymatgen.io.common import VolumetricData +from pymatgen.util.due import Doi, due from atomate2 import SETTINGS from atomate2.common.files import gzip_files, gzip_output_folder @@ -85,6 +86,13 @@ def make(structure): return job(method, data=_DATA_OBJECTS, output_schema=TaskDocument) +@due.dcite( + Doi("10.1063/5.0007045"), + description=( + "CP2K review - ensure you cite all references " + 'in the "R E F E R E N C E S" section of the CP2K output' + ), +) @dataclass class BaseCp2kMaker(Maker): """ diff --git a/src/atomate2/jdftx/jobs/base.py b/src/atomate2/jdftx/jobs/base.py index ecdf6e0ea0..4365d608ee 100644 --- a/src/atomate2/jdftx/jobs/base.py +++ b/src/atomate2/jdftx/jobs/base.py @@ -13,6 +13,7 @@ BandStructure, BandStructureSymmLine, ) +from pymatgen.util.due import Doi, due from atomate2.jdftx.files import write_jdftx_input_set from atomate2.jdftx.run import run_jdftx, should_stop_children @@ -73,6 +74,7 @@ def jdftx_job(method: Callable) -> job: return job(method, data=_DATA_OBJECTS, output_schema=TaskDoc) +@due.dcite(Doi("10.1016/j.softx.2017.10.006"), description="JDFTx") @dataclass class BaseJdftxMaker(Maker): """ diff --git a/src/atomate2/lobster/jobs.py b/src/atomate2/lobster/jobs.py index aef254c64d..ba0cd14a90 100644 --- a/src/atomate2/lobster/jobs.py +++ b/src/atomate2/lobster/jobs.py @@ -10,6 +10,7 @@ from pymatgen.electronic_structure.cohp import CompleteCohp from pymatgen.electronic_structure.dos import LobsterCompleteDos from pymatgen.io.lobster import Bandoverlaps, Icohplist, Lobsterin +from pymatgen.util.due import Doi, due from atomate2 import SETTINGS from atomate2.common.files import gzip_output_folder @@ -27,6 +28,7 @@ _FILES_TO_ZIP = [*LOBSTEROUTPUT_FILES, "lobsterin", *VASP_OUTPUT_FILES] +@due.dcite(Doi("https://doi.org/10.1002/jcc.26353"), description="LOBSTER paper") @dataclass class LobsterMaker(Maker): """ diff --git a/src/atomate2/openff/core.py b/src/atomate2/openff/core.py index 4b9385c3b8..271018bc22 100644 --- a/src/atomate2/openff/core.py +++ b/src/atomate2/openff/core.py @@ -13,6 +13,7 @@ from openff.interchange.components._packmol import pack_box from openff.toolkit import ForceField from openff.units import unit +from pymatgen.util.due import Doi, due from atomate2.openff.utils import create_mol_spec_list, merge_specs_by_name_and_smiles @@ -56,6 +57,7 @@ def make(structure): ) +@due.dcite(Doi("10.1021/acs.jpcb.4c01558"), description="Open forcefield initiative") @openff_job def generate_interchange( input_mol_specs: list[MoleculeSpec | dict], diff --git a/src/atomate2/openmm/jobs/base.py b/src/atomate2/openmm/jobs/base.py index f839752406..534cb74263 100644 --- a/src/atomate2/openmm/jobs/base.py +++ b/src/atomate2/openmm/jobs/base.py @@ -24,6 +24,7 @@ from openmm.app import StateDataReporter from openmm.unit import angstrom, kelvin, picoseconds from pymatgen.core import Structure +from pymatgen.util.due import Doi, due from atomate2.openmm.interchange import OpenMMInterchange from atomate2.openmm.utils import ( @@ -113,6 +114,7 @@ def make(structure): ) +@due.dcite(Doi("10.1021/acs.jpcb.3c06662"), description="OpenMM 8") @dataclass class BaseOpenMMMaker(Maker): """Base class for OpenMM simulation makers. diff --git a/src/atomate2/torchsim/core.py b/src/atomate2/torchsim/core.py index 31a2738a48..e73213b704 100644 --- a/src/atomate2/torchsim/core.py +++ b/src/atomate2/torchsim/core.py @@ -13,6 +13,7 @@ import torch_sim as ts from jobflow import Maker, Response, job from pymatgen.core import Structure +from pymatgen.util.due import Doi, due from torch_sim.autobatching import BinningAutoBatcher, InFlightAutoBatcher from atomate2.torchsim.schema import ( @@ -38,6 +39,7 @@ from torch_sim.trajectory import TrajectoryReporter +@due.dcite(Doi("10.1088/3050-287X/ae1799"), description="TorchSim") def torchsim_job(method: Callable) -> job: """Decorate the ``make`` method of TorchSim job makers. diff --git a/src/atomate2/vasp/jobs/base.py b/src/atomate2/vasp/jobs/base.py index af82fdba81..f384ebe3b9 100644 --- a/src/atomate2/vasp/jobs/base.py +++ b/src/atomate2/vasp/jobs/base.py @@ -20,6 +20,7 @@ ) from pymatgen.electronic_structure.dos import DOS, CompleteDos, Dos from pymatgen.io.vasp import Chgcar, Locpot, Wavecar +from pymatgen.util.due import Doi, due from atomate2 import SETTINGS from atomate2.common.files import gzip_output_folder @@ -165,6 +166,10 @@ def make(structure): return job(method, data=_DATA_OBJECTS, output_schema=TaskDoc) +@due.dcite(Doi("10.1103/PhysRevB.47.558"), description="VASP: MD for metals") +@due.dcite(Doi("10.1103/PhysRevB.49.14251"), description="VASP: MD") +@due.dcite(Doi("10.1016/0927-0256(96)00008-0"), description="VASP: core algorithms") +@due.dcite(Doi("10.1103/PhysRevB.54.11169"), description="VASP: self-consistency") @dataclass class BaseVaspMaker(Maker): """ From 97413046710e683bee0c1f968488e2c016772dee Mon Sep 17 00:00:00 2001 From: esoteric-ephemera Date: Fri, 27 Mar 2026 10:30:17 -0700 Subject: [PATCH 2/5] dtype for matgl --- src/atomate2/forcefields/utils.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/atomate2/forcefields/utils.py b/src/atomate2/forcefields/utils.py index 0eef59de6d..b2a09147c3 100644 --- a/src/atomate2/forcefields/utils.py +++ b/src/atomate2/forcefields/utils.py @@ -310,6 +310,9 @@ def ase_calculator( ) matgl.config.BACKEND = "PYG" + if new_dtype := kwargs.pop("dtype", None): + matgl.set_default_dtype(new_dtype) + matgl_calc = getattr( import_module(f"matgl.ext._ase_{matgl.config.BACKEND.lower()}"), "PESCalculator", From 557eb81fdff989f7aa6afbb0d78f9e913aee971f Mon Sep 17 00:00:00 2001 From: esoteric-ephemera Date: Fri, 27 Mar 2026 16:49:12 -0700 Subject: [PATCH 3/5] make default_dtype an explicit calculator kwarg --- src/atomate2/forcefields/utils.py | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/src/atomate2/forcefields/utils.py b/src/atomate2/forcefields/utils.py index b2a09147c3..92355f2aca 100644 --- a/src/atomate2/forcefields/utils.py +++ b/src/atomate2/forcefields/utils.py @@ -20,6 +20,11 @@ from collections.abc import Callable, Generator from typing import Any + try: + from torch import dtype as torch_dtype + except ImportError: + torch_dtype = str + from ase.calculators.calculator import Calculator from atomate2.ase.schemas import AseResult @@ -229,7 +234,9 @@ def ase_calculator_name(self) -> str: def ase_calculator( - calculator_meta: str | MLFF | dict, **kwargs: Any + calculator_meta: str | MLFF | dict, + default_dtype: str | torch_dtype | None = None, + **kwargs: Any, ) -> Calculator | None: """ Create an ASE calculator from a given set of metadata. @@ -246,7 +253,7 @@ def ase_calculator( "@callable": "CHGNetCalculator" } ``` - args : optional args to pass to a calculator + default_dtype (str or pytorch dtype) : optional pytorch dtype to use if applicable kwargs : optional kwargs to pass to a calculator Returns @@ -310,8 +317,8 @@ def ase_calculator( ) matgl.config.BACKEND = "PYG" - if new_dtype := kwargs.pop("dtype", None): - matgl.set_default_dtype(new_dtype) + if default_dtype is not None: + matgl.set_default_dtype(default_dtype) matgl_calc = getattr( import_module(f"matgl.ext._ase_{matgl.config.BACKEND.lower()}"), @@ -348,13 +355,17 @@ def ase_calculator( "damping": "bj", "xc": "pbe", "cutoff": 40.0 * Bohr, - "dtype": kwargs.get( - "default_dtype", torch.get_default_dtype() - ), + "dtype": default_dtype + if default_dtype is not None + else torch.get_default_dtype(), } - for k, v in default_d3_kwargs.items(): - if k not in kwargs: - kwargs[k] = v + kwargs.update( + { + k: v + for k, v in default_d3_kwargs.items() + if k not in kwargs + } + ) d3_calc = TorchDFTD3Calculator(device=device, **kwargs) calculator = SumCalculator([calculator, d3_calc]) From 94cae14f5797f064069b3f46055f93fcf3c85b65 Mon Sep 17 00:00:00 2001 From: Aaron Kaplan <33381112+esoteric-ephemera@users.noreply.github.com> Date: Fri, 27 Mar 2026 17:09:41 -0700 Subject: [PATCH 4/5] lobster citation description Co-authored-by: J. George --- src/atomate2/lobster/jobs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/atomate2/lobster/jobs.py b/src/atomate2/lobster/jobs.py index ba0cd14a90..1450f01d39 100644 --- a/src/atomate2/lobster/jobs.py +++ b/src/atomate2/lobster/jobs.py @@ -28,7 +28,7 @@ _FILES_TO_ZIP = [*LOBSTEROUTPUT_FILES, "lobsterin", *VASP_OUTPUT_FILES] -@due.dcite(Doi("https://doi.org/10.1002/jcc.26353"), description="LOBSTER paper") +@due.dcite(Doi("https://doi.org/10.1002/jcc.26353"), description="Most recent LOBSTER paper. Please cite the publications mentioned in the LOBSTER Terms of Use.") @dataclass class LobsterMaker(Maker): """ From 610d443319d3c9887410460d81abed626d128cd0 Mon Sep 17 00:00:00 2001 From: esoteric-ephemera Date: Mon, 30 Mar 2026 09:34:05 -0700 Subject: [PATCH 5/5] ensure mace dtype gets passed as kwarg --- src/atomate2/forcefields/utils.py | 7 +++---- src/atomate2/lobster/jobs.py | 8 +++++++- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/atomate2/forcefields/utils.py b/src/atomate2/forcefields/utils.py index 92355f2aca..b11e70f568 100644 --- a/src/atomate2/forcefields/utils.py +++ b/src/atomate2/forcefields/utils.py @@ -338,6 +338,7 @@ def ase_calculator( calculator = MACECalculator( model_paths=model_path, device=device, + default_dtype=default_dtype or "", **kwargs, ) @@ -355,9 +356,7 @@ def ase_calculator( "damping": "bj", "xc": "pbe", "cutoff": 40.0 * Bohr, - "dtype": default_dtype - if default_dtype is not None - else torch.get_default_dtype(), + "dtype": default_dtype or torch.get_default_dtype(), } kwargs.update( { @@ -370,7 +369,7 @@ def ase_calculator( d3_calc = TorchDFTD3Calculator(device=device, **kwargs) calculator = SumCalculator([calculator, d3_calc]) else: - calculator = mace_mp(**kwargs) + calculator = mace_mp(default_dtype=default_dtype or "", **kwargs) case MLFF.Nequip | MLFF.Allegro: from nequip.integrations.ase import NequIPCalculator diff --git a/src/atomate2/lobster/jobs.py b/src/atomate2/lobster/jobs.py index 1450f01d39..f4896665a6 100644 --- a/src/atomate2/lobster/jobs.py +++ b/src/atomate2/lobster/jobs.py @@ -28,7 +28,13 @@ _FILES_TO_ZIP = [*LOBSTEROUTPUT_FILES, "lobsterin", *VASP_OUTPUT_FILES] -@due.dcite(Doi("https://doi.org/10.1002/jcc.26353"), description="Most recent LOBSTER paper. Please cite the publications mentioned in the LOBSTER Terms of Use.") +@due.dcite( + Doi("https://doi.org/10.1002/jcc.26353"), + description=( + "Most recent LOBSTER paper. " + "Please cite the publications mentioned in the LOBSTER Terms of Use." + ), +) @dataclass class LobsterMaker(Maker): """