(git:44e3845)
Loading...
Searching...
No Matches
cp_fm_cholesky.F
Go to the documentation of this file.
1!--------------------------------------------------------------------------------------------------!
2! CP2K: A general program to perform molecular dynamics simulations !
3! Copyright 2000-2025 CP2K developers group <https://cp2k.org> !
4! !
5! SPDX-License-Identifier: GPL-2.0-or-later !
6!--------------------------------------------------------------------------------------------------!
7
8! **************************************************************************************************
9!> \brief various cholesky decomposition related routines
10!> \par History
11!> 09.2002 created [fawzi]
12!> \author Fawzi Mohamed
13! **************************************************************************************************
21 USE cp_fm_types, ONLY: cp_fm_type
23 USE kinds, ONLY: dp,&
24 sp
25#include "../base/base_uses.f90"
26
27 IMPLICIT NONE
28 PRIVATE
29
30 LOGICAL, PRIVATE, PARAMETER :: debug_this_module = .true.
31 CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'cp_fm_cholesky'
32
35
36 ! The following saved variables are Cholesky decomposition global
37 ! Stores the default library for Cholesky decomposition
38 INTEGER, SAVE, PUBLIC :: cholesky_type = 0
39 ! Minimum matrix size for the use of the DLAF Cholesky decomposition.
40 ! ScaLAPACK is used as fallback for all smaller cases.
41 INTEGER, SAVE, PUBLIC :: dlaf_cholesky_n_min = 0
42 ! Constants for the diag_type above
43 INTEGER, PARAMETER, PUBLIC :: fm_cholesky_type_scalapack = 101, &
46
47!***
48CONTAINS
49
50! **************************************************************************************************
51!> \brief used to replace a symmetric positive def. matrix M with its cholesky
52!> decomposition U: M = U^T * U, with U upper triangular
53!> \param matrix the matrix to replace with its cholesky decomposition
54!> \param n the number of row (and columns) of the matrix &
55!> (defaults to the min(size(matrix)))
56!> \param info_out ...
57!> \par History
58!> 05.2002 created [JVdV]
59!> 12.2002 updated, added n optional parm [fawzi]
60!> \author Joost
61! **************************************************************************************************
62 SUBROUTINE cp_fm_cholesky_decompose(matrix, n, info_out)
63 TYPE(cp_fm_type), INTENT(IN) :: matrix
64 INTEGER, INTENT(in), OPTIONAL :: n
65 INTEGER, INTENT(out), OPTIONAL :: info_out
66
67 CHARACTER(len=*), PARAMETER :: routinen = 'cp_fm_cholesky_decompose'
68
69 INTEGER :: handle, info, my_n
70 REAL(kind=dp), DIMENSION(:, :), POINTER :: a
71 REAL(kind=sp), DIMENSION(:, :), POINTER :: a_sp
72#if defined(__parallel)
73 INTEGER, DIMENSION(9) :: desca
74#endif
75
76 CALL timeset(routinen, handle)
77
78 my_n = min(matrix%matrix_struct%nrow_global, &
79 matrix%matrix_struct%ncol_global)
80 IF (PRESENT(n)) THEN
81 cpassert(n <= my_n)
82 my_n = n
83 END IF
84
85 a => matrix%local_data
86 a_sp => matrix%local_data_sp
87
88#if defined(__parallel)
89 desca(:) = matrix%matrix_struct%descriptor(:)
90#if defined(__DLAF)
91 IF (cholesky_type == fm_cholesky_type_dlaf .AND. matrix%matrix_struct%nrow_global >= dlaf_cholesky_n_min) THEN
92 ! Initialize DLA-Future on-demand; if already initialized, does nothing
94
95 ! Create DLAF grid from BLACS context; if already present, does nothing
96 CALL cp_dlaf_create_grid(matrix%matrix_struct%context%get_handle())
97
98 IF (matrix%use_sp) THEN
99 CALL cp_pspotrf_dlaf('U', my_n, a_sp(:, :), 1, 1, desca, info)
100 ELSE
101 CALL cp_pdpotrf_dlaf('U', my_n, a(:, :), 1, 1, desca, info)
102 END IF
103 ELSE
104#endif
105 IF (matrix%use_sp) THEN
106 CALL pspotrf('U', my_n, a_sp(1, 1), 1, 1, desca, info)
107 ELSE
108 CALL pdpotrf('U', my_n, a(1, 1), 1, 1, desca, info)
109 END IF
110#if defined(__DLAF)
111 END IF
112#endif
113#else
114 IF (matrix%use_sp) THEN
115 CALL spotrf('U', my_n, a_sp(1, 1), SIZE(a_sp, 1), info)
116 ELSE
117 CALL dpotrf('U', my_n, a(1, 1), SIZE(a, 1), info)
118 END IF
119#endif
120
121 IF (PRESENT(info_out)) THEN
122 info_out = info
123 ELSE IF (info /= 0) THEN
124 CALL cp_abort(__location__, &
125 "Cholesky decompose failed: the matrix is not positive definite or ill-conditioned.")
126 END IF
127
128 CALL timestop(handle)
129
130 END SUBROUTINE cp_fm_cholesky_decompose
131
132! **************************************************************************************************
133!> \brief used to replace the cholesky decomposition by the inverse
134!> \param matrix the matrix to invert (must be an upper triangular matrix)
135!> \param n size of the matrix to invert (defaults to the min(size(matrix)))
136!> \param info_out ...
137!> \par History
138!> 05.2002 created [JVdV]
139!> \author Joost VandeVondele
140! **************************************************************************************************
141 SUBROUTINE cp_fm_cholesky_invert(matrix, n, info_out)
142 TYPE(cp_fm_type), INTENT(IN) :: matrix
143 INTEGER, INTENT(in), OPTIONAL :: n
144 INTEGER, INTENT(OUT), OPTIONAL :: info_out
145
146 CHARACTER(len=*), PARAMETER :: routinen = 'cp_fm_cholesky_invert'
147 REAL(kind=dp), DIMENSION(:, :), POINTER :: a
148 REAL(kind=sp), DIMENSION(:, :), POINTER :: a_sp
149 INTEGER :: info, handle, my_n
150#if defined(__parallel)
151 INTEGER, DIMENSION(9) :: desca
152#endif
153
154 CALL timeset(routinen, handle)
155
156 my_n = min(matrix%matrix_struct%nrow_global, &
157 matrix%matrix_struct%ncol_global)
158 IF (PRESENT(n)) THEN
159 cpassert(n <= my_n)
160 my_n = n
161 END IF
162
163 a => matrix%local_data
164 a_sp => matrix%local_data_sp
165
166#if defined(__parallel)
167
168 desca(:) = matrix%matrix_struct%descriptor(:)
169
170#if defined(__DLAF)
171 IF (cholesky_type == fm_cholesky_type_dlaf .AND. matrix%matrix_struct%nrow_global >= dlaf_cholesky_n_min) THEN
172 ! Initialize DLA-Future on-demand; if already initialized, does nothing
173 CALL cp_dlaf_initialize()
174
175 ! Create DLAF grid from BLACS context; if already present, does nothing
176 CALL cp_dlaf_create_grid(matrix%matrix_struct%context%get_handle())
177
178 IF (matrix%use_sp) THEN
179 CALL cp_pspotri_dlaf('U', my_n, a_sp(:, :), 1, 1, desca, info)
180 ELSE
181 CALL cp_pdpotri_dlaf('U', my_n, a(:, :), 1, 1, desca, info)
182 END IF
183 ELSE
184#endif
185 IF (matrix%use_sp) THEN
186 CALL pspotri('U', my_n, a_sp(1, 1), 1, 1, desca, info)
187 ELSE
188 CALL pdpotri('U', my_n, a(1, 1), 1, 1, desca, info)
189 END IF
190#if defined(__DLAF)
191 END IF
192#endif
193
194#else
195
196 IF (matrix%use_sp) THEN
197 CALL spotri('U', my_n, a_sp(1, 1), SIZE(a_sp, 1), info)
198 ELSE
199 CALL dpotri('U', my_n, a(1, 1), SIZE(a, 1), info)
200 END IF
201
202#endif
203
204 IF (PRESENT(info_out)) THEN
205 info_out = info
206 ELSE
207 IF (info /= 0) &
208 cpabort("Cholesky invert failed: the matrix is not positive definite or ill-conditioned.")
209 END IF
210
211 CALL timestop(handle)
212
213 END SUBROUTINE cp_fm_cholesky_invert
214
215! **************************************************************************************************
216!> \brief reduce a matrix pencil A,B to normal form
217!> B has to be cholesky decomposed with cp_fm_cholesky_decompose
218!> before calling this routine
219!> A,B -> inv(U^T)*A*inv(U),1
220!> (AX=BX -> inv(U^T)*A*inv(U)*U*X=U*X hence evecs U*X)
221!> \param matrix the symmetric matrix A
222!> \param matrixb the cholesky decomposition of matrix B
223!> \param itype ...
224!> \par History
225!> 05.2002 created [JVdV]
226!> \author Joost VandeVondele
227! **************************************************************************************************
228 SUBROUTINE cp_fm_cholesky_reduce(matrix, matrixb, itype)
229 TYPE(cp_fm_type), INTENT(IN) :: matrix, matrixb
230 INTEGER, OPTIONAL :: itype
231
232 CHARACTER(len=*), PARAMETER :: routinen = 'cp_fm_cholesky_reduce'
233 REAL(kind=dp), DIMENSION(:, :), POINTER :: a, b
234 INTEGER :: info, handle
235 INTEGER :: n, my_itype
236#if defined(__parallel)
237 REAL(kind=dp) :: scale
238 INTEGER, DIMENSION(9) :: desca, descb
239#endif
240
241 CALL timeset(routinen, handle)
242
243 n = matrix%matrix_struct%nrow_global
244
245 my_itype = 1
246 IF (PRESENT(itype)) my_itype = itype
247
248 a => matrix%local_data
249 b => matrixb%local_data
250
251#if defined(__parallel)
252
253 desca(:) = matrix%matrix_struct%descriptor(:)
254 descb(:) = matrixb%matrix_struct%descriptor(:)
255
256 CALL pdsygst(my_itype, 'U', n, a(1, 1), 1, 1, desca, b(1, 1), 1, 1, descb, scale, info)
257
258 ! this is supposed to be one in current version of lapack
259 ! if not, eigenvalues have to be scaled by this number
260 IF (scale /= 1.0_dp) &
261 cpabort("scale not equal 1 (scale="//cp_to_string(scale)//")")
262#else
263
264 CALL dsygst(my_itype, 'U', n, a(1, 1), n, b(1, 1), n, info)
265
266#endif
267
268 cpassert(info == 0)
269
270 CALL timestop(handle)
271
272 END SUBROUTINE cp_fm_cholesky_reduce
273
274! **************************************************************************************************
275!> \brief apply Cholesky decomposition
276!> op can be "SOLVE" (out = U^-1 * in) or "MULTIPLY" (out = U * in)
277!> pos can be "LEFT" or "RIGHT" (U at the left or at the right)
278!> \param fm_matrix ...
279!> \param neig ...
280!> \param fm_matrixb ...
281!> \param fm_matrixout ...
282!> \param op ...
283!> \param pos ...
284!> \param transa ...
285! **************************************************************************************************
286 SUBROUTINE cp_fm_cholesky_restore(fm_matrix, neig, fm_matrixb, fm_matrixout, op, pos, transa)
287 TYPE(cp_fm_type), INTENT(IN) :: fm_matrix, fm_matrixb, fm_matrixout
288 INTEGER, INTENT(IN) :: neig
289 CHARACTER(LEN=*), INTENT(IN) :: op
290 CHARACTER(LEN=*), INTENT(IN), OPTIONAL :: pos
291 CHARACTER(LEN=*), INTENT(IN), OPTIONAL :: transa
292
293 CHARACTER(len=*), PARAMETER :: routinen = 'cp_fm_cholesky_restore'
294 REAL(kind=dp), DIMENSION(:, :), POINTER :: a, b, outm
295 REAL(kind=sp), DIMENSION(:, :), POINTER :: a_sp, b_sp, outm_sp
296 REAL(kind=dp) :: alpha
297 INTEGER :: handle, mdim, n
298 CHARACTER :: chol_pos, chol_transa
299#if defined(__parallel)
300 INTEGER :: i
301 INTEGER, DIMENSION(9) :: desca, descb, descout
302#elif defined(__MKL) && (2025 <= __INTEL_MKL__)
303 REAL(kind=dp) :: beta
304#endif
305
306 CALL timeset(routinen, handle)
307
308 ! wrong argument op
309 cpassert((op == "SOLVE") .OR. (op == "MULTIPLY"))
310 ! not the same precision
311 cpassert(fm_matrix%use_sp .EQV. fm_matrixb%use_sp)
312 cpassert(fm_matrix%use_sp .EQV. fm_matrixout%use_sp)
313
314 chol_pos = 'L'
315 IF (PRESENT(pos)) chol_pos = pos(1:1)
316 cpassert((chol_pos == 'L') .OR. (chol_pos == 'R'))
317
318 chol_transa = 'N'
319 IF (PRESENT(transa)) chol_transa = transa
320
321 ! notice b is the cholesky guy
322 a => fm_matrix%local_data
323 b => fm_matrixb%local_data
324 outm => fm_matrixout%local_data
325 a_sp => fm_matrix%local_data_sp
326 b_sp => fm_matrixb%local_data_sp
327 outm_sp => fm_matrixout%local_data_sp
328 n = fm_matrix%matrix_struct%nrow_global
329 mdim = merge(1, 2, 'L' == chol_pos)
330 alpha = 1.0_dp
331
332#if defined(__parallel)
333 desca(:) = fm_matrix%matrix_struct%descriptor(:)
334 descb(:) = fm_matrixb%matrix_struct%descriptor(:)
335 descout(:) = fm_matrixout%matrix_struct%descriptor(:)
336 DO i = 1, neig
337 IF (fm_matrix%use_sp) THEN
338 CALL pscopy(n, a_sp(1, 1), 1, i, desca, 1, outm_sp(1, 1), 1, i, descout, 1)
339 ELSE
340 CALL pdcopy(n, a(1, 1), 1, i, desca, 1, outm(1, 1), 1, i, descout, 1)
341 END IF
342 END DO
343 IF (op == "SOLVE") THEN
344 IF (fm_matrix%use_sp) THEN
345 CALL pstrsm(chol_pos, 'U', chol_transa, 'N', n, neig, real(alpha, sp), b_sp(1, 1), 1, 1, descb, &
346 outm_sp(1, 1), 1, 1, descout)
347 ELSE
348 CALL pdtrsm(chol_pos, 'U', chol_transa, 'N', n, neig, alpha, b(1, 1), 1, 1, descb, outm(1, 1), 1, 1, descout)
349 END IF
350 ELSE
351 IF (fm_matrix%use_sp) THEN
352 CALL pstrmm(chol_pos, 'U', chol_transa, 'N', n, neig, real(alpha, sp), b_sp(1, 1), 1, 1, descb, &
353 outm_sp(1, 1), 1, 1, descout)
354 ELSE
355 CALL pdtrmm(chol_pos, 'U', chol_transa, 'N', n, neig, alpha, b(1, 1), 1, 1, descb, outm(1, 1), 1, 1, descout)
356 END IF
357 END IF
358#elif defined(__MKL) && (2025 <= __INTEL_MKL__)
359 beta = 0.0_dp
360 IF (op == "SOLVE") THEN
361 IF (fm_matrix%use_sp) THEN
362 CALL strsm_oop(chol_pos, 'U', chol_transa, 'N', n, neig, real(alpha, sp), b_sp(1, 1), SIZE(b_sp, mdim), a_sp(1, 1), n, real(beta, sp), outm_sp(1, 1), n)
363 ELSE
364 CALL dtrsm_oop(chol_pos, 'U', chol_transa, 'N', n, neig, alpha, b(1, 1), SIZE(b, mdim), a(1, 1), n, beta, outm(1, 1), n)
365 END IF
366 ELSE
367 IF (fm_matrix%use_sp) THEN
368 CALL strmm_oop(chol_pos, 'U', chol_transa, 'N', n, neig, real(alpha, sp), b_sp(1, 1), SIZE(b_sp, mdim), a_sp(1, 1), n, real(beta, sp), outm_sp(1, 1), n)
369 ELSE
370 CALL dtrmm_oop(chol_pos, 'U', chol_transa, 'N', n, neig, alpha, b(1, 1), SIZE(b, mdim), a(1, 1), n, beta, outm(1, 1), n)
371 END IF
372 END IF
373#else
374 IF (fm_matrix%use_sp) THEN
375 CALL scopy(neig*n, a_sp(1, 1), 1, outm_sp(1, 1), 1)
376 ELSE
377 CALL dcopy(neig*n, a(1, 1), 1, outm(1, 1), 1)
378 END IF
379 IF (op == "SOLVE") THEN
380 IF (fm_matrix%use_sp) THEN
381 CALL strsm(chol_pos, 'U', chol_transa, 'N', n, neig, real(alpha, sp), b_sp(1, 1), SIZE(b_sp, mdim), outm_sp(1, 1), n)
382 ELSE
383 CALL dtrsm(chol_pos, 'U', chol_transa, 'N', n, neig, alpha, b(1, 1), SIZE(b, mdim), outm(1, 1), n)
384 END IF
385 ELSE
386 IF (fm_matrix%use_sp) THEN
387 CALL strmm(chol_pos, 'U', chol_transa, 'N', n, neig, real(alpha, sp), b_sp(1, 1), SIZE(b_sp, mdim), outm_sp(1, 1), n)
388 ELSE
389 CALL dtrmm(chol_pos, 'U', chol_transa, 'N', n, neig, alpha, b(1, 1), SIZE(b, mdim), outm(1, 1), n)
390 END IF
391 END IF
392#endif
393
394 CALL timestop(handle)
395
396 END SUBROUTINE cp_fm_cholesky_restore
397
398END MODULE cp_fm_cholesky
subroutine, public cp_dlaf_create_grid(blacs_context)
Create DLA-Future grid from BLACS context.
subroutine, public cp_dlaf_initialize()
Initialize DLA-Future and pika runtime.
various cholesky decomposition related routines
integer, parameter, public fm_cholesky_type_dlaf
subroutine, public cp_fm_cholesky_invert(matrix, n, info_out)
used to replace the cholesky decomposition by the inverse
subroutine, public cp_fm_cholesky_restore(fm_matrix, neig, fm_matrixb, fm_matrixout, op, pos, transa)
apply Cholesky decomposition op can be "SOLVE" (out = U^-1 * in) or "MULTIPLY" (out = U * in) pos can...
subroutine, public cp_fm_cholesky_decompose(matrix, n, info_out)
used to replace a symmetric positive def. matrix M with its cholesky decomposition U: M = U^T * U,...
integer, parameter, public fm_cholesky_type_default
subroutine, public cp_fm_cholesky_reduce(matrix, matrixb, itype)
reduce a matrix pencil A,B to normal form B has to be cholesky decomposed with cp_fm_cholesky_decompo...
integer, parameter, public fm_cholesky_type_scalapack
integer, save, public dlaf_cholesky_n_min
integer, save, public cholesky_type
subroutine, public cp_pspotri_dlaf(uplo, n, a, ia, ja, desca, info)
Inverse from Cholesky factorization using DLA-Future.
subroutine, public cp_pdpotrf_dlaf(uplo, n, a, ia, ja, desca, info)
Cholesky factorization using DLA-Future.
subroutine, public cp_pdpotri_dlaf(uplo, n, a, ia, ja, desca, info)
Inverse from Cholesky factorization using DLA-Future.
subroutine, public cp_pspotrf_dlaf(uplo, n, a, ia, ja, desca, info)
Cholesky factorization using DLA-Future.
represent a full matrix distributed on many processors
Definition cp_fm_types.F:15
various routines to log and control the output. The idea is that decisions about where to log should ...
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
represent a full matrix