(git:ed6f26b)
Loading...
Searching...
No Matches
grpp_integrals_gradient.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#include "libgrpp.h"
16
17#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
20
21#include "grpp_diff_gaussian.h"
22#include "grpp_utils.h"
23
25 libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B,
26 libgrpp_grpp_t *grpp_operator, double *grpp_origin, double **grad_arep,
27 double **grad_so_x, double **grad_so_y, double **grad_so_z, double factor);
28
30 libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B,
31 libgrpp_grpp_t *grpp_operator, double *grpp_origin,
32 double **arep_matrix_down, double **so_x_matrix_down,
33 double **so_y_matrix_down, double **so_z_matrix_down,
34 double **arep_matrix_up, double **so_x_matrix_up, double **so_y_matrix_up,
35 double **so_z_matrix_up, int *cart_size_down, int *cart_size_up);
36
38 libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B,
39 libgrpp_grpp_t *grpp_operator, double *grpp_origin, double **grad_arep,
40 double **grad_so_x, double **grad_so_y, double **grad_so_z, double factor);
41
43 libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B,
44 libgrpp_grpp_t *grpp_operator, double *grpp_origin,
45 double **arep_matrix_down, double **so_x_matrix_down,
46 double **so_y_matrix_down, double **so_z_matrix_down,
47 double **arep_matrix_up, double **so_x_matrix_up, double **so_y_matrix_up,
48 double **so_z_matrix_up, int *cart_size_down, int *cart_size_up);
49
51 libgrpp_shell_t *shell_B,
52 libgrpp_grpp_t *grpp_operator,
53 double *grpp_origin, double **grad_arep,
54 double **grad_so_x, double **grad_so_y,
55 double **grad_so_z, int diff_bra,
56 double factor);
57
59 libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B,
60 libgrpp_grpp_t *grpp_operator, double *grpp_origin,
61 double **arep_matrix_down, double **so_x_matrix_down,
62 double **so_y_matrix_down, double **so_z_matrix_down,
63 double **arep_matrix_up, double **so_x_matrix_up, double **so_y_matrix_up,
64 double **so_z_matrix_up, int *cart_size_down, int *cart_size_up,
65 int diff_bra);
66
67extern int libgrpp_nlm_to_linear(int *nlm);
68
70
71void libgrpp_dealloc_gradients(double **grad);
72
73/**
74 * Analytic calculation of gradients of LOCAL potential integrals for a given
75 * shell pair with respect to the point 'point_3d'.
76 */
78 libgrpp_shell_t *shell_B,
79 double *grpp_origin,
80 libgrpp_potential_t *potential,
81 double *point_3d, double **grad_arep) {
82 libgrpp_grpp_t *grpp_operator = libgrpp_new_grpp();
83 libgrpp_grpp_set_local_potential(grpp_operator, potential);
84
85 /*
86 * these arrays are not actually used.
87 * they are needed only in order to use the
88 * libgrpp_full_grpp_integrals_gradient() routine.
89 */
90 double **stub_grad_so_x = libgrpp_alloc_gradients(shell_A, shell_B);
91 double **stub_grad_so_y = libgrpp_alloc_gradients(shell_A, shell_B);
92 double **stub_grad_so_z = libgrpp_alloc_gradients(shell_A, shell_B);
93
95 shell_A, shell_B, grpp_operator, grpp_origin, point_3d, grad_arep,
96 stub_grad_so_x, stub_grad_so_y, stub_grad_so_z);
97
98 libgrpp_dealloc_gradients(stub_grad_so_x);
99 libgrpp_dealloc_gradients(stub_grad_so_y);
100 libgrpp_dealloc_gradients(stub_grad_so_z);
101
102 grpp_operator->U_L = NULL;
103 libgrpp_delete_grpp(grpp_operator);
104}
105
106/**
107 * Analytic calculation of gradients of SEMI-LOCAL potential integrals for a
108 * given shell pair with respect to the point 'point_3d'.
109 */
111 libgrpp_shell_t *shell_B,
112 double *grpp_origin,
113 libgrpp_potential_t *potential,
114 double *point_3d, double **grad_arep) {
115 libgrpp_grpp_t *grpp_operator = libgrpp_new_grpp();
116 libgrpp_grpp_add_averaged_potential(grpp_operator, potential);
117
118 /*
119 * these arrays are not actually used.
120 * they are needed only in order to use the
121 * libgrpp_full_grpp_integrals_gradient() routine.
122 */
123 double **stub_grad_so_x = libgrpp_alloc_gradients(shell_A, shell_B);
124 double **stub_grad_so_y = libgrpp_alloc_gradients(shell_A, shell_B);
125 double **stub_grad_so_z = libgrpp_alloc_gradients(shell_A, shell_B);
126
128 shell_A, shell_B, grpp_operator, grpp_origin, point_3d, grad_arep,
129 stub_grad_so_x, stub_grad_so_y, stub_grad_so_z);
130
131 libgrpp_dealloc_gradients(stub_grad_so_x);
132 libgrpp_dealloc_gradients(stub_grad_so_y);
133 libgrpp_dealloc_gradients(stub_grad_so_z);
134
135 grpp_operator->n_arep = 0;
136 libgrpp_delete_grpp(grpp_operator);
137}
138
139/**
140 * Analytic calculation of gradients of integrals over the effective spin-orbit
141 * operator (potential) for a given shell pair (with respect to the point
142 * 'point_3d').
143 */
145 libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B, double *grpp_origin,
146 libgrpp_potential_t *potential, double *point_3d, double **grad_so_x,
147 double **grad_so_y, double **grad_so_z) {
148 libgrpp_grpp_t *grpp_operator = libgrpp_new_grpp();
149 libgrpp_grpp_add_spin_orbit_potential(grpp_operator, potential);
150
151 /*
152 * this array is not actually used and is needed only in order
153 * to use the libgrpp_full_grpp_integrals_gradient() routine.
154 */
155 double **stub_grad_arep = libgrpp_alloc_gradients(shell_A, shell_B);
156
157 libgrpp_full_grpp_integrals_gradient(shell_A, shell_B, grpp_operator,
158 grpp_origin, point_3d, stub_grad_arep,
159 grad_so_x, grad_so_y, grad_so_z);
160
161 /*
162 * inside the libgrpp_full_grpp_integrals_gradient() function
163 * the SO potential was scaled by 2/(2L+1). Thus the result has to be
164 * re-scaled by (2L+1)/2 to get rid of any problems with pre-factor
165 */
166 int L = potential->L;
167 int buf_size = shell_A->cart_size * shell_B->cart_size;
168 for (int icoord = 0; icoord < 3; icoord++) {
169 for (int i = 0; i < buf_size; i++) {
170 grad_so_x[icoord][i] *= (2.0 * L + 1.0) / 2.0;
171 grad_so_y[icoord][i] *= (2.0 * L + 1.0) / 2.0;
172 grad_so_z[icoord][i] *= (2.0 * L + 1.0) / 2.0;
173 }
174 }
175
176 libgrpp_dealloc_gradients(stub_grad_arep);
177
178 grpp_operator->n_esop = 0;
179 libgrpp_delete_grpp(grpp_operator);
180}
181
183 libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B, double *rpp_origin,
184 int num_oc_shells, libgrpp_potential_t **oc_potentials,
185 libgrpp_shell_t **oc_shells, double *point_3d, double **grad_arep,
186 double **grad_so_x, double **grad_so_y, double **grad_so_z) {
187 libgrpp_grpp_t *grpp_operator = libgrpp_new_grpp();
188 for (int ioc = 0; ioc < num_oc_shells; ioc++) {
189 libgrpp_grpp_add_outercore_potential(grpp_operator, oc_potentials[ioc],
190 oc_shells[ioc]);
191 }
192
193 libgrpp_full_grpp_integrals_gradient(shell_A, shell_B, grpp_operator,
194 rpp_origin, point_3d, grad_arep,
195 grad_so_x, grad_so_y, grad_so_z);
196
197 grpp_operator->n_oc_shells = 0;
198 libgrpp_delete_grpp(grpp_operator);
199}
200
201/**
202 * Analytic calculation of gradients of GRPP integrals for a given shell pair
203 * with respect to the point 'point_3d'.
204 * (for the full GRPP operator which includes local, semi-local and non-local
205 * parts)
206 */
208 libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B,
209 libgrpp_grpp_t *grpp_operator, double *grpp_origin, double *point_3d,
210 double **grad_arep, double **grad_so_x, double **grad_so_y,
211 double **grad_so_z) {
212 int cart_size_A = shell_A->cart_size;
213 int cart_size_B = shell_B->cart_size;
214 int buf_size = cart_size_A * cart_size_B;
215
216 /*
217 * initialization: set all gradients to zero
218 */
219 for (int icoord = 0; icoord < 3; icoord++) {
220 memset(grad_arep[icoord], 0, sizeof(double) * buf_size);
221 memset(grad_so_x[icoord], 0, sizeof(double) * buf_size);
222 memset(grad_so_y[icoord], 0, sizeof(double) * buf_size);
223 memset(grad_so_z[icoord], 0, sizeof(double) * buf_size);
224 }
225
226 /*
227 * d<AAA>/d... = 0
228 */
229 if (points_are_equal(shell_A->origin, grpp_origin) &&
230 points_are_equal(shell_B->origin, grpp_origin)) {
231 return;
232 }
233
234 /*
235 * d<ACB>/dD = 0
236 */
237 if (!points_are_equal(shell_A->origin, point_3d) &&
238 !points_are_equal(shell_B->origin, point_3d) &&
239 !points_are_equal(grpp_origin, point_3d)) {
240 return;
241 }
242
243 double *A = shell_A->origin;
244 double *B = shell_B->origin;
245 double *C = grpp_origin;
246 double *D = point_3d;
247
248 const int diff_bra = 1;
249 const int diff_ket = 0;
250
251 /*
252 * Type ACB
253 */
254 if (!points_are_equal(A, C) && !points_are_equal(C, B) &&
255 !points_are_equal(A, B)) {
256 if (points_are_equal(A, D)) {
257 grpp_gradient_contribution(shell_A, shell_B, grpp_operator, grpp_origin,
258 grad_arep, grad_so_x, grad_so_y, grad_so_z,
259 diff_bra, +1.0);
260 }
261 if (points_are_equal(B, D)) {
262 grpp_gradient_contribution(shell_A, shell_B, grpp_operator, grpp_origin,
263 grad_arep, grad_so_x, grad_so_y, grad_so_z,
264 diff_ket, +1.0);
265 }
266 if (points_are_equal(C, D)) {
267 grpp_gradient_contribution(shell_A, shell_B, grpp_operator, grpp_origin,
268 grad_arep, grad_so_x, grad_so_y, grad_so_z,
269 diff_bra, -1.0);
270 grpp_gradient_contribution(shell_A, shell_B, grpp_operator, grpp_origin,
271 grad_arep, grad_so_x, grad_so_y, grad_so_z,
272 diff_ket, -1.0);
273 }
274 }
275
276 /*
277 * Type ACA
278 */
279 if (points_are_equal(A, B) && !points_are_equal(A, C)) {
280 if (points_are_equal(A, D)) {
281 grpp_gradient_diff_bra_contribution(shell_A, shell_B, grpp_operator,
282 grpp_origin, grad_arep, grad_so_x,
283 grad_so_y, grad_so_z, +1.0);
284 grpp_gradient_diff_ket_contribution(shell_A, shell_B, grpp_operator,
285 grpp_origin, grad_arep, grad_so_x,
286 grad_so_y, grad_so_z, +1.0);
287 } else {
288 grpp_gradient_diff_bra_contribution(shell_A, shell_B, grpp_operator,
289 grpp_origin, grad_arep, grad_so_x,
290 grad_so_y, grad_so_z, -1.0);
291 grpp_gradient_diff_ket_contribution(shell_A, shell_B, grpp_operator,
292 grpp_origin, grad_arep, grad_so_x,
293 grad_so_y, grad_so_z, -1.0);
294 }
295 }
296
297 /*
298 * Type ACC
299 */
300 if (!points_are_equal(A, C) && points_are_equal(C, B)) {
301 if (points_are_equal(A, D)) {
302 grpp_gradient_contribution(shell_A, shell_B, grpp_operator, grpp_origin,
303 grad_arep, grad_so_x, grad_so_y, grad_so_z,
304 diff_bra, +1.0);
305 } else {
306 grpp_gradient_contribution(shell_A, shell_B, grpp_operator, grpp_origin,
307 grad_arep, grad_so_x, grad_so_y, grad_so_z,
308 diff_bra, -1.0);
309 }
310 }
311
312 /*
313 * Type CCB
314 */
315 if (points_are_equal(A, C) && !points_are_equal(C, B)) {
316 if (points_are_equal(B, D)) {
317 grpp_gradient_contribution(shell_A, shell_B, grpp_operator, grpp_origin,
318 grad_arep, grad_so_x, grad_so_y, grad_so_z,
319 diff_ket, +1.0);
320 } else {
321 grpp_gradient_contribution(shell_A, shell_B, grpp_operator, grpp_origin,
322 grad_arep, grad_so_x, grad_so_y, grad_so_z,
323 diff_ket, -1.0);
324 }
325 }
326}
327
328/**
329 * Calculates contribution to gradients arising from the < df/dA | V | g > term:
330 *
331 * grad += factor * < df/dA | V | g >
332 *
333 * (bra basis function is differentiated).
334 */
336 libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B,
337 libgrpp_grpp_t *grpp_operator, double *grpp_origin, double **grad_arep,
338 double **grad_so_x, double **grad_so_y, double **grad_so_z, double factor) {
339 /*
340 * calculate integrals < df/dA | V | B >
341 */
342 double *arep_matrix_down = NULL;
343 double *so_x_matrix_down = NULL;
344 double *so_y_matrix_down = NULL;
345 double *so_z_matrix_down = NULL;
346 double *arep_matrix_up = NULL;
347 double *so_x_matrix_up = NULL;
348 double *so_y_matrix_up = NULL;
349 double *so_z_matrix_up = NULL;
350 int cart_size_down = 0;
351 int cart_size_up = 0;
352
354 shell_A, shell_B, grpp_operator, grpp_origin, &arep_matrix_down,
355 &so_x_matrix_down, &so_y_matrix_down, &so_z_matrix_down, &arep_matrix_up,
356 &so_x_matrix_up, &so_y_matrix_up, &so_z_matrix_up, &cart_size_down,
357 &cart_size_up);
358
359 /*
360 * construct contributions to gradients:
361 * d<A|V|B>/dA += < df/dA | V | B >
362 */
363 for (int icoord = 0; icoord < 3; icoord++) {
364 for (int i = 0; i < shell_A->cart_size; i++) {
365 for (int j = 0; j < shell_B->cart_size; j++) {
366
367 int bra_nlm[3];
368 bra_nlm[0] = shell_A->cart_list[3 * i + 0];
369 bra_nlm[1] = shell_A->cart_list[3 * i + 1];
370 bra_nlm[2] = shell_A->cart_list[3 * i + 2];
371
372 int ket_nlm[3];
373 ket_nlm[0] = shell_B->cart_list[3 * j + 0];
374 ket_nlm[1] = shell_B->cart_list[3 * j + 1];
375 ket_nlm[2] = shell_B->cart_list[3 * j + 2];
376
377 int index = i * shell_B->cart_size + j;
378
379 /*
380 * contribution from the L-1 gaussian
381 */
382 if (shell_A->L > 0) {
383 bra_nlm[icoord] -= 1;
384 int bra_index = libgrpp_nlm_to_linear(bra_nlm);
385 int ket_index = libgrpp_nlm_to_linear(ket_nlm);
386 bra_nlm[icoord] += 1;
387
388 grad_arep[icoord][index] -=
389 factor * bra_nlm[icoord] *
390 arep_matrix_down[shell_B->cart_size * bra_index + ket_index];
391 grad_so_x[icoord][index] -=
392 factor * bra_nlm[icoord] *
393 so_x_matrix_down[shell_B->cart_size * bra_index + ket_index];
394 grad_so_y[icoord][index] -=
395 factor * bra_nlm[icoord] *
396 so_y_matrix_down[shell_B->cart_size * bra_index + ket_index];
397 grad_so_z[icoord][index] -=
398 factor * bra_nlm[icoord] *
399 so_z_matrix_down[shell_B->cart_size * bra_index + ket_index];
400 }
401
402 /*
403 * contribution from the L+1 gaussian
404 */
405 bra_nlm[icoord] += 1;
406 int bra_index = libgrpp_nlm_to_linear(bra_nlm);
407 int ket_index = libgrpp_nlm_to_linear(ket_nlm);
408 bra_nlm[icoord] -= 1;
409
410 grad_arep[icoord][index] +=
411 factor * arep_matrix_up[shell_B->cart_size * bra_index + ket_index];
412 grad_so_x[icoord][index] +=
413 factor * so_x_matrix_up[shell_B->cart_size * bra_index + ket_index];
414 grad_so_y[icoord][index] +=
415 factor * so_y_matrix_up[shell_B->cart_size * bra_index + ket_index];
416 grad_so_z[icoord][index] +=
417 factor * so_z_matrix_up[shell_B->cart_size * bra_index + ket_index];
418 }
419 }
420 }
421
422 if (arep_matrix_down) {
423 free(arep_matrix_down);
424 free(so_x_matrix_down);
425 free(so_y_matrix_down);
426 free(so_z_matrix_down);
427 }
428 free(arep_matrix_up);
429 free(so_x_matrix_up);
430 free(so_y_matrix_up);
431 free(so_z_matrix_up);
432}
433
434/**
435 * To assemble the contribution < df/dA | V | g > to gradients, one have to
436 * differentiate a Gaussian function. Such a differentiation yields two
437 * Gaussians with angular momenta L-1 ("down") and L+1 ("up"): dG/dA -> G(L-1)
438 * and G(L+1)
439 *
440 * This function constructs overlap matrices with these "downgraded" and
441 * "upgraded" Gaussian functions: < G(L-1) | V | G' > and < G(L+1) | V | G' >
442 *
443 */
445 libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B,
446 libgrpp_grpp_t *grpp_operator, double *grpp_origin,
447 double **arep_matrix_down, double **so_x_matrix_down,
448 double **so_y_matrix_down, double **so_z_matrix_down,
449 double **arep_matrix_up, double **so_x_matrix_up, double **so_y_matrix_up,
450 double **so_z_matrix_up, int *cart_size_down, int *cart_size_up) {
451 /*
452 * differentiation of contracted Gaussian functions
453 */
454 libgrpp_shell_t *shell_A_down = NULL;
455 libgrpp_shell_t *shell_A_up = NULL;
456 libgrpp_differentiate_shell(shell_A, &shell_A_down, &shell_A_up);
457
458 *cart_size_down = 0;
459 if (shell_A_down != NULL) {
460 *cart_size_down = shell_A_down->cart_size;
461 }
462 *cart_size_up = shell_A_up->cart_size;
463
464 /*
465 * matrix < L-1 | V | L >
466 */
467 if (shell_A_down != NULL) {
468 size_t mat_size_down = shell_A_down->cart_size * shell_B->cart_size;
469 *arep_matrix_down = (double *)calloc(mat_size_down, sizeof(double));
470 *so_x_matrix_down = (double *)calloc(mat_size_down, sizeof(double));
471 *so_y_matrix_down = (double *)calloc(mat_size_down, sizeof(double));
472 *so_z_matrix_down = (double *)calloc(mat_size_down, sizeof(double));
473
475 shell_A_down, shell_B, grpp_operator, grpp_origin, *arep_matrix_down,
476 *so_x_matrix_down, *so_y_matrix_down, *so_z_matrix_down);
477 } else {
478 *arep_matrix_down = NULL;
479 *so_x_matrix_down = NULL;
480 *so_y_matrix_down = NULL;
481 *so_z_matrix_down = NULL;
482 }
483
484 /*
485 * matrix < L+1 | V | L >
486 */
487 size_t mat_size_up = shell_A_up->cart_size * shell_B->cart_size;
488 *arep_matrix_up = (double *)calloc(mat_size_up, sizeof(double));
489 *so_x_matrix_up = (double *)calloc(mat_size_up, sizeof(double));
490 *so_y_matrix_up = (double *)calloc(mat_size_up, sizeof(double));
491 *so_z_matrix_up = (double *)calloc(mat_size_up, sizeof(double));
492
493 libgrpp_full_grpp_integrals(shell_A_up, shell_B, grpp_operator, grpp_origin,
494 *arep_matrix_up, *so_x_matrix_up, *so_y_matrix_up,
495 *so_z_matrix_up);
496
497 /*
498 * clean up
499 */
500 if (shell_A_down) {
501 libgrpp_delete_shell(shell_A_down);
502 }
503 libgrpp_delete_shell(shell_A_up);
504}
505
506/**
507 * Calculates contribution to gradients arising from the < df/dA | V | g > term:
508 *
509 * grad += factor * < f | V | dg/dA >
510 *
511 * (bra basis function is differentiated).
512 */
514 libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B,
515 libgrpp_grpp_t *grpp_operator, double *grpp_origin, double **grad_arep,
516 double **grad_so_x, double **grad_so_y, double **grad_so_z, double factor) {
517 /*
518 * calculate integrals < df/dA | V | B >
519 */
520 double *arep_matrix_down = NULL;
521 double *so_x_matrix_down = NULL;
522 double *so_y_matrix_down = NULL;
523 double *so_z_matrix_down = NULL;
524 double *arep_matrix_up = NULL;
525 double *so_x_matrix_up = NULL;
526 double *so_y_matrix_up = NULL;
527 double *so_z_matrix_up = NULL;
528 int cart_size_down = 0;
529 int cart_size_up = 0;
530
532 shell_A, shell_B, grpp_operator, grpp_origin, &arep_matrix_down,
533 &so_x_matrix_down, &so_y_matrix_down, &so_z_matrix_down, &arep_matrix_up,
534 &so_x_matrix_up, &so_y_matrix_up, &so_z_matrix_up, &cart_size_down,
535 &cart_size_up);
536
537 /*
538 * construct contributions to gradients:
539 * d<A|B>/dA += < df/dA | V | B >
540 */
541 for (int icoord = 0; icoord < 3; icoord++) {
542 for (int i = 0; i < shell_A->cart_size; i++) {
543 for (int j = 0; j < shell_B->cart_size; j++) {
544
545 int bra_nlm[3];
546 bra_nlm[0] = shell_A->cart_list[3 * i + 0];
547 bra_nlm[1] = shell_A->cart_list[3 * i + 1];
548 bra_nlm[2] = shell_A->cart_list[3 * i + 2];
549
550 int ket_nlm[3];
551 ket_nlm[0] = shell_B->cart_list[3 * j + 0];
552 ket_nlm[1] = shell_B->cart_list[3 * j + 1];
553 ket_nlm[2] = shell_B->cart_list[3 * j + 2];
554
555 int index = i * shell_B->cart_size + j;
556
557 /*
558 * contribution from the L-1 gaussian
559 */
560 if (shell_B->L > 0) {
561 ket_nlm[icoord] -= 1;
562 int bra_index = libgrpp_nlm_to_linear(bra_nlm);
563 int ket_index = libgrpp_nlm_to_linear(ket_nlm);
564 ket_nlm[icoord] += 1;
565
566 grad_arep[icoord][index] -=
567 factor * ket_nlm[icoord] *
568 arep_matrix_down[cart_size_down * bra_index + ket_index];
569 grad_so_x[icoord][index] -=
570 factor * ket_nlm[icoord] *
571 so_x_matrix_down[cart_size_down * bra_index + ket_index];
572 grad_so_y[icoord][index] -=
573 factor * ket_nlm[icoord] *
574 so_y_matrix_down[cart_size_down * bra_index + ket_index];
575 grad_so_z[icoord][index] -=
576 factor * ket_nlm[icoord] *
577 so_z_matrix_down[cart_size_down * bra_index + ket_index];
578 }
579
580 /*
581 * contribution from the L+1 gaussian
582 */
583 ket_nlm[icoord] += 1;
584 int bra_index = libgrpp_nlm_to_linear(bra_nlm);
585 int ket_index = libgrpp_nlm_to_linear(ket_nlm);
586 ket_nlm[icoord] -= 1;
587
588 grad_arep[icoord][index] +=
589 factor * arep_matrix_up[cart_size_up * bra_index + ket_index];
590 grad_so_x[icoord][index] +=
591 factor * so_x_matrix_up[cart_size_up * bra_index + ket_index];
592 grad_so_y[icoord][index] +=
593 factor * so_y_matrix_up[cart_size_up * bra_index + ket_index];
594 grad_so_z[icoord][index] +=
595 factor * so_z_matrix_up[cart_size_up * bra_index + ket_index];
596 }
597 }
598 }
599
600 if (arep_matrix_down) {
601 free(arep_matrix_down);
602 free(so_x_matrix_down);
603 free(so_y_matrix_down);
604 free(so_z_matrix_down);
605 }
606 free(arep_matrix_up);
607 free(so_x_matrix_up);
608 free(so_y_matrix_up);
609 free(so_z_matrix_up);
610}
611
612/**
613 * To assemble the contribution < df/dA | V | g > to gradients, one have to
614 * differentiate Gaussian function. Such a differentiation yields two Gaussians
615 * with angular momenta L-1 ("down") and L+1 ("up"): dG/dA -> G(L-1) and G(L+1)
616 *
617 * This function constructs matrices with these "downgraded" and "upgraded"
618 * Gaussian functions:
619 * < G(L-1) | V | G' > and < G(L+1) | V | G' >
620 *
621 */
623 libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B,
624 libgrpp_grpp_t *grpp_operator, double *grpp_origin,
625 double **arep_matrix_down, double **so_x_matrix_down,
626 double **so_y_matrix_down, double **so_z_matrix_down,
627 double **arep_matrix_up, double **so_x_matrix_up, double **so_y_matrix_up,
628 double **so_z_matrix_up, int *cart_size_down, int *cart_size_up) {
629 /*
630 * differentiation of contracted Gaussian functions
631 */
632 libgrpp_shell_t *shell_B_down = NULL;
633 libgrpp_shell_t *shell_B_up = NULL;
634 libgrpp_differentiate_shell(shell_B, &shell_B_down, &shell_B_up);
635
636 *cart_size_down = 0;
637 if (shell_B_down != NULL) {
638 *cart_size_down = shell_B_down->cart_size;
639 }
640 *cart_size_up = shell_B_up->cart_size;
641
642 /*
643 * matrix < L-1 | L>
644 */
645 if (shell_B_down != NULL) {
646 size_t mat_size_down = shell_A->cart_size * shell_B_down->cart_size;
647 *arep_matrix_down = (double *)calloc(mat_size_down, sizeof(double));
648 *so_x_matrix_down = (double *)calloc(mat_size_down, sizeof(double));
649 *so_y_matrix_down = (double *)calloc(mat_size_down, sizeof(double));
650 *so_z_matrix_down = (double *)calloc(mat_size_down, sizeof(double));
651
653 // evaluate_grpp_integrals_shell_pair(
654 shell_A, shell_B_down, grpp_operator, grpp_origin, *arep_matrix_down,
655 *so_x_matrix_down, *so_y_matrix_down, *so_z_matrix_down);
656 } else {
657 *arep_matrix_down = NULL;
658 *so_x_matrix_down = NULL;
659 *so_y_matrix_down = NULL;
660 *so_z_matrix_down = NULL;
661 }
662
663 /*
664 * matrix < L+1 | L>
665 */
666 size_t mat_size_up = shell_A->cart_size * shell_B_up->cart_size;
667 *arep_matrix_up = (double *)calloc(mat_size_up, sizeof(double));
668 *so_x_matrix_up = (double *)calloc(mat_size_up, sizeof(double));
669 *so_y_matrix_up = (double *)calloc(mat_size_up, sizeof(double));
670 *so_z_matrix_up = (double *)calloc(mat_size_up, sizeof(double));
671
673 // evaluate_grpp_integrals_shell_pair(
674 shell_A, shell_B_up, grpp_operator, grpp_origin, *arep_matrix_up,
675 *so_x_matrix_up, *so_y_matrix_up, *so_z_matrix_up);
676
677 /*
678 * clean up
679 */
680 if (shell_B_down) {
681 libgrpp_delete_shell(shell_B_down);
682 }
683 libgrpp_delete_shell(shell_B_up);
684}
685
687 libgrpp_shell_t *shell_B,
688 libgrpp_grpp_t *grpp_operator,
689 double *grpp_origin, double **grad_arep,
690 double **grad_so_x, double **grad_so_y,
691 double **grad_so_z, int diff_bra,
692 double factor) {
693 // int diff_ket = 0;
694
695 if (diff_bra == 0) {
696 diff_bra = 0;
697 // diff_ket = 1;
698 } else {
699 diff_bra = 1;
700 // diff_ket = 0;
701 }
702
703 /*
704 * calculate overlap integrals < df/dA | V | B >
705 */
706 double *arep_matrix_down = NULL;
707 double *so_x_matrix_down = NULL;
708 double *so_y_matrix_down = NULL;
709 double *so_z_matrix_down = NULL;
710 double *arep_matrix_up = NULL;
711 double *so_x_matrix_up = NULL;
712 double *so_y_matrix_up = NULL;
713 double *so_z_matrix_up = NULL;
714 int cart_size_down = 0;
715 int cart_size_up = 0;
716
718 shell_A, shell_B, grpp_operator, grpp_origin, &arep_matrix_down,
719 &so_x_matrix_down, &so_y_matrix_down, &so_z_matrix_down, &arep_matrix_up,
720 &so_x_matrix_up, &so_y_matrix_up, &so_z_matrix_up, &cart_size_down,
721 &cart_size_up, diff_bra);
722
723 /*
724 * construct contributions to gradients:
725 * d<A|U|B>/dA += < df/dA | U | B >
726 */
727 for (int icoord = 0; icoord < 3; icoord++) {
728 for (int i = 0; i < shell_A->cart_size; i++) {
729 for (int j = 0; j < shell_B->cart_size; j++) {
730
731 int bra_nlm[3];
732 bra_nlm[0] = shell_A->cart_list[3 * i + 0];
733 bra_nlm[1] = shell_A->cart_list[3 * i + 1];
734 bra_nlm[2] = shell_A->cart_list[3 * i + 2];
735
736 int ket_nlm[3];
737 ket_nlm[0] = shell_B->cart_list[3 * j + 0];
738 ket_nlm[1] = shell_B->cart_list[3 * j + 1];
739 ket_nlm[2] = shell_B->cart_list[3 * j + 2];
740
741 int index = i * shell_B->cart_size + j;
742
743 int *diff_nlm = diff_bra ? bra_nlm : ket_nlm;
744
745 /*
746 * contribution from the L-1 gaussian
747 */
748 if (cart_size_down > 0) {
749 diff_nlm[icoord] -= 1;
750 int bra_index = libgrpp_nlm_to_linear(bra_nlm);
751 int ket_index = libgrpp_nlm_to_linear(ket_nlm);
752 diff_nlm[icoord] += 1;
753
754 int n = diff_nlm[icoord];
755 int row_len = diff_bra ? shell_B->cart_size : cart_size_down;
756 int index_down = row_len * bra_index + ket_index;
757
758 grad_arep[icoord][index] -= factor * n * arep_matrix_down[index_down];
759 grad_so_x[icoord][index] -= factor * n * so_x_matrix_down[index_down];
760 grad_so_y[icoord][index] -= factor * n * so_y_matrix_down[index_down];
761 grad_so_z[icoord][index] -= factor * n * so_z_matrix_down[index_down];
762 }
763
764 /*
765 * contribution from the L+1 gaussian
766 */
767 diff_nlm[icoord] += 1;
768 int bra_index = libgrpp_nlm_to_linear(bra_nlm);
769 int ket_index = libgrpp_nlm_to_linear(ket_nlm);
770 diff_nlm[icoord] -= 1;
771
772 int row_len = diff_bra ? shell_B->cart_size : cart_size_up;
773 int index_up = row_len * bra_index + ket_index;
774
775 grad_arep[icoord][index] += factor * arep_matrix_up[index_up];
776 grad_so_x[icoord][index] += factor * so_x_matrix_up[index_up];
777 grad_so_y[icoord][index] += factor * so_y_matrix_up[index_up];
778 grad_so_z[icoord][index] += factor * so_z_matrix_up[index_up];
779 }
780 }
781 }
782
783 if (arep_matrix_down) {
784 free(arep_matrix_down);
785 free(so_x_matrix_down);
786 free(so_y_matrix_down);
787 free(so_z_matrix_down);
788 }
789 free(arep_matrix_up);
790 free(so_x_matrix_up);
791 free(so_y_matrix_up);
792 free(so_z_matrix_up);
793}
794
795/**
796 * To assemble the contribution < df/dA | V | g > to gradients, one have to
797 * differentiate Gaussian function. Such a differentiation yields two Gaussians
798 * with angular momenta L-1 ("down") and L+1 ("up"): dG/dA -> G(L-1) and G(L+1)
799 *
800 * This function constructs matrices with these "downgraded" and "upgraded"
801 * Gaussian functions:
802 * < G(L-1) | V | G' > and < G(L+1) | V | G' >
803 *
804 */
806 libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B,
807 libgrpp_grpp_t *grpp_operator, double *grpp_origin,
808 double **arep_matrix_down, double **so_x_matrix_down,
809 double **so_y_matrix_down, double **so_z_matrix_down,
810 double **arep_matrix_up, double **so_x_matrix_up, double **so_y_matrix_up,
811 double **so_z_matrix_up, int *cart_size_down, int *cart_size_up,
812 int diff_bra) {
813 // int diff_ket = 0;
814
815 if (diff_bra == 0) {
816 diff_bra = 0;
817 // diff_ket = 1;
818 } else {
819 diff_bra = 1;
820 // diff_ket = 0;
821 }
822
823 /*
824 * which shell should be differentiated, bra or ket
825 */
826 libgrpp_shell_t *const_shell = NULL;
827 libgrpp_shell_t *diff_shell = NULL;
828 if (diff_bra) {
829 diff_shell = shell_A;
830 const_shell = shell_B;
831 } else {
832 diff_shell = shell_B;
833 const_shell = shell_A;
834 }
835
836 /*
837 * differentiation of contracted Gaussian functions
838 */
839 libgrpp_shell_t *shell_down = NULL;
840 libgrpp_shell_t *shell_up = NULL;
841 libgrpp_differentiate_shell(diff_shell, &shell_down, &shell_up);
842
843 *cart_size_down = 0;
844 if (shell_down != NULL) {
845 *cart_size_down = shell_down->cart_size;
846 }
847 *cart_size_up = shell_up->cart_size;
848
849 /*
850 * GRPP matrix:
851 * < L-1 | U | L > or < L | U | L-1 >
852 */
853 if (shell_down != NULL) {
854 size_t mat_size_down = const_shell->cart_size * shell_down->cart_size;
855 *arep_matrix_down = (double *)calloc(mat_size_down, sizeof(double));
856 *so_x_matrix_down = (double *)calloc(mat_size_down, sizeof(double));
857 *so_y_matrix_down = (double *)calloc(mat_size_down, sizeof(double));
858 *so_z_matrix_down = (double *)calloc(mat_size_down, sizeof(double));
859
861 diff_bra ? shell_down : shell_A, diff_bra ? shell_B : shell_down,
862 grpp_operator, grpp_origin, *arep_matrix_down, *so_x_matrix_down,
863 *so_y_matrix_down, *so_z_matrix_down);
864 } else {
865 *arep_matrix_down = NULL;
866 *so_x_matrix_down = NULL;
867 *so_y_matrix_down = NULL;
868 *so_z_matrix_down = NULL;
869 }
870
871 /*
872 * GRPP matrix:
873 * < L+1 | U | L > or < L | U | L+1 >
874 */
875 size_t mat_size_up = const_shell->cart_size * shell_up->cart_size;
876 *arep_matrix_up = (double *)calloc(mat_size_up, sizeof(double));
877 *so_x_matrix_up = (double *)calloc(mat_size_up, sizeof(double));
878 *so_y_matrix_up = (double *)calloc(mat_size_up, sizeof(double));
879 *so_z_matrix_up = (double *)calloc(mat_size_up, sizeof(double));
880
881 libgrpp_full_grpp_integrals(diff_bra ? shell_up : shell_A,
882 diff_bra ? shell_B : shell_up, grpp_operator,
883 grpp_origin, *arep_matrix_up, *so_x_matrix_up,
884 *so_y_matrix_up, *so_z_matrix_up);
885
886 /*
887 * clean up
888 */
889 if (shell_down) {
890 libgrpp_delete_shell(shell_down);
891 }
892 libgrpp_delete_shell(shell_up);
893}
894
895/**
896 * Allocates memory for gradients for a given shell pair.
897 */
899 size_t size = bra->cart_size * ket->cart_size;
900
901 double **grad = (double **)calloc(3, sizeof(double *));
902 for (int icoord = 0; icoord < 3; icoord++) {
903 grad[icoord] = (double *)calloc(size, sizeof(double));
904 }
905
906 return grad;
907}
908
909/**
910 * Deallocates arrays containing gradients of AO integrals.
911 */
912void libgrpp_dealloc_gradients(double **grad) {
913 free(grad[0]);
914 free(grad[1]);
915 free(grad[2]);
916 free(grad);
917}
static void const int const int i
libgrpp_grpp_t * libgrpp_new_grpp()
Definition grpp.c:21
void libgrpp_grpp_add_spin_orbit_potential(libgrpp_grpp_t *grpp, libgrpp_potential_t *pot)
Definition grpp.c:44
void libgrpp_grpp_add_outercore_potential(libgrpp_grpp_t *grpp, libgrpp_potential_t *pot, libgrpp_shell_t *oc_shell)
Definition grpp.c:54
void libgrpp_delete_grpp(libgrpp_grpp_t *grpp)
Definition grpp.c:69
void libgrpp_grpp_add_averaged_potential(libgrpp_grpp_t *grpp, libgrpp_potential_t *pot)
Definition grpp.c:34
void libgrpp_grpp_set_local_potential(libgrpp_grpp_t *grpp, libgrpp_potential_t *pot)
Definition grpp.c:25
void libgrpp_differentiate_shell(libgrpp_shell_t *shell, libgrpp_shell_t **shell_minus, libgrpp_shell_t **shell_plus)
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)
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)
double ** libgrpp_alloc_gradients(libgrpp_shell_t *bra, libgrpp_shell_t *ket)
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_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)
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_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 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_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 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)
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)
int libgrpp_nlm_to_linear(int *nlm)
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 libgrpp_dealloc_gradients(double **grad)
void libgrpp_delete_shell(libgrpp_shell_t *shell)
Definition grpp_shell.c:103
int points_are_equal(double *a, double *b)
Definition grpp_utils.c:80
libgrpp_potential_t * U_L