diff --git a/CHANGES b/CHANGES index 64d107896..2f151b375 100644 --- a/CHANGES +++ b/CHANGES @@ -54,7 +54,7 @@ Following is a brief summary of changes made in each release of Libint. - PR #283: bump pybind11 to ValeevGroup/pybind11@v2.11 (HT @asadchev) - PR #282: removed obsolete basis files (HT @JonathonMisiewicz) - PR #279: fixed error in 1-e erf/erfc integrals (HT @JonathonMisiewicz) - - PR @273: support for 1-e (σ·p)V(σ·p) integrals (HT @JonathonMisiewicz) + - PR #273: support for 1-e (σ·p)V(σ·p) integrals (HT @JonathonMisiewicz) - PR #271: Add `libint2::configuration_accessor` and `libint2::supports` functions. If library source is patched, these provide codes for what integrals a library instance can supply. (HT @loriab) - PR #271: Small pkgconfig and cmake detection improvements. Enable unity build. diff --git a/CMakeLists.txt b/CMakeLists.txt index be3509e2a..0af18a6f1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,7 +59,151 @@ set(pnv libint2) # projectnameversion # -- Build files have been written to: /current/dir/build # >>> cmake --build build --target install +# The Libint build is structured into three parts: +# +# * generator/compiler +# - (1) build src/bin/libint/ into compiler executable `build_libint` +# - pretty quick, runs in parallel +# - consumes all the enable/max/opt/orderings integral options +# - (2) optionally testable +# * export +# - (3) run `build_libint` to generate library source (C++) files (that upon +# compilation can become a Libint2 library) and combine them with other +# static source files in src/lib/libint/ and general static files (e.g., +# include/ and docs/) into an independent tarball ready for distribution +# (with its own CMake configuration, tests, etc.). +# - really slow for non-trivial angular momenta; runs in serial +# - consumes no options +# - build target `export` to stop after this step and collect source tarball +# * library +# - can be built as a subproject (FetchContent) or completely insulated (bare +# ExternalProject; default; -or- a tarball start). For FetchContent, must +# build libint-library-export target before library build targets appear +# - (4) unpack the export tarball and build the library and install into \/library-install-stage/ +# - duration depends on number of integrals requested; runs in parallel +# - consumes language-interface and the CMAKE_INSTALL_[DATA|INCLUDE|LIB]DIR paths options +# - the default build target includes this final library build +# - (5) optionally testable +# - (6) install into CMAKE_INSTALL_PREFIX +# - (7) optional Python build alongside library or afterwards. Optional testing requires library install + +#################################### Guide ##################################### + +# See INSTALL.md for elaboration of steps above, options below, & translations from libtool. + +################################### Options #################################### +include(options) +include(GNUInstallDirs) +include(CTest) +message(STATUS "Building using CMake ${CMAKE_VERSION} Generator ${CMAKE_GENERATOR}") + + +# <<< Which Integrals Classes, Which Derivative Levels >>> + +option_with_default(ENABLE_ONEBODY + "Compile with support for up to N-th derivatives of 1-body integrals (-1 for OFF)" 0) +option_with_default(ENABLE_ERI + "Compile with support for up to N-th derivatives of 4-center electron repulsion integrals (-1 for OFF)" 0) +option_with_default(ENABLE_ERI3 + "Compile with support for up to N-th derivatives of 3-center electron repulsion integrals (-1 for OFF)" -1) +option_with_default(ENABLE_ERI2 + "Compile with support for up to N-th derivatives of 2-center electron repulsion integrals (-1 for OFF)" -1) +option_with_default(ENABLE_G12 + "Compile with support for N-th derivatives of MP2-F12 energies with Gaussian factors (-1 for OFF)" -1) +option_with_default(ENABLE_G12DKH + "Compile with support for N-th derivatives of DKH-MP2-F12 energies with Gaussian factors (-1 for OFF)" -1) + +option_with_print(DISABLE_ONEBODY_PROPERTY_DERIVS + "Disable geometric derivatives of 1-body property integrals (all but overlap, kinetic, elecpot). + These derivatives are disabled by default to save compile time. (enable with OFF) + Note that the libtool build won't enable this- if forcibly enabled, build_libint balks." ON) +option_with_print(ENABLE_T1G12_SUPPORT + "Enable Ti,G12 integrals when G12 integrals are enabled. Irrelevant when `ENABLE_G12=OFF`. (disable with OFF)" ON) + +# <<< Ordering Conventions >>> + + +# <<< How High Angular Momentum >>> + +# example for "semicolon-separated string": `-DENABLE_ERI3=2 -DWITH_ERI3_MAX_AM="5;4;3"` + +# special considerations for high-AM library builds: +# * high MAX_AM generates a large number of source files. If unity builds are disabled, more than +# ~20k files may require `ulimit -s 65535` for linking the library target on Linux to avert +# "ld: Argument list too long". +# * Ninja builds use beyond max threads and can run out of memory, resulting in errorless stops or +# "CMake Error: Generator: execution of make failed". Throttle it to physical threads with +# `export CMAKE_BUILD_PARALLEL_LEVEL=N`. + +option_with_default(WITH_MAX_AM + "Support Gaussians of angular momentum up to N. + If ERI3 ints are enabled, specifing values for each derivative level as a + semicolon-separated string also controls the AM of the paired centers." 4) +option_with_default(WITH_OPT_AM + "Optimize maximally for up to angular momentum N (N <= max-am). + Can specify values for each derivative level as a semicolon-separated string. (default: (libint_max_am/2)+1)" -1) + +option_with_default(MULTIPOLE_MAX_ORDER + "Maximum order of spherical multipole integrals. There is no maximum" 4) +option_with_default(WITH_ONEBODY_MAX_AM + "Support 1-body ints for Gaussians of angular momentum up to N. + Can specify values for each derivative level as a semicolon-separated string. (default: max_am)" -1) +option_with_default(WITH_ONEBODY_OPT_AM + "Optimize 1-body ints maximally for up to angular momentum N (N <= max-am). + Can specify values for each derivative level as a semicolon-separated string (default: (max_am/2)+1)" -1) + +option_with_default(WITH_ERI_MAX_AM + "Support 4-center ERIs for Gaussians of angular momentum up to N. + Can specify values for each derivative level as a semicolon-separated string. (default: max_am)" -1) +option_with_default(WITH_ERI_OPT_AM + "Optimize 4-center ERIs maximally for up to angular momentum N (N <= max-am). + Can specify values for each derivative level as a semicolon-separated string (default: (max_am/2)+1)" -1) + +option_with_default(WITH_ERI3_MAX_AM + "Support 3-center ERIs for Gaussians of angular momentum up to N. + Can specify values for each derivative level as a semicolon-separated string. (default: max_am) + This option controls only the single fitting center; the paired centers use WITH_MAX_AM." -1) +option_with_default(WITH_ERI3_OPT_AM + "Optimize 3-center ERIs maximally for up to angular momentum N (N <= max-am). + Can specify values for each derivative level as a semicolon-separated string. (default: (max_am/2)+1)" -1) +option_with_print(ERI3_PURE_SH + "Assume the 'unpaired' center of 3-center ERIs will be transformed to pure solid harmonics" OFF) + +option_with_default(WITH_ERI2_MAX_AM + "Support 2-center ERIs for Gaussians of angular momentum up to N. + Can specify values for each derivative level as a semicolon-separated string. (default: max_am)" -1) +option_with_default(WITH_ERI2_OPT_AM + "Optimize 2-center ERIs maximally for up to angular momentum N (N <= max-am). + Can specify values for each derivative level as a semicolon-separated string. (default: (max_am/2)+1)" -1) +option_with_print(ERI2_PURE_SH + "Assume the 2-center ERIs will be transformed to pure solid harmonics" OFF) + +option_with_default(WITH_G12_MAX_AM + "Support integrals for G12 methods of angular momentum up to N. (default: max_am)" -1) +option_with_default(WITH_G12_OPT_AM + "Optimize G12 integrals for up to angular momentum N (N <= max-am). (default: (max_am/2)+1)" -1) + +option_with_default(WITH_G12DKH_MAX_AM + "Support integrals for relativistic G12 methods of angular momentum up to N. (default: max_am)" -1) +option_with_default(WITH_G12DKH_OPT_AM + "Optimize G12DKH integrals for up to angular momentum N (N <= max-am). (default: (max_am/2)+1)" -1) + +######################## Process & Validate Options ########################### +include(FeatureSummary) +include(int_am) + +booleanize01(ERI3_PURE_SH) +booleanize01(ERI2_PURE_SH) +booleanize01(DISABLE_ONEBODY_PROPERTY_DERIVS) +booleanize01(SUPPORT_T1G12) + ################################## Main Project ################################# +configure_file(include/libint2/config.h.cmake.in include/libint2/config.h @ONLY) + # STRICTLY TEMPORARY FOR DEMONSTRATION PURPOSES configure_file(src/lib/libint/configuration.cc configuration.cc @ONLY) + +message("") +feature_summary(WHAT ENABLED_FEATURES DESCRIPTION "Libint Enabled features:") +feature_summary(WHAT DISABLED_FEATURES DESCRIPTION "Libint Disabled features:") diff --git a/INSTALL.md b/INSTALL.md index fb9ede0e2..80bfe5748 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -1,3 +1,134 @@ +# Configuring Libint + +* Notes + * Codes "G", "L", or "C" for each option indicate whether it is consumed by the _g_enerator, the _l_ibrary, the library _c_onsumer, or a combination. + * If your final target is the export tarball, use options that include the letter "G". + * If you're building a library from an export TARBALL, use options that include the letter "L". + * For a continuous generator->export->library build, options supplied at the top level will be properly handed off to generator and library build. + * See [Update Guide](gnu-autotools-update-guide) for new names for old options. + + +### Which Integrals Classes, Which Derivative Levels (G) + +* `ENABLE_ONEBODY` — G — Compile with support for up to N-th derivatives of 1-body integrals. Use -1 for OFF. [Default=0] +* `ENABLE_ERI` — G — Compile with support for up to N-th derivatives of 4-center electron repulsion integrals. Use -1 for OFF. [Default=0] +* `ENABLE_ERI3` — G — Compile with support for up to N-th derivatives of 3-center electron repulsion integrals. Use -1 for OFF. [Default=-1] +* `ENABLE_ERI2` — G — Compile with support for up to N-th derivatives of 2-center electron repulsion integrals. Use -1 for OFF. [Default=-1] +* `ENABLE_G12` — G — Compile with support for N-th derivatives of MP2-F12 energies with Gaussian factors. Use -1 for OFF. [Default=-1] +* `ENABLE_G12DKH` — G — Compile with support for N-th derivatives of DKH-MP2-F12 energies with Gaussian factors. Use -1 for OFF. [Default=-1] + +* `DISABLE_ONEBODY_PROPERTY_DERIVS` — G — Disable geometric derivatives of 1-body property integrals (all but overlap, kinetic, elecpot). + These derivatives are disabled by default to save compile time. Use OFF to enable. + Note that the libtool build won't enable this- if forcibly enabled, build_libint balks. [Default=ON] + +* `ENABLE_T1G12_SUPPORT` — G — Enable [Ti,G12] integrals when G12 integrals are enabled. Irrelevant when `ENABLE_G12=OFF`. Use OFF to disable. [Default=ON] + + +### Which Ordering Conventions (G) + + + +### How High Angular Momentum (G) + +* Notes + * example for "semicolon-separated string": `-DENABLE_ERI3=2 -DWITH_ERI3_MAX_AM="5;4;3"`. cmake configuration prints: + + ``` + -- Setting option ENABLE_ERI3: 2 + -- Setting option WITH_ERI3_MAX_AM: 5;4;3 + ``` + + * special considerations for high-AM library (L) builds: + * high MAX_AM generates a large number of source files. If unity builds are disabled, more than + ~20k files may require `ulimit -s 65535` for linking the library target on Linux to avert + "ld: Argument list too long". + * Ninja builds use beyond max threads and can run out of memory, resulting in errorless stops or + "CMake Error: Generator: execution of make failed". Throttle it to physical threads with + `export CMAKE_BUILD_PARALLEL_LEVEL=N`. + +* `WITH_MAX_AM` — G — Support Gaussians of angular momentum up to N. If ERI3 ints are enabled, specifing values for each derivative level as a semicolon-separated string also controls the AM of the paired centers. [Default=4] +* `WITH_OPT_AM` — G — Optimize maximally for up to angular momentum N (N <= WITH_MAX_AM). Can specify values for each derivative level as a semicolon-separated string. [Default=-1 -> `(WITH_MAX_AM/2)+1`] + +* `MULTIPOLE_MAX_ORDER` — G — Maximum order of spherical multipole integrals. There is no maximum. [Default=4] + +* `WITH_ONEBODY_MAX_AM` — G — Support 1-body ints for Gaussians of angular momentum up to N. Can specify values for each derivative level as a semicolon-separated string. [Default=-1 -> `WITH_MAX_AM`] +* `WITH_ONEBODY_OPT_AM` — G — Optimize 1-body ints maximally for up to angular momentum N (N <= max-am). Can specify values for each derivative level as a semicolon-separated string. [Default=-1 -> `WITH_OPT_AM`] + +* `WITH_ERI_MAX_AM` — G — Support 4-center ERIs for Gaussians of angular momentum up to N. Can specify values for each derivative level as a semicolon-separated string. [Default=-1 -> `WITH_MAX_AM`] +* `WITH_ERI_OPT_AM` — G — Optimize 4-center ERIs maximally for up to angular momentum N (N <= max-am). Can specify values for each derivative level as a semicolon-separated string. [Default=-1 -> `WITH_OPT_AM`] + +* `WITH_ERI3_MAX_AM` — G — Support 3-center ERIs for Gaussians of angular momentum up to N. Can specify values for each derivative level as a semicolon-separated string. This option controls only the single fitting center; the paired centers use WITH_MAX_AM. [Default=-1 -> `WITH_MAX_AM`] +* `WITH_ERI3_OPT_AM` — G — Optimize 3-center ERIs maximally for up to angular momentum N (N <= max-am). Can specify values for each derivative level as a semicolon-separated string. [Default=-1 -> `WITH_OPT_AM`] +* `ERI3_PURE_SH` — G — Assume the 'unpaired' center of 3-center ERIs will be transformed to pure solid harmonics. [Default=OFF] + +* `WITH_ERI2_MAX_AM` — G — Support 2-center ERIs for Gaussians of angular momentum up to N. Can specify values for each derivative level as a semicolon-separated string. [Default=-1 -> `WITH_MAX_AM`] +* `WITH_ERI2_OPT_AM` — G — Optimize 2-center ERIs maximally for up to angular momentum N (N <= max-am). Can specify values for each derivative level as a semicolon-separated string. [Default=-1 -> `WITH_OPT_AM`] +* `ERI2_PURE_SH` — G — Assume the 2-center ERIs will be transformed to pure solid harmonics. [Default=OFF] + +* `WITH_G12_MAX_AM` — G — Support integrals for G12 methods of angular momentum up to N. No specification with per-derivative list. [Default=-1 -> `WITH_MAX_AM`] +* `WITH_G12_OPT_AM` — G — Optimize G12 integrals for up to angular momentum N (N <= max-am). No specification with per-derivative list. [Default=-1 `WITH_OPT_AM`] + +* `WITH_G12DKH_MAX_AM` — G — Support integrals for relativistic G12 methods of angular momentum up to N. No specification with per-derivative list. [Default=-1 -> `WITH_MAX_AM`] +* `WITH_G12DKH_OPT_AM` — G — Optimize G12DKH integrals for up to angular momentum N (N <= max-am). No specification with per-derivative list. [Default=-1 `WITH_OPT_AM`] + + +### Compilers and Flags (G L) (TARBALL) + + +# GNU Autotools Update Guide + +* Notes + * Multiple option names can be from any long-lived branch but usually libtool+cmake --> final cmake+cmake. + +* `--enable-1body=N` --> `-D ENABLE_ONEBODY=N` +* `--enable-eri=N` --> `-D ENABLE_ERI=N` +* `--disable-eri` --> `-D ENABLE_ERI=-1` +* `--enable-eri3=N` --> `-D ENABLE_ERI3=N` +* `--enable-eri2=N` --> `-D ENABLE_ERI2=N` + +* `--enable-eri3-pure-sh` --> `-D ERI3_PURE_SH=ON` +* `--enable-eri2-pure-sh` --> `-D ERI2_PURE_SH=ON` + +* `--with-max-am=N` --> `-D WITH_MAX_AM=N` +* `--with-max-am=N0,N1,N2` --> `-D WITH_MAX_AM="N0;N1;N2"` (notice semicolons and quotes. This is standard CMake list syntax) +* `--with-opt-am=N` --> `-D WITH_OPT_AM=N` +* `--with-opt-am=N0,N1,N2` --> `-D WITH_OPT_AM="N0;N1;N2"` + +* `--with-multipole-max-order=N` --> `-D MULTIPOLE_MAX_ORDER=N` + +* `--with-1body-max-am=N` --> `-D WITH_ONEBODY_MAX_AM=N` +* `--with-1body-max-am=N0,N1,N2` --> `-D WITH_ONEBODY_MAX_AM="N0;N1;N2"` +* `--with-1body-opt-am=N` --> `-D WITH_ONEBODY_OPT_AM=N` +* `--with-1body-opt-am=N0,N1,N2` --> `-D WITH_ONEBODY_OPT_AM="N0;N1;N2"` + +* `--with-eri-max-am=N` --> `-D WITH_ERI_MAX_AM=N` +* `--with-eri-max-am=N0,N1,N2` --> `-D WITH_ERI_MAX_AM="N0;N1;N2"` +* `--with-eri-opt-am=N` --> `-D WITH_ERI_OPT_AM=N` +* `--with-eri-opt-am=N0,N1,N2` --> `-D WITH_ERI_OPT_AM="N0;N1;N2"` + +* `--with-eri3-max-am=N` --> `-D WITH_ERI3_MAX_AM=N` +* `--with-eri3-max-am=N0,N1,N2` --> `-D WITH_ERI3_MAX_AM="N0;N1;N2"` +* `--with-eri3-opt-am=N` --> `-D WITH_ERI3_OPT_AM=N` +* `--with-eri3-opt-am=N0,N1,N2` --> `-D WITH_ERI3_OPT_AM="N0;N1;N2"` + +* `--with-eri2-max-am=N` --> `-D WITH_ERI2_MAX_AM=N` +* `--with-eri2-max-am=N0,N1,N2` --> `-D WITH_ERI2_MAX_AM="N0;N1;N2"` +* `--with-eri2-opt-am=N` --> `-D WITH_ERI2_OPT_AM=N` +* `--with-eri2-opt-am=N0,N1,N2` --> `-D WITH_ERI2_OPT_AM="N0;N1;N2"` + +* `--enable-g12=N` --> `-D ENABLE_G12=N` +* `--enable-g12dkh=N` --> `-D ENABLE_G12DKH` +* `--disable-t1g12-support` --> `-D ENABLE_T1G12_SUPPORT=OFF` +* `--with-g12-max-am=N` --> `-D WITH_G12_MAX_AM=N` +* `--with-g12-opt-am=N` --> `-D WITH_G12_OPT_AM=N` +* `--with-g12dkh-max-am=N` --> `-D WITH_G12DKH_MAX_AM=N` +* `--with-g12dkh-opt-am=N` --> `-D WITH_G12DKH_OPT_AM=N` + +* `--disable-1body-property-derivs` --> `-D DISABLE_ONEBODY_PROPERTY_DERIVS=ON` + + + + ### Run-Time Compatibility Functions are provided to check the library configuration and solid harmonics orderings at runtime: @@ -82,28 +213,28 @@ Eventually, these will be CMake Components, too. ``` multipole_hh_dD - library includes spherical multipole integrals with max angular momentum up to - "h" (h=spdfghikl...; s,p not enumerated) and derivative order "D" (D=0,1,2,...). + "h" (h=spdfghikl...) and derivative order "D" (D=0,1,2,...). For example, the presence of "multipole_ii_d0" means mpole ints are available for L=6. onebody_hh_dD - library includes 1-body integrals with max angular momentum up to "h" - (h=spdfghikl...; s,p not enumerated) and derivative order "D" (D=0,1,2,...). + (h=spdfghikl...) and derivative order "D" (D=0,1,2,...). For example, the presence of "onebody_ii_d1" means onebody gradient ints are available for L=6. eri_hhhh_dD - library includes 2-body integrals with 4 centers and max angular momentum up to - "h" (h=spdfghikl...; s,p not enumerated) and derivative order "D" (D=0,1,2,...). + "h" (h=spdfghikl...) and derivative order "D" (D=0,1,2,...). For example, the presence of "eri_ffff_d1" means 4-center gradient ints are available for L=3. That is, the library was configured with at least - "--enable-eri=1 --with-eri-max-am=?,>=3". + '-D ENABLE_ERI=1 -D WITH_ERI_MAX_AM="?;>=3"'. eri_hhL_dD - library includes 2-body integrals with 3 centers and max angular momentum up to eri_hhl_dD Cartesian "h" for the two paired centers and Cartesian "l" or solid harmonics "L" for the unpaired/fitting center, (h/l=spdfghikl..., L=SPDFGHIKL...; l>=h - enumerated; s,p,S,P not enumerated) and derivative order "D" (D=0,1,2,...). The + enumerated) and derivative order "D" (D=0,1,2,...). The "eri_hhL_dD" component is always available when 3-center ints are present. When pure solid harmonics are assumed for 3-center ints, "eri_hhl_dD" will *not be available*. For example, the presence of "eri_ffG_d0" means 3-center energy ints are available for L=3 (paired centers) and L=4 (fitting center). That is, the library - was configured with at least "--enable-eri3=0 --with-max-am=3 --with-eri3-max-am=4". + was configured with at least "-D ENABLE_ERI3=0 -D WITH_MAX_AM=3 -D WITH_ERI3_MAX_AM=4". The presence of "eri_ffg_d0" means the library configuration did not additionally - include "--enable-eri3-pure-sh[=yes]". + include "-D ERI3_PURE_SH=ON". eri_HH_dD - library includes 2-body integrals with 2 centers and max angular momentum up to eri_hh_dD Cartesian "h" or solid harmonics "H", (h=spdfghikl..., H=SPDFGHIKL...; s,p,S,P not enumerated) and derivative order "D" (D=0,1,2,...). The "eri_HH_dD" component is @@ -111,10 +242,10 @@ Eventually, these will be CMake Components, too. assumed for 2-center ints, "eri_hh_dD" will *not be available*. For example, the presence of "eri_FF_d2" means 2-center Hessian ints are available for L=3. That is, the library was configured with at least - "--enable-eri2=2 --with-eri2-max-am=?,?,>=3". The presence of "eri_ff_d2" means the - library configuration did not additionally include "--enable-eri2-pure-sh[=yes]". + '-D ENABLE_ERI2=2 -D WITH_ERI2_MAX_AM="?;?;>=3"'. The presence of "eri_ff_d2" means the + library configuration did not additionally include "-D ERI2_PURE_SH=ON". g12_hhhh_dD - library includes F12 integrals with Gaussian factors and max angular momentum up to - "h" (h=spdfghikl...; s,p not enumerated) and derivative order "D" (D=0,1,2,...). + "h" (h=spdfghikl...) and derivative order "D" (D=0,1,2,...). For example, the presence of "g12_iiii_d2" means g12 Hessian ints are available for L=6. cart shell_set used_by @@ -133,7 +264,7 @@ Eventually, these will be CMake Components, too. ### Interfacing -Eventually (approximately 2.9.0 CMake-based), additional functions will be available to retrive Libint version, commit, and literature citation. Below are outputs at the libtool stage. +Eventually (approximately 2.10.0 CMake-based), additional functions will be available to retrive Libint version, commit, and literature citation. Below are outputs at the libtool stage. ``` auto Mmp = libint2::libint_version(); diff --git a/cmake/modules/int_am.cmake b/cmake/modules/int_am.cmake new file mode 100644 index 000000000..98361baac --- /dev/null +++ b/cmake/modules/int_am.cmake @@ -0,0 +1,466 @@ +# handle the defaulting and setting of the following variables +# * ENABLE_[ONEBODY|ERI2|ERI3|ERI|G12|G12DKH] +# * [LIBINT|ONEBODY|ERI2|ERI3|ERI|G12|G12DKH]_[MAX|OPT]_AM[|_LIST] +# * MULTIPOLE_MAX_ORDER +# * LIBINT_ONEBODY_DERIV +# * LIBINT_SUPPORTS_ONEBODY +# * SUPPORT_T1G12 + +# "_candidate" variables are not needed for config.h but are used to figure out +# the AM limits at the CMake level so that libint2-config.cmake components may +# be defined and consuming codes can state their requirements. For example, +# `find_package(Libint2 REQUIRED COMPONENTS eri_hhhh_d1)` requires the detected +# library to include gradient integrals of at least AM=5. +# See INSTALL.md for details. + +# these bounds are for components. Above hard_max produces cmake warning. 0 produces +# error in keeping with configure.ac logic. +set(LIBINT_HARD_MAX_AM 12) +set(LIBINT_HARD_MIN_AM 0) # formerly 2 +# amstr = "SPDFGHIKLMNOQRTUVWXYZ" +set(_am0 "s") +set(_am1 "p") +set(_am2 "d") +set(_am3 "f") +set(_am4 "g") +set(_am5 "h") +set(_am6 "i") +set(_am7 "k") +set(_am8 "l") +set(_am9 "m") +set(_am10 "n") +set(_am11 "o") +set(_am12 "q") +set(_AM0 "S") +set(_AM1 "P") +set(_AM2 "D") +set(_AM3 "F") +set(_AM4 "G") +set(_AM5 "H") +set(_AM6 "I") +set(_AM7 "K") +set(_AM8 "L") +set(_AM9 "M") +set(_AM10 "N") +set(_AM11 "O") +set(_AM12 "Q") + +macro(numerical_max_of_list ansvar liste) + set(_max "-100") + foreach(_i ${liste}) + if (${_i} GREATER _max) + set(_max "${_i}") + endif() + endforeach() + set(${ansvar} "${_max}") +endmacro() + + +message(STATUS "Processing integrals classes ...") + +# <<< overall derivatives level >>> + +set(_glob_classes_derivs ${ENABLE_ONEBODY};${ENABLE_ERI};${ENABLE_ERI3};${ENABLE_ERI2};${ENABLE_G12};${ENABLE_G12DKH}) +numerical_max_of_list(_max_deriv "${_glob_classes_derivs}") +message(STATUS "Preparing highest derivative level ${_max_deriv}") + +# <<< overall max_am defaults >>> + +list(LENGTH WITH_MAX_AM _ntokens_maxam) +if (_ntokens_maxam GREATER 1) + math(EXPR _ntokens_xptd_max_deriv "${_max_deriv} + 1") + if (NOT _ntokens_xptd_max_deriv EQUAL _ntokens_maxam) + message(FATAL_ERROR "Invalid value for WITH_MAX_AM (${WITH_MAX_AM}). Highest ENABLE_ derivative (${_max_deriv}) requires list length ${_ntokens_xptd_max_deriv}, not ${_ntokens_maxam}.") + endif() + + numerical_max_of_list(_max_am "${WITH_MAX_AM}") + list(JOIN WITH_MAX_AM "," _sam) + set(LIBINT_MAX_AM_LIST ${_sam}) + # when LIST populated, only overall LIBINT (not specific ints classes) sets both MAX_AM & MAX_AM_LIST + set(LIBINT_MAX_AM ${_max_am}) + set(_max_LIBINT_MAX_AM ${LIBINT_MAX_AM}) +else() + set(LIBINT_MAX_AM_LIST "") + set(LIBINT_MAX_AM ${WITH_MAX_AM}) +endif() + +foreach(_d RANGE 0 ${_max_deriv}) + if (${_d} LESS _ntokens_maxam) + list(GET WITH_MAX_AM ${_d} _eri3_candidate0_d${_d}) + set(_dflt_candidate0_d${_d} "${LIBINT_MAX_AM}") + else() + set(_eri3_candidate0_d${_d} "${LIBINT_MAX_AM}") + set(_dflt_candidate0_d${_d} "-1") + endif() + # _candidate0_dD=int_am defined up to highest ENABLE_cls deriv D from best info from WITH_MAX_AM + message(VERBOSE "setting _eri3_candidate0_d${_d}=${_eri3_candidate0_d${_d}}") + message(VERBOSE "setting _dflt_candidate0_d${_d}=${_dflt_candidate0_d${_d}}") +endforeach() + +if (LIBINT_MAX_AM GREATER_EQUAL ${LIBINT_HARD_MAX_AM}) + message(WARNING "LIBINT_MAX_AM=${LIBINT_MAX_AM} is greater than ${LIBINT_HARD_MAX_AM}. Are you sure you know what you are doing?") +elseif (LIBINT_MAX_AM LESS_EQUAL 0) + message(FATAL_ERROR "Invalid value for LIBINT_MAX_AM (${LIBINT_MAX_AM}).") +endif() + +message(STATUS "Preparing generic LIBINT_MAX_AM_LIST ${LIBINT_MAX_AM_LIST} and LIBINT_MAX_AM ${LIBINT_MAX_AM} for integrals class defaults.") + +# <<< overall opt_am defaults >>> + +list(LENGTH WITH_OPT_AM _ntokens_optam) +if (NOT WITH_OPT_AM EQUAL -1) + if (NOT _ntokens_optam EQUAL _ntokens_maxam) + # discard two cases: scalar opt and list max -and- list opt and scalar max + message(FATAL_ERROR "Invalid format for WITH_OPT_AM (${WITH_OPT_AM}). Use the same format and length like `N` or `N0;N1;N2` as WITH_MAX_AM (${WITH_MAX_AM}).") + endif() +endif() +if (_ntokens_optam GREATER 1) + # list opt and list max: use list opt validating aginst max + set(_processed_OPT_AM_LIST ) + math(EXPR _range_limit "${_ntokens_maxam} - 1") + foreach(_d RANGE ${_range_limit}) + list(GET WITH_MAX_AM ${_d} _max_am) + list(GET WITH_OPT_AM ${_d} _opt_am) + if (_opt_am LESS_EQUAL _max_am) + list(APPEND _processed_OPT_AM_LIST ${_opt_am}) + else() + list(APPEND _processed_OPT_AM_LIST ${_max_am}) + endif() + endforeach() + + list(JOIN _processed_OPT_AM_LIST "," LIBINT_OPT_AM_LIST) + numerical_max_of_list(LIBINT_OPT_AM "${_processed_OPT_AM_LIST}") +else() + if(WITH_OPT_AM EQUAL -1) + # first branch is a nice default pattern but not exactly what configure.ac prescribes, so bypassing it + # if (_ntokens_maxam GREATER 1) + if (FALSE) + # no opt and list max: default list opt from max + set(_processed_OPT_AM_LIST ) + math(EXPR _range_limit "${_ntokens_maxam} - 1") + foreach(_d RANGE ${_range_limit}) + list(GET WITH_MAX_AM ${_d} _max_am) + math(EXPR _opt_am "${_max_am}/2 + 1") + list(APPEND _processed_OPT_AM_LIST ${_opt_am}) + endforeach() + + list(JOIN _processed_OPT_AM_LIST "," LIBINT_OPT_AM_LIST) + numerical_max_of_list(LIBINT_OPT_AM "${_processed_OPT_AM_LIST}") + else() + # no opt and scalar max: default scalar opt from max + set(LIBINT_OPT_AM_LIST "") + math(EXPR LIBINT_OPT_AM "${LIBINT_MAX_AM}/2 + 1") + endif() + else() + # scalar opt and scalar max: use scalar opt validating aginst max + set(LIBINT_OPT_AM_LIST "") + set(LIBINT_OPT_AM ${WITH_OPT_AM}) + + if (LIBINT_OPT_AM GREATER LIBINT_MAX_AM) + set(LIBINT_OPT_AM ${LIBINT_MAX_AM}) + endif() + endif() +endif() + +message(STATUS "Preparing generic LIBINT_OPT_AM_LIST ${LIBINT_OPT_AM_LIST} and LIBINT_OPT_AM ${LIBINT_OPT_AM} for integrals class defaults.") + +# <<< Macro >>> + +macro(process_integrals_class class) + + list(LENGTH ENABLE_${class} _ntokens) + if (NOT _ntokens EQUAL 1) + message(FATAL_ERROR "Invalid value for ENABLE_${class} (${ENABLE_${class}}). Use scalar of maximum derivative level, not list.") + endif() + + if (ENABLE_${class} GREATER_EQUAL 0) + set(INCLUDE_${class} ${ENABLE_${class}}) + + foreach(_d RANGE 0 ${_max_deriv}) + if (${_d} LESS_EQUAL ${INCLUDE_${class}}) + set(_candidate0_${class}_d${_d} ${_dflt_candidate0_d${_d}}) + message(VERBOSE "setting _candidate0_${class}_d${_d}=${_candidate0_${class}_d${_d}}") + endif() + endforeach() + + set(LIBINT_SUPPORTS_${class} yes) + set(LIBINT_${class}_DERIV ${INCLUDE_${class}}) + message(STATUS "Enabling integrals class ${class} to derivative ${INCLUDE_${class}}") + else() + set(INCLUDE_${class} "-1") + set(${class}_MAX_AM "") + set(${class}_MAX_AM_LIST "") + message(STATUS "Disabling integrals class ${class}") + endif() + + if (ENABLE_${class} GREATER_EQUAL 0) + list(LENGTH WITH_${class}_MAX_AM _ntokens) + if (_ntokens GREATER 1) + math(EXPR _ntokens_xptd_max_deriv "${INCLUDE_${class}} + 1") + if (NOT _ntokens_xptd_max_deriv EQUAL _ntokens) + message(FATAL_ERROR "Invalid value for WITH_${class}_MAX_AM (${WITH_${class}_MAX_AM}). ENABLE_${class} derivative (${INCLUDE_${class}}) requires list length ${_ntokens_xptd_max_deriv}, not ${_ntokens}.") + endif() + + foreach(_d RANGE ${INCLUDE_${class}}) + list(GET WITH_${class}_MAX_AM ${_d} _candidate_${class}_d${_d}) + message(VERBOSE "setting _candidate_${class}_d${_d}=${_candidate_${class}_d${_d}}") + + if (_candidate_${class}_d${_d} LESS_EQUAL 0) + message(FATAL_ERROR "Invalid value for WITH_${class}_MAX_AM derivative element ${_d} (${_candidate_${class}_d${_d}} <= 0).") + endif() + endforeach() + + list(JOIN WITH_${class}_MAX_AM "," ${class}_MAX_AM_LIST) + set(${class}_MAX_AM "") + else() + set(${class}_MAX_AM_LIST "") + if (WITH_${class}_MAX_AM EQUAL -1) + foreach(_d RANGE ${INCLUDE_${class}}) + if (${_candidate0_${class}_d${_d}} EQUAL -1) + set(_candidate_${class}_d${_d} ${_candidate0_${class}_d0}) + else() + set(_candidate_${class}_d${_d} ${_candidate0_${class}_d${_d}}) + endif() + message(VERBOSE "setting _candidate_${class}_d${_d}=${_candidate_${class}_d${_d}}") + endforeach() + + set(${class}_MAX_AM "") + # note: could set class_MAX_AM/LIST from default (in configure.ac, looks like at least scalar var set) + # but philosophy is to set user-only intent and leave further defaulting to compiled code. wrong? + else() + set(${class}_MAX_AM ${WITH_${class}_MAX_AM}) + + foreach(_d RANGE ${INCLUDE_${class}}) + set(_candidate_${class}_d${_d} ${${class}_MAX_AM}) + message(VERBOSE "setting _candidate_${class}_d${_d}=${_candidate_${class}_d${_d}}") + endforeach() + + if (${class}_MAX_AM GREATER_EQUAL ${LIBINT_HARD_MAX_AM}) + message(WARNING "Value for ${class}_MAX_AM too high (${${class}_MAX_AM} >= ${LIBINT_HARD_MAX_AM}). Are you sure you know what you are doing?") + elseif (${class}_MAX_AM LESS_EQUAL 0) + message(FATAL_ERROR "Invalid value for ${class}_MAX_AM (${${class}_MAX_AM} <= 0).") + endif() + endif() + endif() + if (LIBINT_MAX_AM_LIST) + set(_msg ${LIBINT_MAX_AM_LIST}) + else() + set(_msg ${LIBINT_MAX_AM}) + endif() + message(STATUS "Enabling integrals class ${class} to max AM ${${class}_MAX_AM}${${class}_MAX_AM_LIST} (else ${_msg})") + + list(LENGTH WITH_${class}_OPT_AM _ntokens) + if (_ntokens GREATER 1) + if (NOT _ntokens_xptd_max_deriv EQUAL _ntokens) + message(FATAL_ERROR "Invalid value for WITH_${class}_OPT_AM (${WITH_${class}_OPT_AM}). ENABLE_${class} derivative (${INCLUDE_${class}}) requires list length ${_ntokens_xptd_max_deriv}, not ${_ntokens}.") + endif() + + list(JOIN WITH_${class}_OPT_AM "," ${class}_OPT_AM_LIST) + set(${class}_OPT_AM "") + else() + set(${class}_OPT_AM_LIST "") + if (WITH_${class}_OPT_AM EQUAL -1) + set(${class}_OPT_AM "") + else() + set(${class}_OPT_AM ${WITH_${class}_OPT_AM}) + endif() + endif() + if (LIBINT_OPT_AM_LIST) + set(_msg ${LIBINT_OPT_AM_LIST}) + else() + set(_msg ${LIBINT_OPT_AM}) + endif() + message(STATUS "Enabling integrals class ${class} to opt AM ${${class}_OPT_AM}${${class}_OPT_AM_LIST} (else ${_msg})") + endif() +endmacro() + + +macro(process_integrals_class_alt class) + + list(LENGTH ENABLE_${class} _ntokens) + if (NOT _ntokens EQUAL 1) + message(FATAL_ERROR "Invalid value for ENABLE_${class} (${ENABLE_${class}}). Use scalar of maximum derivative level, not list.") + endif() + + if (ENABLE_${class} GREATER_EQUAL 0) + set(INCLUDE_${class} ${ENABLE_${class}}) + + foreach(_d RANGE 0 ${_max_deriv}) + if (${_d} LESS_EQUAL ${INCLUDE_${class}}) + # no per-d defaults. use energy + set(_candidate0_${class}_d${_d} ${_dflt_candidate0_d0}) + message(VERBOSE "setting _candidate0_${class}_d${_d}=${_candidate0_${class}_d${_d}}") + endif() + endforeach() + + set(LIBINT_SUPPORTS_${class} yes) + set(LIBINT_${class}_DERIV ${INCLUDE_${class}}) + message(STATUS "Enabling integrals class ${class} to derivative ${INCLUDE_${class}}") + else() + set(INCLUDE_${class} "-1") + set(${class}_MAX_AM "") + message(STATUS "Disabling integrals class ${class}") + endif() + + if (ENABLE_${class} GREATER_EQUAL 0) + list(LENGTH WITH_${class}_MAX_AM _ntokens) + if (_ntokens GREATER 1) + message(FATAL_ERROR "Invalid value for WITH_${class}_MAX_AM (${WITH_${class}_MAX_AM}). ENABLE_${class} derivative supports only scalar, not list length ${_ntokens}.") + + else() + if (WITH_${class}_MAX_AM EQUAL -1) + foreach(_d RANGE ${INCLUDE_${class}}) + set(_candidate_${class}_d${_d} ${_candidate0_${class}_d0}) + message(VERBOSE "setting _candidate_${class}_d${_d}=${_candidate_${class}_d0}") + endforeach() + + set(_${class}_MAX_AM_pre "") + set(${class}_MAX_AM ${_candidate0_${class}_d0}) + # note: unlike usual classes, C++ code seems to want class_MAX_AM set explicitly to config.h + else() + set(_${class}_MAX_AM_pre ${WITH_${class}_MAX_AM}) + set(${class}_MAX_AM ${WITH_${class}_MAX_AM}) + + foreach(_d RANGE ${INCLUDE_${class}}) + set(_candidate_${class}_d${_d} ${${class}_MAX_AM}) + message(VERBOSE "setting _candidate_${class}_d${_d}=${_candidate_${class}_d${_d}}") + endforeach() + + if (${class}_MAX_AM GREATER_EQUAL ${LIBINT_HARD_MAX_AM}) + message(WARNING "Value for ${class}_MAX_AM too high (${${class}_MAX_AM} >= ${LIBINT_HARD_MAX_AM}). Are you sure you know what you are doing?") + elseif (${class}_MAX_AM LESS_EQUAL 0) + message(FATAL_ERROR "Invalid value for ${class}_MAX_AM (${${class}_MAX_AM} <= 0).") + endif() + endif() + endif() + message(STATUS "Enabling integrals class ${class} to max AM ${_${class}_MAX_AM_pre} (else ${LIBINT_MAX_AM})") + + list(LENGTH WITH_${class}_OPT_AM _ntokens) + if (_ntokens GREATER 1) + message(FATAL_ERROR "Invalid value for WITH_${class}_OPT_AM (${WITH_${class}_OPT_AM}). ENABLE_${class} derivative supports only scalar, not list length ${_ntokens}.") + + else() + if (WITH_${class}_OPT_AM EQUAL -1) + set(_${class}_OPT_AM_pre "") + set(${class}_OPT_AM ${LIBINT_OPT_AM}) + # note: unlike usual classes, C++ code seems to want class_MAX_AM set explicitly + else() + set(_${class}_OPT_AM_pre ${WITH_${class}_OPT_AM}) + set(${class}_OPT_AM ${WITH_${class}_OPT_AM}) + endif() + endif() + message(STATUS "Enabling integrals class ${class} to opt AM ${_${class}_OPT_AM_pre} (else ${LIBINT_OPT_AM})") + endif() +endmacro() + + +process_integrals_class(ONEBODY) +process_integrals_class(ERI) +process_integrals_class(ERI3) +process_integrals_class(ERI2) +# unlike above, these classes (1) don't do AM_LIST and (2) require value in config.h if enabled +process_integrals_class_alt(G12) +process_integrals_class_alt(G12DKH) + +if (ENABLE_G12 GREATER_EQUAL 0) + set(SUPPORT_T1G12 ${ENABLE_T1G12_SUPPORT}) +else() + set(SUPPORT_T1G12 OFF) +endif() + +add_feature_info( + "general integral" + "ON" + "config.h: LIBINT_MAX_AM=${LIBINT_MAX_AM} LIBINT_MAX_AM_LIST=${LIBINT_MAX_AM_LIST} LIBINT_OPT_AM=${LIBINT_OPT_AM} LIBINT_OPT_AM_LIST=${LIBINT_OPT_AM_LIST}" + ) + +# form list of active class + deriv + max_am strings to use in libint2-config.cmake +# * this generates components in same order as export/cmake/configuration-gen.py +set(Libint2_ERI_COMPONENTS "") +set(_amlist "") +set(_eri3_impure_sh "") +set(_eri2_impure_sh "") +add_feature_info( + "integral class MULTIPOLE derivative 0" + "MULTIPOLE_MAX_ORDER" + "max_am ${MULTIPOLE_MAX_ORDER}" + ) +foreach(_l RANGE ${LIBINT_HARD_MIN_AM} ${MULTIPOLE_MAX_ORDER}) + # RANGE with count-down works but docs say behavior is undefined, so we count-up and reverse + # RANGE starting at 2 avoids enumerating s, p + set(_lbl "multipole_${_am${_l}}${_am${_l}}_d0") + list(APPEND _amlist "${_lbl}") +endforeach() +list(REVERSE _amlist) +list(APPEND Libint2_ERI_COMPONENTS "${_amlist}") +message(VERBOSE "setting components ${_amlist}") + +foreach(_cls ONEBODY;ERI;ERI3;ERI2;G12;G12DKH) + if((_cls STREQUAL G12) OR (_cls STREQUAL G12DKH)) + add_feature_info( + "integral class ${_cls}" + "INCLUDE_${_cls} GREATER -1" + "config.h: INCLUDE_${_cls}=${INCLUDE_${_cls}} ${_cls}_MAX_AM=${${_cls}_MAX_AM} ${_cls}_OPT_AM=${${_cls}_OPT_AM}" + ) + else() + add_feature_info( + "integral class ${_cls}" + "INCLUDE_${_cls} GREATER -1" + "config.h: INCLUDE_${_cls}=${INCLUDE_${_cls}} ${_cls}_MAX_AM=${${_cls}_MAX_AM} ${_cls}_MAX_AM_LIST=${${_cls}_MAX_AM_LIST} ${_cls}_OPT_AM=${${_cls}_OPT_AM} ${_cls}_OPT_AM_LIST=${${_cls}_OPT_AM_LIST}" + ) + endif() + if(_cls STREQUAL "G12DKH") + # add G12DKH below when it's granted components + continue() + endif() + if (INCLUDE_${_cls} GREATER -1) + foreach (_d RANGE 0 ${INCLUDE_${_cls}}) + add_feature_info( + "integral class ${_cls} derivative ${_d}" + "INCLUDE_${_cls} GREATER -1" + "max_am ${_candidate_${_cls}_d${_d}}" + ) + set(_amlist "") + set(_pureamlist "") + foreach(_l RANGE ${LIBINT_HARD_MIN_AM} ${_candidate_${_cls}_d${_d}}) # LIBINT_cls_MAX_AM[_LIST] + if (_cls STREQUAL "ERI") + list(APPEND _amlist "eri_${_am${_l}}${_am${_l}}${_am${_l}}${_am${_l}}_d${_d}") + elseif (_cls STREQUAL "ERI2") + list(APPEND _amlist "eri_${_AM${_l}}${_AM${_l}}_d${_d}") + list(APPEND _pureamlist "eri_${_am${_l}}${_am${_l}}_d${_d}") + elseif (_cls STREQUAL "ONEBODY") + list(APPEND _amlist "onebody_${_am${_l}}${_am${_l}}_d${_d}") + elseif (_cls STREQUAL "G12") + list(APPEND _amlist "g12_${_am${_l}}${_am${_l}}${_am${_l}}${_am${_l}}_d${_d}") + endif() + endforeach() + if (_cls STREQUAL "ERI3") + foreach(_lfit RANGE ${LIBINT_HARD_MIN_AM} ${_candidate_${_cls}_d${_d}}) # LIBINT_ERI3_MAX_AM[_LIST], fitting + foreach(_lpr RANGE ${LIBINT_HARD_MIN_AM} ${_eri3_candidate0_d${_d}}) # LIBINT_MAX_AM[_LIST], paired + if (_lfit GREATER_EQUAL _lpr) + list(APPEND _amlist "eri_${_am${_lpr}}${_am${_lpr}}${_AM${_lfit}}_d${_d}") + list(APPEND _pureamlist "eri_${_am${_lpr}}${_am${_lpr}}${_am${_lfit}}_d${_d}") + endif() + endforeach() + endforeach() + endif() + list(REVERSE _amlist) + list(APPEND Libint2_ERI_COMPONENTS "${_amlist}") + message(VERBOSE "setting components ${_amlist}") + list(REVERSE _pureamlist) + if (_cls STREQUAL "ERI2") + list(APPEND _eri2_impure_sh "${_pureamlist}") + elseif (_cls STREQUAL "ERI3") + list(APPEND _eri3_impure_sh "${_pureamlist}") + endif() + endforeach() + if ((_cls STREQUAL "ERI3") AND NOT ERI3_PURE_SH) + list(APPEND Libint2_ERI_COMPONENTS "${_eri3_impure_sh}") + message(VERBOSE "setting components ${_eri3_impure_sh}") + elseif ((_cls STREQUAL "ERI2") AND NOT ERI2_PURE_SH) + list(APPEND Libint2_ERI_COMPONENTS "${_eri2_impure_sh}") + message(VERBOSE "setting components ${_eri2_impure_sh}") + endif() + endif() +endforeach() +message(STATUS "Library will satisfy ERI AM components: ${Libint2_ERI_COMPONENTS}") diff --git a/cmake/modules/options.cmake b/cmake/modules/options.cmake new file mode 100644 index 000000000..921dc7371 --- /dev/null +++ b/cmake/modules/options.cmake @@ -0,0 +1,187 @@ +### based on https://github.com/psi4/psi4/blob/master/cmake/psi4OptionsTools.cmake + +#Macro for printing an option in a consistent manner +# +#Syntax: print_option(