From f902165206bc5e6a1a048eb4062358030bdabf38 Mon Sep 17 00:00:00 2001 From: "Jonathan M. Waldrop" Date: Fri, 5 Apr 2024 19:15:26 -0500 Subject: [PATCH 01/14] backup --- src/python/friendzone/nwx2nwchem/__init__.py | 29 ++++++++++++++++++- .../friendzone/nwx2qcengine/pt2driver.py | 2 ++ .../unit_tests/nwx2nwchem/test_nwchem.py | 10 +++++++ 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/python/friendzone/nwx2nwchem/__init__.py b/src/python/friendzone/nwx2nwchem/__init__.py index 609302a..81203e7 100644 --- a/src/python/friendzone/nwx2nwchem/__init__.py +++ b/src/python/friendzone/nwx2nwchem/__init__.py @@ -15,6 +15,7 @@ from ..friends import is_friend_enabled import pluginplay as pp from simde import TotalEnergy +from simde.provisional import AOEnergyNuclearGradientD from ..nwx2qcengine.call_qcengine import call_qcengine @@ -37,6 +38,28 @@ def run_(self, inputs, submods): rv = self.results() return pt.wrap_results(rv, e) +class NWChemGradientViaMolSSI(pp.ModuleBase): + + def __init__(self): + pp.ModuleBase.__init__(self) + self.satisfies_property_type(AOEnergyNuclearGradientD()) + self.description("Calls NWChem via MolSSI's QCEngine") + self.add_input('method') + self.add_input("basis set") + + def run_(self, inputs, submods): + pt = AOEnergyNuclearGradientD() + + # This line is awkward and needs to be cleaned up + nwx_basis, mol, mol_again = pt.unwrap_inputs(inputs) + + method = inputs['method'].value() + basis = inputs['basis set'].value() + + e = call_qcengine(pt, mol, 'nwchem', method=method, basis=basis) + rv = self.results() + return pt.wrap_results(rv, e) + def load_nwchem_modules(mm): """Loads the collection of modules that wrap NWChem calls. @@ -47,7 +70,8 @@ def load_nwchem_modules(mm): #. NWChem : MP2 #. NWChem : CCSD #. NWChem : CCSD(T) - + #. NWChem : SCF Gradient + :param mm: The ModuleManager that the NWChem Modules will be loaded into. :type mm: pluginplay.ModuleManager """ @@ -56,3 +80,6 @@ def load_nwchem_modules(mm): mod_key = 'NWChem : ' + method mm.add_module(mod_key, NWChemViaMolSSI()) mm.change_input(mod_key, 'method', method) + + mm.add_module('NWChem : SCF Gradient', NWChemGradientViaMolSSI()) + mm.change_input('NWChem : SCF Gradient', 'method', 'SCF') diff --git a/src/python/friendzone/nwx2qcengine/pt2driver.py b/src/python/friendzone/nwx2qcengine/pt2driver.py index 44215e3..4dbe129 100644 --- a/src/python/friendzone/nwx2qcengine/pt2driver.py +++ b/src/python/friendzone/nwx2qcengine/pt2driver.py @@ -31,5 +31,7 @@ def pt2driver(pt): """ if pt.type() == simde.TotalEnergy().type(): return 'energy' + if pt.type() == simde.provisional.AOEnergyNuclearGradientD().type(): + return 'gradient' raise Exception('PropertyType is not registered') diff --git a/tests/python/unit_tests/nwx2nwchem/test_nwchem.py b/tests/python/unit_tests/nwx2nwchem/test_nwchem.py index c8e74bf..59acee5 100644 --- a/tests/python/unit_tests/nwx2nwchem/test_nwchem.py +++ b/tests/python/unit_tests/nwx2nwchem/test_nwchem.py @@ -15,6 +15,8 @@ from pluginplay import ModuleManager from friendzone import friends, load_modules from simde import TotalEnergy +from simde.provisional import AOEnergyNuclearGradientD +from chemist.basis_set import AtomicBasisSetD from molecules import make_h2 import unittest @@ -49,6 +51,14 @@ def test_ccsd_t(self): egy = self.mm.run_as(TotalEnergy(), key, mol) self.assertAlmostEqual(egy, -1.122251361965036, places=4) + def test_scf_gradient(self): + mol = make_h2() + bs = AtomicBasisSetD() + key = 'NWChem : SCF Gradient' + self.mm.change_input(key, 'basis set', 'sto-3g') + grad = self.mm.run_as(AOEnergyNuclearGradientD(), key, mol, bs, mol) + print(grad) + def setUp(self): if not friends.is_friend_enabled('nwchem'): self.skipTest("NWChem backend is not enabled!") From 48d793dc79b55a3081bda2e54f853cee3093f342 Mon Sep 17 00:00:00 2001 From: "Jonathan M. Waldrop" Date: Mon, 8 Apr 2024 16:36:36 -0500 Subject: [PATCH 02/14] should work, but doesn't --- src/python/friendzone/nwx2nwchem/__init__.py | 8 ++++---- src/python/friendzone/nwx2qcengine/pt2driver.py | 2 +- tests/python/unit_tests/nwx2nwchem/test_nwchem.py | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/python/friendzone/nwx2nwchem/__init__.py b/src/python/friendzone/nwx2nwchem/__init__.py index 81203e7..a5de230 100644 --- a/src/python/friendzone/nwx2nwchem/__init__.py +++ b/src/python/friendzone/nwx2nwchem/__init__.py @@ -15,7 +15,7 @@ from ..friends import is_friend_enabled import pluginplay as pp from simde import TotalEnergy -from simde.provisional import AOEnergyNuclearGradientD +from simde.provisional import EnergyNuclearGradientD from ..nwx2qcengine.call_qcengine import call_qcengine @@ -42,16 +42,16 @@ class NWChemGradientViaMolSSI(pp.ModuleBase): def __init__(self): pp.ModuleBase.__init__(self) - self.satisfies_property_type(AOEnergyNuclearGradientD()) + self.satisfies_property_type(EnergyNuclearGradientD()) self.description("Calls NWChem via MolSSI's QCEngine") self.add_input('method') self.add_input("basis set") def run_(self, inputs, submods): - pt = AOEnergyNuclearGradientD() + pt = EnergyNuclearGradientD() # This line is awkward and needs to be cleaned up - nwx_basis, mol, mol_again = pt.unwrap_inputs(inputs) + mol, = pt.unwrap_inputs(inputs) method = inputs['method'].value() basis = inputs['basis set'].value() diff --git a/src/python/friendzone/nwx2qcengine/pt2driver.py b/src/python/friendzone/nwx2qcengine/pt2driver.py index 4dbe129..27df228 100644 --- a/src/python/friendzone/nwx2qcengine/pt2driver.py +++ b/src/python/friendzone/nwx2qcengine/pt2driver.py @@ -31,7 +31,7 @@ def pt2driver(pt): """ if pt.type() == simde.TotalEnergy().type(): return 'energy' - if pt.type() == simde.provisional.AOEnergyNuclearGradientD().type(): + if pt.type() == simde.provisional.EnergyNuclearGradientD().type(): return 'gradient' raise Exception('PropertyType is not registered') diff --git a/tests/python/unit_tests/nwx2nwchem/test_nwchem.py b/tests/python/unit_tests/nwx2nwchem/test_nwchem.py index 59acee5..1c34868 100644 --- a/tests/python/unit_tests/nwx2nwchem/test_nwchem.py +++ b/tests/python/unit_tests/nwx2nwchem/test_nwchem.py @@ -15,7 +15,7 @@ from pluginplay import ModuleManager from friendzone import friends, load_modules from simde import TotalEnergy -from simde.provisional import AOEnergyNuclearGradientD +from simde.provisional import EnergyNuclearGradientD from chemist.basis_set import AtomicBasisSetD from molecules import make_h2 import unittest @@ -56,7 +56,7 @@ def test_scf_gradient(self): bs = AtomicBasisSetD() key = 'NWChem : SCF Gradient' self.mm.change_input(key, 'basis set', 'sto-3g') - grad = self.mm.run_as(AOEnergyNuclearGradientD(), key, mol, bs, mol) + grad = self.mm.run_as(EnergyNuclearGradientD(), key, mol) print(grad) def setUp(self): From ccd275405adeb5229ce1cfbf8372a96e4735bdae Mon Sep 17 00:00:00 2001 From: "Jonathan M. Waldrop" Date: Mon, 8 Apr 2024 17:10:53 -0500 Subject: [PATCH 03/14] flatten qcengine return list --- src/python/friendzone/nwx2nwchem/__init__.py | 1 + tests/python/unit_tests/nwx2nwchem/test_nwchem.py | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/python/friendzone/nwx2nwchem/__init__.py b/src/python/friendzone/nwx2nwchem/__init__.py index a5de230..59f1b8e 100644 --- a/src/python/friendzone/nwx2nwchem/__init__.py +++ b/src/python/friendzone/nwx2nwchem/__init__.py @@ -57,6 +57,7 @@ def run_(self, inputs, submods): basis = inputs['basis set'].value() e = call_qcengine(pt, mol, 'nwchem', method=method, basis=basis) + e = [c for cs in e for c in cs] # Flatten out the list of lists rv = self.results() return pt.wrap_results(rv, e) diff --git a/tests/python/unit_tests/nwx2nwchem/test_nwchem.py b/tests/python/unit_tests/nwx2nwchem/test_nwchem.py index 1c34868..6fac6e1 100644 --- a/tests/python/unit_tests/nwx2nwchem/test_nwchem.py +++ b/tests/python/unit_tests/nwx2nwchem/test_nwchem.py @@ -57,7 +57,9 @@ def test_scf_gradient(self): key = 'NWChem : SCF Gradient' self.mm.change_input(key, 'basis set', 'sto-3g') grad = self.mm.run_as(EnergyNuclearGradientD(), key, mol) - print(grad) + corr = [0.0, 0.0, -0.11827177600466043, 0.0, 0.0, 0.11827177600466043] + for g, c in zip(grad, corr): + self.assertAlmostEqual(g, c, places=4) def setUp(self): if not friends.is_friend_enabled('nwchem'): From 320d9a353470540d6654d8440d34db772f983ee8 Mon Sep 17 00:00:00 2001 From: "Jonathan M. Waldrop" Date: Tue, 9 Apr 2024 17:23:58 -0500 Subject: [PATCH 04/14] backup --- src/python/friendzone/nwx2nwchem/__init__.py | 15 +++++++++++---- .../friendzone/nwx2qcengine/call_qcengine.py | 2 +- .../nwx2qcengine/chemical_system2qc_mol.py | 2 +- tests/python/unit_tests/nwx2nwchem/test_nwchem.py | 11 +++++++++-- 4 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/python/friendzone/nwx2nwchem/__init__.py b/src/python/friendzone/nwx2nwchem/__init__.py index 59f1b8e..3905b00 100644 --- a/src/python/friendzone/nwx2nwchem/__init__.py +++ b/src/python/friendzone/nwx2nwchem/__init__.py @@ -27,17 +27,21 @@ def __init__(self): self.description("Calls NWChem via MolSSI's QCEngine") self.add_input('method') self.add_input("basis set") + self.add_input("keywords").set_default({}) def run_(self, inputs, submods): pt = TotalEnergy() mol, = pt.unwrap_inputs(inputs) method = inputs['method'].value() basis = inputs['basis set'].value() + keywords = inputs['keywords'].value() - e = call_qcengine(pt, mol, 'nwchem', method=method, basis=basis) + model = {"method": method, "basis": basis} + e = call_qcengine(pt, mol, 'nwchem', model=model, keywords=keywords) rv = self.results() return pt.wrap_results(rv, e) + class NWChemGradientViaMolSSI(pp.ModuleBase): def __init__(self): @@ -46,6 +50,7 @@ def __init__(self): self.description("Calls NWChem via MolSSI's QCEngine") self.add_input('method') self.add_input("basis set") + self.add_input("keywords").set_default({}) def run_(self, inputs, submods): pt = EnergyNuclearGradientD() @@ -55,9 +60,11 @@ def run_(self, inputs, submods): method = inputs['method'].value() basis = inputs['basis set'].value() + keywords = inputs['keywords'].value() - e = call_qcengine(pt, mol, 'nwchem', method=method, basis=basis) - e = [c for cs in e for c in cs] # Flatten out the list of lists + model = {"method": method, "basis": basis} + e = call_qcengine(pt, mol, 'nwchem', model=model, keywords=keywords) + e = [c for cs in e for c in cs] # Flatten out the list of lists rv = self.results() return pt.wrap_results(rv, e) @@ -81,6 +88,6 @@ def load_nwchem_modules(mm): mod_key = 'NWChem : ' + method mm.add_module(mod_key, NWChemViaMolSSI()) mm.change_input(mod_key, 'method', method) - + mm.add_module('NWChem : SCF Gradient', NWChemGradientViaMolSSI()) mm.change_input('NWChem : SCF Gradient', 'method', 'SCF') diff --git a/src/python/friendzone/nwx2qcengine/call_qcengine.py b/src/python/friendzone/nwx2qcengine/call_qcengine.py index 2dd6ead..a9cd033 100644 --- a/src/python/friendzone/nwx2qcengine/call_qcengine.py +++ b/src/python/friendzone/nwx2qcengine/call_qcengine.py @@ -64,6 +64,6 @@ def call_qcengine(pt, mol, program, **kwargs): driver = pt2driver(pt) qc_mol = chemical_system2qc_mol(mol) - inp = qcel.models.AtomicInput(molecule=qc_mol, driver=driver, model=kwargs) + inp = qcel.models.AtomicInput(molecule=qc_mol, driver=driver, **kwargs) results = qcng.compute(inp, program) return results.return_result diff --git a/src/python/friendzone/nwx2qcengine/chemical_system2qc_mol.py b/src/python/friendzone/nwx2qcengine/chemical_system2qc_mol.py index c94a50a..9c451ba 100644 --- a/src/python/friendzone/nwx2qcengine/chemical_system2qc_mol.py +++ b/src/python/friendzone/nwx2qcengine/chemical_system2qc_mol.py @@ -42,4 +42,4 @@ def chemical_system2qc_mol(chem_sys): y = str(atom_i.y * au2ang) z = str(atom_i.z * au2ang) out += symbol + " " + x + " " + y + " " + z + "\n" - return qcel.models.Molecule.from_data(out) + return qcel.models.Molecule.from_data(out, fix_com=True, fix_orientation=True, fix_symmetry="C1") diff --git a/tests/python/unit_tests/nwx2nwchem/test_nwchem.py b/tests/python/unit_tests/nwx2nwchem/test_nwchem.py index 6fac6e1..52012dd 100644 --- a/tests/python/unit_tests/nwx2nwchem/test_nwchem.py +++ b/tests/python/unit_tests/nwx2nwchem/test_nwchem.py @@ -16,7 +16,6 @@ from friendzone import friends, load_modules from simde import TotalEnergy from simde.provisional import EnergyNuclearGradientD -from chemist.basis_set import AtomicBasisSetD from molecules import make_h2 import unittest @@ -53,9 +52,17 @@ def test_ccsd_t(self): def test_scf_gradient(self): mol = make_h2() - bs = AtomicBasisSetD() key = 'NWChem : SCF Gradient' self.mm.change_input(key, 'basis set', 'sto-3g') + self.mm.change_input( + key, "keywords", { + "scf; uhf; ": "end", + "geometry__nocenter": ".true.", + "geometry__noautoz": ".true.", + "set scf:maxiter": 100000, + "set scf:thresh": 1.0e-8, + "set cphf:maxiter": 100000 + }) grad = self.mm.run_as(EnergyNuclearGradientD(), key, mol) corr = [0.0, 0.0, -0.11827177600466043, 0.0, 0.0, 0.11827177600466043] for g, c in zip(grad, corr): From 2c31bdaddf6aee173c104d400c70d55ac6a423b7 Mon Sep 17 00:00:00 2001 From: "Jonathan M. Waldrop" Date: Wed, 10 Apr 2024 10:58:58 -0500 Subject: [PATCH 05/14] clean around changes --- src/python/friendzone/nwx2nwchem/__init__.py | 3 --- .../friendzone/nwx2qcengine/call_qcengine.py | 2 +- .../nwx2qcengine/chemical_system2qc_mol.py | 1 + .../python/unit_tests/nwx2nwchem/test_nwchem.py | 16 +++++++--------- .../unit_tests/nwx2qcengine/test_pt2driver.py | 5 +++++ 5 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/python/friendzone/nwx2nwchem/__init__.py b/src/python/friendzone/nwx2nwchem/__init__.py index 3905b00..82b868b 100644 --- a/src/python/friendzone/nwx2nwchem/__init__.py +++ b/src/python/friendzone/nwx2nwchem/__init__.py @@ -54,10 +54,7 @@ def __init__(self): def run_(self, inputs, submods): pt = EnergyNuclearGradientD() - - # This line is awkward and needs to be cleaned up mol, = pt.unwrap_inputs(inputs) - method = inputs['method'].value() basis = inputs['basis set'].value() keywords = inputs['keywords'].value() diff --git a/src/python/friendzone/nwx2qcengine/call_qcengine.py b/src/python/friendzone/nwx2qcengine/call_qcengine.py index a9cd033..a1349f3 100644 --- a/src/python/friendzone/nwx2qcengine/call_qcengine.py +++ b/src/python/friendzone/nwx2qcengine/call_qcengine.py @@ -56,7 +56,7 @@ def call_qcengine(pt, mol, program, **kwargs): backend? :type program: str :param kwargs: Key-value pairs which will be forwarded to QCElemental's - ``AtomicInput`` class via the ``model`` key. + ``AtomicInput`` class constructor. :return: The requested property. :rtype: Varies depending on the requested property diff --git a/src/python/friendzone/nwx2qcengine/chemical_system2qc_mol.py b/src/python/friendzone/nwx2qcengine/chemical_system2qc_mol.py index 9c451ba..0ebffc4 100644 --- a/src/python/friendzone/nwx2qcengine/chemical_system2qc_mol.py +++ b/src/python/friendzone/nwx2qcengine/chemical_system2qc_mol.py @@ -42,4 +42,5 @@ def chemical_system2qc_mol(chem_sys): y = str(atom_i.y * au2ang) z = str(atom_i.z * au2ang) out += symbol + " " + x + " " + y + " " + z + "\n" + # Fixing CoM and orientation and turning off symmetry to prevent molecular translation return qcel.models.Molecule.from_data(out, fix_com=True, fix_orientation=True, fix_symmetry="C1") diff --git a/tests/python/unit_tests/nwx2nwchem/test_nwchem.py b/tests/python/unit_tests/nwx2nwchem/test_nwchem.py index 52012dd..c83a6fb 100644 --- a/tests/python/unit_tests/nwx2nwchem/test_nwchem.py +++ b/tests/python/unit_tests/nwx2nwchem/test_nwchem.py @@ -53,16 +53,14 @@ def test_ccsd_t(self): def test_scf_gradient(self): mol = make_h2() key = 'NWChem : SCF Gradient' + # Keywords need to work to prevent molecular translation + # At time of writing, they only work with Kazuumi's fork + keywords = { + "geometry__nocenter": ".true.", + "geometry__noautoz": ".true.", + } self.mm.change_input(key, 'basis set', 'sto-3g') - self.mm.change_input( - key, "keywords", { - "scf; uhf; ": "end", - "geometry__nocenter": ".true.", - "geometry__noautoz": ".true.", - "set scf:maxiter": 100000, - "set scf:thresh": 1.0e-8, - "set cphf:maxiter": 100000 - }) + self.mm.change_input(key, "keywords", keywords) grad = self.mm.run_as(EnergyNuclearGradientD(), key, mol) corr = [0.0, 0.0, -0.11827177600466043, 0.0, 0.0, 0.11827177600466043] for g, c in zip(grad, corr): diff --git a/tests/python/unit_tests/nwx2qcengine/test_pt2driver.py b/tests/python/unit_tests/nwx2qcengine/test_pt2driver.py index 8398004..ffe5958 100644 --- a/tests/python/unit_tests/nwx2qcengine/test_pt2driver.py +++ b/tests/python/unit_tests/nwx2qcengine/test_pt2driver.py @@ -14,6 +14,7 @@ from friendzone.nwx2qcengine.pt2driver import pt2driver from simde import TotalEnergy +from simde.provisional import EnergyNuclearGradientD import unittest @@ -27,5 +28,9 @@ def test_pts_that_map_to_energy(self): for pt in [TotalEnergy()]: self.assertEqual(pt2driver(pt), 'energy') + def test_pts_that_map_to_gradient(self): + for pt in [EnergyNuclearGradientD()]: + self.assertEqual(pt2driver(pt), 'gradient') + def test_bad_pt(self): self.assertRaises(Exception, pt2driver, NotAPT()) From 0d375563c24d9ed98622de4ea10540137412a78a Mon Sep 17 00:00:00 2001 From: "Jonathan M. Waldrop" Date: Thu, 18 Apr 2024 16:52:48 -0500 Subject: [PATCH 06/14] mostly changed for PT changes --- src/python/friendzone/nwx2nwchem/__init__.py | 8 ++++---- src/python/friendzone/nwx2qcengine/pt2driver.py | 2 +- tests/python/unit_tests/nwx2nwchem/test_nwchem.py | 4 ++-- tests/python/unit_tests/nwx2qcengine/test_pt2driver.py | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/python/friendzone/nwx2nwchem/__init__.py b/src/python/friendzone/nwx2nwchem/__init__.py index 82b868b..08e3eff 100644 --- a/src/python/friendzone/nwx2nwchem/__init__.py +++ b/src/python/friendzone/nwx2nwchem/__init__.py @@ -15,7 +15,7 @@ from ..friends import is_friend_enabled import pluginplay as pp from simde import TotalEnergy -from simde.provisional import EnergyNuclearGradientD +from simde import EnergyNuclearGradientStdVectorD from ..nwx2qcengine.call_qcengine import call_qcengine @@ -46,15 +46,15 @@ class NWChemGradientViaMolSSI(pp.ModuleBase): def __init__(self): pp.ModuleBase.__init__(self) - self.satisfies_property_type(EnergyNuclearGradientD()) + self.satisfies_property_type(EnergyNuclearGradientStdVectorD()) self.description("Calls NWChem via MolSSI's QCEngine") self.add_input('method') self.add_input("basis set") self.add_input("keywords").set_default({}) def run_(self, inputs, submods): - pt = EnergyNuclearGradientD() - mol, = pt.unwrap_inputs(inputs) + pt = EnergyNuclearGradientStdVectorD() + mol, arg = pt.unwrap_inputs(inputs) method = inputs['method'].value() basis = inputs['basis set'].value() keywords = inputs['keywords'].value() diff --git a/src/python/friendzone/nwx2qcengine/pt2driver.py b/src/python/friendzone/nwx2qcengine/pt2driver.py index 27df228..d33554c 100644 --- a/src/python/friendzone/nwx2qcengine/pt2driver.py +++ b/src/python/friendzone/nwx2qcengine/pt2driver.py @@ -31,7 +31,7 @@ def pt2driver(pt): """ if pt.type() == simde.TotalEnergy().type(): return 'energy' - if pt.type() == simde.provisional.EnergyNuclearGradientD().type(): + if pt.type() == simde.EnergyNuclearGradientStdVectorD().type(): return 'gradient' raise Exception('PropertyType is not registered') diff --git a/tests/python/unit_tests/nwx2nwchem/test_nwchem.py b/tests/python/unit_tests/nwx2nwchem/test_nwchem.py index c83a6fb..61666c4 100644 --- a/tests/python/unit_tests/nwx2nwchem/test_nwchem.py +++ b/tests/python/unit_tests/nwx2nwchem/test_nwchem.py @@ -15,7 +15,7 @@ from pluginplay import ModuleManager from friendzone import friends, load_modules from simde import TotalEnergy -from simde.provisional import EnergyNuclearGradientD +from simde import EnergyNuclearGradientStdVectorD from molecules import make_h2 import unittest @@ -61,7 +61,7 @@ def test_scf_gradient(self): } self.mm.change_input(key, 'basis set', 'sto-3g') self.mm.change_input(key, "keywords", keywords) - grad = self.mm.run_as(EnergyNuclearGradientD(), key, mol) + grad = self.mm.run_as(EnergyNuclearGradientStdVectorD(), key, mol, arg1) corr = [0.0, 0.0, -0.11827177600466043, 0.0, 0.0, 0.11827177600466043] for g, c in zip(grad, corr): self.assertAlmostEqual(g, c, places=4) diff --git a/tests/python/unit_tests/nwx2qcengine/test_pt2driver.py b/tests/python/unit_tests/nwx2qcengine/test_pt2driver.py index ffe5958..40c0686 100644 --- a/tests/python/unit_tests/nwx2qcengine/test_pt2driver.py +++ b/tests/python/unit_tests/nwx2qcengine/test_pt2driver.py @@ -14,7 +14,7 @@ from friendzone.nwx2qcengine.pt2driver import pt2driver from simde import TotalEnergy -from simde.provisional import EnergyNuclearGradientD +from simde import EnergyNuclearGradientStdVectorD import unittest @@ -29,7 +29,7 @@ def test_pts_that_map_to_energy(self): self.assertEqual(pt2driver(pt), 'energy') def test_pts_that_map_to_gradient(self): - for pt in [EnergyNuclearGradientD()]: + for pt in [EnergyNuclearGradientStdVectorD()]: self.assertEqual(pt2driver(pt), 'gradient') def test_bad_pt(self): From d351ee1bad5240157e648997c199db6a57786732 Mon Sep 17 00:00:00 2001 From: "Jonathan M. Waldrop" Date: Fri, 19 Apr 2024 09:23:44 -0500 Subject: [PATCH 07/14] fix gradient input --- tests/python/unit_tests/nwx2nwchem/test_nwchem.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/python/unit_tests/nwx2nwchem/test_nwchem.py b/tests/python/unit_tests/nwx2nwchem/test_nwchem.py index 61666c4..a15f5f0 100644 --- a/tests/python/unit_tests/nwx2nwchem/test_nwchem.py +++ b/tests/python/unit_tests/nwx2nwchem/test_nwchem.py @@ -16,6 +16,7 @@ from friendzone import friends, load_modules from simde import TotalEnergy from simde import EnergyNuclearGradientStdVectorD +from chemist import PointSetD from molecules import make_h2 import unittest @@ -61,7 +62,7 @@ def test_scf_gradient(self): } self.mm.change_input(key, 'basis set', 'sto-3g') self.mm.change_input(key, "keywords", keywords) - grad = self.mm.run_as(EnergyNuclearGradientStdVectorD(), key, mol, arg1) + grad = self.mm.run_as(EnergyNuclearGradientStdVectorD(), key, mol, PointSetD()) corr = [0.0, 0.0, -0.11827177600466043, 0.0, 0.0, 0.11827177600466043] for g, c in zip(grad, corr): self.assertAlmostEqual(g, c, places=4) From 3553ab43da87d78b813e5bec9d521d199fdd8fbc Mon Sep 17 00:00:00 2001 From: "Jonathan M. Waldrop" Date: Tue, 23 Apr 2024 10:49:27 -0500 Subject: [PATCH 08/14] remove unneeded keywords from gradient test --- tests/python/unit_tests/nwx2nwchem/test_nwchem.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/tests/python/unit_tests/nwx2nwchem/test_nwchem.py b/tests/python/unit_tests/nwx2nwchem/test_nwchem.py index a15f5f0..75ca953 100644 --- a/tests/python/unit_tests/nwx2nwchem/test_nwchem.py +++ b/tests/python/unit_tests/nwx2nwchem/test_nwchem.py @@ -54,14 +54,7 @@ def test_ccsd_t(self): def test_scf_gradient(self): mol = make_h2() key = 'NWChem : SCF Gradient' - # Keywords need to work to prevent molecular translation - # At time of writing, they only work with Kazuumi's fork - keywords = { - "geometry__nocenter": ".true.", - "geometry__noautoz": ".true.", - } self.mm.change_input(key, 'basis set', 'sto-3g') - self.mm.change_input(key, "keywords", keywords) grad = self.mm.run_as(EnergyNuclearGradientStdVectorD(), key, mol, PointSetD()) corr = [0.0, 0.0, -0.11827177600466043, 0.0, 0.0, 0.11827177600466043] for g, c in zip(grad, corr): From b9342cb54cda477198392ebb71bbe5d98b871d0f Mon Sep 17 00:00:00 2001 From: "Jonathan M. Waldrop" Date: Tue, 23 Apr 2024 10:50:56 -0500 Subject: [PATCH 09/14] use sets to map ptypes to driver type --- src/python/friendzone/nwx2qcengine/pt2driver.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/python/friendzone/nwx2qcengine/pt2driver.py b/src/python/friendzone/nwx2qcengine/pt2driver.py index d33554c..f4b5943 100644 --- a/src/python/friendzone/nwx2qcengine/pt2driver.py +++ b/src/python/friendzone/nwx2qcengine/pt2driver.py @@ -29,9 +29,18 @@ def pt2driver(pt): :raises: Exception if ``pt`` is not a property type which has been registered with this function. """ - if pt.type() == simde.TotalEnergy().type(): + + # Set of Property Types that map to energy driver + energy_pts = { + simde.TotalEnergy().type(), + } + # Set of Property Types that map to gradient driver + gradient_pts = { + simde.EnergyNuclearGradientStdVectorD().type(), + } + + if pt.type() in energy_pts: return 'energy' - if pt.type() == simde.EnergyNuclearGradientStdVectorD().type(): + if pt.type() in gradient_pts: return 'gradient' - raise Exception('PropertyType is not registered') From 2d85083f40f425ed780ed8428a5c52d8643783be Mon Sep 17 00:00:00 2001 From: "Jonathan M. Waldrop" Date: Tue, 23 Apr 2024 11:08:54 -0500 Subject: [PATCH 10/14] update pt2driver test --- .../unit_tests/nwx2qcengine/test_pt2driver.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/tests/python/unit_tests/nwx2qcengine/test_pt2driver.py b/tests/python/unit_tests/nwx2qcengine/test_pt2driver.py index 40c0686..1bcd073 100644 --- a/tests/python/unit_tests/nwx2qcengine/test_pt2driver.py +++ b/tests/python/unit_tests/nwx2qcengine/test_pt2driver.py @@ -13,8 +13,7 @@ # limitations under the License. from friendzone.nwx2qcengine.pt2driver import pt2driver -from simde import TotalEnergy -from simde import EnergyNuclearGradientStdVectorD +import simde import unittest @@ -25,11 +24,17 @@ class NotAPT: class Testpt2driver(unittest.TestCase): def test_pts_that_map_to_energy(self): - for pt in [TotalEnergy()]: + energy_pts = { + simde.TotalEnergy(), + } + for pt in energy_pts: self.assertEqual(pt2driver(pt), 'energy') def test_pts_that_map_to_gradient(self): - for pt in [EnergyNuclearGradientStdVectorD()]: + gradient_pts = { + simde.EnergyNuclearGradientStdVectorD(), + } + for pt in gradient_pts: self.assertEqual(pt2driver(pt), 'gradient') def test_bad_pt(self): From 20977666e4d0703428b3e55452967fbd90b2ca3f Mon Sep 17 00:00:00 2001 From: "Jonathan M. Waldrop" Date: Tue, 23 Apr 2024 11:55:45 -0500 Subject: [PATCH 11/14] docstring fix --- src/python/friendzone/nwx2qcengine/call_qcengine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/python/friendzone/nwx2qcengine/call_qcengine.py b/src/python/friendzone/nwx2qcengine/call_qcengine.py index a1349f3..aa86d08 100644 --- a/src/python/friendzone/nwx2qcengine/call_qcengine.py +++ b/src/python/friendzone/nwx2qcengine/call_qcengine.py @@ -46,7 +46,7 @@ def call_qcengine(pt, mol, program, **kwargs): to module instances, whereas QCEngine requires strings). It is the responsibility of the module wrapping the call to ``call_qcengine`` to pass these additional inputs in as kwargs that can be forwarded to a - QCElemental.models.AtomicInput object via the ``model`` keyword. + QCElemental.models.AtomicInput object. :param pt: The property type we are computing. :type pt: pluginplay.PropertyType From 9107e89a1ba2adc876226ca3883c11f4283ccb98 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 23 Apr 2024 16:59:38 +0000 Subject: [PATCH 12/14] Committing clang-format changes --- src/python/friendzone/nwx2qcengine/chemical_system2qc_mol.py | 5 ++++- tests/python/unit_tests/nwx2nwchem/test_nwchem.py | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/python/friendzone/nwx2qcengine/chemical_system2qc_mol.py b/src/python/friendzone/nwx2qcengine/chemical_system2qc_mol.py index 0ebffc4..1b02976 100644 --- a/src/python/friendzone/nwx2qcengine/chemical_system2qc_mol.py +++ b/src/python/friendzone/nwx2qcengine/chemical_system2qc_mol.py @@ -43,4 +43,7 @@ def chemical_system2qc_mol(chem_sys): z = str(atom_i.z * au2ang) out += symbol + " " + x + " " + y + " " + z + "\n" # Fixing CoM and orientation and turning off symmetry to prevent molecular translation - return qcel.models.Molecule.from_data(out, fix_com=True, fix_orientation=True, fix_symmetry="C1") + return qcel.models.Molecule.from_data(out, + fix_com=True, + fix_orientation=True, + fix_symmetry="C1") diff --git a/tests/python/unit_tests/nwx2nwchem/test_nwchem.py b/tests/python/unit_tests/nwx2nwchem/test_nwchem.py index 75ca953..ee3b5b8 100644 --- a/tests/python/unit_tests/nwx2nwchem/test_nwchem.py +++ b/tests/python/unit_tests/nwx2nwchem/test_nwchem.py @@ -55,7 +55,8 @@ def test_scf_gradient(self): mol = make_h2() key = 'NWChem : SCF Gradient' self.mm.change_input(key, 'basis set', 'sto-3g') - grad = self.mm.run_as(EnergyNuclearGradientStdVectorD(), key, mol, PointSetD()) + grad = self.mm.run_as(EnergyNuclearGradientStdVectorD(), key, mol, + PointSetD()) corr = [0.0, 0.0, -0.11827177600466043, 0.0, 0.0, 0.11827177600466043] for g, c in zip(grad, corr): self.assertAlmostEqual(g, c, places=4) From 7a6b0ded7d3f2f16cd076069bb90e1d70ed91866 Mon Sep 17 00:00:00 2001 From: Kazuumi Fujioka Date: Fri, 26 Apr 2024 16:45:32 +0000 Subject: [PATCH 13/14] Kazuumi's change to add a module that does the energy AND gradient in a single calculation --- src/python/friendzone/nwx2nwchem/__init__.py | 59 ++++++++++++++++--- .../friendzone/nwx2qcengine/call_qcengine.py | 11 ++-- .../nwx2qcengine/chemical_system2qc_mol.py | 5 +- 3 files changed, 59 insertions(+), 16 deletions(-) diff --git a/src/python/friendzone/nwx2nwchem/__init__.py b/src/python/friendzone/nwx2nwchem/__init__.py index 08e3eff..4d2661f 100644 --- a/src/python/friendzone/nwx2nwchem/__init__.py +++ b/src/python/friendzone/nwx2nwchem/__init__.py @@ -28,6 +28,7 @@ def __init__(self): self.add_input('method') self.add_input("basis set") self.add_input("keywords").set_default({}) + self.add_input("MPI config").set_default(None) # Kazuumi addition def run_(self, inputs, submods): pt = TotalEnergy() @@ -35,9 +36,10 @@ def run_(self, inputs, submods): method = inputs['method'].value() basis = inputs['basis set'].value() keywords = inputs['keywords'].value() + MPIconfig = inputs['MPI config'].value() # Kazuumi addition model = {"method": method, "basis": basis} - e = call_qcengine(pt, mol, 'nwchem', model=model, keywords=keywords) + e = call_qcengine(pt, mol, 'nwchem', MPIconfig, model=model, keywords=keywords) # Kazuumi addition rv = self.results() return pt.wrap_results(rv, e) @@ -51,19 +53,50 @@ def __init__(self): self.add_input('method') self.add_input("basis set") self.add_input("keywords").set_default({}) + self.add_input("MPI config").set_default(None) # Kazuumi addition def run_(self, inputs, submods): pt = EnergyNuclearGradientStdVectorD() - mol, arg = pt.unwrap_inputs(inputs) +# mol, = pt.unwrap_inputs(inputs) # old version + mol,pointset1 = pt.unwrap_inputs(inputs) # new version method = inputs['method'].value() basis = inputs['basis set'].value() keywords = inputs['keywords'].value() + MPIconfig = inputs['MPI config'].value() # Kazuumi addition model = {"method": method, "basis": basis} - e = call_qcengine(pt, mol, 'nwchem', model=model, keywords=keywords) - e = [c for cs in e for c in cs] # Flatten out the list of lists + e, f = call_qcengine(pt, mol, 'nwchem', MPIconfig, model=model, keywords=keywords) # Kazuumi addition + f = [c for cs in f for c in cs] # Flatten out the list of lists rv = self.results() - return pt.wrap_results(rv, e) + return pt.wrap_results(rv, f) + + +class NWChemEnergyAndGradientViaMolSSI(pp.ModuleBase): + + def __init__(self): + pp.ModuleBase.__init__(self) + self.satisfies_property_type(EnergyNuclearGradientStdVectorD()) + self.description("Calls NWChem via MolSSI's QCEngine") + self.add_input('method') + self.add_input("basis set") + self.add_input("keywords").set_default({}) + self.add_input("MPI config").set_default(None) # Kazuumi addition + + def run_(self, inputs, submods): + pt = EnergyNuclearGradientStdVectorD() +# mol, = pt.unwrap_inputs(inputs) # old version + mol,pointset1 = pt.unwrap_inputs(inputs) # new version + method = inputs['method'].value() + basis = inputs['basis set'].value() + keywords = inputs['keywords'].value() + MPIconfig = inputs['MPI config'].value() # Kazuumi addition + + model = {"method": method, "basis": basis} + e, f = call_qcengine(pt, mol, 'nwchem', MPIconfig, model=model, keywords=keywords) # Kazuumi addition + combined_ef = [c for cs in f for c in cs] # Flatten out the list of lists + combined_ef.append(e) + rv = self.results() + return pt.wrap_results(rv, combined_ef) def load_nwchem_modules(mm): @@ -73,18 +106,28 @@ def load_nwchem_modules(mm): #. NWChem : SCF #. NWChem : MP2 + #. NWChem : B3LYP #. NWChem : CCSD #. NWChem : CCSD(T) #. NWChem : SCF Gradient + #. NWChem : MP2 Gradient + #. NWChem : B3LYP Gradient :param mm: The ModuleManager that the NWChem Modules will be loaded into. :type mm: pluginplay.ModuleManager """ if is_friend_enabled('nwchem'): - for method in ['SCF', 'MP2', 'CCSD', 'CCSD(T)']: + for method in ['SCF', 'MP2', 'B3LYP', 'CCSD', 'CCSD(T)']: mod_key = 'NWChem : ' + method mm.add_module(mod_key, NWChemViaMolSSI()) mm.change_input(mod_key, 'method', method) - mm.add_module('NWChem : SCF Gradient', NWChemGradientViaMolSSI()) - mm.change_input('NWChem : SCF Gradient', 'method', 'SCF') + for method in ['SCF', 'MP2', 'B3LYP']: + mod_key = 'NWChem : ' + method + ' Gradient' + mm.add_module(mod_key, NWChemGradientViaMolSSI()) + mm.change_input(mod_key, 'method', method) + + for method in ['SCF', 'MP2', 'B3LYP']: + mod_key = 'NWChem : ' + method + ' EnergyAndGradient' + mm.add_module(mod_key, NWChemEnergyAndGradientViaMolSSI()) + mm.change_input(mod_key, 'method', method) diff --git a/src/python/friendzone/nwx2qcengine/call_qcengine.py b/src/python/friendzone/nwx2qcengine/call_qcengine.py index aa86d08..dd2af57 100644 --- a/src/python/friendzone/nwx2qcengine/call_qcengine.py +++ b/src/python/friendzone/nwx2qcengine/call_qcengine.py @@ -18,7 +18,7 @@ from .pt2driver import pt2driver -def call_qcengine(pt, mol, program, **kwargs): +def call_qcengine(pt, mol, program, MPIconfig, **kwargs): """ Wraps calling a program through the QCEngine API. .. note:: @@ -46,7 +46,7 @@ def call_qcengine(pt, mol, program, **kwargs): to module instances, whereas QCEngine requires strings). It is the responsibility of the module wrapping the call to ``call_qcengine`` to pass these additional inputs in as kwargs that can be forwarded to a - QCElemental.models.AtomicInput object. + QCElemental.models.AtomicInput object via the ``model`` keyword. :param pt: The property type we are computing. :type pt: pluginplay.PropertyType @@ -65,5 +65,8 @@ def call_qcengine(pt, mol, program, **kwargs): driver = pt2driver(pt) qc_mol = chemical_system2qc_mol(mol) inp = qcel.models.AtomicInput(molecule=qc_mol, driver=driver, **kwargs) - results = qcng.compute(inp, program) - return results.return_result + results = qcng.compute(inp, program, task_config=MPIconfig) + if (driver == "gradient" and "qcvars" in results.extras): + return float(results.extras["qcvars"]["CURRENT ENERGY"]), results.return_result + else: + return results.return_result diff --git a/src/python/friendzone/nwx2qcengine/chemical_system2qc_mol.py b/src/python/friendzone/nwx2qcengine/chemical_system2qc_mol.py index 1b02976..0ebffc4 100644 --- a/src/python/friendzone/nwx2qcengine/chemical_system2qc_mol.py +++ b/src/python/friendzone/nwx2qcengine/chemical_system2qc_mol.py @@ -43,7 +43,4 @@ def chemical_system2qc_mol(chem_sys): z = str(atom_i.z * au2ang) out += symbol + " " + x + " " + y + " " + z + "\n" # Fixing CoM and orientation and turning off symmetry to prevent molecular translation - return qcel.models.Molecule.from_data(out, - fix_com=True, - fix_orientation=True, - fix_symmetry="C1") + return qcel.models.Molecule.from_data(out, fix_com=True, fix_orientation=True, fix_symmetry="C1") From a8b0de82c6f84f132bb9c6e9f4e9c2da82615dd1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 26 Apr 2024 16:58:15 +0000 Subject: [PATCH 14/14] Committing clang-format changes --- src/python/friendzone/nwx2nwchem/__init__.py | 44 +++++++++++++------ .../friendzone/nwx2qcengine/call_qcengine.py | 3 +- .../nwx2qcengine/chemical_system2qc_mol.py | 5 ++- 3 files changed, 36 insertions(+), 16 deletions(-) diff --git a/src/python/friendzone/nwx2nwchem/__init__.py b/src/python/friendzone/nwx2nwchem/__init__.py index 4d2661f..59b33b2 100644 --- a/src/python/friendzone/nwx2nwchem/__init__.py +++ b/src/python/friendzone/nwx2nwchem/__init__.py @@ -28,7 +28,7 @@ def __init__(self): self.add_input('method') self.add_input("basis set") self.add_input("keywords").set_default({}) - self.add_input("MPI config").set_default(None) # Kazuumi addition + self.add_input("MPI config").set_default(None) # Kazuumi addition def run_(self, inputs, submods): pt = TotalEnergy() @@ -36,10 +36,15 @@ def run_(self, inputs, submods): method = inputs['method'].value() basis = inputs['basis set'].value() keywords = inputs['keywords'].value() - MPIconfig = inputs['MPI config'].value() # Kazuumi addition + MPIconfig = inputs['MPI config'].value() # Kazuumi addition model = {"method": method, "basis": basis} - e = call_qcengine(pt, mol, 'nwchem', MPIconfig, model=model, keywords=keywords) # Kazuumi addition + e = call_qcengine(pt, + mol, + 'nwchem', + MPIconfig, + model=model, + keywords=keywords) # Kazuumi addition rv = self.results() return pt.wrap_results(rv, e) @@ -53,19 +58,24 @@ def __init__(self): self.add_input('method') self.add_input("basis set") self.add_input("keywords").set_default({}) - self.add_input("MPI config").set_default(None) # Kazuumi addition + self.add_input("MPI config").set_default(None) # Kazuumi addition def run_(self, inputs, submods): pt = EnergyNuclearGradientStdVectorD() -# mol, = pt.unwrap_inputs(inputs) # old version - mol,pointset1 = pt.unwrap_inputs(inputs) # new version + # mol, = pt.unwrap_inputs(inputs) # old version + mol, pointset1 = pt.unwrap_inputs(inputs) # new version method = inputs['method'].value() basis = inputs['basis set'].value() keywords = inputs['keywords'].value() - MPIconfig = inputs['MPI config'].value() # Kazuumi addition + MPIconfig = inputs['MPI config'].value() # Kazuumi addition model = {"method": method, "basis": basis} - e, f = call_qcengine(pt, mol, 'nwchem', MPIconfig, model=model, keywords=keywords) # Kazuumi addition + e, f = call_qcengine(pt, + mol, + 'nwchem', + MPIconfig, + model=model, + keywords=keywords) # Kazuumi addition f = [c for cs in f for c in cs] # Flatten out the list of lists rv = self.results() return pt.wrap_results(rv, f) @@ -80,20 +90,26 @@ def __init__(self): self.add_input('method') self.add_input("basis set") self.add_input("keywords").set_default({}) - self.add_input("MPI config").set_default(None) # Kazuumi addition + self.add_input("MPI config").set_default(None) # Kazuumi addition def run_(self, inputs, submods): pt = EnergyNuclearGradientStdVectorD() -# mol, = pt.unwrap_inputs(inputs) # old version - mol,pointset1 = pt.unwrap_inputs(inputs) # new version + # mol, = pt.unwrap_inputs(inputs) # old version + mol, pointset1 = pt.unwrap_inputs(inputs) # new version method = inputs['method'].value() basis = inputs['basis set'].value() keywords = inputs['keywords'].value() - MPIconfig = inputs['MPI config'].value() # Kazuumi addition + MPIconfig = inputs['MPI config'].value() # Kazuumi addition model = {"method": method, "basis": basis} - e, f = call_qcengine(pt, mol, 'nwchem', MPIconfig, model=model, keywords=keywords) # Kazuumi addition - combined_ef = [c for cs in f for c in cs] # Flatten out the list of lists + e, f = call_qcengine(pt, + mol, + 'nwchem', + MPIconfig, + model=model, + keywords=keywords) # Kazuumi addition + combined_ef = [c for cs in f + for c in cs] # Flatten out the list of lists combined_ef.append(e) rv = self.results() return pt.wrap_results(rv, combined_ef) diff --git a/src/python/friendzone/nwx2qcengine/call_qcengine.py b/src/python/friendzone/nwx2qcengine/call_qcengine.py index dd2af57..198c7d4 100644 --- a/src/python/friendzone/nwx2qcengine/call_qcengine.py +++ b/src/python/friendzone/nwx2qcengine/call_qcengine.py @@ -67,6 +67,7 @@ def call_qcengine(pt, mol, program, MPIconfig, **kwargs): inp = qcel.models.AtomicInput(molecule=qc_mol, driver=driver, **kwargs) results = qcng.compute(inp, program, task_config=MPIconfig) if (driver == "gradient" and "qcvars" in results.extras): - return float(results.extras["qcvars"]["CURRENT ENERGY"]), results.return_result + return float( + results.extras["qcvars"]["CURRENT ENERGY"]), results.return_result else: return results.return_result diff --git a/src/python/friendzone/nwx2qcengine/chemical_system2qc_mol.py b/src/python/friendzone/nwx2qcengine/chemical_system2qc_mol.py index 0ebffc4..1b02976 100644 --- a/src/python/friendzone/nwx2qcengine/chemical_system2qc_mol.py +++ b/src/python/friendzone/nwx2qcengine/chemical_system2qc_mol.py @@ -43,4 +43,7 @@ def chemical_system2qc_mol(chem_sys): z = str(atom_i.z * au2ang) out += symbol + " " + x + " " + y + " " + z + "\n" # Fixing CoM and orientation and turning off symmetry to prevent molecular translation - return qcel.models.Molecule.from_data(out, fix_com=True, fix_orientation=True, fix_symmetry="C1") + return qcel.models.Molecule.from_data(out, + fix_com=True, + fix_orientation=True, + fix_symmetry="C1")