(git:ed6f26b)
Loading...
Searching...
No Matches
grpp_overlap_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 <stdlib.h>
16#include <string.h>
17
19#include "libgrpp.h"
20
21#include "grpp_diff_gaussian.h"
22#include "grpp_utils.h"
23
25 libgrpp_shell_t *shell_B,
26 double **grad,
27 double factor);
28
30 libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B, double **overlap_down,
31 double **overlap_up, int *cart_size_down, int *cart_size_up);
32
33int nlm_to_linear(int *nlm);
34
35/**
36 * Analytic calculation of gradients of overlap integrals for a given shell pair
37 * with respect to the point 'point_3d'.
38 */
40 libgrpp_shell_t *shell_B,
41 double *point_3d, double **grad) {
42 int cart_size_A = libgrpp_get_shell_size(shell_A);
43 int cart_size_B = libgrpp_get_shell_size(shell_B);
44 int buf_size = cart_size_A * cart_size_B;
45
46 /*
47 * initializations: set gradients to zero
48 */
49 for (int icoord = 0; icoord < 3; icoord++) {
50 memset(grad[icoord], 0, sizeof(double) * buf_size);
51 }
52
53 /*
54 * integrals are zero:
55 * (1) for 1-center integrals <A|A> (due to the translational invariance)
56 * (2) d<A|B> / dC = 0 (integral is constant for the given 'point_3d')
57 */
58 if (points_are_equal(shell_A->origin, shell_B->origin)) {
59 return;
60 }
61
62 /*
63 * construct gradients:
64 * d<A|B>/dA = + < df/dA | B >
65 * d<A|B>/dB = - < df/dA | B >
66 *
67 * note that due to the property of translational invariance,
68 * d<A|B>/dB = - d<A|B>/dA
69 */
70 if (points_are_equal(shell_A->origin, point_3d)) {
71 overlap_gradient_diff_bra_contribution(shell_A, shell_B, grad, +1.0);
72 }
73 if (points_are_equal(shell_B->origin, point_3d)) {
74 overlap_gradient_diff_bra_contribution(shell_A, shell_B, grad, -1.0);
75 }
76}
77
78/**
79 * Calculates contribution to gradients arising from the < df/dA | g > term:
80 *
81 * grad += factor * < df/dA | g >
82 *
83 * (bra basis function is differentiated).
84 */
86 libgrpp_shell_t *shell_B,
87 double **grad,
88 double factor) {
89 /*
90 * calculate overlap integrals < df/dA | B >
91 */
92 double *overlap_down = NULL;
93 double *overlap_up = NULL;
94 int cart_size_down = 0;
95 int cart_size_up = 0;
96
97 overlap_gradient_diff_bra_overlap_integrals(shell_A, shell_B, &overlap_down,
98 &overlap_up, &cart_size_down,
99 &cart_size_up);
100
101 /*
102 * construct contributions to gradients:
103 * d<A|B>/dA += < df/dA | B >
104 */
105 for (int icoord = 0; icoord < 3; icoord++) {
106 for (int i = 0; i < shell_A->cart_size; i++) {
107 for (int j = 0; j < shell_B->cart_size; j++) {
108
109 int *bra_nlm = shell_A->cart_list + 3 * i;
110 int *ket_nlm = shell_B->cart_list + 3 * j;
111 int index = i * shell_B->cart_size + j;
112
113 /*
114 * contribution from the L-1 gaussian
115 */
116 if (shell_A->L > 0) {
117 bra_nlm[icoord] -= 1;
118 int bra_index = libgrpp_nlm_to_linear(bra_nlm);
119 int ket_index = libgrpp_nlm_to_linear(ket_nlm);
120 bra_nlm[icoord] += 1;
121
122 grad[icoord][index] -=
123 factor * bra_nlm[icoord] *
124 overlap_down[shell_B->cart_size * bra_index + ket_index];
125 }
126
127 /*
128 * contribution from the L+1 gaussian
129 */
130 bra_nlm[icoord] += 1;
131 int bra_index = libgrpp_nlm_to_linear(bra_nlm);
132 int ket_index = libgrpp_nlm_to_linear(ket_nlm);
133 bra_nlm[icoord] -= 1;
134
135 grad[icoord][index] +=
136 factor * overlap_up[shell_B->cart_size * bra_index + ket_index];
137 }
138 }
139 }
140
141 if (overlap_down) {
142 free(overlap_down);
143 }
144 free(overlap_up);
145}
146
147/**
148 * To assemble the contribution < df/dA | g > to gradients, one have to
149 * differentiate Gaussian function. Such a differentiation yields two Gaussians
150 * with angular momenta L-1 ("down") and L+1 ("up"): dG/dA -> G(L-1) and G(L+1)
151 *
152 * This function constructs overlap matrices with these "downgraded" and
153 * "upgraded" Gaussian functions: < G(L-1) | G' > and < G(L+1) | G' >
154 *
155 */
157 libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B, double **overlap_down,
158 double **overlap_up, int *cart_size_down, int *cart_size_up) {
159 /*
160 * differentiation of contracted Gaussian functions
161 */
162 libgrpp_shell_t *shell_A_down = NULL;
163 libgrpp_shell_t *shell_A_up = NULL;
164 libgrpp_differentiate_shell(shell_A, &shell_A_down, &shell_A_up);
165
166 *cart_size_down = 0;
167 if (shell_A_down != NULL) {
168 *cart_size_down = shell_A_down->cart_size;
169 }
170 *cart_size_up = shell_A_up->cart_size;
171
172 /*
173 * overlap matrix:
174 * < L-1 | L>
175 */
176 if (shell_A_down != NULL) {
177 *overlap_down = (double *)calloc(
178 shell_A_down->cart_size * shell_B->cart_size, sizeof(double));
179 libgrpp_overlap_integrals(shell_A_down, shell_B, *overlap_down);
180 } else {
181 *overlap_down = NULL;
182 }
183
184 /*
185 * overlap matrix:
186 * < L+1 | L>
187 */
188 *overlap_up = (double *)calloc(shell_A_up->cart_size * shell_B->cart_size,
189 sizeof(double));
190 libgrpp_overlap_integrals(shell_A_up, shell_B, *overlap_up);
191
192 /*
193 * clean up
194 */
195 if (shell_A_down) {
196 libgrpp_delete_shell(shell_A_down);
197 }
198 libgrpp_delete_shell(shell_A_up);
199}
200
201/**
202 * calculates sequential ("linear") index of the (n,l,m) primitive in the
203 * cartesian shell
204 */
206 int n = nlm[0];
207 int l = nlm[1];
208 int m = nlm[2];
209
210 int L = n + l + m;
211 int cart_size = (L + 1) * (L + 2) / 2;
212 int *cart_list = libgrpp_generate_shell_cartesians(L);
213
214 int index = 0;
215 for (index = 0; index < cart_size; index++) {
216 if (cart_list[3 * index + 0] == n && cart_list[3 * index + 1] == l &&
217 cart_list[3 * index + 2] == m) {
218 break;
219 }
220 }
221
222 free(cart_list);
223
224 return index;
225}
static void const int const int i
void libgrpp_differentiate_shell(libgrpp_shell_t *shell, libgrpp_shell_t **shell_minus, libgrpp_shell_t **shell_plus)
void libgrpp_overlap_integrals(libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B, double *overlap_matrix)
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)
static void overlap_gradient_diff_bra_contribution(libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B, double **grad, double factor)
int nlm_to_linear(int *nlm)
int libgrpp_nlm_to_linear(int *nlm)
void libgrpp_overlap_integrals_gradient(libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B, double *point_3d, double **grad)
int libgrpp_get_shell_size(libgrpp_shell_t *shell)
Definition grpp_shell.c:98
void libgrpp_delete_shell(libgrpp_shell_t *shell)
Definition grpp_shell.c:103
int * libgrpp_generate_shell_cartesians(int L)
Definition grpp_shell.c:110
int points_are_equal(double *a, double *b)
Definition grpp_utils.c:80