! (C) Copyright 2001- ECMWF.
! (C) Copyright 2001- Meteo-France.
!
! This software is licensed under the terms of the Apache Licence Version 2.0
! which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
! In applying this licence, ECMWF does not waive the privileges and immunities
! granted to it by virtue of its status as an intergovernmental organisation
! nor does it submit to any jurisdiction.

MODULE ECTRANS_FIELD_API_MOD

USE PARKIND1, ONLY : JPIM, JPRB
USE FIELD_ACCESS_MODULE, ONLY: GET_HOST_DATA_RDWR, GET_DEVICE_DATA_RDWR, GET_HOST_DATA_RDONLY,GET_DEVICE_DATA_RDONLY
USE FIELD_BASIC_MODULE, ONLY: FIELD_BASIC
USE FIELD_MODULE, ONLY:FIELD_1RB, FIELD_2RB, FIELD_3RB, FIELD_4RB, FIELD_2RB_VIEW, FIELD_3RB_VIEW
IMPLICIT NONE

PRIVATE

PUBLIC :: FIELD_GRID, FIELD_SPEC,SPEC_VIEW, GRID_VIEW, MAKE_FIELD_GRID, MAKE_FIELD_SPEC, LS, LG, &
        & IVSET_PTR, LS_COUNT, LG_COUNT, GET_LAYOUT_S, GET_LAYOUT_G

TYPE FIELD_GRID
 ! A pointer to field API field with additional METADATA
  CLASS (FIELD_BASIC), POINTER :: PTR      ! POINTER TO FIELD_BASIC from field API
  CHARACTER(LEN=10)            :: NAME     ! Name
  INTEGER(KIND=JPIM)           :: DIM_V    ! Vertical dimension (0 if not applicable)
END TYPE

TYPE FIELD_SPEC
 ! A pointer to field API field with additional METADATA
  CLASS (FIELD_BASIC), POINTER :: PTR      ! POINTER TO FIELD_BASIC from field API
  CHARACTER(LEN=10)            :: NAME     ! Name
  INTEGER(KIND=JPIM), POINTER  :: IVSET(:) ! b-set for spectral fields
END TYPE

TYPE SPEC_VIEW
  ! Spectral field view
  REAL(KIND=JPRB),POINTER :: P(:)
  CHARACTER(LEN=12)     :: NAME
END TYPE

TYPE GRID_VIEW
! Grid point field view
  REAL(KIND=JPRB),POINTER :: P(:,:)
  INTEGER(KIND=JPIM)    :: IVSET
  CHARACTER(LEN=12)     :: NAME
END TYPE

TYPE IVSET_PTR
  INTEGER(KIND=JPIM), POINTER :: PTR(:)
END TYPE

INTERFACE MAKE_FIELD_GRID
  MODULE PROCEDURE :: MAKE_FIELD_GRID_1RB, MAKE_FIELD_GRID_2RB, MAKE_FIELD_GRID_3RB, MAKE_FIELD_GRID_4RB
END INTERFACE

INTERFACE MAKE_FIELD_SPEC
  MODULE PROCEDURE :: MAKE_FIELD_SPEC_1RB, MAKE_FIELD_SPEC_2RB, MAKE_FIELD_SPEC_3RB
END INTERFACE

CONTAINS

FUNCTION MAKE_FIELD_SPEC_1RB(YLF,NAME,IVSET)
  ! Creation of a FIELD_SPEC encapsulating a FIELD_1RB field
  TYPE (FIELD_SPEC) :: MAKE_FIELD_SPEC_1RB
  CLASS (FIELD_1RB), INTENT(IN), POINTER :: YLF
  CHARACTER(LEN=*), INTENT(IN) :: NAME
  INTEGER(KIND=JPIM), INTENT(IN), TARGET, OPTIONAL :: IVSET(:)

  MAKE_FIELD_SPEC_1RB%PTR => YLF
  MAKE_FIELD_SPEC_1RB%NAME = NAME
  IF (PRESENT(IVSET)) THEN
    MAKE_FIELD_SPEC_1RB%IVSET => IVSET
  ELSE
    MAKE_FIELD_SPEC_1RB%IVSET => NULL()
  ENDIF
END FUNCTION MAKE_FIELD_SPEC_1RB

FUNCTION MAKE_FIELD_SPEC_2RB(YLF,NAME,IVSET)
  ! Creation of a FIELD_SPEC encapsulating a FIELD_2RB field
  TYPE (FIELD_SPEC) :: MAKE_FIELD_SPEC_2RB
  CLASS (FIELD_2RB), INTENT(IN), POINTER :: YLF
  CHARACTER(LEN=*), INTENT(IN) :: NAME
  INTEGER(KIND=JPIM), INTENT(IN), TARGET, OPTIONAL :: IVSET(:)

  MAKE_FIELD_SPEC_2RB%PTR => YLF
  MAKE_FIELD_SPEC_2RB%NAME = NAME
  IF (PRESENT(IVSET)) THEN
    MAKE_FIELD_SPEC_2RB%IVSET => IVSET
  ELSE
    MAKE_FIELD_SPEC_2RB%IVSET => NULL()
  ENDIF
END FUNCTION MAKE_FIELD_SPEC_2RB

FUNCTION MAKE_FIELD_SPEC_3RB(YLF,NAME,IVSET)
  ! Creation of a FIELD_SPEC encapsulating a FIELD_3RB field
  TYPE (FIELD_SPEC) :: MAKE_FIELD_SPEC_3RB
  CLASS (FIELD_3RB), INTENT(IN), POINTER :: YLF
  CHARACTER(LEN=*), INTENT(IN) :: NAME
  INTEGER(KIND=JPIM), INTENT(IN), TARGET, OPTIONAL :: IVSET(:)

  MAKE_FIELD_SPEC_3RB%PTR => YLF
  MAKE_FIELD_SPEC_3RB%NAME = NAME
  IF (PRESENT(IVSET)) THEN
    MAKE_FIELD_SPEC_3RB%IVSET => IVSET
  ELSE
    MAKE_FIELD_SPEC_3RB%IVSET => NULL()
  ENDIF
END FUNCTION MAKE_FIELD_SPEC_3RB


FUNCTION MAKE_FIELD_GRID_1RB(YLF,NAME)
  ! Creation of a FIELD_GRID encapsulating a FIELD_1RB field
  TYPE (FIELD_GRID) :: MAKE_FIELD_GRID_1RB
  CLASS (FIELD_1RB), INTENT(IN), POINTER :: YLF
  CHARACTER(LEN=*), INTENT(IN) :: NAME

  MAKE_FIELD_GRID_1RB%PTR => YLF
  MAKE_FIELD_GRID_1RB%NAME = NAME
    MAKE_FIELD_GRID_1RB%DIM_V = 0
END FUNCTION MAKE_FIELD_GRID_1RB

FUNCTION MAKE_FIELD_GRID_2RB(YLF,NAME)
  ! Creation of a FIELD_GRID encapsulating a FIELD_2RB field
  TYPE (FIELD_GRID) :: MAKE_FIELD_GRID_2RB
  CLASS (FIELD_2RB), INTENT(IN), POINTER :: YLF
  CHARACTER(LEN=*),  INTENT(IN) :: NAME

  MAKE_FIELD_GRID_2RB%PTR => YLF
  MAKE_FIELD_GRID_2RB%NAME = NAME
  MAKE_FIELD_GRID_2RB%DIM_V = 0
END FUNCTION MAKE_FIELD_GRID_2RB

FUNCTION MAKE_FIELD_GRID_3RB(YLF,NAME)
  ! Creation of a FIELD_GRID encapsulating a FIELD_3RB field
  TYPE (FIELD_GRID) :: MAKE_FIELD_GRID_3RB
  CLASS (FIELD_3RB), INTENT(IN), POINTER :: YLF
  CHARACTER(LEN=*), INTENT(IN) :: NAME

  MAKE_FIELD_GRID_3RB%PTR => YLF
  MAKE_FIELD_GRID_3RB%NAME = NAME
  MAKE_FIELD_GRID_3RB%DIM_V = 1
END FUNCTION MAKE_FIELD_GRID_3RB

FUNCTION MAKE_FIELD_GRID_4RB(YLF,NAME)
  ! Creation of a FIELD_SPEC encapsulating a FIELD_4RB field
  TYPE (FIELD_GRID) :: MAKE_FIELD_GRID_4RB
  CLASS (FIELD_4RB), INTENT(IN), POINTER :: YLF
  CHARACTER(LEN=*), INTENT(IN) :: NAME

  MAKE_FIELD_GRID_4RB%PTR => YLF
  MAKE_FIELD_GRID_4RB%NAME = NAME
  MAKE_FIELD_GRID_4RB%DIM_V = 1
END FUNCTION MAKE_FIELD_GRID_4RB

SUBROUTINE LG2RB(LG2RBV,YLF,NAME,IVSET,LDACC,LDRDONLY)
  ! Creation of a list of GRID_VIEW encapsulating the layer of an input FIELD_2RB field
  ! Given YLF dimensioned(NPROMA, NBLKS) as input,
  ! the output list size will contain one element, its view beeing dimensioned(NPROMA, NBLKS)
  CLASS (FIELD_2RB), POINTER, INTENT (IN) :: YLF
  CHARACTER(LEN=*), INTENT(IN) :: NAME
  INTEGER(KIND=JPIM), POINTER, INTENT(IN) :: IVSET(:)
  LOGICAL, INTENT(IN) :: LDACC
  LOGICAL, INTENT(IN) :: LDRDONLY
  TYPE (GRID_VIEW), INTENT(INOUT) :: LG2RBV (:)

  REAL(KIND=JPRB), POINTER :: ZZ2 (:,:)
  IF (LDACC) THEN
    IF (LDRDONLY) THEN
      ZZ2 => GET_DEVICE_DATA_RDONLY(YLF)
    ELSE
      ZZ2 => GET_DEVICE_DATA_RDWR(YLF)
    ENDIF
  ELSE
    IF (LDRDONLY) THEN
      ZZ2 => GET_HOST_DATA_RDONLY(YLF)
    ELSE
      ZZ2 => GET_HOST_DATA_RDWR(YLF)
    ENDIF
  ENDIF

  IF (SIZE(LG2RBV) /= 1 ) CALL ABOR1("Error - incorrect size for LG2RBV")

  LG2RBV (1)%P => ZZ2(:,:)
  LG2RBV(1)%NAME = TRIM(NAME)
  IF (ASSOCIATED(IVSET)) THEN
    LG2RBV (1)%IVSET = IVSET(1)
  ELSE
    LG2RBV (1)%IVSET = 1 ! default value when IVSET is not provided
  ENDIF
END SUBROUTINE LG2RB

SUBROUTINE LG3RB(LG3RBV,YLF,NAME, IVSET,LDACC,LDRDONLY)
  ! Creation of a list of GRID_VIEW encapsulating the layers of an input FIELD_3RB field
  ! Given YLF dimensioned(NPROMA, NLEVS, NBLKS) as input,
  ! the output list size will contain  (NLEVS) elements, their view beeing dimensioned(NPROMA, NBLKS)
  CLASS (FIELD_3RB), POINTER, INTENT (IN) :: YLF
  CHARACTER(LEN=*), INTENT(IN) ::NAME
  INTEGER(KIND=JPIM), POINTER, INTENT(IN) :: IVSET(:)
  LOGICAL, INTENT(IN) :: LDACC
  LOGICAL, INTENT(IN) :: LDRDONLY
  TYPE (GRID_VIEW), INTENT(INOUT) :: LG3RBV (:)

  REAL(KIND=JPRB), POINTER :: ZZ3 (:,:,:)
  INTEGER(KIND=JPIM) :: JLEV, JCOUNT

  IF (LDACC) THEN
    IF (LDRDONLY) THEN
      ZZ3 => GET_DEVICE_DATA_RDONLY(YLF)
    ELSE
      ZZ3 => GET_DEVICE_DATA_RDWR(YLF)
    ENDIF
  ELSE
    IF (LDRDONLY) THEN
      ZZ3 => GET_HOST_DATA_RDONLY(YLF)
    ELSE
      ZZ3 => GET_HOST_DATA_RDWR(YLF)
    ENDIF
  ENDIF


  IF (SIZE(LG3RBV) /= SIZE (ZZ3, 2) ) CALL ABOR1("Error - incorrect size for LG3RBV")

  IF (ASSOCIATED(IVSET)) THEN
    IF (SIZE(IVSET) /= SIZE(ZZ3, 2)) THEN
      CALL ABOR1("Error - LG3RB("//TRIM(NAME)// "): incorrect size for IVSET: SIZE(IVSET) = " // TRIM(TO_STR(SIZE(IVSET))) &
        // " but SIZE(ZZ3, 2) = " // TRIM(TO_STR(SIZE(ZZ3, 2))))
    END IF
  END IF

  JCOUNT = 1
  DO JLEV = LBOUND (ZZ3, 2), UBOUND (ZZ3, 2)
    LG3RBV (JCOUNT)%P => ZZ3 (:, JLEV, :)
    LG3RBV(JCOUNT)%NAME = TRIM(NAME)
    IF (ASSOCIATED(IVSET)) THEN
      LG3RBV (JCOUNT)%IVSET = IVSET(JLEV)
    ELSE
      LG3RBV (JCOUNT)%IVSET = 1 ! default value when IVSET is not provided
    ENDIF
    JCOUNT = JCOUNT + 1
  ENDDO
CONTAINS
  FUNCTION TO_STR(I) RESULT(STR_OUT)
    INTEGER, INTENT(IN) :: I
    CHARACTER(LEN=16) :: STR_OUT
    WRITE(STR_OUT, '(I0)') I
  END FUNCTION
END SUBROUTINE LG3RB

SUBROUTINE LG4RB(LG4RBV, YLF,NAME,IVSET,LDACC,LDRDONLY)
  ! Creation of a list of GRID_VIEW encapsulating the layers of an input FIELD_4RB field
  ! Given YLF dimensioned(NPROMA, NLEVS, NFIELDS, NBLKS) as input,
  ! the output list size will contain  (NLEVS*NFIELDS) elementa, their view beeing dimensioned(NPROMA, NBLKS)

  CLASS (FIELD_4RB), INTENT(IN), POINTER :: YLF
  CHARACTER(LEN=*), INTENT(IN) :: NAME
  INTEGER(KIND=JPIM), POINTER, INTENT(IN) :: IVSET(:)
  LOGICAL, INTENT(IN) :: LDACC
  LOGICAL, INTENT(IN) :: LDRDONLY
  TYPE (GRID_VIEW), INTENT(INOUT) :: LG4RBV (:)

  REAL(KIND=JPRB), POINTER :: ZZ4 (:,:,:,:)
  INTEGER(KIND=JPIM) :: JLEV, JFLD, JCOUNT

  IF (LDACC) THEN
    IF (LDRDONLY) THEN
      ZZ4 => GET_DEVICE_DATA_RDONLY(YLF)
    ELSE
      ZZ4 => GET_DEVICE_DATA_RDWR(YLF)
    ENDIF
  ELSE
    IF (LDRDONLY) THEN
      ZZ4 => GET_HOST_DATA_RDONLY(YLF)
    ELSE
      ZZ4 => GET_HOST_DATA_RDWR(YLF)
    ENDIF
  ENDIF

  IF (SIZE(LG4RBV) /= SIZE (ZZ4, 2) * SIZE (ZZ4, 3) ) CALL ABOR1("Error - incorrect size for LG4RBV")

  IF (ASSOCIATED(IVSET)) THEN
    IF (SIZE(IVSET) /= SIZE(ZZ4, 2)) THEN
      CALL ABOR1("Error - LG4RB("//TRIM(NAME)// "): incorrect size for IVSET: SIZE(IVSET) = " // TRIM(TO_STR(SIZE(IVSET))) &
        // " but SIZE(ZZ4, 2) = " // TRIM(TO_STR(SIZE(ZZ4, 2))))
    END IF
  END IF

  JCOUNT = 1

  DO JFLD = LBOUND (ZZ4, 3), UBOUND (ZZ4, 3)
    DO JLEV = LBOUND (ZZ4, 2), UBOUND (ZZ4, 2)
      LG4RBV (JCOUNT)%P => ZZ4(:, JLEV, JFLD, :)
      LG4RBV(JCOUNT)%NAME = TRIM(NAME)
      IF (ASSOCIATED(IVSET)) THEN
        LG4RBV (JCOUNT)%IVSET = IVSET(JLEV)
      ELSE
        LG4RBV (JCOUNT)%IVSET = 1 ! default value when IVSET is not provided
      END IF
      JCOUNT = JCOUNT + 1
    ENDDO
  ENDDO
CONTAINS
  FUNCTION TO_STR(I) RESULT(STR_OUT)
    INTEGER, INTENT(IN) :: I
    CHARACTER(LEN=16) :: STR_OUT
    WRITE(STR_OUT, '(I0)') I
  END FUNCTION
END SUBROUTINE LG4RB

FUNCTION LG(YLFL,LGV,IVSET,LDACC,LDRDONLY) RESULT(IOFF)
  ! Creation of a list of GRID_VIEW from a list YLFL of FIELD_GRID
  TYPE (FIELD_GRID), INTENT(IN) :: YLFL (:)           ! input list of FIELD_GRID
  LOGICAL, INTENT(IN), OPTIONAL  :: LDACC             ! retrieve data on device
  LOGICAL, INTENT(IN), OPTIONAL  :: LDRDONLY
  TYPE (GRID_VIEW), INTENT(INOUT), OPTIONAL :: LGV (:) ! output list of GRID_VIEW
  TYPE (IVSET_PTR), INTENT(IN), OPTIONAL :: IVSET(:)

  INTEGER(KIND=JPIM) :: IOFF
  INTEGER(KIND=JPIM) :: ILEN, JFLD
  INTEGER(KIND=JPIM) :: ILBOUNDS (5), IUBOUNDS (5)
  LOGICAL :: LGV_PROVIDED
  LOGICAL :: LLACC, LLRDONLY

  LGV_PROVIDED = .FALSE.
  LLACC = .FALSE.
  LLRDONLY = .FALSE.

  IF (PRESENT(LGV)) LGV_PROVIDED = .TRUE.
  IF (PRESENT(LDACC))  LLACC = LDACC
  IF (PRESENT(LDRDONLY)) LLRDONLY = LDRDONLY
  IF (PRESENT(LGV)) THEN
    IF(.NOT. PRESENT(IVSET)) CALL ABOR1("LG FAILURE: Both LGV and IVSET need to be present")
    IF (SIZE(YLFL) /= SIZE(IVSET)) CALL ABOR1("LG FAILURE: SIZE(YLFL) /= SIZE(IVSET)")
  ENDIF

  IOFF = 0
  ILEN = -1

  ! iterate over YLFL LIST
  DO JFLD = 1, SIZE (YLFL)
  ! compute number of GRID_VIEW that will be generated for each field of the list
  ! In addition if LGV_PROVIDED: call the correct routine to create the GRID_VIEW for each field of the list
    SELECT TYPE (YLF => YLFL (JFLD)%PTR)
      CLASS IS (FIELD_1RB)
        ILEN = 1
      CLASS IS (FIELD_2RB)
        CALL YLF%GET_DIMS (LBOUNDS=ILBOUNDS, UBOUNDS=IUBOUNDS)
        ILEN = 1
        IF (LGV_PROVIDED) CALL LG2RB(LGV (IOFF+1:IOFF+ILEN),YLF,YLFL(JFLD)%NAME,IVSET(JFLD)%PTR,LLACC,LLRDONLY)
      CLASS IS (FIELD_3RB)
        CALL YLF%GET_DIMS (LBOUNDS=ILBOUNDS, UBOUNDS=IUBOUNDS)
        ILEN = (IUBOUNDS (2) - ILBOUNDS (2) + 1)
        IF (LGV_PROVIDED) CALL LG3RB(LGV (IOFF+1:IOFF+ILEN),YLF,YLFL(JFLD)%NAME,IVSET(JFLD)%PTR, LLACC,LLRDONLY)
      CLASS IS (FIELD_4RB)
        CALL YLF%GET_DIMS (LBOUNDS=ILBOUNDS, UBOUNDS=IUBOUNDS)
        ILEN = (IUBOUNDS (2) - ILBOUNDS (2) + 1) * (IUBOUNDS (3) - ILBOUNDS (3) + 1)
        IF (LGV_PROVIDED) CALL LG4RB(LGV (IOFF+1:IOFF+ILEN),YLF,YLFL(JFLD)%NAME,IVSET(JFLD)%PTR,LLACC,LLRDONLY)
      CLASS DEFAULT
        CALL ABOR1("LG FAILURE: CLASS UNKNOWN")
    END SELECT
    IOFF = IOFF + ILEN
  ENDDO

  IF (LGV_PROVIDED) THEN
    IF (SIZE(LGV) /= IOFF)  CALL ABOR1("LG FAILURE: LSV has incorrect size")
  ENDIF

END FUNCTION LG

FUNCTION LG_COUNT(YLFL)
  TYPE (FIELD_GRID), INTENT(IN) :: YLFL (:)
  INTEGER(KIND=JPIM) :: LG_COUNT
  LG_COUNT = LG(YLFL)
END FUNCTION LG_COUNT


SUBROUTINE LS1RB(LS1RBV, YLF, NAME, LDACC,LDRDONLY)
  ! Creation of a list of SPEC_VIEW encapsulating the layer of an input FIELD_1RB field
  ! Given YLF dimensioned(NSPEC) as input,
  ! the output list size will contain one element, its view beeing dimensioned(NSPEC)
  CLASS (FIELD_1RB), POINTER, INTENT (IN) :: YLF
  CHARACTER(LEN=*), INTENT (IN) :: NAME
  LOGICAL, INTENT (IN) :: LDACC
  LOGICAL, INTENT (IN) :: LDRDONLY
  TYPE (SPEC_VIEW), INTENT(INOUT) :: LS1RBV (:)

  REAL(KIND=JPRB), POINTER :: ZZ1 (:)

  IF (LDACC) THEN
    IF (LDRDONLY) THEN
      ZZ1 => GET_DEVICE_DATA_RDONLY(YLF)
    ELSE
      ZZ1 => GET_DEVICE_DATA_RDWR(YLF)
    ENDIF
  ELSE
    IF (LDRDONLY) THEN
      ZZ1 => GET_HOST_DATA_RDONLY(YLF)
    ELSE
      ZZ1 => GET_HOST_DATA_RDWR(YLF)
    ENDIF
  ENDIF

  IF (SIZE(LS1RBV) /= 1 ) CALL ABOR1("Error - incorrect size for LS1RBV")
  LS1RBV(1)%P => ZZ1(:)

END SUBROUTINE LS1RB

SUBROUTINE LS2RB(LS2RBV,YLF,NAME, LDACC,LDRDONLY)
  ! Creation of a list of SPEC_VIEW, each of them encapsulating a layer of an input FIELD_2RB field.
  ! Given YLF dimensioned(NLEVS, NSPEC) as input,
  ! the output list size will contain (NLEVS) elements dimensioned(NSPEC)
  CLASS (FIELD_2RB), POINTER, INTENT (IN) :: YLF
  CHARACTER(LEN=*), INTENT (IN) :: NAME
  LOGICAL, INTENT (IN) :: LDACC
  LOGICAL, INTENT (IN) :: LDRDONLY
  TYPE (SPEC_VIEW), INTENT(INOUT) :: LS2RBV (:)

  REAL(KIND=JPRB), POINTER :: ZZ1 (:)
  REAL(KIND=JPRB), POINTER :: ZZ2 (:,:)
  INTEGER(KIND=JPIM) :: JLEV, JCOUNT
  IF (LDACC) THEN
    IF (LDRDONLY) THEN
      ZZ2 => GET_DEVICE_DATA_RDONLY(YLF)
    ELSE
      ZZ2 => GET_DEVICE_DATA_RDWR(YLF)
    ENDIF
  ELSE
    IF (LDRDONLY) THEN
      ZZ2 => GET_HOST_DATA_RDONLY(YLF)
    ELSE
      ZZ2 => GET_HOST_DATA_RDWR(YLF)
    ENDIF
  ENDIF

  IF (SIZE(LS2RBV) /= SIZE (ZZ2, 1) ) CALL ABOR1("Error - incorrect size for LS2RBV")
  JCOUNT = 1

  DO JLEV = LBOUND (ZZ2, 1), UBOUND (ZZ2, 1)
    LS2RBV (JCOUNT)%P => ZZ2 (JLEV, :)
    LS2RBV(JCOUNT)%NAME=TRIM(NAME)
    JCOUNT = JCOUNT + 1
  ENDDO

END SUBROUTINE LS2RB

SUBROUTINE LS3RB(LS3RBV,YLF,NAME, LDACC,LDRDONLY)
  ! Creation of a list of SPEC_VIEW, each of them encapsulating a layer of an input FIELD_3RB field.
  ! Given YLF dimensioned(NLEVS, NSPEC, NFIELDS) as input,
  ! the output list size will contain (NLEVS*NFIELDS) SPEC_VIEW, each of them dimensioned(NSPEC)
  CLASS (FIELD_3RB), POINTER, INTENT (IN) :: YLF
  CHARACTER(LEN=*), INTENT (IN) :: NAME
  LOGICAL, INTENT (IN) :: LDACC
  LOGICAL, INTENT (IN) :: LDRDONLY
  TYPE (SPEC_VIEW), INTENT(INOUT) :: LS3RBV (:)

  REAL(KIND=JPRB), POINTER :: ZZ3 (:,:,:)
  REAL(KIND=JPRB), POINTER :: ZZ1 (:)
  INTEGER(KIND=JPIM) :: JLEV, JFLD, JCOUNT

  IF (LDACC) THEN
    IF (LDRDONLY) THEN
      ZZ3 => GET_DEVICE_DATA_RDONLY(YLF)
    ELSE
      ZZ3 => GET_DEVICE_DATA_RDWR(YLF)
    ENDIF
  ELSE
    IF (LDRDONLY) THEN
      ZZ3 => GET_HOST_DATA_RDONLY(YLF)
    ELSE
      ZZ3 => GET_HOST_DATA_RDWR(YLF)
    ENDIF
  ENDIF

  IF (SIZE(LS3RBV) /=SIZE (ZZ3, 1) * SIZE (ZZ3, 3) ) CALL ABOR1("Error - incorrect size for LS3RBV")

  JCOUNT = 1

  DO JFLD = LBOUND (ZZ3, 3), UBOUND (ZZ3, 3)
    DO JLEV = LBOUND (ZZ3, 1), UBOUND (ZZ3, 1)
      LS3RBV(JCOUNT)%P => ZZ3 (JLEV, :, JFLD)
      LS3RBV(JCOUNT)%NAME=TRIM(NAME)
      JCOUNT = JCOUNT + 1
    ENDDO
  ENDDO

END SUBROUTINE LS3RB

FUNCTION LS(YLFL,LSV,LDACC,LDRDONLY) RESULT(IOFF)
! Creation of a list of SPEC_VIEW from a list YLFL of FIELD_SPEC
TYPE (FIELD_SPEC), INTENT(IN) :: YLFL (:) ! input list of FIELD_SPEC
TYPE (SPEC_VIEW), INTENT(INOUT), OPTIONAL :: LSV (:)        ! output list of SPEC_VIEW
LOGICAL, INTENT(IN), OPTIONAL :: LDACC                  ! retrieve data on device
LOGICAL, INTENT(IN), OPTIONAL :: LDRDONLY
INTEGER(KIND=JPIM) :: IOFF

INTEGER(KIND=JPIM) :: ILEN, JFLD
INTEGER(KIND=JPIM) :: ILBOUNDS (5), IUBOUNDS (5)

LOGICAL :: LSV_PROVIDED
REAL(KIND=JPRB), POINTER :: ZZ1 (:)
LOGICAL :: LLACC, LLRDONLY

LSV_PROVIDED = .FALSE.
LLACC = .FALSE.
LLRDONLY = .FALSE.
IF (PRESENT(LSV))LSV_PROVIDED = .TRUE.
IF (PRESENT(LDACC))  LLACC = LDACC
IF (PRESENT(LDRDONLY)) LLRDONLY = LDRDONLY

IOFF = 0
ILEN = -1

! iterate over YLFL LIST
DO JFLD = 1, SIZE (YLFL)
  ! compute number of SPEC_VIEW that will be generated for each field of the list
  ! in addition when LSV_PROVIDED: call the correct routine to create the SPEC_VIEW for each field of the list
  SELECT TYPE (YLF => YLFL (JFLD)%PTR)
    CLASS IS (FIELD_1RB)
      ILEN = 1
      IF (LSV_PROVIDED) CALL LS1RB(LSV(IOFF+1:IOFF+ILEN),YLF,YLFL(JFLD)%NAME, LLACC,LLRDONLY)
    CLASS IS (FIELD_2RB)
      CALL YLF%GET_DIMS (LBOUNDS=ILBOUNDS, UBOUNDS=IUBOUNDS)
      ILEN = (IUBOUNDS (1) - ILBOUNDS (1) + 1)
      IF (LSV_PROVIDED) CALL LS2RB(LSV(IOFF+1:IOFF+ILEN),YLF,YLFL(JFLD)%NAME, LLACC,LLRDONLY)
    CLASS IS (FIELD_3RB)
      CALL YLF%GET_DIMS (LBOUNDS=ILBOUNDS, UBOUNDS=IUBOUNDS)
        ILEN =  (IUBOUNDS (1) - ILBOUNDS (1) + 1)* (IUBOUNDS (3) - ILBOUNDS (3) + 1)
      IF (LSV_PROVIDED) CALL LS3RB(LSV(IOFF+1:IOFF+ILEN),YLF ,YLFL(JFLD)%NAME, LLACC,LLRDONLY)
    CLASS IS (FIELD_4RB)
        CALL ABOR1("LS not implemeted for FIELD_4RB")
    CLASS DEFAULT
        ! Skip the spectral field as it is not present on this processor
        ILEN = 0
  END SELECT

  IOFF = IOFF + ILEN
ENDDO

IF (LSV_PROVIDED ) THEN
  IF (SIZE(LSV) /= IOFF)  CALL ABOR1("LS FAILURE: LSV has incorrect size")
ENDIF

END FUNCTION LS

FUNCTION LS_COUNT(YLFL)
  TYPE (FIELD_SPEC), INTENT(IN) :: YLFL (:)  
  INTEGER(KIND=JPIM) :: LS_COUNT

  LS_COUNT = LS(YLFL)
END FUNCTION LS_COUNT

SUBROUTINE GET_LAYOUT_G(YLFL, NBLK, KPROMA)
  TYPE(FIELD_GRID), INTENT(IN) :: YLFL(:)
  INTEGER(KIND=JPIM), INTENT(INOUT) :: NBLK
  INTEGER(KIND=JPIM), INTENT(INOUT) :: KPROMA
  INTEGER(KIND=JPIM) :: ILBOUNDS (5), IUBOUNDS (5)

  INTEGER :: JFLD

  DO JFLD = 1, SIZE(YLFL)
    SELECT TYPE (YLF => YLFL (JFLD)%PTR)
      CLASS IS (FIELD_1RB)
          CALL YLF%GET_DIMS (LBOUNDS=ILBOUNDS, UBOUNDS=IUBOUNDS)
          NBLK = MAX(NBLK, (IUBOUNDS (1) - ILBOUNDS (1) + 1))         
       CLASS IS (FIELD_2RB)
          CALL YLF%GET_DIMS (LBOUNDS=ILBOUNDS, UBOUNDS=IUBOUNDS)
          KPROMA = MAX(KPROMA, (IUBOUNDS (1) - ILBOUNDS (1) + 1))
          NBLK = MAX(NBLK,  (IUBOUNDS (2) - ILBOUNDS (2) + 1))
       CLASS IS (FIELD_3RB)
          CALL YLF%GET_DIMS (LBOUNDS=ILBOUNDS, UBOUNDS=IUBOUNDS)
          KPROMA = MAX(KPROMA, (IUBOUNDS (1) - ILBOUNDS (1) + 1))
          NBLK = MAX(NBLK,  (IUBOUNDS (3) - ILBOUNDS (3) + 1))
       CLASS IS (FIELD_4RB)
          CALL YLF%GET_DIMS (LBOUNDS=ILBOUNDS, UBOUNDS=IUBOUNDS)
          KPROMA = MAX(KPROMA, (IUBOUNDS (1) - ILBOUNDS (1) + 1))      
          NBLK = MAX(NBLK,  (IUBOUNDS (4) - ILBOUNDS (4) + 1)  )
    END SELECT
  ENDDO
END SUBROUTINE GET_LAYOUT_G

SUBROUTINE GET_LAYOUT_S(YLFL, KSPEC)
  TYPE(FIELD_SPEC), INTENT(IN) :: YLFL(:)
  INTEGER(KIND=JPIM), INTENT(INOUT) :: KSPEC
  INTEGER(KIND=JPIM) :: ILBOUNDS (5), IUBOUNDS (5)

  INTEGER :: JFLD

  DO JFLD = 1, SIZE(YLFL)
    SELECT TYPE (YLF => YLFL (JFLD)%PTR)
      CLASS IS (FIELD_1RB)
          CALL YLF%GET_DIMS (LBOUNDS=ILBOUNDS, UBOUNDS=IUBOUNDS)
          KSPEC = MAX(KSPEC, (IUBOUNDS (1) - ILBOUNDS (1) + 1))         
       CLASS IS (FIELD_2RB)
          CALL YLF%GET_DIMS (LBOUNDS=ILBOUNDS, UBOUNDS=IUBOUNDS)
          KSPEC = MAX(KSPEC,  (IUBOUNDS (2) - ILBOUNDS (2) + 1))
       CLASS IS (FIELD_3RB)
          CALL YLF%GET_DIMS (LBOUNDS=ILBOUNDS, UBOUNDS=IUBOUNDS)
          KSPEC = MAX(KSPEC,  (IUBOUNDS (3) - ILBOUNDS (3) + 1))    
    END SELECT
  ENDDO
END SUBROUTINE GET_LAYOUT_S

END MODULE ECTRANS_FIELD_API_MOD
