(git:9ccafda)
Loading...
Searching...
No Matches
ai_cartesian_operators.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 Coordinate and basis-center derivative ladders for Cartesian Gaussian integrals.
10!> Derivatives act on a basis function with the integral operator held fixed.
11!> Electronic-coordinate derivatives have the opposite sign.
12! **************************************************************************************************
14 USE kinds, ONLY: dp
15 USE mathlib, ONLY: binomial_gen
16 USE orbital_pointers, ONLY: coset, &
17 indco, &
18 ncoset
19#include "../base/base_uses.f90"
20
21 IMPLICIT NONE
22 PRIVATE
23
26
28 MODULE PROCEDURE cartesian_ladder_real, cartesian_ladder_complex
29 END INTERFACE cartesian_ladder
30
32 MODULE PROCEDURE apply_cartesian_1d_real, apply_cartesian_1d_complex
33 END INTERFACE apply_cartesian_1d
34
35CONTAINS
36
37! **************************************************************************************************
38!> \brief Construct base, raised, lowered and degree indices for a Cartesian ladder.
39!> \param lmax highest output shell or one-dimensional degree
40!> \param lmin lowest output shell (zero for one-dimensional tables)
41!> \param axis Cartesian axis, or zero for a one-dimensional table
42!> \param map rows contain base, raised, lowered and degree indices
43!> \param source_lmin optional lowest input shell; defaults to lmin for Cartesian blocks
44! **************************************************************************************************
45 SUBROUTINE cartesian_ladder_map(lmax, lmin, axis, map, source_lmin)
46 INTEGER, INTENT(IN) :: lmax, lmin, axis
47 INTEGER, DIMENSION(:, :), INTENT(OUT) :: map
48 INTEGER, INTENT(IN), OPTIONAL :: source_lmin
49
50 INTEGER :: i, ico, lowered(3), offset, power(3), &
51 raised(3), source_offset
52
53 IF (axis == 0) THEN
54 DO i = 0, lmax
55 map(:, i + 1) = [i + 1, i + 2, max(1, i), i]
56 END DO
57 ELSE
58 offset = ncoset(lmin - 1)
59 source_offset = offset
60 IF (PRESENT(source_lmin)) source_offset = ncoset(source_lmin - 1)
61 DO ico = offset + 1, ncoset(lmax)
62 power = indco(:, ico)
63 raised = power
64 lowered = power
65 raised(axis) = raised(axis) + 1
66 lowered(axis) = max(0, lowered(axis) - 1)
67 map(:, ico - offset) = [ico - source_offset, &
68 coset(raised(1), raised(2), raised(3)) - source_offset, &
69 max(1, coset(lowered(1), lowered(2), lowered(3)) - source_offset), power(axis)]
70 END DO
71 END IF
72 END SUBROUTINE cartesian_ladder_map
73
74! **************************************************************************************************
75!> \brief Apply one coordinate or basis-center derivative ladder to indexed integrals.
76!> \param source integral block including the raised functions
77!> \param values transformed integral block
78!> \param map base, raised, lowered and degree indices
79!> \param derivative select a basis-center derivative instead of coordinate multiplication
80!> \param exponent exponent of the differentiated Gaussian
81!> \param origin displacement of the Gaussian center from the coordinate reference point
82!> \param right apply the map to columns rather than rows
83! **************************************************************************************************
84 PURE SUBROUTINE cartesian_ladder_real (source, values, map, derivative, exponent, origin, right)
85 REAL (kind=dp), DIMENSION(:, :), INTENT(IN) :: source
86 REAL (kind=dp), DIMENSION(:, :), INTENT(OUT) :: values
87 INTEGER, DIMENSION(:, :), INTENT(IN) :: map
88 LOGICAL, INTENT(IN) :: derivative
89 REAL(kind=dp), INTENT(IN) :: exponent, origin
90 LOGICAL, INTENT(IN) :: right
91
92 INTEGER :: i, j, second_index
93 REAL(kind=dp) :: scale, second_scale(SIZE(map, 2))
94
95 IF (derivative) THEN
96 scale = 2.0_dp*exponent
97 second_scale = -real(map(4, :), dp)
98 second_index = 3
99 ELSE
100 scale = 1.0_dp
101 second_scale = origin
102 second_index = 1
103 END IF
104
105 ! Keep the first (contiguous) dimension innermost on both sides.
106 IF (right) THEN
107 DO j = 1, SIZE(map, 2)
108 DO i = 1, SIZE(values, 1)
109 values(i, j) = scale*source(i, map(2, j)) + &
110 second_scale(j)*source(i, map(second_index, j))
111 END DO
112 END DO
113 ELSE
114 DO j = 1, SIZE(values, 2)
115 DO i = 1, SIZE(map, 2)
116 values(i, j) = scale*source(map(2, i), j) + &
117 second_scale(i)*source(map(second_index, i), j)
118 END DO
119 END DO
120 END IF
121 END SUBROUTINE cartesian_ladder_real
122! **************************************************************************************************
123!> \brief Apply one coordinate or basis-center derivative ladder to indexed integrals.
124!> \param source integral block including the raised functions
125!> \param values transformed integral block
126!> \param map base, raised, lowered and degree indices
127!> \param derivative select a basis-center derivative instead of coordinate multiplication
128!> \param exponent exponent of the differentiated Gaussian
129!> \param origin displacement of the Gaussian center from the coordinate reference point
130!> \param right apply the map to columns rather than rows
131! **************************************************************************************************
132 PURE SUBROUTINE cartesian_ladder_complex (source, values, map, derivative, exponent, origin, right)
133 COMPLEX (KIND=dp), DIMENSION(:, :), INTENT(IN) :: source
134 COMPLEX (KIND=dp), DIMENSION(:, :), INTENT(OUT) :: values
135 INTEGER, DIMENSION(:, :), INTENT(IN) :: map
136 LOGICAL, INTENT(IN) :: derivative
137 REAL(kind=dp), INTENT(IN) :: exponent, origin
138 LOGICAL, INTENT(IN) :: right
139
140 INTEGER :: i, j, second_index
141 REAL(kind=dp) :: scale, second_scale(SIZE(map, 2))
142
143 IF (derivative) THEN
144 scale = 2.0_dp*exponent
145 second_scale = -real(map(4, :), dp)
146 second_index = 3
147 ELSE
148 scale = 1.0_dp
149 second_scale = origin
150 second_index = 1
151 END IF
152
153 ! Keep the first (contiguous) dimension innermost on both sides.
154 IF (right) THEN
155 DO j = 1, SIZE(map, 2)
156 DO i = 1, SIZE(values, 1)
157 values(i, j) = scale*source(i, map(2, j)) + &
158 second_scale(j)*source(i, map(second_index, j))
159 END DO
160 END DO
161 ELSE
162 DO j = 1, SIZE(values, 2)
163 DO i = 1, SIZE(map, 2)
164 values(i, j) = scale*source(map(2, i), j) + &
165 second_scale(i)*source(map(second_index, i), j)
166 END DO
167 END DO
168 END IF
169 END SUBROUTINE cartesian_ladder_complex
170
171! **************************************************************************************************
172!> \brief Apply a Cartesian operator on either side of a primitive integral block.
173!> The input includes one extra shell on both sides. Coordinate multiplication
174!> uses the supplied shell-range layout; derivative inputs extend the lowest
175!> shell by one on the selected side for lowering. Screened primitive blocks
176!> must be zero in the input, including their raised and lowered functions.
177!> \param la_max highest output shell on A
178!> \param la_min lowest output shell on A
179!> \param npgfa number of primitives on A
180!> \param lb_max highest output shell on B
181!> \param lb_min lowest output shell on B
182!> \param npgfb number of primitives on B
183!> \param ab input integral block with raised shells
184!> \param values three Cartesian components in the output shell-range layout
185!> \param right act on the ket rather than the bra
186!> \param derivative select a basis-center derivative
187!> \param exponents Gaussian exponents on the selected side, required for derivatives
188!> \param origin displacement of the selected center from the coordinate reference point
189! **************************************************************************************************
190 SUBROUTINE apply_cartesian_operator(la_max, la_min, npgfa, lb_max, lb_min, npgfb, &
191 ab, values, right, derivative, exponents, origin)
192 INTEGER, INTENT(IN) :: la_max, la_min, npgfa, lb_max, lb_min, &
193 npgfb
194 REAL(kind=dp), DIMENSION(:, :), INTENT(IN) :: ab
195 REAL(kind=dp), DIMENSION(:, :, :), INTENT(OUT) :: values
196 LOGICAL, INTENT(IN) :: right, derivative
197 REAL(kind=dp), DIMENSION(:), INTENT(IN), OPTIONAL :: exponents
198 REAL(kind=dp), DIMENSION(3), INTENT(IN), OPTIONAL :: origin
199
200 INTEGER :: axis, ia, iap, ib, ibp, ipgf, jpgf, n, &
201 na, nap, nb, nbp, source_min_a, &
202 source_min_b
203 INTEGER, ALLOCATABLE :: map(:, :, :)
204 LOGICAL :: valid_shape
205 REAL(kind=dp) :: center(3), exponent
206
207 na = ncoset(la_max) - ncoset(la_min - 1)
208 nb = ncoset(lb_max) - ncoset(lb_min - 1)
209 source_min_a = la_min
210 source_min_b = lb_min
211 IF (derivative) THEN
212 IF (right) THEN
213 source_min_b = max(0, lb_min - 1)
214 ELSE
215 source_min_a = max(0, la_min - 1)
216 END IF
217 END IF
218 nap = ncoset(la_max + 1) - ncoset(source_min_a - 1)
219 nbp = ncoset(lb_max + 1) - ncoset(source_min_b - 1)
220 IF (derivative) THEN
221 cpassert(PRESENT(exponents))
222 END IF
223 valid_shape = all(shape(ab) >= [nap*npgfa, nbp*npgfb])
224 cpassert(valid_shape)
225 valid_shape = all(shape(values) >= [na*npgfa, nb*npgfb, 3])
226 cpassert(valid_shape)
227 center = 0.0_dp
228 IF (PRESENT(origin)) center = origin
229 n = merge(nb, na, right)
230 ALLOCATE (map(4, n, 3))
231 DO axis = 1, 3
232 IF (right) THEN
233 CALL cartesian_ladder_map(lb_max, lb_min, axis, map(:, :, axis), source_min_b)
234 ELSE
235 CALL cartesian_ladder_map(la_max, la_min, axis, map(:, :, axis), source_min_a)
236 END IF
237 END DO
238
239 values = 0.0_dp
240 DO ipgf = 1, npgfa
241 ia = (ipgf - 1)*na
242 iap = (ipgf - 1)*nap
243 DO jpgf = 1, npgfb
244 ib = (jpgf - 1)*nb
245 ibp = (jpgf - 1)*nbp
246 exponent = 0.0_dp
247 IF (derivative) exponent = exponents(merge(jpgf, ipgf, right))
248 DO axis = 1, 3
249 CALL cartesian_ladder(ab(iap + 1:iap + nap, ibp + 1:ibp + nbp), &
250 values(ia + 1:ia + na, ib + 1:ib + nb, axis), map(:, :, axis), &
251 derivative, exponent, center(axis), right)
252 END DO
253 END DO
254 END DO
255 END SUBROUTINE apply_cartesian_operator
256
257! **************************************************************************************************
258!> \brief Apply the common ladder to separable one-dimensional integral tables.
259!> \param source input tables indexed by the degrees on A and B and the Cartesian axis
260!> \param values transformed tables; entries outside the requested range are untouched
261!> \param la_max highest output degree on A
262!> \param lb_max highest output degree on B
263!> \param right act on B rather than A
264!> \param derivative select a basis-center derivative
265!> \param exponent Gaussian exponent on the selected side
266!> \param origin displacement of that center from the coordinate reference point
267! **************************************************************************************************
268 SUBROUTINE apply_cartesian_1d_real (source, values, la_max, lb_max, right, derivative, exponent, origin)
269 REAL (KIND=dp), DIMENSION(0:, 0:, :), INTENT(IN) :: source
270 REAL (KIND=dp), DIMENSION(0:, 0:, :), INTENT(INOUT) :: values
271 INTEGER, INTENT(IN) :: la_max, lb_max
272 LOGICAL, INTENT(IN) :: right, derivative
273 REAL(KIND=dp), INTENT(IN) :: exponent, origin(3)
274
275 INTEGER :: axis, map(4, MERGE(lb_max, la_max, right) + 1)
276
277 CALL cartesian_ladder_map(merge(lb_max, la_max, right), 0, 0, map)
278 DO axis = 1, 3
279 CALL cartesian_ladder(source(:, :, axis), values(0:la_max, 0:lb_max, axis), map, &
280 derivative, exponent, origin(axis), right)
281 END DO
282 END SUBROUTINE apply_cartesian_1d_real
283! **************************************************************************************************
284!> \brief Apply the common ladder to separable one-dimensional integral tables.
285!> \param source input tables indexed by the degrees on A and B and the Cartesian axis
286!> \param values transformed tables; entries outside the requested range are untouched
287!> \param la_max highest output degree on A
288!> \param lb_max highest output degree on B
289!> \param right act on B rather than A
290!> \param derivative select a basis-center derivative
291!> \param exponent Gaussian exponent on the selected side
292!> \param origin displacement of that center from the coordinate reference point
293! **************************************************************************************************
294 SUBROUTINE apply_cartesian_1d_complex (source, values, la_max, lb_max, right, derivative, exponent, origin)
295 COMPLEX (KIND=dp), DIMENSION(0:, 0:, :), INTENT(IN) :: source
296 COMPLEX (KIND=dp), DIMENSION(0:, 0:, :), INTENT(INOUT) :: values
297 INTEGER, INTENT(IN) :: la_max, lb_max
298 LOGICAL, INTENT(IN) :: right, derivative
299 REAL(KIND=dp), INTENT(IN) :: exponent, origin(3)
300
301 INTEGER :: axis, map(4, MERGE(lb_max, la_max, right) + 1)
302
303 CALL cartesian_ladder_map(merge(lb_max, la_max, right), 0, 0, map)
304 DO axis = 1, 3
305 CALL cartesian_ladder(source(:, :, axis), values(0:la_max, 0:lb_max, axis), map, &
306 derivative, exponent, origin(axis), right)
307 END DO
308 END SUBROUTINE apply_cartesian_1d_complex
309
310! **************************************************************************************************
311!> \brief Form requested coordinate powers from separable Cartesian integral tables.
312!> Only requested powers are stored. With the origin on A, each power is a
313!> direct shift of the bra degree; other origins use the binomial expansion.
314!> \param source input tables with enough raised bra degrees for the largest power
315!> \param values tables indexed by bra degree, ket degree, requested power and axis
316!> \param la_max highest output degree on A
317!> \param lb_max highest output degree on B
318!> \param powers nonnegative coordinate powers to evaluate
319!> \param origin displacement of A from the coordinate reference point
320! **************************************************************************************************
321 SUBROUTINE cartesian_polynomial_1d(source, values, la_max, lb_max, powers, origin)
322 REAL(kind=dp), DIMENSION(0:, 0:, :), INTENT(IN) :: source
323 REAL(kind=dp), DIMENSION(0:, 0:, 0:, :), &
324 INTENT(OUT) :: values
325 INTEGER, INTENT(IN) :: la_max, lb_max, powers(0:)
326 REAL(kind=dp), INTENT(IN) :: origin(3)
327
328 INTEGER :: axis, i, k, p
329 REAL(kind=dp) :: coefficient
330
331 DO axis = 1, 3
332 DO i = 0, SIZE(powers) - 1
333 p = powers(i)
334 IF (abs(origin(axis)) <= 0.0_dp) THEN
335 values(:, :, i, axis) = source(p:p + la_max, 0:lb_max, axis)
336 ELSE
337 values(:, :, i, axis) = 0.0_dp
338 DO k = 0, p
339 coefficient = binomial_gen(real(p, dp), k)*origin(axis)**(p - k)
340 values(:, :, i, axis) = values(:, :, i, axis) + &
341 coefficient*source(k:k + la_max, 0:lb_max, axis)
342 END DO
343 END IF
344 END DO
345 END DO
346 END SUBROUTINE cartesian_polynomial_1d
347
348END MODULE ai_cartesian_operators
Coordinate and basis-center derivative ladders for Cartesian Gaussian integrals. Derivatives act on a...
subroutine, public cartesian_polynomial_1d(source, values, la_max, lb_max, powers, origin)
Form requested coordinate powers from separable Cartesian integral tables. Only requested powers are ...
subroutine, public cartesian_ladder_map(lmax, lmin, axis, map, source_lmin)
Construct base, raised, lowered and degree indices for a Cartesian ladder.
subroutine, public apply_cartesian_operator(la_max, la_min, npgfa, lb_max, lb_min, npgfb, ab, values, right, derivative, exponents, origin)
Apply a Cartesian operator on either side of a primitive integral block. The input includes one extra...
Defines the basic variable types.
Definition kinds.F:23
integer, parameter, public dp
Definition kinds.F:34
Collection of simple mathematical functions and subroutines.
Definition mathlib.F:15
elemental real(kind=dp) function, public binomial_gen(z, k)
The generalized binomial coefficient z over k for 0 <= k <= n is calculated. (z) z*(z-1)*....
Definition mathlib.F:238
Provides Cartesian and spherical orbital pointers and indices.
integer, dimension(:), allocatable, public ncoset
integer, dimension(:, :, :), allocatable, public coset
integer, dimension(:, :), allocatable, public indco