From 5131932d5f6f130455bcf9457e5b155366c2bab3 Mon Sep 17 00:00:00 2001 From: Rohith Srinivaas M Date: Tue, 24 Sep 2024 07:45:09 -0700 Subject: [PATCH] Frequency Flattening Optimizer (#863) * flows for ffopt * opt freq works * ffopt working * remove vim swap files and add extensions to gitignore * precommit * Add prev_dir kwarg to qchem jobs and deprecation warning for prev_qchem_dir * linting * cleanup * fix failing set test * slight cleanup * move H2O.xyz file to pytest fixture * make qchem taskdoc task_type more flexible, add tests for ffopt * precommit * remove duplicate frequency_analysis_2 test dir * precommit --------- Co-authored-by: Rohith Srinivaas Mohanakrishnan Co-authored-by: Rohith Srinivaas Mohanakrishnan Co-authored-by: Aaron Kaplan <33381112+esoteric-ephemera@users.noreply.github.com> Co-authored-by: esoteric-ephemera --- .gitignore | 4 + src/atomate2/qchem/flows/__init__.py | 1 + src/atomate2/qchem/flows/core.py | 225 ++++++++++++++++++ src/atomate2/qchem/jobs/base.py | 34 ++- src/atomate2/qchem/jobs/core.py | 1 + src/atomate2/qchem/run.py | 3 +- src/atomate2/qchem/sets/base.py | 16 +- src/atomate2/settings.py | 2 +- tests/qchem/conftest.py | 16 ++ tests/qchem/flows/test_core.py | 87 +++++++ tests/qchem/jobs/H2O.xyz | 5 - tests/qchem/jobs/test_core.py | 20 +- .../frequency_analysis_1/inputs/mol.qin.gz | Bin 0 -> 265 bytes .../frequency_analysis_1/outputs/132.0.gz | Bin 0 -> 549 bytes .../frequency_analysis_1/outputs/53.0.gz | Bin 0 -> 10948 bytes .../frequency_analysis_1/outputs/HESS.gz | Bin 0 -> 533 bytes .../frequency_analysis_1/outputs/mol.qclog.gz | Bin 0 -> 583 bytes .../frequency_analysis_1/outputs/mol.qin.gz | Bin 0 -> 265 bytes .../outputs/mol.qin.orig.gz | Bin 0 -> 270 bytes .../frequency_analysis_1/outputs/mol.qout.gz | Bin 0 -> 6611 bytes .../geometry_optimization/inputs/mol.qin.gz | Bin 0 -> 264 bytes .../geometry_optimization/outputs/131.0.gz | Bin 0 -> 98 bytes .../geometry_optimization/outputs/53.0.gz | Bin 0 -> 10984 bytes .../geometry_optimization/outputs/GRAD.gz | Bin 0 -> 180 bytes .../outputs/mol.qclog.gz | Bin 0 -> 582 bytes .../geometry_optimization/outputs/mol.qin.gz | Bin 0 -> 264 bytes .../outputs/mol.qin.orig.gz | Bin 0 -> 269 bytes .../geometry_optimization/outputs/mol.qout.gz | Bin 0 -> 9314 bytes 28 files changed, 380 insertions(+), 34 deletions(-) create mode 100644 src/atomate2/qchem/flows/__init__.py create mode 100644 src/atomate2/qchem/flows/core.py create mode 100644 tests/qchem/flows/test_core.py delete mode 100644 tests/qchem/jobs/H2O.xyz create mode 100644 tests/test_data/qchem/ffopt/frequency_analysis_1/inputs/mol.qin.gz create mode 100644 tests/test_data/qchem/ffopt/frequency_analysis_1/outputs/132.0.gz create mode 100644 tests/test_data/qchem/ffopt/frequency_analysis_1/outputs/53.0.gz create mode 100644 tests/test_data/qchem/ffopt/frequency_analysis_1/outputs/HESS.gz create mode 100644 tests/test_data/qchem/ffopt/frequency_analysis_1/outputs/mol.qclog.gz create mode 100644 tests/test_data/qchem/ffopt/frequency_analysis_1/outputs/mol.qin.gz create mode 100644 tests/test_data/qchem/ffopt/frequency_analysis_1/outputs/mol.qin.orig.gz create mode 100644 tests/test_data/qchem/ffopt/frequency_analysis_1/outputs/mol.qout.gz create mode 100644 tests/test_data/qchem/ffopt/geometry_optimization/inputs/mol.qin.gz create mode 100644 tests/test_data/qchem/ffopt/geometry_optimization/outputs/131.0.gz create mode 100644 tests/test_data/qchem/ffopt/geometry_optimization/outputs/53.0.gz create mode 100644 tests/test_data/qchem/ffopt/geometry_optimization/outputs/GRAD.gz create mode 100644 tests/test_data/qchem/ffopt/geometry_optimization/outputs/mol.qclog.gz create mode 100644 tests/test_data/qchem/ffopt/geometry_optimization/outputs/mol.qin.gz create mode 100644 tests/test_data/qchem/ffopt/geometry_optimization/outputs/mol.qin.orig.gz create mode 100644 tests/test_data/qchem/ffopt/geometry_optimization/outputs/mol.qout.gz diff --git a/.gitignore b/.gitignore index 6cdafcdcea..48fb61470e 100644 --- a/.gitignore +++ b/.gitignore @@ -64,6 +64,10 @@ docs/reference/atomate2.* .DS_Store +# vim extensions +*.swp +*.swo + # see https://github.com/materialsproject/atomate2/issues/345 *.doctrees* diff --git a/src/atomate2/qchem/flows/__init__.py b/src/atomate2/qchem/flows/__init__.py new file mode 100644 index 0000000000..ee1c9c1dab --- /dev/null +++ b/src/atomate2/qchem/flows/__init__.py @@ -0,0 +1 @@ +"""Flows for running Q-Chem calculations.""" diff --git a/src/atomate2/qchem/flows/core.py b/src/atomate2/qchem/flows/core.py new file mode 100644 index 0000000000..4f7b89d7d1 --- /dev/null +++ b/src/atomate2/qchem/flows/core.py @@ -0,0 +1,225 @@ +"""Define core QChem flows.""" + +from __future__ import annotations + +from copy import deepcopy +from dataclasses import dataclass, field +from typing import TYPE_CHECKING + +from jobflow import Flow, Maker, Response, job + +from atomate2.qchem.jobs.core import FreqMaker, OptMaker + +if TYPE_CHECKING: + from pathlib import Path + + from jobflow import Job + from pymatgen.core.structure import Molecule + + from atomate2.qchem.jobs.base import BaseQCMaker + + +@dataclass +class DoubleOptMaker(Maker): + """ + Maker to perform a double Qchem relaxation. + + Parameters + ---------- + name : str + Name of the flows produced by this maker. + relax_maker1 : .BaseVaspMaker + Maker to use to generate the first relaxation. + relax_maker2 : .BaseVaspMaker + Maker to use to generate the second relaxation. + """ + + name: str = "double opt" + opt_maker1: BaseQCMaker | None = field(default_factory=OptMaker) + opt_maker2: BaseQCMaker = field(default_factory=OptMaker) + + def make(self, molecule: Molecule, prev_dir: str | Path | None = None) -> Flow: + """ + Create a flow with two chained molecular optimizations. + + Parameters + ---------- + molecule : .Molecule + A pymatgen Molecule object. + prev_dir : str or Path or None + A previous QChem calculation directory to copy output files from. + + Returns + ------- + Flow + A flow containing two geometric optimizations. + """ + jobs: list[Job] = [] + if self.opt_maker1: + # Run a pre-relaxation + opt1 = self.opt_maker1.make(molecule, prev_dir=prev_dir) + opt1.name += " 1" + jobs += [opt1] + molecule = opt1.output.optimized_molecule + prev_dir = opt1.output.dir_name + + opt2 = self.opt_maker2.make(molecule, prev_dir=prev_dir) + opt2.name += " 2" + jobs += [opt2] + + return Flow(jobs, output=opt2.output, name=self.name) + + @classmethod + def from_opt_maker(cls, opt_maker: BaseQCMaker) -> DoubleOptMaker: + """ + Instantiate the DoubleRelaxMaker with two relax makers of the same type. + + Parameters + ---------- + opt_maker : .BaseQCMaker + Maker to use to generate the first and second geometric optimizations. + """ + return cls(relax_maker1=deepcopy(opt_maker), relax_maker2=deepcopy(opt_maker)) + + +@dataclass +class FrequencyOptMaker(Maker): + """ + Maker to perform a frequency calculation after an optimization. + + Parameters + ---------- + name : str + Name of the flows produced by this maker. + opt_maker : .BaseQCMaker + Maker to use to generate the opt maker + freq_maker : .BaseQCMaker + Maker to use to generate the freq maker + """ + + name: str = "opt frequency" + opt_maker: BaseQCMaker = field(default_factory=OptMaker) + freq_maker: BaseQCMaker = field(default_factory=FreqMaker) + + def make(self, molecule: Molecule, prev_dir: str | Path | None = None) -> Flow: + """ + Create a flow with optimization followed by frequency calculation. + + Parameters + ---------- + molecule : .Molecule + A pymatgen Molecule object. + prev_dir : str or Path or None + A previous QChem calculation directory to copy output files from. + + Returns + ------- + Flow + A flow containing with optimization and frequency calculation. + """ + jobs: list[Job] = [] + opt = self.opt_maker.make(molecule, prev_dir=prev_dir) + opt.name = "Geometry Optimization" + jobs += [opt] + + freq = self.freq_maker.make( + molecule=opt.output.output.optimized_molecule, + prev_dir=opt.output.dir_name, + ) + freq.name = "Frequency Analysis" + jobs += [freq] + + return Flow( + jobs, output={"opt": opt.output, "freq": freq.output}, name=self.name + ) + + +@dataclass +class FrequencyOptFlatteningMaker(Maker): + """ + Maker to perform a frequency calculation after an optimization. + + Parameters + ---------- + name : str + Name of the flows produced by this maker. + opt_maker : .BaseQCMaker + Maker to use to generate the opt maker + freq_maker : .BaseQCMaker + Maker to use to generate the freq maker + """ + + name: str = "frequency flattening opt" + opt_maker: BaseQCMaker = field(default_factory=OptMaker) + freq_maker: BaseQCMaker = field(default_factory=FreqMaker) + scale: float = 1.0 + max_ffopt_runs: int = 5 + + @job + def make( + self, + molecule: Molecule, + mode: list | None = None, + lowest_freq: float = -1.0, + ffopt_runs: int = 0, + overwrite_inputs: dict | None = None, + prev_dir: str | Path | None = None, + ) -> Flow: + """ + Optimize geometry and perturb negative frequency modes. + + Parameters + ---------- + molecule : .Molecule + A pymatgen Molecule object. + prev_dir : str or Path or None + A previous QChem calculation directory to copy output files from. + + Returns + ------- + Flow + A flow containing with optimization and frequency calculation. + """ + mode = mode or [[0.0, 0.0, 0.0] for _ in range(len(molecule))] + + if overwrite_inputs is not None: + self.opt_maker.input_set_generator.overwrite_inputs = overwrite_inputs + self.freq_maker.input_set_generator.overwrite_inputs = overwrite_inputs + + new_flow = None + new_output = None + + if (lowest_freq < 0) and (ffopt_runs < self.max_ffopt_runs): + jobs: list[Job] = [] + + for idx in range(len(molecule)): + molecule.translate_sites( + indices=[idx], vector=[self.scale * v for v in mode[idx]] + ) + + opt = self.opt_maker.make(molecule, prev_dir=prev_dir) + opt.name = "Geometry Optimization" + jobs += [opt] + molecule = opt.output.output.optimized_molecule + + freq = self.freq_maker.make(molecule, prev_dir=prev_dir) + freq.name = f"Frequency Analysis {ffopt_runs + 1}" + jobs += [freq] + + recursive = self.make( + molecule, + mode=freq.output.output.frequency_modes[0], + lowest_freq=freq.output.output.frequencies[0], + ffopt_runs=ffopt_runs + 1, + prev_dir=prev_dir, + ) + new_flow = Flow([*jobs, recursive], output=recursive.output) + new_output = recursive.output + + elif ffopt_runs == 0: + freq = self.freq_maker.make(molecule, prev_dir=prev_dir) + freq.name = f"Frequency Analysis {ffopt_runs + 1}" + new_flow = [freq] + new_output = freq.output + + return Response(replace=new_flow, output=new_output) diff --git a/src/atomate2/qchem/jobs/base.py b/src/atomate2/qchem/jobs/base.py index d67322917c..4de1d9499e 100644 --- a/src/atomate2/qchem/jobs/base.py +++ b/src/atomate2/qchem/jobs/base.py @@ -2,6 +2,7 @@ from __future__ import annotations +import logging from dataclasses import dataclass, field from pathlib import Path from typing import TYPE_CHECKING, Callable @@ -19,6 +20,8 @@ if TYPE_CHECKING: from pymatgen.core.structure import Molecule +logger = logging.getLogger(__name__) + def qchem_job(method: Callable) -> job: """ @@ -94,10 +97,14 @@ class BaseQCMaker(Maker): task_document_kwargs: dict = field(default_factory=dict) stop_children_kwargs: dict = field(default_factory=dict) write_additional_data: dict = field(default_factory=dict) + task_type: str | None = None @qchem_job def make( - self, molecule: Molecule, prev_qchem_dir: str | Path | None = None + self, + molecule: Molecule, + prev_dir: str | Path | None = None, + prev_qchem_dir: str | Path | None = None, ) -> Response: """Run a QChem calculation. @@ -105,19 +112,36 @@ def make( ---------- molecule : Molecule A pymatgen molecule object. - prev_qchem_dir : str or Path or None + prev_dir : str or Path or None + A previous calculation directory to copy output files from. + prev_qchem_dir (deprecated): str or Path or None A previous QChem calculation directory to copy output files from. """ # copy previous inputs - from_prev = prev_qchem_dir is not None if prev_qchem_dir is not None: - copy_qchem_outputs(prev_qchem_dir, **self.copy_qchem_kwargs) + logger.warning( + "`prev_qchem_dir` will be deprecated in a future release. " + "Please use `prev_dir` instead." + ) + if prev_dir is not None: + logger.warning( + "You set both `prev_dir` and `prev_qchem_dir`, " + "only `prev_dir` will be used." + ) + else: + prev_dir = prev_qchem_dir + + if from_prev := (prev_dir is not None): + copy_qchem_outputs(prev_dir, **self.copy_qchem_kwargs) self.write_input_set_kwargs.setdefault("from_prev", from_prev) # write qchem input files # self.input_set_generator.get_input_set(molecule).write_inputs() self.input_set_generator.get_input_set(molecule) + self.input_set_generator.get_input_set(molecule).write_input( + directory=Path.cwd() + ) # write any additional data for filename, data in self.write_additional_data.items(): @@ -129,7 +153,7 @@ def make( # parse qchem outputs task_doc = TaskDoc.from_directory(Path.cwd(), **self.task_document_kwargs) # task_doc.task_label = self.name - task_doc.task_type = self.name + task_doc.task_type = self.name if self.task_type is None else self.task_type # decide whether child jobs should proceed stop_children = should_stop_children(task_doc, **self.stop_children_kwargs) diff --git a/src/atomate2/qchem/jobs/core.py b/src/atomate2/qchem/jobs/core.py index b0d7987d1f..2f297be4e4 100644 --- a/src/atomate2/qchem/jobs/core.py +++ b/src/atomate2/qchem/jobs/core.py @@ -197,6 +197,7 @@ class FreqMaker(BaseQCMaker): name: str = "frequency" input_set_generator: QCInputGenerator = field(default_factory=FreqSetGenerator) + task_type: str = "Frequency Analysis" @dataclass diff --git a/src/atomate2/qchem/run.py b/src/atomate2/qchem/run.py index 9010dc7b68..1f4d67709a 100644 --- a/src/atomate2/qchem/run.py +++ b/src/atomate2/qchem/run.py @@ -21,7 +21,7 @@ from emmet.core.qc_tasks import TaskDoc -_DEFAULT_HANDLERS = (QChemErrorHandler,) +_DEFAULT_HANDLERS = (QChemErrorHandler(),) logger = logging.getLogger(__name__) @@ -95,7 +95,6 @@ def run_qchem( scratch_dir=scratch_dir, **custodian_kwargs, ) - logger.info("Running QChem using custodian.") c.run() diff --git a/src/atomate2/qchem/sets/base.py b/src/atomate2/qchem/sets/base.py index 9592b5dfef..29eb04db7c 100644 --- a/src/atomate2/qchem/sets/base.py +++ b/src/atomate2/qchem/sets/base.py @@ -66,11 +66,13 @@ def write_input( inputs.update(self.optional_files) for key, val in inputs.items(): - if val is not None and (overwrite or not (directory / key).exists()): - with zopen(directory / key, "wt") as file: + inp_key = "mol.qin" if key == "Input_Dict" else f"{key}.qin" + if val is not None and (overwrite or not (directory / inp_key).exists()): + # should this be open instead of zopen? can QChem inputs be gzipped? + with zopen(directory / inp_key, "wt") as file: file.write(str(val)) - elif not overwrite and (directory / key).exists(): - raise FileExistsError(f"{directory / key} already exists.") + elif not overwrite and (directory / inp_key).exists(): + raise FileExistsError(f"{directory / inp_key} already exists.") @staticmethod def from_directory( @@ -91,9 +93,9 @@ def from_directory( inputs = {} for name, obj in objs.items(): - if (directory / name).exists(): - inputs[name.lower()] = obj.from_file(directory / name) - + file_path = directory / ("mol.qin" if name == "Input_Dict" else name) + if file_path.exists(): + inputs[name.lower()] = obj.from_file(file_path) optional_inputs = {} if optional_files is not None: for name, obj in optional_files.items(): diff --git a/src/atomate2/settings.py b/src/atomate2/settings.py index 64157f7b60..0f987a0cbf 100644 --- a/src/atomate2/settings.py +++ b/src/atomate2/settings.py @@ -220,7 +220,7 @@ class Atomate2Settings(BaseSettings): # QChem specific settings QCHEM_CMD: str = Field( - "qchem_std", description="Command to run standard version of qchem." + "qchem", description="Command to run standard version of qchem." ) QCHEM_CUSTODIAN_MAX_ERRORS: int = Field( diff --git a/tests/qchem/conftest.py b/tests/qchem/conftest.py index d20ea563da..e8ced094f7 100644 --- a/tests/qchem/conftest.py +++ b/tests/qchem/conftest.py @@ -7,6 +7,7 @@ import pytest from jobflow import CURRENT_JOB +from pymatgen.core import Molecule from pymatgen.io.qchem.inputs import QCInput from pytest import MonkeyPatch @@ -26,6 +27,18 @@ _FAKE_RUN_QCHEM_KWARGS: dict[str, dict] = {} +@pytest.fixture +def h2o_molecule(): + return Molecule( + coords=[ + [0.0000, 0.0000, 0.12124], + [-0.78304, -0.00000, -0.48495], + [0.78304, -0.00000, -0.48495], + ], + species=["O", "H", "H"], + ) + + @pytest.fixture(scope="session") def qchem_test_dir(test_dir): return test_dir / "qchem" @@ -169,6 +182,9 @@ def check_qin( user_qin_path = script_directory / "opt.qin.gz" elif job_name == "water_frequency": user_qin_path = script_directory / "freq.qin.gz" + else: + user_qin_path = Path("mol.qin") + user_qin = QCInput.from_file(user_qin_path) keys_to_check = ( diff --git a/tests/qchem/flows/test_core.py b/tests/qchem/flows/test_core.py new file mode 100644 index 0000000000..2fadffcb00 --- /dev/null +++ b/tests/qchem/flows/test_core.py @@ -0,0 +1,87 @@ +from pathlib import Path + +import pytest +from jobflow import run_locally + +from atomate2.qchem.flows.core import FrequencyOptFlatteningMaker, FrequencyOptMaker + +fake_run_qchem_kwargs = {} + + +def test_frequency_opt_maker(mock_qchem, clean_dir, qchem_test_dir, h2o_molecule): + ref_paths = { + "Geometry Optimization": Path(qchem_test_dir) + / "ffopt" + / "geometry_optimization", + "Frequency Analysis": Path(qchem_test_dir) / "ffopt" / "frequency_analysis_1", + } + mock_qchem(ref_paths, fake_run_qchem_kwargs) + + flow = FrequencyOptMaker().make(h2o_molecule) + responses = run_locally(flow, create_folders=True, ensure_success=True) + + output = {job.name: responses[job.uuid][1].output for job in flow} + + ref_total_energy = -76.346601 + assert output["Geometry Optimization"].output.final_energy == pytest.approx( + ref_total_energy, rel=1e-6 + ) + + assert output["Frequency Analysis"].output.final_energy == pytest.approx( + ref_total_energy, rel=1e-6 + ) + ref_freq = [1587.39, 3864.9, 3969.87] + assert all( + freq == pytest.approx(ref_freq[i], abs=1e-2) + for i, freq in enumerate(output["Frequency Analysis"].output.frequencies) + ) + assert ( + output["Geometry Optimization"].output.optimized_molecule + == output["Frequency Analysis"].output.initial_molecule + ) + assert output["Frequency Analysis"].output.optimized_molecule is None + + +def test_frequency_opt_flattening_maker( + mock_qchem, clean_dir, qchem_test_dir, h2o_molecule +): + ref_paths = { + k: Path(qchem_test_dir) / "ffopt" / f"{k.lower().replace(' ','_')}" + for k in ("Geometry Optimization", "Frequency Analysis 1") + } + + mock_qchem(ref_paths, fake_run_qchem_kwargs) + flow = FrequencyOptFlatteningMaker().make(h2o_molecule) + responses = run_locally(flow, create_folders=True, ensure_success=True) + + # first get job name / uuid pairs from dynamic flow + uuid_to_name = {} + for resp in responses.values(): + if replace_flow := getattr(resp[1], "replace", None): + uuid_to_name.update({job.uuid: job.name for job in replace_flow.jobs}) + + # then get job output + output = {} + for uuid, job_name in uuid_to_name.items(): + output[job_name] = responses[uuid][1].output + + ref_total_energy = -76.346601 + assert output["Geometry Optimization"].output.final_energy == pytest.approx( + ref_total_energy, rel=1e-6 + ) + + # because the initial frequency analysis has no negative frequencies, + # the workflow only performs one frequency analysis + assert output["Frequency Analysis 1"].output.final_energy == pytest.approx( + ref_total_energy, rel=1e-6 + ) + ref_freq = [1587.39, 3864.9, 3969.87] + assert all( + freq == pytest.approx(ref_freq[i], abs=1e-2) + for i, freq in enumerate(output["Frequency Analysis 1"].output.frequencies) + ) + assert ( + output["Geometry Optimization"].output.optimized_molecule + == output["Frequency Analysis 1"].output.initial_molecule + ) + assert output["Frequency Analysis 1"].output.optimized_molecule is None diff --git a/tests/qchem/jobs/H2O.xyz b/tests/qchem/jobs/H2O.xyz deleted file mode 100644 index 212ca2ea8f..0000000000 --- a/tests/qchem/jobs/H2O.xyz +++ /dev/null @@ -1,5 +0,0 @@ -3 - -O 0.00000 0.00000 0.12124 -H -0.78304 -0.00000 -0.48495 -H 0.78304 0.00000 -0.48495 diff --git a/tests/qchem/jobs/test_core.py b/tests/qchem/jobs/test_core.py index 75b5907cf5..e6bf0058cf 100644 --- a/tests/qchem/jobs/test_core.py +++ b/tests/qchem/jobs/test_core.py @@ -1,19 +1,11 @@ -from pathlib import Path - from emmet.core.qc_tasks import TaskDoc from jobflow import run_locally -from pymatgen.core.structure import Molecule from pytest import approx from atomate2.qchem.jobs.core import FreqMaker, OptMaker, SinglePointMaker -current_directory = Path(__file__).resolve().parent -file_name = current_directory / "H2O.xyz" - -H2O = Molecule.from_file(file_name) - -def test_single_point_maker(mock_qchem, clean_dir): +def test_single_point_maker(mock_qchem, clean_dir, h2o_molecule): # mapping from job name to directory containing test files ref_paths = {"single point": "water_single_point"} @@ -25,7 +17,7 @@ def test_single_point_maker(mock_qchem, clean_dir): mock_qchem(ref_paths, fake_run_qchem_kwargs) # generate job - job = SinglePointMaker().make(H2O) + job = SinglePointMaker().make(h2o_molecule) # run the flow or job and ensure that it finished running successfully responses = run_locally(job, create_folders=True, ensure_success=True) @@ -36,12 +28,12 @@ def test_single_point_maker(mock_qchem, clean_dir): assert output1.output.final_energy == approx(-76.4451488262) -def test_opt_maker(mock_qchem, clean_dir): +def test_opt_maker(mock_qchem, clean_dir, h2o_molecule): ref_paths = {"optimization": "water_optimization"} fake_run_qchem_kwargs = {} mock_qchem(ref_paths, fake_run_qchem_kwargs) - job = OptMaker().make(H2O) + job = OptMaker().make(h2o_molecule) responses = run_locally(job, create_folders=True, ensure_success=True) opt_geometry = { @@ -83,12 +75,12 @@ def test_opt_maker(mock_qchem, clean_dir): assert output1.output.final_energy == approx(-76.450849061819) -def test_freq(mock_qchem, clean_dir): +def test_freq(mock_qchem, clean_dir, h2o_molecule): ref_paths = {"frequency": "water_frequency"} fake_run_qchem_kwargs = {} mock_qchem(ref_paths, fake_run_qchem_kwargs) - job = FreqMaker().make(H2O) + job = FreqMaker().make(h2o_molecule) responses = run_locally(job, create_folders=True, ensure_success=True) ref_freqs = [1643.03, 3446.82, 3524.32] diff --git a/tests/test_data/qchem/ffopt/frequency_analysis_1/inputs/mol.qin.gz b/tests/test_data/qchem/ffopt/frequency_analysis_1/inputs/mol.qin.gz new file mode 100644 index 0000000000000000000000000000000000000000..620b6644ba313f5eac25887ea8825b2c6d754bd2 GIT binary patch literal 265 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%0A*u~G|8wyPGxWQliT2B zzM(ZAyX_Gk=1Hatl=_lX5|0O|!x-nN-6@80w!c8j}C;YY_@23Z0 znoq3p^Hk_+h|^TL`a56e0ticcf!}cKi`K5Ew|%d6A_)(6#HL6|79n`Ri6THN6(Sra zZf&!W2RR)H*S|Lf-47L-h2ClJs2O;RG$=tCSuhLQ`qV}wd!sJeoL{BO!hp|YlHS(E zU%cBI4k!t4p2%$e<7UN?vWY(tvBk=}jAdKp2W0)b(;--*cea|D6g*O|G!2BV*H&r= zo0Af3OV_)C9d__PZlOoi!AWh(PfRq0*%td1QWr)nPdud1A?2+@HN~S63Vc7j_APV2 z6($Cx1l!)7Txqobu8F~xyPa07@W=PIwlmeki&uNG_cU1s?u5Pbx_R>BI4c4(grYeH zvGbW6oKx8Rzw;^#vW?iS`lR|86-!lbL35Abho))3n1ItZRUS{2XF6MhGgO+(e z{7c3HO;|lhx8{VlX66^sE|^NiyfLy}5ZJTq7dpS42WsZMTC0>pE+w4s6sPvSx(Lnb z;U))$-CZF{aA%dXZ-Y+Rj-ibNRJyLN#poZwp_A|CCJq(J(g*#5hsToa)7==iQyX3X zBHtt5<@Yu2oNvZqIQ+ebScx-z$u4)$<|II=BknCVIgsq@oK4=-nN8caZuy#QV~jVc zRSc6dszBE&3=crg>Ef{GI-3|CXbxVju_o)S@?&Bgn^&x`Y^8sMyRYz-1Q% z&7-I`H-Gly7s_;5HI@L8*87|e|CnuQ@C03EU&KW5HQaqpKnSw4) zKp(Jm=5tNcj-{y|s^5GtsVaFg+ug0z~91_dgo0|D}W6~*>Mh0AOtqG7F zLq*%5(b`=_$`)!-O`b)NS3ggHu7qs^{m)KiDX~(1s@iigiG?E=*D_{g9q7h|9aWIm z8Xx$Wuzs5R=Nb2ld6#CqDRVW(Nn!04`q@q6yDsc@XfGo*;`ddouLYgp$;TtIRvDoL>x}6iT#w{A*LsCy&SO z5%j{_L+u&DL=DXbMzVLe4iE)hZ`>}o`7WQ0UmqSLDP0H}CnVc>d@{BiE8j|#x;Vid z6My^31HgH@S~7@rS)#YFeQj)Rx*vL&i8&doF(R*`IQBQYnvGD)}Q-cjY_y>sNPz5it@r1}R- zC++E`hoy=P8dHLY5jpvrNhM{{a`yvGSwF~V%|Ut#Iq zt-aN_ROtd z@ZjIcd|S&bAGYlT65dF=pyH$Dm*M<}A>%(B8-rsRL%v#iArIf|Uz$C2lU}uo+={rzOuq+9S43%2kB_I_%;Nl@xv92b0W=&R1BY@3_Mqu6#|@)Q zf@HWxWv1^8N@=JKMwG<14&3NFXOcyKV1C=XO#AbO9k4vQ7BwZYNt+$XWBa~@vF;&0 zhBkn6FoY`akIvq!$S)+3${$uvpo^hI^y~d=O!uAC4AdzRa#UZRDwz0mlM0cE6E$olFs1srxta1gF zp*Ujg;5(M7E4D^!M3^)8Mxc3)frTZT=49k}Y01BtjO)D$-9@T${J!cZ;Yt#$*QTNx zS@`y&CKZ+8+*|q#f06k7c*!+QrH@SZ1WZO#jV0jx;25_K%0Iuk>#xOh^`Cw4BPNbB zt_yxdT;lp~<{}z#N>W4FYbaj(CmI;*R`AqQnZg2d@r0GsI+CAyhB?!;ZJM7dI>&{D z81pzyV*I&&5;(kcS}I#umIyH0v<}6xD}23(Gn3g`NsVDLVm9* literal 0 HcmV?d00001 diff --git a/tests/test_data/qchem/ffopt/frequency_analysis_1/outputs/HESS.gz b/tests/test_data/qchem/ffopt/frequency_analysis_1/outputs/HESS.gz new file mode 100644 index 0000000000000000000000000000000000000000..090407034473a1a15a0fc40b36abcb1dfaa4e791 GIT binary patch literal 533 zcmV+w0_y!AiwFoRQ(9&K|42nsQvhvKyN(+%5bOOFTU={l-jDwBApvqgT*N8-|3Ii+ zt$l~w0@`9EkuxOq_WR@Uxc$6e-fw?C?vLBw`?i05*)|$U5_5@qv(mnE*{(90xV^|S z%iQ9}l{mJm4N@2EWQ%!Ip-#SEC^J_T$%?3$8?4(FgNy|z!d}g8v+k4Gyiim2^r-5S znT9&+T+G>7a&)`Npp;@(*J5|6)e#M0j#hGS<8EF+V9>+_mKqTj+uGRY-1i53+;B}kkyh8Zq%d*L?%h6Naz*PXhPR= zX0v0o$-ppxD%&81`XSOhFO4q4v$8blHJf0BfO@4J7<`GO1NvlY2z5{zKh+jaHHqm_ zNYi&}qun}zasU)Y&u%zPcmMMMda6CQUx6vHDR)I9Q9OMnc*jH9TBw**uzGbg^OAzx zAzYr2c0d20ZQ>^bkeI4n8>xVXoKK`>Tl(ziVD>$#0aI`z4csevmw5p#8ao+mz>Q_w z6mOTAlu+%ir~e2%&SGir4i}?!GlBw@KauDU%v*a=Gp!8ftL|Q69q$S Xd>bS?gY@=s|8@BXAF_OyX#@ZO?u-Eb literal 0 HcmV?d00001 diff --git a/tests/test_data/qchem/ffopt/frequency_analysis_1/outputs/mol.qclog.gz b/tests/test_data/qchem/ffopt/frequency_analysis_1/outputs/mol.qclog.gz new file mode 100644 index 0000000000000000000000000000000000000000..b622a3d5801ce7fdb764d01189eec415c6b0e1de GIT binary patch literal 583 zcmV-N0=WGjiwFoRQ(9&K|7~w*iv zp{#aK$OM;Uo7lm2fc^WOgh12o39VEMBzrvb^5*&3zeEL8GLRML8Q;R(3{qCWo=KGn z?!myaE!#L`I#qPfU^pCtV;DEa4g3~sP)uvA!gVeZnnNm-_5gUcvF$u^r1BUaDimuK(lYIbC}#*ViZPFJc0S}nZ)1)BM>A4Or*0GW@AFdq96 z!cS)7bC(@4(HJbzLjLI}xl7QE=UkOYs*@A}7D4R41|zS-@4K8d52BaAkB|X=o#>*( z$m?YGIF3(pogz=;D4fONQ=3CN)cqe}oBYkxFC-2^zN6UcLip>B{qIgmB`)hK7`CT| zA@n}WKN&w>j5^*2rP9ymU5}#7k~SPKr1Ny;eJPm8{y)O-r z`aP=e`RT=CeBYtXj-`;AZR&8N$~=JPF2coXI76;ee-gsS>B8xz!1=f?lB==tYAk)49z0fJZE22R~8?zo^YEJ3> zwrwL~r|vT9N$OoMfc=^=jH!_S`+$Ak75t(s}6AbMY5-6o#<=M z`$s~bicNI9?a!CbMH{mo zVQNn4{kCl*VyEsh>PhNdFM$1;G2{kTrvXS6dsAXVWJ2tb#ciwFoRQ(9&K|7~w~`13UYN|f!)Y$n;N!j>``60ds2yi&)Kgd=RST zQY8nOy3e0@Dh?8nW?}b0GdgHFuHznvZvy>Qsum8KU$Q^vUt_PH&mzWBg5`>RsQ1C# z(Dc}cf+u;gWEX<3*lB|I(@3zRA}>pq*XkjX@q;qlKSx*^%@LX^UCP|F zLDvW4OtS&mg~JA7xq4FZ{XNF+A}p?VaID!59CpI>TudCJqf#2CSq?knp_*l+JMcPn z*g22oQcpWWr^qsN5-SZ>;>m&pI_K@qwT$+HxO z%Mk`tno6_gxr0MV<{VADxQ=<2iPSKKq+<~o!A5$MpX8j!dV{k50V-RtTSW`q(q8W( zYT__@F<+LgSt`OPFZI-m=g>7z>FkEoT@*4EW~(RYCv&)fpcOx%mq+}O$HEBno~OB0 z5=4G47J7{yHMNMB)QV$;eUduWmpZP*f`0xs!t0X*%8;w@al-?B9fZR2OQ?2P^AaK!H!aJ1I6%~>l8&QtQC+F&($B)v8d#vKQSlej`N2KXKHIru?@^gKdtz@E}?XHiDm?x5# zhI3pX@NzSmx@*3?w|qZ4#=jESbNxgZAGp@`ME~dMjE7Ol=QE8IM)xD_3MV3+W!9}v z$X;NB&+HRS!H%i92p{ZW-D!6^p`9c~&J$IHWFj|3@=zq~q%ayi7wMCvt~4s6S;abu zO8Y&15Ocf0=_AE6I;?e({01IpH0Q4PCaGyoG5HNXeI^a>_Y@=M#Y5@f=UmXalATh= ztdCX%OJ8$Atj|D#c*V{oInAv~7BgA)YNV#~xPapzv=AHY@?3?_Dy_d4CNfYIU0|=o zLPf?Q&lNoNK}!xXxO|W)r`I`83uDCRs)(ibs3~=xcpN^jAI!01sspQ!s3mvQPs++*ob$;_O|g@|$$8`~Mf0}u`AMZ^_Ff8Dv2 z^=o0<&}$YIX!FvuE~JAyU9q>L(eF7H<-*zyj_H_pp8Pl$c8!b4R#LS#dVG8(4+6qFlNs|_B{%0M*2Y4e2VkuhU*Rm6??4RtqDDz#3l`_GySwwKhe zDGr@k*>Ke|00E>%0D2c*@M00gdb7rDCOV*w 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 RrI%Xm{{Ye8D{R0*003AJ3?~2p literal 0 HcmV?d00001 diff --git a/tests/test_data/qchem/ffopt/geometry_optimization/inputs/mol.qin.gz b/tests/test_data/qchem/ffopt/geometry_optimization/inputs/mol.qin.gz new file mode 100644 index 0000000000000000000000000000000000000000..c7f5a8b83a9292927db22f82450c1e21515cd73f GIT binary patch literal 264 zcmV+j0r&nNiwFqWeP?C>18r|?E^%pY0F{tEa>F1Hg?mmxq1GORNo*JC)8z;ZLMuc@ z2nMiY`SfP-$WDr6CR_2oefvk_`~>{b9$% zUxmdZ4&wOoqmcf)uz|TJq>122$$k1x<|P1qqdsILok}(p*~7p$`FakaN9@!^COt^K z=m{|2;u4e^n2|d*7nb7*5MH!2(e{PxQ06g08nH&8O#BI6D=2-{WPG%FbU51DguIx7 z)T4@~PF%aE#W~1vDQHkrTA8$F_7T1ri)-|_#aDOSyYqcr?_{}D;ysUB`14=p&acna Od)GHs4H)b40RRB@!GiJt literal 0 HcmV?d00001 diff --git a/tests/test_data/qchem/ffopt/geometry_optimization/outputs/131.0.gz b/tests/test_data/qchem/ffopt/geometry_optimization/outputs/131.0.gz new file mode 100644 index 0000000000000000000000000000000000000000..397a93c774e13bd27297627f19878e31bab0afe4 GIT binary patch literal 98 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/qchem/ffopt/geometry_optimization/outputs/mol.qclog.gz b/tests/test_data/qchem/ffopt/geometry_optimization/outputs/mol.qclog.gz new file mode 100644 index 0000000000000000000000000000000000000000..0786e012e1a576d5e860a57bd22fe5ea07e9a5a0 GIT binary patch literal 582 zcmV-M0=fMkiwFp5Qd(vJ|7~wpikvK$YT95*T zP*%GqWP(ewP3&Mh(Ej~SLZE5)gjT8rl0BYzdGq}2-=YF48OVzBjPGG-1}Q7x$fU{y z_h4w*mTjCeoho`{FdmPgXBctl5q{Y zOnN}}x!BU2R6Qbz6e)rdszpIHb2f(rzq`>))qrG+c&{7Bc3jgQn2uvQebdEX&vZt^ zfiogGtvFW5Yfiscr@6K{7@B>1(C_z*jF**$mn>(<$s&cwtwY8QQR$C(8^)NyODPfs z_3*$pxK1UbJJl@RrsaksWL#;Q=TxIW9R-$w2iI|FH4#N2I8ow7pHODPQP<=LX@JOC z+hyRde|b08;ha`)SiOj!9=)5Z*&D+(cD%Q6x=}6AX65}a(87=XC<>zn$h=>L@zjqH zezuriy6lLF#$bsS^1Y+vAwf4@a#bR!PErI|1+o7eOuP=i?{d;Ih@JvJLI(JCqKgtE z&$Gq-G(O99jyz1Ga1n3AQMNJ&H0*+Hky{Uw3YB+BV|^QR+YXNJNP) U##a&r1Ix0Ezfnfz-&_R%0D$WlCjbBd literal 0 HcmV?d00001 diff --git a/tests/test_data/qchem/ffopt/geometry_optimization/outputs/mol.qin.gz b/tests/test_data/qchem/ffopt/geometry_optimization/outputs/mol.qin.gz new file mode 100644 index 0000000000000000000000000000000000000000..c7f5a8b83a9292927db22f82450c1e21515cd73f GIT binary patch literal 264 zcmV+j0r&nNiwFqWeP?C>18r|?E^%pY0F{tEa>F1Hg?mmxq1GORNo*JC)8z;ZLMuc@ z2nMiY`SfP-$WDr6CR_2oefvk_`~>{b9$% zUxmdZ4&wOoqmcf)uz|TJq>122$$k1x<|P1qqdsILok}(p*~7p$`FakaN9@!^COt^K z=m{|2;u4e^n2|d*7nb7*5MH!2(e{PxQ06g08nH&8O#BI6D=2-{WPG%FbU51DguIx7 z)T4@~PF%aE#W~1vDQHkrTA8$F_7T1ri)-|_#aDOSyYqcr?_{}D;ysUB`14=p&acna Od)GHs4H)b40RRB@!GiJt literal 0 HcmV?d00001 diff --git a/tests/test_data/qchem/ffopt/geometry_optimization/outputs/mol.qin.orig.gz b/tests/test_data/qchem/ffopt/geometry_optimization/outputs/mol.qin.orig.gz new file mode 100644 index 0000000000000000000000000000000000000000..4c0e2586b216f4c5c89c30d2799b6b6addc1c3f6 GIT binary patch literal 269 zcmV+o0rLJIiwFn;erIL?18r|?E^%pYE^l&aX8@IuJ#xb!5QTeAL7~C@#1 z3_>eJMhFJ5WBK%E@yJe!WF}kjzJ2>g`>-0LK?9~piKM;UMnbl)nt6Md2~41 z+JwBAg4CmmrcPYDr^PwQaVcm}Q(Bp{X7&-j8H;Q5xW!j@+`IFAUGHSMRN_64Tln)| T=FYFr)qB@BRt*^I@&Nz<2+f20 literal 0 HcmV?d00001 diff --git a/tests/test_data/qchem/ffopt/geometry_optimization/outputs/mol.qout.gz b/tests/test_data/qchem/ffopt/geometry_optimization/outputs/mol.qout.gz new file mode 100644 index 0000000000000000000000000000000000000000..8a9213943b30c1c996a55b4163770635fc160eba GIT binary patch literal 9314 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