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