SUBROUTINE SISEVE(KLEV,KLON,PV1,PV2,KNLON)

!**** *SISEVE* - SEcond VErtical derivative operator in Semi - Implicit

!     Purpose.
!     --------
!           Operator L to compute vertical Laplacian in non-hydrostatic
!           dynamics: formulation for semi - implicit

!           The discretisation of the vertical Laplacian must remain
!           consistent with the discretisation of the equivalent quantity
!           in the non linear part (pieces of codes spread in GNHPREH,
!           GNH_TNDLAGADIAB_GW and GNH_TNDLAGADIAB_SVD).

!           This vertical Laplacian is applied to a quantity "X" (in PV1)
!           which matches the following conditions:
!           X_top = 0
!           X_surf = X(l=nflevg)
!           (see for example the calculation of the top and bottom
!           pressure departure variable in GNHPREH).

!**   Interface.
!     ----------
!        *CALL* *SISEVE(KLEV,KLON,PV1,PV2,KNLON)

!        Explicit arguments :
!        --------------------
!        KLEV   : DISTANCE IN MEMORY BETWEEN VALUES OF THE VARIABLES
!                PV1 OR PV2 AT THE VERTICAL
!        KLON   : DISTANCE IN MEMORY BETWEEN VALUES OF THE VARIABLES
!                PV1 OR PV2 AT THE SAME LEVEL

!           TYPICAL VALUES ARE  NDLSUR,1  FOR GRID POINT ARRAY
!                               1,NFLSUR  FOR SPECTRAL ARRAY

!        PV1   : INPUT VARIABLE
!        PV2   : DERIVED VARIABLE BY VERTICAL LAPLACIAN
!        KNLON : NUMBER OF VERTICAL COLUMNS TREATED

!        Implicit arguments :
!        --------------------

!     Method.
!     -------
!        See documentation

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

!     Reference.
!     ----------
!        Arpege/Aladin documentation

!     Author.
!     -------
!        Radmila Bubnova GMAP/COMPAS, stage MRE

!     Modifications.
!     --------------
!        Original : 93-03-21
!        L. Isaksen 96-05-05  Adapted for Message Passing
!        M.Hamrud   01-Oct-2003 CY28 Cleaning
!        K.Yessad   16-Mar-2005 Cleaning 
!        J.Vivoda + KY  02-Mar-2006 VFE for NH model
!     ------------------------------------------------------------------

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

USE YOMDIM   , ONLY : NFLEVG
USE YOMDYN   , ONLY : SILNPR   ,SITLAF   ,SIPR     ,SIRDEL
USE YOMGEM   , ONLY : VBH      ,VAH      ,VFE_RDETAH
USE YOMCVER  , ONLY : LRNHC1   ,LVERTFE  ,LVFE_LAPL,LVFE_LAPL_BC

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

IMPLICIT NONE

INTEGER(KIND=JPIM),INTENT(IN)    :: KLEV 
INTEGER(KIND=JPIM),INTENT(IN)    :: KLON 
INTEGER(KIND=JPIM),INTENT(IN)    :: KNLON 
REAL(KIND=JPRB)   ,INTENT(IN)    :: PV1(1+(NFLEVG-1)*KLEV+(KNLON-1)*KLON) 
REAL(KIND=JPRB)   ,INTENT(OUT)   :: PV2(1+(NFLEVG-1)*KLEV+(KNLON-1)*KLON) 

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

REAL(KIND=JPRB) :: ZA(NFLEVG), ZC(NFLEVG), ZRM(NFLEVG)
REAL(KIND=JPRB) :: ZPRTOP

INTEGER(KIND=JPIM) :: IBOT1, IBOT2, ILEV1, ILEV2, ILEV3, ITOP1, ITOP2
INTEGER(KIND=JPIM) :: JLEV, JLON, IDT

REAL(KIND=JPRB) :: ZIN(KNLON,NFLEVG)
REAL(KIND=JPRB) :: ZINDETA(KNLON,NFLEVG)
REAL(KIND=JPRB) :: ZINDETA2(KNLON,NFLEVG)
REAL(KIND=JPRB) :: ZP2MDETA(KNLON,NFLEVG)

LOGICAL :: LLVFE,LLVFE_LAPL_BC,LLVFE_LAPL

REAL(KIND=JPRB) :: ZHOOK_HANDLE

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

#include "verder.intfb.h"
#include "verdder.intfb.h"

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

IF (LHOOK) CALL DR_HOOK('SISEVE',0,ZHOOK_HANDLE)

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

!*       1.    BOUNDARY CONDITIONS FOR FD
!              --------------------------

IF (LRNHC1) THEN
  LLVFE=.FALSE.
  LLVFE_LAPL_BC=.FALSE.
  LLVFE_LAPL=.FALSE.
ELSE
  LLVFE=LVERTFE
  LLVFE_LAPL_BC=LVFE_LAPL_BC
  LLVFE_LAPL=LVFE_LAPL
ENDIF

IF( .NOT.(LLVFE.AND.LLVFE_LAPL_BC.AND.LLVFE_LAPL) )THEN

  ! --- Finite differences ---

  ! * Compute the coefficients "A" and "C" at full level 1:
  !   "A" must be zero if the top pressure of the model is zero.
  ZPRTOP=VAH(0)+VBH(0)*SIPR
  ZA(1)=ZPRTOP/(SILNPR(1)*(SITLAF(1)-ZPRTOP))
  ZC(1)=SITLAF(2)/(SILNPR(1)*(SITLAF(2)-SITLAF(1)))

  ! * Compute the coefficients "A" and "C" at full level nflevg:
  !   "C" must be zero.
  ZA(NFLEVG)=SITLAF(NFLEVG-1)/(SILNPR(NFLEVG)*(SITLAF(NFLEVG)-SITLAF(NFLEVG-1)))
  ZC(NFLEVG)=0.0_JPRB

  ! * Top:
  DO JLON = 1, KNLON
    ITOP1 = 1 + (JLON-1)*KLON
    ITOP2 = ITOP1 + KLEV
    PV2(ITOP1) = -ZA(1)*PV1(ITOP1)+ZC(1)*(PV1(ITOP2)-PV1(ITOP1))
  ENDDO

  ! * Bottom:
  DO JLON = 1, KNLON
    IBOT1 = 1 + (NFLEVG-2)*KLEV + (JLON-1)*KLON
    IBOT2 = IBOT1 + KLEV
    PV2(IBOT2) = ZA(NFLEVG)*(PV1(IBOT1)-PV1(IBOT2)) &
     & - ZA(NFLEVG)*(SITLAF(NFLEVG)/SITLAF(NFLEVG-1) - 1.0_JPRB)*PV1(IBOT2)
  ENDDO

ENDIF

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

!*       2.    INNER LAYERS (AND BOUNDARY CONDITIONS FOR VFE)
!              ----------------------------------------------

IF(LLVFE.AND.LLVFE_LAPL)THEN

  ! --- VFE ---
  ! In this formulation the vertical laplacian
  ! is computed without proper bottom boundary conditions.

  ! * precompute pi(l)/[d pi/d eta](l):
  DO JLEV=1,NFLEVG
    ZRM(JLEV) = SIRDEL(JLEV)/VFE_RDETAH(JLEV)
    ZA(JLEV)  = (SITLAF(JLEV)**2)*ZRM(JLEV)
    ZC(JLEV)  = ZA(JLEV)*ZRM(JLEV)
  ENDDO

  ! * transform PV1 into form appropriate for VERDER and VERDDER:
  DO JLEV=1,NFLEVG
    DO JLON=1,KNLON
      IDT=1+(JLEV-1)*KLEV+(JLON-1)*KLON
      ZIN(JLON,JLEV)=PV1(IDT) ! array to be derivated
    ENDDO
  ENDDO

  ! * term: 1/[d pi/d eta] * d/deta ( pi^2/[d pi/d eta] ) * ( d X/deta )
  CALL VERDER(KNLON,1,KNLON,NFLEVG,ZIN,ZINDETA)
  ! * term: (pi/[d pi/d eta])^2  d^2 X/deta^2
  CALL VERDDER(KNLON,1,KNLON,NFLEVG,ZIN,ZINDETA2)

  ! * d/deta (p^2/[d pi/d eta])
  DO JLEV=1,NFLEVG
    DO JLON=1,KNLON
      ZIN(JLON,JLEV)=ZA(JLEV)
    ENDDO
  ENDDO
  CALL VERDER(KNLON,1,KNLON,NFLEVG,ZIN,ZP2MDETA)

  ! * compute PV2 = 2 * pi_l/[d pi/d eta]_l * dX/deta 
  !   + (pi_l/[d pi/d eta]_l)**2 * d^2 X/deta^2
  IF(LVFE_LAPL_BC)THEN
    DO JLEV=1,NFLEVG
      DO JLON=1,KNLON
        IDT=1+(JLEV-1)*KLEV+(JLON-1)*KLON
        PV2(IDT)= ZRM(JLEV)*ZP2MDETA(JLON,JLEV)*ZINDETA(JLON,JLEV) + &
         & ZC(JLEV)*ZINDETA2(JLON,JLEV)
      ENDDO
    ENDDO
  ELSE
    DO JLEV=2,NFLEVG-1
      DO JLON=1,KNLON
        IDT=1+(JLEV-1)*KLEV+(JLON-1)*KLON
        PV2(IDT)= ZRM(JLEV)*ZP2MDETA(JLON,JLEV)*ZINDETA(JLON,JLEV) + &
         & ZC(JLEV)*ZINDETA2(JLON,JLEV)
      ENDDO
    ENDDO
  ENDIF

ELSE

  ! --- Finite differences ---

  ! * Compute the coefficients A and C at full levels 2 to nflevg-1:
  DO JLEV = 2, NFLEVG-1
    ZA(JLEV) = SITLAF(JLEV-1)/(SILNPR(JLEV)*(SITLAF(JLEV)-SITLAF(JLEV-1)))
    ZC(JLEV) = SITLAF(JLEV+1)/(SILNPR(JLEV)*(SITLAF(JLEV+1)-SITLAF(JLEV)))
  ENDDO

  ! * Other Levels:
  DO JLEV = 2, NFLEVG-1
    DO JLON = 1, KNLON
      ILEV1 = 1 + (JLEV-2)*KLEV + (JLON-1)*KLON
      ILEV2 = ILEV1 + KLEV
      ILEV3 = ILEV2 + KLEV
      PV2(ILEV2) = ZA(JLEV)*(PV1(ILEV1)-PV1(ILEV2))&
       & + ZC(JLEV)*(PV1(ILEV3)-PV1(ILEV2))
    ENDDO
  ENDDO

ENDIF

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

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