(git:ed6f26b)
Loading...
Searching...
No Matches
grpp_screening.c
Go to the documentation of this file.
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 * Screening of radial integrals.
17 *
18 * The technique of screening is adopted from:
19 * R. A. Shaw, J. G. Hill. Prescreening and efficiency in the evaluation
20 * of integrals over ab initio effective core potentials.
21 * J. Chem. Phys. 147, 074108 (2017). doi: 10.1063/1.4986887
22 * (see also Supplementary Material for this article).
23 *
24 * Note that in this publication the transcendental equation (2) for
25 * type 2 integrals is not correct.
26 */
27
28#include <math.h>
29#include <stdlib.h>
30#ifndef M_PI
31#define M_PI 3.14159265358979323846
32#endif
33
34#include "grpp_factorial.h"
35#include "grpp_screening.h"
36#include "grpp_specfunc.h"
37#include "libgrpp.h"
38
39/*
40 * functions defined below in the file
41 */
42
44 int lambda, int n, double CA_2, double CB_2, double alpha_A, double alpha_B,
45 double k, double eta, double *screened_value);
46
47static double screening_type1_equation_for_maximum(double r, int n, int lambda,
48 double p, double k);
49
51 int lambda1, int lambda2, int n, double CA_2, double CB_2, double alpha_A,
52 double alpha_B, double k1, double k2, double eta, double *screened_value);
53
54static double screening_type2_equation_for_maximum(double r, int n, int lambda1,
55 int lambda2, double p,
56 double k1, double k2);
57
58// static double analytic_one_center_rpp_integral_primitive(int L, double
59// alpha1,
60// double alpha2, int
61// n, double zeta);
62
63/**
64 * screening for the type 1 radial integrals
65 * for the pair of contracted gaussian functions.
66 */
67int libgrpp_screening_radial_type1(int lambda, int n, double CA_2, double CB_2,
68 double alpha_A, double alpha_B, double k,
69 double prefactor,
70 libgrpp_potential_t *potential,
71 double *screened_value) {
72 *screened_value = 0.0;
73
74 if (lambda >= 1 && fabs(k) <= LIBGRPP_ZERO_THRESH) {
75 return EXIT_SUCCESS;
76 }
77
78 /*
79 * loop over RPP primitives
80 */
81 for (int iprim = 0; iprim < potential->num_primitives; iprim++) {
82 double eta = potential->alpha[iprim];
83 int ni = n + potential->powers[iprim];
84 double coef = potential->coeffs[iprim];
85
86 double val_i = 0.0;
88 lambda, ni, CA_2, CB_2, alpha_A, alpha_B, k, eta, &val_i);
89 if (err_code == EXIT_FAILURE) {
90 return EXIT_FAILURE;
91 }
92
93 *screened_value += prefactor * coef * val_i;
94 }
95
96 return EXIT_SUCCESS;
97}
98
99/**
100 * screening for the type 1 radial integrals
101 * for the pair of primitive gaussian functions.
102 */
104 int lambda, int n, double CA_2, double CB_2, double alpha_A, double alpha_B,
105 double k, double eta, double *screened_value) {
106 double p = alpha_A + alpha_B + eta;
107 double CA = sqrt(CA_2);
108 double CB = sqrt(CB_2);
109
110 /*
111 * find position of the maximum of the integrand
112 */
113 const double tol = 1e-2;
114 double r0 = (alpha_A * CA + alpha_B * CB) / p;
115 double r0_prev = 0.0;
116
117 int nsteps = 0;
118 do {
119 nsteps++;
120 if (nsteps == 10) {
121 *screened_value = 0.0;
122 return EXIT_FAILURE;
123 }
124
125 r0_prev = r0;
126 r0 = screening_type1_equation_for_maximum(r0, n, lambda, p, k);
127 } while (fabs(r0 - r0_prev) > tol);
128
129 /*
130 * envelope function for the integrand
131 */
132 *screened_value =
133 sqrt(M_PI / p) * pow(r0, n) *
134 libgrpp_modified_bessel_scaled(lambda, k * r0) *
135 exp(-p * r0 * r0 - alpha_A * CA_2 - alpha_B * CB_2 + k * r0) * 0.5 *
136 (1 + erf(sqrt(p) * r0));
137
138 return EXIT_SUCCESS;
139}
140
141/**
142 * transcendental equation for finding maximum of the type 1 integrand
143 */
144static double screening_type1_equation_for_maximum(double r, int n, int lambda,
145 double p, double k) {
146 double K_ratio = 0.0;
147 if (lambda == 0) {
148 K_ratio = libgrpp_modified_bessel_scaled(1, k * r) /
150 } else {
151 K_ratio = libgrpp_modified_bessel_scaled(lambda - 1, k * r) /
152 libgrpp_modified_bessel_scaled(lambda, k * r);
153 }
154
155 double a = n + K_ratio * k * r;
156 if (lambda > 0) {
157 a = a - lambda - 1;
158 }
159
160 return sqrt(a / (2.0 * p));
161}
162
163/**
164 * screening for the type 2 radial integrals
165 * for the pair of contracted gaussian functions.
166 */
167int libgrpp_screening_radial_type2(int lambda1, int lambda2, int n, double CA_2,
168 double CB_2, libgrpp_shell_t *bra,
169 libgrpp_shell_t *ket,
170 libgrpp_potential_t *potential,
171 double *screened_value) {
172 *screened_value = 0.0;
173
174 double CA = sqrt(CA_2);
175 double CB = sqrt(CB_2);
176
177 /*
178 * loop over 'bra' contracted function
179 */
180 for (int i = 0; i < bra->num_primitives; i++) {
181 double alpha_A = bra->alpha[i];
182 double coef_i = bra->coeffs[i];
183 double k1 = 2 * alpha_A * CA;
184
185 /*
186 * loop over 'ket' contracted function
187 */
188 for (int j = 0; j < ket->num_primitives; j++) {
189 double alpha_B = ket->alpha[j];
190 double coef_j = ket->coeffs[j];
191 double k2 = 2 * alpha_B * CB;
192
193 /*
194 * loop over RPP primitives
195 */
196 for (int k = 0; k < potential->num_primitives; k++) {
197 double eta = potential->alpha[k];
198 int ni = n + potential->powers[k];
199 double coef_k = potential->coeffs[k];
200
201 double val_ijk = 0.0;
203 lambda1, lambda2, ni, CA_2, CB_2, alpha_A, alpha_B, k1, k2, eta,
204 &val_ijk);
205 if (err_code == EXIT_FAILURE) {
206 return EXIT_FAILURE;
207 }
208
209 *screened_value += coef_i * coef_j * coef_k * val_ijk;
210 }
211 }
212 }
213
214 return EXIT_SUCCESS;
215}
216
217/**
218 * Analytically evaluates Gaussian integral:
219 * \int_0^\infty r^n e^(-a r^2) dr
220 */
221double libgrpp_gaussian_integral(int n, double a) {
222 if (n % 2 == 0) {
223 int k = n / 2;
224 return libgrpp_double_factorial(2 * k - 1) / (pow(2.0, k + 1) * pow(a, k)) *
225 sqrt(M_PI / a);
226 } else {
227 int k = (n - 1) / 2;
228 return libgrpp_factorial(k) / (2.0 * pow(a, k + 1));
229 }
230}
231
232/**
233 * screening for the type 2 radial integrals
234 * for the pair of primitive gaussian functions.
235 */
237 int lambda1, int lambda2, int n, double CA_2, double CB_2, double alpha_A,
238 double alpha_B, double k1, double k2, double eta, double *screened_value) {
239 *screened_value = 0.0;
240
241 if (lambda1 >= 1 && fabs(k1) <= LIBGRPP_ZERO_THRESH) {
242 return EXIT_SUCCESS;
243 }
244 if (lambda2 >= 1 && fabs(k2) <= LIBGRPP_ZERO_THRESH) {
245 return EXIT_SUCCESS;
246 }
247
248 double p = alpha_A + alpha_B + eta;
249 double CA = sqrt(CA_2);
250 double CB = sqrt(CB_2);
251
252 /*
253 * special case:
254 * lambda1 = lambda2 = 0,
255 * k1 = k2 = 0.
256 * => M_0(0) = 1
257 * => we have one-center integral which can be evaluated analytically
258 */
259 if (lambda1 == 0 && lambda2 == 0) {
260 if (fabs(k1) <= LIBGRPP_ZERO_THRESH && fabs(k2) <= LIBGRPP_ZERO_THRESH) {
261 *screened_value = exp(-alpha_A * CA * CA - alpha_B * CB * CB) *
263 return EXIT_SUCCESS;
264 }
265 }
266
267 /*
268 * find position of the maximum of the integrand
269 */
270 const double tol = 1e-2;
271 double r0 = (alpha_A * CA + alpha_B * CB) / p;
272 double r0_prev = 0.0;
273 int nsteps = 0;
274
275 do {
276 nsteps++;
277 if (nsteps == 5) {
278 *screened_value = 0.0;
279 return EXIT_FAILURE;
280 }
281 r0_prev = r0;
282 r0 = screening_type2_equation_for_maximum(r0, n, lambda1, lambda2, p, k1,
283 k2);
284 } while (fabs(r0 - r0_prev) > tol);
285
286 /*
287 * envelope function for the integrand
288 */
289 *screened_value = sqrt(M_PI / p) * pow(r0, n) *
290 libgrpp_modified_bessel_scaled(lambda1, k1 * r0) *
291 libgrpp_modified_bessel_scaled(lambda2, k2 * r0) *
292 exp(-eta * r0 * r0 - alpha_A * (r0 - CA) * (r0 - CA) -
293 alpha_B * (r0 - CB) * (r0 - CB)) *
294 0.5 * (1 + erf(sqrt(p) * r0));
295
296 return EXIT_SUCCESS;
297}
298
299/**
300 * transcendental equation for finding maximum of the type 2 integrand
301 */
302static double screening_type2_equation_for_maximum(double r, int n, int lambda1,
303 int lambda2, double p,
304 double k1, double k2) {
305 double K1_ratio = 0.0;
306 double k1_r = k1 * r;
307 if (lambda1 == 0) {
308 K1_ratio = libgrpp_modified_bessel_scaled(1, k1_r) /
310 } else {
311 K1_ratio = libgrpp_modified_bessel_scaled(lambda1 - 1, k1_r) /
312 libgrpp_modified_bessel_scaled(lambda1, k1_r);
313 }
314
315 double K2_ratio = 0.0;
316 double k2_r = k2 * r;
317 if (lambda2 == 0) {
318 K2_ratio = libgrpp_modified_bessel_scaled(1, k2_r) /
320 } else {
321 K2_ratio = libgrpp_modified_bessel_scaled(lambda2 - 1, k2_r) /
322 libgrpp_modified_bessel_scaled(lambda2, k2_r);
323 }
324
325 double a = K1_ratio * k1_r + K2_ratio * k2_r + n;
326
327 if (lambda1 > 0) {
328 a = a - lambda1 - 1;
329 }
330 if (lambda2 > 0) {
331 a = a - lambda2 - 1;
332 }
333
334 return sqrt(a / (2.0 * p));
335}
static void const int const int i
double libgrpp_factorial(int n)
double libgrpp_double_factorial(int n)
double libgrpp_gaussian_integral(int n, double a)
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)
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)
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)
static double screening_type2_equation_for_maximum(double r, int n, int lambda1, int lambda2, double p, double k1, double k2)
static double screening_type1_equation_for_maximum(double r, int n, int lambda, double p, double k)
#define M_PI
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)
double libgrpp_modified_bessel_scaled(int n, double x)
#define LIBGRPP_ZERO_THRESH