Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

work with qcengine and qcmanybody #92

Merged
merged 2 commits into from
Jun 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 17 additions & 3 deletions optking/compute_wrappers.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,13 @@ def generate_schema_input(self, driver):

return inp

def generate_schema_input_for_procedure(self, driver):
molecule = Molecule(**self.molecule)
mbspec = self.keywords
mbspec["driver"] = driver

return {"molecule": molecule, "specification": mbspec}

def _compute(self, driver):
"""Abstract style method for child classes"""
pass
Expand Down Expand Up @@ -149,16 +156,23 @@ def _compute(self, driver):

import qcengine

inp = self.generate_schema_input(driver)

local_options = {}
if self.program == "psi4":
import psi4

local_options["memory"] = psi4.core.get_memory() / 1000000000
local_options["ncores"] = psi4.core.get_num_threads()

ret = qcengine.compute(inp, self.program, True, local_options)
if self.model == "(proc_spec_in_options)":
logger.debug("QCEngineComputer.path: ManyBody")
inp = self.generate_schema_input_for_procedure(driver)
ret = qcengine.compute_procedure(inp, "qcmanybody", True, local_options)

else:
logger.debug("QCEngineComputer.path: Atomic")
inp = self.generate_schema_input(driver)
ret = qcengine.compute(inp, self.program, True, local_options)

return ret


Expand Down
14 changes: 11 additions & 3 deletions optking/optwrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,9 +201,17 @@ def make_computer(opt_input: dict, computer_type):

# This gets updated so it shouldn't be a reference
molecule = copy.deepcopy(opt_input["initial_molecule"])
qc_input = opt_input["input_specification"]
options = qc_input["keywords"]
model = qc_input["model"]

# Sorting by spec_schema_name isn't foolproof b/c opt_input might not be a
# constructed model at this point if it's not arriving through QCEngine.
spec_schema_name = opt_input["input_specification"].get("schema_name", "qcschema_input")
if spec_schema_name == "qcschema_manybodyspecification":
model = "(proc_spec_in_options)"
options = opt_input["input_specification"]
else:
qc_input = opt_input["input_specification"]
options = qc_input["keywords"]
model = qc_input["model"]

if computer_type == "psi4":
# Please note that program is not actually used here
Expand Down
17 changes: 17 additions & 0 deletions optking/tests/json_lif_cp.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{"initial_molecule": {"fragment_charges": [1, -1], "fragments": [[0], [1]], "geometry": [0.0, 0.0, 0.0, 0.0, 0.0, 3.0], "symbols": ["Li", "F"]},
"input_specification": {"driver": "energy",
"schema_name": "qcschema_manybodyspecification",
"keywords": {"bsse_type": "cp", "supersystem_ie_only": true},
"protocols": {"component_results": "all"},
"specification": {"driver": "energy",
"extras": {"psiapi": true},
"keywords": {},
"model": {"basis": "6-31g", "method": "hf"},
"program": "psi4",
"protocols": {"stdout": false}}},
"keywords": {"g_convergence": "interfrag_tight", "program": "psi4"},
"protocols": {"trajectory": "final"},
"provenance": {"creator": "optking", "routine": "optimize_qcengine", "version": "0.2.1+14.gdc8fd03.dirty"},
"schema_name": "qcschema_generalizedoptimizationinput",
"schema_version": 1}

17 changes: 17 additions & 0 deletions optking/tests/json_lif_nocp.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{"initial_molecule": {"fragment_charges": [1, -1], "fragments": [[0], [1]], "geometry": [0.0, 0.0, 0.0, 0.0, 0.0, 3.0], "symbols": ["Li", "F"]},
"input_specification": {"driver": "energy",
"keywords": {"bsse_type": "nocp", "supersystem_ie_only": true},
"protocols": {"component_results": "all"},
"schema_name": "qcschema_manybodyspecification",
"specification": {"driver": "energy",
"extras": {"psiapi": true},
"keywords": {},
"model": {"basis": "6-31g", "method": "hf"},
"program": "psi4",
"protocols": {"stdout": false}}},
"keywords": {"g_convergence": "gau_verytight", "program": "psi4"},
"protocols": {"trajectory": "final"},
"provenance": {"creator": "optking", "routine": "optimize_qcengine", "version": "0.2.1+14.gdc8fd03.dirty"},
"schema_name": "qcschema_generalizedoptimizationinput",
"schema_version": 1}

5 changes: 5 additions & 0 deletions optking/tests/psi4_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import numpy
import pytest
from qcelemental.util import which_import

# Try to pull in Psi4
try:
Expand All @@ -15,3 +16,7 @@

# Wrap Psi4 in ifden
using_psi4 = pytest.mark.skipif(found_psi4, reason="Psi4 not found, skipping.")
using_qcmanybody = pytest.mark.skipif(
which_import("qcmanybody", return_bool=True) is False,
reason="cound not find qcmanybody. please install the package to enable tests",
)
40 changes: 31 additions & 9 deletions optking/tests/test_jsoninput.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,41 +6,63 @@
import psi4

from qcelemental.models import OptimizationInput
from qcelemental.testing import compare_values
from .utils import utils
from .psi4_helper import using_qcmanybody

# Varying number of repulsion energy decimals to check.
@pytest.mark.parametrize(
"inp,expected,num_steps",
[
("json_h2o.json", (8.9064890670, -74.965901192, 3), 5),
("json_betapinene.json", (568.2219045869, -383.38105559, 1), 4),
("json_hooh_frozen.json", (37.969354880, -150.786372411, 2), 6),
pytest.param("json_h2o.json", (8.9064890670, -74.965901192, 3), 5),
pytest.param("json_betapinene.json", (568.2219045869, -383.38105559, 1), 4),
pytest.param("json_hooh_frozen.json", (37.969354880, -150.786372411, 2), 6),
pytest.param("json_lif_cp.json", (8.95167, -106.8867587, 2, 3.016), 4, marks=using_qcmanybody),
pytest.param("json_lif_nocp.json", (9.09281, -106.9208785, 2, 2.969), 5, marks=using_qcmanybody),
],
)
def test_input_through_json(inp, expected, num_steps, check_iter):
with open(os.path.join(os.path.dirname(__file__), inp)) as input_data:
input_copy = json.load(input_data)
opt_schema = OptimizationInput(**input_copy)
if "lif" in inp:
from qcmanybody.models.generalized_optimization import GeneralizedOptimizationInput
opt_schema = GeneralizedOptimizationInput(**input_copy)
else:
opt_schema = OptimizationInput(**input_copy)

# Note it's important to have `input_specification.schema_name = "qcschema_manybodyspecification"`
# in your json for a MBE optimization. Or you can explicitly construct a
# GeneralizedOptimizationInput like above.

# optking.run_json_file(os.path.join(os.path.dirname(__file__), inp))
json_dict = optking.optimize_qcengine(input_copy)

if "lif" in inp:
assert inp, json_dict["trajectory"][-1]["schema_name"] == "qcschema_manybodyresult"
else:
assert inp, json_dict["trajectory"][-1]["schema_name"] == "qcschema_output"

# For testing purposes. If this works, we have properly returned the output, and added the result
# to the original file. In order to preserve the form of the test suite, we now resore the input
# to its original state
# with open(os.path.join(os.path.dirname(__file__), inp)) as input_data:
# json_dict = json.load(input_data)
assert psi4.compare_values(

# LAB: for the MBE optimizations, psi4.compare_values strangely segfaults python, so using compare_values from qcel
assert compare_values(
expected[0],
json_dict["trajectory"][-1]["properties"]["nuclear_repulsion_energy"],
expected[2],
"Nuclear repulsion energy",
atol=1.0 * 10**-expected[2],
label="Nuclear repulsion energy",
)
assert psi4.compare_values(
expected[1], json_dict["trajectory"][-1]["properties"]["return_energy"], 6, "Reference energy"
assert compare_values(
expected[1], json_dict["trajectory"][-1]["properties"]["return_energy"], atol=1.e-6, label="Reference energy"
)
utils.compare_iterations(json_dict, num_steps, check_iter)

if len(expected) > 3:
assert compare_values(expected[3], json_dict["final_molecule"]["geometry"][5] - json_dict["final_molecule"]["geometry"][2], atol=1.e-3, label="bond length")

# with open(os.path.join(os.path.dirname(__file__), inp), 'r+') as input_data:
# input_data.seek(0)
# input_data.truncate()
Expand Down
Loading