From 6dc86c10ab49a1881daa76ecb0a5cb2e20474a51 Mon Sep 17 00:00:00 2001 From: "Ryan M. Richard" Date: Wed, 14 Oct 2026 22:14:35 -0500 Subject: [PATCH 1/2] conversion to module looks good --- cxx/include/integrals/integrals_mm.hpp | 13 ++-- .../integrals/ao_integrals/ao_integrals.hpp | 58 +++++++++--------- cxx/src/integrals/export_integrals.cpp | 5 +- cxx/src/integrals/integrals_mm.cpp | 40 ++++++------- cxx/src/integrals/libint/libint.cpp | 46 ++++++++------- cxx/src/integrals/libint/libint.hpp | 15 ++--- cxx/src/integrals/utils/utils.hpp | 12 ++-- examples/primitive_error_models/main.cpp | 3 +- .../test_uq_atom_symm_blocked_driver.cpp | 3 +- .../integrals/ao_integrals/test_uq_driver.cpp | 3 +- .../cxx/unit/integrals/test_integrals_mm.cpp | 59 +++++++++++++++++++ tests/cxx/unit/integrals/testing/testing.hpp | 3 +- .../unit/integrals/utils/rank2_shell_norm.cpp | 3 +- tests/python/unit_tests/test_plugin.py | 29 +++++++++ .../utils/test_decontract_basis_set.py | 2 +- 15 files changed, 184 insertions(+), 110 deletions(-) create mode 100644 tests/cxx/unit/integrals/test_integrals_mm.cpp create mode 100644 tests/python/unit_tests/test_plugin.py diff --git a/cxx/include/integrals/integrals_mm.hpp b/cxx/include/integrals/integrals_mm.hpp index 28c6ae9a..1c8d0bad 100644 --- a/cxx/include/integrals/integrals_mm.hpp +++ b/cxx/include/integrals/integrals_mm.hpp @@ -19,14 +19,13 @@ namespace integrals { -/** @brief Load this plugin's modules into a Module Manager +/** @brief The Integrals plugin. * - * @param mm The Module Manager to load the modules into - * - * @throw none No throw guarantee + * Load it into a ModuleManager with `mm.load_plugin()` + * (`mm.load_plugin(integrals.Integrals())` from Python). The plugin's name is + * "integrals". All of the plugin's default submodules are provided by the + * plugin itself, so it does not need other plugins to be loaded. */ -DECLARE_PLUGIN(integrals); - -void set_defaults(pluginplay::ModuleManager&); +DECLARE_PLUGIN(Integrals); } // end namespace integrals diff --git a/cxx/src/integrals/ao_integrals/ao_integrals.hpp b/cxx/src/integrals/ao_integrals/ao_integrals.hpp index eb8ae3ff..c996ad5f 100644 --- a/cxx/src/integrals/ao_integrals/ao_integrals.hpp +++ b/cxx/src/integrals/ao_integrals/ao_integrals.hpp @@ -30,37 +30,37 @@ DECLARE_MODULE(UQDriver); DECLARE_MODULE(UQAtomSymmBlockedDriver); DECLARE_MODULE(UQInitializer); -inline void set_defaults(pluginplay::ModuleManager& mm) { - mm.change_submod("AO integral driver", "Coulomb matrix", - "Four center J builder"); - mm.change_submod("AO integral driver", "Exchange matrix", - "Four center K builder"); - mm.change_submod("Density Fitted J builder", "DF ERI", - "Density Fitting Integral"); - mm.change_submod("Density Fitted K builder", "DF ERI", - "Density Fitting Integral"); - mm.change_submod("Density Fitting Integral", "Coulomb Metric", - "Coulomb Metric"); - mm.change_submod("UQ Driver", "ERIs", "ERI4"); - mm.change_submod("UQ Driver", "ERI Error", "Primitive Error Model"); - mm.change_submod("UQ Atom Symm Blocked Driver", "ERIs", "ERI4"); - mm.change_submod("UQ Atom Symm Blocked Driver", "ERI Error", - "Primitive Error Model"); - mm.change_submod("UQ Atom Symm Blocked Driver", "UQ Initializer", - "UQ Initializer"); +inline void set_defaults(pluginplay::ModuleMap& modules) { + modules.change_submod("AO integral driver", "Coulomb matrix", + "Four center J builder"); + modules.change_submod("AO integral driver", "Exchange matrix", + "Four center K builder"); + modules.change_submod("Density Fitted J builder", "DF ERI", + "Density Fitting Integral"); + modules.change_submod("Density Fitted K builder", "DF ERI", + "Density Fitting Integral"); + modules.change_submod("Density Fitting Integral", "Coulomb Metric", + "Coulomb Metric"); + modules.change_submod("UQ Driver", "ERIs", "ERI4"); + modules.change_submod("UQ Driver", "ERI Error", "Primitive Error Model"); + modules.change_submod("UQ Atom Symm Blocked Driver", "ERIs", "ERI4"); + modules.change_submod("UQ Atom Symm Blocked Driver", "ERI Error", + "Primitive Error Model"); + modules.change_submod("UQ Atom Symm Blocked Driver", "UQ Initializer", + "UQ Initializer"); } -inline void load_modules(pluginplay::ModuleManager& mm) { - mm.add_module("AO integral driver"); - mm.add_module("Four center J builder"); - mm.add_module("Four center K builder"); - mm.add_module("Density Fitted J builder"); - mm.add_module("Density Fitted K builder"); - mm.add_module("Density Fitting Integral"); - mm.add_module("Coulomb Metric"); - mm.add_module("UQ Driver"); - mm.add_module("UQ Atom Symm Blocked Driver"); - mm.add_module("UQ Initializer"); +inline void load_modules(pluginplay::ModuleMap& modules) { + modules.add_module("AO integral driver"); + modules.add_module("Four center J builder"); + modules.add_module("Four center K builder"); + modules.add_module("Density Fitted J builder"); + modules.add_module("Density Fitted K builder"); + modules.add_module("Density Fitting Integral"); + modules.add_module("Coulomb Metric"); + modules.add_module("UQ Driver"); + modules.add_module("UQ Atom Symm Blocked Driver"); + modules.add_module("UQ Initializer"); } } // namespace integrals::ao_integrals diff --git a/cxx/src/integrals/export_integrals.cpp b/cxx/src/integrals/export_integrals.cpp index 552450b8..862d354e 100644 --- a/cxx/src/integrals/export_integrals.cpp +++ b/cxx/src/integrals/export_integrals.cpp @@ -21,9 +21,6 @@ namespace integrals { -EXPORT_PLUGIN(integrals, m) { - export_property_types(m); - m.def("set_defaults", &set_defaults); -} +EXPORT_PLUGIN(integrals, Integrals, m) { export_property_types(m); } } // namespace integrals diff --git a/cxx/src/integrals/integrals_mm.cpp b/cxx/src/integrals/integrals_mm.cpp index 9ec4deb1..93c106bd 100644 --- a/cxx/src/integrals/integrals_mm.cpp +++ b/cxx/src/integrals/integrals_mm.cpp @@ -21,29 +21,25 @@ namespace integrals { -/** @brief Set default module relationships - * - * @param mm The Module Manager with modules whose defaults will be set - * - * @throw none No throw guarantee - */ -void set_defaults(pluginplay::ModuleManager& mm) { - libint::set_defaults(mm); - ao_integrals::set_defaults(mm); - utils::set_defaults(mm); - mm.change_submod("AO integral driver", "Kinetic", "Kinetic"); - mm.change_submod("AO integral driver", "Electron-Nuclear attraction", - "Nuclear"); - mm.change_submod("Four center J builder", "Four-center ERI", "ERI4"); - mm.change_submod("Four center K builder", "Four-center ERI", "ERI4"); - mm.change_submod("Density Fitting Integral", "Three-center ERI", "ERI3"); - mm.change_submod("Coulomb Metric", "Two-center ERI", "ERI2"); -} +PLUGIN_CTOR(Integrals) { + set_name("integrals"); + + // The defaults refer to modules from more than one subdirectory, so all + // modules are added before any defaults are set + ao_integrals::load_modules(modules()); + libint::load_modules(modules()); + utils::load_modules(modules()); -void load_modules(pluginplay::ModuleManager& mm) { - ao_integrals::load_modules(mm); - libint::load_modules(mm); - utils::load_modules(mm); + libint::set_defaults(modules()); + ao_integrals::set_defaults(modules()); + utils::set_defaults(modules()); + change_submod("AO integral driver", "Kinetic", "Kinetic"); + change_submod("AO integral driver", "Electron-Nuclear attraction", + "Nuclear"); + change_submod("Four center J builder", "Four-center ERI", "ERI4"); + change_submod("Four center K builder", "Four-center ERI", "ERI4"); + change_submod("Density Fitting Integral", "Three-center ERI", "ERI3"); + change_submod("Coulomb Metric", "Two-center ERI", "ERI2"); } } // namespace integrals diff --git a/cxx/src/integrals/libint/libint.cpp b/cxx/src/integrals/libint/libint.cpp index 2b9a27c2..3a9ebaaf 100644 --- a/cxx/src/integrals/libint/libint.cpp +++ b/cxx/src/integrals/libint/libint.cpp @@ -93,24 +93,25 @@ EXTERN_LIBINT(aos_squared, v_ee_type, aos_squared); #undef EXTERN_LIBINT -void set_defaults(pluginplay::ModuleManager& mm) { - mm.change_submod("CauchySchwarz Estimator", "Decontract Basis Set", - "Decontract Basis Set"); - mm.copy_module("ERI4", "Benchmark ERI4"); - mm.change_input("Benchmark ERI4", "Threshold", 1.0E-16); - mm.change_submod("CauchySchwarz Estimator", "ERI4", "Benchmark ERI4"); - mm.change_submod("Analytic Error", "ERI4s", "Benchmark ERI4"); - mm.change_submod("Raw Primitive ERI4", "Decontract Basis Set", - "Decontract Basis Set"); - mm.change_submod("Primitive Contractor ERI4", "Raw Primitive ERI4", - "Raw Primitive ERI4"); - mm.change_submod("Primitive Contractor ERI4", "Primitive Normalization", - "Primitive Normalization"); +void set_defaults(pluginplay::ModuleMap& modules) { + modules.change_submod("CauchySchwarz Estimator", "Decontract Basis Set", + "Decontract Basis Set"); + modules.copy_module("ERI4", "Benchmark ERI4"); + modules.change_input("Benchmark ERI4", "Threshold", 1.0E-16); + modules.change_submod("CauchySchwarz Estimator", "ERI4", "Benchmark ERI4"); + modules.change_submod("Analytic Error", "ERI4s", "Benchmark ERI4"); + modules.change_submod("Raw Primitive ERI4", "Decontract Basis Set", + "Decontract Basis Set"); + modules.change_submod("Primitive Contractor ERI4", "Raw Primitive ERI4", + "Raw Primitive ERI4"); + modules.change_submod("Primitive Contractor ERI4", + "Primitive Normalization", "Primitive Normalization"); } -#define LOAD_LIBINT(bra, op, ket, key) mm.add_module(key) +#define LOAD_LIBINT(bra, op, ket, key) \ + modules.add_module(key) -void load_modules(pluginplay::ModuleManager& mm) { +void load_modules(pluginplay::ModuleMap& modules) { LOAD_LIBINT(aos, op_base_type, aos, "Evaluate 2-Index BraKet"); LOAD_LIBINT(aos, op_base_type, aos_squared, "Evaluate 3-Index BraKet"); LOAD_LIBINT(aos_squared, op_base_type, aos_squared, @@ -121,14 +122,15 @@ void load_modules(pluginplay::ModuleManager& mm) { LOAD_LIBINT(aos, v_ee_type, aos, "ERI2"); LOAD_LIBINT(aos, v_ee_type, aos_squared, "ERI3"); LOAD_LIBINT(aos_squared, v_ee_type, aos_squared, "ERI4"); - mm.add_module( + modules.add_module( "Black Box Primitive Pair Estimator"); - mm.add_module("CauchySchwarz Estimator"); - mm.add_module("Primitive Error Model"); - mm.add_module("Analytic Error"); - mm.add_module("Raw Primitive ERI4"); - mm.add_module("Primitive Normalization"); - mm.add_module("Primitive Contractor ERI4"); + modules.add_module( + "CauchySchwarz Estimator"); + modules.add_module("Primitive Error Model"); + modules.add_module("Analytic Error"); + modules.add_module("Raw Primitive ERI4"); + modules.add_module("Primitive Normalization"); + modules.add_module("Primitive Contractor ERI4"); } #undef LOAD_LIBINT diff --git a/cxx/src/integrals/libint/libint.hpp b/cxx/src/integrals/libint/libint.hpp index ef115277..870a2cf2 100644 --- a/cxx/src/integrals/libint/libint.hpp +++ b/cxx/src/integrals/libint/libint.hpp @@ -50,21 +50,18 @@ using simde::type::t_e_type; using simde::type::v_ee_type; using simde::type::v_en_type; -/** @brief Load the libint modules into a Module Manager +/** @brief Adds the libint modules to the Integrals plugin's modules * - * @param mm The Module Manager to load the modules into - * - * @throw none No throw guarantee + * @param modules The plugin's modules to add the libint modules to */ -void load_modules(pluginplay::ModuleManager& mm); +void load_modules(pluginplay::ModuleMap& modules); /** @brief Set default module relationships * - * @param mm The Module Manager with modules whose defaults will be set - * - * @throw none No throw guarantee + * @param modules The plugin's modules, whose defaults will be set. Must + * already contain all of the plugin's modules. */ -void set_defaults(pluginplay::ModuleManager& mm); +void set_defaults(pluginplay::ModuleMap& modules); // Forward External Template Declarations #define EXTERN_LIBINT extern template struct Libint diff --git a/cxx/src/integrals/utils/utils.hpp b/cxx/src/integrals/utils/utils.hpp index f2af1a56..d1108de5 100644 --- a/cxx/src/integrals/utils/utils.hpp +++ b/cxx/src/integrals/utils/utils.hpp @@ -32,14 +32,14 @@ namespace integrals::utils { DECLARE_MODULE(DecontractBasisSet); DECLARE_MODULE(ScreenPrimitivePairs); -inline void set_defaults(pluginplay::ModuleManager& mm) { - mm.change_submod("Screen Primitive Pairs", "Primitive Pair Estimator", - "Black Box Primitive Pair Estimator"); +inline void set_defaults(pluginplay::ModuleMap& modules) { + modules.change_submod("Screen Primitive Pairs", "Primitive Pair Estimator", + "Black Box Primitive Pair Estimator"); } -inline void load_modules(pluginplay::ModuleManager& mm) { - mm.add_module("Decontract Basis Set"); - mm.add_module("Screen Primitive Pairs"); +inline void load_modules(pluginplay::ModuleMap& modules) { + modules.add_module("Decontract Basis Set"); + modules.add_module("Screen Primitive Pairs"); } } // end namespace integrals::utils diff --git a/examples/primitive_error_models/main.cpp b/examples/primitive_error_models/main.cpp index 1e6e8b18..53bfc914 100644 --- a/examples/primitive_error_models/main.cpp +++ b/examples/primitive_error_models/main.cpp @@ -66,8 +66,7 @@ int main(int argc, char* argv[]) { // Initializes a ModuleManager object with the integrals plugin pluginplay::ModuleManager mm(std::move(rt), nullptr); - integrals::load_modules(mm); - integrals::set_defaults(mm); + mm.load_plugin(); // Modules for computing analytic error and estimating error auto& analytic_error_mod = mm.at("Analytic Error"); diff --git a/tests/cxx/unit/integrals/ao_integrals/test_uq_atom_symm_blocked_driver.cpp b/tests/cxx/unit/integrals/ao_integrals/test_uq_atom_symm_blocked_driver.cpp index a83b041d..0f97bbe2 100644 --- a/tests/cxx/unit/integrals/ao_integrals/test_uq_atom_symm_blocked_driver.cpp +++ b/tests/cxx/unit/integrals/ao_integrals/test_uq_atom_symm_blocked_driver.cpp @@ -115,8 +115,7 @@ TEMPLATE_LIST_TEST_CASE("UQ Atom Symm Blocked Driver", "", uq_types) { auto rt = std::make_unique(); pluginplay::ModuleManager mm(std::move(rt)); - integrals::load_modules(mm); - integrals::set_defaults(mm); + mm.load_plugin(); REQUIRE(mm.count("UQ Atom Symm Blocked Driver")); mm.change_input("ERI4", "Threshold", 1.0e-6); auto mod = mm.at("UQ Atom Symm Blocked Driver"); diff --git a/tests/cxx/unit/integrals/ao_integrals/test_uq_driver.cpp b/tests/cxx/unit/integrals/ao_integrals/test_uq_driver.cpp index 16e81c88..20d5b968 100644 --- a/tests/cxx/unit/integrals/ao_integrals/test_uq_driver.cpp +++ b/tests/cxx/unit/integrals/ao_integrals/test_uq_driver.cpp @@ -170,8 +170,7 @@ TEMPLATE_LIST_TEST_CASE("UQ Driver", "", uq_types) { auto rt = std::make_unique(); pluginplay::ModuleManager mm(std::move(rt), nullptr); - integrals::load_modules(mm); - integrals::set_defaults(mm); + mm.load_plugin(); REQUIRE(mm.count("UQ Driver")); mm.change_input("ERI4", "Threshold", 1.0e-6); diff --git a/tests/cxx/unit/integrals/test_integrals_mm.cpp b/tests/cxx/unit/integrals/test_integrals_mm.cpp new file mode 100644 index 00000000..17500c90 --- /dev/null +++ b/tests/cxx/unit/integrals/test_integrals_mm.cpp @@ -0,0 +1,59 @@ +/* + * Copyright 2026 NWChemEx-Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "testing/testing.hpp" + +TEST_CASE("Integrals plugin") { + integrals::Integrals plugin; + const auto& modules = plugin.get_modules(); + + SECTION("Identity") { + REQUIRE(plugin.name() == "integrals"); + // Every default comes from the plugin itself + REQUIRE(plugin.preferred_providers().empty()); + } + + SECTION("Modules from each subdirectory") { + REQUIRE(modules.count("AO integral driver")); + REQUIRE(modules.count("ERI4")); + REQUIRE(modules.count("Decontract Basis Set")); + } + + SECTION("Defaults set across subdirectories") { + REQUIRE(modules.has_submod("AO integral driver", "Kinetic")); + REQUIRE(modules.has_submod("CauchySchwarz Estimator", + "Decontract Basis Set")); + REQUIRE(modules.has_submod("Screen Primitive Pairs", + "Primitive Pair Estimator")); + } + + SECTION("Benchmark ERI4 is a tighter copy of ERI4") { + const auto& inputs = modules.at("Benchmark ERI4")->inputs(); + REQUIRE(inputs.at("Threshold").value() == 1.0E-16); + const auto& submod = + modules.at("CauchySchwarz Estimator")->submods().at("ERI4"); + REQUIRE(submod.value() == *modules.at("Benchmark ERI4")); + } + + SECTION("Can be loaded into a ModuleManager") { + pluginplay::ModuleManager mm; + mm.load_plugin(); + REQUIRE(mm.has_plugin("integrals")); + REQUIRE(mm.size() == modules.size()); + REQUIRE(mm.at("AO integral driver").submods().at("Kinetic").value() == + mm.at("Kinetic")); + } +} diff --git a/tests/cxx/unit/integrals/testing/testing.hpp b/tests/cxx/unit/integrals/testing/testing.hpp index 3a208f13..6e04536c 100644 --- a/tests/cxx/unit/integrals/testing/testing.hpp +++ b/tests/cxx/unit/integrals/testing/testing.hpp @@ -43,8 +43,7 @@ namespace integrals::testing { inline auto initialize_integrals() { auto mm = pluginplay::ModuleManager(); - integrals::load_modules(mm); - integrals::set_defaults(mm); + mm.load_plugin(); return mm; } diff --git a/tests/cxx/unit/integrals/utils/rank2_shell_norm.cpp b/tests/cxx/unit/integrals/utils/rank2_shell_norm.cpp index 445eff80..cf503d3e 100644 --- a/tests/cxx/unit/integrals/utils/rank2_shell_norm.cpp +++ b/tests/cxx/unit/integrals/utils/rank2_shell_norm.cpp @@ -42,8 +42,7 @@ using tensorwrapper::buffer::make_contiguous; TEST_CASE("Rank2 Shell Norm") { pluginplay::ModuleManager mm; - integrals::load_modules(mm); - integrals::set_defaults(mm); + mm.load_plugin(); auto eri_mod = mm.at("ERI4"); diff --git a/tests/python/unit_tests/test_plugin.py b/tests/python/unit_tests/test_plugin.py new file mode 100644 index 00000000..11a8d61d --- /dev/null +++ b/tests/python/unit_tests/test_plugin.py @@ -0,0 +1,29 @@ +# +# Copyright 2026 NWChemEx-Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import unittest + +import integrals +import parallelzone as pz +import pluginplay as pp + + +class TestIntegralsPlugin(unittest.TestCase): + def test_load_plugin(self): + mm = pp.ModuleManager(pz.runtime.RuntimeView()) + mm.load_plugin(integrals.Integrals()) + self.assertTrue(mm.has_plugin("integrals")) + self.assertTrue(mm.count("ERI4")) + self.assertEqual(mm.get_plugin("integrals").preferred_providers(), []) diff --git a/tests/python/unit_tests/utils/test_decontract_basis_set.py b/tests/python/unit_tests/utils/test_decontract_basis_set.py index b4e5982a..52df860e 100644 --- a/tests/python/unit_tests/utils/test_decontract_basis_set.py +++ b/tests/python/unit_tests/utils/test_decontract_basis_set.py @@ -53,4 +53,4 @@ def test_temp(self): def setUp(self): self.mm = pp.ModuleManager(pz.runtime.RuntimeView()) - integrals.load_modules(self.mm) + self.mm.load_plugin(integrals.Integrals()) From 01fd1d7204cbb8aca0f260001962d9f3d09df0cb Mon Sep 17 00:00:00 2001 From: "Ryan M. Richard" Date: Thu, 15 Oct 2026 13:01:10 -0500 Subject: [PATCH 2/2] bump simde floor --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index f6697a7a..115ac396 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,7 +22,7 @@ requires = [ # [project].dependencies; leave the floors unbounded so the newest # release is always resolved. "nwchemex-nwxcmake>=0.1.0", - "nwchemex-simde>=0.0.77", + "nwchemex-simde>=0.0.85", ] build-backend = "scikit_build_core.build" @@ -38,7 +38,7 @@ dependencies = [ # registries and breaks cross-module type exchange. "pybind11==3.1.0", "nwchemex-nwxcmake>=0.1.0", - "nwchemex-simde>=0.0.77", + "nwchemex-simde>=0.0.85", ] [project.optional-dependencies]