From 7a35619d860bcdaff59e8d6059aacaa48e5984bb Mon Sep 17 00:00:00 2001 From: cote3804 Date: Wed, 13 Aug 2025 13:43:07 -0400 Subject: [PATCH] Moved JDFTx set over to Pymatgen --- jdftxcov.xml | 101 --------------- src/atomate2/jdftx/run.py | 2 +- src/atomate2/jdftx/schemas/task.py | 2 +- src/atomate2/jdftx/sets/BaseJdftxSet.yaml | 67 ---------- ...BeastConfig.yaml => GenerationConfig.yaml} | 0 src/atomate2/jdftx/sets/base.py | 119 ++---------------- tests/jdftx/conftest.py | 3 +- tests/jdftx/schemas/test_taskdoc.py | 2 +- 8 files changed, 18 insertions(+), 278 deletions(-) delete mode 100644 jdftxcov.xml delete mode 100644 src/atomate2/jdftx/sets/BaseJdftxSet.yaml rename src/atomate2/jdftx/sets/{BeastConfig.yaml => GenerationConfig.yaml} (100%) diff --git a/jdftxcov.xml b/jdftxcov.xml deleted file mode 100644 index b129ce667c..0000000000 --- a/jdftxcov.xml +++ /dev/null @@ -1,101 +0,0 @@ - - - - - - /Users/sophi/envs/jobflow_py310/src/atomate2/src/atomate2/jdftx/jobs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/atomate2/jdftx/run.py b/src/atomate2/jdftx/run.py index 0f7c2645b4..611d012461 100644 --- a/src/atomate2/jdftx/run.py +++ b/src/atomate2/jdftx/run.py @@ -6,10 +6,10 @@ from custodian.jdftx.jobs import JDFTxJob from jobflow.utils import ValueEnum +from pymatgen.io.jdftx.sets import FILE_NAMES from atomate2 import SETTINGS from atomate2.jdftx.schemas.enums import JDFTxStatus -from atomate2.jdftx.sets.base import FILE_NAMES if TYPE_CHECKING: from atomate2.jdftx.schemas.task import TaskDoc diff --git a/src/atomate2/jdftx/schemas/task.py b/src/atomate2/jdftx/schemas/task.py index 87e7d3d93b..29bdeae627 100644 --- a/src/atomate2/jdftx/schemas/task.py +++ b/src/atomate2/jdftx/schemas/task.py @@ -9,6 +9,7 @@ from custodian.jdftx.jobs import JDFTxJob # Waiting on Sophie's PR from emmet.core.structure import StructureMetadata from pydantic import BaseModel, Field +from pymatgen.io.jdftx.sets import FILE_NAMES from typing_extensions import Self from atomate2.jdftx.schemas.calculation import ( @@ -18,7 +19,6 @@ RunStatistics, ) from atomate2.jdftx.schemas.enums import JDFTxStatus, TaskType -from atomate2.jdftx.sets.base import FILE_NAMES from atomate2.utils.datetime import datetime_str __author__ = "Cooper Tezak " diff --git a/src/atomate2/jdftx/sets/BaseJdftxSet.yaml b/src/atomate2/jdftx/sets/BaseJdftxSet.yaml deleted file mode 100644 index f6aa8f6bf6..0000000000 --- a/src/atomate2/jdftx/sets/BaseJdftxSet.yaml +++ /dev/null @@ -1,67 +0,0 @@ -# Default JDFTx settings for atomate2 calculations. -### Functional ### -elec-ex-corr: gga -van-der-waals: D3 - -### Electronic Parameters ### -elec-cutoff: - Ecut: 20 - EcutRho: 100 -electronic-minimize: - nIterations: 100 - energyDiffThreshold: 1.0e-07 -elec-smearing: - smearingType: Fermi - smearingWidth: 0.001 -# elec-initial-magnetization: -# M: 0 -# constrain: False -spintype: z-spin -core-overlap-check: none -converge-empty-states: True -band-projection-params: - ortho: True - norm: False - -### Lattice / Unit Cell ### -latt-move-scale: - s0: 0 - s1: 0 - s2: 0 -lattice-minimize: - nIterations: 00 -symmetries: none -#coulomb-interaction: slab 001 -#coords-type Lattice - -### Solvation & Bias ### -# fluid: LinearPCM -# pcm-variant: CANDLE -# fluid-solvent: H2O -# fluid-cation: -# name: Na+ -# concentration: 0.5 -# fluid-anion: -# name: F- -# concentration: 0.5 - -### Pseudopotential ### -ion-species: GBRV_v1.5/$ID_pbe_v1.uspp - - -### Output Files ### -dump-name: jdftx.$VAR -dump: - - End: - Dtot: True - State: True - BoundCharge: True - Forces: True - Ecomponents: True - VfluidTot: True - ElecDensity: True - KEdensity: True - EigStats: True - BandEigs: True - BandProjections: True - DOS: True diff --git a/src/atomate2/jdftx/sets/BeastConfig.yaml b/src/atomate2/jdftx/sets/GenerationConfig.yaml similarity index 100% rename from src/atomate2/jdftx/sets/BeastConfig.yaml rename to src/atomate2/jdftx/sets/GenerationConfig.yaml diff --git a/src/atomate2/jdftx/sets/base.py b/src/atomate2/jdftx/sets/base.py index 13cea2f6f2..e42b15393b 100644 --- a/src/atomate2/jdftx/sets/base.py +++ b/src/atomate2/jdftx/sets/base.py @@ -2,7 +2,6 @@ from __future__ import annotations -import os from collections import defaultdict from dataclasses import dataclass, field from importlib.resources import files as get_mod_path @@ -12,81 +11,22 @@ import numpy as np from monty.serialization import loadfn from pymatgen.core.units import ang_to_bohr, eV_to_Ha -from pymatgen.io.core import InputGenerator, InputSet -from pymatgen.io.jdftx.inputs import JDFTXInfile, JDFTXStructure +from pymatgen.io.core import InputGenerator +from pymatgen.io.jdftx.inputs import JDFTXInfile +from pymatgen.io.jdftx.sets import JdftxInputSet from pymatgen.io.vasp import Kpoints from atomate2 import SETTINGS if TYPE_CHECKING: from pymatgen.core import Structure - from pymatgen.util.typing import Kpoint, PathLike -_BASE_JDFTX_SET = loadfn(get_mod_path("atomate2.jdftx.sets") / "BaseJdftxSet.yaml") -_BEAST_CONFIG = loadfn(get_mod_path("atomate2.jdftx.sets") / "BeastConfig.yaml") +_BASE_JDFTX_SET = loadfn(get_mod_path("pymatgen.io.jdftx.sets") / "BaseJdftxSet.yaml") +_GENERATION_CONFIG = loadfn( + get_mod_path("atomate2.jdftx.sets") / "GenerationConfig.yaml" +) _PSEUDO_CONFIG = loadfn(get_mod_path("atomate2.jdftx.sets") / "PseudosConfig.yaml") -FILE_NAMES = {"in": "init.in", "out": "jdftx.out"} - - -class JdftxInputSet(InputSet): - """ - A class to represent a JDFTx input file as a JDFTx InputSet. - - Parameters - ---------- - jdftxinput - A JdftxInput object - """ - - def __init__(self, jdftxinput: JDFTXInfile, jdftxstructure: JDFTXStructure) -> None: - self.jdftxstructure = jdftxstructure - self.jdftxinput = jdftxinput - - def write_input( - self, - directory: str | Path, - infile: PathLike = FILE_NAMES["in"], - make_dir: bool = True, - overwrite: bool = True, - ) -> None: - """Write JDFTx input file to a directory. - - Parameters - ---------- - directory - Directory to write input files to. - make_dir - Whether to create the directory if it does not already exist. - overwrite - Whether to overwrite an input file if it already exists. - """ - directory = Path(directory) - if make_dir: - os.makedirs(directory, exist_ok=True) - - if not overwrite and (directory / infile).exists(): - raise FileExistsError(f"{directory / infile} already exists.") - - jdftxinput = condense_jdftxinputs(self.jdftxinput, self.jdftxstructure) - - jdftxinput.write_file(filename=(directory / infile)) - - @staticmethod - def from_directory( - directory: str | Path, - ) -> JdftxInputSet: - """Load a set of JDFTx inputs from a directory. - - Parameters - ---------- - directory - Directory to read JDFTx inputs from. - """ - directory = Path(directory) - jdftxinput = JDFTXInfile.from_file(directory / "input.in") - jdftxstructure = jdftxinput.to_JDFTXStructure(jdftxinput) - return JdftxInputSet(jdftxinput=jdftxinput, jdftxstructure=jdftxstructure) @dataclass @@ -123,7 +63,7 @@ class JdftxInputGenerator(InputGenerator): potential: None | float = None calc_type: str = "bulk" pseudopotentials: str = "GBRV" - config_dict: dict = field(default_factory=lambda: _BEAST_CONFIG) + config_dict: dict = field(default_factory=lambda: _GENERATION_CONFIG) default_settings: dict = field(default_factory=lambda: _BASE_JDFTX_SET) def __post_init__(self) -> None: @@ -172,13 +112,11 @@ def get_input_set( self.set_magnetic_moments(structure=structure) self._apply_settings(self.settings) - jdftx_structure = JDFTXStructure(structure) - jdftxinputs = self.settings - jdftxinput = JDFTXInfile.from_dict(jdftxinputs) + jdftxinput = JDFTXInfile.from_dict(self.settings) - return JdftxInputSet(jdftxinput=jdftxinput, jdftxstructure=jdftx_structure) + return JdftxInputSet(jdftxinput=jdftxinput, structure=structure) - def set_kgrid(self, structure: Structure) -> Kpoint: + def set_kgrid(self, structure: Structure) -> None: """Get k-point grid. Parameters @@ -267,7 +205,7 @@ def set_nbands(self, structure: Structure) -> None: for atom in structure.species: nelec += _PSEUDO_CONFIG[self.pseudopotentials][str(atom)] nbands_add = int(nelec / 2) + 10 - nbands_mult = int(nelec / 2) * _BEAST_CONFIG["bands_multiplier"] + nbands_mult = int(nelec / 2) * self.config_dict["bands_multiplier"] self.settings["elec-n-bands"] = max(nbands_add, nbands_mult) def set_pseudos( @@ -297,7 +235,7 @@ def set_mu(self) -> None: if "target-mu" in self.settings or self.potential is None: return solvent_model = self.settings["pcm-variant"] - ashep = _BEAST_CONFIG["ASHEP"][solvent_model] + ashep = self.config_dict["ASHEP"][solvent_model] # calculate absolute potential in Hartree mu = -(ashep - self.potential) / eV_to_Ha self.settings["target-mu"] = {"mu": mu} @@ -358,37 +296,6 @@ def set_magnetic_moments(self, structure: Structure) -> None: return -def condense_jdftxinputs( - jdftxinput: JDFTXInfile, jdftxstructure: JDFTXStructure -) -> JDFTXInfile: - """ - Combine JDFTXInfile and JDFTxStructure into complete JDFTXInfile. - - Function combines a JDFTXInfile class with calculation - settings and a JDFTxStructure that defines the structure - into one JDFTXInfile instance. - - Parameters - ---------- - jdftxinput: JDFTXInfile - A JDFTXInfile object with calculation settings. - - jdftxstructure: JDFTXStructure - A JDFTXStructure object that defines the structure. - - Returns - ------- - JDFTXInfile - A JDFTXInfile that includes the calculation - parameters and input structure. - """ - # force Cartesian coordinates - coords_type = jdftxinput.get("coords-type") - return jdftxinput + JDFTXInfile.from_str( - jdftxstructure.get_str(in_cart_coords=(coords_type == "Cartesian")) - ) - - def center_of_mass(structure: Structure) -> np.ndarray: """ Calculate center of mass. diff --git a/tests/jdftx/conftest.py b/tests/jdftx/conftest.py index 8412e41254..79d7814c33 100644 --- a/tests/jdftx/conftest.py +++ b/tests/jdftx/conftest.py @@ -11,10 +11,11 @@ from jobflow import CURRENT_JOB from monty.os.path import zpath as monty_zpath from pymatgen.io.jdftx.inputs import JDFTXInfile +from pymatgen.io.jdftx.sets import FILE_NAMES import atomate2.jdftx.jobs.base import atomate2.jdftx.run -from atomate2.jdftx.sets.base import FILE_NAMES, JdftxInputGenerator +from atomate2.jdftx.sets.base import JdftxInputGenerator if TYPE_CHECKING: from collections.abc import Sequence diff --git a/tests/jdftx/schemas/test_taskdoc.py b/tests/jdftx/schemas/test_taskdoc.py index a220b387c9..ed6e8a0fae 100644 --- a/tests/jdftx/schemas/test_taskdoc.py +++ b/tests/jdftx/schemas/test_taskdoc.py @@ -3,9 +3,9 @@ import pytest from pymatgen.io.jdftx.outputs import JDFTXOutfile +from pymatgen.io.jdftx.sets import FILE_NAMES from atomate2.jdftx.schemas.task import TaskDoc -from atomate2.jdftx.sets.base import FILE_NAMES @pytest.mark.parametrize("task_name", ["sp_test"], indirect=True)