Branch data Line data Source code
1 : : !!****f* ABINIT/m_slice_cprj
2 : : !! NAME
3 : : !! m_slice_cprj
4 : : !!
5 : : !! FUNCTION
6 : : !! This module contains the types and routines used to apply the
7 : : !! Spectrum Slicing method (2021 implementation using xG abstraction layer)
8 : : !! It mainly defines a 'slice' datatypes and associated methods.
9 : : !!
10 : : !! COPYRIGHT
11 : : !! Copyright (C) 2023-2025 ABINIT group (LB,IML)
12 : : !! This file is distributed under the terms of the
13 : : !! gnu general public license, see ~abinit/COPYING
14 : : !! or http://www.gnu.org/copyleft/gpl.txt .
15 : : !! for the initials of contributors, see ~abinit/doc/developers/contributors.txt .
16 : : !!
17 : : !! SOURCE
18 : :
19 : : #if defined HAVE_CONFIG_H
20 : : #include "config.h"
21 : : #endif
22 : :
23 : : #include "abi_common.h"
24 : :
25 : : module m_slice_cprj
26 : :
27 : : use defs_basis
28 : : use defs_abitypes
29 : : use m_abicore
30 : : use m_errors
31 : : use m_time, only : timab
32 : : use m_sort, only: sort_dp
33 : :
34 : : use m_cgtools
35 : : use m_xg
36 : : use m_xgTransposer
37 : : use m_xg_ortho_RR
38 : : use m_xg_nonlop
39 : :
40 : : use m_polynomial_filter, only: buildChebyshevJacksonCoeffs
41 : : use m_trace_estimation, only: smallestTridiagEigenpair
42 : :
43 : : use m_xmpi
44 : : use m_xomp
45 : : #ifdef HAVE_OPENMP
46 : : use omp_lib
47 : : #endif
48 : :
49 : : implicit none
50 : :
51 : : private
52 : :
53 : : !Several (private) parameters
54 : : !-------------------------------------------------
55 : :
56 : : integer, parameter :: tim_init = 2171
57 : : integer, parameter :: tim_free = 2172
58 : : integer, parameter :: tim_cprj = 2173
59 : : integer, parameter :: tim_invovl = 2174
60 : : integer, parameter :: tim_residu = 2175
61 : : integer, parameter :: tim_RR = 2176
62 : : integer, parameter :: tim_transpose = 2177
63 : : integer, parameter :: tim_RR_q = 2178
64 : : integer, parameter :: tim_postinvovl = 2179
65 : : integer, parameter :: tim_swap = 2180
66 : : integer, parameter :: tim_amp_f = 2181
67 : : integer, parameter :: tim_barrier = 2182
68 : : integer, parameter :: tim_copy = 2183
69 : : integer, parameter :: tim_ax_k = 2184
70 : : integer, parameter :: tim_ax_v = 2185
71 : : integer, parameter :: tim_ax_nl = 2186
72 : : integer, parameter :: tim_enl = 2187
73 : : integer, parameter :: tim_ortho = 2188
74 : :
75 : : integer, parameter :: tim_slice1_fi = 2190
76 : : integer, parameter :: tim_slice1_rr = 2191
77 : : integer, parameter :: tim_slice1_pr = 2192
78 : : integer, parameter :: tim_slice2_fi = 2193
79 : : integer, parameter :: tim_slice2_rr = 2194
80 : : integer, parameter :: tim_slice2_pr = 2195
81 : :
82 : : !Public 'slice' datatype
83 : : !-------------------------------------------------
84 : :
85 : : type, public :: slice_t
86 : :
87 : : integer :: space
88 : : integer :: space_cprj
89 : : integer :: spacedim ! Space dimension for one vector
90 : : integer :: cprjdim ! cprj dimension
91 : : integer :: blockdim_cprj ! ncols of cprj for slice only
92 : : integer :: all_blockdim_cprj ! ncols of cprj for all vectors
93 : : integer :: neigenpairs ! Number of eigen values/vectors we want
94 : : integer :: ndeg_filter ! Degree of the polynomial filter as input
95 : : integer :: nslice ! Number of spectral slices
96 : : integer :: slicedim ! Number of eigen values/vectors we want in one slice
97 : : integer :: paral_slice ! slice parallelization strategy (off)
98 : : integer :: spectral_cut ! how to cut the eigenvalue spectral interval (off)
99 : : integer :: nbdbuf ! Number of bands in the buffer
100 : : real(dp) :: tolerance ! Tolerance on the residu to stop the minimization
101 : : real(dp) :: ecut ! Ecut for Chebfi oracle
102 : : real(dp) :: tolfilter ! Polynomial filter wanted amplification
103 : :
104 : : ! MPI-related
105 : : integer :: bandpp
106 : : integer :: total_spacedim ! Maybe not needed
107 : : integer :: spacecom ! Communicator for MPI
108 : :
109 : : logical :: paw
110 : : integer :: eigenProblem !1 (A*x = (lambda)*B*x), 2 (A*B*x = (lambda)*x), 3 (B*A*x = (lambda)*x)
111 : : integer :: me_g0
112 : : integer :: me_g0_fft
113 : :
114 : : !ARRAYS for entire spectum
115 : : type(xgBlock_t) :: AllX ! Block of initial and final solution
116 : : type(xg_t) :: AllAX ! space to save AX Hamiltonian application
117 : :
118 : : ! cprj for entire spectrum
119 : : type(xgBlock_t) :: AllcprjX
120 : : type(xg_t) :: Allcprj_work
121 : :
122 : : !ARRAYS on slice using slice-safe memory
123 : : type(xg_t) :: X_SLICE ! memory independent of the entire spectrum
124 : : type(xgBlock_t) :: X ! pointers to slice memory
125 : : type(xgBlock_t) :: AX !
126 : :
127 : : ! space to hold X_next, X_prev for Chebyshev recursion, slice only
128 : : type(xg_t) :: X_NP
129 : : type(xgBlock_t) :: X_next
130 : : type(xgBlock_t) :: X_prev
131 : : !SWAP POINTERS on slice, also for Chebyshev recursion
132 : : type(xgBlock_t) :: X_swap
133 : : type(xgBlock_t) :: AX_swap
134 : :
135 : : ! cprj for slice only
136 : : type(xgBlock_t) :: cprjX ! pointer to AllcprjX
137 : : type(xgBlock_t) :: cprj_work ! pointer to Allcprj_work
138 : : type(xg_t) :: cprj_work2
139 : :
140 : : ! Independent of number of vectors, common to slice and spectrum
141 : : type(xg_t) :: proj_work
142 : : type(xg_nonlop_t) :: xg_nonlop
143 : :
144 : : type(xgBlock_t) :: eigenvalues
145 : :
146 : : end type slice_t
147 : :
148 : : !Public methods associated to 'slice' datatype
149 : : !-------------------------------------------------
150 : : public :: slice_init
151 : : public :: slice_free
152 : : public :: slice_memInfo
153 : : public :: slice_run_cprj
154 : :
155 : : CONTAINS !========================================================================================
156 : : !!***
157 : :
158 : : !!****f* m_slice_cprj/slice_init
159 : : !! NAME
160 : : !! slice_init
161 : : !!
162 : : !! FUNCTION
163 : : !! Initialize a 'slice' datastructure.
164 : : !!
165 : : !! INPUTS
166 : : !! bandpp= number of 'bands' handled by a processor
167 : : !! eigenProblem= type of eigenpb: 1 (A*x = (lambda)*B*x), 2 (A*B*x = (lambda)*x), 3 (B*A*x = (lambda)*x)
168 : : !! me_g0= 1 if this processors treats G=0, 0 otherwise
169 : : !! neigenpairs= number of requested eigenvectors/eigenvalues
170 : : !! ndeg_filter= polynomial degree of the Chebyshev filter (.i.e. number of H applications)
171 : : !! space= defines in which space we are (columns, rows, etc.)
172 : : !! spacecom= MPI communicator
173 : : !! spacedim= space dimension for one vector
174 : : !! paw= flag. TRUE if current calculation ses the PAW approach
175 : : !! ecut= plane-wave cut-off energy
176 : : !! tolerance= tolerance criterion on the residu to stop the minimization
177 : : !! nslice= number of slices
178 : : !! tolfilter= tolerance for filter amplification (a priori)
179 : : !! paral_slice= slice parallelization
180 : : !! spectral_cut= how to cut the eigenvalue spectrum (a priori)
181 : : !!
182 : : !! OUTPUT
183 : : !!
184 : : !! SIDE EFFECTS
185 : : !! slice <type(slice_t)>=all data used to apply Spectrum Slicing algorithm
186 : : !!
187 : : !! SOURCE
188 : :
189 : 0 : subroutine slice_init(slice,neigenpairs,spacedim,cprjdim,tolerance,ecut,bandpp, &
190 : : ndeg_filter,nbdbuf,space,space_cprj,eigenProblem,spacecom,me_g0,paw,&
191 : : nslice,tolfilter,paral_slice,spectral_cut,xg_nonlop,me_g0_fft)
192 : :
193 : : !Arguments ------------------------------------
194 : : integer , intent(in ) :: bandpp
195 : : integer , intent(in ) :: eigenProblem
196 : : integer , intent(in ) :: me_g0
197 : : integer , intent(in ) :: me_g0_fft
198 : : integer , intent(in ) :: neigenpairs
199 : : integer , intent(in ) :: ndeg_filter
200 : : integer , intent(in ) :: nbdbuf
201 : : integer , intent(in ) :: space
202 : : integer , intent(in ) :: space_cprj
203 : : integer , intent(in ) :: spacecom
204 : : integer , intent(in ) :: spacedim
205 : : integer , intent(in ) :: cprjdim
206 : : integer , intent(in ) :: nslice
207 : : integer , intent(in ) :: paral_slice
208 : : integer , intent(in ) :: spectral_cut
209 : : logical , intent(in ) :: paw
210 : : real(dp) , intent(in ) :: ecut
211 : : real(dp) , intent(in ) :: tolerance
212 : : real(dp) , intent(in ) :: tolfilter
213 : : type(xg_nonlop_t), intent(in ) :: xg_nonlop
214 : : type(slice_t) , intent(inout) :: slice
215 : :
216 : : !Local variables-------------------------------
217 : : real(dp) :: tsec(2)
218 : :
219 : : ! *********************************************************************
220 : :
221 : 0 : call timab(tim_init,1,tsec)
222 : :
223 : 0 : slice%space = space
224 : 0 : slice%space_cprj = space_cprj
225 : 0 : slice%neigenpairs = neigenpairs
226 : 0 : slice%spacedim = spacedim
227 : 0 : slice%bandpp = bandpp
228 : 0 : slice%spacecom = spacecom
229 : 0 : slice%cprjdim = cprjdim
230 : 0 : slice%tolerance = 1.0e-20
231 [ # # ]: 0 : if (tolerance > 0.0) then
232 : 0 : slice%tolerance = tolerance
233 : : end if
234 : 0 : slice%ecut = ecut
235 : 0 : slice%ndeg_filter = ndeg_filter
236 : 0 : slice%nbdbuf = nbdbuf
237 : 0 : slice%eigenProblem = eigenProblem
238 : 0 : slice%me_g0 = me_g0
239 : 0 : slice%me_g0_fft = me_g0_fft
240 : 0 : slice%paw = paw
241 [ # # # # : 0 : slice%xg_nonlop = xg_nonlop
# # # # #
# # # # #
# # # # #
# ]
242 : :
243 : : ! slice specific
244 : 0 : slice%nslice = nslice
245 : 0 : slice%tolfilter = tolfilter
246 : 0 : slice%paral_slice = paral_slice
247 : 0 : slice%spectral_cut = spectral_cut
248 : :
249 : : ! cprj depending on number of bands specific
250 : : !slice%blockdim_cprj = slice%slicedim*xg_nonlop%nspinor
251 : 0 : slice%blockdim_cprj = slice%neigenpairs*xg_nonlop%nspinor
252 : 0 : slice%all_blockdim_cprj = neigenpairs*xg_nonlop%nspinor
253 : :
254 : 0 : call slice_allocateAll(slice)
255 : :
256 : 0 : call timab(tim_init,2,tsec)
257 : :
258 : 0 : end subroutine slice_init
259 : : !!***
260 : :
261 : : !----------------------------------------------------------------------
262 : :
263 : : !!****f* m_slice_cprj/slice_allocateAll
264 : : !! NAME
265 : : !! slice_allocateAll
266 : : !!
267 : : !! FUNCTION
268 : : !! Allocate all memory spaces in a 'slice' datastructure.
269 : : !!
270 : : !! INPUTS
271 : : !!
272 : : !! OUTPUT
273 : : !!
274 : : !! SIDE EFFECTS
275 : : !! slice <type(slice_t)>=all data used to apply Spectrum Slicing algorithm
276 : : !!
277 : : !! SOURCE
278 : :
279 : 0 : subroutine slice_allocateAll(slice)
280 : :
281 : : ! Arguments ------------------------------------
282 : : type(slice_t) , intent(inout) :: slice
283 : :
284 : : ! Local variables-------------------------------
285 : : ! scalars
286 : : integer :: neigenpairs
287 : : integer :: space,space_cprj
288 : : integer :: spacedim
289 : : integer :: slicedim
290 : : integer :: total_spacedim, ierr
291 : : integer :: nspinor
292 : :
293 : : ! *********************************************************************
294 : :
295 : 0 : space = slice%space
296 : 0 : space_cprj = slice%space_cprj
297 : 0 : spacedim = slice%spacedim
298 : : !slicedim = slice%slicedim
299 : 0 : slicedim = slice%neigenpairs
300 : 0 : neigenpairs = slice%neigenpairs
301 : 0 : nspinor = slice%xg_nonlop%nspinor
302 : :
303 : 0 : call slice_free(slice)
304 : :
305 : 0 : total_spacedim = spacedim
306 : 0 : call xmpi_sum(total_spacedim,slice%spacecom,ierr)
307 : 0 : slice%total_spacedim = total_spacedim
308 : :
309 : : ! transposed arrays (for slice only)
310 : 0 : call xg_init(slice%X_NP,space,total_spacedim,2*slicedim,xmpi_comm_self,me_g0=slice%me_g0_fft)
311 : 0 : call xg_setBlock(slice%X_NP,slice%X_next,total_spacedim,slicedim)
312 : 0 : call xg_setBlock(slice%X_NP,slice%X_prev,total_spacedim,slicedim,fcol=slicedim+1)
313 : :
314 : : ! This is temporary slice workspace that is the same for all slice initially
315 : 0 : call xg_init(slice%X_SLICE,space,total_spacedim,2*slicedim,xmpi_comm_self,me_g0=slice%me_g0_fft)
316 : 0 : call xg_setBlock(slice%X_SLICE,slice%X,total_spacedim,slicedim)
317 : 0 : call xg_setBlock(slice%X_SLICE,slice%AX,total_spacedim,slicedim,fcol=slicedim+1)
318 : : ! note: the last two are necessary to set space and me_g0 for slice%X and slice%AX
319 : :
320 : : ! cprj workspaces (for entire spectrum)
321 : 0 : call xg_init(slice%AllAX,space,spacedim,neigenpairs,slice%spacecom,me_g0=slice%me_g0)
322 : 0 : call xg_init(slice%Allcprj_work,space_cprj,slice%cprjdim,slice%all_blockdim_cprj,slice%spacecom)
323 : :
324 : : ! cprj workspaces (for slice only)
325 : 0 : call xg_init(slice%cprj_work2,space_cprj,slice%cprjdim,slice%blockdim_cprj,slice%spacecom)
326 : :
327 : : ! cprj workspaces common to slices and entire spectrum
328 : 0 : call xg_init(slice%proj_work,space,slice%xg_nonlop%max_npw_k,slice%xg_nonlop%cprjdim,slice%spacecom,me_g0=slice%me_g0)
329 : :
330 : 0 : end subroutine slice_allocateAll
331 : : !!***
332 : :
333 : : !----------------------------------------------------------------------
334 : :
335 : : !!****f* m_slice_cprj/slice_free
336 : : !! NAME
337 : : !! slice_free
338 : : !!
339 : : !! FUNCTION
340 : : !! Destroy a 'slice' datastructure.
341 : : !!
342 : : !! INPUTS
343 : : !!
344 : : !! OUTPUT
345 : : !! arraymem(2)= memory information
346 : : !!
347 : : !! SIDE EFFECTS
348 : : !! slice <type(slice_t)>=all data used to apply Spectrum Slicing algorithm
349 : : !!
350 : : !! SOURCE
351 : :
352 : 0 : subroutine slice_free(slice)
353 : :
354 : : !Arguments ------------------------------------
355 : : type(slice_t) , intent(inout) :: slice
356 : :
357 : : ! *********************************************************************
358 : :
359 : 0 : call xg_free(slice%X_NP)
360 : 0 : call xg_free(slice%X_SLICE)
361 : 0 : call xg_free(slice%Allcprj_work)
362 : 0 : call xg_free(slice%cprj_work2)
363 : 0 : call xg_free(slice%proj_work)
364 : 0 : call xg_free(slice%AllAX)
365 : 0 : call xg_free(slice%Allcprj_work)
366 : :
367 : 0 : end subroutine slice_free
368 : : !!***
369 : :
370 : : !----------------------------------------------------------------------
371 : :
372 : : !!****f* m_slice_cprj/slice_memInfo
373 : : !! NAME
374 : : !! slice_memInfo
375 : : !!
376 : : !! FUNCTION
377 : : !! Provides memory information about a 'slice' datastructure.
378 : : !!
379 : : !! INPUTS
380 : : !! bandpp= number of 'bands' handled by a processor
381 : : !! neigenpairs= number of requested eigenvectors/eigenvalues
382 : : !! paral_kgb= flag controlling (k,g,bands) parallelization
383 : : !! space= defines in which space we are (columns, rows, etc.)
384 : : !! spacedim= dimension of MPI communicator
385 : : !! total_spacedim= size of global KGB communicator (typically 'banspinorfft' comm.)
386 : : !!
387 : : !! OUTPUT
388 : : !! arraymem(2)= memory information
389 : : !!
390 : : !! SIDE EFFECTS
391 : : !! slice <type(slice_t)>=all data used to apply Spectrum Slicing algorithm
392 : : !!
393 : : !! SOURCE
394 : :
395 [ # # ]: 0 : function slice_memInfo(neigenpairs,spacedim,space,total_spacedim,bandpp) result(arraymem)
396 : :
397 : : !Arguments ------------------------------------
398 : : integer, intent(in ) :: bandpp
399 : : integer, intent(in ) :: neigenpairs
400 : : integer, intent(in ) :: space
401 : : integer, intent(in ) :: spacedim
402 : : integer, intent(in ) :: total_spacedim
403 : :
404 : : !Local variables-------------------------------
405 : : !scalars
406 : : real(dp) :: memX
407 : : real(dp) :: memX_next
408 : : real(dp) :: memX_prev
409 : : real(dp) :: memAX
410 : : real(dp) :: memBX
411 : : !Transposer variables
412 : : real(dp) :: memX_CR
413 : : real(dp) :: memAX_CR
414 : : real(dp) :: memBX_CR
415 : : !slice_rayleighRitz function variables
416 : : real(dp) :: memA_und_X
417 : : real(dp) :: memB_und_X
418 : : real(dp) :: memEigenvalues
419 : : real(dp) :: cplx
420 : : !arrays
421 : : real(dp) :: arraymem(2)
422 : :
423 : : ! *********************************************************************
424 : 0 : cplx = 1
425 [ # # ]: 0 : if ( space == SPACE_C ) cplx = 2 !for now only complex
426 : :
427 : : !Permanent in slice
428 : 0 : memX = cplx * kind(1.d0) * spacedim * neigenpairs
429 : :
430 : : ! if (paral_kgb == 0) then
431 : : ! memX_next = cplx * kind(1.d0) * spacedim * neigenpairs
432 : : ! memX_prev = cplx * kind(1.d0) * spacedim * neigenpairs
433 : : ! else
434 : 0 : memX_next = cplx * kind(1.d0) * total_spacedim * bandpp
435 : 0 : memX_prev = cplx * kind(1.d0) * total_spacedim * bandpp
436 : : ! end if
437 : :
438 : 0 : memAX = cplx * kind(1.d0) * spacedim * neigenpairs
439 : 0 : memBX = cplx * kind(1.d0) * spacedim * neigenpairs
440 : :
441 : : !Transposer colrow array
442 : : ! if (paral_kgb == 1) then
443 : 0 : memX_CR = cplx * kind(1.d0) * total_spacedim * bandpp
444 : 0 : memAX_CR = cplx * kind(1.d0) * total_spacedim * bandpp
445 : 0 : memBX_CR = cplx * kind(1.d0) * total_spacedim * bandpp
446 : : ! else
447 : : ! memX_CR = 0
448 : : ! memAX_CR = 0
449 : : ! memBX_CR = 0
450 : : ! end if
451 : :
452 : : !slice_rayleighRitz function variables
453 : 0 : memA_und_X = cplx * kind(1.d0) * neigenpairs * neigenpairs
454 : 0 : memB_und_X = cplx * kind(1.d0) * neigenpairs * neigenpairs
455 : 0 : memEigenvalues = kind(1.d0) * neigenpairs
456 : :
457 : : arraymem(1) = memX + memX_next + memX_prev + &
458 : 0 : memAX + memBX + memX_CR + memAX_CR + memBX_CR
459 : 0 : arraymem(2) = memA_und_X + memB_und_X + memEigenvalues
460 : :
461 : 0 : end function slice_memInfo
462 : : !!***
463 : :
464 : : !----------------------------------------------------------------------
465 : :
466 : : !!****f* m_slice_cprj/slice_run_cprj
467 : : !! NAME
468 : : !! slice_run_cprj
469 : : !!
470 : : !! FUNCTION
471 : : !! Apply the Spectrum Slicing algorithm on a set of vectors.
472 : : !!
473 : : !! INPUTS
474 : : !! mpi_enreg = information about MPI parallelization
475 : : !! getAX_BX= pointer to the function giving A|X> and B|X>
476 : : !! A is typically the Hamiltonian H, and B the overlap operator S
477 : : !! getBm1X= pointer to the function giving B^-1|X>
478 : : !! B is typically the overlap operator S
479 : : !!
480 : : !! OUTPUT
481 : : !!
482 : : !! SIDE EFFECTS
483 : : !! slice <type(slice_t)>=all data used to apply Spectrum Slicing algorithm
484 : : !! eigen= Full eigenvalues (initial values on entry)
485 : : !! residu= residuals, i.e. norm of (A-lambdaB)|X>
486 : : !! X0= Full set of vectors (initial values on entry)
487 : : !!
488 : : !! SOURCE
489 : :
490 : 0 : subroutine slice_run_cprj(slice,X0,cprjX0,getAX,kin,eigen,occ,residu,enl,nspinor)
491 : :
492 : : !Arguments ------------------------------------
493 : : type(slice_t) , intent(inout) :: slice
494 : : integer, intent(in) :: nspinor
495 : : type(xgBlock_t), intent(inout) :: X0
496 : : type(xgBlock_t), intent(inout) :: cprjX0
497 : : type(xgBlock_t), intent(inout) :: eigen
498 : : type(xgBlock_t), intent(in) :: occ
499 : : type(xgBlock_t), intent(inout) :: residu
500 : : type(xgBlock_t), intent(inout) :: enl
501 : : type(xgBlock_t), intent(in ) :: kin
502 : : interface
503 : : subroutine getAX(X,AX)
504 : : use m_xg, only : xgBlock_t
505 : : type(xgBlock_t), intent(inout) :: X
506 : : type(xgBlock_t), intent(inout) :: AX
507 : : end subroutine getAX
508 : : end interface
509 : :
510 : : !Local variables-------------------------------
511 : : !scalars
512 : : integer :: spacedim
513 : : integer :: space_res
514 : : integer :: neigenpairs
515 : : integer :: nslice
516 : : integer :: spectral_cut
517 : : integer :: paral_slice
518 : : integer :: ndeg_filter,ndeg_filter_max
519 : : integer :: deg_i
520 : : integer :: ideg, ierr, j
521 : : integer :: iband, islice
522 : : integer :: slicedim
523 : : !integer :: shift_x,shift_cprj
524 : : !integer :: niter, max_niter_restart
525 : : integer :: count_mask
526 : : integer :: count_rr
527 : : integer :: count_merge
528 : : integer :: count_slice
529 : : integer :: icount
530 : : integer :: blockdim_cprj
531 : : integer :: fcol_in, lcol_in
532 : : integer :: fcol_dummy, lcol_dummy, ncount_out
533 : : integer :: fcol_global
534 : : integer :: ndeg, ndeg_max
535 : : integer :: tim_slice_fi
536 : : integer :: tim_slice_rr
537 : : integer :: tim_slice_pr
538 : : integer :: my_rank
539 : : integer :: trace_degree, trace_rank
540 : : integer :: nstep_spectrum
541 : : integer :: kmax
542 : : integer :: nfilters, nstep_bisect, ishift
543 : : integer :: nvec_approx
544 : : !integer :: ideg_shift
545 : : integer :: nm
546 : : real(dp) :: balance_prev, balance_this
547 : : real(dp) :: conf_tol
548 : : !real(dp) :: tol_step
549 : : !real(dp) :: tol_probe
550 : : real(dp) :: tolerance
551 : : real(dp) :: tolfilter
552 : : real(dp) :: ramp
553 : : real(dp) :: maxeig, maxeig_global
554 : : real(dp) :: mineig, mineig_global
555 : : real(dp) :: lambda_minus, alpha_minus
556 : : real(dp) :: lambda_plus, alpha_plus
557 : : real(dp) :: ls_in, us_in
558 : : real(dp) :: f_u, f_l, f_uw, f_lw
559 : : real(dp) :: overlap_width
560 : : real(dp) :: one_over_r
561 : : real(dp) :: two_over_r
562 : : real(dp) :: center
563 : : real(dp) :: radius
564 : : real(dp) :: ls, us, cdeg, mu, damp
565 : : real(dp) :: min_low_est
566 : : !real(dp) :: amp_ideg
567 : : !real(dp) :: ein_ideg, eout_ideg
568 : : !real(dp) :: trace_est
569 : : real(dp) :: trace_est_slice1!, trace_est_slice2
570 : : real(dp) :: low_bound, upp_bound, min_low_bound
571 : : real(dp) :: min_upp_bound, max_upp_bound
572 : : real(dp) :: lambda_min, res_norm ! lanczos
573 : : real(dp) :: lower_i, upper_i, mid_i, width
574 : : complex(dp) :: meanz
575 : : real(dp) :: norm2_, variance
576 : : real(dp) :: tol12 = 1.0e-12
577 : : type(xg_t) :: Xsum
578 : : type(xg_t) :: DivResults
579 : : type(xg_t) :: norm2_X
580 : : type(xg_t) :: dot_XfX, norm2_fX
581 : : !type(xg_t) :: res_temp
582 : : type(xg_t) :: X0_out, eigen_out
583 : : type(xgBlock_t) :: X0_out_part, eigen_out_part
584 : : type(xgBlock_t) :: X_in, eigen_in
585 : : !type(xgBlock_t) :: DivResults_part
586 : : !type(xgBlock_t) :: X_prev
587 : : !type(xgBlock_t) :: cprjX_prev
588 : : !type(xgBlock_t) :: cprj_work_prev
589 : : !type(xgBlock_t) :: eig_part
590 : : type(xgBlock_t) :: X_col, AX_col
591 : : type(xg_t) :: X_kept, AX_kept
592 : : type(xg_t) :: cprj_work_slice, cprj_work2_slice
593 : : type(xgBlock_t) :: X_kept_col, AX_kept_col
594 : : type(xgBlock_t) :: eigenvalues_slice, residu_slice
595 : : !type(xg_t) :: X_part
596 : : !type(xg_t) :: AX_part
597 : : !type(xg_t) :: cprjX_part
598 : : integer,parameter :: gpu_option=ABI_GPU_DISABLED
599 : : !arrays
600 : : real(dp) :: tsec(2)
601 : 0 : integer, allocatable :: permute_cols(:)
602 : : !integer, allocatable :: sorted_idx(:) ! same as permute_cols but used elsewhere
603 : 0 : integer, allocatable :: probe_idx(:)
604 : 0 : integer, allocatable :: nb_vec_slices(:)
605 : 0 : real(dp), allocatable :: upper_bound_slices(:)
606 : 0 : real(dp), allocatable :: rayleigh_quotients(:)
607 : 0 : real(dp), allocatable :: energy_filters_left(:,:)
608 : 0 : real(dp), allocatable :: energy_filters_right(:,:)
609 : 0 : real(dp), allocatable :: lower_bounds(:)
610 : 0 : real(dp), allocatable :: upper_bounds(:)
611 : 0 : real(dp), allocatable, target :: cja(:)
612 : 0 : real(dp), allocatable, target :: energy_interval(:)
613 : 0 : real(dp), allocatable :: confi_interval_left(:), confi_interval_right(:)
614 : : real(dp), pointer :: probe(:) => null()
615 : : real(dp), pointer :: probe_XfX(:,:) => null()
616 : : real(dp), pointer :: X0_norm2(:) => null()
617 : : !real(dp), pointer :: lambda_apost(:) => null()
618 : : real(dp), pointer :: lambda_apost_slice(:) => null()
619 : : real(dp), pointer :: theta_(:,:) => null()
620 : : real(dp), pointer :: cheby_moments(:,:) => null()
621 : : real(dp), pointer :: resid(:) => null()
622 : : !Pointers similar to old Chebfi
623 : 0 : type(xg_nonlop_t) :: xg_nonlop
624 : : type(xg_t) :: xgX
625 : : complex(dp), pointer :: Xprobe(:,:) => null()
626 : :
627 : : ! *********************************************************************
628 : :
629 : : ! ITEST
630 : 0 : write(std_out,*) 'inside slice_run'
631 : 0 : write(std_out,*) 'nslice=', slice%nslice
632 : 0 : flush(std_out)
633 : : ! ITEST
634 : :
635 : 0 : write(std_out,*) 'occ array not used', rows(occ), cols(occ)
636 : 0 : flush(std_out)
637 : :
638 : : ! Warning; the entire code assumes this for simplicity and debugging purposes
639 [ # # ]: 0 : ABI_CHECK(slice%bandpp == slice%neigenpairs, "slice_cprj not implemented in MPI")
640 : :
641 : 0 : ABI_WARNING("experimental code is not debugged")
642 : :
643 : : ! Read scalar variables
644 : 0 : nslice = slice%nslice
645 : 0 : slicedim = slice%slicedim
646 : 0 : tolfilter = slice%tolfilter
647 : 0 : spectral_cut = slice%spectral_cut
648 : 0 : paral_slice = slice%paral_slice
649 : 0 : spacedim = slice%spacedim
650 : 0 : neigenpairs = slice%neigenpairs
651 : 0 : ndeg_filter = slice%ndeg_filter
652 : 0 : tolerance = slice%tolerance
653 [ # # # # : 0 : xg_nonlop = slice%xg_nonlop
# # # # #
# # # # #
# # # # #
# ]
654 : :
655 : : ! Set space of results (with symmetry or not)..
656 [ # # ]: 0 : if (slice%space==SPACE_C) then
657 : 0 : space_res = SPACE_C
658 [ # # ]: 0 : else if (slice%space==SPACE_CR) then
659 : 0 : space_res = SPACE_R
660 : : else
661 : 0 : ABI_ERROR('space(X) should be SPACE_C or SPACE_CR')
662 : : end if
663 : :
664 : : ! Allocations
665 : : ! DivResults stores Rayleigh quotients
666 : 0 : call xg_init(DivResults, space_res, neigenpairs, 1)
667 [ # # # # : 0 : ABI_MALLOC(permute_cols, (neigenpairs))
# # # # #
# # # ]
668 [ # # # # : 0 : ABI_MALLOC(probe_idx, (neigenpairs))
# # # # ]
669 [ # # # # : 0 : ABI_MALLOC(rayleigh_quotients, (neigenpairs))
# # # # #
# # # ]
670 [ # # # # : 0 : ABI_MALLOC(confi_interval_left, (neigenpairs))
# # # # ]
671 [ # # # # : 0 : ABI_MALLOC(confi_interval_right, (neigenpairs))
# # # # ]
672 [ # # # # : 0 : ABI_MALLOC(nb_vec_slices, (nslice))
# # # # #
# # # ]
673 [ # # # # : 0 : ABI_MALLOC(upper_bound_slices, (nslice))
# # # # #
# # # ]
674 [ # # # # : 0 : ABI_MALLOC(lower_bounds, (nslice))
# # # # ]
675 [ # # # # : 0 : ABI_MALLOC(upper_bounds, (nslice))
# # # # ]
676 : :
677 : : ! Memory used to store results of slice merging.
678 : 0 : call xg_init(X0_out, slice%space, spacedim, neigenpairs, slice%spacecom, me_g0=slice%me_g0)
679 : 0 : call xg_init(eigen_out, SPACE_R, 1, neigenpairs)
680 : :
681 : 0 : call xg_init(norm2_fX, SPACE_R, neigenpairs, 1)
682 : 0 : call xg_init(norm2_X,SPACE_R,neigenpairs,1)
683 : 0 : call xg_init(dot_XfX, space_res, neigenpairs, 1)
684 : :
685 : : ! Set initial vectors from input guess
686 : 0 : slice%eigenvalues = eigen
687 : :
688 : : ! workspace named "All" will store input and output solution
689 : 0 : slice%AllX = X0
690 : 0 : slice%AllcprjX = cprjX0
691 : :
692 : : ! Compute cprjX for all X (in colsrows)
693 : 0 : call timab(tim_cprj,1,tsec)
694 : 0 : call xg_nonlop_getcprj(xg_nonlop,slice%AllX,slice%AllcprjX,slice%proj_work%self)
695 : 0 : call timab(tim_cprj,2,tsec)
696 : :
697 : : !Compute A * Psi
698 : 0 : call timab(tim_AX_v,1,tsec)
699 : 0 : call getAX(slice%AllX,slice%AllAX%self)
700 : 0 : call timab(tim_AX_v,2,tsec)
701 : 0 : call timab(tim_AX_k,1,tsec)
702 : 0 : call xgBlock_add_diag(slice%AllX,kin,nspinor,slice%AllAX%self)
703 : 0 : call timab(tim_AX_k,2,tsec)
704 : 0 : call timab(tim_AX_nl,1,tsec)
705 : 0 : call xg_nonlop_getHX(xg_nonlop,slice%AllAX%self,slice%AllcprjX,slice%Allcprj_work%self,slice%proj_work%self)
706 : 0 : call timab(tim_AX_nl,2,tsec)
707 : :
708 : : !
709 : : ! ------------------------------------------------------------
710 : : ! Compute Rayleigh quotient for every band
711 : : ! ------------------------------------------------------------
712 : : !
713 : :
714 : 0 : call timab(tim_RR_q, 1, tsec)
715 : 0 : call slice_rayleighRitzQuotients(slice, maxeig, mineig, DivResults%self)
716 : 0 : call xmpi_max(maxeig,maxeig_global,slice%spacecom,ierr)
717 : 0 : call xmpi_min(mineig,mineig_global,slice%spacecom,ierr)
718 : 0 : call timab(tim_RR_q, 2, tsec)
719 : :
720 : : ! Recover column indices of sorted Rayleigh quotients in increasing order
721 : 0 : call xgBlock_reverseMap(DivResults%self, theta_, rows=1, cols=neigenpairs)
722 [ # # ]: 0 : rayleigh_quotients(1:neigenpairs) = theta_(1,1:neigenpairs)
723 : :
724 : : ! ITEST
725 : 0 : write(std_out,*) 'rayleigh quotients='
726 : 0 : call xgBlock_print(DivResults%self, std_out)
727 : 0 : flush(std_out)
728 : : ! ITEST
729 : :
730 : : ! Compute |X|^2 colwise L2-norm (before any filter)
731 : 0 : call xgBlock_colwiseNorm2(slice%AllX,norm2_X%self,comm_loc=xmpi_comm_null)
732 : 0 : call xgBlock_reverseMap_1d(norm2_X%self,X0_norm2)
733 : :
734 : : ! ITEST
735 : : !write(std_out,*) 'norm2(squared) ||X||='
736 : : !call xgBlock_print(norm2_X%self,std_out)
737 : : !flush(std_out)
738 : : ! ITEST
739 : : ! Results: |X|=1 so we don't have to normalize everything after..
740 : :
741 : : !
742 : : ! ------------------------------------------------------------
743 : : ! Approximate lowest eigenvalue
744 : : ! ------------------------------------------------------------
745 : : !
746 : :
747 : 0 : kmax = 100
748 : 0 : call computeBLanczos(slice, getAX, kin, spacedim, kmax, lambda_min, res_norm, gpu_option)
749 : 0 : min_low_bound = lambda_min - res_norm
750 : :
751 : 0 : write(std_out,*) 'Lanczos lambda_min=', lambda_min
752 : 0 : write(std_out,*) 'Lanczos res_norm =', res_norm
753 : 0 : write(std_out,*) 'Lanczos guarantee =', min_low_bound
754 : 0 : flush(std_out)
755 : :
756 [ # # ]: 0 : if (res_norm > 0.1d0) then
757 : 0 : ABI_WARNING("Lanczos has residual > 0.1 may need greater kmax to guarantee lower bound")
758 : : end if
759 : :
760 : : !
761 : : ! ------------------------------------------------------------
762 : : ! Split spectrum to slices based on spectral gaps
763 : : ! ------------------------------------------------------------
764 : : !
765 : :
766 : 0 : nstep_spectrum = 30
767 [ # # # # : 0 : min_upp_bound = maxval(rayleigh_quotients)
# # # # ]
768 : 0 : my_rank = xmpi_comm_rank(slice%spacecom)
769 : 0 : max_upp_bound = slice%ecut
770 : 0 : min_low_est = min_low_bound - min(5*res_norm,0.1d0) ! experimental
771 : 0 : trace_rank = neigenpairs ! FIXME for the moment changing this produces a bug
772 : : trace_degree = 50
773 : :
774 : 0 : write(std_out,*) 'splitting spectrum to slices within global', min_low_est, max_upp_bound
775 : 0 : write(std_out,*) ' wanted', min_low_bound, min_upp_bound
776 : 0 : flush(std_out)
777 : : ! call splitSpectrumToSlices(slice, nslice, trace_rank, trace_degree, nstep_spectrum, &
778 : : ! min_low_bound, min_upp_bound, min_low_est, max_upp_bound, my_rank, getAX, kin, &
779 : : ! nb_vec_slices, upper_bound_slices, & ! output
780 : : ! gpu_option=gpu_option)
781 : :
782 : : ! Au31 system
783 : : !upper_bound_slices(1) = 0.10d0 ! TODO hardcoded!
784 : : ! Alu system
785 : 0 : upper_bound_slices(1) = 1.37d0 ! hardcoded
786 : :
787 : : ! Slice 1:
788 : 0 : my_rank = xmpi_comm_rank(slice%spacecom)
789 : 0 : low_bound = min_low_bound ! [a,b)
790 : 0 : upp_bound = upper_bound_slices(1)
791 : 0 : trace_degree = 80
792 : :
793 : : !call computeTraceEstimation(slice, trace_rank, trace_degree, low_bound, upp_bound,&
794 : : ! min_low_est, max_upp_bound, trace_est_slice1, getAX, kin, my_rank, gpu_option=gpu_option)
795 : 0 : write(std_out,*) 'trace estimation for slice1, deg=', trace_est_slice1, trace_degree
796 : 0 : flush(std_out)
797 : :
798 : : ! Slice 2:
799 : 0 : my_rank = xmpi_comm_rank(slice%spacecom)
800 : 0 : low_bound = upper_bound_slices(1) ! [a,b)
801 : 0 : upp_bound = maxval(rayleigh_quotients)
802 : 0 : overlap_width = (upp_bound - low_bound)/10.0
803 : 0 : low_bound = low_bound - overlap_width
804 : : min_low_est = min_low_est
805 : 0 : max_upp_bound = slice%ecut
806 : 0 : trace_degree = 50
807 : 0 : trace_rank = neigenpairs ! FIXME for the moment changing this produces a bug
808 : :
809 : : !call computeTraceEstimation(slice, trace_rank, trace_degree, low_bound, upp_bound,&
810 : : ! min_low_est, max_upp_bound, trace_est_slice2, getAX, kin, my_rank, gpu_option=gpu_option)
811 : : !write(std_out,*) 'trace estimation for slice2, deg=', trace_est_slice2, trace_degree
812 : : !flush(std_out)
813 : :
814 : : ! attention slice%X est modifie n'est plus X0..
815 : : !! normalement il faut remettre slice%X a valeurs de AllX --->
816 : :
817 : :
818 : : !! ------------------------------------------------------------
819 : : !!
820 : : !! - Spectral trees -
821 : : !!
822 : : !! Probe nband with low degree just to prune and reduce to n.
823 : : !! Then actually filter in parallel using high optimal degree.
824 : : !! Spirit of two-step multiresolution.
825 : : !!
826 : : !! Spectral multigrid method. Tree traversal method.
827 : : !! Try to detect number of vectors with spectral trees (hierarchy).
828 : : !! Pay high filter degrees only where spectrum mass lies.
829 : : !!
830 : : !! ------------------------------------------------------------
831 : :
832 : : ! Reset pointers to dimensions of nband (assumes sequential slices)
833 : 0 : call xg_setBlock(slice%X_SLICE,slice%X,slice%total_spacedim,neigenpairs)
834 : 0 : call xg_setBlock(slice%X_SLICE,slice%AX,slice%total_spacedim,neigenpairs,fcol=neigenpairs+1)
835 : :
836 : : ! Initial slice workspaces are independent entire arrays
837 : 0 : call xgBlock_copy(slice%AllX, slice%X)
838 : 0 : call xgBlock_copy(slice%AllAX%self, slice%AX)
839 : :
840 : : ! the two following ones will be recomputed so whatever
841 : 0 : slice%cprjX = slice%AllcprjX
842 : 0 : slice%cprj_work = slice%Allcprj_work%self
843 : :
844 : : ! reinitialize pointers to workspaces ...
845 : 0 : call xg_setBlock(slice%X_NP,slice%X_next,slice%total_spacedim,slice%neigenpairs)
846 : 0 : call xg_setBlock(slice%X_NP,slice%X_prev,slice%total_spacedim,slice%neigenpairs,fcol=slice%neigenpairs+1)
847 : :
848 : 0 : ndeg_filter_max = 80 ! low degree
849 : : ! if energy oscillates instead of being monotonous this means we have to increase
850 : : ! degree
851 : :
852 : 0 : write(std_out,*) 'Spectral trees %%%%%%%%%'
853 : 0 : write(std_out,*) 'ndeg_filter_max=', ndeg_filter_max
854 : 0 : write(std_out,*) 'min_low_est=', min_low_est
855 : 0 : write(std_out,*) 'max_upp_bound=', max_upp_bound
856 : 0 : write(std_out,*) ' ********************** '
857 : 0 : flush(std_out)
858 : :
859 : 0 : call xg_init(xgX, slice%space, spacedim, neigenpairs, slice%spacecom, me_g0=slice%me_g0)
860 : 0 : call xgBlock_reverseMap(xgX%self, Xprobe, spacedim, neigenpairs)
861 [ # # ]: 0 : call generateRademacherMatrix(Xprobe, spacedim, neigenpairs, my_rank)
862 : :
863 : 0 : nm = spacedim * neigenpairs
864 [ # # # # ]: 0 : meanz = sum(Xprobe) / dcmplx(nm,0.0d0)
865 [ # # # # ]: 0 : norm2_ = sum(abs(Xprobe)**2) / nm
866 : 0 : variance = norm2_ - abs(meanz)**2
867 : :
868 : 0 : write(std_out,*) "mean = ", meanz
869 : 0 : write(std_out,*) "E|z|^2 = ", norm2_
870 : 0 : write(std_out,*) "variance = ", variance
871 : 0 : call xgBlock_copy(xgX%self, slice%X)
872 : 0 : write(std_out,*) xgBlock_getid(slice%X)
873 : 0 : flush(std_out)
874 : :
875 : : call computeChebyshevMoments(slice, getAX, kin, min_low_est, max_upp_bound, &
876 : 0 : ndeg_filter_max, cheby_moments, gpu_option)
877 : :
878 : 0 : call xg_free(xgX)
879 : :
880 : : ! Ugly loop to set slice intervals
881 [ # # ]: 0 : do islice=1, nslice
882 : 0 : lambda_minus = upper_bound_slices(1)
883 : 0 : alpha_minus = upper_bound_slices(1)
884 [ # # ]: 0 : if (islice==1) then
885 : 0 : alpha_minus = min_low_bound
886 : 0 : alpha_plus = lambda_minus
887 : : else
888 [ # # # # : 0 : alpha_plus = maxval(rayleigh_quotients)
# # # # ]
889 : : end if
890 : 0 : overlap_width = (alpha_plus - alpha_minus)/10.0
891 : 0 : lambda_plus = alpha_plus+overlap_width
892 : 0 : lambda_minus = alpha_minus-overlap_width
893 [ # # ]: 0 : if (islice==1) then
894 : 0 : lambda_minus = alpha_minus ! otherwise it is outside the center
895 : 0 : lambda_plus = alpha_plus
896 : : end if
897 : 0 : lower_bounds(islice) = lambda_minus
898 : 0 : upper_bounds(islice) = lambda_plus
899 : : end do
900 : :
901 : 0 : nfilters = nslice
902 : 0 : nstep_bisect = 8 ! number of bisection steps
903 : :
904 [ # # # # : 0 : ABI_MALLOC(energy_filters_left, (neigenpairs, nstep_bisect))
# # # # #
# # # #
# ]
905 [ # # # # : 0 : ABI_MALLOC(energy_filters_right, (neigenpairs, nstep_bisect))
# # # # #
# ]
906 [ # # # # : 0 : ABI_MALLOC(energy_interval, (neigenpairs))
# # # # ]
907 [ # # ]: 0 : ABI_MALLOC(cja, (ndeg_filter_max+1))
908 : :
909 : 0 : upper_bounds(2) = 3.0d0 ! hardcoded FIXME auto
910 : 0 : center = (max_upp_bound + min_low_est)*0.5
911 : 0 : radius = (max_upp_bound - min_low_est)*0.5
912 : 0 : lower_i = lower_bounds(1)
913 : 0 : upper_i = upper_bounds(2)
914 : 0 : width = (upper_i - lower_i) / (nstep_bisect + 1)
915 : :
916 : 0 : write(std_out,*)
917 : 0 : write(std_out,*) 'lower_i=', lower_i
918 : 0 : write(std_out,*) 'upper_i=', upper_i
919 : :
920 : : ! total mass
921 : : call buildChebyshevJacksonCoeffs((lower_i-center)/radius, (upper_i-center)/radius, &
922 : 0 : ndeg_filter_max, cja)
923 : : call computeFilterEnergy(neigenpairs, ndeg_filter_max, cja, cheby_moments, &
924 : 0 : energy_interval, nvec_approx)
925 : 0 : write(std_out,*) 'nvec estimate in total', lower_i, upper_i
926 : 0 : write(std_out,*) nvec_approx
927 : 0 : flush(std_out)
928 : :
929 : : ! shifted bisection
930 [ # # ]: 0 : do ishift = 1, nstep_bisect
931 : :
932 : 0 : mid_i = lower_i + ishift * width
933 : 0 : deg_i = ndeg_filter_max
934 : :
935 : 0 : write(std_out,*) '========================================'
936 : 0 : write(std_out,*) 'ishift=', ishift
937 : 0 : write(std_out,*) 'mid_i =', mid_i
938 : :
939 : : ! Slice Left [a,b)
940 : 0 : call buildChebyshevJacksonCoeffs((lower_i-center)/radius, (mid_i-center)/radius, deg_i, cja)
941 : : call computeFilterEnergy(neigenpairs, deg_i, cja, cheby_moments, &
942 : 0 : energy_interval, nvec_approx)
943 : :
944 [ # # ]: 0 : energy_filters_left(:,ishift) = energy_interval(:)
945 : :
946 : 0 : write(std_out,*) 'nvec estimate left from X0 probe=', nvec_approx
947 : 0 : flush(std_out)
948 : :
949 : : ! Slice Right [b,c)
950 : 0 : call buildChebyshevJacksonCoeffs((mid_i-center)/radius, (upper_i-center)/radius, deg_i, cja)
951 : : call computeFilterEnergy(neigenpairs, deg_i, cja, cheby_moments, &
952 : 0 : energy_interval, nvec_approx)
953 : :
954 [ # # ]: 0 : energy_filters_right(:,ishift) = energy_interval(:)
955 : :
956 : 0 : write(std_out,*) 'nvec estimate right from X0 probe=', nvec_approx
957 : 0 : flush(std_out)
958 : :
959 : : !! Uniform mass bisection
960 : : !! si le degre est assez eleve alors la masse totale est
961 : : !! - constante
962 : : !! - egale a nband
963 : : !!
964 : : !! Actuellement la masse totale est 88<192. Ca veut dire qu'on pert de la masse.
965 : : !! Pour ca il faut augmenter l'overlap a droite et a gauche a mon avis.
966 : : !! todo nvec_approx sign flip means that we found important spectral
967 : : !! mass. Do not split there. also follow how the sign flip moves with degree
968 : : !! if it tends to go left or right. Take convergence into account by taking the limit.
969 : :
970 : : end do
971 : :
972 : : ! for every band print its nfilter scores
973 : 0 : write(std_out,*)
974 : 0 : write(std_out,*) 'j= ', nstep_bisect, 'scores'
975 [ # # ]: 0 : do j = 1, neigenpairs
976 : 0 : write(std_out,*) 'eigenvalue', j
977 [ # # ]: 0 : do ishift = 1, nstep_bisect
978 : 0 : balance_this = energy_filters_left(j,ishift) - energy_filters_right(j,ishift)
979 [ # # ]: 0 : if (ishift > 1) then
980 [ # # ]: 0 : if (balance_prev * balance_this < 0) then
981 : 0 : write(std_out,*) 'sign flip! significant mass between=', ishift-1, ishift
982 : : end if
983 : : end if
984 : 0 : write(std_out,*) energy_filters_left(j,ishift), energy_filters_right(j,ishift)
985 : 0 : balance_prev = balance_this
986 : : end do
987 : : end do
988 : 0 : write(std_out,*)
989 : 0 : flush(std_out)
990 : :
991 : : ! sign flip indicates presence of importance spectral mass
992 : : ! we should NOT cut in the (bi,bi+1) that contains the largest spectral mass
993 : : !! adding more nstep_bisect refines the interval (bi,bi+1) containing the large
994 : : !! spectral mass
995 : :
996 [ # # ]: 0 : ABI_FREE(energy_filters_left)
997 [ # # ]: 0 : ABI_FREE(energy_filters_right)
998 [ # # ]: 0 : ABI_FREE(cja)
999 : :
1000 : : !! TODO do the tree traversal
1001 : : !! like subdivide [A,B) and compute energy is each step
1002 : :
1003 : : !! ------------------------------------------------------------
1004 : : !!
1005 : : !! - Main slice loop -
1006 : : !!
1007 : : !! How to optimize degree using energies:
1008 : : !! Increase degree until the band becomes "energetically isolated"
1009 : : !! and further degree increase changes nothing important.
1010 : : !!
1011 : : !! TODO compute Chebyshev recursion for all filters at the same
1012 : : !! time with ONE recursion and MULTIPLE Xsum per slice. Then
1013 : : !! proceed to Rayleigh-Ritz if slice degree reached. Local operation.
1014 : : !!
1015 : : !! ------------------------------------------------------------
1016 : :
1017 : 0 : count_merge = 0
1018 : 0 : fcol_global = 1
1019 : :
1020 [ # # ]: 0 : do islice=1, nslice
1021 : :
1022 : 0 : write(std_out,*)
1023 : 0 : write(std_out,*) '====================Slice=================', islice
1024 : 0 : flush(std_out)
1025 : :
1026 : : !! ------------------------------------------------------------
1027 : : !!
1028 : : !! - Initialize slice workspaces from global workspaces
1029 : : !! Global to Slice operation -
1030 : : !!
1031 : : !! ------------------------------------------------------------
1032 : :
1033 : : ! Reset pointers to dimensions of nband (assumes sequential slices)
1034 : 0 : call xg_setBlock(slice%X_SLICE,slice%X,slice%total_spacedim,neigenpairs)
1035 : 0 : call xg_setBlock(slice%X_SLICE,slice%AX,slice%total_spacedim,neigenpairs,fcol=neigenpairs+1)
1036 : :
1037 : : ! Initial slice workspaces are independent entire arrays
1038 : 0 : call xgBlock_copy(slice%AllX, slice%X)
1039 : 0 : call xgBlock_copy(slice%AllAX%self, slice%AX)
1040 : :
1041 : : ! the two following ones will be recomputed so whatever
1042 : 0 : slice%cprjX = slice%AllcprjX
1043 : 0 : slice%cprj_work = slice%Allcprj_work%self
1044 : :
1045 : : ! reinitialize pointers to workspaces ...
1046 : 0 : call xg_setBlock(slice%X_NP,slice%X_next,slice%total_spacedim,slice%neigenpairs)
1047 : 0 : call xg_setBlock(slice%X_NP,slice%X_prev,slice%total_spacedim,slice%neigenpairs,fcol=slice%neigenpairs+1)
1048 : :
1049 : : !! ------------------------------------------------------------
1050 : : !!
1051 : : !! - Scalar polynomial tuning -
1052 : : !!
1053 : : !! Defining the degree, interval bounds, overlap..
1054 : : !! TODO move outside and before islice loop and store parameters
1055 : : !! into arrays
1056 : : !!
1057 : : !! ------------------------------------------------------------
1058 : :
1059 : : ! ongoing, hardcoded depends on previous code
1060 : 0 : lambda_minus = upper_bound_slices(1)
1061 : 0 : alpha_minus = upper_bound_slices(1)
1062 : :
1063 [ # # ]: 0 : if (islice==1) then
1064 : 0 : alpha_minus = min_low_bound
1065 : 0 : alpha_plus = lambda_minus
1066 : : else
1067 [ # # # # : 0 : alpha_plus = maxval(rayleigh_quotients)
# # # # ]
1068 : : end if
1069 : :
1070 : : ! overlapping between slices
1071 : 0 : overlap_width = (alpha_plus - alpha_minus)/10.0
1072 : 0 : lambda_plus = alpha_plus+overlap_width
1073 : 0 : lambda_minus = alpha_minus-overlap_width
1074 [ # # ]: 0 : if (islice==1) then
1075 : 0 : lambda_minus = alpha_minus ! otherwise it is outside the center
1076 : 0 : lambda_plus = alpha_plus
1077 [ # # ]: 0 : else if (islice==nslice) then
1078 : 0 : lambda_plus = alpha_plus ! there is nothing righwise of max anyway..
1079 : : ! lambda_plus too wide slows down convergence
1080 : : end if
1081 : :
1082 : : ! ITEST
1083 : 0 : write(std_out,*) 'global spectrum=', min_low_est, slice%ecut
1084 : 0 : write(std_out,*) 'wanted slice=', alpha_minus, alpha_plus
1085 : 0 : write(std_out,*) 'with overlap=', lambda_minus, lambda_plus
1086 : 0 : flush(std_out)
1087 : : ! ITEST
1088 : :
1089 : 0 : lower_bounds(islice) = lambda_minus
1090 : 0 : upper_bounds(islice) = lambda_plus
1091 : :
1092 : 0 : center = (slice%ecut + min_low_est)*0.5
1093 : 0 : radius = (slice%ecut - min_low_est)*0.5
1094 : 0 : ls = (lambda_minus - center) / radius
1095 : 0 : us = (lambda_plus - center) / radius
1096 : :
1097 : : ! Optimize polynomial degree with given tolerance
1098 : 0 : ramp = slice%tolfilter
1099 : 0 : ndeg_max = 200
1100 : 0 : ls_in = (alpha_minus - center) / radius ! scaled point inside slice
1101 : 0 : us_in = (alpha_plus - center) / radius ! scaled point inside slice
1102 : 0 : ndeg = 8
1103 : 0 : f_lw = 1.d0; f_uw = 1.d0; f_l = 1.d0; f_u = 1.d0
1104 : :
1105 : : ! Amplification is f(l-w)/f(l) and f(u+w)/f(u) (between 0 and 1)
1106 [ # # ]: 0 : if (islice==1) then
1107 [ # # # # ]: 0 : do while ( f_uw/f_u > ramp .and. ndeg < ndeg_max )
1108 : 0 : ndeg = ndeg + 1
1109 : 0 : f_u = bandpassIndicator_sca(us_in,ls,us,ndeg)
1110 : 0 : f_uw = bandpassIndicator_sca(us ,ls,us,ndeg)
1111 : : end do
1112 : : else
1113 [ # # # # : 0 : do while ( (f_lw/f_l > ramp .or. f_uw/f_u > ramp) .and. ndeg < ndeg_max )
# # ]
1114 : 0 : ndeg = ndeg + 1
1115 : 0 : f_l = bandpassIndicator_sca(ls_in,ls,us,ndeg)
1116 : 0 : f_lw = bandpassIndicator_sca(ls ,ls,us,ndeg)
1117 : 0 : f_u = bandpassIndicator_sca(us_in,ls,us,ndeg)
1118 : 0 : f_uw = bandpassIndicator_sca(us ,ls,us,ndeg)
1119 : : end do
1120 : : end if
1121 : :
1122 : 0 : ndeg = 90
1123 : :
1124 : 0 : ndeg_filter = ndeg
1125 : :
1126 : : ! ITEST
1127 : 0 : write(std_out,*) 'left/right amplif factor f(out)/f(in)=', f_lw/f_l, f_uw/f_u
1128 : 0 : write(std_out,*) 'minimal polynomial degree=', ndeg_filter
1129 : 0 : flush(std_out)
1130 : : ! ITEST
1131 : :
1132 : : !! ------------------------------------------------------------
1133 : : !!
1134 : : !! - Polynomial degree loop -
1135 : : !!
1136 : : !! ------------------------------------------------------------
1137 : :
1138 [ # # ]: 0 : if (islice==1) then
1139 : 0 : tim_slice_fi = tim_slice1_fi
1140 : : else
1141 : 0 : tim_slice_fi = tim_slice2_fi
1142 : : end if
1143 : :
1144 : 0 : call timab(tim_slice_fi,1,tsec)
1145 : :
1146 : : ! Initialize Chebyshev expansion of indicator function of order ndeg_filter
1147 : 0 : call xg_init(Xsum,slice%space,slice%total_spacedim,neigenpairs,slice%spacecom,gpu_option=gpu_option)
1148 : 0 : cdeg = Pi/(ndeg_filter+2)
1149 : 0 : mu = 1.d0/Pi*(ACOS(ls)-ACOS(us))
1150 : 0 : damp = 1.d0 ! Jackson damping
1151 : 0 : one_over_r = 1.d0/radius
1152 : 0 : two_over_r = 2.d0/radius
1153 : 0 : call xgBlock_saxpy(Xsum%self, mu*damp, slice%X)
1154 : :
1155 [ # # ]: 0 : do ideg = 0, ndeg_filter - 1
1156 : :
1157 : : ! ITEST
1158 : 0 : write(std_out,*) 'polynomial degree=', ideg
1159 : 0 : flush(std_out)
1160 : : ! ITEST
1161 : :
1162 : 0 : call timab(tim_cprj,1,tsec)
1163 : 0 : call xg_nonlop_getcprj(xg_nonlop,slice%AX,slice%cprjX,slice%proj_work%self)
1164 : 0 : call timab(tim_cprj,2,tsec)
1165 : :
1166 : 0 : call slice_computeNextOrderChebfiPolynom(slice, ideg, center, one_over_r, two_over_r)
1167 : :
1168 : 0 : call timab(tim_swap,1,tsec)
1169 : 0 : call slice_swapInnerBuffers(slice, slice%total_spacedim, neigenpairs)
1170 : 0 : call timab(tim_swap,2,tsec)
1171 : :
1172 : : ! Accumulate X with weight in Xsum for bandpass filters
1173 : 0 : mu = 2/Pi * (SIN((ideg+1)*ACOS(ls)) - SIN((ideg+1)*ACOS(us)))/(ideg+1)
1174 : : damp = ((1 - (ideg+1)/(ndeg_filter+2))*SIN(cdeg)*COS((ideg+1)*cdeg) + &
1175 : 0 : 1/(ndeg_filter+2)*COS(cdeg)*SIN((ideg+1)*cdeg))/SIN(cdeg)
1176 : 0 : call xgBlock_saxpy(Xsum%self, mu*damp, slice%X)
1177 : :
1178 [ # # ]: 0 : if (ideg==ndeg_filter - 1) then
1179 : :
1180 : : ! store final expansion Xsum to X
1181 : 0 : call xgBlock_copy(Xsum%self, slice%X)
1182 : :
1183 : : end if
1184 : :
1185 : : !A * Psi
1186 : 0 : call timab(tim_AX_v,1,tsec)
1187 : 0 : call getAX(slice%X,slice%AX)
1188 : 0 : call timab(tim_AX_v,2,tsec)
1189 : 0 : call timab(tim_AX_k,1,tsec)
1190 : 0 : call xgBlock_add_diag(slice%X,kin,nspinor,slice%AX)
1191 : 0 : call timab(tim_AX_k,2,tsec)
1192 : 0 : call timab(tim_cprj,1,tsec)
1193 : 0 : call xg_nonlop_getcprj(xg_nonlop,slice%X,slice%cprjX,slice%proj_work%self)
1194 : 0 : call timab(tim_cprj,2,tsec)
1195 : 0 : call timab(tim_AX_nl,1,tsec)
1196 : 0 : call xg_nonlop_getHX(xg_nonlop,slice%AX,slice%cprjX,slice%cprj_work,slice%proj_work%self)
1197 : 0 : call timab(tim_AX_nl,2,tsec)
1198 : :
1199 : : end do ! End polynomial degree loop
1200 : :
1201 : 0 : call timab(tim_slice_fi,2,tsec)
1202 : :
1203 : : !! ------------------------------------------------------------
1204 : : !!
1205 : : !! - Vector pruning for subspace basis -
1206 : : !!
1207 : : !! The purpose of this step is to select the nvec vectors that
1208 : : !! have the greatest energy norm for the slice. No tolerance.
1209 : : !! We start from all vectors then we keep only nvec of them.
1210 : : !! For every column vector x with npw rows,
1211 : : !! * f(x) = ||f(M)x|| (option 1)
1212 : : !! * f(x) = x^T f(M) x (option 2)
1213 : : !!
1214 : : !! ------------------------------------------------------------
1215 : :
1216 [ # # ]: 0 : if (islice==1) then
1217 : 0 : tim_slice_pr = tim_slice1_pr
1218 : : else
1219 : 0 : tim_slice_pr = tim_slice2_pr
1220 : : end if
1221 : :
1222 : 0 : call timab(tim_slice_pr,1,tsec)
1223 : :
1224 : : ! Step 1
1225 : : ! =============
1226 : : ! Compute probe
1227 : : ! Note: option 1 gives betten results than option 2 so far
1228 : : ! =============
1229 : :
1230 [ # # ]: 0 : if (slice%spectral_cut == 1) then
1231 : : ! norm2_fX = <fX,fX> colwise L2-norm
1232 : 0 : call xgBlock_colwiseNorm2(slice%X, norm2_fX%self, comm_loc=xmpi_comm_null)
1233 : 0 : call xgBlock_reverseMap_1d(norm2_fX%self, probe)
1234 [ # # ]: 0 : else if (slice%spectral_cut == 2) then
1235 : : ! dot_XfX = <X,fX> colwise L2-dot product
1236 : 0 : call xgBlock_colwiseDotProduct(X0, slice%X, dot_XfX%self, comm_loc=xmpi_comm_null)
1237 : 0 : call xgBlock_reverseMap(dot_XfX%self, probe_XfX, rows=1, cols=neigenpairs)
1238 : 0 : probe => probe_XfX(1,1:neigenpairs)
1239 : : end if
1240 : :
1241 : : !write(std_out,*)
1242 : : !write(std_out,*) 'probe=', probe(:)
1243 : : !flush(std_out)
1244 : :
1245 : : ! Step 2
1246 : : ! =============
1247 : : ! Probe pruning
1248 : : ! =============
1249 : :
1250 [ # # ]: 0 : if (islice==1) then
1251 : : !count_mask = min(ceiling(trace_est_slice1), neigenpairs)
1252 : : !count_mask = ceiling(trace_est_slice1) + 20
1253 : 0 : count_mask = 150
1254 [ # # ]: 0 : else if (islice==2) then
1255 : : !count_mask = ceiling(neigenpairs - trace_est_slice1*0.8)
1256 : 0 : count_mask = 150
1257 : : end if
1258 : :
1259 [ # # ]: 0 : probe = -probe
1260 [ # # # # : 0 : probe_idx(1:neigenpairs) = (/ (iband, iband=1,neigenpairs) /)
# # ]
1261 [ # # ]: 0 : call sort_dp(neigenpairs, probe, probe_idx, tol12)
1262 [ # # ]: 0 : probe = -probe
1263 : :
1264 : 0 : write(std_out,*) 'kept probes', probe(1:count_mask)
1265 : :
1266 : : ! TODO
1267 : : ! deal with extra vectors: if great probes are found outside the kept ones maybe include them
1268 : : ! appending vectors should be within a loop here
1269 : :
1270 : : ! Step 3
1271 : : ! ==============================================
1272 : : ! Store kept vectors in contiguous memory layout
1273 : : ! ==============================================
1274 : :
1275 : : ! Allocate slice subspace memory, this is contiguous !!
1276 : 0 : call xg_init(X_kept,slice%space,slice%total_spacedim,count_mask,xmpi_comm_self,me_g0=slice%me_g0_fft)
1277 : 0 : call xg_init(AX_kept,slice%space,slice%total_spacedim,count_mask,xmpi_comm_self,me_g0=slice%me_g0_fft)
1278 : :
1279 [ # # ]: 0 : do icount=1,count_mask
1280 : :
1281 : 0 : iband = probe_idx(icount)
1282 : 0 : call xgBlock_setBlock(X_kept%self, X_kept_col, slice%total_spacedim, 1, fcol=icount)
1283 : 0 : call xgBlock_setBlock(AX_kept%self, AX_kept_col, slice%total_spacedim, 1, fcol=icount)
1284 : 0 : call xgBlock_setBlock(slice%X, X_col, slice%total_spacedim, 1, fcol=iband)
1285 : 0 : call xgBlock_setBlock(slice%AX, AX_col, slice%total_spacedim, 1, fcol=iband)
1286 : :
1287 : 0 : call timab(tim_copy, 1, tsec)
1288 : 0 : call xgBlock_copy(X_col, X_kept_col)
1289 : 0 : call xgBlock_copy(AX_col, AX_kept_col)
1290 : 0 : call timab(tim_copy, 2, tsec)
1291 : :
1292 : : end do
1293 : :
1294 : : ! reset pointers to temporary (kept)
1295 : 0 : slice%X = X_kept%self
1296 : 0 : slice%AX = AX_kept%self
1297 : :
1298 : : ! content is not important, but dimensions
1299 : 0 : call xgBlock_setBlock(slice%AllcprjX, slice%cprjX, slice%cprjdim, count_mask*nspinor)
1300 : :
1301 : : ! Recompute cprj to be sure
1302 : 0 : call timab(tim_cprj,1,tsec)
1303 : 0 : call xg_nonlop_getcprj(xg_nonlop,slice%X,slice%cprjX,slice%proj_work%self)
1304 : 0 : call timab(tim_cprj,2,tsec)
1305 : :
1306 : 0 : call timab(tim_slice_pr,2,tsec)
1307 : :
1308 : : !! ------------------------------------------------------------
1309 : : !!
1310 : : !! - Apply Rayleigh-Ritz step -
1311 : : !!
1312 : : !! ------------------------------------------------------------
1313 : :
1314 [ # # ]: 0 : if (islice==1) then
1315 : 0 : tim_slice_rr = tim_slice1_rr
1316 : : else
1317 : 0 : tim_slice_rr = tim_slice2_rr
1318 : : end if
1319 : :
1320 : : ! Number of vectors on which we apply rr
1321 : 0 : count_rr = count_mask
1322 : :
1323 : : ! restrict eigenvalue array for size consistency (essentially keep nonzero entries)
1324 : 0 : call xgblock_reshape(slice%eigenvalues, 1, neigenpairs)
1325 : 0 : call xgblock_setblock(slice%eigenvalues, eigenvalues_slice, rows=1, cols=count_rr)
1326 : 0 : call xgblock_reshape(eigenvalues_slice, count_rr, 1)
1327 : 0 : call xgblock_reshape(slice%eigenvalues, neigenpairs, 1)
1328 : :
1329 : : ! Orthonormalize (ca fait aucune difference)
1330 : : !call xg_Borthonormalize_cprj(xg_nonlop,slice%X,slice%cprjX,ierr,tim_ortho,&
1331 : : ! gpu_option,count_rr*xg_nonlop%nspinor,AX=slice%AX)
1332 : : !=blocksize_cprj
1333 : :
1334 : : ! Apply Rayleigh Ritz on slice (refinement)
1335 : : ! prtvol = 15015015 to print condition number of overlap matrix
1336 : : call xg_RayleighRitz_cprj(xg_nonlop,slice%X,slice%cprjX,slice%AX,eigenvalues_slice,&
1337 : 0 : ierr,15015015,tim_slice_rr,ABI_GPU_DISABLED,solve_ax_bx=.true.)
1338 : :
1339 [ # # ]: 0 : if ( ierr /= 0 ) then
1340 : 0 : ABI_BUG("RayleighRitz did not work")
1341 : : end if
1342 : :
1343 : : ! restart!
1344 : : ! call xg_RayleighRitz_cprj(xg_nonlop,slice%X,slice%cprjX,slice%AX,eigenvalues_slice,&
1345 : : ! ierr,15015015,tim_slice_rr,ABI_GPU_DISABLED,solve_ax_bx=.true.)
1346 : :
1347 : : ! if ( ierr /= 0 ) then
1348 : : ! ABI_BUG("RayleighRitz did not work")
1349 : : ! end if
1350 : :
1351 : : ! ITEST
1352 : 0 : write(std_out,*) 'converged eigenval='
1353 : 0 : call xgBlock_print(eigenvalues_slice, std_out)
1354 : 0 : flush(std_out)
1355 : : ! ITEST
1356 : :
1357 : : ! Restrict dimension of residual array
1358 : 0 : call xgBlock_reshape(residu, 1, neigenpairs)
1359 : 0 : call xgBlock_setBlock(residu, residu_slice, rows=1, cols=count_rr)
1360 : 0 : call xgBlock_reshape(residu_slice, count_rr, 1)
1361 : 0 : call xgBlock_reshape(residu, neigenpairs, 1)
1362 : :
1363 : : !! ------------------------------------------------------------
1364 : : !!
1365 : : !! - Compute residual HX-eSX on slice -
1366 : : !!
1367 : : !! ------------------------------------------------------------
1368 : :
1369 : 0 : blockdim_cprj = count_rr*xg_nonlop%nspinor
1370 : 0 : call xg_init(cprj_work_slice,slice%space_cprj,slice%cprjdim,blockdim_cprj,slice%spacecom)
1371 : 0 : call xg_init(cprj_work2_slice,slice%space_cprj,slice%cprjdim,blockdim_cprj,slice%spacecom)
1372 : :
1373 : : ! Compute H-eSX
1374 [ # # ]: 0 : if (slice%paw) then
1375 : 0 : call timab(tim_AX_nl,1,tsec)
1376 : : call xg_nonlop_getHmeSX(xg_nonlop,slice%X,slice%cprjX,slice%AX,eigenvalues_slice,&
1377 : 0 : cprj_work_slice%self,cprj_work2_slice%self,no_H=.True.)
1378 : 0 : call timab(tim_AX_nl,2,tsec)
1379 : : end if
1380 : :
1381 : 0 : call xg_free(cprj_work_slice)
1382 : 0 : call xg_free(cprj_work2_slice)
1383 : :
1384 : : ! Compute residual norm squared
1385 : 0 : call timab(tim_residu, 1, tsec)
1386 [ # # ]: 0 : if (.not.slice%paw) then
1387 : 0 : call xgBlock_yxmax(slice%AX,eigenvalues_slice,slice%X)
1388 : : end if
1389 : 0 : call xgBlock_colwiseNorm2(slice%AX, residu_slice)
1390 : 0 : call timab(tim_residu, 2, tsec)
1391 : :
1392 : 0 : call xgBlock_reverseMap_1d(residu_slice, resid)
1393 : :
1394 : : ! ITEST
1395 : 0 : write(std_out,*) 'Slice ', islice, ': colwiseNorm2 residu='
1396 : 0 : call xgBlock_print(residu_slice, std_out)
1397 : 0 : flush(std_out)
1398 : : ! ITEST
1399 : :
1400 : : !! ------------------------------------------------------------
1401 : : !!
1402 : : !! - Diagnostic for full slices -
1403 : : !!
1404 : : !! ------------------------------------------------------------
1405 : :
1406 : 0 : call xgBlock_reverseMap_1d(eigenvalues_slice, lambda_apost_slice)
1407 : :
1408 : : ! count the confidence intervals within the slice and outside the slice
1409 : :
1410 [ # # ]: 0 : confi_interval_left(1:count_rr) = lambda_apost_slice + sqrt(resid)
1411 [ # # ]: 0 : confi_interval_right(1:count_rr) = lambda_apost_slice - sqrt(resid)
1412 : :
1413 [ # # ]: 0 : if (islice==1) then
1414 : 0 : write(std_out,*) 'wanted is <', lambda_minus
1415 : : else
1416 : 0 : write(std_out,*) 'wanted is ', alpha_minus, alpha_plus
1417 : : end if
1418 : 0 : flush(std_out)
1419 : :
1420 : : !! TODO etape suivante: une fois qu'on a diagnostiquer une mauvaise convergence
1421 : : !! dans une slice on pourrait faire une procedure de restart pour corriger
1422 : : !! l'erreur soit en ajoutant plus de vecteurs soit jsp a reflechir
1423 : :
1424 : :
1425 : : !! ------------------------------------------------------------
1426 : : !!
1427 : : !! - Slice to Global operation -
1428 : : !!
1429 : : !! Merge to X0_out, eigen_out using Rayleigh value as criterion
1430 : : !!
1431 : : !! ------------------------------------------------------------
1432 : :
1433 : 0 : lcol_in = count_rr
1434 [ # # # # : 0 : fcol_in = maxloc(lambda_apost_slice, dim=1, mask=(lambda_apost_slice < alpha_minus)) + 1
# # # # #
# # # #
# ]
1435 : :
1436 [ # # # # : 0 : conf_tol = maxval(sqrt(resid))
# # # # ]
1437 [ # # # # : 0 : fcol_dummy = maxloc(lambda_apost_slice, dim=1, mask=(lambda_apost_slice+conf_tol < alpha_minus)) + 1
# # # # #
# # # #
# ]
1438 : 0 : write(std_out,*) 'mergeD: fcol slice ', islice, ' ', fcol_in
1439 : 0 : write(std_out,*) 'mergeD: fcol slice ', islice, 'interval', fcol_dummy
1440 [ # # # # ]: 0 : ncount_out = count(lambda_apost_slice+conf_tol < alpha_minus)
1441 : 0 : write(std_out,*) 'mergeD: count out left', islice, ' ', ncount_out, 'out of', count_rr
1442 [ # # # # ]: 0 : ncount_out = count(lambda_apost_slice-conf_tol > alpha_plus)
1443 : 0 : write(std_out,*) 'mergeD: count outright', islice, ' ', ncount_out, 'out of', count_rr
1444 : 0 : write(std_out,*) 'mergeD-----------------------'
1445 : 0 : flush(std_out)
1446 : :
1447 [ # # ]: 0 : if (islice<nslice) then
1448 : :
1449 [ # # # # : 0 : lcol_in = maxloc(lambda_apost_slice, dim=1, mask=(lambda_apost_slice < alpha_plus))
# # # # #
# # # #
# ]
1450 : 0 : write(std_out,*) 'merge: interval on slice ', islice, ':', lcol_in; flush(std_out)
1451 : :
1452 : : else
1453 : :
1454 : 0 : write(std_out,*) 'merge: maximized on slice ', islice, ':', lcol_in
1455 [ # # # # : 0 : lcol_dummy = maxloc(lambda_apost_slice, dim=1, mask=(lambda_apost_slice < alpha_plus))
# # # # #
# # # #
# ]
1456 : 0 : write(std_out,*) 'merge: interval on slice***', islice, ':', lcol_in
1457 [ # # ]: 0 : write(std_out,*) 'merge: resid***************', islice, ':', sqrt(sum(resid(fcol_in:lcol_dummy)))
1458 : 0 : flush(std_out)
1459 : :
1460 [ # # ]: 0 : if (count_merge + lcol_in-fcol_in+1 > neigenpairs) then
1461 : 0 : write(std_out,*) 'merge: pass on slice ', islice, ':', lcol_in; flush(std_out)
1462 : 0 : lcol_in = fcol_in + neigenpairs - count_merge - 1
1463 : 0 : write(std_out,*) 'merge: pass after on slice ', islice, ':', lcol_in, fcol_in, neigenpairs, count_merge
1464 [ # # ]: 0 : write(std_out,*) 'merge: residBBBBBBBBBBBBBBB', islice, ':', sqrt(sum(resid(fcol_in:lcol_in)))
1465 : 0 : flush(std_out)
1466 : : end if
1467 : :
1468 : : end if
1469 : :
1470 : 0 : count_slice = lcol_in - fcol_in + 1
1471 : :
1472 : : ! ITEST
1473 [ # # ]: 0 : write(std_out,*) 'Frobenius norm (inside slice', islice, 'only)=', sqrt(sum(resid(fcol_in:lcol_in)))
1474 : 0 : flush(std_out)
1475 : : ! ITEST
1476 : :
1477 : : ! ITEST
1478 : 0 : write(std_out,*)
1479 : 0 : write(std_out,*) '====================================== Slice', islice
1480 : 0 : write(std_out,*) 'interval bounds', lambda_minus, alpha_minus, alpha_plus
1481 : : !write(std_out,*) 'count_merged=', count_merge
1482 : 0 : write(std_out,*) 'count_slice =', count_slice
1483 : 0 : write(std_out,*) 'count_rr =', count_rr
1484 : 0 : write(std_out,*) 'fcol_in,val =', fcol_in, lambda_apost_slice(fcol_in)
1485 : 0 : write(std_out,*) 'lcol_in,val =', lcol_in, lambda_apost_slice(lcol_in)
1486 : 0 : write(std_out,*) '======================================'
1487 : 0 : write(std_out,*)
1488 : 0 : flush(std_out)
1489 : : ! ITEST
1490 : :
1491 : 0 : count_merge = count_merge + count_slice
1492 [ # # ]: 0 : if (count_merge > neigenpairs) then
1493 : :
1494 : 0 : ABI_WARNING("Attempting to merge more bands than possible")
1495 : :
1496 : : end if
1497 : :
1498 [ # # # # ]: 0 : if (count_merge < neigenpairs .and. islice==nslice) then
1499 : :
1500 : 0 : write(std_out,*) 'missing eigenvalues!'
1501 : 0 : flush(std_out)
1502 : :
1503 : : end if
1504 : :
1505 : 0 : call xgBlock_setBlock(slice%X, X_in, spacedim, count_slice, fcol=fcol_in)
1506 : 0 : call xgBlock_reshape(eigenvalues_slice, 1, count_rr)
1507 : 0 : call xgBlock_setBlock(eigenvalues_slice, eigen_in, 1, count_slice, fcol=fcol_in)
1508 : 0 : call xgBlock_reshape(eigenvalues_slice, count_rr, 1)
1509 : :
1510 : 0 : call xgBlock_setBlock(X0_out%self, X0_out_part, spacedim, count_slice, fcol=fcol_global)
1511 : 0 : call xgBlock_setBlock(eigen_out%self, eigen_out_part, 1, count_slice, fcol=fcol_global)
1512 : :
1513 : 0 : call timab(tim_copy, 1, tsec)
1514 : 0 : call xgBlock_copy(X_in, X0_out_part)
1515 : 0 : call xgBlock_copy(eigen_in, eigen_out_part)
1516 : 0 : call timab(tim_copy, 2, tsec)
1517 : :
1518 : 0 : fcol_global = count_merge + 1
1519 : :
1520 : : !! Free slice memory whose size depends on count_mask, different for every slice
1521 : 0 : call xg_free(Xsum)
1522 : 0 : call xg_free(X_kept)
1523 : 0 : call xg_free(AX_kept)
1524 : :
1525 : : end do ! End loop on slices
1526 : :
1527 : : !! ------------------------------------------------------------
1528 : : !!
1529 : : !! - Final computation of cprjX, residu, enl -
1530 : : !!
1531 : : !! ------------------------------------------------------------
1532 : :
1533 : 0 : call xgBlock_reshape(eigen_out%self, neigenpairs, 1)
1534 : :
1535 : 0 : call timab(tim_copy, 1, tsec)
1536 : 0 : call xgBlock_copy(X0_out%self, X0)
1537 : 0 : call xgBlock_copy(eigen_out%self, eigen)
1538 : 0 : call timab(tim_copy, 2, tsec)
1539 : :
1540 : 0 : slice%eigenvalues = eigen
1541 : 0 : slice%AllX = X0
1542 : 0 : slice%AllcprjX = cprjX0
1543 : :
1544 : 0 : call timab(tim_cprj,1,tsec)
1545 : 0 : call xg_nonlop_getcprj(xg_nonlop,slice%AllX,slice%AllcprjX,slice%proj_work%self)
1546 : 0 : call timab(tim_cprj,2,tsec)
1547 : :
1548 : : ! A * Psi
1549 : 0 : call timab(tim_AX_v,1,tsec)
1550 : 0 : call getAX(slice%AllX,slice%AllAX%self)
1551 : 0 : call timab(tim_AX_v,2,tsec)
1552 : 0 : call timab(tim_AX_k,1,tsec)
1553 : 0 : call xgBlock_add_diag(slice%AllX,kin,nspinor,slice%AllAX%self)
1554 : 0 : call timab(tim_AX_k,2,tsec)
1555 : 0 : call timab(tim_AX_nl,1,tsec)
1556 : 0 : call xg_nonlop_getHX(xg_nonlop,slice%AllAX%self,slice%AllcprjX,slice%Allcprj_work%self,slice%proj_work%self)
1557 : 0 : call timab(tim_AX_nl,2,tsec)
1558 : :
1559 [ # # ]: 0 : if (slice%paw) then
1560 : 0 : call timab(tim_AX_nl,1,tsec)
1561 : : call xg_nonlop_getHmeSX(xg_nonlop,slice%AllX,slice%AllcprjX,slice%AllAX%self,slice%eigenvalues,&
1562 : 0 : slice%Allcprj_work%self,slice%cprj_work2%self,no_H=.True.)
1563 : 0 : call timab(tim_AX_nl,2,tsec)
1564 : : end if
1565 : :
1566 : : ! Compute residual norm squared
1567 : 0 : call timab(tim_residu, 1, tsec)
1568 [ # # ]: 0 : if (.not.slice%paw) then
1569 : 0 : call xgBlock_yxmax(slice%AllAX%self,slice%eigenvalues,slice%AllX)
1570 : : end if
1571 : 0 : call xgBlock_colwiseNorm2(slice%AllAX%self, residu)
1572 : 0 : call timab(tim_residu, 2, tsec)
1573 : :
1574 : : ! ITEST
1575 : 0 : call xgBlock_reverseMap_1d(residu, resid)
1576 [ # # ]: 0 : write(std_out,*) 'Frobenius norm (merged slices)=', sqrt(sum(resid))
1577 : 0 : write(std_out,*) 'resid (merged slices)='
1578 : 0 : call xgBlock_print(residu, std_out)
1579 : 0 : write(std_out,*) 'eigen (merged slices)='
1580 : 0 : call xgBlock_print(eigen, std_out)
1581 : 0 : flush(std_out)
1582 : : ! ITEST
1583 : :
1584 [ # # ]: 0 : if (.not.slice%paw) then
1585 : 0 : call timab(tim_enl,1,tsec)
1586 : 0 : call xg_nonlop_colwiseXHX(xg_nonlop,slice%AllcprjX,slice%Allcprj_work%self,enl)
1587 : 0 : call timab(tim_enl,2,tsec)
1588 : : end if
1589 : :
1590 : : ! Free memory used for slice merging
1591 : 0 : call xg_free(X0_out)
1592 : 0 : call xg_free(eigen_out)
1593 : :
1594 : 0 : call xg_free(norm2_X)
1595 : 0 : call xg_free(norm2_fX)
1596 : 0 : call xg_free(dot_XfX)
1597 : 0 : call xg_free(norm2_fX)
1598 [ # # ]: 0 : ABI_FREE(permute_cols)
1599 [ # # ]: 0 : ABI_FREE(rayleigh_quotients)
1600 [ # # ]: 0 : ABI_FREE(probe_idx)
1601 [ # # ]: 0 : ABI_FREE(confi_interval_left)
1602 [ # # ]: 0 : ABI_FREE(confi_interval_right)
1603 [ # # ]: 0 : ABI_FREE(nb_vec_slices)
1604 : 0 : ABI_FREE(upper_bound_slices)
1605 : 0 : ABI_FREE(lower_bounds)
1606 : 0 : ABI_FREE(upper_bounds)
1607 : :
1608 [ # # # # : 0 : end subroutine slice_run_cprj
# # # # #
# ]
1609 : : !!***
1610 : :
1611 : : !----------------------------------------------------------------------
1612 : :
1613 : : !!****f* m_slice_cprj/slice_orthoXwrtBlocks
1614 : : !! NAME
1615 : : !! slice_orthoXwrtBlocks
1616 : : !!
1617 : : !! FUNCTION
1618 : : !! same as lobpcg_orthoXwrtBlocks but X0 and cprjX0 is given in input
1619 : :
1620 : : subroutine slice_orthoXwrtBlocks(slice,X0,cprjX0,var,cprjvar,islice,cprj_work)
1621 : :
1622 : : type(slice_t) , intent(inout) :: slice
1623 : : type(xgBlock_t), intent(in) :: X0
1624 : : type(xgBlock_t), intent(inout) :: cprjX0
1625 : : type(xgBlock_t), intent(inout) :: var
1626 : : type(xgBlock_t), intent(inout) :: cprjvar
1627 : : type(xgBlock_t), intent(inout) :: cprj_work
1628 : : integer , intent(in ) :: islice
1629 : : integer :: previousBlock
1630 : : integer :: slicedim
1631 : : integer :: spacedim
1632 : : integer :: space_buf
1633 : : integer :: nspinor,cprjdim
1634 : : type(xg_t) :: buffer
1635 : : double precision :: tsec(2)
1636 : : type(xgBlock_t) :: cprjX0_spinor,cprj_work_spinor
1637 : :
1638 : : call timab(tim_ortho,1,tsec)
1639 : :
1640 : : if (islice<2) then
1641 : : ABI_ERROR("islice<2")
1642 : : end if
1643 : :
1644 : : if (cols(cprjvar)/=cols(cprj_work)) then
1645 : : ABI_ERROR("cprjvar and cprj_work should have same number of columns")
1646 : : end if
1647 : : slicedim = slice%slicedim
1648 : : spacedim = slice%spacedim
1649 : : previousBlock = (islice-1)*slice%slicedim
1650 : :
1651 : : cprjdim = slice%xg_nonlop%cprjdim
1652 : : nspinor = slice%xg_nonlop%nspinor
1653 : :
1654 : : space_buf = space(var)
1655 : : if (space(var)==SPACE_CR) then
1656 : : space_buf = SPACE_R
1657 : : end if
1658 : : call xg_init(buffer,space_buf,previousBlock,slicedim,slice%spacecom)
1659 : :
1660 : : ! buffer = X0^T*X
1661 : : call xgBlock_gemm('t','n',1.0d0,X0,var,0.d0,buffer%self,comm=slice%spacecom)
1662 : :
1663 : : ! Add the nonlocal part if paw
1664 : : if (slice%xg_nonlop%paw) then
1665 : : call xg_nonlop_getSX(slice%xg_nonlop,cprjX0,cprjvar,cprj_work,buffer%self)
1666 : : end if
1667 : :
1668 : : ! sum all process contribution
1669 : : ! X = - X0*(BX0^T*X) + X
1670 : : call xgBlock_gemm('n','n',-1.0d0,X0,buffer%self,1.0d0,var)
1671 : :
1672 : : call xgBlock_zero(cprj_work)
1673 : : call xgBlock_reshape_spinor(cprj_work,cprj_work_spinor,nspinor,COLS2ROWS)
1674 : : call xgBlock_reshape_spinor(cprjX0,cprjX0_spinor,nspinor,COLS2ROWS)
1675 : : call xgBlock_gemm_mpi_cyclic_permutation(cprjX0_spinor,buffer%self,cprj_work_spinor,&
1676 : : & slice%xg_nonlop%me_band,slice%blockdim_cprj/nspinor,comm=slice%xg_nonlop%comm_band)
1677 : : call xgBlock_saxpy(cprjvar,-1.0d0,cprj_work)
1678 : :
1679 : : call xg_free(buffer)
1680 : :
1681 : : call timab(tim_ortho,2,tsec)
1682 : :
1683 : : end subroutine slice_orthoXwrtBlocks
1684 : : !!***
1685 : :
1686 : : !----------------------------------------------------------------------
1687 : :
1688 : : !!****f* m_slice_cprj/slice_rayleighRitzQuotients
1689 : : !! NAME
1690 : : !! slice_rayleighRitzQuotients
1691 : : !!
1692 : : !! FUNCTION
1693 : : !! Compute the Rayleigh-Ritz quotients.
1694 : : !!
1695 : : !! INPUTS
1696 : : !!
1697 : : !! OUTPUT
1698 : : !!
1699 : : !! SIDE EFFECTS
1700 : : !! slice <type(slice_t)>=all data used to apply Spectrum Slicing algorithm
1701 : : !! maxeig= highest eigenvalue
1702 : : !! mineig= lowest eigenvalue
1703 : : !! DivResults= Rayleigh-Ritz quotients
1704 : : !!
1705 : : !! SOURCE
1706 : :
1707 : 0 : subroutine slice_rayleighRitzQuotients(slice,maxeig,mineig,DivResults)
1708 : :
1709 : : !Arguments ------------------------------------
1710 : : real(dp), intent(inout) :: maxeig
1711 : : real(dp), intent(inout) :: mineig
1712 : : type(slice_t), intent(inout) :: slice
1713 : : type(xgBlock_t), intent(inout) :: DivResults
1714 : :
1715 : : !Local variables-------------------------------
1716 : : !scalars
1717 : : type(xg_t)::Results1
1718 : : type(xg_t)::Results2
1719 : : type(xg_t)::Results_work
1720 : : !arrays
1721 : : integer :: maxeig_pos(2)
1722 : : integer :: mineig_pos(2)
1723 : : integer :: space_res
1724 : :
1725 : : ! *********************************************************************
1726 : :
1727 : 0 : if (space(slice%AllX)==SPACE_C) then
1728 : 0 : space_res = SPACE_C
1729 [ # # ]: 0 : else if (space(slice%AllX)==SPACE_CR) then
1730 : 0 : space_res = SPACE_R
1731 : : else
1732 : 0 : ABI_ERROR('space(X) should be SPACE_C or SPACE_CR')
1733 : : end if
1734 : 0 : call xg_init(Results1, space_res, slice%bandpp, 1)
1735 : 0 : call xg_init(Results2, space_res, slice%bandpp, 1)
1736 : :
1737 : 0 : call xgBlock_colwiseDotProduct(slice%AllX,slice%AllAX%self,Results1%self,comm_loc=xmpi_comm_null)
1738 : :
1739 : 0 : call xgBlock_colwiseDotProduct(slice%AllX,slice%AllX,Results2%self,comm_loc=xmpi_comm_null)
1740 [ # # ]: 0 : if (slice%xg_nonlop%paw) then
1741 : 0 : call xg_init(Results_work, space_res, slice%bandpp, 1)
1742 : : call xg_nonlop_colwiseXAX(slice%xg_nonlop,slice%xg_nonlop%Sij%self,slice%AllcprjX,&
1743 : 0 : slice%Allcprj_work%self,Results_work%self)
1744 : 0 : call xgBlock_add(Results2%self,Results_work%self)
1745 : 0 : call xg_free(Results_work)
1746 : : end if
1747 : :
1748 : 0 : call xgBlock_colwiseDivision(Results1%self, Results2%self, DivResults, maxeig, maxeig_pos, mineig, mineig_pos)
1749 : :
1750 : 0 : call xg_free(Results1)
1751 : 0 : call xg_free(Results2)
1752 : :
1753 [ # # ]: 0 : end subroutine slice_rayleighRitzQuotients
1754 : : !!***
1755 : :
1756 : : !----------------------------------------------------------------------
1757 : :
1758 : : !!****f* m_slice_cprj/slice_rayleighRitzQuotientsOnSlice
1759 : : !! NAME
1760 : : !! slice_rayleighRitzQuotientsOnSlice
1761 : : !!
1762 : : !! FUNCTION
1763 : : !! Compute the Rayleigh-Ritz quotients.
1764 : : !!
1765 : : !! INPUTS
1766 : : !!
1767 : : !! OUTPUT
1768 : : !!
1769 : : !! SIDE EFFECTS
1770 : : !! slice <type(slice_t)>=all data used to apply Spectrum Slicing algorithm
1771 : : !! maxeig= highest eigenvalue
1772 : : !! mineig= lowest eigenvalue
1773 : : !! DivResults= Rayleigh-Ritz quotients
1774 : : !!
1775 : : !! SOURCE
1776 : :
1777 : : subroutine slice_rayleighRitzQuotientsOnSlice(slice,maxeig,mineig,DivResults)
1778 : :
1779 : : !Arguments ------------------------------------
1780 : : real(dp), intent(inout) :: maxeig
1781 : : real(dp), intent(inout) :: mineig
1782 : : type(slice_t), intent(inout) :: slice
1783 : : type(xgBlock_t), intent(inout) :: DivResults
1784 : :
1785 : : !Local variables-------------------------------
1786 : : !scalars
1787 : : type(xg_t)::Results1
1788 : : type(xg_t)::Results2
1789 : : type(xg_t)::Results_work
1790 : : !arrays
1791 : : integer :: maxeig_pos(2)
1792 : : integer :: mineig_pos(2)
1793 : : integer :: space_res
1794 : :
1795 : : ! *********************************************************************
1796 : :
1797 : : if (space(slice%X)==SPACE_C) then
1798 : : space_res = SPACE_C
1799 : : else if (space(slice%X)==SPACE_CR) then
1800 : : space_res = SPACE_R
1801 : : else
1802 : : ABI_ERROR('space(X) should be SPACE_C or SPACE_CR')
1803 : : end if
1804 : : call xg_init(Results1, space_res, slice%neigenpairs, 1)
1805 : : call xg_init(Results2, space_res, slice%neigenpairs, 1)
1806 : :
1807 : : call xgBlock_colwiseDotProduct(slice%X,slice%AX,Results1%self,comm_loc=xmpi_comm_null)
1808 : :
1809 : : call xgBlock_colwiseDotProduct(slice%X,slice%X,Results2%self,comm_loc=xmpi_comm_null)
1810 : : if (slice%xg_nonlop%paw) then
1811 : : call xg_init(Results_work, space_res, slice%neigenpairs, 1)
1812 : : call xg_nonlop_colwiseXAX(slice%xg_nonlop,slice%xg_nonlop%Sij%self,slice%cprjX,&
1813 : : slice%cprj_work,Results_work%self)
1814 : : call xgBlock_add(Results2%self,Results_work%self)
1815 : : call xg_free(Results_work)
1816 : : end if
1817 : :
1818 : : call xgBlock_colwiseDivision(Results1%self, Results2%self, DivResults, maxeig, maxeig_pos, mineig, mineig_pos)
1819 : :
1820 : : call xg_free(Results1)
1821 : : call xg_free(Results2)
1822 : :
1823 : : end subroutine slice_rayleighRitzQuotientsOnSlice
1824 : : !!***
1825 : :
1826 : : !----------------------------------------------------------------------
1827 : :
1828 : : !!****f* m_slice_cprj/slice_computeNextOrderChebfiPolynom
1829 : : !! NAME
1830 : : !! slice_computeNextOrderChebfiPolynom
1831 : : !!
1832 : : !! FUNCTION
1833 : : !! From P_n(B-^1.A)|X> (where P_n is the Chebyshev polynom of order n),
1834 : : !! computes P_n+1(B-^1.A)|X>
1835 : : !!
1836 : : !! INPUTS
1837 : : !! ideg=current degree of polynom
1838 : : !! center=filter center
1839 : : !! one_over_r,two_over_r=1/R, 2/R, R being the radius of the filter
1840 : : !! getBm1X= pointer to the function giving B^-1|X>
1841 : : !! B is typically the overlap operator S
1842 : : !!
1843 : : !! OUTPUT
1844 : : !!
1845 : : !! SIDE EFFECTS
1846 : : !! slice <type(slice_t)>=all data used to apply Spectrum Slicing algorithm
1847 : : !!
1848 : : !! SOURCE
1849 : :
1850 : 0 : subroutine slice_computeNextOrderChebfiPolynom(slice,ideg,center,one_over_r,two_over_r)
1851 : :
1852 : : !Arguments ------------------------------------
1853 : : real(dp) , intent(in) :: center
1854 : : integer , intent(in) :: ideg
1855 : : real(dp) , intent(in) :: one_over_r
1856 : : real(dp) , intent(in) :: two_over_r
1857 : : type(slice_t) , intent(inout) :: slice
1858 : :
1859 : : !Local variables-------------------------------
1860 : : real(dp) :: tsec(2)
1861 : :
1862 : : ! *********************************************************************
1863 : :
1864 : 0 : call timab(tim_copy, 1, tsec)
1865 : 0 : call xgBlock_copy(slice%AX,slice%X_next)
1866 : 0 : call timab(tim_copy, 2, tsec)
1867 : :
1868 [ # # ]: 0 : if (slice%paw) then
1869 : 0 : call timab(tim_invovl, 1, tsec)
1870 : : call xg_nonlop_getSm1X(slice%xg_nonlop,slice%X_next,slice%cprjX,&
1871 : 0 : & slice%cprj_work,slice%cprj_work2%self,slice%proj_work%self)
1872 : 0 : call timab(tim_invovl, 2, tsec)
1873 : : else
1874 : 0 : call timab(tim_copy, 1, tsec)
1875 : 0 : call xgBlock_copy(slice%AX,slice%X_next)
1876 : 0 : call timab(tim_copy, 2, tsec)
1877 : : end if
1878 : :
1879 : 0 : call timab(tim_postinvovl, 1, tsec)
1880 : 0 : call xgBlock_scale(slice%X, center, 1) !scale by center
1881 : :
1882 : : !(B-1 * A * Psi^i-1 - c * Psi^i-1)
1883 : 0 : call xgBlock_saxpy(slice%X_next, dble(-1.0), slice%X)
1884 : :
1885 : : !Psi^i-1 = 1/c * Psi^i-1
1886 : 0 : call xgBlock_scale(slice%X, 1/center, 1) !counter scale by 1/center
1887 : :
1888 [ # # ]: 0 : if (ideg == 0) then
1889 : 0 : call xgBlock_scale(slice%X_next, one_over_r, 1)
1890 : : else
1891 : 0 : call xgBlock_scale(slice%X_next, two_over_r, 1)
1892 : :
1893 : 0 : call xgBlock_saxpy(slice%X_next, dble(-1.0), slice%X_prev)
1894 : : end if
1895 : :
1896 : 0 : call timab(tim_postinvovl, 2, tsec)
1897 : :
1898 : 0 : end subroutine slice_computeNextOrderChebfiPolynom
1899 : : !!***
1900 : :
1901 : : !----------------------------------------------------------------------
1902 : :
1903 : : !!****f* m_slice_cprj/slice_swapInnerBuffers
1904 : : !! NAME
1905 : : !! slice_swapInnerBuffers
1906 : : !!
1907 : : !! FUNCTION
1908 : : !! Swap buffers inside a 'slice' datastructure.
1909 : : !!
1910 : : !! INPUTS
1911 : : !! ncols= number of requested eigenvectors/eigenvalues
1912 : : !! spacedim= space dimension for one vector
1913 : : !!
1914 : : !! OUTPUT
1915 : : !!
1916 : : !! SIDE EFFECTS
1917 : : !! slice <type(slice_t)>=all data used to apply Spectrum Slicing algorithm
1918 : : !!
1919 : : !! SOURCE
1920 : :
1921 : 0 : subroutine slice_swapInnerBuffers(slice,spacedim,ncols)
1922 : :
1923 : : ! Arguments ------------------------------------
1924 : : integer , intent(in ) :: spacedim
1925 : : integer , intent(in ) :: ncols
1926 : : type(slice_t) , intent(inout) :: slice
1927 : :
1928 : : ! *********************************************************************
1929 : :
1930 : 0 : call xgBlock_setBlock(slice%X_prev, slice%X_swap, spacedim, ncols) !X_swap = X_prev
1931 : 0 : call xgBlock_setBlock(slice%X, slice%X_prev, spacedim, ncols) !X_prev = X
1932 : 0 : call xgBlock_setBlock(slice%X_next, slice%X, spacedim, ncols) !X = X_next
1933 : 0 : call xgBlock_setBlock(slice%X_swap, slice%X_next, spacedim, ncols) !X_next = X_swap
1934 : :
1935 : 0 : end subroutine slice_swapInnerBuffers
1936 : : !!***
1937 : :
1938 : : !----------------------------------------------------------------------
1939 : :
1940 : : !!****f* m_slice_cprj/slice_ampfactor
1941 : : !! NAME
1942 : : !! slice_ampfactor
1943 : : !!
1944 : : !! FUNCTION
1945 : : !! Compute amplification factor
1946 : : !!
1947 : : !! INPUTS
1948 : : !! eig (:,:)= eigenvalues
1949 : : !! lambda_minus,lambda_plus=
1950 : : !! ndeg_filter_bands(:)= degree of Spectrum Slicing filter for each band
1951 : : !!
1952 : : !! OUTPUT
1953 : : !!
1954 : : !! SIDE EFFECTS
1955 : : !! residu<type(xgBlock_t)>= vector of residuals
1956 : : !! slice <type(slice_t)>=all data used to apply Spectrum Slicing algorithm
1957 : : !!
1958 : : !! SOURCE
1959 : :
1960 : : subroutine slice_ampfactor(slice,DivResults,lambda_minus,lambda_plus,ndeg_filter_bands)
1961 : :
1962 : : ! Arguments ------------------------------------
1963 : : integer, intent(in ) :: ndeg_filter_bands(:)
1964 : : type(xgBlock_t), intent(in ) :: DivResults
1965 : : real(dp), intent(in ) :: lambda_minus
1966 : : real(dp), intent(in ) :: lambda_plus
1967 : : type(slice_t), intent(inout) :: slice
1968 : :
1969 : : ! Local variables-------------------------------
1970 : : ! scalars
1971 : : integer :: iband
1972 : : !integer :: npw, nband
1973 : : real(dp) :: ampfactor
1974 : : real(dp) :: eig_per_band
1975 : : type(xgBlock_t) :: X_part
1976 : : type(xgBlock_t) :: AX_part
1977 : : real(dp),pointer :: eig(:,:)
1978 : :
1979 : : ! *********************************************************************
1980 : :
1981 : : call xgBlock_reverseMap(DivResults,eig,rows=1,cols=slice%bandpp)
1982 : :
1983 : : do iband = 1, slice%bandpp
1984 : :
1985 : : eig_per_band = eig(1,iband)
1986 : :
1987 : : !cheb_poly1(x, n, a, b)
1988 : : ampfactor = cheb_poly1(eig_per_band, ndeg_filter_bands(iband), lambda_minus, lambda_plus)
1989 : :
1990 : : if(abs(ampfactor) < 1e-3) ampfactor = 1e-3 !just in case, avoid amplifying too much
1991 : :
1992 : : call xgBlock_setBlock(slice%X, X_part, slice%total_spacedim, 1, fcol=iband)
1993 : : call xgBlock_setBlock(slice%AX, AX_part, slice%total_spacedim, 1, fcol=iband)
1994 : :
1995 : : call xgBlock_scale(X_part, 1/ampfactor, 1)
1996 : : call xgBlock_scale(AX_part, 1/ampfactor, 1)
1997 : :
1998 : : end do
1999 : :
2000 : : end subroutine slice_ampfactor
2001 : : !!***
2002 : :
2003 : : subroutine slice_ampfactorMax(slice,DivResults,lambda_minus,lambda_plus,ndeg_filter_bands)
2004 : :
2005 : : ! Arguments ------------------------------------
2006 : : integer, intent(in ) :: ndeg_filter_bands(:)
2007 : : type(xgBlock_t), intent(in ) :: DivResults
2008 : : real(dp), intent(in ) :: lambda_minus
2009 : : real(dp), intent(in ) :: lambda_plus
2010 : : type(slice_t), intent(inout) :: slice
2011 : :
2012 : : ! Local variables-------------------------------
2013 : : ! scalars
2014 : : integer :: iband
2015 : : real(dp) :: ampfactor
2016 : : !type(xgBlock_t) :: X_part
2017 : : !type(xgBlock_t) :: AX_part
2018 : : real(dp),pointer :: eig(:,:)
2019 : :
2020 : : ! *********************************************************************
2021 : :
2022 : : call xgBlock_reverseMap(DivResults,eig,rows=1,cols=cols(DivResults))
2023 : :
2024 : : !cheb_poly1(x, n, a, b)
2025 : : ampfactor = maxval( (/ (cheb_poly1(eig(1,iband), ndeg_filter_bands(iband), lambda_minus, lambda_plus),&
2026 : : iband=1,cols(DivResults)) /) )
2027 : :
2028 : : call xgBlock_scale(slice%X, 1/ampfactor, 1)
2029 : : call xgBlock_scale(slice%AX, 1/ampfactor, 1)
2030 : :
2031 : : end subroutine slice_ampfactorMax
2032 : : !!***
2033 : :
2034 : : !----------------------------------------------------------------------
2035 : :
2036 : : !!****f* m_slice_cprj/slice_probeProximity
2037 : : !! NAME
2038 : : !! slice_probeProximity
2039 : : !!
2040 : : !! FUNCTION
2041 : : !! Compute the principal angles to measure the subspace convergence
2042 : : !! regarding the slice subspace associated to spectral interval [a,b).
2043 : : !! Essentially computes the distance between two subspaces.
2044 : : !! Note that A=Span(a1,..ak) and B=Span(b1,...bk) where families
2045 : : !! are assumed to be linearly independent set of vectors.
2046 : : !! They do not need to be orthogonal!!
2047 : : !!
2048 : : !! IML debug version 08/07:
2049 : : !! probe an interior slice, works for test case only
2050 : :
2051 : : !subroutine slice_probeProximity(slice,islice)
2052 : : !
2053 : : ! implicit none
2054 : : ! type(slice_t), intent(inout) :: slice
2055 : : ! integer, intent(in) :: islice
2056 : : !
2057 : : !
2058 : : !end subroutine slice_probeProximity
2059 : : !!***
2060 : :
2061 : : !----------------------------------------------------------------------
2062 : :
2063 : : !!****f* m_slice_cprj/slice_oracle1
2064 : : !! NAME
2065 : : !! slice_oracle1
2066 : : !!
2067 : : !! FUNCTION
2068 : : !! Compute order of Chebyshev polynom necessary to converge to a given tol
2069 : : !!
2070 : : !! INPUTS
2071 : : !! xx= input variable
2072 : : !! aa= left bound of the interval
2073 : : !! bb= right bound of the interval
2074 : : !! tol= needed precision
2075 : : !! nmax= max number of iterations
2076 : : !!
2077 : : !! OUTPUT
2078 : : !!
2079 : : !! SIDE EFFECTS
2080 : : !!
2081 : : !! SOURCE
2082 : :
2083 : : function cheb_oracle1(xx,aa,bb,tol,nmax) result(nn)
2084 : :
2085 : : ! Arguments ------------------------------------
2086 : : integer :: nn
2087 : : integer, intent(in) :: nmax
2088 : : real(dp), intent(in) :: xx,aa,bb
2089 : : real(dp), intent(in) :: tol
2090 : :
2091 : : ! Local variables-------------------------------
2092 : : integer :: ii
2093 : : real(dp) :: yy,yim1,xred,temp
2094 : :
2095 : : ! *************************************************************************
2096 : :
2097 : : xred = (xx-(aa+bb)/2)/(bb-aa)*2
2098 : : yy = xred
2099 : : yim1 = 1 !ONE
2100 : :
2101 : : nn = nmax
2102 : : if(1/(yy**2) < tol) then
2103 : : nn = 1
2104 : : else
2105 : : do ii=2, nmax-1
2106 : : temp = yy
2107 : : yy = 2*xred*yy - yim1
2108 : : yim1 = temp
2109 : : if(1/(yy**2) < tol) then
2110 : : nn = ii
2111 : : exit
2112 : : end if
2113 : : end do
2114 : : end if
2115 : :
2116 : : end function cheb_oracle1
2117 : : !!***
2118 : :
2119 : : !----------------------------------------------------------------------
2120 : :
2121 : : !!****f* m_slice_cprj/cheb_poly1
2122 : : !! NAME
2123 : : !! cheb_poly1
2124 : : !!
2125 : : !! FUNCTION
2126 : : !! Compute Chebyshev polynomial???
2127 : : !!
2128 : : !! INPUTS
2129 : : !! xx= input variable
2130 : : !! aa= left bound of the interval
2131 : : !! bb= right bound of the interval
2132 : : !! nn=
2133 : : !!
2134 : : !! OUTPUT
2135 : : !!
2136 : : !! SIDE EFFECTS
2137 : : !!
2138 : : !! SOURCE
2139 : :
2140 : : function cheb_poly1(xx,nn,aa,bb) result(yy)
2141 : :
2142 : : ! Arguments ------------------------------------
2143 : : integer, intent(in) :: nn
2144 : : real(dp), intent(in) :: xx, aa, bb
2145 : : real(dp) :: yy
2146 : :
2147 : : ! Local variables-------------------------------
2148 : : integer :: ii
2149 : : real(dp) :: xred,yim1,temp
2150 : :
2151 : : ! *************************************************************************
2152 : :
2153 : : xred = (xx-(aa+bb)/2)/(bb-aa)*2
2154 : : yy = xred
2155 : : yim1 = 1
2156 : : do ii= 2, nn
2157 : : temp = yy
2158 : : yy = 2*xred*yy - yim1
2159 : : yim1 = temp
2160 : : end do
2161 : :
2162 : : end function cheb_poly1
2163 : : !!***
2164 : :
2165 : 0 : function bandpassIndicator_sca(t,a,b,deg) result(f_t)
2166 : :
2167 : : implicit none
2168 : :
2169 : : !Arguments ------------------------------------
2170 : : real(dp), intent(in ) :: t,a,b
2171 : : integer , intent(in ) :: deg
2172 : :
2173 : : real(dp) :: f_t
2174 : :
2175 : : !Local variables-------------------------------
2176 : : real(dp) :: yt0,yt,yt_swap,ck,mu,damp
2177 : : integer :: i
2178 : :
2179 : : ! *********************************************************************
2180 : :
2181 : : ! init cheby of deg=0,1 eval at t
2182 : 0 : yt0 = 1.d0
2183 : 0 : yt = t
2184 : :
2185 : : ! init filter for deg=0
2186 : 0 : ck = Pi/(deg+2)
2187 : 0 : mu = 1/Pi*(ACOS(a)-ACOS(b))
2188 : 0 : damp = 1.d0
2189 : 0 : f_t = mu * damp * yt0
2190 : :
2191 [ # # ]: 0 : do i=1,deg
2192 : :
2193 : : ! Update damping and expansion coefficient
2194 : 0 : mu = 2/Pi * (SIN(i*ACOS(a)) - SIN(i*ACOS(b)))/i
2195 : 0 : damp = ((1 - i/(deg+2))*SIN(ck)*COS(i*ck) + 1/(deg+2)*COS(ck)*SIN(i*ck))/SIN(ck)
2196 : :
2197 : : ! Sum terms
2198 : 0 : f_t = f_t + mu * damp * yt
2199 : :
2200 : : ! Update Chebyshev polynomial
2201 : 0 : yt_swap = yt
2202 : 0 : yt = 2 * t * yt - yt0
2203 : 0 : yt0 = yt_swap
2204 : :
2205 : : end do
2206 : :
2207 : 0 : end function bandpassIndicator_sca
2208 : : !!***
2209 : :
2210 : : !----------------------------------------------------------------------
2211 : :
2212 : : !!****f* m_slice_cprj/generateRademacherMatrix
2213 : : !! NAME
2214 : : !! generateRademacherMatrix
2215 : : !!
2216 : : !! SOURCE
2217 : 0 : subroutine generateRademacherMatrix(V, n, m, rank)
2218 : :
2219 : : implicit none
2220 : :
2221 : : ! input/output
2222 : : integer, intent(in) :: n, m, rank
2223 : : complex(dp), intent(out) :: V(n,m)
2224 : : ! local arguments
2225 : : integer :: nseed, i, j, k
2226 : : integer :: base_seed
2227 : 0 : real(dp) :: R(n,m)
2228 : 0 : integer, allocatable :: seed(:)
2229 : :
2230 : : ! *********************************************************************
2231 : :
2232 : : ! MPI-safe seed: deterministic way to generate a unique seed per MPI rank
2233 : 0 : call random_seed(size=nseed) ! runtime value of nseed
2234 : :
2235 [ # # # # : 0 : ABI_MALLOC(seed, (nseed))
# # # # #
# # # #
# ]
2236 : 0 : base_seed = 123456789
2237 [ # # # # : 0 : seed = mod( base_seed + rank*73856093 + [(i*19349663, i=1,nseed)], 2147483647 )
# # # # #
# # # # #
# # # # ]
2238 : 0 : call random_seed(put=seed)
2239 : :
2240 : 0 : call random_number(R)
2241 [ # # ]: 0 : do j = 1, m
2242 [ # # ]: 0 : do i = 1, n
2243 : 0 : k = int(4.0d0 * R(i,j)) ! 0,1,2,3
2244 : 0 : V(i,j) = dcmplx( cos(0.5d0*pi*k), sin(0.5d0*pi*k))
2245 : : end do
2246 : : end do
2247 : :
2248 [ # # ]: 0 : ABI_FREE(seed)
2249 : :
2250 : 0 : end subroutine generateRademacherMatrix
2251 : : !!***
2252 : :
2253 : : !----------------------------------------------------------------------
2254 : :
2255 : : !!****f* m_slice_cprj/generateGaussianMatrix
2256 : : !! NAME
2257 : : !! generateGaussianMatrix
2258 : : !!
2259 : : !! SOURCE
2260 : : subroutine generateGaussianMatrix(V, n, m, rank)
2261 : :
2262 : : implicit none
2263 : :
2264 : : ! input/output
2265 : : integer, intent(in) :: n, m, rank
2266 : : real(dp), intent(out) :: V(2, n*m)
2267 : :
2268 : : ! local arguments
2269 : : integer :: nseed, i, nm
2270 : : integer :: base_seed
2271 : : integer, allocatable :: seed(:)
2272 : : real(dp) :: u1, u2
2273 : :
2274 : : ! *********************************************************************
2275 : :
2276 : : nm = n * m
2277 : :
2278 : : ! MPI-safe seed: deterministic way to generate a unique seed per MPI rank
2279 : : call random_seed(size = nseed)
2280 : :
2281 : : ABI_MALLOC(seed, (nseed))
2282 : : base_seed = 123456789
2283 : : seed = mod( base_seed + rank*73856093 + [(i*19349663, i=1,nseed)], 2147483647 )
2284 : : call random_seed(put = seed)
2285 : :
2286 : : ! Generate i.i.d. N(0,1) entries (real-valued)
2287 : : i = 1
2288 : : do while (i <= nm)
2289 : : call random_number(u1)
2290 : : call random_number(u2)
2291 : :
2292 : : ! Box-Muller transform
2293 : : V(1, i) = sqrt(-2.0_dp * log(u1)) * cos(2.0_dp * Pi * u2)
2294 : :
2295 : : if (i + 1 <= nm) then
2296 : : V(1, i+1) = sqrt(-2.0_dp * log(u1)) * sin(2.0_dp * Pi * u2)
2297 : : end if
2298 : :
2299 : : i = i + 2
2300 : : end do
2301 : :
2302 : : ! Imaginary part = 0 (consistent with your Rademacher routine)
2303 : : V(2, 1:nm) = 0.0_dp
2304 : :
2305 : : ABI_FREE(seed)
2306 : :
2307 : : end subroutine generateGaussianMatrix
2308 : : !!***
2309 : :
2310 : : !----------------------------------------------------------------------
2311 : :
2312 : : !!****f* m_slice_cprj/applyLowpassFilter
2313 : : !! NAME
2314 : : !! applyLowpassFilter
2315 : : !!
2316 : : !! SOURCE
2317 : : subroutine applyLowpassFilter(slice, getAX, ampl_factors, kin, low_bound, upp_bound, &
2318 : : ndeg_filter, gpu_option)
2319 : :
2320 : : implicit none
2321 : :
2322 : : type(slice_t), intent(inout) :: slice
2323 : : type(xgBlock_t), intent(in) :: kin
2324 : : type(xgBlock_t), intent(in) :: ampl_factors
2325 : : integer, intent(in) :: ndeg_filter
2326 : : real(dp), intent(in) :: low_bound, upp_bound
2327 : : integer, optional, intent(in) :: gpu_option
2328 : : interface
2329 : : subroutine getAX(X,AX)
2330 : : use m_xg, only : xgBlock_t
2331 : : type(xgBlock_t), intent(inout) :: X
2332 : : type(xgBlock_t), intent(inout) :: AX
2333 : : end subroutine getAX
2334 : : end interface
2335 : :
2336 : : integer :: neigenpairs
2337 : : integer :: ideg
2338 : : integer :: nspinor
2339 : : integer :: l_gpu_option
2340 : : real(dp) :: center, radius
2341 : : real(dp) :: one_over_r
2342 : : real(dp) :: two_over_r
2343 : : real(dp) :: tsec(2)
2344 : : integer, allocatable :: ndeg_filter_bands(:) !Oracle variable
2345 : : type(xg_nonlop_t) :: xg_nonlop
2346 : :
2347 : : ! *********************************************************************
2348 : :
2349 : : ! Initialize values
2350 : : neigenpairs = cols(slice%X)
2351 : : xg_nonlop = slice%xg_nonlop
2352 : : nspinor = slice%xg_nonlop%nspinor
2353 : : l_gpu_option = ABI_GPU_DISABLED
2354 : :
2355 : : ! Process input arguments
2356 : : if (present(gpu_option)) then
2357 : : l_gpu_option = gpu_option
2358 : : end if
2359 : :
2360 : : ! Spectral interval to be amplified scaled to [-1,1)
2361 : : center = (upp_bound + low_bound)*0.5
2362 : : radius = (upp_bound - low_bound)*0.5
2363 : : one_over_r = 1.0/radius
2364 : : two_over_r = 2.0/radius
2365 : :
2366 : : ! Loop on degree
2367 : : do ideg = 0, ndeg_filter - 1
2368 : :
2369 : : ! ITEST
2370 : : write(std_out,*) 'polynomial degree=', ideg
2371 : : flush(std_out)
2372 : : ! ITEST
2373 : :
2374 : : call timab(tim_cprj,1,tsec)
2375 : : call xg_nonlop_getcprj(xg_nonlop,slice%AX,slice%cprjX,slice%proj_work%self)
2376 : : call timab(tim_cprj,2,tsec)
2377 : :
2378 : : call slice_computeNextOrderChebfiPolynom(slice, ideg, center, one_over_r, two_over_r)
2379 : :
2380 : : call timab(tim_swap,1,tsec)
2381 : : call slice_swapInnerBuffers(slice, slice%total_spacedim, neigenpairs)
2382 : : call timab(tim_swap,2,tsec)
2383 : :
2384 : : !A * Psi
2385 : : call timab(tim_AX_v,1,tsec)
2386 : : call getAX(slice%X,slice%AX)
2387 : : call timab(tim_AX_v,2,tsec)
2388 : : call timab(tim_AX_k,1,tsec)
2389 : : call xgBlock_add_diag(slice%X,kin,nspinor,slice%AX)
2390 : : call timab(tim_AX_k,2,tsec)
2391 : : call timab(tim_cprj,1,tsec)
2392 : : call xg_nonlop_getcprj(xg_nonlop,slice%X,slice%cprjX,slice%proj_work%self)
2393 : : call timab(tim_cprj,2,tsec)
2394 : : call timab(tim_AX_nl,1,tsec)
2395 : : call xg_nonlop_getHX(xg_nonlop,slice%AX,slice%cprjX,slice%cprj_work,slice%proj_work%self)
2396 : : call timab(tim_AX_nl,2,tsec)
2397 : :
2398 : : end do ! End polynomial degree loop
2399 : :
2400 : : ! Amplify to finalize filter application
2401 : : call timab(tim_amp_f,1,tsec)
2402 : : ABI_MALLOC(ndeg_filter_bands,(neigenpairs))
2403 : : ndeg_filter_bands(:) = ndeg_filter
2404 : : call slice_ampfactor(slice, ampl_factors, low_bound, upp_bound, ndeg_filter_bands)
2405 : : ABI_FREE(ndeg_filter_bands)
2406 : : call timab(tim_amp_f,2,tsec)
2407 : :
2408 : : end subroutine applyLowpassFilter
2409 : : !!***
2410 : :
2411 : : !----------------------------------------------------------------------
2412 : :
2413 : : !!****f* m_slice_cprj/applyBandpassFilter
2414 : : !! NAME
2415 : : !! applyBandpassFilter
2416 : : !!
2417 : : !! SOURCE
2418 : : subroutine applyBandpassFilter(slice, getAX, kin, low_bound, upp_bound, &
2419 : : min_low_bound, max_upp_bound, ndeg_filter, gpu_option)
2420 : :
2421 : : implicit none
2422 : :
2423 : : type(slice_t), intent(inout) :: slice
2424 : : type(xgBlock_t), intent(in) :: kin
2425 : : integer, intent(in) :: ndeg_filter
2426 : : real(dp), intent(in) :: low_bound, upp_bound
2427 : : real(dp), intent(in) :: min_low_bound, max_upp_bound
2428 : : integer, optional, intent(in) :: gpu_option
2429 : : interface
2430 : : subroutine getAX(X,AX)
2431 : : use m_xg, only : xgBlock_t
2432 : : type(xgBlock_t), intent(inout) :: X
2433 : : type(xgBlock_t), intent(inout) :: AX
2434 : : end subroutine getAX
2435 : : end interface
2436 : :
2437 : : integer :: neigenpairs
2438 : : integer :: ideg
2439 : : integer :: nspinor
2440 : : integer :: l_gpu_option
2441 : : real(dp) :: cdeg
2442 : : real(dp) :: center, radius
2443 : : real(dp) :: ls, us
2444 : : real(dp) :: mu, damp
2445 : : real(dp) :: one_over_r
2446 : : real(dp) :: two_over_r
2447 : : real(dp) :: tsec(2)
2448 : : type(xg_t) :: Xsum
2449 : : type(xg_nonlop_t) :: xg_nonlop
2450 : :
2451 : : ! *********************************************************************
2452 : :
2453 : : ! Initialize values
2454 : : neigenpairs = cols(slice%X)
2455 : : xg_nonlop = slice%xg_nonlop
2456 : : nspinor = slice%xg_nonlop%nspinor
2457 : : l_gpu_option = ABI_GPU_DISABLED
2458 : :
2459 : : ! Process input arguments
2460 : : if (present(gpu_option)) then
2461 : : l_gpu_option = gpu_option
2462 : : end if
2463 : :
2464 : : ! Allocate space
2465 : : call xg_init(Xsum,slice%space,slice%total_spacedim,neigenpairs,&
2466 : : slice%spacecom,gpu_option=l_gpu_option)
2467 : :
2468 : : ! Spectral interval to be amplified scaled to [-1,1)
2469 : : center = (max_upp_bound + min_low_bound)*0.5
2470 : : radius = (max_upp_bound - min_low_bound)*0.5
2471 : : ls = (low_bound - center) / radius
2472 : : us = (upp_bound - center) / radius
2473 : : one_over_r = 1.0/radius
2474 : : two_over_r = 2.0/radius
2475 : :
2476 : : ! Initialize Chebyshev expansion of indicator function of order ndeg_filter
2477 : : cdeg = Pi/(ndeg_filter+2)
2478 : : mu = 1.d0/Pi*(ACOS(ls)-ACOS(us))
2479 : : damp = 1.d0 ! Jackson damping
2480 : : call xgBlock_saxpy(Xsum%self, mu*damp, slice%X)
2481 : :
2482 : : ! Loop on degree
2483 : : do ideg = 0, ndeg_filter - 1
2484 : :
2485 : : call timab(tim_cprj,1,tsec)
2486 : : call xg_nonlop_getcprj(xg_nonlop,slice%AX,slice%cprjX,slice%proj_work%self)
2487 : : call timab(tim_cprj,2,tsec)
2488 : :
2489 : : call slice_computeNextOrderChebfiPolynom(slice, ideg, center, one_over_r, two_over_r)
2490 : :
2491 : : call timab(tim_swap,1,tsec)
2492 : : call slice_swapInnerBuffers(slice, slice%total_spacedim, neigenpairs)
2493 : : call timab(tim_swap,2,tsec)
2494 : :
2495 : : ! Accumulate X with weight in Xsum for bandpass filters
2496 : : mu = 2/Pi * (SIN((ideg+1)*ACOS(ls)) - SIN((ideg+1)*ACOS(us)))/(ideg+1)
2497 : : damp = ((1 - (ideg+1)/(ndeg_filter+2))*SIN(cdeg)*COS((ideg+1)*cdeg) + &
2498 : : 1/(ndeg_filter+2)*COS(cdeg)*SIN((ideg+1)*cdeg))/SIN(cdeg)
2499 : : call xgBlock_saxpy(Xsum%self, mu*damp, slice%X)
2500 : :
2501 : : if (ideg==ndeg_filter - 1) then
2502 : :
2503 : : ! store final expansion Xsum to X (inplace rewrites X)
2504 : : call xgBlock_copy(Xsum%self, slice%X)
2505 : :
2506 : : end if
2507 : :
2508 : : !A * Psi
2509 : : call timab(tim_AX_v,1,tsec)
2510 : : call getAX(slice%X,slice%AX)
2511 : : call timab(tim_AX_v,2,tsec)
2512 : : call timab(tim_AX_k,1,tsec)
2513 : : call xgBlock_add_diag(slice%X,kin,nspinor,slice%AX)
2514 : : call timab(tim_AX_k,2,tsec)
2515 : : call timab(tim_cprj,1,tsec)
2516 : : call xg_nonlop_getcprj(xg_nonlop,slice%X,slice%cprjX,slice%proj_work%self)
2517 : : call timab(tim_cprj,2,tsec)
2518 : : call timab(tim_AX_nl,1,tsec)
2519 : : call xg_nonlop_getHX(xg_nonlop,slice%AX,slice%cprjX,slice%cprj_work,slice%proj_work%self)
2520 : : call timab(tim_AX_nl,2,tsec)
2521 : :
2522 : : end do ! End polynomial degree loop
2523 : :
2524 : : ! Free memory
2525 : : call xg_free(Xsum)
2526 : :
2527 : : end subroutine applyBandpassFilter
2528 : : !!***
2529 : :
2530 : : !----------------------------------------------------------------------
2531 : :
2532 : : !!****f* m_slice_cprj/computeChebyshevMoments
2533 : : !! NAME
2534 : : !! computeChebyshevMoments
2535 : : !!
2536 : : !! FUNCTION
2537 : : !! Compute Chebyshev moments up to maximal degree all centered in [A,B)
2538 : : !!
2539 : : !! OUTPUT
2540 : : !! M_n = <X, f_n(B^{-1}AX) X> for n=1,..,ndeg_filter_max
2541 : : !!
2542 : : !! SOURCE
2543 : 0 : subroutine computeChebyshevMoments(slice, getAX, kin, min_low_bound, max_upp_bound, &
2544 : : ndeg_filter_max, cheby_moments, gpu_option)
2545 : :
2546 : : implicit none
2547 : :
2548 : : type(slice_t), intent(inout) :: slice
2549 : : type(xgBlock_t), intent(in) :: kin
2550 : : integer, intent(in) :: ndeg_filter_max
2551 : : real(dp), intent(in) :: min_low_bound, max_upp_bound
2552 : : real(dp), pointer, intent(inout) :: cheby_moments(:,:)
2553 : : integer, optional, intent(in) :: gpu_option
2554 : : interface
2555 : : subroutine getAX(X,AX)
2556 : : use m_xg, only : xgBlock_t
2557 : : type(xgBlock_t), intent(inout) :: X
2558 : : type(xgBlock_t), intent(inout) :: AX
2559 : : end subroutine getAX
2560 : : end interface
2561 : :
2562 : : integer :: neigenpairs
2563 : : integer :: ideg
2564 : : integer :: nspinor
2565 : : integer :: nrows
2566 : : integer :: l_gpu_option
2567 : : real(dp) :: center, radius
2568 : : real(dp) :: one_over_r
2569 : : real(dp) :: two_over_r
2570 : : real(dp) :: tsec(2)
2571 : : type(xg_t) :: Moments, X0
2572 : : type(xgBlock_t) :: moment_ideg
2573 : 0 : type(xg_nonlop_t) :: xg_nonlop
2574 : :
2575 : : ! *********************************************************************
2576 : :
2577 : : ! Initialize values
2578 : 0 : neigenpairs = cols(slice%X)
2579 : 0 : nrows = slice%total_spacedim
2580 [ # # # # : 0 : xg_nonlop = slice%xg_nonlop
# # # # ]
2581 : 0 : nspinor = slice%xg_nonlop%nspinor
2582 : 0 : l_gpu_option = ABI_GPU_DISABLED
2583 : :
2584 : : if (present(gpu_option)) then
2585 : : l_gpu_option = gpu_option
2586 : : end if
2587 : :
2588 : : ! Allocate space
2589 : 0 : call xg_init(Moments, slice%space, neigenpairs, ndeg_filter_max+1) ! M_n=<X0,f_n(A)X0>
2590 : 0 : call xg_init(X0, slice%space, nrows, neigenpairs, slice%spacecom, me_g0=slice%me_g0) ! X0
2591 : :
2592 : 0 : call xgBlock_copy(slice%X, X0%self)
2593 : :
2594 : : ! Spectral interval to be amplified scaled to [-1,1)
2595 : 0 : center = (max_upp_bound + min_low_bound)*0.5
2596 : 0 : radius = (max_upp_bound - min_low_bound)*0.5
2597 : 0 : one_over_r = 1.0/radius
2598 : 0 : two_over_r = 2.0/radius
2599 : :
2600 : : ! Initialize
2601 : 0 : call xgBlock_setBlock(Moments%self, moment_ideg, neigenpairs, 1)
2602 : 0 : call xgBlock_colwiseDotProduct(slice%X, slice%X, moment_ideg, comm_loc=xmpi_comm_null)
2603 : :
2604 : : ! Loop on degree
2605 [ # # ]: 0 : do ideg = 0, ndeg_filter_max - 1
2606 : :
2607 : 0 : call timab(tim_cprj,1,tsec)
2608 : 0 : call xg_nonlop_getcprj(xg_nonlop,slice%AX,slice%cprjX,slice%proj_work%self)
2609 : 0 : call timab(tim_cprj,2,tsec)
2610 : :
2611 : 0 : call slice_computeNextOrderChebfiPolynom(slice, ideg, center, one_over_r, two_over_r)
2612 : :
2613 : : ! slice%X = f_ideg X0
2614 : 0 : call timab(tim_swap,1,tsec)
2615 : 0 : call slice_swapInnerBuffers(slice, slice%total_spacedim, neigenpairs)
2616 : 0 : call timab(tim_swap,2,tsec)
2617 : :
2618 : : ! M_ideg = < X0, f_ideg X0 > in C^nband for every ideg
2619 : 0 : call xgBlock_setBlock(Moments%self, moment_ideg, neigenpairs, 1, fcol=ideg+2)
2620 : 0 : call xgBlock_colwiseDotProduct(X0%self, slice%X, moment_ideg, comm_loc=xmpi_comm_null)
2621 : :
2622 : : !A * Psi
2623 : 0 : call timab(tim_AX_v,1,tsec)
2624 : 0 : call getAX(slice%X,slice%AX)
2625 : 0 : call timab(tim_AX_v,2,tsec)
2626 : 0 : call timab(tim_AX_k,1,tsec)
2627 : 0 : call xgBlock_add_diag(slice%X,kin,nspinor,slice%AX)
2628 : 0 : call timab(tim_AX_k,2,tsec)
2629 : 0 : call timab(tim_cprj,1,tsec)
2630 : 0 : call xg_nonlop_getcprj(xg_nonlop,slice%X,slice%cprjX,slice%proj_work%self)
2631 : 0 : call timab(tim_cprj,2,tsec)
2632 : 0 : call timab(tim_AX_nl,1,tsec)
2633 : 0 : call xg_nonlop_getHX(xg_nonlop,slice%AX,slice%cprjX,slice%cprj_work,slice%proj_work%self)
2634 : 0 : call timab(tim_AX_nl,2,tsec)
2635 : :
2636 : : end do ! End polynomial degree loop
2637 : :
2638 : 0 : call xgBlock_reverseMap(Moments%self, cheby_moments, neigenpairs, ndeg_filter_max+1)
2639 : :
2640 : : ! Free memory
2641 : 0 : call xg_free(X0)
2642 : 0 : call xg_free(Moments)
2643 : :
2644 [ # # # # : 0 : end subroutine computeChebyshevMoments
# # # # #
# ]
2645 : : !!***
2646 : :
2647 : : !----------------------------------------------------------------------
2648 : :
2649 : : !!****f* m_slice_cprj/computeTraceEstimation
2650 : : !! NAME
2651 : : !! computeTraceEstimation
2652 : : !!
2653 : : !! FUNCTION
2654 : : !! Compute Girard-Hutchinson trace estimator
2655 : : !!
2656 : : !! SOURCE
2657 : : subroutine computeTraceEstimation(slice, m_vecs, trace_degree, low_bound, upp_bound, &
2658 : : min_low_bound, max_upp_bound, trace_est, getAX, kin, my_rank, gpu_option)
2659 : :
2660 : : implicit none
2661 : :
2662 : : type(slice_t), intent(inout) :: slice
2663 : : type(xgBlock_t), intent(in) :: kin
2664 : : integer, intent(in) :: my_rank
2665 : : integer, intent(in) :: trace_degree
2666 : : integer, intent(in) :: m_vecs
2667 : : real(dp), intent(out) :: trace_est
2668 : : real(dp), intent(in) :: low_bound, upp_bound
2669 : : real(dp), intent(in) :: min_low_bound, max_upp_bound
2670 : : integer, optional, intent(in) :: gpu_option
2671 : :
2672 : : interface
2673 : : subroutine getAX(X,AX)
2674 : : use m_xg, only : xgBlock_t
2675 : : type(xgBlock_t), intent(inout) :: X
2676 : : type(xgBlock_t), intent(inout) :: AX
2677 : : end subroutine getAX
2678 : : end interface
2679 : :
2680 : : type(xg_t) :: dot_XfX
2681 : : type(xg_t) :: xgX
2682 : : type(xg_nonlop_t) :: xg_nonlop
2683 : : integer :: cprjdim
2684 : : integer :: spacedim
2685 : : integer :: blockdim_cprj
2686 : : integer :: nspinor
2687 : : integer :: l_gpu_option
2688 : : !integer :: idx_i, idx_j
2689 : : real(dp) :: tolerance
2690 : : !real(dp) :: trace_tmp
2691 : : !real(dp) :: normX
2692 : : real(dp), pointer :: accum(:,:) => null()
2693 : : complex(dp), pointer :: X(:,:) => null()
2694 : : real(dp) :: tsec(2)
2695 : :
2696 : : ! *********************************************************************
2697 : :
2698 : : spacedim = slice%total_spacedim
2699 : : tolerance = slice%tolerance
2700 : : cprjdim = slice%cprjdim
2701 : : nspinor = slice%xg_nonlop%nspinor
2702 : : blockdim_cprj = m_vecs*nspinor
2703 : : xg_nonlop = slice%xg_nonlop
2704 : :
2705 : : l_gpu_option = ABI_GPU_DISABLED
2706 : : if (present(gpu_option)) then
2707 : : l_gpu_option = gpu_option
2708 : : end if
2709 : :
2710 : : ! Allocate contiguous memory blocks
2711 : : call xg_init(dot_XfX, slice%space, m_vecs, 1) ! <X,f(A)X>
2712 : : call xg_init(xgX, slice%space, spacedim, m_vecs, slice%spacecom, me_g0=slice%me_g0) ! X
2713 : :
2714 : : call xgBlock_reverseMap(xgX%self, X, spacedim, m_vecs)
2715 : :
2716 : : ! Fill entries of random matrices
2717 : : call generateRademacherMatrix(X, spacedim, m_vecs, my_rank)
2718 : : !call generateGaussianMatrix(X, spacedim, m_vecs, my_rank)
2719 : :
2720 : : ! Initialize X (dimensions then values)
2721 : : call xg_setBlock(slice%X_SLICE, slice%X, spacedim, m_vecs)
2722 : : call xgBlock_copy(xgX%self, slice%X)
2723 : :
2724 : : ! Initialize Xprev, Xnext (dimensions)
2725 : : call xg_setBlock(slice%X_NP,slice%X_next,spacedim,m_vecs)
2726 : : call xg_setBlock(slice%X_NP,slice%X_prev,spacedim,m_vecs,fcol=m_vecs+1)
2727 : :
2728 : : ! Initialize cprj (dimensions and values)
2729 : : call xgBlock_setBlock(slice%AllcprjX, slice%cprjX, slice%cprjdim, blockdim_cprj)
2730 : : call xgBlock_setBlock(slice%Allcprj_work%self, slice%cprj_work, slice%cprjdim, blockdim_cprj)
2731 : :
2732 : : call timab(tim_cprj,1,tsec)
2733 : : call xg_nonlop_getcprj(xg_nonlop,slice%X,slice%cprjX,slice%proj_work%self)
2734 : : call timab(tim_cprj,2,tsec)
2735 : :
2736 : : ! Initialize A * Psi (dimensions and values)
2737 : : call xg_setBlock(slice%X_SLICE, slice%AX, spacedim, m_vecs, fcol=m_vecs+1)
2738 : :
2739 : : call timab(tim_AX_v,1,tsec)
2740 : : call getAX(slice%X,slice%AX)
2741 : : call timab(tim_AX_v,2,tsec)
2742 : : call timab(tim_AX_k,1,tsec)
2743 : : call xgBlock_add_diag(slice%X,kin,nspinor,slice%AX)
2744 : : call timab(tim_AX_k,2,tsec)
2745 : : call timab(tim_AX_nl,1,tsec)
2746 : : call xg_nonlop_getHX(xg_nonlop,slice%AX,slice%cprjX,slice%cprj_work,slice%proj_work%self)
2747 : : call timab(tim_AX_nl,2,tsec)
2748 : :
2749 : : ! Compute f(A) * X
2750 : : call applyBandpassFilter(slice, getAX, kin, low_bound, upp_bound, &
2751 : : min_low_bound, max_upp_bound, trace_degree, l_gpu_option)
2752 : :
2753 : : call xgBlock_colwiseDotProduct(xgX%self, slice%X, dot_XfX%self, comm_loc=xmpi_comm_null)
2754 : : call xgBlock_reverseMap(dot_XfX%self, accum, m_vecs, 1)
2755 : :
2756 : : trace_est = sum(accum) / m_vecs
2757 : :
2758 : : ! Free memory
2759 : : call xg_free(dot_XfX)
2760 : : call xg_free(xgX)
2761 : :
2762 : : end subroutine computeTraceEstimation
2763 : : !!***
2764 : :
2765 : : !----------------------------------------------------------------------
2766 : :
2767 : : !!****f* m_slice_cprj/splitSpectrumToSlices
2768 : : !! NAME
2769 : : !! splitSpectrumToSlices
2770 : : !!
2771 : : !! SOURCE
2772 : : !subroutine splitSpectrumToSlices( &
2773 : : ! slice, nslice, trace_rank, trace_degree, nstep_spectrum, &
2774 : : ! low_bound_wanted, upp_bound_wanted, min_bound, max_bound, my_rank, &
2775 : : ! getAX, kin, nb_vec_slices, upp_bound_slices, gpu_option)
2776 : : subroutine splitSpectrumToSlices( &
2777 : : slice, nslice, nstep_spectrum, &
2778 : : low_bound_wanted, upp_bound_wanted, min_bound, max_bound, &
2779 : : nb_vec_slices, upp_bound_slices, gpu_option)
2780 : :
2781 : : implicit none
2782 : :
2783 : : ! Arguments
2784 : : type(slice_t), intent(inout) :: slice
2785 : : !type(xgBlock_t), intent(in) :: kin
2786 : : integer, intent(in) :: nslice
2787 : : !integer, intent(in) :: trace_rank
2788 : : !integer, intent(in) :: trace_degree
2789 : : integer, intent(in) :: nstep_spectrum
2790 : : !integer, intent(in) :: my_rank
2791 : : real(dp), intent(in) :: low_bound_wanted
2792 : : real(dp), intent(in) :: upp_bound_wanted
2793 : : real(dp), intent(in) :: min_bound
2794 : : real(dp), intent(in) :: max_bound
2795 : : integer, intent(inout) :: nb_vec_slices(nslice)
2796 : : real(dp), intent(inout) :: upp_bound_slices(nslice)
2797 : : integer, optional, intent(in) :: gpu_option
2798 : : !interface
2799 : : ! subroutine getAX(X,AX)
2800 : : ! use m_xg, only : xgBlock_t
2801 : : ! type(xgBlock_t), intent(inout) :: X
2802 : : ! type(xgBlock_t), intent(inout) :: AX
2803 : : ! end subroutine getAX
2804 : : !end interface
2805 : :
2806 : : ! Local variables
2807 : : integer, parameter :: trace_crit = 2
2808 : : integer :: l_gpu_option
2809 : : integer :: trace_sum
2810 : : integer :: neigenpairs
2811 : : integer :: ipart
2812 : : integer :: mid, idx, k, n
2813 : : logical :: found_gap(nstep_spectrum)
2814 : : real(dp) :: width
2815 : : real(dp) :: trace_est
2816 : : real(dp) :: lower_i
2817 : : real(dp) :: upper_i
2818 : : real(dp) :: trace_estim_spectrum(nstep_spectrum)
2819 : : real(dp) :: upper_bound_spectrum(nstep_spectrum)
2820 : :
2821 : : ! *********************************************************************
2822 : :
2823 : : neigenpairs = slice%neigenpairs
2824 : : l_gpu_option = ABI_GPU_DISABLED
2825 : : if (present(gpu_option)) then
2826 : : l_gpu_option = gpu_option
2827 : : end if
2828 : :
2829 : : if (low_bound_wanted < min_bound) then
2830 : : ABI_ERROR('wanted spectrum falls outside given lower bound')
2831 : : end if
2832 : : if (upp_bound_wanted > max_bound) then
2833 : : ABI_ERROR('wanted spectrum falls outside given upper bound')
2834 : : end if
2835 : :
2836 : : ! Split working spectrum into N intervals (N=nstep_spectrum)
2837 : : width = (upp_bound_wanted - low_bound_wanted) / nstep_spectrum
2838 : : trace_sum = 0
2839 : :
2840 : : do ipart=1, nstep_spectrum
2841 : :
2842 : : lower_i = min(max_bound, low_bound_wanted + (ipart - 1) * width)
2843 : : upper_i = min(max_bound, low_bound_wanted + ipart * width)
2844 : :
2845 : : !call computeTraceEstimation(slice, trace_rank, trace_degree, lower_i, upper_i,&
2846 : : ! min_bound, max_bound, trace_est, getAX, kin, my_rank, gpu_option=l_gpu_option)
2847 : :
2848 : : ! TODO keep this version and add second version that reuses Chebyshev
2849 : : ! recursion to avoid repeated calculations...
2850 : :
2851 : : found_gap(ipart) = ( ipart>1 .and. trace_est < trace_crit )
2852 : :
2853 : : write(std_out,*) 'spectrum part : nbvecs', ipart, lower_i, upper_i, ceiling(trace_est)
2854 : : flush(std_out)
2855 : :
2856 : : upper_bound_spectrum(ipart) = upper_i
2857 : : trace_estim_spectrum(ipart) = ceiling(trace_est)
2858 : :
2859 : : trace_sum = trace_sum + ceiling(trace_est)
2860 : :
2861 : : end do
2862 : :
2863 : : if (trace_sum < slice%neigenpairs) then
2864 : : ABI_WARNING("trace estimation missed eigenvalues")
2865 : : end if
2866 : :
2867 : : ! Chose the spectral gap with the index closer to the middle
2868 : : ! same for interval bound closer to the midpoint
2869 : : write(std_out,*) "found_gap=", found_gap
2870 : : write(std_out,*) "upper_bound=", upper_bound_spectrum
2871 : : flush(std_out)
2872 : :
2873 : : found_gap = ( trace_estim_spectrum == minval(trace_estim_spectrum) )
2874 : :
2875 : : write(std_out,*) "found_gap(mod)=", found_gap
2876 : :
2877 : : n = nstep_spectrum
2878 : : mid = (n + 1) / 2
2879 : : idx = 0 ! 0 = not found
2880 : :
2881 : : if (found_gap(mid)) then
2882 : : idx = mid
2883 : : else
2884 : : do k = 1, max(mid-1, n-mid)
2885 : : if (mid-k >= 1) then
2886 : : if (found_gap(mid-k)) then
2887 : : idx = mid-k
2888 : : exit
2889 : : end if
2890 : : end if
2891 : : if (mid+k <= n) then
2892 : : if (found_gap(mid+k)) then
2893 : : idx = mid+k
2894 : : exit
2895 : : end if
2896 : : end if
2897 : : end do
2898 : : end if
2899 : :
2900 : : nb_vec_slices(1) = min(ceiling(sum(trace_estim_spectrum(1:idx+1))), neigenpairs)
2901 : : nb_vec_slices(2) = min(ceiling(sum(trace_estim_spectrum(idx+2:nstep_spectrum))), neigenpairs)
2902 : : write(std_out,*) 'gap idx =', idx
2903 : : write(std_out,*) 'gap value =', upper_bound_spectrum(idx)
2904 : : write(std_out,*) 'trace left =', nb_vec_slices(1)
2905 : : write(std_out,*) 'trace right=', nb_vec_slices(2)
2906 : : flush(std_out)
2907 : :
2908 : : ! output the gap
2909 : : upp_bound_slices(1) = upper_bound_spectrum(idx)
2910 : :
2911 : :
2912 : : end subroutine splitSpectrumToSlices
2913 : : !!***
2914 : :
2915 : : !----------------------------------------------------------------------
2916 : :
2917 : : !!****f* m_slice_cprj/computeBLanczos
2918 : : !! NAME
2919 : : !! computeBLanczos
2920 : : !!
2921 : : !! FUNCTION
2922 : : !! B-Lanczos three-term recurrence (using B-inner product)
2923 : : !!
2924 : : !! SOURCE
2925 : :
2926 : 0 : subroutine computeBLanczos(slice, getAX, kin, n, k, lambda_min, res_norm, gpu_option)
2927 : :
2928 : : implicit none
2929 : :
2930 : : type(slice_t), intent(inout) :: slice
2931 : : type(xgBlock_t), intent(in) :: kin
2932 : : integer, intent(in) :: n, k
2933 : : real(dp), intent(out) :: lambda_min, res_norm
2934 : : integer, optional, intent(in) :: gpu_option
2935 : : interface
2936 : : subroutine getAX(X,AX)
2937 : : use m_xg, only : xgBlock_t
2938 : : type(xgBlock_t), intent(inout) :: X
2939 : : type(xgBlock_t), intent(inout) :: AX
2940 : : end subroutine getAX
2941 : : end interface
2942 : :
2943 : 0 : type(xg_nonlop_t) :: xg_nonlop
2944 : : !type(xg_t) :: xg_Bv
2945 : 0 : real(dp) :: Bv(n), Bv2(2,n)
2946 : 0 : real(dp) :: q(n), q2(2,n), v(n), v2(2,n)
2947 : 0 : real(dp) :: Bm1v2(2,n)
2948 : 0 : real(dp) :: alpha(k), beta(k-1)
2949 : 0 : real(dp) :: q_prev(n)
2950 : 0 : real(dp) :: v_min(n)
2951 : : real(dp) :: beta_prev
2952 : : real(dp) :: normB
2953 : :
2954 : : integer :: i, j
2955 : : integer :: space
2956 : : integer :: spacedim
2957 : : integer :: l_gpu_option
2958 : :
2959 : : ! *********************************************************************
2960 : :
2961 [ # # # # : 0 : xg_nonlop = slice%xg_nonlop
# # # # #
# ]
2962 : 0 : space = slice%space
2963 : 0 : spacedim = slice%spacedim
2964 : :
2965 : 0 : l_gpu_option = ABI_GPU_DISABLED
2966 [ # # ]: 0 : if (present(gpu_option)) then
2967 : 0 : l_gpu_option = gpu_option
2968 : : end if
2969 : :
2970 : : ! ONGOING
2971 : : ! unit tests per elementary operation
2972 : :
2973 : 0 : call random_number(q)
2974 [ # # ]: 0 : do i = 1, n
2975 : 0 : q2(1, i) = q(i)
2976 : 0 : q2(2, i) = 0.0d0
2977 : : end do
2978 [ # # # # : 0 : v2(:,:) = 0.0d0; v(:) = 0.0d0
# # ]
2979 [ # # # # : 0 : Bv2(:,:) = 0.0d0; Bv(:) = 0.0d0
# # ]
2980 [ # # # # ]: 0 : Bm1v2(:,:) = 0.0d0
2981 : :
2982 : : ! Bv = B * q
2983 : 0 : call matmul_op_B(slice, n, q2, Bv2, l_gpu_option)
2984 [ # # ]: 0 : do i = 1, n
2985 : 0 : Bv(i) = Bv2(1, i) ! avoids temporary
2986 : : end do
2987 : :
2988 [ # # ]: 0 : normB = sqrt(dot_product(q, Bv))
2989 [ # # ]: 0 : q = q / normB
2990 : :
2991 [ # # ]: 0 : q_prev = 0.0_dp
2992 : : beta_prev = 0.0_dp
2993 : :
2994 [ # # ]: 0 : do j = 1, k
2995 : : ! v = A * q
2996 [ # # ]: 0 : do i = 1, n
2997 : 0 : q2(1, i) = q(i)
2998 : : end do
2999 : 0 : call matmul_op_A(slice, getAX, kin, n, q2, v2, l_gpu_option)
3000 [ # # ]: 0 : do i = 1, n
3001 : 0 : v(i) = v2(1, i)
3002 : : end do
3003 : :
3004 : : ! alpha_j = q^T * Aq
3005 [ # # ]: 0 : alpha(j) = dot_product(q, v)
3006 : :
3007 : : ! v = B^{-1} * A * q
3008 : 0 : call matmul_op_Binv(slice, n, v2, Bm1v2, l_gpu_option)
3009 [ # # ]: 0 : do i = 1, n
3010 : 0 : v(i) = Bm1v2(1, i)
3011 : : end do
3012 : :
3013 : : ! v = B^{-1} A q - alpha q - beta_prev q_prev
3014 [ # # ]: 0 : v = v - alpha(j)*q
3015 [ # # # # ]: 0 : if (j > 1) v = v - beta_prev*q_prev
3016 : :
3017 : : ! Compute beta_j if j<k
3018 [ # # ]: 0 : if (j < k) then
3019 : : ! Bv = B * v
3020 [ # # ]: 0 : do i = 1, n
3021 : 0 : v2(1, i) = v(i)
3022 : : end do
3023 : 0 : call matmul_op_B(slice, n, v2, Bv2, l_gpu_option)
3024 [ # # ]: 0 : do i = 1, n
3025 : 0 : Bv(i) = Bv2(1, i)
3026 : : end do
3027 : :
3028 [ # # ]: 0 : beta(j) = sqrt(dot_product(v, Bv))
3029 : :
3030 : : ! Update q_prev, q, beta_prev
3031 [ # # ]: 0 : q_prev = q
3032 [ # # ]: 0 : q = v / beta(j)
3033 : : beta_prev = beta(j)
3034 : : end if
3035 : : end do
3036 : :
3037 : : ! Diagonalize T
3038 : 0 : call smallestTridiagEigenpair(k, alpha, beta, lambda_min, v_min)
3039 : :
3040 : : ! residual norm using Lanczos shortcut
3041 : 0 : res_norm = abs(beta(k-1)*v_min(k))
3042 : :
3043 [ # # # # : 0 : end subroutine computeBLanczos
# # # # ]
3044 : : !!***
3045 : :
3046 : : !----------------------------------------------------------------------
3047 : :
3048 : : !!****f* m_slice_cprj/matmul_op_A
3049 : : !! NAME
3050 : : !! matmul_op_A
3051 : : !!
3052 : : !! FUNCTION
3053 : : !! Apply A to Fortran 1D array q2 and store result to Fortran 1D array Aq2
3054 : : !! All in complex.
3055 : : !!
3056 : : !! SOURCE
3057 : :
3058 : 0 : subroutine matmul_op_A(slice, getAX, kin, n, q2, Aq2, gpu_option)
3059 : :
3060 : : implicit none
3061 : :
3062 : : type(slice_t), intent(inout) :: slice
3063 : : type(xgBlock_t), intent(in) :: kin
3064 : : integer, intent(in) :: n
3065 : : real(dp), intent(in) :: q2(2,n) ! 1d complex array (in)
3066 : : real(dp), intent(out) :: Aq2(2,n) ! 1d complex array (out)
3067 : : integer, optional, intent(in) :: gpu_option
3068 : :
3069 : : interface
3070 : : subroutine getAX(X,AX)
3071 : : use m_xg, only : xgBlock_t
3072 : : type(xgBlock_t), intent(inout) :: X
3073 : : type(xgBlock_t), intent(inout) :: AX
3074 : : end subroutine getAX
3075 : : end interface
3076 : :
3077 : : type(xg_t) :: cprjW, cprj_work
3078 : : type(xgBlock_t) :: W, AW, proj_work
3079 : 0 : type(xg_nonlop_t) :: xg_nonlop
3080 : : integer :: l_gpu_option, space, spacecom, space_cprj, cprjdim, nspinor
3081 : : integer :: blockdim_cprj
3082 : : real(dp) :: tsec(2)
3083 : :
3084 : : ! *********************************************************************
3085 : :
3086 : 0 : space = slice%space
3087 : 0 : spacecom = slice%spacecom
3088 : 0 : space_cprj = slice%space_cprj
3089 : 0 : cprjdim = slice%cprjdim
3090 : 0 : nspinor = slice%xg_nonlop%nspinor
3091 [ # # # # : 0 : xg_nonlop = slice%xg_nonlop
# # # # ]
3092 : 0 : proj_work = slice%proj_work%self
3093 : :
3094 : 0 : l_gpu_option = ABI_GPU_DISABLED
3095 : : if (present(gpu_option)) then
3096 : : l_gpu_option = gpu_option
3097 : : end if
3098 : :
3099 : : ! TODO make this optional
3100 : 0 : blockdim_cprj = nspinor ! = number_columns * nspinor
3101 : 0 : call xg_init(cprjW, space_cprj, cprjdim, blockdim_cprj, spacecom)
3102 : 0 : call xg_init(cprj_work, space_cprj, cprjdim, blockdim_cprj, spacecom)
3103 : :
3104 : : ! TODO make this optional otherwise W=slice%X and AW=slice%AX
3105 : 0 : call xgBlock_map(W, q2, space, n, 1, spacecom, gpu_option=gpu_option)
3106 : 0 : call xgBlock_map(AW, Aq2, space, n, 1, spacecom, gpu_option=gpu_option)
3107 : :
3108 : 0 : call timab(tim_cprj,1,tsec)
3109 : 0 : call xg_nonlop_getcprj(xg_nonlop, W, cprjW%self, proj_work)
3110 : 0 : call timab(tim_cprj,2,tsec)
3111 : :
3112 : 0 : call timab(tim_ax_v,1,tsec)
3113 : 0 : call getAX(W,AW)
3114 : 0 : call timab(tim_ax_v,2,tsec)
3115 : :
3116 : 0 : call timab(tim_ax_k,1,tsec)
3117 : 0 : call xgBlock_add_diag(W,kin,nspinor,AW)
3118 : 0 : call timab(tim_ax_k,2,tsec)
3119 : :
3120 : 0 : call timab(tim_AX_nl,1,tsec)
3121 : 0 : call xg_nonlop_getHX(xg_nonlop, AW, cprjW%self, cprj_work%self, proj_work)
3122 : 0 : call timab(tim_AX_nl,2,tsec)
3123 : :
3124 : 0 : call xg_free(cprjW)
3125 : 0 : call xg_free(cprj_work)
3126 : :
3127 [ # # # # : 0 : end subroutine matmul_op_A
# # # # #
# ]
3128 : : !!***
3129 : :
3130 : : !----------------------------------------------------------------------
3131 : :
3132 : : !!****f* m_slice_cprj/matmul_op_B
3133 : : !! NAME
3134 : : !! matmul_op_B
3135 : : !!
3136 : : !! FUNCTION
3137 : : !! Apply B to Fortran 1D array q2 and store result to Fortran 1D array Bq2
3138 : : !! All in complex.
3139 : : !!
3140 : : !! SOURCE
3141 : :
3142 : 0 : subroutine matmul_op_B(slice, n, q2, Bq2, gpu_option)
3143 : :
3144 : : implicit none
3145 : :
3146 : : type(slice_t), intent(inout) :: slice
3147 : : integer, intent(in) :: n
3148 : : real(dp), intent(in) :: q2(2,n) ! 1d complex array (in)
3149 : : real(dp), intent(out) :: Bq2(2,n) ! 1d complex array (out)
3150 : : integer, optional, intent(in) :: gpu_option
3151 : :
3152 : : type(xg_t) :: cprjW, cprj_work
3153 : : type(xgBlock_t) :: W, BW, proj_work
3154 : 0 : type(xg_nonlop_t) :: xg_nonlop
3155 : : integer :: l_gpu_option, space, spacecom, space_cprj, cprjdim, nspinor
3156 : : integer :: blockdim_cprj
3157 : : real(dp) :: tsec(2)
3158 : :
3159 : : ! *********************************************************************
3160 : :
3161 : 0 : space = slice%space
3162 : 0 : spacecom = slice%spacecom
3163 : 0 : space_cprj = slice%space_cprj
3164 : 0 : cprjdim = slice%cprjdim
3165 : 0 : nspinor = slice%xg_nonlop%nspinor
3166 [ # # # # : 0 : xg_nonlop = slice%xg_nonlop
# # # # ]
3167 : 0 : proj_work = slice%proj_work%self
3168 : :
3169 : 0 : l_gpu_option = ABI_GPU_DISABLED
3170 : : if (present(gpu_option)) then
3171 : : l_gpu_option = gpu_option
3172 : : end if
3173 : :
3174 : : ! TODO make this optional
3175 : 0 : blockdim_cprj = nspinor ! = number_columns * nspinor
3176 : 0 : call xg_init(cprjW, space_cprj, cprjdim, blockdim_cprj, spacecom)
3177 : 0 : call xg_init(cprj_work, space_cprj, cprjdim, blockdim_cprj, spacecom)
3178 : :
3179 : : ! TODO make this optional otherwise W=slice%X and AW=slice%AX
3180 : 0 : call xgBlock_map(W, q2, space, n, 1, spacecom, gpu_option=gpu_option)
3181 : 0 : call xgBlock_map(BW, Bq2, space, n, 1, spacecom, gpu_option=gpu_option)
3182 : :
3183 : 0 : call timab(tim_cprj,1,tsec)
3184 : 0 : call xg_nonlop_getcprj(xg_nonlop, W, cprjW%self, proj_work)
3185 : 0 : call timab(tim_cprj,2,tsec)
3186 : :
3187 : : ! BW = S|Psi>
3188 : 0 : call timab(tim_copy, 1, tsec)
3189 : 0 : call xgBlock_copy(W,BW)
3190 : 0 : call timab(tim_copy, 2, tsec)
3191 : :
3192 [ # # ]: 0 : if (slice%paw) then
3193 : 0 : call xg_nonlop_getSX(xg_nonlop, BW, cprjW%self, cprj_work%self, proj_work)
3194 : : end if
3195 : :
3196 : 0 : call xg_free(cprjW)
3197 : 0 : call xg_free(cprj_work)
3198 : :
3199 [ # # # # : 0 : end subroutine matmul_op_B
# # # # #
# ]
3200 : : !!***
3201 : :
3202 : : !----------------------------------------------------------------------
3203 : :
3204 : : !!****f* m_slice_cprj/matmul_op_Binv
3205 : : !! NAME
3206 : : !! matmul_op_Binv
3207 : : !!
3208 : : !! FUNCTION
3209 : : !! Apply Binv to Fortran 1D array q2 and store result to Fortran 1D array Binvq2
3210 : : !! All in complex.
3211 : : !!
3212 : : !! SOURCE
3213 : :
3214 : 0 : subroutine matmul_op_Binv(slice, n, q2, Binvq2, gpu_option)
3215 : :
3216 : : implicit none
3217 : :
3218 : : type(slice_t), intent(inout) :: slice
3219 : : integer, intent(in) :: n
3220 : : real(dp), intent(in) :: q2(2,n) ! 1d complex array (in)
3221 : : real(dp), intent(out) :: Binvq2(2,n) ! 1d complex array (out)
3222 : : integer, optional, intent(in) :: gpu_option
3223 : :
3224 : : type(xg_t) :: cprjW, cprj_work, cprj_work2
3225 : : type(xgBlock_t) :: W, BinvW, proj_work
3226 : 0 : type(xg_nonlop_t) :: xg_nonlop
3227 : : integer :: l_gpu_option, space, spacecom, space_cprj, cprjdim, nspinor
3228 : : integer :: blockdim_cprj
3229 : : real(dp) :: tsec(2)
3230 : :
3231 : : ! *********************************************************************
3232 : :
3233 : 0 : space = slice%space
3234 : 0 : spacecom = slice%spacecom
3235 : 0 : space_cprj = slice%space_cprj
3236 : 0 : cprjdim = slice%cprjdim
3237 : 0 : nspinor = slice%xg_nonlop%nspinor
3238 [ # # # # : 0 : xg_nonlop = slice%xg_nonlop
# # # # ]
3239 : 0 : proj_work = slice%proj_work%self
3240 : :
3241 : 0 : l_gpu_option = ABI_GPU_DISABLED
3242 : : if (present(gpu_option)) then
3243 : : l_gpu_option = gpu_option
3244 : : end if
3245 : :
3246 : 0 : blockdim_cprj = nspinor ! = number_columns * nspinor
3247 : 0 : call xg_init(cprjW, space_cprj, cprjdim, blockdim_cprj, spacecom)
3248 : 0 : call xg_init(cprj_work, space_cprj, cprjdim, blockdim_cprj, spacecom)
3249 : 0 : call xg_init(cprj_work2, space_cprj, cprjdim, blockdim_cprj, spacecom)
3250 : :
3251 : 0 : call xgBlock_map(W, q2, space, n, 1, spacecom, gpu_option=gpu_option)
3252 : 0 : call xgBlock_map(BinvW, Binvq2, space, n, 1, spacecom, gpu_option=gpu_option)
3253 : :
3254 : 0 : call timab(tim_cprj,1,tsec)
3255 : 0 : call xg_nonlop_getcprj(xg_nonlop, W, cprjW%self, proj_work)
3256 : 0 : call timab(tim_cprj,2,tsec)
3257 : :
3258 : : ! BinvW = S^{-1}|Psi>
3259 : 0 : call timab(tim_copy, 1, tsec)
3260 : 0 : call xgBlock_copy(W,BinvW)
3261 : 0 : call timab(tim_copy, 2, tsec)
3262 : :
3263 [ # # ]: 0 : if (slice%paw) then
3264 : 0 : call timab(tim_invovl, 1, tsec)
3265 : : call xg_nonlop_getSm1X(xg_nonlop, BinvW, cprjW%self, cprj_work%self, &
3266 : 0 : cprj_work2%self,proj_work)
3267 : 0 : call timab(tim_invovl, 2, tsec)
3268 : : end if
3269 : :
3270 : 0 : call xg_free(cprjW)
3271 : 0 : call xg_free(cprj_work)
3272 : 0 : call xg_free(cprj_work2)
3273 : :
3274 [ # # # # : 0 : end subroutine matmul_op_Binv
# # # # #
# ]
3275 : : !!***
3276 : :
3277 : : !----------------------------------------------------------------------
3278 : :
3279 : : !!****f* m_slice_cprj/computeFilterEnergy
3280 : : !! NAME
3281 : : !! computeFilterEnergy
3282 : : !!
3283 : : !! SOURCE
3284 : :
3285 : 0 : subroutine computeFilterEnergy(neigenpairs, ndeg_filter, cja, cheby_moments, &
3286 : : energy_interval, nvec_approx)
3287 : :
3288 : : implicit none
3289 : :
3290 : : integer, intent(in) :: ndeg_filter
3291 : : integer, intent(in) :: neigenpairs
3292 : : integer, intent(out) :: nvec_approx
3293 : : real(dp), pointer, intent(in) :: cja(:)
3294 : : real(dp), pointer, intent(in) :: cheby_moments(:,:)
3295 : : real(dp), pointer, intent(in) :: energy_interval(:)
3296 : :
3297 : 0 : real(dp) :: E_re(neigenpairs)
3298 : 0 : real(dp) :: E_im(neigenpairs)
3299 : : real(dp) :: E_tot
3300 : : real(dp) :: energy_magn_j
3301 : : integer :: ideg
3302 : : integer :: j
3303 : :
3304 : : ! *********************************************************************
3305 : :
3306 [ # # ]: 0 : E_re = 0.0d0
3307 [ # # ]: 0 : E_im = 0.0d0
3308 : 0 : E_tot = 0.d0
3309 [ # # ]: 0 : do ideg = 1, ndeg_filter+1
3310 [ # # ]: 0 : do j = 1, neigenpairs
3311 : 0 : E_re(j) = E_re(j) + cja(ideg) * cheby_moments(2*j-1, ideg)
3312 : 0 : E_im(j) = E_im(j) + cja(ideg) * cheby_moments(2*j, ideg)
3313 : : end do
3314 : : end do
3315 [ # # ]: 0 : do j = 1, neigenpairs
3316 : : !energy_magn_j = hypot(E_re(j), E_im(j))
3317 : 0 : energy_magn_j = real(E_re(j))
3318 : 0 : energy_interval(j) = energy_magn_j
3319 : 0 : E_tot = E_tot + energy_magn_j
3320 : : end do
3321 [ # # ]: 0 : nvec_approx = ceiling(E_tot)
3322 : :
3323 : 0 : end subroutine computeFilterEnergy
3324 : : !!***
3325 : :
3326 [ # # # # : 0 : end module m_slice_cprj
# # # # #
# # # # #
# # ]
3327 : : !!***
|