SUBROUTINE READ_SPEC(CD_CFILE, YD_SPEC,KSTEP, LDGRIB, LDBACKGR)

!     Purpose.
!     --------
!       Read spectral fields from files, one file per level.

!     Author.
!     -------
!       Yannick Tremolet *ECMWF*

!     Modifications.
!     --------------
!       Original  : 02-03-21 (from write_spec)
!        M.Hamrud      01-Oct-2003 CY28 Cleaning
!        M.Hamrud      01-May-2006 Generalized IO scheme
! ------------------------------------------------------------------

USE PARKIND1  ,ONLY : JPIM     ,JPRB
USE YOMHOOK   ,ONLY : LHOOK,   DR_HOOK

USE YOMCT0, ONLY: NPRTRW, LELAM, NPROC,NPRTRV
USE YOMMP , ONLY:  MYSETV, MYPROC,NBSETLEV
USE SPECTRAL_FIELDS_MOD, ONLY : SPECTRAL_FIELD
USE PARDIM, ONLY: JPMXLE
USE IOSTREAM_MIX , ONLY : SETUP_IOSTREAM, SETUP_IOREQUEST, IO_GET, &
 & CLOSE_IOSTREAM, TYPE_IOSTREAM , TYPE_IOREQUEST, &
 & CLOSE_IOREQUEST

IMPLICIT NONE

CHARACTER(LEN=*)  ,INTENT(IN)    :: CD_CFILE 
TYPE(SPECTRAL_FIELD),INTENT(INOUT) :: YD_SPEC 
INTEGER(KIND=JPIM),INTENT(IN)    :: KSTEP 
LOGICAL           ,INTENT(IN), OPTIONAL :: LDGRIB
LOGICAL           ,INTENT(IN), OPTIONAL :: LDBACKGR

INTEGER(KIND=JPIM) :: JLEV, JF, IL, ILL,JS
INTEGER(KIND=JPIM) :: JA,JB
INTEGER(KIND=JPIM) :: IONPROCS,ICHUNKS,JCH,ISTLEV,IENLEV,ILEVS,IGLEV
INTEGER(KIND=JPIM) :: IOPROCS(JPMXLE),ILEVLIST(JPMXLE),IUMLL(NPRTRV)
INTEGER(KIND=JPIM) :: IMYLEVS,IPE,IS3D
INTEGER(KIND=JPIM) :: IGRIB3D(99),ILEVS3D(JPMXLE),IPROC3D(JPMXLE),IBSET3D(JPMXLE)
CHARACTER(LEN=128) :: CLFILELEV
CHARACTER(LEN=3) :: CLEV
CHARACTER(LEN=1) :: CLMODE
TYPE(TYPE_IOSTREAM), SAVE :: YL_IOSTREAM_BG(JPMXLE)
TYPE(TYPE_IOSTREAM), SAVE :: YL_IOSTREAM(JPMXLE)
TYPE(TYPE_IOSTREAM), SAVE :: YL_IOSTREAM_SL_BG, YL_IOSTREAM_SL
TYPE(TYPE_IOREQUEST) :: YL_IOREQUEST
LOGICAL,SAVE :: LL_OPEN_STREAM(JPMXLE), LL_OPEN_STREAM2
REAL(KIND=JPRB),ALLOCATABLE :: ZSPEC(:,:,:)
LOGICAL :: LLGRIB, LLBACKGR,LLCLOSE
LOGICAL,SAVE :: LLFIRST=.TRUE.
REAL(KIND=JPRB) :: ZHOOK_HANDLE

#include "abor1.intfb.h"
#include "set2pe.intfb.h"

! --------------------------------------------------------------

IF (LHOOK) CALL DR_HOOK('READ_SPEC',0,ZHOOK_HANDLE)
IF (LELAM) CALL ABOR1(' READ_SPEC: lelam case not implemented ')

LLGRIB = .TRUE.
IF (PRESENT(LDGRIB)) LLGRIB = LDGRIB
CLMODE = 'r'

IF (PRESENT(LDBACKGR)) THEN
  LLBACKGR = LDBACKGR
ELSE
  LLBACKGR = .FALSE.
ENDIF

IS3D = YD_SPEC%ns3d
IF(LLFIRST) THEN
  LL_OPEN_STREAM(:) = .FALSE.
  LL_OPEN_STREAM2   = .FALSE.
  LLFIRST = .FALSE.
ENDIF

LLCLOSE = LLBACKGR
IF (IS3D > 0) THEN
  IONPROCS = MIN(NPROC,YD_SPEC%NFLEVG)
  ICHUNKS  = (YD_SPEC%NFLEVG-1)/IONPROCS+1
  ILEVS    = 0
  IUMLL(:) = 0
  OUTER:DO
    DO JA=1,NPRTRW
      DO JB=1,NPRTRV
        ILEVS = ILEVS+1
        IF(ILEVS > YD_SPEC%NFLEVG) EXIT OUTER
        IUMLL(JB) = IUMLL(JB)+1
        IF( IUMLL(JB) <= YD_SPEC%NUMLL(JB)) THEN
          IGLEV = YD_SPEC%NPTRLL(JB)+IUMLL(JB)-1
          ILEVLIST(ILEVS) = IGLEV
          CALL SET2PE(IPE,0,0,JA,JB)
          IOPROCS(ILEVS) = IPE
        ENDIF
      ENDDO
    ENDDO
  ENDDO OUTER

  DO JCH=1,ICHUNKS
    ISTLEV = (JCH-1)*IONPROCS+1
    IENLEV = MIN(YD_SPEC%NFLEVG,JCH*IONPROCS)
    ILEVS  = IENLEV-ISTLEV+1
    IMYLEVS = 0
    DO JLEV=ISTLEV,IENLEV
      IGLEV = ILEVLIST(JLEV)
      IF(NBSETLEV(IGLEV) == MYSETV) THEN
        IMYLEVS = IMYLEVS+1
      ENDIF
      IF (IOPROCS(JLEV) == MYPROC) THEN
        WRITE(CLEV,'(I3.3)')IGLEV
        CLFILELEV=CD_CFILE//'L'//CLEV
      ENDIF
    ENDDO
    IF(KSTEP == 1) THEN
      IF (LLBACKGR) THEN
        CALL SETUP_IOSTREAM(YL_IOSTREAM_BG(JCH),'CIO',TRIM(CLFILELEV),CDMODE=CLMODE,&
         & KIOPROCS=IOPROCS(ISTLEV:IENLEV))
      ELSE
        IF(LL_OPEN_STREAM(JCH)) CALL CLOSE_IOSTREAM(YL_IOSTREAM(JCH))
        CALL SETUP_IOSTREAM(YL_IOSTREAM(JCH),'CIO',TRIM(CLFILELEV),CDMODE=CLMODE,&
         & KIOPROCS=IOPROCS(ISTLEV:IENLEV))
        LL_OPEN_STREAM(JCH) = .TRUE.
      ENDIF
    ENDIF
    ALLOCATE(ZSPEC(IMYLEVS,YD_SPEC%nspec2,IS3D))
    DO JF=1,IS3D
      IGRIB3D(JF) = YD_SPEC%NGRIB3(JF)
    ENDDO
    ILEVS3D(1:ILEVS) = ILEVLIST(ISTLEV:IENLEV)
    IPROC3D(1:ILEVS) = IOPROCS(ISTLEV:IENLEV)
    DO JLEV=1,ILEVS
      IBSET3D(JLEV) = NBSETLEV(ILEVS3D(JLEV))
    ENDDO

    CALL SETUP_IOREQUEST(YL_IOREQUEST,'SPECTRAL_FIELDS',LDGRIB=.TRUE.,&
     & KGRIB3D=IGRIB3D(1:IS3D),KLEVS3D=ILEVS3D(1:ILEVS),KBSET3D=IBSET3D,&
     & LDRANDOM_ORDER=.FALSE.,KSMAX=YD_SPEC%NSMAX)
    IF (LLBACKGR) THEN
      CALL IO_GET(YL_IOSTREAM_BG(JCH),YL_IOREQUEST,&
       & PR3=ZSPEC,KLEVPROC3D=IPROC3D(1:ILEVS))
    ELSE
      CALL IO_GET(YL_IOSTREAM(JCH),YL_IOREQUEST,&
       & PR3=ZSPEC,KLEVPROC3D=IPROC3D(1:ILEVS))
    ENDIF

    CALL GSTATS(1475,0)
!$OMP PARALLEL DO SCHEDULE(STATIC) PRIVATE(JS,JF,ILL,JLEV,IGLEV,IL)
    DO JS=1,YD_SPEC%NSPEC2
      DO JF=1,IS3D
        ILL = 0
        DO JLEV=ISTLEV,IENLEV
          IGLEV = ILEVLIST(JLEV)
          IF(NBSETLEV(IGLEV) == MYSETV) THEN
            IL = IGLEV-YD_SPEC%NPTRLL(MYSETV)+1
            ILL = ILL+1
            YD_SPEC%SP3D(IL,JS,JF) = ZSPEC(ILL,JS,JF)
          ENDIF
        ENDDO
      ENDDO
    ENDDO
!$OMP END PARALLEL DO
    CALL GSTATS(1475,1)

    CALL CLOSE_IOREQUEST(YL_IOREQUEST)
    DEALLOCATE(ZSPEC)

    IF(LLCLOSE) THEN
      IF (LLBACKGR) THEN
        CALL CLOSE_IOSTREAM(YL_IOSTREAM_BG(JCH))
      ELSE
        CALL CLOSE_IOSTREAM(YL_IOSTREAM(JCH))
        LL_OPEN_STREAM(JCH) = .FALSE.
      ENDIF
    ENDIF
  ENDDO
ENDIF


! ------------------------------------------------------------------
! 2D arrays
! ------------------------------------------------------------------

IF (YD_SPEC%NS2G>0) THEN
  IL = 0
  WRITE(CLEV,'(I3.3)')IL
  CLFILELEV = CD_CFILE//'L'//CLEV

!   Read fields
  IF(KSTEP == 1) THEN
    IF (LLBACKGR) THEN
      CALL SETUP_IOSTREAM(YL_IOSTREAM_SL_BG,'CIO',TRIM(CLFILELEV),CDMODE=CLMODE,&
       & KIOMASTER=1)
    ELSE
      IF(LL_OPEN_STREAM2) CALL CLOSE_IOSTREAM(YL_IOSTREAM_SL)
      CALL SETUP_IOSTREAM(YL_IOSTREAM_SL,'CIO',TRIM(CLFILELEV),CDMODE=CLMODE,&
       & KIOMASTER=1)
      LL_OPEN_STREAM2 = .TRUE.
    ENDIF
  ENDIF
  CALL SETUP_IOREQUEST(YL_IOREQUEST,'SPECTRAL_FIELDS',LDGRIB=.TRUE.,&
   & KGRIB2D=YD_SPEC%NGRIB2(1:YD_SPEC%NS2G),LDRANDOM_ORDER=.FALSE.)
  IF (LLBACKGR) THEN
    CALL IO_GET(YL_IOSTREAM_SL_BG,YL_IOREQUEST,&
     & PR2=YD_SPEC%SP2D)
  ELSE
    CALL IO_GET(YL_IOSTREAM_SL,YL_IOREQUEST,&
     & PR2=YD_SPEC%SP2D)
  ENDIF
  CALL CLOSE_IOREQUEST(YL_IOREQUEST)
  IF (LLCLOSE) THEN
    IF (LLBACKGR) THEN
      CALL CLOSE_IOSTREAM(YL_IOSTREAM_SL_BG)
    ELSE
      CALL CLOSE_IOSTREAM(YL_IOSTREAM_SL)
      LL_OPEN_STREAM2 = .FALSE.
    ENDIF
  ENDIF
ENDIF

IF (LHOOK) CALL DR_HOOK('READ_SPEC',1,ZHOOK_HANDLE)
END SUBROUTINE READ_SPEC
