LCOV - code coverage report
Current view: top level - src/48_diago - m_slice.F90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 92.5 % 306 283
Test Date: 2026-09-21 13:49:52 Functions: 80.0 % 10 8

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

Generated by: LCOV version 2.3-1