Skip to content

Commit

Permalink
geometric and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
loriab committed Jun 5, 2024
1 parent f40c966 commit 566db4a
Show file tree
Hide file tree
Showing 7 changed files with 162 additions and 14 deletions.
3 changes: 2 additions & 1 deletion qcengine/procedures/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

from ..exceptions import InputError, ResourceError
from .berny import BernyProcedure
from .geometric import GeometricProcedure
from .geometric import GeometricProcedure, GenGeometricProcedure
from .qcmanybody import QCManyBodyProcedure
from .nwchem_opt import NWChemDriverProcedure
from .optking import OptKingProcedure, GenOptKingProcedure
Expand Down Expand Up @@ -68,6 +68,7 @@ def list_available_procedures() -> Set[str]:


register_procedure(GeometricProcedure())
register_procedure(GenGeometricProcedure())
register_procedure(OptKingProcedure())
register_procedure(GenOptKingProcedure())
register_procedure(BernyProcedure())
Expand Down
65 changes: 65 additions & 0 deletions qcengine/procedures/geometric.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,68 @@ def compute(self, input_model: "OptimizationInput", config: "TaskConfig") -> "Op
output_data = OptimizationResult(**output_data)

return output_data


class GenGeometricProcedure(GeometricProcedure):

# # note that "procedure" value below not used
_defaults = {"name": "GenGeometric", "procedure": "genoptimization"}

version_cache: Dict[str, str] = {}

def found(self, raise_error: bool = False) -> bool:
qc = which_import(
"geometric",
return_bool=True,
raise_error=raise_error,
raise_msg="Please install via `conda install geometric -c conda-forge`.",
)
dep = which_import(
"qcmanybody",
return_bool=True,
raise_error=raise_error,
raise_msg="For GenGeometric harness, please install via `conda install qcmanybody -c conda-forge`.",
)

return qc and dep

def build_input_model(
self, data: Union[Dict[str, Any], "GeneralizedOptimizationInput"]
) -> "GeneralizedOptimizationInput":
from qcmanybody.models.generalized_optimization import GeneralizedOptimizationInput

return self._build_model(data, GeneralizedOptimizationInput)

def compute(
self, input_model: "GeneralizedOptimizationInput", config: "TaskConfig"
) -> "GeneralizedOptimizationResult":
self.found(raise_error=True)

import geometric
from qcmanybody.models.generalized_optimization import GeneralizedOptimizationResult

input_data = input_model.dict()

# Temporary patch for geomeTRIC
input_data["initial_molecule"]["symbols"] = list(input_data["initial_molecule"]["symbols"])

# Set retries to two if zero while respecting local_config
local_config = config.dict()
local_config["retries"] = local_config.get("retries", 2) or 2
input_data["input_specification"]["extras"]["_qcengine_local_config"] = local_config

# Run the program
output_data = geometric.run_json.geometric_run_json(input_data)

output_data["provenance"] = {
"creator": "geomeTRIC",
"routine": "geometric.run_json.geometric_run_json",
"version": geometric.__version__,
}

output_data["schema_name"] = "qcschema_generalizedoptimizationresult"
output_data["input_specification"]["extras"].pop("_qcengine_local_config", None)
if output_data["success"]:
output_data = GeneralizedOptimizationResult(**output_data)

return output_data
4 changes: 2 additions & 2 deletions qcengine/procedures/optking.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,13 +106,13 @@ def compute(
# Set retries to two if zero while respecting local_config
local_config = config.dict()
local_config["retries"] = local_config.get("retries", 2) or 2
# TODO input_data["input_specification"]["extras"]["_qcengine_local_config"] = local_config
input_data["input_specification"]["extras"]["_qcengine_local_config"] = local_config

# Run the program
output_data = optking.optwrapper.optimize_qcengine(input_data)

output_data["schema_name"] = "qcschema_generalizedoptimizationresult"
# TODO output_data["input_specification"]["extras"].pop("_qcengine_local_config", None)
output_data["input_specification"]["extras"].pop("_qcengine_local_config", None)
if output_data["success"]:
output_data = GeneralizedOptimizationResult(**output_data)

Expand Down
5 changes: 2 additions & 3 deletions qcengine/procedures/qcmanybody.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from qcelemental.util import safe_version, which_import

from .model import ProcedureHarness
from ..exceptions import UnknownError

if TYPE_CHECKING:
from ..config import TaskConfig
Expand Down Expand Up @@ -45,8 +44,8 @@ def get_version(self) -> str:
return self.version_cache[which_prog]

def compute(self, input_model: "ManyBodyInput", config: "TaskConfig") -> "ManyBodyResult":
from qcmanybody.qcng_computer import ManyBodyComputerQCNG
from qcmanybody import ManyBodyComputer

output_model = ManyBodyComputerQCNG.from_manybodyinput(input_model)
output_model = ManyBodyComputer.from_manybodyinput(input_model)

return output_model
2 changes: 1 addition & 1 deletion qcengine/programs/cfour/harvester.py
Original file line number Diff line number Diff line change
Expand Up @@ -1004,7 +1004,7 @@ def harvest_outfile_pass(outtext):
# Process atom geometry
mobj = re.search(r"^\s+" + r"@GETXYZ-I, 1 atoms read from ZMAT." + r"\s*$", outtext, re.MULTILINE)
mobj2 = re.search(
r"^([A-Z]+)#1" + r"\s+" + NUMBER + r"\s+" + NUMBER + r"\s+" + NUMBER + r"\s*$", outtext, re.MULTILINE
r"^\s*([A-Z]+)" + r"\s*" + r"#1" + r"\s+" + NUMBER + r"\s+" + NUMBER + r"\s+" + NUMBER + r"\s*$", outtext, re.MULTILINE
)
if mobj and mobj2:
logger.debug("matched atom2") # unsavory for when atom never printed except for basis file
Expand Down
2 changes: 2 additions & 0 deletions qcengine/testing.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,13 +164,15 @@ def get_job(self):
"mctc-gcp": is_program_new_enough("mctc-gcp", "2.3.0"),
"gcp": which("gcp", return_bool=True),
"geometric": which_import("geometric", return_bool=True),
"geometric_genopt": is_program_new_enough("geometric", "1.1.0"),
"berny": which_import("berny", return_bool=True),
"mdi": is_mdi_new_enough("1.2"),
"molpro": is_program_new_enough("molpro", "2018.1"),
"mopac": is_program_new_enough("mopac", "2016"),
"mp2d": which("mp2d", return_bool=True),
"nwchem": which("nwchem", return_bool=True),
"optking": which_import("optking", return_bool=True),
"optking_genopt": is_program_new_enough("optking", "0.3.0"),
"psi4": is_program_new_enough("psi4", "1.2"),
"psi4_runqcsk": is_program_new_enough("psi4", "1.4a2.dev160"),
"psi4_mp2qcsk": is_program_new_enough("psi4", "1.4a2.dev580"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
pytest.param("psi4", marks=using("psi4")),
],
)
def test_tu6_cp_ne2(qcprog):
def test_bsse_ene_tu6_cp_ne2(qcprog):
"""
from https://github.com/psi4/psi4/blob/master/tests/tu6-cp-ne2/input.dat
Example potential energy surface scan and CP-correction for Ne2
Expand Down Expand Up @@ -136,14 +136,18 @@ def test_mbe_error():
"optimizer,bsse_type,sio",
[
pytest.param("optking", "none", None, marks=using("optking")),
pytest.param("genoptking", "none", None, marks=using("optking")),
pytest.param("genoptking", "nocp", False, marks=using("optking")),
# pytest.param("genoptking", "nocp", True, marks=using("optking")),
# pytest.param("genoptking", "cp", False, marks=using("optking")),
pytest.param("genoptking", "cp", True, marks=using("optking")),
pytest.param("genoptking", "none", None, marks=using("optking_genopt")),
pytest.param("genoptking", "nocp", False, marks=using("optking_genopt")),
# pytest.param("genoptking", "nocp", True, marks=using("optking_genopt")),
# pytest.param("genoptking", "cp", False, marks=using("optking_genopt")),
pytest.param("geometric", "none", None, marks=using("geometric")),
pytest.param("gengeometric", "none", None, marks=using("geometric_genopt")),
pytest.param("gengeometric", "nocp", False, marks=using("geometric_genopt")),
pytest.param("gengeometric", "cp", True, marks=using("geometric_genopt")),
],
)
def test_optimization_qcmanybody(optimizer, bsse_type, sio):
def test_bsse_opt_hf_trimer(optimizer, bsse_type, sio):

initial_molecule = Molecule.from_data(
"""
Expand Down Expand Up @@ -237,3 +241,80 @@ def test_optimization_qcmanybody(optimizer, bsse_type, sio):
assert (
ret.trajectory[-1].component_results['["(auto)", [1, 2, 3], [1, 2, 3]]'].stdout is None
), f"atomic protocol did not take"


@using("qcmanybody")
@pytest.mark.parametrize("bsse_type", ["mbe", "ssfc"]) # aka nocp, cp
@pytest.mark.parametrize("qcprog,qc_keywords", [
pytest.param("psi4", {}, marks=using("psi4")),
pytest.param("cfour", {}, marks=using("cfour")),
pytest.param("nwchem", {}, marks=using("nwchem")),
])
@pytest.mark.parametrize("optimizer,opt_keywords", [
pytest.param("optking", {}, marks=using("optking_genopt")),
pytest.param("geometric", {"convergence_set": "interfrag_tight", "maxiter": 15}, marks=using("geometric_genopt")),
])
def test_bsse_opt_lif_dimer(optimizer, opt_keywords, bsse_type, qcprog, qc_keywords):
# in geomeTRIC: test_lif_bsse

lif = {
"symbols": ["Li", "F"],
"geometry": [0, 0, 0, 0, 0, 3],
"fragments": [[0], [1]],
"fragment_charges": [+1, -1],
}

mbe_spec = {
"schema_name": "qcschema_manybodyspecification",
"specification": {
"model": {
"method": "hf",
"basis": "6-31G",
},
"driver": "energy",
"program": qcprog,
"keywords": qc_keywords,
"protocols": {
"stdout": False,
},
},
"keywords": {
"bsse_type": bsse_type,
"supersystem_ie_only": True,
},
"protocols": {
"component_results": "all",
},
"driver": "energy",
}

opt_data = {
"initial_molecule": lif,
"input_specification": mbe_spec,
"keywords": {
"program": "nonsense",
**opt_keywords,
},
"protocols": {
"trajectory": "final",
},
}

ret = qcng.compute_procedure(opt_data, "gen" + optimizer, raise_error=True)

# printing will show up if job fails
import pprint

Check notice

Code scanning / CodeQL

Module is imported more than once Note test

This import of module pprint is redundant, as it was previously imported
on line 1
.
pprint.pprint(ret.dict(), width=200)

assert ret.success

assert len(ret.trajectory[0].component_properties) == (5 if bsse_type == "ssfc" else 3)

assert ret.provenance.creator.lower() == optimizer
assert ret.trajectory[0].provenance.creator == "QCManyBody"
atres = list(ret.trajectory[0].component_results.values())[0]
assert atres.provenance.creator.lower() == qcprog

Rlif = ret.final_molecule.measure([0, 1])
Rref = 3.016 if bsse_type == "ssfc" else 2.969
assert compare_values(Rlif, Rref, "bond length", atol=1.e-3)

0 comments on commit 566db4a

Please sign in to comment.