LCOV - code coverage report
Current view: top level - src/67_common - m_ioarr.F90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 37.9 % 494 187
Test Date: 2026-09-21 22:40:37 Functions: 50.0 % 6 3

            Line data    Source code
       1              : !!****m* ABINIT/m_ioarr
       2              : !! NAME
       3              : !! m_ioarr
       4              : !!
       5              : !! FUNCTION
       6              : !!  This module provides routines to read/write arrays given on the FFT mesh (densities, potentials ...).
       7              : !!  The code supports both Fortran files as well as netcdf files in a transparent way.
       8              : !!  The appropriate IO layer is selected from files extensions: netcdf primitives are used if the
       9              : !!  file ends with `.nc`. If all the other cases we read/write files in Fortran format.
      10              : !!  MPI-IO primitives are used when the FFT arrays are MPI distributed.
      11              : !!
      12              : !! COPYRIGHT
      13              : !! Copyright (C) 1998-2026 ABINIT group (DCA, XG, GMR, MVer, MT, MG)
      14              : !!  This file is distributed under the terms of the
      15              : !!  GNU General Public License, see ~abinit/COPYING
      16              : !!  or http://www.gnu.org/copyleft/gpl.txt .
      17              : !!
      18              : !! SOURCE
      19              : 
      20              : #if defined HAVE_CONFIG_H
      21              : #include "config.h"
      22              : #endif
      23              : 
      24              : #include "abi_common.h"
      25              : 
      26              : MODULE m_ioarr
      27              : 
      28              :  use defs_basis
      29              :  use m_abicore
      30              :  USE_MPI
      31              :  use m_xmpi
      32              :  use m_wffile
      33              :  use m_errors
      34              :  use m_nctk
      35              :  use m_dtset
      36              :  use m_crystal
      37              :  use m_ebands
      38              :  use m_hdr
      39              :  use m_pawrhoij
      40              :  use netcdf
      41              : 
      42              :  use defs_abitypes,   only : mpi_type
      43              :  use defs_wvltypes,   only : wvl_denspot_type
      44              :  use m_time,          only : cwtime, cwtime_report, timab
      45              :  use m_io_tools,      only : iomode_from_fname, iomode2str, open_file, get_unit
      46              :  use m_fstrings,      only : sjoin, itoa, endswith, ltoa
      47              :  use m_numeric_tools, only : interpolate_denpot
      48              :  use m_geometry,      only : metric
      49              :  use m_mpinfo,        only : destroy_mpi_enreg, ptabs_fourdp, initmpi_seq
      50              :  use m_fourier_interpol,only : fourier_interpol
      51              : 
      52              :  implicit none
      53              : 
      54              : #ifdef HAVE_MPI1
      55              :  include 'mpif.h'
      56              : #endif
      57              : 
      58              :  private
      59              : 
      60              :  public :: ioarr                     ! Read or write rho(r) or v(r), either ground-state or response-functions.
      61              :  public :: fftdatar_write            ! Write an array in real space. IO library is automatically selected
      62              :                                      ! from the file extension and the number of FFT processors:
      63              :  public :: fftdatar_write_from_hdr   ! Write an array in real-space to file plus crystal_t and ebands_t
      64              :  public :: read_rhor                 ! Read rhor from DEN file.
      65              :  public :: fort_denpot_skip          ! Skip the header and the DEN/POT records (Fortran format)
      66              : 
      67              :  private :: denpot_spin_convert      ! Convert a density/potential from a spin representation to another
      68              : 
      69              : CONTAINS  !====================================================================================================
      70              : !!***
      71              : 
      72              : !----------------------------------------------------------------------
      73              : 
      74              : !!****f* m_ioarr/ioarr
      75              : !!
      76              : !! NAME
      77              : !! ioarr
      78              : !!
      79              : !! FUNCTION
      80              : !! Read or write rho(r) or v(r), either ground-state or response-functions.
      81              : !! If ground-state, these arrays are real, if response-functions, these arrays are complex.
      82              : !! (in general, an array stored in unformatted form on a real space fft grid).
      83              : !! rdwr=1 to read, 2 to write
      84              : !!
      85              : !! This subroutine should be called only by one processor in the writing mode
      86              : !!
      87              : !! INPUTS
      88              : !! (some may be output)
      89              : !! accessfil=
      90              : !!    0 for FORTRAN_IO
      91              : !!    3 for ETSF_IO
      92              : !!    4 for MPI_IO
      93              : !! cplex=1 for real array, 2 for complex
      94              : !! nfft=Number of FFT points treated by this node.
      95              : !! ngfft(18)=contain all needed information about 3D FFT, see ~abinit/doc/variables/vargs.htm#ngfft
      96              : !! dtset <type(dataset_type)>=all input variables for this dataset
      97              : !! fform=integer specification for data type:
      98              : !!   2 for wf; 52 for density; 102 for potential
      99              : !!   old format (prior to ABINITv2.0): 1, 51 and 101.
     100              : !! fildata=file name
     101              : !! hdr <type(hdr_type)>=the header of wf, den and pot files
     102              : !!  if rdwr=1 , used to compare with the hdr of the read disk file
     103              : !!  if rdwr=2 , used as the header of the written disk file
     104              : !! mpi_enreg=information about MPI parallelization
     105              : !! rdwr=choice parameter, see above
     106              : !! rdwrpaw=1 only if rhoij PAW quantities have to be read (if rdwr=1)
     107              : !! [single_proc]=True if only ONE MPI process is calling this routine. This usually happens when
     108              : !!   master calls ioarr to read data that is then broadcasted in the caller. Default: False.
     109              : !!   Note that singleproc is not compatible with FFT parallelism because nfft is assumed to be
     110              : !!   the total number of points in the FFT mesh.
     111              : !!
     112              : !! OUTPUT
     113              : !!  (see side effects)
     114              : !!
     115              : !! SIDE EFFECTS
     116              : !! Input/Output
     117              : !! arr(cplex*nfft,nspden)=array on real space grid, returned for rdwr=1, input for rdwr=2
     118              : !! etotal=total energy (Ha), returned for rdwr=1
     119              : !! === if rdwrpaw/=0 ===
     120              : !!  pawrhoij(my_natom*usepaw) <type(pawrhoij_type)>= paw rhoij occupancies and related data
     121              : !!
     122              : !! SOURCE
     123              : 
     124            0 : subroutine ioarr(accessfil,arr,dtset,etotal,fform,fildata,hdr,mpi_enreg, &
     125            0 : &                ngfft,cplex,nfft,pawrhoij,rdwr,rdwrpaw,wvl_den,single_proc)
     126              : 
     127              : !Arguments ------------------------------------
     128              : !scalars
     129              :  integer,intent(in) :: accessfil,cplex,nfft,rdwr,rdwrpaw
     130              :  integer,intent(inout) :: fform
     131              :  real(dp),intent(inout) :: etotal
     132              :  character(len=*),intent(in) :: fildata
     133              :  logical,optional,intent(in) :: single_proc
     134              :  type(MPI_type),intent(inout) :: mpi_enreg
     135              :  type(dataset_type),intent(in) :: dtset
     136              :  type(hdr_type),intent(inout) :: hdr
     137              :  type(wvl_denspot_type),optional, intent(in) :: wvl_den
     138              : !arrays
     139              :  integer,intent(in) :: ngfft(18)
     140              :  real(dp),intent(inout),target :: arr(cplex*nfft,dtset%nspden)
     141              :  type(pawrhoij_type),intent(inout) :: pawrhoij(:)
     142              : 
     143              : !Local variables-------------------------------
     144              :  integer :: ncid,ncerr
     145              :  character(len=fnlen) :: file_etsf
     146              : #ifdef HAVE_BIGDFT
     147              :  integer :: i,i1,i2,i3,ia,ind,n1,n2,n3
     148              :  integer :: zindex,zstart,zstop
     149              : #endif
     150              : !scalars
     151              :  integer,parameter :: master=0
     152              :  logical,parameter :: ALLOW_FFTINTERP=.True.
     153              :  logical :: need_fftinterp,icheck_fft,qeq0
     154              :  integer :: in_unt,out_unt,nfftot_in,nfftot_out,nspden,ncplxfft
     155              :  integer :: iomode,fform_dum,iarr,ierr,ispden,me,me_fft,comm_fft
     156              :  integer :: comm_cell,usewvl,unt
     157              :  integer :: restart,restartpaw,spaceComm,spaceComm_io
     158              :  real(dp) :: cputime,walltime,gflops
     159              :  character(len=500) :: msg,errmsg
     160              :  character(len=fnlen) :: my_fildata
     161              :  character(len=nctk_slen) :: varname
     162            0 :  type(hdr_type),target :: hdr0
     163              :  type(wffile_type) :: wff
     164            0 :  type(MPI_type) :: MPI_enreg_seq
     165              : !arrays
     166              :  integer :: ngfft_in(18),ngfft_out(18)
     167            0 :  integer, contiguous, pointer :: fftn2_distrib(:),ffti2_local(:),fftn3_distrib(:),ffti3_local(:)
     168            0 :  real(dp), contiguous, pointer :: arr_file(:,:),my_density(:,:)
     169            0 :  real(dp),allocatable :: rhor_file(:,:),rhog_in(:,:),rhor_out(:,:),rhog_out(:,:)
     170            0 :  type(pawrhoij_type),pointer:: pawrhoij__(:)
     171              : ! *************************************************************************
     172              : 
     173              :  DBG_ENTER("COLL")
     174              : 
     175            0 :  ncplxfft = cplex*nfft
     176              : 
     177            0 :  restartpaw=0
     178            0 :  my_fildata = fildata
     179            0 :  nspden = dtset%nspden; usewvl = dtset%usewvl
     180              : 
     181              :  ! Check validity of arguments--only rho(r) (51,52) and V(r) (101,102) are presently supported
     182            0 :  if ( (fform-1)/2 /=25 .and. (fform-1)/2 /=50 ) then
     183            0 :    write(msg,'(a,i0,a)')' Input fform= ',fform,' not allowed.'
     184            0 :    ABI_BUG(msg)
     185              :  end if
     186              : 
     187              :  ! Print input fform
     188            0 :  if ( (fform-1)/2==25 .and. rdwr==1) then
     189            0 :    msg = ' ioarr: reading density data '
     190            0 :  else if ( (fform-1)/2==25 .and. rdwr==2) then
     191            0 :    msg = ' ioarr: writing density data'
     192            0 :  else if ( (fform-1)/2==50 .and. rdwr==1) then
     193            0 :    msg = ' ioarr: reading potential data'
     194            0 :  else if ( (fform-1)/2==50 .and. rdwr==2) then
     195            0 :    msg = ' ioarr: writing potential data'
     196              :  end if
     197            0 :  call wrtout(std_out,msg)
     198              : 
     199            0 :  call wrtout(std_out, 'ioarr: file name is: '//TRIM(fildata))
     200              : 
     201            0 :  if (accessfil == IO_MODE_ETSF) then ! Initialize filename in case of ETSF file.
     202            0 :    file_etsf = nctk_ncify(fildata)
     203            0 :    call wrtout(std_out,sjoin('file name for ETSF access: ', file_etsf))
     204              :  end if
     205              : 
     206              : !Some definitions for MPI-IO access
     207            0 :  spaceComm = mpi_enreg%comm_cell
     208            0 :  comm_cell = mpi_enreg%comm_cell
     209            0 :  comm_fft = mpi_enreg%comm_fft
     210              : 
     211            0 :  if (accessfil == 4) then
     212            0 :    iomode=IO_MODE_MPI
     213            0 :    if (rdwr==1) then
     214              :      spaceComm=mpi_enreg%comm_cell
     215              :    else
     216            0 :      spaceComm=mpi_enreg%comm_fft
     217              :    end if
     218            0 :    me=xmpi_comm_rank(spaceComm)
     219            0 :    if (mpi_enreg%nproc_fft>1) then
     220            0 :      me_fft=mpi_enreg%me_fft
     221            0 :      spaceComm_io=mpi_enreg%comm_fft
     222              :    else
     223            0 :      me_fft=0
     224            0 :      spaceComm_io=xmpi_comm_self
     225              :    end if
     226              :  end if
     227            0 :  if (usewvl==1) then
     228            0 :    spaceComm=mpi_enreg%comm_cell
     229            0 :    me=xmpi_comm_rank(spaceComm)
     230              :  end if
     231              : 
     232              :  ! Change communicators and ranks if we are calling ioarr with one single processor.
     233            0 :  if (present(single_proc)) then
     234            0 :    if (single_proc) then
     235            0 :      spaceComm = xmpi_comm_self
     236            0 :      spaceComm_io = xmpi_comm_self
     237            0 :      ABI_CHECK(mpi_enreg%nproc_fft == 1, "single_proc cannot be used when nproc_fft > 1")
     238            0 :      comm_cell = xmpi_comm_self
     239            0 :      comm_fft = xmpi_comm_self
     240            0 :      me = 0
     241              :    end if
     242              :  end if
     243              : 
     244              : !=======================================
     245              : !Handle input from disk file
     246              : !=======================================
     247              : 
     248            0 :  call cwtime(cputime, walltime, gflops, "start")
     249              : 
     250            0 :  if (rdwr==1) then
     251            0 :    if (accessfil == 0 .or. accessfil == 4) then
     252              : 
     253              :      ! Here master checks if the input rho(r) is given on a FFT mesh that quals
     254              :      ! the one used in the run. If not, we perform a Fourier interpolation, we write the
     255              :      ! interpolated rho(r) to a temporary file and we use this file to restart.
     256            0 :      if (ALLOW_FFTINTERP .and. usewvl==0) then
     257            0 :        need_fftinterp = .False.; icheck_fft = .True.
     258              :        ! only master checks the FFT mesh if MPI-IO. All processors read ngfft if Fortran-IO
     259              :        ! Note that, when Fortran-IO is used, we don't know if the routine is called
     260              :        ! by a single processor or by all procs in comm_cell hence we cannot broadcast my_fildata
     261              :        ! inside spaceComm as done if accessfil == 4
     262            0 :        if (accessfil == 4) icheck_fft = (xmpi_comm_rank(spaceComm)==master)
     263              : 
     264            0 :        if (icheck_fft) then
     265            0 :          if (open_file(fildata,msg,newunit=in_unt,form='unformatted',status='old') /= 0) then
     266            0 :            ABI_ERROR(msg)
     267              :          end if
     268              : 
     269            0 :          call hdr_io(fform_dum,hdr0,rdwr,in_unt)
     270            0 :          need_fftinterp = (ANY(hdr%ngfft/=hdr0%ngfft) )
     271            0 :          qeq0=(hdr%qptn(1)**2+hdr%qptn(2)**2+hdr%qptn(3)**2<1.d-14)
     272              :          ! FIXME: SHould handle double-grid if PAW
     273            0 :          nfftot_in = product(hdr0%ngfft(1:3))
     274            0 :          nfftot_out = product(hdr%ngfft(1:3))
     275              : 
     276            0 :          if (need_fftinterp) then
     277              :            write(msg, "(2a,2(a,3(i0,1x)))")&
     278            0 :             "Will perform Fourier interpolation since in and out ngfft differ",ch10,&
     279            0 :             "ngfft in file: ",hdr0%ngfft,", expected ngfft: ",hdr%ngfft
     280            0 :            ABI_WARNING(msg)
     281              : 
     282              :            ! Read rho(r) from file, interpolate it, write data and change fildata
     283            0 :            ABI_MALLOC(rhor_file, (cplex*nfftot_in, hdr0%nspden))
     284            0 :            ABI_MALLOC(rhog_in, (2, nfftot_in))
     285            0 :            ABI_MALLOC(rhor_out, (cplex*nfftot_out, hdr0%nspden))
     286            0 :            ABI_MALLOC(rhog_out, (2, nfftot_out))
     287              : 
     288            0 :            do ispden=1,hdr0%nspden
     289            0 :              read(in_unt, err=10, iomsg=errmsg) (rhor_file(iarr,ispden), iarr=1,cplex*nfftot_in)
     290              :            end do
     291              : 
     292            0 :            ngfft_in = dtset%ngfft; ngfft_out = dtset%ngfft
     293            0 :            ngfft_in(1:3) = hdr0%ngfft(1:3); ngfft_out(1:3) = hdr%ngfft(1:3)
     294            0 :            ngfft_in(4:6) = hdr0%ngfft(1:3); ngfft_out(4:6) = hdr%ngfft(1:3)
     295            0 :            ngfft_in(9:18) = 0; ngfft_out(9:18) = 0
     296            0 :            ngfft_in(10) = 1; ngfft_out(10) = 1
     297              : 
     298            0 :            call initmpi_seq(MPI_enreg_seq)
     299              :            ! Which one is coarse? Note that this part is not very robust and can fail!
     300            0 :            if (ngfft_in(2) * ngfft_in(3) < ngfft_out(2) * ngfft_out(3)) then
     301            0 :              call MPI_enreg_seq%distribfft%init_seq('c',ngfft_in(2),ngfft_in(3),'all')
     302            0 :              call MPI_enreg_seq%distribfft%init_seq('f',ngfft_out(2),ngfft_out(3),'all')
     303              :            else
     304            0 :              call MPI_enreg_seq%distribfft%init_seq('f',ngfft_in(2),ngfft_in(3),'all')
     305            0 :              call MPI_enreg_seq%distribfft%init_seq('c',ngfft_out(2),ngfft_out(3),'all')
     306              :            end if
     307              : 
     308              :            call fourier_interpol(cplex,hdr0%nspden,0,0,nfftot_in,ngfft_in,nfftot_out,ngfft_out,&
     309            0 :             MPI_enreg_seq,rhor_file,rhor_out,rhog_in,rhog_out)
     310              : 
     311            0 :            call destroy_mpi_enreg(MPI_enreg_seq)
     312              : 
     313              :            ! MG Hack: Change fildata so that we will use this file to read the correct rho(r)
     314              :            ! FIXME: This should be done in a cleaner way!
     315            0 :            my_fildata = trim(fildata)//"__fftinterp_rhor__"
     316            0 :            if (my_fildata == fildata) my_fildata = "__fftinterp_rhor__"
     317            0 :            if (open_file(my_fildata,msg,newunit=out_unt,form='unformatted',status='unknown') /= 0) then
     318            0 :              ABI_ERROR(msg)
     319              :            end if
     320            0 :            call hdr_io(fform_dum,hdr,2,out_unt)
     321            0 :            do ispden=1,hdr0%nspden
     322            0 :              write(out_unt, err=10, iomsg=errmsg) (rhor_out(iarr,ispden),iarr=1,cplex*nfftot_out)
     323              :            end do
     324            0 :            close(out_unt)
     325              : 
     326            0 :            ABI_FREE(rhor_file)
     327            0 :            ABI_FREE(rhog_in)
     328            0 :            ABI_FREE(rhor_out)
     329            0 :            ABI_FREE(rhog_out)
     330              :          end if ! need_fftinterp
     331              : 
     332            0 :          call hdr0%free()
     333            0 :          close(in_unt, err=10, iomsg=errmsg)
     334              :        end if ! master
     335            0 :        if (accessfil == 4) call xmpi_bcast(my_fildata,master,spaceComm,ierr)
     336              :      end if
     337              : 
     338            0 :      if (accessfil == 4) then
     339            0 :        unt = get_unit()
     340            0 :        call WffOpen(iomode,spaceComm,my_fildata,ierr,wff,0,me,unt,spaceComm_io)
     341            0 :        call hdr_io(fform_dum,hdr0,rdwr,wff)
     342              :        ! Compare the internal header and the header from the file
     343            0 :        call hdr_check(fform,fform_dum,hdr,hdr0,'COLL',restart,restartpaw)
     344              : 
     345              :      else
     346            0 :        if (open_file(my_fildata, msg, newunit=unt, form="unformatted", status="old", action="read") /= 0) then
     347            0 :          ABI_ERROR(msg)
     348              :        end if
     349              :        ! Initialize hdr0, thanks to reading of unwff1
     350            0 :        call hdr_io(fform_dum,hdr0,rdwr,unt)
     351              :        ! Compare the internal header and the header from the file
     352            0 :        call hdr_check(fform,fform_dum,hdr,hdr0,'COLL',restart,restartpaw)
     353              :      end if
     354            0 :      etotal=hdr0%etot
     355              : 
     356              :      ! NOTE: should check that restart is possible !!
     357              :      !call ptabs_fourdp(mpi_enreg,ngfft(2),ngfft(3),fftn2_distrib,ffti2_local,fftn3_distrib,ffti3_local)
     358              : 
     359              :      ! If nspden[file] /= nspden, need a temporary array
     360            0 :      if (hdr0%nspden/=nspden) then
     361            0 :        ABI_MALLOC(arr_file,(cplex*nfft,hdr0%nspden))
     362              :      else
     363            0 :        arr_file => arr
     364              :      end if
     365              : 
     366              :      ! Read data
     367            0 :      do ispden=1,hdr0%nspden
     368            0 :        if(accessfil == 4) then
     369            0 :          call xderiveRRecInit(wff,ierr)
     370            0 :          call xderiveRead(wff,arr(1:ncplxfft,ispden),ncplxfft,spaceComm_io,ierr)
     371            0 :          call xderiveRRecEnd(wff,ierr)
     372              : 
     373              :          !call xmpio_read_dp(mpi_fh,offset,sc_mode,ncount,buf,fmarker,mpierr,advance)
     374              :          !do idat=1,ndat
     375              :          !  do i3=1,n3
     376              :          !    if( fftn3_distrib(i3) == me_fft) then
     377              :          !      i3_local = ffti3_local(i3)
     378              :          !      i3_ldat = i3_local + (idat - 1) * nd3proc
     379              :          !      do i2=1,n2
     380              :          !        frbase=n1*(i2-1+n2*(i3_local-1)) + (idat - 1) * nfft
     381              :          !        do i1=1,n1
     382              :          !          fofr(i1+frbase)=workr(1,i1,i2,i3_ldat)
     383              :          !        end do
     384              :          !      end do
     385              :          !    end if
     386              :          !  end do
     387              :          !end do
     388              : 
     389              :        else
     390            0 :          read(unt, err=10, iomsg=errmsg) (arr_file(iarr,ispden),iarr=1,ncplxfft)
     391              :        end if
     392              :      end do
     393              : 
     394            0 :      if (accessfil == 4) then
     395            0 :        call wffclose(wff,ierr)
     396              :      else
     397            0 :        close (unit=unt, err=10, iomsg=errmsg)
     398              :      end if
     399              : 
     400            0 :    else if (accessfil == 3) then
     401              : 
     402              :      ! Read the header and broadcast it in comm_cell
     403              :      ! FIXME: Use xmpi_comm_self for the time-being because, in loper, ioarr
     404              :      ! is called by me==0
     405            0 :      call hdr0%from_fname(file_etsf, fform_dum, comm_cell)
     406            0 :      ABI_CHECK(fform_dum/=0, "hdr_read_from_fname returned fform 0")
     407              : 
     408              :      ! Compare the internal header and the header from the file
     409            0 :      call hdr_check(fform, fform_dum, hdr, hdr0, 'COLL', restart, restartpaw)
     410              : 
     411              :      ! If nspden[file] /= nspden, need a temporary array
     412            0 :      if (hdr0%nspden /= nspden) then
     413            0 :        ABI_MALLOC(arr_file,(cplex*nfft,hdr0%nspden))
     414              :      else
     415            0 :        arr_file => arr
     416              :      end if
     417              : 
     418            0 :      if (usewvl == 1) then
     419              :        ! Read the array
     420            0 :        if (fform==52) then ! density
     421            0 :          varname = "density"
     422            0 :        else if (fform==102) then ! all potential forms!!!!
     423            0 :          varname = "exchange_correlation_potential"
     424              :        end if
     425              : 
     426              :        ! Open the file
     427            0 :        NCF_CHECK(nctk_open_read(ncid, file_etsf, xmpi_comm_self))
     428            0 :        NCF_CHECK(nf90_get_var(ncid, nctk_idname(ncid, varname), arr_file))
     429            0 :        NCF_CHECK(nf90_close(ncid))
     430              :      else
     431              :        ! Get MPI-FFT tables from input ngfft
     432            0 :        call ptabs_fourdp(mpi_enreg,ngfft(2),ngfft(3),fftn2_distrib,ffti2_local,fftn3_distrib,ffti3_local)
     433              : 
     434              :        ! Get the name of the netcdf variable from the ABINIT extension and read data.
     435            0 :        varname = varname_from_fname(file_etsf)
     436            0 :        ncerr = nctk_read_datar(file_etsf,varname,ngfft,cplex,nfft,hdr0%nspden,comm_fft,fftn3_distrib,ffti3_local,arr)
     437            0 :        NCF_CHECK(ncerr)
     438              :      end if
     439              : 
     440              :    else
     441            0 :      write(msg,'(a,i0,a)')'Bad value for accessfil', accessfil, ' on read '
     442            0 :      ABI_BUG(msg)
     443              :    end if
     444              : 
     445            0 :    call wrtout(std_out,sjoin("data read from disk file: ", fildata))
     446              : 
     447            0 :    etotal=hdr0%etot
     448              : 
     449              :    ! Possibly need to convert the potential/density spin components
     450            0 :    if (hdr0%nspden/=nspden) then
     451            0 :      call denpot_spin_convert(arr_file,hdr0%nspden,arr,nspden,fform)
     452            0 :      ABI_FREE(arr_file)
     453              :    end if
     454              : 
     455              :    ! Eventually copy (or distribute) PAW data
     456            0 :    if (rdwrpaw==1.and.restartpaw/=0) then
     457            0 :      pawrhoij__ => hdr0%pawrhoij  ! Trick needed by nvhpc 23.9
     458            0 :      if (size(pawrhoij__) /= size(pawrhoij)) then
     459              :        call pawrhoij_copy(hdr0%pawrhoij,pawrhoij,comm_atom=mpi_enreg%comm_atom,mpi_atmtab=mpi_enreg%my_atmtab, &
     460            0 :                           keep_nspden=.true.)
     461              :      else
     462            0 :        call pawrhoij_copy(hdr0%pawrhoij,pawrhoij,keep_nspden=.true.)
     463              :      end if
     464              :    end if
     465              : 
     466            0 :    if (accessfil == 0 .or. accessfil == 3 .or. accessfil == 4) call hdr0%free()
     467              : 
     468              :  ! =======================================
     469              :  ! Set up for writing data
     470              :  ! =======================================
     471            0 :  else if (rdwr==2) then
     472              : 
     473              : !  In the wavelet case (isolated boundary counditions), the
     474              : !  arr array has a buffer that we need to remove.
     475            0 :    if (usewvl == 1) then
     476              : #ifdef HAVE_BIGDFT
     477              :      zindex = wvl_den%denspot%dpbox%nscatterarr(me, 3)
     478              :      if (wvl_den%denspot%rhod%geocode == 'F') then
     479              :        n1 = (wvl_den%denspot%dpbox%ndims(1) - 31) / 2
     480              :        n2 = (wvl_den%denspot%dpbox%ndims(2) - 31) / 2
     481              :        n3 = (wvl_den%denspot%dpbox%ndims(3) - 31) / 2
     482              :        zstart = max(15 - zindex, 0)
     483              :        zstop  = wvl_den%denspot%dpbox%nscatterarr(me, 2) + &
     484              : &       wvl_den%denspot%dpbox%nscatterarr(me, 4) - &
     485              : &       max(zindex + wvl_den%denspot%dpbox%nscatterarr(me, 2) &
     486              : &       - 2 * n3 - 15, 0)
     487              :      else
     488              :        ABI_ERROR('ioarr: WVL not implemented yet.')
     489              :      end if
     490              :      if (zstop - zstart + 1 > 0) then
     491              : !      Our slab contains (zstop - zstart + 1) elements
     492              :        ABI_MALLOC(my_density,((n1*2)*(n2*2)*(zstop-zstart),nspden))
     493              : !      We copy the data except the buffer to my_density
     494              :        ind = 0
     495              : 
     496              :        do i3 = zstart, zstop - 1, 1
     497              :          ia = (i3 - 1) * dtset%ngfft(1) * dtset%ngfft(2)
     498              :          do i2 = 0, 2 * n2 - 1, 1
     499              :            i = ia + (i2 + 14) * dtset%ngfft(1) + 14
     500              :            do i1 = 0, 2 * n1 - 1, 1
     501              :              i   = i + 1
     502              :              ind = ind + 1
     503              :              my_density(ind, :) = arr(i, :)
     504              :            end do
     505              :          end do
     506              :        end do
     507              :      else
     508              :        nullify(my_density)
     509              :      end if
     510              : #else
     511            0 :      BIGDFT_NOTENABLED_ERROR()
     512              :      if(.false. .and. present(wvl_den))then
     513              :        write(std_out,*)' One should not be here'
     514              :      endif
     515              : #endif
     516              :    end if
     517              : 
     518              :    ! Make sure ngfft agrees with hdr%ngfft.
     519            0 :    if (usewvl == 0) then
     520            0 :      if (any(ngfft(:3) /= hdr%ngfft(:3))) then
     521            0 :        write(msg,"(2(a,3(1x,i0)))")"input ngfft: ",ngfft(:3),"differs from  hdr%ngfft: ",hdr%ngfft(:3)
     522            0 :        ABI_ERROR(msg)
     523              :      end if
     524              :    end if
     525              : 
     526            0 :    if (accessfil == 0 .or. accessfil == 4) then
     527            0 :      if(accessfil == 4) then
     528            0 :        unt = get_unit()
     529            0 :        call WffOpen(iomode,spaceComm,fildata,ierr,wff,0,me,unt)
     530            0 :        call hdr_io(fform,hdr,rdwr,wff)
     531              :      else
     532            0 :        if (open_file(fildata, msg, newunit=unt, form='unformatted', status='unknown', action="write") /= 0) then
     533            0 :          ABI_ERROR(msg)
     534              :        end if
     535              : 
     536              :        ! Write header
     537            0 :        call hdr_io(fform,hdr,rdwr,unt)
     538              :      end if
     539              : 
     540              :      ! Write actual data
     541            0 :      do ispden=1,nspden
     542            0 :        if(accessfil == 4) then
     543            0 :          call xderiveWRecInit(wff,ierr,me_fft)
     544            0 :          call xderiveWrite(wff,arr(1:ncplxfft,ispden),ncplxfft,spaceComm_io,ierr)
     545            0 :          call xderiveWRecEnd(wff,ierr,me_fft)
     546              :        else
     547            0 :          if (usewvl == 0) then
     548            0 :            write(unt, err=10, iomsg=errmsg) (arr(iarr,ispden),iarr=1,ncplxfft)
     549              :          else
     550            0 :            write(unt, err=10, iomsg=errmsg) (my_density(iarr,ispden),iarr=1,size(my_density, 1))
     551              :          end if
     552              :        end if
     553              :      end do
     554              : 
     555            0 :      if(accessfil == 4) then
     556            0 :        call WffClose(wff,ierr)
     557              :      else
     558            0 :        close(unt, err=10, iomsg=errmsg)
     559              :      end if
     560              : 
     561            0 :    else if ( accessfil == 3 ) then
     562              : 
     563              :      ! Master in comm_fft creates the file and writes the header.
     564            0 :      if (xmpi_comm_rank(comm_fft) == 0) then
     565            0 :        call hdr%write_to_fname(file_etsf, fform)
     566              :      end if
     567            0 :      call xmpi_barrier(comm_fft)
     568              : 
     569              :      ! Write the array
     570            0 :      if (usewvl == 0) then
     571              :        ! Get MPI-FFT tables from input ngfft
     572            0 :        call ptabs_fourdp(mpi_enreg,ngfft(2),ngfft(3),fftn2_distrib,ffti2_local,fftn3_distrib,ffti3_local)
     573              : 
     574            0 :        varname = varname_from_fname(file_etsf)
     575            0 :        ncerr = nctk_write_datar(varname,file_etsf,ngfft,cplex,nfft,nspden,comm_fft,fftn3_distrib,ffti3_local,arr)
     576            0 :        NCF_CHECK(ncerr)
     577              :      else
     578            0 :        NCF_CHECK(nctk_open_modify(ncid, file_etsf, xmpi_comm_self))
     579              : 
     580            0 :        if (fform==52) then ! density
     581            0 :          varname = "density"
     582              :          if (usewvl == 0) then
     583              :            NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, varname), arr))
     584              :          else
     585            0 :            NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, varname), my_density))
     586              :          end if
     587            0 :        else if (fform==102) then ! all potential forms!!!!
     588            0 :          varname = "exchange_correlation_potential"
     589            0 :          NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, varname), arr))
     590              :        end if
     591              : 
     592            0 :        NCF_CHECK(nf90_close(ncid))
     593              :      end if
     594              : 
     595              :    else
     596            0 :      write(msg,'(a,i0,a)')'Bad value for accessfil', accessfil, ' on write '
     597            0 :      ABI_ERROR(msg)
     598              :    end if
     599              : 
     600            0 :    if (usewvl == 1 .and. associated(my_density)) then
     601            0 :      ABI_FREE(my_density)
     602              :    end if
     603              : 
     604            0 :    call wrtout(std_out,sjoin(' Data written to disk file:', fildata))
     605              : 
     606              :  else
     607            0 :    write(msg,'(a,i0,a)')'Called with rdwr = ',rdwr,' not allowed.'
     608            0 :    ABI_BUG(msg)
     609              :  end if
     610              : 
     611            0 :  call cwtime_report(" IO operation", cputime, walltime, gflops)
     612              : 
     613              :  DBG_EXIT("COLL")
     614              : 
     615            0 :  return
     616              : 
     617              :  ! Handle Fortran IO error
     618              : 10 continue
     619            0 :  ABI_ERROR(errmsg)
     620              : 
     621            0 : end subroutine ioarr
     622              : !!***
     623              : 
     624              : !----------------------------------------------------------------------
     625              : 
     626              : !!****f* m_ioarr/fftdatar_write
     627              : !! NAME
     628              : !! fftdatar_write
     629              : !!
     630              : !! FUNCTION
     631              : !! Write an array in real space on the FFT box to file.
     632              : !! The array can be real or complex depending on cplex
     633              : !! IO library is automatically selected from the file extension and the number of FFT processors:
     634              : !!
     635              : !!   1) If path ends with ".nc", the netcdf library is used else Fortran format.
     636              : !!
     637              : !!   2) If nproc_fft > 1, parallel IO is used (if available)
     638              : !!
     639              : !! INPUTS
     640              : !! varname=Name of the variable to write (used if ETSF-IO).
     641              : !! path=File name
     642              : !! iomode=
     643              : !! hdr <type(hdr_type)>=the header of wf, den and pot files
     644              : !! crystal<crystal_t>= data type gathering info on symmetries and unit cell (used if etsf_io)
     645              : !! ngfft(18)=contain all needed information about 3D FFT, see ~abinit/doc/variables/vargs.htm#ngfft
     646              : !! cplex=1 for real array, 2 for complex
     647              : !! nfft=Number of FFT points treated by this node.
     648              : !! nspden=Number of spin-density components.
     649              : !! datar(cplex*nfft,nspden)=array on the real space FFT grid.
     650              : !! mpi_enreg=information about MPI parallelization
     651              : !! [ebands]<ebands_t>=data type with energies and occupations (used if etsf_io)
     652              : !!
     653              : !! OUTPUT
     654              : !!  Only writing
     655              : !!
     656              : !! NOTES
     657              : !!   The string passed to fftdatar_write (first argument) gives the name used to store the data in the netcdf file
     658              : !!   The function varname_from_fname defined in the module m_hdr.F90 gives the mapping between the Abinit
     659              : !!   file extension and the netcdf name e.g. foo_VHXC.nc --> vxc
     660              : !!   This function is used in cut3d so that we can immediately select the data to analyze without having
     661              : !!   to prompt the user
     662              : !!   Remember to update varname_from_fname if you add a new file or if you change the name of the variable.
     663              : !!
     664              : !!   fform i.e. the integer specification for data type is automatically initialized from varname.
     665              : !!
     666              : !! SOURCE
     667              : 
     668         7834 : subroutine fftdatar_write(varname,path,iomode,hdr,crystal,ngfft,cplex,nfft,nspden,datar,mpi_enreg,ebands)
     669              : 
     670              : !Arguments ------------------------------------
     671              : !scalars
     672              :  integer,intent(in) :: iomode,cplex,nfft,nspden
     673              :  character(len=*),intent(in) :: varname,path
     674              :  type(hdr_type),intent(inout) :: hdr
     675              :  type(crystal_t),intent(in) :: crystal
     676              :  type(ebands_t),optional,intent(in) :: ebands
     677              :  type(MPI_type),intent(in) :: mpi_enreg
     678              : !arrays
     679              :  integer,intent(in) :: ngfft(18)
     680              :  real(dp),intent(inout) :: datar(cplex*nfft,nspden)
     681              :  !type(pawrhoij_type),optional,intent(inout) :: pawrhoij_all(hdr%usepaw*crystal%natom)
     682              : 
     683              : !Local variables-------------------------------
     684              : !!scalars
     685              :  integer,parameter :: master=0
     686              :  integer :: n1,n2,n3,comm_fft,nproc_fft,me_fft,iarr,ierr,ii,ispden,unt,mpierr,fform
     687              :  integer :: i3_glob,my_iomode
     688              :  integer(kind=XMPI_OFFSET_KIND) :: hdr_offset,my_offset,nfft_tot
     689              :  integer :: ncid,ncerr
     690              :  character(len=fnlen) :: file_etsf
     691              :  real(dp) :: cputime,walltime,gflops
     692              :  character(len=500) :: msg,errmsg
     693              :  type(abifile_t) :: abifile
     694              : !arrays
     695         7834 :  integer, contiguous, pointer :: fftn2_distrib(:),ffti2_local(:),fftn3_distrib(:),ffti3_local(:)
     696         7834 :  integer(XMPI_OFFSET_KIND) :: bsize_frecord(nspden)
     697              : ! *************************************************************************
     698              : 
     699         7834 :  abifile = abifile_from_varname(varname)
     700         7834 :  if (abifile%fform == 0) then
     701            0 :     ABI_ERROR(sjoin("Cannot find any abifile object associated to varname:", varname))
     702              :  end if
     703              :  ! Get fform from abifile. TODO: check file extension
     704         7834 :  fform = abifile%fform
     705              : 
     706         7834 :  comm_fft = mpi_enreg%comm_fft; nproc_fft = xmpi_comm_size(comm_fft); me_fft = mpi_enreg%me_fft
     707         7834 :  n1 = ngfft(1); n2 = ngfft(2); n3 = ngfft(3); nfft_tot = n1*n2*n3
     708              : 
     709              :  ! Select iomode
     710              :  ! Use Fortran IO if nproc_fft 1, in principle this is not needed because the
     711              :  ! MPI-IO code should produce binary files that are readable with Fortran-IO
     712              :  ! but it seems that NAG uses its own binary format
     713         7834 :  my_iomode = iomode
     714         7834 :  if (my_iomode /= IO_MODE_ETSF .and. nproc_fft == 1) my_iomode = IO_MODE_FORTRAN
     715         7834 :  if (nproc_fft > 1 .and. my_iomode == IO_MODE_FORTRAN) my_iomode = IO_MODE_MPI
     716              : 
     717         7834 :  call wrtout(std_out, sjoin(ch10, "fftdatar_write: About to write data to:", path, "with iomode:",iomode2str(my_iomode)))
     718         7834 :  call cwtime(cputime, walltime, gflops, "start")
     719              : 
     720              :  ! Get MPI-FFT tables from input ngfft
     721         7834 :  call ptabs_fourdp(mpi_enreg,n2,n3,fftn2_distrib,ffti2_local,fftn3_distrib,ffti3_local)
     722              : 
     723           28 :  select case (my_iomode)
     724              :  case (IO_MODE_FORTRAN)
     725           28 :    ABI_CHECK(nproc_fft == 1, "MPI-IO must be enabled when FFT parallelism is used")
     726           28 :    if (open_file(path, msg, newunit=unt, form='unformatted', status='unknown', action="write") /= 0) then
     727            0 :      ABI_ERROR(msg)
     728              :    end if
     729           28 :    call hdr%fort_write(unt, fform, ierr)
     730           28 :    ABI_CHECK(ierr==0, "ierr !=0")
     731           59 :    do ii=1,nspden
     732           59 :      write(unt, err=10, iomsg=errmsg) (datar(iarr,ii), iarr=1,cplex * nfft)
     733              :    end do
     734           28 :    close(unt, err=10, iomsg=errmsg)
     735              : 
     736              :    ! Write PAW rhoij
     737              :    !call pawrhoij_io(hdr%pawrhoij,unit,hdr%nsppol,hdr%nspinor,hdr%nspden,hdr%lmn_size,hdr%typat,headform,"Write")
     738              :    !call pawrhoij_io(rhoij_ptr,ncid,hdr%nsppol,hdr%nspinor,hdr%nspden,hdr%lmn_size,hdr%typat,&
     739              :    !                 HDR_LATEST_HEADFORM,"Write",form="netcdf")
     740              : 
     741              : #ifdef HAVE_MPI_IO
     742              :  case (IO_MODE_MPI)
     743              :    ! Find the first z-plane treated by this node.
     744              :    ! WARNING: Here I assume that the z-planes in real space
     745              :    ! are distributed in contiguous blocks (as usually done in MPI-FFT)
     746         1188 :    do i3_glob=1,n3
     747         1188 :      if (me_fft == fftn3_distrib(i3_glob)) exit
     748              :    end do
     749          134 :    ABI_CHECK(i3_glob /= n3 +1, "This processor does not have z-planes!")
     750              : 
     751              :    ! Master writes the header.
     752          134 :    if (me_fft == master) call hdr%write_to_fname(path, fform)
     753          134 :    call xmpi_barrier(comm_fft) ! TODO: Non-blocking barrier.
     754              : 
     755          134 :    call MPI_FILE_OPEN(comm_fft, path, MPI_MODE_RDWR, xmpio_info, unt, mpierr)
     756          134 :    ABI_CHECK_MPI(mpierr,"MPI_FILE_OPEN")
     757              : 
     758              :    ! Skip the header and get the offset of the header
     759          134 :    call hdr_mpio_skip(unt,fform,hdr_offset)
     760              :    !write(std_out,*)"i3_glob, nfft, hdr_offset,",i3_glob,nfft,hdr_offset,fftn3_distrib == me_fft
     761              : 
     762              :    ! Each proc writes a contiguous slice of the nspden records.
     763              :    ! my_offset is the position inside the Fortran record.
     764          356 :    do ispden=1,nspden
     765              :      my_offset = hdr_offset + xmpio_bsize_frm + ((ispden - 1) * 2 * xmpio_bsize_frm) + &
     766          222 :      ((i3_glob-1) * cplex * n1 * n2 * xmpi_bsize_dp)  + ((ispden-1) * cplex * nfft_tot * xmpi_bsize_dp)
     767          222 :      call MPI_FILE_WRITE_AT_ALL(unt,my_offset,datar(:,ispden),cplex*nfft,MPI_DOUBLE_PRECISION,MPI_STATUS_IGNORE,mpierr)
     768          356 :      ABI_CHECK_MPI(mpierr,"MPI_FILE_WRITE_AT_ALL")
     769              :    end do
     770              : 
     771              :    ! master writes the fortran record markers.
     772          134 :    if (me_fft == master) then
     773          178 :      bsize_frecord = cplex * nfft_tot * xmpi_bsize_dp
     774              : #if 1
     775           67 :      my_offset = hdr_offset
     776          178 :      do ispden=1,nspden
     777          111 :        call xmpio_write_frm(unt,my_offset,xmpio_single,bsize_frecord(ispden),mpierr)
     778          178 :        ABI_CHECK_MPI(mpierr,"xmpio_write_frm")
     779              :      end do
     780              : #else
     781              :      ! TODO: Understand why this code does not work!
     782              :      call xmpio_write_frmarkers(unt,hdr_offset,xmpio_single,nspden,bsize_frecord,ierr)
     783              :      ABI_CHECK(ierr==0, "xmpio_write_frmarkers")
     784              : #endif
     785              :    end if
     786              : 
     787          134 :    call MPI_FILE_CLOSE(unt,mpierr)
     788          134 :    ABI_CHECK_MPI(mpierr,"FILE_CLOSE!")
     789              : 
     790              :    ! Add full pawrhoij datastructure at the end of the file.
     791              :    !if (present(pawrhoij_all) .and. me_fft == master .and. hdr%usepaw == 1) then
     792              :    !  if (open_file(path, msg, newunit=unt, form='unformatted', status='old', action="write", access="append") /= 0) then
     793              :    !    ABI_ERROR(msg)
     794              :    !  end if
     795              :    !  call pawrhoij_io(pawrhoij_all,un,hdr%nsppol,hdr%nspinor,hdr%nspden,hdr%lmn_size,hdr%typat,hdr%headform,"Write")
     796              :    !  close(unt)
     797              :    !end if
     798              : #endif
     799              : 
     800              :  case (IO_MODE_ETSF)
     801         7672 :    file_etsf = nctk_ncify(path)
     802              : 
     803              :    ! Write datar.
     804              :    ncerr = nctk_write_datar(varname,file_etsf,ngfft,cplex,nfft,nspden, &
     805         7672 :    comm_fft,fftn3_distrib,ffti3_local,datar,action="create")
     806         7672 :    NCF_CHECK(ncerr)
     807         7672 :    call xmpi_barrier(comm_fft)
     808              : 
     809              :    ! Master writes the header.
     810         7672 :    if (xmpi_comm_rank(comm_fft) == master) then
     811         7515 :      NCF_CHECK(nctk_open_modify(ncid, file_etsf, xmpi_comm_self))
     812         7515 :      NCF_CHECK(hdr%ncwrite(ncid, fform, nc_define=.True.))
     813              :      ! Add information on the crystalline structure.
     814         7515 :      NCF_CHECK(crystal%ncwrite(ncid))
     815         7515 :      if (present(ebands)) then
     816         3673 :        NCF_CHECK(ebands%ncwrite(ncid))
     817              :      end if
     818              : 
     819              :      ! Add full pawrhoij datastructure.
     820              :      !if (present(pawrhoij_all) .and. me_fft == master .and. hdr%usepaw == 1) then
     821              :      !  call pawrhoij_io(pawrhoij_all,ncid,hdr%nsppol,hdr%nspinor,hdr%nspden,hdr%lmn_size,hdr%typat,hdr%headform,"Write", form="netcdf")
     822              :      !end if
     823              : 
     824         7515 :      NCF_CHECK(nf90_close(ncid))
     825              :    end if
     826              : 
     827              :  case default
     828         7968 :    ABI_ERROR(sjoin("Wrong iomode:",itoa(my_iomode)))
     829              :  end select
     830              : 
     831         7834 :  call cwtime_report(" IO operation", cputime, walltime, gflops)
     832              : 
     833              :  return
     834              : 
     835              :  ! Handle Fortran IO error
     836              : 10 continue
     837            0 :  ABI_ERROR(errmsg)
     838              : 
     839         7834 : end subroutine fftdatar_write
     840              : !!***
     841              : 
     842              : !----------------------------------------------------------------------
     843              : 
     844              : !!****f* m_ioarr/fftdatar_write_from_hdr
     845              : !! NAME
     846              : !! fftdatar_write_from_hdr
     847              : !!
     848              : !! FUNCTION
     849              : !! Write an array in real space on the FFT box to file.
     850              : !! crystal and ebands are constructed from the Abinit header.
     851              : !!
     852              : !! TODO
     853              : !! This routine will be removed when crystal_t and ebands_t will become standard objects
     854              : !! available in the GS/DFPT part.
     855              : !!
     856              : !! INPUTS
     857              : !! [eigen](mband*hdr%nkpt*hdr%nsppol)=GS eigenvalues
     858              : !! See fftdatar_write for the meaning of the other variables.
     859              : !!
     860              : !! OUTPUT
     861              : !!
     862              : !! SOURCE
     863              : 
     864         3877 : subroutine fftdatar_write_from_hdr(varname,path,iomode,hdr,ngfft,cplex,nfft,nspden,datar,mpi_enreg,eigen)
     865              : 
     866              : !Arguments ------------------------------------
     867              : !scalars
     868              :  integer,intent(in) :: iomode,cplex,nfft,nspden
     869              :  character(len=*),intent(in) :: varname,path
     870              :  type(hdr_type),intent(inout) :: hdr
     871              :  type(MPI_type),intent(in) :: mpi_enreg
     872              : !arrays
     873              :  integer,intent(in) :: ngfft(18)
     874              :  real(dp),intent(inout) :: datar(cplex*nfft,nspden)
     875              :  real(dp),optional,intent(in) :: eigen(:)
     876              : 
     877              : !Local variables-------------------------------
     878              : !!scalars
     879              :  integer :: mband
     880              :  type(crystal_t) :: crystal
     881         3877 :  type(ebands_t) :: ebands
     882              : !arrays
     883         3877 :  real(dp),allocatable :: ene3d(:,:,:)
     884              : ! *************************************************************************
     885              : 
     886         3877 :  crystal = hdr%get_crystal()
     887              : 
     888         3877 :  if (present(eigen)) then
     889         1476 :      mband = maxval(hdr%nband)
     890           36 :      ABI_CHECK(size(eigen) ==  mband * hdr%nkpt * hdr%nsppol, "Wrong size(eigen)")
     891          180 :      ABI_MALLOC(ene3d, (mband, hdr%nkpt, hdr%nsppol))
     892           36 :      call unpack_eneocc(hdr%nkpt, hdr%nsppol, mband, hdr%nband, eigen, ene3d)
     893           36 :      call ebands%from_hdr(hdr, mband, ene3d)
     894           36 :      ABI_FREE(ene3d)
     895              : 
     896           36 :     call fftdatar_write(varname,path,iomode,hdr,crystal,ngfft,cplex,nfft,nspden,datar,mpi_enreg,ebands=ebands)
     897           36 :     call ebands%free()
     898              :  else
     899         3841 :     call fftdatar_write(varname,path,iomode,hdr,crystal,ngfft,cplex,nfft,nspden,datar,mpi_enreg)
     900              :  end if
     901              : 
     902         3877 :  call crystal%free()
     903              : 
     904         3877 : end subroutine fftdatar_write_from_hdr
     905              : !!***
     906              : 
     907              : !----------------------------------------------------------------------
     908              : 
     909              : !!****f* m_ioarr/read_rhor
     910              : !! NAME
     911              : !! read_rhor
     912              : !!
     913              : !! FUNCTION
     914              : !!  Read the DEN file with name fname reporting the density on the real FFT mesh
     915              : !!  specified through the input variable ngfft. If the FFT mesh asked in input and that found
     916              : !!  on file differ, the routine performs a FFT interpolation and renormalize the density so that it
     917              : !!  integrates to the correct number of electrons. The interpolation is done only for NC.
     918              : !!  For PAW, this is not possible because one should include the onsite contribution so this task
     919              : !!  is delegated to the caller.
     920              : !!
     921              : !! INPUTS
     922              : !! fname=Name of the file
     923              : !! cplex=1 if array is real, 2 if complex e.g. DFPT density.
     924              : !! nspden=Number of spin density components.
     925              : !! nfft=Number of FFT points (treated by this processor)
     926              : !! ngfft(18)=Info on the FFT mesh.
     927              : !! pawread= 1 if pawrhoij should be read from file, 0 otherwise. Meaningful only if usepaw==1.
     928              : !! mpi_enreg<MPI_type>=Information about MPI parallelization
     929              : !! comm=MPI communicator. See notes
     930              : !! [check_hdr] <type(hdr_type)>=Optional. Used to compare with the hdr read from disk file
     931              : !!   The routine will abort if restart cannot be performed.
     932              : !! [allow_interp]=If True, the density read from file will be interpolated if the mesh differs from the one
     933              : !!   expected by the caller. This option is usually used in **self-consistent** calculations.
     934              : !!   If False (default), the code stops if the two meshes are different.
     935              : !! [varname]=If present, check whether file contains varname
     936              : !!
     937              : !! OUTPUT
     938              : !! orhor(cplex*nfft,nspden)=The density on the real space mesh.
     939              : !! ohdr=Abinit header read from file.
     940              : !! pawrhoij(my_natom*usepaw) <type(pawrhoij_type)>= paw rhoij occupancies and related data. only
     941              : !!   if pawread==1. The arrays is supposed to be already allocated in the caller and its
     942              : !!   size must be consistent with the MPI communicator comm.
     943              : !!
     944              : !! NOTES
     945              : !!   if xmpi_comm_size(comm) == 1, nfft shall be equal to nfftot, and len(pawrhoij) == natom
     946              : !!   This means that one can call this routine with
     947              : !!
     948              : !!     if (xmpi_comm_rank(comm) == 0) call read_rhor(...., comm=xmpi_comm_self)
     949              : !!
     950              : !!   to get the full array and pawrhoij(natom) on the master node.
     951              : !!
     952              : !!   if xmpi_comm_size(comm) > 1, nfft represents the number of FFT points treated by this processor,
     953              : !!   and pawrhoij is dimensioned with my_natom
     954              : !!   All the processors inside comm and comm_atom should call this routine.
     955              : !!
     956              : !! SOURCE
     957              : 
     958         2186 : subroutine read_rhor(fname, cplex, nspden, nfft, ngfft, pawread, mpi_enreg, orhor, ohdr, pawrhoij, comm, &
     959              :                      check_hdr, allow_interp, want_varname) ! Optional
     960              : 
     961              : !Arguments ------------------------------------
     962              : !scalars
     963              :  integer,intent(in) :: cplex,nfft,nspden,pawread,comm
     964              :  character(len=*),intent(in) :: fname
     965              :  type(MPI_type),intent(in) :: mpi_enreg
     966              :  type(hdr_type),intent(out) :: ohdr
     967              :  type(hdr_type),optional,intent(in) :: check_hdr
     968              :  logical,optional,intent(in) :: allow_interp
     969              :  character(len=*),optional,intent(in) :: want_varname
     970              : !arrays
     971              :  integer,intent(in) :: ngfft(18)
     972              :  real(dp),intent(out) :: orhor(cplex*nfft,nspden)
     973              :  type(pawrhoij_type),intent(inout) :: pawrhoij(:)
     974              : 
     975              : !Local variables-------------------------------
     976              : !scalars
     977              :  integer,parameter :: master=0
     978              :  integer :: unt,fform,iomode,my_rank,mybase,globase,cplex_file
     979              :  integer :: ispden,ifft,nfftot_file,nprocs,ierr,i1,i2,i3,i3_local,n1,n2,n3
     980              :  integer,parameter :: fform_den=52
     981              :  integer :: restart, restartpaw
     982              :  integer :: ncerr
     983              :  real(dp) :: ratio,ucvol
     984              :  real(dp) :: cputime,walltime,gflops
     985              :  logical :: need_interp,have_mpifft,allow_interp__
     986              :  character(len=500) :: msg,errmsg
     987              :  character(len=fnlen) :: my_fname
     988              :  character(len=nctk_slen) :: varname
     989              : !arrays
     990         2186 :  integer, contiguous, pointer :: fftn2_distrib(:),ffti2_local(:),fftn3_distrib(:),ffti3_local(:)
     991              :  real(dp) :: gmet(3,3),gprimd(3,3),rmet(3,3),tsec(2)
     992         2186 :  real(dp),allocatable :: rhor_file(:,:),rhor_tmp(:,:)
     993         2186 :  type(pawrhoij_type),allocatable :: pawrhoij_file(:)
     994              : ! *************************************************************************
     995              : 
     996         2186 :  my_rank = xmpi_comm_rank(comm); nprocs = xmpi_comm_size(comm)
     997         8744 :  n1 = ngfft(1); n2 = ngfft(2); n3 = ngfft(3); have_mpifft = (nfft /= product(ngfft(1:3)))
     998         2186 :  allow_interp__ = .False.; if (present(allow_interp)) allow_interp__ = allow_interp
     999              : 
    1000         2186 :  call timab(1280,1,tsec)
    1001         2186 :  call wrtout(std_out, sjoin(" About to read data(r) from:", fname), do_flush=.True.)
    1002         2186 :  call cwtime(cputime, walltime, gflops, "start")
    1003              : 
    1004              :  ! Master node opens the file, read the header and the FFT data
    1005              :  ! This approach facilitates the interpolation of the density if in_ngfft(1:3) /= file_ngfft(1:3)
    1006         2186 :  if (my_rank == master) then
    1007         1990 :    my_fname = fname
    1008         1990 :    if (nctk_try_fort_or_ncfile(my_fname, msg) /= 0 ) then
    1009            0 :      ABI_ERROR(msg)
    1010              :    end if
    1011              : 
    1012         1990 :    iomode = iomode_from_fname(my_fname)
    1013            3 :    select case (iomode)
    1014              : 
    1015              :    case (IO_MODE_FORTRAN, IO_MODE_MPI)
    1016            3 :      if (open_file(my_fname, msg, newunit=unt, form='unformatted', status='old', action="read") /= 0) then
    1017            0 :        ABI_ERROR(msg)
    1018              :      end if
    1019              : 
    1020            3 :      call ohdr%fort_read(unt, fform)
    1021              : 
    1022              :      ! Check important dimensions.
    1023            3 :      ABI_CHECK(fform /= 0, sjoin("fform == 0 while reading:", my_fname))
    1024            3 :      if (present(want_varname)) then
    1025            0 :        ABI_CHECK(fform_contains(fform, want_varname, msg), msg)
    1026              :      end if
    1027              : 
    1028            3 :      cplex_file = 1
    1029            3 :      if (ohdr%pertcase /= 0) then
    1030            3 :        cplex_file = 2; if (ohdr%qptn(1)**2 + ohdr%qptn(2)**2 + ohdr%qptn(3)**2 <1.d-14) cplex_file= 1
    1031              :      end if
    1032            3 :      ABI_CHECK(cplex_file == cplex, "cplex_file != cplex")
    1033              : 
    1034              :      ! Read FFT array (full box)
    1035           12 :      nfftot_file = product(ohdr%ngfft(:3))
    1036           12 :      ABI_MALLOC(rhor_file, (cplex*nfftot_file, ohdr%nspden))
    1037            6 :      do ispden=1,ohdr%nspden
    1038            6 :        read(unt, err=10, iomsg=errmsg) (rhor_file(ifft,ispden), ifft=1,cplex*nfftot_file)
    1039              :      end do
    1040            3 :      close(unt)
    1041              : 
    1042              :    case (IO_MODE_ETSF)
    1043         1987 :      NCF_CHECK(nctk_open_read(unt, my_fname, xmpi_comm_self))
    1044         1987 :      call ohdr%ncread(unt, fform)
    1045              : 
    1046              :      ! Check important dimensions.
    1047         1987 :      ABI_CHECK(fform /= 0, sjoin("fform == 0 while reading:", my_fname))
    1048              :      !if (fform /= fform_den) then
    1049              :      !  write(msg, "(2a, 2(a, i0))")' File: ',trim(my_fname),' is not a density file: fform= ',fform,", expecting:", fform_den
    1050              :      !  ABI_WARNING(msg)
    1051              :      !end if
    1052              : 
    1053         1987 :      cplex_file = 1
    1054         1987 :      if (ohdr%pertcase /= 0) then
    1055         1987 :        cplex_file = 2; if (ohdr%qptn(1)**2 + ohdr%qptn(2)**2 + ohdr%qptn(3)**2 <1.d-14) cplex_file= 1
    1056              :      end if
    1057         1987 :      ABI_CHECK(cplex_file == cplex, "cplex_file != cplex")
    1058              : 
    1059              :      ! Read FFT array (full box)
    1060         7948 :      nfftot_file = product(ohdr%ngfft(:3))
    1061         7948 :      ABI_MALLOC(rhor_file, (cplex*nfftot_file, ohdr%nspden))
    1062              : 
    1063         1987 :      varname = varname_from_fname(my_fname)
    1064              :      ncerr= nf90_get_var(unt, nctk_idname(unt, varname), rhor_file, &
    1065        11922 :                         count=[cplex, ohdr%ngfft(1), ohdr%ngfft(2), ohdr%ngfft(3), ohdr%nspden])
    1066         1987 :      NCF_CHECK(ncerr)
    1067         1987 :      NCF_CHECK(nf90_close(unt))
    1068              : 
    1069              :    case default
    1070         1990 :      ABI_ERROR(sjoin("Wrong iomode:", itoa(iomode)))
    1071              :    end select
    1072              : 
    1073         7909 :    need_interp = any(ohdr%ngfft(1:3) /= ngfft(1:3))
    1074         1990 :    if (need_interp) then
    1075              :      msg = sjoin("Different FFT meshes. Caller expects:", ltoa(ngfft(1:3)), &
    1076           17 :                  ". File: ", ltoa(ohdr%ngfft(1:3)), ". Need to perform interpolation.")
    1077           17 :      ABI_COMMENT(msg)
    1078           17 :      if (.not. allow_interp__) then
    1079              :        write(msg, "(5a)") &
    1080            0 :         " Cannot continue as allow_interp = .False. ", ch10, &
    1081            0 :         " Please set ngfft to: ", trim(ltoa(ohdr%ngfft(1:3))), " in the input file"
    1082            0 :        ABI_ERROR(msg)
    1083              :      end if
    1084              : 
    1085          119 :      ABI_MALLOC(rhor_tmp, (cplex*product(ngfft(1:3)), ohdr%nspden))
    1086           17 :      call timab(1281,1,tsec)
    1087           17 :      call interpolate_denpot(cplex, ohdr%ngfft(1:3), ohdr%nspden, rhor_file, ngfft(1:3), rhor_tmp)
    1088           17 :      call timab(1281,2,tsec)
    1089              : 
    1090           68 :      ohdr%ngfft(1:3) = ngfft(1:3)
    1091           68 :      nfftot_file = product(ohdr%ngfft(:3))
    1092           17 :      ABI_FREE(rhor_file)
    1093           68 :      ABI_MALLOC(rhor_file, (cplex*nfftot_file, ohdr%nspden))
    1094       223947 :      rhor_file = rhor_tmp
    1095           17 :      ABI_FREE(rhor_tmp)
    1096              : 
    1097              :      ! Renormalize charge to avoid errors due to the interpolation.
    1098              :      ! Do this only for NC since for PAW we should add the onsite contribution.
    1099              :      ! This is left to the caller.
    1100              :      !if (ohdr%usepaw == 0) then
    1101           17 :      if (ohdr%usepaw == 0 .and. fform == fform_den) then
    1102            4 :        call metric(gmet, gprimd, -1, rmet, ohdr%rprimd, ucvol)
    1103        46808 :        ratio = ohdr%nelect / (sum(rhor_file(:,1))*ucvol/ product(ngfft(1:3)))
    1104        46800 :        rhor_file = rhor_file * ratio
    1105            4 :        write(msg,'(a,f8.2,a,f8.4)')' Expected nelect: ',ohdr%nelect,' renormalization ratio: ',ratio
    1106            4 :        call wrtout(std_out,msg)
    1107              :      end if
    1108              :    end if ! need_interp
    1109              : 
    1110              :    ! Read PAW Rhoij
    1111         1990 :    if (ohdr%usepaw == 1) then
    1112         2149 :      ABI_MALLOC(pawrhoij_file, (ohdr%natom))
    1113          427 :      call pawrhoij_nullify(pawrhoij_file)
    1114              :      call pawrhoij_alloc(pawrhoij_file, ohdr%pawrhoij(1)%cplex_rhoij, ohdr%pawrhoij(1)%nspden, ohdr%pawrhoij(1)%nspinor, &
    1115          427 :          ohdr%pawrhoij(1)%nsppol, ohdr%typat, lmnsize=ohdr%lmn_size, qphase=ohdr%pawrhoij(1)%qphase)
    1116          427 :      call pawrhoij_copy(ohdr%pawrhoij, pawrhoij_file)
    1117              :    end if
    1118              : 
    1119              :   ! Check that restart is possible !
    1120              :   ! This check must be done here because we may have changed hdr% if need_interp
    1121         1990 :   if (present(check_hdr)) then
    1122              :     ! FIXME: Temporary hack: fform_den to make hdr_check happy!
    1123         1958 :     call hdr_check(fform_den, fform_den, check_hdr, ohdr, "COLL", restart, restartpaw)
    1124              :     !call hdr_check(fform_den, fform, check_hdr, ohdr, "COLL", restart, restartpaw)
    1125              :   end if
    1126              : 
    1127              :  end if ! master
    1128              : 
    1129         2186 :  if (nprocs == 1) then
    1130         1898 :    if (ohdr%nspden == nspden) then
    1131     21141320 :      orhor = rhor_file
    1132              :    else
    1133            0 :      call denpot_spin_convert(rhor_file,ohdr%nspden,orhor,nspden,fform)
    1134              :    end if
    1135         1898 :    if (pawread == 1) call pawrhoij_copy(pawrhoij_file, pawrhoij, keep_nspden=.true.)
    1136              : 
    1137              :  else
    1138          288 :    call ohdr%bcast(master, my_rank, comm)
    1139          288 :    call xmpi_bcast(fform, master, comm, ierr)
    1140              : 
    1141              :    ! Eventually copy (or distribute) PAW data
    1142          288 :    if (ohdr%usepaw == 1 .and. pawread == 1) then
    1143           20 :      if (my_rank /= master) then
    1144           63 :        ABI_MALLOC(pawrhoij_file, (ohdr%natom))
    1145           15 :        call pawrhoij_nullify(pawrhoij_file)
    1146              :        call pawrhoij_alloc(pawrhoij_file, ohdr%pawrhoij(1)%cplex_rhoij, ohdr%pawrhoij(1)%nspden, ohdr%pawrhoij(1)%nspinor, &
    1147           15 :             ohdr%pawrhoij(1)%nsppol, ohdr%typat, lmnsize=ohdr%lmn_size, qphase=ohdr%pawrhoij(1)%qphase)
    1148              :      end if
    1149           20 :      if (size(ohdr%pawrhoij) /= size(pawrhoij)) then
    1150              :        call pawrhoij_copy(ohdr%pawrhoij,pawrhoij,comm_atom=mpi_enreg%comm_atom,mpi_atmtab=mpi_enreg%my_atmtab, &
    1151            4 :                           keep_nspden=.true.)
    1152              :      else
    1153           16 :        call pawrhoij_copy(ohdr%pawrhoij,pawrhoij, keep_nspden=.true.)
    1154              :      end if
    1155              :    end if
    1156              : 
    1157          288 :    if (my_rank /= master) then
    1158          784 :      nfftot_file = product(ohdr%ngfft(1:3))
    1159          784 :      ABI_MALLOC(rhor_file, (cplex*nfftot_file, ohdr%nspden))
    1160              :    end if
    1161          288 :    call xmpi_bcast(rhor_file, master, comm,ierr)
    1162              : 
    1163          288 :    if (have_mpifft) then
    1164              :      ! Extract slice treated by this MPI-FFT process.
    1165           24 :      call ptabs_fourdp(mpi_enreg, ngfft(2), ngfft(3), fftn2_distrib, ffti2_local, fftn3_distrib, ffti3_local)
    1166           24 :      if (ohdr%nspden==nspden) then
    1167           48 :        do ispden=1,nspden
    1168          744 :          do i3=1,n3
    1169          696 :            if (fftn3_distrib(i3) /= mpi_enreg%me_fft) cycle
    1170          268 :            i3_local = ffti3_local(i3)
    1171         8524 :            do i2=1,n2
    1172         8232 :              mybase = cplex * (n1 * (i2-1 + n2*(i3_local-1)))
    1173         8232 :              globase = cplex * (n1 * (i2-1 + n2*(i3-1)))
    1174       293104 :              do i1=1,n1*cplex
    1175       292408 :                orhor(i1+mybase,ispden) = rhor_file(i1+globase,ispden)
    1176              :              end do
    1177              :            end do
    1178              :          end do
    1179              :        end do
    1180              :      else
    1181            0 :        do i3=1,n3
    1182            0 :          if (fftn3_distrib(i3) /= mpi_enreg%me_fft) cycle
    1183            0 :          i3_local = ffti3_local(i3)
    1184            0 :          do i2=1,n2
    1185            0 :            mybase  = 1 + cplex * (n1 * (i2-1 + n2*(i3_local-1)))
    1186            0 :            globase = 1 + cplex * (n1 * (i2-1 + n2*(i3-1)))
    1187              :            call denpot_spin_convert(rhor_file,ohdr%nspden,orhor,nspden,fform,&
    1188            0 :                                     istart_in=globase,istart_out=mybase,nelem=n1*cplex)
    1189              :          end do
    1190              :        end do
    1191              :      end if
    1192              :    else
    1193          264 :      if (ohdr%nspden==nspden) then
    1194      2998846 :        orhor = rhor_file
    1195              :      else
    1196            0 :        call denpot_spin_convert(rhor_file,ohdr%nspden,orhor,nspden,fform)
    1197              :      end if
    1198              :    end if
    1199              :  end if ! nprocs > 1
    1200              : 
    1201         2186 :  ABI_FREE(rhor_file)
    1202              : 
    1203         2186 :  if (allocated(pawrhoij_file)) then
    1204          442 :    call pawrhoij_free(pawrhoij_file)
    1205         1328 :    ABI_FREE(pawrhoij_file)
    1206              :  end if
    1207              : 
    1208              : ! Non-collinear magnetism: avoid zero magnetization, because it produces numerical instabilities
    1209              : ! Add a small real to the magnetization
    1210        16330 :  if (nspden==4) orhor(:,4)=orhor(:,4)+tol14
    1211         2186 :  if (ohdr%usepaw==1.and.size(pawrhoij)>0) then
    1212          421 :    if (pawrhoij(1)%nspden==4) then
    1213            5 :      do i1=1,size(pawrhoij)
    1214          711 :        pawrhoij(i1)%rhoijp(:,4)=pawrhoij(i1)%rhoijp(:,4)+tol10
    1215              :      end do
    1216              :    end if
    1217              :  end if
    1218              : 
    1219         2186 :  call timab(1280,2,tsec)
    1220         2186 :  call cwtime_report(" read_rhor", cputime, walltime, gflops)
    1221         2186 :  return
    1222              : 
    1223              :  ! Handle Fortran IO error
    1224              : 10 continue
    1225            0 :  ABI_ERROR(errmsg)
    1226              : 
    1227         4386 : end subroutine read_rhor
    1228              : !!***
    1229              : 
    1230              : !----------------------------------------------------------------------
    1231              : 
    1232              : !!****f* m_ioarr/fort_denpot_skip
    1233              : !! NAME
    1234              : !!  fort_denpot_skip
    1235              : !!
    1236              : !! FUNCTION
    1237              : !!  Skip the header and the DEN/POT records. Mainly used to append data to a pre-existent file.
    1238              : !!  Return exit code.
    1239              : !!
    1240              : !! INPUTS
    1241              : !!  unit=Fortran unit number (already opened in the caller).
    1242              : !!  msg=Error message if ierr /= 0
    1243              : !!
    1244              : !! SOURCE
    1245              : 
    1246            0 : integer function fort_denpot_skip(unit, msg) result(ierr)
    1247              : 
    1248              : !Arguments ------------------------------------
    1249              :  integer,intent(in) :: unit
    1250              :  character(len=*),intent(out) :: msg
    1251              : 
    1252              : !Local variables-------------------------------
    1253              :  integer :: ii,fform,nspden
    1254            0 :  type(hdr_type) :: hdr
    1255              : 
    1256              : ! *********************************************************************
    1257              : 
    1258            0 :  ierr = 1
    1259            0 :  call hdr%fort_read(unit, fform)
    1260            0 :  if (fform == 0) then
    1261            0 :    msg = "hdr_fort_read returned fform == 0"; return
    1262              :  end if
    1263              : 
    1264            0 :  nspden = hdr%nspden
    1265            0 :  call hdr%free()
    1266              : 
    1267              :  ! Skip the records with v1.
    1268            0 :  do ii=1,nspden
    1269            0 :    read(unit, iostat=ierr, iomsg=msg)
    1270            0 :    if (ierr /= 0) return
    1271              :  end do
    1272              : 
    1273            0 :  ierr = 0
    1274              : 
    1275            0 : end function fort_denpot_skip
    1276              : !!***
    1277              : 
    1278              : !----------------------------------------------------------------------
    1279              : 
    1280              : !!****f* m_ioarr/denpot_spin_convert
    1281              : !! NAME
    1282              : !!  denpot_spin_convert
    1283              : !!
    1284              : !! FUNCTION
    1285              : !!  Convert a density/potential from a spin representation to another
    1286              : !!
    1287              : !! INPUTS
    1288              : !!  denpot_in(:,nspden_in)=input density//potential
    1289              : !!  nspden_in=number of spin-component of the input density/potential
    1290              : !!  fform=file format (density or potential)
    1291              : !!  [istart_in]= --optional-- starting index in the denpot_in array; default is 1
    1292              : !!  [istart_out]= --optional-- starting index in the denpot_out array; default is 1
    1293              : !!  [nelem]= --optional-- number of elements to copy from denpot_in to denpot_out; default is all
    1294              : !!
    1295              : !! OUTPUT
    1296              : !!  denpot_out(:,nspden_out)=output density//potential
    1297              : !!  nspden_out=number of spin-component of the output density/potential
    1298              : !!
    1299              : !! NOTES
    1300              : !!  More explicitely:
    1301              : !!    We copy denpot_in(istar_in+1:istart_in+nelem,:)
    1302              : !!       into denpot_out(istart_out+1:istart_out+nelem,:)
    1303              : !!
    1304              : !! SOURCE
    1305              : 
    1306            0 : subroutine denpot_spin_convert(denpot_in,nspden_in,denpot_out,nspden_out,fform,&
    1307              : &                              istart_in,istart_out,nelem) ! optional arguments
    1308              : 
    1309              : !Arguments ------------------------------------
    1310              : !scalars
    1311              :  integer,intent(in) :: nspden_in,nspden_out,fform
    1312              :  integer,intent(in),optional :: istart_in,istart_out,nelem
    1313              : !arrays
    1314              :  real(dp),intent(in) :: denpot_in(:,:)
    1315              :  real(dp),intent(out) :: denpot_out(:,:)
    1316              : 
    1317              : !Local variables-------------------------------
    1318              :  integer :: iend_in,iend_out,ispden,my_istart_in,my_istart_out,my_nelem
    1319              :  character(len=500) :: msg
    1320              : 
    1321              : ! *********************************************************************
    1322              : 
    1323              : !Optional arguments
    1324            0 :  my_istart_in=1;if (present(istart_in)) my_istart_in=istart_in
    1325            0 :  my_istart_out=1;if (present(istart_out)) my_istart_out=istart_out
    1326            0 :  iend_in=size(denpot_in,1) ; iend_out=size(denpot_out,1)
    1327            0 :  my_nelem=min(iend_in-my_istart_in+1,iend_out-my_istart_out+1)
    1328            0 :  if (present(nelem)) my_nelem=nelem
    1329              : 
    1330              : !Checks
    1331            0 :  if (size(denpot_in,2)/=nspden_in) then
    1332            0 :    msg='size(denpot_in,2)/=nspden_in!'
    1333            0 :    ABI_BUG(msg)
    1334              :  end if
    1335            0 :  if (size(denpot_out,2)/=nspden_out) then
    1336            0 :    msg='size(denpot_out,2)/=nspden_out!'
    1337            0 :    ABI_BUG(msg)
    1338              :  end if
    1339            0 :  if (my_istart_in+my_nelem-1>size(denpot_in,1)) then
    1340            0 :    msg='istart_in+nelem>size(denpot_in,1)!'
    1341            0 :    ABI_BUG(msg)
    1342              :  end if
    1343            0 :  if (my_istart_out+my_nelem-1>size(denpot_out,1)) then
    1344            0 :    msg='istart_out+nelem>size(denpot_out,1)!'
    1345            0 :    ABI_BUG(msg)
    1346              :  end if
    1347              : 
    1348              : !Simple copy if the number of spin-components is unchanged...
    1349            0 :  if (nspden_in==nspden_out) then
    1350            0 :    do ispden=1,nspden_in
    1351              :      denpot_out(my_istart_out:my_istart_out+my_nelem-1,ispden)= &
    1352            0 : &      denpot_in(my_istart_in:my_istart_in+my_nelem-1,ispden)
    1353              :    end do
    1354            0 :    return
    1355              :  end if
    1356              : 
    1357              : !...otherwise, we need to convert.
    1358            0 :  if ((fform-1)/2==25) then
    1359              : 
    1360              : !  First case: DENSITY
    1361              : 
    1362            0 :    if      (nspden_in==1.and.nspden_out==2) then
    1363            0 :      denpot_out(my_istart_out:my_istart_out+my_nelem-1,1)=denpot_in(my_istart_in:my_istart_in+my_nelem-1,1)
    1364            0 :      denpot_out(my_istart_out:my_istart_out+my_nelem-1,2)=denpot_in(my_istart_in:my_istart_in+my_nelem-1,1)*half
    1365            0 :    else if (nspden_in==1.and.nspden_out==4) then
    1366            0 :      denpot_out(my_istart_out:my_istart_out+my_nelem-1,1)=denpot_in(my_istart_in:my_istart_in+my_nelem-1,1)
    1367            0 :      denpot_out(my_istart_out:my_istart_out+my_nelem-1,2)=zero
    1368            0 :      denpot_out(my_istart_out:my_istart_out+my_nelem-1,3)=zero
    1369            0 :      denpot_out(my_istart_out:my_istart_out+my_nelem-1,4)=zero
    1370            0 :    else if (nspden_in==2.and.nspden_out==1) then
    1371            0 :      denpot_out(my_istart_out:my_istart_out+my_nelem-1,1)=denpot_in(my_istart_in:my_istart_in+my_nelem-1,1)
    1372            0 :    else if (nspden_in==2.and.nspden_out==4) then
    1373            0 :      denpot_out(my_istart_out:my_istart_out+my_nelem-1,1)=denpot_in(my_istart_in:my_istart_in+my_nelem-1,1)
    1374            0 :      denpot_out(my_istart_out:my_istart_out+my_nelem-1,2)=zero
    1375            0 :      denpot_out(my_istart_out:my_istart_out+my_nelem-1,3)=zero
    1376              :      denpot_out(my_istart_out:my_istart_out+my_nelem-1,4)=denpot_in(my_istart_in:my_istart_in+my_nelem-1,2)*two &
    1377            0 : &                                                        -denpot_in(my_istart_in:my_istart_in+my_nelem,1)
    1378            0 :    else if (nspden_in==4.and.nspden_out==1) then
    1379            0 :      denpot_out(my_istart_out:my_istart_out+my_nelem-1,1)=denpot_in(my_istart_in:my_istart_in+my_nelem-1,1)
    1380            0 :    else if (nspden_in==4.and.nspden_out==2) then
    1381            0 :      denpot_out(my_istart_out:my_istart_out+my_nelem-1,1)=denpot_in(my_istart_in:my_istart_in+my_nelem-1,1)
    1382              :      denpot_out(my_istart_out:my_istart_out+my_nelem-1,2)=denpot_in(my_istart_in:my_istart_in+my_nelem-1,1)*half &
    1383            0 : &                                                        +denpot_in(my_istart_in:my_istart_in+my_nelem-1,4)*half
    1384              :    end if
    1385              : 
    1386              :  else
    1387              : 
    1388              : !  Second case: POTENTIAL
    1389              : 
    1390            0 :    if      (nspden_in==1.and.nspden_out==2) then
    1391            0 :      denpot_out(my_istart_out:my_istart_out+my_nelem-1,1)=denpot_in(my_istart_in:my_istart_in+my_nelem-1,1)
    1392            0 :      denpot_out(my_istart_out:my_istart_out+my_nelem-1,2)=denpot_in(my_istart_in:my_istart_in+my_nelem-1,1)
    1393            0 :    else if (nspden_in==1.and.nspden_out==4) then
    1394            0 :      denpot_out(my_istart_out:my_istart_out+my_nelem-1,1)=denpot_in(my_istart_in:my_istart_in+my_nelem-1,1)
    1395            0 :      denpot_out(my_istart_out:my_istart_out+my_nelem-1,2)=denpot_in(my_istart_in:my_istart_in+my_nelem-1,1)
    1396            0 :      denpot_out(my_istart_out:my_istart_out+my_nelem-1,3)=zero
    1397            0 :      denpot_out(my_istart_out:my_istart_out+my_nelem-1,4)=zero
    1398            0 :    else if (nspden_in==2.and.nspden_out==1) then
    1399              :      denpot_out(my_istart_out:my_istart_out+my_nelem-1,1)=denpot_in(my_istart_in:my_istart_in+my_nelem-1,1)*half &
    1400            0 : &                                                        +denpot_in(my_istart_in:my_istart_in+my_nelem-1,2)*half
    1401            0 :    else if (nspden_in==2.and.nspden_out==4) then
    1402            0 :      denpot_out(my_istart_out:my_istart_out+my_nelem-1,1)=denpot_in(my_istart_in:my_istart_in+my_nelem-1,1)
    1403            0 :      denpot_out(my_istart_out:my_istart_out+my_nelem-1,2)=denpot_in(my_istart_in:my_istart_in+my_nelem-1,2)
    1404            0 :      denpot_out(my_istart_out:my_istart_out+my_nelem-1,3)=zero
    1405            0 :      denpot_out(my_istart_out:my_istart_out+my_nelem-1,4)=zero
    1406            0 :    else if (nspden_in==4.and.nspden_out==1) then
    1407              :      denpot_out(my_istart_out:my_istart_out+my_nelem-1,1)=denpot_in(my_istart_in:my_istart_in+my_nelem-1,1)*half &
    1408            0 : &                                                        +denpot_in(my_istart_in:my_istart_in+my_nelem-1,2)*half
    1409            0 :    else if (nspden_in==4.and.nspden_out==2) then
    1410            0 :      denpot_out(my_istart_out:my_istart_out+my_nelem-1,1)=denpot_in(my_istart_in:my_istart_in+my_nelem-1,1)
    1411            0 :      denpot_out(my_istart_out:my_istart_out+my_nelem-1,2)=denpot_in(my_istart_in:my_istart_in+my_nelem-1,2)
    1412              :    end if
    1413              : 
    1414              :  end if
    1415              : 
    1416              : end subroutine denpot_spin_convert
    1417              : !!***
    1418              : 
    1419              : end module m_ioarr
    1420              : !!***
        

Generated by: LCOV version 2.3-1