Branch data Line data Source code
1 : : !!****m* ABINIT/m_invovl
2 : : !! NAME
3 : : !! m_invovl
4 : : !!
5 : : !! FUNCTION
6 : : !! Provides functions to invert the overlap matrix S. Used by Chebyshev in PAW
7 : : !! See paper by A. Levitt and M. Torrent for details
8 : : !! S = 1 + projs * s_projs * projs'
9 : : !! S^-1 = 1 + projs * inv_s_projs * projs', with
10 : : !! inv_s_projs = - (s_projs^-1 + projs'*projs)^-1
11 : : !!
12 : : !! COPYRIGHT
13 : : !! Copyright (C) 2013-2026 ABINIT group (AL)
14 : : !! This file is distributed under the terms of the
15 : : !! GNU General Public License, see ~abinit/COPYING
16 : : !! or http://www.gnu.org/copyleft/gpl.txt .
17 : : !!
18 : : !! SOURCE
19 : :
20 : : #if defined HAVE_CONFIG_H
21 : : #include "config.h"
22 : : #endif
23 : :
24 : : #include "abi_common.h"
25 : :
26 : : ! nvtx related macro definition
27 : : #include "nvtx_macros.h"
28 : :
29 : : MODULE m_invovl
30 : :
31 : : use defs_basis
32 : : use m_errors
33 : : use m_xmpi
34 : : use m_xomp
35 : : use m_abicore
36 : : use m_abi_linalg
37 : :
38 : : use defs_abitypes, only : mpi_type
39 : : use m_time, only : timab
40 : : use m_hamiltonian, only : gs_hamiltonian_type
41 : : use m_bandfft_kpt, only : bandfft_kpt_get_ikpt
42 : : use m_pawcprj, only : pawcprj_type, pawcprj_alloc, pawcprj_free, pawcprj_axpby
43 : : use m_gemm_nonlop_projectors, only : gemm_nonlop_use_gemm
44 : : use m_nonlop, only : nonlop
45 : : use m_prep_kgb, only : prep_nonlop
46 : :
47 : : #ifdef HAVE_FC_ISO_C_BINDING
48 : : ! FIXME Don't know what's wrong with GCC when OpenMP GPU Offload is enabled here...
49 : : #ifdef FC_GNU
50 : : use, intrinsic :: iso_c_binding, only : c_int32_t, c_int64_t, c_float, c_double, c_size_t, c_loc
51 : : #else
52 : : use, intrinsic :: iso_c_binding, only : c_ptr, c_int32_t, c_int64_t, c_float, c_double, c_size_t, c_loc
53 : : #endif
54 : : #endif
55 : :
56 : : #if defined(HAVE_GPU_MARKERS)
57 : : use m_nvtx_data
58 : : #endif
59 : :
60 : : #ifdef HAVE_GPU
61 : : use m_gputk
62 : : #endif
63 : :
64 : : #ifdef HAVE_KOKKOS
65 : : use m_manage_kokkos, only : add_array_kokkos
66 : : #endif
67 : :
68 : : implicit none
69 : :
70 : : private
71 : :
72 : : !public procedures.
73 : : public :: init_invovl
74 : : public :: make_invovl
75 : : public :: apply_invovl
76 : : public :: destroy_invovl
77 : :
78 : : ! Those routines are here to assess memory requirements
79 : : public :: invovl_ompgpu_work_mem
80 : : public :: invovl_ompgpu_static_mem
81 : : !!***
82 : :
83 : : !!****t* m_invovl/invovl_kpt_type
84 : : !! NAME
85 : : !! invovl_kpt_type
86 : : !!
87 : : !! FUNCTION
88 : : !! Contains information needed to invert the overlap matrix S
89 : : !!
90 : : !! SOURCE
91 : :
92 : : #if defined(HAVE_FC_ISO_C_BINDING) && defined(HAVE_GPU_CUDA)
93 : :
94 : : type, public :: invovl_kpt_type
95 : :
96 : : integer(kind=c_int32_t) :: nprojs
97 : : ! total number of projectors
98 : : ! nlmn for a specific atom = count(indlmn(3,:,itypat)>0)
99 : : ! A value of -1 means that the following arrays are not allocated
100 : :
101 : : real(kind=c_double), allocatable :: gram_projs(:,:,:)
102 : : ! gram_projs(cplx, nprojs, nprojs)
103 : : ! projs' * projs
104 : :
105 : : real(kind=c_double), allocatable :: inv_sij(:,:,:,:)
106 : : ! inv_sij(cplx, lmnmax, lmnmax, ntypat)
107 : : ! inverse of ham%sij
108 : :
109 : : real(kind=c_double), allocatable :: inv_s_approx(:,:,:,:)
110 : : ! inv_s_approx(cplx, lmnmax, lmnmax, ntypat)
111 : : ! preconditionner
112 : :
113 : : end type invovl_kpt_type
114 : :
115 : : !> companion type to invovl_kpt_type to pass data to gpu/cuda
116 : : type, bind(c), public :: invovl_kpt_gpu_type
117 : :
118 : : integer(kind=c_int32_t) :: nprojs
119 : : ! total number of projectors
120 : : ! nlmn for a specific atom = count(indlmn(3,:,itypat)>0)
121 : : ! A value of -1 means that the following arrays are not allocated
122 : :
123 : : type(c_ptr) :: gram_projs
124 : : ! gram_projs(cplx, nprojs, nprojs)
125 : : ! projs' * projs
126 : :
127 : : integer(kind=c_int32_t) :: gram_projs_dim(3)
128 : :
129 : : type(c_ptr) :: inv_sij
130 : : ! inv_sij(cplx, lmnmax, lmnmax, ntypat)
131 : : ! inverse of ham%sij
132 : :
133 : : integer(kind=c_int32_t) :: inv_sij_dim(4)
134 : :
135 : : type(c_ptr) :: inv_s_approx
136 : : ! inv_s_approx(cplx, lmnmax, lmnmax, ntypat)
137 : : ! preconditionner
138 : :
139 : : integer(kind=c_int32_t) :: inv_s_approx_dim(4)
140 : :
141 : : end type invovl_kpt_gpu_type
142 : :
143 : : #else
144 : :
145 : : type, public :: invovl_kpt_type
146 : :
147 : : integer :: nprojs
148 : : ! total number of projectors
149 : : ! nlmn for a specific atom = count(indlmn(3,:,itypat)>0)
150 : : ! A value of -1 means that the following arrays are not allocated
151 : :
152 : : real(dp), allocatable :: gram_projs(:,:,:)
153 : : ! gram_projs(cplx, nprojs, nprojs)
154 : : ! projs' * projs
155 : :
156 : : real(dp), allocatable :: inv_sij(:,:,:,:)
157 : : ! inv_sij(cplx, lmnmax, lmnmax, ntypat)
158 : : ! inverse of ham%sij
159 : :
160 : : real(dp), allocatable :: inv_s_approx(:,:,:,:)
161 : : ! inv_s_approx(cplx, lmnmax, lmnmax, ntypat)
162 : : ! preconditionner
163 : :
164 : : end type invovl_kpt_type
165 : :
166 : : #endif
167 : :
168 : : !!***
169 : :
170 : : integer, parameter :: tim_nonlop = 13
171 : :
172 : : integer, parameter :: &
173 : : & timer_apply_inv_ovl_opernla = 1630, &
174 : : & timer_apply_inv_ovl_opernlb = 1631, &
175 : : & timer_apply_inv_ovl_inv_s = 1632
176 : :
177 : : type(invovl_kpt_type), public,save,allocatable, target :: invovl_kpt(:)
178 : : #ifdef HAVE_OPENMP_OFFLOAD
179 : : !Module variable keeping track of which K-point data is so=tored on GPU
180 : : integer, save :: current_ikpt_in_gpu=-1
181 : : #endif
182 : :
183 : : #if defined(HAVE_GPU_CUDA)
184 : :
185 : : !> this interface is only useful when gpu is enabled
186 : : !! these functions are defined in 46_manage_gpu/gpu_apply_invovl_inner.cu
187 : : !! these functions are entry point for calling cuda implemented functions
188 : : interface
189 : :
190 : : !> allocate GPU workspace for apply_invovl
191 : : subroutine f_gpu_apply_invovl_inner_alloc(proj_dim, ntypat, realloc) bind(c, name='gpu_apply_invovl_inner_alloc')
192 : : use, intrinsic :: iso_c_binding
193 : : integer(kind=c_int32_t), intent(in) :: proj_dim(3)
194 : : integer(kind=c_int32_t), value, intent(in) :: ntypat
195 : : integer(kind=c_int32_t), value, intent(in) :: realloc
196 : : end subroutine f_gpu_apply_invovl_inner_alloc
197 : :
198 : : !> deallocate GPU workspace for apply_invovl
199 : : subroutine f_gpu_apply_invovl_inner_dealloc() bind(c, name='gpu_apply_invovl_inner_dealloc')
200 : : end subroutine f_gpu_apply_invovl_inner_dealloc
201 : :
202 : : !> allocate GPU workspace for make_invovl (sij and s_approx)
203 : : subroutine f_gpu_apply_invovl_matrix_alloc(cplx, nprojs, lmnmax, ntypat, realloc) bind(c, name='gpu_apply_invovl_matrix_alloc')
204 : : use, intrinsic :: iso_c_binding
205 : : integer(kind=c_int32_t), value, intent(in) :: cplx
206 : : integer(kind=c_int32_t), value, intent(in) :: nprojs
207 : : integer(kind=c_int32_t), value, intent(in) :: ntypat
208 : : integer(kind=c_int32_t), value, intent(in) :: lmnmax
209 : : integer(kind=c_int32_t), value, intent(in) :: realloc
210 : : end subroutine f_gpu_apply_invovl_matrix_alloc
211 : :
212 : : !> deallocate GPU workspace for make_invovl (sij and s_approx)
213 : : subroutine f_gpu_apply_invovl_matrix_dealloc() bind(c, name='gpu_apply_invovl_matrix_dealloc')
214 : : end subroutine f_gpu_apply_invovl_matrix_dealloc
215 : :
216 : : !> init data for GPU
217 : : subroutine f_gpu_init_invovl_data(indlmn_dim, indlmn_ptr) bind(c, name='init_invovl_data')
218 : : use, intrinsic :: iso_c_binding
219 : : integer(kind=c_int32_t), intent(in) :: indlmn_dim(3)
220 : : type(c_ptr) , value :: indlmn_ptr
221 : : end subroutine f_gpu_init_invovl_data
222 : :
223 : : !> upload inverse overlap matrices
224 : : subroutine f_upload_inverse_overlap(invovl_gpu, cplx, nprojs, lmnmax, ntypat) bind(c, name='upload_inverse_overlap')
225 : : use, intrinsic :: iso_c_binding
226 : : import invovl_kpt_gpu_type
227 : : type(invovl_kpt_gpu_type), value, intent(in) :: invovl_gpu
228 : : integer(kind=c_int32_t), value, intent(in) :: cplx
229 : : integer(kind=c_int32_t), value, intent(in) :: nprojs
230 : : integer(kind=c_int32_t), value, intent(in) :: lmnmax
231 : : integer(kind=c_int32_t), value, intent(in) :: ntypat
232 : : end subroutine f_upload_inverse_overlap
233 : :
234 : : !> solve_inner on GPU
235 : : subroutine f_solve_inner_gpu(proj_dim, proj_ptr, sm1proj_ptr, ptp_sm1proj_ptr, &
236 : : & nattyp_dim, nattyp_ptr, ntypat, lmnmax, cplx, block_sliced) bind(c, name='solve_inner_gpu')
237 : :
238 : : use, intrinsic :: iso_c_binding
239 : : integer(kind=c_int32_t), intent(in) :: proj_dim(3)
240 : : type(c_ptr) , value :: proj_ptr
241 : : type(c_ptr) , value :: sm1proj_ptr
242 : : type(c_ptr) , value :: ptp_sm1proj_ptr
243 : : integer(kind=c_int32_t), value, intent(in) :: nattyp_dim
244 : : type(c_ptr) , value :: nattyp_ptr
245 : : integer(kind=c_int32_t), value, intent(in) :: ntypat
246 : : integer(kind=c_int32_t), value, intent(in) :: lmnmax
247 : : integer(kind=c_int32_t), value, intent(in) :: cplx
248 : : integer(kind=c_int32_t), value, intent(in) :: block_sliced
249 : : end subroutine f_solve_inner_gpu
250 : :
251 : : end interface
252 : :
253 : : #endif
254 : :
255 : : CONTAINS
256 : :
257 : : #if defined(HAVE_FC_ISO_C_BINDING) && defined(HAVE_GPU_CUDA)
258 : : !!****f* m_invovl/make_invovl_kpt_gpu
259 : : !! NAME
260 : : !! make_invovl_kpt
261 : : !!
262 : : !! FUNCTION
263 : : !! Create a invovl_pkt_gpu_type from a cpu counter part for cuda interoperability
264 : : !! SOURCE
265 : : function make_invovl_kpt_gpu(invovl) result(invovl_gpu)
266 : : type(invovl_kpt_type), intent(inout),target :: invovl
267 : : type(invovl_kpt_gpu_type) :: invovl_gpu
268 : :
269 : : invovl_gpu%nprojs = invovl%nprojs
270 : :
271 : : invovl_gpu%gram_projs = c_loc(invovl%gram_projs(1,1,1))
272 : : invovl_gpu%gram_projs_dim = (/ &
273 : : & size(invovl%gram_projs,1), &
274 : : & size(invovl%gram_projs,2), &
275 : : & size(invovl%gram_projs,3) &
276 : : & /)
277 : :
278 : : invovl_gpu%inv_sij = c_loc(invovl%inv_sij(1,1,1,1))
279 : : invovl_gpu%inv_sij_dim = (/ &
280 : : & size(invovl%inv_sij,1), &
281 : : & size(invovl%inv_sij,2), &
282 : : & size(invovl%inv_sij,3), &
283 : : & size(invovl%inv_sij,4) &
284 : : & /)
285 : :
286 : : invovl_gpu%inv_s_approx = c_loc(invovl%inv_s_approx(1,1,1,1))
287 : : invovl_gpu%inv_s_approx_dim = (/ &
288 : : & size(invovl%inv_s_approx,1), &
289 : : & size(invovl%inv_s_approx,2), &
290 : : & size(invovl%inv_s_approx,3), &
291 : : & size(invovl%inv_s_approx,4) &
292 : : & /)
293 : :
294 : : end function make_invovl_kpt_gpu
295 : : !!***
296 : : #endif
297 : :
298 : : #ifdef HAVE_OPENMP_OFFLOAD
299 : :
300 : : ! NOTE cumbersome implementation to avoid using derived-type syntax in OMP directives (loose support in compilers)
301 : : subroutine alloc_invovl_arrays_ompgpu(gram_projs, inv_s_approx, inv_sij)
302 : : real(dp), intent(inout) :: gram_projs(:,:,:)
303 : : real(dp), intent(inout) :: inv_sij(:,:,:,:)
304 : : real(dp), intent(inout) :: inv_s_approx(:,:,:,:)
305 : : !$OMP TARGET ENTER DATA MAP(to:gram_projs,inv_sij,inv_s_approx)
306 : : end subroutine alloc_invovl_arrays_ompgpu
307 : :
308 : : subroutine delete_invovl_arrays_ompgpu(gram_projs, inv_s_approx, inv_sij)
309 : : real(dp), intent(inout) :: gram_projs(:,:,:)
310 : : real(dp), intent(inout) :: inv_sij(:,:,:,:)
311 : : real(dp), intent(inout) :: inv_s_approx(:,:,:,:)
312 : : !$OMP TARGET EXIT DATA MAP(delete:gram_projs,inv_sij,inv_s_approx)
313 : : end subroutine delete_invovl_arrays_ompgpu
314 : :
315 : : subroutine refresh_invovl_ompgpu_kpt(ikpt)
316 : : integer,intent(in) :: ikpt
317 : :
318 : : ! *************************************************************************
319 : :
320 : : if(ikpt < 0) then
321 : : ABI_BUG("Requested GPU upload of a negative K-point index !")
322 : : end if
323 : :
324 : : if(current_ikpt_in_gpu /= -1) then
325 : : call delete_invovl_arrays_ompgpu(invovl_kpt(current_ikpt_in_gpu)%gram_projs, &
326 : : & invovl_kpt(current_ikpt_in_gpu)%inv_s_approx, &
327 : : & invovl_kpt(current_ikpt_in_gpu)%inv_sij)
328 : : end if
329 : :
330 : : call alloc_invovl_arrays_ompgpu(invovl_kpt(ikpt)%gram_projs, &
331 : : & invovl_kpt(ikpt)%inv_s_approx, &
332 : : & invovl_kpt(ikpt)%inv_sij)
333 : : current_ikpt_in_gpu=ikpt
334 : :
335 : : end subroutine refresh_invovl_ompgpu_kpt
336 : : #endif
337 : :
338 : : !!****f* m_invovl/init_invovl
339 : : !! NAME
340 : : !! init_invovl
341 : : !!
342 : : !! FUNCTION
343 : : !! Initalization of the invovl_kpt array
344 : : !!
345 : : !! INPUTS
346 : : !! nkpt= number of k-points
347 : : !!
348 : : !! SOURCE
349 : :
350 : 126 : subroutine init_invovl(nkpt)
351 : :
352 : : integer, intent(in) :: nkpt
353 : : integer :: ikpt
354 : :
355 : : ! *************************************************************************
356 : :
357 [ - + + - : 1820 : ABI_MALLOC(invovl_kpt, (nkpt))
+ - + - -
+ - + - +
+ + ]
358 : : ! TODO add cycling if kpt parallelism
359 [ + + ]: 1568 : do ikpt=1,nkpt
360 : 1568 : invovl_kpt(ikpt)%nprojs = -1
361 : : end do
362 : :
363 : 126 : end subroutine init_invovl
364 : : !!***
365 : :
366 : : !!****f* m_invovl/destroy_invovl_ikpt
367 : : !! NAME
368 : : !! destroy_invovl_ikpt
369 : : !!
370 : : !! FUNCTION
371 : : !! Destruction of the ikpt-th member of invovl array
372 : : !!
373 : : !! INPUTS
374 : : !! ikpt= index of k-point
375 : : !!
376 : : !! SOURCE
377 : 16747 : subroutine destroy_invovl_ikpt(ikpt, gpu_option)
378 : :
379 : : integer, intent(in) :: ikpt
380 : : integer, intent(in) :: gpu_option
381 : :
382 : : ! *************************************************************************
383 : :
384 : : if(gpu_option==ABI_GPU_OPENMP) then
385 : : #ifdef HAVE_OPENMP_OFFLOAD
386 : : if(current_ikpt_in_gpu == ikpt) then
387 : : call delete_invovl_arrays_ompgpu(invovl_kpt(ikpt)%gram_projs, &
388 : : & invovl_kpt(ikpt)%inv_s_approx, invovl_kpt(ikpt)%inv_sij)
389 : : current_ikpt_in_gpu = -1
390 : : end if
391 : : #endif
392 : : end if
393 : :
394 [ - + ]: 16747 : ABI_FREE(invovl_kpt(ikpt)%gram_projs)
395 [ - + ]: 16747 : ABI_FREE(invovl_kpt(ikpt)%inv_sij)
396 [ - + ]: 16747 : ABI_FREE(invovl_kpt(ikpt)%inv_s_approx)
397 : 16747 : invovl_kpt(ikpt)%nprojs = -1
398 : :
399 : : #if defined(HAVE_GPU_CUDA) && defined(HAVE_FC_ISO_C_BINDING)
400 : : if (gpu_option == ABI_GPU_LEGACY .or. gpu_option == ABI_GPU_KOKKOS) then
401 : : call f_gpu_apply_invovl_inner_dealloc()
402 : : call f_gpu_apply_invovl_matrix_dealloc()
403 : : end if
404 : : #endif
405 : :
406 : 16747 : end subroutine destroy_invovl_ikpt
407 : : !!***
408 : :
409 : : !!****f* m_invovl/destroy_invovl
410 : : !! NAME
411 : : !! destroy_invovl
412 : : !!
413 : : !! FUNCTION
414 : : !! Destruction of the invovl_kpt array
415 : : !!
416 : : !! INPUTS
417 : : !! nkpt= number of k-points
418 : : !!
419 : : !! SOURCE
420 : 125 : subroutine destroy_invovl(nkpt, gpu_option)
421 : :
422 : : integer, intent(in) :: nkpt
423 : : integer, intent(in) :: gpu_option
424 : : integer :: ikpt
425 : :
426 : : ! *************************************************************************
427 : :
428 : : ! TODO add cycling if kpt parallelism
429 [ + + ]: 1539 : do ikpt=1,nkpt
430 [ + + ]: 1414 : if(invovl_kpt(ikpt)%nprojs == -1) then
431 : : ! write(0, *) 'ERROR invovl_kpt is unallocated'
432 : : cycle
433 : : end if
434 : 1539 : call destroy_invovl_ikpt(ikpt, gpu_option)
435 : : end do
436 : :
437 [ + - + + : 1539 : ABI_FREE(invovl_kpt)
- + - + -
+ - + ]
438 : :
439 : 125 : end subroutine destroy_invovl
440 : : !!***
441 : :
442 : : !!****f* m_invovl/make_invovl
443 : : !! NAME
444 : : !! make_invovl
445 : : !!
446 : : !! FUNCTION
447 : : !! Builds of the invovl structure
448 : : !!
449 : : !! INPUTS
450 : : !!
451 : : !! SOURCE
452 : :
453 : 16775 : subroutine make_invovl(ham, dimffnl, ffnl, ph3d, mpi_enreg)
454 : :
455 : : use m_abi_linalg
456 : :
457 : : type(gs_hamiltonian_type),intent(in), target :: ham
458 : : integer, intent(in) :: dimffnl
459 : : real(dp),intent(in) :: ffnl(ham%npw_k,dimffnl,ham%lmnmax,ham%ntypat)
460 : : real(dp),intent(in) :: ph3d(2,ham%npw_k,ham%matblk)
461 : : type(mpi_type) :: mpi_enreg
462 : :
463 : 33550 : real(dp) :: atom_projs(2, ham%npw_k, ham%lmnmax)
464 : 33550 : real(dp) :: temp(ham%npw_k)
465 : 16775 : complex(dp), allocatable :: work(:)
466 : 16775 : real(dp), allocatable,target :: projs(:,:,:)
467 : 16775 : real(dp), allocatable :: gram_proj(:,:,:)
468 : 16775 : integer, allocatable :: ipiv(:)
469 : :
470 : : integer :: itypat, ilmn, nlmn, jlmn, ia, iaph3d, shift
471 : : integer :: il, ilm, jlm, ipw, info, ierr, cplx
472 : : integer :: ikpt_this_proc,cplex_dij
473 : : logical :: parity
474 : : real(dp) :: tsec(2)
475 : : #if defined(HAVE_FC_ISO_C_BINDING) && defined(HAVE_GPU_CUDA)
476 : : character(len=500) :: message
477 : : #endif
478 : : character :: blas_transpose
479 : :
480 : : type(invovl_kpt_type), pointer :: invovl
481 : : #if defined(HAVE_FC_ISO_C_BINDING) && defined(HAVE_GPU_CUDA)
482 : : type(invovl_kpt_gpu_type) :: invovl_gpu
483 : : #endif
484 : 33550 : integer :: array_nprojs_pp(mpi_enreg%nproc_fft)
485 : : integer :: iproc, slice_size
486 : 16775 : real(dp), allocatable :: gramwork(:,:,:)
487 : :
488 : : integer, parameter :: timer_mkinvovl = 1620, timer_mkinvovl_build_d = 1621, timer_mkinvovl_build_ptp = 1622
489 : :
490 : : ! *************************************************************************
491 : :
492 : : !! S = 1 + PDP', so
493 : : !! S^-1 = 1 + P inv_s_projs P', with
494 : : !! inv_s_projs = - (D^-1 + P'*P)^-1
495 : :
496 : : ABI_NVTX_START_RANGE(NVTX_MAKE_INVOVL)
497 : :
498 [ + + ]: 16775 : if(ham%istwf_k == 1) then
499 : 16639 : cplx = 2
500 : 16639 : blas_transpose = 'c'
501 : : else
502 : 136 : cplx = 1
503 : 136 : blas_transpose = 't'
504 : : end if
505 : :
506 : 16775 : ikpt_this_proc=bandfft_kpt_get_ikpt()
507 : 16775 : invovl => invovl_kpt(ikpt_this_proc)
508 : :
509 [ + + ]: 16775 : if(invovl%nprojs /= -1) then
510 : : ! We have been here before, cleanup before remaking
511 : 15736 : call destroy_invovl_ikpt(ikpt_this_proc, ham%gpu_option)
512 : : end if
513 : :
514 : 16775 : iaph3d = 1
515 : :
516 : 16775 : call timab(timer_mkinvovl,1,tsec)
517 : 16775 : call timab(timer_mkinvovl_build_d,1,tsec)
518 : :
519 : : ! build nprojs
520 : 16775 : invovl%nprojs = 0
521 [ + + ]: 34144 : do itypat=1,ham%ntypat
522 [ + + + + ]: 173466 : invovl%nprojs = invovl%nprojs + count(ham%indlmn(3,:,itypat)>0)*ham%nattyp(itypat)
523 : : end do
524 : :
525 [ - + + - : 67100 : ABI_MALLOC(projs, (2, ham%npw_k, invovl%nprojs))
- + + - +
- + - - +
- + ]
526 [ - + + - : 100650 : ABI_MALLOC(invovl%inv_sij, (cplx, ham%lmnmax, ham%lmnmax, ham%ntypat))
- + + - -
+ + - - +
+ - + - +
- - + - +
- + ]
527 [ - + + - : 100650 : ABI_MALLOC(invovl%inv_s_approx, (cplx, ham%lmnmax, ham%lmnmax, ham%ntypat))
- + + - -
+ + - - +
+ - + - +
- - + - +
- + ]
528 : : ! workspace for inversion
529 [ - + + - : 50325 : ABI_MALLOC(ipiv, (ham%lmnmax))
+ - + - -
+ - + ]
530 [ + - - + : 50325 : ABI_MALLOC(work, (64*ham%lmnmax))
+ - + - +
- - + -
+ ]
531 : :
532 [ + + + + : 133788887 : projs = zero
+ + ]
533 [ + + + + : 3519766 : invovl%inv_sij = zero
+ + + + ]
534 [ + + + + : 3519766 : invovl%inv_s_approx = zero
+ + + + ]
535 : :
536 : : shift = 0
537 [ + + ]: 34144 : do itypat = 1, ham%ntypat
538 [ + + + + ]: 156691 : nlmn = count(ham%indlmn(3,:,itypat)>0)
539 [ + + ]: 17369 : if (size(ham%sij(:,itypat))==ham%lmnmax*(ham%lmnmax+1)/2) then
540 : : cplex_dij = 1
541 [ - + ]: 192 : else if (size(ham%sij(:,itypat))==ham%lmnmax*(ham%lmnmax+1)) then
542 : : cplex_dij = 2
543 : : else
544 : 0 : ABI_ERROR('sij size not recognize')
545 : : end if
546 : : !! unpack ham%sij into inv_sij
547 [ + + ]: 156671 : do jlmn = 1, nlmn
548 [ + + ]: 139302 : if (cplex_dij==1) then
549 : 137766 : invovl%inv_sij(1, jlmn, jlmn, itypat) = ham%sij(jlmn*(jlmn-1)/2 + jlmn, itypat)
550 : : else
551 : 1536 : invovl%inv_sij(1, jlmn, jlmn, itypat) = ham%sij(jlmn*(jlmn-1) + 2*jlmn-1, itypat)
552 : : end if
553 [ + + ]: 647378 : do ilmn = 1, jlmn-1
554 [ + + ]: 630009 : if (cplex_dij==1) then
555 : 485331 : invovl%inv_sij(1, ilmn, jlmn, itypat) = ham%sij(jlmn*(jlmn-1)/2 + ilmn, itypat)
556 : 485331 : invovl%inv_sij(1, jlmn, ilmn, itypat) = ham%sij(jlmn*(jlmn-1)/2 + ilmn, itypat)
557 : : else
558 : 5376 : invovl%inv_sij(1, ilmn, jlmn, itypat) = ham%sij(jlmn*(jlmn-1) + 2*ilmn-1, itypat)
559 : 5376 : invovl%inv_sij(1, jlmn, ilmn, itypat) = ham%sij(jlmn*(jlmn-1) + 2*ilmn-1, itypat)
560 : :
561 : : end if
562 : : end do
563 : : end do
564 : :
565 : : ! Invert sij
566 [ + + ]: 17369 : if(cplx == 2) then
567 : 17097 : call ZHETRF('U', nlmn, invovl%inv_sij(:,:,:,itypat), ham%lmnmax, ipiv, work, (64*nlmn), info)
568 : 17097 : call ZHETRI('U', nlmn, invovl%inv_sij(:,:,:,itypat), ham%lmnmax, ipiv, work, info)
569 : : else
570 : 272 : call DSYTRF('U', nlmn, invovl%inv_sij(:,:,:,itypat), ham%lmnmax, ipiv, work, (64*nlmn), info)
571 : 272 : call DSYTRI('U', nlmn, invovl%inv_sij(:,:,:,itypat), ham%lmnmax, ipiv, work, info)
572 : : end if
573 : : ! complete the matrix
574 [ + + ]: 156671 : do ilm=1, nlmn
575 [ + + ]: 647378 : do jlm=1, ilm-1
576 : 630009 : invovl%inv_sij(1,ilm,jlm,itypat) = invovl%inv_sij(1,jlm,ilm,itypat)
577 : : end do
578 : : end do
579 : :
580 : : !! loop on atoms to build atom_projs and fill projs, s_projs
581 [ + + ]: 68019 : do ia = 1, ham%nattyp(itypat)
582 : :
583 : : !! build atom_projs, from opernlb
584 : : !! P = 4pi/sqrt(ucvol)* conj(diag(ph3d)) * ffnl * diag(parity), with parity = (-i)^l
585 [ + + + + : 133871987 : atom_projs(:,:,:) = zero
+ + ]
586 : :
587 : : ! start from 4pi/sqrt(ucvol)*ffnl
588 : : ! atom_projs(1, :, 1:nlmn) = four_pi/sqrt(ham%ucvol) * ffnl(:, 1, 1:nlmn)
589 : : ! TODO vectorize (DCOPY with stride)
590 [ + + ]: 5109778 : do ipw=1, ham%npw_k
591 [ + + ]: 49608872 : atom_projs(1,ipw, 1:nlmn) = four_pi/sqrt(ham%ucvol) * ffnl(ipw, 1, 1:nlmn, itypat)
592 : : end do
593 : :
594 : : ! multiply by (-i)^l
595 [ + + ]: 308705 : do ilmn=1,nlmn
596 : 274830 : il=mod(ham%indlmn(1,ilmn, itypat),4);
597 : 274830 : parity=(mod(il,2)==0)
598 [ + + ]: 274830 : if (il>1) then
599 : : ! multiply by -1
600 [ + + + + ]: 11679440 : atom_projs(:,:,ilmn) = -atom_projs(:,:,ilmn)
601 : : end if
602 [ + + ]: 308705 : if(.not. parity) then
603 : : ! multiply by -i
604 [ + + ]: 30658668 : temp = atom_projs(2,:,ilmn)
605 [ + + ]: 30658668 : atom_projs(2,:,ilmn) = -atom_projs(1,:,ilmn)
606 [ + + ]: 30658668 : atom_projs(1,:,ilmn) = temp
607 : : end if
608 : : end do
609 : :
610 : : ! multiply by conj(ph3d)
611 [ + + ]: 308705 : do ilmn=1,nlmn
612 [ + + ]: 44773924 : temp = atom_projs(1, :, ilmn)
613 [ + + ]: 44773924 : atom_projs(1, :, ilmn) = atom_projs(1, :, ilmn) * ph3d(1, :, iaph3d) + atom_projs(2, :, ilmn) * ph3d(2, :, iaph3d)
614 [ + + ]: 44807799 : atom_projs(2, :, ilmn) = atom_projs(2, :, ilmn) * ph3d(1, :, iaph3d) - temp * ph3d(2, :, iaph3d)
615 : : end do
616 : :
617 : : ! me_g0 trick
618 [ + + + + ]: 33875 : if(ham%istwf_k == 2 .and. mpi_enreg%me_g0 == 1) then
619 [ + + ]: 270 : atom_projs(1,1,:) = atom_projs(1,1,:) / sqrt2
620 [ + + ]: 270 : atom_projs(2,1,:) = zero
621 : : end if
622 [ + + ]: 33875 : if(ham%istwf_k > 1) then
623 [ + + + + : 224880 : atom_projs(:,:,:) = atom_projs(:,:,:) * sqrt2
+ + ]
624 : : end if
625 : :
626 : :
627 : : !! atom_projs and typat_s_projs are built, copy them to projs and inv_s_projs
628 [ + + + + : 133805987 : projs(:, :, shift+1:shift+nlmn) = atom_projs(:, :, 1:nlmn)
+ + ]
629 : 33875 : shift = shift + nlmn
630 : :
631 : : ! build inv_s_approx = (D^-1+PtP)^-1 restricted to a single atom block
632 : : ! can be optimized (real, build directly from ffnl)
633 [ + + ]: 33875 : if(ia == 1) then
634 : : ! D^-1
635 [ + + + + ]: 1277343 : invovl%inv_s_approx(1, :, :, itypat) = invovl%inv_sij(1, :, :, itypat)
636 : : ! + PtP
637 [ - + + - : 86805 : ABI_MALLOC(gram_proj, (cplx, nlmn, nlmn))
- + + - -
+ + - + -
+ - - + -
+ - + ]
638 : : call abi_xgemm(blas_transpose,'N', nlmn, nlmn, (3-cplx)*ham%npw_k, cone, atom_projs(:,:,1), (3-cplx)*ham%npw_k, &
639 : 17361 : & atom_projs(:,:,1), (3-cplx)*ham%npw_k, czero, gram_proj(:,:,1), nlmn,x_cplx=cplx)
640 : 17361 : call xmpi_sum(gram_proj,mpi_enreg%comm_bandspinorfft,ierr)
641 [ + + + + : 3499803 : invovl%inv_s_approx(:,1:nlmn,1:nlmn,itypat) = invovl%inv_s_approx(:,1:nlmn,1:nlmn,itypat) + gram_proj(:,:,:)
+ + ]
642 [ - + ]: 17361 : ABI_FREE(gram_proj)
643 : : ! ^-1
644 [ + + ]: 17361 : if(cplx == 2) then
645 : 17089 : call ZHETRF('U', nlmn, invovl%inv_s_approx(:,:,:,itypat), ham%lmnmax, ipiv, work, (64*nlmn), info)
646 : 17089 : call ZHETRI('U', nlmn, invovl%inv_s_approx(:,:,:,itypat), ham%lmnmax, ipiv, work, info)
647 : : else
648 : 272 : call DSYTRF('U', nlmn, invovl%inv_s_approx(:,:,:,itypat), ham%lmnmax, ipiv, work, (64*nlmn), info)
649 : 272 : call DSYTRI('U', nlmn, invovl%inv_s_approx(:,:,:,itypat), ham%lmnmax, ipiv, work, info)
650 : : end if
651 : : ! complete lower triangle of matrix
652 [ + + ]: 173960 : do ilm=1, nlmn
653 [ + + ]: 647082 : do jlm=1, ilm-1
654 : 490483 : invovl%inv_s_approx(1, ilm, jlm, itypat) = invovl%inv_s_approx(1, jlm, ilm, itypat)
655 [ + + ]: 629721 : if(cplx == 2) then
656 : 482867 : invovl%inv_s_approx(2, ilm, jlm, itypat) = -invovl%inv_s_approx(2, jlm, ilm, itypat)
657 : : end if
658 : : end do
659 : : end do
660 : : end if
661 : :
662 : 51244 : iaph3d = iaph3d + 1
663 : : end do
664 : : end do
665 [ - + ]: 16775 : ABI_FREE(ipiv)
666 [ - + ]: 16775 : ABI_FREE(work)
667 : :
668 : 16775 : call timab(timer_mkinvovl_build_d, 2, tsec)
669 : 16775 : call timab(timer_mkinvovl_build_ptp, 1, tsec)
670 : :
671 : : ! Compute P'P one column slice at a time (might be too big to fit in one proc)
672 [ + + ]: 16775 : if(mpi_enreg%paral_kgb == 1) then
673 : : ! Split the work evenly the fft processors
674 [ + + ]: 13464 : array_nprojs_pp(:) = invovl%nprojs / mpi_enreg%nproc_fft
675 : : ! not enough work, there's MOD(nprojs,mpi_enreg%nproc_fft) tasks left
676 : : ! assign them to the first ones
677 [ - + ]: 6728 : array_nprojs_pp(1:MOD(invovl%nprojs,mpi_enreg%nproc_fft)) = array_nprojs_pp(1:MOD(invovl%nprojs,mpi_enreg%nproc_fft)) + 1
678 : : else
679 [ + + ]: 20094 : array_nprojs_pp = invovl%nprojs
680 : : end if
681 [ - + + - : 83875 : ABI_MALLOC(invovl%gram_projs, (cplx,invovl%nprojs,array_nprojs_pp(mpi_enreg%me_fft+1)))
- + + - -
+ + - + -
+ - - + -
+ - + ]
682 : 16775 : shift = 0
683 [ - + - - ]: 16775 : if (ham%gpu_option==ABI_GPU_OPENMP .and. mpi_enreg%nproc_fft==1) then
684 : : #ifdef HAVE_OPENMP_OFFLOAD
685 : : ! compute gram_projs in one GEMM, only one FFT proc expected in GPU mode
686 : : slice_size = array_nprojs_pp(1)
687 : : !$OMP TARGET ENTER DATA MAP(alloc:invovl%gram_projs)
688 : : !$OMP TARGET ENTER DATA MAP(to:projs)
689 : :
690 : : call abi_xgemm(blas_transpose,'N', invovl%nprojs, slice_size, (3-cplx)*ham%npw_k, cone, &
691 : : & projs, (3-cplx)*ham%npw_k, &
692 : : & projs, (3-cplx)*ham%npw_k, czero, &
693 : : & invovl%gram_projs, invovl%nprojs, &
694 : : & x_cplx=cplx, gpu_option=ham%gpu_option)
695 : : call xmpi_sum(invovl%gram_projs,mpi_enreg%comm_band,ierr,use_omp_map=.true.)
696 : : !$OMP TARGET EXIT DATA MAP(from:invovl%gram_projs)
697 : : !$OMP TARGET EXIT DATA MAP(delete:projs)
698 : : #endif
699 : : else
700 [ + + ]: 33558 : do iproc = 1, mpi_enreg%nproc_fft
701 : : ! compute local contribution to slice iproc of gram_projs
702 : 16783 : slice_size = array_nprojs_pp(iproc)
703 [ - + + - : 83915 : ABI_MALLOC(gramwork, (cplx,invovl%nprojs,slice_size))
- + + - -
+ + - + -
+ - - + -
+ - + ]
704 : : call abi_xgemm(blas_transpose,'N', invovl%nprojs, slice_size, (3-cplx)*ham%npw_k, cone,&
705 : : & projs(:,:,1), (3-cplx)*ham%npw_k, &
706 : : & projs(:, :, shift+1), (3-cplx)*ham%npw_k, czero, &
707 : : & gramwork(:,:,1), invovl%nprojs,&
708 : 16783 : & x_cplx=cplx)
709 : 16783 : shift = shift + slice_size
710 : : ! reduce on proc i
711 : 16783 : call xmpi_sum_master(gramwork, iproc-1, mpi_enreg%comm_fft, ierr)
712 [ + + ]: 16783 : if(iproc == mpi_enreg%me_fft+1) then
713 [ + - + - : 21993224 : invovl%gram_projs = gramwork
+ - - + -
- - - - -
- - + + +
+ + + ]
714 : : end if
715 [ - + ]: 33558 : ABI_FREE(gramwork)
716 : : end do
717 : 16775 : call xmpi_sum(invovl%gram_projs,mpi_enreg%comm_band,ierr)
718 : : end if
719 : :
720 : 16775 : call timab(timer_mkinvovl_build_ptp, 2, tsec)
721 : 16775 : call timab(timer_mkinvovl,2,tsec)
722 : :
723 [ - + ]: 16775 : ABI_FREE(projs)
724 : :
725 : : #if defined(HAVE_FC_ISO_C_BINDING) && defined(HAVE_GPU_CUDA)
726 : :
727 : : ! upload inverse overlap matrices (sij and s_approx) to GPU memory
728 : : if (ham%gpu_option==ABI_GPU_LEGACY .or. ham%gpu_option==ABI_GPU_KOKKOS) then
729 : : ! allocate memory for sij and s_approx on GPU
730 : : write(message,'(a,a,i12,a,a,i6,a,a,i6,a,a,es12.4,a)') &
731 : : & 'Allocate GPU memory for inverse overlap computations (sij and s_approx) : ',&
732 : : & 'nprojs=',invovl%nprojs,ch10,&
733 : : & 'nlmnax=',ham%lmnmax,ch10,&
734 : : & 'ntypat=',ham%ntypat,ch10,&
735 : : & 'gram_projs_gpu_size (GBytes)=',1e-9*cplx*invovl%nprojs*invovl%nprojs*dp,ch10
736 : : call wrtout(std_out,message,'COLL')
737 : : call f_gpu_apply_invovl_matrix_alloc(cplx, invovl%nprojs, ham%lmnmax, ham%ntypat, 0)
738 : :
739 : : invovl_gpu = make_invovl_kpt_gpu(invovl)
740 : : call f_upload_inverse_overlap(invovl_gpu, cplx, invovl%nprojs, ham%lmnmax, ham%ntypat)
741 : : write(message,*) 'Invovl uploaded to GPU memory'
742 : : call wrtout(std_out,message,'COLL')
743 : : end if
744 : :
745 : : #endif
746 : :
747 : : #ifdef HAVE_OPENMP_OFFLOAD
748 : : if (ham%gpu_option==ABI_GPU_OPENMP) then
749 : : call refresh_invovl_ompgpu_kpt(ikpt_this_proc)
750 : : end if
751 : : #endif
752 : :
753 : : ! LB-10/06/24: This message is too verbose on some cases (for example many k-points)
754 : : ! write(message,*) 'Invovl built'
755 : : ! call wrtout(std_out,message,'COLL')
756 : :
757 : : ABI_NVTX_END_RANGE()
758 : :
759 [ - + - + ]: 16775 : end subroutine make_invovl
760 : : !!***
761 : :
762 : : !!****f* m_invovl/apply_invovl
763 : : !! NAME
764 : : !! apply_invovl
765 : : !!
766 : : !! FUNCTION
767 : : !! Applies the inverse of the overlap matrix to cwavef
768 : : !!
769 : : !! INPUTS
770 : : !!
771 : : !! SOURCE
772 : :
773 [ - + ]: 178662 : subroutine apply_invovl(ham, cwavef, sm1cwavef, cwaveprj, npw, ndat, mpi_enreg, nspinor, block_sliced, invovl_precision, algo)
774 : :
775 : : #if defined(HAVE_FC_ISO_C_BINDING) && defined(HAVE_GPU)
776 : : use, intrinsic :: iso_c_binding
777 : : #endif
778 : :
779 : : ! args
780 : : type(gs_hamiltonian_type), intent(in), target :: ham
781 : : integer, intent(in) :: npw, ndat
782 : : integer, intent(in) :: nspinor
783 : : integer, intent(in) :: block_sliced
784 : : integer, intent(in), optional :: algo
785 : : real(dp), intent(in) :: invovl_precision
786 : : real(dp), intent(inout), target :: cwavef(2, npw*nspinor*ndat) ! TODO should be in, fix nonlop
787 : : type(mpi_type) :: mpi_enreg
788 : : real(dp), intent(inout), target :: sm1cwavef(2, npw*nspinor*ndat)
789 : : type(pawcprj_type), intent(inout) :: cwaveprj(:,:)
790 : : #ifdef HAVE_OPENMP_OFFLOAD
791 : : logical :: transfer_omp_args
792 : : #endif
793 : :
794 : 178662 : real(dp),allocatable, target :: proj(:,:,:), sm1proj(:,:,:), PtPsm1proj(:,:,:)
795 : :
796 : : #if defined(HAVE_GPU_CUDA) && defined(HAVE_FC_ISO_C_BINDING)
797 : : ! used to pass proj dimensions to cuda
798 : : integer(kind=c_int32_t) :: proj_dim(3)
799 : : integer(kind=c_int32_t) :: nattyp_dim
800 : : integer(kind=c_int32_t) :: indlmn_dim(3)
801 : : #endif
802 : :
803 : : #if defined(HAVE_GPU_CUDA) && defined(HAVE_KOKKOS) && defined(HAVE_YAKL)
804 : : integer(kind=c_int32_t) :: cwavef_size
805 : : #endif
806 : :
807 : : integer :: idat, iatom, nprojs, nlmn, shift, l_algo
808 : : #ifdef HAVE_OPENMP_OFFLOAD
809 : : integer :: icplx, iproj
810 : : #endif
811 : : real(dp) :: tsec(2)
812 : :
813 : : integer :: choice, cpopt, paw_opt , cplx, old_me_g0
814 : 178662 : type(pawcprj_type),allocatable :: cwaveprj_in(:,:)
815 : :
816 : : integer :: ikpt_this_proc
817 : : ! dummies
818 : 357324 : real(dp) :: enlout(ndat), lambda_block(1), gvnlxc(1,1)
819 : : integer, parameter :: nnlout = 0, idir = 0, signs = 2
820 : :
821 : : type(invovl_kpt_type), pointer :: invovl
822 : :
823 : : ! *************************************************************************
824 : :
825 : :
826 : : ABI_NVTX_START_RANGE(NVTX_INVOVL_PREP)
827 [ + + ]: 178662 : l_algo=0; if(present(algo)) l_algo=algo
828 : 178662 : ikpt_this_proc=bandfft_kpt_get_ikpt()
829 : 178662 : invovl => invovl_kpt(ikpt_this_proc)
830 : 178662 : nprojs=invovl%nprojs
831 : :
832 [ + + ]: 178662 : if(ham%istwf_k == 1) then
833 : 160803 : cplx = 2
834 : : else
835 : 17859 : cplx = 1
836 : : end if
837 : :
838 [ - + + - : 893310 : ABI_MALLOC(proj, (cplx,invovl%nprojs,nspinor*ndat))
- + + - -
+ + - + -
+ - - + -
+ ]
839 [ - + + - : 714648 : ABI_MALLOC(sm1proj, (cplx,invovl%nprojs,nspinor*ndat))
- + + - -
+ + - - +
- + ]
840 [ - + + - : 714648 : ABI_MALLOC(PtPsm1proj, (cplx,invovl%nprojs,nspinor*ndat))
- + + - -
+ + - - +
- + ]
841 [ + - ]: 178662 : if(ham%gpu_option/=ABI_GPU_OPENMP) then
842 [ + + + + : 73471254 : proj = zero
+ + ]
843 [ + + + + : 73471254 : sm1proj = zero
+ + ]
844 [ + + + + : 73471254 : PtPsm1proj = zero
+ + ]
845 : : end if
846 : :
847 : : #ifdef HAVE_OPENMP_OFFLOAD
848 : : if(ham%gpu_option == ABI_GPU_OPENMP) then
849 : : if(ikpt_this_proc /= current_ikpt_in_gpu) call refresh_invovl_ompgpu_kpt(ikpt_this_proc)
850 : : !$OMP TARGET ENTER DATA MAP(alloc:proj,sm1proj,PtPsm1proj)
851 : :
852 : : transfer_omp_args = .not. ( xomp_target_is_present(c_loc(sm1cwavef)) &
853 : : .and. xomp_target_is_present(c_loc(cwavef)))
854 : : !$OMP TARGET ENTER DATA MAP(alloc:gvnlxc)
855 : : if(transfer_omp_args) then
856 : : !$OMP TARGET ENTER DATA MAP(alloc:sm1cwavef,cwavef)
857 : : !$OMP TARGET UPDATE TO(sm1cwavef,cwavef)
858 : : end if
859 : : end if
860 : : #endif
861 : :
862 : : #if defined(HAVE_GPU_CUDA) && defined(HAVE_FC_ISO_C_BINDING)
863 : :
864 : : proj_dim = (/ size(proj,1), size(proj,2), size(proj,3) /)
865 : : nattyp_dim = size(ham%nattyp)
866 : : indlmn_dim = (/ size(ham%indlmn,1), size(ham%indlmn,2), size(ham%indlmn,3) /)
867 : :
868 : : !! memory allocation of data used in solve_inner_gpu
869 : : !! note : this is actually done only once
870 : : if (ham%gpu_option==ABI_GPU_LEGACY .or. ham%gpu_option==ABI_GPU_KOKKOS) then
871 : :
872 : : #ifdef DEBUG_VERBOSE_GPU
873 : : if(xmpi_comm_rank(xmpi_world) == 0) then
874 : : call check_gpu_mem("gpu_apply_invovl_inner_alloc begin")
875 : : end if
876 : : #endif
877 : :
878 : : ! make sure to use sizes from apply_invovl
879 : : call f_gpu_apply_invovl_inner_alloc(proj_dim, ham%ntypat, 0)
880 : :
881 : : #ifdef DEBUG_VERBOSE_GPU
882 : : if(xmpi_comm_rank(xmpi_world) == 0) then
883 : : call check_gpu_mem("gpu_apply_invovl_inner_alloc end")
884 : : end if
885 : : #endif
886 : :
887 : : ! TODO find a better place to put that initialization
888 : : call f_gpu_init_invovl_data(indlmn_dim, c_loc(ham%indlmn(1,1,1)))
889 : :
890 : : end if
891 : :
892 : : #endif
893 : :
894 : 178662 : call timab(timer_apply_inv_ovl_opernla, 1, tsec)
895 : :
896 : : ! cwaveprj may be dummy or unused if gemm nonlop is turned on
897 [ + + + + : 535986 : if((.not. (gemm_nonlop_use_gemm .or. ham%gpu_option==ABI_GPU_OPENMP)) .or. size(cwaveprj) > 1) then
- + + + ]
898 [ - + + - : 4778856 : ABI_MALLOC(cwaveprj_in, (ham%natom,nspinor*ndat))
- + + - +
- + - - +
- + - + +
+ + + ]
899 : 178374 : call pawcprj_alloc(cwaveprj_in,0,ham%dimcprj)
900 : : else
901 [ - + - + : 864 : ABI_MALLOC(cwaveprj_in, (1,1))
+ + + + ]
902 : 288 : call pawcprj_alloc(cwaveprj_in,0,(/1/))
903 : : end if
904 : : ABI_NVTX_END_RANGE()
905 : :
906 : : ! get the cprj
907 : : ABI_NVTX_START_RANGE(NVTX_INVOVL_NONLOP1)
908 : 178662 : choice = 0 ! only compute cprj, nothing else
909 : 178662 : cpopt = 0 ! compute and save cprj
910 : 178662 : paw_opt = 3 ! S nonlocal operator
911 [ + + + - ]: 178662 : if (mpi_enreg%paral_kgb==1 .and. ham%gpu_option/=ABI_GPU_OPENMP) then
912 : : call prep_nonlop(choice,cpopt,cwaveprj_in,enlout,ham,idir,lambda_block,ndat,mpi_enreg,&
913 : : & nnlout,paw_opt,signs,sm1cwavef,tim_nonlop,cwavef,gvnlxc,&
914 : : & already_transposed=.true.,&
915 : : & gpu_option=ham%gpu_option,&
916 : 62460 : & vectproj=proj)
917 : : else
918 [ + + - + ]: 116202 : if(ham%istwf_k==2 .and. ham%gpu_option==ABI_GPU_OPENMP) then
919 : 0 : old_me_g0=mpi_enreg%me_g0
920 [ # # ]: 0 : if (mpi_enreg%me_fft==0) then
921 : 0 : mpi_enreg%me_g0=1
922 : : else
923 : 0 : mpi_enreg%me_g0=0
924 : : end if
925 : : end if
926 : : call nonlop(choice,cpopt,cwaveprj_in,enlout,ham,idir,lambda_block,mpi_enreg,ndat,&
927 : 116202 : & nnlout,paw_opt,signs,sm1cwavef,tim_nonlop,cwavef,gvnlxc,vectproj=proj)
928 : : end if
929 : : ABI_NVTX_END_RANGE()
930 : :
931 : 178662 : call timab(timer_apply_inv_ovl_opernla, 2, tsec)
932 : 178662 : call timab(timer_apply_inv_ovl_inv_s, 1, tsec)
933 : :
934 : : ! If using GEMM nonlop, proj array is used directly instead of writing in cwaveprj_in content, so skip this copy
935 [ + + + - ]: 178662 : if(.not. (gemm_nonlop_use_gemm .or. ham%gpu_option==ABI_GPU_OPENMP)) then
936 : : ! copy cwaveprj_in to proj(:,:)
937 [ + + ]: 1475318 : do idat=1, ndat*nspinor
938 : 1297232 : shift = 0
939 [ + + ]: 4238262 : do iatom = 1, ham%natom
940 : 2762944 : nlmn = cwaveprj_in(iatom, idat)%nlmn
941 [ + + + + ]: 74631296 : proj(1:cplx, shift+1:shift+nlmn, idat) = cwaveprj_in(iatom, idat)%cp(1:cplx, 1:nlmn)
942 : 4060176 : shift = shift + nlmn
943 : : end do
944 : : end do
945 : : end if
946 : :
947 : : !multiply by S^1
948 : : ABI_NVTX_START_RANGE(NVTX_INVOVL_INNER)
949 : : ! TODO : when solve_inner_gpu is ready, update the following to activate GPU computation
950 [ + - ]: 178662 : if (ham%gpu_option == ABI_GPU_LEGACY .or. ham%gpu_option==ABI_GPU_KOKKOS) then
951 : :
952 : : #if defined(HAVE_FC_ISO_C_BINDING) && defined(HAVE_GPU_CUDA)
953 : :
954 : : if (mpi_enreg%nproc_fft /= 1) then
955 : : ABI_ERROR("[66_wfs/m_invovl.F90:apply_invovl] nproc_fft must be 1, when GPU/CUDA is activated")
956 : : end if
957 : :
958 : : call f_solve_inner_gpu(proj_dim, c_loc(proj(1,1,1)), &
959 : : & c_loc(sm1proj(1,1,1)), c_loc(PtPsm1proj(1,1,1)), &
960 : : & nattyp_dim, c_loc(ham%nattyp(1)), ham%ntypat, &
961 : : & ham%lmnmax, cplx, block_sliced)
962 : :
963 : : #endif
964 : :
965 : : else
966 : :
967 [ + + ]: 178662 : if(l_algo == 0) then
968 : : call solve_inner(invovl, ham, cplx, mpi_enreg, proj, ndat*nspinor, sm1proj, PtPsm1proj, &
969 : 171686 : & block_sliced, ham%gpu_option, invovl_precision)
970 [ + - ]: 6976 : else if(l_algo == 1) then
971 : : call solve_inner_sqmr(invovl, ham, cplx, mpi_enreg, proj, ndat*nspinor, sm1proj, PtPsm1proj, &
972 : 6976 : & block_sliced, ham%gpu_option, invovl_precision)
973 : : else
974 : 0 : ABI_BUG("Incorrect algo value")
975 : : end if
976 : :
977 [ + - ]: 178662 : if(ham%gpu_option == ABI_GPU_DISABLED) then
978 [ + + + + : 73471254 : sm1proj = - sm1proj
+ + ]
979 [ + + + + : 73471254 : PtPsm1proj = - PtPsm1proj
+ + ]
980 : : else if(ham%gpu_option == ABI_GPU_OPENMP) then
981 : : #ifdef HAVE_OPENMP_OFFLOAD
982 : : !$OMP TARGET TEAMS DISTRIBUTE MAP(to:sm1proj,PtPsm1proj)
983 : : do idat =1, ndat*nspinor
984 : : !$OMP PARALLEL DO COLLAPSE(2) PRIVATE(iproj,icplx)
985 : : do iproj = 1, nprojs
986 : : do icplx = 1, cplx
987 : : sm1proj(icplx,iproj,idat) = - sm1proj(icplx,iproj,idat)
988 : : PtPsm1proj(icplx,iproj,idat) = - PtPsm1proj(icplx,iproj,idat)
989 : : end do
990 : : end do
991 : : end do
992 : : #endif
993 : : end if
994 : : end if
995 : :
996 : : ABI_NVTX_END_RANGE()
997 : :
998 : : ! If using GEMM nonlop, sm1proj array is used directly instead of reading cwaveprj content, so skip this copy
999 [ + + + - ]: 178662 : if(.not. (gemm_nonlop_use_gemm .or. ham%gpu_option==ABI_GPU_OPENMP)) then
1000 : : ! copy sm1proj to cwaveprj(:,:)
1001 [ + + ]: 1475318 : do idat=1, ndat*nspinor
1002 : 1297232 : shift = 0
1003 [ + + ]: 4238262 : do iatom = 1, ham%natom
1004 : 2762944 : nlmn = cwaveprj(iatom, idat)%nlmn
1005 [ + + + + ]: 74631296 : cwaveprj(iatom, idat)%cp(1:cplx, 1:nlmn) = sm1proj(1:cplx, shift+1:shift+nlmn, idat)
1006 : 4060176 : shift = shift + nlmn
1007 : : end do
1008 : : end do
1009 : : end if
1010 : 178662 : call timab(timer_apply_inv_ovl_inv_s, 2, tsec)
1011 : 178662 : call timab(timer_apply_inv_ovl_opernlb, 1, tsec)
1012 : :
1013 : : ! get the corresponding wf
1014 : : ABI_NVTX_START_RANGE(NVTX_INVOVL_NONLOP2)
1015 : 178662 : cpopt = 2 ! reuse cprj
1016 : 178662 : choice = 7 ! get wf from cprj, without the application of S
1017 : : paw_opt = 3
1018 [ + + + - ]: 178662 : if (mpi_enreg%paral_kgb==1 .and. ham%gpu_option/=ABI_GPU_OPENMP) then
1019 : : call prep_nonlop(choice,cpopt,cwaveprj,enlout,ham,idir,lambda_block,ndat,mpi_enreg,nnlout,&
1020 : : & paw_opt,signs,sm1cwavef,tim_nonlop,cwavef,gvnlxc,already_transposed=.true.,&
1021 : 62460 : & gpu_option=ham%gpu_option,vectproj=sm1proj)
1022 : : else
1023 : : call nonlop(choice,cpopt,cwaveprj,enlout,ham,idir,lambda_block,mpi_enreg,ndat,nnlout,paw_opt,&
1024 : 116202 : & signs,sm1cwavef,tim_nonlop,cwavef,gvnlxc,vectproj=sm1proj)
1025 : : end if
1026 : : ABI_NVTX_END_RANGE()
1027 : :
1028 : 178662 : call timab(timer_apply_inv_ovl_opernlb, 2, tsec)
1029 [ + + - + ]: 178662 : if (ham%istwf_k==2 .and. ham%gpu_option==ABI_GPU_OPENMP) mpi_enreg%me_g0=old_me_g0
1030 : :
1031 : : ABI_NVTX_START_RANGE(NVTX_INVOVL_POST2)
1032 [ + + + + ]: 535986 : if(size(cwaveprj) > 1) then
1033 : : #ifdef HAVE_OPENMP_OFFLOAD
1034 : : !$OMP TARGET UPDATE FROM(PtPsm1proj,proj) IF(ham%gpu_option==ABI_GPU_OPENMP)
1035 : : #endif
1036 : : ! copy PtPsm1proj to cwaveprj(:,:)
1037 [ + + ]: 1477334 : do idat=1, ndat*nspinor
1038 : 1298960 : shift = 0
1039 [ + + ]: 4243734 : do iatom = 1, ham%natom
1040 : 2766400 : nlmn = cwaveprj(iatom, idat)%nlmn
1041 [ + + + + ]: 74717696 : cwaveprj(iatom, idat)%cp(1:cplx, 1:nlmn) = PtPsm1proj(1:cplx, shift+1:shift+nlmn, idat)
1042 : 4065360 : shift = shift + nlmn
1043 : : end do
1044 : : end do
1045 : : !cwaveprj_in is empty if GEMM nonlop is being used, so populate it here
1046 [ + + - + ]: 178374 : if(gemm_nonlop_use_gemm .or. ham%gpu_option == ABI_GPU_OPENMP) then
1047 [ + + ]: 2016 : do idat=1, ndat*nspinor
1048 : 1728 : shift = 0
1049 [ + + ]: 183558 : do iatom = 1, ham%natom
1050 : 3456 : nlmn = cwaveprj_in(iatom, idat)%nlmn
1051 [ + + + + ]: 86400 : cwaveprj_in(iatom, idat)%cp(1:cplx, 1:nlmn) = proj(1:cplx, shift+1:shift+nlmn, idat)
1052 : 5184 : shift = shift + nlmn
1053 : : end do
1054 : : end do
1055 : : end if
1056 : 178374 : call pawcprj_axpby(one, one, cwaveprj_in, cwaveprj)
1057 : : end if
1058 : 178662 : call pawcprj_free(cwaveprj_in)
1059 [ + - + + : 2945350 : ABI_FREE(cwaveprj_in)
- + - + -
+ ]
1060 : :
1061 [ + - ]: 178662 : if (ham%gpu_option == ABI_GPU_LEGACY .or. ham%gpu_option==ABI_GPU_KOKKOS) then
1062 : : #if defined(HAVE_GPU_CUDA) && defined(HAVE_KOKKOS) && defined(HAVE_YAKL)
1063 : : cwavef_size = 2*npw*nspinor*ndat
1064 : : call add_array_kokkos(c_loc(sm1cwavef), c_loc(cwavef), cwavef_size)
1065 : : #endif
1066 [ - + ]: 178662 : else if(ham%gpu_option == ABI_GPU_OPENMP) then
1067 : 0 : call abi_xaxpy(2*npw*nspinor*ndat, cone, cwavef, 1, sm1cwavef, 1, gpu_option=ABI_GPU_OPENMP)
1068 : : else
1069 [ + + + + ]: 735307302 : sm1cwavef = cwavef + sm1cwavef
1070 : : end if
1071 : :
1072 : : ABI_NVTX_END_RANGE()
1073 : :
1074 : : if(ham%gpu_option==ABI_GPU_OPENMP) then
1075 : : #ifdef HAVE_OPENMP_OFFLOAD
1076 : : if(transfer_omp_args) then
1077 : : !$OMP TARGET UPDATE FROM(sm1cwavef,cwavef)
1078 : : !$OMP TARGET EXIT DATA MAP(delete:sm1cwavef,cwavef)
1079 : : end if
1080 : : !$OMP TARGET EXIT DATA MAP(delete:gvnlxc)
1081 : : !$OMP TARGET EXIT DATA MAP(delete:proj,sm1proj,PtPsm1proj)
1082 : : #endif
1083 : : end if
1084 : :
1085 [ - + ]: 178662 : ABI_FREE(proj)
1086 [ - + ]: 178662 : ABI_FREE(sm1proj)
1087 [ - + ]: 178662 : ABI_FREE(PtPsm1proj)
1088 : :
1089 [ - + - - : 178662 : end subroutine apply_invovl
- - - - ]
1090 : : !!***
1091 : :
1092 : : !!****f* m_invovl/solve_inner
1093 : : !! NAME
1094 : : !! solve_inner
1095 : : !!
1096 : : !! FUNCTION
1097 : : !! Helper function: iteratively solves the inner system
1098 : : !!
1099 : : !! INPUTS
1100 : : !!
1101 : : !! SOURCE
1102 : 171686 : subroutine solve_inner(invovl, ham, cplx, mpi_enreg, proj, ndat, sm1proj, PtPsm1proj, block_sliced, gpu_option, invovl_precision)
1103 : :
1104 : : use m_abi_linalg
1105 : :
1106 : : integer,intent(in) :: ndat,cplx
1107 : : type(invovl_kpt_type), intent(in), target :: invovl
1108 : : real(dp), intent(in) :: invovl_precision
1109 : : real(dp), intent(inout) :: proj(cplx, invovl%nprojs,ndat)
1110 : : real(dp), intent(inout), target :: sm1proj(cplx, invovl%nprojs, ndat)
1111 : : real(dp), intent(inout), target :: PtPsm1proj(cplx, invovl%nprojs, ndat)
1112 : 171686 : real(dp), allocatable :: temp_proj(:,:,:)
1113 : : type(mpi_type), intent(in) :: mpi_enreg
1114 : : type(gs_hamiltonian_type),intent(in) :: ham
1115 : : integer, intent(in) :: block_sliced, gpu_option
1116 : :
1117 : 343372 : integer :: array_nlmntot_pp(mpi_enreg%nproc_fft)
1118 : : integer :: nlmntot_this_proc, ibeg, iend, ierr, i, nprojs
1119 : : integer :: nstagnated
1120 : 343372 : real(dp) :: resid(cplx, invovl%nprojs,ndat), precondresid(cplx, invovl%nprojs,ndat)
1121 : 343372 : real(dp) :: normprojs(ndat), errs(ndat), maxerr, previous_maxerr
1122 : : ! Stagnation check: if the (global, over ndat) residual fails to shrink by
1123 : : ! at least a factor stagnation_tol over max_stagnated_it consecutive
1124 : : ! iterations, further iterations are extremely unlikely to help (this
1125 : : ! typically happens once invovl_precision is set close to, or below, the
1126 : : ! relative residual level attainable in double precision for the given
1127 : : ! conditioning of A) : give up early instead of iterating all the way to
1128 : : ! maxit.
1129 : : real(dp), parameter :: stagnation_tol = 0.99_dp
1130 : : integer, parameter :: max_stagnated_it = 3
1131 : : character(len=500) :: message
1132 : :
1133 : : real(dp) :: convergence_rate
1134 : : integer :: additional_steps_to_take
1135 : : #ifdef HAVE_OPENMP_OFFLOAD
1136 : : real(dp) :: sum_tmp
1137 : : integer :: idat,iproj,icplx
1138 : : #endif
1139 : :
1140 : : ! *************************************************************************
1141 : :
1142 : 171686 : nprojs = invovl%nprojs
1143 [ + - ]: 171686 : if(gpu_option == ABI_GPU_DISABLED) then
1144 [ + + + + : 69497302 : normprojs = SUM(SUM(proj**2, 1),1)
+ + ]
1145 : 171686 : call xmpi_sum(normprojs, mpi_enreg%comm_fft, ierr)
1146 : : else if(gpu_option == ABI_GPU_OPENMP) then
1147 : : #ifdef HAVE_OPENMP_OFFLOAD
1148 : : !$OMP TARGET ENTER DATA MAP(alloc:errs,precondresid,resid,normprojs)
1149 : : !$OMP TARGET TEAMS DISTRIBUTE MAP(to:normprojs,proj) PRIVATE(idat,sum_tmp)
1150 : : do idat = 1,ndat
1151 : : sum_tmp=0
1152 : : !$OMP PARALLEL DO COLLAPSE(2) REDUCTION(+:sum_tmp) PRIVATE(iproj,icplx)
1153 : : do iproj = 1,nprojs
1154 : : do icplx = 1,cplx
1155 : : sum_tmp = sum_tmp + proj(icplx,iproj,idat)**2
1156 : : end do
1157 : : end do
1158 : : normprojs(idat)=sum_tmp
1159 : : end do
1160 : : !$OMP TARGET UPDATE FROM(normprojs)
1161 : : #endif
1162 : : end if
1163 : :
1164 : : ! Compute work distribution : split nprojs evenly between the fft processors
1165 : : ! On GPU, work isn't shared on npfft so path is the same wether paral_kgb={0,1}
1166 [ + + + - ]: 171686 : if(mpi_enreg%paral_kgb == 1 .and. gpu_option == ABI_GPU_DISABLED) then
1167 [ + + ]: 125208 : array_nlmntot_pp(:) = nprojs / mpi_enreg%nproc_fft
1168 : : ! not enough work, there's MOD(nprojs,mpi_enreg%nproc_fft) tasks left
1169 : : ! assign them to the first ones
1170 [ - + ]: 62460 : array_nlmntot_pp(1:MOD(nprojs,mpi_enreg%nproc_fft)) = array_nlmntot_pp(1:MOD(nprojs,mpi_enreg%nproc_fft)) + 1
1171 [ + + ]: 62604 : ibeg = SUM(array_nlmntot_pp(1:mpi_enreg%me_fft)) + 1
1172 : 62460 : iend = ibeg + array_nlmntot_pp(1+mpi_enreg%me_fft) - 1
1173 : 62460 : nlmntot_this_proc = iend - ibeg + 1
1174 : : else
1175 : 109226 : ibeg = 1
1176 : 109226 : iend = nprojs
1177 : 109226 : nlmntot_this_proc = nprojs
1178 : : end if
1179 : :
1180 [ + - ]: 171686 : if(gpu_option == ABI_GPU_DISABLED) then
1181 [ - + + - : 858430 : ABI_MALLOC(temp_proj, (cplx, nlmntot_this_proc, ndat))
- + + - -
+ + - + -
+ - - + -
+ ]
1182 : : end if
1183 : :
1184 : : ! first guess for sm1proj
1185 : 171686 : call apply_block(ham, cplx, invovl%inv_s_approx, nprojs, ndat, proj, sm1proj, block_sliced, gpu_option)
1186 : :
1187 : 171686 : previous_maxerr = 1.0 ! Avoid uninit value
1188 : :
1189 : : ! Iterative refinement
1190 : : ! TODO use a more efficient iterative algorithm than iterative refinement, use locking
1191 : 171686 : additional_steps_to_take = -1
1192 [ + - ]: 1550561 : do i=1, 30
1193 : : #ifdef FC_NVHPC
1194 : : ! Silly fix for NVHPC 25.1
1195 : : if(ndat == -42) write(100,*) ndat
1196 : : #endif
1197 : : ! compute resid = proj - (D^-1 + PtP)sm1proj
1198 : 1550561 : call apply_block(ham, cplx, invovl%inv_sij, nprojs, ndat, sm1proj, resid, block_sliced, gpu_option)
1199 : :
1200 : : ABI_NVTX_START_RANGE(NVTX_INVOVL_INNER_GEMM)
1201 [ + - ]: 1550561 : if(gpu_option == ABI_GPU_DISABLED) then
1202 [ + - + - : 753397000 : temp_proj = sm1proj(:,ibeg:iend,:)
+ - - + -
- + + + +
+ + ]
1203 : :
1204 : : ! compute matrix multiplication : PtPsm1proj(:,:,1) = invovl%gram * temp_proj(:,:,1)
1205 : : call abi_xgemm('N', 'N', nprojs, ndat, nlmntot_this_proc, cone, &
1206 : : & invovl%gram_projs(:,:,1), nprojs, &
1207 : : & temp_proj(:,:,1), nlmntot_this_proc, czero, &
1208 : : & PtPsm1proj(:,:,1), nprojs, &
1209 : 1550561 : & x_cplx=cplx)
1210 : 1550561 : call xmpi_sum(PtPsm1proj, mpi_enreg%comm_fft, ierr)
1211 [ + + + + : 752330567 : resid = proj - resid - PtPsm1proj
+ + ]
1212 [ # # ]: 0 : else if(gpu_option == ABI_GPU_OPENMP) then
1213 : : ! compute matrix multiplication : PtPsm1proj(:,:,1) = invovl%gram * sm1proj(:,:,1)
1214 : : call abi_xgemm('N', 'N', nprojs, ndat, nlmntot_this_proc, cone, &
1215 : : & invovl%gram_projs, nprojs,&
1216 : : & sm1proj, nlmntot_this_proc, czero, &
1217 : : & PtPsm1proj, nprojs, &
1218 : 0 : & x_cplx=cplx, gpu_option=ABI_GPU_OPENMP)
1219 : :
1220 : : #ifdef HAVE_OPENMP_OFFLOAD
1221 : : !$OMP TARGET TEAMS DISTRIBUTE &
1222 : : !$OMP& PRIVATE(idat) MAP(to:proj,resid,PtPsm1proj)
1223 : : do idat =1, ndat
1224 : : !$OMP PARALLEL DO COLLAPSE(2) PRIVATE(iproj,icplx)
1225 : : do iproj =1, nprojs
1226 : : do icplx = 1,cplx
1227 : : resid(icplx, iproj, idat) = proj(icplx, iproj, idat) - resid(icplx, iproj, idat) - PtPsm1proj(icplx, iproj, idat)
1228 : : end do
1229 : : end do
1230 : : end do
1231 : : #endif
1232 : : end if
1233 : :
1234 : : ! exit check
1235 [ + - ]: 1550561 : if(gpu_option == ABI_GPU_DISABLED) then
1236 [ + + + + : 752330567 : errs = SUM(SUM(resid**2, 1),1)
+ + ]
1237 : 1550561 : call xmpi_sum(errs, mpi_enreg%comm_fft, ierr)
1238 : : else if (gpu_option == ABI_GPU_OPENMP) then
1239 : : #ifdef HAVE_OPENMP_OFFLOAD
1240 : : !$OMP TARGET TEAMS DISTRIBUTE MAP(to:errs,resid) PRIVATE(idat,sum_tmp)
1241 : : do idat = 1,ndat
1242 : : sum_tmp=0
1243 : : !$OMP PARALLEL DO COLLAPSE(2) REDUCTION(+:sum_tmp) PRIVATE(iproj,icplx)
1244 : : do iproj = 1,nprojs
1245 : : do icplx = 1,cplx
1246 : : sum_tmp = sum_tmp + resid(icplx,iproj,idat)**2
1247 : : end do
1248 : : end do
1249 : : errs(idat)=sum_tmp
1250 : : end do
1251 : : !$OMP TARGET UPDATE FROM(errs)
1252 : : #endif
1253 : : end if
1254 : : ABI_NVTX_END_RANGE()
1255 : :
1256 [ + - - + : 14298218 : maxerr = sqrt(MAXVAL(errs/normprojs))
- - + + ]
1257 [ + + + + ]: 1550561 : if(maxerr < invovl_precision .or. additional_steps_to_take == 1) then
1258 : : exit
1259 : : ! We might stall and never get to the specified precision because of machine errors.
1260 : : ! If we got to 1e-10, extrapolate convergence rate and determine the number of additional
1261 : : ! steps to take to reach precision
1262 [ + + + + ]: 1462593 : else if(maxerr < 1e-10 .and. additional_steps_to_take == -1) then
1263 : 165918 : convergence_rate = -LOG(1e-10) / i
1264 [ - + ]: 165918 : additional_steps_to_take = CEILING(-LOG(invovl_precision/1e-10)/convergence_rate) + 1
1265 [ + + ]: 1296675 : else if(additional_steps_to_take > 0) then
1266 [ + + ]: 541092 : if(previous_maxerr<maxerr)exit
1267 : 457374 : additional_steps_to_take = additional_steps_to_take - 1
1268 : : end if
1269 : :
1270 : : ! Stagnation check (see comment on stagnation_tol/max_stagnated_it above).
1271 [ + + ]: 1378875 : if(maxerr > stagnation_tol*previous_maxerr) then
1272 : 2437 : nstagnated = nstagnated + 1
1273 [ - + ]: 2437 : if(nstagnated >= max_stagnated_it) exit
1274 : : else
1275 : : nstagnated = 0
1276 : : end if
1277 : :
1278 : 1378875 : previous_maxerr=maxerr
1279 : :
1280 : : ! add preconditionned residual
1281 : 1378875 : call apply_block(ham, cplx, invovl%inv_s_approx, nprojs, ndat, resid, precondresid, block_sliced, gpu_option)
1282 [ + - ]: 1550561 : if(gpu_option == ABI_GPU_DISABLED) then
1283 [ + + + + : 682833265 : sm1proj = sm1proj + precondresid
+ + ]
1284 [ # # ]: 0 : else if(gpu_option == ABI_GPU_OPENMP) then
1285 : 0 : call abi_xaxpy(cplx*nprojs*ndat, cone, precondresid, 1, sm1proj, 1, gpu_option=ABI_GPU_OPENMP)
1286 : : end if
1287 : : end do
1288 : :
1289 [ + + - + ]: 171686 : if(maxerr >= invovl_precision .and. maxerr >= 1e-10) then
1290 : 0 : write(message, *) 'In invovl, max error was', maxerr, ' after 30 iterations'
1291 : 0 : ABI_WARNING(message)
1292 : : else
1293 : 171686 : write(message,'(a,i2,a,es13.5)') 'Iterative solver in invovl finished in ', i, ' iterations, error', maxerr
1294 : 171686 : call wrtout(std_out,message,'COLL')
1295 : : end if
1296 : :
1297 [ + - ]: 171686 : if(gpu_option == ABI_GPU_DISABLED) then
1298 [ - + ]: 171686 : ABI_FREE(temp_proj)
1299 : : else if(gpu_option == ABI_GPU_OPENMP) then
1300 : : #ifdef HAVE_OPENMP_OFFLOAD
1301 : : !$OMP TARGET EXIT DATA MAP(delete:errs,resid,precondresid,normprojs)
1302 : : #endif
1303 : : end if
1304 : :
1305 [ - + ]: 171686 : end subroutine solve_inner
1306 : : !!***
1307 : :
1308 : : !!****f* m_invovl/solve_inner_sqmr
1309 : : !! NAME
1310 : : !! solve_inner_sqmr
1311 : : !!
1312 : : !! FUNCTION
1313 : : !! Helper function: iteratively solves the inner system using SQMR algorithm
1314 : : !!
1315 : : !! INPUTS
1316 : : !!
1317 : : !! SOURCE
1318 : 6976 : subroutine solve_inner_sqmr(invovl, ham, cplx, mpi_enreg, proj, ndat, sm1proj, PtPsm1proj, block_sliced, gpu_option, invovl_precision)
1319 : :
1320 : : use m_abi_linalg
1321 : :
1322 : : integer,intent(in) :: ndat,cplx
1323 : : type(invovl_kpt_type), intent(in), target :: invovl
1324 : : real(dp), intent(in) :: invovl_precision
1325 : : real(dp), intent(inout) :: proj(cplx, invovl%nprojs,ndat)
1326 : : real(dp), intent(inout), target :: sm1proj(cplx, invovl%nprojs, ndat)
1327 : : real(dp), intent(inout), target :: PtPsm1proj(cplx, invovl%nprojs, ndat)
1328 : 6976 : real(dp), allocatable :: temp_proj(:,:,:)
1329 : : type(mpi_type), intent(in) :: mpi_enreg
1330 : : type(gs_hamiltonian_type),intent(in) :: ham
1331 : : integer, intent(in) :: block_sliced, gpu_option
1332 : :
1333 : 13952 : integer :: array_nlmntot_pp(mpi_enreg%nproc_fft)
1334 : : integer :: nlmntot_this_proc, ibeg, iend, ierr, i, nprojs
1335 : : integer :: nstagnated
1336 : : integer, parameter :: maxit = 30
1337 : : real(dp), parameter :: breakdown_tol = 1.0e-300_dp
1338 : : ! Stagnation check: if the (global, over ndat) residual fails to shrink by
1339 : : ! at least a factor stagnation_tol over max_stagnated_it consecutive
1340 : : ! iterations, further iterations are extremely unlikely to help (this
1341 : : ! typically happens once invovl_precision is set close to, or below, the
1342 : : ! relative residual level attainable in double precision for the given
1343 : : ! conditioning of A) : give up early instead of iterating all the way to
1344 : : ! maxit. Requiring several consecutive non-improving iterations (rather
1345 : : ! than a single one) avoids bailing out on transient slow steps, which are
1346 : : ! common with Krylov-type methods and do not by themselves indicate a
1347 : : ! genuine stall.
1348 : : real(dp), parameter :: stagnation_tol = 0.99_dp
1349 : : integer, parameter :: max_stagnated_it = 3
1350 : : real(dp) :: previous_maxerr
1351 : : ! SQMR work vectors: r is the underlying (BiCG-type) Lanczos residual, t is
1352 : : ! the preconditioned residual (M^-1 r, also reused as the "u" vector of the
1353 : : ! algorithm), q is the search direction, Aq = A q. d is the quasi-minimized
1354 : : ! smoothing correction added to sm1proj at each step, and Ad/rx track the
1355 : : ! *exact* residual (rx = proj - A*sm1proj) of the returned iterate at no
1356 : : ! extra matrix-vector product cost (see comments below).
1357 : 13952 : real(dp) :: r(cplx, invovl%nprojs,ndat), t(cplx, invovl%nprojs,ndat)
1358 : 13952 : real(dp) :: q(cplx, invovl%nprojs,ndat), Aq(cplx, invovl%nprojs,ndat)
1359 : 13952 : real(dp) :: d(cplx, invovl%nprojs,ndat), Ad(cplx, invovl%nprojs,ndat)
1360 : 13952 : real(dp) :: rx(cplx, invovl%nprojs,ndat)
1361 : 13952 : real(dp) :: normprojs(ndat), errs(ndat), maxerr
1362 : 13952 : real(dp) :: tau(ndat), tnorm2(ndat), rho(ndat), theta(ndat), sigma(ndat)
1363 : 13952 : real(dp) :: alpha(ndat), beta(ndat), psi(ndat), theta_old(ndat), rho_old(ndat)
1364 : : character(len=500) :: message
1365 : :
1366 : : #ifdef HAVE_OPENMP_OFFLOAD
1367 : : real(dp) :: sum_tmp
1368 : : integer :: idat,iproj,icplx
1369 : : #endif
1370 : :
1371 : : ! *************************************************************************
1372 : :
1373 : 6976 : nprojs = invovl%nprojs
1374 [ + - ]: 6976 : if(gpu_option == ABI_GPU_DISABLED) then
1375 [ + + + + : 3973952 : normprojs = SUM(SUM(proj**2, 1),1)
+ + ]
1376 : 6976 : call xmpi_sum(normprojs, mpi_enreg%comm_fft, ierr)
1377 : : else if(gpu_option == ABI_GPU_OPENMP) then
1378 : : #ifdef HAVE_OPENMP_OFFLOAD
1379 : : !$OMP TARGET ENTER DATA MAP(alloc:errs,normprojs,r,t,q,Aq,d,Ad,rx, &
1380 : : !$OMP& tau,tnorm2,rho,theta,sigma,alpha,beta,psi,theta_old,rho_old)
1381 : : !$OMP TARGET TEAMS DISTRIBUTE MAP(to:normprojs,proj) PRIVATE(idat,sum_tmp)
1382 : : do idat = 1,ndat
1383 : : sum_tmp=0
1384 : : !$OMP PARALLEL DO COLLAPSE(2) REDUCTION(+:sum_tmp) PRIVATE(iproj,icplx)
1385 : : do iproj = 1,nprojs
1386 : : do icplx = 1,cplx
1387 : : sum_tmp = sum_tmp + proj(icplx,iproj,idat)**2
1388 : : end do
1389 : : end do
1390 : : normprojs(idat)=sum_tmp
1391 : : end do
1392 : : !$OMP TARGET UPDATE FROM(normprojs)
1393 : : #endif
1394 : : end if
1395 : :
1396 : : ! Compute work distribution : split nprojs evenly between the fft processors
1397 : : ! On GPU, work isn't shared on npfft so path is the same wether paral_kgb={0,1}
1398 [ - + - - ]: 6976 : if(mpi_enreg%paral_kgb == 1 .and. gpu_option == ABI_GPU_DISABLED) then
1399 [ # # ]: 0 : array_nlmntot_pp(:) = nprojs / mpi_enreg%nproc_fft
1400 : : ! not enough work, there's MOD(nprojs,mpi_enreg%nproc_fft) tasks left
1401 : : ! assign them to the first ones
1402 [ # # ]: 0 : array_nlmntot_pp(1:MOD(nprojs,mpi_enreg%nproc_fft)) = array_nlmntot_pp(1:MOD(nprojs,mpi_enreg%nproc_fft)) + 1
1403 [ # # ]: 0 : ibeg = SUM(array_nlmntot_pp(1:mpi_enreg%me_fft)) + 1
1404 : 0 : iend = ibeg + array_nlmntot_pp(1+mpi_enreg%me_fft) - 1
1405 : 0 : nlmntot_this_proc = iend - ibeg + 1
1406 : : else
1407 : 6976 : ibeg = 1
1408 : 6976 : iend = nprojs
1409 : 6976 : nlmntot_this_proc = nprojs
1410 : : end if
1411 : :
1412 [ + - ]: 6976 : if(gpu_option == ABI_GPU_DISABLED) then
1413 [ - + + - : 34880 : ABI_MALLOC(temp_proj, (cplx, nlmntot_this_proc, ndat))
- + + - -
+ + - + -
+ - - + -
+ ]
1414 : : end if
1415 : :
1416 : : ! first guess for sm1proj
1417 : 6976 : call apply_block(ham, cplx, invovl%inv_s_approx, nprojs, ndat, proj, sm1proj, block_sliced, gpu_option)
1418 : :
1419 : : ! Solve (D^-1 + PtP) sm1proj = proj with SQMR (symmetric quasi-minimal
1420 : : ! residual, Freund & Nachtigal, "A new Krylov-subspace method for symmetric
1421 : : ! indefinite linear systems", 1994), left-preconditioned by inv_s_approx.
1422 : : ! A = D^-1+PtP is Hermitian but indefinite, and so is the block-diagonal
1423 : : ! preconditioner (built with ZHETRF/ZHETRI in mkinvovl): plain (P)CG/MINRES
1424 : : ! are not guaranteed to work in that setting, whereas SQMR tolerates an
1425 : : ! indefinite preconditioner and converges in markedly fewer iterations than
1426 : : ! the previous Richardson-type iterative refinement.
1427 : : ! See A. Levitt & M. Torrent, https://arxiv.org/abs/1406.4350, section 5.1.
1428 : : !
1429 : : ! All the scalar quantities below (tau, rho, sigma, theta...) are, in exact
1430 : : ! arithmetic, real numbers even though cplx=2 (complex Hermitian case),
1431 : : ! because A and the preconditioner are Hermitian: they are computed with
1432 : : ! dot_per_idat(), which sums v(icplx,iproj,idat)*w(icplx,iproj,idat) over
1433 : : ! icplx without conjugation, which is exactly Re(v^H w) for such quantities.
1434 : : !
1435 : : ! d is the quasi-minimized smoothing correction added to sm1proj at each
1436 : : ! step. Ad and rx are kept consistent with d and sm1proj (rx = proj -
1437 : : ! (D^-1+PtP)*sm1proj exactly) through the same linear recurrence as d,
1438 : : ! reusing Aq that is already computed for the algorithm: this gives the
1439 : : ! *exact* residual of the returned solution at every step, at no extra
1440 : : ! matrix-vector product cost, so that the convergence check below has
1441 : : ! exactly the same meaning as with the previous algorithm.
1442 : :
1443 : 6976 : call compute_Amult(sm1proj, rx)
1444 : 6976 : call vec_sub(proj, rx, r)
1445 : 6976 : call vec_copy(r, rx)
1446 : :
1447 : 6976 : call apply_block(ham, cplx, invovl%inv_s_approx, nprojs, ndat, r, t, block_sliced, gpu_option)
1448 : 6976 : call vec_copy(t, q)
1449 : :
1450 : 6976 : call zero_vec(d)
1451 : 6976 : call zero_vec(Ad)
1452 : 6976 : call zero_scalar(theta)
1453 : :
1454 : 6976 : call dot_per_idat(t, t, tau, need_host=.false.)
1455 : 6976 : call dot_per_idat(t, r, rho, need_host=.false.)
1456 : :
1457 : 6976 : call dot_per_idat(rx, rx, errs)
1458 [ + - - + : 95872 : maxerr = sqrt(MAXVAL(errs/normprojs))
- - + + ]
1459 : :
1460 : 6976 : i = 0
1461 : 6976 : previous_maxerr = maxerr
1462 : 6976 : nstagnated = 0
1463 [ + - ]: 6976 : if(maxerr >= invovl_precision) then
1464 [ + - ]: 40050 : do i=1, maxit
1465 : : #ifdef FC_NVHPC
1466 : : ! Silly fix for NVHPC 25.1
1467 : : if(ndat == -42) write(100,*) ndat
1468 : : #endif
1469 : : ! Aq = A q ; sigma = q . Aq ; alpha = rho/sigma
1470 : 40050 : call compute_Amult(q, Aq)
1471 : 40050 : call dot_per_idat(q, Aq, sigma, need_host=.false.)
1472 : 40050 : call compute_alpha()
1473 : :
1474 : : ! r = r - alpha*Aq
1475 : 40050 : call update_r()
1476 : :
1477 : 40050 : call copy_scalar(theta_old, theta)
1478 : : ! t = M^-1 r (preconditioned residual, doubles as "u" below since we use
1479 : : ! left preconditioning)
1480 : 40050 : call apply_block(ham, cplx, invovl%inv_s_approx, nprojs, ndat, r, t, block_sliced, gpu_option)
1481 : 40050 : call dot_per_idat(t, t, tnorm2, need_host=.false.)
1482 : 40050 : call compute_theta_psi_tau()
1483 : :
1484 : : ! d = psi*theta_old*d + psi*alpha*q ; sm1proj = sm1proj + d
1485 : 40050 : call update_d_x()
1486 : : ! Ad = psi*theta_old*Ad + psi*alpha*Aq ; rx = rx - Ad (keeps rx exact)
1487 : 40050 : call update_Ad_rx()
1488 : :
1489 : 40050 : call dot_per_idat(rx, rx, errs)
1490 [ + - - + : 570204 : maxerr = sqrt(MAXVAL(errs/normprojs))
- - + + ]
1491 [ + + ]: 40050 : if(maxerr < invovl_precision) exit
1492 : :
1493 : : ! Stagnation check (see comment on stagnation_tol/max_stagnated_it above).
1494 [ + + ]: 33074 : if(maxerr > stagnation_tol*previous_maxerr) then
1495 : 8 : nstagnated = nstagnated + 1
1496 [ - + ]: 8 : if(nstagnated >= max_stagnated_it) exit
1497 : : else
1498 : : nstagnated = 0
1499 : : end if
1500 : 33074 : previous_maxerr = maxerr
1501 : :
1502 : 33074 : call copy_scalar(rho_old, rho)
1503 : : ! rho = t . r ; beta = rho/rho_old ; q = t + beta*q
1504 : 33074 : call dot_per_idat(t, r, rho, need_host=.false.)
1505 : 33074 : call compute_beta()
1506 : 40050 : call update_q()
1507 : : end do
1508 : : end if
1509 : :
1510 : : ! Recover PtPsm1proj = PtP*sm1proj from bookkeeping instead of an extra GEMM:
1511 : : ! proj - rx = (D^-1+PtP)*sm1proj, and D^-1*sm1proj is cheap (block-diagonal).
1512 : 6976 : call apply_block(ham, cplx, invovl%inv_sij, nprojs, ndat, sm1proj, r, block_sliced, gpu_option)
1513 : 6976 : call vec_sub(proj, rx, t)
1514 : 6976 : call vec_sub(t, r, PtPsm1proj)
1515 : :
1516 [ - + - - ]: 6976 : if(maxerr >= invovl_precision .and. maxerr >= 1e-10) then
1517 : 0 : write(message, *) 'In invovl, max error was', maxerr, ' after ', i, ' iterations'
1518 : 0 : ABI_WARNING(message)
1519 : : else
1520 : 6976 : write(message,'(a,i2,a,es13.5)') 'Iterative solver in invovl finished in ', i, ' iterations, error', maxerr
1521 : : end if
1522 : 6976 : call wrtout(std_out,message,'COLL')
1523 : 6976 : flush(std_out)
1524 : :
1525 [ + - - + ]: 13952 : if(gpu_option == ABI_GPU_DISABLED) then
1526 [ - + ]: 6976 : ABI_FREE(temp_proj)
1527 : : else if(gpu_option == ABI_GPU_OPENMP) then
1528 : : #ifdef HAVE_OPENMP_OFFLOAD
1529 : : !$OMP TARGET EXIT DATA MAP(delete:errs,normprojs,r,t,q,Aq,d,Ad,rx, &
1530 : : !$OMP& tau,tnorm2,rho,theta,sigma,alpha,beta,psi,theta_old,rho_old)
1531 : : #endif
1532 : : end if
1533 : :
1534 : : contains
1535 : :
1536 : 47026 : subroutine compute_Amult(x, y)
1537 : : ! y := (D^-1 + PtP) x. Uses PtPsm1proj as the GEMM scratch buffer, exactly
1538 : : ! as the previous iterative refinement did.
1539 : : real(dp), intent(inout) :: x(cplx,nprojs,ndat)
1540 : : real(dp), intent(inout) :: y(cplx,nprojs,ndat)
1541 : : integer :: ierr_l
1542 : :
1543 : 47026 : call apply_block(ham, cplx, invovl%inv_sij, nprojs, ndat, x, y, block_sliced, gpu_option)
1544 : :
1545 : : ABI_NVTX_START_RANGE(NVTX_INVOVL_INNER_GEMM)
1546 [ + - ]: 47026 : if(gpu_option == ABI_GPU_DISABLED) then
1547 [ + - + - : 27819868 : temp_proj = x(:,ibeg:iend,:)
+ - - + -
- + + + +
+ + ]
1548 : :
1549 : : ! compute matrix multiplication : PtPsm1proj(:,:,1) = invovl%gram * temp_proj(:,:,1)
1550 : : call abi_xgemm('N', 'N', nprojs, ndat, nlmntot_this_proc, cone, &
1551 : : & invovl%gram_projs(:,:,1), nprojs, &
1552 : : & temp_proj(:,:,1), nlmntot_this_proc, czero, &
1553 : : & PtPsm1proj(:,:,1), nprojs, &
1554 : 47026 : & x_cplx=cplx)
1555 : 47026 : call xmpi_sum(PtPsm1proj, mpi_enreg%comm_fft, ierr_l)
1556 [ + + + + : 27772842 : y = y + PtPsm1proj
+ + ]
1557 [ # # ]: 0 : else if(gpu_option == ABI_GPU_OPENMP) then
1558 : : ! compute matrix multiplication : PtPsm1proj(:,:,1) = invovl%gram * x(:,:,1)
1559 : : call abi_xgemm('N', 'N', nprojs, ndat, nlmntot_this_proc, cone, &
1560 : : & invovl%gram_projs, nprojs,&
1561 : : & x, nlmntot_this_proc, czero, &
1562 : : & PtPsm1proj, nprojs, &
1563 : 0 : & x_cplx=cplx, gpu_option=ABI_GPU_OPENMP)
1564 : :
1565 : 0 : call abi_xaxpy(cplx*nprojs*ndat, cone, PtPsm1proj, 1, y, 1, gpu_option=gpu_option)
1566 : : end if
1567 : : ABI_NVTX_END_RANGE()
1568 : 47026 : end subroutine compute_Amult
1569 : :
1570 : 174152 : subroutine dot_per_idat(v, w, out_arr, need_host)
1571 : : ! out_arr(idat) = sum_{iproj,icplx} v(icplx,iproj,idat)*w(icplx,iproj,idat)
1572 : : ! need_host (GPU only, default .true.): whether out_arr must be made
1573 : : ! available on the host after this call. Most call sites only feed the
1574 : : ! result into further device-resident scalar arithmetic (see
1575 : : ! compute_alpha/compute_theta_psi_tau/compute_beta below) and can skip the
1576 : : ! blocking host<->device round trip entirely; only the calls computing
1577 : : ! errs (used for the host-side convergence/stagnation checks) need it.
1578 : : real(dp), intent(in) :: v(cplx,nprojs,ndat), w(cplx,nprojs,ndat)
1579 : : real(dp), intent(out) :: out_arr(ndat)
1580 : : logical, intent(in), optional :: need_host
1581 : : integer :: ierr_l
1582 : : logical :: need_host_
1583 : : #ifdef HAVE_OPENMP_OFFLOAD
1584 : : integer :: idat_l, iproj_l, icplx_l
1585 : : real(dp) :: sum_tmp_l
1586 : : #endif
1587 : :
1588 : 174152 : need_host_ = .true. ; if(present(need_host)) need_host_ = need_host
1589 [ + - ]: 174152 : if(gpu_option == ABI_GPU_DISABLED) then
1590 [ + + + + : 103143464 : out_arr = SUM(SUM(v*w, 1), 1)
+ + ]
1591 : 174152 : call xmpi_sum(out_arr, mpi_enreg%comm_fft, ierr_l)
1592 : : else if(gpu_option == ABI_GPU_OPENMP) then
1593 : : #ifdef HAVE_OPENMP_OFFLOAD
1594 : : !$OMP TARGET TEAMS DISTRIBUTE MAP(to:out_arr,v,w) PRIVATE(idat_l,sum_tmp_l)
1595 : : do idat_l = 1,ndat
1596 : : sum_tmp_l=0
1597 : : !$OMP PARALLEL DO COLLAPSE(2) REDUCTION(+:sum_tmp_l) PRIVATE(iproj_l,icplx_l)
1598 : : do iproj_l = 1,nprojs
1599 : : do icplx_l = 1,cplx
1600 : : sum_tmp_l = sum_tmp_l + v(icplx_l,iproj_l,idat_l)*w(icplx_l,iproj_l,idat_l)
1601 : : end do
1602 : : end do
1603 : : out_arr(idat_l)=sum_tmp_l
1604 : : end do
1605 : : if(need_host_) then
1606 : : !$OMP TARGET UPDATE FROM(out_arr)
1607 : : end if
1608 : : #endif
1609 : : end if
1610 : 174152 : end subroutine dot_per_idat
1611 : :
1612 : 6976 : subroutine zero_scalar(y)
1613 : : ! y := 0 (ndat-sized scalar work array, e.g. theta)
1614 : : real(dp), intent(out) :: y(ndat)
1615 : : #ifdef HAVE_OPENMP_OFFLOAD
1616 : : integer :: idat_l
1617 : : #endif
1618 : :
1619 [ + - ]: 6976 : if(gpu_option == ABI_GPU_DISABLED) then
1620 [ + + ]: 88896 : y = zero
1621 : : else if(gpu_option == ABI_GPU_OPENMP) then
1622 : : #ifdef HAVE_OPENMP_OFFLOAD
1623 : : !$OMP TARGET TEAMS DISTRIBUTE PARALLEL DO PRIVATE(idat_l) MAP(to:y)
1624 : : do idat_l = 1,ndat
1625 : : y(idat_l) = zero
1626 : : end do
1627 : : #endif
1628 : : end if
1629 : 6976 : end subroutine zero_scalar
1630 : :
1631 : 73124 : subroutine copy_scalar(y, x)
1632 : : ! y := x (ndat-sized scalar work arrays, e.g. theta_old := theta). Done on
1633 : : ! device (instead of a plain host assignment) so the device-resident copy
1634 : : ! stays in sync without an extra host<->device round trip.
1635 : : real(dp), intent(out) :: y(ndat)
1636 : : real(dp), intent(in) :: x(ndat)
1637 : : #ifdef HAVE_OPENMP_OFFLOAD
1638 : : integer :: idat_l
1639 : : #endif
1640 : :
1641 [ + - ]: 73124 : if(gpu_option == ABI_GPU_DISABLED) then
1642 [ + + ]: 971412 : y = x
1643 : : else if(gpu_option == ABI_GPU_OPENMP) then
1644 : : #ifdef HAVE_OPENMP_OFFLOAD
1645 : : !$OMP TARGET TEAMS DISTRIBUTE PARALLEL DO PRIVATE(idat_l) MAP(to:y,x)
1646 : : do idat_l = 1,ndat
1647 : : y(idat_l) = x(idat_l)
1648 : : end do
1649 : : #endif
1650 : : end if
1651 : 73124 : end subroutine copy_scalar
1652 : :
1653 : 40050 : subroutine compute_alpha()
1654 : : ! sigma := sign(breakdown_tol,sigma) if too small ; alpha := rho/sigma.
1655 : : ! Kept entirely device-resident: sigma/rho/alpha are all already present
1656 : : ! on the device (never synced to host), so no round trip is needed here.
1657 : : #ifdef HAVE_OPENMP_OFFLOAD
1658 : : integer :: idat_l
1659 : : #endif
1660 : :
1661 [ + - ]: 40050 : if(gpu_option == ABI_GPU_DISABLED) then
1662 [ + + - + ]: 530154 : where(abs(sigma) < breakdown_tol) sigma = sign(breakdown_tol, sigma)
1663 [ + + ]: 530154 : alpha = rho / sigma
1664 : : else if(gpu_option == ABI_GPU_OPENMP) then
1665 : : #ifdef HAVE_OPENMP_OFFLOAD
1666 : : !$OMP TARGET TEAMS DISTRIBUTE PARALLEL DO PRIVATE(idat_l) MAP(to:sigma,rho,alpha)
1667 : : do idat_l = 1,ndat
1668 : : if(abs(sigma(idat_l)) < breakdown_tol) sigma(idat_l) = sign(breakdown_tol, sigma(idat_l))
1669 : : alpha(idat_l) = rho(idat_l) / sigma(idat_l)
1670 : : end do
1671 : : #endif
1672 : : end if
1673 : 40050 : end subroutine compute_alpha
1674 : :
1675 : 40050 : subroutine compute_theta_psi_tau()
1676 : : ! tau := sign(breakdown_tol,tau) if too small ; theta := tnorm2/tau ;
1677 : : ! psi := 1/(1+theta) ; tau := tnorm2*psi. Kept entirely device-resident.
1678 : : #ifdef HAVE_OPENMP_OFFLOAD
1679 : : integer :: idat_l
1680 : : #endif
1681 : :
1682 [ + - ]: 40050 : if(gpu_option == ABI_GPU_DISABLED) then
1683 [ + + - + ]: 530154 : where(abs(tau) < breakdown_tol) tau = sign(breakdown_tol, tau)
1684 [ + + ]: 530154 : theta = tnorm2 / tau
1685 [ + + ]: 530154 : psi = one / (one + theta)
1686 [ + + ]: 530154 : tau = tnorm2 * psi
1687 : : else if(gpu_option == ABI_GPU_OPENMP) then
1688 : : #ifdef HAVE_OPENMP_OFFLOAD
1689 : : !$OMP TARGET TEAMS DISTRIBUTE PARALLEL DO PRIVATE(idat_l) &
1690 : : !$OMP& MAP(to:tau,theta,psi,tnorm2)
1691 : : do idat_l = 1,ndat
1692 : : if(abs(tau(idat_l)) < breakdown_tol) tau(idat_l) = sign(breakdown_tol, tau(idat_l))
1693 : : theta(idat_l) = tnorm2(idat_l) / tau(idat_l)
1694 : : psi(idat_l) = one / (one + theta(idat_l))
1695 : : tau(idat_l) = tnorm2(idat_l) * psi(idat_l)
1696 : : end do
1697 : : #endif
1698 : : end if
1699 : 40050 : end subroutine compute_theta_psi_tau
1700 : :
1701 : 33074 : subroutine compute_beta()
1702 : : ! rho_old := sign(breakdown_tol,rho_old) if too small ; beta := rho/rho_old.
1703 : : ! Kept entirely device-resident.
1704 : : #ifdef HAVE_OPENMP_OFFLOAD
1705 : : integer :: idat_l
1706 : : #endif
1707 : :
1708 [ + - ]: 33074 : if(gpu_option == ABI_GPU_DISABLED) then
1709 [ + + - + ]: 441258 : where(abs(rho_old) < breakdown_tol) rho_old = sign(breakdown_tol, rho_old)
1710 [ + + ]: 441258 : beta = rho / rho_old
1711 : : else if(gpu_option == ABI_GPU_OPENMP) then
1712 : : #ifdef HAVE_OPENMP_OFFLOAD
1713 : : !$OMP TARGET TEAMS DISTRIBUTE PARALLEL DO PRIVATE(idat_l) MAP(to:rho_old,rho,beta)
1714 : : do idat_l = 1,ndat
1715 : : if(abs(rho_old(idat_l)) < breakdown_tol) rho_old(idat_l) = sign(breakdown_tol, rho_old(idat_l))
1716 : : beta(idat_l) = rho(idat_l) / rho_old(idat_l)
1717 : : end do
1718 : : #endif
1719 : : end if
1720 : 33074 : end subroutine compute_beta
1721 : :
1722 : 20928 : subroutine vec_sub(a, b, y)
1723 : : ! y := a - b (full array, no per-idat scaling)
1724 : : real(dp), intent(in) :: a(cplx,nprojs,ndat), b(cplx,nprojs,ndat)
1725 : : real(dp), intent(out) :: y(cplx,nprojs,ndat)
1726 : : #ifdef HAVE_OPENMP_OFFLOAD
1727 : : integer :: idat_l, iproj_l, icplx_l
1728 : : #endif
1729 : :
1730 [ + - ]: 20928 : if(gpu_option == ABI_GPU_DISABLED) then
1731 [ + + + + : 11921856 : y = a - b
+ + ]
1732 : : else if(gpu_option == ABI_GPU_OPENMP) then
1733 : : #ifdef HAVE_OPENMP_OFFLOAD
1734 : : !$OMP TARGET TEAMS DISTRIBUTE PARALLEL DO COLLAPSE(3) &
1735 : : !$OMP& PRIVATE(idat_l,iproj_l,icplx_l) MAP(to:y,a,b)
1736 : : do idat_l = 1,ndat
1737 : : do iproj_l = 1,nprojs
1738 : : do icplx_l = 1,cplx
1739 : : y(icplx_l,iproj_l,idat_l) = a(icplx_l,iproj_l,idat_l) - b(icplx_l,iproj_l,idat_l)
1740 : : end do
1741 : : end do
1742 : : end do
1743 : : #endif
1744 : : end if
1745 : 20928 : end subroutine vec_sub
1746 : :
1747 : 13952 : subroutine vec_copy(a, y)
1748 : : ! y := a
1749 : : real(dp), intent(in) :: a(cplx,nprojs,ndat)
1750 : : real(dp), intent(out) :: y(cplx,nprojs,ndat)
1751 : :
1752 [ + - ]: 13952 : if(gpu_option == ABI_GPU_DISABLED) then
1753 [ + + + + : 7947904 : y = a
+ + ]
1754 : : else if(gpu_option == ABI_GPU_OPENMP) then
1755 : : #ifdef HAVE_OPENMP_OFFLOAD
1756 : : call gpu_copy(y, a, int(cplx,c_size_t)*nprojs*ndat)
1757 : : #endif
1758 : : end if
1759 : 13952 : end subroutine vec_copy
1760 : :
1761 : 13952 : subroutine zero_vec(y)
1762 : : ! y := 0
1763 : : real(dp), intent(out) :: y(cplx,nprojs,ndat)
1764 : :
1765 [ + - ]: 13952 : if(gpu_option == ABI_GPU_DISABLED) then
1766 [ + + + + : 7947904 : y = zero
+ + ]
1767 : : else if(gpu_option == ABI_GPU_OPENMP) then
1768 : : #ifdef HAVE_OPENMP_OFFLOAD
1769 : : call gpu_set_to_zero(y,int(cplx,c_size_t)*nprojs*ndat)
1770 : : #endif
1771 : : end if
1772 : 13952 : end subroutine zero_vec
1773 : :
1774 : 40050 : subroutine update_r()
1775 : : ! r := r - alpha(idat)*Aq. alpha/r/Aq are all host-associated, already
1776 : : ! device-resident arrays: no coefficient argument is passed (an expression
1777 : : ! like "-alpha" would force a host-side compiler temporary, defeating the
1778 : : ! whole point of keeping alpha device-resident), and there is no
1779 : : ! TARGET UPDATE TO left to do.
1780 : : integer :: idat_l
1781 : : #ifdef HAVE_OPENMP_OFFLOAD
1782 : : integer :: iproj_l, icplx_l
1783 : : #endif
1784 : :
1785 [ + - ]: 40050 : if(gpu_option == ABI_GPU_DISABLED) then
1786 [ + + ]: 530154 : do idat_l = 1,ndat
1787 [ + + + + ]: 23798890 : r(:,:,idat_l) = r(:,:,idat_l) - alpha(idat_l)*Aq(:,:,idat_l)
1788 : : end do
1789 : : else if(gpu_option == ABI_GPU_OPENMP) then
1790 : : #ifdef HAVE_OPENMP_OFFLOAD
1791 : : !$OMP TARGET TEAMS DISTRIBUTE PARALLEL DO COLLAPSE(2) PRIVATE(idat_l,iproj_l,icplx_l) MAP(to:r,Aq,alpha)
1792 : : do idat_l = 1,ndat
1793 : : do iproj_l = 1,nprojs
1794 : : do icplx_l = 1,cplx
1795 : : r(icplx_l,iproj_l,idat_l) = r(icplx_l,iproj_l,idat_l) - alpha(idat_l)*Aq(icplx_l,iproj_l,idat_l)
1796 : : end do
1797 : : end do
1798 : : end do
1799 : : #endif
1800 : : end if
1801 : 40050 : end subroutine update_r
1802 : :
1803 : 40050 : subroutine update_d_x()
1804 : : ! d := psi(idat)*theta_old(idat)*d + psi(idat)*alpha(idat)*q ;
1805 : : ! sm1proj := sm1proj + d. No arguments: psi/theta_old/alpha are
1806 : : ! host-associated device-resident arrays, and the products are formed
1807 : : ! inside the kernel instead of being passed in (which would force
1808 : : ! host-side temporaries for "psi*theta_old"/"psi*alpha" and lose device
1809 : : ! residency).
1810 : : integer :: idat_l
1811 : : #ifdef HAVE_OPENMP_OFFLOAD
1812 : : integer :: iproj_l, icplx_l
1813 : : #endif
1814 : :
1815 [ + - ]: 40050 : if(gpu_option == ABI_GPU_DISABLED) then
1816 [ + + ]: 530154 : do idat_l = 1,ndat
1817 [ + + + + ]: 23798890 : d(:,:,idat_l) = psi(idat_l)*theta_old(idat_l)*d(:,:,idat_l) + psi(idat_l)*alpha(idat_l)*q(:,:,idat_l)
1818 : : end do
1819 [ + + + + : 23798890 : sm1proj = sm1proj + d
+ + ]
1820 : : else if(gpu_option == ABI_GPU_OPENMP) then
1821 : : #ifdef HAVE_OPENMP_OFFLOAD
1822 : : !$OMP TARGET TEAMS DISTRIBUTE PARALLEL DO COLLAPSE(3) &
1823 : : !$OMP& PRIVATE(idat_l,iproj_l,icplx_l) MAP(to:d,q,sm1proj,psi,theta_old,alpha)
1824 : : do idat_l = 1,ndat
1825 : : do iproj_l = 1,nprojs
1826 : : do icplx_l = 1,cplx
1827 : : d(icplx_l,iproj_l,idat_l) = psi(idat_l)*theta_old(idat_l)*d(icplx_l,iproj_l,idat_l) + &
1828 : : & psi(idat_l)*alpha(idat_l)*q(icplx_l,iproj_l,idat_l)
1829 : : sm1proj(icplx_l,iproj_l,idat_l) = sm1proj(icplx_l,iproj_l,idat_l) + d(icplx_l,iproj_l,idat_l)
1830 : : end do
1831 : : end do
1832 : : end do
1833 : : #endif
1834 : : end if
1835 : 40050 : end subroutine update_d_x
1836 : :
1837 : 40050 : subroutine update_Ad_rx()
1838 : : ! Ad := psi(idat)*theta_old(idat)*Ad + psi(idat)*alpha(idat)*Aq ;
1839 : : ! rx := rx - Ad. Same no-argument rationale as update_d_x.
1840 : : integer :: idat_l
1841 : : #ifdef HAVE_OPENMP_OFFLOAD
1842 : : integer :: iproj_l, icplx_l
1843 : : #endif
1844 : :
1845 [ + - ]: 40050 : if(gpu_option == ABI_GPU_DISABLED) then
1846 [ + + ]: 530154 : do idat_l = 1,ndat
1847 [ + + + + ]: 23798890 : Ad(:,:,idat_l) = psi(idat_l)*theta_old(idat_l)*Ad(:,:,idat_l) + psi(idat_l)*alpha(idat_l)*Aq(:,:,idat_l)
1848 : : end do
1849 [ + + + + : 23798890 : rx = rx - Ad
+ + ]
1850 : : else if(gpu_option == ABI_GPU_OPENMP) then
1851 : : #ifdef HAVE_OPENMP_OFFLOAD
1852 : : !$OMP TARGET TEAMS DISTRIBUTE PARALLEL DO COLLAPSE(3) &
1853 : : !$OMP& PRIVATE(idat_l,iproj_l,icplx_l) MAP(to:Ad,Aq,rx,psi,theta_old,alpha)
1854 : : do idat_l = 1,ndat
1855 : : do iproj_l = 1,nprojs
1856 : : do icplx_l = 1,cplx
1857 : : Ad(icplx_l,iproj_l,idat_l) = psi(idat_l)*theta_old(idat_l)*Ad(icplx_l,iproj_l,idat_l) + &
1858 : : & psi(idat_l)*alpha(idat_l)*Aq(icplx_l,iproj_l,idat_l)
1859 : : rx(icplx_l,iproj_l,idat_l) = rx(icplx_l,iproj_l,idat_l) - Ad(icplx_l,iproj_l,idat_l)
1860 : : end do
1861 : : end do
1862 : : end do
1863 : : #endif
1864 : : end if
1865 : 40050 : end subroutine update_Ad_rx
1866 : :
1867 : 33074 : subroutine update_q()
1868 : : ! q := t + beta(idat)*q. beta is host-associated and already
1869 : : ! device-resident (computed in place by compute_beta).
1870 : : integer :: idat_l
1871 : : #ifdef HAVE_OPENMP_OFFLOAD
1872 : : integer :: iproj_l, icplx_l
1873 : : #endif
1874 : :
1875 [ + - ]: 33074 : if(gpu_option == ABI_GPU_DISABLED) then
1876 [ + + ]: 441258 : do idat_l = 1,ndat
1877 [ + + + + ]: 19824938 : q(:,:,idat_l) = t(:,:,idat_l) + beta(idat_l)*q(:,:,idat_l)
1878 : : end do
1879 : : else if(gpu_option == ABI_GPU_OPENMP) then
1880 : : #ifdef HAVE_OPENMP_OFFLOAD
1881 : : !$OMP TARGET TEAMS DISTRIBUTE PARALLEL DO COLLAPSE(3) &
1882 : : !$OMP& PRIVATE(idat_l,iproj_l,icplx_l) MAP(to:q,t,beta)
1883 : : do idat_l = 1,ndat
1884 : : do iproj_l = 1,nprojs
1885 : : do icplx_l = 1,cplx
1886 : : q(icplx_l,iproj_l,idat_l) = t(icplx_l,iproj_l,idat_l) + beta(idat_l)*q(icplx_l,iproj_l,idat_l)
1887 : : end do
1888 : : end do
1889 : : end do
1890 : : #endif
1891 : : end if
1892 : 33074 : end subroutine update_q
1893 : :
1894 : : end subroutine solve_inner_sqmr
1895 : : !!***
1896 : :
1897 : : !!****f* m_invovl/apply_block
1898 : : !! NAME
1899 : : !! apply_block
1900 : : !!
1901 : : !! FUNCTION
1902 : : !! Helper function: applies a block-diagonal matrix mat(lmnmax, lmnmax, ntypat)
1903 : : !!
1904 : : !! INPUTS
1905 : : !!
1906 : : !! SOURCE
1907 : 3209126 : subroutine apply_block(ham, cplx, mat, nprojs, ndat, x, y, block_sliced, gpu_option)
1908 : :
1909 : : use m_abi_linalg
1910 : :
1911 : : integer,intent(in) :: ndat, nprojs, cplx
1912 : : real(dp), intent(inout), target :: x(cplx, nprojs, ndat), y(cplx, nprojs, ndat)
1913 : : type(gs_hamiltonian_type),intent(in) :: ham
1914 : : real(dp), intent(in), target :: mat(cplx, ham%lmnmax, ham%lmnmax, ham%ntypat)
1915 : : integer, intent(in) :: block_sliced, gpu_option
1916 : :
1917 : : integer :: nlmn, shift, itypat, idat
1918 : 3209126 : real(dp),pointer :: work_x(:,:),work_y(:,:)
1919 : 3209126 : real(dp), contiguous, pointer :: mat_ptr(:,:,:)
1920 : :
1921 : : ! *************************************************************************
1922 : :
1923 : 3209126 : if (block_sliced == 1) then
1924 : :
1925 [ + + ]: 26208684 : do idat = 1, ndat
1926 : 23077616 : shift = 1
1927 [ + + ]: 57915764 : do itypat=1, ham%ntypat
1928 [ + + + + ]: 305616460 : nlmn = count(ham%indlmn(3,:,itypat)>0)
1929 : : !! apply mat to all atoms at once
1930 : : ! perform natom multiplications of size nlmn
1931 : : ! compute y = mat*x
1932 : 31707080 : work_x => x(:, shift:shift+nlmn*ham%nattyp(itypat)-1, idat)
1933 : 31707080 : work_y => y(:, shift:shift+nlmn*ham%nattyp(itypat)-1, idat)
1934 : 31707080 : mat_ptr => mat(:, :, :, itypat)
1935 [ + + ]: 31707080 : if(cplx == 2) then
1936 [ + - ]: 28701952 : if(gpu_option /= ABI_GPU_OPENMP) then
1937 : : call ZHEMM('L','U', nlmn, ham%nattyp(itypat), cone, &
1938 : : & mat_ptr, ham%lmnmax, &
1939 : : & work_x, nlmn, czero, &
1940 [ - + - + ]: 28701952 : & work_y, nlmn)
1941 : : else
1942 : : #ifdef HAVE_OPENMP_OFFLOAD
1943 : : !$OMP TARGET DATA USE_DEVICE_ADDR(mat_ptr,work_x,work_y)
1944 : : call abi_gpu_zhemm('L','U', nlmn, ham%nattyp(itypat), cone, &
1945 : : c_loc(mat_ptr), ham%lmnmax, &
1946 : : c_loc(work_x), nlmn, czero, &
1947 : : c_loc(work_y), nlmn)
1948 : : !$OMP END TARGET DATA
1949 : : #endif
1950 : : end if
1951 : : else
1952 [ + - ]: 3005128 : if(gpu_option /= ABI_GPU_OPENMP) then
1953 : : call DSYMM('L','U', nlmn, ham%nattyp(itypat), one, &
1954 : : & mat_ptr, ham%lmnmax, &
1955 : : & work_x, nlmn, zero, &
1956 [ - + - + ]: 3005128 : & work_y, nlmn)
1957 : : else
1958 : : #ifdef HAVE_OPENMP_OFFLOAD
1959 : : !$OMP TARGET DATA USE_DEVICE_ADDR(mat_ptr,work_x,work_y)
1960 : : call abi_gpu_xsymm(cplx, 'L','U', nlmn, ham%nattyp(itypat), cone, &
1961 : : c_loc(mat_ptr), ham%lmnmax, &
1962 : : c_loc(work_x), nlmn, czero, &
1963 : : c_loc(work_y), nlmn)
1964 : : !$OMP END TARGET DATA
1965 : : #endif
1966 : : end if
1967 : : end if
1968 : 54784696 : shift = shift + nlmn*ham%nattyp(itypat)
1969 : : end do
1970 : : end do
1971 : :
1972 : : else ! block_sliced = 0
1973 : :
1974 : : shift = 1
1975 [ + + ]: 234174 : do itypat=1, ham%ntypat
1976 [ + + + - ]: 1405044 : nlmn = count(ham%indlmn(3,:,itypat)>0)
1977 : 156116 : mat_ptr => mat(:, :, :, itypat)
1978 : : !! apply mat to all atoms at once, all idat at once
1979 : : ! perform natom multiplications of size nlmn
1980 : : ! be careful here matrix extracted from x and y are not memory contiguous
1981 : : ! the GPU version use batched GEMM with strides to workaround this
1982 [ + - ]: 156116 : if(gpu_option == ABI_GPU_DISABLED) then
1983 [ + + ]: 156116 : if(cplx == 2) then
1984 : : call ZHEMM('L','U', nlmn, ham%nattyp(itypat)*ndat, cone, &
1985 : : & mat(:, :, :, itypat), ham%lmnmax, &
1986 : : & x(:, shift:shift+nlmn*ham%nattyp(itypat)-1, 1:ndat), nlmn, czero, &
1987 [ + - + - : 117843120 : & y(:, shift:shift+nlmn*ham%nattyp(itypat)-1, 1:ndat), nlmn)
+ + + + +
+ + - + -
+ + + + +
+ + - + +
+ + + + +
- + + + +
+ + ]
1988 : : else
1989 : : call DSYMM('L','U', nlmn, ham%nattyp(itypat)*ndat, one, &
1990 : : & mat(:, :, :, itypat), ham%lmnmax, &
1991 : : & x(:, shift:shift+nlmn*ham%nattyp(itypat)-1, 1:ndat), nlmn, zero, &
1992 [ + - + - : 4902820 : & y(:, shift:shift+nlmn*ham%nattyp(itypat)-1, 1:ndat), nlmn)
+ + + + +
+ + - + -
+ + + + +
+ + - + +
+ + + + +
- + + + +
+ + ]
1993 : : end if
1994 : : else if(gpu_option == ABI_GPU_OPENMP) then
1995 : : #ifdef HAVE_OPENMP_OFFLOAD
1996 : : !$OMP TARGET DATA USE_DEVICE_ADDR(mat_ptr,x,y)
1997 : : call abi_gpu_xgemm_strided(cplx, 'N','N', &
1998 : : nlmn, ham%nattyp(itypat), nlmn, cone, &
1999 : : c_loc(mat_ptr), ham%lmnmax, 0, &
2000 : : c_loc(x(1,shift,1)), nlmn, nprojs, &
2001 : : czero, &
2002 : : c_loc(y(1,shift,1)), nlmn, nprojs, ndat)
2003 : : !$OMP END TARGET DATA
2004 : : #endif
2005 : : end if
2006 : 234174 : shift = shift + nlmn*ham%nattyp(itypat)
2007 : : end do
2008 : :
2009 : : end if
2010 : :
2011 [ + + ]: 3209126 : end subroutine apply_block
2012 : : !!***
2013 : :
2014 : 0 : function invovl_ompgpu_work_mem(ham, ndat) result(req_mem)
2015 : :
2016 : : type(gs_hamiltonian_type), intent(in) :: ham
2017 : : integer, intent(in) :: ndat
2018 : : integer :: nprojs, cplx, itypat
2019 : : integer(kind=c_size_t) :: req_mem
2020 : :
2021 : 0 : nprojs = 0
2022 [ # # ]: 0 : do itypat=1,ham%ntypat
2023 [ # # # # ]: 0 : nprojs = nprojs + count(ham%indlmn(3,:,itypat)>0)*ham%nattyp(itypat)
2024 : : end do
2025 [ # # ]: 0 : cplx = 2; if(ham%istwf_k == 2) cplx = 1
2026 : :
2027 : 0 : req_mem = 0
2028 : 0 : req_mem = req_mem + dp * cplx * int(nprojs, c_size_t) * int(ndat, c_size_t) ! proj
2029 : 0 : req_mem = req_mem + dp * cplx * int(nprojs, c_size_t) * int(ndat, c_size_t) ! sm1proj
2030 : 0 : req_mem = req_mem + dp * cplx * int(nprojs, c_size_t) * int(ndat, c_size_t) ! PtPsm1proj
2031 : : ! solve_inner (SQMR): r, t, q, Aq, d, Ad, rx
2032 : 0 : req_mem = req_mem + 7 * dp * cplx * int(nprojs, c_size_t) * int(ndat, c_size_t)
2033 : : ! solve_inner (SQMR scalars): tau, tnorm2, rho, theta, sigma, alpha, beta, psi, theta_old, rho_old, errs, normprojs
2034 : 0 : req_mem = req_mem + 12 * dp * int(ndat, c_size_t)
2035 : :
2036 : 0 : end function invovl_ompgpu_work_mem
2037 : :
2038 : 0 : function invovl_ompgpu_static_mem(ham) result(req_mem)
2039 : :
2040 : : type(gs_hamiltonian_type), intent(in) :: ham
2041 : : integer :: nprojs, cplx, itypat
2042 : : integer(kind=c_size_t) :: req_mem
2043 : :
2044 : 0 : nprojs = 0
2045 [ # # ]: 0 : do itypat=1,ham%ntypat
2046 [ # # # # ]: 0 : nprojs = nprojs + count(ham%indlmn(3,:,itypat)>0)*ham%nattyp(itypat)
2047 : : end do
2048 [ # # ]: 0 : cplx = 2; if(ham%istwf_k > 1) cplx = 1
2049 : :
2050 : 0 : req_mem = 0
2051 : 0 : req_mem = req_mem + dp * cplx * int(nprojs, c_size_t) * int(nprojs, c_size_t) ! gram_projs
2052 : : req_mem = req_mem + dp * cplx * int(ham%lmnmax, c_size_t) * &
2053 : 0 : & int(ham%lmnmax, c_size_t) * int(ham%ntypat, c_size_t) ! inv_sij
2054 : : req_mem = req_mem + dp * cplx * int(ham%lmnmax, c_size_t) * &
2055 : 0 : & int(ham%lmnmax, c_size_t) * int(ham%ntypat, c_size_t) ! inv_s_approx
2056 : :
2057 : 0 : end function invovl_ompgpu_static_mem
2058 : :
2059 [ # # # # : 0 : end MODULE m_invovl
# # # # #
# # # # #
# # # # ]
2060 : : !!***
|