LCOV - code coverage report
Current view: top level - src/71_bse - m_exc_diago.F90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 69.0 % 449 310
Test Date: 2026-09-19 17:42:43 Functions: 80.0 % 5 4

            Line data    Source code
       1              : !!****m* ABINIT/m_exc_diago
       2              : !! NAME
       3              : !! m_exc_diago
       4              : !!
       5              : !! FUNCTION
       6              : !!
       7              : !! COPYRIGHT
       8              : !! Copyright (C) 2009-2026 ABINIT and EXC groups (L.Reining, V.Olevano, F.Sottile, S.Albrecht, G.Onida, M.Giantomassi)
       9              : !!  This file is distributed under the terms of the
      10              : !!  GNU General Public License, see ~abinit/COPYING
      11              : !!  or http://www.gnu.org/copyleft/gpl.txt .
      12              : !!
      13              : !! SOURCE
      14              : 
      15              : #if defined HAVE_CONFIG_H
      16              : #include "config.h"
      17              : #endif
      18              : 
      19              : #include "abi_common.h"
      20              : 
      21              : MODULE m_exc_diago
      22              : 
      23              :  use defs_basis
      24              :  use m_bs_defs
      25              :  use m_abicore
      26              :  use m_errors
      27              :  USE_MPI
      28              :  use m_xmpi
      29              :  use m_hdr
      30              :  use m_sort
      31              :  use m_slk
      32              : 
      33              :  use defs_datatypes,    only : pseudopotential_type
      34              :  use m_io_tools,        only : open_file
      35              :  use m_fstrings,        only : int2char4
      36              :  use m_numeric_tools,   only : print_arr, hermitianize
      37              :  use m_crystal,         only : crystal_t
      38              :  use m_kpts,            only : listkk
      39              :  use m_bz_mesh,         only : kmesh_t
      40              :  use m_ebands,          only : ebands_t
      41              :  use m_eprenorms,       only : eprenorms_t
      42              :  use m_wfd,             only : wfdgw_t
      43              :  use m_paw_hr,          only : pawhur_t
      44              :  use m_pawtab,          only : pawtab_type
      45              :  use m_exc_itdiago,     only : exc_iterative_diago
      46              :  use m_hide_lapack,     only : xheev, xheevx, xgeev, xhegvx, xginv, xhdp_invert, xhegv
      47              :  use m_hide_blas,       only : xdotc, xgemm
      48              :  use m_bse_io,          only : exc_fullh_from_blocks, offset_in_file, rrs_of_glob, ccs_of_glob, &
      49              : &                              exc_read_bshdr, exc_skip_bshdr_mpio, exc_read_rblock_fio
      50              :  use m_exc_spectra,     only : build_spectra
      51              : 
      52              :  implicit none
      53              : 
      54              :  private
      55              : 
      56              : #if defined HAVE_MPI1
      57              :  include 'mpif.h'
      58              : #endif
      59              : 
      60              : !#define DEV_MG_DEBUG_THIS
      61              : 
      62              :  public ::  exc_diago_driver ! Driver routine for the direct diagonalization of the BSE Hamiltonian (main entry point)
      63              : !!***
      64              : 
      65              : contains
      66              : 
      67              : !!****f* m_exc_diago/exc_diago_driver
      68              : !! NAME
      69              : !!  exc_diago_driver
      70              : !!
      71              : !! FUNCTION
      72              : !!  Driver routine for the direct diagonalization of the Hermitian excitonic Hamiltonian.
      73              : !!
      74              : !! INPUTS
      75              : !!  neh=Rank of the resonant block of the Hamiltonian.
      76              : !!  BS_files<excfiles>=Datatype storing names and files used in the Bethe-Salpeter code.
      77              : !!    %exh=Name of the file storing the excitonic resonant part.
      78              : !!
      79              : !! OUTPUT
      80              : !!  Eigenvalues and eigenvectors are written on file.
      81              : !!
      82              : !! SOURCE
      83              : 
      84            6 : subroutine exc_diago_driver(Wfd,Bsp,BS_files,KS_BSt,QP_BSt,Cryst,Kmesh,Psps,&
      85            6 : &  Pawtab,Hur,Hdr_bse,drude_plsmf,Epren)
      86              : 
      87              : !Arguments ------------------------------------
      88              : !scalars
      89              :  real(dp),intent(in) :: drude_plsmf
      90              :  type(excparam),intent(in) :: BSp
      91              :  type(excfiles),intent(in) ::  BS_files
      92              :  type(Hdr_type),intent(in) :: Hdr_bse
      93              :  type(crystal_t),intent(in) :: Cryst
      94              :  type(pseudopotential_type),intent(in) :: Psps
      95              :  type(kmesh_t),intent(in) :: Kmesh
      96              :  type(ebands_t),intent(in) :: KS_BSt,QP_BSt
      97              :  type(wfdgw_t),intent(inout) :: Wfd
      98              :  type(eprenorms_t),intent(in) :: Epren
      99              : !arrays
     100              :  type(pawtab_type),intent(in) :: Pawtab(Cryst%ntypat*Wfd%usepaw)
     101              :  type(pawhur_t),intent(in) :: Hur(Cryst%natom*Wfd%usepaw)
     102              : 
     103              : !Local variables ------------------------------
     104              : !scalars
     105              :  integer :: my_rank,master,comm,prtvol
     106              :  complex(dp) :: exc_gap,gw_gap
     107              :  logical :: eval_eigenstates
     108              :  character(len=500) :: msg
     109              : !arrays
     110           12 :  real(dp) :: gaps(3,QP_BSt%nsppol)
     111              : !************************************************************************
     112              : 
     113              :  DBG_ENTER("COLL")
     114              : 
     115            6 :  comm    = Wfd%comm
     116            6 :  my_rank = Wfd%my_rank
     117            6 :  master  = Wfd%master
     118            6 :  prtvol  = Wfd%prtvol
     119              : 
     120            6 :  if (BSp%have_complex_ene) then
     121            0 :    ABI_ERROR("Complex energies are not supported yet")
     122              :  end if
     123              :  !
     124              :  ! This trick is needed to restart a CG run, use DDIAGO to calculate the spectra reusing an old BSEIG file.
     125            6 :  eval_eigenstates = (BS_files%in_eig == BSE_NOFILE) .or. (Bsp%algorithm == BSE_ALGO_CG)
     126              : 
     127              :  if (eval_eigenstates) then
     128              :    !
     129           11 :    select case (BSp%algorithm)
     130              :    case (BSE_ALGO_DDIAGO)
     131            5 :      if (BSp%use_coupling==0) then
     132            4 :        call exc_diago_resonant(BSp,BS_files,Hdr_bse,prtvol,comm)
     133            4 :        if(Bsp%do_ep_renorm) then
     134            1 :          call exc_diago_resonant(BSp,BS_files,Hdr_bse,prtvol,comm,Epren=Epren,Kmesh=Kmesh,Cryst=Cryst,elph_lifetime=.TRUE.)
     135              :        end if
     136              :      else
     137            1 :        if (Bsp%have_complex_ene) then
     138              :          ! Solve Hv = ev with generic complex matrix.
     139            0 :          call exc_diago_coupling(BSp,BS_files,Hdr_bse,prtvol,comm)
     140              :        else
     141              :          ! Solve generalized eigenvalue problem F Hbar with Hbar Hermitian definitive positive matrix.
     142            1 :          call exc_diago_coupling_hegv(BSp,BS_files,Hdr_bse,prtvol,comm)
     143              :        end if
     144              :      end if
     145              : 
     146              :    case (BSE_ALGO_CG)
     147            1 :      if (BSp%use_coupling==0) then
     148            1 :        call exc_iterative_diago(Bsp,BS_files,Hdr_bse,prtvol,comm)
     149              :      else
     150            0 :        ABI_ERROR("CG + coupling not coded")
     151              :      end if
     152              : 
     153              :    case default
     154            0 :      write(msg,'(a,i0)')" Wrong value for Bsp%algorithm: ",Bsp%algorithm
     155            6 :      ABI_ERROR(msg)
     156              :    end select
     157              :    !
     158            6 :    if (my_rank==master) then
     159            6 :      call QP_BSt%report_gap(header="QP bands",unit=std_out,gaps=gaps)
     160           19 :      gw_gap = MINVAL(gaps(2,:))
     161            6 :      call exc_print_eig(BSp,BS_files%out_eig,gw_gap,exc_gap)
     162              :    end if
     163            6 :    call xmpi_barrier(comm)
     164              :    !
     165              :  end if
     166              : 
     167            6 :  call build_spectra(BSp,BS_files,Cryst,Kmesh,KS_BSt,QP_BSt,Psps,Pawtab,Wfd,Hur,drude_plsmf,comm)
     168              : 
     169              :  ! Electron-phonon renormalization !
     170            6 :  if (BSp%algorithm == BSE_ALGO_DDIAGO .and. BSp%use_coupling == 0 .and. BSp%do_ep_renorm) then
     171            1 :    call build_spectra(BSp,BS_files,Cryst,Kmesh,KS_BSt,QP_BSt,Psps,Pawtab,Wfd,Hur,drude_plsmf,comm,Epren=Epren)
     172              :  end if
     173              : 
     174              :  DBG_EXIT("COLL")
     175              : 
     176            6 : end subroutine exc_diago_driver
     177              : !!***
     178              : 
     179              : !----------------------------------------------------------------------
     180              : 
     181              : !!****f* m_exc_diago/exc_diago_resonant
     182              : !! NAME
     183              : !!  exc_diago_resonant
     184              : !!
     185              : !! FUNCTION
     186              : !!  Calculates eigenvalues and eigenvectors of the Hermitian excitonic Hamiltonian (coupling is neglected).
     187              : !!
     188              : !! INPUTS
     189              : !!  Bsp
     190              : !!  BS_files<excfiles>=Datatype storing names and files used in the Bethe-Salpeter code.
     191              : !!  comm=MPI communicator.
     192              : !!  bseig_fname=The name of the output file
     193              : !!  prtvol=Verbosity level.
     194              : !!
     195              : !! OUTPUT
     196              : !!  Eigenvalues and eigenvectors are written on file bseig_fname
     197              : !!
     198              : !! SOURCE
     199              : 
     200            5 : subroutine exc_diago_resonant(Bsp,BS_files,Hdr_bse,prtvol,comm,Epren,Kmesh,Cryst,elph_lifetime)
     201              : 
     202              : !Arguments ------------------------------------
     203              : !scalars
     204              :  integer,intent(in) :: comm,prtvol
     205              :  logical,optional,intent(in) :: elph_lifetime
     206              :  type(excparam),intent(in) :: BSp
     207              :  type(excfiles),intent(in) :: BS_files
     208              :  type(Hdr_type),intent(in) :: Hdr_bse
     209              :  type(eprenorms_t),optional,intent(in) :: Epren
     210              :  type(kmesh_t),optional,intent(in) :: Kmesh
     211              :  type(crystal_t),optional,intent(in) :: Cryst
     212              : 
     213              : !Local variables ------------------------------
     214              : !scalars
     215              :  integer,parameter :: master=0
     216              :  integer :: ii,it,mi,hreso_unt,eig_unt,exc_size,neh1,neh2,j
     217              :  integer :: nsppol,il,iu,mene_found,nstates
     218              :  integer :: nprocs,my_rank,fform,nene_printed,ierr
     219              :  real(dp) :: exc_gap,exc_maxene,abstol
     220              :  real(dp) :: vl,vu
     221              :  logical :: use_scalapack,do_full_diago,diagonal_is_real
     222              :  character(len=500) :: msg
     223              :  character(len=fnlen) :: hreso_fname,bseig_fname
     224              : !arrays
     225            5 :  real(dp),allocatable :: exc_ene(:)
     226            5 :  complex(dp),allocatable :: exc_mat(:,:),exc_vec(:,:)
     227              : #if defined HAVE_LINALG_SCALAPACK && defined HAVE_MPI_IO
     228              :  integer :: amode,mpi_fh,istwf_k,tbloc
     229              :  integer(XMPI_OFFSET_KIND) :: ehdr_offset,fmarker
     230              :  integer :: block_sizes(2,3),array_of_sizes(2),gsub(2,2)
     231              :  logical,parameter :: is_fortran_file=.TRUE.
     232              :  real(dp),external :: PDLAMCH
     233              :  type(slkmat_dp_t) :: Slk_mat,Slk_vec
     234              :  type(slk_processor_t) :: Slk_processor
     235              : #endif
     236              : 
     237              :  integer :: ik, ic, iv, isppol, ireh, ep_ik, itemp
     238              :  complex(dp) :: en
     239              : 
     240              :  real(dp) :: dksqmax
     241            5 :  integer,allocatable :: bs2eph(:,:)
     242              :  integer :: sppoldbl, timrev
     243              :  logical :: do_ep_renorm, do_ep_lifetime
     244              :  integer :: ntemp
     245              :  character(len=4) :: ts
     246            5 :  complex(dp),allocatable :: exc_vl(:,:),exc_ene_c(:)
     247              :  complex(dp) :: ctemp
     248              : !! complex(dp),allocatable :: ovlp(:,:)
     249              : !************************************************************************
     250              : 
     251              :  DBG_ENTER("PERS")
     252              : 
     253            5 :  nprocs  = xmpi_comm_size(comm); my_rank = xmpi_comm_rank(comm)
     254              : 
     255            5 :  if (BSp%have_complex_ene) then ! QP lifetimes are not included
     256            0 :    ABI_ERROR("complex energies not coded yet")
     257              :  end if
     258              : 
     259           11 :  if (ANY(Bsp%nreh/=Bsp%nreh(1))) then
     260            0 :    write(std_out,*)" Bsp%nreh: ",Bsp%nreh
     261            0 :    write(msg,'(a)')" BSE code does not support different number of transitions for the two spin channels"
     262            0 :    ABI_WARNING(msg)
     263              :  end if
     264              : 
     265            5 :  nsppol   = Hdr_bse%nsppol
     266           11 :  exc_size = SUM(BSp%nreh)
     267            5 :  nstates  = BSp%nstates; do_full_diago=(Bsp%nstates==exc_size)
     268              : 
     269            5 :  neh1 = Bsp%nreh(1); neh2 = neh1
     270              :  if (Hdr_bse%nsppol==2) neh2 = Bsp%nreh(2)
     271              : 
     272              :  ! Scalapack is disabled due to portability issues in slk_read
     273              :  ! This part should be rewritten  with hdf5 + mpi-io
     274              : 
     275              :  use_scalapack = .FALSE.
     276              : !#if defined HAVE_LINALG_SCALAPACK
     277              : ! use_scalapack = (nprocs > 1)
     278              : !#endif
     279              :  if (use_scalapack .and. nsppol == 2) then
     280              :    use_scalapack = .False.
     281              :    ABI_WARNING("Scalapack with nsppol==2 not yet available. Using sequential version")
     282              :  end if
     283              : 
     284            5 :  if (.not.use_scalapack .and. my_rank/=master) GOTO 10 ! Inversion is done by master only.
     285              : 
     286            5 :  nene_printed = MIN(32*nsppol,nstates); if (prtvol>10) nene_printed = nstates
     287              : 
     288            5 :  if (BS_files%in_hreso /= BSE_NOFILE) then
     289            1 :    hreso_fname = BS_files%in_hreso
     290              :  else
     291            4 :    hreso_fname = BS_files%out_hreso
     292              :  end if
     293              : 
     294            5 :  bseig_fname = BS_files%out_eig
     295            5 :  if (BS_files%in_eig /= BSE_NOFILE) then
     296            0 :    ABI_ERROR("BS_files%in_eig is defined!")
     297              :  end if
     298              : 
     299            5 :  write(msg,'(a,i0)')' Direct diagonalization of the resonant excitonic Hamiltonian, Matrix size= ',exc_size
     300           15 :  call wrtout([std_out, ab_out], msg)
     301              : 
     302           15 :  ABI_MALLOC_OR_DIE(exc_ene,(exc_size), ierr)
     303           15 :  ABI_MALLOC_OR_DIE(exc_ene_c,(exc_size), ierr)
     304              : 
     305            5 :  do_ep_renorm = .FALSE.
     306            5 :  ntemp = 1
     307            5 :  do_ep_lifetime = .FALSE.
     308            5 :  if(BSp%do_ep_renorm .and. present(Epren)) then
     309            1 :    do_ep_renorm = .TRUE.
     310            1 :    ntemp = Epren%ntemp
     311            1 :    if(present(elph_lifetime)) then
     312            1 :      do_ep_lifetime = elph_lifetime
     313              :    end if
     314              :  end if
     315              : 
     316              :  if (do_ep_renorm) then
     317            1 :    ABI_CHECK(nsppol == 1, "Nsppol == 2 not supported with elphon renormalizations")
     318              :  end if
     319              : 
     320              :  SELECT CASE (use_scalapack)
     321              :  CASE (.FALSE.)
     322              : 
     323            5 :    write(msg,'(a)')". Using LAPACK sequential version. "
     324           15 :    call wrtout([std_out, ab_out], msg)
     325            5 :    write(msg,'(a,f8.1,a)')' Allocating excitonic eigenvalues. Memory required: ', exc_size*dp*b2Mb,' Mb. '
     326            5 :    call wrtout(std_out, msg)
     327              : 
     328            5 :    write(msg,'(a,f8.1,a)')' Allocating excitonic hamiltonian.  Memory required: ',exc_size**2*dp*b2Mb,' Mb.'
     329            5 :    call wrtout(std_out, msg, do_flush=.True.)
     330              : 
     331           20 :    ABI_MALLOC_OR_DIE(exc_mat,(exc_size,exc_size), ierr)
     332              : 
     333            5 :    if (do_ep_renorm) then
     334            3 :      ABI_MALLOC_OR_DIE(exc_vl,(exc_size,exc_size),ierr)
     335              :    end if
     336              :    !exc_mat = HUGE(zero)
     337              :    !
     338              :    ! Read data from file.
     339            5 :    if (open_file(hreso_fname,msg,newunit=hreso_unt,form="unformatted",status="old",action="read") /= 0) then
     340            0 :      ABI_ERROR(msg)
     341              :    end if
     342              :    !
     343              :    ! Read the header and perform consistency checks.
     344            5 :    call exc_read_bshdr(hreso_unt,Bsp,fform,ierr)
     345            5 :    ABI_CHECK(ierr==0,"Fatal error, cannot continue")
     346              :    !
     347              :    ! Construct full resonant block using Hermiticity.
     348            5 :    diagonal_is_real = .not.Bsp%have_complex_ene
     349            5 :    call exc_read_rblock_fio(hreso_unt,diagonal_is_real,nsppol,Bsp%nreh,exc_size,exc_mat,ierr)
     350            5 :    ABI_CHECK(ierr==0,"Fatal error, cannot continue")
     351              : 
     352            5 :    close(hreso_unt)
     353              : 
     354            5 :    if (do_ep_renorm) then
     355            1 :      write(std_out,'(a)') "Mapping kpts from bse to eph"
     356            1 :      sppoldbl = 1 !; if (any(Cryst%symafm == -1) .and. Epren%nsppol == 1) nsppoldbl=2
     357            3 :      ABI_MALLOC(bs2eph, (Kmesh%nbz*sppoldbl, 6))
     358            1 :      timrev = 1
     359              :      call listkk(dksqmax, Cryst%gmet, bs2eph, Epren%kpts, Kmesh%bz, Epren%nkpt, Kmesh%nbz, Cryst%nsym, &
     360            1 :         sppoldbl, Cryst%symafm, Cryst%symrel, timrev, xmpi_comm_self, use_symrec=.False.)
     361              :    end if
     362              : 
     363           19 :    do itemp = 1, ntemp
     364              : 
     365              :      !TODO should find a way not to read again and again !
     366              :      !  but without storing it twice !!!
     367              :      !exc_mat = HUGE(zero)
     368              :      !
     369              :      ! Read data from file.
     370           14 :      if (open_file(hreso_fname,msg,newunit=hreso_unt,form="unformatted",status="old",action="read") /= 0) then
     371            0 :        ABI_ERROR(msg)
     372              :      end if
     373              :      !
     374              :      ! Read the header and perform consistency checks.
     375           14 :      call exc_read_bshdr(hreso_unt,Bsp,fform,ierr)
     376           14 :      ABI_CHECK(ierr==0,"Fatal error, cannot continue")
     377              :      !
     378              :      ! Construct full resonant block using Hermiticity.
     379           14 :      diagonal_is_real = .not.Bsp%have_complex_ene
     380           14 :      call exc_read_rblock_fio(hreso_unt,diagonal_is_real,nsppol,Bsp%nreh,exc_size,exc_mat,ierr)
     381           14 :      ABI_CHECK(ierr==0,"Fatal error, cannot continue")
     382              : 
     383           14 :      close(hreso_unt)
     384              : 
     385           14 :      bseig_fname = BS_files%out_eig
     386              : 
     387           14 :      if (do_ep_renorm) then
     388           10 :        write(std_out,'(a,i4)') "Will perform elphon renormalization for itemp = ",itemp
     389              : 
     390           10 :        call int2char4(itemp,ts)
     391              : 
     392           10 :        bseig_fname = TRIM(BS_files%out_eig) // TRIM("_T") // ts
     393              : 
     394              :        ! Should patch the diagonal of exc_mat
     395              : 
     396           20 :        do isppol = 1, BSp%nsppol
     397          980 :          do ireh = 1, BSp%nreh(isppol)
     398          960 :            ic = BSp%Trans(ireh,isppol)%c
     399          960 :            iv = BSp%Trans(ireh,isppol)%v
     400          960 :            ik = BSp%Trans(ireh,isppol)%k ! In the full bz
     401          960 :            en = BSp%Trans(ireh,isppol)%en
     402              : 
     403          960 :            ep_ik = bs2eph(ik,1)
     404              : 
     405              :            !TODO support multiple spins !
     406          960 :            if(ABS(en - (Epren%eigens(ic,ep_ik,isppol)-Epren%eigens(iv,ep_ik,isppol)+BSp%mbpt_sciss)) > tol3) then
     407            0 :              ABI_ERROR("Eigen from the transition does not correspond to the EP file !")
     408              :            end if
     409          960 :            exc_mat(ireh,ireh) = exc_mat(ireh,ireh) + (Epren%renorms(1,ic,ik,isppol,itemp) - Epren%renorms(1,iv,ik,isppol,itemp))
     410              : 
     411              :            ! Add lifetime
     412          970 :            if(do_ep_lifetime) then
     413              :              exc_mat(ireh,ireh) = exc_mat(ireh,ireh) - j_dpc*(Epren%linewidth(1,ic,ik,isppol,itemp) &
     414          960 : &                + Epren%linewidth(1,iv,ik,isppol,itemp))
     415              :            end if
     416              : 
     417              :          end do
     418              :        end do
     419              : 
     420              :      end if
     421              : 
     422           14 :      if (do_full_diago) then
     423           13 :        if(do_ep_renorm) then
     424           10 :          call wrtout(std_out," Full diagonalization with XGEEV... ")
     425           30 :          ABI_MALLOC(exc_vec,(exc_size,exc_size))
     426           10 :          call xgeev('V','V',exc_size,exc_mat,exc_size,exc_ene_c,exc_vl,exc_size,exc_vec,exc_size)
     427        93130 :          exc_mat(:,1:nstates) = exc_vec
     428           10 :          ABI_FREE(exc_vec)
     429              :        else
     430            3 :          call wrtout(std_out," Full diagonalization with XHEEV... ")
     431            3 :          call xheev("Vectors","Upper",exc_size,exc_mat,exc_ene)
     432         1251 :          exc_ene_c(:) = exc_ene(:)
     433              :        end if
     434              :      else
     435            1 :        call wrtout(std_out," Partial diagonalization with XHEEVX... ")
     436            1 :        abstol=zero; il=1; iu=nstates
     437            4 :        ABI_MALLOC_OR_DIE(exc_vec,(exc_size,nstates),ierr)
     438            1 :        call xheevx("Vectors","Index","Upper",exc_size,exc_mat,vl,vu,il,iu,abstol,mene_found,exc_ene,exc_vec,exc_size)
     439         3851 :        exc_mat(:,1:nstates) = exc_vec
     440          385 :        exc_ene_c(:) = exc_ene(:)
     441            1 :        ABI_FREE(exc_vec)
     442              :      end if
     443              :      !
     444              :      ! ==============================================
     445              :      ! === Now exc_mat contains the eigenvectors ====
     446              :      ! ==============================================
     447              : 
     448              :      ! * Write the final results.
     449           14 :      call wrtout(std_out,' Writing eigenvalues and eigenvectors to file: '//TRIM(bseig_fname))
     450              : 
     451           14 :      if (open_file(bseig_fname,msg,newunit=eig_unt,form="unformatted",action="write") /= 0) then
     452            0 :        ABI_ERROR(msg)
     453              :      end if
     454              : 
     455              :      !!! !DBYG
     456              :      !!! !Compute overlap matrix
     457              :      !!! ABI_MALLOC(ovlp,(exc_size,exc_size))
     458              :      !!! do mi=1,nstates
     459              :      !!!   do ireh=1,nstates
     460              :      !!!     ovlp(mi,ireh) = xdotc(exc_size,exc_vl(:,mi),1,exc_mat(:,ireh),1)
     461              :      !!!     if(mi==ireh) then
     462              :      !!!       !if(ABS(ovlp(mi,ireh)) < 0.999) then
     463              :      !!!       !  write(*,*) "it,itp = ",mi,ireh,"ovlp = ",ovlp(mi,ireh)
     464              :      !!!       !end if
     465              :      !!!     else
     466              :      !!!       if(ABS(ovlp(mi,ireh)) > 0.001) then
     467              :      !!!         write(*,*) "it,itp = ",mi,ireh,"ovlp = ",ovlp(mi,ireh)
     468              :      !!!       end if
     469              :      !!!     end if
     470              :      !!!   end do
     471              :      !!! end do
     472              :      !!! !call xgemm("C","N",exc_size,nstates,nstates,cone,exc_vl,exc_size,exc_mat,exc_size,czero,ovlp,nstates)
     473              : 
     474              :      !!! write(777,*) ovlp
     475              :      !!! ABI_FREE(ovlp)
     476              :      !!! !ENDDBYG
     477              : 
     478              :      !% fform = 1002 ! FIXME
     479              :      !% call hdr_io_int(fform,Hdr_bse,2,eig_unt)
     480              : 
     481           14 :      write(eig_unt) do_ep_lifetime
     482           14 :      write(eig_unt) exc_size, nstates
     483           14 :      write(eig_unt) exc_ene_c(1:nstates)
     484         2232 :      do mi=1,nstates
     485         2218 :        write(eig_unt) exc_mat(1:exc_size,mi)
     486         2232 :        if(do_ep_lifetime) then
     487          960 :          write(eig_unt) exc_vl(1:exc_size,mi)
     488              :        end if
     489              :      end do
     490              : 
     491           47 :      close(eig_unt)
     492              : 
     493              :    end do ! itemp
     494              : 
     495            5 :    ABI_FREE(exc_mat)
     496           15 :    if (do_ep_renorm) then
     497            1 :      ABI_FREE(exc_vl)
     498            1 :      ABI_FREE(bs2eph)
     499              :    end if
     500              : 
     501              :  CASE (.TRUE.)
     502              : 
     503              : #if defined HAVE_LINALG_SCALAPACK && defined HAVE_MPI_IO
     504              :    if (nsppol==2) then
     505              :      ABI_WARNING("nsppol==2 + scalapack not coded yet")
     506              :    end if
     507              : 
     508              :    istwf_k=1; tbloc=50
     509              :    write(msg,'(2(a,i0))')". Using scaLAPACK version with nprocs= ",nprocs,"; block size= ",tbloc
     510              :    call wrtout([std_out, ab_out], msg)
     511              : 
     512              :    write(msg,'(a,f8.1,a)')' Allocating excitonic eigenvalues. Memory required: ',exc_size*dp*b2Mb,' Mb. '
     513              :    call wrtout(std_out, msg)
     514              :    !
     515              :    ! Init scaLAPACK environment.
     516              :    call Slk_processor%init(comm)
     517              :    !
     518              :    ! Init scaLAPACK matrices
     519              :    call Slk_mat%init(exc_size,exc_size,Slk_processor,istwf_k)
     520              :    call Slk_vec%init(exc_size,exc_size,Slk_processor,istwf_k)
     521              :    !
     522              :    ! Open the file with MPI-IO and skip the record.
     523              :    amode=MPI_MODE_RDONLY
     524              : 
     525              :    call MPI_FILE_OPEN(comm, hreso_fname, amode, MPI_INFO_NULL, mpi_fh, ierr)
     526              :    ABI_CHECK_MPI(ierr,"MPI_IO error opening file: "//TRIM(hreso_fname))
     527              : 
     528              :    ! Skip the header and find the offset for reading the matrix.
     529              :    call exc_skip_bshdr_mpio(mpi_fh,xmpio_collective,ehdr_offset)
     530              :    !
     531              :    ! Read scaLAPACK matrix from the file.
     532              :    if (nsppol==1) then
     533              :      call slk_read(Slk_mat,"Upper","Hermitian",is_fortran_file,mpi_fh=mpi_fh,offset=ehdr_offset)
     534              :    else
     535              :      array_of_sizes = (/exc_size,exc_size/)
     536              :      block_sizes(:,1) = (/neh1,neh1/)
     537              :      block_sizes(:,2) = (/neh2,neh2/)
     538              :      block_sizes(:,3) = (/neh1,neh2/)
     539              :      ABI_ERROR("Not tested")
     540              :      !call slk_read_from_blocks(Slk_mat,array_of_sizes,block_sizes,is_fortran_file,mpi_fh=mpi_fh,offset=ehdr_offset)
     541              :    end if
     542              : 
     543              :    call MPI_FILE_CLOSE(mpi_fh, ierr)
     544              :    ABI_CHECK_MPI(ierr,"FILE_CLOSE")
     545              : 
     546              :    if (do_full_diago) then
     547              :      call wrtout(std_out," Performing full diagonalization with scaLAPACK...")
     548              :      call slk_mat%heev("Vectors","Upper",Slk_vec,exc_ene)
     549              :    else
     550              :      call wrtout(std_out," Performing partial diagonalization with scaLAPACK...")
     551              :      il=1; iu=nstates; abstol=zero !ABSTOL = PDLAMCH(comm,'U')
     552              :      call slk_mat%pzheevx("Vectors","Index","Upper",vl,vu,il,iu,abstol,Slk_vec,mene_found,exc_ene)
     553              :    end if
     554              : 
     555              :    exc_ene_c(:) = exc_ene(:)
     556              : 
     557              :    call Slk_mat%free()
     558              : 
     559              :    call wrtout(std_out,' Writing eigenvalues/vectors to file: '//TRIM(bseig_fname), do_flush=.True.)
     560              : 
     561              :    ! Write distributed matrix on file bseig_fname with Fortran records.
     562              :    if (my_rank==master) then ! Write exc eigenvalues. Vectors will be appended in slk_write.
     563              :      if (open_file(bseig_fname,msg,newunit=eig_unt,form="unformatted",action="write") /= 0) then
     564              :        ABI_ERROR(msg)
     565              :      end if
     566              :      write(eig_unt) exc_size, nstates
     567              :      write(eig_unt) exc_ene_c(1:nstates)
     568              :      close(eig_unt)
     569              :    end if
     570              : 
     571              :    call xmpi_barrier(comm)
     572              :    !
     573              :    ! Open the file with MPI-IO and skip the record.
     574              :    amode=MPI_MODE_RDWR
     575              : 
     576              :    call MPI_FILE_OPEN(comm, bseig_fname, amode, MPI_INFO_NULL, mpi_fh, ierr)
     577              :    ABI_CHECK_MPI(ierr,"MPI_IO error opening file: "//TRIM(hreso_fname))
     578              : 
     579              :    !call MPI_FILE_SYNC(mpi_fh,ierr)
     580              : 
     581              :    ehdr_offset = 0
     582              :    call xmpio_read_frm(mpi_fh,ehdr_offset,xmpio_collective,fmarker,ierr)
     583              :    call xmpio_read_frm(mpi_fh,ehdr_offset,xmpio_collective,fmarker,ierr)
     584              : 
     585              :    write(std_out,*)"Writing nstates ",nstates
     586              :    gsub(:,1) = (/1,1/)
     587              :    gsub(:,2) = (/exc_size,nstates/)
     588              :    call slk_write(Slk_vec,"All",is_fortran_file,mpi_fh=mpi_fh,offset=ehdr_offset,glob_subarray=gsub)
     589              : 
     590              :    call MPI_FILE_CLOSE(mpi_fh, ierr)
     591              :    ABI_CHECK_MPI(ierr,"FILE_CLOSE")
     592              : 
     593              :    call Slk_vec%free()
     594              :    call Slk_processor%free()
     595              :    call xmpi_barrier(comm)
     596              : #else
     597              :    ABI_BUG("You should not be here!")
     598              : #endif
     599              : 
     600              :  END SELECT
     601              : 
     602              :  ! Order the eigenvalues
     603         1354 :  do ii=nstates,2,-1
     604       378583 :    do j=1,ii-1
     605       378578 :      if (DBLE(exc_ene_c(j)) > DBLE(exc_ene_c(j+1))) then
     606         3583 :        ctemp = exc_ene_c(j)
     607         3583 :        exc_ene_c(j) = exc_ene_c(j+1)
     608         3583 :        exc_ene_c(j+1) = ctemp
     609              :      end if
     610              :    end do
     611              :  end do
     612              : 
     613              : 
     614            5 :  write(msg,'(a,i4)')' Excitonic eigenvalues in eV up to n= ',nene_printed
     615           15 :  call wrtout([std_out, ab_out], msg)
     616              : 
     617           27 :  do it=0,(nene_printed-1)/8
     618          192 :    write(msg,'(8f10.5)') ( DBLE(exc_ene_c(ii))*Ha_eV, ii=1+it*8,MIN(it*8+8,nene_printed) )
     619           71 :    call wrtout([std_out, ab_out], msg)
     620              :  end do
     621              : 
     622         1364 :  exc_gap    = MINVAL(DBLE(exc_ene_c(1:nstates)))
     623         1364 :  exc_maxene = MAXVAL(DBLE(exc_ene_c(1:nstates)))
     624              : 
     625            5 :  write(msg,'(a,2(a,f7.2,2a),a)')ch10,&
     626            5 :   " First excitonic eigenvalue= ",exc_gap*Ha_eV,   " [eV]",ch10,&
     627           10 :   " Last  excitonic eigenvalue= ",exc_maxene*Ha_eV," [eV]",ch10,ch10
     628           15 :  call wrtout([std_out, ab_out], msg, do_flush=.True.)
     629              : 
     630            5 :  ABI_FREE(exc_ene_c)
     631            5 :  ABI_FREE(exc_ene)
     632              : 
     633            5 : 10 call xmpi_barrier(comm)
     634              : 
     635              :  DBG_EXIT("PERS")
     636              : 
     637            5 : end subroutine exc_diago_resonant
     638              : !!***
     639              : 
     640              : !----------------------------------------------------------------------
     641              : 
     642              : !!****f* m_exc_diago/exc_print_eig
     643              : !! NAME
     644              : !!  exc_print_eig
     645              : !!
     646              : !! FUNCTION
     647              : !!  Print excitonic eigenvalues on std_out and ab_out.
     648              : !!
     649              : !! INPUTS
     650              : !!  gw_gap=GW direct gap.
     651              : !!  bseig_fname=The name of file containing eigenvalues and eigenvectors
     652              : !!
     653              : !! OUTPUT
     654              : !!  exc_gap=Excitonic direct gap.
     655              : !!  Additional info on the Excitonic spectrum are reported on standard output.
     656              : !!
     657              : !! SOURCE
     658              : 
     659            6 : subroutine exc_print_eig(BSp,bseig_fname,gw_gap,exc_gap)
     660              : 
     661              : !Arguments ------------------------------------
     662              : !scalars
     663              :  complex(dp),intent(in) :: gw_gap
     664              :  complex(dp),intent(out) :: exc_gap
     665              :  character(len=*),intent(in) :: bseig_fname
     666              :  type(excparam),intent(in) :: BSp
     667              : 
     668              : !Local variables ------------------------------
     669              : !scalars
     670              :  integer :: nstates_read,ii,j,k,eig_unt,ieig,hsize_exp, hsize_read !,nstates
     671              :  complex(dp) :: bind_energy,ctemp
     672              :  character(len=500) :: msg
     673              :  !type(Hdr_type) :: tmp_Hdr
     674              : !arrays
     675            6 :  integer,allocatable :: iperm(:)
     676            6 :  real(dp),allocatable :: exc_rene(:)
     677            6 :  complex(dp),allocatable :: exc_cene(:)
     678              : !************************************************************************
     679              : 
     680            6 :  exc_gap = czero
     681              : 
     682            6 :  if (open_file(bseig_fname,msg,newunit=eig_unt,form="unformatted",status="old",action="read") /= 0) then
     683            0 :    ABI_ERROR(msg)
     684              :  end if
     685              : 
     686            6 :  read(eig_unt) ! do_ep_lifetime
     687            6 :  read(eig_unt) hsize_read, nstates_read
     688              : 
     689           12 :  if (BSp%use_coupling==0) hsize_exp =   SUM(Bsp%nreh)
     690            7 :  if (BSp%use_coupling>0)  hsize_exp = 2*SUM(Bsp%nreh)
     691              : 
     692            6 :  if (hsize_exp /= hsize_read) then
     693            0 :    write(msg,'(2(a,i0))')" Wrong dimension: read: ",hsize_read," expected= ",hsize_exp
     694            0 :    ABI_ERROR(msg)
     695              :  end if
     696              : 
     697           18 :  ABI_MALLOC(exc_cene,(nstates_read))
     698            6 :  read(eig_unt) exc_cene(:)
     699              : 
     700           18 :  ABI_MALLOC(exc_rene,(nstates_read))
     701         2048 :  exc_rene = DBLE(exc_cene)
     702              : 
     703           18 :  ABI_MALLOC(iperm,(nstates_read))
     704         6126 :  iperm = (/(ii, ii=1,nstates_read)/)
     705              : 
     706            6 :  call sort_dp(nstates_read,exc_rene,iperm,tol6)
     707              : 
     708            6 :  ABI_FREE(exc_rene)
     709            6 :  ABI_FREE(iperm)
     710              : 
     711              :  ! put in ascending order
     712         2036 :  do ii=nstates_read,2,-1
     713       669278 :    do j=1,ii-1
     714       669272 :      if (DBLE(exc_cene(j)) > DBLE(exc_cene(j+1))) then
     715            0 :        ctemp = exc_cene(j)
     716            0 :        exc_cene(j) = exc_cene(j+1)
     717            0 :        exc_cene(j+1) = ctemp
     718              :      end if
     719              :    end do
     720              :  end do
     721              : 
     722            6 :  exc_gap = DCMPLX(ABS(DBLE(exc_cene(1))),AIMAG(exc_cene(1)))
     723              : 
     724         2042 :  do ii=1,nstates_read
     725         2042 :    if (ABS(DBLE(exc_cene(ii))) < DBLE(exc_gap)) then
     726          383 :      exc_gap = DCMPLX(ABS(DBLE(exc_cene(ii))),AIMAG(exc_cene(ii)))
     727              :    end if
     728              :  end do
     729              : 
     730            6 :  bind_energy = gw_gap - exc_gap
     731              : 
     732              :  write(msg,"(3(a,2f6.2,2a))")&
     733            6 :   " GW  direct gap     ",gw_gap*Ha_eV,     " [eV] ",ch10,&
     734            6 :   " EXC direct gap     ",exc_gap*Ha_eV,    " [eV] ",ch10,&
     735           12 :   " EXC binding energy ",bind_energy*Ha_eV," [eV] ",ch10
     736           18 :  call wrtout([std_out, ab_out], msg)
     737              : 
     738            6 :  msg=' Excitonic eigenvalues up to the GW energy gap [eV]'
     739           18 :  call wrtout([std_out, ab_out], msg)
     740              : 
     741          390 :  do ii=1,nstates_read
     742          390 :    if (DBLE(exc_cene(ii)) > zero) EXIT
     743              :  end do
     744              : 
     745           96 :  do j=ii,nstates_read
     746           96 :    if (DBLE(exc_cene(j)) > DBLE(gw_gap)) EXIT
     747              :  end do
     748            6 :  j=j-1
     749              : 
     750           96 :  do ieig=ii,j
     751           90 :    write(msg,'(i3,a,2f6.2,a)')ieig," (",exc_cene(ieig)*Ha_eV,")"
     752          276 :    call wrtout([std_out, ab_out], msg)
     753              :  end do
     754              : 
     755            6 :  ii=ii-1
     756           22 :  do j=ii,1,-1
     757           22 :    if (ABS(DBLE(exc_cene(j))) > DBLE(gw_gap)) EXIT
     758              :  end do
     759            6 :  j=j+1
     760              : 
     761              :  ! This coding is not portable, write to ab_out has been disabled.
     762            6 :  if (ii>0) then
     763           17 :    do k=ii,j,-1
     764           16 :      write(msg,'(i3,a,2f6.2,a)')k," (",exc_cene(k)*Ha_eV,")"
     765           17 :      call wrtout(std_out, msg)
     766              :    end do
     767              :  end if
     768              : 
     769            6 :  ABI_FREE(exc_cene)
     770              : 
     771            6 :  close(eig_unt)
     772              : 
     773            6 : end subroutine exc_print_eig
     774              : !!***
     775              : 
     776              : !----------------------------------------------------------------------
     777              : 
     778              : !!****f* m_exc_diago/exc_diago_coupling
     779              : !! NAME
     780              : !!  exc_diago_coupling
     781              : !!
     782              : !! FUNCTION
     783              : !!  Calculate excitonic eigenvalues and eigenvectors by performing a direct diagonalization.
     784              : !!  of the non Hermitian excitonic Hamiltoninan (resonant + coupling).
     785              : !!
     786              : !! INPUTS
     787              : !!  bseig_fname=The name of the output file.
     788              : !!  Bsp
     789              : !!    neh=Rank of the resonant block of the Hamiltoninan (equal to the rank of the coupling part)
     790              : !!  comm=MPI communicator.
     791              : !!  BS_files<excfiles>=Datatype storing names and files used in the Bethe-Salpeter code.
     792              : !!
     793              : !! OUTPUT
     794              : !!  Excitonic eigenvectors and eigenvalues are written on file BS_files%out_eig.
     795              : !!
     796              : !! SOURCE
     797              : 
     798            0 : subroutine exc_diago_coupling(Bsp,BS_files,Hdr_bse,prtvol,comm)
     799              : 
     800              : !Arguments ------------------------------------
     801              : !scalars
     802              :  integer,intent(in) :: comm,prtvol
     803              :  type(excfiles),intent(in) :: BS_files
     804              :  type(excparam),intent(in) :: BSp
     805              :  type(Hdr_type),intent(in) :: Hdr_bse
     806              : 
     807              : !Local variables ------------------------------
     808              : !scalars
     809              :  integer,parameter :: master=0,ldvl=1
     810              :  integer(i8b) :: bsize_ham
     811              :  integer :: ii,exc_size,hreso_unt,hcoup_unt,eig_unt,nsppol,nstates
     812              :  integer :: bsz,block,bs1,bs2,jj, fform,row_sign, mi,it,nprocs,my_rank !itp
     813              :  integer :: nene_printed,ierr
     814              :  real(dp) :: exc_gap,exc_maxene,temp
     815              :  logical :: diago_is_real,do_full_diago, do_ep_lifetime
     816              :  character(len=500) :: msg
     817              :  character(len=fnlen) :: hreso_fname,hcoup_fname,bseig_fname
     818              : !arrays
     819            0 :  complex(dp),allocatable :: exc_ham(:,:),exc_rvect(:,:),exc_ene(:),ovlp(:,:), cbuff(:,:)
     820              :  complex(dp) :: vl_dpc(ldvl,1)
     821              : !************************************************************************
     822              : 
     823            0 :  my_rank = xmpi_comm_rank(comm); nprocs  = xmpi_comm_size(comm)
     824              : 
     825            0 :  nsppol = Hdr_bse%nsppol
     826            0 :  if (nsppol==2) then
     827            0 :    ABI_WARNING("nsppol==2 with coupling is still under development")
     828              :  end if
     829              : 
     830            0 :  if (nprocs > 1) then
     831            0 :    ABI_WARNING("Scalapack does not provide ZGEEV, diagonalization is done in sequential!")
     832              :  end if
     833              : 
     834            0 :  exc_size = 2*SUM(BSp%nreh)
     835            0 :  nstates  = BSp%nstates
     836            0 :  do_full_diago = (exc_size==nstates)
     837            0 :  ABI_CHECK(do_full_diago,"Partial diago not coded yet")
     838              : 
     839            0 :  bseig_fname = BS_files%out_eig
     840            0 :  if (BS_files%in_eig /= BSE_NOFILE) then
     841            0 :    ABI_ERROR("BS_files%in_eig is defined!")
     842              :  end if
     843              :  !
     844              :  ! Only master performs the diagonalization since ScaLAPACK does not provide the parallel version of ZGEEV.
     845            0 :  if (my_rank/=master) GOTO 10
     846              : 
     847            0 :  write(msg,'(a,i0)')' Direct diagonalization of the full excitonic Hamiltonian, Matrix size= ',exc_size
     848            0 :  call wrtout([std_out, ab_out], msg)
     849              : 
     850            0 :  bsize_ham = 2*dp*exc_size**2
     851            0 :  write(msg,'(a,f9.2,a)')' Allocating full excitonic Hamiltonian. Memory requested: ',bsize_ham*b2Gb,' Gb. '
     852            0 :  call wrtout(std_out, msg)
     853              : 
     854            0 :  ABI_MALLOC_OR_DIE(exc_ham,(exc_size,exc_size), ierr)
     855              : 
     856              :  write(msg,'(3a,f8.1,3a,f8.1,a)')&
     857            0 :   ' Allocating excitonic eigenvalues and eigenvectors. ',ch10,&
     858            0 :   ' Memory-space requested: ',2*dp*exc_size*b2Gb,' Gb. ',ch10,&
     859            0 :   ' Memory-space requested: ',bsize_ham*b2Gb,' Gb. '
     860            0 :  call wrtout(std_out, msg)
     861              : 
     862            0 :  ABI_MALLOC_OR_DIE(exc_ene,(exc_size), ierr)
     863              : 
     864            0 :  if (BS_files%in_hreso /= BSE_NOFILE) then
     865            0 :    hreso_fname = BS_files%in_hreso
     866              :  else
     867            0 :    hreso_fname = BS_files%out_hreso
     868              :  end if
     869              : 
     870            0 :  call wrtout(std_out,' Reading resonant excitonic Hamiltonian from '//TRIM(hreso_fname))
     871              : 
     872            0 :  if (open_file(hreso_fname,msg,newunit=hreso_unt,form="unformatted",status="old",action="read") /= 0) then
     873            0 :    ABI_ERROR(msg)
     874              :  end if
     875              :  !
     876              :  ! Read the header and perform consistency checks.
     877            0 :  call exc_read_bshdr(hreso_unt,Bsp,fform,ierr)
     878            0 :  ABI_CHECK(ierr==0,"Wrong header")
     879              :  !
     880              :  ! Construct resonant and anti-resonant part of the excitonic Hamiltonian using Hermiticity. File is always in double precision.
     881              :  ! Fill exc_ham with ( R  0 )
     882              :  !                   ( 0 -R*)
     883              : !BEGINDEBUG
     884            0 :  exc_ham = HUGE(one)
     885              : !ENDDEBUG
     886              : 
     887            0 :  row_sign=-1; diago_is_real=(.not.BSp%have_complex_ene)
     888            0 :  call exc_fullh_from_blocks(hreso_unt,"Resonant",nsppol,row_sign,diago_is_real,BSp%nreh,exc_size,exc_ham)
     889            0 :  close(hreso_unt)
     890              : 
     891            0 :  if (BS_files%in_hcoup /= BSE_NOFILE) then
     892            0 :    hcoup_fname =  BS_files%in_hcoup
     893              :  else
     894            0 :    hcoup_fname =  BS_files%out_hcoup
     895              :  end if
     896              : 
     897            0 :  call wrtout(std_out,' Reading coupling excitonic Hamiltonian from '//TRIM(hcoup_fname))
     898            0 :  if (open_file(hcoup_fname,msg,newunit=hcoup_unt,form="unformatted",status="old",action="read") /= 0) then
     899            0 :    ABI_ERROR(msg)
     900              :  end if
     901              :  !
     902              :  ! Read the header and perform consistency checks.
     903            0 :  call exc_read_bshdr(hcoup_unt,Bsp,fform,ierr)
     904            0 :  ABI_CHECK(ierr==0,"Wrong header")
     905              :  !
     906              :  ! Fill exc_ham with ( 0  C) to have ( R   C )
     907              :  !                   (-C* 0)         (-C* -R*)
     908            0 :  row_sign=-1; diago_is_real=(.not.BSp%have_complex_ene) ! not used here
     909            0 :  call exc_fullh_from_blocks(hcoup_unt,"Coupling",nsppol,row_sign,diago_is_real,BSp%nreh,exc_size,exc_ham)
     910              : 
     911              : !BEGINDEBUG
     912            0 :  if (ANY(exc_ham==HUGE(one))) then
     913            0 :    write(msg,'(a,2(1x,i0))')"There is a bug in exc_fullh_from_blocks",COUNT(exc_ham==HUGE(one)),exc_size**2
     914            0 :    ABI_WARNING(msg)
     915            0 :    bsz = Bsp%nreh(1)
     916            0 :    ABI_MALLOC(cbuff,(bsz,bsz))
     917            0 :    block=0
     918            0 :    do jj=1,2*nsppol
     919            0 :      do ii=1,2*nsppol
     920            0 :        block=block+1
     921            0 :        bs1 = (ii-1)*bsz+1
     922            0 :        bs2 = (jj-1)*bsz+1
     923            0 :        cbuff = exc_ham(bs1:bs1+bsz-1,bs2:bs2+bsz-1)
     924            0 :        if (ANY(cbuff==HUGE(one))) then
     925            0 :          write(std_out,*)" for block ",ii,jj," found ",COUNT(cbuff==HUGE(one))," wrong entries"
     926              :        end if
     927              :      end do
     928              :    end do
     929              : 
     930            0 :    ABI_FREE(cbuff)
     931            0 :    ABI_ERROR("Cannot continue")
     932              :  end if
     933              : !ENDDEBUG
     934              : 
     935            0 :  close(hcoup_unt)
     936              :  !
     937              :  ! ======================================================
     938              :  ! ==== Calculate right eigenvectors and eigenvalues ====
     939              :  ! ======================================================
     940            0 :  ABI_MALLOC_OR_DIE(exc_rvect,(exc_size,exc_size), ierr)
     941              : 
     942            0 :  if (do_full_diago) then
     943            0 :    call wrtout(std_out,"Complete direct diagonalization with xgeev...")
     944            0 :    call xgeev("No_left_eigen","Vectors",exc_size,exc_ham,exc_size,exc_ene,vl_dpc,ldvl,exc_rvect,exc_size)
     945              :  else
     946            0 :    ABI_ERROR("Not implemented error")
     947              :  end if
     948              : 
     949            0 :  ABI_FREE(exc_ham)
     950              : 
     951            0 :  exc_gap    = MINVAL(ABS(DBLE (exc_ene(1:nstates))))
     952            0 :  exc_maxene = MAXVAL(ABS(DBLE (exc_ene(1:nstates))))
     953            0 :  temp       = MAXVAL(ABS(AIMAG(exc_ene(1:nstates))))
     954              : 
     955              :  write(msg,'(2(a,f7.2,2a),a,es9.2,2a)')&
     956            0 :   " First excitonic eigenvalue: ",exc_gap*Ha_eV,   " [eV].",ch10,&
     957            0 :   " Last  excitonic eigenvalue: ",exc_maxene*Ha_eV," [eV].",ch10,&
     958            0 :   " Largest imaginary part:     ",temp*Ha_eV,      " [eV] ",ch10
     959            0 :  call wrtout([std_out, ab_out], msg)
     960              : 
     961            0 :  nene_printed = MIN(32*nsppol,nstates); if (prtvol>10) nene_printed = nstates
     962              : 
     963              :  ! This is not portable as the the eigenvalues calculated by ZGEEV are not sorted.
     964              :  ! Even two subsequent calculations with the same input on the same machine
     965              :  ! might produce different orderings. Might sort the eigenvalues though, just for printing.
     966              : 
     967            0 :  write(msg,'(a,i0)')' Complex excitonic eigenvalues in eV up to n= ',nene_printed
     968            0 :  call wrtout(std_out,msg)
     969              : 
     970            0 :  do it=0,(nene_printed-1)/4
     971            0 :    write(msg,'(8f10.5)') ( exc_ene(ii)*Ha_eV, ii=1+it*4,MIN(it*4+4,nene_printed) )
     972            0 :    call wrtout(std_out,msg)
     973              :  end do
     974              : 
     975            0 :  call wrtout(std_out,ch10//" Writing eigenvalues and eigenvectors on file "//TRIM(bseig_fname))
     976              : 
     977            0 :  if (open_file(bseig_fname,msg,newunit=eig_unt,form="unformatted",action="write") /= 0) then
     978            0 :    ABI_ERROR(msg)
     979              :  end if
     980              : 
     981              : !YG : new version with lifetime
     982            0 :  do_ep_lifetime = .FALSE.
     983            0 :  write(eig_unt) do_ep_lifetime
     984              : 
     985            0 :  write(eig_unt)exc_size,nstates
     986            0 :  write(eig_unt)CMPLX(exc_ene(1:nstates),kind=dp)
     987            0 :  do mi=1,nstates
     988            0 :    write(eig_unt) exc_rvect(:,mi)
     989              :  end do
     990              : 
     991            0 :  ABI_FREE(exc_ene)
     992              : 
     993            0 :  ABI_MALLOC_OR_DIE(ovlp,(nstates,nstates), ierr)
     994              : 
     995            0 :  call wrtout(std_out,' Calculating overlap matrix... ')
     996              : 
     997              :  !do itp=1,nstates
     998              :  !  do it=1,nstates
     999              :  !    ovlp(it,itp) = xdotc(exc_size,exc_rvect(:,it),1,exc_rvect(:,itp),1)
    1000              :  !  end do
    1001              :  !end do
    1002            0 :  call xgemm("C","N",exc_size,nstates,nstates,cone,exc_rvect,exc_size,exc_rvect,exc_size,czero,ovlp,nstates)
    1003            0 :  ABI_FREE(exc_rvect)
    1004              : 
    1005            0 :  call wrtout(std_out," Inverting overlap matrix... ")
    1006              : 
    1007              :  ! Version for generic complex matrix.
    1008              :  !call xginv(ovlp,exc_size)
    1009              : 
    1010              :  ! The overlap is Hermitian definite positive.
    1011            0 :  call xhdp_invert("Upper",ovlp,nstates)
    1012            0 :  call hermitianize(ovlp,"Upper")
    1013              : 
    1014            0 :  call wrtout(std_out,' Writing overlap matrix S^-1 on file: '//TRIM(bseig_fname))
    1015              : 
    1016            0 :  do it=1,nstates
    1017            0 :    write(eig_unt) CMPLX(ovlp(:,it),kind=dp)
    1018              :  end do
    1019              : 
    1020            0 :  ABI_FREE(ovlp)
    1021              : 
    1022            0 :  close(eig_unt)
    1023              : 
    1024            0 : 10 call xmpi_barrier(comm)
    1025              : 
    1026            0 : end subroutine exc_diago_coupling
    1027              : !!***
    1028              : 
    1029              : !----------------------------------------------------------------------
    1030              : 
    1031              : !!****f* m_exc_diago/exc_diago_coupling_hegv
    1032              : !! NAME
    1033              : !!  exc_diago_coupling_hegv
    1034              : !!
    1035              : !! FUNCTION
    1036              : !!  Calculate excitonic eigenvalues and eigenvectors by performing a direct diagonalization.
    1037              : !!  of the non Hermitian excitonic Hamiltonian (resonant + coupling).
    1038              : !!
    1039              : !! INPUTS
    1040              : !!  bseig_fname=The name of the output file.
    1041              : !!  Bsp
    1042              : !!    neh=Rank of the resonant block of the Hamiltoninan (equal to the rank of the coupling part)
    1043              : !!  comm=MPI communicator.
    1044              : !!  BS_files<excfiles>=Datatype storing names and files used in the Bethe-Salpeter code.
    1045              : !!
    1046              : !! OUTPUT
    1047              : !!  Excitonic eigenvectors and eigenvalues are written to file BS_files%out_eig.
    1048              : !!
    1049              : !! SOURCE
    1050              : 
    1051            1 : subroutine exc_diago_coupling_hegv(Bsp,BS_files,Hdr_bse,prtvol,comm)
    1052              : 
    1053              : !Arguments ------------------------------------
    1054              : !scalars
    1055              :  integer,intent(in) :: comm,prtvol
    1056              :  type(excparam),intent(in) :: BSp
    1057              :  type(excfiles),intent(in) :: BS_files
    1058              :  type(Hdr_type),intent(in) :: Hdr_bse
    1059              : 
    1060              : !Local variables ------------------------------
    1061              : !scalars
    1062              :  integer,parameter :: master=0
    1063              :  integer(i8b) :: bsize_ham
    1064              :  integer :: itype,il,iu,spin,row1,row2,pad_r1,pad_r2,neh1,neh2
    1065              :  integer :: ii,exc_size,hreso_unt,hcoup_unt,eig_unt
    1066              :  integer :: fform,neig_found,nstates, mi,it,nprocs,my_rank
    1067              :  integer :: nene_printed,nsppol,row_sign,ierr
    1068              :  real(dp) :: exc_gap,exc_maxene,abstol,vl,vu
    1069              :  character(len=500) :: msg
    1070              :  character(len=fnlen) :: reso_fname,coup_fname,bseig_fname
    1071              :  logical :: use_scalapack,do_full_diago,diago_is_real, do_ep_lifetime
    1072              : !arrays
    1073            1 :  real(dp),allocatable :: exc_ene(:) !,test_ene(:)
    1074            1 :  complex(dp),allocatable :: exc_ham(:,:),exc_rvect(:,:),fmat(:,:),ovlp(:,:)
    1075              : #if defined HAVE_LINALG_SCALAPACK && defined HAVE_MPI_IO
    1076              :  integer,parameter :: istwfk1=1
    1077              :  integer :: amode,mpi_fh,tbloc,mene_found,mpi_err,my_nel,nsblocks
    1078              :  integer :: iloc,jloc,iglob,jglob,etype,slk_mask_type,offset_err,el,rrs_kind,ccs_kind
    1079              :  !integer :: max_r,max_c
    1080              :  integer(XMPI_OFFSET_KIND) :: ehdr_offset,fmarker,my_offset
    1081              :  integer :: gsub(2,2)
    1082              :  logical,parameter :: is_fortran_file=.TRUE.
    1083              :  complex(dp) :: ctmp
    1084              :  integer,allocatable :: sub_block(:,:,:)
    1085              :  integer,pointer :: myel2loc(:,:)
    1086              :  complex(dp),allocatable :: tmp_cbuffer(:)
    1087              :  character(50) :: uplo
    1088              :  real(dp),external :: PDLAMCH
    1089              :  type(slkmat_dp_t) :: Slk_F,Slk_Hbar,Slk_vec,Slk_ovlp !,Slk_tmp
    1090              :  type(slk_processor_t) :: Slk_processor
    1091              : #endif
    1092              : !************************************************************************
    1093              : 
    1094            1 :  my_rank = xmpi_comm_rank(comm); nprocs  = xmpi_comm_size(comm)
    1095              : 
    1096            1 :  nsppol = Hdr_bse%nsppol
    1097            1 :  if (nsppol==2) then
    1098            0 :    ABI_WARNING("nsppol==2 is still under development!")
    1099              :  end if
    1100              : 
    1101            1 :  neh1 = BSp%nreh(1); neh2=neh1
    1102              :  if (nsppol==2) neh2 = BSp%nreh(2)
    1103              : 
    1104            2 :  exc_size = 2*SUM(Bsp%nreh)
    1105            1 :  nstates  = Bsp%nstates
    1106            1 :  do_full_diago=(nstates==exc_size)
    1107              : 
    1108            1 :  write(msg,'(a,i0)')'. Direct diagonalization of the full excitonic Hamiltonian, Matrix size= ',exc_size
    1109            3 :  call wrtout([std_out, ab_out], msg)
    1110              : 
    1111            1 :  bseig_fname = BS_files%out_eig
    1112            1 :  if (BS_files%in_eig /= BSE_NOFILE) then
    1113            0 :    ABI_ERROR("BS_files%in_eig is defined!")
    1114              :  end if
    1115              : 
    1116            1 :  if (BS_files%in_hreso /= BSE_NOFILE) then
    1117            1 :    reso_fname = BS_files%in_hreso
    1118              :  else
    1119            0 :    reso_fname = BS_files%out_hreso
    1120              :  end if
    1121            1 :  call wrtout(std_out,' Reading resonant excitonic Hamiltonian from '//TRIM(reso_fname))
    1122              : 
    1123            1 :  if (BS_files%in_hcoup /= BSE_NOFILE) then
    1124            0 :    coup_fname =  BS_files%in_hcoup
    1125              :  else
    1126            1 :    coup_fname =  BS_files%out_hcoup
    1127              :  end if
    1128            1 :  call wrtout(std_out,' Reading coupling excitonic Hamiltonian from '//TRIM(coup_fname))
    1129              : 
    1130              :  ! TODO: Reintegrate SCALAPACK: use new format
    1131              : ! --- !ERROR
    1132              : ! src_file: m_exc_diago.F90
    1133              : ! src_line: 1398
    1134              : ! mpi_rank: 0
    1135              : ! message: |
    1136              : !     SET_VIEW
    1137              : !     Other I/O error , error stack:
    1138              : !     ADIO_Set_view(48):  **iobadoverlap displacements of filetype must be in a monotonically nondecreasing order
    1139              : ! ...
    1140              : 
    1141            1 :  use_scalapack = .FALSE.
    1142              : #ifdef HAVE_LINALG_SCALAPACK
    1143              :  ! This is alway false. I use this trick so that the second case below is always compiled
    1144              :  ! to avoid regressions.
    1145              :  use_scalapack = nprocs > 1 .and. nsppol > 5
    1146              : #endif
    1147              :  !use_scalapack = .FALSE.
    1148              :  !use_scalapack = .TRUE.
    1149              : 
    1150            1 :  if (.not.use_scalapack .and. my_rank/=master) GOTO 10
    1151              : 
    1152            3 :  ABI_MALLOC_OR_DIE(exc_ene,(exc_size), ierr)
    1153              : 
    1154              :  SELECT CASE (use_scalapack)
    1155              : 
    1156              :  CASE (.FALSE.)
    1157            1 :    write(msg,'(a)')". Using LAPACK sequential version to solve FHv = ev with H positive definite. "
    1158            3 :    call wrtout([std_out, ab_out], msg)
    1159              : 
    1160            1 :    bsize_ham = 2*dp*exc_size**2
    1161            1 :    write(msg,'(a,f9.2,a)')' Allocating full excitonic Hamiltonian. Memory requested: ',2*bsize_ham*b2Gb,' Gb. '
    1162            1 :    call wrtout(std_out, msg)
    1163              : 
    1164            4 :    ABI_MALLOC_OR_DIE(exc_ham,(exc_size,exc_size), ierr)
    1165            3 :    ABI_MALLOC_OR_DIE(fmat,(exc_size,exc_size), ierr)
    1166              : 
    1167              :    write(msg,'(3a,f8.1,3a,f8.1,a)')&
    1168            1 :     ' Allocating excitonic eigenvalues and eigenvectors. ',ch10,&
    1169            1 :     ' Memory-space requested: ',2*dp*exc_size*b2Gb,' Gb. ',ch10,&
    1170            2 :     ' Memory-space requested: ',bsize_ham*b2Gb,' Gb. '
    1171            1 :    call wrtout(std_out, msg)
    1172              : 
    1173            1 :    if (open_file(reso_fname,msg,newunit=hreso_unt,form="unformatted",status="old",action="read") /= 0) then
    1174            0 :      ABI_ERROR(msg)
    1175              :    end if
    1176              :    !
    1177              :    ! Read the header and perform consistency checks.
    1178            1 :    call exc_read_bshdr(hreso_unt,Bsp,fform,ierr)
    1179            1 :    ABI_CHECK(ierr==0,"Wrong header")
    1180              :    !
    1181              :    ! Construct Hbar = ( R   C )
    1182              :    !                  ( C*  R*)
    1183              :    !
    1184            1 :    row_sign=+1; diago_is_real=(.not.BSp%have_complex_ene)
    1185            1 :    call exc_fullh_from_blocks(hreso_unt,"Resonant",nsppol,row_sign,diago_is_real,Bsp%nreh,exc_size,exc_ham)
    1186            1 :    close(hreso_unt)
    1187              : 
    1188            1 :    if (open_file(coup_fname,msg,newunit=hcoup_unt,form="unformatted",status="old",action="read") /= 0) then
    1189            0 :      ABI_ERROR(msg)
    1190              :    end if
    1191              :    !
    1192              :    ! Read the header and perform consistency checks.
    1193            1 :    call exc_read_bshdr(hcoup_unt,Bsp,fform,ierr)
    1194            1 :    ABI_CHECK(ierr==0,"Wrong header")
    1195              : 
    1196            1 :    row_sign=+1; diago_is_real=(.not.BSp%have_complex_ene) ! not used here.
    1197            1 :    call exc_fullh_from_blocks(hcoup_unt,"Coupling",nsppol,row_sign,diago_is_real,Bsp%nreh,exc_size,exc_ham)
    1198            1 :    close(hcoup_unt)
    1199              : 
    1200              : !#ifdef DEV_MG_DEBUG_THIS
    1201              : !write(666)exc_ham
    1202              : !#endif
    1203              :    !
    1204              :    ! Fill fmat = (1  0)
    1205              :    !             (0 -1)
    1206       590593 :    fmat = czero
    1207            2 :    do spin=1,nsppol
    1208            1 :      pad_r1 = (spin-1)*Bsp%nreh(1)
    1209            2 :      pad_r2 = SUM(Bsp%nreh)
    1210            1 :      if (spin==2) pad_r2 = pad_r2 + Bsp%nreh(1)
    1211          386 :      do it=1,Bsp%nreh(spin)
    1212          384 :        row1 = it + pad_r1
    1213          384 :        row2 = it + pad_r2
    1214          384 :        fmat(row1,row1) =  cone
    1215          385 :        fmat(row2,row2) = -cone
    1216              :      end do
    1217              :    end do
    1218              :    !
    1219              :    ! ==================================================
    1220              :    ! ==== Solve generalized EV problem F H u = e u ====
    1221              :    ! ==================================================
    1222              :    ! The eigenvectors Z are normalized as follows: if ITYPE = 1 or 2, Z**T*B*Z = I; if ITYPE = 3, Z**T*inv(B)*Z = I.
    1223              :    !
    1224            1 :    itype=2
    1225            1 :    if (do_full_diago) then
    1226            1 :      call wrtout(std_out," Full diagonalization with XHEGV... ")
    1227            1 :      call xhegv(itype,"Vectors","Upper",exc_size,fmat,exc_ham,exc_ene)
    1228              :    else
    1229            0 :      call wrtout(std_out," Partial diagonalization with XHEGVX... ")
    1230            0 :      ABI_MALLOC_OR_DIE(exc_rvect,(exc_size,nstates), ierr)
    1231            0 :      il=1; iu=1; abstol=zero
    1232            0 :      call xhegvx(itype,"Vectors","All","Upper",exc_size,fmat,exc_ham,vl,vu,il,iu,abstol,neig_found,exc_ene,exc_rvect,exc_size)
    1233              :    end if
    1234              : 
    1235            1 :    ABI_FREE(exc_ham)
    1236              : 
    1237            1 :    if (do_full_diago) then
    1238            4 :      ABI_MALLOC(exc_rvect,(exc_size,nstates))
    1239       590594 :      exc_rvect = fmat(:,1:nstates)
    1240              :    end if
    1241              : 
    1242            1 :    ABI_FREE(fmat)
    1243              : 
    1244            1 :    call wrtout(std_out," Writing eigenvalues and eigenvectors on file: "//TRIM(bseig_fname))
    1245              : 
    1246            1 :    if (open_file(bseig_fname,msg,newunit=eig_unt,form="unformatted",action="write") /= 0) then
    1247            0 :      ABI_ERROR(msg)
    1248              :    end if
    1249              : 
    1250            1 :    do_ep_lifetime = .FALSE.
    1251            1 :    write(eig_unt) do_ep_lifetime
    1252            1 :    write(eig_unt) exc_size, nstates
    1253          769 :    write(eig_unt) CMPLX(exc_ene(1:nstates),kind=dp)
    1254          769 :    do mi=1,nstates
    1255       590593 :      write(eig_unt) CMPLX(exc_rvect(:,mi),kind=dp)
    1256              :    end do
    1257              : 
    1258              : !#ifdef DEV_MG_DEBUG_THIS
    1259              : !   write(888)exc_rvect
    1260              : !   write(888)exc_ene
    1261              : !#endif
    1262              : 
    1263            4 :    ABI_MALLOC_OR_DIE(ovlp,(nstates,nstates), ierr)
    1264              : 
    1265            1 :    call wrtout(std_out,' Calculating overlap matrix...')
    1266              : 
    1267            1 :    call xgemm("C","N",exc_size,nstates,nstates,cone,exc_rvect,exc_size,exc_rvect,exc_size,czero,ovlp,nstates)
    1268            1 :    ABI_FREE(exc_rvect)
    1269              : 
    1270              : !#ifdef DEV_MG_DEBUG_THIS
    1271              : !write(667)ovlp
    1272              : !#endif
    1273              : 
    1274            1 :    call wrtout(std_out," Inverting overlap matrix... ")
    1275              :    !
    1276              :    ! The overlap is Hermitian definite positive.
    1277            1 :    call xhdp_invert("Upper",ovlp,nstates)
    1278            1 :    call hermitianize(ovlp,"Upper")
    1279              : 
    1280              :    ! Version for generic complex matrix.
    1281              :    !call xginv(ovlp,nstates)
    1282              : 
    1283              : !#ifdef DEV_MG_DEBUG_THIS
    1284              : !write(668,*)ovlp
    1285              : !#endif
    1286              : 
    1287            1 :    call wrtout(std_out,' Writing overlap matrix O^-1 on file: '//TRIM(bseig_fname))
    1288          769 :    do it=1,nstates
    1289          769 :      write(eig_unt) ovlp(:,it)
    1290              :    end do
    1291              : 
    1292            1 :    ABI_FREE(ovlp)
    1293            3 :    close(eig_unt)
    1294              : 
    1295              :  CASE (.TRUE.)
    1296              : 
    1297              : #if defined HAVE_LINALG_SCALAPACK && defined HAVE_MPI_IO
    1298              :    !
    1299              :    ! Init scaLAPACK matrix Hbar = ( R   C )
    1300              :    !                              ( C*  R*)
    1301              :    ! Battle plan:
    1302              :    !   Here the reading is complicated by the fact that R and C are stored on two different files
    1303              :    !   and moreover the matrices are in packed storage mode.
    1304              :    !   For initializing the local part of the resonant and anti-resonant block we have to allocate
    1305              :    !   a temporary buffer. Then we read the buffer from file and the corresponding elements of the
    1306              :    !   scaLAPACK matrix are initialized taking into account the symmetries of R (Hermitian)
    1307              :    !   The same procedure is used to read the coupling and the anti-coupling part (Symmetric).
    1308              :    !
    1309              :    tbloc=50
    1310              :    write(msg,'(2(a,i0))')". Using MPI-IO + scaLAPACK version with nprocs= ",nprocs,"; block size= ",tbloc
    1311              :    call wrtout([std_out, ab_out], msg, do_flush=.True.)
    1312              :    !
    1313              :    ! Init scaLAPACK environment.
    1314              :    call Slk_processor%init(comm)
    1315              :    !
    1316              :    ! Open the Resonant file with MPI-IO and skip the record.
    1317              :    amode=MPI_MODE_RDONLY
    1318              : 
    1319              :    call MPI_FILE_OPEN(comm, reso_fname, amode, MPI_INFO_NULL, mpi_fh, mpi_err)
    1320              :    msg = " MPI_IO error opening file: "//TRIM(reso_fname)
    1321              :    ABI_CHECK_MPI(mpi_err,msg)
    1322              :    !
    1323              :    ! Skip the header and find the offset for reading the matrix.
    1324              :    call exc_skip_bshdr_mpio(mpi_fh,xmpio_collective,ehdr_offset)
    1325              :    !
    1326              :    ! Read  = ( R  - )
    1327              :    !         ( -  R*)
    1328              :    call Slk_Hbar%init(exc_size,exc_size,Slk_processor,istwfk1)
    1329              : 
    1330              :    nullify(myel2loc)
    1331              :    nsblocks=nsppol
    1332              :    ABI_MALLOC(sub_block,(2,2,nsblocks))
    1333              :    ABI_CHECK(nsppol==1,"nsppol==2 not coded yet")
    1334              : 
    1335              :    call slk_single_fview_read_mask(Slk_Hbar,rrs_of_glob,offset_in_file,nsblocks,sub_block,my_nel,myel2loc,etype,slk_mask_type,&
    1336              : &    offset_err,is_fortran_file)
    1337              : 
    1338              :    if (offset_err/=0) then
    1339              :      write(msg,"(3a)")&
    1340              : &      " Global position index cannot be stored in a standard Fortran integer ",ch10,&
    1341              : &      " Excitonic matrix cannot be read with a single MPI-IO call."
    1342              :      ABI_ERROR(msg)
    1343              :    end if
    1344              : 
    1345              :    ! Shift the offset because the view starts at the fist matrix element!
    1346              :    ! TODO should rationalize the treatment of the offset
    1347              :    my_offset = ehdr_offset + xmpio_bsize_frm
    1348              :    call MPI_FILE_SET_VIEW(mpi_fh, my_offset, etype, slk_mask_type, 'native', MPI_INFO_NULL, mpi_err)
    1349              :    ABI_CHECK_MPI(mpi_err,"SET_VIEW")
    1350              : 
    1351              :    call MPI_TYPE_FREE(slk_mask_type,mpi_err)
    1352              :    ABI_CHECK_MPI(mpi_err,"MPI_TYPE_FREE")
    1353              :    !
    1354              :    ! Read my portion of the R,-R* sublocks and store the values in a temporary buffer.
    1355              :    ABI_MALLOC_OR_DIE(tmp_cbuffer,(my_nel), ierr)
    1356              : 
    1357              :    call xmpi_barrier(comm)
    1358              : 
    1359              :    call MPI_FILE_READ_ALL(mpi_fh, tmp_cbuffer, my_nel, MPI_DOUBLE_COMPLEX, MPI_STATUS_IGNORE, mpi_err)
    1360              :    ABI_CHECK_MPI(mpi_err,"READ_ALL")
    1361              :    !
    1362              :    ! Symmetrize my Resonant part.
    1363              :    do el=1,my_nel
    1364              :      iloc = myel2loc(1,el)
    1365              :      jloc = myel2loc(2,el)
    1366              :      call Slk_Hbar%loc2glob(iloc,jloc,iglob,jglob)
    1367              :      ctmp = tmp_cbuffer(el)
    1368              :      if (iglob==jglob.and..not.Bsp%have_complex_ene) ctmp = DBLE(ctmp) ! Force the diagonal to be real.
    1369              :      rrs_kind = rrs_of_glob(iglob,jglob,Slk_Hbar%size_global)
    1370              :      if (rrs_kind==1.and.jglob<iglob) then ! Lower resonant
    1371              :        ctmp = DCONJG(ctmp)
    1372              :      else if (rrs_kind==-1.and.jglob>=iglob) then  ! Lower Anti-resonant (Diagonal is included).
    1373              :        ctmp = DCONJG(ctmp)
    1374              :      end if
    1375              :      Slk_Hbar%buffer_cplx(iloc,jloc) = ctmp
    1376              :    end do
    1377              : 
    1378              :    ABI_FREE(tmp_cbuffer)
    1379              :    ABI_FREE(myel2loc)
    1380              : 
    1381              :    call MPI_FILE_CLOSE(mpi_fh, mpi_err)
    1382              :    ABI_CHECK_MPI(mpi_err,"FILE_CLOSE")
    1383              :    !
    1384              :    ! Read  = ( -  C)
    1385              :    !         (-C* -)
    1386              :    !
    1387              :    call MPI_FILE_OPEN(comm, coup_fname, amode, MPI_INFO_NULL, mpi_fh, mpi_err)
    1388              :    msg = " MPI_IO error opening file: "//TRIM(coup_fname)
    1389              :    ABI_CHECK_MPI(mpi_err,msg)
    1390              :    !
    1391              :    ! Skip the header and find the offset for reading the matrix.
    1392              :    call exc_skip_bshdr_mpio(mpi_fh,xmpio_collective,ehdr_offset)
    1393              : 
    1394              :    nullify(myel2loc)
    1395              :    call slk_single_fview_read_mask(Slk_Hbar,ccs_of_glob,offset_in_file,nsblocks,sub_block,my_nel,myel2loc,etype,slk_mask_type,&
    1396              : &    offset_err,is_fortran_file)
    1397              : 
    1398              :    ABI_FREE(sub_block)
    1399              : 
    1400              :    if (offset_err/=0) then
    1401              :      write(msg,"(3a)")&
    1402              : &      " Global position index cannot be stored in a standard Fortran integer ",ch10,&
    1403              : &      " Excitonic matrix cannot be read with a single MPI-IO call."
    1404              :      ABI_ERROR(msg)
    1405              :    end if
    1406              :    !
    1407              :    ! Shift the offset because the view starts at the fist matrix element!
    1408              :    ! TODO should rationalize the treatment of the offset so that the client code
    1409              :    ! will automatically receive my_offset.
    1410              :    my_offset = ehdr_offset + xmpio_bsize_frm
    1411              :    call MPI_FILE_SET_VIEW(mpi_fh, my_offset, etype, slk_mask_type, 'native', MPI_INFO_NULL, mpi_err)
    1412              :    ABI_CHECK_MPI(mpi_err,"SET_VIEW")
    1413              : 
    1414              :    call MPI_TYPE_FREE(slk_mask_type,mpi_err)
    1415              :    ABI_CHECK_MPI(mpi_err,"MPI_TYPE_FREE")
    1416              :    !
    1417              :    ! Read my portion of the C-C* blocks and store the values in a temporary buffer.
    1418              :    ABI_MALLOC_OR_DIE(tmp_cbuffer,(my_nel), ierr)
    1419              : 
    1420              :    call MPI_FILE_READ_ALL(mpi_fh, tmp_cbuffer, my_nel, MPI_DOUBLE_COMPLEX, MPI_STATUS_IGNORE, mpi_err)
    1421              :    ABI_CHECK_MPI(mpi_err,"READ_ALL")
    1422              :    !
    1423              :    ! Symmetrize my coupling part.
    1424              :    ! Coupling block is symmetric => No symmetrization of the lower triangle.
    1425              :    do el=1,my_nel
    1426              :      iloc = myel2loc(1,el)
    1427              :      jloc = myel2loc(2,el)
    1428              :      call Slk_Hbar%loc2glob(iloc, jloc, iglob, jglob)
    1429              :      ccs_kind = ccs_of_glob(iglob,jglob,Slk_Hbar%size_global)
    1430              :      ctmp = tmp_cbuffer(el)
    1431              :      if (ccs_kind==-1) ctmp = DCONJG(ctmp) ! Anti-coupling (Diagonal is included).
    1432              :      Slk_Hbar%buffer_cplx(iloc,jloc) = ctmp
    1433              :    end do
    1434              : 
    1435              :    ABI_FREE(tmp_cbuffer)
    1436              :    ABI_FREE(myel2loc)
    1437              : 
    1438              :    !max_r=20; max_c=10
    1439              :    !call print_arr(Slk_Hbar%buffer_cplx,max_r=max_r,max_c=max_c,unit=std_out)
    1440              : 
    1441              : !#ifdef DEV_MG_DEBUG_THIS
    1442              : !   ABI_MALLOC(exc_ham,(exc_size,exc_size))
    1443              : !   read(666)exc_ham
    1444              : !
    1445              : !   write(std_out,*)"Error Hbar: ",MAXVAL(ABS(exc_ham-Slk_Hbar%buffer_cplx))
    1446              : !   ABI_FREE(exc_ham)
    1447              : !#endif
    1448              : 
    1449              :    call MPI_FILE_CLOSE(mpi_fh, mpi_err)
    1450              :    ABI_CHECK_MPI(mpi_err,"FILE_CLOSE")
    1451              :    !
    1452              :    ! Init scaLAPACK matrix F
    1453              :    call Slk_F%init(exc_size,exc_size,Slk_processor,istwfk1)
    1454              :    !
    1455              :    ! Global F = (1  0)
    1456              :    !            (0 -1)
    1457              :    do jloc=1,Slk_F%size_local(2)
    1458              :      do iloc=1,Slk_F%size_local(1)
    1459              :        call Slk_F%loc2glob(iloc, jloc, iglob, jglob)
    1460              :        if (iglob==jglob) then
    1461              :          if (iglob<=SUM(Bsp%nreh)) then
    1462              :            Slk_F%buffer_cplx(iloc,jloc) =  cone
    1463              :          else
    1464              :            Slk_F%buffer_cplx(iloc,jloc) = -cone
    1465              :          end if
    1466              :        else
    1467              :          Slk_F%buffer_cplx(iloc,jloc) =  czero
    1468              :        end if
    1469              :      end do
    1470              :    end do
    1471              :    !
    1472              :    ! ===========================================================
    1473              :    ! ==== Solve generalized EV problem H u = F Hbar u = e u ====
    1474              :    ! ===========================================================
    1475              :    call Slk_vec%init(exc_size,exc_size,Slk_processor,istwfk1)
    1476              :    !
    1477              :    itype=2; vl=1; vu=1; il=1; iu=nstates
    1478              :    abstol=zero !ABSTOL = PDLAMCH(comm,'U')
    1479              : 
    1480              : !#if 1
    1481              :    if (do_full_diago) then
    1482              :      call slk_F%pzhegvx(itype,"Vectors","All","Upper",Slk_Hbar,vl,vu,il,iu,abstol,Slk_vec,mene_found,exc_ene)
    1483              :    else
    1484              :      ABI_WARNING("Partial diago is still under testing")
    1485              :      call slk_F%pzhegvx(itype,"Vectors","Index","Upper",Slk_Hbar,vl,vu,il,iu,abstol,Slk_vec,mene_found,exc_ene)
    1486              :    end if
    1487              : !#else
    1488              : !   call xhegv(itype,"Vectors","Upper",exc_size,Slk_F%buffer_cplx,Slk_Hbar%buffer_cplx,exc_ene)
    1489              : !   Slk_vec%buffer_cplx = Slk_F%buffer_cplx
    1490              : !#endif
    1491              : 
    1492              : !#ifdef DEV_MG_DEBUG_THIS
    1493              : !   if (PRODUCT(Slk_Hbar%size_local) /= exc_size**2) then
    1494              : !     ABI_ERROR("Wrong size")
    1495              : !   end if
    1496              : !
    1497              : !   ABI_MALLOC(exc_ham,(exc_size,exc_size))
    1498              : !   read(888)exc_ham
    1499              : !
    1500              : !   write(std_out,*)"Error rvec: ",MAXVAL(ABS(exc_ham-Slk_vec%buffer_cplx))
    1501              : !   ABI_FREE(exc_ham)
    1502              : !
    1503              : !   ABI_MALLOC(test_ene,(exc_size))
    1504              : !   read(888)test_ene
    1505              : !   write(std_out,*)"Error ene: ",MAXVAL(ABS(exc_ene-test_ene))
    1506              : !   ABI_FREE(test_ene)
    1507              : !#endif
    1508              : 
    1509              :    call Slk_F%free()
    1510              :    call Slk_Hbar%free()
    1511              : 
    1512              :    call wrtout(std_out,ch10//" Writing eigenvalues and eigenvectors on file: "//TRIM(bseig_fname))
    1513              :    !
    1514              :    ! Open the file with Fortran-IO to write the Header.
    1515              :    if (my_rank==master) then
    1516              :      if (open_file(bseig_fname,msg,newunit=eig_unt,form="unformatted",action="write") /= 0) then
    1517              :        ABI_ERROR(msg)
    1518              :      end if
    1519              : 
    1520              :      write(eig_unt) exc_size,nstates
    1521              :      write(eig_unt) CMPLX(exc_ene(1:nstates),kind=dp)
    1522              :      !do mi=1,exc_size
    1523              :      !  write(eig_unt) CMPLX(exc_rvect(:,mi),kind=dp)
    1524              :      !end do
    1525              :      close(eig_unt)
    1526              :    end if
    1527              :    !
    1528              :    ! Open the file with MPI-IO and write the distributed eigevectors.
    1529              :    call xmpi_barrier(comm)
    1530              :    amode=MPI_MODE_RDWR
    1531              :    call MPI_FILE_OPEN(comm, bseig_fname, amode, MPI_INFO_NULL, mpi_fh, mpi_err)
    1532              :    ABI_CHECK_MPI(mpi_err,"FILE_OPEN: "//TRIM(bseig_fname))
    1533              :    !
    1534              :    ! Skip the header and find the offset for writing the matrix.
    1535              :    ehdr_offset=0
    1536              :    !call hdr_mpio_skip(mpi_fh,fform,ehdr_offset)
    1537              : 
    1538              :    call xmpio_read_frm(mpi_fh,ehdr_offset,xmpio_collective,fmarker,mpi_err)
    1539              :    write(std_out,*)" fmarker1 = ",fmarker
    1540              :    call xmpio_read_frm(mpi_fh,ehdr_offset,xmpio_collective,fmarker,mpi_err)
    1541              :    write(std_out,*)" fmarker2 = ",fmarker
    1542              : 
    1543              :    write(std_out,*)" Writing nstates ",nstates
    1544              :    gsub(:,1) = (/1,1/)
    1545              :    gsub(:,2) = (/exc_size,nstates/)
    1546              :    call slk_write(Slk_vec,"All",is_fortran_file,mpi_fh=mpi_fh,offset=ehdr_offset,glob_subarray=gsub)
    1547              : 
    1548              :    call wrtout(std_out,' Calculating overlap matrix... ')
    1549              :    if (.not.do_full_diago) then
    1550              :      ABI_ERROR(" Init of Slk_ovlp is wrong")
    1551              :    end if
    1552              : 
    1553              :    call Slk_ovlp%init(exc_size,exc_size,Slk_processor,istwfk1)
    1554              : 
    1555              :    ! Calculate the overlap matrix.
    1556              :    ! FIXME
    1557              :    ! The ESLL manual says that "matrices matrix1 and matrix2 must have no common elements;
    1558              :    ! otherwise, results are unpredictable."
    1559              :    ! However the official scaLAPACK documentation does not report this (severe) limitation.
    1560              : 
    1561              :    !call Slk_tmp%init(exc_size,exc_size,Slk_processor,istwfk1)
    1562              :    !Slk_tmp%buffer_cplx = Slk_vec%buffer_cplx
    1563              :    !call slk_pgemm("C","N",Slk_tmp,cone,Slk_vec,czero,Slk_ovlp)
    1564              :    !call Slk_tmp%free()
    1565              : 
    1566              :    call slk_pgemm("C","N",Slk_vec,cone,Slk_vec,czero,Slk_ovlp)
    1567              : 
    1568              : !#ifdef DEV_MG_DEBUG_THIS
    1569              : !   ABI_MALLOC(exc_ham,(exc_size,exc_size))
    1570              : !   read(667)exc_ham
    1571              : !
    1572              : !   write(std_out,*)"Error Ovlp: ",MAXVAL(ABS(exc_ham-Slk_ovlp%buffer_cplx))
    1573              : !   !Slk_ovlp%buffer_cplx = exc_ham
    1574              : !#endif
    1575              : 
    1576              :    !max_r=20; max_c=10
    1577              :    !call print_arr(Slk_ovlp%buffer_cplx,max_r=max_r,max_c=max_c,unit=std_out)
    1578              : 
    1579              :    call Slk_vec%free()
    1580              : 
    1581              :    call wrtout(std_out," Inverting overlap matrix... ")
    1582              :    uplo="Upper"
    1583              : 
    1584              : !#if 0
    1585              : !!DEBUG
    1586              : !   call xhdp_invert(uplo,Slk_ovlp%buffer_cplx,exc_size)
    1587              : !
    1588              : !   !call slk_symmetrize(Slk_ovlp,uplo,"Hermitian")
    1589              : !   call hermitianize(Slk_ovlp%buffer_cplx,uplo)
    1590              : !
    1591              : !   exc_ham = MATMUL(exc_ham,Slk_ovlp%buffer_cplx)
    1592              : !   do it=1,exc_size
    1593              : !     exc_ham(it,it) = exc_ham(it,it) - cone
    1594              : !   end do
    1595              : !
    1596              : !   write(std_out,*)"Error Inversion: ",MAXVAL(ABS(exc_ham))
    1597              : !   ABI_FREE(exc_ham)
    1598              : !!END DEBUG
    1599              : !
    1600              : !#else
    1601              :    ! call Slk_ovlp%hpd_invert(uplo)
    1602              :    ! call hermitianize(Slk_ovlp%buffer_cplx,uplo)
    1603              :    ! !call slk_symmetrize(Slk_ovlp,uplo,"Hermitian")
    1604              : 
    1605              :    call Slk_ovlp%invert()  ! Version for generic complex matrix.
    1606              : !#endif
    1607              : 
    1608              : !#ifdef DEV_MG_DEBUG_THIS
    1609              : !   ABI_MALLOC(exc_ham,(exc_size,exc_size))
    1610              : !   read(668)exc_ham
    1611              : !   write(std_out,*)"Error in Inv Ovlp: ",MAXVAL(ABS(exc_ham-Slk_ovlp%buffer_cplx))
    1612              : !
    1613              : !   !exc_ham = exc_ham-Slk_ovlp%buffer_cplx
    1614              : !   !do it=1,exc_size
    1615              : !   !  if ( MAXVAL(ABS(exc_ham(:,it))) > 0.1 ) write(std_out,*)"it: ",it,exc_ham(:,it)
    1616              : !   !end do
    1617              : !
    1618              : !   !Slk_ovlp%buffer_cplx = exc_ham
    1619              : !   ABI_FREE(exc_ham)
    1620              : !
    1621              : !   !write(std_out,*)"MAX ERR",MAXVAL(ABS(Slk_ovlp%buffer_cplx - TRANSPOSE(DCONJG(Slk_ovlp%buffer_cplx))))
    1622              : !#endif
    1623              : 
    1624              :    call wrtout(std_out,' Writing overlap matrix S^-1 on file: '//TRIM(bseig_fname))
    1625              : 
    1626              :    call slk_write(Slk_ovlp,"All",is_fortran_file,mpi_fh=mpi_fh,offset=ehdr_offset)
    1627              : 
    1628              :    call MPI_FILE_CLOSE(mpi_fh, mpi_err)
    1629              :    ABI_CHECK_MPI(mpi_err,"FILE_CLOSE")
    1630              : 
    1631              :    call Slk_ovlp%free()
    1632              :    call Slk_processor%free()
    1633              : #else
    1634              :    ABI_BUG("You should not be here!")
    1635              : #endif
    1636              : 
    1637              :  END SELECT
    1638              : 
    1639          770 :  exc_gap    = MINVAL(ABS(exc_ene(1:nstates)))
    1640          770 :  exc_maxene = MAXVAL(ABS(exc_ene(1:nstates)))
    1641              : 
    1642              :  write(msg,'(2(a,f7.2,2a))')&
    1643            1 :   " First excitonic eigenvalue: ",exc_gap*Ha_eV,   " [eV].",ch10,&
    1644            2 :   " Last  excitonic eigenvalue: ",exc_maxene*Ha_eV," [eV].",ch10
    1645            3 :  call wrtout([std_out, ab_out], msg)
    1646              : 
    1647            1 :  nene_printed = MIN(32*nsppol,nstates); if (prtvol>10) nene_printed = nstates
    1648            1 :  write(msg,'(a,i0)')' Complex excitonic eigenvalues in eV up to n= ',nene_printed
    1649            1 :  call wrtout(std_out, msg)
    1650              : 
    1651            9 :  do it=0,(nene_printed-1)/4
    1652           40 :    write(msg,'(4f10.5)') ( exc_ene(ii)*Ha_eV, ii=1+it*4,MIN(it*4+4,nene_printed) )
    1653            9 :    call wrtout(std_out, msg)
    1654              :  end do
    1655              : 
    1656            1 :  ABI_FREE(exc_ene)
    1657              : 
    1658            1 : 10 call xmpi_barrier(comm)
    1659              : 
    1660            1 : end subroutine exc_diago_coupling_hegv
    1661              : !!***
    1662              : 
    1663              : !----------------------------------------------------------------------
    1664              : 
    1665              : end module m_exc_diago
    1666              : !!***
        

Generated by: LCOV version 2.3-1