(git:08825b9)
Loading...
Searching...
No Matches
upf_projector_integrals.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 Half-numerical overlaps with the original scalar UPF radial projectors.
10!> Cartesian polynomials and angular products are integrated analytically.
11!> Only a radial quadrature remains; no fit or rotation of projector identities
12!> is performed. The UPF reader preserves the tabulated beta amplitude and
13!> includes the Ry-to-Hartree factor in the coupling matrix D.
14! **************************************************************************************************
16 USE iso_c_binding, ONLY: c_double,&
17 c_int
18 USE kinds, ONLY: dp
19 USE libgrpp, ONLY: libgrpp_init
20 USE mathconstants, ONLY: dfac,&
21 fourpi,&
22 maxfac
23 USE mathlib, ONLY: binomial
24 USE orbital_pointers, ONLY: indco,&
26 nco,&
27 ncoset
31#include "../base/base_uses.f90"
32
33 IMPLICIT NONE
34 PRIVATE
35 CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'upf_projector_integrals'
36
38 INTEGER :: degree = -1, lmax = -1, harmonic_max = -1, nproj = 0
39 REAL(kind=dp) :: radius = 0.0_dp
40 INTEGER, ALLOCATABLE :: radial_index(:), angular_index(:), lbeta(:)
41 REAL(kind=dp), ALLOCATABLE :: r(:), weighted_beta(:, :), d(:, :), gaunt(:, :, :)
42 END TYPE upf_projector_type
43
45
46 INTERFACE
47 FUNCTION scaled_bessel(n, x) RESULT(value) BIND(C, name="libgrpp_modified_bessel_scaled")
48 IMPORT :: c_double, c_int
49 INTEGER(C_INT), VALUE :: n
50 REAL(c_double), VALUE :: x
51 REAL(c_double) :: value
52 END FUNCTION scaled_bessel
53 END INTERFACE
54
55CONTAINS
56
57! **************************************************************************************************
58!> \brief Prepare immutable radial and angular data outside parallel regions.
59!> \param pot Original UPF data, including beta(r), not r*beta(r).
60!> \param degree Largest Cartesian degree needed (AO degree + derivatives/moments).
61!> \param projectors Prepared data; reinitializing also releases the previous allocation.
62! **************************************************************************************************
63 SUBROUTINE upf_projector_init(pot, degree, projectors)
64 TYPE(atom_upfpot_type), INTENT(IN) :: pot
65 INTEGER, INTENT(IN) :: degree
66 TYPE(upf_projector_type), INTENT(OUT) :: projectors
67
68 INTEGER :: a, b, i, j, k, l, lambda, m, n, &
69 nsimpson, p, powers(3), q, s
70 REAL(kind=dp), ALLOCATABLE :: moments(:, :), weights(:)
71
72 cpassert(degree >= 0)
73 IF (pot%has_so) THEN
74 cpabort("Spin-orbit UPF projectors are not supported")
75 END IF
76 cpassert(pot%number_of_proj > 0)
77 cpassert(all(pot%lbeta >= 0))
78 projectors%degree = degree
79 projectors%lmax = maxval(pot%lbeta)
80 projectors%harmonic_max = degree + projectors%lmax
81 ! Both the factorial and bundled Bessel tables cover this range.
82 cpassert(projectors%harmonic_max <= min(20, maxfac/2))
83 CALL init_orbital_pointers(projectors%harmonic_max)
84 CALL init_spherical_harmonics(projectors%harmonic_max, -1)
85 CALL libgrpp_init()
86
87 n = SIZE(pot%r)
88 cpassert(n >= 3)
89 cpassert(SIZE(pot%rab) == n)
90 cpassert(SIZE(pot%beta, 1) == n)
91 cpassert(SIZE(pot%beta, 2) == pot%number_of_proj)
92 cpassert(all(pot%r(2:) > pot%r(:n - 1)))
93 cpassert(all(pot%rab > 0.0_dp))
94 ALLOCATE (projectors%r(n), projectors%lbeta(pot%number_of_proj))
95 projectors%r(:) = pot%r
96 projectors%lbeta(:) = pot%lbeta
97 ALLOCATE (weights(n))
98 weights = 0.0_dp
99 ! Composite Simpson in the mesh index; PP_RAB is dr/d(index).
100 ! An even mesh has one final trapezoidal interval.
101 nsimpson = n - 1 + modulo(n, 2)
102 weights(1:nsimpson:2) = 2.0_dp/3.0_dp
103 weights(2:nsimpson - 1:2) = 4.0_dp/3.0_dp
104 weights(1) = 1.0_dp/3.0_dp
105 weights(nsimpson) = 1.0_dp/3.0_dp
106 IF (nsimpson < n) weights(n - 1:n) = weights(n - 1:n) + 0.5_dp
107 weights(:) = weights*pot%rab*pot%r**2
108 ALLOCATE (projectors%weighted_beta(n, pot%number_of_proj))
109 DO i = 1, pot%number_of_proj
110 projectors%weighted_beta(:, i) = weights*pot%beta(:, i)
111 DO j = n, 1, -1
112 IF (pot%beta(j, i) /= 0.0_dp) THEN
113 projectors%radius = max(projectors%radius, pot%r(j))
114 EXIT
115 END IF
116 END DO
117 END DO
118
119 projectors%nproj = sum(2*pot%lbeta + 1)
120 ALLOCATE (projectors%radial_index(projectors%nproj), projectors%angular_index(projectors%nproj))
121 p = 0
122 DO i = 1, pot%number_of_proj
123 l = pot%lbeta(i)
124 DO m = 1, 2*l + 1
125 p = p + 1
126 projectors%radial_index(p) = i
127 projectors%angular_index(p) = l*l + m
128 END DO
129 END DO
130 ALLOCATE (projectors%d(projectors%nproj, projectors%nproj))
131 projectors%d = 0.0_dp
132 DO p = 1, projectors%nproj
133 DO q = 1, projectors%nproj
134 i = projectors%radial_index(p)
135 j = projectors%radial_index(q)
136 IF (projectors%angular_index(p) == projectors%angular_index(q)) THEN
137 projectors%d(p, q) = pot%dion(i, j)
138 ELSE IF (pot%lbeta(i) /= pot%lbeta(j)) THEN
139 cpassert(abs(pot%dion(i, j)) < 1.e-12_dp)
140 END IF
141 END DO
142 END DO
143
144 ! G(s,lm,lambda*nu) = integral Omega**s Y_lm(Omega) Y_lambda,nu(Omega).
145 ALLOCATE (projectors%gaunt(ncoset(degree), (projectors%lmax + 1)**2, &
146 (projectors%harmonic_max + 1)**2))
147 projectors%gaunt = 0.0_dp
148 DO s = 1, ncoset(degree)
149 k = sum(indco(:, s))
150 DO l = 0, projectors%lmax
151 IF (.NOT. any(pot%lbeta == l)) cycle
152 DO lambda = max(0, l - k), l + k
153 IF (modulo(k + l + lambda, 2) /= 0) cycle
154 ALLOCATE (moments(nco(l), nco(lambda)))
155 DO b = 1, nco(lambda)
156 DO a = 1, nco(l)
157 powers = indco(:, s) + indco(:, ncoset(l - 1) + a) + indco(:, ncoset(lambda - 1) + b)
158 moments(a, b) = 0.0_dp
159 IF (all(modulo(powers, 2) == 0)) THEN
160 moments(a, b) = fourpi*product(dfac(powers - 1))/dfac(sum(powers) + 1)
161 END IF
162 END DO
163 END DO
164 projectors%gaunt(s, l*l + 1:(l + 1)**2, lambda*lambda + 1:(lambda + 1)**2) = &
165 matmul(matmul(orbtramat(l)%slm, moments), transpose(orbtramat(lambda)%slm))
166 DEALLOCATE (moments)
167 END DO
168 END DO
169 END DO
170 END SUBROUTINE upf_projector_init
171
172! **************************************************************************************************
173!> \brief Evaluate <Cartesian Gaussian|beta_i Y_lm> and AO-center derivatives.
174!> \param projectors Immutable prepared data.
175!> \param la Largest AO Cartesian degree (all degrees 0..la are returned).
176!> \param zeta Primitive Gaussian exponents.
177!> \param rac Projector center minus AO center, as in ai_overlap.
178!> \param nder Maximum derivative degree, or moment degree in moment mode.
179!> \param integrals Primitive-major AO order, original radial/m order, coset derivative order.
180!> \param moment_origin Optional AO center minus moment reference; requests moments
181!> instead of derivatives, in the same coset ordering including the overlap.
182! **************************************************************************************************
183 SUBROUTINE upf_projector_overlap(projectors, la, zeta, rac, nder, integrals, moment_origin)
184 TYPE(upf_projector_type), INTENT(IN) :: projectors
185 INTEGER, INTENT(IN) :: la
186 REAL(kind=dp), INTENT(IN) :: zeta(:), rac(3)
187 INTEGER, INTENT(IN) :: nder
188 REAL(kind=dp), INTENT(OUT) :: integrals(:, :, :)
189 REAL(kind=dp), INTENT(IN), OPTIONAL :: moment_origin(3)
190
191 INTEGER :: a(3), axis, b(3), degree, deriv(3), i, &
192 id, ip, j, k, l, lambda, nb, nc, nh, &
193 nr, p, power, s, shifted(3), step, t
194 REAL(kind=dp) :: alpha, direction(3), distance, factor
195 REAL(kind=dp), ALLOCATABLE :: angular(:, :, :), cartesian(:, :), centered(:, :), &
196 coeff(:, :), envelope(:), harmonics(:), monomials(:), next_coeff(:), radial(:, :, :), &
197 radial_power(:), radial_work(:), shift(:, :)
198
199 degree = la + nder
200 cpassert(la >= 0 .AND. nder >= 0)
201 cpassert(degree <= projectors%degree)
202 cpassert(all(zeta > 0.0_dp))
203 cpassert(SIZE(integrals, 1) == SIZE(zeta)*ncoset(la))
204 cpassert(SIZE(integrals, 2) == projectors%nproj)
205 cpassert(SIZE(integrals, 3) == ncoset(nder))
206 nc = ncoset(degree)
207 nh = degree + projectors%lmax
208 nr = SIZE(projectors%r)
209 nb = SIZE(projectors%weighted_beta, 2)
210 ALLOCATE (harmonics((nh + 1)**2), monomials(ncoset(nh)))
211 distance = norm2(rac)
212 direction = [0.0_dp, 0.0_dp, 1.0_dp]
213 IF (distance > 0.0_dp) direction = -rac/distance
214 DO i = 1, ncoset(nh)
215 monomials(i) = product(direction**indco(:, i))
216 END DO
217 DO l = 0, nh
218 harmonics(l*l + 1:(l + 1)**2) = &
219 matmul(orbtramat(l)%slm, monomials(ncoset(l - 1) + 1:ncoset(l)))
220 END DO
221 ALLOCATE (angular(nc, (projectors%lmax + 1)**2, 0:nh))
222 DO lambda = 0, nh
223 DO i = 1, SIZE(angular, 2)
224 angular(:, i, lambda) = matmul( &
225 projectors%gaunt(:nc, i, lambda*lambda + 1:(lambda + 1)**2), &
226 harmonics(lambda*lambda + 1:(lambda + 1)**2))
227 END DO
228 END DO
229 ALLOCATE (shift(nc, nc))
230 shift = 0.0_dp
231 DO t = 1, nc
232 a = indco(:, t)
233 DO s = 1, nc
234 b = indco(:, s)
235 IF (any(b > a)) cycle
236 factor = 1.0_dp
237 DO axis = 1, 3
238 factor = factor*binomial(a(axis), b(axis))*rac(axis)**(a(axis) - b(axis))
239 END DO
240 shift(t, s) = factor
241 END DO
242 END DO
243 ALLOCATE (radial(0:degree, nb, 0:nh), radial_work(nr), radial_power(nr), envelope(nr))
244 ALLOCATE (centered(nc, projectors%nproj), cartesian(nc, projectors%nproj))
245 ALLOCATE (coeff(0:degree, 3), next_coeff(0:degree))
246 integrals = 0.0_dp
247 DO ip = 1, SIZE(zeta)
248 alpha = zeta(ip)
249 envelope(:) = exp(-alpha*(projectors%r - distance)**2)
250 DO lambda = 0, nh
251 DO i = 1, nr
252 radial_work(i) = envelope(i)*scaled_bessel(int(lambda, c_int), &
253 REAL(2.0_dp*alpha*projectors%r(i)*distance, c_double))
254 END DO
255 radial_power(:) = radial_work
256 DO k = 0, degree
257 radial(k, :, lambda) = matmul(radial_power, projectors%weighted_beta)
258 radial_power(:) = radial_power*projectors%r
259 END DO
260 END DO
261 centered = 0.0_dp
262 DO p = 1, projectors%nproj
263 i = projectors%radial_index(p)
264 j = projectors%angular_index(p)
265 DO s = 1, nc
266 k = sum(indco(:, s))
267 centered(s, p) = fourpi*dot_product(angular(s, j, :), radial(k, i, :))
268 END DO
269 END DO
270 cartesian(:, :) = matmul(shift, centered)
271 DO id = 1, ncoset(nder)
272 deriv = indco(:, id)
273 DO t = 1, ncoset(la)
274 a = indco(:, t)
275 coeff = 0.0_dp
276 DO axis = 1, 3
277 coeff(a(axis), axis) = 1.0_dp
278 IF (PRESENT(moment_origin)) THEN
279 coeff(:, axis) = 0.0_dp
280 DO power = 0, deriv(axis)
281 coeff(a(axis) + power, axis) = binomial(deriv(axis), power)* &
282 moment_origin(axis)**(deriv(axis) - power)
283 END DO
284 ELSE
285 DO step = 1, deriv(axis)
286 next_coeff = 0.0_dp
287 DO power = 0, a(axis) + step - 1
288 next_coeff(power + 1) = next_coeff(power + 1) + 2.0_dp*alpha*coeff(power, axis)
289 IF (power > 0) next_coeff(power - 1) = next_coeff(power - 1) - power*coeff(power, axis)
290 END DO
291 coeff(:, axis) = next_coeff
292 END DO
293 END IF
294 END DO
295 DO s = 1, nc
296 shifted = indco(:, s)
297 factor = coeff(shifted(1), 1)*coeff(shifted(2), 2)*coeff(shifted(3), 3)
298 IF (factor == 0.0_dp) cycle
299 integrals((ip - 1)*ncoset(la) + t, :, id) = integrals((ip - 1)*ncoset(la) + t, :, id) + &
300 factor*cartesian(s, :)
301 END DO
302 END DO
303 END DO
304 END DO
305 END SUBROUTINE upf_projector_overlap
306
static GRID_HOST_DEVICE int modulo(int a, int m)
Equivalent of Fortran's MODULO, which always return a positive number. https://gcc....
Defines the basic variable types.
Definition kinds.F:23
integer, parameter, public dp
Definition kinds.F:34
Definition of mathematical constants and functions.
real(kind=dp), parameter, public degree
real(kind=dp), dimension(-1:2 *maxfac+1), parameter, public dfac
real(kind=dp), parameter, public fourpi
integer, parameter, public maxfac
Collection of simple mathematical functions and subroutines.
Definition mathlib.F:15
elemental real(kind=dp) function, public binomial(n, k)
The binomial coefficient n over k for 0 <= k <= n is calculated, otherwise zero is returned.
Definition mathlib.F:214
Provides Cartesian and spherical orbital pointers and indices.
subroutine, public init_orbital_pointers(maxl)
Initialize or update the orbital pointers.
integer, dimension(:), allocatable, public nco
integer, dimension(:), allocatable, public ncoset
integer, dimension(:, :), allocatable, public indco
Calculation of the spherical harmonics and the corresponding orbital transformation matrices.
subroutine, public init_spherical_harmonics(maxl, output_unit)
Initialize or update the orbital transformation matrices.
type(orbtramat_type), dimension(:), pointer, public orbtramat
Half-numerical overlaps with the original scalar UPF radial projectors. Cartesian polynomials and ang...
subroutine, public upf_projector_init(pot, degree, projectors)
Prepare immutable radial and angular data outside parallel regions.
subroutine, public upf_projector_overlap(projectors, la, zeta, rac, nder, integrals, moment_origin)
Evaluate <Cartesian Gaussian|beta_i Y_lm> and AO-center derivatives.
Owned UPF dataset and radial conventions shared by ATOM and Quickstep. Dataset availability does not ...
Definition upf_types.F:12