From a55d0316c38753587f561efc4af1e511a543e906 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Robidas?= Date: Mon, 21 Aug 2023 09:56:42 -0400 Subject: [PATCH] Added concerted xtb scans --- ccinput/packages/xtb.py | 19 +++++++++ ccinput/tests/test_xtb.py | 87 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 105 insertions(+), 1 deletion(-) diff --git a/ccinput/packages/xtb.py b/ccinput/packages/xtb.py index 62324b1..2ab927a 100644 --- a/ccinput/packages/xtb.py +++ b/ccinput/packages/xtb.py @@ -33,6 +33,7 @@ def __init__(self, calc): self.input_file = "" self.specifications = "" self.force_constant = 1.0 + self.concerted_scan = False self.confirmed_specifications = "" if self.calc.type not in self.EXECUTABLES: @@ -111,8 +112,17 @@ def handle_constraints_scan(self): if cmd.scan: self.has_scan = True + if self.concerted_scan and ( + not self.has_scan or len(self.calc.constraints) < 2 + ): + raise InvalidParameter( + "The concerted mode only influences scans with multiple coordinates" + ) + if self.has_scan: self.input_file += "$scan\n" + if self.concerted_scan: + self.input_file += "mode=concerted\n" for counter, cmd in enumerate(self.calc.constraints): if cmd.scan: self.input_file += f"{counter+1}: {cmd.start_d:.2f}, {cmd.end_d:.2f}, {cmd.num_steps}\n" @@ -217,6 +227,15 @@ def handle_specifications(self): self.cmd_arguments += "--squick " elif ss[0] == "mquick": self.cmd_arguments += "--mquick " + elif ss[0] == "concerted": + if self.calc.type not in [ + CalcType.CONSTR_OPT, + ]: + raise InvalidParameter( + f"Invalid specification for calculation type: {ss[0]}" + ) + self.concerted_scan = True + else: raise InvalidParameter("Invalid specification") elif len(ss) == 2: diff --git a/ccinput/tests/test_xtb.py b/ccinput/tests/test_xtb.py index 1b877e1..15d73cb 100644 --- a/ccinput/tests/test_xtb.py +++ b/ccinput/tests/test_xtb.py @@ -258,6 +258,56 @@ def test_scan_auto(self): """ self.assertTrue(self.is_equivalent(INPUT, xtb.input_file)) + def test_scan_two_coordinates(self): + params = { + "type": "Constrained Optimisation", + "file": "ethanol.xyz", + "software": "xtb", + "constraints": "Scan_9_1.4_10/1_2;Scan_9_1.4_10/2_3", + } + + xtb = self.generate_calculation(**params) + + REF = "xtb ethanol.xyz --opt tight --input input" + + self.assertTrue(self.is_equivalent(REF, xtb.command)) + + INPUT = """$constrain + force constant=1.0 + distance: 1, 2, auto + distance: 2, 3, auto + $scan + 1: 9.00, 1.40, 10 + 2: 9.00, 1.40, 10 + """ + self.assertTrue(self.is_equivalent(INPUT, xtb.input_file)) + + def test_scan_two_coordinates_concerted(self): + params = { + "type": "Constrained Optimisation", + "file": "ethanol.xyz", + "software": "xtb", + "constraints": "Scan_9_1.4_10/1_2;Scan_9_1.4_10/2_3", + "specifications": "--concerted", + } + + xtb = self.generate_calculation(**params) + + REF = "xtb ethanol.xyz --opt tight --input input" + + self.assertTrue(self.is_equivalent(REF, xtb.command)) + + INPUT = """$constrain + force constant=1.0 + distance: 1, 2, auto + distance: 2, 3, auto + $scan + mode=concerted + 1: 9.00, 1.40, 10 + 2: 9.00, 1.40, 10 + """ + self.assertTrue(self.is_equivalent(INPUT, xtb.input_file)) + def test_constrained_opt_no_constraint(self): params = { "type": "Constrained Optimisation", @@ -266,7 +316,42 @@ def test_constrained_opt_no_constraint(self): } with self.assertRaises(InvalidParameter): - xtb = self.generate_calculation(**params) + self.generate_calculation(**params) + + def test_freeze_concerted_exception(self): + params = { + "type": "Constrained Optimisation", + "file": "ethanol.xyz", + "software": "xtb", + "constraints": "Freeze_9_1.4_10;Freeze_9_1.4_10", + "specifications": "--concerted", + } + + with self.assertRaises(InvalidParameter): + self.generate_calculation(**params) + + def test_scan_single_coordinate_concerted_exception(self): + params = { + "type": "Constrained Optimisation", + "file": "ethanol.xyz", + "software": "xtb", + "constraints": "Scan_9_1.4_10/1_2;", + "specifications": "--concerted", + } + + with self.assertRaises(InvalidParameter): + self.generate_calculation(**params) + + def test_opt_concerted_exception(self): + params = { + "type": "Geometrical Optimisation", + "file": "ethanol.xyz", + "software": "xtb", + "specifications": "--concerted", + } + + with self.assertRaises(InvalidParameter): + self.generate_calculation(**params) def test_freeze(self): params = {