diff --git a/.github/optional_modules.cmake b/.github/optional_modules.cmake new file mode 100644 index 0000000..56a3cb1 --- /dev/null +++ b/.github/optional_modules.cmake @@ -0,0 +1,2 @@ +set(INTEGRATION_TESTING FALSE) +set(BUILD_TAMM_SCF TRUE) \ No newline at end of file diff --git a/.github/workflows/pull_request.yaml b/.github/workflows/pull_request.yaml index 9e66ae4..a66eb79 100644 --- a/.github/workflows/pull_request.yaml +++ b/.github/workflows/pull_request.yaml @@ -21,7 +21,7 @@ on: - master jobs: - Common-Pull-Request: + default_build: uses: NWChemEx/.github/.github/workflows/common_pull_request.yaml@master with: config_file: '.github/.licenserc.yaml' @@ -30,3 +30,13 @@ jobs: doc_target: 'scf_cxx_api' build_fail_on_warning: false secrets: inherit + optional_modules: + uses: NWChemEx/.github/.github/workflows/common_pull_request.yaml@master + with: + config_file: '.github/.licenserc.yaml' + source_dir: '' + compilers: '["gcc-11"]' + doc_target: 'scf_cxx_api' + build_fail_on_warning: false + repo_toolchain: '.github/optional_modules.cmake' + secrets: inherit diff --git a/CMakeLists.txt b/CMakeLists.txt index b09478f..4909c16 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,86 +13,41 @@ # limitations under the License. cmake_minimum_required(VERSION 3.14) -set(VERSION 1.0.0) #TODO: get from git -project(scf VERSION "${VERSION}" LANGUAGES CXX) -include(FetchContent) -enable_language(C) -FetchContent_Declare( - nwx_cmake - GIT_REPOSITORY https://github.com/NWChemEx/NWXCMake -) -FetchContent_MakeAvailable(nwx_cmake) -list(APPEND CMAKE_MODULE_PATH "${nwx_cmake_SOURCE_DIR}/cmake") - -set( - CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" "${PROJECT_SOURCE_DIR}/cmake" - CACHE STRING "" FORCE -) +# Downloads common CMake modules used throughout NWChemEx +#Sets the version to whatever git thinks it is +#include(get_version_from_git) +#get_version_from_git(scf_version "${CMAKE_CURRENT_LIST_DIR}") +project(scf VERSION "1.0.0" LANGUAGES CXX) +include(cmake/get_nwx_cmake.cmake) include(nwx_versions) include(get_cmaize) include(nwx_cxx_api_docs) set(SCF_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/src") set(SCF_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include") -nwx_cxx_api_docs("${SCF_SOURCE_DIR}" "${SCF_INCLUDE_DIR}") +set(SCF_TESTS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/tests") -set(DEPENDENCIES "") +nwx_cxx_api_docs("${SCF_SOURCE_DIR}" "${SCF_INCLUDE_DIR}") +### Options ### cmaize_option_list( BUILD_TESTING OFF "Should we build the tests?" - BUILD_PYBIND11_PYBINDINGS ON "Build pybind11 python3 bindings?" - ENABLE_EXPERIMENTAL_FEATURES OFF "Build features which are not 1.0-ed yet?" -) - -cmaize_find_or_build_dependency( - simde - URL github.com/NWChemEx/SimDE - BUILD_TARGET simde - FIND_TARGET nwx::simde - CMAKE_ARGS BUILD_TESTING=OFF - BUILD_PYBIND11_PYBINDINGS=${BUILD_PYBIND11_PYBINDINGS} + BUILD_PYBIND11_PYBINDINGS ON "Build Python bindings with pybind11?" + BUILD_TAMM_SCF OFF "Should we build modules that rely on TAMM/Exachem?" + INTEGRATION_TESTING OFF "Should we build the integration tests?" ) -list(APPEND DEPENDENCIES simde) - -cmaize_find_or_build_dependency( - gauxc - URL github.com/wavefunction91/GauXC - BUILD_TARGET gauxc - FIND_TARGET gauxc::gauxc - CMAKE_ARGS BUILD_TESTING=OFF GAUXC_ENABLE_HDF5=OFF -) -list(APPEND DEPENDENCIES gauxc) - -cmaize_find_or_build_dependency( - tamm - URL github.com/NWChemEx-Project/TAMM - VERSION main - BUILD_TARGET tamm - FIND_TARGET tamm::tamm - CMAKE_ARGS MODULES="DFT" -) -list(APPEND DEPENDENCIES tamm) - -cmaize_find_or_build_dependency( - exachem - URL github.com/ExaChem/exachem - VERSION main - BUILD_TARGET exachem - FIND_TARGET exachem::exachem - CMAKE_ARGS MODULES="DFT" -) -list(APPEND DEPENDENCIES exachem) +if("${BUILD_TAMM_SCF}") + set(DEPENDENCIES simde gauxc tamm exachem chemcache) + include(get_libint2) +else() + set(DEPENDENCIES simde gauxc) +endif() -cmaize_find_or_build_dependency( - Libint2 - URL github.com/evaleev/libint - VERSION 2.7.2 - BUILD_TARGET int2 - FIND_TARGET Libint2::int2 -) -list(APPEND DEPENDENCIES Libint2) +foreach(dependency_i ${DEPENDENCIES}) + include(get_${dependency_i}) +endforeach() cmaize_add_library( scf @@ -101,6 +56,15 @@ cmaize_add_library( DEPENDS "${DEPENDENCIES}" ) +if("${BUILD_TAMM_SCF}") + target_compile_definitions(scf PRIVATE BUILD_TAMM_SCF) + cmaize_add_executable( + scf_driver + SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/examples/driver" + DEPENDS scf Libint2 + ) +endif() + include(nwx_pybind11) nwx_add_pybind11_module( ${PROJECT_NAME} @@ -108,59 +72,39 @@ nwx_add_pybind11_module( DEPENDS "${PROJECT_NAME}" ) -cmaize_find_or_build_dependency( - chemcache - URL github.com/NWChemEx/ChemCache - BUILD_TARGET chemcache - FIND_TARGET nwx::chemcache - CMAKE_ARGS BUILD_TESTING=OFF - BUILD_PYBIND11_PYBINDINGS=${BUILD_PYBIND11_PYBINDINGS} -) - -cmaize_add_executable( - scf_driver - SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/examples/driver" - DEPENDS scf chemcache -) - if("${BUILD_TESTING}") include(CTest) - set(PYTHON_TEST_DIR "${CMAKE_CURRENT_LIST_DIR}/tests/python") - set(CXX_TEST_DIR "${CMAKE_CURRENT_LIST_DIR}/tests/cxx") - - # Need to call with MPI, so we have to deconstruct the cmaize_add_test and - # nwx_pybind11_tests methods - cmaize_find_or_build_dependency( - Catch2 - URL github.com/catchorg/Catch2 - BUILD_TARGET Catch2 - FIND_TARGET Catch2::Catch2 - VERSION v3.6.0 - ) - cmaize_add_executable( - test_scf - SOURCE_DIR "${CXX_TEST_DIR}" + set(PYTHON_TEST_DIR "${SCF_TESTS_DIR}/python") + set(CXX_TEST_DIR "${SCF_TESTS_DIR}/cxx") + + include(get_catch2) + include(cmake/mpi_test.cmake) + cxx_mpi_test( + unit_test_scf + SOURCE_DIR "${CXX_TEST_DIR}/unit_tests" INCLUDE_DIRS "${CMAKE_CURRENT_LIST_DIR}/src/scf" - DEPENDS Catch2 scf chemcache + DEPENDS Catch2 scf ) - add_test( - NAME "test_scf" - COMMAND "${MPIEXEC_EXECUTABLE}" "${MPIEXEC_NUMPROC_FLAG}" "2" - "${CMAKE_BINARY_DIR}/test_scf" + python_mpi_test( + unit_test_scf + "${PYTHON_TEST_DIR}/unit_tests/run_unit_tests.py" + SUBMODULES simde chemist pluginplay parallelzone ) - add_test( - NAME py_test_unit_${PROJECT_NAME} - COMMAND "${MPIEXEC_EXECUTABLE}" "${MPIEXEC_NUMPROC_FLAG}" "2" - "${Python_EXECUTABLE}" - "${PYTHON_TEST_DIR}/unit_tests/test_scf.py" - ) - nwx_python_path( - TEST_PYTHONPATH - SUBMODULES chemcache simde chemist pluginplay parallelzone - ) - set_tests_properties( - py_test_unit_${PROJECT_NAME} - PROPERTIES ENVIRONMENT "${TEST_PYTHONPATH}" - ) + if("${INTEGRATION_TESTING}") + include(get_nwchemex) + cxx_mpi_test( + integration_test_scf + SOURCE_DIR "${CXX_TEST_DIR}/integration_tests" + INCLUDE_DIRS "${CMAKE_CURRENT_LIST_DIR}/src/scf" + DEPENDS Catch2 nwchemex scf + ) + + python_mpi_test( + integration_test_scf + "${PYTHON_TEST_DIR}/integration_tests/run_integration_tests.py" + SUBMODULES nwchemex chemcache simde chemist pluginplay parallelzone + friendzone + ) + endif() endif() diff --git a/cmake/get_nwx_cmake.cmake b/cmake/get_nwx_cmake.cmake new file mode 100644 index 0000000..2aec0e7 --- /dev/null +++ b/cmake/get_nwx_cmake.cmake @@ -0,0 +1,31 @@ +# Copyright 2024 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_guard() + +macro(get_nwx_cmake) + include(FetchContent) + FetchContent_Declare( + nwx_cmake + GIT_REPOSITORY https://github.com/NWChemEx/NWXCMake + ) + FetchContent_MakeAvailable(nwx_cmake) + set( + CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" "${nwx_cmake_SOURCE_DIR}/cmake" + CACHE STRING "" + FORCE + ) +endmacro() + +get_nwx_cmake() \ No newline at end of file diff --git a/cmake/mpi_test.cmake b/cmake/mpi_test.cmake new file mode 100644 index 0000000..619c13b --- /dev/null +++ b/cmake/mpi_test.cmake @@ -0,0 +1,38 @@ +# Copyright 2024 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. + +macro(cxx_mpi_test test_name) + # Need to call with MPI, so we have to deconstruct the cmaize_add_test and + # nwx_pybind11_tests methods + cmaize_add_executable("${test_name}" ${ARGN}) + add_test( + NAME "${test_name}" + COMMAND "${MPIEXEC_EXECUTABLE}" "${MPIEXEC_NUMPROC_FLAG}" "2" + "${CMAKE_BINARY_DIR}/${test_name}" + ) +endmacro() + +macro(python_mpi_test test_name test_script) + add_test( + NAME "py_${test_name}" + COMMAND "${MPIEXEC_EXECUTABLE}" "${MPIEXEC_NUMPROC_FLAG}" "2" + "${Python_EXECUTABLE}" + "${test_script}" + ) + nwx_python_path(TEST_PYTHONPATH ${ARGN}) + set_tests_properties( + "py_${test_name}" + PROPERTIES ENVIRONMENT "${TEST_PYTHONPATH}" + ) +endmacro() \ No newline at end of file diff --git a/include/scf/scf.hpp b/include/scf/scf.hpp index e7d54bb..ef9bb70 100644 --- a/include/scf/scf.hpp +++ b/include/scf/scf.hpp @@ -15,6 +15,25 @@ */ #pragma once -#include "scf/scf_mm.hpp" +#include #include +#ifdef BUILD_TAMM_SCF +#include +#endif +namespace scf { + +inline auto initialize(int argc, char *argv[]) { +#ifdef BUILD_TAMM_SCF + tamm::initialize(argc, argv); +#endif + return parallelzone::runtime::RuntimeView(argc, argv); +} + +inline auto finalize() { +#ifdef BUILD_TAMM_SCF + tamm::finalize(); +#endif +} + +} // namespace scf \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..9bf8cb8 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,6 @@ +# This file is a hack to get CI/CD to work. These packages are needed by +# FriendZone NOT this repo. +pydantic>=1.10.13 +qcengine +networkx +ase \ No newline at end of file diff --git a/src/python/export_fastscf.cpp b/src/python/export_scf.cpp similarity index 59% rename from src/python/export_fastscf.cpp rename to src/python/export_scf.cpp index 0ef190e..92d2293 100644 --- a/src/python/export_fastscf.cpp +++ b/src/python/export_scf.cpp @@ -14,29 +14,27 @@ * limitations under the License. */ -#include #include #include -#include +#include namespace scf { EXPORT_PLUGIN(scf, m) { - m.def("tamm_initialize", [](pybind11::list py_args) { - std::vector args; - for (const auto& arg : py_args) - args.push_back(arg.cast()); + pybind11::module::import("parallelzone"); + m.def("initialize", [](pybind11::list py_args) { + std::vector args; + for (const auto &arg : py_args) + args.push_back(arg.cast()); - std::vector argv; - for (const auto& arg : args) - argv.push_back(const_cast(arg.c_str())); + std::vector argv; + for (const auto &arg : args) + argv.push_back(const_cast(arg.c_str())); - int argc = static_cast(argv.size()); - tamm::initialize(argc, argv.data()); - }); - m.def("tamm_finalize", []() { - tamm::finalize(); - }); + int argc = static_cast(argv.size()); + return scf::initialize(argc, argv.data()); + }); + m.def("finalize", []() { scf::finalize(); }); } } // namespace scf diff --git a/src/scf/scf.cpp b/src/scf/scf.cpp deleted file mode 100644 index d32acd0..0000000 --- a/src/scf/scf.cpp +++ /dev/null @@ -1,247 +0,0 @@ -/* - * Copyright 2024 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 "scf_modules.hpp" -#include -#include -#include "exachem/common/chemenv.hpp" -#include "exachem/scf/scf_main.hpp" -#include "exachem/common/initialize_system_data.hpp" - -namespace scf { - -using energy_pt = simde::AOEnergy; - - -inline libint2::BasisSet make_libint_basis(const simde::type::ao_basis_set& bs) { - /// Typedefs for everything - using atom_t = libint2::Atom; - using shell_t = libint2::Shell; - using basis_t = libint2::BasisSet; - using cont_t = libint2::Shell::Contraction; - using svec_d_t = libint2::svector; - using conts_t = libint2::svector; - using centers_t = std::vector; - using atom_bases_t = std::vector; - using element_bases_t = std::vector; - - /// Inputs for BasisSet constructor - centers_t centers{}; - element_bases_t element_bases{}; - - /// Atom doesn't have a value ctor, so here's a stand in - auto atom_ctor = [](int Z, double x, double y, double z) { - atom_t atom{}; - atom.atomic_number = Z; - atom.x = x; - atom.y = y; - atom.z = z; - return atom; - }; - - /// Origin for shell construction - std::array origin = {0.0, 0.0, 0.0}; - - /// Convert centers and their shells to libint equivalents. - for(auto abs_i = 0; abs_i < bs.size(); ++abs_i) { - /// Add current center to atoms list - const auto& abs = bs[abs_i]; - centers.push_back(atom_ctor(abs_i, abs.center().x(), abs.center().y(), abs.center().z())); - - /// Gather shells for this center and add them to element_bases - atom_bases_t atom_bases{}; - for(const auto&& shelli: abs) { - const auto nprims = shelli.n_primitives(); - const auto prim0 = shelli.primitive(0); - const auto primN = shelli.primitive(nprims - 1); - const bool pure = shelli.pure() == chemist::ShellType::pure; - const int l = shelli.l(); - - svec_d_t alphas(&prim0.exponent(), &primN.exponent() + 1); - svec_d_t coefs(&prim0.coefficient(), &primN.coefficient() + 1); - conts_t conts{cont_t{l, pure, coefs}}; - /// Use origin for position, because BasisSet moves shells to center - atom_bases.push_back(shell_t(alphas, conts, origin)); - } - element_bases.push_back(atom_bases); - } - - /// Return the new basis set - return basis_t(centers, element_bases); -} - -MODULE_CTOR(SCFEnergy) { - satisfies_property_type(); - - add_input("molecule_name").set_description("The name of the molecule"); - add_input("units").set_default("angstrom").set_description("Specifies the units as bohr or angstrom"); - - add_input("charge").set_default(0).set_description("Charge"); - add_input("multiplicity").set_default(1).set_description("number of singly occupied orbitals for a particular calculation"); - add_input("lshift").set_default(0.0).set_description("level shift factor denoting the amount of shift applied to the diagonal elements of the unoccupied block of the Fock matrix"); - - add_input("tol_int").set_default(1e-22).set_description("integral primitive screening threshold"); - - add_input("tol_sch").set_default(1.0e-10).set_description( - "The Schwarz inequality is used to screen the product of integrals and density matrices"); - - add_input("tol_lindep").set_default(1e-5).set_description("Tolerance for detecting the linear dependence of basis set"); - - add_input("conve").set_default(1e-8).set_description("Specifies the energy convergence threshold"); - add_input("convd").set_default(1e-6).set_description("Specifies the density convergence threshold"); - - add_input("diis_hist").set_default(10).set_description("number of DIIS history entries to store for the fock and error matrices"); - - add_input("damp").set_default(100).set_description("percentage of the current iterations density mixed with the previous iterations density. 100\% indicates no damping"); - - add_input("writem").set_default(1).set_description("An integer specifying the frequency (as number of iterations) after which the movecs and density matrices are written to disk for restarting the calculation"); - - add_input("debug").set_default(false).set_description("enable verbose printing for debugging a calculation"); - - add_input("restart").set_default(false).set_description("indicates the calculation be restarted"); - add_input("noscf").set_default(false).set_description("computes only the SCF energy upon restart"); - - add_input("scf_type").set_default("restricted").set_description("options supported are restricted and unrestricted"); - add_input("direct_df").set_default(false).set_description("Requests the direct computation of the density-fitted Coulomb contribution. Works only for pure Kohn-Sham fnctionals (no exact exchange) "); - - //DFT - add_input("snK").set_default(false).set_description("Computes the exact exchange contribution using the seminumerical approach implemented in GauXC"); - add_input>("xc_type").set_default(std::vector{}).set_description("A list of strings specifying the exchange and correlation functionals for DFT calculations"); - - add_input("xc_grid_type").set_default("UltraFine").set_description("Specifies the quality of the numerical integration grid"); - - add_input("xc_pruning_scheme").set_default("Robust").set_description("GauXC pruning scheme. Options supported are Robust, Treutler, Unpruned"); - add_input("xc_rad_quad").set_default("MK").set_description("Specifies the GauXC radial quadrature. Options are MK,TA,MHL"); - add_input("xc_weight_scheme").set_default("SSF").set_description("Specifies the GauXC partitioning scheme. Can be SSF, Becke, LKO"); - add_input("xc_exec_space").set_default("Host").set_description("Specifies the GauXC execution space (Host or Device) for the load balancer and integrator"); - - add_input("xc_basis_tol").set_default(1e-10).set_description("Specifies the GauXC basis tolerance"); - add_input("xc_batch_size").set_default(2048).set_description("Specifies the GauXC batch size"); - - add_input("xc_snK_etol").set_default(1e-10).set_description("snK energy tolerance. If conve < xc_snK_etol, this tolerance will be automatically set to the conve value"); - add_input("xc_snK_ktol").set_default(1e-10).set_description("K matrix tolerance. If conve * 1e-2 < xc_snK_ktol, this tolerance will be automatically set to conve * 1e-2"); - - add_input("xc_lb_kernel" ).set_default("Default").set_description("Specifies the GauXC Load Balancer Kernel"); - add_input("xc_mw_kernel" ).set_default("Default").set_description("Specifies the GauXC Molecular Weights Kernel"); - add_input("xc_int_kernel").set_default("Default").set_description("Specifies the GauXC Integrator Kernel"); - add_input("xc_red_kernel").set_default("Default").set_description("Specifies the GauXC Reduction Kernel"); - add_input("xc_lwd_kernel").set_default("Default").set_description("Specifies the GauXC Local Work Driver Kernel"); - -} - -MODULE_RUN(SCFEnergy) { - - const auto rank = ProcGroup::world_rank(); - ProcGroup pg = ProcGroup::create_world_coll(); - ExecutionContext ec{pg, DistributionKind::nw, MemoryManagerKind::ga}; - - const auto& [aos, cs] = energy_pt::unwrap_inputs(inputs); - - const double angstrom_to_bohr = 1.8897259878858; - - libint2::BasisSet li_shells = make_libint_basis(aos); - - ChemEnv chem_env; - chem_env.input_file = inputs.at("molecule_name").value(); - auto mol = cs.molecule(); - chem_env.ec_atoms.resize(mol.size()); - chem_env.atoms.resize(mol.size()); - - CommonOptions& coptions = chem_env.ioptions.common_options; - //parse common options - coptions.geom_units = inputs.at("units").value(); - const double convert_units = (coptions.geom_units == "angstrom") ? angstrom_to_bohr : 1.0; - coptions.basis = aos[0].basis_set_name().value_or("sto-3g"); - - std::cout << std::endl; - for (int i = 0; i < mol.size(); i++) { - auto atom_i = mol[i]; - chem_env.atoms[i] = {(int)atom_i.Z(), atom_i.x() * convert_units, atom_i.y() * convert_units, atom_i.z() * convert_units}; - chem_env.ec_atoms[i].atom = chem_env.atoms[i]; - chem_env.ec_atoms[i].esymbol = atom_i.name(); - chem_env.ec_atoms[i].basis = coptions.basis; - - std::cout << std::setw(3) << std::left << chem_env.ec_atoms[i].esymbol << " " << std::right << std::setw(14) - << std::fixed << std::setprecision(10) << chem_env.atoms[i].x << " " << std::right - << std::setw(14) << std::fixed << std::setprecision(10) << chem_env.atoms[i].y << " " - << std::right << std::setw(14) << std::fixed << std::setprecision(10) << chem_env.atoms[i].z << "\n"; - } - - chem_env.sys_data.input_molecule = chem_env.input_file; - - if(chem_env.ioptions.common_options.file_prefix.empty()) { - chem_env.ioptions.common_options.file_prefix = chem_env.sys_data.input_molecule; - } - - chem_env.sys_data.output_file_prefix = - chem_env.ioptions.common_options.file_prefix + "." + chem_env.ioptions.common_options.basis; - chem_env.workspace_dir = chem_env.sys_data.output_file_prefix + "_files/"; - - // Set SCF options - SCFOptions& scf = chem_env.ioptions.scf_options; - scf.charge = inputs.at("charge").value(); - scf.multiplicity = inputs.at("multiplicity").value(); - scf.lshift = inputs.at("lshift").value(); - scf.tol_int = inputs.at("tol_int").value(); - scf.tol_sch = inputs.at("tol_sch").value(); - scf.tol_lindep = inputs.at("tol_lindep").value(); - scf.conve = inputs.at("conve").value(); - scf.conve = inputs.at("convd").value(); - scf.diis_hist = inputs.at("diis_hist").value(); - scf.damp = inputs.at("damp").value(); - scf.writem = inputs.at("writem").value(); - scf.debug = inputs.at("debug").value(); - scf.restart = inputs.at("restart").value(); - scf.noscf = inputs.at("noscf").value(); - scf.scf_type = inputs.at("scf_type").value(); - scf.direct_df = inputs.at("direct_df").value(); - - // DFT - scf.snK = inputs.at("snK").value(); - scf.xc_type = inputs.at("xc_type").value>(); - - scf.xc_grid_type = inputs.at("xc_grid_type").value(); - scf.xc_pruning_scheme = inputs.at("xc_pruning_scheme").value(); - scf.xc_rad_quad = inputs.at("xc_rad_quad").value(); - scf.xc_weight_scheme = inputs.at("xc_weight_scheme").value(); - scf.xc_exec_space = inputs.at("xc_exec_space").value(); - - scf.xc_basis_tol = inputs.at("xc_basis_tol").value(); - scf.xc_batch_size = inputs.at("xc_batch_size").value(); - scf.xc_snK_etol = inputs.at("xc_snK_etol").value(); - scf.xc_snK_ktol = inputs.at("xc_snK_ktol").value(); - - scf.xc_lb_kernel = inputs.at("xc_lb_kernel" ).value(); - scf.xc_mw_kernel = inputs.at("xc_mw_kernel" ).value(); - scf.xc_int_kernel = inputs.at("xc_int_kernel").value(); - scf.xc_red_kernel = inputs.at("xc_red_kernel").value(); - scf.xc_lwd_kernel = inputs.at("xc_lwd_kernel").value(); - - IniSystemData ini_sys_data(chem_env); - SCFOptions& scf_options = chem_env.ioptions.scf_options; - chem_env.ec_basis = ECBasis(ec, scf_options.basis, scf_options.basisfile, - scf_options.gaussian_type, chem_env.atoms, chem_env.ec_atoms); - chem_env.shells = chem_env.ec_basis.shells; - chem_env.sys_data.has_ecp = chem_env.ec_basis.has_ecp; - - exachem::scf::scf(ec, chem_env); - - double E0 = chem_env.hf_energy; // This is a total energy in Hartree - auto rv = results(); - return energy_pt::wrap_results(rv, E0); -} - -} // namespace scf diff --git a/src/scf/scf_mm.cpp b/src/scf/scf_mm.cpp index 014274a..43354f8 100644 --- a/src/scf/scf_mm.cpp +++ b/src/scf/scf_mm.cpp @@ -14,14 +14,15 @@ * limitations under the License. */ -#include - #include "scf_modules.hpp" +#include namespace scf { -void load_modules(pluginplay::ModuleManager& mm) { - mm.add_module("SCF Energy"); +void load_modules(pluginplay::ModuleManager &mm) { +#ifdef BUILD_TAMM_SCF + mm.add_module("SCF Energy via TAMM"); +#endif } } // namespace scf diff --git a/src/scf/scf_modules.hpp b/src/scf/scf_modules.hpp index 52b5bbc..af51695 100644 --- a/src/scf/scf_modules.hpp +++ b/src/scf/scf_modules.hpp @@ -19,6 +19,8 @@ namespace scf { -DECLARE_MODULE(SCFEnergy); +#ifdef BUILD_TAMM_SCF +DECLARE_MODULE(TAMMEnergy); +#endif } // namespace scf diff --git a/src/scf/tamm_scf.cpp b/src/scf/tamm_scf.cpp new file mode 100644 index 0000000..d285b82 --- /dev/null +++ b/src/scf/tamm_scf.cpp @@ -0,0 +1,333 @@ +/* + * Copyright 2024 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. + */ + +#ifdef BUILD_TAMM_SCF +#include "exachem/common/chemenv.hpp" +#include "exachem/common/initialize_system_data.hpp" +#include "exachem/scf/scf_main.hpp" +#include "scf_modules.hpp" +#include +#include + +namespace scf { + +using energy_pt = simde::AOEnergy; + +inline libint2::BasisSet +make_libint_basis(const simde::type::ao_basis_set &bs) { + /// Typedefs for everything + using atom_t = libint2::Atom; + using shell_t = libint2::Shell; + using basis_t = libint2::BasisSet; + using cont_t = libint2::Shell::Contraction; + using svec_d_t = libint2::svector; + using conts_t = libint2::svector; + using centers_t = std::vector; + using atom_bases_t = std::vector; + using element_bases_t = std::vector; + + /// Inputs for BasisSet constructor + centers_t centers{}; + element_bases_t element_bases{}; + + /// Atom doesn't have a value ctor, so here's a stand in + auto atom_ctor = [](int Z, double x, double y, double z) { + atom_t atom{}; + atom.atomic_number = Z; + atom.x = x; + atom.y = y; + atom.z = z; + return atom; + }; + + /// Origin for shell construction + std::array origin = {0.0, 0.0, 0.0}; + + /// Convert centers and their shells to libint equivalents. + for (auto abs_i = 0; abs_i < bs.size(); ++abs_i) { + /// Add current center to atoms list + const auto &abs = bs[abs_i]; + centers.push_back( + atom_ctor(abs_i, abs.center().x(), abs.center().y(), abs.center().z())); + + /// Gather shells for this center and add them to element_bases + atom_bases_t atom_bases{}; + for (const auto &&shelli : abs) { + const auto nprims = shelli.n_primitives(); + const auto prim0 = shelli.primitive(0); + const auto primN = shelli.primitive(nprims - 1); + const bool pure = shelli.pure() == chemist::ShellType::pure; + const int l = shelli.l(); + + svec_d_t alphas(&prim0.exponent(), &primN.exponent() + 1); + svec_d_t coefs(&prim0.coefficient(), &primN.coefficient() + 1); + conts_t conts{cont_t{l, pure, coefs}}; + /// Use origin for position, because BasisSet moves shells to center + atom_bases.push_back(shell_t(alphas, conts, origin)); + } + element_bases.push_back(atom_bases); + } + + /// Return the new basis set + return basis_t(centers, element_bases); +} + +MODULE_CTOR(TAMMEnergy) { + satisfies_property_type(); + + add_input("molecule_name") + .set_description("The name of the molecule"); + add_input("units") + .set_default("angstrom") + .set_description("Specifies the units as bohr or angstrom"); + + add_input("charge").set_default(0).set_description("Charge"); + add_input("multiplicity") + .set_default(1) + .set_description( + "number of singly occupied orbitals for a particular calculation"); + add_input("lshift").set_default(0.0).set_description( + "level shift factor denoting the amount of shift applied to the diagonal " + "elements of the unoccupied block of the Fock matrix"); + + add_input("tol_int").set_default(1e-22).set_description( + "integral primitive screening threshold"); + + add_input("tol_sch").set_default(1.0e-10).set_description( + "The Schwarz inequality is used to screen the product of integrals and " + "density matrices"); + + add_input("tol_lindep") + .set_default(1e-5) + .set_description( + "Tolerance for detecting the linear dependence of basis set"); + + add_input("conve").set_default(1e-8).set_description( + "Specifies the energy convergence threshold"); + add_input("convd").set_default(1e-6).set_description( + "Specifies the density convergence threshold"); + + add_input("diis_hist") + .set_default(10) + .set_description("number of DIIS history entries to store for the fock " + "and error matrices"); + + add_input("damp").set_default(100).set_description( + "percentage of the current iterations density mixed with the previous " + "iterations density. 100\% indicates no damping"); + + add_input("writem").set_default(1).set_description( + "An integer specifying the frequency (as number of iterations) after " + "which the movecs and density matrices are written to disk for " + "restarting the calculation"); + + add_input("debug").set_default(false).set_description( + "enable verbose printing for debugging a calculation"); + + add_input("restart").set_default(false).set_description( + "indicates the calculation be restarted"); + add_input("noscf").set_default(false).set_description( + "computes only the SCF energy upon restart"); + + add_input("scf_type") + .set_default("restricted") + .set_description("options supported are restricted and unrestricted"); + add_input("direct_df") + .set_default(false) + .set_description("Requests the direct computation of the density-fitted " + "Coulomb contribution. Works only for pure Kohn-Sham " + "fnctionals (no exact exchange) "); + + // DFT + add_input("snK").set_default(false).set_description( + "Computes the exact exchange contribution using the seminumerical " + "approach implemented in GauXC"); + add_input>("xc_type") + .set_default(std::vector{}) + .set_description("A list of strings specifying the exchange and " + "correlation functionals for DFT calculations"); + + add_input("xc_grid_type") + .set_default("UltraFine") + .set_description( + "Specifies the quality of the numerical integration grid"); + + add_input("xc_pruning_scheme") + .set_default("Robust") + .set_description("GauXC pruning scheme. Options supported are Robust, " + "Treutler, Unpruned"); + add_input("xc_rad_quad") + .set_default("MK") + .set_description( + "Specifies the GauXC radial quadrature. Options are MK,TA,MHL"); + add_input("xc_weight_scheme") + .set_default("SSF") + .set_description( + "Specifies the GauXC partitioning scheme. Can be SSF, Becke, LKO"); + add_input("xc_exec_space") + .set_default("Host") + .set_description("Specifies the GauXC execution space (Host or Device) " + "for the load balancer and integrator"); + + add_input("xc_basis_tol") + .set_default(1e-10) + .set_description("Specifies the GauXC basis tolerance"); + add_input("xc_batch_size") + .set_default(2048) + .set_description("Specifies the GauXC batch size"); + + add_input("xc_snK_etol") + .set_default(1e-10) + .set_description( + "snK energy tolerance. If conve < xc_snK_etol, this tolerance will " + "be automatically set to the conve value"); + add_input("xc_snK_ktol") + .set_default(1e-10) + .set_description( + "K matrix tolerance. If conve * 1e-2 < xc_snK_ktol, this tolerance " + "will be automatically set to conve * 1e-2"); + + add_input("xc_lb_kernel") + .set_default("Default") + .set_description("Specifies the GauXC Load Balancer Kernel"); + add_input("xc_mw_kernel") + .set_default("Default") + .set_description("Specifies the GauXC Molecular Weights Kernel"); + add_input("xc_int_kernel") + .set_default("Default") + .set_description("Specifies the GauXC Integrator Kernel"); + add_input("xc_red_kernel") + .set_default("Default") + .set_description("Specifies the GauXC Reduction Kernel"); + add_input("xc_lwd_kernel") + .set_default("Default") + .set_description("Specifies the GauXC Local Work Driver Kernel"); +} + +MODULE_RUN(TAMMEnergy) { + + const auto rank = ProcGroup::world_rank(); + ProcGroup pg = ProcGroup::create_world_coll(); + ExecutionContext ec{pg, DistributionKind::nw, MemoryManagerKind::ga}; + + const auto &[aos, cs] = energy_pt::unwrap_inputs(inputs); + + const double angstrom_to_bohr = 1.8897259878858; + + libint2::BasisSet li_shells = make_libint_basis(aos); + + ChemEnv chem_env; + chem_env.input_file = inputs.at("molecule_name").value(); + auto mol = cs.molecule(); + chem_env.ec_atoms.resize(mol.size()); + chem_env.atoms.resize(mol.size()); + + CommonOptions &coptions = chem_env.ioptions.common_options; + // parse common options + coptions.geom_units = inputs.at("units").value(); + const double convert_units = + (coptions.geom_units == "angstrom") ? angstrom_to_bohr : 1.0; + coptions.basis = aos[0].basis_set_name().value_or("sto-3g"); + + std::cout << std::endl; + for (int i = 0; i < mol.size(); i++) { + auto atom_i = mol[i]; + chem_env.atoms[i] = {(int)atom_i.Z(), atom_i.x() * convert_units, + atom_i.y() * convert_units, + atom_i.z() * convert_units}; + chem_env.ec_atoms[i].atom = chem_env.atoms[i]; + chem_env.ec_atoms[i].esymbol = atom_i.name(); + chem_env.ec_atoms[i].basis = coptions.basis; + + std::cout << std::setw(3) << std::left << chem_env.ec_atoms[i].esymbol + << " " << std::right << std::setw(14) << std::fixed + << std::setprecision(10) << chem_env.atoms[i].x << " " + << std::right << std::setw(14) << std::fixed + << std::setprecision(10) << chem_env.atoms[i].y << " " + << std::right << std::setw(14) << std::fixed + << std::setprecision(10) << chem_env.atoms[i].z << "\n"; + } + + chem_env.sys_data.input_molecule = chem_env.input_file; + + if (chem_env.ioptions.common_options.file_prefix.empty()) { + chem_env.ioptions.common_options.file_prefix = + chem_env.sys_data.input_molecule; + } + + chem_env.sys_data.output_file_prefix = + chem_env.ioptions.common_options.file_prefix + "." + + chem_env.ioptions.common_options.basis; + chem_env.workspace_dir = chem_env.sys_data.output_file_prefix + "_files/"; + + // Set SCF options + SCFOptions &scf = chem_env.ioptions.scf_options; + scf.charge = inputs.at("charge").value(); + scf.multiplicity = inputs.at("multiplicity").value(); + scf.lshift = inputs.at("lshift").value(); + scf.tol_int = inputs.at("tol_int").value(); + scf.tol_sch = inputs.at("tol_sch").value(); + scf.tol_lindep = inputs.at("tol_lindep").value(); + scf.conve = inputs.at("conve").value(); + scf.conve = inputs.at("convd").value(); + scf.diis_hist = inputs.at("diis_hist").value(); + scf.damp = inputs.at("damp").value(); + scf.writem = inputs.at("writem").value(); + scf.debug = inputs.at("debug").value(); + scf.restart = inputs.at("restart").value(); + scf.noscf = inputs.at("noscf").value(); + scf.scf_type = inputs.at("scf_type").value(); + scf.direct_df = inputs.at("direct_df").value(); + + // DFT + scf.snK = inputs.at("snK").value(); + scf.xc_type = inputs.at("xc_type").value>(); + + scf.xc_grid_type = inputs.at("xc_grid_type").value(); + scf.xc_pruning_scheme = inputs.at("xc_pruning_scheme").value(); + scf.xc_rad_quad = inputs.at("xc_rad_quad").value(); + scf.xc_weight_scheme = inputs.at("xc_weight_scheme").value(); + scf.xc_exec_space = inputs.at("xc_exec_space").value(); + + scf.xc_basis_tol = inputs.at("xc_basis_tol").value(); + scf.xc_batch_size = inputs.at("xc_batch_size").value(); + scf.xc_snK_etol = inputs.at("xc_snK_etol").value(); + scf.xc_snK_ktol = inputs.at("xc_snK_ktol").value(); + + scf.xc_lb_kernel = inputs.at("xc_lb_kernel").value(); + scf.xc_mw_kernel = inputs.at("xc_mw_kernel").value(); + scf.xc_int_kernel = inputs.at("xc_int_kernel").value(); + scf.xc_red_kernel = inputs.at("xc_red_kernel").value(); + scf.xc_lwd_kernel = inputs.at("xc_lwd_kernel").value(); + + IniSystemData ini_sys_data(chem_env); + SCFOptions &scf_options = chem_env.ioptions.scf_options; + chem_env.ec_basis = + ECBasis(ec, scf_options.basis, scf_options.basisfile, + scf_options.gaussian_type, chem_env.atoms, chem_env.ec_atoms); + chem_env.shells = chem_env.ec_basis.shells; + chem_env.sys_data.has_ecp = chem_env.ec_basis.has_ecp; + + exachem::scf::scf(ec, chem_env); + + // This is a total energy in Hartree + double E0 = chem_env.scf_context.hf_energy; + auto rv = results(); + return energy_pt::wrap_results(rv, E0); +} + +} // namespace scf +#endif \ No newline at end of file diff --git a/tests/cxx/main.cpp b/tests/cxx/integration_tests/main.cpp similarity index 78% rename from tests/cxx/main.cpp rename to tests/cxx/integration_tests/main.cpp index 0ac0592..420fc4e 100644 --- a/tests/cxx/main.cpp +++ b/tests/cxx/integration_tests/main.cpp @@ -16,14 +16,14 @@ #define CATCH_CONFIG_RUNNER #include -#include +#include -int main(int argc, char* argv[]) { - tamm::initialize(argc, argv); +int main(int argc, char *argv[]) { + auto rt = scf::initialize(argc, argv); - int res = Catch::Session().run(argc, argv); + int res = Catch::Session().run(argc, argv); - tamm::finalize(); + scf::finalize(); - return res; -} \ No newline at end of file + return res; +} diff --git a/tests/cxx/integration_tests/test_scf.cpp b/tests/cxx/integration_tests/test_scf.cpp new file mode 100644 index 0000000..00c7b02 --- /dev/null +++ b/tests/cxx/integration_tests/test_scf.cpp @@ -0,0 +1,74 @@ +/* + * Copyright 2024 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 +#include +#include +#include +#include +#include + +TEST_CASE("SCF") { + + // Populate modules + pluginplay::ModuleManager mm; + chemcache::load_modules(mm); + scf::load_modules(mm); + + // Create ChemicalSystem + std::string mol_name = "water"; + auto mol = mm.at("NWX Molecules").run_as(mol_name); + simde::type::chemical_system cs(mol); + + // Create BasisSet + std::string basis_name = + "sto-3g"; // This is the only supported basis in ChemCache + auto aos = mm.at(basis_name).run_as(mol); + + // Run module + mm.change_input("SCF Energy via TAMM", "molecule_name", mol_name); + auto E = mm.at("SCF Energy via TAMM").run_as(aos, cs); + std::cout << "SCF Energy = " << E << " Hartree" << std::endl; + + REQUIRE(E == Catch::Approx(-74.3670617803483).margin(1.0e-6)); +} + +TEST_CASE("DFT") { + + // Populate modules + pluginplay::ModuleManager mm; + chemcache::load_modules(mm); + scf::load_modules(mm); + + // Create ChemicalSystem + std::string mol_name = "water"; + auto mol = mm.at("NWX Molecules").run_as(mol_name); + simde::type::chemical_system cs(mol); + + // Create BasisSet + std::string basis_name = + "sto-3g"; // This is the only supported basis in ChemCache + auto aos = mm.at(basis_name).run_as(mol); + + // Run module + std::vector xc_type = {"pbe0"}; + mm.change_input("SCF Energy via TAMM", "xc_type", xc_type); + mm.change_input("SCF Energy via TAMM", "molecule_name", mol_name); + auto E = mm.at("SCF Energy via TAMM").run_as(aos, cs); + std::cout << "SCF Energy = " << E << " Hartree" << std::endl; + + REQUIRE(E == Catch::Approx(-74.81168986385825).margin(1.0e-6)); +} \ No newline at end of file diff --git a/tests/cxx/test_scf.cpp b/tests/cxx/test_scf.cpp deleted file mode 100644 index 94c613a..0000000 --- a/tests/cxx/test_scf.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2024 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 -#include -#include -#include -#include -#include - -TEST_CASE("SCF") { - - // Populate modules - pluginplay::ModuleManager mm; - chemcache::load_modules(mm); - scf::load_modules(mm); - - // Create ChemicalSystem - std::string mol_name = "water"; - auto mol = mm.at("NWX Molecules").run_as(mol_name); - simde::type::chemical_system cs(mol); - - // Create BasisSet - std::string basis_name = "sto-3g"; // This is the only supported basis in ChemCache - auto aos = mm.at(basis_name).run_as(mol); - - // Run module - mm.change_input("SCF Energy", "molecule_name", mol_name); - auto E = mm.at("SCF Energy").run_as(aos, cs); - std::cout << "SCF Energy = " << E << " Hartree" << std::endl; - - REQUIRE(E == Catch::Approx(-74.3670617803483).margin(1.0e-6)); -} - -TEST_CASE("DFT") { - - // Populate modules - pluginplay::ModuleManager mm; - chemcache::load_modules(mm); - scf::load_modules(mm); - - // Create ChemicalSystem - std::string mol_name = "water"; - auto mol = mm.at("NWX Molecules").run_as(mol_name); - simde::type::chemical_system cs(mol); - - // Create BasisSet - std::string basis_name = "sto-3g"; // This is the only supported basis in ChemCache - auto aos = mm.at(basis_name).run_as(mol); - - // Run module - std::vector xc_type = {"pbe0"}; - mm.change_input("SCF Energy", "xc_type", xc_type); - mm.change_input("SCF Energy", "molecule_name", mol_name); - auto E = mm.at("SCF Energy").run_as(aos, cs); - std::cout << "SCF Energy = " << E << " Hartree" << std::endl; - - REQUIRE(E == Catch::Approx(-74.81168986385825).margin(1.0e-6)); -} \ No newline at end of file diff --git a/tests/cxx/unit_tests/main.cpp b/tests/cxx/unit_tests/main.cpp new file mode 100644 index 0000000..420fc4e --- /dev/null +++ b/tests/cxx/unit_tests/main.cpp @@ -0,0 +1,29 @@ +/* + * Copyright 2024 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. + */ + +#define CATCH_CONFIG_RUNNER +#include +#include + +int main(int argc, char *argv[]) { + auto rt = scf::initialize(argc, argv); + + int res = Catch::Session().run(argc, argv); + + scf::finalize(); + + return res; +} diff --git a/tests/cxx/unit_tests/stub.cpp b/tests/cxx/unit_tests/stub.cpp new file mode 100644 index 0000000..ebcfb0b --- /dev/null +++ b/tests/cxx/unit_tests/stub.cpp @@ -0,0 +1,21 @@ +/* + * Copyright 2024 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 +#include +#include + +TEST_CASE("Stub Test") {} \ No newline at end of file diff --git a/tests/python/integration_tests/run_integration_tests.py b/tests/python/integration_tests/run_integration_tests.py new file mode 100644 index 0000000..3889763 --- /dev/null +++ b/tests/python/integration_tests/run_integration_tests.py @@ -0,0 +1,31 @@ +# Copyright 2024 NWChemEx +# +# 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 scf +import sys +import os +import unittest + +if __name__ == '__main__': + rv = scf.initialize(sys.argv) + + my_dir = os.path.dirname(os.path.realpath(__file__)) + + loader = unittest.TestLoader() + tests = loader.discover(my_dir) + testrunner = unittest.runner.TextTestRunner() + ret = not testrunner.run(tests).wasSuccessful() + + scf.finalize() + + sys.exit(ret) \ No newline at end of file diff --git a/tests/python/integration_tests/test_scf/__init__.py b/tests/python/integration_tests/test_scf/__init__.py new file mode 100644 index 0000000..15622f7 --- /dev/null +++ b/tests/python/integration_tests/test_scf/__init__.py @@ -0,0 +1,13 @@ +# Copyright 2024 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. diff --git a/tests/python/integration_tests/test_scf/test_tamm_scf.py b/tests/python/integration_tests/test_scf/test_tamm_scf.py new file mode 100755 index 0000000..5e7446a --- /dev/null +++ b/tests/python/integration_tests/test_scf/test_tamm_scf.py @@ -0,0 +1,45 @@ +# Copyright 2023 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. + +from pluginplay import ModuleManager +import scf +from simde import AOEnergy, MoleculeFromString, MolecularBasisSet +import nwchemex +from chemist import ChemicalSystem +import unittest + + +class TestTAMMSCF(unittest.TestCase): + + def test_4cHF(self): + self.mm.change_input(self.key, 'molecule_name', 'water') + egy = self.mm.run_as(AOEnergy(), self.key, self.aos, self.cs) + self.assertAlmostEqual(egy, -74.3670617803483, places=6) + + def test_dft(self): + self.mm.change_input(self.key, 'xc_type', ["pbe0"]) + self.mm.change_input(self.key, 'molecule_name', 'water') + egy = self.mm.run_as(AOEnergy(), self.key, self.aos, self.cs) + self.assertAlmostEqual(egy, -74.81168986385825, places=6) + + def setUp(self): + self.mm = ModuleManager() + nwchemex.load_modules(self.mm) + scf.load_modules(self.mm) + self.key = 'SCF Energy via TAMM' + basis_name = 'sto-3g' + pt = MoleculeFromString() + mol = self.mm.run_as(pt, "NWX Molecules", "water") + self.aos = self.mm.run_as(MolecularBasisSet(), basis_name, mol) + self.cs = ChemicalSystem(mol) diff --git a/tests/python/unit_tests/run_unit_tests.py b/tests/python/unit_tests/run_unit_tests.py new file mode 100644 index 0000000..3889763 --- /dev/null +++ b/tests/python/unit_tests/run_unit_tests.py @@ -0,0 +1,31 @@ +# Copyright 2024 NWChemEx +# +# 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 scf +import sys +import os +import unittest + +if __name__ == '__main__': + rv = scf.initialize(sys.argv) + + my_dir = os.path.dirname(os.path.realpath(__file__)) + + loader = unittest.TestLoader() + tests = loader.discover(my_dir) + testrunner = unittest.runner.TextTestRunner() + ret = not testrunner.run(tests).wasSuccessful() + + scf.finalize() + + sys.exit(ret) \ No newline at end of file diff --git a/tests/python/unit_tests/test_scf.py b/tests/python/unit_tests/test_scf.py deleted file mode 100755 index b93098c..0000000 --- a/tests/python/unit_tests/test_scf.py +++ /dev/null @@ -1,76 +0,0 @@ -#!/Users/jwaldrop/venvs/nwx/bin/python -# Copyright 2023 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. - -from pluginplay import ModuleManager -from scf import load_modules, tamm_finalize, tamm_initialize -from simde import AOEnergy, MoleculeFromString, MolecularBasisSet -import chemcache as ccache -from molecules import make_h2 -import parallelzone as pz -from chemist import ChemicalSystem -import unittest -import os -import sys - - -class TestSCF(unittest.TestCase): - - def test_4cHF(self): - mol_name = "water" - mol = self.mm.run_as(MoleculeFromString(), "NWX Molecules", mol_name) - cs = ChemicalSystem(mol) - - basis_name = "sto-3g" - aos = self.mm.run_as(MolecularBasisSet(), basis_name, mol) - - key = 'SCF Energy' - self.mm.change_input(key, 'molecule_name', mol_name) - egy = self.mm.run_as(AOEnergy(), key, aos, cs) - self.assertAlmostEqual(egy, -74.3670617803483, places=6) - - def test_dft(self): - mol_name = "water" - mol = self.mm.run_as(MoleculeFromString(), "NWX Molecules", mol_name) - cs = ChemicalSystem(mol) - - basis_name = "sto-3g" - aos = self.mm.run_as(MolecularBasisSet(), basis_name, mol) - - key = 'SCF Energy' - self.mm.change_input(key, 'xc_type', ["pbe0"]) - self.mm.change_input(key, 'molecule_name', mol_name) - egy = self.mm.run_as(AOEnergy(), key, aos, cs) - self.assertAlmostEqual(egy, -74.81168986385825, places=6) - - def setUp(self): - self.mm = ModuleManager() - ccache.load_modules(self.mm) - load_modules(self.mm) - - -if __name__ == '__main__': - tamm_initialize(sys.argv) - rv = pz.runtime.RuntimeView() - - my_dir = os.path.dirname(os.path.realpath(__file__)) - - loader = unittest.TestLoader() - tests = loader.discover(my_dir) - testrunner = unittest.runner.TextTestRunner() - ret = not testrunner.run(tests).wasSuccessful() - - tamm_finalize() - - sys.exit(ret) diff --git a/tests/python/unit_tests/test_scf/__init__.py b/tests/python/unit_tests/test_scf/__init__.py new file mode 100644 index 0000000..15622f7 --- /dev/null +++ b/tests/python/unit_tests/test_scf/__init__.py @@ -0,0 +1,13 @@ +# Copyright 2024 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.