(git:ed6f26b)
Loading...
Searching...
No Matches
grpp_radial_type2_integral.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 * Evaluation of type 2 radial integrals.
17 *
18 * The procedure in general follows that described in:
19 * R. Flores-Moreno et al. Half-numerical evaluation of pseudopotential
20 * integrals. J. Comp. Chem. 27, 1009 (2006) (see formulas (12) and (13) for
21 * radial integrals invoking contracted Gaussian functions and RPPs)
22 *
23 * The Log3 integration scheme used here is detailed in:
24 * C.-K. Skylaris et al. An efficient method for calculating effective core
25 * potential integrals which involve projection operators. Chem. Phys. Lett.
26 * 296, 445 (1998)
27 */
28
29#include <math.h>
30#include <stdlib.h>
31#ifndef M_PI
32#define M_PI 3.14159265358979323846
33#endif
34
36
37#include "grpp_norm_gaussian.h"
38#include "grpp_screening.h"
39#include "grpp_specfunc.h"
40#include "grpp_utils.h"
41
42#define MIN_GRID 31
43#define MAX_GRID 10000
44
52
53/**
54 * RPP and radial contracted Gaussians are pre-calculated on a grid,
55 * and then combined into radial integrals
56 */
57typedef struct {
58 int nr;
59 int n_max;
62 double *r;
63 double *w;
64 double *rpp_values;
65 double **r_N;
66 double **F1;
67 double **F2;
70
71/**
72 * pre-definitions of the functions used below
73 */
74
76 int lambda1, int lambda2,
77 double tolerance, int *converged);
78
80create_radial_type2_grid(int lambda1_max, int lambda2_max, int n_max,
81 radial_type2_params_t *params);
82
84
85static double radial_type2_integrand_fun_contracted(double r, int lambda,
86 double *k, double CA,
87 libgrpp_shell_t *gauss_fun);
88
90
91static void calc_k_values(int nprim, const double *alpha, double CA, double *k);
92
93double libgrpp_gaussian_integral(int n, double a);
94
95/**
96 * Creates table with pre-calculated radial type 2 integrals.
97 */
99 int lambda1_max, int lambda2_max, int n_max, double CA_2, double CB_2,
100 libgrpp_potential_t *potential, libgrpp_shell_t *bra,
101 libgrpp_shell_t *ket) {
102 /*
103 * create empty table containing pre-tabulated radial type 2 integrals
104 */
106 table = (radial_type2_table_t *)calloc(1, sizeof(radial_type2_table_t));
107 table->lambda1_max = lambda1_max;
108 table->lambda2_max = lambda2_max;
109 table->n_max = n_max;
110 table->radial_integrals = (double *)calloc(
111 (lambda1_max + 1) * (lambda2_max + 1) * (n_max + 1), sizeof(double));
112
113 /*
114 * the special case of one-center RPP integrals
115 */
116 if (CA_2 < 1e-14 && CB_2 < 1e-14) {
117
118 for (int i = 0; i < bra->num_primitives; i++) {
119 double alpha_A = bra->alpha[i];
120 double coef_i =
121 bra->coeffs[i] * libgrpp_gaussian_norm_factor(bra->L, 0, 0, alpha_A);
122
123 for (int j = 0; j < ket->num_primitives; j++) {
124 double alpha_B = ket->alpha[j];
125 double coef_j = ket->coeffs[j] *
126 libgrpp_gaussian_norm_factor(ket->L, 0, 0, alpha_B);
127
128 for (int k = 0; k < potential->num_primitives; k++) {
129 double eta = potential->alpha[k];
130 int ni = potential->powers[k];
131 double coef_k = potential->coeffs[k];
132
133 double p = alpha_A + alpha_B + eta;
134 double factor = coef_i * coef_j * coef_k;
135
136 for (int n = 0; n <= n_max; n++) {
137
138 double val_ijk = libgrpp_gaussian_integral(ni + n, p);
139 table->radial_integrals[n] += factor * val_ijk;
140 ;
141 }
142 }
143 }
144 }
145
146 return table;
147 }
148
149 /*
150 * for numerical integration on the grid
151 */
153 params.CA = sqrt(CA_2);
154 params.CB = sqrt(CB_2);
155 params.potential = libgrpp_shrink_potential(potential);
156
157 params.bra = libgrpp_shell_deep_copy(bra);
160
161 params.ket = libgrpp_shell_deep_copy(ket);
164
165 /*
166 * create radial grid
167 */
169 create_radial_type2_grid(lambda1_max, lambda2_max, n_max, &params);
170
171 /*
172 * calculate radial integrals and store them into the table
173 */
174 for (int lambda_1 = 0; lambda_1 <= lambda1_max; lambda_1++) {
175 for (int lambda_2 = 0; lambda_2 <= lambda2_max; lambda_2++) {
176 for (int n = 0; n <= n_max; n++) {
177
178 int converged;
179 double Q = calculate_radial_type2_integral(grid, n, lambda_1, lambda_2,
180 1e-16, &converged);
181
182 // int dim1 = lambda1_max + 1;
183 int dim2 = lambda2_max + 1;
184 int dimn = n_max + 1;
185 table->radial_integrals[dim2 * dimn * lambda_1 + dimn * lambda_2 + n] =
186 Q;
187 }
188 }
189 }
190
191 /*
192 * clean-up
193 */
198
199 return table;
200}
201
202/**
203 * destructor for the table of radial type 2 integrals
204 */
206 free(table->radial_integrals);
207 free(table);
208}
209
210/**
211 * Returns radial integral at complex index (lambda1,lambda2,N)
212 */
214 int lambda1, int lambda2, int n) {
215 // int lambda1_max = table->lambda1_max;
216 int lambda2_max = table->lambda2_max;
217 int n_max = table->n_max;
218 // int dim1 = lambda1_max + 1;
219 int dim2 = lambda2_max + 1;
220 int dimn = n_max + 1;
221
222 double Q =
223 table->radial_integrals[dim2 * dimn * lambda1 + dimn * lambda2 + n];
224
225 return Q;
226}
227
228/**
229 * calculates type 2 radial integral T^N_{lambda1,lambda2}
230 * for the two given contracted gaussian functions and the contracted potential
231 */
233 int lambda1, int lambda2,
234 double tolerance,
235 int *converged) {
236 int nr = MIN_GRID;
237
238 *converged = 0;
239 double prev_sum = 0.0;
240 double sum = 0.0;
241
242 double *w = grid->w;
243 // double *r = grid->r;
244 double *pot_values = grid->rpp_values;
245 double *F1 = grid->F1[lambda1];
246 double *F2 = grid->F2[lambda2];
247 double *r_N = grid->r_N[n];
248
249 /*
250 * first step: integral screening
251 */
252 double CA = grid->params->CA;
253 double CB = grid->params->CB;
254
255 double screened = 0.0;
256 int screen_success = libgrpp_screening_radial_type2(
257 lambda1, lambda2, n, CA * CA, CB * CB, grid->params->bra,
258 grid->params->ket, grid->params->potential, &screened);
259
260 if (screen_success == EXIT_SUCCESS && fabs(screened) < tolerance) {
261 *converged = 1;
262 return screened;
263 }
264
265 /*
266 * second step: calculation on the smallest possible grid
267 */
268 for (int i = 0; i < nr; i++) {
269 sum += w[i] * pot_values[i] * F1[i] * F2[i] * r_N[i];
270 }
271
272 /*
273 * third step: adaptive integration, refinement of the result
274 */
275 do {
276 int idx = nr;
277 nr = 2 * nr + 1;
278 if (nr > MAX_GRID) {
279 break;
280 }
281
282 prev_sum = sum;
283 sum = 0.5 * sum;
284
286
287 for (int i = idx; i < nr; i++) {
288 sum += w[i] * pot_values[i] * F1[i] * F2[i] * r_N[i];
289 }
290
291 if (screen_success == EXIT_SUCCESS &&
292 (fabs(sum) / fabs(screened) < 0.001)) {
293 *converged = 0;
294 continue;
295 }
296
297 *converged = fabs(sum - prev_sum) <= tolerance;
298
299 } while (!(*converged));
300
301 return sum;
302}
303
304/**
305 * Numerical integration on the Log3 grid
306 */
307static radial_type2_grid_t *
308create_radial_type2_grid(int lambda1_max, int lambda2_max, int n_max,
309 radial_type2_params_t *params) {
311 (radial_type2_grid_t *)calloc(1, sizeof(radial_type2_grid_t));
312
313 grid->nr = MIN_GRID;
314 grid->n_max = n_max;
315 grid->lambda1_max = lambda1_max;
316 grid->lambda2_max = lambda2_max;
317 grid->params = params;
318
321 grid->rpp_values = alloc_zeros_1d(MAX_GRID);
322 grid->F1 = alloc_zeros_2d(lambda1_max + 1, MAX_GRID);
323 grid->F2 = alloc_zeros_2d(lambda2_max + 1, MAX_GRID);
324 grid->r_N = alloc_zeros_2d(n_max + 1, MAX_GRID);
325
326 // vectors 'k': k = - 2 * alpha * |CA|
327 double *bra_k = alloc_zeros_1d(params->bra->num_primitives);
328 double *ket_k = alloc_zeros_1d(params->ket->num_primitives);
329 calc_k_values(params->bra->num_primitives, params->bra->alpha, params->CA,
330 bra_k);
331 calc_k_values(params->ket->num_primitives, params->ket->alpha, params->CB,
332 ket_k);
333
334 // initial set of pre-calculated points
335 int nr = grid->nr;
336 const double R = 5.0;
337 const double R3 = R * R * R;
338
339 for (int i = 1; i <= nr; i++) {
340 double xi = i / (nr + 1.0);
341 double xi3 = xi * xi * xi;
342 double ln_xi = log(1 - xi3);
343 double wi = 3 * R3 * xi * xi * ln_xi * ln_xi / ((1 - xi3) * (nr + 1.0));
344 double ri = -R * ln_xi;
345
346 grid->r[i - 1] = ri;
347 grid->w[i - 1] = wi;
348 grid->rpp_values[i - 1] =
349 libgrpp_potential_value(grid->params->potential, ri);
350 for (int n = 0; n <= n_max; n++) {
351 grid->r_N[n][i - 1] = pow(ri, n);
352 }
353 for (int lambda1 = 0; lambda1 <= lambda1_max; lambda1++) {
354 grid->F1[lambda1][i - 1] = radial_type2_integrand_fun_contracted(
355 ri, lambda1, bra_k, params->CA, params->bra);
356 }
357 for (int lambda2 = 0; lambda2 <= lambda2_max; lambda2++) {
358 grid->F2[lambda2][i - 1] = radial_type2_integrand_fun_contracted(
359 ri, lambda2, ket_k, params->CB, params->ket);
360 }
361 }
362
363 free(bra_k);
364 free(ket_k);
365
366 return grid;
367}
368
369/**
370 * constructs new radial grid points
371 */
373 const double R = 5.0;
374 const double R3 = R * R * R;
375
376 if (nr > MAX_GRID) {
377 return;
378 }
379
380 if (nr <= grid->nr) { // nothing to do
381 return;
382 }
383
384 radial_type2_params_t *params = grid->params;
385
386 // vectors 'k': k = - 2 * alpha * |CA|
387 double *bra_k = alloc_zeros_1d(params->bra->num_primitives);
388 double *ket_k = alloc_zeros_1d(params->ket->num_primitives);
389 calc_k_values(params->bra->num_primitives, params->bra->alpha, params->CA,
390 bra_k);
391 calc_k_values(params->ket->num_primitives, params->ket->alpha, params->CB,
392 ket_k);
393
394 // additional set of grid points
395 int idx = grid->nr;
396 for (int i = 1; i <= nr; i += 2) {
397 double xi = i / (nr + 1.0);
398 double xi3 = xi * xi * xi;
399 double ln_xi = log(1 - xi3);
400 double wi = 3 * R3 * xi * xi * ln_xi * ln_xi / ((1 - xi3) * (nr + 1.0));
401 double ri = -R * ln_xi;
402
403 grid->r[idx] = ri;
404 grid->w[idx] = wi;
405 grid->rpp_values[idx] =
406 libgrpp_potential_value(grid->params->potential, ri);
407
408 for (int n = 0; n <= grid->n_max; n++) {
409 grid->r_N[n][idx] = pow(ri, n);
410 }
411
412 for (int lambda1 = 0; lambda1 <= grid->lambda1_max; lambda1++) {
414 ri, lambda1, bra_k, grid->params->CA, params->bra);
415 }
416 for (int lambda2 = 0; lambda2 <= grid->lambda2_max; lambda2++) {
418 ri, lambda2, ket_k, grid->params->CB, params->ket);
419 }
420
421 idx++;
422 }
423
424 grid->nr = nr;
425
426 free(bra_k);
427 free(ket_k);
428}
429
430/**
431 * deallocates memory used for the radial grid
432 */
434 free(grid->r);
435 free(grid->w);
436 free(grid->rpp_values);
437 free_2d(grid->F1, grid->lambda1_max + 1);
438 free_2d(grid->F2, grid->lambda2_max + 1);
439 free_2d(grid->r_N, grid->n_max + 1);
440 free(grid);
441}
442
443/**
444 * Calculate the value of the integrand function
445 */
446static double
447radial_type2_integrand_fun_contracted(double r, int lambda, double *k,
448 double CA, libgrpp_shell_t *gauss_fun) {
449 double F = 0.0;
450 double r_CA_2 = (r - CA) * (r - CA);
451
452 int nprim = gauss_fun->num_primitives;
453 double *alpha = gauss_fun->alpha;
454 double *coeffs = gauss_fun->coeffs;
455
456 for (int i = 0; i < nprim; i++) {
457 double power = -alpha[i] * r_CA_2;
458 F += coeffs[i] * exp(power) *
459 libgrpp_modified_bessel_scaled(lambda, k[i] * r);
460 }
461
462 return F;
463}
464
465static void calc_k_values(int nprim, const double *alpha, double CA,
466 double *k) {
467 for (int i = 0; i < nprim; i++) {
468 k[i] = 2.0 * alpha[i] * CA;
469 }
470}
static GRID_HOST_DEVICE int idx(const orbital a)
Return coset index of given orbital angular momentum.
static void const int const int const int const int const int const double const int const int const int int GRID_CONST_WHEN_COLLOCATE double GRID_CONST_WHEN_INTEGRATE double * grid
static void const int const int i
double libgrpp_gaussian_norm_factor(int n, int l, int m, double alpha)
double libgrpp_potential_value(libgrpp_potential_t *potential, double r)
void libgrpp_delete_potential(libgrpp_potential_t *potential)
libgrpp_potential_t * libgrpp_shrink_potential(libgrpp_potential_t *src_potential)
double libgrpp_gaussian_integral(int n, double a)
static double calculate_radial_type2_integral(radial_type2_grid_t *grid, int n, int lambda1, int lambda2, double tolerance, int *converged)
static void expand_radial_type2_grid(radial_type2_grid_t *grid, int nr)
void libgrpp_delete_radial_type2_integrals(radial_type2_table_t *table)
double libgrpp_get_radial_type2_integral(radial_type2_table_t *table, int lambda1, int lambda2, int n)
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)
#define MAX_GRID
static void calc_k_values(int nprim, const double *alpha, double CA, double *k)
#define MIN_GRID
static double radial_type2_integrand_fun_contracted(double r, int lambda, double *k, double CA, libgrpp_shell_t *gauss_fun)
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)
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)
void libgrpp_delete_shell(libgrpp_shell_t *shell)
Definition grpp_shell.c:103
void libgrpp_shell_mult_normcoef(libgrpp_shell_t *shell)
Definition grpp_shell.c:87
libgrpp_shell_t * libgrpp_shell_deep_copy(libgrpp_shell_t *src_shell)
Definition grpp_shell.c:57
void libgrpp_shell_shrink(libgrpp_shell_t *shell)
Definition grpp_shell.c:69
double libgrpp_modified_bessel_scaled(int n, double x)
void free_2d(double **array, int n)
Definition grpp_utils.c:35
double * alloc_zeros_1d(int n)
Definition grpp_utils.c:23
double ** alloc_zeros_2d(int n, int m)
Definition grpp_utils.c:25
radial_type2_params_t * params
libgrpp_potential_t * potential