(git:d2a9ebd)
Loading...
Searching...
No Matches
cp_cfm_types.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 Represents a complex full matrix distributed on many processors.
10!> \author Joost VandeVondele, based on Fawzi's cp_fm_* routines
11! **************************************************************************************************
20 USE cp_fm_types, ONLY: cp_fm_type
21 USE kinds, ONLY: dp
22 USE mathconstants, ONLY: z_one,&
23 z_zero
31#include "../base/base_uses.f90"
32
33 IMPLICIT NONE
34 PRIVATE
35
36 LOGICAL, PRIVATE, PARAMETER :: debug_this_module = .true.
37 CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'cp_cfm_types'
38 INTEGER, PARAMETER, PRIVATE :: src_tag = 3, dest_tag = 5, send_tag = 7, recv_tag = 11
39
55
56 INTERFACE cp_cfm_to_cfm
57 MODULE PROCEDURE cp_cfm_to_cfm_matrix, & ! a full matrix
58 cp_cfm_to_cfm_columns ! just a number of columns
59 END INTERFACE
60
61! **************************************************************************************************
62!> \brief Represent a complex full matrix.
63!> \param name the name of the matrix, used for printing
64!> \param matrix_struct structure of this matrix
65!> \param local_data array with the data of the matrix (its content depends on
66!> the matrix type used: in parallel run it will be in
67!> ScaLAPACK format, in sequential run it will simply contain the matrix)
68! **************************************************************************************************
70 CHARACTER(len=60) :: name = ""
71 TYPE(cp_fm_struct_type), POINTER :: matrix_struct => null()
72 COMPLEX(kind=dp), DIMENSION(:, :), POINTER, CONTIGUOUS :: local_data => null()
73 END TYPE cp_cfm_type
74
75! **************************************************************************************************
76!> \brief Just to build arrays of pointers to matrices.
77!> \param matrix the pointer to the matrix
78! **************************************************************************************************
80 TYPE(cp_cfm_type), POINTER :: matrix => null()
81 END TYPE cp_cfm_p_type
82
83! **************************************************************************************************
84!> \brief Stores the state of a copy between cp_cfm_start_copy_general
85!> and cp_cfm_finish_copy_general.
86!> \par History
87!> Jan 2017 derived type 'copy_info_type' has been created [Mark T]
88!> Jan 2018 the type 'copy_info_type' has been adapted for complex matrices [Sergey Chulkov]
89! **************************************************************************************************
91 !> number of MPI processes that send data
92 INTEGER :: send_size = -1
93 !> number of locally stored rows (1) and columns (2) of the destination matrix
94 INTEGER, DIMENSION(2) :: nlocal_recv = -1
95 !> number of rows (1) and columns (2) of the ScaLAPACK block of the source matrix
96 INTEGER, DIMENSION(2) :: nblock_src = -1
97 !> BLACS process grid shape of the source matrix: (1) nproc_row, (2) nproc_col
98 INTEGER, DIMENSION(2) :: src_num_pe = -1
99 !> displacements into recv_buf
100 INTEGER, ALLOCATABLE, DIMENSION(:) :: recv_disp
101 !> MPI requests for non-blocking receive and send operations
102 TYPE(mp_request_type), ALLOCATABLE, DIMENSION(:) :: recv_request, send_request
103 !> global column and row indices of locally stored elements of the destination matrix
104 INTEGER, DIMENSION(:), POINTER :: recv_col_indices => null(), recv_row_indices => null()
105 !> rank of MPI process with BLACS coordinates (prow, pcol)
106 INTEGER, ALLOCATABLE, DIMENSION(:, :) :: src_blacs2mpi
107 !> receiving and sending buffers for non-blocking MPI communication
108 COMPLEX(kind=dp), ALLOCATABLE, DIMENSION(:) :: recv_buf, send_buf
109 END TYPE copy_cfm_info_type
110
111CONTAINS
112
113! **************************************************************************************************
114!> \brief Creates a new full matrix with the given structure.
115!> \param matrix matrix to be created
116!> \param matrix_struct structure of the matrix
117!> \param name name of the matrix
118!> \param nrow ...
119!> \param ncol ...
120!> \param set_zero ...
121!> \note
122!> preferred allocation routine
123! **************************************************************************************************
124 SUBROUTINE cp_cfm_create(matrix, matrix_struct, name, nrow, ncol, set_zero)
125 TYPE(cp_cfm_type), INTENT(OUT) :: matrix
126 TYPE(cp_fm_struct_type), INTENT(IN), TARGET :: matrix_struct
127 CHARACTER(len=*), INTENT(in), OPTIONAL :: name
128 INTEGER, INTENT(IN), OPTIONAL :: nrow, ncol
129 LOGICAL, INTENT(IN), OPTIONAL :: set_zero
130
131 INTEGER :: ncol_global, ncol_local, nrow_global, &
132 nrow_local
133 TYPE(cp_blacs_env_type), POINTER :: context
134 TYPE(cp_fm_struct_type), POINTER :: cfm_struct
135
136 IF (PRESENT(nrow) .OR. PRESENT(ncol)) THEN
137 CALL cp_fm_struct_get(matrix_struct, nrow_global=nrow_global, ncol_global=ncol_global)
138 IF (PRESENT(nrow)) nrow_global = nrow
139 IF (PRESENT(ncol)) ncol_global = ncol
140 CALL cp_fm_struct_create(cfm_struct, template_fmstruct=matrix_struct, &
141 nrow_global=nrow_global, ncol_global=ncol_global)
142
143 context => cfm_struct%context
144 matrix%matrix_struct => cfm_struct
145 CALL cp_fm_struct_retain(matrix%matrix_struct)
146
147 nrow_local = cfm_struct%local_leading_dimension
148 ncol_local = max(1, cfm_struct%ncol_locals(context%mepos(2)))
149
150 CALL cp_fm_struct_release(cfm_struct)
151 ELSE
152 context => matrix_struct%context
153 matrix%matrix_struct => matrix_struct
154 CALL cp_fm_struct_retain(matrix%matrix_struct)
155
156 nrow_local = matrix_struct%local_leading_dimension
157 ncol_local = max(1, matrix_struct%ncol_locals(context%mepos(2)))
158 END IF
159
160 NULLIFY (matrix%local_data)
161 ALLOCATE (matrix%local_data(nrow_local, ncol_local))
162
163 IF (PRESENT(set_zero)) THEN
164 IF (set_zero) THEN
165 matrix%local_data(1:nrow_local, 1:ncol_local) = z_zero
166 END IF
167 END IF
168
169 IF (PRESENT(name)) THEN
170 matrix%name = name
171 ELSE
172 matrix%name = 'full complex matrix'
173 END IF
174
175 END SUBROUTINE cp_cfm_create
176
177! **************************************************************************************************
178!> \brief Releases a full matrix.
179!> \param matrix the matrix to release
180! **************************************************************************************************
181 SUBROUTINE cp_cfm_release(matrix)
182 TYPE(cp_cfm_type), INTENT(INOUT) :: matrix
183
184 IF (ASSOCIATED(matrix%local_data)) THEN
185 DEALLOCATE (matrix%local_data)
186 END IF
187 matrix%name = ""
188 CALL cp_fm_struct_release(matrix%matrix_struct)
189 END SUBROUTINE cp_cfm_release
190
191! **************************************************************************************************
192!> \brief Set all elements of the full matrix to alpha. Besides, set all
193!> diagonal matrix elements to beta (if given explicitly).
194!> \param matrix matrix to initialise
195!> \param alpha value of off-diagonal matrix elements
196!> \param beta value of diagonal matrix elements (equal to alpha if absent)
197!> \date 12.06.2001
198!> \author Matthias Krack
199!> \version 1.0
200! **************************************************************************************************
201 SUBROUTINE cp_cfm_set_all(matrix, alpha, beta)
202 TYPE(cp_cfm_type), INTENT(IN) :: matrix
203 COMPLEX(kind=dp), INTENT(in) :: alpha
204 COMPLEX(kind=dp), INTENT(in), OPTIONAL :: beta
205
206 INTEGER :: irow_local, nrow_local
207#if defined(__parallel)
208 INTEGER :: icol_local, ncol_local
209 INTEGER, DIMENSION(:), POINTER :: col_indices, row_indices
210#endif
211
212 CALL zcopy(SIZE(matrix%local_data), alpha, 0, matrix%local_data(1, 1), 1)
213
214 IF (PRESENT(beta)) THEN
215#if defined(__parallel)
216 CALL cp_cfm_get_info(matrix, nrow_local=nrow_local, ncol_local=ncol_local, &
217 row_indices=row_indices, col_indices=col_indices)
218
219 icol_local = 1
220 irow_local = 1
221
222 DO WHILE (irow_local <= nrow_local .AND. icol_local <= ncol_local)
223 IF (row_indices(irow_local) < col_indices(icol_local)) THEN
224 irow_local = irow_local + 1
225 ELSE IF (row_indices(irow_local) > col_indices(icol_local)) THEN
226 icol_local = icol_local + 1
227 ELSE
228 matrix%local_data(irow_local, icol_local) = beta
229 irow_local = irow_local + 1
230 icol_local = icol_local + 1
231 END IF
232 END DO
233#else
234 nrow_local = min(matrix%matrix_struct%nrow_global, matrix%matrix_struct%ncol_global)
235
236 DO irow_local = 1, nrow_local
237 matrix%local_data(irow_local, irow_local) = beta
238 END DO
239#endif
240 END IF
241
242 END SUBROUTINE cp_cfm_set_all
243
244! **************************************************************************************************
245!> \brief Get the matrix element by its global index.
246!> \param matrix full matrix
247!> \param irow_global global row index
248!> \param icol_global global column index
249!> \param alpha matrix element
250!> \par History
251!> , TCH, created
252!> always return the answer
253! **************************************************************************************************
254 SUBROUTINE cp_cfm_get_element(matrix, irow_global, icol_global, alpha)
255 TYPE(cp_cfm_type), INTENT(IN) :: matrix
256 INTEGER, INTENT(in) :: irow_global, icol_global
257 COMPLEX(kind=dp), INTENT(out) :: alpha
258
259#if defined(__parallel)
260 INTEGER :: icol_local, ipcol, iprow, irow_local, &
261 mypcol, myprow, npcol, nprow
262 INTEGER, DIMENSION(9) :: desca
263 TYPE(cp_blacs_env_type), POINTER :: context
264#endif
265
266#if defined(__parallel)
267 context => matrix%matrix_struct%context
268 myprow = context%mepos(1)
269 mypcol = context%mepos(2)
270 nprow = context%num_pe(1)
271 npcol = context%num_pe(2)
272
273 desca(:) = matrix%matrix_struct%descriptor(:)
274
275 CALL infog2l(irow_global, icol_global, desca, nprow, npcol, myprow, mypcol, &
276 irow_local, icol_local, iprow, ipcol)
277
278 IF ((iprow == myprow) .AND. (ipcol == mypcol)) THEN
279 alpha = matrix%local_data(irow_local, icol_local)
280 CALL context%ZGEBS2D('All', ' ', 1, 1, alpha, 1)
281 ELSE
282 CALL context%ZGEBR2D('All', ' ', 1, 1, alpha, 1, iprow, ipcol)
283 END IF
284
285#else
286 alpha = matrix%local_data(irow_global, icol_global)
287#endif
288
289 END SUBROUTINE cp_cfm_get_element
290
291! **************************************************************************************************
292!> \brief Set the matrix element (irow_global,icol_global) of the full matrix to alpha.
293!> \param matrix full matrix
294!> \param irow_global global row index
295!> \param icol_global global column index
296!> \param alpha value of the matrix element
297!> \date 12.06.2001
298!> \author Matthias Krack
299!> \version 1.0
300! **************************************************************************************************
301 SUBROUTINE cp_cfm_set_element(matrix, irow_global, icol_global, alpha)
302 TYPE(cp_cfm_type), INTENT(IN) :: matrix
303 INTEGER, INTENT(in) :: irow_global, icol_global
304 COMPLEX(kind=dp), INTENT(in) :: alpha
305
306#if defined(__parallel)
307 INTEGER :: icol_local, ipcol, iprow, irow_local, &
308 mypcol, myprow, npcol, nprow
309 INTEGER, DIMENSION(9) :: desca
310 TYPE(cp_blacs_env_type), POINTER :: context
311#endif
312
313#if defined(__parallel)
314 context => matrix%matrix_struct%context
315 myprow = context%mepos(1)
316 mypcol = context%mepos(2)
317 nprow = context%num_pe(1)
318 npcol = context%num_pe(2)
319
320 desca(:) = matrix%matrix_struct%descriptor(:)
321
322 CALL infog2l(irow_global, icol_global, desca, nprow, npcol, myprow, mypcol, &
323 irow_local, icol_local, iprow, ipcol)
324
325 IF ((iprow == myprow) .AND. (ipcol == mypcol)) THEN
326 matrix%local_data(irow_local, icol_local) = alpha
327 END IF
328
329#else
330 matrix%local_data(irow_global, icol_global) = alpha
331#endif
332
333 END SUBROUTINE cp_cfm_set_element
334
335! **************************************************************************************************
336!> \brief Extract a sub-matrix from the full matrix:
337!> op(target_m)(1:n_rows,1:n_cols) = fm(start_row:start_row+n_rows,start_col:start_col+n_cols).
338!> Sub-matrix 'target_m' is replicated on each CPU. Using this call is expensive.
339!> \param fm full matrix you want to get the elements from
340!> \param target_m 2-D array to store the extracted sub-matrix
341!> \param start_row global row index of the matrix element target_m(1,1) (defaults to 1)
342!> \param start_col global column index of the matrix element target_m(1,1) (defaults to 1)
343!> \param n_rows number of rows to extract (defaults to size(op(target_m),1))
344!> \param n_cols number of columns to extract (defaults to size(op(target_m),2))
345!> \param transpose indicates that the extracted sub-matrix target_m should be transposed:
346!> op(target_m) = target_m^T if .TRUE.,
347!> op(target_m) = target_m if .FALSE. (defaults to false)
348!> \par History
349!> * 04.2016 created borrowing from Fawzi's cp_fm_get_submatrix [Lianheng Tong]
350!> * 01.2018 drop innermost conditional branching [Sergey Chulkov]
351!> \author Lianheng Tong
352!> \note
353!> Optimized for full column updates. The matrix target_m is replicated and valid on all CPUs.
354! **************************************************************************************************
355 SUBROUTINE cp_cfm_get_submatrix(fm, target_m, start_row, start_col, n_rows, n_cols, transpose)
356 TYPE(cp_cfm_type), INTENT(IN) :: fm
357 COMPLEX(kind=dp), DIMENSION(:, :), INTENT(out) :: target_m
358 INTEGER, INTENT(in), OPTIONAL :: start_row, start_col, n_rows, n_cols
359 LOGICAL, INTENT(in), OPTIONAL :: transpose
360
361 CHARACTER(len=*), PARAMETER :: routinen = 'cp_cfm_get_submatrix'
362
363 COMPLEX(kind=dp), DIMENSION(:, :), POINTER :: local_data
364 INTEGER :: end_col_global, end_col_local, end_row_global, end_row_local, handle, i, j, &
365 ncol_global, ncol_local, nrow_global, nrow_local, start_col_global, start_col_local, &
366 start_row_global, start_row_local, this_col
367 INTEGER, DIMENSION(:), POINTER :: col_indices, row_indices
368 LOGICAL :: do_zero, tr_a
369 TYPE(mp_para_env_type), POINTER :: para_env
370
371 CALL timeset(routinen, handle)
372
373 IF (SIZE(target_m) /= 0) THEN
374#if defined(__parallel)
375 do_zero = .true.
376#else
377 do_zero = .false.
378#endif
379
380 tr_a = .false.
381 IF (PRESENT(transpose)) tr_a = transpose
382
383 ! find out the first and last global row/column indices
384 start_row_global = 1
385 start_col_global = 1
386 IF (PRESENT(start_row)) start_row_global = start_row
387 IF (PRESENT(start_col)) start_col_global = start_col
388
389 IF (tr_a) THEN
390 end_row_global = SIZE(target_m, 2)
391 end_col_global = SIZE(target_m, 1)
392 ELSE
393 end_row_global = SIZE(target_m, 1)
394 end_col_global = SIZE(target_m, 2)
395 END IF
396 IF (PRESENT(n_rows)) end_row_global = n_rows
397 IF (PRESENT(n_cols)) end_col_global = n_cols
398
399 end_row_global = end_row_global + start_row_global - 1
400 end_col_global = end_col_global + start_col_global - 1
401
402 CALL cp_cfm_get_info(matrix=fm, &
403 nrow_global=nrow_global, ncol_global=ncol_global, &
404 nrow_local=nrow_local, ncol_local=ncol_local, &
405 row_indices=row_indices, col_indices=col_indices)
406 IF (end_row_global > nrow_global) THEN
407 end_row_global = nrow_global
408 do_zero = .true.
409 END IF
410 IF (end_col_global > ncol_global) THEN
411 end_col_global = ncol_global
412 do_zero = .true.
413 END IF
414
415 ! find out row/column indices of locally stored matrix elements that needs to be copied.
416 ! Arrays row_indices and col_indices are assumed to be sorted in ascending order
417 DO start_row_local = 1, nrow_local
418 IF (row_indices(start_row_local) >= start_row_global) EXIT
419 END DO
420
421 DO end_row_local = start_row_local, nrow_local
422 IF (row_indices(end_row_local) > end_row_global) EXIT
423 END DO
424 end_row_local = end_row_local - 1
425
426 DO start_col_local = 1, ncol_local
427 IF (col_indices(start_col_local) >= start_col_global) EXIT
428 END DO
429
430 DO end_col_local = start_col_local, ncol_local
431 IF (col_indices(end_col_local) > end_col_global) EXIT
432 END DO
433 end_col_local = end_col_local - 1
434
435 para_env => fm%matrix_struct%para_env
436 local_data => fm%local_data
437
438 ! wipe the content of the target matrix if:
439 ! * the source matrix is distributed across a number of processes, or
440 ! * not all elements of the target matrix will be assigned, e.g.
441 ! when the target matrix is larger then the source matrix
442 IF (do_zero) THEN
443 CALL zcopy(SIZE(target_m), z_zero, 0, target_m(1, 1), 1)
444 END IF
445
446 IF (tr_a) THEN
447 DO j = start_col_local, end_col_local
448 this_col = col_indices(j) - start_col_global + 1
449 DO i = start_row_local, end_row_local
450 target_m(this_col, row_indices(i) - start_row_global + 1) = local_data(i, j)
451 END DO
452 END DO
453 ELSE
454 DO j = start_col_local, end_col_local
455 this_col = col_indices(j) - start_col_global + 1
456 DO i = start_row_local, end_row_local
457 target_m(row_indices(i) - start_row_global + 1, this_col) = local_data(i, j)
458 END DO
459 END DO
460 END IF
461
462 CALL para_env%sum(target_m)
463 END IF
464
465 CALL timestop(handle)
466 END SUBROUTINE cp_cfm_get_submatrix
467
468! **************************************************************************************************
469!> \brief Set a sub-matrix of the full matrix:
470!> matrix(start_row:start_row+n_rows,start_col:start_col+n_cols)
471!> = alpha*op(new_values)(1:n_rows,1:n_cols) +
472!> beta*matrix(start_row:start_row+n_rows,start_col:start_col+n_cols)
473!> \param matrix full to update
474!> \param new_values replicated 2-D array that holds new elements of the updated sub-matrix
475!> \param start_row global row index of the matrix element new_values(1,1) (defaults to 1)
476!> \param start_col global column index of the matrix element new_values(1,1) (defaults to 1)
477!> \param n_rows number of rows to update (defaults to size(op(new_values),1))
478!> \param n_cols number of columns to update (defaults to size(op(new_values),2))
479!> \param alpha scale factor for the new values (defaults to (1.0,0.0))
480!> \param beta scale factor for the old values (defaults to (0.0,0.0))
481!> \param transpose indicates that the matrix new_values should be transposed:
482!> op(new_values) = new_values^T if .TRUE.,
483!> op(new_values) = new_values if .FALSE. (defaults to false)
484!> \par History
485!> * 04.2016 created borrowing from Fawzi's cp_fm_set_submatrix [Lianheng Tong]
486!> * 01.2018 drop innermost conditional branching [Sergey Chulkov]
487!> \author Lianheng Tong
488!> \note
489!> Optimized for alpha=(1.0,0.0), beta=(0.0,0.0)
490!> All matrix elements 'new_values' need to be valid on all CPUs
491! **************************************************************************************************
492 SUBROUTINE cp_cfm_set_submatrix(matrix, new_values, start_row, &
493 start_col, n_rows, n_cols, alpha, beta, transpose)
494 TYPE(cp_cfm_type), INTENT(IN) :: matrix
495 COMPLEX(kind=dp), DIMENSION(:, :), INTENT(in) :: new_values
496 INTEGER, INTENT(in), OPTIONAL :: start_row, start_col, n_rows, n_cols
497 COMPLEX(kind=dp), INTENT(in), OPTIONAL :: alpha, beta
498 LOGICAL, INTENT(in), OPTIONAL :: transpose
499
500 CHARACTER(len=*), PARAMETER :: routinen = 'cp_cfm_set_submatrix'
501
502 COMPLEX(kind=dp) :: al, be
503 COMPLEX(kind=dp), DIMENSION(:, :), POINTER :: local_data
504 INTEGER :: end_col_global, end_col_local, end_row_global, end_row_local, handle, i, j, &
505 ncol_global, ncol_local, nrow_global, nrow_local, start_col_global, start_col_local, &
506 start_row_global, start_row_local, this_col
507 INTEGER, DIMENSION(:), POINTER :: col_indices, row_indices
508 LOGICAL :: tr_a
509
510 CALL timeset(routinen, handle)
511
512 al = z_one
513 be = z_zero
514 IF (PRESENT(alpha)) al = alpha
515 IF (PRESENT(beta)) be = beta
516
517 ! find out the first and last global row/column indices
518 start_row_global = 1
519 start_col_global = 1
520 IF (PRESENT(start_row)) start_row_global = start_row
521 IF (PRESENT(start_col)) start_col_global = start_col
522
523 tr_a = .false.
524 IF (PRESENT(transpose)) tr_a = transpose
525
526 IF (tr_a) THEN
527 end_row_global = SIZE(new_values, 2)
528 end_col_global = SIZE(new_values, 1)
529 ELSE
530 end_row_global = SIZE(new_values, 1)
531 end_col_global = SIZE(new_values, 2)
532 END IF
533 IF (PRESENT(n_rows)) end_row_global = n_rows
534 IF (PRESENT(n_cols)) end_col_global = n_cols
535
536 end_row_global = end_row_global + start_row_global - 1
537 end_col_global = end_col_global + start_col_global - 1
538
539 CALL cp_cfm_get_info(matrix=matrix, &
540 nrow_global=nrow_global, ncol_global=ncol_global, &
541 nrow_local=nrow_local, ncol_local=ncol_local, &
542 row_indices=row_indices, col_indices=col_indices)
543 IF (end_row_global > nrow_global) end_row_global = nrow_global
544 IF (end_col_global > ncol_global) end_col_global = ncol_global
545
546 ! find out row/column indices of locally stored matrix elements that needs to be set.
547 ! Arrays row_indices and col_indices are assumed to be sorted in ascending order
548 DO start_row_local = 1, nrow_local
549 IF (row_indices(start_row_local) >= start_row_global) EXIT
550 END DO
551
552 DO end_row_local = start_row_local, nrow_local
553 IF (row_indices(end_row_local) > end_row_global) EXIT
554 END DO
555 end_row_local = end_row_local - 1
556
557 DO start_col_local = 1, ncol_local
558 IF (col_indices(start_col_local) >= start_col_global) EXIT
559 END DO
560
561 DO end_col_local = start_col_local, ncol_local
562 IF (col_indices(end_col_local) > end_col_global) EXIT
563 END DO
564 end_col_local = end_col_local - 1
565
566 local_data => matrix%local_data
567
568 IF (al == z_one .AND. be == z_zero) THEN
569 IF (tr_a) THEN
570 DO j = start_col_local, end_col_local
571 this_col = col_indices(j) - start_col_global + 1
572 DO i = start_row_local, end_row_local
573 local_data(i, j) = new_values(this_col, row_indices(i) - start_row_global + 1)
574 END DO
575 END DO
576 ELSE
577 DO j = start_col_local, end_col_local
578 this_col = col_indices(j) - start_col_global + 1
579 DO i = start_row_local, end_row_local
580 local_data(i, j) = new_values(row_indices(i) - start_row_global + 1, this_col)
581 END DO
582 END DO
583 END IF
584 ELSE
585 IF (tr_a) THEN
586 DO j = start_col_local, end_col_local
587 this_col = col_indices(j) - start_col_global + 1
588 DO i = start_row_local, end_row_local
589 local_data(i, j) = al*new_values(this_col, row_indices(i) - start_row_global + 1) + &
590 be*local_data(i, j)
591 END DO
592 END DO
593 ELSE
594 DO j = start_col_local, end_col_local
595 this_col = col_indices(j) - start_col_global + 1
596 DO i = start_row_local, end_row_local
597 local_data(i, j) = al*new_values(row_indices(i) - start_row_global + 1, this_col) + &
598 be*local_data(i, j)
599 END DO
600 END DO
601 END IF
602 END IF
603
604 CALL timestop(handle)
605 END SUBROUTINE cp_cfm_set_submatrix
606
607! **************************************************************************************************
608!> \brief Returns information about a full matrix.
609!> \param matrix matrix
610!> \param name name of the matrix
611!> \param nrow_global total number of rows
612!> \param ncol_global total number of columns
613!> \param nrow_block number of rows per ScaLAPACK block
614!> \param ncol_block number of columns per ScaLAPACK block
615!> \param nrow_local number of locally stored rows
616!> \param ncol_local number of locally stored columns
617!> \param row_indices global indices of locally stored rows
618!> \param col_indices global indices of locally stored columns
619!> \param local_data locally stored matrix elements
620!> \param context BLACS context
621!> \param matrix_struct matrix structure
622!> \param para_env parallel environment
623!> \date 12.06.2001
624!> \author Matthias Krack
625!> \version 1.0
626! **************************************************************************************************
627 SUBROUTINE cp_cfm_get_info(matrix, name, nrow_global, ncol_global, &
628 nrow_block, ncol_block, nrow_local, ncol_local, &
629 row_indices, col_indices, local_data, context, &
630 matrix_struct, para_env)
631 TYPE(cp_cfm_type), INTENT(IN) :: matrix
632 CHARACTER(len=*), INTENT(OUT), OPTIONAL :: name
633 INTEGER, INTENT(OUT), OPTIONAL :: nrow_global, ncol_global, nrow_block, &
634 ncol_block, nrow_local, ncol_local
635 INTEGER, DIMENSION(:), OPTIONAL, POINTER :: row_indices, col_indices
636 COMPLEX(kind=dp), CONTIGUOUS, DIMENSION(:, :), &
637 OPTIONAL, POINTER :: local_data
638 TYPE(cp_blacs_env_type), OPTIONAL, POINTER :: context
639 TYPE(cp_fm_struct_type), OPTIONAL, POINTER :: matrix_struct
640 TYPE(mp_para_env_type), OPTIONAL, POINTER :: para_env
641
642 IF (PRESENT(name)) name = matrix%name
643 IF (PRESENT(matrix_struct)) matrix_struct => matrix%matrix_struct
644 IF (PRESENT(local_data)) local_data => matrix%local_data ! not hiding things anymore :-(
645
646 CALL cp_fm_struct_get(matrix%matrix_struct, nrow_local=nrow_local, &
647 ncol_local=ncol_local, nrow_global=nrow_global, &
648 ncol_global=ncol_global, nrow_block=nrow_block, &
649 ncol_block=ncol_block, context=context, &
650 row_indices=row_indices, col_indices=col_indices, para_env=para_env)
651
652 END SUBROUTINE cp_cfm_get_info
653
654! **************************************************************************************************
655!> \brief Copy content of a full matrix into another full matrix of the same size.
656!> \param source source matrix
657!> \param destination destination matrix
658!> \author Joost VandeVondele
659! **************************************************************************************************
660 SUBROUTINE cp_cfm_to_cfm_matrix(source, destination)
661 TYPE(cp_cfm_type), INTENT(IN) :: source, destination
662
663 INTEGER :: npcol, nprow
664
665 nprow = source%matrix_struct%context%num_pe(1)
666 npcol = source%matrix_struct%context%num_pe(2)
667
668 IF (.NOT. cp2k_is_parallel .OR. &
669 cp_fm_struct_equivalent(source%matrix_struct, &
670 destination%matrix_struct)) THEN
671 IF (SIZE(source%local_data, 1) /= SIZE(destination%local_data, 1) .OR. &
672 SIZE(source%local_data, 2) /= SIZE(destination%local_data, 2)) THEN
673 cpabort("internal local_data has different sizes")
674 END IF
675 CALL zcopy(SIZE(source%local_data), source%local_data(1, 1), 1, destination%local_data(1, 1), 1)
676 ELSE
677 IF (source%matrix_struct%nrow_global /= destination%matrix_struct%nrow_global) THEN
678 cpabort("cannot copy between full matrixes of differen sizes")
679 END IF
680 IF (source%matrix_struct%ncol_global /= destination%matrix_struct%ncol_global) THEN
681 cpabort("cannot copy between full matrixes of differen sizes")
682 END IF
683#if defined(__parallel)
684 CALL pzcopy(source%matrix_struct%nrow_global* &
685 source%matrix_struct%ncol_global, &
686 source%local_data(1, 1), 1, 1, source%matrix_struct%descriptor, 1, &
687 destination%local_data(1, 1), 1, 1, destination%matrix_struct%descriptor, 1)
688#else
689 cpabort("cp_cfm_to_cfm_matrix: pzcopy needs __parallel build flag")
690#endif
691 END IF
692 END SUBROUTINE cp_cfm_to_cfm_matrix
693
694! **************************************************************************************************
695!> \brief Copy a number of sequential columns of a full matrix into another full matrix.
696!> \param msource source matrix
697!> \param mtarget destination matrix
698!> \param ncol number of columns to copy
699!> \param source_start global index of the first column to copy within the source matrix
700!> \param target_start global index of the first column to copy within the destination matrix
701! **************************************************************************************************
702 SUBROUTINE cp_cfm_to_cfm_columns(msource, mtarget, ncol, source_start, &
703 target_start)
704
705 TYPE(cp_cfm_type), INTENT(IN) :: msource, mtarget
706 INTEGER, INTENT(IN) :: ncol
707 INTEGER, INTENT(IN), OPTIONAL :: source_start, target_start
708
709 CHARACTER(len=*), PARAMETER :: routineN = 'cp_cfm_to_cfm_columns'
710
711 COMPLEX(kind=dp), DIMENSION(:, :), POINTER :: a, b
712 INTEGER :: handle, n, ss, ts
713#if defined(__parallel)
714 INTEGER :: i
715 INTEGER, DIMENSION(9) :: desca, descb
716#endif
717
718 CALL timeset(routinen, handle)
719
720 ss = 1
721 ts = 1
722
723 IF (PRESENT(source_start)) ss = source_start
724 IF (PRESENT(target_start)) ts = target_start
725
726 n = msource%matrix_struct%nrow_global
727
728 a => msource%local_data
729 b => mtarget%local_data
730
731#if defined(__parallel)
732 desca(:) = msource%matrix_struct%descriptor(:)
733 descb(:) = mtarget%matrix_struct%descriptor(:)
734 DO i = 0, ncol - 1
735 CALL pzcopy(n, a(1, 1), 1, ss + i, desca, 1, b(1, 1), 1, ts + i, descb, 1)
736 END DO
737#else
738 CALL zcopy(ncol*n, a(1, ss), 1, b(1, ts), 1)
739#endif
740
741 CALL timestop(handle)
742
743 END SUBROUTINE cp_cfm_to_cfm_columns
744
745! **************************************************************************************************
746!> \brief Copy just a triangular matrix.
747!> \param msource source matrix
748!> \param mtarget target matrix
749!> \param uplo 'U' for upper triangular, 'L' for lower triangular
750! **************************************************************************************************
751 SUBROUTINE cp_cfm_to_cfm_triangular(msource, mtarget, uplo)
752 TYPE(cp_cfm_type), INTENT(IN) :: msource, mtarget
753 CHARACTER(len=*), INTENT(IN) :: uplo
754
755 CHARACTER(len=*), PARAMETER :: routineN = 'cp_cfm_to_cfm_triangular'
756
757 COMPLEX(kind=dp), DIMENSION(:, :), POINTER :: aa, bb
758 INTEGER :: handle, ncol, nrow
759#if defined(__parallel)
760 INTEGER, DIMENSION(9) :: desca, descb
761#endif
762
763 CALL timeset(routinen, handle)
764
765 nrow = msource%matrix_struct%nrow_global
766 ncol = msource%matrix_struct%ncol_global
767
768 aa => msource%local_data
769 bb => mtarget%local_data
770
771#if defined(__parallel)
772 desca(:) = msource%matrix_struct%descriptor(:)
773 descb(:) = mtarget%matrix_struct%descriptor(:)
774 CALL pzlacpy(uplo, nrow, ncol, aa(1, 1), 1, 1, desca, bb(1, 1), 1, 1, descb)
775#else
776 CALL zlacpy(uplo, nrow, ncol, aa(1, 1), nrow, bb(1, 1), nrow)
777#endif
778
779 CALL timestop(handle)
780 END SUBROUTINE cp_cfm_to_cfm_triangular
781
782! **************************************************************************************************
783!> \brief Copy real and imaginary parts of a complex full matrix into
784!> separate real-value full matrices.
785!> \param msource complex matrix
786!> \param mtargetr (optional) real part of the source matrix
787!> \param mtargeti (optional) imaginary part of the source matrix
788!> \note
789!> Matrix structures are assumed to be equivalent.
790! **************************************************************************************************
791 SUBROUTINE cp_cfm_to_fm(msource, mtargetr, mtargeti)
792
793 TYPE(cp_cfm_type), INTENT(IN) :: msource
794 TYPE(cp_fm_type), INTENT(IN), OPTIONAL :: mtargetr, mtargeti
795
796 CHARACTER(len=*), PARAMETER :: routinen = 'cp_cfm_to_fm'
797
798 COMPLEX(kind=dp), DIMENSION(:, :), POINTER :: zmat
799 INTEGER :: handle
800 REAL(kind=dp), DIMENSION(:, :), POINTER :: imat, rmat
801
802 CALL timeset(routinen, handle)
803
804 zmat => msource%local_data
805 IF (PRESENT(mtargetr)) THEN
806 rmat => mtargetr%local_data
807 IF ((.NOT. cp_fm_struct_equivalent(mtargetr%matrix_struct, msource%matrix_struct)) .OR. &
808 (SIZE(rmat, 1) /= SIZE(zmat, 1)) .OR. &
809 (SIZE(rmat, 2) /= SIZE(zmat, 2))) THEN
810 cpabort("size of local_data of mtargetr differ to msource")
811 END IF
812 ! copy local data
813 rmat = real(zmat, kind=dp)
814 ELSE
815 NULLIFY (rmat)
816 END IF
817 IF (PRESENT(mtargeti)) THEN
818 imat => mtargeti%local_data
819 IF ((.NOT. cp_fm_struct_equivalent(mtargeti%matrix_struct, msource%matrix_struct)) .OR. &
820 (SIZE(imat, 1) /= SIZE(zmat, 1)) .OR. &
821 (SIZE(imat, 2) /= SIZE(zmat, 2))) THEN
822 cpabort("size of local_data of mtargeti differ to msource")
823 END IF
824 ! copy local data
825 imat = real(aimag(zmat), kind=dp)
826 ELSE
827 NULLIFY (imat)
828 END IF
829
830 CALL timestop(handle)
831
832 END SUBROUTINE cp_cfm_to_fm
833
834! **************************************************************************************************
835!> \brief Construct a complex full matrix by taking its real and imaginary parts from
836!> two separate real-value full matrices.
837!> \param msourcer (optional) real part of the complex matrix (defaults to 0.0)
838!> \param msourcei (optional) imaginary part of the complex matrix (defaults to 0.0)
839!> \param mtarget resulting complex matrix
840!> \note
841!> Matrix structures are assumed to be equivalent.
842! **************************************************************************************************
843 SUBROUTINE cp_fm_to_cfm(msourcer, msourcei, mtarget)
844 TYPE(cp_fm_type), INTENT(IN), OPTIONAL :: msourcer, msourcei
845 TYPE(cp_cfm_type), INTENT(IN) :: mtarget
846
847 CHARACTER(len=*), PARAMETER :: routinen = 'cp_fm_to_cfm'
848
849 COMPLEX(kind=dp), DIMENSION(:, :), POINTER :: zmat
850 INTEGER :: handle, mode
851 REAL(kind=dp), DIMENSION(:, :), POINTER :: imat, rmat
852
853 CALL timeset(routinen, handle)
854
855 mode = 0
856 zmat => mtarget%local_data
857 IF (PRESENT(msourcer)) THEN
858 rmat => msourcer%local_data
859 IF ((.NOT. cp_fm_struct_equivalent(msourcer%matrix_struct, mtarget%matrix_struct)) .OR. &
860 (SIZE(rmat, 1) /= SIZE(zmat, 1)) .OR. &
861 (SIZE(rmat, 2) /= SIZE(zmat, 2))) THEN
862 cpabort("size of local_data of msourcer differ to mtarget")
863 END IF
864 mode = mode + 1
865 ELSE
866 NULLIFY (rmat)
867 END IF
868 IF (PRESENT(msourcei)) THEN
869 imat => msourcei%local_data
870 IF ((.NOT. cp_fm_struct_equivalent(msourcei%matrix_struct, mtarget%matrix_struct)) .OR. &
871 (SIZE(imat, 1) /= SIZE(zmat, 1)) .OR. &
872 (SIZE(imat, 2) /= SIZE(zmat, 2))) THEN
873 cpabort("size of local_data of msourcei differ to mtarget")
874 END IF
875 mode = mode + 2
876 ELSE
877 NULLIFY (imat)
878 END IF
879 ! copy local data
880 SELECT CASE (mode)
881 CASE (0)
882 zmat(:, :) = z_zero
883 CASE (1)
884 zmat(:, :) = cmplx(rmat(:, :), 0.0_dp, kind=dp)
885 CASE (2)
886 zmat(:, :) = cmplx(0.0_dp, imat(:, :), kind=dp)
887 CASE (3)
888 zmat(:, :) = cmplx(rmat(:, :), imat(:, :), kind=dp)
889 END SELECT
890
891 CALL timestop(handle)
892
893 END SUBROUTINE cp_fm_to_cfm
894
895! **************************************************************************************************
896!> \brief Initiate the copy operation: get distribution data, post MPI isend and irecvs.
897!> \param source input complex-valued fm matrix
898!> \param destination output complex-valued fm matrix
899!> \param para_env parallel environment corresponding to the BLACS env that covers all parts
900!> of the input and output matrices
901!> \param info all of the data that will be needed to complete the copy operation
902!> \note a slightly modified version of the subroutine cp_fm_start_copy_general() that uses
903!> allocatable arrays instead of pointers wherever possible.
904! **************************************************************************************************
905 SUBROUTINE cp_cfm_start_copy_general(source, destination, para_env, info)
906 TYPE(cp_cfm_type), INTENT(IN) :: source, destination
907 TYPE(mp_para_env_type), INTENT(IN), POINTER :: para_env
908 TYPE(copy_cfm_info_type), INTENT(out) :: info
909
910 CHARACTER(len=*), PARAMETER :: routinen = 'cp_cfm_start_copy_general'
911
912 INTEGER :: dest_p_i, dest_q_j, global_rank, global_size, handle, i, j, k, mpi_rank, &
913 ncol_block_dest, ncol_block_src, ncol_local_recv, ncol_local_send, ncols, &
914 nrow_block_dest, nrow_block_src, nrow_local_recv, nrow_local_send, nrows, p, q, &
915 recv_rank, recv_size, send_rank, send_size
916 INTEGER, ALLOCATABLE, DIMENSION(:) :: all_ranks, dest2global, dest_p, dest_q, &
917 recv_count, send_count, send_disp, &
918 source2global, src_p, src_q
919 INTEGER, ALLOCATABLE, DIMENSION(:, :) :: dest_blacs2mpi
920 INTEGER, DIMENSION(2) :: dest_block, dest_block_tmp, dest_num_pe, &
921 src_block, src_block_tmp, src_num_pe
922 INTEGER, DIMENSION(:), POINTER :: recv_col_indices, recv_row_indices, &
923 send_col_indices, send_row_indices
924 TYPE(cp_fm_struct_type), POINTER :: recv_dist, send_dist
925 TYPE(mp_request_type), DIMENSION(6) :: recv_req, send_req
926
927 CALL timeset(routinen, handle)
928
929 IF (.NOT. cp2k_is_parallel) THEN
930 ! Just copy all of the matrix data into a 'send buffer', to be unpacked later
931 nrow_local_send = SIZE(source%local_data, 1)
932 ncol_local_send = SIZE(source%local_data, 2)
933 ALLOCATE (info%send_buf(nrow_local_send*ncol_local_send))
934 k = 0
935 DO j = 1, ncol_local_send
936 DO i = 1, nrow_local_send
937 k = k + 1
938 info%send_buf(k) = source%local_data(i, j)
939 END DO
940 END DO
941 ELSE
942 NULLIFY (recv_dist, send_dist)
943 NULLIFY (recv_col_indices, recv_row_indices, send_col_indices, send_row_indices)
944
945 ! The 'global' communicator contains both the source and destination decompositions
946 global_size = para_env%num_pe
947 global_rank = para_env%mepos
948
949 ! The source/send decomposition and destination/recv decompositions may only exist on
950 ! on a subset of the processes involved in the communication
951 ! Check if the source and/or destination arguments are .not. ASSOCIATED():
952 ! if so, skip the send / recv parts (since these processes do not participate in the sending/receiving distribution)
953 IF (ASSOCIATED(destination%matrix_struct)) THEN
954 recv_dist => destination%matrix_struct
955 recv_rank = recv_dist%para_env%mepos
956 ELSE
957 recv_rank = mp_proc_null
958 END IF
959
960 IF (ASSOCIATED(source%matrix_struct)) THEN
961 send_dist => source%matrix_struct
962 send_rank = send_dist%para_env%mepos
963 ELSE
964 send_rank = mp_proc_null
965 END IF
966
967 ! Map the rank in the source/dest communicator to the global rank
968 ALLOCATE (all_ranks(0:global_size - 1))
969
970 CALL para_env%allgather(send_rank, all_ranks)
971 IF (ASSOCIATED(destination%matrix_struct)) THEN
972 ALLOCATE (source2global(0:count(all_ranks /= mp_proc_null) - 1))
973 DO i = 0, global_size - 1
974 IF (all_ranks(i) /= mp_proc_null) THEN
975 source2global(all_ranks(i)) = i
976 END IF
977 END DO
978 END IF
979
980 CALL para_env%allgather(recv_rank, all_ranks)
981 IF (ASSOCIATED(source%matrix_struct)) THEN
982 ALLOCATE (dest2global(0:count(all_ranks /= mp_proc_null) - 1))
983 DO i = 0, global_size - 1
984 IF (all_ranks(i) /= mp_proc_null) THEN
985 dest2global(all_ranks(i)) = i
986 END IF
987 END DO
988 END IF
989 DEALLOCATE (all_ranks)
990
991 ! Some data from the two decompositions will be needed by all processes in the global group :
992 ! process grid shape, block size, and the BLACS-to-MPI mapping
993
994 ! The global root process will receive the data (from the root process in each decomposition)
995 send_req(:) = mp_request_null
996 IF (global_rank == 0) THEN
997 recv_req(:) = mp_request_null
998 CALL para_env%irecv(src_block, mp_any_source, recv_req(1), tag=src_tag)
999 CALL para_env%irecv(dest_block, mp_any_source, recv_req(2), tag=dest_tag)
1000 CALL para_env%irecv(src_num_pe, mp_any_source, recv_req(3), tag=src_tag)
1001 CALL para_env%irecv(dest_num_pe, mp_any_source, recv_req(4), tag=dest_tag)
1002 END IF
1003
1004 IF (ASSOCIATED(source%matrix_struct)) THEN
1005 IF ((send_rank == 0)) THEN
1006 ! need to use separate buffers here in case this is actually global rank 0
1007 src_block_tmp = [send_dist%nrow_block, send_dist%ncol_block]
1008 CALL para_env%isend(src_block_tmp, 0, send_req(1), tag=src_tag)
1009 CALL para_env%isend(send_dist%context%num_pe, 0, send_req(2), tag=src_tag)
1010 END IF
1011 END IF
1012
1013 IF (ASSOCIATED(destination%matrix_struct)) THEN
1014 IF ((recv_rank == 0)) THEN
1015 dest_block_tmp = [recv_dist%nrow_block, recv_dist%ncol_block]
1016 CALL para_env%isend(dest_block_tmp, 0, send_req(3), tag=dest_tag)
1017 CALL para_env%isend(recv_dist%context%num_pe, 0, send_req(4), tag=dest_tag)
1018 END IF
1019 END IF
1020
1021 IF (global_rank == 0) THEN
1022 CALL mp_waitall(recv_req(1:4))
1023 ! Now we know the process decomposition, we can allocate the arrays to hold the blacs2mpi mapping
1024 ALLOCATE (info%src_blacs2mpi(0:src_num_pe(1) - 1, 0:src_num_pe(2) - 1), &
1025 dest_blacs2mpi(0:dest_num_pe(1) - 1, 0:dest_num_pe(2) - 1))
1026 CALL para_env%irecv(info%src_blacs2mpi, mp_any_source, recv_req(5), tag=src_tag)
1027 CALL para_env%irecv(dest_blacs2mpi, mp_any_source, recv_req(6), tag=dest_tag)
1028 END IF
1029
1030 IF (ASSOCIATED(source%matrix_struct)) THEN
1031 IF ((send_rank == 0)) THEN
1032 CALL para_env%isend(send_dist%context%blacs2mpi(:, :), 0, send_req(5), tag=src_tag)
1033 END IF
1034 END IF
1035
1036 IF (ASSOCIATED(destination%matrix_struct)) THEN
1037 IF ((recv_rank == 0)) THEN
1038 CALL para_env%isend(recv_dist%context%blacs2mpi(:, :), 0, send_req(6), tag=dest_tag)
1039 END IF
1040 END IF
1041
1042 IF (global_rank == 0) THEN
1043 CALL mp_waitall(recv_req(5:6))
1044 END IF
1045
1046 ! Finally, broadcast the data to all processes in the global communicator
1047 CALL para_env%bcast(src_block, 0)
1048 CALL para_env%bcast(dest_block, 0)
1049 CALL para_env%bcast(src_num_pe, 0)
1050 CALL para_env%bcast(dest_num_pe, 0)
1051 info%src_num_pe(1:2) = src_num_pe(1:2)
1052 info%nblock_src(1:2) = src_block(1:2)
1053 IF (global_rank /= 0) THEN
1054 ALLOCATE (info%src_blacs2mpi(0:src_num_pe(1) - 1, 0:src_num_pe(2) - 1), &
1055 dest_blacs2mpi(0:dest_num_pe(1) - 1, 0:dest_num_pe(2) - 1))
1056 END IF
1057 CALL para_env%bcast(info%src_blacs2mpi, 0)
1058 CALL para_env%bcast(dest_blacs2mpi, 0)
1059
1060 recv_size = dest_num_pe(1)*dest_num_pe(2)
1061 send_size = src_num_pe(1)*src_num_pe(2)
1062 info%send_size = send_size
1063 CALL mp_waitall(send_req(:))
1064
1065 ! Setup is now complete, we can start the actual communication here.
1066 ! The order implemented here is:
1067 ! DEST_1
1068 ! compute recv sizes
1069 ! call irecv
1070 ! SRC_1
1071 ! compute send sizes
1072 ! pack send buffers
1073 ! call isend
1074 ! DEST_2
1075 ! wait for the recvs and unpack buffers (this part eventually will go into another
1076 ! routine to allow comms to run concurrently)
1077 ! SRC_2
1078 ! wait for the sends
1079
1080 ! DEST_1
1081 IF (ASSOCIATED(destination%matrix_struct)) THEN
1082 CALL cp_fm_struct_get(recv_dist, row_indices=recv_row_indices, &
1083 col_indices=recv_col_indices)
1084 info%recv_col_indices => recv_col_indices
1085 info%recv_row_indices => recv_row_indices
1086 nrow_block_src = src_block(1)
1087 ncol_block_src = src_block(2)
1088 ALLOCATE (recv_count(0:send_size - 1), info%recv_disp(0:send_size - 1), info%recv_request(0:send_size - 1))
1089
1090 ! Determine the recv counts, allocate the receive buffers, call mpi_irecv for all the non-zero sized receives
1091 nrow_local_recv = recv_dist%nrow_locals(recv_dist%context%mepos(1))
1092 ncol_local_recv = recv_dist%ncol_locals(recv_dist%context%mepos(2))
1093 info%nlocal_recv(1) = nrow_local_recv
1094 info%nlocal_recv(2) = ncol_local_recv
1095 ! Initialise src_p, src_q arrays (sized using number of rows/cols in the receiving distribution)
1096 ALLOCATE (src_p(nrow_local_recv), src_q(ncol_local_recv))
1097 DO i = 1, nrow_local_recv
1098 ! For each local row we will receive, we look up its global row (in recv_row_indices),
1099 ! then work out which row block it comes from, and which process row that row block comes from.
1100 src_p(i) = mod(((recv_row_indices(i) - 1)/nrow_block_src), src_num_pe(1))
1101 END DO
1102 DO j = 1, ncol_local_recv
1103 ! Similarly for the columns
1104 src_q(j) = mod(((recv_col_indices(j) - 1)/ncol_block_src), src_num_pe(2))
1105 END DO
1106 ! src_p/q now contains the process row/column ID that will send data to that row/column
1107
1108 DO q = 0, src_num_pe(2) - 1
1109 ncols = count(src_q == q)
1110 DO p = 0, src_num_pe(1) - 1
1111 nrows = count(src_p == p)
1112 ! Use the send_dist here as we are looking up the processes where the data comes from
1113 recv_count(info%src_blacs2mpi(p, q)) = nrows*ncols
1114 END DO
1115 END DO
1116 DEALLOCATE (src_p, src_q)
1117
1118 ! Use one long buffer (and displacements into that buffer)
1119 ! this prevents the need for a rectangular array where not all elements will be populated
1120 ALLOCATE (info%recv_buf(sum(recv_count(:))))
1121 info%recv_disp(0) = 0
1122 DO i = 1, send_size - 1
1123 info%recv_disp(i) = info%recv_disp(i - 1) + recv_count(i - 1)
1124 END DO
1125
1126 ! Issue receive calls on ranks which expect data
1127 DO k = 0, send_size - 1
1128 IF (recv_count(k) > 0) THEN
1129 CALL para_env%irecv(info%recv_buf(info%recv_disp(k) + 1:info%recv_disp(k) + recv_count(k)), &
1130 source2global(k), info%recv_request(k))
1131 ELSE
1132 info%recv_request(k) = mp_request_null
1133 END IF
1134 END DO
1135 DEALLOCATE (source2global)
1136 END IF ! ASSOCIATED(destination)
1137
1138 ! SRC_1
1139 IF (ASSOCIATED(source%matrix_struct)) THEN
1140 CALL cp_fm_struct_get(send_dist, row_indices=send_row_indices, &
1141 col_indices=send_col_indices)
1142 nrow_block_dest = dest_block(1)
1143 ncol_block_dest = dest_block(2)
1144 ALLOCATE (send_count(0:recv_size - 1), send_disp(0:recv_size - 1), info%send_request(0:recv_size - 1))
1145
1146 ! Determine the send counts, allocate the send buffers
1147 nrow_local_send = send_dist%nrow_locals(send_dist%context%mepos(1))
1148 ncol_local_send = send_dist%ncol_locals(send_dist%context%mepos(2))
1149
1150 ! Initialise dest_p, dest_q arrays (sized nrow_local, ncol_local)
1151 ! i.e. number of rows,cols in the sending distribution
1152 ALLOCATE (dest_p(nrow_local_send), dest_q(ncol_local_send))
1153
1154 DO i = 1, nrow_local_send
1155 ! Use the send_dist%row_indices() here (we are looping over the local rows we will send)
1156 dest_p(i) = mod(((send_row_indices(i) - 1)/nrow_block_dest), dest_num_pe(1))
1157 END DO
1158 DO j = 1, ncol_local_send
1159 dest_q(j) = mod(((send_col_indices(j) - 1)/ncol_block_dest), dest_num_pe(2))
1160 END DO
1161 ! dest_p/q now contain the process row/column ID that will receive data from that row/column
1162
1163 DO q = 0, dest_num_pe(2) - 1
1164 ncols = count(dest_q == q)
1165 DO p = 0, dest_num_pe(1) - 1
1166 nrows = count(dest_p == p)
1167 send_count(dest_blacs2mpi(p, q)) = nrows*ncols
1168 END DO
1169 END DO
1170 DEALLOCATE (dest_p, dest_q)
1171
1172 ! Allocate the send buffer using send_count -- and calculate the offset into the buffer for each process
1173 ALLOCATE (info%send_buf(sum(send_count(:))))
1174 send_disp(0) = 0
1175 DO k = 1, recv_size - 1
1176 send_disp(k) = send_disp(k - 1) + send_count(k - 1)
1177 END DO
1178
1179 ! Loop over the smat, pack the send buffers
1180 send_count(:) = 0
1181 DO j = 1, ncol_local_send
1182 ! Use send_col_indices and row_indices here, as we are looking up the global row/column number of local rows.
1183 dest_q_j = mod(((send_col_indices(j) - 1)/ncol_block_dest), dest_num_pe(2))
1184 DO i = 1, nrow_local_send
1185 dest_p_i = mod(((send_row_indices(i) - 1)/nrow_block_dest), dest_num_pe(1))
1186 mpi_rank = dest_blacs2mpi(dest_p_i, dest_q_j)
1187 send_count(mpi_rank) = send_count(mpi_rank) + 1
1188 info%send_buf(send_disp(mpi_rank) + send_count(mpi_rank)) = source%local_data(i, j)
1189 END DO
1190 END DO
1191
1192 ! For each non-zero send_count, call mpi_isend
1193 DO k = 0, recv_size - 1
1194 IF (send_count(k) > 0) THEN
1195 CALL para_env%isend(info%send_buf(send_disp(k) + 1:send_disp(k) + send_count(k)), &
1196 dest2global(k), info%send_request(k))
1197 ELSE
1198 info%send_request(k) = mp_request_null
1199 END IF
1200 END DO
1201 DEALLOCATE (send_count, send_disp, dest2global)
1202 END IF ! ASSOCIATED(source)
1203 DEALLOCATE (dest_blacs2mpi)
1204
1205 END IF !IF (.NOT. cp2k_is_parallel)
1206
1207 CALL timestop(handle)
1208
1209 END SUBROUTINE cp_cfm_start_copy_general
1210
1211! **************************************************************************************************
1212!> \brief Complete the copy operation: wait for comms, unpack, clean up MPI state.
1213!> \param destination output cfm matrix
1214!> \param info all of the data that will be needed to complete the copy operation
1215!> \note a slightly modified version of the subroutine cp_fm_finish_copy_general() that uses
1216!> allocatable arrays instead of pointers wherever possible.
1217! **************************************************************************************************
1218 SUBROUTINE cp_cfm_finish_copy_general(destination, info)
1219 TYPE(cp_cfm_type), INTENT(IN) :: destination
1220 TYPE(copy_cfm_info_type), INTENT(inout) :: info
1221
1222 CHARACTER(len=*), PARAMETER :: routinen = 'cp_cfm_finish_copy_general'
1223
1224 INTEGER :: handle, i, j, k, mpi_rank, ni, nj, &
1225 src_q_j
1226 INTEGER, ALLOCATABLE, DIMENSION(:) :: recv_count, src_p_i
1227 INTEGER, DIMENSION(:), POINTER :: recv_col_indices, recv_row_indices
1228
1229 CALL timeset(routinen, handle)
1230
1231 IF (.NOT. cp2k_is_parallel) THEN
1232 ! Now unpack the data from the 'send buffer'
1233 k = 0
1234 DO j = 1, SIZE(destination%local_data, 2)
1235 DO i = 1, SIZE(destination%local_data, 1)
1236 k = k + 1
1237 destination%local_data(i, j) = info%send_buf(k)
1238 END DO
1239 END DO
1240 DEALLOCATE (info%send_buf)
1241 ELSE
1242 ! Set up local variables ...
1243 recv_col_indices => info%recv_col_indices
1244 recv_row_indices => info%recv_row_indices
1245
1246 ! ... use the local variables to do the work
1247 ! DEST_2
1248 CALL mp_waitall(info%recv_request(:))
1249
1250 nj = info%nlocal_recv(2)
1251 ni = info%nlocal_recv(1)
1252 ALLOCATE (recv_count(0:info%send_size - 1), src_p_i(ni))
1253 ! Loop over the rmat, filling it in with data from the recv buffers
1254 ! (here the block sizes, num_pes refer to the distribution of the source matrix)
1255 recv_count(:) = 0
1256 DO i = 1, ni
1257 src_p_i(i) = mod(((recv_row_indices(i) - 1)/info%nblock_src(1)), info%src_num_pe(1))
1258 END DO
1259
1260 DO j = 1, nj
1261 src_q_j = mod(((recv_col_indices(j) - 1)/info%nblock_src(2)), info%src_num_pe(2))
1262 DO i = 1, ni
1263 mpi_rank = info%src_blacs2mpi(src_p_i(i), src_q_j)
1264 recv_count(mpi_rank) = recv_count(mpi_rank) + 1
1265 destination%local_data(i, j) = info%recv_buf(info%recv_disp(mpi_rank) + recv_count(mpi_rank))
1266 END DO
1267 END DO
1268
1269 DEALLOCATE (recv_count, src_p_i)
1270 ! Invalidate the stored state
1271 NULLIFY (info%recv_col_indices, info%recv_row_indices)
1272 DEALLOCATE (info%recv_disp, info%recv_request, info%recv_buf, info%src_blacs2mpi)
1273 END IF
1274
1275 CALL timestop(handle)
1276
1277 END SUBROUTINE cp_cfm_finish_copy_general
1278
1279! **************************************************************************************************
1280!> \brief Complete the copy operation: wait for comms clean up MPI state.
1281!> \param info all of the data that will be needed to complete the copy operation
1282!> \note a slightly modified version of the subroutine cp_fm_cleanup_copy_general() that uses
1283!> allocatable arrays instead of pointers wherever possible.
1284! **************************************************************************************************
1286 TYPE(copy_cfm_info_type), INTENT(inout) :: info
1287
1288 CHARACTER(len=*), PARAMETER :: routinen = 'cp_cfm_cleanup_copy_general'
1289
1290 INTEGER :: handle
1291
1292 CALL timeset(routinen, handle)
1293
1294 IF (cp2k_is_parallel) THEN
1295 ! SRC_2
1296 ! If this process is also in the destination decomposition, this deallocate
1297 ! Was already done in cp_fm_finish_copy_general
1298 IF (ALLOCATED(info%src_blacs2mpi)) DEALLOCATE (info%src_blacs2mpi)
1299 CALL mp_waitall(info%send_request(:))
1300 DEALLOCATE (info%send_request, info%send_buf)
1301 END IF
1302
1303 CALL timestop(handle)
1304 END SUBROUTINE cp_cfm_cleanup_copy_general
1305END MODULE cp_cfm_types
methods related to the blacs parallel environment
Represents a complex full matrix distributed on many processors.
subroutine, public cp_cfm_get_submatrix(fm, target_m, start_row, start_col, n_rows, n_cols, transpose)
Extract a sub-matrix from the full matrix: op(target_m)(1:n_rows,1:n_cols) = fm(start_row:start_row+n...
subroutine, public cp_cfm_get_element(matrix, irow_global, icol_global, alpha)
Get the matrix element by its global index.
subroutine, public cp_cfm_release(matrix)
Releases a full matrix.
subroutine, public cp_cfm_set_element(matrix, irow_global, icol_global, alpha)
Set the matrix element (irow_global,icol_global) of the full matrix to alpha.
subroutine, public cp_cfm_start_copy_general(source, destination, para_env, info)
Initiate the copy operation: get distribution data, post MPI isend and irecvs.
subroutine, public cp_fm_to_cfm(msourcer, msourcei, mtarget)
Construct a complex full matrix by taking its real and imaginary parts from two separate real-value f...
subroutine, public cp_cfm_create(matrix, matrix_struct, name, nrow, ncol, set_zero)
Creates a new full matrix with the given structure.
subroutine, public cp_cfm_cleanup_copy_general(info)
Complete the copy operation: wait for comms clean up MPI state.
subroutine, public cp_cfm_get_info(matrix, name, nrow_global, ncol_global, nrow_block, ncol_block, nrow_local, ncol_local, row_indices, col_indices, local_data, context, matrix_struct, para_env)
Returns information about a full matrix.
subroutine, public cp_cfm_set_submatrix(matrix, new_values, start_row, start_col, n_rows, n_cols, alpha, beta, transpose)
Set a sub-matrix of the full matrix: matrix(start_row:start_row+n_rows,start_col:start_col+n_cols) = ...
subroutine, public cp_cfm_set_all(matrix, alpha, beta)
Set all elements of the full matrix to alpha. Besides, set all diagonal matrix elements to beta (if g...
subroutine, public cp_cfm_to_fm(msource, mtargetr, mtargeti)
Copy real and imaginary parts of a complex full matrix into separate real-value full matrices.
subroutine, public cp_cfm_finish_copy_general(destination, info)
Complete the copy operation: wait for comms, unpack, clean up MPI state.
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_get(fmstruct, para_env, context, descriptor, ncol_block, nrow_block, nrow_global, ncol_global, first_p_pos, row_indices, col_indices, nrow_local, ncol_local, nrow_locals, ncol_locals, local_leading_dimension)
returns the values of various attributes of the matrix structure
logical function, public cp_fm_struct_equivalent(fmstruct1, fmstruct2)
returns true if the two matrix structures are equivalent, false otherwise.
subroutine, public cp_fm_struct_retain(fmstruct)
retains 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
Defines the basic variable types.
Definition kinds.F:23
integer, parameter, public dp
Definition kinds.F:34
Definition of mathematical constants and functions.
complex(kind=dp), parameter, public z_one
complex(kind=dp), parameter, public z_zero
Interface to the message passing library MPI.
integer, parameter, public mp_proc_null
logical, parameter, public cp2k_is_parallel
integer, parameter, public mp_any_source
type(mp_request_type), parameter, public mp_request_null
represent a blacs multidimensional parallel environment (for the mpi corrispective see cp_paratypes/m...
Stores the state of a copy between cp_cfm_start_copy_general and cp_cfm_finish_copy_general.
Just to build arrays of pointers to matrices.
Represent a complex full matrix.
keeps the information about the structure of a full matrix
represent a full matrix
stores all the informations relevant to an mpi environment