Line data Source code
1 : !--------------------------------------------------------------------------------------------------!
2 : ! CP2K: A general program to perform molecular dynamics simulations !
3 : ! Copyright 2000-2024 CP2K developers group <https://cp2k.org> !
4 : ! !
5 : ! SPDX-License-Identifier: GPL-2.0-or-later !
6 : !--------------------------------------------------------------------------------------------------!
7 :
8 : ! **************************************************************************************************
9 : !> \brief Set of routines to:
10 : !> Contract integrals over primitive Gaussians
11 : !> Decontract (density) matrices
12 : !> Trace matrices to get forces
13 : !> Block copy and add matrices
14 : !> \par History
15 : !> Replace dgemm by MATMUL: Massive speedups in openMP loops (JGH, 12.2019)
16 : !> \author JGH (01.07.2014)
17 : ! **************************************************************************************************
18 : MODULE ai_contraction
19 :
20 : USE kinds, ONLY: dp
21 : #include "../base/base_uses.f90"
22 :
23 : IMPLICIT NONE
24 :
25 : CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'ai_contraction'
26 :
27 : PRIVATE
28 :
29 : PUBLIC :: contraction, decontraction, block_add, force_trace
30 :
31 : INTERFACE contraction
32 : MODULE PROCEDURE contraction_ab, contraction_abc
33 : END INTERFACE
34 :
35 : INTERFACE decontraction
36 : MODULE PROCEDURE decontraction_ab
37 : END INTERFACE
38 :
39 : INTERFACE force_trace
40 : MODULE PROCEDURE force_trace_ab
41 : END INTERFACE
42 :
43 : INTERFACE block_add
44 : MODULE PROCEDURE block_add_ab
45 : END INTERFACE
46 :
47 : ! **************************************************************************************************
48 :
49 : CONTAINS
50 :
51 : ! **************************************************************************************************
52 : !> \brief Applying the contraction coefficients to a set of two-center primitive
53 : !> integrals
54 : !> QAB <- CA(T) * SAB * CB
55 : !> QAB is optionally scaled with "fscale"
56 : !> Variable "trans" requests the output to be QAB(T)
57 : !> If only one of the transformation matrix is given, only a half
58 : !> transformation is done
59 : !> Active dimensions are: QAB(ma,mb), SAB(na,nb)
60 : !> \param sab Input matrix, dimension(:,:)
61 : !> \param qab Output matrix, dimension(:,:)
62 : !> \param ca Left transformation matrix, optional
63 : !> \param na First dimension of ca, optional
64 : !> \param ma Second dimension of ca, optional
65 : !> \param cb Right transformation matrix, optional
66 : !> \param nb First dimension of cb, optional
67 : !> \param mb Second dimension of cb, optional
68 : !> \param fscale Optional scaling of output
69 : !> \param trans Optional transposition of output
70 : ! **************************************************************************************************
71 19274566 : SUBROUTINE contraction_ab(sab, qab, ca, na, ma, cb, nb, mb, fscale, trans)
72 :
73 : REAL(KIND=dp), DIMENSION(:, :), INTENT(IN) :: sab
74 : REAL(KIND=dp), DIMENSION(:, :), INTENT(INOUT) :: qab
75 : REAL(KIND=dp), DIMENSION(:, :), INTENT(IN), &
76 : OPTIONAL :: ca
77 : INTEGER, INTENT(IN), OPTIONAL :: na, ma
78 : REAL(KIND=dp), DIMENSION(:, :), INTENT(IN), &
79 : OPTIONAL :: cb
80 : INTEGER, INTENT(IN), OPTIONAL :: nb, mb
81 : REAL(KIND=dp), INTENT(IN), OPTIONAL :: fscale
82 : LOGICAL, INTENT(IN), OPTIONAL :: trans
83 :
84 : INTEGER :: lda, ldb, ldq, lds, ldw, mal, mbl, nal, &
85 : nbl
86 : LOGICAL :: my_trans
87 : REAL(KIND=dp) :: fs
88 19274566 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: work
89 :
90 : ! Should output matrix be transposed?
91 :
92 19274566 : IF (PRESENT(trans)) THEN
93 19273842 : my_trans = trans
94 : ELSE
95 : my_trans = .FALSE.
96 : END IF
97 :
98 : ! Scaling of output matrix
99 19274566 : IF (PRESENT(fscale)) THEN
100 19272816 : fs = fscale
101 : ELSE
102 : fs = 1.0_dp
103 : END IF
104 :
105 : ! Active matrix size
106 19274566 : IF (PRESENT(ca)) THEN
107 19274566 : IF (PRESENT(na)) THEN
108 19274566 : nal = na
109 : ELSE
110 0 : nal = SIZE(ca, 1)
111 : END IF
112 19274566 : IF (PRESENT(ma)) THEN
113 19274566 : mal = ma
114 : ELSE
115 0 : mal = SIZE(ca, 2)
116 : END IF
117 19274566 : lda = SIZE(ca, 1)
118 : END IF
119 19274566 : IF (PRESENT(cb)) THEN
120 19274566 : IF (PRESENT(nb)) THEN
121 19274566 : nbl = nb
122 : ELSE
123 0 : nbl = SIZE(cb, 1)
124 : END IF
125 19274566 : IF (PRESENT(mb)) THEN
126 19274566 : mbl = mb
127 : ELSE
128 0 : mbl = SIZE(cb, 2)
129 : END IF
130 19274566 : ldb = SIZE(cb, 1)
131 : END IF
132 :
133 19274566 : lds = SIZE(sab, 1)
134 19274566 : ldq = SIZE(qab, 1)
135 :
136 19274566 : IF (PRESENT(ca) .AND. PRESENT(cb)) THEN
137 : ! Full transform
138 77098264 : ALLOCATE (work(nal, mbl))
139 19274566 : ldw = nal
140 : !dg CALL dgemm("N", "N", nal, mbl, nbl, 1.0_dp, sab(1, 1), lds, cb(1, 1), ldb, 0.0_dp, work(1, 1), ldw)
141 16789299197 : work(1:nal, 1:mbl) = MATMUL(sab(1:nal, 1:nbl), cb(1:nbl, 1:mbl))
142 19274566 : IF (my_trans) THEN
143 : !dg CALL dgemm("T", "N", mbl, mal, nal, fs, work(1, 1), ldw, ca(1, 1), lda, 0.0_dp, qab(1, 1), ldq)
144 2222280802 : qab(1:mbl, 1:mal) = fs*MATMUL(TRANSPOSE(work(1:nal, 1:mbl)), ca(1:nal, 1:mal))
145 : ELSE
146 : !dg CALL dgemm("T", "N", mal, mbl, nal, fs, ca(1, 1), lda, work(1, 1), ldw, 0.0_dp, qab(1, 1), ldq)
147 5053534043 : qab(1:mal, 1:mbl) = fs*MATMUL(TRANSPOSE(ca(1:nal, 1:mal)), work(1:nal, 1:mbl))
148 : END IF
149 19274566 : DEALLOCATE (work)
150 0 : ELSE IF (PRESENT(ca)) THEN
151 0 : IF (PRESENT(nb)) THEN
152 0 : nbl = nb
153 : ELSE
154 0 : nbl = SIZE(sab, 2)
155 : END IF
156 0 : IF (my_trans) THEN
157 : !dg CALL dgemm("T", "N", nbl, mal, nal, fs, sab(1, 1), lds, ca(1, 1), lda, 0.0_dp, qab(1, 1), ldq)
158 0 : qab(1:nbl, 1:mal) = fs*MATMUL(TRANSPOSE(sab(1:nal, 1:nbl)), ca(1:nal, 1:mal))
159 : ELSE
160 : !dg CALL dgemm("T", "N", mal, nbl, nal, fs, ca(1, 1), lda, sab(1, 1), lds, 0.0_dp, qab(1, 1), ldq)
161 0 : qab(1:mal, 1:nbl) = fs*MATMUL(TRANSPOSE(ca(1:nal, 1:mal)), sab(1:nal, 1:nbl))
162 : END IF
163 0 : ELSE IF (PRESENT(cb)) THEN
164 0 : IF (PRESENT(na)) THEN
165 0 : nal = na
166 : ELSE
167 0 : nal = SIZE(sab, 1)
168 : END IF
169 0 : IF (my_trans) THEN
170 : !dg CALL dgemm("N", "N", nal, mbl, nbl, fs, sab(1, 1), lds, cb(1, 1), ldb, 0.0_dp, qab, ldq)
171 0 : qab(1:nal, 1:mbl) = fs*MATMUL(sab(1:nal, 1:nbl), cb(1:nbl, 1:mbl))
172 : ELSE
173 : !dg CALL dgemm("T", "T", mbl, nal, nbl, fs, cb(1, 1), ldb, sab(1, 1), lds, 0.0_dp, qab, ldq)
174 0 : qab(1:mbl, 1:nal) = fs*MATMUL(TRANSPOSE(cb(1:nbl, 1:mbl)), TRANSPOSE(sab(1:nal, 1:nbl)))
175 : END IF
176 : ELSE
177 : ! Copy of arrays is not covered here
178 0 : CPABORT("Copy of arrays is not covered here")
179 : END IF
180 :
181 19274566 : END SUBROUTINE contraction_ab
182 :
183 : ! **************************************************************************************************
184 : !> \brief Applying the contraction coefficients to a tripple set integrals
185 : !> QABC <- CA(T) * SABC * CB * CC
186 : !> If only one or two of the transformation matrices are given, only a
187 : !> part transformation is done
188 : !> \param sabc Input matrix, dimension(:,:)
189 : !> \param qabc Output matrix, dimension(:,:)
190 : !> \param ca Transformation matrix (index 1), optional
191 : !> \param na First dimension of ca, optional
192 : !> \param ma Second dimension of ca, optional
193 : !> \param cb Transformation matrix (index 2), optional
194 : !> \param nb First dimension of cb, optional
195 : !> \param mb Second dimension of cb, optional
196 : !> \param cc Transformation matrix (index 3), optional
197 : !> \param nc First dimension of cc, optional
198 : !> \param mc Second dimension of cc, optional
199 : ! **************************************************************************************************
200 0 : SUBROUTINE contraction_abc(sabc, qabc, ca, na, ma, cb, nb, mb, cc, nc, mc)
201 :
202 : REAL(KIND=dp), DIMENSION(:, :, :), INTENT(IN) :: sabc
203 : REAL(KIND=dp), DIMENSION(:, :, :), INTENT(INOUT) :: qabc
204 : REAL(KIND=dp), DIMENSION(:, :), INTENT(IN), &
205 : OPTIONAL :: ca
206 : INTEGER, INTENT(IN), OPTIONAL :: na, ma
207 : REAL(KIND=dp), DIMENSION(:, :), INTENT(IN), &
208 : OPTIONAL :: cb
209 : INTEGER, INTENT(IN), OPTIONAL :: nb, mb
210 : REAL(KIND=dp), DIMENSION(:, :), INTENT(IN), &
211 : OPTIONAL :: cc
212 : INTEGER, INTENT(IN), OPTIONAL :: nc, mc
213 :
214 : INTEGER :: lda, ldb, ldc, mal, mbl, mcl, nal, nbl, &
215 : ncl
216 0 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :) :: work1, work2, work3, work4
217 :
218 : ! Active matrix size
219 :
220 0 : IF (PRESENT(ca)) THEN
221 0 : IF (PRESENT(na)) THEN
222 0 : nal = na
223 : ELSE
224 0 : nal = SIZE(ca, 1)
225 : END IF
226 0 : IF (PRESENT(ma)) THEN
227 0 : mal = ma
228 : ELSE
229 0 : mal = SIZE(ca, 2)
230 : END IF
231 0 : lda = SIZE(ca, 1)
232 : END IF
233 0 : IF (PRESENT(cb)) THEN
234 0 : IF (PRESENT(nb)) THEN
235 0 : nbl = nb
236 : ELSE
237 0 : nbl = SIZE(cb, 1)
238 : END IF
239 0 : IF (PRESENT(mb)) THEN
240 0 : mbl = mb
241 : ELSE
242 0 : mbl = SIZE(cb, 2)
243 : END IF
244 0 : ldb = SIZE(cb, 1)
245 : END IF
246 0 : IF (PRESENT(cc)) THEN
247 0 : IF (PRESENT(nc)) THEN
248 0 : ncl = nc
249 : ELSE
250 0 : ncl = SIZE(cc, 1)
251 : END IF
252 0 : IF (PRESENT(mc)) THEN
253 0 : mcl = mc
254 : ELSE
255 0 : mcl = SIZE(cc, 2)
256 : END IF
257 0 : ldc = SIZE(cc, 1)
258 : END IF
259 :
260 0 : IF (PRESENT(ca) .AND. PRESENT(cb) .AND. PRESENT(cc)) THEN
261 : ! Full transform
262 0 : ALLOCATE (work1(nal, nbl, ncl))
263 : ! make sure that we have contiguous memory, needed for transpose algorithm
264 0 : work1(1:nal, 1:nbl, 1:ncl) = sabc(1:nal, 1:nbl, 1:ncl)
265 : !
266 0 : ALLOCATE (work2(nbl, ncl, mal))
267 : CALL dgemm("T", "N", nbl*ncl, mal, nal, 1.0_dp, work1(1, 1, 1), nal, ca(1, 1), lda, &
268 0 : 0.0_dp, work2(1, 1, 1), nbl*ncl)
269 : !
270 0 : ALLOCATE (work3(ncl, mal, mbl))
271 : CALL dgemm("T", "N", ncl*mal, mbl, nbl, 1.0_dp, work2(1, 1, 1), nbl, cb(1, 1), ldb, &
272 0 : 0.0_dp, work3(1, 1, 1), ncl*mal)
273 : !
274 0 : ALLOCATE (work4(mal, mbl, mcl))
275 : CALL dgemm("T", "N", mal*mbl, mcl, ncl, 1.0_dp, work3(1, 1, 1), ncl, cc(1, 1), ldc, &
276 0 : 0.0_dp, work4(1, 1, 1), mal*mbl)
277 : !
278 0 : qabc(1:mal, 1:mbl, 1:mcl) = work4(1:mal, 1:mbl, 1:mcl)
279 : !
280 0 : DEALLOCATE (work1, work2, work3, work4)
281 : !
282 0 : ELSE IF (PRESENT(ca) .AND. PRESENT(cb)) THEN
283 0 : CPABORT("Not implemented")
284 0 : ELSE IF (PRESENT(ca) .AND. PRESENT(cc)) THEN
285 0 : CPABORT("Not implemented")
286 0 : ELSE IF (PRESENT(cb) .AND. PRESENT(cc)) THEN
287 0 : CPABORT("Not implemented")
288 0 : ELSE IF (PRESENT(ca)) THEN
289 0 : CPABORT("Not implemented")
290 0 : ELSE IF (PRESENT(cb)) THEN
291 0 : CPABORT("Not implemented")
292 0 : ELSE IF (PRESENT(cc)) THEN
293 0 : CPABORT("Not implemented")
294 : ELSE
295 : ! Copy of arrays is not covered here
296 0 : CPABORT("Copy of arrays is not covered here")
297 : END IF
298 :
299 0 : END SUBROUTINE contraction_abc
300 :
301 : ! **************************************************************************************************
302 : !> \brief Applying the de-contraction coefficients to a matrix
303 : !> QAB <- CA * SAB * CB(T)
304 : !> Variable "trans" requests the input matrix to be SAB(T)
305 : !> Active dimensions are: QAB(na,nb), SAB(ma,mb)
306 : !> \param sab Input matrix, dimension(:,:)
307 : !> \param qab Output matrix, dimension(:,:)
308 : !> \param ca Left transformation matrix
309 : !> \param na First dimension of ca
310 : !> \param ma Second dimension of ca
311 : !> \param cb Right transformation matrix
312 : !> \param nb First dimension of cb
313 : !> \param mb Second dimension of cb
314 : !> \param trans Optional transposition of input matrix
315 : ! **************************************************************************************************
316 1664667 : SUBROUTINE decontraction_ab(sab, qab, ca, na, ma, cb, nb, mb, trans)
317 :
318 : REAL(KIND=dp), DIMENSION(:, :), INTENT(IN) :: sab
319 : REAL(KIND=dp), DIMENSION(:, :), INTENT(INOUT) :: qab
320 : REAL(KIND=dp), DIMENSION(:, :), INTENT(IN) :: ca
321 : INTEGER, INTENT(IN) :: na, ma
322 : REAL(KIND=dp), DIMENSION(:, :), INTENT(IN) :: cb
323 : INTEGER, INTENT(IN) :: nb, mb
324 : LOGICAL, INTENT(IN), OPTIONAL :: trans
325 :
326 : INTEGER :: lda, ldb, ldq, lds, ldw
327 : LOGICAL :: my_trans
328 1664667 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: work
329 :
330 : ! Should input matrix be transposed?
331 1664667 : IF (PRESENT(trans)) THEN
332 1664667 : my_trans = trans
333 : ELSE
334 : my_trans = .FALSE.
335 : END IF
336 :
337 1664667 : lds = SIZE(sab, 1)
338 1664667 : ldq = SIZE(qab, 1)
339 1664667 : lda = SIZE(ca, 1)
340 1664667 : ldb = SIZE(cb, 1)
341 :
342 6658668 : ALLOCATE (work(na, mb))
343 1664667 : ldw = na
344 :
345 1664667 : IF (my_trans) THEN
346 : !dg CALL dgemm("N", "T", na, mb, ma, 1.0_dp, ca, lda, sab, lds, 0.0_dp, work, ldw)
347 650765605 : work(1:na, 1:mb) = MATMUL(ca(1:na, 1:ma), TRANSPOSE(sab(1:mb, 1:ma)))
348 : ELSE
349 : !dg CALL dgemm("N", "N", na, mb, ma, 1.0_dp, ca, lda, sab, lds, 0.0_dp, work, ldw)
350 602278495 : work(1:na, 1:mb) = MATMUL(ca(1:na, 1:ma), sab(1:ma, 1:mb))
351 : END IF
352 : !dg CALL dgemm("N", "T", na, nb, mb, 1.0_dp, work, ldw, cb, ldb, 0.0_dp, qab, ldq)
353 3628347731 : qab(1:na, 1:nb) = MATMUL(work(1:na, 1:mb), TRANSPOSE(cb(1:nb, 1:mb)))
354 :
355 1664667 : DEALLOCATE (work)
356 :
357 1664667 : END SUBROUTINE decontraction_ab
358 :
359 : ! **************************************************************************************************
360 : !> \brief Routine to trace a series of matrices with another matrix
361 : !> Calculate forces of type f(:) = Trace(Pab*Sab(:))
362 : !> \param force Vector to hold output forces
363 : !> \param sab Input vector of matrices, dimension (:,:,:)
364 : !> \param pab Input matrix
365 : !> \param na Active first dimension
366 : !> \param nb Active second dimension
367 : !> \param m Number of matrices to be traced
368 : !> \param trans Matrices are transposed (Sab and Pab)
369 : ! **************************************************************************************************
370 1664667 : SUBROUTINE force_trace_ab(force, sab, pab, na, nb, m, trans)
371 :
372 : REAL(KIND=dp), DIMENSION(:), INTENT(INOUT) :: force
373 : REAL(KIND=dp), DIMENSION(:, :, :), INTENT(IN) :: sab
374 : REAL(KIND=dp), DIMENSION(:, :), INTENT(IN) :: pab
375 : INTEGER, INTENT(IN) :: na, nb, m
376 : LOGICAL, INTENT(IN), OPTIONAL :: trans
377 :
378 : INTEGER :: i
379 : LOGICAL :: my_trans
380 :
381 1664667 : CPASSERT(m <= SIZE(SAB, 3))
382 1664667 : CPASSERT(m <= SIZE(force, 1))
383 :
384 : ! are matrices transposed?
385 1664667 : IF (PRESENT(trans)) THEN
386 0 : my_trans = trans
387 : ELSE
388 : my_trans = .FALSE.
389 : END IF
390 :
391 6658668 : DO i = 1, m
392 6658668 : IF (my_trans) THEN
393 0 : force(i) = SUM(sab(1:nb, 1:na, i)*pab(1:nb, 1:na))
394 : ELSE
395 1083790743 : force(i) = SUM(sab(1:na, 1:nb, i)*pab(1:na, 1:nb))
396 : END IF
397 : END DO
398 :
399 1664667 : END SUBROUTINE force_trace_ab
400 :
401 : ! **************************************************************************************************
402 : !> \brief Copy a block out of a matrix and add it to another matrix
403 : !> SAB = SAB + QAB or QAB = QAB + SAB
404 : !> QAB(ia:,ib:) and SAB(1:,1:)
405 : !> \param dir "IN" and "OUT" defines direction of copy
406 : !> \param sab Matrix input for "IN", output for "OUT"
407 : !> \param na first dimension of matrix to copy
408 : !> \param nb second dimension of matrix to copy
409 : !> \param qab Matrix output for "IN", input for "OUT"
410 : !> Use subblock of this matrix
411 : !> \param ia Starting index in qab first dimension
412 : !> \param ib Starting index in qab second dimension
413 : !> \param trans Matrices (qab and sab) are transposed
414 : ! **************************************************************************************************
415 21677378 : SUBROUTINE block_add_ab(dir, sab, na, nb, qab, ia, ib, trans)
416 :
417 : CHARACTER(LEN=*), INTENT(IN) :: dir
418 : REAL(KIND=dp), DIMENSION(:, :), INTENT(INOUT) :: sab
419 : INTEGER, INTENT(IN) :: na, nb
420 : REAL(KIND=dp), DIMENSION(:, :), INTENT(INOUT) :: qab
421 : INTEGER, INTENT(IN) :: ia, ib
422 : LOGICAL, INTENT(IN), OPTIONAL :: trans
423 :
424 : INTEGER :: ja, jb
425 : LOGICAL :: my_trans
426 :
427 21677378 : IF (PRESENT(trans)) THEN
428 21676654 : my_trans = trans
429 : ELSE
430 : my_trans = .FALSE.
431 : END IF
432 :
433 21677378 : IF (dir == "IN" .OR. dir == "in") THEN
434 : ! QAB(block) <= SAB
435 20012711 : ja = ia + na - 1
436 20012711 : jb = ib + nb - 1
437 20012711 : IF (my_trans) THEN
438 190065871 : qab(ib:jb, ia:ja) = qab(ib:jb, ia:ja) + sab(1:nb, 1:na)
439 : ELSE
440 380103905 : qab(ia:ja, ib:jb) = qab(ia:ja, ib:jb) + sab(1:na, 1:nb)
441 : END IF
442 1664667 : ELSEIF (dir == "OUT" .OR. dir == "out") THEN
443 : ! SAB <= QAB(block)
444 1664667 : ja = ia + na - 1
445 1664667 : jb = ib + nb - 1
446 1664667 : IF (my_trans) THEN
447 31278372 : sab(1:nb, 1:na) = sab(1:nb, 1:na) + qab(ib:jb, ia:ja)
448 : ELSE
449 26715152 : sab(1:na, 1:nb) = sab(1:na, 1:nb) + qab(ia:ja, ib:jb)
450 : END IF
451 : ELSE
452 0 : CPABORT("")
453 : END IF
454 :
455 21677378 : END SUBROUTINE block_add_ab
456 : ! **************************************************************************************************
457 :
458 : END MODULE ai_contraction
|