mirror of
https://github.com/cp2k/cp2k.git
synced 2026-07-27 05:35:28 -04:00
Make GRPP an internal dependency
Co-authored-by: Mathieu Taillefumier <mathieu.taillefumier@free.fr>
This commit is contained in:
parent
a60d89c369
commit
cbdeaffe0e
79 changed files with 54582 additions and 319 deletions
|
|
@ -50,8 +50,8 @@ endif()
|
|||
# set language and standard
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_HIP_STANDARD 11)
|
||||
set(CMAKE_CUDA_STANDARD 11)
|
||||
set(CMAKE_HIP_STANDARD 14)
|
||||
set(CMAKE_CUDA_STANDARD 14)
|
||||
# remove NDEBUG flag
|
||||
string(REPLACE "-DNDEBUG" "" CMAKE_C_FLAGS_RELEASE ${CMAKE_C_FLAGS_RELEASE})
|
||||
string(REPLACE "-DNDEBUG" "" CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE})
|
||||
|
|
@ -724,10 +724,6 @@ if(CP2K_USE_TREXIO)
|
|||
find_package(TrexIO REQUIRED)
|
||||
endif()
|
||||
|
||||
if(CP2K_USE_GRPP)
|
||||
# we need grpp when TREXIO is on
|
||||
find_package(grpp REQUIRED CONFIG)
|
||||
endif()
|
||||
# OPTION HANDLING
|
||||
|
||||
# make sure that the default build type is RELEASE
|
||||
|
|
@ -931,9 +927,7 @@ if(CP2K_USE_DLAF)
|
|||
endif()
|
||||
|
||||
if(CP2K_USE_GRPP)
|
||||
message(" - grpp\n" # let below line separate
|
||||
" - include directories: ${GRPP_INCLUDE_DIRS}\n"
|
||||
" - libraries: ${GRPP_LINK_LIBRARIES}\n\n")
|
||||
message(" - grpp\n")
|
||||
endif()
|
||||
|
||||
if(CP2K_USE_TREXIO)
|
||||
|
|
|
|||
10
INSTALL.md
10
INSTALL.md
|
|
@ -454,12 +454,10 @@ Calls to `offload_dgemm` also accept pointers on GPU or a combination of them.
|
|||
|
||||
### 2y. libgrpp (optional, enables calculations with ECPs)
|
||||
|
||||
- libgrpp is a library for the calculation of integrals with GTOs and ECPs
|
||||
- The libgrpp library can be found under <https://github.com/aoleynichenko/libgrpp>
|
||||
- During the installation, the directories `$(LIBGRPP_DIR)/lib` and `$(LIBGRPP_DIR)/include` are
|
||||
created.
|
||||
- Add `-D__LIBGRPP` to DFLAGS, `-I$(LIBGRPP_DIR)/include` to FCFLAGS and
|
||||
`-L$(LIBGRPP_DIR)/lib -llibgrpp` to LIBS
|
||||
libgrpp is a library for the calculation of integrals with GTOs and ECPs. The source code of the
|
||||
library is part of cp2k.
|
||||
|
||||
- Add `-D__LIBGRPP` to DFLAGS.
|
||||
|
||||
<!---
|
||||
### 2y. LibMaxwell (External Maxwell Solver)
|
||||
|
|
|
|||
|
|
@ -161,12 +161,7 @@ endif
|
|||
|
||||
ifneq ($(USE_LIBGRPP),)
|
||||
USE_LIBGRPP := $(strip $(USE_LIBGRPP))
|
||||
LIBGRPP_INC := $(INSTALL_PATH)/libgrpp-main-$(USE_LIBGRPP)/include
|
||||
LIBGRPP_INC += -I$(INSTALL_PATH)/libgrpp-main-$(USE_LIBGRPP)/include/libgrpp/GNU-$(GNU_VER)/fortran_modules
|
||||
LIBGRPP_LIB := $(INSTALL_PATH)/libgrpp-main-$(USE_LIBGRPP)/lib
|
||||
CFLAGS += -I$(LIBGRPP_INC)
|
||||
DFLAGS += -D__LIBGRPP
|
||||
LIBS += $(LIBGRPP_LIB)/libgrpp.a
|
||||
endif
|
||||
|
||||
ifneq ($(USE_LIBINT),)
|
||||
|
|
|
|||
|
|
@ -144,12 +144,7 @@ endif
|
|||
|
||||
ifneq ($(USE_LIBGRPP),)
|
||||
USE_LIBGRPP := $(strip $(USE_LIBGRPP))
|
||||
LIBGRPP_INC := $(INSTALL_PATH)/libgrpp-main-$(USE_LIBGRPP)/include
|
||||
LIBGRPP_INC += -I$(INSTALL_PATH)/libgrpp-main-$(USE_LIBGRPP)/include/libgrpp/GNU-$(GNU_VER)/fortran_modules
|
||||
LIBGRPP_LIB := $(INSTALL_PATH)/libgrpp-main-$(USE_LIBGRPP)/lib
|
||||
CFLAGS += -I$(LIBGRPP_INC)
|
||||
DFLAGS += -D__LIBGRPP
|
||||
LIBS += $(LIBGRPP_LIB)/libgrpp.a
|
||||
endif
|
||||
|
||||
ifneq ($(USE_LIBINT),)
|
||||
|
|
|
|||
|
|
@ -168,12 +168,7 @@ endif
|
|||
|
||||
ifneq ($(USE_LIBGRPP),)
|
||||
USE_LIBGRPP := $(strip $(USE_LIBGRPP))
|
||||
LIBGRPP_INC := $(INSTALL_PATH)/libgrpp-main-$(USE_LIBGRPP)/include
|
||||
LIBGRPP_INC += -I$(INSTALL_PATH)/libgrpp-main-$(USE_LIBGRPP)/include/libgrpp/GNU-$(GNU_VER)/fortran_modules
|
||||
LIBGRPP_LIB := $(INSTALL_PATH)/libgrpp-main-$(USE_LIBGRPP)/lib
|
||||
CFLAGS += -I$(LIBGRPP_INC)
|
||||
DFLAGS += -D__LIBGRPP
|
||||
LIBS += $(LIBGRPP_LIB)/libgrpp.a
|
||||
endif
|
||||
|
||||
ifneq ($(USE_LIBINT),)
|
||||
|
|
|
|||
|
|
@ -165,12 +165,7 @@ endif
|
|||
|
||||
ifneq ($(USE_LIBGRPP),)
|
||||
USE_LIBGRPP := $(strip $(USE_LIBGRPP))
|
||||
LIBGRPP_INC := $(INSTALL_PATH)/libgrpp-main-$(USE_LIBGRPP)/include
|
||||
LIBGRPP_INC += -I$(INSTALL_PATH)/libgrpp-main-$(USE_LIBGRPP)/include/libgrpp/GNU-$(GNU_VER)/fortran_modules
|
||||
LIBGRPP_LIB := $(INSTALL_PATH)/libgrpp-main-$(USE_LIBGRPP)/lib
|
||||
CFLAGS += -I$(LIBGRPP_INC)
|
||||
DFLAGS += -D__LIBGRPP
|
||||
LIBS += $(LIBGRPP_LIB)/libgrpp.a
|
||||
endif
|
||||
|
||||
ifneq ($(USE_LIBINT),)
|
||||
|
|
|
|||
|
|
@ -102,12 +102,7 @@ endif
|
|||
|
||||
ifneq ($(USE_LIBGRPP),)
|
||||
USE_LIBGRPP := $(strip $(USE_LIBGRPP))
|
||||
LIBGRPP_INC := $(INSTALL_PATH)/libgrpp-main-$(USE_LIBGRPP)/include
|
||||
LIBGRPP_INC += -I$(INSTALL_PATH)/libgrpp-main-$(USE_LIBGRPP)/include/libgrpp/GNU-$(GNU_VER)/fortran_modules
|
||||
LIBGRPP_LIB := $(INSTALL_PATH)/libgrpp-main-$(USE_LIBGRPP)/lib
|
||||
CFLAGS += -I$(LIBGRPP_INC)
|
||||
DFLAGS += -D__LIBGRPP
|
||||
LIBS += $(LIBGRPP_LIB)/libgrpp.a
|
||||
endif
|
||||
|
||||
ifneq ($(USE_LIBINT),)
|
||||
|
|
|
|||
|
|
@ -121,12 +121,7 @@ endif
|
|||
|
||||
ifneq ($(USE_LIBGRPP),)
|
||||
USE_LIBGRPP := $(strip $(USE_LIBGRPP))
|
||||
LIBGRPP_INC := $(INSTALL_PATH)/libgrpp-main-$(USE_LIBGRPP)/include
|
||||
LIBGRPP_INC += -I$(INSTALL_PATH)/libgrpp-main-$(USE_LIBGRPP)/include/libgrpp/GNU-$(GNU_VER)/fortran_modules
|
||||
LIBGRPP_LIB := $(INSTALL_PATH)/libgrpp-main-$(USE_LIBGRPP)/lib
|
||||
CFLAGS += -I$(LIBGRPP_INC)
|
||||
DFLAGS += -D__LIBGRPP
|
||||
LIBS += $(LIBGRPP_LIB)/libgrpp.a
|
||||
endif
|
||||
|
||||
ifneq ($(USE_LIBINT),)
|
||||
|
|
|
|||
|
|
@ -223,12 +223,7 @@ endif
|
|||
|
||||
ifneq ($(USE_LIBGRPP),)
|
||||
USE_LIBGRPP := $(strip $(USE_LIBGRPP))
|
||||
LIBGRPP_INC := $(INSTALL_PATH)/libgrpp-main-$(USE_LIBGRPP)/include
|
||||
LIBGRPP_INC += -I$(INSTALL_PATH)/libgrpp-main-$(USE_LIBGRPP)/include/libgrpp/GNU-$(GNU_VER)/fortran_modules
|
||||
LIBGRPP_LIB := $(INSTALL_PATH)/libgrpp-main-$(USE_LIBGRPP)/lib
|
||||
CFLAGS += -I$(LIBGRPP_INC)
|
||||
DFLAGS += -D__LIBGRPP
|
||||
LIBS += $(LIBGRPP_LIB)/libgrpp.a
|
||||
endif
|
||||
|
||||
ifneq ($(USE_LIBINT),)
|
||||
|
|
|
|||
|
|
@ -128,12 +128,7 @@ endif
|
|||
|
||||
ifneq ($(USE_LIBGRPP),)
|
||||
USE_LIBGRPP := $(strip $(USE_LIBGRPP))
|
||||
LIBGRPP_INC := $(INSTALL_PATH)/libgrpp-main-$(USE_LIBGRPP)/include
|
||||
LIBGRPP_INC += -I$(INSTALL_PATH)/libgrpp-main-$(USE_LIBGRPP)/include/libgrpp/GNU-$(GNU_VER)/fortran_modules
|
||||
LIBGRPP_LIB := $(INSTALL_PATH)/libgrpp-main-$(USE_LIBGRPP)/lib
|
||||
CFLAGS += -I$(LIBGRPP_INC)
|
||||
DFLAGS += -D__LIBGRPP
|
||||
LIBS += $(LIBGRPP_LIB)/libgrpp.a
|
||||
endif
|
||||
|
||||
ifneq ($(USE_LIBINT),)
|
||||
|
|
|
|||
|
|
@ -248,12 +248,7 @@ endif
|
|||
|
||||
ifneq ($(USE_LIBGRPP),)
|
||||
USE_LIBGRPP := $(strip $(USE_LIBGRPP))
|
||||
LIBGRPP_INC := $(INSTALL_PATH)/libgrpp-main-$(USE_LIBGRPP)/include
|
||||
LIBGRPP_INC += -I$(INSTALL_PATH)/libgrpp-main-$(USE_LIBGRPP)/include/libgrpp/GNU-$(GNU_VER)/fortran_modules
|
||||
LIBGRPP_LIB := $(INSTALL_PATH)/libgrpp-main-$(USE_LIBGRPP)/lib
|
||||
CFLAGS += -I$(LIBGRPP_INC)
|
||||
DFLAGS += -D__LIBGRPP
|
||||
LIBS += $(LIBGRPP_LIB)/libgrpp.a
|
||||
endif
|
||||
|
||||
ifneq ($(USE_LIBINT),)
|
||||
|
|
|
|||
|
|
@ -202,12 +202,7 @@ endif
|
|||
|
||||
ifneq ($(USE_LIBGRPP),)
|
||||
USE_LIBGRPP := $(strip $(USE_LIBGRPP))
|
||||
LIBGRPP_INC := $(INSTALL_PATH)/libgrpp-main-$(USE_LIBGRPP)/include
|
||||
LIBGRPP_INC += -I$(INSTALL_PATH)/libgrpp-main-$(USE_LIBGRPP)/include/libgrpp/GNU-$(GNU_VER)/fortran_modules
|
||||
LIBGRPP_LIB := $(INSTALL_PATH)/libgrpp-main-$(USE_LIBGRPP)/lib
|
||||
CFLAGS += -I$(LIBGRPP_INC)
|
||||
DFLAGS += -D__LIBGRPP
|
||||
LIBS += $(LIBGRPP_LIB)/liblibgrpp.a
|
||||
endif
|
||||
|
||||
ifneq ($(USE_LIBINT),)
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ if [[ "${PROFILE}" == "spack" ]] && [[ "${VERSION}" == "psmp" ]]; then
|
|||
-DCP2K_USE_COSMA=ON \
|
||||
-DCP2K_USE_SIRIUS=ON \
|
||||
-DCP2K_USE_LIBVDWXC=ON \
|
||||
-DCP2K_USE_GRPP=OFF \
|
||||
-DCP2K_USE_GRPP=ON \
|
||||
-DCP2K_USE_TREXIO=ON \
|
||||
-DCP2K_USE_LIBTORCH=ON \
|
||||
-DCP2K_USE_DLAF=ON \
|
||||
|
|
@ -82,7 +82,7 @@ elif [[ "${PROFILE}" == "toolchain" ]] && [[ "${VERSION}" == "ssmp" ]]; then
|
|||
-DCP2K_USE_DFTD4=ON \
|
||||
-DCP2K_USE_DLAF=OFF \
|
||||
-DCP2K_USE_FFTW3=ON \
|
||||
-DCP2K_USE_GRPP=OFF \
|
||||
-DCP2K_USE_GRPP=ON \
|
||||
-DCP2K_USE_HDF5=ON \
|
||||
-DCP2K_USE_LIBINT2=ON \
|
||||
-DCP2K_USE_LIBTORCH=ON \
|
||||
|
|
@ -129,7 +129,7 @@ elif [[ "${PROFILE}" == "toolchain" ]] && [[ "${VERSION}" == "psmp" ]]; then
|
|||
-DCP2K_USE_DLAF=OFF \
|
||||
-DCP2K_USE_ELPA=ON \
|
||||
-DCP2K_USE_FFTW3=ON \
|
||||
-DCP2K_USE_GRPP=OFF \
|
||||
-DCP2K_USE_GRPP=ON \
|
||||
-DCP2K_USE_HDF5=ON \
|
||||
-DCP2K_USE_LIBINT2=ON \
|
||||
-DCP2K_USE_LIBSMEAGOL=ON \
|
||||
|
|
|
|||
|
|
@ -1404,6 +1404,46 @@ set(CP2K_GRID_SRCS_C
|
|||
grid/cpu/grid_cpu_task_list.c
|
||||
grid/grid_replay.c)
|
||||
|
||||
set(CP2K_GRPP_SRCS_C
|
||||
grpp/grpp_angular_integrals.c
|
||||
grpp/grpp_binomial.c
|
||||
grpp/grpp_diff_gaussian.c
|
||||
grpp/grpp_factorial.c
|
||||
grpp/grpp_fortran.c
|
||||
grpp/grpp_full_grpp_integrals.c
|
||||
grpp/grpp.c
|
||||
grpp/grpp_integrals_gradient.c
|
||||
grpp/grpp_init_finalize.c
|
||||
grpp/grpp_kinetic.c
|
||||
grpp/grpp_lmatrix.c
|
||||
grpp/grpp_momentum.c
|
||||
grpp/grpp_norm_gaussian.c
|
||||
grpp/grpp_nuclear_attraction.c
|
||||
grpp/grpp_nuclear_models.c
|
||||
grpp/grpp_outercore_integrals.c
|
||||
grpp/grpp_overlap.c
|
||||
grpp/grpp_overlap_gradient.c
|
||||
grpp/grpp_parameters.c
|
||||
grpp/grpp_potential.c
|
||||
grpp/grpp_radial_type1_integral.c
|
||||
grpp/grpp_radial_type2_integral.c
|
||||
grpp/grpp_screening.c
|
||||
grpp/grpp_shell.c
|
||||
grpp/grpp_specfunc_bessel_table.c
|
||||
grpp/grpp_specfunc_boys.c
|
||||
grpp/grpp_specfunc_dawson.c
|
||||
grpp/grpp_specfunc_fermi_sk.c
|
||||
grpp/grpp_specfunc_gfun.c
|
||||
grpp/grpp_specfunc_scaled_mod_sph_bessel.c
|
||||
grpp/grpp_spherical_harmonics.c
|
||||
grpp/grpp_spin_orbit_integrals.c
|
||||
grpp/grpp_type1_integrals.c
|
||||
grpp/grpp_type1_mcmurchie_davidson.c
|
||||
grpp/grpp_type2_integrals.c
|
||||
grpp/grpp_utils.c)
|
||||
|
||||
set(CP2K_GRPP_SRCS_F grpp/libgrpp.F)
|
||||
|
||||
set(CP2K_FPGA_SRC_C pw/fpga/fft_fpga.c pw/fpga/opencl_utils.c)
|
||||
set(CP2K_PW_SRCS_C pw/gpu/pw_gpu_internal.c)
|
||||
set(CP2K_OFFLOAD_SRCS_C offload/offload_buffer.c offload/offload_library.c)
|
||||
|
|
@ -1489,6 +1529,10 @@ endif()
|
|||
|
||||
list(APPEND CP2K_SRCS_C ${CP2K_DBM_SRCS_C} ${CP2K_GRID_SRCS_C})
|
||||
|
||||
if(CP2K_USE_GRPP)
|
||||
list(APPEND CP2K_SRCS_C ${CP2K_GRPP_SRCS_C})
|
||||
list(APPEND CP2K_SRCS_F ${CP2K_GRPP_SRCS_F})
|
||||
endif()
|
||||
# ##############################################################################
|
||||
# check that the files registered in CMakeLists.txt are all present and return
|
||||
# an error otherwise. cmake only runs this test nothing else below
|
||||
|
|
@ -1496,12 +1540,12 @@ list(APPEND CP2K_SRCS_C ${CP2K_DBM_SRCS_C} ${CP2K_GRID_SRCS_C})
|
|||
|
||||
if(CP2K_ENABLE_CONSISTENCY_CHECKS)
|
||||
cp2k_compare_src_with_list(
|
||||
"${CP2K_FPGA_SRC_C};${CP2K_SRCS_C};${CP2K_OFFLOAD_SRCS_C};${CP2K_DBM_SRCS_C};${CP2K_GRID_SRCS_C};${CP2K_PW_SRCS_C};${CP2K_DBM_SRCS_GPU_C};${CP2K_PROGS_C}"
|
||||
"${CP2K_FPGA_SRC_C};${CP2K_SRCS_C};${CP2K_OFFLOAD_SRCS_C};${CP2K_DBM_SRCS_C};${CP2K_GRID_SRCS_C};${CP2K_PW_SRCS_C};${CP2K_DBM_SRCS_GPU_C};${CP2K_PROGS_C};${CP2K_GRPP_SRCS_C}"
|
||||
"*.c"
|
||||
"${CP2K_EXCLUDED_SRCS_C}")
|
||||
cp2k_compare_src_with_list(
|
||||
"${CP2K_SRCS_F};${CP2K_OFFLOAD_SRCS_F};${CP2K_PROGS_F}" "*.F"
|
||||
"${CP2K_EXCLUDED_SRCS_F}")
|
||||
"${CP2K_GRPP_SRCS_F};${CP2K_SRCS_F};${CP2K_OFFLOAD_SRCS_F};${CP2K_PROGS_F}"
|
||||
"*.F" "${CP2K_EXCLUDED_SRCS_F}")
|
||||
cp2k_compare_src_with_list(
|
||||
"${CP2K_GRID_SRCS_GPU};${CP2K_GRID_SRCS_HIP};${CP2K_DBM_SRCS_GPU};${CP2K_PW_SRCS_GPU}"
|
||||
"*.cu"
|
||||
|
|
@ -1658,7 +1702,6 @@ target_link_libraries(
|
|||
$<$<BOOL:${CP2K_USE_COSMA}>:cosma::cosma>
|
||||
$<$<BOOL:${CP2K_USE_DLAF}>:DLAF::Fortran>
|
||||
$<$<BOOL:${CP2K_USE_TREXIO}>:cp2k::trexio::trexio>
|
||||
$<$<BOOL:${CP2K_USE_GRPP}>:cp2k::grpp::grpp>
|
||||
$<$<BOOL:${CP2K_USE_HDF5}>:HDF5::HDF5
|
||||
hdf5::hdf5_fortran>
|
||||
DBCSR::dbcsr
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
"shg_int",
|
||||
"arnoldi",
|
||||
"grid",
|
||||
"grpp",
|
||||
"dbm",
|
||||
"dbt",
|
||||
"dbx",
|
||||
|
|
|
|||
21
src/grpp/LICENSE
Normal file
21
src/grpp/LICENSE
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2023 Alexander Oleynichenko
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
5
src/grpp/PACKAGE
Normal file
5
src/grpp/PACKAGE
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"description": "grpp library",
|
||||
"requires": [],
|
||||
"public": ["libgrpp.F"],
|
||||
}
|
||||
140
src/grpp/README.md
Normal file
140
src/grpp/README.md
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
# libgrpp
|
||||
|
||||
A library for the evaluation of molecular integrals of the generalized relativistic pseudopotential
|
||||
operator (GRPP) over Gaussian functions.
|
||||
|
||||
# Features
|
||||
|
||||
- basis functions:
|
||||
|
||||
- Cartesian contracted GTOs
|
||||
- max angular momentum of basis functions $l_{max} = 10$ (up to $n$-functions, can be increased by
|
||||
hands)
|
||||
|
||||
- RPP integrals:
|
||||
|
||||
- scalar-relativistic part: integrals over the local potential (type 1 integrals)
|
||||
- scalar-relativistic part: integrals with angular projectors (type 2 integrals)
|
||||
- integrals over the effective spin-orbit (SO) interaction operator
|
||||
- integrals over GRPP-specific non-local terms (with projectors onto subvalence shells)
|
||||
- analytic gradients of GRPP integrals
|
||||
|
||||
- other one-electron integrals:
|
||||
|
||||
- overlap integrals
|
||||
- nuclear attraction integrals
|
||||
|
||||
- C and Fortran 90 interfaces
|
||||
|
||||
- no dependence on external libraries
|
||||
|
||||
- thread safety
|
||||
|
||||
# What is a generalized pseudopotential?
|
||||
|
||||
[Generalized relativistic pseudopotentials (GRPPs)](https://onlinelibrary.wiley.com/doi/10.1002/%28SICI%291097-461X%281999%2971%3A5%3C359%3A%3AAID-QUA1%3E3.0.CO%3B2-U)
|
||||
of atomic cores imply the use of different potentials for atomic electronic shells with different
|
||||
principal quantum numbers. GRPPs give rise to accurate and reliable relativistic electronic
|
||||
structure models of [atoms](https://onlinelibrary.wiley.com/doi/abs/10.1002/qua.26076),
|
||||
[molecules](https://www.mdpi.com/2073-8994/15/1/197),
|
||||
[clusters](https://pubs.rsc.org/en/content/articlelanding/2022/CP/D2CP01738E) and
|
||||
[solids](https://journals.aps.org/prb/abstract/10.1103/PhysRevB.103.205105). GRPPs readily
|
||||
incorporate the effects of
|
||||
[Breit electron–electron interactions](https://iopscience.iop.org/article/10.1088/0953-4075/37/23/004)
|
||||
and
|
||||
[one-loop quantum electrodynamics effects](https://onlinelibrary.wiley.com/doi/abs/10.1002/qua.27077).
|
||||
GRPPs are one of the most precise relativistic Hamiltonians at the moment, allowing one to
|
||||
completely bypass any complicated four-component calculations.
|
||||
|
||||
Library of generalized pseudopotentials:
|
||||
[http://qchem.pnpi.spb.ru/recp](http://qchem.pnpi.spb.ru/recp)
|
||||
|
||||
# How to compile examples and run tests
|
||||
|
||||
```
|
||||
mkdir build
|
||||
cd build
|
||||
CC=icc FC=ifort cmake ..
|
||||
make
|
||||
make test
|
||||
```
|
||||
|
||||
# Citation
|
||||
|
||||
A. V. Oleynichenko, A. Zaitsevskii, N. S. Mosyagin, A. N. Petrov, E. Eliav, A. V. Titov.
|
||||
|
||||
LIBGRPP: A Library for the Evaluation of Molecular Integrals of the Generalized Relativistic
|
||||
Pseudopotential Operator over Gaussian Functions.
|
||||
|
||||
<i>Symmetry</i>, 15(1), 197 (2023)
|
||||
|
||||
doi: [10.3390/sym15010197](https://doi.org/10.3390/sym15010197)
|
||||
|
||||
```
|
||||
@article{Oleynichenko2023,
|
||||
title = {{LIBGRPP}: A library for the evaluation of molecular integrals of the generalized relativistic pseudopotential operator over {G}aussian functions},
|
||||
author = {A. V. Oleynichenko and A. Zaitsevskii and N. S. Mosyagin and A. N. Petrov and E. Eliav and A. V. Titov},
|
||||
year = {2022},
|
||||
journal = {Symmetry},
|
||||
volume = {15},
|
||||
year = {2023},
|
||||
number = {1},
|
||||
article-number = {197},
|
||||
url = {https://www.mdpi.com/2073-8994/15/1/197},
|
||||
doi = {10.3390/sym15010197}
|
||||
}
|
||||
```
|
||||
|
||||
# Bug report
|
||||
|
||||
Alexander Oleynichenko, alexvoleynichenko@gmail.com
|
||||
|
||||
# References: more on algorithms used
|
||||
|
||||
- type 1 integrals (local part):
|
||||
|
||||
- L. E. McMurchie, E. R. Davidson. One- and two-electron integrals over Cartesian Gaussian
|
||||
functions.
|
||||
[<i>J. Comput. Phys.</i> 26, 218 (1978)](<https://doi.org/10.1016/0021-9991(78)90092-X>)
|
||||
|
||||
- J. O. Jensen, A. H. Carrieri, C. P. Vlahacos, D. Zeroka, H. F. Hameka, C. N. Merrow. Evaluation
|
||||
of one-electron integrals for arbitrary operators $V(r)$ over Cartesian Gaussians: Application
|
||||
to inverse-square distance and Yukawa operators.
|
||||
[<i>J. Comput. Chem.</i> 14, 986 (1993)](https://doi.org/10.1002/jcc.540140814)
|
||||
|
||||
- B. Gao, A. J. Thorvaldsen, K. Ruud. GEN1INT: A unified procedure for the evaluation of
|
||||
one-electron integrals over Gaussian basis functions and their geometric derivatives.
|
||||
[<i>Int. J. Quantum Chem.</i> 111, 858 (2011)](https://doi.org/10.1002/qua.22886)
|
||||
|
||||
- type 2 integrals (semilocal part):
|
||||
|
||||
- L. E. McMurchie, E. R. Davidson. Calculation of integrals over ab initio pseudopotentials.
|
||||
[<i>J. Comput. Phys.</i> 44, 289 (1981)](<https://doi.org/10.1016/0021-9991(81)90053-X>)
|
||||
|
||||
- C. K. Skylaris, L. Gagliardi, N. C. Handy, A. G. Ioannou, S. Spencer, A. Willetts, A. M. Simper.
|
||||
An efficient method for calculating effective core potential integrals which involve projection
|
||||
operators.
|
||||
[<i>Chem. Phys. Lett.</i> 296, 445 (1998)](<https://doi.org/10.1016/S0009-2614(98)01077-X>)
|
||||
|
||||
- R. Flores-Moreno, R. J. Alvarez-Mendez, A. Vela, A. M. Köster. Half-numerical evaluation of
|
||||
pseudopotential integrals.
|
||||
[<i>J. Comput. Chem.</i> 27, 1009 (2006)](https://doi.org/10.1002/jcc.20410)
|
||||
|
||||
- C. van Wüllen. Numerical instabilities in the computation of pseudopotential matrix elements.
|
||||
[<i>J. Comput. Chem.</i> 27, 135 (2006)](https://doi.org/10.1002/jcc.20325)
|
||||
|
||||
- R. A. Shaw, J. G. Hill. Prescreening and efficiency in the evaluation of integrals over ab
|
||||
initio effective core potentials.
|
||||
[<i>J. Chem. Phys.</i> 147, 074108 (2017)](https://doi.org/10.1063/1.4986887)
|
||||
|
||||
- spin-orbit integrals:
|
||||
|
||||
- R. M. Pitzer, N. W. Winter. Spin-orbit (core) and core potential integrals.
|
||||
[<i>Int. J. Quantum Chem.</i> 40, 773 (1991)](https://doi.org/10.1002/qua.560400606)
|
||||
|
||||
- integrals non-local terms (with projectors onto subvalence shells):
|
||||
|
||||
- A. V. Oleynichenko, A. Zaitsevskii, N. S. Mosyagin, A. N. Petrov, E. Eliav, A. V. Titov.
|
||||
LIBGRPP: A library for the evaluation of molecular integrals of the generalized relativistic
|
||||
pseudopotential operator over Gaussian functions.
|
||||
[<i>Symmetry</i>, 15(1), 197 (2023).](https://doi.org/10.3390/sym15010197)
|
||||
113
src/grpp/grpp.c
Normal file
113
src/grpp/grpp.c
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
/*----------------------------------------------------------------------------*/
|
||||
/* CP2K: A general program to perform molecular dynamics simulations */
|
||||
/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
|
||||
/* */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* libgrpp - a library for the evaluation of integrals over
|
||||
* generalized relativistic pseudopotentials.
|
||||
*
|
||||
* Copyright (C) 2021-2023 Alexander Oleynichenko
|
||||
*/
|
||||
|
||||
#include "libgrpp.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#define LIBGRPP_MAX_NUMBER_POTENTIALS 100
|
||||
|
||||
libgrpp_grpp_t *libgrpp_new_grpp() {
|
||||
return (libgrpp_grpp_t *)calloc(1, sizeof(libgrpp_grpp_t));
|
||||
}
|
||||
|
||||
void libgrpp_grpp_set_local_potential(libgrpp_grpp_t *grpp,
|
||||
libgrpp_potential_t *pot) {
|
||||
if (grpp->U_L != NULL) {
|
||||
libgrpp_delete_potential(grpp->U_L);
|
||||
}
|
||||
|
||||
grpp->U_L = pot;
|
||||
}
|
||||
|
||||
void libgrpp_grpp_add_averaged_potential(libgrpp_grpp_t *grpp,
|
||||
libgrpp_potential_t *pot) {
|
||||
if (grpp->n_arep == 0) {
|
||||
grpp->U_arep = (libgrpp_potential_t **)calloc(
|
||||
LIBGRPP_MAX_NUMBER_POTENTIALS, sizeof(libgrpp_potential_t *));
|
||||
}
|
||||
|
||||
grpp->U_arep[grpp->n_arep++] = pot;
|
||||
}
|
||||
|
||||
void libgrpp_grpp_add_spin_orbit_potential(libgrpp_grpp_t *grpp,
|
||||
libgrpp_potential_t *pot) {
|
||||
if (grpp->n_esop == 0) {
|
||||
grpp->U_esop = (libgrpp_potential_t **)calloc(
|
||||
LIBGRPP_MAX_NUMBER_POTENTIALS, sizeof(libgrpp_potential_t *));
|
||||
}
|
||||
|
||||
grpp->U_esop[grpp->n_esop++] = pot;
|
||||
}
|
||||
|
||||
void libgrpp_grpp_add_outercore_potential(libgrpp_grpp_t *grpp,
|
||||
libgrpp_potential_t *pot,
|
||||
libgrpp_shell_t *oc_shell) {
|
||||
if (grpp->n_oc_shells == 0) {
|
||||
grpp->U_oc = (libgrpp_potential_t **)calloc(LIBGRPP_MAX_NUMBER_POTENTIALS,
|
||||
sizeof(libgrpp_potential_t *));
|
||||
grpp->oc_shells = (libgrpp_shell_t **)calloc(LIBGRPP_MAX_NUMBER_POTENTIALS,
|
||||
sizeof(libgrpp_shell_t *));
|
||||
}
|
||||
|
||||
grpp->U_oc[grpp->n_oc_shells] = pot;
|
||||
grpp->oc_shells[grpp->n_oc_shells] = oc_shell;
|
||||
grpp->n_oc_shells++;
|
||||
}
|
||||
|
||||
void libgrpp_delete_grpp(libgrpp_grpp_t *grpp) {
|
||||
if (grpp == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* scalar-relativistic part
|
||||
*/
|
||||
if (grpp->U_L != NULL) {
|
||||
libgrpp_delete_potential(grpp->U_L);
|
||||
}
|
||||
|
||||
for (int i = 0; i < grpp->n_arep; i++) {
|
||||
if (grpp->U_arep[i] != NULL) {
|
||||
libgrpp_delete_potential(grpp->U_arep[i]);
|
||||
}
|
||||
}
|
||||
free(grpp->U_arep);
|
||||
|
||||
/*
|
||||
* effective spin-orbit operator
|
||||
*/
|
||||
for (int i = 0; i < grpp->n_esop; i++) {
|
||||
if (grpp->U_esop[i] != NULL) {
|
||||
libgrpp_delete_potential(grpp->U_esop[i]);
|
||||
}
|
||||
}
|
||||
free(grpp->U_esop);
|
||||
|
||||
/*
|
||||
* outercore shells and potentials
|
||||
*/
|
||||
for (int i = 0; i < grpp->n_oc_shells; i++) {
|
||||
if (grpp->U_oc[i] != NULL) {
|
||||
libgrpp_delete_potential(grpp->U_oc[i]);
|
||||
}
|
||||
if (grpp->oc_shells[i] != NULL) {
|
||||
libgrpp_delete_shell(grpp->oc_shells[i]);
|
||||
}
|
||||
}
|
||||
free(grpp->U_oc);
|
||||
free(grpp->oc_shells);
|
||||
|
||||
free(grpp);
|
||||
}
|
||||
141
src/grpp/grpp_angular_integrals.c
Normal file
141
src/grpp/grpp_angular_integrals.c
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
/*----------------------------------------------------------------------------*/
|
||||
/* CP2K: A general program to perform molecular dynamics simulations */
|
||||
/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
|
||||
/* */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* libgrpp - a library for the evaluation of integrals over
|
||||
* generalized relativistic pseudopotentials.
|
||||
*
|
||||
* Copyright (C) 2021-2023 Alexander Oleynichenko
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file contains subroutines for evaluation of angular integrals of the 1st
|
||||
* and 2nd type. It also contains functions for construction of matrices of the
|
||||
* angular momentum operator in the bases of either real or complex spherical
|
||||
* harmonics.
|
||||
*
|
||||
* For more details on the angular integrals used in RPP integration, see:
|
||||
*
|
||||
* L. E. McMurchie, E. R. Davidson. Calculation of integrals over ab initio
|
||||
* pseudopotentials. J. Comput. Phys. 44(2), 289 (1981).
|
||||
* doi: 10.1016/0021-9991(81)90053-x
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
#include "grpp_angular_integrals.h"
|
||||
#include "grpp_factorial.h"
|
||||
#include "grpp_spherical_harmonics.h"
|
||||
#include "libgrpp.h"
|
||||
|
||||
static double integrate_unitary_sphere_polynomial(int i, int j, int k);
|
||||
|
||||
/**
|
||||
* Type 1 angular integral.
|
||||
* (see MrMurchie & Davidson, formula (28))
|
||||
*/
|
||||
double libgrpp_angular_type1_integral(int lambda, int II, int JJ, int KK,
|
||||
double *k) {
|
||||
double sum = 0.0;
|
||||
|
||||
for (int mu = -lambda; mu <= lambda; mu++) {
|
||||
double sum2 = 0.0;
|
||||
for (int r = 0; r <= lambda; r++) {
|
||||
for (int s = 0; s <= lambda; s++) {
|
||||
for (int t = 0; t <= lambda; t++) {
|
||||
if (r + s + t == lambda) {
|
||||
double y_lm_rst =
|
||||
libgrpp_spherical_to_cartesian_coef(lambda, mu, r, s);
|
||||
double usp_int =
|
||||
integrate_unitary_sphere_polynomial(II + r, JJ + s, KK + t);
|
||||
sum2 += y_lm_rst * usp_int;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
sum += sum2 * libgrpp_evaluate_real_spherical_harmonic(lambda, mu, k);
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Type 2 angular integral.
|
||||
* (see MrMurchie & Davidson, formula (29))
|
||||
*/
|
||||
double libgrpp_angular_type2_integral(const int lambda, const int L,
|
||||
const int m, const int a, const int b,
|
||||
const int c, const double *rsh_values) {
|
||||
double sum = 0.0;
|
||||
|
||||
rsh_coef_table_t *rsh_coef_lambda =
|
||||
libgrpp_get_real_spherical_harmonic_table(lambda);
|
||||
rsh_coef_table_t *rsh_coef_L = libgrpp_get_real_spherical_harmonic_table(L);
|
||||
|
||||
int ncomb_rst = rsh_coef_lambda->n_cart_comb;
|
||||
int ncomb_uvw = rsh_coef_L->n_cart_comb;
|
||||
|
||||
for (int mu = -lambda; mu <= lambda; mu++) {
|
||||
double sum2 = 0.0;
|
||||
double rsh_value_k = rsh_values[mu + lambda];
|
||||
if (fabs(rsh_value_k) < LIBGRPP_ZERO_THRESH) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int icomb_uvw = 0; icomb_uvw < ncomb_uvw; icomb_uvw++) {
|
||||
|
||||
int u = rsh_coef_L->cartesian_comb[3 * icomb_uvw];
|
||||
int v = rsh_coef_L->cartesian_comb[3 * icomb_uvw + 1];
|
||||
int w = rsh_coef_L->cartesian_comb[3 * icomb_uvw + 2];
|
||||
double y_lm_uvw = rsh_coef_L->coeffs[(m + L) * ncomb_uvw + icomb_uvw];
|
||||
if (fabs(y_lm_uvw) < LIBGRPP_ZERO_THRESH) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int icomb_rst = 0; icomb_rst < ncomb_rst; icomb_rst++) {
|
||||
|
||||
int r = rsh_coef_lambda->cartesian_comb[3 * icomb_rst];
|
||||
int s = rsh_coef_lambda->cartesian_comb[3 * icomb_rst + 1];
|
||||
int t = rsh_coef_lambda->cartesian_comb[3 * icomb_rst + 2];
|
||||
double y_lam_mu_rst =
|
||||
rsh_coef_lambda->coeffs[(mu + lambda) * ncomb_rst + icomb_rst];
|
||||
if (fabs(y_lam_mu_rst) < LIBGRPP_ZERO_THRESH) {
|
||||
continue;
|
||||
}
|
||||
|
||||
double usp_int = integrate_unitary_sphere_polynomial(
|
||||
a + r + u, b + s + v, c + t + w);
|
||||
|
||||
sum2 += y_lam_mu_rst * y_lm_uvw * usp_int;
|
||||
}
|
||||
}
|
||||
|
||||
sum += sum2 * rsh_value_k;
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Integral of the unitary sphere polynomial over full solid angle.
|
||||
* (see MrMurchie & Davidson, formula (30))
|
||||
*/
|
||||
static double integrate_unitary_sphere_polynomial(int i, int j, int k) {
|
||||
if ((i % 2 == 0) && (j % 2 == 0) && (k % 2 == 0)) {
|
||||
double dfac_i = (double)libgrpp_double_factorial(i - 1);
|
||||
double dfac_j = (double)libgrpp_double_factorial(j - 1);
|
||||
double dfac_k = (double)libgrpp_double_factorial(k - 1);
|
||||
double dfac_ijk = (double)libgrpp_double_factorial(i + j + k + 1);
|
||||
return 4 * M_PI * dfac_i * dfac_j * dfac_k / dfac_ijk;
|
||||
} else {
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
24
src/grpp/grpp_angular_integrals.h
Normal file
24
src/grpp/grpp_angular_integrals.h
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
/*----------------------------------------------------------------------------*/
|
||||
/* CP2K: A general program to perform molecular dynamics simulations */
|
||||
/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
|
||||
/* */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* libgrpp - a library for the evaluation of integrals over
|
||||
* generalized relativistic pseudopotentials.
|
||||
*
|
||||
* Copyright (C) 2021-2023 Alexander Oleynichenko
|
||||
*/
|
||||
|
||||
#ifndef LIBGRPP_ANGULAR_INTEGRALS_H
|
||||
#define LIBGRPP_ANGULAR_INTEGRALS_H
|
||||
|
||||
double libgrpp_angular_type1_integral(int lambda, int II, int JJ, int KK,
|
||||
double *k);
|
||||
|
||||
double libgrpp_angular_type2_integral(int lambda, int L, int m, int a, int b,
|
||||
int c, const double *rsh_values);
|
||||
|
||||
#endif // LIBGRPP_ANGULAR_INTEGRALS_H
|
||||
82
src/grpp/grpp_binomial.c
Normal file
82
src/grpp/grpp_binomial.c
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
/*----------------------------------------------------------------------------*/
|
||||
/* CP2K: A general program to perform molecular dynamics simulations */
|
||||
/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
|
||||
/* */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* libgrpp - a library for the evaluation of integrals over
|
||||
* generalized relativistic pseudopotentials.
|
||||
*
|
||||
* Copyright (C) 2021-2023 Alexander Oleynichenko
|
||||
*/
|
||||
|
||||
#include "grpp_binomial.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* The code is borrowed from RosettaCode:
|
||||
* https://rosettacode.org/wiki/Evaluate_binomial_coefficients#C
|
||||
* We go to some effort to handle overflow situations.
|
||||
*/
|
||||
|
||||
static uint64_t gcd_ui(uint64_t x, uint64_t y);
|
||||
|
||||
/*
|
||||
* returns binomial coefficient:
|
||||
* ( n )
|
||||
* ( k )
|
||||
*/
|
||||
uint64_t libgrpp_binomial(uint64_t n, uint64_t k) {
|
||||
uint64_t d, g, r = 1;
|
||||
|
||||
if (k == 0) {
|
||||
return 1;
|
||||
}
|
||||
if (k == 1) {
|
||||
return n;
|
||||
}
|
||||
if (k >= n) {
|
||||
return (k == n);
|
||||
}
|
||||
if (k > n / 2) {
|
||||
k = n - k;
|
||||
}
|
||||
for (d = 1; d <= k; d++) {
|
||||
if (r >= UINT64_MAX / n) { /* Possible overflow */
|
||||
uint64_t nr, dr; /* reduced numerator / denominator */
|
||||
g = gcd_ui(n, d);
|
||||
nr = n / g;
|
||||
dr = d / g;
|
||||
g = gcd_ui(r, dr);
|
||||
r = r / g;
|
||||
dr = dr / g;
|
||||
if (r >= UINT64_MAX / nr)
|
||||
return 0; /* Unavoidable overflow */
|
||||
r *= nr;
|
||||
r /= dr;
|
||||
n--;
|
||||
} else {
|
||||
r *= n--;
|
||||
r /= d;
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static uint64_t gcd_ui(uint64_t x, uint64_t y) {
|
||||
uint64_t t;
|
||||
|
||||
if (y < x) {
|
||||
t = x;
|
||||
x = y;
|
||||
y = t;
|
||||
}
|
||||
while (y > 0) {
|
||||
t = y;
|
||||
y = x % y;
|
||||
x = t; /* y1 <- x0 % y0 ; x1 <- y0 */
|
||||
}
|
||||
return x;
|
||||
}
|
||||
22
src/grpp/grpp_binomial.h
Normal file
22
src/grpp/grpp_binomial.h
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/*----------------------------------------------------------------------------*/
|
||||
/* CP2K: A general program to perform molecular dynamics simulations */
|
||||
/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
|
||||
/* */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* libgrpp - a library for the evaluation of integrals over
|
||||
* generalized relativistic pseudopotentials.
|
||||
*
|
||||
* Copyright (C) 2021-2023 Alexander Oleynichenko
|
||||
*/
|
||||
|
||||
#ifndef LIBGRPP_BINOMIAL_H
|
||||
#define LIBGRPP_BINOMIAL_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
uint64_t libgrpp_binomial(uint64_t n, uint64_t k);
|
||||
|
||||
#endif // LIBGRPP_BINOMIAL_H
|
||||
83
src/grpp/grpp_diff_gaussian.c
Normal file
83
src/grpp/grpp_diff_gaussian.c
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
/*----------------------------------------------------------------------------*/
|
||||
/* CP2K: A general program to perform molecular dynamics simulations */
|
||||
/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
|
||||
/* */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* libgrpp - a library for the evaluation of integrals over
|
||||
* generalized relativistic pseudopotentials.
|
||||
*
|
||||
* Copyright (C) 2021-2023 Alexander Oleynichenko
|
||||
*/
|
||||
|
||||
/*
|
||||
* Differentiation of contracted Gaussian functions.
|
||||
* Derivatives are then used to calculate analytic gradients of 1-el integrals.
|
||||
*/
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
#include "grpp_diff_gaussian.h"
|
||||
|
||||
#include "libgrpp.h"
|
||||
|
||||
static double norm_factor(double alpha, int L);
|
||||
|
||||
/**
|
||||
* Performs differentiation of a contracted Gaussian.
|
||||
*
|
||||
* Note that the "2 alpha" factors are absorbed into coefficients, while the 'n'
|
||||
* factor is not. The latter must be accounted for explicitly at the stage of
|
||||
* gradient construction. For more details, see: T. Helgaker, P. Jorgensen, J.
|
||||
* Olsen, Molecular Electronic-Structure Theory, John Wiley & Sons Ltd, 2000.
|
||||
* Chapter 9.2.2, "Recurrence relations for Cartesian Gaussians"
|
||||
*
|
||||
*/
|
||||
void libgrpp_differentiate_shell(libgrpp_shell_t *shell,
|
||||
libgrpp_shell_t **shell_minus,
|
||||
libgrpp_shell_t **shell_plus) {
|
||||
// downwards
|
||||
if (shell->L > 0) {
|
||||
*shell_minus =
|
||||
libgrpp_new_shell(shell->origin, shell->L - 1, shell->num_primitives,
|
||||
shell->coeffs, shell->alpha);
|
||||
|
||||
for (int i = 0; i < shell->num_primitives; i++) {
|
||||
|
||||
double alpha = shell->alpha[i];
|
||||
double L = shell->L;
|
||||
|
||||
(*shell_minus)->coeffs[i] *=
|
||||
norm_factor(alpha, L) / norm_factor(alpha, L - 1);
|
||||
}
|
||||
} else {
|
||||
*shell_minus = NULL;
|
||||
}
|
||||
|
||||
// upwards
|
||||
*shell_plus =
|
||||
libgrpp_new_shell(shell->origin, shell->L + 1, shell->num_primitives,
|
||||
shell->coeffs, shell->alpha);
|
||||
for (int i = 0; i < shell->num_primitives; i++) {
|
||||
|
||||
double alpha = shell->alpha[i];
|
||||
double L = shell->L;
|
||||
|
||||
(*shell_plus)->coeffs[i] *=
|
||||
2.0 * alpha * norm_factor(alpha, L) / norm_factor(alpha, L + 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates normalization factor for the primitive Gaussian
|
||||
* with the exponential parameter 'alpha' and angular momentum L.
|
||||
*/
|
||||
static double norm_factor(double alpha, int L) {
|
||||
return pow(2 * alpha / M_PI, 0.75) * pow(4 * alpha, 0.5 * L);
|
||||
}
|
||||
29
src/grpp/grpp_diff_gaussian.h
Normal file
29
src/grpp/grpp_diff_gaussian.h
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
/*----------------------------------------------------------------------------*/
|
||||
/* CP2K: A general program to perform molecular dynamics simulations */
|
||||
/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
|
||||
/* */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* libgrpp - a library for the evaluation of integrals over
|
||||
* generalized relativistic pseudopotentials.
|
||||
*
|
||||
* Copyright (C) 2021-2023 Alexander Oleynichenko
|
||||
*/
|
||||
|
||||
/*
|
||||
* Differentiation of contracted Gaussian functions.
|
||||
* Derivatives are then used to calculate analytic gradients of 1-el integrals.
|
||||
*/
|
||||
|
||||
#ifndef LIBGRPP_DIFF_GAUSSIAN_H
|
||||
#define LIBGRPP_DIFF_GAUSSIAN_H
|
||||
|
||||
#include "libgrpp_types.h"
|
||||
|
||||
void libgrpp_differentiate_shell(libgrpp_shell_t *shell,
|
||||
libgrpp_shell_t **shell_minus,
|
||||
libgrpp_shell_t **shell_plus);
|
||||
|
||||
#endif // LIBGRPP_DIFF_GAUSSIAN_H
|
||||
116
src/grpp/grpp_factorial.c
Normal file
116
src/grpp/grpp_factorial.c
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
/*----------------------------------------------------------------------------*/
|
||||
/* CP2K: A general program to perform molecular dynamics simulations */
|
||||
/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
|
||||
/* */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* libgrpp - a library for the evaluation of integrals over
|
||||
* generalized relativistic pseudopotentials.
|
||||
*
|
||||
* Copyright (C) 2021-2023 Alexander Oleynichenko
|
||||
*/
|
||||
|
||||
#include "grpp_factorial.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
|
||||
static uint64_t pretabulated_factorials[] = {1,
|
||||
1,
|
||||
2,
|
||||
6,
|
||||
24,
|
||||
120,
|
||||
720,
|
||||
5040,
|
||||
40320,
|
||||
362880,
|
||||
3628800,
|
||||
39916800,
|
||||
479001600,
|
||||
6227020800,
|
||||
87178291200,
|
||||
1307674368000,
|
||||
20922789888000,
|
||||
355687428096000,
|
||||
6402373705728000,
|
||||
121645100408832000,
|
||||
2432902008176640000};
|
||||
|
||||
double libgrpp_factorial(int n) {
|
||||
if (n < 0) {
|
||||
return 1;
|
||||
} else if (n <= 20) {
|
||||
return (double)pretabulated_factorials[n];
|
||||
} else {
|
||||
return n * libgrpp_factorial(n - 1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculates ratio of two factorials:
|
||||
* n!
|
||||
* ----
|
||||
* m!
|
||||
*/
|
||||
double libgrpp_factorial_ratio(int n, int m) {
|
||||
if (n == m) {
|
||||
return 1.0;
|
||||
}
|
||||
if (n < m) {
|
||||
return 1.0 / libgrpp_factorial_ratio(m, n);
|
||||
} else { // n > m
|
||||
double prod = 1.0;
|
||||
for (int i = m + 1; i <= n; i++) {
|
||||
prod *= i;
|
||||
}
|
||||
return prod;
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t pretabulated_double_factorials[] = {
|
||||
1, // 0!!
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
8,
|
||||
15, // 5!!
|
||||
48,
|
||||
105,
|
||||
384,
|
||||
945,
|
||||
3840, // 10!!
|
||||
10395,
|
||||
46080,
|
||||
135135,
|
||||
645120,
|
||||
2027025, // 15!!
|
||||
10321920,
|
||||
34459425,
|
||||
185794560,
|
||||
654729075,
|
||||
3715891200, // 20!!
|
||||
13749310575,
|
||||
81749606400,
|
||||
316234143225,
|
||||
1961990553600,
|
||||
7905853580625, // 25!!
|
||||
51011754393600,
|
||||
213458046676875,
|
||||
1428329123020800,
|
||||
6190283353629375,
|
||||
42849873690624000 // 30!!
|
||||
};
|
||||
|
||||
double libgrpp_double_factorial(int n) {
|
||||
assert(n >= -1 && n <= 30);
|
||||
if (n == -1) {
|
||||
return 1;
|
||||
} else if (n <= 30) {
|
||||
return (double)pretabulated_double_factorials[n];
|
||||
} else {
|
||||
return n * libgrpp_double_factorial(n - 2);
|
||||
}
|
||||
}
|
||||
24
src/grpp/grpp_factorial.h
Normal file
24
src/grpp/grpp_factorial.h
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
/*----------------------------------------------------------------------------*/
|
||||
/* CP2K: A general program to perform molecular dynamics simulations */
|
||||
/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
|
||||
/* */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* libgrpp - a library for the evaluation of integrals over
|
||||
* generalized relativistic pseudopotentials.
|
||||
*
|
||||
* Copyright (C) 2021-2023 Alexander Oleynichenko
|
||||
*/
|
||||
|
||||
#ifndef LIBGRPP_FACTORIAL_H
|
||||
#define LIBGRPP_FACTORIAL_H
|
||||
|
||||
double libgrpp_factorial(int n);
|
||||
|
||||
double libgrpp_factorial_ratio(int n, int m);
|
||||
|
||||
double libgrpp_double_factorial(int n);
|
||||
|
||||
#endif // LIBGRPP_FACTORIAL_H
|
||||
859
src/grpp/grpp_fortran.c
Normal file
859
src/grpp/grpp_fortran.c
Normal file
|
|
@ -0,0 +1,859 @@
|
|||
/*----------------------------------------------------------------------------*/
|
||||
/* CP2K: A general program to perform molecular dynamics simulations */
|
||||
/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
|
||||
/* */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* libgrpp - a library for the evaluation of integrals over
|
||||
* generalized relativistic pseudopotentials.
|
||||
*
|
||||
* Copyright (C) 2021-2023 Alexander Oleynichenko
|
||||
*/
|
||||
|
||||
/*
|
||||
* Wrappers for the LIBGRPP subroutines to be used from Fortran projects.
|
||||
*
|
||||
* C99 Fortran
|
||||
* --------------------
|
||||
* int32_t integer(4)
|
||||
* double real(8)
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "grpp_factorial.h"
|
||||
#include "libgrpp.h"
|
||||
|
||||
/*
|
||||
* Fine-tuning of the LIBGRPP internal parameters.
|
||||
*/
|
||||
|
||||
void libgrpp_set_default_parameters_() { libgrpp_set_default_parameters(); }
|
||||
|
||||
void libgrpp_set_radial_tolerance_(const double *tolerance) {
|
||||
libgrpp_set_radial_tolerance(*tolerance);
|
||||
}
|
||||
|
||||
void libgrpp_set_angular_screening_tolerance_(const double *tolerance) {
|
||||
libgrpp_set_angular_screening_tolerance(*tolerance);
|
||||
}
|
||||
|
||||
void libgrpp_set_modified_bessel_tolerance_(const double *tolerance) {
|
||||
libgrpp_set_modified_bessel_tolerance(*tolerance);
|
||||
}
|
||||
|
||||
void libgrpp_set_cartesian_order_(const int32_t *order) {
|
||||
libgrpp_set_cartesian_order(*order);
|
||||
}
|
||||
|
||||
/*
|
||||
* initialization and finalization
|
||||
*/
|
||||
void libgrpp_init_() { libgrpp_init(); }
|
||||
|
||||
void libgrpp_finalize_() { libgrpp_finalize(); }
|
||||
|
||||
/*
|
||||
* Type 1 RPP integrals (local term)
|
||||
*/
|
||||
|
||||
void libgrpp_type1_integrals_(
|
||||
// contracted Gaussian A
|
||||
double *origin_A, int32_t *L_A, int32_t *num_primitives_A, double *coeffs_A,
|
||||
double *alpha_A,
|
||||
// contracted Gaussian B
|
||||
double *origin_B, int32_t *L_B, int32_t *num_primitives_B, double *coeffs_B,
|
||||
double *alpha_B,
|
||||
// pseudopotential
|
||||
double *rpp_origin, int32_t *rpp_num_primitives, int32_t *rpp_powers,
|
||||
double *rpp_coeffs, double *rpp_alpha,
|
||||
// answer
|
||||
double *matrix) {
|
||||
int *pot_powers_int = (int *)calloc(*rpp_num_primitives, sizeof(int));
|
||||
|
||||
for (int i = 0; i < *rpp_num_primitives; i++) {
|
||||
pot_powers_int[i] = rpp_powers[i];
|
||||
}
|
||||
|
||||
libgrpp_potential_t *pot = libgrpp_new_potential(
|
||||
0, 0, *rpp_num_primitives, pot_powers_int, rpp_coeffs, rpp_alpha);
|
||||
libgrpp_shell_t *shell_A =
|
||||
libgrpp_new_shell(origin_A, *L_A, *num_primitives_A, coeffs_A, alpha_A);
|
||||
libgrpp_shell_t *shell_B =
|
||||
libgrpp_new_shell(origin_B, *L_B, *num_primitives_B, coeffs_B, alpha_B);
|
||||
|
||||
libgrpp_type1_integrals(shell_A, shell_B, rpp_origin, pot, matrix);
|
||||
|
||||
libgrpp_delete_shell(shell_A);
|
||||
libgrpp_delete_shell(shell_B);
|
||||
libgrpp_delete_potential(pot);
|
||||
free(pot_powers_int);
|
||||
}
|
||||
|
||||
/*
|
||||
* Type 2 RPP integrals (semilocal terms with projectors)
|
||||
*/
|
||||
|
||||
void libgrpp_type2_integrals_(
|
||||
// contracted Gaussian A
|
||||
double *origin_A, int32_t *L_A, int32_t *num_primitives_A, double *coeffs_A,
|
||||
double *alpha_A, double *origin_B,
|
||||
// contracted Gaussian B
|
||||
int32_t *L_B, int32_t *num_primitives_B, double *coeffs_B, double *alpha_B,
|
||||
// pseudopotential
|
||||
double *pot_origin, int32_t *pot_L, int32_t *pot_num_primitives,
|
||||
int32_t *pot_powers, double *pot_coeffs, double *pot_alpha,
|
||||
// answer
|
||||
double *matrix) {
|
||||
int *pot_powers_int = (int *)calloc(*pot_num_primitives, sizeof(int));
|
||||
|
||||
for (int i = 0; i < *pot_num_primitives; i++) {
|
||||
pot_powers_int[i] = pot_powers[i];
|
||||
}
|
||||
|
||||
libgrpp_potential_t *pot = libgrpp_new_potential(
|
||||
*pot_L, 0, *pot_num_primitives, pot_powers_int, pot_coeffs, pot_alpha);
|
||||
libgrpp_shell_t *shell_A =
|
||||
libgrpp_new_shell(origin_A, *L_A, *num_primitives_A, coeffs_A, alpha_A);
|
||||
libgrpp_shell_t *shell_B =
|
||||
libgrpp_new_shell(origin_B, *L_B, *num_primitives_B, coeffs_B, alpha_B);
|
||||
|
||||
libgrpp_type2_integrals(shell_A, shell_B, pot_origin, pot, matrix);
|
||||
|
||||
libgrpp_delete_shell(shell_A);
|
||||
libgrpp_delete_shell(shell_B);
|
||||
libgrpp_delete_potential(pot);
|
||||
free(pot_powers_int);
|
||||
}
|
||||
|
||||
/*
|
||||
* Effective spin-orbit operator ("Type 3") RPP integrals (semilocal terms with
|
||||
* projectors)
|
||||
*/
|
||||
|
||||
void libgrpp_spin_orbit_integrals_(
|
||||
// contracted Gaussian A
|
||||
double *origin_A, int32_t *L_A, int32_t *num_primitives_A, double *coeffs_A,
|
||||
double *alpha_A,
|
||||
// contracted Gaussian B
|
||||
double *origin_B, int32_t *L_B, int32_t *num_primitives_B, double *coeffs_B,
|
||||
double *alpha_B,
|
||||
// pseudopotential
|
||||
double *pot_origin, int32_t *pot_L, int32_t *pot_num_primitives,
|
||||
int32_t *pot_powers, double *pot_coeffs, double *pot_alpha,
|
||||
// answer
|
||||
double *so_x_matrix, double *so_y_matrix, double *so_z_matrix) {
|
||||
int *pot_powers_int = (int *)calloc(*pot_num_primitives, sizeof(int));
|
||||
|
||||
for (int i = 0; i < *pot_num_primitives; i++) {
|
||||
pot_powers_int[i] = pot_powers[i];
|
||||
}
|
||||
|
||||
/*
|
||||
* construct RPP structure
|
||||
*/
|
||||
libgrpp_potential_t *pot = libgrpp_new_potential(
|
||||
*pot_L, 0, *pot_num_primitives, pot_powers_int, pot_coeffs, pot_alpha);
|
||||
|
||||
/*
|
||||
* construct shells
|
||||
*/
|
||||
libgrpp_shell_t *shell_A =
|
||||
libgrpp_new_shell(origin_A, *L_A, *num_primitives_A, coeffs_A, alpha_A);
|
||||
libgrpp_shell_t *shell_B =
|
||||
libgrpp_new_shell(origin_B, *L_B, *num_primitives_B, coeffs_B, alpha_B);
|
||||
|
||||
libgrpp_spin_orbit_integrals(shell_A, shell_B, pot_origin, pot, so_x_matrix,
|
||||
so_y_matrix, so_z_matrix);
|
||||
|
||||
libgrpp_delete_shell(shell_A);
|
||||
libgrpp_delete_shell(shell_B);
|
||||
libgrpp_delete_potential(pot);
|
||||
free(pot_powers_int);
|
||||
}
|
||||
|
||||
/**
|
||||
* Outercore RPP integrals (non-local terms with projectors onto outercore
|
||||
* spinors)
|
||||
*
|
||||
* Part 1: integration of the first non-local term:
|
||||
* U*|nlj><nlj| + |nlj><nlj|*U
|
||||
*/
|
||||
void libgrpp_outercore_potential_integrals_part_1_(
|
||||
// contracted Gaussian A
|
||||
double *origin_A, int32_t *L_A, int32_t *num_primitives_A, double *coeffs_A,
|
||||
double *alpha_A, double *origin_B,
|
||||
// contracted Gaussian B
|
||||
int32_t *L_B, int32_t *num_primitives_B, double *coeffs_B, double *alpha_B,
|
||||
// pseudopotential for the outercore shell LJ
|
||||
double *pot_origin, int32_t *pot_L, int32_t *pot_J,
|
||||
int32_t *pot_num_primitives, int32_t *pot_powers, double *pot_coeffs,
|
||||
double *pot_alpha,
|
||||
// expansion of the outercore shell LJ
|
||||
int32_t *oc_shell_num_primitives, double *oc_shell_coeffs,
|
||||
double *oc_shell_alpha,
|
||||
// answer
|
||||
double *arep_matrix, double *so_x_matrix, double *so_y_matrix,
|
||||
double *so_z_matrix) {
|
||||
void libgrpp_outercore_potential_integrals_part_1(
|
||||
libgrpp_shell_t * shell_A, libgrpp_shell_t * shell_B, double *C,
|
||||
libgrpp_potential_t *oc_potential, libgrpp_shell_t *oc_shell,
|
||||
double *arep_matrix, double *so_x_matrix, double *so_y_matrix,
|
||||
double *so_z_matrix);
|
||||
|
||||
/*
|
||||
* array conversion: Fortran -> C
|
||||
*/
|
||||
int *pot_powers_int = (int *)calloc(*pot_num_primitives, sizeof(int));
|
||||
for (int i = 0; i < *pot_num_primitives; i++) {
|
||||
pot_powers_int[i] = pot_powers[i];
|
||||
}
|
||||
|
||||
/*
|
||||
* construct shells
|
||||
*/
|
||||
libgrpp_shell_t *shell_A =
|
||||
libgrpp_new_shell(origin_A, *L_A, *num_primitives_A, coeffs_A, alpha_A);
|
||||
libgrpp_shell_t *shell_B =
|
||||
libgrpp_new_shell(origin_B, *L_B, *num_primitives_B, coeffs_B, alpha_B);
|
||||
|
||||
/*
|
||||
* construct pseudopotential for the given L,J numbers
|
||||
*/
|
||||
libgrpp_potential_t *oc_potential =
|
||||
libgrpp_new_potential(*pot_L, *pot_J, *pot_num_primitives, pot_powers_int,
|
||||
pot_coeffs, pot_alpha);
|
||||
|
||||
/*
|
||||
* construct outercore shell associated with the pseudopotential
|
||||
*/
|
||||
libgrpp_shell_t *oc_shell =
|
||||
libgrpp_new_shell(pot_origin, *pot_L, *oc_shell_num_primitives,
|
||||
oc_shell_coeffs, oc_shell_alpha);
|
||||
|
||||
/*
|
||||
* evaluate RPP integrals
|
||||
*/
|
||||
libgrpp_outercore_potential_integrals_part_1(
|
||||
shell_A, shell_B, pot_origin, oc_potential, oc_shell, arep_matrix,
|
||||
so_x_matrix, so_y_matrix, so_z_matrix);
|
||||
|
||||
/*
|
||||
* clean-up
|
||||
*/
|
||||
libgrpp_delete_shell(shell_A);
|
||||
libgrpp_delete_shell(shell_B);
|
||||
libgrpp_delete_potential(oc_potential);
|
||||
libgrpp_delete_shell(oc_shell);
|
||||
free(pot_powers_int);
|
||||
}
|
||||
|
||||
/**
|
||||
* Outercore RPP integrals (non-local terms with projectors onto outercore
|
||||
* spinors)
|
||||
*
|
||||
* Part 2: integration of the second non-local term:
|
||||
* |nlj><nlj| U |n'lj><n'lj|
|
||||
*/
|
||||
void libgrpp_outercore_potential_integrals_part_2_(
|
||||
// contracted Gaussian A
|
||||
double *origin_A, int32_t *L_A, int32_t *num_primitives_A, double *coeffs_A,
|
||||
double *alpha_A,
|
||||
// contracted Gaussian B
|
||||
double *origin_B, int32_t *L_B, int32_t *num_primitives_B, double *coeffs_B,
|
||||
double *alpha_B,
|
||||
// origin of the RPP
|
||||
double *pot_origin,
|
||||
// outercore shell 1:
|
||||
int32_t *oc_shell_1_L, int32_t *oc_shell_1_J, int32_t *pot1_num_primitives,
|
||||
int32_t *pot1_powers, double *pot1_coeffs, double *pot1_alpha,
|
||||
int32_t *oc_shell_1_num_primitives, double *oc_shell_1_coeffs,
|
||||
double *oc_shell_1_alpha,
|
||||
// outercore shell 2:
|
||||
int32_t *oc_shell_2_L, int32_t *oc_shell_2_J, int32_t *pot2_num_primitives,
|
||||
int32_t *pot2_powers, double *pot2_coeffs, double *pot2_alpha,
|
||||
int32_t *oc_shell_2_num_primitives, double *oc_shell_2_coeffs,
|
||||
double *oc_shell_2_alpha,
|
||||
// answer:
|
||||
double *arep_matrix, double *so_x_matrix, double *so_y_matrix,
|
||||
double *so_z_matrix) {
|
||||
void libgrpp_outercore_potential_integrals_part_2(
|
||||
libgrpp_shell_t * shell_A, libgrpp_shell_t * shell_B, double *C,
|
||||
libgrpp_potential_t *oc_potential_1, libgrpp_shell_t *oc_shell_1,
|
||||
libgrpp_potential_t *oc_potential_2, libgrpp_shell_t *oc_shell_2,
|
||||
double *arep_matrix, double *so_x_matrix, double *so_y_matrix,
|
||||
double *so_z_matrix);
|
||||
|
||||
/*
|
||||
* array conversion: Fortran -> C
|
||||
*/
|
||||
int *pot1_powers_int = (int *)calloc(*pot1_num_primitives, sizeof(int));
|
||||
int *pot2_powers_int = (int *)calloc(*pot2_num_primitives, sizeof(int));
|
||||
|
||||
for (int i = 0; i < *pot1_num_primitives; i++) {
|
||||
pot1_powers_int[i] = pot1_powers[i];
|
||||
}
|
||||
for (int i = 0; i < *pot2_num_primitives; i++) {
|
||||
pot2_powers_int[i] = pot2_powers[i];
|
||||
}
|
||||
|
||||
/*
|
||||
* construct shells
|
||||
*/
|
||||
libgrpp_shell_t *shell_A =
|
||||
libgrpp_new_shell(origin_A, *L_A, *num_primitives_A, coeffs_A, alpha_A);
|
||||
libgrpp_shell_t *shell_B =
|
||||
libgrpp_new_shell(origin_B, *L_B, *num_primitives_B, coeffs_B, alpha_B);
|
||||
|
||||
/*
|
||||
* the first outercore pseudopotential U_{n,L,J} and the corresponding
|
||||
* outercore shell
|
||||
*/
|
||||
libgrpp_potential_t *oc_potential_1 =
|
||||
libgrpp_new_potential(*oc_shell_1_L, *oc_shell_1_J, *pot1_num_primitives,
|
||||
pot1_powers_int, pot1_coeffs, pot1_alpha);
|
||||
libgrpp_shell_t *oc_shell_1 =
|
||||
libgrpp_new_shell(pot_origin, *oc_shell_1_L, *oc_shell_1_num_primitives,
|
||||
oc_shell_1_coeffs, oc_shell_1_alpha);
|
||||
|
||||
/*
|
||||
* the second outercore pseudopotential U_{n',L',J'} and the corresponding
|
||||
* outercore shell
|
||||
*/
|
||||
libgrpp_potential_t *oc_potential_2 =
|
||||
libgrpp_new_potential(*oc_shell_2_L, *oc_shell_2_J, *pot2_num_primitives,
|
||||
pot2_powers_int, pot2_coeffs, pot2_alpha);
|
||||
libgrpp_shell_t *oc_shell_2 =
|
||||
libgrpp_new_shell(pot_origin, *oc_shell_2_L, *oc_shell_2_num_primitives,
|
||||
oc_shell_2_coeffs, oc_shell_2_alpha);
|
||||
|
||||
/*
|
||||
* evaluate integrals
|
||||
*/
|
||||
libgrpp_outercore_potential_integrals_part_2(
|
||||
shell_A, shell_B, pot_origin, oc_potential_1, oc_shell_1, oc_potential_2,
|
||||
oc_shell_2, arep_matrix, so_x_matrix, so_y_matrix, so_z_matrix);
|
||||
|
||||
/*
|
||||
* clean-up
|
||||
*/
|
||||
libgrpp_delete_shell(shell_A);
|
||||
libgrpp_delete_shell(shell_B);
|
||||
libgrpp_delete_potential(oc_potential_1);
|
||||
libgrpp_delete_potential(oc_potential_2);
|
||||
libgrpp_delete_shell(oc_shell_1);
|
||||
libgrpp_delete_shell(oc_shell_2);
|
||||
free(pot1_powers_int);
|
||||
free(pot2_powers_int);
|
||||
}
|
||||
|
||||
/**
|
||||
* Analytic calculation of gradients of LOCAL potential integrals for a given
|
||||
* shell pair with respect to the point 'point_3d'.
|
||||
*/
|
||||
void libgrpp_type1_integrals_gradient_(
|
||||
// contracted Gaussian A
|
||||
double *origin_A, int32_t *L_A, int32_t *num_primitives_A, double *coeffs_A,
|
||||
double *alpha_A,
|
||||
// contracted Gaussian B
|
||||
double *origin_B, int32_t *L_B, int32_t *num_primitives_B, double *coeffs_B,
|
||||
double *alpha_B,
|
||||
// pseudopotential
|
||||
double *rpp_origin, int32_t *rpp_num_primitives, int32_t *rpp_powers,
|
||||
double *rpp_coeffs, double *rpp_alpha,
|
||||
// differentiation wrt the 3d point (x,y,z)
|
||||
double *point_3d,
|
||||
// answer: matrices d<Int>/dx, d<Int>/dy, d<Int>/dZ
|
||||
double *grad_arep_x, double *grad_arep_y, double *grad_arep_z) {
|
||||
int *pot_powers_int = (int *)calloc(*rpp_num_primitives, sizeof(int));
|
||||
double *grad_array[3];
|
||||
grad_array[0] = grad_arep_x;
|
||||
grad_array[1] = grad_arep_y;
|
||||
grad_array[2] = grad_arep_z;
|
||||
|
||||
for (int i = 0; i < *rpp_num_primitives; i++) {
|
||||
pot_powers_int[i] = rpp_powers[i];
|
||||
}
|
||||
|
||||
libgrpp_potential_t *pot = libgrpp_new_potential(
|
||||
0, 0, *rpp_num_primitives, pot_powers_int, rpp_coeffs, rpp_alpha);
|
||||
libgrpp_shell_t *shell_A =
|
||||
libgrpp_new_shell(origin_A, *L_A, *num_primitives_A, coeffs_A, alpha_A);
|
||||
libgrpp_shell_t *shell_B =
|
||||
libgrpp_new_shell(origin_B, *L_B, *num_primitives_B, coeffs_B, alpha_B);
|
||||
|
||||
libgrpp_type1_integrals_gradient(shell_A, shell_B, rpp_origin, pot, point_3d,
|
||||
grad_array);
|
||||
|
||||
libgrpp_delete_shell(shell_A);
|
||||
libgrpp_delete_shell(shell_B);
|
||||
libgrpp_delete_potential(pot);
|
||||
free(pot_powers_int);
|
||||
}
|
||||
|
||||
/**
|
||||
* Analytic calculation of gradients of SEMI-LOCAL potential integrals for a
|
||||
* given shell pair with respect to the point 'point_3d'.
|
||||
*/
|
||||
void libgrpp_type2_integrals_gradient_(
|
||||
// contracted Gaussian A
|
||||
double *origin_A, int32_t *L_A, int32_t *num_primitives_A, double *coeffs_A,
|
||||
double *alpha_A, double *origin_B,
|
||||
// contracted Gaussian B
|
||||
int32_t *L_B, int32_t *num_primitives_B, double *coeffs_B, double *alpha_B,
|
||||
// pseudopotential
|
||||
double *pot_origin, int32_t *pot_L, int32_t *pot_num_primitives,
|
||||
int32_t *pot_powers, double *pot_coeffs, double *pot_alpha,
|
||||
// differentiation wrt the 3d point (x,y,z)
|
||||
double *point_3d,
|
||||
// answer: matrices d<Int>/dx, d<Int>/dy, d<Int>/dZ
|
||||
double *grad_arep_x, double *grad_arep_y, double *grad_arep_z) {
|
||||
int *pot_powers_int = (int *)calloc(*pot_num_primitives, sizeof(int));
|
||||
for (int i = 0; i < *pot_num_primitives; i++) {
|
||||
pot_powers_int[i] = pot_powers[i];
|
||||
}
|
||||
|
||||
double *grad_array[3];
|
||||
grad_array[0] = grad_arep_x;
|
||||
grad_array[1] = grad_arep_y;
|
||||
grad_array[2] = grad_arep_z;
|
||||
|
||||
libgrpp_potential_t *pot = libgrpp_new_potential(
|
||||
*pot_L, 0, *pot_num_primitives, pot_powers_int, pot_coeffs, pot_alpha);
|
||||
libgrpp_shell_t *shell_A =
|
||||
libgrpp_new_shell(origin_A, *L_A, *num_primitives_A, coeffs_A, alpha_A);
|
||||
libgrpp_shell_t *shell_B =
|
||||
libgrpp_new_shell(origin_B, *L_B, *num_primitives_B, coeffs_B, alpha_B);
|
||||
|
||||
libgrpp_type2_integrals_gradient(shell_A, shell_B, pot_origin, pot, point_3d,
|
||||
grad_array);
|
||||
|
||||
libgrpp_delete_shell(shell_A);
|
||||
libgrpp_delete_shell(shell_B);
|
||||
libgrpp_delete_potential(pot);
|
||||
free(pot_powers_int);
|
||||
}
|
||||
|
||||
/**
|
||||
* Analytic calculation of gradients of integrals over the effective spin-orbit
|
||||
* operator (potential) for a given shell pair (with respect to the point
|
||||
* 'point_3d').
|
||||
*/
|
||||
void libgrpp_spin_orbit_integrals_gradient_(
|
||||
// contracted Gaussian A
|
||||
double *origin_A, int32_t *L_A, int32_t *num_primitives_A, double *coeffs_A,
|
||||
double *alpha_A,
|
||||
// contracted Gaussian B
|
||||
double *origin_B, int32_t *L_B, int32_t *num_primitives_B, double *coeffs_B,
|
||||
double *alpha_B,
|
||||
// pseudopotential
|
||||
double *pot_origin, int32_t *pot_L, int32_t *pot_num_primitives,
|
||||
int32_t *pot_powers, double *pot_coeffs, double *pot_alpha,
|
||||
// differentiation wrt the 3d point (x,y,z)
|
||||
double *point_3d,
|
||||
// answer: 9 matrices
|
||||
// d<SO-x>/dx, d<SO-x>/dy, d<SO-x>/dZ
|
||||
double *grad_sox_x, double *grad_sox_y, double *grad_sox_z,
|
||||
// d<SO-y>/dx, d<SO-y>/dy, d<SO-y>/dZ
|
||||
double *grad_soy_x, double *grad_soy_y, double *grad_soy_z,
|
||||
// d<SO-z>/dx, d<SO-z>/dy, d<SO-z>/dZ
|
||||
double *grad_soz_x, double *grad_soz_y, double *grad_soz_z) {
|
||||
int *pot_powers_int = (int *)calloc(*pot_num_primitives, sizeof(int));
|
||||
|
||||
double *grad_array_SO_x[3];
|
||||
grad_array_SO_x[0] = grad_sox_x;
|
||||
grad_array_SO_x[1] = grad_sox_y;
|
||||
grad_array_SO_x[2] = grad_sox_z;
|
||||
|
||||
double *grad_array_SO_y[3];
|
||||
grad_array_SO_y[0] = grad_soy_x;
|
||||
grad_array_SO_y[1] = grad_soy_y;
|
||||
grad_array_SO_y[2] = grad_soy_z;
|
||||
|
||||
double *grad_array_SO_z[3];
|
||||
grad_array_SO_z[0] = grad_soz_x;
|
||||
grad_array_SO_z[1] = grad_soz_y;
|
||||
grad_array_SO_z[2] = grad_soz_z;
|
||||
|
||||
for (int i = 0; i < *pot_num_primitives; i++) {
|
||||
pot_powers_int[i] = pot_powers[i];
|
||||
}
|
||||
|
||||
/*
|
||||
* construct RPP structure
|
||||
*/
|
||||
libgrpp_potential_t *pot = libgrpp_new_potential(
|
||||
*pot_L, 0, *pot_num_primitives, pot_powers_int, pot_coeffs, pot_alpha);
|
||||
|
||||
/*
|
||||
* construct shells
|
||||
*/
|
||||
libgrpp_shell_t *shell_A =
|
||||
libgrpp_new_shell(origin_A, *L_A, *num_primitives_A, coeffs_A, alpha_A);
|
||||
libgrpp_shell_t *shell_B =
|
||||
libgrpp_new_shell(origin_B, *L_B, *num_primitives_B, coeffs_B, alpha_B);
|
||||
|
||||
libgrpp_spin_orbit_integrals_gradient(shell_A, shell_B, pot_origin, pot,
|
||||
point_3d, grad_array_SO_x,
|
||||
grad_array_SO_y, grad_array_SO_z);
|
||||
|
||||
libgrpp_delete_shell(shell_A);
|
||||
libgrpp_delete_shell(shell_B);
|
||||
libgrpp_delete_potential(pot);
|
||||
free(pot_powers_int);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overlap integrals between two contracted Gaussians with given cartesian parts
|
||||
* x^n y^l z^m (auxiliary function)
|
||||
*/
|
||||
|
||||
void evaluate_overlap_integral_contracted_(
|
||||
// contracted Gaussian A
|
||||
double *origin_A, int32_t *n_A, int32_t *l_A, int32_t *m_A,
|
||||
int32_t *num_primitives_A, double *coeffs_A, double *alpha_A,
|
||||
// contracted Gaussian B
|
||||
double *origin_B, int32_t *n_B, int32_t *l_B, int32_t *m_B,
|
||||
int32_t *num_primitives_B, double *coeffs_B, double *alpha_B,
|
||||
// answer
|
||||
double *overlap_integral) {
|
||||
void libgrpp_overlap_integrals(libgrpp_shell_t * shell_A,
|
||||
libgrpp_shell_t * shell_B,
|
||||
double *overlap_matrix);
|
||||
|
||||
libgrpp_shell_t *shell_A = libgrpp_new_shell(
|
||||
origin_A, *n_A + *l_A + *m_A, *num_primitives_A, coeffs_A, alpha_A);
|
||||
libgrpp_shell_t *shell_B = libgrpp_new_shell(
|
||||
origin_B, *n_B + *l_B + *m_B, *num_primitives_B, coeffs_B, alpha_B);
|
||||
|
||||
shell_A->cart_size = 1;
|
||||
shell_A->cart_list[0] = *n_A;
|
||||
shell_A->cart_list[1] = *l_A;
|
||||
shell_A->cart_list[2] = *m_A;
|
||||
|
||||
shell_B->cart_size = 1;
|
||||
shell_B->cart_list[0] = *n_B;
|
||||
shell_B->cart_list[1] = *l_B;
|
||||
shell_B->cart_list[2] = *m_B;
|
||||
|
||||
libgrpp_overlap_integrals(shell_A, shell_B, overlap_integral);
|
||||
|
||||
libgrpp_delete_shell(shell_A);
|
||||
libgrpp_delete_shell(shell_B);
|
||||
}
|
||||
|
||||
/*
|
||||
* calculates normalization factor for the given contracted Gaussians
|
||||
* (auxiliary function)
|
||||
*/
|
||||
void radial_gto_norm_factor_(int32_t *L, int32_t *num_primitives,
|
||||
double *coeffs, double *alpha, double *norm) {
|
||||
*norm = 0.0;
|
||||
double S = 0.0;
|
||||
double origin[] = {0, 0, 0};
|
||||
int zero = 0;
|
||||
|
||||
evaluate_overlap_integral_contracted_(origin, L, &zero, &zero, num_primitives,
|
||||
coeffs, alpha, origin, L, &zero, &zero,
|
||||
num_primitives, coeffs, alpha, &S);
|
||||
|
||||
*norm = sqrt(libgrpp_double_factorial(2 * (*L) - 1)) / sqrt(S);
|
||||
}
|
||||
|
||||
/*
|
||||
* overlap integrals (for the shell pair)
|
||||
*/
|
||||
|
||||
void libgrpp_overlap_integrals_(
|
||||
// contracted Gaussian A
|
||||
double *origin_A, int32_t *L_A, int32_t *num_primitives_A, double *coeffs_A,
|
||||
double *alpha_A,
|
||||
// contracted Gaussian B
|
||||
double *origin_B, int32_t *L_B, int32_t *num_primitives_B, double *coeffs_B,
|
||||
double *alpha_B,
|
||||
// answer
|
||||
double *matrix) {
|
||||
libgrpp_shell_t *shell_A =
|
||||
libgrpp_new_shell(origin_A, *L_A, *num_primitives_A, coeffs_A, alpha_A);
|
||||
libgrpp_shell_t *shell_B =
|
||||
libgrpp_new_shell(origin_B, *L_B, *num_primitives_B, coeffs_B, alpha_B);
|
||||
|
||||
libgrpp_overlap_integrals(shell_A, shell_B, matrix);
|
||||
|
||||
libgrpp_delete_shell(shell_A);
|
||||
libgrpp_delete_shell(shell_B);
|
||||
}
|
||||
|
||||
/*
|
||||
* kinetic-energy integrals (for the shell pair)
|
||||
*/
|
||||
|
||||
void libgrpp_kinetic_energy_integrals_(
|
||||
// contracted Gaussian A
|
||||
double *origin_A, int32_t *L_A, int32_t *num_primitives_A, double *coeffs_A,
|
||||
double *alpha_A,
|
||||
// contracted Gaussian B
|
||||
double *origin_B, int32_t *L_B, int32_t *num_primitives_B, double *coeffs_B,
|
||||
double *alpha_B,
|
||||
// answer
|
||||
double *matrix) {
|
||||
libgrpp_shell_t *shell_A =
|
||||
libgrpp_new_shell(origin_A, *L_A, *num_primitives_A, coeffs_A, alpha_A);
|
||||
libgrpp_shell_t *shell_B =
|
||||
libgrpp_new_shell(origin_B, *L_B, *num_primitives_B, coeffs_B, alpha_B);
|
||||
|
||||
libgrpp_kinetic_energy_integrals(shell_A, shell_B, matrix);
|
||||
|
||||
libgrpp_delete_shell(shell_A);
|
||||
libgrpp_delete_shell(shell_B);
|
||||
}
|
||||
|
||||
/*
|
||||
* momentum operator integrals (for the shell pair)
|
||||
*/
|
||||
|
||||
void libgrpp_momentum_integrals_(
|
||||
// contracted Gaussian A
|
||||
double *origin_A, int32_t *L_A, int32_t *num_primitives_A, double *coeffs_A,
|
||||
double *alpha_A,
|
||||
// contracted Gaussian B
|
||||
double *origin_B, int32_t *L_B, int32_t *num_primitives_B, double *coeffs_B,
|
||||
double *alpha_B,
|
||||
// answer
|
||||
double *matrix_x, double *matrix_y, double *matrix_z) {
|
||||
libgrpp_shell_t *shell_A =
|
||||
libgrpp_new_shell(origin_A, *L_A, *num_primitives_A, coeffs_A, alpha_A);
|
||||
libgrpp_shell_t *shell_B =
|
||||
libgrpp_new_shell(origin_B, *L_B, *num_primitives_B, coeffs_B, alpha_B);
|
||||
|
||||
libgrpp_momentum_integrals(shell_A, shell_B, matrix_x, matrix_y, matrix_z);
|
||||
|
||||
libgrpp_delete_shell(shell_A);
|
||||
libgrpp_delete_shell(shell_B);
|
||||
}
|
||||
|
||||
/*
|
||||
* nuclear attraction integrals
|
||||
*/
|
||||
|
||||
void libgrpp_nuclear_attraction_integrals_(
|
||||
// contracted Gaussian A
|
||||
double *origin_A, int32_t *L_A, int32_t *num_primitives_A, double *coeffs_A,
|
||||
double *alpha_A,
|
||||
// contracted Gaussian B
|
||||
double *origin_B, int32_t *L_B, int32_t *num_primitives_B, double *coeffs_B,
|
||||
double *alpha_B,
|
||||
// potential definition
|
||||
double *charge_origin, int32_t *charge, int32_t *nuclear_model,
|
||||
double *model_params,
|
||||
// answer
|
||||
double *matrix) {
|
||||
libgrpp_shell_t *shell_A =
|
||||
libgrpp_new_shell(origin_A, *L_A, *num_primitives_A, coeffs_A, alpha_A);
|
||||
libgrpp_shell_t *shell_B =
|
||||
libgrpp_new_shell(origin_B, *L_B, *num_primitives_B, coeffs_B, alpha_B);
|
||||
|
||||
libgrpp_nuclear_attraction_integrals(shell_A, shell_B, charge_origin, *charge,
|
||||
*nuclear_model, model_params, matrix);
|
||||
|
||||
libgrpp_delete_shell(shell_A);
|
||||
libgrpp_delete_shell(shell_B);
|
||||
}
|
||||
|
||||
void libgrpp_nuclear_attraction_integrals_point_charge_(
|
||||
// contracted Gaussian A
|
||||
double *origin_A, int32_t *L_A, int32_t *num_primitives_A, double *coeffs_A,
|
||||
double *alpha_A,
|
||||
// contracted Gaussian B
|
||||
double *origin_B, int32_t *L_B, int32_t *num_primitives_B, double *coeffs_B,
|
||||
double *alpha_B,
|
||||
// potential definition
|
||||
double *charge_origin, int32_t *charge,
|
||||
// answer
|
||||
double *matrix) {
|
||||
libgrpp_shell_t *shell_A =
|
||||
libgrpp_new_shell(origin_A, *L_A, *num_primitives_A, coeffs_A, alpha_A);
|
||||
libgrpp_shell_t *shell_B =
|
||||
libgrpp_new_shell(origin_B, *L_B, *num_primitives_B, coeffs_B, alpha_B);
|
||||
|
||||
libgrpp_nuclear_attraction_integrals_point_charge(
|
||||
shell_A, shell_B, charge_origin, *charge, matrix);
|
||||
|
||||
libgrpp_delete_shell(shell_A);
|
||||
libgrpp_delete_shell(shell_B);
|
||||
}
|
||||
|
||||
void libgrpp_nuclear_attraction_integrals_charged_ball_(
|
||||
// contracted Gaussian A
|
||||
double *origin_A, int32_t *L_A, int32_t *num_primitives_A, double *coeffs_A,
|
||||
double *alpha_A,
|
||||
// contracted Gaussian B
|
||||
double *origin_B, int32_t *L_B, int32_t *num_primitives_B, double *coeffs_B,
|
||||
double *alpha_B,
|
||||
// potential definition
|
||||
double *charge_origin, int32_t *charge, double *r_rms,
|
||||
// answer
|
||||
double *matrix) {
|
||||
libgrpp_shell_t *shell_A =
|
||||
libgrpp_new_shell(origin_A, *L_A, *num_primitives_A, coeffs_A, alpha_A);
|
||||
libgrpp_shell_t *shell_B =
|
||||
libgrpp_new_shell(origin_B, *L_B, *num_primitives_B, coeffs_B, alpha_B);
|
||||
|
||||
libgrpp_nuclear_attraction_integrals_charged_ball(
|
||||
shell_A, shell_B, charge_origin, *charge, *r_rms, matrix);
|
||||
|
||||
libgrpp_delete_shell(shell_A);
|
||||
libgrpp_delete_shell(shell_B);
|
||||
}
|
||||
|
||||
void libgrpp_nuclear_attraction_integrals_gaussian_model_(
|
||||
// contracted Gaussian A
|
||||
double *origin_A, int32_t *L_A, int32_t *num_primitives_A, double *coeffs_A,
|
||||
double *alpha_A,
|
||||
// contracted Gaussian B
|
||||
double *origin_B, int32_t *L_B, int32_t *num_primitives_B, double *coeffs_B,
|
||||
double *alpha_B,
|
||||
// potential definition
|
||||
double *charge_origin, int32_t *charge, double *r_rms,
|
||||
// answer
|
||||
double *matrix) {
|
||||
libgrpp_shell_t *shell_A =
|
||||
libgrpp_new_shell(origin_A, *L_A, *num_primitives_A, coeffs_A, alpha_A);
|
||||
libgrpp_shell_t *shell_B =
|
||||
libgrpp_new_shell(origin_B, *L_B, *num_primitives_B, coeffs_B, alpha_B);
|
||||
|
||||
libgrpp_nuclear_attraction_integrals_gaussian_model(
|
||||
shell_A, shell_B, charge_origin, *charge, *r_rms, matrix);
|
||||
|
||||
libgrpp_delete_shell(shell_A);
|
||||
libgrpp_delete_shell(shell_B);
|
||||
}
|
||||
|
||||
void libgrpp_nuclear_attraction_integrals_fermi_model_(
|
||||
// contracted Gaussian A
|
||||
double *origin_A, int32_t *L_A, int32_t *num_primitives_A, double *coeffs_A,
|
||||
double *alpha_A,
|
||||
// contracted Gaussian B
|
||||
double *origin_B, int32_t *L_B, int32_t *num_primitives_B, double *coeffs_B,
|
||||
double *alpha_B,
|
||||
// potential definition
|
||||
double *charge_origin, int32_t *charge, double *fermi_param_c,
|
||||
double *fermi_param_a,
|
||||
// answer
|
||||
double *matrix) {
|
||||
libgrpp_shell_t *shell_A =
|
||||
libgrpp_new_shell(origin_A, *L_A, *num_primitives_A, coeffs_A, alpha_A);
|
||||
libgrpp_shell_t *shell_B =
|
||||
libgrpp_new_shell(origin_B, *L_B, *num_primitives_B, coeffs_B, alpha_B);
|
||||
|
||||
libgrpp_nuclear_attraction_integrals_fermi_model(
|
||||
shell_A, shell_B, charge_origin, *charge, *fermi_param_c, *fermi_param_a,
|
||||
matrix);
|
||||
|
||||
libgrpp_delete_shell(shell_A);
|
||||
libgrpp_delete_shell(shell_B);
|
||||
}
|
||||
|
||||
void libgrpp_nuclear_attraction_integrals_fermi_bubble_model_(
|
||||
// contracted Gaussian A
|
||||
double *origin_A, int32_t *L_A, int32_t *num_primitives_A, double *coeffs_A,
|
||||
double *alpha_A,
|
||||
// contracted Gaussian B
|
||||
double *origin_B, int32_t *L_B, int32_t *num_primitives_B, double *coeffs_B,
|
||||
double *alpha_B,
|
||||
// potential definition
|
||||
double *charge_origin, int32_t *charge, double *fermi_param_c,
|
||||
double *fermi_param_a, double *param_k,
|
||||
// answer
|
||||
double *matrix) {
|
||||
libgrpp_shell_t *shell_A =
|
||||
libgrpp_new_shell(origin_A, *L_A, *num_primitives_A, coeffs_A, alpha_A);
|
||||
libgrpp_shell_t *shell_B =
|
||||
libgrpp_new_shell(origin_B, *L_B, *num_primitives_B, coeffs_B, alpha_B);
|
||||
|
||||
libgrpp_nuclear_attraction_integrals_fermi_bubble_model(
|
||||
shell_A, shell_B, charge_origin, *charge, *fermi_param_c, *fermi_param_a,
|
||||
*param_k, matrix);
|
||||
|
||||
libgrpp_delete_shell(shell_A);
|
||||
libgrpp_delete_shell(shell_B);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fortran interface to the nuclear models
|
||||
*/
|
||||
|
||||
void libgrpp_estimate_nuclear_rms_radius_johnson_1985_(int32_t *A,
|
||||
double *R_rms) {
|
||||
*R_rms = libgrpp_estimate_nuclear_rms_radius_johnson_1985(*A);
|
||||
}
|
||||
|
||||
void libgrpp_estimate_nuclear_rms_radius_golovko_2008_(int32_t *A,
|
||||
double *R_rms) {
|
||||
*R_rms = libgrpp_estimate_nuclear_rms_radius_golovko_2008(*A);
|
||||
}
|
||||
|
||||
void libgrpp_estimate_fermi_model_parameters_(double *R_rms, double *c,
|
||||
double *a, int32_t *err_code) {
|
||||
*err_code = (int32_t)libgrpp_estimate_fermi_model_parameters(*R_rms, c, a);
|
||||
}
|
||||
|
||||
void libgrpp_charge_density_ball_(double *r, double *Z, double *R_rms,
|
||||
double *rho) {
|
||||
*rho = libgrpp_charge_density_ball(*r, *Z, *R_rms);
|
||||
}
|
||||
|
||||
void libgrpp_charge_density_gaussian_(double *r, double *Z, double *R_rms,
|
||||
double *rho) {
|
||||
*rho = libgrpp_charge_density_gaussian(*r, *Z, *R_rms);
|
||||
}
|
||||
|
||||
void libgrpp_charge_density_fermi_(double *r, double *Z, double *c, double *a,
|
||||
double *rho) {
|
||||
*rho = libgrpp_charge_density_fermi(*r, *Z, *c, *a);
|
||||
}
|
||||
|
||||
void libgrpp_charge_density_fermi_bubble_(double *r, double *Z, double *c,
|
||||
double *a, double *k, double *rho) {
|
||||
*rho = libgrpp_charge_density_fermi_bubble(*r, *Z, *c, *a, *k);
|
||||
}
|
||||
|
||||
void libgrpp_coulomb_potential_point_(double *r, double *Z, double *potential) {
|
||||
*potential = libgrpp_coulomb_potential_point(*r, *Z);
|
||||
}
|
||||
|
||||
void libgrpp_coulomb_potential_ball_(double *r, double *Z, double *R_rms,
|
||||
double *potential) {
|
||||
*potential = libgrpp_coulomb_potential_ball(*r, *Z, *R_rms);
|
||||
}
|
||||
|
||||
void libgrpp_coulomb_potential_gaussian_(double *r, double *Z, double *R_rms,
|
||||
double *potential) {
|
||||
*potential = libgrpp_coulomb_potential_gaussian(*r, *Z, *R_rms);
|
||||
}
|
||||
|
||||
void libgrpp_coulomb_potential_fermi_(double *r, double *Z, double *c,
|
||||
double *a, double *potential) {
|
||||
*potential = libgrpp_coulomb_potential_fermi(*r, *Z, *c, *a);
|
||||
}
|
||||
|
||||
void libgrpp_coulomb_potential_fermi_bubble_(double *r, double *Z, double *c,
|
||||
double *a, double *k,
|
||||
double *potential) {
|
||||
*potential = libgrpp_coulomb_potential_fermi_bubble(*r, *Z, *c, *a, *k);
|
||||
}
|
||||
|
||||
void libgrpp_rms_radius_fermi_(int32_t *Z, double *c, double *a,
|
||||
double *r_rms) {
|
||||
*r_rms = libgrpp_rms_radius_fermi(*Z, *c, *a);
|
||||
}
|
||||
|
||||
void libgrpp_rms_radius_fermi_bubble_(int32_t *Z, double *c, double *a,
|
||||
double *k, double *r_rms) {
|
||||
*r_rms = libgrpp_rms_radius_fermi_bubble(*Z, *c, *a, *k);
|
||||
}
|
||||
106
src/grpp/grpp_full_grpp_integrals.c
Normal file
106
src/grpp/grpp_full_grpp_integrals.c
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
/*----------------------------------------------------------------------------*/
|
||||
/* CP2K: A general program to perform molecular dynamics simulations */
|
||||
/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
|
||||
/* */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* libgrpp - a library for the evaluation of integrals over
|
||||
* generalized relativistic pseudopotentials.
|
||||
*
|
||||
* Copyright (C) 2021-2023 Alexander Oleynichenko
|
||||
*/
|
||||
|
||||
#include "libgrpp.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "grpp_utils.h"
|
||||
|
||||
/**
|
||||
* Evaluates integrals over the full GRPP operator consisting of three parts:
|
||||
* - scalar relativistic (local)
|
||||
* - scalar relativistic (semi-local)
|
||||
* - effective spin-orbit (semi-local)
|
||||
* - outercore potentials (non-local)
|
||||
*
|
||||
* See libgrpp.h for the definition of the libgrpp_grpp_t structure.
|
||||
*/
|
||||
void libgrpp_full_grpp_integrals(libgrpp_shell_t *shell_A,
|
||||
libgrpp_shell_t *shell_B,
|
||||
libgrpp_grpp_t *grpp_operator,
|
||||
double *grpp_origin, double *arep_matrix,
|
||||
double *so_x_matrix, double *so_y_matrix,
|
||||
double *so_z_matrix) {
|
||||
assert(libgrpp_is_initialized());
|
||||
|
||||
size_t size = shell_A->cart_size * shell_B->cart_size;
|
||||
double *buf_arep = (double *)calloc(size, sizeof(double));
|
||||
double *buf_so_x = (double *)calloc(size, sizeof(double));
|
||||
double *buf_so_y = (double *)calloc(size, sizeof(double));
|
||||
double *buf_so_z = (double *)calloc(size, sizeof(double));
|
||||
|
||||
memset(arep_matrix, 0, sizeof(double) * size);
|
||||
memset(so_x_matrix, 0, sizeof(double) * size);
|
||||
memset(so_y_matrix, 0, sizeof(double) * size);
|
||||
memset(so_z_matrix, 0, sizeof(double) * size);
|
||||
|
||||
/*
|
||||
* radially-local ("type-1") integrals
|
||||
*/
|
||||
libgrpp_type1_integrals(shell_A, shell_B, grpp_origin, grpp_operator->U_L,
|
||||
buf_arep);
|
||||
libgrpp_daxpy(size, 1.0, buf_arep, arep_matrix);
|
||||
|
||||
/*
|
||||
* semilocal AREP ("type-2") integrals
|
||||
*/
|
||||
for (int L = 0; L < grpp_operator->n_arep; L++) {
|
||||
libgrpp_type2_integrals(shell_A, shell_B, grpp_origin,
|
||||
grpp_operator->U_arep[L], buf_arep);
|
||||
libgrpp_daxpy(size, 1.0, buf_arep, arep_matrix);
|
||||
}
|
||||
|
||||
/*
|
||||
* semilocal SO ("type-3") integrals
|
||||
*/
|
||||
for (int i_so = 0; i_so < grpp_operator->n_esop; i_so++) {
|
||||
libgrpp_potential_t *so_potential = grpp_operator->U_esop[i_so];
|
||||
libgrpp_spin_orbit_integrals(shell_A, shell_B, grpp_origin, so_potential,
|
||||
buf_so_x, buf_so_y, buf_so_z);
|
||||
|
||||
int L = so_potential->L;
|
||||
libgrpp_daxpy(size, 2.0 / (2 * L + 1), buf_so_x, so_x_matrix);
|
||||
libgrpp_daxpy(size, 2.0 / (2 * L + 1), buf_so_y, so_y_matrix);
|
||||
libgrpp_daxpy(size, 2.0 / (2 * L + 1), buf_so_z, so_z_matrix);
|
||||
}
|
||||
|
||||
/*
|
||||
* integrals over outercore non-local potentials,
|
||||
* the part specific for GRPP.
|
||||
*
|
||||
* note that proper pre-factors for the SO part are calculated inside
|
||||
* the libgrpp_outercore_potential_integrals() procedure.
|
||||
*/
|
||||
libgrpp_outercore_potential_integrals(
|
||||
shell_A, shell_B, grpp_origin, grpp_operator->n_oc_shells,
|
||||
grpp_operator->U_oc, grpp_operator->oc_shells, buf_arep, buf_so_x,
|
||||
buf_so_y, buf_so_z);
|
||||
|
||||
libgrpp_daxpy(size, 1.0, buf_arep, arep_matrix);
|
||||
libgrpp_daxpy(size, 1.0, buf_so_x, so_x_matrix);
|
||||
libgrpp_daxpy(size, 1.0, buf_so_y, so_y_matrix);
|
||||
libgrpp_daxpy(size, 1.0, buf_so_z, so_z_matrix);
|
||||
|
||||
/*
|
||||
* cleanup
|
||||
*/
|
||||
free(buf_arep);
|
||||
free(buf_so_x);
|
||||
free(buf_so_y);
|
||||
free(buf_so_z);
|
||||
}
|
||||
49
src/grpp/grpp_init_finalize.c
Normal file
49
src/grpp/grpp_init_finalize.c
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/*----------------------------------------------------------------------------*/
|
||||
/* CP2K: A general program to perform molecular dynamics simulations */
|
||||
/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
|
||||
/* */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* libgrpp - a library for the evaluation of integrals over
|
||||
* generalized relativistic pseudopotentials.
|
||||
*
|
||||
* Copyright (C) 2021-2023 Alexander Oleynichenko
|
||||
*/
|
||||
|
||||
#include "libgrpp.h"
|
||||
|
||||
void libgrpp_create_real_spherical_harmonic_coeffs_tables(int Lmax);
|
||||
void libgrpp_pretabulate_bessel();
|
||||
|
||||
static int libgrpp_initialized = 0;
|
||||
|
||||
/**
|
||||
* thread-safe initialization
|
||||
*/
|
||||
void libgrpp_init() {
|
||||
#pragma omp critical
|
||||
{
|
||||
if (libgrpp_initialized == 0) {
|
||||
libgrpp_create_real_spherical_harmonic_coeffs_tables(40);
|
||||
libgrpp_pretabulate_bessel();
|
||||
|
||||
libgrpp_initialized = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int libgrpp_is_initialized() { return libgrpp_initialized; }
|
||||
|
||||
/**
|
||||
* thread-safe finalization
|
||||
*/
|
||||
void libgrpp_finalize() {
|
||||
#pragma omp critical
|
||||
{
|
||||
if (libgrpp_initialized == 1) {
|
||||
libgrpp_initialized = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
917
src/grpp/grpp_integrals_gradient.c
Normal file
917
src/grpp/grpp_integrals_gradient.c
Normal file
|
|
@ -0,0 +1,917 @@
|
|||
/*----------------------------------------------------------------------------*/
|
||||
/* CP2K: A general program to perform molecular dynamics simulations */
|
||||
/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
|
||||
/* */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* libgrpp - a library for the evaluation of integrals over
|
||||
* generalized relativistic pseudopotentials.
|
||||
*
|
||||
* Copyright (C) 2021-2023 Alexander Oleynichenko
|
||||
*/
|
||||
|
||||
#include "libgrpp.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "grpp_diff_gaussian.h"
|
||||
#include "grpp_utils.h"
|
||||
|
||||
void grpp_gradient_diff_bra_contribution(
|
||||
libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B,
|
||||
libgrpp_grpp_t *grpp_operator, double *grpp_origin, double **grad_arep,
|
||||
double **grad_so_x, double **grad_so_y, double **grad_so_z, double factor);
|
||||
|
||||
void grpp_gradient_diff_bra_grpp_integrals(
|
||||
libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B,
|
||||
libgrpp_grpp_t *grpp_operator, double *grpp_origin,
|
||||
double **arep_matrix_down, double **so_x_matrix_down,
|
||||
double **so_y_matrix_down, double **so_z_matrix_down,
|
||||
double **arep_matrix_up, double **so_x_matrix_up, double **so_y_matrix_up,
|
||||
double **so_z_matrix_up, int *cart_size_down, int *cart_size_up);
|
||||
|
||||
void grpp_gradient_diff_ket_contribution(
|
||||
libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B,
|
||||
libgrpp_grpp_t *grpp_operator, double *grpp_origin, double **grad_arep,
|
||||
double **grad_so_x, double **grad_so_y, double **grad_so_z, double factor);
|
||||
|
||||
void grpp_gradient_diff_ket_grpp_integrals(
|
||||
libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B,
|
||||
libgrpp_grpp_t *grpp_operator, double *grpp_origin,
|
||||
double **arep_matrix_down, double **so_x_matrix_down,
|
||||
double **so_y_matrix_down, double **so_z_matrix_down,
|
||||
double **arep_matrix_up, double **so_x_matrix_up, double **so_y_matrix_up,
|
||||
double **so_z_matrix_up, int *cart_size_down, int *cart_size_up);
|
||||
|
||||
void grpp_gradient_contribution(libgrpp_shell_t *shell_A,
|
||||
libgrpp_shell_t *shell_B,
|
||||
libgrpp_grpp_t *grpp_operator,
|
||||
double *grpp_origin, double **grad_arep,
|
||||
double **grad_so_x, double **grad_so_y,
|
||||
double **grad_so_z, int diff_bra,
|
||||
double factor);
|
||||
|
||||
void grpp_gradient_diff_gaussian(
|
||||
libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B,
|
||||
libgrpp_grpp_t *grpp_operator, double *grpp_origin,
|
||||
double **arep_matrix_down, double **so_x_matrix_down,
|
||||
double **so_y_matrix_down, double **so_z_matrix_down,
|
||||
double **arep_matrix_up, double **so_x_matrix_up, double **so_y_matrix_up,
|
||||
double **so_z_matrix_up, int *cart_size_down, int *cart_size_up,
|
||||
int diff_bra);
|
||||
|
||||
extern int libgrpp_nlm_to_linear(int *nlm);
|
||||
|
||||
double **libgrpp_alloc_gradients(libgrpp_shell_t *bra, libgrpp_shell_t *ket);
|
||||
|
||||
void libgrpp_dealloc_gradients(double **grad);
|
||||
|
||||
/**
|
||||
* Analytic calculation of gradients of LOCAL potential integrals for a given
|
||||
* shell pair with respect to the point 'point_3d'.
|
||||
*/
|
||||
void libgrpp_type1_integrals_gradient(libgrpp_shell_t *shell_A,
|
||||
libgrpp_shell_t *shell_B,
|
||||
double *grpp_origin,
|
||||
libgrpp_potential_t *potential,
|
||||
double *point_3d, double **grad_arep) {
|
||||
libgrpp_grpp_t *grpp_operator = libgrpp_new_grpp();
|
||||
libgrpp_grpp_set_local_potential(grpp_operator, potential);
|
||||
|
||||
/*
|
||||
* these arrays are not actually used.
|
||||
* they are needed only in order to use the
|
||||
* libgrpp_full_grpp_integrals_gradient() routine.
|
||||
*/
|
||||
double **stub_grad_so_x = libgrpp_alloc_gradients(shell_A, shell_B);
|
||||
double **stub_grad_so_y = libgrpp_alloc_gradients(shell_A, shell_B);
|
||||
double **stub_grad_so_z = libgrpp_alloc_gradients(shell_A, shell_B);
|
||||
|
||||
libgrpp_full_grpp_integrals_gradient(
|
||||
shell_A, shell_B, grpp_operator, grpp_origin, point_3d, grad_arep,
|
||||
stub_grad_so_x, stub_grad_so_y, stub_grad_so_z);
|
||||
|
||||
libgrpp_dealloc_gradients(stub_grad_so_x);
|
||||
libgrpp_dealloc_gradients(stub_grad_so_y);
|
||||
libgrpp_dealloc_gradients(stub_grad_so_z);
|
||||
|
||||
grpp_operator->U_L = NULL;
|
||||
libgrpp_delete_grpp(grpp_operator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Analytic calculation of gradients of SEMI-LOCAL potential integrals for a
|
||||
* given shell pair with respect to the point 'point_3d'.
|
||||
*/
|
||||
void libgrpp_type2_integrals_gradient(libgrpp_shell_t *shell_A,
|
||||
libgrpp_shell_t *shell_B,
|
||||
double *grpp_origin,
|
||||
libgrpp_potential_t *potential,
|
||||
double *point_3d, double **grad_arep) {
|
||||
libgrpp_grpp_t *grpp_operator = libgrpp_new_grpp();
|
||||
libgrpp_grpp_add_averaged_potential(grpp_operator, potential);
|
||||
|
||||
/*
|
||||
* these arrays are not actually used.
|
||||
* they are needed only in order to use the
|
||||
* libgrpp_full_grpp_integrals_gradient() routine.
|
||||
*/
|
||||
double **stub_grad_so_x = libgrpp_alloc_gradients(shell_A, shell_B);
|
||||
double **stub_grad_so_y = libgrpp_alloc_gradients(shell_A, shell_B);
|
||||
double **stub_grad_so_z = libgrpp_alloc_gradients(shell_A, shell_B);
|
||||
|
||||
libgrpp_full_grpp_integrals_gradient(
|
||||
shell_A, shell_B, grpp_operator, grpp_origin, point_3d, grad_arep,
|
||||
stub_grad_so_x, stub_grad_so_y, stub_grad_so_z);
|
||||
|
||||
libgrpp_dealloc_gradients(stub_grad_so_x);
|
||||
libgrpp_dealloc_gradients(stub_grad_so_y);
|
||||
libgrpp_dealloc_gradients(stub_grad_so_z);
|
||||
|
||||
grpp_operator->n_arep = 0;
|
||||
libgrpp_delete_grpp(grpp_operator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Analytic calculation of gradients of integrals over the effective spin-orbit
|
||||
* operator (potential) for a given shell pair (with respect to the point
|
||||
* 'point_3d').
|
||||
*/
|
||||
void libgrpp_spin_orbit_integrals_gradient(
|
||||
libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B, double *grpp_origin,
|
||||
libgrpp_potential_t *potential, double *point_3d, double **grad_so_x,
|
||||
double **grad_so_y, double **grad_so_z) {
|
||||
libgrpp_grpp_t *grpp_operator = libgrpp_new_grpp();
|
||||
libgrpp_grpp_add_spin_orbit_potential(grpp_operator, potential);
|
||||
|
||||
/*
|
||||
* this array is not actually used and is needed only in order
|
||||
* to use the libgrpp_full_grpp_integrals_gradient() routine.
|
||||
*/
|
||||
double **stub_grad_arep = libgrpp_alloc_gradients(shell_A, shell_B);
|
||||
|
||||
libgrpp_full_grpp_integrals_gradient(shell_A, shell_B, grpp_operator,
|
||||
grpp_origin, point_3d, stub_grad_arep,
|
||||
grad_so_x, grad_so_y, grad_so_z);
|
||||
|
||||
/*
|
||||
* inside the libgrpp_full_grpp_integrals_gradient() function
|
||||
* the SO potential was scaled by 2/(2L+1). Thus the result has to be
|
||||
* re-scaled by (2L+1)/2 to get rid of any problems with pre-factor
|
||||
*/
|
||||
int L = potential->L;
|
||||
int buf_size = shell_A->cart_size * shell_B->cart_size;
|
||||
for (int icoord = 0; icoord < 3; icoord++) {
|
||||
for (int i = 0; i < buf_size; i++) {
|
||||
grad_so_x[icoord][i] *= (2.0 * L + 1.0) / 2.0;
|
||||
grad_so_y[icoord][i] *= (2.0 * L + 1.0) / 2.0;
|
||||
grad_so_z[icoord][i] *= (2.0 * L + 1.0) / 2.0;
|
||||
}
|
||||
}
|
||||
|
||||
libgrpp_dealloc_gradients(stub_grad_arep);
|
||||
|
||||
grpp_operator->n_esop = 0;
|
||||
libgrpp_delete_grpp(grpp_operator);
|
||||
}
|
||||
|
||||
void libgrpp_outercore_potential_integrals_gradient(
|
||||
libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B, double *rpp_origin,
|
||||
int num_oc_shells, libgrpp_potential_t **oc_potentials,
|
||||
libgrpp_shell_t **oc_shells, double *point_3d, double **grad_arep,
|
||||
double **grad_so_x, double **grad_so_y, double **grad_so_z) {
|
||||
libgrpp_grpp_t *grpp_operator = libgrpp_new_grpp();
|
||||
for (int ioc = 0; ioc < num_oc_shells; ioc++) {
|
||||
libgrpp_grpp_add_outercore_potential(grpp_operator, oc_potentials[ioc],
|
||||
oc_shells[ioc]);
|
||||
}
|
||||
|
||||
libgrpp_full_grpp_integrals_gradient(shell_A, shell_B, grpp_operator,
|
||||
rpp_origin, point_3d, grad_arep,
|
||||
grad_so_x, grad_so_y, grad_so_z);
|
||||
|
||||
grpp_operator->n_oc_shells = 0;
|
||||
libgrpp_delete_grpp(grpp_operator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Analytic calculation of gradients of GRPP integrals for a given shell pair
|
||||
* with respect to the point 'point_3d'.
|
||||
* (for the full GRPP operator which includes local, semi-local and non-local
|
||||
* parts)
|
||||
*/
|
||||
void libgrpp_full_grpp_integrals_gradient(
|
||||
libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B,
|
||||
libgrpp_grpp_t *grpp_operator, double *grpp_origin, double *point_3d,
|
||||
double **grad_arep, double **grad_so_x, double **grad_so_y,
|
||||
double **grad_so_z) {
|
||||
int cart_size_A = shell_A->cart_size;
|
||||
int cart_size_B = shell_B->cart_size;
|
||||
int buf_size = cart_size_A * cart_size_B;
|
||||
|
||||
/*
|
||||
* initialization: set all gradients to zero
|
||||
*/
|
||||
for (int icoord = 0; icoord < 3; icoord++) {
|
||||
memset(grad_arep[icoord], 0, sizeof(double) * buf_size);
|
||||
memset(grad_so_x[icoord], 0, sizeof(double) * buf_size);
|
||||
memset(grad_so_y[icoord], 0, sizeof(double) * buf_size);
|
||||
memset(grad_so_z[icoord], 0, sizeof(double) * buf_size);
|
||||
}
|
||||
|
||||
/*
|
||||
* d<AAA>/d... = 0
|
||||
*/
|
||||
if (points_are_equal(shell_A->origin, grpp_origin) &&
|
||||
points_are_equal(shell_B->origin, grpp_origin)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* d<ACB>/dD = 0
|
||||
*/
|
||||
if (!points_are_equal(shell_A->origin, point_3d) &&
|
||||
!points_are_equal(shell_B->origin, point_3d) &&
|
||||
!points_are_equal(grpp_origin, point_3d)) {
|
||||
return;
|
||||
}
|
||||
|
||||
double *A = shell_A->origin;
|
||||
double *B = shell_B->origin;
|
||||
double *C = grpp_origin;
|
||||
double *D = point_3d;
|
||||
|
||||
const int diff_bra = 1;
|
||||
const int diff_ket = 0;
|
||||
|
||||
/*
|
||||
* Type ACB
|
||||
*/
|
||||
if (!points_are_equal(A, C) && !points_are_equal(C, B) &&
|
||||
!points_are_equal(A, B)) {
|
||||
if (points_are_equal(A, D)) {
|
||||
grpp_gradient_contribution(shell_A, shell_B, grpp_operator, grpp_origin,
|
||||
grad_arep, grad_so_x, grad_so_y, grad_so_z,
|
||||
diff_bra, +1.0);
|
||||
}
|
||||
if (points_are_equal(B, D)) {
|
||||
grpp_gradient_contribution(shell_A, shell_B, grpp_operator, grpp_origin,
|
||||
grad_arep, grad_so_x, grad_so_y, grad_so_z,
|
||||
diff_ket, +1.0);
|
||||
}
|
||||
if (points_are_equal(C, D)) {
|
||||
grpp_gradient_contribution(shell_A, shell_B, grpp_operator, grpp_origin,
|
||||
grad_arep, grad_so_x, grad_so_y, grad_so_z,
|
||||
diff_bra, -1.0);
|
||||
grpp_gradient_contribution(shell_A, shell_B, grpp_operator, grpp_origin,
|
||||
grad_arep, grad_so_x, grad_so_y, grad_so_z,
|
||||
diff_ket, -1.0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Type ACA
|
||||
*/
|
||||
if (points_are_equal(A, B) && !points_are_equal(A, C)) {
|
||||
if (points_are_equal(A, D)) {
|
||||
grpp_gradient_diff_bra_contribution(shell_A, shell_B, grpp_operator,
|
||||
grpp_origin, grad_arep, grad_so_x,
|
||||
grad_so_y, grad_so_z, +1.0);
|
||||
grpp_gradient_diff_ket_contribution(shell_A, shell_B, grpp_operator,
|
||||
grpp_origin, grad_arep, grad_so_x,
|
||||
grad_so_y, grad_so_z, +1.0);
|
||||
} else {
|
||||
grpp_gradient_diff_bra_contribution(shell_A, shell_B, grpp_operator,
|
||||
grpp_origin, grad_arep, grad_so_x,
|
||||
grad_so_y, grad_so_z, -1.0);
|
||||
grpp_gradient_diff_ket_contribution(shell_A, shell_B, grpp_operator,
|
||||
grpp_origin, grad_arep, grad_so_x,
|
||||
grad_so_y, grad_so_z, -1.0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Type ACC
|
||||
*/
|
||||
if (!points_are_equal(A, C) && points_are_equal(C, B)) {
|
||||
if (points_are_equal(A, D)) {
|
||||
grpp_gradient_contribution(shell_A, shell_B, grpp_operator, grpp_origin,
|
||||
grad_arep, grad_so_x, grad_so_y, grad_so_z,
|
||||
diff_bra, +1.0);
|
||||
} else {
|
||||
grpp_gradient_contribution(shell_A, shell_B, grpp_operator, grpp_origin,
|
||||
grad_arep, grad_so_x, grad_so_y, grad_so_z,
|
||||
diff_bra, -1.0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Type CCB
|
||||
*/
|
||||
if (points_are_equal(A, C) && !points_are_equal(C, B)) {
|
||||
if (points_are_equal(B, D)) {
|
||||
grpp_gradient_contribution(shell_A, shell_B, grpp_operator, grpp_origin,
|
||||
grad_arep, grad_so_x, grad_so_y, grad_so_z,
|
||||
diff_ket, +1.0);
|
||||
} else {
|
||||
grpp_gradient_contribution(shell_A, shell_B, grpp_operator, grpp_origin,
|
||||
grad_arep, grad_so_x, grad_so_y, grad_so_z,
|
||||
diff_ket, -1.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates contribution to gradients arising from the < df/dA | V | g > term:
|
||||
*
|
||||
* grad += factor * < df/dA | V | g >
|
||||
*
|
||||
* (bra basis function is differentiated).
|
||||
*/
|
||||
void grpp_gradient_diff_bra_contribution(
|
||||
libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B,
|
||||
libgrpp_grpp_t *grpp_operator, double *grpp_origin, double **grad_arep,
|
||||
double **grad_so_x, double **grad_so_y, double **grad_so_z, double factor) {
|
||||
/*
|
||||
* calculate integrals < df/dA | V | B >
|
||||
*/
|
||||
double *arep_matrix_down = NULL;
|
||||
double *so_x_matrix_down = NULL;
|
||||
double *so_y_matrix_down = NULL;
|
||||
double *so_z_matrix_down = NULL;
|
||||
double *arep_matrix_up = NULL;
|
||||
double *so_x_matrix_up = NULL;
|
||||
double *so_y_matrix_up = NULL;
|
||||
double *so_z_matrix_up = NULL;
|
||||
int cart_size_down = 0;
|
||||
int cart_size_up = 0;
|
||||
|
||||
grpp_gradient_diff_bra_grpp_integrals(
|
||||
shell_A, shell_B, grpp_operator, grpp_origin, &arep_matrix_down,
|
||||
&so_x_matrix_down, &so_y_matrix_down, &so_z_matrix_down, &arep_matrix_up,
|
||||
&so_x_matrix_up, &so_y_matrix_up, &so_z_matrix_up, &cart_size_down,
|
||||
&cart_size_up);
|
||||
|
||||
/*
|
||||
* construct contributions to gradients:
|
||||
* d<A|V|B>/dA += < df/dA | V | B >
|
||||
*/
|
||||
for (int icoord = 0; icoord < 3; icoord++) {
|
||||
for (int i = 0; i < shell_A->cart_size; i++) {
|
||||
for (int j = 0; j < shell_B->cart_size; j++) {
|
||||
|
||||
int bra_nlm[3];
|
||||
bra_nlm[0] = shell_A->cart_list[3 * i + 0];
|
||||
bra_nlm[1] = shell_A->cart_list[3 * i + 1];
|
||||
bra_nlm[2] = shell_A->cart_list[3 * i + 2];
|
||||
|
||||
int ket_nlm[3];
|
||||
ket_nlm[0] = shell_B->cart_list[3 * j + 0];
|
||||
ket_nlm[1] = shell_B->cart_list[3 * j + 1];
|
||||
ket_nlm[2] = shell_B->cart_list[3 * j + 2];
|
||||
|
||||
int index = i * shell_B->cart_size + j;
|
||||
|
||||
/*
|
||||
* contribution from the L-1 gaussian
|
||||
*/
|
||||
if (shell_A->L > 0) {
|
||||
bra_nlm[icoord] -= 1;
|
||||
int bra_index = libgrpp_nlm_to_linear(bra_nlm);
|
||||
int ket_index = libgrpp_nlm_to_linear(ket_nlm);
|
||||
bra_nlm[icoord] += 1;
|
||||
|
||||
grad_arep[icoord][index] -=
|
||||
factor * bra_nlm[icoord] *
|
||||
arep_matrix_down[shell_B->cart_size * bra_index + ket_index];
|
||||
grad_so_x[icoord][index] -=
|
||||
factor * bra_nlm[icoord] *
|
||||
so_x_matrix_down[shell_B->cart_size * bra_index + ket_index];
|
||||
grad_so_y[icoord][index] -=
|
||||
factor * bra_nlm[icoord] *
|
||||
so_y_matrix_down[shell_B->cart_size * bra_index + ket_index];
|
||||
grad_so_z[icoord][index] -=
|
||||
factor * bra_nlm[icoord] *
|
||||
so_z_matrix_down[shell_B->cart_size * bra_index + ket_index];
|
||||
}
|
||||
|
||||
/*
|
||||
* contribution from the L+1 gaussian
|
||||
*/
|
||||
bra_nlm[icoord] += 1;
|
||||
int bra_index = libgrpp_nlm_to_linear(bra_nlm);
|
||||
int ket_index = libgrpp_nlm_to_linear(ket_nlm);
|
||||
bra_nlm[icoord] -= 1;
|
||||
|
||||
grad_arep[icoord][index] +=
|
||||
factor * arep_matrix_up[shell_B->cart_size * bra_index + ket_index];
|
||||
grad_so_x[icoord][index] +=
|
||||
factor * so_x_matrix_up[shell_B->cart_size * bra_index + ket_index];
|
||||
grad_so_y[icoord][index] +=
|
||||
factor * so_y_matrix_up[shell_B->cart_size * bra_index + ket_index];
|
||||
grad_so_z[icoord][index] +=
|
||||
factor * so_z_matrix_up[shell_B->cart_size * bra_index + ket_index];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (arep_matrix_down) {
|
||||
free(arep_matrix_down);
|
||||
free(so_x_matrix_down);
|
||||
free(so_y_matrix_down);
|
||||
free(so_z_matrix_down);
|
||||
}
|
||||
free(arep_matrix_up);
|
||||
free(so_x_matrix_up);
|
||||
free(so_y_matrix_up);
|
||||
free(so_z_matrix_up);
|
||||
}
|
||||
|
||||
/**
|
||||
* To assemble the contribution < df/dA | V | g > to gradients, one have to
|
||||
* differentiate a Gaussian function. Such a differentiation yields two
|
||||
* Gaussians with angular momenta L-1 ("down") and L+1 ("up"): dG/dA -> G(L-1)
|
||||
* and G(L+1)
|
||||
*
|
||||
* This function constructs overlap matrices with these "downgraded" and
|
||||
* "upgraded" Gaussian functions: < G(L-1) | V | G' > and < G(L+1) | V | G' >
|
||||
*
|
||||
*/
|
||||
void grpp_gradient_diff_bra_grpp_integrals(
|
||||
libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B,
|
||||
libgrpp_grpp_t *grpp_operator, double *grpp_origin,
|
||||
double **arep_matrix_down, double **so_x_matrix_down,
|
||||
double **so_y_matrix_down, double **so_z_matrix_down,
|
||||
double **arep_matrix_up, double **so_x_matrix_up, double **so_y_matrix_up,
|
||||
double **so_z_matrix_up, int *cart_size_down, int *cart_size_up) {
|
||||
/*
|
||||
* differentiation of contracted Gaussian functions
|
||||
*/
|
||||
libgrpp_shell_t *shell_A_down = NULL;
|
||||
libgrpp_shell_t *shell_A_up = NULL;
|
||||
libgrpp_differentiate_shell(shell_A, &shell_A_down, &shell_A_up);
|
||||
|
||||
*cart_size_down = 0;
|
||||
if (shell_A_down != NULL) {
|
||||
*cart_size_down = shell_A_down->cart_size;
|
||||
}
|
||||
*cart_size_up = shell_A_up->cart_size;
|
||||
|
||||
/*
|
||||
* matrix < L-1 | V | L >
|
||||
*/
|
||||
if (shell_A_down != NULL) {
|
||||
size_t mat_size_down = shell_A_down->cart_size * shell_B->cart_size;
|
||||
*arep_matrix_down = (double *)calloc(mat_size_down, sizeof(double));
|
||||
*so_x_matrix_down = (double *)calloc(mat_size_down, sizeof(double));
|
||||
*so_y_matrix_down = (double *)calloc(mat_size_down, sizeof(double));
|
||||
*so_z_matrix_down = (double *)calloc(mat_size_down, sizeof(double));
|
||||
|
||||
libgrpp_full_grpp_integrals(
|
||||
shell_A_down, shell_B, grpp_operator, grpp_origin, *arep_matrix_down,
|
||||
*so_x_matrix_down, *so_y_matrix_down, *so_z_matrix_down);
|
||||
} else {
|
||||
*arep_matrix_down = NULL;
|
||||
*so_x_matrix_down = NULL;
|
||||
*so_y_matrix_down = NULL;
|
||||
*so_z_matrix_down = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* matrix < L+1 | V | L >
|
||||
*/
|
||||
size_t mat_size_up = shell_A_up->cart_size * shell_B->cart_size;
|
||||
*arep_matrix_up = (double *)calloc(mat_size_up, sizeof(double));
|
||||
*so_x_matrix_up = (double *)calloc(mat_size_up, sizeof(double));
|
||||
*so_y_matrix_up = (double *)calloc(mat_size_up, sizeof(double));
|
||||
*so_z_matrix_up = (double *)calloc(mat_size_up, sizeof(double));
|
||||
|
||||
libgrpp_full_grpp_integrals(shell_A_up, shell_B, grpp_operator, grpp_origin,
|
||||
*arep_matrix_up, *so_x_matrix_up, *so_y_matrix_up,
|
||||
*so_z_matrix_up);
|
||||
|
||||
/*
|
||||
* clean up
|
||||
*/
|
||||
if (shell_A_down) {
|
||||
libgrpp_delete_shell(shell_A_down);
|
||||
}
|
||||
libgrpp_delete_shell(shell_A_up);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates contribution to gradients arising from the < df/dA | V | g > term:
|
||||
*
|
||||
* grad += factor * < f | V | dg/dA >
|
||||
*
|
||||
* (bra basis function is differentiated).
|
||||
*/
|
||||
void grpp_gradient_diff_ket_contribution(
|
||||
libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B,
|
||||
libgrpp_grpp_t *grpp_operator, double *grpp_origin, double **grad_arep,
|
||||
double **grad_so_x, double **grad_so_y, double **grad_so_z, double factor) {
|
||||
/*
|
||||
* calculate integrals < df/dA | V | B >
|
||||
*/
|
||||
double *arep_matrix_down = NULL;
|
||||
double *so_x_matrix_down = NULL;
|
||||
double *so_y_matrix_down = NULL;
|
||||
double *so_z_matrix_down = NULL;
|
||||
double *arep_matrix_up = NULL;
|
||||
double *so_x_matrix_up = NULL;
|
||||
double *so_y_matrix_up = NULL;
|
||||
double *so_z_matrix_up = NULL;
|
||||
int cart_size_down = 0;
|
||||
int cart_size_up = 0;
|
||||
|
||||
grpp_gradient_diff_ket_grpp_integrals(
|
||||
shell_A, shell_B, grpp_operator, grpp_origin, &arep_matrix_down,
|
||||
&so_x_matrix_down, &so_y_matrix_down, &so_z_matrix_down, &arep_matrix_up,
|
||||
&so_x_matrix_up, &so_y_matrix_up, &so_z_matrix_up, &cart_size_down,
|
||||
&cart_size_up);
|
||||
|
||||
/*
|
||||
* construct contributions to gradients:
|
||||
* d<A|B>/dA += < df/dA | V | B >
|
||||
*/
|
||||
for (int icoord = 0; icoord < 3; icoord++) {
|
||||
for (int i = 0; i < shell_A->cart_size; i++) {
|
||||
for (int j = 0; j < shell_B->cart_size; j++) {
|
||||
|
||||
int bra_nlm[3];
|
||||
bra_nlm[0] = shell_A->cart_list[3 * i + 0];
|
||||
bra_nlm[1] = shell_A->cart_list[3 * i + 1];
|
||||
bra_nlm[2] = shell_A->cart_list[3 * i + 2];
|
||||
|
||||
int ket_nlm[3];
|
||||
ket_nlm[0] = shell_B->cart_list[3 * j + 0];
|
||||
ket_nlm[1] = shell_B->cart_list[3 * j + 1];
|
||||
ket_nlm[2] = shell_B->cart_list[3 * j + 2];
|
||||
|
||||
int index = i * shell_B->cart_size + j;
|
||||
|
||||
/*
|
||||
* contribution from the L-1 gaussian
|
||||
*/
|
||||
if (shell_B->L > 0) {
|
||||
ket_nlm[icoord] -= 1;
|
||||
int bra_index = libgrpp_nlm_to_linear(bra_nlm);
|
||||
int ket_index = libgrpp_nlm_to_linear(ket_nlm);
|
||||
ket_nlm[icoord] += 1;
|
||||
|
||||
grad_arep[icoord][index] -=
|
||||
factor * ket_nlm[icoord] *
|
||||
arep_matrix_down[cart_size_down * bra_index + ket_index];
|
||||
grad_so_x[icoord][index] -=
|
||||
factor * ket_nlm[icoord] *
|
||||
so_x_matrix_down[cart_size_down * bra_index + ket_index];
|
||||
grad_so_y[icoord][index] -=
|
||||
factor * ket_nlm[icoord] *
|
||||
so_y_matrix_down[cart_size_down * bra_index + ket_index];
|
||||
grad_so_z[icoord][index] -=
|
||||
factor * ket_nlm[icoord] *
|
||||
so_z_matrix_down[cart_size_down * bra_index + ket_index];
|
||||
}
|
||||
|
||||
/*
|
||||
* contribution from the L+1 gaussian
|
||||
*/
|
||||
ket_nlm[icoord] += 1;
|
||||
int bra_index = libgrpp_nlm_to_linear(bra_nlm);
|
||||
int ket_index = libgrpp_nlm_to_linear(ket_nlm);
|
||||
ket_nlm[icoord] -= 1;
|
||||
|
||||
grad_arep[icoord][index] +=
|
||||
factor * arep_matrix_up[cart_size_up * bra_index + ket_index];
|
||||
grad_so_x[icoord][index] +=
|
||||
factor * so_x_matrix_up[cart_size_up * bra_index + ket_index];
|
||||
grad_so_y[icoord][index] +=
|
||||
factor * so_y_matrix_up[cart_size_up * bra_index + ket_index];
|
||||
grad_so_z[icoord][index] +=
|
||||
factor * so_z_matrix_up[cart_size_up * bra_index + ket_index];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (arep_matrix_down) {
|
||||
free(arep_matrix_down);
|
||||
free(so_x_matrix_down);
|
||||
free(so_y_matrix_down);
|
||||
free(so_z_matrix_down);
|
||||
}
|
||||
free(arep_matrix_up);
|
||||
free(so_x_matrix_up);
|
||||
free(so_y_matrix_up);
|
||||
free(so_z_matrix_up);
|
||||
}
|
||||
|
||||
/**
|
||||
* To assemble the contribution < df/dA | V | g > to gradients, one have to
|
||||
* differentiate Gaussian function. Such a differentiation yields two Gaussians
|
||||
* with angular momenta L-1 ("down") and L+1 ("up"): dG/dA -> G(L-1) and G(L+1)
|
||||
*
|
||||
* This function constructs matrices with these "downgraded" and "upgraded"
|
||||
* Gaussian functions:
|
||||
* < G(L-1) | V | G' > and < G(L+1) | V | G' >
|
||||
*
|
||||
*/
|
||||
void grpp_gradient_diff_ket_grpp_integrals(
|
||||
libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B,
|
||||
libgrpp_grpp_t *grpp_operator, double *grpp_origin,
|
||||
double **arep_matrix_down, double **so_x_matrix_down,
|
||||
double **so_y_matrix_down, double **so_z_matrix_down,
|
||||
double **arep_matrix_up, double **so_x_matrix_up, double **so_y_matrix_up,
|
||||
double **so_z_matrix_up, int *cart_size_down, int *cart_size_up) {
|
||||
/*
|
||||
* differentiation of contracted Gaussian functions
|
||||
*/
|
||||
libgrpp_shell_t *shell_B_down = NULL;
|
||||
libgrpp_shell_t *shell_B_up = NULL;
|
||||
libgrpp_differentiate_shell(shell_B, &shell_B_down, &shell_B_up);
|
||||
|
||||
*cart_size_down = 0;
|
||||
if (shell_B_down != NULL) {
|
||||
*cart_size_down = shell_B_down->cart_size;
|
||||
}
|
||||
*cart_size_up = shell_B_up->cart_size;
|
||||
|
||||
/*
|
||||
* matrix < L-1 | L>
|
||||
*/
|
||||
if (shell_B_down != NULL) {
|
||||
size_t mat_size_down = shell_A->cart_size * shell_B_down->cart_size;
|
||||
*arep_matrix_down = (double *)calloc(mat_size_down, sizeof(double));
|
||||
*so_x_matrix_down = (double *)calloc(mat_size_down, sizeof(double));
|
||||
*so_y_matrix_down = (double *)calloc(mat_size_down, sizeof(double));
|
||||
*so_z_matrix_down = (double *)calloc(mat_size_down, sizeof(double));
|
||||
|
||||
libgrpp_full_grpp_integrals(
|
||||
// evaluate_grpp_integrals_shell_pair(
|
||||
shell_A, shell_B_down, grpp_operator, grpp_origin, *arep_matrix_down,
|
||||
*so_x_matrix_down, *so_y_matrix_down, *so_z_matrix_down);
|
||||
} else {
|
||||
*arep_matrix_down = NULL;
|
||||
*so_x_matrix_down = NULL;
|
||||
*so_y_matrix_down = NULL;
|
||||
*so_z_matrix_down = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* matrix < L+1 | L>
|
||||
*/
|
||||
size_t mat_size_up = shell_A->cart_size * shell_B_up->cart_size;
|
||||
*arep_matrix_up = (double *)calloc(mat_size_up, sizeof(double));
|
||||
*so_x_matrix_up = (double *)calloc(mat_size_up, sizeof(double));
|
||||
*so_y_matrix_up = (double *)calloc(mat_size_up, sizeof(double));
|
||||
*so_z_matrix_up = (double *)calloc(mat_size_up, sizeof(double));
|
||||
|
||||
libgrpp_full_grpp_integrals(
|
||||
// evaluate_grpp_integrals_shell_pair(
|
||||
shell_A, shell_B_up, grpp_operator, grpp_origin, *arep_matrix_up,
|
||||
*so_x_matrix_up, *so_y_matrix_up, *so_z_matrix_up);
|
||||
|
||||
/*
|
||||
* clean up
|
||||
*/
|
||||
if (shell_B_down) {
|
||||
libgrpp_delete_shell(shell_B_down);
|
||||
}
|
||||
libgrpp_delete_shell(shell_B_up);
|
||||
}
|
||||
|
||||
void grpp_gradient_contribution(libgrpp_shell_t *shell_A,
|
||||
libgrpp_shell_t *shell_B,
|
||||
libgrpp_grpp_t *grpp_operator,
|
||||
double *grpp_origin, double **grad_arep,
|
||||
double **grad_so_x, double **grad_so_y,
|
||||
double **grad_so_z, int diff_bra,
|
||||
double factor) {
|
||||
// int diff_ket = 0;
|
||||
|
||||
if (diff_bra == 0) {
|
||||
diff_bra = 0;
|
||||
// diff_ket = 1;
|
||||
} else {
|
||||
diff_bra = 1;
|
||||
// diff_ket = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* calculate overlap integrals < df/dA | V | B >
|
||||
*/
|
||||
double *arep_matrix_down = NULL;
|
||||
double *so_x_matrix_down = NULL;
|
||||
double *so_y_matrix_down = NULL;
|
||||
double *so_z_matrix_down = NULL;
|
||||
double *arep_matrix_up = NULL;
|
||||
double *so_x_matrix_up = NULL;
|
||||
double *so_y_matrix_up = NULL;
|
||||
double *so_z_matrix_up = NULL;
|
||||
int cart_size_down = 0;
|
||||
int cart_size_up = 0;
|
||||
|
||||
grpp_gradient_diff_gaussian(
|
||||
shell_A, shell_B, grpp_operator, grpp_origin, &arep_matrix_down,
|
||||
&so_x_matrix_down, &so_y_matrix_down, &so_z_matrix_down, &arep_matrix_up,
|
||||
&so_x_matrix_up, &so_y_matrix_up, &so_z_matrix_up, &cart_size_down,
|
||||
&cart_size_up, diff_bra);
|
||||
|
||||
/*
|
||||
* construct contributions to gradients:
|
||||
* d<A|U|B>/dA += < df/dA | U | B >
|
||||
*/
|
||||
for (int icoord = 0; icoord < 3; icoord++) {
|
||||
for (int i = 0; i < shell_A->cart_size; i++) {
|
||||
for (int j = 0; j < shell_B->cart_size; j++) {
|
||||
|
||||
int bra_nlm[3];
|
||||
bra_nlm[0] = shell_A->cart_list[3 * i + 0];
|
||||
bra_nlm[1] = shell_A->cart_list[3 * i + 1];
|
||||
bra_nlm[2] = shell_A->cart_list[3 * i + 2];
|
||||
|
||||
int ket_nlm[3];
|
||||
ket_nlm[0] = shell_B->cart_list[3 * j + 0];
|
||||
ket_nlm[1] = shell_B->cart_list[3 * j + 1];
|
||||
ket_nlm[2] = shell_B->cart_list[3 * j + 2];
|
||||
|
||||
int index = i * shell_B->cart_size + j;
|
||||
|
||||
int *diff_nlm = diff_bra ? bra_nlm : ket_nlm;
|
||||
|
||||
/*
|
||||
* contribution from the L-1 gaussian
|
||||
*/
|
||||
if (cart_size_down > 0) {
|
||||
diff_nlm[icoord] -= 1;
|
||||
int bra_index = libgrpp_nlm_to_linear(bra_nlm);
|
||||
int ket_index = libgrpp_nlm_to_linear(ket_nlm);
|
||||
diff_nlm[icoord] += 1;
|
||||
|
||||
int n = diff_nlm[icoord];
|
||||
int row_len = diff_bra ? shell_B->cart_size : cart_size_down;
|
||||
int index_down = row_len * bra_index + ket_index;
|
||||
|
||||
grad_arep[icoord][index] -= factor * n * arep_matrix_down[index_down];
|
||||
grad_so_x[icoord][index] -= factor * n * so_x_matrix_down[index_down];
|
||||
grad_so_y[icoord][index] -= factor * n * so_y_matrix_down[index_down];
|
||||
grad_so_z[icoord][index] -= factor * n * so_z_matrix_down[index_down];
|
||||
}
|
||||
|
||||
/*
|
||||
* contribution from the L+1 gaussian
|
||||
*/
|
||||
diff_nlm[icoord] += 1;
|
||||
int bra_index = libgrpp_nlm_to_linear(bra_nlm);
|
||||
int ket_index = libgrpp_nlm_to_linear(ket_nlm);
|
||||
diff_nlm[icoord] -= 1;
|
||||
|
||||
int row_len = diff_bra ? shell_B->cart_size : cart_size_up;
|
||||
int index_up = row_len * bra_index + ket_index;
|
||||
|
||||
grad_arep[icoord][index] += factor * arep_matrix_up[index_up];
|
||||
grad_so_x[icoord][index] += factor * so_x_matrix_up[index_up];
|
||||
grad_so_y[icoord][index] += factor * so_y_matrix_up[index_up];
|
||||
grad_so_z[icoord][index] += factor * so_z_matrix_up[index_up];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (arep_matrix_down) {
|
||||
free(arep_matrix_down);
|
||||
free(so_x_matrix_down);
|
||||
free(so_y_matrix_down);
|
||||
free(so_z_matrix_down);
|
||||
}
|
||||
free(arep_matrix_up);
|
||||
free(so_x_matrix_up);
|
||||
free(so_y_matrix_up);
|
||||
free(so_z_matrix_up);
|
||||
}
|
||||
|
||||
/**
|
||||
* To assemble the contribution < df/dA | V | g > to gradients, one have to
|
||||
* differentiate Gaussian function. Such a differentiation yields two Gaussians
|
||||
* with angular momenta L-1 ("down") and L+1 ("up"): dG/dA -> G(L-1) and G(L+1)
|
||||
*
|
||||
* This function constructs matrices with these "downgraded" and "upgraded"
|
||||
* Gaussian functions:
|
||||
* < G(L-1) | V | G' > and < G(L+1) | V | G' >
|
||||
*
|
||||
*/
|
||||
void grpp_gradient_diff_gaussian(
|
||||
libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B,
|
||||
libgrpp_grpp_t *grpp_operator, double *grpp_origin,
|
||||
double **arep_matrix_down, double **so_x_matrix_down,
|
||||
double **so_y_matrix_down, double **so_z_matrix_down,
|
||||
double **arep_matrix_up, double **so_x_matrix_up, double **so_y_matrix_up,
|
||||
double **so_z_matrix_up, int *cart_size_down, int *cart_size_up,
|
||||
int diff_bra) {
|
||||
// int diff_ket = 0;
|
||||
|
||||
if (diff_bra == 0) {
|
||||
diff_bra = 0;
|
||||
// diff_ket = 1;
|
||||
} else {
|
||||
diff_bra = 1;
|
||||
// diff_ket = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* which shell should be differentiated, bra or ket
|
||||
*/
|
||||
libgrpp_shell_t *const_shell = NULL;
|
||||
libgrpp_shell_t *diff_shell = NULL;
|
||||
if (diff_bra) {
|
||||
diff_shell = shell_A;
|
||||
const_shell = shell_B;
|
||||
} else {
|
||||
diff_shell = shell_B;
|
||||
const_shell = shell_A;
|
||||
}
|
||||
|
||||
/*
|
||||
* differentiation of contracted Gaussian functions
|
||||
*/
|
||||
libgrpp_shell_t *shell_down = NULL;
|
||||
libgrpp_shell_t *shell_up = NULL;
|
||||
libgrpp_differentiate_shell(diff_shell, &shell_down, &shell_up);
|
||||
|
||||
*cart_size_down = 0;
|
||||
if (shell_down != NULL) {
|
||||
*cart_size_down = shell_down->cart_size;
|
||||
}
|
||||
*cart_size_up = shell_up->cart_size;
|
||||
|
||||
/*
|
||||
* GRPP matrix:
|
||||
* < L-1 | U | L > or < L | U | L-1 >
|
||||
*/
|
||||
if (shell_down != NULL) {
|
||||
size_t mat_size_down = const_shell->cart_size * shell_down->cart_size;
|
||||
*arep_matrix_down = (double *)calloc(mat_size_down, sizeof(double));
|
||||
*so_x_matrix_down = (double *)calloc(mat_size_down, sizeof(double));
|
||||
*so_y_matrix_down = (double *)calloc(mat_size_down, sizeof(double));
|
||||
*so_z_matrix_down = (double *)calloc(mat_size_down, sizeof(double));
|
||||
|
||||
libgrpp_full_grpp_integrals(
|
||||
diff_bra ? shell_down : shell_A, diff_bra ? shell_B : shell_down,
|
||||
grpp_operator, grpp_origin, *arep_matrix_down, *so_x_matrix_down,
|
||||
*so_y_matrix_down, *so_z_matrix_down);
|
||||
} else {
|
||||
*arep_matrix_down = NULL;
|
||||
*so_x_matrix_down = NULL;
|
||||
*so_y_matrix_down = NULL;
|
||||
*so_z_matrix_down = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* GRPP matrix:
|
||||
* < L+1 | U | L > or < L | U | L+1 >
|
||||
*/
|
||||
size_t mat_size_up = const_shell->cart_size * shell_up->cart_size;
|
||||
*arep_matrix_up = (double *)calloc(mat_size_up, sizeof(double));
|
||||
*so_x_matrix_up = (double *)calloc(mat_size_up, sizeof(double));
|
||||
*so_y_matrix_up = (double *)calloc(mat_size_up, sizeof(double));
|
||||
*so_z_matrix_up = (double *)calloc(mat_size_up, sizeof(double));
|
||||
|
||||
libgrpp_full_grpp_integrals(diff_bra ? shell_up : shell_A,
|
||||
diff_bra ? shell_B : shell_up, grpp_operator,
|
||||
grpp_origin, *arep_matrix_up, *so_x_matrix_up,
|
||||
*so_y_matrix_up, *so_z_matrix_up);
|
||||
|
||||
/*
|
||||
* clean up
|
||||
*/
|
||||
if (shell_down) {
|
||||
libgrpp_delete_shell(shell_down);
|
||||
}
|
||||
libgrpp_delete_shell(shell_up);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates memory for gradients for a given shell pair.
|
||||
*/
|
||||
double **libgrpp_alloc_gradients(libgrpp_shell_t *bra, libgrpp_shell_t *ket) {
|
||||
size_t size = bra->cart_size * ket->cart_size;
|
||||
|
||||
double **grad = (double **)calloc(3, sizeof(double *));
|
||||
for (int icoord = 0; icoord < 3; icoord++) {
|
||||
grad[icoord] = (double *)calloc(size, sizeof(double));
|
||||
}
|
||||
|
||||
return grad;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deallocates arrays containing gradients of AO integrals.
|
||||
*/
|
||||
void libgrpp_dealloc_gradients(double **grad) {
|
||||
free(grad[0]);
|
||||
free(grad[1]);
|
||||
free(grad[2]);
|
||||
free(grad);
|
||||
}
|
||||
161
src/grpp/grpp_kinetic.c
Normal file
161
src/grpp/grpp_kinetic.c
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
/*----------------------------------------------------------------------------*/
|
||||
/* CP2K: A general program to perform molecular dynamics simulations */
|
||||
/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
|
||||
/* */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* libgrpp - a library for the evaluation of integrals over
|
||||
* generalized relativistic pseudopotentials.
|
||||
*
|
||||
* Copyright (C) 2021-2023 Alexander Oleynichenko
|
||||
*/
|
||||
|
||||
/**
|
||||
* Calculation of kinetic-energy integrals.
|
||||
*
|
||||
* For details, see:
|
||||
* T. Helgaker, P. Jorgensen, J. Olsen, Molecular Electronic-Structure Theory,
|
||||
* John Wiley & Sons Ltd, 2000.
|
||||
* Chapter 9.3.4, "Momentum and kinetic-energy integrals"
|
||||
*/
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
#include "grpp_kinetic.h"
|
||||
|
||||
#include "grpp_norm_gaussian.h"
|
||||
#include "grpp_utils.h"
|
||||
#include "libgrpp.h"
|
||||
|
||||
static void kinetic_energy_integrals_shell_pair_obara_saika(
|
||||
libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B, double alpha_A,
|
||||
double alpha_B, double *kinetic_matrix);
|
||||
|
||||
void libgrpp_kinetic_energy_integrals(libgrpp_shell_t *shell_A,
|
||||
libgrpp_shell_t *shell_B,
|
||||
double *kinetic_matrix) {
|
||||
int size_A = libgrpp_get_shell_size(shell_A);
|
||||
int size_B = libgrpp_get_shell_size(shell_B);
|
||||
|
||||
double *buf = calloc(size_A * size_B, sizeof(double));
|
||||
|
||||
memset(kinetic_matrix, 0, size_A * size_B * sizeof(double));
|
||||
|
||||
// loop over primitives in contractions
|
||||
for (int i = 0; i < shell_A->num_primitives; i++) {
|
||||
for (int j = 0; j < shell_B->num_primitives; j++) {
|
||||
double alpha_i = shell_A->alpha[i];
|
||||
double alpha_j = shell_B->alpha[j];
|
||||
double coef_A_i = shell_A->coeffs[i];
|
||||
double coef_B_j = shell_B->coeffs[j];
|
||||
|
||||
kinetic_energy_integrals_shell_pair_obara_saika(shell_A, shell_B, alpha_i,
|
||||
alpha_j, buf);
|
||||
|
||||
libgrpp_daxpy(size_A * size_B, coef_A_i * coef_B_j, buf, kinetic_matrix);
|
||||
}
|
||||
}
|
||||
|
||||
free(buf);
|
||||
}
|
||||
|
||||
static void kinetic_energy_integrals_shell_pair_obara_saika(
|
||||
libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B, double alpha_A,
|
||||
double alpha_B, double *kinetic_matrix) {
|
||||
int size_A = libgrpp_get_shell_size(shell_A);
|
||||
int size_B = libgrpp_get_shell_size(shell_B);
|
||||
int L_A = shell_A->L;
|
||||
int L_B = shell_B->L;
|
||||
double N_A = libgrpp_gaussian_norm_factor(L_A, 0, 0, alpha_A);
|
||||
double N_B = libgrpp_gaussian_norm_factor(L_B, 0, 0, alpha_B);
|
||||
|
||||
double p = alpha_A + alpha_B;
|
||||
double mu = alpha_A * alpha_B / (alpha_A + alpha_B);
|
||||
double *A = shell_A->origin;
|
||||
double *B = shell_B->origin;
|
||||
|
||||
// calculate S_ij
|
||||
double S[3][LIBGRPP_MAX_BASIS_L + 2][LIBGRPP_MAX_BASIS_L + 2];
|
||||
|
||||
for (int coord = 0; coord < 3; coord++) {
|
||||
double P = (alpha_A * A[coord] + alpha_B * B[coord]) / p;
|
||||
|
||||
double X_AB = A[coord] - B[coord];
|
||||
double X_PA = P - A[coord];
|
||||
double X_PB = P - B[coord];
|
||||
double pfac = 1.0 / (2.0 * p);
|
||||
|
||||
for (int i = 0; i <= L_A + 2; i++) {
|
||||
for (int j = 0; j <= L_B + 2; j++) {
|
||||
double S_ij = 0.0;
|
||||
|
||||
if (i + j == 0) {
|
||||
S[coord][0][0] = sqrt(M_PI / p) * exp(-mu * X_AB * X_AB);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i == 0) { // upward by j
|
||||
S_ij += X_PB * S[coord][i][j - 1];
|
||||
if (j - 1 > 0) {
|
||||
S_ij += (j - 1) * pfac * S[coord][i][j - 2];
|
||||
}
|
||||
} else { // upward by i
|
||||
S_ij += X_PA * S[coord][i - 1][j];
|
||||
if (i - 1 > 0) {
|
||||
S_ij += (i - 1) * pfac * S[coord][i - 2][j];
|
||||
}
|
||||
if (j > 0) {
|
||||
S_ij += j * pfac * S[coord][i - 1][j - 1];
|
||||
}
|
||||
}
|
||||
|
||||
S[coord][i][j] = S_ij;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// calculate D^2_ij
|
||||
|
||||
double D2[3][LIBGRPP_MAX_BASIS_L][LIBGRPP_MAX_BASIS_L];
|
||||
|
||||
for (int coord = 0; coord < 3; coord++) {
|
||||
for (int i = 0; i <= L_A; i++) {
|
||||
for (int j = 0; j <= L_B; j++) {
|
||||
|
||||
double D2_ij = 0.0;
|
||||
D2_ij += 4.0 * alpha_A * alpha_A * S[coord][i + 2][j];
|
||||
D2_ij -= 2.0 * alpha_A * (2 * i + 1) * S[coord][i][j];
|
||||
if (i >= 2) {
|
||||
D2_ij += i * (i - 1) * S[coord][i - 2][j];
|
||||
}
|
||||
|
||||
D2[coord][i][j] = D2_ij;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// loop over cartesian functions inside the shells
|
||||
for (int m = 0; m < size_A; m++) {
|
||||
for (int n = 0; n < size_B; n++) {
|
||||
int n_A = shell_A->cart_list[3 * m + 0];
|
||||
int l_A = shell_A->cart_list[3 * m + 1];
|
||||
int m_A = shell_A->cart_list[3 * m + 2];
|
||||
int n_B = shell_B->cart_list[3 * n + 0];
|
||||
int l_B = shell_B->cart_list[3 * n + 1];
|
||||
int m_B = shell_B->cart_list[3 * n + 2];
|
||||
|
||||
kinetic_matrix[m * size_B + n] =
|
||||
-0.5 * N_A * N_B *
|
||||
(D2[0][n_A][n_B] * S[1][l_A][l_B] * S[2][m_A][m_B] +
|
||||
S[0][n_A][n_B] * D2[1][l_A][l_B] * S[2][m_A][m_B] +
|
||||
S[0][n_A][n_B] * S[1][l_A][l_B] * D2[2][m_A][m_B]);
|
||||
}
|
||||
}
|
||||
}
|
||||
24
src/grpp/grpp_kinetic.h
Normal file
24
src/grpp/grpp_kinetic.h
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
/*----------------------------------------------------------------------------*/
|
||||
/* CP2K: A general program to perform molecular dynamics simulations */
|
||||
/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
|
||||
/* */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* libgrpp - a library for the evaluation of integrals over
|
||||
* generalized relativistic pseudopotentials.
|
||||
*
|
||||
* Copyright (C) 2021-2023 Alexander Oleynichenko
|
||||
*/
|
||||
|
||||
#ifndef LIBGRPP_KINETIC_H
|
||||
#define LIBGRPP_KINETIC_H
|
||||
|
||||
#include "libgrpp_types.h"
|
||||
|
||||
void libgrpp_kinetic_energy_integrals(libgrpp_shell_t *shell_A,
|
||||
libgrpp_shell_t *shell_B,
|
||||
double *kinetic_matrix);
|
||||
|
||||
#endif // LIBGRPP_KINETIC_H
|
||||
146
src/grpp/grpp_lmatrix.c
Normal file
146
src/grpp/grpp_lmatrix.c
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
/*----------------------------------------------------------------------------*/
|
||||
/* CP2K: A general program to perform molecular dynamics simulations */
|
||||
/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
|
||||
/* */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* libgrpp - a library for the evaluation of integrals over
|
||||
* generalized relativistic pseudopotentials.
|
||||
*
|
||||
* Copyright (C) 2021-2023 Alexander Oleynichenko
|
||||
*/
|
||||
|
||||
/*
|
||||
* Functions for construction of matrices of the angular momentum operator L
|
||||
* in the bases of either real or complex spherical harmonics.
|
||||
*/
|
||||
|
||||
#include "grpp_lmatrix.h"
|
||||
|
||||
#include <complex.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static void get_transformation_coeffs_csh_to_rsh(int m, double complex *a,
|
||||
double complex *b);
|
||||
|
||||
/**
|
||||
* Constructs matrices of the Lx, Ly, Lz operators for the given angular
|
||||
* momentum L in the basis of real spherical harmonics (rsh).
|
||||
*/
|
||||
void libgrpp_construct_angular_momentum_matrices_rsh(int L, double *lx_matrix,
|
||||
double *ly_matrix,
|
||||
double *lz_matrix) {
|
||||
int dim = 2 * L + 1;
|
||||
|
||||
// set all matrices to zero
|
||||
memset(lx_matrix, 0, dim * dim * sizeof(double));
|
||||
memset(ly_matrix, 0, dim * dim * sizeof(double));
|
||||
memset(lz_matrix, 0, dim * dim * sizeof(double));
|
||||
|
||||
double *lx_matrix_csh = calloc(dim * dim, sizeof(double));
|
||||
double *ly_matrix_csh = calloc(dim * dim, sizeof(double));
|
||||
double *lz_matrix_csh = calloc(dim * dim, sizeof(double));
|
||||
|
||||
libgrpp_construct_angular_momentum_matrices_csh(L, lx_matrix_csh,
|
||||
ly_matrix_csh, lz_matrix_csh);
|
||||
|
||||
for (int m1 = -L; m1 <= L; m1++) {
|
||||
for (int m2 = -L; m2 <= L; m2++) {
|
||||
|
||||
// coefficients: S_lm = a * Y_{l,-m} + b * Y_{l,m}
|
||||
double complex a1, b1;
|
||||
double complex a2, b2;
|
||||
get_transformation_coeffs_csh_to_rsh(m1, &a1, &b1); // bra
|
||||
get_transformation_coeffs_csh_to_rsh(m2, &a2, &b2); // ket
|
||||
|
||||
int m1m = -abs(m1);
|
||||
int m1p = +abs(m1);
|
||||
int m2m = -abs(m2);
|
||||
int m2p = +abs(m2);
|
||||
|
||||
double complex lx = 0.0 + 0.0 * I;
|
||||
lx += conj(a1) * a2 * lx_matrix_csh[dim * (m1m + L) + (m2m + L)];
|
||||
lx += conj(a1) * b2 * lx_matrix_csh[dim * (m1m + L) + (m2p + L)];
|
||||
lx += conj(b1) * a2 * lx_matrix_csh[dim * (m1p + L) + (m2m + L)];
|
||||
lx += conj(b1) * b2 * lx_matrix_csh[dim * (m1p + L) + (m2p + L)];
|
||||
|
||||
double complex ly = 0.0 + 0.0 * I;
|
||||
ly += conj(a1) * a2 * ly_matrix_csh[dim * (m1m + L) + (m2m + L)];
|
||||
ly += conj(a1) * b2 * ly_matrix_csh[dim * (m1m + L) + (m2p + L)];
|
||||
ly += conj(b1) * a2 * ly_matrix_csh[dim * (m1p + L) + (m2m + L)];
|
||||
ly += conj(b1) * b2 * ly_matrix_csh[dim * (m1p + L) + (m2p + L)];
|
||||
|
||||
double complex lz = 0.0 + 0.0 * I;
|
||||
lz += conj(a1) * a2 * lz_matrix_csh[dim * (m1m + L) + (m2m + L)];
|
||||
lz += conj(a1) * b2 * lz_matrix_csh[dim * (m1m + L) + (m2p + L)];
|
||||
lz += conj(b1) * a2 * lz_matrix_csh[dim * (m1p + L) + (m2m + L)];
|
||||
lz += conj(b1) * b2 * lz_matrix_csh[dim * (m1p + L) + (m2p + L)];
|
||||
|
||||
lx_matrix[(m1 + L) * dim + (m2 + L)] = cimag(lx);
|
||||
ly_matrix[(m1 + L) * dim + (m2 + L)] = -creal(ly);
|
||||
lz_matrix[(m1 + L) * dim + (m2 + L)] = cimag(lz);
|
||||
}
|
||||
}
|
||||
|
||||
free(lx_matrix_csh);
|
||||
free(ly_matrix_csh);
|
||||
free(lz_matrix_csh);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs matrices of the Lx, Ly, Lz operators in the basis of
|
||||
* complex spherical harmonics (csh) |Y_lm> for angular momentum l=L.
|
||||
* Matrices of size (2*L+1) x (2*L+1) must be pre-allocated.
|
||||
*/
|
||||
void libgrpp_construct_angular_momentum_matrices_csh(int L, double *lx_matrix,
|
||||
double *ly_matrix,
|
||||
double *lz_matrix) {
|
||||
int dim = 2 * L + 1;
|
||||
|
||||
// set all matrices to zero
|
||||
memset(lx_matrix, 0, dim * dim * sizeof(double));
|
||||
memset(ly_matrix, 0, dim * dim * sizeof(double));
|
||||
memset(lz_matrix, 0, dim * dim * sizeof(double));
|
||||
|
||||
for (int m1 = -L; m1 <= L; m1++) {
|
||||
for (int m2 = -L; m2 <= L; m2++) {
|
||||
|
||||
double lz = m2 * (m1 == m2);
|
||||
double lp = sqrt((L - m2) * (L + m2 + 1)) * (m1 == m2 + 1); // L+
|
||||
double lm = sqrt((L + m2) * (L - m2 + 1)) * (m1 == m2 - 1); // L-
|
||||
double lx = 0.5 * (lp + lm);
|
||||
double ly = 0.5 * (lp - lm);
|
||||
|
||||
lx_matrix[(m1 + L) * dim + (m2 + L)] = lx;
|
||||
ly_matrix[(m1 + L) * dim + (m2 + L)] = ly;
|
||||
lz_matrix[(m1 + L) * dim + (m2 + L)] = lz;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Real spherical harmonic S_{l,m} can be represented as a linear combination
|
||||
* of two complex spherical harmonics:
|
||||
* S_{l,m} = a * Y_{l,-m} + b * Y_{l,m}
|
||||
* (except for the case m=0, where S_{l,0} = Y_{l,0})
|
||||
*
|
||||
* coefficients can be found elsewhere, see, for example,
|
||||
* https://en.wikipedia.org/wiki/Table_of_spherical_harmonics
|
||||
*/
|
||||
static void get_transformation_coeffs_csh_to_rsh(int m, double complex *a,
|
||||
double complex *b) {
|
||||
if (m == 0) {
|
||||
*a = 0.5;
|
||||
*b = 0.5;
|
||||
} else if (m < 0) {
|
||||
*a = +1.0 * I / sqrt(2);
|
||||
*b = -1.0 * I / sqrt(2) * pow(-1, abs(m));
|
||||
} else { // m > 0
|
||||
*a = +1.0 / sqrt(2);
|
||||
*b = +1.0 / sqrt(2) * pow(-1, m);
|
||||
}
|
||||
}
|
||||
26
src/grpp/grpp_lmatrix.h
Normal file
26
src/grpp/grpp_lmatrix.h
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
/*----------------------------------------------------------------------------*/
|
||||
/* CP2K: A general program to perform molecular dynamics simulations */
|
||||
/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
|
||||
/* */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* libgrpp - a library for the evaluation of integrals over
|
||||
* generalized relativistic pseudopotentials.
|
||||
*
|
||||
* Copyright (C) 2021-2023 Alexander Oleynichenko
|
||||
*/
|
||||
|
||||
#ifndef LIBGRPP_LMATRIX_H
|
||||
#define LIBGRPP_LMATRIX_H
|
||||
|
||||
void libgrpp_construct_angular_momentum_matrices_rsh(int L, double *lx_matrix,
|
||||
double *ly_matrix,
|
||||
double *lz_matrix);
|
||||
|
||||
void libgrpp_construct_angular_momentum_matrices_csh(int L, double *lx_matrix,
|
||||
double *ly_matrix,
|
||||
double *lz_matrix);
|
||||
|
||||
#endif // LIBGRPP_LMATRIX_H
|
||||
178
src/grpp/grpp_momentum.c
Normal file
178
src/grpp/grpp_momentum.c
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
/*----------------------------------------------------------------------------*/
|
||||
/* CP2K: A general program to perform molecular dynamics simulations */
|
||||
/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
|
||||
/* */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* libgrpp - a library for the evaluation of integrals over
|
||||
* generalized relativistic pseudopotentials.
|
||||
*
|
||||
* Copyright (C) 2021-2023 Alexander Oleynichenko
|
||||
*/
|
||||
|
||||
/**
|
||||
* Calculation of momentum integrals.
|
||||
*
|
||||
* For details, see:
|
||||
* T. Helgaker, P. Jorgensen, J. Olsen, Molecular Electronic-Structure Theory,
|
||||
* John Wiley & Sons Ltd, 2000.
|
||||
* Chapter 9.3.4, "Momentum and kinetic-energy integrals"
|
||||
*/
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
#include "grpp_momentum.h"
|
||||
|
||||
#include "grpp_norm_gaussian.h"
|
||||
#include "grpp_utils.h"
|
||||
#include "libgrpp.h"
|
||||
|
||||
static void momentum_integrals_shell_pair_obara_saika(
|
||||
libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B, double alpha_A,
|
||||
double alpha_B, double *momentum_x_matrix, double *momentum_y_matrix,
|
||||
double *momentum_z_matrix);
|
||||
|
||||
/**
|
||||
* returns imaginary(!) part of integrals over the momentum operator p = -i
|
||||
* \hbar \nabla. The "minus" sign is included.
|
||||
*/
|
||||
void libgrpp_momentum_integrals(libgrpp_shell_t *shell_A,
|
||||
libgrpp_shell_t *shell_B,
|
||||
double *momentum_x_matrix,
|
||||
double *momentum_y_matrix,
|
||||
double *momentum_z_matrix) {
|
||||
int size_A = libgrpp_get_shell_size(shell_A);
|
||||
int size_B = libgrpp_get_shell_size(shell_B);
|
||||
|
||||
double *buf_x = calloc(size_A * size_B, sizeof(double));
|
||||
double *buf_y = calloc(size_A * size_B, sizeof(double));
|
||||
double *buf_z = calloc(size_A * size_B, sizeof(double));
|
||||
|
||||
memset(momentum_x_matrix, 0, size_A * size_B * sizeof(double));
|
||||
memset(momentum_y_matrix, 0, size_A * size_B * sizeof(double));
|
||||
memset(momentum_z_matrix, 0, size_A * size_B * sizeof(double));
|
||||
|
||||
// loop over primitives in contractions
|
||||
for (int i = 0; i < shell_A->num_primitives; i++) {
|
||||
for (int j = 0; j < shell_B->num_primitives; j++) {
|
||||
double alpha_i = shell_A->alpha[i];
|
||||
double alpha_j = shell_B->alpha[j];
|
||||
double coef_A_i = shell_A->coeffs[i];
|
||||
double coef_B_j = shell_B->coeffs[j];
|
||||
|
||||
momentum_integrals_shell_pair_obara_saika(shell_A, shell_B, alpha_i,
|
||||
alpha_j, buf_x, buf_y, buf_z);
|
||||
|
||||
libgrpp_daxpy(size_A * size_B, coef_A_i * coef_B_j, buf_x,
|
||||
momentum_x_matrix);
|
||||
libgrpp_daxpy(size_A * size_B, coef_A_i * coef_B_j, buf_y,
|
||||
momentum_y_matrix);
|
||||
libgrpp_daxpy(size_A * size_B, coef_A_i * coef_B_j, buf_z,
|
||||
momentum_z_matrix);
|
||||
}
|
||||
}
|
||||
|
||||
free(buf_x);
|
||||
free(buf_y);
|
||||
free(buf_z);
|
||||
}
|
||||
|
||||
static void momentum_integrals_shell_pair_obara_saika(
|
||||
libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B, double alpha_A,
|
||||
double alpha_B, double *momentum_x_matrix, double *momentum_y_matrix,
|
||||
double *momentum_z_matrix) {
|
||||
int size_A = libgrpp_get_shell_size(shell_A);
|
||||
int size_B = libgrpp_get_shell_size(shell_B);
|
||||
int L_A = shell_A->L;
|
||||
int L_B = shell_B->L;
|
||||
double N_A = libgrpp_gaussian_norm_factor(L_A, 0, 0, alpha_A);
|
||||
double N_B = libgrpp_gaussian_norm_factor(L_B, 0, 0, alpha_B);
|
||||
|
||||
double p = alpha_A + alpha_B;
|
||||
double mu = alpha_A * alpha_B / (alpha_A + alpha_B);
|
||||
double *A = shell_A->origin;
|
||||
double *B = shell_B->origin;
|
||||
|
||||
// calculate S_ij
|
||||
double S[3][LIBGRPP_MAX_BASIS_L + 1][LIBGRPP_MAX_BASIS_L + 1];
|
||||
|
||||
for (int coord = 0; coord < 3; coord++) {
|
||||
double P = (alpha_A * A[coord] + alpha_B * B[coord]) / p;
|
||||
|
||||
double X_AB = A[coord] - B[coord];
|
||||
double X_PA = P - A[coord];
|
||||
double X_PB = P - B[coord];
|
||||
double pfac = 1.0 / (2.0 * p);
|
||||
|
||||
for (int i = 0; i <= L_A + 1; i++) {
|
||||
for (int j = 0; j <= L_B + 1; j++) {
|
||||
double S_ij = 0.0;
|
||||
|
||||
if (i + j == 0) {
|
||||
S[coord][0][0] = sqrt(M_PI / p) * exp(-mu * X_AB * X_AB);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i == 0) { // upward by j
|
||||
S_ij += X_PB * S[coord][i][j - 1];
|
||||
if (j - 1 > 0) {
|
||||
S_ij += (j - 1) * pfac * S[coord][i][j - 2];
|
||||
}
|
||||
} else { // upward by i
|
||||
S_ij += X_PA * S[coord][i - 1][j];
|
||||
if (i - 1 > 0) {
|
||||
S_ij += (i - 1) * pfac * S[coord][i - 2][j];
|
||||
}
|
||||
if (j > 0) {
|
||||
S_ij += j * pfac * S[coord][i - 1][j - 1];
|
||||
}
|
||||
}
|
||||
|
||||
S[coord][i][j] = S_ij;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// calculate D^1_ij
|
||||
|
||||
double D1[3][LIBGRPP_MAX_BASIS_L][LIBGRPP_MAX_BASIS_L];
|
||||
|
||||
for (int coord = 0; coord < 3; coord++) {
|
||||
for (int i = 0; i <= L_A; i++) {
|
||||
for (int j = 0; j <= L_B; j++) {
|
||||
|
||||
double D1_ij = 0.0;
|
||||
D1_ij += 2.0 * alpha_A * S[coord][i + 1][j];
|
||||
if (i >= 1) {
|
||||
D1_ij -= i * S[coord][i - 1][j];
|
||||
}
|
||||
|
||||
D1[coord][i][j] = D1_ij;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// loop over cartesian functions inside the shells
|
||||
for (int m = 0; m < size_A; m++) {
|
||||
for (int n = 0; n < size_B; n++) {
|
||||
int n_A = shell_A->cart_list[3 * m + 0];
|
||||
int l_A = shell_A->cart_list[3 * m + 1];
|
||||
int m_A = shell_A->cart_list[3 * m + 2];
|
||||
int n_B = shell_B->cart_list[3 * n + 0];
|
||||
int l_B = shell_B->cart_list[3 * n + 1];
|
||||
int m_B = shell_B->cart_list[3 * n + 2];
|
||||
|
||||
momentum_x_matrix[m * size_B + n] =
|
||||
-N_A * N_B * D1[0][n_A][n_B] * S[1][l_A][l_B] * S[2][m_A][m_B];
|
||||
momentum_y_matrix[m * size_B + n] =
|
||||
-N_A * N_B * S[0][n_A][n_B] * D1[1][l_A][l_B] * S[2][m_A][m_B];
|
||||
momentum_z_matrix[m * size_B + n] =
|
||||
-N_A * N_B * S[0][n_A][n_B] * S[1][l_A][l_B] * D1[2][m_A][m_B];
|
||||
}
|
||||
}
|
||||
}
|
||||
26
src/grpp/grpp_momentum.h
Normal file
26
src/grpp/grpp_momentum.h
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
/*----------------------------------------------------------------------------*/
|
||||
/* CP2K: A general program to perform molecular dynamics simulations */
|
||||
/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
|
||||
/* */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* libgrpp - a library for the evaluation of integrals over
|
||||
* generalized relativistic pseudopotentials.
|
||||
*
|
||||
* Copyright (C) 2021-2023 Alexander Oleynichenko
|
||||
*/
|
||||
|
||||
#ifndef LIBGRPP_MOMENTUM_H
|
||||
#define LIBGRPP_MOMENTUM_H
|
||||
|
||||
#include "libgrpp_types.h"
|
||||
|
||||
void libgrpp_momentum_integrals(libgrpp_shell_t *shell_A,
|
||||
libgrpp_shell_t *shell_B,
|
||||
double *momentum_x_matrix,
|
||||
double *momentum_y_matrix,
|
||||
double *momentum_z_matrix);
|
||||
|
||||
#endif // LIBGRPP_MOMENTUM_H
|
||||
33
src/grpp/grpp_norm_gaussian.c
Normal file
33
src/grpp/grpp_norm_gaussian.c
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/*----------------------------------------------------------------------------*/
|
||||
/* CP2K: A general program to perform molecular dynamics simulations */
|
||||
/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
|
||||
/* */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* libgrpp - a library for the evaluation of integrals over
|
||||
* generalized relativistic pseudopotentials.
|
||||
*
|
||||
* Copyright (C) 2021-2023 Alexander Oleynichenko
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
#include "grpp_norm_gaussian.h"
|
||||
|
||||
/**
|
||||
* Calculates normalization factor for the cartesian Gaussian x^n y^l z^m
|
||||
* exp(-alpha*r^2)
|
||||
*/
|
||||
double libgrpp_gaussian_norm_factor(int n, int l, int m, double alpha) {
|
||||
return pow(2 * alpha / M_PI, 0.75) *
|
||||
pow(4 * alpha, 0.5 * (n + l + m)); /* /
|
||||
sqrt((double) double_factorial(2 * n - 1) *
|
||||
(double) double_factorial(2 * l - 1) *
|
||||
(double) double_factorial(2 * m - 1));*/
|
||||
}
|
||||
20
src/grpp/grpp_norm_gaussian.h
Normal file
20
src/grpp/grpp_norm_gaussian.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/*----------------------------------------------------------------------------*/
|
||||
/* CP2K: A general program to perform molecular dynamics simulations */
|
||||
/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
|
||||
/* */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* libgrpp - a library for the evaluation of integrals over
|
||||
* generalized relativistic pseudopotentials.
|
||||
*
|
||||
* Copyright (C) 2021-2023 Alexander Oleynichenko
|
||||
*/
|
||||
|
||||
#ifndef LIBGRPP_NORM_GAUSSIAN_H
|
||||
#define LIBGRPP_NORM_GAUSSIAN_H
|
||||
|
||||
double libgrpp_gaussian_norm_factor(int n, int l, int m, double alpha);
|
||||
|
||||
#endif // LIBGRPP_NORM_GAUSSIAN_H
|
||||
310
src/grpp/grpp_nuclear_attraction.c
Normal file
310
src/grpp/grpp_nuclear_attraction.c
Normal file
|
|
@ -0,0 +1,310 @@
|
|||
/*----------------------------------------------------------------------------*/
|
||||
/* CP2K: A general program to perform molecular dynamics simulations */
|
||||
/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
|
||||
/* */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* libgrpp - a library for the evaluation of integrals over
|
||||
* generalized relativistic pseudopotentials.
|
||||
*
|
||||
* Copyright (C) 2021-2023 Alexander Oleynichenko
|
||||
*/
|
||||
|
||||
/**
|
||||
* Calculation of nuclear attraction integrals.
|
||||
*
|
||||
* For the point charge nuclear model the recursive Obara-Saika scheme is used
|
||||
* to calculate nuclear attraction integrals. For details, see
|
||||
* T. Helgaker, P. Jorgensen, J. Olsen, Molecular Electronic-Structure Theory,
|
||||
* John Wiley & Sons Ltd, 2000.
|
||||
* Chapter 9.10.1, "The Obara-Saika scheme for one-electron Coulomb integrals"
|
||||
*
|
||||
* For the other three models,
|
||||
* - uniformly charged ball
|
||||
* - Gaussian nucleus
|
||||
* - Fermi nucleus,
|
||||
* the scheme is actually the same as for the type 1 (radially-local) ECP
|
||||
* integrals. Electrostatic potential V(r) induced by the finite nuclear charge
|
||||
* distribution is integrated numerically on a radial grid.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "grpp_norm_gaussian.h"
|
||||
#include "grpp_nuclear_models.h"
|
||||
#include "grpp_utils.h"
|
||||
#include "libgrpp.h"
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
void libgrpp_evaluate_radially_local_potential_integral_primitive_gaussians(
|
||||
double *A, int n_cart_A, int *cart_list_A, double alpha_A, double *B,
|
||||
int n_cart_B, int *cart_list_B, double alpha_B, double *C,
|
||||
double (*potential)(double r, void *params), void *potential_params,
|
||||
double *matrix);
|
||||
|
||||
void libgrpp_evaluate_rpp_type1_mmd_n1_primitive_shell_pair(
|
||||
libgrpp_shell_t *shell_A, double alpha_A, libgrpp_shell_t *shell_B,
|
||||
double alpha_B, double *rpp_origin, double rpp_alpha, double *rpp_matrix);
|
||||
|
||||
static double wrapper_coulomb_potential_point(double r, void *params);
|
||||
|
||||
static double wrapper_coulomb_potential_ball(double r, void *params);
|
||||
|
||||
static double wrapper_coulomb_potential_gaussian(double r, void *params);
|
||||
|
||||
static double wrapper_coulomb_potential_fermi(double r, void *params);
|
||||
|
||||
static double wrapper_coulomb_potential_fermi_bubble(double r, void *params);
|
||||
|
||||
/**
|
||||
* Calculates nuclear attraction integral between two shells
|
||||
* represented by contracted Gaussian functions.
|
||||
*
|
||||
* nuclear model should be one of:
|
||||
* LIBGRPP_NUCLEAR_MODEL_POINT_CHARGE
|
||||
* LIBGRPP_NUCLEAR_MODEL_CHARGED_BALL
|
||||
* LIBGRPP_NUCLEAR_MODEL_GAUSSIAN
|
||||
* LIBGRPP_NUCLEAR_MODEL_FERMI
|
||||
* LIBGRPP_NUCLEAR_MODEL_FERMI_BUBBLE
|
||||
* LIBGRPP_NUCLEAR_MODEL_POINT_CHARGE_NUMERICAL
|
||||
*/
|
||||
void libgrpp_nuclear_attraction_integrals(libgrpp_shell_t *shell_A,
|
||||
libgrpp_shell_t *shell_B,
|
||||
double *charge_origin, int charge,
|
||||
int nuclear_model,
|
||||
double *model_params,
|
||||
double *coulomb_matrix) {
|
||||
assert(libgrpp_is_initialized());
|
||||
|
||||
int size_A = libgrpp_get_shell_size(shell_A);
|
||||
int size_B = libgrpp_get_shell_size(shell_B);
|
||||
|
||||
double *buf = calloc(size_A * size_B, sizeof(double));
|
||||
|
||||
memset(coulomb_matrix, 0, size_A * size_B * sizeof(double));
|
||||
|
||||
// loop over primitives in contractions
|
||||
for (int i = 0; i < shell_A->num_primitives; i++) {
|
||||
double coef_A_i = shell_A->coeffs[i];
|
||||
|
||||
for (int j = 0; j < shell_B->num_primitives; j++) {
|
||||
double coef_B_j = shell_B->coeffs[j];
|
||||
|
||||
if (fabs(coef_A_i * coef_B_j) < 1e-13) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (nuclear_model == LIBGRPP_NUCLEAR_MODEL_POINT_CHARGE) {
|
||||
|
||||
// use code for RPP type-1 integrals with RPP exponent = 0.0
|
||||
libgrpp_evaluate_rpp_type1_mmd_n1_primitive_shell_pair(
|
||||
shell_A, shell_A->alpha[i], shell_B, shell_B->alpha[j],
|
||||
charge_origin, 0.0, buf);
|
||||
|
||||
for (int k = 0; k < size_A * size_B; k++) {
|
||||
buf[k] *= (-1) * charge;
|
||||
}
|
||||
} else if (nuclear_model == LIBGRPP_NUCLEAR_MODEL_CHARGED_BALL ||
|
||||
nuclear_model == LIBGRPP_NUCLEAR_MODEL_GAUSSIAN ||
|
||||
nuclear_model == LIBGRPP_NUCLEAR_MODEL_FERMI ||
|
||||
nuclear_model == LIBGRPP_NUCLEAR_MODEL_FERMI_BUBBLE ||
|
||||
nuclear_model ==
|
||||
LIBGRPP_NUCLEAR_MODEL_POINT_CHARGE_NUMERICAL) {
|
||||
|
||||
double params[10];
|
||||
params[0] = charge;
|
||||
|
||||
/*
|
||||
* choose nuclear model
|
||||
*/
|
||||
double (*electrostatic_potential_fun)(double, void *) = NULL;
|
||||
|
||||
if (nuclear_model == LIBGRPP_NUCLEAR_MODEL_POINT_CHARGE_NUMERICAL) {
|
||||
// printf("charge distribution: point\n");
|
||||
electrostatic_potential_fun = wrapper_coulomb_potential_point;
|
||||
} else if (nuclear_model == LIBGRPP_NUCLEAR_MODEL_CHARGED_BALL) {
|
||||
params[1] = model_params[0]; // R_rms
|
||||
electrostatic_potential_fun = wrapper_coulomb_potential_ball;
|
||||
} else if (nuclear_model == LIBGRPP_NUCLEAR_MODEL_GAUSSIAN) {
|
||||
params[1] = model_params[0]; // R_rms
|
||||
electrostatic_potential_fun = wrapper_coulomb_potential_gaussian;
|
||||
} else if (nuclear_model == LIBGRPP_NUCLEAR_MODEL_FERMI) {
|
||||
params[1] = model_params[0]; // c
|
||||
params[2] = model_params[1]; // a
|
||||
electrostatic_potential_fun = wrapper_coulomb_potential_fermi;
|
||||
} else {
|
||||
params[1] = model_params[0]; // c
|
||||
params[2] = model_params[1]; // a
|
||||
params[3] = model_params[2]; // k
|
||||
electrostatic_potential_fun = wrapper_coulomb_potential_fermi_bubble;
|
||||
}
|
||||
|
||||
/*
|
||||
* calculate integrals for the shell pair
|
||||
*/
|
||||
libgrpp_evaluate_radially_local_potential_integral_primitive_gaussians(
|
||||
shell_A->origin, size_A, shell_A->cart_list, shell_A->alpha[i],
|
||||
shell_B->origin, size_B, shell_B->cart_list, shell_B->alpha[j],
|
||||
charge_origin, electrostatic_potential_fun, params, buf);
|
||||
} else {
|
||||
printf("LIBGRPP: unknown finite nuclear charge distribution model!\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
libgrpp_daxpy(size_A * size_B, coef_A_i * coef_B_j, buf, coulomb_matrix);
|
||||
}
|
||||
}
|
||||
|
||||
free(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates nuclear attraction integral between two shells
|
||||
* represented by contracted Gaussian functions for the electrostatic potential
|
||||
* generated by the point charge.
|
||||
*/
|
||||
void libgrpp_nuclear_attraction_integrals_point_charge(libgrpp_shell_t *shell_A,
|
||||
libgrpp_shell_t *shell_B,
|
||||
double *charge_origin,
|
||||
int charge,
|
||||
double *coulomb_matrix) {
|
||||
libgrpp_nuclear_attraction_integrals(shell_A, shell_B, charge_origin, charge,
|
||||
LIBGRPP_NUCLEAR_MODEL_POINT_CHARGE, NULL,
|
||||
coulomb_matrix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates nuclear attraction integral between two shells
|
||||
* represented by contracted Gaussian functions for the electrostatic potential
|
||||
* generated by the charged ball.
|
||||
*
|
||||
* r_rms stands for the root mean square radius (in bohrs)
|
||||
*/
|
||||
void libgrpp_nuclear_attraction_integrals_charged_ball(libgrpp_shell_t *shell_A,
|
||||
libgrpp_shell_t *shell_B,
|
||||
double *charge_origin,
|
||||
int charge, double r_rms,
|
||||
double *coulomb_matrix) {
|
||||
double params[10];
|
||||
params[0] = charge;
|
||||
params[1] = r_rms;
|
||||
|
||||
libgrpp_nuclear_attraction_integrals(shell_A, shell_B, charge_origin, charge,
|
||||
LIBGRPP_NUCLEAR_MODEL_CHARGED_BALL,
|
||||
params, coulomb_matrix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates nuclear attraction integral between two shells
|
||||
* represented by contracted Gaussian functions for the electrostatic potential
|
||||
* generated by the Gaussian distribution.
|
||||
*
|
||||
* r_rms stands for the root mean square radius (in bohrs)
|
||||
*/
|
||||
void libgrpp_nuclear_attraction_integrals_gaussian_model(
|
||||
libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B, double *charge_origin,
|
||||
int charge, double r_rms, double *coulomb_matrix) {
|
||||
double params[10];
|
||||
params[0] = charge;
|
||||
params[1] = r_rms;
|
||||
|
||||
libgrpp_nuclear_attraction_integrals(shell_A, shell_B, charge_origin, charge,
|
||||
LIBGRPP_NUCLEAR_MODEL_GAUSSIAN, params,
|
||||
coulomb_matrix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates nuclear attraction integral between two shells
|
||||
* represented by contracted Gaussian functions for the electrostatic potential
|
||||
* generated by the Fermi distribution.
|
||||
*
|
||||
* Model parameters 'c' and 'a' must be given in bohrs.
|
||||
*/
|
||||
void libgrpp_nuclear_attraction_integrals_fermi_model(
|
||||
libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B, double *charge_origin,
|
||||
int charge, double fermi_param_c, double fermi_param_a,
|
||||
double *coulomb_matrix) {
|
||||
double params[10];
|
||||
params[0] = charge;
|
||||
params[1] = fermi_param_c;
|
||||
params[2] = fermi_param_a;
|
||||
|
||||
libgrpp_nuclear_attraction_integrals(shell_A, shell_B, charge_origin, charge,
|
||||
LIBGRPP_NUCLEAR_MODEL_FERMI, params,
|
||||
coulomb_matrix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates nuclear attraction integral between two shells
|
||||
* represented by contracted Gaussian functions for the electrostatic potential
|
||||
* generated by the "Fermi + bubble" distribution.
|
||||
*
|
||||
* Model parameters 'c' and 'a' must be given in bohrs.
|
||||
* The 'k' constant is dimensionless.
|
||||
*/
|
||||
void libgrpp_nuclear_attraction_integrals_fermi_bubble_model(
|
||||
libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B, double *charge_origin,
|
||||
int charge, double param_c, double param_a, double param_k,
|
||||
double *coulomb_matrix) {
|
||||
double params[10];
|
||||
params[0] = charge;
|
||||
params[1] = param_c;
|
||||
params[2] = param_a;
|
||||
params[3] = param_k;
|
||||
|
||||
libgrpp_nuclear_attraction_integrals(shell_A, shell_B, charge_origin, charge,
|
||||
LIBGRPP_NUCLEAR_MODEL_FERMI_BUBBLE,
|
||||
params, coulomb_matrix);
|
||||
}
|
||||
|
||||
/**
|
||||
* wrappers for charge distribution functions.
|
||||
* are used to provide a unified interface to radially-local potentials.
|
||||
* the 'params' argument is unpacked, then the specific routines are invoked.
|
||||
*/
|
||||
|
||||
static double wrapper_coulomb_potential_point(double r, void *params) {
|
||||
double Z = ((double *)params)[0];
|
||||
|
||||
return libgrpp_coulomb_potential_point(r, Z);
|
||||
}
|
||||
|
||||
static double wrapper_coulomb_potential_ball(double r, void *params) {
|
||||
double Z = ((double *)params)[0];
|
||||
double R_rms = ((double *)params)[1];
|
||||
|
||||
return libgrpp_coulomb_potential_ball(r, Z, R_rms);
|
||||
}
|
||||
|
||||
static double wrapper_coulomb_potential_gaussian(double r, void *params) {
|
||||
double Z = ((double *)params)[0];
|
||||
double R_rms = ((double *)params)[1];
|
||||
|
||||
return libgrpp_coulomb_potential_gaussian(r, Z, R_rms);
|
||||
}
|
||||
|
||||
static double wrapper_coulomb_potential_fermi(double r, void *params) {
|
||||
double Z = ((double *)params)[0];
|
||||
double c = ((double *)params)[1];
|
||||
double a = ((double *)params)[2];
|
||||
|
||||
return libgrpp_coulomb_potential_fermi(r, Z, c, a);
|
||||
}
|
||||
|
||||
static double wrapper_coulomb_potential_fermi_bubble(double r, void *params) {
|
||||
double Z = ((double *)params)[0];
|
||||
double c = ((double *)params)[1];
|
||||
double a = ((double *)params)[2];
|
||||
double k = ((double *)params)[3];
|
||||
|
||||
return libgrpp_coulomb_potential_fermi_bubble(r, Z, c, a, k);
|
||||
}
|
||||
337
src/grpp/grpp_nuclear_models.c
Normal file
337
src/grpp/grpp_nuclear_models.c
Normal file
|
|
@ -0,0 +1,337 @@
|
|||
/*----------------------------------------------------------------------------*/
|
||||
/* CP2K: A general program to perform molecular dynamics simulations */
|
||||
/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
|
||||
/* */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* libgrpp - a library for the evaluation of integrals over
|
||||
* generalized relativistic pseudopotentials.
|
||||
*
|
||||
* Copyright (C) 2021-2023 Alexander Oleynichenko
|
||||
*/
|
||||
|
||||
#include "grpp_nuclear_models.h"
|
||||
#include "grpp_specfunc.h"
|
||||
#include <math.h>
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
extern double libgrpp_fermi_model_Sk(int k, double x);
|
||||
|
||||
extern double libgrpp_fermi_model_norm_factor(double c, double a);
|
||||
|
||||
extern double libgrpp_fermi_bubble_model_norm_factor(double c, double a,
|
||||
double k);
|
||||
|
||||
/*
|
||||
* estimates for root mean square radius of nuclear charge distribution
|
||||
*/
|
||||
|
||||
/**
|
||||
* estimate for R(rms) from:
|
||||
* W. R. Johnson, G. Soff. The Lamb shift in hydrogen-like atoms, 1 <= Z <=>
|
||||
* 110. At. Data Nucl. Data Tables, 33(3), 405 (1985).
|
||||
*
|
||||
* A = mass number
|
||||
* returns R(rms) in [fm] units
|
||||
*/
|
||||
double libgrpp_estimate_nuclear_rms_radius_johnson_1985(int A) {
|
||||
return 0.836 * pow(A, 1.0 / 3.0) + 0.570;
|
||||
}
|
||||
|
||||
/**
|
||||
* estimate for R(rms) from:
|
||||
* O. A. Golovko, I. A. Goidenko, I. I. Tupitsyn.
|
||||
* Quantum electrodynamic corrections for valence electrons in Eka-Hg.
|
||||
* Opt. Spectrosc. 104(5), 662 (2008).
|
||||
*
|
||||
* A = mass number
|
||||
* returns R(rms) in [fm] units
|
||||
*/
|
||||
double libgrpp_estimate_nuclear_rms_radius_golovko_2008(int A) {
|
||||
return 0.77 * pow(A, 1.0 / 3.0) + 0.98;
|
||||
}
|
||||
|
||||
/**
|
||||
* estimate parameters of the Fermi model using default formulas for 'c' and
|
||||
* 'a'. return -1 if such estimate cannot be performed, 1 otherwise.
|
||||
*
|
||||
* units: Fermi for R_rms, c, a.
|
||||
*/
|
||||
int libgrpp_estimate_fermi_model_parameters(double R_rms, double *c,
|
||||
double *a) {
|
||||
const double t = 2.3;
|
||||
*a = t / (4 * log(3));
|
||||
|
||||
const double c2 =
|
||||
5.0 / 3.0 * R_rms * R_rms - 7.0 / 3.0 * M_PI * M_PI * (*a) * (*a);
|
||||
if (c2 < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*c = sqrt(c2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* radially-local electrostatic potentials and density functions
|
||||
* for different nuclear finite charge distribution models
|
||||
*/
|
||||
|
||||
/**
|
||||
* point charge
|
||||
*/
|
||||
double libgrpp_coulomb_potential_point(double r, double Z) { return -Z / r; }
|
||||
|
||||
/**
|
||||
* uniformly charged ball: density
|
||||
*/
|
||||
double libgrpp_charge_density_ball(double r, double Z, double R_rms) {
|
||||
const double R0 = sqrt(5.0 / 3.0) * R_rms;
|
||||
|
||||
if (r <= R0) {
|
||||
return 3.0 * Z / (4.0 * M_PI * R0 * R0 * R0);
|
||||
} else {
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* uniformly charged ball: potential
|
||||
*
|
||||
* formula from:
|
||||
* L. Visscher, K. G. Dyall,
|
||||
* Dirac-Fock atomic electronic structure calculations using different nuclear
|
||||
* charge distributions. Atomic Data and Nuclear Data Tables, 67, 207–224 (1997)
|
||||
*/
|
||||
double libgrpp_coulomb_potential_ball(double r, double Z, double R_rms) {
|
||||
const double R0 = sqrt(5.0 / 3.0) * R_rms;
|
||||
|
||||
if (r <= R0) {
|
||||
return -Z / (2.0 * R0) * (3.0 - r * r / (R0 * R0));
|
||||
} else {
|
||||
return -Z / r;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gaussian charge distribution: density
|
||||
*/
|
||||
double libgrpp_charge_density_gaussian(double r, double Z, double R_rms) {
|
||||
const double xi = 3.0 / (2.0 * R_rms * R_rms);
|
||||
const double rho0 = Z * pow(xi / M_PI, 1.5);
|
||||
|
||||
return rho0 * exp(-xi * r * r);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gaussian charge distribution: potential
|
||||
*
|
||||
* formula from:
|
||||
* L. Visscher, K. G. Dyall,
|
||||
* Dirac-Fock atomic electronic structure calculations using different nuclear
|
||||
* charge distributions. Atomic Data and Nuclear Data Tables, 67, 207–224 (1997)
|
||||
*/
|
||||
double libgrpp_coulomb_potential_gaussian(double r, double Z, double R_rms) {
|
||||
const double xi = 3.0 / (2.0 * R_rms * R_rms);
|
||||
|
||||
return -Z / r * erf(sqrt(xi) * r);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fermi charge distribution: density
|
||||
*/
|
||||
double libgrpp_charge_density_fermi(double r, double Z, double c, double a) {
|
||||
const double N = libgrpp_fermi_model_norm_factor(c, a);
|
||||
const double c3 = c * c * c;
|
||||
const double rho0 = 3.0 * Z / (4 * M_PI * c3 * N);
|
||||
|
||||
return rho0 / (1.0 + exp((r - c) / a));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fermi charge distribution: rms radius
|
||||
*/
|
||||
double libgrpp_rms_radius_fermi(int Z, double c, double a) {
|
||||
const double N = libgrpp_fermi_model_norm_factor(c, a);
|
||||
const double c3 = c * c * c;
|
||||
const double rho0 = 3.0 * Z / (4 * M_PI * c3 * N);
|
||||
|
||||
const double r2 =
|
||||
4 * M_PI * rho0 / Z * pow(c, 5) / 5.0 *
|
||||
(1.0 + 10.0 / 3.0 * a * a * M_PI * M_PI / (c * c) +
|
||||
7.0 / 3.0 * pow(M_PI, 4) * pow(a, 4) / pow(c, 4) -
|
||||
120.0 * pow(a, 5) / pow(c, 5) * libgrpp_specfunc_fermi_sk(5, -c / a));
|
||||
|
||||
return sqrt(r2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fermi charge distribution: potential
|
||||
*
|
||||
* formula from:
|
||||
* N. S. Mosyagin, A. V. Zaitsevskii, A. V. Titov
|
||||
* Generalized relativistic effective core potentials for superheavy elements
|
||||
* Int. J. Quantum Chem. e26076 (2019)
|
||||
* doi: https://doi.org/10.1002/qua.26076
|
||||
*/
|
||||
double libgrpp_coulomb_potential_fermi(double r, double Z, double c, double a) {
|
||||
const double a2 = a * a;
|
||||
const double a3 = a * a * a;
|
||||
const double c3 = c * c * c;
|
||||
const double N = libgrpp_fermi_model_norm_factor(c, a);
|
||||
|
||||
if (r > c) {
|
||||
const double S2 = libgrpp_specfunc_fermi_sk(2, (c - r) / a);
|
||||
const double S3 = libgrpp_specfunc_fermi_sk(3, (c - r) / a);
|
||||
|
||||
return -Z / (N * r) * (N + 3 * a2 * r / c3 * S2 + 6 * a3 / c3 * S3);
|
||||
} else {
|
||||
const double P2 = libgrpp_specfunc_fermi_sk(2, (r - c) / a);
|
||||
const double P3 = libgrpp_specfunc_fermi_sk(3, (r - c) / a);
|
||||
const double S3 = libgrpp_specfunc_fermi_sk(3, -c / a);
|
||||
const double r3 = r * r * r;
|
||||
|
||||
return -Z / (N * r) *
|
||||
(1.5 * r / c - r3 / (2 * c3) + M_PI * M_PI * a2 * r / (2 * c3) -
|
||||
3 * a2 * r / c3 * P2 + 6 * a3 / c3 * (P3 - S3));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* normalization factor for the Fermi nuclear charge distribution
|
||||
*/
|
||||
double libgrpp_fermi_model_norm_factor(double c, double a) {
|
||||
const double a2 = a * a;
|
||||
const double a3 = a * a * a;
|
||||
const double c2 = c * c;
|
||||
const double c3 = c * c * c;
|
||||
|
||||
return 1.0 + M_PI * M_PI * a2 / c2 -
|
||||
6.0 * a3 / c3 * libgrpp_specfunc_fermi_sk(3, -c / a);
|
||||
}
|
||||
|
||||
/**
|
||||
* "Fermi bubble" charge distribution: density
|
||||
*/
|
||||
double libgrpp_charge_density_fermi_bubble(double r, double Z, double c,
|
||||
double a, double k) {
|
||||
const double Nk = libgrpp_fermi_bubble_model_norm_factor(c, a, k);
|
||||
const double c3 = c * c * c;
|
||||
const double rho0 = 3.0 * Z / (4 * M_PI * c3 * Nk);
|
||||
|
||||
return rho0 * (1 + k * pow(r / c, 2)) / (1.0 + exp((r - c) / a));
|
||||
}
|
||||
|
||||
/**
|
||||
* "Fermi bubble" charge distribution: rms radius
|
||||
*/
|
||||
double libgrpp_rms_radius_fermi_bubble(int Z, double c, double a, double k) {
|
||||
const double Nk = libgrpp_fermi_bubble_model_norm_factor(c, a, k);
|
||||
const double c3 = c * c * c;
|
||||
const double rho0 = 3.0 * Z / (4 * M_PI * c3 * Nk);
|
||||
|
||||
const double part_r4 =
|
||||
pow(c, 5) / 5.0 *
|
||||
(1.0 + 10.0 / 3.0 * a * a * M_PI * M_PI / (c * c) +
|
||||
7.0 / 3.0 * pow(M_PI, 4) * pow(a, 4) / pow(c, 4) -
|
||||
120.0 * pow(a, 5) / pow(c, 5) * libgrpp_specfunc_fermi_sk(5, -c / a));
|
||||
|
||||
const double part_r6 =
|
||||
pow(c, 7) / 7.0 *
|
||||
(1.0 + 7.0 * a * a * M_PI * M_PI / (c * c) +
|
||||
49.0 / 3.0 * pow(M_PI, 4) * pow(a, 4) / pow(c, 4) +
|
||||
31.0 / 3.0 * pow(M_PI, 6) * pow(a, 6) / pow(c, 6) -
|
||||
5040.0 * pow(a, 7) / pow(c, 7) * libgrpp_specfunc_fermi_sk(7, -c / a));
|
||||
|
||||
const double r2 = 4 * M_PI * rho0 / Z * (part_r4 + k / (c * c) * part_r6);
|
||||
|
||||
return sqrt(r2);
|
||||
}
|
||||
|
||||
/**
|
||||
* "Fermi bubble" charge distribution: potential.
|
||||
*
|
||||
* derivation of the formula is based on:
|
||||
*
|
||||
* F. A. Parpia and A. K. Mohanty,
|
||||
* Relativistic basis-set calculations for atoms with Fermi nuclei.
|
||||
* Phys. Rev. A 46, 3735 (1992)
|
||||
* doi: 10.1103/PhysRevA.46.3735
|
||||
*
|
||||
*/
|
||||
double libgrpp_coulomb_potential_fermi_bubble(double r, double Z, double c,
|
||||
double a, double k) {
|
||||
// const double a2 = a * a;
|
||||
// const double a3 = a * a * a;
|
||||
// const double c2 = c * c;
|
||||
// const double c3 = c * c * c;
|
||||
|
||||
const double Nk = libgrpp_fermi_bubble_model_norm_factor(c, a, k);
|
||||
// const double rho0 = 3 * Z / (4 * M_PI * M_PI * c * c * c * Nk);
|
||||
|
||||
double F0 = 0.0;
|
||||
double F2 = 0.0;
|
||||
|
||||
if (r < c) {
|
||||
const double S2 = libgrpp_specfunc_fermi_sk(2, (r - c) / a);
|
||||
const double S3 = libgrpp_specfunc_fermi_sk(3, (r - c) / a);
|
||||
const double S4 = libgrpp_specfunc_fermi_sk(4, (r - c) / a);
|
||||
const double S5 = libgrpp_specfunc_fermi_sk(5, (r - c) / a);
|
||||
|
||||
// contribution from the "classical" Fermi term
|
||||
F0 = -pow(r, 3) / 6.0 - r * a * a * S2 + 2.0 * pow(a, 3) * S3 +
|
||||
r * c * c / 2.0 + M_PI * M_PI / 6.0 * r * a * a -
|
||||
2.0 * pow(a, 3) * libgrpp_specfunc_fermi_sk(3, -c / a);
|
||||
|
||||
// contribution from the quadratic, "hole" term
|
||||
F2 = -pow(r, 5) / 20.0 - pow(r, 3) * pow(a, 2) * S2 +
|
||||
6.0 * pow(r, 2) * pow(a, 3) * S3 - 18.0 * r * pow(a, 4) * S4 +
|
||||
24.0 * pow(a, 5) * S5 + r * pow(c, 4) / 4.0 +
|
||||
r * M_PI * M_PI * c * c * a * a / 2.0 +
|
||||
r * pow(a, 4) * pow(M_PI, 4) * 7.0 / 60.0 -
|
||||
24.0 * pow(a, 5) * libgrpp_specfunc_fermi_sk(5, -c / a);
|
||||
} else {
|
||||
const double S2 = libgrpp_specfunc_fermi_sk(2, (c - r) / a);
|
||||
const double S3 = libgrpp_specfunc_fermi_sk(3, (c - r) / a);
|
||||
const double S4 = libgrpp_specfunc_fermi_sk(4, (c - r) / a);
|
||||
const double S5 = libgrpp_specfunc_fermi_sk(5, (c - r) / a);
|
||||
|
||||
// contribution from the "classical" Fermi term
|
||||
F0 = pow(c, 3) / 3.0 + M_PI * M_PI / 3.0 * c * a * a -
|
||||
2.0 * pow(a, 3) * libgrpp_specfunc_fermi_sk(3, -c / a) +
|
||||
r * a * a * S2 + 2.0 * pow(a, 3) * S3;
|
||||
|
||||
// contribution from the quadratic, "hole" term
|
||||
F2 = pow(c, 5) / 5.0 + 2.0 * pow(c, 3) * a * a * M_PI * M_PI / 3.0 +
|
||||
7.0 * pow(a, 4) * c * pow(M_PI, 4) / 15.0 -
|
||||
24.0 * pow(a, 5) * libgrpp_specfunc_fermi_sk(5, -c / a) +
|
||||
pow(a, 2) * pow(r, 3) * S2 + 6.0 * pow(a, 3) * pow(r, 2) * S3 +
|
||||
18.0 * r * pow(a, 4) * S4 + 24.0 * pow(a, 5) * S5;
|
||||
}
|
||||
|
||||
return -Z / (Nk * r) * 3.0 / pow(c, 3) * (F0 + k / (c * c) * F2);
|
||||
}
|
||||
|
||||
/**
|
||||
* normalization factor for the "Fermi bubble" nuclear charge distribution
|
||||
*/
|
||||
double libgrpp_fermi_bubble_model_norm_factor(double c, double a, double k) {
|
||||
const double a2 = a * a;
|
||||
const double a3 = a * a2;
|
||||
const double a4 = a * a3;
|
||||
const double a5 = a * a4;
|
||||
const double c2 = c * c;
|
||||
const double c3 = c * c2;
|
||||
const double c4 = c * c3;
|
||||
const double c5 = c * c4;
|
||||
|
||||
return libgrpp_fermi_model_norm_factor(c, a) + 3.0 / 5.0 * k +
|
||||
2.0 * M_PI * M_PI * a2 * k / c2 +
|
||||
7.0 * M_PI * M_PI * M_PI * M_PI * a4 * k / (5.0 * c4) -
|
||||
72.0 * a5 * k / c5 * libgrpp_specfunc_fermi_sk(5, -c / a);
|
||||
}
|
||||
50
src/grpp/grpp_nuclear_models.h
Normal file
50
src/grpp/grpp_nuclear_models.h
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/*----------------------------------------------------------------------------*/
|
||||
/* CP2K: A general program to perform molecular dynamics simulations */
|
||||
/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
|
||||
/* */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* libgrpp - a library for the evaluation of integrals over
|
||||
* generalized relativistic pseudopotentials.
|
||||
*
|
||||
* Copyright (C) 2021-2023 Alexander Oleynichenko
|
||||
*/
|
||||
|
||||
#ifndef TEST_LIBGRPP_F90_X_NUCLEAR_MODELS_H
|
||||
#define TEST_LIBGRPP_F90_X_NUCLEAR_MODELS_H
|
||||
|
||||
#define FERMI_UNITS_TO_ATOMIC (1.0 / 52917.7210903)
|
||||
|
||||
double libgrpp_estimate_nuclear_rms_radius_johnson_1985(int A);
|
||||
|
||||
double libgrpp_estimate_nuclear_rms_radius_golovko_2008(int A);
|
||||
|
||||
int libgrpp_estimate_fermi_model_parameters(double R_rms, double *c, double *a);
|
||||
|
||||
double libgrpp_charge_density_ball(double r, double Z, double R_rms);
|
||||
|
||||
double libgrpp_charge_density_gaussian(double r, double Z, double R_rms);
|
||||
|
||||
double libgrpp_charge_density_fermi(double r, double Z, double c, double a);
|
||||
|
||||
double libgrpp_charge_density_fermi_bubble(double r, double Z, double c,
|
||||
double a, double k);
|
||||
|
||||
double libgrpp_rms_radius_fermi(int Z, double c, double a);
|
||||
|
||||
double libgrpp_rms_radius_fermi_bubble(int Z, double c, double a, double k);
|
||||
|
||||
double libgrpp_coulomb_potential_point(double r, double Z);
|
||||
|
||||
double libgrpp_coulomb_potential_ball(double r, double Z, double R_rms);
|
||||
|
||||
double libgrpp_coulomb_potential_gaussian(double r, double Z, double R_rms);
|
||||
|
||||
double libgrpp_coulomb_potential_fermi(double r, double Z, double c, double a);
|
||||
|
||||
double libgrpp_coulomb_potential_fermi_bubble(double r, double Z, double c,
|
||||
double a, double k);
|
||||
|
||||
#endif // TEST_LIBGRPP_F90_X_NUCLEAR_MODELS_H
|
||||
549
src/grpp/grpp_outercore_integrals.c
Normal file
549
src/grpp/grpp_outercore_integrals.c
Normal file
|
|
@ -0,0 +1,549 @@
|
|||
/*----------------------------------------------------------------------------*/
|
||||
/* CP2K: A general program to perform molecular dynamics simulations */
|
||||
/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
|
||||
/* */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* libgrpp - a library for the evaluation of integrals over
|
||||
* generalized relativistic pseudopotentials.
|
||||
*
|
||||
* Copyright (C) 2021-2023 Alexander Oleynichenko
|
||||
*/
|
||||
|
||||
/*
|
||||
* Integration of the non-local terms in the GRPP operator.
|
||||
* These integrals are reduced to the type 1 integrals and overlap integrals.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
#include "grpp_factorial.h"
|
||||
#include "grpp_lmatrix.h"
|
||||
#include "grpp_overlap.h"
|
||||
#include "grpp_spherical_harmonics.h"
|
||||
#include "grpp_utils.h"
|
||||
#include "libgrpp.h"
|
||||
|
||||
/*
|
||||
* pre-definitions of function used below
|
||||
*/
|
||||
|
||||
void libgrpp_outercore_potential_integrals_part_1(
|
||||
libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B, double *C,
|
||||
libgrpp_potential_t *oc_potential, libgrpp_shell_t *oc_shell,
|
||||
double *arep_matrix, double *so_x_matrix, double *so_y_matrix,
|
||||
double *so_z_matrix);
|
||||
|
||||
void libgrpp_outercore_potential_integrals_part_2(
|
||||
libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B, double *C,
|
||||
libgrpp_potential_t *oc_potential_1, libgrpp_shell_t *oc_shell_1,
|
||||
libgrpp_potential_t *oc_potential_2, libgrpp_shell_t *oc_shell_2,
|
||||
double *arep_matrix, double *so_x_matrix, double *so_y_matrix,
|
||||
double *so_z_matrix);
|
||||
|
||||
static double calculate_delta_integral(libgrpp_potential_t *oc_pot_1,
|
||||
libgrpp_shell_t *oc_shell_1,
|
||||
libgrpp_potential_t *oc_pot_2,
|
||||
libgrpp_shell_t *oc_shell_2);
|
||||
|
||||
static void transform_to_sph_basis_ket(int dim_bra, int dim_ket_cart,
|
||||
int dim_ket_sph, double *A_in,
|
||||
double *A_out, double *S_lm_coef);
|
||||
|
||||
static void transform_to_sph_basis_bra(int dim_bra_cart, int dim_bra_sph,
|
||||
int dim_ket, double *A_in, double *A_out,
|
||||
double *S_lm_coef);
|
||||
|
||||
static double ang_norm_factor(int lx, int ly, int lz);
|
||||
|
||||
static double analytic_one_center_rpp_integral_contracted(
|
||||
libgrpp_shell_t *bra, libgrpp_shell_t *ket, libgrpp_potential_t *pot);
|
||||
|
||||
static double analytic_one_center_rpp_integral_primitive(int L, double alpha1,
|
||||
double alpha2, int n,
|
||||
double zeta);
|
||||
|
||||
static double radial_gto_norm_factor(int L, double alpha);
|
||||
|
||||
/**
|
||||
* Calculates non-local contributions to the scalar-relativistic ECP and
|
||||
* effective spin-orbit interaction matrices from the outercore (OC) potentials.
|
||||
*/
|
||||
void libgrpp_outercore_potential_integrals(
|
||||
libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B, double *rpp_origin,
|
||||
int num_oc_shells, libgrpp_potential_t **oc_potentials,
|
||||
libgrpp_shell_t **oc_shells, double *arep, double *esop_x, double *esop_y,
|
||||
double *esop_z) {
|
||||
assert(libgrpp_is_initialized());
|
||||
|
||||
// clear output matrices
|
||||
int size_A = libgrpp_get_shell_size(shell_A);
|
||||
int size_B = libgrpp_get_shell_size(shell_B);
|
||||
memset(arep, 0, size_A * size_B * sizeof(double));
|
||||
memset(esop_x, 0, size_A * size_B * sizeof(double));
|
||||
memset(esop_y, 0, size_A * size_B * sizeof(double));
|
||||
memset(esop_z, 0, size_A * size_B * sizeof(double));
|
||||
|
||||
// bind outercore shells of the GRPP to the RPP center
|
||||
for (int ioc = 0; ioc < num_oc_shells; ioc++) {
|
||||
oc_shells[ioc]->origin[0] = rpp_origin[0];
|
||||
oc_shells[ioc]->origin[1] = rpp_origin[1];
|
||||
oc_shells[ioc]->origin[2] = rpp_origin[2];
|
||||
}
|
||||
|
||||
// 1. the U * |nlj><nlj| + |nlj><nlj| * U part
|
||||
for (int ioc = 0; ioc < num_oc_shells; ioc++) {
|
||||
libgrpp_potential_t *pot = oc_potentials[ioc];
|
||||
libgrpp_shell_t *nlj = oc_shells[ioc];
|
||||
|
||||
libgrpp_outercore_potential_integrals_part_1(
|
||||
shell_A, shell_B, rpp_origin, pot, nlj, arep, esop_x, esop_y, esop_z);
|
||||
}
|
||||
|
||||
// 2. the |nlj><nlj| U |n'lj><n'lj| part
|
||||
for (int ioc = 0; ioc < num_oc_shells; ioc++) {
|
||||
for (int joc = 0; joc < num_oc_shells; joc++) {
|
||||
|
||||
libgrpp_potential_t *pot_1 = oc_potentials[ioc];
|
||||
libgrpp_potential_t *pot_2 = oc_potentials[joc];
|
||||
libgrpp_shell_t *nlj_1 = oc_shells[ioc];
|
||||
libgrpp_shell_t *nlj_2 = oc_shells[joc];
|
||||
|
||||
libgrpp_outercore_potential_integrals_part_2(
|
||||
shell_A, shell_B, rpp_origin, pot_1, nlj_1, pot_2, nlj_2, arep,
|
||||
esop_x, esop_y, esop_z);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* integration of the non-local outercore potential:
|
||||
* the U*|nlj><nlj| + |nlj><nlj|*U part
|
||||
*/
|
||||
void libgrpp_outercore_potential_integrals_part_1(
|
||||
libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B, double *C,
|
||||
libgrpp_potential_t *oc_potential, libgrpp_shell_t *oc_shell,
|
||||
double *arep_matrix, double *so_x_matrix, double *so_y_matrix,
|
||||
double *so_z_matrix) {
|
||||
int L = oc_shell->L;
|
||||
double J = oc_potential->J / 2.0;
|
||||
int size_A = libgrpp_get_shell_size(shell_A);
|
||||
int size_B = libgrpp_get_shell_size(shell_B);
|
||||
int size_nlj = libgrpp_get_shell_size(oc_shell);
|
||||
|
||||
/*
|
||||
* foolproof: bind outercore shells to the ECP center
|
||||
*/
|
||||
oc_shell->origin[0] = C[0];
|
||||
oc_shell->origin[1] = C[1];
|
||||
oc_shell->origin[2] = C[2];
|
||||
|
||||
/*
|
||||
* Transformation coefficients: Cartesian -> Real spherical
|
||||
* Rows: real spherical harmonics S_lm
|
||||
* Columns: cartesians x^r y^s z^t
|
||||
*/
|
||||
double *S_lm_coef = (double *)calloc((2 * L + 1) * size_nlj, sizeof(double));
|
||||
for (int m = -L; m <= +L; m++) {
|
||||
for (int icart = 0; icart < size_nlj; icart++) {
|
||||
int r = oc_shell->cart_list[3 * icart + 0];
|
||||
int s = oc_shell->cart_list[3 * icart + 1];
|
||||
int t = oc_shell->cart_list[3 * icart + 2];
|
||||
double u = libgrpp_spherical_to_cartesian_coef(L, m, r, s) /
|
||||
ang_norm_factor(r, s, t);
|
||||
S_lm_coef[size_nlj * (m + L) + icart] = u;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Overlap integrals of the A and B shells with the outercore shell |nlj>:
|
||||
* <A|nljm> and <nljm|B>
|
||||
*
|
||||
* Integrals are evaluated first for the cartesian components of |nlj>, and
|
||||
* then transformed to the basis of real spherical components |nljm>.
|
||||
* Resulting integrals are stored in the 'S_a_nljm' and 'S_nljm_b' arrays.
|
||||
*/
|
||||
double *S_nljm_b_cart =
|
||||
alloc_zeros_1d(size_nlj * size_B); // in cart_list basis
|
||||
double *S_a_nljm_cart = alloc_zeros_1d(size_A * size_nlj);
|
||||
double *S_nljm_b = alloc_zeros_1d((2 * L + 1) * size_B); // in spherical basis
|
||||
double *S_a_nljm = alloc_zeros_1d(size_A * (2 * L + 1));
|
||||
libgrpp_overlap_integrals(oc_shell, shell_B, S_nljm_b_cart); // <nljm|B>
|
||||
libgrpp_overlap_integrals(shell_A, oc_shell, S_a_nljm_cart); // <A|nljm>
|
||||
transform_to_sph_basis_ket(size_A, size_nlj, 2 * L + 1, S_a_nljm_cart,
|
||||
S_a_nljm, S_lm_coef);
|
||||
transform_to_sph_basis_bra(size_nlj, 2 * L + 1, size_B, S_nljm_b_cart,
|
||||
S_nljm_b, S_lm_coef);
|
||||
free(S_nljm_b_cart);
|
||||
free(S_a_nljm_cart);
|
||||
|
||||
/*
|
||||
* ECP type-2 (semilocal) integrals of the A and B shells with the outercore
|
||||
* shell |nlj>: <A|U(r)P_L|nljm> and <nljm|U(r)P_L|B>
|
||||
*
|
||||
* Integrals are evaluated first for the cartesian components of |nlj>, and
|
||||
* then transformed to the basis of real spherical components |nljm>.
|
||||
* Resulting integrals are stored in the 'U_a_nljm' and 'U_nljm_b' arrays.
|
||||
*/
|
||||
double *U_nljm_b_cart =
|
||||
alloc_zeros_1d(size_nlj * size_B); // in cart_list basis
|
||||
double *U_a_nljm_cart = alloc_zeros_1d(size_A * size_nlj);
|
||||
double *U_nljm_b = alloc_zeros_1d((2 * L + 1) * size_B); // in spherical basis
|
||||
double *U_a_nljm = alloc_zeros_1d(size_A * (2 * L + 1));
|
||||
libgrpp_type1_integrals(oc_shell, shell_B, C, oc_potential,
|
||||
U_nljm_b_cart); // <nljm|U(r)P_L|B>
|
||||
libgrpp_type1_integrals(shell_A, oc_shell, C, oc_potential,
|
||||
U_a_nljm_cart); // <A|U(r)P_L|nljm>
|
||||
transform_to_sph_basis_ket(size_A, size_nlj, 2 * L + 1, U_a_nljm_cart,
|
||||
U_a_nljm, S_lm_coef);
|
||||
transform_to_sph_basis_bra(size_nlj, 2 * L + 1, size_B, U_nljm_b_cart,
|
||||
U_nljm_b, S_lm_coef);
|
||||
free(U_nljm_b_cart);
|
||||
free(U_a_nljm_cart);
|
||||
|
||||
/*
|
||||
* Construct outercore AREP matrix elements
|
||||
* < a | P_nlj U(r) P_L + U(r) P_nlj P_L | b >
|
||||
*/
|
||||
double arep_factor =
|
||||
(J < L) ? (L / (2.0 * L + 1)) : ((L + 1) / (2.0 * L + 1));
|
||||
double *buf = alloc_zeros_1d(size_A * size_B);
|
||||
libgrpp_multiply_matrices(size_A, size_B, 2 * L + 1, S_a_nljm, U_nljm_b, buf);
|
||||
libgrpp_multiply_matrices(size_A, size_B, 2 * L + 1, U_a_nljm, S_nljm_b, buf);
|
||||
libgrpp_daxpy(size_A * size_B, arep_factor, buf, arep_matrix);
|
||||
free(buf);
|
||||
|
||||
/*
|
||||
* Construct outercore effective SO potential matrix elements
|
||||
* < a | P_nlj U(r) L P_L + U(r) P_nlj L P_L | b >
|
||||
*/
|
||||
double **L_matrices = alloc_zeros_2d(3, (2 * L + 1) * (2 * L + 1));
|
||||
libgrpp_construct_angular_momentum_matrices_rsh(L, L_matrices[0],
|
||||
L_matrices[1], L_matrices[2]);
|
||||
|
||||
double **so_buf = alloc_zeros_2d(3, size_A * size_B);
|
||||
buf = alloc_zeros_1d((2 * L + 1) * int_max2(size_A, size_B));
|
||||
|
||||
for (int icoord = 0; icoord < 3; icoord++) {
|
||||
// U(r) P_nlj
|
||||
memset(buf, 0, (2 * L + 1) * size_B * sizeof(double));
|
||||
libgrpp_multiply_matrices(2 * L + 1, size_B, 2 * L + 1, L_matrices[icoord],
|
||||
S_nljm_b, buf);
|
||||
libgrpp_multiply_matrices(size_A, size_B, 2 * L + 1, U_a_nljm, buf,
|
||||
so_buf[icoord]);
|
||||
|
||||
// P_nlj U(r)
|
||||
memset(buf, 0, (2 * L + 1) * size_A * sizeof(double));
|
||||
libgrpp_multiply_matrices(size_A, 2 * L + 1, 2 * L + 1, S_a_nljm,
|
||||
L_matrices[icoord], buf);
|
||||
libgrpp_multiply_matrices(size_A, size_B, 2 * L + 1, buf, U_nljm_b,
|
||||
so_buf[icoord]);
|
||||
}
|
||||
|
||||
free(buf);
|
||||
|
||||
double esop_factor = (J < L) ? (-2.0 / (2 * L + 1)) : (+2.0 / (2 * L + 1));
|
||||
libgrpp_daxpy(size_A * size_B, esop_factor, so_buf[0], so_x_matrix);
|
||||
libgrpp_daxpy(size_A * size_B, esop_factor, so_buf[1], so_y_matrix);
|
||||
libgrpp_daxpy(size_A * size_B, esop_factor, so_buf[2], so_z_matrix);
|
||||
|
||||
/*
|
||||
* Cleanup
|
||||
*/
|
||||
free(S_lm_coef);
|
||||
free(S_a_nljm);
|
||||
free(S_nljm_b);
|
||||
free(U_a_nljm);
|
||||
free(U_nljm_b);
|
||||
free_2d(L_matrices, 3);
|
||||
free_2d(so_buf, 3);
|
||||
}
|
||||
|
||||
/**
|
||||
* integration of the non-local outercore potential:
|
||||
* the |nlj><nlj| U |n'lj><n'lj| part
|
||||
*/
|
||||
void libgrpp_outercore_potential_integrals_part_2(
|
||||
libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B, double *C,
|
||||
libgrpp_potential_t *oc_potential_1, libgrpp_shell_t *oc_shell_1,
|
||||
libgrpp_potential_t *oc_potential_2, libgrpp_shell_t *oc_shell_2,
|
||||
double *arep_matrix, double *so_x_matrix, double *so_y_matrix,
|
||||
double *so_z_matrix) {
|
||||
int size_A = libgrpp_get_shell_size(shell_A);
|
||||
int size_B = libgrpp_get_shell_size(shell_B);
|
||||
|
||||
if (oc_potential_1->L != oc_potential_2->L) {
|
||||
return;
|
||||
}
|
||||
if (oc_potential_1->J != oc_potential_2->J) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* foolproof: bind outercore shells to the ECP center
|
||||
*/
|
||||
oc_shell_1->origin[0] = C[0];
|
||||
oc_shell_1->origin[1] = C[1];
|
||||
oc_shell_1->origin[2] = C[2];
|
||||
oc_shell_2->origin[0] = C[0];
|
||||
oc_shell_2->origin[1] = C[1];
|
||||
oc_shell_2->origin[2] = C[2];
|
||||
|
||||
/*
|
||||
* just to be consistent with the MOLGEP code by A. Titov, N. Mosyagin, A.
|
||||
* Petrov: off-diagonal elements <n'lj|U|n''lj> = 0
|
||||
*/
|
||||
/*if (!ecps_are_equal(oc_potential_1, oc_potential_2)) {
|
||||
return;
|
||||
}*/
|
||||
|
||||
int L = oc_potential_1->L;
|
||||
double J = oc_potential_1->J / 2.0;
|
||||
int size_nlj = libgrpp_get_shell_size(oc_shell_1);
|
||||
|
||||
double delta = calculate_delta_integral(oc_potential_1, oc_shell_1,
|
||||
oc_potential_2, oc_shell_2);
|
||||
|
||||
/*
|
||||
* Transformation coefficients: Cartesian -> Real spherical
|
||||
* Rows: real spherical harmonics S_lm
|
||||
* Columns: cartesians x^r y^s z^t
|
||||
*/
|
||||
double *S_lm_coef = (double *)calloc((2 * L + 1) * size_nlj, sizeof(double));
|
||||
for (int m = -L; m <= +L; m++) {
|
||||
for (int icart = 0; icart < size_nlj; icart++) {
|
||||
int r = oc_shell_1->cart_list[3 * icart + 0];
|
||||
int s = oc_shell_1->cart_list[3 * icart + 1];
|
||||
int t = oc_shell_1->cart_list[3 * icart + 2];
|
||||
double u = libgrpp_spherical_to_cartesian_coef(L, m, r, s) /
|
||||
ang_norm_factor(r, s, t);
|
||||
S_lm_coef[size_nlj * (m + L) + icart] = u;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Overlap integrals of the A and B shells with the outercore shells |nlj> and
|
||||
* |n'lj>: <A|nljm> and <n'ljm|B>
|
||||
*
|
||||
* Integrals are evaluated first for the cartesian components of |nlj>, and
|
||||
* then transformed to the basis of real spherical components |nljm>.
|
||||
* Resulting integrals are stored in the 'S_a_nljm1' and 'S_nljm2_b' arrays.
|
||||
*/
|
||||
double *S_nljm2_b_cart =
|
||||
alloc_zeros_1d(size_nlj * size_B); // in cart_list basis
|
||||
double *S_a_nljm1_cart = alloc_zeros_1d(size_A * size_nlj);
|
||||
double *S_nljm2_b =
|
||||
alloc_zeros_1d((2 * L + 1) * size_B); // in spherical basis
|
||||
double *S_a_nljm1 = alloc_zeros_1d(size_A * (2 * L + 1));
|
||||
libgrpp_overlap_integrals(oc_shell_2, shell_B, S_nljm2_b_cart); // <nljm|B>
|
||||
libgrpp_overlap_integrals(shell_A, oc_shell_1, S_a_nljm1_cart); // <A|nljm>
|
||||
transform_to_sph_basis_ket(size_A, size_nlj, 2 * L + 1, S_a_nljm1_cart,
|
||||
S_a_nljm1, S_lm_coef);
|
||||
transform_to_sph_basis_bra(size_nlj, 2 * L + 1, size_B, S_nljm2_b_cart,
|
||||
S_nljm2_b, S_lm_coef);
|
||||
free(S_nljm2_b_cart);
|
||||
free(S_a_nljm1_cart);
|
||||
|
||||
/*
|
||||
* Construct outercore AREP matrix elements
|
||||
* < a | P_nlj U(r) P_n'lj | b >
|
||||
*/
|
||||
double arep_factor =
|
||||
(J < L) ? (L / (2.0 * L + 1)) : ((L + 1) / (2.0 * L + 1));
|
||||
double *buf = alloc_zeros_1d(size_A * size_B);
|
||||
libgrpp_multiply_matrices(size_A, size_B, 2 * L + 1, S_a_nljm1, S_nljm2_b,
|
||||
buf);
|
||||
libgrpp_daxpy(size_A * size_B, (-1.0) * delta * arep_factor, buf,
|
||||
arep_matrix);
|
||||
free(buf);
|
||||
|
||||
/*
|
||||
* Construct outercore effective SO potential matrix elements
|
||||
* < a | P_nlj U(r) L P_L + U(r) P_nlj L P_L | b >
|
||||
*/
|
||||
double **L_matrices = alloc_zeros_2d(3, (2 * L + 1) * (2 * L + 1));
|
||||
libgrpp_construct_angular_momentum_matrices_rsh(L, L_matrices[0],
|
||||
L_matrices[1], L_matrices[2]);
|
||||
|
||||
double **so_buf = alloc_zeros_2d(3, size_A * size_B);
|
||||
buf = alloc_zeros_1d((2 * L + 1) * size_B);
|
||||
for (int icoord = 0; icoord < 3; icoord++) {
|
||||
memset(buf, 0, (2 * L + 1) * size_B * sizeof(double));
|
||||
libgrpp_multiply_matrices(2 * L + 1, size_B, 2 * L + 1, L_matrices[icoord],
|
||||
S_nljm2_b, buf);
|
||||
libgrpp_multiply_matrices(size_A, size_B, 2 * L + 1, S_a_nljm1, buf,
|
||||
so_buf[icoord]);
|
||||
}
|
||||
free(buf);
|
||||
|
||||
double esop_factor = (J < L) ? (-2.0 / (2 * L + 1)) : (+2.0 / (2 * L + 1));
|
||||
libgrpp_daxpy(size_A * size_B, (-1.0) * delta * esop_factor, so_buf[0],
|
||||
so_x_matrix);
|
||||
libgrpp_daxpy(size_A * size_B, (-1.0) * delta * esop_factor, so_buf[1],
|
||||
so_y_matrix);
|
||||
libgrpp_daxpy(size_A * size_B, (-1.0) * delta * esop_factor, so_buf[2],
|
||||
so_z_matrix);
|
||||
|
||||
free_2d(so_buf, 3);
|
||||
free_2d(L_matrices, 3);
|
||||
|
||||
free(S_nljm2_b);
|
||||
free(S_a_nljm1);
|
||||
free(S_lm_coef);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculation of radial "delta" integrals.
|
||||
* Is performed analytically.
|
||||
*/
|
||||
static double calculate_delta_integral(libgrpp_potential_t *oc_pot_1,
|
||||
libgrpp_shell_t *oc_shell_1,
|
||||
libgrpp_potential_t *oc_pot_2,
|
||||
libgrpp_shell_t *oc_shell_2) {
|
||||
// both shells must have equal L,J quantum numbers, otherwise
|
||||
// the < nlj | U | n'l'j' > integral is strictly zero
|
||||
if (oc_pot_1->L != oc_pot_2->L || oc_pot_1->J != oc_pot_2->J) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
double U1 = analytic_one_center_rpp_integral_contracted(oc_shell_1,
|
||||
oc_shell_2, oc_pot_1);
|
||||
double U2 = analytic_one_center_rpp_integral_contracted(oc_shell_1,
|
||||
oc_shell_2, oc_pot_2);
|
||||
|
||||
return 0.5 * (U1 + U2);
|
||||
}
|
||||
|
||||
/**
|
||||
* analytic formula for one-center RPP integral between two contracted gaussian
|
||||
* functions.
|
||||
*/
|
||||
static double analytic_one_center_rpp_integral_contracted(
|
||||
libgrpp_shell_t *bra, libgrpp_shell_t *ket, libgrpp_potential_t *pot) {
|
||||
double sum = 0.0;
|
||||
int L = pot->L;
|
||||
|
||||
for (int i = 0; i < bra->num_primitives; i++) {
|
||||
double coef_i = bra->coeffs[i];
|
||||
double alpha_i = bra->alpha[i];
|
||||
double N_i = radial_gto_norm_factor(L, alpha_i);
|
||||
|
||||
for (int j = 0; j < ket->num_primitives; j++) {
|
||||
double coef_j = ket->coeffs[j];
|
||||
double alpha_j = ket->alpha[j];
|
||||
double N_j = radial_gto_norm_factor(L, alpha_j);
|
||||
double factor = N_i * N_j * coef_i * coef_j;
|
||||
|
||||
for (int k = 0; k < pot->num_primitives; k++) {
|
||||
double coef_k = pot->coeffs[k];
|
||||
double zeta = pot->alpha[k];
|
||||
int n_rpp = pot->powers[k];
|
||||
|
||||
double u_ijk = analytic_one_center_rpp_integral_primitive(
|
||||
L, alpha_i, alpha_j, n_rpp, zeta);
|
||||
|
||||
sum += factor * coef_k * u_ijk;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
/**
|
||||
* analytic formula for one-center RPP integral between two gaussian primitives.
|
||||
* normalization factors are omitted here.
|
||||
*/
|
||||
static double analytic_one_center_rpp_integral_primitive(int L, double alpha1,
|
||||
double alpha2, int n,
|
||||
double zeta) {
|
||||
double a = alpha1 + alpha2 + zeta;
|
||||
|
||||
if (n % 2 == 0) { // even n
|
||||
int k = L + n / 2;
|
||||
return libgrpp_double_factorial(2 * k - 1) / (pow(2.0, k + 1) * pow(a, k)) *
|
||||
sqrt(M_PI / a);
|
||||
} else { // odd n
|
||||
int k = L + (n - 1) / 2;
|
||||
return libgrpp_factorial(k) / (2.0 * pow(a, k + 1));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* calculate normalization factor for the radial Gaussian-type orbital:
|
||||
* G(r) = N * r^L * exp(-alpha * r^2)
|
||||
*/
|
||||
static double radial_gto_norm_factor(int L, double alpha) {
|
||||
// pre-tabulated factors for calculation of normalization constants
|
||||
// (for each value of L)
|
||||
static const double factors[] = {
|
||||
2.5264751109842587, 2.9173221708553032, 2.6093322745198853,
|
||||
1.9724697960897537, 1.3149798640598356, 7.9296269381073192e-1,
|
||||
4.3985656185609934e-1, 2.2714095183849672e-1, 1.1017954545099481e-1,
|
||||
5.0553842554329785e-2, 2.2063505731056757e-2, 9.2011179391124215e-3,
|
||||
3.6804471756449694e-3, 1.4166047783978804e-3, 5.2611380677564405e-4,
|
||||
1.8898565833279173e-4, 6.5796360823633550e-5, 2.2243229718298637e-5,
|
||||
7.3135288801774484e-6, 2.3422037547660024e-6};
|
||||
|
||||
return factors[L] * pow(alpha, 0.75 + L / 2.0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms matrix from the basis of unitary sphere polynomials
|
||||
* to the basis of real spherical harmonics S_lm
|
||||
* (separately for 'bra' and 'ket' vectors)
|
||||
*/
|
||||
static void transform_to_sph_basis_ket(int dim_bra, int dim_ket_cart,
|
||||
int dim_ket_sph, double *A_in,
|
||||
double *A_out, double *S_lm_coef) {
|
||||
for (int i = 0; i < dim_bra; i++) {
|
||||
for (int j = 0; j < dim_ket_sph; j++) {
|
||||
double s = 0.0;
|
||||
|
||||
for (int icart = 0; icart < dim_ket_cart; icart++) {
|
||||
double u_nljm = S_lm_coef[dim_ket_cart * j + icart];
|
||||
s += u_nljm * A_in[i * dim_ket_cart + icart];
|
||||
}
|
||||
|
||||
A_out[i * dim_ket_sph + j] = s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void transform_to_sph_basis_bra(int dim_bra_cart, int dim_bra_sph,
|
||||
int dim_ket, double *A_in, double *A_out,
|
||||
double *S_lm_coef) {
|
||||
for (int j = 0; j < dim_ket; j++) {
|
||||
for (int i = 0; i < dim_bra_sph; i++) {
|
||||
|
||||
double s = 0.0;
|
||||
|
||||
for (int icart = 0; icart < dim_bra_cart; icart++) {
|
||||
double u_nljm = S_lm_coef[dim_bra_cart * i + icart];
|
||||
s += u_nljm * A_in[icart * dim_ket + j];
|
||||
}
|
||||
|
||||
A_out[i * dim_ket + j] = s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static double ang_norm_factor(int lx, int ly, int lz) {
|
||||
int L = lx + ly + lz;
|
||||
|
||||
return 1.0 / (2.0 * sqrt(M_PI)) *
|
||||
sqrt(libgrpp_double_factorial(2 * L + 1)
|
||||
/*(double_factorial(2 * lx - 1) * double_factorial(2 * ly - 1) *
|
||||
double_factorial(2 * lz - 1))*/
|
||||
);
|
||||
}
|
||||
145
src/grpp/grpp_overlap.c
Normal file
145
src/grpp/grpp_overlap.c
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
/*----------------------------------------------------------------------------*/
|
||||
/* CP2K: A general program to perform molecular dynamics simulations */
|
||||
/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
|
||||
/* */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* libgrpp - a library for the evaluation of integrals over
|
||||
* generalized relativistic pseudopotentials.
|
||||
*
|
||||
* Copyright (C) 2021-2023 Alexander Oleynichenko
|
||||
*/
|
||||
|
||||
/**
|
||||
* Calculation of overlap integrals.
|
||||
*
|
||||
* The recursive Obara-Saika scheme is used to calculate 1- and 2-center overlap
|
||||
* integrals. For details, see: T. Helgaker, P. Jorgensen, J. Olsen, Molecular
|
||||
* Electronic-Structure Theory, John Wiley & Sons Ltd, 2000. Chapter 9.3.1,
|
||||
* "Overlap integrals"
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
#include "grpp_norm_gaussian.h"
|
||||
#include "grpp_overlap.h"
|
||||
#include "libgrpp.h"
|
||||
|
||||
#include "grpp_utils.h"
|
||||
|
||||
static void overlap_integrals_shell_pair_obara_saika(libgrpp_shell_t *shell_A,
|
||||
libgrpp_shell_t *shell_B,
|
||||
double alpha_A,
|
||||
double alpha_B,
|
||||
double *overlap_matrix);
|
||||
|
||||
/**
|
||||
* Calculates overlap integral between two shells represented by contracted
|
||||
* Gaussian functions.
|
||||
*/
|
||||
void libgrpp_overlap_integrals(libgrpp_shell_t *shell_A,
|
||||
libgrpp_shell_t *shell_B,
|
||||
double *overlap_matrix) {
|
||||
int size_A = libgrpp_get_shell_size(shell_A);
|
||||
int size_B = libgrpp_get_shell_size(shell_B);
|
||||
|
||||
double *buf = calloc(size_A * size_B, sizeof(double));
|
||||
|
||||
memset(overlap_matrix, 0, size_A * size_B * sizeof(double));
|
||||
|
||||
// loop over primitives in contractions
|
||||
for (int i = 0; i < shell_A->num_primitives; i++) {
|
||||
for (int j = 0; j < shell_B->num_primitives; j++) {
|
||||
double alpha_i = shell_A->alpha[i];
|
||||
double alpha_j = shell_B->alpha[j];
|
||||
double coef_A_i = shell_A->coeffs[i];
|
||||
double coef_B_j = shell_B->coeffs[j];
|
||||
|
||||
overlap_integrals_shell_pair_obara_saika(shell_A, shell_B, alpha_i,
|
||||
alpha_j, buf);
|
||||
|
||||
libgrpp_daxpy(size_A * size_B, coef_A_i * coef_B_j, buf, overlap_matrix);
|
||||
}
|
||||
}
|
||||
|
||||
free(buf);
|
||||
}
|
||||
|
||||
static void overlap_integrals_shell_pair_obara_saika(libgrpp_shell_t *shell_A,
|
||||
libgrpp_shell_t *shell_B,
|
||||
double alpha_A,
|
||||
double alpha_B,
|
||||
double *overlap_matrix) {
|
||||
int size_A = libgrpp_get_shell_size(shell_A);
|
||||
int size_B = libgrpp_get_shell_size(shell_B);
|
||||
int L_A = shell_A->L;
|
||||
int L_B = shell_B->L;
|
||||
double N_A = libgrpp_gaussian_norm_factor(L_A, 0, 0, alpha_A);
|
||||
double N_B = libgrpp_gaussian_norm_factor(L_B, 0, 0, alpha_B);
|
||||
|
||||
double p = alpha_A + alpha_B;
|
||||
double mu = alpha_A * alpha_B / (alpha_A + alpha_B);
|
||||
double *A = shell_A->origin;
|
||||
double *B = shell_B->origin;
|
||||
|
||||
double S[3][LIBGRPP_MAX_BASIS_L][LIBGRPP_MAX_BASIS_L];
|
||||
|
||||
for (int coord = 0; coord < 3; coord++) {
|
||||
double P = (alpha_A * A[coord] + alpha_B * B[coord]) / p;
|
||||
|
||||
double X_AB = A[coord] - B[coord];
|
||||
double X_PA = P - A[coord];
|
||||
double X_PB = P - B[coord];
|
||||
double pfac = 1.0 / (2.0 * p);
|
||||
|
||||
for (int i = 0; i <= L_A; i++) {
|
||||
for (int j = 0; j <= L_B; j++) {
|
||||
double S_ij = 0.0;
|
||||
|
||||
if (i + j == 0) {
|
||||
S[coord][0][0] = sqrt(M_PI / p) * exp(-mu * X_AB * X_AB);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i == 0) { // upward by j
|
||||
S_ij += X_PB * S[coord][i][j - 1];
|
||||
if (j - 1 > 0) {
|
||||
S_ij += (j - 1) * pfac * S[coord][i][j - 2];
|
||||
}
|
||||
} else { // upward by i
|
||||
S_ij += X_PA * S[coord][i - 1][j];
|
||||
if (i - 1 > 0) {
|
||||
S_ij += (i - 1) * pfac * S[coord][i - 2][j];
|
||||
}
|
||||
if (j > 0) {
|
||||
S_ij += j * pfac * S[coord][i - 1][j - 1];
|
||||
}
|
||||
}
|
||||
|
||||
S[coord][i][j] = S_ij;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// loop over cartesian functions inside the shells
|
||||
for (int m = 0; m < size_A; m++) {
|
||||
for (int n = 0; n < size_B; n++) {
|
||||
int n_A = shell_A->cart_list[3 * m + 0];
|
||||
int l_A = shell_A->cart_list[3 * m + 1];
|
||||
int m_A = shell_A->cart_list[3 * m + 2];
|
||||
int n_B = shell_B->cart_list[3 * n + 0];
|
||||
int l_B = shell_B->cart_list[3 * n + 1];
|
||||
int m_B = shell_B->cart_list[3 * n + 2];
|
||||
|
||||
overlap_matrix[m * size_B + n] =
|
||||
N_A * N_B * S[0][n_A][n_B] * S[1][l_A][l_B] * S[2][m_A][m_B];
|
||||
}
|
||||
}
|
||||
}
|
||||
23
src/grpp/grpp_overlap.h
Normal file
23
src/grpp/grpp_overlap.h
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
/*----------------------------------------------------------------------------*/
|
||||
/* CP2K: A general program to perform molecular dynamics simulations */
|
||||
/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
|
||||
/* */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* libgrpp - a library for the evaluation of integrals over
|
||||
* generalized relativistic pseudopotentials.
|
||||
*
|
||||
* Copyright (C) 2021-2023 Alexander Oleynichenko
|
||||
*/
|
||||
|
||||
#ifndef LIBGRPP_OVERLAP_H
|
||||
#define LIBGRPP_OVERLAP_H
|
||||
|
||||
#include "libgrpp_types.h"
|
||||
void libgrpp_overlap_integrals(libgrpp_shell_t *shell_A,
|
||||
libgrpp_shell_t *shell_B,
|
||||
double *overlap_matrix);
|
||||
|
||||
#endif // LIBGRPP_OVERLAP_H
|
||||
225
src/grpp/grpp_overlap_gradient.c
Normal file
225
src/grpp/grpp_overlap_gradient.c
Normal file
|
|
@ -0,0 +1,225 @@
|
|||
/*----------------------------------------------------------------------------*/
|
||||
/* CP2K: A general program to perform molecular dynamics simulations */
|
||||
/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
|
||||
/* */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* libgrpp - a library for the evaluation of integrals over
|
||||
* generalized relativistic pseudopotentials.
|
||||
*
|
||||
* Copyright (C) 2021-2023 Alexander Oleynichenko
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "grpp_overlap_gradient.h"
|
||||
#include "libgrpp.h"
|
||||
|
||||
#include "grpp_diff_gaussian.h"
|
||||
#include "grpp_utils.h"
|
||||
|
||||
static void overlap_gradient_diff_bra_contribution(libgrpp_shell_t *shell_A,
|
||||
libgrpp_shell_t *shell_B,
|
||||
double **grad,
|
||||
double factor);
|
||||
|
||||
static void overlap_gradient_diff_bra_overlap_integrals(
|
||||
libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B, double **overlap_down,
|
||||
double **overlap_up, int *cart_size_down, int *cart_size_up);
|
||||
|
||||
int nlm_to_linear(int *nlm);
|
||||
|
||||
/**
|
||||
* Analytic calculation of gradients of overlap integrals for a given shell pair
|
||||
* with respect to the point 'point_3d'.
|
||||
*/
|
||||
void libgrpp_overlap_integrals_gradient(libgrpp_shell_t *shell_A,
|
||||
libgrpp_shell_t *shell_B,
|
||||
double *point_3d, double **grad) {
|
||||
int cart_size_A = libgrpp_get_shell_size(shell_A);
|
||||
int cart_size_B = libgrpp_get_shell_size(shell_B);
|
||||
int buf_size = cart_size_A * cart_size_B;
|
||||
|
||||
/*
|
||||
* initializations: set gradients to zero
|
||||
*/
|
||||
for (int icoord = 0; icoord < 3; icoord++) {
|
||||
memset(grad[icoord], 0, sizeof(double) * buf_size);
|
||||
}
|
||||
|
||||
/*
|
||||
* integrals are zero:
|
||||
* (1) for 1-center integrals <A|A> (due to the translational invariance)
|
||||
* (2) d<A|B> / dC = 0 (integral is constant for the given 'point_3d')
|
||||
*/
|
||||
if (points_are_equal(shell_A->origin, shell_B->origin)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* construct gradients:
|
||||
* d<A|B>/dA = + < df/dA | B >
|
||||
* d<A|B>/dB = - < df/dA | B >
|
||||
*
|
||||
* note that due to the property of translational invariance,
|
||||
* d<A|B>/dB = - d<A|B>/dA
|
||||
*/
|
||||
if (points_are_equal(shell_A->origin, point_3d)) {
|
||||
overlap_gradient_diff_bra_contribution(shell_A, shell_B, grad, +1.0);
|
||||
}
|
||||
if (points_are_equal(shell_B->origin, point_3d)) {
|
||||
overlap_gradient_diff_bra_contribution(shell_A, shell_B, grad, -1.0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates contribution to gradients arising from the < df/dA | g > term:
|
||||
*
|
||||
* grad += factor * < df/dA | g >
|
||||
*
|
||||
* (bra basis function is differentiated).
|
||||
*/
|
||||
static void overlap_gradient_diff_bra_contribution(libgrpp_shell_t *shell_A,
|
||||
libgrpp_shell_t *shell_B,
|
||||
double **grad,
|
||||
double factor) {
|
||||
/*
|
||||
* calculate overlap integrals < df/dA | B >
|
||||
*/
|
||||
double *overlap_down = NULL;
|
||||
double *overlap_up = NULL;
|
||||
int cart_size_down = 0;
|
||||
int cart_size_up = 0;
|
||||
|
||||
overlap_gradient_diff_bra_overlap_integrals(shell_A, shell_B, &overlap_down,
|
||||
&overlap_up, &cart_size_down,
|
||||
&cart_size_up);
|
||||
|
||||
/*
|
||||
* construct contributions to gradients:
|
||||
* d<A|B>/dA += < df/dA | B >
|
||||
*/
|
||||
for (int icoord = 0; icoord < 3; icoord++) {
|
||||
for (int i = 0; i < shell_A->cart_size; i++) {
|
||||
for (int j = 0; j < shell_B->cart_size; j++) {
|
||||
|
||||
int *bra_nlm = shell_A->cart_list + 3 * i;
|
||||
int *ket_nlm = shell_B->cart_list + 3 * j;
|
||||
int index = i * shell_B->cart_size + j;
|
||||
|
||||
/*
|
||||
* contribution from the L-1 gaussian
|
||||
*/
|
||||
if (shell_A->L > 0) {
|
||||
bra_nlm[icoord] -= 1;
|
||||
int bra_index = libgrpp_nlm_to_linear(bra_nlm);
|
||||
int ket_index = libgrpp_nlm_to_linear(ket_nlm);
|
||||
bra_nlm[icoord] += 1;
|
||||
|
||||
grad[icoord][index] -=
|
||||
factor * bra_nlm[icoord] *
|
||||
overlap_down[shell_B->cart_size * bra_index + ket_index];
|
||||
}
|
||||
|
||||
/*
|
||||
* contribution from the L+1 gaussian
|
||||
*/
|
||||
bra_nlm[icoord] += 1;
|
||||
int bra_index = libgrpp_nlm_to_linear(bra_nlm);
|
||||
int ket_index = libgrpp_nlm_to_linear(ket_nlm);
|
||||
bra_nlm[icoord] -= 1;
|
||||
|
||||
grad[icoord][index] +=
|
||||
factor * overlap_up[shell_B->cart_size * bra_index + ket_index];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (overlap_down) {
|
||||
free(overlap_down);
|
||||
}
|
||||
free(overlap_up);
|
||||
}
|
||||
|
||||
/**
|
||||
* To assemble the contribution < df/dA | g > to gradients, one have to
|
||||
* differentiate Gaussian function. Such a differentiation yields two Gaussians
|
||||
* with angular momenta L-1 ("down") and L+1 ("up"): dG/dA -> G(L-1) and G(L+1)
|
||||
*
|
||||
* This function constructs overlap matrices with these "downgraded" and
|
||||
* "upgraded" Gaussian functions: < G(L-1) | G' > and < G(L+1) | G' >
|
||||
*
|
||||
*/
|
||||
static void overlap_gradient_diff_bra_overlap_integrals(
|
||||
libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B, double **overlap_down,
|
||||
double **overlap_up, int *cart_size_down, int *cart_size_up) {
|
||||
/*
|
||||
* differentiation of contracted Gaussian functions
|
||||
*/
|
||||
libgrpp_shell_t *shell_A_down = NULL;
|
||||
libgrpp_shell_t *shell_A_up = NULL;
|
||||
libgrpp_differentiate_shell(shell_A, &shell_A_down, &shell_A_up);
|
||||
|
||||
*cart_size_down = 0;
|
||||
if (shell_A_down != NULL) {
|
||||
*cart_size_down = shell_A_down->cart_size;
|
||||
}
|
||||
*cart_size_up = shell_A_up->cart_size;
|
||||
|
||||
/*
|
||||
* overlap matrix:
|
||||
* < L-1 | L>
|
||||
*/
|
||||
if (shell_A_down != NULL) {
|
||||
*overlap_down = (double *)calloc(
|
||||
shell_A_down->cart_size * shell_B->cart_size, sizeof(double));
|
||||
libgrpp_overlap_integrals(shell_A_down, shell_B, *overlap_down);
|
||||
} else {
|
||||
*overlap_down = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* overlap matrix:
|
||||
* < L+1 | L>
|
||||
*/
|
||||
*overlap_up = (double *)calloc(shell_A_up->cart_size * shell_B->cart_size,
|
||||
sizeof(double));
|
||||
libgrpp_overlap_integrals(shell_A_up, shell_B, *overlap_up);
|
||||
|
||||
/*
|
||||
* clean up
|
||||
*/
|
||||
if (shell_A_down) {
|
||||
libgrpp_delete_shell(shell_A_down);
|
||||
}
|
||||
libgrpp_delete_shell(shell_A_up);
|
||||
}
|
||||
|
||||
/**
|
||||
* calculates sequential ("linear") index of the (n,l,m) primitive in the
|
||||
* cartesian shell
|
||||
*/
|
||||
int libgrpp_nlm_to_linear(int *nlm) {
|
||||
int n = nlm[0];
|
||||
int l = nlm[1];
|
||||
int m = nlm[2];
|
||||
|
||||
int L = n + l + m;
|
||||
int cart_size = (L + 1) * (L + 2) / 2;
|
||||
int *cart_list = libgrpp_generate_shell_cartesians(L);
|
||||
|
||||
int index = 0;
|
||||
for (index = 0; index < cart_size; index++) {
|
||||
if (cart_list[3 * index + 0] == n && cart_list[3 * index + 1] == l &&
|
||||
cart_list[3 * index + 2] == m) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(cart_list);
|
||||
|
||||
return index;
|
||||
}
|
||||
25
src/grpp/grpp_overlap_gradient.h
Normal file
25
src/grpp/grpp_overlap_gradient.h
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
/*----------------------------------------------------------------------------*/
|
||||
/* CP2K: A general program to perform molecular dynamics simulations */
|
||||
/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
|
||||
/* */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* libgrpp - a library for the evaluation of integrals over
|
||||
* generalized relativistic pseudopotentials.
|
||||
*
|
||||
* Copyright (C) 2021-2023 Alexander Oleynichenko
|
||||
*/
|
||||
|
||||
#ifndef LIBGRPP_OVERLAP_GRADIENT_H
|
||||
#define LIBGRPP_OVERLAP_GRADIENT_H
|
||||
|
||||
#include "libgrpp_types.h"
|
||||
|
||||
extern void libgrpp_overlap_integrals_gradient(libgrpp_shell_t *shell_A,
|
||||
libgrpp_shell_t *shell_B,
|
||||
double *point_3d, double **grad);
|
||||
extern int libgrpp_nlm_to_linear(int *nlm);
|
||||
|
||||
#endif // LIBGRPP_OVERLAP_GRADIENT_H
|
||||
115
src/grpp/grpp_parameters.c
Normal file
115
src/grpp/grpp_parameters.c
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
/*----------------------------------------------------------------------------*/
|
||||
/* CP2K: A general program to perform molecular dynamics simulations */
|
||||
/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
|
||||
/* */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* libgrpp - a library for the evaluation of integrals over
|
||||
* generalized relativistic pseudopotentials.
|
||||
*
|
||||
* Copyright (C) 2021-2023 Alexander Oleynichenko
|
||||
*/
|
||||
#include <assert.h>
|
||||
|
||||
#include "grpp_parameters.h"
|
||||
|
||||
static int cartesian_generator_dirac(int L, int *cart_list);
|
||||
|
||||
static int cartesian_generator_turbomole(int L, int *cart_list);
|
||||
|
||||
libgrpp_parameters_t libgrpp_params = {
|
||||
// tolerance of radial integration
|
||||
1e-16,
|
||||
// tolerance of angular integral screening
|
||||
1e-16,
|
||||
// tolerance of modified Bessel functions evaluation
|
||||
// is it really needed?
|
||||
1e-16,
|
||||
// subroutine to generate cartesian components with given ang momentum L
|
||||
cartesian_generator_dirac};
|
||||
|
||||
void libgrpp_set_default_parameters() {
|
||||
// #pragma omp critical
|
||||
{
|
||||
libgrpp_set_radial_tolerance(1e-16);
|
||||
libgrpp_set_angular_screening_tolerance(1e-16);
|
||||
libgrpp_set_modified_bessel_tolerance(1e-16);
|
||||
libgrpp_set_cartesian_generator(cartesian_generator_dirac);
|
||||
}
|
||||
}
|
||||
|
||||
void libgrpp_set_radial_tolerance(double tolerance) {
|
||||
// #pragma omp critical
|
||||
{ libgrpp_params.radial_tolerance = tolerance; }
|
||||
}
|
||||
|
||||
void libgrpp_set_angular_screening_tolerance(double tolerance) {
|
||||
// #pragma omp critical
|
||||
{ libgrpp_params.angular_screening_tolerance = tolerance; }
|
||||
}
|
||||
|
||||
void libgrpp_set_modified_bessel_tolerance(double tolerance) {
|
||||
// #pragma omp critical
|
||||
{ libgrpp_params.modified_bessel_tolerance = tolerance; }
|
||||
}
|
||||
|
||||
void libgrpp_set_cartesian_order(int order) {
|
||||
// #pragma omp critical
|
||||
{
|
||||
assert(order == LIBGRPP_CART_ORDER_DIRAC ||
|
||||
order == LIBGRPP_CART_ORDER_TURBOMOLE);
|
||||
|
||||
if (order == LIBGRPP_CART_ORDER_DIRAC) {
|
||||
libgrpp_set_cartesian_generator(cartesian_generator_dirac);
|
||||
} else if (order == LIBGRPP_CART_ORDER_TURBOMOLE) {
|
||||
libgrpp_set_cartesian_generator(cartesian_generator_turbomole);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void libgrpp_set_cartesian_generator(
|
||||
int (*cartesian_generator)(int L, int *cart_list)) {
|
||||
// #pragma omp critical
|
||||
{ libgrpp_params.cartesian_generator = cartesian_generator; }
|
||||
}
|
||||
|
||||
static int cartesian_generator_dirac(int L, int *cart_list) {
|
||||
int count = 0;
|
||||
int n_cart = (L + 1) * (L + 2) / 2;
|
||||
|
||||
for (int r = L; r >= 0; r--) {
|
||||
for (int s = L; s >= 0; s--) {
|
||||
for (int t = L; t >= 0; t--) {
|
||||
if (r + s + t == L) {
|
||||
cart_list[3 * count + 0] = r;
|
||||
cart_list[3 * count + 1] = s;
|
||||
cart_list[3 * count + 2] = t;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return n_cart;
|
||||
}
|
||||
|
||||
static int cartesian_generator_turbomole(int L, int *cart_list) {
|
||||
int count = 0;
|
||||
int n_cart = (L + 1) * (L + 2) / 2;
|
||||
|
||||
for (int r = L; r >= 0; r--) {
|
||||
for (int s = L - r; s >= 0; s--) {
|
||||
int t = L - r - s;
|
||||
|
||||
cart_list[3 * count + 0] = r;
|
||||
cart_list[3 * count + 1] = s;
|
||||
cart_list[3 * count + 2] = t;
|
||||
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return n_cart;
|
||||
}
|
||||
42
src/grpp/grpp_parameters.h
Normal file
42
src/grpp/grpp_parameters.h
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/*----------------------------------------------------------------------------*/
|
||||
/* CP2K: A general program to perform molecular dynamics simulations */
|
||||
/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
|
||||
/* */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* libgrpp - a library for the evaluation of integrals over
|
||||
* generalized relativistic pseudopotentials.
|
||||
*
|
||||
* Copyright (C) 2021-2023 Alexander Oleynichenko
|
||||
*/
|
||||
|
||||
#ifndef LIBGRPP_PARAMETERS_H
|
||||
#define LIBGRPP_PARAMETERS_H
|
||||
|
||||
enum { LIBGRPP_CART_ORDER_DIRAC, LIBGRPP_CART_ORDER_TURBOMOLE };
|
||||
|
||||
typedef struct {
|
||||
double radial_tolerance;
|
||||
double angular_screening_tolerance;
|
||||
double modified_bessel_tolerance;
|
||||
int (*cartesian_generator)(int L, int *cart_list);
|
||||
} libgrpp_parameters_t;
|
||||
|
||||
extern libgrpp_parameters_t libgrpp_params;
|
||||
|
||||
void libgrpp_set_default_parameters();
|
||||
|
||||
void libgrpp_set_radial_tolerance(double tolerance);
|
||||
|
||||
void libgrpp_set_angular_screening_tolerance(double tolerance);
|
||||
|
||||
void libgrpp_set_modified_bessel_tolerance(double tolerance);
|
||||
|
||||
void libgrpp_set_cartesian_order(int order);
|
||||
|
||||
void libgrpp_set_cartesian_generator(
|
||||
int (*cartesian_generator)(int L, int *cart_list));
|
||||
|
||||
#endif // LIBGRPP_PARAMETERS_H
|
||||
122
src/grpp/grpp_potential.c
Normal file
122
src/grpp/grpp_potential.c
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
/*----------------------------------------------------------------------------*/
|
||||
/* CP2K: A general program to perform molecular dynamics simulations */
|
||||
/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
|
||||
/* */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* libgrpp - a library for the evaluation of integrals over
|
||||
* generalized relativistic pseudopotentials.
|
||||
*
|
||||
* Copyright (C) 2021-2023 Alexander Oleynichenko
|
||||
*/
|
||||
|
||||
/*
|
||||
* representation of (generalized) effective core potentials
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.1415926535897932384626433
|
||||
#endif
|
||||
|
||||
#include "libgrpp.h"
|
||||
|
||||
/**
|
||||
* constructor for the pseudopotential
|
||||
*/
|
||||
libgrpp_potential_t *libgrpp_new_potential(int L, int J, int num_primitives,
|
||||
int *powers, double *coeffs,
|
||||
double *alpha) {
|
||||
libgrpp_potential_t *pot =
|
||||
(libgrpp_potential_t *)calloc(1, sizeof(libgrpp_potential_t));
|
||||
|
||||
pot->L = L;
|
||||
pot->J = J;
|
||||
pot->powers = (int *)calloc(num_primitives, sizeof(int));
|
||||
pot->coeffs = (double *)calloc(num_primitives, sizeof(double));
|
||||
pot->alpha = (double *)calloc(num_primitives, sizeof(double));
|
||||
|
||||
pot->num_primitives = 0;
|
||||
for (int i = 0; i < num_primitives; i++) {
|
||||
if (fabs(coeffs[i]) < LIBGRPP_ZERO_THRESH) {
|
||||
continue;
|
||||
}
|
||||
|
||||
pot->coeffs[pot->num_primitives] = coeffs[i];
|
||||
pot->powers[pot->num_primitives] = powers[i];
|
||||
pot->alpha[pot->num_primitives] = alpha[i];
|
||||
|
||||
pot->num_primitives++;
|
||||
}
|
||||
|
||||
return pot;
|
||||
}
|
||||
|
||||
/*
|
||||
* destructor for the pseudopotential
|
||||
*/
|
||||
void libgrpp_delete_potential(libgrpp_potential_t *potential) {
|
||||
if (potential == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
free(potential->powers);
|
||||
free(potential->coeffs);
|
||||
free(potential->alpha);
|
||||
free(potential);
|
||||
}
|
||||
|
||||
/*
|
||||
* calculates value of the pseudopotential at the point 'r'
|
||||
*
|
||||
* TODO: remove the invocation of 'pow()'
|
||||
*/
|
||||
double libgrpp_potential_value(libgrpp_potential_t *potential, double r) {
|
||||
double val = 0.0;
|
||||
double r_2 = r * r;
|
||||
|
||||
for (int i = 0; i < potential->num_primitives; i++) {
|
||||
int n = potential->powers[i];
|
||||
val +=
|
||||
potential->coeffs[i] * pow(r, n - 2) * exp(-potential->alpha[i] * r_2);
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
/*
|
||||
* removes redundant (zero) primitives from the RPP.
|
||||
* argument remains constant.
|
||||
*/
|
||||
libgrpp_potential_t *
|
||||
libgrpp_shrink_potential(libgrpp_potential_t *src_potential) {
|
||||
int n = src_potential->num_primitives;
|
||||
int *new_powers = calloc(n, sizeof(int));
|
||||
double *new_coeffs = calloc(n, sizeof(double));
|
||||
double *new_alpha = calloc(n, sizeof(double));
|
||||
|
||||
int n_nonzero_primitives = 0;
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (fabs(src_potential->coeffs[i]) > LIBGRPP_ZERO_THRESH) {
|
||||
new_powers[n_nonzero_primitives] = src_potential->powers[i];
|
||||
new_coeffs[n_nonzero_primitives] = src_potential->coeffs[i];
|
||||
new_alpha[n_nonzero_primitives] = src_potential->alpha[i];
|
||||
n_nonzero_primitives++;
|
||||
}
|
||||
}
|
||||
|
||||
libgrpp_potential_t *new_pot = libgrpp_new_potential(
|
||||
src_potential->L, src_potential->J, n_nonzero_primitives, new_powers,
|
||||
new_coeffs, new_alpha);
|
||||
|
||||
free(new_powers);
|
||||
free(new_coeffs);
|
||||
free(new_alpha);
|
||||
|
||||
return new_pot;
|
||||
}
|
||||
330
src/grpp/grpp_radial_type1_integral.c
Normal file
330
src/grpp/grpp_radial_type1_integral.c
Normal file
|
|
@ -0,0 +1,330 @@
|
|||
/*----------------------------------------------------------------------------*/
|
||||
/* CP2K: A general program to perform molecular dynamics simulations */
|
||||
/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
|
||||
/* */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* libgrpp - a library for the evaluation of integrals over
|
||||
* generalized relativistic pseudopotentials.
|
||||
*
|
||||
* Copyright (C) 2021-2023 Alexander Oleynichenko
|
||||
*/
|
||||
|
||||
/*
|
||||
* Evaluation of type 1 radial integrals.
|
||||
*
|
||||
* The procedure in general follows that described in:
|
||||
* R. Flores-Moreno et al. Half-numerical evaluation of pseudopotential
|
||||
integrals.
|
||||
* J. Comp. Chem. 27, 1009 (2006)
|
||||
* (see formulas (12) and (13) for radial integrals invoking contracted Gaussian
|
||||
functions and RPPs).
|
||||
|
||||
* In contrast to type 2 integrals, the special case of type 1 integrals Bessel
|
||||
functions
|
||||
* cannot be factorized, and one cannot use contracted Gaussians directly
|
||||
* (and we have to use primitive Gaussians instead).
|
||||
* However, the RPP radial function still can be used as a whole in the
|
||||
integrand.
|
||||
*
|
||||
* The Log3 integration scheme used here is detailed in:
|
||||
* C.-K. Skylaris et al. An efficient method for calculating effective core
|
||||
potential integrals
|
||||
* which involve projection operators.
|
||||
* Chem. Phys. Lett. 296, 445 (1998)
|
||||
*/
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
#include "grpp_radial_type1_integral.h"
|
||||
#include "libgrpp.h"
|
||||
|
||||
#include "grpp_specfunc.h"
|
||||
#include "grpp_utils.h"
|
||||
|
||||
#define MIN_GRID 2047
|
||||
#define MAX_GRID 10000
|
||||
|
||||
typedef struct {
|
||||
double k;
|
||||
double alpha_A;
|
||||
double alpha_B;
|
||||
double CA_2;
|
||||
double CB_2;
|
||||
double prefactor;
|
||||
double (*potential)(double r, void *params);
|
||||
void *potential_params;
|
||||
} radial_type1_params_t;
|
||||
|
||||
typedef struct {
|
||||
int nr;
|
||||
int n_max;
|
||||
int lambda_max;
|
||||
double *r;
|
||||
double *w;
|
||||
double *pot_values;
|
||||
double *gto_values;
|
||||
double **r_N;
|
||||
double **mod_bessel;
|
||||
radial_type1_params_t *params;
|
||||
} radial_type1_grid_t;
|
||||
|
||||
static radial_type1_grid_t *
|
||||
create_radial_type1_grid(int lambda_max, int n_max,
|
||||
radial_type1_params_t *params);
|
||||
|
||||
static void expand_radial_type1_grid(radial_type1_grid_t *grid, int nr);
|
||||
|
||||
static void delete_radial_type1_grid(radial_type1_grid_t *grid);
|
||||
|
||||
static double calculate_radial_type1_integral(radial_type1_grid_t *grid, int n,
|
||||
int lambda, double tolerance,
|
||||
int *converged);
|
||||
|
||||
radial_type1_table_t *libgrpp_tabulate_radial_type1_integrals(
|
||||
int lambda_max, int n_max, double CA_2, double CB_2, double alpha_A,
|
||||
double alpha_B, double k, double prefactor,
|
||||
double (*potential)(double r, void *params), void *potential_params) {
|
||||
radial_type1_table_t *table;
|
||||
double const tolerance = libgrpp_params.radial_tolerance;
|
||||
|
||||
table = (radial_type1_table_t *)calloc(1, sizeof(radial_type1_table_t));
|
||||
table->lambda_max = lambda_max;
|
||||
table->n_max = n_max;
|
||||
table->radial_integrals =
|
||||
(double *)calloc((lambda_max + 1) * (n_max + 1), sizeof(double));
|
||||
|
||||
radial_type1_params_t params;
|
||||
params.CA_2 = CA_2;
|
||||
params.CB_2 = CB_2;
|
||||
params.alpha_A = alpha_A;
|
||||
params.alpha_B = alpha_B;
|
||||
params.k = k;
|
||||
params.prefactor = prefactor;
|
||||
params.potential = potential;
|
||||
params.potential_params = potential_params;
|
||||
|
||||
radial_type1_grid_t *grid =
|
||||
create_radial_type1_grid(lambda_max, n_max, ¶ms);
|
||||
|
||||
for (int lambda = 0; lambda <= lambda_max; lambda++) {
|
||||
for (int n = 0; n <= n_max; n++) {
|
||||
|
||||
int converged;
|
||||
double Q = calculate_radial_type1_integral(grid, n, lambda, tolerance,
|
||||
&converged);
|
||||
|
||||
table->radial_integrals[lambda * (lambda_max + 1) + n] = Q;
|
||||
}
|
||||
}
|
||||
|
||||
delete_radial_type1_grid(grid);
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
void libgrpp_delete_radial_type1_integrals(radial_type1_table_t *table) {
|
||||
free(table->radial_integrals);
|
||||
free(table);
|
||||
}
|
||||
|
||||
double libgrpp_get_radial_type1_integral(radial_type1_table_t *table,
|
||||
int lambda, int n) {
|
||||
int lambda_max = table->lambda_max;
|
||||
return table->radial_integrals[lambda * (lambda_max + 1) + n];
|
||||
}
|
||||
|
||||
static double radial_type1_integrand_fun(double r,
|
||||
radial_type1_params_t *params) {
|
||||
double alpha_A = params->alpha_A;
|
||||
double alpha_B = params->alpha_B;
|
||||
double k = params->k;
|
||||
double CA_2 = params->CA_2;
|
||||
double CB_2 = params->CB_2;
|
||||
double prefactor = params->prefactor;
|
||||
|
||||
double power = k * r - (alpha_A + alpha_B) * r * r - alpha_A * CA_2 -
|
||||
alpha_B * CB_2; // + N * log(r);
|
||||
|
||||
return prefactor * exp(power);
|
||||
}
|
||||
|
||||
static radial_type1_grid_t *
|
||||
create_radial_type1_grid(int lambda_max, int n_max,
|
||||
radial_type1_params_t *params) {
|
||||
radial_type1_grid_t *grid =
|
||||
(radial_type1_grid_t *)calloc(1, sizeof(radial_type1_grid_t));
|
||||
|
||||
grid->nr = MIN_GRID;
|
||||
grid->n_max = n_max;
|
||||
grid->lambda_max = lambda_max;
|
||||
grid->params = params;
|
||||
|
||||
grid->r = (double *)calloc(MAX_GRID, sizeof(double));
|
||||
grid->w = (double *)calloc(MAX_GRID, sizeof(double));
|
||||
grid->pot_values = (double *)calloc(MAX_GRID, sizeof(double));
|
||||
grid->gto_values = (double *)calloc(MAX_GRID, sizeof(double));
|
||||
grid->r_N = alloc_zeros_2d(n_max + 1, MAX_GRID);
|
||||
grid->mod_bessel = alloc_zeros_2d(lambda_max + 1, MAX_GRID);
|
||||
|
||||
// initial set of pre-calculated points
|
||||
int nr = grid->nr;
|
||||
const double R = 5.0;
|
||||
const double R3 = R * R * R;
|
||||
|
||||
for (int i = 1; i <= nr; i++) {
|
||||
double xi = i / (nr + 1.0);
|
||||
double xi3 = xi * xi * xi;
|
||||
double ln_xi = log(1 - xi3);
|
||||
double wi = 3 * R3 * xi * xi * ln_xi * ln_xi / ((1 - xi3) * (nr + 1.0));
|
||||
double ri = -R * ln_xi;
|
||||
|
||||
grid->r[i - 1] = ri;
|
||||
grid->w[i - 1] = wi;
|
||||
grid->pot_values[i - 1] = params->potential(ri, params->potential_params);
|
||||
grid->gto_values[i - 1] = radial_type1_integrand_fun(ri, params);
|
||||
|
||||
for (int lambda = 0; lambda <= lambda_max; lambda++) {
|
||||
grid->mod_bessel[lambda][i - 1] =
|
||||
libgrpp_modified_bessel_scaled(lambda, ri * params->k);
|
||||
}
|
||||
|
||||
for (int n = 0; n <= n_max; n++) {
|
||||
grid->r_N[n][i - 1] = pow(ri, n);
|
||||
}
|
||||
}
|
||||
|
||||
return grid;
|
||||
}
|
||||
|
||||
static void delete_radial_type1_grid(radial_type1_grid_t *grid) {
|
||||
free(grid->r);
|
||||
free(grid->w);
|
||||
free(grid->pot_values);
|
||||
free(grid->gto_values);
|
||||
free_2d(grid->r_N, grid->n_max + 1);
|
||||
free_2d(grid->mod_bessel, grid->lambda_max + 1);
|
||||
free(grid);
|
||||
}
|
||||
|
||||
static void expand_radial_type1_grid(radial_type1_grid_t *grid, int nr) {
|
||||
const double R = 5.0;
|
||||
const double R3 = R * R * R;
|
||||
|
||||
if (nr > MAX_GRID) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (nr <= grid->nr) { // nothing to do
|
||||
return;
|
||||
}
|
||||
|
||||
int idx = grid->nr;
|
||||
for (int i = 1; i <= nr; i += 2) {
|
||||
double xi = i / (nr + 1.0);
|
||||
double xi3 = xi * xi * xi;
|
||||
double ln_xi = log(1 - xi3);
|
||||
double wi = 3 * R3 * xi * xi * ln_xi * ln_xi / ((1 - xi3) * (nr + 1.0));
|
||||
double ri = -R * ln_xi;
|
||||
|
||||
grid->r[idx] = ri;
|
||||
grid->w[idx] = wi;
|
||||
grid->pot_values[idx] =
|
||||
grid->params->potential(ri, grid->params->potential_params);
|
||||
grid->gto_values[idx] = radial_type1_integrand_fun(ri, grid->params);
|
||||
|
||||
for (int lambda = 0; lambda <= grid->lambda_max; lambda++) {
|
||||
double kr = grid->params->k * ri;
|
||||
double bessel = libgrpp_modified_bessel_scaled(lambda, kr);
|
||||
grid->mod_bessel[lambda][idx] = bessel;
|
||||
}
|
||||
|
||||
for (int n = 0; n <= grid->n_max; n++) {
|
||||
grid->r_N[n][idx] = pow(ri, n);
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
|
||||
grid->nr = nr;
|
||||
}
|
||||
|
||||
static double calculate_radial_type1_integral(radial_type1_grid_t *grid, int n,
|
||||
int lambda, double tolerance,
|
||||
int *converged) {
|
||||
int nr = MIN_GRID;
|
||||
|
||||
*converged = 0;
|
||||
double prev_sum = 0.0;
|
||||
double sum = 0.0;
|
||||
|
||||
double *w = grid->w;
|
||||
// double *r = grid->r;
|
||||
double *pot_values = grid->pot_values;
|
||||
double *gto_values = grid->gto_values;
|
||||
double *r_N = grid->r_N[n];
|
||||
double *mod_bessel = grid->mod_bessel[lambda];
|
||||
|
||||
/*
|
||||
* first step: screening of an integral
|
||||
*/
|
||||
/*double screened = 0.0;
|
||||
int screened_success = screening_radial_type1(
|
||||
lambda,
|
||||
n,
|
||||
grid->params->CA_2,
|
||||
grid->params->CB_2,
|
||||
grid->params->alpha_A,
|
||||
grid->params->alpha_B,
|
||||
grid->params->k,
|
||||
grid->params->prefactor,
|
||||
grid->params->potential_params,
|
||||
&screened
|
||||
);
|
||||
|
||||
if (screened_success == EXIT_SUCCESS && fabs(screened) < tolerance) {
|
||||
*converged = 1;
|
||||
return screened;
|
||||
}*/
|
||||
|
||||
/*
|
||||
* second step: calculation on the smallest possible grid
|
||||
*/
|
||||
for (int i = 0; i < nr; i++) {
|
||||
sum += w[i] * pot_values[i] * gto_values[i] * r_N[i] * mod_bessel[i];
|
||||
}
|
||||
|
||||
/*
|
||||
* third step: adaptive integration, refinement of the result
|
||||
*/
|
||||
do {
|
||||
int idx = nr;
|
||||
nr = 2 * nr + 1;
|
||||
|
||||
if (nr > MAX_GRID) {
|
||||
break;
|
||||
}
|
||||
|
||||
prev_sum = sum;
|
||||
sum = 0.5 * sum;
|
||||
|
||||
expand_radial_type1_grid(grid, nr);
|
||||
|
||||
for (int i = idx; i < nr; i++) {
|
||||
sum += w[i] * pot_values[i] * gto_values[i] * r_N[i] * mod_bessel[i];
|
||||
}
|
||||
|
||||
/*if (screened_success == EXIT_SUCCESS && (fabs(sum) / fabs(screened) <
|
||||
0.001)) { *converged = 0; continue;
|
||||
}*/
|
||||
|
||||
*converged = fabs(sum - prev_sum) <= tolerance;
|
||||
|
||||
} while (!(*converged));
|
||||
|
||||
return sum;
|
||||
}
|
||||
36
src/grpp/grpp_radial_type1_integral.h
Normal file
36
src/grpp/grpp_radial_type1_integral.h
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/*----------------------------------------------------------------------------*/
|
||||
/* CP2K: A general program to perform molecular dynamics simulations */
|
||||
/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
|
||||
/* */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* libgrpp - a library for the evaluation of integrals over
|
||||
* generalized relativistic pseudopotentials.
|
||||
*
|
||||
* Copyright (C) 2021-2023 Alexander Oleynichenko
|
||||
*/
|
||||
|
||||
#ifndef LIBGRPP_RADIAL_TYPE1_INTEGRAL_H
|
||||
#define LIBGRPP_RADIAL_TYPE1_INTEGRAL_H
|
||||
|
||||
#include "libgrpp.h"
|
||||
|
||||
typedef struct {
|
||||
int lambda_max;
|
||||
int n_max;
|
||||
double *radial_integrals;
|
||||
} radial_type1_table_t;
|
||||
|
||||
radial_type1_table_t *libgrpp_tabulate_radial_type1_integrals(
|
||||
int lambda_max, int n_max, double CA_2, double CB_2, double alpha_A,
|
||||
double alpha_B, double k, double prefactor,
|
||||
double (*potential)(double r, void *params), void *potential_params);
|
||||
|
||||
void libgrpp_delete_radial_type1_integrals(radial_type1_table_t *table);
|
||||
|
||||
double libgrpp_get_radial_type1_integral(radial_type1_table_t *table,
|
||||
int lambda, int n);
|
||||
|
||||
#endif // LIBGRPP_RADIAL_TYPE1_INTEGRAL_H
|
||||
470
src/grpp/grpp_radial_type2_integral.c
Normal file
470
src/grpp/grpp_radial_type2_integral.c
Normal file
|
|
@ -0,0 +1,470 @@
|
|||
/*----------------------------------------------------------------------------*/
|
||||
/* CP2K: A general program to perform molecular dynamics simulations */
|
||||
/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
|
||||
/* */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* libgrpp - a library for the evaluation of integrals over
|
||||
* generalized relativistic pseudopotentials.
|
||||
*
|
||||
* Copyright (C) 2021-2023 Alexander Oleynichenko
|
||||
*/
|
||||
|
||||
/*
|
||||
* Evaluation of type 2 radial integrals.
|
||||
*
|
||||
* The procedure in general follows that described in:
|
||||
* R. Flores-Moreno et al. Half-numerical evaluation of pseudopotential
|
||||
* integrals. J. Comp. Chem. 27, 1009 (2006) (see formulas (12) and (13) for
|
||||
* radial integrals invoking contracted Gaussian functions and RPPs)
|
||||
*
|
||||
* The Log3 integration scheme used here is detailed in:
|
||||
* C.-K. Skylaris et al. An efficient method for calculating effective core
|
||||
* potential integrals which involve projection operators. Chem. Phys. Lett.
|
||||
* 296, 445 (1998)
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
#include "grpp_radial_type2_integral.h"
|
||||
|
||||
#include "grpp_norm_gaussian.h"
|
||||
#include "grpp_screening.h"
|
||||
#include "grpp_specfunc.h"
|
||||
#include "grpp_utils.h"
|
||||
|
||||
#define MIN_GRID 31
|
||||
#define MAX_GRID 10000
|
||||
|
||||
typedef struct {
|
||||
double CA;
|
||||
double CB;
|
||||
libgrpp_potential_t *potential;
|
||||
libgrpp_shell_t *bra;
|
||||
libgrpp_shell_t *ket;
|
||||
} radial_type2_params_t;
|
||||
|
||||
/**
|
||||
* RPP and radial contracted Gaussians are pre-calculated on a grid,
|
||||
* and then combined into radial integrals
|
||||
*/
|
||||
typedef struct {
|
||||
int nr;
|
||||
int n_max;
|
||||
int lambda1_max;
|
||||
int lambda2_max;
|
||||
double *r;
|
||||
double *w;
|
||||
double *rpp_values;
|
||||
double **r_N;
|
||||
double **F1;
|
||||
double **F2;
|
||||
radial_type2_params_t *params;
|
||||
} radial_type2_grid_t;
|
||||
|
||||
/**
|
||||
* pre-definitions of the functions used below
|
||||
*/
|
||||
|
||||
static double calculate_radial_type2_integral(radial_type2_grid_t *grid, int n,
|
||||
int lambda1, int lambda2,
|
||||
double tolerance, int *converged);
|
||||
|
||||
static radial_type2_grid_t *
|
||||
create_radial_type2_grid(int lambda1_max, int lambda2_max, int n_max,
|
||||
radial_type2_params_t *params);
|
||||
|
||||
static void delete_radial_type2_grid(radial_type2_grid_t *grid);
|
||||
|
||||
static double radial_type2_integrand_fun_contracted(double r, int lambda,
|
||||
double *k, double CA,
|
||||
libgrpp_shell_t *gauss_fun);
|
||||
|
||||
static void expand_radial_type2_grid(radial_type2_grid_t *grid, int nr);
|
||||
|
||||
static void calc_k_values(int nprim, const double *alpha, double CA, double *k);
|
||||
|
||||
double libgrpp_gaussian_integral(int n, double a);
|
||||
|
||||
/**
|
||||
* Creates table with pre-calculated radial type 2 integrals.
|
||||
*/
|
||||
radial_type2_table_t *libgrpp_tabulate_radial_type2_integrals(
|
||||
int lambda1_max, int lambda2_max, int n_max, double CA_2, double CB_2,
|
||||
libgrpp_potential_t *potential, libgrpp_shell_t *bra,
|
||||
libgrpp_shell_t *ket) {
|
||||
/*
|
||||
* create empty table containing pre-tabulated radial type 2 integrals
|
||||
*/
|
||||
radial_type2_table_t *table;
|
||||
table = (radial_type2_table_t *)calloc(1, sizeof(radial_type2_table_t));
|
||||
table->lambda1_max = lambda1_max;
|
||||
table->lambda2_max = lambda2_max;
|
||||
table->n_max = n_max;
|
||||
table->radial_integrals = (double *)calloc(
|
||||
(lambda1_max + 1) * (lambda2_max + 1) * (n_max + 1), sizeof(double));
|
||||
|
||||
/*
|
||||
* the special case of one-center RPP integrals
|
||||
*/
|
||||
if (CA_2 < 1e-14 && CB_2 < 1e-14) {
|
||||
|
||||
for (int i = 0; i < bra->num_primitives; i++) {
|
||||
double alpha_A = bra->alpha[i];
|
||||
double coef_i =
|
||||
bra->coeffs[i] * libgrpp_gaussian_norm_factor(bra->L, 0, 0, alpha_A);
|
||||
|
||||
for (int j = 0; j < ket->num_primitives; j++) {
|
||||
double alpha_B = ket->alpha[j];
|
||||
double coef_j = ket->coeffs[j] *
|
||||
libgrpp_gaussian_norm_factor(ket->L, 0, 0, alpha_B);
|
||||
|
||||
for (int k = 0; k < potential->num_primitives; k++) {
|
||||
double eta = potential->alpha[k];
|
||||
int ni = potential->powers[k];
|
||||
double coef_k = potential->coeffs[k];
|
||||
|
||||
double p = alpha_A + alpha_B + eta;
|
||||
double factor = coef_i * coef_j * coef_k;
|
||||
|
||||
for (int n = 0; n <= n_max; n++) {
|
||||
|
||||
double val_ijk = libgrpp_gaussian_integral(ni + n, p);
|
||||
table->radial_integrals[n] += factor * val_ijk;
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
/*
|
||||
* for numerical integration on the grid
|
||||
*/
|
||||
radial_type2_params_t params;
|
||||
params.CA = sqrt(CA_2);
|
||||
params.CB = sqrt(CB_2);
|
||||
params.potential = libgrpp_shrink_potential(potential);
|
||||
|
||||
params.bra = libgrpp_shell_deep_copy(bra);
|
||||
libgrpp_shell_shrink(params.bra);
|
||||
libgrpp_shell_mult_normcoef(params.bra);
|
||||
|
||||
params.ket = libgrpp_shell_deep_copy(ket);
|
||||
libgrpp_shell_shrink(params.ket);
|
||||
libgrpp_shell_mult_normcoef(params.ket);
|
||||
|
||||
/*
|
||||
* create radial grid
|
||||
*/
|
||||
radial_type2_grid_t *grid =
|
||||
create_radial_type2_grid(lambda1_max, lambda2_max, n_max, ¶ms);
|
||||
|
||||
/*
|
||||
* calculate radial integrals and store them into the table
|
||||
*/
|
||||
for (int lambda_1 = 0; lambda_1 <= lambda1_max; lambda_1++) {
|
||||
for (int lambda_2 = 0; lambda_2 <= lambda2_max; lambda_2++) {
|
||||
for (int n = 0; n <= n_max; n++) {
|
||||
|
||||
int converged;
|
||||
double Q = calculate_radial_type2_integral(grid, n, lambda_1, lambda_2,
|
||||
1e-16, &converged);
|
||||
|
||||
// int dim1 = lambda1_max + 1;
|
||||
int dim2 = lambda2_max + 1;
|
||||
int dimn = n_max + 1;
|
||||
table->radial_integrals[dim2 * dimn * lambda_1 + dimn * lambda_2 + n] =
|
||||
Q;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* clean-up
|
||||
*/
|
||||
libgrpp_delete_potential(params.potential);
|
||||
libgrpp_delete_shell(params.bra);
|
||||
libgrpp_delete_shell(params.ket);
|
||||
delete_radial_type2_grid(grid);
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
/**
|
||||
* destructor for the table of radial type 2 integrals
|
||||
*/
|
||||
void libgrpp_delete_radial_type2_integrals(radial_type2_table_t *table) {
|
||||
free(table->radial_integrals);
|
||||
free(table);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns radial integral at complex index (lambda1,lambda2,N)
|
||||
*/
|
||||
double libgrpp_get_radial_type2_integral(radial_type2_table_t *table,
|
||||
int lambda1, int lambda2, int n) {
|
||||
// int lambda1_max = table->lambda1_max;
|
||||
int lambda2_max = table->lambda2_max;
|
||||
int n_max = table->n_max;
|
||||
// int dim1 = lambda1_max + 1;
|
||||
int dim2 = lambda2_max + 1;
|
||||
int dimn = n_max + 1;
|
||||
|
||||
double Q =
|
||||
table->radial_integrals[dim2 * dimn * lambda1 + dimn * lambda2 + n];
|
||||
|
||||
return Q;
|
||||
}
|
||||
|
||||
/**
|
||||
* calculates type 2 radial integral T^N_{lambda1,lambda2}
|
||||
* for the two given contracted gaussian functions and the contracted potential
|
||||
*/
|
||||
static double calculate_radial_type2_integral(radial_type2_grid_t *grid, int n,
|
||||
int lambda1, int lambda2,
|
||||
double tolerance,
|
||||
int *converged) {
|
||||
int nr = MIN_GRID;
|
||||
|
||||
*converged = 0;
|
||||
double prev_sum = 0.0;
|
||||
double sum = 0.0;
|
||||
|
||||
double *w = grid->w;
|
||||
// double *r = grid->r;
|
||||
double *pot_values = grid->rpp_values;
|
||||
double *F1 = grid->F1[lambda1];
|
||||
double *F2 = grid->F2[lambda2];
|
||||
double *r_N = grid->r_N[n];
|
||||
|
||||
/*
|
||||
* first step: integral screening
|
||||
*/
|
||||
double CA = grid->params->CA;
|
||||
double CB = grid->params->CB;
|
||||
|
||||
double screened = 0.0;
|
||||
int screen_success = libgrpp_screening_radial_type2(
|
||||
lambda1, lambda2, n, CA * CA, CB * CB, grid->params->bra,
|
||||
grid->params->ket, grid->params->potential, &screened);
|
||||
|
||||
if (screen_success == EXIT_SUCCESS && fabs(screened) < tolerance) {
|
||||
*converged = 1;
|
||||
return screened;
|
||||
}
|
||||
|
||||
/*
|
||||
* second step: calculation on the smallest possible grid
|
||||
*/
|
||||
for (int i = 0; i < nr; i++) {
|
||||
sum += w[i] * pot_values[i] * F1[i] * F2[i] * r_N[i];
|
||||
}
|
||||
|
||||
/*
|
||||
* third step: adaptive integration, refinement of the result
|
||||
*/
|
||||
do {
|
||||
int idx = nr;
|
||||
nr = 2 * nr + 1;
|
||||
if (nr > MAX_GRID) {
|
||||
break;
|
||||
}
|
||||
|
||||
prev_sum = sum;
|
||||
sum = 0.5 * sum;
|
||||
|
||||
expand_radial_type2_grid(grid, nr);
|
||||
|
||||
for (int i = idx; i < nr; i++) {
|
||||
sum += w[i] * pot_values[i] * F1[i] * F2[i] * r_N[i];
|
||||
}
|
||||
|
||||
if (screen_success == EXIT_SUCCESS &&
|
||||
(fabs(sum) / fabs(screened) < 0.001)) {
|
||||
*converged = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
*converged = fabs(sum - prev_sum) <= tolerance;
|
||||
|
||||
} while (!(*converged));
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Numerical integration on the Log3 grid
|
||||
*/
|
||||
static radial_type2_grid_t *
|
||||
create_radial_type2_grid(int lambda1_max, int lambda2_max, int n_max,
|
||||
radial_type2_params_t *params) {
|
||||
radial_type2_grid_t *grid =
|
||||
(radial_type2_grid_t *)calloc(1, sizeof(radial_type2_grid_t));
|
||||
|
||||
grid->nr = MIN_GRID;
|
||||
grid->n_max = n_max;
|
||||
grid->lambda1_max = lambda1_max;
|
||||
grid->lambda2_max = lambda2_max;
|
||||
grid->params = params;
|
||||
|
||||
grid->r = alloc_zeros_1d(MAX_GRID);
|
||||
grid->w = alloc_zeros_1d(MAX_GRID);
|
||||
grid->rpp_values = alloc_zeros_1d(MAX_GRID);
|
||||
grid->F1 = alloc_zeros_2d(lambda1_max + 1, MAX_GRID);
|
||||
grid->F2 = alloc_zeros_2d(lambda2_max + 1, MAX_GRID);
|
||||
grid->r_N = alloc_zeros_2d(n_max + 1, MAX_GRID);
|
||||
|
||||
// vectors 'k': k = - 2 * alpha * |CA|
|
||||
double *bra_k = alloc_zeros_1d(params->bra->num_primitives);
|
||||
double *ket_k = alloc_zeros_1d(params->ket->num_primitives);
|
||||
calc_k_values(params->bra->num_primitives, params->bra->alpha, params->CA,
|
||||
bra_k);
|
||||
calc_k_values(params->ket->num_primitives, params->ket->alpha, params->CB,
|
||||
ket_k);
|
||||
|
||||
// initial set of pre-calculated points
|
||||
int nr = grid->nr;
|
||||
const double R = 5.0;
|
||||
const double R3 = R * R * R;
|
||||
|
||||
for (int i = 1; i <= nr; i++) {
|
||||
double xi = i / (nr + 1.0);
|
||||
double xi3 = xi * xi * xi;
|
||||
double ln_xi = log(1 - xi3);
|
||||
double wi = 3 * R3 * xi * xi * ln_xi * ln_xi / ((1 - xi3) * (nr + 1.0));
|
||||
double ri = -R * ln_xi;
|
||||
|
||||
grid->r[i - 1] = ri;
|
||||
grid->w[i - 1] = wi;
|
||||
grid->rpp_values[i - 1] =
|
||||
libgrpp_potential_value(grid->params->potential, ri);
|
||||
for (int n = 0; n <= n_max; n++) {
|
||||
grid->r_N[n][i - 1] = pow(ri, n);
|
||||
}
|
||||
for (int lambda1 = 0; lambda1 <= lambda1_max; lambda1++) {
|
||||
grid->F1[lambda1][i - 1] = radial_type2_integrand_fun_contracted(
|
||||
ri, lambda1, bra_k, params->CA, params->bra);
|
||||
}
|
||||
for (int lambda2 = 0; lambda2 <= lambda2_max; lambda2++) {
|
||||
grid->F2[lambda2][i - 1] = radial_type2_integrand_fun_contracted(
|
||||
ri, lambda2, ket_k, params->CB, params->ket);
|
||||
}
|
||||
}
|
||||
|
||||
free(bra_k);
|
||||
free(ket_k);
|
||||
|
||||
return grid;
|
||||
}
|
||||
|
||||
/**
|
||||
* constructs new radial grid points
|
||||
*/
|
||||
static void expand_radial_type2_grid(radial_type2_grid_t *grid, int nr) {
|
||||
const double R = 5.0;
|
||||
const double R3 = R * R * R;
|
||||
|
||||
if (nr > MAX_GRID) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (nr <= grid->nr) { // nothing to do
|
||||
return;
|
||||
}
|
||||
|
||||
radial_type2_params_t *params = grid->params;
|
||||
|
||||
// vectors 'k': k = - 2 * alpha * |CA|
|
||||
double *bra_k = alloc_zeros_1d(params->bra->num_primitives);
|
||||
double *ket_k = alloc_zeros_1d(params->ket->num_primitives);
|
||||
calc_k_values(params->bra->num_primitives, params->bra->alpha, params->CA,
|
||||
bra_k);
|
||||
calc_k_values(params->ket->num_primitives, params->ket->alpha, params->CB,
|
||||
ket_k);
|
||||
|
||||
// additional set of grid points
|
||||
int idx = grid->nr;
|
||||
for (int i = 1; i <= nr; i += 2) {
|
||||
double xi = i / (nr + 1.0);
|
||||
double xi3 = xi * xi * xi;
|
||||
double ln_xi = log(1 - xi3);
|
||||
double wi = 3 * R3 * xi * xi * ln_xi * ln_xi / ((1 - xi3) * (nr + 1.0));
|
||||
double ri = -R * ln_xi;
|
||||
|
||||
grid->r[idx] = ri;
|
||||
grid->w[idx] = wi;
|
||||
grid->rpp_values[idx] =
|
||||
libgrpp_potential_value(grid->params->potential, ri);
|
||||
|
||||
for (int n = 0; n <= grid->n_max; n++) {
|
||||
grid->r_N[n][idx] = pow(ri, n);
|
||||
}
|
||||
|
||||
for (int lambda1 = 0; lambda1 <= grid->lambda1_max; lambda1++) {
|
||||
grid->F1[lambda1][idx] = radial_type2_integrand_fun_contracted(
|
||||
ri, lambda1, bra_k, grid->params->CA, params->bra);
|
||||
}
|
||||
for (int lambda2 = 0; lambda2 <= grid->lambda2_max; lambda2++) {
|
||||
grid->F2[lambda2][idx] = radial_type2_integrand_fun_contracted(
|
||||
ri, lambda2, ket_k, grid->params->CB, params->ket);
|
||||
}
|
||||
|
||||
idx++;
|
||||
}
|
||||
|
||||
grid->nr = nr;
|
||||
|
||||
free(bra_k);
|
||||
free(ket_k);
|
||||
}
|
||||
|
||||
/**
|
||||
* deallocates memory used for the radial grid
|
||||
*/
|
||||
static void delete_radial_type2_grid(radial_type2_grid_t *grid) {
|
||||
free(grid->r);
|
||||
free(grid->w);
|
||||
free(grid->rpp_values);
|
||||
free_2d(grid->F1, grid->lambda1_max + 1);
|
||||
free_2d(grid->F2, grid->lambda2_max + 1);
|
||||
free_2d(grid->r_N, grid->n_max + 1);
|
||||
free(grid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the value of the integrand function
|
||||
*/
|
||||
static double
|
||||
radial_type2_integrand_fun_contracted(double r, int lambda, double *k,
|
||||
double CA, libgrpp_shell_t *gauss_fun) {
|
||||
double F = 0.0;
|
||||
double r_CA_2 = (r - CA) * (r - CA);
|
||||
|
||||
int nprim = gauss_fun->num_primitives;
|
||||
double *alpha = gauss_fun->alpha;
|
||||
double *coeffs = gauss_fun->coeffs;
|
||||
|
||||
for (int i = 0; i < nprim; i++) {
|
||||
double power = -alpha[i] * r_CA_2;
|
||||
F += coeffs[i] * exp(power) *
|
||||
libgrpp_modified_bessel_scaled(lambda, k[i] * r);
|
||||
}
|
||||
|
||||
return F;
|
||||
}
|
||||
|
||||
static void calc_k_values(int nprim, const double *alpha, double CA,
|
||||
double *k) {
|
||||
for (int i = 0; i < nprim; i++) {
|
||||
k[i] = 2.0 * alpha[i] * CA;
|
||||
}
|
||||
}
|
||||
36
src/grpp/grpp_radial_type2_integral.h
Normal file
36
src/grpp/grpp_radial_type2_integral.h
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/*----------------------------------------------------------------------------*/
|
||||
/* CP2K: A general program to perform molecular dynamics simulations */
|
||||
/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
|
||||
/* */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* libgrpp - a library for the evaluation of integrals over
|
||||
* generalized relativistic pseudopotentials.
|
||||
*
|
||||
* Copyright (C) 2021-2023 Alexander Oleynichenko
|
||||
*/
|
||||
|
||||
#ifndef LIBGRPP_RADIAL_TYPE2_INTEGRAL_H
|
||||
#define LIBGRPP_RADIAL_TYPE2_INTEGRAL_H
|
||||
|
||||
#include "libgrpp_types.h"
|
||||
|
||||
typedef struct {
|
||||
int lambda1_max;
|
||||
int lambda2_max;
|
||||
int n_max;
|
||||
double *radial_integrals;
|
||||
} radial_type2_table_t;
|
||||
|
||||
radial_type2_table_t *libgrpp_tabulate_radial_type2_integrals(
|
||||
int lambda1_max, int lambda2_max, int n_max, double CA_2, double CB_2,
|
||||
libgrpp_potential_t *potential, libgrpp_shell_t *bra, libgrpp_shell_t *ket);
|
||||
|
||||
double libgrpp_get_radial_type2_integral(radial_type2_table_t *table,
|
||||
int lambda1, int lambda2, int n);
|
||||
|
||||
void libgrpp_delete_radial_type2_integrals(radial_type2_table_t *table);
|
||||
|
||||
#endif // LIBGRPP_RADIAL_TYPE2_INTEGRAL_H
|
||||
335
src/grpp/grpp_screening.c
Normal file
335
src/grpp/grpp_screening.c
Normal file
|
|
@ -0,0 +1,335 @@
|
|||
/*----------------------------------------------------------------------------*/
|
||||
/* CP2K: A general program to perform molecular dynamics simulations */
|
||||
/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
|
||||
/* */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* libgrpp - a library for the evaluation of integrals over
|
||||
* generalized relativistic pseudopotentials.
|
||||
*
|
||||
* Copyright (C) 2021-2023 Alexander Oleynichenko
|
||||
*/
|
||||
|
||||
/*
|
||||
* Screening of radial integrals.
|
||||
*
|
||||
* The technique of screening is adopted from:
|
||||
* R. A. Shaw, J. G. Hill. Prescreening and efficiency in the evaluation
|
||||
* of integrals over ab initio effective core potentials.
|
||||
* J. Chem. Phys. 147, 074108 (2017). doi: 10.1063/1.4986887
|
||||
* (see also Supplementary Material for this article).
|
||||
*
|
||||
* Note that in this publication the transcendental equation (2) for
|
||||
* type 2 integrals is not correct.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
#include "grpp_factorial.h"
|
||||
#include "grpp_screening.h"
|
||||
#include "grpp_specfunc.h"
|
||||
#include "libgrpp.h"
|
||||
|
||||
/*
|
||||
* functions defined below in the file
|
||||
*/
|
||||
|
||||
static int screening_radial_type1_integral_primitive(
|
||||
int lambda, int n, double CA_2, double CB_2, double alpha_A, double alpha_B,
|
||||
double k, double eta, double *screened_value);
|
||||
|
||||
static double screening_type1_equation_for_maximum(double r, int n, int lambda,
|
||||
double p, double k);
|
||||
|
||||
static int screening_radial_type2_integral_primitive(
|
||||
int lambda1, int lambda2, int n, double CA_2, double CB_2, double alpha_A,
|
||||
double alpha_B, double k1, double k2, double eta, double *screened_value);
|
||||
|
||||
static double screening_type2_equation_for_maximum(double r, int n, int lambda1,
|
||||
int lambda2, double p,
|
||||
double k1, double k2);
|
||||
|
||||
// static double analytic_one_center_rpp_integral_primitive(int L, double
|
||||
// alpha1,
|
||||
// double alpha2, int
|
||||
// n, double zeta);
|
||||
|
||||
/**
|
||||
* screening for the type 1 radial integrals
|
||||
* for the pair of contracted gaussian functions.
|
||||
*/
|
||||
int libgrpp_screening_radial_type1(int lambda, int n, double CA_2, double CB_2,
|
||||
double alpha_A, double alpha_B, double k,
|
||||
double prefactor,
|
||||
libgrpp_potential_t *potential,
|
||||
double *screened_value) {
|
||||
*screened_value = 0.0;
|
||||
|
||||
if (lambda >= 1 && fabs(k) <= LIBGRPP_ZERO_THRESH) {
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* loop over RPP primitives
|
||||
*/
|
||||
for (int iprim = 0; iprim < potential->num_primitives; iprim++) {
|
||||
double eta = potential->alpha[iprim];
|
||||
int ni = n + potential->powers[iprim];
|
||||
double coef = potential->coeffs[iprim];
|
||||
|
||||
double val_i = 0.0;
|
||||
int err_code = screening_radial_type1_integral_primitive(
|
||||
lambda, ni, CA_2, CB_2, alpha_A, alpha_B, k, eta, &val_i);
|
||||
if (err_code == EXIT_FAILURE) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
*screened_value += prefactor * coef * val_i;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* screening for the type 1 radial integrals
|
||||
* for the pair of primitive gaussian functions.
|
||||
*/
|
||||
static int screening_radial_type1_integral_primitive(
|
||||
int lambda, int n, double CA_2, double CB_2, double alpha_A, double alpha_B,
|
||||
double k, double eta, double *screened_value) {
|
||||
double p = alpha_A + alpha_B + eta;
|
||||
double CA = sqrt(CA_2);
|
||||
double CB = sqrt(CB_2);
|
||||
|
||||
/*
|
||||
* find position of the maximum of the integrand
|
||||
*/
|
||||
const double tol = 1e-2;
|
||||
double r0 = (alpha_A * CA + alpha_B * CB) / p;
|
||||
double r0_prev = 0.0;
|
||||
|
||||
int nsteps = 0;
|
||||
do {
|
||||
nsteps++;
|
||||
if (nsteps == 10) {
|
||||
*screened_value = 0.0;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
r0_prev = r0;
|
||||
r0 = screening_type1_equation_for_maximum(r0, n, lambda, p, k);
|
||||
} while (fabs(r0 - r0_prev) > tol);
|
||||
|
||||
/*
|
||||
* envelope function for the integrand
|
||||
*/
|
||||
*screened_value =
|
||||
sqrt(M_PI / p) * pow(r0, n) *
|
||||
libgrpp_modified_bessel_scaled(lambda, k * r0) *
|
||||
exp(-p * r0 * r0 - alpha_A * CA_2 - alpha_B * CB_2 + k * r0) * 0.5 *
|
||||
(1 + erf(sqrt(p) * r0));
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* transcendental equation for finding maximum of the type 1 integrand
|
||||
*/
|
||||
static double screening_type1_equation_for_maximum(double r, int n, int lambda,
|
||||
double p, double k) {
|
||||
double K_ratio = 0.0;
|
||||
if (lambda == 0) {
|
||||
K_ratio = libgrpp_modified_bessel_scaled(1, k * r) /
|
||||
libgrpp_modified_bessel_scaled(0, k * r);
|
||||
} else {
|
||||
K_ratio = libgrpp_modified_bessel_scaled(lambda - 1, k * r) /
|
||||
libgrpp_modified_bessel_scaled(lambda, k * r);
|
||||
}
|
||||
|
||||
double a = n + K_ratio * k * r;
|
||||
if (lambda > 0) {
|
||||
a = a - lambda - 1;
|
||||
}
|
||||
|
||||
return sqrt(a / (2.0 * p));
|
||||
}
|
||||
|
||||
/**
|
||||
* screening for the type 2 radial integrals
|
||||
* for the pair of contracted gaussian functions.
|
||||
*/
|
||||
int libgrpp_screening_radial_type2(int lambda1, int lambda2, int n, double CA_2,
|
||||
double CB_2, libgrpp_shell_t *bra,
|
||||
libgrpp_shell_t *ket,
|
||||
libgrpp_potential_t *potential,
|
||||
double *screened_value) {
|
||||
*screened_value = 0.0;
|
||||
|
||||
double CA = sqrt(CA_2);
|
||||
double CB = sqrt(CB_2);
|
||||
|
||||
/*
|
||||
* loop over 'bra' contracted function
|
||||
*/
|
||||
for (int i = 0; i < bra->num_primitives; i++) {
|
||||
double alpha_A = bra->alpha[i];
|
||||
double coef_i = bra->coeffs[i];
|
||||
double k1 = 2 * alpha_A * CA;
|
||||
|
||||
/*
|
||||
* loop over 'ket' contracted function
|
||||
*/
|
||||
for (int j = 0; j < ket->num_primitives; j++) {
|
||||
double alpha_B = ket->alpha[j];
|
||||
double coef_j = ket->coeffs[j];
|
||||
double k2 = 2 * alpha_B * CB;
|
||||
|
||||
/*
|
||||
* loop over RPP primitives
|
||||
*/
|
||||
for (int k = 0; k < potential->num_primitives; k++) {
|
||||
double eta = potential->alpha[k];
|
||||
int ni = n + potential->powers[k];
|
||||
double coef_k = potential->coeffs[k];
|
||||
|
||||
double val_ijk = 0.0;
|
||||
int err_code = screening_radial_type2_integral_primitive(
|
||||
lambda1, lambda2, ni, CA_2, CB_2, alpha_A, alpha_B, k1, k2, eta,
|
||||
&val_ijk);
|
||||
if (err_code == EXIT_FAILURE) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
*screened_value += coef_i * coef_j * coef_k * val_ijk;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Analytically evaluates Gaussian integral:
|
||||
* \int_0^\infty r^n e^(-a r^2) dr
|
||||
*/
|
||||
double libgrpp_gaussian_integral(int n, double a) {
|
||||
if (n % 2 == 0) {
|
||||
int k = n / 2;
|
||||
return libgrpp_double_factorial(2 * k - 1) / (pow(2.0, k + 1) * pow(a, k)) *
|
||||
sqrt(M_PI / a);
|
||||
} else {
|
||||
int k = (n - 1) / 2;
|
||||
return libgrpp_factorial(k) / (2.0 * pow(a, k + 1));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* screening for the type 2 radial integrals
|
||||
* for the pair of primitive gaussian functions.
|
||||
*/
|
||||
static int screening_radial_type2_integral_primitive(
|
||||
int lambda1, int lambda2, int n, double CA_2, double CB_2, double alpha_A,
|
||||
double alpha_B, double k1, double k2, double eta, double *screened_value) {
|
||||
*screened_value = 0.0;
|
||||
|
||||
if (lambda1 >= 1 && fabs(k1) <= LIBGRPP_ZERO_THRESH) {
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
if (lambda2 >= 1 && fabs(k2) <= LIBGRPP_ZERO_THRESH) {
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
double p = alpha_A + alpha_B + eta;
|
||||
double CA = sqrt(CA_2);
|
||||
double CB = sqrt(CB_2);
|
||||
|
||||
/*
|
||||
* special case:
|
||||
* lambda1 = lambda2 = 0,
|
||||
* k1 = k2 = 0.
|
||||
* => M_0(0) = 1
|
||||
* => we have one-center integral which can be evaluated analytically
|
||||
*/
|
||||
if (lambda1 == 0 && lambda2 == 0) {
|
||||
if (fabs(k1) <= LIBGRPP_ZERO_THRESH && fabs(k2) <= LIBGRPP_ZERO_THRESH) {
|
||||
*screened_value = exp(-alpha_A * CA * CA - alpha_B * CB * CB) *
|
||||
libgrpp_gaussian_integral(n, p);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* find position of the maximum of the integrand
|
||||
*/
|
||||
const double tol = 1e-2;
|
||||
double r0 = (alpha_A * CA + alpha_B * CB) / p;
|
||||
double r0_prev = 0.0;
|
||||
int nsteps = 0;
|
||||
|
||||
do {
|
||||
nsteps++;
|
||||
if (nsteps == 5) {
|
||||
*screened_value = 0.0;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
r0_prev = r0;
|
||||
r0 = screening_type2_equation_for_maximum(r0, n, lambda1, lambda2, p, k1,
|
||||
k2);
|
||||
} while (fabs(r0 - r0_prev) > tol);
|
||||
|
||||
/*
|
||||
* envelope function for the integrand
|
||||
*/
|
||||
*screened_value = sqrt(M_PI / p) * pow(r0, n) *
|
||||
libgrpp_modified_bessel_scaled(lambda1, k1 * r0) *
|
||||
libgrpp_modified_bessel_scaled(lambda2, k2 * r0) *
|
||||
exp(-eta * r0 * r0 - alpha_A * (r0 - CA) * (r0 - CA) -
|
||||
alpha_B * (r0 - CB) * (r0 - CB)) *
|
||||
0.5 * (1 + erf(sqrt(p) * r0));
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* transcendental equation for finding maximum of the type 2 integrand
|
||||
*/
|
||||
static double screening_type2_equation_for_maximum(double r, int n, int lambda1,
|
||||
int lambda2, double p,
|
||||
double k1, double k2) {
|
||||
double K1_ratio = 0.0;
|
||||
double k1_r = k1 * r;
|
||||
if (lambda1 == 0) {
|
||||
K1_ratio = libgrpp_modified_bessel_scaled(1, k1_r) /
|
||||
libgrpp_modified_bessel_scaled(0, k1_r);
|
||||
} else {
|
||||
K1_ratio = libgrpp_modified_bessel_scaled(lambda1 - 1, k1_r) /
|
||||
libgrpp_modified_bessel_scaled(lambda1, k1_r);
|
||||
}
|
||||
|
||||
double K2_ratio = 0.0;
|
||||
double k2_r = k2 * r;
|
||||
if (lambda2 == 0) {
|
||||
K2_ratio = libgrpp_modified_bessel_scaled(1, k2_r) /
|
||||
libgrpp_modified_bessel_scaled(0, k2_r);
|
||||
} else {
|
||||
K2_ratio = libgrpp_modified_bessel_scaled(lambda2 - 1, k2_r) /
|
||||
libgrpp_modified_bessel_scaled(lambda2, k2_r);
|
||||
}
|
||||
|
||||
double a = K1_ratio * k1_r + K2_ratio * k2_r + n;
|
||||
|
||||
if (lambda1 > 0) {
|
||||
a = a - lambda1 - 1;
|
||||
}
|
||||
if (lambda2 > 0) {
|
||||
a = a - lambda2 - 1;
|
||||
}
|
||||
|
||||
return sqrt(a / (2.0 * p));
|
||||
}
|
||||
32
src/grpp/grpp_screening.h
Normal file
32
src/grpp/grpp_screening.h
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/*----------------------------------------------------------------------------*/
|
||||
/* CP2K: A general program to perform molecular dynamics simulations */
|
||||
/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
|
||||
/* */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* libgrpp - a library for the evaluation of integrals over
|
||||
* generalized relativistic pseudopotentials.
|
||||
*
|
||||
* Copyright (C) 2021-2023 Alexander Oleynichenko
|
||||
*/
|
||||
|
||||
#ifndef LIBGRPP_SCREENING_H
|
||||
#define LIBGRPP_SCREENING_H
|
||||
|
||||
#include "libgrpp.h"
|
||||
|
||||
int libgrpp_screening_radial_type1(int lambda, int n, double CA_2, double CB_2,
|
||||
double alpha_A, double alpha_B, double k,
|
||||
double prefactor,
|
||||
libgrpp_potential_t *potential,
|
||||
double *screened_value);
|
||||
|
||||
int libgrpp_screening_radial_type2(int lambda1, int lambda2, int n, double CA_2,
|
||||
double CB_2, libgrpp_shell_t *bra,
|
||||
libgrpp_shell_t *ket,
|
||||
libgrpp_potential_t *potential,
|
||||
double *screened_value);
|
||||
|
||||
#endif // LIBGRPP_SCREENING_H
|
||||
117
src/grpp/grpp_shell.c
Normal file
117
src/grpp/grpp_shell.c
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
/*----------------------------------------------------------------------------*/
|
||||
/* CP2K: A general program to perform molecular dynamics simulations */
|
||||
/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
|
||||
/* */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* libgrpp - a library for the evaluation of integrals over
|
||||
* generalized relativistic pseudopotentials.
|
||||
*
|
||||
* Copyright (C) 2021-2023 Alexander Oleynichenko
|
||||
*/
|
||||
|
||||
/*
|
||||
* representation of atom-centered shell of contracted Gaussian functions
|
||||
*/
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.1415926535897932384626433
|
||||
#endif
|
||||
|
||||
#include "libgrpp.h"
|
||||
|
||||
#include "grpp_norm_gaussian.h"
|
||||
|
||||
/**
|
||||
* constructs new object representing a shell; returns pointer to it.
|
||||
*/
|
||||
libgrpp_shell_t *libgrpp_new_shell(double *origin, int L, int num_primitives,
|
||||
double *coeffs, double *alpha) {
|
||||
libgrpp_shell_t *shell = (libgrpp_shell_t *)malloc(sizeof(libgrpp_shell_t));
|
||||
|
||||
shell->L = L;
|
||||
shell->origin[0] = origin[0];
|
||||
shell->origin[1] = origin[1];
|
||||
shell->origin[2] = origin[2];
|
||||
shell->cart_size = (L + 1) * (L + 2) / 2;
|
||||
shell->cart_list = libgrpp_generate_shell_cartesians(L);
|
||||
|
||||
shell->num_primitives = num_primitives;
|
||||
shell->coeffs = (double *)calloc(num_primitives, sizeof(double));
|
||||
shell->alpha = (double *)calloc(num_primitives, sizeof(double));
|
||||
for (int i = 0; i < num_primitives; i++) {
|
||||
shell->coeffs[i] = coeffs[i];
|
||||
shell->alpha[i] = alpha[i];
|
||||
}
|
||||
|
||||
return shell;
|
||||
}
|
||||
|
||||
/**
|
||||
* creates deep copy of the 'libgrpp_shell_t' object
|
||||
*/
|
||||
libgrpp_shell_t *libgrpp_shell_deep_copy(libgrpp_shell_t *src_shell) {
|
||||
libgrpp_shell_t *new_shell = libgrpp_new_shell(
|
||||
src_shell->origin, src_shell->L, src_shell->num_primitives,
|
||||
src_shell->coeffs, src_shell->alpha);
|
||||
|
||||
return new_shell;
|
||||
}
|
||||
|
||||
/**
|
||||
* removes primitive gaussians (from the contracted function)
|
||||
* with zero coefficients
|
||||
*/
|
||||
void libgrpp_shell_shrink(libgrpp_shell_t *shell) {
|
||||
int nprim = 0;
|
||||
|
||||
for (int i = 0; i < shell->num_primitives; i++) {
|
||||
if (fabs(shell->coeffs[i]) > LIBGRPP_ZERO_THRESH) {
|
||||
shell->coeffs[nprim] = shell->coeffs[i];
|
||||
shell->alpha[nprim] = shell->alpha[i];
|
||||
nprim++;
|
||||
}
|
||||
}
|
||||
|
||||
shell->num_primitives = nprim;
|
||||
}
|
||||
|
||||
/**
|
||||
* multiplies coefficients of the primitive gaussians by their normalization
|
||||
* factors
|
||||
*/
|
||||
void libgrpp_shell_mult_normcoef(libgrpp_shell_t *shell) {
|
||||
for (int i = 0; i < shell->num_primitives; i++) {
|
||||
double norm_factor =
|
||||
libgrpp_gaussian_norm_factor(shell->L, 0, 0, shell->alpha[i]);
|
||||
shell->coeffs[i] *= norm_factor;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* returns number of Cartesian primitives encapsulated inside the shell
|
||||
*/
|
||||
int libgrpp_get_shell_size(libgrpp_shell_t *shell) { return shell->cart_size; }
|
||||
|
||||
/**
|
||||
* destructor for the shell object
|
||||
*/
|
||||
void libgrpp_delete_shell(libgrpp_shell_t *shell) {
|
||||
free(shell->cart_list);
|
||||
free(shell->coeffs);
|
||||
free(shell->alpha);
|
||||
free(shell);
|
||||
}
|
||||
|
||||
int *libgrpp_generate_shell_cartesians(int L) {
|
||||
int ncart = (L + 1) * (L + 2) / 2;
|
||||
|
||||
int *cart_list = (int *)calloc(3 * ncart, sizeof(int));
|
||||
libgrpp_params.cartesian_generator(L, cart_list);
|
||||
|
||||
return cart_list;
|
||||
}
|
||||
35
src/grpp/grpp_specfunc.h
Normal file
35
src/grpp/grpp_specfunc.h
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/*----------------------------------------------------------------------------*/
|
||||
/* CP2K: A general program to perform molecular dynamics simulations */
|
||||
/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
|
||||
/* */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* libgrpp - a library for the evaluation of integrals over
|
||||
* generalized relativistic pseudopotentials.
|
||||
*
|
||||
* Copyright (C) 2021-2023 Alexander Oleynichenko
|
||||
*/
|
||||
|
||||
/*
|
||||
* Interface to the MyMathLib library:
|
||||
* http://www.mymathlib.com/
|
||||
*/
|
||||
|
||||
#ifndef LIBGRPP_SPECFUNC_H
|
||||
#define LIBGRPP_SPECFUNC_H
|
||||
|
||||
double libgrpp_modified_bessel_scaled(int n, double x);
|
||||
|
||||
void libgrpp_gfun_values(double x, int nmax, double *g);
|
||||
|
||||
double libgrpp_boys_function(int n, double x);
|
||||
|
||||
void libgrpp_boys_values(double x, int nmax, double *b);
|
||||
|
||||
double libgrpp_specfunc_fermi_sk(int k, double x);
|
||||
|
||||
double libgrpp_Dawsons_Integral(double x);
|
||||
|
||||
#endif // LIBGRPP_SPECFUNC_H
|
||||
28853
src/grpp/grpp_specfunc_bessel_table.c
Normal file
28853
src/grpp/grpp_specfunc_bessel_table.c
Normal file
File diff suppressed because it is too large
Load diff
4577
src/grpp/grpp_specfunc_boys.c
Normal file
4577
src/grpp/grpp_specfunc_boys.c
Normal file
File diff suppressed because it is too large
Load diff
570
src/grpp/grpp_specfunc_dawson.c
Normal file
570
src/grpp/grpp_specfunc_dawson.c
Normal file
|
|
@ -0,0 +1,570 @@
|
|||
/*----------------------------------------------------------------------------*/
|
||||
/* CP2K: A general program to perform molecular dynamics simulations */
|
||||
/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
|
||||
/* */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* libgrpp - a library for the evaluation of integrals over
|
||||
* generalized relativistic pseudopotentials.
|
||||
*
|
||||
* Copyright (C) 2021-2023 Alexander Oleynichenko
|
||||
*/
|
||||
|
||||
#include <float.h> // required for LDBL_EPSILON
|
||||
#include <math.h> // required for fabsl()
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.1415926535897932384626433
|
||||
#endif
|
||||
|
||||
#include "grpp_specfunc.h"
|
||||
|
||||
/*
|
||||
* This code is taken from the website:
|
||||
* http://www.mymathlib.com/functions/dawsons_integral.html
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// File: specfunc_dawson.c //
|
||||
// Routine(s): //
|
||||
// Dawsons_Integral //
|
||||
// xDawsons_Integral //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Description: //
|
||||
// Dawson's integral, Daw(x), is the integral from 0 to x of the //
|
||||
// integrand: //
|
||||
// exp(-x^2) exp(t^2) dt. //
|
||||
// I.e. //
|
||||
// Daw(x) = exp(-x^2) * I[0,x] (exp(t^2)) dt, //
|
||||
// where I[0,x] indicates the integral from 0 to x. //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#define Asymptotic_Expansion_Cutoff 50
|
||||
|
||||
// Externally Defined Routines //
|
||||
static long double xChebyshev_Tn_Series(long double x, long double a[],
|
||||
int degree);
|
||||
|
||||
// Internally Defined Routines //
|
||||
double libgrpp_Dawsons_Integral(double x);
|
||||
long double xDawsons_Integral(long double x);
|
||||
|
||||
static long double Dawson_Power_Series(long double x);
|
||||
static long double Dawson_Chebyshev_Expansion_1_175(long double x);
|
||||
static long double Dawson_Chebyshev_Expansion_175_250(long double x);
|
||||
static long double Dawson_Chebyshev_Expansion_250_325(long double x);
|
||||
static long double Dawson_Chebyshev_Expansion_325_425(long double x);
|
||||
static long double Dawson_Chebyshev_Expansion_425_550(long double x);
|
||||
static long double Dawson_Chebyshev_Expansion_550_725(long double x);
|
||||
static long double Dawson_Asymptotic_Expansion(long double x);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// double libgrpp_Dawsons_Integral( double x ) //
|
||||
// //
|
||||
// Description: //
|
||||
// Dawson's integral, Daw(x), is the integral with integrand //
|
||||
// exp(-x^2) exp(t^2) dt //
|
||||
// where the integral extends from 0 to x. //
|
||||
// //
|
||||
// Arguments: //
|
||||
// double x The argument of Dawson's integral Daw(). //
|
||||
// //
|
||||
// Return Value: //
|
||||
// The value of Dawson's integral, Daw(), evaluated at x. //
|
||||
// //
|
||||
// Example: //
|
||||
// double y, x; //
|
||||
// //
|
||||
// ( code to initialize x ) //
|
||||
// //
|
||||
// y = Dawsons_Integral( x ); //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
double libgrpp_Dawsons_Integral(double x) {
|
||||
return (double)xDawsons_Integral((long double)x);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// long double xDawsons_Integral( long double x ) //
|
||||
// //
|
||||
// Description: //
|
||||
// Dawson's integral, Daw(x), is the integral with integrand //
|
||||
// exp(-x^2) exp(t^2) dt //
|
||||
// where the integral extends from 0 to x. //
|
||||
// //
|
||||
// Arguments: //
|
||||
// long double x The argument of Dawson's integral Daw(). //
|
||||
// //
|
||||
// Return Value: //
|
||||
// The value of Dawson's integral, Daw(), evaluated at x. //
|
||||
// //
|
||||
// Example: //
|
||||
// long double y, x; //
|
||||
// //
|
||||
// ( code to initialize x ) //
|
||||
// //
|
||||
// y = xDawsons_Integral( x ); //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
long double xDawsons_Integral(long double x) {
|
||||
long double abs_x = fabsl(x);
|
||||
|
||||
if (abs_x <= 1.0L)
|
||||
return Dawson_Power_Series(x);
|
||||
if (abs_x <= 1.75L)
|
||||
return Dawson_Chebyshev_Expansion_1_175(x);
|
||||
if (abs_x <= 2.50L)
|
||||
return Dawson_Chebyshev_Expansion_175_250(x);
|
||||
if (abs_x <= 3.25L)
|
||||
return Dawson_Chebyshev_Expansion_250_325(x);
|
||||
if (abs_x <= 4.25L)
|
||||
return Dawson_Chebyshev_Expansion_325_425(x);
|
||||
if (abs_x <= 5.50L)
|
||||
return Dawson_Chebyshev_Expansion_425_550(x);
|
||||
if (abs_x <= 7.25L)
|
||||
return Dawson_Chebyshev_Expansion_550_725(x);
|
||||
return Dawson_Asymptotic_Expansion(x);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// static long double Dawson_Power_Series( long double x ) //
|
||||
// //
|
||||
// Description: //
|
||||
// Evaluate Dawsons integral for -1 <= x <= 1 using the power series //
|
||||
// expansion: //
|
||||
// Daw(x) = x Sum [(-2x^2)^j / (2j + 1)!!, //
|
||||
// where the sum extends over j = 0, ... . //
|
||||
// //
|
||||
// Arguments: //
|
||||
// long double x The argument of Dawson's integral Daw(), where //
|
||||
// where |x| <= 1. //
|
||||
// //
|
||||
// Return Value: //
|
||||
// The value of Dawson's integral, Daw(), evaluated at x where |x| <= 1. //
|
||||
// //
|
||||
// Example: //
|
||||
// long double y, x; //
|
||||
// //
|
||||
// ( code to initialize x ) //
|
||||
// //
|
||||
// y = Dawson_Power_Series(x); //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static long double Dawson_Power_Series(long double x) {
|
||||
long double two_x2 = -2.0L * x * x;
|
||||
long double sum = 0.0;
|
||||
long double term = 1.0L;
|
||||
long double factorial = 1.0L;
|
||||
long double xn = 1.0L;
|
||||
const long double epsilon = LDBL_EPSILON / 2.0L;
|
||||
int y = 0;
|
||||
|
||||
if (x == 0.0L)
|
||||
return 0.0L;
|
||||
do {
|
||||
sum += term;
|
||||
y += 1;
|
||||
factorial *= (long double)(y + y + 1);
|
||||
xn *= two_x2;
|
||||
term = xn / factorial;
|
||||
} while (fabsl(term) > epsilon * fabsl(sum));
|
||||
return x * sum;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// static long double Dawson_Chebyshev_Expansion_1_175( long double x ) //
|
||||
// //
|
||||
// Description: //
|
||||
// Evaluate Dawsons integral for 1 <= |x| <= 1.75 using the Chebyshev //
|
||||
// expansion of Daw(x) for x in the interval [1,1.75]. //
|
||||
// //
|
||||
// Arguments: //
|
||||
// long double x The argument of Dawson's integral Daw(), where //
|
||||
// where 1 <= |x| <= 1.75. //
|
||||
// //
|
||||
// Return Value: //
|
||||
// The value of Dawson's integral, Daw(), evaluated at x where //
|
||||
// 1 <= x <= 1.75. //
|
||||
// //
|
||||
// Example: //
|
||||
// long double y, x; //
|
||||
// //
|
||||
// ( code to initialize x ) //
|
||||
// //
|
||||
// y = Dawson_Chebyshev_Expansion_1_175(x); //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static long double Dawson_Chebyshev_Expansion_1_175(long double x) {
|
||||
static long double c[] = {
|
||||
+4.563960711239483142081e-1L, -9.268566100670767619861e-2L,
|
||||
-7.334392170021420220239e-3L, +3.379523740404396755124e-3L,
|
||||
-3.085898448678595090813e-4L, -1.519846724619319512311e-5L,
|
||||
+4.903955822454009397182e-6L, -2.106910538629224721838e-7L,
|
||||
-2.930676220603996192089e-8L, +3.326790071774057337673e-9L,
|
||||
+3.335593457695769191326e-11L, -2.279104036721012221982e-11L,
|
||||
+7.877561633156348806091e-13L, +9.173158167107974472228e-14L,
|
||||
-7.341175636102869400671e-15L, -1.763370444125849029511e-16L,
|
||||
+3.792946298506435014290e-17L, -4.251969162435936250171e-19L,
|
||||
-1.358295820818448686821e-19L, +5.268740962820224108235e-21L,
|
||||
+3.414939674304748094484e-22L};
|
||||
|
||||
static const int degree = sizeof(c) / sizeof(long double) - 1;
|
||||
static const long double midpoint = (1.75L + 1.0L) / 2.0L;
|
||||
static const long double half_length = (1.75L - 1.0L) / 2.0L;
|
||||
long double daw =
|
||||
xChebyshev_Tn_Series((fabsl(x) - midpoint) / half_length, c, degree);
|
||||
return (x > 0.0L) ? daw : -daw;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// static long double Dawson_Chebyshev_Expansion_175_250( long double x ) //
|
||||
// //
|
||||
// Description: //
|
||||
// Evaluate Dawsons integral for 1.75 <= |x| <= 2.50 using the Chebyshev //
|
||||
// expansion of Daw(x) for x in the interval [1.75,2.50]. //
|
||||
// //
|
||||
// Arguments: //
|
||||
// long double x The argument of Dawson's integral Daw(), where //
|
||||
// where 1.75 <= |x| <= 2.50. //
|
||||
// //
|
||||
// Return Value: //
|
||||
// The value of Dawson's integral, Daw(), evaluated at x where //
|
||||
// 1.75 <= x <= 2.50. //
|
||||
// //
|
||||
// Example: //
|
||||
// long double y, x; //
|
||||
// //
|
||||
// ( code to initialize x ) //
|
||||
// //
|
||||
// y = Dawson_Chebyshev_Expansion_175_250(x); //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static long double Dawson_Chebyshev_Expansion_175_250(long double x) {
|
||||
static long double c[] = {
|
||||
+2.843711194548592808550e-1L, -6.791774139166808940530e-2L,
|
||||
+6.955211059379384327814e-3L, -2.726366582146839486784e-4L,
|
||||
-6.516682485087925163874e-5L, +1.404387911504935155228e-5L,
|
||||
-1.103288540946056915318e-6L, -1.422154597293404846081e-8L,
|
||||
+1.102714664312839585330e-8L, -8.659211557383544255053e-10L,
|
||||
-8.048589443963965285748e-12L, +6.092061709996351761426e-12L,
|
||||
-3.580977611213519234324e-13L, -1.085173558590137965737e-14L,
|
||||
+2.411707924175380740802e-15L, -7.760751294610276598631e-17L,
|
||||
-6.701490147030045891595e-18L, +6.350145841254563572100e-19L,
|
||||
-2.034625734538917052251e-21L, -2.260543651146274653910e-21L,
|
||||
+9.782419961387425633151e-23L};
|
||||
|
||||
static const int degree = sizeof(c) / sizeof(long double) - 1;
|
||||
static const long double midpoint = (2.50L + 1.75L) / 2.0L;
|
||||
static const long double half_length = (2.50L - 1.75L) / 2.0;
|
||||
long double daw =
|
||||
xChebyshev_Tn_Series((fabsl(x) - midpoint) / half_length, c, degree);
|
||||
return (x > 0.0L) ? daw : -daw;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// static long double Dawson_Chebyshev_Expansion_250_325( long double x ) //
|
||||
// //
|
||||
// Description: //
|
||||
// Evaluate Dawsons integral for 2.5 <= |x| <= 3.25 using the Chebyshev //
|
||||
// expansion of Daw(x) for x in the interval [2.50,3.25]. //
|
||||
// //
|
||||
// Arguments: //
|
||||
// long double x The argument of Dawson's integral Daw(), where //
|
||||
// where 2.50 <= |x| <= 3.25. //
|
||||
// //
|
||||
// Return Value: //
|
||||
// The value of Dawson's integral, Daw(), evaluated at x where //
|
||||
// 2.50 <= x <= 3.25. //
|
||||
// //
|
||||
// Example: //
|
||||
// long double y, x; //
|
||||
// //
|
||||
// ( code to initialize x ) //
|
||||
// //
|
||||
// y = Dawson_Chebyshev_Expansion_250_325(x); //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static long double Dawson_Chebyshev_Expansion_250_325(long double x) {
|
||||
static long double c[] = {
|
||||
+1.901351274204578126827e-1L, -3.000575522193632460118e-2L,
|
||||
+2.672138524890489432579e-3L, -2.498237548675235150519e-4L,
|
||||
+2.013483163459701593271e-5L, -8.454663603108548182962e-7L,
|
||||
-8.036589636334016432368e-8L, +2.055498509671357933537e-8L,
|
||||
-2.052151324060186596995e-9L, +8.584315967075483822464e-11L,
|
||||
+5.062689357469596748991e-12L, -1.038671167196342609090e-12L,
|
||||
+6.367962851860231236238e-14L, +3.084688422647419767229e-16L,
|
||||
-3.417946142546575188490e-16L, +2.311567730100119302160e-17L,
|
||||
-6.170132546983726244716e-20L, -9.133176920944950460847e-20L,
|
||||
+5.712092431423316128728e-21L, +1.269641078369737220790e-23L,
|
||||
-2.072659711527711312699e-23L};
|
||||
|
||||
static const int degree = sizeof(c) / sizeof(long double) - 1;
|
||||
static const long double midpoint = (3.25L + 2.50L) / 2.0L;
|
||||
static const long double half_length = (3.25L - 2.50L) / 2.0L;
|
||||
long double daw =
|
||||
xChebyshev_Tn_Series((fabsl(x) - midpoint) / half_length, c, degree);
|
||||
return (x > 0.0L) ? daw : -daw;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// static long double Dawson_Chebyshev_Expansion_325_425( long double x ) //
|
||||
// //
|
||||
// Description: //
|
||||
// Evaluate Dawsons integral for 3.25 <= |x| <= 4.25 using the Chebyshev //
|
||||
// expansion of Daw(x) for x in the interval [3.25,4.75]. //
|
||||
// //
|
||||
// Arguments: //
|
||||
// long double x The argument of Dawson's integral Daw(), where //
|
||||
// where 3.25 <= |x| <= 4.25. //
|
||||
// //
|
||||
// Return Value: //
|
||||
// The value of Dawson's integral, Daw(), evaluated at x where //
|
||||
// 3.25 <= x <= 4.25. //
|
||||
// //
|
||||
// Example: //
|
||||
// long double y, x; //
|
||||
// //
|
||||
// ( code to initialize x ) //
|
||||
// //
|
||||
// y = Dawson_Chebyshev_Expansion_325_425(x); //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static long double Dawson_Chebyshev_Expansion_325_425(long double x) {
|
||||
static long double c[] = {
|
||||
+1.402884974484995678749e-1L, -2.053975371995937033959e-2L,
|
||||
+1.595388628922920119352e-3L, -1.336894584910985998203e-4L,
|
||||
+1.224903774178156286300e-5L, -1.206856028658387948773e-6L,
|
||||
+1.187997233269528945503e-7L, -1.012936061496824448259e-8L,
|
||||
+5.244408240062370605664e-10L, +2.901444759022254846562e-11L,
|
||||
-1.168987502493903926906e-11L, +1.640096995420504465839e-12L,
|
||||
-1.339190668554209618318e-13L, +3.643815972666851044790e-15L,
|
||||
+6.922486581126169160232e-16L, -1.158761251467106749752e-16L,
|
||||
+8.164320395639210093180e-18L, -5.397918405779863087588e-20L,
|
||||
-5.052069908100339242896e-20L, +5.322512674746973445361e-21L,
|
||||
-1.869294542789169825747e-22L};
|
||||
|
||||
static const int degree = sizeof(c) / sizeof(long double) - 1;
|
||||
// static const long double lower_bound = 3.25L;
|
||||
// static const long double upper_bound = 4.25L;
|
||||
static const long double midpoint = (4.25L + 3.25L) / 2.0L;
|
||||
static const long double half_length = (4.25L - 3.25L) / 2.0L;
|
||||
long double daw =
|
||||
xChebyshev_Tn_Series((fabsl(x) - midpoint) / half_length, c, degree);
|
||||
return (x > 0.0L) ? daw : -daw;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// static long double Dawson_Chebyshev_Expansion_425_550( long double x ) //
|
||||
// //
|
||||
// Description: //
|
||||
// Evaluate Dawsons integral for 4.25 <= |x| <= 5.50 using the Chebyshev //
|
||||
// expansion of Daw(x) for x in the interval [4.25,5.50]. //
|
||||
// //
|
||||
// Arguments: //
|
||||
// long double x The argument of Dawson's integral Daw(), where //
|
||||
// where 4.25 <= |x| <= 5.50. //
|
||||
// //
|
||||
// Return Value: //
|
||||
// The value of Dawson's integral, Daw(), evaluated at x where //
|
||||
// 4.25 <= x <= 5.50. //
|
||||
// //
|
||||
// Example: //
|
||||
// long double y, x; //
|
||||
// //
|
||||
// ( code to initialize x ) //
|
||||
// //
|
||||
// y = Dawson_Chebyshev_Expansion_425_550(x); //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static long double Dawson_Chebyshev_Expansion_425_550(long double x) {
|
||||
static long double c[] = {
|
||||
+1.058610209741581514157e-1L, -1.429297757627935191694e-2L,
|
||||
+9.911301703835545472874e-4L, -7.079903107876049846509e-5L,
|
||||
+5.229587914675267516134e-6L, -4.016071345964089296212e-7L,
|
||||
+3.231734714422926453741e-8L, -2.752870944370338482109e-9L,
|
||||
+2.503059741885009530630e-10L, -2.418699000594890423278e-11L,
|
||||
+2.410158905786160001792e-12L, -2.327254341132174000949e-13L,
|
||||
+1.958284411563056492727e-14L, -1.099893145048991004460e-15L,
|
||||
-2.959085292526991317697e-17L, +1.966366179276295203082e-17L,
|
||||
-3.314408783993662492621e-18L, +3.635520318133814622089e-19L,
|
||||
-2.550826919215104648800e-20L, +3.830090587178262542288e-22L,
|
||||
+1.836693763159216122739e-22L};
|
||||
|
||||
static const int degree = sizeof(c) / sizeof(long double) - 1;
|
||||
static const long double midpoint = (5.50L + 4.25L) / 2.0L;
|
||||
static const long double half_length = (5.50L - 4.25L) / 2.0L;
|
||||
long double daw =
|
||||
xChebyshev_Tn_Series((fabsl(x) - midpoint) / half_length, c, degree);
|
||||
return (x > 0.0L) ? daw : -daw;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// static long double Dawson_Chebyshev_Expansion_550_725( long double x ) //
|
||||
// //
|
||||
// Description: //
|
||||
// Evaluate Dawsons integral for 5.50 <= |x| <= 7.25 using the Chebyshev //
|
||||
// expansion of Daw(x) for x in the interval [5.50,7.25]. //
|
||||
// //
|
||||
// Arguments: //
|
||||
// long double x The argument of Dawson's integral Daw(), where //
|
||||
// where 5.50 <= |x| <= 7.25. //
|
||||
// //
|
||||
// Return Value: //
|
||||
// The value of Dawson's integral, Daw(), evaluated at x where //
|
||||
// 5.50 <= x <= 7.25. //
|
||||
// //
|
||||
// Example: //
|
||||
// long double y, x; //
|
||||
// //
|
||||
// ( code to initialize x ) //
|
||||
// //
|
||||
// y = Dawson_Chebyshev_Expansion_550_725(x); //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static long double Dawson_Chebyshev_Expansion_550_725(long double x) {
|
||||
static long double c[] = {+8.024637207807814739314e-2L,
|
||||
-1.136614891549306029413e-2L,
|
||||
+8.164249750628661856014e-4L,
|
||||
-5.951964778701328943018e-5L,
|
||||
+4.407349502747483429390e-6L,
|
||||
-3.317746826184531133862e-7L,
|
||||
+2.541483569880571680365e-8L,
|
||||
-1.983391157250772649001e-9L,
|
||||
+1.579050614491277335581e-10L,
|
||||
-1.284592098551537518322e-11L,
|
||||
+1.070070857004674207604e-12L,
|
||||
-9.151832297362522251950e-14L,
|
||||
+8.065447314948125338081e-15L,
|
||||
-7.360105847607056315915e-16L,
|
||||
+6.995966000187407197283e-17L,
|
||||
-6.964349343411584120055e-18L,
|
||||
+7.268789359189778223225e-19L,
|
||||
-7.885125241947769024019e-20L,
|
||||
+8.689022564130615225208e-21L,
|
||||
-9.353211304381231554634e-22L +
|
||||
9.218280404899298404756e-23L};
|
||||
|
||||
static const int degree = sizeof(c) / sizeof(long double) - 1;
|
||||
// static const long double lower_bound = 5.50L;
|
||||
// static const long double upper_bound = 7.25L;
|
||||
static const long double midpoint = (7.25L + 5.50L) / 2.0L;
|
||||
static const long double half_length = (7.25L - 5.50L) / 2.0L;
|
||||
long double daw =
|
||||
xChebyshev_Tn_Series((fabsl(x) - midpoint) / half_length, c, degree);
|
||||
return (x > 0.0L) ? daw : -daw;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// static long double Dawson_Asymptotic_Expansion( long double x ) //
|
||||
// //
|
||||
// Description: //
|
||||
// For a large magnitude of the argument x, Dawson's integral can be //
|
||||
// expressed as the asymptotic series //
|
||||
// Daw(x) ~ (1/2x) [ 1 + 1 / (2x^2) + ... + (2j - 1)!! / (2x^2)^j + ... ] //
|
||||
// //
|
||||
// Arguments: //
|
||||
// long double x The argument of Dawson's integral Daw(), where //
|
||||
// |x| > 7. //
|
||||
// //
|
||||
// Return Value: //
|
||||
// The value of Dawson's integral, Daw(), evaluated at x where |x| > 7. //
|
||||
// //
|
||||
// Example: //
|
||||
// long double y, x; //
|
||||
// //
|
||||
// ( code to initialize x ) //
|
||||
// //
|
||||
// y = Dawson_Asymptotic_Expansion( x ); //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
static long double Dawson_Asymptotic_Expansion(long double x) {
|
||||
long double term[Asymptotic_Expansion_Cutoff + 1];
|
||||
long double x2 = x * x;
|
||||
long double two_x = x + x;
|
||||
long double two_x2 = x2 + x2;
|
||||
long double xn = two_x2;
|
||||
long double Sn = 0.0L;
|
||||
long double factorial = 1.0L;
|
||||
int n;
|
||||
|
||||
term[0] = 1.0L;
|
||||
term[1] = 1.0L / xn;
|
||||
for (n = 2; n <= Asymptotic_Expansion_Cutoff; n++) {
|
||||
xn *= two_x2;
|
||||
factorial *= (long double)(n + n - 1);
|
||||
term[n] = factorial / xn;
|
||||
if (term[n] < LDBL_EPSILON / 2.0L)
|
||||
break;
|
||||
}
|
||||
|
||||
if (n > Asymptotic_Expansion_Cutoff)
|
||||
n = Asymptotic_Expansion_Cutoff;
|
||||
for (; n >= 0; n--)
|
||||
Sn += term[n];
|
||||
return Sn / two_x;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// File: xchebyshev_Tn_series.c //
|
||||
// Routine(s): //
|
||||
// xChebyshev_Tn_Series //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// long double xChebyshev_Tn_Series(long double x, long double a[],int degree)//
|
||||
// //
|
||||
// Description: //
|
||||
// This routine uses Clenshaw's recursion algorithm to evaluate a given //
|
||||
// polynomial p(x) expressed as a linear combination of Chebyshev //
|
||||
// polynomials of the first kind, Tn, at a point x, //
|
||||
// p(x) = a[0] + a[1]*T[1](x) + a[2]*T[2](x) + ... + a[deg]*T[deg](x). //
|
||||
// //
|
||||
// Clenshaw's recursion formula applied to Chebyshev polynomials of the //
|
||||
// first kind is: //
|
||||
// Set y[degree + 2] = 0, y[degree + 1] = 0, then for k = degree, ..., 1 //
|
||||
// set y[k] = 2 * x * y[k+1] - y[k+2] + a[k]. Finally //
|
||||
// set y[0] = x * y[1] - y[2] + a[0]. Then p(x) = y[0]. //
|
||||
// //
|
||||
// Arguments: //
|
||||
// long double x //
|
||||
// The point at which to evaluate the polynomial. //
|
||||
// long double a[] //
|
||||
// The coefficients of the expansion in terms of Chebyshev polynomials,//
|
||||
// i.e. a[k] is the coefficient of T[k](x). Note that in the calling //
|
||||
// routine a must be defined double a[N] where N >= degree + 1. //
|
||||
// int degree //
|
||||
// The degree of the polynomial p(x). //
|
||||
// //
|
||||
// Return Value: //
|
||||
// The value of the polynomial at x. //
|
||||
// If degree is negative, then 0.0 is returned. //
|
||||
// //
|
||||
// Example: //
|
||||
// long double x, a[N], p; //
|
||||
// int deg = N - 1; //
|
||||
// //
|
||||
// ( code to initialize x, and a[i] i = 0, ... , a[deg] ) //
|
||||
// //
|
||||
// p = xChebyshev_Tn_Series(x, a, deg); //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static long double xChebyshev_Tn_Series(long double x, long double a[],
|
||||
int degree) {
|
||||
long double yp2 = 0.0L;
|
||||
long double yp1 = 0.0L;
|
||||
long double y = 0.0L;
|
||||
long double two_x = x + x;
|
||||
int k;
|
||||
|
||||
// Check that degree >= 0. If not, then return 0. //
|
||||
|
||||
if (degree < 0)
|
||||
return 0.0L;
|
||||
|
||||
// Apply Clenshaw's recursion save the last iteration. //
|
||||
|
||||
for (k = degree; k >= 1; k--, yp2 = yp1, yp1 = y)
|
||||
y = two_x * yp1 - yp2 + a[k];
|
||||
|
||||
// Now apply the last iteration and return the result. //
|
||||
|
||||
return x * yp1 - yp2 + a[0];
|
||||
}
|
||||
10169
src/grpp/grpp_specfunc_fermi_sk.c
Normal file
10169
src/grpp/grpp_specfunc_fermi_sk.c
Normal file
File diff suppressed because it is too large
Load diff
94
src/grpp/grpp_specfunc_gfun.c
Normal file
94
src/grpp/grpp_specfunc_gfun.c
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
/*----------------------------------------------------------------------------*/
|
||||
/* CP2K: A general program to perform molecular dynamics simulations */
|
||||
/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
|
||||
/* */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* libgrpp - a library for the evaluation of integrals over
|
||||
* generalized relativistic pseudopotentials.
|
||||
*
|
||||
* Copyright (C) 2021-2023 Alexander Oleynichenko
|
||||
*/
|
||||
|
||||
/*
|
||||
* Implementation of the Gn(x) auxiliary function.
|
||||
* This function is required to calculate integrals over the 1/r^2 operator.
|
||||
*
|
||||
* More on the Gn(x) function evaluation:
|
||||
* (1) J. 0. Jensen, A. H. Cameri, C. P. Vlahacos, D. Zeroka, H. F. Hameka, C.
|
||||
* N. Merrow, Evaluation of one-electron integrals for arbitrary operators V(r)
|
||||
* over cartesian Gaussians: Application to inverse-square distance and Yukawa
|
||||
* operators. J. Comput. Chem. 14(8), 986 (1993). doi: 10.1002/jcc.540140814 (2)
|
||||
* B. Gao, A. J. Thorvaldsen, K. Ruud, GEN1INT: A unified procedure for the
|
||||
* evaluation of one-electron integrals over Gaussian basis functions and their
|
||||
* geometric derivatives. Int. J. Quantum Chem. 111(4), 858 (2011).
|
||||
* doi: 10.1002/qua.22886
|
||||
*/
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.1415926535897932384626433
|
||||
#endif
|
||||
|
||||
#include "grpp_factorial.h"
|
||||
#include "grpp_specfunc.h"
|
||||
|
||||
static double gfun_taylor(int n, double x);
|
||||
|
||||
/**
|
||||
* Calculates values of the Gn(x) auxiliary function for n = 0, ..., nmax
|
||||
* and stores them into the g[] array.
|
||||
*/
|
||||
void libgrpp_gfun_values(double x, int nmax, double *g) {
|
||||
memset(g, 0, (nmax + 1) * sizeof(double));
|
||||
|
||||
if (x <= 12.0) {
|
||||
/*
|
||||
* downward recursion
|
||||
*/
|
||||
g[nmax] = gfun_taylor(nmax, x);
|
||||
|
||||
for (int n = nmax; n > 0; n--) {
|
||||
g[n - 1] = (1.0 - 2.0 * x * g[n]) / (2.0 * n - 1.0);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* upward recursion
|
||||
*/
|
||||
double sqrt_x = sqrt(x);
|
||||
g[0] = libgrpp_Dawsons_Integral(sqrt_x) / sqrt_x;
|
||||
|
||||
for (int n = 0; n < nmax; n++) {
|
||||
g[n + 1] = (1.0 - (2 * n + 1) * g[n]) / (2.0 * x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates value of the Gn(x) auxiliary function using the Taylor expansion.
|
||||
* The Taylor series converges for x <= 30.
|
||||
*/
|
||||
static double gfun_taylor(int n, double x) {
|
||||
const double thresh = 1e-15;
|
||||
double sum = 0.0;
|
||||
|
||||
for (int k = 0; k < 100; k++) {
|
||||
|
||||
double y_exp = exp(-x);
|
||||
double y_pow = pow(x, k);
|
||||
double y_fac = libgrpp_factorial(k);
|
||||
double y_nk1 = 2.0 * n + 2.0 * k + 1.0;
|
||||
|
||||
double contrib = y_exp * y_pow / y_fac / y_nk1;
|
||||
sum += contrib;
|
||||
|
||||
if (fabs(contrib) < thresh) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
1095
src/grpp/grpp_specfunc_scaled_mod_sph_bessel.c
Normal file
1095
src/grpp/grpp_specfunc_scaled_mod_sph_bessel.c
Normal file
File diff suppressed because it is too large
Load diff
304
src/grpp/grpp_spherical_harmonics.c
Normal file
304
src/grpp/grpp_spherical_harmonics.c
Normal file
|
|
@ -0,0 +1,304 @@
|
|||
/*----------------------------------------------------------------------------*/
|
||||
/* CP2K: A general program to perform molecular dynamics simulations */
|
||||
/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
|
||||
/* */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* libgrpp - a library for the evaluation of integrals over
|
||||
* generalized relativistic pseudopotentials.
|
||||
*
|
||||
* Copyright (C) 2021-2023 Alexander Oleynichenko
|
||||
*/
|
||||
|
||||
/*
|
||||
* Constructs tables with the expansion coefficients of real spherical harmonics
|
||||
* in the basis of (cartesian) unitary spherical polynomials.
|
||||
*
|
||||
* For more details about the algorithm used, see:
|
||||
* R. Flores-Moreno et al, J. Comput. Chem. 27, 1009 (2006),
|
||||
* doi: 10.1002/jcc.20410
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.1415926535897932384626433
|
||||
#endif
|
||||
|
||||
#ifndef M_SQRT1_2
|
||||
#define M_SQRT1_2 0.70710678118654752440
|
||||
#endif
|
||||
|
||||
#include "grpp_binomial.h"
|
||||
#include "grpp_factorial.h"
|
||||
#include "grpp_spherical_harmonics.h"
|
||||
#include "libgrpp.h"
|
||||
/*
|
||||
* Tables with pretabulated expansion coefficients
|
||||
*/
|
||||
|
||||
static rsh_coef_table_t **rsh_coef_tables = NULL;
|
||||
static int rsh_tables_lmax = -1;
|
||||
|
||||
/*
|
||||
* Function pre-definitions
|
||||
*/
|
||||
rsh_coef_table_t *libgrpp_tabulate_real_spherical_harmonic_coeffs(int L);
|
||||
|
||||
static int *generate_cartesian_combinations(int L, int *num);
|
||||
|
||||
/**
|
||||
* Constructs the set of tables with C_{l,m}^{lx,ly,lz} coefficients
|
||||
* (up to maximum angular momentum Lmax).
|
||||
* (pretabulation step)
|
||||
*/
|
||||
void libgrpp_create_real_spherical_harmonic_coeffs_tables(int Lmax) {
|
||||
if (Lmax <= rsh_tables_lmax) {
|
||||
// nothing to do
|
||||
} else {
|
||||
// expand tables: realloc memory and add tables for the highest L values
|
||||
rsh_coef_tables = (rsh_coef_table_t **)realloc(
|
||||
rsh_coef_tables, (Lmax + 1) * sizeof(rsh_coef_table_t *));
|
||||
|
||||
for (int L = rsh_tables_lmax + 1; L <= Lmax; L++) {
|
||||
rsh_coef_tables[L] = libgrpp_tabulate_real_spherical_harmonic_coeffs(L);
|
||||
}
|
||||
rsh_tables_lmax = Lmax;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates all C_{l,m}^{lx,ly,lz} coefficients for the given angular momentum
|
||||
* L.
|
||||
*/
|
||||
rsh_coef_table_t *libgrpp_tabulate_real_spherical_harmonic_coeffs(int L) {
|
||||
int ncart = (L + 1) * (L + 2) / 2;
|
||||
|
||||
rsh_coef_table_t *coef_table =
|
||||
(rsh_coef_table_t *)calloc(1, sizeof(rsh_coef_table_t));
|
||||
coef_table->n_cart_comb = ncart;
|
||||
coef_table->cartesian_comb = generate_cartesian_combinations(L, &ncart);
|
||||
coef_table->coeffs = (double *)calloc((2 * L + 1) * ncart, sizeof(double));
|
||||
|
||||
for (int m = -L; m <= L; m++) {
|
||||
for (int icomb = 0; icomb < ncart; icomb++) {
|
||||
int lx = coef_table->cartesian_comb[3 * icomb];
|
||||
int ly = coef_table->cartesian_comb[3 * icomb + 1];
|
||||
// int lz = coef_table->cartesian_comb[3 * icomb + 2];
|
||||
double u_lm_lx_ly_lz = libgrpp_spherical_to_cartesian_coef(L, m, lx, ly);
|
||||
int index = (m + L) * ncart + icomb;
|
||||
coef_table->coeffs[index] = u_lm_lx_ly_lz;
|
||||
}
|
||||
}
|
||||
|
||||
return coef_table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Access to the table for the angular momentum value L.
|
||||
*/
|
||||
rsh_coef_table_t *libgrpp_get_real_spherical_harmonic_table(int L) {
|
||||
if (L > rsh_tables_lmax) {
|
||||
printf("get_real_spherical_harmonic_table(): %d > Lmax\n", L);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return rsh_coef_tables[L];
|
||||
}
|
||||
|
||||
/**
|
||||
* For the given real spherical harmonic (RSH) S_lm calculates the coefficient
|
||||
* C_{l,m}^{lx,ly,lz} before the unitary spherical polynomial (USP) in its
|
||||
* expansion.
|
||||
*
|
||||
* The formula is taken from:
|
||||
* R. Flores-Moreno et al, J. Comput. Chem. 27, 1009 (2006)
|
||||
* doi: 10.1002/jcc.20410
|
||||
* (formula 32)
|
||||
*/
|
||||
double libgrpp_spherical_to_cartesian_coef(int l, int m, int lx, int ly) {
|
||||
int j = lx + ly - abs(m);
|
||||
if (j % 2 != 0) {
|
||||
return 0.0;
|
||||
}
|
||||
j /= 2;
|
||||
|
||||
if (!((m > 0 && (abs(m) - lx) % 2 == 0) || (m == 0 && lx % 2 == 0) ||
|
||||
(m < 0 && (abs(m) - lx) % 2 != 0))) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
double prefactor =
|
||||
sqrt((2 * l + 1) / (2 * M_PI) * libgrpp_factorial(l - abs(m)) /
|
||||
libgrpp_factorial(l + abs(m)));
|
||||
prefactor /= pow(2, l) * libgrpp_factorial(l);
|
||||
|
||||
double u_lm_lx_ly_lz = 0.0;
|
||||
for (int i = j; i <= (l - abs(m)) / 2; i++) {
|
||||
// any term that implies the factorial of a negative number is neglected
|
||||
if (2 * l - 2 * i < 0) {
|
||||
u_lm_lx_ly_lz = 0.0;
|
||||
break;
|
||||
}
|
||||
if (l - abs(m) - 2 * i < 0) {
|
||||
u_lm_lx_ly_lz = 0.0;
|
||||
break;
|
||||
}
|
||||
|
||||
double factor_1 =
|
||||
libgrpp_binomial(l, i) * libgrpp_binomial(i, j) * pow(-1, i) *
|
||||
libgrpp_factorial_ratio(2 * l - 2 * i, l - abs(m) - 2 * i);
|
||||
|
||||
double sum = 0.0;
|
||||
for (int k = 0; k <= j; k++) {
|
||||
sum += libgrpp_binomial(j, k) * libgrpp_binomial(abs(m), lx - 2 * k) *
|
||||
pow(-1, (abs(m) - lx + 2 * k) / 2);
|
||||
}
|
||||
|
||||
u_lm_lx_ly_lz += factor_1 * sum;
|
||||
}
|
||||
|
||||
u_lm_lx_ly_lz *= prefactor;
|
||||
if (m == 0 && (lx % 2 == 0)) {
|
||||
u_lm_lx_ly_lz *= M_SQRT1_2; // x 1/sqrt(2)
|
||||
}
|
||||
|
||||
return u_lm_lx_ly_lz;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates value of the real spherical harmonic S_lm at the point k/|k| of
|
||||
* the unit sphere.
|
||||
*/
|
||||
double libgrpp_evaluate_real_spherical_harmonic(const int l, const int m,
|
||||
const double *k) {
|
||||
double unitary_kx;
|
||||
double unitary_ky;
|
||||
double unitary_kz;
|
||||
double kx_powers[200];
|
||||
double ky_powers[200];
|
||||
double kz_powers[200];
|
||||
|
||||
rsh_coef_table_t *rsh_coef_l = libgrpp_get_real_spherical_harmonic_table(l);
|
||||
|
||||
double length_k = sqrt(k[0] * k[0] + k[1] * k[1] + k[2] * k[2]);
|
||||
|
||||
if (length_k > LIBGRPP_ZERO_THRESH) {
|
||||
unitary_kx = k[0] / length_k;
|
||||
unitary_ky = k[1] / length_k;
|
||||
unitary_kz = k[2] / length_k;
|
||||
} else {
|
||||
unitary_kx = 0.0;
|
||||
unitary_ky = 0.0;
|
||||
unitary_kz = 0.0;
|
||||
}
|
||||
|
||||
kx_powers[0] = 1.0;
|
||||
ky_powers[0] = 1.0;
|
||||
kz_powers[0] = 1.0;
|
||||
|
||||
for (int i = 1; i <= l; i++) {
|
||||
kx_powers[i] = kx_powers[i - 1] * unitary_kx;
|
||||
ky_powers[i] = ky_powers[i - 1] * unitary_ky;
|
||||
kz_powers[i] = kz_powers[i - 1] * unitary_kz;
|
||||
}
|
||||
|
||||
double value = 0.0;
|
||||
|
||||
int ncart = rsh_coef_l->n_cart_comb;
|
||||
for (int icomb = 0; icomb < ncart; icomb++) {
|
||||
int r = rsh_coef_l->cartesian_comb[3 * icomb];
|
||||
int s = rsh_coef_l->cartesian_comb[3 * icomb + 1];
|
||||
int t = rsh_coef_l->cartesian_comb[3 * icomb + 2];
|
||||
double y_lm_rst = rsh_coef_l->coeffs[(m + l) * ncart + icomb];
|
||||
|
||||
value += y_lm_rst * kx_powers[r] * ky_powers[s] * kz_powers[t];
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates values of the real spherical harmonic S_lm at the point k/|k| of
|
||||
* the unit sphere for all m = -l, ..., +l
|
||||
*/
|
||||
void libgrpp_evaluate_real_spherical_harmonics_array(const int l,
|
||||
const double *k,
|
||||
double *rsh_array) {
|
||||
double unitary_kx;
|
||||
double unitary_ky;
|
||||
double unitary_kz;
|
||||
double kx_powers[200];
|
||||
double ky_powers[200];
|
||||
double kz_powers[200];
|
||||
|
||||
rsh_coef_table_t *rsh_coef_l = libgrpp_get_real_spherical_harmonic_table(l);
|
||||
|
||||
double length_k = sqrt(k[0] * k[0] + k[1] * k[1] + k[2] * k[2]);
|
||||
|
||||
if (length_k > LIBGRPP_ZERO_THRESH) {
|
||||
double inv_length = 1.0 / length_k;
|
||||
unitary_kx = k[0] * inv_length;
|
||||
unitary_ky = k[1] * inv_length;
|
||||
unitary_kz = k[2] * inv_length;
|
||||
} else {
|
||||
unitary_kx = 0.0;
|
||||
unitary_ky = 0.0;
|
||||
unitary_kz = 0.0;
|
||||
}
|
||||
|
||||
kx_powers[0] = 1.0;
|
||||
ky_powers[0] = 1.0;
|
||||
kz_powers[0] = 1.0;
|
||||
|
||||
for (int i = 1; i <= l; i++) {
|
||||
kx_powers[i] = kx_powers[i - 1] * unitary_kx;
|
||||
ky_powers[i] = ky_powers[i - 1] * unitary_ky;
|
||||
kz_powers[i] = kz_powers[i - 1] * unitary_kz;
|
||||
}
|
||||
|
||||
memset(rsh_array, 0, (2 * l + 1) * sizeof(double));
|
||||
|
||||
int ncart = rsh_coef_l->n_cart_comb;
|
||||
int *rst_array = rsh_coef_l->cartesian_comb;
|
||||
|
||||
for (int icomb = 0; icomb < ncart; icomb++) {
|
||||
int r = rst_array[3 * icomb];
|
||||
int s = rst_array[3 * icomb + 1];
|
||||
int t = rst_array[3 * icomb + 2];
|
||||
|
||||
double k_xyz = kx_powers[r] * ky_powers[s] * kz_powers[t];
|
||||
|
||||
for (int m = -l; m <= l; m++) {
|
||||
double y_lm_rst = rsh_coef_l->coeffs[(m + l) * ncart + icomb];
|
||||
rsh_array[m + l] += y_lm_rst * k_xyz;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int *generate_cartesian_combinations(int L, int *num) {
|
||||
*num = (L + 1) * (L + 2) / 2;
|
||||
|
||||
int *combinations = (int *)calloc(*num, 3 * sizeof(int));
|
||||
|
||||
int n = 0;
|
||||
for (int i = 0; i <= L; i++) {
|
||||
for (int j = 0; j <= L; j++) {
|
||||
for (int k = 0; k <= L; k++) {
|
||||
if (i + j + k == L) {
|
||||
combinations[3 * n + 0] = i;
|
||||
combinations[3 * n + 1] = j;
|
||||
combinations[3 * n + 2] = k;
|
||||
n++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return combinations;
|
||||
}
|
||||
39
src/grpp/grpp_spherical_harmonics.h
Normal file
39
src/grpp/grpp_spherical_harmonics.h
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/*----------------------------------------------------------------------------*/
|
||||
/* CP2K: A general program to perform molecular dynamics simulations */
|
||||
/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
|
||||
/* */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* libgrpp - a library for the evaluation of integrals over
|
||||
* generalized relativistic pseudopotentials.
|
||||
*
|
||||
* Copyright (C) 2021-2023 Alexander Oleynichenko
|
||||
*/
|
||||
|
||||
#ifndef LIBGRPP_SPHERICAL_HARMONICS_H
|
||||
#define LIBGRPP_SPHERICAL_HARMONICS_H
|
||||
|
||||
/*
|
||||
* Tables with pretabulated expansion coefficients
|
||||
*/
|
||||
typedef struct {
|
||||
int L;
|
||||
int n_cart_comb;
|
||||
int *cartesian_comb;
|
||||
double *coeffs;
|
||||
} rsh_coef_table_t;
|
||||
|
||||
double libgrpp_spherical_to_cartesian_coef(int l, int m, int lx, int ly);
|
||||
|
||||
double libgrpp_evaluate_real_spherical_harmonic(int l, int m, const double *k);
|
||||
|
||||
void libgrpp_evaluate_real_spherical_harmonics_array(int l, const double *k,
|
||||
double *rsh_array);
|
||||
|
||||
void libgrpp_create_real_spherical_harmonic_coeffs_tables(int Lmax);
|
||||
|
||||
rsh_coef_table_t *libgrpp_get_real_spherical_harmonic_table(int L);
|
||||
|
||||
#endif // LIBGRPP_SPHERICAL_HARMONICS_H
|
||||
302
src/grpp/grpp_spin_orbit_integrals.c
Normal file
302
src/grpp/grpp_spin_orbit_integrals.c
Normal file
|
|
@ -0,0 +1,302 @@
|
|||
/*----------------------------------------------------------------------------*/
|
||||
/* CP2K: A general program to perform molecular dynamics simulations */
|
||||
/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
|
||||
/* */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* libgrpp - a library for the evaluation of integrals over
|
||||
* generalized relativistic pseudopotentials.
|
||||
*
|
||||
* Copyright (C) 2021-2023 Alexander Oleynichenko
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
#include "grpp_angular_integrals.h"
|
||||
#include "grpp_binomial.h"
|
||||
#include "grpp_lmatrix.h"
|
||||
#include "grpp_radial_type2_integral.h"
|
||||
#include "grpp_spherical_harmonics.h"
|
||||
#include "grpp_utils.h"
|
||||
#include "libgrpp.h"
|
||||
|
||||
#define LMAX (2 * LIBGRPP_MAX_BASIS_L + LIBGRPP_MAX_RPP_L)
|
||||
|
||||
static void type3_angular_sum(int L, double *Lx_matrix, double *Ly_matrix,
|
||||
double *Lz_matrix, int lambda_1, int a, int b,
|
||||
int c, double *rsh_values_kA, int lambda_2, int d,
|
||||
int e, int f, double *rsh_values_kB,
|
||||
double *sum_angular_x, double *sum_angular_y,
|
||||
double *sum_angular_z);
|
||||
|
||||
/**
|
||||
* Evaluation of spin-orbit ("type 3") RPP integrals.
|
||||
*
|
||||
* The theoretical outline is given in the paper:
|
||||
* R. M. Pitzer, N. W. Winter. Spin-orbit (core) and core potential integrals.
|
||||
* Int. J. Quantum Chem. 40(6), 773 (1991). doi: 10.1002/qua.560400606
|
||||
* However, the formula on page 776 of Pitzer & Winter is not reproduced in the
|
||||
* code exactly.
|
||||
*/
|
||||
void libgrpp_spin_orbit_integrals(libgrpp_shell_t *shell_A,
|
||||
libgrpp_shell_t *shell_B, double *rpp_origin,
|
||||
libgrpp_potential_t *potential,
|
||||
double *so_x_matrix, double *so_y_matrix,
|
||||
double *so_z_matrix) {
|
||||
assert(libgrpp_is_initialized());
|
||||
|
||||
int size_A = libgrpp_get_shell_size(shell_A);
|
||||
int size_B = libgrpp_get_shell_size(shell_B);
|
||||
|
||||
memset(so_x_matrix, 0, size_A * size_B * sizeof(double));
|
||||
memset(so_y_matrix, 0, size_A * size_B * sizeof(double));
|
||||
memset(so_z_matrix, 0, size_A * size_B * sizeof(double));
|
||||
|
||||
int L = potential->L;
|
||||
int L_A =
|
||||
shell_A->cart_list[0] + shell_A->cart_list[1] + shell_A->cart_list[2];
|
||||
int L_B =
|
||||
shell_B->cart_list[0] + shell_B->cart_list[1] + shell_B->cart_list[2];
|
||||
|
||||
double *A = shell_A->origin;
|
||||
double *B = shell_B->origin;
|
||||
double *C = rpp_origin;
|
||||
|
||||
double CA_x = C[0] - A[0];
|
||||
double CA_y = C[1] - A[1];
|
||||
double CA_z = C[2] - A[2];
|
||||
double CB_x = C[0] - B[0];
|
||||
double CB_y = C[1] - B[1];
|
||||
double CB_z = C[2] - B[2];
|
||||
double CA_2 = CA_x * CA_x + CA_y * CA_y + CA_z * CA_z;
|
||||
double CB_2 = CB_x * CB_x + CB_y * CB_y + CB_z * CB_z;
|
||||
|
||||
double alpha_A = shell_A->alpha[0];
|
||||
double alpha_B = shell_B->alpha[0];
|
||||
double kA_x = -2.0 * (alpha_A * CA_x);
|
||||
double kA_y = -2.0 * (alpha_A * CA_y);
|
||||
double kA_z = -2.0 * (alpha_A * CA_z);
|
||||
double kB_x = -2.0 * (alpha_B * CB_x);
|
||||
double kB_y = -2.0 * (alpha_B * CB_y);
|
||||
double kB_z = -2.0 * (alpha_B * CB_z);
|
||||
double kA_vec[3];
|
||||
kA_vec[0] = kA_x;
|
||||
kA_vec[1] = kA_y;
|
||||
kA_vec[2] = kA_z;
|
||||
double kB_vec[3];
|
||||
kB_vec[0] = kB_x;
|
||||
kB_vec[1] = kB_y;
|
||||
kB_vec[2] = kB_z;
|
||||
|
||||
int lambda1_max = L + L_A;
|
||||
int lambda2_max = L + L_B;
|
||||
int N_max = L_A + L_B; // + n_RPP;
|
||||
|
||||
/*
|
||||
* pre-compute matrices of the Lx, Ly, Lz operators
|
||||
*/
|
||||
double *Lx_matrix = calloc((2 * L + 1) * (2 * L + 1), sizeof(double));
|
||||
double *Ly_matrix = calloc((2 * L + 1) * (2 * L + 1), sizeof(double));
|
||||
double *Lz_matrix = calloc((2 * L + 1) * (2 * L + 1), sizeof(double));
|
||||
libgrpp_construct_angular_momentum_matrices_rsh(L, Lx_matrix, Ly_matrix,
|
||||
Lz_matrix);
|
||||
|
||||
/*
|
||||
* for further evaluation of angular integrals
|
||||
*/
|
||||
int lmax = int_max3(lambda1_max, lambda2_max, L);
|
||||
// create_real_spherical_harmonic_coeffs_tables(lmax);
|
||||
|
||||
/*
|
||||
* pre-calculate values of real spherical harmonics for different L
|
||||
*/
|
||||
double rsh_values_kA[LMAX][2 * LMAX + 1];
|
||||
double rsh_values_kB[LMAX][2 * LMAX + 1];
|
||||
|
||||
for (int lambda = 0; lambda <= lmax; lambda++) {
|
||||
libgrpp_evaluate_real_spherical_harmonics_array(lambda, kA_vec,
|
||||
rsh_values_kA[lambda]);
|
||||
libgrpp_evaluate_real_spherical_harmonics_array(lambda, kB_vec,
|
||||
rsh_values_kB[lambda]);
|
||||
}
|
||||
|
||||
/*
|
||||
* pre-compute radial integrals
|
||||
*/
|
||||
radial_type2_table_t *radial_table = libgrpp_tabulate_radial_type2_integrals(
|
||||
lambda1_max, lambda2_max, N_max, CA_2, CB_2, potential, shell_A, shell_B);
|
||||
|
||||
/*
|
||||
* loop over shell pairs
|
||||
*/
|
||||
for (int icart = 0; icart < size_A; icart++) {
|
||||
for (int jcart = 0; jcart < size_B; jcart++) {
|
||||
|
||||
double SO_x = 0.0;
|
||||
double SO_y = 0.0;
|
||||
double SO_z = 0.0;
|
||||
|
||||
int n_A = shell_A->cart_list[3 * icart + 0];
|
||||
int l_A = shell_A->cart_list[3 * icart + 1];
|
||||
int m_A = shell_A->cart_list[3 * icart + 2];
|
||||
int n_B = shell_B->cart_list[3 * jcart + 0];
|
||||
int l_B = shell_B->cart_list[3 * jcart + 1];
|
||||
int m_B = shell_B->cart_list[3 * jcart + 2];
|
||||
|
||||
for (int a = 0; a <= n_A; a++) {
|
||||
|
||||
double C_nA_a = libgrpp_binomial(n_A, a);
|
||||
double pow_CA_x = pow(CA_x, n_A - a);
|
||||
|
||||
for (int b = 0; b <= l_A; b++) {
|
||||
|
||||
double C_lA_b = libgrpp_binomial(l_A, b);
|
||||
double pow_CA_y = pow(CA_y, l_A - b);
|
||||
|
||||
for (int c = 0; c <= m_A; c++) {
|
||||
|
||||
double C_mA_c = libgrpp_binomial(m_A, c);
|
||||
double pow_CA_z = pow(CA_z, m_A - c);
|
||||
|
||||
for (int d = 0; d <= n_B; d++) {
|
||||
|
||||
double C_nB_d = libgrpp_binomial(n_B, d);
|
||||
double pow_CB_x = pow(CB_x, n_B - d);
|
||||
|
||||
for (int e = 0; e <= l_B; e++) {
|
||||
|
||||
double C_lB_e = libgrpp_binomial(l_B, e);
|
||||
double pow_CB_y = pow(CB_y, l_B - e);
|
||||
|
||||
for (int f = 0; f <= m_B; f++) {
|
||||
|
||||
double C_mB_f = libgrpp_binomial(m_B, f);
|
||||
double pow_CB_z = pow(CB_z, m_B - f);
|
||||
|
||||
int N = a + b + c + d + e + f;
|
||||
double factor = C_nA_a * C_lA_b * C_mA_c * C_nB_d * C_lB_e *
|
||||
C_mB_f * pow_CA_x * pow_CA_y * pow_CA_z *
|
||||
pow_CB_x * pow_CB_y * pow_CB_z;
|
||||
|
||||
if (fabs(factor) < LIBGRPP_ZERO_THRESH) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* contraction of radial integrals with angular integrals
|
||||
*/
|
||||
|
||||
double sum_omega_Q_x = 0.0;
|
||||
double sum_omega_Q_y = 0.0;
|
||||
double sum_omega_Q_z = 0.0;
|
||||
|
||||
int lambda1_lower = int_max2(L - a - b - c, 0);
|
||||
int lambda2_lower = int_max2(L - d - e - f, 0);
|
||||
int lambda1_upper = L + a + b + c;
|
||||
int lambda2_upper = L + d + e + f;
|
||||
|
||||
for (int lambda_1 = lambda1_lower; lambda_1 <= lambda1_upper;
|
||||
lambda_1++) {
|
||||
if ((L + a + b + c - lambda_1) % 2 != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int lambda_2 = lambda2_lower;
|
||||
lambda_2 <= lambda2_upper; lambda_2++) {
|
||||
if ((L + d + e + f - lambda_2) % 2 != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
double QN = libgrpp_get_radial_type2_integral(
|
||||
radial_table, lambda_1, lambda_2, N);
|
||||
if (fabs(QN) < LIBGRPP_ZERO_THRESH) {
|
||||
continue;
|
||||
}
|
||||
|
||||
double sum_angular_x, sum_angular_y, sum_angular_z;
|
||||
type3_angular_sum(
|
||||
L, Lx_matrix, Ly_matrix, Lz_matrix, lambda_1, a, b, c,
|
||||
rsh_values_kA[lambda_1], lambda_2, d, e, f,
|
||||
rsh_values_kB[lambda_2], &sum_angular_x,
|
||||
&sum_angular_y, &sum_angular_z);
|
||||
|
||||
sum_omega_Q_x += QN * sum_angular_x;
|
||||
sum_omega_Q_y += QN * sum_angular_y;
|
||||
sum_omega_Q_z += QN * sum_angular_z;
|
||||
}
|
||||
}
|
||||
|
||||
SO_x += factor * sum_omega_Q_x;
|
||||
SO_y += factor * sum_omega_Q_y;
|
||||
SO_z += factor * sum_omega_Q_z;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
so_x_matrix[icart * size_B + jcart] = SO_x * (16.0 * M_PI * M_PI);
|
||||
so_y_matrix[icart * size_B + jcart] = SO_y * (16.0 * M_PI * M_PI);
|
||||
so_z_matrix[icart * size_B + jcart] = SO_z * (16.0 * M_PI * M_PI);
|
||||
}
|
||||
}
|
||||
|
||||
libgrpp_delete_radial_type2_integrals(radial_table);
|
||||
free(Lx_matrix);
|
||||
free(Ly_matrix);
|
||||
free(Lz_matrix);
|
||||
}
|
||||
|
||||
/*
|
||||
* Double sum of products of type 2 angular integrals
|
||||
* (Pitzer, Winter, 1991, formula on the top of the page 776)
|
||||
*/
|
||||
static void type3_angular_sum(int L, double *Lx_matrix, double *Ly_matrix,
|
||||
double *Lz_matrix, int lambda_1, int a, int b,
|
||||
int c, double *rsh_values_kA, int lambda_2, int d,
|
||||
int e, int f, double *rsh_values_kB,
|
||||
double *sum_angular_x, double *sum_angular_y,
|
||||
double *sum_angular_z) {
|
||||
*sum_angular_x = 0.0;
|
||||
*sum_angular_y = 0.0;
|
||||
*sum_angular_z = 0.0;
|
||||
|
||||
/*
|
||||
* contract tensors with angular integrals
|
||||
*/
|
||||
for (int m1 = -L; m1 <= L; m1++) {
|
||||
for (int m2 = -L; m2 <= L; m2++) {
|
||||
|
||||
double lx = Lx_matrix[(2 * L + 1) * (m1 + L) + (m2 + L)];
|
||||
double ly = Ly_matrix[(2 * L + 1) * (m1 + L) + (m2 + L)];
|
||||
double lz = Lz_matrix[(2 * L + 1) * (m1 + L) + (m2 + L)];
|
||||
if (fabs(lx) < LIBGRPP_ZERO_THRESH && fabs(ly) < LIBGRPP_ZERO_THRESH &&
|
||||
fabs(lz) < LIBGRPP_ZERO_THRESH) {
|
||||
continue;
|
||||
}
|
||||
|
||||
double omega_1 = libgrpp_angular_type2_integral(lambda_1, L, m1, a, b, c,
|
||||
rsh_values_kA);
|
||||
if (fabs(omega_1) < LIBGRPP_ZERO_THRESH) {
|
||||
continue;
|
||||
}
|
||||
|
||||
double omega_2 = libgrpp_angular_type2_integral(lambda_2, L, m2, d, e, f,
|
||||
rsh_values_kB);
|
||||
|
||||
*sum_angular_x += omega_1 * omega_2 * lx;
|
||||
*sum_angular_y += omega_1 * omega_2 * ly;
|
||||
*sum_angular_z += omega_1 * omega_2 * lz;
|
||||
}
|
||||
}
|
||||
}
|
||||
261
src/grpp/grpp_type1_integrals.c
Normal file
261
src/grpp/grpp_type1_integrals.c
Normal file
|
|
@ -0,0 +1,261 @@
|
|||
/*----------------------------------------------------------------------------*/
|
||||
/* CP2K: A general program to perform molecular dynamics simulations */
|
||||
/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
|
||||
/* */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* libgrpp - a library for the evaluation of integrals over
|
||||
* generalized relativistic pseudopotentials.
|
||||
*
|
||||
* Copyright (C) 2021-2023 Alexander Oleynichenko
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
#include "grpp_angular_integrals.h"
|
||||
#include "grpp_binomial.h"
|
||||
#include "grpp_norm_gaussian.h"
|
||||
#include "grpp_radial_type1_integral.h"
|
||||
#include "grpp_type1_mcmurchie_davidson.h"
|
||||
#include "grpp_utils.h"
|
||||
#include "libgrpp.h"
|
||||
#include "libgrpp_types.h"
|
||||
/* for the old (numerical) version:
|
||||
void evaluate_type1_integral_primitive_gaussians(double *A, int n_cart_A, int
|
||||
*cart_list_A, double alpha_A, double *B, int n_cart_B, int *cart_list_B, double
|
||||
alpha_B, double *C, libgrpp_potential_t *potential, double *matrix);
|
||||
*/
|
||||
|
||||
extern void libgrpp_delete_radial_type1_integrals(radial_type1_table_t *table);
|
||||
|
||||
void libgrpp_evaluate_radially_local_potential_integral_primitive_gaussians(
|
||||
double *A, int n_cart_A, int *cart_list_A, double alpha_A, double *B,
|
||||
int n_cart_B, int *cart_list_B, double alpha_B, double *C,
|
||||
double (*potential)(double r, void *params), void *potential_params,
|
||||
double *matrix);
|
||||
|
||||
static double evaluate_pseudopotential(double r, void *params);
|
||||
|
||||
/**
|
||||
* Evaluation of type 1 RPP integrals (scalar-relativistic radially local RPP).
|
||||
*/
|
||||
void libgrpp_type1_integrals(libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B,
|
||||
double *rpp_origin, libgrpp_potential_t *potential,
|
||||
double *matrix) {
|
||||
assert(libgrpp_is_initialized());
|
||||
|
||||
int size_A = libgrpp_get_shell_size(shell_A);
|
||||
int size_B = libgrpp_get_shell_size(shell_B);
|
||||
memset(matrix, 0, size_A * size_B * sizeof(double));
|
||||
|
||||
if (potential == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* RPP terms with n = 1, 2 are evaluated in a completely analytic manner
|
||||
* using the Obara-Saika-like recurrence relations
|
||||
*/
|
||||
|
||||
double *buf = calloc(size_A * size_B, sizeof(double));
|
||||
|
||||
for (int k = 0; k < potential->num_primitives; k++) {
|
||||
double pot_coef = potential->coeffs[k];
|
||||
double pot_alpha = potential->alpha[k];
|
||||
int pot_n = potential->powers[k];
|
||||
|
||||
libgrpp_type1_integrals_mcmurchie_davidson_1978(
|
||||
shell_A, shell_B, rpp_origin, pot_alpha, pot_n, buf);
|
||||
|
||||
libgrpp_daxpy(size_A * size_B, pot_coef, buf, matrix);
|
||||
}
|
||||
|
||||
free(buf);
|
||||
|
||||
/*
|
||||
* old (numerical) version
|
||||
*/
|
||||
|
||||
/*for (int i = 0; i < shell_A->num_primitives; i++) {
|
||||
for (int j = 0; j < shell_B->num_primitives; j++) {
|
||||
double coef_A_i = shell_A->coeffs[i];
|
||||
double coef_B_j = shell_B->coeffs[j];
|
||||
|
||||
if (fabs(coef_A_i * coef_B_j) < 1e-15) {
|
||||
continue;
|
||||
}
|
||||
|
||||
evaluate_type1_integral_primitive_gaussians(
|
||||
shell_A->origin, size_A, shell_A->cart_list,
|
||||
shell_A->alpha[i], shell_B->origin, size_B, shell_B->cart_list,
|
||||
shell_B->alpha[j], rpp_origin, potential, buf
|
||||
);
|
||||
|
||||
libgrpp_daxpy(size_A * size_B, coef_A_i * coef_B_j, buf, matrix);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluation of type 1 RPP integrals (scalar-relativistic radially local RPP)
|
||||
* for the pair of shells constructed from primitive Gaussians.
|
||||
*/
|
||||
void evaluate_type1_integral_primitive_gaussians(
|
||||
double *A, int n_cart_A, int *cart_list_A, double alpha_A, double *B,
|
||||
int n_cart_B, int *cart_list_B, double alpha_B, double *C,
|
||||
libgrpp_potential_t *potential, double *matrix) {
|
||||
libgrpp_potential_t *potential_shrinked = libgrpp_shrink_potential(potential);
|
||||
|
||||
libgrpp_evaluate_radially_local_potential_integral_primitive_gaussians(
|
||||
A, n_cart_A, cart_list_A, alpha_A, B, n_cart_B, cart_list_B, alpha_B, C,
|
||||
evaluate_pseudopotential, potential_shrinked, matrix);
|
||||
|
||||
libgrpp_delete_potential(potential_shrinked);
|
||||
}
|
||||
|
||||
static double evaluate_pseudopotential(double r, void *params) {
|
||||
libgrpp_potential_t *potential = (libgrpp_potential_t *)params;
|
||||
|
||||
double u = libgrpp_potential_value(potential, r);
|
||||
|
||||
return u;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluation of AO integrals for an arbitrary radially-local operator
|
||||
* for the pair of shells constructed from primitive Gaussians.
|
||||
*/
|
||||
void libgrpp_evaluate_radially_local_potential_integral_primitive_gaussians(
|
||||
double *A, int n_cart_A, int *cart_list_A, double alpha_A, double *B,
|
||||
int n_cart_B, int *cart_list_B, double alpha_B, double *C,
|
||||
double (*potential)(double r, void *params), void *potential_params,
|
||||
double *matrix) {
|
||||
assert(n_cart_A > 0);
|
||||
assert(n_cart_B > 0);
|
||||
|
||||
memset(matrix, 0, n_cart_A * n_cart_B * sizeof(double));
|
||||
|
||||
double CA_x = C[0] - A[0];
|
||||
double CA_y = C[1] - A[1];
|
||||
double CA_z = C[2] - A[2];
|
||||
double CB_x = C[0] - B[0];
|
||||
double CB_y = C[1] - B[1];
|
||||
double CB_z = C[2] - B[2];
|
||||
double CA_2 = CA_x * CA_x + CA_y * CA_y + CA_z * CA_z;
|
||||
double CB_2 = CB_x * CB_x + CB_y * CB_y + CB_z * CB_z;
|
||||
|
||||
double kx = -2.0 * (alpha_A * CA_x + alpha_B * CB_x);
|
||||
double ky = -2.0 * (alpha_A * CA_y + alpha_B * CB_y);
|
||||
double kz = -2.0 * (alpha_A * CA_z + alpha_B * CB_z);
|
||||
double k = sqrt(kx * kx + ky * ky + kz * kz);
|
||||
double kvec[3];
|
||||
kvec[0] = kx;
|
||||
kvec[1] = ky;
|
||||
kvec[2] = kz;
|
||||
|
||||
int L_A = cart_list_A[0] + cart_list_A[1] + cart_list_A[2];
|
||||
int L_B = cart_list_B[0] + cart_list_B[1] + cart_list_B[2];
|
||||
|
||||
double N_A = libgrpp_gaussian_norm_factor(L_A, 0, 0, alpha_A);
|
||||
double N_B = libgrpp_gaussian_norm_factor(L_B, 0, 0, alpha_B);
|
||||
double D_ABC = 4 * M_PI * N_A * N_B;
|
||||
|
||||
int lambda_max = L_A + L_B;
|
||||
int n_max = lambda_max;
|
||||
// create_real_spherical_harmonic_coeffs_tables(lambda_max);
|
||||
|
||||
/*
|
||||
* pre-compute type 1 radial integrals
|
||||
*/
|
||||
radial_type1_table_t *radial_table = libgrpp_tabulate_radial_type1_integrals(
|
||||
lambda_max, n_max, CA_2, CB_2, alpha_A, alpha_B, k, D_ABC, potential,
|
||||
potential_params);
|
||||
|
||||
/*
|
||||
* main loop
|
||||
* over shell pairs
|
||||
*/
|
||||
for (int icart = 0; icart < n_cart_A; icart++) {
|
||||
for (int jcart = 0; jcart < n_cart_B; jcart++) {
|
||||
|
||||
double chi_AB = 0.0;
|
||||
|
||||
int n_A = cart_list_A[3 * icart + 0];
|
||||
int l_A = cart_list_A[3 * icart + 1];
|
||||
int m_A = cart_list_A[3 * icart + 2];
|
||||
int n_B = cart_list_B[3 * jcart + 0];
|
||||
int l_B = cart_list_B[3 * jcart + 1];
|
||||
int m_B = cart_list_B[3 * jcart + 2];
|
||||
|
||||
for (int a = 0; a <= n_A; a++) {
|
||||
double C_nA_a = libgrpp_binomial(n_A, a);
|
||||
double pow_CA_x = pow(CA_x, n_A - a);
|
||||
|
||||
for (int b = 0; b <= l_A; b++) {
|
||||
double C_lA_b = libgrpp_binomial(l_A, b);
|
||||
double pow_CA_y = pow(CA_y, l_A - b);
|
||||
|
||||
for (int c = 0; c <= m_A; c++) {
|
||||
double C_mA_c = libgrpp_binomial(m_A, c);
|
||||
double pow_CA_z = pow(CA_z, m_A - c);
|
||||
|
||||
for (int d = 0; d <= n_B; d++) {
|
||||
double C_nB_d = libgrpp_binomial(n_B, d);
|
||||
double pow_CB_x = pow(CB_x, n_B - d);
|
||||
|
||||
for (int e = 0; e <= l_B; e++) {
|
||||
double C_lB_e = libgrpp_binomial(l_B, e);
|
||||
double pow_CB_y = pow(CB_y, l_B - e);
|
||||
|
||||
for (int f = 0; f <= m_B; f++) {
|
||||
double C_mB_f = libgrpp_binomial(m_B, f);
|
||||
double pow_CB_z = pow(CB_z, m_B - f);
|
||||
|
||||
double factor = C_nA_a * C_lA_b * C_mA_c * C_nB_d * C_lB_e *
|
||||
C_mB_f * pow_CA_x * pow_CA_y * pow_CA_z *
|
||||
pow_CB_x * pow_CB_y * pow_CB_z;
|
||||
|
||||
if (fabs(factor) < 1e-13) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int N = a + b + c + d + e + f;
|
||||
double sum_omega_Q = 0.0;
|
||||
for (int lambda = 0; lambda <= lambda_max; lambda++) {
|
||||
|
||||
double Q = libgrpp_get_radial_type1_integral(radial_table,
|
||||
lambda, N);
|
||||
if (fabs(Q) < 1e-16) {
|
||||
continue;
|
||||
}
|
||||
|
||||
double omega = libgrpp_angular_type1_integral(
|
||||
lambda, a + d, b + e, c + f, kvec);
|
||||
|
||||
sum_omega_Q += omega * Q;
|
||||
}
|
||||
|
||||
chi_AB += factor * sum_omega_Q;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
matrix[icart * n_cart_B + jcart] = chi_AB;
|
||||
}
|
||||
}
|
||||
|
||||
libgrpp_delete_radial_type1_integrals(radial_table);
|
||||
}
|
||||
577
src/grpp/grpp_type1_mcmurchie_davidson.c
Normal file
577
src/grpp/grpp_type1_mcmurchie_davidson.c
Normal file
|
|
@ -0,0 +1,577 @@
|
|||
/*----------------------------------------------------------------------------*/
|
||||
/* CP2K: A general program to perform molecular dynamics simulations */
|
||||
/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
|
||||
/* */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* libgrpp - a library for the evaluation of integrals over
|
||||
* generalized relativistic pseudopotentials.
|
||||
*
|
||||
* Copyright (C) 2021-2023 Alexander Oleynichenko
|
||||
*/
|
||||
|
||||
/*
|
||||
* Implementation of the McMurchie-Davidson (MMD) recurrence relations
|
||||
* for radially local RPP integrals.
|
||||
*
|
||||
* Operators to be integrated are:
|
||||
* n = 2: e^{-ar^2}
|
||||
* n = 1: e^{-ar^2}/r^1
|
||||
* n = 0: e^{-ar^2}/r^2
|
||||
*
|
||||
* General description of the MMD scheme is given in:
|
||||
* (1) T. Helgaker, P. Jorgensen, J. Olsen, Molecular Electronic-Structure
|
||||
* Theory, John Wiley & Sons Ltd, 2000. (2) L. E. McMurchie, E. R. Davidson,
|
||||
* One- and two-electron integrals over cartesian gaussian functions.
|
||||
* J. Comput. Phys. 26(2), 218 (1978).
|
||||
* doi: 10.1016/0021-9991(78)90092-X
|
||||
*
|
||||
* More on the evaluation of integrals over the 1/r^2 operator:
|
||||
* (1) J. 0. Jensen, A. H. Cameri, C. P. Vlahacos, D. Zeroka, H. F. Hameka, C.
|
||||
* N. Merrow, Evaluation of one-electron integrals for arbitrary operators V(r)
|
||||
* over cartesian Gaussians: Application to inverse-square distance and Yukawa
|
||||
* operators. J. Comput. Chem. 14(8), 986 (1993). doi: 10.1002/jcc.540140814 (2)
|
||||
* B. Gao, A. J. Thorvaldsen, K. Ruud, GEN1INT: A unified procedure for the
|
||||
* evaluation of one-electron integrals over Gaussian basis functions and their
|
||||
* geometric derivatives. Int. J. Quantum Chem. 111(4), 858 (2011).
|
||||
* doi: 10.1002/qua.22886
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "grpp_type1_mcmurchie_davidson.h"
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
#include "grpp_norm_gaussian.h"
|
||||
#include "grpp_specfunc.h"
|
||||
#include "grpp_utils.h"
|
||||
#include "libgrpp.h"
|
||||
|
||||
#define LMAX LIBGRPP_MAX_BASIS_L
|
||||
|
||||
/*
|
||||
* temporary data for the McMurchie-Davidson algorithm
|
||||
*/
|
||||
struct mmd_data {
|
||||
double A[3];
|
||||
double B[3];
|
||||
double C[3];
|
||||
double Q[3];
|
||||
double q;
|
||||
double K_abc[3];
|
||||
double R_QC_2;
|
||||
double boys[100];
|
||||
double E[3][LMAX][LMAX][2 * LMAX];
|
||||
double R[2 * LMAX][2 * LMAX][2 * LMAX][2 * LMAX];
|
||||
};
|
||||
|
||||
/*
|
||||
* functions used below in the file
|
||||
*/
|
||||
|
||||
static void evaluate_rpp_type1_mmd_n2_primitive_shell_pair(
|
||||
libgrpp_shell_t *shell_A, double alpha_A, libgrpp_shell_t *shell_B,
|
||||
double alpha_B, double *rpp_origin, double rpp_alpha, double *rpp_matrix);
|
||||
|
||||
void libgrpp_evaluate_rpp_type1_mmd_n1_primitive_shell_pair(
|
||||
libgrpp_shell_t *shell_A, double alpha_A, libgrpp_shell_t *shell_B,
|
||||
double alpha_B, double *rpp_origin, double rpp_alpha, double *rpp_matrix);
|
||||
|
||||
static void evaluate_rpp_type1_mmd_n0_primitive_shell_pair(
|
||||
libgrpp_shell_t *shell_A, double alpha_A, libgrpp_shell_t *shell_B,
|
||||
double alpha_B, double *rpp_origin, double rpp_alpha, double *rpp_matrix);
|
||||
|
||||
static void setup_E_array(struct mmd_data *data, int L_A, int L_B);
|
||||
|
||||
static void setup_R_array(struct mmd_data *data, int L_A, int L_B);
|
||||
|
||||
static void setup_G_array(struct mmd_data *data, int L_A, int L_B);
|
||||
|
||||
/**
|
||||
* General interface for the McMurchie-Davidson algorithm for integrals
|
||||
* over the radially local RPP operator.
|
||||
*/
|
||||
void libgrpp_type1_integrals_mcmurchie_davidson_1978(
|
||||
libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B, double *origin_C,
|
||||
double alpha_C, int ecp_power, double *rpp_matrix) {
|
||||
assert((ecp_power == 0) || (ecp_power == 1) || (ecp_power == 2));
|
||||
|
||||
int size_A = libgrpp_get_shell_size(shell_A);
|
||||
int size_B = libgrpp_get_shell_size(shell_B);
|
||||
|
||||
double *buf = calloc(size_A * size_B, sizeof(double));
|
||||
|
||||
memset(rpp_matrix, 0, size_A * size_B * sizeof(double));
|
||||
|
||||
/*
|
||||
* loop over primitives in contractions
|
||||
*/
|
||||
for (int i = 0; i < shell_A->num_primitives; i++) {
|
||||
double coef_A_i = shell_A->coeffs[i];
|
||||
if (fabs(coef_A_i) < LIBGRPP_ZERO_THRESH) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int j = 0; j < shell_B->num_primitives; j++) {
|
||||
double coef_B_j = shell_B->coeffs[j];
|
||||
if (fabs(coef_B_j) < LIBGRPP_ZERO_THRESH) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ecp_power == 2) {
|
||||
evaluate_rpp_type1_mmd_n2_primitive_shell_pair(
|
||||
shell_A, shell_A->alpha[i], shell_B, shell_B->alpha[j], origin_C,
|
||||
alpha_C, buf);
|
||||
} else if (ecp_power == 1) {
|
||||
libgrpp_evaluate_rpp_type1_mmd_n1_primitive_shell_pair(
|
||||
shell_A, shell_A->alpha[i], shell_B, shell_B->alpha[j], origin_C,
|
||||
alpha_C, buf);
|
||||
} else if (ecp_power == 0) {
|
||||
evaluate_rpp_type1_mmd_n0_primitive_shell_pair(
|
||||
shell_A, shell_A->alpha[i], shell_B, shell_B->alpha[j], origin_C,
|
||||
alpha_C, buf);
|
||||
}
|
||||
|
||||
libgrpp_daxpy(size_A * size_B, coef_A_i * coef_B_j, buf, rpp_matrix);
|
||||
}
|
||||
}
|
||||
|
||||
free(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Integrals of the operator: e^{-ar^2}/r^2
|
||||
*/
|
||||
static void evaluate_rpp_type1_mmd_n0_primitive_shell_pair(
|
||||
libgrpp_shell_t *shell_A, double alpha_A, libgrpp_shell_t *shell_B,
|
||||
double alpha_B, double *rpp_origin, double rpp_alpha, double *rpp_matrix) {
|
||||
double a = alpha_A;
|
||||
double b = alpha_B;
|
||||
double c = rpp_alpha;
|
||||
|
||||
double *A = shell_A->origin;
|
||||
double *B = shell_B->origin;
|
||||
double *C = rpp_origin;
|
||||
|
||||
double q = a + b + c;
|
||||
double mu_AB = a * b / q;
|
||||
double mu_AC = a * c / q;
|
||||
double mu_BC = b * c / q;
|
||||
|
||||
struct mmd_data data;
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
data.A[i] = A[i];
|
||||
data.B[i] = B[i];
|
||||
data.C[i] = C[i];
|
||||
data.Q[i] = (a * A[i] + b * B[i] + c * C[i]) / q;
|
||||
|
||||
double X_AB = A[i] - B[i];
|
||||
double X_AC = A[i] - C[i];
|
||||
double X_BC = B[i] - C[i];
|
||||
|
||||
double K_ab = exp(-mu_AB * X_AB * X_AB);
|
||||
double K_ac = exp(-mu_AC * X_AC * X_AC);
|
||||
double K_bc = exp(-mu_BC * X_BC * X_BC);
|
||||
|
||||
data.K_abc[i] = K_ab * K_ac * K_bc;
|
||||
}
|
||||
|
||||
data.q = q;
|
||||
data.R_QC_2 = distance_squared(data.Q, data.C);
|
||||
int L_A = shell_A->L;
|
||||
int L_B = shell_B->L;
|
||||
int Nmax = L_A + L_B;
|
||||
libgrpp_gfun_values(q * data.R_QC_2, Nmax, data.boys);
|
||||
|
||||
/*
|
||||
* setup E array
|
||||
*/
|
||||
setup_E_array(&data, L_A, L_B);
|
||||
|
||||
/*
|
||||
* setup R array
|
||||
*/
|
||||
setup_G_array(&data, L_A, L_B);
|
||||
|
||||
/*
|
||||
* loop over cartesian functions inside the shells
|
||||
*/
|
||||
int size_A = libgrpp_get_shell_size(shell_A);
|
||||
int size_B = libgrpp_get_shell_size(shell_B);
|
||||
double N_A = libgrpp_gaussian_norm_factor(L_A, 0, 0, alpha_A);
|
||||
double N_B = libgrpp_gaussian_norm_factor(L_B, 0, 0, alpha_B);
|
||||
|
||||
for (int m = 0; m < size_A; m++) {
|
||||
for (int n = 0; n < size_B; n++) {
|
||||
int n_A = shell_A->cart_list[3 * m + 0];
|
||||
int l_A = shell_A->cart_list[3 * m + 1];
|
||||
int m_A = shell_A->cart_list[3 * m + 2];
|
||||
int n_B = shell_B->cart_list[3 * n + 0];
|
||||
int l_B = shell_B->cart_list[3 * n + 1];
|
||||
int m_B = shell_B->cart_list[3 * n + 2];
|
||||
|
||||
double s = 0.0;
|
||||
|
||||
for (int t = 0; t <= n_A + n_B; t++) {
|
||||
double Ex = data.E[0][n_A][n_B][t];
|
||||
|
||||
for (int u = 0; u <= l_A + l_B; u++) {
|
||||
double Ey = data.E[1][l_A][l_B][u];
|
||||
|
||||
for (int v = 0; v <= m_A + m_B; v++) {
|
||||
double Ez = data.E[2][m_A][m_B][v];
|
||||
|
||||
double R_tuv = data.R[t][u][v][0];
|
||||
|
||||
s += Ex * Ey * Ez * R_tuv;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s *= N_A * N_B * 2.0 * pow(M_PI, 1.5) / sqrt(q);
|
||||
rpp_matrix[m * size_B + n] = s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Integrals of the operator: e^{-ar^2}/r
|
||||
*/
|
||||
void libgrpp_evaluate_rpp_type1_mmd_n1_primitive_shell_pair(
|
||||
libgrpp_shell_t *shell_A, double alpha_A, libgrpp_shell_t *shell_B,
|
||||
double alpha_B, double *rpp_origin, double rpp_alpha, double *rpp_matrix) {
|
||||
double a = alpha_A;
|
||||
double b = alpha_B;
|
||||
double c = rpp_alpha;
|
||||
|
||||
double *A = shell_A->origin;
|
||||
double *B = shell_B->origin;
|
||||
double *C = rpp_origin;
|
||||
|
||||
double q = a + b + c;
|
||||
double mu_AB = a * b / q;
|
||||
double mu_AC = a * c / q;
|
||||
double mu_BC = b * c / q;
|
||||
|
||||
struct mmd_data data;
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
data.A[i] = A[i];
|
||||
data.B[i] = B[i];
|
||||
data.C[i] = C[i];
|
||||
data.Q[i] = (a * A[i] + b * B[i] + c * C[i]) / q;
|
||||
|
||||
double X_AB = A[i] - B[i];
|
||||
double X_AC = A[i] - C[i];
|
||||
double X_BC = B[i] - C[i];
|
||||
|
||||
double K_ab = exp(-mu_AB * X_AB * X_AB);
|
||||
double K_ac = exp(-mu_AC * X_AC * X_AC);
|
||||
double K_bc = exp(-mu_BC * X_BC * X_BC);
|
||||
|
||||
data.K_abc[i] = K_ab * K_ac * K_bc;
|
||||
}
|
||||
|
||||
data.q = q;
|
||||
data.R_QC_2 = distance_squared(data.Q, data.C);
|
||||
int L_A = shell_A->L;
|
||||
int L_B = shell_B->L;
|
||||
int Nmax = L_A + L_B;
|
||||
|
||||
libgrpp_boys_values(q * data.R_QC_2, Nmax, data.boys);
|
||||
|
||||
/*
|
||||
* setup E array
|
||||
*/
|
||||
setup_E_array(&data, L_A, L_B);
|
||||
|
||||
/*
|
||||
* setup R array
|
||||
*/
|
||||
setup_R_array(&data, L_A, L_B);
|
||||
|
||||
/*
|
||||
* loop over cartesian functions inside the shells
|
||||
*/
|
||||
int size_A = libgrpp_get_shell_size(shell_A);
|
||||
int size_B = libgrpp_get_shell_size(shell_B);
|
||||
double N_A = libgrpp_gaussian_norm_factor(L_A, 0, 0, alpha_A);
|
||||
double N_B = libgrpp_gaussian_norm_factor(L_B, 0, 0, alpha_B);
|
||||
|
||||
for (int m = 0; m < size_A; m++) {
|
||||
for (int n = 0; n < size_B; n++) {
|
||||
int n_A = shell_A->cart_list[3 * m + 0];
|
||||
int l_A = shell_A->cart_list[3 * m + 1];
|
||||
int m_A = shell_A->cart_list[3 * m + 2];
|
||||
int n_B = shell_B->cart_list[3 * n + 0];
|
||||
int l_B = shell_B->cart_list[3 * n + 1];
|
||||
int m_B = shell_B->cart_list[3 * n + 2];
|
||||
|
||||
double s = 0.0;
|
||||
|
||||
for (int t = 0; t <= n_A + n_B; t++) {
|
||||
double Ex = data.E[0][n_A][n_B][t];
|
||||
|
||||
for (int u = 0; u <= l_A + l_B; u++) {
|
||||
double Ey = data.E[1][l_A][l_B][u];
|
||||
|
||||
for (int v = 0; v <= m_A + m_B; v++) {
|
||||
double Ez = data.E[2][m_A][m_B][v];
|
||||
|
||||
double R_tuv = data.R[t][u][v][0];
|
||||
|
||||
s += Ex * Ey * Ez * R_tuv;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s *= N_A * N_B * 2.0 * M_PI / q;
|
||||
rpp_matrix[m * size_B + n] = s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Integrals of the operator: e^{-ar^2}
|
||||
*/
|
||||
static void evaluate_rpp_type1_mmd_n2_primitive_shell_pair(
|
||||
libgrpp_shell_t *shell_A, double alpha_A, libgrpp_shell_t *shell_B,
|
||||
double alpha_B, double *rpp_origin, double rpp_alpha, double *rpp_matrix) {
|
||||
double a = alpha_A;
|
||||
double b = alpha_B;
|
||||
double c = rpp_alpha;
|
||||
|
||||
double *A = shell_A->origin;
|
||||
double *B = shell_B->origin;
|
||||
double *C = rpp_origin;
|
||||
|
||||
double q = a + b + c;
|
||||
double mu_AB = a * b / q;
|
||||
double mu_AC = a * c / q;
|
||||
double mu_BC = b * c / q;
|
||||
|
||||
struct mmd_data data;
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
data.A[i] = A[i];
|
||||
data.B[i] = B[i];
|
||||
data.C[i] = C[i];
|
||||
data.Q[i] = (a * A[i] + b * B[i] + c * C[i]) / q;
|
||||
|
||||
double X_AB = A[i] - B[i];
|
||||
double X_AC = A[i] - C[i];
|
||||
double X_BC = B[i] - C[i];
|
||||
|
||||
double K_ab = exp(-mu_AB * X_AB * X_AB);
|
||||
double K_ac = exp(-mu_AC * X_AC * X_AC);
|
||||
double K_bc = exp(-mu_BC * X_BC * X_BC);
|
||||
|
||||
data.K_abc[i] = K_ab * K_ac * K_bc;
|
||||
}
|
||||
|
||||
data.q = q;
|
||||
data.R_QC_2 = distance_squared(data.Q, data.C);
|
||||
|
||||
int L_A = shell_A->L;
|
||||
int L_B = shell_B->L;
|
||||
|
||||
/*
|
||||
* setup E array
|
||||
*/
|
||||
setup_E_array(&data, L_A, L_B);
|
||||
|
||||
/*
|
||||
* loop over cartesian functions inside the shells
|
||||
*/
|
||||
int size_A = libgrpp_get_shell_size(shell_A);
|
||||
int size_B = libgrpp_get_shell_size(shell_B);
|
||||
double N_A = libgrpp_gaussian_norm_factor(L_A, 0, 0, alpha_A);
|
||||
double N_B = libgrpp_gaussian_norm_factor(L_B, 0, 0, alpha_B);
|
||||
|
||||
for (int m = 0; m < size_A; m++) {
|
||||
for (int n = 0; n < size_B; n++) {
|
||||
int n_A = shell_A->cart_list[3 * m + 0];
|
||||
int l_A = shell_A->cart_list[3 * m + 1];
|
||||
int m_A = shell_A->cart_list[3 * m + 2];
|
||||
int n_B = shell_B->cart_list[3 * n + 0];
|
||||
int l_B = shell_B->cart_list[3 * n + 1];
|
||||
int m_B = shell_B->cart_list[3 * n + 2];
|
||||
|
||||
double E_ij_0 = data.E[0][n_A][n_B][0];
|
||||
double E_kl_0 = data.E[1][l_A][l_B][0];
|
||||
double E_mn_0 = data.E[2][m_A][m_B][0];
|
||||
|
||||
double s = N_A * N_B * E_ij_0 * E_kl_0 * E_mn_0 * pow(M_PI / q, 1.5);
|
||||
|
||||
rpp_matrix[m * size_B + n] = s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculation of the R_{tuv}^N auxiliary integrals for the 1/r operator
|
||||
*/
|
||||
static void setup_R_array(struct mmd_data *data, int L_A, int L_B) {
|
||||
double q = data->q;
|
||||
double X_QC = data->Q[0] - data->C[0];
|
||||
double Y_QC = data->Q[1] - data->C[1];
|
||||
double Z_QC = data->Q[2] - data->C[2];
|
||||
|
||||
int nmax = L_A + L_B;
|
||||
int L_SUM = L_A + L_B;
|
||||
|
||||
for (int t = 0; t <= L_SUM; t++) {
|
||||
for (int u = 0; u <= L_SUM; u++) {
|
||||
for (int v = 0; v <= L_SUM; v++) {
|
||||
|
||||
if (t + u + v > L_SUM) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int n = 0; n <= nmax - (t + u + v); n++) {
|
||||
|
||||
double val = 0.0;
|
||||
|
||||
if (t + u + v == 0) {
|
||||
val = pow(-2.0 * q, n) * data->boys[n];
|
||||
} else if (t + u == 0) {
|
||||
if (v > 1) {
|
||||
val += (v - 1) * data->R[t][u][v - 2][n + 1];
|
||||
}
|
||||
val += Z_QC * data->R[t][u][v - 1][n + 1];
|
||||
} else if (t == 0) {
|
||||
if (u > 1) {
|
||||
val += (u - 1) * data->R[t][u - 2][v][n + 1];
|
||||
}
|
||||
val += Y_QC * data->R[t][u - 1][v][n + 1];
|
||||
} else {
|
||||
if (t > 1) {
|
||||
val += (t - 1) * data->R[t - 2][u][v][n + 1];
|
||||
}
|
||||
val += X_QC * data->R[t - 1][u][v][n + 1];
|
||||
}
|
||||
|
||||
data->R[t][u][v][n] = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculation of the R_{tuv}^N auxiliary integrals for the 1/r^2 operator
|
||||
*/
|
||||
static void setup_G_array(struct mmd_data *data, int L_A, int L_B) {
|
||||
double q = data->q;
|
||||
double X_QC = data->Q[0] - data->C[0];
|
||||
double Y_QC = data->Q[1] - data->C[1];
|
||||
double Z_QC = data->Q[2] - data->C[2];
|
||||
|
||||
int nmax = L_A + L_B;
|
||||
int L_SUM = L_A + L_B;
|
||||
|
||||
for (int t = 0; t <= L_SUM; t++) {
|
||||
for (int u = 0; u <= L_SUM; u++) {
|
||||
for (int v = 0; v <= L_SUM; v++) {
|
||||
|
||||
if (t + u + v > L_SUM) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int n = 0; n <= nmax - (t + u + v); n++) {
|
||||
|
||||
double val = 0.0;
|
||||
|
||||
if (t + u + v == 0) {
|
||||
val = pow(2.0 * q, n) * data->boys[n];
|
||||
} else if (t + u == 0) {
|
||||
if (v > 1) {
|
||||
val += (v - 1) * (data->R[t][u][v - 2][n + 1] -
|
||||
2.0 * q * data->R[t][u][v - 2][n]);
|
||||
}
|
||||
val += Z_QC * (data->R[t][u][v - 1][n + 1] -
|
||||
2.0 * q * data->R[t][u][v - 1][n]);
|
||||
} else if (t == 0) {
|
||||
if (u > 1) {
|
||||
val += (u - 1) * (data->R[t][u - 2][v][n + 1] -
|
||||
2.0 * q * data->R[t][u - 2][v][n]);
|
||||
}
|
||||
val += Y_QC * (data->R[t][u - 1][v][n + 1] -
|
||||
2.0 * q * data->R[t][u - 1][v][n]);
|
||||
} else {
|
||||
if (t > 1) {
|
||||
val += (t - 1) * (data->R[t - 2][u][v][n + 1] -
|
||||
2.0 * q * data->R[t - 2][u][v][n]);
|
||||
}
|
||||
val += X_QC * (data->R[t - 1][u][v][n + 1] -
|
||||
2.0 * q * data->R[t - 1][u][v][n]);
|
||||
}
|
||||
|
||||
data->R[t][u][v][n] = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates E^{ij}_t coefficients in the MMD scheme.
|
||||
*/
|
||||
static void setup_E_array(struct mmd_data *data, int L_A, int L_B) {
|
||||
double q = data->q;
|
||||
|
||||
for (int coord = 0; coord < 3; coord++) {
|
||||
for (int i = 0; i <= L_A; i++) {
|
||||
for (int j = 0; j <= L_B; j++) {
|
||||
|
||||
for (int t = 0; t <= i + j; t++) {
|
||||
|
||||
if (t == 0) {
|
||||
if (i == 0 && j == 0) {
|
||||
data->E[coord][0][0][0] = data->K_abc[coord];
|
||||
continue;
|
||||
} else if (i == 1 && j == 0) {
|
||||
double X_QA = data->Q[coord] - data->A[coord];
|
||||
data->E[coord][1][0][0] = X_QA * data->E[coord][0][0][0];
|
||||
continue;
|
||||
} else if (i == 0 && j == 1) {
|
||||
double X_QB = data->Q[coord] - data->B[coord];
|
||||
data->E[coord][0][1][0] = X_QB * data->E[coord][0][0][0];
|
||||
continue;
|
||||
} else if (i == 0) {
|
||||
double X_QB = data->Q[coord] - data->B[coord];
|
||||
data->E[coord][i][j][0] = X_QB * data->E[coord][i][j - 1][0] +
|
||||
data->E[coord][i][j - 1][1];
|
||||
continue;
|
||||
} else {
|
||||
double X_QA = data->Q[coord] - data->A[coord];
|
||||
data->E[coord][i][j][0] = X_QA * data->E[coord][i - 1][j][0] +
|
||||
data->E[coord][i - 1][j][1];
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
double E_ijt = 0.0;
|
||||
double factor = 1.0 / (2.0 * q * t);
|
||||
|
||||
if (i > 0) {
|
||||
E_ijt += factor * i * data->E[coord][i - 1][j][t - 1];
|
||||
}
|
||||
if (j > 0) {
|
||||
E_ijt += factor * j * data->E[coord][i][j - 1][t - 1];
|
||||
}
|
||||
|
||||
data->E[coord][i][j][t] = E_ijt;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
24
src/grpp/grpp_type1_mcmurchie_davidson.h
Normal file
24
src/grpp/grpp_type1_mcmurchie_davidson.h
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
/*----------------------------------------------------------------------------*/
|
||||
/* CP2K: A general program to perform molecular dynamics simulations */
|
||||
/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
|
||||
/* */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* libgrpp - a library for the evaluation of integrals over
|
||||
* generalized relativistic pseudopotentials.
|
||||
*
|
||||
* Copyright (C) 2021-2023 Alexander Oleynichenko
|
||||
*/
|
||||
|
||||
#ifndef __TYPE1_MCMURCHIE_DAVIDSON_H__
|
||||
#define __TYPE1_MCMURCHIE_DAVIDSON_H__
|
||||
|
||||
#include "libgrpp_types.h"
|
||||
|
||||
void libgrpp_type1_integrals_mcmurchie_davidson_1978(
|
||||
libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B, double *origin_C,
|
||||
double alpha_C, int ecp_power, double *rpp_matrix);
|
||||
|
||||
#endif // TYPE1_MCMURCHIE_DAVIDSON_H
|
||||
245
src/grpp/grpp_type2_integrals.c
Normal file
245
src/grpp/grpp_type2_integrals.c
Normal file
|
|
@ -0,0 +1,245 @@
|
|||
/*----------------------------------------------------------------------------*/
|
||||
/* CP2K: A general program to perform molecular dynamics simulations */
|
||||
/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
|
||||
/* */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* libgrpp - a library for the evaluation of integrals over
|
||||
* generalized relativistic pseudopotentials.
|
||||
*
|
||||
* Copyright (C) 2021-2023 Alexander Oleynichenko
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
#include "grpp_angular_integrals.h"
|
||||
#include "grpp_binomial.h"
|
||||
#include "grpp_radial_type2_integral.h"
|
||||
#include "grpp_spherical_harmonics.h"
|
||||
#include "grpp_utils.h"
|
||||
#include "libgrpp.h"
|
||||
|
||||
#define LMAX (2 * LIBGRPP_MAX_BASIS_L + LIBGRPP_MAX_RPP_L)
|
||||
|
||||
static double type2_angular_sum(int L, int lambda_1, int a, int b, int c,
|
||||
int lambda_2, int d, int e, int f,
|
||||
double *rsh_values_kA, double *rsh_values_kB);
|
||||
|
||||
/**
|
||||
* Evaluation of type 2 RPP integrals (scalar-relativistic semilocal RPP with
|
||||
* L-projectors).
|
||||
*/
|
||||
void libgrpp_type2_integrals(libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B,
|
||||
double *rpp_origin, libgrpp_potential_t *potential,
|
||||
double *matrix) {
|
||||
assert(libgrpp_is_initialized());
|
||||
|
||||
int size_A = libgrpp_get_shell_size(shell_A);
|
||||
int size_B = libgrpp_get_shell_size(shell_B);
|
||||
|
||||
memset(matrix, 0, size_A * size_B * sizeof(double));
|
||||
|
||||
int L = potential->L;
|
||||
int L_A =
|
||||
shell_A->cart_list[0] + shell_A->cart_list[1] + shell_A->cart_list[2];
|
||||
int L_B =
|
||||
shell_B->cart_list[0] + shell_B->cart_list[1] + shell_B->cart_list[2];
|
||||
|
||||
double *A = shell_A->origin;
|
||||
double *B = shell_B->origin;
|
||||
double *C = rpp_origin;
|
||||
|
||||
double CA_x = C[0] - A[0];
|
||||
double CA_y = C[1] - A[1];
|
||||
double CA_z = C[2] - A[2];
|
||||
double CB_x = C[0] - B[0];
|
||||
double CB_y = C[1] - B[1];
|
||||
double CB_z = C[2] - B[2];
|
||||
double CA_2 = CA_x * CA_x + CA_y * CA_y + CA_z * CA_z;
|
||||
double CB_2 = CB_x * CB_x + CB_y * CB_y + CB_z * CB_z;
|
||||
|
||||
double alpha_A = shell_A->alpha[0];
|
||||
double alpha_B = shell_B->alpha[0];
|
||||
double kA_x = -2.0 * (alpha_A * CA_x);
|
||||
double kA_y = -2.0 * (alpha_A * CA_y);
|
||||
double kA_z = -2.0 * (alpha_A * CA_z);
|
||||
double kB_x = -2.0 * (alpha_B * CB_x);
|
||||
double kB_y = -2.0 * (alpha_B * CB_y);
|
||||
double kB_z = -2.0 * (alpha_B * CB_z);
|
||||
double kA_vec[3];
|
||||
kA_vec[0] = kA_x;
|
||||
kA_vec[1] = kA_y;
|
||||
kA_vec[2] = kA_z;
|
||||
double kB_vec[3];
|
||||
kB_vec[0] = kB_x;
|
||||
kB_vec[1] = kB_y;
|
||||
kB_vec[2] = kB_z;
|
||||
|
||||
int lambda1_max = L + L_A;
|
||||
int lambda2_max = L + L_B;
|
||||
int N_max = L_A + L_B;
|
||||
|
||||
/*
|
||||
* for further evaluation of angular integrals
|
||||
*/
|
||||
int lmax = int_max3(lambda1_max, lambda2_max, L);
|
||||
// create_real_spherical_harmonic_coeffs_tables(lmax);
|
||||
|
||||
/*
|
||||
* pre-compute type 2 radial integrals
|
||||
*/
|
||||
radial_type2_table_t *radial_table = libgrpp_tabulate_radial_type2_integrals(
|
||||
lambda1_max, lambda2_max, N_max, CA_2, CB_2, potential, shell_A, shell_B);
|
||||
|
||||
/*
|
||||
* pre-calculate values of real spherical harmonics for different L
|
||||
*/
|
||||
double rsh_values_kA[3 * LMAX][6 * LMAX];
|
||||
double rsh_values_kB[3 * LMAX][6 * LMAX];
|
||||
|
||||
for (int lambda = 0; lambda <= lmax; lambda++) {
|
||||
libgrpp_evaluate_real_spherical_harmonics_array(lambda, kA_vec,
|
||||
rsh_values_kA[lambda]);
|
||||
libgrpp_evaluate_real_spherical_harmonics_array(lambda, kB_vec,
|
||||
rsh_values_kB[lambda]);
|
||||
}
|
||||
|
||||
/*
|
||||
* main loop
|
||||
* over shell pairs
|
||||
*/
|
||||
for (int icart = 0; icart < size_A; icart++) {
|
||||
for (int jcart = 0; jcart < size_B; jcart++) {
|
||||
|
||||
double gamma_AB = 0.0;
|
||||
|
||||
int n_A = shell_A->cart_list[3 * icart + 0];
|
||||
int l_A = shell_A->cart_list[3 * icart + 1];
|
||||
int m_A = shell_A->cart_list[3 * icart + 2];
|
||||
int n_B = shell_B->cart_list[3 * jcart + 0];
|
||||
int l_B = shell_B->cart_list[3 * jcart + 1];
|
||||
int m_B = shell_B->cart_list[3 * jcart + 2];
|
||||
|
||||
for (int a = 0; a <= n_A; a++) {
|
||||
|
||||
double C_nA_a = libgrpp_binomial(n_A, a);
|
||||
double pow_CA_x = pow(CA_x, n_A - a);
|
||||
|
||||
for (int b = 0; b <= l_A; b++) {
|
||||
|
||||
double C_lA_b = libgrpp_binomial(l_A, b);
|
||||
double pow_CA_y = pow(CA_y, l_A - b);
|
||||
|
||||
for (int c = 0; c <= m_A; c++) {
|
||||
|
||||
double C_mA_c = libgrpp_binomial(m_A, c);
|
||||
double pow_CA_z = pow(CA_z, m_A - c);
|
||||
|
||||
for (int d = 0; d <= n_B; d++) {
|
||||
|
||||
double C_nB_d = libgrpp_binomial(n_B, d);
|
||||
double pow_CB_x = pow(CB_x, n_B - d);
|
||||
|
||||
for (int e = 0; e <= l_B; e++) {
|
||||
|
||||
double C_lB_e = libgrpp_binomial(l_B, e);
|
||||
double pow_CB_y = pow(CB_y, l_B - e);
|
||||
|
||||
for (int f = 0; f <= m_B; f++) {
|
||||
|
||||
double C_mB_f = libgrpp_binomial(m_B, f);
|
||||
double pow_CB_z = pow(CB_z, m_B - f);
|
||||
|
||||
double factor = C_nA_a * C_lA_b * C_mA_c * C_nB_d * C_lB_e *
|
||||
C_mB_f * pow_CA_x * pow_CA_y * pow_CA_z *
|
||||
pow_CB_x * pow_CB_y * pow_CB_z;
|
||||
|
||||
if (fabs(factor) < 1e-13) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int N = a + b + c + d + e + f;
|
||||
double sum_omega_Q = 0.0;
|
||||
|
||||
int lambda1_lower = int_max2(L - a - b - c, 0);
|
||||
int lambda2_lower = int_max2(L - d - e - f, 0);
|
||||
int lambda1_upper = L + a + b + c;
|
||||
int lambda2_upper = L + d + e + f;
|
||||
|
||||
for (int lambda_1 = lambda1_lower; lambda_1 <= lambda1_upper;
|
||||
lambda_1++) {
|
||||
if ((L + a + b + c - lambda_1) % 2 != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int lambda_2 = lambda2_lower;
|
||||
lambda_2 <= lambda2_upper; lambda_2++) {
|
||||
if ((L + d + e + f - lambda_2) % 2 != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
double QN = libgrpp_get_radial_type2_integral(
|
||||
radial_table, lambda_1, lambda_2, N);
|
||||
if (fabs(QN) < 1e-16) {
|
||||
continue;
|
||||
}
|
||||
|
||||
double sum_angular = type2_angular_sum(
|
||||
L, lambda_1, a, b, c, lambda_2, d, e, f,
|
||||
rsh_values_kA[lambda_1], rsh_values_kB[lambda_2]);
|
||||
|
||||
sum_omega_Q += QN * sum_angular;
|
||||
} // loop over lambda_2
|
||||
} // loop over lambda_1
|
||||
|
||||
gamma_AB += factor * sum_omega_Q;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gamma_AB *= 16 * M_PI * M_PI;
|
||||
|
||||
matrix[icart * size_B + jcart] = gamma_AB;
|
||||
}
|
||||
}
|
||||
|
||||
libgrpp_delete_radial_type2_integrals(radial_table);
|
||||
}
|
||||
|
||||
/*
|
||||
* Sum of products of type 2 angular integrals
|
||||
* (McMurchie, Davidson, 1981, formulas (23) and (24))
|
||||
*/
|
||||
static double type2_angular_sum(int L, int lambda_1, int a, int b, int c,
|
||||
int lambda_2, int d, int e, int f,
|
||||
double *rsh_values_kA, double *rsh_values_kB) {
|
||||
double sum_angular = 0.0;
|
||||
|
||||
/*
|
||||
* contract tensors with angular integrals
|
||||
*/
|
||||
for (int m = -L; m <= L; m++) {
|
||||
double omega_1 =
|
||||
libgrpp_angular_type2_integral(lambda_1, L, m, a, b, c, rsh_values_kA);
|
||||
if (fabs(omega_1) < 1e-16) {
|
||||
continue;
|
||||
}
|
||||
|
||||
double omega_2 =
|
||||
libgrpp_angular_type2_integral(lambda_2, L, m, d, e, f, rsh_values_kB);
|
||||
|
||||
sum_angular += omega_1 * omega_2;
|
||||
}
|
||||
|
||||
return sum_angular;
|
||||
}
|
||||
89
src/grpp/grpp_utils.c
Normal file
89
src/grpp/grpp_utils.c
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
/*----------------------------------------------------------------------------*/
|
||||
/* CP2K: A general program to perform molecular dynamics simulations */
|
||||
/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
|
||||
/* */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* libgrpp - a library for the evaluation of integrals over
|
||||
* generalized relativistic pseudopotentials.
|
||||
*
|
||||
* Copyright (C) 2021-2023 Alexander Oleynichenko
|
||||
*/
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "grpp_utils.h"
|
||||
|
||||
inline int int_max2(int x, int y) { return (x > y) ? x : y; }
|
||||
|
||||
inline int int_max3(int x, int y, int z) { return int_max2(int_max2(x, y), z); }
|
||||
|
||||
double *alloc_zeros_1d(int n) { return (double *)calloc(n, sizeof(double)); }
|
||||
|
||||
double **alloc_zeros_2d(int n, int m) {
|
||||
double **array = (double **)calloc(n, sizeof(double *));
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
array[i] = (double *)calloc(m, sizeof(double));
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
void free_2d(double **array, int n) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
free(array[i]);
|
||||
}
|
||||
free(array);
|
||||
}
|
||||
|
||||
/*
|
||||
* constant times a vector plus a vector:
|
||||
* y = a * x + y
|
||||
*/
|
||||
void libgrpp_daxpy(int n, double a, double *x, double *y) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
y[i] += a * x[i];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* naive matrix multiplication
|
||||
*/
|
||||
void libgrpp_multiply_matrices(int M, int N, int K, double *A, double *B,
|
||||
double *C) {
|
||||
for (int i = 0; i < M; i++) {
|
||||
for (int j = 0; j < N; j++) {
|
||||
double sum = 0.0;
|
||||
for (int k = 0; k < K; k++) {
|
||||
sum += A[i * K + k] * B[k * N + j];
|
||||
}
|
||||
C[i * N + j] += sum;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double distance_squared(double *A, double *B) {
|
||||
double dx = A[0] - B[0];
|
||||
double dy = A[1] - B[1];
|
||||
double dz = A[2] - B[2];
|
||||
return dx * dx + dy * dy + dz * dz;
|
||||
}
|
||||
|
||||
double distance(double *A, double *B) { return sqrt(distance_squared(A, B)); }
|
||||
|
||||
/**
|
||||
* Checks if two 3d points coincide with each other.
|
||||
*/
|
||||
int points_are_equal(double *a, double *b) {
|
||||
double const thresh = 1e-12;
|
||||
|
||||
if (fabs(a[0] - b[0]) < thresh && fabs(a[1] - b[1]) < thresh &&
|
||||
fabs(a[2] - b[2]) < thresh) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
39
src/grpp/grpp_utils.h
Normal file
39
src/grpp/grpp_utils.h
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/*----------------------------------------------------------------------------*/
|
||||
/* CP2K: A general program to perform molecular dynamics simulations */
|
||||
/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
|
||||
/* */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* libgrpp - a library for the evaluation of integrals over
|
||||
* generalized relativistic pseudopotentials.
|
||||
*
|
||||
* Copyright (C) 2021-2023 Alexander Oleynichenko
|
||||
*/
|
||||
|
||||
#ifndef LIBGRPP_UTILS_H
|
||||
#define LIBGRPP_UTILS_H
|
||||
|
||||
int int_max2(int x, int y);
|
||||
|
||||
int int_max3(int x, int y, int z);
|
||||
|
||||
double *alloc_zeros_1d(int n);
|
||||
|
||||
double **alloc_zeros_2d(int n, int m);
|
||||
|
||||
void free_2d(double **array, int n);
|
||||
|
||||
void libgrpp_daxpy(int n, double a, double *x, double *y);
|
||||
|
||||
void libgrpp_multiply_matrices(int M, int N, int K, double *A, double *B,
|
||||
double *C);
|
||||
|
||||
double distance_squared(double *A, double *B);
|
||||
|
||||
double distance(double *A, double *B);
|
||||
|
||||
int points_are_equal(double *a, double *b);
|
||||
|
||||
#endif // LIBGRPP_UTILS_H
|
||||
327
src/grpp/libgrpp.F
Normal file
327
src/grpp/libgrpp.F
Normal file
|
|
@ -0,0 +1,327 @@
|
|||
!--------------------------------------------------------------------------------------------------!
|
||||
! CP2K: A general program to perform molecular dynamics simulations !
|
||||
! Copyright 2000-2025 CP2K developers group <https://cp2k.org> !
|
||||
! !
|
||||
! SPDX-License-Identifier: MIT !
|
||||
!--------------------------------------------------------------------------------------------------!
|
||||
|
||||
!
|
||||
! libgrpp - a library for the evaluation of integrals over
|
||||
! generalized relativistic pseudopotentials.
|
||||
!
|
||||
! Copyright (C) 2021-2023 Alexander Oleynichenko
|
||||
!
|
||||
|
||||
MODULE libgrpp
|
||||
|
||||
INTEGER(4), PARAMETER :: LIBGRPP_CART_ORDER_DIRAC = 0
|
||||
INTEGER(4), PARAMETER :: LIBGRPP_CART_ORDER_TURBOMOLE = 1
|
||||
|
||||
INTEGER(4), PARAMETER :: LIBGRPP_NUCLEAR_MODEL_POINT_CHARGE = 0
|
||||
INTEGER(4), PARAMETER :: LIBGRPP_NUCLEAR_MODEL_CHARGED_BALL = 1
|
||||
INTEGER(4), PARAMETER :: LIBGRPP_NUCLEAR_MODEL_GAUSSIAN = 2
|
||||
INTEGER(4), PARAMETER :: LIBGRPP_NUCLEAR_MODEL_FERMI = 3
|
||||
INTEGER(4), PARAMETER :: LIBGRPP_NUCLEAR_MODEL_FERMI_BUBBLE = 4
|
||||
INTEGER(4), PARAMETER :: LIBGRPP_NUCLEAR_MODEL_POINT_CHARGE_NUMERICAL = 5
|
||||
|
||||
INTERFACE
|
||||
|
||||
SUBROUTINE libgrpp_init()
|
||||
! no arguments
|
||||
END SUBROUTINE libgrpp_init
|
||||
|
||||
SUBROUTINE libgrpp_finalize()
|
||||
! no arguments
|
||||
END SUBROUTINE libgrpp_finalize
|
||||
|
||||
SUBROUTINE libgrpp_set_default_parameters()
|
||||
! no arguments
|
||||
END SUBROUTINE libgrpp_set_default_parameters
|
||||
|
||||
SUBROUTINE libgrpp_set_radial_tolerance(tolerance)
|
||||
REAL(8), INTENT(in) :: tolerance
|
||||
|
||||
END SUBROUTINE libgrpp_set_radial_tolerance
|
||||
|
||||
SUBROUTINE libgrpp_set_angular_screening_tolerance(tolerance)
|
||||
REAL(8), INTENT(in) :: tolerance
|
||||
|
||||
END SUBROUTINE libgrpp_set_angular_screening_tolerance
|
||||
|
||||
SUBROUTINE libgrpp_set_modified_bessel_tolerance(tolerance)
|
||||
REAL(8), INTENT(in) :: tolerance
|
||||
|
||||
END SUBROUTINE libgrpp_set_modified_bessel_tolerance
|
||||
|
||||
SUBROUTINE libgrpp_set_cartesian_order(order)
|
||||
INTEGER(4), INTENT(in) :: order
|
||||
|
||||
END SUBROUTINE libgrpp_set_cartesian_order
|
||||
|
||||
SUBROUTINE libgrpp_type1_integrals( &
|
||||
origin_A, L_A, num_primitives_A, coeffs_A, alpha_A, &
|
||||
origin_B, L_B, num_primitives_B, coeffs_B, alpha_B, &
|
||||
rpp_origin, rpp_num_primitives, rpp_powers, rpp_coeffs, rpp_alpha, &
|
||||
matrix &
|
||||
)
|
||||
! shell centered on atom A
|
||||
REAL(8), DIMENSION(*), INTENT(in) :: origin_A
|
||||
INTEGER(4), INTENT(in) :: L_A, num_primitives_A
|
||||
REAL(8), INTENT(in) :: coeffs_A(*), alpha_A(*)
|
||||
REAL(8), DIMENSION(*), INTENT(in) :: origin_B
|
||||
INTEGER(4), INTENT(in) :: L_B, num_primitives_B
|
||||
REAL(8), INTENT(in) :: coeffs_B(*), alpha_B(*)
|
||||
REAL(8), DIMENSION(*), INTENT(in) :: rpp_origin
|
||||
INTEGER(4), DIMENSION(*), INTENT(in) :: rpp_num_primitives, rpp_powers
|
||||
REAL(8), DIMENSION(*), INTENT(in) :: rpp_coeffs, rpp_alpha
|
||||
REAL(8), DIMENSION(*), INTENT(out) :: matrix
|
||||
|
||||
! shell centered on atom B
|
||||
! pseudopotential expansion
|
||||
! output: matrix with PP integrals
|
||||
|
||||
END SUBROUTINE libgrpp_type1_integrals
|
||||
|
||||
SUBROUTINE libgrpp_type2_integrals( &
|
||||
origin_A, L_A, num_primitives_A, coeffs_A, alpha_A, &
|
||||
origin_B, L_B, num_primitives_B, coeffs_B, alpha_B, &
|
||||
rpp_origin, rpp_ang_momentum, rpp_num_primitives, rpp_powers, rpp_coeffs, rpp_alpha, &
|
||||
matrix &
|
||||
)
|
||||
! shell centered on atom A
|
||||
REAL(8), DIMENSION(*), INTENT(in) :: origin_A
|
||||
INTEGER(4), INTENT(in) :: L_A, num_primitives_A
|
||||
REAL(8), INTENT(in) :: coeffs_A(*), alpha_A(*)
|
||||
REAL(8), DIMENSION(*), INTENT(in) :: origin_B
|
||||
INTEGER(4), INTENT(in) :: L_B, num_primitives_B
|
||||
REAL(8), INTENT(in) :: coeffs_B(*), alpha_B(*)
|
||||
REAL(8), DIMENSION(*), INTENT(in) :: rpp_origin
|
||||
INTEGER(4), INTENT(in) :: rpp_ang_momentum
|
||||
INTEGER(4), DIMENSION(*), INTENT(in) :: rpp_num_primitives, rpp_powers
|
||||
REAL(8), DIMENSION(*), INTENT(in) :: rpp_coeffs, rpp_alpha
|
||||
REAL(8), DIMENSION(*), INTENT(out) :: matrix
|
||||
|
||||
! shell centered on atom B
|
||||
! pseudopotential expansion
|
||||
! output: matrix with PP integrals
|
||||
|
||||
END SUBROUTINE libgrpp_type2_integrals
|
||||
|
||||
SUBROUTINE libgrpp_spin_orbit_integrals( &
|
||||
origin_A, L_A, num_primitives_A, coeffs_A, alpha_A, &
|
||||
origin_B, L_B, num_primitives_B, coeffs_B, alpha_B, &
|
||||
rpp_origin, rpp_ang_momentum, rpp_num_primitives, rpp_powers, rpp_coeffs, rpp_alpha, &
|
||||
so_x_matrix, so_y_matrix, so_z_matrix &
|
||||
)
|
||||
! shell centered on atom A
|
||||
REAL(8), DIMENSION(*), INTENT(in) :: origin_A
|
||||
INTEGER(4), INTENT(in) :: L_A, num_primitives_A
|
||||
REAL(8), INTENT(in) :: coeffs_A(*), alpha_A(*)
|
||||
REAL(8), DIMENSION(*), INTENT(in) :: origin_B
|
||||
INTEGER(4), INTENT(in) :: L_B, num_primitives_B
|
||||
REAL(8), INTENT(in) :: coeffs_B(*), alpha_B(*)
|
||||
REAL(8), DIMENSION(*), INTENT(in) :: rpp_origin
|
||||
INTEGER(4), INTENT(in) :: rpp_ang_momentum
|
||||
INTEGER(4), DIMENSION(*), INTENT(in) :: rpp_num_primitives, rpp_powers
|
||||
REAL(8), DIMENSION(*), INTENT(in) :: rpp_coeffs, rpp_alpha
|
||||
REAL(8), DIMENSION(*), INTENT(out) :: so_x_matrix, so_y_matrix, so_z_matrix
|
||||
|
||||
! shell centered on atom B
|
||||
! pseudopotential expansion
|
||||
! output: matrices with PP integrals
|
||||
|
||||
END SUBROUTINE libgrpp_spin_orbit_integrals
|
||||
|
||||
SUBROUTINE libgrpp_type1_integrals_gradient( &
|
||||
origin_A, L_A, num_primitives_A, coeffs_A, alpha_A, &
|
||||
origin_B, L_B, num_primitives_B, coeffs_B, alpha_B, &
|
||||
rpp_origin, rpp_num_primitives, rpp_powers, rpp_coeffs, rpp_alpha, &
|
||||
point_3d, grad_arep_x, grad_arep_y, grad_arep_z &
|
||||
)
|
||||
! shell centered on atom A
|
||||
REAL(8), DIMENSION(*), INTENT(in) :: origin_A
|
||||
INTEGER(4), INTENT(in) :: L_A, num_primitives_A
|
||||
REAL(8), INTENT(in) :: coeffs_A(*), alpha_A(*)
|
||||
REAL(8), DIMENSION(*), INTENT(in) :: origin_B
|
||||
INTEGER(4), INTENT(in) :: L_B, num_primitives_B
|
||||
REAL(8), INTENT(in) :: coeffs_B(*), alpha_B(*)
|
||||
REAL(8), DIMENSION(*), INTENT(in) :: rpp_origin
|
||||
INTEGER(4), DIMENSION(*), INTENT(in) :: rpp_num_primitives, rpp_powers
|
||||
REAL(8), DIMENSION(*), INTENT(in) :: rpp_coeffs, rpp_alpha, point_3d
|
||||
REAL(8), DIMENSION(*), INTENT(out) :: grad_arep_x, grad_arep_y, grad_arep_z
|
||||
|
||||
! shell centered on atom B
|
||||
! pseudopotential expansion
|
||||
! differentiation wrt the 3d point (x,y,z)
|
||||
! output: matrices d<Int>/dx, d<Int>/dy, d<Int>/dZ
|
||||
|
||||
END SUBROUTINE libgrpp_type1_integrals_gradient
|
||||
|
||||
SUBROUTINE libgrpp_type2_integrals_gradient( &
|
||||
origin_A, L_A, num_primitives_A, coeffs_A, alpha_A, &
|
||||
origin_B, L_B, num_primitives_B, coeffs_B, alpha_B, &
|
||||
rpp_origin, rpp_ang_momentum, rpp_num_primitives, rpp_powers, rpp_coeffs, rpp_alpha, &
|
||||
point_3d, grad_arep_x, grad_arep_y, grad_arep_z &
|
||||
)
|
||||
! shell centered on atom A
|
||||
REAL(8), DIMENSION(*), INTENT(in) :: origin_A
|
||||
INTEGER(4), INTENT(in) :: L_A, num_primitives_A
|
||||
REAL(8), INTENT(in) :: coeffs_A(*), alpha_A(*)
|
||||
REAL(8), DIMENSION(*), INTENT(in) :: origin_B
|
||||
INTEGER(4), INTENT(in) :: L_B, num_primitives_B
|
||||
REAL(8), INTENT(in) :: coeffs_B(*), alpha_B(*)
|
||||
REAL(8), DIMENSION(*), INTENT(in) :: rpp_origin
|
||||
INTEGER(4), INTENT(in) :: rpp_ang_momentum
|
||||
INTEGER(4), DIMENSION(*), INTENT(in) :: rpp_num_primitives, rpp_powers
|
||||
REAL(8), DIMENSION(*), INTENT(in) :: rpp_coeffs, rpp_alpha, point_3d
|
||||
REAL(8), DIMENSION(*), INTENT(out) :: grad_arep_x, grad_arep_y, grad_arep_z
|
||||
|
||||
! shell centered on atom B
|
||||
! pseudopotential expansion
|
||||
! differentiation wrt the 3d point (x,y,z)
|
||||
! output: matrices d<Int>/dx, d<Int>/dy, d<Int>/dZ
|
||||
|
||||
END SUBROUTINE libgrpp_type2_integrals_gradient
|
||||
|
||||
SUBROUTINE libgrpp_spin_orbit_integrals_gradient( &
|
||||
origin_A, L_A, num_primitives_A, coeffs_A, alpha_A, &
|
||||
origin_B, L_B, num_primitives_B, coeffs_B, alpha_B, &
|
||||
rpp_origin, rpp_ang_momentum, rpp_num_primitives, rpp_powers, rpp_coeffs, rpp_alpha, &
|
||||
point_3d, grad_sox_x, grad_sox_y, grad_sox_z, &
|
||||
grad_soy_x, grad_soy_y, grad_soy_z, &
|
||||
grad_soz_x, grad_soz_y, grad_soz_z &
|
||||
)
|
||||
! shell centered on atom A
|
||||
REAL(8), DIMENSION(*), INTENT(in) :: origin_A
|
||||
INTEGER(4), INTENT(in) :: L_A, num_primitives_A
|
||||
REAL(8), INTENT(in) :: coeffs_A(*), alpha_A(*)
|
||||
REAL(8), DIMENSION(*), INTENT(in) :: origin_B
|
||||
INTEGER(4), INTENT(in) :: L_B, num_primitives_B
|
||||
REAL(8), INTENT(in) :: coeffs_B(*), alpha_B(*)
|
||||
REAL(8), DIMENSION(*), INTENT(in) :: rpp_origin
|
||||
INTEGER(4), INTENT(in) :: rpp_ang_momentum
|
||||
INTEGER(4), DIMENSION(*), INTENT(in) :: rpp_num_primitives, rpp_powers
|
||||
REAL(8), DIMENSION(*), INTENT(in) :: rpp_coeffs, rpp_alpha, point_3d
|
||||
REAL(8), DIMENSION(*), INTENT(out) :: grad_sox_x, grad_sox_y, grad_sox_z, &
|
||||
grad_soy_x, grad_soy_y, grad_soy_z, &
|
||||
grad_soz_x, grad_soz_y, grad_soz_z
|
||||
|
||||
! shell centered on atom B
|
||||
! pseudopotential expansion
|
||||
! differentiation wrt the 3d point (x,y,z)
|
||||
! output: matrices d<SO_x>/dx, d<SO_x>/dy, d<SO_x>/dZ
|
||||
! output: matrices d<SO_y>/dx, d<SO_y>/dy, d<SO_y>/dZ
|
||||
! output: matrices d<SO_z>/dx, d<SO_z>/dy, d<SO_z>/dZ
|
||||
|
||||
END SUBROUTINE libgrpp_spin_orbit_integrals_gradient
|
||||
|
||||
END INTERFACE
|
||||
|
||||
CONTAINS
|
||||
|
||||
! **************************************************************************************************
|
||||
!> \brief ...
|
||||
!> \param origin_A ...
|
||||
!> \param L_A ...
|
||||
!> \param num_primitives_A ...
|
||||
!> \param coeffs_A ...
|
||||
!> \param alpha_A ...
|
||||
!> \param origin_B ...
|
||||
!> \param L_B ...
|
||||
!> \param num_primitives_B ...
|
||||
!> \param coeffs_B ...
|
||||
!> \param alpha_B ...
|
||||
!> \param rpp_origin ...
|
||||
!> \param num_oc_shells ...
|
||||
!> \param oc_shells_L ...
|
||||
!> \param oc_shells_J ...
|
||||
!> \param rpp_num_primitives ...
|
||||
!> \param rpp_powers ...
|
||||
!> \param rpp_coeffs ...
|
||||
!> \param rpp_alpha ...
|
||||
!> \param oc_shells_num_primitives ...
|
||||
!> \param oc_shells_coeffs ...
|
||||
!> \param oc_shells_alpha ...
|
||||
!> \param arep_matrix ...
|
||||
!> \param so_x_matrix ...
|
||||
!> \param so_y_matrix ...
|
||||
!> \param so_z_matrix ...
|
||||
! **************************************************************************************************
|
||||
SUBROUTINE libgrpp_outercore_potential_integrals( &
|
||||
origin_A, L_A, num_primitives_A, coeffs_A, alpha_A, &
|
||||
origin_B, L_B, num_primitives_B, coeffs_B, alpha_B, &
|
||||
rpp_origin, num_oc_shells, &
|
||||
oc_shells_L, oc_shells_J, rpp_num_primitives, rpp_powers, rpp_coeffs, rpp_alpha, &
|
||||
oc_shells_num_primitives, oc_shells_coeffs, oc_shells_alpha, &
|
||||
arep_matrix, so_x_matrix, so_y_matrix, so_z_matrix &
|
||||
)
|
||||
|
||||
! shell centered on atom A
|
||||
REAL(8), INTENT(in) :: origin_A(*)
|
||||
INTEGER(4), INTENT(in) :: L_A, num_primitives_A
|
||||
REAL(8), INTENT(in) :: coeffs_A(*), alpha_A(*), origin_B(*)
|
||||
INTEGER(4), INTENT(in) :: L_B, num_primitives_B
|
||||
REAL(8), INTENT(in) :: coeffs_B(*), alpha_B(*), rpp_origin(*)
|
||||
INTEGER(4) :: num_oc_shells
|
||||
INTEGER(4), INTENT(in) :: oc_shells_L(:), oc_shells_J(:), &
|
||||
rpp_num_primitives(:), rpp_powers(:, :)
|
||||
REAL(8), INTENT(in) :: rpp_coeffs(:, :), rpp_alpha(:, :)
|
||||
INTEGER(4) :: oc_shells_num_primitives(:)
|
||||
REAL(8) :: oc_shells_coeffs(:, :), &
|
||||
oc_shells_alpha(:, :)
|
||||
REAL(8), INTENT(out) :: arep_matrix(*), so_x_matrix(*), &
|
||||
so_y_matrix(*), so_z_matrix(*)
|
||||
|
||||
INTEGER :: i, j, ncart1, ncart2
|
||||
|
||||
! shell centered on atom B
|
||||
! pseudopotential expansion
|
||||
! outercore shells
|
||||
! output: matrices with PP integrals
|
||||
! local variables
|
||||
|
||||
ncart1 = (L_A + 1)*(L_A + 2)/2
|
||||
ncart2 = (L_B + 1)*(L_B + 2)/2
|
||||
|
||||
arep_matrix(1:ncart1*ncart2) = 0.0d0
|
||||
so_x_matrix(1:ncart1*ncart2) = 0.0d0
|
||||
so_y_matrix(1:ncart1*ncart2) = 0.0d0
|
||||
so_z_matrix(1:ncart1*ncart2) = 0.0d0
|
||||
|
||||
! the first non-local term:
|
||||
! \sum_{nlj} U*|nlj><nlj| + |nlj><nlj|*U
|
||||
DO i = 1, num_oc_shells
|
||||
CALL libgrpp_outercore_potential_integrals_part_1( &
|
||||
origin_A, L_A, num_primitives_A, coeffs_A, alpha_A, &
|
||||
origin_B, L_B, num_primitives_B, coeffs_B, alpha_B, &
|
||||
rpp_origin, oc_shells_L(i), oc_shells_J(i), &
|
||||
rpp_num_primitives(i), rpp_powers(i, :), rpp_coeffs(i, :), rpp_alpha(i, :), &
|
||||
oc_shells_num_primitives(i), oc_shells_coeffs(i, :), oc_shells_alpha(i, :), &
|
||||
arep_matrix, so_x_matrix, so_y_matrix, so_z_matrix &
|
||||
)
|
||||
END DO
|
||||
|
||||
! the second non-local term:
|
||||
! \sum_{nlj,n'lj} |nlj><nlj| U |n'lj><n'lj|
|
||||
DO i = 1, num_oc_shells
|
||||
DO j = 1, num_oc_shells
|
||||
|
||||
CALL libgrpp_outercore_potential_integrals_part_2( &
|
||||
origin_A, L_A, num_primitives_A, coeffs_A, alpha_A, &
|
||||
origin_B, L_B, num_primitives_B, coeffs_B, alpha_B, &
|
||||
rpp_origin, &
|
||||
oc_shells_L(i), oc_shells_J(i), &
|
||||
rpp_num_primitives(i), rpp_powers(i, :), rpp_coeffs(i, :), rpp_alpha(i, :), &
|
||||
oc_shells_num_primitives(i), oc_shells_coeffs(i, :), oc_shells_alpha(i, :), &
|
||||
oc_shells_L(j), oc_shells_J(j), &
|
||||
rpp_num_primitives(j), rpp_powers(j, :), rpp_coeffs(j, :), rpp_alpha(j, :), &
|
||||
oc_shells_num_primitives(j), oc_shells_coeffs(j, :), oc_shells_alpha(j, :), &
|
||||
arep_matrix, so_x_matrix, so_y_matrix, so_z_matrix &
|
||||
)
|
||||
|
||||
END DO
|
||||
END DO
|
||||
|
||||
END SUBROUTINE libgrpp_outercore_potential_integrals
|
||||
END MODULE libgrpp
|
||||
|
||||
197
src/grpp/libgrpp.h
Normal file
197
src/grpp/libgrpp.h
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
/*----------------------------------------------------------------------------*/
|
||||
/* CP2K: A general program to perform molecular dynamics simulations */
|
||||
/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
|
||||
/* */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* libgrpp - a library for the evaluation of integrals over
|
||||
* generalized relativistic pseudopotentials.
|
||||
*
|
||||
* Copyright (C) 2021-2023 Alexander Oleynichenko
|
||||
*/
|
||||
|
||||
#ifndef LIBGRPP_LIBGRPP_H
|
||||
#define LIBGRPP_LIBGRPP_H
|
||||
|
||||
#include "grpp_parameters.h"
|
||||
#include "libgrpp_types.h"
|
||||
|
||||
/*
|
||||
* other integrals
|
||||
*/
|
||||
|
||||
#include "grpp_kinetic.h"
|
||||
#include "grpp_momentum.h"
|
||||
#include "grpp_overlap.h"
|
||||
#include "grpp_overlap_gradient.h"
|
||||
|
||||
/*
|
||||
* models of nuclear charge density distribution
|
||||
*/
|
||||
|
||||
#include "grpp_nuclear_models.h"
|
||||
|
||||
extern void libgrpp_init();
|
||||
extern void libgrpp_finalize();
|
||||
extern int libgrpp_is_initialized();
|
||||
|
||||
libgrpp_potential_t *libgrpp_new_potential(int L, int J, int num_primitives,
|
||||
int *powers, double *coeffs,
|
||||
double *alpha);
|
||||
|
||||
void libgrpp_delete_potential(libgrpp_potential_t *potential);
|
||||
|
||||
double libgrpp_potential_value(libgrpp_potential_t *potential, double r);
|
||||
|
||||
libgrpp_potential_t *
|
||||
libgrpp_shrink_potential(libgrpp_potential_t *src_potential);
|
||||
|
||||
libgrpp_potential_t *
|
||||
libgrpp_shrink_potential_n0(libgrpp_potential_t *src_potential);
|
||||
|
||||
libgrpp_shell_t *libgrpp_new_shell(double *origin, int L, int num_primitives,
|
||||
double *coeffs, double *alpha);
|
||||
|
||||
int libgrpp_get_shell_size(libgrpp_shell_t *shell);
|
||||
|
||||
void libgrpp_delete_shell(libgrpp_shell_t *shell);
|
||||
|
||||
int *libgrpp_generate_shell_cartesians(int L);
|
||||
|
||||
libgrpp_shell_t *libgrpp_shell_deep_copy(libgrpp_shell_t *src_shell);
|
||||
|
||||
void libgrpp_shell_shrink(libgrpp_shell_t *shell);
|
||||
|
||||
void libgrpp_shell_mult_normcoef(libgrpp_shell_t *shell);
|
||||
|
||||
libgrpp_grpp_t *libgrpp_new_grpp();
|
||||
|
||||
void libgrpp_grpp_set_local_potential(libgrpp_grpp_t *grpp,
|
||||
libgrpp_potential_t *pot);
|
||||
|
||||
void libgrpp_grpp_add_averaged_potential(libgrpp_grpp_t *grpp,
|
||||
libgrpp_potential_t *pot);
|
||||
|
||||
void libgrpp_grpp_add_spin_orbit_potential(libgrpp_grpp_t *grpp,
|
||||
libgrpp_potential_t *pot);
|
||||
|
||||
void libgrpp_grpp_add_outercore_potential(libgrpp_grpp_t *grpp,
|
||||
libgrpp_potential_t *pot,
|
||||
libgrpp_shell_t *oc_shell);
|
||||
|
||||
void libgrpp_delete_grpp(libgrpp_grpp_t *);
|
||||
|
||||
/*
|
||||
* integrators: pseudopotential
|
||||
*/
|
||||
|
||||
void libgrpp_type1_integrals(libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B,
|
||||
double *rpp_origin, libgrpp_potential_t *potential,
|
||||
double *matrix);
|
||||
|
||||
void libgrpp_type2_integrals(libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B,
|
||||
double *rpp_origin, libgrpp_potential_t *potential,
|
||||
double *matrix);
|
||||
|
||||
void libgrpp_spin_orbit_integrals(libgrpp_shell_t *shell_A,
|
||||
libgrpp_shell_t *shell_B, double *rpp_origin,
|
||||
libgrpp_potential_t *potential,
|
||||
double *so_x_matrix, double *so_y_matrix,
|
||||
double *so_z_matrix);
|
||||
|
||||
void libgrpp_outercore_potential_integrals(
|
||||
libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B, double *rpp_origin,
|
||||
int num_oc_shells, libgrpp_potential_t **oc_potentials,
|
||||
libgrpp_shell_t **oc_shells, double *arep, double *esop_x, double *esop_y,
|
||||
double *esop_z);
|
||||
|
||||
void libgrpp_full_grpp_integrals(libgrpp_shell_t *shell_A,
|
||||
libgrpp_shell_t *shell_B,
|
||||
libgrpp_grpp_t *grpp_operator,
|
||||
double *grpp_origin, double *arep_matrix,
|
||||
double *so_x_matrix, double *so_y_matrix,
|
||||
double *so_z_matrix);
|
||||
|
||||
/*
|
||||
* gradients of pseudopotential matrix elements
|
||||
* with respect to nuclear coordinates
|
||||
*/
|
||||
|
||||
void libgrpp_type1_integrals_gradient(libgrpp_shell_t *shell_A,
|
||||
libgrpp_shell_t *shell_B,
|
||||
double *grpp_origin,
|
||||
libgrpp_potential_t *potential,
|
||||
double *point_3d, double **grad_arep);
|
||||
|
||||
void libgrpp_type2_integrals_gradient(libgrpp_shell_t *shell_A,
|
||||
libgrpp_shell_t *shell_B,
|
||||
double *grpp_origin,
|
||||
libgrpp_potential_t *potential,
|
||||
double *point_3d, double **grad_arep);
|
||||
|
||||
void libgrpp_spin_orbit_integrals_gradient(
|
||||
libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B, double *grpp_origin,
|
||||
libgrpp_potential_t *potential, double *point_3d, double **grad_so_x,
|
||||
double **grad_so_y, double **grad_so_z);
|
||||
|
||||
void libgrpp_outercore_potential_integrals_gradient(
|
||||
libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B, double *rpp_origin,
|
||||
int num_oc_shells, libgrpp_potential_t **oc_potentials,
|
||||
libgrpp_shell_t **oc_shells, double *point_3d, double **grad_arep,
|
||||
double **grad_so_x, double **grad_so_y, double **grad_so_z);
|
||||
|
||||
void libgrpp_full_grpp_integrals_gradient(
|
||||
libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B,
|
||||
libgrpp_grpp_t *grpp_operator, double *grpp_origin, double *point_3d,
|
||||
double **grad_arep, double **grad_so_x, double **grad_so_y,
|
||||
double **grad_so_z);
|
||||
|
||||
/*
|
||||
* integrator for nuclear attraction integrals
|
||||
*/
|
||||
|
||||
enum {
|
||||
LIBGRPP_NUCLEAR_MODEL_POINT_CHARGE = 0,
|
||||
LIBGRPP_NUCLEAR_MODEL_CHARGED_BALL,
|
||||
LIBGRPP_NUCLEAR_MODEL_GAUSSIAN,
|
||||
LIBGRPP_NUCLEAR_MODEL_FERMI,
|
||||
LIBGRPP_NUCLEAR_MODEL_FERMI_BUBBLE,
|
||||
LIBGRPP_NUCLEAR_MODEL_POINT_CHARGE_NUMERICAL
|
||||
};
|
||||
|
||||
void libgrpp_nuclear_attraction_integrals(libgrpp_shell_t *shell_A,
|
||||
libgrpp_shell_t *shell_B,
|
||||
double *charge_origin, int charge,
|
||||
int nuclear_model,
|
||||
double *model_params,
|
||||
double *coulomb_matrix);
|
||||
|
||||
void libgrpp_nuclear_attraction_integrals_point_charge(libgrpp_shell_t *shell_A,
|
||||
libgrpp_shell_t *shell_B,
|
||||
double *charge_origin,
|
||||
int charge,
|
||||
double *coulomb_matrix);
|
||||
|
||||
void libgrpp_nuclear_attraction_integrals_charged_ball(libgrpp_shell_t *shell_A,
|
||||
libgrpp_shell_t *shell_B,
|
||||
double *charge_origin,
|
||||
int charge, double r_rms,
|
||||
double *coulomb_matrix);
|
||||
|
||||
void libgrpp_nuclear_attraction_integrals_gaussian_model(
|
||||
libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B, double *charge_origin,
|
||||
int charge, double r_rms, double *coulomb_matrix);
|
||||
|
||||
void libgrpp_nuclear_attraction_integrals_fermi_model(
|
||||
libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B, double *charge_origin,
|
||||
int charge, double fermi_param_c, double fermi_param_a,
|
||||
double *coulomb_matrix);
|
||||
|
||||
void libgrpp_nuclear_attraction_integrals_fermi_bubble_model(
|
||||
libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B, double *charge_origin,
|
||||
int charge, double param_c, double param_a, double param_k,
|
||||
double *coulomb_matrix);
|
||||
|
||||
#endif // LIBGRPP_LIBGRPP_H
|
||||
62
src/grpp/libgrpp_types.h
Normal file
62
src/grpp/libgrpp_types.h
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
/*----------------------------------------------------------------------------*/
|
||||
/* CP2K: A general program to perform molecular dynamics simulations */
|
||||
/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
|
||||
/* */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef __LIBGRPP_TYPES_H__
|
||||
#define __LIBGRPP_TYPES_H__
|
||||
|
||||
typedef struct {
|
||||
int L;
|
||||
int J;
|
||||
int num_primitives;
|
||||
int *powers;
|
||||
double *coeffs;
|
||||
double *alpha;
|
||||
} libgrpp_potential_t;
|
||||
|
||||
typedef struct {
|
||||
int L;
|
||||
int cart_size;
|
||||
int *cart_list;
|
||||
int num_primitives;
|
||||
double *coeffs;
|
||||
double *alpha;
|
||||
double origin[3];
|
||||
} libgrpp_shell_t;
|
||||
|
||||
/**
|
||||
* Generalized relativistic pseudopotential: all-in-one
|
||||
*/
|
||||
typedef struct {
|
||||
int n_arep;
|
||||
int n_esop;
|
||||
int n_oc_shells;
|
||||
libgrpp_potential_t *U_L;
|
||||
libgrpp_potential_t **U_arep;
|
||||
libgrpp_potential_t **U_esop;
|
||||
libgrpp_potential_t **U_oc;
|
||||
libgrpp_shell_t **oc_shells;
|
||||
} libgrpp_grpp_t;
|
||||
/*
|
||||
* maximum angular momentum of basis functions
|
||||
*/
|
||||
#define LIBGRPP_MAX_BASIS_L 10
|
||||
|
||||
/*
|
||||
* maximum angular momentum occuring in the RPP operator
|
||||
*/
|
||||
#define LIBGRPP_MAX_RPP_L 10
|
||||
|
||||
/*
|
||||
* threshold for zero
|
||||
*/
|
||||
#define LIBGRPP_ZERO_THRESH 1e-14
|
||||
|
||||
/*
|
||||
* tolerance of radial integrals evaluation
|
||||
*/
|
||||
#define LIBGRPP_RADIAL_TOL 1e-14
|
||||
#endif
|
||||
|
|
@ -33,10 +33,13 @@ FLAG_EXCEPTIONS = (
|
|||
r"GRID_DO_COLLOCATE",
|
||||
r"INTEL_MKL_VERSION",
|
||||
r"LIBINT2_MAX_AM_eri",
|
||||
r"LIBGRPP",
|
||||
r"M_",
|
||||
r"LIBINT_CONTRACTED_INTS",
|
||||
r"XC_MAJOR_VERSION",
|
||||
r"XC_MINOR_VERSION",
|
||||
r"NDEBUG",
|
||||
r"M_PI",
|
||||
r"OMP_DEFAULT_NONE_WITH_OOP",
|
||||
r"FTN_NO_DEFAULT_INIT",
|
||||
r"_OPENMP",
|
||||
|
|
@ -68,6 +71,8 @@ FLAG_EXCEPTIONS = (
|
|||
r"LIBXSMM_VERSION2",
|
||||
r"LIBXSMM_VERSION3",
|
||||
r"LIBXSMM_VERSION4",
|
||||
r"LIBGRPP_..*",
|
||||
r"TEST_LIBGRPP_..*",
|
||||
r"__LIBXSMM2",
|
||||
r"CPVERSION",
|
||||
r"_WIN32",
|
||||
|
|
@ -118,6 +123,8 @@ C_EXTENSIONS = (".c", ".cu", ".cpp", ".cc", ".h", ".hpp")
|
|||
|
||||
BSD_PATHS = ("src/offload/", "src/grid/", "src/dbm/", "src/base/openmp_trace.c")
|
||||
|
||||
MIT_PATHS = "src/grpp/"
|
||||
|
||||
|
||||
@lru_cache(maxsize=None)
|
||||
def get_install_txt() -> str:
|
||||
|
|
@ -148,7 +155,7 @@ def check_file(path: pathlib.Path) -> List[str]:
|
|||
- undocumented preprocessor flags
|
||||
- stray unicode characters
|
||||
"""
|
||||
warnings = []
|
||||
warnings = [] # type: List[str]
|
||||
|
||||
fn_ext = path.suffix
|
||||
abspath = path.resolve()
|
||||
|
|
@ -192,8 +199,18 @@ def check_file(path: pathlib.Path) -> List[str]:
|
|||
# check banner
|
||||
year = datetime.now(timezone.utc).year
|
||||
bsd_licensed = any(str(path).startswith(p) for p in BSD_PATHS)
|
||||
spdx = "BSD-3-Clause " if bsd_licensed else "GPL-2.0-or-later"
|
||||
# mit_licensed = any(str(path).startswith(p) for p in MIT_PATHS)
|
||||
spdx = "GPL-2.0-or-later"
|
||||
if bsd_licensed:
|
||||
spdx = "BSD-3-Clause "
|
||||
else:
|
||||
if str(path).startswith(MIT_PATHS):
|
||||
spdx = "MIT "
|
||||
else:
|
||||
spdx = "GPL-2.0-or-later"
|
||||
|
||||
if fn_ext == ".F" and not content.startswith(BANNER_F.format(year, spdx)):
|
||||
print(BANNER_F.format(year, spdx))
|
||||
warnings += [f"{path}: Copyright banner malformed"]
|
||||
if fn_ext == ".fypp" and not content.startswith(BANNER_SHELL.format(year, spdx)):
|
||||
warnings += [f"{path}: Copyright banner malformed"]
|
||||
|
|
@ -211,7 +228,6 @@ def check_file(path: pathlib.Path) -> List[str]:
|
|||
PY_SHEBANG = "#!/usr/bin/env python3"
|
||||
if fn_ext == ".py" and is_executable and not content.startswith(f"{PY_SHEBANG}\n"):
|
||||
warnings += [f"{path}: Wrong shebang, please use '{PY_SHEBANG}'"]
|
||||
|
||||
# find all flags
|
||||
flags = set()
|
||||
line_continuation = False
|
||||
|
|
|
|||
|
|
@ -1,164 +0,0 @@
|
|||
diff --git a/CMakeLists.txt b/CMakeLists.txt
|
||||
index b5cc84f..efd61cf 100644
|
||||
--- a/CMakeLists.txt
|
||||
+++ b/CMakeLists.txt
|
||||
@@ -6,12 +6,29 @@
|
||||
#
|
||||
|
||||
cmake_minimum_required(VERSION 3.19)
|
||||
-project(test_libgrpp_c.x C)
|
||||
-project(test_libgrpp_f90.x Fortran)
|
||||
+
|
||||
+include(CMakeDependentOption)
|
||||
+include(CMakePackageConfigHelpers)
|
||||
+
|
||||
+set(VERSION_MAJOR 2023)
|
||||
+set(VERSION_MINOR 12)
|
||||
+set(VERSION_PATCH 25)
|
||||
+
|
||||
+project(libgrpp
|
||||
+ DESCRIPTION "A library for the evaluation of molecular integrals of the generalized relativistic pseudopotential operator (GRPP) over Gaussian functions."
|
||||
+ HOMEPAGE_URL https://github.com/aoleynichenko/libgrpp
|
||||
+ VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}
|
||||
+ LANGUAGES Fortran C)
|
||||
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
find_package(OpenMP)
|
||||
|
||||
+# imply -O3 -DNDEBUG, can be changed with cmake -DCMAKE_BUILD_TYPE=DEBUG,etc....
|
||||
+
|
||||
+set(CMAKE_BUILD_TYPE Release)
|
||||
+
|
||||
+set(libgrpp_APIVERSION ${libgrpp_VERSION_MAJOR}.${libgrpp_VERSION_MINOR})
|
||||
+
|
||||
add_subdirectory(libgrpp)
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS} -O3")
|
||||
@@ -43,10 +60,9 @@ add_executable(test_libgrpp_f90.x
|
||||
test_libgrpp_f90/libgrpp.f90
|
||||
)
|
||||
|
||||
-target_link_libraries(test_libgrpp_c.x libgrpp -lm ${OpenMP_C_LIBRARIES}) # -pg)
|
||||
-target_link_libraries(test_libgrpp_f90.x libgrpp -lm ${OpenMP_C_LIBRARIES})
|
||||
-
|
||||
-
|
||||
+target_link_libraries(test_libgrpp_c.x grpp OpenMP::OpenMP_C m)
|
||||
+target_link_libraries(test_libgrpp_f90.x grpp OpenMP::OpenMP_Fortran m)
|
||||
+set_target_properties(test_libgrpp_f90.x PROPERTIES Fortran_MODULE_DIRECTORY "fortran_modules")
|
||||
# enable testing functionality
|
||||
enable_testing()
|
||||
|
||||
@@ -63,3 +79,42 @@ add_test(NAME UO2 WORKING_DIRECTORY ../test/UO2 COMMAND bash run_test.sh)
|
||||
foreach (t KCs)
|
||||
set_property(TEST ${t} PROPERTY ENVIRONMENT "PATH=${CMAKE_BINARY_DIR}:$ENV{PATH}")
|
||||
endforeach ()
|
||||
+
|
||||
+include(GNUInstallDirs)
|
||||
+
|
||||
+write_basic_package_version_file(
|
||||
+ "${PROJECT_BINARY_DIR}/grppConfigVersion.cmake"
|
||||
+ VERSION "${libgrpp_VERSION}"
|
||||
+ COMPATIBILITY SameMajorVersion)
|
||||
+
|
||||
+if(NOT CMAKE_INSTALL_Fortran_MODULES)
|
||||
+ set(CMAKE_INSTALL_Fortran_MODULES "${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}"
|
||||
+ )
|
||||
+endif()
|
||||
+
|
||||
+configure_file("${PROJECT_SOURCE_DIR}/cmake/grppConfig.cmake.in"
|
||||
+ "${PROJECT_BINARY_DIR}/grppConfig.cmake" @ONLY)
|
||||
+
|
||||
+configure_file(cmake/libgrpp.pc.in libgrpp.pc @ONLY)
|
||||
+
|
||||
+install(FILES "${PROJECT_BINARY_DIR}/grppConfig.cmake"
|
||||
+ "${PROJECT_BINARY_DIR}/grppConfigVersion.cmake"
|
||||
+ DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}")
|
||||
+
|
||||
+install(FILES "${PROJECT_BINARY_DIR}/libgrpp.pc"
|
||||
+ DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
|
||||
+
|
||||
+
|
||||
+
|
||||
+install(
|
||||
+ DIRECTORY "${PROJECT_BINARY_DIR}/fortran_modules"
|
||||
+ DESTINATION "${CMAKE_INSTALL_Fortran_MODULES}/${CMAKE_Fortran_COMPILER_ID}-${CMAKE_Fortran_COMPILER_VERSION}"
|
||||
+ FILES_MATCHING
|
||||
+ PATTERN "*.mod")
|
||||
+
|
||||
+install(
|
||||
+ DIRECTORY "${PROJECT_SOURCE_DIR}/libgrpp"
|
||||
+ DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
|
||||
+ FILES_MATCHING
|
||||
+ PATTERN "*.h")
|
||||
+
|
||||
diff --git a/cmake/grppConfig.cmake.in b/cmake/grppConfig.cmake.in
|
||||
new file mode 100644
|
||||
index 0000000..ce54dc2
|
||||
--- /dev/null
|
||||
+++ b/cmake/grppConfig.cmake.in
|
||||
@@ -0,0 +1,6 @@
|
||||
+cmake_minimum_required(VERSION 3.19)
|
||||
+include(CMakeFindDependencyMacro)
|
||||
+
|
||||
+if(NOT TARGET grpp::grpp)
|
||||
+ include("${CMAKE_CURRENT_LIST_DIR}/grppTargets.cmake")
|
||||
+endif()
|
||||
diff --git a/cmake/libgrpp.pc.in b/cmake/libgrpp.pc.in
|
||||
new file mode 100644
|
||||
index 0000000..dfa3a9b
|
||||
--- /dev/null
|
||||
+++ b/cmake/libgrpp.pc.in
|
||||
@@ -0,0 +1,11 @@
|
||||
+prefix="@CMAKE_INSTALL_PREFIX@"
|
||||
+exec_prefix="${prefix}"
|
||||
+libdir="${prefix}/@CMAKE_INSTALL_LIBDIR@"
|
||||
+includedir="${prefix}/@CMAKE_INSTALL_INCLUDEDIR@"
|
||||
+
|
||||
+Name: @PROJECT_NAME@
|
||||
+Description: @CMAKE_PROJECT_DESCRIPTION@
|
||||
+URL: @CMAKE_PROJECT_HOMEPAGE_URL@
|
||||
+Version: @PROJECT_VERSION@
|
||||
+Cflags: -I"${includedir}/libgrpp" -I"${includedir}/libgrpp/@CMAKE_Fortran_COMPILER_ID@-@CMAKE_Fortran_COMPILER_VERSION@/fortran_modules"
|
||||
+Libs: -L"${libdir}" -lgrpp
|
||||
diff --git a/libgrpp/CMakeLists.txt b/libgrpp/CMakeLists.txt
|
||||
index f579f7b..ad3408c 100644
|
||||
--- a/libgrpp/CMakeLists.txt
|
||||
+++ b/libgrpp/CMakeLists.txt
|
||||
@@ -5,16 +5,7 @@
|
||||
# Copyright (C) 2021-2023 Alexander Oleynichenko
|
||||
#
|
||||
|
||||
-cmake_minimum_required(VERSION 3.19)
|
||||
-project(libgrpp C)
|
||||
-
|
||||
-set(CMAKE_C_STANDARD 11)
|
||||
-
|
||||
-find_package(OpenMP)
|
||||
-set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS} -O3")
|
||||
-#add_compile_options(-pg)
|
||||
-
|
||||
-add_library(libgrpp
|
||||
+add_library(grpp
|
||||
angular_integrals.c
|
||||
binomial.c
|
||||
diff_gaussian.c
|
||||
@@ -53,4 +44,18 @@ add_library(libgrpp
|
||||
utils.c
|
||||
)
|
||||
|
||||
-target_link_libraries(libgrpp -lm)
|
||||
+set_target_properties(grpp PROPERTIES POSITION_INDEPENDENT_CODE ON
|
||||
+ VERSION ${grpp_VERSION}
|
||||
+ SOVERSION ${grpp_APIVERSION})
|
||||
+include(GNUInstallDirs)
|
||||
+install(
|
||||
+ TARGETS grpp
|
||||
+ EXPORT libgrpp_targets
|
||||
+ LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}")
|
||||
+
|
||||
+install(EXPORT libgrpp_targets
|
||||
+ FILE grppTargets.cmake
|
||||
+ NAMESPACE grpp::
|
||||
+ DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}")
|
||||
+
|
||||
+
|
||||
|
|
@ -6,10 +6,6 @@
|
|||
[ "${BASH_SOURCE[0]}" ] && SCRIPT_NAME="${BASH_SOURCE[0]}" || SCRIPT_NAME=$0
|
||||
SCRIPT_DIR="$(cd "$(dirname "$SCRIPT_NAME")/.." && pwd -P)"
|
||||
|
||||
libgrpp_ver="20231225"
|
||||
libgrpp_sha="64d157f1dc95815096b1fd437a5851abeb3425929cf7b2092bf8262db9c5e33d"
|
||||
libgrpp_pkg="libgrpp-main-${libgrpp_ver}.zip"
|
||||
|
||||
source "${SCRIPT_DIR}"/common_vars.sh
|
||||
source "${SCRIPT_DIR}"/tool_kit.sh
|
||||
source "${SCRIPT_DIR}"/signal_trap.sh
|
||||
|
|
@ -18,85 +14,11 @@ source "${INSTALLDIR}"/toolchain.env
|
|||
|
||||
[ -f "${BUILDDIR}/setup_libgrpp" ] && rm "${BUILDDIR}/setup_libgrpp"
|
||||
|
||||
LIBGRPP_CFLAGS=""
|
||||
LIBGRPP_LDFLAGS=""
|
||||
LIBGRPP_LIBS=""
|
||||
! [ -d "${BUILDDIR}" ] && mkdir -p "${BUILDDIR}"
|
||||
cd "${BUILDDIR}"
|
||||
|
||||
case "${with_libgrpp}" in
|
||||
__INSTALL__)
|
||||
echo "==================== Installing LIBGRPP ===================="
|
||||
pkg_install_dir="${INSTALLDIR}/libgrpp-main-${libgrpp_ver}"
|
||||
install_lock_file="$pkg_install_dir/install_successful"
|
||||
|
||||
if verify_checksums "${install_lock_file}"; then
|
||||
echo "libgrpp-main-${libgrpp_ver} is already installed, skipping it."
|
||||
else
|
||||
if [ -f ${libgrpp_pkg} ]; then
|
||||
echo "${libgrpp_pkg} is found"
|
||||
else
|
||||
download_pkg_from_cp2k_org "${libgrpp_sha}" "${libgrpp_pkg}"
|
||||
fi
|
||||
echo "Installing from scratch into ${pkg_install_dir}"
|
||||
[ -d libgrpp-main ] && rm -rf libgrpp-main
|
||||
unzip -qq ${libgrpp_pkg}
|
||||
cd libgrpp-main
|
||||
patch -Np1 -i ${SCRIPT_DIR}/stage3/grpp-cmake.patch
|
||||
mkdir build
|
||||
cd build
|
||||
CC=${CC} FC=${FC} cmake -DCMAKE_INSTALL_PREFIX="${pkg_install_dir}" -DCMAKE_INSTALL_LIBDIR="lib" .. > cmake.log 2>&1 || tail -n ${LOG_LINES} cmake.log
|
||||
make > make.log 2>&1 || tail -n ${LOG_LINES} make.log
|
||||
make install > make.log 2>&1 || tail -n ${LOG_LINES} make.log
|
||||
cd ..
|
||||
write_checksums "${install_lock_file}" "${SCRIPT_DIR}/stage3/$(basename ${SCRIPT_NAME})"
|
||||
fi
|
||||
|
||||
PKG_CONFIG_PATH=${PKG_CONFIG_PATH}:${pkg_install_dir}/lib/pkgconfig:${pkg_install_dir}/lib64/pkgconfig
|
||||
LIBGRPP_CFLAGS=$(pkg-config --cflags libgrpp)
|
||||
LIBGRPP_LDFLAGS="-L'${pkg_install_dir}/lib' -Wl,-rpath,'${pkg_install_dir}/lib'"
|
||||
;;
|
||||
__SYSTEM__)
|
||||
echo "==================== Finding libgrpp from system paths ===================="
|
||||
check_lib -lgrpp "grpp"
|
||||
add_include_from_paths -p LIBGRPP_CFLAGS "grpp.h" $INCLUDE_PATHS
|
||||
add_lib_from_paths LIBGRPP_LDFLAGS "libgrpp.*" $LIB_PATHS
|
||||
;;
|
||||
__DONTUSE__) ;;
|
||||
|
||||
*)
|
||||
echo "==================== Linking libgrpp to user paths ===================="
|
||||
pkg_install_dir="$with_libgrpp"
|
||||
check_dir "${pkg_install_dir}/include"
|
||||
check_dir "${pkg_install_dir}/lib"
|
||||
LIBGRPP_CFLAGS="-I'${pkg_install_dir}/include'"
|
||||
LIBGRPP_LDFLAGS="-L'${pkg_install_dir}/lib'"
|
||||
;;
|
||||
esac
|
||||
if [ "$with_libgrpp" != "__DONTUSE__" ]; then
|
||||
LIBGRPP_LIBS="-lgrpp"
|
||||
cat << EOF > "${BUILDDIR}/setup_libgrpp"
|
||||
export LIBGRPP_VER="${libgrpp_ver}"
|
||||
EOF
|
||||
if [ "$with_libgrpp" != "__SYSTEM__" ]; then
|
||||
cat << EOF >> "${BUILDDIR}/setup_libgrpp"
|
||||
prepend_path LD_LIBRARY_PATH "$pkg_install_dir/lib"
|
||||
prepend_path LD_RUN_PATH "$pkg_install_dir/lib"
|
||||
prepend_path LIBRARY_PATH "$pkg_install_dir/lib"
|
||||
prepend_path PKG_CONFIG_PATH "$pkg_install_dir/lib/pkgconfig"
|
||||
prepend_path CMAKE_PREFIX_PATH "$pkg_install_dir"
|
||||
export LIBGRPP_ROOT="${pkg_install_dir}"
|
||||
EOF
|
||||
cat "${BUILDDIR}/setup_libgrpp" >> $SETUPFILE
|
||||
fi
|
||||
echo "==================== Using libgrpp ===================="
|
||||
|
||||
cat << EOF >> "${BUILDDIR}/setup_libgrpp"
|
||||
export LIBGRPP_CFLAGS="${LIBGRPP_CFLAGS}"
|
||||
export LIBGRPP_LDFLAGS="${LIBGRPP_LDFLAGS}"
|
||||
export LIBGRPP_LIBS="${LIBGRPP_LIBS}"
|
||||
export CP_DFLAGS="\${CP_DFLAGS} -D__LIBGRPP"
|
||||
export CP_CFLAGS="\${CP_CFLAGS} ${LIBGRPP_CFLAGS}"
|
||||
export CP_LDFLAGS="\${CP_LDFLAGS} ${LIBGRPP_LDFLAGS}"
|
||||
export CP_LIBS="${LIBGRPP_LIBS} \${CP_LIBS}"
|
||||
EOF
|
||||
fi
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue