diff --git a/docs/about/contributors.md b/docs/about/contributors.md index 8a2c9531df..c79533749a 100644 --- a/docs/about/contributors.md +++ b/docs/about/contributors.md @@ -24,7 +24,7 @@ Lawrence Livermore National Laboratory [jmmshn]: https://github.com/jmmshn [0000-0002-2743-7531]: https://orcid.org/0000-0002-2743-7531 -**Janosh Riebesell** [![gh]][janosh] [![orc]][0000-0001-5233-3462]\ +**Janosh Riebesell** [![gh]][janosh] [![orc]][0000-0001-5233-3462] \ PhD Student \ Cambridge University @@ -68,16 +68,30 @@ Microsoft Research [0000-0001-7777-8871]: https://orcid.org/0000-0001-7777-8871 **Zhuoying Zhu** [![gh]][zhuoying] [![orc]][0000-0003-1775-7651] \ -Postdoctoral researcher\ +Postdoctoral Researcher \ Lawrence Berkeley National Laboratory [zhuoying]: https://github.com/zhuoying [0000-0003-1775-7651]: https://orcid.org/0000-0003-1775-7651 **Aakash Ashok Naik** [![gh]][naik-aakash] [![orc]][0000-0002-6071-6786] \ -PhD student\ +PhD student \ Federal Institute for Materials Research and Testing (Berlin) \ Friedrich Schiller University Jena [naik-aakash]: https://github.com/naik-aakash [0000-0002-6071-6786]: https://orcid.org/0000-0002-6071-6786 + +**Aaron Kaplan** [![gh]][esoteric-ephemera] [![orc]][0000-0003-3439-4856] \ +Postdoctoral Researcher \ +Lawrence Berkeley National Laboratory + +[esoteric-ephemera]: https://github.com/esoteric-ephemera +[0000-0003-3439-4856]: https://orcid.org/0000-0003-3439-4856 + +**Matthew McDermott** [![gh]][mattmcdermott] [![orc]][0000-0002-4071-3000] \ +PhD student \ +University of California, Berkeley + +[mattmcdermott]: https://github.com/mattmcdermott +[0000-0002-4071-3000]: https://orcid.org/0000-0002-4071-3000 diff --git a/docs/user/atomate-1-vs-2.md b/docs/user/atomate-1-vs-2.md new file mode 100644 index 0000000000..3aa317dfe9 --- /dev/null +++ b/docs/user/atomate-1-vs-2.md @@ -0,0 +1,25 @@ +# Atomate 1 vs 2 + +This document contains introductory context for people coming from atomate 1. +One of atomate2's core ideas is to allow scaling from a single material, to 100 materials, or 100,000 materials. Therefore, both local submission options and a connection to workflow managers such as FireWorks exist. We plan to support more workflow managers in the future to further ease job submission. +## Relation between managers running the actual jobs and the workflow as written in `atomate2` + +There is no leakage between job manager and the workflow definition in `atomate2`. For example, Fireworks is not a required dependency of `atomate2` or `jobflow`. Any `atomate2` workflow can be run using the local manager or an extensible set of external providers, Fireworks just one among them. E.g. all tests are run with mocked calls to the executables using the local manager. + +## Do I need to write separate codes for different managers? + +If you are adding a new manager option beyond local or FireWorks, you'll need to write a new converter in `jobflow` that takes a job or flow and converts it to the analogous object(s) for the manager you wish to use. This does not impact the `atomate2` code in any way. + +Typically, the workflow is as follows: + +1. Write a workflow in `atomate2` that represents a job or flow. +2. Import the job or flow in your script/notebook from `atomate2`. +3. Convert the job or flow to manager-compatible objects using a convenience function in `jobflow`. +4. Define the specs for the new object type based on your desired resources. +5. Dispatch the jobs. + +## What if a workflow manager stops being maintained? + +`atomate2` and `jobflow` remain unaffected in such a case. The user can choose a different manager to suit their needs. This ensures that workflow definition and dispatch are fully decoupled. + +In an ideal world, `jobflow` would offer multiple manager options, allowing users to run `atomate2` codes as per their preference. This full decoupling is one of the most powerful features of this stack. diff --git a/src/atomate2/amset/schemas.py b/src/atomate2/amset/schemas.py index 75942e3ee8..41045b4693 100644 --- a/src/atomate2/amset/schemas.py +++ b/src/atomate2/amset/schemas.py @@ -165,7 +165,7 @@ def from_directory( from amset.io import load_mesh from amset.util import cast_dict_list - additional_fields = {} if additional_fields is None else additional_fields + additional_fields = additional_fields or {} dir_name = Path(dir_name) settings = loadfn("settings.yaml") diff --git a/src/atomate2/common/schemas/cclib.py b/src/atomate2/common/schemas/cclib.py index 61165cd1ca..d6587f7fa9 100644 --- a/src/atomate2/common/schemas/cclib.py +++ b/src/atomate2/common/schemas/cclib.py @@ -120,7 +120,7 @@ def from_logfile( logger.info(f"Getting task doc from {logfile}") - additional_fields = {} if additional_fields is None else additional_fields + additional_fields = additional_fields or {} # Let's parse the log file with cclib cclib_obj = ccread(logfile, logging.ERROR) diff --git a/src/atomate2/cp2k/run.py b/src/atomate2/cp2k/run.py index 721bd3e308..058f697c94 100644 --- a/src/atomate2/cp2k/run.py +++ b/src/atomate2/cp2k/run.py @@ -94,8 +94,8 @@ def run_cp2k( custodian_kwargs : dict Keyword arguments that are passed to :obj:`.Custodian`. """ - cp2k_job_kwargs = {} if cp2k_job_kwargs is None else cp2k_job_kwargs - custodian_kwargs = {} if custodian_kwargs is None else custodian_kwargs + cp2k_job_kwargs = cp2k_job_kwargs or {} + custodian_kwargs = custodian_kwargs or {} cp2k_cmd = expandvars(cp2k_cmd) split_cp2k_cmd = shlex.split(cp2k_cmd) diff --git a/src/atomate2/cp2k/schemas/task.py b/src/atomate2/cp2k/schemas/task.py index 8f83904cf9..147984489d 100644 --- a/src/atomate2/cp2k/schemas/task.py +++ b/src/atomate2/cp2k/schemas/task.py @@ -336,7 +336,7 @@ def from_directory( """ logger.info(f"Getting task doc in: {dir_name}") - additional_fields = {} if additional_fields is None else additional_fields + additional_fields = additional_fields or {} dir_name = Path(dir_name) task_files = _find_cp2k_files(dir_name, volumetric_files=volumetric_files) diff --git a/src/atomate2/cp2k/sets/base.py b/src/atomate2/cp2k/sets/base.py index 155784d5d0..3c8ca41673 100644 --- a/src/atomate2/cp2k/sets/base.py +++ b/src/atomate2/cp2k/sets/base.py @@ -77,7 +77,7 @@ def __init__( """ self.cp2k_input = cp2k_input - self.optional_files = {} if optional_files is None else optional_files + self.optional_files = optional_files or {} def write_input( self, @@ -98,8 +98,8 @@ def write_input( Whether to overwrite an input file if it already exists. """ directory = Path(directory) - if make_dir and not directory.exists(): - os.makedirs(directory) + if make_dir: + os.makedirs(directory, exist_ok=True) inputs = { "input": {"filename": "cp2k.inp", "object": self.cp2k_input}, @@ -270,9 +270,7 @@ def get_input_updates(self, structure, prev_input) -> dict: raise NotImplementedError def get_kpoints_updates( - self, - structure: Structure, - prev_input: Cp2kInput = None, + self, structure: Structure, prev_input: Cp2kInput = None ) -> dict: """ Get updates to the kpoints configuration for this calculation type. @@ -329,8 +327,8 @@ def _get_input( input_updates: dict = None, ): """Get the input.""" - previous_input = {} if previous_input is None else previous_input - input_updates = {} if input_updates is None else input_updates + previous_input = previous_input or {} + input_updates = input_updates or {} input_settings = dict(self.config_dict["cp2k_input"]) # Generate base input but override with user input settings @@ -349,9 +347,9 @@ def _get_input( and input_settings[setting] and callable(getattr(cp2k_input, setting)) ): - subsettings = input_settings.get(setting) + sub_settings = input_settings.get(setting) getattr(cp2k_input, setting)( - **subsettings if isinstance(subsettings, dict) else {} + **sub_settings if isinstance(sub_settings, dict) else {} ) cp2k_input.update(overrides) @@ -399,7 +397,7 @@ def _get_kpoints( kpoints_updates: dict[str, Any] | None, ) -> Kpoints | None: """Get the kpoints object.""" - kpoints_updates = {} if kpoints_updates is None else kpoints_updates + kpoints_updates = kpoints_updates or {} # use user setting if set otherwise default to base config settings if self.user_kpoints_settings != {}: diff --git a/src/atomate2/lobster/run.py b/src/atomate2/lobster/run.py index a708317c2e..b674a5ca9a 100644 --- a/src/atomate2/lobster/run.py +++ b/src/atomate2/lobster/run.py @@ -68,8 +68,8 @@ def run_lobster( custodian_kwargs : dict Keyword arguments that are passed to :obj:`.Custodian`. """ - lobster_job_kwargs = {} if lobster_job_kwargs is None else lobster_job_kwargs - custodian_kwargs = {} if custodian_kwargs is None else custodian_kwargs + lobster_job_kwargs = lobster_job_kwargs or {} + custodian_kwargs = custodian_kwargs or {} lobster_cmd = expandvars(lobster_cmd) split_lobster_cmd = shlex.split(lobster_cmd) diff --git a/src/atomate2/lobster/schemas.py b/src/atomate2/lobster/schemas.py index 479342e68e..aa882f153f 100644 --- a/src/atomate2/lobster/schemas.py +++ b/src/atomate2/lobster/schemas.py @@ -211,7 +211,7 @@ def from_directory( which_bonds: str mode for condensed bonding analysis: "cation-anion" and "all". """ - plot_kwargs = {} if plot_kwargs is None else plot_kwargs + plot_kwargs = plot_kwargs or {} dir_name = Path(dir_name) cohpcar_path = dir_name / "COHPCAR.lobster.gz" charge_path = dir_name / "CHARGE.lobster.gz" @@ -451,7 +451,7 @@ def from_directory( LobsterTaskDocument A task document for the lobster calculation. """ - additional_fields = {} if additional_fields is None else additional_fields + additional_fields = additional_fields or {} dir_name = Path(dir_name) # Read in lobsterout and lobsterin diff --git a/src/atomate2/vasp/files.py b/src/atomate2/vasp/files.py index 543ecc4dcd..077da5c3b2 100644 --- a/src/atomate2/vasp/files.py +++ b/src/atomate2/vasp/files.py @@ -82,7 +82,7 @@ def copy_vasp_outputs( # check at least one type of POTCAR file is included if len([f for f in optional_files if "POTCAR" in f.name]) == 0: - raise FileNotFoundError("Could not find POTCAR file to copy.") + raise FileNotFoundError(f"Could not find a POTCAR file in {src_dir!r} to copy") copy_files( src_dir, diff --git a/src/atomate2/vasp/jobs/defect.py b/src/atomate2/vasp/jobs/defect.py index d0c7ed4259..b74f9518c4 100644 --- a/src/atomate2/vasp/jobs/defect.py +++ b/src/atomate2/vasp/jobs/defect.py @@ -51,7 +51,7 @@ def calculate_finite_diff( previous calculations). """ ref_calc_dir = distorted_calc_dirs[ref_calc_index] - run_vasp_kwargs = {} if run_vasp_kwargs is None else run_vasp_kwargs + run_vasp_kwargs = run_vasp_kwargs or {} fc = FileClient() copy_vasp_outputs(ref_calc_dir, additional_vasp_files=["WAVECAR"], file_client=fc) diff --git a/src/atomate2/vasp/jobs/mp.py b/src/atomate2/vasp/jobs/mp.py index 29b5f55d65..a6686ef0cb 100644 --- a/src/atomate2/vasp/jobs/mp.py +++ b/src/atomate2/vasp/jobs/mp.py @@ -138,6 +138,7 @@ class MPPreRelaxMaker(BaseVaspMaker): "GGA": "PS", "LWAVE": True, "LCHARG": True, + "METAGGA": None, }, ) ) diff --git a/src/atomate2/vasp/run.py b/src/atomate2/vasp/run.py index 6981c45bf5..5b64b067f6 100644 --- a/src/atomate2/vasp/run.py +++ b/src/atomate2/vasp/run.py @@ -118,8 +118,8 @@ def run_vasp( custodian_kwargs : dict Keyword arguments that are passed to :obj:`.Custodian`. """ - vasp_job_kwargs = {} if vasp_job_kwargs is None else vasp_job_kwargs - custodian_kwargs = {} if custodian_kwargs is None else custodian_kwargs + vasp_job_kwargs = vasp_job_kwargs or {} + custodian_kwargs = custodian_kwargs or {} vasp_cmd = expandvars(vasp_cmd) vasp_gamma_cmd = expandvars(vasp_gamma_cmd) diff --git a/src/atomate2/vasp/sets/base.py b/src/atomate2/vasp/sets/base.py index cd6f450467..8a6ae1ba5a 100644 --- a/src/atomate2/vasp/sets/base.py +++ b/src/atomate2/vasp/sets/base.py @@ -67,7 +67,7 @@ def __init__( self.poscar = poscar self.potcar = potcar self.kpoints = kpoints - self.optional_files = {} if optional_files is None else optional_files + self.optional_files = optional_files or {} def write_input( self, @@ -89,8 +89,8 @@ def write_input( Whether to overwrite an input file if it already exists. """ directory = Path(directory) - if make_dir and not directory.exists(): - os.makedirs(directory) + if make_dir: + os.makedirs(directory, exist_ok=True) inputs = { "INCAR": self.incar, @@ -620,8 +620,8 @@ def _get_incar( ispin: int = None, ): """Get the INCAR.""" - previous_incar = {} if previous_incar is None else previous_incar - incar_updates = {} if incar_updates is None else incar_updates + previous_incar = previous_incar or {} + incar_updates = incar_updates or {} incar_settings = dict(self.config_dict["INCAR"]) config_magmoms = incar_settings.get("MAGMOM", {}) auto_updates = {} @@ -717,7 +717,7 @@ def _get_kpoints( bandgap: float | None, ) -> Kpoints | None: """Get the kpoints file.""" - kpoints_updates = {} if kpoints_updates is None else kpoints_updates + kpoints_updates = kpoints_updates or {} # use user setting if set otherwise default to base config settings if self.user_kpoints_settings != {}: diff --git a/tests/forcefields/test_jobs.py b/tests/forcefields/test_jobs.py index d804ee95fe..f78bd3a9d2 100644 --- a/tests/forcefields/test_jobs.py +++ b/tests/forcefields/test_jobs.py @@ -1,4 +1,6 @@ -from pytest import approx +from pytest import approx, importorskip + +importorskip("quippy") def test_chgnet_static_maker(si_structure): diff --git a/tests/test_data/lobster/lobsteroutputs/mp-2534/POTCAR.gz b/tests/test_data/lobster/lobsteroutputs/mp-2534/POTCAR.gz deleted file mode 100644 index 3d640ca34e..0000000000 Binary files a/tests/test_data/lobster/lobsteroutputs/mp-2534/POTCAR.gz and /dev/null differ diff --git a/tests/test_data/lobster/lobsteroutputs/mp-754354/POTCAR.gz b/tests/test_data/lobster/lobsteroutputs/mp-754354/POTCAR.gz deleted file mode 100644 index 5929fa2e0e..0000000000 Binary files a/tests/test_data/lobster/lobsteroutputs/mp-754354/POTCAR.gz and /dev/null differ diff --git a/tests/test_data/vasp/Si_hse_optics/hse_optics/inputs/INCAR b/tests/test_data/vasp/Si_hse_optics/hse_optics/inputs/INCAR index 24b0ac1bdc..9ac70e3177 100644 --- a/tests/test_data/vasp/Si_hse_optics/hse_optics/inputs/INCAR +++ b/tests/test_data/vasp/Si_hse_optics/hse_optics/inputs/INCAR @@ -1,4 +1,4 @@ -ALGO = All +ALGO = Normal EDIFF = 1e-05 ENAUG = 1360.0 ENCUT = 680.0 @@ -20,10 +20,12 @@ LVTOT = True LWAVE = False NBANDS = 11 NCORE = 4 -NEDOS = 5062 +NEDOS = 1265 NELM = 200 NELMIN = 5 NSW = 0 PREC = Accurate PRECFOCK = Fast SIGMA = 0.05 +CSHIFT = 1e-5 +LDAU = False diff --git a/tests/test_data/vasp/Si_hse_optics/hse_static/inputs/INCAR b/tests/test_data/vasp/Si_hse_optics/hse_static/inputs/INCAR index cbc162ec9a..4f8139f76b 100644 --- a/tests/test_data/vasp/Si_hse_optics/hse_static/inputs/INCAR +++ b/tests/test_data/vasp/Si_hse_optics/hse_static/inputs/INCAR @@ -1,4 +1,4 @@ -ALGO = All +ALGO = Normal EDIFF = 1e-05 ENAUG = 1360 ENCUT = 680 @@ -10,10 +10,11 @@ KSPACING = 0.5 LAECHG = True LASPH = True LCHARG = True -LELF = True +LELF = False LHFCALC = True LMIXTAU = True LORBIT = 11 +LDAU = False LREAL = False LVTOT = True LWAVE = False @@ -23,4 +24,4 @@ NELM = 200 NSW = 0 PREC = Accurate PRECFOCK = Fast -SIGMA = 0.05 +SIGMA = 0.2 diff --git a/tests/test_data/vasp/Si_mp_gga_relax/GGA_Relax_1/outputs/POTCAR.gz b/tests/test_data/vasp/Si_mp_gga_relax/GGA_Relax_1/outputs/POTCAR.gz deleted file mode 100644 index 62848023ed..0000000000 Binary files a/tests/test_data/vasp/Si_mp_gga_relax/GGA_Relax_1/outputs/POTCAR.gz and /dev/null differ diff --git a/tests/test_data/vasp/Si_mp_gga_relax/GGA_Relax_2/outputs/POTCAR.gz b/tests/test_data/vasp/Si_mp_gga_relax/GGA_Relax_2/outputs/POTCAR.gz deleted file mode 100644 index aabff95a04..0000000000 Binary files a/tests/test_data/vasp/Si_mp_gga_relax/GGA_Relax_2/outputs/POTCAR.gz and /dev/null differ diff --git a/tests/test_data/vasp/Si_mp_gga_relax/GGA_Static/outputs/POTCAR.gz b/tests/test_data/vasp/Si_mp_gga_relax/GGA_Static/outputs/POTCAR.gz deleted file mode 100644 index 97e9fc4131..0000000000 Binary files a/tests/test_data/vasp/Si_mp_gga_relax/GGA_Static/outputs/POTCAR.gz and /dev/null differ diff --git a/tests/test_data/vasp/Si_mp_meta_gga_relax/pbesol_pre_relax/inputs/INCAR b/tests/test_data/vasp/Si_mp_meta_gga_relax/pbesol_pre_relax/inputs/INCAR index f99b56f149..0449a1623f 100644 --- a/tests/test_data/vasp/Si_mp_meta_gga_relax/pbesol_pre_relax/inputs/INCAR +++ b/tests/test_data/vasp/Si_mp_meta_gga_relax/pbesol_pre_relax/inputs/INCAR @@ -19,7 +19,6 @@ LREAL = Auto LVTOT = True LWAVE = True MAGMOM = 2*0.0 -METAGGA = R2scan NELM = 200 NSW = 99 PREC = Accurate diff --git a/tests/test_data/vasp/Si_mp_meta_gga_relax/r2scan_final_static/inputs/INCAR b/tests/test_data/vasp/Si_mp_meta_gga_relax/r2scan_final_static/inputs/INCAR index 4fc78b68ae..5babb45f25 100644 --- a/tests/test_data/vasp/Si_mp_meta_gga_relax/r2scan_final_static/inputs/INCAR +++ b/tests/test_data/vasp/Si_mp_meta_gga_relax/r2scan_final_static/inputs/INCAR @@ -2,7 +2,6 @@ ALGO = Fast EDIFF = 1e-05 ENAUG = 1360.0 ENCUT = 680.0 -GGA = Ps ISMEAR = -5 ISPIN = 2 KSPACING = 0.29539340980039036 diff --git a/tests/test_data/vasp/Si_mp_meta_gga_relax/r2scan_relax/inputs/INCAR b/tests/test_data/vasp/Si_mp_meta_gga_relax/r2scan_relax/inputs/INCAR index 3f8e69a582..c6c4eadd46 100644 --- a/tests/test_data/vasp/Si_mp_meta_gga_relax/r2scan_relax/inputs/INCAR +++ b/tests/test_data/vasp/Si_mp_meta_gga_relax/r2scan_relax/inputs/INCAR @@ -3,10 +3,9 @@ EDIFF = 1e-05 EDIFFG = -0.05 ENAUG = 1360.0 ENCUT = 680.0 -GGA = Ps IBRION = 2 ISIF = 3 -ISMEAR = 0 +ISMEAR = -5 ISPIN = 2 KSPACING = 0.28253269576667883 LAECHG = True diff --git a/tests/test_data/vasp/Si_old_double_relax/outputs/POTCAR.gz b/tests/test_data/vasp/Si_old_double_relax/outputs/POTCAR.gz index 9106d6a249..e69de29bb2 100644 Binary files a/tests/test_data/vasp/Si_old_double_relax/outputs/POTCAR.gz and b/tests/test_data/vasp/Si_old_double_relax/outputs/POTCAR.gz differ diff --git a/tests/vasp/conftest.py b/tests/vasp/conftest.py index 44a734c49f..ad985b9707 100644 --- a/tests/vasp/conftest.py +++ b/tests/vasp/conftest.py @@ -115,7 +115,7 @@ def _run(ref_paths, fake_run_vasp_kwargs=None): def fake_run_vasp( ref_path: Path, - incar_settings: Sequence[str] = (), + incar_settings: Sequence[str] = None, check_inputs: Sequence[Literal["incar", "kpoints", "poscar", "potcar"]] = _VFILES, clear_inputs: bool = True, ): @@ -128,7 +128,8 @@ def fake_run_vasp( Path to reference directory with VASP input files in the folder named 'inputs' and output files in the folder named 'outputs'. incar_settings - A list of INCAR settings to check. + A list of INCAR settings to check. Defaults to None which checks all settings. + Empty list or tuple means no settings will be checked. check_inputs A list of vasp input files to check. Supported options are "incar", "kpoints", "poscar", "potcar", "wavecar". @@ -167,13 +168,13 @@ def fake_run_vasp( def check_incar(ref_path: Path, incar_settings: Sequence[str]): from pymatgen.io.vasp import Incar - user = Incar.from_file("INCAR") + user_incar = Incar.from_file("INCAR") ref_incar_path = ref_path / "inputs" / "INCAR" - ref = Incar.from_file(ref_incar_path) + ref_incar = Incar.from_file(ref_incar_path) defaults = {"ISPIN": 1, "ISMEAR": 1, "SIGMA": 0.2} - for key in incar_settings: - user_val = user.get(key, defaults.get(key)) - ref_val = ref.get(key, defaults.get(key)) + for key in list(user_incar) if incar_settings is None else incar_settings: + user_val = user_incar.get(key, defaults.get(key)) + ref_val = ref_incar.get(key, defaults.get(key)) if user_val != ref_val: raise ValueError( f"\n\nINCAR value of {key} is inconsistent: expected {ref_val}, " @@ -198,21 +199,22 @@ def check_kpoints(ref_path: Path): "a KPOINTS file" ) if user_kpoints_exists and ref_kpoints_exists: - user = Kpoints.from_file("KPOINTS") + user_kpts = Kpoints.from_file("KPOINTS") ref_kpt_path = ref_path / "inputs" / "KPOINTS" - ref = Kpoints.from_file(ref_kpt_path) - if user.style != ref.style or user.num_kpts != ref.num_kpts: + ref_kpts = Kpoints.from_file(ref_kpt_path) + if user_kpts.style != ref_kpts.style or user_kpts.num_kpts != ref_kpts.num_kpts: raise ValueError( - f"\n\nKPOINTS files are inconsistent: {user.style} != {ref.style} " - f"or {user.num_kpts} != {ref.num_kpts}\nin ref file {ref_kpt_path}" + f"\n\nKPOINTS files are inconsistent: {user_kpts.style} != " + f"{ref_kpts.style} or {user_kpts.num_kpts} != {ref_kpts.num_kpts}\nin " + f"ref file {ref_kpt_path}" ) else: # check k-spacing - user = Incar.from_file("INCAR") + user_incar = Incar.from_file("INCAR") ref_incar_path = ref_path / "inputs" / "INCAR" - ref = Incar.from_file(ref_incar_path) + ref_incar = Incar.from_file(ref_incar_path) - user_ksp, ref_ksp = user.get("KSPACING"), ref.get("KSPACING") + user_ksp, ref_ksp = user_incar.get("KSPACING"), ref_incar.get("KSPACING") if user_ksp != ref_ksp: raise ValueError( f"\n\nKSPACING is inconsistent: {user_ksp} != {ref_ksp} " @@ -225,22 +227,21 @@ def check_poscar(ref_path: Path): from pymatgen.io.vasp import Poscar from pymatgen.util.coord import pbc_diff - user = Poscar.from_file("POSCAR") - ref = Poscar.from_file(ref_path / "inputs" / "POSCAR") + user_poscar = Poscar.from_file("POSCAR") + ref_poscar = Poscar.from_file(ref_path / "inputs" / "POSCAR") + user_frac_coords = user_poscar.structure.frac_coords + ref_frac_coords = ref_poscar.structure.frac_coords if ( - user.natoms != ref.natoms - or user.site_symbols != ref.site_symbols - or np.any( - np.abs(pbc_diff(user.structure.frac_coords, ref.structure.frac_coords)) - > 1e-3 - ) + user_poscar.natoms != ref_poscar.natoms + or user_poscar.site_symbols != ref_poscar.site_symbols + or np.any(np.abs(pbc_diff(user_frac_coords, ref_frac_coords)) > 1e-3) ): ref_poscar_path = ref_path / "inputs" / "POSCAR" user_poscar_path = Path("POSCAR").absolute() raise ValueError( - f"POSCAR files are inconsistent\n\n{ref_poscar_path!s}\n{ref}" - f"\n\n{user_poscar_path!s}\n{user}" + f"POSCAR files are inconsistent\n\n{ref_poscar_path!s}\n{ref_poscar}" + f"\n\n{user_poscar_path!s}\n{user_poscar}" ) @@ -248,21 +249,25 @@ def check_potcar(ref_path: Path): from pymatgen.io.vasp import Potcar if Path(ref_path / "inputs" / "POTCAR").exists(): - ref = Potcar.from_file(ref_path / "inputs" / "POTCAR").symbols + ref_potcar = Potcar.from_file(ref_path / "inputs" / "POTCAR").symbols elif Path(ref_path / "inputs" / "POTCAR.spec").exists(): - ref = Path(ref_path / "inputs" / "POTCAR.spec").read_text().strip().split("\n") + ref_potcar = ( + Path(ref_path / "inputs" / "POTCAR.spec").read_text().strip().split("\n") + ) else: raise FileNotFoundError("no reference POTCAR or POTCAR.spec file found") if Path("POTCAR").exists(): - user = Potcar.from_file("POTCAR").symbols + user_potcar = Potcar.from_file("POTCAR").symbols elif Path("POTCAR.spec").exists(): - user = Path("POTCAR.spec").read_text().strip().split("\n") + user_potcar = Path("POTCAR.spec").read_text().strip().split("\n") else: raise FileNotFoundError("no POTCAR or POTCAR.spec file found") - if user != ref: - raise ValueError(f"POTCAR files are inconsistent: {user} != {ref}") + if user_potcar != ref_potcar: + raise ValueError( + f"POTCAR files are inconsistent: {user_potcar} != {ref_potcar}" + ) def clear_vasp_inputs():