Line data Source code
1 : /*----------------------------------------------------------------------------*/ 2 : /* CP2K: A general program to perform molecular dynamics simulations */ 3 : /* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */ 4 : /* */ 5 : /* SPDX-License-Identifier: MIT */ 6 : /*----------------------------------------------------------------------------*/ 7 : 8 : /* 9 : * libgrpp - a library for the evaluation of integrals over 10 : * generalized relativistic pseudopotentials. 11 : * 12 : * Copyright (C) 2021-2023 Alexander Oleynichenko 13 : */ 14 : 15 : /** 16 : * Calculation of overlap integrals. 17 : * 18 : * The recursive Obara-Saika scheme is used to calculate 1- and 2-center overlap 19 : * integrals. For details, see: T. Helgaker, P. Jorgensen, J. Olsen, Molecular 20 : * Electronic-Structure Theory, John Wiley & Sons Ltd, 2000. Chapter 9.3.1, 21 : * "Overlap integrals" 22 : */ 23 : 24 : #include <math.h> 25 : #include <stdlib.h> 26 : #include <string.h> 27 : #ifndef M_PI 28 : #define M_PI 3.14159265358979323846 29 : #endif 30 : 31 : #include "grpp_norm_gaussian.h" 32 : #include "grpp_overlap.h" 33 : #include "libgrpp.h" 34 : 35 : #include "grpp_utils.h" 36 : 37 : static void overlap_integrals_shell_pair_obara_saika(libgrpp_shell_t *shell_A, 38 : libgrpp_shell_t *shell_B, 39 : double alpha_A, 40 : double alpha_B, 41 : double *overlap_matrix); 42 : 43 : /** 44 : * Calculates overlap integral between two shells represented by contracted 45 : * Gaussian functions. 46 : */ 47 0 : void libgrpp_overlap_integrals(libgrpp_shell_t *shell_A, 48 : libgrpp_shell_t *shell_B, 49 : double *overlap_matrix) { 50 0 : int size_A = libgrpp_get_shell_size(shell_A); 51 0 : int size_B = libgrpp_get_shell_size(shell_B); 52 : 53 0 : double *buf = calloc(size_A * size_B, sizeof(double)); 54 : 55 0 : memset(overlap_matrix, 0, size_A * size_B * sizeof(double)); 56 : 57 : // loop over primitives in contractions 58 0 : for (int i = 0; i < shell_A->num_primitives; i++) { 59 0 : for (int j = 0; j < shell_B->num_primitives; j++) { 60 0 : double alpha_i = shell_A->alpha[i]; 61 0 : double alpha_j = shell_B->alpha[j]; 62 0 : double coef_A_i = shell_A->coeffs[i]; 63 0 : double coef_B_j = shell_B->coeffs[j]; 64 : 65 0 : overlap_integrals_shell_pair_obara_saika(shell_A, shell_B, alpha_i, 66 : alpha_j, buf); 67 : 68 0 : libgrpp_daxpy(size_A * size_B, coef_A_i * coef_B_j, buf, overlap_matrix); 69 : } 70 : } 71 : 72 0 : free(buf); 73 0 : } 74 : 75 0 : static void overlap_integrals_shell_pair_obara_saika(libgrpp_shell_t *shell_A, 76 : libgrpp_shell_t *shell_B, 77 : double alpha_A, 78 : double alpha_B, 79 : double *overlap_matrix) { 80 0 : int size_A = libgrpp_get_shell_size(shell_A); 81 0 : int size_B = libgrpp_get_shell_size(shell_B); 82 0 : int L_A = shell_A->L; 83 0 : int L_B = shell_B->L; 84 0 : double N_A = libgrpp_gaussian_norm_factor(L_A, 0, 0, alpha_A); 85 0 : double N_B = libgrpp_gaussian_norm_factor(L_B, 0, 0, alpha_B); 86 : 87 0 : double p = alpha_A + alpha_B; 88 0 : double mu = alpha_A * alpha_B / (alpha_A + alpha_B); 89 0 : double *A = shell_A->origin; 90 0 : double *B = shell_B->origin; 91 : 92 0 : double S[3][LIBGRPP_MAX_BASIS_L][LIBGRPP_MAX_BASIS_L]; 93 : 94 0 : for (int coord = 0; coord < 3; coord++) { 95 0 : double P = (alpha_A * A[coord] + alpha_B * B[coord]) / p; 96 : 97 0 : double X_AB = A[coord] - B[coord]; 98 0 : double X_PA = P - A[coord]; 99 0 : double X_PB = P - B[coord]; 100 0 : double pfac = 1.0 / (2.0 * p); 101 : 102 0 : for (int i = 0; i <= L_A; i++) { 103 0 : for (int j = 0; j <= L_B; j++) { 104 0 : double S_ij = 0.0; 105 : 106 0 : if (i + j == 0) { 107 0 : S[coord][0][0] = sqrt(M_PI / p) * exp(-mu * X_AB * X_AB); 108 0 : continue; 109 : } 110 : 111 0 : if (i == 0) { // upward by j 112 0 : S_ij += X_PB * S[coord][i][j - 1]; 113 0 : if (j - 1 > 0) { 114 0 : S_ij += (j - 1) * pfac * S[coord][i][j - 2]; 115 : } 116 : } else { // upward by i 117 0 : S_ij += X_PA * S[coord][i - 1][j]; 118 0 : if (i - 1 > 0) { 119 0 : S_ij += (i - 1) * pfac * S[coord][i - 2][j]; 120 : } 121 0 : if (j > 0) { 122 0 : S_ij += j * pfac * S[coord][i - 1][j - 1]; 123 : } 124 : } 125 : 126 0 : S[coord][i][j] = S_ij; 127 : } 128 : } 129 : } 130 : 131 : // loop over cartesian functions inside the shells 132 0 : for (int m = 0; m < size_A; m++) { 133 0 : for (int n = 0; n < size_B; n++) { 134 0 : int n_A = shell_A->cart_list[3 * m + 0]; 135 0 : int l_A = shell_A->cart_list[3 * m + 1]; 136 0 : int m_A = shell_A->cart_list[3 * m + 2]; 137 0 : int n_B = shell_B->cart_list[3 * n + 0]; 138 0 : int l_B = shell_B->cart_list[3 * n + 1]; 139 0 : int m_B = shell_B->cart_list[3 * n + 2]; 140 : 141 0 : overlap_matrix[m * size_B + n] = 142 0 : N_A * N_B * S[0][n_A][n_B] * S[1][l_A][l_B] * S[2][m_A][m_B]; 143 : } 144 : } 145 0 : }