Branch data Line data Source code
1 : : !!****f* ABINIT/m_slice
2 : : !! NAME
3 : : !! m_slice
4 : : !!
5 : : !! FUNCTION
6 : : !! This module contains the types and routines used to apply the Spectrum Slicing
7 : : !! method. It mainly defines 'slice' datatypes and associated methods.
8 : : !!
9 : : !! Main features:
10 : : !! - uses 'xgTools' implementation for matrix data structure.
11 : : !! - adopts 'chebfi' functionalities for most matrix calculations.
12 : : !! - uses polynomial filtering, Chebyshev lowpass, next Chebyshev-Jackson.
13 : : !! - uses scheduler and resource allocator for slice tasks.
14 : : !! - uses logic for asynchronous slice memory avoiding race condition in read/write.
15 : : !! - applies Rayleigh-Ritz for individual slices in parallel or sequentially.
16 : : !!
17 : : !! NOTES
18 : : !! Dependence with other modules and hierarchy in this directory:
19 : : !! m_slice uses:
20 : : !! |- m_polynomial_filter | various math compute routines
21 : : !! |- m_trace_estimation | various math compute routines
22 : : !! |- m_chebfi2 ! the Chebyshev recursion
23 : : !! |- m_slice_task | Low-level
24 : : !!
25 : : !! COPYRIGHT
26 : : !! Copyright (C) 2018-2026 ABINIT group (IML)
27 : : !! This file is distributed under the terms of the
28 : : !! gnu general public license, see ~abinit/COPYING
29 : : !! or http://www.gnu.org/copyleft/gpl.txt .
30 : : !! for the initials of contributors, see ~abinit/doc/developers/contributors.txt .
31 : : !!
32 : : !! SOURCE
33 : :
34 : : #if defined HAVE_CONFIG_H
35 : : #include "config.h"
36 : : #endif
37 : :
38 : : #include "abi_common.h"
39 : :
40 : : ! nvtx related macro definition
41 : : #include "nvtx_macros.h"
42 : :
43 : : module m_slice
44 : :
45 : : use defs_basis
46 : : use defs_abitypes
47 : : use m_abicore
48 : : use m_errors
49 : : use m_time, only : timab
50 : : use m_sort, only: sort_dp
51 : :
52 : : use m_cgtools
53 : : use m_xg
54 : : use m_xgTransposer
55 : : use m_xg_ortho_RR
56 : : use m_chebfi2
57 : :
58 : : use m_trace_estimation
59 : : use m_slice_task
60 : : use m_polynomial_filter
61 : :
62 : : use m_xmpi
63 : : use m_xomp
64 : : #ifdef HAVE_OPENMP
65 : : use omp_lib
66 : : #endif
67 : :
68 : : #if defined(HAVE_GPU_CUDA) && defined(HAVE_YAKL)
69 : : use m_gpu_toolbox, only : CPU_DEVICE_ID, gpu_device_synchronize
70 : : #endif
71 : :
72 : : #if defined(HAVE_GPU_MARKERS)
73 : : use m_nvtx_data
74 : : #endif
75 : :
76 : : implicit none
77 : :
78 : : private
79 : :
80 : : ! Spectral interval decomposition strategy (spectral_cut input variable)
81 : : ! todo delete this obsolete
82 : : !---------------------------------------------------
83 : : integer, parameter :: DIVIDE_INTERVAL_WIDTH = 0
84 : : integer, parameter :: DIVIDE_NUMBER_OF_VECTORS = 1
85 : : integer, parameter :: DIVIDE_SPECTRAL_GAPS = 2
86 : :
87 : : ! Load balance criteria for fair resource allocation (paral_slice input variable)
88 : : ! todo should be either 0 or 1
89 : : !---------------------------------------------------
90 : : integer, parameter :: FAIR_BANDPP = 1 ! bandpp (unweigted)
91 : : integer, parameter :: FAIR_BANDPP_WDEG = 2 ! bandpp weighted by degree
92 : : integer, parameter :: EVEN_SLICES = 3 ! all slices have the same num of procs
93 : : integer, parameter :: SEQUENTIAL_SLICE = 4 ! sequential slice treatment
94 : :
95 : : integer, parameter :: ENABLE_PARAL = 0
96 : : integer, parameter :: DISABLE_PARAL = 1
97 : :
98 : : ! Timers
99 : : !---------------------------------------------------
100 : : integer, parameter :: tim_swap = 1761
101 : : integer, parameter :: tim_RR_q = 1759
102 : : integer, parameter :: tim_barrier = 1764
103 : : integer, parameter :: tim_copy = 1765
104 : : integer, parameter :: tim_Bortho_X = 1641
105 : : integer, parameter :: tim_getAX_BX = 1754
106 : : integer, parameter :: tim_invovl = 1755
107 : : integer, parameter :: tim_slice_sched = 2161
108 : : integer, parameter :: tim_slice_1 = 2162
109 : : integer, parameter :: tim_slice_2 = 2163
110 : : integer, parameter :: tim_slice_3 = 2164
111 : : integer, parameter :: tim_slice_X = 2165
112 : : integer, parameter :: tim_lanczos = 2167
113 : : integer, parameter :: tim_trace = 2168
114 : :
115 : : ! Public 'slice' datatype
116 : : !-------------------------------------------------
117 : : type, public :: slice_t
118 : :
119 : : ! MPI-related common to all-slice phase
120 : : integer :: nproc ! number of available processes
121 : : integer :: comm_rows ! xmpi_comm_self ...
122 : : integer :: comm_cols ! same as spacecom
123 : : integer :: spacecom ! same as comm_cols
124 : : integer :: bandpp ! nb of bands per process in colsrows representation
125 : : integer :: me_g0 ! 1 if this processors treats G=0, 0 otherwise
126 : : integer :: me_g0_fft ! 1 if this processors treats G=0 in FFT, 0 otherwise
127 : :
128 : : ! Eigenpair parameters
129 : : integer :: neigenpairs ! total number of bands (=number of eigenpairs)
130 : : integer :: total_spacedim ! total number of plane-waves
131 : : integer :: spacedim ! nb of plane-waves per process in linalg representation
132 : : integer :: nslice ! number of spectral slices
133 : : integer :: space ! real or complex eigenvectors
134 : : integer :: nbdbuf ! fixme for the moment not clear if useful
135 : :
136 : : ! GPU-related
137 : : integer :: gpu_kokkos_nthrd
138 : : integer :: gpu_thread_limit
139 : :
140 : : ! Various options
141 : : integer :: gpu_option ! enable GPU
142 : : integer :: paral_kgb ! enable parallel (k-points, G basis, bands)
143 : : integer :: paral_slice ! how to allocate resources for parallel slices
144 : : integer :: spectral_cut ! how to decompose spectrum into slices
145 : :
146 : : ! Various model parameters
147 : : logical :: paw ! use PAW or not
148 : : integer :: ndeg_filter ! lowpass degree of polynomial filter
149 : : real(dp) :: tolerance ! tolerance on the residu to stop the minimization
150 : : real(dp) :: ramp ! bandpass filter tolerance
151 : : real(dp) :: ecut ! Ecut Fermi level
152 : : real(dp) :: mineig ! slightly larger than mineig_global
153 : : real(dp) :: mineig_global ! guaranteed lower spectral bound
154 : : real(dp) :: maxeig_global ! guaranteed upper spectral bound
155 : :
156 : : ! Arrays related to polynomial filtering
157 : : integer, allocatable :: neigen_per_slice(:) ! total number of eigenpairs per slice
158 : : integer, allocatable :: poly_degrees(:) ! polynomial filter degrees per slice
159 : : real(dp), allocatable :: low_bounds(:) ! lower bounds in spectral partition (disjoint)
160 : : real(dp), allocatable :: upp_bounds(:) ! upper bounds in spectral partition (disjoint)
161 : :
162 : : end type slice_t
163 : :
164 : : ! Public methods associated to 'slice' datatype
165 : : !-------------------------------------------------
166 : : public :: slice_init ! initialize slice datatype object
167 : : public :: slice_free ! free slice datatype object
168 : : public :: slice_run ! run Spectrum Slicing for active slice task
169 : :
170 : : CONTAINS
171 : : !=====================================================================
172 : : !!***
173 : :
174 : : !!****f* m_slice/slice_init
175 : : !! NAME
176 : : !! slice_init
177 : : !!
178 : : !! FUNCTION
179 : : !! Initialize a 'slice' datastructure.
180 : : !!
181 : : !! INPUTS
182 : : !! nslice= number of spectral slices
183 : : !! neigenpairs= number of requested eigenvectors/eigenvalues
184 : : !! spacedim= space dimension for one vector
185 : : !! tolerance= tolerance criterion on the residu to stop the minimization
186 : : !! ecut= plane-wave cut-off energy
187 : : !! paral_kgb= flag controlling (k,g,bands) parallelization
188 : : !! bandpp= number of 'bands' handled by a processor
189 : : !! ndeg_filter= polynomial degree of the polynomial filter (.i.e. number of H applications)
190 : : !! is_lowpass= flag. True: use lowpass Chebyshev, false: use bandpass Heaviside expanded on Chebyshev
191 : : !! space= defines in which space we are (columns, rows, etc.)
192 : : !! eigenProblem= type of eigenpb: 1 (A*x = (lambda)*B*x), 2 (A*B*x = (lambda)*x), 3 (B*A*x = (lambda)*x)
193 : : !! spacecom= MPI communicator
194 : : !! me_g0= 1 if this processors treats G=0, 0 otherwise
195 : : !! me_g0_ftt= 1 if this processors treats G=0 in FFT, 0 otherwise
196 : : !! paw= flag. TRUE if current calculation ses the PAW approach
197 : : !! comm_rows= "rows" communicator
198 : : !! comm_cols= "cols" communicator
199 : : !! gpu_option= flag. Enable GPU if true
200 : : !! gpu_kokkos_nthrd= number of OpenMP offloaded threads used
201 : : !! gpu_thread_limit= maximum number of OpenMP offloaded threads
202 : : !!
203 : : !! SOURCE
204 : :
205 : 18 : subroutine slice_init(slice,nslice,neigenpairs,spacedim,tolerance,paral_kgb,&
206 : : paral_slice,ndeg_filter,nbdbuf,ramp,ecut,bandpp,space,spacecom,me_g0,me_g0_fft,&
207 : : paw,comm_rows,comm_cols,spectral_cut,gpu_option,gpu_kokkos_nthrd,gpu_thread_limit)
208 : :
209 : : implicit none
210 : :
211 : : ! Arguments ------------------------------------
212 : : integer , intent(in ) :: bandpp
213 : : integer , intent(in ) :: nslice
214 : : integer , intent(in ) :: me_g0
215 : : integer , intent(in ) :: me_g0_fft
216 : : integer , intent(in ) :: neigenpairs
217 : : integer , intent(in ) :: comm_rows
218 : : integer , intent(in ) :: comm_cols
219 : : integer , intent(in ) :: paral_kgb
220 : : integer , intent(in ) :: paral_slice
221 : : integer , intent(in ) :: space
222 : : integer , intent(in ) :: spacecom
223 : : integer , intent(in ) :: spacedim
224 : : integer , intent(in ) :: ndeg_filter
225 : : integer , intent(in ) :: nbdbuf
226 : : integer , intent(in ) :: spectral_cut
227 : : integer , intent(in ) :: gpu_option
228 : : logical , intent(in ) :: paw
229 : : real(dp) , intent(in ) :: ramp
230 : : real(dp) , intent(in ) :: tolerance
231 : : real(dp) , intent(in ) :: ecut
232 : : type(slice_t), intent(inout) :: slice
233 : : integer , intent(in ), optional :: gpu_kokkos_nthrd
234 : : integer , intent(in ), optional :: gpu_thread_limit
235 : :
236 : : ! Local variables --------------------------------
237 : : integer :: total_spacedim, ierr
238 : : !logical :: on_host, on_device
239 : :
240 : : ! *********************************************************************
241 : :
242 : 18 : slice%bandpp = bandpp
243 : 18 : slice%nslice = nslice
244 : 18 : slice%me_g0 = me_g0
245 : 18 : slice%me_g0_fft = me_g0_fft
246 : 18 : slice%neigenpairs = neigenpairs
247 : 18 : slice%comm_rows = comm_rows
248 : 18 : slice%comm_cols = comm_cols
249 : 18 : slice%paral_kgb = paral_kgb
250 : 18 : slice%paral_slice = paral_slice
251 : 18 : slice%space = space
252 : 18 : slice%spacecom = spacecom
253 : 18 : slice%spacedim = spacedim
254 : 18 : slice%ndeg_filter = ndeg_filter
255 : 18 : slice%nbdbuf = nbdbuf
256 : 18 : slice%spectral_cut = spectral_cut
257 : 18 : slice%gpu_option = gpu_option
258 : 18 : slice%paw = paw
259 : 18 : slice%ramp = ramp
260 : 18 : slice%tolerance = tolerance
261 : 18 : slice%ecut = ecut
262 : :
263 : 18 : slice%gpu_kokkos_nthrd = 1
264 [ + - ]: 18 : if (present(gpu_kokkos_nthrd)) then
265 : 18 : slice%gpu_kokkos_nthrd = gpu_kokkos_nthrd
266 : : end if
267 : 18 : slice%gpu_thread_limit = 0
268 [ + - ]: 18 : if (present(gpu_thread_limit)) then
269 : 18 : slice%gpu_thread_limit = gpu_thread_limit
270 : : end if
271 : :
272 : : ! Total number of rows (used in colsrows representation)
273 [ + + ]: 18 : if (paral_kgb==0) then
274 : 2 : slice%total_spacedim = spacedim
275 : : else
276 : 16 : total_spacedim = spacedim
277 : 16 : call xmpi_sum(total_spacedim, spacecom, ierr)
278 : 16 : slice%total_spacedim = total_spacedim
279 : : end if
280 : :
281 : : ! Total number of processes
282 : 18 : slice%nproc = xmpi_comm_size(spacecom)
283 : :
284 : : ! Arrays
285 : 18 : call slice_allocateAll(slice)
286 : :
287 : 18 : end subroutine slice_init
288 : : !!***
289 : :
290 : : !----------------------------------------------------------------------
291 : :
292 : : !!****f* m_slice/slice_allocateAll
293 : : !! name
294 : : !! slice_allocateAll
295 : :
296 : 18 : subroutine slice_allocateAll(slice)
297 : :
298 : : implicit none
299 : : type(slice_t), intent(inout) :: slice
300 : :
301 : : ! *********************************************************************
302 : :
303 : 18 : call slice_free(slice)
304 : :
305 [ + - - + : 54 : ABI_MALLOC_IFNOT(slice%neigen_per_slice, (slice%nslice))
+ - + - +
- - + - +
- + ]
306 [ + - - + : 54 : ABI_MALLOC_IFNOT(slice%poly_degrees, (slice%nslice))
+ - + - +
- - + - +
- + ]
307 [ + - - + : 54 : ABI_MALLOC_IFNOT(slice%low_bounds, (slice%nslice))
+ - + - +
- - + - +
- + ]
308 [ + - - + : 54 : ABI_MALLOC_IFNOT(slice%upp_bounds, (slice%nslice))
+ - + - +
- - + - +
- + ]
309 : :
310 : 18 : end subroutine slice_allocateAll
311 : : !!***
312 : :
313 : : !----------------------------------------------------------------------
314 : :
315 : : !!****f* m_slice/slice_free
316 : : !! name
317 : : !! slice_free
318 : :
319 : 36 : subroutine slice_free(slice)
320 : :
321 : : implicit none
322 : : type(slice_t), intent(inout) :: slice
323 : :
324 : : ! *********************************************************************
325 : :
326 [ + + ]: 36 : ABI_SFREE(slice%neigen_per_slice)
327 [ + + ]: 36 : ABI_SFREE(slice%poly_degrees)
328 [ + + ]: 36 : ABI_SFREE(slice%low_bounds)
329 [ + + ]: 36 : ABI_SFREE(slice%upp_bounds)
330 : :
331 : 36 : end subroutine slice_free
332 : : !!***
333 : :
334 : : !----------------------------------------------------------------------
335 : :
336 : : !!****f* m_slice/slice_run
337 : : !! NAME
338 : : !! slice_run
339 : : !!
340 : : !! FUNCTION
341 : : !! Run Spectrum slicing on a given set of active vectors.
342 : : !! Computation uses marked resources for current task **only**.
343 : : !!
344 : : !! INPUTS
345 : : !! X0= size (spacedim, neigenpairs)
346 : : !! eigen,residu= size (neigenpairs, 1) (column vectors)
347 : : !! getAX_BX= pointer to the function giving A|X> and B|X>
348 : : !! A is typically the Hamiltonian H, and B the overlap operator S
349 : : !! getBm1X= pointer to the function giving B^-1|X>
350 : : !! B is typically the overlap operator S
351 : : !! nspinor= number of spinorial components of the wavefunctions
352 : : !!
353 : : !! SIDE EFFECTS
354 : : !! slice <type(slice_t)>= memory workspace used for Spectrum slicing
355 : : !!
356 : : !! SOURCE
357 : :
358 : 18 : subroutine slice_run(slice, X0, getAX_BX, getBm1X, eigen, residu, nspinor)
359 : :
360 : : implicit none
361 : :
362 : : ! Arguments
363 : : type(slice_t), target, intent(inout) :: slice
364 : : type(xgBlock_t), intent(inout) :: X0 ! size (spacedim, neigenpairs)
365 : : type(xgBlock_t), intent(inout) :: eigen ! size (neigenpairs,1)
366 : : type(xgBlock_t), intent(inout) :: residu ! size (neigenpairs,1)
367 : : integer, intent(in) :: nspinor
368 : : interface
369 : : subroutine getAX_BX(X,AX,BX)
370 : : use m_xg, only : xgBlock_t
371 : : type(xgBlock_t), intent(inout) :: X
372 : : type(xgBlock_t), intent(inout) :: AX
373 : : type(xgBlock_t), intent(inout) :: BX
374 : : end subroutine getAX_BX
375 : : end interface
376 : : interface
377 : : subroutine getBm1X(X,Bm1X)
378 : : use m_xg, only : xgBlock_t
379 : : type(xgBlock_t), intent(inout) :: X
380 : : type(xgBlock_t), intent(inout) :: Bm1X
381 : : end subroutine getBm1X
382 : : end interface
383 : :
384 : : ! Local scalars
385 : : integer :: tim_slice_me
386 : : integer :: nrows, ncols
387 : : integer :: space_res
388 : : !integer :: neigenpairs, bandpp, ndeg_filter
389 : : integer :: neigenpairs_ext
390 : : integer :: p_offset, ndeg_filter_max
391 : : !integer :: ierr
392 : : !real(dp) :: theta
393 : : real(dp) :: safe, tol ! for slice selection window
394 : : !logical :: is_lowpass, on_host, on_device ! todo use slice%..
395 : : ! ----> variables for logic of slice solver
396 : : type(matrixInfo_t) :: matrixInfo
397 : : type(xg_t) :: DivResults
398 : 18 : type(activeTask_t) :: task
399 : 18 : type(taskScheduler_t) :: scheduler
400 : 18 : type(asyncMemory_t) :: asyncMemory
401 : : ! <-----
402 : : ! Arrays
403 : : !real(dp) :: tsec(2)
404 : 18 : real(dp), allocatable :: moments(:)
405 : 18 : logical, allocatable, target :: mapper(:,:)
406 : :
407 : : ! *********************************************************************
408 : :
409 : : tim_slice_me = tim_slice_X
410 : : select case(task%me_id_slice)
411 : : case(1)
412 : : tim_slice_me = tim_slice_1
413 : : case(2)
414 : : tim_slice_me = tim_slice_2
415 : : case(3)
416 : : tim_slice_me = tim_slice_3
417 : : end select
418 : :
419 : 18 : nrows = slice%spacedim
420 : 18 : ncols = slice%neigenpairs
421 : : if (slice%paral_kgb==1) then ! colsrows distribution
422 : : nrows = slice%total_spacedim
423 : : ncols = slice%bandpp
424 : : end if
425 : :
426 : 18 : if (slice%space==SPACE_C) then
427 : 18 : space_res = SPACE_C
428 [ # # ]: 0 : else if (slice%space==SPACE_CR) then
429 : 0 : space_res = SPACE_R
430 : : else
431 : 0 : ABI_ERROR('space(X) should be SPACE_C or SPACE_CR')
432 : : end if
433 : :
434 : 18 : call xg_init(DivResults, space_res, slice%neigenpairs, 1, gpu_option=slice%gpu_option)
435 : :
436 : : call init_matrixInfo(matrixInfo, slice%comm_rows, slice%comm_cols, slice%spacecom, &
437 : : slice%neigenpairs,slice%total_spacedim, slice%spacedim, slice%space, &
438 : : slice%gpu_kokkos_nthrd, slice%gpu_thread_limit,slice%gpu_option, slice%paral_kgb, &
439 : 18 : slice%me_g0, slice%me_g0_fft, nspinor)
440 : :
441 : 18 : write(std_out,*) 'in slice_run'
442 : 18 : write(std_out,*) 'array of eigenvalues', rows(eigen), cols(eigen)
443 : 18 : flush(std_out)
444 : :
445 : : ! ============================= Prepare spectral slices =====================================
446 : :
447 : : !call timab(tim_slice_sched,1,tsec) ! fixme those timers
448 : : !ABI_NVTX_START_RANGE(NVTX_SLICE_SCHEDULE) ! fixme those markers
449 : :
450 : 18 : ndeg_filter_max = 10 ! todo IML autotune based on the presence of oscillations
451 [ - + ]: 18 : ABI_MALLOC(moments, (ndeg_filter_max+1))
452 : :
453 : : !ABI_NVTX_START_RANGE(NVTX_SLICE_RRQ)
454 : : call slice_getSpectralInfo(slice, X0, matrixInfo, moments, DivResults%self, residu, &
455 : 18 : getAX_BX, getBm1X)
456 : : !ABI_NVTX_END_RANGE()
457 : :
458 : : !ABI_NVTX_END_RANGE()
459 : : !call timab(tim_slice_sched,2,tsec)
460 : :
461 : 18 : call slice_splitSpectrum(slice, moments)
462 [ - + ]: 18 : ABI_FREE(moments)
463 : :
464 : : ! Attribute column vectors of X0 to slices using query results
465 [ - + + - : 72 : ABI_MALLOC(mapper, (slice%neigenpairs, slice%nslice))
- + + - +
- + - - +
- + - + ]
466 [ + + + + ]: 6966 : mapper = .false.
467 : 18 : write(std_out,*) 'tolerance in residual window=', slice%tolerance
468 : 18 : flush(std_out)
469 : :
470 : 18 : safe = 2.d0
471 : 18 : tol = 1e-2 ! slice%tolerance
472 : 18 : call slice_applySelectionWindow(slice, mapper, DivResults%self, residu, tol, safe)
473 : :
474 : 18 : write(std_out,*) 'created the following map slices to cols='
475 : 18 : write(std_out,*) mapper(1,:)
476 : 18 : flush(std_out)
477 : :
478 : : ! Include m+p where p offset 10%
479 : 18 : p_offset = 0.1d0
480 : 18 : slice%neigen_per_slice = ceiling(slice%neigen_per_slice*(1.d0+p_offset))
481 [ + + ]: 54 : neigenpairs_ext = sum(slice%neigen_per_slice)
482 : :
483 : 18 : write(std_out,*) 'allocating async memory of size', neigenpairs_ext
484 : 18 : flush(std_out)
485 : :
486 : : ! Allocate extended buffer in Linalg representation. Notice spacecom communicator (global)
487 : 18 : call slice_task_allocAsyncMemory(asyncMemory, matrixInfo, neigenpairs_ext)
488 : :
489 : : ! Init extended buffer with vectors from X or random vectors. This part also uses global comm.
490 : 18 : call slice_task_copyToAsyncMemory(asyncMemory, X0, matrixInfo, mapper, slice%neigen_per_slice)
491 : :
492 : 18 : write(std_out,*) 'getid after init', xgBlock_getid(asyncMemory%XextLinalg)
493 : 18 : flush(std_out)
494 : :
495 : : ! =========================== MPI distribution for slices ==================================
496 : :
497 : : ! MPI phase I: Compute 'process-to-slice(task)' distribution according to paral options
498 : : call slice_task_initSchedule(scheduler, slice%nslice, slice%nproc, slice%neigen_per_slice,&
499 : 18 : slice%paral_kgb, slice%paral_slice)
500 : : ! /IML\ in here there should be some per-rank parameter called slice%neigen_per_slice
501 : : ! that is updated along slice iterations
502 : : ! also nslice should be rank-wise as well
503 : :
504 : 18 : call slice_task_printSchedule(scheduler, std_out)
505 : :
506 : : ! MPI phase II: Compute 'slice columns(load)-to-process' distribution for next task
507 : : ! and apply schedule to distribute the async memory to processes
508 : 18 : call slice_task_initNextTask(scheduler, task, matrixInfo)
509 : 18 : call slice_task_enableAsync(asyncMemory, task, matrixInfo)
510 : :
511 : : !!! ^------- start region containing data on slice only --------^
512 : :
513 : : ! ============================ Active task execution =======================================
514 : :
515 : : ! IML is here
516 : : ! pass explicit slice parameters such as degree, lowb, uppb
517 : : ! call slice_task_runActiveTask(task...)
518 : :
519 : : ! if (paral_slice==yes) then
520 : : !! exit
521 : : !! otherwise, update slice%neigen_per_slice etc
522 : :
523 : : !
524 : : ! call timab(tim_slice_me,1,tsec)
525 : : !
526 : : ! if (slice%paral_kgb==0 .or. slice%paral_slice==DISABLE_PARAL) then
527 : : ! ! execute active tasks sequentially
528 : : !
529 : : ! do islice=1, nslice
530 : : ! if (task%active(islice)) then ! <--- normally it should not be that different..
531 : : ! call schedule_next_task(schedule, neigenpairs)
532 : : ! call init_active_memory(asyncMemory, task, X0, p)
533 : : ! call execute_active_task(task)
534 : : ! call mask_active_task(task, tol) ! mask extendedMem
535 : : ! end do
536 : : !
537 : : ! else
538 : : ! ! execute active tasks in parallel
539 : : !
540 : : ! call init_active_memory(asyncMemory, task, X0, p)
541 : : ! call execute_active_task(task)
542 : : ! call mask_active_task(task, tol) ! mask extendedMem
543 : : !
544 : : ! end if
545 : : !
546 : : ! ! Copy to spectrum memory only when active tasks have finished
547 : : ! call compress_extended_memory(work) ! extendendMem -> spectrumMem
548 : : !
549 : : !
550 : : ! call free_schedule(schedule)
551 : : !
552 : : !
553 : : !
554 : : ! ! Free temporary memory
555 : : ! call chebfi_free(chebfi)
556 : : ! ABI_SFREE(nrowsLinalg)
557 : : !
558 : : ! ! Timer is BEFORE the barrier !!
559 : : ! call timab(tim_slice_me,2,tsec)
560 : : !
561 [ - + ]: 18 : ABI_FREE(mapper)
562 : 18 : call xg_free(DivResults)
563 : 18 : call slice_task_freeAsyncMemory(asyncMemory)
564 : 18 : call slice_task_freeSchedule(scheduler)
565 : 18 : call slice_task_freeActiveTask(task)
566 : :
567 [ + - - + : 36 : end subroutine slice_run
- + - + -
+ - + - +
- + - + -
+ ]
568 : : !!***
569 : :
570 : : !----------------------------------------------------------------------
571 : :
572 : : !!****f* m_slice/slice_getSpectralInfo
573 : : !! NAME
574 : : !! slice_getSpectralInfo
575 : : !!
576 : : !! FUNCTION
577 : : !! Approximate eigenvalue spectrum and query input X for Ritz values and residuals.
578 : : !! This is a Hamiltonian-application-based approximation.
579 : : !! Inner calculations use colsrows representation to apply the Hamiltonian.
580 : : !!
581 : : !! INPUTS
582 : : !! X =eigenvector guess
583 : : !! getAX_BX =Hamiltonian application
584 : : !!
585 : : !! SOURCE
586 : :
587 [ - + ]: 18 : subroutine slice_getSpectralInfo(slice, X, matrixInfo, moments, eigen, resid, getAX_BX, getBm1X)
588 : :
589 : : implicit none
590 : :
591 : : ! Arguments
592 : : type(slice_t), intent(inout) :: slice
593 : : type(xgBlock_t), intent(inout) :: X
594 : : type(matrixInfo_t), intent(in) :: matrixInfo
595 : : real(dp), intent(inout) :: moments(:)
596 : : type(xgBlock_t), intent(inout) :: eigen
597 : : type(xgBlock_t), intent(inout) :: resid
598 : : interface
599 : : subroutine getAX_BX(X,AX,BX)
600 : : use m_xg, only : xgBlock_t
601 : : type(xgBlock_t), intent(inout) :: X
602 : : type(xgBlock_t), intent(inout) :: AX
603 : : type(xgBlock_t), intent(inout) :: BX
604 : : end subroutine getAX_BX
605 : : end interface
606 : : interface
607 : : subroutine getBm1X(X,Bm1X)
608 : : use m_xg, only : xgBlock_t
609 : : type(xgBlock_t), intent(inout) :: X
610 : : type(xgBlock_t), intent(inout) :: Bm1X
611 : : end subroutine getBm1X
612 : : end interface
613 : :
614 : : ! Local variables
615 : : ! Scalars
616 : : integer :: spacedim, tot_spacedim, nspinor
617 : : integer :: ndeg_filter_max, neigenpairs
618 : : integer :: ierr
619 : : !integer :: ideg
620 : : integer :: kmax
621 : : integer :: m_probe
622 : : integer :: my_shift, my_rank
623 : : integer :: space, spacecom, gpu_option
624 : : !integer :: k_sketch
625 : : real(dp) :: lambda_min, res_norm
626 : : !real(dp) :: center, radius
627 : : real(dp) :: lowb!, mineig, maxeig
628 : : real(dp) :: lanczos_lowb, lanczos_lowb_global
629 : : ! Derived types
630 : : #ifdef HAVE_OPENMP_OFFLOAD
631 : : integer :: me_g0
632 : : type(xg_t) :: W_dummy
633 : : integer :: work_size
634 : : #endif
635 : : !type(xg_t) :: BX
636 : : type(xgBlock_t) :: xXColsRows
637 : : type(xgBlock_t) :: eigen_me, resid_me
638 : 18 : type(xgTransposer_t) :: xgTransposerX
639 : : ! Arrays
640 : : #ifdef HAVE_OPENMP_OFFLOAD
641 : : real(dp) :: tsec(2)
642 : : #endif
643 : : ! *********************************************************************
644 : :
645 : 18 : neigenpairs = slice%neigenpairs
646 : 18 : tot_spacedim = slice%total_spacedim
647 : 18 : spacedim = slice%spacedim
648 : 18 : gpu_option = slice%gpu_option
649 : 18 : spacecom = slice%spacecom
650 : 18 : space = slice%space
651 : 18 : nspinor = matrixInfo%nspinor
652 : : #ifdef HAVE_OPENMP_OFFLOAD
653 : : me_g0 = slice%me_g0
654 : : if (slice%paral_kgb==1) then
655 : : me_g0 = slice%me_g0_fft
656 : : end if
657 : : #endif
658 : :
659 : : ! ============== Transpose ==============
660 : 18 : if (slice%paral_kgb==1) then
661 : :
662 : : ! Allocate memory for X in colsrows representation
663 : : call xgTransposer_constructor(xgTransposerX, X, xXColsRows, nspinor, STATE_LINALG,&
664 : : TRANS_ALL2ALL, slice%comm_rows, slice%comm_cols, 0, 0, slice%me_g0_fft,&
665 : 16 : gpu_option=slice%gpu_option, gpu_thread_limit=slice%gpu_thread_limit)
666 : :
667 : 16 : xgTransposerX%gpu_kokkos_nthrd = slice%gpu_kokkos_nthrd
668 : :
669 : : !call xmpi_barrier(slice%spacecom)
670 : : ABI_NVTX_START_RANGE(NVTX_SLICE_TRANSPOSE)
671 : 16 : call xgTransposer_transpose(xgTransposerX, STATE_COLSROWS)
672 : : ABI_NVTX_END_RANGE()
673 : :
674 : : else
675 : :
676 : : ! Use colsrows notion instead of X notion
677 : 2 : call xgBlock_setBlock(X, xXColsRows, spacedim, neigenpairs)
678 : :
679 : : end if
680 : :
681 : : ! Prevent invovl error
682 : : ! dummy invovl calculation to allocate buffers of full size
683 : : ! Workaround: getBm1X error related to invovl allocated buffers.
684 : : ! With this setup we allocate large then use 1 in Lanczos.
685 : : ! The inverse is not possible with current implementation. This order allows to avoid
686 : : ! make_invovl for 1 vector then make_invovl for nband vectors.
687 : : #ifdef HAVE_OPENMP_OFFLOAD
688 : : if (slice%paw) then
689 : : work_size = slice%neigenpairs ! fixme will complain
690 : : call xg_init(W_dummy, slice%space, tot_spacedim, work_size, xmpi_comm_null, &
691 : : me_g0=me_g0, gpu_option=slice%gpu_option)
692 : : call timab(tim_invovl, 1, tsec)
693 : : ABI_NVTX_START_RANGE(NVTX_CHEBFI2_GET_BM1X)
694 : : call getBm1X(W_dummy%self, W_dummy%self)
695 : : ABI_NVTX_END_RANGE()
696 : : call timab(tim_invovl, 2, tsec)
697 : : call xg_free(W_dummy)
698 : : end if
699 : : #endif
700 : :
701 : 18 : kmax = 30
702 : 18 : call computeBLanczos(matrixInfo, slice%paw, getAX_BX, getBm1X, kmax, lambda_min, res_norm)
703 : :
704 : 18 : lanczos_lowb = lambda_min - res_norm
705 : 18 : call xmpi_min(lanczos_lowb,lanczos_lowb_global,slice%spacecom,ierr)
706 : 18 : lowb = lanczos_lowb_global
707 : :
708 : 18 : write(std_out,*) 'Lanczos lambda_min=', lambda_min
709 : 18 : write(std_out,*) 'Lanczos res_norm =', res_norm
710 : 18 : write(std_out,*) 'Lanczos guarantee =', lanczos_lowb
711 : 18 : write(std_out,*) 'Lanczos guarantee(global) =', lanczos_lowb_global
712 : 18 : flush(std_out)
713 : :
714 : : ! Perform sensitivity study of trace estimation for these parameters
715 : : ! Keep m_probe small allows to reduce noise
716 : 18 : m_probe = 5
717 : 18 : ndeg_filter_max = size(moments) - 1
718 : 18 : write(std_out,*) 'Here I compute Stochastic Trace Estimation'
719 : 18 : write(std_out,*) 'm_probe= ', m_probe
720 : 18 : write(std_out,*) 'ndeg_filter=', ndeg_filter_max
721 : 18 : flush(std_out)
722 : :
723 : : call computeTraceEstimation(matrixInfo, slice%ecut, slice%paw, slice%tolerance, &
724 : 18 : getAX_BX, getBm1X, ndeg_filter_max, m_probe, lanczos_lowb_global, moments)
725 : :
726 : : ! Define working spectrum to be splitted to slices
727 : 18 : slice%mineig = lanczos_lowb
728 : 18 : slice%mineig_global = lanczos_lowb_global
729 : 18 : slice%maxeig_global = slice%ecut
730 : :
731 : 18 : write(std_out,*) 'STE exited'
732 : 18 : flush(std_out)
733 : :
734 : : ! Compute Rayleigh quotients (colsrows distribution) ! fixme timers
735 : : !ABI_NVTX_START_RANGE(NVTX_CHEBFI2_RRQ)
736 : : !call timab(tim_RR_q, 1, tsec)
737 : :
738 [ + + ]: 18 : if (slice%paral_kgb==1) then
739 : 16 : my_rank = xmpi_comm_rank(slice%spacecom)
740 : 16 : my_shift = my_rank * slice%bandpp
741 : 16 : call xgBlock_reshape(eigen, 1, slice%neigenpairs)
742 : 16 : call xgBlock_reshape(resid, 1, slice%neigenpairs)
743 : 16 : call xgBlock_setBlock(eigen, eigen_me, 1, slice%bandpp, fcol=my_shift+1)
744 : 16 : call xgBlock_setBlock(resid, resid_me, 1, slice%bandpp, fcol=my_shift+1)
745 : 16 : call xgBlock_reshape(eigen, slice%neigenpairs, 1)
746 : 16 : call xgBlock_reshape(resid, slice%neigenpairs, 1)
747 : 16 : call xgBlock_reshape(eigen_me, slice%bandpp, 1)
748 : 16 : call xgBlock_reshape(resid_me, slice%bandpp, 1)
749 : : else
750 : 2 : call xgBlock_setBlock(eigen, eigen_me, rows(eigen), 1)
751 : 2 : call xgBlock_setBlock(resid, resid_me, rows(resid), 1)
752 : : end if
753 : :
754 : 18 : call slice_queryCandidates(slice, xXColsRows, eigen_me, resid_me, getAX_BX)
755 : : !call timab(tim_RR_q, 2, tsec)
756 : : !ABI_NVTX_END_RANGE()
757 : :
758 : 18 : call xgBlock_mpi_sum(eigen, comm=slice%spacecom)
759 : 18 : call xgBlock_mpi_sum(resid, comm=slice%spacecom)
760 : :
761 : : ! ============== Transpose ==============
762 [ + + ]: 18 : if (slice%paral_kgb == 1) then
763 : 16 : call xmpi_barrier(slice%spacecom)
764 : : ABI_NVTX_START_RANGE(NVTX_SLICE_TRANSPOSE)
765 : 16 : call xgTransposer_transpose(xgTransposerX, STATE_LINALG)
766 : : ABI_NVTX_END_RANGE()
767 : :
768 : : ! reset buffers to right address
769 [ - + ]: 16 : if (xmpi_comm_size(slice%spacecom) == 1) then
770 : 0 : call xgBlock_setBlock(xXColsRows, X, spacedim, neigenpairs)
771 : : end if
772 : : else
773 : 2 : call xgBlock_setBlock(xXColsRows, X, spacedim, neigenpairs)
774 : : end if
775 : :
776 [ + + ]: 18 : if (slice%paral_kgb == 1) then
777 : 16 : call xgTransposer_free(xgTransposerX)
778 : : end if
779 : :
780 [ + + - + ]: 36 : end subroutine slice_getSpectralInfo
781 : : !!***
782 : :
783 : : !----------------------------------------------------------------------
784 : :
785 : : !!****f* m_slice/slice_queryCandidates
786 : : !! NAME
787 : : !! slice_queryCandidates
788 : : !!
789 : : !! FUNCTION
790 : : !! Compute Rayleigh-Ritz quotients and residuals in colsrows MPI representation.
791 : : !! Return bandpp indicators per MPI process.
792 : : !! These two indicators are useful to rank candidates per slices.
793 : : !!
794 : : !! SOURCE
795 : :
796 : 18 : subroutine slice_queryCandidates(slice, xXColsRows, eigen, resid, getAX_BX)
797 : :
798 : : implicit none
799 : :
800 : : !Arguments ------------------------------------
801 : : type(slice_t), intent(inout) :: slice
802 : : type(xgBlock_t), intent(inout) :: xXColsRows
803 : : type(xgBlock_t), intent(inout) :: eigen
804 : : type(xgBlock_t), intent(inout) :: resid
805 : : interface
806 : : subroutine getAX_BX(X,AX,BX)
807 : : use m_xg, only : xgBlock_t
808 : : type(xgBlock_t), intent(inout) :: X
809 : : type(xgBlock_t), intent(inout) :: AX
810 : : type(xgBlock_t), intent(inout) :: BX
811 : : end subroutine getAX_BX
812 : : end interface
813 : :
814 : : !Local variables-------------------------------
815 : : type(xg_t) :: XAB
816 : : type(xg_t) :: Results1
817 : : type(xg_t) :: Results2
818 : : type(xg_t) :: norml
819 : : type(xgBlock_t) :: xAXColsRows
820 : : type(xgBlock_t) :: xBXColsRows
821 : : type(xgBlock_t) :: xRXColsRows
822 : : integer :: space_res
823 : : integer :: me_g0, nrows, ncols, gpu_option
824 : : real(dp) :: tsec(2)
825 : :
826 : : ! *********************************************************************
827 : :
828 : 18 : if (slice%space==SPACE_C) then
829 : 18 : space_res = SPACE_C
830 [ # # ]: 0 : else if (slice%space==SPACE_CR) then
831 : 0 : space_res = SPACE_R
832 : : else
833 : 0 : ABI_ERROR('space(X) should be SPACE_C or SPACE_CR')
834 : : end if
835 : :
836 : 18 : ncols = slice%bandpp
837 : 18 : nrows = rows(xXColsRows)
838 : 18 : me_g0 = slice%me_g0
839 : 18 : gpu_option = slice%gpu_option
840 [ + + ]: 18 : if (slice%paral_kgb==1) then
841 : : ncols = slice%bandpp
842 : 16 : nrows = slice%total_spacedim
843 : 16 : me_g0 = slice%me_g0_fft
844 : : end if
845 : 18 : call xg_init(Results1, space_res, ncols, 1, gpu_option=slice%gpu_option)
846 : 18 : call xg_init(Results2, space_res, ncols, 1, gpu_option=slice%gpu_option)
847 : 18 : call xg_init(norml, SPACE_R, slice%bandpp, 1)
848 : :
849 : 18 : call xg_init(XAB,slice%space,nrows,3*ncols,slice%spacecom,me_g0=me_g0,gpu_option=gpu_option)
850 : 18 : call xg_setBlock(XAB, xAXColsRows, nrows, ncols)
851 : 18 : call xg_setBlock(XAB, xBXColsRows, nrows, ncols, fcol=ncols+1)
852 : 18 : call xg_setBlock(XAB, xRXColsRows, nrows, ncols, fcol=2*ncols+1)
853 : :
854 : : ! Compute A*Psi
855 : 18 : call timab(tim_getAX_BX,1,tsec)
856 : : ABI_NVTX_START_RANGE(NVTX_SLICE_GET_AX_BX)
857 : 18 : call getAX_BX(xXColsRows, xAXColsRows, xBXColsRows)
858 : 18 : call xgBlock_zero_im_g0(xAXColsRows)
859 : 18 : call xgBlock_zero_im_g0(xBXColsRows)
860 : : ABI_NVTX_END_RANGE()
861 : 18 : call timab(tim_getAX_BX,2,tsec)
862 : :
863 : : ! <Psi|H|Psi>
864 : 18 : call xgBlock_colwiseDotProduct(xXColsRows, xAXColsRows, Results1%self, comm_loc=xmpi_comm_null)
865 : :
866 : : ! <Psi|S|Psi>
867 : 18 : call xgBlock_colwiseDotProduct(xXColsRows, xBXColsRows, Results2%self, comm_loc=xmpi_comm_null)
868 : :
869 : : ! eig = <Psi|H|Psi> / <Psi|S|Psi>
870 : 18 : call xgBlock_colwiseDivision(Results1%self, Results2%self, eigen)
871 : :
872 : : ! xRXColsRows = S|Psi>
873 : 18 : call xgBlock_copy(xBXColsRows,xRXColsRows)
874 : : ! xRXColsRows = - eigen * S|Psi>
875 : 18 : call xgBlock_ymax(xRXColsRows,eigen,0,1)
876 : : ! norml = |eigen*S|Psi>|^2
877 : 18 : call xgBlock_colwiseNorm2(xBXColsRows, norml%self, comm_loc=xmpi_comm_null)
878 : : ! xRXColsRows = H|Psi> - eigen * S|Psi>
879 : 18 : call xgBlock_add(xRXColsRows,xAXColsRows)
880 : : ! resid = |xRXColsRows|^2
881 : 18 : call xgBlock_colwiseNorm2(xRXColsRows, resid, comm_loc=xmpi_comm_null)
882 : :
883 : : ! compute relative resid=resid/(|eigen|*|BX|)^2
884 : : ! scales with the eigenvalue
885 : 18 : call xgBlock_colwiseDivision(resid, norml%self, resid)
886 : :
887 : 18 : call xg_free(Results1)
888 : 18 : call xg_free(Results2)
889 : 18 : call xg_free(XAB)
890 : 18 : call xg_free(norml)
891 : :
892 [ + - ]: 18 : end subroutine slice_queryCandidates
893 : : !!***
894 : :
895 : : !----------------------------------------------------------------------
896 : :
897 : : !!****f* m_slice/slice_unitTest
898 : : !! NAME
899 : : !! slice_unitTest
900 : : !!
901 : : !! FUNCTION
902 : : !! Given a set of vectors X computes the columnwise norm squared, on:
903 : : !! - CPU sequential,
904 : : !! - CPU MPI,
905 : : !! - GPU sequential (if GPU available),
906 : : !! - GPU MPI (if GPU available).
907 : : !! Checks that all four are the same.
908 : : !!
909 : : !! SOURCE
910 : :
911 : : function slice_unitTest(X) result(ierr)
912 : :
913 : : implicit none
914 : :
915 : : !Arguments ------------------------------------
916 : : type(xgBlock_t), intent(in) :: X
917 : : integer :: ierr
918 : :
919 : : !Local variables-------------------------------
920 : : integer :: nrows,ncols
921 : : integer :: comm
922 : : integer :: gpu_option
923 : : real(dp) :: id_cpu, id_from_gpu, id_to_gpu
924 : :
925 : : ! *********************************************************************
926 : :
927 : : ! Get nrows, nrcols, gpu_option of X
928 : : call xgBlock_getSize(X,nrows,ncols)
929 : : call xgBlock_get_gpu_option(X,gpu_option)
930 : : call xgBlock_get_communicator(X,comm)
931 : : ! above this is just comm(X)
932 : : write(std_out,*) '<--*--> Start unitary test for matrix'
933 : : write(std_out,*) 'nrows =', nrows
934 : : write(std_out,*) 'ncols =', ncols
935 : : write(std_out,*) 'gpu_option =', gpu_option
936 : : write(std_out,*) 'communicator=', comm
937 : :
938 : : id_cpu = -1.0d0
939 : : id_from_gpu = -1.0d0
940 : : id_to_gpu = -1.0d0
941 : :
942 : : if (gpu_option==ABI_GPU_DISABLED) then
943 : : id_cpu = xgBlock_getid(X, comm)
944 : : write(std_out,*) 'id_cpu =', id_cpu
945 : : end if
946 : :
947 : : #if defined HAVE_GPU && defined HAVE_OPENMP_OFFLOAD
948 : : if (gpu_option/=ABI_GPU_DISABLED) then
949 : : call xgBlock_copy_from_gpu(X)
950 : : id_from_gpu = xgBlock_getid(X, comm)
951 : : call xgBlock_copy_to_gpu(X)
952 : : write(std_out,*) 'id_from_gpu=', id_from_gpu
953 : : else
954 : : call xgBlock_copy_to_gpu(X)
955 : : call xgBlock_copy_from_gpu(X)
956 : : id_to_gpu = xgBlock_getid(X, comm)
957 : : call xgBlock_copy_to_gpu(X)
958 : : call xgBlock_copy_from_gpu(X)
959 : : write(std_out,*) 'id_to_gpu =', id_to_gpu
960 : : end if
961 : : #endif
962 : :
963 : : ! TODO getid on xmpi_comm_null
964 : : ! then sum across comm
965 : : ! should give the same as
966 : : ! getid on comm
967 : : ! this is useful for MPI
968 : :
969 : : ierr = 0
970 : : if (id_cpu < 0) ierr = -1
971 : : if (id_from_gpu < 0) ierr = -1
972 : : if (id_to_gpu < 0) ierr = -1
973 : :
974 : : end function slice_unitTest
975 : : !!***
976 : :
977 : : !----------------------------------------------------------------------
978 : :
979 : : !!****f* m_slice/slice_splitSpectrum
980 : : !! NAME
981 : : !! slice_splitSpectrum
982 : : !!
983 : : !! FUNCTION
984 : : !! Split working spectrum [a,b) mapped to [-1,1) with center and radius.
985 : : !!
986 : : !! INPUT
987 : : !! a= slice%mineig_global
988 : : !! b= slice%maxeig_global
989 : : !!
990 : : !! SIDE EFFECTS
991 : : !! slice%low_bounds
992 : : !! slice%upp_bounds
993 : : !! slice%neigen_per_slice
994 : : !!
995 : : !! SOURCE
996 : :
997 [ - + ]: 18 : subroutine slice_splitSpectrum(slice, moments)
998 : :
999 : : implicit none
1000 : :
1001 : : ! Arguments ------------------------------------
1002 : : type(slice_t), intent(inout) :: slice
1003 : : real(dp), intent(inout) :: moments(:)
1004 : :
1005 : : ! Local variables --------------------------------
1006 : : integer :: uppb_loc, ib
1007 : : integer :: ngrid_fine, ngrid_coarse
1008 : : integer :: half_index, i_left, i_right
1009 : : integer :: i_split, num_moments
1010 : : logical :: gap_left, gap_right
1011 : : real(dp) :: a, b
1012 : : real(dp) :: center, radius
1013 : : real(dp) :: step_fine, step_coarse
1014 : : real(dp) :: partial_mass, half_mass
1015 : : real(dp) :: b_scaled
1016 : : real(dp) :: mass_left, mass_right
1017 : : real(dp) :: lambda_plus_wanted
1018 : 18 : real(dp), allocatable :: cumm_eigen_count(:)
1019 : 18 : real(dp), allocatable :: bgrid_fine(:)
1020 : 18 : real(dp), allocatable :: bgrid_coarse(:)
1021 : 18 : real(dp), allocatable :: work(:)
1022 : : character(len=500) :: msg
1023 : :
1024 : : ! *********************************************************************
1025 : :
1026 [ - + ]: 18 : if (slice%nslice/=2) then
1027 : 0 : ABI_ERROR("spectral bidirectional split not yet implemented for 3 slices")
1028 : : end if
1029 : :
1030 : 18 : ngrid_coarse = 10 ! coarse, just to find uppb, hardcoded
1031 : 18 : ngrid_fine = 30 ! used for cumulative eigenvalue count, hardcoded
1032 : :
1033 : 18 : a = slice%mineig_global
1034 : 18 : b = slice%maxeig_global
1035 : :
1036 : 18 : num_moments = size(moments)
1037 [ - + + - : 54 : ABI_MALLOC(work, (num_moments))
+ - + - -
+ - + -
+ ]
1038 [ - + ]: 18 : ABI_MALLOC(bgrid_coarse, (ngrid_coarse))
1039 [ - + ]: 18 : ABI_MALLOC(bgrid_fine, (ngrid_fine))
1040 [ - + ]: 18 : ABI_MALLOC(cumm_eigen_count, (ngrid_fine))
1041 : :
1042 : 18 : center = (a + b) / 2.d0
1043 : 18 : radius = (b - a) / 2.d0
1044 : :
1045 : : ! #########################################
1046 : : ! ########## Coarse resolution ############
1047 : : ! #########################################
1048 : :
1049 : : ! scan with lowpass
1050 : : ! first pass uppb is actually unknown
1051 : 18 : step_coarse = (b - a) / (ngrid_coarse - 1)
1052 [ + - + + : 594 : bgrid_coarse = (/ ( a + (ib-1)*step_coarse, ib=1,ngrid_coarse ) /)
+ - + + +
- - + - -
+ + ]
1053 : 18 : uppb_loc = -1
1054 [ + - ]: 36 : do ib=1, ngrid_coarse
1055 : 36 : b_scaled = (bgrid_coarse(ib) - center) / radius
1056 : 36 : partial_mass = get_eigenvalue_count(b_scaled, moments, work)
1057 : :
1058 : 36 : write(std_out,*) ib, 'scan: <=', bgrid_coarse(ib), 'mass=', partial_mass
1059 : 36 : flush(std_out)
1060 : :
1061 [ + + ]: 36 : if (partial_mass > slice%neigenpairs) then
1062 : : uppb_loc = ib
1063 : : exit
1064 : : end if
1065 : :
1066 : : end do
1067 : :
1068 : 18 : lambda_plus_wanted = (bgrid_coarse(uppb_loc-1) + bgrid_coarse(uppb_loc)) / 2.d0
1069 : 18 : write(std_out,*) 'found upp bound in', lambda_plus_wanted
1070 : 18 : write(std_out,*) 'estimated mass=', get_eigenvalue_count((lambda_plus_wanted-center)/radius, moments, work)
1071 : 18 : write(std_out,*) 'starting adaptive refinement ..'
1072 : 18 : flush(std_out)
1073 : :
1074 : : ! #########################################
1075 : : ! ########### Fine resolution #############
1076 : : ! #########################################
1077 : :
1078 : : ! Now compute eigenvalue count
1079 : 18 : step_fine = (lambda_plus_wanted - a) / (ngrid_fine - 1)
1080 [ + - + + : 1674 : bgrid_fine = (/ (a + (ib-1)*step_fine, ib=1,ngrid_fine) /)
+ - + + +
- - + - -
+ + ]
1081 [ + + ]: 558 : do ib=1, ngrid_fine
1082 : 540 : b_scaled = (bgrid_fine(ib) - center) / radius
1083 : 540 : partial_mass = get_eigenvalue_count(b_scaled, moments, work)
1084 : 540 : cumm_eigen_count(ib) = partial_mass
1085 [ - + - - ]: 540 : if (partial_mass < 0.d0 .and. abs(partial_mass) > 1.d0) then
1086 : 0 : write(msg,'(a)') "fine resolution for eigenvalue count failed due to oscillations. ",&
1087 : 0 : "Reduce ndeg_filter_max (hard-coded) as a solution"
1088 : 0 : ABI_ERROR(msg)
1089 : : end if
1090 : 558 : write(std_out,*) ib, 'scan: <=', bgrid_fine(ib), 'mass=', partial_mass
1091 : : end do
1092 : : !! todo if not found then add points in the fine grid...
1093 : :
1094 : : ! Prepare: detect gap existence in the interior of slice
1095 : : ! define value of smallest_gap
1096 : : ! todo
1097 : :
1098 : : ! step 1 cut in half balanced mass
1099 : 18 : half_mass = cumm_eigen_count(ngrid_fine)/2.d0
1100 [ + - + - : 576 : half_index = minloc(abs(half_mass - cumm_eigen_count), dim=1)
+ + + + ]
1101 : : ! step 2 adjust so that it is on constant mass (predicts gap)
1102 : : ! bidirectional search left and right
1103 : 18 : write(std_out,*) 'bidirectional search from index=', half_index
1104 : 18 : write(std_out,*) 'half mass=', half_mass
1105 : 18 : flush(std_out)
1106 : 18 : i_left = half_index
1107 : 18 : i_right = half_index
1108 : 18 : gap_left = .false.
1109 : 18 : gap_right = .false.
1110 [ + + - + ]: 36 : do while((.not.gap_right .and. .not.gap_left) .and. (i_left >= 2 .and. i_right <=ngrid_fine-1))
1111 : : ! this is if gap exists. If it does not exist.. must minimize using smallest_gap
1112 : 18 : gap_left = abs(cumm_eigen_count(i_left) - cumm_eigen_count(i_left-1)) < 1e-4
1113 : 18 : gap_right = abs(cumm_eigen_count(i_right) - cumm_eigen_count(i_right+1)) < 1e-4
1114 : 18 : i_left = i_left - 1
1115 : 18 : i_right = i_right + 1
1116 : : end do
1117 [ + - ]: 18 : if (gap_right) then
1118 : 18 : i_split = i_right
1119 : : end if
1120 [ - + ]: 18 : if (gap_left) then
1121 : 0 : i_split = i_left
1122 : : end if
1123 [ - + ]: 18 : if (.not.gap_right .and. .not.gap_left) then
1124 : : ! todo treat this case
1125 : 0 : ABI_ERROR("spectrum has no gap..")
1126 : : end if
1127 : 18 : mass_left = get_eigenvalue_count((bgrid_fine(i_split)-center)/radius,moments,work)
1128 : 18 : mass_right = slice%neigenpairs - mass_left
1129 : 18 : write(std_out,*) 'i_split val=', i_split, bgrid_fine(i_split)
1130 : 18 : write(std_out,*) 'mass left=', mass_left
1131 : 18 : write(std_out,*) 'mass right=', mass_right
1132 : 18 : flush(std_out)
1133 : :
1134 : : ! Store results into the slice
1135 [ + - ]: 18 : slice%neigen_per_slice(1) = ceiling(mass_left)
1136 [ + - ]: 18 : slice%neigen_per_slice(2) = ceiling(mass_right)
1137 : :
1138 : 18 : slice%low_bounds(1) = slice%mineig
1139 : 18 : slice%low_bounds(2) = bgrid_fine(i_split)
1140 : :
1141 : 18 : slice%upp_bounds(1) = bgrid_fine(i_split)
1142 : 18 : slice%upp_bounds(2) = bgrid_fine(ngrid_fine)
1143 : :
1144 : 18 : ABI_FREE(bgrid_fine)
1145 : 18 : ABI_FREE(bgrid_coarse)
1146 : 18 : ABI_FREE(cumm_eigen_count)
1147 [ - + ]: 18 : ABI_FREE(work)
1148 : :
1149 : 18 : end subroutine slice_splitSpectrum
1150 : : !!***
1151 : :
1152 : : !----------------------------------------------------------------------
1153 : :
1154 : : !!****f* m_slice/slice_applySelectionWindow
1155 : : !! NAME
1156 : : !! slice_applySelectionWindow
1157 : : !!
1158 : : !! FUNCTION
1159 : : !! Input: k=m+p ou m la masse et p oversampling parameter
1160 : : !! step 1) calculer les valeurs de Ritz
1161 : : !! step 2) calculer les residus
1162 : : !! step 3) mettre les valeurs de Ritz dans part_low_bounds, part_upp_bounds sous condition que res<tol
1163 : : !! step 4) sinon faire un sketch de taille K du reste
1164 : : !!
1165 : : !! INPUT
1166 : : !! safe is between 2 and 10
1167 : : !!
1168 : : !! OUTPUT
1169 : : !! mapper contains the column indices per slice (allowing repetitions)
1170 : : !!
1171 : : !! SOURCE
1172 : :
1173 [ - + ]: 18 : subroutine slice_applySelectionWindow(slice, mapper, eigen, resid, tol, safe)
1174 : :
1175 : : implicit none
1176 : :
1177 : : type(slice_t), intent(inout) :: slice
1178 : : logical, intent(inout) :: mapper(:,:)
1179 : : type(xgBlock_t), intent(inout) :: eigen
1180 : : type(xgBlock_t), intent(inout) :: resid
1181 : : real(dp), intent(in) :: tol
1182 : : real(dp), intent(in) :: safe
1183 : :
1184 : : integer :: nband, iband, islice, m, k_kept
1185 : : real(dp) :: uppb, lowb, uppb_plus, lowb_minus
1186 : : real(dp) :: theta, relaxf, relres
1187 : : real(dp), pointer :: resid_vals(:,:) => null()
1188 : : complex(dp), pointer :: thetas(:,:) => null()
1189 : :
1190 : : ! *********************************************************************
1191 : :
1192 : 18 : nband = slice%neigenpairs
1193 : :
1194 : 18 : call xgBlock_reverseMap(eigen, thetas, rows=nband, cols=1)
1195 : 18 : call xgBlock_reverseMap(resid, resid_vals, rows=nband, cols=1)
1196 : :
1197 : : ! apply selection window per slice
1198 [ + + ]: 54 : do islice=1,slice%nslice
1199 : 36 : m = slice%neigen_per_slice(islice)
1200 : 36 : lowb = slice%low_bounds(islice)
1201 : 36 : uppb = slice%upp_bounds(islice)
1202 : 36 : write(std_out,*) islice, 'slice bounds', lowb, uppb
1203 : :
1204 : : ! keep candidates in expanded interval
1205 : 36 : k_kept = 0
1206 [ + + ]: 6948 : do iband=1, nband
1207 : 6912 : relres = resid_vals(iband, 1)
1208 [ - + ]: 6948 : if (relres < tol) then
1209 : : ! Soft selection:
1210 : : ! relaxed bounds for converged eigenpairs near boundaries
1211 : 0 : relaxf = safe * relres
1212 : 0 : lowb_minus = lowb - relaxf
1213 : 0 : uppb_plus = uppb + relaxf
1214 : 0 : theta = real(thetas(iband, 1))
1215 : 0 : write(std_out,*) iband, 'theta=', theta, 'resid=', relres
1216 : 0 : flush(std_out)
1217 : :
1218 : : ! accept if lambda in relaxed interval
1219 [ # # # # ]: 0 : if (theta < uppb_plus .and. theta > lowb_minus) then
1220 : 0 : k_kept = k_kept + 1
1221 : 0 : mapper(iband, islice) = .true.
1222 : : end if
1223 : : end if
1224 : : end do
1225 : :
1226 : : ! todo m not set must modify computeTraceEstimation and separate the split spectrum from that
1227 : : ! because split spectrum will store info on slice object that is invisible from trace
1228 : 36 : write(std_out,*) 'selection window kept', k_kept, 'for eigendimension', m
1229 : 54 : flush(std_out)
1230 : : end do
1231 : :
1232 : 18 : end subroutine slice_applySelectionWindow
1233 : : !!***
1234 : :
1235 [ # # # # : 0 : end module m_slice
# # # # #
# # # # #
# # # # #
# ]
1236 : : !!***
|