(git:f824184)
Loading...
Searching...
No Matches
ao_util.F
Go to the documentation of this file.
1!--------------------------------------------------------------------------------------------------!
2! CP2K: A general program to perform molecular dynamics simulations !
3! Copyright 2000-2026 CP2K developers group <https://cp2k.org> !
4! !
5! SPDX-License-Identifier: GPL-2.0-or-later !
6!--------------------------------------------------------------------------------------------------!
7
8! **************************************************************************************************
9!> \brief All kind of helpful little routines
10!> \par History
11!> - Cleaned (22.04.2021, MK)
12!> \author CJM & JGH
13! **************************************************************************************************
14MODULE ao_util
15
16 USE kinds, ONLY: dp,&
17 sp
18 USE mathconstants, ONLY: dfac,&
19 fac,&
20 rootpi
21 USE orbital_pointers, ONLY: coset
22#include "../base/base_uses.f90"
23
24 IMPLICIT NONE
25
26 PRIVATE
27
28 CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'ao_util'
29
30 ! Public subroutines
31
32 PUBLIC :: exp_radius, &
37
38CONTAINS
39
40! **************************************************************************************************
41!> \brief The exponent of a primitive Gaussian function for a given radius
42!> and threshold is calculated.
43!> \param l ...
44!> \param radius ...
45!> \param threshold ...
46!> \param prefactor ...
47!> \return ...
48!> \date 07.03.1999
49!> \par Variables
50!> - exponent : Exponent of the primitive Gaussian function.
51!> - l : Angular momentum quantum number l.
52!> - prefactor: Prefactor of the Gaussian function (e.g. a contraction
53!> coefficient).
54!> - radius : Calculated radius of the Gaussian function.
55!> - threshold: Threshold for radius.
56!> \author MK
57!> \version 1.0
58! **************************************************************************************************
59 FUNCTION gauss_exponent(l, radius, threshold, prefactor) RESULT(exponent)
60 INTEGER, INTENT(IN) :: l
61 REAL(kind=dp), INTENT(IN) :: radius, threshold, prefactor
62 REAL(kind=dp) :: exponent
63
64 exponent = 0.0_dp
65
66 IF (radius < 1.0e-6_dp) RETURN
67 IF (threshold < 1.0e-12_dp) RETURN
68
69 exponent = log(abs(prefactor)*radius**l/threshold)/radius**2
70
71 END FUNCTION gauss_exponent
72
73! **************************************************************************************************
74!> \brief The radius of a primitive Gaussian function for a given threshold
75!> is calculated.
76!> g(r) = prefactor*r**l*exp(-alpha*r**2) - threshold = 0
77!> \param l Angular momentum quantum number l.
78!> \param alpha Exponent of the primitive Gaussian function.
79!> \param threshold Threshold for function g(r).
80!> \param prefactor Prefactor of the Gaussian function (e.g. a contraction
81!> coefficient).
82!> \param epsabs Absolute tolerance (radius)
83!> \param epsrel Relative tolerance (radius)
84!> \param rlow Optional lower bound radius, e.g., when searching maximum radius
85!> \return Calculated radius of the Gaussian function
86!> \par Variables
87!> - g : function g(r)
88!> - prec_exp: single/double precision exponential function
89!> - itermax : Maximum number of iterations
90!> - contract: Golden Section Search (GSS): [0.38, 0.62]
91!> Equidistant sampling: [0.2, 0.4, 0.6, 0.8]
92!> Bisection (original approach): [0.5]
93!> Array size may trigger vectorization
94! **************************************************************************************************
95 FUNCTION exp_radius(l, alpha, threshold, prefactor, epsabs, epsrel, rlow) RESULT(radius)
96 INTEGER, INTENT(IN) :: l
97 REAL(kind=dp), INTENT(IN) :: alpha, threshold, prefactor
98 REAL(kind=dp), INTENT(IN), OPTIONAL :: epsabs, epsrel, rlow
99 REAL(kind=dp) :: radius
100
101 INTEGER, PARAMETER :: itermax = 5000, prec_exp = sp
102 REAL(kind=dp), PARAMETER :: contract(*) = [0.38_dp, 0.62_dp], mineps = 1.0e-12_dp, &
103 next = 2.0_dp, step = 1.0_dp
104
105 INTEGER :: i, j
106 REAL(kind=dp) :: a, d, dr, eps, r, rd, t
107 REAL(kind=dp), DIMENSION(SIZE(contract)) :: g, s
108
109 IF (l < 0) THEN
110 cpabort("The angular momentum quantum number is negative")
111 END IF
112
113 IF (alpha == 0.0_dp) THEN
114 cpabort("The Gaussian function exponent is zero")
115 ELSE
116 a = abs(alpha)
117 END IF
118
119 IF (threshold /= 0.0_dp) THEN
120 t = abs(threshold)
121 ELSE
122 cpabort("The requested threshold is zero")
123 END IF
124
125 radius = 0.0_dp
126 IF (PRESENT(rlow)) radius = rlow
127 IF (prefactor == 0.0_dp) RETURN
128
129 ! MAX: facilitate early exit
130 r = max(sqrt(0.5_dp*real(l, dp)/a), radius)
131
132 d = abs(prefactor); g(1) = d
133 IF (l /= 0) THEN
134 g(1) = g(1)*exp(real(-a*r*r, kind=prec_exp))*r**l
135 END IF
136 ! original approach may return radius=0
137 ! with g(r) != g(radius)
138 !radius = r
139 IF (g(1) < t) RETURN ! early exit
140
141 radius = r*next + step
142 DO i = 1, itermax
143 g(1) = d*exp(real(-a*radius*radius, kind=prec_exp))*radius**l
144 IF (g(1) < t) EXIT
145 r = radius; radius = r*next + step
146 END DO
147
148 ! consider absolute and relative accuracy (interval width)
149 IF (PRESENT(epsabs)) THEN
150 eps = epsabs
151 ELSE IF (.NOT. PRESENT(epsrel)) THEN
152 eps = mineps
153 ELSE
154 eps = huge(eps)
155 END IF
156 IF (PRESENT(epsrel)) eps = min(eps, epsrel*r)
157
158 dr = 0.0_dp
159 DO i = i + 1, itermax
160 rd = radius - r
161 ! check if finished or no further progress
162 IF ((rd < eps) .OR. (rd == dr)) RETURN
163 s = r + rd*contract ! interval contraction
164 g = d*exp(real(-a*s*s, kind=prec_exp))*s**l
165 DO j = 1, SIZE(contract)
166 IF (g(j) < t) THEN
167 radius = s(j) ! interval [r, sj)
168 EXIT
169 ELSE
170 r = s(j) ! interval [sj, radius)
171 END IF
172 END DO
173 dr = rd
174 END DO
175 IF (i >= itermax) THEN
176 cpabort("Maximum number of iterations reached")
177 END IF
178
179 END FUNCTION exp_radius
180
181! **************************************************************************************************
182!> \brief computes the radius of the Gaussian outside of which it is smaller
183!> than eps
184!> \param la_min ...
185!> \param la_max ...
186!> \param lb_min ...
187!> \param lb_max ...
188!> \param pab ...
189!> \param o1 ...
190!> \param o2 ...
191!> \param ra ...
192!> \param rb ...
193!> \param rp ...
194!> \param zetp ...
195!> \param eps ...
196!> \param prefactor ...
197!> \param cutoff ...
198!> \param epsabs ...
199!> \return ...
200!> \par History
201!> 03.2007 new version that assumes that the Gaussians origante from spherical
202!> Gaussians
203!> \note
204!> can optionally screen by the maximum element of the pab block
205! **************************************************************************************************
206 FUNCTION exp_radius_very_extended(la_min, la_max, lb_min, lb_max, pab, o1, o2, ra, rb, rp, &
207 zetp, eps, prefactor, cutoff, epsabs) RESULT(radius)
208
209 INTEGER, INTENT(IN) :: la_min, la_max, lb_min, lb_max
210 REAL(kind=dp), DIMENSION(:, :), OPTIONAL, POINTER :: pab
211 INTEGER, OPTIONAL :: o1, o2
212 REAL(kind=dp), INTENT(IN) :: ra(3), rb(3), rp(3), zetp, eps, &
213 prefactor, cutoff
214 REAL(kind=dp), OPTIONAL :: epsabs
215 REAL(kind=dp) :: radius
216
217 INTEGER :: i, ico, j, jco, la(3), lb(3), lxa, lxb, &
218 lya, lyb, lza, lzb
219 REAL(kind=dp) :: bini, binj, coef(0:20), epsin_local, &
220 polycoef(0:60), prefactor_local, &
221 rad_a, rad_b, s1, s2
222
223! get the local prefactor, we'll now use the largest density matrix element of the block to screen
224
225 epsin_local = 1.0e-2_dp
226 IF (PRESENT(epsabs)) epsin_local = epsabs
227
228 IF (PRESENT(pab)) THEN
229 prefactor_local = cutoff
230 DO lxa = 0, la_max
231 DO lxb = 0, lb_max
232 DO lya = 0, la_max - lxa
233 DO lyb = 0, lb_max - lxb
234 DO lza = max(la_min - lxa - lya, 0), la_max - lxa - lya
235 DO lzb = max(lb_min - lxb - lyb, 0), lb_max - lxb - lyb
236 la = [lxa, lya, lza]
237 lb = [lxb, lyb, lzb]
238 ico = coset(lxa, lya, lza)
239 jco = coset(lxb, lyb, lzb)
240 prefactor_local = max(abs(pab(o1 + ico, o2 + jco)), prefactor_local)
241 END DO
242 END DO
243 END DO
244 END DO
245 END DO
246 END DO
247 prefactor_local = prefactor*prefactor_local
248 ELSE
249 prefactor_local = prefactor*max(1.0_dp, cutoff)
250 END IF
251
252 !
253 ! assumes that we can compute the radius for the case where
254 ! the Gaussians a and b are both on the z - axis, but at the same
255 ! distance as the original a and b
256 !
257 rad_a = sqrt(sum((ra - rp)**2))
258 rad_b = sqrt(sum((rb - rp)**2))
259
260 polycoef(0:la_max + lb_max) = 0.0_dp
261 DO lxa = 0, la_max
262 DO lxb = 0, lb_max
263 coef(0:la_max + lb_max) = 0.0_dp
264 bini = 1.0_dp
265 s1 = 1.0_dp
266 DO i = 0, lxa
267 binj = 1.0_dp
268 s2 = 1.0_dp
269 DO j = 0, lxb
270 coef(lxa + lxb - i - j) = coef(lxa + lxb - i - j) + bini*binj*s1*s2
271 binj = (binj*(lxb - j))/(j + 1)
272 s2 = s2*(rad_b)
273 END DO
274 bini = (bini*(lxa - i))/(i + 1)
275 s1 = s1*(rad_a)
276 END DO
277 DO i = 0, lxa + lxb
278 polycoef(i) = max(polycoef(i), coef(i))
279 END DO
280 END DO
281 END DO
282
283 polycoef(0:la_max + lb_max) = polycoef(0:la_max + lb_max)*prefactor_local
284 radius = 0.0_dp
285 DO i = 0, la_max + lb_max
286 radius = max(radius, exp_radius(i, zetp, eps, polycoef(i), epsin_local, rlow=radius))
287 END DO
288
289 END FUNCTION exp_radius_very_extended
290
291! **************************************************************************************************
292!> \brief ...
293!> \param alpha ...
294!> \param l ...
295!> \return ...
296! **************************************************************************************************
297 FUNCTION gaussint_sph(alpha, l)
298
299 ! calculates the radial integral over a spherical Gaussian
300 ! of the form
301 ! r**(2+l) * exp(-alpha * r**2)
302 !
303
304 REAL(dp), INTENT(IN) :: alpha
305 INTEGER, INTENT(IN) :: l
306 REAL(dp) :: gaussint_sph
307
308 IF ((l/2)*2 == l) THEN
309 !even l:
310 gaussint_sph = rootpi*0.5_dp**(l/2 + 2)*dfac(l + 1) &
311 /sqrt(alpha)**(l + 3)
312 ELSE
313 !odd l:
314 gaussint_sph = 0.5_dp*fac((l + 1)/2)/sqrt(alpha)**(l + 3)
315 END IF
316
317 END FUNCTION gaussint_sph
318
319! **************************************************************************************************
320!> \brief ...
321!> \param A ...
322!> \param lda ...
323!> \param B ...
324!> \param ldb ...
325!> \param m ...
326!> \param n ...
327!> \return ...
328! **************************************************************************************************
329 PURE FUNCTION trace_r_axb(A, lda, B, ldb, m, n)
330
331 INTEGER, INTENT(in) :: lda
332 REAL(dp), INTENT(in) :: a(lda, *)
333 INTEGER, INTENT(in) :: ldb
334 REAL(dp), INTENT(in) :: b(ldb, *)
335 INTEGER, INTENT(in) :: m, n
336 REAL(dp) :: trace_r_axb
337
338 INTEGER :: i1, i2, imod, mminus3
339 REAL(dp) :: t1, t2, t3, t4
340
341 t1 = 0._dp
342 t2 = 0._dp
343 t3 = 0._dp
344 t4 = 0._dp
345 imod = modulo(m, 4)
346 SELECT CASE (imod)
347 CASE (0)
348 DO i2 = 1, n
349 DO i1 = 1, m, 4
350 t1 = t1 + a(i1, i2)*b(i1, i2)
351 t2 = t2 + a(i1 + 1, i2)*b(i1 + 1, i2)
352 t3 = t3 + a(i1 + 2, i2)*b(i1 + 2, i2)
353 t4 = t4 + a(i1 + 3, i2)*b(i1 + 3, i2)
354 END DO
355 END DO
356 CASE (1)
357 mminus3 = m - 3
358 DO i2 = 1, n
359 DO i1 = 1, mminus3, 4
360 t1 = t1 + a(i1, i2)*b(i1, i2)
361 t2 = t2 + a(i1 + 1, i2)*b(i1 + 1, i2)
362 t3 = t3 + a(i1 + 2, i2)*b(i1 + 2, i2)
363 t4 = t4 + a(i1 + 3, i2)*b(i1 + 3, i2)
364 END DO
365 t1 = t1 + a(m, i2)*b(m, i2)
366 END DO
367 CASE (2)
368 mminus3 = m - 3
369 DO i2 = 1, n
370 DO i1 = 1, mminus3, 4
371 t1 = t1 + a(i1, i2)*b(i1, i2)
372 t2 = t2 + a(i1 + 1, i2)*b(i1 + 1, i2)
373 t3 = t3 + a(i1 + 2, i2)*b(i1 + 2, i2)
374 t4 = t4 + a(i1 + 3, i2)*b(i1 + 3, i2)
375 END DO
376 t1 = t1 + a(m - 1, i2)*b(m - 1, i2)
377 t2 = t2 + a(m, i2)*b(m, i2)
378 END DO
379 CASE (3)
380 mminus3 = m - 3
381 DO i2 = 1, n
382 DO i1 = 1, mminus3, 4
383 t1 = t1 + a(i1, i2)*b(i1, i2)
384 t2 = t2 + a(i1 + 1, i2)*b(i1 + 1, i2)
385 t3 = t3 + a(i1 + 2, i2)*b(i1 + 2, i2)
386 t4 = t4 + a(i1 + 3, i2)*b(i1 + 3, i2)
387 END DO
388 t1 = t1 + a(m - 2, i2)*b(m - 2, i2)
389 t2 = t2 + a(m - 1, i2)*b(m - 1, i2)
390 t3 = t3 + a(m, i2)*b(m, i2)
391 END DO
392 END SELECT
393 trace_r_axb = t1 + t2 + t3 + t4
394
395 END FUNCTION trace_r_axb
396
397END MODULE ao_util
398
static GRID_HOST_DEVICE int modulo(int a, int m)
Equivalent of Fortran's MODULO, which always return a positive number. https://gcc....
All kind of helpful little routines.
Definition ao_util.F:14
real(dp) function, public gaussint_sph(alpha, l)
...
Definition ao_util.F:298
real(kind=dp) function, public exp_radius(l, alpha, threshold, prefactor, epsabs, epsrel, rlow)
The radius of a primitive Gaussian function for a given threshold is calculated. g(r) = prefactor*r**...
Definition ao_util.F:96
pure real(dp) function, public trace_r_axb(a, lda, b, ldb, m, n)
...
Definition ao_util.F:330
real(kind=dp) function, public exp_radius_very_extended(la_min, la_max, lb_min, lb_max, pab, o1, o2, ra, rb, rp, zetp, eps, prefactor, cutoff, epsabs)
computes the radius of the Gaussian outside of which it is smaller than eps
Definition ao_util.F:208
real(kind=dp) function, public gauss_exponent(l, radius, threshold, prefactor)
The exponent of a primitive Gaussian function for a given radius and threshold is calculated.
Definition ao_util.F:60
Defines the basic variable types.
Definition kinds.F:23
integer, parameter, public dp
Definition kinds.F:34
integer, parameter, public sp
Definition kinds.F:33
Definition of mathematical constants and functions.
real(kind=dp), dimension(-1:2 *maxfac+1), parameter, public dfac
real(kind=dp), parameter, public rootpi
real(kind=dp), dimension(0:maxfac), parameter, public fac
Provides Cartesian and spherical orbital pointers and indices.
integer, dimension(:, :, :), allocatable, public coset