(git:f7b9015)
Loading...
Searching...
No Matches
ai_moments.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 Calculation of the moment integrals over Cartesian Gaussian-type
10!> functions.
11!> \par Literature
12!> S. Obara and A. Saika, J. Chem. Phys. 84, 3963 (1986)
13!> \par History
14!> none
15!> \author J. Hutter (16.02.2005)
16! **************************************************************************************************
18
19! ax,ay,az : Angular momentum index numbers of orbital a.
20! bx,by,bz : Angular momentum index numbers of orbital b.
21! coset : Cartesian orbital set pointer.
22! dab : Distance between the atomic centers a and b.
23! l{a,b} : Angular momentum quantum number of shell a or b.
24! l{a,b}_max: Maximum angular momentum quantum number of shell a or b.
25! l{a,b}_min: Minimum angular momentum quantum number of shell a or b.
26! rac : Distance vector between the atomic center a and reference point c.
27! rbc : Distance vector between the atomic center b and reference point c.
28! rpgf{a,b} : Radius of the primitive Gaussian-type function a or b.
29! zet{a,b} : Exponents of the Gaussian-type functions a or b.
30! zetp : Reciprocal of the sum of the exponents of orbital a and b.
31
37 USE ai_os_rr, ONLY: os_rr_ovlp
38 USE ai_overlap, ONLY: overlap_ab
39 USE kinds, ONLY: dp
40 USE mathconstants, ONLY: pi
41 USE orbital_pointers, ONLY: indco, &
42 ncoset
43#include "../base/base_uses.f90"
44
45 IMPLICIT NONE
46
47 PRIVATE
48
49 CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'ai_moments'
50
52
53CONTAINS
54
55! **************************************************************************************************
56!> \brief Contract complex primitive integrals into real cosine and sine AO blocks.
57!> \param cos_block ...
58!> \param sin_block ...
59!> \param iatom ...
60!> \param ncoa ...
61!> \param nsgfa ...
62!> \param sgfa ...
63!> \param sphi_a ...
64!> \param ldsa ...
65!> \param jatom ...
66!> \param ncob ...
67!> \param nsgfb ...
68!> \param sgfb ...
69!> \param sphi_b ...
70!> \param ldsb ...
71!> \param expab complex primitive plane-wave integrals
72!> \param work ...
73!> \param ldwork ...
74!> \param ordered retain the ordered atom pair instead of mapping to an upper block
75! **************************************************************************************************
76 SUBROUTINE contract_expikr(cos_block, sin_block, &
77 iatom, ncoa, nsgfa, sgfa, sphi_a, ldsa, &
78 jatom, ncob, nsgfb, sgfb, sphi_b, ldsb, &
79 expab, work, ldwork, ordered)
80
81 REAL(dp), DIMENSION(:, :), POINTER :: cos_block, sin_block
82 INTEGER, INTENT(IN) :: iatom, ncoa, nsgfa, sgfa
83 REAL(dp), DIMENSION(:, :), INTENT(IN) :: sphi_a
84 INTEGER, INTENT(IN) :: ldsa, jatom, ncob, nsgfb, sgfb
85 REAL(dp), DIMENSION(:, :), INTENT(IN) :: sphi_b
86 INTEGER, INTENT(IN) :: ldsb
87 COMPLEX(dp), DIMENSION(:, :), INTENT(IN) :: expab
88 REAL(dp), DIMENSION(:, :) :: work
89 INTEGER, INTENT(IN) :: ldwork
90 LOGICAL, INTENT(IN), OPTIONAL :: ordered
91
92 LOGICAL :: direct_block
93 REAL(dp), ALLOCATABLE :: primitive(:, :)
94
95 direct_block = iatom <= jatom
96 IF (PRESENT(ordered)) direct_block = direct_block .OR. ordered
97
98 ALLOCATE (primitive(ncoa, ncob))
99 primitive(:, :) = real(expab(1:ncoa, 1:ncob), kind=dp)
100 CALL dgemm("N", "N", ncoa, nsgfb, ncob, &
101 1.0_dp, primitive(1, 1), ncoa, &
102 sphi_b(1, sgfb), ldsb, &
103 0.0_dp, work(1, 1), ldwork)
104
105 IF (direct_block) THEN
106 CALL dgemm("T", "N", nsgfa, nsgfb, ncoa, &
107 1.0_dp, sphi_a(1, sgfa), ldsa, &
108 work(1, 1), ldwork, &
109 1.0_dp, cos_block(sgfa, sgfb), &
110 SIZE(cos_block, 1))
111 ELSE
112 CALL dgemm("T", "N", nsgfb, nsgfa, ncoa, &
113 1.0_dp, work(1, 1), ldwork, &
114 sphi_a(1, sgfa), ldsa, &
115 1.0_dp, cos_block(sgfb, sgfa), &
116 SIZE(cos_block, 1))
117 END IF
118 primitive(:, :) = aimag(expab(1:ncoa, 1:ncob))
119 CALL dgemm("N", "N", ncoa, nsgfb, ncob, &
120 1.0_dp, primitive(1, 1), ncoa, &
121 sphi_b(1, sgfb), ldsb, &
122 0.0_dp, work(1, 1), ldwork)
123
124 IF (direct_block) THEN
125 CALL dgemm("T", "N", nsgfa, nsgfb, ncoa, &
126 1.0_dp, sphi_a(1, sgfa), ldsa, &
127 work(1, 1), ldwork, &
128 1.0_dp, sin_block(sgfa, sgfb), &
129 SIZE(sin_block, 1))
130 ELSE
131 CALL dgemm("T", "N", nsgfb, nsgfa, ncoa, &
132 1.0_dp, work(1, 1), ldwork, &
133 sphi_a(1, sgfa), ldsa, &
134 1.0_dp, sin_block(sgfb, sgfa), &
135 SIZE(sin_block, 1))
136 END IF
137
138 END SUBROUTINE contract_expikr
139
140! **************************************************************************************************
141!> \brief Evaluate primitive exp(i k.r) integrals through the complex overlap recurrence.
142!> \param la_max_set highest bra shell
143!> \param npgfa number of bra primitives
144!> \param zeta bra Gaussian exponents
145!> \param rpgfa bra primitive radii
146!> \param la_min_set lowest bra shell
147!> \param lb_max highest ket shell
148!> \param npgfb number of ket primitives
149!> \param zetb ket Gaussian exponents
150!> \param rpgfb ket primitive radii
151!> \param lb_min lowest ket shell
152!> \param rac bra-center coordinates relative to the phase origin
153!> \param rbc ket-center coordinates relative to the phase origin
154!> \param kvec plane-wave vector
155!> \param expab primitive integrals in the full Cartesian layout, zero below the requested shells
156!> \param dexpab optional bra-center derivatives with the plane-wave operator held fixed
157!> \param dexpba optional ket-center derivatives in the same bra/ket layout
158!> \param momentab optional coordinate-weighted integrals relative to the phase origin
159!> Derivative and moment outputs cover the full Cartesian range.
160! **************************************************************************************************
161 SUBROUTINE expikr(la_max_set, npgfa, zeta, rpgfa, la_min_set, &
162 lb_max, npgfb, zetb, rpgfb, lb_min, rac, rbc, kvec, expab, dexpab, dexpba, momentab)
163 INTEGER, INTENT(IN) :: la_max_set, npgfa
164 REAL(kind=dp), INTENT(IN) :: zeta(:), rpgfa(:)
165 INTEGER, INTENT(IN) :: la_min_set, lb_max, npgfb
166 REAL(kind=dp), INTENT(IN) :: zetb(:), rpgfb(:)
167 INTEGER, INTENT(IN) :: lb_min
168 REAL(kind=dp), INTENT(IN) :: rac(3), rbc(3), kvec(3)
169 COMPLEX(KIND=dp), INTENT(INOUT) :: expab(:, :)
170 COMPLEX(KIND=dp), INTENT(INOUT), OPTIONAL, TARGET :: dexpab(:, :, :), dexpba(:, :, :), &
171 momentab(:, :, :)
172
173 COMPLEX(KIND=dp) :: prefactor, zrap(3), zrbp(3)
174 COMPLEX(KIND=dp), ALLOCATABLE :: opr_rr(:, :, :), rr(:, :, :)
175 COMPLEX(KIND=dp), POINTER :: opr_values(:, :, :)
176 INTEGER :: avec(3), bvec(3), coa, cob, ia, ib, &
177 idir, ipgf, jdir, jpgf, kdir, ldrr, &
178 lma, lmb, ma, mb, na, nb, op
179 LOGICAL :: derivative, right
180 REAL(kind=dp) :: dab, exponent, f0, f1, f2, k2, kdp, &
181 origin(3), rab(3), rab2, zet, zetp
182
183 rab = rbc - rac
184 dab = norm2(rab)
185 rab2 = sum(rab**2)
186 k2 = sum(kvec**2)
187 lma = la_max_set
188 lmb = lb_max
189 IF (PRESENT(dexpab) .OR. PRESENT(momentab)) lma = lma + 1
190 IF (PRESENT(dexpba)) lmb = lmb + 1
191 ldrr = max(lma, lmb) + 1
192 ALLOCATE (rr(0:ldrr - 1, 0:ldrr - 1, 3))
193 IF (PRESENT(dexpab) .OR. PRESENT(dexpba) .OR. PRESENT(momentab)) THEN
194 ALLOCATE (opr_rr(0:la_max_set, 0:lb_max, 3))
195 END IF
196
197 na = ncoset(la_max_set)
198 nb = ncoset(lb_max)
199 expab(1:na*npgfa, 1:nb*npgfb) = 0.0_dp
200 IF (PRESENT(dexpab)) dexpab(1:na*npgfa, 1:nb*npgfb, 1:3) = 0.0_dp
201 IF (PRESENT(dexpba)) dexpba(1:na*npgfa, 1:nb*npgfb, 1:3) = 0.0_dp
202 IF (PRESENT(momentab)) momentab(1:na*npgfa, 1:nb*npgfb, 1:3) = 0.0_dp
203
204 DO ipgf = 1, npgfa
205 ma = (ipgf - 1)*na
206 DO jpgf = 1, npgfb
207 IF (rpgfa(ipgf) + rpgfb(jpgf) < dab) cycle
208 mb = (jpgf - 1)*nb
209 zet = zeta(ipgf) + zetb(jpgf)
210 zetp = 1.0_dp/zet
211 f0 = (pi*zetp)**1.5_dp
212 f1 = zetb(jpgf)*zetp
213 f2 = 0.5_dp*zetp
214 kdp = zetp*dot_product(kvec, zeta(ipgf)*rac + zetb(jpgf)*rbc)
215 prefactor = f0*exp(cmplx(-zeta(ipgf)*f1*rab2 - 0.25_dp*k2*zetp, kdp, kind=dp))
216
217 ! The normalized 1D tables carry no three-dimensional prefactor.
218 zrap = cmplx(f1*rab, f2*kvec, kind=dp)
219 zrbp = zrap - rab
220 CALL os_rr_ovlp(zrap, lma, zrbp, lmb, zet, ldrr, rr)
221 DO cob = ncoset(lb_min - 1) + 1, nb
222 bvec = indco(:, cob)
223 DO coa = ncoset(la_min_set - 1) + 1, na
224 avec = indco(:, coa)
225 expab(ma + coa, mb + cob) = prefactor*rr(avec(1), bvec(1), 1)* &
226 rr(avec(2), bvec(2), 2)*rr(avec(3), bvec(3), 3)
227 END DO
228 END DO
229
230 DO op = 1, 3
231 SELECT CASE (op)
232 CASE (1)
233 IF (.NOT. PRESENT(dexpab)) cycle
234 opr_values => dexpab
235 exponent = zeta(ipgf)
236 CASE (2)
237 IF (.NOT. PRESENT(dexpba)) cycle
238 opr_values => dexpba
239 exponent = zetb(jpgf)
240 CASE (3)
241 IF (.NOT. PRESENT(momentab)) cycle
242 opr_values => momentab
243 exponent = 0.0_dp
244 END SELECT
245 right = op == 2
246 derivative = op /= 3
247 origin = 0.0_dp
248 IF (.NOT. derivative) origin = rac
249 CALL apply_cartesian_1d(rr, opr_rr, la_max_set, lb_max, right, derivative, exponent, origin)
250 DO cob = 1, nb
251 bvec = indco(:, cob)
252 ib = mb + cob
253 DO coa = 1, na
254 avec = indco(:, coa)
255 ia = ma + coa
256 DO idir = 1, 3
257 jdir = mod(idir, 3) + 1
258 kdir = mod(idir + 1, 3) + 1
259 opr_values(ia, ib, idir) = prefactor*opr_rr(avec(idir), bvec(idir), idir)* &
260 rr(avec(jdir), bvec(jdir), jdir)*rr(avec(kdir), bvec(kdir), kdir)
261 END DO
262 END DO
263 END DO
264 END DO
265 END DO
266 END DO
267 END SUBROUTINE expikr
268
269! **************************************************************************************************
270!> \brief ...
271!> \param la_max ...
272!> \param npgfa ...
273!> \param zeta ...
274!> \param rpgfa ...
275!> \param la_min ...
276!> \param lb_max ...
277!> \param npgfb ...
278!> \param zetb ...
279!> \param rpgfb ...
280!> \param lc_max ...
281!> \param rac ...
282!> \param rbc ...
283!> \param mab ...
284!> \param overlap optional zeroth moment in primitive-major cumulative Cartesian order;
285!> entries outside the requested row and column ranges are untouched
286! **************************************************************************************************
287 SUBROUTINE moment(la_max, npgfa, zeta, rpgfa, la_min, &
288 lb_max, npgfb, zetb, rpgfb, lc_max, rac, rbc, mab, overlap)
289 INTEGER, INTENT(IN) :: la_max, npgfa
290 REAL(kind=dp), DIMENSION(:), INTENT(IN) :: zeta, rpgfa
291 INTEGER, INTENT(IN) :: la_min, lb_max, npgfb
292 REAL(kind=dp), DIMENSION(:), INTENT(IN) :: zetb, rpgfb
293 INTEGER, INTENT(IN) :: lc_max
294 REAL(kind=dp), DIMENSION(3), INTENT(IN) :: rac, rbc
295 REAL(kind=dp), DIMENSION(:, :, :), INTENT(INOUT) :: mab
296 REAL(kind=dp), DIMENSION(:, :), INTENT(INOUT), OPTIONAL :: overlap
297
298 INTEGER :: ax, ay, az, bx, by, bz, coa, cob, i, ia, &
299 ib, imom, ipgf, jpgf, ldrr, lx, ly, &
300 lz, ma, mb, powers(0:lc_max)
301 REAL(kind=dp) :: a, b, dab, f0, rab(3), rab2, rap(3), &
302 rbp(3), zet
303 REAL(kind=dp), ALLOCATABLE :: polynomial(:, :, :, :), rr(:, :, :)
304
305 mark_used(la_min)
306 rab = rbc - rac
307 dab = norm2(rab)
308 rab2 = dab**2
309 ldrr = max(la_max + lc_max, lb_max) + 1
310 ALLOCATE (rr(0:ldrr - 1, 0:ldrr - 1, 3), polynomial(0:la_max, 0:lb_max, 0:lc_max, 3))
311 powers = [(i, i=0, lc_max)]
312 mab(:npgfa*ncoset(la_max), :npgfb*ncoset(lb_max), :ncoset(lc_max) - 1) = 0.0_dp
313 IF (PRESENT(overlap)) overlap(:npgfa*ncoset(la_max), :npgfb*ncoset(lb_max)) = 0.0_dp
314 DO ipgf = 1, npgfa
315 ma = (ipgf - 1)*ncoset(la_max)
316 DO jpgf = 1, npgfb
317 IF (rpgfa(ipgf) + rpgfb(jpgf) < dab) cycle
318 mb = (jpgf - 1)*ncoset(lb_max)
319 a = zeta(ipgf)
320 b = zetb(jpgf)
321 zet = a + b
322 rap = b*rab/zet
323 rbp = -a*rab/zet
324 f0 = (pi/zet)**1.5_dp*exp(-a*b*rab2/zet)
325 CALL os_rr_ovlp(rap, la_max + lc_max, rbp, lb_max, zet, ldrr, rr)
326 CALL cartesian_polynomial_1d(rr, polynomial, la_max, lb_max, powers, rac)
327
328 DO cob = 1, ncoset(lb_max)
329 bx = indco(1, cob)
330 by = indco(2, cob)
331 bz = indco(3, cob)
332 ib = mb + cob
333 DO coa = 1, ncoset(la_max)
334 ax = indco(1, coa)
335 ay = indco(2, coa)
336 az = indco(3, coa)
337 ia = ma + coa
338 IF (PRESENT(overlap)) THEN
339 overlap(ia, ib) = f0*polynomial(ax, bx, 0, 1)* &
340 polynomial(ay, by, 0, 2)*polynomial(az, bz, 0, 3)
341 END IF
342 ! Preserve the coset ordering and omission of the zeroth moment.
343 DO imom = 1, ncoset(lc_max) - 1
344 lx = indco(1, imom + 1)
345 ly = indco(2, imom + 1)
346 lz = indco(3, imom + 1)
347 mab(ia, ib, imom) = f0*polynomial(ax, bx, lx, 1)* &
348 polynomial(ay, by, ly, 2)*polynomial(az, bz, lz, 3)
349 END DO
350 END DO
351 END DO
352 END DO
353 END DO
354 END SUBROUTINE moment
355
356! **************************************************************************************************
357!> \brief This returns the derivative of the moment integrals [a|\mu|b].
358!> By default, it differentiates the primitive on the right:
359!> [a|\mu|d/dR_bi] = 2*zetb*[a|\mu|b+1i] - Ni(b)[a|\mu|b-1i]
360!> A weighted derivative combines the left and right primitive derivatives
361!> using deltaR for the corresponding atom centers.
362!> order indicates the max order of the moment operator to be calculated
363!> 1: dipole
364!> 2: quadrupole
365!> ...
366!> \param la_max ...
367!> \param npgfa ...
368!> \param zeta ...
369!> \param rpgfa ...
370!> \param la_min ...
371!> \param lb_max ...
372!> \param npgfb ...
373!> \param zetb ...
374!> \param rpgfb ...
375!> \param lb_min ...
376!> \param order ...
377!> \param rac ...
378!> \param rbc ...
379!> \param difmab ...
380!> \param mab_ext optional precomputed moments with zero screened primitive blocks, including raised shells
381!> \param deltaR optional weights for the left and right primitive derivatives
382!> \param lambda optional atom selector for the factor (iatom == lambda) - (jatom == lambda)
383!> \param iatom atom associated with the left basis function
384!> \param jatom atom associated with the right basis function
385!> \note
386! **************************************************************************************************
387 SUBROUTINE diff_momop(la_max, npgfa, zeta, rpgfa, la_min, &
388 lb_max, npgfb, zetb, rpgfb, lb_min, &
389 order, rac, rbc, difmab, mab_ext, deltaR, lambda, iatom, jatom)
390
391 INTEGER, INTENT(IN) :: la_max, npgfa
392 REAL(kind=dp), DIMENSION(:), INTENT(IN) :: zeta, rpgfa
393 INTEGER, INTENT(IN) :: la_min, lb_max, npgfb
394 REAL(kind=dp), DIMENSION(:), INTENT(IN) :: zetb, rpgfb
395 INTEGER, INTENT(IN) :: lb_min, order
396 REAL(kind=dp), DIMENSION(3), INTENT(IN) :: rac, rbc
397 REAL(kind=dp), DIMENSION(:, :, :, :), INTENT(OUT) :: difmab
398 REAL(kind=dp), DIMENSION(:, :, :), OPTIONAL, &
399 POINTER :: mab_ext
400 REAL(kind=dp), DIMENSION(:, :), OPTIONAL, POINTER :: deltar
401 INTEGER, INTENT(IN), OPTIONAL :: lambda, iatom, jatom
402
403 INTEGER :: ider, imom, lda, lda_min, ldb, ldb_min
404 REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :, :) :: difmab_tmp
405 REAL(kind=dp), DIMENSION(:, :, :), POINTER :: mab
406
407 lda_min = max(0, la_min - 1)
408 ldb_min = max(0, lb_min - 1)
409 lda = ncoset(la_max)*npgfa
410 ldb = ncoset(lb_max)*npgfb
411 ALLOCATE (difmab_tmp(lda, ldb, 3))
412
413 IF (PRESENT(mab_ext)) THEN
414 mab => mab_ext
415 ELSE
416 ALLOCATE (mab(npgfa*ncoset(la_max + 1), npgfb*ncoset(lb_max + 1), &
417 ncoset(order) - 1))
418 mab = 0.0_dp
419! *** Calculate the primitive overlap integrals ***
420 CALL moment(la_max + 1, npgfa, zeta, rpgfa, lda_min, &
421 lb_max + 1, npgfb, zetb, rpgfb, &
422 order, rac, rbc, mab)
423
424 END IF
425 DO imom = 1, ncoset(order) - 1
426 CALL apply_cartesian_operator(la_max, 0, npgfa, lb_max, 0, npgfb, mab(:, :, imom), &
427 difmab_tmp, right=.true., derivative=.true., exponents=zetb)
428 IF (PRESENT(deltar)) THEN
429 cpassert(ASSOCIATED(deltar))
430 cpassert(PRESENT(iatom) .AND. PRESENT(jatom))
431 DO ider = 1, 3
432 difmab(1:lda, 1:ldb, imom, ider) = &
433 difmab_tmp(1:lda, 1:ldb, ider)*deltar(ider, jatom)
434 END DO
435
436 CALL apply_cartesian_operator(la_max, 0, npgfa, lb_max, 0, npgfb, mab(:, :, imom), &
437 difmab_tmp, right=.false., derivative=.true., exponents=zeta)
438 DO ider = 1, 3
439 difmab(1:lda, 1:ldb, imom, ider) = difmab(1:lda, 1:ldb, imom, ider) &
440 + difmab_tmp(1:lda, 1:ldb, ider)*deltar(ider, iatom)
441 END DO
442 ELSE
443 difmab(1:lda, 1:ldb, imom, :) = difmab_tmp(1:lda, 1:ldb, :)
444 END IF
445 END DO
446
447 IF (PRESENT(lambda)) THEN
448 cpassert(.NOT. PRESENT(deltar))
449 cpassert(PRESENT(iatom) .AND. PRESENT(jatom))
450 IF (iatom == lambda .AND. jatom == lambda) THEN
451 difmab = 0.0_dp
452 ELSE IF (iatom == lambda) THEN
453 ! The right-hand derivative is selected with a positive sign.
454 ELSE IF (jatom == lambda) THEN
455 difmab = -difmab
456 ELSE
457 difmab = 0.0_dp
458 END IF
459 END IF
460
461 IF (PRESENT(mab_ext)) THEN
462 NULLIFY (mab)
463 ELSE
464 DEALLOCATE (mab)
465 END IF
466 DEALLOCATE (difmab_tmp)
467
468 END SUBROUTINE diff_momop
469
470! **************************************************************************************************
471!> \brief This returns the derivative of the dipole integrals [a|x|b], with respect
472!> to the position of the primitive on the left and right, i.e.
473!> [da/dR_ai|\mu|b] = 2*zeta*[a+1i|\mu|b] - Ni(a)[a-1i|\mu|b]
474!> \param la_max ...
475!> \param npgfa ...
476!> \param zeta ...
477!> \param rpgfa ...
478!> \param la_min ...
479!> \param lb_max ...
480!> \param npgfb ...
481!> \param zetb ...
482!> \param rpgfb ...
483!> \param lb_min ...
484!> \param order ...
485!> \param rac ...
486!> \param rbc ...
487!> \param pab ...
488!> \param forcea ...
489!> \param forceb ...
490!> \note
491! **************************************************************************************************
492 SUBROUTINE dipole_force(la_max, npgfa, zeta, rpgfa, la_min, &
493 lb_max, npgfb, zetb, rpgfb, lb_min, &
494 order, rac, rbc, pab, forcea, forceb)
495
496 INTEGER, INTENT(IN) :: la_max, npgfa
497 REAL(kind=dp), DIMENSION(:), INTENT(IN) :: zeta, rpgfa
498 INTEGER, INTENT(IN) :: la_min, lb_max, npgfb
499 REAL(kind=dp), DIMENSION(:), INTENT(IN) :: zetb, rpgfb
500 INTEGER, INTENT(IN) :: lb_min, order
501 REAL(kind=dp), DIMENSION(3), INTENT(IN) :: rac, rbc
502 REAL(kind=dp), DIMENSION(:, :), INTENT(IN) :: pab
503 REAL(kind=dp), DIMENSION(:, :), INTENT(INOUT), TARGET :: forcea, forceb
504
505 INTEGER, PARAMETER :: components(2, 9) = reshape([1, 1, 2, 1, 3, 1, 1, 2, 2, 2, 3, 2, 1, 3, 2, 3, 3, 3], [2, 9])
506 INTEGER :: axis, first_a, first_b, icomp, ipgf, jpgf, ma, mb, nrow, ncol, side
507 INTEGER :: map_a(4, ncoset(la_max) - ncoset(la_min - 1), 3), &
508 map_b(4, ncoset(lb_max) - ncoset(lb_min - 1), 3)
509 REAL(kind=dp) :: origin(3, 2), rab(3), distance, rr_work(3*(max(la_max, lb_max) + 2)**2)
510 REAL(kind=dp), ALLOCATABLE :: source(:, :), work(:, :), derivatives(:, :, :)
511 REAL(kind=dp), POINTER :: forces(:, :)
512
513 cpassert(order == 1)
514 mark_used(order)
515 first_a = ncoset(la_min - 1) + 1
516 first_b = ncoset(lb_min - 1) + 1
517 nrow = ncoset(la_max) - first_a + 1
518 ncol = ncoset(lb_max) - first_b + 1
519 ALLOCATE (source(ncoset(la_max + 1), ncoset(lb_max + 1)), work(ncoset(la_max + 1), ncoset(lb_max + 1)), &
520 derivatives(nrow, ncol, 9))
521 DO axis = 1, 3
522 CALL cartesian_ladder_map(la_max, la_min, axis, map_a(:, :, axis), source_lmin=0)
523 CALL cartesian_ladder_map(lb_max, lb_min, axis, map_b(:, :, axis), source_lmin=0)
524 END DO
525 origin = 0.0_dp
526 rab = rbc - rac
527 distance = norm2(rab)
528 DO ipgf = 1, npgfa
529 ma = (ipgf - 1)*ncoset(la_max)
530 DO jpgf = 1, npgfb
531 IF (rpgfa(ipgf) + rpgfb(jpgf) < distance) cycle
532 mb = (jpgf - 1)*ncoset(lb_max)
533 CALL overlap_ab(la_max + 1, 0, 1, rpgfa(ipgf:ipgf), zeta(ipgf:ipgf), &
534 lb_max + 1, 0, 1, rpgfb(jpgf:jpgf), zetb(jpgf:jpgf), rab, &
535 sab=source, rr_work=rr_work)
536 ! Multiply by the coordinate on the side opposite the differentiated Gaussian.
537 DO side = 1, 2
538 IF (side == 1) THEN
539 forces => forcea
540 origin(:, 1) = rbc
541 CALL apply_cartesian_operator_pair(source, derivatives, map_b, map_a, components, &
542 [.false., .true.], [0.0_dp, zeta(ipgf)], &
543 [.true., .false.], work(:, 1:ncol), origin)
544 ELSE
545 forces => forceb
546 origin(:, 1) = rac
547 CALL apply_cartesian_operator_pair(source, derivatives, map_a, map_b, components, &
548 [.false., .true.], [0.0_dp, zetb(jpgf)], &
549 [.false., .true.], work(1:nrow, :), origin)
550 END IF
551 DO icomp = 1, 9
552 forces(components(1, icomp), components(2, icomp)) = &
553 forces(components(1, icomp), components(2, icomp)) + &
554 sum(pab(ma + first_a:ma + ncoset(la_max), mb + first_b:mb + ncoset(lb_max))*derivatives(:, :, icomp))
555 END DO
556 END DO
557 END DO
558 END DO
559
560 END SUBROUTINE dipole_force
561
562END MODULE ai_moments
static void dgemm(const char transa, const char transb, const int m, const int n, const int k, const double alpha, const double *a, const int lda, const double *b, const int ldb, const double beta, double *c, const int ldc)
Convenient wrapper to hide Fortran nature of dgemm_, swapping a and b.
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...
Calculation of the moment integrals over Cartesian Gaussian-type functions.
Definition ai_moments.F:17
subroutine, public moment(la_max, npgfa, zeta, rpgfa, la_min, lb_max, npgfb, zetb, rpgfb, lc_max, rac, rbc, mab, overlap)
...
Definition ai_moments.F:289
subroutine, public dipole_force(la_max, npgfa, zeta, rpgfa, la_min, lb_max, npgfb, zetb, rpgfb, lb_min, order, rac, rbc, pab, forcea, forceb)
This returns the derivative of the dipole integrals [a|x|b], with respect to the position of the prim...
Definition ai_moments.F:495
subroutine, public expikr(la_max_set, npgfa, zeta, rpgfa, la_min_set, lb_max, npgfb, zetb, rpgfb, lb_min, rac, rbc, kvec, expab, dexpab, dexpba, momentab)
Evaluate primitive exp(i k.r) integrals through the complex overlap recurrence.
Definition ai_moments.F:163
subroutine, public diff_momop(la_max, npgfa, zeta, rpgfa, la_min, lb_max, npgfb, zetb, rpgfb, lb_min, order, rac, rbc, difmab, mab_ext, deltar, lambda, iatom, jatom)
This returns the derivative of the moment integrals [a|\mu|b]. By default, it differentiates the prim...
Definition ai_moments.F:390
subroutine, public contract_expikr(cos_block, sin_block, iatom, ncoa, nsgfa, sgfa, sphi_a, ldsa, jatom, ncob, nsgfb, sgfb, sphi_b, ldsb, expab, work, ldwork, ordered)
Contract complex primitive integrals into real cosine and sine AO blocks.
Definition ai_moments.F:80
Calculation of the overlap integrals over Cartesian Gaussian-type functions.
Definition ai_overlap.F:18
subroutine, public overlap(la_max_set, la_min_set, npgfa, rpgfa, zeta, lb_max_set, lb_min_set, npgfb, rpgfb, zetb, rab, dab, sab, da_max_set, return_derivatives, s, lds)
Purpose: Calculation of the two-center overlap integrals [a|b] over Cartesian Gaussian-type functions...
Definition ai_overlap.F:75
subroutine, public overlap_ab(la_max, la_min, npgfa, rpgfa, zeta, lb_max, lb_min, npgfb, rpgfb, zetb, rab, sab, dab, ddab, rr_work)
Calculation of the two-center overlap integrals [a|b] over Cartesian Gaussian-type functions....
Definition ai_overlap.F:249
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 pi
Provides Cartesian and spherical orbital pointers and indices.
integer, dimension(:), allocatable, public ncoset
integer, dimension(:, :), allocatable, public indco