Skip to content

Commit 5b5370e

Browse files
changed the test_orca.py testsuite to match the test_xtb.py tests
Signed-off-by: Jonathan Schöps <s6jtscho@uni-bonn.de>
1 parent 40ed4f2 commit 5b5370e

1 file changed

Lines changed: 138 additions & 30 deletions

File tree

test/test_qm/test_orca.py

Lines changed: 138 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import subprocess as sp
22
from pathlib import Path
33
from types import SimpleNamespace
4+
import numpy as np
45
import pytest
6+
from mindlessgen.molecules import Molecule # type: ignore
7+
from mindlessgen.prog import DistanceConstraint, XTBConfig # type: ignore
58
from mindlessgen.qm.orca import ORCA
69

710

@@ -21,19 +24,6 @@ def __init__(self, **kwargs):
2124
super().__init__(**defaults)
2225

2326

24-
class DummyXTBConfig(SimpleNamespace):
25-
def __init__(self, **kwargs):
26-
defaults = dict(
27-
distance_constraints=None, distance_constraint_force_constant=None
28-
)
29-
defaults.update(kwargs)
30-
super().__init__(**defaults)
31-
32-
33-
class DummyMolecule:
34-
ati = [1, 1, 6, 8]
35-
36-
3727
@pytest.fixture
3828
def make_orca():
3929
def _factory(cfg=None, xtb_cfg_param=None):
@@ -43,12 +33,84 @@ def _factory(cfg=None, xtb_cfg_param=None):
4333
return _factory
4434

4535

46-
def test_run_xtb_driver_success(monkeypatch, tmp_path, make_orca):
36+
@pytest.fixture
37+
def xtb_cfg_oh():
38+
"""
39+
xTB config with an O-H distance constraint.
40+
"""
41+
cfg = XTBConfig()
42+
cfg.distance_constraints = [DistanceConstraint.from_cli_string("O,H,1.0")]
43+
cfg.distance_constraint_force_constant = 0.5
44+
return cfg
45+
46+
47+
@pytest.fixture
48+
def xtb_cfg_ff():
49+
"""
50+
xTB config with an F-F distance constraint.
51+
"""
52+
cfg = XTBConfig()
53+
cfg.distance_constraints = [DistanceConstraint.from_cli_string("F,F,1.0")]
54+
return cfg
55+
56+
57+
@pytest.fixture
58+
def xtb_cfg_fe3():
59+
"""
60+
xTB config with a Fe-Fe distance constraint.
61+
"""
62+
cfg = XTBConfig()
63+
cfg.distance_constraints = [
64+
DistanceConstraint.from_mapping({"pair": ["Fe", "Fe"], "distance": 2.5})
65+
]
66+
return cfg
67+
68+
69+
@pytest.fixture
70+
def mol_oh():
71+
"""
72+
Simple O-H molecule for constraint tests.
73+
"""
74+
mol = Molecule("OH")
75+
mol.ati = np.array([7, 0])
76+
return mol
77+
78+
79+
@pytest.fixture
80+
def mol_h2():
81+
"""
82+
Simple H2 molecule for constraint tests.
83+
"""
84+
mol = Molecule("H2")
85+
mol.ati = np.array([0, 0])
86+
return mol
87+
88+
89+
@pytest.fixture
90+
def mol_fe3():
91+
"""
92+
Simple Fe3 molecule for constraint tests.
93+
"""
94+
mol = Molecule("Fe3")
95+
mol.ati = np.array([25, 25, 25])
96+
return mol
97+
98+
99+
@pytest.fixture
100+
def fake_xtb_path(monkeypatch):
101+
"""
102+
Force xTB path discovery to a fake binary.
103+
"""
104+
xtb_path = Path("/fake/xtb")
105+
monkeypatch.setattr("mindlessgen.qm.orca.get_xtb_path", lambda: xtb_path)
106+
return xtb_path
107+
108+
109+
def test_run_xtb_driver_success(monkeypatch, tmp_path, make_orca, fake_xtb_path):
47110
orca = make_orca(
48111
cfg=DummyORCAConfig(optlevel="tight"),
49-
xtb_cfg_param=DummyXTBConfig(),
112+
xtb_cfg_param=XTBConfig(),
50113
)
51-
monkeypatch.setattr("mindlessgen.qm.orca.get_xtb_path", lambda: Path("/fake/xtb"))
52114
captured = {}
53115

54116
def fake_run(args, cwd, capture_output, check):
@@ -57,10 +119,10 @@ def fake_run(args, cwd, capture_output, check):
57119
assert capture_output and check
58120
return SimpleNamespace(stdout=b"ok", stderr=b"")
59121

60-
monkeypatch.setattr(sp, "run", fake_run)
122+
monkeypatch.setattr("mindlessgen.qm.xtb.sp.run", fake_run)
61123
out, err, code = orca._run_xtb_driver(tmp_path, "geom.xyz", "ctrl.inp", ncores=4)
62124
assert captured["args"] == [
63-
str(Path("/fake/xtb")),
125+
str(fake_xtb_path),
64126
"geom.xyz",
65127
"--opt",
66128
"tight",
@@ -73,35 +135,38 @@ def fake_run(args, cwd, capture_output, check):
73135
assert code == 0
74136

75137

76-
def test_run_xtb_driver_failure_returns_error(monkeypatch, tmp_path, make_orca):
138+
def test_run_xtb_driver_failure_returns_error(
139+
monkeypatch, tmp_path, make_orca, fake_xtb_path
140+
):
77141
"""Ensure the ORCA wrapper surfaces errors from the xTB driver."""
78-
orca = make_orca(xtb_cfg_param=DummyXTBConfig())
79-
monkeypatch.setattr("mindlessgen.qm.orca.get_xtb_path", lambda: Path("/fake/xtb"))
142+
orca = make_orca(xtb_cfg_param=XTBConfig())
80143

81144
def fake_run(*_, **kwargs):
82145
del kwargs
83146
raise sp.CalledProcessError(1, "xtb", output=b"bad", stderr=b"worse")
84147

85-
monkeypatch.setattr(sp, "run", fake_run)
148+
monkeypatch.setattr("mindlessgen.qm.xtb.sp.run", fake_run)
86149
out, err, code = orca._run_xtb_driver( # pylint: disable=protected-access
87150
tmp_path, "geom.xyz", "ctrl.inp", ncores=1
88151
)
89152
assert (out, err, code) == ("bad", "worse", 1)
90153

91154

92-
def test_run_xtb_driver_requires_xtb_cfg(monkeypatch, tmp_path, make_orca):
155+
def test_run_xtb_driver_requires_xtb_cfg(
156+
monkeypatch, tmp_path, make_orca, fake_xtb_path
157+
):
93158
orca = make_orca()
94-
monkeypatch.setattr("mindlessgen.qm.orca.get_xtb_path", lambda: Path("/fake/xtb"))
95159
with pytest.raises(RuntimeError, match="xTB driver requested"):
96160
orca._run_xtb_driver(tmp_path, "geom.xyz", "ctrl.inp", ncores=1)
97161

98162

99-
def test_write_xtb_input_creates_expected_file(monkeypatch, tmp_path, make_orca):
100-
xtb_cfg_instance = DummyXTBConfig(
101-
distance_constraints=["dummy"], distance_constraint_force_constant=0.7
102-
)
163+
def test_write_xtb_input_creates_expected_file(
164+
monkeypatch, tmp_path, make_orca, fake_xtb_path, mol_oh
165+
):
166+
xtb_cfg_instance = XTBConfig()
167+
xtb_cfg_instance.distance_constraints = []
168+
xtb_cfg_instance.distance_constraint_force_constant = 0.7
103169
orca = make_orca(xtb_cfg_param=xtb_cfg_instance)
104-
monkeypatch.setattr("mindlessgen.qm.orca.get_xtb_path", lambda: Path("/fake/xtb"))
105170

106171
def fake_prepare(self, molecule, temp_dir):
107172
assert temp_dir == tmp_path
@@ -123,7 +188,7 @@ def fake_prepare(self, molecule, temp_dir):
123188
"mindlessgen.qm.orca.XTB._prepare_distance_constraint_file", fake_prepare
124189
)
125190
target = tmp_path / "xtb.inp"
126-
orca._write_xtb_input(DummyMolecule(), target, "orca.inp")
191+
orca._write_xtb_input(mol_oh, target, "orca.inp")
127192
content = target.read_text().splitlines()
128193
assert content[:4] == [
129194
"$constrain",
@@ -134,3 +199,46 @@ def fake_prepare(self, molecule, temp_dir):
134199
assert "$external" in content
135200
assert " orca input file= orca.inp" in content
136201
assert f" orca bin= {orca.path}" in content
202+
203+
204+
def test_write_xtb_input_generates_constraints(
205+
fake_xtb_path, tmp_path, make_orca, xtb_cfg_oh, mol_oh
206+
):
207+
orca = make_orca(xtb_cfg_param=xtb_cfg_oh)
208+
209+
xtb_input = tmp_path / "xtb.inp"
210+
orca._write_xtb_input(mol_oh, xtb_input, "orca.inp")
211+
212+
contents = xtb_input.read_text(encoding="utf8").splitlines()
213+
assert contents[0] == "$constrain"
214+
assert "force constant= 0.5" in contents[1]
215+
distance_lines = [line for line in contents if line.startswith(" distance:")]
216+
assert distance_lines == [" distance: 1, 2, 1.0"]
217+
assert "$external" in contents
218+
assert " orca input file= orca.inp" in contents
219+
assert f" orca bin= {orca.path}" in contents
220+
221+
222+
def test_write_xtb_input_missing_atoms(
223+
fake_xtb_path, tmp_path, make_orca, xtb_cfg_ff, mol_h2
224+
):
225+
orca = make_orca(xtb_cfg_param=xtb_cfg_ff)
226+
227+
with pytest.raises(RuntimeError):
228+
orca._write_xtb_input(mol_h2, tmp_path / "xtb.inp", "orca.inp")
229+
230+
231+
def test_distance_constraints_use_first_atoms(
232+
fake_xtb_path, tmp_path, make_orca, xtb_cfg_fe3, mol_fe3
233+
):
234+
orca = make_orca(xtb_cfg_param=xtb_cfg_fe3)
235+
236+
xtb_input = tmp_path / "xtb.inp"
237+
orca._write_xtb_input(mol_fe3, xtb_input, "orca.inp")
238+
239+
contents = xtb_input.read_text(encoding="utf8").splitlines()
240+
distance_lines = [line for line in contents if "distance:" in line]
241+
242+
assert len(distance_lines) == 1
243+
assert "1, 2" in distance_lines[0]
244+
assert ", 3," not in distance_lines[0]

0 commit comments

Comments
 (0)