LCOV - code coverage report
Current view: top level - src/68_recursion - m_rec.F90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 51.9 % 507 263
Test Date: 2026-09-20 15:27:41 Functions: 76.9 % 13 10

            Line data    Source code
       1              : !!****m* ABINIT/m_rec
       2              : !! NAME
       3              : !!  m_rec
       4              : !!
       5              : !! FUNCTION
       6              : !!  This module  provides some functions applied to the
       7              : !!  recursion structured datatype recursion_type.
       8              : !!  It includes also some function used to change some variables
       9              : !!  of recursion_type
      10              : !!
      11              : !! COPYRIGHT
      12              : !! Copyright (C) 2002-2026 ABINIT group (MMancini)
      13              : !! This file is distributed under the terms of the
      14              : !! GNU General Public License, see ~abinit/COPYING
      15              : !! or http://www.gnu.org/copyleft/gpl.txt .
      16              : !! For the initials of contributors, see ~abinit/doc/developers/contributors.txt.
      17              : !!
      18              : !! NOTES
      19              : !!
      20              : !! * Routines tagged with "@type_name" are strongly connected to the definition of the data type.
      21              : !!   Strongly connected means that the proper functioning of the implementation relies on the
      22              : !!   assumption that the tagged procedure is consistent with the type declaration.
      23              : !!   Every time a developer changes the structure "type_name" adding new entries, he/she has to make sure
      24              : !!   that all the strongly connected routines are changed accordingly to accomodate the modification of the data type.
      25              : !!   Typical examples of strongly connected routines are creation, destruction or reset methods.
      26              : !!
      27              : !!
      28              : !! SOURCE
      29              : 
      30              : #if defined HAVE_CONFIG_H
      31              : #include "config.h"
      32              : #endif
      33              : 
      34              : #include "abi_common.h"
      35              : 
      36              : module m_rec
      37              : 
      38              :  use defs_basis
      39              :  use defs_rectypes
      40              :  use m_abicore
      41              :  use m_errors
      42              :  use m_xmpi
      43              :  use m_sort
      44              :  use m_dtset
      45              : 
      46              :  use defs_datatypes,    only : pseudopotential_type
      47              :  use defs_abitypes,     only : mpi_type
      48              :  use m_exp_mat,         only : exp_mat
      49              :  use m_numeric_tools,   only : set2unit
      50              :  use m_special_funcs,   only : gamma_function
      51              :  use m_pawfgr,          only : pawfgr_nullify, indgrid, pawfgr_destroy
      52              :  use m_paw_sphharm,     only : initylmr
      53              :  use m_time,            only : timab
      54              :  use m_rec_tools,       only : get_pt0_pt1
      55              :  use m_per_cond,        only : per_cond
      56              : #ifdef HAVE_GPU_CUDA
      57              :  use m_hidecudarec,     only : InitRecGPU, CleanRecGPU
      58              : #endif
      59              : 
      60              :  implicit none
      61              : 
      62              :  private ::           &
      63              :    find_maxmin_proc,  &  !--To calculate max and min pt for any cpu
      64              :    H_D_distrib
      65              : 
      66              :  public ::            &
      67              :    InitRec,           &  !--Main creation method.
      68              :    Init_MetricRec,    &  !--To Initalize the inf. metric in recursion
      69              :    Init_nlpspRec,     &  !--Main creation method for non-local part.
      70              :    CleanRec,          &  !--deallocate all pointers.
      71              :    Calcnrec,          &  !--calculates the new min_nrec
      72              :    cpu_distribution      !--Regulates the work load on cpu-gpu
      73              : CONTAINS  !===========================================================
      74              : !!***
      75              : 
      76              : !!****f* m_rec/H_D_distrib
      77              : !! NAME
      78              : !! H_D_distrib
      79              : !!
      80              : !! FUNCTION
      81              : !! Calculate the number of point,GPU,for any proc
      82              : !!
      83              : !! INPUTS
      84              : !!  rset<recursion_type>= recursion variables
      85              : !!  cpu (-1 if there are not gpu)
      86              : !!  nfft=nuber of point of the fine grid
      87              : !!  ngfftrec=nuber of point of one edge of the coarse grid
      88              : !!  gratio=recgratio ratio between the fine and coarse grid
      89              : !!  beta_coeff=estimated time ratio between CPU_time and GPU_time
      90              : !!
      91              : !! OUTPUT
      92              : !!  proc_pt_dev(2,0:nproc-1) which device and how many points
      93              : !!  that proc has to compute: proc_pt_dev(1,iproc) which device
      94              : !!  associated to proc i (-1 if none), proc_pt_dev(2,iproc) how
      95              : !!  many points
      96              : !!
      97              : !! SOURCE
      98              : 
      99            6 : subroutine H_D_distrib(rset,nfft,gratio,proc_pt_dev,beta_coeff)
     100              : 
     101              : !Arguments ------------------------------------
     102              :  integer, intent(in) :: nfft,gratio
     103              :  real(dp),intent(in) :: beta_coeff
     104              :  integer,pointer :: proc_pt_dev(:,:)
     105              :  type(recursion_type),intent(inout) :: rset
     106              : !Local ---------------------------
     107              :  integer :: me,icpu,resto,ntot,ngpu
     108              :  integer :: n_per_cpu,n_per_gpu
     109              :  character(500) :: msg
     110              : #ifdef HAVE_GPU_CUDA
     111              :  integer,pointer :: ndev(:)
     112              : #else
     113           12 :  integer :: ndev(0:rset%mpi%nproc-1)
     114              : #endif
     115              : ! *********************************************************************
     116              : 
     117              : 
     118              : #ifdef HAVE_GPU_CUDA
     119              :  ndev => rset%GPU%map
     120              : #else
     121           24 :  ndev = -1
     122              : #endif
     123              : 
     124            6 :  me = rset%mpi%me
     125            6 :  ntot = nfft/(gratio*gratio*gratio)
     126            6 :  ngpu = rset%ngpu
     127              : 
     128              :  !--If sequential code all points are computed by the proc 0
     129            6 :  if(rset%mpi%nproc ==1) then
     130            2 :    proc_pt_dev(1,0) = ndev(0)
     131            2 :    proc_pt_dev(2,0) = ntot
     132            2 :    return
     133              :  end if
     134              : 
     135              :  !--Number of points for any cpu
     136            4 :  n_per_cpu = int(int(ntot/(rset%mpi%nproc+ngpu*(beta_coeff-1.d0))))
     137            4 :  n_per_gpu = int(n_per_cpu*beta_coeff)
     138              :  !write(std_out,*)'n_per_cpu',n_per_cpu
     139              :  !write(std_out,*)'rset%GPU%map',rset%GPU%map
     140           20 :  do icpu=0,rset%mpi%nproc-1
     141           16 :    proc_pt_dev(1,icpu) = ndev(icpu)
     142           16 :    proc_pt_dev(2,icpu) = n_per_cpu
     143           20 :    if(ndev(icpu)>-1) proc_pt_dev(2,icpu) = n_per_gpu
     144              :  end do
     145              : 
     146              :  !--Distribute the rest
     147           20 :  resto = ntot-sum(proc_pt_dev(2,:))
     148            4 :  icpu = 0
     149              :  !write(std_out,*)'rest',resto,ngpu
     150            4 :  if(resto>0) then
     151            0 :    if(ngpu/=0) then
     152              :      !--distribute rest only on GPU
     153            0 :      do while(resto/=0)
     154            0 :        if(proc_pt_dev(1,icpu)>-1) then
     155            0 :          proc_pt_dev(2,icpu) = proc_pt_dev(2,icpu)+1
     156            0 :          resto = resto-1
     157              :        endif
     158            0 :        icpu = mod(icpu+1,rset%mpi%nproc)
     159              :      enddo
     160              :    else
     161              :      !--distribute rest on all CPU
     162            0 :      do while(resto/=0)
     163            0 :        proc_pt_dev(2,icpu) = proc_pt_dev(2,icpu)+1
     164            0 :        resto = resto-1
     165            0 :        icpu = mod(icpu+1,rset%mpi%nproc)
     166              :      enddo
     167              :      return
     168              :    endif
     169              :  endif
     170              : 
     171              :  !--Printing GPU and load distribution on procs
     172              :  write(msg,'(3a)')&
     173            4 :       & ' -Load on procs------------',ch10,&
     174            8 :       & '   me  device        points'
     175            4 :  call wrtout(std_out,msg,'COLL')
     176           20 :  do icpu=0,rset%mpi%nproc-1
     177           16 :    write(msg,'(i5,i8,i14)') icpu,proc_pt_dev(:,icpu);
     178           20 :    call wrtout(std_out,msg,'COLL')
     179              :  end do
     180              : 
     181              : end subroutine H_D_distrib
     182              : !!***
     183              : 
     184              : 
     185              : 
     186              : !!****f* m_rec/find_maxmin_proc
     187              : !! NAME
     188              : !! find_maxmin_proc
     189              : !!
     190              : !! FUNCTION
     191              : !! To calculate max and min pt for any cpu, it is useful for
     192              : !! recgratio!=1
     193              : !!
     194              : !! INPUTS
     195              : !! nproc = number of procs
     196              : !! me = identity of the proc
     197              : !! ngfft(3) = fine grid (corresponds to dtset%ngfft(1:3))
     198              : !! proc_pt_dev(2,0:nproc-1) which device and how many points
     199              : !! recpar%npt = number of points computed by the proc me (see side effects)
     200              : !!
     201              : !! OUTPUT
     202              : !! recpar%pt0<type(vec_int)>=Intial point for this proc in x,y,z
     203              : !! recpar%pt1<type(vec_int)>=Final point for this proc in x,y,z
     204              : !! recpar%min_pt=Intial point for this proc
     205              : !! recpar%max_pt=Final point for this proc
     206              : !!
     207              : !! SIDE EFFECTS
     208              : !! recpar%ntranche=number of pts computed by the proc me on the fine grid.
     209              : !!
     210              : !!
     211              : !! So when  recgratio!=1, ntranche will  not correspond to the npt!
     212              : !!
     213              : !! SOURCE
     214              : 
     215            6 : subroutine find_maxmin_proc(recpar,nproc,me,gratio,ngfft,proc_pt_dev)
     216              : 
     217              : !Arguments ------------------------------------
     218              :  integer,intent(in)   :: nproc,me,gratio
     219              :  integer,intent(in)   :: ngfft(3)
     220              :  type(recparall_type),intent(inout) :: recpar
     221              :  integer,pointer :: proc_pt_dev(:,:)
     222              : !Local ---------------------------
     223              :  integer :: pointoncpu
     224              :  integer :: nfft,ntot,ii
     225              :  integer :: inf,sup
     226           12 :  integer :: proc_limit(0:nproc-1)
     227              : ! *********************************************************************
     228              :  !  write(std_out,*)'start find_maxmin_proc'
     229            6 :  recpar%npt = 0
     230              :  nfft = product(ngfft)
     231            6 :  ntot = nfft/(gratio*gratio*gratio)
     232            6 :  pointoncpu = ntot/nproc
     233              : 
     234           90 :  proc_limit = (/(sum(proc_pt_dev(2,:ii)),ii=0,nproc-1)/)
     235              : 
     236            6 :  if(gratio==1)then
     237            5 :    recpar%ntranche = proc_limit(me)
     238            5 :    if(me/=0) recpar%ntranche = recpar%ntranche-proc_limit(me-1)
     239              :  endif
     240              : 
     241            6 :  inf=0
     242            6 :  if(me/=0) inf = proc_limit(me-1)
     243            6 :  sup = proc_limit(me)
     244              : 
     245              : 
     246            6 :  call get_pt0_pt1(ngfft,gratio,inf,sup,recpar)
     247              : 
     248            6 :  recpar%npt = sup-inf
     249              : 
     250              :  !write(std_out,*)'exit find_maxmin_proc'
     251            6 : end subroutine find_maxmin_proc
     252              : !!***
     253              : 
     254              : !!****f* m_rec/cpu_distribution
     255              : !! NAME
     256              : !! cpu_distribution
     257              : !!
     258              : !! FUNCTION
     259              : !! Calculate the number of point,GPU,for any proc
     260              : !!
     261              : !! INPUTS
     262              : !!  ngfft(3)=nuber of point of the grid
     263              : !!  gratio=recgratio ratio between the fine and coarse grid
     264              : !!  beta_coeff=estimated time ratio between CPU_time and GPU_time
     265              : !!  calc_type=if 0 takes the possible max for nptrec (to test the
     266              : !!  completly full graphic card). 1 after test to calculate the min
     267              : !!  possible value for nptrec
     268              : !!
     269              : !! OUTPUT
     270              : !!
     271              : !! SOURCE
     272              : 
     273            6 :  subroutine cpu_distribution(gratio,rset,ngfft,beta_coeff,calc_type)
     274              : 
     275              : !Arguments ------------------------------------
     276              :  integer,intent(in)  :: gratio,calc_type
     277              :  real(dp),intent(in) :: beta_coeff
     278              :  integer,intent(in)  :: ngfft(3)
     279              :  type(recursion_type),intent(inout),target :: rset
     280              : !Local ---------------------------
     281              :  integer :: ii,nfft,ierr
     282            6 :  integer,pointer :: proc_pt_dev(:,:)
     283              :  type(recparall_type),pointer :: recpar
     284              :  character(500) :: msg
     285              : ! *********************************************************************
     286              : 
     287              :  ! write(std_out,*)'start cpu_distribution'
     288              : 
     289              :  nullify(proc_pt_dev)
     290           18 :  ABI_MALLOC(proc_pt_dev,(2,0:rset%mpi%nproc-1))
     291              : 
     292           24 :  nfft = product(ngfft)
     293            6 :  call H_D_distrib(rset,nfft,gratio,proc_pt_dev,beta_coeff)
     294              : 
     295            6 :  nullify(recpar)
     296            6 :  if(rset%load == 0)then
     297           18 :    ABI_MALLOC(rset%par%displs,(0:rset%mpi%nproc-1))
     298           18 :    ABI_MALLOC(rset%par%vcount,(0:rset%mpi%nproc-1))
     299            6 :    recpar => rset%par
     300              : #if defined HAVE_GPU_CUDA
     301              :  else
     302              :    if(rset%tp==4)then
     303              :      if(.not. allocated(rset%GPU%par%displs)) then
     304              :        ABI_MALLOC(rset%GPU%par%displs,(0:rset%mpi%nproc-1))
     305              :        ABI_MALLOC(rset%GPU%par%vcount,(0:rset%mpi%nproc-1))
     306              :      end if
     307              :    endif
     308              :    recpar => rset%GPU%par
     309              : #endif
     310              :  endif
     311              : 
     312            6 :  recpar%ntranche = nfft/(rset%mpi%nproc)!equipartitioned point
     313              : 
     314              :  call find_maxmin_proc(recpar,rset%mpi%nproc,&
     315            6 : &                      rset%mpi%me,gratio,ngfft,proc_pt_dev)
     316              : 
     317           24 :  recpar%vcount = 0
     318            6 :  if(rset%load==0)then
     319            6 :    recpar%vcount(rset%mpi%me) = recpar%ntranche
     320              :  else
     321            0 :    recpar%vcount(rset%mpi%me) = recpar%npt
     322              :  endif
     323              : 
     324            6 :  call xmpi_sum(recpar%vcount,rset%mpi%comm_bandfft,ierr)
     325              : 
     326           24 :  recpar%displs = 0
     327           58 :  if(rset%mpi%nproc>1) recpar%displs(1:) = (/(sum(recpar%vcount(:ii)),ii=0,rset%mpi%nproc-2)/)
     328              : 
     329              :  !--INITALIZATION OF CUDA FOR RECURSION
     330              : #if defined HAVE_GPU_CUDA
     331              :  if(rset%load == 0)   rset%GPU%par = rset%par
     332              :  call InitRecGPU(rset,nfft,gratio,rset%GPU%map(rset%mpi%me),calc_type)
     333              : #else
     334              :   ierr = calc_type !only of abirule when there is not HAVE_GPU_CUDA
     335              : #endif
     336              : 
     337              : 
     338              : ! if(rset%debug ) then
     339              :  write(msg,'(a,i7,2(2a,3i7),8(2a,i7),2(2a,3i7),(2a,e14.6))')&
     340            6 :    & ' me                 ',  rset%mpi%me,ch10,&
     341            6 :    & ' ngfft              ',  ngfft(1:3),ch10,&
     342            6 :    & ' ngfftrec           ',  rset%ngfftrec(1:3),ch10,&
     343            6 :    & ' load               ',  rset%load,ch10,&
     344            6 :    & ' ntranche           ',  recpar%ntranche,ch10,&
     345            6 :    & ' min_pt             ',  recpar%min_pt,ch10,&
     346            6 :    & ' max_pt             ',  recpar%max_pt,ch10,&
     347            6 :    & ' rset%mpi%nproc     ',  rset%mpi%nproc,ch10,&
     348            6 :    & ' rset%mpi%nproc_fft ',  rset%mpi%nproc_fft,ch10,&
     349            6 :    & ' dtset%ngfft(10)    ',  rset%ngfftrec(10),ch10,&
     350            6 :    & ' recpar%npt         ',  recpar%npt,ch10,&
     351            6 :    & ' recpar%pt0         ',  recpar%pt0%x,recpar%pt0%y,recpar%pt0%z,ch10,&
     352            6 :    & ' recpar%pt1         ',  recpar%pt1%x,recpar%pt1%y,recpar%pt1%z,ch10,&
     353           12 :    & ' grid step          ',  rset%inf%tr(1)
     354            6 :  call wrtout(std_out,msg,'PERS')
     355              : #if defined HAVE_GPU_CUDA
     356              :  write(msg,'(a,i7,2(2a,i7),a)')&
     357              :    & ' rset%ngp           ',  rset%ngpu,ch10,&
     358              :    & ' gpudevice          ',  rset%gpudevice,ch10,&
     359              :    & ' nptrec             ',  rset%GPU%nptrec,ch10
     360              :  call wrtout(std_out,msg,'PERS')
     361              : #endif
     362              : !  write(std_out,*)'display',recpar%displs
     363              : !  write(std_out,*)'vcount',recpar%vcount
     364              : ! end if
     365              : 
     366              : 
     367            6 :  nullify(recpar)
     368            6 :  if(associated(proc_pt_dev))  then
     369            6 :    ABI_FREE(proc_pt_dev)
     370              :  end if
     371              : 
     372              : ! write(std_out,*)'exit from cpu_distribution'
     373            6 : end subroutine cpu_distribution
     374              : !!***
     375              : 
     376              : 
     377              : !!****f* m_rec/InitRec
     378              : !! NAME
     379              : !! InitRec
     380              : !!
     381              : !! FUNCTION
     382              : !! Initialise the rset<recursion_type>=Data type concerning recursion.
     383              : !!
     384              : !! INPUTS
     385              : !! dtset <type(dataset_type)>=all input variables in this dataset
     386              : !! mpi_ab <type(mpi_type)=MPI-parallelisation information
     387              : !! mproj=0 if psp is only local
     388              : !!
     389              : !! SIDE EFFECTS
     390              : !! All pointers set to null().
     391              : !!
     392              : !!
     393              : !! SOURCE
     394              : 
     395            6 : subroutine InitRec(dtset,mpi_ab,rset,rmet,mproj)
     396              : 
     397              : #ifdef HAVE_GPU_CUDA
     398              :  use m_gpu_detect,only    :get_topo,find_set_gpu
     399              :  use m_hidecudarec,only   :InitRecGPU_0
     400              : #include "cuda_common.h"
     401              : #endif
     402              : 
     403              : !Arguments ------------------------------------
     404              : ! scalars
     405              :  integer,intent(in) :: mproj
     406              :  type(dataset_type),intent(in) :: dtset
     407              :  type(MPI_type),intent(in),target :: mpi_ab
     408              :  type(recursion_type),intent(inout) :: rset
     409              :  real(dp),intent(in) :: rmet(3,3)
     410              : ! arrays
     411              : !Local ---------------------------
     412              :  integer :: ii
     413              :  real(dp) :: beta,rtrotter
     414              : #if defined HAVE_GPU_CUDA
     415              :  character(500) :: msg
     416              : #endif
     417              : ! *********************************************************************
     418              :  ! @recursion_type
     419              :  ! @pawfgr_type
     420              : 
     421              :  !--Initialisation
     422            6 :  beta = one/dtset%tsmear  !--Inverse of temperature
     423              :  !--Rewriting the trotter parameter
     424            6 :  rtrotter  = max(half,real(dtset%recptrott,dp))
     425              : 
     426            6 :  rset%debug= (dtset%prtvol==-7)
     427            6 :  rset%quitrec   = 0
     428            6 :  rset%min_nrec  = dtset%recnrec
     429            6 :  rset%efermi    = dtset%recefermi !initial guess for fermie
     430              : 
     431            6 :  rset%nfftrec   = 0
     432          114 :  rset%ngfftrec  = 0
     433              : 
     434            6 :  rset%tronc = .False.
     435              : 
     436            6 :  rset%mpi => mpi_ab
     437              : 
     438              :  !--Are all pseudo-potentials local?
     439            6 :  rset%nl%nlpsp = (mproj/=0)
     440              :  !--Some initialisation concerning the metrics
     441              :  !  If non-local psps then it allocates the atoms positions
     442              :  !   on the grid
     443            6 :  if(rset%nl%nlpsp)  then
     444            0 :   ABI_MALLOC(rset%inf%gcart,(3,dtset%natom))
     445              :  else
     446            6 :   ABI_MALLOC(rset%inf%gcart,(0,0))
     447              :  end if
     448            6 :  rset%inf%gcart = 0
     449              : 
     450              :  !----------------------------------------------------------
     451              :  !--TRONCATION OF THE BOX
     452              :  !! determines new dimensions the method is similar to the one used
     453              :  !! in getng  (except that ecut and xboxcutmin give no constraint,
     454              :  !!  and symmetries are not handled)
     455              : 
     456            6 :  call getngrec(dtset%ngfft,rmet,rset%ngfftrec,rset%nfftrec,dtset%recrcut,0.25d0*sqrt(beta/rtrotter),rset%tronc)
     457              :  !  1/4*sqrt(beta/trotter) for guess - should be modified
     458              : 
     459              :  !------------------------------------------------------------
     460              :  !--DETERMINING WHICH POINT WILL COMPUTE THAT PROC
     461              :  !----------------------------------------------------------
     462              :  !--Paralelism using the band communicator (not used in the recursion)
     463              :  !--Distribution on procs with cuda
     464              : 
     465              : 
     466            6 :  rset%ngpu = 0       !--Initial guess no GPU at all
     467            6 :  rset%gpudevice = -1 !--Inital guess no GPU associated
     468            6 :  rset%load = 0       !--Inital homogeneous work load
     469            6 :  rset%tp = 0         !--Initial guess 1 cpu, 0 gpu
     470              : 
     471              : 
     472              : #ifdef HAVE_GPU_CUDA
     473              :  !--Initialise GPU variables for recursion
     474              :  call InitRecGPU_0(rset%GPU,mpi_ab)
     475              : 
     476              :  !--Get the distribution of GPUs on CPUs
     477              :  call find_set_gpu(mpi_ab%nproc,mpi_ab%comm_bandfft,rset%GPU%map,rset%ngpu)
     478              : 
     479              :  !--Get the topology of the machine
     480              :  call get_topo(rset%mpi%nproc,rset%ngpu,rset%tp)
     481              :  if(rset%tp>4)then
     482              :    msg = 'm_rec: number of gpu>number of cpu is not implemented'
     483              :    ABI_ERROR(msg)
     484              :  endif
     485              : !  rset%tp = 0;if(rset%mpi%nproc>1)rset%tp = 1
     486              : !  rset%ngpu = 0; rset%GPU%map=-1
     487              :  !--For the moment cuda doesnt take into account non-local psp
     488              :  if(rset%nl%nlpsp) then
     489              :    rset%tp = 0;if(rset%mpi%nproc>1)rset%tp = 1
     490              :    rset%GPU%map = -1
     491              :  endif
     492              : #else
     493            6 :  if(rset%mpi%nproc>1)rset%tp = 1
     494              : #endif
     495              : 
     496              :  !--Basic initialization for recursion metric (only needed for printing)
     497           24 :  do ii=1,3
     498           78 :    rset%inf%rmet(ii,:) = rmet(ii,:)/(real(dtset%ngfft(1:3)*dtset%ngfft(ii),dp))
     499              :  end do
     500           24 :  rset%inf%tr(:) = sqrt((/(rset%inf%rmet(ii,ii),ii=1,3)/)) !grid step
     501              : 
     502              :  !--Compute the work loqd distribution on devices (gpu,cpu)
     503            6 :  call cpu_distribution(dtset%recgratio,rset,dtset%ngfft(:3),1.d0,0)
     504              : 
     505              :  !------------------------------------------------------------
     506              :  !--DEFINITION VARIABLE COARSE-FINE GRID  TO USE TRANSGRID--INGRID FUNCTIONS
     507            6 :  call pawfgr_nullify(rset%pawfgr)
     508              :  !if coarse grid is used
     509            6 :  if (dtset%recgratio>1) then
     510              :    !fine grid--
     511            1 :    rset%pawfgr%mgfft = 0
     512            4 :    rset%pawfgr%nfft = product(dtset%ngfft(1:3))
     513           19 :    rset%pawfgr%ngfft(:) = dtset%ngfft(:)
     514            4 :    rset%pawfgr%ngfft(9:11)=(/0,1,0/)
     515            3 :    rset%pawfgr%ngfft(12:13)= dtset%ngfft(2:3)
     516              :    !coarse grid--
     517            1 :    rset%pawfgr%mgfftc = 0
     518           19 :    rset%pawfgr%ngfftc(:) = rset%pawfgr%ngfft(:)
     519            4 :    rset%pawfgr%ngfftc(:3) = floor(real(dtset%ngfft(:3)+1,dp)/real(dtset%recgratio,dp))
     520            4 :    rset%pawfgr%nfftc = product(rset%pawfgr%ngfftc(1:3))
     521              : 
     522            1 :    rset%pawfgr%usefinegrid = 1
     523            3 :    ABI_MALLOC(rset%pawfgr%fintocoa,(rset%pawfgr%nfft))
     524            3 :    ABI_MALLOC(rset%pawfgr%coatofin,(rset%pawfgr%nfftc))
     525              :    call indgrid(rset%pawfgr%coatofin,rset%pawfgr%fintocoa,&
     526              :      rset%pawfgr%nfftc,rset%pawfgr%nfft,&
     527            1 :      rset%pawfgr%ngfftc,rset%pawfgr%ngfft)
     528              : 
     529              :  else
     530            5 :    rset%pawfgr%mgfft = 0
     531           95 :    rset%pawfgr%ngfft = 0
     532            5 :    rset%pawfgr%mgfftc = 0
     533              : 
     534            5 :    rset%pawfgr%usefinegrid = 0
     535              :  end if
     536              : 
     537              : 
     538            6 : end subroutine InitRec
     539              : !!***
     540              : 
     541              : !!****f* m_rec/Init_MetricRec
     542              : !! NAME
     543              : !! Init_MetricRec
     544              : !!
     545              : !! FUNCTION
     546              : !! Initialise the rset<recursion_type>=Data type concerning recursion.
     547              : !! In particular, the information on the infinitesimal metric.
     548              : !! Also other variable are initialized
     549              : !!
     550              : !! INPUTS
     551              : !! rmet: metrics
     552              : !! ucvol=unit cell volume in bohr**3.
     553              : !! ngfft(1:3)=fine grid used in recursion
     554              : !! rprimd=Real space PRIMitive translations, Dimensional
     555              : !! xred=vectors (X) of atom positions in reduced coordinates
     556              : !! natom=number of atoms
     557              : !! debug=debug variable
     558              : !!
     559              : !! OUTPUT
     560              : !! metrec <type(metricrec_type)>= infinitesimal metrics used in recursion
     561              : !!
     562              : !! SOURCE
     563              : 
     564           11 : subroutine Init_MetricRec(metrec,nlpsp,rmet,ucvol,rprimd,xred,ngfft,natom,debug)
     565              : 
     566              : !Arguments ------------------------------------
     567              : !scalars
     568              :  integer, intent(in) ::natom
     569              :  real(dp), intent(in) :: ucvol
     570              :  logical,intent(in) ::nlpsp,debug
     571              :  type(metricrec_type),intent(inout) :: metrec
     572              : !arrays
     573              :  integer,intent(in) :: ngfft(3)
     574              :  real(dp),intent(in) :: rmet(3,3),rprimd(3,3),xred(3,natom)
     575              : 
     576              : !Local ---------------------------
     577              :  integer :: ii
     578           22 :  real(dp) :: xcart(3,natom)
     579              :  character(500) :: msg
     580              : ! *********************************************************************
     581              : 
     582              :  !--Intialisation of variables concerning the infinitesimal metric
     583           44 :  do ii=1,3
     584          143 :    metrec%rmet(ii,:) = rmet(ii,:)/(real(ngfft(1:3)*ngfft(ii),dp))
     585              :  end do
     586           44 :  metrec%ucvol = ucvol/real(product(ngfft(1:3)),dp)
     587           44 :  metrec%tr(:) = sqrt((/(metrec%rmet(ii,ii),ii=1,3)/)) !grid step
     588              : 
     589              :  !--Initialisation of others variables
     590              :  !--In non-loc-psp case: calculate the position of ions and conversion factor
     591           11 :  if(nlpsp) then
     592            0 :    do ii = 1,natom
     593            0 :      xcart(:,ii) = matmul(rprimd(:,:),xred(:,ii))
     594              :    end do
     595            0 :    metrec%gcart(:,:) = per_cond(natom,xcart,ngfft(1:3),metrec%tr(:))
     596            0 :    if(debug) then
     597            0 :      do ii=1,natom
     598            0 :        write (msg,'(a,3f8.2)')'xcart=',xcart(:,ii)
     599            0 :        call wrtout(std_out,msg,'COLL')
     600            0 :        write (msg,'(a,3i4)')'gcart=',metrec%gcart(:,ii)
     601            0 :        call wrtout(std_out,msg,'COLL')
     602              :      end do
     603              :    end if
     604              :  end if
     605              : 
     606           11 : end subroutine Init_MetricRec
     607              : !!***
     608              : 
     609              : !!****f* m_rec/Init_nlpspRec
     610              : !! NAME
     611              : !! Init_nlpspRec
     612              : !!
     613              : !! FUNCTION
     614              : !! Initialise the rset<recursion_type>=Data type concerning recursion.
     615              : !! In particular, the non-local part of pseudo-potential.
     616              : !!
     617              : !! INPUTS
     618              : !! tempe=temperature
     619              : !! psps <type(pseudopotential_type)>=variables related to pseudo-potentials
     620              : !! metrec <type(metricrec_type)>=infinitesimal metrics used in recursion
     621              : !! ngfftrec(18)=Number of Grid points for Fast Fourier Transform for
     622              : !!   Recursion (truncated box, if different from ngfft)
     623              : !! debug=debug variable
     624              : !!
     625              : !! SIDE EFFECTS
     626              : !! nlrec <type(nlpsprec_type)>=pseudo-potentials information for recursion
     627              : !!
     628              : !! SOURCE
     629              : 
     630            6 : subroutine Init_nlpspRec(tempe,psps,nlrec,metrec,ngfftrec,debug)
     631              : 
     632              : !Arguments ------------------------------------
     633              : ! scalars
     634              :  logical,intent(in) :: debug
     635              :  real(dp), intent(in) :: tempe
     636              :  type(pseudopotential_type),intent(in) ::psps
     637              :  type(metricrec_type),intent(inout) :: metrec
     638              :  type(nlpsprec_type),intent(inout) :: nlrec
     639              : ! arrays
     640              :  integer,intent(in) :: ngfftrec(18)
     641              : !Local ---------------------------
     642              :  integer :: ii,jj
     643              :  character(500) :: msg
     644              : ! *********************************************************************
     645              :  !!--Routine for the calcul of the non-local pseudo
     646           12 :  if(any(psps%pspcod/=3) .and. nlrec%nlpsp ) then
     647            0 :    msg = "The non-local part of psp is used in Recursion only for hgh-psp"
     648            0 :    ABI_WARNING(msg)
     649            0 :    nlrec%nlpsp = .False.
     650            0 :    if (allocated(metrec%gcart))  then
     651            0 :      ABI_FREE(metrec%gcart)
     652              :    end if
     653              :  end if
     654              : 
     655            6 :  if(any(psps%pspcod==3) .and.  nlrec%nlpsp) then
     656              : 
     657            0 :   nlrec%nlpsp = .True.
     658            0 :   nlrec%npsp  = psps%npsp
     659            0 :   nlrec%lmnmax = count(psps%indlmn(3,:,psps%npsp)/=0)
     660            0 :   ABI_MALLOC(nlrec%mat_exp_psp_nl,(3,3,psps%mpsang,psps%npsp))
     661            0 :   ABI_MALLOC(nlrec%eival,(3,psps%mpsang,psps%npsp))
     662            0 :   ABI_MALLOC(nlrec%eivec,(3,3,psps%mpsang,psps%npsp))
     663            0 :   ABI_MALLOC(nlrec%pspinfo,(psps%mpsang,psps%npsp))
     664            0 :   ABI_MALLOC(nlrec%radii,(psps%mpsang,psps%npsp))
     665            0 :   ABI_MALLOC(nlrec%indlmn,(6,nlrec%lmnmax,psps%npsp))
     666            0 :   nlrec%indlmn(:,:,:) = psps%indlmn(:,:nlrec%lmnmax,:)
     667            0 :   nlrec%mat_exp_psp_nl(:,:,:,:) = zero
     668            0 :   nlrec%eivec(:,:,:,:) = zero
     669            0 :   nlrec%eival(:,:,:) = zero
     670            0 :   nlrec%radii(:,:) = zero
     671            0 :   nlrec%pspinfo(:,:) = 0
     672              : 
     673              :   !--Get the exponential of the strength times the projectors overlap
     674              :   !  of the non-local part of psp(hgh):
     675              :   !  h_ij=strength; g_ij=ovelap => (exp(-h.g/temp/4p)-Identity).g^(-1)
     676              :   !  And the diagonalisation of the projectors and associated eigenvectors
     677            0 :   call pspnl_hgh_rec(psps,tempe,nlrec,debug)
     678              : 
     679            0 :   if(debug)then
     680            0 :    do jj=1,psps%npsp
     681            0 :     write(msg,'(a)')' Exponential matrices:'
     682            0 :     call wrtout(std_out,msg,'COLL')
     683            0 :     do ii=1,psps%mpsang
     684              :      write(msg,'(a,i2,a,3f15.10,a,3f15.10,a,3f15.10)')&
     685            0 :        &   'angular moment',ii-1,ch10,&
     686            0 :        &                    nlrec%mat_exp_psp_nl(1,:,ii,jj),ch10,&
     687            0 :        &                    nlrec%mat_exp_psp_nl(2,:,ii,jj),ch10,&
     688            0 :        &                    nlrec%mat_exp_psp_nl(3,:,ii,jj)
     689            0 :      call wrtout(std_out,msg,'COLL')
     690              :     end do
     691              :    end do
     692              :   end if
     693              : 
     694              :   !--Now it calculates the matrix of the exp(V_NL)
     695            0 :   call pspnl_operat_rec(nlrec,metrec,ngfftrec,debug)
     696              : 
     697              :  else !--Only local pseudo potentials
     698            6 :   nlrec%nlpsp = .False.
     699            6 :   nlrec%npsp  = psps%npsp
     700            6 :   ABI_MALLOC(nlrec%mat_exp_psp_nl,(0,0,0,0))
     701            6 :   ABI_MALLOC(nlrec%pspinfo,(0,0))
     702            6 :   ABI_MALLOC(nlrec%radii,(0,0))
     703            6 :   ABI_MALLOC(nlrec%indlmn,(0,0,0))
     704            6 :   ABI_MALLOC(nlrec%projec,(0,0,0))
     705              :  endif
     706              : 
     707            6 : end subroutine Init_nlpspRec
     708              : !!***
     709              : 
     710              : !!****f* m_rec/CleanRec
     711              : !! NAME
     712              : !! CleanRec
     713              : !!
     714              : !! FUNCTION
     715              : !! Deallocate the pointers of rset<recursion_type>=Data type concerning recursion.
     716              : !!
     717              : !! INPUTS
     718              : !! rset<recursion_type>=Data type concerning recursion
     719              : !!
     720              : !! SIDE EFFECTS
     721              : !! All pointers are deallocated.
     722              : !!
     723              : !! SOURCE
     724              : 
     725            6 : subroutine CleanRec(rset)
     726              : 
     727              : !Arguments ------------------------------------
     728              : ! scalars
     729              :  type(recursion_type),intent(inout) :: rset
     730              : ! arrays
     731              : ! *********************************************************************
     732              : 
     733              :  ! @recursion_type
     734              : 
     735            6 :   ABI_SFREE(rset%ZT_p)
     736            6 :   ABI_SFREE(rset%par%displs)
     737            6 :   ABI_SFREE(rset%par%vcount)
     738            6 :   ABI_SFREE(rset%nl%mat_exp_psp_nl)
     739            6 :   ABI_SFREE(rset%nl%eival)
     740            6 :   ABI_SFREE(rset%nl%eivec)
     741            6 :   ABI_SFREE(rset%nl%pspinfo)
     742            6 :   ABI_SFREE(rset%nl%radii)
     743            6 :   ABI_SFREE(rset%nl%indlmn)
     744            6 :   ABI_SFREE(rset%nl%projec)
     745            6 :   ABI_SFREE(rset%inf%gcart)
     746              : 
     747            6 :  call pawfgr_destroy(rset%pawfgr)
     748              : 
     749              :  ! No is needed deallocate rset%mpi: it is a copy of mpi_enreg which
     750              :  ! pointers are deallocated in gstate
     751              : 
     752              : #ifdef HAVE_GPU_CUDA
     753              :   call CleanRecGPU(rset%GPU,rset%load)
     754              : #endif
     755              : 
     756            6 : end subroutine CleanRec
     757              : !!***
     758              : 
     759              : !!****f* m_rec/Calcnrec
     760              : !! NAME
     761              : !! Calcnrec
     762              : !!
     763              : !! FUNCTION
     764              : !! Calculate the new min_nrec.
     765              : !!
     766              : !! INPUTS
     767              : !! rset<recursion_type>=Data type concerning recursion
     768              : !! b2(:,:) recursion coefficients
     769              : !!
     770              : !! OUTPUT
     771              : !! rset%min_nrec is changed
     772              : !!
     773              : !! SOURCE
     774              : 
     775           12 : subroutine Calcnrec(rset,b2)
     776              : 
     777              :  !Arguments ------------------------------------
     778              :  ! scalars
     779              :  type(recursion_type),intent(inout) :: rset
     780              :  ! arrays
     781              :  real(dp), intent(in):: b2(0:rset%min_nrec,1:rset%par%ntranche)
     782              :  !Local ----------------------------------------
     783              :  ! scalars
     784              :  integer :: kk,ii,jj,ierr,loc_nrec
     785              :  character(len=500) :: msg
     786              :  ! *********************************************************************
     787              :  ! @recursion_type
     788              :  ! @pawfgr_type
     789            6 :  kk = 1
     790            6 :  loc_nrec = rset%min_nrec
     791         5190 :  do ii=1,rset%par%ntranche
     792              :   !--Use to lbound because b2 passed as argument
     793              :   !  doesn't have the same bounds as in the calling
     794              :   !  subroutine, the +1 because b2(lbound,ii)=1.
     795        10368 :   jj = lbound(b2,dim=1)+1
     796        23631 :   do while (b2(jj,ii)>tol10 .and.  jj<=rset%min_nrec-1)
     797        18441 :    jj = jj+1
     798        23625 :    kk = max(jj,kk)
     799              :   end do
     800              :  enddo
     801            6 :  call xmpi_max(kk,rset%min_nrec,rset%mpi%comm_bandfft,ierr)
     802            6 :  rset%min_nrec = rset%min_nrec+1-lbound(b2,dim=1)
     803              : 
     804            6 :  write(msg,'(a,i2.2,a9,i2.2)') ' -- nrec adjustement   nrec=',loc_nrec,' => nrec=',rset%min_nrec
     805            6 :  call wrtout(std_out,msg,'COLL')
     806          306 :  write(msg,'(51a)')' ',('-',ii=1,50)
     807            6 :  call wrtout(std_out,msg,'COLL')
     808              : 
     809            6 : end subroutine Calcnrec
     810              : !!***
     811              : 
     812              : !!****f* ABINIT/getngrec
     813              : !! NAME
     814              : !! getngrec
     815              : !!
     816              : !! FUNCTION
     817              : !! This routine computes the fft box for the recursion method, accordingly to the troncation radius.
     818              : !! It is quite similar to getng, but :
     819              : !!     - there is no xboxcut and ecut consistency
     820              : !!     - ngfft (the initial fft box) is the maximum fft box
     821              : !!
     822              : !! INPUTS
     823              : !!  ngfft(18)=non truncated fft box
     824              : !!  mgfft=maximum of ngfft(1:3)
     825              : !!  inf_rmet=define the infinitesimal metric : rprimd*(transpose(rprimd)), divided by the number of discretisation point
     826              : !!  recrcut=truncating
     827              : !!  delta=to obtain radius of truncation
     828              : !!
     829              : !! OUTPUT
     830              : !!  ngfftrec=truncated fft box
     831              : !!  nfftrec= truncated nfft
     832              : !!  tronc=True if truncation is made
     833              : !!
     834              : !! SIDE EFFECTS
     835              : !!
     836              : !! SOURCE
     837              : 
     838            6 : subroutine getngrec(ngfft,rmet,ngfftrec,nfftrec,recrcut,delta,tronc)
     839              : 
     840              : !Arguments -------------------------------
     841              : !scalars
     842              : real(dp),intent(in) :: recrcut,delta
     843              : integer,intent(out) :: nfftrec
     844              : logical,intent(out) :: tronc
     845              : !arrays
     846              : integer,intent(in)  :: ngfft(18)
     847              : real(dp),intent(in) :: rmet(3,3)
     848              : integer,intent(out) :: ngfftrec(18)
     849              : 
     850              : !Local variables-------------------------------
     851              : !scalars
     852              : integer :: ii,iimin,index,jj,jjmin,kk,kkmin,largest_ngfftrec,maxpow11,maxpow2
     853              : integer :: maxpow3,maxpow5,maxpow7,mmsrch,plane
     854              : real(dp) :: dsm,dsp,dsqmin,rtroncat
     855              : !arrays
     856              : integer :: get_ngfftrec(3),maxsrch(3),minsrch(3)
     857            6 : integer,allocatable :: iperm(:),srch(:)
     858              : real(dp) :: tsec(2)
     859              : real(dp) :: inf_rmet(3,3)
     860              : ! *************************************************************************
     861              : 
     862            6 :  call timab(602,1,tsec)
     863              : 
     864            6 :  ngfftrec(:) = ngfft(:)
     865              : 
     866            6 :  if (recrcut>tol14) then  !default value dtset%recrcut = zero means no troncation
     867            1 :    rtroncat = recrcut+delta
     868            4 :    get_ngfftrec(:)=1
     869            1 :    plane = 1
     870              : 
     871            4 :    do ii=1,3
     872           13 :      inf_rmet(ii,:) = rmet(ii,:)/(real(ngfft(1:3)*ngfft(ii),dp))
     873              :    end do
     874              : 
     875              : 
     876              : !  minimum value of ngfftrec
     877            4 :    do ii = 1,3
     878            3 :      ngfftrec(ii)=floor(2*rtroncat/sqrt(inf_rmet(ii,ii)))+1  !minimum value
     879            4 :      if(ngfftrec(ii)>=ngfft(ii))then
     880            0 :        ngfftrec(ii)=ngfft(ii)
     881            0 :        get_ngfftrec(ii)=0
     882              :      end if
     883              :    end do
     884              : 
     885              : 
     886            4 :    if(sum(get_ngfftrec)/=0)then
     887            4 :      largest_ngfftrec=maxval(ngfft(1:3))
     888            1 :      maxpow2=int(log(largest_ngfftrec+0.5d0)/log(two))
     889            1 :      maxpow3=int(log(largest_ngfftrec+0.5d0)/log(three))
     890            1 :      maxpow5=int(log(largest_ngfftrec+0.5d0)/log(five))
     891            1 :      maxpow7=0
     892            1 :      maxpow11=0
     893            1 :      mmsrch=(maxpow2+1)*(maxpow3+1)*(maxpow5+1)*(maxpow7+1)*(maxpow11+1)
     894            3 :      ABI_MALLOC(srch,(mmsrch))
     895            2 :      ABI_MALLOC(iperm,(mmsrch))
     896              : !    Factors of 2
     897            1 :      srch(1)=1
     898            4 :      do ii=1,maxpow2
     899            4 :        srch(ii+1)=srch(ii)*2
     900              :      end do
     901              : !    Factors of 3
     902            1 :      index=maxpow2+1
     903            1 :      if(maxpow3>0)then
     904            3 :        do ii=1,maxpow3
     905           19 :          srch(1+ii*index:(ii+1)*index)=3*srch(1+(ii-1)*index:ii*index)
     906              :        end do
     907              :      end if
     908              : !    Factors of 5
     909            1 :      index=(maxpow3+1)*index
     910            1 :      if(maxpow5>0)then
     911            2 :        do ii=1,maxpow5
     912           26 :          srch(1+ii*index:(ii+1)*index)=5*srch(1+(ii-1)*index:ii*index)
     913              :        end do
     914              :      end if
     915              : !    Factors of 7
     916              :      index=(maxpow5+1)*index
     917              :      if(maxpow7>0)then
     918              :        do ii=1,maxpow7
     919              :          srch(1+ii*index:(ii+1)*index)=7*srch(1+(ii-1)*index:ii*index)
     920              :        end do
     921              :      end if
     922              : !    Factors of 11
     923            1 :      index=(maxpow7+1)*index
     924              :      if(maxpow11>0)then
     925              :        do ii=1,maxpow11
     926              :          srch(1+ii*index:(ii+1)*index)=11*srch(1+(ii-1)*index:ii*index)
     927              :        end do
     928              :      end if
     929              : !    srch is the set of allowed ngfftrec values
     930              : 
     931            1 :      call sort_int(mmsrch,srch,iperm)
     932            1 :      ABI_FREE(iperm)
     933              : 
     934            4 :      do ii=1,3
     935            3 :        if(get_ngfftrec(ii)==1)then
     936           12 :          do jj=1,mmsrch
     937           12 :            if(srch(jj)>=ngfftrec(ii))then
     938            3 :              minsrch(ii)=jj
     939            3 :              ngfftrec(ii)=srch(jj)
     940            3 :              exit
     941              :            end if
     942              :          end do
     943           24 :          do jj=minsrch(ii),mmsrch
     944           24 :            if(srch(jj)>ngfft(ii))then
     945              : !            since ngfftrec(ii)<ngfft(ii) for get_ngfftrec(ii)==1,
     946              : !            and srch(mmsrch)maxval(ngfft(1:3)),
     947              : !            that will appens in the range minsrch(ii),mmsrch
     948            3 :              maxsrch(ii)=jj-1
     949            3 :              exit
     950              :            end if
     951              :          end do
     952              :        end if
     953              : !      since ngfft(ii) is in srch, we have here srch(maxsrch(ii))=ngfft(ii)
     954              : !      minsrch(ii), maxsrch(ii) is the range of index of srch in which we can
     955              : !      search ngfftrec(ii)
     956              : 
     957            4 :        if(ngfftrec(ii)>=ngfft(ii))then
     958            0 :          ngfftrec(ii)=ngfft(ii)
     959            0 :          get_ngfftrec(ii)=0
     960              :        end if
     961              :      end do
     962              :    end if
     963              : 
     964              : !  verify that the entiere truncation sphere is in the fft box ;
     965              : !  but only in the dimension in which we do not consider the entiere fft box
     966            4 :    do while(sum(get_ngfftrec)/=0)  !again...
     967              : 
     968              : !    determining the minimum distance between 0 and the boundary
     969              : !    of the fft box
     970              : !    quite similar to the subroutine "bound", but only over the plane which
     971              : !    are not the whole fft box
     972            1 :      dsqmin=dsq_rec(ngfftrec(1)/2,-ngfftrec(2)/2,-ngfftrec(3)/2,inf_rmet)+0.01d0
     973              : 
     974            1 :      if(get_ngfftrec(1)/=0)then
     975              : !      look at +/- g1 planes:
     976            6 :        do jj=-ngfftrec(2)/2,ngfftrec(2)/2
     977           31 :          do kk=-ngfftrec(3)/2,ngfftrec(3)/2
     978           25 :            dsp = dsq_rec(ngfftrec(1)/2, jj, kk,inf_rmet)
     979           25 :            dsm = dsq_rec( - ngfftrec(1)/2, jj, kk,inf_rmet)
     980           25 :            if (dsp<dsqmin) then
     981            6 :              dsqmin = dsp
     982            6 :              iimin = ngfftrec(1)/2
     983            6 :              jjmin = jj
     984            6 :              kkmin = kk
     985            6 :              plane=1
     986              :            end if
     987           30 :            if (dsm<dsqmin) then
     988            0 :              dsqmin = dsm
     989            0 :              iimin =  - ngfftrec(1)/2
     990            0 :              jjmin = jj
     991            0 :              kkmin = kk
     992            0 :              plane=1
     993              :            end if
     994              :          end do
     995              :        end do
     996              :      end if
     997              : 
     998            1 :      if(get_ngfftrec(2)/=0)then
     999              : !      +/- g2 planes:
    1000            6 :        do ii=-ngfftrec(1)/2,ngfftrec(1)/2
    1001           31 :          do kk=-ngfftrec(3)/2,ngfftrec(3)/2
    1002           25 :            dsp = dsq_rec(ii,ngfftrec(2)/2,kk,inf_rmet)
    1003           25 :            dsm = dsq_rec(ii,-ngfftrec(2)/2,kk,inf_rmet)
    1004           25 :            if (dsp<dsqmin) then
    1005            0 :              dsqmin = dsp
    1006            0 :              iimin = ii
    1007            0 :              jjmin = ngfftrec(2)/2
    1008            0 :              kkmin = kk
    1009            0 :              plane=2
    1010              :            end if
    1011           30 :            if (dsm<dsqmin) then
    1012            0 :              dsqmin = dsm
    1013            0 :              iimin = ii
    1014            0 :              jjmin =  - ngfftrec(2)/2
    1015            0 :              kkmin = kk
    1016            0 :              plane=2
    1017              :            end if
    1018              :          end do
    1019              :        end do
    1020              :      end if
    1021              : 
    1022            1 :      if(get_ngfftrec(3)/=0)then
    1023              : !      +/- g3 planes:
    1024            6 :        do ii=-ngfftrec(1)/2,ngfftrec(1)/2
    1025           31 :          do jj=-ngfftrec(2)/2,ngfftrec(2)/2
    1026           25 :            dsp = dsq_rec(ii,jj,ngfftrec(3)/2,inf_rmet)
    1027           25 :            dsm = dsq_rec(ii,jj,-ngfftrec(3)/2,inf_rmet)
    1028           25 :            if (dsp<dsqmin) then
    1029            0 :              dsqmin = dsp
    1030            0 :              iimin = ii
    1031            0 :              jjmin = jj
    1032            0 :              kkmin = ngfftrec(3)/2
    1033            0 :              plane=3
    1034              :            end if
    1035           30 :            if (dsm<dsqmin) then
    1036            0 :              dsqmin = dsm
    1037            0 :              iimin = ii
    1038            0 :              jjmin = jj
    1039            0 :              kkmin =  - ngfftrec(3)/2
    1040            0 :              plane=3
    1041              :            end if
    1042              :          end do
    1043              :        end do
    1044              :      end if
    1045              : 
    1046            1 :      if(dsqmin>=rtroncat)then
    1047              :        get_ngfftrec=0
    1048              :        exit
    1049              :      end if
    1050              : 
    1051              : !    Fix nearest boundary
    1052            0 :      do ii=minsrch(plane),maxsrch(plane)
    1053            0 :        if (srch(ii)>=ngfftrec(plane)) then
    1054              : !        redefine ngfft(plane) to next higher choice
    1055            0 :          ngfftrec(plane)=srch(ii+1)
    1056              : !        verify if we cover the whole box
    1057            0 :          if(ngfftrec(plane)>=ngfft(plane))then
    1058            0 :            ngfftrec(plane)=ngfft(plane)
    1059            0 :            get_ngfftrec(plane)=0
    1060              :          end if
    1061              : !        Exit the loop over ii
    1062              :          exit
    1063              :        end if
    1064              :      end do
    1065              : 
    1066              :    end do
    1067              : 
    1068            1 :    if (allocated(srch)) then
    1069            1 :      ABI_FREE(srch)
    1070              :    end if
    1071              : 
    1072              : !  if(mod(ngfftrec(1),16)/=0) then
    1073              : !  ngfftrec(1) = ngfftrec(1)+(16-mod(ngfftrec(1),16))
    1074              : !  ngfftrec(2:3) = ngfftrec(1)
    1075              : !  endif
    1076              : 
    1077            1 :    ngfftrec(4)=2*(ngfftrec(1)/2)+1
    1078            1 :    ngfftrec(5)=2*(ngfftrec(2)/2)+1
    1079            1 :    ngfftrec(6)=ngfftrec(3)
    1080              : 
    1081              : !  --algorithm
    1082            1 :    ngfftrec(7)=ngfft(7)   ! to be improved for a better non-parallel algorithm - here it is automatically 401
    1083            1 :    ngfftrec(8)=ngfft(8)
    1084              : 
    1085              :  end if
    1086              : 
    1087              : !--For now, recursion method doesn't use paralelism on FFT - which would require a great number of processors
    1088           24 :  nfftrec = product(ngfftrec(1:3))
    1089           24 :  ngfftrec(9:11) = (/0,1,0/)   !--(/ paral, nproc, %me \)
    1090           18 :  ngfftrec(12:13) = ngfftrec(2:3)   ! n2proc ! n3proc
    1091              : 
    1092            9 :  tronc  = all(ngfftrec(:3)/=ngfft(:3))
    1093            6 :  call timab(602,2,tsec)
    1094              : 
    1095              :  contains
    1096              : 
    1097          151 :    function dsq_rec(ii,jj,kk,inf_rmet)
    1098              : 
    1099              :    real(dp) :: dsq_rec
    1100              :    integer,intent(in) :: ii,jj,kk
    1101              :    real(dp),intent(in) :: inf_rmet(3,3)
    1102              :    dsq_rec=sqrt(&
    1103              : &   inf_rmet(1,1)*dble(ii**2)&
    1104              : &   +inf_rmet(2,2)*dble(jj**2)&
    1105              : &   +inf_rmet(3,3)*dble(kk**2)&
    1106              : &   +two*(inf_rmet(1,2)*dble(ii*jj)&
    1107              : &   +inf_rmet(2,3)*dble(jj*kk)&
    1108          151 : &   +inf_rmet(3,1)*dble(kk*ii)))
    1109          151 :  end function dsq_rec
    1110              : 
    1111              : 
    1112              : end subroutine getngrec
    1113              : !!***
    1114              : 
    1115              : !!****f* ABINIT/pspnl_operat_rec
    1116              : !! NAME
    1117              : !! pspnl_operat_rec
    1118              : !!
    1119              : !! FUNCTION
    1120              : !! It calculates the non-local projectors used in recursion for any psp non-local:
    1121              : !! The nl interaction in recursion is $$exp{-V_{NL}/beta}=\sum_A\sum_{lm}
    1122              : !! \sum{ij}Y_{lm}(\hat{r-R_A}')f^l_i(r-R_A)D^l_{i,j}Y_{lm}(\hat{r-R_A})f^l_j{r-R_A}$$
    1123              : !! where $D^_{i,j}$ is a matrix  previously (see pspnl_operat_rec).
    1124              : !! In this routine  the projectors $Y_{lm}(\hat{r-R_A}')f^l_i(r-R_A)$
    1125              : !! are calculated. So an array of dimensions
    1126              : !! rset%nl%projec(nfftrec,lmnmax,nlrec%npsp)
    1127              : !!
    1128              : !! INPUTS
    1129              : !! metrec<metricrec_type>=contains information concerning metric in
    1130              : !!         recursion: grid_step, metric, infinitesimal volume
    1131              : !! ngfftrec(18)=is the ngfft grid (truncated if different from ngfft) of recursion
    1132              : !! debug=debug variable
    1133              : !!
    1134              : !!
    1135              : !! OUTPUT
    1136              : !! nlrec<nlpsprec_type>%projec= array containig the projectors on the real grid
    1137              : !! nlrec<nlpsprec_type>%intlen= integer linear size of the non-local grid
    1138              : !!
    1139              : !! SIDE EFFECTS
    1140              : !! nlrec<nlpsprec_type> data set of non-local pseudo for recursion
    1141              : !! The better Interaction length (Intlen) is also calculated and printed but
    1142              : !! recursion use intlen=ngfftrec/2
    1143              : !!
    1144              : !! NOTES
    1145              : !!
    1146              : !! SOURCE
    1147              : 
    1148              : 
    1149            0 : subroutine pspnl_operat_rec(nlrec,metrec,ngfftrec,debug)
    1150              : 
    1151              : !Arguments ------------------------------------
    1152              : !scalars
    1153              :  logical,intent(in) :: debug
    1154              :  type(metricrec_type),intent(in) ::metrec
    1155              :  type(nlpsprec_type),intent(inout) :: nlrec
    1156              : !arrays
    1157              :  integer,intent(in) :: ngfftrec(18)
    1158              : !Local variables-------------------------------
    1159              :  integer :: ii,intlen
    1160              :  integer :: iangol,ipsp,iproj
    1161              :  integer :: mpsang,jj,kk,rr
    1162              :  integer :: nfftrec
    1163              :  integer :: ilmn,il,ilm,in,lmnmax
    1164              :  real(dp) :: raggio,rloc,denom,step
    1165              :  real(dp) :: delta_out,partial,err
    1166              :  character(len=500) :: msg
    1167              :  real(dp) :: part_sum(3)
    1168              :  real(dp) :: ylmr_gr_dm(0,0,0)
    1169            0 :  real(dp),allocatable :: ylmr(:,:),proj_arr(:,:,:)
    1170            0 :  real(dp),allocatable :: radloc(:,:),nrm(:)
    1171              : 
    1172              : ! *************************************************************************
    1173              : 
    1174            0 :  if(debug)then
    1175            0 :    write(msg,'(80a,a,a)') ('=',ii=1,80),ch10,' pspnl_operat_rec : enter '
    1176            0 :    call wrtout(std_out,msg,'PERS')
    1177              :  end if
    1178              : 
    1179              : !#####################################################################
    1180              : !--CALCULATE THE (SEMI-)MAXIMUM INTERVAL WHERE ALL THE PROJECTORS ARE
    1181              : !DIFFERENT TO ZERO.
    1182              : !--For any pseudo potential:
    1183            0 :  delta_out = zero
    1184            0 :  step = metrec%tr(1)*half !--Scanning step= grid step/2
    1185              : 
    1186              : 
    1187            0 :  do ipsp = 1, nlrec%npsp !--Loop on the pseudos
    1188              : 
    1189              : !  --For any angular moment:
    1190            0 :    do iangol = 0,maxval(nlrec%indlmn(1,:,ipsp)) !--Loop on the angular moment
    1191            0 :      rloc = nlrec%radii(iangol+1,ipsp) !--Local radius
    1192              : 
    1193              : !    --For any projector
    1194            0 :      do iproj = 1,nlrec%pspinfo(iangol+1,ipsp)
    1195              : !      --Starting point to searching when the projector goes to zero.
    1196              : !      this correspond to twice the radius wher the projector has its maximum
    1197            0 :        raggio = two*sqrt(real(-2+2*iproj+iangol,dp))*rloc
    1198              : !      --Caculate the gamma func at the denominator
    1199            0 :        call gamma_function(real(iangol+2*iproj,dp)-half,denom)
    1200              : !      --Find the zero
    1201              : !      --The following while cycle should be replaced by a bisection
    1202              : !      --method. Bucause this is calculated only 1 time it is not very
    1203              : !      important.
    1204            0 :        err = one
    1205            0 :        ii=0
    1206              : !      tolloc = 1.d0*abs(minval(nlrec%mat_exp_psp_nl(:nlrec%pspinfo(iangol+1,ipsp),:nlrec%pspinfo(iangol+1,ipsp),iangol+1,ipsp)))
    1207            0 :        do while(abs(err)>1.d-2)
    1208            0 :          raggio = raggio + step
    1209            0 :          err = project_prec(raggio,iproj,iangol,rloc)/sqrt(denom)
    1210            0 :          ii = ii+1
    1211              :        end do
    1212            0 :        write(std_out,*)'local delta',raggio,ii
    1213            0 :        delta_out=maxval((/ delta_out,raggio /))
    1214              :      end do !end loop on projectors
    1215              : 
    1216              :    end do !enddo on angular moment
    1217              :  end do !enddo on pseudos
    1218              : 
    1219              : !--CALCULATE how many grid steps correspond to delta_out
    1220            0 :  intlen = int(delta_out/metrec%tr(1))
    1221              : !--I want that intlen is odd
    1222            0 :  if(mod(intlen,2)==0) intlen = intlen+1
    1223              : 
    1224            0 :  write(msg,'(2a,i3,a)') ch10,' Interac. length of non-local psp(grid steps)=',intlen,ch10
    1225            0 :  call wrtout(std_out,msg,'COLL')
    1226              : !#####################################################################
    1227              : 
    1228              : !--Initialisation
    1229            0 :  nfftrec = product(ngfftrec(1:3))
    1230            0 :  lmnmax = nlrec%lmnmax
    1231            0 :  intlen = ngfftrec(1)/2
    1232            0 :  nlrec%intlen = intlen !--Setted in recursion variables
    1233              : 
    1234              : !#####################################################################
    1235              : !--CALCULATE E(q,q')
    1236              : !--Cration of the exponential*projectors*ylm matrix
    1237              : 
    1238              : !--Initialisation
    1239            0 :  ABI_MALLOC(nlrec%projec,(nfftrec,lmnmax,nlrec%npsp))
    1240            0 :  nlrec%projec = zero
    1241            0 :  ABI_MALLOC(radloc,(3,nfftrec))
    1242            0 :  radloc = zero
    1243            0 :  ABI_MALLOC(nrm,(nfftrec))
    1244            0 :  nrm = zero
    1245              : 
    1246              : !--Loop on pseudo types
    1247            0 :  pseudodo: do ipsp = 1, nlrec%npsp
    1248              : !  --Control if the psp is non-local, else continue
    1249            0 :    if(all(nlrec%pspinfo(:,ipsp)==0)) cycle
    1250              : !  --Vector which stores localy the upper part of symmetrical
    1251              : !  matrix of the exponential of the non-local operator
    1252            0 :    mpsang = maxval(nlrec%indlmn(1,:,ipsp))+1
    1253            0 :    ABI_MALLOC(proj_arr,(nfftrec,maxval(nlrec%pspinfo(:,ipsp)),mpsang))
    1254            0 :    ABI_MALLOC(ylmr,(mpsang*mpsang,nfftrec))
    1255            0 :    proj_arr = zero
    1256            0 :    ylmr = zero
    1257              : 
    1258              : !  !debug
    1259              : !  write(std_out,*)'mpsang,proj num',mpsang,maxval(nlrec%pspinfo(:,ipsp))
    1260              : !  !enddebug
    1261              : 
    1262              : !  --Calculate the projctors
    1263            0 :    do iangol = 0,mpsang-1
    1264            0 :      rloc = nlrec%radii(iangol+1,ipsp)
    1265            0 :      do iproj = 1,nlrec%pspinfo(iangol+1,ipsp)
    1266            0 :        call gamma_function(real(iangol+2*iproj,dp)-half,denom)
    1267            0 :        denom = one/sqrt(denom)
    1268            0 :        do ii = 0,ngfftrec(1)-1 !--3-loop on coordinates
    1269            0 :          do jj = 0,ngfftrec(2)-1
    1270            0 :            do kk = 0,ngfftrec(3)-1
    1271              : !            --Calculate the radii
    1272            0 :              part_sum(:) = real((/ ii,jj,kk /)-intlen,dp)*(metrec%tr)
    1273            0 :              rr = 1+ii+(jj+kk*ngfftrec(2))*ngfftrec(3)
    1274            0 :              radloc(:,rr) = part_sum
    1275            0 :              nrm(rr) = sqrt(sum(part_sum(:)**two))
    1276            0 :              partial = project_prec(nrm(rr),iproj,iangol,rloc)*denom
    1277            0 :              if(abs(partial)>tol12 ) proj_arr(rr,iproj,iangol+1) = partial
    1278              :            end do
    1279              :          end do
    1280              :        end do  !--End 3-loop on coordinates
    1281              :      end do
    1282              :    end do
    1283              : 
    1284              : 
    1285              : !  -------------------------------------------------------------
    1286              : !  --Calculate the spherical harmonics (Verified: it works well)
    1287            0 :    call initylmr(mpsang,1,nfftrec,nrm(:),1,radloc(:,:),ylmr(:,:),ylmr_gr_dm)
    1288              : !  -------------------------------------------------------------
    1289              : 
    1290              : 
    1291            0 :    do ilmn = 1,lmnmax
    1292            0 :      ilm = nlrec%indlmn(4,ilmn,ipsp)
    1293            0 :      il = nlrec%indlmn(1,ilmn,ipsp)+1
    1294            0 :      in = nlrec%indlmn(3,ilmn,ipsp)
    1295            0 :      write(msg,'(2a,i3,2i2)')ch10,'lm,l,n',ilm,il,in
    1296            0 :      call wrtout(std_out,msg,'COLL')
    1297              : 
    1298            0 :      nlrec%projec(:,ilmn,ipsp) = ylmr(ilm,:)*proj_arr(:,in,il)
    1299              :    end do
    1300              : 
    1301            0 :    ABI_FREE(ylmr)
    1302            0 :    ABI_FREE(proj_arr)
    1303              :  end do pseudodo !--end loop on pseudo types
    1304              : 
    1305              : 
    1306            0 :  ABI_FREE(radloc)
    1307            0 :  ABI_FREE(nrm)
    1308              : 
    1309            0 :  if(debug)then
    1310            0 :    write(msg,'(80a,a,a)') ('=',ii=1,80),ch10,' pspnl_operat_rec : exit '
    1311            0 :    call wrtout(std_out,msg,'PERS')
    1312              :  end if
    1313              : 
    1314              :  contains
    1315              : 
    1316            0 :    function project_prec(raggio,iproj,iangol,rloc)
    1317              : !--Analytical expression of the projectors in hgh-pspeudopotential
    1318              : !--The gamma function at denominator is missing
    1319              :    real(dp) :: project_prec
    1320              :    integer,intent(in) :: iproj,iangol
    1321              :    real(dp),intent(in) :: raggio,rloc
    1322              : 
    1323              :    project_prec=sqrt2*(raggio/rloc)**real((iangol+2*(iproj-1)),dp)*&
    1324            0 : &   exp(-((raggio/rloc)**two)*half)/rloc**onehalf
    1325            0 :  end function project_prec
    1326              : 
    1327              : end subroutine pspnl_operat_rec
    1328              : !!***
    1329              : 
    1330              : !!****f* ABINIT/pspnl_hgh_rec
    1331              : !! NAME
    1332              : !! pspnl_hgh_rec
    1333              : !!
    1334              : !! FUNCTION
    1335              : !! This routine computes the matrices S_kk'^{l,A} of the projectors
    1336              : !! (it is the exponential of the overlap matrix). It coorresponds to the matrix:
    1337              : !!   $$\left[(U_l)^{-1}*Exp(-temperature D_l )*U_l* (g_l)^{-1} -Identity\right]_kk'
    1338              : !!   where (U_l)^-1* D_l* U_l = h^lg_l.
    1339              : !! $g_l = <f^l_k|f^l_{k'}>$ is the overlap matrix between projectors
    1340              : !! and $h^l_{kk'}$ is the strength matrix of the projectors.
    1341              : !! It calulates also the strength eigenvalues and eigenvectors of $h$,
    1342              : !! used in the calculus of non-local energy
    1343              : !!
    1344              : !! INPUTS
    1345              : !!  temperature=4*rtrotter/beta=4*rtrotter*tsmear: the effective temp. in  recursion
    1346              : !!  psps <type(pseudopotential_type)>=variables related to pseudo-potentials
    1347              : !!  debug=debug variable
    1348              : !!
    1349              : !! OUTPUT
    1350              : !!
    1351              : !!  nlrec%mat_exp_psp_nl=the matrix of the exponential of the projectors:
    1352              : !!   for any psp, for any angular moment:
    1353              : !!   h_ij=strength; g_ij=ovelap => exp(-h.g/temp/4p).g^(-1)
    1354              : !!  nlrec%radii=Local radii of nl psp
    1355              : !!  nlrec%pspinfo(:,:) for any typat:  (momang,typat)=number of projectors
    1356              : !!  nlrec%eival(:,:,:) for any psp, any momang, the eigenvalues of the
    1357              : !!    strength matrix H: eival(:,mang,psp)
    1358              : !!  nlrec%eivec(:,:,:,:)for any psp, any momang, the eigenvectors of the
    1359              : !!    strength matrix H: eivec(:,:,mang,psp)
    1360              : !!
    1361              : !! SIDE EFFECTS
    1362              : !!
    1363              : !! SOURCE
    1364              : 
    1365            0 : subroutine pspnl_hgh_rec(psps,temperature,nlrec,debug)
    1366              : 
    1367              :  use m_linalg_interfaces
    1368              : 
    1369              : !Arguments -----------------------------------
    1370              : !scalars
    1371              :  real(dp),intent(in) :: temperature
    1372              :  logical,intent(in) :: debug
    1373              :  type(pseudopotential_type),intent(in) :: psps
    1374              :  type(nlpsprec_type),intent(inout) :: nlrec
    1375              : !arrays
    1376              : !Local variables-------------------------------
    1377              : !scalars
    1378              :  integer,parameter :: maxsize=3
    1379              :  integer,parameter :: lwork=(1+32)*maxsize
    1380              :  integer :: iangol,ipseudo,info,nproj
    1381              :  integer :: g_mat_size,ii,nproj2
    1382              :  real(dp) :: denom_1,denom_2,tot_proj
    1383              :  character(len=500) :: msg
    1384              : !arrays
    1385              :  integer :: ipvt(1)
    1386              :  !real(dp) :: rwork(2*maxsize)
    1387              :  real(dp) :: h_mat_init(3,3), rework(lwork)
    1388            0 :  real(dp), allocatable :: g_mat(:,:),h_mat(:,:),eig_val_h(:)
    1389            0 :  real(dp), allocatable :: identity(:,:),inv_g_mat(:,:),u_mat(:,:)
    1390            0 :  complex(dp),allocatable :: hg_mat(:,:)
    1391              : ! *************************************************************************
    1392              : 
    1393            0 :  if(debug)then
    1394            0 :    write(msg,'(80a,a,a)') ('=',ii=1,80),ch10,' pspnl_hgh_rec : enter '
    1395            0 :    call wrtout(std_out,msg,'COLL')
    1396              :  end if
    1397              : 
    1398              : !--For any pseudo potential:
    1399            0 :  do ipseudo = 1, psps%npsp !--Loop on the pseudos
    1400            0 :    write(msg,'(a,80a)')' pseudo file',('-',ii=1,10)
    1401            0 :    call wrtout(std_out,msg,'COLL')
    1402            0 :    write(msg,'(a)') psps%filpsp(ipseudo)
    1403            0 :    call wrtout(std_out,msg,'COLL')
    1404              : 
    1405              : !  --For any angular moment:
    1406            0 :    do iangol = 0,psps%mpsang-1 !--Loop on the angular moment
    1407              : 
    1408              : !    --Local radius
    1409            0 :      nlrec%radii(iangol+1,ipseudo) = psps%gth_params%psppar(iangol+1,0,ipseudo)
    1410              : 
    1411              : !    --Strenghts of non-local projectors  (matrix h)
    1412              : !    --Diagonal part:
    1413            0 :      h_mat_init = zero
    1414            0 :      h_mat_init(1,1) = psps%gth_params%psppar(iangol+1,1,ipseudo)
    1415            0 :      h_mat_init(2,2) = psps%gth_params%psppar(iangol+1,2,ipseudo)
    1416            0 :      h_mat_init(3,3) = psps%gth_params%psppar(iangol+1,3,ipseudo)
    1417              : !    --Out-diagonal part
    1418              : !    --Depending on angular moment the projectors
    1419              : !    strength is calculated differently
    1420            0 :      select case(iangol)
    1421              :      case(0)
    1422            0 :        h_mat_init(1,2) = -half*sqrt(3.d0/5.d0)*h_mat_init(2,2)
    1423            0 :        h_mat_init(1,3) =  half*sqrt(5.d0/21.d0)*h_mat_init(3,3)
    1424            0 :        h_mat_init(2,3) = -half*sqrt(100.d0/63.d0)*h_mat_init(3,3)
    1425              :      case(1)
    1426            0 :        h_mat_init(1,2) = -half*sqrt(5.d0/7.d0)*h_mat_init(2,2)
    1427            0 :        h_mat_init(1,3) =  sixth*sqrt(35.d0/11.d0)*h_mat_init(3,3)
    1428            0 :        h_mat_init(2,3) = -14.d0/six/sqrt(11.d0) *h_mat_init(3,3)
    1429              :      case(2)
    1430            0 :        h_mat_init(1,2) = -half*sqrt(7.d0/9.d0)*h_mat_init(2,2)
    1431            0 :        h_mat_init(1,3) =  half*sqrt(63.d0/143.d0)*h_mat_init(3,3)
    1432            0 :        h_mat_init(2,3) = -nine/sqrt(143.d0)*h_mat_init(3,3)
    1433              :      case(3)
    1434            0 :        h_mat_init(1,2) = zero;  h_mat_init(1,3) = zero;  h_mat_init(2,3) = zero;
    1435              :      case default
    1436            0 :        write(msg,'(a)')' error angular: moment component'
    1437            0 :        call wrtout(std_out,msg,'COLL')
    1438              :      end select
    1439              : 
    1440              : 
    1441              : 
    1442              : !    --Real dimensions of projectors.
    1443            0 :      g_mat_size = count(abs((/ (h_mat_init(ii,ii),ii=1,3) /))>1.d-8)
    1444            0 :      nlrec%pspinfo(iangol+1,ipseudo) = g_mat_size
    1445            0 :      write(msg,'(a,i2,a,i2)')' ang. moment=',iangol,', N projectors=',g_mat_size
    1446            0 :      call wrtout(std_out,msg,'COLL')
    1447            0 :      if (g_mat_size>0) then
    1448              : !      --Identity matrix
    1449            0 :        ABI_MALLOC(identity,(g_mat_size,g_mat_size))
    1450            0 :        call set2unit(identity)
    1451              : !      identity = zero
    1452              : !      identity(:,1) = one
    1453              : !      identity(:,:) = cshift(array=identity,shift=(/ (-ii,ii=0,g_mat_size) /), dim=2 )
    1454              : 
    1455              : 
    1456              : !      ############## CALCULOUS OF THE EIGEN_SPACE OF THE PROJECTORS STRENGTHS ##################
    1457              : !      --Inverse of the matrix h
    1458            0 :        ABI_MALLOC(eig_val_h,(g_mat_size))
    1459            0 :        ABI_MALLOC(u_mat,(g_mat_size,g_mat_size))
    1460              : !      --u-mat will contain the eigenvectors of h_mat_init
    1461            0 :        u_mat = h_mat_init(:g_mat_size,:g_mat_size)
    1462              : 
    1463              : !      write(std_out,*)'hmat_init'
    1464              : !      do ii=1,g_mat_size
    1465              : !      write(std_out,*)h_mat_init(ii,:)
    1466              : !      end do
    1467            0 :        call DSYEV('v','u',g_mat_size,u_mat,g_mat_size,eig_val_h,rework,lwork,info)
    1468              : 
    1469              : !      --THE DIAGONAL MATRIX IS GIVEN BY D=U^t.H.U
    1470              : !      (eival=transpose(eivec).h_mat_init.eivec)
    1471            0 :        write(msg,'(a,3d10.3)')'  eigenvalues=',eig_val_h
    1472            0 :        call wrtout(std_out,msg,'COLL')
    1473              : !      write(std_out,*)'autovec';write(std_out,*)u_mat
    1474              : 
    1475            0 :        nlrec%eival(:g_mat_size,1+iangol,ipseudo) = eig_val_h
    1476            0 :        nlrec%eivec(:g_mat_size,:g_mat_size,1+iangol,ipseudo) = u_mat
    1477            0 :        ABI_FREE(eig_val_h)
    1478            0 :        ABI_FREE(u_mat)
    1479              : 
    1480              : !      ##########END  CALCULOUS OF THE EIGEN_SPACE OF THE PROJECTORS STRENGTHS ##################
    1481              : 
    1482            0 :        ABI_MALLOC(g_mat,(g_mat_size,g_mat_size))
    1483            0 :        ABI_MALLOC(inv_g_mat,(g_mat_size,g_mat_size))
    1484            0 :        ABI_MALLOC(h_mat,(g_mat_size,g_mat_size))
    1485            0 :        ABI_MALLOC(hg_mat,(g_mat_size,g_mat_size))
    1486              : 
    1487            0 :        g_mat(:,:) = one
    1488            0 :        h_mat(:,:) = zero
    1489            0 :        h_mat(:,:) = h_mat_init(:g_mat_size,:g_mat_size)
    1490              : 
    1491              : !      -------------------------------------------------------
    1492              : !      --Matrix  of the overlap between projetors (matrix g)
    1493              : !      and the h matrix of strength
    1494            0 :        do nproj = 1,g_mat_size-1
    1495            0 :          do nproj2 = 1+nproj,g_mat_size
    1496              :            tot_proj = zero
    1497              : !          --Analytic value of overlap
    1498              : !          g_ij=Gamma[-1/2+i+j+l]/Sqrt(Gamma[-1/2+i+iangol]*Gamma[-1/2+j+iangol])
    1499            0 :            call gamma_function(-half+real(nproj+nproj2+iangol,dp),tot_proj)
    1500            0 :            call gamma_function(-half+real(iangol+2*nproj,dp),denom_1)
    1501            0 :            call gamma_function(-half+real(iangol+2*nproj2,dp),denom_2)
    1502              : 
    1503            0 :            g_mat(nproj,nproj2) = tot_proj/sqrt(denom_1*denom_2)
    1504            0 :            g_mat(nproj2,nproj) = g_mat(nproj,nproj2)
    1505              : 
    1506            0 :            h_mat(nproj,nproj2) = h_mat_init(nproj,nproj2)
    1507            0 :            h_mat(nproj2,nproj) = h_mat_init(nproj,nproj2)
    1508              :          end do
    1509              :        end do
    1510              : 
    1511              : !      --Inverse of the overlap matrix g
    1512            0 :        inv_g_mat = g_mat
    1513            0 :        call DGETRF(g_mat_size,g_mat_size,inv_g_mat,g_mat_size,ipvt,info)
    1514            0 :        call DGETRI(g_mat_size,inv_g_mat,g_mat_size,ipvt,rework,lwork,info)
    1515              : 
    1516              : 
    1517              : !      -----------------------------------------------------------
    1518              : !      --Now it calculates the exponential of the matrix h.g
    1519            0 :        hg_mat = matmul(h_mat,g_mat)
    1520              : 
    1521            0 :        call exp_mat(hg_mat,g_mat_size,-one/temperature)
    1522              : 
    1523              : !      --(exp(h.g)-Identity).(g^-1)
    1524            0 :        hg_mat = hg_mat-identity(:,:)
    1525              : 
    1526              : 
    1527              : !      --results on output
    1528            0 :        nlrec%mat_exp_psp_nl(:g_mat_size,:g_mat_size,1+iangol,ipseudo) = matmul(real(hg_mat,dp),inv_g_mat)
    1529              : 
    1530              : !      write(std_out,*) nlrec%mat_exp_psp_nl(:g_mat_size,:g_mat_size,1+iangol,ipseudo)
    1531              : 
    1532            0 :        ABI_FREE(g_mat)
    1533            0 :        ABI_FREE(hg_mat)
    1534            0 :        ABI_FREE(h_mat)
    1535            0 :        ABI_FREE(inv_g_mat)
    1536            0 :        ABI_FREE(identity)
    1537              :      end if
    1538              : 
    1539              :    end do !enddo on angular moment
    1540              :  end do !enddo on pseudos
    1541              : 
    1542              : 
    1543            0 :  if(debug)then
    1544            0 :    write(msg,'(80a,a,a)') ('=',ii=1,80),ch10,' pspnl_hgh_rec : exit '
    1545            0 :    call wrtout(std_out,msg,'COLL')
    1546              :  end if
    1547              : 
    1548            0 : end subroutine pspnl_hgh_rec
    1549              : !!***
    1550              : 
    1551            0 : end module m_rec
    1552              : !!***
        

Generated by: LCOV version 2.3-1