LCOV - code coverage report
Current view: top level - src/71_bse - m_bse_io.F90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 24.3 % 481 117
Test Date: 2026-09-21 22:40:37 Functions: 42.9 % 14 6

            Line data    Source code
       1              : !!****m* ABINIT/m_bse_io
       2              : !! NAME
       3              : !! m_bse_io
       4              : !!
       5              : !! FUNCTION
       6              : !!  This module provides routines to read the Bethe-Salpeter Hamiltonian from file
       7              : !!
       8              : !! COPYRIGHT
       9              : !!  Copyright (C) 2008-2026 ABINIT group (MG)
      10              : !!  This file is distributed under the terms of the
      11              : !!  GNU General Public License, see ~abinit/COPYING
      12              : !!  or http://www.gnu.org/copyleft/gpl.txt .
      13              : !!
      14              : !! SOURCE
      15              : 
      16              : #if defined HAVE_CONFIG_H
      17              : #include "config.h"
      18              : #endif
      19              : 
      20              : #include "abi_common.h"
      21              : 
      22              : MODULE m_bse_io
      23              : 
      24              :  use, intrinsic :: iso_c_binding
      25              :  use defs_basis
      26              :  USE_MPI
      27              :  use m_xmpi
      28              :  use m_errors
      29              :  use m_abicore
      30              :  use netcdf
      31              :  use m_nctk
      32              :  use m_hdr
      33              : 
      34              :  use m_time,           only : cwtime
      35              :  use m_fstrings,       only : toupper
      36              :  use m_io_tools,       only : open_file
      37              :  use m_numeric_tools,  only : arth
      38              :  use m_special_funcs,  only : gaussian
      39              :  use m_bs_defs,        only : excparam
      40              :  use m_bz_mesh,        only : kmesh_t
      41              : 
      42              :  implicit none
      43              : 
      44              : #if defined HAVE_MPI1
      45              :  include 'mpif.h'
      46              : #endif
      47              : 
      48              :  private
      49              : 
      50              :  public  :: exc_read_rblock_fio      ! Reads the entire resonant sub-block from file using Fortran IO.
      51              :  public  :: exc_read_rcblock         ! Reads a distributed sub-block of the excitonic Hamiltonian from file.
      52              :  public  :: exc_fullh_from_blocks    ! Initialize the specified sub-blocks of the *full* matrix (reso+anti-reso) from file.
      53              :  public  :: rrs_of_glob              ! [+1,-1,0] if (row_glob,col_glob) belongs to the [ resonant, anti-resonant, (anti)coupling block ]
      54              :  public  :: ccs_of_glob              ! [+1,-1,0] if (row_glob,col_glob) belongs to the [ coupling, anti-coupling, (anti)resonant block ]
      55              :  public  :: offset_in_file           ! Function used to describe the way the Hamiltonian is stored on disk.
      56              :  public  :: exc_write_bshdr          ! Writes the Header of the (BSR|BSC) files storing the excitonic Hamiltonian.
      57              :  public  :: exc_read_bshdr           ! Reads the Header of the (BSR|BSC) files.
      58              :  public  :: exc_skip_bshdr           ! Skip the Header of the (BSR|BSC) files. Fortran version.
      59              :  public  :: exc_skip_bshdr_mpio      ! Skip the Header of the (BSR|BSC) files. MPI-IO  version.
      60              :  public  :: exc_read_eigen           ! Read selected energies and eigenvectors from the BSEIG file.
      61              :  public  :: exc_amplitude            ! Calculate the amplitude function F(w) = \sum_t |<t|exc_vec>|^2 \delta(ww- ene_t) where t is the eh transition.
      62              :  public  :: exc_write_optme          ! Writes the OME file storing the optical matrix elements
      63              :  public  :: exc_ham_ncwrite          ! Writes the hamiltonian in NETCDF format
      64              : !!***
      65              : 
      66              : CONTAINS  !====================================================================
      67              : !!***
      68              : 
      69              : !----------------------------------------------------------------------
      70              : 
      71              : !!****f* m_bse_io/exc_write_bshdr
      72              : !! NAME
      73              : !!  exc_write_bshdr
      74              : !!
      75              : !! FUNCTION
      76              : !!   Writes the header of the (BSR|BSC) files storing the excitonic Hamiltonian.
      77              : !!
      78              : !! INPUTS
      79              : !!  funt=Fortran unit number.
      80              : !!  Bsp<excparam>=Structure storing the parameters of the run.
      81              : !!  Hdr<hdr_type>=The abinit header.
      82              : !!
      83              : !! OUTPUT
      84              : !!  Only writing
      85              : !!
      86              : !! SOURCE
      87              : 
      88           22 : subroutine exc_write_bshdr(funt,Bsp,Hdr)
      89              : 
      90              :  !Arguments ------------------------------------
      91              :  integer,intent(in) :: funt
      92              :  type(excparam),intent(in) :: BSp
      93              :  type(hdr_type),intent(inout) :: Hdr
      94              : 
      95              : !Local variables ------------------------------
      96              : !scalars
      97              :  integer :: fform_1002 = 1002 ! TODO: change setup_bse so that Hdr_bse reflects the parameters of the run.
      98              :  integer :: ierr
      99              :  character(len=500) :: errmsg
     100              :  ! *************************************************************************
     101              : 
     102           22 :  call hdr%fort_write(funt, fform_1002, ierr)
     103           22 :  ABI_CHECK(ierr == 0, "hdr_fort_write returned ierr != 0")
     104           22 :  write(funt, err=10, iomsg=errmsg) BSp%nreh,BSp%nkbz
     105              : 
     106           22 :  return
     107              : 
     108              : ! Handle IO Error
     109              : 10 continue
     110            0 :  ABI_ERROR(errmsg)
     111              : 
     112              : end subroutine exc_write_bshdr
     113              : !!***
     114              : 
     115              : !----------------------------------------------------------------------
     116              : 
     117              : !!****f* m_bse_io/exc_read_bshdr
     118              : !! NAME
     119              : !!  exc_read_bshdr
     120              : !!
     121              : !! FUNCTION
     122              : !!  Reads the header of the (BSR|BSC) files storing the excitonic Hamiltonian.
     123              : !!  and performs basilar consistency checks.
     124              : !!
     125              : !! INPUTS
     126              : !!  funt=Unit number.
     127              : !!  Bsp<excparam>=Structure storing the parameters of the run.
     128              : !!  Hdr<hdr_type>=The abinit header.
     129              : !!
     130              : !! OUTPUT
     131              : !!  fform=Integer defining the file format.
     132              : !!  ierr=Status error.
     133              : !!
     134              : !! SOURCE
     135              : 
     136           51 : subroutine exc_read_bshdr(funt,Bsp,fform,ierr)
     137              : 
     138              :  !Arguments ------------------------------------
     139              :  integer,intent(in) :: funt
     140              :  integer,intent(out) :: fform,ierr
     141              :  type(excparam),intent(in) :: BSp
     142              : 
     143              : !Local variables ------------------------------
     144              : !scalars
     145              :  integer :: nkbz_read
     146              :  character(len=500) :: errmsg
     147           51 :  type(hdr_type) :: Hdr
     148              : !arrays
     149          102 :  integer :: nreh_read(SIZE(BSp%nreh))
     150              :  ! *************************************************************************
     151              : 
     152           51 :  ierr=0
     153              : 
     154              :  ! Read the header and perform consistency checks.
     155           51 :  call hdr%fort_read(funt, fform, rewind=.True.)
     156           51 :  ABI_CHECK(fform /= 0, "hdr_fort_read returned fform == 0")
     157              : 
     158           51 :  read(funt, err=10, iomsg=errmsg) nreh_read, nkbz_read
     159           51 :  call Hdr%free()
     160              : 
     161          104 :  if (ANY(nreh_read /= BSp%nreh)) then
     162            0 :    call wrtout(std_out,"Wrong number of e-h transitions")
     163            0 :    ierr = ierr + 1
     164              :  end if
     165              : 
     166              :  return
     167              : 
     168            0 : 10 ierr = 1
     169            0 :  ABI_WARNING(errmsg)
     170              : 
     171           51 : end subroutine exc_read_bshdr
     172              : !!***
     173              : 
     174              : !----------------------------------------------------------------------
     175              : 
     176              : !!****f* m_bse_io/exc_skip_bshdr
     177              : !! NAME
     178              : !!  exc_skip_bshdr
     179              : !!
     180              : !! FUNCTION
     181              : !!   Skip the header of the (BSR|BSC) files storing the excitonic Hamiltonian. Fortran version.
     182              : !!
     183              : !! INPUTS
     184              : !!  funt=Unit number.
     185              : !!
     186              : !! OUTPUT
     187              : !!  ierr=Status error.
     188              : !!
     189              : !! SIDE EFFECTS
     190              : !!  Skip the header.
     191              : !!
     192              : !! SOURCE
     193              : 
     194           22 : subroutine exc_skip_bshdr(funt,ierr)
     195              : 
     196              : !Arguments ------------------------------------
     197              :  integer,intent(in) :: funt
     198              :  integer,intent(out) :: ierr
     199              : 
     200              : !Local variables-------------------------------
     201              :  character(len=500) :: errmsg
     202              : ! *************************************************************************
     203              : 
     204           22 :  call hdr_skip(funt,ierr)
     205           44 :  if (ierr/=0) RETURN
     206           22 :  read(funt, err=10, iomsg=errmsg)
     207              : 
     208           22 :  return
     209              : 
     210              : ! Handle IO Error
     211              : 10 continue
     212            0 :  ierr = 0
     213            0 :  ABI_WARNING(errmsg)
     214              : 
     215              : end subroutine exc_skip_bshdr
     216              : !!***
     217              : 
     218              : !----------------------------------------------------------------------
     219              : 
     220              : !!****f* m_bse_io/exc_skip_bshdr_mpio
     221              : !! NAME
     222              : !!  exc_skip_bshdr_mpio
     223              : !!
     224              : !! FUNCTION
     225              : !!   Skip the header of the (BSR|BSC) files storing the excitonic Hamiltonian. MPI-IO version.
     226              : !!
     227              : !! INPUTS
     228              : !!  mpifh=MPI-IO file handler.
     229              : !!  at_option
     230              : !!
     231              : !! SIDE EFFECTS
     232              : !!  ehdr_offset
     233              : !!
     234              : !! SOURCE
     235              : 
     236            0 : subroutine exc_skip_bshdr_mpio(mpifh,at_option,ehdr_offset)
     237              : 
     238              :  !Arguments ------------------------------------
     239              :  integer,intent(in) :: mpifh,at_option
     240              :  integer(XMPI_OFFSET_KIND),intent(inout) :: ehdr_offset
     241              : 
     242              : !Local variables ------------------------------
     243              :  integer :: fform,ierr
     244              : #ifdef HAVE_MPI_IO
     245              :  integer(XMPI_OFFSET_KIND) :: fmarker
     246              : #endif
     247              : ! *************************************************************************
     248              : 
     249            0 :  call hdr_mpio_skip(mpifh,fform,ehdr_offset)
     250              : 
     251              : #ifdef HAVE_MPI_IO
     252            0 :  call xmpio_read_frm(mpifh,ehdr_offset,at_option,fmarker,ierr)
     253              :  !write(std_out,*)"fmarker last record ",fmarker
     254              : #else
     255              :  ABI_ERROR("You should not be here")
     256              : #endif
     257              : 
     258            0 : end subroutine exc_skip_bshdr_mpio
     259              : !!***
     260              : 
     261              : !----------------------------------------------------------------------
     262              : 
     263              : !!****f* m_bse_io/exc_read_eigen
     264              : !! NAME
     265              : !!  exc_read_eigen
     266              : !!
     267              : !! FUNCTION
     268              : !!  Read selected energies and eigenvectors from the BSEIG file.
     269              : !!
     270              : !! INPUTS
     271              : !!  eig_fname=The name of the file storing the excitonic eigenvectors.
     272              : !!  hsize=Size of the Hamiltonian.
     273              : !!  nvec=Number of excitonic states to analyze.
     274              : !!  vec_idx(nvec)=List with the indices of the excitonic states sorted in ascending order.
     275              : !!  [Bsp]<excparam>=Structure storing the parameters of the run. If present the
     276              : !!    routine will perform additional consistency checks to make sure that
     277              : !!    the content of the file is consistent with the present run.
     278              : !!
     279              : !! OUTPUT
     280              : !!  [ene_list(nvec)]=Excitonic energies
     281              : !!  vec_list(hsize,nvec)=Excitonic eigenvectors.
     282              : !!
     283              : !! SOURCE
     284              : 
     285            0 : subroutine exc_read_eigen(eig_fname,hsize,nvec,vec_idx,vec_list,ene_list,Bsp)
     286              : 
     287              : !Arguments ------------------------------------
     288              : !scalars
     289              :  integer,intent(in) :: nvec,hsize
     290              :  character(len=*),intent(in) :: eig_fname
     291              :  type(excparam),optional,intent(in) :: BSp
     292              : ! arrays
     293              :  integer,intent(in) :: vec_idx(nvec)
     294              :  real(dp),optional,intent(out) :: ene_list(nvec)
     295              :  complex(dp),intent(out) :: vec_list(hsize,nvec)
     296              : 
     297              : !Local variables ------------------------------
     298              : !scalars
     299              :  integer :: eig_unt,hsize_read,neig_read,ll,vec
     300              :  character(len=500) :: msg,errmsg
     301              : !arrays
     302              :  !real(dp),allocatable :: exc_ene(:)
     303            0 :  complex(dp),allocatable :: exc_ene_cplx(:)
     304              : ! *************************************************************************
     305              : 
     306              :  ABI_UNUSED(BSp%nline)
     307              : 
     308            0 :  if (open_file(eig_fname,msg,newunit=eig_unt,form="unformatted",status="old",action="read") /= 0) then
     309            0 :    ABI_ERROR(msg)
     310              :  end if
     311              : 
     312            0 :  read(eig_unt, err=10, iomsg=errmsg)hsize_read,neig_read
     313              :  !write(std_out,*)hsize_read, neig_read
     314              : 
     315            0 :  if (hsize_read/=hsize) then
     316            0 :    write(msg,'(a,2(1x,i0))')" hsize_read/=hsize: ",hsize_read,hsize
     317            0 :    ABI_ERROR(msg)
     318              :  end if
     319              : 
     320              :  ! Read eigenvalues, ignore possibly small imaginary part.
     321            0 :  ABI_MALLOC(exc_ene_cplx,(neig_read))
     322            0 :  read(eig_unt, err=10, iomsg=errmsg) exc_ene_cplx
     323              : 
     324            0 :  if (PRESENT(ene_list)) then
     325            0 :    do vec=1,nvec
     326            0 :      ll = vec_idx(vec)
     327            0 :      ene_list(vec) = DBLE(exc_ene_cplx(ll))
     328              :    end do
     329              :  end if
     330            0 :  ABI_FREE(exc_ene_cplx)
     331              : 
     332            0 :  vec=1
     333            0 :  do ll=1,neig_read ! Read the selected excitons.
     334            0 :    if (ll==vec_idx(vec))  then
     335            0 :      read(eig_unt, err=10, iomsg=errmsg) vec_list(:,vec)
     336            0 :      if (vec==nvec) EXIT
     337            0 :      vec=vec+1
     338              :    else
     339            0 :      read(eig_unt, err=10, iomsg=errmsg)
     340              :    end if
     341              :  end do
     342              : 
     343            0 :  close(eig_unt, err=10, iomsg=errmsg)
     344              : 
     345            0 :  if (vec/=nvec) then
     346            0 :    write(msg,'(a,2(1x,i0))')" vec_idx is wrong, vec/=nvec ",vec,nvec+1
     347            0 :    ABI_ERROR(msg)
     348              :  end if
     349              : 
     350              :  return
     351              : 
     352              :  ! Handle IO-error
     353              : 10 continue
     354            0 :  ABI_ERROR(errmsg)
     355              : 
     356            0 : end subroutine exc_read_eigen
     357              : !!***
     358              : 
     359              : !----------------------------------------------------------------------
     360              : 
     361              : !!****f* m_bse_io/exc_read_rcblock
     362              : !! NAME
     363              : !! exc_read_rcblock
     364              : !!
     365              : !! FUNCTION
     366              : !!  Reads the excitonic Hamiltonian from file
     367              : !!
     368              : !! INPUTS
     369              : !!  fname=File name.
     370              : !!  diago_is_real=.TRUE. if diagonal elements are real (used only if is_resonant==.TRUE.)
     371              : !!  nreh(nsppol)=Number of resonant transition for the two spins.
     372              : !!  is_resonant=Set to .TRUE. if the block is resonant.
     373              : !!  hsize=Dimension of the block.
     374              : !!  nsppol=2 for spin polarized systems. 1 otherwise.
     375              : !!  my_t1,my_t2=The first and the last columns of the matrix treated by this node.
     376              : !!  use_mpio=.TRUE. is MPI-IO routines are used.
     377              : !!  comm=MPI communicator.
     378              : !!
     379              : !! OUTPUT
     380              : !!  hmat(hsize,my_t1:my_t2)=The block read from file fname.
     381              : !!
     382              : !! TODO
     383              : !! Remove Bsp
     384              : !!
     385              : !! SOURCE
     386              : 
     387           30 : subroutine exc_read_rcblock(fname,Bsp,is_resonant,diago_is_real,nsppol,nreh,hsize,my_t1,my_t2,hmat,use_mpio,comm)
     388              : 
     389              : !Arguments ------------------------------------
     390              : !scalars
     391              :  integer,intent(in) :: comm,hsize,my_t1,my_t2,nsppol
     392              :  logical,intent(in) :: is_resonant,use_mpio,diago_is_real
     393              :  character(len=*),intent(in) :: fname
     394              :  type(excparam),intent(in) :: Bsp
     395              : !arrays
     396              :  integer,intent(in) :: nreh(nsppol)
     397              :  complex(dp),intent(out) :: hmat(hsize,my_t1:my_t2)
     398              : 
     399              : !Local variables ------------------------------
     400              : !scalars
     401              :  integer,parameter :: master=0
     402              :  integer :: it,itp,funit,nproc,my_rank,neh1,neh2
     403              :  integer :: fform,my_nt
     404              :  integer :: row,col,block,spad,spin_dim,ierr,size_exp
     405              :  real(dp) :: cputime,walltime,gflops
     406              :  character(len=500) :: msg,errmsg
     407              :  !type(Hdr_type) :: bse_Hdr
     408              : !arrays
     409           30 :  complex(dp),allocatable :: buffer_dpc(:)
     410              :  logical :: have_row,have_col
     411              : #ifdef HAVE_MPI_IO
     412              :  integer :: mpierr,mpifh,ham_type,my_nel,old_type,etype,offset_err,amode
     413              :  integer :: irec,nrec !,ncount
     414              :  integer(XMPI_OFFSET_KIND) :: ehdr_offset,my_offset,my_offpad,fsize
     415           30 :  integer(XMPI_OFFSET_KIND),allocatable :: bsize_frecord(:)
     416              :  integer :: glob_sizes(2),my_cols(2), block_sizes(2,3), status(MPI_STATUS_SIZE)
     417              : #endif
     418              : !************************************************************************
     419              : 
     420           30 :  nproc = xmpi_comm_size(comm); my_rank= xmpi_comm_rank(comm)
     421              : 
     422              :  ! Compute the (Expected) size of the hamiltonian.
     423           30 :  neh1 = nreh(1)
     424           30 :  neh2 = neh1; if (nsppol==2) neh2=nreh(2)
     425              : 
     426           30 :  size_exp=neh1; if (nsppol==2) size_exp=SUM(nreh)
     427              : 
     428           30 :  ABI_CHECK(hsize==size_exp,"Wrong hsize")
     429           30 :  if (neh1/=neh2) then
     430            0 :    ABI_ERROR("BSE code does not support different number of transitions for the two spin channels")
     431              :  end if
     432              : 
     433           30 :  my_nt = my_t2-my_t1+1
     434              :  !hmat = HUGE(zero)
     435              : 
     436           30 :  if (.not.use_mpio) then
     437              : 
     438           30 :    if (is_resonant) then
     439           30 :      call wrtout(std_out,". Reading resonant block from file: "//TRIM(fname)//" using Fortran-IO")
     440              :    else
     441            0 :      call wrtout(std_out,". Reading coupling block from file: "//TRIM(fname)//" using Fortran-IO")
     442              :    end if
     443              : 
     444           30 :    if (open_file(fname,msg,newunit=funit,form="unformatted",status="old",action="read") /= 0) then
     445            0 :      ABI_ERROR(msg)
     446              :    end if
     447              :    !
     448              :    ! Read the header and perform consistency checks.
     449           30 :    call exc_read_bshdr(funit,Bsp,fform,ierr)
     450           30 :    ABI_CHECK(ierr==0,"Wrong BSE header")
     451              :    !
     452              :    ! Construct full excitonic Hamiltonian using symmetries.
     453           30 :    if (nsppol==1) then
     454           30 :      call cwtime(cputime,walltime,gflops,"start")
     455              :      !
     456           90 :      ABI_MALLOC(buffer_dpc,(neh1))
     457         8990 :      do itp=1,hsize
     458         8960 :        read(funit, err=10, iomsg=errmsg) buffer_dpc(1:itp)
     459              :        !
     460              :        ! Fill the upper triangle if I have this column.
     461         8960 :        if (itp>=my_t1 .and. itp<=my_t2) then
     462      1704832 :          do it=1,itp
     463      1704832 :            hmat(it,itp) = buffer_dpc(it)
     464              :          end do
     465              :          ! Force the diagonal to be real.
     466         7424 :          if (is_resonant .and.diago_is_real) hmat(itp,itp) = DBLE(hmat(itp,itp))
     467              :        end if
     468              :        !
     469              :        ! Reconstruct the rows below the diagonal (diagonal part is not touched here).
     470         8990 :        if (is_resonant) then ! Use Hermiticity.
     471      1993088 :          do it=1,itp-1
     472      1993088 :            if (it>=my_t1 .and. it<=my_t2) hmat(itp,it) = CONJG(buffer_dpc(it))
     473              :          end do
     474              :        else  ! Coupling is symmetric.
     475            0 :          do it=1,itp-1
     476            0 :            if (it>=my_t1 .and. it<=my_t2) hmat(itp,it) = buffer_dpc(it)
     477              :          end do
     478              :        end if
     479              :        !
     480              :      end do ! itp
     481           30 :      ABI_FREE(buffer_dpc)
     482              : 
     483           30 :      call cwtime(cputime,walltime,gflops,"stop")
     484           30 :      write(msg,'(2(a,f9.1),a)')" Fortran-IO completed. cpu_time ",cputime,"[s], walltime ",walltime," [s]"
     485           90 :      call wrtout(std_out, msg, do_flush=.True.)
     486              :    else
     487              :      ! Spin polarized case.
     488              :      !
     489              :      ! The file contains
     490              :      ! A) The up-up and the down-down block in packed form
     491              :      ! (only the upper triangle is stored since the blocks are Hermitian)
     492              :      ! B) The entire up-down exchange block (no symmetry here)
     493              :      !
     494              :      ! A) Construct resonant blocks from the upper triangles stored on file.
     495              :      ! FIXME this part won't work if we have a different number of e-h pairs
     496            0 :      if (.not.is_resonant) then
     497            0 :        ABI_ERROR("exc_read_rcblock does not support coupling.")
     498              :      end if
     499              :      ! It should be checked.
     500            0 :      spin_dim=neh1
     501            0 :      do block=1,2
     502            0 :        ABI_MALLOC(buffer_dpc,(neh1))
     503            0 :        if (block==1) spad=0
     504            0 :        if (block==2) spad=neh1
     505            0 :        do itp=1,spin_dim
     506              :          !
     507            0 :          read(funit, err=10, iomsg=errmsg) buffer_dpc(1:itp)
     508              :          !
     509              :          ! Fill the upper triangle if this node treats this column
     510            0 :          col = itp+spad
     511            0 :          if (col>=my_t1 .and. col<=my_t2) then
     512            0 :            do it=1,itp
     513            0 :              row = it + spad
     514            0 :              hmat(row,col) = buffer_dpc(it)
     515              :            end do
     516              :            ! Force the diagonal to be real.
     517            0 :            if (is_resonant .and.diago_is_real) hmat(col,col) = DBLE(hmat(col,col))
     518              :          end if
     519              :          !
     520              :          ! Reconstruct the rows below the diagonal (diagonal part is not touched here).
     521            0 :          row = itp + spad
     522            0 :          if (is_resonant) then ! Hermitian
     523            0 :            do it=1,itp-1
     524            0 :              col = it + spad
     525            0 :              if (col>=my_t1 .and. col<=my_t2) hmat(row,col) = CONJG(buffer_dpc(it))
     526              :            end do
     527              :          else  ! Coupling is symmetric.
     528            0 :            do it=1,itp-1
     529            0 :              col = it + spad
     530            0 :              if (col>=my_t1 .and. col<=my_t2) hmat(row,col) = buffer_dpc(it)
     531              :            end do
     532              :          end if
     533              :          !
     534              :        end do ! itp
     535            0 :        ABI_FREE(buffer_dpc)
     536              :      end do ! block
     537              :      !
     538              :      ! B) Kx_{down up} = Kx_{up down}^H.
     539              :      ! FIXME this part won't work if we have a different number of e-h pairs
     540            0 :      spad=neh1
     541            0 :      spin_dim=neh1
     542            0 :      ABI_MALLOC(buffer_dpc,(neh1))
     543            0 :      do itp=1,spin_dim
     544            0 :        read(funit, err=10, iomsg=errmsg) buffer_dpc(1:spin_dim)
     545            0 :        have_col = (spad+itp>=my_t1 .and. spad+itp<=my_t2)
     546            0 :        if (have_col) hmat(1:spin_dim,spad+itp) = buffer_dpc(1:spin_dim)
     547              :        ! Construct and store the lower block
     548            0 :        if (is_resonant) then ! Hermitian
     549            0 :          do it=1,spin_dim
     550            0 :            have_row = (it>=my_t1 .and. it<=my_t2)
     551            0 :            if (have_row) hmat(spad+itp,it) = CONJG(buffer_dpc(it))
     552              :          end do
     553              :        else ! Symmetric
     554            0 :          do it=1,spin_dim
     555            0 :            have_row = (it>=my_t1 .and. it<=my_t2)
     556            0 :            if (have_row) hmat(spad+itp,it) = buffer_dpc(it)
     557              :          end do
     558              :        end if
     559              :      end do
     560            0 :      ABI_FREE(buffer_dpc)
     561              :    end if
     562              : 
     563           30 :    close(funit)
     564              : 
     565              :  else
     566              : #ifdef HAVE_MPI_IO
     567            0 :    if (is_resonant) then
     568            0 :      call wrtout(std_out,". Reading resonant block from file "//TRIM(fname)//" using MPI-IO")
     569              :    else
     570            0 :      call wrtout(std_out,". Reading coupling block from file "//TRIM(fname)//" using MPI-IO")
     571              :    end if
     572              : 
     573            0 :    amode=MPI_MODE_RDONLY
     574            0 :    call MPI_FILE_OPEN(comm,fname,amode,MPI_INFO_NULL,mpifh,mpierr)
     575            0 :    msg = " FILE_OPEN "//TRIM(fname)
     576            0 :    ABI_CHECK_MPI(mpierr,msg)
     577              : 
     578            0 :    call MPI_FILE_GET_SIZE(mpifh,fsize,mpierr)
     579              :    !write(std_out,*)" file size is ",fsize
     580              :    !
     581              :    ! Skip the header and find the offset for reading the matrix.
     582            0 :    call exc_skip_bshdr_mpio(mpifh,xmpio_collective,ehdr_offset)
     583              :    !
     584              :    ! Read my columns from file.
     585            0 :    old_type=MPI_DOUBLE_COMPLEX
     586            0 :    glob_sizes = (/hsize,hsize/); my_cols=(/my_t1,my_t2/)
     587              : 
     588            0 :    if (nsppol==1) then
     589            0 :      call xmpio_create_coldistr_from_fpacked(glob_sizes,my_cols,old_type,ham_type,my_offpad,offset_err)
     590              :    else
     591            0 :      ABI_WARNING("nsppol==2 => calling fp3blocks")
     592            0 :      write(std_out,*)"neh, hsize",neh1,neh2,hsize
     593              : 
     594            0 :      nrec=neh1+2*neh2
     595            0 :      ABI_MALLOC(bsize_frecord,(nrec))
     596            0 :      bsize_frecord(1:neh1)           = (/(irec*xmpi_bsize_dpc, irec=1,neh1)/)
     597            0 :      bsize_frecord(neh1+1:neh1+neh2) = (/(irec*xmpi_bsize_dpc, irec=1,neh2)/)
     598            0 :      bsize_frecord(neh1+neh2+1:)     = neh1*xmpi_bsize_dpc
     599            0 :      call xmpio_check_frmarkers(mpifh,ehdr_offset,xmpio_collective,nrec,bsize_frecord,ierr)
     600            0 :      ABI_CHECK(ierr==0,"Error in Fortran markers")
     601            0 :      ABI_FREE(bsize_frecord)
     602            0 :      ABI_COMMENT("Marker check ok")
     603            0 :      call xmpi_barrier(comm)
     604              : 
     605            0 :      block_sizes(:,1) = (/neh1,neh1/)
     606            0 :      block_sizes(:,2) = (/neh2,neh2/)
     607            0 :      block_sizes(:,3) = (/neh1,neh2/)
     608            0 :      ABI_ERROR("fp3blocks is buggy")
     609            0 :      call xmpio_create_coldistr_from_fp3blocks(glob_sizes,block_sizes,my_cols,old_type,ham_type,my_offpad,offset_err)
     610              :    end if
     611              : 
     612            0 :    if (offset_err/=0) then
     613              :      write(msg,"(3a)")&
     614            0 :       "Global position index cannot be stored in a standard Fortran integer ",ch10,&
     615            0 :       "Excitonic matrix cannot be read with a single MPI-IO call."
     616            0 :      ABI_ERROR(msg)
     617              :    end if
     618              :    !
     619              :    ! The offset used for reading.
     620            0 :    my_offset = ehdr_offset + my_offpad
     621            0 :    write(std_out,*)"my_offset= ",my_offset
     622              : 
     623            0 :    etype=MPI_BYTE
     624            0 :    call MPI_FILE_SET_VIEW(mpifh, my_offset, etype, ham_type, 'native', MPI_INFO_NULL, mpierr)
     625            0 :    ABI_CHECK_MPI(mpierr,"SET_VIEW")
     626              : 
     627              :    ! Release the MPI filetype.
     628            0 :    call MPI_TYPE_FREE(ham_type,mpierr)
     629            0 :    ABI_CHECK_MPI(mpierr,"TYPE_FREE")
     630              : 
     631            0 :    my_nel = my_nt*hsize
     632            0 :    call MPI_FILE_READ_ALL(mpifh, hmat, my_nel, MPI_DOUBLE_COMPLEX, status, mpierr)
     633            0 :    ABI_CHECK_MPI(mpierr,"READ_ALL")
     634              : 
     635              :    !call MPI_GET_COUNT(status, MPI_DOUBLE_COMPLEX, ncount, mpierr)
     636              :    !write(std_out,*)"count, my_nel ",ncount,my_nel
     637              :    !ABI_CHECK_MPI(mpierr,"READ_ALL")
     638              :    !
     639              :    ! Close the file.
     640            0 :    call MPI_FILE_CLOSE(mpifh, mpierr)
     641            0 :    ABI_CHECK_MPI(mpierr,"FILE_CLOSE")
     642              :    !
     643              :    ! Use the symmetries of the block to reconstruct the local buffer.
     644              :    ! Coupling does not require in-place symmetrization since it is symmetric.
     645            0 :    if (is_resonant) then
     646            0 :      do itp=my_t1,my_t2
     647            0 :        if (itp+1<=hsize) hmat(itp+1:,itp) = DCONJG(hmat(itp+1:,itp)) ! Lower triangle using Hermiticity.
     648            0 :        if (diago_is_real) hmat(itp,itp) = DBLE(hmat(itp,itp))        ! The diagonal is forced to be real when energies are real.
     649              :      end do
     650              :    end if
     651              : 
     652            0 :    call xmpi_barrier(comm)
     653              : #else
     654              :    ABI_ERROR("MPI-IO support not enabled")
     655              : #endif
     656              :  end if
     657              : 
     658              : !BEGINDEBUG
     659              : ! if ( ANY(hmat==HUGE(zero)) ) then
     660              : !   write(std_out,*)"COUNT",COUNT(hmat==HUGE(zero))," hsize= ",hsize
     661              : !   ABI_ERROR("Something wrong in the reading")
     662              : ! end if
     663              : !ENDDEBUG
     664              : 
     665           30 :  call xmpi_barrier(comm)
     666              : 
     667              :  return
     668              : 
     669              : ! Handle IO Error
     670              : 10 continue
     671            0 :  ABI_ERROR(errmsg)
     672              : 
     673            0 : end subroutine exc_read_rcblock
     674              : !!***
     675              : 
     676              : !----------------------------------------------------------------------
     677              : 
     678              : !!****f* m_bse_io/exc_fullh_from_blocks
     679              : !! NAME
     680              : !!  exc_fullh_from_blocks
     681              : !!
     682              : !! FUNCTION
     683              : !!   Construct the matrix F H
     684              : !!
     685              : !! INPUTS
     686              : !!  funt
     687              : !!  nsppol
     688              : !!  block_type
     689              : !!    "Resonant"
     690              : !!    "Coupling"
     691              : !!  row_sign
     692              : !!   -1 to read ( R   C )
     693              : !!              (-C* -R*)
     694              : !!
     695              : !!   +1 to read ( R   C )
     696              : !!              ( C*  R*)
     697              : !!  diago_is_real=Used when block_type=resonat to specify whether the diagonal matrix elements are
     698              : !!  real or complex (when QP linewidth are included)
     699              : !!  nreh(nsppol)
     700              : !!  exc_size=Size of the full excitonic Hamiltonian.
     701              : !!
     702              : !! SIDE EFFECTS
     703              : !!  exc_ham(exc_size,exc_size)
     704              : !!
     705              : !! NOTES
     706              : !!
     707              : !! SOURCE
     708              : 
     709            2 : subroutine exc_fullh_from_blocks(funt,block_type,nsppol,row_sign,diago_is_real,nreh,exc_size,exc_ham)
     710              : 
     711              : !Arguments ------------------------------------
     712              : !scalars
     713              :  integer,intent(in) :: funt,exc_size,nsppol,row_sign
     714              :  logical,intent(in) :: diago_is_real
     715              :  character(len=*),intent(in) :: block_type
     716              : !arrays
     717              :  integer,intent(in) :: nreh(nsppol)
     718              :  complex(dp),intent(inout) :: exc_ham(exc_size,exc_size)
     719              : 
     720              : !Local variables-------------------------------
     721              : !scalars
     722              :  integer :: it,itp,szbuf,neh,pad_c1,pad_r1,spin_dim,spad_r,spad_c
     723              :  integer :: block,spad,row1,col1,row2,col2,spin_stride,ierr
     724              :  complex(dp) :: cttp
     725              :  character(len=500) :: errmsg
     726              : !arrays
     727            2 :  complex(dp),allocatable :: cbuff_dpc(:)
     728              : ! *********************************************************************
     729              : 
     730            2 :  szbuf=exc_size ! FIXME oversized!
     731            2 :  neh = nreh(1)
     732              : 
     733            2 :  if (nsppol==2) then
     734            0 :    ABI_WARNING("nsppol==2 is very experimental")
     735              :  end if
     736            4 :  if (ANY(nreh(1)/=nreh)) then
     737            0 :    ABI_ERROR(" different nreh are not supported")
     738              :  end if
     739              : 
     740            6 :  ABI_MALLOC_OR_DIE(cbuff_dpc,(exc_size), ierr)
     741              :  !
     742              :  ! The two cases nsppol==1,2 can be merged but we keep them
     743              :  ! separated to keep to code readable.
     744              : 
     745            5 :  SELECT CASE (toupper(block_type))
     746              :  CASE ("RESONANT")
     747              : 
     748            1 :    if (nsppol==1) then
     749              :      !
     750              :      ! Construct resonant block from the upper triangle stored on file.
     751          385 :      neh = nreh(1)
     752          385 :      do itp=1,neh
     753          384 :        read(funt, err=10, iomsg=errmsg) cbuff_dpc(1:itp)
     754        73920 :        do it=1,itp-1 ! The diagonal is treated below.
     755        73536 :          cttp = cbuff_dpc(it)
     756        73536 :          exc_ham(it     ,itp)     =                cttp   ! R
     757        73536 :          exc_ham(itp    ,it )     =          CONJG(cttp)  ! row_sign R*
     758        73536 :          exc_ham(neh+it ,neh+itp) = row_sign*CONJG(cttp)
     759        73920 :          exc_ham(neh+itp,neh+it ) = row_sign*cttp
     760              :        end do
     761          385 :        if (diago_is_real) then
     762          384 :          exc_ham(itp    ,itp)     =          DBLE(cbuff_dpc(itp))
     763          384 :          exc_ham(neh+itp,neh+itp) = row_sign*DBLE(cbuff_dpc(itp))
     764              :        else
     765            0 :          exc_ham(itp,itp)         =           cbuff_dpc(itp)
     766            0 :          exc_ham(neh+itp,neh+itp) = row_sign*(CONJG(cbuff_dpc(itp)))
     767              :        end if
     768              :      end do
     769              :      !
     770              :      !
     771              :    else
     772              :      ! FIXME this part won't work if we have a different number of e-h pairs
     773            0 :      ABI_CHECK(ALL(nreh==nreh(1)),"Different number of transitions")
     774              :      ! The file contains
     775              :      ! A) The up-up and the down-down block in packed form
     776              :      ! (only the upper triangle is stored since these blocks are Hermitian)
     777              :      ! B) The entire up-down exchange block (no symmetry here)
     778              :      !
     779              :      ! The resonant block is given by:
     780              :      !     |  (v'c' up)    | (v'c' dwn) |
     781              :      !     ------------------------------           where v_{-+} = v_{+-}^H when the momentum of the photon is neglected.
     782              :      !     | [T-W+v]++     |      v+-   | (vc up)   Note that v_{+-} is not Hermitian due to the presence of different spins.
     783              :      ! R = ------------------------------           Actually it reduces to a Hermitian matrix when the system is not spin polarized.
     784              :      !     |     v-+       | [T-W+v]--  | (vc dwn)  [T-W+v] is Hermitian provided the the QP energies are purely real.
     785              :      !     ------------------------------
     786              :      !
     787              :      ! *) Fill the diagonal blocks.
     788              :      !    only the upper triangle is stored on file.
     789              :      !    row1,col1 refer to the resonant block.
     790              :      !    row2,col2 refer to the anti-resonant block.
     791            0 :      do block=1,2
     792            0 :        if (block==1) then
     793            0 :          spad=0
     794            0 :          spin_stride=SUM(nreh)
     795              :        end if
     796            0 :        if (block==2) then
     797            0 :          spad=nreh(1)
     798            0 :          spin_stride=2*nreh(1) + nreh(2)
     799              :        end if
     800            0 :        do itp=1,nreh(block)
     801            0 :          read(funt, err=10, iomsg=errmsg) cbuff_dpc(1:itp)
     802            0 :          col1 = itp+spad
     803            0 :          col2 = itp+spin_stride
     804            0 :          do it=1,itp-1
     805            0 :            cttp = cbuff_dpc(it)
     806            0 :            row1 = it + spad
     807            0 :            row2 = it + spin_stride
     808            0 :            exc_ham(row1,col1) =                cttp    ! [T-W+v]
     809            0 :            exc_ham(col1,row1) =          CONJG(cttp)
     810            0 :            exc_ham(row2,col2) = row_sign*CONJG(cttp)   ! row_sign [T-W+v]*
     811            0 :            exc_ham(col2,row2) = row_sign*cttp
     812              :          end do
     813            0 :          if (diago_is_real) then
     814            0 :            exc_ham(col1,col1) =          DBLE(cbuff_dpc(itp))
     815            0 :            exc_ham(col2,col2) = row_sign*DBLE(cbuff_dpc(itp))
     816              :          else
     817            0 :            exc_ham(col1,col1) = cbuff_dpc(itp)
     818            0 :            exc_ham(col2,col2) = row_sign*CONJG(cbuff_dpc(itp))
     819              :          end if
     820              :        end do
     821              :      end do
     822              :      !
     823              :      ! Read v+- and reconstruct resonant and anti-resonat blocks.
     824              :      ! TODO recheck this
     825            0 :      pad_r1=SUM(nreh)
     826            0 :      pad_c1=2*nreh(1) + nreh(2)
     827              : 
     828            0 :      spin_dim=nreh(1)
     829            0 :      do itp=1,spin_dim
     830            0 :        read(funt, err=10, iomsg=errmsg) cbuff_dpc(1:spin_dim)
     831            0 :        exc_ham(1:spin_dim,nreh(1)+itp) = cbuff_dpc(1:spin_dim)                              ! upper reso
     832            0 :        exc_ham(1+pad_r1:pad_r1+spin_dim,pad_c1+itp) = row_sign*CONJG(cbuff_dpc(1:spin_dim)) ! upper anti-reso
     833            0 :        col1 = itp+nreh(1)
     834            0 :        col2 = itp+(2*nreh(1) + nreh(2))
     835            0 :        do it=1,spin_dim
     836            0 :          cttp = cbuff_dpc(it)
     837            0 :          row1 = it
     838            0 :          exc_ham(col1,row1) =    CONJG(cttp)  ! lower reso.
     839            0 :          row2 = it + SUM(nreh)
     840            0 :          exc_ham(col2,row2) = row_sign*cttp   ! lower anti-reso.
     841              :        end do
     842              :      end do
     843              :    end if
     844              : 
     845              :  CASE ("COUPLING")
     846              :    !
     847            1 :    if (nsppol==1) then
     848              :      !
     849          385 :      do itp=1,neh
     850          384 :        read(funt, err=10, iomsg=errmsg) cbuff_dpc(1:itp)
     851        74305 :        do it=1,itp
     852        73920 :          cttp = cbuff_dpc(it)
     853        73920 :          exc_ham(it    ,neh+itp) = cttp
     854        73920 :          exc_ham(itp   ,neh+it ) = cttp
     855        73920 :          exc_ham(neh+it ,itp   ) = row_sign*CONJG(cttp)
     856        74304 :          exc_ham(neh+itp,it    ) = row_sign*CONJG(cttp)
     857              :        end do
     858              :      end do
     859              :      !
     860              :    else
     861              :      !  The coupling block is given by:
     862              :      !      |  (c'v' up)   |    (c'v dwn)     |
     863              :      !      -----------------------------------           where v_{-+} = v_{+-}^t when the momentum of the photon is neglected.
     864              :      !      | [-W+v]++     |      v+-         | (vc up)   The entire matrix v_{+-} is stored on file.
     865              :      !  C = -----------------------------------
     866              :      !      |     v-+      |    [-W+v]--      | (vc dwn)
     867              :      !      -----------------------------------
     868              :      !
     869              :      ! *) Fill blocks that are diagonal in spin coordinates.
     870              :      !    row1,col1 refer to the resonat block.
     871              :      !    row2,col2 refer to the anti-resonant block.
     872            0 :      do block=1,2
     873            0 :        if (block==1) then
     874            0 :          spad_r=0
     875            0 :          spad_c=SUM(nreh)
     876              :        end if
     877            0 :        if (block==2) then
     878            0 :          spad_r=nreh(1)
     879            0 :          spad_c=2*nreh(1)+nreh(2)
     880              :        end if
     881            0 :        do itp=1,nreh(block)
     882            0 :          read(funt, err=10, iomsg=errmsg) cbuff_dpc(1:itp)
     883            0 :          col1 = itp+spad_c
     884            0 :          row2 = itp+spad_r
     885            0 :          do it=1,itp-1
     886            0 :            cttp = cbuff_dpc(it)
     887            0 :            row1 = it + spad_r
     888            0 :            col2 = it + spad_c
     889            0 :            exc_ham(row1,col1) =                cttp  ! upper coupling
     890            0 :            exc_ham(row2,col2) =                cttp  ! lower coupling (symmetric)
     891            0 :            exc_ham(col1,row1) = row_sign*CONJG(cttp) ! lower anti-coupling
     892            0 :            exc_ham(col2,row2) = row_sign*CONJG(cttp) ! upper anti-couling
     893              :          end do
     894              :          ! TODO recheck this
     895            0 :          row1 = itp+spad_r
     896            0 :          exc_ham(row1,col1) = cbuff_dpc(itp)                  ! Diagonals of the block.
     897            0 :          col2 = itp+spad_c
     898            0 :          exc_ham(col2,row2) = row_sign*CONJG(cbuff_dpc(itp))
     899              :        end do
     900              :      end do
     901              :      !
     902              :      ! Read Full v+- and reconstruct resonant and anti-resonat blocks.
     903              :      ! TODO recheck this
     904            0 :      spad=2*nreh(1) + nreh(2)
     905            0 :      pad_r1=SUM(nreh)
     906            0 :      pad_c1=2*nreh(1) + nreh(2)
     907              : 
     908            0 :      spin_dim=nreh(1)
     909            0 :      do itp=1,spin_dim
     910            0 :        read(funt, err=10, iomsg=errmsg) cbuff_dpc(1:spin_dim)
     911            0 :        exc_ham(1:spin_dim,spad+itp) = cbuff_dpc(1:spin_dim)                                  ! upper block reso
     912            0 :        exc_ham(1+pad_r1:pad_r1+spin_dim,nreh(1)+itp) = row_sign*CONJG(cbuff_dpc(1:spin_dim)) ! upper block anti-reso
     913            0 :        col1 = itp+spad
     914            0 :        row2 = itp+nreh(1)
     915            0 :        do it=1,spin_dim
     916            0 :          cttp = cbuff_dpc(it)
     917            0 :          row1 = it
     918            0 :          exc_ham(col1,row1) =  row_sign*CONJG(cttp)  ! lower anti-reso.
     919            0 :          col2 = it + SUM(nreh)
     920            0 :          exc_ham(row2,col2) = cttp                   ! lower reso.
     921              :        end do
     922              :      end do
     923              :      !
     924              :    end if
     925              : 
     926              :  CASE DEFAULT
     927            2 :    ABI_ERROR("Unknown block_type: "//TRIM(block_type))
     928              :  END SELECT
     929              : 
     930            2 :  ABI_FREE(cbuff_dpc)
     931              : 
     932              :  return
     933              : 
     934              : ! Handle IO Error
     935              : 10 continue
     936            0 :  ABI_ERROR(errmsg)
     937              : 
     938            0 : end subroutine exc_fullh_from_blocks
     939              : !!***
     940              : 
     941              : !----------------------------------------------------------------------
     942              : 
     943              : !!****f* m_bse_io/rrs_of_glob
     944              : !! NAME
     945              : !!  rrs_of_glob
     946              : !!
     947              : !! FUNCTION
     948              : !!   [+1,-1,0] if (row_glob,col_glob) belongs to the [ resonant, anti-resonant, (anti)coupling block ]
     949              : !!
     950              : !! INPUTS
     951              : !!
     952              : !! OUTPUT
     953              : !!
     954              : !! SOURCE
     955              : 
     956            0 : pure function rrs_of_glob(row_glob,col_glob,size_glob)
     957              : 
     958              : !Arguments ------------------------------------
     959              :  integer :: rrs_of_glob
     960              :  integer,intent(in) :: row_glob,col_glob
     961              :  integer,intent(in) :: size_glob(2)
     962              : 
     963              : !Local variables ------------------------------
     964              :  integer :: nreh1,nreh2
     965              : ! *************************************************************************
     966              : 
     967            0 :  nreh1=size_glob(1)/2 ! Matrix is square and nreh1==nreh2 but oh well.
     968            0 :  nreh2=size_glob(2)/2
     969              : 
     970            0 :  if (row_glob<=nreh1 .and. col_glob<=nreh2) then
     971              :    rrs_of_glob=+1  ! Resonant.
     972            0 :  else if (row_glob >nreh1 .and. col_glob >nreh2) then
     973              :    rrs_of_glob=-1  ! anti-Resonant.
     974              :  else
     975            0 :    rrs_of_glob=0
     976              :  end if
     977              : 
     978            0 : end function rrs_of_glob
     979              : !!***
     980              : 
     981              : !----------------------------------------------------------------------
     982              : 
     983              : !!****f* m_bse_io/ccs_of_glob
     984              : !! NAME
     985              : !!! ccs_of_glob
     986              : !!
     987              : !! FUNCTION
     988              : !!  [+1,-1,0] if (row_glob,col_glob) belongs to the [ coupling, anti-coupling, (anti)resonant block ]
     989              : !!
     990              : !! INPUTS
     991              : !!
     992              : !! OUTPUT
     993              : !!
     994              : !! SOURCE
     995              : 
     996            0 : pure function ccs_of_glob(row_glob,col_glob,size_glob)
     997              : 
     998              : !Arguments ------------------------------------
     999              :  integer :: ccs_of_glob
    1000              :  integer,intent(in) :: row_glob,col_glob
    1001              :  integer,intent(in) :: size_glob(2)
    1002              : 
    1003              : !Local variables ------------------------------
    1004              :  integer :: nreh1,nreh2
    1005              : ! *************************************************************************
    1006              : 
    1007            0 :  nreh1=size_glob(1)/2 ! Matrix is square and nreh1==nreh2 but oh well.
    1008            0 :  nreh2=size_glob(2)/2
    1009              : 
    1010            0 :  if (row_glob<=nreh1 .and. col_glob >nreh2) then      ! Coupling.
    1011              :    ccs_of_glob = +1
    1012            0 :  else if (row_glob >nreh1 .and. col_glob<=nreh2) then ! anti-Coupling
    1013              :    ccs_of_glob = -1
    1014              :  else
    1015            0 :    ccs_of_glob = 0
    1016              :  end if
    1017              : 
    1018            0 : end function ccs_of_glob
    1019              : !!***
    1020              : 
    1021              : !----------------------------------------------------------------------
    1022              : 
    1023              : !!****f* m_bse_io/offset_in_file
    1024              : !! NAME
    1025              : !!  offset_in_file
    1026              : !!
    1027              : !! FUNCTION
    1028              : !!  Return the offset of the matrix element (row_glob,col_glob)
    1029              : !!  size_glob(2) gives the number of row and column of the global matrix
    1030              : !!  nsblocks is the number of sublocks, used for nsppol==2 (not used if 1)
    1031              : !!  sub_block(2,2,nsblocks)= For each subblock the coordinates of the first and last element.
    1032              : !!
    1033              : !! INPUTS
    1034              : !!
    1035              : !! OUTPUT
    1036              : !!
    1037              : !! SOURCE
    1038              : 
    1039            0 : function offset_in_file(row_glob,col_glob,size_glob,nsblocks,sub_block,bsize_elm,bsize_frm)
    1040              : 
    1041              :  !Arguments ------------------------------------
    1042              :  integer(XMPI_OFFSET_KIND) :: offset_in_file
    1043              :  integer,intent(in) :: row_glob,col_glob,nsblocks,bsize_elm,bsize_frm
    1044              :  integer,intent(in) :: size_glob(2),sub_block(2,2,nsblocks)
    1045              : 
    1046              : !Local variables ------------------------------
    1047              : !scalars
    1048              :  integer :: ii,jj,ijp_glob,swap
    1049              :  integer(XMPI_OFFSET_KIND) :: my_offset
    1050              : ! *************************************************************************
    1051              : 
    1052            0 :  if (nsblocks==1) then
    1053            0 :    ii = row_glob
    1054            0 :    jj = col_glob
    1055            0 :    if (ii>size_glob(1)/2) ii = ii - size_glob(1)/2 ! Wrap the index.
    1056            0 :    if (jj>size_glob(2)/2) jj = jj - size_glob(2)/2
    1057            0 :    if (jj<ii) then ! Exchange the indices since the symmetric element is read.
    1058            0 :      swap = jj
    1059            0 :      jj   = ii
    1060            0 :      ii   = swap
    1061              :    end if
    1062            0 :    ijp_glob = ii + jj*(jj-1)/2  ! Index for packed storage mode.
    1063            0 :    my_offset = (ijp_glob-1)*bsize_elm + (jj-1)*2*bsize_frm
    1064              :  else
    1065              :    ABI_UNUSED(sub_block(1,1,1))
    1066            0 :    ABI_ERROR("nsppol==2 not coded")
    1067              :  end if
    1068              : 
    1069            0 :  offset_in_file = my_offset
    1070              : 
    1071            0 : end function offset_in_file
    1072              : !!***
    1073              : 
    1074              : !----------------------------------------------------------------------
    1075              : 
    1076              : !!****f* m_bse_io/exc_read_rblock_fio
    1077              : !! NAME
    1078              : !!  exc_read_rblock_fio
    1079              : !!
    1080              : !! FUNCTION
    1081              : !!  Reads the resonant block from file using Fortran IO.
    1082              : !!
    1083              : !! INPUTS
    1084              : !!  funt=Fortran unit number.
    1085              : !!  nsppol=Number of spins
    1086              : !!  exc_size=Size of the resonant bock.
    1087              : !!  diago_is_real=.TRUE. if diagonal elements are real.
    1088              : !!  nreh(nsppol)=Number of resonant transitions for each spin.
    1089              : !!
    1090              : !! OUTPUT
    1091              : !!  ierr=Status error
    1092              : !!  exc_mat(exc_size,exc_size)=The resonant block.
    1093              : !!
    1094              : !! SOURCE
    1095              : 
    1096           19 : subroutine exc_read_rblock_fio(funt,diago_is_real,nsppol,nreh,exc_size,exc_mat,ierr)
    1097              : 
    1098              : !Arguments ------------------------------------
    1099              : !scalars
    1100              :  integer,intent(in) :: funt,nsppol,exc_size
    1101              :  logical,intent(in) :: diago_is_real
    1102              :  integer,intent(out) :: ierr
    1103              : !arrays
    1104              :  integer,intent(in) :: nreh(nsppol)
    1105              :  complex(dp),intent(out) :: exc_mat(exc_size,exc_size)
    1106              : 
    1107              : !Local variables ------------------------------
    1108              : !scalars
    1109              :  integer :: itp,it,block,col,row,spad
    1110              :  complex(dp) :: ctemp
    1111              :  character(len=500) :: errmsg
    1112              : !arrays
    1113           19 :  complex(dp),allocatable :: cbuff_dpc(:)
    1114              : ! *************************************************************************
    1115              : 
    1116           19 :  ierr=0
    1117              : 
    1118              :  ! Construct full resonant block using Hermiticity. File is always in double precision.
    1119           57 :  ABI_MALLOC(cbuff_dpc,(exc_size))
    1120              : 
    1121           19 :  if (nsppol==1) then ! Construct resonant block from the upper triangle stored on file.
    1122              :    !
    1123         2801 :    do itp=1,nreh(1)
    1124         2784 :      read(funt, err=10, iomsg=errmsg) cbuff_dpc(1:itp)
    1125       356208 :      do it=1,itp-1 ! Diagonal is treated below.
    1126       353424 :        ctemp = cbuff_dpc(it)
    1127       353424 :        exc_mat(it,itp) = ctemp
    1128       356208 :        exc_mat(itp,it) = CONJG(ctemp)
    1129              :      end do
    1130         2801 :      if (diago_is_real) then
    1131         2784 :        exc_mat(itp,itp) = DBLE(cbuff_dpc(itp))
    1132              :      else
    1133            0 :        exc_mat(itp,itp) = cbuff_dpc(itp)
    1134              :      end if
    1135              :    end do
    1136              :    !
    1137              :  else
    1138              :    ! The file contains
    1139              :    ! A) The up-up and the down-down block in packed form
    1140              :    ! (only the upper triangle is stored since these blocks are Hermitian)
    1141              :    ! B) The entire up-down exchange block (no symmetry here)
    1142              :    !
    1143              :    ! A) Construct resonant blocks from the upper triangles stored on file.
    1144              :    ! FIXME this part won't work if we have a different number of e-h pairs
    1145              :    !ABI_CHECK(ALL(nreh==nreh(1)),"Different number of transitions")
    1146              : 
    1147            6 :    do block=1,2
    1148            4 :      if (block==1) spad=0
    1149            2 :      if (block==2) spad=nreh(1)
    1150         1542 :      do itp=1,nreh(block)
    1151         1536 :        read(funt, err=10, iomsg=errmsg) cbuff_dpc(1:itp)
    1152         1536 :        col = itp+spad
    1153       295680 :        do it=1,itp-1 ! diagonal is treated below.
    1154       294144 :          ctemp = cbuff_dpc(it)
    1155       294144 :          row = it + spad
    1156       294144 :          exc_mat(row,col) = ctemp
    1157       295680 :          exc_mat(col,row) = CONJG(ctemp)
    1158              :        end do
    1159         1540 :        if (diago_is_real) then
    1160         1536 :          exc_mat(col,col) = DBLE(cbuff_dpc(itp))
    1161              :        else
    1162            0 :          exc_mat(col,col) = cbuff_dpc(itp)
    1163              :        end if
    1164              :      end do
    1165              :    end do
    1166              :    !
    1167              :    ! read v+- that is a matrix with shape nreh(1) X nreh(2)
    1168            2 :    spad=nreh(1)
    1169          770 :    do itp=1,nreh(2)
    1170          768 :      read(funt, err=10, iomsg=errmsg) cbuff_dpc(1:nreh(1))
    1171       295682 :      exc_mat(1:nreh(1),spad+itp) = cbuff_dpc(1:nreh(1))
    1172              :    end do
    1173              : 
    1174              :  end if
    1175              : 
    1176           19 :  ABI_FREE(cbuff_dpc)
    1177              : 
    1178              :  return
    1179              : 
    1180              :  ! Raise the error.
    1181              : 10 continue
    1182            0 :  ierr = 1
    1183            0 :  ABI_WARNING(errmsg)
    1184              : 
    1185            0 : end subroutine exc_read_rblock_fio
    1186              : !!***
    1187              : 
    1188              : !----------------------------------------------------------------------
    1189              : 
    1190              : !!****f* m_bse_io/exc_amplitude
    1191              : !! NAME
    1192              : !!  exc_amplitude
    1193              : !!
    1194              : !! FUNCTION
    1195              : !!  Calculate the amplitude function of the excitonic eigenstate |exc_vec\>
    1196              : !!    F(w) = \sum_t |<t|exc_vec>|^2 \delta(ww- ene_t) where the sum over t is done
    1197              : !!  of the full set of transitions used to construct the BS Hamiltoniam.
    1198              : !!
    1199              : !! INPUTS
    1200              : !!  Bsp<excparam>=Structure storing the parameters of the run.
    1201              : !!  eig_fname=The name of the file storing the excitonic eigenvectors.
    1202              : !!  nvec=Number of excitonic states to analyze.
    1203              : !!  vec_idx(nvec)=List with the indices of the excitonic states sorted in ascending order.
    1204              : !!  out_fname=The name of the file where the results are written.
    1205              : !!
    1206              : !! OUTPUT
    1207              : !!  Only writing.
    1208              : !!
    1209              : !! SOURCE
    1210              : 
    1211            0 : subroutine exc_amplitude(Bsp,eig_fname,nvec,vec_idx,out_fname)
    1212              : 
    1213              : !Arguments ------------------------------------
    1214              : !scalars
    1215              :  integer,intent(in) :: nvec
    1216              :  character(len=*),intent(in) :: eig_fname,out_fname
    1217              :  type(excparam),intent(in) :: BSp
    1218              : ! arrays
    1219              :  integer,intent(in) :: vec_idx(nvec)
    1220              : 
    1221              : !Local variables ------------------------------
    1222              : !scalars
    1223              :  integer :: vec,art_idx,ierr
    1224              :  integer :: spin,iw,it,nw,pos_w,neg_w,out_unt,rt_idx,hsize
    1225              :  real(dp) :: ene_rt,ampl_eh,ampl_he,xx,stdev,w_max,w_min,step
    1226              :  character(len=500) :: msg
    1227              : !arrays
    1228            0 :  real(dp),allocatable :: wmesh(:),amplitude(:),ene_list(:)
    1229            0 :  complex(dp),allocatable :: vec_list(:,:)
    1230              : ! *************************************************************************
    1231              : 
    1232              :  ! Setup of the frequency mesh for F(w).
    1233            0 :  w_min=greatest_real; w_max=smallest_real
    1234            0 :  do spin=1,BSp%nsppol
    1235            0 :    do it=1,BSp%nreh(spin)
    1236            0 :      ene_rt  = Bsp%Trans(it,spin)%en
    1237            0 :      w_min = MIN(w_min,ene_rt)
    1238            0 :      w_max = MAX(w_max,ene_rt)
    1239              :    end do
    1240              :  end do
    1241              : 
    1242            0 :  step = Bsp%domega
    1243            0 :  if (Bsp%use_coupling==0) then
    1244            0 :    nw = (w_max - w_min)/step + 1
    1245            0 :    ABI_MALLOC(wmesh,(nw))
    1246            0 :    wmesh = arth(w_min,step,nw)
    1247              :  else
    1248              :    ! Both positive and negative frequencies are needed.
    1249            0 :    pos_w = (w_max - w_min)/step + 1
    1250            0 :    neg_w = pos_w; if (ABS(w_min) < tol6) neg_w=neg_w-1 ! zero should not included twice.
    1251            0 :    nw = neg_w + pos_w
    1252            0 :    ABI_MALLOC(wmesh,(nw))
    1253            0 :    wmesh(1:neg_w)  = arth(-w_max,step,neg_w)
    1254            0 :    wmesh(neg_w+1:) = arth( w_min,step,pos_w)
    1255              :  end if
    1256              :  !
    1257              :  ! Read selected eigenvectors.
    1258            0 :  hsize = SUM(Bsp%nreh); if (Bsp%use_coupling>0) hsize=2*hsize
    1259              : 
    1260            0 :  ABI_MALLOC(ene_list,(nvec))
    1261            0 :  ABI_MALLOC_OR_DIE(vec_list,(hsize,nvec), ierr)
    1262              : 
    1263            0 :  call exc_read_eigen(eig_fname,hsize,nvec,vec_idx,vec_list,ene_list,Bsp=Bsp)
    1264              : 
    1265            0 :  ABI_FREE(ene_list)
    1266              : 
    1267            0 :  if (open_file(out_fname,msg,newunit=out_unt,form="formatted",action="write") /= 0) then
    1268            0 :    ABI_ERROR(msg)
    1269              :  end if
    1270              : 
    1271            0 :  write(out_unt,*)"# Amplitude functions F(w) = \sum_t |<t|exc_vec>|^2 \delta(ww- ene_t), w is given in eV. "
    1272            0 :  write(out_unt,*)"# Number of excitonic eigenvectors analyzed: ",nvec
    1273              : 
    1274            0 :  ABI_MALLOC(amplitude,(nw))
    1275            0 :  stdev = BSp%broad ! Broadening for the gaussian.
    1276              : 
    1277            0 :  do vec=1,nvec
    1278              :    !
    1279              :    ! amplitude(ww) = \sum_t |<t|exc_vec>|^2 \delta(ww- ene_t)
    1280            0 :    amplitude = zero
    1281            0 :    do spin=1,BSp%nsppol
    1282            0 :      do it=1,BSp%nreh(spin)
    1283            0 :       ene_rt  = Bsp%Trans(it,spin)%en
    1284            0 :       rt_idx  = it + (spin-1)*Bsp%nreh(1)
    1285            0 :       ampl_eh = (ABS(vec_list(rt_idx,vec)))**2
    1286            0 :       if (Bsp%use_coupling>0) then ! Need the index and the amplitude of the anti-resonant component.
    1287            0 :         art_idx  = it + (spin-1)*Bsp%nreh(1) + SUM(Bsp%nreh)
    1288            0 :         ampl_he = (ABS(vec_list(art_idx,vec)))**2
    1289              :       end if
    1290              :       !
    1291            0 :       do iw=1,nw ! Accumulate
    1292            0 :         xx = wmesh(iw) - ene_rt
    1293            0 :         amplitude(iw) = amplitude(iw) + ampl_eh * gaussian(xx, stdev)
    1294            0 :         if (Bsp%use_coupling>0) then
    1295            0 :           xx = wmesh(iw) + ene_rt
    1296            0 :           amplitude(iw) = amplitude(iw) + ampl_he * gaussian(xx, stdev)
    1297              :         end if
    1298              :       end do
    1299              :       !
    1300              :      end do
    1301              :    end do
    1302              :    !
    1303              :    ! Write results
    1304            0 :    write(out_unt,*)"# Amplitude function F(w) for exc_vector index ",vec_idx(vec)
    1305            0 :    do iw=1,nw
    1306            0 :      write(out_unt,*)wmesh(iw)*Ha_eV,amplitude(iw)
    1307              :    end do
    1308            0 :    write(out_unt,*)"#"
    1309              :  end do
    1310              : 
    1311            0 :  close(out_unt)
    1312              : 
    1313            0 :  ABI_FREE(amplitude)
    1314            0 :  ABI_FREE(wmesh)
    1315            0 :  ABI_FREE(vec_list)
    1316              : 
    1317            0 : end subroutine exc_amplitude
    1318              : !!***
    1319              : 
    1320              : !----------------------------------------------------------------------
    1321              : 
    1322              : !!****f* m_bse_io/exc_write_optme
    1323              : !! NAME
    1324              : !!  exc_write_optme
    1325              : !!
    1326              : !! FUNCTION
    1327              : !!   Writes the optical matrix elements in the OME.nc file.
    1328              : !!   Note that this is only available when NetCDF is available
    1329              : !!
    1330              : !! INPUTS
    1331              : !!  filename=filename used to write the optical matrix elements
    1332              : !!  minb,maxb=minimum and max band index that have been calculated.
    1333              : !!  nkbz=Number of points in the full Brillouin zone.
    1334              : !!  nsppol=Number of independent spin polarizations.
    1335              : !!  nq=Number of "small" q for optical limit.
    1336              : !!  opt_cvk=Optical matrix elements to be written
    1337              : !!
    1338              : !! OUTPUT
    1339              : !!  ierr=return status of the writing process.
    1340              : !!      => 0 if everything was ok
    1341              : !!      => -1 if NetCDF is not available
    1342              : !!      => 1 if NetCDF is available
    1343              : !!
    1344              : !! SOURCE
    1345              : 
    1346            0 : subroutine exc_write_optme(filename,minb,maxb,nkbz,nsppol,nq,opt_cvk,ierr)
    1347              : 
    1348              :  !Arguments ------------------------------------
    1349              :  integer,intent(in) :: minb,maxb,nkbz,nsppol,nq
    1350              :  character(len=fnlen),intent(in) :: filename
    1351              :  complex(dp),intent(in) :: opt_cvk(minb:maxb,minb:maxb,nkbz,nsppol,nq)
    1352              :  integer,intent(out) :: ierr
    1353              : 
    1354              : !Local variables ------------------------------
    1355              : !scalars
    1356              :  integer :: ncid,cmplx_id,nband_id,nkbz_id,nsppol_id,nq_id,xyz_id
    1357              :  integer :: minb_id,maxb_id,ome_id,iq,is,ik,ib,jb
    1358              :  integer :: dimOME(6),dimKPT(2),dimQPT(2),dimSCA(0),start6(6),count6(6)
    1359              :  real(dp) :: complex2(2)
    1360              :  ! *************************************************************************
    1361              : 
    1362            0 :  ierr = 1
    1363              : 
    1364              : !1. Create netCDF file
    1365            0 :  NCF_CHECK_MSG(nctk_open_create(ncid, filename, xmpi_comm_self), " create netcdf OME file")
    1366              : 
    1367              : !2. Define dimensions
    1368            0 :  NCF_CHECK(nf90_def_dim(ncid,"xyz",3,xyz_id))
    1369            0 :  NCF_CHECK(nf90_def_dim(ncid,"cmplx",2,cmplx_id))
    1370            0 :  NCF_CHECK(nf90_def_dim(ncid,"nband",maxb-minb+1,nband_id))
    1371            0 :  NCF_CHECK(nf90_def_dim(ncid,"nkbz",nkbz,nkbz_id))
    1372            0 :  NCF_CHECK(nf90_def_dim(ncid,"nq",nq,nq_id))
    1373            0 :  NCF_CHECK(nf90_def_dim(ncid,"nsppol",nsppol,nsppol_id))
    1374              : 
    1375              : !Dimensions for optical matrix elements
    1376            0 :  dimOME = (/ cmplx_id, nband_id, nband_id, nkbz_id, nsppol_id, nq_id /)
    1377              : !Dimensions for kpoint positions
    1378            0 :  dimKPT = (/ xyz_id, nkbz_id /)
    1379              : !Dimensions for qpoints for the optical limit
    1380            0 :  dimQPT = (/ xyz_id, nq_id /)
    1381              : 
    1382              : !3. Define variables
    1383              : 
    1384              :  call ab_define_var(ncid, dimOME, ome_id, NF90_DOUBLE,&
    1385            0 :  "OME", "Values of optical matrix elements","Tobedone")
    1386              : 
    1387              :  call ab_define_var(ncid, dimSCA, minb_id, NF90_INT,"minb",&
    1388            0 :  "Minimum band index for the optical matrix elements", "Dimensionless")
    1389              : 
    1390              :  call ab_define_var(ncid, dimSCA, maxb_id, NF90_INT,"maxb",&
    1391            0 :  "Maximum band index for the optical matrix elements", "Dimensionless")
    1392              : 
    1393              : !4. End define mode
    1394            0 :  NCF_CHECK(nf90_enddef(ncid))
    1395              : 
    1396              : !5 Write scalars (minb and maxb)
    1397              : 
    1398            0 :  NCF_CHECK(nf90_put_var(ncid, minb_id, minb))
    1399            0 :  NCF_CHECK(nf90_put_var(ncid, maxb_id, maxb))
    1400              : 
    1401              : !6 Write optical matrix elements
    1402              : 
    1403            0 :  do iq=1,nq
    1404            0 :    do is=1,nsppol
    1405            0 :      do ik=1,nkbz
    1406            0 :        do ib=minb,maxb
    1407            0 :          do jb=minb,maxb
    1408            0 :            start6 = (/ 1, ib-minb+1, jb-minb+1, ik, is, iq /)
    1409            0 :            count6 = (/ 2, 1, 1, 1, 1, 1 /)
    1410            0 :            complex2 = (/ REAL(opt_cvk(ib,jb,ik,is,iq)),AIMAG(opt_cvk(ib,jb,ik,is,iq)) /)
    1411            0 :            NCF_CHECK(nf90_put_var(ncid, ome_id, complex2, start = start6, count = count6))
    1412              :        end do
    1413              :        end do
    1414              :      end do
    1415              :    end do
    1416              :  end do
    1417              : 
    1418              :  !7 Close file
    1419            0 :  NCF_CHECK(nf90_close(ncid))
    1420            0 :  ierr = 0
    1421              : 
    1422            0 : end subroutine exc_write_optme
    1423              : !!***
    1424              : 
    1425              : !----------------------------------------------------------------------
    1426              : 
    1427              : !!****f* m_hexc/exc_ham_ncwrite
    1428              : !! NAME
    1429              : !! exc_ham_ncwrite
    1430              : !!
    1431              : !! FUNCTION
    1432              : !!  Writes the content of a hexc object to a NETCDF file
    1433              : !!  according to the ETSF-IO specifications.
    1434              : !!
    1435              : !! INPUTS
    1436              : !!  ncid =NC file handle
    1437              : !!
    1438              : !! OUTPUT
    1439              : !!
    1440              : !! SOURCE
    1441              : 
    1442            0 : subroutine exc_ham_ncwrite(ncid,Kmesh,BSp,hsize,nreh,vcks2t,hreso,diag)
    1443              : 
    1444              : !Arguments ------------------------------------
    1445              : !scalars
    1446              :  integer,intent(in) :: ncid
    1447              :  integer,intent(in) :: hsize
    1448              :  type(kmesh_t),intent(in) :: Kmesh
    1449              :  type(excparam),intent(in) :: BSp
    1450              :  integer,intent(in) :: nreh(BSp%nsppol)
    1451              :  integer,target,intent(in) :: vcks2t(BSp%maxnbndv,BSp%maxnbndc,Kmesh%nbz,BSp%nsppol)
    1452              :  complex(dp),target,intent(in) :: hreso(hsize,hsize)
    1453              :  complex(dp),target,intent(in) :: diag(hsize)
    1454              : 
    1455              : !Local variables-------------------------------
    1456              :  integer :: ncerr
    1457              :  integer :: max_nreh, sum_nreh
    1458            0 :  real(dp), contiguous, pointer :: r2vals(:,:),r3vals(:,:,:)
    1459              : ! *************************************************************************
    1460              : 
    1461              :  ! ==============================================
    1462              :  ! === Write the dimensions specified by ETSF ===
    1463              :  ! ==============================================
    1464            0 :  max_nreh = MAXVAL(nreh)
    1465            0 :  sum_nreh = SUM(nreh)
    1466              : 
    1467              :  ncerr = nctk_def_dims(ncid, [nctkdim_t("number_of_reduced_dimensions", 3), nctkdim_t("number_of_spins", bsp%nsppol),&
    1468              :     nctkdim_t("number_of_kpoints", kmesh%nbz), nctkdim_t("max_number_of_valence_bands", bsp%maxnbndv),&
    1469              :     nctkdim_t("max_number_of_conduction_bands", bsp%maxnbndc), nctkdim_t("max_number_of_transitions", max_nreh),&
    1470            0 :     nctkdim_t("total_number_of_transitions", sum_nreh), nctkdim_t("cplex", 2)], defmode=.True.)
    1471            0 :  NCF_CHECK(ncerr)
    1472              : 
    1473              :  ncerr = nctk_def_arrays(ncid, [&
    1474              :    nctkarr_t('vcks2t', "i", 'max_number_of_valence_bands, max_number_of_conduction_bands, number_of_kpoints, number_of_spins'),&
    1475              :    nctkarr_t('hamiltonian', "dp", 'cplex total_number_of_transitions total_number_of_transitions'),&
    1476              :    nctkarr_t('diagonal', "dp", 'cplex total_number_of_transitions'),&
    1477              :    nctkarr_t('lomo', "dp", 'number_of_spins'), &
    1478              :    nctkarr_t('homo', "dp", 'number_of_spins'), &
    1479              :    nctkarr_t('lumo', "dp", 'number_of_spins'), &
    1480              :    nctkarr_t('humo', "dp", 'number_of_spins'), &
    1481              :    nctkarr_t("reduced_coordinates_of_kpoints", "dp", "number_of_reduced_dimensions, number_of_kpoints"), &
    1482              :    nctkarr_t("kpoint_weights", "dp", "number_of_kpoints") &
    1483            0 :    ])
    1484            0 :  NCF_CHECK(ncerr)
    1485              : 
    1486              : ! Write data
    1487            0 :  NCF_CHECK(nctk_set_datamode(ncid))
    1488            0 :  NCF_CHECK(nf90_put_var(ncid, vid('vcks2t'), vcks2t))
    1489            0 :  NCF_CHECK(nf90_put_var(ncid, vid('lomo'), BSp%lomo_spin))
    1490            0 :  NCF_CHECK(nf90_put_var(ncid, vid('homo'), BSp%homo_spin))
    1491            0 :  NCF_CHECK(nf90_put_var(ncid, vid('lumo'), BSp%lumo_spin))
    1492            0 :  NCF_CHECK(nf90_put_var(ncid, vid('humo'), BSp%humo_spin))
    1493              : 
    1494            0 :  call c_f_pointer(c_loc(hreso(1,1)), r3vals, shape=[2, hsize, hsize])
    1495            0 :  NCF_CHECK(nf90_put_var(ncid, vid("hamiltonian"), r3vals))
    1496              : 
    1497            0 :  call c_f_pointer(c_loc(diag(1)), r2vals, shape=[2, hsize])
    1498            0 :  NCF_CHECK(nf90_put_var(ncid, vid("diag"), r2vals))
    1499              : 
    1500              :  ! Write K-points
    1501            0 :  NCF_CHECK(nf90_put_var(ncid, vid("reduced_coordinates_of_kpoints"), kmesh%bz))
    1502            0 :  NCF_CHECK(nf90_put_var(ncid, vid("kpoint_weights"), kmesh%wt))
    1503            0 :  NCF_CHECK(ncerr)
    1504              : 
    1505              : contains
    1506            0 :  integer function vid(vname)
    1507              :    character(len=*),intent(in) :: vname
    1508            0 :    vid = nctk_idname(ncid, vname)
    1509              :  end function vid
    1510              : 
    1511              : end subroutine exc_ham_ncwrite
    1512              : !!***
    1513              : 
    1514              : !----------------------------------------------------------------------
    1515              : 
    1516              : END MODULE m_bse_io
    1517              : !!***
        

Generated by: LCOV version 2.3-1