(git:691081d)
Loading...
Searching...
No Matches
gw_compute_Z_lP_utils.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 Shared numerical operations for computing the RI-RS matrix Z_lP.
10!> \par History
11!> 09.2026 created Jan Wilhelm
12! **************************************************************************************************
15 USE cp_dbcsr_api, ONLY: dbcsr_put_block,&
22 USE cp_fm_types, ONLY: cp_fm_create,&
28 USE kinds, ONLY: dp
30#include "./base/base_uses.f90"
31
32 IMPLICIT NONE
33 PRIVATE
34
35 CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'gw_compute_Z_lP_utils'
36 REAL(KIND=dp), PARAMETER, PRIVATE :: jacobi_floor = 1.0e-16_dp
37
38 PUBLIC :: build_gram_jacobi_blas, &
43
44CONTAINS
45
46! **************************************************************************************************
47!> \brief Forms the conditioned dense RI-RS matrix
48!>
49!> D_ll' = [Σ_μ Φ_μ(r_l) Φ_μ(r_l')]²,
50!> d_l = 1/sqrt(D_ll),
51!> D'_ll' = d_l D_ll' d_l' + λ δ_ll'.
52!>
53!> Only the dense single-rank solve needs the complete matrix D'.
54!> \param phi_local ...
55!> \param n_local_grid ...
56!> \param n_ao_used ...
57!> \param tikhonov ...
58!> \param D_local ...
59!> \param d_vec_local ...
60! **************************************************************************************************
61 SUBROUTINE build_gram_jacobi_blas(phi_local, n_local_grid, n_ao_used, tikhonov, D_local, &
62 d_vec_local)
63
64 REAL(kind=dp), DIMENSION(:, :), INTENT(IN) :: phi_local
65 INTEGER, INTENT(IN) :: n_local_grid, n_ao_used
66 REAL(kind=dp), INTENT(IN) :: tikhonov
67 REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :), &
68 INTENT(OUT) :: d_local
69 REAL(kind=dp), DIMENSION(:), INTENT(OUT) :: d_vec_local
70
71 CHARACTER(LEN=*), PARAMETER :: routinen = 'build_gram_jacobi_blas'
72
73 INTEGER :: handle, handle_dsyrk, i, j
74
75 CALL timeset(routinen, handle)
76
77 ALLOCATE (d_local(n_local_grid, n_local_grid))
78 d_local = 0.0_dp
79
80 CALL timeset(routinen//'_dsyrk', handle_dsyrk)
81 CALL dsyrk("L", "N", n_local_grid, n_ao_used, 1.0_dp, phi_local, &
82 n_local_grid, 0.0_dp, d_local, n_local_grid)
83 CALL timestop(handle_dsyrk)
84
85 !$OMP PARALLEL DO DEFAULT(NONE) &
86 !$OMP SHARED(n_local_grid, D_local, d_vec_local, tikhonov) &
87 !$OMP PRIVATE(i) &
88 !$OMP SCHEDULE(STATIC)
89 DO i = 1, n_local_grid
90 d_local(i, i) = d_local(i, i)**2
91 d_vec_local(i) = 1.0_dp/sqrt(max(d_local(i, i), jacobi_floor))
92 d_local(i, i) = (d_local(i, i)*d_vec_local(i)**2) + tikhonov
93 END DO
94 !$OMP END PARALLEL DO
95
96 !$OMP PARALLEL DO DEFAULT(NONE) &
97 !$OMP SHARED(n_local_grid, D_local, d_vec_local) &
98 !$OMP PRIVATE(j, i) &
99 !$OMP SCHEDULE(DYNAMIC)
100 DO j = 1, n_local_grid
101 DO i = j + 1, n_local_grid
102 d_local(i, j) = d_local(i, j)**2
103 d_local(i, j) = d_local(i, j)*d_vec_local(i)*d_vec_local(j)
104 d_local(j, i) = d_local(i, j)
105 END DO
106 END DO
107 !$OMP END PARALLEL DO
108
109 CALL timestop(handle)
110
111 END SUBROUTINE build_gram_jacobi_blas
112
113! **************************************************************************************************
114!> \brief Computes d_l = 1/sqrt(D_ll) = 1/Σ_μ Φ_μ(r_l)² without forming D.
115!> \param phi_local ...
116!> \param n_local_grid ...
117!> \param n_ao_used ...
118!> \param d_vec_local ...
119! **************************************************************************************************
120 SUBROUTINE build_jacobi_diag_from_phi(phi_local, n_local_grid, n_ao_used, d_vec_local)
121
122 REAL(kind=dp), DIMENSION(:, :), INTENT(IN) :: phi_local
123 INTEGER, INTENT(IN) :: n_local_grid, n_ao_used
124 REAL(kind=dp), DIMENSION(:), INTENT(OUT) :: d_vec_local
125
126 CHARACTER(LEN=*), PARAMETER :: routinen = 'build_jacobi_diag_from_phi'
127
128 INTEGER :: handle, i, j
129
130 CALL timeset(routinen, handle)
131
132 !$OMP PARALLEL DO DEFAULT(NONE) &
133 !$OMP SHARED(n_local_grid, n_ao_used, phi_local, d_vec_local) &
134 !$OMP PRIVATE(i, j) &
135 !$OMP SCHEDULE(STATIC)
136 DO i = 1, n_local_grid
137 d_vec_local(i) = 0.0_dp
138 DO j = 1, n_ao_used
139 d_vec_local(i) = d_vec_local(i) + phi_local(i, j)*phi_local(i, j)
140 END DO
141 d_vec_local(i) = 1.0_dp/max(d_vec_local(i), jacobi_floor)
142 END DO
143 !$OMP END PARALLEL DO
144
145 CALL timestop(handle)
146
147 END SUBROUTINE build_jacobi_diag_from_phi
148
149! **************************************************************************************************
150!> \brief Multiplies every matrix row by the corresponding diagonal entry:
151!> A(l, :) <- d_l A(l, :).
152!> \param matrix ...
153!> \param diagonal ...
154!> \param nrow ...
155!> \param ncol ...
156! **************************************************************************************************
157 SUBROUTINE scale_rows_by_diag(matrix, diagonal, nrow, ncol)
158
159 REAL(kind=dp), DIMENSION(:, :), INTENT(INOUT) :: matrix
160 REAL(kind=dp), DIMENSION(:), INTENT(IN) :: diagonal
161 INTEGER, INTENT(IN) :: nrow, ncol
162
163 CHARACTER(LEN=*), PARAMETER :: routinen = 'scale_rows_by_diag'
164
165 INTEGER :: handle, i, j
166
167 CALL timeset(routinen, handle)
168
169 !$OMP PARALLEL DO DEFAULT(NONE) &
170 !$OMP SHARED(ncol, nrow, matrix, diagonal) &
171 !$OMP PRIVATE(j, i) &
172 !$OMP SCHEDULE(STATIC)
173 DO j = 1, ncol
174 DO i = 1, nrow
175 matrix(i, j) = matrix(i, j)*diagonal(i)
176 END DO
177 END DO
178 !$OMP END PARALLEL DO
179
180 CALL timestop(handle)
181
182 END SUBROUTINE scale_rows_by_diag
183
184! **************************************************************************************************
185!> \brief Stores dense Z_lP columns in the distributed block-sparse matrix.
186!> \param mat_Z_lP ...
187!> \param Z_local ...
188!> \param local_grid_idx ...
189!> \param n_local_grid ...
190!> \param n_loc_ri ...
191!> \param atom_P ...
192!> \param r_blk_sizes ...
193!> \param row_offset ...
194!> \param eps_filter ...
195! **************************************************************************************************
196 SUBROUTINE store_z_lp_columns(mat_Z_lP, Z_local, local_grid_idx, n_local_grid, n_loc_ri, &
197 atom_P, r_blk_sizes, row_offset, eps_filter)
198
199 TYPE(dbcsr_type), INTENT(INOUT) :: mat_z_lp
200 REAL(kind=dp), DIMENSION(:, :), INTENT(IN) :: z_local
201 INTEGER, DIMENSION(:), INTENT(IN) :: local_grid_idx
202 INTEGER, INTENT(IN) :: n_local_grid, n_loc_ri, atom_p
203 INTEGER, DIMENSION(:), INTENT(IN) :: r_blk_sizes, row_offset
204 REAL(kind=dp), INTENT(IN) :: eps_filter
205
206 CHARACTER(LEN=*), PARAMETER :: routinen = 'store_Z_lP_columns'
207
208 INTEGER :: current_chunk_size, g_pt, handle, i_blk, &
209 loc_ptr, r_end, r_start
210 REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :) :: z_blk
211
212 CALL timeset(routinen, handle)
213
214 ALLOCATE (z_blk(maxval(r_blk_sizes), n_loc_ri))
215 loc_ptr = 1
216
217 DO i_blk = 1, SIZE(r_blk_sizes)
218 r_start = row_offset(i_blk) + 1
219 r_end = row_offset(i_blk) + r_blk_sizes(i_blk)
220 current_chunk_size = r_blk_sizes(i_blk)
221 z_blk = 0.0_dp
222
223 DO WHILE (loc_ptr <= n_local_grid)
224 g_pt = local_grid_idx(loc_ptr)
225 IF (g_pt > r_end) EXIT
226 z_blk(g_pt - r_start + 1, 1:n_loc_ri) = z_local(loc_ptr, 1:n_loc_ri)
227 loc_ptr = loc_ptr + 1
228 END DO
229
230 IF (maxval(abs(z_blk(1:current_chunk_size, 1:n_loc_ri))) > eps_filter) THEN
231 CALL dbcsr_put_block(mat_z_lp, row=i_blk, col=atom_p, &
232 block=z_blk(1:current_chunk_size, 1:n_loc_ri))
233 END IF
234 END DO
235
236 DEALLOCATE (z_blk)
237
238 CALL timestop(handle)
239
240 END SUBROUTINE store_z_lp_columns
241
242! **************************************************************************************************
243!> \brief Solves D Z = d with ScaLAPACK for one RI atom and replicated inputs.
244!>
245!> Each rank builds its block-cyclic part of
246!>
247!> D'_ll' = d_l [Σ_μ Φ_μ(r_l) Φ_μ(r_l')]² d_l' + λ δ_ll'.
248!>
249!> The Cholesky solution is gathered into the replicated right-hand side.
250!> \param phi_local ...
251!> \param d_vec ...
252!> \param d_lp ...
253!> \param n_loc ...
254!> \param n_ao ...
255!> \param n_rhs ...
256!> \param tikhonov ...
257!> \param para_env_sub ...
258!> \param blacs_env_sub ...
259!> \param fm_struct_D ...
260!> \param fm_struct_b ...
261!> \param fm_D ...
262!> \param fm_b ...
263!> \param info ...
264! **************************************************************************************************
265 SUBROUTINE solve_d_lp_distributed(phi_local, d_vec, d_lp, n_loc, n_ao, n_rhs, &
266 tikhonov, para_env_sub, blacs_env_sub, &
267 fm_struct_D, fm_struct_b, fm_D, fm_b, info)
268
269 REAL(kind=dp), DIMENSION(:, :), INTENT(IN) :: phi_local
270 REAL(kind=dp), DIMENSION(:), INTENT(IN) :: d_vec
271 REAL(kind=dp), DIMENSION(:, :), INTENT(INOUT) :: d_lp
272 INTEGER, INTENT(IN) :: n_loc, n_ao, n_rhs
273 REAL(kind=dp), INTENT(IN) :: tikhonov
274 TYPE(mp_para_env_type), POINTER :: para_env_sub
275 TYPE(cp_blacs_env_type), POINTER :: blacs_env_sub
276 TYPE(cp_fm_struct_type), POINTER :: fm_struct_d, fm_struct_b
277 TYPE(cp_fm_type), INTENT(INOUT) :: fm_d, fm_b
278 INTEGER, INTENT(OUT) :: info
279
280 CHARACTER(LEN=*), PARAMETER :: routinen = 'solve_D_lp_distributed'
281
282 INTEGER :: handle, i_loc, ig, j_loc, jg, &
283 ncol_local, nrow_local
284 INTEGER, DIMENSION(:), POINTER :: col_indices, row_indices
285 REAL(kind=dp), CONTIGUOUS, DIMENSION(:, :), &
286 POINTER :: local_data
287
288 CALL timeset(routinen, handle)
289 info = 0
290
291 NULLIFY (fm_struct_d, fm_struct_b)
292 CALL cp_fm_struct_create(fm_struct_d, para_env=para_env_sub, &
293 context=blacs_env_sub, &
294 nrow_global=n_loc, ncol_global=n_loc)
295 CALL cp_fm_struct_create(fm_struct_b, para_env=para_env_sub, &
296 context=blacs_env_sub, &
297 nrow_global=n_loc, ncol_global=n_rhs)
298 CALL cp_fm_create(fm_d, fm_struct_d)
299 CALL cp_fm_create(fm_b, fm_struct_b)
300
301 CALL cp_fm_get_info(fm_d, nrow_local=nrow_local, ncol_local=ncol_local, &
302 row_indices=row_indices, col_indices=col_indices, &
303 local_data=local_data)
304
305 IF (nrow_local > 0 .AND. ncol_local > 0) THEN
306 block
307 INTEGER, PARAMETER :: ntile = 1024
308 INTEGER :: ib, ie, jb, je, mb, kb, ti, tj, handle_dgemm
309 REAL(kind=dp), ALLOCATABLE :: gram_t(:, :), phi_cols_t(:, :), phi_rows_t(:, :)
310 ALLOCATE (phi_rows_t(ntile, n_ao), phi_cols_t(n_ao, ntile), gram_t(ntile, ntile))
311 DO ib = 1, nrow_local, ntile
312 ie = min(ib + ntile - 1, nrow_local)
313 mb = ie - ib + 1
314 !$OMP PARALLEL DO DEFAULT(NONE) &
315 !$OMP SHARED(mb, n_ao, phi_rows_t, phi_local, row_indices, ib) &
316 !$OMP PRIVATE(ti, j_loc) SCHEDULE(STATIC)
317 DO j_loc = 1, n_ao
318 DO ti = 1, mb
319 phi_rows_t(ti, j_loc) = phi_local(row_indices(ib + ti - 1), j_loc)
320 END DO
321 END DO
322 !$OMP END PARALLEL DO
323 DO jb = 1, ncol_local, ntile
324 je = min(jb + ntile - 1, ncol_local)
325 kb = je - jb + 1
326 !$OMP PARALLEL DO DEFAULT(NONE) &
327 !$OMP SHARED(kb, n_ao, phi_cols_t, phi_local, col_indices, jb) &
328 !$OMP PRIVATE(tj, i_loc) SCHEDULE(STATIC)
329 DO tj = 1, kb
330 DO i_loc = 1, n_ao
331 phi_cols_t(i_loc, tj) = phi_local(col_indices(jb + tj - 1), i_loc)
332 END DO
333 END DO
334 !$OMP END PARALLEL DO
335 CALL timeset(routinen//'_dgemm', handle_dgemm)
336 CALL dgemm('N', 'N', mb, kb, n_ao, &
337 1.0_dp, phi_rows_t, ntile, phi_cols_t, n_ao, &
338 0.0_dp, gram_t, ntile)
339 CALL timestop(handle_dgemm)
340 !$OMP PARALLEL DO DEFAULT(NONE) &
341 !$OMP SHARED(mb, kb, gram_t, d_vec, row_indices, col_indices, ib, jb) &
342 !$OMP SHARED(local_data, tikhonov) &
343 !$OMP PRIVATE(ti, tj, ig, jg) SCHEDULE(STATIC)
344 DO tj = 1, kb
345 jg = col_indices(jb + tj - 1)
346 DO ti = 1, mb
347 ig = row_indices(ib + ti - 1)
348 local_data(ib + ti - 1, jb + tj - 1) = &
349 gram_t(ti, tj)*gram_t(ti, tj)*d_vec(ig)*d_vec(jg)
350 IF (ig == jg) THEN
351 local_data(ib + ti - 1, jb + tj - 1) = &
352 local_data(ib + ti - 1, jb + tj - 1) + tikhonov
353 END IF
354 END DO
355 END DO
356 !$OMP END PARALLEL DO
357 END DO
358 END DO
359 DEALLOCATE (phi_rows_t, phi_cols_t, gram_t)
360 END block
361 END IF
362
363 CALL cp_fm_set_submatrix(fm_b, d_lp)
364
365 CALL cp_fm_cholesky_decompose(fm_d, n=n_loc, info_out=info)
366 IF (info /= 0) cpabort("pdpotrf failed in solve_D_lp_distributed")
367
368 CALL cp_fm_cholesky_solve(fm_d, fm_b, n=n_loc, info_out=info)
369 IF (info /= 0) cpabort("pdpotrs failed in solve_D_lp_distributed")
370
371 CALL cp_fm_get_submatrix(fm_b, d_lp)
372
373 CALL cp_fm_release(fm_d)
374 CALL cp_fm_release(fm_b)
375 CALL cp_fm_struct_release(fm_struct_d)
376 CALL cp_fm_struct_release(fm_struct_b)
377
378 CALL timestop(handle)
379
380 END SUBROUTINE solve_d_lp_distributed
381
382END MODULE gw_compute_z_lp_utils
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.
methods related to the blacs parallel environment
subroutine, public dbcsr_put_block(matrix, row, col, block, summation)
...
various cholesky decomposition related routines
subroutine, public cp_fm_cholesky_solve(matrix, matrixb, n, info_out)
solves A*X = B for X, given the Cholesky decomposition U of the symmetric positive def....
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,...
represent the structure of a full matrix
subroutine, public cp_fm_struct_create(fmstruct, para_env, context, nrow_global, ncol_global, nrow_block, ncol_block, descriptor, first_p_pos, local_leading_dimension, template_fmstruct, square_blocks, force_block)
allocates and initializes a full matrix structure
subroutine, public cp_fm_struct_release(fmstruct)
releases a full matrix structure
represent a full matrix distributed on many processors
Definition cp_fm_types.F:15
subroutine, public cp_fm_get_info(matrix, name, nrow_global, ncol_global, nrow_block, ncol_block, nrow_local, ncol_local, row_indices, col_indices, local_data, context, nrow_locals, ncol_locals, matrix_struct, para_env)
returns all kind of information about the full matrix
subroutine, public cp_fm_set_submatrix(fm, new_values, start_row, start_col, n_rows, n_cols, alpha, beta, transpose)
sets a submatrix of a full matrix fm(start_row:start_row+n_rows,start_col:start_col+n_cols) = alpha*o...
subroutine, public cp_fm_create(matrix, matrix_struct, name, nrow, ncol, set_zero)
creates a new full matrix with the given structure
subroutine, public cp_fm_get_submatrix(fm, target_m, start_row, start_col, n_rows, n_cols, transpose)
gets a submatrix of a full matrix op(target_m)(1:n_rows,1:n_cols) =fm(start_row:start_row+n_rows,...
Shared numerical operations for computing the RI-RS matrix Z_lP.
subroutine, public build_gram_jacobi_blas(phi_local, n_local_grid, n_ao_used, tikhonov, d_local, d_vec_local)
Forms the conditioned dense RI-RS matrix.
subroutine, public solve_d_lp_distributed(phi_local, d_vec, d_lp, n_loc, n_ao, n_rhs, tikhonov, para_env_sub, blacs_env_sub, fm_struct_d, fm_struct_b, fm_d, fm_b, info)
Solves D Z = d with ScaLAPACK for one RI atom and replicated inputs.
subroutine, public scale_rows_by_diag(matrix, diagonal, nrow, ncol)
Multiplies every matrix row by the corresponding diagonal entry: A(l, :) <- d_l A(l,...
subroutine, public store_z_lp_columns(mat_z_lp, z_local, local_grid_idx, n_local_grid, n_loc_ri, atom_p, r_blk_sizes, row_offset, eps_filter)
Stores dense Z_lP columns in the distributed block-sparse matrix.
subroutine, public build_jacobi_diag_from_phi(phi_local, n_local_grid, n_ao_used, d_vec_local)
Computes d_l = 1/sqrt(D_ll) = 1/Σ_μ Φ_μ(r_l)² without forming D.
Defines the basic variable types.
Definition kinds.F:23
integer, parameter, public dp
Definition kinds.F:34
Interface to the message passing library MPI.
represent a blacs multidimensional parallel environment (for the mpi corrispective see cp_paratypes/m...
keeps the information about the structure of a full matrix
represent a full matrix
stores all the informations relevant to an mpi environment