Branch data Line data Source code
1 : : !!****m* ABINIT/m_slk
2 : : !! NAME
3 : : !! m_slk
4 : : !!
5 : : !! FUNCTION
6 : : !! High-level objects and wrappers around the ScaLAPACK and ELPA API.
7 : : !!
8 : : !! COPYRIGHT
9 : : !! Copyright (C) 2004-2026 ABINIT group (CS,GZ,FB,MG,MT)
10 : : !! This file is distributed under the terms of the
11 : : !! GNU General Public License, see ~abinit/COPYING
12 : : !! or http://www.gnu.org/copyleft/gpl.txt .
13 : : !!
14 : : !! TODO
15 : : !! Provide fallbacks for sequential version (No scalapack) so that we can implement generic high-level algorithms.
16 : : !!
17 : : !! SOURCE
18 : :
19 : : #if defined HAVE_CONFIG_H
20 : : #include "config.h"
21 : : #endif
22 : :
23 : : #include "abi_common.h"
24 : :
25 : : module m_slk
26 : :
27 : : use, intrinsic :: iso_c_binding
28 : : use defs_basis
29 : : USE_MPI
30 : : use m_xmpi
31 : : use m_xomp
32 : : use m_errors
33 : : use m_abicore
34 : : use m_gputk
35 : : #ifdef HAVE_LINALG_ELPA
36 : : use m_elpa
37 : : #endif
38 : :
39 : : use m_fstrings, only : firstchar, toupper, itoa, sjoin, ltoa, string_in
40 : : use m_time, only : cwtime, cwtime_report
41 : : !use m_numeric_tools, only : blocked_loop !, print_arr
42 : :
43 : : implicit none
44 : :
45 : : #ifdef HAVE_MPI1
46 : : include 'mpif.h'
47 : : #endif
48 : :
49 : : private
50 : :
51 : : ! scaLAPACK array descriptor.
52 : : integer,private,parameter :: DLEN_ = 9 ! length
53 : : integer,private,parameter :: Dtype_ = 1 ! type
54 : : integer,private,parameter :: CTXT_ = 2 ! BLACS context
55 : : integer,private,parameter :: M_ = 3 ! nb global lines
56 : : integer,private,parameter :: N_ = 4 ! nb global columns
57 : : integer,private,parameter :: MB_ = 5 ! nb lines of a block
58 : : integer,private,parameter :: NB_ = 6 ! nb columns of a block
59 : : integer,private,parameter :: RSRC_ = 7 ! line of processors at the beginning
60 : : integer,private,parameter :: CSRC_ = 8 ! column of processors at the beginning
61 : : integer,private,parameter :: LLD_ = 9 ! local number of lines
62 : : !!***
63 : :
64 : : !----------------------------------------------------------------------
65 : :
66 : : !!****t* m_slk/slk_grid_t
67 : : !! NAME
68 : : !! slk_grid_t
69 : : !!
70 : : !! FUNCTION
71 : : !! Grid of ScaLAPACK processors.
72 : : !!
73 : : !! SOURCE
74 : :
75 : : type,public :: slk_grid_t
76 : :
77 : : integer :: nprocs = -1
78 : : ! Total number of processors
79 : :
80 : : integer :: dims(2) = -1
81 : : ! Number of procs for rows/columns
82 : :
83 : : integer :: comm = xmpi_comm_null
84 : : ! BLACS context i.e. MPI communicator.
85 : :
86 : : logical :: use_gpu = .false.
87 : : ! Wether GPU is used, relevant for determining matrix block size.
88 : :
89 : : contains
90 : : procedure :: init => slk_grid_init ! Set up the processor grid for ScaLAPACK.
91 : : end type slk_grid_t
92 : : !!***
93 : :
94 : : !----------------------------------------------------------------------
95 : :
96 : : !!****t* m_slk/slk_processor_t
97 : : !! NAME
98 : : !! slk_processor_t
99 : : !!
100 : : !! FUNCTION
101 : : !! One processor in the grid.
102 : : !!
103 : : !! SOURCE
104 : :
105 : : type,public :: slk_processor_t
106 : :
107 : : integer :: my_rank = -1
108 : : ! rank of the processor in comm
109 : :
110 : : integer :: comm = xmpi_comm_null
111 : : ! MPI communicator underlying the BLACS grid.
112 : :
113 : : integer :: coords(2) = -1
114 : : ! Coordinates of the processor in the grid.
115 : :
116 : : type(slk_grid_t) :: grid
117 : : ! the grid to which the processor is associated to.
118 : :
119 : : contains
120 : : procedure :: init => slk_processor_init ! Initializes an instance of processor ScaLAPACK from a MPI communicator.
121 : : procedure :: free => slk_processor_free ! Free the object
122 : : end type slk_processor_t
123 : : !!***
124 : :
125 : : !----------------------------------------------------------------------
126 : :
127 : : !!****t* m_slk/basemat_t
128 : : !! NAME
129 : : !! basemat_t
130 : : !!
131 : : !! FUNCTION
132 : : !! Base class for scalapack matrices.
133 : : !! Methods that are agnostic about type and precision or methods that can handle both
134 : : !! single and double precision, real and complex arrays via `select type` should be defined here.
135 : : !!
136 : : !! SOURCE
137 : :
138 : : type, private :: basemat_t
139 : :
140 : : integer :: size_local(2) = -1
141 : : ! dimensions of the local buffer.
142 : :
143 : : integer(c_size_t) :: bufsize = -1
144 : : ! Size of the local buffer.
145 : :
146 : : integer :: size_global(2) = -1
147 : : ! dimensions of the global matrix.
148 : :
149 : : integer :: size_blocs(2) = -1
150 : : ! size of the block of consecutive data
151 : :
152 : : integer :: istwf_k = -1
153 : :
154 : : type(slk_processor_t),pointer :: processor => null()
155 : :
156 : : integer :: desc(DLEN_)
157 : : ! Scalapack descriptor.
158 : :
159 : : contains
160 : :
161 : : procedure :: init => basemat_init
162 : : ! Basic Constructor
163 : :
164 : : procedure :: glob2loc => basemat_glob2loc
165 : : ! Determine the local indices of an element from its global indices and return haveit bool flag.
166 : :
167 : : procedure :: loc2glob => basemat_loc2glob
168 : : ! Return global indices of a matrix element from the local indices.
169 : :
170 : : procedure :: loc2grow => basemat_loc2grow
171 : : ! Determine the global row index from the local index
172 : :
173 : : procedure :: loc2gcol => basemat_loc2col
174 : : ! Determine the global column index from the local index
175 : :
176 : : procedure :: idx_loc => basemat_idx_loc
177 : : ! Local indices of an entry
178 : : ! from its global indices, independently of the processor.
179 : :
180 : : procedure :: locmem_mb => basemat_locmem_mb
181 : : ! Return memory allocated for the local buffer in Mb.
182 : :
183 : : procedure :: print => basemat_print
184 : : ! Print info on the object.
185 : :
186 : : procedure :: check_local_shape => basemat_check_local_shape
187 : : ! Debugging tool to test the local shape `lshape` of the local buffer.
188 : :
189 : : procedure :: is_gpu_mapped => basemat_is_gpu_mapped
190 : : ! True if the local buffer is mapped to the GPU.
191 : :
192 : : procedure :: gpu_map => basemat_gpu_map
193 : : ! Use Opemp to allocate/delete the local buffer on the GPU.
194 : :
195 : : procedure :: gpu_set_zero => basemat_gpu_set_zero
196 : : ! Fill the local buffer on the GPU with zeros.
197 : :
198 : : procedure :: free => basemat_free
199 : : ! Free memory
200 : :
201 : : procedure :: change_size_blocs => basemat_change_size_blocs
202 : : ! Change the block sizes, return new object.
203 : :
204 : : procedure :: get_trace => basemat_get_trace
205 : : ! Compute the trace of an N-by-N distributed matrix.
206 : :
207 : : procedure :: set_imag_diago_to_zero => basemat_set_imag_diago_to_zero
208 : : ! Set the imaginary part of the diagonal to zero.
209 : :
210 : : procedure :: invert => basemat_invert
211 : : ! Inverse of a complex matrix.
212 : :
213 : : end type basemat_t
214 : : !!***
215 : :
216 : : !----------------------------------------------------------------------
217 : :
218 : : !!****t* m_slk/slkmat_dp_t
219 : : !! NAME
220 : : !! slkmat_dp_t
221 : : !!
222 : : !! FUNCTION
223 : : !! high-level interface to ScaLAPACK matrix (double precision version)
224 : : !!
225 : : !! SOURCE
226 : :
227 : : type, public, extends(basemat_t) :: slkmat_dp_t
228 : :
229 : : real(dp),allocatable :: buffer_real(:,:)
230 : : ! local part of the (real) matrix.
231 : : ! The istwf_k option passed to the constructor defines whether we have a real or complex matrix
232 : :
233 : : complex(dpc),allocatable :: buffer_cplx(:,:)
234 : : ! local part of the (complex) matrix
235 : :
236 : : contains
237 : :
238 : : procedure :: get_head_and_wings => slkmat_dp_get_head_and_wings
239 : : ! Return global arrays with the head and the wings of the matrix.
240 : :
241 : : procedure :: set_head_and_wings => slkmat_dp_set_head_and_wings
242 : : ! Set head and the wings of the matrix starting from global arrays.
243 : :
244 : : procedure :: copy => slkmat_dp_copy
245 : : ! Copy object
246 : :
247 : : procedure :: hpd_invert => slkmat_dp_hpd_invert
248 : : ! Inverse of a Hermitian positive definite matrix.
249 : :
250 : : procedure :: ptrans => slkmat_dp_ptrans
251 : : ! Transpose matrix
252 : :
253 : : procedure :: cut => slkmat_dp_cut
254 : : ! Extract submatrix and create new matrix with `size_blocs` and `processor`
255 : :
256 : : procedure :: take_from => slkmat_dp_take_from
257 : : ! Take values from source
258 : :
259 : : procedure :: collect_cplx => slkmat_dp_collect_cplx
260 : : ! Return on all processors the submatrix of shape (mm, nn) starting at position ija.
261 : :
262 : : procedure :: heev => slkmat_dp_heev
263 : : ! Compute eigenvalues and, optionally, eigenvectors of an Hermitian matrix A. A * X = lambda * X
264 : :
265 : : procedure :: pzheevx => slkmat_dp_pzheevx
266 : : ! Compute Eigenvalues and, optionally, eigenvectors of a complex Hermitian matrix A. ! A * X = lambda * X
267 : :
268 : : procedure :: pzhegvx => slkmat_dp_pzhegvx
269 : : ! Eigenvalues and, optionally, eigenvectors of a complex
270 : : ! generalized Hermitian-definite eigenproblem, of the form
271 : : ! sub( A )*x=(lambda)*sub( B )*x, sub( A )*sub( B )x=(lambda)*x,
272 : : ! or sub( B )*sub( A )*x=(lambda)*x.
273 : :
274 : : procedure :: symmetrize => slkmat_dp_symmetrize
275 : : ! Symmetrizes a square scaLAPACK matrix.
276 : :
277 : : procedure :: bsize_and_type => slkmat_dp_bsize_and_type
278 : : ! Returns the byte size and the MPI datatype
279 : :
280 : : procedure :: svd => slkmat_dp_svd
281 : : ! Singular Value Decomposition (double precision version).
282 : :
283 : : procedure :: to_global => slkmat_dp_to_global
284 : : ! Fill a full matrix with respect to a SCALAPACK matrix.
285 : :
286 : : procedure :: from_real_glob => slkmat_dp_from_real_glob
287 : : ! Fills SCALAPACK matrix from full matrix.
288 : :
289 : : procedure :: from_global_pack => slkmat_dp_from_global_pack
290 : : ! Fills SCALAPACK matrix from full matrix.
291 : :
292 : : procedure :: from_global_sym => slkmat_dp_from_global_sym
293 : : ! Fills SCALAPACK matrix from full matrix.
294 : :
295 : : procedure :: to_global_pack => slkmat_dp_to_global_pack
296 : : ! Inserts a ScaLAPACK matrix into a global one.
297 : :
298 : : procedure :: to_real_glob => slkmat_dp_to_real_glob
299 : : ! Inserts a ScaLAPACK matrix into a real matrix.
300 : :
301 : : procedure :: to_complex_glob => slkmat_dp_to_complex_glob
302 : : ! Inserts a ScaLAPACK matrix into a complex matrix.
303 : :
304 : : procedure :: from_complex_glob => slkmat_dp_from_complex_glob
305 : : ! Fills SCALAPACK matrix from a full matrix.
306 : :
307 : : end type slkmat_dp_t
308 : : !!***
309 : :
310 : : !!****t* m_slk/slkmat_sp_t
311 : : !! NAME
312 : : !! slkmat_sp_t
313 : : !!
314 : : !! FUNCTION
315 : : !! High-level interface to ScaLAPACK matrix (single precision version).
316 : : !!
317 : : !! SOURCE
318 : :
319 : : type, public, extends(basemat_t) :: slkmat_sp_t
320 : :
321 : : real(sp),allocatable :: buffer_real(:,:)
322 : : ! local part of the (real) matrix.
323 : : ! The istwf_k option passed to the constructor defines whether we have a real or complex matrix
324 : :
325 : : complex(sp),allocatable :: buffer_cplx(:,:)
326 : : ! local part of the (complex) matrix
327 : :
328 : : contains
329 : :
330 : : procedure :: copy => slkmat_sp_copy
331 : : ! Copy object
332 : :
333 : : procedure :: take_from => slkmat_sp_take_from
334 : : ! Take values from source
335 : :
336 : : procedure :: ptrans => slkmat_sp_ptrans
337 : : ! Transpose matrix
338 : :
339 : : procedure :: set_head_and_wings => slkmat_sp_set_head_and_wings
340 : : ! Set head and the wings of the matrix starting from global arrays.
341 : :
342 : : procedure :: cut => slkmat_sp_cut
343 : : ! Extract submatrix and create new matrix with `size_blocs` and `processor`
344 : :
345 : : procedure :: collect_cplx => slkmat_sp_collect_cplx
346 : : ! Return on all processors the submatrix of shape (mm, nn) starting at position ija.
347 : :
348 : : procedure :: heev => slkmat_sp_heev
349 : : ! Compute eigenvalues and, optionally, eigenvectors of an Hermitian matrix A. A * X = lambda * X
350 : :
351 : : procedure :: hpd_invert => slkmat_sp_hpd_invert
352 : : ! Inverse of a Hermitian positive definite matrix.
353 : :
354 : : procedure :: svd => slkmat_sp_svd
355 : : ! Singular Value Decomposition (single precision version).
356 : :
357 : : end type slkmat_sp_t
358 : : !!***
359 : :
360 : : public :: block_dist_1d ! Return block size for one-dimensional block column/row distribution
361 : : public :: slk_has_elpa ! Return True if ELPA support is activated
362 : :
363 : : ! ???
364 : : public :: matrix_get_local_cplx ! Return a local matrix coefficient of complex type.
365 : : public :: matrix_get_local_real ! Return a local matrix coefficient of double precision type.
366 : : public :: matrix_set_local_cplx ! Sets a local matrix coefficient of complex type.
367 : : public :: matrix_set_local_real ! Sets a local matrix coefficient of double precision type.
368 : : ! ???
369 : :
370 : : public :: slk_matrix_from_global_dpc_2D ! Fill a complex SCALAPACK matrix with respect to a global matrix.
371 : : public :: slk_matrix_from_global_dpc_1Dp ! Fill a complex SCALAPACK matrix with respect to a global matrix.
372 : : ! target: double precision complex matrix in packed form.
373 : : public :: slk_matrix_to_global_dpc_2D ! Fill a global matrix with respect to a SCALAPACK matrix.
374 : : ! target: Two-dimensional Double precision complex matrix.
375 : :
376 : : public :: slk_pgemm ! Compute: C := alpha*A*B + beta*C
377 : : interface slk_pgemm
378 : : module procedure slk_pgemm_dp
379 : : module procedure slk_pgemm_sp
380 : : end interface slk_pgemm
381 : :
382 : :
383 : : public :: compute_eigen_problem ! Compute eigenvalues and eigenvectors of: A * X = lambda * X.
384 : : ! complex and real cases.
385 : : public :: compute_generalized_eigen_problem ! Compute generalized eigenvalue problem
386 : : public :: compute_eigen1 ! Compute eigenvalues and eigenvectors. complex and real cases.
387 : : public :: compute_eigen2 ! Compute eigenvalues and eigenvectors: A * X = lambda * B * X
388 : : ! complex and real cases.
389 : :
390 : : public :: slk_write ! Writes a square scaLAPACK distributed matrix on an external file using MPI-IO.
391 : : public :: slk_read ! Read a square scaLAPACK distributed matrix from an external file using MPI-IO.
392 : : public :: slk_single_fview_read_mask ! Returns an MPI datatype that can be used to read a scaLAPACK matrix from
393 : : ! a binary file using MPI-IO.
394 : : ! The view is created using the user-defined mask function
395 : : public :: slk_single_fview_read ! Returns an MPI datatype to read a scaLAPACK distributed matrix
396 : : ! from a binary file using MPI-IO.
397 : : public :: slk_single_fview_write ! Returns an MPI datatype to write a scaLAPACK distributed matrix
398 : : ! to a binary file using MPI-IO.
399 : :
400 : : public :: slk_array_free ! Deallocate array of slkmat_dp_t elements
401 : : interface slk_array_free
402 : : module procedure slk_array1_free
403 : : module procedure slk_array2_free
404 : : module procedure slk_array3_free
405 : : module procedure slk_array4_free
406 : : module procedure slk_array5_free
407 : : end interface slk_array_free
408 : :
409 : : public :: slk_array_set_zero ! Elemental routine to zero the value of the local buffer.
410 : : public :: slk_array_locmem_mb ! Compute memory allocated for an array of slkmat_dp_t elements
411 : :
412 : : public :: slk_array_gpu_set_zero ! Zero the value of the local buffer on the GPU
413 : : interface slk_array_gpu_set_zero
414 : : module procedure slk_array1_gpu_set_zero
415 : : module procedure slk_array2_gpu_set_zero
416 : : module procedure slk_array3_gpu_set_zero
417 : : module procedure slk_array4_gpu_set_zero
418 : : module procedure slk_array5_gpu_set_zero
419 : : end interface slk_array_gpu_set_zero
420 : :
421 : : ! External functions.
422 : : #if defined(HAVE_LINALG_SCALAPACK) || defined(HAVE_LINALG_ELPA)
423 : : integer,external :: indxl2g, numroc
424 : : real(dp),external :: PDLAMCH
425 : : real(dp),external :: PDLATRA
426 : : real(sp),external :: PSLATRA
427 : : complex(sp),external :: PCLATRA
428 : : complex(dp),external :: PZLATRA
429 : : #endif
430 : :
431 : : #ifdef HAVE_LINALG_SLATE
432 : :
433 : : interface
434 : : ! Standard complex Hermitian: A * Z = Z * diag(w)
435 : : subroutine slate_zheev_c(n, nb, nprow, npcol, comm_f, &
436 : : lda, a_data, ldz, z_data, w, nev, use_gpu, info) &
437 : : bind(C, name="slate_zheev_c")
438 : : use, intrinsic :: iso_c_binding
439 : : integer(c_int), value :: n, nb, nprow, npcol, comm_f, lda, ldz, nev, use_gpu
440 : : complex(c_double_complex), intent(inout) :: a_data(*)
441 : : complex(c_double_complex), intent(out) :: z_data(*)
442 : : real(c_double), intent(out) :: w(*)
443 : : integer(c_int), intent(out) :: info
444 : : end subroutine slate_zheev_c
445 : :
446 : : ! Standard real symmetric: A * Z = Z * diag(w)
447 : : subroutine slate_dsyev_c(n, nb, nprow, npcol, comm_f, &
448 : : lda, a_data, ldz, z_data, w, nev, use_gpu, info) &
449 : : bind(C, name="slate_dsyev_c")
450 : : use, intrinsic :: iso_c_binding
451 : : integer(c_int), value :: n, nb, nprow, npcol, comm_f, lda, ldz, nev, use_gpu
452 : : real(c_double), intent(inout) :: a_data(*)
453 : : real(c_double), intent(out) :: z_data(*)
454 : : real(c_double), intent(out) :: w(*)
455 : : integer(c_int), intent(out) :: info
456 : : end subroutine slate_dsyev_c
457 : :
458 : : ! Generalised complex Hermitian: A * Z = B * Z * diag(w)
459 : : subroutine slate_zhegv_c(n, nb, nprow, npcol, comm_f, &
460 : : lda, a_data, ldb, b_data, ldz, z_data, &
461 : : w, nev, use_gpu, info) &
462 : : bind(C, name="slate_zhegv_c")
463 : : use, intrinsic :: iso_c_binding
464 : : integer(c_int), value :: n, nb, nprow, npcol, comm_f
465 : : integer(c_int), value :: lda, ldb, ldz, nev, use_gpu
466 : : complex(c_double_complex), intent(inout) :: a_data(*), b_data(*)
467 : : complex(c_double_complex), intent(out) :: z_data(*)
468 : : real(c_double), intent(out) :: w(*)
469 : : integer(c_int), intent(out) :: info
470 : : end subroutine slate_zhegv_c
471 : :
472 : : ! Generalised real symmetric: A * Z = B * Z * diag(w)
473 : : subroutine slate_dsygv_c(n, nb, nprow, npcol, comm_f, &
474 : : lda, a_data, ldb, b_data, ldz, z_data, &
475 : : w, nev, use_gpu, info) &
476 : : bind(C, name="slate_dsygv_c")
477 : : use, intrinsic :: iso_c_binding
478 : : integer(c_int), value :: n, nb, nprow, npcol, comm_f
479 : : integer(c_int), value :: lda, ldb, ldz, nev, use_gpu
480 : : real(c_double), intent(inout) :: a_data(*), b_data(*)
481 : : real(c_double), intent(out) :: z_data(*)
482 : : real(c_double), intent(out) :: w(*)
483 : : integer(c_int), intent(out) :: info
484 : : end subroutine slate_dsygv_c
485 : :
486 : : end interface
487 : :
488 : : #endif
489 : :
490 : : contains !==============================================================================
491 : : !!***
492 : :
493 : : !!****f* m_slk/slk_grid_init
494 : : !! NAME
495 : : !! slk_grid_init
496 : : !!
497 : : !! FUNCTION
498 : : !! Set up the ScaLAPACK grid given the total number of processors.
499 : : !!
500 : : !! INPUTS
501 : : !! nprocs= total number of processors
502 : : !! comm= MPI communicator
503 : : !! [grid_dims]=Number of procs for each dimension.
504 : : !!
505 : : !! OUTPUT
506 : : !! grid= the grid of processors used by Scalapack
507 : : !!
508 : : !! SOURCE
509 : :
510 [ # # ]: 0 : subroutine slk_grid_init(grid, nprocs, comm, use_gpu, grid_dims)
511 : :
512 : : !Arguments ------------------------------------
513 : : class(slk_grid_t),intent(out) :: grid
514 : : integer,intent(in) :: nprocs,comm
515 : : logical,intent(in) :: use_gpu
516 : : integer,optional,intent(in) :: grid_dims(2)
517 : :
518 : : !Local variables-------------------------------
519 : : integer :: i
520 : : ! *********************************************************************
521 : :
522 : 0 : grid%nprocs = nprocs
523 : :
524 [ # # ]: 0 : if (.not. present(grid_dims)) then
525 : : ! Search for a rectangular grid of processors
526 : 0 : i=INT(SQRT(float(nprocs)))
527 [ # # ]: 0 : do while (MOD(nprocs,i) /= 0)
528 : 0 : i = i-1
529 : : end do
530 : 0 : i=max(i,1)
531 : :
532 : 0 : grid%dims(1) = i
533 : 0 : grid%dims(2) = INT(nprocs/i)
534 : :
535 : : else
536 [ # # ]: 0 : grid%dims = grid_dims
537 : : end if
538 : :
539 [ # # # # ]: 0 : ABI_CHECK(product(grid%dims) == nprocs, sjoin("grid%dims:", ltoa(grid%dims), "does not agree with nprocs:", itoa(nprocs)))
540 : :
541 : 0 : grid%comm = comm
542 : 0 : grid%use_gpu = use_gpu
543 : :
544 : : #ifdef HAVE_LINALG_SCALAPACK
545 : : ! 'R': Use row-major natural ordering
546 : : call BLACS_GRIDINIT(grid%comm, 'R', grid%dims(1), grid%dims(2))
547 : : #endif
548 : :
549 : 0 : end subroutine slk_grid_init
550 : : !!***
551 : :
552 : : !----------------------------------------------------------------------
553 : :
554 : : !!****f* m_slk/build_processor
555 : : !! NAME
556 : : !! build_processor
557 : : !!
558 : : !! FUNCTION
559 : : !! Builds a ScaLAPACK processor descriptor.
560 : : !! Build of the data related to one processor in a grid
561 : : !!
562 : : !! INPUTS
563 : : !! grid= array representing the grid of processors.
564 : : !! my_rank= selected processor
565 : : !! comm= MPI communicator
566 : : !!
567 : : !! OUTPUT
568 : : !! processor= descriptor of a processor
569 : : !!
570 : : !! SOURCE
571 : :
572 : 0 : subroutine build_processor(processor, grid, my_rank, comm)
573 : :
574 : : !Arguments ------------------------------------
575 : : class(slk_processor_t),intent(inout) :: processor
576 : : class(slk_grid_t),intent(in) :: grid
577 : : integer,intent(in) :: my_rank, comm
578 : : ! *********************************************************************
579 : :
580 : 0 : processor%grid = grid
581 : 0 : processor%my_rank = my_rank
582 : 0 : processor%comm = comm
583 : :
584 : : #ifdef HAVE_LINALG_SCALAPACK
585 : : call BLACS_GRIDINFO(grid%comm, processor%grid%dims(1), processor%grid%dims(2), &
586 : : processor%coords(1), processor%coords(2))
587 : : #endif
588 : :
589 : : ! These values are the same as those computed by BLACS_GRIDINFO
590 : : ! except in the case where the my_rank argument is not the local proc
591 : 0 : processor%coords(1) = INT((my_rank) / grid%dims(2))
592 : 0 : processor%coords(2) = MOD((my_rank), grid%dims(2))
593 : :
594 : : end subroutine build_processor
595 : : !!***
596 : :
597 : : !----------------------------------------------------------------------
598 : :
599 : : !!****f* m_slk/slk_processor_init
600 : : !! NAME
601 : : !! slk_processor_init
602 : : !!
603 : : !! FUNCTION
604 : : !! Initializes an instance of processor ScaLAPACK from an MPI communicator.
605 : : !!
606 : : !! INPUTS
607 : : !! comm= MPI communicator
608 : : !! [grid_dims]=Number of procs for each dimension.
609 : : !!
610 : : !! OUTPUT
611 : : !! processor= descriptor of a processor
612 : : !!
613 : : !! SOURCE
614 : :
615 : 0 : subroutine slk_processor_init(processor, comm, &
616 : : grid_dims) ! optional
617 : :
618 : : !Arguments ------------------------------------
619 : : class(slk_processor_t),intent(out) :: processor
620 : : integer, intent(in) :: comm
621 : : integer,optional,intent(in) :: grid_dims(2)
622 : :
623 : : !Local variables-------------------------------
624 : : type(slk_grid_t) :: grid
625 : : integer :: nprocs, my_rank
626 : : ! *********************************************************************
627 : :
628 : 0 : nprocs = xmpi_comm_size(comm)
629 : 0 : my_rank = xmpi_comm_rank(comm)
630 : :
631 [ # # ]: 0 : if (present(grid_dims)) then
632 : 0 : call grid%init(nprocs, comm, .false., grid_dims=grid_dims)
633 : : else
634 : 0 : call grid%init(nprocs, comm, .false.)
635 : : end if
636 : :
637 : 0 : call build_processor(processor, grid, my_rank, comm)
638 : :
639 [ # # # # ]: 0 : end subroutine slk_processor_init
640 : : !!***
641 : :
642 : : !----------------------------------------------------------------------
643 : :
644 : : !!****f* m_slk/slk_processor_free
645 : : !! NAME
646 : : !! slk_processor_free
647 : : !!
648 : : !! FUNCTION
649 : : !! Removes a processor from the ScaLAPACK grid.
650 : : !!
651 : : !! SOURCE
652 : :
653 : 0 : subroutine slk_processor_free(processor)
654 : :
655 : : !Arguments ------------------------------------
656 : : class(slk_processor_t),intent(inout) :: processor
657 : : ! *********************************************************************
658 : :
659 : : #ifdef HAVE_LINALG_SCALAPACK
660 : : if (processor%grid%comm /= xmpi_comm_null) then
661 : : call BLACS_GRIDEXIT(processor%grid%comm)
662 : : !call BLACS_EXIT(0)
663 : : end if
664 : : #endif
665 : :
666 : 0 : end subroutine slk_processor_free
667 : : !!***
668 : :
669 : : !----------------------------------------------------------------------
670 : :
671 : : !!****f* m_slk/basemat_init
672 : : !! NAME
673 : : !! basemat_init
674 : : !!
675 : : !! FUNCTION
676 : : !! Initialisation of a SCALAPACK matrix (each proc initializes its own part of the matrix)
677 : : !!
678 : : !! INPUTS
679 : : !! processor= descriptor of a processor
680 : : !! nbli_global= total number of lines
681 : : !! nbco_global= total number of columns
682 : : !! istwf_k= 2 if we have a real matrix else complex.
683 : : !! [size_blocs]= custom block sizes. Use -1 to use global size along that direction.
684 : : !! Useful to distribute only rows or columns. Obviously, [-1, -1] is not allowed.
685 : : !!
686 : : !! OUTPUT
687 : : !! matrix= the matrix to process
688 : : !!
689 : : !! SOURCE
690 : :
691 : 0 : subroutine basemat_init(matrix, nbli_global, nbco_global, processor, istwf_k, &
692 : : size_blocs, gpu_action) ! optional
693 : :
694 : : !Arguments ------------------------------------
695 : : class(basemat_t),intent(inout) :: matrix
696 : : integer,intent(in) :: nbli_global, nbco_global, istwf_k
697 : : type(slk_processor_t),target,intent(in) :: processor
698 : : integer,optional,intent(in) :: size_blocs(2)
699 : : character(len=*),optional,intent(in) :: gpu_action
700 : :
701 : : #ifdef HAVE_LINALG_SCALAPACK
702 : : !Local variables-------------------------------
703 : : #ifdef HAVE_LINALG_ELPA
704 : : integer, parameter :: DEFAULT_SIZE_BLOCS = 1
705 : : #else
706 : : ! As recommended by Intel MKL, a more sensible default than the previous value of 40
707 : : integer, parameter :: DEFAULT_SIZE_BLOCS = 24
708 : : #endif
709 : : ! As recommended in ELPA, which advises distributions as squared as possible using powers of 2
710 : : integer, parameter :: DEFAULT_SIZE_BLOCS_GPU = 16
711 : : integer :: info,sizeb
712 : : !character(len=500) :: msg
713 : : ! *********************************************************************
714 : :
715 : : call matrix%free()
716 : :
717 : : sizeb = DEFAULT_SIZE_BLOCS
718 : : if (processor%grid%use_gpu) sizeb = DEFAULT_SIZE_BLOCS_GPU
719 : :
720 : : !Records of the matrix type
721 : : matrix%processor => processor
722 : : matrix%size_blocs(1) = MIN(sizeb, nbli_global)
723 : : matrix%size_blocs(2) = MIN(sizeb, nbco_global)
724 : :
725 : : #if defined(HAVE_LINALG_ELPA) || defined(HAVE_LINALG_SLATE)
726 : : if(matrix%size_blocs(1) .ne. matrix%size_blocs(2)) then
727 : : matrix%size_blocs(1) = MIN(matrix%size_blocs(1), matrix%size_blocs(2))
728 : : matrix%size_blocs(2) = matrix%size_blocs(1)
729 : : end if
730 : : #endif
731 : :
732 : : ! Use custom block sizes.
733 : : if (present(size_blocs)) then
734 : : ABI_CHECK(.not. all(size_blocs == -1), "size_blocs [-1, -1] is not allowed")
735 : : if (size_blocs(1) == -1) then
736 : : matrix%size_blocs(1) = nbli_global
737 : : else
738 : : matrix%size_blocs(1) = MIN(size_blocs(1), nbli_global)
739 : : end if
740 : : if (size_blocs(2) == -1) then
741 : : matrix%size_blocs(2) = nbco_global
742 : : else
743 : : matrix%size_blocs(2) = MIN(size_blocs(2), nbco_global)
744 : : end if
745 : : end if
746 : :
747 : : matrix%size_global(1) = nbli_global
748 : : matrix%size_global(2) = nbco_global
749 : : !write(std_out, *)"matrix%size_global", matrix%size_global
750 : :
751 : : ! Size of the local buffer
752 : : ! NUMROC computes the NUMber of Rows Or Columns of a distributed matrix owned by the process indicated by IPROC.
753 : : ! NUMROC (n, nb, iproc, isrcproc, nprocs)
754 : : matrix%size_local(1) = NUMROC(nbli_global, matrix%size_blocs(1), &
755 : : processor%coords(1), 0, processor%grid%dims(1))
756 : :
757 : : matrix%size_local(2) = NUMROC(nbco_global,matrix%size_blocs(2), &
758 : : processor%coords(2), 0, processor%grid%dims(2))
759 : :
760 : : matrix%bufsize = int(matrix%size_local(1), c_size_t) * int(matrix%size_local(2), c_size_t)
761 : :
762 : : call matrix%idx_loc(matrix%size_global(1), matrix%size_global(2), &
763 : : matrix%size_local(1), matrix%size_local(2))
764 : :
765 : : ! Initialisation of the SCALAPACK description of the matrix
766 : : ! (desc, m, n, mb, nb, irsrc, icsrc, comm, lld, info)
767 : : call DESCINIT(matrix%desc, nbli_global, nbco_global, &
768 : : matrix%size_blocs(1), matrix%size_blocs(2), 0, 0, &
769 : : processor%grid%comm, MAX(1, matrix%size_local(1)), info)
770 : :
771 : : if (info /= 0) then
772 : : ABI_ERROR(sjoin("Error while initializing scalapack matrix. info:", itoa(info)))
773 : : end if
774 : :
775 : : ! Allocate local buffer.
776 : : matrix%istwf_k = istwf_k
777 : : select type (matrix)
778 : : class is (slkmat_dp_t)
779 : : if (istwf_k /= 2) then
780 : : ABI_MALLOC(matrix%buffer_cplx, (matrix%size_local(1), matrix%size_local(2)))
781 : : matrix%buffer_cplx = czero
782 : : else
783 : : ABI_MALLOC(matrix%buffer_real, (matrix%size_local(1), matrix%size_local(2)))
784 : : matrix%buffer_real = zero
785 : : end if
786 : :
787 : : class is (slkmat_sp_t)
788 : : if (istwf_k /= 2) then
789 : : ABI_MALLOC(matrix%buffer_cplx, (matrix%size_local(1), matrix%size_local(2)))
790 : : matrix%buffer_cplx = czero_sp
791 : : else
792 : : ABI_MALLOC(matrix%buffer_real, (matrix%size_local(1), matrix%size_local(2)))
793 : : matrix%buffer_real = zero_sp
794 : : end if
795 : :
796 : : class default
797 : : ABI_ERROR("Wrong class")
798 : : end select
799 : :
800 : : if (present(gpu_action)) call matrix%gpu_map(gpu_action)
801 : : #endif
802 : :
803 : 0 : end subroutine basemat_init
804 : : !!***
805 : :
806 : : !----------------------------------------------------------------------
807 : :
808 : : !!****f* m_slk/basemat_locmem_mb
809 : : !! NAME
810 : : !! basemat_locmem_mb
811 : : !!
812 : : !! FUNCTION
813 : : !! Returns memory allocated for the local buffer in Mb.
814 : : !!
815 : : !! SOURCE
816 : :
817 : 0 : pure real(dp) function basemat_locmem_mb(mat) result(locmem_mb)
818 : :
819 : : !Arguments ------------------------------------
820 : : class(basemat_t),intent(in) :: mat
821 : : ! *********************************************************************
822 : :
823 : 0 : locmem_mb = zero
824 : : select type (mat)
825 : : class is (slkmat_dp_t)
826 [ # # # # ]: 0 : if (allocated(mat%buffer_real)) locmem_mb = product(int(shape(mat%buffer_real))) * dp
827 [ # # # # ]: 0 : if (allocated(mat%buffer_cplx)) locmem_mb = product(int(shape(mat%buffer_cplx))) * two * dp
828 : : class is (slkmat_sp_t)
829 [ # # # # ]: 0 : if (allocated(mat%buffer_real)) locmem_mb = product(int(shape(mat%buffer_real))) * sp
830 [ # # # # ]: 0 : if (allocated(mat%buffer_cplx)) locmem_mb = product(int(shape(mat%buffer_cplx))) * two * sp
831 : : end select
832 : 0 : locmem_mb = locmem_mb * b2Mb
833 : :
834 : 0 : end function basemat_locmem_mb
835 : : !!***
836 : :
837 : : !----------------------------------------------------------------------
838 : :
839 : : !!****f* m_slk/basemat_print
840 : : !! NAME
841 : : !! basemat_print
842 : : !!
843 : : !! FUNCTION
844 : : !! Print info on scalapack matrix.
845 : : !!
846 : : !! INPUTS
847 : : !! [unit]=Unit number (default: std_out)
848 : : !! [header]=title for info
849 : : !! [prtvol]=Verbosity level (default: 0)
850 : : !!
851 : : !! SOURCE
852 : :
853 : 0 : subroutine basemat_print(mat, header, unit, prtvol)
854 : :
855 : : !Arguments ------------------------------------
856 : : class(basemat_t),intent(in) :: mat
857 : : character(len=*),optional,intent(in) :: header
858 : : integer,optional,intent(in) :: prtvol, unit
859 : :
860 : : !Local variables-------------------------------
861 : : integer :: unt, my_prtvol, grid_dims(2)
862 : : character(len=50) :: matrix_dtype
863 : : character(len=5000) :: msg
864 : : ! *********************************************************************
865 : :
866 : 0 : unt = std_out; if (present(unit)) unt =unit
867 : 0 : my_prtvol = 0; if (present(prtvol)) my_prtvol = prtvol
868 : :
869 : 0 : msg = ' ==== Info on scalapack matrix ==== '
870 [ # # # # : 0 : if (present(header)) msg=' ==== '//trim(adjustl(header))//' ==== '
# # ]
871 : 0 : call wrtout(unt, msg)
872 : :
873 : 0 : matrix_dtype = "undefined"
874 : : select type (mat)
875 : : class is (slkmat_dp_t)
876 [ # # ]: 0 : if (allocated(mat%buffer_real)) matrix_dtype = "real dp"
877 [ # # ]: 0 : if (allocated(mat%buffer_cplx)) matrix_dtype = "complex dp"
878 : :
879 : : class is (slkmat_sp_t)
880 [ # # ]: 0 : if (allocated(mat%buffer_real)) matrix_dtype = "real sp"
881 [ # # ]: 0 : if (allocated(mat%buffer_cplx)) matrix_dtype = "complex sp"
882 : :
883 : : class default
884 : 0 : ABI_ERROR("Wrong class")
885 : : end select
886 : :
887 : 0 : grid_dims = [-1, -1]
888 [ # # # # ]: 0 : if (associated(mat%processor)) grid_dims = mat%processor%grid%dims
889 : :
890 : : write(msg,'(5(3a),a,f8.1,a)') &
891 : 0 : " matrix_dtype ..... ", trim(matrix_dtype), ch10, &
892 [ # # ]: 0 : " size_global ...... ", trim(ltoa(mat%size_global)), ch10, &
893 [ # # ]: 0 : " size_local ...... ", trim(ltoa(mat%size_local)), ch10, &
894 [ # # ]: 0 : " size_blocs ...... ", trim(ltoa(mat%size_blocs)), ch10, &
895 [ # # ]: 0 : " processor grid ... ", trim(ltoa(grid_dims)), ch10, &
896 : 0 : " memory (Mb) ...... ", mat%locmem_mb(), ch10
897 : 0 : call wrtout(unt, msg)
898 : :
899 : : !if (prtvol > 10) call mat%write(unit)
900 : :
901 [ # # ]: 0 : end subroutine basemat_print
902 : : !!***
903 : :
904 : : !----------------------------------------------------------------------
905 : :
906 : : !!****f* m_slk/slkmat_check_shape
907 : : !! NAME
908 : : !! slkmat_check_shape
909 : : !!
910 : : !! FUNCTION
911 : : !! Debugging tool to test the local shape `lshape` of the local buffer.
912 : : !! Return exit status in `ok` and error message in `msg`.
913 : : !!
914 : : !! SOURCE
915 : :
916 : 0 : logical function basemat_check_local_shape(mat, lshape, msg) result (ok)
917 : :
918 : : !Arguments ------------------------------------
919 : : class(basemat_t),intent(in) :: mat
920 : : integer,intent(in) :: lshape(2)
921 : : character(len=*),intent(out) :: msg
922 : : ! *********************************************************************
923 : :
924 : 0 : msg = ""
925 [ # # # # ]: 0 : ok = all(mat%size_local == lshape)
926 [ # # ]: 0 : if (.not. ok) then
927 [ # # # # ]: 0 : msg = sjoin("mat%size_local:", ltoa(mat%size_local), " not equal to input local lshape ", ltoa(lshape))
928 : 0 : return
929 : : end if
930 : :
931 : : select type (mat)
932 : : class is (slkmat_dp_t)
933 [ # # ]: 0 : if (allocated(mat%buffer_cplx)) then
934 [ # # # # ]: 0 : ok = all(shape(mat%buffer_cplx) == lshape)
935 [ # # ]: 0 : if (.not. ok) then
936 [ # # # # : 0 : msg = sjoin("shape(buffer_cplx):", ltoa(shape(mat%buffer_cplx)), " != input local lshape ", ltoa(lshape)); return
# # ]
937 : : end if
938 [ # # ]: 0 : else if (allocated(mat%buffer_real)) then
939 [ # # # # ]: 0 : ok = all(shape(mat%buffer_real) == lshape)
940 [ # # ]: 0 : if (.not. ok) then
941 [ # # # # : 0 : msg = sjoin("shape(buffer_real):", ltoa(shape(mat%buffer_real)), " != input local lshape ", ltoa(lshape)); return
# # ]
942 : : end if
943 : : end if
944 : :
945 : : class is (slkmat_sp_t)
946 : : ! Same piece of code as above. May use include file!
947 [ # # ]: 0 : if (allocated(mat%buffer_cplx)) then
948 [ # # # # ]: 0 : ok = all(shape(mat%buffer_cplx) == lshape)
949 [ # # ]: 0 : if (.not. ok) then
950 [ # # # # : 0 : msg = sjoin("shape(buffer_cplx):", ltoa(shape(mat%buffer_cplx)), " != input local lshape ", ltoa(lshape)); return
# # ]
951 : : end if
952 [ # # ]: 0 : else if (allocated(mat%buffer_real)) then
953 [ # # # # ]: 0 : ok = all(shape(mat%buffer_real) == lshape)
954 [ # # ]: 0 : if (.not. ok) then
955 [ # # # # : 0 : msg = sjoin("shape(buffer_real):", ltoa(shape(mat%buffer_real)), " != input local lshape ", ltoa(lshape)); return
# # ]
956 : : end if
957 : : end if
958 : :
959 : : class default
960 : 0 : ABI_ERROR("Wrong class")
961 : : end select
962 : :
963 [ # # ]: 0 : end function basemat_check_local_shape
964 : : !!***
965 : :
966 : : !----------------------------------------------------------------------
967 : :
968 : : !!****f* m_slk/slkmat_dp_get_head_and_wings
969 : : !! NAME
970 : : !! slkmat_dp_get_head_and_wings
971 : : !!
972 : : !! FUNCTION
973 : : !! Return global arrays with head and wings of the matrix.
974 : : !! If call_mpi if False, global MPI sum is postponed.
975 : : !! Useful to reduce the number of MPI calls if one has to operate on multiple matrices.
976 : : !!
977 : : !! SOURCE
978 : :
979 : 0 : subroutine slkmat_dp_get_head_and_wings(mat, head, low_wing, up_wing, call_mpi)
980 : :
981 : : !Arguments ------------------------------------
982 : : class(slkmat_dp_t),intent(in) :: mat
983 : : complex(dp),intent(out) :: head, low_wing(mat%size_global(1)), up_wing(mat%size_global(2))
984 : : logical,intent(in) :: call_mpi
985 : :
986 : : !Local variables-------------------------------
987 : : integer :: ierr, il_g1, il_g2, iglob1, iglob2
988 : : logical :: is_cplx
989 : : ! *********************************************************************
990 : :
991 [ # # # # ]: 0 : head = zero; low_wing = zero; up_wing = zero
992 : :
993 : 0 : is_cplx = allocated(mat%buffer_cplx)
994 : :
995 [ # # ]: 0 : do il_g2=1,mat%size_local(2)
996 : 0 : iglob2 = mat%loc2gcol(il_g2)
997 [ # # ]: 0 : do il_g1=1,mat%size_local(1)
998 : 0 : iglob1 = mat%loc2grow(il_g1)
999 : :
1000 [ # # ]: 0 : if (iglob1 == 1 .or. iglob2 == 1) then
1001 [ # # ]: 0 : if (iglob1 == 1 .and. iglob2 == 1) then
1002 [ # # ]: 0 : if (is_cplx) then
1003 : 0 : head = mat%buffer_cplx(il_g1, il_g2)
1004 : : else
1005 : 0 : head = mat%buffer_real(il_g1, il_g2)
1006 : : end if
1007 [ # # ]: 0 : else if (iglob1 == 1) then
1008 [ # # ]: 0 : if (is_cplx) then
1009 : 0 : up_wing(iglob2) = mat%buffer_cplx(il_g1, il_g2)
1010 : : else
1011 : 0 : up_wing(iglob2) = mat%buffer_real(il_g1, il_g2)
1012 : : end if
1013 [ # # ]: 0 : else if (iglob2 == 1) then
1014 [ # # ]: 0 : if (is_cplx) then
1015 : 0 : low_wing(iglob1) = mat%buffer_cplx(il_g1, il_g2)
1016 : : else
1017 : 0 : low_wing(iglob1) = mat%buffer_real(il_g1, il_g2)
1018 : : end if
1019 : : end if
1020 : : end if
1021 : :
1022 : : end do
1023 : : end do
1024 : :
1025 [ # # ]: 0 : if (call_mpi) then
1026 : 0 : call xmpi_sum(head, mat%processor%comm, ierr)
1027 : 0 : call xmpi_sum(low_wing, mat%processor%comm, ierr)
1028 : 0 : call xmpi_sum(up_wing, mat%processor%comm, ierr)
1029 : : end if
1030 : :
1031 : 0 : end subroutine slkmat_dp_get_head_and_wings
1032 : : !!***
1033 : :
1034 : : !----------------------------------------------------------------------
1035 : :
1036 : : !!****f* m_slk/slkmat_dp_set_head_and_wings
1037 : : !! NAME
1038 : : !! slkmat_dp_set_head_and_wings
1039 : : !!
1040 : : !! FUNCTION
1041 : : !! Set head and wings of the matrix starting from global arrays.
1042 : : !!
1043 : : !! SOURCE
1044 : :
1045 : 0 : subroutine slkmat_dp_set_head_and_wings(mat, head, low_wing, up_wing)
1046 : :
1047 : : !Arguments ------------------------------------
1048 : : class(slkmat_dp_t),intent(inout) :: mat
1049 : : complex(dp),intent(in) :: head, low_wing(mat%size_global(1)), up_wing(mat%size_global(2))
1050 : :
1051 : : !Local variables-------------------------------
1052 : : integer :: il_g1, il_g2, iglob1, iglob2
1053 : : logical :: is_cplx
1054 : : ! *********************************************************************
1055 : :
1056 : 0 : is_cplx = allocated(mat%buffer_cplx)
1057 : :
1058 [ # # ]: 0 : do il_g2=1,mat%size_local(2)
1059 : 0 : iglob2 = mat%loc2gcol(il_g2)
1060 [ # # ]: 0 : do il_g1=1,mat%size_local(1)
1061 : 0 : iglob1 = mat%loc2grow(il_g1)
1062 : :
1063 [ # # ]: 0 : if (iglob1 == 1 .or. iglob2 == 1) then
1064 [ # # ]: 0 : if (iglob1 == 1 .and. iglob2 == 1) then
1065 [ # # ]: 0 : if (is_cplx) then
1066 : 0 : mat%buffer_cplx(il_g1, il_g2) = head
1067 : : else
1068 : 0 : mat%buffer_real(il_g1, il_g2) = real(head)
1069 : : end if
1070 [ # # ]: 0 : else if (iglob1 == 1) then
1071 [ # # ]: 0 : if (is_cplx) then
1072 : 0 : mat%buffer_cplx(il_g1, il_g2) = up_wing(iglob2)
1073 : : else
1074 : 0 : mat%buffer_real(il_g1, il_g2) = real(up_wing(iglob2))
1075 : : end if
1076 [ # # ]: 0 : else if (iglob2 == 1) then
1077 [ # # ]: 0 : if (is_cplx) then
1078 : 0 : mat%buffer_cplx(il_g1, il_g2) = low_wing(iglob1)
1079 : : else
1080 : 0 : mat%buffer_real(il_g1, il_g2) = real(low_wing(iglob1))
1081 : : end if
1082 : : end if
1083 : : end if
1084 : :
1085 : : end do
1086 : : end do
1087 : :
1088 : 0 : end subroutine slkmat_dp_set_head_and_wings
1089 : : !!***
1090 : :
1091 : : !----------------------------------------------------------------------
1092 : :
1093 : : !!****f* m_slk/slkmat_sp_set_head_and_wings
1094 : : !! NAME
1095 : : !! slkmat_sp_set_head_and_wings
1096 : : !!
1097 : : !! FUNCTION
1098 : : !! Set head and the wings of the matrix starting from global arrays.
1099 : : !!
1100 : : !! SOURCE
1101 : :
1102 : 0 : subroutine slkmat_sp_set_head_and_wings(mat, head, low_wing, up_wing)
1103 : :
1104 : : !Arguments ------------------------------------
1105 : : class(slkmat_sp_t),intent(inout) :: mat
1106 : : complex(sp),intent(in) :: head, low_wing(mat%size_global(1)), up_wing(mat%size_global(2))
1107 : :
1108 : : !Local variables-------------------------------
1109 : : integer :: il_g1, il_g2, iglob1, iglob2
1110 : : logical :: is_cplx
1111 : : ! *********************************************************************
1112 : :
1113 : 0 : is_cplx = allocated(mat%buffer_cplx)
1114 : :
1115 [ # # ]: 0 : do il_g2=1,mat%size_local(2)
1116 : 0 : iglob2 = mat%loc2gcol(il_g2)
1117 [ # # ]: 0 : do il_g1=1,mat%size_local(1)
1118 : 0 : iglob1 = mat%loc2grow(il_g1)
1119 : :
1120 [ # # ]: 0 : if (iglob1 == 1 .or. iglob2 == 1) then
1121 [ # # ]: 0 : if (iglob1 == 1 .and. iglob2 == 1) then
1122 [ # # ]: 0 : if (is_cplx) then
1123 : 0 : mat%buffer_cplx(il_g1, il_g2) = head
1124 : : else
1125 : 0 : mat%buffer_real(il_g1, il_g2) = real(head)
1126 : : end if
1127 [ # # ]: 0 : else if (iglob1 == 1) then
1128 [ # # ]: 0 : if (is_cplx) then
1129 : 0 : mat%buffer_cplx(il_g1, il_g2) = up_wing(iglob2)
1130 : : else
1131 : 0 : mat%buffer_real(il_g1, il_g2) = real(up_wing(iglob2))
1132 : : end if
1133 [ # # ]: 0 : else if (iglob2 == 1) then
1134 [ # # ]: 0 : if (is_cplx) then
1135 : 0 : mat%buffer_cplx(il_g1, il_g2) = low_wing(iglob1)
1136 : : else
1137 : 0 : mat%buffer_real(il_g1, il_g2) = real(low_wing(iglob1))
1138 : : end if
1139 : : end if
1140 : : end if
1141 : :
1142 : : end do
1143 : : end do
1144 : :
1145 : 0 : end subroutine slkmat_sp_set_head_and_wings
1146 : : !!***
1147 : :
1148 : : !----------------------------------------------------------------------
1149 : :
1150 : : !!****f* m_slk/slkmat_dp_copy
1151 : : !! NAME
1152 : : !! slkmat_dp_copy
1153 : : !!
1154 : : !! FUNCTION
1155 : : !! Copy in_mat to out_mat. If empty is True, the values in the local buffer are not copied. Default: False
1156 : : !!
1157 : : !! SOURCE
1158 : :
1159 [ # # ]: 0 : subroutine slkmat_dp_copy(in_mat, out_mat, empty)
1160 : :
1161 : : !Arguments ------------------------------------
1162 : : class(slkmat_dp_t),intent(in) :: in_mat
1163 : : class(slkmat_dp_t),intent(out) :: out_mat
1164 : : logical,optional,intent(in) :: empty
1165 : :
1166 : : !Local variables-------------------------------
1167 : : logical :: empty__
1168 : : type(c_ptr) :: gpu_ptr
1169 : : ! *********************************************************************
1170 : :
1171 : : call out_mat%init(in_mat%size_global(1), in_mat%size_global(2), in_mat%processor, in_mat%istwf_k, &
1172 : 0 : size_blocs=in_mat%size_blocs)
1173 : :
1174 [ # # ]: 0 : empty__ = .False.; if (present(empty)) empty__ = empty
1175 [ # # ]: 0 : if (.not. empty__) then
1176 [ # # ]: 0 : if (in_mat%istwf_k == 1) then
1177 [ # # # # : 0 : out_mat%buffer_cplx = in_mat%buffer_cplx
# # # # #
# # # # #
# # # # #
# ]
1178 : : else
1179 [ # # # # : 0 : out_mat%buffer_real = in_mat%buffer_real
# # # # #
# # # # #
# # # # #
# ]
1180 : : end if
1181 : : end if
1182 : :
1183 [ # # ]: 0 : if (in_mat%is_gpu_mapped(gpu_ptr)) then
1184 : 0 : call out_mat%gpu_map("alloc")
1185 [ # # ]: 0 : if (in_mat%istwf_k == 1) then
1186 : 0 : call gpu_copy_complex(out_mat%buffer_cplx, in_mat%buffer_cplx, in_mat%bufsize)
1187 : : else
1188 : 0 : call gpu_copy(out_mat%buffer_real, in_mat%buffer_real, in_mat%bufsize)
1189 : : end if
1190 : : end if
1191 : :
1192 : 0 : end subroutine slkmat_dp_copy
1193 : : !!***
1194 : :
1195 : : !----------------------------------------------------------------------
1196 : :
1197 : : !!****f* m_slk/slkmat_sp_copy
1198 : : !! NAME
1199 : : !! slkmat_sp_copy
1200 : : !!
1201 : : !! FUNCTION
1202 : : !! Copy in_mat to out_mat. If empty is True, the values in the local buffer are not copied. Default: False
1203 : : !!
1204 : : !! SOURCE
1205 : :
1206 [ # # ]: 0 : subroutine slkmat_sp_copy(in_mat, out_mat, empty)
1207 : :
1208 : : !Arguments ------------------------------------
1209 : : class(slkmat_sp_t),intent(in) :: in_mat
1210 : : class(slkmat_sp_t),intent(out) :: out_mat
1211 : : logical,optional,intent(in) :: empty
1212 : :
1213 : : !Local variables-------------------------------
1214 : : logical :: empty__
1215 : : type(c_ptr) :: gpu_ptr
1216 : : ! *********************************************************************
1217 : :
1218 : : call out_mat%init(in_mat%size_global(1), in_mat%size_global(2), in_mat%processor, in_mat%istwf_k, &
1219 : 0 : size_blocs=in_mat%size_blocs)
1220 : :
1221 [ # # ]: 0 : empty__ = .False.; if (present(empty)) empty__ = empty
1222 [ # # ]: 0 : if (.not. empty__) then
1223 [ # # ]: 0 : if (in_mat%istwf_k == 1) then
1224 [ # # # # : 0 : out_mat%buffer_cplx = in_mat%buffer_cplx
# # # # #
# # # # #
# # # # #
# ]
1225 : : else
1226 [ # # # # : 0 : out_mat%buffer_real = in_mat%buffer_real
# # # # #
# # # # #
# # # # #
# ]
1227 : : end if
1228 : : end if
1229 : :
1230 [ # # ]: 0 : if (in_mat%is_gpu_mapped(gpu_ptr)) then
1231 : 0 : call out_mat%gpu_map("alloc")
1232 [ # # ]: 0 : if (in_mat%istwf_k == 1) then
1233 : 0 : call gpu_copy_complex_sp(out_mat%buffer_cplx, in_mat%buffer_cplx, in_mat%bufsize)
1234 : : else
1235 : 0 : call gpu_copy_sp(out_mat%buffer_real, in_mat%buffer_real, in_mat%bufsize)
1236 : : end if
1237 : : end if
1238 : :
1239 : 0 : end subroutine slkmat_sp_copy
1240 : : !!***
1241 : :
1242 : : !----------------------------------------------------------------------
1243 : :
1244 : : !!****f* m_slk/basemat_free
1245 : : !! NAME
1246 : : !! basemat_free
1247 : : !!
1248 : : !! FUNCTION
1249 : : !! Free dynamic memory
1250 : : !!
1251 : : !! SOURCE
1252 : :
1253 : 0 : subroutine basemat_free(mat)
1254 : :
1255 : : !Arguments ------------------------------------
1256 : : class(basemat_t),intent(inout) :: mat
1257 : :
1258 : : !Local variables-------------------------------
1259 : : type(c_ptr) :: gpu_ptr
1260 : : ! *********************************************************************
1261 : :
1262 : : ! Don't free the grid. Just nullify the pointer as there might be other objects keeping a ref to processor.
1263 : 0 : mat%processor => null()
1264 : :
1265 [ # # ]: 0 : mat%size_global = 0
1266 [ # # ]: 0 : mat%size_blocs = 0
1267 [ # # ]: 0 : mat%size_local = 0
1268 [ # # ]: 0 : mat%desc = 0
1269 : :
1270 [ # # ]: 0 : if (mat%is_gpu_mapped(gpu_ptr)) then
1271 : 0 : call wrtout(std_out, "Deallocating mat%buffer on the GPU")
1272 : 0 : call mat%gpu_map("delete")
1273 : : end if
1274 : :
1275 : : select type (mat)
1276 : : class is (slkmat_dp_t)
1277 [ # # ]: 0 : ABI_SFREE(mat%buffer_cplx)
1278 [ # # ]: 0 : ABI_SFREE(mat%buffer_real)
1279 : :
1280 : : class is (slkmat_sp_t)
1281 [ # # ]: 0 : ABI_SFREE(mat%buffer_cplx)
1282 [ # # ]: 0 : ABI_SFREE(mat%buffer_real)
1283 : :
1284 : : class default
1285 : 0 : ABI_ERROR("Wrong class")
1286 : : end select
1287 : :
1288 : 0 : end subroutine basemat_free
1289 : : !!***
1290 : :
1291 : : !----------------------------------------------------------------------
1292 : :
1293 : : !!****f* m_slk/slk_array1_free
1294 : : !! NAME
1295 : : !! slk_array1_free
1296 : : !!
1297 : : !! FUNCTION
1298 : : !! Deallocate 1d array of slkmat_dp_t elements
1299 : : !!
1300 : : !! SOURCE
1301 : :
1302 : 0 : subroutine slk_array1_free(slk_arr1)
1303 : : class(basemat_t),intent(inout) :: slk_arr1(:)
1304 : : integer :: i1
1305 [ # # ]: 0 : do i1=1,size(slk_arr1, dim=1)
1306 : 0 : call slk_arr1(i1)%free()
1307 : : end do
1308 : 0 : end subroutine slk_array1_free
1309 : : !!***
1310 : :
1311 : : !----------------------------------------------------------------------
1312 : :
1313 : : !!****f* m_slk/slk_array2_free
1314 : : !! NAME
1315 : : !! slk_array2_free
1316 : : !!
1317 : : !! FUNCTION
1318 : : !! Deallocate 2d array of slkmat_dp_t elements
1319 : : !!
1320 : : !! SOURCE
1321 : :
1322 : 0 : subroutine slk_array2_free(slk_arr2)
1323 : : class(basemat_t),intent(inout) :: slk_arr2(:,:)
1324 : : integer :: i1, i2
1325 [ # # ]: 0 : do i2=1,size(slk_arr2, dim=2)
1326 [ # # ]: 0 : do i1=1,size(slk_arr2, dim=1)
1327 : 0 : call slk_arr2(i1, i2)%free()
1328 : : end do
1329 : : end do
1330 : 0 : end subroutine slk_array2_free
1331 : : !!***
1332 : :
1333 : : !----------------------------------------------------------------------
1334 : :
1335 : : !!****f* m_slk/slk_array3_free
1336 : : !! NAME
1337 : : !! slk_array3_free
1338 : : !!
1339 : : !! FUNCTION
1340 : : !! Deallocate 3d array of slkmat_dp_t elements
1341 : : !!
1342 : : !! SOURCE
1343 : :
1344 : 0 : subroutine slk_array3_free(slk_arr3)
1345 : : class(basemat_t),intent(inout) :: slk_arr3(:,:,:)
1346 : : integer :: i1, i2, i3
1347 [ # # ]: 0 : do i3=1,size(slk_arr3, dim=3)
1348 [ # # ]: 0 : do i2=1,size(slk_arr3, dim=2)
1349 [ # # ]: 0 : do i1=1,size(slk_arr3, dim=1)
1350 : 0 : call slk_arr3(i1, i2, i3)%free()
1351 : : end do
1352 : : end do
1353 : : end do
1354 : 0 : end subroutine slk_array3_free
1355 : : !!***
1356 : :
1357 : : !----------------------------------------------------------------------
1358 : :
1359 : : !!****f* m_slk/slk_array4_free
1360 : : !! NAME
1361 : : !! slk_array4_free
1362 : : !!
1363 : : !! FUNCTION
1364 : : !! Deallocate 4d array of slkmat_dp_t elements
1365 : : !!
1366 : : !! SOURCE
1367 : :
1368 : 0 : subroutine slk_array4_free(slk_arr4)
1369 : : class(basemat_t),intent(inout) :: slk_arr4(:,:,:,:)
1370 : : integer :: i1, i2, i3, i4
1371 [ # # ]: 0 : do i4=1,size(slk_arr4, dim=4)
1372 [ # # ]: 0 : do i3=1,size(slk_arr4, dim=3)
1373 [ # # ]: 0 : do i2=1,size(slk_arr4, dim=2)
1374 [ # # ]: 0 : do i1=1,size(slk_arr4, dim=1)
1375 : 0 : call slk_arr4(i1, i2, i3, i4)%free()
1376 : : end do
1377 : : end do
1378 : : end do
1379 : : end do
1380 : 0 : end subroutine slk_array4_free
1381 : : !!***
1382 : :
1383 : : !----------------------------------------------------------------------
1384 : :
1385 : : !!****f* m_slk/slk_array5_free
1386 : : !! NAME
1387 : : !! slk_array5_free
1388 : : !!
1389 : : !! FUNCTION
1390 : : !! Deallocate 5d array of slkmat_dp_t elements
1391 : : !!
1392 : : !! SOURCE
1393 : :
1394 : 0 : subroutine slk_array5_free(slk_arr5)
1395 : : class(basemat_t),intent(inout) :: slk_arr5(:,:,:,:,:)
1396 : : integer :: i1, i2, i3, i4, i5
1397 [ # # ]: 0 : do i5=1,size(slk_arr5, dim=5)
1398 [ # # ]: 0 : do i4=1,size(slk_arr5, dim=4)
1399 [ # # ]: 0 : do i3=1,size(slk_arr5, dim=3)
1400 [ # # ]: 0 : do i2=1,size(slk_arr5, dim=2)
1401 [ # # ]: 0 : do i1=1,size(slk_arr5, dim=1)
1402 : 0 : call slk_arr5(i1, i2, i3, i4, i5)%free()
1403 : : end do
1404 : : end do
1405 : : end do
1406 : : end do
1407 : : end do
1408 : 0 : end subroutine slk_array5_free
1409 : : !!***
1410 : :
1411 : : !----------------------------------------------------------------------
1412 : :
1413 : : !!****f* m_slk/slk_array_set_zero
1414 : : !! NAME
1415 : : !! slk_array_set_zero
1416 : : !!
1417 : : !! FUNCTION
1418 : : !! Elemental routine to set the value of the PBLAS buffer to zero
1419 : : !!
1420 : : !! SOURCE
1421 : :
1422 : 0 : elemental subroutine slk_array_set_zero(mat)
1423 : :
1424 : : !Arguments ------------------------------------
1425 : : class(basemat_t),intent(inout) :: mat
1426 : :
1427 : : select type (mat)
1428 : : class is (slkmat_dp_t)
1429 [ # # # # : 0 : if (allocated(mat%buffer_cplx)) mat%buffer_cplx = zero
# # ]
1430 [ # # # # : 0 : if (allocated(mat%buffer_real)) mat%buffer_real = zero
# # ]
1431 : : class is (slkmat_sp_t)
1432 [ # # # # : 0 : if (allocated(mat%buffer_cplx)) mat%buffer_cplx = cmplx(zero, kind=sp)
# # ]
1433 [ # # # # : 0 : if (allocated(mat%buffer_real)) mat%buffer_real = real(zero, kind=sp)
# # ]
1434 : : end select
1435 : :
1436 : 0 : end subroutine slk_array_set_zero
1437 : : !!***
1438 : :
1439 : : !----------------------------------------------------------------------
1440 : :
1441 : : !!****f* m_slk/basemat_gpu_set_zero
1442 : : !! NAME
1443 : : !! basemat_gpu_set_zero
1444 : : !!
1445 : : !! FUNCTION
1446 : : !! Elemental routine to set the value of the PBLAS buffer to zero
1447 : : !!
1448 : : !! SOURCE
1449 : :
1450 : 0 : subroutine basemat_gpu_set_zero(mat)
1451 : :
1452 : : !Arguments ------------------------------------
1453 : : class(basemat_t),target,intent(inout) :: mat
1454 : :
1455 : : #ifdef HAVE_OPENMP_OFFLOAD
1456 : : !Local variables-------------------------------
1457 : : type(c_ptr) :: gpu_ptr
1458 : : ! *********************************************************************
1459 : :
1460 : : select type (mat)
1461 : : class is (slkmat_dp_t)
1462 : : if (allocated(mat%buffer_cplx)) then
1463 : : gpu_ptr = xomp_get_mapped_ptr(c_loc(mat%buffer_cplx))
1464 : : ABI_CHECK_CNULL(gpu_ptr, "buffer_cplx not on GPU!")
1465 : : call gpu_memset(gpu_ptr, 0, mat%bufsize*dp*2)
1466 : : end if
1467 : : if (allocated(mat%buffer_real)) then
1468 : : gpu_ptr = xomp_get_mapped_ptr(c_loc(mat%buffer_real))
1469 : : ABI_CHECK_CNULL(gpu_ptr, "buffer_real not on GPU!")
1470 : : call gpu_memset(gpu_ptr, 0, mat%bufsize*dp)
1471 : : end if
1472 : : class is (slkmat_sp_t)
1473 : : if (allocated(mat%buffer_cplx)) then
1474 : : gpu_ptr = xomp_get_mapped_ptr(c_loc(mat%buffer_cplx))
1475 : : ABI_CHECK_CNULL(gpu_ptr, "buffer_cplx not on GPU!")
1476 : : call gpu_memset(gpu_ptr, 0, mat%bufsize*sp*2)
1477 : : end if
1478 : : if (allocated(mat%buffer_real)) then
1479 : : gpu_ptr = xomp_get_mapped_ptr(c_loc(mat%buffer_real))
1480 : : ABI_CHECK_CNULL(gpu_ptr, "buffer_real not on GPU!")
1481 : : call gpu_memset(gpu_ptr, 0, mat%bufsize*sp)
1482 : : end if
1483 : : end select
1484 : : #else
1485 : 0 : ABI_ERROR("basemat_gpu_set cannot be used if HAVE_OPENMP_OFFLOAD is not defined!")
1486 : : ABI_UNUSED(mat%size_local(1))
1487 : : #endif
1488 : :
1489 : 0 : end subroutine basemat_gpu_set_zero
1490 : : !!***
1491 : :
1492 : : !!****f* m_slk/slk_array1_gpu_set_zero
1493 : : !! NAME
1494 : : !! slk_array1_gpu_set_zero
1495 : : !!
1496 : : !! FUNCTION
1497 : : !!
1498 : : !! SOURCE
1499 : :
1500 : 0 : subroutine slk_array1_gpu_set_zero(mat1d)
1501 : :
1502 : : !Arguments ------------------------------------
1503 : : class(basemat_t),intent(inout) :: mat1d(:)
1504 : :
1505 : : !Local variables-------------------------------
1506 : : integer :: i1
1507 : : ! *********************************************************************
1508 : :
1509 [ # # ]: 0 : do i1=1,size(mat1d, dim=1)
1510 : 0 : call mat1d(i1)%gpu_set_zero()
1511 : : end do
1512 : :
1513 : 0 : end subroutine slk_array1_gpu_set_zero
1514 : : !!***
1515 : :
1516 : : !!****f* m_slk/slk_array2_gpu_set_zero
1517 : : !! NAME
1518 : : !! slk_array2_gpu_set_zero
1519 : : !!
1520 : : !! FUNCTION
1521 : : !!
1522 : : !! SOURCE
1523 : :
1524 : 0 : subroutine slk_array2_gpu_set_zero(mat2d)
1525 : :
1526 : : !Arguments ------------------------------------
1527 : : class(basemat_t),intent(inout) :: mat2d(:,:)
1528 : :
1529 : : !Local variables-------------------------------
1530 : : integer :: i1, i2
1531 : : ! *********************************************************************
1532 : :
1533 [ # # ]: 0 : do i2=1,size(mat2d, dim=2)
1534 [ # # ]: 0 : do i1=1,size(mat2d, dim=1)
1535 : 0 : call mat2d(i1, i2)%gpu_set_zero()
1536 : : end do
1537 : : end do
1538 : :
1539 : 0 : end subroutine slk_array2_gpu_set_zero
1540 : : !!***
1541 : :
1542 : : !!****f* m_slk/slk_array3_gpu_set_zero
1543 : : !! NAME
1544 : : !! slk_array3_gpu_set_zero
1545 : : !!
1546 : : !! FUNCTION
1547 : : !!
1548 : : !! SOURCE
1549 : :
1550 : 0 : subroutine slk_array3_gpu_set_zero(mat3d)
1551 : :
1552 : : !Arguments ------------------------------------
1553 : : class(basemat_t),intent(inout) :: mat3d(:,:,:)
1554 : :
1555 : : !Local variables-------------------------------
1556 : : integer :: i1,i2,i3
1557 : : ! *********************************************************************
1558 : :
1559 [ # # ]: 0 : do i3=1,size(mat3d, dim=3)
1560 [ # # ]: 0 : do i2=1,size(mat3d, dim=2)
1561 [ # # ]: 0 : do i1=1,size(mat3d, dim=1)
1562 : 0 : call mat3d(i1,i2,i3)%gpu_set_zero()
1563 : : end do
1564 : : end do
1565 : : end do
1566 : :
1567 : 0 : end subroutine slk_array3_gpu_set_zero
1568 : : !!***
1569 : :
1570 : : !!****f* m_slk/slk_array4_gpu_set_zero
1571 : : !! NAME
1572 : : !! slk_array4_gpu_set_zero
1573 : : !!
1574 : : !! FUNCTION
1575 : : !!
1576 : : !! SOURCE
1577 : :
1578 : 0 : subroutine slk_array4_gpu_set_zero(mat4d)
1579 : :
1580 : : !Arguments ------------------------------------
1581 : : class(basemat_t),intent(inout) :: mat4d(:,:,:,:)
1582 : :
1583 : : !Local variables-------------------------------
1584 : : integer :: i1, i2, i3, i4
1585 : : ! *********************************************************************
1586 : :
1587 [ # # ]: 0 : do i4=1,size(mat4d, dim=4)
1588 [ # # ]: 0 : do i3=1,size(mat4d, dim=3)
1589 [ # # ]: 0 : do i2=1,size(mat4d, dim=2)
1590 [ # # ]: 0 : do i1=1,size(mat4d, dim=1)
1591 : 0 : call mat4d(i1, i2, i3, i4)%gpu_set_zero()
1592 : : end do
1593 : : end do
1594 : : end do
1595 : : end do
1596 : :
1597 : 0 : end subroutine slk_array4_gpu_set_zero
1598 : : !!***
1599 : :
1600 : : !!****f* m_slk/slk_array5_gpu_set_zero
1601 : : !! NAME
1602 : : !! slk_array5_gpu_set_zero
1603 : : !!
1604 : : !! FUNCTION
1605 : : !!
1606 : : !! SOURCE
1607 : :
1608 : 0 : subroutine slk_array5_gpu_set_zero(mat5d)
1609 : :
1610 : : !Arguments ------------------------------------
1611 : : class(basemat_t),intent(inout) :: mat5d(:,:,:,:,:)
1612 : :
1613 : : !Local variables-------------------------------
1614 : : integer :: i1,i2,i3,i4,i5
1615 : : ! *********************************************************************
1616 : :
1617 [ # # ]: 0 : do i5=1,size(mat5d, dim=5)
1618 [ # # ]: 0 : do i4=1,size(mat5d, dim=4)
1619 [ # # ]: 0 : do i3=1,size(mat5d, dim=3)
1620 [ # # ]: 0 : do i2=1,size(mat5d, dim=2)
1621 [ # # ]: 0 : do i1=1,size(mat5d, dim=1)
1622 : 0 : call mat5d(i1,i2,i3,i4,i5)%gpu_set_zero()
1623 : : end do
1624 : : end do
1625 : : end do
1626 : : end do
1627 : : end do
1628 : :
1629 : 0 : end subroutine slk_array5_gpu_set_zero
1630 : : !!***
1631 : :
1632 : : !----------------------------------------------------------------------
1633 : :
1634 : : !!****f* m_slk/basemat_is_gpu_mapped
1635 : : !! NAME
1636 : : !! basemat_is_gpu_mapped
1637 : : !!
1638 : : !! FUNCTION
1639 : : !! Return True if the local buffer is mapped to the GPU and the pointer on the gpu.
1640 : : !!
1641 : : !! SOURCE
1642 : :
1643 : 0 : logical function basemat_is_gpu_mapped(mat, gpu_ptr) result(is_gpu_mapped)
1644 : :
1645 : : !Arguments ------------------------------------
1646 : : class(basemat_t),target,intent(in) :: mat
1647 : : type(c_ptr),intent(out) :: gpu_ptr
1648 : :
1649 : : !Local variables-------------------------------
1650 : : #ifdef HAVE_OPENMP_OFFLOAD
1651 : : real(sp), contiguous, pointer :: buf_real_sp(:,:)
1652 : : real(dp), contiguous, pointer :: buf_real_dp(:,:)
1653 : : complex(sp), contiguous, pointer :: buf_cplx_sp(:,:)
1654 : : complex(dp), contiguous, pointer :: buf_cplx_dp(:,:)
1655 : : #endif
1656 : : ! *********************************************************************
1657 : :
1658 : 0 : is_gpu_mapped = .False.; gpu_ptr = c_null_ptr
1659 : : #ifdef HAVE_OPENMP_OFFLOAD
1660 : : select type (mat)
1661 : : class is (slkmat_dp_t)
1662 : : if (allocated(mat%buffer_cplx)) then
1663 : : buf_cplx_dp => mat%buffer_cplx
1664 : : gpu_ptr = xomp_get_mapped_ptr(c_loc(buf_cplx_dp))
1665 : : is_gpu_mapped = c_associated(gpu_ptr)
1666 : : end if
1667 : : if (allocated(mat%buffer_real)) then
1668 : : buf_real_dp => mat%buffer_real
1669 : : gpu_ptr = xomp_get_mapped_ptr(c_loc(buf_real_dp))
1670 : : is_gpu_mapped = c_associated(gpu_ptr)
1671 : : end if
1672 : :
1673 : : class is (slkmat_sp_t)
1674 : : if (allocated(mat%buffer_cplx)) then
1675 : : buf_cplx_sp => mat%buffer_cplx
1676 : : gpu_ptr= xomp_get_mapped_ptr(c_loc(buf_cplx_sp))
1677 : : is_gpu_mapped = c_associated(gpu_ptr)
1678 : : end if
1679 : : if (allocated(mat%buffer_real)) then
1680 : : buf_real_sp => mat%buffer_real
1681 : : gpu_ptr = xomp_get_mapped_ptr(c_loc(buf_real_sp))
1682 : : is_gpu_mapped = c_associated(gpu_ptr)
1683 : : end if
1684 : : end select
1685 : : #else
1686 : : ABI_UNUSED(mat%size_local(1))
1687 : : #endif
1688 : :
1689 : 0 : end function basemat_is_gpu_mapped
1690 : : !!***
1691 : :
1692 : : !----------------------------------------------------------------------
1693 : :
1694 : : !!****f* m_slk/basemat_gpu_map
1695 : : !! NAME
1696 : : !! basemat_gpu_map
1697 : : !!
1698 : : !! FUNCTION
1699 : : !! Use Opemp to allocate/delete the local buffer on the GPU.
1700 : : !!
1701 : : !! SOURCE
1702 : :
1703 : 0 : subroutine basemat_gpu_map(mat, gpu_action)
1704 : :
1705 : : !Arguments ------------------------------------
1706 : : class(basemat_t),target,intent(inout) :: mat
1707 : : character(len=*), intent(in) :: gpu_action
1708 : :
1709 : : !Local variables-------------------------------
1710 : : #ifdef HAVE_OPENMP_OFFLOAD
1711 : : real(sp), contiguous, pointer :: buf_real_sp(:,:)
1712 : : real(dp), contiguous, pointer :: buf_real_dp(:,:)
1713 : : complex(sp), contiguous, pointer :: buf_cplx_sp(:,:)
1714 : : complex(dp), contiguous, pointer :: buf_cplx_dp(:,:)
1715 : : #endif
1716 : : ! *********************************************************************
1717 : :
1718 [ # # ]: 0 : if (.not. string_in(gpu_action, "None, alloc, alloc_zero, delete, update_from, update_to")) then
1719 : 0 : ABI_ERROR(sjoin("Invalid gpu_action", gpu_action))
1720 : : ABI_UNUSED(mat%size_local(1))
1721 : : end if
1722 : :
1723 : : if (gpu_action == "None") return
1724 : :
1725 : : #ifdef HAVE_OPENMP_OFFLOAD
1726 : : select type (mat)
1727 : : class is (slkmat_dp_t)
1728 : : if (allocated(mat%buffer_cplx)) then
1729 : : buf_cplx_dp => mat%buffer_cplx
1730 : : if (string_in(gpu_action, "alloc, alloc_zero")) then
1731 : : !$OMP TARGET ENTER DATA MAP(alloc:buf_cplx_dp)
1732 : : if (gpu_action == "alloc_zero") call gpu_set_to_zero_complex(mat%buffer_cplx, mat%bufsize)
1733 : : else if (gpu_action == "delete") then !.and. c_associated(xomp_get_mapped_ptr(c_loc(buf_cplx_dp))
1734 : : !$OMP TARGET EXIT DATA MAP(delete:buf_cplx_dp)
1735 : : else if (gpu_action == "update_from") then
1736 : : !$OMP TARGET UPDATE FROM(buf_cplx_dp)
1737 : : else if (gpu_action == "update_to") then
1738 : : !$OMP TARGET UPDATE TO(buf_cplx_dp)
1739 : : end if
1740 : : end if
1741 : : if (allocated(mat%buffer_real)) then
1742 : : buf_real_dp => mat%buffer_real
1743 : : if (string_in(gpu_action, "alloc, alloc_zero")) then
1744 : : !$OMP TARGET ENTER DATA MAP(alloc:buf_real_dp)
1745 : : if (gpu_action == "alloc_zero") call gpu_set_to_zero(mat%buffer_real, mat%bufsize)
1746 : : else if (gpu_action == "delete") then !.and. c_associated(xomp_get_mapped_ptr(c_loc(buf_real_dp))
1747 : : !$OMP TARGET EXIT DATA MAP(delete:buf_real_dp)
1748 : : else if (gpu_action == "update_from") then
1749 : : !$OMP TARGET UPDATE FROM(buf_real_dp)
1750 : : else if (gpu_action == "update_to") then
1751 : : !$OMP TARGET UPDATE TO(buf_real_dp)
1752 : : end if
1753 : : end if
1754 : :
1755 : : class is (slkmat_sp_t)
1756 : : if (allocated(mat%buffer_cplx)) then
1757 : : buf_cplx_sp => mat%buffer_cplx
1758 : : if (string_in(gpu_action, "alloc, alloc_zero")) then
1759 : : !$OMP TARGET ENTER DATA MAP(alloc:buf_cplx_sp)
1760 : : if (gpu_action == "alloc_zero") call gpu_set_to_zero_complex_sp(mat%buffer_cplx, mat%bufsize)
1761 : : else if (gpu_action == "delete") then !.and. c_associated(xomp_get_mapped_ptr(c_loc(buf_cplx_sp))
1762 : : !$OMP TARGET EXIT DATA MAP(delete:buf_cplx_sp)
1763 : : else if (gpu_action == "update_from") then
1764 : : !$OMP TARGET UPDATE FROM(buf_cplx_sp)
1765 : : else if (gpu_action == "update_to") then
1766 : : !$OMP TARGET UPDATE TO(buf_cplx_sp)
1767 : : end if
1768 : : end if
1769 : : if (allocated(mat%buffer_real)) then
1770 : : buf_real_sp => mat%buffer_real
1771 : : if (string_in(gpu_action, "alloc, alloc_zero")) then
1772 : : !$OMP TARGET ENTER DATA MAP(alloc:buf_real_sp)
1773 : : if (gpu_action == "alloc_zero") call gpu_set_to_zero_sp(mat%buffer_real, mat%bufsize)
1774 : : else if (gpu_action == "delete") then !.and. c_associated(xomp_get_mapped_ptr(c_loc(buf_real_sp))
1775 : : !$OMP TARGET EXIT DATA MAP(delete:buf_real_sp)
1776 : : else if (gpu_action == "update_from") then
1777 : : !$OMP TARGET UPDATE FROM(buf_real_sp)
1778 : : else if (gpu_action == "update_to") then
1779 : : !$OMP TARGET UPDATE TO(buf_real_sp)
1780 : : end if
1781 : : end if
1782 : : end select
1783 : : #endif
1784 : :
1785 : : end subroutine basemat_gpu_map
1786 : : !!***
1787 : :
1788 : : !----------------------------------------------------------------------
1789 : :
1790 : : !!****f* m_slk/slk_array_locmem_mb
1791 : : !! NAME
1792 : : !! slk_array_locmem_mb
1793 : : !!
1794 : : !! FUNCTION
1795 : : !! Elemental function to compute the memory allocated for an array of slkmat_dp_t elements
1796 : : !! Usage: mem_mb = sum(mat_array)
1797 : : !!
1798 : : !! SOURCE
1799 : :
1800 : 0 : elemental real(dp) function slk_array_locmem_mb(mat) result(mem_mb)
1801 : : class(basemat_t),intent(in) :: mat
1802 : 0 : mem_mb = mat%locmem_mb()
1803 : 0 : end function slk_array_locmem_mb
1804 : : !!***
1805 : :
1806 : : !----------------------------------------------------------------------
1807 : :
1808 : : !!****f* m_slk/block_dist_1d
1809 : : !! NAME
1810 : : !! block_dist_1d
1811 : : !!
1812 : : !! FUNCTION
1813 : : !! Return block size for one-dimensional block column (row) distribution.
1814 : : !! Mainly used to assign blocks of contiguous columns (rows) of a matrix to successive processes
1815 : : !! when a 1d grid is employed.
1816 : : !!
1817 : : !! It is usually interfaced with CPP macros, e.g:
1818 : : !!
1819 : : !! ABI_CHECK(block_dist_1d(mat_size, nproc, block_size, msg), msg)
1820 : : !!
1821 : : !! INPUTS
1822 : : !! mat_size=Size of the matrix (either number of rows or number of colums)
1823 : : !! nproc=Number of processoes in the 1D scalapack grid
1824 : : !!
1825 : : !! OUTPUT
1826 : : !! ok= Boolean flag with exit status (idle processes are not allowed).
1827 : : !! block_size=Size of the block along this axis needed for one-dimensional block distribution
1828 : : !! msg=Error message (if not ok)
1829 : : !!
1830 : : !! SOURCE
1831 : :
1832 : 0 : logical function block_dist_1d(mat_size, nproc, block_size, msg) result (ok)
1833 : :
1834 : : !Arguments ------------------------------------
1835 : : integer, intent(in) :: mat_size, nproc
1836 : : integer,intent(out) :: block_size
1837 : : character(len=*),intent(out) :: msg
1838 : : ! *********************************************************************
1839 : :
1840 : 0 : ok = .True.; msg = ""
1841 : : !block_size = 1; return
1842 : :
1843 : 0 : block_size = mat_size / nproc
1844 [ # # ]: 0 : if (block_size == 0) then
1845 : 0 : ok = .False.
1846 : : write(msg, "(2(a,i0), 2a)") &
1847 : 0 : "The number of MPI processors: ", nproc, " exceeeds the number of rows (columms) of the matrix: ", mat_size, ch10, &
1848 : 0 : "Decrease the number of MPI processes for the scalapack level."
1849 : 0 : return
1850 : : end if
1851 : :
1852 [ # # ]: 0 : if (mod(mat_size, nproc) /= 0) block_size = block_size + 1
1853 : :
1854 [ # # ]: 0 : end function block_dist_1d
1855 : : !!***
1856 : :
1857 : : !----------------------------------------------------------------------
1858 : :
1859 : : !!****f* m_slk/slk_has_elpa
1860 : : !! NAME
1861 : : !! slk_has_elpa
1862 : : !!
1863 : : !! FUNCTION
1864 : : !! Return True if ELPA support is activated
1865 : : !!
1866 : : !! SOURCE
1867 : :
1868 : 0 : pure logical function slk_has_elpa() result (ans)
1869 : :
1870 : 0 : ans = .False.
1871 : : #ifdef HAVE_LINALG_ELPA
1872 : : ans = .True.
1873 : : #endif
1874 : :
1875 : 0 : end function slk_has_elpa
1876 : : !!***
1877 : :
1878 : : !----------------------------------------------------------------------
1879 : :
1880 : : !!****f* m_slk/matrix_get_local_cplx
1881 : : !! NAME
1882 : : !! matrix_get_local_cplx
1883 : : !!
1884 : : !! FUNCTION
1885 : : !! Returns a local matrix coefficient of complex type.
1886 : : !! Access to a component thanks to its local indices
1887 : : !!
1888 : : !! INPUTS
1889 : : !! matrix= the matrix to process
1890 : : !! i= row in the matrix
1891 : : !! j= column in the matrix
1892 : : !!
1893 : : !! OUTPUT
1894 : : !! The value of the local matrix.
1895 : : !!
1896 : : !! SOURCE
1897 : :
1898 : 0 : pure complex(dpc) function matrix_get_local_cplx(matrix, i, j)
1899 : :
1900 : : !Arguments ------------------------------------
1901 : : class(slkmat_dp_t),intent(in) :: matrix
1902 : : integer, intent(in) :: i,j
1903 : : ! *********************************************************************
1904 : :
1905 : 0 : matrix_get_local_cplx = matrix%buffer_cplx(i,j)
1906 : :
1907 : 0 : end function matrix_get_local_cplx
1908 : : !!***
1909 : :
1910 : : !----------------------------------------------------------------------
1911 : :
1912 : : !!****f* m_slk/matrix_get_local_real
1913 : : !! NAME
1914 : : !! matrix_get_local_real
1915 : : !!
1916 : : !! FUNCTION
1917 : : !! Returns a local matrix coefficient of double precision type.
1918 : : !!
1919 : : !! INPUTS
1920 : : !! matrix= the matrix to process
1921 : : !! i= row in the matrix
1922 : : !! j= column in the matrix
1923 : : !!
1924 : : !! SOURCE
1925 : :
1926 : 0 : pure real(dp) function matrix_get_local_real(matrix,i,j)
1927 : :
1928 : : !Arguments ------------------------------------
1929 : : class(slkmat_dp_t),intent(in) :: matrix
1930 : : integer, intent(in) :: i,j
1931 : : ! *********************************************************************
1932 : :
1933 : 0 : matrix_get_local_real = matrix%buffer_real(i,j)
1934 : :
1935 : 0 : end function matrix_get_local_real
1936 : : !!***
1937 : :
1938 : : !----------------------------------------------------------------------
1939 : :
1940 : : !!****f* m_slk/matrix_set_local_cplx
1941 : : !! NAME
1942 : : !! matrix_set_local_cplx
1943 : : !!
1944 : : !! FUNCTION
1945 : : !! Sets a local matrix coefficient of complex type.
1946 : : !! -------------------------------------------------------
1947 : : !! Positioning of a component of a matrix thanks to its local indices
1948 : : !! -------------------------------------------------------
1949 : : !!
1950 : : !! INPUTS
1951 : : !! i= row in the matrix
1952 : : !! j= column in the matrix
1953 : : !! value= the value to set
1954 : : !!
1955 : : !! SIDE EFFECTS
1956 : : !! matrix%buffer_cplx(i,j) filled with value
1957 : : !!
1958 : : !! SOURCE
1959 : :
1960 : 0 : pure subroutine matrix_set_local_cplx(matrix,i,j,value)
1961 : :
1962 : : !Arguments ------------------------------------
1963 : : class(slkmat_dp_t),intent(inout) :: matrix
1964 : : integer, intent(in) :: i,j
1965 : : complex(dp), intent(in) :: value
1966 : : ! *********************************************************************
1967 : :
1968 : 0 : matrix%buffer_cplx(i,j) = value
1969 : :
1970 : 0 : end subroutine matrix_set_local_cplx
1971 : : !!***
1972 : :
1973 : : !----------------------------------------------------------------------
1974 : :
1975 : : !!****f* m_slk/matrix_set_local_real
1976 : : !! NAME
1977 : : !! matrix_set_local_real
1978 : : !!
1979 : : !! FUNCTION
1980 : : !! Sets a local matrix coefficient of double precision type.
1981 : : !!
1982 : : !! INPUTS
1983 : : !! i= row in the matrix
1984 : : !! j= column in the matrix
1985 : : !! value= the value to set
1986 : : !!
1987 : : !! SIDE EFFECTS
1988 : : !! matrix%buffer_real(i,j) set to value
1989 : : !!
1990 : : !! SOURCE
1991 : :
1992 : 0 : pure subroutine matrix_set_local_real(matrix, i, j, value)
1993 : :
1994 : : !Arguments ------------------------------------
1995 : : class(slkmat_dp_t),intent(inout) :: matrix
1996 : : integer, intent(in) :: i,j
1997 : : real(dp), intent(in) :: value
1998 : : ! *********************************************************************
1999 : :
2000 : 0 : matrix%buffer_real(i,j) = value
2001 : :
2002 : 0 : end subroutine matrix_set_local_real
2003 : : !!***
2004 : :
2005 : : !----------------------------------------------------------------------
2006 : :
2007 : : !!****f* m_slk/idx_loc
2008 : : !! NAME
2009 : : !! idx_loc
2010 : : !!
2011 : : !! FUNCTION
2012 : : !! Return local indices from global indices, **independently** of the processor.
2013 : : !!
2014 : : !! INPUTS
2015 : : !! matrix= the matrix to process
2016 : : !! i= row in the matrix
2017 : : !! j= column in the matrix
2018 : : !!
2019 : : !! OUTPUT
2020 : : !! iloc= local row of the coefficient
2021 : : !! jloc= local column of the coefficient
2022 : : !!
2023 : : !! SOURCE
2024 : :
2025 : 0 : subroutine basemat_idx_loc(matrix, i, j, iloc, jloc)
2026 : :
2027 : : !Arguments ------------------------------------
2028 : : class(basemat_t),intent(in) :: matrix
2029 : : integer, intent(in) :: i,j
2030 : : integer, intent(out) :: iloc,jloc
2031 : : ! *********************************************************************
2032 : :
2033 : 0 : iloc = glob_loc__(matrix, i, 1)
2034 : 0 : jloc = glob_loc__(matrix, j, 2)
2035 : :
2036 : 0 : end subroutine basemat_idx_loc
2037 : : !!***
2038 : :
2039 : : !----------------------------------------------------------------------
2040 : :
2041 : : !!****f* m_slk/glob_loc__
2042 : : !! NAME
2043 : : !! glob_loc__
2044 : : !!
2045 : : !! FUNCTION
2046 : : !! Returns the global location of a matrix coefficient.
2047 : : !!
2048 : : !! INPUTS
2049 : : !! matrix= the matrix to process
2050 : : !! idx= number of rows in the distributed matrix
2051 : : !! lico= block size index
2052 : : !!
2053 : : !! SOURCE
2054 : :
2055 : : integer function glob_loc__(matrix, idx, lico)
2056 : :
2057 : : !Arguments ------------------------------------
2058 : : class(basemat_t),intent(in) :: matrix
2059 : : integer, intent(in) :: idx, lico
2060 : : ! *********************************************************************
2061 : :
2062 : : #ifdef HAVE_LINALG_SCALAPACK
2063 : : glob_loc__ = NUMROC(idx, matrix%size_blocs(lico), &
2064 : : matrix%processor%coords(lico), 0, matrix%processor%grid%dims(lico))
2065 : : #endif
2066 : :
2067 : : end function glob_loc__
2068 : : !!***
2069 : :
2070 : : !----------------------------------------------------------------------
2071 : :
2072 : : !!****f* m_slk/basemat_glob2loc
2073 : : !! NAME
2074 : : !! basemat_glob2loc
2075 : : !!
2076 : : !! FUNCTION
2077 : : !! Determine the local indices of an element from its global indices and return haveit bool flag.
2078 : : !!
2079 : : !! INPUTS
2080 : : !! iloc= local row index.
2081 : : !! jloc= local column index.
2082 : : !!
2083 : : !! OUTPUT
2084 : : !! iloc= row in the matrix
2085 : : !! jloc= column in the matrix
2086 : : !! haveit= True if (iglob, jglob) is stored on this proc
2087 : : !!
2088 : : !! SOURCE
2089 : :
2090 : 0 : subroutine basemat_glob2loc(mat, iglob, jglob, iloc, jloc, haveit)
2091 : :
2092 : : !Arguments ------------------------------------
2093 : : class(basemat_t),intent(in) :: mat
2094 : : integer, intent(in) :: iglob, jglob
2095 : : integer, intent(out) :: iloc, jloc
2096 : : logical,intent(out) :: haveit
2097 : :
2098 : : !Local variables-------------------------------
2099 : : integer :: row_src, col_src
2100 : : ! *********************************************************************
2101 : :
2102 : : #ifdef HAVE_LINALG_SCALAPACK
2103 : : ! SUBROUTINE INFOG2L( GRINDX, GCINDX, DESC, NPROW, NPCOL, MYROW, MYCOL, LRINDX, LCINDX, RSRC, CSRC)
2104 : :
2105 : : call INFOG2L(iglob, jglob, mat%desc, mat%processor%grid%dims(1), mat%processor%grid%dims(2), &
2106 : : mat%processor%coords(1), mat%processor%coords(2), iloc, jloc, row_src, col_src)
2107 : :
2108 : : haveit = all(mat%processor%coords == [row_src, col_src])
2109 : : #endif
2110 : :
2111 : 0 : end subroutine basemat_glob2loc
2112 : : !!***
2113 : :
2114 : : !----------------------------------------------------------------------
2115 : :
2116 : : !!****f* m_slk/basemat_loc2glob
2117 : : !! NAME
2118 : : !! basemat_loc2glob
2119 : : !!
2120 : : !! FUNCTION
2121 : : !! Determine the global indices of an element from its local indices.
2122 : : !!
2123 : : !! INPUTS
2124 : : !! matrix= the matrix to process.
2125 : : !! iloc= local row index.
2126 : : !! jloc= local column index.
2127 : : !!
2128 : : !! OUTPUT
2129 : : !! i= row in the matrix
2130 : : !! j= column in the matrix
2131 : : !!
2132 : : !! SOURCE
2133 : :
2134 : 0 : pure subroutine basemat_loc2glob(matrix, iloc, jloc, i, j)
2135 : :
2136 : : !Arguments ------------------------------------
2137 : : class(basemat_t),intent(in) :: matrix
2138 : : integer, intent(in) :: iloc,jloc
2139 : : integer, intent(out) :: i,j
2140 : : ! *********************************************************************
2141 : :
2142 : 0 : i = loc_glob__(matrix, matrix%processor, iloc, 1)
2143 : 0 : j = loc_glob__(matrix, matrix%processor, jloc, 2)
2144 : :
2145 : 0 : end subroutine basemat_loc2glob
2146 : : !!***
2147 : :
2148 : : !!****f* m_slk/basemat_loc2grow
2149 : : !! NAME
2150 : : !! basemat_loc2grow
2151 : : !!
2152 : : !! FUNCTION
2153 : : !! Determine the global row index from the local index
2154 : : !!
2155 : : !! INPUTS
2156 : : !! matrix= the matrix to process.
2157 : : !! iloc= local row index.
2158 : : !!
2159 : : !! SOURCE
2160 : :
2161 : 0 : integer pure function basemat_loc2grow(matrix, iloc) result(iglob)
2162 : :
2163 : : !Arguments ------------------------------------
2164 : : class(basemat_t),intent(in) :: matrix
2165 : : integer, intent(in) :: iloc
2166 : : ! *********************************************************************
2167 : :
2168 : 0 : iglob = loc_glob__(matrix, matrix%processor, iloc, 1)
2169 : :
2170 : 0 : end function basemat_loc2grow
2171 : : !!***
2172 : :
2173 : : !!****f* m_slk/basemat_loc2col
2174 : : !! NAME
2175 : : !! basemat_loc2col
2176 : : !!
2177 : : !! FUNCTION
2178 : : !! Determine the global column index of an element from the local index
2179 : : !!
2180 : : !! INPUTS
2181 : : !! matrix= the matrix to process.
2182 : : !! jloc= local column index.
2183 : : !!
2184 : : !! SOURCE
2185 : :
2186 : 0 : integer pure function basemat_loc2col(matrix, jloc) result(jglob)
2187 : :
2188 : : !Arguments ------------------------------------
2189 : : class(basemat_t),intent(in) :: matrix
2190 : : integer, intent(in) :: jloc
2191 : : ! *********************************************************************
2192 : :
2193 : 0 : jglob = loc_glob__(matrix, matrix%processor, jloc, 2)
2194 : :
2195 : 0 : end function basemat_loc2col
2196 : : !!***
2197 : :
2198 : : !----------------------------------------------------------------------
2199 : :
2200 : : !!****f* m_slk/loc_glob__
2201 : : !! NAME
2202 : : !! loc_glob__
2203 : : !!
2204 : : !! FUNCTION
2205 : : !! Determine the global index from a local index (row or column) as a function of a given processor
2206 : : !!
2207 : : !! INPUTS
2208 : : !! matrix= the matrix to process
2209 : : !! proc= descriptor of a processor
2210 : : !! idx= number of rows in the distributed matrix
2211 : : !! lico= block size index. 1 for rows. 2 for columns
2212 : : !!
2213 : : !! SOURCE
2214 : :
2215 : 0 : integer pure function loc_glob__(matrix, proc, idx, lico)
2216 : :
2217 : : !Arguments ------------------------------------
2218 : : class(basemat_t),intent(in) :: matrix
2219 : : class(slk_processor_t),intent(in) :: proc
2220 : : integer, intent(in) :: idx,lico
2221 : :
2222 : : !Local variables-------------------------------
2223 : : integer :: nbcyc, rest, nblocs
2224 : : ! *********************************************************************
2225 : :
2226 : 0 : nbcyc = INT((idx-1) / matrix%size_blocs(lico))
2227 : 0 : rest = MOD(idx-1, matrix%size_blocs(lico))
2228 : 0 : nblocs = nbcyc * proc%grid%dims(lico) + proc%coords(lico)
2229 : :
2230 : 0 : loc_glob__ = nblocs * matrix%size_blocs(lico) + rest + 1
2231 : :
2232 : 0 : end function loc_glob__
2233 : : !!***
2234 : :
2235 : : !----------------------------------------------------------------------
2236 : :
2237 : : !!****f* m_slk/slkmat_dp_from_global_pack
2238 : : !! NAME
2239 : : !! slkmat_dp_from_global_pack
2240 : : !!
2241 : : !! FUNCTION
2242 : : !! Routine to fill a SCALAPACK matrix from a global PACKED matrix.
2243 : : !!
2244 : : !! INPUTS
2245 : : !! istwf_k= 2 if we have a real matrix else complex.
2246 : : !! glob_mat_pack= one-dimensional array with packed matrix.
2247 : : !!
2248 : : !! SIDE EFFECTS
2249 : : !! matrix= the matrix to process
2250 : : !!
2251 : : !! SOURCE
2252 : :
2253 : 0 : subroutine slkmat_dp_from_global_pack(matrix, glob_mat_pack, istwf_k)
2254 : :
2255 : : !Arguments ------------------------------------
2256 : : class(slkmat_dp_t),intent(inout) :: matrix
2257 : : integer,intent(in) :: istwf_k
2258 : : real(dp),intent(in) :: glob_mat_pack(*)
2259 : :
2260 : : !Local variables-------------------------------
2261 : : integer :: i,j,iglob,jglob,ind
2262 : : real(dp) :: val_real
2263 : : complex(dp) :: val_cplx
2264 : : ! *********************************************************************
2265 : :
2266 [ # # ]: 0 : do i=1,matrix%size_local(1)
2267 [ # # ]: 0 : do j=1,matrix%size_local(2)
2268 : 0 : call matrix%loc2glob(i, j, iglob, jglob)
2269 : :
2270 [ # # ]: 0 : if (istwf_k/=2) then
2271 : 0 : ind = jglob*(jglob-1)+2*iglob-1
2272 : 0 : val_cplx = dcmplx(glob_mat_pack(ind),glob_mat_pack(ind+1))
2273 : 0 : call matrix_set_local_cplx(matrix,i,j,val_cplx)
2274 : : else
2275 : 0 : ind = (jglob*(jglob-1))/2 + iglob
2276 : 0 : val_real = glob_mat_pack(ind)
2277 : 0 : call matrix_set_local_real(matrix,i,j,val_real)
2278 : : end if
2279 : :
2280 : : end do
2281 : : end do
2282 : :
2283 : 0 : end subroutine slkmat_dp_from_global_pack
2284 : : !!***
2285 : :
2286 : : !----------------------------------------------------------------------
2287 : :
2288 : : !!****f* m_slk/slkmat_dp_from_global_sym
2289 : : !! NAME
2290 : : !! slkmat_dp_from_global_sym
2291 : : !!
2292 : : !! FUNCTION
2293 : : !!
2294 : : !! INPUTS
2295 : : !! istwf_k= 2 if we have a real matrix else complex.
2296 : : !! glob_vec_pack= one-dimensional array in packed form
2297 : : !!
2298 : : !! SIDE EFFECTS
2299 : : !! matrix= the matrix to process
2300 : : !!
2301 : : !! SOURCE
2302 : :
2303 [ # # ]: 0 : subroutine slkmat_dp_from_global_sym(matrix, glob_vec_pack, istwf_k)
2304 : :
2305 : : !Arguments ------------------------------------
2306 : : class(slkmat_dp_t),intent(inout) :: matrix
2307 : : real(dp),intent(in) :: glob_vec_pack(:)
2308 : : integer,intent(in) :: istwf_k
2309 : :
2310 : : !Local variables-------------------------------
2311 : : integer :: i,j,iglob,jglob,ind
2312 : : complex(dp):: val_cplx
2313 : : real(dp) ::val_real
2314 : : ! *********************************************************************
2315 : :
2316 [ # # ]: 0 : do i=1,matrix%size_local(1)
2317 [ # # ]: 0 : do j=1,matrix%size_local(2)
2318 : 0 : call matrix%loc2glob(i,j,iglob,jglob)
2319 [ # # ]: 0 : if (jglob < iglob) then
2320 : 0 : ind = iglob*(iglob-1)+2*jglob-1
2321 : : else
2322 : 0 : ind = jglob*(jglob-1)+2*iglob-1
2323 : : end if
2324 [ # # ]: 0 : if (istwf_k /= 2) then
2325 : 0 : val_cplx = dcmplx(glob_vec_pack(ind),glob_vec_pack(ind+1))
2326 [ # # ]: 0 : if (jglob < iglob) then
2327 : 0 : call matrix_set_local_cplx(matrix,i,j,conjg(val_cplx))
2328 : : else
2329 : 0 : call matrix_set_local_cplx(matrix,i,j,val_cplx)
2330 : : end if
2331 : : else
2332 : 0 : ind = (ind + 1) / 2
2333 : 0 : val_real = glob_vec_pack(ind)
2334 : 0 : call matrix_set_local_real(matrix,i,j,val_real)
2335 : : end if
2336 : : end do
2337 : : end do
2338 : :
2339 : 0 : end subroutine slkmat_dp_from_global_sym
2340 : : !!***
2341 : :
2342 : : !----------------------------------------------------------------------
2343 : :
2344 : : !!****f* m_slk/slkmat_dp_from_real_glob
2345 : : !! NAME
2346 : : !! slkmat_dp_from_real_glob
2347 : : !!
2348 : : !! FUNCTION
2349 : : !! Routine to fill a SCALAPACK matrix from a real global matrix (FULL STORAGE MODE)
2350 : : !!
2351 : : !! INPUTS
2352 : : !! istwf_k= 2 if we have a real matrix else complex.
2353 : : !! glob_mat= a real matrix
2354 : : !!
2355 : : !! SIDE EFFECTS
2356 : : !! matrix= the matrix to process
2357 : : !!
2358 : : !! SOURCE
2359 : :
2360 [ # # ]: 0 : subroutine slkmat_dp_from_real_glob(matrix, glob_mat, istwf_k)
2361 : :
2362 : : !Arguments ------------------------------------
2363 : : class(slkmat_dp_t),intent(inout) :: matrix
2364 : : integer,intent(in) :: istwf_k
2365 : : !arrays
2366 : : real(dp),intent(in) :: glob_mat(:,:)
2367 : :
2368 : : !Local variables-------------------------------
2369 : : integer :: i,j,iglob,jglob
2370 : : real(dp) :: val
2371 : : ! *********************************************************************
2372 : :
2373 : : ABI_UNUSED(istwf_k)
2374 : :
2375 [ # # ]: 0 : do i=1,matrix%size_local(1)
2376 [ # # ]: 0 : do j=1,matrix%size_local(2)
2377 : 0 : call matrix%loc2glob(i, j, iglob, jglob)
2378 : 0 : val = glob_mat(iglob, jglob)
2379 : 0 : call matrix_set_local_real(matrix,i,j,val)
2380 : : end do
2381 : : end do
2382 : :
2383 : 0 : end subroutine slkmat_dp_from_real_glob
2384 : : !!***
2385 : :
2386 : : !----------------------------------------------------------------------
2387 : :
2388 : : !!****f* m_slk/slkmat_dp_from_complex_glob
2389 : : !! NAME
2390 : : !! slkmat_dp_from_complex_glob
2391 : : !!
2392 : : !! FUNCTION
2393 : : !! Routine to fill a SCALAPACK matrix from a global matrix (FULL STORAGE MODE)
2394 : : !!
2395 : : !! INPUTS
2396 : : !! istwf_k= 2 if we have a real matrix else complex.
2397 : : !! glob_mat= a complex matrix
2398 : : !!
2399 : : !! SIDE EFFECTS
2400 : : !! matrix= the matrix to process
2401 : : !!
2402 : : !! SOURCE
2403 : :
2404 [ # # ]: 0 : subroutine slkmat_dp_from_complex_glob(matrix, glob_mat, istwf_k)
2405 : :
2406 : : !Arguments ------------------------------------
2407 : : class(slkmat_dp_t),intent(inout) :: matrix
2408 : : integer,intent(in) :: istwf_k
2409 : : !arrays
2410 : : real(dp),intent(in) :: glob_mat(:,:)
2411 : :
2412 : : !Local variables-------------------------------
2413 : : integer :: i,j,iglob,jglob
2414 : : complex(dpc) :: val
2415 : : ! *********************************************************************
2416 : :
2417 : : ABI_UNUSED(istwf_k)
2418 : :
2419 [ # # ]: 0 : do i=1,matrix%size_local(1)
2420 [ # # ]: 0 : do j=1,matrix%size_local(2)
2421 : 0 : call matrix%loc2glob(i, j, iglob, jglob)
2422 : 0 : val = dcmplx(glob_mat(2*iglob-1, jglob),glob_mat(2*iglob, jglob))
2423 : 0 : call matrix_set_local_cplx(matrix,i,j,val)
2424 : : end do
2425 : : end do
2426 : :
2427 : 0 : end subroutine slkmat_dp_from_complex_glob
2428 : : !!***
2429 : :
2430 : : !----------------------------------------------------------------------
2431 : :
2432 : : !!****f* m_slk/slkmat_dp_to_global_pack
2433 : : !! NAME
2434 : : !! slkmat_dp_to_global_pack
2435 : : !!
2436 : : !! FUNCTION
2437 : : !! Inserts a ScaLAPACK matrix into a global one in PACKED storage mode.
2438 : : !!
2439 : : !! INPUTS
2440 : : !! matrix= the matrix to process
2441 : : !! istwf_k= 2 if we have a real matrix else complex.
2442 : : !! nband_k= number of bands at this k point for that spin polarization
2443 : : !!
2444 : : !! SIDE EFFECTS
2445 : : !! glob_pack= one-dimensional array
2446 : : !!
2447 : : !! SOURCE
2448 : :
2449 : 0 : subroutine slkmat_dp_to_global_pack(matrix, glob_pack, istwf_k)
2450 : :
2451 : : !Arguments ------------------------------------
2452 : : class(slkmat_dp_t),intent(in) :: matrix
2453 : : integer,intent(in) :: istwf_k !,nband_k
2454 : : real(dp),intent(inout) :: glob_pack(*) !(nband_k*(nband_k+1))
2455 : :
2456 : : !Local variables-------------------------------
2457 : : integer :: i,j,iglob,jglob,ind
2458 : : ! *********************************************************************
2459 : :
2460 [ # # ]: 0 : do i=1,matrix%size_local(1)
2461 [ # # ]: 0 : do j=1,matrix%size_local(2)
2462 : 0 : call matrix%loc2glob(i, j, iglob, jglob)
2463 : :
2464 : 0 : ind = jglob*(jglob-1)+2*iglob-1
2465 [ # # ]: 0 : if (ind <= matrix%size_global(2)*(matrix%size_global(2)+1)) then
2466 [ # # ]: 0 : if (istwf_k/=2) then
2467 : 0 : glob_pack(ind) = real(matrix_get_local_cplx(matrix,i,j))
2468 : 0 : glob_pack(ind+1) = aimag(matrix_get_local_cplx(matrix,i,j))
2469 : : else
2470 : 0 : ind=(ind+1)/2 !real packed storage
2471 : 0 : glob_pack(ind) = matrix_get_local_real(matrix,i,j)
2472 : : end if
2473 : : end if
2474 : : end do
2475 : : end do
2476 : :
2477 : 0 : end subroutine slkmat_dp_to_global_pack
2478 : : !!***
2479 : :
2480 : : !----------------------------------------------------------------------
2481 : :
2482 : : !!****f* m_slk/slkmat_dp_to_real_glob
2483 : : !! NAME
2484 : : !! slkmat_dp_to_real_glob
2485 : : !!
2486 : : !! FUNCTION
2487 : : !! Inserts a ScaLAPACK matrix into a real matrix in FULL STORAGE MODE.
2488 : : !!
2489 : : !! INPUTS
2490 : : !! matrix= the matrix to process
2491 : : !! istwf_k= 2 if we have a real matrix else complex.
2492 : : !!
2493 : : !! SIDE EFFECTS
2494 : : !! glob_mat= the matrix to fill
2495 : : !!
2496 : : !! SOURCE
2497 : :
2498 [ # # ]: 0 : subroutine slkmat_dp_to_real_glob(matrix, glob_mat, istwf_k)
2499 : :
2500 : : !Arguments ------------------------------------
2501 : : class(slkmat_dp_t),intent(in) :: matrix
2502 : : integer,intent(in) :: istwf_k
2503 : : !arrays
2504 : : real(dp),intent(inout) :: glob_mat(:,:)
2505 : :
2506 : : !Local variables-------------------------------
2507 : : integer :: i,j,iglob,jglob
2508 : : ! *********************************************************************
2509 : :
2510 : : ABI_UNUSED(istwf_k)
2511 : :
2512 [ # # ]: 0 : do i=1,matrix%size_local(1)
2513 [ # # ]: 0 : do j=1,matrix%size_local(2)
2514 : 0 : call matrix%loc2glob(i, j, iglob, jglob)
2515 : 0 : glob_mat(iglob,jglob) = matrix_get_local_real(matrix,i,j)
2516 : : end do
2517 : : end do
2518 : :
2519 : 0 : end subroutine slkmat_dp_to_real_glob
2520 : : !!***
2521 : :
2522 : : !----------------------------------------------------------------------
2523 : :
2524 : : !!****f* m_slk/slkmat_dp_to_complex_glob
2525 : : !! NAME
2526 : : !! slkmat_dp_to_complex_glob
2527 : : !!
2528 : : !! FUNCTION
2529 : : !! Inserts a ScaLAPACK matrix into a complex matrix in FULL STORAGE MODE.
2530 : : !!
2531 : : !! INPUTS
2532 : : !! matrix= the matrix to process
2533 : : !! istwf_k= 2 if we have a real matrix else complex.
2534 : : !!
2535 : : !! SIDE EFFECTS
2536 : : !! glob_cmat= the matrix to fill
2537 : : !!
2538 : : !! SOURCE
2539 : :
2540 [ # # ]: 0 : subroutine slkmat_dp_to_complex_glob(matrix, glob_cmat, istwf_k)
2541 : :
2542 : : !Arguments ------------------------------------
2543 : : integer,intent(in) :: istwf_k
2544 : : class(slkmat_dp_t),intent(in) :: matrix
2545 : : !arrays
2546 : : complex(dpc),intent(inout) :: glob_cmat(:,:)
2547 : :
2548 : : !Local variables-------------------------------
2549 : : integer :: i,j,iglob,jglob
2550 : : ! *********************************************************************
2551 : :
2552 : : ABI_UNUSED(istwf_k)
2553 : :
2554 [ # # ]: 0 : do i=1,matrix%size_local(1)
2555 [ # # ]: 0 : do j=1,matrix%size_local(2)
2556 : 0 : call matrix%loc2glob(i, j, iglob, jglob)
2557 : 0 : glob_cmat(iglob,jglob) = matrix_get_local_cplx(matrix,i,j)
2558 : : end do
2559 : : end do
2560 : :
2561 : 0 : end subroutine slkmat_dp_to_complex_glob
2562 : : !!***
2563 : :
2564 : : !----------------------------------------------------------------------
2565 : :
2566 : : !!****f* m_slk/slkmat_dp_to_global
2567 : : !! NAME
2568 : : !! slkmat_dp_to_global
2569 : : !!
2570 : : !! FUNCTION
2571 : : !! Routine to fill a full matrix with respect to a SCALAPACK matrix.
2572 : : !!
2573 : : !! INPUTS
2574 : : !! matrix= the matrix to process
2575 : : !! istwf_k= 2 if we have a real matrix else complex.
2576 : : !!
2577 : : !! SIDE EFFECTS
2578 : : !! glob_mat= one-dimensional array
2579 : : !!
2580 : : !! SOURCE
2581 : :
2582 [ # # ]: 0 : subroutine slkmat_dp_to_global(matrix, glob_mat, istwf_k)
2583 : :
2584 : : !Arguments ------------------------------------
2585 : : class(slkmat_dp_t),intent(in) :: matrix
2586 : : integer,intent(in) :: istwf_k
2587 : : !arrays
2588 : : real(dp),intent(inout) :: glob_mat(:,:)
2589 : :
2590 : : !Local variables-------------------------------
2591 : : integer :: i,j,iglob,jglob,ind
2592 : : ! *********************************************************************
2593 : :
2594 [ # # ]: 0 : do i=1,matrix%size_local(1)
2595 [ # # ]: 0 : do j=1,matrix%size_local(2)
2596 : 0 : call matrix%loc2glob(i, j, iglob, jglob)
2597 : :
2598 [ # # ]: 0 : if (istwf_k/=2) then
2599 : 0 : ind=(iglob-1)*2+1
2600 : 0 : glob_mat(ind, jglob) = real(matrix_get_local_cplx(matrix,i,j))
2601 : 0 : glob_mat(ind+1,jglob) = aimag(matrix_get_local_cplx(matrix,i,j))
2602 : : else
2603 : 0 : ind=iglob
2604 : 0 : glob_mat(ind,jglob) = matrix_get_local_real(matrix,i,j)
2605 : : !glob_mat(ind+1,jglob) = 0._dp
2606 : : end if
2607 : :
2608 : : end do
2609 : : end do
2610 : :
2611 : 0 : end subroutine slkmat_dp_to_global
2612 : : !!***
2613 : :
2614 : : !----------------------------------------------------------------------
2615 : :
2616 : : !!****f* m_slk/slk_matrix_from_global_dpc_2D
2617 : : !! NAME
2618 : : !! slk_matrix_from_global_dpc_2D
2619 : : !!
2620 : : !! FUNCTION
2621 : : !! Routine to fill a complex SCALAPACK matrix with respect to a global matrix.
2622 : : !! target: Two-dimensional double precision complex matrix
2623 : : !!
2624 : : !! INPUTS
2625 : : !! glob_cmat=Two-dimensional array containing the global matrix.
2626 : : !! uplo=String specifying whether only the upper or lower triangular part of the global matrix is used:
2627 : : !! = "U": Upper triangular
2628 : : !! = "L": Lower triangular
2629 : : !! = "A": Full matrix (used for general complex matrices)
2630 : : !!
2631 : : !! SIDE EFFECTS
2632 : : !! mat<slkmat_dp_t>=The distributed matrix.
2633 : : !! %buffer_cplx=Local buffer containg the value this node is dealing with.
2634 : : !!
2635 : : !! SOURCE
2636 : :
2637 [ # # ]: 0 : subroutine slk_matrix_from_global_dpc_2D(mat, uplo, glob_cmat)
2638 : :
2639 : : !Arguments ------------------------------------
2640 : : !scalars
2641 : : class(slkmat_dp_t),intent(inout) :: mat
2642 : : character(len=*),intent(in) :: uplo
2643 : : !array
2644 : : complex(dpc),intent(in) :: glob_cmat(:,:)
2645 : :
2646 : : !Local variables-------------------------------
2647 : : integer :: ii, jj, iglob, jglob
2648 : : !************************************************************************
2649 : :
2650 [ # # ]: 0 : ABI_CHECK(allocated(mat%buffer_cplx), "%buffer_cplx not allocated")
2651 : :
2652 : 0 : select case (uplo(1:1))
2653 : :
2654 : : case ("A", "a")
2655 : : ! Full global matrix is used.
2656 [ # # ]: 0 : do jj=1,mat%size_local(2)
2657 [ # # ]: 0 : do ii=1,mat%size_local(1)
2658 : 0 : call mat%loc2glob(ii, jj, iglob, jglob)
2659 : 0 : mat%buffer_cplx(ii,jj) = glob_cmat(iglob,jglob)
2660 : : end do
2661 : : end do
2662 : :
2663 : : case ("U", "u")
2664 : : ! Only the upper triangle of the global matrix is used.
2665 [ # # ]: 0 : do jj=1,mat%size_local(2)
2666 [ # # ]: 0 : do ii=1,mat%size_local(1)
2667 : 0 : call mat%loc2glob(ii, jj, iglob, jglob)
2668 [ # # ]: 0 : if (jglob>=iglob) then
2669 : 0 : mat%buffer_cplx(ii,jj) = glob_cmat(iglob,jglob)
2670 : : else
2671 : 0 : mat%buffer_cplx(ii,jj) = DCONJG(glob_cmat(jglob,iglob))
2672 : : end if
2673 : : end do
2674 : : end do
2675 : :
2676 : : case ("L", "l")
2677 : : ! Only the lower triangle of the global matrix is used.
2678 [ # # ]: 0 : do jj=1,mat%size_local(2)
2679 [ # # ]: 0 : do ii=1,mat%size_local(1)
2680 : 0 : call mat%loc2glob(ii, jj, iglob, jglob)
2681 [ # # ]: 0 : if (jglob<=iglob) then
2682 : 0 : mat%buffer_cplx(ii,jj) = glob_cmat(iglob,jglob)
2683 : : else
2684 : 0 : mat%buffer_cplx(ii,jj) = DCONJG(glob_cmat(jglob,iglob))
2685 : : end if
2686 : : end do
2687 : : end do
2688 : :
2689 : : case default
2690 [ # # # # : 0 : ABI_BUG(" Wrong uplo: "//TRIM(uplo))
# # ]
2691 : : end select
2692 : :
2693 : 0 : end subroutine slk_matrix_from_global_dpc_2D
2694 : : !!***
2695 : :
2696 : : !----------------------------------------------------------------------
2697 : :
2698 : : !!****f* m_slk/slk_matrix_from_global_dpc_1Dp
2699 : : !! NAME
2700 : : !! slk_matrix_from_global_dpc_1Dp
2701 : : !!
2702 : : !! FUNCTION
2703 : : !! Routine to fill a complex SCALAPACK matrix with respect to a global matrix.
2704 : : !! target: double precision complex matrix in packed form.
2705 : : !!
2706 : : !! INPUTS
2707 : : !! glob_cmat_pack(n*(n+1)/2)=One-dimensional array containing the global matrix A packed columnwise in a linear array.
2708 : : !! The j-th column of A is stored in the array glob_cmat_pack as follows:
2709 : : !! if uplo = "U", glob_cmat_pack(i + (j-1)*j/2) = A(i,j) for 1<=i<=j;
2710 : : !! if uplo = "L", glob_cmat_pack(i + (j-1)*(2*n-j)/2) = A(i,j) for j<=i<=n.
2711 : : !! where n is the number of rows or columns in the global matrix.
2712 : : !! uplo=String specifying whether only the upper or lower triangular part of the global matrix is used:
2713 : : !! = "U": Upper triangular
2714 : : !! = "L": Lower triangular
2715 : : !!
2716 : : !! SIDE EFFECTS
2717 : : !! mat<slkmat_dp_t>=The distributed matrix.
2718 : : !! %buffer_cplx=Local buffer containg the value this node is dealing with.
2719 : : !!
2720 : : !! SOURCE
2721 : :
2722 [ # # ]: 0 : subroutine slk_matrix_from_global_dpc_1Dp(mat,uplo, glob_cmat_pack)
2723 : :
2724 : : !Arguments ------------------------------------
2725 : : !scalars
2726 : : class(slkmat_dp_t),intent(inout) :: mat
2727 : : character(len=*),intent(in) :: uplo
2728 : : !array
2729 : : complex(dpc),intent(in) :: glob_cmat_pack(:)
2730 : :
2731 : : !Local variables-------------------------------
2732 : : integer :: ii,jj,iglob,jglob,ind,n
2733 : : real(dp) :: szm
2734 : : !************************************************************************
2735 : :
2736 [ # # ]: 0 : ABI_CHECK(allocated(mat%buffer_cplx), "%buffer_cplx not allocated")
2737 : :
2738 : 0 : szm = SIZE(glob_cmat_pack)
2739 : 0 : n = NINT( (-1 + SQRT(one+8*szm) )*half )
2740 [ # # ]: 0 : if (n*(n+1)/2 /= SIZE(glob_cmat_pack)) then
2741 : 0 : ABI_ERROR("Buggy compiler")
2742 : : end if
2743 : :
2744 : 0 : select case (uplo(1:1))
2745 : :
2746 : : case ("U", "u")
2747 : : ! Only the upper triangle of the global matrix is used.
2748 [ # # ]: 0 : do jj=1,mat%size_local(2)
2749 [ # # ]: 0 : do ii=1,mat%size_local(1)
2750 : 0 : call mat%loc2glob(ii, jj, iglob, jglob)
2751 : :
2752 [ # # ]: 0 : if (jglob>=iglob) then
2753 : 0 : ind = iglob + jglob*(jglob-1)/2
2754 : 0 : mat%buffer_cplx(ii,jj) = glob_cmat_pack(ind)
2755 : : else
2756 : 0 : ind = jglob + iglob*(iglob-1)/2
2757 : 0 : mat%buffer_cplx(ii,jj) = DCONJG( glob_cmat_pack(ind) )
2758 : : end if
2759 : :
2760 : : end do
2761 : : end do
2762 : :
2763 : : case ("L", "l")
2764 : : ! Only the lower triangle of the global matrix is used.
2765 [ # # ]: 0 : do jj=1,mat%size_local(2)
2766 [ # # ]: 0 : do ii=1,mat%size_local(1)
2767 : 0 : call mat%loc2glob(ii, jj, iglob, jglob)
2768 : :
2769 [ # # ]: 0 : if (jglob<=iglob) then
2770 : 0 : ind = iglob + (jglob-1)*(2*n-jglob)/2
2771 : 0 : mat%buffer_cplx(ii,jj) = glob_cmat_pack(ind)
2772 : : else
2773 : 0 : ind = jglob + (iglob-1)*(2*n-iglob)/2
2774 : 0 : mat%buffer_cplx(ii,jj) = DCONJG( glob_cmat_pack(ind) )
2775 : : end if
2776 : : end do
2777 : : end do
2778 : :
2779 : : case default
2780 [ # # # # : 0 : ABI_BUG(" Wrong uplo: "//TRIM(uplo))
# ]
2781 : : end select
2782 : :
2783 : 0 : end subroutine slk_matrix_from_global_dpc_1Dp
2784 : : !!***
2785 : :
2786 : : !----------------------------------------------------------------------
2787 : :
2788 : : !!****f* m_slk/slk_matrix_to_global_dpc_2D
2789 : : !! NAME
2790 : : !! slk_matrix_to_global_dpc_2D
2791 : : !!
2792 : : !! FUNCTION
2793 : : !! Fill a global matrix with respect to a SCALAPACK matrix.
2794 : : !! target: Two-dimensional double precision complex matrix.
2795 : : !!
2796 : : !! INPUTS
2797 : : !! Slk_mat<slkmat_dp_t>=The distributed matrix.
2798 : : !! uplo=String specifying whether the upper or lower triangular part of the global matrix has to be filled:
2799 : : !! = "U": Upper triangular
2800 : : !! = "L": Lower triangular
2801 : : !! = "A": Full matrix is filled (used for general complex matrices)
2802 : : !!
2803 : : !! SIDE EFFECTS
2804 : : !! glob_cmat=The global matrix where the entries owned by this processors have been overwritten.
2805 : : !! Note that the remaing entries not treated by this node are not changed.
2806 : : !!
2807 : : !! SOURCE
2808 : :
2809 [ # # ]: 0 : subroutine slk_matrix_to_global_dpc_2D(mat, uplo, glob_cmat)
2810 : :
2811 : : !Arguments ------------------------------------
2812 : : !scalaras
2813 : : class(slkmat_dp_t),intent(in) :: mat
2814 : : character(len=*),intent(in) :: uplo
2815 : : !arrays
2816 : : complex(dpc),intent(inout) :: glob_cmat(:,:)
2817 : :
2818 : : !Local variables-------------------------------
2819 : : integer :: ii,jj,iglob,jglob
2820 : : !************************************************************************
2821 : :
2822 : 0 : select case (uplo(1:1))
2823 : : case ("A", "a")
2824 : : ! Full global matrix has to be filled.
2825 [ # # ]: 0 : do jj=1,mat%size_local(2)
2826 [ # # ]: 0 : do ii=1,mat%size_local(1)
2827 : 0 : call mat%loc2glob(ii, jj, iglob, jglob)
2828 : 0 : glob_cmat(iglob,jglob) = mat%buffer_cplx(ii,jj)
2829 : : end do
2830 : : end do
2831 : :
2832 : : case ("U", "u")
2833 : : ! Only the upper triangle of the global matrix is filled.
2834 [ # # ]: 0 : do jj=1,mat%size_local(2)
2835 [ # # ]: 0 : do ii=1,mat%size_local(1)
2836 : 0 : call mat%loc2glob(ii, jj, iglob, jglob)
2837 [ # # ]: 0 : if (jglob>=iglob) glob_cmat(iglob,jglob) = mat%buffer_cplx(ii,jj)
2838 : : end do
2839 : : end do
2840 : :
2841 : : case ("L", "l")
2842 : : ! Only the lower triangle of the global matrix is filled.
2843 [ # # ]: 0 : do jj=1,mat%size_local(2)
2844 [ # # ]: 0 : do ii=1,mat%size_local(1)
2845 : 0 : call mat%loc2glob(ii, jj, iglob, jglob)
2846 [ # # ]: 0 : if (jglob<=iglob) glob_cmat(iglob,jglob) = mat%buffer_cplx(ii,jj)
2847 : : end do
2848 : : end do
2849 : :
2850 : : case default
2851 [ # # # # : 0 : ABI_BUG(" Wrong uplo: "//TRIM(uplo))
# # ]
2852 : : end select
2853 : :
2854 : 0 : end subroutine slk_matrix_to_global_dpc_2D
2855 : : !!***
2856 : :
2857 : : !----------------------------------------------------------------------
2858 : :
2859 : : !!****f* m_slk/my_locr
2860 : : !! NAME
2861 : : !! my_locr
2862 : : !!
2863 : : !! FUNCTION
2864 : : !! Method of slkmat_dp_t wrapping the scaLAPACK tool LOCr.
2865 : : !!
2866 : : !! OUTPUT
2867 : : !! my_locr= For the meaning see NOTES below.
2868 : : !!
2869 : : !! NOTES
2870 : : !! Let K be the number of rows or columns of a distributed matrix, and assume that its process grid has dimension p x q.
2871 : : !! LOCr( K ) denotes the number of elements of K that a process would receive if K were distributed over the p
2872 : : !! processes of its process column.
2873 : : !! Similarly, LOCc( K ) denotes the number of elements of K that a process would receive if K were distributed over
2874 : : !! the q processes of its process row.
2875 : : !! The values of LOCr() and LOCc() may be determined via a call to the ScaLAPACK tool function, NUMROC:
2876 : : !! LOCr( M ) = NUMROC( M, MB_A, MYROW, RSRC_A, NPROW ),
2877 : : !! LOCc( N ) = NUMROC( N, NB_A, MYCOL, CSRC_A, NPCOL ). An upper bound for these quantities may be computed
2878 : : !! by:
2879 : : !! LOCr( M ) <= ceil( ceil(M/MB_A)/NPROW )*MB_A
2880 : : !! LOCc( N ) <= ceil( ceil(N/NB_A)/NPCOL )*NB_A
2881 : : !!
2882 : : !! SOURCE
2883 : :
2884 : : integer function my_locr(mat)
2885 : :
2886 : : !Arguments ------------------------------------
2887 : : class(basemat_t),intent(in) :: mat
2888 : :
2889 : : !Local variables-------------------------------
2890 : : #ifdef HAVE_LINALG_SCALAPACK
2891 : : integer :: M, MB_A, MYROW, RSRC_A, NPROW
2892 : : ! *************************************************************************
2893 : :
2894 : : M = mat%desc(M_ ) ! The number of rows in the global matrix.
2895 : : MB_A = mat%desc(MB_) ! The number of rows in a block.
2896 : : MYROW = mat%processor%coords(1) ! The row index of my processor
2897 : : RSRC_A = mat%desc(RSRC_) ! The row of the processors at the beginning.
2898 : : NPROW = mat%processor%grid%dims(1) ! The number of processors per row in the Scalapack grid.
2899 : :
2900 : : my_locr = NUMROC( M, MB_A, MYROW, RSRC_A, NPROW )
2901 : : #endif
2902 : :
2903 : : end function my_locr
2904 : : !!***
2905 : :
2906 : : !----------------------------------------------------------------------
2907 : :
2908 : : !!****f* m_slk/my_locc
2909 : : !! NAME
2910 : : !! my_locc
2911 : : !!
2912 : : !! FUNCTION
2913 : : !! Method of slkmat_dp_t wrapping the scaLAPACK tool LOCc.
2914 : : !!
2915 : : !! OUTPUT
2916 : : !! my_locc= For the meaning see NOTES below.
2917 : : !!
2918 : : !! NOTES
2919 : : !! Let K be the number of rows or columns of a distributed matrix, and assume that its process grid has dimension p x q.
2920 : : !! LOCr( K ) denotes the number of elements of K that a process would receive if K were distributed over the p
2921 : : !! processes of its process column.
2922 : : !! Similarly, LOCc( K ) denotes the number of elements of K that a process would receive if K were distributed over
2923 : : !! the q processes of its process row.
2924 : : !! The values of LOCr() and LOCc() may be determined via a call to the ScaLAPACK tool function, NUMROC:
2925 : : !! LOCr( M ) = NUMROC( M, MB_A, MYROW, RSRC_A, NPROW ),
2926 : : !! LOCc( N ) = NUMROC( N, NB_A, MYCOL, CSRC_A, NPCOL ). An upper bound for these quantities may be computed
2927 : : !! by:
2928 : : !! LOCr( M ) <= ceil( ceil(M/MB_A)/NPROW )*MB_A
2929 : : !! LOCc( N ) <= ceil( ceil(N/NB_A)/NPCOL )*NB_A
2930 : : !!
2931 : : !! SOURCE
2932 : :
2933 : : integer function my_locc(mat)
2934 : :
2935 : : !Arguments ------------------------------------
2936 : : class(basemat_t),intent(in) :: mat
2937 : :
2938 : : #ifdef HAVE_LINALG_SCALAPACK
2939 : : !Local variables-------------------------------
2940 : : integer :: N, NB_A, MYCOL, CSRC_A, NPCOL
2941 : : ! *************************************************************************
2942 : :
2943 : : N = mat%desc(N_ ) ! The number of columns in the global matrix.
2944 : : NB_A = mat%desc(NB_) ! The number of columns in a block.
2945 : : MYCOL = mat%processor%coords(2) ! The column index of my processor
2946 : : CSRC_A = mat%desc(CSRC_) ! The column of the processors at the beginning.
2947 : : NPCOL = mat%processor%grid%dims(2) ! The number of processors per column in the Scalapack grid.
2948 : :
2949 : : my_locc = NUMROC( N, NB_A, MYCOL, CSRC_A, NPCOL )
2950 : : #endif
2951 : :
2952 : : end function my_locc
2953 : : !!***
2954 : :
2955 : : !----------------------------------------------------------------------
2956 : :
2957 : : !!****f* m_slk/slk_pgemm_dp
2958 : : !! NAME
2959 : : !! slk_pgemm_dp
2960 : : !!
2961 : : !! FUNCTION
2962 : : !! Extended matrix * matrix product: C := alpha*A*B + beta*C
2963 : : !! For a simple matrix vector product, one can simply pass alpha = cone and beta = czero
2964 : : !!
2965 : : !! INPUTS
2966 : : !! matrix1= first ScaLAPACK matrix (matrix A)
2967 : : !! matrix2= second ScaLAPACK matrix (matrix B)
2968 : : !! alpha= scalar multiplicator for the A*B product
2969 : : !! beta= scalar multiplicator for the C matrix
2970 : : !! [ija, ijb, ijc]: (global). The row and column indices in the distributed matrix A/B/C
2971 : : !! indicating the first row and the first column of the submatrix, respectively. Default [1, 1]
2972 : : !!
2973 : : !! OUTPUT
2974 : : !! results= ScaLAPACK matrix coming out of the operation
2975 : : !!
2976 : : !! NOTES
2977 : : !! The ESLL manual says that
2978 : : !! "matrices matrix1 and matrix2 must have no common elements otherwise, results are unpredictable."
2979 : : !! However the official scaLAPACK documentation does not report this (severe) limitation.
2980 : : !!
2981 : : !! SOURCE
2982 : :
2983 : 0 : subroutine slk_pgemm_dp(transa, transb, matrix1, alpha, matrix2, beta, results, &
2984 : : ija, ijb, ijc) ! optional
2985 : :
2986 : : !Arguments ------------------------------------
2987 : : character(len=1),intent(in) :: transa, transb
2988 : : class(slkmat_dp_t),intent(in) :: matrix1, matrix2
2989 : : class(slkmat_dp_t),intent(inout) :: results
2990 : : complex(dpc),intent(in) :: alpha, beta
2991 : : integer,optional,intent(in) :: ija(2), ijb(2), ijc(2)
2992 : :
2993 : : !Local variables-------------------------------
2994 : : integer :: mm, nn, kk, ija__(2), ijb__(2), ijc__(2)
2995 : : !************************************************************************
2996 : :
2997 : 0 : ija__ = [1, 1]; if (present(ija)) ija__ = ija
2998 : 0 : ijb__ = [1, 1]; if (present(ijb)) ijb__ = ijb
2999 : 0 : ijc__ = [1, 1]; if (present(ijc)) ijc__ = ijc
3000 : :
3001 : 0 : mm = matrix1%size_global(1)
3002 : 0 : nn = matrix2%size_global(2)
3003 : 0 : kk = matrix1%size_global(2)
3004 : :
3005 : 0 : if (toupper(transa) /= 'N') then
3006 : : mm = matrix1%size_global(2)
3007 : 0 : kk = matrix1%size_global(1)
3008 : : end if
3009 : 0 : if (toupper(transb) /= 'N') nn = matrix2%size_global(1)
3010 : :
3011 : : #ifdef HAVE_LINALG_SCALAPACK
3012 : : ! pzgemm(transa, transb, m, n, k, alpha, a, ia, ja, desca, b, ib, jb, descb, beta, c, ic, jc, descc)
3013 : : if (matrix1%istwf_k /= 2) then
3014 : : call PZGEMM(transa, transb, mm, nn, kk, alpha, &
3015 : : matrix1%buffer_cplx, ija__(1), ija__(2), matrix1%desc, &
3016 : : matrix2%buffer_cplx, ijb__(1), ijb__(2), matrix2%desc, &
3017 : : beta, results%buffer_cplx, ijc__(1), ijc__(2), results%desc)
3018 : : else
3019 : : call PDGEMM(transa, transb, mm, nn, kk, real(alpha, kind=dp), &
3020 : : matrix1%buffer_cplx, ija__(1), ija__(2), matrix1%desc, &
3021 : : matrix2%buffer_cplx, ijb__(1), ijb__(2), matrix2%desc, &
3022 : : real(beta, kind=dp), results%buffer_cplx, ijc__(1), ijc__(2), results%desc)
3023 : : end if
3024 : : #endif
3025 : :
3026 : 0 : end subroutine slk_pgemm_dp
3027 : : !!***
3028 : :
3029 : : !----------------------------------------------------------------------
3030 : :
3031 : : !!****f* m_slk/slk_pgemm_sp
3032 : : !! NAME
3033 : : !! slk_pgemm_sp
3034 : : !!
3035 : : !! FUNCTION
3036 : : !! Extended matrix * matrix product: C := alpha*A*B + beta*C
3037 : : !! For a simple matrix vector product, one can simply pass alpha = cone and beta = czero
3038 : : !!
3039 : : !! INPUTS
3040 : : !! matrix1= first ScaLAPACK matrix (matrix A)
3041 : : !! matrix2= second ScaLAPACK matrix (matrix B)
3042 : : !! alpha= scalar multiplicator for the A*B product
3043 : : !! beta= scalar multiplicator for the C matrix
3044 : : !! [ija, ijb, ijc]: (global). The row and column indices in the distributed matrix A/B/C
3045 : : !! indicating the first row and the first column of the submatrix, respectively. Default [1, 1]
3046 : : !!
3047 : : !! OUTPUT
3048 : : !! results= ScaLAPACK matrix coming out of the operation
3049 : : !!
3050 : : !! NOTES
3051 : : !! The ESLL manual says that
3052 : : !! "matrices matrix1 and matrix2 must have no common elements otherwise, results are unpredictable."
3053 : : !! However the official scaLAPACK documentation does not report this (severe) limitation.
3054 : : !!
3055 : : !! SOURCE
3056 : :
3057 : 0 : subroutine slk_pgemm_sp(transa, transb, matrix1, alpha, matrix2, beta, results, &
3058 : : ija, ijb, ijc) ! optional
3059 : :
3060 : : !Arguments ------------------------------------
3061 : : character(len=1),intent(in) :: transa, transb
3062 : : class(slkmat_sp_t),intent(in) :: matrix1, matrix2
3063 : : class(slkmat_sp_t),intent(inout) :: results
3064 : : complex(sp),intent(in) :: alpha, beta
3065 : : integer,optional,intent(in) :: ija(2), ijb(2), ijc(2)
3066 : :
3067 : : !Local variables-------------------------------
3068 : : integer :: mm, nn, kk, ija__(2), ijb__(2), ijc__(2)
3069 : : !************************************************************************
3070 : :
3071 : 0 : ija__ = [1, 1]; if (present(ija)) ija__ = ija
3072 : 0 : ijb__ = [1, 1]; if (present(ijb)) ijb__ = ijb
3073 : 0 : ijc__ = [1, 1]; if (present(ijc)) ijc__ = ijc
3074 : :
3075 : 0 : mm = matrix1%size_global(1)
3076 : 0 : nn = matrix2%size_global(2)
3077 : 0 : kk = matrix1%size_global(2)
3078 : :
3079 : 0 : if (toupper(transa) /= 'N') then
3080 : : mm = matrix1%size_global(2)
3081 : 0 : kk = matrix1%size_global(1)
3082 : : end if
3083 : 0 : if (toupper(transb) /= 'N') nn = matrix2%size_global(1)
3084 : :
3085 : : #ifdef HAVE_LINALG_SCALAPACK
3086 : : ! pzgemm(transa, transb, m, n, k, alpha, a, ia, ja, desca, b, ib, jb, descb, beta, c, ic, jc, descc)
3087 : : if (matrix1%istwf_k /= 2) then
3088 : : call PCGEMM(transa, transb, mm, nn, kk, alpha, &
3089 : : matrix1%buffer_cplx, ija__(1), ija__(2), matrix1%desc, &
3090 : : matrix2%buffer_cplx, ijb__(1), ijb__(2), matrix2%desc, &
3091 : : beta, results%buffer_cplx, ijc__(1), ijc__(2), results%desc)
3092 : : else
3093 : : call PSGEMM(transa, transb, mm, nn, kk, real(alpha, kind=sp), &
3094 : : matrix1%buffer_cplx, ija__(1), ija__(2), matrix1%desc, &
3095 : : matrix2%buffer_cplx, ijb__(1), ijb__(2), matrix2%desc, &
3096 : : real(beta, kind=sp), results%buffer_cplx, ijc__(1), ijc__(2), results%desc)
3097 : : end if
3098 : : #endif
3099 : :
3100 : 0 : end subroutine slk_pgemm_sp
3101 : : !!***
3102 : :
3103 : : !----------------------------------------------------------------------
3104 : :
3105 : : !!****f* m_slk/compute_eigen_problem
3106 : : !! NAME
3107 : : !! compute_eigen_problem
3108 : : !!
3109 : : !! FUNCTION
3110 : : !! Calculation of eigenvalues and eigenvectors: A * X = lambda * X, complex and real cases.
3111 : : !!
3112 : : !! INPUTS
3113 : : !! processor= descriptor of a processor
3114 : : !! matrix= the matrix to process
3115 : : !! comm= MPI communicator
3116 : : !! istwf_k= 2 if we have a real matrix else complex.
3117 : : !! [nev]= Number of eigenvalues needed. Default: full set
3118 : : !! [use_gpu_elpa]= Flag to activate the use of GPU (ELPA only)
3119 : : !!
3120 : : !! OUTPUT
3121 : : !! results= ScaLAPACK matrix coming out of the operation (global dimensions must be equal to matrix
3122 : : !! even if only a part of the eigenvectors is needed.
3123 : : !! eigen= eigenvalues of the matrix dimensioned as the global size of the square matrix
3124 : : !! even if only a part of the eigenvalues is needed.
3125 : : !!
3126 : : !! SOURCE
3127 : :
3128 : 0 : subroutine compute_eigen_problem(processor, matrix, results, eigen, comm, istwf_k, &
3129 : : nev, use_gpu_elpa) ! Optional arguments
3130 : :
3131 : : !Arguments ------------------------------------
3132 : : class(slk_processor_t),intent(in) :: processor
3133 : : class(slkmat_dp_t),intent(inout) :: matrix
3134 : : class(slkmat_dp_t),intent(inout) :: results
3135 : : DOUBLE PRECISION,intent(inout) :: eigen(:)
3136 : : integer,intent(in) :: comm,istwf_k
3137 : : integer,optional,intent(in) :: nev
3138 : : integer,optional,intent(in) :: use_gpu_elpa
3139 : :
3140 : : #if defined(HAVE_LINALG_ELPA)
3141 : : !Local variables ------------------------------
3142 : : type(elpa_hdl_t) :: elpa_hdl
3143 : : integer :: nev__,use_gpu_elpa_
3144 : : !************************************************************************
3145 : :
3146 : : nev__ = matrix%size_global(1); if (present(nev)) nev__ = nev
3147 : : use_gpu_elpa_=0; if (present(use_gpu_elpa)) use_gpu_elpa_=use_gpu_elpa
3148 : :
3149 : : call elpa_func_allocate(elpa_hdl,gpu=use_gpu_elpa_)
3150 : : call elpa_func_set_matrix(elpa_hdl,matrix%size_global(1),matrix%size_blocs(1),nev__,&
3151 : : matrix%size_local(1),matrix%size_local(2))
3152 : : call elpa_func_get_communicators(elpa_hdl,processor%comm,processor%coords(1),processor%coords(2))
3153 : :
3154 : : if (istwf_k/=2) then
3155 : : call elpa_func_solve_evp_1stage(elpa_hdl,matrix%buffer_cplx,results%buffer_cplx,eigen,nev__)
3156 : : else
3157 : : call elpa_func_solve_evp_1stage(elpa_hdl,matrix%buffer_real,results%buffer_real,eigen,nev__)
3158 : : end if
3159 : :
3160 : : call elpa_func_deallocate(elpa_hdl)
3161 : :
3162 : :
3163 : : #elif defined(HAVE_LINALG_SLATE)
3164 : : !Local variables-------------------------------
3165 : : integer :: nev__,use_gpu_elpa_, info_slate
3166 : : ! *************************************************************************
3167 : :
3168 : : if (istwf_k /= 2) then
3169 : : call slate_zheev_c( &
3170 : : matrix%size_global(1), & ! n
3171 : : matrix%size_blocs(1), & ! nb (mb==nb required)
3172 : : processor%grid%dims(1), & ! nprow
3173 : : processor%grid%dims(2), & ! npcol
3174 : : processor%comm, & ! Fortran MPI comm handle
3175 : : matrix%size_local(1), & ! lda
3176 : : matrix%buffer_cplx, & ! a_data (destroyed on exit)
3177 : : results%size_local(1), & ! ldz
3178 : : results%buffer_cplx, & ! z_data (eigenvectors out)
3179 : : eigen, & ! w (eigenvalues out)
3180 : : nev__, & ! nev
3181 : : use_gpu_elpa_, & ! use_gpu (reuse existing flag)
3182 : : info_slate)
3183 : : ABI_CHECK(info_slate == 0, "slate_zheev_c failed")
3184 : : else
3185 : : call slate_dsyev_c( &
3186 : : matrix%size_global(1), & ! n
3187 : : matrix%size_blocs(1), & ! nb (mb==nb required)
3188 : : processor%grid%dims(1), & ! nprow
3189 : : processor%grid%dims(2), & ! npcol
3190 : : processor%comm, & ! Fortran MPI comm handle
3191 : : matrix%size_local(1), & ! lda
3192 : : matrix%buffer_real, & ! a_data (destroyed on exit)
3193 : : results%size_local(1), & ! ldz
3194 : : results%buffer_real, & ! z_data (eigenvectors out)
3195 : : eigen, & ! w (eigenvalues out)
3196 : : nev__, & ! nev
3197 : : use_gpu_elpa_, & ! use_gpu (reuse existing flag)
3198 : : info_slate)
3199 : : ABI_CHECK(info_slate == 0, "slate_dsyev_c failed")
3200 : : end if
3201 : :
3202 : :
3203 : : #elif defined(HAVE_LINALG_SCALAPACK)
3204 : : !Local variables-------------------------------
3205 : : integer :: LRWORK,LIWORK,LCWORK,INFO
3206 : : !character(len=500) :: msg
3207 : : integer , dimension(1) :: IWORK_tmp
3208 : : DOUBLE PRECISION, dimension(1) :: RWORK_tmp
3209 : : complex(dpc) , dimension(1) :: CWORK_tmp
3210 : : integer , allocatable :: IWORK(:)
3211 : : DOUBLE PRECISION, allocatable :: RWORK(:)
3212 : : complex(dpc) , allocatable :: CWORK(:)
3213 : : integer, allocatable :: ICLUSTR(:)
3214 : : integer, allocatable :: IFAIL(:)
3215 : : DOUBLE PRECISION, allocatable :: GAP(:)
3216 : : DOUBLE PRECISION :: ABSTOL,ORFAC
3217 : : integer, parameter :: IZERO=0
3218 : : integer :: M,NZ,ierr,TWORK_tmp(3),TWORK(3) ! IA,JA,IZ,JZ,
3219 : : integer :: nev__, il, iu, use_gpu_elpa_
3220 : : character(len=1) :: range
3221 : : ! *************************************************************************
3222 : :
3223 : : ABI_UNUSED(use_gpu_elpa) ! No GPU implementation if using scaLAPACK
3224 : : use_gpu_elpa_=0; if (present(use_gpu_elpa)) use_gpu_elpa_=use_gpu_elpa
3225 : : nev__ = matrix%size_global(1); range = "A"; il = 0; iu = 0
3226 : : if (present(nev)) then
3227 : : nev__ = nev; range = "I"; il = 1; iu = nev
3228 : : end if
3229 : :
3230 : : ! Initialisation
3231 : : INFO = 0
3232 : : ABSTOL = zero
3233 : : ORFAC = -1.D+0
3234 : :
3235 : : ! Allocation of the variables for the results of the calculations
3236 : : ABI_MALLOC(IFAIL,(matrix%size_global(2)))
3237 : : ABI_MALLOC(ICLUSTR,(2*processor%grid%dims(1)*processor%grid%dims(2)))
3238 : : ABI_MALLOC(GAP,(processor%grid%dims(1)*processor%grid%dims(2)))
3239 : :
3240 : : CWORK_tmp = (0.0_DP,0.0_DP)
3241 : : RWORK_tmp = 0.0_DP
3242 : : ! Get the size of the work arrays
3243 : : if (istwf_k/=2) then
3244 : : call PZHEEVX('V', range, 'U',&
3245 : : matrix%size_global(2),&
3246 : : matrix%buffer_cplx,1,1,matrix%desc, &
3247 : : ZERO,ZERO,il,iu,ABSTOL,&
3248 : : m,nz,eigen,ORFAC, &
3249 : : results%buffer_cplx,1,1,results%desc, &
3250 : : CWORK_tmp,-1,RWORK_tmp,-1,IWORK_tmp,-1,&
3251 : : IFAIL,ICLUSTR,GAP,INFO)
3252 : : else
3253 : : call PDSYEVX('V', range, 'U',&
3254 : : matrix%size_global(2),&
3255 : : matrix%buffer_real,1,1,matrix%desc, &
3256 : : ZERO,ZERO,il,iu,ABSTOL,&
3257 : : m,nz,eigen,ORFAC, &
3258 : : results%buffer_real,1,1,results%desc, &
3259 : : RWORK_tmp,-1,IWORK_tmp,-1,&
3260 : : IFAIL,ICLUSTR,GAP,INFO)
3261 : : end if
3262 : :
3263 : : if (INFO/=0) then
3264 : : ABI_ERROR(sjoin("Problem to compute workspace to use ScaLAPACK, INFO: ", itoa(INFO)))
3265 : : endif
3266 : : !write(std_out, *)"First call to compute workspace OK"
3267 : :
3268 : : TWORK_tmp(1) = IWORK_tmp(1)
3269 : : TWORK_tmp(2) = INT(RWORK_tmp(1))
3270 : : TWORK_tmp(3) = INT(real(CWORK_tmp(1)))
3271 : :
3272 : : ! Get the maximum of the size of the work arrays processor%comm
3273 : : call MPI_ALLREDUCE(TWORK_tmp,TWORK,3,MPI_integer,MPI_MAX,comm,ierr)
3274 : :
3275 : : LIWORK = TWORK(1)
3276 : : LRWORK = TWORK(2) + matrix%size_global(2) *(matrix%size_global(2)-1)
3277 : : LCWORK = TWORK(3)
3278 : :
3279 : : ! Allocation of the work arrays
3280 : : if (LIWORK>0) then
3281 : : ABI_MALLOC(IWORK,(LIWORK))
3282 : : IWORK(:) = 0
3283 : : else
3284 : : ABI_MALLOC(IWORK,(1))
3285 : : end if
3286 : : if (LRWORK>0) then
3287 : : ! This workspace scales with the number of processors but not always in a simple linear way.
3288 : : ! and the optimal LRWORK might be pretty big (~1 Gb) even for small systems.
3289 : : ABI_MALLOC(RWORK,(LRWORK))
3290 : : RWORK(:) = 0._dp
3291 : : else
3292 : : ABI_MALLOC(RWORK,(1))
3293 : : end if
3294 : : if (LCWORK>0) then
3295 : : ABI_MALLOC(CWORK,(LCWORK))
3296 : : CWORK(:) = (0._dp,0._dp)
3297 : : else
3298 : : ABI_MALLOC(CWORK,(1))
3299 : : end if
3300 : :
3301 : : ! prototype
3302 : : !call pzheevx(jobz, range, uplo, n, a, ia, ja, desca, vl, vu, il, iu, abstol, m, nz, w,
3303 : : ! orfac, z, iz, jz, descz, work, lwork, rwork, lrwork, iwork, liwork, ifail, iclustr, gap, info)
3304 : :
3305 : : ! Call the calculation routine
3306 : : if (istwf_k/=2) then
3307 : : ! write(std_out,*) 'I am using PZHEEVX'
3308 : : call PZHEEVX('V', range, 'U',&
3309 : : matrix%size_global(2),&
3310 : : matrix%buffer_cplx,1,1,matrix%desc, &
3311 : : ZERO,ZERO,il,iu,ABSTOL,&
3312 : : m,nz,eigen,ORFAC, &
3313 : : results%buffer_cplx,1,1,results%desc, &
3314 : : CWORK,LCWORK,RWORK,LRWORK,IWORK,LIWORK,&
3315 : : IFAIL,ICLUSTR,GAP,INFO)
3316 : : else
3317 : : ! write(std_out,*) ' I am using PDSYEVX'
3318 : : call PDSYEVX('V', range, 'U',&
3319 : : matrix%size_global(2),&
3320 : : matrix%buffer_real,1,1,matrix%desc, &
3321 : : ZERO,ZERO,il,iu,ABSTOL,&
3322 : : m,nz,eigen,ORFAC, &
3323 : : results%buffer_real,1,1,results%desc, &
3324 : : RWORK,LRWORK,IWORK,LIWORK,&
3325 : : IFAIL,ICLUSTR,GAP,INFO)
3326 : : endif
3327 : :
3328 : : ! MG: TODO: Recheck the computation of the workspace as I got INFO 2 with a 5x5x5 si supercell.
3329 : : if (INFO/=0) then
3330 : : ABI_ERROR(sjoin("Problem to compute eigenvalues and eigenvectors with ScaLAPACK, INFO:", itoa(INFO)))
3331 : : endif
3332 : :
3333 : : ABI_FREE(IFAIl)
3334 : : ABI_FREE(ICLUSTR)
3335 : : ABI_FREE(GAP)
3336 : : ABI_SFREE(IWORK)
3337 : : ABI_SFREE(RWORK)
3338 : : ABI_SFREE(CWORK)
3339 : : #endif
3340 : 0 : return
3341 : :
3342 : : end subroutine compute_eigen_problem
3343 : : !!***
3344 : :
3345 : : !----------------------------------------------------------------------
3346 : :
3347 : : !!****f* m_slk/solve_gevp_complex
3348 : : !! NAME
3349 : : !! solve_gevp_complex
3350 : : !!
3351 : : !! FUNCTION
3352 : : !! Calculation of eigenvalues and eigenvectors: A * X = lambda * B * X
3353 : : !! complex and real cases.
3354 : : !!
3355 : : !! INPUTS
3356 : : !! processor= descriptor of a processor
3357 : : !! matrix1= first ScaLAPACK matrix (matrix A)
3358 : : !! matrix2= second ScaLAPACK matrix (matrix B)
3359 : : !! comm= MPI communicator
3360 : : !! istwf_k= 2 if we have a real matrix else complex.
3361 : : !! [use_gpu_elpa]= Flag to activate the use of GPU (ELPA only)
3362 : : !!
3363 : : !! SIDE EFFECTS
3364 : : !! results= ScaLAPACK matrix coming out of the operation
3365 : : !! eigen= eigenvalues of the matrix
3366 : : !!
3367 : : !! SOURCE
3368 : :
3369 : : #ifdef HAVE_LINALG_ELPA
3370 : :
3371 : : subroutine solve_gevp_complex(na,nev,na_rows,na_cols,nblk,a,b,ev,z,tmp1,tmp2, &
3372 : : my_prow,my_pcol,np_rows,np_cols,sc_desc,comm,&
3373 : : use_gpu_elpa) ! Optional parameter
3374 : :
3375 : : !-Arguments
3376 : : integer,intent(in) :: na
3377 : : integer,intent(in) :: nev
3378 : : integer,intent(in) :: na_rows,na_cols
3379 : : integer,intent(in) :: nblk
3380 : : integer,intent(in) :: my_pcol,my_prow
3381 : : integer,intent(in) :: np_cols,np_rows
3382 : : integer,intent(in) :: sc_desc(9)
3383 : : integer,intent(in) :: comm
3384 : : integer,optional,intent(in) :: use_gpu_elpa
3385 : : real*8 :: ev(na)
3386 : : complex*16 :: a(na_rows,na_cols),b(na_rows,na_cols),z(na_rows,na_cols)
3387 : : complex*16 :: tmp1(na_rows,na_cols),tmp2(na_rows,na_cols)
3388 : : !-Local variables
3389 : : integer :: i, n_col, n_row, use_gpu_elpa_
3390 : : complex*16, parameter :: CZERO = (0.d0,0.d0), CONE = (1.d0,0.d0)
3391 : : type(elpa_hdl_t) :: elpa_hdl
3392 : : ! *************************************************************************
3393 : :
3394 : : use_gpu_elpa_=0
3395 : : #ifdef HAVE_LINALG_ELPA
3396 : : if (present(use_gpu_elpa)) use_gpu_elpa_=use_gpu_elpa
3397 : : #endif
3398 : :
3399 : : ! Allocate ELPA handle
3400 : : call elpa_func_allocate(elpa_hdl,blacs_ctx=sc_desc(CTXT_),gpu=use_gpu_elpa_)
3401 : : call elpa_func_set_matrix(elpa_hdl,na,nblk,nev,na_rows,na_cols)
3402 : : call elpa_func_get_communicators(elpa_hdl,comm,my_prow,my_pcol)
3403 : : call elpa_func_solve_gevp_2stage(elpa_hdl,a,b,z,ev,nev)
3404 : : call elpa_func_deallocate(elpa_hdl)
3405 : :
3406 : : end subroutine solve_gevp_complex
3407 : :
3408 : : !----------------------------------------------------------------------
3409 : :
3410 : : subroutine solve_gevp_real(na,nev,na_rows,na_cols,nblk,a,b,ev,z,tmp1,tmp2, &
3411 : : my_prow,my_pcol,np_rows,np_cols,sc_desc,comm, &
3412 : : use_gpu_elpa) ! Optional argument
3413 : :
3414 : : !-Arguments
3415 : : integer,intent(in) :: na
3416 : : integer,intent(in) :: nev
3417 : : integer,intent(in) :: na_rows,na_cols
3418 : : integer,intent(in) :: nblk
3419 : : integer,intent(in) :: my_pcol,my_prow
3420 : : integer,intent(in) :: np_cols,np_rows
3421 : : integer,intent(in) :: sc_desc(9)
3422 : : integer,intent(in) :: comm
3423 : : integer,optional,intent(in) :: use_gpu_elpa
3424 : : real*8 :: ev(na)
3425 : : real*8 :: a(na_rows,na_cols),b(na_rows,na_cols),z(na_rows,na_cols)
3426 : : real*8 :: tmp1(na_rows,na_cols),tmp2(na_rows,na_cols)
3427 : : !-Local variables
3428 : : integer :: i, n_col, n_row, use_gpu_elpa_
3429 : : type(elpa_hdl_t) :: elpa_hdl
3430 : : ! *************************************************************************
3431 : :
3432 : : use_gpu_elpa_=0
3433 : : #ifdef HAVE_LINALG_ELPA
3434 : : if (present(use_gpu_elpa)) use_gpu_elpa_=use_gpu_elpa
3435 : : #endif
3436 : :
3437 : : ! Allocate ELPA handle
3438 : : call elpa_func_allocate(elpa_hdl,blacs_ctx=sc_desc(CTXT_),gpu=use_gpu_elpa_)
3439 : : call elpa_func_set_matrix(elpa_hdl,na,nblk,nev,na_rows,na_cols)
3440 : : call elpa_func_get_communicators(elpa_hdl,comm,my_prow,my_pcol)
3441 : :
3442 : : !FIXME Need to figure out why generalized_eigenvectors doesn't work in this real case
3443 : : ! while it is fine with complex case
3444 : : if(.false.) then
3445 : : call elpa_func_solve_gevp_2stage(elpa_hdl,a,b,tmp1,ev,nev)
3446 : : else
3447 : : ! 1. Calculate Cholesky factorization of Matrix B = U**T * U
3448 : : ! and invert triangular matrix U
3449 : : call elpa_func_cholesky(elpa_hdl,b)
3450 : : call elpa_func_invert_triangular(elpa_hdl,b)
3451 : : ! 2. Calculate U**-T * A * U**-1
3452 : : ! 2a. tmp1 = U**-T * A
3453 : : call elpa_func_hermitian_multiply(elpa_hdl,'U','L',na,b,a,na_rows,na_cols,tmp1,na_rows,na_cols)
3454 : : ! 2b. tmp2 = tmp1**T
3455 : : call pdtran(na,na,1.d0,tmp1,1,1,sc_desc,0.d0,tmp2,1,1,sc_desc)
3456 : : ! 2c. A = U**-T * tmp2 ( = U**-T * Aorig * U**-1 )
3457 : : call elpa_func_hermitian_multiply(elpa_hdl,'U','U',na,b,tmp2,na_rows,na_cols,a,na_rows,na_cols)
3458 : : ! A is only set in the upper half, solve_evp_real needs a full matrix
3459 : : ! Set lower half from upper half
3460 : : call pdtran(na,na,1.d0,a,1,1,sc_desc,0.d0,tmp1,1,1,sc_desc)
3461 : : do i=1,na_cols
3462 : : ! Get global column corresponding to i and number of local rows up to
3463 : : ! and including the diagonal, these are unchanged in A
3464 : : n_col = indxl2g(i, nblk, my_pcol, 0, np_cols)
3465 : : n_row = numroc (n_col, nblk, my_prow, 0, np_rows)
3466 : : a(n_row+1:na_rows,i) = tmp1(n_row+1:na_rows,i)
3467 : : enddo
3468 : : ! 3. Calculate eigenvalues/eigenvectors of U**-T * A * U**-1
3469 : : ! Eigenvectors go to tmp1
3470 : : call elpa_func_solve_evp_1stage(elpa_hdl,a,tmp1,ev,nev)
3471 : : ! 4. Backtransform eigenvectors: Z = U**-1 * tmp1
3472 : : ! hermitian_multiply needs the transpose of U**-1, thus tmp2 = (U**-1)**T
3473 : : call pdtran(na,na,1.d0,b,1,1,sc_desc,0.d0,tmp2,1,1,sc_desc)
3474 : : call elpa_func_hermitian_multiply(elpa_hdl,'L','N',nev,tmp2,tmp1,na_rows,na_cols,z,na_rows,na_cols)
3475 : : end if
3476 : :
3477 : : call elpa_func_deallocate(elpa_hdl)
3478 : :
3479 : : end subroutine solve_gevp_real
3480 : : !!***
3481 : : #endif
3482 : :
3483 : : !----------------------------------------------------------------------
3484 : :
3485 : : !!****f* m_slk/compute_generalized_eigen_problem
3486 : : !! NAME
3487 : : !! compute_generalized_eigen_problem
3488 : : !!
3489 : : !! FUNCTION
3490 : : !! Calculation of eigenvalues and eigenvectors of the generalized eigenvalue problem: A * X = lambda * B X
3491 : : !! complex and real cases.
3492 : : !!
3493 : : !! INPUTS
3494 : : !! processor= descriptor of a processor
3495 : : !! matrix1= A matrix
3496 : : !! matrix2= B matrix
3497 : : !! comm= MPI communicator
3498 : : !! istwf_k= 2 if we have a real matrix else complex.
3499 : : !! [nev]= Number of eigenvalues needed. Default: full set
3500 : : !! [use_gpu_elpa]= Flag to activate the use of GPU (ELPA only)
3501 : : !!
3502 : : !! OUTPUT
3503 : : !! results= ScaLAPACK matrix coming out of the operation (global dimensions must be equal to matrix
3504 : : !! even if only a part of the eigenvectors is needed.
3505 : : !! eigen= eigenvalues of the matrix dimensioned as the global size of the square matrix
3506 : : !! even if only a part of the eigenvalues is needed.
3507 : : !!
3508 : : !! SOURCE
3509 : :
3510 : 0 : subroutine compute_generalized_eigen_problem(processor,matrix1,matrix2,results,eigen,comm,istwf_k,&
3511 : : nev,use_gpu_elpa) ! Optional arguments
3512 : :
3513 : : !Arguments ------------------------------------
3514 : : class(slk_processor_t),intent(in) :: processor
3515 : : class(slkmat_dp_t),intent(inout) :: matrix1,matrix2
3516 : : class(slkmat_dp_t),intent(inout) :: results
3517 : : DOUBLE PRECISION,intent(inout) :: eigen(:)
3518 : : integer,intent(in) :: comm,istwf_k
3519 : : integer,optional,intent(in) :: nev
3520 : : integer,optional,intent(in) :: use_gpu_elpa
3521 : : #ifdef HAVE_LINALG_ELPA
3522 : : !Local
3523 : : type(slkmat_dp_t) :: tmp1, tmp2
3524 : : integer :: i,n_col, n_row, nev__,use_gpu_elpa__
3525 : :
3526 : : nev__ = matrix1%size_global(2); if (present(nev)) nev__ = nev
3527 : : use_gpu_elpa__ = 0; if (present(use_gpu_elpa)) use_gpu_elpa__ = use_gpu_elpa
3528 : :
3529 : : call tmp1%init(matrix1%size_global(1),matrix1%size_global(2),processor,istwf_k)
3530 : : call tmp2%init(matrix1%size_global(1),matrix1%size_global(2),processor,istwf_k)
3531 : :
3532 : : if (istwf_k/=2) then
3533 : : call solve_gevp_complex(matrix1%size_global(1), nev__, &
3534 : : matrix1%size_local(1),matrix1%size_local(2),matrix1%size_blocs(1), &
3535 : : matrix1%buffer_cplx,matrix2%buffer_cplx,eigen,results%buffer_cplx, &
3536 : : tmp1%buffer_cplx,tmp2%buffer_cplx, &
3537 : : processor%coords(1),processor%coords(2), &
3538 : : processor%grid%dims(1),processor%grid%dims(2), &
3539 : : matrix1%desc,processor%comm,use_gpu_elpa=use_gpu_elpa__)
3540 : : else
3541 : : call solve_gevp_real(matrix1%size_global(1), nev__, &
3542 : : matrix1%size_local(1),matrix1%size_local(2),matrix1%size_blocs(1), &
3543 : : matrix1%buffer_real,matrix2%buffer_real,eigen,results%buffer_real, &
3544 : : tmp1%buffer_real,tmp2%buffer_real, &
3545 : : processor%coords(1),processor%coords(2), &
3546 : : processor%grid%dims(1),processor%grid%dims(2), &
3547 : : matrix1%desc,processor%comm,use_gpu_elpa=use_gpu_elpa__)
3548 : : end if
3549 : : call tmp1%free()
3550 : : call tmp2%free()
3551 : :
3552 : :
3553 : : !#elif defined HAVE_LINALG_SLATE
3554 : : !!FIXME Doesn't work. slate_zheev/syev is fine though so we fall back to scaLAPACK instead
3555 : : !!Local variables-------------------------------
3556 : : ! integer :: nev__, use_gpu_elpa_, info_slate
3557 : : !! *************************************************************************
3558 : : !
3559 : : ! nev__ = matrix1%size_global(2); if (present(nev)) nev__ = nev
3560 : : ! use_gpu_elpa__ = 0; if (present(use_gpu_elpa)) use_gpu_elpa__ = use_gpu_elpa
3561 : : !
3562 : : ! if (istwf_k /= 2) then
3563 : : ! call slate_zhegv_c( &
3564 : : ! matrix1%size_global(1), & ! n
3565 : : ! matrix1%size_blocs(1), & ! nb (mb==nb required)
3566 : : ! processor%grid%dims(1), & ! nprow
3567 : : ! processor%grid%dims(2), & ! npcol
3568 : : ! processor%comm, & ! Fortran MPI comm handle
3569 : : ! matrix1%size_local(1), & ! lda
3570 : : ! matrix1%buffer_cplx, & ! a_data (destroyed on exit)
3571 : : ! matrix2%size_local(1), & ! ldb
3572 : : ! matrix2%buffer_cplx, & ! b_data (destroyed on exit)
3573 : : ! results%size_local(1), & ! ldz
3574 : : ! results%buffer_cplx, & ! z_data (eigenvectors out)
3575 : : ! eigen, & ! w (eigenvalues out)
3576 : : ! nev__, & ! nev
3577 : : ! use_gpu_elpa_, & ! use_gpu (reuse existing flag)
3578 : : ! info_slate)
3579 : : ! ABI_CHECK(info_slate == 0, "slate_zhgev_c failed")
3580 : : ! else
3581 : : ! call slate_dsygv_c( &
3582 : : ! matrix1%size_global(1), & ! n
3583 : : ! matrix1%size_blocs(1), & ! nb (mb==nb required)
3584 : : ! processor%grid%dims(1), & ! nprow
3585 : : ! processor%grid%dims(2), & ! npcol
3586 : : ! processor%comm, & ! Fortran MPI comm handle
3587 : : ! matrix1%size_local(1), & ! lda
3588 : : ! matrix1%buffer_real, & ! a_data (destroyed on exit)
3589 : : ! matrix2%size_local(1), & ! ldb
3590 : : ! matrix2%buffer_real, & ! b_data (destroyed on exit)
3591 : : ! results%size_local(1), & ! ldz
3592 : : ! results%buffer_real, & ! z_data (eigenvectors out)
3593 : : ! eigen, & ! w (eigenvalues out)
3594 : : ! nev__, & ! nev
3595 : : ! use_gpu_elpa_, & ! use_gpu (reuse existing flag)
3596 : : ! info_slate)
3597 : : ! ABI_CHECK(info_slate == 0, "slate_dsygv_c failed")
3598 : : ! end if
3599 : :
3600 : :
3601 : : #elif defined(HAVE_LINALG_SCALAPACK)
3602 : : !Local variables-------------------------------
3603 : : integer :: LRWORK,LIWORK,LCWORK,INFO
3604 : : !character(len=500) :: msg
3605 : : integer , dimension(1) :: IWORK_tmp
3606 : : DOUBLE PRECISION, dimension(1) :: RWORK_tmp
3607 : : complex(dpc) , dimension(1) :: CWORK_tmp
3608 : :
3609 : : integer , allocatable :: IWORK(:)
3610 : : DOUBLE PRECISION, allocatable :: RWORK(:)
3611 : : complex(dpc) , allocatable :: CWORK(:)
3612 : : integer, allocatable :: ICLUSTR(:)
3613 : : integer, allocatable :: IFAIL(:)
3614 : : DOUBLE PRECISION, allocatable :: GAP(:)
3615 : : DOUBLE PRECISION :: ABSTOL,ORFAC
3616 : : integer , parameter :: IZERO=0
3617 : : integer :: M,NZ,ierr,TWORK_tmp(3),TWORK(3) ! IA,JA,IZ,JZ,
3618 : : character(len=1) :: range
3619 : : integer :: nev__, il, iu
3620 : : ! *************************************************************************
3621 : :
3622 : : ABI_UNUSED(use_gpu_elpa) ! No GPU implementation is using scaLAPACK
3623 : : nev__ = matrix1%size_global(2); range = "A"; il = 0; iu = 0
3624 : : if (present(nev)) then
3625 : : nev__ = nev; range = "I"; il = 1; iu = nev
3626 : : end if
3627 : :
3628 : : ! Initialisation
3629 : : INFO = 0
3630 : : ABSTOL = zero
3631 : : ORFAC = -1.D+0
3632 : :
3633 : : ! Allocate the arrays for the results of the calculation
3634 : : ABI_MALLOC(IFAIL ,(matrix1%size_global(2)))
3635 : : ABI_MALLOC(ICLUSTR,(2*processor%grid%dims(1)*processor%grid%dims(2)))
3636 : : ABI_MALLOC(GAP ,( processor%grid%dims(1)*processor%grid%dims(2)))
3637 : :
3638 : : CWORK_tmp = (0.0_DP,0.0_DP)
3639 : : RWORK_tmp = 0.0_DP
3640 : : ! Get the size of the work arrays
3641 : : if (istwf_k /= 2) then
3642 : : call PZHEGVX(1, 'V', range, 'U',&
3643 : : matrix1%size_global(2),&
3644 : : matrix1%buffer_cplx,1,1,matrix1%desc, &
3645 : : matrix2%buffer_cplx,1,1,matrix2%desc, &
3646 : : ZERO,ZERO,il,iu,ABSTOL,&
3647 : : m,nz,eigen,ORFAC, &
3648 : : results%buffer_cplx,1,1,results%desc, &
3649 : : CWORK_tmp,-1,RWORK_tmp,-1,IWORK_tmp,-1,&
3650 : : IFAIL,ICLUSTR,GAP,INFO)
3651 : : else
3652 : : call PDSYGVX(1,'V',range,'U',&
3653 : : matrix1%size_global(2),&
3654 : : matrix1%buffer_real,1,1,matrix1%desc, &
3655 : : matrix2%buffer_real,1,1,matrix2%desc, &
3656 : : ZERO,ZERO,il,iu,ABSTOL,&
3657 : : m,nz,eigen,ORFAC, &
3658 : : results%buffer_real,1,1,results%desc, &
3659 : : RWORK_tmp,-1,IWORK_tmp,-1,&
3660 : : IFAIL,ICLUSTR,GAP,INFO)
3661 : : endif
3662 : :
3663 : : if (INFO/=0) then
3664 : : ABI_ERROR(sjoin("Problem to compute workspace to use ScaLAPACK, INFO=",itoa(INFO)))
3665 : : endif
3666 : :
3667 : : TWORK_tmp(1) = IWORK_tmp(1)
3668 : : TWORK_tmp(2) = INT(RWORK_tmp(1)) + matrix1%size_global(2) *(matrix1%size_global(2)-1)
3669 : : TWORK_tmp(3) = INT(real(CWORK_tmp(1)))
3670 : :
3671 : : ! Get the maximum of sizes of the work arrays processor%comm
3672 : : call MPI_ALLREDUCE(TWORK_tmp,TWORK,3,MPI_integer,MPI_MAX,comm,ierr)
3673 : :
3674 : : LIWORK = TWORK(1)
3675 : : LRWORK = TWORK(2)
3676 : : LCWORK = TWORK(3)
3677 : :
3678 : : ! Allocate the work arrays
3679 : : if (LIWORK>0) then
3680 : : ABI_MALLOC(IWORK,(LIWORK))
3681 : : IWORK(:) = 0
3682 : : else
3683 : : ABI_MALLOC(IWORK,(1))
3684 : : end if
3685 : : if (LRWORK>0) then
3686 : : ABI_MALLOC(RWORK,(LRWORK))
3687 : : RWORK(:) = 0._dp
3688 : : else
3689 : : ABI_MALLOC(RWORK,(1))
3690 : : end if
3691 : : if (LCWORK>0) then
3692 : : ABI_MALLOC(CWORK,(LCWORK))
3693 : : CWORK(:) = (0._dp,0._dp)
3694 : : else
3695 : : ABI_MALLOC(CWORK,(1))
3696 : : end if
3697 : :
3698 : : ! Call the calculation routine
3699 : : if (istwf_k/=2) then
3700 : : ! write(std_out,*) 'I am using PZHEGVX'
3701 : : call PZHEGVX(1,'V',range,'U',&
3702 : : matrix1%size_global(2),&
3703 : : matrix1%buffer_cplx,1,1,matrix1%desc, &
3704 : : matrix2%buffer_cplx,1,1,matrix2%desc, &
3705 : : ZERO,ZERO,il,iu,ABSTOL,&
3706 : : m,nz,eigen,ORFAC, &
3707 : : results%buffer_cplx,1,1,results%desc, &
3708 : : CWORK,LCWORK,RWORK,LRWORK,IWORK,LIWORK,&
3709 : : IFAIL,ICLUSTR,GAP,INFO)
3710 : : else
3711 : : ! write(std_out,*) 'I am using PDSYGVX'
3712 : : call PDSYGVX(1,'V',range,'U',&
3713 : : matrix1%size_global(2),&
3714 : : matrix1%buffer_real,1,1,matrix1%desc, &
3715 : : matrix2%buffer_real,1,1,matrix2%desc, &
3716 : : ZERO,ZERO,il,iu,ABSTOL,&
3717 : : m,nz,eigen,ORFAC, &
3718 : : results%buffer_real,1,1,results%desc, &
3719 : : RWORK,LRWORK,IWORK,LIWORK,&
3720 : : IFAIL,ICLUSTR,GAP,INFO)
3721 : : endif
3722 : :
3723 : : if (INFO/=0) then
3724 : : ABI_ERROR(sjoin("Problem to compute eigen problem with ScaLAPACK, INFO=", itoa(INFO)))
3725 : : endif
3726 : :
3727 : : ABI_FREE(IFAIl)
3728 : : ABI_FREE(ICLUSTR)
3729 : : ABI_FREE(GAP)
3730 : : ABI_SFREE(IWORK)
3731 : : ABI_SFREE(RWORK)
3732 : : ABI_SFREE(CWORK)
3733 : : #endif
3734 : 0 : return
3735 : :
3736 : : end subroutine compute_generalized_eigen_problem
3737 : : !!***
3738 : :
3739 : : !----------------------------------------------------------------------
3740 : :
3741 : : !!****f* m_slk/compute_eigen1
3742 : : !! NAME
3743 : : !! compute_eigen1
3744 : : !!
3745 : : !! FUNCTION
3746 : : !! Calculation of eigenvalues and eigenvectors. complex and real cases.
3747 : : !!
3748 : : !! INPUTS
3749 : : !! comm= MPI communicator
3750 : : !! cplex=1 if matrix is real, 2 if complex
3751 : : !! nbli_global number of lines
3752 : : !! nbco_global number of columns
3753 : : !! matrix= the matrix to process
3754 : : !! vector= eigenvalues of the matrix
3755 : : !! istwf_k= 2 if we have a real matrix else complex.
3756 : : !! [use_gpu_elpa]= Flag to activate the use of GPU (ELPA only)
3757 : : !!
3758 : : !! OUTPUT
3759 : : !! vector
3760 : : !!
3761 : : !! SIDE EFFECTS
3762 : : !! results= ScaLAPACK matrix coming out of the operation
3763 : : !! eigen= eigenvalues of the matrix
3764 : : !!
3765 : : !! SOURCE
3766 : :
3767 : 0 : subroutine compute_eigen1(comm,processor,cplex,nbli_global,nbco_global,matrix,vector,istwf_k,&
3768 : : use_gpu_elpa) ! Optional argument
3769 : :
3770 : : !Arguments ------------------------------------
3771 : : !scalaras
3772 : : integer,intent(in) :: comm
3773 : : integer,intent(in) :: cplex,nbli_global,nbco_global
3774 : : integer,intent(in) :: istwf_k
3775 : : class(slk_processor_t),intent(in) :: processor
3776 : : integer,intent(in),optional :: use_gpu_elpa
3777 : : !arrays
3778 : : real(dp),intent(inout) :: matrix(cplex*nbli_global,nbco_global)
3779 : : real(dp),intent(inout) :: vector(:)
3780 : :
3781 : : !Local variables-------------------------------
3782 : : #if defined(HAVE_LINALG_ELPA) || defined(HAVE_LINALG_SLATE)
3783 : : integer :: i,j
3784 : : #endif
3785 : : integer :: ierr,use_gpu_elpa_
3786 [ # # # # : 0 : type(slkmat_dp_t) :: sca_matrix1
# # ]
3787 [ # # # # : 0 : type(slkmat_dp_t) :: sca_matrix2
# # ]
3788 : 0 : real(dp),allocatable :: r_tmp_evec(:,:)
3789 : 0 : complex(dpc),allocatable :: z_tmp_evec(:,:)
3790 : : ! *************************************************************************
3791 : :
3792 : 0 : use_gpu_elpa_=0
3793 : : #if defined(HAVE_LINALG_ELPA) || defined(HAVE_LINALG_SLATE)
3794 : : if (present(use_gpu_elpa)) use_gpu_elpa_=use_gpu_elpa
3795 : : #endif
3796 : :
3797 : : ! ================================
3798 : : ! INITIALISATION SCALAPACK MATRIX
3799 : : ! ================================
3800 : 0 : call sca_matrix1%init(nbli_global,nbco_global,processor,istwf_k)
3801 : 0 : call sca_matrix2%init(nbli_global,nbco_global,processor,istwf_k)
3802 : :
3803 : : ! ==============================
3804 : : ! FILLING SCALAPACK MATRIX
3805 : : ! ==============================
3806 [ # # ]: 0 : if ( istwf_k /= 2 ) then
3807 [ # # ]: 0 : ABI_CHECK_IEQ(cplex, 2, "cplex != 2")
3808 [ # # # # : 0 : ABI_MALLOC(z_tmp_evec,(nbli_global,nbco_global))
# # # # #
# # # # #
# # ]
3809 [ # # # # ]: 0 : z_tmp_evec=cmplx(0._DP,0._DP)
3810 : : #if defined(HAVE_LINALG_ELPA) || defined(HAVE_LINALG_SLATE)
3811 : : ! The full matrix must be set (not only one half like in scalapack).
3812 : : do j=1,nbco_global
3813 : : do i=j+1,nbli_global
3814 : : matrix(2*(i-1)+1,j) = matrix(2*(j-1)+1,i)
3815 : : matrix(2*(i-1)+2,j) = -matrix(2*(j-1)+2,i)
3816 : : end do
3817 : : end do
3818 : : #endif
3819 : 0 : call sca_matrix1%from_complex_glob(matrix,istwf_k)
3820 : : else
3821 [ # # ]: 0 : ABI_CHECK_IEQ(cplex, 1, "cplex != 2")
3822 [ # # # # : 0 : ABI_MALLOC(r_tmp_evec,(nbli_global,nbco_global))
# # # # #
# # # # #
# # ]
3823 [ # # # # ]: 0 : r_tmp_evec(:,:)=0._DP
3824 : : #if defined(HAVE_LINALG_ELPA) || defined(HAVE_LINALG_SLATE)
3825 : : ! The full matrix must be set (not only one half like in scalapack).
3826 : : do j=1,nbco_global
3827 : : do i=j+1,nbli_global
3828 : : matrix(i,j) = matrix(j,i)
3829 : : end do
3830 : : end do
3831 : : #endif
3832 : 0 : call sca_matrix1%from_real_glob(matrix, istwf_k)
3833 : : endif
3834 : :
3835 : : ! ================================
3836 : : ! COMPUTE EIGEN VALUES AND VECTORS : A * X = lambda * X
3837 : : ! ================================
3838 : : call compute_eigen_problem(processor,sca_matrix1, sca_matrix2,vector, comm,istwf_k, &
3839 : 0 : use_gpu_elpa=use_gpu_elpa_)
3840 : :
3841 : : ! ==============================
3842 : : ! CONCATENATE EIGEN VECTORS
3843 : : ! ==============================
3844 : : #ifdef HAVE_MPI
3845 [ # # ]: 0 : if (istwf_k /= 2) then
3846 : 0 : call sca_matrix2%to_complex_glob(z_tmp_evec, istwf_k)
3847 : 0 : call MPI_ALLREDUCE(z_tmp_evec, matrix, nbli_global*nbco_global, MPI_DOUBLE_complex, MPI_SUM,comm,ierr)
3848 : : else
3849 : 0 : call sca_matrix2%to_real_glob(r_tmp_evec, istwf_k)
3850 : 0 : call MPI_ALLREDUCE(r_tmp_evec, matrix, nbli_global*nbco_global, MPI_DOUBLE_PRECISION, MPI_SUM,comm,ierr)
3851 : : endif
3852 : : #endif
3853 : :
3854 : : ! ====================================
3855 : : ! DESTRUCTION SCALAPACK AND TMP MATRICES
3856 : : ! ====================================
3857 : 0 : call sca_matrix1%free()
3858 : 0 : call sca_matrix2%free()
3859 : :
3860 [ # # ]: 0 : ABI_SFREE(z_tmp_evec)
3861 [ # # ]: 0 : ABI_SFREE(r_tmp_evec)
3862 : :
3863 : : #ifndef HAVE_LINALG_ELPA
3864 : : ABI_UNUSED(use_gpu_elpa)
3865 : : #endif
3866 : :
3867 [ # # # # : 0 : end subroutine compute_eigen1
# # # # #
# # # ]
3868 : : !!***
3869 : :
3870 : : !----------------------------------------------------------------------
3871 : :
3872 : : !!****f* m_slk/compute_eigen2
3873 : : !! NAME
3874 : : !! compute_eigen2
3875 : : !!
3876 : : !! FUNCTION
3877 : : !! Calculation of eigenvalues and eigenvectors: A * X = lambda * B * X
3878 : : !! complex and real cases.
3879 : : !!
3880 : : !! INPUTS
3881 : : !! comm= MPI communicator
3882 : : !! cplex=1 if matrix is real, 2 if complex
3883 : : !! nbli_global number of lines
3884 : : !! nbco_global number of columns
3885 : : !! matrix1= first ScaLAPACK matrix (matrix A)
3886 : : !! matrix2= second ScaLAPACK matrix (matrix B)
3887 : : !! vector=
3888 : : !! istwf_k= 2 if we have a real matrix else complex.
3889 : : !! [use_gpu_elpa]= Flag to activate the use of GPU (ELPA only)
3890 : : !!
3891 : : !! SIDE EFFECTS
3892 : : !! results= ScaLAPACK matrix coming out of the operation
3893 : : !! eigen= eigenvalues of the matrix
3894 : : !!
3895 : : !! SOURCE
3896 : :
3897 : 0 : subroutine compute_eigen2(comm,processor,cplex,nbli_global,nbco_global,matrix1,matrix2,vector,istwf_k, &
3898 : : use_gpu_elpa) ! Optional argument
3899 : :
3900 : : !Arguments ------------------------------------
3901 : : !scalars
3902 : : integer,intent(in) :: cplex,nbli_global,nbco_global
3903 : : integer,intent(in) :: comm
3904 : : integer,intent(in) :: istwf_k
3905 : : class(slk_processor_t),intent(in) :: processor
3906 : : integer,optional,intent(in) :: use_gpu_elpa
3907 : : !arrays
3908 : : real(dp),intent(inout) :: matrix1(cplex*nbli_global,nbco_global)
3909 : : real(dp),intent(inout) :: matrix2(cplex*nbli_global,nbco_global)
3910 : : real(dp),intent(inout) :: vector(:)
3911 : :
3912 : : !Local variables-------------------------------
3913 : : #if defined(HAVE_LINALG_ELPA) || defined(HAVE_LINALG_SLATE)
3914 : : integer :: i,j
3915 : : #endif
3916 : : integer :: ierr,use_gpu_elpa_
3917 [ # # # # : 0 : type(slkmat_dp_t) :: sca_matrix1, sca_matrix2, sca_matrix3
# # # # #
# # # # #
# # # # ]
3918 : 0 : real(dp),allocatable :: r_tmp_evec(:,:)
3919 : 0 : complex(dpc),allocatable :: z_tmp_evec(:,:)
3920 : : ! *************************************************************************
3921 : :
3922 : 0 : use_gpu_elpa_=0
3923 : : #if defined HAVE_LINALG_ELPA
3924 : : if (present(use_gpu_elpa)) use_gpu_elpa_=use_gpu_elpa
3925 : : #endif
3926 : :
3927 : : ! ================================
3928 : : ! INITIALISATION SCALAPACK MATRIX
3929 : : ! ================================
3930 : 0 : call sca_matrix1%init(nbli_global,nbco_global,processor,istwf_k)
3931 : 0 : call sca_matrix2%init(nbli_global,nbco_global,processor,istwf_k)
3932 : 0 : call sca_matrix3%init(nbli_global,nbco_global,processor,istwf_k)
3933 : :
3934 : : ! ==============================
3935 : : ! FILLING SCALAPACK MATRIX
3936 : : ! ==============================
3937 [ # # ]: 0 : if ( istwf_k /= 2 ) then
3938 [ # # ]: 0 : ABI_CHECK_IEQ(cplex, 2, "cplex != 2")
3939 [ # # # # : 0 : ABI_MALLOC(z_tmp_evec,(nbli_global,nbco_global))
# # # # #
# # # # #
# # ]
3940 [ # # # # ]: 0 : z_tmp_evec=cmplx(0._DP,0._DP)
3941 : : #if defined(HAVE_LINALG_ELPA) || defined(HAVE_LINALG_SLATE)
3942 : : ! The full matrix must be set (not only one half like in scalapack).
3943 : : do j=1,nbco_global
3944 : : do i=j+1,nbli_global
3945 : : matrix1(2*(i-1)+1,j) = matrix1(2*(j-1)+1,i)
3946 : : matrix1(2*(i-1)+2,j) = -matrix1(2*(j-1)+2,i)
3947 : : matrix2(2*(i-1)+1,j) = matrix2(2*(j-1)+1,i)
3948 : : matrix2(2*(i-1)+2,j) = -matrix2(2*(j-1)+2,i)
3949 : : end do
3950 : : end do
3951 : : #endif
3952 : 0 : call sca_matrix1%from_complex_glob(matrix1, istwf_k)
3953 : 0 : call sca_matrix2%from_complex_glob(matrix2, istwf_k)
3954 : : else
3955 [ # # ]: 0 : ABI_CHECK_IEQ(cplex, 1, "cplex != 1")
3956 [ # # # # : 0 : ABI_MALLOC(r_tmp_evec,(nbli_global,nbco_global))
# # # # #
# # # # #
# # ]
3957 [ # # # # ]: 0 : r_tmp_evec(:,:)=0._DP
3958 : : #if defined(HAVE_LINALG_ELPA) || defined(HAVE_LINALG_SLATE)
3959 : : ! The full matrix must be set (not only one half like in scalapack).
3960 : : do j=1,nbco_global
3961 : : do i=j+1,nbli_global
3962 : : matrix1(i,j) = matrix1(j,i)
3963 : : matrix2(i,j) = matrix2(j,i)
3964 : : end do
3965 : : end do
3966 : : #endif
3967 : 0 : call sca_matrix1%from_real_glob(matrix1,istwf_k)
3968 : 0 : call sca_matrix2%from_real_glob(matrix2,istwf_k)
3969 : : endif
3970 : :
3971 : : ! ================================
3972 : : ! COMPUTE EIGEN VALUES AND VECTORS : A * X = lambda * B * X
3973 : : ! ================================
3974 : : call compute_generalized_eigen_problem(processor,sca_matrix1,sca_matrix2,&
3975 : 0 : sca_matrix3,vector,comm,istwf_k,use_gpu_elpa=use_gpu_elpa_)
3976 : :
3977 : : ! ==============================
3978 : : ! CONCATENATE EIGEN VECTORS
3979 : : ! ==============================
3980 : : #ifdef HAVE_MPI
3981 [ # # ]: 0 : if ( istwf_k /= 2 ) then
3982 : 0 : call sca_matrix3%to_complex_glob(z_tmp_evec,istwf_k)
3983 : 0 : call MPI_ALLREDUCE(z_tmp_evec, matrix1, nbli_global*nbco_global, MPI_DOUBLE_complex, MPI_SUM,comm,ierr)
3984 [ # # ]: 0 : ABI_FREE(z_tmp_evec)
3985 : : else
3986 : 0 : call sca_matrix3%to_real_glob(r_tmp_evec, istwf_k)
3987 : 0 : call MPI_ALLREDUCE(r_tmp_evec, matrix1, nbli_global*nbco_global, MPI_DOUBLE_PRECISION, MPI_SUM,comm,ierr)
3988 [ # # ]: 0 : ABI_FREE(r_tmp_evec)
3989 : : endif
3990 : : #endif
3991 : :
3992 : : ! ====================================
3993 : : ! DESTRUCTION SCALAPACK AND TMP MATRICES
3994 : : ! ====================================
3995 : 0 : call sca_matrix1%free()
3996 : 0 : call sca_matrix2%free()
3997 : 0 : call sca_matrix3%free()
3998 : :
3999 : : #ifndef HAVE_LINALG_ELPA
4000 : : ABI_UNUSED(use_gpu_elpa)
4001 : : #endif
4002 : :
4003 [ # # # # : 0 : end subroutine compute_eigen2
# # # # #
# # # # #
# # ]
4004 : : !!***
4005 : :
4006 : : !----------------------------------------------------------------------
4007 : :
4008 : : !!****f* m_slk/slkmat_dp_heev
4009 : : !! NAME
4010 : : !! slkmat_dp_heev
4011 : : !!
4012 : : !! FUNCTION
4013 : : !! slkmat_dp_heev computes selected eigenvalues and, optionally, eigenvectors of an Hermitian matrix A.
4014 : : !! A * X = lambda * X
4015 : : !!
4016 : : !! INPUTS
4017 : : !! JOBZ (global input) CHARACTER*1
4018 : : !! Specifies whether or not to compute the eigenvectors:
4019 : : !! = "N": Compute eigenvalues only.
4020 : : !! = "V": Compute eigenvalues and eigenvectors.
4021 : : !! UPLO (global input) CHARACTER*1
4022 : : !! Specifies whether the upper or lower triangular part of the symmetric matrix A is stored:
4023 : : !! = "U": Upper triangular
4024 : : !! = "L": Lower triangular
4025 : : !!
4026 : : !! mat=The object storing the local buffer in DOUBLE PRECISION, the array descriptor, the PBLAS context.
4027 : : !! vec=The distributed eigenvectors. Not referenced if JOBZ="N"
4028 : : !!
4029 : : !! OUTPUT
4030 : : !! W (global output) array, dimension (N) where N is the rank of the global matrix.
4031 : : !! On normal exit, the first M entries contain the selected eigenvalues in ascending order.
4032 : : !!
4033 : : !! SIDE EFFECTS
4034 : : !! If JOBZ="V", the local buffer vec%buffer_cplx will contain part of the distributed eigenvectors.
4035 : : !! On exit, the lower triangle (if UPLO='L') or the upper triangle (if UPLO='U') of A, including the diagonal, is destroyed.
4036 : : !!
4037 : : !! SOURCE
4038 : :
4039 : 0 : subroutine slkmat_dp_heev(mat, jobz, uplo, vec, w, &
4040 : : mat_size, ija, ijz) ! Optional
4041 : :
4042 : : !Arguments ------------------------------------
4043 : : !scalars
4044 : : class(slkmat_dp_t),intent(inout) :: mat
4045 : : character(len=*),intent(in) :: jobz, uplo
4046 : : class(slkmat_dp_t),intent(inout) :: vec
4047 : : !arrays
4048 : : real(dp),intent(out) :: w(:)
4049 : : integer,optional,intent(in) :: mat_size, ija(2), ijz(2)
4050 : :
4051 : : #ifdef HAVE_LINALG_SCALAPACK
4052 : : !Local variables ------------------------------
4053 : : !scalars
4054 : : integer :: lwork, lrwork, info, nn
4055 : : !character(len=500) :: msg
4056 : : !arrays
4057 : : integer :: ija__(2), ijz__(2)
4058 : : real(dp),allocatable :: rwork_dp(:)
4059 : : complex(dp),allocatable :: work_dp(:)
4060 : : !************************************************************************
4061 : :
4062 : : ABI_CHECK(allocated(mat%buffer_cplx), "buffer_cplx not allocated")
4063 : :
4064 : : nn = mat%size_global(2); if (present(mat_size)) nn = mat_size
4065 : : ija__ = [1, 1]; if (present(ija)) ija__ = ija
4066 : : ijz__ = [1, 1]; if (present(ijz)) ijz__ = ijz
4067 : :
4068 : : ! Get optimal size of workspace.
4069 : : lwork = - 1; lrwork = -1
4070 : : ABI_MALLOC(work_dp, (1))
4071 : : ABI_MALLOC(rwork_dp, (1))
4072 : :
4073 : : !call pzheev(jobz, uplo, n, a, ia, ja, desca, w, z, iz, jz, descz, work, lwork, rwork, lrwork, info)
4074 : :
4075 : : call PZHEEV(jobz, uplo, nn, mat%buffer_cplx, ija__(1), ija__(2), mat%desc, &
4076 : : w, vec%buffer_cplx, ijz__(1), ijz__(2), vec%desc, work_dp, lwork, rwork_dp, lrwork, info)
4077 : : ABI_CHECK(info == 0, sjoin("Error in the calculation of the workspace size, info:", itoa(info)))
4078 : :
4079 : : lwork = NINT(real(work_dp(1))); lrwork= NINT(rwork_dp(1)) !*2
4080 : : ABI_FREE(work_dp)
4081 : : ABI_FREE(rwork_dp)
4082 : :
4083 : : ! MG: Nov 23 2011. On my mac with the official scalapack package, rwork(1) is not large enough and causes a SIGFAULT.
4084 : : if (firstchar(jobz, ['V'])) then
4085 : : if (lrwork < 2*nn + 2*nn-2) lrwork = 2*nn + 2*nn-2
4086 : : else if (firstchar(jobz, ['N'])) then
4087 : : if (lrwork < 2*nn) lrwork = 2*nn
4088 : : end if
4089 : : !write(std_out,*)lwork,lrwork
4090 : :
4091 : : ! Solve the problem.
4092 : : ABI_MALLOC(work_dp, (lwork))
4093 : : ABI_MALLOC(rwork_dp, (lrwork))
4094 : :
4095 : : call PZHEEV(jobz, uplo, nn, mat%buffer_cplx, ija__(1), ija__(2), mat%desc, &
4096 : : w, vec%buffer_cplx, ijz__(1), ijz__(2), vec%desc, work_dp, lwork, rwork_dp, lrwork, info)
4097 : : ABI_CHECK(info == 0, sjoin("PZHEEV returned info:", itoa(info)))
4098 : : ABI_FREE(work_dp)
4099 : : ABI_FREE(rwork_dp)
4100 : : #endif
4101 : :
4102 : 0 : end subroutine slkmat_dp_heev
4103 : : !!***
4104 : :
4105 : : !----------------------------------------------------------------------
4106 : :
4107 : : !!****f* m_slk/slkmat_sp_heev
4108 : : !! NAME
4109 : : !! slkmat_sp_heev
4110 : : !!
4111 : : !! FUNCTION
4112 : : !! slkmat_sp_heev computes selected eigenvalues and, optionally, eigenvectors of an Hermitian matrix A.
4113 : : !! A * X = lambda * X
4114 : : !!
4115 : : !! INPUTS
4116 : : !! JOBZ (global input) CHARACTER*1
4117 : : !! Specifies whether or not to compute the eigenvectors:
4118 : : !! = "N": Compute eigenvalues only.
4119 : : !! = "V": Compute eigenvalues and eigenvectors.
4120 : : !! UPLO (global input) CHARACTER*1
4121 : : !! Specifies whether the upper or lower triangular part of the symmetric matrix A is stored:
4122 : : !! = "U": Upper triangular
4123 : : !! = "L": Lower triangular
4124 : : !!
4125 : : !! mat=The object storing the local buffer in SINGLE PRECISION, the array descriptor, the PBLAS context.
4126 : : !! vec=The distributed eigenvectors. Not referenced if JOBZ="N"
4127 : : !!
4128 : : !! OUTPUT
4129 : : !! W (global output) array, dimension (N) where N is the rank of the global matrix.
4130 : : !! On normal exit, the first M entries contain the selected eigenvalues in ascending order.
4131 : : !!
4132 : : !! SIDE EFFECTS
4133 : : !! If JOBZ="V", the local buffer vec%buffer_cplx will contain part of the distributed eigenvectors.
4134 : : !! On exit, the lower triangle (if UPLO='L') or the upper triangle (if UPLO='U') of A, including the diagonal, is destroyed.
4135 : : !!
4136 : : !! SOURCE
4137 : :
4138 : 0 : subroutine slkmat_sp_heev(mat, jobz, uplo, vec, w, &
4139 : : mat_size, ija, ijz) ! Optional
4140 : :
4141 : : !Arguments ------------------------------------
4142 : : !scalars
4143 : : class(slkmat_sp_t),intent(inout) :: mat
4144 : : character(len=*),intent(in) :: jobz, uplo
4145 : : class(slkmat_sp_t),intent(inout) :: vec
4146 : : !arrays
4147 : : real(sp),intent(out) :: w(:)
4148 : : integer,optional,intent(in) :: mat_size, ija(2), ijz(2)
4149 : :
4150 : : #ifdef HAVE_LINALG_SCALAPACK
4151 : : !Local variables ------------------------------
4152 : : !scalars
4153 : : integer :: lwork, lrwork, info, nn
4154 : : !arrays
4155 : : integer :: ija__(2), ijz__(2)
4156 : : real(sp),allocatable :: rwork_sp(:)
4157 : : complex(sp),allocatable :: work_sp(:)
4158 : : !************************************************************************
4159 : :
4160 : : ABI_CHECK(allocated(mat%buffer_cplx), "buffer_cplx not allocated")
4161 : :
4162 : : nn = mat%size_global(2); if (present(mat_size)) nn = mat_size
4163 : : ija__ = [1, 1]; if (present(ija)) ija__ = ija
4164 : : ijz__ = [1, 1]; if (present(ijz)) ijz__ = ijz
4165 : :
4166 : : ! Get optimal size of workspace.
4167 : : lwork = - 1; lrwork = -1
4168 : : ABI_MALLOC(work_sp, (1))
4169 : : ABI_MALLOC(rwork_sp, (1))
4170 : :
4171 : : !call pzheev(jobz, uplo, n, a, ia, ja, desca, w, z, iz, jz, descz, work, lwork, rwork, lrwork, info)
4172 : :
4173 : : call PCHEEV(jobz, uplo, nn, mat%buffer_cplx, ija__(1), ija__(2), mat%desc, &
4174 : : w, vec%buffer_cplx, ijz__(1), ijz__(2), vec%desc, work_sp, lwork, rwork_sp, lrwork, info)
4175 : : ABI_CHECK(info == 0, sjoin("Error in the calculation of the workspace size, info:", itoa(info)))
4176 : :
4177 : : lwork = NINT(real(work_sp(1))); lrwork= NINT(rwork_sp(1)) !*2
4178 : : ABI_FREE(work_sp)
4179 : : ABI_FREE(rwork_sp)
4180 : :
4181 : : ! MG: Nov 23 2011. On my mac with the official scalapack package, rwork(1) is not large enough and causes a SIGFAULT.
4182 : : if (firstchar(jobz, ['V'])) then
4183 : : if (lrwork < 2*nn + 2*nn-2) lrwork = 2*nn + 2*nn-2
4184 : : else if (firstchar(jobz, ['N'])) then
4185 : : if (lrwork < 2*nn) lrwork = 2*nn
4186 : : end if
4187 : : !write(std_out,*)lwork,lrwork
4188 : :
4189 : : ! Solve the problem.
4190 : : ABI_MALLOC(work_sp, (lwork))
4191 : : ABI_MALLOC(rwork_sp, (lrwork))
4192 : :
4193 : : call PCHEEV(jobz, uplo, nn, mat%buffer_cplx, ija__(1), ija__(2), mat%desc, &
4194 : : w, vec%buffer_cplx, ijz__(1), ijz__(2), vec%desc, work_sp, lwork, rwork_sp, lrwork, info)
4195 : : ABI_CHECK(info == 0, sjoin("PCHEEV returned info:", itoa(info)))
4196 : : ABI_FREE(work_sp)
4197 : : ABI_FREE(rwork_sp)
4198 : : #endif
4199 : :
4200 : 0 : end subroutine slkmat_sp_heev
4201 : : !!***
4202 : :
4203 : : !----------------------------------------------------------------------
4204 : :
4205 : : !!****f* m_slk/slkmat_dp_pzheevx
4206 : : !! NAME
4207 : : !! slkmat_dp_pzheevx
4208 : : !!
4209 : : !! FUNCTION
4210 : : !! slkmat_dp_pzheevx computes selected eigenvalues and, optionally, eigenvectors of a complex Hermitian matrix A.
4211 : : !! A * X = lambda * X
4212 : : !!
4213 : : !! INPUTS
4214 : : !! mat=ScaLAPACK matrix (matrix A)
4215 : : !!
4216 : : !! vec=The distributed eigenvectors X. Not referenced if JOBZ="N"
4217 : : !!
4218 : : !! JOBZ (global input) CHARACTER*1
4219 : : !! Specifies whether or not to compute the eigenvectors:
4220 : : !! = "N": Compute eigenvalues only.
4221 : : !! = "V": Compute eigenvalues and eigenvectors.
4222 : : !!
4223 : : !! RANGE (global input) CHARACTER*1
4224 : : !! = "A": all eigenvalues will be found.
4225 : : !! = "V": all eigenvalues in the interval [VL,VU] will be found.
4226 : : !! = "I": the IL-th through IU-th eigenvalues will be found.
4227 : : !!
4228 : : !! UPLO (global input) CHARACTER*1
4229 : : !! Specifies whether the upper or lower triangular part of the Hermitian matrix A is stored:
4230 : : !! = "U": Upper triangular
4231 : : !! = "L": Lower triangular
4232 : : !!
4233 : : !! VL (global input) DOUBLE PRECISION
4234 : : !! If RANGE="V",the lower bound of the interval to be searched for eigenvalues. Not referenced if RANGE =
4235 : : !! "A" or "I"
4236 : : !!
4237 : : !! VU (global input) DOUBLE PRECISION
4238 : : !! If RANGE="V", the upper bound of the interval to be searched for eigenvalues. Not referenced if RANGE =
4239 : : !! "A" or "I".
4240 : : !!
4241 : : !! IL (global input) integer
4242 : : !! If RANGE="I", the index (from smallest to largest) of the smallest eigenvalue to be returned. IL >= 1.
4243 : : !! Not referenced if RANGE = "A" or "V".
4244 : : !!
4245 : : !! IU (global input) integer
4246 : : !! If RANGE="I", the index (from smallest to largest) of the largest eigenvalue to be returned. min(IL,N) <=
4247 : : !! IU <= N. Not referenced if RANGE = "A" or "V"
4248 : : !!
4249 : : !! ABSTOL (global input) DOUBLE PRECISION
4250 : : !! If JOBZ="V", setting ABSTOL to PDLAMCH( CONTEXT, "U") yields the most orthogonal eigenvectors.
4251 : : !! The absolute error tolerance for the eigenvalues. An approximate eigenvalue is accepted as converged when
4252 : : !! it is determined to lie in an interval [a,b] of width less than or equal to
4253 : : !!
4254 : : !! ABSTOL + EPS * max( |a|,|b| ) ,
4255 : : !!
4256 : : !! where EPS is the machine precision. If ABSTOL is less than or equal to zero, then EPS*norm(T) will be used
4257 : : !! in its place, where norm(T) is the 1-norm of the tridiagonal matrix obtained by reducing A to tridiagonal form.
4258 : : !! Eigenvalues will be computed most accurately when ABSTOL is set to twice the underflow threshold
4259 : : !! 2*PDLAMCH("S") not zero. If this routine returns with ((MOD(INFO,2).NE.0) .OR. (MOD(INFO/8,2).NE.0)),
4260 : : !! indicating that some eigenvalues or eigenvectors did not converge, try setting ABSTOL to 2*PDLAMCH("S").
4261 : : !!
4262 : : !! OUTPUT
4263 : : !! mene_found= (global output) Total number of eigenvalues found. 0 <= mene_found <= N.
4264 : : !! eigen(N)= (global output) Eigenvalues of A where N is the dimension of M
4265 : : !! On normal exit, the first mene_found entries contain the selected eigenvalues in ascending order.
4266 : : !!
4267 : : !! SIDE EFFECTS
4268 : : !! If JOBZ="V", the local buffer vec%buffer_cplx will contain part of the distributed eigenvectors.
4269 : : !! Slk%mat%buffer_cplx is destroyed when the routine returns
4270 : : !!
4271 : : !! SOURCE
4272 : :
4273 : 0 : subroutine slkmat_dp_pzheevx(mat, jobz, range, uplo, vl, vu, il, iu, abstol, vec, mene_found, eigen)
4274 : :
4275 : : !Arguments ------------------------------------
4276 : : class(slkmat_dp_t),intent(inout) :: mat
4277 : : integer,intent(in) :: il, iu
4278 : : integer,intent(out) :: mene_found
4279 : : real(dp),intent(in) :: abstol,vl,vu
4280 : : character(len=*),intent(in) :: jobz,range,uplo
4281 : : class(slkmat_dp_t),intent(inout) :: vec
4282 : : !arrays
4283 : : real(dp),intent(out) :: eigen(*)
4284 : :
4285 : : #ifdef HAVE_LINALG_SCALAPACK
4286 : : !Local variables-------------------------------
4287 : : !scalars
4288 : : integer :: lwork,lrwork,liwork,info,nvec_calc !,ierr
4289 : : real(dp) :: orfac
4290 : : character(len=500) :: msg
4291 : : !arrays
4292 : : !integer :: ibuff(3),max_ibuff(3)
4293 : : integer,allocatable :: iwork(:),iclustr(:),ifail(:)
4294 : : real(dp),allocatable :: rwork(:),gap(:)
4295 : : complex(dpc),allocatable :: work(:)
4296 : : !************************************************************************
4297 : :
4298 : : ABI_CHECK(allocated(mat%buffer_cplx), "buffer_cplx is not allocated!")
4299 : :
4300 : : ! abstol = PDLAMCH(vec%processor%grid%comm,'U')
4301 : :
4302 : : orfac = -one ! Only for eigenvectors: use default value 10d-3.
4303 : : ! Vectors within orfac*norm(A) will be reorthogonalized.
4304 : :
4305 : : ! Allocate the arrays for the results of the calculation
4306 : : ABI_MALLOC(gap, (mat%processor%grid%dims(1) * mat%processor%grid%dims(2)))
4307 : :
4308 : : if (firstchar(jobz, ["V","v"])) then
4309 : : ABI_MALLOC(ifail, (mat%size_global(2)))
4310 : : ABI_MALLOC(iclustr, (2*mat%processor%grid%dims(1) * mat%processor%grid%dims(2)))
4311 : : end if
4312 : :
4313 : : ! Get the optimal size of the work arrays.
4314 : : lwork=-1; lrwork=-1; liwork=-1
4315 : : ABI_MALLOC(work, (1))
4316 : : ABI_MALLOC(iwork, (1))
4317 : : ABI_MALLOC(rwork, (3))
4318 : : ! This is clearly seen in the source in which rwork(1:3) is accessed
4319 : : ! in the calculation of the workspace size.
4320 : :
4321 : : ! prototype
4322 : : !call pzheevx(jobz, range, uplo, n, a, ia, ja, desca, vl, vu, il, iu, abstol, m, nz, w,
4323 : : ! orfac, z, iz, jz, descz, work, lwork, rwork, lrwork, iwork, liwork, ifail, iclustr, gap, info)
4324 : :
4325 : : call PZHEEVX(jobz,range,uplo, mat%size_global(2),mat%buffer_cplx,1,1,mat%desc,&
4326 : : vl,vu,il,iu,abstol,mene_found,nvec_calc,eigen,orfac,&
4327 : : vec%buffer_cplx,1,1,vec%desc,&
4328 : : work,lwork,rwork,lrwork,iwork,liwork,ifail,iclustr,gap,info)
4329 : :
4330 : : ABI_CHECK(info == 0, sjoin("Problem to compute workspace, info:", itoa(info)))
4331 : :
4332 : : lwork = NINT(real(work(1)),kind=dp)
4333 : : lrwork = NINT(rwork(1))
4334 : : liwork = iwork(1)
4335 : :
4336 : : ABI_FREE(work)
4337 : : ABI_FREE(rwork)
4338 : : ABI_FREE(iwork)
4339 : : !
4340 : : ! FROM THE SCALAPACK MAN PAGE:
4341 : : ! The computed eigenvectors may not be orthogonal if the minimal workspace is supplied and ORFAC is too
4342 : : ! small. If you want to guarantee orthogonality (at the cost of potentially poor performance) you should
4343 : : ! add the following to LRWORK: (CLUSTERSIZE-1)*N where CLUSTERSIZE is the number of eigenvalues in the
4344 : : ! largest cluster, where a cluster is defined as a set of close eigenvalues: { W(K),...,W(K+CLUSTERSIZE-1) |
4345 : : ! W(J+1) <= W(J) + ORFAC*2*norm(A) }.
4346 : :
4347 : : if (firstchar(jobz, ["V","v"])) then
4348 : : lrwork = INT( lrwork + mat%size_global(2) *(mat%size_global(2)-1) )
4349 : : end if
4350 : :
4351 : : ! ibuff(1) = lwork
4352 : : ! ibuff(2) = lrwork !INT(lrwork + mat%size_global(2) *(mat%size_global(2)-1)
4353 : : ! ibuff(3) = liwork
4354 : :
4355 : : ! Get the maximum of sizes of the work arrays processor%comm
4356 : : ! call MPI_ALLREDUCE(ibuff,max_ibuff,3,MPI_integer,MPI_MAX,comm,ierr)
4357 : :
4358 : : ! lwork = max_ibuff(1)
4359 : : ! lrwork = max_ibuff(2)
4360 : : ! liwork = max_ibuff(3)
4361 : :
4362 : : ABI_MALLOC(work , (lwork ))
4363 : : ABI_MALLOC(rwork, (lrwork))
4364 : : ABI_MALLOC(iwork, (liwork))
4365 : :
4366 : : ! prototype
4367 : : !call pzheevx(jobz, range, uplo, n, a, ia, ja, desca, vl, vu, il, iu, abstol, m, nz, w,
4368 : : ! orfac, z, iz, jz, descz, work, lwork, rwork, lrwork, iwork, liwork, ifail, iclustr, gap, info)
4369 : :
4370 : : ! Call the scaLAPACK routine.
4371 : : ! write(std_out,*) 'I am using PZHEEVX'
4372 : : call PZHEEVX(jobz,range,uplo, mat%size_global(2),mat%buffer_cplx,1,1,mat%desc,&
4373 : : vl,vu,il,iu,abstol,mene_found,nvec_calc, eigen,orfac,&
4374 : : vec%buffer_cplx,1,1,vec%desc,&
4375 : : work,lwork,rwork,lrwork,iwork,liwork,ifail,iclustr,gap,info)
4376 : :
4377 : : ! Handle possible error.
4378 : : if (info < 0) then
4379 : : write(msg,'(a,i0,a)')" The ", -info, "-th argument of P?HEEVX had an illegal value."
4380 : : if (info == -25) msg = " LRWORK is too small to compute all the eigenvectors requested, no computation is performed"
4381 : : ABI_ERROR(msg)
4382 : : end if
4383 : :
4384 : : if (info > 0) then
4385 : : write(msg,'(a,i0)') " P?HEEVX returned info: ",info
4386 : : call wrtout(std_out, msg)
4387 : : if (MOD(info, 2) /= 0)then
4388 : : write(msg,'(3a)')&
4389 : : " One or more eigenvectors failed to converge. ",ch10,&
4390 : : " Their indices are stored in IFAIL. Ensure ABSTOL=2.0*PDLAMCH('U')"
4391 : : call wrtout(std_out, msg)
4392 : : end if
4393 : : if (MOD(info / 2, 2) /= 0) then
4394 : : write(msg,'(5a)')&
4395 : : " Eigenvectors corresponding to one or more clusters of eigenvalues ",ch10,&
4396 : : " could not be reorthogonalized because of insufficient workspace. ",ch10,&
4397 : : " The indices of the clusters are stored in the array ICLUSTR."
4398 : : call wrtout(std_out, msg)
4399 : : end if
4400 : : if (MOD(info / 4, 2) /= 0) then
4401 : : write(msg,'(3a)')" Space limit prevented PZHEEVX from computing all of the eigenvectors between VL and VU. ",ch10,&
4402 : : " The number of eigenvectors computed is returned in NZ."
4403 : : call wrtout(std_out, msg)
4404 : : end if
4405 : : if (MOD(info / 8, 2) /= 0) then
4406 : : call wrtout(std_out, "PZSTEBZ failed to compute eigenvalues. Ensure ABSTOL=2.0*PDLAMCH('U')")
4407 : : end if
4408 : : ABI_ERROR("Cannot continue")
4409 : : end if
4410 : :
4411 : : ! Check the number of eigenvalues found wrt to the number of vectors calculated.
4412 : : if (firstchar(jobz, ['V','v']) .and. mene_found /= nvec_calc) then
4413 : : write(msg,'(5a)') &
4414 : : " The user supplied insufficient space and PZHEEVX is not able to detect this before beginning computation. ",ch10,&
4415 : : " To get all the eigenvectors requested, the user must supply both sufficient space to hold the ",ch10,&
4416 : : " eigenvectors in Z (M .LE. DESCZ(N_)) and sufficient workspace to compute them. "
4417 : : ABI_ERROR(msg)
4418 : : end if
4419 : :
4420 : : ABI_FREE(work)
4421 : : ABI_FREE(rwork)
4422 : : ABI_FREE(iwork)
4423 : : ABI_FREE(gap)
4424 : : ABI_SFREE(ifail)
4425 : : ABI_SFREE(iclustr)
4426 : : #endif
4427 : :
4428 : 0 : end subroutine slkmat_dp_pzheevx
4429 : : !!***
4430 : :
4431 : : !----------------------------------------------------------------------
4432 : :
4433 : : !!****f* m_slk/slkmat_dp_pzhegvx
4434 : : !! NAME
4435 : : !! slkmat_dp_pzhegvx
4436 : : !!
4437 : : !! FUNCTION
4438 : : !! slkmat_dp_pzhegvx provides an object-oriented interface to the ScaLAPACK routine PZHEGVX that
4439 : : !! computes selected eigenvalues and, optionally, eigenvectors of a complex generalized
4440 : : !! Hermitian-definite eigenproblem, of the form
4441 : : !! sub( A )*x=(lambda)*sub( B )*x, sub( A )*sub( B )x=(lambda)*x, or sub( B )*sub( A )*x=(lambda)*x.
4442 : : !! Here sub( A ) denoting A( IA:IA+N-1, JA:JA+N-1 ) is assumed to be
4443 : : !! Hermitian, and sub( B ) denoting B( IB:IB+N-1, JB:JB+N-1 ) is assumed
4444 : : !! to be Hermitian positive definite.
4445 : : !!
4446 : : !! INPUTS
4447 : : !! Slk_matA<slkmat_dp_t>=ScaLAPACK matrix (matrix A)
4448 : : !! Slk_matB<slkmat_dp_t>=ScaLAPACK matrix (matrix B)
4449 : : !! Slk_vec<slkmat_dp_t>=The distributed eigenvectors X. Not referenced if JOBZ="N"
4450 : : !!
4451 : : !! IBtype (global input) integer
4452 : : !! Specifies the problem type to be solved:
4453 : : !! = 1: sub( A )*x = (lambda)*sub( B )*x
4454 : : !! = 2: sub( A )*sub( B )*x = (lambda)*x
4455 : : !! = 3: sub( B )*sub( A )*x = (lambda)*x
4456 : : !!
4457 : : !! JOBZ (global input) CHARACTER*1
4458 : : !! Specifies whether or not to compute the eigenvectors:
4459 : : !! = "N": Compute eigenvalues only.
4460 : : !! = "V": Compute eigenvalues and eigenvectors.
4461 : : !!
4462 : : !! RANGE (global input) CHARACTER*1
4463 : : !! = "A": all eigenvalues will be found.
4464 : : !! = "V": all eigenvalues in the interval [VL,VU] will be found.
4465 : : !! = "I": the IL-th through IU-th eigenvalues will be found.
4466 : : !!
4467 : : !! UPLO (global input) CHARACTER*1
4468 : : !! Specifies whether the upper or lower triangular part of the Hermitian matrix sub(A) and sub(B) is stored:
4469 : : !! = "U": Upper triangular
4470 : : !! = "L": Lower triangular
4471 : : !!
4472 : : !! VL (global input) DOUBLE PRECISION
4473 : : !! If RANGE="V",the lower bound of the interval to be searched for eigenvalues. Not referenced if RANGE =
4474 : : !! "A" or "I"
4475 : : !!
4476 : : !! VU (global input) DOUBLE PRECISION
4477 : : !! If RANGE="V", the upper bound of the interval to be searched for eigenvalues. Not referenced if RANGE =
4478 : : !! "A" or "I".
4479 : : !!
4480 : : !! IL (global input) integer
4481 : : !! If RANGE="I", the index (from smallest to largest) of the smallest eigenvalue to be returned. IL >= 1.
4482 : : !! Not referenced if RANGE = "A" or "V".
4483 : : !!
4484 : : !! IU (global input) integer
4485 : : !! If RANGE="I", the index (from smallest to largest) of the largest eigenvalue to be returned. min(IL,N) <=
4486 : : !! IU <= N. Not referenced if RANGE = "A" or "V"
4487 : : !!
4488 : : !! ABSTOL (global input) DOUBLE PRECISION
4489 : : !! If JOBZ="V", setting ABSTOL to PDLAMCH( CONTEXT, "U") yields the most orthogonal eigenvectors.
4490 : : !! The absolute error tolerance for the eigenvalues. An approximate eigenvalue is accepted as converged when
4491 : : !! it is determined to lie in an interval [a,b] of width less than or equal to
4492 : : !!
4493 : : !! ABSTOL + EPS * max( |a|,|b| ) ,
4494 : : !!
4495 : : !! where EPS is the machine precision. If ABSTOL is less than or equal to zero, then EPS*norm(T) will be used
4496 : : !! in its place, where norm(T) is the 1-norm of the tridiagonal matrix obtained by reducing A to tridiagonal form.
4497 : : !! Eigenvalues will be computed most accurately when ABSTOL is set to twice the underflow threshold
4498 : : !! 2*PDLAMCH("S") not zero. If this routine returns with ((MOD(INFO,2).NE.0) .OR. (MOD(INFO/8,2).NE.0)),
4499 : : !! indicating that some eigenvalues or eigenvectors did not converge, try setting ABSTOL to 2*PDLAMCH("S").
4500 : : !!
4501 : : !! OUTPUT
4502 : : !! mene_found= (global output) Total number of eigenvalues found. 0 <= mene_found <= N.
4503 : : !!
4504 : : !! eigen(N)= (global output) Eigenvalues of A where N is the dimension of M
4505 : : !! On normal exit, the first mene_found entries contain the selected eigenvalues in ascending order.
4506 : : !!
4507 : : !! SIDE EFFECTS
4508 : : !! Slk_vec<slkmat_dp_t>:
4509 : : !! %buffer_cplx local output (global dimension (N,N)
4510 : : !! If JOBZ = 'V', then on normal exit the first M columns of Z
4511 : : !! contain the orthonormal eigenvectors of the matrix
4512 : : !! corresponding to the selected eigenvalues.
4513 : : !! If JOBZ = 'N', then Z is not referenced.
4514 : : !!
4515 : : !! Slk_matA<slkmat_dp_t>:
4516 : : !! %buffer_cplx
4517 : : !! (local input/local output) complex(DP) pointer into the
4518 : : !! local memory to an array of dimension (LLD_A, LOCc(JA+N-1)).
4519 : : !! On entry, this array contains the local pieces of the
4520 : : !! N-by-N Hermitian distributed matrix sub( A ). If UPLO = 'U',
4521 : : !! the leading N-by-N upper triangular part of sub( A ) contains
4522 : : !! the upper triangular part of the matrix. If UPLO = 'L', the
4523 : : !! leading N-by-N lower triangular part of sub( A ) contains
4524 : : !! the lower triangular part of the matrix.
4525 : : !!
4526 : : !! On exit, if JOBZ = 'V', then if INFO = 0, sub( A ) contains
4527 : : !! the distributed matrix Z of eigenvectors. The eigenvectors
4528 : : !! are normalized as follows:
4529 : : !! if IBtype = 1 or 2, Z**H*sub( B )*Z = I;
4530 : : !! if IBtype = 3, Z**H*inv( sub( B ) )*Z = I.
4531 : : !! If JOBZ = 'N', then on exit the upper triangle (if UPLO='U')
4532 : : !! or the lower triangle (if UPLO='L') of sub( A ), including
4533 : : !! the diagonal, is destroyed.
4534 : : !!
4535 : : !! Slk_matB=
4536 : : !! %buffer_cplx
4537 : : !! (local input/local output) complex*(DP) pointer into the
4538 : : !! local memory to an array of dimension (LLD_B, LOCc(JB+N-1)).
4539 : : !! On entry, this array contains the local pieces of the
4540 : : !! N-by-N Hermitian distributed matrix sub( B ). If UPLO = 'U',
4541 : : !! the leading N-by-N upper triangular part of sub( B ) contains
4542 : : !! the upper triangular part of the matrix. If UPLO = 'L', the
4543 : : !! leading N-by-N lower triangular part of sub( B ) contains
4544 : : !! the lower triangular part of the matrix.
4545 : : !!
4546 : : !! On exit, if INFO <= N, the part of sub( B ) containing the
4547 : : !! matrix is overwritten by the triangular factor U or L from
4548 : : !! the Cholesky factorization sub( B ) = U**H*U or
4549 : : !! sub( B ) = L*L**H.
4550 : : !!
4551 : : !! SOURCE
4552 : :
4553 : 0 : subroutine slkmat_dp_pzhegvx(Slk_matA, ibtype, jobz, range, uplo, Slk_matB, vl, vu, il, iu, abstol, Slk_vec, mene_found, eigen)
4554 : :
4555 : : !Arguments ------------------------------------
4556 : : class(slkmat_dp_t),intent(inout) :: Slk_matA
4557 : : integer,intent(in) :: il,iu,ibtype
4558 : : integer,intent(out) :: mene_found
4559 : : real(dp),intent(in) :: abstol,vl,vu
4560 : : character(len=*),intent(in) :: jobz,range,uplo
4561 : : class(slkmat_dp_t),intent(inout) :: Slk_matB
4562 : : class(slkmat_dp_t),intent(inout) :: Slk_vec
4563 : : !arrays
4564 : : real(dp),intent(out) :: eigen(*)
4565 : :
4566 : : #ifdef HAVE_LINALG_SCALAPACK
4567 : : !Local variables-------------------------------
4568 : : !scalars
4569 : : integer :: lwork,lrwork,liwork,info,nvec_calc !,ierr
4570 : : real(dp) :: orfac
4571 : : logical :: ltest
4572 : : character(len=500) :: msg
4573 : : !arrays
4574 : : !integer :: ibuff(3),max_ibuff(3)
4575 : : integer :: desca(DLEN_),descb(DLEN_),descz(DLEN_)
4576 : : integer,allocatable :: iwork(:),iclustr(:),ifail(:)
4577 : : real(dp),allocatable :: rwork(:),gap(:)
4578 : : complex(dpc),allocatable :: work(:)
4579 : : !************************************************************************
4580 : :
4581 : : ABI_CHECK(allocated(Slk_matA%buffer_cplx), "buffer_cplx is not allocated!")
4582 : :
4583 : : ! abstol = PDLAMCH(Slk_vecprocessor%grid%comm,'U')
4584 : :
4585 : : orfac = -one ! Only for eigenvectors: use default value 10d-3.
4586 : : ! Vectors within orfac*norm(A) will be reorthogonalized.
4587 : :
4588 : : ! ======================
4589 : : ! Alignment requirements
4590 : : ! ======================
4591 : : ! The distributed submatrices A(IA:*, JA:*), C(IC:IC+M-1,JC:JC+N-1),
4592 : : ! and B( IB:IB+N-1, JB:JB+N-1 ) must verify some alignment properties,
4593 : :
4594 : : desca = Slk_matA%desc
4595 : : descb = Slk_matB%desc
4596 : : if (firstchar(jobz, ["V", "v"])) then
4597 : : descz = Slk_vec%desc
4598 : : else
4599 : : descz = Slk_matA%desc
4600 : : end if
4601 : :
4602 : : ltest = .TRUE.
4603 : : ltest = ltest .and. (DESCA(MB_) == DESCA(NB_))
4604 : : !IA = IB = IZ
4605 : : !JA = IB = JZ
4606 : : ltest = ltest .and.ALL(DESCA(M_ ) == [DESCB(M_ ), DESCZ(M_ )])
4607 : : ltest = ltest .and.ALL(DESCA(N_ ) == [DESCB(N_ ), DESCZ(N_ )])
4608 : : ltest = ltest .and.ALL(DESCA(MB_ ) == [DESCB(MB_ ), DESCZ(MB_ )])
4609 : : ltest = ltest .and.ALL(DESCA(NB_ ) == [DESCB(NB_ ), DESCZ(NB_ )])
4610 : : ltest = ltest .and.ALL(DESCA(RSRC_) == [DESCB(RSRC_), DESCZ(RSRC_)])
4611 : : ltest = ltest .and.ALL(DESCA(CSRC_) == [DESCB(CSRC_), DESCZ(CSRC_)])
4612 : : !MOD( IA-1, DESCA( MB_ ) ) = 0
4613 : : !MOD( JA-1, DESCA( NB_ ) ) = 0
4614 : : !MOD( IB-1, DESCB( MB_ ) ) = 0
4615 : : !MOD( JB-1, DESCB( NB_ ) ) = 0
4616 : :
4617 : : if (.not.ltest) then
4618 : : ABI_ERROR("Alignment requirements not satisfied, check the caller")
4619 : : end if
4620 : :
4621 : : !Allocate the arrays for the results of the calculation
4622 : : ABI_MALLOC(gap, (Slk_matA%processor%grid%dims(1) * Slk_matA%processor%grid%dims(2)))
4623 : :
4624 : : if (firstchar(jobz, ["V","v"])) then
4625 : : ABI_MALLOC(ifail,(Slk_matA%size_global(2)))
4626 : : ABI_MALLOC(iclustr,( 2*Slk_matA%processor%grid%dims(1) * Slk_matA%processor%grid%dims(2)))
4627 : : else
4628 : : ABI_MALLOC(ifail,(1))
4629 : : end if
4630 : :
4631 : : ! Get the optimal size of the work arrays.
4632 : : lwork=-1; lrwork=-1; liwork=-1
4633 : : ABI_MALLOC(work,(1))
4634 : : ABI_MALLOC(iwork,(1))
4635 : : ABI_MALLOC(rwork,(3))
4636 : : ! This is clearly seen in the source in which rwork(1:3) is accessed
4637 : : ! in the calcuation of the workspace size.
4638 : :
4639 : : call pzhegvx(ibtype,jobz,range,uplo, Slk_matA%size_global(2),Slk_matA%buffer_cplx,1,1,Slk_matA%desc,&
4640 : : Slk_matB%buffer_cplx,1,1,Slk_matB%desc,&
4641 : : vl,vu,il,iu,abstol,mene_found,nvec_calc,eigen,orfac,&
4642 : : Slk_vec%buffer_cplx,1,1,Slk_vec%desc,&
4643 : : work,lwork,rwork,lrwork,iwork,liwork,ifail,iclustr,gap,info)
4644 : :
4645 : : ABI_CHECK(info == 0, sjoin("Problem to compute workspace, info:", itoa(info)))
4646 : :
4647 : : lwork = NINT(real(work(1)),kind=dp)
4648 : : lrwork = NINT(rwork(1))
4649 : : liwork = iwork(1)
4650 : :
4651 : : ABI_FREE(work)
4652 : : ABI_FREE(rwork)
4653 : : ABI_FREE(iwork)
4654 : :
4655 : : !FROM THE SCALAPACK MAN PAGE:
4656 : : !The computed eigenvectors may not be orthogonal if the minimal workspace is supplied and ORFAC is too
4657 : : !small. If you want to guarantee orthogonality (at the cost of potentially poor performance) you should
4658 : : !add the following to LRWORK: (CLUSTERSIZE-1)*N where CLUSTERSIZE is the number of eigenvalues in the
4659 : : !largest cluster, where a cluster is defined as a set of close eigenvalues: { W(K),...,W(K+CLUSTERSIZE-1) |
4660 : : !W(J+1) <= W(J) + ORFAC*2*norm(A) }.
4661 : :
4662 : : if (firstchar(jobz, ["V","v"])) then
4663 : : lrwork = INT( lrwork + Slk_matA%size_global(2) *(Slk_matA%size_global(2)-1) )
4664 : : end if
4665 : :
4666 : : !ibuff(1) = lwork
4667 : : !ibuff(2) = lrwork !INT(lrwork + Slk_matA%size_global(2) *(Slk_matA%size_global(2)-1)
4668 : : !ibuff(3) = liwork
4669 : :
4670 : : !Get the maximum of sizes of the work arrays processor%comm
4671 : : !call MPI_ALLREDUCE(ibuff,max_ibuff,3,MPI_integer,MPI_MAX,comm,ierr)
4672 : :
4673 : : !lwork = max_ibuff(1)
4674 : : !lrwork = max_ibuff(2)
4675 : : !liwork = max_ibuff(3)
4676 : :
4677 : : ABI_MALLOC(work , (lwork ))
4678 : : ABI_MALLOC(rwork, (lrwork))
4679 : : ABI_MALLOC(iwork, (liwork))
4680 : :
4681 : : ! Call the scaLAPACK routine.
4682 : : ! write(std_out,*) 'I am using PZHEGVX'
4683 : : call pzhegvx(ibtype,jobz,range,uplo, Slk_matA%size_global(2),Slk_matA%buffer_cplx,1,1,Slk_matA%desc,&
4684 : : Slk_matB%buffer_cplx,1,1,Slk_matB%desc,&
4685 : : vl,vu,il,iu,abstol,mene_found,nvec_calc, eigen,orfac,&
4686 : : Slk_vec%buffer_cplx,1,1,Slk_vec%desc,&
4687 : : work,lwork,rwork,lrwork,iwork,liwork,ifail,iclustr,gap,info)
4688 : :
4689 : : ! Handle the possible error.
4690 : : if (info < 0) then
4691 : : write(msg,'(a,i0,a)')" The ",-info,"-th argument of PZHEGVX had an illegal value."
4692 : : if (info==-25) msg = " LRWORK is too small to compute all the eigenvectors requested, no computation is performed"
4693 : : ABI_ERROR(msg)
4694 : : end if
4695 : :
4696 : : if (info > 0) then
4697 : : write(msg,'(a,i0)') " PZHEGVX returned info: ",info
4698 : : call wrtout(std_out, msg)
4699 : : if (MOD(info,2)/=0)then
4700 : : write(msg,'(3a)')&
4701 : : " One or more eigenvectors failed to converge. ",ch10,&
4702 : : " Their indices are stored in IFAIL. Ensure ABSTOL=2.0*PDLAMCH('U')"
4703 : : call wrtout(std_out, msg)
4704 : : end if
4705 : : if (MOD(info / 2, 2) /= 0) then
4706 : : write(msg,'(5a)')&
4707 : : " Eigenvectors corresponding to one or more clusters of eigenvalues ",ch10,&
4708 : : " could not be reorthogonalized because of insufficient workspace. ",ch10,&
4709 : : " The indices of the clusters are stored in the array ICLUSTR."
4710 : : call wrtout(std_out, msg)
4711 : : end if
4712 : : if (MOD(info / 4, 2) /= 0) then
4713 : : write(msg,'(3a)')&
4714 : : " Space limit prevented PZHEGVX from computing all of the eigenvectors between VL and VU. ",ch10,&
4715 : : " The number of eigenvectors computed is returned in NZ."
4716 : : call wrtout(std_out, msg)
4717 : : end if
4718 : : if (MOD(info / 8, 2) /= 0) then
4719 : : msg = " PZSTEBZ failed to compute eigenvalues. Ensure ABSTOL=2.0*PDLAMCH('U')"
4720 : : call wrtout(std_out, msg)
4721 : : end if
4722 : : if (MOD(info / 16, 2) /= 0) then
4723 : : write(msg,'(3a)')&
4724 : : " B was not positive definite.",ch10,&
4725 : : " IFAIL(1) indicates the order of the smallest minor which is not positive definite."
4726 : : call wrtout(std_out, msg)
4727 : : end if
4728 : : ABI_ERROR("Cannot continue")
4729 : : end if
4730 : :
4731 : : ! Check the number of eigenvalues found wrt to the number of vectors calculated.
4732 : : if ( firstchar(jobz, ['V','v']) .and. mene_found/=nvec_calc) then
4733 : : write(msg,'(5a)')&
4734 : : " The user supplied insufficient space and PZHEGVX is not able to detect this before beginning computation. ",ch10,&
4735 : : " To get all the eigenvectors requested, the user must supply both sufficient space to hold the ",ch10,&
4736 : : " eigenvectors in Z (M .LE. DESCZ(N_)) and sufficient workspace to compute them. "
4737 : : ABI_ERROR(msg)
4738 : : end if
4739 : :
4740 : : ABI_FREE(work)
4741 : : ABI_FREE(rwork)
4742 : : ABI_FREE(iwork)
4743 : : ABI_FREE(gap)
4744 : : ABI_FREE(ifail)
4745 : : ABI_SFREE(iclustr)
4746 : : #endif
4747 : :
4748 : 0 : end subroutine slkmat_dp_pzhegvx
4749 : : !!***
4750 : :
4751 : : !----------------------------------------------------------------------
4752 : :
4753 : : !!****f* m_slk/basemat_invert
4754 : : !! NAME
4755 : : !! basemat_invert
4756 : : !!
4757 : : !! FUNCTION
4758 : : !! Compute the inverse of a complex matrix.
4759 : : !!
4760 : : !! SIDE EFFECTS
4761 : : !! mat
4762 : : !! In input, the matrix to invert.
4763 : : !! In output the matrix inverted and distributed among the nodes.
4764 : : !!
4765 : : !! SOURCE
4766 : :
4767 : 0 : subroutine basemat_invert(mat)
4768 : :
4769 : : !Arguments ------------------------------------
4770 : : class(basemat_t),intent(inout) :: mat
4771 : :
4772 : : #ifdef HAVE_LINALG_SCALAPACK
4773 : : !Local variables ------------------------------
4774 : : !scalars
4775 : : integer :: lwork,info,ipiv_size,liwork
4776 : : !array
4777 : : integer,allocatable :: ipiv(:), iwork(:)
4778 : : complex(dp),allocatable :: work_dp(:)
4779 : : complex(sp),allocatable :: work_sp(:)
4780 : : !************************************************************************
4781 : :
4782 : : if (mat%desc(MB_) /= mat%desc(NB_)) then
4783 : : ABI_ERROR("PZGETRF requires square block decomposition i.e MB_A = NB_A.")
4784 : : end if
4785 : :
4786 : : ipiv_size = my_locr(mat) + mat%desc(MB_)
4787 : : ABI_MALLOC(ipiv, (ipiv_size))
4788 : :
4789 : : select type (mat)
4790 : : class is (slkmat_dp_t)
4791 : : if (allocated(mat%buffer_cplx)) then
4792 : : ! P * L * U Factorization.
4793 : : call PZGETRF(mat%size_global(1), mat%size_global(2), mat%buffer_cplx, 1, 1, mat%desc,ipiv, info)
4794 : : ABI_CHECK(info == 0, sjoin(" PZGETRF returned info:", itoa(info)))
4795 : :
4796 : : ! Get optimal size of workspace for PZGETRI.
4797 : : lwork = -1; liwork = -1
4798 : : ABI_MALLOC(work_dp,(1))
4799 : : ABI_MALLOC(iwork,(1))
4800 : :
4801 : : call PZGETRI(mat%size_global(1), mat%buffer_cplx, 1, 1, mat%desc, ipiv, work_dp, lwork, iwork, liwork, info)
4802 : : ABI_CHECK(info == 0, "PZGETRI: Error while computing workspace size")
4803 : :
4804 : : lwork = nint(real(work_dp(1))); liwork=iwork(1)
4805 : : ABI_FREE(work_dp)
4806 : : ABI_FREE(iwork)
4807 : :
4808 : : ! Solve the problem.
4809 : : ABI_MALLOC(work_dp, (lwork))
4810 : : ABI_MALLOC(iwork, (liwork))
4811 : :
4812 : : call PZGETRI(mat%size_global(1), mat%buffer_cplx, 1, 1, mat%desc, ipiv, work_dp, lwork, iwork, liwork, info)
4813 : : ABI_CHECK(info == 0, sjoin("PZGETRI returned info:", itoa(info)))
4814 : : ABI_FREE(work_dp)
4815 : :
4816 : : else if (allocated(mat%buffer_real)) then
4817 : : ABI_ERROR("Inversion for real matrices not coded!")
4818 : : end if
4819 : :
4820 : : class is (slkmat_sp_t)
4821 : : if (allocated(mat%buffer_cplx)) then
4822 : : ! P * L * U Factorization.
4823 : : call PCGETRF(mat%size_global(1), mat%size_global(2), mat%buffer_cplx, 1, 1, mat%desc,ipiv, info)
4824 : : ABI_CHECK(info == 0, sjoin(" PCGETRF returned info:", itoa(info)))
4825 : :
4826 : : ! Get optimal size of workspace for PZGETRI.
4827 : : lwork = -1; liwork = -1
4828 : : ABI_MALLOC(work_sp,(1))
4829 : : ABI_MALLOC(iwork,(1))
4830 : :
4831 : : call PCGETRI(mat%size_global(1), mat%buffer_cplx, 1, 1, mat%desc, ipiv, work_sp, lwork, iwork, liwork, info)
4832 : : ABI_CHECK(info == 0, "PZGETRI: Error while computing workspace size")
4833 : :
4834 : : lwork = nint(real(work_sp(1))); liwork=iwork(1)
4835 : : ABI_FREE(work_sp)
4836 : : ABI_FREE(iwork)
4837 : :
4838 : : ! Solve the problem.
4839 : : ABI_MALLOC(work_sp, (lwork))
4840 : : ABI_MALLOC(iwork, (liwork))
4841 : :
4842 : : call PCGETRI(mat%size_global(1), mat%buffer_cplx, 1, 1, mat%desc, ipiv, work_sp, lwork, iwork, liwork, info)
4843 : : ABI_CHECK(info == 0, sjoin("PZGETRI returned info:", itoa(info)))
4844 : : ABI_FREE(work_sp)
4845 : :
4846 : : else if (allocated(mat%buffer_real)) then
4847 : : ABI_ERROR("Inversion for real matrices not coded!")
4848 : : end if
4849 : :
4850 : : class default
4851 : : ABI_ERROR("Wrong class")
4852 : : end select
4853 : :
4854 : : ABI_FREE(iwork)
4855 : : ABI_FREE(ipiv)
4856 : : #endif
4857 : :
4858 : 0 : end subroutine basemat_invert
4859 : : !!***
4860 : :
4861 : : !----------------------------------------------------------------------
4862 : :
4863 : : !!****f* m_slk/slkmat_dp_hpd_invert
4864 : : !! NAME
4865 : : !! slkmat_dp_hpd_invert
4866 : : !!
4867 : : !! FUNCTION
4868 : : !! Compute the inverse of an Hermitian positive definite matrix.
4869 : : !!
4870 : : !! INPUTS
4871 : : !! uplo: global input
4872 : : !! = 'U': Upper triangle of sub( A ) is stored;
4873 : : !! = 'L': Lower triangle of sub( A ) is stored.
4874 : : !! [full]: If full PBLAS matrix is neeeded. Default: True
4875 : : !!
4876 : : !! SIDE EFFECTS
4877 : : !! mat= The object storing the local buffer, the array descriptor, the context, etc.
4878 : : !! On entry, this array contains the local pieces of the N-by-N Hermitian distributed matrix sub( A ) to be factored.
4879 : : !! If UPLO = 'U', the leading N-by-N upper triangular part of sub( A ) contains the upper triangular part of the matrix,
4880 : : !! and its strictly lower triangular part is not referenced.
4881 : : !! If UPLO = 'L', the leading N-by-N lower triangular part of sub( A ) contains the lower triangular part of the distribu-
4882 : : !! ted matrix, and its strictly upper triangular part is not referenced.
4883 : : !! On exit, the local pieces of the upper or lower triangle of the (Hermitian) inverse of sub( A )
4884 : : !!
4885 : : !! SOURCE
4886 : :
4887 : 0 : subroutine slkmat_dp_hpd_invert(mat, uplo, full)
4888 : :
4889 : : !Arguments ------------------------------------
4890 : : class(slkmat_dp_t),intent(inout) :: mat
4891 : : character(len=*),intent(in) :: uplo
4892 : : logical,optional,intent(in) :: full
4893 : :
4894 : : #ifdef HAVE_LINALG_SCALAPACK
4895 : : !Local variables ------------------------------
4896 : : !scalars
4897 : : integer :: info, mm, il1, il2, iglob1, iglob2
4898 : : type(slkmat_dp_t) :: work_mat
4899 : : logical :: full__
4900 : : !************************************************************************
4901 : :
4902 : : ABI_CHECK(allocated(mat%buffer_cplx), "buffer_cplx not allocated")
4903 : :
4904 : : ! ZPOTRF computes the Cholesky factorization of a complex Hermitian positive definite.
4905 : : ! A = U**H * U, if UPLO = 'U', or
4906 : : ! A = L * L**H, if UPLO = 'L',
4907 : : mm = mat%size_global(1)
4908 : : call PZPOTRF(uplo, mm, mat%buffer_cplx, 1, 1, mat%desc, info)
4909 : : ABI_CHECK(info == 0, sjoin("PZPOTRF returned info:", itoa(info)))
4910 : :
4911 : : ! PZPOTRI computes the inverse of a complex Hermitian positive definite
4912 : : ! distributed matrix sub( A ) = A(IA:IA+N-1,JA:JA+N-1) using the
4913 : : ! Cholesky factorization sub( A ) = U**H*U or L*L**H computed by PZPOTRF.
4914 : : call PZPOTRI(uplo, mm, mat%buffer_cplx, 1, 1, mat%desc, info)
4915 : : ABI_CHECK(info == 0, sjoin("PZPOTRI returned info:", itoa(info)))
4916 : :
4917 : : full__ = .True.; if (present(full)) full__ = full
4918 : : if (full__) then
4919 : : ! Only the uplo part contains the inverse so we need to fill the other triangular part.
4920 : : ! 1) Fill the missing triangle with zeros and copy results to work_mat
4921 : : ! 2) Call pzgeadd to compute: sub(C) := beta*sub(C) + alpha*op(sub(A))
4922 : : ! 3) Divide diagonal elements by two.
4923 : :
4924 : : do il2=1,mat%size_local(2)
4925 : : iglob2 = mat%loc2gcol(il2)
4926 : : do il1=1,mat%size_local(1)
4927 : : iglob1 = mat%loc2grow(il1)
4928 : : if (uplo == "L" .and. iglob2 > iglob1) mat%buffer_cplx(il1, il2) = zero
4929 : : if (uplo == "U" .and. iglob2 < iglob1) mat%buffer_cplx(il1, il2) = zero
4930 : : end do
4931 : : end do
4932 : :
4933 : : call mat%copy(work_mat, empty=.False.)
4934 : :
4935 : : ! call pzgeadd(trans, m, n, alpha, a, ia, ja, desca, beta, c, ic, jc, descc)
4936 : : ! sub(C) := beta*sub(C) + alpha*op(sub(A))
4937 : : call pzgeadd("C", mm, mm, cone, work_mat%buffer_cplx, 1, 1, work_mat%desc, &
4938 : : cone, mat%buffer_cplx, 1, 1, mat%desc)
4939 : : call work_mat%free()
4940 : :
4941 : : do il2=1,mat%size_local(2)
4942 : : iglob2 = mat%loc2gcol(il2)
4943 : : do il1=1,mat%size_local(1)
4944 : : iglob1 = mat%loc2grow(il1)
4945 : : if (iglob2 == iglob1) mat%buffer_cplx(il1, il2) = half * mat%buffer_cplx(il1, il2)
4946 : : end do
4947 : : end do
4948 : : end if ! full__
4949 : : #endif
4950 : :
4951 : 0 : end subroutine slkmat_dp_hpd_invert
4952 : : !!***
4953 : :
4954 : : !----------------------------------------------------------------------
4955 : :
4956 : : !!****f* m_slk/slkmat_sp_hpd_invert
4957 : : !! NAME
4958 : : !! slkmat_sp_hpd_invert
4959 : : !!
4960 : : !! FUNCTION
4961 : : !! Compute the inverse of an Hermitian positive definite matrix.
4962 : : !!
4963 : : !! INPUTS
4964 : : !! uplo: global input
4965 : : !! = 'U': Upper triangle of sub( A ) is stored;
4966 : : !! = 'L': Lower triangle of sub( A ) is stored.
4967 : : !! [full]: If full PBLAS matrix is neeeded. Default: True
4968 : : !!
4969 : : !! SIDE EFFECTS
4970 : : !! mat= The object storing the local buffer, the array descriptor, the context, etc.
4971 : : !! On entry, this array contains the local pieces of the N-by-N Hermitian distributed matrix sub( A ) to be factored.
4972 : : !! If UPLO = 'U', the leading N-by-N upper triangular part of sub( A ) contains the upper triangular part of the matrix,
4973 : : !! and its strictly lower triangular part is not referenced.
4974 : : !! If UPLO = 'L', the leading N-by-N lower triangular part of sub( A ) contains the lower triangular part of the distribu-
4975 : : !! ted matrix, and its strictly upper triangular part is not referenced.
4976 : : !! On exit, the local pieces of the upper or lower triangle of the (Hermitian) inverse of sub( A )
4977 : : !!
4978 : : !! SOURCE
4979 : :
4980 : 0 : subroutine slkmat_sp_hpd_invert(mat, uplo, full)
4981 : :
4982 : : !Arguments ------------------------------------
4983 : : class(slkmat_sp_t),intent(inout) :: mat
4984 : : character(len=*),intent(in) :: uplo
4985 : : logical,optional,intent(in) :: full
4986 : :
4987 : : #ifdef HAVE_LINALG_SCALAPACK
4988 : : !Local variables ------------------------------
4989 : : !scalars
4990 : : integer :: info, mm, il1, il2, iglob1, iglob2
4991 : : type(slkmat_sp_t) :: work_mat
4992 : : logical :: full__
4993 : : !************************************************************************
4994 : :
4995 : : ABI_CHECK(allocated(mat%buffer_cplx), "buffer_cplx not allocated")
4996 : :
4997 : : ! ZPOTRF computes the Cholesky factorization of a complex Hermitian positive definite.
4998 : : ! A = U**H * U, if UPLO = 'U', or
4999 : : ! A = L * L**H, if UPLO = 'L',
5000 : : mm = mat%size_global(1)
5001 : : call PCPOTRF(uplo, mm, mat%buffer_cplx, 1, 1, mat%desc, info)
5002 : : ABI_CHECK(info == 0, sjoin("PCPOTRF returned info:", itoa(info)))
5003 : :
5004 : : ! PZPOTRI computes the inverse of a complex Hermitian positive definite
5005 : : ! distributed matrix sub( A ) = A(IA:IA+N-1,JA:JA+N-1) using the
5006 : : ! Cholesky factorization sub( A ) = U**H*U or L*L**H computed by PZPOTRF.
5007 : : call PCPOTRI(uplo, mm, mat%buffer_cplx, 1, 1, mat%desc, info)
5008 : : ABI_CHECK(info == 0, sjoin("PCPOTRI returned info:", itoa(info)))
5009 : :
5010 : : full__ = .True.; if (present(full)) full__ = full
5011 : : if (full__) then
5012 : : ! Only the uplo part contains the inverse so we need to fill the other triangular part.
5013 : : ! 1) Fill the missing triangle with zeros and copy results to work_mat
5014 : : ! 2) Call pzgeadd to compute: sub(C) := beta*sub(C) + alpha*op(sub(A))
5015 : : ! 3) Divide diagonal elements by two.
5016 : :
5017 : : do il2=1,mat%size_local(2)
5018 : : iglob2 = mat%loc2gcol(il2)
5019 : : do il1=1,mat%size_local(1)
5020 : : iglob1 = mat%loc2grow(il1)
5021 : : if (uplo == "L" .and. iglob2 > iglob1) mat%buffer_cplx(il1, il2) = zero_sp
5022 : : if (uplo == "U" .and. iglob2 < iglob1) mat%buffer_cplx(il1, il2) = zero_sp
5023 : : end do
5024 : : end do
5025 : :
5026 : : call mat%copy(work_mat, empty=.False.)
5027 : :
5028 : : ! call pzgeadd(trans, m, n, alpha, a, ia, ja, desca, beta, c, ic, jc, descc)
5029 : : ! sub(C) := beta*sub(C) + alpha*op(sub(A))
5030 : : call pcgeadd("C", mm, mm, cone_sp, work_mat%buffer_cplx, 1, 1, work_mat%desc, &
5031 : : cone_sp, mat%buffer_cplx, 1, 1, mat%desc)
5032 : : call work_mat%free()
5033 : :
5034 : : do il2=1,mat%size_local(2)
5035 : : iglob2 = mat%loc2gcol(il2)
5036 : : do il1=1,mat%size_local(1)
5037 : : iglob1 = mat%loc2grow(il1)
5038 : : if (iglob2 == iglob1) mat%buffer_cplx(il1, il2) = 0.5_sp * mat%buffer_cplx(il1, il2)
5039 : : end do
5040 : : end do
5041 : : end if ! full__
5042 : : #endif
5043 : :
5044 : 0 : end subroutine slkmat_sp_hpd_invert
5045 : : !!***
5046 : :
5047 : : !----------------------------------------------------------------------
5048 : :
5049 : : !!****f* m_slk/slkmat_dp_ptrans
5050 : : !! NAME
5051 : : !! slkmat_dp_ptrans
5052 : : !!
5053 : : !! FUNCTION
5054 : : !! Transposes a matrix
5055 : : !!
5056 : : !! sub( C ) := beta*sub( C ) + alpha*op( sub( A ) )
5057 : : !!
5058 : : !! where
5059 : : !!
5060 : : !! sub( C ) denotes C(IC:IC+M-1,JC:JC+N-1),
5061 : : !! sub( A ) denotes A(IA:IA+N-1,JA:JA+M-1), and, op( X ) = X'.
5062 : : !!
5063 : : !! Thus, op( sub( A ) ) denotes A(IA:IA+N-1,JA:JA+M-1)'.
5064 : : !! Beta is a scalar, sub( C ) is an m by n submatrix, and sub( A ) is an n by m submatrix.
5065 : : !!
5066 : : !! INPUTS
5067 : : !! [ija(2)]: (global) The row and column indices in the distributed matrix in_mat indicating
5068 : : !! the first row and the first column of the submatrix sub(A), respectively.
5069 : : !! [ijc(2)]: (global) The row and column indices in the distributed matrix out_mat
5070 : : !! indicating the first row and the first column of the submatrix sub(C), respectively.
5071 : : !! [free]: True to deallocate in_mat. Default: False
5072 : : !!
5073 : : !! SOURCE
5074 : :
5075 : 0 : subroutine slkmat_dp_ptrans(in_mat, trans, out_mat, &
5076 : : out_gshape, ija, ijc, size_blocs, alpha, beta, free) ! optional
5077 : :
5078 : : !Arguments ------------------------------------
5079 : : class(slkmat_dp_t),intent(inout) :: in_mat
5080 : : character(len=1),intent(in) :: trans
5081 : : class(slkmat_dp_t),intent(inout) :: out_mat
5082 : : integer,optional,intent(in) :: out_gshape(2), size_blocs(2), ija(2), ijc(2)
5083 : : complex(dp),optional,intent(in) :: alpha, beta
5084 : : logical,optional,intent(in) :: free
5085 : :
5086 : : !Local variables-------------------------------
5087 : : integer :: sb, mm, nn, size_blocs__(2)
5088 : : real(dp) :: ralpha__, rbeta__
5089 : : integer :: ija__(2), ijc__(2)
5090 : : complex(dp) :: calpha__, cbeta__
5091 : : ! *************************************************************************
5092 : :
5093 : 0 : ija__ = [1, 1]; if (present(ija)) ija__ = ija
5094 : 0 : ijc__ = [1, 1]; if (present(ijc)) ijc__ = ijc
5095 : :
5096 : : ! transposed output (sub)matrix has shape (nn, mm)
5097 [ # # ]: 0 : if (present(out_gshape)) then
5098 : 0 : nn = out_gshape(1)
5099 : 0 : mm = out_gshape(2)
5100 : : else
5101 : 0 : nn = in_mat%size_global(2)
5102 : 0 : mm = in_mat%size_global(1)
5103 : : end if
5104 : :
5105 [ # # ]: 0 : if (present(size_blocs)) then
5106 : 0 : size_blocs__ = size_blocs
5107 : : else
5108 : : ! FIXME: This can cause problems if I start to use round-robin distribution in GWR!!!!!
5109 : 0 : size_blocs__(1) = in_mat%size_global(2)
5110 : 0 : sb = in_mat%size_global(1) / in_mat%processor%grid%dims(2)
5111 [ # # ]: 0 : if (mod(in_mat%size_global(1), in_mat%processor%grid%dims(2)) /= 0) sb = sb + 1
5112 : 0 : size_blocs__(2) = sb
5113 : : !size_blocs__(2) = in_mat%size_blocs(1); size_blocs__(1) = in_mat%size_blocs(2)
5114 : : end if
5115 : :
5116 : 0 : call out_mat%init(nn, mm, in_mat%processor, in_mat%istwf_k, size_blocs=size_blocs__)
5117 : :
5118 : : ! prototype: call pdtran(m, n, alpha, a, ia, ja, desca, beta, c, ic, jc, descc)
5119 : :
5120 [ # # ]: 0 : if (allocated(in_mat%buffer_cplx)) then
5121 : : #ifdef HAVE_LINALG_SCALAPACK
5122 : : select case (trans)
5123 : : case ("N")
5124 : : ! sub(C) := beta*sub(C) + alpha*sub(A)',
5125 : : calpha__ = cone; if (present(alpha)) calpha__ = alpha
5126 : : cbeta__ = czero; if (present(beta)) cbeta__ = beta
5127 : : call pztranu(nn, mm, calpha__, in_mat%buffer_cplx, ija__(1), ija__(2), &
5128 : : in_mat%desc, cbeta__, out_mat%buffer_cplx, ijc__(1), ijc__(2), out_mat%desc)
5129 : :
5130 : : case ("C")
5131 : : ! sub(C) := beta * sub(C) + alpha * conjg(sub(A)')
5132 : : calpha__ = cone; if (present(alpha)) calpha__ = alpha
5133 : : cbeta__ = czero; if (present(beta)) cbeta__ = beta
5134 : : call pztranc(nn, mm, calpha__, in_mat%buffer_cplx, ija__(1), ija__(2), &
5135 : : in_mat%desc, cbeta__, out_mat%buffer_cplx, ijc__(1), ijc__(2), out_mat%desc)
5136 : :
5137 : : case default
5138 : : ABI_ERROR(sjoin("Invalid value for trans:", trans))
5139 : : end select
5140 : :
5141 : : else if (allocated(in_mat%buffer_real)) then
5142 : : ralpha__ = one; if (present(alpha)) ralpha__ = real(alpha)
5143 : : rbeta__ = zero; if (present(beta)) rbeta__ = real(beta)
5144 : : call pdtran(nn, mm, ralpha__, in_mat%buffer_real, ija__(1), ija__(2), &
5145 : : in_mat%desc, rbeta__, out_mat%buffer_real, ijc__(1), ijc__(2), out_mat%desc)
5146 : : #endif
5147 : : else
5148 : 0 : ABI_ERROR("Neither buffer_cplx nor buffer_real are allocated!")
5149 : : end if
5150 : :
5151 [ # # ]: 0 : if (present(free)) then
5152 [ # # ]: 0 : if (free) call in_mat%free()
5153 : : end if
5154 : :
5155 : 0 : end subroutine slkmat_dp_ptrans
5156 : : !!***
5157 : :
5158 : : !!****f* m_slk/slkmat_sp_ptrans
5159 : : !! NAME
5160 : : !! slkmat_sp_ptrans
5161 : : !!
5162 : : !! FUNCTION
5163 : : !! Transposes a matrix
5164 : : !!
5165 : : !! sub( C ) := beta*sub( C ) + alpha*op( sub( A ) )
5166 : : !!
5167 : : !! where
5168 : : !!
5169 : : !! sub( C ) denotes C(IC:IC+M-1,JC:JC+N-1),
5170 : : !! sub( A ) denotes A(IA:IA+N-1,JA:JA+M-1), and, op( X ) = X'.
5171 : : !!
5172 : : !! Thus, op( sub( A ) ) denotes A(IA:IA+N-1,JA:JA+M-1)'.
5173 : : !! Beta is a scalar, sub( C ) is an m by n submatrix, and sub( A ) is an n by m submatrix.
5174 : : !!
5175 : : !! INPUTS
5176 : : !! [ija(2)]: (global) The row and column indices in the distributed matrix in_mat indicating
5177 : : !! the first row and the first column of the submatrix sub(A), respectively.
5178 : : !! [ijc(2)]: (global) The row and column indices in the distributed matrix out_mat
5179 : : !! indicating the first row and the first column of the submatrix sub(C), respectively.
5180 : : !! [free]: True to deallocate in_mat. Default: False
5181 : : !!
5182 : : !! SOURCE
5183 : :
5184 : 0 : subroutine slkmat_sp_ptrans(in_mat, trans, out_mat, &
5185 : : out_gshape, ija, ijc, size_blocs, alpha, beta, free) ! optional
5186 : :
5187 : : !Arguments ------------------------------------
5188 : : class(slkmat_sp_t),intent(inout) :: in_mat
5189 : : character(len=1),intent(in) :: trans
5190 : : class(slkmat_sp_t),intent(inout) :: out_mat
5191 : : integer,optional,intent(in) :: out_gshape(2), size_blocs(2), ija(2), ijc(2)
5192 : : complex(sp),optional,intent(in) :: alpha, beta
5193 : : logical,optional,intent(in) :: free
5194 : :
5195 : : !Local variables-------------------------------
5196 : : integer :: sb, mm, nn, size_blocs__(2)
5197 : : real(sp) :: ralpha__, rbeta__
5198 : : integer :: ija__(2), ijc__(2)
5199 : : complex(sp) :: calpha__, cbeta__
5200 : : ! *************************************************************************
5201 : :
5202 : 0 : ija__ = [1, 1]; if (present(ija)) ija__ = ija
5203 : 0 : ijc__ = [1, 1]; if (present(ijc)) ijc__ = ijc
5204 : :
5205 : : ! transposed output (sub)matrix has shape (nn, mm)
5206 [ # # ]: 0 : if (present(out_gshape)) then
5207 : 0 : nn = out_gshape(1)
5208 : 0 : mm = out_gshape(2)
5209 : : else
5210 : 0 : nn = in_mat%size_global(2)
5211 : 0 : mm = in_mat%size_global(1)
5212 : : end if
5213 : :
5214 [ # # ]: 0 : if (present(size_blocs)) then
5215 : 0 : size_blocs__ = size_blocs
5216 : : else
5217 : : ! FIXME: This can cause problems if I start to use round-robin distribution in GWR!!!!!
5218 : 0 : size_blocs__(1) = in_mat%size_global(2)
5219 : 0 : sb = in_mat%size_global(1) / in_mat%processor%grid%dims(2)
5220 [ # # ]: 0 : if (mod(in_mat%size_global(1), in_mat%processor%grid%dims(2)) /= 0) sb = sb + 1
5221 : 0 : size_blocs__(2) = sb
5222 : : !size_blocs__(2) = in_mat%size_blocs(1); size_blocs__(1) = in_mat%size_blocs(2)
5223 : : end if
5224 : :
5225 : 0 : call out_mat%init(nn, mm, in_mat%processor, in_mat%istwf_k, size_blocs=size_blocs__)
5226 : :
5227 : : ! prototype: call pdtran(m, n, alpha, a, ia, ja, desca, beta, c, ic, jc, descc)
5228 : :
5229 [ # # ]: 0 : if (allocated(in_mat%buffer_cplx)) then
5230 : : #ifdef HAVE_LINALG_SCALAPACK
5231 : : select case (trans)
5232 : : case ("N")
5233 : : ! sub(C) := beta*sub(C) + alpha*sub(A)',
5234 : : calpha__ = cone_sp; if (present(alpha)) calpha__ = alpha
5235 : : cbeta__ = czero_sp; if (present(beta)) cbeta__ = beta
5236 : : call pctranu(nn, mm, calpha__, in_mat%buffer_cplx, ija__(1), ija__(2), &
5237 : : in_mat%desc, cbeta__, out_mat%buffer_cplx, ijc__(1), ijc__(2), out_mat%desc)
5238 : :
5239 : : case ("C")
5240 : : ! sub(C) := beta * sub(C) + alpha * conjg(sub(A)')
5241 : : calpha__ = cone_sp; if (present(alpha)) calpha__ = alpha
5242 : : cbeta__ = czero_sp; if (present(beta)) cbeta__ = beta
5243 : : call pctranc(nn, mm, calpha__, in_mat%buffer_cplx, ija__(1), ija__(2), &
5244 : : in_mat%desc, cbeta__, out_mat%buffer_cplx, ijc__(1), ijc__(2), out_mat%desc)
5245 : :
5246 : : case default
5247 : : ABI_ERROR(sjoin("Invalid value for trans:", trans))
5248 : : end select
5249 : :
5250 : : else if (allocated(in_mat%buffer_real)) then
5251 : : ralpha__ = one_sp; if (present(alpha)) ralpha__ = real(alpha)
5252 : : rbeta__ = zero_sp; if (present(beta)) rbeta__ = real(beta)
5253 : : call pstran(nn, mm, ralpha__, in_mat%buffer_real, ija__(1), ija__(2), &
5254 : : in_mat%desc, rbeta__, out_mat%buffer_real, ijc__(1), ijc__(2), out_mat%desc)
5255 : : #endif
5256 : : else
5257 : 0 : ABI_ERROR("Neither buffer_cplx nor buffer_real are allocated!")
5258 : : end if
5259 : :
5260 [ # # ]: 0 : if (present(free)) then
5261 [ # # ]: 0 : if (free) call in_mat%free()
5262 : : end if
5263 : :
5264 : 0 : end subroutine slkmat_sp_ptrans
5265 : : !!***
5266 : :
5267 : : !----------------------------------------------------------------------
5268 : :
5269 : : !!****f* m_slk/basemat_change_size_blocs
5270 : : !! NAME
5271 : : !! basemat_change_size_blocs
5272 : : !!
5273 : : !! FUNCTION
5274 : : !! Change the block sizes, return new matrix in out_mat
5275 : : !!
5276 : : !! INPUTS
5277 : : !! [free]: True if `in_mat` should be deallocated. Default: False
5278 : : !!
5279 : : !! OUTPUT
5280 : : !!
5281 : : !! SOURCE
5282 : :
5283 [ # # ]: 0 : subroutine basemat_change_size_blocs(in_mat, out_mat, &
5284 : : size_blocs, processor, free) ! Optional
5285 : :
5286 : : !Arguments ------------------------------------
5287 : : class(basemat_t),target,intent(inout) :: in_mat
5288 : : class(basemat_t),intent(out) :: out_mat
5289 : : integer,optional,intent(in) :: size_blocs(2)
5290 : : class(slk_processor_t), target, optional,intent(in) :: processor
5291 : : logical,optional,intent(in) :: free
5292 : :
5293 : : !Local variables-------------------------------
5294 : : type(slk_processor_t), pointer :: processor__
5295 : : ! *************************************************************************
5296 : :
5297 [ # # # # ]: 0 : processor__ => in_mat%processor; if (present(processor)) processor__ => processor
5298 : :
5299 [ # # ]: 0 : if (present(size_blocs)) then
5300 : 0 : call out_mat%init(in_mat%size_global(1), in_mat%size_global(2), processor__, in_mat%istwf_k, size_blocs=size_blocs)
5301 : : else
5302 : 0 : call out_mat%init(in_mat%size_global(1), in_mat%size_global(2), processor__, in_mat%istwf_k)
5303 : : end if
5304 : :
5305 : : !write(std_out, *)"out_mat%size_global", out_mat%size_global
5306 : : !call in_mat%print(header="input matrix in by basemat_change_size_blocs")
5307 : : !call out_mat%print(header="output matrix generated by basemat_change_size_blocs")
5308 : :
5309 [ # # ]: 0 : ABI_CHECK(same_type_as(in_mat, out_mat), "in_mat and out_mat should have same type!")
5310 : :
5311 : : ! p?gemr2d: Copies a submatrix from one general rectangular matrix to another.
5312 : : ! prototype
5313 : : !call pzgemr2d(m, n, a, ia, ja, desca, b, ib, jb, descb, comm)
5314 : :
5315 : : #ifdef HAVE_LINALG_SCALAPACK
5316 : : select type (in_mat)
5317 : : class is (slkmat_dp_t)
5318 : : select type (out_mat)
5319 : : class is (slkmat_dp_t)
5320 : : if (allocated(in_mat%buffer_cplx)) then
5321 : : ABI_CHECK_IEQ(kind(in_mat%buffer_cplx), kind(out_mat%buffer_cplx), "Different kind")
5322 : : ABI_CHECK(allocated(out_mat%buffer_cplx), "out_mat%buffer_cplx should be allocated")
5323 : : call pzgemr2d(in_mat%size_global(1), in_mat%size_global(2), &
5324 : : in_mat%buffer_cplx, 1, 1, in_mat%desc, &
5325 : : out_mat%buffer_cplx, 1, 1, out_mat%desc, &
5326 : : processor__%grid%comm)
5327 : :
5328 : : else if (allocated(in_mat%buffer_real)) then
5329 : : ABI_CHECK_IEQ(kind(in_mat%buffer_real), kind(out_mat%buffer_real), "Different kind")
5330 : : ABI_CHECK(allocated(out_mat%buffer_real), "out_mat%buffer_real should be allocated")
5331 : : call pdgemr2d(in_mat%size_global(1), in_mat%size_global(2), &
5332 : : in_mat%buffer_real, 1, 1, in_mat%desc, &
5333 : : out_mat%buffer_real, 1, 1, out_mat%desc, &
5334 : : processor__%grid%comm)
5335 : : else
5336 : : ABI_ERROR("Neither buffer_cplx nor buffer_real are allocated!")
5337 : : end if
5338 : : end select
5339 : :
5340 : : class is (slkmat_sp_t)
5341 : : select type (out_mat)
5342 : : class is (slkmat_sp_t)
5343 : : if (allocated(in_mat%buffer_cplx)) then
5344 : : ABI_CHECK_IEQ(kind(in_mat%buffer_cplx), kind(out_mat%buffer_cplx), "Different kind")
5345 : :
5346 : : ABI_CHECK(allocated(out_mat%buffer_cplx), "out_mat%buffer should be allocated")
5347 : : call pcgemr2d(in_mat%size_global(1), in_mat%size_global(2), &
5348 : : in_mat%buffer_cplx, 1, 1, in_mat%desc, &
5349 : : out_mat%buffer_cplx, 1, 1, out_mat%desc, &
5350 : : processor__%grid%comm)
5351 : :
5352 : : else if (allocated(in_mat%buffer_real)) then
5353 : : ABI_CHECK_IEQ(kind(in_mat%buffer_real), kind(out_mat%buffer_real), "Different kind")
5354 : : ABI_CHECK(allocated(out_mat%buffer_real), "out_mat%buffer_real should be allocated")
5355 : : call psgemr2d(in_mat%size_global(1), in_mat%size_global(2), &
5356 : : in_mat%buffer_real, 1, 1, in_mat%desc, &
5357 : : out_mat%buffer_real, 1, 1, out_mat%desc, &
5358 : : processor__%grid%comm)
5359 : : else
5360 : : ABI_ERROR("Neither buffer_cplx nor buffer_real are allocated!")
5361 : : end if
5362 : : end select
5363 : :
5364 : : class default
5365 : : ABI_ERROR("Wrong class")
5366 : : end select
5367 : : #endif
5368 : :
5369 [ # # ]: 0 : if (present(free)) then
5370 [ # # ]: 0 : if (free) call in_mat%free()
5371 : : end if
5372 : :
5373 : 0 : end subroutine basemat_change_size_blocs
5374 : : !!***
5375 : :
5376 : : !----------------------------------------------------------------------
5377 : :
5378 : : !!****f* m_slk/slkmat_dp_cut
5379 : : !! NAME
5380 : : !! slkmat_dp_cut
5381 : : !!
5382 : : !! FUNCTION
5383 : : !! Extract submatrix of shape (glob_nrows, glob_ncols) starting at `ija` from `in_mat`
5384 : : !! and create new matrix with `size_blocs` and `processor`
5385 : : !!
5386 : : !! INPUTS
5387 : : !! [free]: True if `in_mat` should be deallocated. Default: False
5388 : : !!
5389 : : !! OUTPUT
5390 : : !!
5391 : : !! SOURCE
5392 : :
5393 [ # # ]: 0 : subroutine slkmat_dp_cut(in_mat, glob_nrows, glob_ncols, out_mat, &
5394 : : size_blocs, processor, ija, ijb, free) ! Optional
5395 : :
5396 : : !Arguments ------------------------------------
5397 : : class(slkmat_dp_t),target,intent(inout) :: in_mat
5398 : : integer,intent(in) :: glob_nrows, glob_ncols
5399 : : class(slkmat_dp_t),intent(out) :: out_mat
5400 : : integer,optional,intent(in) :: size_blocs(2)
5401 : : class(slk_processor_t), target, optional,intent(in) :: processor
5402 : : integer,optional,intent(in) :: ija(2), ijb(2)
5403 : : logical,optional,intent(in) :: free
5404 : :
5405 : : !Local variables-------------------------------
5406 : : type(slk_processor_t), pointer :: processor__
5407 : : integer :: ija__(2), ijb__(2)
5408 : : ! *************************************************************************
5409 : :
5410 : 0 : ija__ = [1, 1]; if (present(ija)) ija__ = ija
5411 : 0 : ijb__ = [1, 1]; if (present(ijb)) ijb__ = ijb
5412 : :
5413 [ # # # # ]: 0 : processor__ => in_mat%processor; if (present(processor)) processor__ => processor
5414 : :
5415 [ # # ]: 0 : if (present(size_blocs)) then
5416 : 0 : call out_mat%init(glob_nrows, glob_ncols, processor__, in_mat%istwf_k, size_blocs=size_blocs)
5417 : : else
5418 : 0 : call out_mat%init(glob_nrows, glob_ncols, processor__, in_mat%istwf_k)
5419 : : end if
5420 : : !call out_mat%print(header="output matrix generated by slkmat_dp_cut")
5421 : :
5422 : : ! p?gemr2d: Copies a submatrix from one general rectangular matrix to another.
5423 : : ! prototype
5424 : : !call pzgemr2d(m, n, a, ia, ja, desca, b, ib, jb, descb, comm)
5425 : :
5426 [ # # ]: 0 : if (allocated(in_mat%buffer_cplx)) then
5427 : : #ifdef HAVE_LINALG_SCALAPACK
5428 : : call pzgemr2d(glob_nrows, glob_ncols, &
5429 : : in_mat%buffer_cplx, ija__(1), ija__(2), in_mat%desc, &
5430 : : out_mat%buffer_cplx, ijb__(1), ijb__(2), out_mat%desc, &
5431 : : processor__%grid%comm)
5432 : :
5433 : : else if (allocated(in_mat%buffer_real)) then
5434 : : call pdgemr2d(glob_nrows, glob_ncols, &
5435 : : in_mat%buffer_real, ija__(1), ija__(2), in_mat%desc, &
5436 : : out_mat%buffer_real, ijb__(1), ijb__(2), out_mat%desc, &
5437 : : processor__%grid%comm)
5438 : : #endif
5439 : : else
5440 : 0 : ABI_ERROR("Neither buffer_cplx nor buffer_real are allocated!")
5441 : : end if
5442 : :
5443 [ # # ]: 0 : if (present(free)) then
5444 [ # # ]: 0 : if (free) call in_mat%free()
5445 : : end if
5446 : :
5447 : 0 : end subroutine slkmat_dp_cut
5448 : : !!***
5449 : :
5450 : : !----------------------------------------------------------------------
5451 : :
5452 : : !!****f* m_slk/slkmat_sp_cut
5453 : : !! NAME
5454 : : !! slkmat_sp_cut
5455 : : !!
5456 : : !! FUNCTION
5457 : : !! Extract submatrix of shape (glob_nrows, glob_ncols) starting at `ija` from `in_mat`
5458 : : !! and create new matrix with `size_blocs` and `processor`
5459 : : !!
5460 : : !! INPUTS
5461 : : !! [free]: True if `in_mat` should be deallocated. Default: False
5462 : : !!
5463 : : !! OUTPUT
5464 : : !!
5465 : : !! SOURCE
5466 : :
5467 [ # # ]: 0 : subroutine slkmat_sp_cut(in_mat, glob_nrows, glob_ncols, out_mat, &
5468 : : size_blocs, processor, ija, ijb, free) ! Optional
5469 : :
5470 : : !Arguments ------------------------------------
5471 : : class(slkmat_sp_t),target,intent(inout) :: in_mat
5472 : : integer,intent(in) :: glob_nrows, glob_ncols
5473 : : class(slkmat_sp_t),intent(out) :: out_mat
5474 : : integer,optional,intent(in) :: size_blocs(2)
5475 : : class(slk_processor_t), target, optional,intent(in) :: processor
5476 : : integer,optional,intent(in) :: ija(2), ijb(2)
5477 : : logical,optional,intent(in) :: free
5478 : :
5479 : : !Local variables-------------------------------
5480 : : type(slk_processor_t), pointer :: processor__
5481 : : integer :: ija__(2), ijb__(2)
5482 : : ! *************************************************************************
5483 : :
5484 : 0 : ija__ = [1, 1]; if (present(ija)) ija__ = ija
5485 : 0 : ijb__ = [1, 1]; if (present(ijb)) ijb__ = ijb
5486 : :
5487 [ # # # # ]: 0 : processor__ => in_mat%processor; if (present(processor)) processor__ => processor
5488 : :
5489 [ # # ]: 0 : if (present(size_blocs)) then
5490 : 0 : call out_mat%init(glob_nrows, glob_ncols, processor__, in_mat%istwf_k, size_blocs=size_blocs)
5491 : : else
5492 : 0 : call out_mat%init(glob_nrows, glob_ncols, processor__, in_mat%istwf_k)
5493 : : end if
5494 : : !call out_mat%print(header="output matrix generated by slkmat_dp_cut")
5495 : :
5496 : : ! p?gemr2d: Copies a submatrix from one general rectangular matrix to another.
5497 : : ! prototype
5498 : : !call pzgemr2d(m, n, a, ia, ja, desca, b, ib, jb, descb, comm)
5499 : :
5500 [ # # ]: 0 : if (allocated(in_mat%buffer_cplx)) then
5501 : : #ifdef HAVE_LINALG_SCALAPACK
5502 : : call pcgemr2d(glob_nrows, glob_ncols, &
5503 : : in_mat%buffer_cplx, ija__(1), ija__(2), in_mat%desc, &
5504 : : out_mat%buffer_cplx, ijb__(1), ijb__(2), out_mat%desc, &
5505 : : processor__%grid%comm)
5506 : :
5507 : : else if (allocated(in_mat%buffer_real)) then
5508 : : call psgemr2d(glob_nrows, glob_ncols, &
5509 : : in_mat%buffer_real, ija__(1), ija__(2), in_mat%desc, &
5510 : : out_mat%buffer_real, ijb__(1), ijb__(2), out_mat%desc, &
5511 : : processor__%grid%comm)
5512 : : #endif
5513 : : else
5514 : 0 : ABI_ERROR("Neither buffer_cplx nor buffer_real are allocated!")
5515 : : end if
5516 : :
5517 [ # # ]: 0 : if (present(free)) then
5518 [ # # ]: 0 : if (free) call in_mat%free()
5519 : : end if
5520 : :
5521 : 0 : end subroutine slkmat_sp_cut
5522 : : !!***
5523 : :
5524 : : !----------------------------------------------------------------------
5525 : :
5526 : : !!****f* m_slk/slkmat_dp_take_from
5527 : : !! NAME
5528 : : !! slkmat_dp_take_from
5529 : : !!
5530 : : !! FUNCTION
5531 : : !! Take values from source
5532 : : !! NB: This routine should be called by all procs owning mat and source.
5533 : : !!
5534 : : !! INPUTS
5535 : : !! [free]: True if source should be deallocated. Default: False
5536 : : !!
5537 : : !! OUTPUT
5538 : : !!
5539 : : !! SOURCE
5540 : :
5541 : 0 : subroutine slkmat_dp_take_from(out_mat, source, &
5542 : : ija, ijb, free) ! optional
5543 : :
5544 : : !Arguments ------------------------------------
5545 : : class(slkmat_dp_t),intent(inout) :: out_mat
5546 : : class(slkmat_dp_t),intent(inout) :: source
5547 : : integer,optional,intent(in) :: ija(2), ijb(2)
5548 : : logical,optional,intent(in) :: free
5549 : :
5550 : : !Local variables-------------------------------
5551 : : integer :: mm, nn
5552 : : character(len=500) :: msg
5553 : : integer :: ija__(2), ijb__(2)
5554 : : ! *************************************************************************
5555 : :
5556 : : ! prototype
5557 : : !call pzgemr2d(m, n, a, ia, ja, desca, b, ib, jb, descb, comm)
5558 : :
5559 : : ! Take care when context A is disjoint from context B. The general rules for which parameters need to be set are:
5560 : : !
5561 : : ! - All calling processes must have the correct m and n.
5562 : : ! - Processes in context A must correctly define all parameters describing A.
5563 : : ! - Processes in context B must correctly define all parameters describing B.
5564 : : ! - Processes which are not members of context A must pass ctxt_a = -1 and need not set other parameters describing A.
5565 : : ! - Processes which are not members of contextB must pass ctxt_b = -1 and need not set other parameters describing B.
5566 : :
5567 : 0 : mm = source%size_global(1)
5568 : 0 : nn = source%size_global(2)
5569 : :
5570 : 0 : ija__ = [1, 1]; if (present(ija)) ija__ = ija
5571 : 0 : ijb__ = [1, 1]; if (present(ijb)) ijb__ = ijb
5572 : :
5573 [ # # # # : 0 : if (all(out_mat%size_global == -1)) then
# # ]
5574 : 0 : out_mat%desc(CTXT_) = -1
5575 : : else
5576 [ # # ]: 0 : ABI_CHECK_IEQ(out_mat%istwf_k, source%istwf_k, "istwfk_mat /= istwfk_source")
5577 [ # # # # : 0 : if (any(out_mat%size_global /= source%size_global)) then
# # ]
5578 : : msg = sjoin("Matrices should have same global shape but out_mat:", ltoa(out_mat%size_global), &
5579 [ # # ]: 0 : "source:", ltoa(source%size_global))
5580 : 0 : ABI_ERROR(msg)
5581 : : end if
5582 : : end if
5583 : :
5584 [ # # ]: 0 : if (allocated(source%buffer_cplx)) then
5585 : : #ifdef HAVE_LINALG_SCALAPACK
5586 : : call pzgemr2d(mm, nn, &
5587 : : source%buffer_cplx, ija__(1), ija__(2), source%desc, &
5588 : : out_mat%buffer_cplx, ijb__(1), ijb__(2), out_mat%desc, &
5589 : : source%processor%grid%comm)
5590 : :
5591 : : else if (allocated(source%buffer_real)) then
5592 : : call pdgemr2d(mm, nn, &
5593 : : source%buffer_real, ija__(1), ija__(2), source%desc, &
5594 : : out_mat%buffer_real,ijb__(1), ijb__(2), out_mat%desc, &
5595 : : source%processor%grid%comm)
5596 : : #endif
5597 : : else
5598 : 0 : ABI_ERROR("Neither buffer_cplx nor buffer_real are allocated!")
5599 : : end if
5600 : :
5601 [ # # ]: 0 : if (present(free)) then
5602 [ # # ]: 0 : if (free) call source%free()
5603 : : end if
5604 : :
5605 : 0 : end subroutine slkmat_dp_take_from
5606 : : !!***
5607 : :
5608 : : !----------------------------------------------------------------------
5609 : :
5610 : : !!****f* m_slk/slkmat_sp_take_from
5611 : : !! NAME
5612 : : !! slkmat_sp_take_from
5613 : : !!
5614 : : !! FUNCTION
5615 : : !! Take values from source
5616 : : !! NB: This routine should be called by all procs owning mat and source.
5617 : : !!
5618 : : !! INPUTS
5619 : : !! [free]: True if source should be deallocated. Default: False
5620 : : !!
5621 : : !! OUTPUT
5622 : : !!
5623 : : !! SOURCE
5624 : :
5625 : 0 : subroutine slkmat_sp_take_from(out_mat, source, &
5626 : : ija, ijb, free) ! optional
5627 : :
5628 : : !Arguments ------------------------------------
5629 : : class(slkmat_sp_t),intent(inout) :: out_mat
5630 : : class(slkmat_sp_t),intent(inout) :: source
5631 : : integer,optional,intent(in) :: ija(2), ijb(2)
5632 : : logical,optional,intent(in) :: free
5633 : :
5634 : : !Local variables-------------------------------
5635 : : integer :: mm, nn
5636 : : character(len=500) :: msg
5637 : : integer :: ija__(2), ijb__(2)
5638 : : ! *************************************************************************
5639 : :
5640 : : ! prototype
5641 : : !call pzgemr2d(m, n, a, ia, ja, desca, b, ib, jb, descb, comm)
5642 : :
5643 : : ! Take care when context A is disjoint from context B. The general rules for which parameters need to be set are:
5644 : : !
5645 : : ! - All calling processes must have the correct m and n.
5646 : : ! - Processes in context A must correctly define all parameters describing A.
5647 : : ! - Processes in context B must correctly define all parameters describing B.
5648 : : ! - Processes which are not members of context A must pass ctxt_a = -1 and need not set other parameters describing A.
5649 : : ! - Processes which are not members of contextB must pass ctxt_b = -1 and need not set other parameters describing B.
5650 : :
5651 : 0 : mm = source%size_global(1)
5652 : 0 : nn = source%size_global(2)
5653 : :
5654 : 0 : ija__ = [1, 1]; if (present(ija)) ija__ = ija
5655 : 0 : ijb__ = [1, 1]; if (present(ijb)) ijb__ = ijb
5656 : :
5657 [ # # # # : 0 : if (all(out_mat%size_global == -1)) then
# # ]
5658 : 0 : out_mat%desc(CTXT_) = -1
5659 : : else
5660 [ # # ]: 0 : ABI_CHECK_IEQ(out_mat%istwf_k, source%istwf_k, "istwfk_mat /= istwfk_source")
5661 [ # # # # : 0 : if (any(out_mat%size_global /= source%size_global)) then
# # ]
5662 : : msg = sjoin("Matrices should have same global shape but out_mat:", ltoa(out_mat%size_global), &
5663 [ # # ]: 0 : "source:", ltoa(source%size_global))
5664 : 0 : ABI_ERROR(msg)
5665 : : end if
5666 : : end if
5667 : :
5668 [ # # ]: 0 : if (allocated(source%buffer_cplx)) then
5669 : : #ifdef HAVE_LINALG_SCALAPACK
5670 : : call pcgemr2d(mm, nn, &
5671 : : source%buffer_cplx, ija__(1), ija__(2), source%desc, &
5672 : : out_mat%buffer_cplx, ijb__(1), ijb__(2), out_mat%desc, &
5673 : : source%processor%grid%comm)
5674 : :
5675 : : else if (allocated(source%buffer_real)) then
5676 : : call psgemr2d(mm, nn, &
5677 : : source%buffer_real, ija__(1), ija__(2), source%desc, &
5678 : : out_mat%buffer_real,ijb__(1), ijb__(2), out_mat%desc, &
5679 : : source%processor%grid%comm)
5680 : : #endif
5681 : : else
5682 : 0 : ABI_ERROR("Neither buffer_cplx nor buffer_real are allocated!")
5683 : : end if
5684 : :
5685 [ # # ]: 0 : if (present(free)) then
5686 [ # # ]: 0 : if (free) call source%free()
5687 : : end if
5688 : :
5689 : 0 : end subroutine slkmat_sp_take_from
5690 : : !!***
5691 : :
5692 : : !----------------------------------------------------------------------
5693 : :
5694 : : !!****f* m_slk/slkmat_dp_collect_cplx
5695 : : !! NAME
5696 : : !! slkmat_dp_collect_cplx
5697 : : !!
5698 : : !! FUNCTION
5699 : : !! Return on all processors the complex submatrix of shape (mm, nn) starting at position ija.
5700 : : !! NB: `out_carr` is allocated by the routine.
5701 : : !! If optional argument request is use, the routine uses non-blocking BCAST and client code is
5702 : : !! supposed to wait before accessing out_carr.
5703 : : !!
5704 : : !! SOURCE
5705 : :
5706 : 0 : subroutine slkmat_dp_collect_cplx(in_mat, mm, nn, ija, out_carr, request)
5707 : :
5708 : : !Arguments ------------------------------------
5709 : : class(slkmat_dp_t),intent(in) :: in_mat
5710 : : integer,intent(in) :: mm, nn, ija(2)
5711 : : complex(dp) ABI_ASYNC, allocatable,intent(out) :: out_carr(:,:)
5712 : : integer ABI_ASYNC, optional,intent(out) :: request
5713 : :
5714 : : !Local variables-------------------------------
5715 : : integer,parameter :: master = 0
5716 : : integer :: ierr
5717 : : type(slk_processor_t) :: self_processor
5718 [ # # # # : 0 : type(slkmat_dp_t) :: out_mat
# # ]
5719 : : ! *************************************************************************
5720 : :
5721 : 0 : ABI_CHECK(allocated(in_mat%buffer_cplx), "buffer_cplx is not allocated")
5722 : :
5723 [ # # ]: 0 : if (in_mat%processor%grid%nprocs == 1) then
5724 : : ! Copy buffer and return
5725 [ # # # # : 0 : ABI_MALLOC(out_carr, (mm, nn))
# # # # #
# # # # #
# # # # ]
5726 [ # # # # ]: 0 : out_carr(:,:) = in_mat%buffer_cplx(ija(1):ija(1)+mm-1, ija(2):ija(2)+nn-1); return
5727 : : end if
5728 : :
5729 : : ! Two-step algorithm:
5730 : : ! 1) Use pzgemr2d to collect submatrix on master.
5731 : : ! 2) Master brodacasts submatrix.
5732 : :
5733 [ # # ]: 0 : if (in_mat%processor%my_rank == master) then
5734 : 0 : call self_processor%init(xmpi_comm_self)
5735 [ # # ]: 0 : call out_mat%init(mm, nn, self_processor, in_mat%istwf_k, size_blocs=[mm, nn])
5736 : : else
5737 : 0 : out_mat%desc(CTXT_) = -1
5738 : : end if
5739 : :
5740 : : #ifdef HAVE_LINALG_SCALAPACK
5741 : : call pzgemr2d(mm, nn, &
5742 : : in_mat%buffer_cplx, ija(1), ija(2), in_mat%desc, &
5743 : : out_mat%buffer_cplx, 1, 1, out_mat%desc, &
5744 : : in_mat%processor%grid%comm)
5745 : : #endif
5746 : :
5747 [ # # ]: 0 : if (in_mat%processor%my_rank == master) then
5748 [ # # ]: 0 : ABI_MOVE_ALLOC(out_mat%buffer_cplx, out_carr)
5749 : 0 : call out_mat%free()
5750 : 0 : call self_processor%free()
5751 : : else
5752 [ # # # # : 0 : ABI_MALLOC(out_carr, (mm, nn))
# # # # #
# # # # #
# # # # ]
5753 : : end if
5754 : :
5755 [ # # ]: 0 : if (present(request)) then
5756 : 0 : call xmpi_ibcast(out_carr, master, in_mat%processor%comm, request, ierr)
5757 : : else
5758 : 0 : call xmpi_bcast(out_carr, master, in_mat%processor%comm, ierr)
5759 : : end if
5760 : :
5761 [ # # # # : 0 : end subroutine slkmat_dp_collect_cplx
# # # # #
# # # #
# ]
5762 : : !!***
5763 : :
5764 : : !----------------------------------------------------------------------
5765 : :
5766 : : !!****f* m_slk/slkmat_sp_collect_cplx
5767 : : !! NAME
5768 : : !! slkmat_sp_collect_cplx
5769 : : !!
5770 : : !! FUNCTION
5771 : : !! Return on all processors the complex submatrix of shape (mm, nn) starting at position ija.
5772 : : !! NB: `out_carr` is allocated by the routine.
5773 : : !! If optional argument request is use, the routine uses non-blocking BCAST and client code is
5774 : : !! supposed to wait before accessing out_carr.
5775 : : !!
5776 : : !! SOURCE
5777 : :
5778 : 0 : subroutine slkmat_sp_collect_cplx(in_mat, mm, nn, ija, out_carr, request)
5779 : :
5780 : : !Arguments ------------------------------------
5781 : : class(slkmat_sp_t),intent(in) :: in_mat
5782 : : integer,intent(in) :: mm, nn, ija(2)
5783 : : complex(sp) ABI_ASYNC, allocatable,intent(out) :: out_carr(:,:)
5784 : : integer ABI_ASYNC, optional,intent(out) :: request
5785 : :
5786 : : !Local variables-------------------------------
5787 : : integer,parameter :: master = 0
5788 : : integer :: ierr
5789 : : type(slk_processor_t) :: self_processor
5790 [ # # # # : 0 : type(slkmat_sp_t) :: out_mat
# # ]
5791 : : ! *************************************************************************
5792 : :
5793 : 0 : ABI_CHECK(allocated(in_mat%buffer_cplx), "buffer_cplx is not allocated")
5794 : :
5795 [ # # ]: 0 : if (in_mat%processor%grid%nprocs == 1) then
5796 : : ! Copy buffer and return
5797 [ # # # # : 0 : ABI_MALLOC(out_carr, (mm, nn))
# # # # #
# # # # #
# # # # ]
5798 [ # # # # ]: 0 : out_carr(:,:) = in_mat%buffer_cplx(ija(1):ija(1)+mm-1, ija(2):ija(2)+nn-1); return
5799 : : end if
5800 : :
5801 : : ! Two-step algorithm:
5802 : : ! 1) Use pzgemr2d to collect submatrix on master.
5803 : : ! 2) Master brodacasts submatrix.
5804 : :
5805 [ # # ]: 0 : if (in_mat%processor%my_rank == master) then
5806 : 0 : call self_processor%init(xmpi_comm_self)
5807 [ # # ]: 0 : call out_mat%init(mm, nn, self_processor, in_mat%istwf_k, size_blocs=[mm, nn])
5808 : : else
5809 : 0 : out_mat%desc(CTXT_) = -1
5810 : : end if
5811 : :
5812 : : #ifdef HAVE_LINALG_SCALAPACK
5813 : : call pcgemr2d(mm, nn, &
5814 : : in_mat%buffer_cplx, ija(1), ija(2), in_mat%desc, &
5815 : : out_mat%buffer_cplx, 1, 1, out_mat%desc, &
5816 : : in_mat%processor%grid%comm)
5817 : : #endif
5818 : :
5819 [ # # ]: 0 : if (in_mat%processor%my_rank == master) then
5820 [ # # ]: 0 : ABI_MOVE_ALLOC(out_mat%buffer_cplx, out_carr)
5821 : 0 : call out_mat%free()
5822 : 0 : call self_processor%free()
5823 : : else
5824 [ # # # # : 0 : ABI_MALLOC(out_carr, (mm, nn))
# # # # #
# # # # #
# # # # ]
5825 : : end if
5826 : :
5827 [ # # ]: 0 : if (present(request)) then
5828 : 0 : call xmpi_ibcast(out_carr, master, in_mat%processor%comm, request, ierr)
5829 : : else
5830 : 0 : call xmpi_bcast(out_carr, master, in_mat%processor%comm, ierr)
5831 : : end if
5832 : :
5833 [ # # # # : 0 : end subroutine slkmat_sp_collect_cplx
# # # # #
# # # #
# ]
5834 : : !!***
5835 : :
5836 : : !----------------------------------------------------------------------
5837 : :
5838 : : !!****f* m_slk/basemat_get_trace
5839 : : !! NAME
5840 : : !! basemat_get_trace
5841 : : !!
5842 : : !! FUNCTION
5843 : : !! Compute the trace of an N-by-N distributed matrix.
5844 : : !!
5845 : : !! SOURCE
5846 : :
5847 : 0 : complex(dp) function basemat_get_trace(mat) result(ctrace)
5848 : :
5849 : : !Arguments ------------------------------------
5850 : : class(basemat_t), intent(in) :: mat
5851 : :
5852 : : !Local variables-------------------------------
5853 : : #ifdef HAVE_LINALG_SCALAPACK
5854 : : integer :: iloc, jloc, iglob, jglob, ierr
5855 : : real(dp) :: rtrace
5856 : : real(sp) :: rtrace_sp
5857 : : complex(sp) :: ctrace_sp
5858 : : #endif
5859 : : ! *************************************************************************
5860 : :
5861 [ # # ]: 0 : ABI_CHECK_IEQ(mat%size_global(1), mat%size_global(2), "get_trace assumes square matrix!")
5862 : :
5863 : : ! prototype for complex version.
5864 : : ! COMPLEX*16 FUNCTION PZLATRA( N, A, IA, JA, DESCA )
5865 : : !
5866 : : ! NOTE: We don't use PZLATRA and friends as these calls can lead to SIGSEGV when
5867 : : ! we compile with gcc and link with intel scalack (very likely there's an ABI mismatch
5868 : : ! even when the compatibily layer is used --> we implement our own version.
5869 : :
5870 : : #ifdef HAVE_LINALG_SCALAPACK
5871 : : select type (mat)
5872 : : class is (slkmat_dp_t)
5873 : : if (allocated(mat%buffer_cplx)) then
5874 : : !ctrace = PZLATRA(mat%size_global(1), mat%buffer_cplx, 1, 1, mat%desc)
5875 : : ctrace = zero
5876 : : do jloc=1,mat%size_local(2)
5877 : : do iloc=1,mat%size_local(1)
5878 : : call mat%loc2glob(iloc, jloc, iglob, jglob)
5879 : : if (iglob == jglob) ctrace = ctrace + mat%buffer_cplx(iloc, jloc)
5880 : : end do
5881 : : end do
5882 : :
5883 : : else if (allocated(mat%buffer_real)) then
5884 : : !rtrace = PDLATRA(mat%size_global(1), mat%buffer_real, 1, 1, mat%desc)
5885 : : rtrace = zero
5886 : : do jloc=1,mat%size_local(2)
5887 : : do iloc=1,mat%size_local(1)
5888 : : call mat%loc2glob(iloc, jloc, iglob, jglob)
5889 : : if (iglob == jglob) rtrace = rtrace + mat%buffer_real(iloc, jloc)
5890 : : end do
5891 : : end do
5892 : : ctrace = rtrace
5893 : :
5894 : : else
5895 : : ABI_ERROR("Neither buffer_cplx nor buffer_real are allocated!")
5896 : : end if
5897 : :
5898 : : class is (slkmat_sp_t)
5899 : : if (allocated(mat%buffer_cplx)) then
5900 : : !ctrace_sp = PCLATRA(mat%size_global(1), mat%buffer_cplx, 1, 1, mat%desc)
5901 : : ctrace_sp = zero
5902 : : do jloc=1,mat%size_local(2)
5903 : : do iloc=1,mat%size_local(1)
5904 : : call mat%loc2glob(iloc, jloc, iglob, jglob)
5905 : : if (iglob == jglob) ctrace_sp = ctrace_sp + mat%buffer_cplx(iloc, jloc)
5906 : : end do
5907 : : end do
5908 : : ctrace = ctrace_sp
5909 : :
5910 : : else if (allocated(mat%buffer_real)) then
5911 : : !rtrace_sp = PSLATRA(mat%size_global(1), mat%buffer_real, 1, 1, mat%desc)
5912 : : rtrace_sp = zero
5913 : : do jloc=1,mat%size_local(2)
5914 : : do iloc=1,mat%size_local(1)
5915 : : call mat%loc2glob(iloc, jloc, iglob, jglob)
5916 : : if (iglob == jglob) rtrace_sp = rtrace_sp + mat%buffer_real(iloc, jloc)
5917 : : end do
5918 : : end do
5919 : : ctrace = rtrace_sp
5920 : :
5921 : : else
5922 : : ABI_ERROR("Neither buffer_cplx nor buffer_real are allocated!")
5923 : : end if
5924 : :
5925 : : class default
5926 : : ABI_ERROR("Wrong class")
5927 : : end select
5928 : :
5929 : : call xmpi_sum(ctrace, mat%processor%comm, ierr)
5930 : : #endif
5931 : :
5932 : 0 : end function basemat_get_trace
5933 : : !!***
5934 : :
5935 : : !----------------------------------------------------------------------
5936 : :
5937 : : !!****f* m_slk/basemat_set_imag_diago_to_zero
5938 : : !! NAME
5939 : : !! basemat_set_imag_diago_to_zero
5940 : : !!
5941 : : !! FUNCTION
5942 : : !! Set the imaginary part of the diagonal to zero.
5943 : : !! Return in local_max the max of the imaginar part in the local buffer.
5944 : : !! No MPI communication is performed inside the routine. Client code can easily reduce
5945 : : !! local_max within the PBLAS communicator if needed.
5946 : : !!
5947 : : !! INPUTS
5948 : : !!
5949 : : !! OUTPUT
5950 : : !!
5951 : : !! SOURCE
5952 : :
5953 : 0 : subroutine basemat_set_imag_diago_to_zero(mat, local_max)
5954 : :
5955 : : !Arguments ------------------------------------
5956 : : class(basemat_t), intent(inout) :: mat
5957 : : real(dp),intent(out) :: local_max
5958 : :
5959 : : !Local variables-------------------------------
5960 : : integer :: il1, iglob1, il2, iglob2
5961 : : ! *************************************************************************
5962 : :
5963 : 0 : local_max = -huge(one)
5964 : :
5965 : : select type (mat)
5966 : : class is (slkmat_dp_t)
5967 [ # # ]: 0 : if (allocated(mat%buffer_real)) return
5968 [ # # ]: 0 : do il2=1,mat%size_local(2)
5969 : 0 : iglob2 = mat%loc2gcol(il2)
5970 [ # # ]: 0 : do il1=1,mat%size_local(1)
5971 : 0 : iglob1 = mat%loc2grow(il1)
5972 [ # # ]: 0 : if (iglob1 == iglob2) then
5973 : 0 : local_max = max(local_max, aimag(mat%buffer_cplx(il1, il2)))
5974 : 0 : mat%buffer_cplx(il1, il2) = real(mat%buffer_cplx(il1, il2))
5975 : : end if
5976 : : end do
5977 : : end do
5978 : :
5979 : : class is (slkmat_sp_t)
5980 [ # # ]: 0 : if (allocated(mat%buffer_real)) return
5981 [ # # ]: 0 : do il2=1,mat%size_local(2)
5982 : 0 : iglob2 = mat%loc2gcol(il2)
5983 [ # # ]: 0 : do il1=1,mat%size_local(1)
5984 : 0 : iglob1 = mat%loc2grow(il1)
5985 [ # # ]: 0 : if (iglob1 == iglob2) then
5986 : 0 : local_max = max(local_max, aimag(mat%buffer_cplx(il1, il2)))
5987 : 0 : mat%buffer_cplx(il1, il2) = real(mat%buffer_cplx(il1, il2))
5988 : : end if
5989 : : end do
5990 : : end do
5991 : :
5992 : : class default
5993 : 0 : ABI_ERROR("Wrong class")
5994 : : end select
5995 : :
5996 : : end subroutine basemat_set_imag_diago_to_zero
5997 : : !!***
5998 : :
5999 : : !----------------------------------------------------------------------
6000 : :
6001 : : !!****f* m_slk/slk_write
6002 : : !! NAME
6003 : : !! slk_write
6004 : : !!
6005 : : !! FUNCTION
6006 : : !! Routine to write a square scaLAPACK-distributed matrix to an external file using MPI-IO.
6007 : : !!
6008 : : !! INPUTS
6009 : : !! Slk_mat<slkmat_dp_t>=Structured datatype defining the scaLAPACK distribution with the local buffer
6010 : : !! containing the distributed matrix.
6011 : : !! uplo=String specifying whether only the upper or lower triangular part of the global matrix is used:
6012 : : !! = "U": Upper triangular
6013 : : !! = "L": Lower triangular
6014 : : !! = "A": Full matrix (used for general complex matrices)
6015 : : !! is_fortran_file=.FALSE. is C stream is used. .TRUE. for writing Fortran binary files.
6016 : : !! [fname]= Mutually exclusive with mpi_fh. The name of the external file on which the matrix will be written.
6017 : : !! The file is open and closed inside the routine with MPI flags specified by flags.
6018 : : !! [mpi_fh]=File handler associated to the file (already open in the caller). Not compatible with fname.
6019 : : !! [flags]=MPI-IO flags used to open the file in MPI_FILE_OPEN.
6020 : : !! Default is MPI_MODE_CREATE + MPI_MODE_WRONLY + MPI_MODE_EXCL.
6021 : : !! [glob_subarray(2,2)] = Used to select the subarray of the global matrix. Used only when uplo="All"
6022 : : !! NOTE that each node should call the routine with the same value.
6023 : : !! glob_subarray(:,1)=starting global coordinates of the subarray in each dimension
6024 : : !! (array of nonnegative integers >=1, <=array_of_sizes)
6025 : : !! glob_subarray(:,2)=Number of elements in each dimension of the subarray (array of positive integers)
6026 : : !!
6027 : : !! OUTPUT
6028 : : !! Only writing. The global scaLAPACK matrix is written to file fname.
6029 : : !! If fname is present then the file is open and closed inside the routine. Any exception is fatal.
6030 : : !!
6031 : : !! SIDE EFFECTS
6032 : : !! [offset]=
6033 : : !! input: Offset used to access the content of the file. Default is zero.
6034 : : !! output: New offset incremented with the byte size of the matrix that has been read (Fortran
6035 : : !! markers are included if is_fortran_file=.TRUE.)
6036 : : !! TODO
6037 : : !! - Generalize the implementation adding the writing the real buffer.
6038 : : !! - This routine should be removed and replaced by hdf5 + mpi-io
6039 : : !!
6040 : : !! SOURCE
6041 : :
6042 : 0 : subroutine slk_write(Slk_mat, uplo, is_fortran_file, fname,mpi_fh, offset, flags, glob_subarray)
6043 : :
6044 : : !Arguments ------------------------------------
6045 : : !scalars
6046 : : integer,optional,intent(in) :: flags
6047 : : integer,optional,intent(inout) :: mpi_fh
6048 : : integer(XMPI_OFFSET_KIND),optional,intent(inout) :: offset
6049 : : logical,intent(in) :: is_fortran_file
6050 : : character(len=*),optional,intent(in) :: fname
6051 : : character(len=*),intent(in) :: uplo
6052 : : class(slkmat_dp_t),intent(in) :: Slk_mat
6053 : : !array
6054 : : integer,optional,intent(in) :: glob_subarray(2,2)
6055 : :
6056 : : !Local variables ------------------------------
6057 : : !scalars
6058 : : #if defined HAVE_LINALG_SCALAPACK && defined HAVE_MPI_IO
6059 : : integer :: jloc,iloc,nrows_glob,ncols_glob,elw,nrows_w,ncols_w ! iglob,jglob,
6060 : : integer :: slk_type,offset_err,etype,nfrec,bsize_elm,mpi_type_elm
6061 : : integer(XMPI_OFFSET_KIND) :: my_offset
6062 : : logical :: do_open
6063 : : integer :: comm,my_flags,my_fh,buffer_size
6064 : : integer :: ierr,nelw,col_glob ! ij_loc,
6065 : : !arrays
6066 : : integer(XMPI_OFFSET_KIND),allocatable :: bsize_frecord(:)
6067 : : integer,pointer :: elw2slk(:,:)
6068 : : complex(dpc),allocatable :: buffer1_cplx(:)
6069 : : character(len=500) :: msg
6070 : : !************************************************************************
6071 : :
6072 : : ABI_CHECK(allocated(Slk_mat%buffer_cplx), "buffer_cplx not allocated")
6073 : :
6074 : : if (firstchar(uplo, ["U","L"]) .and. Slk_mat%size_global(1) /= Slk_mat%size_global(2) ) then
6075 : : ABI_ERROR("rectangular matrices are not compatible with the specified uplo")
6076 : : end if
6077 : :
6078 : : if (PRESENT(glob_subarray).and. .not. firstchar(uplo, ["A"])) then
6079 : : ABI_ERROR("glob_subarray should not be used when uplo/=All")
6080 : : end if
6081 : :
6082 : : do_open = PRESENT(fname)
6083 : : if (do_open) then
6084 : : ABI_CHECK(.not.PRESENT(fname),"fname should not be present")
6085 : : else
6086 : : ABI_CHECK(PRESENT(mpi_fh),"mpi_fh should be present")
6087 : : end if
6088 : :
6089 : : my_offset=0; if (PRESENT(offset)) my_offset=offset
6090 : :
6091 : : comm = Slk_mat%processor%comm
6092 : :
6093 : : nrows_glob=Slk_mat%size_global(1)
6094 : : ncols_glob=Slk_mat%size_global(1)
6095 : : buffer_size= PRODUCT(Slk_mat%size_local(1:2))
6096 : :
6097 : : call slk_mat%bsize_and_type(bsize_elm, mpi_type_elm)
6098 : :
6099 : : if (do_open) then !Open the file.
6100 : : my_flags=MPI_MODE_CREATE + MPI_MODE_WRONLY + MPI_MODE_APPEND
6101 : : if (PRESENT(flags)) my_flags = flags
6102 : :
6103 : : call MPI_FILE_OPEN(comm, fname, my_flags, MPI_INFO_NULL, my_fh, ierr)
6104 : : ABI_CHECK_MPI(ierr, "MPI_FILE_OPEN "//TRIM(fname))
6105 : : else
6106 : : my_fh = mpi_fh
6107 : : end if
6108 : :
6109 : : if (PRESENT(glob_subarray)) then
6110 : : call slk_single_fview_write(Slk_mat,uplo,nelw,elw2slk,etype,slk_type,offset_err,&
6111 : : is_fortran_file=is_fortran_file,glob_subarray=glob_subarray)
6112 : : else
6113 : : call slk_single_fview_write(Slk_mat,uplo,nelw,elw2slk,etype,slk_type,offset_err,&
6114 : : is_fortran_file=is_fortran_file)
6115 : : end if
6116 : :
6117 : : if (offset_err /= 0) then
6118 : : write(msg,"(3a)")&
6119 : : " Global position index cannot be stored in standard Fortran integer ",ch10,&
6120 : : " scaLAPACK matrix cannot be read with a single MPI-IO call."
6121 : : ABI_ERROR(msg)
6122 : : end if
6123 : :
6124 : : call MPI_FILE_SET_VIEW(my_fh, my_offset, etype, slk_type, 'native', MPI_INFO_NULL, ierr)
6125 : : ABI_CHECK_MPI(ierr,"SET_VIEW")
6126 : :
6127 : : call MPI_TYPE_FREE(slk_type,ierr)
6128 : : ABI_CHECK_MPI(ierr,"MPI_type_FREE")
6129 : :
6130 : : if (nelw == buffer_size) then
6131 : : ! Dump Slk_mat% immediately.
6132 : : call MPI_FILE_WRITE_ALL(my_fh, Slk_mat%buffer_cplx, buffer_size, MPI_DOUBLE_complex, MPI_STATUS_IGNORE, ierr)
6133 : : ABI_CHECK_MPI(ierr,"WRITE_ALL")
6134 : : else
6135 : : ! Have to extract the data to be written.
6136 : : ABI_MALLOC(buffer1_cplx,(nelw))
6137 : : do elw=1,nelw
6138 : : iloc = elw2slk(1,elw)
6139 : : jloc = elw2slk(2,elw)
6140 : : buffer1_cplx(elw) = Slk_mat%buffer_cplx(iloc,jloc)
6141 : : end do
6142 : : call MPI_FILE_WRITE_ALL(my_fh, buffer1_cplx, nelw, MPI_DOUBLE_complex, MPI_STATUS_IGNORE, ierr)
6143 : : ABI_CHECK_MPI(ierr,"WRITE_ALL")
6144 : : ABI_FREE(buffer1_cplx)
6145 : : end if
6146 : :
6147 : : ABI_FREE(elw2slk)
6148 : : !
6149 : : ! Number of columns and rows that have been written.
6150 : : ! Used to write the Fortran markers and to increment the offset.
6151 : : nrows_w = nrows_glob
6152 : : ncols_w = ncols_glob
6153 : : if (PRESENT(glob_subarray)) then
6154 : : nrows_w = glob_subarray(1,2) - glob_subarray(1,1) + 1
6155 : : ncols_w = glob_subarray(2,2) - glob_subarray(2,1) + 1
6156 : : if (.not.firstchar(uplo, ["A"])) then
6157 : : ABI_ERROR("glob_subarray should not be used when uplo/=All")
6158 : : end if
6159 : : end if
6160 : :
6161 : : !TODO check whether slk_single_fview_write can report an offset to reduce the extent.
6162 : : if (is_fortran_file) then ! Collective writing of the Fortran markers.
6163 : : nfrec = ncols_w
6164 : : ABI_MALLOC(bsize_frecord,(nfrec))
6165 : : if (firstchar(uplo, ["A"])) then
6166 : : bsize_frecord = nrows_w * bsize_elm
6167 : : else if (firstchar(uplo, ["U"])) then
6168 : : bsize_frecord = (/(col_glob * bsize_elm, col_glob=1,nfrec)/)
6169 : : else if (firstchar(uplo, ["L"])) then
6170 : : bsize_frecord = (/(col_glob * bsize_elm, col_glob=nfrec,1,-1)/)
6171 : : else
6172 : : ABI_ERROR("Wrong uplo")
6173 : : end if
6174 : : call xmpio_write_frmarkers(mpi_fh,my_offset,xmpio_collective,nfrec,bsize_frecord,ierr)
6175 : : ABI_CHECK(ierr==0,"Error while writing Fortran markers")
6176 : : ABI_FREE(bsize_frecord)
6177 : : end if
6178 : :
6179 : : if (do_open) then
6180 : : ! Close the file.
6181 : : call MPI_FILE_CLOSE(my_fh, ierr)
6182 : : ABI_CHECK_MPI(ierr,"FILE_CLOSE")
6183 : : end if
6184 : :
6185 : : ! Increment the offset
6186 : : if (PRESENT(offset)) then
6187 : : if (firstchar(uplo, ["A"])) then
6188 : : offset = offset + nrows_w*ncols_w*bsize_elm
6189 : : if (is_fortran_file) offset = offset + ncols_w*2*xmpio_bsize_frm
6190 : : else if (firstchar(uplo, ["U","L"])) then
6191 : : offset = offset + ( (Slk_mat%size_global(2) * (Slk_mat%size_global(2))+1)/2 ) * bsize_elm
6192 : : if (is_fortran_file) offset = offset + Slk_mat%size_global(2)*2*xmpio_bsize_frm
6193 : : else
6194 : : ABI_ERROR("Wrong uplo")
6195 : : end if
6196 : : end if
6197 : :
6198 : : call xmpi_barrier(comm)
6199 : : RETURN
6200 : :
6201 : : #else
6202 : 0 : ABI_ERROR("MPI-IO support not activated")
6203 : : #endif
6204 : :
6205 : 0 : end subroutine slk_write
6206 : : !!***
6207 : :
6208 : : !----------------------------------------------------------------------
6209 : :
6210 : : !!****f* m_slk/slk_read
6211 : : !! NAME
6212 : : !! slk_read
6213 : : !!
6214 : : !! FUNCTION
6215 : : !! Routine to read a square scaLAPACK distributed matrix from an external file using MPI-IO.
6216 : : !!
6217 : : !! INPUTS
6218 : : !! uplo=String specifying whether only the upper or lower triangular part of the global matrix is stored on disk:
6219 : : !! = "U": Upper triangular is stored
6220 : : !! = "L": Lower triangular is stored
6221 : : !! = "A": Full matrix (used for general complex matrices)
6222 : : !! symtype=Symmetry type of the matrix stored on disk (used only if uplo = "L" or "A").
6223 : : !! = "H" for Hermitian matrix
6224 : : !! = "S" for symmetric matrix.
6225 : : !! = "N" if matrix has no symmetry (not compatible with uplo="L" or uplo="U".
6226 : : !! is_fortran_file=.FALSE. is C stream is used. .TRUE. for writing Fortran binary files.
6227 : : !! [fname]= Mutually exclusive with mpi_fh. The name of the external file from which the matrix will be read.
6228 : : !! The file is open and closed inside the routine with MPI flags specified by flags.
6229 : : !! [mpi_fh]=File handler associated to the file (already open in the caller). Not compatible with fname.
6230 : : !! [flags]=MPI-IO flags used to open the file in MPI_FILE_OPEN. Default is MPI_MODE_RDONLY. Referenced only when fname is used.
6231 : : !!
6232 : : !! SIDE EFFECTS
6233 : : !! Slk_mat<slkmat_dp_t>=Structured datatype defining the scaLAPACK distribution with the local buffer
6234 : : !! supposed to be allocated.
6235 : : !! %buffer_cplx=Local buffer containg the distributed matrix stored on the external file.
6236 : : !! If fname is present then the file is opened and closed inside the routine. Any exception is fatal.
6237 : : !! [offset]=
6238 : : !! input: Offset used to access the content of the file. Default is zero.
6239 : : !! output: New offset incremented with the byte size of the matrix that has been read (Fortran
6240 : : !! markers are included if is_fortran_file=.TRUE.)
6241 : : !!
6242 : : !! TODO
6243 : : !! - Generalize the implementation adding the reading of the real buffer.
6244 : : !!
6245 : : !! - This routine is not portable as this kind of access pattern is not supported by all MPI implementations
6246 : : !! E.g. with MPICH we have
6247 : : !!
6248 : : !! --- !ERROR
6249 : : !! src_file: m_slk.F90
6250 : : !! src_line: 3780
6251 : : !! mpi_rank: 1
6252 : : !! message: |
6253 : : !! SET_VIEW
6254 : : !! Other I/O error , error stack:
6255 : : !! ADIO_Set_view(48): **iobadoverlap displacements of filetype must be in a monotonically nondecreasing order
6256 : : !! ...
6257 : : !!
6258 : : !! - This routine should be removed and replaced by hdf5 + mpi-io
6259 : : !!
6260 : : !! SOURCE
6261 : :
6262 : 0 : subroutine slk_read(Slk_mat,uplo,symtype,is_fortran_file,fname,mpi_fh,offset,flags)
6263 : :
6264 : : !Arguments ------------------------------------
6265 : : !scalars
6266 : : integer,optional,intent(in) :: flags,mpi_fh
6267 : : integer(XMPI_OFFSET_KIND),optional,intent(inout) :: offset
6268 : : character(len=*),optional,intent(in) :: fname
6269 : : character(len=*),intent(in) :: uplo,symtype
6270 : : logical,intent(in) :: is_fortran_file
6271 : : class(slkmat_dp_t),intent(inout) :: Slk_mat
6272 : :
6273 : : !Local variables ------------------------------
6274 : : #if defined HAVE_LINALG_SCALAPACK && defined HAVE_MPI_IO
6275 : : !scalars
6276 : : integer :: nrows_glob,offset_err,slk_type,etype
6277 : : integer(XMPI_OFFSET_KIND) :: my_offset
6278 : : logical :: do_open
6279 : : integer :: comm,my_flags,my_fh,buffer_size,ierr,col_glob
6280 : : integer :: nfrec,bsize_elm,mpi_type_elm
6281 : : !complex(dpc) :: ctest
6282 : : logical,parameter :: check_frm=.TRUE.
6283 : : integer(XMPI_OFFSET_KIND),allocatable :: bsize_frecord(:)
6284 : : !arrays
6285 : : character(len=500) :: msg
6286 : : !************************************************************************
6287 : :
6288 : : do_open = PRESENT(fname)
6289 : : if (do_open) then
6290 : : ABI_CHECK(.not.PRESENT(fname), "fname should not be present")
6291 : : else
6292 : : ABI_CHECK(PRESENT(mpi_fh), "mpi_fh should be present")
6293 : : end if
6294 : :
6295 : : my_offset=0; if (PRESENT(offset)) my_offset=offset
6296 : :
6297 : : ABI_CHECK(allocated(Slk_mat%buffer_cplx), "%buffer_cplx not allocated")
6298 : : if (firstchar(uplo, ["U","L"]) .and. Slk_mat%size_global(1) /= Slk_mat%size_global(2) ) then
6299 : : ABI_ERROR("rectangular matrices are not compatible with the specified uplo")
6300 : : end if
6301 : :
6302 : : nrows_glob = Slk_mat%size_global(1)
6303 : :
6304 : : buffer_size= PRODUCT(Slk_mat%size_local(1:2))
6305 : :
6306 : : call wrtout(std_out, "slk_read: Using MPI-IO")
6307 : :
6308 : : comm = Slk_mat%processor%comm
6309 : :
6310 : : if (do_open) then ! Open the file.
6311 : : my_flags=MPI_MODE_RDONLY; if (PRESENT(flags)) my_flags = flags
6312 : : call MPI_FILE_OPEN(comm, fname, my_flags, MPI_INFO_NULL, my_fh, ierr)
6313 : : ABI_CHECK_MPI(ierr,"FILE_OPEN "//TRIM(fname))
6314 : : else
6315 : : my_fh = mpi_fh
6316 : : end if
6317 : :
6318 : : call slk_single_fview_read(Slk_mat,uplo,etype,slk_type,offset_err,is_fortran_file=is_fortran_file)
6319 : :
6320 : : if (offset_err/=0) then
6321 : : write(msg,"(3a)")&
6322 : : "Global position index cannot be stored in standard Fortran integer ",ch10,&
6323 : : "scaLAPACK matrix cannot be read with a single MPI-IO call."
6324 : : ABI_ERROR(msg)
6325 : : end if
6326 : :
6327 : : call MPI_FILE_SET_VIEW(my_fh, my_offset, etype, slk_type, 'native', MPI_INFO_NULL, ierr)
6328 : : ABI_CHECK_MPI(ierr,"SET_VIEW")
6329 : :
6330 : : call MPI_FILE_READ_ALL(my_fh, Slk_mat%buffer_cplx, buffer_size, MPI_DOUBLE_complex, MPI_STATUS_IGNORE, ierr)
6331 : : ABI_CHECK_MPI(ierr,"READ_ALL")
6332 : :
6333 : : ! Symmetrize local buffer if uplo /= "All"
6334 : : call Slk_mat%symmetrize(uplo, symtype)
6335 : :
6336 : : !BEGINDEBUG
6337 : : !call MPI_FILE_READ_AT(mpi_fh,my_offset+xmpio_bsize_frm,ctest,1,MPI_DOUBLE_complex,MPI_STATUS_IGNORE,ierr)
6338 : : !write(std_out,*)"ctest",ctest
6339 : : !call MPI_FILE_READ_AT(mpi_fh,my_offset+2*xmpio_bsize_frm,ctest,1,MPI_DOUBLE_complex,MPI_STATUS_IGNORE,ierr)
6340 : : !write(std_out,*)"ctest",ctest
6341 : : !ENDDEBUG
6342 : :
6343 : : !call print_arr(Slk_mat%buffer_cplx,max_r=10,max_c=10,unit=std_out)
6344 : : !
6345 : : ! Close the file and release the MPI filetype.
6346 : : call MPI_type_FREE(slk_type,ierr)
6347 : : ABI_CHECK_MPI(ierr,"MPI_type_FREE")
6348 : :
6349 : : call slk_mat%bsize_and_type(bsize_elm, mpi_type_elm)
6350 : :
6351 : : !It seems that personal call makes the code stuck
6352 : : !if (is_fortran_file .and. check_frm .and. Slk_mat%Processor%my_rank==0) then ! Master checks the Fortran markers.
6353 : : if (is_fortran_file .and. check_frm) then ! Master checks the Fortran markers.
6354 : : call wrtout(std_out,"Checking Fortran record markers...", do_flush=.True.)
6355 : : nfrec = Slk_mat%size_global(2)
6356 : : ABI_MALLOC(bsize_frecord,(nfrec))
6357 : : if (firstchar(uplo, ["A"])) then
6358 : : bsize_frecord = Slk_mat%size_global(1) * bsize_elm
6359 : : else if (firstchar(uplo, ["U"])) then
6360 : : bsize_frecord = (/(col_glob * bsize_elm, col_glob=1,nfrec)/)
6361 : : else if (firstchar(uplo, ["L"])) then
6362 : : bsize_frecord = (/(col_glob * bsize_elm, col_glob=nfrec,1,-1)/)
6363 : : else
6364 : : ABI_ERROR("Wrong uplo")
6365 : : end if
6366 : : call xmpio_check_frmarkers(my_fh,my_offset,xmpio_collective,nfrec,bsize_frecord,ierr)
6367 : : ABI_CHECK(ierr==0,"Wrong Fortran record markers")
6368 : : ABI_FREE(bsize_frecord)
6369 : : end if
6370 : :
6371 : : if (do_open) then ! Close the file.
6372 : : call MPI_FILE_CLOSE(my_fh, ierr)
6373 : : ABI_CHECK_MPI(ierr,"FILE_CLOSE")
6374 : : end if
6375 : :
6376 : : !Increment the offset
6377 : : if (PRESENT(offset)) then
6378 : : if (firstchar(uplo, ["A"])) then
6379 : : offset = offset + PRODUCT(Slk_mat%size_global(1:2)) * bsize_elm
6380 : : if (is_fortran_file) offset = offset + Slk_mat%size_global(2)*2*xmpio_bsize_frm
6381 : : else if (firstchar(uplo, ["U","L"])) then
6382 : : offset = offset + ( (Slk_mat%size_global(2) * (Slk_mat%size_global(2))+1)/2 ) * bsize_elm
6383 : : if (is_fortran_file) offset = offset + Slk_mat%size_global(2)*2*xmpio_bsize_frm
6384 : : else
6385 : : ABI_ERROR("Wrong uplo")
6386 : : end if
6387 : : end if
6388 : :
6389 : : call xmpi_barrier(comm)
6390 : : RETURN
6391 : :
6392 : : #else
6393 : 0 : ABI_ERROR("MPI-IO support not enabled")
6394 : : #endif
6395 : :
6396 : 0 : end subroutine slk_read
6397 : : !!***
6398 : :
6399 : : !----------------------------------------------------------------------
6400 : :
6401 : : !!****f* m_slk/slk_single_fview_read_mask
6402 : : !! NAME
6403 : : !! slk_single_fview_read_mask
6404 : : !!
6405 : : !! FUNCTION
6406 : : !! Return an MPI datatype that can be used to read a scaLAPACK distributed matrix from
6407 : : !! a binary file using MPI-IO. The view is created using the user-defined mask function
6408 : : !! mask_of_glob. The storage of the data on file is described via the user-defined function offset_of_glob.
6409 : : !!
6410 : : !! INPUTS
6411 : : !! Slk_mat<slkmat_dp_t>=Structured datatype defining the scaLAPACK matrix.
6412 : : !! mask_of_glob(row_glob,col_glob,size_glob) is an integer function that accepts in input
6413 : : !! the global indices of the matrix size_glob(1:2) are the global dimensions.
6414 : : !! Return 0 if (row_glob,col_glob) should not be read.
6415 : : !! offset_of_glob(row_glob,col_glob,size_glob,nsblocks,sub_block,bsize_elm,bsize_frm)
6416 : : !! nsblocks=Number of sub-blocks (will be passed to offset_of_glob)
6417 : : !! sub_block(2,2,nsblocks)=Global coordinates of the extremal points delimiting the sub-blocs
6418 : : !! e.g. sub_block(:,1,1) gives the coordinates of the left upper corner of the first block.
6419 : : !! sub_block(:,2,1) gives the coordinates of the right lower corner of the first block.
6420 : : !! [is_fortran_file]=.FALSE. is C stream is used. Set to .TRUE. for writing Fortran binary files
6421 : : !! with record marker.
6422 : : !!
6423 : : !! OUTPUT
6424 : : !! my_nel=Number of elements that will be read by this node.
6425 : : !! etype=Elementary data type (handle) defining the elementary unit used to access the file.
6426 : : !! This is the elementary type that must be used to creae the view (MPI_BYTE is used).
6427 : : !! slk_type=New MPI type that can be used to instantiate the MPI-IO view for the Fortran file.
6428 : : !! Note that the view assumes that the file pointer points to the FIRST Fortran record marker.
6429 : : !! offset_err=Error code. A returned non-zero value signals that the global matrix is too large
6430 : : !! for a single MPI-IO access. See notes in other slk_single_fview_* routines.
6431 : : !!
6432 : : !! SIDE EFFECTS
6433 : : !! myel2loc(:,:)
6434 : : !! input: pointer to NULL
6435 : : !! output: myel2loc(2,my_nel): myel2loc(:,el) gives (iloc,jloc) for el=1,my_nel.
6436 : : !!
6437 : : !! SOURCE
6438 : :
6439 : 0 : subroutine slk_single_fview_read_mask(Slk_mat,mask_of_glob,offset_of_glob,nsblocks,sub_block,&
6440 : : my_nel,myel2loc,etype,slk_type,offset_err,is_fortran_file)
6441 : :
6442 : : !Arguments ------------------------------------
6443 : : !scalars
6444 : : integer,intent(in) :: nsblocks
6445 : : integer,intent(out) :: my_nel,offset_err,slk_type,etype
6446 : : logical,optional,intent(in) :: is_fortran_file
6447 : : class(slkmat_dp_t),intent(in) :: Slk_mat
6448 : : !arrays
6449 : : integer,intent(in) :: sub_block(2,2,nsblocks)
6450 : : integer,pointer :: myel2loc(:,:)
6451 : :
6452 : : interface
6453 : : function mask_of_glob(row_glob,col_glob,size_glob)
6454 : : use defs_basis
6455 : : integer :: mask_of_glob
6456 : : integer,intent(in) :: row_glob,col_glob
6457 : : integer,intent(in) :: size_glob(2)
6458 : : end function mask_of_glob
6459 : : end interface
6460 : :
6461 : : interface
6462 : : function offset_of_glob(row_glob,col_glob,size_glob,nsblocks,sub_block,bsize_elm,bsize_frm)
6463 : : use defs_basis
6464 : : use m_xmpi
6465 : : integer(XMPI_OFFSET_KIND) :: offset_of_glob
6466 : : integer,intent(in) :: row_glob,col_glob,bsize_elm,bsize_frm,nsblocks
6467 : : integer,intent(in) :: size_glob(2),sub_block(2,2,nsblocks)
6468 : : end function offset_of_glob
6469 : : end interface
6470 : :
6471 : : !Local variables ------------------------------
6472 : : !scalars
6473 : : integer :: el,jloc,iloc,iglob,jglob,mpi_err,sweep
6474 : : integer :: bsize_frm,mpi_type_elm,bsize_elm
6475 : : integer(XMPI_OFFSET_KIND) :: tmp_off,max_displ
6476 : : !arrays
6477 : : character(len=500) :: msg
6478 : 0 : integer,allocatable :: block_length(:),block_type(:)
6479 : 0 : integer(XMPI_ADDRESS_KIND),allocatable :: block_displ(:)
6480 : : !************************************************************************
6481 : :
6482 : : #ifdef HAVE_MPI_IO
6483 : 0 : bsize_frm = xmpio_bsize_frm ! Byte size of the Fortran record marker.
6484 [ # # ]: 0 : if (PRESENT(is_fortran_file)) then
6485 [ # # ]: 0 : if (.not.is_fortran_file) bsize_frm = 0
6486 : : end if
6487 : :
6488 : : ! Byte size of the matrix element.
6489 : 0 : call slk_mat%bsize_and_type(bsize_elm, mpi_type_elm)
6490 : :
6491 : : ! Find the number of local matrix elements to be read, then create the table myel2loc.
6492 [ # # ]: 0 : do sweep=1,2
6493 [ # # ]: 0 : if (sweep==2) then
6494 [ # # # # : 0 : ABI_MALLOC(myel2loc,(2,my_nel))
# # # # #
# # # ]
6495 : : end if
6496 : 0 : my_nel=0
6497 : :
6498 [ # # ]: 0 : do jloc=1,Slk_mat%size_local(2)
6499 [ # # ]: 0 : do iloc=1,Slk_mat%size_local(1)
6500 : 0 : call slk_mat%loc2glob(iloc, jloc, iglob, jglob)
6501 [ # # ]: 0 : if ( mask_of_glob(iglob,jglob,Slk_mat%size_global)/= 0) then ! Will fill this entry.
6502 : 0 : my_nel = my_nel+1
6503 [ # # # # ]: 0 : if (sweep==2) myel2loc(:,my_nel) = (/iloc,jloc/)
6504 : : end if
6505 : : end do
6506 : : end do
6507 : : end do
6508 : :
6509 : 0 : etype = MPI_BYTE
6510 : :
6511 : : ! Define the mapping between scaLAPACK buffer and the storage on file.
6512 : : ! Note that the view assumes that the file pointer points to the first Fortran record marker.
6513 [ # # # # : 0 : ABI_MALLOC(block_length,(my_nel+2))
# # # # #
# # # #
# ]
6514 [ # # # # : 0 : ABI_MALLOC(block_displ,(my_nel+2))
# # # # #
# # # ]
6515 [ # # # # : 0 : ABI_MALLOC(block_type,(my_nel+2))
# # # # ]
6516 : 0 : block_length(1)=1
6517 : 0 : block_displ (1)=0
6518 : 0 : block_type (1)=MPI_LB
6519 : :
6520 : 0 : offset_err=0; max_displ=0
6521 [ # # ]: 0 : do el=1,my_nel
6522 : 0 : iloc = myel2loc(1,el)
6523 : 0 : jloc = myel2loc(2,el)
6524 : 0 : call slk_mat%loc2glob(iloc, jloc, iglob, jglob)
6525 : 0 : tmp_off = offset_of_glob(iglob,jglob,Slk_mat%size_global,nsblocks,sub_block,bsize_elm,bsize_frm)
6526 [ # # ]: 0 : if (xmpio_max_address(tmp_off)) offset_err=1 ! Test for possible wraparounds.
6527 : 0 : max_displ = MAX(max_displ,tmp_off)
6528 : 0 : block_displ (el+1) = tmp_off
6529 : 0 : block_type (el+1) = mpi_type_elm
6530 : 0 : block_length(el+1) = 1
6531 : : !write(std_out,*)" iglob, jglob, tmp_off ",iglob, jglob, tmp_off
6532 : : end do
6533 : : !write(std_out,*)" MAX displ is ",MAXVAL(block_displ)
6534 : :
6535 [ # # ]: 0 : if (offset_err/=0) then ! just warn, let the caller handle the exception.
6536 : : write(msg,"(3a)")&
6537 : 0 : " Global position index cannot be stored in standard Fortran integer ",ch10,&
6538 : 0 : " scaLAPACK matrix cannot be read with a single MPI-IO call ."
6539 : 0 : ABI_WARNING(msg)
6540 : : end if
6541 : :
6542 : 0 : block_length(my_nel+2) = 1
6543 : 0 : block_displ (my_nel+2) = max_displ
6544 : 0 : block_type (my_nel+2) = MPI_UB
6545 : :
6546 : 0 : call xmpio_type_struct(my_nel+2,block_length,block_displ,block_type,slk_type,mpi_err)
6547 : 0 : ABI_CHECK_MPI(mpi_err,"MPI_type_STRUCT")
6548 : :
6549 : 0 : ABI_FREE(block_length)
6550 : 0 : ABI_FREE(block_displ)
6551 : 0 : ABI_FREE(block_type)
6552 : :
6553 : 0 : call MPI_type_COMMIT(slk_type,mpi_err)
6554 : 0 : ABI_CHECK_MPI(mpi_err,"MPI_type_COMMIT")
6555 : :
6556 : : #else
6557 : : ABI_ERROR("MPI-IO is mandatatory in slk_single_fview_read_mask")
6558 : : #endif
6559 : :
6560 : 0 : end subroutine slk_single_fview_read_mask
6561 : : !!***
6562 : :
6563 : : !----------------------------------------------------------------------
6564 : :
6565 : : !!****f* m_slk/slkmat_dp_symmetrize
6566 : : !! NAME
6567 : : !! slkmat_dp_symmetrize
6568 : : !!
6569 : : !! FUNCTION
6570 : : !! Symmetrize a square scaLAPACK matrix.
6571 : : !!
6572 : : !! INPUTS
6573 : : !! uplo=String specifying whether only the upper or lower triangular part of the global matrix has been read
6574 : : !! = "U": Upper triangular has been read.
6575 : : !! = "L": Lower triangular has been read.
6576 : : !! = "A": Full matrix (used for general complex matrices)
6577 : : !! symtype=Symmetry type of the matrix (used only if uplo = "L" or "A").
6578 : : !! = "H" for Hermitian matrix
6579 : : !! = "S" for symmetric matrix.
6580 : : !! = "N" if matrix has no symmetry (not compatible with uplo="L" or uplo="U".
6581 : : !!
6582 : : !! SIDE EFFECTS
6583 : : !! Slk_mat<slkmat_dp_t>=Structured datatype defining the scaLAPACK distribution with the local buffer
6584 : : !! supposed to be allocated.
6585 : : !! %buffer_cplx=Local buffer containg the distributed matrix stored on the external file.
6586 : : !!
6587 : : !! SOURCE
6588 : :
6589 : 0 : subroutine slkmat_dp_symmetrize(Slk_mat, uplo, symtype)
6590 : :
6591 : : !Arguments ------------------------------------
6592 : : !scalars
6593 : : class(slkmat_dp_t),intent(inout) :: Slk_mat
6594 : : character(len=*),intent(in) :: uplo, symtype
6595 : :
6596 : : !Local variables ------------------------------
6597 : : !scalars
6598 : : integer :: jloc,iloc,iglob,jglob,ij_loc
6599 : : logical :: is_hermitian,is_real,is_cplx,is_symmetric
6600 : : character(len=500) :: msg
6601 : : !************************************************************************
6602 : :
6603 : 0 : is_cplx = (allocated(Slk_mat%buffer_cplx))
6604 : 0 : is_real = (allocated(Slk_mat%buffer_real))
6605 : :
6606 : : ! One and only one buffer should be allocated.
6607 [ # # ]: 0 : if (is_real .and. is_cplx) then
6608 : 0 : write(msg,'(a,2l1)')" ScaLAPACK buffers are not allocated correctly, is_real, is_cplx ",is_real,is_cplx
6609 : 0 : ABI_ERROR(msg)
6610 : : end if
6611 : :
6612 [ # # ]: 0 : if (is_real) RETURN
6613 : :
6614 : 0 : is_hermitian=.FALSE.; is_symmetric=.FALSE.
6615 : : select case (symtype(1:1))
6616 : : case ("H", "h")
6617 : : is_hermitian = .TRUE.
6618 : : case ("S","s")
6619 : 0 : is_symmetric = .TRUE.
6620 : : case("N","n")
6621 [ # # # # : 0 : if (ALL(uplo(1:1) /= ["A","a"])) then
# # ]
6622 [ # # ]: 0 : msg = " Found symtype= "//TRIM(symtype)//", but uplo= "//TRIM(uplo)
6623 : 0 : ABI_ERROR(msg)
6624 : : end if
6625 : 0 : RETURN ! Nothing to do.
6626 : : case default
6627 [ # # # # : 0 : ABI_ERROR("Wrong symtype "//TRIM(symtype))
# # ]
6628 : : end select
6629 : :
6630 : : !write(std_out,*)"is_cplx",is_cplx
6631 : : !write(std_out,*)"is_hermitian",is_hermitian
6632 : :
6633 : : select case (uplo(1:1))
6634 : : case ("A","a")
6635 : : ! Full global matrix has been read, nothing to do.
6636 : 0 : return
6637 : :
6638 : : case ("U", "u")
6639 : : ! Only the upper triangle of the global matrix was read.
6640 [ # # # # ]: 0 : if (is_cplx .and. is_hermitian) then
6641 : 0 : ij_loc=0
6642 [ # # ]: 0 : do jloc=1,Slk_mat%size_local(2)
6643 [ # # ]: 0 : do iloc=1,Slk_mat%size_local(1)
6644 : 0 : call slk_mat%loc2glob(iloc, jloc, iglob, jglob)
6645 : 0 : ij_loc = ij_loc+1
6646 [ # # ]: 0 : if (jglob < iglob) then
6647 : : ! Diagonal elements are not forced to be real.
6648 : 0 : Slk_mat%buffer_cplx(iloc,jloc) = DCONJG(Slk_mat%buffer_cplx(iloc,jloc))
6649 : : end if
6650 : : !if (iglob==jglob) Slk_mat%buffer_cplx(iloc,jloc) = real(Slk_mat%buffer_cplx(iloc,jloc))
6651 : : end do
6652 : : end do
6653 : : end if
6654 : :
6655 : : case ("L", "l")
6656 : : ! Only the lower triangle of the global matrix was read.
6657 [ # # # # ]: 0 : if (is_cplx .and. is_hermitian) then
6658 : 0 : ij_loc=0
6659 [ # # ]: 0 : do jloc=1,Slk_mat%size_local(2)
6660 [ # # ]: 0 : do iloc=1,Slk_mat%size_local(1)
6661 : 0 : call slk_mat%loc2glob(iloc, jloc, iglob, jglob)
6662 : 0 : ij_loc = ij_loc+1
6663 [ # # ]: 0 : if (jglob>iglob) then ! diagonal elements are not forced to be real.
6664 : 0 : Slk_mat%buffer_cplx(iloc,jloc) = DCONJG(Slk_mat%buffer_cplx(iloc,jloc))
6665 : : end if
6666 : : !if (iglob==jglob) Slk_mat%buffer_cplx(iloc,jloc) = real(Slk_mat%buffer_cplx(iloc,jloc))
6667 : : end do
6668 : : end do
6669 : : end if
6670 : :
6671 : : case default
6672 [ # # # # : 0 : ABI_BUG(" Wrong uplo: "//TRIM(uplo))
# # ]
6673 : : end select
6674 : :
6675 : : end subroutine slkmat_dp_symmetrize
6676 : : !!***
6677 : :
6678 : : !----------------------------------------------------------------------
6679 : :
6680 : : !!****f* m_slk/slk_single_fview_read
6681 : : !! NAME
6682 : : !! slk_single_fview_read
6683 : : !!
6684 : : !! FUNCTION
6685 : : !! Return an MPI datatype that can be used to read a scaLAPACK distributed matrix from
6686 : : !! a binary file using MPI-IO.
6687 : : !!
6688 : : !! INPUTS
6689 : : !! Slk_mat<slkmat_dp_t>=Structured datatype defining the scaLAPACK distribution with the local buffer.
6690 : : !! uplo=String specifying whether only the upper or lower triangular part of the global matrix is stored on disk:
6691 : : !! = "U": Upper triangular is stored
6692 : : !! = "L": Lower triangular is stored
6693 : : !! = "A": Full matrix (used for general complex matrices)
6694 : : !! [is_fortran_file]=.FALSE. is C stream is used. .TRUE. for writing Fortran binary files
6695 : : !! with record markers. In this case etype is set xmpio_mpi_type_frm provided that
6696 : : !! the mpi_type of the matrix element is commensurate with xmpio_mpi_type_frm. Defaults to .TRUE.
6697 : : !!
6698 : : !! OUTPUT
6699 : : !! etype=Elementary data type (handle) defining the elementary unit used to access the file.
6700 : : !! slk_type=New MPI type that can be used to instantiate the MPI-IO view for the Fortran file.
6701 : : !! Note that the view assumes that the file pointer points to the FIRST Fortran record marker.
6702 : : !! offset_err=Error code. A non-zero value signals that the global matrix is too large
6703 : : !! for a single MPI-IO access (see notes below).
6704 : : !!
6705 : : !! NOTES
6706 : : !! With (signed) Fortran integers, the maximum size of the file that
6707 : : !! that can be read in one-shot is around 2Gb when etype is set to byte.
6708 : : !! Using a larger etype might create portability problems (real data on machines using
6709 : : !! integer*16 for the marker) since etype must be a multiple of the Fortran record marker
6710 : : !! Due to the above reason, block_displ is given in bytes and must be stored in a integer
6711 : : !! of kind XMPI_ADDRESS_KIND. If the displacement is too large, the routine returns
6712 : : !! offset_err=1 so that the caller will know that several MPI-IO reads are needed to
6713 : : !! read the local buffer.
6714 : : !!
6715 : : !! SOURCE
6716 : :
6717 : 0 : subroutine slk_single_fview_read(Slk_mat,uplo,etype,slk_type,offset_err,is_fortran_file)
6718 : :
6719 : : !Arguments ------------------------------------
6720 : : !scalars
6721 : : class(slkmat_dp_t),intent(in) :: Slk_mat
6722 : : integer,intent(out) :: offset_err,slk_type,etype
6723 : : character(len=*),intent(in) :: uplo
6724 : : logical,optional,intent(in) :: is_fortran_file
6725 : :
6726 : : !Local variables ------------------------------
6727 : : !scalars
6728 : : integer :: jloc,iloc,iglob,jglob,nrows_glob,ncols_glob,mpi_err,nel
6729 : : integer :: bsize_frm,mpi_type_elm,ij_loc,bsize_etype,bsize_elm
6730 : : integer(XMPI_OFFSET_KIND) :: ijp_glob,my_offset,cpad_frm
6731 : : !arrays
6732 : : character(len=500) :: msg
6733 : 0 : integer,allocatable :: block_length(:),block_type(:)
6734 : 0 : integer(XMPI_ADDRESS_KIND),allocatable :: block_displ(:)
6735 : : !************************************************************************
6736 : :
6737 : : #ifdef HAVE_MPI_IO
6738 : : !@slkmat_dp_t
6739 : 0 : bsize_frm = xmpio_bsize_frm ! Byte size of the Fortran record marker.
6740 [ # # ]: 0 : if (PRESENT(is_fortran_file)) then
6741 [ # # ]: 0 : if (.not.is_fortran_file) bsize_frm = 0
6742 : : end if
6743 : :
6744 : 0 : call slk_mat%bsize_and_type(bsize_elm, mpi_type_elm)
6745 : :
6746 : : ! Global dimensions.
6747 : 0 : nrows_glob=Slk_mat%size_global(1)
6748 : 0 : ncols_glob=Slk_mat%size_global(2)
6749 : :
6750 : : ! Number of matrix elements treated by this node.
6751 [ # # ]: 0 : nel = PRODUCT(Slk_mat%size_local(1:2))
6752 : :
6753 : : !Cannot use MPI_type_CREATE_INDEXED_BLOCK since it is not correctly implemented in several MPI libraries.
6754 : : !etype has to be set to MPI_BYTE, since the displacement in MPI structures is always in byte.
6755 : : ! ABI_WARNING("Using MPI_type_STRUCT for the MPI-IO file view")
6756 : :
6757 : 0 : etype = MPI_BYTE
6758 : 0 : call MPI_type_SIZE(etype,bsize_etype,mpi_err)
6759 : :
6760 : : ! Define the mapping between scaLAPACK buffer and the storage on file.
6761 [ # # # # : 0 : ABI_MALLOC(block_length, (nel+2))
# # # # #
# # # #
# ]
6762 [ # # # # : 0 : ABI_MALLOC(block_displ, (nel+2))
# # # # #
# # # ]
6763 [ # # # # : 0 : ABI_MALLOC(block_type, (nel+2))
# # # # ]
6764 : 0 : block_length(1)=1
6765 : 0 : block_displ (1)=0
6766 : 0 : block_type (1)=MPI_LB
6767 : :
6768 : : ! Note that the view assumes that the file pointer points to the first Fortran record marker.
6769 : 0 : offset_err=0
6770 : 0 : select case (uplo(1:1))
6771 : : case ("A","a")
6772 : : ! The entire global matrix is stored on disk.
6773 : : ! TODO can use contigous vectors for better access.
6774 : 0 : ij_loc=0
6775 [ # # ]: 0 : do jloc=1,Slk_mat%size_local(2)
6776 [ # # ]: 0 : do iloc=1,Slk_mat%size_local(1)
6777 : 0 : call slk_mat%loc2glob(iloc, jloc, iglob, jglob)
6778 : 0 : ij_loc = ij_loc+1
6779 : 0 : my_offset = 2*(jglob-1)*bsize_frm + bsize_frm + (jglob-1)*nrows_glob*bsize_elm + (iglob-1) * bsize_elm
6780 : 0 : my_offset = my_offset / bsize_etype
6781 [ # # ]: 0 : if (xmpio_max_address(my_offset)) offset_err=1 ! Test for possible wraparounds
6782 : 0 : block_displ (ij_loc+1) = my_offset
6783 : 0 : block_type (ij_loc+1) = mpi_type_elm
6784 : 0 : block_length(ij_loc+1) = 1
6785 : : end do
6786 : : end do
6787 : :
6788 : : case ("U","u")
6789 : : ! Only the upper triangle of the global matrix is stored on disk.
6790 : 0 : ij_loc=0
6791 [ # # ]: 0 : do jloc=1,Slk_mat%size_local(2)
6792 [ # # ]: 0 : do iloc=1,Slk_mat%size_local(1)
6793 : 0 : call slk_mat%loc2glob(iloc, jloc, iglob, jglob)
6794 [ # # ]: 0 : if (jglob>=iglob) then
6795 : 0 : ijp_glob = iglob + jglob*(jglob-1)/2 ! Index for packed form
6796 : 0 : cpad_frm = 2*(jglob-1)*bsize_frm
6797 : : else
6798 : 0 : ijp_glob = jglob + iglob*(iglob-1)/2 ! Index for packed form
6799 : 0 : cpad_frm = 2*(iglob-1)*bsize_frm
6800 : : end if
6801 : 0 : ij_loc = ij_loc+1
6802 : 0 : my_offset = cpad_frm + bsize_frm + (ijp_glob-1) * bsize_elm
6803 : 0 : my_offset = my_offset / bsize_etype
6804 [ # # ]: 0 : if (xmpio_max_address(my_offset)) offset_err=1 ! Test for possible wraparounds
6805 : 0 : block_displ (ij_loc+1) = my_offset
6806 : 0 : block_type (ij_loc+1) = mpi_type_elm
6807 : 0 : block_length(ij_loc+1) = 1
6808 : : end do
6809 : : end do
6810 : :
6811 : : case ("L","l")
6812 : : ! Only the lower triangle of the global matrix is stored on disk.
6813 : 0 : ij_loc=0
6814 [ # # ]: 0 : do jloc=1,Slk_mat%size_local(2)
6815 [ # # ]: 0 : do iloc=1,Slk_mat%size_local(1)
6816 : 0 : call slk_mat%loc2glob(iloc, jloc, iglob, jglob)
6817 [ # # ]: 0 : if (jglob<=iglob) then
6818 : 0 : ijp_glob = iglob + (jglob-1)*(2*nrows_glob-jglob)/2 ! Index for packed form
6819 : 0 : cpad_frm = 2*(jglob-1)*bsize_frm
6820 : : else
6821 : 0 : ijp_glob = jglob + (iglob-1)*(2*nrows_glob-iglob)/2 ! Index for packed form
6822 : 0 : cpad_frm = 2*(iglob-1)*bsize_frm
6823 : : end if
6824 : 0 : ij_loc = ij_loc+1
6825 : 0 : my_offset = cpad_frm + bsize_frm + (ijp_glob-1) * bsize_elm
6826 : 0 : my_offset = my_offset / bsize_etype
6827 [ # # ]: 0 : if (xmpio_max_address(my_offset)) offset_err=1 ! block_displ is usually integer*4. Test for possible wraparounds
6828 : 0 : block_displ (ij_loc+1) = my_offset
6829 : 0 : block_type (ij_loc+1) = mpi_type_elm
6830 : 0 : block_length(ij_loc+1) = 1
6831 : : end do
6832 : : end do
6833 : :
6834 [ # # ]: 0 : if (offset_err/=0) then ! just warn, let the caller handle the exception.
6835 : : write(msg,"(3a)")&
6836 : 0 : " Global position index cannot be stored in standard Fortran integer ",ch10,&
6837 : 0 : " scaLAPACK matrix cannot be read with a single MPI-IO call ."
6838 : 0 : ABI_WARNING(msg)
6839 : : end if
6840 : :
6841 : : case default
6842 [ # # # # : 0 : ABI_BUG(" Wrong uplo: "//TRIM(uplo))
# # ]
6843 : : end select
6844 : :
6845 : 0 : block_length(nel+2)= 1
6846 : 0 : block_displ (nel+2)= ncols_glob * (nrows_glob*bsize_elm + 2*bsize_frm) / bsize_etype
6847 : 0 : block_type (nel+2)= MPI_UB
6848 : :
6849 : 0 : call xmpio_type_struct(nel+2,block_length,block_displ,block_type,slk_type,mpi_err)
6850 : 0 : ABI_CHECK_MPI(mpi_err,"MPI_type_STRUCT")
6851 : :
6852 : 0 : ABI_FREE(block_length)
6853 : 0 : ABI_FREE(block_displ)
6854 : 0 : ABI_FREE(block_type)
6855 : :
6856 : 0 : call MPI_type_COMMIT(slk_type,mpi_err)
6857 : 0 : ABI_CHECK_MPI(mpi_err,"MPI_type_COMMIT")
6858 : :
6859 : : #else
6860 : : ABI_ERROR("MPI-IO is mandatatory in slk_single_fview_read")
6861 : : #endif
6862 : :
6863 : 0 : end subroutine slk_single_fview_read
6864 : : !!***
6865 : :
6866 : : !----------------------------------------------------------------------
6867 : :
6868 : : !!****f* m_slk/slk_single_fview_write
6869 : : !! NAME
6870 : : !! slk_single_fview_write
6871 : : !!
6872 : : !! FUNCTION
6873 : : !! Returns an MPI datatype that can be used to write a scaLAPACK distributed matrix to
6874 : : !! a binary file using MPI-IO.
6875 : : !!
6876 : : !! INPUTS
6877 : : !! Slk_mat<slkmat_dp_t>=Structured datatype defining the scaLAPACK distribution with the local buffer.
6878 : : !! uplo=String specifying whether only the upper or lower triangular part of the global matrix is stored on disk:
6879 : : !! = "U": Upper triangular is stored
6880 : : !! = "L": Lower triangular is stored
6881 : : !! = "A": Full matrix (used for general complex matrices)
6882 : : !! [is_fortran_file]=.FALSE. is C stream is used. .TRUE. for writing Fortran binary files
6883 : : !! with record marker. In this case etype is set xmpio_mpi_type_frm provided that
6884 : : !! the mpi_type of the matrix element is commensurate with xmpio_mpi_type_frm. Defaults to .TRUE.
6885 : : !! glob_subarray(2,2) = Used to select the subarray of the global matrix. Used only when uplo="All"
6886 : : !! glob_subarray(:,1)=starting global coordinates of the subarray in each dimension
6887 : : !! (array of nonnegative integers >=1, <=array_of_sizes)
6888 : : !! glob_subarray(:,2)=Number of elements in each dimension of the subarray (array of positive integers)
6889 : : !!
6890 : : !! OUTPUT
6891 : : !! nelw=Number of elements to be written.
6892 : : !! etype=Elementary data type (handle) defining the elementary unit used to access the file.
6893 : : !! slk_type=New MPI type that can be used to instantiate the MPI-IO view for the Fortran file.
6894 : : !! Note that the view assumes that the file pointer points to the FIRST Fortran record marker.
6895 : : !! offset_err=Error code. A non-zero value signals that the global matrix is too large
6896 : : !! for a single MPI-IO access (see notes below).
6897 : : !!
6898 : : !! SIDE EFFECTS
6899 : : !! elw2slk(:,:) =
6900 : : !! input: pointer to null().
6901 : : !! output: elw2slk(2,nelw) contains the local coordinates of the matrix elements to be written.
6902 : : !! (useful only if the upper or lower triangle of the global matrix has to be written or when
6903 : : !! uplo="all" but a global subarray is written.
6904 : : !!
6905 : : !! NOTES
6906 : : !! With (signed) Fortran integers, the maximum size of the file that
6907 : : !! that can be read in one-shot is around 2Gb when etype is set to byte.
6908 : : !! Using a larger etype might create portability problems (real data on machines using
6909 : : !! integer*16 for the marker) since etype must be a multiple of the Fortran record marker
6910 : : !! Due to the above reason, block_displ is given in bytes and must be stored in a Fortran
6911 : : !! integer of kind XMPI_ADDRESS_KIND. If the displacement is too large, the routine returns
6912 : : !! offset_err=1 so that the caller will know that several MPI-IO reads are needed to
6913 : : !! write the local buffer.
6914 : : !!
6915 : : !! SOURCE
6916 : :
6917 : 0 : subroutine slk_single_fview_write(Slk_mat,uplo,nelw,elw2slk,etype,slk_type,offset_err,is_fortran_file,glob_subarray)
6918 : :
6919 : : !Arguments ------------------------------------
6920 : : !scalars
6921 : : class(slkmat_dp_t),intent(in) :: Slk_mat
6922 : : integer,intent(out) :: offset_err,slk_type,etype,nelw
6923 : : character(len=*),intent(in) :: uplo
6924 : : logical,optional,intent(in) :: is_fortran_file
6925 : : !arrays
6926 : : integer,pointer :: elw2slk(:,:)
6927 : : integer,optional,intent(in) :: glob_subarray(2,2)
6928 : :
6929 : : !Local variables ------------------------------
6930 : : !scalars
6931 : : integer :: jloc,iloc,iglob,jglob,nrows_glob,ncols_glob,mpi_err,nel_max
6932 : : integer :: grow_min,grow_max,gcol_min,gcol_max
6933 : : integer :: bsize_frm,mpi_type_elm,ij_loc,bsize_elm
6934 : : integer(XMPI_OFFSET_KIND) :: ijp_glob,my_offset,cpad_frm
6935 : : !arrays
6936 : : character(len=500) :: msg
6937 : 0 : integer,allocatable :: block_length(:),block_type(:)
6938 : 0 : integer(XMPI_ADDRESS_KIND),allocatable :: block_displ(:)
6939 : : !************************************************************************
6940 : :
6941 : : #ifdef HAVE_MPI_IO
6942 : : !@slkmat_dp_t
6943 : 0 : bsize_frm = xmpio_bsize_frm ! Byte size of the Fortran record marker.
6944 [ # # ]: 0 : if (PRESENT(is_fortran_file)) then
6945 [ # # ]: 0 : if (.not.is_fortran_file) bsize_frm = 0
6946 : : end if
6947 : :
6948 [ # # # # : 0 : if (PRESENT(glob_subarray).and..not.firstchar(uplo, ["A"])) then
# # ]
6949 : 0 : ABI_ERROR("glob_subarray should not be used when uplo/=All")
6950 : : end if
6951 : :
6952 : 0 : call slk_mat%bsize_and_type(bsize_elm, mpi_type_elm)
6953 : :
6954 : : ! Global dimensions.
6955 : 0 : nrows_glob=Slk_mat%size_global(1)
6956 : 0 : ncols_glob=Slk_mat%size_global(2)
6957 : :
6958 : : ! Number of matrix elements treated by this node.
6959 [ # # ]: 0 : nel_max = PRODUCT(Slk_mat%size_local(1:2))
6960 : :
6961 [ # # # # : 0 : ABI_MALLOC(elw2slk,(2,nel_max))
# # # # #
# # # ]
6962 [ # # # # ]: 0 : elw2slk=0
6963 : :
6964 : : ! Cannot use MPI_type_CREATE_INDEXED_BLOCK since it is not correctly implemented in several MPI libraries.
6965 : : ! etype has to be set to MPI_BYTE, since the displacement in MPI structures is always in byte.
6966 : 0 : etype = MPI_BYTE
6967 : :
6968 : : ! Define the mapping between scaLAPACK buffer and the storage on file.
6969 [ # # # # : 0 : ABI_MALLOC(block_length, (nel_max+2))
# # # # #
# # # #
# ]
6970 [ # # # # : 0 : ABI_MALLOC(block_displ, (nel_max+2))
# # # # #
# # # ]
6971 [ # # # # : 0 : ABI_MALLOC(block_type, (nel_max+2))
# # # # ]
6972 : 0 : block_length(1)=1
6973 : 0 : block_displ (1)=0
6974 : 0 : block_type (1)=MPI_LB
6975 : :
6976 : : ! Note that the view assumes that the file pointer points to the first Fortran record marker.
6977 : 0 : offset_err=0
6978 : :
6979 : 0 : select case (uplo(1:1))
6980 : : case ("A","a")
6981 : : ! The entire global matrix is written on disk. TODO can use contigous vectors for better access.
6982 : 0 : grow_min=1; grow_max=nrows_glob
6983 : 0 : gcol_min=1; gcol_max=ncols_glob
6984 [ # # ]: 0 : if (PRESENT(glob_subarray)) then ! subarray access.
6985 : 0 : grow_min = glob_subarray(1,1)
6986 : 0 : gcol_min = glob_subarray(2,1)
6987 : 0 : grow_max = grow_min + glob_subarray(1,2) -1
6988 : 0 : gcol_max = gcol_min + glob_subarray(2,2) -1
6989 : : end if
6990 : :
6991 : 0 : ij_loc=0
6992 [ # # ]: 0 : do jloc=1,Slk_mat%size_local(2)
6993 [ # # ]: 0 : do iloc=1,Slk_mat%size_local(1)
6994 : 0 : call slk_mat%loc2glob(iloc, jloc, iglob, jglob)
6995 : : if (iglob>=grow_min.and.iglob<=grow_max .and. & ! glob_subarray element.
6996 [ # # # # : 0 : jglob>=gcol_min.and.jglob<=gcol_max) then
# # # # ]
6997 : 0 : ij_loc = ij_loc+1
6998 : 0 : my_offset = 2*(jglob-1)*bsize_frm + bsize_frm + (jglob-1)*nrows_glob*bsize_elm + (iglob-1) * bsize_elm
6999 [ # # ]: 0 : if (xmpio_max_address(my_offset)) offset_err=1 ! Test for possible wraparounds
7000 : 0 : block_displ (ij_loc+1) = my_offset
7001 : 0 : block_type (ij_loc+1) = mpi_type_elm
7002 : 0 : block_length(ij_loc+1) = 1
7003 [ # # ]: 0 : elw2slk(:,ij_loc) = (/iloc,jloc/) ! useless when subarray are not used but oh well!
7004 : : end if
7005 : : end do
7006 : : end do
7007 : :
7008 : : case ("U","u")
7009 : : ! Only the upper triangle of the global matrix is stored on disk.
7010 : 0 : ij_loc=0
7011 [ # # ]: 0 : do jloc=1,Slk_mat%size_local(2)
7012 [ # # ]: 0 : do iloc=1,Slk_mat%size_local(1)
7013 : 0 : call slk_mat%loc2glob(iloc, jloc, iglob, jglob)
7014 [ # # ]: 0 : if (jglob>=iglob) then
7015 : 0 : ijp_glob = iglob + jglob*(jglob-1)/2 ! Index for packed form
7016 : 0 : cpad_frm = 2*(jglob-1)*bsize_frm
7017 : 0 : ij_loc = ij_loc+1
7018 : 0 : my_offset = cpad_frm + bsize_frm + (ijp_glob-1) * bsize_elm
7019 [ # # ]: 0 : if (xmpio_max_address(my_offset)) offset_err=1 ! Test for possible wraparounds
7020 : 0 : block_displ (ij_loc+1) = my_offset
7021 : 0 : block_type (ij_loc+1) = mpi_type_elm
7022 : 0 : block_length(ij_loc+1) = 1
7023 [ # # ]: 0 : elw2slk(:,ij_loc) = (/iloc,jloc/)
7024 : : end if
7025 : : end do
7026 : : end do
7027 : :
7028 : : case ("L","l")
7029 : : ! Only the lower triangle of the global matrix is stored on disk.
7030 : 0 : ij_loc=0
7031 [ # # ]: 0 : do jloc=1,Slk_mat%size_local(2)
7032 [ # # ]: 0 : do iloc=1,Slk_mat%size_local(1)
7033 : 0 : call slk_mat%loc2glob(iloc, jloc, iglob, jglob)
7034 [ # # ]: 0 : if (jglob<=iglob) then
7035 : 0 : ijp_glob = iglob + (jglob-1)*(2*nrows_glob-jglob)/2 ! Index for packed form
7036 : 0 : cpad_frm = 2*(jglob-1)*bsize_frm
7037 : 0 : ij_loc = ij_loc+1
7038 : 0 : my_offset = cpad_frm + bsize_frm + (ijp_glob-1) * bsize_elm
7039 [ # # ]: 0 : if (xmpio_max_address(my_offset)) offset_err=1 ! block_displ is usually integer*4. Test for possible wraparounds
7040 : 0 : block_displ (ij_loc+1) = my_offset
7041 : 0 : block_type (ij_loc+1) = mpi_type_elm
7042 : 0 : block_length(ij_loc+1) = 1
7043 [ # # ]: 0 : elw2slk(:,ij_loc) = (/iloc,jloc/)
7044 : : end if
7045 : : end do
7046 : : end do
7047 : :
7048 : : case default
7049 [ # # # # : 0 : ABI_BUG(" Wrong uplo: "//TRIM(uplo))
# # ]
7050 : : end select
7051 : :
7052 [ # # ]: 0 : if (offset_err/=0) then ! just warn, let the caller handle the exception.
7053 : : write(msg,"(3a)")&
7054 : 0 : "Global position index cannot be stored in standard Fortran integer ",ch10,&
7055 : 0 : "scaLAPACK matrix cannot be read with a single MPI-IO call ."
7056 : 0 : ABI_WARNING(msg)
7057 : : end if
7058 : :
7059 : : ! Final number of matrix elements that will be written by this node.
7060 : 0 : nelw = ij_loc
7061 : :
7062 : 0 : block_length(nelw+2)= 1
7063 : 0 : block_displ (nelw+2)= ncols_glob * (nrows_glob*bsize_elm + 2*bsize_frm)
7064 : 0 : block_type (nelw+2)= MPI_UB
7065 : :
7066 : 0 : call xmpio_type_struct(nelw+2,block_length,block_displ,block_type,slk_type,mpi_err)
7067 : 0 : ABI_CHECK_MPI(mpi_err, "MPI_type_STRUCT")
7068 : :
7069 : 0 : ABI_FREE(block_length)
7070 : 0 : ABI_FREE(block_displ)
7071 : 0 : ABI_FREE(block_type)
7072 : :
7073 : 0 : call MPI_type_COMMIT(slk_type,mpi_err)
7074 : 0 : ABI_CHECK_MPI(mpi_err, "MPI_type_COMMIT")
7075 : :
7076 : : #else
7077 : : ABI_ERROR("MPI-IO is mandatatory in slk_single_fview_read")
7078 : : #endif
7079 : :
7080 : 0 : end subroutine slk_single_fview_write
7081 : : !!***
7082 : :
7083 : : !----------------------------------------------------------------------
7084 : :
7085 : : !!****f* m_slk/slkmat_dp_bsize_and_type
7086 : : !! NAME
7087 : : !! slkmat_dp_bsize_and_type
7088 : : !!
7089 : : !! FUNCTION
7090 : : !! Returns the byte size and the MPI datatype associated to the matrix elements
7091 : : !! that are stored in the ScaLAPACK_matrix
7092 : : !!
7093 : : !! INPUTS
7094 : : !! Slk_mat<slkmat_dp_t>=Structured datatype defining the scaLAPACK distribution with the local buffer
7095 : : !!
7096 : : !! OUTPUT
7097 : : !! bsize_elm=Byte size of the matrix element.
7098 : : !! mpi_type_elm=MPI datatype of the matrix element.
7099 : : !!
7100 : : !! SOURCE
7101 : :
7102 : 0 : subroutine slkmat_dp_bsize_and_type(Slk_mat, bsize_elm, mpi_type_elm)
7103 : :
7104 : : !Arguments ------------------------------------
7105 : : !scalars
7106 : : class(slkmat_dp_t),intent(in) :: Slk_mat
7107 : : integer,intent(out) :: bsize_elm,mpi_type_elm
7108 : :
7109 : : !Local variables ------------------------------
7110 : : !scalars
7111 : : integer :: ierr
7112 : : character(len=500) :: msg
7113 : : ! ************************************************************************
7114 : :
7115 : 0 : ierr=0
7116 : : #ifdef HAVE_MPI
7117 [ # # ]: 0 : if (allocated(Slk_mat%buffer_cplx)) then
7118 : 0 : ierr = ierr + 1
7119 : 0 : mpi_type_elm = MPI_DOUBLE_COMPLEX
7120 : 0 : bsize_elm = xmpi_bsize_dpc
7121 : : end if
7122 : :
7123 [ # # ]: 0 : if (allocated(Slk_mat%buffer_real)) then
7124 : 0 : ierr = ierr + 1
7125 : 0 : mpi_type_elm = MPI_DOUBLE_PRECISION
7126 : 0 : bsize_elm = xmpi_bsize_dp
7127 : : end if
7128 : : #endif
7129 : :
7130 : : ! One and only one buffer should be allocated.
7131 [ # # ]: 0 : if (ierr /= 1) then
7132 : 0 : write(msg,'(a,i0)')" ScaLAPACK buffers are not allocated correctly, ierr= ",ierr
7133 : 0 : ABI_ERROR(msg)
7134 : : end if
7135 : :
7136 : 0 : end subroutine slkmat_dp_bsize_and_type
7137 : : !!***
7138 : :
7139 : : !----------------------------------------------------------------------
7140 : :
7141 : : !!****f* m_slk/slkmat_sp_svd
7142 : : !! NAME
7143 : : !! slkmat_sp_svd
7144 : : !!
7145 : : !! FUNCTION
7146 : : !! Compute Singular Value Decomposition of matrix in_mat (single precision version).
7147 : : !!
7148 : : !! SIDE EFFECTS
7149 : : !! in_mat: matrix is destroyed in output.
7150 : : !!
7151 : : !! SOURCE
7152 : :
7153 [ # # # # ]: 0 : subroutine slkmat_sp_svd(in_mat, jobu, jobvt, u_mat, s_vals, vt_mat)
7154 : :
7155 : : !Arguments ------------------------------------
7156 : : class(slkmat_sp_t),intent(inout) :: in_mat
7157 : : character(len=1),intent(in) :: jobu, jobvt
7158 : : class(slkmat_sp_t),intent(out) :: u_mat, vt_mat
7159 : : real(sp),allocatable, intent(out) :: s_vals(:)
7160 : :
7161 : : #ifdef HAVE_LINALG_SCALAPACK
7162 : : !Local variables ------------------------------
7163 : : !scalars
7164 : : integer :: info, lwork, lrwork, isize, mm, nn
7165 : : !array
7166 : : real(sp),allocatable :: rwork_sp(:)
7167 : : complex(sp),allocatable :: cwork_sp(:)
7168 : : !************************************************************************
7169 : :
7170 : : if (in_mat%desc(MB_) /= in_mat%desc(NB_)) then
7171 : : ABI_ERROR("PCGESVD requires square block decomposition i.e MB_A = NB_A.")
7172 : : end if
7173 : :
7174 : : mm = in_mat%size_global(1); nn = in_mat%size_global(2); isize = min(mm, nn)
7175 : :
7176 : : ! Allocate singular values and output matrices.
7177 : :
7178 : : ABI_CALLOC(s_vals, (isize))
7179 : : if (jobu == "V") call u_mat%init(mm, isize, in_mat%processor, in_mat%istwf_k)
7180 : : if (jobvt == "V") call vt_mat%init(isize, nn, in_mat%processor, in_mat%istwf_k)
7181 : :
7182 : : if (allocated(in_mat%buffer_cplx)) then
7183 : : ! Query optimal workspace size
7184 : : lwork = -1
7185 : : ABI_MALLOC(cwork_sp, (1))
7186 : : ABI_MALLOC(rwork_sp, (1))
7187 : :
7188 : : call PCGESVD(jobu, jobvt, &
7189 : : mm, nn, in_mat%buffer_cplx, 1, 1, in_mat%desc, s_vals, &
7190 : : u_mat%buffer_cplx, 1, 1, u_mat%desc, &
7191 : : vt_mat%buffer_cplx, 1, 1, vt_mat%desc, &
7192 : : cwork_sp, lwork, rwork_sp, info)
7193 : :
7194 : : ABI_CHECK(info == 0, sjoin("CZGESVD returned info:", itoa(info)))
7195 : :
7196 : : ! Allocate optimal workspace
7197 : : lwork = nint(real(cwork_sp(1)))
7198 : : lrwork = nint(rwork_sp(1))
7199 : : ABI_FREE(cwork_sp)
7200 : : ABI_FREE(rwork_sp)
7201 : :
7202 : : ABI_MALLOC(cwork_sp, (lwork))
7203 : : ABI_MALLOC(rwork_sp, (lrwork))
7204 : :
7205 : : ! Perform SVD
7206 : : call PCGESVD(jobu, jobvt, &
7207 : : mm, nn, in_mat%buffer_cplx, 1, 1, in_mat%desc, s_vals, &
7208 : : u_mat%buffer_cplx, 1, 1, u_mat%desc, &
7209 : : vt_mat%buffer_cplx, 1, 1, vt_mat%desc, &
7210 : : cwork_sp, lwork, rwork_sp, info)
7211 : :
7212 : : ABI_FREE(cwork_sp)
7213 : : ABI_FREE(rwork_sp)
7214 : : ABI_CHECK(info == 0, sjoin("PCGESVD returned info:", itoa(info)))
7215 : :
7216 : : else if (allocated(in_mat%buffer_real)) then
7217 : : ABI_ERROR("SVD for real matrices not coded!")
7218 : : else
7219 : : ABI_ERROR("Neither complex nor real buffer are allocated!")
7220 : : end if
7221 : : #endif
7222 : :
7223 : 0 : end subroutine slkmat_sp_svd
7224 : : !!***
7225 : :
7226 : : !----------------------------------------------------------------------
7227 : :
7228 : : !!****f* m_slk/slkmat_dp_svd
7229 : : !! NAME
7230 : : !! slkmat_dp_svd
7231 : : !!
7232 : : !! FUNCTION
7233 : : !! Compute Singular Value Decomposition of matrix in_mat (double precision version).
7234 : : !!
7235 : : !! SIDE EFFECTS
7236 : : !! in_mat: matrix is destroyed in output.
7237 : : !!
7238 : : !! SOURCE
7239 : :
7240 [ # # # # ]: 0 : subroutine slkmat_dp_svd(in_mat, jobu, jobvt, u_mat, s_vals, vt_mat)
7241 : :
7242 : : !Arguments ------------------------------------
7243 : : class(slkmat_dp_t),intent(inout) :: in_mat
7244 : : character(len=1),intent(in) :: jobu, jobvt
7245 : : class(slkmat_dp_t),intent(out) :: u_mat, vt_mat
7246 : : real(dp),allocatable, intent(out) :: s_vals(:)
7247 : :
7248 : : #ifdef HAVE_LINALG_SCALAPACK
7249 : : !Local variables ------------------------------
7250 : : !scalars
7251 : : integer :: info, lwork, lrwork, isize, mm, nn
7252 : : !array
7253 : : real(dp),allocatable :: rwork_dp(:)
7254 : : complex(dp),allocatable :: cwork_dp(:)
7255 : : !************************************************************************
7256 : :
7257 : : if (in_mat%desc(MB_) /= in_mat%desc(NB_)) then
7258 : : ABI_ERROR("PZGESVD requires square block decomposition i.e MB_A = NB_A.")
7259 : : end if
7260 : :
7261 : : mm = in_mat%size_global(1); nn = in_mat%size_global(2); isize = min(mm, nn)
7262 : :
7263 : : ! Allocate singular values and output matrices.
7264 : : ABI_CALLOC(s_vals, (isize))
7265 : :
7266 : : if (jobu == "V") call u_mat%init(mm, isize, in_mat%processor, in_mat%istwf_k)
7267 : : if (jobvt == "V") call vt_mat%init(isize, nn, in_mat%processor, in_mat%istwf_k)
7268 : :
7269 : : if (allocated(in_mat%buffer_cplx)) then
7270 : : ! Query optimal workspace size
7271 : : lwork = -1
7272 : : ABI_MALLOC(cwork_dp, (1))
7273 : : ABI_MALLOC(rwork_dp, (1))
7274 : :
7275 : : call PZGESVD(jobu, jobvt, &
7276 : : mm, nn, in_mat%buffer_cplx, 1, 1, in_mat%desc, s_vals, &
7277 : : u_mat%buffer_cplx, 1, 1, u_mat%desc, &
7278 : : vt_mat%buffer_cplx, 1, 1, vt_mat%desc, &
7279 : : cwork_dp, lwork, rwork_dp, info)
7280 : :
7281 : : ABI_CHECK(info == 0, sjoin("CZGESVD returned info:", itoa(info)))
7282 : :
7283 : : ! Allocate optimal workspace
7284 : : lwork = nint(real(cwork_dp(1)))
7285 : : lrwork = nint(rwork_dp(1))
7286 : : ABI_FREE(cwork_dp)
7287 : : ABI_FREE(rwork_dp)
7288 : :
7289 : : ABI_MALLOC(cwork_dp, (lwork))
7290 : : ABI_MALLOC(rwork_dp, (lrwork))
7291 : :
7292 : : ! Perform SVD
7293 : : call PZGESVD(jobu, jobvt, &
7294 : : mm, nn, in_mat%buffer_cplx, 1, 1, in_mat%desc, s_vals, &
7295 : : u_mat%buffer_cplx, 1, 1, u_mat%desc, &
7296 : : vt_mat%buffer_cplx, 1, 1, vt_mat%desc, &
7297 : : cwork_dp, lwork, rwork_dp, info)
7298 : :
7299 : : ABI_FREE(cwork_dp)
7300 : : ABI_FREE(rwork_dp)
7301 : : ABI_CHECK(info == 0, sjoin("CZGESVD returned info:", itoa(info)))
7302 : :
7303 : : else if (allocated(in_mat%buffer_real)) then
7304 : : ABI_ERROR("SVD for real matrices not coded!")
7305 : : else
7306 : : ABI_ERROR("Neither complex nor real buffer are allocated!")
7307 : : end if
7308 : : #endif
7309 : :
7310 : 0 : end subroutine slkmat_dp_svd
7311 : : !!***
7312 : :
7313 [ # # # # : 0 : end module m_slk
# # # # #
# # # # #
# # # # #
# # # #
# ]
7314 : : !!***
|