Skip to content

Commit

Permalink
Streamline quasi-IRC handling (#2373)
Browse files Browse the repository at this point in the history
Addresses #2324.

- Removes the old `quasi_irc_job` from Q-Chem
- Renames `quasi_irc_perturb_job` to `quasi_irc_job`

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
  • Loading branch information
Andrew-S-Rosen and pre-commit-ci[bot] authored Jul 29, 2024
1 parent 36dde0f commit ecbc1d0
Show file tree
Hide file tree
Showing 5 changed files with 28 additions and 160 deletions.
31 changes: 15 additions & 16 deletions docs/user/recipes/recipes_list.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,13 +141,13 @@ The list of available quacc recipes is shown below. The "Req'd Extras" column sp

<center>

| Name | Decorator | Documentation | Req'd Extras |
| -------------------------- | --------------- | ----------------------------------------------------- | ------------ |
| ORCA Static | `#!Python @job` | [quacc.recipes.orca.core.static_job][] | |
| ORCA Relax | `#!Python @job` | [quacc.recipes.orca.core.relax_job][] | |
| ORCA Freq | `#!Python @job` | [quacc.recipes.orca.core.freq_job][] | |
| ORCA ASE Relax | `#!Python @job` | [quacc.recipes.orca.core.ase_relax_job][] | |
| ORCA ASE Quasi-IRC Perturb | `#!Python @job` | [quacc.recipes.orca.core.ase_quasi_irc_perturb_job][] | |
| Name | Decorator | Documentation | Req'd Extras |
| ------------------ | --------------- | --------------------------------------------- | ------------ |
| ORCA Static | `#!Python @job` | [quacc.recipes.orca.core.static_job][] | |
| ORCA Relax | `#!Python @job` | [quacc.recipes.orca.core.relax_job][] | |
| ORCA Freq | `#!Python @job` | [quacc.recipes.orca.core.freq_job][] | |
| ORCA ASE Relax | `#!Python @job` | [quacc.recipes.orca.core.ase_relax_job][] | |
| ORCA ASE Quasi-IRC | `#!Python @job` | [quacc.recipes.orca.core.ase_quasi_irc_job][] | |

</center>

Expand All @@ -173,15 +173,14 @@ The list of available quacc recipes is shown below. The "Req'd Extras" column sp

<center>

| Name | Decorator | Documentation | Req'd Extras |
| ------------------------ | --------------- | ------------------------------------------------ | -------------- |
| Q-Chem Static | `#!Python @job` | [quacc.recipes.qchem.core.static_job][] | |
| Q-Chem Relax | `#!Python @job` | [quacc.recipes.qchem.core.relax_job][] | |
| Q-Chem Frequency | `#!Python @job` | [quacc.recipes.qchem.core.freq_job][] | |
| Q-Chem TS | `#!Python @job` | [quacc.recipes.qchem.ts.ts_job][] | `quacc[sella]` |
| Q-Chem IRC | `#!Python @job` | [quacc.recipes.qchem.ts.irc_job][] | `quacc[sella]` |
| Q-Chem Quasi IRC | `#!Python @job` | [quacc.recipes.qchem.ts.quasi_irc_job][] | `quacc[sella]` |
| Q-Chem Quasi IRC Perturb | `#!Python @job` | [quacc.recipes.qchem.ts.quasi_irc_perturb_job][] | `quacc[sella]` |
| Name | Decorator | Documentation | Req'd Extras |
| ---------------- | --------------- | ---------------------------------------- | -------------- |
| Q-Chem Static | `#!Python @job` | [quacc.recipes.qchem.core.static_job][] | |
| Q-Chem Relax | `#!Python @job` | [quacc.recipes.qchem.core.relax_job][] | |
| Q-Chem Frequency | `#!Python @job` | [quacc.recipes.qchem.core.freq_job][] | |
| Q-Chem TS | `#!Python @job` | [quacc.recipes.qchem.ts.ts_job][] | `quacc[sella]` |
| Q-Chem IRC | `#!Python @job` | [quacc.recipes.qchem.ts.irc_job][] | `quacc[sella]` |
| Q-Chem Quasi IRC | `#!Python @job` | [quacc.recipes.qchem.ts.quasi_irc_job][] | `quacc[sella]` |

</center>

Expand Down
4 changes: 2 additions & 2 deletions src/quacc/recipes/orca/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ def ase_relax_job(


@job
def ase_quasi_irc_perturb_job(
def ase_quasi_irc_job(
atoms: Atoms,
mode: list[list[float]] | NDArray,
perturb_magnitude: float = 0.6,
Expand Down Expand Up @@ -368,6 +368,6 @@ def ase_quasi_irc_perturb_job(
input_swaps=orcasimpleinput,
block_swaps=orcablocks,
opt_params=opt_params,
additional_fields={"name": "ORCA ASE Quasi-IRC perturbed optimization"},
additional_fields={"name": "ORCA ASE Quasi-IRC optimization"},
copy_files=copy_files,
)
80 changes: 4 additions & 76 deletions src/quacc/recipes/qchem/ts.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,23 @@

from monty.dev import requires

from quacc import change_settings, job, strip_decorator
from quacc import job
from quacc.atoms.core import perturb
from quacc.recipes.qchem._base import run_and_summarize_opt
from quacc.recipes.qchem.core import _BASE_SET, relax_job
from quacc.recipes.qchem.core import _BASE_SET
from quacc.utils.dicts import recursive_dict_merge

has_sella = bool(find_spec("sella"))
if has_sella:
from sella import IRC, Sella

if TYPE_CHECKING:
from typing import Any, Literal
from typing import Literal

from ase.atoms import Atoms
from numpy.typing import NDArray

from quacc.types import (
Filenames,
OptParams,
OptSchema,
QchemQuasiIRCSchema,
SourceDirectory,
)
from quacc.types import Filenames, OptParams, OptSchema, SourceDirectory


@job
Expand Down Expand Up @@ -170,72 +164,6 @@ def irc_job(
@job
@requires(has_sella, "Sella must be installed. Refer to the quacc documentation.")
def quasi_irc_job(
atoms: Atoms,
charge: int = 0,
spin_multiplicity: int = 1,
direction: Literal["forward", "reverse"] = "forward",
method: str = "wb97mv",
basis: str = "def2-svpd",
irc_job_kwargs: dict[str, Any] | None = None,
relax_job_kwargs: dict[str, Any] | None = None,
copy_files: SourceDirectory | dict[SourceDirectory, Filenames] | None = None,
) -> QchemQuasiIRCSchema:
"""
Quasi-IRC optimize a molecular structure. Runs `irc_job` for 10 steps (default)
followed by `relax_job`.
Parameters
----------
atoms
Atoms object.
charge
Charge of the system.
spin_multiplicity
Multiplicity of the system.
direction
Direction of the IRC. Should be "forward" or "reverse".
irc_job_kwargs
Dictionary of kwargs for the `irc_job`.
relax_job_kwargs
Dictionary of kwargs for the `relax_job`.
copy_files
Files to copy (and decompress) from source to the runtime directory.
Returns
-------
OptSchema
Dictionary of results from [quacc.schemas.ase.Summarize.opt][]
"""
irc_job_defaults = {
"charge": charge,
"spin_multiplicity": spin_multiplicity,
"direction": direction,
"method": method,
"basis": basis,
"opt_params": {"max_steps": 10},
"copy_files": copy_files,
}
relax_job_defaults = {
"charge": charge,
"spin_multiplicity": spin_multiplicity,
"method": method,
"basis": basis,
}
irc_job_kwargs = recursive_dict_merge(irc_job_defaults, irc_job_kwargs)
relax_job_kwargs = recursive_dict_merge(relax_job_defaults, relax_job_kwargs)

with change_settings({"CHECK_CONVERGENCE": False}):
irc_summary = strip_decorator(irc_job)(atoms, **irc_job_kwargs)

relax_summary = strip_decorator(relax_job)(irc_summary["atoms"], **relax_job_kwargs)
relax_summary["initial_irc"] = irc_summary

return relax_summary


@job
@requires(has_sella, "Sella must be installed. Refer to the quacc documentation.")
def quasi_irc_perturb_job(
atoms: Atoms,
mode: list[list[float]] | NDArray,
perturb_magnitude: float = 0.6,
Expand Down
6 changes: 3 additions & 3 deletions tests/core/recipes/orca_recipes/test_orca_recipes.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from ase.build import molecule

from quacc.recipes.orca.core import (
ase_quasi_irc_perturb_job,
ase_quasi_irc_job,
ase_relax_job,
freq_job,
relax_job,
Expand Down Expand Up @@ -172,14 +172,14 @@ def test_freq_job(tmp_path, monkeypatch):


@pytest.mark.skipif(os.name == "nt", reason="mpirun not available on Windows")
def test_ase_quasi_irc_perturb_job(tmp_path, monkeypatch):
def test_ase_quasi_irc_job(tmp_path, monkeypatch):
monkeypatch.chdir(tmp_path)

atoms = molecule("H2")

mode = [[0.0, 0.0, 0.1], [0.0, 0.1, 0.0]]

output = ase_quasi_irc_perturb_job(
output = ase_quasi_irc_job(
atoms,
mode,
charge=0,
Expand Down
67 changes: 4 additions & 63 deletions tests/core/recipes/qchem_recipes/mocked/test_qchem_recipes.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from quacc.atoms.core import check_charge_and_spin
from quacc.calculators.qchem import QChem
from quacc.recipes.qchem.core import freq_job, relax_job, static_job
from quacc.recipes.qchem.ts import irc_job, quasi_irc_job, quasi_irc_perturb_job, ts_job
from quacc.recipes.qchem.ts import irc_job, quasi_irc_job, ts_job

has_sella = bool(find_spec("sella"))

Expand Down Expand Up @@ -561,66 +561,7 @@ def test_irc_job_v2(tmp_path, monkeypatch, test_atoms):


@pytest.mark.skipif(has_sella is False, reason="Does not have Sella")
def test_quasi_irc_job(monkeypatch, tmp_path, test_atoms):
monkeypatch.chdir(tmp_path)

monkeypatch.setattr(QChem, "read_results", mock_read)
monkeypatch.setattr(QChem, "execute", mock_execute4)

charge, spin_multiplicity = check_charge_and_spin(test_atoms)

output = quasi_irc_job(
test_atoms,
charge=charge,
spin_multiplicity=spin_multiplicity,
direction="forward",
basis="def2-tzvpd",
relax_job_kwargs={"opt_params": {"max_steps": 5}},
)

assert output["atoms"] != test_atoms
assert output["charge"] == 0
assert output["spin_multiplicity"] == 1
assert output["formula_alphabetical"] == "C4 H4 O6"
assert output["nelectrons"] == 76
assert output["parameters"]["charge"] == 0
assert output["parameters"]["spin_multiplicity"] == 1

qcin = QCInput.from_file(str(Path(output["dir_name"], "mol.qin.gz")))
ref_qcin = QCInput.from_file(str(QCHEM_DIR / "mol.qin.basic.quasi_irc_forward"))
qcinput_nearly_equal(qcin, ref_qcin)

output = quasi_irc_job(
test_atoms,
charge=-1,
spin_multiplicity=2,
direction="reverse",
basis="def2-svpd",
irc_job_kwargs={
"rem": {"scf_algorithm": "gdm"},
"opt_params": {"max_steps": 6},
},
relax_job_kwargs={
"rem": {"scf_algorithm": "gdm"},
"opt_params": {"max_steps": 6},
},
)

assert output["atoms"] != test_atoms
assert output["charge"] == -1
assert output["spin_multiplicity"] == 2
assert output["formula_alphabetical"] == "C4 H4 O6"
assert output["nelectrons"] == 77
assert output["parameters"]["charge"] == -1
assert output["parameters"]["spin_multiplicity"] == 2

qcin = QCInput.from_file(str(Path(output["dir_name"], "mol.qin.gz")))
ref_qcin = QCInput.from_file(str(QCHEM_DIR / "mol.qin.quasi_irc_reverse"))
qcinput_nearly_equal(qcin, ref_qcin)


@pytest.mark.skipif(has_sella is False, reason="Does not have Sella")
def test_quasi_irc_perturb_job(monkeypatch, tmp_path, test_qirc_atoms):
def test_quasi_irc_job(monkeypatch, tmp_path, test_qirc_atoms):
monkeypatch.chdir(tmp_path)

monkeypatch.setattr(QChem, "read_results", mock_read)
Expand Down Expand Up @@ -648,7 +589,7 @@ def test_quasi_irc_perturb_job(monkeypatch, tmp_path, test_qirc_atoms):

charge, spin_multiplicity = check_charge_and_spin(test_qirc_atoms)

output = quasi_irc_perturb_job(
output = quasi_irc_job(
test_qirc_atoms,
mode,
charge=charge,
Expand All @@ -671,7 +612,7 @@ def test_quasi_irc_perturb_job(monkeypatch, tmp_path, test_qirc_atoms):
ref_qcin = QCInput.from_file(str(QCHEM_DIR / "mol.qin.qirc_forward"))
qcinput_nearly_equal(qcin, ref_qcin)

output = quasi_irc_perturb_job(
output = quasi_irc_job(
test_qirc_atoms,
mode,
charge=-1,
Expand Down

0 comments on commit ecbc1d0

Please sign in to comment.