Skip to content

Commit

Permalink
Allow extra constraints in torsiondrives (#440)
Browse files Browse the repository at this point in the history
* do not overwrite constraints in torsiondrives

* lint

* add test with extra torsion constraints

---------

Co-authored-by: Lori A. Burns <[email protected]>
  • Loading branch information
jthorton and loriab authored Jan 15, 2025
1 parent 7521e59 commit 879205a
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 13 deletions.
23 changes: 10 additions & 13 deletions qcengine/procedures/torsiondrive.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,19 +183,16 @@ def _spawn_optimization(
dihedrals = input_model.keywords.dihedrals
angles = grid_point.split()

keywords = {
**input_model.optimization_spec.keywords,
"constraints": {
"set": [
{
"type": "dihedral",
"indices": dihedral,
"value": int(angle),
}
for dihedral, angle in zip(dihedrals, angles)
]
},
}
# update the keywords with extra constraints for the target torsion
keywords = input_model.optimization_spec.keywords
keywords.setdefault("constraints", {})
keywords["constraints"].setdefault("set", [])
keywords["constraints"]["set"].extend(
[
{"type": "dihedral", "indices": dihedral, "value": int(angle)}
for dihedral, angle in zip(dihedrals, angles)
]
)

input_data = OptimizationInput(
keywords=keywords,
Expand Down
28 changes: 28 additions & 0 deletions qcengine/stock_mols.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,34 @@
],
"molecular_multiplicity": 2,
},
"propane": {
"symbols": ["C", "C", "C", "H", "H", "H", "H", "H", "H", "H", "H"],
"geometry": [
[-1.04538535e00, -5.26451580e-01, 1.70615765e00],
[7.27312570e-01, -8.36259840e-01, 3.94379109e00],
[2.13664641e00, 1.54796144e00, 4.51430690e00],
[-2.06001307e00, -2.28648849e00, 1.31543249e00],
[-2.45194896e00, 9.45839060e-01, 2.07343776e00],
[1.59997800e-02, -6.00690000e-04, 1.13012700e-02],
[-3.60389010e-01, -1.40265264e00, 5.61211494e00],
[2.08128086e00, -2.35136798e00, 3.54633241e00],
[3.39307317e00, 1.25279930e00, 6.13498553e00],
[8.27431450e-01, 3.07919479e00, 4.98806078e00],
[3.29667371e00, 2.11896834e00, 2.89840427e00],
],
"connectivity": [
(0, 1, 1.0),
(0, 3, 1.0),
(0, 4, 1.0),
(0, 5, 1.0),
(1, 2, 1.0),
(1, 6, 1.0),
(1, 7, 1.0),
(2, 8, 1.0),
(2, 9, 1.0),
(2, 10, 1.0),
],
},
}


Expand Down
54 changes: 54 additions & 0 deletions qcengine/tests/test_procedures.py
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,60 @@ def test_torsiondrive_generic():
assert ret.stdout == "All optimizations converged at lowest energy. Job Finished!\n"


@using("mace")
@using("torsiondrive")
def test_torsiondrive_extra_constraints():

input_data = TorsionDriveInput(
keywords=TDKeywords(dihedrals=[(3, 0, 1, 2)], grid_spacing=[180]),
input_specification=QCInputSpecification(driver=DriverEnum.gradient, model=Model(method="small", basis=None)),
initial_molecule=[qcng.get_molecule("propane")],
optimization_spec=OptimizationSpecification(
procedure="geomeTRIC",
keywords={
"coordsys": "dlc",
# use mace as it does not have convergence issues like UFF
"program": "mace",
"constraints": {
"set": [
{
"type": "dihedral", # hold a dihedral through the other C-C bond fixed
"indices": (0, 1, 2, 10),
"value": 0.0,
}
]
},
},
),
)

ret = qcng.compute_procedure(input_data, "torsiondrive", raise_error=True)

assert ret.error is None
assert ret.success

expected_grid_ids = {"180", "0"}

assert {*ret.optimization_history} == expected_grid_ids

assert {*ret.final_energies} == expected_grid_ids
assert {*ret.final_molecules} == expected_grid_ids

assert (
pytest.approx(ret.final_molecules["180"].measure([3, 0, 1, 2]), abs=1.0e-2) == 180.0
or pytest.approx(ret.final_molecules["180"].measure([3, 0, 1, 2]), abs=1.0e-2) == -180.0
)
assert pytest.approx(ret.final_molecules["180"].measure([0, 1, 2, 10]), abs=1.0e-2) == 0.0
assert pytest.approx(ret.final_molecules["0"].measure([3, 0, 1, 2]), abs=1.0e-2) == 0.0

assert ret.provenance.creator.lower() == "torsiondrive"
assert ret.optimization_history["180"][0].provenance.creator.lower() == "geometric"
assert ret.optimization_history["180"][0].trajectory[0].provenance.creator.lower() == "mace"

assert "Using MACE-OFF23 MODEL for MACECalculator" in ret.stdout
assert "All optimizations converged at lowest energy. Job Finished!\n" in ret.stdout


@using("mrchem")
@pytest.mark.parametrize(
"optimizer",
Expand Down

0 comments on commit 879205a

Please sign in to comment.