MODULE EFSC_MOD
CONTAINS
SUBROUTINE EFSC(PREEL,KF_UV,KF_SCALARS,KF_SCDERS,KF_FS)
!SUBROUTINE EFSC(KF_UV,KF_SCALARS,KF_SCDERS,&
! & PUV,PSCALAR,PNSDERS,PEWDERS,PUVDERS)

!**** *FSC - Division by a*cos(theta), east-west derivatives

!     Purpose.
!     --------
!        In Fourier space divide u and v and all north-south
!        derivatives by a*cos(theta). Also compute east-west derivatives
!        of u,v,thermodynamic, passiv scalar variables and surface
!        pressure.

!**   Interface.
!     ----------
!        CALL FSC(..)
!        Explicit arguments :  PUV     - u and v
!        --------------------  PSCALAR - scalar valued varaibles
!                              PNSDERS - N-S derivative of S.V.V.
!                              PEWDERS - E-W derivative of S.V.V.
!                              PUVDERS - E-W derivative of u and v
!     Method.
!     -------

!     Externals.   None.
!     ----------

!     Author.
!     -------
!        Mats Hamrud *ECMWF*

!     Modifications.
!     --------------
!        Original : 00-03-03 (From SC2FSC)
!        M.Hamrud      01-Oct-2003 CY28 Cleaning

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

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

USE TPM_TRANS       ,ONLY : LUVDER, LVORGP, LDIVGP
USE TPM_DISTR       ,ONLY : D, MYSETW
USE TPM_GEOMETRY    ,ONLY : G
USE TPMALD_GEO      ,ONLY : GALD
!

IMPLICIT NONE

REAL(KIND=JPRB) , INTENT(INOUT) :: PREEL(:)
INTEGER(KIND=JPIM) , INTENT(IN) :: KF_UV,KF_SCALARS,KF_SCDERS, KF_FS

INTEGER(KIND=JPIM) :: JLOEN_MAX

INTEGER(KIND=JPIM) :: JF,IGLG,JM,JGL
REAL(KIND=JPRB) :: ZIM
INTEGER(KIND=JPIM) :: I_UV_OFFSET, I_SC_OFFSET, I_SCDERS_OFFSET, I_UVDERS_OFFSET, IST
INTEGER(KIND=JPIM) :: IOFF_LAT,IOFF_UV,IOFF_UV_EWDER, IOFF_SCALARS, IOFF_SCALARS_EWDER
REAL(KIND=JPRB)    :: RET_REAL, RET_COMPLEX
REAL(KIND=JPHOOK) :: ZHOOK_HANDLE
!     ------------------------------------------------------------------

IF (LHOOK) CALL DR_HOOK('EFSC_MOD:EFSC',0,ZHOOK_HANDLE)

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


IF(KF_UV > 0 .OR. KF_SCDERS > 0) THEN
  IST = 0
  IF(LVORGP) THEN
    IST = IST+KF_UV
  ENDIF
  IF(LDIVGP) THEN
    IST = IST+KF_UV
  ENDIF
  I_UV_OFFSET=IST

  IST = IST+2*KF_UV
  I_SC_OFFSET=IST

  IST = IST+KF_SCALARS
  !I_NSDERS_OFFSET=IST
  
  IST = IST+KF_SCDERS
  IF(LUVDER) THEN
    I_UVDERS_OFFSET=IST
    IST = IST+2*KF_UV
  ENDIF

  IF(KF_SCDERS > 0) THEN
    I_SCDERS_OFFSET=IST
  ENDIF
ENDIF

#ifdef ACCGPU
!$ACC DATA &
!$ACC& PRESENT(D%NPTRLS,D%NSTAGTF,PREEL,G%NMEN, D)
#endif


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

!*       2.    EAST-WEST DERIVATIVES
!              ---------------------

!*       2.1      U AND V.

JLOEN_MAX=MAXVAL(G%NMEN)

IF (LUVDER) THEN
#ifdef OMPGPU
  !$OMP TARGET TEAMS DISTRIBUTE PARALLEL DO DEFAULT(NONE) SHARED(KF_UVPREEL)
#endif
#ifdef ACCGPU
  !$ACC PARALLEL LOOP COLLAPSE(3) PRIVATE(IGLG,IOFF_LAT,IOFF_UV,IOFF_UV_EWDER,ZIM,RET_REAL,RET_COMPLEX,JM,JF,JGL) &
  !$ACC& FIRSTPRIVATE(KF_UV,I_UVDERS_OFFSET,I_UV_OFFSET,KF_FS)
#endif
  DO JGL=1,D%NDGL_FS
    DO JF=1,2*KF_UV
      DO JM=0,JLOEN_MAX/2
        IGLG = D%NPTRLS(MYSETW)+JGL-1
        IOFF_LAT = KF_FS*D%NSTAGTF(JGL)
        IOFF_UV = IOFF_LAT+(I_UV_OFFSET+JF-1)*(D%NSTAGTF(JGL+1)-D%NSTAGTF(JGL))
        IOFF_UV_EWDER = IOFF_LAT+(I_UVDERS_OFFSET+JF-1)*(D%NSTAGTF(JGL+1)-D%NSTAGTF(JGL))

        RET_REAL = 0.0_JPRBT
        RET_COMPLEX = 0.0_JPRBT

        IF (JM <= G%NMEN(IGLG)) THEN
          ZIM  = REAL(JM,JPRB)*GALD%EXWN

          RET_REAL = &
              & -PREEL(IOFF_UV+2*JM+2)*ZIM
          RET_COMPLEX =  &
              &  PREEL(IOFF_UV+2*JM+1)*ZIM
        ENDIF
        PREEL(IOFF_UV_EWDER+2*JM+1) = RET_REAL
        PREEL(IOFF_UV_EWDER+2*JM+2) = RET_COMPLEX
      ENDDO
    ENDDO
  ENDDO
ENDIF

!*       2.2     SCALAR VARIABLES

IF (KF_SCDERS > 0) THEN
#ifdef OMPGPU
  !$OMP TARGET TEAMS DISTRIBUTE PARALLEL DO DEFAULT(NONE) SHARED(KF_SCALARS,PEWDERS,PSCALAR)
#endif
#ifdef ACCGPU
  !$ACC PARALLEL LOOP COLLAPSE(3) PRIVATE(IGLG,IOFF_LAT,IOFF_SCALARS_EWDER,IOFF_SCALARS,ZIM,RET_REAL,RET_COMPLEX) &
  !$ACC& FIRSTPRIVATE(KF_SCALARS,I_SCDERS_OFFSET,I_SC_OFFSET,KF_FS)
#endif
  DO JGL=1,D%NDGL_FS
    DO JF=1,KF_SCALARS
      DO JM=0,JLOEN_MAX/2
        IGLG = D%NPTRLS(MYSETW)+JGL-1
        IOFF_LAT = KF_FS*D%NSTAGTF(JGL)
        IOFF_SCALARS_EWDER = IOFF_LAT+(I_SCDERS_OFFSET+JF-1)*(D%NSTAGTF(JGL+1)-D%NSTAGTF(JGL))
        IOFF_SCALARS = IOFF_LAT+(I_SC_OFFSET+JF-1)*(D%NSTAGTF(JGL+1)-D%NSTAGTF(JGL))

        RET_REAL = 0.0_JPRBT
        RET_COMPLEX = 0.0_JPRBT

        IF (JM <= G%NMEN(IGLG)) THEN
          ZIM  = REAL(JM,JPRB)*GALD%EXWN

          RET_REAL = &
              & -PREEL(IOFF_SCALARS+2*JM+2)*ZIM
          RET_COMPLEX = &
              &  PREEL(IOFF_SCALARS+2*JM+1)*ZIM
        ENDIF
        ! The rest from G_NMEN(IGLG+1)...MAX is zero truncated
        PREEL(IOFF_SCALARS_EWDER+2*JM+1) = RET_REAL
        PREEL(IOFF_SCALARS_EWDER+2*JM+2) = RET_COMPLEX
      ENDDO
    ENDDO
  ENDDO
ENDIF

#ifdef ACCGPU
!$ACC END DATA
#endif

IF (LHOOK) CALL DR_HOOK('EFSC_MOD:EFSC',1,ZHOOK_HANDLE)

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

END SUBROUTINE EFSC
END MODULE EFSC_MOD