diff --git a/src/ZSOLVER/anel_balancen.f90 b/src/ZSOLVER/anel_balancen.f90
new file mode 100644
index 0000000000000000000000000000000000000000..c1659356c3616b260ddda416eb328e07ddb3faca
--- /dev/null
+++ b/src/ZSOLVER/anel_balancen.f90
@@ -0,0 +1,334 @@
+!MNH_LIC Copyright 1994-2020 CNRS, Meteo-France and Universite Paul Sabatier
+!MNH_LIC This is part of the Meso-NH software governed by the CeCILL-C licence
+!MNH_LIC version 1. See LICENSE, CeCILL-C_V1-en.txt and CeCILL-C_V1-fr.txt
+!MNH_LIC for details. version 1.
+!-----------------------------------------------------------------
+!     ##########################
+      MODULE MODI_ANEL_BALANCE_n
+!     ##########################
+!
+INTERFACE
+!
+SUBROUTINE ANEL_BALANCE_n(PRESIDUAL)
+!
+REAL, OPTIONAL                 :: PRESIDUAL
+END SUBROUTINE ANEL_BALANCE_n
+!
+END INTERFACE
+!
+END MODULE MODI_ANEL_BALANCE_n
+!
+!
+!
+!     ################################
+      SUBROUTINE ANEL_BALANCE_n(PRESIDUAL)
+!
+!     ################################
+!
+!
+!!****  *ANEL_BALANCE_n* - routine to apply an anelastic correction
+!!                   
+!!
+!!    PURPOSE
+!!    -------
+!       The purpose of this routine is to  fulfill the anelastic balance
+!    in case of non-vanishing orography
+!
+!
+!
+!!**  METHOD
+!!    ------
+!!      The coefficients for the flat operator are first computed. Then the
+!!    pressure equation is solved and the pressure gradient is added to the wind
+!!    components in order to render this wind field non-divergent.
+!!
+!!    EXTERNAL
+!!    --------
+!!    TRID     : to compute coefficients for the flat operator
+!!    PRESSURE : to solve the pressure equation and add the pressure term to
+!!               wind
+!!    MXM,MYM,MZM : to average a field at mass point in the x,y,z directions
+!!
+!!
+!!    IMPLICIT ARGUMENTS
+!!    ------------------
+!!
+!!      Module MODD_CONF    : contains configuration variables for all models.
+!!         NVERB : verbosity level for output-listing
+!!
+!!      Module MODD_GRID_n  : contains grid variables
+!!         XMAP,XXHAT,XYHAT,XZZ
+!!
+!!      Module MODD_REF_n   : contains reference state variables 
+!!         XRHODJ,XTHVREF,XEXNREF,XRHODREF,XRVREF
+!!
+!!      Module MODD_REF_n   : contains reference state variables 
+!!         XLINMASS : lineic mass along the lateral boundaries
+!!
+!!      Module MODD_FIELD_n : contains prognostic variables
+!!         XUT,XVT,XWT,XTHT,XRT
+!! 
+!!      Module MODD_DYN_n : contains parameters for the dynamics
+!!         CPRESOPT : option for the pressure solver
+!!         NITR     : number of iterations for the solver
+!!         XRELAX   : relaxation coefficient used in the Richardson method
+!! 
+!!      Module MODD_LBC_n : contains parameters relative to the boundaries
+!!         CLBCX    : choice of lateral boundary condition along x
+!!         CLBCY    : choice of lateral boundary condition along y
+!!
+!!    REFERENCE
+!!    ---------
+!!      NONE
+!!
+!!
+!!    AUTHOR
+!!    ------
+!!      V. Ducrocq       * Meteo France *
+!!
+!!    MODIFICATIONS
+!!    -------------
+!!      Original     6/09/94
+!!      J. Stein     4/11/94  put the pressure solver parameters in namelist
+!!      J. Stein     2/12/94  source cleaning
+!!      J.P. Lafore 03/01/95  call to PRESSURE to account for absolute pressure
+!!      J. Stein    17/01/95  bug in the pressure call
+!!      J. Stein    15/03/95  remove R from the historical variables
+!!      J.Stein and J.P. lafore 17/04/96 new version including the way to choose
+!!            the model number and the instant where the projection is performed
+!!      Stein,Lafore 14/01/97 new anelastic equations
+!!      M.Faivre    2014
+!!      M.Moge      08/2015   removing UPDATE_HALO_ll(XRHODJ) + EXTRAPOL on ZRU and ZRV in part 3.1
+!!      J.Escobar : 15/09/2015 : WENO5 & JPHEXT <> 1 
+!!  Philippe Wautelet: 05/2016-04/2018: new data structures and calls for I/O
+!  P. Wautelet 20/05/2019: add name argument to ADDnFIELD_ll + new ADD4DFIELD_ll subroutine
+!-------------------------------------------------------------------------------
+!
+!*       0.    DECLARATIONS
+!              ------------
+!
+!
+USE MODE_ll
+USE MODE_MODELN_HANDLER
+!
+USE MODD_CONF    ! declarative modules
+USE MODD_PARAMETERS
+USE MODD_GRID_n
+USE MODD_DIM_n
+USE MODD_METRICS_n
+USE MODD_REF_n
+USE MODD_FIELD_n
+USE MODD_DYN_n
+USE MODD_LBC_n
+!
+USE MODI_TRIDZ    ! interface modules
+USE MODI_PRESSUREZ
+USE MODE_SPLITTINGZ_ll
+USE MODI_SHUMAN
+!
+USE MODD_ARGSLIST_ll, ONLY : LIST_ll
+USE MODE_MPPDB
+USE MODE_EXTRAPOL
+!
+IMPLICIT NONE
+!
+!*       0.1   Declarations of arguments :
+!
+REAL, OPTIONAL                 :: PRESIDUAL
+!
+!*       0.2   Declarations of local variables :
+!
+INTEGER :: IRESP                  ! return code
+INTEGER :: IIY,IJY                ! same variable for Y decomposition
+INTEGER :: ITCOUNT                ! counter value of temporal loop set to 1 ( this
+                                  ! means that no guess of the pressure is available for
+                                  ! the pressure solver
+REAL    :: ZDXHATM                   ! mean grid increment in the x direction
+REAL    :: ZDYHATM                   ! mean grid increment in the y direction
+REAL, DIMENSION (SIZE(XRHODJ,3)) :: ZRHOM   !  mean of XRHODJ on the plane x y
+                                            !  localized at a mass level
+!
+REAL, DIMENSION(SIZE(XRHODJ,3))    :: ZAF,ZCF  ! vector giving the nonvanishing
+REAL, DIMENSION(:,:,:), ALLOCATABLE :: ZBFY    ! elements of the tri-diag matrix
+                                               ! in the pressure equation
+REAL, DIMENSION(:), ALLOCATABLE   :: ZTRIGSX   ! arrays of sin or cos values for
+REAL, DIMENSION(:), ALLOCATABLE   :: ZTRIGSY   ! the FFT in x and y directions
+INTEGER, DIMENSION(19)            :: IIFAXX    ! decomposition in prime numbers
+INTEGER, DIMENSION(19)            :: IIFAXY    ! for the FFT in x and y
+                                               ! directions
+REAL, DIMENSION(SIZE(XRHODJ,1),SIZE(XRHODJ,2),SIZE(XRHODJ,3)) :: ZPABST
+                                               ! Potential at time t
+REAL, DIMENSION(SIZE(XRHODJ,1),SIZE(XRHODJ,2),SIZE(XRHODJ,3)) :: ZRU,ZRV,ZRW
+                                               ! Rhod * (U,V,W)
+REAL, DIMENSION(SIZE(XRHODJ,1),SIZE(XRHODJ,2),SIZE(XRHODJ,3)) :: ZTH
+REAL, DIMENSION(:,:,:,:), ALLOCATABLE :: ZRR
+!
+INTEGER                       ::       IRR     ! Total number of water variables
+INTEGER                       ::       IRRL    ! Number of liquid water variables
+INTEGER                       ::       IRRI    ! Number of solid water variables
+REAL                          ::  ZDRYMASST    ! Mass of dry air Md
+REAL                          ::  ZREFMASS     ! Total mass of the ref. atmosphere
+REAL                          ::  ZMASS_O_PHI0 ! Mass / Phi0
+LOGICAL                       ::  GCLOSE_OUT   ! switch for the LFI writing
+CHARACTER (LEN= 28)           ::  YFMFILE      ! virtual FM file
+INTEGER                       ::  IMI          ! model index
+!JUAN
+INTEGER                               ::  IIU_B,IJU_B,IKU
+INTEGER                               ::  IIU_SXP2_YP1_Z_ll,IJU_SXP2_YP1_Z_ll,IKU_SXP2_YP1_Z_ll
+REAL, DIMENSION(:,:,:), ALLOCATABLE   ::  ZBFB,ZBF_SXP2_YP1_Z   
+REAL, DIMENSION(:,:,:), ALLOCATABLE   :: ZAF_ZS,ZBF_ZS,ZCF_ZS
+REAL, DIMENSION(:,:)  , ALLOCATABLE   :: ZDXATH_ZS,ZDYATH_ZS
+REAL, DIMENSION(:,:,:), ALLOCATABLE   :: ZRHO_ZS    
+REAL, DIMENSION(:),     ALLOCATABLE   :: ZA_K,ZB_K,ZC_K,ZD_K                 
+!JUAN
+!
+INTEGER :: IINFO_ll
+TYPE(LIST_ll), POINTER :: TZFIELDS_ll=>NULL()   ! list of fields to exchange
+!
+!-------------------------------------------------------------------------------
+!
+!*       1.     PROLOGUE  :
+!               --------
+!
+CALL GET_DIM_EXT_ll('Y',IIY,IJY)
+IF (L2D) THEN
+  ALLOCATE(ZBFY(IIY,IJY,SIZE(XRHODJ,3)))
+ELSE
+  ALLOCATE(ZBFY(IJY,IIY,SIZE(XRHODJ,3)))
+ENDIF
+ALLOCATE(ZTRIGSX(3*(NIMAX_ll+2*JPHEXT)))
+ALLOCATE(ZTRIGSY(3*(NJMAX_ll+2*JPHEXT)))
+!JUAN Z_SPLITING
+IKU=SIZE(XRHODJ,3)
+CALL GET_DIM_EXT_ll('B',IIU_B,IJU_B)
+ALLOCATE(ZBFB(IIU_B,IJU_B,IKU))
+!
+ALLOCATE(ZAF_ZS(IIU_B,IJU_B,IKU))
+ALLOCATE(ZBF_ZS(IIU_B,IJU_B,IKU))
+ALLOCATE(ZCF_ZS(IIU_B,IJU_B,IKU))
+ALLOCATE(ZDXATH_ZS(IIU_B,IJU_B))
+ALLOCATE(ZDYATH_ZS(IIU_B,IJU_B))
+ALLOCATE(ZRHO_ZS(IIU_B,IJU_B,IKU))
+ALLOCATE(ZA_K(IKU))
+ALLOCATE(ZB_K(IKU))
+ALLOCATE(ZC_K(IKU))
+ALLOCATE(ZD_K(IKU))
+!
+CALL GET_DIM_EXTZ_ll('SXP2_YP1_Z',IIU_SXP2_YP1_Z_ll,IJU_SXP2_YP1_Z_ll,IKU_SXP2_YP1_Z_ll)
+ALLOCATE(ZBF_SXP2_YP1_Z(IIU_SXP2_YP1_Z_ll,IJU_SXP2_YP1_Z_ll,IKU_SXP2_YP1_Z_ll))
+!
+!JUAN Z_SPLITING
+CALL MPPDB_CHECK3D(XRHODJ,"anel_balancen1-::XRHODJ",PRECISION)
+CALL MPPDB_CHECK3D(XUT,"anel_balancen1-::XUT",PRECISION)
+!
+!-------------------------------------------------------------------------------
+!
+!*       2.     PRESSURE SOLVER INITIALIZATION :
+!               -------------------------------
+!
+!
+CALL TRIDZ(CLBCX,CLBCY,XMAP,XDXHAT,XDYHAT,CPRESOPT,                     &
+          ZDXHATM,ZDYHATM,ZRHOM,                                        &
+          ZAF,ZCF,ZTRIGSX,ZTRIGSY,IIFAXX,IIFAXY,XRHODJ,XTHVREF,XZZ,ZBFY,&
+          ZBFB,ZBF_SXP2_YP1_Z,                                          &
+          ZAF_ZS,ZBF_ZS,ZCF_ZS,                                         &
+          ZDXATH_ZS,ZDYATH_ZS,ZRHO_ZS,                      &
+          ZA_K,ZB_K,ZC_K,ZD_K) !JUAN  FULL ZSOLVER
+CALL MPPDB_CHECK3D(XRHODJ,"anel_balancen1-after TRIDZ::XRHODJ",PRECISION)
+!
+!-------------------------------------------------------------------------------
+!
+!*       3.      ANELASTIC CORRECTION :
+!                ---------------------
+!
+!
+!*       3.1     multiplication by RHODJ
+!
+!$20140710 UPHALO on XRHODJ
+!CALL ADD3DFIELD_ll( TZFIELDS_ll, XRHODJ, 'ANEL_BALANCE_n::XRHODJ' )
+!CALL UPDATE_HALO_ll(TZFIELDS_ll,IINFO_ll)
+!CALL CLEANLIST_ll(TZFIELDS_ll)
+CALL MPPDB_CHECK3D(XRHODJ,"anel_balancen3.1-after update halo::XRHODJ",PRECISION)
+CALL MPPDB_CHECK3D(XUT,"anel_balancen3.1-after update halo::XUT",PRECISION)
+CALL MPPDB_CHECK3D(XWT,"anel_balancen3.1-after update halo::XWT",PRECISION)
+!
+ZRU(:,:,:) = MXM(XRHODJ) * XUT(:,:,:)
+ZRV(:,:,:) = MYM(XRHODJ) * XVT(:,:,:)
+ZRW(:,:,:) = MZM(XRHODJ) * XWT(:,:,:)
+ZTH(:,:,:) = XTHT(:,:,:)
+ALLOCATE(ZRR(SIZE(XRHODJ,1),SIZE(XRHODJ,2),SIZE(XRHODJ,3),SIZE(XRT,4)))
+ZRR(:,:,:,:) = XRT(:,:,:,:)
+!20131112 appli update_halo_ll
+CALL ADD3DFIELD_ll( TZFIELDS_ll, ZRU, 'ANEL_BALANCE_n::ZRU' )
+CALL ADD3DFIELD_ll( TZFIELDS_ll, ZRV, 'ANEL_BALANCE_n::ZRV' )
+CALL ADD3DFIELD_ll( TZFIELDS_ll, ZRW, 'ANEL_BALANCE_n::ZRW' )
+CALL ADD3DFIELD_ll( TZFIELDS_ll, ZTH, 'ANEL_BALANCE_n::ZTH' )
+CALL UPDATE_HALO_ll(TZFIELDS_ll,IINFO_ll)
+CALL CLEANLIST_ll(TZFIELDS_ll)
+CALL MPPDB_CHECK3D(ZRU,"anel_balancen3.1-after1stupdhalo::ZRU",PRECISION)
+!$20131125 add extrapol on ZRU to have correct boundaries
+!CALL EXTRAPOL('W',ZRU)  ! ZRU boundaries now correct
+CALL MPPDB_CHECK3D(ZRU,"anel_balancen3.1-afterextrapol W::ZRU",PRECISION)
+!20131126 add extrapol on ZRV to have correct boundaries
+!CALL EXTRAPOL('S',ZRV)  ! ZRV boundaries now correct
+CALL MPPDB_CHECK3D(ZRV,"anel_balancen3.1-afterextrapol S::ZRV",PRECISION)
+CALL MPPDB_CHECK3D(ZRW,"anel_balancen3.1-afterextrapol S::ZRW",PRECISION)
+!
+!
+!
+!
+!*       3.2     satisfy the anelastic constraint
+!
+ITCOUNT      =-1     ! no first guess of the pressure is available
+ZPABST(:,:,:)= 0.    !       ==================CAUTION=====================
+ZDRYMASST    = 0.    !      |   Initialization necessary for the           |
+ZREFMASS     = 0.    !      |  computation of the absolute pressure,       |
+ZMASS_O_PHI0 = 1.    !      |  which is here not needed                    |
+IRR  = 0             !      |                                              |
+IRRL = 0             !      |                                              |
+IRRI = 0             !       ==============================================
+GCLOSE_OUT=.FALSE.
+YFMFILE='UNUSED'
+!
+IMI = GET_CURRENT_MODEL_INDEX()
+CALL PRESSUREZ(CLBCX,CLBCY,CPRESOPT,NITR,LITRADJ,ITCOUNT,XRELAX,IMI,  &
+               XRHODJ,XDXX,XDYY,XDZZ,XDZX,XDZY,ZDXHATM,ZDYHATM,ZRHOM, &
+               ZAF,ZBFY,ZCF,ZTRIGSX,ZTRIGSY,IIFAXX,IIFAXY,            &
+               IRR,IRRL,IRRI,ZDRYMASST,ZREFMASS,ZMASS_O_PHI0,         &
+               ZTH,ZRR,XRHODREF,XTHVREF,XRVREF,XEXNREF, XLINMASS,     &
+               ZRU,ZRV,ZRW,ZPABST,                                    &
+               ZBFB,ZBF_SXP2_YP1_Z,                                   &
+               XAF_ZS,XBF_ZS,XCF_ZS,                                  &
+               XDXATH_ZS,XDYATH_ZS,XRHO_ZS,                           &
+               XA_K,XB_K,XC_K,XD_K,                                   &
+               PRESIDUAL                          )
+!
+CALL MPPDB_CHECK3D(XRHODJ,"anel_balancen3.2-after pressurez halo::XRHODJ",PRECISION)
+CALL MPPDB_CHECK3D(ZRU,"anel_balancen3.2-after pressurez::ZRU",PRECISION)
+CALL MPPDB_CHECK3D(ZRV,"anel_balancen3.2-after pressurez::ZRV",PRECISION)
+!
+DEALLOCATE(ZBFY,ZTRIGSX,ZTRIGSY,ZRR,ZBF_SXP2_YP1_Z)
+!*       3.2     return to the historical variables
+!
+!20131112 appli update_halo_ll and associated operations
+XUT(:,:,:) = ZRU(:,:,:) / MXM(XRHODJ)
+XVT(:,:,:) = ZRV(:,:,:) / MYM(XRHODJ)
+XWT(:,:,:) = ZRW(:,:,:) / MZM(XRHODJ)
+!20131112 appli update_halo_ll to XUT,XVT,XWT
+CALL ADD3DFIELD_ll( TZFIELDS_ll, XUT, 'ANEL_BALANCE_n::XUT' )
+CALL ADD3DFIELD_ll( TZFIELDS_ll, XVT, 'ANEL_BALANCE_n::XVT' )
+CALL ADD3DFIELD_ll( TZFIELDS_ll, XWT, 'ANEL_BALANCE_n::XWT' )
+CALL UPDATE_HALO_ll(TZFIELDS_ll,IINFO_ll)
+CALL CLEANLIST_ll(TZFIELDS_ll)
+CALL MPPDB_CHECK3D(XUT,"anel_balancen3.2-afterupdhalo::XUT",PRECISION)
+CALL MPPDB_CHECK3D(XVT,"anel_balancen3.2-afterupdhalo::XVT",PRECISION)
+!20131125 apply extrapol to fix boundary issue in //
+CALL EXTRAPOL('W',XUT)
+CALL EXTRAPOL('S',XVT)
+CALL MPPDB_CHECK3D(XUT,"anel_balancen3.2-after extrapolW::XUT",PRECISION)
+CALL MPPDB_CHECK3D(XVT,"anel_balancen3.2-after extrapolS::XVT",PRECISION)
+!
+!
+!-------------------------------------------------------------------------------
+!
+END SUBROUTINE ANEL_BALANCE_n
diff --git a/src/ZSOLVER/flat_inv.f90 b/src/ZSOLVER/flat_inv.f90
new file mode 100644
index 0000000000000000000000000000000000000000..38fd8718dff9fbfb46dee6c8b59de4b1b6d8d94a
--- /dev/null
+++ b/src/ZSOLVER/flat_inv.f90
@@ -0,0 +1,702 @@
+!MNH_LIC Copyright 1994-2014 CNRS, Meteo-France and Universite Paul Sabatier
+!MNH_LIC This is part of the Meso-NH software governed by the CeCILL-C licence
+!MNH_LIC version 1. See LICENSE, CeCILL-C_V1-en.txt and CeCILL-C_V1-fr.txt  
+!MNH_LIC for details. version 1.
+!-----------------------------------------------------------------
+!--------------- special set of characters for RCS information
+!-----------------------------------------------------------------
+! $Source$ $Revision$
+! MASDEV4_7 solver 2006/05/18 13:07:25
+!-----------------------------------------------------------------
+!     ####################
+      MODULE MODI_FLAT_INV
+!     ####################
+!
+INTERFACE
+!
+      SUBROUTINE FLAT_INV(HLBCX,HLBCY,PDXHATM,PDYHATM,PRHOM,PAF,PBF,PCF, &
+      PTRIGSX,PTRIGSY,KIFAXX,KIFAXY,PY,PF_1_Y)
+!
+!  
+IMPLICIT NONE
+!
+CHARACTER (LEN=4), DIMENSION(2), INTENT(IN) :: HLBCX    ! x-direction LBC type 
+CHARACTER (LEN=4), DIMENSION(2), INTENT(IN) :: HLBCY    ! y-direction LBC type 
+!
+REAL, INTENT(IN) :: PDXHATM                     ! mean grid increment in the x
+                                                ! direction
+REAL, INTENT(IN) :: PDYHATM                     ! mean grid increment in the y
+                                                ! direction
+!
+REAL, DIMENSION (:), INTENT(IN) :: PRHOM         !  mean of XRHODJ on the plane x y 
+                                                 !  localized at a mass level
+!
+REAL, DIMENSION(:), INTENT(IN)     :: PAF,PCF    ! vectors giving the nonvanishing
+REAL, DIMENSION(:,:,:), INTENT(IN) :: PBF        ! elements of the tri-diag. 
+                                                 ! matrix in the pressure eq.
+!
+                                                 ! arrays of sin or cos values
+                                                 ! for the FFT :
+REAL, DIMENSION(:), INTENT(IN) :: PTRIGSX        ! - along x
+REAL, DIMENSION(:), INTENT(IN) :: PTRIGSY        ! - along y
+!
+                                                 ! decomposition in prime 
+                                                 ! numbers for the FFT:
+INTEGER, DIMENSION(19), INTENT(IN) :: KIFAXX      ! - along x
+INTEGER, DIMENSION(19), INTENT(IN) :: KIFAXY      ! - along y
+!
+REAL, DIMENSION(:,:,:), INTENT(IN) :: PY         ! RHS of the equation
+!                                                         
+REAL, DIMENSION(:,:,:), INTENT(OUT):: PF_1_Y     ! solution of the equation
+!
+END SUBROUTINE FLAT_INV
+!
+END INTERFACE
+!
+END MODULE MODI_FLAT_INV
+!     ######################################################################
+      SUBROUTINE FLAT_INV(HLBCX,HLBCY,PDXHATM,PDYHATM,PRHOM,PAF,PBF,PCF,   &
+      PTRIGSX,PTRIGSY,KIFAXX,KIFAXY,PY,PF_1_Y)
+!     ######################################################################
+!
+!!****  *FLAT_INV * - Invert the flat quasi-laplacian operator
+!!
+!!    PURPOSE
+!!    -------
+!       This routine solves the following equation:
+!                    F ( F_1_Y ) =  Y 
+!     where F represents the quasi-laplacian without orography. The solution is 
+!     F_1_Y.
+!
+!!**  METHOD
+!!    ------
+!!      The horizontal part of F is inverted with a FFT transform. For each 
+!!    horizontal direction, the FFT form depends on the lateral boundary 
+!!    conditions :
+!!    - CRAY intrinsic function RFFTMLT in the cyclic case 
+!!    - fast cosine transform called FFT55 for all other boundary condtions.
+!!    Then, in the wavenumber space, we invert for each 
+!!    horizontal mode i,j a tridiagonal matrix by a classical double sweep 
+!!    method.  The singular mean mode (i,j)=(0,0) corresponds to the 
+!!    undetermination of the pressure to within a constant and is treated apart.
+!!    To fix this degree of freedom, we set the horizontal mean value of the 
+!!    pressure perturbation to 0 at the upper level of the model. 
+!!       
+!!    EXTERNAL
+!!    --------
+!!      Subroutine FFT55 : aplly multiple fast real staggered (shifted) 
+!!    cosine transform
+!!      Subroutine RFFTMLT : apply real-to-complex or complex-to-real Fast 
+!!    Fourier Transform (FFT) on multiple input vectors.
+!!      Subroutine FFT991  : equivalent to RFFTMLT
+!!
+!!    IMPLICIT ARGUMENTS
+!!    ------------------ 
+!!      Module MODD_PARAMETERS: declaration of parameter variables
+!!        JPHEXT, JPVEXT: define the number of marginal points out of the 
+!!        physical domain along horizontal and vertical directions respectively
+!!      Module MODD_CONF: model configurations
+!!        L2D: logical for 2D model version
+!!
+!!    REFERENCE
+!!    ---------
+!!      Book2 of documentation (subroutine FLAT_INV)     
+!!
+!!    AUTHOR
+!!    ------
+!!	P. Hereil and J. Stein       * Meteo France *
+!!
+!!    MODIFICATIONS
+!!    -------------
+!!      Original    20/07/94 
+!!      Revision  Jabouille (juillet 96) replace the CRAY intrinsic function
+!!                             RFFTMLT by the arpege routine FFT991
+!!                  17/07/97  ( J. Stein and V. Masson) initialize the corner
+!!                             verticals
+!!                  17/07/97  ( J. Stein and V. Masson) initialize the corner
+!!                             verticals
+!!      Revision  Jabouille (septembre 97) suppress the particular case for
+!!                                         tridiagonal inversion
+!!                Stein     ( January 98 ) faster computation for the unused 
+!!                                points under the ground and out of the domain  
+!!      Modification   Lugato, Guivarch (June 1998) Parallelisation
+!!                     Escobar, Stein   (July 2000) optimisation
+!-------------------------------------------------------------------------------
+!
+!*       0.    DECLARATIONS
+!              ------------
+!
+USE MODD_PARAMETERS
+USE MODD_CONF
+!
+USE MODE_ll
+USE MODD_ARGSLIST_ll, ONLY : LIST_ll
+!
+USE MODI_FFT55
+!
+IMPLICIT NONE
+!
+!*       0.1   declarations of arguments
+!
+CHARACTER (LEN=4), DIMENSION(2), INTENT(IN) :: HLBCX    ! x-direction LBC type 
+CHARACTER (LEN=4), DIMENSION(2), INTENT(IN) :: HLBCY    ! y-direction LBC type 
+!
+REAL, INTENT(IN) :: PDXHATM                     ! mean grid increment in the x
+                                                ! direction
+REAL, INTENT(IN) :: PDYHATM                     ! mean grid increment in the y
+                                                ! direction
+!
+REAL, DIMENSION (:), INTENT(IN) :: PRHOM         !  mean of XRHODJ on the plane x y 
+                                                 !  localized at a mass level
+!
+REAL, DIMENSION(:), INTENT(IN)     :: PAF,PCF    ! vectors giving the nonvanishing
+REAL, DIMENSION(:,:,:), INTENT(IN) :: PBF        ! elements of the tri-diag. 
+                                                 ! matrix in the pressure eq.
+!
+                                                 ! arrays of sin or cos values
+                                                 ! for the FFT :
+REAL, DIMENSION(:), INTENT(IN) :: PTRIGSX        ! - along x
+REAL, DIMENSION(:), INTENT(IN) :: PTRIGSY        ! - along y
+!
+                                                 ! decomposition in prime 
+                                                 ! numbers for the FFT:
+INTEGER, DIMENSION(19), INTENT(IN) :: KIFAXX      ! - along x
+INTEGER, DIMENSION(19), INTENT(IN) :: KIFAXY      ! - along y
+!
+REAL, DIMENSION(:,:,:), INTENT(IN) :: PY         ! RHS of the equation
+!                                                         
+REAL, DIMENSION(:,:,:), INTENT(OUT):: PF_1_Y     ! solution of the equation
+!
+!*       0.2   declaration of local variables
+!
+REAL, DIMENSION(SIZE(PY,1),SIZE(PY,2),SIZE(PY,3)) :: ZY ! work array to store 
+                                                    ! the RHS of the equation
+!
+!REAL, DIMENSION(SIZE(PY,1),SIZE(PY,2),SIZE(PY,3)) :: ZWORK ! work array used by 
+! the FFT. It has been enlarged in order to be sufficient for 2D and 3D cases
+!
+REAL, DIMENSION(SIZE(PBF,1),SIZE(PBF,2),SIZE(PBF,3)) :: ZAF ! work array to
+!                                                        ! expand PAF
+INTEGER :: IIB          ! indice I for the first inner mass point along x
+INTEGER :: IIE          ! indice I for the last inner mass point along x
+INTEGER :: IIMAX        ! number of inner mass points along the x direction
+INTEGER :: IJB          ! indice J for the first inner mass point along y
+INTEGER :: IJE          ! indice J for the last inner mass point along y
+INTEGER :: IJMAX        ! number of inner mass points along the y direction
+INTEGER :: IKB          ! indice K for the first inner mass point along z
+INTEGER :: IKE          ! indice K for the last inner mass point along z
+INTEGER :: IKU          ! size of the arrays along z
+INTEGER :: IKMAX        ! number of inner mass points along the z direction
+!
+REAL :: ZDXM2,ZDYM2     ! respectively equal to PDXHATM*PDXHATM 
+                        ! and PDYHATM*PDYHATM                         
+INTEGER :: JI,JJ,JK     ! loop indexes along x, y, z respectively
+!
+!
+INTEGER :: IIE_INT,IJE_INT   ! highest indice I  and J values for the x y modes.
+                             ! They  depend on the l.b.c. !
+!
+INTEGER :: ILOTX,ILOTY ! number of data vectors along x, y resp. computed 
+                       ! in parallel during the FFT process 
+!
+INTEGER :: INC1X,INC1Y ! increment within each data vector for the FFT along
+                       ! x, y resp.
+!
+INTEGER :: INC2X,INC2Y ! increment between the start of one data vector and 
+                       ! the next for the FFT along x,y resp.
+!
+!
+REAL, DIMENSION(:,:,:), ALLOCATABLE :: ZWORKX ! work array used by
+! the FFT. It has been enlarged in order to be sufficient for 2D and 3D cases
+REAL, DIMENSION(:,:,:), ALLOCATABLE :: ZWORKY ! work array used by
+! the FFT. It has been enlarged in order to be sufficient for 2D and 3D cases
+!
+REAL, DIMENSION(:,:,:), ALLOCATABLE :: ZGAM
+                                                        ! intermediate arrays
+REAL, DIMENSION(:,:), ALLOCATABLE   :: ZBETX            ! for the tridiag.
+                                                        ! matrix inversion
+REAL, DIMENSION(:,:,:), ALLOCATABLE :: ZBAND_X  ! array in X slices distribution
+REAL, DIMENSION(:,:,:), ALLOCATABLE :: ZBAND_Y  ! array in Y slices distribution
+REAL, DIMENSION(:,:,:), ALLOCATABLE :: ZBAND_YR ! array in Y slices distribution
+!
+INTEGER :: IINFO_ll           ! return code of parallel routine
+!
+INTEGER :: IIX,IJX,IIY,IJY ! dimensions of the extended x or y slices subdomain
+!
+REAL, DIMENSION(:,:,:), ALLOCATABLE :: ZBAND_YT  ! array in Y slices distribution transpose
+REAL, DIMENSION(:,:,:), ALLOCATABLE :: ZBAND_YRT ! array in Y slices distribution transpose
+!-------------------------------------------------------------------------------
+!
+!*       1.    COMPUTE LOOP BOUNDS
+!              -------------------
+!
+CALL GET_PHYSICAL_ll(IIB,IJB,IIE,IJE)
+CALL GET_DIM_EXT_ll('X',IIX,IJX)
+CALL GET_DIM_EXT_ll('Y',IIY,IJY)
+IIMAX = IIX-2*JPHEXT
+IJMAX = IJY-2*JPHEXT
+!
+IKU=SIZE(PY,3)
+IKB=1+JPVEXT
+IKE=IKU - JPVEXT
+IKMAX=IKE-IKB+1
+!
+!!
+ALLOCATE(ZBAND_X(IIX,IJX,IKU))
+ALLOCATE(ZBAND_Y(IIY,IJY,IKU))
+ALLOCATE(ZBAND_YR(IIY,IJY,IKU))
+ALLOCATE(ZWORKX(IIX,IJX,IKU))
+ALLOCATE(ZWORKY(IIY,IJY,IKU))
+ALLOCATE(ZBETX(IIY,IJY))
+ALLOCATE(ZGAM(IIY,IJY,IKU))
+IF (.NOT. L2D) THEN
+  ALLOCATE(ZBAND_YT(IJY,IIY,IKU))
+  ALLOCATE(ZBAND_YRT(IJY,IIY,IKU))
+END IF
+!
+!-------------------------------------------------------------------------------
+!
+!*       2.    COMPUTE THE ARRAY INCREMENTS FOR THE FFT
+!              ----------------------------------------
+!
+IF(.NOT. L2D) THEN
+!
+  ILOTX = IJX*IKU
+  INC1X = 1
+  INC2X = IIX
+!
+  ILOTY = IIY*IKU
+  INC1Y = 1
+  INC2Y = IJY
+!
+ELSE
+!
+  ILOTX = IKU
+  INC1X = 1
+  INC2X = IIX*IJX
+ENDIF
+!
+!-------------------------------------------------------------------------------
+!
+!*      3.    FORM HOMOGENEOUS BOUNDARY CONDITIONS FOR A NONCYCLIC CASE
+!             ---------------------------------------------------------
+!
+!
+!*      3.1 copy the RHS in a local array REMAP functions will shift the indices for the FFT
+!
+PF_1_Y = 0.
+ZY = PY
+!
+!*      3.2 form homogeneous boundary condition used by the FFT for non-periodic
+!           cases
+!
+!  modify the RHS in the x direction
+!
+IF (HLBCX(1) /= 'CYCL') THEN
+!
+  IF (LWEST_ll(HSPLITTING='B')) THEN
+    DO JK=IKB,IKE                    
+      DO JJ = IJB, IJE
+        ZY(IIB,JJ,JK)     = ZY(IIB,JJ,JK)     + PY(IIB-1,JJ,JK)
+      END DO
+    END DO
+  END IF
+!
+  IF (LEAST_ll(HSPLITTING='B')) THEN
+    DO JK=IKB,IKE
+      DO JJ = IJB, IJE
+        ZY(IIE,JJ,JK)     = ZY(IIE,JJ,JK)     - PY(IIE+1,JJ,JK)
+      END DO
+    END DO
+  END IF
+END IF
+!
+! modify the RHS in the same way along y
+!
+IF (HLBCY(1) /= 'CYCL'.AND. (.NOT. L2D)) THEN
+  IF (LSOUTH_ll(HSPLITTING='B')) THEN
+    DO JK=IKB,IKE
+      DO JI = IIB, IIE
+        ZY(JI,IJB,JK)     = ZY(JI,IJB,JK)     + PY(JI,IJB-1,JK)
+      END DO
+    END DO
+  END IF
+!
+  IF (LNORTH_ll(HSPLITTING='B')) THEN
+    DO JK=IKB,IKE
+      DO JI = IIB, IIE
+        ZY(JI,IJE,JK)     = ZY(JI,IJE,JK)     - PY(JI,IJE+1,JK)
+      END DO
+    END DO
+  END IF
+END IF
+!
+!
+!*      3.3 2way structure -> xslice structure, + data shift
+!
+ZBAND_X=0.
+CALL REMAP_2WAY_X_ll(ZY,ZBAND_X,IINFO_ll)
+!
+!  
+!-------------------------------------------------------------------------------
+!
+!*      4.    APPLY A REAL TO COMPLEX FFT
+!             ---------------------------
+!
+!
+IF (HLBCX(1) == 'CYCL') THEN
+  CALL FFT991(ZBAND_X(1,1,IKB-1),ZWORKX,PTRIGSX,KIFAXX,INC1X,INC2X,  &
+              IIMAX,ILOTX,-1 )
+ELSE
+  CALL FFT55(ZBAND_X(1,1,IKB-1),ZWORKX,PTRIGSX,KIFAXX,INC1X,INC2X,  &
+             IIMAX,ILOTX,-1 )
+END IF  
+!
+!
+ZBAND_Y=0.
+CALL REMAP_X_Y_ll(ZBAND_X,ZBAND_Y,IINFO_ll)
+!
+IF (.NOT. L2D) THEN                                 
+!
+! array transposition I --> J
+!
+  CALL FAST_TRANSPOSE(ZBAND_Y,ZBAND_YT,IIY,IJY,IKU)
+!
+  IF (HLBCY(1) == 'CYCL') THEN
+      CALL FFT991(ZBAND_YT(1,1,IKB-1),ZWORKY,PTRIGSY,KIFAXY,INC1Y,INC2Y,  &
+                  IJMAX,ILOTY,-1 )
+  ELSE
+      CALL FFT55(ZBAND_YT(1,1,IKB-1),ZWORKY,PTRIGSY,KIFAXY,INC1Y,INC2Y,  &
+                  IJMAX,ILOTY,-1 )
+  END IF 
+!
+END IF                                        
+!
+!       singular matrix case : the last term is computed by setting the 
+!       average of the pressure field equal to zero.
+IF (LWEST_ll(HSPLITTING='Y')) THEN
+  IF (L2D) THEN
+    ZBAND_Y(1,1,IKE+1)=0
+  ELSE
+    ZBAND_YT(1,1,IKE+1)=0.
+  END IF
+END IF
+!
+!-------------------------------------------------------------------------------
+!
+!*      5.    MATRIX INVERSION FOR THE FLAT OPERATOR
+!             --------------------------------------
+!
+CALL FAST_SPREAD(PAF,ZAF,IIY,IJY,IKU)
+!
+IF (LWEST_ll(HSPLITTING='Y')) THEN
+   ZAF(1,1,IKE+1)=0. !singular matrix corresponding to the horizontal average
+END IF
+!
+IF (L2D) THEN
+  CALL FAST_SUBSTITUTION_2D(ZBAND_YR,ZBETX,PBF,ZGAM,PCF,ZAF &
+                           ,ZBAND_Y,IIY,IJY,IKU)
+ELSE
+  CALL FAST_SUBSTITUTION_3D(ZBAND_YRT,ZBETX,PBF,ZGAM,PCF,ZAF &
+                      ,ZBAND_YT,IIY,IJY,IKU)
+END IF
+!  
+!
+!-------------------------------------------------------------------------------
+!
+!*      6.    APPLY A COMPLEX TO REAL FFT
+!             ---------------------------
+!
+!  
+IF (.NOT. L2D) THEN
+  IF (HLBCY(1) == 'CYCL') THEN
+    CALL FFT991( ZBAND_YRT(1,1,IKB-1),ZWORKY,PTRIGSY,KIFAXY,INC1Y,INC2Y,  &
+                  IJMAX,ILOTY,+1 )
+  ELSE
+      CALL FFT55( ZBAND_YRT(1,1,IKB-1),ZWORKY,PTRIGSY,KIFAXY,INC1Y,INC2Y,  &
+                  IJMAX,ILOTY,+1 )
+  END IF 
+  ! array transposition J --> I
+  CALL FAST_TRANSPOSE(ZBAND_YRT,ZBAND_YR,IJY,IIY,IKU)
+ENDIF
+!
+! Transposition Y-> X
+!
+ZBAND_X=0.
+CALL REMAP_Y_X_ll(ZBAND_YR,ZBAND_X,IINFO_ll)
+!
+!
+IF (HLBCX(1) == 'CYCL') THEN
+    CALL FFT991( ZBAND_X(1,1,IKB-1),ZWORKX,PTRIGSX,KIFAXX,INC1X,INC2X,  &
+                IIMAX,ILOTX,+1 )
+ELSE
+    CALL FFT55( ZBAND_X(1,1,IKB-1),ZWORKX,PTRIGSX,KIFAXX,INC1X,INC2X,  &
+                IIMAX,ILOTX,+1 )
+END IF  
+!
+!-------------------------------------------------------------------------------
+!
+!*      7.    RETURN TO A NON HOMOGENEOUS NEUMAN CONDITION FOR NON-CYCLIC CASES
+!             -----------------------------------------------------------------
+!
+!*      7.1   Transposition + shift X -> 2way
+!
+CALL REMAP_X_2WAY_ll(ZBAND_X,PF_1_Y,IINFO_ll)
+!
+!*      7.2 complete the lateral boundaries
+!
+IF (HLBCX(1) /= 'CYCL') THEN
+!
+!*      7.2.1 return to a non-homogeneous case in the x direction
+! 
+  ZDXM2 = PDXHATM*PDXHATM
+!
+  IF (LWEST_ll(HSPLITTING='B')) THEN
+    DO JK=IKB,IKE
+      DO JJ = IJB,IJE
+        PF_1_Y(IIB-1,JJ,JK) = PF_1_Y(IIB,JJ,JK) - PY(IIB-1,JJ,JK)*ZDXM2/PRHOM(JK)
+      END DO
+    END DO
+  END IF
+!
+  IF (LEAST_ll(HSPLITTING='B')) THEN
+    DO JK=IKB,IKE
+      DO JJ = IJB,IJE
+        PF_1_Y(IIE+1,JJ,JK) = PF_1_Y(IIE,JJ,JK) + PY(IIE+1,JJ,JK)*ZDXM2/PRHOM(JK)
+      END DO
+    END DO
+  END IF
+!
+!    we set the solution at the corner point by the condition:
+!    dxm ( P ) = 0
+  IF (LWEST_ll(HSPLITTING='B')) THEN
+    DO JJ = IJB,IJE
+      PF_1_Y(IIB-1,JJ,IKB-1) = PF_1_Y(IIB,JJ,IKB-1) 
+      PF_1_Y(IIB-1,JJ,IKE+1) = PF_1_Y(IIB,JJ,IKE+1)
+    END DO
+  END IF
+  IF (LEAST_ll(HSPLITTING='B')) THEN
+    DO JJ = IJB,IJE
+      PF_1_Y(IIE+1,JJ,IKB-1) = PF_1_Y(IIE,JJ,IKB-1)
+      PF_1_Y(IIE+1,JJ,IKE+1) = PF_1_Y(IIE,JJ,IKE+1)
+    END DO
+  END IF
+!
+ELSE
+!
+!*      7.2.2 periodize the pressure function field along the x direction
+!
+! in fact this part is useless because it is done in the routine
+! REMAP_X_2WAY.
+!
+END IF
+!
+IF (.NOT.L2D) THEN
+  IF (HLBCY(1) /= 'CYCL') THEN
+!
+!*      7.2.3 return to a non-homogeneous case in the y direction
+!
+    ZDYM2 = PDYHATM*PDYHATM 
+!
+    IF (LSOUTH_ll(HSPLITTING='B')) THEN
+      DO JK=IKB,IKE
+        DO JI = IIB,IIE
+          PF_1_Y(JI,IJB-1,JK) = PF_1_Y(JI,IJB,JK) - PY(JI,IJB-1,JK)*ZDYM2/PRHOM(JK)
+        END DO
+      END DO
+    END IF
+!
+    IF (LNORTH_ll(HSPLITTING='B')) THEN
+      DO JK=IKB,IKE
+        DO JI = IIB,IIE
+          PF_1_Y(JI,IJE+1,JK) = PF_1_Y(JI,IJE,JK) + PY(JI,IJE+1,JK)*ZDYM2/PRHOM(JK)
+        END DO
+      END DO
+    END IF
+!    we set the solution at the corner point by the condition:
+!    dym ( P )  = 0
+!
+    IF (LSOUTH_ll(HSPLITTING='B')) THEN
+      DO JI = IIB,IIE
+        PF_1_Y(JI,IJB-1,IKB-1) = PF_1_Y(JI,IJB,IKB-1)
+        PF_1_Y(JI,IJB-1,IKE+1) = PF_1_Y(JI,IJB,IKE+1)
+      END DO
+    END IF
+!
+    IF (LNORTH_ll(HSPLITTING='B')) THEN
+      DO JI = IIB,IIE
+        PF_1_Y(JI,IJE+1,IKB-1) = PF_1_Y(JI,IJE,IKB-1)
+        PF_1_Y(JI,IJE+1,IKE+1) = PF_1_Y(JI,IJE,IKE+1)
+      END DO
+    END IF
+  ELSE
+!
+!*      7.2.4 periodize the pressure function field along the y direction
+!
+!
+! in fact this part is useless because it is done in the routine
+! REMAP_X_2WAY.
+!
+  END IF
+!
+END IF
+!
+IF (.NOT. L2D .AND. HLBCX(1)/='CYCL' .AND. HLBCY(1)/='CYCL') THEN
+! the following verticals are not used
+  IF ( (LWEST_ll(HSPLITTING='B')).AND.(LSOUTH_ll(HSPLITTING='B')) ) THEN
+    PF_1_Y(IIB-1,IJB-1,:)=PF_1_Y(IIB,IJB,:)
+  END IF
+!
+  IF ( (LWEST_ll(HSPLITTING='B')).AND.(LNORTH_ll(HSPLITTING='B')) ) THEN
+    PF_1_Y(IIB-1,IJE+1,:)=PF_1_Y(IIB,IJE,:)
+  END IF
+!
+  IF ( (LEAST_ll(HSPLITTING='B')).AND.(LSOUTH_ll(HSPLITTING='B')) ) THEN
+    PF_1_Y(IIE+1,IJB-1,:)=PF_1_Y(IIE,IJB,:)
+  END IF
+!
+  IF ( (LEAST_ll(HSPLITTING='B')).AND.(LNORTH_ll(HSPLITTING='B')) ) THEN
+    PF_1_Y(IIE+1,IJE+1,:)=PF_1_Y(IIE,IJE,:)
+  END IF
+END IF
+!
+DEALLOCATE(ZBAND_X)
+DEALLOCATE(ZBAND_Y)
+IF (.NOT. L2D) THEN
+  DEALLOCATE(ZBAND_YT)
+  DEALLOCATE(ZBAND_YRT)
+END IF
+DEALLOCATE(ZBAND_YR)
+DEALLOCATE(ZWORKX)
+DEALLOCATE(ZWORKY)
+DEALLOCATE(ZBETX)
+DEALLOCATE(ZGAM)
+!
+!-------------------------------------------------------------------------------
+!
+CONTAINS
+  SUBROUTINE FAST_TRANSPOSE(PX,PXT,KNI,KNJ,KNK)
+    INTEGER                      :: KNI,KNJ,KNK ! 3D dimension of X and XT
+    REAL, DIMENSION(KNI*KNJ,KNK) :: PX
+    REAL, DIMENSION(KNJ*KNI,KNK) :: PXT
+    !
+    INTEGER                      :: IJI,II,IJ,IIJ ! index in array X and XT
+    INTEGER                      :: JK
+!
+    DO JK=1,KNK
+       ! PERMUTATION(PX,PXT)
+       !CDIR NODEP
+       !OCL NOVREC
+       DO IJI = 1, KNJ*KNI
+          ! I,J Indice in XT array from linearised index IJI
+          II   = 1 +    (IJI-1)/KNJ
+          IJ   = IJI - (II-1)*KNJ 
+          ! linearised index in X
+          IIJ = II + (IJ-1)*KNI 
+          ! transposition
+          PXT(IJI,JK) = PX(IIJ,JK)
+       
+       END DO
+    END DO
+!    
+END SUBROUTINE FAST_TRANSPOSE
+
+SUBROUTINE FAST_SUBSTITUTION_3D(PBAND_YR,PBETX,PPBF,PGAM,PPCF,PAF &
+                            ,PBAND_Y,KIY,KJY,KKU)
+INTEGER                        :: KIY,KJY,KKU
+REAL, DIMENSION (KIY*KJY,KKU)  :: PBAND_YR,PBAND_Y,PPBF,PGAM,PAF
+REAL, DIMENSION (KIY*KJY)      :: PBETX
+REAL, DIMENSION (KKU)          :: PPCF
+INTEGER                        :: JK
+!
+!
+!       initialization 
+!
+!
+PBAND_YR = 0.0
+PBETX(:) = PPBF(:,IKB-1)
+PBAND_YR(:,IKB-1) = PBAND_Y(:,IKB-1)  &
+                                      / PBETX(:)
+!
+!        decomposition and forward substitution
+!
+DO JK = IKB,IKE+1
+  PGAM(:,JK) = PPCF(JK-1) / PBETX(:)
+!
+  PBETX(:) = PPBF(:,JK) -              &      
+                 PAF(:,JK)*PGAM(:,JK)
+!
+  PBAND_YR(:,JK) = ( PBAND_Y(:,JK) -  &
+       PAF(:,JK)*PBAND_YR(:,JK- 1) )  &
+                                /PBETX(:)
+!
+END DO
+!
+!       backsubstitution
+!
+DO JK = IKE,IKB-1,-1
+  PBAND_YR(:,JK) = PBAND_YR(:,JK) -    &
+          PGAM(:,JK+1)*PBAND_YR(:,JK+1)
+END DO
+!  
+!
+END SUBROUTINE FAST_SUBSTITUTION_3D
+!
+SUBROUTINE FAST_SUBSTITUTION_2D(PBAND_YR,PBETX,PPBF,PGAM,PPCF,PAF &
+                            ,PBAND_Y,KIY,KJY,KKU)
+INTEGER                        :: KIY,KJY,KKU
+REAL, DIMENSION (KIY,KJY,KKU)  :: PBAND_YR,PBAND_Y,PPBF,PGAM,PAF
+REAL, DIMENSION (KIY,KJY)      :: PBETX
+REAL, DIMENSION (KKU)          :: PPCF
+INTEGER                        :: JK
+!
+!
+!       initialization 
+!
+!
+PBAND_YR = 0.0
+PBETX(:,1) = PPBF(:,1,IKB-1)
+PBAND_YR(:,1,IKB-1) = PBAND_Y(:,1,IKB-1)  &
+                                     / PBETX(:,1)
+!
+!        decomposition and forward substitution
+!
+DO JK = IKB,IKE+1
+  PGAM(:,1,JK) = PPCF(JK-1) / PBETX(:,1)
+!
+  PBETX(:,1) = PPBF(:,1,JK) -              &      
+                 PAF(:,1,JK)*PGAM(:,1,JK)
+!
+  PBAND_YR(:,1,JK) = ( PBAND_Y(:,1,JK) -  &
+       PAF(:,1,JK)*PBAND_YR(:,1,JK- 1) )  &
+                                /PBETX(:,1)
+!
+END DO
+!
+!       backsubstitution
+!
+DO JK = IKE,IKB-1,-1
+  PBAND_YR(:,1,JK) = PBAND_YR(:,1,JK) -    &
+          PGAM(:,1,JK+1)*PBAND_YR(:,1,JK+1)
+END DO
+!  
+!
+END SUBROUTINE FAST_SUBSTITUTION_2D
+
+SUBROUTINE FAST_SPREAD(PTAB1D,PTAB3D,KIY,KJY,KKU)
+INTEGER                        :: KIY,KJY,KKU
+REAL, DIMENSION (KKU)          :: PTAB1D
+REAL, DIMENSION (KIY*KJY,KKU)  :: PTAB3D
+
+INTEGER                        :: JIJ,JK
+!
+DO JK=1,KKU
+   DO JIJ=1,KIY*KJY
+      PTAB3D(JIJ,JK) = PTAB1D(JK)
+   ENDDO
+ENDDO
+!
+END SUBROUTINE FAST_SPREAD
+!
+!------------------------------------------------------------------------------  
+END SUBROUTINE FLAT_INV
diff --git a/src/ZSOLVER/ini_dynamics.f90 b/src/ZSOLVER/ini_dynamics.f90
new file mode 100644
index 0000000000000000000000000000000000000000..40aa0eb77eb2b9006ff0fba76d8f24366581a555
--- /dev/null
+++ b/src/ZSOLVER/ini_dynamics.f90
@@ -0,0 +1,640 @@
+!MNH_LIC Copyright 1994-2018 CNRS, Meteo-France and Universite Paul Sabatier
+!MNH_LIC This is part of the Meso-NH software governed by the CeCILL-C licence
+!MNH_LIC version 1. See LICENSE, CeCILL-C_V1-en.txt and CeCILL-C_V1-fr.txt  
+!MNH_LIC for details. version 1.
+!-----------------------------------------------------------------
+!     ########################
+      MODULE MODI_INI_DYNAMICS
+!     ########################
+INTERFACE
+SUBROUTINE INI_DYNAMICS(PLON,PLAT,PRHODJ,PTHVREF,PMAP,PZZ,                   &
+               PDXHAT,PDYHAT,PZHAT,HLBCX,HLBCY,PTSTEP,HPRESOPT,              &
+               OVE_RELAX,OVE_RELAX_GRD,OHORELAX_UVWTH,OHORELAX_RV,           &
+               OHORELAX_RC,OHORELAX_RR,OHORELAX_RI,OHORELAX_RS,OHORELAX_RG,  &
+               OHORELAX_RH,OHORELAX_TKE,OHORELAX_SV,                         &
+               OHORELAX_SVC2R2,OHORELAX_SVC1R3,OHORELAX_SVELEC,OHORELAX_SVLG,&
+               OHORELAX_SVCHEM,OHORELAX_SVAER,OHORELAX_SVDST,OHORELAX_SVSLT, &
+               OHORELAX_SVPP,OHORELAX_SVCS,  OHORELAX_SVCHIC,OHORELAX_SVSNW, &
+#ifdef MNH_FOREFIRE
+               OHORELAX_SVFF,                                                &
+#endif
+               PRIMKMAX,KRIMX,KRIMY,PALKTOP,PALKGRD,PALZBOT,PALZBAS,         &
+               PT4DIFU,PT4DIFTH,PT4DIFSV,                                    &
+               PCORIOX,PCORIOY,PCORIOZ,PCURVX,PCURVY,                        &
+               PDXHATM,PDYHATM,PRHOM,PAF,PBFY,PCF,                           &
+               PTRIGSX,PTRIGSY,KIFAXX,KIFAXY,                                &
+               PALK,PALKW,KALBOT,PALKBAS,PALKWBAS,KALBAS,                    &
+               OMASK_RELAX,PKURELAX, PKVRELAX, PKWRELAX,                     &
+               PDK2U,PDK4U,PDK2TH,PDK4TH,PDK2SV,PDK4SV,OZDIFFU,PZDIFFU_HALO2,& 
+               PBFB,                                                         &
+               PBF_SXP2_YP1_Z,                                               &
+               PAF_ZS,PBF_ZS,PCF_ZS,                                         &
+               PDXATH_ZS,PDYATH_ZS,PRHO_ZS,                                  &
+               A_K,B_K,C_K,D_K) !JUAN FULL ZSOLVER
+!  intent in arguments
+!
+USE MODE_TYPE_ZDIFFU
+IMPLICIT NONE
+!
+REAL, DIMENSION(:,:),   INTENT(IN)        :: PLON,PLAT !Longitude and latitude
+REAL, DIMENSION(:,:,:), INTENT(IN)        :: PRHODJ    ! rho J
+REAL, DIMENSION(:,:,:), INTENT(IN)        :: PTHVREF   ! virtual potential 
+                                      ! temperature of the reference state
+REAL, DIMENSION(:,:),   INTENT(IN)        :: PMAP      ! Map factor
+REAL, DIMENSION(:,:,:), INTENT(IN)        :: PZZ       ! height 
+REAL, DIMENSION(:),     INTENT(IN)        :: PDXHAT     ! Stretching in x direction
+REAL, DIMENSION(:),     INTENT(IN)        :: PDYHAT     ! Stretching in y direction
+REAL, DIMENSION(:),     INTENT(IN)        :: PZHAT     ! Gal-Chen Height   
+CHARACTER(LEN=4), DIMENSION(:), INTENT(IN) :: HLBCX    ! x-direction LBC type
+CHARACTER(LEN=4), DIMENSION(:), INTENT(IN) :: HLBCY    ! y-direction LBC type
+LOGICAL,                INTENT(IN)        :: OVE_RELAX ! logical
+             ! switch to activate the VErtical  RELAXation
+LOGICAL,                INTENT(IN)        :: OVE_RELAX_GRD ! logical
+             ! switch to activate the VErtical  RELAXation (ground layer)
+LOGICAL,            INTENT(IN) :: OHORELAX_UVWTH  ! switch for the 
+                       ! horizontal relaxation for U,V,W,TH
+LOGICAL,            INTENT(IN) :: OHORELAX_RV     ! switch for the 
+                       ! horizontal relaxation for Rv
+LOGICAL,            INTENT(IN) :: OHORELAX_RC     ! switch for the 
+                       ! horizontal relaxation for Rc
+LOGICAL,            INTENT(IN) :: OHORELAX_RR     ! switch for the 
+                       ! horizontal relaxation for Rr
+LOGICAL,            INTENT(IN) :: OHORELAX_RI     ! switch for the 
+                       ! horizontal relaxation for Ri
+LOGICAL,            INTENT(IN) :: OHORELAX_RS     ! switch for the 
+                       ! horizontal relaxation for Rs
+LOGICAL,            INTENT(IN) :: OHORELAX_RG     ! switch for the 
+                       ! horizontal relaxation for Rg
+LOGICAL,            INTENT(IN) :: OHORELAX_RH     ! switch for the 
+                       ! horizontal relaxation for Rh
+LOGICAL,            INTENT(IN) :: OHORELAX_TKE    ! switch for the 
+                       ! horizontal relaxation for tke
+LOGICAL,DIMENSION(:),INTENT(IN):: OHORELAX_SV     ! switch for the 
+                       ! horizontal relaxation for sv variables
+LOGICAL,             INTENT(IN):: OHORELAX_SVC2R2 ! switch for the 
+                       ! horizontal relaxation for c2r2 variables
+LOGICAL,             INTENT(IN):: OHORELAX_SVC1R3 ! switch for the 
+                       ! horizontal relaxation for c1r3 variables
+LOGICAL,             INTENT(IN):: OHORELAX_SVELEC ! switch for the 
+                       ! horizontal relaxation for elec variables
+LOGICAL,             INTENT(IN):: OHORELAX_SVLG   ! switch for the 
+                       ! horizontal relaxation for lg variables
+LOGICAL,             INTENT(IN):: OHORELAX_SVCHEM ! switch for the 
+                       ! horizontal relaxation for chem variables
+LOGICAL,             INTENT(IN):: OHORELAX_SVCHIC ! switch for the 
+                       ! horizontal relaxation for ice chem variables
+LOGICAL,             INTENT(IN):: OHORELAX_SVAER  ! switch for the 
+                       ! horizontal relaxation for aer variables
+LOGICAL,             INTENT(IN):: OHORELAX_SVDST  ! switch for the 
+                       ! horizontal relaxation for dst variables
+LOGICAL,             INTENT(IN):: OHORELAX_SVSLT  ! switch for the 
+                       ! horizontal relaxation for slt variables
+LOGICAL,             INTENT(IN):: OHORELAX_SVPP   ! switch for the 
+                       ! horizontal relaxation for passive pollutants
+LOGICAL,             INTENT(IN):: OHORELAX_SVSNW   ! switch for the
+                       ! horizontal relaxation for blowing snow variables    
+#ifdef MNH_FOREFIRE
+LOGICAL,             INTENT(IN):: OHORELAX_SVFF   ! switch for the 
+                       ! horizontal relaxation for ForeFire variables
+#endif
+LOGICAL,             INTENT(IN):: OHORELAX_SVCS   ! switch for the 
+                       ! horizontal relaxation for conditional sampling
+REAL,                    INTENT(IN)    :: PRIMKMAX !Max. value of the horiz.
+                                     ! relaxation coefficients
+INTEGER,                INTENT(IN)     :: KRIMX,KRIMY ! Number of points in 
+                                     ! the rim zone in the x and y directions 
+REAL,     INTENT(IN)   :: PALKTOP    ! Damping coef. at the top of the absorbing
+                                     ! layer
+REAL,     INTENT(IN)   :: PALKGRD    ! Damping coef. at the top of the absorbing
+                                     ! layer                                    
+REAL,     INTENT(IN)   :: PALZBOT    ! Height of the absorbing layer base
+REAL,     INTENT(IN)   :: PALZBAS    ! Height of the absorbing layer base
+REAL,     INTENT(IN)   :: PT4DIFU    ! Damping time scale for 2*dx wavelength
+                                     ! specified for the 4nd order num. diffusion
+                                     ! for momentum
+REAL,     INTENT(IN)   :: PT4DIFTH   ! for meteorological scalar variables
+REAL,     INTENT(IN)   :: PT4DIFSV   ! for tracer scalar variables
+
+REAL,     INTENT(IN)   :: PTSTEP     ! Time step
+CHARACTER (LEN=5), INTENT(IN) :: HPRESOPT        ! choice of the pressure solver
+!
+!  intent out arguments
+!
+REAL, INTENT(OUT) :: PDXHATM                     ! mean grid increment in the x
+                                                 ! direction
+REAL, INTENT(OUT) :: PDYHATM                     ! mean grid increment in the y
+                                                 ! direction
+!
+REAL, DIMENSION (:), INTENT(OUT) :: PRHOM        !  mean of XRHODJ on the plane x y 
+                                                 !  localized at a mass level
+!
+REAL, DIMENSION(:,:), INTENT(OUT) :: PCORIOX,PCORIOY ! Hor. Coriolis parameters
+REAL, DIMENSION(:,:), INTENT(OUT) :: PCORIOZ         ! Vert. Coriolis parameter 
+REAL, DIMENSION(:,:), INTENT(OUT) :: PCURVX,PCURVY   ! Curvature coefficients
+! 
+REAL, DIMENSION(:),     INTENT(OUT) :: PAF ! vectors giving the non-vanishing        
+REAL, DIMENSION(:,:,:), INTENT(OUT) :: PBFY ! elements of the tri-diag matrix        
+                                            ! on an y-slice of global physical domain
+REAL, DIMENSION(:),     INTENT(OUT) :: PCF ! in the pressure equation
+REAL, DIMENSION(:),     INTENT(OUT) :: PTRIGSX ! Arrays for sinus or cosinus 
+REAL, DIMENSION(:),     INTENT(OUT) :: PTRIGSY ! values for the FFT in x and
+                                               ! y directions
+INTEGER, DIMENSION(:),  INTENT(OUT) :: KIFAXX  ! Decomposition in prime numbers
+INTEGER, DIMENSION(:),  INTENT(OUT) :: KIFAXY  ! for the FFT in x and y
+                                               ! direction      
+INTEGER          ,  INTENT(OUT)  :: KALBOT     ! Vertical index corresponding
+                                               ! to the absorbing layer base
+!  
+REAL, DIMENSION(:),   INTENT(OUT) :: PALK  ! Function of the absorbing
+                                           ! layer damping coefficient
+                                           ! defined for  u,v,and theta
+REAL, DIMENSION(:),   INTENT(OUT) :: PALKW ! Idem but defined for w    
+INTEGER          ,  INTENT(OUT)  :: KALBAS     ! Vertical index corresponding
+                                               ! to the absorbing layer base
+!  
+REAL, DIMENSION(:),   INTENT(OUT) :: PALKBAS  ! Function of the absorbing
+                                           ! layer damping coefficient
+                                           ! defined for  u,v,and theta
+REAL, DIMENSION(:),   INTENT(OUT) :: PALKWBAS ! Idem but defined for w
+LOGICAL, DIMENSION(:,:),  INTENT(OUT)   :: OMASK_RELAX  ! True where the 
+                                           ! lateral relax. has to be performed
+REAL, DIMENSION(:,:),     INTENT(OUT)   :: PKURELAX  !  Horizontal relaxation
+REAL, DIMENSION(:,:),     INTENT(OUT)   :: PKVRELAX  !  coefficients for the
+REAL, DIMENSION(:,:),     INTENT(OUT)   :: PKWRELAX  ! u, v and mass locations
+REAL,                 INTENT(OUT) :: PDK2U ! 2nd order num. diffusion coef. /dx2
+REAL,                 INTENT(OUT) :: PDK4U ! 4nd order num. diffusion coef. /dx4
+                                           ! for momentum
+REAL,                 INTENT(OUT) :: PDK2TH! for meteorological scalar variables
+REAL,                 INTENT(OUT) :: PDK4TH! 
+REAL,                 INTENT(OUT) :: PDK2SV! for tracer scalar variables
+REAL,                 INTENT(OUT) :: PDK4SV! 
+!
+LOGICAL, INTENT(IN) :: OZDIFFU
+TYPE(TYPE_ZDIFFU_HALO2)                       :: PZDIFFU_HALO2
+!
+REAL, DIMENSION(:,:,:), INTENT(OUT) :: PBFB ! elements of the tri-diag matrix
+                                            ! on an b-slice of global physical domain
+REAL, DIMENSION(:,:,:), INTENT(OUT) :: PBF_SXP2_YP1_Z ! elements of the tri-diag. SXP2_YP1_Z-slide 
+                                                   ! matrix in the pressure eq.
+REAL, DIMENSION(:,:,:), INTENT(OUT) :: PAF_ZS,PBF_ZS,PCF_ZS
+REAL, DIMENSION(:,:)  , INTENT(OUT) :: PDXATH_ZS,PDYATH_ZS
+REAL, DIMENSION(:,:,:), INTENT(OUT) :: PRHO_ZS
+REAL, DIMENSION(:)    , INTENT(OUT) :: A_K,B_K,C_K,D_K
+
+END SUBROUTINE INI_DYNAMICS
+!
+END INTERFACE
+!
+END MODULE MODI_INI_DYNAMICS
+!     ######################################################################
+SUBROUTINE INI_DYNAMICS(PLON,PLAT,PRHODJ,PTHVREF,PMAP,PZZ,                   &
+               PDXHAT,PDYHAT,PZHAT,HLBCX,HLBCY,PTSTEP,HPRESOPT,              &
+               OVE_RELAX,OVE_RELAX_GRD,OHORELAX_UVWTH,OHORELAX_RV,           &
+               OHORELAX_RC,OHORELAX_RR,OHORELAX_RI,OHORELAX_RS,OHORELAX_RG,  &
+               OHORELAX_RH,OHORELAX_TKE,OHORELAX_SV,                         &
+               OHORELAX_SVC2R2,OHORELAX_SVC1R3,OHORELAX_SVELEC,OHORELAX_SVLG,&
+               OHORELAX_SVCHEM,OHORELAX_SVAER,OHORELAX_SVDST,OHORELAX_SVSLT, &
+               OHORELAX_SVPP,OHORELAX_SVCS,  OHORELAX_SVCHIC,OHORELAX_SVSNW, &
+#ifdef MNH_FOREFIRE
+               OHORELAX_SVFF,                                                &
+#endif
+               PRIMKMAX,KRIMX,KRIMY,PALKTOP,PALKGRD,PALZBOT,PALZBAS,         &
+               PT4DIFU,PT4DIFTH,PT4DIFSV,                                    &
+               PCORIOX,PCORIOY,PCORIOZ,PCURVX,PCURVY,                        &
+               PDXHATM,PDYHATM,PRHOM,PAF,PBFY,PCF,                           &
+               PTRIGSX,PTRIGSY,KIFAXX,KIFAXY,                                &
+               PALK,PALKW,KALBOT,PALKBAS,PALKWBAS,KALBAS,                    &
+               OMASK_RELAX,PKURELAX, PKVRELAX, PKWRELAX,                     &
+               PDK2U,PDK4U,PDK2TH,PDK4TH,PDK2SV,PDK4SV,OZDIFFU,PZDIFFU_HALO2,& 
+               PBFB,                                                         &
+               PBF_SXP2_YP1_Z,                                               &
+               PAF_ZS,PBF_ZS,PCF_ZS,                                         &
+               PDXATH_ZS,PDYATH_ZS,PRHO_ZS,                                  &
+               A_K,B_K,C_K,D_K) !JUAN FULL ZSOLVER  
+!     ######################################################################
+!
+!!****  *INI_DYNAMICS* - routine to initialize the parameters for the dynamics
+!!
+!!    PURPOSE
+!!    -------
+!       The purpose of this routine is to set or compute the parameters used
+!     by the MESONH dynamics : 
+!              * Coriolis parameters
+!              * Curvature coefficients
+!              * Pressure solver coefficients
+!              * Absorbing layer coefficients
+!              * Numerical difussion coefficients
+!
+!!**  METHOD
+!!    ------
+!!      - Coriolis parameters and curvature terms :
+!!           Horizontal Coriolis parameters are not initialized if thinshell
+!!    approximation is made (LTHINSHELL=.TRUE.).
+!!           Curvature coefficients are not initialized if Cartesian geometry
+!!    (LCARTESIAN=.TRUE.)  
+!!      - Coefficients and variables for pressure solver :
+!!          This is done by TRID
+!!      - Coefficients and variables for the absorbing layer 
+!!          ( upper and lateral) : This is done by RELAXDEF
+!!      - Coefficients for the numerical diffusion
+!!      
+!!    EXTERNAL
+!!    --------   
+!!      TRID    : to initialize pressure solver
+!!      RELAXDEF: to compute the relaxation coefficients
+!!      GET_DIM_EXT_ll : get extended sub-domain sizes
+!!
+!!     Module MODI_TRID   : interface for routine TRID
+!!     Module MODI_RELAXDEF : interface for routine RELAXDEF
+!!
+!!    IMPLICIT ARGUMENTS
+!!    ------------------ 
+!!      Module MODD_CONF  : contains declaration of configuration variables
+!!        
+!!         LTHINSHELL : Logical for  THINSHELL approximation                
+!!                     .TRUE.  = thinshell approximation
+!!         LCARTESIAN : Logical for cartesian geometry :
+!!                     .TRUE.  = cartesian geometry 
+!!         L1D        : Logical for 1D configuration :
+!!                     .TRUE.  = 1D model 
+!!
+!!      Module MODD_CST   : contains physical constants 
+!!
+!!         XPI        : Pi
+!!         XOMEGA     : Earth rotation
+!!
+!!      Module MODD_GRID  : contains grid variables
+!!
+!!         XLON0      :  Reference longitude for the conformal projection
+!!         XLAT0      :  Reference latitude for the conformal projection  
+!!         XBETA      :  Rotation angle for the conformal projection
+!!         XRPK       :  Projection parameter for the conformal projection
+!!
+!!    REFERENCE
+!!    ---------
+!!      Book2 of documentation (routine INI_DYNAMICS)
+!!      
+!!
+!!    AUTHOR
+!!    ------
+!!	V. Ducrocq       * Meteo France *
+!!
+!!    MODIFICATIONS
+!!    -------------
+!!      Original        01/07/94 
+!!      Modification    18/10/94 (J. Stein) to add the abs. layer
+!!      Modification    16/11/94 (Lafore+Pinty) to add the num. diffusion
+!!      Modification    06/12/94  (J.Stein) add the switch LABSLAYER
+!!      Modification    12/12/94  (J.Stein) add the lateral relaxation 
+!!      Modification    16/01/95  (J.Stein) conditional CALL to trid for 1D case
+!!      Modification    13/08/98  (N.Asencio) add parallel code
+!!      Modification    20/05/06  Remove KEPS
+!!      Modification    07/2013   (Bosseur & Filippi) Adds Forefire
+!!  Philippe Wautelet: 05/2016-04/2018: new data structures and calls for I/O
+!!     Vionnet 07/2017 : blow snow
+!-------------------------------------------------------------------------------
+!
+!*       0.    DECLARATIONS
+!              ------------ 
+USE MODD_CONF
+USE MODD_CST
+USE MODD_GRID
+USE MODD_LUNIT_n, ONLY: TLUOUT
+!
+USE MODI_RELAXDEF
+! USE MODI_TRID
+USE MODI_TRIDZ
+USE MODI_ZDIFFUSETUP
+!
+USE MODE_ll
+USE MODE_TYPE_ZDIFFU
+#ifdef MNH_BITREP
+USE MODI_BITREP
+#define SIN BR_SIN
+#define COS BR_COS
+#endif
+!
+USE MODE_MPPDB
+!
+IMPLICIT NONE
+!
+!*       0.1   declarations of argument
+!
+!  intent in arguments
+!
+REAL, DIMENSION(:,:),   INTENT(IN)        :: PLON,PLAT !Longitude and latitude
+REAL, DIMENSION(:,:,:), INTENT(IN)        :: PRHODJ    ! rho J
+REAL, DIMENSION(:,:,:), INTENT(IN)        :: PTHVREF   ! virtual potential 
+                                      ! temperature of the reference state
+REAL, DIMENSION(:,:),   INTENT(IN)        :: PMAP      ! Map factor
+REAL, DIMENSION(:,:,:), INTENT(IN)        :: PZZ       ! height 
+REAL, DIMENSION(:),     INTENT(IN)        :: PDXHAT     ! Stretching in x direction
+REAL, DIMENSION(:),     INTENT(IN)        :: PDYHAT     ! Stretching in y direction
+REAL, DIMENSION(:),     INTENT(IN)        :: PZHAT     ! Gal-Chen Height   
+CHARACTER(LEN=4), DIMENSION(:), INTENT(IN) :: HLBCX    ! x-direction LBC type
+CHARACTER(LEN=4), DIMENSION(:), INTENT(IN) :: HLBCY    ! y-direction LBC type
+LOGICAL,                INTENT(IN)        :: OVE_RELAX ! logical
+             ! switch to activate the VErtical  RELAXation 
+LOGICAL,                INTENT(IN)        :: OVE_RELAX_GRD ! logical
+             ! switch to activate the VErtical  RELAXation (ground layer)       
+LOGICAL,            INTENT(IN) :: OHORELAX_UVWTH  ! switch for the 
+                       ! horizontal relaxation for U,V,W,TH
+LOGICAL,            INTENT(IN) :: OHORELAX_RV     ! switch for the 
+                       ! horizontal relaxation for Rv
+LOGICAL,            INTENT(IN) :: OHORELAX_RC     ! switch for the 
+                       ! horizontal relaxation for Rc
+LOGICAL,            INTENT(IN) :: OHORELAX_RR     ! switch for the 
+                       ! horizontal relaxation for Rr
+LOGICAL,            INTENT(IN) :: OHORELAX_RI     ! switch for the 
+                       ! horizontal relaxation for Ri
+LOGICAL,            INTENT(IN) :: OHORELAX_RS     ! switch for the 
+                       ! horizontal relaxation for Rs
+LOGICAL,            INTENT(IN) :: OHORELAX_RG     ! switch for the 
+                       ! horizontal relaxation for Rg
+LOGICAL,            INTENT(IN) :: OHORELAX_RH     ! switch for the 
+                       ! horizontal relaxation for Rh
+LOGICAL,            INTENT(IN) :: OHORELAX_TKE    ! switch for the 
+                       ! horizontal relaxation for tke
+LOGICAL,DIMENSION(:),INTENT(IN):: OHORELAX_SV     ! switch for the 
+                       ! horizontal relaxation for sv variables
+LOGICAL,             INTENT(IN):: OHORELAX_SVC2R2 ! switch for the 
+                       ! horizontal relaxation for c2r2 variables
+LOGICAL,             INTENT(IN):: OHORELAX_SVC1R3 ! switch for the 
+                       ! horizontal relaxation for c1r3 variables
+LOGICAL,             INTENT(IN):: OHORELAX_SVELEC ! switch for the 
+                       ! horizontal relaxation for elec variables
+LOGICAL,             INTENT(IN):: OHORELAX_SVLG   ! switch for the 
+                       ! horizontal relaxation for lg variables
+LOGICAL,             INTENT(IN):: OHORELAX_SVCHEM ! switch for the 
+                       ! horizontal relaxation for chem variables
+LOGICAL,             INTENT(IN):: OHORELAX_SVCHIC ! switch for the
+                       ! horizontal relaxation for ice chem variables
+LOGICAL,             INTENT(IN):: OHORELAX_SVAER  ! switch for the 
+                       ! horizontal relaxation for aer variables
+LOGICAL,             INTENT(IN):: OHORELAX_SVDST  ! switch for the 
+                       ! horizontal relaxation for dst variables
+LOGICAL,             INTENT(IN):: OHORELAX_SVSLT  ! switch for the 
+                       ! horizontal relaxation for slt variables
+LOGICAL,             INTENT(IN):: OHORELAX_SVPP   ! switch for the 
+                       ! horizontal relaxation for passive pollutants
+LOGICAL,             INTENT(IN):: OHORELAX_SVSNW   ! switch for the
+                       ! horizontal relaxation for blowing snow variables
+#ifdef MNH_FOREFIRE
+LOGICAL,             INTENT(IN):: OHORELAX_SVFF   ! switch for the 
+                       ! horizontal relaxation for ForeFire variables
+#endif
+LOGICAL,             INTENT(IN):: OHORELAX_SVCS   ! switch for the 
+                       ! horizontal relaxation for conditional sampling
+REAL,                    INTENT(IN)    :: PRIMKMAX !Max. value of the horiz.
+                                     ! relaxation coefficients
+INTEGER,                INTENT(IN)     :: KRIMX,KRIMY ! Number of points in 
+                                     ! the rim zone in the x and y directions 
+REAL,     INTENT(IN)   :: PALKTOP    ! Damping coef. at the top of the absorbing
+                                     ! layer
+REAL,     INTENT(IN)   :: PALZBOT    ! Height of the absorbing layer base
+REAL,     INTENT(IN)   :: PALKGRD    ! Damping coef. at the top of the absorbing
+                                     ! layer
+REAL,     INTENT(IN)   :: PALZBAS    ! Height of the absorbing layer base
+REAL,     INTENT(IN)   :: PT4DIFU    ! Damping time scale for 2*dx wavelength
+                                     ! specified for the 4nd order num. diffusion
+                                     ! for momentum
+REAL,     INTENT(IN)   :: PT4DIFTH   ! for meteorological scalar variables
+REAL,     INTENT(IN)   :: PT4DIFSV   ! for tracer scalar variables
+
+REAL,     INTENT(IN)   :: PTSTEP     ! Time step
+CHARACTER (LEN=5), INTENT(IN) :: HPRESOPT        ! choice of the pressure solver
+!
+!  intent out arguments
+!
+REAL, INTENT(OUT) :: PDXHATM                     ! mean grid increment in the x
+                                                 ! direction
+REAL, INTENT(OUT) :: PDYHATM                     ! mean grid increment in the y
+                                                 ! direction
+!
+REAL, DIMENSION (:), INTENT(OUT) :: PRHOM        !  mean of XRHODJ on the plane x y 
+                                                 !  localized at a mass level
+!
+REAL, DIMENSION(:,:), INTENT(OUT) :: PCORIOX,PCORIOY ! Hor. Coriolis parameters
+REAL, DIMENSION(:,:), INTENT(OUT) :: PCORIOZ         ! Vert. Coriolis parameter 
+REAL, DIMENSION(:,:), INTENT(OUT) :: PCURVX,PCURVY   ! Curvature coefficients
+! 
+REAL, DIMENSION(:),     INTENT(OUT) :: PAF ! vectors giving the non-vanishing        
+REAL, DIMENSION(:,:,:), INTENT(OUT) :: PBFY ! elements of the tri-diag matrix
+                                            ! on an y-slice of global physical domain
+REAL, DIMENSION(:),     INTENT(OUT) :: PCF ! in the pressure equation
+REAL, DIMENSION(:),     INTENT(OUT) :: PTRIGSX ! Arrays for sinus or cosinus 
+REAL, DIMENSION(:),     INTENT(OUT) :: PTRIGSY ! values for the FFT in x and
+                                               ! y directions
+INTEGER, DIMENSION(:),  INTENT(OUT) :: KIFAXX  ! Decomposition in prime numbers
+INTEGER, DIMENSION(:),  INTENT(OUT) :: KIFAXY  ! for the FFT in x and y
+                                               ! direction      
+INTEGER          ,  INTENT(OUT)  :: KALBOT     ! Vertical index corresponding
+                                               ! to the absorbing layer base
+!  
+REAL, DIMENSION(:),   INTENT(OUT) :: PALK  ! Function of the absorbing
+                                           ! layer damping coefficient
+                                           ! defined for  u,v,and theta
+REAL, DIMENSION(:),   INTENT(OUT) :: PALKW ! Idem but defined for w     
+INTEGER          ,  INTENT(OUT)  :: KALBAS     ! Vertical index corresponding
+                                               ! to the absorbing layer base
+!  
+REAL, DIMENSION(:),   INTENT(OUT) :: PALKBAS  ! Function of the absorbing
+                                           ! layer damping coefficient
+                                           ! defined for  u,v,and theta
+REAL, DIMENSION(:),   INTENT(OUT) :: PALKWBAS ! Idem but defined for w
+LOGICAL, DIMENSION(:,:),  INTENT(OUT)   :: OMASK_RELAX  ! True where the 
+                                           ! lateral relax. has to be performed
+REAL, DIMENSION(:,:),     INTENT(OUT)   :: PKURELAX  !  Horizontal relaxation
+REAL, DIMENSION(:,:),     INTENT(OUT)   :: PKVRELAX  !  coefficients for the
+REAL, DIMENSION(:,:),     INTENT(OUT)   :: PKWRELAX  ! u, v and mass locations
+REAL,                 INTENT(OUT) :: PDK2U ! 2nd order num. diffusion coef. /dx2
+REAL,                 INTENT(OUT) :: PDK4U ! 4nd order num. diffusion coef. /dx4
+                                           ! for momentum
+REAL,                 INTENT(OUT) :: PDK2TH! for meteorological scalar variables
+REAL,                 INTENT(OUT) :: PDK4TH! 
+REAL,                 INTENT(OUT) :: PDK2SV! for tracer scalar variables
+REAL,                 INTENT(OUT) :: PDK4SV! 
+LOGICAL, INTENT(IN) :: OZDIFFU
+TYPE(TYPE_ZDIFFU_HALO2)                       :: PZDIFFU_HALO2
+REAL, DIMENSION(:,:,:), INTENT(OUT) :: PBFB ! elements of the tri-diag matrix
+                                            ! on an b-slice of global physical domain
+REAL, DIMENSION(:,:,:), INTENT(OUT) :: PBF_SXP2_YP1_Z ! elements of the tri-diag. SXP2_YP1_Z-slide 
+                                                   ! matrix in the pressure eq.
+REAL, DIMENSION(:,:,:), INTENT(OUT) :: PAF_ZS,PBF_ZS,PCF_ZS
+REAL, DIMENSION(:,:)  , INTENT(OUT) :: PDXATH_ZS,PDYATH_ZS
+REAL, DIMENSION(:,:,:), INTENT(OUT) :: PRHO_ZS
+REAL, DIMENSION(:)    , INTENT(OUT) :: A_K,B_K,C_K,D_K
+!
+!*       0.2   declarations of local variables
+!
+REAL, DIMENSION(SIZE(PRHODJ,1),SIZE(PRHODJ,2)) :: ZGAMMA ! Gamma =K(lambda-lambda0) - beta
+REAL                                       :: ZMBETA ! -beta
+REAL                                       :: ZCDR   ! to convert degrees in
+                                                     ! radians 
+INTEGER                                    :: ILUOUT ! Logical unit number for output_listing file
+INTEGER                                    :: IIU,IJU !  Upper bounds in x,y directions
+LOGICAL                                    :: GHORELAX
+LOGICAL, DIMENSION(7) :: GHORELAXR ! local array of logical
+#ifdef MNH_FOREFIRE
+LOGICAL, DIMENSION(13):: GHORELAXSV! local array of logical
+#else
+LOGICAL, DIMENSION(12):: GHORELAXSV! local array of logical
+#endif
+!
+!-------------------------------------------------------------------------------
+!
+!*       1.    COMPUTES CORIOLIS PARAMETERS AND CURVATURE COEFFICIENTS
+!              -------------------------------------------------------
+! 
+ZCDR = XPI/180.
+IF (.NOT.LCARTESIAN) THEN
+  ZGAMMA(:,:) = XRPK * ((PLON(:,:) - XLON0)*ZCDR) - (XBETA*ZCDR)
+  IF (.NOT.LTHINSHELL) THEN    
+    PCORIOX(:,:) = - 2. * XOMEGA * COS(PLAT(:,:)*ZCDR) * SIN(ZGAMMA(:,:))
+    PCORIOY(:,:) =   2. * XOMEGA * COS(PLAT(:,:)*ZCDR) * COS(ZGAMMA(:,:))
+  END IF
+  PCORIOZ(:,:)   =   2. * XOMEGA * SIN(PLAT(:,:)*ZCDR) 
+  PCURVX (:,:)   = COS(ZGAMMA(:,:)) * (SIN(PLAT(:,:)*ZCDR) -XRPK)         &
+                 / COS(PLAT(:,:)*ZCDR)
+  PCURVY (:,:)   = SIN(ZGAMMA(:,:)) * (SIN(PLAT(:,:)*ZCDR) -XRPK)         &
+                 / COS(PLAT(:,:)*ZCDR)
+  !
+  CALL MPPDB_CHECK2D(PCORIOX,"ini_dynamics:PCORIOX",PRECISION)
+  CALL MPPDB_CHECK2D(PCORIOY,"ini_dynamics:PCORIOY",PRECISION)
+  CALL MPPDB_CHECK2D(PCORIOZ,"ini_dynamics:PCORIOZ",PRECISION)
+  !
+ELSE
+  ZMBETA = - (XBETA*ZCDR)
+  PCORIOX(:,:) = - 2. * XOMEGA * COS(XLAT0*ZCDR) * SIN(ZMBETA)
+  PCORIOY(:,:) =   2. * XOMEGA * COS(XLAT0*ZCDR) * COS(ZMBETA)
+  PCORIOZ(:,:) =   2. * XOMEGA * SIN(XLAT0*ZCDR) 
+END IF           
+!
+!-------------------------------------------------------------------------------
+!
+!*       2.    INITIALIZATION OF PRESSURE SOLVER
+!              ---------------------------------
+!
+IF (.NOT.L1D) THEN
+! CALL TRID(HLBCX,HLBCY,                                                  &
+!           PMAP,PDXHAT,PDYHAT,PDXHATM,PDYHATM,PRHOM,PAF,                 &
+!           PCF,PTRIGSX,PTRIGSY,KIFAXX,KIFAXY,                            &
+!           PRHODJ,PTHVREF,PZZ,PBFY)
+  CALL TRIDZ(HLBCX,HLBCY,                                                 &
+            PMAP,PDXHAT,PDYHAT,HPRESOPT,                                  &
+            PDXHATM,PDYHATM,PRHOM,PAF,                                    &
+            PCF,PTRIGSX,PTRIGSY,KIFAXX,KIFAXY,                            &
+            PRHODJ,PTHVREF,PZZ,PBFY,PBFB,                                 &
+            PBF_SXP2_YP1_Z,                                               &
+            PAF_ZS,PBF_ZS,PCF_ZS,                                         &
+            PDXATH_ZS,PDYATH_ZS,PRHO_ZS,                                  &
+            A_K,B_K,C_K,D_K) !JUAN  FULL ZSOLVER
+END IF
+!
+!
+!
+!-------------------------------------------------------------------------------
+!
+!*       3.    COMPUTE THE ABSORBING LAYER COEFFICIENTS
+!              ----------------------------------------
+!
+GHORELAXR(1) = OHORELAX_RV
+GHORELAXR(2) = OHORELAX_RC
+GHORELAXR(3) = OHORELAX_RR
+GHORELAXR(4) = OHORELAX_RI
+GHORELAXR(5) = OHORELAX_RS
+GHORELAXR(6) = OHORELAX_RG
+GHORELAXR(7) = OHORELAX_RH
+!
+GHORELAXSV(1) = OHORELAX_SVC2R2
+GHORELAXSV(2) = OHORELAX_SVC1R3
+GHORELAXSV(3) = OHORELAX_SVELEC
+GHORELAXSV(4) = OHORELAX_SVLG
+GHORELAXSV(5) = OHORELAX_SVCHEM
+GHORELAXSV(6) = OHORELAX_SVAER
+GHORELAXSV(7) = OHORELAX_SVDST
+GHORELAXSV(8) = OHORELAX_SVSLT
+GHORELAXSV(9) = OHORELAX_SVPP
+GHORELAXSV(10)= OHORELAX_SVCS
+GHORELAXSV(11) = OHORELAX_SVCHIC
+GHORELAXSV(12) = OHORELAX_SVSNW
+#ifdef MNH_FOREFIRE
+GHORELAXSV(13) = OHORELAX_SVFF
+#endif
+!
+GHORELAX=ANY(GHORELAXR) .OR. ANY(GHORELAXSV) .OR. ANY(OHORELAX_SV) &
+                        .OR. OHORELAX_UVWTH  .OR. OHORELAX_TKE 
+!
+IF (GHORELAX .OR. OVE_RELAX.OR.OVE_RELAX_GRD) THEN
+  CALL RELAXDEF( OVE_RELAX,OVE_RELAX_GRD,OHORELAX_UVWTH,OHORELAX_RV,  &
+     OHORELAX_RC,OHORELAX_RR,OHORELAX_RI,OHORELAX_RS,OHORELAX_RG,     &
+     OHORELAX_RH,OHORELAX_TKE,OHORELAX_SV,                            &
+     OHORELAX_SVC2R2,OHORELAX_SVC1R3,OHORELAX_SVELEC,OHORELAX_SVLG,   &
+     OHORELAX_SVCHEM, OHORELAX_SVAER, OHORELAX_SVDST, OHORELAX_SVSLT, &
+     OHORELAX_SVPP, OHORELAX_SVCS, OHORELAX_SVCHIC,OHORELAX_SVSNW,    &
+     PALKTOP,PALKGRD, PALZBOT,PALZBAS,                                &
+     PZZ, PZHAT, PTSTEP,                                              &
+     PRIMKMAX,KRIMX,KRIMY,                                            &
+     PALK, PALKW, KALBOT,                                             &
+     PALKBAS, PALKWBAS, KALBAS,                                       &
+     OMASK_RELAX,PKURELAX, PKVRELAX, PKWRELAX                         )
+END IF
+!
+!
+!
+!-------------------------------------------------------------------------------
+!
+!*       4.    COMPUTE THE NUMERICAL DIFFUSION COEFFICIENTS
+!              --------------------------------------------
+!
+PDK4U = 1.0/(16.0*PT4DIFU) ! The damping rate for the 2*dx wavelength is the same
+PDK2U = 2.0*PDK4U          ! for the 2nd and the 4th order diffusion schemes
+                           ! for momentum
+PDK4TH= 1.0/(16.0*PT4DIFTH) ! for meteorological scalar variables                       
+PDK2TH= 2.0*PDK4TH         
+PDK4SV= 1.0/(16.0*PT4DIFSV) ! for tracer scalar variables                       
+PDK2SV= 2.0*PDK4SV         
+!
+! Call ZDIFFUSETUP if OZDIFFU is true (parameters for truly horizontal diffusion)
+!
+IF (OZDIFFU) THEN
+  CALL ZDIFFUSETUP (PZZ,&
+                    PZDIFFU_HALO2)
+ENDIF
+!
+!-------------------------------------------------------------------------------
+!
+!*       5.    PRINT ON OUTPUT_LISTING
+!              -----------------------
+!
+IF (NVERB >= 10) THEN
+  CALL GET_DIM_EXT_ll ('B',IIU,IJU)
+  ILUOUT = TLUOUT%NLU
+!
+  WRITE(ILUOUT,*) 'INI_DYNAMICS : Some PCORIOZ values'
+  WRITE(ILUOUT,*) '(1,1)          (IIU/2,IJU/2)         (IIU,IJU)  '
+  WRITE(ILUOUT,*) PCORIOZ(1,1),PCORIOZ(IIU/2,IJU/2),PCORIOZ(IIU,IJU) 
+!
+  IF (.NOT.LTHINSHELL) THEN
+    WRITE(ILUOUT,*) 'INI_DYNAMICS : Some PCORIOX values'
+    WRITE(ILUOUT,*) '(1,1)          (IIU/2,IJU/2)         (IIU,IJU)  '
+    WRITE(ILUOUT,*) PCORIOX(1,1),PCORIOX(IIU/2,IJU/2),PCORIOX(IIU,IJU) 
+!
+    WRITE(ILUOUT,*) 'INI_DYNAMICS : Some PCORIOY values'
+    WRITE(ILUOUT,*) '(1,1)          (IIU/2,IJU/2)         (IIU,IJU)  '
+    WRITE(ILUOUT,*) PCORIOY(1,1),PCORIOY(IIU/2,IJU/2),PCORIOY(IIU,IJU) 
+  END IF
+!
+  IF ( .NOT. LCARTESIAN ) THEN
+    WRITE(ILUOUT,*) 'INI_DYNAMICS : Some PCURVX values'
+    WRITE(ILUOUT,*) '(1,1)          (IIU/2,IJU/2)         (IIU,IJU)  '
+    WRITE(ILUOUT,*) PCURVX(1,1),PCURVX(IIU/2,IJU/2),PCURVX(IIU,IJU)
+! 
+    WRITE(ILUOUT,*) 'INI_DYNAMICS : Some PCURVY values'
+    WRITE(ILUOUT,*) '(1,1)          (IIU/2,IJU/2)         (IIU,IJU)  '
+    WRITE(ILUOUT,*) PCURVY(1,1),PCURVY(IIU/2,IJU/2),PCURVY(IIU,IJU) 
+  END IF
+END IF
+!-------------------------------------------------------------------------------
+!
+END SUBROUTINE INI_DYNAMICS
diff --git a/src/ZSOLVER/ini_modeln.f90 b/src/ZSOLVER/ini_modeln.f90
new file mode 100644
index 0000000000000000000000000000000000000000..8203f0ada7d3d47b9a065697b8587553b551aa77
--- /dev/null
+++ b/src/ZSOLVER/ini_modeln.f90
@@ -0,0 +1,2525 @@
+!MNH_LIC Copyright 1994-2019 CNRS, Meteo-France and Universite Paul Sabatier
+!MNH_LIC This is part of the Meso-NH software governed by the CeCILL-C licence
+!MNH_LIC version 1. See LICENSE, CeCILL-C_V1-en.txt and CeCILL-C_V1-fr.txt
+!MNH_LIC for details. version 1.
+!-----------------------------------------------------------------
+!     #######################
+      MODULE MODI_INI_MODEL_n
+!     #######################
+!
+INTERFACE
+!
+       SUBROUTINE INI_MODEL_n(KMI,TPINIFILE)
+!
+USE MODD_IO, ONLY: TFILEDATA
+!
+INTEGER,          INTENT(IN)   :: KMI       ! Model Index
+TYPE(TFILEDATA),  INTENT(IN)   :: TPINIFILE ! Initial file
+!
+END SUBROUTINE INI_MODEL_n
+!
+END INTERFACE
+!
+END MODULE MODI_INI_MODEL_n
+!     ############################################
+      SUBROUTINE INI_MODEL_n(KMI,TPINIFILE)
+!     ############################################
+!
+!!****  *INI_MODEL_n* - routine to initialize the nested model _n
+!!
+!!    PURPOSE
+!!    -------
+!       The purpose of this routine is to initialize the variables
+!     of the nested model _n.
+!
+!!**  METHOD
+!!    ------
+!!      The initialization of the model _n is performed as follows :
+!!       - Memory for arrays are then allocated :
+!!            * If  turbulence kinetic energy variable is not needed
+!!    (CTURB='NONE'),  XTKET, XTKEM and XTKES are zero-size arrays.
+!!            * If  dissipation of TKE variable is not needed
+!!    (CTURBLEN /='KEPS'),  XEPST, XEPSM and XREPSS are zero-size arrays.
+!!            * Memory for mixing ratio arrays is allocated according to the
+!!     value of logicals LUSERn (the number NRR of moist variables is deduced).
+!!            * The latitude (XLAT), longitude (XLON) and map factor (XMAP)
+!!     arrays are zero-size arrays if Cartesian geometry (LCARTESIAN=.TRUE.)
+!!            * Memory for reference state without orography ( XRHODREFZ and
+!!     XTHVREFZ) is only allocated in INI_MODEL1
+!!            * The horizontal Coriolis parameters (XCORIOX and XCORIOY) arrays
+!!     are  zero-size arrays if thinshell approximation (LTHINSHELL=.TRUE.)
+!!            * The Curvature coefficients (XCURVX and XCURVY) arrays
+!!     are zero-size arrays if Cartesian geometry (LCARTESIAN=.TRUE.)
+!!            * Memory for the Jacobian (ZJ) local array is allocated
+!!     (This variable is computed in SET_GRID and used in SET_REF).
+!!       - The spatial and temporal grid variables are initialized by SET_GRID.
+!!       - The metric coefficients are computed by METRICS (they are using in
+!!     the SET-REF call).
+!!       - The prognostic variables and are read in initial
+!!    LFIFM file (in READ_FIELD)
+!!       - The reference state variables  are initialized by SET_REF.
+!!       - The temporal indexes of the outputs are computed by SET_OUTPUT_TIMES
+!!       - The large scale sources are computed in case of coupling case by
+!!    INI_CPL.
+!!       - The initialization of the parameters needed for the dynamics
+!!         of the model n is realized in INI_DYNAMICS.
+!!       - Then the initial file (DESFM+LFIFM files) is closed by IO_File_close.
+!!       - The initialization of the parameters needed for the ECMWF radiation
+!!         code is realized in INI_RADIATIONS.
+!!       - The contents of the scalar variables are overwritten by
+!!         the chemistry initialization subroutine CH_INIT_FIELDn when
+!!         the flags LUSECHEM and LCH_INIT_FIELD are set to TRUE.
+!!         This allows easy initialization of the chemical fields at a
+!!         restart of the model.
+!!
+!!    EXTERNAL
+!!    --------
+!!      SET_DIM     : to initialize dimensions
+!!      SET_GRID    : to initialize grid
+!!      METRICS     : to compute metric coefficients
+!!      READ_FIELD  : to initialize field
+!!      FMCLOS      : to close a FM-file
+!!      SET_REF     : to initialize reference state for anelastic approximation
+!!      INI_DYNAMICS: to initialize parameters for the dynamics
+!!      INI_TKE_EPS : to initialize the TKE 
+!!      SET_DIRCOS  : to compute the director cosinus of the orography
+!!      INI_RADIATIONS : to initialize radiation computations
+!!      CH_INIT_CCS: to initialize the chemical core system
+!!      CH_INIT_FIELDn: to (re)initialize the scalar variables
+!!      INI_DEEP_CONVECTION : to initialize the deep convection scheme
+!!      CLEANLIST_ll : deaalocate a list
+!!
+!!    IMPLICIT ARGUMENTS
+!!    ------------------
+!!
+!!      Module MODD_PARAMETERS : contains declaration of parameter variables
+!!         JPHEXT : Horizontal external points number
+!!         JPVEXT : Vertical external points number
+!!
+!!      Module MODD_MODD_DYN   : contains declaration of parameters
+!!                               for the dynamics
+!!      Module MODD_CONF       : contains declaration of configuration variables
+!!                               for all models
+!!         NMODEL     : Number of nested models
+!!         NVERB      : Level of informations on output-listing
+!!                          0 for minimum  prints
+!!                          5 for intermediate level of prints
+!!                         10 for maximum  prints
+!!
+!!      Module MODD_REF        : contains declaration of reference state
+!!                               variables for all models
+!!      Module MODD_FIELD_n    : contains declaration of prognostic fields
+!!      Module MODD_LSFIELD_n  : contains declaration of Larger Scale fields
+!!      Module MODD_GRID_n     : contains declaration of spatial grid variables
+!!      Module MODD_TIME_n     : contains declaration of temporal grid variables
+!!      Module MODD_REF_n      : contains declaration of reference state
+!!                               variables
+!!      Module MODD_CURVCOR_n  : contains declaration of curvature and Coriolis
+!!                               variables
+!!      Module MODD_BUDGET     : contains declarations of the budget parameters
+!!      Module MODD_RADIATIONS_n:contains declaration of the variables of the
+!!                               radiation interface scheme
+!!      Module MODD_STAND_ATM  : contains declaration of the 5 standard
+!!                               atmospheres used for the ECMWF-radiation code
+!!      Module MODD_FRC        : contains declaration of the control variables
+!!                               and of the forcing fields
+!!      Module MODD_CH_MNHC_n   : contains the control parameters for chemistry
+!!      Module MODD_DEEP_CONVECTION_n: contains declaration of the variables of
+!!                                     the deep convection scheme
+!!
+!!
+!!
+!!
+!!      Module MODN_CONF_n     : contains declaration of namelist NAM_CONFn and 
+!!                             uses module MODD_CONF_n (configuration variables)
+!!      Module MODN_LUNIT_n    : contains declaration of namelist NAM_LUNITn and
+!!                             uses module MODD_LUNIT_n (Logical units)
+!!      Module MODN_DYN_n      : contains declaration of namelist NAM_DYNn and
+!!                             uses module MODD_DYN_n (control of dynamics)
+!!      Module MODN_PARAM_n    : contains declaration of namelist NAM_PARAMn and
+!!                             uses module MODD_PARAM_n (control of physical
+!!                             parameterization)
+!!      Module MODN_LBC_n      : contains declaration of namelist NAM_LBCn and 
+!!                             uses module MODD_LBC_n (lateral boundaries)
+!!      Module MODN_TURB_n     : contains declaration of namelist NAM_TURBn and 
+!!                             uses module MODD_TURB_n (turbulence scheme)
+!!      Module MODN_PARAM_RAD_n: contains declaration of namelist NAM_PARAM_RADn
+!!
+!!    REFERENCE
+!!    ---------
+!!      Book2 of documentation (routine INI_MODEL_n)
+!!
+!!
+!!    AUTHOR
+!!    ------
+!!      V. Ducrocq       * Meteo France *
+!!
+!!    MODIFICATIONS
+!!    -------------
+!!      Original     10/06/94
+!!      Modification 17/10/94  (Stein)  For LCORIO
+!!      Modification 20/10/94  (Stein)  For SET_GRID and NAMOUTN
+!!      Modification 26/10/94  (Stein)  Modifications of the namelist names
+!!      Modification 10/11/94  (Lafore) allocatation of tke fields
+!!      Modification 22/11/94  (Stein)  change the READ_FIELDS call ( add
+!!                                      pressure function
+!!      Modification 06/12/94  (Stein)  add the LS fields
+!!                   12/12/94  (Stein)  rename END_INI in INI_DYNAMICS
+!!      Modification 09/01/95  (Stein)  add the turbulence scheme
+!!      Modification Jan 19, 1995 (J. Cuxart) add the TKE initialization
+!!                   Jan 23, 1995 (J. Stein ) remove the condition
+!!                             LTHINSHELL=T LCARTESIAN=T => stop
+!!      Modification Feb 16, 1995 (I.Mallet) add the METRICS call and
+!!                                      change the SET_REF call (add
+!!                                      the lineic mass)
+!!      Modification Mar 10, 1995 (I. Mallet) add the COUPLING initialization
+!!                   June 29,1995 (Ph. Hereil, J. Stein) add the budget init.
+!!      Modification Sept. 1, 1995 (S. Belair) Reading of the surface variables
+!!                                 and parameters for ISBA (i.e., add a
+!!                                 CALL READ_GR_FIELD)
+!!      Modification 18/08/95     (J.P.Lafore)   time step change case
+!!                   25/09/95     (J. Cuxart and J.Stein)   add LES variables
+!!                                and the diachronic file initialization
+!!      Modification Sept 20,1995 (Lafore) coupling for the dry mass Md
+!!      Modification Sept. 12, 1995 (J.-P. Pinty) add the initialization of
+!!                                      the ECMWF radiation code
+!!      Modification Sept. 13, 1995 (J.-P. Pinty) control the allocation of the
+!!                                      arrays of MODD_GR_FIELD_n
+!!      Modification Nove. 17, 1995 (J.Stein) control of the control !! 
+!!                   March 01, 1996 (J. Stein) add the cloud fraction    
+!!                   April 03, 1996 (J. Stein) unify the ISBA and TSZ0 cases
+!!      Modification 13/12/95 (M. Georgelin) add the forcing variables in
+!!                                           the call read_field, and their
+!!                                           allocation.
+!!                   Mai   23, 1996 (J. Stein) allocate XSEA in the TSZ0 case
+!!                   June  11, 1996 (V. Masson) add XSILT and XLAKE of
+!!                                              MODD_GR_FIELD_n
+!!                   August 7, 1996 (K. Suhre)  add (re)initialization of
+!!                                              chemistry
+!!                   Octo. 11, 1996 (J. Stein ) add XSRCT and XSRCM
+!!                   October 8, 1996 (J. Cuxart, E. Sanchez) Moist LES diagnostics
+!!                                     and control on TKE initialization.
+!!      Modification 19/12/96 (J.-P. Pinty) add the ice parameterization and
+!!                                          the precipitation fields
+!!      Modification 11/01/97 (J.-P. Pinty) add the deep convection
+!!                   Nov.   1, 1996 (V. Masson) Read the vertical grid kind
+!!                   Nov.  20, 1996 (V. Masson) control of convection calling time
+!!                   July  16, 1996 (J.P.Lafore) update of EXSEG file reading
+!!                   Oct.  08, 1996 (J.P.Lafore, V.Masson)
+!!                                       MY_NAME and DAD_NAME reading and check
+!!                   Oct.  30, 1996 (J.P.Lafore) resolution ratio reading for nesting
+!!                                       and Bikhardt interpolation coef. initialization
+!!                   Nov.  22, 1996 (J.P.Lafore) allocation of LS sources for nesting
+!!                   Feb.  26, 1997 (J.P.Lafore) allocation of "surfacic" LS fields
+!!                   March 10, 1997 (J.P.Lafore) forcing only for model 1
+!!                   June  22, 1997 (J. Stein)   add the absolute pressure
+!!                   July  09, 1997 (V. Masson)  add directional z0 and SSO
+!!                   Aug.  18, 1997 (V. Masson)  consistency between storage
+!!                                               type and CCONF
+!!                   Dec.  22, 1997 (J. Stein)   add the LS field spawning
+!!                   Jan.  24, 1998 (P.Bechtold) change MODD_FRC and MODD_DEEP_CONVECTION
+!!                   Dec.  24, 1997 (V.Masson)   directional z0 parameters
+!!                   Aug.  13, 1998 (V. Ducrocq P Jabouille)   //
+!!                   Mai.  26, 1998 (J. Stein)   remove NXEND,NYEND
+!!                   Feb.   1, 1999 (J. Stein)   compute the Bikhardt
+!!                                       interpolation coeff. before the call to set_grid
+!!                   April  5, 1999 (V. Ducrocq) change the DXRATIO_ALL init.
+!!                   April  12, 1999 (J. Stein)  cleaning + INI_SPAWN_LS
+!!                   Apr.   7, 1999 (P Jabouille) store the metric coefficients
+!!                                                in modd_metrics_n
+!!                   Jui.   15,1999 (P Jabouille) split the routines in two parts
+!!                   Jan.   04,2000 (V. Masson)   removes the TSZ0 case
+!!                   Apr.   15,2000 (P Jabouille) parallelization of grid nesting
+!!                   Aug.   20,2000 (J Stein    ) tranpose XBFY
+!!                   Jui    01,2000 (F.solmon )   adapatation for patch approach
+!!                   Jun.   15,2000 (J.-P. Pinty) add C2R2 initialization
+!!                   Nov.  15,2000 (V.Masson) use of ini_modeln in prep_real_case
+!!                   Nov.  15,2000 (V.Masson) call of LES routines
+!!                   Nov.  15,2000 (V.Masson) aircraft and balloon initialization routines
+!!                   Jan.  22,2001 (D.Gazen) update_nsv set NSV_* var. for current model
+!!                   Mar.  04,2002 (V.Ducrocq) initialization to temporal series
+!!                   Mar.  15,2002 (F.Solmon) modification of ini_radiation interface
+!!                   Nov.  29,2002 (JP Pinty) add C3R5, ICE2, ICE4, ELEC
+!!                   Jan.  2004    (V.Masson) externalization of surface
+!!                   May   2006    Remove KEPS
+!!                   Apr.  2010    (M. Leriche) add pH for aqueous phase chemistry
+!!                   Jul.  2010    (M. Leriche) add Ice phase chemistry
+!!                   Oct.  2010  (J.Escobar) check if local domain not to small for NRIMX NRIMY
+!!                   Nov.  2010  (J.Escobar) PGI BUG , add SIZE(CSV) to init_ground routine
+!!                   Nov.  2009    (C. Barthe) add call to INI_ELEC_n
+!!                   Mar.  2010    (M. Chong) add small ions 
+!!                   Apr.  2011    (M. Chong) correction of RESTART (ELEC)
+!!                   June  2011  (B.Aouizerats) Prognostic aerosols
+!!                   June  2011  (P.Aumond) Drag of the vegetation  
+!!                                         + Mean fields
+!!                   July  2013  (Bosseur & Filippi) Adds Forefire
+!!                   P. Tulet      Nov 2014 accumulated moles of aqueous species that fall at the surface   
+!!                   JAn.  2015  (F. Brosse) bug in allocate XACPRAQ
+!!                   Dec 2014 (C.Lac) : For reproducibility START/RESTA
+!!                   J.Escobar : 15/09/2015 : WENO5 & JPHEXT <> 1 
+!!                   V. Masson     Feb 2015 replaces, for aerosols, cover fractions by sea, town, bare soil fractions
+!!                   J.Escobar : 19/04/2016 : Pb IOZ/NETCDF , missing OPARALLELIO=.FALSE. for PGD files
+!!                   J.Escobar : 01/06/2016 : correct check limit of NRIM versus local subdomain size IDIM
+!!                   06/2016     (G.Delautier) phasage surfex 8
+!!                   Modification    01/2016  (JP Pinty) Add LIMA
+!!                   Aug.  2016 (J.Pianezze) Add SFX_OASIS_READ_NAM function from SurfEx
+!!                   M.Leriche 2016 Chemistry
+!!                   10/2016 M.Mazoyer New KHKO output fields
+!!                      10/2016 (C.Lac) Add max values
+!!       F. Brosse   Oct.  2016 add prod/loss terms computation for chemistry       
+!!                   M.Leriche 2016 Chemistry
+!!                   M.Leriche 10/02/17 prevent negative values in LBX(Y)SVS 
+!!                   M.Leriche 01/07/2017 Add DIAG chimical surface fluxes
+!!                   09/2017 Q.Rodier add LTEND_UV_FRC
+!!                   02/2018 Q.Libois ECRAD
+!!  Philippe Wautelet: 05/2016-04/2018: new data structures and calls for I/O
+!!                   V. Vionnet : 18/07/2017 : add blowing snow scheme 
+!!                   01/18 J.Colin Add DRAG 
+!  P. Wautelet 29/01/2019: bug: add missing zero-size allocations
+!  P. Wautelet 07/02/2019: force TYPE to a known value for IO_File_add2list
+!  P. Wautelet 13/02/2019: initialize XALBUV even if no radiation (needed in CH_INTERP_JVALUES)
+!  P. Wautelet 13/02/2019: removed PPABSM and PTSTEP dummy arguments of READ_FIELD
+!  P. Wautelet 14/02/2019: remove CLUOUT/CLUOUT0 and associated variables
+!  P. Wautelet 14/02/2019: remove HINIFILE dummy argument from INI_RADIATIONS_ECMWF/ECRAD
+!!                   02/2019 C.Lac add rain fraction as an output field
+!!      Bielli S. 02/2019  Sea salt : significant sea wave height influences salt emission; 5 salt modes
+!  P. Wautelet 14/03/2019: correct ZWS when variable not present in file (set to XZWS_DEFAULT)
+!  P. Wautelet 10/04/2019: replace ABORT and STOP calls by Print_msg
+!  P. Wautelet 19/04/2019: removed unused dummy arguments and variables
+!  P. Wautelet 07/06/2019: allocate lookup tables for optical properties only when needed
+!---------------------------------------------------------------------------------
+!
+!*       0.    DECLARATIONS
+!              ------------
+!
+#ifdef MNH_ECRAD
+USE YOERDI,                 only: RCCO2
+#endif
+
+USE MODD_2D_FRC
+USE MODD_ADVFRC_n
+USE MODD_ADV_n
+use MODD_AEROSET,           only: POLYTAU, POLYSSA, POLYG
+USE MODD_ARGSLIST_ll,       only: LIST_ll
+USE MODD_BIKHARDT_n
+USE MODD_BLOWSNOW
+USE MODD_BLOWSNOW_n
+USE MODD_BUDGET
+USE MODD_CH_AERO_n,         only: XSOLORG,XMI
+USE MODD_CH_AEROSOL,        only: LORILAM
+USE MODD_CH_BUDGET_n
+USE MODD_CH_FLX_n,          only: XCHFLX
+USE MODD_CH_M9_n,           only:NNONZEROTERMS
+USE MODD_CH_MNHC_n,         only: LUSECHEM, LUSECHAQ, LUSECHIC, LCH_INIT_FIELD, &
+                                  LCH_CONV_LINOX, XCH_TUV_DOBNEW, LCH_PH
+USE MODD_CH_PH_n
+USE MODD_CH_PRODLOSSTOT_n
+USE MODD_CLOUD_MF_n
+USE MODD_CONF
+USE MODD_CONF_n
+USE MODD_CST
+USE MODD_CTURB
+USE MODD_CURVCOR_n
+USE MODD_DEEP_CONVECTION_n
+USE MODD_DEF_EDDY_FLUX_n   ! for VT and WT fluxes
+USE MODD_DEF_EDDYUV_FLUX_n ! FOR UV
+USE MODD_DIAG_FLAG,         only: LCHEMDIAG, CSPEC_BU_DIAG
+USE MODD_DIM_n
+USE MODD_DRAG_n
+USE MODD_DRAGTREE
+USE MODD_DUST
+use MODD_DUST_OPT_LKT,      only: NMAX_RADIUS_LKT_DUST=>NMAX_RADIUS_LKT, NMAX_SIGMA_LKT_DUST=>NMAX_SIGMA_LKT,               &
+                                  NMAX_WVL_SW_DUST=>NMAX_WVL_SW,                                                            &
+                                  XEXT_COEFF_WVL_LKT_DUST=>XEXT_COEFF_WVL_LKT, XEXT_COEFF_550_LKT_DUST=>XEXT_COEFF_550_LKT, &
+                                  XPIZA_LKT_DUST=>XPIZA_LKT, XCGA_LKT_DUST=>XCGA_LKT
+USE MODD_DYN
+USE MODD_DYN_n
+USE MODD_DYNZD
+USE MODD_DYNZD_n
+USE MODD_ELEC_n,            only: XCION_POS_FW, XCION_NEG_FW
+USE MODD_FIELD_n
+#ifdef MNH_FOREFIRE
+USE MODD_FOREFIRE
+USE MODD_FOREFIRE_n
+#endif
+USE MODD_FRC
+USE MODD_FRC_n
+USE MODD_GET_n
+USE MODD_GRID_n
+USE MODD_GRID,              only: XLONORI,XLATORI
+USE MODD_IO,                only: CIO_DIR, TFILEDATA, TFILE_DUMMY
+USE MODD_IO_SURF_MNH,       only: IO_SURF_MNH_MODEL
+USE MODD_LATZ_EDFLX
+USE MODD_LBC_n,             only: CLBCX, CLBCY
+USE MODD_LSFIELD_n
+USE MODD_LUNIT_n
+USE MODD_MEAN_FIELD
+USE MODD_MEAN_FIELD_n
+USE MODD_METRICS_n
+USE MODD_MNH_SURFEX_n
+USE MODD_NESTING,           only: CDAD_NAME, NDAD, NDT_2_WAY, NDTRATIO, NDXRATIO_ALL, NDYRATIO_ALL
+USE MODD_NSV
+USE MODD_NSV
+USE MODD_NUDGING_n,         only: LNUDGING
+USE MODD_OUT_n
+USE MODD_PARAMETERS
+USE MODD_PARAM_KAFR_n
+USE MODD_PARAM_MFSHALL_n
+USE MODD_PARAM_n
+USE MODD_PARAM_RAD_n,       only: CAER, CAOP, CLW
+USE MODD_PASPOL
+USE MODD_PASPOL_n
+USE MODD_PAST_FIELD_n
+use modd_precision,         only: LFIINT
+USE MODD_RADIATIONS_n
+USE MODD_REF
+USE MODD_REF_n
+USE MODD_RELFRC_n
+use MODD_SALT,              only: LSALT
+use MODD_SALT_OPT_LKT,      only: NMAX_RADIUS_LKT_SALT=>NMAX_RADIUS_LKT, NMAX_SIGMA_LKT_SALT=>NMAX_SIGMA_LKT,               &
+                                  NMAX_WVL_SW_SALT=>NMAX_WVL_SW,                                                            &
+                                  XEXT_COEFF_WVL_LKT_SALT=>XEXT_COEFF_WVL_LKT, XEXT_COEFF_550_LKT_SALT=>XEXT_COEFF_550_LKT, &
+                                  XPIZA_LKT_SALT=>XPIZA_LKT, XCGA_LKT_SALT=>XCGA_LKT
+USE MODD_SERIES,            only: LSERIES
+USE MODD_SHADOWS_n
+USE MODD_STAND_ATM,         only: XSTROATM, XSMLSATM, XSMLWATM, XSPOSATM, XSPOWATM
+USE MODD_TIME
+USE MODD_TIME_n
+USE MODD_TURB_CLOUD,        only: NMODEL_CLOUD, CTURBLEN_CLOUD,XCEI
+USE MODD_TURB_n
+USE MODD_VAR_ll,            only: IP
+
+USE MODE_GATHER_ll
+USE MODE_INI_ONE_WAY_n
+USE MODE_IO
+USE MODE_IO_FIELD_READ,     only: IO_Field_read
+USE MODE_IO_FILE,           only: IO_File_open
+USE MODE_IO_MANAGE_STRUCT,  only: IO_File_add2list
+USE MODE_ll
+USE MODE_MODELN_HANDLER
+USE MODE_MPPDB
+USE MODE_MSG
+USE MODE_SPLITTINGZ_ll,     only: GET_DIM_EXTZ_ll
+USE MODE_TYPE_ZDIFFU
+
+USE MODI_CH_AER_MOD_INIT
+USE MODI_CH_INIT_BUDGET_n
+USE MODI_CH_INIT_FIELD_n
+USE MODI_CH_INIT_JVALUES
+USE MODI_CH_INIT_PRODLOSSTOT_n
+USE MODI_GET_SIZEX_LB
+USE MODI_GET_SIZEY_LB
+USE MODI_INI_AEROSET1
+USE MODI_INI_AEROSET2
+USE MODI_INI_AEROSET3
+USE MODI_INI_AEROSET4
+USE MODI_INI_AEROSET5
+USE MODI_INI_AEROSET6
+USE MODI_INI_AIRCRAFT_BALLOON
+USE MODI_INI_AIRCRAFT_BALLOON
+USE MODI_INI_BIKHARDT_n
+USE MODI_INI_BUDGET
+USE MODI_INI_CPL
+USE MODI_INI_DEEP_CONVECTION
+USE MODI_INI_DRAG
+USE MODI_INI_DYNAMICS
+USE MODI_INI_ELEC_n
+USE MODI_INI_LES_N
+USE MODI_INI_LG
+USE MODI_INI_LW_SETUP
+USE MODI_INI_MICRO_n
+USE MODI_INI_POSPROFILER_n
+USE MODI_INI_RADIATIONS
+USE MODI_INI_RADIATIONS_ECMWF
+USE MODI_INI_RADIATIONS_ECRAD
+USE MODI_INI_SERIES_N
+USE MODI_INI_SPAWN_LS_n
+USE MODI_INI_SURF_RAD
+USE MODI_INI_SURFSTATION_n
+USE MODI_INI_SW_SETUP
+USE MODI_INIT_AEROSOL_PROPERTIES
+#ifdef MNH_FOREFIRE
+USE MODI_INIT_FOREFIRE_n
+#endif
+USE MODI_INIT_GROUND_PARAM_n
+USE MODI_INI_TKE_EPS
+USE MODI_METRICS
+USE MODI_MNHGET_SURF_PARAM_n
+USE MODI_MNHREAD_ZS_DUMMY_n
+USE MODI_READ_FIELD
+USE MODI_SET_DIRCOS
+USE MODI_SET_GRID
+USE MODI_SET_REF
+#ifdef CPLOASIS
+USE MODI_SFX_OASIS_READ_NAM
+#endif
+USE MODI_SUNPOS_n
+USE MODI_SURF_SOLAR_GEOM
+USE MODI_UPDATE_METRICS
+USE MODI_UPDATE_NSV
+!
+IMPLICIT NONE
+!
+!*       0.1   declarations of arguments
+!
+!
+INTEGER,          INTENT(IN)   :: KMI       ! Model Index
+TYPE(TFILEDATA),  INTENT(IN)   :: TPINIFILE ! Initial file
+!
+!*       0.2   declarations of local variables
+!
+REAL, PARAMETER :: NALBUV_DEFAULT = 0.01 ! Arbitrary low value for XALBUV
+!
+INTEGER             :: JSV     ! Loop index
+INTEGER             :: IRESP   ! Return code of FM routines
+INTEGER             :: ILUOUT  ! Logical unit number of output-listing
+CHARACTER(LEN=28)   :: YNAME
+INTEGER             :: IIU     ! Upper dimension in x direction (local)
+INTEGER             :: IJU     ! Upper dimension in y direction (local)
+INTEGER             :: IIU_ll  ! Upper dimension in x direction (global)
+INTEGER             :: IJU_ll  ! Upper dimension in y direction (global)
+INTEGER             :: IKU     ! Upper dimension in z direction
+REAL, DIMENSION(:,:,:), ALLOCATABLE :: ZJ ! Jacobian
+LOGICAL             :: GINIDCONV ! logical switch for the deep convection
+                               ! initialization
+LOGICAL             :: GINIRAD ! logical switch for the radiation
+                               ! initialization
+!
+!
+TYPE(LIST_ll), POINTER :: TZINITHALO2D_ll ! pointer for the list of 2D fields
+                                      !  which must be communicated in INIT
+TYPE(LIST_ll), POINTER :: TZINITHALO3D_ll ! pointer for the list of 3D fields
+                                      !  which must be communicated in INIT
+!
+INTEGER :: IISIZEXF,IJSIZEXF,IISIZEXFU,IJSIZEXFU     ! dimensions of the
+INTEGER :: IISIZEX4,IJSIZEX4,IISIZEX2,IJSIZEX2       ! West-east LB arrays
+INTEGER :: IISIZEYF,IJSIZEYF,IISIZEYFV,IJSIZEYFV     ! dimensions of the
+INTEGER :: IISIZEY4,IJSIZEY4,IISIZEY2,IJSIZEY2       ! North-south LB arrays
+INTEGER :: IINFO_ll  ! Return code of //routines
+INTEGER :: IIY,IJY
+INTEGER :: IIU_B,IJU_B
+INTEGER :: IIU_SXP2_YP1_Z_ll,IJU_SXP2_YP1_Z_ll,IKU_SXP2_YP1_Z_ll
+!
+REAL, DIMENSION(:,:),   ALLOCATABLE :: ZCO2   ! CO2 concentration near the surface
+REAL, DIMENSION(:,:),   ALLOCATABLE :: ZSEA   ! sea fraction
+REAL, DIMENSION(:,:),   ALLOCATABLE :: ZTOWN  ! town fraction
+REAL, DIMENSION(:,:),   ALLOCATABLE :: ZBARE  ! bare soil fraction
+!
+REAL, DIMENSION(:,:,:), ALLOCATABLE :: ZDIR_ALB ! direct albedo
+REAL, DIMENSION(:,:,:), ALLOCATABLE :: ZSCA_ALB ! diffuse albedo
+REAL, DIMENSION(:,:,:),   ALLOCATABLE :: ZEMIS    ! emissivity
+REAL, DIMENSION(:,:),   ALLOCATABLE :: ZTSRAD   ! surface temperature
+!
+!
+INTEGER, DIMENSION(:,:),ALLOCATABLE :: IINDEX   ! indices of non-zero terms
+INTEGER, DIMENSION(:),ALLOCATABLE   :: IIND
+INTEGER                             :: JM
+!
+!------------------------------------------
+! Dummy pointers needed to correct an ifort Bug
+REAL, DIMENSION(:), POINTER :: DPTR_XZHAT
+REAL, DIMENSION(:), POINTER :: DPTR_XBMX1,DPTR_XBMX2,DPTR_XBMX3,DPTR_XBMX4
+REAL, DIMENSION(:), POINTER :: DPTR_XBMY1,DPTR_XBMY2,DPTR_XBMY3,DPTR_XBMY4
+REAL, DIMENSION(:), POINTER :: DPTR_XBFX1,DPTR_XBFX2,DPTR_XBFX3,DPTR_XBFX4
+REAL, DIMENSION(:), POINTER :: DPTR_XBFY1,DPTR_XBFY2,DPTR_XBFY3,DPTR_XBFY4
+CHARACTER(LEN=4), DIMENSION(:), POINTER :: DPTR_CLBCX,DPTR_CLBCY
+INTEGER, DIMENSION(:,:,:), POINTER :: DPTR_NKLIN_LBXU,DPTR_NKLIN_LBYU,DPTR_NKLIN_LBXV,DPTR_NKLIN_LBYV
+INTEGER, DIMENSION(:,:,:), POINTER :: DPTR_NKLIN_LBXW,DPTR_NKLIN_LBYW,DPTR_NKLIN_LBXM,DPTR_NKLIN_LBYM
+REAL, DIMENSION(:,:,:), POINTER :: DPTR_XCOEFLIN_LBXU,DPTR_XCOEFLIN_LBYU
+REAL, DIMENSION(:,:,:), POINTER :: DPTR_XCOEFLIN_LBXV,DPTR_XCOEFLIN_LBYV
+REAL, DIMENSION(:,:,:), POINTER :: DPTR_XCOEFLIN_LBXW,DPTR_XCOEFLIN_LBYW
+REAL, DIMENSION(:,:,:), POINTER :: DPTR_XCOEFLIN_LBXM,DPTR_XCOEFLIN_LBYM
+REAL, DIMENSION(:,:,:),   POINTER :: DPTR_XLBXUM,DPTR_XLBYUM,DPTR_XLBXVM,DPTR_XLBYVM
+REAL, DIMENSION(:,:,:),   POINTER :: DPTR_XLBXWM,DPTR_XLBYWM,DPTR_XLBXTHM,DPTR_XLBYTHM
+REAL, DIMENSION(:,:,:),   POINTER :: DPTR_XLBXTKEM,DPTR_XLBYTKEM
+REAL, DIMENSION(:,:,:,:),   POINTER :: DPTR_XLBXSVM,DPTR_XLBYSVM                
+REAL, DIMENSION(:,:,:,:), POINTER :: DPTR_XLBXRM,DPTR_XLBYRM
+REAL, DIMENSION(:,:,:),   POINTER ::  DPTR_XZZ
+REAL, DIMENSION(:,:,:), POINTER ::   DPTR_XLSUM,DPTR_XLSVM,DPTR_XLSWM,DPTR_XLSTHM,DPTR_XLSRVM
+REAL, DIMENSION(:,:,:), POINTER ::   DPTR_XLSUS,DPTR_XLSVS,DPTR_XLSWS,DPTR_XLSTHS,DPTR_XLSRVS
+REAL, DIMENSION(:,:),   POINTER ::   DPTR_XLSZWSM,DPTR_XLSZWSS
+!
+INTEGER                         ::  IIB,IJB,IIE,IJE,IDIMX,IDIMY,IMI
+!
+!-------------------------------------------------------------------------------
+!
+!*       0.    PROLOGUE
+!              --------
+! Compute relaxation coefficients without changing INI_DYNAMICS nor RELAXDEF
+!
+IF (CCLOUD == 'LIMA') THEN
+  LHORELAX_SVC1R3=LHORELAX_SVLIMA
+END IF
+!
+!
+NULLIFY(TZINITHALO2D_ll)
+NULLIFY(TZINITHALO3D_ll)
+!
+!*       1.    RETRIEVE LOGICAL UNIT NUMBER
+!              ----------------------------
+!
+ILUOUT = TLUOUT%NLU
+!
+!-------------------------------------------------------------------------------
+!
+!*       2.   END OF READING
+!             --------------
+!*       2.1  Read number of forcing fields
+!
+IF (LFORCING) THEN ! Retrieve the number of time-dependent forcings.
+  CALL IO_Field_read(TPINIFILE,'FRC',NFRC,IRESP)
+  IF ( (IRESP /= 0) .OR. (NFRC <=0) ) THEN
+    WRITE(ILUOUT,'(A/A)') &
+     "INI_MODEL_n ERROR: you want to read forcing variables from FMfile", &
+     "                   but no fields have been found by IO_Field_read"
+!callabortstop
+    CALL PRINT_MSG(NVERB_FATAL,'GEN','INI_MODEL_n','')
+  END IF
+END IF
+!
+! Modif PP for time evolving adv forcing
+  IF ( L2D_ADV_FRC ) THEN ! Retrieve the number of time-dependent forcings.
+    WRITE(ILUOUT,FMT=*) "INI_MODEL_n ENTER ADV_FORCING"
+    CALL IO_Field_read(TPINIFILE,'NADVFRC1',NADVFRC,IRESP)
+    IF ( (IRESP /= 0) .OR. (NADVFRC <=0) ) THEN
+      WRITE(ILUOUT,'(A/A)') &
+      "INI_MODELn ERROR: you want to read forcing ADV variables from FMfile", &
+      "                   but no fields have been found by IO_Field_read"
+    !callabortstop
+      CALL PRINT_MSG(NVERB_FATAL,'GEN','INI_MODEL_n','')
+    END IF
+    WRITE(ILUOUT,*) 'NADVFRC = ', NADVFRC
+END IF
+!
+IF ( L2D_REL_FRC ) THEN ! Retrieve the number of time-dependent forcings.
+    WRITE(ILUOUT,FMT=*) "INI_MODEL_n ENTER REL_FORCING"
+    CALL IO_Field_read(TPINIFILE,'NRELFRC1',NRELFRC,IRESP)
+    IF ( (IRESP /= 0) .OR. (NRELFRC <=0) ) THEN
+      WRITE(ILUOUT,'(A/A)') &
+      "INI_MODELn ERROR: you want to read forcing REL variables from FMfile", &
+      "                   but no fields have been found by IO_Field_read"
+    !callabortstop
+      CALL PRINT_MSG(NVERB_FATAL,'GEN','INI_MODEL_n','')
+    END IF
+    WRITE(ILUOUT,*) 'NRELFRC = ', NRELFRC
+END IF
+!*       2.2  Checks the position of vertical absorbing layer
+!
+IKU=NKMAX+2*JPVEXT
+!
+ALLOCATE(XZHAT(IKU))
+CALL IO_Field_read(TPINIFILE,'ZHAT',XZHAT)
+CALL IO_Field_read(TPINIFILE,'ZTOP',XZTOP)
+IF (XALZBOT>=XZHAT(IKU) .AND. LVE_RELAX) THEN
+  WRITE(ILUOUT,FMT=*) "INI_MODEL_n ERROR: you want to use vertical relaxation"
+  WRITE(ILUOUT,FMT=*) "                  but bottom of layer XALZBOT(",XALZBOT,")"
+  WRITE(ILUOUT,FMT=*) "                  is upper than model top    (",XZHAT(IKU),")"
+!callabortstop
+  CALL PRINT_MSG(NVERB_FATAL,'GEN','INI_MODEL_n','')
+END IF
+IF (LVE_RELAX) THEN
+ IF (XALZBOT>=XZHAT(IKU-4) ) THEN
+  WRITE(ILUOUT,FMT=*) "INI_MODEL_n WARNING: you want to use vertical relaxation"
+  WRITE(ILUOUT,FMT=*) "                    but the layer defined by XALZBOT(",XALZBOT,")"
+  WRITE(ILUOUT,FMT=*) "                    contains less than 5 model levels"
+ END IF
+END IF
+DEALLOCATE(XZHAT)
+!
+!*       2.3  Compute sizes of arrays of the extended sub-domain
+!
+CALL GET_DIM_EXT_ll('B',IIU,IJU)
+IIU_ll=NIMAX_ll + 2 * JPHEXT
+IJU_ll=NJMAX_ll + 2 * JPHEXT
+! initialize NIMAX and NJMAX for not updated versions regarding the parallelism
+! spawning,...
+CALL GET_DIM_PHYS_ll('B',NIMAX,NJMAX)
+!
+CALL GET_INDICE_ll( IIB,IJB,IIE,IJE)
+IDIMX = IIE - IIB + 1
+IDIMY = IJE - IJB + 1
+!
+NRR=0
+NRRL=0
+NRRI=0
+IF (CGETRVT /= 'SKIP' ) THEN
+  NRR = NRR+1
+  IDX_RVT = NRR
+END IF
+IF (CGETRCT /= 'SKIP' ) THEN
+  NRR = NRR+1
+  NRRL = NRRL+1
+  IDX_RCT = NRR
+END IF
+IF (CGETRRT /= 'SKIP' ) THEN
+  NRR = NRR+1
+  NRRL = NRRL+1
+  IDX_RRT = NRR
+END IF
+IF (CGETRIT /= 'SKIP' ) THEN
+  NRR = NRR+1
+  NRRI = NRRI+1
+  IDX_RIT = NRR
+END IF
+IF (CGETRST /= 'SKIP' ) THEN
+  NRR = NRR+1
+  NRRI = NRRI+1
+  IDX_RST = NRR
+END IF
+IF (CGETRGT /= 'SKIP' ) THEN
+  NRR = NRR+1
+  NRRI = NRRI+1
+  IDX_RGT = NRR
+END IF
+IF (CGETRHT /= 'SKIP' ) THEN
+  NRR = NRR+1
+  NRRI = NRRI+1
+  IDX_RHT = NRR
+END IF
+IF (NVERB >= 5) THEN
+  WRITE (UNIT=ILUOUT,FMT='("THERE ARE ",I2," WATER VARIABLES")') NRR
+  WRITE (UNIT=ILUOUT,FMT='("THERE ARE ",I2," LIQUID VARIABLES")') NRRL
+  WRITE (UNIT=ILUOUT,FMT='("THERE ARE ",I2," SOLID VARIABLES")') NRRI
+END IF
+!
+!*       2.4  Update NSV and floating indices for the current model
+!
+! 
+CALL UPDATE_NSV(KMI) 
+!
+!-------------------------------------------------------------------------------
+!
+!*       3.    ALLOCATE  MEMORY
+!              -----------------
+!
+!*       3.1   Module MODD_FIELD_n
+!
+IF (LMEAN_FIELD) THEN
+!
+  MEAN_COUNT = 0
+!
+  ALLOCATE(XUM_MEAN(IIU,IJU,IKU))      ; XUM_MEAN  = 0.0
+  ALLOCATE(XVM_MEAN(IIU,IJU,IKU))      ; XVM_MEAN  = 0.0
+  ALLOCATE(XWM_MEAN(IIU,IJU,IKU))      ; XWM_MEAN  = 0.0
+  ALLOCATE(XTHM_MEAN(IIU,IJU,IKU))     ; XTHM_MEAN = 0.0
+  ALLOCATE(XTEMPM_MEAN(IIU,IJU,IKU))   ; XTEMPM_MEAN = 0.0
+  IF (CTURB/='NONE') THEN
+    ALLOCATE(XTKEM_MEAN(IIU,IJU,IKU))
+    XTKEM_MEAN = 0.0
+  ELSE
+    ALLOCATE(XTKEM_MEAN(0,0,0))
+  END IF
+  ALLOCATE(XPABSM_MEAN(IIU,IJU,IKU))   ; XPABSM_MEAN = 0.0
+!
+  ALLOCATE(XU2_MEAN(IIU,IJU,IKU))      ; XU2_MEAN  = 0.0
+  ALLOCATE(XV2_MEAN(IIU,IJU,IKU))      ; XV2_MEAN  = 0.0
+  ALLOCATE(XW2_MEAN(IIU,IJU,IKU))      ; XW2_MEAN  = 0.0
+  ALLOCATE(XTH2_MEAN(IIU,IJU,IKU))     ; XTH2_MEAN = 0.0
+  ALLOCATE(XTEMP2_MEAN(IIU,IJU,IKU))   ; XTEMP2_MEAN = 0.0
+  ALLOCATE(XPABS2_MEAN(IIU,IJU,IKU))   ; XPABS2_MEAN = 0.0
+!
+  ALLOCATE(XUM_MAX(IIU,IJU,IKU))      ; XUM_MAX  = -1.E20
+  ALLOCATE(XVM_MAX(IIU,IJU,IKU))      ; XVM_MAX  = -1.E20
+  ALLOCATE(XWM_MAX(IIU,IJU,IKU))      ; XWM_MAX  = -1.E20
+  ALLOCATE(XTHM_MAX(IIU,IJU,IKU))     ; XTHM_MAX = 0.0
+  ALLOCATE(XTEMPM_MAX(IIU,IJU,IKU))   ; XTEMPM_MAX = 0.0
+  IF (CTURB/='NONE') THEN
+    ALLOCATE(XTKEM_MAX(IIU,IJU,IKU))
+    XTKEM_MAX = 0.0
+  ELSE
+    ALLOCATE(XTKEM_MAX(0,0,0))
+  END IF
+  ALLOCATE(XPABSM_MAX(IIU,IJU,IKU))   ; XPABSM_MAX = 0.0
+ELSE
+  ALLOCATE(XUM_MEAN(0,0,0))
+  ALLOCATE(XVM_MEAN(0,0,0))
+  ALLOCATE(XWM_MEAN(0,0,0))
+  ALLOCATE(XTHM_MEAN(0,0,0))
+  ALLOCATE(XTEMPM_MEAN(0,0,0))
+  ALLOCATE(XTKEM_MEAN(0,0,0))
+  ALLOCATE(XPABSM_MEAN(0,0,0))
+!
+  ALLOCATE(XU2_MEAN(0,0,0))
+  ALLOCATE(XV2_MEAN(0,0,0))
+  ALLOCATE(XW2_MEAN(0,0,0))
+  ALLOCATE(XTH2_MEAN(0,0,0))
+  ALLOCATE(XTEMP2_MEAN(0,0,0))
+  ALLOCATE(XPABS2_MEAN(0,0,0))
+!
+  ALLOCATE(XUM_MAX(0,0,0))
+  ALLOCATE(XVM_MAX(0,0,0))
+  ALLOCATE(XWM_MAX(0,0,0))
+  ALLOCATE(XTHM_MAX(0,0,0))
+  ALLOCATE(XTEMPM_MAX(0,0,0))
+  ALLOCATE(XTKEM_MAX(0,0,0))
+  ALLOCATE(XPABSM_MAX(0,0,0))
+END IF
+!
+IF ((CUVW_ADV_SCHEME(1:3)=='CEN') .AND. (CTEMP_SCHEME == 'LEFR') ) THEN
+  ALLOCATE(XUM(IIU,IJU,IKU))
+  ALLOCATE(XVM(IIU,IJU,IKU))
+  ALLOCATE(XWM(IIU,IJU,IKU))
+  ALLOCATE(XDUM(IIU,IJU,IKU))
+  ALLOCATE(XDVM(IIU,IJU,IKU))
+  ALLOCATE(XDWM(IIU,IJU,IKU))
+  IF (CCONF == 'START') THEN
+    XUM  = 0.0
+    XVM  = 0.0
+    XWM  = 0.0
+    XDUM  = 0.0
+    XDVM  = 0.0
+    XDWM  = 0.0
+  END IF
+ELSE
+  ALLOCATE(XUM(0,0,0))
+  ALLOCATE(XVM(0,0,0))
+  ALLOCATE(XWM(0,0,0))
+  ALLOCATE(XDUM(0,0,0))
+  ALLOCATE(XDVM(0,0,0))
+  ALLOCATE(XDWM(0,0,0))
+END IF
+!
+ALLOCATE(XUT(IIU,IJU,IKU))      ; XUT  = 0.0
+ALLOCATE(XVT(IIU,IJU,IKU))      ; XVT  = 0.0
+ALLOCATE(XWT(IIU,IJU,IKU))      ; XWT  = 0.0
+ALLOCATE(XTHT(IIU,IJU,IKU))     ; XTHT = 0.0
+ALLOCATE(XRUS(IIU,IJU,IKU))     ; XRUS = 0.0
+ALLOCATE(XRVS(IIU,IJU,IKU))     ; XRVS = 0.0
+ALLOCATE(XRWS(IIU,IJU,IKU))     ; XRWS = 0.0
+ALLOCATE(XRUS_PRES(IIU,IJU,IKU)); XRUS_PRES = 0.0
+ALLOCATE(XRVS_PRES(IIU,IJU,IKU)); XRVS_PRES = 0.0
+ALLOCATE(XRWS_PRES(IIU,IJU,IKU)); XRWS_PRES = 0.0
+ALLOCATE(XRTHS(IIU,IJU,IKU))    ; XRTHS = 0.0
+!$acc enter data copyin(XRTHS)
+ALLOCATE(XRTHS_CLD(IIU,IJU,IKU)); XRTHS_CLD = 0.0
+IF (CTURB /= 'NONE') THEN
+  ALLOCATE(XTKET(IIU,IJU,IKU))
+  ALLOCATE(XRTKES(IIU,IJU,IKU))
+  ALLOCATE(XRTKEMS(IIU,IJU,IKU)); XRTKEMS = 0.0
+  ALLOCATE(XWTHVMF(IIU,IJU,IKU))
+  ALLOCATE(XDYP(IIU,IJU,IKU))
+  ALLOCATE(XTHP(IIU,IJU,IKU))
+  ALLOCATE(XTR(IIU,IJU,IKU))
+  ALLOCATE(XDISS(IIU,IJU,IKU))
+  ALLOCATE(XLEM(IIU,IJU,IKU))
+  XTKEMIN=XKEMIN
+  XCED   =XCEDIS
+ELSE
+  ALLOCATE(XTKET(0,0,0))
+  ALLOCATE(XRTKES(0,0,0))
+  ALLOCATE(XRTKEMS(0,0,0))
+  ALLOCATE(XWTHVMF(0,0,0))
+  ALLOCATE(XDYP(0,0,0))
+  ALLOCATE(XTHP(0,0,0))
+  ALLOCATE(XTR(0,0,0))
+  ALLOCATE(XDISS(0,0,0))
+  ALLOCATE(XLEM(0,0,0))
+END IF
+IF (CTOM == 'TM06') THEN
+  ALLOCATE(XBL_DEPTH(IIU,IJU))
+ELSE
+  ALLOCATE(XBL_DEPTH(0,0))
+END IF
+IF (LRMC01) THEN
+  ALLOCATE(XSBL_DEPTH(IIU,IJU))
+ELSE
+  ALLOCATE(XSBL_DEPTH(0,0))
+END IF
+!
+ALLOCATE(XPABSM(IIU,IJU,IKU)) ; XPABSM = 0.0
+ALLOCATE(XPABST(IIU,IJU,IKU)) ; XPABST = 0.0
+!
+ALLOCATE(XRT(IIU,IJU,IKU,NRR)) ;     XRT = 0.0
+ALLOCATE(XRRS(IIU,IJU,IKU,NRR)) ;    XRRS = 0.0
+ALLOCATE(XRRS_CLD(IIU,IJU,IKU,NRR)); XRRS_CLD = 0.0
+!
+IF (CTURB /= 'NONE' .AND. NRR>1) THEN
+  ALLOCATE(XSRCT(IIU,IJU,IKU))
+  ALLOCATE(XSIGS(IIU,IJU,IKU))
+ELSE
+  ALLOCATE(XSRCT(0,0,0))
+  ALLOCATE(XSIGS(0,0,0))
+END IF
+!
+IF (NRR>1) THEN
+  ALLOCATE(XCLDFR(IIU,IJU,IKU))
+  ALLOCATE(XRAINFR(IIU,IJU,IKU))
+ELSE
+  ALLOCATE(XCLDFR(0,0,0))
+  ALLOCATE(XRAINFR(0,0,0))
+END IF
+!
+ALLOCATE(XSVT(IIU,IJU,IKU,NSV)) ;     XSVT  = 0.
+ALLOCATE(XRSVS(IIU,IJU,IKU,NSV));     XRSVS = 0.
+ALLOCATE(XRSVS_CLD(IIU,IJU,IKU,NSV)); XRSVS_CLD = 0.0
+ALLOCATE(XZWS(IIU,IJU)) ;             XZWS(:,:) = XZWS_DEFAULT
+!
+IF (LPASPOL) THEN
+  ALLOCATE( XATC(IIU,IJU,IKU,NSV_PP) )
+  XATC = 0.
+ELSE
+  ALLOCATE( XATC(0,0,0,0))
+END IF
+!
+IF(LBLOWSNOW) THEN
+  ALLOCATE(XSNWCANO(IIU,IJU,NBLOWSNOW_2D))
+  ALLOCATE(XRSNWCANOS(IIU,IJU,NBLOWSNOW_2D))
+  XSNWCANO(:,:,:) = 0.0
+  XRSNWCANOS(:,:,:) = 0.0
+ELSE
+  ALLOCATE(XSNWCANO(0,0,0))
+  ALLOCATE(XRSNWCANOS(0,0,0))
+END IF
+!
+!*       3.2   Module MODD_GRID_n and MODD_METRICS_n
+!
+IF (LCARTESIAN) THEN
+  ALLOCATE(XLON(0,0))
+  ALLOCATE(XLAT(0,0))
+  ALLOCATE(XMAP(0,0))
+ELSE
+  ALLOCATE(XLON(IIU,IJU))
+  ALLOCATE(XLAT(IIU,IJU))
+  ALLOCATE(XMAP(IIU,IJU))
+END IF
+ALLOCATE(XXHAT(IIU))
+ALLOCATE(XDXHAT(IIU))
+ALLOCATE(XYHAT(IJU))
+ALLOCATE(XDYHAT(IJU))
+ALLOCATE(XZS(IIU,IJU))
+ALLOCATE(XZSMT(IIU,IJU))
+ALLOCATE(XZZ(IIU,IJU,IKU))
+ALLOCATE(XZHAT(IKU))
+ALLOCATE(XDIRCOSZW(IIU,IJU))
+ALLOCATE(XDIRCOSXW(IIU,IJU))
+ALLOCATE(XDIRCOSYW(IIU,IJU))
+ALLOCATE(XCOSSLOPE(IIU,IJU))
+ALLOCATE(XSINSLOPE(IIU,IJU))
+!
+ALLOCATE(XDXX(IIU,IJU,IKU))
+ALLOCATE(XDYY(IIU,IJU,IKU))
+ALLOCATE(XDZX(IIU,IJU,IKU))
+ALLOCATE(XDZY(IIU,IJU,IKU))
+ALLOCATE(XDZZ(IIU,IJU,IKU))
+!$acc enter data create(XDXX,XDYY,XDZZ,XDZX,XDZY)
+!
+!*       3.3   Modules MODD_REF and  MODD_REF_n
+!
+IF (KMI == 1) THEN
+  ALLOCATE(XRHODREFZ(IKU),XTHVREFZ(IKU))
+ELSE
+  !Do not allocate XRHODREFZ and XTHVREFZ because they are the same on all grids (not 'n' variables)
+END IF
+ALLOCATE(XRHODREF(IIU,IJU,IKU))
+ALLOCATE(XTHVREF(IIU,IJU,IKU))
+ALLOCATE(XEXNREF(IIU,IJU,IKU))
+ALLOCATE(XRHODJ(IIU,IJU,IKU))
+!$acc enter data create(XRHODJ)
+IF (CEQNSYS=='DUR' .AND. LUSERV) THEN
+  ALLOCATE(XRVREF(IIU,IJU,IKU))
+ELSE
+  ALLOCATE(XRVREF(0,0,0))
+END IF
+!
+!*       3.4   Module MODD_CURVCOR_n
+!
+IF (LTHINSHELL) THEN
+  ALLOCATE(XCORIOX(0,0))
+  ALLOCATE(XCORIOY(0,0))
+ELSE
+  ALLOCATE(XCORIOX(IIU,IJU))
+  ALLOCATE(XCORIOY(IIU,IJU))
+END IF
+  ALLOCATE(XCORIOZ(IIU,IJU))
+IF (LCARTESIAN) THEN
+  ALLOCATE(XCURVX(0,0))
+  ALLOCATE(XCURVY(0,0))
+ELSE
+  ALLOCATE(XCURVX(IIU,IJU))
+  ALLOCATE(XCURVY(IIU,IJU))
+END IF
+!
+!*       3.5   Module MODD_DYN_n
+!
+CALL GET_DIM_EXT_ll('Y',IIY,IJY)
+IF (L2D) THEN
+  ALLOCATE(XBFY(IIY,IJY,IKU))
+ELSE
+  ALLOCATE(XBFY(IJY,IIY,IKU)) ! transposition needed by the optimisation of the
+                              ! FFT solver
+END IF
+CALL GET_DIM_EXT_ll('B',IIU_B,IJU_B)
+ALLOCATE(XBFB(IIU_B,IJU_B,IKU))
+ALLOCATE(XAF_ZS(IIU_B,IJU_B,IKU))
+ALLOCATE(XBF_ZS(IIU_B,IJU_B,IKU))
+ALLOCATE(XCF_ZS(IIU_B,IJU_B,IKU))
+ALLOCATE(XDXATH_ZS(IIU_B,IJU_B))
+ALLOCATE(XDYATH_ZS(IIU_B,IJU_B))
+ALLOCATE(XRHO_ZS(IIU_B,IJU_B,IKU))
+ALLOCATE(XA_K(IKU))
+ALLOCATE(XB_K(IKU))
+ALLOCATE(XC_K(IKU))
+ALLOCATE(XD_K(IKU))
+
+CALL GET_DIM_EXTZ_ll('SXP2_YP1_Z',IIU_SXP2_YP1_Z_ll,IJU_SXP2_YP1_Z_ll,IKU_SXP2_YP1_Z_ll)
+ALLOCATE(XBF_SXP2_YP1_Z(IIU_SXP2_YP1_Z_ll,IJU_SXP2_YP1_Z_ll,IKU_SXP2_YP1_Z_ll))
+ALLOCATE(XAF(IKU),XCF(IKU))
+ALLOCATE(XTRIGSX(3*IIU_ll))
+ALLOCATE(XTRIGSY(3*IJU_ll))
+ALLOCATE(XRHOM(IKU))
+ALLOCATE(XALK(IKU))
+ALLOCATE(XALKW(IKU))
+ALLOCATE(XALKBAS(IKU))
+ALLOCATE(XALKWBAS(IKU))
+!
+IF ( LHORELAX_UVWTH .OR. LHORELAX_RV .OR.                                  &
+     LHORELAX_RC .OR. LHORELAX_RR .OR. LHORELAX_RI  .OR. LHORELAX_RS  .OR. &
+     LHORELAX_RG .OR. LHORELAX_RH .OR. LHORELAX_TKE .OR.                   &
+     ANY(LHORELAX_SV) ) THEN
+  ALLOCATE(XKURELAX(IIU,IJU))
+  ALLOCATE(XKVRELAX(IIU,IJU))
+  ALLOCATE(XKWRELAX(IIU,IJU))
+  ALLOCATE(LMASK_RELAX(IIU,IJU))
+ELSE
+  ALLOCATE(XKURELAX(0,0))
+  ALLOCATE(XKVRELAX(0,0))
+  ALLOCATE(XKWRELAX(0,0))
+  ALLOCATE(LMASK_RELAX(0,0))
+END IF
+!
+! Additional fields for truly horizontal diffusion (Module MODD_DYNZD$n)
+IF (LZDIFFU) THEN
+  CALL INIT_TYPE_ZDIFFU_HALO2(XZDIFFU_HALO2)
+ELSE
+  CALL INIT_TYPE_ZDIFFU_HALO2(XZDIFFU_HALO2,0)
+ENDIF
+!
+!*       3.6   Larger Scale variables (Module MODD_LSFIELD$n)
+!
+!
+! upper relaxation part
+!
+ALLOCATE(XLSUM(IIU,IJU,IKU))    ; XLSUM  = 0.0
+ALLOCATE(XLSVM(IIU,IJU,IKU))    ; XLSVM  = 0.0
+ALLOCATE(XLSWM(IIU,IJU,IKU))    ; XLSWM  = 0.0
+ALLOCATE(XLSTHM(IIU,IJU,IKU))   ; XLSTHM = 0.0
+IF ( NRR > 0 ) THEN
+  ALLOCATE(XLSRVM(IIU,IJU,IKU)) ; XLSRVM = 0.0
+ELSE
+  ALLOCATE(XLSRVM(0,0,0))
+END IF
+ALLOCATE(XLSZWSM(IIU,IJU)) ; XLSZWSM = -1.
+!
+!  lbc part
+!
+IF ( L1D) THEN                         ! 1D case
+!
+  NSIZELBX_ll=0
+  NSIZELBXU_ll=0
+  NSIZELBY_ll=0
+  NSIZELBYV_ll=0
+  NSIZELBXTKE_ll=0
+  NSIZELBXR_ll=0
+  NSIZELBXSV_ll=0
+  NSIZELBYTKE_ll=0
+  NSIZELBYR_ll=0
+  NSIZELBYSV_ll=0
+  ALLOCATE(XLBXUM(0,0,0))
+  ALLOCATE(XLBYUM(0,0,0))
+  ALLOCATE(XLBXVM(0,0,0))
+  ALLOCATE(XLBYVM(0,0,0))
+  ALLOCATE(XLBXWM(0,0,0))
+  ALLOCATE(XLBYWM(0,0,0))
+  ALLOCATE(XLBXTHM(0,0,0))
+  ALLOCATE(XLBYTHM(0,0,0))
+  ALLOCATE(XLBXTKEM(0,0,0))
+  ALLOCATE(XLBYTKEM(0,0,0))
+  ALLOCATE(XLBXRM(0,0,0,0))
+  ALLOCATE(XLBYRM(0,0,0,0))
+  ALLOCATE(XLBXSVM(0,0,0,0))
+  ALLOCATE(XLBYSVM(0,0,0,0))
+!
+ELSEIF( L2D ) THEN                         ! 2D case
+!
+  NSIZELBY_ll=0
+  NSIZELBYV_ll=0
+  NSIZELBYTKE_ll=0
+  NSIZELBYR_ll=0
+  NSIZELBYSV_ll=0
+  ALLOCATE(XLBYUM(0,0,0))
+  ALLOCATE(XLBYVM(0,0,0))
+  ALLOCATE(XLBYWM(0,0,0))
+  ALLOCATE(XLBYTHM(0,0,0))
+  ALLOCATE(XLBYTKEM(0,0,0))
+  ALLOCATE(XLBYRM(0,0,0,0))
+  ALLOCATE(XLBYSVM(0,0,0,0))
+!
+  CALL GET_SIZEX_LB(NIMAX_ll,NJMAX_ll,NRIMX,  &
+       IISIZEXF,IJSIZEXF,IISIZEXFU,IJSIZEXFU, &
+       IISIZEX4,IJSIZEX4,IISIZEX2,IJSIZEX2)
+!
+  IF ( LHORELAX_UVWTH ) THEN
+    NSIZELBX_ll=2*NRIMX+2*JPHEXT
+    NSIZELBXU_ll=2*NRIMX+2*JPHEXT
+    ALLOCATE(XLBXUM(IISIZEXFU,IJSIZEXFU,IKU))
+    ALLOCATE(XLBXVM(IISIZEXF,IJSIZEXF,IKU))
+    ALLOCATE(XLBXWM(IISIZEXF,IJSIZEXF,IKU))
+    ALLOCATE(XLBXTHM(IISIZEXF,IJSIZEXF,IKU))
+  ELSE
+    NSIZELBX_ll=2*JPHEXT      ! 2
+    NSIZELBXU_ll=2*(JPHEXT+1) ! 4
+    ALLOCATE(XLBXUM(IISIZEX4,IJSIZEX4,IKU))
+    ALLOCATE(XLBXVM(IISIZEX2,IJSIZEX2,IKU))
+    ALLOCATE(XLBXWM(IISIZEX2,IJSIZEX2,IKU))
+    ALLOCATE(XLBXTHM(IISIZEX2,IJSIZEX2,IKU))
+  END IF
+!
+  IF (CTURB /= 'NONE') THEN
+    IF ( LHORELAX_TKE) THEN
+      NSIZELBXTKE_ll=2* NRIMX+2*JPHEXT
+      ALLOCATE(XLBXTKEM(IISIZEXF,IJSIZEXF,IKU))
+    ELSE
+      NSIZELBXTKE_ll=2*JPHEXT  ! 2
+      ALLOCATE(XLBXTKEM(IISIZEX2,IJSIZEX2,IKU))
+    END IF
+  ELSE
+    NSIZELBXTKE_ll=0
+    ALLOCATE(XLBXTKEM(0,0,0))
+  END IF
+  !
+  IF ( NRR > 0 ) THEN
+    IF (LHORELAX_RV .OR. LHORELAX_RC .OR. LHORELAX_RR .OR. LHORELAX_RI    &
+         .OR. LHORELAX_RS .OR. LHORELAX_RG .OR. LHORELAX_RH               &
+       ) THEN
+      NSIZELBXR_ll=2* NRIMX+2*JPHEXT
+      ALLOCATE(XLBXRM(IISIZEXF,IJSIZEXF,IKU,NRR))
+    ELSE
+      NSIZELBXR_ll=2*JPHEXT  ! 2
+      ALLOCATE(XLBXRM(IISIZEX2,IJSIZEX2,IKU,NRR))
+    ENDIF
+  ELSE
+    NSIZELBXR_ll=0
+    ALLOCATE(XLBXRM(0,0,0,0))
+  END IF
+  !
+  IF ( NSV > 0 ) THEN
+    IF ( ANY( LHORELAX_SV(:)) ) THEN
+      NSIZELBXSV_ll=2* NRIMX+2*JPHEXT
+      ALLOCATE(XLBXSVM(IISIZEXF,IJSIZEXF,IKU,NSV))
+    ELSE
+      NSIZELBXSV_ll=2*JPHEXT  ! 2
+      ALLOCATE(XLBXSVM(IISIZEX2,IJSIZEX2,IKU,NSV))
+    END IF
+  ELSE
+    NSIZELBXSV_ll=0
+    ALLOCATE(XLBXSVM(0,0,0,0))
+  END IF
+!
+ELSE                                   ! 3D case
+!
+!
+  CALL GET_SIZEX_LB(NIMAX_ll,NJMAX_ll,NRIMX,               &
+                    IISIZEXF,IJSIZEXF,IISIZEXFU,IJSIZEXFU, &
+                    IISIZEX4,IJSIZEX4,IISIZEX2,IJSIZEX2)
+  CALL GET_SIZEY_LB(NIMAX_ll,NJMAX_ll,NRIMY,               &
+                    IISIZEYF,IJSIZEYF,IISIZEYFV,IJSIZEYFV, &
+                    IISIZEY4,IJSIZEY4,IISIZEY2,IJSIZEY2)
+!
+! check if local domain not to small for NRIMX NRIMY
+!
+  IF ( CLBCX(1) /= 'CYCL' )  THEN
+     IF ( NRIMX .GT. IDIMX )   THEN
+        WRITE(*,'(A,I8,A/A,2I8,/A)') "Processor=", IP-1, &
+             " :: INI_MODEL_n ERROR:  ( NRIMX  > IDIMX )  ", &
+             " Local domain to small for relaxation NRIMX,IDIMX ", &
+             NRIMX,IDIMX ,&
+             " change relaxation parameters or number of processors "
+        call Print_msg(NVERB_FATAL,'GEN','INI_MODEL_n','')
+     END IF
+  END IF
+  IF ( CLBCY(1) /= 'CYCL' ) THEN
+     IF ( NRIMY .GT. IDIMY )  THEN
+        WRITE(*,'(A,I8,A/A,2I8,/A)') "Processor=", IP-1, &
+             " :: INI_MODEL_n ERROR:  ( NRIMY > IDIMY )  ", &
+             " Local domain to small for relaxation NRIMY,IDIMY ", &
+             NRIMY,IDIMY ,&
+             " change relaxation parameters or number of processors "
+        call Print_msg(NVERB_FATAL,'GEN','INI_MODEL_n','')
+     END IF
+  END IF
+IF ( LHORELAX_UVWTH ) THEN
+    NSIZELBX_ll=2*NRIMX+2*JPHEXT
+    NSIZELBXU_ll=2*NRIMX+2*JPHEXT
+    NSIZELBY_ll=2*NRIMY+2*JPHEXT
+    NSIZELBYV_ll=2*NRIMY+2*JPHEXT
+    ALLOCATE(XLBXUM(IISIZEXFU,IJSIZEXFU,IKU))
+    ALLOCATE(XLBYUM(IISIZEYF,IJSIZEYF,IKU))
+    ALLOCATE(XLBXVM(IISIZEXF,IJSIZEXF,IKU))
+    ALLOCATE(XLBYVM(IISIZEYFV,IJSIZEYFV,IKU))
+    ALLOCATE(XLBXWM(IISIZEXF,IJSIZEXF,IKU))
+    ALLOCATE(XLBYWM(IISIZEYF,IJSIZEYF,IKU))
+    ALLOCATE(XLBXTHM(IISIZEXF,IJSIZEXF,IKU))
+    ALLOCATE(XLBYTHM(IISIZEYF,IJSIZEYF,IKU))
+  ELSE
+    NSIZELBX_ll=2*JPHEXT  ! 2
+    NSIZELBXU_ll=2*(JPHEXT+1) ! 4
+    NSIZELBY_ll=2*JPHEXT  ! 2
+    NSIZELBYV_ll=2*(JPHEXT+1) ! 4
+    ALLOCATE(XLBXUM(IISIZEX4,IJSIZEX4,IKU))
+    ALLOCATE(XLBYUM(IISIZEY2,IJSIZEY2,IKU))
+    ALLOCATE(XLBXVM(IISIZEX2,IJSIZEX2,IKU))
+    ALLOCATE(XLBYVM(IISIZEY4,IJSIZEY4,IKU))
+    ALLOCATE(XLBXWM(IISIZEX2,IJSIZEX2,IKU))
+    ALLOCATE(XLBYWM(IISIZEY2,IJSIZEY2,IKU))
+    ALLOCATE(XLBXTHM(IISIZEX2,IJSIZEX2,IKU))
+    ALLOCATE(XLBYTHM(IISIZEY2,IJSIZEY2,IKU))
+  END IF
+  !
+  IF (CTURB /= 'NONE') THEN
+    IF ( LHORELAX_TKE) THEN
+      NSIZELBXTKE_ll=2*NRIMX+2*JPHEXT
+      NSIZELBYTKE_ll=2*NRIMY+2*JPHEXT
+      ALLOCATE(XLBXTKEM(IISIZEXF,IJSIZEXF,IKU))
+      ALLOCATE(XLBYTKEM(IISIZEYF,IJSIZEYF,IKU))
+    ELSE
+      NSIZELBXTKE_ll=2*JPHEXT  ! 2
+      NSIZELBYTKE_ll=2*JPHEXT  ! 2
+      ALLOCATE(XLBXTKEM(IISIZEX2,IJSIZEX2,IKU))
+      ALLOCATE(XLBYTKEM(IISIZEY2,IJSIZEY2,IKU))
+    END IF
+  ELSE
+    NSIZELBXTKE_ll=0
+    NSIZELBYTKE_ll=0
+    ALLOCATE(XLBXTKEM(0,0,0))
+    ALLOCATE(XLBYTKEM(0,0,0))
+  END IF
+  !
+  IF ( NRR > 0 ) THEN
+    IF (LHORELAX_RV .OR. LHORELAX_RC .OR. LHORELAX_RR .OR. LHORELAX_RI    &
+          .OR. LHORELAX_RS .OR. LHORELAX_RG .OR. LHORELAX_RH              &
+       ) THEN
+      NSIZELBXR_ll=2*NRIMX+2*JPHEXT
+      NSIZELBYR_ll=2*NRIMY+2*JPHEXT
+      ALLOCATE(XLBXRM(IISIZEXF,IJSIZEXF,IKU,NRR))
+      ALLOCATE(XLBYRM(IISIZEYF,IJSIZEYF,IKU,NRR))
+    ELSE
+      NSIZELBXR_ll=2*JPHEXT  ! 2
+      NSIZELBYR_ll=2*JPHEXT  ! 2
+      ALLOCATE(XLBXRM(IISIZEX2,IJSIZEX2,IKU,NRR))
+      ALLOCATE(XLBYRM(IISIZEY2,IJSIZEY2,IKU,NRR))
+    ENDIF
+  ELSE
+    NSIZELBXR_ll=0
+    NSIZELBYR_ll=0
+    ALLOCATE(XLBXRM(0,0,0,0))
+    ALLOCATE(XLBYRM(0,0,0,0))
+  END IF
+  !
+  IF ( NSV > 0 ) THEN
+    IF ( ANY( LHORELAX_SV(:)) ) THEN
+      NSIZELBXSV_ll=2*NRIMX+2*JPHEXT
+      NSIZELBYSV_ll=2*NRIMY+2*JPHEXT
+      ALLOCATE(XLBXSVM(IISIZEXF,IJSIZEXF,IKU,NSV))
+      ALLOCATE(XLBYSVM(IISIZEYF,IJSIZEYF,IKU,NSV))
+    ELSE
+      NSIZELBXSV_ll=2*JPHEXT  ! 2
+      NSIZELBYSV_ll=2*JPHEXT  ! 2
+      ALLOCATE(XLBXSVM(IISIZEX2,IJSIZEX2,IKU,NSV))
+      ALLOCATE(XLBYSVM(IISIZEY2,IJSIZEY2,IKU,NSV))
+    END IF
+  ELSE
+    NSIZELBXSV_ll=0
+    NSIZELBYSV_ll=0
+    ALLOCATE(XLBXSVM(0,0,0,0))
+    ALLOCATE(XLBYSVM(0,0,0,0))
+  END IF
+END IF      ! END OF THE IF STRUCTURE ON THE MODEL DIMENSION
+!
+!
+IF ( KMI > 1 ) THEN 
+  ! it has been assumed that the THeta field used the largest rim area compared
+  ! to the others prognostic variables, if it is not the case, you must change
+  ! these lines
+  ALLOCATE(XCOEFLIN_LBXM(SIZE(XLBXTHM,1),SIZE(XLBXTHM,2),SIZE(XLBXTHM,3)))
+  ALLOCATE(   NKLIN_LBXM(SIZE(XLBXTHM,1),SIZE(XLBXTHM,2),SIZE(XLBXTHM,3)))
+  ALLOCATE(XCOEFLIN_LBYM(SIZE(XLBYTHM,1),SIZE(XLBYTHM,2),SIZE(XLBYTHM,3)))
+  ALLOCATE(   NKLIN_LBYM(SIZE(XLBYTHM,1),SIZE(XLBYTHM,2),SIZE(XLBYTHM,3)))
+  ALLOCATE(XCOEFLIN_LBXU(SIZE(XLBXUM,1),SIZE(XLBXUM,2),SIZE(XLBXUM,3)))
+  ALLOCATE(   NKLIN_LBXU(SIZE(XLBXUM,1),SIZE(XLBXUM,2),SIZE(XLBXUM,3)))
+  ALLOCATE(XCOEFLIN_LBYU(SIZE(XLBYUM,1),SIZE(XLBYUM,2),SIZE(XLBYUM,3)))
+  ALLOCATE(   NKLIN_LBYU(SIZE(XLBYUM,1),SIZE(XLBYUM,2),SIZE(XLBYUM,3)))
+  ALLOCATE(XCOEFLIN_LBXV(SIZE(XLBXVM,1),SIZE(XLBXVM,2),SIZE(XLBXVM,3)))
+  ALLOCATE(   NKLIN_LBXV(SIZE(XLBXVM,1),SIZE(XLBXVM,2),SIZE(XLBXVM,3)))
+  ALLOCATE(XCOEFLIN_LBYV(SIZE(XLBYVM,1),SIZE(XLBYVM,2),SIZE(XLBYVM,3)))
+  ALLOCATE(   NKLIN_LBYV(SIZE(XLBYVM,1),SIZE(XLBYVM,2),SIZE(XLBYVM,3)))
+  ALLOCATE(XCOEFLIN_LBXW(SIZE(XLBXWM,1),SIZE(XLBXWM,2),SIZE(XLBXWM,3)))
+  ALLOCATE(   NKLIN_LBXW(SIZE(XLBXWM,1),SIZE(XLBXWM,2),SIZE(XLBXWM,3)))
+  ALLOCATE(XCOEFLIN_LBYW(SIZE(XLBYWM,1),SIZE(XLBYWM,2),SIZE(XLBYWM,3)))
+  ALLOCATE(   NKLIN_LBYW(SIZE(XLBYWM,1),SIZE(XLBYWM,2),SIZE(XLBYWM,3)))
+ELSE
+  ALLOCATE(XCOEFLIN_LBXM(0,0,0))
+  ALLOCATE(   NKLIN_LBXM(0,0,0))
+  ALLOCATE(XCOEFLIN_LBYM(0,0,0))
+  ALLOCATE(   NKLIN_LBYM(0,0,0))
+  ALLOCATE(XCOEFLIN_LBXU(0,0,0))
+  ALLOCATE(   NKLIN_LBXU(0,0,0))
+  ALLOCATE(XCOEFLIN_LBYU(0,0,0))
+  ALLOCATE(   NKLIN_LBYU(0,0,0))
+  ALLOCATE(XCOEFLIN_LBXV(0,0,0))
+  ALLOCATE(   NKLIN_LBXV(0,0,0))
+  ALLOCATE(XCOEFLIN_LBYV(0,0,0))
+  ALLOCATE(   NKLIN_LBYV(0,0,0))
+  ALLOCATE(XCOEFLIN_LBXW(0,0,0))
+  ALLOCATE(   NKLIN_LBXW(0,0,0))
+  ALLOCATE(XCOEFLIN_LBYW(0,0,0))
+  ALLOCATE(   NKLIN_LBYW(0,0,0))
+END IF
+!
+!  allocation of the LS fields for vertical relaxation and numerical diffusion
+IF( .NOT. LSTEADYLS )  THEN
+!
+  ALLOCATE(XLSUS(SIZE(XLSUM,1),SIZE(XLSUM,2),SIZE(XLSUM,3)))
+  ALLOCATE(XLSVS(SIZE(XLSVM,1),SIZE(XLSVM,2),SIZE(XLSVM,3)))
+  ALLOCATE(XLSWS(SIZE(XLSWM,1),SIZE(XLSWM,2),SIZE(XLSWM,3)))
+  ALLOCATE(XLSTHS(SIZE(XLSTHM,1),SIZE(XLSTHM,2),SIZE(XLSTHM,3)))
+  ALLOCATE(XLSRVS(SIZE(XLSRVM,1),SIZE(XLSRVM,2),SIZE(XLSRVM,3)))
+  ALLOCATE(XLSZWSS(SIZE(XLSZWSM,1),SIZE(XLSZWSM,2)))
+!
+ELSE
+!
+  ALLOCATE(XLSUS(0,0,0))
+  ALLOCATE(XLSVS(0,0,0))
+  ALLOCATE(XLSWS(0,0,0))
+  ALLOCATE(XLSTHS(0,0,0))
+  ALLOCATE(XLSRVS(0,0,0))
+  ALLOCATE(XLSZWSS(0,0))
+!
+END IF
+!  allocation of the LB fields for horizontal relaxation and Lateral Boundaries
+IF( .NOT. ( LSTEADYLS .AND. KMI==1 ) )  THEN
+!
+  ALLOCATE(XLBXTKES(SIZE(XLBXTKEM,1),SIZE(XLBXTKEM,2),SIZE(XLBXTKEM,3)))
+  ALLOCATE(XLBYTKES(SIZE(XLBYTKEM,1),SIZE(XLBYTKEM,2),SIZE(XLBYTKEM,3)))
+  ALLOCATE(XLBXUS(SIZE(XLBXUM,1),SIZE(XLBXUM,2),SIZE(XLBXUM,3)))
+  ALLOCATE(XLBYUS(SIZE(XLBYUM,1),SIZE(XLBYUM,2),SIZE(XLBYUM,3)))
+  ALLOCATE(XLBXVS(SIZE(XLBXVM,1),SIZE(XLBXVM,2),SIZE(XLBXVM,3)))
+  ALLOCATE(XLBYVS(SIZE(XLBYVM,1),SIZE(XLBYVM,2),SIZE(XLBYVM,3)))
+  ALLOCATE(XLBXWS(SIZE(XLBXWM,1),SIZE(XLBXWM,2),SIZE(XLBXWM,3)))
+  ALLOCATE(XLBYWS(SIZE(XLBYWM,1),SIZE(XLBYWM,2),SIZE(XLBYWM,3)))
+  ALLOCATE(XLBXTHS(SIZE(XLBXTHM,1),SIZE(XLBXTHM,2),SIZE(XLBXTHM,3)))
+  ALLOCATE(XLBYTHS(SIZE(XLBYTHM,1),SIZE(XLBYTHM,2),SIZE(XLBYTHM,3)))
+  ALLOCATE(XLBXRS(SIZE(XLBXRM,1),SIZE(XLBXRM,2),SIZE(XLBXRM,3),SIZE(XLBXRM,4)))
+  ALLOCATE(XLBYRS(SIZE(XLBYRM,1),SIZE(XLBYRM,2),SIZE(XLBYRM,3),SIZE(XLBYRM,4)))
+  ALLOCATE(XLBXSVS(SIZE(XLBXSVM,1),SIZE(XLBXSVM,2),SIZE(XLBXSVM,3),SIZE(XLBXSVM,4)))
+  ALLOCATE(XLBYSVS(SIZE(XLBYSVM,1),SIZE(XLBYSVM,2),SIZE(XLBYSVM,3),SIZE(XLBYSVM,4)))
+!
+ELSE
+!
+  ALLOCATE(XLBXTKES(0,0,0))
+  ALLOCATE(XLBYTKES(0,0,0))
+  ALLOCATE(XLBXUS(0,0,0))
+  ALLOCATE(XLBYUS(0,0,0))
+  ALLOCATE(XLBXVS(0,0,0))
+  ALLOCATE(XLBYVS(0,0,0))
+  ALLOCATE(XLBXWS(0,0,0))
+  ALLOCATE(XLBYWS(0,0,0))
+  ALLOCATE(XLBXTHS(0,0,0))
+  ALLOCATE(XLBYTHS(0,0,0))
+  ALLOCATE(XLBXRS(0,0,0,0))
+  ALLOCATE(XLBYRS(0,0,0,0))
+  ALLOCATE(XLBXSVS(0,0,0,0))
+  ALLOCATE(XLBYSVS(0,0,0,0))
+!
+END IF
+!
+!
+!*       3.7   Module MODD_RADIATIONS_n (except XOZON and XAER)
+!
+! Initialization of SW bands
+NSWB_OLD = 6 ! Number of bands in ECMWF original scheme (from Fouquart et Bonnel (1980))
+             ! then modified through INI_RADIATIONS_ECMWF but remains equal to 6 practically
+IF (CRAD == 'ECRA') THEN
+    NSWB_MNH = 14
+ELSE
+    NSWB_MNH = NSWB_OLD
+END IF
+
+NLWB_MNH = 16 ! For XEMIS initialization (should be spectral in the future)
+
+
+ALLOCATE(XSW_BANDS (NSWB_MNH)) 
+ALLOCATE(XLW_BANDS (NLWB_MNH)) 
+ALLOCATE(XZENITH   (IIU,IJU))
+ALLOCATE(XAZIM     (IIU,IJU))
+ALLOCATE(XALBUV    (IIU,IJU))
+XALBUV(:,:) = NALBUV_DEFAULT !Set to an arbitrary low value (XALBUV is needed in CH_INTERP_JVALUES even if no radiation)
+ALLOCATE(XDIRSRFSWD(IIU,IJU,NSWB_MNH))
+ALLOCATE(XSCAFLASWD(IIU,IJU,NSWB_MNH))
+ALLOCATE(XFLALWD   (IIU,IJU))
+!
+IF (CRAD /= 'NONE') THEN
+  ALLOCATE(XSLOPANG(IIU,IJU))
+  ALLOCATE(XSLOPAZI(IIU,IJU))
+  ALLOCATE(XDTHRAD(IIU,IJU,IKU))
+  ALLOCATE(XDIRFLASWD(IIU,IJU,NSWB_MNH))
+  ALLOCATE(XDIR_ALB(IIU,IJU,NSWB_MNH))
+  ALLOCATE(XSCA_ALB(IIU,IJU,NSWB_MNH))
+  ALLOCATE(XEMIS  (IIU,IJU,NLWB_MNH))
+  ALLOCATE(XTSRAD (IIU,IJU))    ; XTSRAD = 0.0
+  ALLOCATE(XSEA (IIU,IJU))
+  ALLOCATE(XZS_XY (IIU,IJU))
+  ALLOCATE(NCLEARCOL_TM1(IIU,IJU))
+  ALLOCATE(XSWU(IIU,IJU,IKU))
+  ALLOCATE(XSWD(IIU,IJU,IKU))
+  ALLOCATE(XLWU(IIU,IJU,IKU))
+  ALLOCATE(XLWD(IIU,IJU,IKU))
+  ALLOCATE(XDTHRADSW(IIU,IJU,IKU))
+  ALLOCATE(XDTHRADLW(IIU,IJU,IKU))
+  ALLOCATE(XRADEFF(IIU,IJU,IKU))
+ELSE
+  ALLOCATE(XSLOPANG(0,0))
+  ALLOCATE(XSLOPAZI(0,0))
+  ALLOCATE(XDTHRAD(0,0,0))
+  ALLOCATE(XDIRFLASWD(0,0,0))
+  ALLOCATE(XDIR_ALB(0,0,0))
+  ALLOCATE(XSCA_ALB(0,0,0))
+  ALLOCATE(XEMIS  (0,0,0))
+  ALLOCATE(XTSRAD (0,0))
+  ALLOCATE(XSEA (0,0))
+  ALLOCATE(XZS_XY (0,0))
+  ALLOCATE(NCLEARCOL_TM1(0,0))
+  ALLOCATE(XSWU(0,0,0))
+  ALLOCATE(XSWD(0,0,0))
+  ALLOCATE(XLWU(0,0,0))
+  ALLOCATE(XLWD(0,0,0))
+  ALLOCATE(XDTHRADSW(0,0,0))
+  ALLOCATE(XDTHRADLW(0,0,0))
+  ALLOCATE(XRADEFF(0,0,0))
+END IF
+
+IF (CRAD == 'ECMW' .OR. CRAD == 'ECRA') THEN
+  ALLOCATE(XSTROATM(31,6))
+  ALLOCATE(XSMLSATM(31,6))
+  ALLOCATE(XSMLWATM(31,6))
+  ALLOCATE(XSPOSATM(31,6))
+  ALLOCATE(XSPOWATM(31,6))
+  ALLOCATE(XSTATM(31,6))
+ELSE
+  ALLOCATE(XSTROATM(0,0))
+  ALLOCATE(XSMLSATM(0,0))
+  ALLOCATE(XSMLWATM(0,0))
+  ALLOCATE(XSPOSATM(0,0))
+  ALLOCATE(XSPOWATM(0,0))
+  ALLOCATE(XSTATM(0,0))
+END IF
+!
+!*       3.8   Module MODD_DEEP_CONVECTION_n
+!
+IF (CDCONV /= 'NONE' .OR. CSCONV == 'KAFR') THEN
+  ALLOCATE(NCOUNTCONV(IIU,IJU))
+  ALLOCATE(XDTHCONV(IIU,IJU,IKU))
+  ALLOCATE(XDRVCONV(IIU,IJU,IKU))
+  ALLOCATE(XDRCCONV(IIU,IJU,IKU))
+  ALLOCATE(XDRICONV(IIU,IJU,IKU))
+  ALLOCATE(XPRCONV(IIU,IJU))
+  ALLOCATE(XPACCONV(IIU,IJU))
+  ALLOCATE(XPRSCONV(IIU,IJU))
+  ! diagnostics
+  IF (LCH_CONV_LINOX) THEN
+    ALLOCATE(XIC_RATE(IIU,IJU))
+    ALLOCATE(XCG_RATE(IIU,IJU))
+    ALLOCATE(XIC_TOTAL_NUMBER(IIU,IJU))
+    ALLOCATE(XCG_TOTAL_NUMBER(IIU,IJU))
+  ELSE
+    ALLOCATE(XIC_RATE(0,0))
+    ALLOCATE(XCG_RATE(0,0))
+    ALLOCATE(XIC_TOTAL_NUMBER(0,0))
+    ALLOCATE(XCG_TOTAL_NUMBER(0,0))
+  END IF
+  IF ( LDIAGCONV )  THEN
+    ALLOCATE(XUMFCONV(IIU,IJU,IKU))
+    ALLOCATE(XDMFCONV(IIU,IJU,IKU))
+    ALLOCATE(XPRLFLXCONV(IIU,IJU,IKU))
+    ALLOCATE(XPRSFLXCONV(IIU,IJU,IKU))
+    ALLOCATE(XCAPE(IIU,IJU))
+    ALLOCATE(NCLTOPCONV(IIU,IJU))
+    ALLOCATE(NCLBASCONV(IIU,IJU))
+  ELSE
+    ALLOCATE(XUMFCONV(0,0,0))
+    ALLOCATE(XDMFCONV(0,0,0))
+    ALLOCATE(XPRLFLXCONV(0,0,0))
+    ALLOCATE(XPRSFLXCONV(0,0,0))
+    ALLOCATE(XCAPE(0,0))
+    ALLOCATE(NCLTOPCONV(0,0))
+    ALLOCATE(NCLBASCONV(0,0))
+  END IF
+ELSE
+  ALLOCATE(NCOUNTCONV(0,0))
+  ALLOCATE(XDTHCONV(0,0,0))
+  ALLOCATE(XDRVCONV(0,0,0))
+  ALLOCATE(XDRCCONV(0,0,0))
+  ALLOCATE(XDRICONV(0,0,0))
+  ALLOCATE(XPRCONV(0,0))
+  ALLOCATE(XPACCONV(0,0))
+  ALLOCATE(XPRSCONV(0,0))
+  ALLOCATE(XIC_RATE(0,0))
+  ALLOCATE(XCG_RATE(0,0))
+  ALLOCATE(XIC_TOTAL_NUMBER(0,0))
+  ALLOCATE(XCG_TOTAL_NUMBER(0,0))
+  ALLOCATE(XUMFCONV(0,0,0))
+  ALLOCATE(XDMFCONV(0,0,0))
+  ALLOCATE(XPRLFLXCONV(0,0,0))
+  ALLOCATE(XPRSFLXCONV(0,0,0))
+  ALLOCATE(XCAPE(0,0))
+  ALLOCATE(NCLTOPCONV(0,0))
+  ALLOCATE(NCLBASCONV(0,0))
+END IF
+!
+IF ((CDCONV == 'KAFR' .OR. CSCONV == 'KAFR') &
+    .AND. LSUBG_COND .AND. LSIG_CONV) THEN
+  ALLOCATE(XMFCONV(IIU,IJU,IKU))
+ELSE
+  ALLOCATE(XMFCONV(0,0,0))
+ENDIF
+!
+IF ((CDCONV == 'KAFR' .OR. CSCONV == 'KAFR') &
+    .AND. LCHTRANS .AND. NSV > 0 ) THEN
+  ALLOCATE(XDSVCONV(IIU,IJU,IKU,NSV))
+ELSE
+  ALLOCATE(XDSVCONV(0,0,0,0))
+END IF
+!
+ALLOCATE(XCF_MF(IIU,IJU,IKU)) ; XCF_MF=0.0
+ALLOCATE(XRC_MF(IIU,IJU,IKU)) ; XRC_MF=0.0
+ALLOCATE(XRI_MF(IIU,IJU,IKU)) ; XRI_MF=0.0
+!
+!*       3.9   Local variables
+!
+ALLOCATE(ZJ(IIU,IJU,IKU))
+!
+!*      3.10 Forcing variables (Module MODD_FRC)
+!
+IF (KMI == 1) THEN
+  IF ( LFORCING ) THEN
+    ALLOCATE(TDTFRC(NFRC))
+    ALLOCATE(XUFRC(IKU,NFRC))
+    ALLOCATE(XVFRC(IKU,NFRC))
+    ALLOCATE(XWFRC(IKU,NFRC))
+    ALLOCATE(XTHFRC(IKU,NFRC))
+    ALLOCATE(XRVFRC(IKU,NFRC))
+    ALLOCATE(XTENDTHFRC(IKU,NFRC))
+    ALLOCATE(XTENDRVFRC(IKU,NFRC))
+    ALLOCATE(XGXTHFRC(IKU,NFRC))
+    ALLOCATE(XGYTHFRC(IKU,NFRC))
+    ALLOCATE(XPGROUNDFRC(NFRC))
+    ALLOCATE(XTENDUFRC(IKU,NFRC))
+    ALLOCATE(XTENDVFRC(IKU,NFRC))
+  ELSE
+    ALLOCATE(TDTFRC(0))
+    ALLOCATE(XUFRC(0,0))
+    ALLOCATE(XVFRC(0,0))
+    ALLOCATE(XWFRC(0,0))
+    ALLOCATE(XTHFRC(0,0))
+    ALLOCATE(XRVFRC(0,0))
+    ALLOCATE(XTENDTHFRC(0,0))
+    ALLOCATE(XTENDRVFRC(0,0))
+    ALLOCATE(XGXTHFRC(0,0))
+    ALLOCATE(XGYTHFRC(0,0))
+    ALLOCATE(XPGROUNDFRC(0))
+    ALLOCATE(XTENDUFRC(0,0))
+    ALLOCATE(XTENDVFRC(0,0))
+  END IF
+  IF ( LFORCING ) THEN
+    ALLOCATE(XWTFRC(IIU,IJU,IKU))
+    ALLOCATE(XUFRC_PAST(IIU,IJU,IKU)) ; XUFRC_PAST = XUNDEF
+    ALLOCATE(XVFRC_PAST(IIU,IJU,IKU)) ; XVFRC_PAST = XUNDEF
+  ELSE
+    ALLOCATE(XWTFRC(0,0,0))
+    ALLOCATE(XUFRC_PAST(0,0,0))
+    ALLOCATE(XVFRC_PAST(0,0,0))
+  END IF
+ELSE
+  !Do not allocate because they are the same on all grids (not 'n' variables)
+END IF
+! ----------------------------------------------------------------------
+!
+IF (L2D_ADV_FRC) THEN
+  WRITE(ILUOUT,*) 'L2D_ADV_FRC IS SET TO', L2D_ADV_FRC
+  WRITE(ILUOUT,*) 'ADV FRC WILL BE SET'
+  ALLOCATE(TDTADVFRC(NADVFRC))
+  ALLOCATE(XDTHFRC(IIU,IJU,IKU,NADVFRC))  ; XDTHFRC=0.
+  ALLOCATE(XDRVFRC(IIU,IJU,IKU,NADVFRC))  ; XDRVFRC=0.
+ELSE
+  ALLOCATE(TDTADVFRC(0))
+  ALLOCATE(XDTHFRC(0,0,0,0))
+  ALLOCATE(XDRVFRC(0,0,0,0))
+ENDIF
+
+IF (L2D_REL_FRC) THEN
+  WRITE(ILUOUT,*) 'L2D_REL_FRC IS SET TO', L2D_REL_FRC
+  WRITE(ILUOUT,*) 'REL FRC WILL BE SET'
+  ALLOCATE(TDTRELFRC(NRELFRC))
+  ALLOCATE(XTHREL(IIU,IJU,IKU,NRELFRC))  ; XTHREL=0.
+  ALLOCATE(XRVREL(IIU,IJU,IKU,NRELFRC))  ; XRVREL=0.
+ELSE
+  ALLOCATE(TDTRELFRC(0))
+  ALLOCATE(XTHREL(0,0,0,0))
+  ALLOCATE(XRVREL(0,0,0,0))
+ENDIF
+!
+!*      4.11 BIS: Eddy fluxes allocation
+!
+IF ( LTH_FLX ) THEN
+  ALLOCATE(XVTH_FLUX_M(IIU,IJU,IKU)) ; XVTH_FLUX_M = 0.
+  ALLOCATE(XWTH_FLUX_M(IIU,IJU,IKU)) ; XWTH_FLUX_M = 0.
+  IF (KMI /= 1) THEN
+    ALLOCATE(XRTHS_EDDY_FLUX(IIU,IJU,IKU))
+    XRTHS_EDDY_FLUX = 0.
+  ELSE
+    ALLOCATE(XRTHS_EDDY_FLUX(0,0,0))
+  ENDIF
+ELSE
+  ALLOCATE(XVTH_FLUX_M(0,0,0))
+  ALLOCATE(XWTH_FLUX_M(0,0,0))
+  ALLOCATE(XRTHS_EDDY_FLUX(0,0,0))
+END IF
+!
+IF ( LUV_FLX) THEN
+  ALLOCATE(XVU_FLUX_M(IIU,IJU,IKU)) ; XVU_FLUX_M  = 0.
+  IF (KMI /= 1) THEN
+    ALLOCATE(XRVS_EDDY_FLUX(IIU,IJU,IKU))
+    XRVS_EDDY_FLUX = 0.
+  ELSE
+    ALLOCATE(XRVS_EDDY_FLUX(0,0,0))
+  ENDIF
+ELSE
+  ALLOCATE(XVU_FLUX_M(0,0,0))
+  ALLOCATE(XRVS_EDDY_FLUX(0,0,0))
+END IF
+!
+!*      3.11   Module MODD_ICE_CONC_n
+!
+IF (     (CCLOUD == 'ICE3'.OR.CCLOUD == 'ICE4') .AND.   &
+     (CPROGRAM == 'DIAG  '.OR.CPROGRAM == 'MESONH')) THEN
+  ALLOCATE(XCIT(IIU,IJU,IKU))
+ELSE
+  ALLOCATE(XCIT(0,0,0))
+END IF
+!
+IF ( CCLOUD == 'KHKO' .OR. CCLOUD == 'C2R2') THEN
+   ALLOCATE(XSUPSAT(IIU,IJU,IKU))
+   ALLOCATE(XNACT(IIU,IJU,IKU))
+   ALLOCATE(XNPRO(IIU,IJU,IKU))
+   ALLOCATE(XSSPRO(IIU,IJU,IKU))
+ELSE
+   ALLOCATE(XSUPSAT(0,0,0))
+   ALLOCATE(XNACT(0,0,0))
+   ALLOCATE(XNPRO(0,0,0))
+   ALLOCATE(XSSPRO(0,0,0))
+END IF
+!
+!*      3.12   Module MODD_TURB_CLOUD
+!
+IF (.NOT.(ALLOCATED(XCEI))) ALLOCATE(XCEI(0,0,0))
+IF (KMI == NMODEL_CLOUD .AND. CTURBLEN_CLOUD/='NONE' ) THEN
+  DEALLOCATE(XCEI)
+  ALLOCATE(XCEI(IIU,IJU,IKU))
+ENDIF
+!
+!*      3.13  Module MODD_CH_PH_n
+!
+IF (LUSECHAQ.AND.(CPROGRAM == 'DIAG  '.OR.CPROGRAM == 'MESONH')) THEN
+  IF (LCH_PH) THEN
+    ALLOCATE(XPHC(IIU,IJU,IKU))
+    IF (NRRL==2) THEN
+      ALLOCATE(XPHR(IIU,IJU,IKU))
+      ALLOCATE(XACPHR(IIU,IJU))
+      XACPHR(:,:) =  0.
+    ENDIF
+  ENDIF
+  IF (NRRL==2) THEN
+    ALLOCATE(XACPRAQ(IIU,IJU,NSV_CHAC/2))
+    XACPRAQ(:,:,:) = 0.
+  ENDIF
+ENDIF
+IF (.NOT.(ASSOCIATED(XPHC))) ALLOCATE(XPHC(0,0,0))
+IF (.NOT.(ASSOCIATED(XPHR))) ALLOCATE(XPHR(0,0,0))
+IF (.NOT.(ASSOCIATED(XACPHR))) ALLOCATE(XACPHR(0,0))
+IF (.NOT.(ASSOCIATED(XACPRAQ))) ALLOCATE(XACPRAQ(0,0,0))
+IF ((LUSECHEM).AND.(CPROGRAM == 'DIAG  ')) THEN
+  ALLOCATE(XCHFLX(IIU,IJU,NSV_CHEM))
+  XCHFLX(:,:,:) = 0.
+ELSE
+  ALLOCATE(XCHFLX(0,0,0))
+END IF
+!
+!*          3.14 Module MODD_DRAG
+!
+IF (LDRAG) THEN
+  ALLOCATE(XDRAG(IIU,IJU))
+ELSE
+  ALLOCATE(XDRAG(0,0))
+ENDIF
+!
+!-------------------------------------------------------------------------------
+!
+!*       4.    INITIALIZE BUDGET VARIABLES
+!              ---------------------------
+!
+IF ( CBUTYPE /= "NONE" .AND. NBUMOD == KMI ) THEN
+  CALL INI_BUDGET(ILUOUT,XTSTEP,NSV,NRR,                                      &
+             LNUMDIFU,LNUMDIFTH,LNUMDIFSV,                                    &
+             LHORELAX_UVWTH,LHORELAX_RV, LHORELAX_RC,LHORELAX_RR,             &
+             LHORELAX_RI,LHORELAX_RS,LHORELAX_RG, LHORELAX_RH,LHORELAX_TKE,   &
+             LHORELAX_SV,LVE_RELAX,LCHTRANS,LNUDGING,LDRAGTREE,LDEPOTREE,     &
+             CRAD,CDCONV,CSCONV,CTURB,CTURBDIM,CCLOUD                         )
+END IF
+!
+!-------------------------------------------------------------------------------
+!
+!
+!*       5.    INITIALIZE INTERPOLATION COEFFICIENTS
+!
+CALL INI_BIKHARDT_n (NDXRATIO_ALL(KMI),NDYRATIO_ALL(KMI),KMI)
+!
+!-------------------------------------------------------------------------------
+!
+!*       6.     BUILT THE GENERIC OUTPUT NAME
+!               ----------------------------
+!
+IF (KMI == 1) THEN
+  DO IMI = 1 , NMODEL
+    WRITE(IO_SURF_MNH_MODEL(IMI)%COUTFILE,'(A,".",I1,".",A)') CEXP,IMI,TRIM(ADJUSTL(CSEG))
+    WRITE(YNAME, '(A,".",I1,".",A)') CEXP,IMI,TRIM(ADJUSTL(CSEG))//'.000'
+    CALL IO_File_add2list(LUNIT_MODEL(IMI)%TDIAFILE,YNAME,'MNHDIACHRONIC','WRITE', &
+                          HDIRNAME=CIO_DIR,                                        &
+                          KLFINPRAR=INT(50,KIND=LFIINT),KLFITYPE=1,KLFIVERB=NVERB, &
+                          TPDADFILE=LUNIT_MODEL(NDAD(IMI))%TDIAFILE )
+  END DO
+  !
+  TDIAFILE => LUNIT_MODEL(KMI)%TDIAFILE !Necessary because no call to GOTO_MODEL before needing it
+  !
+  IF (CPROGRAM=='MESONH') THEN
+    IF ( NDAD(KMI) == 1)  CDAD_NAME(KMI) = CEXP//'.1.'//CSEG
+    IF ( NDAD(KMI) == 2)  CDAD_NAME(KMI) = CEXP//'.2.'//CSEG
+    IF ( NDAD(KMI) == 3)  CDAD_NAME(KMI) = CEXP//'.3.'//CSEG
+    IF ( NDAD(KMI) == 4)  CDAD_NAME(KMI) = CEXP//'.4.'//CSEG
+    IF ( NDAD(KMI) == 5)  CDAD_NAME(KMI) = CEXP//'.5.'//CSEG
+    IF ( NDAD(KMI) == 6)  CDAD_NAME(KMI) = CEXP//'.6.'//CSEG
+    IF ( NDAD(KMI) == 7)  CDAD_NAME(KMI) = CEXP//'.7.'//CSEG
+    IF ( NDAD(KMI) == 8)  CDAD_NAME(KMI) = CEXP//'.8.'//CSEG
+  END IF
+ELSE
+  ALLOCATE(XUM(0,0,0))
+  ALLOCATE(XVM(0,0,0))
+  ALLOCATE(XWM(0,0,0))
+  ALLOCATE(XDUM(0,0,0))
+  ALLOCATE(XDVM(0,0,0))
+  ALLOCATE(XDWM(0,0,0))
+END IF
+!
+!-------------------------------------------------------------------------------
+!
+!*       7.    INITIALIZE GRIDS AND METRIC COEFFICIENTS
+!              ----------------------------------------
+!
+CALL SET_GRID(KMI,TPINIFILE,IKU,NIMAX_ll,NJMAX_ll,                       &
+              XTSTEP,XSEGLEN,                                            &
+              XLONORI,XLATORI,XLON,XLAT,                                 &
+              XXHAT,XYHAT,XDXHAT,XDYHAT, XMAP,                           &
+              XZS,XZZ,XZHAT,XZTOP,LSLEVE,XLEN1,XLEN2,XZSMT,              &
+              ZJ,                                                        &
+              TDTMOD,TDTCUR,NSTOP,NBAK_NUMB,NOUT_NUMB,TBACKUPN,TOUTPUTN)
+!
+CALL METRICS(XMAP,XDXHAT,XDYHAT,XZZ,XDXX,XDYY,XDZX,XDZY,XDZZ)
+!
+!* update halos of metric coefficients
+!
+!
+CALL UPDATE_METRICS(CLBCX,CLBCY,XDXX,XDYY,XDZX,XDZY,XDZZ)
+!
+!
+CALL SET_DIRCOS(CLBCX,CLBCY,XDXX,XDYY,XDZX,XDZY,TZINITHALO2D_ll,   &
+                XDIRCOSXW,XDIRCOSYW,XDIRCOSZW,XCOSSLOPE,XSINSLOPE  )
+!
+! grid nesting initializations
+IF ( KMI == 1 ) THEN
+  XTSTEP_MODEL1=XTSTEP
+END IF
+!
+NDT_2_WAY(KMI)=4
+!
+!-------------------------------------------------------------------------------
+!
+!*      8.    INITIALIZE DATA FOR JVALUES AND AEROSOLS 
+!
+IF ( LUSECHEM .OR. LCHEMDIAG ) THEN
+  IF ((KMI==1).AND.(CPROGRAM == "MESONH".OR.CPROGRAM == "DIAG  "))  &
+    CALL CH_INIT_JVALUES(TDTCUR%TDATE%DAY, TDTCUR%TDATE%MONTH,      &
+                         TDTCUR%TDATE%YEAR, ILUOUT, XCH_TUV_DOBNEW)
+!
+  IF (LORILAM) THEN
+    CALL CH_AER_MOD_INIT
+  ENDIF
+END IF
+IF (.NOT.(ASSOCIATED(XMI))) ALLOCATE(XMI(0,0,0,0))
+IF (.NOT.(ASSOCIATED(XSOLORG))) ALLOCATE(XSOLORG(0,0,0,0))
+!
+IF (CCLOUD=='LIMA') CALL INIT_AEROSOL_PROPERTIES
+!
+!-------------------------------------------------------------------------------
+!
+!*       9.    INITIALIZE THE PROGNOSTIC FIELDS
+!              --------------------------------
+!
+CALL MPPDB_CHECK3D(XUT,"INI_MODEL_N-before read_field::XUT",PRECISION)
+CALL READ_FIELD(TPINIFILE,IIU,IJU,IKU,                                        &
+                CGETTKET,CGETRVT,CGETRCT,CGETRRT,CGETRIT,CGETCIT,CGETZWS,     &
+                CGETRST,CGETRGT,CGETRHT,CGETSVT,CGETSRCT,CGETSIGS,CGETCLDFR,  &
+                CGETBL_DEPTH,CGETSBL_DEPTH,CGETPHC,CGETPHR,CUVW_ADV_SCHEME,   &
+                CTEMP_SCHEME,NSIZELBX_ll,NSIZELBXU_ll,NSIZELBY_ll,NSIZELBYV_ll,&
+                NSIZELBXTKE_ll,NSIZELBYTKE_ll,                                &
+                NSIZELBXR_ll,NSIZELBYR_ll,NSIZELBXSV_ll,NSIZELBYSV_ll,        &
+                XUM,XVM,XWM,XDUM,XDVM,XDWM,                                   &
+                XUT,XVT,XWT,XTHT,XPABST,XTKET,XRTKEMS,                        &
+                XRT,XSVT,XZWS,XCIT,XDRYMASST,                                 &
+                XSIGS,XSRCT,XCLDFR,XBL_DEPTH,XSBL_DEPTH,XWTHVMF,XPHC,XPHR,    &
+                XLSUM,XLSVM,XLSWM,XLSTHM,XLSRVM,XLSZWSM,                      &
+                XLBXUM,XLBXVM,XLBXWM,XLBXTHM,XLBXTKEM,                        &
+                XLBXRM,XLBXSVM,                                               &
+                XLBYUM,XLBYVM,XLBYWM,XLBYTHM,XLBYTKEM,                        &
+                XLBYRM,XLBYSVM,                                               &
+                NFRC,TDTFRC,XUFRC,XVFRC,XWFRC,XTHFRC,XRVFRC,                  &
+                XTENDTHFRC,XTENDRVFRC,XGXTHFRC,XGYTHFRC,                      &
+                XPGROUNDFRC, XATC,                                            &
+                XTENDUFRC, XTENDVFRC,                                         &
+                NADVFRC,TDTADVFRC,XDTHFRC,XDRVFRC,                            &
+                NRELFRC,TDTRELFRC,XTHREL,XRVREL,                              &
+                XVTH_FLUX_M,XWTH_FLUX_M,XVU_FLUX_M,                           &
+                XRUS_PRES,XRVS_PRES,XRWS_PRES,XRTHS_CLD,XRRS_CLD,XRSVS_CLD    )
+!
+!-------------------------------------------------------------------------------
+!
+!
+!*        10.  INITIALIZE REFERENCE STATE
+!              ---------------------------
+!
+!
+CALL SET_REF(KMI,TPINIFILE,                         &
+             XZZ,XZHAT,ZJ,XDXX,XDYY,CLBCX,CLBCY,    &
+             XREFMASS,XMASS_O_PHI0,XLINMASS,        &
+             XRHODREF,XTHVREF,XRVREF,XEXNREF,XRHODJ )
+!
+!-------------------------------------------------------------------------------
+!
+!*       10.1    INITIALIZE THE TURBULENCE VARIABLES
+!               -----------------------------------
+!
+IF ((CTURB == 'TKEL').AND.(CCONF=='START')) THEN
+  CALL MPPDB_CHECK3D(XUT,"INI_MODEL_N-before ini_tke_eps::XUT",PRECISION)
+  CALL INI_TKE_EPS(CGETTKET,XTHVREF,XZZ, &
+                   XUT,XVT,XTHT,                  &
+                   XTKET,TZINITHALO3D_ll    )
+  CALL MPPDB_CHECK3D(XUT,"INI_MODEL_N-after ini_tke_eps::XUT",PRECISION)
+END IF
+!
+!
+!*       10.2   INITIALIZE THE LES VARIABLES
+!               ----------------------------
+!
+CALL INI_LES_n
+!
+!-------------------------------------------------------------------------------
+!
+!*       11.    INITIALIZE THE SOURCE OF TOTAL DRY MASS Md
+!               ------------------------------------------
+!
+IF((KMI==1).AND.LSTEADYLS) THEN
+  XDRYMASSS = 0.
+END IF
+!
+!-------------------------------------------------------------------------------
+!
+!*       12.    INITIALIZE THE MICROPHYSICS                   
+!               ----------------------------
+!
+IF (CELEC == 'NONE') THEN
+  CALL INI_MICRO_n(TPINIFILE,ILUOUT)
+!
+!-------------------------------------------------------------------------------
+!
+!*       13.    INITIALIZE THE ATMOSPHERIC ELECTRICITY                   
+!               --------------------------------------
+!
+ELSE
+  CALL INI_ELEC_n(ILUOUT, CELEC, CCLOUD, TPINIFILE, &
+                  XTSTEP, XZZ,                      &
+                  XDXX, XDYY, XDZZ, XDZX, XDZY      )
+!
+  WRITE (UNIT=ILUOUT,&
+  FMT='(/,"ELECTRIC VARIABLES ARE BETWEEN INDEX",I2," AND ",I2)')&
+  NSV_ELECBEG, NSV_ELECEND
+! 
+    IF( CGETSVT(NSV_ELECBEG)=='INIT' ) THEN
+      XSVT(:,:,:,NSV_ELECBEG) = XCION_POS_FW(:,:,:)                  ! Nb/kg
+      XSVT(:,:,:,NSV_ELECEND) = XCION_NEG_FW(:,:,:)
+!
+      XSVT(:,:,:,NSV_ELECBEG+1:NSV_ELECEND-1) = 0.0
+    ELSE  ! Convert elec_variables per m3 into elec_variables per kg of air
+      DO JSV = NSV_ELECBEG, NSV_ELECEND
+         XSVT(:,:,:,JSV) = XSVT(:,:,:,JSV) / XRHODREF(:,:,:)
+      ENDDO
+    END IF
+END IF
+!
+!-------------------------------------------------------------------------------
+!
+!*       14.   INITIALIZE THE LARGE SCALE SOURCES
+!              ----------------------------------
+!
+IF ((KMI==1).AND.(.NOT. LSTEADYLS)) THEN
+  CALL MPPDB_CHECK3D(XUT,"INI_MODEL_N-before ini_cpl::XUT",PRECISION)
+  CALL INI_CPL(NSTOP,XTSTEP,LSTEADYLS,CCONF,                                  &
+               CGETTKET,                                                      &
+               CGETRVT,CGETRCT,CGETRRT,CGETRIT,                               &
+               CGETRST,CGETRGT,CGETRHT,CGETSVT,LCH_INIT_FIELD,                &
+               NSV,NIMAX_ll,NJMAX_ll,                                         &
+               NSIZELBX_ll,NSIZELBXU_ll,NSIZELBY_ll,NSIZELBYV_ll,             &
+               NSIZELBXTKE_ll,NSIZELBYTKE_ll,                                 &
+               NSIZELBXR_ll,NSIZELBYR_ll,NSIZELBXSV_ll,NSIZELBYSV_ll,         &
+               XLSUM,XLSVM,XLSWM,XLSTHM,XLSRVM,XLSZWSM,XDRYMASST,             &
+               XLBXUM,XLBXVM,XLBXWM,XLBXTHM,XLBXTKEM,XLBXRM,XLBXSVM,          &
+               XLBYUM,XLBYVM,XLBYWM,XLBYTHM,XLBYTKEM,XLBYRM,XLBYSVM,          &
+               XLSUS,XLSVS,XLSWS,XLSTHS,XLSRVS,XLSZWSS,XDRYMASSS,             &
+               XLBXUS,XLBXVS,XLBXWS,XLBXTHS,XLBXTKES,XLBXRS,XLBXSVS,          &
+               XLBYUS,XLBYVS,XLBYWS,XLBYTHS,XLBYTKES,XLBYRS,XLBYSVS           )
+  CALL MPPDB_CHECK3D(XUT,"INI_MODEL_N-after ini_cpl::XUT",PRECISION)
+!
+      DO JSV=NSV_CHEMBEG,NSV_CHEMEND
+        XLBXSVS(:,:,:,JSV)=MAX(XLBXSVS(:,:,:,JSV),0.)
+        XLBYSVS(:,:,:,JSV)=MAX(XLBYSVS(:,:,:,JSV),0.)
+      ENDDO
+      !
+      DO JSV=NSV_LNOXBEG,NSV_LNOXEND
+        XLBXSVS(:,:,:,JSV)=MAX(XLBXSVS(:,:,:,JSV),0.)
+        XLBYSVS(:,:,:,JSV)=MAX(XLBYSVS(:,:,:,JSV),0.)
+      ENDDO
+      !
+      DO JSV=NSV_AERBEG,NSV_AEREND
+        XLBXSVS(:,:,:,JSV)=MAX(XLBXSVS(:,:,:,JSV),0.)
+        XLBYSVS(:,:,:,JSV)=MAX(XLBYSVS(:,:,:,JSV),0.)
+      ENDDO
+      !
+      DO JSV=NSV_DSTBEG,NSV_DSTEND
+        XLBXSVS(:,:,:,JSV)=MAX(XLBXSVS(:,:,:,JSV),0.)
+        XLBYSVS(:,:,:,JSV)=MAX(XLBYSVS(:,:,:,JSV),0.)
+      ENDDO
+      !
+      DO JSV=NSV_DSTDEPBEG,NSV_DSTDEPEND
+        XLBXSVS(:,:,:,JSV)=MAX(XLBXSVS(:,:,:,JSV),0.)
+        XLBYSVS(:,:,:,JSV)=MAX(XLBYSVS(:,:,:,JSV),0.)
+      ENDDO
+      !
+      DO JSV=NSV_SLTBEG,NSV_SLTEND
+        XLBXSVS(:,:,:,JSV)=MAX(XLBXSVS(:,:,:,JSV),0.)
+        XLBYSVS(:,:,:,JSV)=MAX(XLBYSVS(:,:,:,JSV),0.)
+      ENDDO
+      !
+      DO JSV=NSV_SLTDEPBEG,NSV_SLTDEPEND
+        XLBXSVS(:,:,:,JSV)=MAX(XLBXSVS(:,:,:,JSV),0.)
+        XLBYSVS(:,:,:,JSV)=MAX(XLBYSVS(:,:,:,JSV),0.)
+      ENDDO
+      !
+      DO JSV=NSV_PPBEG,NSV_PPEND
+        XLBXSVS(:,:,:,JSV)=MAX(XLBXSVS(:,:,:,JSV),0.)
+        XLBYSVS(:,:,:,JSV)=MAX(XLBYSVS(:,:,:,JSV),0.)
+      ENDDO
+      !
+#ifdef MNH_FOREFIRE
+      DO JSV=NSV_FFBEG,NSV_FFEND
+        XLBXSVS(:,:,:,JSV)=MAX(XLBXSVS(:,:,:,JSV),0.)
+        XLBYSVS(:,:,:,JSV)=MAX(XLBYSVS(:,:,:,JSV),0.)
+      ENDDO
+      !
+#endif
+      DO JSV=NSV_CSBEG,NSV_CSEND
+        XLBXSVS(:,:,:,JSV)=MAX(XLBXSVS(:,:,:,JSV),0.)
+        XLBYSVS(:,:,:,JSV)=MAX(XLBYSVS(:,:,:,JSV),0.)
+      ENDDO
+!
+END IF
+ALLOCATE(XLSZWSM(IIU,IJU)) ; XLSZWSM = -1.
+!
+IF ( KMI > 1) THEN
+  ! Use dummy pointers to correct an ifort BUG
+  DPTR_XBMX1=>XBMX1
+  DPTR_XBMX2=>XBMX2
+  DPTR_XBMX3=>XBMX3
+  DPTR_XBMX4=>XBMX4
+  DPTR_XBMY1=>XBMY1
+  DPTR_XBMY2=>XBMY2
+  DPTR_XBMY3=>XBMY3
+  DPTR_XBMY4=>XBMY4
+  DPTR_XBFX1=>XBFX1
+  DPTR_XBFX2=>XBFX2
+  DPTR_XBFX3=>XBFX3
+  DPTR_XBFX4=>XBFX4
+  DPTR_XBFY1=>XBFY1
+  DPTR_XBFY2=>XBFY2
+  DPTR_XBFY3=>XBFY3
+  DPTR_XBFY4=>XBFY4
+  DPTR_CLBCX=>CLBCX
+  DPTR_CLBCY=>CLBCY
+  !
+  DPTR_XZZ=>XZZ
+  DPTR_XZHAT=>XZHAT
+  DPTR_XLSUM=>XLSUM
+  DPTR_XLSVM=>XLSVM
+  DPTR_XLSWM=>XLSWM
+  DPTR_XLSTHM=>XLSTHM
+  DPTR_XLSRVM=>XLSRVM
+  DPTR_XLSZWSM=>XLSZWSM
+  DPTR_XLSUS=>XLSUS
+  DPTR_XLSVS=>XLSVS
+  DPTR_XLSWS=>XLSWS
+  DPTR_XLSTHS=>XLSTHS
+  DPTR_XLSRVS=>XLSRVS
+  DPTR_XLSZWSS=>XLSZWSS
+  !
+  DPTR_NKLIN_LBXU=>NKLIN_LBXU
+  DPTR_XCOEFLIN_LBXU=>XCOEFLIN_LBXU
+  DPTR_NKLIN_LBYU=>NKLIN_LBYU
+  DPTR_XCOEFLIN_LBYU=>XCOEFLIN_LBYU
+  DPTR_NKLIN_LBXV=>NKLIN_LBXV
+  DPTR_XCOEFLIN_LBXV=>XCOEFLIN_LBXV
+  DPTR_NKLIN_LBYV=>NKLIN_LBYV
+  DPTR_XCOEFLIN_LBYV=>XCOEFLIN_LBYV
+  DPTR_NKLIN_LBXW=>NKLIN_LBXW
+  DPTR_XCOEFLIN_LBXW=>XCOEFLIN_LBXW
+  DPTR_NKLIN_LBYW=>NKLIN_LBYW
+  DPTR_XCOEFLIN_LBYW=>XCOEFLIN_LBYW
+  DPTR_NKLIN_LBXM=>NKLIN_LBXM
+  DPTR_XCOEFLIN_LBXM=>XCOEFLIN_LBXM
+  DPTR_NKLIN_LBYM=>NKLIN_LBYM
+  DPTR_XCOEFLIN_LBYM=>XCOEFLIN_LBYM
+  !
+  CALL INI_SPAWN_LS_n(NDAD(KMI),XTSTEP,KMI,                                 &
+       DPTR_XBMX1,DPTR_XBMX2,DPTR_XBMX3,DPTR_XBMX4,DPTR_XBMY1,DPTR_XBMY2,DPTR_XBMY3,DPTR_XBMY4,      &
+       DPTR_XBFX1,DPTR_XBFX2,DPTR_XBFX3,DPTR_XBFX4,DPTR_XBFY1,DPTR_XBFY2,DPTR_XBFY3,DPTR_XBFY4,      &
+       NDXRATIO_ALL(KMI),NDYRATIO_ALL(KMI),                  &
+       DPTR_CLBCX,DPTR_CLBCY,DPTR_XZZ,DPTR_XZHAT,                                &
+       LSLEVE,XLEN1,XLEN2,                                   &
+       DPTR_XLSUM,DPTR_XLSVM,DPTR_XLSWM,DPTR_XLSTHM,DPTR_XLSRVM,DPTR_XLSZWSM,         &
+       DPTR_XLSUS,DPTR_XLSVS,DPTR_XLSWS,DPTR_XLSTHS,DPTR_XLSRVS,DPTR_XLSZWSS,                      &       
+       DPTR_NKLIN_LBXU,DPTR_XCOEFLIN_LBXU,DPTR_NKLIN_LBYU,DPTR_XCOEFLIN_LBYU,    &
+       DPTR_NKLIN_LBXV,DPTR_XCOEFLIN_LBXV,DPTR_NKLIN_LBYV,DPTR_XCOEFLIN_LBYV,    &
+       DPTR_NKLIN_LBXW,DPTR_XCOEFLIN_LBXW,DPTR_NKLIN_LBYW,DPTR_XCOEFLIN_LBYW,    &
+       DPTR_NKLIN_LBXM,DPTR_XCOEFLIN_LBXM,DPTR_NKLIN_LBYM,DPTR_XCOEFLIN_LBYM     )
+  !
+  DPTR_XLBXUM=>XLBXUM
+  DPTR_XLBYUM=>XLBYUM
+  DPTR_XLBXVM=>XLBXVM
+  DPTR_XLBYVM=>XLBYVM
+  DPTR_XLBXWM=>XLBXWM
+  DPTR_XLBYWM=>XLBYWM
+  DPTR_XLBXTHM=>XLBXTHM
+  DPTR_XLBYTHM=>XLBYTHM
+  DPTR_XLBXTKEM=>XLBXTKEM
+  DPTR_XLBYTKEM=>XLBYTKEM
+  DPTR_XLBXRM=>XLBXRM
+  DPTR_XLBYRM=>XLBYRM
+  DPTR_XLBXSVM=>XLBXSVM
+  DPTR_XLBYSVM=>XLBYSVM
+  CALL INI_ONE_WAY_n(NDAD(KMI),KMI,                                                             &
+       DPTR_XBMX1,DPTR_XBMX2,DPTR_XBMX3,DPTR_XBMX4,DPTR_XBMY1,DPTR_XBMY2,DPTR_XBMY3,DPTR_XBMY4, &
+       DPTR_XBFX1,DPTR_XBFX2,DPTR_XBFX3,DPTR_XBFX4,DPTR_XBFY1,DPTR_XBFY2,DPTR_XBFY3,DPTR_XBFY4, &
+       NDXRATIO_ALL(KMI),NDYRATIO_ALL(KMI),                                                     &
+       DPTR_CLBCX,DPTR_CLBCY,NRIMX,NRIMY,                                                       &
+       DPTR_NKLIN_LBXU,DPTR_XCOEFLIN_LBXU,DPTR_NKLIN_LBYU,DPTR_XCOEFLIN_LBYU,                   &
+       DPTR_NKLIN_LBXV,DPTR_XCOEFLIN_LBXV,DPTR_NKLIN_LBYV,DPTR_XCOEFLIN_LBYV,                   &
+       DPTR_NKLIN_LBXW,DPTR_XCOEFLIN_LBXW,DPTR_NKLIN_LBYW,DPTR_XCOEFLIN_LBYW,                   &
+       DPTR_NKLIN_LBXM,DPTR_XCOEFLIN_LBXM,DPTR_NKLIN_LBYM,DPTR_XCOEFLIN_LBYM,                   &
+       CCLOUD, LUSECHAQ, LUSECHIC,                                                              &
+       DPTR_XLBXUM,DPTR_XLBYUM,DPTR_XLBXVM,DPTR_XLBYVM,DPTR_XLBXWM,DPTR_XLBYWM,                 &
+       DPTR_XLBXTHM,DPTR_XLBYTHM,                                                               &
+       DPTR_XLBXTKEM,DPTR_XLBYTKEM,                                                             &
+       DPTR_XLBXRM,DPTR_XLBYRM,DPTR_XLBXSVM,DPTR_XLBYSVM                                        )
+END IF
+!
+!
+!-------------------------------------------------------------------------------
+!
+!*       15.    INITIALIZE THE SCALAR VARIABLES
+!               -------------------------------
+!
+IF (LLG .AND. LINIT_LG .AND. CPROGRAM=='MESONH') &
+  CALL INI_LG(XXHAT,XYHAT,XZZ,XSVT,XLBXSVM,XLBYSVM)
+
+!
+!-------------------------------------------------------------------------------
+!
+!*       16.    INITIALIZE THE PARAMETERS FOR THE DYNAMICS
+!               ------------------------------------------
+!
+CALL INI_DYNAMICS(XLON,XLAT,XRHODJ,XTHVREF,XMAP,XZZ,XDXHAT,XDYHAT,            &
+             XZHAT,CLBCX,CLBCY,XTSTEP,CPRESOPT,                               &
+             LVE_RELAX,LVE_RELAX_GRD,LHORELAX_UVWTH,LHORELAX_RV,              &
+             LHORELAX_RC,LHORELAX_RR,LHORELAX_RI,LHORELAX_RS,LHORELAX_RG,     &
+             LHORELAX_RH,LHORELAX_TKE,LHORELAX_SV,                            &
+             LHORELAX_SVC2R2,LHORELAX_SVC1R3,LHORELAX_SVELEC,LHORELAX_SVLG,   &
+             LHORELAX_SVCHEM,LHORELAX_SVAER,LHORELAX_SVDST,LHORELAX_SVSLT,    &
+             LHORELAX_SVPP,LHORELAX_SVCS,LHORELAX_SVCHIC,LHORELAX_SVSNW,      &
+#ifdef MNH_FOREFIRE
+             LHORELAX_SVFF,                                                   &
+#endif
+             XRIMKMAX,NRIMX,NRIMY,                                            &
+             XALKTOP,XALKGRD,XALZBOT,XALZBAS,                                 &
+             XT4DIFU,XT4DIFTH,XT4DIFSV,                                       &
+             XCORIOX,XCORIOY,XCORIOZ,XCURVX,XCURVY,                           &
+             XDXHATM,XDYHATM,XRHOM,XAF,XBFY,XCF,XTRIGSX,XTRIGSY,NIFAXX,NIFAXY,&
+             XALK,XALKW,NALBOT,XALKBAS,XALKWBAS,NALBAS,                       &
+             LMASK_RELAX,XKURELAX,XKVRELAX,XKWRELAX,                          &
+             XDK2U,XDK4U,XDK2TH,XDK4TH,XDK2SV,XDK4SV,                         &
+             LZDIFFU,XZDIFFU_HALO2,                                           &
+             XBFB,XBF_SXP2_YP1_Z,                                             &
+             XAF_ZS,XBF_ZS,XCF_ZS,                                            &
+             XDXATH_ZS,XDYATH_ZS,XRHO_ZS,                                     &
+             XA_K,XB_K,XC_K,XD_K                                              ) 
+!
+!
+!*      16.1 Initialize the XDRAG array
+!              -------------
+IF (LDRAG) THEN
+   CALL INI_DRAG(LMOUNT,XZS,XHSTART,NSTART,XDRAG)
+ENDIF
+!-------------------------------------------------------------------------------
+!
+!*      17.    SURFACE FIELDS
+!              --------------
+!
+!*      17.1   Radiative setup
+!              ---------------
+!
+IF (CRAD   /= 'NONE') THEN
+  IF (CGETRAD =='INIT') THEN
+    GINIRAD  =.TRUE.
+  ELSE
+    GINIRAD  =.FALSE.
+  END IF
+  CALL INI_RADIATIONS(TPINIFILE,GINIRAD,TDTCUR,TDTEXP,XZZ, &
+                      XDXX, XDYY,                         &
+                      XSINDEL,XCOSDEL,XTSIDER,XCORSOL,    &
+                      XSLOPANG,XSLOPAZI,                  &
+                      XDTHRAD,XDIRFLASWD,XSCAFLASWD,      &
+                      XFLALWD,XDIRSRFSWD,NCLEARCOL_TM1,   &
+                      XZENITH,XAZIM,                      &
+                      TDTRAD_FULL,TDTRAD_CLONLY,          &
+                      TZINITHALO2D_ll,                    &
+                      XRADEFF,XSWU,XSWD,XLWU,             &
+                      XLWD,XDTHRADSW,XDTHRADLW           )
+  !
+  IF (GINIRAD) CALL SUNPOS_n(XZENITH,PAZIMSOL=XAZIM)
+  CALL SURF_SOLAR_GEOM    (XZS, XZS_XY)
+  !
+  ALLOCATE(XXHAT_ll                 (IIU_ll))
+  ALLOCATE(XYHAT_ll                 (IJU_ll))
+  ALLOCATE(XZS_ll                   (IIU_ll,IJU_ll))
+  ALLOCATE(XZS_XY_ll                (IIU_ll,IJU_ll))
+  !
+  CALL GATHERALL_FIELD_ll('XY',XZS,XZS_ll,IRESP)
+  CALL GATHERALL_FIELD_ll('XY',XZS_XY,XZS_XY_ll,IRESP)
+  CALL GATHERALL_FIELD_ll('XX',XXHAT,XXHAT_ll,IRESP)
+  CALL GATHERALL_FIELD_ll('YY',XYHAT,XYHAT_ll,IRESP)
+  XZS_MAX_ll=MAXVAL(XZS_ll)
+ELSE
+  XAZIM       = XPI
+  XZENITH     = XPI/2.
+  XDIRSRFSWD  = 0.
+  XSCAFLASWD  = 0.
+  XFLALWD     = 300.  ! W/m2
+  XTSIDER     = 0.
+END IF
+!
+!
+CALL INI_SW_SETUP (CRAD,NSWB_MNH,XSW_BANDS)
+CALL INI_LW_SETUP (CRAD,NLWB_MNH,XLW_BANDS)
+!
+!
+!       17.1.1 Special initialisation for CO2 content
+!              CO2 (molar mass=44) horizontally and vertically homogeneous at 360 ppm
+!
+XCCO2 = 360.0E-06 * 44.0E-03 / XMD
+#ifdef MNH_ECRAD
+RCCO2 = 360.0E-06 * 44.0E-03 / XMD
+#endif
+!
+!
+!*      17.2   Externalized surface fields
+!              ---------------------------
+!
+ALLOCATE(ZCO2(IIU,IJU))
+ZCO2(:,:) = XCCO2
+!
+
+ALLOCATE(ZDIR_ALB(IIU,IJU,NSWB_MNH))
+ALLOCATE(ZSCA_ALB(IIU,IJU,NSWB_MNH))
+ALLOCATE(ZEMIS  (IIU,IJU,NLWB_MNH))
+ALLOCATE(ZTSRAD (IIU,IJU))
+!
+IF ((TPINIFILE%NMNHVERSION(1)==4 .AND. TPINIFILE%NMNHVERSION(2)>=6) .OR. TPINIFILE%NMNHVERSION(1)>4) THEN
+  CALL IO_Field_read(TPINIFILE,'SURF',CSURF)
+ELSE
+  CSURF = "EXTE"
+END IF
+!
+!
+IF (CSURF=='EXTE' .AND. (CPROGRAM=='MESONH' .OR. CPROGRAM=='DIAG  ')) THEN
+  ! ouverture du fichier PGD
+  IF  ( LEN_TRIM(CINIFILEPGD) > 0 ) THEN
+    CALL IO_File_add2list(TINIFILEPGD,TRIM(CINIFILEPGD),'PGD','READ',KLFITYPE=2,KLFIVERB=NVERB)
+    CALL IO_File_open(TINIFILEPGD,KRESP=IRESP)
+    LUNIT_MODEL(KMI)%TINIFILEPGD => TINIFILEPGD
+    IF (IRESP/=0) THEN
+      WRITE(ILUOUT,FMT=*) "INI_MODEL_n ERROR TO OPEN THE FILE CINIFILEPGD=",CINIFILEPGD
+      WRITE(ILUOUT,FMT=*) "CHECK YOUR NAMELIST NAM_LUNITn"
+    !callabortstop
+      CALL PRINT_MSG(NVERB_FATAL,'GEN','INI_MODEL_n','')
+    ENDIF
+  ELSE
+  ! case after a spawning
+    CINIFILEPGD = TPINIFILE%CNAME
+  END IF
+  !
+  CALL GOTO_SURFEX(KMI)
+#ifdef CPLOASIS
+  CALL SFX_OASIS_READ_NAM(CPROGRAM,XTSTEP)
+  WRITE(*,*) 'SFX-OASIS: READ NAM_SFX_SEA_CPL OK'
+#endif
+  !* initialization of surface
+  CALL INIT_GROUND_PARAM_n ('ALL',SIZE(CSV),CSV,ZCO2,                             &
+                            XZENITH,XAZIM,XSW_BANDS,XLW_BANDS,ZDIR_ALB,ZSCA_ALB,  &
+                            ZEMIS,ZTSRAD                                )
+  !
+  IF (SIZE(XEMIS)>0) THEN
+    XDIR_ALB = ZDIR_ALB
+    XSCA_ALB = ZSCA_ALB
+    XEMIS    = ZEMIS
+    XTSRAD   = ZTSRAD
+    CALL MNHGET_SURF_PARAM_n (PSEA=XSEA)                          
+  END IF
+ELSE
+  !* fields not physically necessary, but must be initialized
+  IF (SIZE(XEMIS)>0) THEN
+    XDIR_ALB = 0.
+    XSCA_ALB = 0.
+    XEMIS    = 1.
+    XTSRAD   = XTT
+    XSEA     = 1.
+  END IF
+
+END IF
+IF (CSURF=='EXTE' .AND. (CPROGRAM=='SPAWN ')) THEN
+  ! ouverture du fichier PGD
+  CALL IO_File_add2list(TINIFILEPGD,TRIM(CINIFILEPGD),'PGD','READ',KLFITYPE=2,KLFIVERB=NVERB)
+  CALL IO_File_open(TINIFILEPGD,KRESP=IRESP)
+  LUNIT_MODEL(KMI)%TINIFILEPGD => TINIFILEPGD
+  IF (IRESP/=0) THEN
+    WRITE(ILUOUT,FMT=*) "INI_MODEL_n ERROR TO OPEN THE FILE CINIFILEPGD=",CINIFILEPGD
+    WRITE(ILUOUT,FMT=*) "CHECK YOUR NAMELIST NAM_LUNIT2_SPA"
+    !callabortstop
+    CALL PRINT_MSG(NVERB_FATAL,'GEN','INI_MODEL_n','')
+  ENDIF
+ENDIF
+!
+IF (.NOT.ASSOCIATED(TINIFILEPGD)) TINIFILEPGD => TFILE_DUMMY
+!
+  !* special case after spawning in prep_real_case
+IF (CSURF=='EXRM' .AND. CPROGRAM=='REAL  ') CSURF = 'EXTE'
+!
+DEALLOCATE(ZDIR_ALB)
+DEALLOCATE(ZSCA_ALB)
+DEALLOCATE(ZEMIS   )
+DEALLOCATE(ZTSRAD  )
+!
+DEALLOCATE(ZCO2)
+!
+!
+!* in a RESTART case, reads surface radiative quantities in the MESONH file
+!
+IF ((CRAD  == 'ECMW' .OR. CRAD  == 'ECRA') .AND. CGETRAD=='READ') THEN
+  CALL INI_SURF_RAD(TPINIFILE, XDIR_ALB, XSCA_ALB, XEMIS, XTSRAD)
+END IF
+!
+!
+!*      17.3   Mesonh fields
+!              -------------
+!
+IF (CPROGRAM/='REAL  ') CALL MNHREAD_ZS_DUMMY_n(TINIFILEPGD)
+!
+!-------------------------------------------------------------------------------
+!
+!*       18.    INITIALIZE THE PARAMETERS FOR THE PHYSICS
+!               -----------------------------------------
+!
+IF (CRAD   == 'ECMW') THEN
+!
+!* get cover mask for aerosols
+!
+  IF (CPROGRAM=='MESONH' .OR. CPROGRAM=='DIAG  ') THEN
+    ALLOCATE(ZSEA(IIU,IJU))
+    ALLOCATE(ZTOWN(IIU,IJU))
+    ALLOCATE(ZBARE(IIU,IJU))
+    IF (CSURF=='EXTE') THEN
+      CALL GOTO_SURFEX(KMI)
+      CALL MNHGET_SURF_PARAM_n(PSEA=ZSEA,PTOWN=ZTOWN,PBARE=ZBARE)
+    ELSE
+      ZSEA (:,:) = 1.
+      ZTOWN(:,:) = 0.
+      ZBARE(:,:) = 0.
+    END IF
+!
+    IF ( CAOP=='EXPL' .AND. LDUST ) THEN
+      ALLOCATE( XEXT_COEFF_WVL_LKT_DUST( NMAX_RADIUS_LKT_DUST, NMAX_SIGMA_LKT_DUST, NMAX_WVL_SW_DUST ) )
+      ALLOCATE( XEXT_COEFF_550_LKT_DUST( NMAX_RADIUS_LKT_DUST, NMAX_SIGMA_LKT_DUST )                   )
+      ALLOCATE( XPIZA_LKT_DUST         ( NMAX_RADIUS_LKT_DUST, NMAX_SIGMA_LKT_DUST, NMAX_WVL_SW_DUST ) )
+      ALLOCATE( XCGA_LKT_DUST          ( NMAX_RADIUS_LKT_DUST, NMAX_SIGMA_LKT_DUST, NMAX_WVL_SW_DUST ) )
+    END IF
+!
+    IF ( CAOP=='EXPL' .AND. LSALT ) THEN
+      ALLOCATE( XEXT_COEFF_WVL_LKT_SALT( NMAX_RADIUS_LKT_SALT, NMAX_SIGMA_LKT_SALT, NMAX_WVL_SW_SALT ) )
+      ALLOCATE( XEXT_COEFF_550_LKT_SALT( NMAX_RADIUS_LKT_SALT, NMAX_SIGMA_LKT_SALT )                   )
+      ALLOCATE( XPIZA_LKT_SALT         ( NMAX_RADIUS_LKT_SALT, NMAX_SIGMA_LKT_SALT, NMAX_WVL_SW_SALT ) )
+      ALLOCATE( XCGA_LKT_SALT          ( NMAX_RADIUS_LKT_SALT, NMAX_SIGMA_LKT_SALT, NMAX_WVL_SW_SALT ) )
+    END IF
+!
+    CALL INI_RADIATIONS_ECMWF (XZHAT,XPABST,XTHT,XTSRAD,XLAT,XLON,TDTCUR,TDTEXP,       &
+                               CLW,NDLON,NFLEV,NFLUX,NRAD,NSWB_OLD,CAER,NAER,NSTATM,   &
+                               XSTATM,ZSEA,ZTOWN,ZBARE,XOZON, XAER,XDST_WL, LSUBG_COND )
+!
+    DEALLOCATE(ZSEA,ZTOWN,ZBARE)
+    ALLOCATE (XAER_CLIM(SIZE(XAER,1),SIZE(XAER,2),SIZE(XAER,3),SIZE(XAER,4)))
+    XAER_CLIM(:,:,:,:) =XAER(:,:,:,:)
+!
+  END IF
+
+ELSE IF (CRAD   == 'ECRA') THEN
+#ifdef MNH_ECRAD
+!* get cover mask for aerosols
+!
+  IF (CPROGRAM=='MESONH' .OR. CPROGRAM=='DIAG  ') THEN
+    ALLOCATE(ZSEA(IIU,IJU))
+    ALLOCATE(ZTOWN(IIU,IJU))
+    ALLOCATE(ZBARE(IIU,IJU))
+    IF (CSURF=='EXTE') THEN
+      CALL GOTO_SURFEX(KMI)
+      CALL MNHGET_SURF_PARAM_n(PSEA=ZSEA,PTOWN=ZTOWN,PBARE=ZBARE)
+    ELSE
+      ZSEA (:,:) = 1.
+      ZTOWN(:,:) = 0.
+      ZBARE(:,:) = 0.
+    END IF
+!
+    CALL INI_RADIATIONS_ECRAD (XZHAT,XPABST,XTHT,XTSRAD,XLAT,XLON,TDTCUR,TDTEXP,       &
+                               CLW,NDLON,NFLEV,NFLUX,NRAD,NSWB_OLD,CAER,NAER,NSTATM,   &
+                               XSTATM,ZSEA,ZTOWN,ZBARE,XOZON, XAER,XDST_WL, LSUBG_COND )
+
+    DEALLOCATE(ZSEA,ZTOWN,ZBARE)
+    ALLOCATE (XAER_CLIM(SIZE(XAER,1),SIZE(XAER,2),SIZE(XAER,3),SIZE(XAER,4)))
+    XAER_CLIM(:,:,:,:) = XAER(:,:,:,:)
+!
+  END IF
+#endif
+ELSE
+  ALLOCATE (XOZON(0,0,0))
+  ALLOCATE (XAER(0,0,0,0))
+  ALLOCATE (XDST_WL(0,0,0,0))
+  ALLOCATE (XAER_CLIM(0,0,0,0))  
+END IF
+!
+!
+!
+IF (CDCONV /= 'NONE' .OR. CSCONV == 'KAFR') THEN
+  IF (CGETCONV=='INIT') THEN
+    GINIDCONV=.TRUE.
+  ELSE
+    GINIDCONV=.FALSE.
+  END IF
+!
+!  commensurability between convection calling time and time step
+!
+  XDTCONV=XTSTEP*REAL( INT( (MIN(XDTCONV,1800.)+1.E-10)/XTSTEP ) )
+  XDTCONV=MAX( XDTCONV, XTSTEP )
+  IF (NVERB>=10) THEN
+    WRITE(ILUOUT,*) 'XDTCONV has been set to : ',XDTCONV
+  END IF
+  CALL INI_DEEP_CONVECTION (TPINIFILE,GINIDCONV,TDTCUR,                      &
+                           NCOUNTCONV,XDTHCONV,XDRVCONV,XDRCCONV,            &
+                           XDRICONV,XPRCONV,XPRSCONV,XPACCONV,               &
+                           XUMFCONV,XDMFCONV,XMFCONV,XPRLFLXCONV,XPRSFLXCONV,&
+                           XCAPE,NCLTOPCONV,NCLBASCONV,                      &
+                           TDTDCONV, CGETSVCONV, XDSVCONV,                   &
+                           LCH_CONV_LINOX, XIC_RATE, XCG_RATE,               &
+                           XIC_TOTAL_NUMBER, XCG_TOTAL_NUMBER                )
+
+END IF
+!
+!-------------------------------------------------------------------------------
+!
+!
+!*      19.    ALLOCATION OF THE TEMPORAL SERIES
+!              ---------------------------------
+!
+IF (LSERIES .AND. CPROGRAM/='DIAG  ') CALL INI_SERIES_n
+!
+!-------------------------------------------------------------------------------
+!
+!
+!*      20.   (re)initialize scalar variables
+!             -------------------------------
+!
+!
+IF ( LUSECHEM .OR. LCHEMDIAG ) THEN
+  IF (CPROGRAM=='MESONH'.AND.CCONF=='RESTA') LCH_INIT_FIELD =.FALSE.
+  IF (CPROGRAM=='MESONH'.OR. CPROGRAM=='DIAG  ' .OR. CPROGRAM=='IDEAL ') &
+        CALL CH_INIT_FIELD_n(KMI, ILUOUT, NVERB)
+END IF
+!
+!-------------------------------------------------------------------------------
+!
+!*      21.    UPDATE HALO
+!              -----------
+!
+!
+CALL UPDATE_HALO_ll(TZINITHALO3D_ll,IINFO_ll)
+CALL UPDATE_HALO_ll(TZINITHALO2D_ll,IINFO_ll)
+CALL CLEANLIST_ll(TZINITHALO3D_ll)
+CALL CLEANLIST_ll(TZINITHALO2D_ll)
+!
+!
+!-------------------------------------------------------------------------------
+!
+!*      22.    DEALLOCATION
+!              -------------
+!
+DEALLOCATE(ZJ)
+!
+DEALLOCATE(XSTROATM)
+DEALLOCATE(XSMLSATM)
+DEALLOCATE(XSMLWATM)
+DEALLOCATE(XSPOSATM)
+DEALLOCATE(XSPOWATM)
+!
+!-------------------------------------------------------------------------------
+!
+!*      23.     BALLOON and AIRCRAFT initializations
+!              ------------------------------------
+!
+CALL INI_AIRCRAFT_BALLOON(TPINIFILE,XTSTEP, TDTSEG, XSEGLEN, NRR, NSV, &
+                          IKU,CTURB=="TKEL" ,                          &
+                          XLATORI, XLONORI                             )
+!
+!-------------------------------------------------------------------------------
+!
+!*      24.     STATION initializations
+!              -----------------------
+!
+CALL INI_SURFSTATION_n(XTSTEP, TDTSEG, XSEGLEN, NRR, NSV, &
+                       CTURB=="TKEL" ,                    &
+                       XLATORI, XLONORI                   )
+!
+!-------------------------------------------------------------------------------
+!
+!*      25.     PROFILER initializations
+!              ------------------------
+!
+CALL INI_POSPROFILER_n(XTSTEP, TDTSEG, XSEGLEN, NRR, NSV,  &
+                       CTURB=="TKEL",                      &
+                       XLATORI, XLONORI                    )
+!
+!-------------------------------------------------------------------------------
+!
+!*      26.     Prognostic aerosols          
+!              ------------------------
+!
+IF ( ( CRAD=='ECMW' .OR. CRAD=='ECRA' ) .AND. CAOP=='EXPL' .AND. LORILAM ) THEN
+  ALLOCATE(POLYTAU(6,10,8,6,13))
+  ALLOCATE(POLYSSA(6,10,8,6,13))
+  ALLOCATE(POLYG  (6,10,8,6,13))
+  CALL INI_AEROSET1
+  CALL INI_AEROSET2
+  CALL INI_AEROSET3
+  CALL INI_AEROSET4
+  CALL INI_AEROSET5
+  CALL INI_AEROSET6
+END IF
+#ifdef MNH_FOREFIRE
+! 
+!-------------------------------------------------------------------------------
+!
+!*      27.    FOREFIRE initializations
+!              ------------------------
+!
+
+! Coupling with ForeFire if resolution is low enough
+!---------------------------------------------------
+IF ( LFOREFIRE .AND. 0.5*(XXHAT(2)-XXHAT(1)+XYHAT(2)-XYHAT(1)) < COUPLINGRES ) THEN
+  FFCOUPLING = .TRUE.
+ELSE
+  FFCOUPLING = .FALSE.
+ENDIF
+
+! Initializing the ForeFire variables
+!------------------------------------
+IF ( LFOREFIRE ) THEN
+  CALL INIT_FOREFIRE_n(KMI, ILUOUT, IP &
+        , TDTCUR%TDATE%YEAR, TDTCUR%TDATE%MONTH, TDTCUR%TDATE%DAY, TDTCUR%TIME, XTSTEP)
+END IF
+#endif
+
+!-------------------------------------------------------------------------------
+!
+!*      30.   Total production/Loss for chemical species
+!
+IF (LCHEMDIAG)  THEN
+  CALL CH_INIT_PRODLOSSTOT_n(ILUOUT)
+  IF (NEQ_PLT>0) THEN
+    ALLOCATE(XPROD(IIU,IJU,IKU,NEQ_PLT))
+    ALLOCATE(XLOSS(IIU,IJU,IKU,NEQ_PLT))
+    XPROD=0.0
+    XLOSS=0.0
+  ELSE
+    ALLOCATE(XPROD(0,0,0,0))
+    ALLOCATE(XLOSS(0,0,0,0))
+  END IF
+ELSE
+  ALLOCATE(XPROD(0,0,0,0))
+  ALLOCATE(XLOSS(0,0,0,0))
+END IF
+!
+!-------------------------------------------------------------------------------
+!
+!*     31. Extended production/loss terms for chemical species
+!
+IF (LCHEMDIAG) THEN
+  CALL CH_INIT_BUDGET_n(ILUOUT)
+  IF (NEQ_BUDGET>0) THEN
+    ALLOCATE(IINDEX(2,NNONZEROTERMS))
+    ALLOCATE(IIND(NEQ_BUDGET))
+    CALL CH_NONZEROTERMS(KMI,IINDEX,NNONZEROTERMS)
+    ALLOCATE(XTCHEM(NEQ_BUDGET))
+    DO JM=1,NEQ_BUDGET
+      IIND(JM)=COUNT((IINDEX(1,:))==NSPEC_BUDGET(JM))
+      ALLOCATE(XTCHEM(JM)%NB_REAC(IIND(JM)))
+      ALLOCATE(XTCHEM(JM)%XB_REAC(IIU,IJU,IKU,IIND(JM)))
+    END DO
+    DEALLOCATE(IIND)
+    DEALLOCATE(IINDEX)
+  ELSE
+    ALLOCATE(XTCHEM(0))
+  END IF
+ELSE
+  ALLOCATE(XTCHEM(0))
+END IF
+
+END SUBROUTINE INI_MODEL_n
+
diff --git a/src/ZSOLVER/ini_spectren.f90 b/src/ZSOLVER/ini_spectren.f90
new file mode 100644
index 0000000000000000000000000000000000000000..4783443207ecf52aa183b97da09c2f4014f94b58
--- /dev/null
+++ b/src/ZSOLVER/ini_spectren.f90
@@ -0,0 +1,941 @@
+!MNH_LIC Copyright 2015-2019 CNRS, Meteo-France and Universite Paul Sabatier
+!MNH_LIC This is part of the Meso-NH software governed by the CeCILL-C licence
+!MNH_LIC version 1. See LICENSE, CeCILL-C_V1-en.txt and CeCILL-C_V1-fr.txt
+!MNH_LIC for details. version 1.
+!-----------------------------------------------------------------
+!     #######################
+      MODULE MODI_INI_SPECTRE_n
+!     #######################
+!
+INTERFACE
+!
+       SUBROUTINE INI_SPECTRE_n(KMI,TPINIFILE)
+!
+       USE MODD_IO, ONLY: TFILEDATA
+!
+       INTEGER,           INTENT(IN) :: KMI       ! Model index 
+       TYPE(TFILEDATA),   INTENT(IN) :: TPINIFILE ! Initial file
+!
+END SUBROUTINE INI_SPECTRE_n
+!
+END INTERFACE
+!
+END MODULE MODI_INI_SPECTRE_n
+!     #######################################
+      SUBROUTINE INI_SPECTRE_n(KMI,TPINIFILE)
+!     #######################################
+!
+!!****  *INI_SPECTRE_n* - routine to initialize SPECTRE (based on ini_modeln.f90)
+!!
+!!
+!!    AUTHOR
+!!    ------
+!!      J.P Chaboureau       * L.A*
+!!      10/2016 (C.Lac) Cleaning of the modules
+!!  Philippe Wautelet: 05/2016-04/2018: new data structures and calls for I/O
+!  P. Wautelet 08/02/2019: allocate to zero-size non associated pointers
+!  P. Wautelet 14/02/2019: remove CLUOUT/CLUOUT0 and associated variables
+!  S. Bielli      02/2019: sea salt: significant sea wave height influences salt emission; 5 salt modes
+!  P. Wautelet 10/04/2019: replace ABORT and STOP calls by Print_msg
+!  P. Wautelet 19/04/2019: removed unused dummy arguments and variables
+!
+!---------------------------------------------------------------------------------
+!
+!*       0.    DECLARATIONS
+!              ------------
+!
+USE MODD_ADV_n
+USE MODD_ARGSLIST_ll,   ONLY: LIST_ll
+USE MODD_BIKHARDT_n
+USE MODD_BUDGET
+USE MODD_CH_MNHC_n,     ONLY: LUSECHAQ, LUSECHIC, LCH_INIT_FIELD
+USE MODD_CH_PH_n
+USE MODD_CLOUD_MF_n
+USE MODD_CST
+USE MODD_CONF
+USE MODD_CONF_n
+USE MODD_CTURB
+USE MODD_CURVCOR_n
+USE MODD_DEEP_CONVECTION_n
+USE MODD_DIM_n
+USE MODD_DRAGTREE
+USE MODD_DUST
+USE MODD_DYN
+USE MODD_DYN_n
+USE MODD_DYNZD
+USE MODD_DYNZD_n
+USE MODD_FIELD_n
+USE MODD_FRC
+USE MODD_FRC_n
+USE MODD_GET_n
+USE MODD_GRID,          ONLY: XLONORI,XLATORI
+USE MODD_GRID_n
+USE MODD_IO,            ONLY: TFILEDATA
+USE MODD_LBC_n,         only: CLBCX, CLBCY
+USE MODD_LSFIELD_n
+USE MODD_LUNIT_n,       ONLY: COUTFILE, TLUOUT
+USE MODD_MEAN_FIELD
+USE MODD_MEAN_FIELD_n
+USE MODD_METRICS_n
+USE MODD_NESTING,       only: NDAD, NDT_2_WAY, NDXRATIO_ALL, NDYRATIO_ALL
+USE MODD_NSV
+USE MODD_OUT_n
+USE MODD_PARAMETERS
+USE MODD_PARAM_KAFR_n
+USE MODD_PARAM_MFSHALL_n
+USE MODD_PARAM_n
+USE MODD_PASPOL
+USE MODD_PASPOL_n
+USE MODD_BLOWSNOW
+USE MODD_BLOWSNOW_n
+USE MODD_PAST_FIELD_n
+USE MODD_RADIATIONS_n
+USE MODD_REF
+USE MODD_REF_n
+USE MODD_SHADOWS_n
+USE MODD_SPECTRE
+USE MODD_TIME
+USE MODD_TIME_n
+USE MODD_TURB_n
+USE MODD_VAR_ll,        ONLY: IP
+!
+USE MODE_GATHER_ll
+USE MODE_INI_ONE_WAY_n
+USE MODE_IO_FIELD_READ, only: IO_Field_read
+USE MODE_ll
+USE MODE_MODELN_HANDLER
+USE MODE_MSG
+USE MODE_SPLITTINGZ_ll, ONLY: GET_DIM_EXTZ_ll
+USE MODE_TYPE_ZDIFFU
+!
+USE MODI_INI_BIKHARDT_n
+USE MODI_INI_CPL
+USE MODI_INI_DYNAMICS
+USE MODI_INI_SPAWN_LS_n
+USE MODI_GET_SIZEX_LB
+USE MODI_GET_SIZEY_LB
+USE MODI_SET_GRID
+USE MODI_METRICS
+USE MODI_SET_REF
+USE MODI_UPDATE_METRICS
+USE MODI_UPDATE_NSV
+!
+IMPLICIT NONE
+!
+!*       0.1   declarations of arguments
+!
+!
+INTEGER,           INTENT(IN) :: KMI       ! Model index 
+TYPE(TFILEDATA),   INTENT(IN) :: TPINIFILE ! Initial file
+!
+!*       0.2   declarations of local variables
+!
+INTEGER             :: ILUOUT  ! Logical unit number of output-listing
+INTEGER             :: IIU     ! Upper dimension in x direction (local)
+INTEGER             :: IJU     ! Upper dimension in y direction (local)
+INTEGER             :: IIU_ll  ! Upper dimension in x direction (global)
+INTEGER             :: IJU_ll  ! Upper dimension in y direction (global)
+INTEGER             :: IKU     ! Upper dimension in z direction
+REAL, DIMENSION(:,:,:), ALLOCATABLE :: ZJ ! Jacobian
+!
+!
+TYPE(LIST_ll), POINTER :: TZINITHALO2D_ll ! pointer for the list of 2D fields
+                                      !  which must be communicated in INIT
+TYPE(LIST_ll), POINTER :: TZINITHALO3D_ll ! pointer for the list of 3D fields
+                                      !  which must be communicated in INIT
+!
+INTEGER :: IISIZEXF,IJSIZEXF,IISIZEXFU,IJSIZEXFU     ! dimensions of the
+INTEGER :: IISIZEX4,IJSIZEX4,IISIZEX2,IJSIZEX2       ! West-east LB arrays
+INTEGER :: IISIZEYF,IJSIZEYF,IISIZEYFV,IJSIZEYFV     ! dimensions of the
+INTEGER :: IISIZEY4,IJSIZEY4,IISIZEY2,IJSIZEY2       ! North-south LB arrays
+INTEGER :: IINFO_ll  ! Return code of //routines
+INTEGER :: IIY,IJY
+INTEGER :: IIU_B,IJU_B
+INTEGER :: IIU_SXP2_YP1_Z_ll,IJU_SXP2_YP1_Z_ll,IKU_SXP2_YP1_Z_ll
+!
+!------------------------------------------
+! Dummy pointers needed to correct an ifort Bug
+REAL, DIMENSION(:), POINTER :: DPTR_XZHAT
+REAL, DIMENSION(:), POINTER :: DPTR_XBMX1,DPTR_XBMX2,DPTR_XBMX3,DPTR_XBMX4
+REAL, DIMENSION(:), POINTER :: DPTR_XBMY1,DPTR_XBMY2,DPTR_XBMY3,DPTR_XBMY4
+REAL, DIMENSION(:), POINTER :: DPTR_XBFX1,DPTR_XBFX2,DPTR_XBFX3,DPTR_XBFX4
+REAL, DIMENSION(:), POINTER :: DPTR_XBFY1,DPTR_XBFY2,DPTR_XBFY3,DPTR_XBFY4
+CHARACTER(LEN=4), DIMENSION(:), POINTER :: DPTR_CLBCX,DPTR_CLBCY
+INTEGER, DIMENSION(:,:,:), POINTER :: DPTR_NKLIN_LBXU,DPTR_NKLIN_LBYU,DPTR_NKLIN_LBXV,DPTR_NKLIN_LBYV
+INTEGER, DIMENSION(:,:,:), POINTER :: DPTR_NKLIN_LBXW,DPTR_NKLIN_LBYW,DPTR_NKLIN_LBXM,DPTR_NKLIN_LBYM
+REAL, DIMENSION(:,:,:), POINTER :: DPTR_XCOEFLIN_LBXU,DPTR_XCOEFLIN_LBYU
+REAL, DIMENSION(:,:,:), POINTER :: DPTR_XCOEFLIN_LBXV,DPTR_XCOEFLIN_LBYV
+REAL, DIMENSION(:,:,:), POINTER :: DPTR_XCOEFLIN_LBXW,DPTR_XCOEFLIN_LBYW
+REAL, DIMENSION(:,:,:), POINTER :: DPTR_XCOEFLIN_LBXM,DPTR_XCOEFLIN_LBYM
+REAL, DIMENSION(:,:,:),   POINTER :: DPTR_XLBXUM,DPTR_XLBYUM,DPTR_XLBXVM,DPTR_XLBYVM
+REAL, DIMENSION(:,:,:),   POINTER :: DPTR_XLBXWM,DPTR_XLBYWM,DPTR_XLBXTHM,DPTR_XLBYTHM
+REAL, DIMENSION(:,:,:),   POINTER :: DPTR_XLBXTKEM,DPTR_XLBYTKEM
+REAL, DIMENSION(:,:,:,:),   POINTER :: DPTR_XLBXSVM,DPTR_XLBYSVM                
+REAL, DIMENSION(:,:,:,:), POINTER :: DPTR_XLBXRM,DPTR_XLBYRM
+REAL, DIMENSION(:,:,:),   POINTER ::  DPTR_XZZ
+REAL, DIMENSION(:,:,:), POINTER ::   DPTR_XLSUM,DPTR_XLSVM,DPTR_XLSWM,DPTR_XLSTHM,DPTR_XLSRVM
+REAL, DIMENSION(:,:,:), POINTER ::   DPTR_XLSUS,DPTR_XLSVS,DPTR_XLSWS,DPTR_XLSTHS,DPTR_XLSRVS
+REAL, DIMENSION(:,:),   POINTER ::   DPTR_XLSZWSS,DPTR_XLSZWSM
+!
+!-------------------------------------------------------------------------------
+!
+!*       0.    PROLOGUE
+!              --------
+!
+NULLIFY(TZINITHALO2D_ll)
+NULLIFY(TZINITHALO3D_ll)
+!
+!*       1.    RETRIEVE LOGICAL UNIT NUMBER
+!              ----------------------------
+!
+ILUOUT = TLUOUT%NLU
+!
+!-------------------------------------------------------------------------------
+!
+!*       2.   END OF READING
+!             --------------
+!*       2.1  Read number of forcing fields
+!
+!*       2.2  Checks the position of vertical absorbing layer
+!
+IKU=NKMAX+2*JPVEXT
+!
+ALLOCATE(XZHAT(IKU))
+CALL IO_Field_read(TPINIFILE,'ZHAT',XZHAT)
+CALL IO_Field_read(TPINIFILE,'ZTOP',XZTOP)
+IF (XALZBOT>=XZHAT(IKU) .AND. LVE_RELAX) THEN
+  WRITE(ILUOUT,FMT=*) "INI_SPECTRE_n ERROR: you want to use vertical relaxation"
+  WRITE(ILUOUT,FMT=*) "                  but bottom of layer XALZBOT(",XALZBOT,")"
+  WRITE(ILUOUT,FMT=*) "                  is upper than model top    (",XZHAT(IKU),")"
+!callabortstop
+  CALL PRINT_MSG(NVERB_FATAL,'GEN','INI_SPECTRE_n','')
+END IF
+IF (LVE_RELAX) THEN
+ IF (XALZBOT>=XZHAT(IKU-4) ) THEN
+  WRITE(ILUOUT,FMT=*) "INI_SPECTRE_n WARNING: you want to use vertical relaxation"
+  WRITE(ILUOUT,FMT=*) "                    but the layer defined by XALZBOT(",XALZBOT,")"
+  WRITE(ILUOUT,FMT=*) "                    contains less than 5 model levels"
+ END IF
+END IF
+DEALLOCATE(XZHAT)
+!
+!*       2.3  Compute sizes of arrays of the extended sub-domain
+!
+CALL GET_DIM_EXT_ll('B',IIU,IJU)
+IIU_ll=NIMAX_ll + 2 * JPHEXT
+IJU_ll=NJMAX_ll + 2 * JPHEXT
+! initialize NIMAX and NJMAX for not updated versions regarding the parallelism
+! spawning,...
+CALL GET_DIM_PHYS_ll('B',NIMAX,NJMAX)
+!
+NRR=1
+NRRL=0
+NRRI=0
+IF (NVERB >= 5) THEN
+  WRITE (UNIT=ILUOUT,FMT='("THERE ARE ",I2," WATER VARIABLES")') NRR
+  WRITE (UNIT=ILUOUT,FMT='("THERE ARE ",I2," LIQUID VARIABLES")') NRRL
+  WRITE (UNIT=ILUOUT,FMT='("THERE ARE ",I2," SOLID VARIABLES")') NRRI
+END IF
+!
+!*       2.3  Update NSV and floating indices for the current model
+!
+! 
+CALL UPDATE_NSV(KMI) 
+!
+!-------------------------------------------------------------------------------
+!
+!*       3.    ALLOCATE  MEMORY
+!              -----------------
+!
+!*       3.2   Module MODD_GRID_n and MODD_METRICS_n
+!
+IF (LCARTESIAN) THEN
+  ALLOCATE(XLON(0,0))
+  ALLOCATE(XLAT(0,0))
+  ALLOCATE(XMAP(0,0))
+ELSE
+  ALLOCATE(XLON(IIU,IJU))
+  ALLOCATE(XLAT(IIU,IJU))
+  ALLOCATE(XMAP(IIU,IJU))
+END IF
+ALLOCATE(XXHAT(IIU))
+ALLOCATE(XDXHAT(IIU))
+ALLOCATE(XYHAT(IJU))
+ALLOCATE(XDYHAT(IJU))
+ALLOCATE(XZS(IIU,IJU))
+ALLOCATE(XZSMT(IIU,IJU))
+ALLOCATE(XZZ(IIU,IJU,IKU))
+ALLOCATE(XZHAT(IKU))
+!
+ALLOCATE(XDXX(IIU,IJU,IKU))
+ALLOCATE(XDYY(IIU,IJU,IKU))
+ALLOCATE(XDZX(IIU,IJU,IKU))
+ALLOCATE(XDZY(IIU,IJU,IKU))
+ALLOCATE(XDZZ(IIU,IJU,IKU))
+!
+!*       3.3   Modules MODD_REF and  MODD_REF_n
+!
+IF (KMI == 1) THEN
+  ALLOCATE(XRHODREFZ(IKU),XTHVREFZ(IKU))
+END IF
+ALLOCATE(XRHODREF(IIU,IJU,IKU))
+ALLOCATE(XTHVREF(IIU,IJU,IKU))
+ALLOCATE(XEXNREF(IIU,IJU,IKU))
+ALLOCATE(XRHODJ(IIU,IJU,IKU))
+IF (CEQNSYS=='DUR' .AND. LUSERV) THEN
+  ALLOCATE(XRVREF(IIU,IJU,IKU))
+ELSE
+  ALLOCATE(XRVREF(0,0,0))
+END IF
+!
+!*       3.4   Module MODD_CURVCOR_n
+!
+IF (LTHINSHELL) THEN
+  ALLOCATE(XCORIOX(0,0))
+  ALLOCATE(XCORIOY(0,0))
+ELSE
+  ALLOCATE(XCORIOX(IIU,IJU))
+  ALLOCATE(XCORIOY(IIU,IJU))
+END IF
+  ALLOCATE(XCORIOZ(IIU,IJU))
+IF (LCARTESIAN) THEN
+  ALLOCATE(XCURVX(0,0))
+  ALLOCATE(XCURVY(0,0))
+ELSE
+  ALLOCATE(XCURVX(IIU,IJU))
+  ALLOCATE(XCURVY(IIU,IJU))
+END IF
+!
+!*       3.5   Module MODD_DYN_n
+!
+CALL GET_DIM_EXT_ll('Y',IIY,IJY)
+IF (L2D) THEN
+  ALLOCATE(XBFY(IIY,IJY,IKU))
+ELSE
+  ALLOCATE(XBFY(IJY,IIY,IKU)) ! transposition needed by the optimisition of the
+                              ! FFT solver
+END IF
+CALL GET_DIM_EXT_ll('B',IIU_B,IJU_B)
+ALLOCATE(XBFB(IIU_B,IJU_B,IKU))
+CALL GET_DIM_EXTZ_ll('SXP2_YP1_Z',IIU_SXP2_YP1_Z_ll,IJU_SXP2_YP1_Z_ll,IKU_SXP2_YP1_Z_ll)
+ALLOCATE(XBF_SXP2_YP1_Z(IIU_SXP2_YP1_Z_ll,IJU_SXP2_YP1_Z_ll,IKU_SXP2_YP1_Z_ll))
+ALLOCATE(XAF(IKU),XCF(IKU))
+ALLOCATE(XTRIGSX(3*IIU_ll))
+ALLOCATE(XTRIGSY(3*IJU_ll))
+ALLOCATE(XRHOM(IKU))
+ALLOCATE(XALK(IKU))
+ALLOCATE(XALKW(IKU))
+!
+IF ( LHORELAX_UVWTH .OR. LHORELAX_RV .OR.                                  &
+     LHORELAX_RC .OR. LHORELAX_RR .OR. LHORELAX_RI  .OR. LHORELAX_RS  .OR. &
+     LHORELAX_RG .OR. LHORELAX_RH .OR. LHORELAX_TKE .OR.                   &
+     ANY(LHORELAX_SV) ) THEN
+  ALLOCATE(XKURELAX(IIU,IJU))
+  ALLOCATE(XKVRELAX(IIU,IJU))
+  ALLOCATE(XKWRELAX(IIU,IJU))
+  ALLOCATE(LMASK_RELAX(IIU,IJU))
+ELSE
+  ALLOCATE(XKURELAX(0,0))
+  ALLOCATE(XKVRELAX(0,0))
+  ALLOCATE(XKWRELAX(0,0))
+  ALLOCATE(LMASK_RELAX(0,0))
+END IF
+!
+! Additional fields for truly horizontal diffusion (Module MODD_DYNZD$n)
+IF (LZDIFFU) THEN
+  CALL INIT_TYPE_ZDIFFU_HALO2(XZDIFFU_HALO2)
+ELSE
+  CALL INIT_TYPE_ZDIFFU_HALO2(XZDIFFU_HALO2,0)
+ENDIF
+!
+!*       3.6   Larger Scale variables (Module MODD_LSFIELD$n)
+!
+!
+! upper relaxation part
+!
+ALLOCATE(XLSUM(IIU,IJU,IKU))    ; XLSUM  = 0.0
+ALLOCATE(XLSVM(IIU,IJU,IKU))    ; XLSVM  = 0.0
+ALLOCATE(XLSWM(IIU,IJU,IKU))    ; XLSWM  = 0.0
+ALLOCATE(XLSTHM(IIU,IJU,IKU))   ; XLSTHM = 0.0
+IF ( NRR > 0 ) THEN
+  ALLOCATE(XLSRVM(IIU,IJU,IKU)) ; XLSRVM = 0.0
+ELSE
+  ALLOCATE(XLSRVM(0,0,0))
+END IF
+!
+!  lbc part
+!
+IF ( L1D) THEN                         ! 1D case
+!
+  NSIZELBX_ll=0
+  NSIZELBXU_ll=0
+  NSIZELBY_ll=0
+  NSIZELBYV_ll=0
+  NSIZELBXTKE_ll=0
+  NSIZELBXR_ll=0
+  NSIZELBXSV_ll=0
+  NSIZELBYTKE_ll=0
+  NSIZELBYR_ll=0
+  NSIZELBYSV_ll=0
+  ALLOCATE(XLBXUM(0,0,0))
+  ALLOCATE(XLBYUM(0,0,0))
+  ALLOCATE(XLBXVM(0,0,0))
+  ALLOCATE(XLBYVM(0,0,0))
+  ALLOCATE(XLBXWM(0,0,0))
+  ALLOCATE(XLBYWM(0,0,0))
+  ALLOCATE(XLBXTHM(0,0,0))
+  ALLOCATE(XLBYTHM(0,0,0))
+  ALLOCATE(XLBXTKEM(0,0,0))
+  ALLOCATE(XLBYTKEM(0,0,0))
+  ALLOCATE(XLBXRM(0,0,0,0))
+  ALLOCATE(XLBYRM(0,0,0,0))
+  ALLOCATE(XLBXSVM(0,0,0,0))
+  ALLOCATE(XLBYSVM(0,0,0,0))
+!
+ELSEIF( L2D ) THEN                         ! 2D case
+!
+  NSIZELBY_ll=0
+  NSIZELBYV_ll=0
+  NSIZELBYTKE_ll=0
+  NSIZELBYR_ll=0
+  NSIZELBYSV_ll=0
+  ALLOCATE(XLBYUM(0,0,0))
+  ALLOCATE(XLBYVM(0,0,0))
+  ALLOCATE(XLBYWM(0,0,0))
+  ALLOCATE(XLBYTHM(0,0,0))
+  ALLOCATE(XLBYTKEM(0,0,0))
+  ALLOCATE(XLBYRM(0,0,0,0))
+  ALLOCATE(XLBYSVM(0,0,0,0))
+!
+  CALL GET_SIZEX_LB(NIMAX_ll,NJMAX_ll,NRIMX,               &
+                    IISIZEXF,IJSIZEXF,IISIZEXFU,IJSIZEXFU, &
+                    IISIZEX4,IJSIZEX4,IISIZEX2,IJSIZEX2)
+!
+  IF ( LHORELAX_UVWTH ) THEN
+    NSIZELBX_ll=2*NRIMX+2
+    NSIZELBXU_ll=2*NRIMX+2
+    ALLOCATE(XLBXUM(IISIZEXFU,IJSIZEXFU,IKU))
+    ALLOCATE(XLBXVM(IISIZEXF,IJSIZEXF,IKU))
+    ALLOCATE(XLBXWM(IISIZEXF,IJSIZEXF,IKU))
+    ALLOCATE(XLBXTHM(IISIZEXF,IJSIZEXF,IKU))
+  ELSE
+    NSIZELBX_ll=2
+    NSIZELBXU_ll=4
+    ALLOCATE(XLBXUM(IISIZEX4,IJSIZEX4,IKU))
+    ALLOCATE(XLBXVM(IISIZEX2,IJSIZEX2,IKU))
+    ALLOCATE(XLBXWM(IISIZEX2,IJSIZEX2,IKU))
+    ALLOCATE(XLBXTHM(IISIZEX2,IJSIZEX2,IKU))
+  END IF
+!
+  IF (CTURB /= 'NONE') THEN
+    IF ( LHORELAX_TKE) THEN
+      NSIZELBXTKE_ll=2* NRIMX+2
+      ALLOCATE(XLBXTKEM(IISIZEXF,IJSIZEXF,IKU))
+    ELSE
+      NSIZELBXTKE_ll=2
+      ALLOCATE(XLBXTKEM(IISIZEX2,IJSIZEX2,IKU))
+    END IF
+  ELSE
+    NSIZELBXTKE_ll=0
+    ALLOCATE(XLBXTKEM(0,0,0))
+  END IF
+  !
+  IF ( NRR > 0 ) THEN
+    IF (LHORELAX_RV .OR. LHORELAX_RC .OR. LHORELAX_RR .OR. LHORELAX_RI    &
+         .OR. LHORELAX_RS .OR. LHORELAX_RG .OR. LHORELAX_RH               &
+       ) THEN
+      NSIZELBXR_ll=2* NRIMX+2
+      ALLOCATE(XLBXRM(IISIZEXF,IJSIZEXF,IKU,NRR))
+    ELSE
+      NSIZELBXR_ll=2
+      ALLOCATE(XLBXRM(IISIZEX2,IJSIZEX2,IKU,NRR))
+    ENDIF
+  ELSE
+    NSIZELBXR_ll=0
+    ALLOCATE(XLBXRM(0,0,0,0))
+  END IF
+  !
+  IF ( NSV > 0 ) THEN
+    IF ( ANY( LHORELAX_SV(:)) ) THEN
+      NSIZELBXSV_ll=2* NRIMX+2
+      ALLOCATE(XLBXSVM(IISIZEXF,IJSIZEXF,IKU,NSV))
+    ELSE
+      NSIZELBXSV_ll=2
+      ALLOCATE(XLBXSVM(IISIZEX2,IJSIZEX2,IKU,NSV))
+    END IF
+  ELSE
+    NSIZELBXSV_ll=0
+    ALLOCATE(XLBXSVM(0,0,0,0))
+  END IF
+!
+ELSE                                   ! 3D case
+!
+!
+  CALL GET_SIZEX_LB(NIMAX_ll,NJMAX_ll,NRIMX,               &
+                    IISIZEXF,IJSIZEXF,IISIZEXFU,IJSIZEXFU, &
+                    IISIZEX4,IJSIZEX4,IISIZEX2,IJSIZEX2)
+  CALL GET_SIZEY_LB(NIMAX_ll,NJMAX_ll,NRIMY,               &
+                    IISIZEYF,IJSIZEYF,IISIZEYFV,IJSIZEYFV, &
+                    IISIZEY4,IJSIZEY4,IISIZEY2,IJSIZEY2)
+!
+! check if local domain not to small for NRIMX NRIMY
+!
+  IF ( CLBCX(1) /= 'CYCL' )  THEN
+     IF ( NRIMX+2*JPHEXT .GE. IIU )   THEN
+        WRITE(*,'(A,I8,A/A,2I8,/A)') "Processor=", IP-1, &
+             " :: INI_SPECTRE_n ERROR:  ( NRIMX+2*JPHEXT >= IIU )  ", &
+             " Local domain to small for relaxation NRIMX+2*JPHEXT,IIU ", &
+             NRIMX+2*JPHEXT,IIU ,&
+             " change relaxation parameters or number of processors "
+        call Print_msg(NVERB_FATAL,'GEN','INI_SPECTRE_n','')
+     END IF
+  END IF
+  IF ( CLBCY(1) /= 'CYCL' ) THEN
+     IF ( NRIMY+2*JPHEXT .GE. IJU )  THEN
+        WRITE(*,'(A,I8,A/A,2I8,/A)') "Processor=", IP-1, &
+             " :: INI_SPECTRE_n ERROR:  ( NRIMY+2*JPHEXT >= IJU )  ", &
+             " Local domain to small for relaxation NRIMY+2*JPHEXT,IJU ", &
+             NRIMY+2*JPHEXT,IJU ,&
+             " change relaxation parameters or number of processors "
+        call Print_msg(NVERB_FATAL,'GEN','INI_SPECTRE_n','')
+     END IF
+  END IF
+IF ( LHORELAX_UVWTH ) THEN
+    NSIZELBX_ll=2*NRIMX+2
+    NSIZELBXU_ll=2*NRIMX+2
+    NSIZELBY_ll=2*NRIMY+2
+    NSIZELBYV_ll=2*NRIMY+2
+    ALLOCATE(XLBXUM(IISIZEXFU,IJSIZEXFU,IKU))
+    ALLOCATE(XLBYUM(IISIZEYF,IJSIZEYF,IKU))
+    ALLOCATE(XLBXVM(IISIZEXF,IJSIZEXF,IKU))
+    ALLOCATE(XLBYVM(IISIZEYFV,IJSIZEYFV,IKU))
+    ALLOCATE(XLBXWM(IISIZEXF,IJSIZEXF,IKU))
+    ALLOCATE(XLBYWM(IISIZEYF,IJSIZEYF,IKU))
+    ALLOCATE(XLBXTHM(IISIZEXF,IJSIZEXF,IKU))
+    ALLOCATE(XLBYTHM(IISIZEYF,IJSIZEYF,IKU))
+  ELSE
+    NSIZELBX_ll=2
+    NSIZELBXU_ll=4
+    NSIZELBY_ll=2
+    NSIZELBYV_ll=4
+    ALLOCATE(XLBXUM(IISIZEX4,IJSIZEX4,IKU))
+    ALLOCATE(XLBYUM(IISIZEY2,IJSIZEY2,IKU))
+    ALLOCATE(XLBXVM(IISIZEX2,IJSIZEX2,IKU))
+    ALLOCATE(XLBYVM(IISIZEY4,IJSIZEY4,IKU))
+    ALLOCATE(XLBXWM(IISIZEX2,IJSIZEX2,IKU))
+    ALLOCATE(XLBYWM(IISIZEY2,IJSIZEY2,IKU))
+    ALLOCATE(XLBXTHM(IISIZEX2,IJSIZEX2,IKU))
+    ALLOCATE(XLBYTHM(IISIZEY2,IJSIZEY2,IKU))
+  END IF
+  !
+  IF (CTURB /= 'NONE') THEN
+    IF ( LHORELAX_TKE) THEN
+      NSIZELBXTKE_ll=2*NRIMX+2
+      NSIZELBYTKE_ll=2*NRIMY+2
+      ALLOCATE(XLBXTKEM(IISIZEXF,IJSIZEXF,IKU))
+      ALLOCATE(XLBYTKEM(IISIZEYF,IJSIZEYF,IKU))
+    ELSE
+      NSIZELBXTKE_ll=2
+      NSIZELBYTKE_ll=2
+      ALLOCATE(XLBXTKEM(IISIZEX2,IJSIZEX2,IKU))
+      ALLOCATE(XLBYTKEM(IISIZEY2,IJSIZEY2,IKU))
+    END IF
+  ELSE
+    NSIZELBXTKE_ll=0
+    NSIZELBYTKE_ll=0
+    ALLOCATE(XLBXTKEM(0,0,0))
+    ALLOCATE(XLBYTKEM(0,0,0))
+  END IF
+  !
+  IF ( NRR > 0 ) THEN
+    IF (LHORELAX_RV .OR. LHORELAX_RC .OR. LHORELAX_RR .OR. LHORELAX_RI    &
+          .OR. LHORELAX_RS .OR. LHORELAX_RG .OR. LHORELAX_RH              &
+       ) THEN
+      NSIZELBXR_ll=2*NRIMX+2
+      NSIZELBYR_ll=2*NRIMY+2
+      ALLOCATE(XLBXRM(IISIZEXF,IJSIZEXF,IKU,NRR))
+      ALLOCATE(XLBYRM(IISIZEYF,IJSIZEYF,IKU,NRR))
+    ELSE
+      NSIZELBXR_ll=2
+      NSIZELBYR_ll=2
+      ALLOCATE(XLBXRM(IISIZEX2,IJSIZEX2,IKU,NRR))
+      ALLOCATE(XLBYRM(IISIZEY2,IJSIZEY2,IKU,NRR))
+    ENDIF
+  ELSE
+    NSIZELBXR_ll=0
+    NSIZELBYR_ll=0
+    ALLOCATE(XLBXRM(0,0,0,0))
+    ALLOCATE(XLBYRM(0,0,0,0))
+  END IF
+  !
+  IF ( NSV > 0 ) THEN
+    IF ( ANY( LHORELAX_SV(:)) ) THEN
+      NSIZELBXSV_ll=2*NRIMX+2
+      NSIZELBYSV_ll=2*NRIMY+2
+      ALLOCATE(XLBXSVM(IISIZEXF,IJSIZEXF,IKU,NSV))
+      ALLOCATE(XLBYSVM(IISIZEYF,IJSIZEYF,IKU,NSV))
+    ELSE
+      NSIZELBXSV_ll=2
+      NSIZELBYSV_ll=2
+      ALLOCATE(XLBXSVM(IISIZEX2,IJSIZEX2,IKU,NSV))
+      ALLOCATE(XLBYSVM(IISIZEY2,IJSIZEY2,IKU,NSV))
+    END IF
+  ELSE
+    NSIZELBXSV_ll=0
+    NSIZELBYSV_ll=0
+    ALLOCATE(XLBXSVM(0,0,0,0))
+    ALLOCATE(XLBYSVM(0,0,0,0))
+  END IF
+END IF      ! END OF THE IF STRUCTURE ON THE MODEL DIMENSION
+!
+!
+IF ( KMI > 1 ) THEN 
+  ! it has been assumed that the THeta field used the largest rim area compared
+  ! to the others prognostic variables, if it is not the case, you must change
+  ! these lines
+  ALLOCATE(XCOEFLIN_LBXM(SIZE(XLBXTHM,1),SIZE(XLBXTHM,2),SIZE(XLBXTHM,3)))
+  ALLOCATE(   NKLIN_LBXM(SIZE(XLBXTHM,1),SIZE(XLBXTHM,2),SIZE(XLBXTHM,3)))
+  ALLOCATE(XCOEFLIN_LBYM(SIZE(XLBYTHM,1),SIZE(XLBYTHM,2),SIZE(XLBYTHM,3)))
+  ALLOCATE(   NKLIN_LBYM(SIZE(XLBYTHM,1),SIZE(XLBYTHM,2),SIZE(XLBYTHM,3)))
+  ALLOCATE(XCOEFLIN_LBXU(SIZE(XLBXUM,1),SIZE(XLBXUM,2),SIZE(XLBXUM,3)))
+  ALLOCATE(   NKLIN_LBXU(SIZE(XLBXUM,1),SIZE(XLBXUM,2),SIZE(XLBXUM,3)))
+  ALLOCATE(XCOEFLIN_LBYU(SIZE(XLBYUM,1),SIZE(XLBYUM,2),SIZE(XLBYUM,3)))
+  ALLOCATE(   NKLIN_LBYU(SIZE(XLBYUM,1),SIZE(XLBYUM,2),SIZE(XLBYUM,3)))
+  ALLOCATE(XCOEFLIN_LBXV(SIZE(XLBXVM,1),SIZE(XLBXVM,2),SIZE(XLBXVM,3)))
+  ALLOCATE(   NKLIN_LBXV(SIZE(XLBXVM,1),SIZE(XLBXVM,2),SIZE(XLBXVM,3)))
+  ALLOCATE(XCOEFLIN_LBYV(SIZE(XLBYVM,1),SIZE(XLBYVM,2),SIZE(XLBYVM,3)))
+  ALLOCATE(   NKLIN_LBYV(SIZE(XLBYVM,1),SIZE(XLBYVM,2),SIZE(XLBYVM,3)))
+  ALLOCATE(XCOEFLIN_LBXW(SIZE(XLBXWM,1),SIZE(XLBXWM,2),SIZE(XLBXWM,3)))
+  ALLOCATE(   NKLIN_LBXW(SIZE(XLBXWM,1),SIZE(XLBXWM,2),SIZE(XLBXWM,3)))
+  ALLOCATE(XCOEFLIN_LBYW(SIZE(XLBYWM,1),SIZE(XLBYWM,2),SIZE(XLBYWM,3)))
+  ALLOCATE(   NKLIN_LBYW(SIZE(XLBYWM,1),SIZE(XLBYWM,2),SIZE(XLBYWM,3)))
+END IF
+!
+!  allocation of the LS fields for vertical relaxation and numerical diffusion
+IF( .NOT. LSTEADYLS )  THEN
+!
+  ALLOCATE(XLSUS(SIZE(XLSUM,1),SIZE(XLSUM,2),SIZE(XLSUM,3)))
+  ALLOCATE(XLSVS(SIZE(XLSVM,1),SIZE(XLSVM,2),SIZE(XLSVM,3)))
+  ALLOCATE(XLSWS(SIZE(XLSWM,1),SIZE(XLSWM,2),SIZE(XLSWM,3)))
+  ALLOCATE(XLSTHS(SIZE(XLSTHM,1),SIZE(XLSTHM,2),SIZE(XLSTHM,3)))
+  ALLOCATE(XLSRVS(SIZE(XLSRVM,1),SIZE(XLSRVM,2),SIZE(XLSRVM,3)))
+!
+ELSE
+!
+  ALLOCATE(XLSUS(0,0,0))
+  ALLOCATE(XLSVS(0,0,0))
+  ALLOCATE(XLSWS(0,0,0))
+  ALLOCATE(XLSTHS(0,0,0))
+  ALLOCATE(XLSRVS(0,0,0))
+!
+END IF
+!  allocation of the LB fields for horizontal relaxation and Lateral Boundaries
+IF( .NOT. ( LSTEADYLS .AND. KMI==1 ) )  THEN
+!
+  ALLOCATE(XLBXTKES(SIZE(XLBXTKEM,1),SIZE(XLBXTKEM,2),SIZE(XLBXTKEM,3)))
+  ALLOCATE(XLBYTKES(SIZE(XLBYTKEM,1),SIZE(XLBYTKEM,2),SIZE(XLBYTKEM,3)))
+  ALLOCATE(XLBXUS(SIZE(XLBXUM,1),SIZE(XLBXUM,2),SIZE(XLBXUM,3)))
+  ALLOCATE(XLBYUS(SIZE(XLBYUM,1),SIZE(XLBYUM,2),SIZE(XLBYUM,3)))
+  ALLOCATE(XLBXVS(SIZE(XLBXVM,1),SIZE(XLBXVM,2),SIZE(XLBXVM,3)))
+  ALLOCATE(XLBYVS(SIZE(XLBYVM,1),SIZE(XLBYVM,2),SIZE(XLBYVM,3)))
+  ALLOCATE(XLBXWS(SIZE(XLBXWM,1),SIZE(XLBXWM,2),SIZE(XLBXWM,3)))
+  ALLOCATE(XLBYWS(SIZE(XLBYWM,1),SIZE(XLBYWM,2),SIZE(XLBYWM,3)))
+  ALLOCATE(XLBXTHS(SIZE(XLBXTHM,1),SIZE(XLBXTHM,2),SIZE(XLBXTHM,3)))
+  ALLOCATE(XLBYTHS(SIZE(XLBYTHM,1),SIZE(XLBYTHM,2),SIZE(XLBYTHM,3)))
+  ALLOCATE(XLBXRS(SIZE(XLBXRM,1),SIZE(XLBXRM,2),SIZE(XLBXRM,3),SIZE(XLBXRM,4)))
+  ALLOCATE(XLBYRS(SIZE(XLBYRM,1),SIZE(XLBYRM,2),SIZE(XLBYRM,3),SIZE(XLBYRM,4)))
+  ALLOCATE(XLBXSVS(SIZE(XLBXSVM,1),SIZE(XLBXSVM,2),SIZE(XLBXSVM,3),SIZE(XLBXSVM,4)))
+  ALLOCATE(XLBYSVS(SIZE(XLBYSVM,1),SIZE(XLBYSVM,2),SIZE(XLBYSVM,3),SIZE(XLBYSVM,4)))
+!
+ELSE
+!
+  ALLOCATE(XLBXTKES(0,0,0))
+  ALLOCATE(XLBYTKES(0,0,0))
+  ALLOCATE(XLBXUS(0,0,0))
+  ALLOCATE(XLBYUS(0,0,0))
+  ALLOCATE(XLBXVS(0,0,0))
+  ALLOCATE(XLBYVS(0,0,0))
+  ALLOCATE(XLBXWS(0,0,0))
+  ALLOCATE(XLBYWS(0,0,0))
+  ALLOCATE(XLBXTHS(0,0,0))
+  ALLOCATE(XLBYTHS(0,0,0))
+  ALLOCATE(XLBXRS(0,0,0,0))
+  ALLOCATE(XLBYRS(0,0,0,0))
+  ALLOCATE(XLBXSVS(0,0,0,0))
+  ALLOCATE(XLBYSVS(0,0,0,0))
+!
+END IF
+!
+!*       3.9   Local variables
+!
+ALLOCATE(ZJ(IIU,IJU,IKU))
+!
+!-------------------------------------------------------------------------------
+!
+!
+!*       5.    INITIALIZE INTERPOLATION COEFFICIENTS
+!
+CALL INI_BIKHARDT_n (NDXRATIO_ALL(KMI),NDYRATIO_ALL(KMI),KMI)
+!
+!-------------------------------------------------------------------------------
+!
+!*       6.    INITIALIZE GRIDS AND METRIC COEFFICIENTS
+!              ----------------------------------------
+!
+CALL SET_GRID(KMI,TPINIFILE,IKU,NIMAX_ll,NJMAX_ll,                       &
+              XTSTEP,XSEGLEN,                                            &
+              XLONORI,XLATORI,XLON,XLAT,                                 &
+              XXHAT,XYHAT,XDXHAT,XDYHAT, XMAP,                           &
+              XZS,XZZ,XZHAT,XZTOP,LSLEVE,XLEN1,XLEN2,XZSMT,              &
+              ZJ,                                                        &
+              TDTMOD,TDTCUR,NSTOP,NBAK_NUMB,NOUT_NUMB,TBACKUPN,TOUTPUTN)
+!
+CALL METRICS(XMAP,XDXHAT,XDYHAT,XZZ,XDXX,XDYY,XDZX,XDZY,XDZZ)
+!
+!* update halos of metric coefficients
+!
+!
+CALL UPDATE_METRICS(CLBCX,CLBCY,XDXX,XDYY,XDZX,XDZY,XDZZ)
+!
+!
+! grid nesting initializations
+IF ( KMI == 1 ) THEN
+  XTSTEP_MODEL1=XTSTEP
+END IF
+!
+NDT_2_WAY(KMI)=4
+!
+!-------------------------------------------------------------------------------
+!
+!*       8.    INITIALIZE THE PROGNOSTIC FIELDS
+!              --------------------------------
+!
+
+IF (LSPECTRE_U) THEN
+  ALLOCATE(XUT(IIU,IJU,IKU))      ; XUT  = 0.0
+  CALL IO_Field_read(TPINIFILE,'UT',XUT)
+END IF
+!
+IF (LSPECTRE_V) THEN
+  ALLOCATE(XVT(IIU,IJU,IKU))      ; XVT  = 0.0
+  CALL IO_Field_read(TPINIFILE,'VT',XVT)
+END IF
+!
+IF (LSPECTRE_W) THEN  
+  ALLOCATE(XWT(IIU,IJU,IKU))      ; XWT  = 0.0
+  CALL IO_Field_read(TPINIFILE,'WT',XWT)
+END IF
+!
+IF (LSPECTRE_TH) THEN
+  ALLOCATE(XTHT(IIU,IJU,IKU))     ; XTHT = 0.0
+  CALL IO_Field_read(TPINIFILE,'THT',XTHT)
+END IF
+!
+IF (LSPECTRE_RV) THEN
+  ALLOCATE(XRT(IIU,IJU,IKU,NRR))
+  CALL IO_Field_read(TPINIFILE,'RVT',XRT(:,:,:,1))
+END IF
+!
+!-------------------------------------------------------------------------------
+!
+!
+!*        9.   INITIALIZE REFERENCE STATE
+!              ---------------------------
+!
+!
+CALL SET_REF(KMI,TPINIFILE,                        &
+             XZZ,XZHAT,ZJ,XDXX,XDYY,CLBCX,CLBCY,   &
+             XREFMASS,XMASS_O_PHI0,XLINMASS,       &
+             XRHODREF,XTHVREF,XRVREF,XEXNREF,XRHODJ)
+!-------------------------------------------------------------------------------
+!
+!*       11.    INITIALIZE THE SOURCE OF TOTAL DRY MASS Md
+!               ------------------------------------------
+!
+IF((KMI==1).AND.LSTEADYLS) THEN
+  XDRYMASSS = 0.
+END IF
+!
+!
+!-------------------------------------------------------------------------------
+!
+!*       14.   INITIALIZE THE LARGE SCALE SOURCES
+!              ----------------------------------
+!
+IF ((KMI==1).AND.(.NOT. LSTEADYLS)) THEN
+  IF (LSPECTRE_LSU.OR.LSPECTRE_LSV.OR.LSPECTRE_LSW.OR. &
+      LSPECTRE_LSRV.OR.LSPECTRE_LSTH) THEN 
+    CALL INI_CPL(NSTOP,XTSTEP,LSTEADYLS,CCONF,                                &
+               CGETTKET,                                                      &
+               CGETRVT,CGETRCT,CGETRRT,CGETRIT,                               &
+               CGETRST,CGETRGT,CGETRHT,CGETSVT,LCH_INIT_FIELD,                &
+               NSV,NIMAX_ll,NJMAX_ll,                                         &
+               NSIZELBX_ll,NSIZELBXU_ll,NSIZELBY_ll,NSIZELBYV_ll,             &
+               NSIZELBXTKE_ll,NSIZELBYTKE_ll,                                 &
+               NSIZELBXR_ll,NSIZELBYR_ll,NSIZELBXSV_ll,NSIZELBYSV_ll,         &
+               XLSUM,XLSVM,XLSWM,XLSTHM,XLSRVM,XLSZWSM,XDRYMASST,             &
+               XLBXUM,XLBXVM,XLBXWM,XLBXTHM,XLBXTKEM,XLBXRM,XLBXSVM,          &
+               XLBYUM,XLBYVM,XLBYWM,XLBYTHM,XLBYTKEM,XLBYRM,XLBYSVM,          &
+               XLSUS,XLSVS,XLSWS,XLSTHS,XLSRVS,XLSZWSS,XDRYMASSS,             &
+               XLBXUS,XLBXVS,XLBXWS,XLBXTHS,XLBXTKES,XLBXRS,XLBXSVS,          &
+               XLBYUS,XLBYVS,XLBYWS,XLBYTHS,XLBYTKES,XLBYRS,XLBYSVS           )
+  END IF
+END IF
+!
+IF ( KMI > 1) THEN
+  ! Use dummy pointers to correct an ifort BUG
+  DPTR_XBMX1=>XBMX1
+  DPTR_XBMX2=>XBMX2
+  DPTR_XBMX3=>XBMX3
+  DPTR_XBMX4=>XBMX4
+  DPTR_XBMY1=>XBMY1
+  DPTR_XBMY2=>XBMY2
+  DPTR_XBMY3=>XBMY3
+  DPTR_XBMY4=>XBMY4
+  DPTR_XBFX1=>XBFX1
+  DPTR_XBFX2=>XBFX2
+  DPTR_XBFX3=>XBFX3
+  DPTR_XBFX4=>XBFX4
+  DPTR_XBFY1=>XBFY1
+  DPTR_XBFY2=>XBFY2
+  DPTR_XBFY3=>XBFY3
+  DPTR_XBFY4=>XBFY4
+  DPTR_CLBCX=>CLBCX
+  DPTR_CLBCY=>CLBCY
+  !
+  DPTR_XZZ=>XZZ
+  DPTR_XZHAT=>XZHAT
+  DPTR_XLSUM=>XLSUM
+  DPTR_XLSVM=>XLSVM
+  DPTR_XLSWM=>XLSWM
+  DPTR_XLSTHM=>XLSTHM
+  DPTR_XLSRVM=>XLSRVM
+  DPTR_XLSZWSM=>XLSZWSM
+  DPTR_XLSUS=>XLSUS
+  DPTR_XLSVS=>XLSVS
+  DPTR_XLSWS=>XLSWS
+  DPTR_XLSTHS=>XLSTHS
+  DPTR_XLSRVS=>XLSRVS
+  DPTR_XLSZWSS=>XLSZWSS
+  !
+  DPTR_NKLIN_LBXU=>NKLIN_LBXU
+  DPTR_XCOEFLIN_LBXU=>XCOEFLIN_LBXU
+  DPTR_NKLIN_LBYU=>NKLIN_LBYU
+  DPTR_XCOEFLIN_LBYU=>XCOEFLIN_LBYU
+  DPTR_NKLIN_LBXV=>NKLIN_LBXV
+  DPTR_XCOEFLIN_LBXV=>XCOEFLIN_LBXV
+  DPTR_NKLIN_LBYV=>NKLIN_LBYV
+  DPTR_XCOEFLIN_LBYV=>XCOEFLIN_LBYV
+  DPTR_NKLIN_LBXW=>NKLIN_LBXW
+  DPTR_XCOEFLIN_LBXW=>XCOEFLIN_LBXW
+  DPTR_NKLIN_LBYW=>NKLIN_LBYW
+  DPTR_XCOEFLIN_LBYW=>XCOEFLIN_LBYW
+  DPTR_NKLIN_LBXM=>NKLIN_LBXM
+  DPTR_XCOEFLIN_LBXM=>XCOEFLIN_LBXM
+  DPTR_NKLIN_LBYM=>NKLIN_LBYM
+  DPTR_XCOEFLIN_LBYM=>XCOEFLIN_LBYM
+  !
+  CALL INI_SPAWN_LS_n(NDAD(KMI),XTSTEP,KMI,                                 &
+       DPTR_XBMX1,DPTR_XBMX2,DPTR_XBMX3,DPTR_XBMX4,DPTR_XBMY1,DPTR_XBMY2,DPTR_XBMY3,DPTR_XBMY4,      &
+       DPTR_XBFX1,DPTR_XBFX2,DPTR_XBFX3,DPTR_XBFX4,DPTR_XBFY1,DPTR_XBFY2,DPTR_XBFY3,DPTR_XBFY4,      &
+       NDXRATIO_ALL(KMI),NDYRATIO_ALL(KMI),                  &
+       DPTR_CLBCX,DPTR_CLBCY,DPTR_XZZ,DPTR_XZHAT,                                &
+       LSLEVE,XLEN1,XLEN2,                                   &
+       DPTR_XLSUM,DPTR_XLSVM,DPTR_XLSWM,DPTR_XLSTHM,DPTR_XLSRVM,DPTR_XLSZWSM,         &
+       DPTR_XLSUS,DPTR_XLSVS,DPTR_XLSWS,DPTR_XLSTHS,DPTR_XLSRVS,DPTR_XLSZWSS,         &
+       DPTR_NKLIN_LBXU,DPTR_XCOEFLIN_LBXU,DPTR_NKLIN_LBYU,DPTR_XCOEFLIN_LBYU,    &
+       DPTR_NKLIN_LBXV,DPTR_XCOEFLIN_LBXV,DPTR_NKLIN_LBYV,DPTR_XCOEFLIN_LBYV,    &
+       DPTR_NKLIN_LBXW,DPTR_XCOEFLIN_LBXW,DPTR_NKLIN_LBYW,DPTR_XCOEFLIN_LBYW,    &
+       DPTR_NKLIN_LBXM,DPTR_XCOEFLIN_LBXM,DPTR_NKLIN_LBYM,DPTR_XCOEFLIN_LBYM     )
+  !
+  DPTR_XLBXUM=>XLBXUM
+  DPTR_XLBYUM=>XLBYUM
+  DPTR_XLBXVM=>XLBXVM
+  DPTR_XLBYVM=>XLBYVM
+  DPTR_XLBXWM=>XLBXWM
+  DPTR_XLBYWM=>XLBYWM
+  DPTR_XLBXTHM=>XLBXTHM
+  DPTR_XLBYTHM=>XLBYTHM
+  DPTR_XLBXTKEM=>XLBXTKEM
+  DPTR_XLBYTKEM=>XLBYTKEM
+  DPTR_XLBXRM=>XLBXRM
+  DPTR_XLBYRM=>XLBYRM
+  DPTR_XLBXSVM=>XLBXSVM
+  DPTR_XLBYSVM=>XLBYSVM
+  CALL INI_ONE_WAY_n(NDAD(KMI),KMI,                                                             &
+       DPTR_XBMX1,DPTR_XBMX2,DPTR_XBMX3,DPTR_XBMX4,DPTR_XBMY1,DPTR_XBMY2,DPTR_XBMY3,DPTR_XBMY4, &
+       DPTR_XBFX1,DPTR_XBFX2,DPTR_XBFX3,DPTR_XBFX4,DPTR_XBFY1,DPTR_XBFY2,DPTR_XBFY3,DPTR_XBFY4, &
+       NDXRATIO_ALL(KMI),NDYRATIO_ALL(KMI),                                                     &
+       DPTR_CLBCX,DPTR_CLBCY,NRIMX,NRIMY,                                                       &
+       DPTR_NKLIN_LBXU,DPTR_XCOEFLIN_LBXU,DPTR_NKLIN_LBYU,DPTR_XCOEFLIN_LBYU,                   &
+       DPTR_NKLIN_LBXV,DPTR_XCOEFLIN_LBXV,DPTR_NKLIN_LBYV,DPTR_XCOEFLIN_LBYV,                   &
+       DPTR_NKLIN_LBXW,DPTR_XCOEFLIN_LBXW,DPTR_NKLIN_LBYW,DPTR_XCOEFLIN_LBYW,                   &
+       DPTR_NKLIN_LBXM,DPTR_XCOEFLIN_LBXM,DPTR_NKLIN_LBYM,DPTR_XCOEFLIN_LBYM,                   &
+       CCLOUD, LUSECHAQ, LUSECHIC,                                                              &
+       DPTR_XLBXUM,DPTR_XLBYUM,DPTR_XLBXVM,DPTR_XLBYVM,DPTR_XLBXWM,DPTR_XLBYWM,                 &
+       DPTR_XLBXTHM,DPTR_XLBYTHM,                                                               &
+       DPTR_XLBXTKEM,DPTR_XLBYTKEM,                                                             &
+       DPTR_XLBXRM,DPTR_XLBYRM,DPTR_XLBXSVM,DPTR_XLBYSVM                                        )
+END IF
+!
+!
+!*       16.    BUILT THE GENERIC OUTPUT NAME
+!               ----------------------------
+!
+WRITE(COUTFILE,'(A,".",I1,".",A)') CEXP,KMI,TRIM(ADJUSTL(CSEG))
+
+!-------------------------------------------------------------------------------
+!
+!*       17.    INITIALIZE THE PARAMETERS FOR THE DYNAMICS
+!               ------------------------------------------
+!
+!Allocate to zero size to not pass unallocated pointers
+ALLOCATE(XALKBAS(0))
+ALLOCATE(XALKWBAS(0))
+!
+CALL INI_DYNAMICS(XLON,XLAT,XRHODJ,XTHVREF,XMAP,XZZ,XDXHAT,XDYHAT,            &
+             XZHAT,CLBCX,CLBCY,XTSTEP,CPRESOPT,                               &
+             LVE_RELAX,LVE_RELAX_GRD,LHORELAX_UVWTH,LHORELAX_RV,              &
+             LHORELAX_RC,LHORELAX_RR,LHORELAX_RI,LHORELAX_RS,LHORELAX_RG,     &
+             LHORELAX_RH,LHORELAX_TKE,LHORELAX_SV,                            &
+             LHORELAX_SVC2R2,LHORELAX_SVC1R3,LHORELAX_SVELEC,LHORELAX_SVLG,   &
+             LHORELAX_SVCHEM,LHORELAX_SVAER,LHORELAX_SVDST,LHORELAX_SVSLT,    &
+             LHORELAX_SVPP,LHORELAX_SVCS,LHORELAX_SVCHIC,LHORELAX_SVSNW,      &
+#ifdef MNH_FOREFIRE
+             LHORELAX_SVFF,                                                   &
+#endif
+             XRIMKMAX,NRIMX,NRIMY,                                            &
+             XALKTOP,XALKGRD,XALZBOT,XALZBAS,                                 &
+             XT4DIFU,XT4DIFTH,XT4DIFSV,                                       &
+             XCORIOX,XCORIOY,XCORIOZ,XCURVX,XCURVY,                           &
+             XDXHATM,XDYHATM,XRHOM,XAF,XBFY,XCF,XTRIGSX,XTRIGSY,NIFAXX,NIFAXY,&
+             XALK,XALKW,NALBOT,XALKBAS,XALKWBAS,NALBAS,                       &
+             LMASK_RELAX,XKURELAX,XKVRELAX,XKWRELAX,                          &
+             XDK2U,XDK4U,XDK2TH,XDK4TH,XDK2SV,XDK4SV,                         &
+             LZDIFFU,XZDIFFU_HALO2,                                           &
+             XBFB,XBF_SXP2_YP1_Z,                                             &
+             XAF_ZS,XBF_ZS,XCF_ZS,                                            &
+             XDXATH_ZS,XDYATH_ZS,XRHO_ZS,                                     &
+             XA_K,XB_K,XC_K,XD_K) 
+!
+!-------------------------------------------------------------------------------
+!
+!*      22.    UPDATE HALO
+!              -----------
+!
+!
+CALL UPDATE_HALO_ll(TZINITHALO3D_ll,IINFO_ll)
+CALL UPDATE_HALO_ll(TZINITHALO2D_ll,IINFO_ll)
+CALL CLEANLIST_ll(TZINITHALO3D_ll)
+CALL CLEANLIST_ll(TZINITHALO2D_ll)
+!
+!
+!-------------------------------------------------------------------------------
+!
+!*      23.    DEALLOCATION
+!              -------------
+!
+DEALLOCATE(ZJ)
+!
+
+END SUBROUTINE INI_SPECTRE_n
diff --git a/src/ZSOLVER/modd_dynn.f90 b/src/ZSOLVER/modd_dynn.f90
new file mode 100644
index 0000000000000000000000000000000000000000..445105291501c6f96285c0eb1654124d801036a5
--- /dev/null
+++ b/src/ZSOLVER/modd_dynn.f90
@@ -0,0 +1,402 @@
+!MNH_LIC Copyright 1994-2018 CNRS, Meteo-France and Universite Paul Sabatier
+!MNH_LIC This is part of the Meso-NH software governed by the CeCILL-C licence
+!MNH_LIC version 1. See LICENSE, CeCILL-C_V1-en.txt and CeCILL-C_V1-fr.txt  
+!MNH_LIC for details. version 1.
+!-----------------------------------------------------------------
+!     #################
+      MODULE MODD_DYN_n
+!     #################
+!
+!!****  *MODD_DYN$n* - declaration of dynamic control variables 
+!!
+!!    PURPOSE
+!!    -------
+!       The purpose of this declarative module is to declare the dynamic
+!     control variables.    
+!
+!!
+!!**  IMPLICIT ARGUMENTS
+!!    ------------------
+!!      None 
+!!
+!!    REFERENCE
+!!    ---------
+!!      Book2 of documentation of Meso-NH (module MODD_DYNn)
+!!      Technical Specifications Report of the Meso-NH (chapters 2 and 3)
+!!          
+!!    AUTHOR
+!!    ------
+!!	V. Ducrocq   *Meteo France*
+!!
+!!    MODIFICATIONS
+!!    -------------
+!!      Original    18/05/94                      
+!!      Modifications 16/11/94   (Lafore+Pinty)  For NUM_DIFF
+!!      Modifications 06/01/95   (Lafore)        For LSTEADY_DMASS
+!!      Modifications 28/07/96   (Masson)        Supress LSTEADY_DMASS
+!!      Modifications 15/03/98   (Stein)         Add LHO_RELAX for each variables 
+!!      Modifications 22/01/01   (Gazen)         Add LHORELAX_SVC2R2, _SVCHEM, _SVLG
+!!      Modifications 29/11/02   (Pinty)         Add  LHORELAX_SVC1R3, _SVELEC
+!!      Modifications    07/05   (P.Tulet)       Add  relaxation for dust and aerosol
+!!      Modifications    05/07   (C.Lac)         Separation of num diffusion
+!!      Modifications    07/10   (M.Leriche)     Add relaxation for ice phase chemical
+!!      Modification    01/2016  (JP Pinty) Add LIMA
+!!  Philippe Wautelet: 05/2016-04/2018: new data structures and calls for I/O
+!!      Modification    07/2017  (V. Vionnet)    Add blowing snow variable
+!-------------------------------------------------------------------------------
+!
+!*       0.   DECLARATIONS
+!             ------------
+!
+USE MODD_PARAMETERS, ONLY: JPMODELMAX, JPSVMAX
+IMPLICIT NONE
+
+TYPE DYN_t
+!
+  INTEGER :: NSTOP          ! Number of time step
+  REAL    :: XTSTEP         ! Time step
+!
+!++++++++++++++++++++++++++++++++++
+!PART USED BY THE PRESSURE SOLVER
+!++++++++++++++++++++++++++++++++++
+!
+  REAL, DIMENSION(:,:,:), POINTER :: XBFY=>NULL()     ! Vectors giving the non
+  REAL, DIMENSION(:,:,:), POINTER :: XBFB=>NULL()     ! Vectors giving the non
+  REAL, DIMENSION(:,:,:), POINTER :: XBF_SXP2_YP1_Z=>NULL()     ! Vectors giving the non
+  REAL, DIMENSION(:,:,:), POINTER :: XBF=>NULL()      ! vanishing elements of the 
+  REAL, DIMENSION(:),     POINTER :: XAF=>NULL(),XCF=>NULL() ! tri-diag matrix in the pressure equation
+  REAL, DIMENSION(:,:,:), POINTER :: XAF_ZS=>NULL(),XBF_ZS=>NULL(),XCF_ZS=>NULL() ! coef for Zsolver   
+  REAL, DIMENSION(:,:)  , POINTER :: XDXATH_ZS=>NULL(),XDYATH_ZS=>NULL()
+  REAL, DIMENSION(:,:,:), POINTER :: XRHO_ZS=>NULL()
+  REAL, DIMENSION(:),     POINTER :: XA_K=>NULL(),XB_K=>NULL(),XC_K=>NULL(),XD_K=>NULL()
+!
+                                                   ! Arrays of sinus or cosinus
+                                                   ! values for the FFT 
+  REAL, DIMENSION(:),   POINTER :: XTRIGSX=>NULL()  ! in x-direction   
+  REAL, DIMENSION(:),   POINTER :: XTRIGSY=>NULL()  ! in y-direction   
+  INTEGER, DIMENSION(:),POINTER :: NIFAXX =>NULL()  ! Decomposition in prime numbers 
+  INTEGER, DIMENSION(:),POINTER :: NIFAXY =>NULL()  ! for the FFT in x and y directions 
+  CHARACTER(LEN=5)       :: CPRESOPT     ! Choice of the pressure solver
+  INTEGER                :: NITR         ! Number of iterations for the 
+                                            ! pressure solver
+  LOGICAL                :: LITRADJ      ! Choice to adjust the number of 
+                                            !solver iterations during
+                                            !the simulation
+  LOGICAL                :: LRES         ! Choice of a different residual
+                                         ! divergence limit
+  REAL                   :: XRES         ! Value of residual divergence limit
+  REAL                   :: XRELAX       ! relaxation coefficient for the
+                                         ! Richardson's method
+!
+  REAL :: XDXHATM                        ! mean grid increment in the 
+  REAL :: XDYHATM                        ! x and  y directions
+
+  REAL, DIMENSION (:), POINTER  :: XRHOM=>NULL()  !  mean of XRHODJ on the plane x y 
+                                                 !  localized at a mass level
+!
+!++++++++++++++++++++++++++++++++++
+!PART USED BY THE ABSORBING LAYERS 
+!++++++++++++++++++++++++++++++++++
+!
+  INTEGER      :: NALBOT     ! Vertical index corresponding to the     
+                                ! absorbing layer base
+!  
+  INTEGER      :: NALBAS     ! Vertical index corresponding to the     
+                                ! absorbing layer base
+!                                
+  REAL, DIMENSION(:),   POINTER :: XALK=>NULL()  ! Function of the absorbing
+                                ! layer damping coefficient defined for
+                                !   u,v,and theta
+  REAL, DIMENSION(:),   POINTER :: XALKW=>NULL() ! Idem but defined for w 
+!
+  REAL, DIMENSION(:),   POINTER :: XALKBAS=>NULL()  ! Function of the absorbing
+                                ! layer damping coefficient defined for
+                                !   u,v,and theta
+  REAL, DIMENSION(:),   POINTER :: XALKWBAS=>NULL() ! Idem but defined for w 
+!
+  LOGICAL ::  LVE_RELAX ! switch to activate the VErtical RELAXation
+  LOGICAL ::  LVE_RELAX_GRD ! switch to activate the VErtical RELAXation
+!
+!                            switch to activate the HOrizontal RELAXation
+!  LOGICAL :: LHORELAX_UVWTH
+!
+  LOGICAL :: LHORELAX_RV, LHORELAX_RC, LHORELAX_RR, LHORELAX_RI
+  LOGICAL :: LHORELAX_RS, LHORELAX_RG, LHORELAX_RH
+!
+!  LOGICAL :: LHORELAX_TKE
+!
+  LOGICAL :: LHORELAX_SVC2R2
+  LOGICAL :: LHORELAX_SVC1R3
+  LOGICAL :: LHORELAX_SVLIMA
+  LOGICAL :: LHORELAX_SVELEC
+  LOGICAL :: LHORELAX_SVCHEM
+  LOGICAL :: LHORELAX_SVCHIC
+  LOGICAL :: LHORELAX_SVLG
+  LOGICAL :: LHORELAX_SVDST
+  LOGICAL :: LHORELAX_SVSLT
+  LOGICAL :: LHORELAX_SVAER
+  LOGICAL :: LHORELAX_SVPP 
+#ifdef MNH_FOREFIRE
+  LOGICAL :: LHORELAX_SVFF
+#endif
+  LOGICAL :: LHORELAX_SVCS 
+  LOGICAL :: LHORELAX_SVSNW  
+  LOGICAL, DIMENSION(:),POINTER :: LHORELAX_SV =>NULL()
+!
+  REAL    :: XRIMKMAX   ! Max. value of the horiz. relaxation coeff.
+!  INTEGER :: NRIMX,NRIMY! Number of points in the lateral absorbing
+                           ! layer in the x and y directions 
+! sizes of the West-east total LB area
+  INTEGER :: NSIZELBX_ll,NSIZELBXU_ll      ! for T,V,W and u 
+  INTEGER :: NSIZELBXTKE_ll                ! for TKE       
+  INTEGER :: NSIZELBXR_ll,NSIZELBXSV_ll    ! for Rx and SV    
+! sizes of the North-south total LB area
+  INTEGER :: NSIZELBY_ll,NSIZELBYV_ll      ! for T,U,W  and v
+  INTEGER :: NSIZELBYTKE_ll                ! for TKE       
+  INTEGER :: NSIZELBYR_ll,NSIZELBYSV_ll    ! for Rx and SV    
+  LOGICAL, DIMENSION(:,:),  POINTER   :: LMASK_RELAX=>NULL()  ! Mask for lateral
+                           ! relaxation: True where it has to be performed
+  REAL, DIMENSION(:,:),     POINTER   :: XKURELAX=>NULL() ! Horizontal relaxation
+  REAL, DIMENSION(:,:),     POINTER   :: XKVRELAX=>NULL() ! coefficients for the
+  REAL, DIMENSION(:,:),     POINTER   :: XKWRELAX=>NULL() ! u, v and mass locations
+!
+!++++++++++++++++++++++++++++++++++++
+!PART USED BY THE NUMERICAL DIFFUSION
+!++++++++++++++++++++++++++++++++++++
+!
+  REAL              :: XT4DIFU ! Damping time scale for 2*dx wavelength
+                               ! specified for the 4nd order num. diffusion
+                               ! for momentum
+  REAL              :: XT4DIFTH! for theta and mixing ratios                  
+  REAL              :: XT4DIFSV! for scalar variables                         
+  REAL              :: XDK2U   ! 2nd order num. diffusion coef. /dx2
+                               ! for momentum
+  REAL              :: XDK4U   ! 4nd order num. diffusion coef. /dx4
+                               ! for momentum
+  REAL              :: XDK2TH  ! for theta and mixing ratios                                        
+  REAL              :: XDK4TH  ! for theta and mixing ratios           
+  REAL              :: XDK2SV  ! for scalar variables                                                               
+  REAL              :: XDK4SV  ! for scalar variables                  
+!
+END TYPE DYN_t
+
+TYPE(DYN_t), DIMENSION(JPMODELMAX), TARGET, SAVE :: DYN_MODEL
+LOGICAL    , DIMENSION(JPMODELMAX),         SAVE :: DYN_FIRST_CALL = .TRUE.
+
+INTEGER, POINTER :: NSTOP=>NULL()
+REAL, POINTER :: XTSTEP=>NULL()
+REAL, DIMENSION(:,:,:), POINTER :: XBFY=>NULL()
+REAL, DIMENSION(:,:,:), POINTER :: XBFB=>NULL()
+REAL, DIMENSION(:,:,:), POINTER :: XBF_SXP2_YP1_Z=>NULL()
+REAL, DIMENSION(:,:,:), POINTER :: XBF=>NULL()
+REAL, DIMENSION(:),     POINTER :: XAF=>NULL(),XCF=>NULL()
+REAL, DIMENSION(:,:,:), POINTER :: XAF_ZS=>NULL(),XBF_ZS=>NULL(),XCF_ZS=>NULL()
+REAL, DIMENSION(:,:)  , POINTER :: XDXATH_ZS=>NULL(),XDYATH_ZS=>NULL()
+REAL, DIMENSION(:,:,:), POINTER :: XRHO_ZS=>NULL() 
+REAL, DIMENSION(:),     POINTER :: XA_K=>NULL(),XB_K=>NULL(),XC_K=>NULL(),XD_K=>NULL()
+REAL, DIMENSION(:),   POINTER :: XTRIGSX=>NULL()
+REAL, DIMENSION(:),   POINTER :: XTRIGSY=>NULL()
+INTEGER, DIMENSION(:), POINTER :: NIFAXX=>NULL()
+INTEGER, DIMENSION(:), POINTER :: NIFAXY=>NULL()
+CHARACTER(LEN=5), POINTER :: CPRESOPT=>NULL()
+INTEGER, POINTER :: NITR=>NULL()
+LOGICAL, POINTER :: LITRADJ=>NULL()
+LOGICAL, POINTER :: LRES=>NULL()
+REAL, POINTER :: XRES=>NULL()
+REAL, POINTER :: XRELAX=>NULL()
+REAL, POINTER :: XDXHATM=>NULL()
+REAL, POINTER :: XDYHATM=>NULL()
+REAL, DIMENSION (:), POINTER  :: XRHOM=>NULL()
+INTEGER, POINTER :: NALBOT=>NULL()
+REAL, DIMENSION(:),   POINTER :: XALK=>NULL()
+REAL, DIMENSION(:),   POINTER :: XALKW=>NULL()
+INTEGER, POINTER :: NALBAS=>NULL()
+REAL, DIMENSION(:),   POINTER :: XALKBAS=>NULL()
+REAL, DIMENSION(:),   POINTER :: XALKWBAS=>NULL()
+LOGICAL, POINTER :: LVE_RELAX=>NULL()
+LOGICAL, POINTER :: LVE_RELAX_GRD=>NULL()
+LOGICAL, POINTER :: LHORELAX_UVWTH=>NULL()
+LOGICAL, POINTER :: LHORELAX_RV=>NULL(), LHORELAX_RC=>NULL(), LHORELAX_RR=>NULL(), LHORELAX_RI=>NULL()
+LOGICAL, POINTER :: LHORELAX_RS=>NULL(), LHORELAX_RG=>NULL(), LHORELAX_RH=>NULL()
+LOGICAL, POINTER :: LHORELAX_TKE=>NULL()
+LOGICAL, POINTER :: LHORELAX_SVC2R2=>NULL()
+LOGICAL, POINTER :: LHORELAX_SVC1R3=>NULL()
+LOGICAL, POINTER :: LHORELAX_SVLIMA=>NULL()
+LOGICAL, POINTER :: LHORELAX_SVELEC=>NULL()
+LOGICAL, POINTER :: LHORELAX_SVCHEM=>NULL()
+LOGICAL, POINTER :: LHORELAX_SVCHIC=>NULL()
+LOGICAL, POINTER :: LHORELAX_SVLG=>NULL()
+LOGICAL, POINTER :: LHORELAX_SVDST=>NULL()
+LOGICAL, POINTER :: LHORELAX_SVSLT=>NULL()
+LOGICAL, POINTER :: LHORELAX_SVAER=>NULL()
+LOGICAL, POINTER :: LHORELAX_SVPP=>NULL()
+#ifdef MNH_FOREFIRE
+LOGICAL, POINTER :: LHORELAX_SVFF=>NULL()
+#endif
+LOGICAL, POINTER :: LHORELAX_SVCS=>NULL()
+LOGICAL, POINTER :: LHORELAX_SVSNW=>NULL()
+LOGICAL, DIMENSION(:), POINTER :: LHORELAX_SV=>NULL()
+REAL, POINTER :: XRIMKMAX=>NULL()
+INTEGER, POINTER :: NRIMX=>NULL(),NRIMY=>NULL()
+INTEGER, POINTER :: NSIZELBX_ll=>NULL(),NSIZELBXU_ll=>NULL()
+INTEGER, POINTER :: NSIZELBXTKE_ll=>NULL()
+INTEGER, POINTER :: NSIZELBXR_ll=>NULL(),NSIZELBXSV_ll=>NULL()
+INTEGER, POINTER :: NSIZELBY_ll=>NULL(),NSIZELBYV_ll=>NULL()
+INTEGER, POINTER :: NSIZELBYTKE_ll=>NULL()
+INTEGER, POINTER :: NSIZELBYR_ll=>NULL(),NSIZELBYSV_ll=>NULL()
+LOGICAL, DIMENSION(:,:),  POINTER   :: LMASK_RELAX=>NULL()
+REAL, DIMENSION(:,:),     POINTER   :: XKURELAX=>NULL()
+REAL, DIMENSION(:,:),     POINTER   :: XKVRELAX=>NULL()
+REAL, DIMENSION(:,:),     POINTER   :: XKWRELAX=>NULL()
+REAL, POINTER :: XT4DIFU=>NULL()
+REAL, POINTER :: XDK2U=>NULL()
+REAL, POINTER :: XDK4U=>NULL()
+REAL, POINTER :: XT4DIFTH=>NULL()
+REAL, POINTER :: XDK2TH=>NULL()
+REAL, POINTER :: XDK4TH=>NULL()
+REAL, POINTER :: XT4DIFSV=>NULL()
+REAL, POINTER :: XDK2SV=>NULL()
+REAL, POINTER :: XDK4SV=>NULL()
+
+CONTAINS
+
+SUBROUTINE DYN_GOTO_MODEL(KFROM, KTO)
+INTEGER, INTENT(IN) :: KFROM, KTO
+!
+IF (DYN_FIRST_CALL(KTO)) THEN
+ALLOCATE (DYN_MODEL(KTO)%NIFAXX(19))
+ALLOCATE (DYN_MODEL(KTO)%NIFAXY(19))
+ALLOCATE (DYN_MODEL(KTO)%LHORELAX_SV(JPSVMAX))
+DYN_FIRST_CALL(KTO) = .FALSE.
+ENDIF
+! Save current state for allocated arrays
+DYN_MODEL(KFROM)%XBFY=>XBFY
+DYN_MODEL(KFROM)%XBFB=>XBFB
+DYN_MODEL(KFROM)%XBF_SXP2_YP1_Z=>XBF_SXP2_YP1_Z
+DYN_MODEL(KFROM)%XBF=>XBF
+DYN_MODEL(KFROM)%XAF=>XAF
+DYN_MODEL(KFROM)%XCF=>XCF
+
+DYN_MODEL(KFROM)%XAF_ZS=>XAF_ZS
+DYN_MODEL(KFROM)%XBF_ZS=>XBF_ZS
+DYN_MODEL(KFROM)%XCF_ZS=>XCF_ZS
+
+DYN_MODEL(KFROM)%XDXATH_ZS=>XDXATH_ZS
+DYN_MODEL(KFROM)%XDYATH_ZS=>XDYATH_ZS
+DYN_MODEL(KFROM)%XRHO_ZS=>XRHO_ZS
+DYN_MODEL(KFROM)%XA_K=>XA_K
+DYN_MODEL(KFROM)%XB_K=>XB_K
+DYN_MODEL(KFROM)%XC_K=>XC_K
+DYN_MODEL(KFROM)%XD_K=>XD_K
+
+DYN_MODEL(KFROM)%XTRIGSX=>XTRIGSX
+DYN_MODEL(KFROM)%XTRIGSY=>XTRIGSY
+DYN_MODEL(KFROM)%XRHOM=>XRHOM
+DYN_MODEL(KFROM)%XALK=>XALK
+DYN_MODEL(KFROM)%XALKW=>XALKW
+DYN_MODEL(KFROM)%XALKBAS=>XALKBAS
+DYN_MODEL(KFROM)%XALKWBAS=>XALKWBAS
+DYN_MODEL(KFROM)%LMASK_RELAX=>LMASK_RELAX
+DYN_MODEL(KFROM)%XKURELAX=>XKURELAX
+DYN_MODEL(KFROM)%XKVRELAX=>XKVRELAX
+DYN_MODEL(KFROM)%XKWRELAX=>XKWRELAX
+!
+! Current model is set to model KTO
+NSTOP=>DYN_MODEL(KTO)%NSTOP
+XTSTEP=>DYN_MODEL(KTO)%XTSTEP
+XBFY=>DYN_MODEL(KTO)%XBFY
+XBFB=>DYN_MODEL(KTO)%XBFB
+XBF_SXP2_YP1_Z=>DYN_MODEL(KTO)%XBF_SXP2_YP1_Z
+XBF=>DYN_MODEL(KTO)%XBF
+XAF=>DYN_MODEL(KTO)%XAF
+XCF=>DYN_MODEL(KTO)%XCF
+
+XAF_ZS=>DYN_MODEL(KTO)%XAF_ZS
+XBF_ZS=>DYN_MODEL(KTO)%XBF_ZS
+XCF_ZS=>DYN_MODEL(KTO)%XCF_ZS
+
+XDXATH_ZS=>DYN_MODEL(KFROM)%XDXATH_ZS
+XDYATH_ZS=>DYN_MODEL(KFROM)%XDYATH_ZS
+XRHO_ZS=>DYN_MODEL(KFROM)%XRHO_ZS
+XA_K=>DYN_MODEL(KFROM)%XA_K
+XB_K=>DYN_MODEL(KFROM)%XB_K
+XC_K=>DYN_MODEL(KFROM)%XC_K
+XD_K=>DYN_MODEL(KFROM)%XD_K
+
+XTRIGSX=>DYN_MODEL(KTO)%XTRIGSX
+XTRIGSY=>DYN_MODEL(KTO)%XTRIGSY
+NIFAXX=>DYN_MODEL(KTO)%NIFAXX
+NIFAXY=>DYN_MODEL(KTO)%NIFAXY
+CPRESOPT=>DYN_MODEL(KTO)%CPRESOPT
+NITR=>DYN_MODEL(KTO)%NITR
+LITRADJ=>DYN_MODEL(KTO)%LITRADJ
+LRES=>DYN_MODEL(KTO)%LRES          
+XRES=>DYN_MODEL(KTO)%XRES
+XRELAX=>DYN_MODEL(KTO)%XRELAX
+XDXHATM=>DYN_MODEL(KTO)%XDXHATM
+XDYHATM=>DYN_MODEL(KTO)%XDYHATM
+XRHOM=>DYN_MODEL(KTO)%XRHOM
+NALBOT=>DYN_MODEL(KTO)%NALBOT
+XALK=>DYN_MODEL(KTO)%XALK
+XALKW=>DYN_MODEL(KTO)%XALKW
+NALBAS=>DYN_MODEL(KTO)%NALBAS
+XALKBAS=>DYN_MODEL(KTO)%XALKBAS
+XALKWBAS=>DYN_MODEL(KTO)%XALKWBAS
+LVE_RELAX=>DYN_MODEL(KTO)%LVE_RELAX
+LVE_RELAX_GRD=>DYN_MODEL(KTO)%LVE_RELAX_GRD
+!LHORELAX_UVWTH=>DYN_MODEL(KTO)%LHORELAX_UVWTH !Done in FIELDLIST_GOTO_MODEL
+LHORELAX_RV=>DYN_MODEL(KTO)%LHORELAX_RV
+LHORELAX_RC=>DYN_MODEL(KTO)%LHORELAX_RC
+LHORELAX_RR=>DYN_MODEL(KTO)%LHORELAX_RR
+LHORELAX_RI=>DYN_MODEL(KTO)%LHORELAX_RI
+LHORELAX_RS=>DYN_MODEL(KTO)%LHORELAX_RS
+LHORELAX_RG=>DYN_MODEL(KTO)%LHORELAX_RG
+LHORELAX_RH=>DYN_MODEL(KTO)%LHORELAX_RH
+!LHORELAX_TKE=>DYN_MODEL(KTO)%LHORELAX_TKE !Done in FIELDLIST_GOTO_MODEL
+LHORELAX_SVC2R2=>DYN_MODEL(KTO)%LHORELAX_SVC2R2
+LHORELAX_SVC1R3=>DYN_MODEL(KTO)%LHORELAX_SVC1R3
+LHORELAX_SVLIMA=>DYN_MODEL(KTO)%LHORELAX_SVLIMA
+LHORELAX_SVELEC=>DYN_MODEL(KTO)%LHORELAX_SVELEC
+LHORELAX_SVCHEM=>DYN_MODEL(KTO)%LHORELAX_SVCHEM
+LHORELAX_SVCHIC=>DYN_MODEL(KTO)%LHORELAX_SVCHIC
+LHORELAX_SVLG=>DYN_MODEL(KTO)%LHORELAX_SVLG
+LHORELAX_SVDST=>DYN_MODEL(KTO)%LHORELAX_SVDST
+LHORELAX_SVSLT=>DYN_MODEL(KTO)%LHORELAX_SVSLT
+LHORELAX_SVAER=>DYN_MODEL(KTO)%LHORELAX_SVAER
+LHORELAX_SVPP=>DYN_MODEL(KTO)%LHORELAX_SVPP
+#ifdef MNH_FOREFIRE
+LHORELAX_SVFF=>DYN_MODEL(KTO)%LHORELAX_SVFF
+#endif
+LHORELAX_SVCS=>DYN_MODEL(KTO)%LHORELAX_SVCS
+LHORELAX_SVSNW=>DYN_MODEL(KTO)%LHORELAX_SVSNW
+LHORELAX_SV=>DYN_MODEL(KTO)%LHORELAX_SV
+XRIMKMAX=>DYN_MODEL(KTO)%XRIMKMAX
+!NRIMX=>DYN_MODEL(KTO)%NRIMX !Done in FIELDLIST_GOTO_MODEL
+!NRIMY=>DYN_MODEL(KTO)%NRIMY !Done in FIELDLIST_GOTO_MODEL
+NSIZELBX_ll=>DYN_MODEL(KTO)%NSIZELBX_ll
+NSIZELBXU_ll=>DYN_MODEL(KTO)%NSIZELBXU_ll
+NSIZELBXTKE_ll=>DYN_MODEL(KTO)%NSIZELBXTKE_ll
+NSIZELBXR_ll=>DYN_MODEL(KTO)%NSIZELBXR_ll
+NSIZELBXSV_ll=>DYN_MODEL(KTO)%NSIZELBXSV_ll
+NSIZELBY_ll=>DYN_MODEL(KTO)%NSIZELBY_ll
+NSIZELBYV_ll=>DYN_MODEL(KTO)%NSIZELBYV_ll
+NSIZELBYTKE_ll=>DYN_MODEL(KTO)%NSIZELBYTKE_ll
+NSIZELBYR_ll=>DYN_MODEL(KTO)%NSIZELBYR_ll
+NSIZELBYSV_ll=>DYN_MODEL(KTO)%NSIZELBYSV_ll
+LMASK_RELAX=>DYN_MODEL(KTO)%LMASK_RELAX
+XKURELAX=>DYN_MODEL(KTO)%XKURELAX
+XKVRELAX=>DYN_MODEL(KTO)%XKVRELAX
+XKWRELAX=>DYN_MODEL(KTO)%XKWRELAX
+XT4DIFU=>DYN_MODEL(KTO)%XT4DIFU
+XDK2U=>DYN_MODEL(KTO)%XDK2U
+XDK4U=>DYN_MODEL(KTO)%XDK4U
+XT4DIFTH=>DYN_MODEL(KTO)%XT4DIFTH
+XDK2TH=>DYN_MODEL(KTO)%XDK2TH
+XDK4TH=>DYN_MODEL(KTO)%XDK4TH
+XT4DIFSV=>DYN_MODEL(KTO)%XT4DIFSV
+XDK2SV=>DYN_MODEL(KTO)%XDK2SV
+XDK4SV=>DYN_MODEL(KTO)%XDK4SV
+
+END SUBROUTINE DYN_GOTO_MODEL
+
+END MODULE MODD_DYN_n
diff --git a/src/ZSOLVER/modeln.f90 b/src/ZSOLVER/modeln.f90
new file mode 100644
index 0000000000000000000000000000000000000000..a65e4e58abd7369dc942b9d7956f844df1cfa6dc
--- /dev/null
+++ b/src/ZSOLVER/modeln.f90
@@ -0,0 +1,2257 @@
+!MNH_LIC Copyright 1994-2020 CNRS, Meteo-France and Universite Paul Sabatier
+!MNH_LIC This is part of the Meso-NH software governed by the CeCILL-C licence
+!MNH_LIC version 1. See LICENSE, CeCILL-C_V1-en.txt and CeCILL-C_V1-fr.txt
+!MNH_LIC for details. version 1.
+!-----------------------------------------------------------------
+!     ###################
+      MODULE MODI_MODEL_n
+!     ###################
+!
+INTERFACE
+!
+       SUBROUTINE MODEL_n(KTCOUNT,OEXIT)
+!
+INTEGER, INTENT(IN)   :: KTCOUNT  ! temporal loop index of model KMODEL
+LOGICAL, INTENT(INOUT):: OEXIT    ! switch for the end of the temporal loop
+!
+END SUBROUTINE MODEL_n
+!
+END INTERFACE
+!
+END MODULE MODI_MODEL_n
+
+!     ################################### 
+      SUBROUTINE MODEL_n(KTCOUNT, OEXIT) 
+!     ###################################
+!
+!!****  *MODEL_n * -monitor of the model version _n 
+!!
+!!    PURPOSE
+!!    -------
+!       The purpose of this routine is to build up a typical model version
+!     by sequentially calling the specialized routines.
+!
+!!**  METHOD
+!!    ------
+!!      Some preliminary initializations are performed in the first section.
+!!    Then, specialized routines are called to update the guess of the future
+!!    instant XRxxS of the variable xx by adding the effects of all the
+!!    different sources of evolution.
+!!
+!!              (guess of xx at t+dt) * Rhod_ref * Jacobian
+!!      XRxxS = -------------------------------------------
+!!                           2 dt
+!!
+!!      At this level, the informations are transferred with a USE association
+!!    from the INIT step, where the modules have been previously filled. The
+!!    transfer to the subroutines computing each source term is performed by
+!!    argument in order to avoid repeated compilations of these subroutines.
+!!      This monitor model_n, must therefore be duplicated for each model,
+!!    model1 corresponds in this case to the outermost model, model2 is used
+!!    for the first level of gridnesting,....  
+!!      The effect of all parameterizations is computed in PHYS_PARAM_n, which
+!!    is itself a monitor. This is due to a possible large number of
+!!    parameterizations, which can be activated and therefore, will require a
+!!    very large list of arguments. To circumvent this problem, we transfer by
+!!    a USE association, the necessary informations in this monitor, which will
+!!    dispatch the pertinent information to every parametrization.
+!!      Some elaborated diagnostics, LES tools, budget storages are also called
+!!    at this level because they require informations about the fields at every
+!!    timestep.
+!!
+!!
+!!    EXTERNAL
+!!    --------
+!!      Subroutine IO_File_open: to open a file
+!!      Subroutine WRITE_DESFM: to write the descriptive part of a FMfile
+!!      Subroutine WRITE_LFIFM: to write the binary part of a FMfile
+!!      Subroutine SET_MASK   : to compute all the masks selected for budget
+!!                         computations
+!!      Subroutine BOUNDARIES   : set the fields at the marginal points in every
+!!                         directions according the selected boundary conditions
+!!      Subroutine INITIAL_GUESS: initializes the guess of the future instant
+!!      Subroutine LES_FLX_SPECTRA: computes the resolved fluxes and the
+!!                     spectra of some quantities when running in LES mode.
+!!      Subroutine ADVECTION: computes the advection terms.
+!!      Subroutine DYN_SOURCES: computes the curvature, Coriolis, gravity terms.
+!!      Subroutine NUM_DIFF: applies the fourth order numerical diffusion.
+!!      Subroutine RELAXATION: performs the relaxation to Larger Scale fields
+!!                             in the upper levels and outermost vertical planes
+!!      Subroutine PHYS_PARAM_n : computes the parameterized physical terms
+!!      Subroutine RAD_BOUND: prepares the velocity normal components for the bc.
+!!      Subroutine RESOLVED_CLOUD : computes the sources terms for water in any
+!!                                  form
+!!      Subroutine PRESSURE : computes the pressure gradient term and the
+!!                            absolute pressure
+!!      Subroutine EXCHANGE : updates the halo of each subdomains
+!!      Subroutine ENDSTEP : advances in time the  fields.
+!!      Subroutines UVW_LS_COUPLING and SCALAR_LS_COUPLING:
+!!                                 compute the large scale fields, used to
+!!                                 couple Model_n with outer informations.
+!!      Subroutine ENDSTEP_BUDGET: writes the budget informations.
+!!      Subroutine IO_File_close: closes a file
+!!      Subroutine DATETIME_CORRECTDATE: transform the current time in GMT
+!!      Subroutine FORCING : computes forcing terms
+!!      Subroutine ADD3DFIELD_ll : add a field to 3D-list
+!!
+!!    IMPLICIT ARGUMENTS
+!!    ------------------
+!!          MODD_DYN
+!!          MODD_CONF
+!!          MODD_NESTING
+!!          MODD_BUDGET
+!!          MODD_PARAMETERS
+!!          MODD_CONF_n
+!!          MODD_CURVCOR_n
+!!          MODD_DYN_n
+!!          MODD_DIM_n
+!!          MODD_ADV_n
+!!          MODD_FIELD_n
+!!          MODD_LSFIELD_n
+!!          MODD_GRID_n
+!!          MODD_METRICS_n
+!!          MODD_LBC_n
+!!          MODD_PARAM_n
+!!          MODD_REF_n
+!!          MODD_LUNIT_n
+!!          MODD_OUT_n
+!!          MODD_TIME_n
+!!          MODD_TURB_n
+!!          MODD_CLOUDPAR_n
+!!          MODD_TIME
+!!
+!!    REFERENCE
+!!    ---------
+!!
+!!    AUTHOR
+!!    ------
+!!      J.-P. Pinty                  * LA *
+!!
+!!    MODIFICATIONS
+!!    -------------
+!!      Original    15/09/94
+!!      Modification 20/10/94  (J.Stein) for the outputs and abs_layers routines
+!!      Modification 10/11/94  (J.Stein) change ABS_LAYER_FIELDS call
+!!      Modification 16/11/94  (J.Stein) add call to the renormalization
+!!      Modification 17/11/94  (J.-P. Lafore and J.-P. Pinty) call NUM_DIFF
+!!      Modification 08/12/94  (J.Stein) cleaning + remove (RENORM + ABS_LAYER..
+!!                             ..) + add RELAXATION + LS fiels in the arguments
+!!      Modification 19/12/94  (J.Stein) switch for the num diff
+!!      Modification 22/12/94  (J.Stein) update tdtcur + change dyn_source call
+!!      Modification 05/01/95  (J.Stein) add the parameterization monitor
+!!      Modification 09/01/95  (J.Stein) add the 1D switch
+!!      Modification 10/01/95  (J.Stein) displace the TDTCUR computation
+!!      Modification 03/01/95  (J.-P. Lafore) Absolute pressure diagnosis
+!!      Modification Jan 19, 1995 (J. Cuxart) Shunt the DYN_SOURCES in 1D cases.
+!!      Modification Jan 24, 1995 (J. Stein)  Interchange Boundaries and
+!!                           Initial_guess to correct a bug in 2D configuration
+!!      Modification Feb 02, 1995 (I.Mallet) update BOUNDARIES and RAD_BOUND
+!!                                           calls
+!!      Modification Mar 10, 1995 (I.Mallet) add call to SET_COUPLING
+!!                   March,21, 1995 (J. Stein) remove R from the historical var.
+!!                   March,26, 1995 (J. Stein) add the EPS variable
+!!                   April 18, 1995 (J. Cuxart) add the LES call
+!!                   Sept 20,1995 (Lafore) coupling for the dry mass Md
+!!                   Nov   2,1995 (Stein) displace the temporal counter increase
+!!                   Jan   2,1996 (Stein) rm the test on the temporal counter
+!!      Modification Feb   5,1996 (J. Vila) implementation new advection
+!!                                          schemes for scalars
+!!      Modification Feb  20,1996 (J.Stein) doctor norm
+!!                   Dec95 - Jul96 (Georgelin, Pinty, Mari, Suhre) FORCING
+!!                   June 17,1996 (Vincent, Lafore, Jabouille)
+!!                                        statistics of computing time
+!!                   Aug 8, 1996 (K. Suhre) add chemistry
+!!                   October 12, 1996 (J. Stein) save the PSRC value
+!!                   Sept 05,1996 (V.Masson) print of loop index for debugging
+!!                                           purposes
+!!                   July 22,1996 (Lafore) improve write of computing time statistics
+!!                   July 29,1996 (Lafore) nesting introduction
+!!                   Aug.  1,1996 (Lafore) synchronization between models
+!!                   Sept. 4,1996 (Lafore) modification of call to routine SET_COUPLING
+!!                                         now splitted in 2 routines
+!!                                         (UVW_LS_COUPLING and SCALAR_LS_COUPLING)
+!!                   Sept  5,1996 (V.Masson) print of loop index for debugging
+!!                                           purposes
+!!                   Sept 25,1996 (V.Masson) test for coupling performed here
+!!                   Oct. 29,1996 (Lafore)   one-way nesting implementation
+!!                   Oct. 12,1996 (J. Stein) save the PSRC value
+!!                   Dec. 12,1996 (Lafore)   change call to RAD_BOUND
+!!                   Dec. 21,1996 (Lafore)   two-way nesting implementation
+!!                   Mar. 12,1997 (Lafore)   introduction of "surfacic" LS fields
+!!                   Nov 18, 1996 (J.-P. Pinty) FORCING revisited (translation)
+!!                   Dec 04, 1996 (J.-P. Pinty) include mixed-phase clouds
+!!                   Dec 20, 1996 (J.-P. Pinty) update the budgets
+!!                   Dec 23, 1996 (J.-P. Pinty) add the diachronic file control
+!!                   Jan 11, 1997 (J.-P. Pinty) add the deep convection control
+!!                   Dec  20,1996 (V.Masson) call boundaries before the writing
+!!                   Fev 25, 1997 (P.Jabouille) modify the LES tools
+!!                   April 3,1997 (Lafore)      merging of the nesting
+!!                                              developments on MASTER3
+!!                   Jul.  8,1997 (Lafore)  print control for nesting (NVERB>=7)
+!!                   Jul. 28,1997 (Masson)  supress LSTEADY_DMASS
+!!                   Aug. 19,1997 (Lafore)  full Clark's formulation introduction
+!!                   Sept 26,1997 (Lafore)  LS source calculation at restart
+!!                                          (temporarily test to have LS at instant t)
+!!                   Jan. 28,1998 (Bechtold) add SST forcing
+!!                   fev. 10,1998 (Lafore)  RHODJ computation and storage for budget
+!!                   Jul. 10,1998 (Stein )  sequentiel loop for nesting
+!!                   Apr. 07,1999 (Stein )  cleaning of the nesting subroutines
+!!                   oct. 20,1998 (Jabouille) //
+!!                   oct. 20,2000 (J.-P. Pinty) add the C2R2 scheme
+!!                   fev. 01,2001 (D.Gazen) add module MODD_NSV for NSV variables
+!!                   mar,  4,2002 (V.Ducrocq) call to temporal series
+!!                   mar, 8, 2001 (V. Masson) advection of perturbation of theta in neutral cases.
+!!                   Nov, 6, 2002 (V. Masson) time counters for budgets & LES
+!!                   mars 20,2001 (Pinty)   add ICE4 and C3R5 options
+!!                   jan. 2004    (Masson)  surface externalization
+!!                   sept 2004 (M. Tomasini) Cloud mixing length modification
+!!                   june 2005 (P. Tulet)  add aerosols / dusts
+!!                   Jul. 2005 (N. Asencio)  two_way and phys_param calls: 
+!!                             Add the surface parameters : precipitating 
+!!                             hydrometeors, Short and Long Wave , MASKkids array 
+!!                   Fev. 2006 (M. Leriche) add aqueous phase chemistry
+!!                   april 2006 (T.Maric) Add halo related to 4th order advection scheme
+!!                   May 2006 Remove KEPS
+!!                   Oct 2008 (C.Lac) FIT for variables advected with PPM
+!!                   July 2009 : Displacement of surface diagnostics call to be
+!!                               coherent with  surface diagnostics obtained with DIAG
+!!                   10/11/2009 (P. Aumond) Add mean moments
+!!                   Nov, 12, 2009 (C. Barthe) add cloud electrification and lightning flashes
+!!                   July 2010 (M. Leriche) add ice phase chemical species
+!!                   April 2011 (C.Lac) : Remove instant M 
+!!                   April 2011 (C.Lac, V.Masson) : Time splitting for advection
+!!      J.Escobar 21/03/2013: for HALOK comment all NHALO=1 test
+!!       P. Tulet      Nov 2014 accumulated moles of aqueous species that fall at the surface   
+!!                   Dec 2014 (C.Lac) : For reproducibility START/RESTA
+!!      J.Escobar 20/04/2015: missing UPDATE_HALO before UPDATE_HALO2
+!!              July, 2015 (O.Nuissier/F.Duffourg) Add microphysics diagnostic for
+!!                                      aircraft, ballon and profiler
+!!       C.Lac    11/09/2015: correction of the budget due to FIT temporal scheme
+!!      J.Escobar : 15/09/2015 : WENO5 & JPHEXT <> 1
+!!                   Sep 2015 (S. Bielli) : Remove YDADFILE from argument call 
+!                              of write_phys_param
+!!      J.Escobar : 19/04/2016 : Pb IOZ/NETCDF , missing OPARALLELIO=.FALSE. for PGD files
+!!      M.Mazoyer : 04/2016      DTHRAD used for radiative cooling when LACTIT
+!!!      Modification    01/2016  (JP Pinty) Add LIMA
+!!  06/2016     (G.Delautier) phasage surfex 8
+!!      M.Leriche : 03/2016 Move computation of accumulated chem. in rain to ch_monitor
+!!                  09/2016 Add filter on negative values on AERDEP SV before relaxation
+!!                  10/2016  (C.Lac) _ Correction on the flag for Strang splitting
+!!                                  to insure reproducibility between START and RESTA
+!!                                  _  Add OSPLIT_WENO
+!!                                  _ Add droplet deposition 
+!!                   10/2016 (M.Mazoyer) New KHKO output fields
+!!      P.Wautelet : 11/07/2016 : removed MNH_NCWRIT define
+!!                   09/2017 Q.Rodier add LTEND_UV_FRC
+!!                   10/2017 (C.Lac) Necessity to have chemistry processes as
+!!                            the las process modifying XRSVS
+!!  01/2018      (G.Delautier) SURFEX 8.1
+!!  03/2018     (P.Wautelet)   replace ADD_FORECAST_TO_DATE by DATETIME_CORRECTDATE
+!!  Philippe Wautelet: 05/2016-04/2018: new data structures and calls for I/O
+!!                  07/2017  (V. Vionnet) : Add blowing snow scheme 
+!!      S. Riette : 11/2016 Add ZPABST to keep pressure constant during timestep
+!!                   01/2018 (C.Lac) Add VISCOSITY
+!!  Philippe Wautelet: 21/01/2019: add LIO_ALLOW_NO_BACKUP and LIO_NO_WRITE to modd_io_ll
+!                                  to allow to disable writes (for bench purposes)
+!  P. Wautelet 07/02/2019: remove OPARALLELIO argument from open and close files subroutines
+!                          (nsubfiles_ioz is now determined in IO_File_add2list)
+!!                   02/2019 C.Lac add rain fraction as an output field
+!!      Bielli S. 02/2019  Sea salt : significant sea wave height influences salt emission; 5 salt modes
+!  P. Wautelet 28/03/2019: use MNHTIME for time measurement variables
+!  P. Wautelet 28/03/2019: use TFILE instead of unit number for set_iluout_timing
+!  P. Wautelet 19/04/2019: removed unused dummy arguments and variables
+!  P. Wautelet 26/04/2019: replace non-standard FLOAT function by REAL function
+!  P. Wautelet 20/05/2019: add name argument to ADDnFIELD_ll + new ADD4DFIELD_ll subroutine
+!  J. Escobar  09/07/2019: norme Doctor -> Rename Module Type variable TZ -> T
+!  J. Escobar  09/07/2019: for bug in management of XLSZWSM variable, add/use specific 2D TLSFIELD2D_ll pointer
+!  P. Wautelet 23/07/2019: OpenACC: move data creations from resolved_cloud to modeln and optimize updates
+!  J. Escobar  27/09/2019: add missing report timing of RESOLVED_ELEC
+!!-------------------------------------------------------------------------------
+!
+!*       0.     DECLARATIONS
+!               ------------
+!
+USE MODD_2D_FRC
+USE MODD_ADV_n
+USE MODD_AIRCRAFT_BALLOON
+USE MODD_BAKOUT
+USE MODD_BIKHARDT_n
+USE MODD_BLANK
+USE MODD_BUDGET
+USE MODD_CH_AERO_n,      ONLY: XSOLORG, XMI
+USE MODD_CH_MNHC_n,      ONLY: LUSECHEM,LCH_CONV_LINOX,LUSECHAQ,LUSECHIC, &
+                               LCH_INIT_FIELD
+USE MODD_CLOUD_MF_n
+USE MODD_VISCOSITY
+USE MODD_DRAG_n
+USE MODD_CLOUDPAR_n
+USE MODD_CONF
+USE MODD_CONF_n
+USE MODD_CURVCOR_n
+USE MODD_DEEP_CONVECTION_n
+USE MODD_DIM_n
+USE MODD_DUST,           ONLY: LDUST
+USE MODD_DYN
+USE MODD_DYN_n
+USE MODD_DYNZD
+USE MODD_DYNZD_n
+USE MODD_ELEC_DESCR
+USE MODD_FIELD_n
+USE MODD_FRC
+USE MODD_FRC_n
+USE MODD_GET_n
+USE MODD_GRID,           ONLY: XLONORI,XLATORI
+USE MODD_GRID_n
+USE MODD_ICE_C1R3_DESCR, ONLY: XRTMIN_C1R3=>XRTMIN
+USE MODD_IO,             ONLY: LIO_NO_WRITE, TFILEDATA, TFILE_SURFEX, TFILE_DUMMY
+USE MODD_LBC_n
+USE MODD_LES
+USE MODD_LES_BUDGET
+USE MODD_LIMA_PRECIP_SCAVENGING_n
+USE MODD_LSFIELD_n
+USE MODD_LUNIT,          ONLY: TLUOUT0,TOUTDATAFILE
+USE MODD_LUNIT_n,        ONLY: TDIAFILE,TINIFILE,TINIFILEPGD,TLUOUT
+USE MODD_MEAN_FIELD
+USE MODD_MEAN_FIELD_n
+USE MODD_METRICS_n
+USE MODD_MNH_SURFEX_n
+USE MODD_NESTING
+USE MODD_NSV
+USE MODD_NUDGING_n
+USE MODD_OUT_n
+USE MODD_PARAM_C1R3,     ONLY: NSEDI => LSEDI, NHHONI => LHHONI
+USE MODD_PARAM_C2R2,     ONLY: NSEDC => LSEDC, NRAIN => LRAIN, NACTIT => LACTIT,LACTTKE,LDEPOC
+USE MODD_PARAMETERS
+USE MODD_PARAM_ICE,      ONLY: LWARM,LSEDIC,LCONVHG,LDEPOSC
+USE MODD_PARAM_LIMA,     ONLY: MSEDC => LSEDC, MWARM => LWARM, MRAIN => LRAIN, &
+                               MACTIT => LACTIT, LSCAV, LCOLD,                 &
+                               MSEDI => LSEDI, MHHONI => LHHONI, LHAIL,        &
+                               XRTMIN_LIMA=>XRTMIN, MACTTKE=>LACTTKE
+USE MODD_BLOWSNOW_n
+USE MODD_BLOWSNOW
+USE MODD_PARAM_MFSHALL_n
+USE MODD_PARAM_n
+USE MODD_PAST_FIELD_n
+USE MODD_PRECIP_n
+use modd_precision,      only: MNHTIME
+USE MODD_PROFILER_n
+USE MODD_RADIATIONS_n,   ONLY: XTSRAD,XSCAFLASWD,XDIRFLASWD,XDIRSRFSWD, XAER, XDTHRAD
+USE MODD_RAIN_ICE_DESCR, ONLY: XRTMIN
+USE MODD_REF_n
+USE MODD_SALT,           ONLY: LSALT
+USE MODD_SERIES,         ONLY: LSERIES
+USE MODD_SERIES_n,       ONLY: NFREQSERIES
+USE MODD_STATION_n
+USE MODD_SUB_MODEL_n
+USE MODD_TIME
+USE MODD_TIME_n
+USE MODD_TIMEZ
+USE MODD_TURB_CLOUD,     ONLY: NMODEL_CLOUD,CTURBLEN_CLOUD,XCEI
+USE MODD_TURB_n
+!
+USE MODE_DATETIME
+USE MODE_ELEC_ll
+USE MODE_GRIDCART
+USE MODE_GRIDPROJ
+USE MODE_IO_FIELD_WRITE,   only: IO_Field_user_write, IO_Fieldlist_write, IO_Header_write
+USE MODE_IO_FILE,          only: IO_File_close, IO_File_open
+USE MODE_IO_MANAGE_STRUCT, only: IO_File_add2list
+USE MODE_ll
+USE MODE_MNH_TIMING
+USE MODE_MODELN_HANDLER
+USE MODE_MPPDB
+USE MODE_ONE_WAY_n
+!
+USE MODI_ADVECTION_METSV
+USE MODI_ADVECTION_UVW
+USE MODI_ADVECTION_UVW_CEN
+USE MODI_ADV_FORCING_n
+USE MODI_AER_MONITOR_n
+USE MODI_AIRCRAFT_BALLOON
+USE MODI_BLOWSNOW
+USE MODI_BOUNDARIES
+USE MODI_BUDGET_FLAGS
+USE MODI_CART_COMPRESS
+USE MODI_CH_MONITOR_n
+USE MODI_DIAG_SURF_ATM_N
+USE MODI_DYN_SOURCES
+USE MODI_END_DIAG_IN_RUN
+USE MODI_ENDSTEP
+USE MODI_ENDSTEP_BUDGET
+USE MODI_EXCHANGE
+USE MODI_FORCING
+USE MODI_FORC_SQUALL_LINE
+USE MODI_FORC_WIND
+USE MODI_GET_HALO
+USE MODI_GRAVITY_IMPL
+USE MODI_INI_DIAG_IN_RUN
+USE MODI_INI_LG
+USE MODI_INI_MEAN_FIELD
+USE MODI_INITIAL_GUESS
+USE MODI_LES_INI_TIMESTEP_n
+USE MODI_LES_N
+USE MODI_VISCOSITY
+USE MODI_LIMA_PRECIP_SCAVENGING
+USE MODI_LS_COUPLING
+USE MODI_MASK_COMPRESS
+USE MODI_MEAN_FIELD
+USE MODI_MENU_DIACHRO
+USE MODI_MNHGET_SURF_PARAM_n
+USE MODI_MNHWRITE_ZS_DUMMY_n
+USE MODI_NUDGING
+USE MODI_NUM_DIFF
+USE MODI_PHYS_PARAM_n
+USE MODI_PRESSUREZ
+USE MODI_PROFILER_n
+USE MODI_RAD_BOUND
+USE MODI_RELAX2FW_ION 
+USE MODI_RELAXATION
+USE MODI_REL_FORCING_n
+USE MODI_RESOLVED_CLOUD
+USE MODI_RESOLVED_ELEC_n
+USE MODI_SERIES_N
+USE MODI_SETLB_LG
+USE MODI_SET_MASK
+USE MODI_SHUMAN
+USE MODI_SPAWN_LS_n
+USE MODI_STATION_n
+USE MODI_TURB_CLOUD_INDEX
+USE MODI_TWO_WAY
+USE MODI_UPDATE_NSV
+USE MODI_WRITE_AIRCRAFT_BALLOON
+USE MODI_WRITE_DESFM_n
+USE MODI_WRITE_DIAG_SURF_ATM_N
+USE MODI_WRITE_LES_n
+USE MODI_WRITE_LFIFM_n
+USE MODI_WRITE_LFIFMN_FORDIACHRO_n
+USE MODI_WRITE_PROFILER_n
+USE MODI_WRITE_SERIES_n
+USE MODI_WRITE_STATION_n
+USE MODI_WRITE_SURF_ATM_N
+!
+IMPLICIT NONE
+!
+!*       0.1   declarations of arguments
+!
+!
+!
+INTEGER, INTENT(IN)   :: KTCOUNT
+LOGICAL, INTENT(INOUT):: OEXIT
+!
+!*       0.2   declarations of local variables
+!
+INTEGER :: ILUOUT      ! Logical unit number for the output listing
+INTEGER :: IIU,IJU,IKU ! array size in first, second and third dimensions
+INTEGER :: IIB,IIE,IJB,IJE ! index values for the physical subdomain
+INTEGER :: JSV,JRR     ! Loop index for scalar and moist variables
+INTEGER  :: INBVAR              ! number of HALO2_lls to allocate
+INTEGER  :: IINFO_ll            ! return code of parallel routine
+INTEGER :: IVERB                ! LFI verbosity level
+LOGICAL :: GSTEADY_DMASS        ! conditional call to mass computation
+!
+                                ! for computing time analysis
+REAL(kind=MNHTIME), DIMENSION(2) :: ZTIME, ZTIME1, ZTIME2, ZEND, ZTOT, ZALL, ZTOT_PT
+REAL(kind=MNHTIME), DIMENSION(2) :: ZTIME_STEP,ZTIME_STEP_PTS
+CHARACTER                 :: YMI
+INTEGER                   :: IPOINTS
+CHARACTER(len=16)         :: YTCOUNT,YPOINTS
+!
+INTEGER :: ISYNCHRO          ! model synchronic index relative to its father
+                             ! = 1  for the first time step in phase with DAD
+                             ! = 0  for the last  time step (out of phase)
+INTEGER      :: IMI ! Current model index
+REAL, DIMENSION(:,:),ALLOCATABLE          :: ZSEA
+REAL, DIMENSION(:,:),ALLOCATABLE          :: ZTOWN
+! Dummy pointers needed to correct an ifort Bug
+REAL, DIMENSION(:), POINTER :: DPTR_XZHAT
+REAL, DIMENSION(:), POINTER :: DPTR_XBMX1,DPTR_XBMX2,DPTR_XBMX3,DPTR_XBMX4
+REAL, DIMENSION(:), POINTER :: DPTR_XBMY1,DPTR_XBMY2,DPTR_XBMY3,DPTR_XBMY4
+REAL, DIMENSION(:), POINTER :: DPTR_XBFX1,DPTR_XBFX2,DPTR_XBFX3,DPTR_XBFX4
+REAL, DIMENSION(:), POINTER :: DPTR_XBFY1,DPTR_XBFY2,DPTR_XBFY3,DPTR_XBFY4
+CHARACTER(LEN=4), DIMENSION(:), POINTER :: DPTR_CLBCX,DPTR_CLBCY
+INTEGER, DIMENSION(:,:,:), POINTER :: DPTR_NKLIN_LBXU,DPTR_NKLIN_LBYU,DPTR_NKLIN_LBXV,DPTR_NKLIN_LBYV
+INTEGER, DIMENSION(:,:,:), POINTER :: DPTR_NKLIN_LBXW,DPTR_NKLIN_LBYW,DPTR_NKLIN_LBXM,DPTR_NKLIN_LBYM
+REAL, DIMENSION(:,:,:), POINTER :: DPTR_XCOEFLIN_LBXU,DPTR_XCOEFLIN_LBYU
+REAL, DIMENSION(:,:,:), POINTER :: DPTR_XCOEFLIN_LBXV,DPTR_XCOEFLIN_LBYV
+REAL, DIMENSION(:,:,:), POINTER :: DPTR_XCOEFLIN_LBXW,DPTR_XCOEFLIN_LBYW
+REAL, DIMENSION(:,:,:), POINTER :: DPTR_XCOEFLIN_LBXM,DPTR_XCOEFLIN_LBYM
+REAL, DIMENSION(:,:,:),   POINTER :: DPTR_XLBXUM,DPTR_XLBYUM,DPTR_XLBXVM,DPTR_XLBYVM
+REAL, DIMENSION(:,:,:),   POINTER :: DPTR_XLBXWM,DPTR_XLBYWM,DPTR_XLBXTHM,DPTR_XLBYTHM
+REAL, DIMENSION(:,:,:),   POINTER :: DPTR_XLBXTKEM,DPTR_XLBYTKEM
+REAL, DIMENSION(:,:,:,:),   POINTER :: DPTR_XLBXSVM,DPTR_XLBYSVM                
+REAL, DIMENSION(:,:,:,:), POINTER :: DPTR_XLBXRM,DPTR_XLBYRM
+REAL, DIMENSION(:,:,:),   POINTER ::  DPTR_XZZ
+REAL, DIMENSION(:,:,:), POINTER :: DPTR_XLSUM,DPTR_XLSVM,DPTR_XLSWM,DPTR_XLSTHM,DPTR_XLSRVM
+REAL, DIMENSION(:,:,:), POINTER :: DPTR_XLSUS,DPTR_XLSVS,DPTR_XLSWS,DPTR_XLSTHS,DPTR_XLSRVS
+REAL, DIMENSION(:,:),   POINTER :: DPTR_XLSZWSM,DPTR_XLSZWSS
+REAL, DIMENSION(:,:,:), POINTER :: DPTR_XLBXUS,DPTR_XLBYUS,DPTR_XLBXVS,DPTR_XLBYVS
+REAL, DIMENSION(:,:,:), POINTER :: DPTR_XLBXWS,DPTR_XLBYWS,DPTR_XLBXTHS,DPTR_XLBYTHS
+REAL, DIMENSION(:,:,:), POINTER :: DPTR_XLBXTKES,DPTR_XLBYTKES
+REAL, DIMENSION(:,:,:,:), POINTER :: DPTR_XLBXRS,DPTR_XLBYRS,DPTR_XLBXSVS,DPTR_XLBYSVS
+!
+REAL, DIMENSION(:,:,:), POINTER :: DPTR_XRHODJ,DPTR_XUM,DPTR_XVM,DPTR_XWM,DPTR_XTHM
+REAL, DIMENSION(:,:,:), POINTER :: DPTR_XTKEM,DPTR_XRUS,DPTR_XRVS,DPTR_XRWS,DPTR_XRTHS
+REAL, DIMENSION(:,:,:), POINTER :: DPTR_XRTKES,DPTR_XDIRFLASWD,DPTR_XSCAFLASWD,DPTR_XDIRSRFSWD
+REAL, DIMENSION(:,:,:,:), POINTER :: DPTR_XRM,DPTR_XSVM,DPTR_XRRS,DPTR_XRSVS
+REAL, DIMENSION(:,:), POINTER :: DPTR_XINPRC,DPTR_XINPRR,DPTR_XINPRS,DPTR_XINPRG
+REAL, DIMENSION(:,:), POINTER :: DPTR_XINPRH,DPTR_XPRCONV,DPTR_XPRSCONV
+LOGICAL, DIMENSION(:,:),POINTER :: DPTR_GMASKkids
+!
+! REAL, DIMENSION(SIZE(XTHT,1),SIZE(XTHT,2),SIZE(XTHT,3))           :: ZSPEEDC
+! REAL, DIMENSION(SIZE(XTHT,1),SIZE(XTHT,2),SIZE(XTHT,3))           :: ZSPEEDR
+! REAL, DIMENSION(SIZE(XTHT,1),SIZE(XTHT,2),SIZE(XTHT,3))           :: ZSPEEDS
+! REAL, DIMENSION(SIZE(XTHT,1),SIZE(XTHT,2),SIZE(XTHT,3))           :: ZSPEEDG
+! REAL, DIMENSION(SIZE(XTHT,1),SIZE(XTHT,2),SIZE(XTHT,3))           :: ZSPEEDH
+! REAL, DIMENSION(SIZE(XTHT,1),SIZE(XTHT,2),SIZE(XTHT,3))           :: ZINPRC3D
+! REAL, DIMENSION(SIZE(XTHT,1),SIZE(XTHT,2),SIZE(XTHT,3))           :: ZINPRS3D
+! REAL, DIMENSION(SIZE(XTHT,1),SIZE(XTHT,2),SIZE(XTHT,3))           :: ZINPRG3D
+! REAL, DIMENSION(SIZE(XTHT,1),SIZE(XTHT,2),SIZE(XTHT,3))           :: ZINPRH3D
+!
+LOGICAL :: KWARM
+LOGICAL :: KRAIN
+LOGICAL :: KSEDC
+LOGICAL :: KACTIT
+LOGICAL :: KSEDI
+LOGICAL :: KHHONI
+!
+REAL, DIMENSION(:,:,:), ALLOCATABLE :: ZRUS,ZRVS,ZRWS
+REAL, DIMENSION(:,:,:), ALLOCATABLE :: ZPABST !To give pressure at t
+                                                     ! (and not t+1) to resolved_cloud
+REAL, DIMENSION(:,:,:), ALLOCATABLE :: ZJ
+!
+TYPE(LIST_ll), POINTER :: TZFIELDC_ll   ! list of fields to exchange
+TYPE(HALO2LIST_ll), POINTER :: TZHALO2C_ll   ! list of fields to exchange
+LOGICAL :: GCLD                     ! conditionnal call for dust wet deposition
+LOGICAL :: GCLOUD_ONLY              ! conditionnal radiation computations for
+                                !      the only cloudy columns
+REAL, DIMENSION(:,:,:,:), ALLOCATABLE :: ZWETDEPAER
+
+
+!
+TYPE(TFILEDATA),POINTER :: TZBAKFILE, TZOUTFILE
+! TYPE(TFILEDATA),SAVE    :: TZDIACFILE
+!-------------------------------------------------------------------------------
+!
+TZBAKFILE=> NULL()
+TZOUTFILE=> NULL()
+
+allocate( ZRUS  (SIZE(XTHT,1),SIZE(XTHT,2),SIZE(XTHT,3)) )
+allocate( ZRVS  (SIZE(XTHT,1),SIZE(XTHT,2),SIZE(XTHT,3)) )
+allocate( ZRWS  (SIZE(XTHT,1),SIZE(XTHT,2),SIZE(XTHT,3)) )
+allocate( ZPABST(SIZE(XTHT,1),SIZE(XTHT,2),SIZE(XTHT,3)) )
+allocate( ZJ    (SIZE(XTHT,1),SIZE(XTHT,2),SIZE(XTHT,3)) )
+allocate( ZWETDEPAER(SIZE(XRSVS,1), SIZE(XRSVS,2), SIZE(XRSVS,3), NSV_AER) )
+
+!$acc data create( zrws )
+
+!
+!*       0.    MICROPHYSICAL SCHEME
+!              ------------------- 
+SELECT CASE(CCLOUD)
+CASE('C2R2','KHKO','C3R5')
+  KWARM  = .TRUE.        
+  KRAIN  = NRAIN
+  KSEDC  = NSEDC
+  KACTIT = NACTIT
+!
+  KSEDI  = NSEDI
+  KHHONI = NHHONI
+CASE('LIMA')
+  KWARM  = MWARM        
+  KRAIN  = MRAIN
+  KSEDC  = MSEDC
+  KACTIT = MACTIT
+!
+  KSEDI  = MSEDI
+  KHHONI = MHHONI
+CASE('ICE3','ICE4') !default values
+  KWARM  = LWARM        
+  KRAIN  = .TRUE.
+  KSEDC  = .TRUE.
+  KACTIT = .FALSE.
+!
+  KSEDI  = .TRUE.
+  KHHONI = .FALSE.
+END SELECT
+!
+!
+!*        1    PRELIMINARY
+!              ------------
+IMI = GET_CURRENT_MODEL_INDEX()
+!
+!*       1.0   update NSV_* variables for current model
+!              ----------------------------------------
+!
+CALL UPDATE_NSV(IMI)
+!
+!*       1.1   RECOVER THE LOGICAL UNIT NUMBER FOR THE OUTPUT PRINTS
+!
+ILUOUT = TLUOUT%NLU
+!
+!*       1.2   SET ARRAY SIZE
+!
+CALL GET_DIM_EXT_ll('B',IIU,IJU)
+IKU=NKMAX+2*JPVEXT
+CALL GET_INDICE_ll (IIB,IJB,IIE,IJE)
+!
+IF (IMI==1) THEN
+  GSTEADY_DMASS=LSTEADYLS
+ELSE
+  GSTEADY_DMASS=.FALSE.
+END IF
+!
+!*       1.3   OPEN THE DIACHRONIC FILE
+!
+IF (KTCOUNT == 1) THEN
+!
+  NULLIFY(TFIELDS_ll,TLSFIELD_ll,TFIELDT_ll)
+  NULLIFY(TLSFIELD2D_ll)
+  NULLIFY(THALO2T_ll)
+  NULLIFY(TLSHALO2_ll)
+  NULLIFY(TFIELDSC_ll)
+!
+  ALLOCATE(XWT_ACT_NUC(SIZE(XWT,1),SIZE(XWT,2),SIZE(XWT,3)))
+  ALLOCATE(GMASKkids(SIZE(XWT,1),SIZE(XWT,2)))
+!
+! initialization of the FM file backup/output number
+  IBAK=0
+  IOUT=0
+!
+  IF ( .NOT. LIO_NO_WRITE ) THEN
+    CALL IO_File_open(TDIAFILE)
+!
+    CALL IO_Header_write(TDIAFILE)
+    CALL WRITE_DESFM_n(IMI,TDIAFILE)
+    CALL WRITE_LFIFMN_FORDIACHRO_n(TDIAFILE)
+  END IF
+!
+!*       1.4   Initialization of the list of fields for the halo updates
+!
+!                 a) Sources terms
+!
+  CALL ADD3DFIELD_ll( TFIELDS_ll, XRUS,      'MODEL_n::XRUS' )
+  CALL ADD3DFIELD_ll( TFIELDS_ll, XRVS,      'MODEL_n::XRVS' )
+  CALL ADD3DFIELD_ll( TFIELDS_ll, XRWS,      'MODEL_n::XRWS' )
+  CALL ADD3DFIELD_ll( TFIELDS_ll, XRTHS,     'MODEL_n::XRTHS' )
+  CALL ADD3DFIELD_ll( TFIELDS_ll, XRUS_PRES, 'MODEL_n::XRUS_PRES' )
+  CALL ADD3DFIELD_ll( TFIELDS_ll, XRVS_PRES, 'MODEL_n::XRVS_PRES' )
+  CALL ADD3DFIELD_ll( TFIELDS_ll, XRWS_PRES, 'MODEL_n::XRWS_PRES' )
+  CALL ADD3DFIELD_ll( TFIELDS_ll, XRTHS_CLD, 'MODEL_n::XRTHS_CLD' )
+  IF (SIZE(XRTKES,1) /= 0) CALL ADD3DFIELD_ll( TFIELDS_ll, XRTKES, 'MODEL_n::XRTKES' )
+  CALL ADD4DFIELD_ll( TFIELDS_ll, XRRS     (:,:,:,1:NRR), 'MODEL_n::XRRS' )
+  CALL ADD4DFIELD_ll( TFIELDS_ll, XRRS_CLD (:,:,:,1:NRR), 'MODEL_n::XRRS_CLD' )
+  CALL ADD4DFIELD_ll( TFIELDS_ll, XRSVS    (:,:,:,1:NSV), 'MODEL_n::XRSVS')
+  CALL ADD4DFIELD_ll( TFIELDS_ll, XRSVS_CLD(:,:,:,1:NSV), 'MODEL_n::XRSVS_CLD')
+  IF (SIZE(XSRCT,1) /= 0) CALL ADD3DFIELD_ll( TFIELDS_ll, XSRCT, 'MODEL_n::XSRCT' )
+  !
+  IF ((LNUMDIFU .OR. LNUMDIFTH .OR. LNUMDIFSV) ) THEN
+  !
+  !                 b) LS fields
+  !
+    CALL ADD3DFIELD_ll( TLSFIELD_ll,   XLSUM,   'MODEL_n::XLSUM'   )
+    CALL ADD3DFIELD_ll( TLSFIELD_ll,   XLSVM,   'MODEL_n::XLSVM'   )
+    CALL ADD3DFIELD_ll( TLSFIELD_ll,   XLSWM,   'MODEL_n::XLSWM'   )
+    CALL ADD3DFIELD_ll( TLSFIELD_ll,   XLSTHM,  'MODEL_n::XLSTHM'  )
+    CALL ADD2DFIELD_ll( TLSFIELD2D_ll, XLSZWSM, 'MODEL_n::XLSZWSM' )
+    IF (NRR >= 1) THEN
+      CALL ADD3DFIELD_ll( TLSFIELD_ll, XLSRVM, 'MODEL_n::XLSRVM' )
+    ENDIF
+  !
+  !                 c) Fields at t
+  !
+    CALL ADD3DFIELD_ll( TFIELDT_ll, XUT,  'MODEL_n::XUT'  )
+    CALL ADD3DFIELD_ll( TFIELDT_ll, XVT,  'MODEL_n::XVT'  )
+    CALL ADD3DFIELD_ll( TFIELDT_ll, XWT,  'MODEL_n::XWT'  )
+    CALL ADD3DFIELD_ll( TFIELDT_ll, XTHT, 'MODEL_n::XTHT' )
+    IF (SIZE(XRTKES,1) /= 0) CALL ADD3DFIELD_ll( TFIELDT_ll, XTKET, 'MODEL_n::XTKET' )
+    CALL ADD4DFIELD_ll(TFIELDT_ll, XRT (:,:,:,1:NRR), 'MODEL_n::XSV'  )
+    CALL ADD4DFIELD_ll(TFIELDT_ll, XSVT(:,:,:,1:NSV), 'MODEL_n::XSVT' )
+  !
+  !*       1.5   Initialize the list of fields for the halo updates (2nd layer)
+  !
+    INBVAR = 4+NRR+NSV
+    IF (SIZE(XRTKES,1) /= 0) INBVAR=INBVAR+1
+    CALL INIT_HALO2_ll(THALO2T_ll,INBVAR,IIU,IJU,IKU)
+    CALL INIT_HALO2_ll(TLSHALO2_ll,4+MIN(1,NRR),IIU,IJU,IKU)
+  !
+  !*       1.6   Initialise the 2nd layer of the halo of the LS fields
+  !
+    IF ( LSTEADYLS ) THEN
+       CALL UPDATE_HALO_ll(TLSFIELD_ll, IINFO_ll)
+       CALL UPDATE_HALO_ll(TLSFIELD2D_ll,IINFO_ll) 
+       CALL UPDATE_HALO2_ll(TLSFIELD_ll, TLSHALO2_ll, IINFO_ll)
+    END IF
+  END IF
+  !
+!
+  !
+  XT_START     = 0.0_MNHTIME
+  !
+  XT_STORE     = 0.0_MNHTIME
+  XT_BOUND     = 0.0_MNHTIME
+  XT_GUESS     = 0.0_MNHTIME
+  XT_FORCING   = 0.0_MNHTIME
+  XT_NUDGING   = 0.0_MNHTIME
+  XT_ADV       = 0.0_MNHTIME
+  XT_ADVUVW    = 0.0_MNHTIME
+  XT_GRAV      = 0.0_MNHTIME
+  XT_SOURCES   = 0.0_MNHTIME
+  !
+  XT_DIFF      = 0.0_MNHTIME
+  XT_RELAX     = 0.0_MNHTIME
+  XT_PARAM     = 0.0_MNHTIME
+  XT_SPECTRA   = 0.0_MNHTIME
+  XT_HALO      = 0.0_MNHTIME
+  XT_VISC      = 0.0_MNHTIME
+  XT_RAD_BOUND = 0.0_MNHTIME
+  XT_PRESS     = 0.0_MNHTIME
+  !
+  XT_CLOUD     = 0.0_MNHTIME
+  XT_STEP_SWA  = 0.0_MNHTIME
+  XT_STEP_MISC = 0.0_MNHTIME
+  XT_COUPL     = 0.0_MNHTIME
+  XT_1WAY      = 0.0_MNHTIME
+  XT_STEP_BUD  = 0.0_MNHTIME
+  !
+  XT_RAD       = 0.0_MNHTIME
+  XT_DCONV     = 0.0_MNHTIME
+  XT_GROUND    = 0.0_MNHTIME
+  XT_TURB      = 0.0_MNHTIME
+  XT_MAFL      = 0.0_MNHTIME
+  XT_DRAG      = 0.0_MNHTIME
+  XT_TRACER    = 0.0_MNHTIME
+  XT_SHADOWS   = 0.0_MNHTIME
+  XT_ELEC      = 0.0_MNHTIME
+  XT_CHEM      = 0.0_MNHTIME
+  XT_2WAY      = 0.0_MNHTIME
+  !
+END IF
+!
+!*       1.7   Allocation of arrays for observation diagnostics
+!
+CALL INI_DIAG_IN_RUN(IIU,IJU,IKU,LFLYER,LSTATION,LPROFILER)
+!
+!
+CALL SECOND_MNH2(ZEND)
+!
+!-------------------------------------------------------------------------------
+!
+!*       2.    ONE-WAY NESTING AND LARGE SCALE FIELD REFRESH
+!              ---------------------------------------------
+!
+!
+CALL SECOND_MNH2(ZTIME1)
+!
+ISYNCHRO = MODULO (KTCOUNT, NDTRATIO(IMI) )      ! test of synchronisation
+!
+
+
+IF (IMI/=1 .AND. NDAD(IMI)/=IMI .AND. (ISYNCHRO==1 .OR. NDTRATIO(IMI) == 1) ) THEN     
+!                                                                        
+  ! Use dummy pointers to correct an ifort BUG
+  DPTR_XBMX1=>XBMX1
+  DPTR_XBMX2=>XBMX2
+  DPTR_XBMX3=>XBMX3
+  DPTR_XBMX4=>XBMX4
+  DPTR_XBMY1=>XBMY1
+  DPTR_XBMY2=>XBMY2
+  DPTR_XBMY3=>XBMY3
+  DPTR_XBMY4=>XBMY4
+  DPTR_XBFX1=>XBFX1
+  DPTR_XBFX2=>XBFX2
+  DPTR_XBFX3=>XBFX3
+  DPTR_XBFX4=>XBFX4
+  DPTR_XBFY1=>XBFY1
+  DPTR_XBFY2=>XBFY2
+  DPTR_XBFY3=>XBFY3
+  DPTR_XBFY4=>XBFY4
+  DPTR_CLBCX=>CLBCX
+  DPTR_CLBCY=>CLBCY
+  !
+  DPTR_XZZ=>XZZ
+  DPTR_XZHAT=>XZHAT
+  DPTR_XCOEFLIN_LBXM=>XCOEFLIN_LBXM
+  DPTR_XLSTHM=>XLSTHM
+  DPTR_XLSRVM=>XLSRVM
+  DPTR_XLSUM=>XLSUM
+  DPTR_XLSVM=>XLSVM
+  DPTR_XLSWM=>XLSWM
+  DPTR_XLSZWSM=>XLSZWSM
+  DPTR_XLSTHS=>XLSTHS
+  DPTR_XLSRVS=>XLSRVS
+  DPTR_XLSUS=>XLSUS
+  DPTR_XLSVS=>XLSVS
+  DPTR_XLSWS=>XLSWS
+  DPTR_XLSZWSS=>XLSZWSS
+  !
+  IF ( LSTEADYLS                     ) THEN
+    NCPL_CUR=0
+  ELSE
+    IF (NCPL_CUR/=1) THEN
+      IF ( KTCOUNT+1 == NCPL_TIMES(NCPL_CUR-1,IMI)  ) THEN
+        !
+        !  LS sources are interpolated from the LS field 
+        ! values of model DAD(IMI)
+        CALL SPAWN_LS_n(NDAD(IMI),XTSTEP,IMI,                        &
+             DPTR_XBMX1,DPTR_XBMX2,DPTR_XBMX3,DPTR_XBMX4,DPTR_XBMY1,DPTR_XBMY2,DPTR_XBMY3,DPTR_XBMY4,        &
+             DPTR_XBFX1,DPTR_XBFX2,DPTR_XBFX3,DPTR_XBFX4,DPTR_XBFY1,DPTR_XBFY2,DPTR_XBFY3,DPTR_XBFY4,        &
+             NDXRATIO_ALL(IMI),NDYRATIO_ALL(IMI),                    &
+             DPTR_CLBCX,DPTR_CLBCY,DPTR_XZZ,DPTR_XZHAT,LSLEVE,XLEN1,XLEN2,DPTR_XCOEFLIN_LBXM, &
+             DPTR_XLSTHM,DPTR_XLSRVM,DPTR_XLSUM,DPTR_XLSVM,DPTR_XLSWM,DPTR_XLSZWSM,                        &
+             DPTR_XLSTHS,DPTR_XLSRVS,DPTR_XLSUS,DPTR_XLSVS,DPTR_XLSWS, DPTR_XLSZWSS                         )
+      END IF
+    END IF
+    !
+  END IF
+  !
+  DPTR_NKLIN_LBXU=>NKLIN_LBXU
+  DPTR_XCOEFLIN_LBXU=>XCOEFLIN_LBXU
+  DPTR_NKLIN_LBYU=>NKLIN_LBYU
+  DPTR_XCOEFLIN_LBYU=>XCOEFLIN_LBYU
+  DPTR_NKLIN_LBXV=>NKLIN_LBXV
+  DPTR_XCOEFLIN_LBXV=>XCOEFLIN_LBXV
+  DPTR_NKLIN_LBYV=>NKLIN_LBYV
+  DPTR_XCOEFLIN_LBYV=>XCOEFLIN_LBYV
+  DPTR_NKLIN_LBXW=>NKLIN_LBXW
+  DPTR_XCOEFLIN_LBXW=>XCOEFLIN_LBXW
+  DPTR_NKLIN_LBYW=>NKLIN_LBYW
+  DPTR_XCOEFLIN_LBYW=>XCOEFLIN_LBYW
+  !
+  DPTR_NKLIN_LBXM=>NKLIN_LBXM
+  DPTR_XCOEFLIN_LBXM=>XCOEFLIN_LBXM
+  DPTR_NKLIN_LBYM=>NKLIN_LBYM
+  DPTR_XCOEFLIN_LBYM=>XCOEFLIN_LBYM
+  !
+  DPTR_XLBXUM=>XLBXUM
+  DPTR_XLBYUM=>XLBYUM
+  DPTR_XLBXVM=>XLBXVM
+  DPTR_XLBYVM=>XLBYVM
+  DPTR_XLBXWM=>XLBXWM
+  DPTR_XLBYWM=>XLBYWM
+  DPTR_XLBXTHM=>XLBXTHM
+  DPTR_XLBYTHM=>XLBYTHM
+  DPTR_XLBXTKEM=>XLBXTKEM
+  DPTR_XLBYTKEM=>XLBYTKEM
+  DPTR_XLBXRM=>XLBXRM
+  DPTR_XLBYRM=>XLBYRM
+  DPTR_XLBXSVM=>XLBXSVM
+  DPTR_XLBYSVM=>XLBYSVM
+  !  
+  DPTR_XLBXUS=>XLBXUS
+  DPTR_XLBYUS=>XLBYUS
+  DPTR_XLBXVS=>XLBXVS
+  DPTR_XLBYVS=>XLBYVS
+  DPTR_XLBXWS=>XLBXWS
+  DPTR_XLBYWS=>XLBYWS
+  DPTR_XLBXTHS=>XLBXTHS
+  DPTR_XLBYTHS=>XLBYTHS
+  DPTR_XLBXTKES=>XLBXTKES
+  DPTR_XLBYTKES=>XLBYTKES
+  DPTR_XLBXRS=>XLBXRS
+  DPTR_XLBYRS=>XLBYRS
+  DPTR_XLBXSVS=>XLBXSVS
+  DPTR_XLBYSVS=>XLBYSVS
+  !
+  CALL ONE_WAY_n(NDAD(IMI),XTSTEP,IMI,KTCOUNT,                   &
+       DPTR_XBMX1,DPTR_XBMX2,DPTR_XBMX3,DPTR_XBMX4,DPTR_XBMY1,DPTR_XBMY2,DPTR_XBMY3,DPTR_XBMY4,        &
+       DPTR_XBFX1,DPTR_XBFX2,DPTR_XBFX3,DPTR_XBFX4,DPTR_XBFY1,DPTR_XBFY2,DPTR_XBFY3,DPTR_XBFY4,        &
+       NDXRATIO_ALL(IMI),NDYRATIO_ALL(IMI),NDTRATIO(IMI),         &
+       DPTR_CLBCX,DPTR_CLBCY,NRIMX,NRIMY,                                &
+       DPTR_NKLIN_LBXU,DPTR_XCOEFLIN_LBXU,DPTR_NKLIN_LBYU,DPTR_XCOEFLIN_LBYU,      &
+       DPTR_NKLIN_LBXV,DPTR_XCOEFLIN_LBXV,DPTR_NKLIN_LBYV,DPTR_XCOEFLIN_LBYV,      &
+       DPTR_NKLIN_LBXW,DPTR_XCOEFLIN_LBXW,DPTR_NKLIN_LBYW,DPTR_XCOEFLIN_LBYW,      &
+       DPTR_NKLIN_LBXM,DPTR_XCOEFLIN_LBXM,DPTR_NKLIN_LBYM,DPTR_XCOEFLIN_LBYM,      &
+       GSTEADY_DMASS,CCLOUD,LUSECHAQ,LUSECHIC,                           &
+       DPTR_XLBXUM,DPTR_XLBYUM,DPTR_XLBXVM,DPTR_XLBYVM,DPTR_XLBXWM,DPTR_XLBYWM,              &
+       DPTR_XLBXTHM,DPTR_XLBYTHM,                                        &
+       DPTR_XLBXTKEM,DPTR_XLBYTKEM,                                      &
+       DPTR_XLBXRM,DPTR_XLBYRM,DPTR_XLBXSVM,DPTR_XLBYSVM,                          &
+       XDRYMASST,XDRYMASSS,                                    &
+       DPTR_XLBXUS,DPTR_XLBYUS,DPTR_XLBXVS,DPTR_XLBYVS,DPTR_XLBXWS,DPTR_XLBYWS,              &
+       DPTR_XLBXTHS,DPTR_XLBYTHS,                                        &
+       DPTR_XLBXTKES,DPTR_XLBYTKES,                                      &
+       DPTR_XLBXRS,DPTR_XLBYRS,DPTR_XLBXSVS,DPTR_XLBYSVS                           )
+  !
+END IF
+!
+CALL SECOND_MNH2(ZTIME2)                                                  
+XT_1WAY = XT_1WAY + ZTIME2 - ZTIME1                                
+!
+!-------------------------------------------------------------------------------
+!
+!*       3.    LATERAL BOUNDARY CONDITIONS EXCEPT FOR NORMAL VELOCITY
+!              ------------------------------------------------------
+!
+ZTIME1=ZTIME2
+!
+!*       3.1   Set the lagragian variables values at the LB
+!
+IF( LLG .AND. IMI==1 ) CALL SETLB_LG
+!
+IF (CCONF == "START" .OR. (CCONF == "RESTA" .AND. KTCOUNT /= 1 )) THEN
+CALL BOUNDARIES (                                                   &
+            XTSTEP,CLBCX,CLBCY,NRR,NSV,KTCOUNT,                     &
+            XLBXUM,XLBXVM,XLBXWM,XLBXTHM,XLBXTKEM,XLBXRM,XLBXSVM,   &
+            XLBYUM,XLBYVM,XLBYWM,XLBYTHM,XLBYTKEM,XLBYRM,XLBYSVM,   &
+            XLBXUS,XLBXVS,XLBXWS,XLBXTHS,XLBXTKES,XLBXRS,XLBXSVS,   &
+            XLBYUS,XLBYVS,XLBYWS,XLBYTHS,XLBYTKES,XLBYRS,XLBYSVS,   &
+            XRHODJ,                                                 &
+            XUT, XVT, XWT, XTHT, XTKET, XRT, XSVT, XSRCT            )
+END IF
+!
+CALL SECOND_MNH2(ZTIME2)
+!
+XT_BOUND = XT_BOUND + ZTIME2 - ZTIME1
+!
+!-------------------------------------------------------------------------------
+!* initializes surface number
+IF (CSURF=='EXTE') CALL GOTO_SURFEX(IMI)
+!-------------------------------------------------------------------------------
+!
+!*       4.    STORAGE IN A SYNCHRONOUS FILE
+!              -----------------------------
+!
+ZTIME1 = ZTIME2
+!
+IF (IBAK < NBAK_NUMB ) THEN
+  IF (KTCOUNT == TBACKUPN(IBAK+1)%NSTEP) THEN
+    IBAK=IBAK+1
+    GCLOSE_OUT=.TRUE.
+    !
+    TZBAKFILE => TBACKUPN(IBAK)%TFILE
+    IVERB    = TZBAKFILE%NLFIVERB
+    !
+    CALL IO_File_open(TZBAKFILE)
+    !
+    CALL WRITE_DESFM_n(IMI,TZBAKFILE)
+    CALL IO_Header_write(TBACKUPN(IBAK)%TFILE)
+    CALL WRITE_LFIFM_n(TBACKUPN(IBAK)%TFILE,TBACKUPN(IBAK)%TFILE%TDADFILE%CNAME)
+    TOUTDATAFILE => TZBAKFILE
+    CALL MNHWRITE_ZS_DUMMY_n(TZBAKFILE)
+    IF (CSURF=='EXTE') THEN
+      TFILE_SURFEX => TZBAKFILE
+      CALL GOTO_SURFEX(IMI)
+      CALL WRITE_SURF_ATM_n(YSURF_CUR,'MESONH','ALL',.FALSE.)
+      NULLIFY(TFILE_SURFEX)
+    END IF
+    !
+    ! Reinitialize Lagragian variables at every model backup
+    IF (LLG .AND. LINIT_LG .AND. CINIT_LG=='FMOUT') THEN
+      CALL INI_LG(XXHAT,XYHAT,XZZ,XSVT,XLBXSVM,XLBYSVM)
+      IF (IVERB>=5) THEN
+        WRITE(UNIT=ILUOUT,FMT=*) '************************************'
+        WRITE(UNIT=ILUOUT,FMT=*) '*** Lagrangian variables refreshed after ',TRIM(TZBAKFILE%CNAME),' backup'
+        WRITE(UNIT=ILUOUT,FMT=*) '************************************'
+      END IF
+    END IF
+    ! Reinitialise mean variables
+    IF (LMEAN_FIELD) THEN
+       CALL INI_MEAN_FIELD
+    END IF
+!
+  ELSE
+    !Necessary to have a 'valid' CNAME when calling some subroutines
+    TZBAKFILE => TFILE_DUMMY
+  END IF
+ELSE
+  !Necessary to have a 'valid' CNAME when calling some subroutines
+  TZBAKFILE => TFILE_DUMMY
+END IF
+!
+IF (IOUT < NOUT_NUMB ) THEN
+  IF (KTCOUNT == TOUTPUTN(IOUT+1)%NSTEP) THEN
+    IOUT=IOUT+1
+    !
+    TZOUTFILE => TOUTPUTN(IOUT)%TFILE
+    !
+    CALL IO_File_open(TZOUTFILE)
+    !
+    CALL IO_Header_write(TZOUTFILE)
+    CALL IO_Fieldlist_write(TOUTPUTN(IOUT))
+    CALL IO_Field_user_write(TOUTPUTN(IOUT))
+    !
+    CALL IO_File_close(TZOUTFILE)
+    !
+  END IF
+END IF
+!
+CALL SECOND_MNH2(ZTIME2)
+!
+XT_STORE = XT_STORE + ZTIME2 - ZTIME1
+!
+!-------------------------------------------------------------------------------
+!
+!*       5.    INITIALIZATION OF THE BUDGET VARIABLES
+!              --------------------------------------
+!
+IF (NBUMOD==IMI) THEN
+  LBU_ENABLE = CBUTYPE /='NONE'.AND. CBUTYPE /='SKIP' 
+ELSE
+  LBU_ENABLE = .FALSE.
+END IF
+!
+IF (NBUMOD==IMI .AND. CBUTYPE=='MASK' ) THEN
+  CALL SET_MASK
+  IF (LBU_RU)   XBURHODJU(:,NBUTIME,:) = XBURHODJU(:,NBUTIME,:)    &
+                            + MASK_COMPRESS(MXM(XRHODJ))
+  IF (LBU_RV)   XBURHODJV(:,NBUTIME,:) = XBURHODJV(:,NBUTIME,:)    &
+                            + MASK_COMPRESS(MYM(XRHODJ))
+  IF (LBU_RW)   XBURHODJW(:,NBUTIME,:) = XBURHODJW(:,NBUTIME,:)    &
+                            + MASK_COMPRESS(MZM(XRHODJ))
+  IF (ALLOCATED(XBURHODJ))                                         &
+                XBURHODJ (:,NBUTIME,:) = XBURHODJ (:,NBUTIME,:)    &
+                              + MASK_COMPRESS(XRHODJ)
+END IF
+!
+IF (NBUMOD==IMI .AND. CBUTYPE=='CART' ) THEN
+  IF (LBU_RU)   XBURHODJU(:,:,:) = XBURHODJU(:,:,:)    &
+                + CART_COMPRESS(MXM(XRHODJ))
+  IF (LBU_RV)   XBURHODJV(:,:,:) = XBURHODJV(:,:,:)    &
+                + CART_COMPRESS(MYM(XRHODJ))
+  IF (LBU_RW)   XBURHODJW(:,:,:) = XBURHODJW(:,:,:)    &
+                + CART_COMPRESS(MZM(XRHODJ))
+  IF (ALLOCATED(XBURHODJ))                             &
+                XBURHODJ (:,:,:) = XBURHODJ (:,:,:)    &
+                + CART_COMPRESS(XRHODJ)
+END IF
+!
+CALL BUDGET_FLAGS(LUSERV, LUSERC, LUSERR,         &
+                  LUSERI, LUSERS, LUSERG, LUSERH  )
+!
+XTIME_BU   = 0.0
+!
+!-------------------------------------------------------------------------------
+!
+!*       6.    INITIALIZATION OF THE FIELD TENDENCIES
+!              --------------------------------------
+!
+ZTIME1 = ZTIME2
+XTIME_BU_PROCESS = 0.
+!
+CALL INITIAL_GUESS ( NRR, NSV, KTCOUNT, XRHODJ,IMI, XTSTEP,                 &
+                     XRUS, XRVS, XRWS, XRTHS, XRRS, XRTKES, XRSVS,          &
+                     XUT, XVT, XWT, XTHT, XRT, XTKET, XSVT )
+!
+CALL SECOND_MNH2(ZTIME2)
+!
+XT_GUESS = XT_GUESS + ZTIME2 - ZTIME1 - XTIME_BU_PROCESS
+!
+!-------------------------------------------------------------------------------
+!
+!*       7.    INITIALIZATION OF THE LES FOR CURRENT TIME-STEP
+!              -----------------------------------------------
+!
+XTIME_LES_BU   = 0.0
+XTIME_LES      = 0.0
+IF (LLES) CALL LES_INI_TIMESTEP_n(KTCOUNT)
+!
+!-------------------------------------------------------------------------------
+!
+!*       8.    TWO-WAY INTERACTIVE GRID-NESTING
+!              --------------------------------
+!
+!
+CALL SECOND_MNH2(ZTIME1)
+XTIME_BU_PROCESS = 0.
+XTIME_LES_BU_PROCESS = 0.
+!
+GMASKkids(:,:)=.FALSE.
+!
+IF (NMODEL>1) THEN
+  ! correct an ifort bug
+  DPTR_XRHODJ=>XRHODJ
+  DPTR_XUM=>XUT
+  DPTR_XVM=>XVT
+  DPTR_XWM=>XWT
+  DPTR_XTHM=>XTHT
+  DPTR_XRM=>XRT
+  DPTR_XTKEM=>XTKET
+  DPTR_XSVM=>XSVT
+  DPTR_XRUS=>XRUS
+  DPTR_XRVS=>XRVS
+  DPTR_XRWS=>XRWS
+  DPTR_XRTHS=>XRTHS
+  DPTR_XRRS=>XRRS
+  DPTR_XRTKES=>XRTKES
+  DPTR_XRSVS=>XRSVS
+  DPTR_XINPRC=>XINPRC
+  DPTR_XINPRR=>XINPRR
+  DPTR_XINPRS=>XINPRS
+  DPTR_XINPRG=>XINPRG
+  DPTR_XINPRH=>XINPRH
+  DPTR_XPRCONV=>XPRCONV
+  DPTR_XPRSCONV=>XPRSCONV
+  DPTR_XDIRFLASWD=>XDIRFLASWD
+  DPTR_XSCAFLASWD=>XSCAFLASWD
+  DPTR_XDIRSRFSWD=>XDIRSRFSWD
+  DPTR_GMASKkids=>GMASKkids
+  !
+  CALL TWO_WAY(     NRR,NSV,KTCOUNT,DPTR_XRHODJ,IMI,XTSTEP,                                    &
+       DPTR_XUM ,DPTR_XVM ,DPTR_XWM , DPTR_XTHM, DPTR_XRM,DPTR_XSVM,                           &
+       DPTR_XRUS,DPTR_XRVS,DPTR_XRWS,DPTR_XRTHS,DPTR_XRRS,DPTR_XRSVS,                          &
+       DPTR_XINPRC,DPTR_XINPRR,DPTR_XINPRS,DPTR_XINPRG,DPTR_XINPRH,DPTR_XPRCONV,DPTR_XPRSCONV, &
+       DPTR_XDIRFLASWD,DPTR_XSCAFLASWD,DPTR_XDIRSRFSWD,DPTR_GMASKkids           )
+END IF
+!
+CALL SECOND_MNH2(ZTIME2)
+XT_2WAY = XT_2WAY + ZTIME2 - ZTIME1 - XTIME_LES_BU_PROCESS - XTIME_BU_PROCESS
+!
+!-------------------------------------------------------------------------------
+!-------------------------------------------------------------------------------
+!
+!*       10.    FORCING
+!               -------
+!
+!
+ZTIME1 = ZTIME2
+XTIME_BU_PROCESS = 0.
+XTIME_LES_BU_PROCESS = 0.
+IF (LCARTESIAN) THEN
+  CALL SM_GRIDCART(XXHAT,XYHAT,XZHAT,XZS,LSLEVE,XLEN1,XLEN2,XZSMT,XDXHAT,XDYHAT,XZZ,ZJ)
+  XMAP=1.
+ELSE
+  CALL SM_GRIDPROJ(XXHAT,XYHAT,XZHAT,XZS,LSLEVE,XLEN1,XLEN2,XZSMT,XLATORI,XLONORI, &
+                   XMAP,XLAT,XLON,XDXHAT,XDYHAT,XZZ,ZJ)
+END IF
+!
+IF ( LFORCING ) THEN
+  CALL FORCING(XTSTEP,LUSERV,XRHODJ,XCORIOZ,XZHAT,XZZ,TDTCUR,&
+               XUFRC_PAST, XVFRC_PAST,                &
+               XUT,XVT,XWT,XTHT,XTKET,XRT,XSVT,       &
+               XRUS,XRVS,XRWS,XRTHS,XRTKES,XRRS,XRSVS,IMI,ZJ)
+END IF
+!
+IF ( L2D_ADV_FRC ) THEN 
+  CALL ADV_FORCING_n(XRHODJ,TDTCUR,XTHT,XRT,XZZ,XRTHS,XRRS)
+END IF
+IF ( L2D_REL_FRC ) THEN 
+  CALL REL_FORCING_n(XRHODJ,TDTCUR,XTHT,XRT,XZZ,XRTHS,XRRS)
+END IF
+!
+CALL SECOND_MNH2(ZTIME2)
+!
+XT_FORCING = XT_FORCING + ZTIME2 - ZTIME1 &
+             - XTIME_LES_BU_PROCESS - XTIME_BU_PROCESS
+!
+!-------------------------------------------------------------------------------
+!
+!*       11.    NUDGING
+!               -------
+!
+!
+ZTIME1 = ZTIME2
+XTIME_BU_PROCESS = 0.
+XTIME_LES_BU_PROCESS = 0.
+!
+IF ( LNUDGING ) THEN
+  CALL NUDGING(LUSERV,XRHODJ,XTNUDGING,         &
+               XUT,XVT,XWT,XTHT,XRT,            &
+               XLSUM,XLSVM,XLSWM,XLSTHM,XLSRVM, &
+               XRUS,XRVS,XRWS,XRTHS,XRRS)
+
+END IF
+!
+CALL SECOND_MNH2(ZTIME2)
+!
+XT_NUDGING = XT_NUDGING + ZTIME2 - ZTIME1 &
+             - XTIME_LES_BU_PROCESS - XTIME_BU_PROCESS
+!
+!-------------------------------------------------------------------------------
+!
+!*       12.    DYNAMICAL SOURCES
+!               -----------------
+!
+ZTIME1 = ZTIME2
+XTIME_BU_PROCESS = 0.
+XTIME_LES_BU_PROCESS = 0.
+!
+IF( LTRANS ) THEN
+  XUT(:,:,:) = XUT(:,:,:) + XUTRANS
+  XVT(:,:,:) = XVT(:,:,:) + XVTRANS
+END IF
+!
+CALL DYN_SOURCES( NRR,NRRL, NRRI,                              &
+                  XUT, XVT, XWT, XTHT, XRT,                    &
+                  XCORIOX, XCORIOY, XCORIOZ, XCURVX, XCURVY,   &
+                  XRHODJ, XZZ, XTHVREF, XEXNREF,               &
+                  XRUS, XRVS, XRWS, XRTHS                      )
+!
+IF( LTRANS ) THEN
+  XUT(:,:,:) = XUT(:,:,:) - XUTRANS
+  XVT(:,:,:) = XVT(:,:,:) - XVTRANS
+END IF
+!
+CALL SECOND_MNH2(ZTIME2)
+!
+XT_SOURCES = XT_SOURCES + ZTIME2 - ZTIME1 &
+             - XTIME_LES_BU_PROCESS - XTIME_BU_PROCESS
+!
+!-------------------------------------------------------------------------------
+!
+!*       13.    NUMERICAL DIFFUSION
+!               -------------------
+!
+ZTIME1 = ZTIME2
+XTIME_BU_PROCESS = 0.
+XTIME_LES_BU_PROCESS = 0.
+!
+IF ( LNUMDIFU .OR. LNUMDIFTH .OR. LNUMDIFSV ) THEN
+!
+  CALL UPDATE_HALO_ll(TFIELDT_ll, IINFO_ll)
+  CALL UPDATE_HALO2_ll(TFIELDT_ll, THALO2T_ll, IINFO_ll)
+  IF ( .NOT. LSTEADYLS ) THEN
+     CALL UPDATE_HALO_ll(TLSFIELD_ll, IINFO_ll)
+     CALL UPDATE_HALO_ll(TLSFIELD2D_ll,IINFO_ll) 
+     CALL UPDATE_HALO2_ll(TLSFIELD_ll, TLSHALO2_ll, IINFO_ll)
+  END IF
+  CALL NUM_DIFF ( CLBCX, CLBCY, NRR, NSV,                               &
+                  XDK2U, XDK4U, XDK2TH, XDK4TH, XDK2SV, XDK4SV, IMI,    &
+                  XUT, XVT, XWT, XTHT, XTKET, XRT, XSVT,                &
+                  XLSUM,XLSVM,XLSWM,XLSTHM,XLSRVM,XRHODJ,               &
+                  XRUS, XRVS, XRWS, XRTHS, XRTKES, XRRS, XRSVS,         &
+                  LZDIFFU,LNUMDIFU, LNUMDIFTH, LNUMDIFSV,               &
+                  THALO2T_ll, TLSHALO2_ll,XZDIFFU_HALO2      )
+END IF
+!
+DO JSV = NSV_CHEMBEG,NSV_CHEMEND
+  XRSVS(:,:,:,JSV) = MAX(XRSVS(:,:,:,JSV),0.)
+END DO
+DO JSV = NSV_CHICBEG,NSV_CHICEND
+  XRSVS(:,:,:,JSV) = MAX(XRSVS(:,:,:,JSV),0.)
+END DO
+DO JSV = NSV_AERBEG,NSV_AEREND
+  XRSVS(:,:,:,JSV) = MAX(XRSVS(:,:,:,JSV),0.)
+END DO
+DO JSV = NSV_LNOXBEG,NSV_LNOXEND
+  XRSVS(:,:,:,JSV) = MAX(XRSVS(:,:,:,JSV),0.)
+END DO
+DO JSV = NSV_DSTBEG,NSV_DSTEND
+  XRSVS(:,:,:,JSV) = MAX(XRSVS(:,:,:,JSV),0.)
+END DO
+DO JSV = NSV_SLTBEG,NSV_SLTEND
+  XRSVS(:,:,:,JSV) = MAX(XRSVS(:,:,:,JSV),0.)
+END DO
+DO JSV = NSV_PPBEG,NSV_PPEND
+  XRSVS(:,:,:,JSV) = MAX(XRSVS(:,:,:,JSV),0.)
+END DO
+#ifdef MNH_FOREFIRE
+DO JSV = NSV_FFBEG,NSV_FFEND
+  XRSVS(:,:,:,JSV) = MAX(XRSVS(:,:,:,JSV),0.)
+END DO
+#endif
+DO JSV = NSV_CSBEG,NSV_CSEND
+  XRSVS(:,:,:,JSV) = MAX(XRSVS(:,:,:,JSV),0.)
+END DO
+DO JSV = NSV_DSTDEPBEG,NSV_DSTDEPEND
+  XRSVS(:,:,:,JSV) = MAX(XRSVS(:,:,:,JSV),0.)
+END DO
+DO JSV = NSV_SLTDEPBEG,NSV_SLTDEPEND
+  XRSVS(:,:,:,JSV) = MAX(XRSVS(:,:,:,JSV),0.)
+END DO
+DO JSV = NSV_AERDEPBEG,NSV_AERDEPEND
+  XRSVS(:,:,:,JSV) = MAX(XRSVS(:,:,:,JSV),0.)
+END DO
+DO JSV = NSV_SNWBEG,NSV_SNWEND
+  XRSVS(:,:,:,JSV) = MAX(XRSVS(:,:,:,JSV),0.)
+END DO
+IF (CELEC .NE. 'NONE') THEN
+  XRSVS(:,:,:,NSV_ELECBEG) = MAX(XRSVS(:,:,:,NSV_ELECBEG),0.)
+  XRSVS(:,:,:,NSV_ELECEND) = MAX(XRSVS(:,:,:,NSV_ELECEND),0.)
+END IF
+!
+CALL SECOND_MNH2(ZTIME2)
+!
+XT_DIFF = XT_DIFF + ZTIME2 - ZTIME1 &
+          - XTIME_LES_BU_PROCESS - XTIME_BU_PROCESS
+!
+!-------------------------------------------------------------------------------
+!
+!*       14.    UPPER AND LATERAL RELAXATION
+!               ----------------------------
+!
+ZTIME1 = ZTIME2
+XTIME_BU_PROCESS = 0.
+XTIME_LES_BU_PROCESS = 0.
+!
+IF(LVE_RELAX .OR. LVE_RELAX_GRD .OR. LHORELAX_UVWTH .OR. LHORELAX_RV .OR.&
+   LHORELAX_RC .OR. LHORELAX_RR .OR. LHORELAX_RI .OR. LHORELAX_RS .OR.   &
+   LHORELAX_RG .OR. LHORELAX_RH .OR. LHORELAX_TKE .OR.                   &
+   ANY(LHORELAX_SV)) THEN
+  CALL RELAXATION (LVE_RELAX,LVE_RELAX_GRD,LHORELAX_UVWTH,LHORELAX_RV,LHORELAX_RC,   &
+                   LHORELAX_RR,LHORELAX_RI,LHORELAX_RS,LHORELAX_RG,    &
+                   LHORELAX_RH,LHORELAX_TKE,LHORELAX_SV,               &
+                   LHORELAX_SVC2R2,LHORELAX_SVC1R3,                    &
+                   LHORELAX_SVELEC,LHORELAX_SVLG,                      &
+                   LHORELAX_SVCHEM,LHORELAX_SVCHIC,LHORELAX_SVAER,     &
+                   LHORELAX_SVDST,LHORELAX_SVSLT,LHORELAX_SVPP,        &
+                   LHORELAX_SVCS,LHORELAX_SVSNW,                       &
+#ifdef MNH_FOREFIRE
+                   LHORELAX_SVFF,                                      &
+#endif
+                   KTCOUNT,NRR,NSV,XTSTEP,XRHODJ,                      &
+                   XUT, XVT, XWT, XTHT, XRT, XSVT, XTKET,              &
+                   XLSUM, XLSVM, XLSWM, XLSTHM,                        &
+                   XLBXUM, XLBXVM, XLBXWM, XLBXTHM,                    &
+                   XLBXRM, XLBXSVM, XLBXTKEM,                          &
+                   XLBYUM, XLBYVM, XLBYWM, XLBYTHM,                    &
+                   XLBYRM, XLBYSVM, XLBYTKEM,                          &
+                   NALBOT, XALK, XALKW,                                &
+                   NALBAS, XALKBAS, XALKWBAS,                          &
+                   LMASK_RELAX,XKURELAX, XKVRELAX, XKWRELAX,           &
+                   NRIMX,NRIMY,                                        &
+                   XRUS, XRVS, XRWS, XRTHS, XRRS, XRSVS, XRTKES        )
+END IF
+
+IF (CELEC.NE.'NONE' .AND. LRELAX2FW_ION) THEN
+   CALL RELAX2FW_ION (KTCOUNT, IMI, XTSTEP, XRHODJ, XSVT, NALBOT,      &
+                      XALK, LMASK_RELAX, XKWRELAX, XRSVS )   
+END IF                      
+!
+CALL SECOND_MNH2(ZTIME2)
+!
+XT_RELAX = XT_RELAX + ZTIME2 - ZTIME1 &
+           - XTIME_LES_BU_PROCESS - XTIME_BU_PROCESS
+!
+!-------------------------------------------------------------------------------
+!
+!*       15.    PARAMETRIZATIONS' MONITOR
+!               -------------------------
+!
+ZTIME1 = ZTIME2
+!
+CALL PHYS_PARAM_n(KTCOUNT,TZBAKFILE, GCLOSE_OUT,                &
+                  XT_RAD,XT_SHADOWS,XT_DCONV,XT_GROUND,XT_MAFL, &
+                  XT_DRAG,XT_TURB,XT_TRACER,                    &
+                  ZTIME,ZWETDEPAER,GMASKkids,GCLOUD_ONLY)
+!
+IF (CDCONV/='NONE') THEN
+  XPACCONV = XPACCONV + XPRCONV * XTSTEP
+  IF (LCH_CONV_LINOX) THEN
+    XIC_TOTAL_NUMBER = XIC_TOTAL_NUMBER + XIC_RATE * XTSTEP
+    XCG_TOTAL_NUMBER = XCG_TOTAL_NUMBER + XCG_RATE * XTSTEP
+  END IF
+END IF
+!
+IF (IBAK>0 .AND. IBAK <= NBAK_NUMB ) THEN
+  IF (KTCOUNT == TBACKUPN(IBAK)%NSTEP) THEN
+    IF (CSURF=='EXTE') THEN
+      CALL GOTO_SURFEX(IMI)
+      CALL DIAG_SURF_ATM_n(YSURF_CUR,'MESONH')
+      TFILE_SURFEX => TZBAKFILE
+      CALL WRITE_DIAG_SURF_ATM_n(YSURF_CUR,'MESONH','ALL')
+      NULLIFY(TFILE_SURFEX)
+    END IF
+  END IF
+END IF
+!
+CALL SECOND_MNH2(ZTIME2)
+!
+XT_PARAM = XT_PARAM + ZTIME2 - ZTIME1 - XTIME_LES - ZTIME
+!
+!-------------------------------------------------------------------------------
+!
+!*       16.    TEMPORAL SERIES
+!               ---------------
+!
+ZTIME1 = ZTIME2
+!
+IF (LSERIES) THEN
+  IF ( MOD (KTCOUNT-1,NFREQSERIES) == 0 ) CALL SERIES_n
+END IF
+!
+CALL SECOND_MNH2(ZTIME2)
+!
+XT_STEP_MISC = XT_STEP_MISC + ZTIME2 - ZTIME1
+!
+!-------------------------------------------------------------------------------
+!
+!*       17.    LARGE SCALE FIELD REFRESH
+!               -------------------------
+!
+ZTIME1 = ZTIME2
+!
+IF (.NOT. LSTEADYLS) THEN
+  IF (  IMI==1                             .AND.      &
+    NCPL_CUR < NCPL_NBR                              ) THEN
+    IF (KTCOUNT+1 == NCPL_TIMES(NCPL_CUR,1)          ) THEN
+                                  ! The next current time reachs a
+      NCPL_CUR=NCPL_CUR+1         ! coupling one, LS sources are refreshed
+      !
+      CALL LS_COUPLING(XTSTEP,GSTEADY_DMASS,CCONF,                          &
+             CGETTKET,                                                      &
+             CGETRVT,CGETRCT,CGETRRT,CGETRIT,                               &
+             CGETRST,CGETRGT,CGETRHT,CGETSVT,LCH_INIT_FIELD, NSV,           &
+             NIMAX_ll,NJMAX_ll,                                             &
+             NSIZELBX_ll,NSIZELBXU_ll,NSIZELBY_ll,NSIZELBYV_ll,             &
+             NSIZELBXTKE_ll,NSIZELBYTKE_ll,                                 &
+             NSIZELBXR_ll,NSIZELBYR_ll,NSIZELBXSV_ll,NSIZELBYSV_ll,         &
+             XLSUM,XLSVM,XLSWM,XLSTHM,XLSRVM,XLSZWSM,XDRYMASST,             &
+             XLBXUM,XLBXVM,XLBXWM,XLBXTHM,XLBXTKEM,XLBXRM,XLBXSVM,          &
+             XLBYUM,XLBYVM,XLBYWM,XLBYTHM,XLBYTKEM,XLBYRM,XLBYSVM,          &
+             XLSUS,XLSVS,XLSWS,XLSTHS,XLSRVS,XLSZWSS,XDRYMASSS,             &
+             XLBXUS,XLBXVS,XLBXWS,XLBXTHS,XLBXTKES,XLBXRS,XLBXSVS,          &
+             XLBYUS,XLBYVS,XLBYWS,XLBYTHS,XLBYTKES,XLBYRS,XLBYSVS           )
+      !
+      DO JSV=NSV_CHEMBEG,NSV_CHEMEND
+        XLBXSVS(:,:,:,JSV)=MAX(XLBXSVS(:,:,:,JSV),0.)
+        XLBYSVS(:,:,:,JSV)=MAX(XLBYSVS(:,:,:,JSV),0.)
+      ENDDO
+      !
+      DO JSV=NSV_LNOXBEG,NSV_LNOXEND
+        XLBXSVS(:,:,:,JSV)=MAX(XLBXSVS(:,:,:,JSV),0.)
+        XLBYSVS(:,:,:,JSV)=MAX(XLBYSVS(:,:,:,JSV),0.)
+      ENDDO
+      !
+      DO JSV=NSV_AERBEG,NSV_AEREND
+        XLBXSVS(:,:,:,JSV)=MAX(XLBXSVS(:,:,:,JSV),0.)
+        XLBYSVS(:,:,:,JSV)=MAX(XLBYSVS(:,:,:,JSV),0.)
+      ENDDO
+      !
+      DO JSV=NSV_DSTBEG,NSV_DSTEND
+        XLBXSVS(:,:,:,JSV)=MAX(XLBXSVS(:,:,:,JSV),0.)
+        XLBYSVS(:,:,:,JSV)=MAX(XLBYSVS(:,:,:,JSV),0.)
+      ENDDO
+      !
+      DO JSV=NSV_DSTDEPBEG,NSV_DSTDEPEND
+        XLBXSVS(:,:,:,JSV)=MAX(XLBXSVS(:,:,:,JSV),0.)
+        XLBYSVS(:,:,:,JSV)=MAX(XLBYSVS(:,:,:,JSV),0.)
+      ENDDO
+      !
+      DO JSV=NSV_SLTBEG,NSV_SLTEND
+        XLBXSVS(:,:,:,JSV)=MAX(XLBXSVS(:,:,:,JSV),0.)
+        XLBYSVS(:,:,:,JSV)=MAX(XLBYSVS(:,:,:,JSV),0.)
+      ENDDO
+      !
+      DO JSV=NSV_SLTDEPBEG,NSV_SLTDEPEND
+        XLBXSVS(:,:,:,JSV)=MAX(XLBXSVS(:,:,:,JSV),0.)
+        XLBYSVS(:,:,:,JSV)=MAX(XLBYSVS(:,:,:,JSV),0.)
+      ENDDO
+      !
+      DO JSV=NSV_PPBEG,NSV_PPEND
+        XLBXSVS(:,:,:,JSV)=MAX(XLBXSVS(:,:,:,JSV),0.)
+        XLBYSVS(:,:,:,JSV)=MAX(XLBYSVS(:,:,:,JSV),0.)
+      ENDDO
+      !
+#ifdef MNH_FOREFIRE
+      DO JSV=NSV_FFBEG,NSV_FFEND
+        XLBXSVS(:,:,:,JSV)=MAX(XLBXSVS(:,:,:,JSV),0.)
+        XLBYSVS(:,:,:,JSV)=MAX(XLBYSVS(:,:,:,JSV),0.)
+      ENDDO
+      !
+#endif
+      DO JSV=NSV_CSBEG,NSV_CSEND
+        XLBXSVS(:,:,:,JSV)=MAX(XLBXSVS(:,:,:,JSV),0.)
+        XLBYSVS(:,:,:,JSV)=MAX(XLBYSVS(:,:,:,JSV),0.)
+      ENDDO
+      !
+      DO JSV=NSV_SNWBEG,NSV_SNWEND
+        XLBXSVS(:,:,:,JSV)=MAX(XLBXSVS(:,:,:,JSV),0.)
+        XLBYSVS(:,:,:,JSV)=MAX(XLBYSVS(:,:,:,JSV),0.)
+      ENDDO
+      !
+     END IF
+  END IF
+END IF
+!
+CALL SECOND_MNH2(ZTIME2)
+!
+XT_COUPL = XT_COUPL + ZTIME2 - ZTIME1
+!
+!-------------------------------------------------------------------------------
+!
+!
+!
+!*      8 Bis . Blowing snow scheme
+!              ---------
+!
+IF(LBLOWSNOW) THEN
+ CALL BLOWSNOW(CLBCX,CLBCY,XTSTEP,NRR,XPABST,XTHT,XRT,XZZ,XRHODREF,  &
+                     XRHODJ,XEXNREF,XRRS,XRTHS,XSVT,XRSVS,XSNWSUBL3D )
+ENDIF
+!
+!-----------------------------------------------------------------------
+!
+!*       8 Ter  VISCOSITY (no-slip condition inside)
+!              ---------
+!
+!
+IF ( LVISC ) THEN
+!
+ZTIME1 = ZTIME2
+!
+   CALL VISCOSITY(CLBCX, CLBCY, NRR, NSV, XMU_V,XPRANDTL,         &
+                  LVISC_UVW,LVISC_TH,LVISC_SV,LVISC_R,            &
+                  LDRAG,    &
+                  XUT, XVT, XWT, XTHT, XRT, XSVT,                 &
+                  XRHODJ, XDXX, XDYY, XDZZ, XDZX, XDZY,           &
+                  XRUS, XRVS, XRWS, XRTHS, XRRS, XRSVS,XDRAG )
+!
+ENDIF
+!
+CALL SECOND_MNH2(ZTIME2)
+!
+XT_VISC = XT_VISC + ZTIME2 - ZTIME1
+!!
+!-------------------------------------------------------------------------------
+!
+!*       9.    ADVECTION
+!              ---------
+!
+ZTIME1 = ZTIME2
+XTIME_BU_PROCESS = 0.
+XTIME_LES_BU_PROCESS = 0.
+!
+!$acc update device(XRTHS)
+!
+!$acc data create (XUT, XVT, XWT)                                         &
+!$acc &    copyin (XTHT, XPABST, XRT, XSVT, XRTHS_CLD, XRRS_CLD, XTHVREF) &
+!$acc &    copy   (XRRS, XRUS, XRVS, XRWS)                         &
+!$acc &    copy   (XRWS_PRES)                                             & !XRWS_PRES copy and not copyout (hidden in UPDATE_HALO)
+!$acc &    present(XDXX, XDYY, XDZZ, XDZX, XDZY, XRHODJ)
+!
+!$acc update device(XUT, XVT, XWT, XRHODJ)
+
+!
+!
+!$acc data copyin (XTKET, XRSVS_CLD) &
+!$acc &    copy   (XRTKES, XRSVS)    &
+!$acc &    copyout(XRTKEMS)
+CALL ADVECTION_METSV ( TZBAKFILE, GCLOSE_OUT,CUVW_ADV_SCHEME,          &
+                 CMET_ADV_SCHEME, CSV_ADV_SCHEME, CCLOUD, NSPLIT,      &
+                 LSPLIT_CFL, XSPLIT_CFL, LCFL_WRIT,                    &
+                 CLBCX, CLBCY, NRR, NSV, TDTCUR, XTSTEP,               &
+                 XUT, XVT, XWT, XTHT, XRT, XTKET, XSVT, XPABST,        &
+                 XTHVREF, XRHODJ, XDXX, XDYY, XDZZ, XDZX, XDZY,        &
+                 XRTHS, XRRS, XRTKES, XRSVS,                           &
+                 XRTHS_CLD, XRRS_CLD, XRSVS_CLD, XRTKEMS               )
+!$acc end data
+!
+!$acc update host(XRTHS)
+!
+CALL SECOND_MNH2(ZTIME2)
+!
+XT_ADV = XT_ADV + ZTIME2 - ZTIME1 - XTIME_LES_BU_PROCESS - XTIME_BU_PROCESS
+!
+!-------------------------------------------------------------------------------
+ZTIME1 = ZTIME2
+XTIME_BU_PROCESS = 0.
+XTIME_LES_BU_PROCESS = 0.
+!
+!$acc kernels
+ZRWS(:,:,:) = XRWS(:,:,:)
+!$acc end kernels
+!
+CALL GRAVITY_IMPL ( CLBCX, CLBCY, NRR, NRRL, NRRI,XTSTEP,            &
+                 XTHT, XRT, XTHVREF, XRHODJ, XRWS, XRTHS, XRRS,      &
+                 XRTHS_CLD, XRRS_CLD                                 )
+!
+! At the initial instant the difference with the ref state creates a 
+! vertical velocity production that must not be advected as it is 
+! compensated by the pressure gradient
+!
+IF (KTCOUNT == 1 .AND. CCONF=='START') THEN
+!$acc kernels
+  XRWS_PRES(:,:,:) = ZRWS(:,:,:) - XRWS(:,:,:)
+!$acc end kernels
+END IF
+!
+CALL SECOND_MNH2(ZTIME2)
+!
+XT_GRAV = XT_GRAV + ZTIME2 - ZTIME1 - XTIME_LES_BU_PROCESS - XTIME_BU_PROCESS
+! 
+ZTIME1 = ZTIME2
+XTIME_BU_PROCESS = 0.
+XTIME_LES_BU_PROCESS = 0.
+!
+IF ((CUVW_ADV_SCHEME(1:3)=='CEN') .AND. (CTEMP_SCHEME == 'LEFR')) THEN
+  IF (CUVW_ADV_SCHEME=='CEN4TH') THEN
+    NULLIFY(TZFIELDC_ll)
+    NULLIFY(TZHALO2C_ll)
+      CALL ADD3DFIELD_ll( TZFIELDC_ll, XUT, 'MODEL_n::XUT' )
+      CALL ADD3DFIELD_ll( TZFIELDC_ll, XVT, 'MODEL_n::XVT' )
+      CALL ADD3DFIELD_ll( TZFIELDC_ll, XWT, 'MODEL_n::XWT' )
+      CALL INIT_HALO2_ll(TZHALO2C_ll,3,IIU,IJU,IKU)
+      CALL UPDATE_HALO_ll(TZFIELDC_ll,IINFO_ll)
+      CALL UPDATE_HALO2_ll(TZFIELDC_ll, TZHALO2C_ll, IINFO_ll)
+!$acc update device(XUT, XVT, XWT)
+  END IF
+!$acc data copyin(XUM, XVM, XWM)    &
+!$acc &    copy  (XDUM, XDVM, XDWM)
+ CALL ADVECTION_UVW_CEN(CUVW_ADV_SCHEME,                           &
+                           CLBCX, CLBCY,                           &
+                           XTSTEP, KTCOUNT,                        &
+                           XUM, XVM, XWM, XDUM, XDVM, XDWM,        &
+                           XUT, XVT, XWT,                          &
+                           XRHODJ, XDXX, XDYY, XDZZ, XDZX, XDZY,   &
+                           XRUS,XRVS, XRWS,                        &
+                           TZHALO2C_ll                             )
+!$acc end data
+  IF (CUVW_ADV_SCHEME=='CEN4TH') THEN
+    CALL CLEANLIST_ll(TZFIELDC_ll)
+    NULLIFY(TZFIELDC_ll)
+    CALL  DEL_HALO2_ll(TZHALO2C_ll)
+    NULLIFY(TZHALO2C_ll)
+  END IF
+ELSE
+
+!$acc data copyin(XRUS_PRES, XRVS_PRES)
+  CALL ADVECTION_UVW(CUVW_ADV_SCHEME, CTEMP_SCHEME,                  &
+                 NWENO_ORDER, LSPLIT_WENO,                           &
+                 CLBCX, CLBCY, XTSTEP,                               &
+                 XUT, XVT, XWT,                                      &
+                 XRHODJ, XDXX, XDYY, XDZZ, XDZX, XDZY,               &
+                 XRUS, XRVS, XRWS,                                   &
+                 XRUS_PRES, XRVS_PRES, XRWS_PRES                     )
+!$acc end data
+END IF
+!
+!$acc end data
+!
+CALL SECOND_MNH2(ZTIME2)
+!
+XT_ADVUVW = XT_ADVUVW + ZTIME2 - ZTIME1 - XTIME_LES_BU_PROCESS - XTIME_BU_PROCESS
+!
+!-------------------------------------------------------------------------------
+!
+IF (NMODEL_CLOUD==IMI .AND. CTURBLEN_CLOUD/='NONE') THEN
+  CALL TURB_CLOUD_INDEX(XTSTEP,TZBAKFILE,                         &
+                        LTURB_DIAG,GCLOSE_OUT,NRRI,               &
+                        XRRS,XRT,XRHODJ,XDXX,XDYY,XDZZ,XDZX,XDZY, &
+                        XCEI )
+END IF
+!
+!-------------------------------------------------------------------------------
+!
+!*       18.    LATERAL BOUNDARY CONDITION FOR THE NORMAL VELOCITY
+!               --------------------------------------------------
+!
+ZTIME1 = ZTIME2
+!
+ZRUS=XRUS
+ZRVS=XRVS
+ZRWS=XRWS
+!
+  CALL RAD_BOUND (CLBCX,CLBCY,CTURB,XCARPKMAX,           &
+                XTSTEP,                                  &
+                XDXHAT, XDYHAT, XZHAT,                   &
+                XUT, XVT,                                &
+                XLBXUM, XLBYVM, XLBXUS, XLBYVS,          &
+                XCPHASE, XCPHASE_PBL, XRHODJ,            &
+                XTKET,XRUS, XRVS, XRWS                   )
+ZRUS=XRUS-ZRUS
+ZRVS=XRVS-ZRVS
+ZRWS=XRWS-ZRWS
+!
+CALL SECOND_MNH2(ZTIME2)
+!
+XT_RAD_BOUND = XT_RAD_BOUND + ZTIME2 - ZTIME1
+!
+!-------------------------------------------------------------------------------
+!
+!*       19.    PRESSURE COMPUTATION
+!               --------------------
+!
+ZTIME1 = ZTIME2
+XTIME_BU_PROCESS = 0.
+XTIME_LES_BU_PROCESS = 0.
+!
+ZPABST = XPABST
+!
+IF(.NOT. L1D) THEN
+!
+  XRUS_PRES = XRUS
+  XRVS_PRES = XRVS
+  XRWS_PRES = XRWS
+!
+  CALL PRESSUREZ( CLBCX,CLBCY,CPRESOPT,NITR,LITRADJ,KTCOUNT, XRELAX,IMI, &
+                  XRHODJ,XDXX,XDYY,XDZZ,XDZX,XDZY,XDXHATM,XDYHATM,XRHOM, &
+                  XAF,XBFY,XCF,XTRIGSX,XTRIGSY,NIFAXX,NIFAXY,            &
+                  NRR,NRRL,NRRI,XDRYMASST,XREFMASS,XMASS_O_PHI0,         &
+                  XTHT,XRT,XRHODREF,XTHVREF,XRVREF,XEXNREF, XLINMASS,    &
+                  XRUS, XRVS, XRWS, XPABST,                              &
+                  XBFB,                                                  &
+                  XBF_SXP2_YP1_Z,                                        &
+                  XAF_ZS,XBF_ZS,XCF_ZS,                                  &
+                  XDXATH_ZS,XDYATH_ZS,XRHO_ZS,                           &
+                  XA_K,XB_K,XC_K,XD_K) !JUAN FULL ZSOLVER
+!
+  XRUS_PRES = XRUS - XRUS_PRES + ZRUS
+  XRVS_PRES = XRVS - XRVS_PRES + ZRVS
+  XRWS_PRES = XRWS - XRWS_PRES + ZRWS
+!
+END IF
+!
+CALL SECOND_MNH2(ZTIME2)
+!
+XT_PRESS = XT_PRESS + ZTIME2 - ZTIME1 &
+           - XTIME_LES_BU_PROCESS - XTIME_BU_PROCESS
+!
+!-------------------------------------------------------------------------------
+!
+!*       20.    CHEMISTRY/AEROSOLS
+!               ------------------
+!
+ZTIME1 = ZTIME2
+XTIME_BU_PROCESS = 0.
+XTIME_LES_BU_PROCESS = 0.
+!
+IF (LUSECHEM) THEN
+  CALL CH_MONITOR_n(ZWETDEPAER,KTCOUNT,XTSTEP, ILUOUT, NVERB)
+END IF
+!
+! For inert aerosol (dust and sea salt) => aer_monitor_n
+IF ((LDUST).OR.(LSALT)) THEN
+!
+! tests to see if any cloud exists
+!   
+    GCLD=.TRUE.
+    IF (GCLD .AND. NRR.LE.3 ) THEN 
+      IF( MAXVAL(XCLDFR(:,:,:)).LE. 1.E-10 .AND. GCLOUD_ONLY ) THEN
+          GCLD = .FALSE.                ! only the cloudy verticals would be 
+                                        ! refreshed but there is no clouds 
+      END IF
+    END IF
+!
+    IF (GCLD .AND. NRR.GE.4 ) THEN 
+      IF( CCLOUD(1:3)=='ICE' )THEN
+        IF( MAXVAL(XRT(:,:,:,2)).LE.XRTMIN(2) .AND.             &
+            MAXVAL(XRT(:,:,:,4)).LE.XRTMIN(4) .AND. GCLOUD_ONLY ) THEN
+            GCLD = .FALSE.            ! only the cloudy verticals would be 
+                                      ! refreshed but there is no cloudwater and ice
+        END IF
+      END IF
+      IF( CCLOUD=='C3R5' )THEN
+        IF( MAXVAL(XRT(:,:,:,2)).LE.XRTMIN_C1R3(2) .AND.             &
+            MAXVAL(XRT(:,:,:,4)).LE.XRTMIN_C1R3(4) .AND. GCLOUD_ONLY ) THEN
+            GCLD = .FALSE.            ! only the cloudy verticals would be 
+                                      ! refreshed but there is no cloudwater and ice
+        END IF
+      END IF
+      IF( CCLOUD=='LIMA' )THEN
+        IF( MAXVAL(XRT(:,:,:,2)).LE.XRTMIN_LIMA(2) .AND.             &
+            MAXVAL(XRT(:,:,:,4)).LE.XRTMIN_LIMA(4) .AND. GCLOUD_ONLY ) THEN
+            GCLD = .FALSE.            ! only the cloudy verticals would be 
+                                      ! refreshed but there is no cloudwater and ice
+        END IF
+      END IF
+    END IF
+
+!
+        CALL AER_MONITOR_n(KTCOUNT,XTSTEP, ILUOUT, NVERB, GCLD)
+END IF
+!
+!
+CALL SECOND_MNH2(ZTIME2)
+!
+XT_CHEM = XT_CHEM + ZTIME2 - ZTIME1 &
+      - XTIME_LES_BU_PROCESS - XTIME_BU_PROCESS
+!
+ZTIME = ZTIME + XTIME_LES_BU_PROCESS + XTIME_BU_PROCESS
+
+!-------------------------------------------------------------------------------
+!
+!*       20.    WATER MICROPHYSICS
+!               ------------------
+!
+ZTIME1 = ZTIME2
+XTIME_BU_PROCESS = 0.
+XTIME_LES_BU_PROCESS = 0.
+!
+IF (CCLOUD /= 'NONE' .AND. CELEC == 'NONE') THEN
+!
+  IF (CCLOUD == 'C2R2' .OR. CCLOUD == 'KHKO' .OR. CCLOUD == 'C3R5' &
+                                             .OR. CCLOUD == "LIMA" ) THEN
+    IF ( LFORCING ) THEN
+      XWT_ACT_NUC(:,:,:) = XWT(:,:,:) + XWTFRC(:,:,:)
+    ELSE
+      XWT_ACT_NUC(:,:,:) = XWT(:,:,:)
+    END IF
+    IF (CTURB /= 'NONE' ) THEN
+     IF ( ((CCLOUD=='C2R2'.OR.CCLOUD=='KHKO').AND.LACTTKE) .OR. (CCLOUD=='LIMA'.AND.MACTTKE) ) THEN 
+       XWT_ACT_NUC(:,:,:) = XWT_ACT_NUC(:,:,:) +  (2./3. * XTKET(:,:,:))**0.5
+     ELSE
+       XWT_ACT_NUC(:,:,:) = XWT_ACT_NUC(:,:,:) 
+     ENDIF
+    ENDIF
+  ELSE
+    XWT_ACT_NUC(:,:,:) = 0.
+  END IF
+!
+  XRTHS_CLD(:, :, : )    = XRTHS(:, :, : )
+  XRRS_CLD (:, :, :, : ) = XRRS(:, :, :, : )
+  XRSVS_CLD(:, :, :, : ) = XRSVS(:, :, :, : )
+!$acc data present(XRHODJ)                                                                       &
+!$acc &    copyin (XZZ, XRHODREF, XEXNREF, ZPABST, XTHT, XSIGS, VSIGQSAT, XMFCONV, XTHM, XPABSM, &
+!$acc &            XRCM, XWT_ACT_NUC, XDTHRAD, XCF_MF, XRC_MF, XRI_MF,                           &
+!$acc &            XSOLORG, XMI)                                                                 &
+!$acc &    copy   (XSUPSAT, XNACT, XNPRO, XSSPRO,                                                &
+!$acc &            XRT, XRRS, XSVT, XRSVS, XCLDFR, XCIT, XINPRR3D, XEVAP3D,               &
+!$acc &            XINPRC, XINPRR, XINPRS, XINPRG, XINPRH, XINDEP)                               &
+!$acc &    copyout(XSRCT, XRAINFR)
+
+!$acc update device ( XRTHS )
+  
+  IF (CSURF=='EXTE') THEN
+    ALLOCATE (ZSEA(SIZE(XRHODJ,1),SIZE(XRHODJ,2)))
+    ALLOCATE (ZTOWN(SIZE(XRHODJ,1),SIZE(XRHODJ,2)))
+    ZSEA(:,:) = 0.
+    ZTOWN(:,:)= 0.
+    CALL MNHGET_SURF_PARAM_n (PSEA=ZSEA(:,:),PTOWN=ZTOWN(:,:))
+!$acc data copyin(ZSEA, ZTOWN )
+    CALL RESOLVED_CLOUD ( CCLOUD, CACTCCN, CSCONV, CMF_CLOUD, NRR, NSPLITR,    &
+                          NSPLITG, IMI, KTCOUNT,                               &
+                          CLBCX,CLBCY,TZBAKFILE, CRAD, CTURBDIM,               &
+                          GCLOSE_OUT, LSUBG_COND,LSIGMAS,CSUBG_AUCV,XTSTEP,    &
+                          XZZ, XRHODJ, XRHODREF, XEXNREF,                      &
+                          ZPABST, XTHT,XRT,XSIGS,VSIGQSAT,XMFCONV,XTHM,XRCM,   &
+                          XPABSM, XWT_ACT_NUC,XDTHRAD, XRTHS, XRRS,            &
+                          XSVT, XRSVS,                                         &
+                          XSRCT, XCLDFR,XCIT,                                  &
+                          LSEDIC,KACTIT, KSEDC, KSEDI, KRAIN, KWARM, KHHONI,   &
+                          LCONVHG, XCF_MF,XRC_MF, XRI_MF,                      &
+!                           XINPRC,ZINPRC3D,XINPRR, XINPRR3D, XEVAP3D,             &
+!                           XINPRS,ZINPRS3D, XINPRG,ZINPRG3D, XINPRH,ZINPRH3D,   &
+                          XINPRC,XINPRR, XINPRR3D, XEVAP3D,             &
+                          XINPRS, XINPRG,XINPRH,   &
+!                           XSOLORG, XMI,ZSPEEDC, ZSPEEDR, ZSPEEDS, ZSPEEDG, ZSPEEDH, &
+                          XSOLORG, XMI, &
+                          XINDEP, XSUPSAT, XNACT, XNPRO,XSSPRO, XRAINFR,       &
+                          ZSEA, ZTOWN                                          )
+!$acc end data
+    DEALLOCATE(ZTOWN)
+  ELSE
+    CALL RESOLVED_CLOUD ( CCLOUD, CACTCCN, CSCONV, CMF_CLOUD, NRR, NSPLITR,    &
+                          NSPLITG, IMI, KTCOUNT,                               &
+                          CLBCX,CLBCY,TZBAKFILE, CRAD, CTURBDIM,               &
+                          GCLOSE_OUT, LSUBG_COND,LSIGMAS,CSUBG_AUCV,           &
+                          XTSTEP,XZZ, XRHODJ, XRHODREF, XEXNREF,               &
+                          ZPABST, XTHT,XRT,XSIGS,VSIGQSAT,XMFCONV,XTHM,XRCM,   &
+                          XPABSM, XWT_ACT_NUC,XDTHRAD, XRTHS, XRRS,            &
+                          XSVT, XRSVS,                                         &
+                          XSRCT, XCLDFR,XCIT,                                  &
+                          LSEDIC,KACTIT, KSEDC, KSEDI, KRAIN, KWARM, KHHONI,   &
+                          LCONVHG, XCF_MF,XRC_MF, XRI_MF,                      &
+!                           XINPRC,ZINPRC3D,XINPRR, XINPRR3D, XEVAP3D,             &
+!                           XINPRS,ZINPRS3D, XINPRG,ZINPRG3D, XINPRH,ZINPRH3D,   &
+                          XINPRC,XINPRR, XINPRR3D, XEVAP3D,             &
+                          XINPRS, XINPRG,XINPRH,   &
+!                           XSOLORG, XMI,ZSPEEDC, ZSPEEDR, ZSPEEDS, ZSPEEDG, ZSPEEDH, &
+                          XSOLORG, XMI, &
+                          XINDEP, XSUPSAT, XNACT, XNPRO,XSSPRO, XRAINFR        )
+  END IF
+!$acc end data
+
+!$acc update host(XRTHS)
+  
+  XRTHS_CLD(:, :, : )    = XRTHS(:, :, : )    - XRTHS_CLD(:, :, : )
+  XRRS_CLD (:, :, :, : ) = XRRS (:, :, :, : ) - XRRS_CLD (:, :, :, : )
+  XRSVS_CLD(:, :, :, : ) = XRSVS(:, :, :, : ) - XRSVS_CLD(:, :, :, : )
+!
+  IF (CCLOUD /= 'REVE' ) THEN
+    XACPRR = XACPRR + XINPRR * XTSTEP
+          IF ( (CCLOUD(1:3) == 'ICE' .AND. LSEDIC ) .OR.                     &
+        ((CCLOUD == 'C2R2' .OR. CCLOUD == 'C3R5' .OR. CCLOUD == 'KHKO' &
+                           .OR. CCLOUD == 'LIMA' ) .AND. KSEDC ) )    THEN
+      XACPRC = XACPRC + XINPRC * XTSTEP
+      IF (LDEPOSC .OR. LDEPOC) XACDEP = XACDEP + XINDEP * XTSTEP
+    END IF
+    IF (CCLOUD(1:3) == 'ICE' .OR. CCLOUD == 'C3R5' .OR. &
+                                 (CCLOUD == 'LIMA' .AND. LCOLD ) ) THEN
+      XACPRS = XACPRS + XINPRS * XTSTEP
+      XACPRG = XACPRG + XINPRG * XTSTEP
+      IF (CCLOUD == 'ICE4' .OR. (CCLOUD == 'LIMA' .AND. LHAIL)) XACPRH = XACPRH + XINPRH * XTSTEP          
+    END IF
+!
+! Lessivage des CCN et IFN nucléables par Slinn
+!
+    IF (LSCAV .AND. (CCLOUD == 'LIMA')) THEN
+      CALL LIMA_PRECIP_SCAVENGING(CCLOUD, ILUOUT, KTCOUNT,XTSTEP,XRT(:,:,:,3), &
+                              XRHODREF, XRHODJ, XZZ, XPABST, XTHT,             &
+                              XSVT(:,:,:,NSV_LIMA_BEG:NSV_LIMA_END),           &
+                              XRSVS(:,:,:,NSV_LIMA_BEG:NSV_LIMA_END), XINPAP   )
+!
+      XACPAP(:,:) = XACPAP(:,:) + XINPAP(:,:) * XTSTEP
+    END IF
+  END IF
+!
+! It is necessary that SV_C2R2 and SV_C1R3 are contiguous in the preceeding CALL
+!
+END IF
+!
+CALL SECOND_MNH2(ZTIME2)
+!
+XT_CLOUD = XT_CLOUD + ZTIME2 - ZTIME1 &
+           - XTIME_LES_BU_PROCESS - XTIME_BU_PROCESS
+!
+!-------------------------------------------------------------------------------
+!
+!*       21.    CLOUD ELECTRIFICATION AND LIGHTNING FLASHES
+!               -------------------------------------------
+!
+ZTIME1 = ZTIME2
+XTIME_BU_PROCESS = 0.
+XTIME_LES_BU_PROCESS = 0.
+!
+IF (CELEC /= 'NONE' .AND. (CCLOUD(1:3) == 'ICE')) THEN
+  XWT_ACT_NUC(:,:,:) = 0.
+!
+  XRTHS_CLD = XRTHS
+  XRRS_CLD  = XRRS
+  XRSVS_CLD = XRSVS
+  IF (CSURF=='EXTE') THEN
+    ALLOCATE (ZSEA(SIZE(XRHODJ,1),SIZE(XRHODJ,2)))
+    ALLOCATE (ZTOWN(SIZE(XRHODJ,1),SIZE(XRHODJ,2)))
+    ZSEA(:,:) = 0.
+    ZTOWN(:,:)= 0.
+    CALL MNHGET_SURF_PARAM_n (PSEA=ZSEA(:,:),PTOWN=ZTOWN(:,:))
+    CALL RESOLVED_ELEC_n (CCLOUD, CSCONV, CMF_CLOUD,                     &
+                          NRR, NSPLITR, IMI, KTCOUNT, OEXIT,             &
+                          CLBCX, CLBCY, CRAD, CTURBDIM,                  &
+                          LSUBG_COND, LSIGMAS,VSIGQSAT,CSUBG_AUCV,       &
+                          XTSTEP, XZZ, XRHODJ, XRHODREF, XEXNREF,        &
+                          ZPABST, XTHT, XRTHS, XWT,  XRT, XRRS,          &
+                          XSVT, XRSVS, XCIT,                             &
+                          XSIGS, XSRCT, XCLDFR, XMFCONV, XCF_MF, XRC_MF, &
+                          XRI_MF, LSEDIC, LWARM,                         &
+                          XINPRC, XINPRR, XINPRR3D, XEVAP3D,             &
+                          XINPRS, XINPRG, XINPRH,                        &
+                          ZSEA, ZTOWN                                    )
+    DEALLOCATE(ZTOWN)
+  ELSE
+    CALL RESOLVED_ELEC_n (CCLOUD, CSCONV, CMF_CLOUD,                     &
+                          NRR, NSPLITR, IMI, KTCOUNT, OEXIT,             &
+                          CLBCX, CLBCY, CRAD, CTURBDIM,                  &
+                          LSUBG_COND, LSIGMAS,VSIGQSAT, CSUBG_AUCV,      &
+                          XTSTEP, XZZ, XRHODJ, XRHODREF, XEXNREF,        &
+                          ZPABST, XTHT, XRTHS, XWT,                      &
+                          XRT, XRRS, XSVT, XRSVS, XCIT,                  &
+                          XSIGS, XSRCT, XCLDFR, XMFCONV, XCF_MF, XRC_MF, &
+                          XRI_MF, LSEDIC, LWARM,                         &
+                          XINPRC, XINPRR, XINPRR3D, XEVAP3D,             &
+                          XINPRS, XINPRG, XINPRH                         )
+  END IF
+  XRTHS_CLD = XRTHS - XRTHS_CLD
+  XRRS_CLD  = XRRS  - XRRS_CLD
+  XRSVS_CLD = XRSVS - XRSVS_CLD
+!
+  XACPRR = XACPRR + XINPRR * XTSTEP
+  IF ((CCLOUD(1:3) == 'ICE' .AND. LSEDIC)) & 
+       XACPRC = XACPRC + XINPRC * XTSTEP
+  IF (CCLOUD(1:3) == 'ICE') THEN
+    XACPRS = XACPRS + XINPRS * XTSTEP
+    XACPRG = XACPRG + XINPRG * XTSTEP
+    IF (CCLOUD == 'ICE4') XACPRH = XACPRH + XINPRH * XTSTEP          
+  END IF
+END IF
+!
+CALL SECOND_MNH2(ZTIME2)
+!
+XT_ELEC = XT_ELEC + ZTIME2 - ZTIME1 &
+           - XTIME_LES_BU_PROCESS - XTIME_BU_PROCESS
+!
+!-------------------------------------------------------------------------------
+!
+!*       21.    L.E.S. COMPUTATIONS
+!               -------------------
+!
+ZTIME1 = ZTIME2
+!
+CALL LES_n
+!
+CALL SECOND_MNH2(ZTIME2)
+!
+XT_SPECTRA = XT_SPECTRA + ZTIME2 - ZTIME1 + XTIME_LES_BU + XTIME_LES
+!
+!-------------------------------------------------------------------------------
+!
+!*       21. bis    MEAN_UM
+!               --------------------
+!
+IF (LMEAN_FIELD) THEN
+   CALL MEAN_FIELD(XUT, XVT, XWT, XTHT, XTKET, XPABST)
+END IF
+!
+!-------------------------------------------------------------------------------
+!
+!*       22.    UPDATE HALO OF EACH SUBDOMAINS FOR TIME T+DT
+!               --------------------------------------------
+!
+ZTIME1 = ZTIME2
+!
+CALL EXCHANGE (XTSTEP,NRR,NSV,XRHODJ,TFIELDS_ll,     &
+               XRUS, XRVS,XRWS,XRTHS,XRRS,XRTKES,XRSVS)
+!
+CALL SECOND_MNH2(ZTIME2)
+!
+XT_HALO = XT_HALO + ZTIME2 - ZTIME1
+!
+!-------------------------------------------------------------------------------
+!
+!*       23.    TEMPORAL SWAPPING
+!               -----------------
+!
+ZTIME1 = ZTIME2
+XTIME_BU_PROCESS = 0.
+!
+CALL ENDSTEP  ( XTSTEP,NRR,NSV,KTCOUNT,IMI,               &
+                CUVW_ADV_SCHEME,CTEMP_SCHEME,XRHODJ,      &
+                XRUS,XRVS,XRWS,XDRYMASSS,                 &
+                XRTHS,XRRS,XRTKES,XRSVS,                  &
+                XLSUS,XLSVS,XLSWS,                        &
+                XLSTHS,XLSRVS,XLSZWSS,                    &
+                XLBXUS,XLBXVS,XLBXWS,                     &
+                XLBXTHS,XLBXRS,XLBXTKES,XLBXSVS,          &
+                XLBYUS,XLBYVS,XLBYWS,                     &
+                XLBYTHS,XLBYRS,XLBYTKES,XLBYSVS,          &
+                XUM,XVM,XWM,XZWS,                         &
+                XUT,XVT,XWT,XPABST,XDRYMASST,             &
+                XTHT, XRT, XTHM, XRCM, XPABSM,XTKET, XSVT,&
+                XLSUM,XLSVM,XLSWM,                        &
+                XLSTHM,XLSRVM,XLSZWSM,                    &
+                XLBXUM,XLBXVM,XLBXWM,                     &
+                XLBXTHM,XLBXRM,XLBXTKEM,XLBXSVM,          &
+                XLBYUM,XLBYVM,XLBYWM,                     &
+                XLBYTHM,XLBYRM,XLBYTKEM,XLBYSVM           )
+!
+CALL SECOND_MNH2(ZTIME2)
+!
+XT_STEP_SWA = XT_STEP_SWA + ZTIME2 - ZTIME1 - XTIME_BU_PROCESS
+!
+!-------------------------------------------------------------------------------
+!
+!*       24.1    BALLOON and AIRCRAFT
+!               --------------------
+!
+ZTIME1 = ZTIME2
+!
+IF (LFLYER)                                                                   &
+  CALL AIRCRAFT_BALLOON(XTSTEP,                                               &
+                      TDTEXP, TDTMOD, TDTSEG, TDTCUR,                         &
+                      XXHAT, XYHAT, XZZ, XMAP, XLONORI, XLATORI,              &
+                      XUT, XVT, XWT, XPABST, XTHT, XRT, XSVT, XTKET, XTSRAD,  &
+                      XRHODREF,XCIT,PSEA=ZSEA(:,:))
+
+
+!-------------------------------------------------------------------------------
+!
+!*       24.2    STATION (observation diagnostic)
+!               --------------------------------
+!
+IF (LSTATION)                                                            &
+  CALL STATION_n(XTSTEP,                                                 &
+                 TDTEXP, TDTMOD, TDTSEG, TDTCUR,                         &
+                 XXHAT, XYHAT, XZZ,                                      &
+                 XUT, XVT, XWT, XTHT, XRT, XSVT, XTKET, XTSRAD, XPABST   )
+!
+!---------------------------------------------------------
+!
+!*       24.3    PROFILER (observation diagnostic)
+!               ---------------------------------
+!
+IF (LPROFILER)                                                           &
+  CALL PROFILER_n(XTSTEP,                                                &
+                  TDTEXP, TDTMOD, TDTSEG, TDTCUR,                        &
+                  XXHAT, XYHAT, XZZ,XRHODREF,                            &
+                  XUT, XVT, XWT, XTHT, XRT, XSVT, XTKET, XTSRAD, XPABST, &
+                  XAER, XCLDFR, XCIT)
+!
+!
+CALL SECOND_MNH2(ZTIME2)
+!
+XT_STEP_MISC = XT_STEP_MISC + ZTIME2 - ZTIME1
+!
+!-------------------------------------------------------------------------------
+!
+!*       24.4   deallocation of observation diagnostics
+!               ---------------------------------------
+!
+CALL END_DIAG_IN_RUN
+!
+!-------------------------------------------------------------------------------
+!
+!
+!*       25.    STORAGE OF BUDGET FIELDS
+!               ------------------------
+!
+ZTIME1 = ZTIME2
+!
+IF ( .NOT. LIO_NO_WRITE ) THEN
+  IF (NBUMOD==IMI .AND. CBUTYPE/='NONE') THEN
+    CALL ENDSTEP_BUDGET(TDIAFILE,KTCOUNT,TDTCUR,TDTMOD,XTSTEP,NSV)
+  END IF
+END IF
+!
+CALL SECOND_MNH2(ZTIME2)
+!
+XT_STEP_BUD = XT_STEP_BUD + ZTIME2 - ZTIME1 + XTIME_BU
+!
+!-------------------------------------------------------------------------------
+!
+!*       26.    FM FILE CLOSURE
+!               ---------------
+!
+IF (GCLOSE_OUT) THEN
+  GCLOSE_OUT=.FALSE.
+  CALL IO_File_close(TZBAKFILE)
+END IF
+!
+!-------------------------------------------------------------------------------
+!
+!*       27.    CURRENT TIME REFRESH
+!               --------------------
+!
+TDTCUR%TIME=TDTCUR%TIME + XTSTEP
+CALL DATETIME_CORRECTDATE(TDTCUR)
+!
+!-------------------------------------------------------------------------------
+!
+!*       28.    CPU ANALYSIS
+!               ------------
+!
+CALL SECOND_MNH2(ZTIME2)
+XT_START=XT_START+ZTIME2-ZEND
+!
+!
+IF ( KTCOUNT == NSTOP .AND. IMI==1) THEN
+  OEXIT=.TRUE.
+END IF
+!
+IF (OEXIT) THEN
+!
+  IF ( .NOT. LIO_NO_WRITE ) THEN
+    IF (LSERIES) CALL WRITE_SERIES_n(TDIAFILE)
+    CALL WRITE_AIRCRAFT_BALLOON(TDIAFILE)
+    CALL WRITE_STATION_n(TDIAFILE)
+    CALL WRITE_PROFILER_n(TDIAFILE)
+    CALL WRITE_LES_n(TDIAFILE,' ')
+    CALL WRITE_LES_n(TDIAFILE,'A')
+    CALL WRITE_LES_n(TDIAFILE,'E')
+    CALL WRITE_LES_n(TDIAFILE,'H')
+    CALL MENU_DIACHRO(TDIAFILE,'END')
+    CALL IO_File_close(TDIAFILE)
+  END IF
+  !
+  CALL IO_File_close(TINIFILE)
+  IF (CSURF=="EXTE") CALL IO_File_close(TINIFILEPGD)
+!
+!*       28.1   print statistics!
+!
+  ! Set File Timing OUTPUT
+  !
+  CALL SET_ILUOUT_TIMING(TLUOUT)
+  !
+  ! Compute global time
+  !
+  CALL TIME_STAT_ll(XT_START,ZTOT)
+  !
+  CALL TIME_HEADER_ll(IMI)
+  !
+  CALL TIME_STAT_ll(XT_1WAY,ZTOT,       ' ONE WAY','=')
+  CALL TIME_STAT_ll(XT_BOUND,ZTOT,      ' BOUNDARIES','=')
+  CALL TIME_STAT_ll(XT_STORE,ZTOT,      ' STORE-FIELDS','=')
+    CALL TIME_STAT_ll(TIMEZ%T_WRIT3D_SEND,ZTOT,    '   W3D_SEND ','-')
+    CALL TIME_STAT_ll(TIMEZ%T_WRIT3D_RECV,ZTOT,    '   W3D_RECV ','-')
+    CALL TIME_STAT_ll(TIMEZ%T_WRIT3D_WRIT,ZTOT,    '   W3D_WRIT ','-')
+    CALL TIME_STAT_ll(TIMEZ%T_WRIT3D_WAIT,ZTOT,    '   W3D_WAIT ','-')
+    CALL TIME_STAT_ll(TIMEZ%T_WRIT3D_ALL ,ZTOT,    '   W3D_ALL ','-')
+    CALL TIME_STAT_ll(TIMEZ%T_WRIT2D_GATH,ZTOT,    '   W2D_GATH ','-')
+    CALL TIME_STAT_ll(TIMEZ%T_WRIT2D_WRIT,ZTOT,    '   W2D_WRIT ','-')
+    CALL TIME_STAT_ll(TIMEZ%T_WRIT2D_ALL ,ZTOT,    '   W2D_ALL ','-')
+  CALL TIME_STAT_ll(XT_GUESS,ZTOT,      ' INITIAL_GUESS','=')
+  CALL TIME_STAT_ll(XT_2WAY,ZTOT,       ' TWO WAY','=')
+  CALL TIME_STAT_ll(XT_ADV,ZTOT,        ' ADVECTION MET','=')
+  CALL TIME_STAT_ll(XT_ADVUVW,ZTOT,     ' ADVECTION UVW','=')
+  CALL TIME_STAT_ll(XT_GRAV,ZTOT,       ' GRAVITY','=')
+  CALL TIME_STAT_ll(XT_FORCING,ZTOT,    ' FORCING','=')
+  CALL TIME_STAT_ll(XT_NUDGING,ZTOT,    ' NUDGING','=')
+  CALL TIME_STAT_ll(XT_SOURCES,ZTOT,    ' DYN_SOURCES','=')
+  CALL TIME_STAT_ll(XT_DIFF,ZTOT,       ' NUM_DIFF','=')
+  CALL TIME_STAT_ll(XT_RELAX,ZTOT,      ' RELAXATION','=')
+  !
+  CALL  TIMING_LEGEND() 
+  !
+  CALL TIME_STAT_ll(XT_PARAM,ZTOT,      ' PHYS_PARAM','=')
+    CALL TIME_STAT_ll(XT_RAD,ZTOT,      '   RAD       = '//CRAD  ,'-')
+    CALL TIME_STAT_ll(XT_SHADOWS,ZTOT,  '   SHADOWS'             ,'-')
+    CALL TIME_STAT_ll(XT_DCONV,ZTOT,    '   DEEP CONV = '//CDCONV,'-')
+    CALL TIME_STAT_ll(XT_GROUND,ZTOT,   '   GROUND'              ,'-')
+    CALL TIME_STAT_ll(XT_TURB,ZTOT,     '   TURB      = '//CTURB ,'-')
+    CALL TIME_STAT_ll(XT_MAFL,ZTOT,     '   MAFL      = '//CSCONV,'-')
+    CALL TIME_STAT_ll(XT_CHEM,ZTOT,     '   CHIMIE'              ,'-')
+  CALL  TIMING_LEGEND()
+  CALL TIME_STAT_ll(XT_COUPL,ZTOT,      ' SET_COUPLING','=')
+  CALL TIME_STAT_ll(XT_RAD_BOUND,ZTOT,  ' RAD_BOUND','=')
+  !
+  CALL  TIMING_LEGEND()
+  ! 
+  CALL TIME_STAT_ll(XT_PRESS,ZTOT,      ' PRESSURE ','=','F')
+  !JUAN Z_SPLITTING
+    CALL TIME_STAT_ll(TIMEZ%T_MAP_B_SX_YP2_ZP1,ZTOT,          '   REMAP       B=>FFTXZ'  ,'-','F')
+    CALL TIME_STAT_ll(TIMEZ%T_MAP_SX_YP2_ZP1_SXP2_Y_ZP1,ZTOT, '   REMAP   FFTXZ=>FFTYZ'  ,'-','F')
+    CALL TIME_STAT_ll(TIMEZ%T_MAP_SXP2_Y_ZP1_B,ZTOT,          '   REMAP   FTTYZ=>B'      ,'-','F')
+    CALL TIME_STAT_ll(TIMEZ%T_MAP_SXP2_Y_ZP1_SXP2_YP1_Z,ZTOT, '   REMAP   FFTYZ=>SUBZ'   ,'-','F')
+    CALL TIME_STAT_ll(TIMEZ%T_MAP_B_SXP2_Y_ZP1,ZTOT,          '   REMAP       B=>FFTYZ-1','-','F')
+    CALL TIME_STAT_ll(TIMEZ%T_MAP_SXP2_YP1_Z_SXP2_Y_ZP1,ZTOT, '   REMAP    SUBZ=>FFTYZ-1','-','F')
+    CALL TIME_STAT_ll(TIMEZ%T_MAP_SXP2_Y_ZP1_SX_YP2_ZP1,ZTOT, '   REMAP FFTYZ-1=>FFTXZ-1','-','F')
+    CALL TIME_STAT_ll(TIMEZ%T_MAP_SX_YP2_ZP1_B,ZTOT,          '   REMAP FFTXZ-1=>B     ' ,'-','F')
+  ! JUAN P1/P2
+  CALL TIME_STAT_ll(XT_CLOUD,ZTOT,      ' RESOLVED_CLOUD','=')
+  CALL TIME_STAT_ll(XT_ELEC,ZTOT,      ' RESOLVED_ELEC','=')
+  CALL TIME_STAT_ll(XT_HALO,ZTOT,       ' EXCHANGE_HALO','=')
+  CALL TIME_STAT_ll(XT_STEP_SWA,ZTOT,   ' ENDSTEP','=')
+  CALL TIME_STAT_ll(XT_STEP_BUD,ZTOT,   ' BUDGETS','=')
+  CALL TIME_STAT_ll(XT_SPECTRA,ZTOT,    ' LES','=')
+  CALL TIME_STAT_ll(XT_STEP_MISC,ZTOT,  ' MISCELLANEOUS','=')
+  !
+  ! sum of call subroutine
+  !
+  ZALL   = XT_1WAY + XT_BOUND   + XT_STORE   + XT_GUESS    +  XT_2WAY   + &
+           XT_ADV  + XT_FORCING + XT_NUDGING + XT_SOURCES  +  XT_DIFF   + &
+           XT_ADVUVW  + XT_GRAV +                                         &
+           XT_RELAX+ XT_PARAM   + XT_COUPL   + XT_RAD_BOUND+XT_PRESS    + &
+           XT_CLOUD+ XT_ELEC    + XT_HALO    + XT_SPECTRA + XT_STEP_SWA + &
+           XT_STEP_MISC+ XT_STEP_BUD
+  CALL TIME_STAT_ll(ZALL,ZTOT,          ' SUM(CALL)','=')
+  CALL  TIMING_SEPARATOR('=')
+  !
+  ! Gobale Stat
+  !
+  WRITE(ILUOUT,FMT=*)
+  WRITE(ILUOUT,FMT=*)
+  CALL  TIMING_LEGEND() 
+  !
+  ! MODELN all included
+  !
+  CALL  TIMING_SEPARATOR('+')
+  CALL  TIMING_SEPARATOR('+')  
+  WRITE(YMI,FMT="(I0)") IMI
+  CALL TIME_STAT_ll(XT_START,ZTOT,      ' MODEL'//YMI,'+')
+  CALL  TIMING_SEPARATOR('+')
+  CALL  TIMING_SEPARATOR('+')
+  CALL  TIMING_SEPARATOR('+')
+  !
+  ! Timing/ Steps
+  !
+  ZTIME_STEP     =  XT_START / REAL(KTCOUNT)
+  WRITE(YTCOUNT,FMT="(I0)") KTCOUNT
+  CALL TIME_STAT_ll(ZTIME_STEP,ZTOT,     ' SECOND/STEP='//YTCOUNT,'=')
+  !
+  ! Timing/Step/Points
+  !
+  IPOINTS = NIMAX_ll*NJMAX_ll*NKMAX
+  WRITE(YPOINTS,FMT="(I0)") IPOINTS
+  ZTIME_STEP_PTS =  ZTIME_STEP / REAL(IPOINTS) * 1e6
+  CALL TIME_STAT_ll(ZTIME_STEP_PTS,ZTOT_PT)
+  CALL TIME_STAT_ll(ZTIME_STEP_PTS,ZTOT_PT,  ' MICROSEC/STP/PT='//YPOINTS,'-')
+  !
+  CALL  TIMING_SEPARATOR('=')
+  !
+  !
+  !
+  CALL IO_File_close(TLUOUT)
+  IF (IMI==NMODEL) CALL IO_File_close(TLUOUT0)
+END IF
+
+!$acc end data
+
+END SUBROUTINE MODEL_n
diff --git a/src/ZSOLVER/pressurez.f90 b/src/ZSOLVER/pressurez.f90
new file mode 100644
index 0000000000000000000000000000000000000000..c9b2b9db971f01c05b40f5c809a24c8f18a47d18
--- /dev/null
+++ b/src/ZSOLVER/pressurez.f90
@@ -0,0 +1,789 @@
+!MNH_LIC Copyright 1994-2020 CNRS, Meteo-France and Universite Paul Sabatier
+!MNH_LIC This is part of the Meso-NH software governed by the CeCILL-C licence
+!MNH_LIC version 1. See LICENSE, CeCILL-C_V1-en.txt and CeCILL-C_V1-fr.txt
+!MNH_LIC for details. version 1.
+!-----------------------------------------------------------------
+!###################
+MODULE MODI_PRESSUREZ
+!###################
+!
+INTERFACE
+!
+      SUBROUTINE PRESSUREZ(                                                &
+      HLBCX,HLBCY,HPRESOPT,KITR,OITRADJ,KTCOUNT,PRELAX,KMI,                &
+      PRHODJ,PDXX,PDYY,PDZZ,PDZX,PDZY,PDXHATM,PDYHATM,PRHOT,               &
+      PAF,PBF,PCF,PTRIGSX,PTRIGSY,KIFAXX,KIFAXY,                           &
+      KRR,KRRL,KRRI,PDRYMASST,PREFMASS,PMASS_O_PHI0,                       &
+      PTHT,PRT,PRHODREF,PTHVREF,PRVREF,PEXNREF,PLINMASS,                   &
+      PRUS,PRVS,PRWS,PPABST,                                               &
+      PBFB,                                                                &
+      PBF_SXP2_YP1_Z,                                                      &
+      PAF_ZS,PBF_ZS,PCF_ZS,                                                &
+      PDXATH_ZS,PDYATH_ZS,PRHO_ZS,                                         &
+      A_K,B_K,C_K,D_K,                                                     &
+      PRESIDUAL) !JUAN  FULL ZSOLVER                                        
+!
+IMPLICIT NONE
+!
+CHARACTER (LEN=*), DIMENSION(:), INTENT(IN) :: HLBCX    ! x-direction LBC type
+CHARACTER (LEN=*), DIMENSION(:), INTENT(IN) :: HLBCY    ! y-direction LBC type
+!
+CHARACTER (LEN=5), INTENT(IN) :: HPRESOPT        ! choice of the pressure solver
+!
+INTEGER, INTENT(INOUT) :: KITR                   ! number of iterations for the
+                                                 ! pressure solver
+LOGICAL, INTENT(IN) :: OITRADJ                   ! switch to adjust or not KITR
+INTEGER, INTENT(IN) :: KTCOUNT                   ! counter value of the
+                                                 ! model temporal loop
+INTEGER, INTENT(IN) :: KMI                       ! Model index
+REAL, INTENT(IN)    :: PRELAX                    ! relaxation coefficient for
+                                                 ! the Richardson's method
+!
+REAL, DIMENSION(:,:,:), INTENT(IN) :: PRHODJ     ! density of reference state
+                                                 ! * J
+!
+REAL, DIMENSION(:,:,:), INTENT(IN) :: PDXX,PDYY,PDZZ,PDZX,PDZY ! metric coefficients
+!
+REAL, INTENT(IN) :: PDXHATM                     ! mean grid increment in the x
+                                                ! direction
+REAL, INTENT(IN) :: PDYHATM                     ! mean grid increment in the y
+                                                ! direction
+!
+REAL, DIMENSION (:), INTENT(IN) :: PRHOT         !  mean of XRHODJ on the plane x y
+                                                 !  localized at a mass level
+!
+REAL, DIMENSION(:), INTENT(IN)     :: PAF,PCF    ! vectors giving the nonvanishing
+REAL, DIMENSION(:,:,:), INTENT(IN) :: PBF        ! elements of the tri-diag. y-slide
+                                                 ! matrix in the pressure eq.
+!
+                                                 ! arrays of sin or cos values
+                                                 ! for the FFT :
+REAL, DIMENSION(:), INTENT(IN) :: PTRIGSX        ! - along x
+REAL, DIMENSION(:), INTENT(IN) :: PTRIGSY        ! - along y
+!
+                                                 ! decomposition in prime
+                                                 ! numbers for the FFT:
+INTEGER, DIMENSION(19), INTENT(IN) :: KIFAXX      ! - along x
+INTEGER, DIMENSION(19), INTENT(IN) :: KIFAXY      ! - along y
+!
+!
+INTEGER,                  INTENT(IN)    :: KRR   ! Total number of water var.
+INTEGER,                  INTENT(IN)    :: KRRL  ! Number of liquid water var.
+INTEGER,                  INTENT(IN)    :: KRRI  ! Number of ice water var.
+!
+REAL,                     INTENT(IN)    :: PDRYMASST   ! Mass of dry air and of
+REAL,                     INTENT(IN)    :: PREFMASS    ! the ref. atmosphere
+REAL,                     INTENT(IN)    :: PMASS_O_PHI0 !    Mass / Phi0
+!
+REAL, DIMENSION(:,:,:),   INTENT(IN)    :: PTHT       ! Temperature and water
+REAL, DIMENSION(:,:,:,:), INTENT(IN)    :: PRT        !  variables at time t
+!
+REAL, DIMENSION(:,:,:),   INTENT(IN)    :: PRHODREF    ! dry Density
+REAL, DIMENSION(:,:,:),   INTENT(IN)    :: PTHVREF     ! Virtual Temperature
+                                                       ! of the reference state
+REAL, DIMENSION(:,:,:),   INTENT(IN)    :: PRVREF      ! mixing ratio of the
+                                                       ! reference state
+REAL, DIMENSION(:,:,:),   INTENT(IN)    :: PEXNREF     ! Exner function
+                                                       ! of the reference state
+REAL,                     INTENT(IN)    :: PLINMASS    ! lineic mass through
+                                                       ! open boundaries
+!
+REAL,       INTENT(INOUT) :: PRUS(:,:,:)         ! source term along x
+REAL,       INTENT(INOUT) :: PRVS(:,:,:)         ! source term along y
+REAL,       INTENT(INOUT) :: PRWS(:,:,:)         ! source term along z
+!
+REAL,       INTENT(INOUT)   :: PPABST(:,:,:)        ! pressure(t)
+!
+!JUAN Z_SPLITING
+REAL, DIMENSION(:,:,:), INTENT(IN) :: PBFB       ! elements of the tri-diag b-slide .
+                                                 ! matrix in the pressure eq.
+REAL, DIMENSION(:,:,:), INTENT(IN) :: PBF_SXP2_YP1_Z       ! elements of the tri-diag. SXP2_YP1_Z-slide 
+                                                   ! matrix in the pressure eq.
+
+REAL, DIMENSION(:,:,:), INTENT(IN) :: PAF_ZS,PBF_ZS,PCF_ZS
+REAL, DIMENSION(:,:)  , INTENT(IN) :: PDXATH_ZS,PDYATH_ZS
+REAL, DIMENSION(:,:,:), INTENT(IN) :: PRHO_ZS
+REAL, DIMENSION(:)    , INTENT(IN) :: A_K,B_K,C_K,D_K
+
+REAL, OPTIONAL                     :: PRESIDUAL
+!JUAN Z_SPLITING
+END SUBROUTINE PRESSUREZ
+!
+END INTERFACE
+!
+END MODULE MODI_PRESSUREZ
+!     ######################################################################
+      SUBROUTINE PRESSUREZ(                                                &
+      HLBCX,HLBCY,HPRESOPT,KITR,OITRADJ,KTCOUNT,PRELAX,KMI,                &
+      PRHODJ,PDXX,PDYY,PDZZ,PDZX,PDZY,PDXHATM,PDYHATM,PRHOT,               &
+      PAF,PBF,PCF,PTRIGSX,PTRIGSY,KIFAXX,KIFAXY,                           &
+      KRR,KRRL,KRRI,PDRYMASST,PREFMASS,PMASS_O_PHI0,                       &
+      PTHT,PRT,PRHODREF,PTHVREF,PRVREF,PEXNREF,PLINMASS,                   &
+      PRUS,PRVS,PRWS,PPABST,                                               &
+      PBFB,                                                                &
+      PBF_SXP2_YP1_Z,                                                      &
+      PAF_ZS,PBF_ZS,PCF_ZS,                                                &
+      PDXATH_ZS,PDYATH_ZS,PRHO_ZS,                                         &
+      A_K,B_K,C_K,D_K,                                                     &
+      PRESIDUAL) !JUAN FULL ZSOLVER
+!     ######################################################################
+!
+!!****  *PRESSUREZ * - solve the pressure equation and add the pressure term
+!!      to the sources
+!!
+!!    PURPOSE
+!!    -------
+!       The purpose of this routine is to solve the pressure equation:
+!     with either the conjugate gradient method or the Richardson's method.
+!     The pressure gradient is added to the sources in order
+!     to nullify the divergence of the momentum* Thetavref*(1+Rvref)
+!     at the time t+dt.
+!
+!!**  METHOD
+!!    ------
+!!     The divergence of the sources  ( RHS of the pressure equation ) is
+!!    computed. The pressure equation is then solved by either CG method,
+!!    either Richardson's method, or an exact method. Finally, the pressure
+!!    gradient is added to the sources RUS, RVS, RWS.
+!!    Finally, the absolute pressure is diagnozed from the total mass
+!!    included in the simulation domain.
+!!
+!!    EXTERNAL
+!!    --------
+!!      Subroutine MASS_LEAK : assures global non-divergence condition in the
+!!                             case of open boundaries
+!!      Subroutine FLAT_INV  : solve the pressure equation for the case
+!!                             without orography
+!!      Subroutine RICHARDSON: solve the pressure equation with the
+!!                             Richardson's method
+!!      Subroutine CONJGRAD  : solve the pressure equation with the Conjugate
+!!                             Gradient algorithm
+!!      Function   GX_M_U : compute the gradient along x
+!!      Function   GY_M_V : compute the gradient along y
+!!      Function   GZ_M_W : compute the gradient along z
+!!      Subroutine GDIV     : compute J times the divergence of 1/J times a vector
+!!      Function MXM: compute an average in the x direction for a variable
+!!      at a mass localization
+!!      Function MYM: compute an average in the y direction for a variable
+!!      at a mass localization
+!!      Function MZM: compute an average in the z direction for a variable
+!!      at a mass localization
+!!      Subroutine P_ABS   : compute the constant for PABS and therefore, the
+!!      absolute pressure function
+!!
+!!    IMPLICIT ARGUMENTS
+!!    ------------------
+!!      Module MODD_CONF: model configuration
+!!        LFLAT: logical switch for zero orography
+!!        L2D  : logical switch for two-dimensional configuration
+!!        LCARTESIAN : logical switch for cartesian geometry
+!!      Module MODD_PARAMETERS: declaration of parameter variables
+!!        JPHEXT, JPVEXT: define the number of marginal points out of the
+!!        physical domain along horizontal and vertical directions respectively
+!!      Module MODD_CST: physical constants
+!!        XCPD
+!!
+!!    REFERENCE
+!!    ---------
+!!      Book2 of documentation (subroutine PRESSURE) + Book1 (  )
+!!
+!!    AUTHOR
+!!    ------
+!!      P. Hereil and J. Stein       * Meteo France *
+!!
+!!    MODIFICATIONS
+!!    -------------
+!!      Original      05/07/94
+!!      Modification  03/01/95  (Lafore)  To add the absolute pressure diagnosis
+!!      Modification  31/01/95  (Stein)   Copy of the pressure function in the
+!!                                        2D case in the two outermost planes
+!!      Modification  16/02/95  (Mallet)  Add the call to MASS_LEAK
+!!      Modification  16/03/95  (Stein)  change the argument list of the
+!!                              gradient and remove R from the historical var.
+!!      Modification  30/06/95  (Stein)  Add a test not to compute the absolute
+!!                              pressure in the Boussinesq case
+!!                    16/10/95 (J. Stein) change the budget calls
+!!                    29/01/96 (J. Stein) call iterative resolution for
+!!                              non-cartessian geometry
+!!                    19/12/96 (J.-P. Pinty) update the budget calls
+!!                    14/01/97 (Stein,Lafore) New anelastic equations
+!!                    17/12/97 ( Stein )include the case of non-vanishing
+!!                              orography at the lbc
+!!                    26/03/98 (Stein,Jabouille) fix the value of the corner point
+!!                    15/06/98  (D.Lugato, R.Guivarch) Parallelisation
+!!                    25/08/99 (J.-P. Pinty) add CRESI option to CPRESOPT
+!!                    06/11/02 (V. Masson) update the budget calls
+!!                    24/08/2005 (J. escobar) BUG : remove IIE+1, IJE+1 out of bound
+!!                                references in parallel run
+!!                    08/2010 (V.Masson, C.Lac) Add UPDATE_HALO
+!!                    11/2010 (V.Masson, C.Lac) PPABST, must not be cyclic => add temp array
+!!                                             to save it before UPDATE_HALO
+!!                    07/2011 (J.escobar ) Bypass Bug with ifort11/12 on  HLBCX,HLBCY 
+!!                    09/2001 (J.escobar ) reintroduce correctly the GMAXLOC_ll call 
+!!                    11/2010 (V.Masson, C.Lac) PPABST must not be cyclic => add temp array
+!!                                             to save it before UPDATE_HALO
+!!                    02/2013 (J.Escobar ) add a test on abs(err) > 100.O for BG without controle of NAN
+!!                    2012    (V.Masson)  Modif update_halo due to CONTRAV
+!!                    2014    (C.Lac) correction for 3D run with LBOUSS=.TRUE.
+!!   J.Escobar : 15/09/2015 : WENO5 & JPHEXT <> 1 
+!!   J.escobar : check nb proc versus ZRESI & min(DIMX,DIMY)
+!!  Philippe Wautelet: 05/2016-04/2018: new data structures and calls for I/O
+!!  Philippe Wautelet: 22/01/2019: use standard FLUSH statement instead of non standard intrinsics
+!  P. Wautelet 10/04/2019: replace ABORT and STOP calls by Print_msg
+!  P. Wautelet 20/05/2019: add name argument to ADDnFIELD_ll + new ADD4DFIELD_ll subroutine
+!-------------------------------------------------------------------------------
+!
+!*       0.    DECLARATIONS
+!              ------------
+!
+USE MODD_ARGSLIST_ll, ONLY: LIST_ll
+USE MODD_BUDGET
+USE MODD_CST
+USE MODD_CONF
+USE MODD_DYN_n,       ONLY: LRES, XRES
+USE MODD_LUNIT_n,     ONLY: TLUOUT
+USE MODD_MPIF
+USE MODD_PARAMETERS
+use modd_precision,   only: MNHREAL_MPI
+USE MODD_REF,         ONLY: LBOUSS
+USE MODD_VAR_ll,      ONLY: NMNH_COMM_WORLD , NPROC
+!
+USE MODE_ll
+USE MODE_MPPDB
+USE MODE_MSG
+USE MODE_SUM2_ll,     ONLY: GMAXLOC_ll
+!
+USE MODI_BUDGET
+USE MODI_CONJGRAD
+USE MODI_ZCONJGRAD
+USE MODI_CONRESOL
+USE MODI_CONRESOLZ
+USE MODI_FLAT_INV
+USE MODI_ZSOLVER
+USE MODI_FLAT_INVZ
+USE MODI_GDIV
+USE MODI_GRADIENT_M
+USE MODI_MASS_LEAK
+USE MODI_P_ABS
+USE MODI_RICHARDSON
+USE MODI_SHUMAN
+!
+IMPLICIT NONE
+!
+!*       0.1   declarations of arguments
+!
+  CHARACTER (LEN=*), DIMENSION(:), INTENT(IN) :: HLBCX    ! x-direction LBC type
+  CHARACTER (LEN=*), DIMENSION(:), INTENT(IN) :: HLBCY    ! y-direction LBC type
+!
+CHARACTER (LEN=5), INTENT(IN) :: HPRESOPT        ! choice of the pressure solver
+!
+INTEGER, INTENT(INOUT) :: KITR                   ! number of iterations for the
+                                                 ! pressure solver
+LOGICAL, INTENT(IN) :: OITRADJ                   ! switch to adjust or not KITR
+INTEGER, INTENT(IN) :: KTCOUNT                   ! counter value of the
+                                                 ! model temporal loop
+INTEGER, INTENT(IN) :: KMI                       ! Model index
+REAL, INTENT(IN)    :: PRELAX                    ! relaxation coefficient for
+                                                 ! the Richardson's method
+!
+REAL, DIMENSION(:,:,:), INTENT(IN) :: PRHODJ     ! density of reference state
+                                                 ! * J
+!
+REAL, DIMENSION(:,:,:), INTENT(IN) :: PDXX,PDYY,PDZZ,PDZX,PDZY ! metric coefficients
+!
+REAL, INTENT(IN) :: PDXHATM                     ! mean grid increment in the x
+                                                ! direction
+REAL, INTENT(IN) :: PDYHATM                     ! mean grid increment in the y
+                                                ! direction
+!
+REAL, DIMENSION (:), INTENT(IN) :: PRHOT         !  mean of XRHODJ on the plane x y
+                                                 !  localized at a mass level
+!
+REAL, DIMENSION(:), INTENT(IN)     :: PAF,PCF    ! vectors giving the nonvanishing
+REAL, DIMENSION(:,:,:), INTENT(IN) :: PBF        ! elements of the tri-diag y-slide .
+                                                 ! matrix in the pressure eq.
+!
+                                                 ! arrays of sin or cos values
+                                                 ! for the FFT :
+REAL, DIMENSION(:), INTENT(IN) :: PTRIGSX        ! - along x
+REAL, DIMENSION(:), INTENT(IN) :: PTRIGSY        ! - along y
+!
+                                                 ! decomposition in prime
+                                                 ! numbers for the FFT:
+INTEGER, DIMENSION(19), INTENT(IN) :: KIFAXX      ! - along x
+INTEGER, DIMENSION(19), INTENT(IN) :: KIFAXY      ! - along y
+!
+INTEGER,                  INTENT(IN)    :: KRR   ! Total number of water var.
+INTEGER,                  INTENT(IN)    :: KRRL  ! Number of liquid water var.
+INTEGER,                  INTENT(IN)    :: KRRI  ! Number of ice water var.
+!
+REAL,                     INTENT(IN)    :: PDRYMASST   ! Mass of dry air and of
+REAL,                     INTENT(IN)    :: PREFMASS    ! the ref. atmosphere
+REAL,                     INTENT(IN)    :: PMASS_O_PHI0 !    Mass / Phi0
+!
+REAL, DIMENSION(:,:,:),   INTENT(IN)    :: PTHT       ! Temperature and water
+REAL, DIMENSION(:,:,:,:), INTENT(IN)    :: PRT        !  variables at time t
+!
+REAL, DIMENSION(:,:,:),   INTENT(IN)    :: PRHODREF    ! dry Density
+REAL, DIMENSION(:,:,:),   INTENT(IN)    :: PTHVREF     ! Virtual Temperature
+                                                       ! of the reference state
+REAL, DIMENSION(:,:,:),   INTENT(IN)    :: PRVREF      ! mixing ratio of the
+                                                       ! reference state
+REAL, DIMENSION(:,:,:),   INTENT(IN)    :: PEXNREF     ! Exner function
+                                                       ! of the reference state
+REAL,                     INTENT(IN)    :: PLINMASS    ! lineic mass through
+                                                       ! open boundaries
+!
+REAL,       INTENT(INOUT) :: PRUS(:,:,:)         ! source term along x
+REAL,       INTENT(INOUT) :: PRVS(:,:,:)         ! source term along y
+REAL,       INTENT(INOUT) :: PRWS(:,:,:)         ! source term along z
+!
+REAL,       INTENT(INOUT)   :: PPABST(:,:,:)        ! pressure(t)
+!
+!JUAN Z_SPLITING
+REAL, DIMENSION(:,:,:), INTENT(IN) :: PBFB       ! elements of the tri-diag b-slide .
+                                                 ! matrix in the pressure eq.
+REAL, DIMENSION(:,:,:), INTENT(IN) :: PBF_SXP2_YP1_Z       ! elements of the tri-diag. SXP2_YP1_Z-slide 
+                                                   ! matrix in the pressure eq.
+REAL, DIMENSION(:,:,:), INTENT(IN) :: PAF_ZS,PBF_ZS,PCF_ZS
+REAL, DIMENSION(:,:)  , INTENT(IN) :: PDXATH_ZS,PDYATH_ZS
+REAL, DIMENSION(:,:,:), INTENT(IN) :: PRHO_ZS
+REAL, DIMENSION(:)    , INTENT(IN) :: A_K,B_K,C_K,D_K
+
+REAL, OPTIONAL                     :: PRESIDUAL
+!JUAN Z_SPLITING
+!
+!*       0.2   declarations of local variables
+!
+!                                                           Metric coefficients:
+!
+REAL, DIMENSION(SIZE(PPABST,1),SIZE(PPABST,2),SIZE(PPABST,3)) :: ZDV_SOURCE
+!                                                   ! divergence of the sources
+!
+INTEGER :: IIB          ! indice I for the first inner mass point along x
+INTEGER :: IIE          ! indice I for the last inner mass point along x
+INTEGER :: IJB          ! indice J for the first inner mass point along y
+INTEGER :: IJE          ! indice J for the last inner mass point along y
+INTEGER :: IKB          ! indice K for the first inner mass point along z
+INTEGER :: IKE          ! indice K for the last inner mass point along z
+INTEGER :: ILUOUT       ! Logical unit of output listing
+INTEGER :: IRESP        ! Return code of FM routines
+!
+REAL, DIMENSION(SIZE(PPABST,1),SIZE(PPABST,2),SIZE(PPABST,3)) :: ZTHETAV, &
+                        ! virtual potential temperature
+                                                                 ZPHIT
+                        ! MAE + DUR => Exner function perturbation
+                        ! LHE       => Exner function perturbation * CPD * THVREF
+!
+REAL            :: ZRV_OV_RD !  XRV / XRD
+REAL                  :: ZMAXVAL, ZMAXRES, ZMAX,ZMAX_ll ! for print
+INTEGER, DIMENSION(3) :: IMAXLOC ! purpose
+INTEGER         :: JWATER          ! loop index on water species
+INTEGER         :: IIU,IJU,IKU     ! array sizes in I,J,K
+INTEGER         :: JK              ! loop index on the vertical levels
+INTEGER         :: JI,JJ
+!
+REAL, DIMENSION(SIZE(PDXX,1),SIZE(PDXX,3)) :: ZPABS_S ! local pressure on southern side
+REAL, DIMENSION(SIZE(PDXX,1),SIZE(PDXX,3)) :: ZPABS_N ! local pressure on northern side
+REAL, DIMENSION(SIZE(PDYY,2),SIZE(PDXX,3)) :: ZPABS_E ! local pressure on eastern side
+REAL, DIMENSION(SIZE(PDYY,2),SIZE(PDXX,3)) :: ZPABS_W ! local pressure on western side
+INTEGER :: IINFO_ll,KINFO
+TYPE(LIST_ll), POINTER :: TZFIELDS_ll, TZFIELDS2_ll  ! list of fields to exchange
+!
+INTEGER :: IIB_I,IIE_I,IJB_I,IJE_I
+INTEGER :: IIMAX_ll,IJMAX_ll
+!
+!
+!------------------------------------------------------------------------------
+!-------------------------------------------------------------------------------
+!
+!*       1.      PRELIMINARIES
+!                -------------
+!
+ILUOUT = TLUOUT%NLU
+!
+CALL GET_GLOBALDIMS_ll (IIMAX_ll,IJMAX_ll)
+IF ( ( MIN(IIMAX_ll,IJMAX_ll) < NPROC  ) .AND. ( HPRESOPT /= 'ZRESI' ) .AND. ( HPRESOPT /= 'ZSOLV' )) THEN
+   WRITE(UNIT=ILUOUT,FMT=*) 'ERROR IN PRESSUREZ:: YOU WANT TO USE TO MANY PROCESSOR WITHOUT CPRESOPT="ZRESI/ZSOLV" '
+   WRITE(UNIT=ILUOUT,FMT=*) 'MIN(IIMAX_ll,IJMAX_ll)=',MIN(IIMAX_ll,IJMAX_ll),' < NPROC =', NPROC
+   WRITE(UNIT=ILUOUT,FMT=*) 'YOU HAVE TO SET CPRESOPT="ZRESI => JOB ABORTED '
+   CALL PRINT_MSG(NVERB_FATAL,'GEN','PRESSUREZ','')
+ENDIF
+CALL GET_PHYSICAL_ll(IIB,IJB,IIE,IJE)
+CALL GET_DIM_EXT_ll('B',IIU,IJU)
+!
+IKB= 1+JPVEXT
+IKU= SIZE(PPABST,3)
+IKE= IKU - JPVEXT
+!
+ZPABS_S(:,:) = 0.
+ZPABS_N(:,:) = 0.
+ZPABS_E(:,:) = 0.
+ZPABS_W(:,:) = 0.
+!
+!
+!-------------------------------------------------------------------------------
+!
+!*       3.    COMPUTE THE LINEIC MASS
+!              -----------------------
+!
+IF ( ANY(HLBCX(:)=='OPEN') .OR. ANY(HLBCY(:)=='OPEN') ) THEN                     
+  CALL MASS_LEAK(PDXX,PDYY,HLBCX,HLBCY,PLINMASS,PRHODJ,PRUS,PRVS)
+END IF
+!
+!-------------------------------------------------------------------------------
+!
+!*       4.    COMPUTE THE FORCING TERM FOR THE PRESSURE EQUATION
+!              --------------------------------------------------
+!
+!
+CALL MPPDB_CHECK3D(PRUS,"pressurez 4-before update_halo_ll::PRUS",PRECISION)
+CALL MPPDB_CHECK3D(PRVS,"pressurez 4-before update_halo_ll::PRVS",PRECISION)
+CALL MPPDB_CHECK3D(PRWS,"pressurez 4-before update_halo_ll::PRWS",PRECISION)
+NULLIFY(TZFIELDS_ll)
+CALL ADD3DFIELD_ll( TZFIELDS_ll, PRUS, 'PRESSUREZ::PRUS' )
+CALL ADD3DFIELD_ll( TZFIELDS_ll, PRVS, 'PRESSUREZ::PRVS' )
+CALL ADD3DFIELD_ll( TZFIELDS_ll, PRWS, 'PRESSUREZ::PRWS' )
+CALL UPDATE_HALO_ll(TZFIELDS_ll,IINFO_ll)
+CALL CLEANLIST_ll(TZFIELDS_ll)
+CALL MPPDB_CHECK3D(PRUS,"pressurez 4-after update_halo_ll::PRUS",PRECISION)
+CALL MPPDB_CHECK3D(PRVS,"pressurez 4-after update_halo_ll::PRVS",PRECISION)
+CALL MPPDB_CHECK3D(PRWS,"pressurez 4-after update_halo_ll::PRWS",PRECISION)
+!
+CALL GDIV(HLBCX,HLBCY,PDXX,PDYY,PDZX,PDZY,PDZZ,PRUS,PRVS,PRWS,ZDV_SOURCE)
+!
+! The non-homogenous Neuman problem is transformed in an homogenous Neuman
+! problem in the non-periodic cases
+IF (HLBCX(1) /= 'CYCL') THEN
+  IF (LWEST_ll()) ZDV_SOURCE(IIB-1,:,:) = 0.
+  IF (LEAST_ll()) ZDV_SOURCE(IIE+1,:,:) = 0.
+ENDIF
+!
+IF (.NOT. L2D .AND. HLBCY(1) /= 'CYCL') THEN
+  IF (LSOUTH_ll()) ZDV_SOURCE(:,IJB-1,:) = 0.
+  IF (LNORTH_ll()) ZDV_SOURCE(:,IJE+1,:) = 0.
+ENDIF
+!
+!-------------------------------------------------------------------------------
+!
+!*       5.    SOLVE THE PRESSURE EQUATION
+!              ---------------------------
+!
+!
+!*       5.1   Compute the virtual theta and the pressure perturbation
+!              -------------------------------------------------------
+!
+IF(CEQNSYS=='MAE' .OR. CEQNSYS=='DUR') THEN
+  IF(KRR > 0) THEN
+  !
+  !   compute the ratio : 1 + total water mass / dry air mass
+    ZRV_OV_RD = XRV / XRD
+    ZTHETAV(:,:,:) = 1. + PRT(:,:,:,1)
+    DO JWATER = 2 , 1+KRRL+KRRI
+      ZTHETAV(:,:,:) = ZTHETAV(:,:,:) + PRT(:,:,:,JWATER)
+    END DO
+  !   compute the virtual potential temperature when water is present in any
+  !   form
+    ZTHETAV(:,:,:) = PTHT(:,:,:) * (1. + PRT(:,:,:,1) * ZRV_OV_RD) / ZTHETAV(:,:,:)
+  ELSE
+  !   compute the virtual potential temperature when water is absent
+    ZTHETAV(:,:,:) = PTHT(:,:,:)
+  END IF
+  !
+  ZPHIT(:,:,:)=(PPABST(:,:,:)/XP00)**(XRD/XCPD)-PEXNREF(:,:,:)
+  !
+ELSEIF(CEQNSYS=='LHE') THEN
+  ZPHIT(:,:,:)= ((PPABST(:,:,:)/XP00)**(XRD/XCPD)-PEXNREF(:,:,:))   &
+               * XCPD * PTHVREF(:,:,:)
+  !
+END IF
+!
+IF(CEQNSYS=='LHE'.AND. LFLAT .AND. LCARTESIAN) THEN
+   ! flat cartesian LHE case -> exact solution
+ IF ( HPRESOPT /= "ZRESI" ) THEN
+  CALL FLAT_INV(HLBCX,HLBCY,PDXHATM,PDYHATM,PRHOT,PAF,PBF,PCF,         &
+               PTRIGSX,PTRIGSY,KIFAXX,KIFAXY,ZDV_SOURCE,ZPHIT)
+ ELSE
+  CALL FLAT_INVZ(HLBCX,HLBCY,PDXHATM,PDYHATM,PRHOT,PAF,PBF,PCF,         &
+               PTRIGSX,PTRIGSY,KIFAXX,KIFAXY,ZDV_SOURCE,ZPHIT,& 
+               PBFB,&
+               PBF_SXP2_YP1_Z)
+ ENDIF
+ELSE
+  SELECT CASE(HPRESOPT)
+  CASE('RICHA')     ! Richardson's method
+!
+    CALL RICHARDSON(HLBCX,HLBCY,PDXX,PDYY,PDZX,PDZY,PDZZ,PRHODJ,ZTHETAV,      &
+    PDXHATM,PDYHATM,PRHOT,PAF,PBF,PCF,PTRIGSX,PTRIGSY,                        &
+    KIFAXX,KIFAXY,KITR,KTCOUNT,PRELAX,ZDV_SOURCE,ZPHIT)
+!
+   CASE('CGRAD')     ! Conjugate Gradient method
+     CALL CONJGRAD(HLBCX,HLBCY,PDXX,PDYY,PDZX,PDZY,PDZZ,PRHODJ,ZTHETAV,       &
+     PDXHATM,PDYHATM,PRHOT,PAF,PBF,PCF,PTRIGSX,PTRIGSY,                       &
+     KIFAXX,KIFAXY,KITR,ZDV_SOURCE,ZPHIT)
+  CASE('ZGRAD')     ! Conjugate Gradient method
+     CALL ZCONJGRAD(HLBCX,HLBCY,PDXX,PDYY,PDZX,PDZY,PDZZ,PRHODJ,ZTHETAV,       &
+     PDXHATM,PDYHATM,PRHOT,PAF,PBF,PCF,PTRIGSX,PTRIGSY,                       &
+     KIFAXX,KIFAXY,KITR,ZDV_SOURCE,ZPHIT)
+!
+  CASE('CRESI')     ! Conjugate Residual method
+    CALL CONRESOL(HLBCX,HLBCY,PDXX,PDYY,PDZX,PDZY,PDZZ,PRHODJ,ZTHETAV,       &
+    PDXHATM,PDYHATM,PRHOT,PAF,PBF,PCF,PTRIGSX,PTRIGSY,                       &
+    KIFAXX,KIFAXY,KITR,ZDV_SOURCE,ZPHIT)
+!
+  CASE('ZSOLV')     ! Conjugate Residual method
+    CALL ZSOLVER(HLBCX,HLBCY,PDXX,PDYY,PDZX,PDZY,PDZZ,PRHODJ,ZTHETAV,       &
+    PDXHATM,PDYHATM,PRHOT,PAF,PBF,PCF,PTRIGSX,PTRIGSY,                      &
+    KIFAXX,KIFAXY,KITR,ZDV_SOURCE,ZPHIT,                                    &
+    PAF_ZS,PBF_ZS,PCF_ZS,                                                   &
+    PDXATH_ZS,PDYATH_ZS,PRHO_ZS,PBFB,                                       &
+    A_K,B_K,C_K,D_K)
+!
+  CASE('ZRESI')     ! Conjugate Residual method
+    CALL CONRESOLZ(HLBCX,HLBCY,PDXX,PDYY,PDZX,PDZY,PDZZ,PRHODJ,ZTHETAV,       &
+    PDXHATM,PDYHATM,PRHOT,PAF,PBF,PCF,PTRIGSX,PTRIGSY,                       &
+    KIFAXX,KIFAXY,KITR,ZDV_SOURCE,ZPHIT,                                     &
+    PBFB,&
+    PBF_SXP2_YP1_Z) !JUAN Z_SPLITING
+  END SELECT
+END IF
+!
+!-------------------------------------------------------------------------------
+!
+!*       6.    ADD THE PRESSURE GRADIENT TO THE SOURCES
+!              ----------------------------------------
+!
+IF ( HLBCX(1) /= 'CYCL' ) THEN
+  IF(LWEST_ll()) ZPHIT(IIB-1,:,IKB-1) = ZPHIT(IIB,:,IKB-1)
+  IF(LEAST_ll()) ZPHIT(IIE+1,:,IKB-1) = ZPHIT(IIE,:,IKB-1)
+ENDIF
+IF ( HLBCY(1) /= 'CYCL' ) THEN
+  IF (LSOUTH_ll()) ZPHIT(:,IJB-1,IKB-1) = ZPHIT(:,IJB,IKB-1)
+  IF (LNORTH_ll()) ZPHIT(:,IJE+1,IKB-1) = ZPHIT(:,IJE,IKB-1)
+ENDIF
+!
+IF ( L2D ) THEN
+  IF (LSOUTH_ll()) ZPHIT(:,IJB-1,:) = ZPHIT(:,IJB,:)
+  IF (LNORTH_ll()) ZPHIT(:,IJE+1,:) = ZPHIT(:,IJB,:)
+END IF
+!
+ZDV_SOURCE = GX_M_U(1,IKU,1,ZPHIT,PDXX,PDZZ,PDZX)
+!
+IF ( HLBCX(1) /= 'CYCL' ) THEN
+  IF(LWEST_ll()) THEN
+!!!!!!!!!!!!!!!!  FUJI  compiler directive !!!!!!!!!!
+!!!!!!!!!!!!!!!!  FUJI  compiler directive !!!!!!!!!!
+    DO JK=2,IKU-1
+      ZDV_SOURCE(IIB,:,JK)=                                                    &
+       (ZPHIT(IIB,:,JK) - ZPHIT(IIB-1,:,JK) - 0.5 * (                              &
+        PDZX(IIB,:,JK)   * (ZPHIT(IIB,:,JK)-ZPHIT(IIB,:,JK-1)) / PDZZ(IIB,:,JK)      &
+       +PDZX(IIB,:,JK+1) * (ZPHIT(IIB,:,JK+1)-ZPHIT(IIB,:,JK)) / PDZZ(IIB,:,JK+1)    &
+                                              )                              &
+       ) / PDXX(IIB,:,JK)
+    END DO
+  ENDIF
+  !
+  IF(LEAST_ll()) THEN
+    DO JK=2,IKU-1
+      ZDV_SOURCE(IIE+1,:,JK)=                                                   &
+        (ZPHIT(IIE+1,:,JK) - ZPHIT(IIE+1-1,:,JK) - 0.5 * (                        &
+         PDZX(IIE+1,:,JK)   * (ZPHIT(IIE+1-1,:,JK)-ZPHIT(IIE+1-1,:,JK-1))           &
+                          / PDZZ(IIE+1-1,:,JK)                                  &
+        +PDZX(IIE+1,:,JK+1) * (ZPHIT(IIE+1-1,:,JK+1)-ZPHIT(IIE+1-1,:,JK))           &
+                          / PDZZ(IIE+1-1,:,JK+1)                                &
+                                                     )                        &
+        ) / PDXX(IIE+1,:,JK)
+    END DO
+  END IF
+END IF
+!
+CALL MPPDB_CHECK3DM("before MXM PRESSUREZ :PRU/V/WS",PRECISION,PRUS,PRVS,PRWS)
+IF(CEQNSYS=='MAE' .OR. CEQNSYS=='DUR') THEN
+  PRUS = PRUS - MXM(PRHODJ * XCPD * ZTHETAV) * ZDV_SOURCE
+  PRWS = PRWS - MZM(PRHODJ * XCPD * ZTHETAV) * GZ_M_W(1,IKU,1,ZPHIT,PDZZ)
+ELSEIF(CEQNSYS=='LHE') THEN
+  PRUS = PRUS - MXM(PRHODJ) * ZDV_SOURCE
+  PRWS = PRWS - MZM(PRHODJ) * GZ_M_W(1,IKU,1,ZPHIT,PDZZ)
+END IF
+!
+IF(.NOT. L2D) THEN
+!
+  ZDV_SOURCE = GY_M_V(1,IKU,1,ZPHIT,PDYY,PDZZ,PDZY)
+!
+  IF ( HLBCY(1) /= 'CYCL' ) THEN
+    IF (LSOUTH_ll()) THEN
+!!!!!!!!!!!!!!!!  FUJI  compiler directive !!!!!!!!!!
+!!!!!!!!!!!!!!!!  FUJI  compiler directive !!!!!!!!!!
+      DO JK=2,IKU-1
+        ZDV_SOURCE(:,IJB,JK)=                                                  &
+         (ZPHIT(:,IJB,JK) - ZPHIT(:,IJB-1,JK) - 0.5 * (                            &
+          PDZY(:,IJB,JK)   * (ZPHIT(:,IJB,JK)-ZPHIT(:,IJB,JK-1)) / PDZZ(:,IJB,JK)    &
+         +PDZY(:,IJB,JK+1) * (ZPHIT(:,IJB,JK+1)-ZPHIT(:,IJB,JK)) / PDZZ(:,IJB,JK+1)  &
+                                                )                            &
+         ) / PDYY(:,IJB,JK)
+      END DO
+    END IF
+    !
+    IF (LNORTH_ll()) THEN
+      DO JK=2,IKU-1
+        ZDV_SOURCE(:,IJE+1,JK)=                                                &
+         (ZPHIT(:,IJE+1,JK) - ZPHIT(:,IJE+1-1,JK) - 0.5 * (                      &
+          PDZY(:,IJE+1,JK)   * (ZPHIT(:,IJE+1-1,JK)-ZPHIT(:,IJE+1-1,JK-1))         &
+                           / PDZZ(:,IJE+1-1,JK)                                &
+         +PDZY(:,IJE+1,JK+1) * (ZPHIT(:,IJE+1-1,JK+1)-ZPHIT(:,IJE+1-1,JK))         &
+                           / PDZZ(:,IJE+1-1,JK+1)                              &
+                                                      )                      &
+        ) / PDYY(:,IJE+1,JK)
+      END DO
+    END IF
+  END IF
+!
+  CALL MPPDB_CHECK3DM("before MYM PRESSUREZ :PRU/V/WS",PRECISION,PRUS,PRVS,PRWS)
+  IF(CEQNSYS=='MAE' .OR. CEQNSYS=='DUR') THEN
+    PRVS = PRVS - MYM(PRHODJ * XCPD * ZTHETAV) * ZDV_SOURCE
+  ELSEIF(CEQNSYS=='LHE') THEN
+    PRVS = PRVS - MYM(PRHODJ) * ZDV_SOURCE
+  END IF
+END IF
+!
+!! same boundary conditions as in gdiv ... !! (provisory coding)
+!! (necessary when NVERB=1)
+!!
+    PRUS(:,:,IKB-1)=PRUS(:,:,IKB)
+    PRUS(:,:,IKE+1)=PRUS(:,:,IKE)
+    PRVS(:,:,IKB-1)=PRVS(:,:,IKB)
+    PRVS(:,:,IKE+1)=PRVS(:,:,IKE)
+!
+NULLIFY(TZFIELDS2_ll)
+CALL ADD3DFIELD_ll( TZFIELDS2_ll, PRUS, 'PRESSUREZ::PRUS' )
+CALL ADD3DFIELD_ll( TZFIELDS2_ll, PRVS, 'PRESSUREZ::PRVS' )
+CALL ADD3DFIELD_ll( TZFIELDS2_ll, PRWS, 'PRESSUREZ::PRWS' )
+CALL UPDATE_HALO_ll(TZFIELDS2_ll,IINFO_ll)
+CALL CLEANLIST_ll(TZFIELDS2_ll)
+!
+!  compute the residual divergence
+CALL GDIV(HLBCX,HLBCY,PDXX,PDYY,PDZX,PDZY,PDZZ,PRUS,PRVS,PRWS,ZDV_SOURCE)
+!
+IF ( CEQNSYS=='DUR' ) THEN
+  IF ( SIZE(PRVREF,1) == 0 ) THEN
+    ZDV_SOURCE=ZDV_SOURCE/PRHODJ/XTH00*PRHODREF*PTHVREF
+  ELSE
+    ZDV_SOURCE=ZDV_SOURCE/PRHODJ/XTH00*PRHODREF*PTHVREF*(1.+PRVREF)
+  END IF
+ELSEIF( CEQNSYS=='MAE' .OR. CEQNSYS=='LHE' ) THEN
+  ZDV_SOURCE=ZDV_SOURCE/PRHODJ*PRHODREF
+END IF
+!
+ZMAXVAL=MAX_ll(ABS(ZDV_SOURCE),IINFO_ll)
+!JUANZ
+IF (PRESENT(PRESIDUAL)) PRESIDUAL = ZMAXVAL
+!JUANZ
+IMAXLOC=GMAXLOC_ll( ABS(ZDV_SOURCE) )
+!
+WRITE(ILUOUT,*) 'residual divergence / 2 DT', ZMAXVAL,     &
+                ' located at ',   IMAXLOC
+FLUSH(unit=ILUOUT)
+IF (ABS(ZMAXVAL) .GT. 100.0 ) THEN
+   call Print_msg( NVERB_FATAL, 'GEN', 'PRESSUREZ', 'something wrong with pressure: abs(residual) > 100.0' )
+END IF
+! number of iterations adjusted
+IF (LRES) THEN
+   ZMAXRES = XRES
+ELSEIF (LFLAT .AND. LCARTESIAN) THEN
+  ZMAXRES = XRES_FLAT_CART
+ELSE
+  ZMAXRES = XRES_OTHER
+END IF
+!
+IF (OITRADJ) THEN
+  IF (ZMAXVAL>10.*ZMAXRES) THEN
+    KITR=KITR+2
+    WRITE(ILUOUT,*) 'NITR adjusted to ', KITR
+  ELSE IF (ZMAXVAL<ZMAXRES) THEN
+    KITR=MAX(KITR-1,1)
+    WRITE(ILUOUT,*) 'NITR adjusted to ', KITR
+  ENDIF
+ENDIF
+!
+!*       7.    STORAGE OF THE FIELDS IN BUDGET ARRAYS
+!              --------------------------------------
+!
+IF (LBUDGET_U) CALL BUDGET (PRUS,1,'PRES_BU_RU')
+IF (LBUDGET_V) CALL BUDGET (PRVS,2,'PRES_BU_RV')
+IF (LBUDGET_W) CALL BUDGET (PRWS,3,'PRES_BU_RW')
+!
+!-------------------------------------------------------------------------------
+!
+!*       8.    ABSOLUTE PRESSURE COMPUTATION
+!              -----------------------------
+!
+ZMAX = MAXVAL(ABS ( PRHODREF(:,:,IKB)-PRHODREF(:,:,IKE)) )
+CALL MPI_ALLREDUCE(ZMAX, ZMAX_ll, 1, MNHREAL_MPI, MPI_MAX,  &
+                   NMNH_COMM_WORLD, KINFO)
+!IF (      ABS(PRHODREF(IIB,IJB,IKB)-PRHODREF(IIB,IJB,IKE)) > 1.E-12 &
+!  .AND. KTCOUNT >0 ) THEN
+IF ((ZMAX_ll > 1.E-12) .AND. KTCOUNT >0 ) THEN 
+!IF (  KTCOUNT >0 .AND. .NOT.LBOUSS ) THEN
+  CALL P_ABS   ( KRR, KRRL, KRRI, PDRYMASST, PREFMASS, PMASS_O_PHI0, &
+                 PTHT, PRT, PRHODJ, PRHODREF, ZTHETAV, PTHVREF,      &
+                 PRVREF, PEXNREF,  ZPHIT                             )
+!
+  IF(CEQNSYS=='MAE' .OR. CEQNSYS=='DUR') THEN
+    PPABST(:,:,:)=XP00*(ZPHIT+PEXNREF)**(XCPD/XRD)
+  ELSEIF(CEQNSYS=='LHE') THEN
+    PPABST(:,:,:)=XP00*(ZPHIT/(XCPD*PTHVREF)+PEXNREF)**(XCPD/XRD)
+  ENDIF
+!
+  IF( HLBCX(1) == 'CYCL' ) THEN
+   IF (LWEST_ll()) THEN
+       ZPABS_W(:,:)= PPABST(IIB,:,:)
+   END IF
+!
+   IF (LEAST_ll()) THEN
+       ZPABS_E(:,:)= PPABST(IIE+1,:,:)
+   END IF
+!
+  END IF
+!
+  IF( HLBCY(1) == 'CYCL' ) THEN
+   IF (LSOUTH_ll()) THEN
+      ZPABS_S(:,:)= PPABST(:,IJB,:)
+   END IF
+!
+   IF (LNORTH_ll()) THEN
+      ZPABS_N(:,:)= PPABST(:,IJE+1,:)
+   END IF
+!
+  END IF
+!
+  CALL ADD3DFIELD_ll( TZFIELDS_ll, PPABST, 'PRESSUREZ::PPABST' )
+  CALL UPDATE_HALO_ll(TZFIELDS_ll,IINFO_ll)
+  CALL CLEANLIST_ll(TZFIELDS_ll)
+!
+  IF( HLBCX(1) == 'CYCL' ) THEN
+   IF (LWEST_ll()) THEN
+       PPABST(IIB,:,:) = ZPABS_W(:,:)
+   END IF
+!
+   IF (LEAST_ll()) THEN
+       PPABST(IIE+1,:,:) = ZPABS_E(:,:)
+   END IF
+!
+  END IF
+!
+  IF( HLBCY(1) == 'CYCL' ) THEN
+   IF (LSOUTH_ll()) THEN
+      PPABST(:,IJB,:) = ZPABS_S(:,:)
+   END IF
+!
+   IF (LNORTH_ll()) THEN
+      PPABST(:,IJE+1,:) = ZPABS_N(:,:)
+   END IF
+!
+  END IF
+!
+END IF
+!
+!-------------------------------------------------------------------------------
+!
+END SUBROUTINE PRESSUREZ
diff --git a/src/ZSOLVER/read_exsegn.f90 b/src/ZSOLVER/read_exsegn.f90
new file mode 100644
index 0000000000000000000000000000000000000000..85e867132c14957b8d40a881ad9fe9d337879228
--- /dev/null
+++ b/src/ZSOLVER/read_exsegn.f90
@@ -0,0 +1,2853 @@
+!MNH_LIC Copyright 1994-2019 CNRS, Meteo-France and Universite Paul Sabatier
+!MNH_LIC This is part of the Meso-NH software governed by the CeCILL-C licence
+!MNH_LIC version 1. See LICENSE, CeCILL-C_V1-en.txt and CeCILL-C_V1-fr.txt
+!MNH_LIC for details. version 1.
+!-----------------------------------------------------------------
+!     ###################### 
+      MODULE MODI_READ_EXSEG_n
+!     ######################
+!
+INTERFACE
+!
+      SUBROUTINE READ_EXSEG_n(KMI,TPEXSEGFILE,HCONF,OFLAT,OUSERV,                  &
+                   OUSERC,OUSERR,OUSERI,OUSECI,OUSERS,OUSERG,OUSERH,               &
+                   OUSECHEM,OUSECHAQ,OUSECHIC,OCH_PH,OCH_CONV_LINOX,OSALT,         &
+                   ODEPOS_SLT, ODUST,ODEPOS_DST, OCHTRANS,                         &
+                   OORILAM,ODEPOS_AER, OLG,OPASPOL,                                &
+#ifdef MNH_FOREFIRE
+                   OFOREFIRE,                                                      &
+#endif
+                   OLNOX_EXPLICIT,                                                 &
+                   OCONDSAMP,OBLOWSNOW,                                            &
+                   KRIMX,KRIMY, KSV_USER,                                          &
+                   HTURB,HTOM,ORMC01,HRAD,HDCONV,HSCONV,HCLOUD,HELEC,              &
+                   HEQNSYS,PTSTEP_ALL,HSTORAGE_TYPE,HINIFILEPGD                    )
+!
+USE MODD_IO,   ONLY: TFILEDATA
+!
+INTEGER,            INTENT(IN) :: KMI    ! Model index
+TYPE(TFILEDATA),    INTENT(IN) :: TPEXSEGFILE ! EXSEG file
+!     The following variables are read by READ_DESFM in DESFM descriptor : 
+CHARACTER (LEN=*),  INTENT(IN) :: HCONF  ! configuration var. linked to FMfile
+LOGICAL,            INTENT(IN) :: OFLAT  ! Logical for zero orography
+LOGICAL,            INTENT(IN) :: OUSERV,OUSERC,OUSERR,OUSERI,OUSERS, &
+                                  OUSERG,OUSERH  ! kind of moist variables in 
+                                                 ! FMfile
+LOGICAL,            INTENT(IN) :: OUSECI         ! ice concentration in
+                                                 ! FMfile
+LOGICAL,            INTENT(IN) :: OUSECHEM       ! Chemical FLAG in FMFILE
+LOGICAL,            INTENT(IN) :: OUSECHAQ       ! Aqueous chemical FLAG in FMFILE
+LOGICAL,            INTENT(IN) :: OUSECHIC       ! Ice chemical FLAG in FMFILE
+LOGICAL,            INTENT(IN) :: OCH_PH         ! pH FLAG in FMFILE
+LOGICAL,            INTENT(IN) :: OCH_CONV_LINOX ! LiNOx FLAG in FMFILE
+LOGICAL,            INTENT(IN) :: ODUST          ! Dust FLAG in FMFILE
+LOGICAL,DIMENSION(:), INTENT(IN)  :: ODEPOS_DST  ! Dust wet deposition FLAG in FMFILE     
+LOGICAL,DIMENSION(:), INTENT(IN)  :: ODEPOS_SLT  ! Sea Salt wet deposition FLAG in FMFILE     
+LOGICAL,DIMENSION(:), INTENT(IN)  :: ODEPOS_AER  ! Orilam wet deposition FLAG in FMFILE     
+LOGICAL,            INTENT(IN) :: OSALT          ! Sea Salt FLAG in FMFILE
+LOGICAL,            INTENT(IN) :: OORILAM        ! Orilam FLAG in FMFILE
+LOGICAL,            INTENT(IN) :: OPASPOL        ! Passive pollutant FLAG in FMFILE
+#ifdef MNH_FOREFIRE
+LOGICAL,            INTENT(IN) :: OFOREFIRE      ! ForeFire FLAG in FMFILE
+#endif
+LOGICAL,            INTENT(IN) :: OLNOX_EXPLICIT ! explicit LNOx FLAG in FMFILE
+LOGICAL,            INTENT(IN) :: OCONDSAMP      ! Conditional sampling FLAG in FMFILE
+LOGICAL,            INTENT(IN) :: OBLOWSNOW     ! Blowing snow FLAG in FMFILE
+LOGICAL,            INTENT(IN) :: OCHTRANS       ! LCHTRANS FLAG in FMFILE
+
+LOGICAL,            INTENT(IN) :: OLG            ! lagrangian FLAG in FMFILE
+INTEGER,            INTENT(IN) :: KRIMX, KRIMY   ! number of points for the
+                       ! horizontal relaxation for the outermost verticals
+INTEGER,            INTENT(IN) :: KSV_USER    ! number of additional scalar
+                                         ! variables in FMfile 
+CHARACTER (LEN=*),  INTENT(IN) :: HTURB  ! Kind of turbulence parameterization
+                                         ! used to  produce FMFILE
+CHARACTER (LEN=*),  INTENT(IN) :: HTOM   ! Kind of third order moment
+LOGICAL,            INTENT(IN) :: ORMC01 ! flag for RMC01 SBL computations
+CHARACTER (LEN=*),  INTENT(IN) :: HRAD   ! Kind of radiation scheme
+CHARACTER (LEN=4),  INTENT(IN) :: HDCONV ! Kind of deep convection scheme
+CHARACTER (LEN=4),  INTENT(IN) :: HSCONV ! Kind of shallow convection scheme
+CHARACTER (LEN=4),  INTENT(IN) :: HCLOUD ! Kind of microphysical scheme
+CHARACTER (LEN=4),  INTENT(IN) :: HELEC  ! Kind of electrical scheme
+CHARACTER (LEN=*),  INTENT(IN) :: HEQNSYS! type of equations' system
+REAL,DIMENSION(:),  INTENT(INOUT):: PTSTEP_ALL ! Time STEP of ALL models
+CHARACTER (LEN=*),  INTENT(IN) :: HSTORAGE_TYPE ! type of initial file
+CHARACTER (LEN=*),  INTENT(IN) :: HINIFILEPGD ! name of PGD file
+!
+END SUBROUTINE READ_EXSEG_n
+!
+END INTERFACE
+!
+END MODULE MODI_READ_EXSEG_n
+!
+!
+!     #########################################################################
+      SUBROUTINE READ_EXSEG_n(KMI,TPEXSEGFILE,HCONF,OFLAT,OUSERV,                  &
+                   OUSERC,OUSERR,OUSERI,OUSECI,OUSERS,OUSERG,OUSERH,               &
+                   OUSECHEM,OUSECHAQ,OUSECHIC,OCH_PH,OCH_CONV_LINOX,OSALT,         &
+                   ODEPOS_SLT, ODUST,ODEPOS_DST, OCHTRANS,                         &
+                   OORILAM,ODEPOS_AER, OLG,OPASPOL,                                &
+#ifdef MNH_FOREFIRE
+                   OFOREFIRE,                                                      &
+#endif
+                   OLNOX_EXPLICIT,                                                 &
+                   OCONDSAMP, OBLOWSNOW,                                           &
+                   KRIMX,KRIMY, KSV_USER,                                          &
+                   HTURB,HTOM,ORMC01,HRAD,HDCONV,HSCONV,HCLOUD,HELEC,              &
+                   HEQNSYS,PTSTEP_ALL,HSTORAGE_TYPE,HINIFILEPGD                    )
+!     #########################################################################
+!
+!!****  *READ_EXSEG_n * - routine to read  the descriptor file EXSEG
+!!
+!!    PURPOSE
+!!    -------
+!       The purpose of this routine is to read the descriptor file called 
+!     EXSEG and to control the coherence with FMfile data . 
+!       
+!!
+!!**  METHOD
+!!    ------
+!!      The descriptor file is read. Namelists (NAMXXXn) which contain
+!!    variables linked to one nested model are at the beginning of the file.
+!!    Namelists (NAMXXX) which contain variables common to all models
+!!    are at the end of the file. When the  model index is different from 1, 
+!!    the end of the file (namelists NAMXXX) is not read. 
+!!
+!!      Coherence between the initial file (description read in DESFM file)
+!!    and the segment to perform (description read in EXSEG file)
+!!    is checked for segment achievement  configurations 
+!!    or  postprocessing configuration. The get indicators are set according 
+!!      to the following check :
+!!
+!!      - segment achievement and preinit configurations :
+!!
+!!       * if there is no turbulence kinetic energy in  initial
+!!      file (HTURB='NONE'), and the segment to perform requires a turbulence
+!!      parameterization (CTURB /= 'NONE'), the get indicators for turbulence 
+!!      kinetic energy variables are set to 'INIT'; i.e. these variables will be
+!!      set equal to  zero by READ_FIELD according to the get indicators.
+!!       * The same procedure is applied to the dissipation of TKE. 
+!!       * if there is no moist variables RRn  in  initial file (OUSERn=.FALSE.)
+!!      and the segment to perform requires  moist variables RRn
+!!      (LUSERn=.TRUE.),  the get indicators for moist variables RRn are set
+!!      equal to 'INIT'; i.e. these variables will be set equal to  zero by 
+!!      READ_FIELD according to the get indicators.
+!!       * if there are KSV_USER additional scalar variables in initial file and the
+!!      segment to perform needs more than KSV_USER additional variables,  the get
+!!      indicators for these (NSV_USER-KSV_USER) additional scalar variables are set 
+!!      equal to 'INIT'; i.e. these variables will be set equal to  zero by 
+!!      READ_FIELD according to the get indicators. If the segment to perform
+!!      needs less additional scalar variables than there are in initial file,
+!!      the get indicators for these (KSV_USER - NSV_USER) additional scalar variables are
+!!      set equal to 'SKIP'.      
+!!       * warning messages are printed if the fields in initial file are the
+!!      same at time t and t-dt (HCONF='START') and  a leap-frog advance 
+!!      at first time step will be used  for the segment to perform
+!!      (CCONF='RESTA'); It is likewise when HCONF='RESTA' and CCONF='START'.
+!!       * A warning message is printed if the orography in initial file is zero
+!!      (OFLAT=.TRUE.) and the segment to perform considers no-zero orography
+!!      (LFLAT=.FALSE.). It is likewise for LFLAT=.TRUE. and OFLAT=.FALSE..
+!!       If the segment to perform requires zero orography (LFLAT=.TRUE.), the
+!!       orography (XZS) will not read in initial file but  set equal to zero 
+!!       by SET_GRID.  
+!!       * check of the depths of the Lateral Damping Layer in x and y 
+!!       direction is performed
+!!       * If some coupling files are specified, LSTEADYLS is set to T
+!!       * If no coupling files are specified, LSTEADYLS is set to F
+!!
+!!
+!!    EXTERNAL
+!!    --------
+!!
+!!    IMPLICIT ARGUMENTS
+!!    ------------------
+!!     Module MODN_CONF : CCONF,LTHINSHELL,LFLAT,NMODEL,NVERB     
+!!
+!!      Module MODN_DYN : LCORIO, LZDIFFU
+!!
+!!      Module MODN_NESTING : NDAD(m),NDTRATIO(m),XWAY(m)
+!!
+!!      Module MODN_BUDGET : CBUTYPE,XBULEN
+!!
+!!      Module MODN_CONF1 : LUSERV,LUSERC,LUSERR,LUSERI,LUSERS,LUSERG,LUSERH,CSEG
+!!
+!!      Module MODN_DYN1 : XTSTEP,CPRESOPT,NITR,XRELAX
+!!
+!!      Module MODD_ADV1 : CMET_ADV_SCHEME,CSV_ADV_SCHEME,CUVW_ADV_SCHEME,NLITER
+!!
+!!      Module MODN_PARAM1 : CTURB,CRAD,CDCONV,CSCONV
+!!
+!!      Module MODN_LUNIT1 : 
+!!      Module MODN_LBC1 : CLBCX,CLBCY,NLBLX,NLBLY,XCPHASE,XPOND
+!!
+!!      Module MODN_TURB_n : CTURBLEN,CTURBDIM
+!!
+!!      Module MODD_GET1: 
+!!        CGETTKEM,CGETTKET,
+!!        CGETRVM,CGETRCM,CGETRRM,CGETRIM,CGETRSM,CGETRGM,CGETRHM
+!!        CGETRVT,CGETRCT,CGETRRT,CGETRIT,CGETRST,CGETRGT,CGETRHT,CGETSVM
+!!        CGETSVT,CGETSIGS,CGETSRCM,CGETSRCT 
+!!        NCPL_NBR,NCPL_TIMES,NCPL_CUR
+!!      Module MODN_LES  : contains declaration of the control parameters
+!!                                for Large Eddy Simulations' storages
+!!                                for the forcing
+!!
+!!    REFERENCE
+!!    ---------
+!!      Book2 of the  documentation (routine READ_EXSEG_n)
+!!      
+!!
+!!    AUTHOR
+!!    ------
+!!  	V. Ducrocq       * Meteo France *
+!!
+!!    MODIFICATIONS
+!!    -------------
+!!      Original    07/06/94 
+!!      Modification   26/10/94  (Stein)  remove NAM_GET from the Namelists
+!!      present in DESFM + change the namelist names
+!!      Modification   22/11/94  (Stein)  add GET indicator for phi
+!!      Modification   21/12/94  (Stein)  add GET indicator for LS fields  
+!!      Modification   06/01/95  (Stein)  bug in the test for Scalar Var.
+!!      Modifications  09/01/95  (Stein)  add the turbulence scheme
+!!      Modifications  09/01/95  (Stein)  add the 1D switch
+!!      Modifications  10/03/95  (Mallet) add coherence in coupling case
+!!      Modifications  16/03/95  (Stein)  remove R from the historical variables
+!!      Modifications  01/03/95  (Hereil) add the budget namelists
+!!      Modifications  16/06/95  (Stein)  coherence control for the
+!!                microphysical scheme + remove the wrong messge for RESTA conf
+!!      Modifications  30/06/95  (Stein)  conditionnal reading of the fields
+!!                used by the moist turbulence scheme
+!!      Modifications  12/09/95  (Pinty)  add the radiation scheme
+!!      Modification   06/02/96  (J.Vila) implement scalar advection schemes
+!!      Modifications  24/02/96  (Stein)  change the default value for CCPLFILE
+!!      Modifications  02/05/96  (Stein Jabouille) change the Z0SEA activation
+!!      Modifications  24/05/96  (Stein)  change the SRC SIGS control
+!!      Modifications  08/09/96  (Masson) the coupling file names are reset to
+!!                               default value " " before reading in EXSEG1.nam
+!!                               to avoid extra non-existant coupling files
+!!
+!!      Modifications  25/04/95  (K.Suhre)add namelist NAM_BLANK
+!!                                        add read for LFORCING
+!!                     25/04/95  (K.Suhre)add namelist NAM_FRC
+!!                                        and switch checking
+!!                     06/08/96  (K.Suhre)add namelist NAM_CH_MNHCn
+!!                                        and NAM_CH_SOLVER
+!!      Modifications  10/10/96  (Stein)  change SRC into SRCM and SRCT
+!!      Modifications  11/04/96  (Pinty)  add the rain-ice microphysical scheme
+!!      Modifications  11/01/97  (Pinty)  add the deep convection scheme
+!!      Modifications  22/05/97  (Lafore) gridnesting implementation
+!!      Modifications  22/06/97  (Stein)  add the absolute pressure + cleaning
+!!      Modifications  25/08/97  (Masson) add tests on surface schemes
+!!                     22/10/97  (Stein) remove the RIMX /= 0 control
+!!                                       + new namelist + cleaning
+!!      Modifications  17/04/98  (Masson) add tests on character variables
+!!      Modification   15/03/99  (Masson) add tests on PROGRAM
+!!      Modification   04/01/00  (Masson) removes TSZ0 case
+!!      Modification   04/06/00  (Pinty)  add C2R2 scheme
+!!                     11/12/00  (Tomasini) add CSEA_FLUX to MODD_PARAMn
+!!                                          delete the test on SST_FRC only in 1D
+!!      Modification   22/01/01  (Gazen)  change NSV,KSV to NSV_USER,KSV_USER and add
+!!                                        NSV_* variables initialization
+!!      Modification   15/10/01  (Mallet) allow namelists in different orders
+!!      Modification   18/03/02  (Solmon)  new radiation scheme test
+!!      Modification   29/11/02 (JP Pinty) add C3R5, ICE2, ICE4, ELEC
+!!      Modification   06/11/02  (Masson)  new LES BL height diagnostic
+!!      Modification   06/11/02  (Jabouille)  remove LTHINSHELL LFORCING test
+!!      Modification   01/12/03  (Gazen)   change Chemical scheme interface
+!!      Modification   01/2004   (Masson) removes surface (externalization)
+!!      Modification   01/2005   (Masson) removes 1D and 2D switches
+!!      Modification   04/2005   (Tulet)  add dust, orilam
+!!      Modification   03/2006   (O.Geoffroy) Add KHKO scheme
+!!      Modification   04/2006   (Maric)  include 4th order advection scheme
+!!      Modification   05/2006   (Masson) add nudging
+!!      Modification   05/2006   Remove KEPS
+!!      Modification   04/2006   (Maric)  include PPM advection scheme
+!!      Modification   04/2006   (J.Escobar) Bug dollarn add CALL UPDATE_NAM_CONFN  
+!!      Modifications  01/2007   (Malardel,Pergaud)  add the MF shallow
+!!                               convection scheme MODN_PARAM_MFSHALL_n
+!!      Modification   09/2009   (J.Escobar) add more info on relaxation problems
+!!      Modification   09/2011   (J.Escobar) re-add 'ZRESI' choose
+!!      Modification   12/2011   (C.Lac) Adaptation to FIT temporal scheme 
+!!      Modification   12/2012   (S.Bielli) add NAM_NCOUT for netcdf output (removed 08/07/2016)
+!!      Modification   02/2012   (Pialat/Tulet) add ForeFire
+!!      Modification   02/2012   (T.Lunet) add of new Runge-Kutta methods
+!!      Modification   01/2015   (C. Barthe) add explicit LNOx
+!!      J.Escobar : 15/09/2015 : WENO5 & JPHEXT <> 1 
+!!      M.Leriche 18/12/2015 : bug chimie glace dans prep_real_case
+!!      Modification    01/2016  (JP Pinty) Add LIMA
+!!      Modification   02/2016   (M.Leriche) treat gas and aq. chemicals separately
+!!      P.Wautelet 08/07/2016 : removed MNH_NCWRIT define
+!!      Modification   10/2016    (C.LAC) Add OSPLIT_WENO + Add droplet
+!!                                deposition + Add max values
+!!      Modification   11/2016   (Ph. Wautelet) Allocate/initialise some output/backup structures
+!!      Modification   03/2017   (JP Chaboureau) Fix the initialization of
+!!                                               LUSERx-type variables for LIMA
+!!      M.Leriche      06/2017 for spawn and prep_real avoid abort if wet dep for 
+!!                             aerosol and no cloud scheme defined
+!!      Q.Libois       02/2018  ECRAD
+!!  Philippe Wautelet: 05/2016-04/2018: new data structures and calls for I/O
+!!      Modification   07/2017   (V. Vionnet) add blowing snow scheme
+!!      Modification   01/2019   (Q. Rodier) define XCEDIS depending on BL89 or RM17 mixing length
+!!      Modification   01/2019   (P. Wautelet) bugs correction: incorrect writes
+!!      Modification   01/2019   (R. Honnert) remove SURF in CMF_UPDRAFT
+!!      Bielli S. 02/2019  Sea salt : significant sea wave height influences salt emission; 5 salt modes
+!  P. Wautelet 10/04/2019: replace ABORT and STOP calls by Print_msg
+!!------------------------------------------------------------------------------
+!
+!*       0.    DECLARATIONS
+!              ------------
+USE MODD_PARAMETERS
+USE MODD_CONF
+USE MODD_CONFZ
+USE MODD_CONF_n,  ONLY: CSTORAGE_TYPE
+USE MODD_IO,   ONLY: TFILEDATA
+USE MODD_LUNIT_n, ONLY: TLUOUT
+USE MODD_VAR_ll,  ONLY: NPROC
+!
+USE MODN_BACKUP
+USE MODN_BUDGET
+USE MODN_LES
+USE MODN_CONF
+USE MODN_CONFZ
+USE MODN_FRC
+USE MODN_DYN
+USE MODN_NESTING
+USE MODN_OUTPUT
+USE MODN_CONF_n
+USE MODN_LBC_n      ! routine is used for each nested model. This has been done 
+USE MODN_DYN_n      ! to avoid the duplication of this routine for each model.
+USE MODN_ADV_n      ! The final filling of these modules for the model n is
+USE MODN_PARAM_n    ! realized in subroutine ini_model n
+USE MODN_PARAM_RAD_n
+USE MODN_PARAM_ECRAD_n
+USE MODN_PARAM_KAFR_n
+USE MODN_PARAM_MFSHALL_n
+USE MODN_PARAM_ICE
+USE MODN_LUNIT_n
+USE MODN_NUDGING_n
+USE MODN_TURB_n
+USE MODN_DRAG_n
+USE MODN_BLANK
+USE MODN_CH_MNHC_n
+USE MODN_CH_SOLVER_n
+USE MODN_PARAM_C2R2, ONLY : EPARAM_CCN=>HPARAM_CCN, EINI_CCN=>HINI_CCN, &
+                            WNUC=>XNUC, WALPHAC=>XALPHAC, NAM_PARAM_C2R2
+USE MODN_PARAM_C1R3, ONLY : NAM_PARAM_C1R3, CPRISTINE_ICE_C1R3,    &
+                            CHEVRIMED_ICE_C1R3
+USE MODN_PARAM_LIMA, ONLY : FINI_CCN=>HINI_CCN,NAM_PARAM_LIMA,NMOD_CCN,LSCAV, &
+                            CPRISTINE_ICE_LIMA, CHEVRIMED_ICE_LIMA, NMOD_IFN, &
+                            LCOLD, LACTI, LNUCL, XALPHAC, XNUC, LMEYERS, LHAIL
+USE MODN_ELEC
+USE MODN_SERIES
+USE MODN_SERIES_n 
+USE MODN_TURB_CLOUD
+USE MODN_TURB
+USE MODN_MEAN
+USE MODN_DRAGTREE
+USE MODN_LATZ_EDFLX
+!
+USE MODD_NSV,NSV_USER_n=>NSV_USER
+USE MODD_DYN
+USE MODD_DYN_n, ONLY : LHORELAX_SVLIMA
+USE MODD_GET_n
+USE MODD_GR_FIELD_n
+!
+USE MODE_POS
+USE MODE_MSG
+!
+USE MODI_TEST_NAM_VAR
+USE MODI_INI_NSV
+USE MODI_CH_INIT_SCHEME_n
+USE MODN_CH_ORILAM
+USE MODD_CH_AEROSOL
+USE MODD_DUST
+USE MODD_SALT
+USE MODD_PASPOL
+#ifdef MNH_FOREFIRE
+USE MODD_FOREFIRE
+USE MODN_FOREFIRE
+#endif
+USE MODD_CONDSAMP
+USE MODD_BLOWSNOW
+USE MODN_DUST
+USE MODN_SALT
+USE MODD_CH_M9_n, ONLY : NEQ
+USE MODN_PASPOL
+USE MODN_CONDSAMP
+USE MODN_BLOWSNOW
+USE MODN_BLOWSNOW_n
+USE MODN_2D_FRC
+USE MODN_VISCOSITY
+USE MODD_VISCOSITY
+USE MODD_DRAG_n
+!
+IMPLICIT NONE
+!
+!*       0.1   declarations of arguments
+!
+!
+!
+INTEGER,            INTENT(IN) :: KMI    ! Model index
+TYPE(TFILEDATA),    INTENT(IN) :: TPEXSEGFILE ! EXSEG file
+!     The following variables are read by READ_DESFM in DESFM descriptor : 
+CHARACTER (LEN=*),  INTENT(IN) :: HCONF  ! configuration var. linked to FMfile
+LOGICAL,            INTENT(IN) :: OFLAT  ! Logical for zero orography
+LOGICAL,            INTENT(IN) :: OUSERV,OUSERC,OUSERR,OUSERI,OUSERS, &
+                                  OUSERG,OUSERH  ! kind of moist variables in 
+                                                 ! FMfile
+LOGICAL,            INTENT(IN) :: OUSECI         ! ice concentration in
+                                                 ! FMfile
+LOGICAL,            INTENT(IN) :: OUSECHEM       ! Chemical FLAG in FMFILE
+LOGICAL,            INTENT(IN) :: OUSECHAQ       ! Aqueous chemical FLAG in FMFILE
+LOGICAL,            INTENT(IN) :: OUSECHIC       ! Ice chemical FLAG in FMFILE
+LOGICAL,            INTENT(IN) :: OCH_PH         ! pH FLAG in FMFILE
+LOGICAL,            INTENT(IN) :: OCH_CONV_LINOX ! LiNOx FLAG in FMFILE
+LOGICAL,            INTENT(IN) :: ODUST          ! Dust FLAG in FMFILE
+LOGICAL,DIMENSION(:), INTENT(IN) :: ODEPOS_DST   ! Dust Deposition FLAG in FMFILE
+LOGICAL,DIMENSION(:), INTENT(IN) :: ODEPOS_SLT   ! Sea Salt wet deposition FLAG in FMFILE     
+LOGICAL,DIMENSION(:), INTENT(IN) :: ODEPOS_AER   ! Orilam wet deposition FLAG in FMFILE     
+LOGICAL,            INTENT(IN) :: OSALT          ! Sea Salt FLAG in FMFILE
+LOGICAL,            INTENT(IN) :: OORILAM        ! Orilam FLAG in FMFILE
+LOGICAL,            INTENT(IN) :: OPASPOL        ! Passive pollutant FLAG in FMFILE
+#ifdef MNH_FOREFIRE
+LOGICAL,            INTENT(IN) :: OFOREFIRE      ! ForeFire FLAG in FMFILE
+#endif
+LOGICAL,            INTENT(IN) :: OLNOX_EXPLICIT ! explicit LNOx FLAG in FMFILE
+LOGICAL,            INTENT(IN) :: OCONDSAMP      ! Conditional sampling FLAG in FMFILE
+LOGICAL,            INTENT(IN) :: OCHTRANS       ! LCHTRANS FLAG in FMFILE
+LOGICAL,            INTENT(IN) :: OBLOWSNOW     ! Blowing snow FLAG in FMFILE
+
+LOGICAL,            INTENT(IN) :: OLG            ! lagrangian FLAG in FMFILE
+INTEGER,            INTENT(IN) :: KRIMX, KRIMY   ! number of points for the
+                       ! horizontal relaxation for the outermost verticals
+INTEGER,            INTENT(IN) :: KSV_USER    ! number of additional scalar
+                                         ! variables in FMfile 
+CHARACTER (LEN=*),  INTENT(IN) :: HTURB  ! Kind of turbulence parameterization
+                                         ! used to  produce FMFILE
+CHARACTER (LEN=*),  INTENT(IN) :: HTOM   ! Kind of third order moment
+LOGICAL,            INTENT(IN) :: ORMC01 ! flag for RMC01 SBL computations
+CHARACTER (LEN=*),  INTENT(IN) :: HRAD   ! Kind of radiation scheme
+CHARACTER (LEN=4),  INTENT(IN) :: HDCONV ! Kind of deep convection scheme
+CHARACTER (LEN=4),  INTENT(IN) :: HSCONV ! Kind of shallow convection scheme
+CHARACTER (LEN=4),  INTENT(IN) :: HCLOUD ! Kind of microphysical scheme
+CHARACTER (LEN=4),  INTENT(IN) :: HELEC  ! Kind of electrical scheme
+CHARACTER (LEN=*),  INTENT(IN) :: HEQNSYS! type of equations' system
+REAL,DIMENSION(:),  INTENT(INOUT):: PTSTEP_ALL ! Time STEP of ALL models
+CHARACTER (LEN=*),  INTENT(IN) :: HSTORAGE_TYPE ! type of initial file
+CHARACTER (LEN=*),  INTENT(IN) :: HINIFILEPGD ! name of PGD file
+!
+!*       0.2   declarations of local variables
+!
+INTEGER :: ILUSEG,ILUOUT ! logical unit numbers of EXSEG file and outputlisting
+INTEGER :: JS,JCI,JI,JSV       ! Loop indexes 
+LOGICAL :: GRELAX              
+LOGICAL :: GFOUND              ! Return code when searching namelist
+!
+INTEGER :: IMOMENTS, JMODE, IMODEIDX, JMOM, JSV_NAME, JMOD, I
+!
+!-------------------------------------------------------------------------------
+!
+!*       1.    READ EXSEG FILE
+!              ---------------
+!
+CALL PRINT_MSG(NVERB_DEBUG,'IO','READ_EXSEG_n','called for '//TRIM(TPEXSEGFILE%CNAME))
+!
+ILUSEG = TPEXSEGFILE%NLU
+ILUOUT = TLUOUT%NLU
+!
+CALL INIT_NAM_LUNITN
+CCPLFILE(:)="                            "
+CALL INIT_NAM_CONFN
+CALL INIT_NAM_DYNN
+CALL INIT_NAM_ADVN
+CALL INIT_NAM_PARAMN
+CALL INIT_NAM_PARAM_RADN
+#ifdef MNH_ECRAD
+CALL INIT_NAM_PARAM_ECRADN
+#endif
+CALL INIT_NAM_PARAM_KAFRN
+CALL INIT_NAM_PARAM_MFSHALLN
+CALL INIT_NAM_LBCN
+CALL INIT_NAM_NUDGINGN
+CALL INIT_NAM_TURBN
+CALL INIT_NAM_DRAGN
+CALL INIT_NAM_CH_MNHCN
+CALL INIT_NAM_CH_SOLVERN
+CALL INIT_NAM_SERIESN
+CALL INIT_NAM_BLOWSNOWN
+!
+WRITE(UNIT=ILUOUT,FMT="(/,'READING THE EXSEG.NAM FILE')")
+CALL POSNAM(ILUSEG,'NAM_LUNITN',GFOUND,ILUOUT)
+IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_LUNITn)
+CALL POSNAM(ILUSEG,'NAM_CONFN',GFOUND,ILUOUT)
+IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_CONFn)
+CALL POSNAM(ILUSEG,'NAM_DYNN',GFOUND,ILUOUT)
+IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_DYNn)
+CALL POSNAM(ILUSEG,'NAM_ADVN',GFOUND,ILUOUT)
+IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_ADVn)
+CALL POSNAM(ILUSEG,'NAM_PARAMN',GFOUND,ILUOUT)
+IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_PARAMn)
+CALL POSNAM(ILUSEG,'NAM_PARAM_RADN',GFOUND,ILUOUT)
+IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_PARAM_RADn)
+#ifdef MNH_ECRAD
+CALL POSNAM(ILUSEG,'NAM_PARAM_ECRADN',GFOUND,ILUOUT)
+IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_PARAM_ECRADn)
+#endif
+CALL POSNAM(ILUSEG,'NAM_PARAM_KAFRN',GFOUND,ILUOUT)
+IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_PARAM_KAFRn)
+CALL POSNAM(ILUSEG,'NAM_PARAM_MFSHALLN',GFOUND,ILUOUT)
+IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_PARAM_MFSHALLn)
+CALL POSNAM(ILUSEG,'NAM_LBCN',GFOUND,ILUOUT)
+IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_LBCn)
+CALL POSNAM(ILUSEG,'NAM_NUDGINGN',GFOUND,ILUOUT)
+IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_NUDGINGn)
+CALL POSNAM(ILUSEG,'NAM_TURBN',GFOUND,ILUOUT)
+IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_TURBn)
+CALL POSNAM(ILUSEG,'NAM_DRAGN',GFOUND,ILUOUT)
+IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_DRAGn)
+CALL POSNAM(ILUSEG,'NAM_CH_MNHCN',GFOUND,ILUOUT)
+IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_CH_MNHCn)
+CALL POSNAM(ILUSEG,'NAM_CH_SOLVERN',GFOUND,ILUOUT)
+IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_CH_SOLVERn)
+CALL POSNAM(ILUSEG,'NAM_SERIESN',GFOUND,ILUOUT)
+IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_SERIESn)
+CALL POSNAM(ILUSEG,'NAM_BLOWSNOWN',GFOUND,ILUOUT)
+IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_BLOWSNOWn)
+!
+IF (KMI == 1) THEN                                               
+  WRITE(UNIT=ILUOUT,FMT="(' namelists common to all the models ')")
+  CALL POSNAM(ILUSEG,'NAM_CONF',GFOUND,ILUOUT)
+  IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_CONF)
+  CALL POSNAM(ILUSEG,'NAM_CONFZ',GFOUND,ILUOUT)
+  IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_CONFZ)
+  CALL POSNAM(ILUSEG,'NAM_DYN',GFOUND,ILUOUT)
+  IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_DYN)
+  CALL POSNAM(ILUSEG,'NAM_NESTING',GFOUND,ILUOUT)
+  IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_NESTING)
+  CALL POSNAM(ILUSEG,'NAM_BACKUP',GFOUND,ILUOUT)
+  IF (GFOUND) THEN
+    !Should have been allocated before in READ_DESFM_n
+    IF (.NOT.ALLOCATED(XBAK_TIME)) THEN
+      ALLOCATE(XBAK_TIME(NMODEL,JPOUTMAX))
+      XBAK_TIME(:,:) = XNEGUNDEF
+    END IF
+    IF (.NOT.ALLOCATED(XOUT_TIME)) THEN
+      ALLOCATE(XOUT_TIME(NMODEL,JPOUTMAX)) !Allocate *OUT* variables to prevent
+      XOUT_TIME(:,:) = XNEGUNDEF
+    END IF
+    IF (.NOT.ALLOCATED(NBAK_STEP)) THEN
+      ALLOCATE(NBAK_STEP(NMODEL,JPOUTMAX))
+      NBAK_STEP(:,:) = NNEGUNDEF
+    END IF
+    IF (.NOT.ALLOCATED(NOUT_STEP)) THEN
+      ALLOCATE(NOUT_STEP(NMODEL,JPOUTMAX)) !problems if NAM_OUTPUT does not exist
+      NOUT_STEP(:,:) = NNEGUNDEF
+    END IF
+    IF (.NOT.ALLOCATED(COUT_VAR)) THEN
+      ALLOCATE(COUT_VAR (NMODEL,JPOUTVARMAX))
+      COUT_VAR(:,:)  = ''
+    END IF
+    READ(UNIT=ILUSEG,NML=NAM_BACKUP)
+  ELSE
+    CALL POSNAM(ILUSEG,'NAM_FMOUT',GFOUND)
+    IF (GFOUND) THEN
+      CALL PRINT_MSG(NVERB_FATAL,'IO','READ_EXSEG_n','use namelist NAM_BACKUP instead of namelist NAM_FMOUT')
+    ELSE
+      IF (CPROGRAM=='MESONH') CALL PRINT_MSG(NVERB_ERROR,'IO','READ_EXSEG_n','namelist NAM_BACKUP not found')
+    END IF
+  END IF
+  CALL POSNAM(ILUSEG,'NAM_OUTPUT',GFOUND,ILUOUT)
+  IF (GFOUND) THEN
+    !Should have been allocated before in READ_DESFM_n
+    IF (.NOT.ALLOCATED(XBAK_TIME)) THEN
+      ALLOCATE(XBAK_TIME(NMODEL,JPOUTMAX)) !Allocate *BAK* variables to prevent
+      XBAK_TIME(:,:) = XNEGUNDEF
+    END IF
+    IF (.NOT.ALLOCATED(XOUT_TIME)) THEN
+      ALLOCATE(XOUT_TIME(NMODEL,JPOUTMAX))
+      XOUT_TIME(:,:) = XNEGUNDEF
+    END IF
+    IF (.NOT.ALLOCATED(NBAK_STEP)) THEN
+      ALLOCATE(NBAK_STEP(NMODEL,JPOUTMAX)) !problems if NAM_BACKUP does not exist
+      NBAK_STEP(:,:) = NNEGUNDEF
+    END IF
+    IF (.NOT.ALLOCATED(NOUT_STEP)) THEN
+      ALLOCATE(NOUT_STEP(NMODEL,JPOUTMAX))
+      NOUT_STEP(:,:) = NNEGUNDEF
+    END IF
+    IF (.NOT.ALLOCATED(COUT_VAR)) THEN
+      ALLOCATE(COUT_VAR (NMODEL,JPOUTVARMAX))
+      COUT_VAR(:,:)  = ''
+    END IF
+    READ(UNIT=ILUSEG,NML=NAM_OUTPUT)
+  END IF
+  CALL POSNAM(ILUSEG,'NAM_BUDGET',GFOUND,ILUOUT)
+  IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_BUDGET)
+  CALL POSNAM(ILUSEG,'NAM_BU_RU',GFOUND,ILUOUT)
+  IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_BU_RU)
+  CALL POSNAM(ILUSEG,'NAM_BU_RV',GFOUND,ILUOUT)
+  IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_BU_RV)
+  CALL POSNAM(ILUSEG,'NAM_BU_RW',GFOUND,ILUOUT)
+  IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_BU_RW)
+  CALL POSNAM(ILUSEG,'NAM_BU_RTH',GFOUND,ILUOUT)
+  IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_BU_RTH)
+  CALL POSNAM(ILUSEG,'NAM_BU_RTKE',GFOUND,ILUOUT)
+  IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_BU_RTKE)
+  CALL POSNAM(ILUSEG,'NAM_BU_RRV',GFOUND,ILUOUT)
+  IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_BU_RRV)
+  CALL POSNAM(ILUSEG,'NAM_BU_RRC',GFOUND,ILUOUT)
+  IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_BU_RRC)
+  CALL POSNAM(ILUSEG,'NAM_BU_RRR',GFOUND,ILUOUT)
+  IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_BU_RRR)
+  CALL POSNAM(ILUSEG,'NAM_BU_RRI',GFOUND,ILUOUT)
+  IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_BU_RRI)
+  CALL POSNAM(ILUSEG,'NAM_BU_RRS',GFOUND,ILUOUT)
+  IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_BU_RRS)
+  CALL POSNAM(ILUSEG,'NAM_BU_RRG',GFOUND,ILUOUT)
+  IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_BU_RRG)
+  CALL POSNAM(ILUSEG,'NAM_BU_RRH',GFOUND,ILUOUT)
+  IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_BU_RRH)
+  CALL POSNAM(ILUSEG,'NAM_BU_RSV',GFOUND,ILUOUT)
+  IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_BU_RSV)
+  CALL POSNAM(ILUSEG,'NAM_LES',GFOUND,ILUOUT)
+  IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_LES)
+  CALL POSNAM(ILUSEG,'NAM_MEAN',GFOUND,ILUOUT)
+  IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_MEAN)
+  CALL POSNAM(ILUSEG,'NAM_PDF',GFOUND,ILUOUT)
+  IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_PDF)
+  CALL POSNAM(ILUSEG,'NAM_BLANK',GFOUND,ILUOUT)
+  IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_BLANK)
+  CALL POSNAM(ILUSEG,'NAM_FRC',GFOUND,ILUOUT)
+  IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_FRC)
+  CALL POSNAM(ILUSEG,'NAM_PARAM_ICE',GFOUND,ILUOUT)
+  IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_PARAM_ICE)
+  CALL POSNAM(ILUSEG,'NAM_PARAM_C2R2',GFOUND,ILUOUT)
+  IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_PARAM_C2R2)
+  CALL POSNAM(ILUSEG,'NAM_PARAM_C1R3',GFOUND,ILUOUT)
+  IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_PARAM_C1R3)
+  CALL POSNAM(ILUSEG,'NAM_PARAM_LIMA',GFOUND,ILUOUT)
+  IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_PARAM_LIMA)
+  CALL POSNAM(ILUSEG,'NAM_ELEC',GFOUND,ILUOUT)
+  IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_ELEC)
+  CALL POSNAM(ILUSEG,'NAM_SERIES',GFOUND,ILUOUT)
+  IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_SERIES)
+  CALL POSNAM(ILUSEG,'NAM_TURB_CLOUD',GFOUND,ILUOUT)
+  IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_TURB_CLOUD)
+  CALL POSNAM(ILUSEG,'NAM_TURB',GFOUND,ILUOUT)
+  IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_TURB)
+  CALL POSNAM(ILUSEG,'NAM_CH_ORILAM',GFOUND,ILUOUT)
+  IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_CH_ORILAM)
+  CALL POSNAM(ILUSEG,'NAM_DUST',GFOUND,ILUOUT)
+  IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_DUST)
+  CALL POSNAM(ILUSEG,'NAM_SALT',GFOUND,ILUOUT)
+  IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_SALT)
+  CALL POSNAM(ILUSEG,'NAM_PASPOL',GFOUND,ILUOUT)
+  IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_PASPOL)
+#ifdef MNH_FOREFIRE
+  CALL POSNAM(ILUSEG,'NAM_FOREFIRE',GFOUND,ILUOUT)
+  IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_FOREFIRE)
+#endif
+  CALL POSNAM(ILUSEG,'NAM_CONDSAMP',GFOUND,ILUOUT)
+  IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_CONDSAMP)
+  CALL POSNAM(ILUSEG,'NAM_DRAGTREE',GFOUND,ILUOUT)
+  IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_DRAGTREE)
+  CALL POSNAM(ILUSEG,'NAM_2D_FRC',GFOUND,ILUOUT)
+  IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_2D_FRC)
+  CALL POSNAM(ILUSEG,'NAM_LATZ_EDFLX',GFOUND)
+  IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_LATZ_EDFLX)
+  CALL POSNAM(ILUSEG,'NAM_BLOWSNOW',GFOUND,ILUOUT)
+  IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_BLOWSNOW)
+  CALL POSNAM(ILUSEG,'NAM_VISC',GFOUND,ILUOUT)
+  IF (GFOUND) READ(UNIT=ILUSEG,NML=NAM_VISC)
+END IF
+!
+!-------------------------------------------------------------------------------
+!
+CALL TEST_NAM_VAR(ILUOUT,'CPRESOPT',CPRESOPT,'RICHA','CGRAD','CRESI','ZRESI','ZSOLV',&
+                         'ZGRAD')
+!
+CALL TEST_NAM_VAR(ILUOUT,'CUVW_ADV_SCHEME',CUVW_ADV_SCHEME, &
+       'CEN4TH','CEN2ND','WENO_K' ) 
+CALL TEST_NAM_VAR(ILUOUT,'CMET_ADV_SCHEME',CMET_ADV_SCHEME, &
+      &'PPM_00','PPM_01','PPM_02')
+CALL TEST_NAM_VAR(ILUOUT,'CSV_ADV_SCHEME',CSV_ADV_SCHEME,   &
+      &'PPM_00','PPM_01','PPM_02')
+CALL TEST_NAM_VAR(ILUOUT,'CTEMP_SCHEME',CTEMP_SCHEME,       &
+  &'RK11','RK21','RK33','RKC4','RK53','RK4B','RK62','RK65','NP32','SP32','LEFR')
+!
+CALL TEST_NAM_VAR(ILUOUT,'CTURB',CTURB,'NONE','TKEL')
+CALL TEST_NAM_VAR(ILUOUT,'CRAD',CRAD,'NONE','FIXE','ECMW',&
+#ifdef MNH_ECRAD
+                 'ECRA',&
+#endif
+                 'TOPA')
+CALL TEST_NAM_VAR(ILUOUT,'CCLOUD',CCLOUD,'NONE','REVE','KESS',  &
+      & 'ICE3','ICE4','C2R2','C3R5','KHKO','LIMA')
+CALL TEST_NAM_VAR(ILUOUT,'CDCONV',CDCONV,'NONE','KAFR')
+CALL TEST_NAM_VAR(ILUOUT,'CSCONV',CSCONV,'NONE','KAFR','EDKF')
+CALL TEST_NAM_VAR(ILUOUT,'CELEC',CELEC,'NONE','ELE3','ELE4')
+!
+CALL TEST_NAM_VAR(ILUOUT,'CAER',CAER,'TANR','TEGE','SURF','NONE')
+CALL TEST_NAM_VAR(ILUOUT,'CAOP',CAOP,'CLIM','EXPL')
+CALL TEST_NAM_VAR(ILUOUT,'CLW',CLW,'RRTM','MORC')
+CALL TEST_NAM_VAR(ILUOUT,'CEFRADL',CEFRADL,'PRES','OCLN','MART','C2R2','LIMA')
+CALL TEST_NAM_VAR(ILUOUT,'CEFRADI',CEFRADI,'FX40','LIOU','SURI','C3R5','LIMA')
+CALL TEST_NAM_VAR(ILUOUT,'COPWLW',COPWLW,'SAVI','SMSH','LILI','MALA')
+CALL TEST_NAM_VAR(ILUOUT,'COPILW',COPILW,'FULI','EBCU','SMSH','FU98')
+CALL TEST_NAM_VAR(ILUOUT,'COPWSW',COPWSW,'SLIN','FOUQ','MALA')
+CALL TEST_NAM_VAR(ILUOUT,'COPISW',COPISW,'FULI','EBCU','FU96')
+!
+CALL TEST_NAM_VAR(ILUOUT,'CLBCX(1)',CLBCX(1),'CYCL','WALL','OPEN')
+CALL TEST_NAM_VAR(ILUOUT,'CLBCX(2)',CLBCX(2),'CYCL','WALL','OPEN')
+CALL TEST_NAM_VAR(ILUOUT,'CLBCY(1)',CLBCY(1),'CYCL','WALL','OPEN')
+CALL TEST_NAM_VAR(ILUOUT,'CLBCY(2)',CLBCY(2),'CYCL','WALL','OPEN')
+!
+CALL TEST_NAM_VAR(ILUOUT,'CTURBDIM',CTURBDIM,'1DIM','3DIM')
+CALL TEST_NAM_VAR(ILUOUT,'CTURBLEN',CTURBLEN,'DELT','BL89','RM17','DEAR','BLKR')
+CALL TEST_NAM_VAR(ILUOUT,'CTOM',CTOM,'NONE','TM06')
+CALL TEST_NAM_VAR(ILUOUT,'CSUBG_AUCV',CSUBG_AUCV,'NONE','CLFR','SIGM','PDF')
+!
+CALL TEST_NAM_VAR(ILUOUT,'CCH_TDISCRETIZATION',CCH_TDISCRETIZATION, &
+                 'SPLIT     ','CENTER    ','LAGGED    ')
+!
+CALL TEST_NAM_VAR(ILUOUT,'CCONF',CCONF,'START','RESTA')
+CALL TEST_NAM_VAR(ILUOUT,'CEQNSYS',CEQNSYS,'LHE','DUR','MAE')
+CALL TEST_NAM_VAR(ILUOUT,'CSPLIT',CSPLIT,'BSPLITTING','XSPLITTING','YSPLITTING')
+!
+CALL TEST_NAM_VAR(ILUOUT,'CBUTYPE',CBUTYPE,'NONE','CART','MASK')
+!
+CALL TEST_NAM_VAR(ILUOUT,'CRELAX_HEIGHT_TYPE',CRELAX_HEIGHT_TYPE,'FIXE','THGR')
+!
+CALL TEST_NAM_VAR(ILUOUT,'CLES_NORM_TYPE',CLES_NORM_TYPE,'NONE','CONV','EKMA','MOBU')
+CALL TEST_NAM_VAR(ILUOUT,'CBL_HEIGHT_DEF',CBL_HEIGHT_DEF,'TKE','KE','WTV','FRI','DTH')
+CALL TEST_NAM_VAR(ILUOUT,'CTURBLEN_CLOUD',CTURBLEN_CLOUD,'NONE','DEAR','DELT','BL89')
+!
+!   The test on the mass flux scheme for shallow convection
+!
+CALL TEST_NAM_VAR(ILUOUT,'CMF_UPDRAFT',CMF_UPDRAFT,'NONE','EDKF','RHCJ',&
+                   'HRIO','BOUT')
+CALL TEST_NAM_VAR(ILUOUT,'CMF_CLOUD',CMF_CLOUD,'NONE','STAT','DIRE')
+!
+!   The test on the CSOLVER name is made elsewhere
+!
+CALL TEST_NAM_VAR(ILUOUT,'CPRISTINE_ICE',CPRISTINE_ICE,'PLAT','COLU','BURO')
+CALL TEST_NAM_VAR(ILUOUT,'CSEDIM',CSEDIM,'SPLI','STAT','NONE')
+IF( CCLOUD == 'C3R5' ) THEN
+  CALL TEST_NAM_VAR(ILUOUT,'CPRISTINE_ICE_C1R3',CPRISTINE_ICE_C1R3, &
+                                                'PLAT','COLU','BURO')
+  CALL TEST_NAM_VAR(ILUOUT,'CHEVRIMED_ICE_C1R3',CHEVRIMED_ICE_C1R3, &
+                                                'GRAU','HAIL')
+END IF
+!
+IF( CCLOUD == 'LIMA' ) THEN
+  CALL TEST_NAM_VAR(ILUOUT,'CPRISTINE_ICE_LIMA',CPRISTINE_ICE_LIMA, &
+                                                'PLAT','COLU','BURO')
+  CALL TEST_NAM_VAR(ILUOUT,'CHEVRIMED_ICE_LIMA',CHEVRIMED_ICE_LIMA, &
+                                                'GRAU','HAIL')
+END IF
+IF(LBLOWSNOW) THEN
+       CALL TEST_NAM_VAR(ILUOUT,'CSNOWSEDIM',CSNOWSEDIM,'NONE','MITC','CARR','TABC')
+       IF (XALPHA_SNOW .NE. 3 .AND. CSNOWSEDIM=='TABC') THEN
+         WRITE(ILUOUT,*) '*****************************************'
+         WRITE(ILUOUT,*) '* XALPHA_SNW must be set to 3 when                '
+         WRITE(ILUOUT,*) '* CSNOWSEDIM = TABC                                 '
+         WRITE(ILUOUT,*) '* Update the look-up table in BLOWSNOW_SEDIM_LKT1D    '
+         WRITE(ILUOUT,*) '* to use TABC with a different value of XEMIALPHA_SNW'
+         WRITE(ILUOUT,*) '*****************************************'
+         !callabortstop
+         CALL PRINT_MSG(NVERB_FATAL,'GEN','READ_EXSEG_n','')
+       ENDIF
+END IF
+!
+!-------------------------------------------------------------------------------!
+!*       2.    FIRST INITIALIZATIONS
+!              ---------------------
+!
+!*       2.1   Time step in gridnesting case
+!
+IF (KMI /= 1 .AND. NDAD(KMI) /= KMI)  THEN
+  XTSTEP = PTSTEP_ALL(NDAD(KMI)) / NDTRATIO(KMI)
+END IF
+PTSTEP_ALL(KMI) = XTSTEP
+!
+!*       2.2    Fill the global configuration module 
+!
+! Check coherence between the microphysical scheme and water species and 
+!initialize the logicals LUSERn 
+!
+SELECT CASE ( CCLOUD )
+  CASE ( 'NONE' )
+    IF (.NOT. ( (.NOT. LUSERC) .AND. (.NOT. LUSERR) .AND. (.NOT. LUSERI) .AND. &
+                (.NOT. LUSERS) .AND. (.NOT. LUSERG) .AND. (.NOT. LUSERH)       &
+              ) .AND. CPROGRAM=='MESONH' )  THEN
+!
+      LUSERC=.FALSE.
+      LUSERR=.FALSE.; LUSERI=.FALSE.
+      LUSERS=.FALSE.; LUSERG=.FALSE. 
+      LUSERH=.FALSE.
+!
+    END IF
+!
+    IF (CSUBG_AUCV == 'SIGM')  THEN
+!
+      WRITE(UNIT=ILUOUT,FMT=9002) KMI
+      WRITE(UNIT=ILUOUT,FMT=*) 'YOU WANT TO USE THE SUBGRID AUTOCONVERSION SCHEME '                                         
+      WRITE(UNIT=ILUOUT,FMT=*) ' WITHOUT MICROPHYSICS'                         
+      WRITE(UNIT=ILUOUT,FMT=*) ' CSUBG_AUCV IS PUT TO "NONE"'                            
+!
+      CSUBG_AUCV = 'NONE'
+!
+    END IF
+!
+  CASE ( 'REVE' ) 
+    IF (.NOT. ( LUSERV .AND. LUSERC .AND. (.NOT. LUSERR) .AND. (.NOT. LUSERI) &
+               .AND. (.NOT. LUSERS) .AND. (.NOT. LUSERG) .AND. (.NOT. LUSERH) &
+              ) )  THEN
+!
+      WRITE(UNIT=ILUOUT,FMT=9002) KMI
+      WRITE(UNIT=ILUOUT,FMT='("YOU WANT TO USE A REVERSIBLE MICROPHYSICAL "   ,&
+      &" SCHEME. YOU WILL ONLY HAVE VAPOR AND CLOUD WATER ",/,                 &
+      &" LUSERV AND LUSERC ARE TO TRUE AND THE OTHERS TO FALSE ")') 
+!
+      LUSERV=.TRUE. ; LUSERC=.TRUE.
+      LUSERR=.FALSE.; LUSERI=.FALSE.
+      LUSERS=.FALSE.; LUSERG=.FALSE. 
+      LUSERH=.FALSE.
+    END IF
+!
+    IF (CSUBG_AUCV == 'SIGM')  THEN
+!
+      WRITE(UNIT=ILUOUT,FMT=9003) KMI
+      WRITE(UNIT=ILUOUT,FMT=*) 'YOU WANT TO USE BOTH A REVERSIBLE MICROPHYSICAL SCHEME '
+      WRITE(UNIT=ILUOUT,FMT=*) ' AND THE SUBGRID AUTOCONVERSION SCHEME '       
+      WRITE(UNIT=ILUOUT,FMT=*) 'BUT YOU DO NOT HAVE RAIN in the "REVE" SCHEME'
+      WRITE(UNIT=ILUOUT,FMT=*) ' CSUBG_AUCV IS PUT TO "NONE"'                            
+!
+      CSUBG_AUCV = 'NONE'
+!
+    END IF
+!
+  CASE ( 'KESS' )
+    IF (.NOT. ( LUSERV .AND. LUSERC .AND. LUSERR .AND. (.NOT. LUSERI) .AND. &
+              (.NOT. LUSERS) .AND. (.NOT. LUSERG) .AND. (.NOT. LUSERH)      &
+              ) )  THEN
+!
+      WRITE(UNIT=ILUOUT,FMT=9002) KMI
+      WRITE(UNIT=ILUOUT,FMT='("YOU WANT TO USE A KESSLER MICROPHYSICAL "   , &
+      &" SCHEME. YOU WILL ONLY HAVE VAPOR, CLOUD WATER AND RAIN ",/,           &
+      &" LUSERV, LUSERC AND LUSERR ARE SET TO TRUE AND THE OTHERS TO FALSE ")') 
+!
+      LUSERV=.TRUE. ; LUSERC=.TRUE. ; LUSERR=.TRUE.
+      LUSERI=.FALSE.; LUSERS=.FALSE.
+      LUSERG=.FALSE.; LUSERH=.FALSE.
+    END IF
+!
+    IF (CSUBG_AUCV == 'SIGM')  THEN
+!
+      WRITE(UNIT=ILUOUT,FMT=9003) KMI
+      WRITE(UNIT=ILUOUT,FMT=*) 'YOU WANT TO USE BOTH A KESSLER MICROPHYSICAL SCHEME '
+      WRITE(UNIT=ILUOUT,FMT=*) ' AND THE SUBGRID AUTOCONVERSION SCHEME USING'
+      WRITE(UNIT=ILUOUT,FMT=*) 'SIGMA_RC.'
+      WRITE(UNIT=ILUOUT,FMT=*) 'THIS IS NOT YET AVAILABLE.'
+      WRITE(UNIT=ILUOUT,FMT=*) 'SET CSUBG_AUCV TO "CLFR" or "NONE"  OR CCLOUD TO "ICE3"'
+!
+ !callabortstop
+      CALL PRINT_MSG(NVERB_FATAL,'GEN','READ_EXSEG_n','')
+    END IF
+!
+  CASE ( 'ICE3' )
+    IF (.NOT. ( LUSERV .AND. LUSERC .AND. LUSERR .AND. LUSERI .AND. LUSECI &
+                       .AND. LUSERS .AND. LUSERG .AND. (.NOT. LUSERH))     &
+                .AND. CPROGRAM=='MESONH' )  THEN
+      !
+      WRITE(UNIT=ILUOUT,FMT=9002) KMI
+      WRITE(UNIT=ILUOUT,FMT=*) 'YOU WANT TO USE THE ice3 SIMPLE MIXED PHASE'
+      WRITE(UNIT=ILUOUT,FMT=*) 'MICROPHYSICAL SCHEME. YOU WILL ONLY HAVE VAPOR, CLOUD WATER,'
+      WRITE(UNIT=ILUOUT,FMT=*) 'RAIN WATER, CLOUD ICE (MIXING RATIO AND CONCENTRATION)'
+      WRITE(UNIT=ILUOUT,FMT=*) 'SNOW-AGGREGATES AND GRAUPELN.'
+      WRITE(UNIT=ILUOUT,FMT=*) 'LUSERV,LUSERC,LUSERR,LUSERI,LUSECI,LUSERS,LUSERG ARE SET TO TRUE'
+      WRITE(UNIT=ILUOUT,FMT=*) 'AND LUSERH TO FALSE'
+!
+      LUSERV=.TRUE. ; LUSERC=.TRUE. ; LUSERR=.TRUE.
+      LUSERI=.TRUE. ; LUSECI=.TRUE.
+      LUSERS=.TRUE. ; LUSERG=.TRUE. 
+      LUSERH=.FALSE.
+    END IF    
+!
+    IF (CSUBG_AUCV == 'SIGM' .AND. .NOT. LSUBG_COND)  THEN
+      WRITE(UNIT=ILUOUT,FMT=9002) KMI
+      WRITE(UNIT=ILUOUT,FMT=*) 'YOU WANT TO USE SUBGRID AUTOCONVERSION SCHEME'
+      WRITE(UNIT=ILUOUT,FMT=*) ' WITHOUT THE SUBGRID CONDENSATION SCHEME.'
+      WRITE(UNIT=ILUOUT,FMT=*) 'THIS IS NOT ALLOWED: CSUBG_AUCV is SET to NONE' 
+      CSUBG_AUCV='NONE' 
+    END IF
+!
+    IF (CSUBG_AUCV == 'CLFR' .AND. CSCONV /= 'EDKF')  THEN
+      WRITE(UNIT=ILUOUT,FMT=9002) KMI
+      WRITE(UNIT=ILUOUT,FMT=*) 'YOU WANT TO USE SUBGRID AUTOCONVERSION SCHEME'
+      WRITE(UNIT=ILUOUT,FMT=*) 'WITH THE CONVECTIVE CLOUD FRACTION WITHOUT EDKF'
+      WRITE(UNIT=ILUOUT,FMT=*) 'THIS IS NOT ALLOWED: CSUBG_AUCV is SET to NONE' 
+      CSUBG_AUCV='NONE' 
+    END IF
+!
+  CASE ( 'ICE4' )
+    IF (.NOT. ( LUSERV .AND. LUSERC .AND. LUSERR .AND. LUSERI .AND. LUSECI &
+                       .AND. LUSERS .AND. LUSERG .AND. LUSERH)             &
+                .AND. CPROGRAM=='MESONH' )  THEN
+      !
+      WRITE(UNIT=ILUOUT,FMT=9002) KMI
+      WRITE(UNIT=ILUOUT,FMT=*) 'YOU WANT TO USE THE ice4 SIMPLE MIXED PHASE'
+      WRITE(UNIT=ILUOUT,FMT=*) 'MICROPHYSICAL SCHEME. YOU WILL ONLY HAVE VAPOR, CLOUD WATER,'
+      WRITE(UNIT=ILUOUT,FMT=*) 'RAIN WATER, CLOUD ICE (MIXING RATIO AND CONCENTRATION)'
+      WRITE(UNIT=ILUOUT,FMT=*) 'SNOW-AGGREGATES, GRAUPELN AND HAILSTONES.'
+      WRITE(UNIT=ILUOUT,FMT=*) 'LUSERV,LUSERC,LUSERR,LUSERI,LUSECI,LUSERS,LUSERG'
+      WRITE(UNIT=ILUOUT,FMT=*) 'AND LUSERH ARE SET TO TRUE'
+!
+      LUSERV=.TRUE. ; LUSERC=.TRUE. ; LUSERR=.TRUE.
+      LUSERI=.TRUE. ; LUSECI=.TRUE.
+      LUSERS=.TRUE. ; LUSERG=.TRUE. ; LUSERH=.TRUE.
+    END IF
+!
+    IF (CSUBG_AUCV /= 'NONE' .AND. .NOT. LSUBG_COND)  THEN
+      WRITE(UNIT=ILUOUT,FMT=9002) KMI
+      WRITE(UNIT=ILUOUT,FMT=*) 'YOU WANT TO USE SUBGRID AUTOCONVERSION SCHEME'
+      WRITE(UNIT=ILUOUT,FMT=*) ' WITHOUT THE SUBGRID CONDENSATION SCHEME.'
+      WRITE(UNIT=ILUOUT,FMT=*) 'THIS IS NOT ALLOWED: CSUBG_AUCV is SET to NONE' 
+      CSUBG_AUCV='NONE' 
+    END IF
+!
+  CASE ( 'C2R2','C3R5', 'KHKO' )
+    IF (( EPARAM_CCN == 'XXX') .OR. (EINI_CCN  == 'XXX')) THEN
+          WRITE(UNIT=ILUOUT,FMT='("YOU WANT TO USE A 2-MOMENT MICROPHYSICAL ",    &
+         &" SCHEME BUT YOU DIDNT FILL CORRECTLY NAM_PARAM_C2R2", &
+         &" YOU HAVE TO FILL HPARAM_CCN and HINI_CCN ")')
+ !callabortstop
+        CALL PRINT_MSG(NVERB_FATAL,'GEN','READ_EXSEG_n','')
+    END IF
+    IF (HCLOUD == 'NONE') THEN
+      CGETCLOUD = 'SKIP'
+    ELSE IF (HCLOUD == 'REVE' ) THEN
+      CGETCLOUD = 'INI1'
+    ELSE IF (HCLOUD == 'KESS' ) THEN
+      CGETCLOUD = 'INI2'
+    ELSE IF (HCLOUD == 'ICE3' ) THEN
+      IF (CCLOUD == 'C3R5') THEN
+        CGETCLOUD = 'INI2'
+      ELSE
+        WRITE(UNIT=ILUOUT,FMT=9003) KMI
+        WRITE(UNIT=ILUOUT,FMT='("YOU WANT TO USE THE WARM MICROPHYSICAL ",    &
+        &" SCHEME BUT YOU WERE USING THE ICE3 SCHEME PREVIOUSLY.",/,          &
+        &" AS THIS IS A LITTLE BIT STUPID IT IS NOT AUTHORIZED !!!")')
+ !callabortstop
+        CALL PRINT_MSG(NVERB_FATAL,'GEN','READ_EXSEG_n','')
+      END IF
+    ELSE
+      CGETCLOUD = 'READ' ! This is automatically done
+    END IF
+!
+    IF ((CCLOUD == 'C2R2' ).OR. (CCLOUD == 'KHKO' )) THEN
+      IF (.NOT. ( LUSERV .AND. LUSERC .AND. LUSERR .AND. (.NOT. LUSERI) .AND. &
+                (.NOT. LUSERS) .AND. (.NOT. LUSERG) .AND. (.NOT. LUSERH)      &
+                ) )  THEN
+        WRITE(UNIT=ILUOUT,FMT=9002) KMI
+        WRITE(UNIT=ILUOUT,FMT='("YOU WANT TO USE THE C2R2 MICROPHYSICAL ",    &
+        &" SCHEME. YOU WILL ONLY HAVE VAPOR, CLOUD WATER AND RAIN ",/,        &
+        &"LUSERV, LUSERC AND LUSERR ARE SET TO TRUE AND THE OTHERS TO FALSE ")')
+!
+        LUSERV=.TRUE. ; LUSERC=.TRUE. ; LUSERR=.TRUE.
+        LUSERI=.FALSE.; LUSERS=.FALSE.
+        LUSERG=.FALSE.; LUSERH=.FALSE.
+      END IF
+    ELSE IF (CCLOUD == 'C3R5') THEN
+      IF (.NOT. ( LUSERV .AND. LUSERC .AND. LUSERR .AND. LUSERI .AND. &
+                  LUSERS .AND. LUSERG .AND. (.NOT. LUSERH)            &
+                ) )  THEN
+        WRITE(UNIT=ILUOUT,FMT=9002) KMI
+        WRITE(UNIT=ILUOUT,FMT='("YOU WANT TO USE THE C3R5 MICROPHYS. SCHEME.",&
+        &" YOU WILL HAVE VAPOR, CLOUD WATER/ICE, RAIN, SNOW AND GRAUPEL ",/,  &
+        &"LUSERV, LUSERC, LUSERR, LUSERI, LUSERS, LUSERG ARE SET TO TRUE")' )
+!
+        LUSERV=.TRUE. ; LUSERC=.TRUE. ; LUSERR=.TRUE.
+        LUSERI=.TRUE. ; LUSECI=.TRUE.
+        LUSERS=.TRUE. ; LUSERG=.TRUE.
+        LUSERH=.FALSE.
+      END IF
+    ELSE IF (CCLOUD == 'LIMA') THEN
+      IF (.NOT. ( LUSERV .AND. LUSERC .AND. LUSERR .AND. LUSERI .AND. &
+                  LUSERS .AND. LUSERG .AND. (.NOT. LUSERH)            &
+                ) )  THEN
+        WRITE(UNIT=ILUOUT,FMT=9002) KMI
+        WRITE(UNIT=ILUOUT,FMT='("YOU WANT TO USE THE LIMA MICROPHYS. SCHEME.",&
+        &" YOU WILL HAVE VAPOR, CLOUD WATER/ICE, RAIN, SNOW AND GRAUPEL ",/,  &
+        &"LUSERV, LUSERC, LUSERR, LUSERI, LUSERS, LUSERG ARE SET TO TRUE")' )
+!
+        LUSERV=.TRUE. ; LUSERC=.TRUE. ; LUSERR=.TRUE.
+        LUSERI=.TRUE. ; LUSECI=.TRUE.        
+        LUSERS=.TRUE. ; LUSERG=.TRUE. 
+        LUSERH=.FALSE.
+      END IF
+    END IF
+!
+    IF (LSUBG_COND)  THEN
+      WRITE(UNIT=ILUOUT,FMT=9003) KMI
+      WRITE(UNIT=ILUOUT,FMT=*) 'YOU WANT TO USE BOTH THE SIMPLE MIXED PHASE'
+      WRITE(UNIT=ILUOUT,FMT=*) 'MICROPHYS. SCHEME AND THE SUBGRID COND. SCHEME.'
+      WRITE(UNIT=ILUOUT,FMT=*) 'THIS IS NOT YET AVAILABLE.'
+      WRITE(UNIT=ILUOUT,FMT=*) 'SET LSUBG_COND TO FALSE OR CCLOUD TO "REVE", "KESS"' 
+ !callabortstop
+      CALL PRINT_MSG(NVERB_FATAL,'GEN','READ_EXSEG_n','')
+    END IF
+!
+    IF ( CEFRADL /= 'C2R2') THEN
+      WRITE(UNIT=ILUOUT,FMT=9001) KMI
+      WRITE(UNIT=ILUOUT,FMT=*) ' YOU DID NOT CHOOSE CEFRADL=C2R2 FOR RADIATION'
+      WRITE(UNIT=ILUOUT,FMT=*) ' IT IS ADVISED TO USE CEFRADL=C2R2 '                       
+      WRITE(UNIT=ILUOUT,FMT=*) ' WITH A 2-MOMENT MICROPHYSICAL SCHEME'                     
+    END IF
+!
+    IF ( CCLOUD == 'C3R5' .AND. CEFRADI /= 'C3R5') THEN
+      WRITE(UNIT=ILUOUT,FMT=9001) KMI
+      WRITE(UNIT=ILUOUT,FMT=*) ' YOU DID NOT CHOOSE CEFRADI=C3R5 FOR RADIATION'
+      WRITE(UNIT=ILUOUT,FMT=*) ' IT IS ADVISED TO USE CEFRADI=C3R5 '                       
+      WRITE(UNIT=ILUOUT,FMT=*) ' WITH A 2-MOMENT MICROPHYSICAL SCHEME'                     
+    END IF
+!
+   IF ( WALPHAC /= 3.0 .OR. WNUC /= 2.0) THEN
+      WRITE(UNIT=ILUOUT,FMT=9001) KMI
+      WRITE(UNIT=ILUOUT,FMT=*) 'IT IS ADVISED TO USE XALPHAC=3. and XNUC=2.'
+      WRITE(UNIT=ILUOUT,FMT=*) 'FOR STRATOCUMULUS WITH KHKO SCHEME. '
+   END IF
+!
+   IF ( CEFRADL /= 'C2R2') THEN
+      WRITE(UNIT=ILUOUT,FMT=9001) KMI
+      WRITE(UNIT=ILUOUT,FMT=*) ' YOU DID NOT CHOOSE CEFRADL=C2R2 FOR RADIATION'
+      WRITE(UNIT=ILUOUT,FMT=*) ' IT IS ADVISED TO USE CEFRADL=C2R2 '   
+      WRITE(UNIT=ILUOUT,FMT=*) ' WITH A 2-MOMENT MICROPHYSICAL SCHEME'
+   END IF
+!
+  CASE ( 'LIMA')
+    IF ((LACTI .AND. FINI_CCN  == 'XXX')) THEN
+      WRITE(UNIT=ILUOUT,FMT=9001) KMI
+      WRITE(UNIT=ILUOUT,FMT='("YOU WANT TO USE A 2-MOMENT MICROPHYSICAL ",  &
+           &" SCHEME BUT YOU DIDNT FILL CORRECTLY NAM_PARAM_LIMA",             &
+           &" YOU HAVE TO FILL FINI_CCN ")')
+      call Print_msg( NVERB_FATAL, 'GEN', 'READ_EXSEG_n', '' )
+    END IF
+!
+    IF(LACTI .AND. NMOD_CCN == 0) THEN
+      WRITE(UNIT=ILUOUT,FMT=9001) KMI
+      WRITE(UNIT=ILUOUT,FMT='("ACTIVATION OF AEROSOL PARTICLES IS NOT ",      &
+           &"POSSIBLE IF NMOD_CCN HAS VALUE ZERO. YOU HAVE TO SET AN UPPER ", &
+           &"VALUE OF NMOD_CCN IN ORDER TO USE LIMA WARM ACTIVATION SCHEME.")') 
+      call Print_msg( NVERB_FATAL, 'GEN', 'READ_EXSEG_n', '' )
+    END IF
+!
+    IF(LNUCL .AND. NMOD_IFN == 0 .AND. (.NOT.LMEYERS)) THEN
+      WRITE(UNIT=ILUOUT,FMT=9001) KMI
+      WRITE(UNIT=ILUOUT,FMT='("NUCLEATION BY DEPOSITION AND CONTACT IS NOT ", &
+           &"POSSIBLE IF NMOD_IFN HAS VALUE ZERO. YOU HAVE TO SET AN UPPER",  &
+           &"VALUE OF NMOD_IFN IN ORDER TO USE LIMA COLD NUCLEATION SCHEME.")') 
+    END IF
+!
+    IF (HCLOUD == 'NONE') THEN
+      CGETCLOUD = 'SKIP'
+    ELSE IF (HCLOUD == 'REVE' ) THEN
+      CGETCLOUD = 'INI1'
+    ELSE IF (HCLOUD == 'KESS' ) THEN
+      CGETCLOUD = 'INI2'
+    ELSE IF (HCLOUD == 'ICE3' ) THEN
+      CGETCLOUD = 'INI2'
+    ELSE
+      CGETCLOUD = 'READ' ! This is automatically done
+    END IF
+!
+    IF (LWARM) THEN
+      LUSERV=.TRUE. ; LUSERC=.TRUE. ; LUSERR=.TRUE.
+      LUSERI=.FALSE.; LUSERS=.FALSE. ; LUSERG=.FALSE.; LUSERH=.FALSE.
+    END IF
+!
+    IF (LCOLD) THEN
+      LUSERV=.TRUE. ; LUSERC=.TRUE. ; LUSERR=.TRUE.
+      LUSERI=.TRUE. ; LUSERS=.TRUE. ; LUSERG=.TRUE.
+      LUSERH=LHAIL
+    END IF
+!
+    IF (LSUBG_COND .AND. LCOLD)  THEN
+      WRITE(UNIT=ILUOUT,FMT=9003) KMI
+      WRITE(UNIT=ILUOUT,FMT=*) 'YOU WANT TO USE BOTH THE SIMPLE MIXED PHASE'
+      WRITE(UNIT=ILUOUT,FMT=*) 'MICROPHYS. SCHEME AND THE SUBGRID COND. SCHEME.'
+      WRITE(UNIT=ILUOUT,FMT=*) 'THIS IS NOT YET AVAILABLE. SET LSUBG_COND '
+      WRITE(UNIT=ILUOUT,FMT=*) 'TO FALSE OR CCLOUD TO "REVE", "KESS" '
+ !callabortstop
+      CALL PRINT_MSG(NVERB_FATAL,'GEN','READ_EXSEG_n','')
+    END IF 
+!
+    IF ( XALPHAC /= 3.0 .OR. XNUC /= 2.0) THEN
+      WRITE(UNIT=ILUOUT,FMT=9001) KMI
+      WRITE(UNIT=ILUOUT,FMT=*) 'IT IS ADVISED TO USE XALPHAC=3. and XNUC=2.'
+      WRITE(UNIT=ILUOUT,FMT=*) 'FOR STRATOCUMULUS. '
+    END IF
+!
+    IF ( CEFRADL /= 'LIMA') THEN
+      WRITE(UNIT=ILUOUT,FMT=9001) KMI
+      WRITE(UNIT=ILUOUT,FMT=*) ' YOU DID NOT CHOOSE CEFRADL=LIMA FOR RADIATION'
+      WRITE(UNIT=ILUOUT,FMT=*) ' IT IS ADVISED TO USE CEFRADL=LIMA '
+      WRITE(UNIT=ILUOUT,FMT=*) ' WITH A 2-MOMENT MICROPHYSICAL SCHEME "LIMA"'
+    END IF
+
+    IF (LUSECHEM )  THEN
+      WRITE(UNIT=ILUOUT,FMT=*) 'YOU WANT TO USE BOTH LIMA MICROPHYS. SCHEME AND CHEMISTRY'
+      WRITE(UNIT=ILUOUT,FMT=*) 'THIS IS NOT YET AVAILABLE. SET LUSECHEM '
+      WRITE(UNIT=ILUOUT,FMT=*) 'TO FALSE OR CCLOUD TO "ICE3" '
+ !callabortstop
+      CALL PRINT_MSG(NVERB_FATAL,'GEN','READ_EXSEG_n','')
+    END IF 
+    IF (LDUST )  THEN
+      WRITE(UNIT=ILUOUT,FMT=*) 'YOU WANT TO USE BOTH LIMA MICROPHYS. SCHEME AND DUSTS '
+      WRITE(UNIT=ILUOUT,FMT=*) 'THIS IS NOT YET AVAILABLE. SET LDUST '
+      WRITE(UNIT=ILUOUT,FMT=*) 'TO FALSE OR CCLOUD TO "ICE3" '
+ !callabortstop
+      CALL PRINT_MSG(NVERB_FATAL,'GEN','READ_EXSEG_n','')
+    END IF   
+  IF (LSALT )  THEN
+      WRITE(UNIT=ILUOUT,FMT=*) 'YOU WANT TO USE BOTH LIMA MICROPHYS. SCHEME AND SEA SALTS '
+      WRITE(UNIT=ILUOUT,FMT=*) 'THIS IS NOT YET AVAILABLE. SET LSALT '
+      WRITE(UNIT=ILUOUT,FMT=*) 'TO FALSE OR CCLOUD TO "ICE3" '
+ !callabortstop
+      CALL PRINT_MSG(NVERB_FATAL,'GEN','READ_EXSEG_n','')
+    END IF 
+!
+END SELECT
+!
+LUSERV_G(KMI) = LUSERV
+LUSERC_G(KMI) = LUSERC
+LUSERR_G(KMI) = LUSERR
+LUSERI_G(KMI) = LUSERI
+LUSERS_G(KMI) = LUSERS
+LUSERG_G(KMI) = LUSERG
+LUSERH_G(KMI) = LUSERH
+LUSETKE(KMI) = (CTURB /= 'NONE')
+!
+!-------------------------------------------------------------------------------
+!
+!*       2.3     Chemical and NSV_* variables initializations
+!
+CALL UPDATE_NAM_PARAMN
+CALL UPDATE_NAM_DYNN
+CALL UPDATE_NAM_CONFN
+!
+IF (LORILAM .AND. .NOT. LUSECHEM) THEN
+  WRITE(UNIT=ILUOUT,FMT=9002) KMI
+  WRITE(ILUOUT,FMT=*) 'YOU CANNOT USE ORILAM AEROSOL SCHEME WITHOUT  '
+  WRITE(ILUOUT,FMT=*) 'CHEMICAL GASEOUS CHEMISTRY                    '
+  WRITE(ILUOUT,FMT=*) 'THEREFORE LUSECHEM IS SET TO TRUE    '
+  LUSECHEM=.TRUE.
+END IF
+!
+IF (LUSECHAQ.AND.(.NOT.LUSECHEM))  THEN
+  WRITE(UNIT=ILUOUT,FMT=9003) KMI
+  WRITE(UNIT=ILUOUT,FMT=*) 'YOU WANT TO USE AQUEOUS PHASE CHEMISTRY'
+  WRITE(UNIT=ILUOUT,FMT=*) 'BUT THE CHEMISTRY IS NOT ACTIVATED'
+  WRITE(UNIT=ILUOUT,FMT=*) 'SET LUSECHEM TO TRUE IF YOU WANT REALLY USE CHEMISTRY' 
+  WRITE(UNIT=ILUOUT,FMT=*) 'OR SET LUSECHAQ TO FALSE IF YOU DO NOT WANT USE IT' 
+ !callabortstop
+  CALL PRINT_MSG(NVERB_FATAL,'GEN','READ_EXSEG_n','')
+END IF
+IF (LUSECHAQ.AND.(.NOT.LUSERC).AND.CPROGRAM=='MESONH')  THEN
+  WRITE(UNIT=ILUOUT,FMT=9003) KMI
+  WRITE(UNIT=ILUOUT,FMT=*) 'YOU WANT TO USE AQUEOUS PHASE CHEMISTRY'
+  WRITE(UNIT=ILUOUT,FMT=*) 'BUT CLOUD MICROPHYSICS IS NOT ACTIVATED'
+  WRITE(UNIT=ILUOUT,FMT=*) 'LUSECHAQ IS SET TO FALSE' 
+  LUSECHAQ = .FALSE.
+END IF
+IF (LUSECHAQ.AND.CCLOUD(1:3) == 'ICE'.AND. .NOT. LUSECHIC) THEN
+  WRITE(UNIT=ILUOUT,FMT=9002) KMI
+  WRITE(UNIT=ILUOUT,FMT=*) 'YOU WANT TO USE AQUEOUS PHASE CHEMISTRY'
+  WRITE(UNIT=ILUOUT,FMT=*) 'WITH MIXED PHASE CLOUD MICROPHYSICS'
+  WRITE(UNIT=ILUOUT,FMT=*) 'SET LUSECHIC TO TRUE IF YOU WANT TO ACTIVATE'
+  WRITE(UNIT=ILUOUT,FMT=*) 'ICE PHASE CHEMICAL SPECIES'
+  IF (LCH_RET_ICE) THEN
+    WRITE(UNIT=ILUOUT,FMT=*) 'LCH_RET_ICE TRUE MEANS ALL SOLUBLE'
+    WRITE(UNIT=ILUOUT,FMT=*) 'GASES ARE RETAINED IN ICE PHASE'
+    WRITE(UNIT=ILUOUT,FMT=*) 'WHEN SUPERCOOLED WATER FREEZES'
+  ELSE
+    WRITE(UNIT=ILUOUT,FMT=*) 'LCH_RET_ICE FALSE MEANS ALL SOLUBLE'
+    WRITE(UNIT=ILUOUT,FMT=*) 'GASES GO BACK TO THE GAS PHASE WHEN'
+    WRITE(UNIT=ILUOUT,FMT=*) 'SUPERCOOLED WATER FREEZES'
+  ENDIF
+ENDIF
+IF (LUSECHIC.AND. .NOT. CCLOUD(1:3) == 'ICE'.AND.CPROGRAM=='MESONH') THEN
+  WRITE(UNIT=ILUOUT,FMT=9003) KMI
+  WRITE(UNIT=ILUOUT,FMT=*) 'YOU WANT TO USE ICE PHASE CHEMISTRY'
+  WRITE(UNIT=ILUOUT,FMT=*) 'BUT MIXED PHASE CLOUD MICROPHYSICS IS NOT ACTIVATED'
+  WRITE(UNIT=ILUOUT,FMT=*) 'LUSECHIC IS SET TO FALSE'  
+  LUSECHIC= .FALSE.
+ENDIF
+IF (LCH_PH.AND. (.NOT. LUSECHAQ)) THEN
+  WRITE(UNIT=ILUOUT,FMT=9003) KMI
+  WRITE(UNIT=ILUOUT,FMT=*) 'DIAGNOSTIC PH COMPUTATION IS ACTIVATED'
+  WRITE(UNIT=ILUOUT,FMT=*) 'BUT AQUEOUS PHASE CHEMISTRY IS NOT ACTIVATED'
+  WRITE(UNIT=ILUOUT,FMT=*) 'SET LUSECHAQ TO TRUE IF YOU WANT TO ACTIVATE IT'
+  WRITE(UNIT=ILUOUT,FMT=*) 'LCH_PH IS SET TO FALSE'
+  LCH_PH= .FALSE.
+ENDIF
+IF (LUSECHIC.AND.(.NOT.LUSECHAQ))  THEN
+  WRITE(UNIT=ILUOUT,FMT=9003) KMI
+  WRITE(UNIT=ILUOUT,FMT=*) 'YOU WANT TO USE ICE PHASE CHEMISTRY'
+  WRITE(UNIT=ILUOUT,FMT=*) 'BUT THE AQUEOUS PHASE CHEMISTRY IS NOT ACTIVATED'
+  WRITE(UNIT=ILUOUT,FMT=*) 'SET LUSECHAQ TO TRUE IF YOU WANT REALLY USE CLOUD CHEMISTRY'
+  WRITE(UNIT=ILUOUT,FMT=*) 'OR SET LUSECHIC TO FALSE IF YOU DO NOT WANT USE IT'
+!callabortstop
+  CALL PRINT_MSG(NVERB_FATAL,'GEN','READ_EXSEG_n','')
+END IF
+IF ((LUSECHIC).AND.(LCH_RET_ICE)) THEN
+  WRITE(UNIT=ILUOUT,FMT=9003) KMI
+  WRITE(UNIT=ILUOUT,FMT=*) 'YOU WANT TO USE RETENTION OF SOLUBLE GASES IN ICE'
+  WRITE(UNIT=ILUOUT,FMT=*) 'BUT THE ICE PHASE CHEMISTRY IS ACTIVATED'
+  WRITE(UNIT=ILUOUT,FMT=*) 'FLAG LCH_RET_ICE IS ONLY USES WHEN LUSECHIC IS SET'
+  WRITE(UNIT=ILUOUT,FMT=*) 'TO FALSE IE NO CHEMICAL SPECIES IN ICE' 
+ENDIF
+!
+IF (LUSECHEM) THEN
+  CALL CH_INIT_SCHEME_n(KMI,LUSECHAQ,LUSECHIC,LCH_PH,ILUOUT,NVERB)
+  IF (LORILAM) CALL CH_AER_INIT_SOA(ILUOUT, NVERB)
+END IF
+!
+
+CALL UPDATE_NAM_CH_MNHCN
+CALL INI_NSV(KMI)
+!
+! From this point, all NSV* variables contain valid values for model KMI
+! 
+DO JSV = 1,NSV
+ LUSESV(JSV,KMI) = .TRUE.
+END DO
+!
+IF ( CAOP=='EXPL' .AND. .NOT.LDUST .AND. .NOT.LORILAM          &
+                  .AND. .NOT.LSALT .AND. .NOT.(CCLOUD=='LIMA') ) THEN
+      WRITE(UNIT=ILUOUT,FMT=9001) KMI
+      WRITE(UNIT=ILUOUT,FMT=*) ' YOU WANT TO USE EXPLICIT AEROSOL OPTICAL '       
+      WRITE(UNIT=ILUOUT,FMT=*) 'PROPERTIES BUT YOU DONT HAVE DUST OR '            
+      WRITE(UNIT=ILUOUT,FMT=*) 'AEROSOL OR SALT THEREFORE CAOP=CLIM'            
+      CAOP='CLIM'
+END IF      
+!-------------------------------------------------------------------------------
+!
+!*       3.    CHECK COHERENCE BETWEEN EXSEG VARIABLES AND FMFILE ATTRIBUTES
+!              -------------------------------------------------------------
+!
+!
+!*       3.1  Turbulence variable 
+!
+IF ((CTURB /= 'NONE').AND.(HTURB == 'NONE')) THEN
+  CGETTKET ='INIT'
+  WRITE(UNIT=ILUOUT,FMT=9001) KMI
+  WRITE(UNIT=ILUOUT,FMT=*)'YOU WANT TO USE TURBULENCE KINETIC ENERGY TKE'
+  WRITE(UNIT=ILUOUT,FMT=*)'WHEREAS IT  IS NOT IN INITIAL FMFILE'
+  WRITE(UNIT=ILUOUT,FMT=*)'TKE WILL BE INITIALIZED TO ZERO'
+ELSE 
+  IF (CTURB /= 'NONE') THEN 
+    CGETTKET ='READ'
+    IF ((CCONF=='START') .AND. CPROGRAM /= 'DIAG') CGETTKET='INIT' 
+  ELSE
+   CGETTKET ='SKIP'
+  END IF
+END IF
+!
+!
+IF ((CTOM == 'TM06').AND.(HTOM /= 'TM06')) THEN
+  CGETBL_DEPTH ='INIT'
+  WRITE(UNIT=ILUOUT,FMT=9001) KMI
+  WRITE(UNIT=ILUOUT,FMT=*)'YOU WANT TO USE BL DEPTH FOR THIRD ORDER MOMENTS'
+  WRITE(UNIT=ILUOUT,FMT=*)'WHEREAS IT IS NOT IN INITIAL FMFILE'
+  WRITE(UNIT=ILUOUT,FMT=*)'IT WILL BE INITIALIZED TO ZERO'
+ELSE 
+  IF (CTOM == 'TM06') THEN 
+    CGETBL_DEPTH ='READ'
+  ELSE 
+    CGETBL_DEPTH ='SKIP'
+  END IF
+END IF
+!
+IF (LRMC01 .AND. .NOT. ORMC01) THEN
+  CGETSBL_DEPTH ='INIT'
+  WRITE(UNIT=ILUOUT,FMT=9001) KMI
+  WRITE(UNIT=ILUOUT,FMT=*)'YOU WANT TO USE SBL DEPTH FOR RMC01'
+  WRITE(UNIT=ILUOUT,FMT=*)'WHEREAS IT IS NOT IN INITIAL FMFILE'
+  WRITE(UNIT=ILUOUT,FMT=*)'IT WILL BE INITIALIZED TO ZERO'
+ELSE 
+  IF (LRMC01) THEN 
+    CGETSBL_DEPTH ='READ'
+  ELSE 
+    CGETSBL_DEPTH ='SKIP'
+  END IF
+END IF
+!
+!
+!*       3.2  Moist  variables 
+!
+IF (LUSERV.AND. (.NOT.OUSERV)) THEN
+  WRITE(UNIT=ILUOUT,FMT=9001) KMI
+  WRITE(UNIT=ILUOUT,FMT='("YOU WANT TO USE VAPOR VARIABLE Rv WHEREAS IT  ", &
+                  & "IS NOT IN INITIAL FMFILE",/,                           &
+                  & "Rv WILL BE INITIALIZED TO ZERO")')
+  CGETRVT='INIT'
+ELSE                                                                
+  IF (LUSERV) THEN
+    CGETRVT='READ'
+  ELSE
+    CGETRVT='SKIP'
+  END IF
+END IF
+!
+IF (LUSERC.AND. (.NOT.OUSERC)) THEN
+  WRITE(UNIT=ILUOUT,FMT=9001) KMI
+  WRITE(UNIT=ILUOUT,FMT='("YOU WANT TO USE CLOUD VARIABLE Rc WHEREAS IT ",  &
+                 &   " IS NOT IN INITIAL FMFILE",/,                        &
+                 &   "Rc WILL BE INITIALIZED TO ZERO")')
+  CGETRCT='INIT'
+ELSE
+  IF (LUSERC) THEN
+    CGETRCT='READ'
+!   IF(CCONF=='START') CGETRCT='INIT' 
+  ELSE
+    CGETRCT='SKIP'
+  END IF
+END IF
+!
+IF (LUSERR.AND. (.NOT.OUSERR)) THEN
+  WRITE(UNIT=ILUOUT,FMT=9001) KMI
+  WRITE(UNIT=ILUOUT,FMT='("YOU WANT TO USE RAIN VARIABLE Rr WHEREAS IT ", &
+                  &  "IS NOT IN INITIAL FMFILE",/,                     &
+                  &  " Rr WILL BE INITIALIZED TO ZERO")')
+ 
+  CGETRRT='INIT'
+ELSE
+  IF (LUSERR) THEN
+    CGETRRT='READ'
+!   IF( (CCONF=='START').AND. CPROGRAM /= 'DIAG') CGETRRT='INIT' 
+  ELSE
+    CGETRRT='SKIP'
+  END IF
+END IF
+!
+IF (LUSERI.AND. (.NOT.OUSERI)) THEN
+  WRITE(UNIT=ILUOUT,FMT=9001) KMI
+  WRITE(UNIT=ILUOUT,FMT='("YOU WANT TO USE ICE VARIABLE Ri WHEREAS IT ", &
+               &    "IS NOT IN INITIAL FMFILE",/,                      &
+               &     " Ri WILL BE INITIALIZED TO ZERO")')
+  CGETRIT='INIT'
+ELSE
+  IF (LUSERI) THEN
+    CGETRIT='READ'
+!   IF(CCONF=='START') CGETRIT='INIT' 
+  ELSE
+    CGETRIT='SKIP'
+  END IF
+END IF
+!
+IF (LUSECI.AND. (.NOT.OUSECI)) THEN
+  WRITE(UNIT=ILUOUT,FMT=9001) KMI
+  WRITE(UNIT=ILUOUT,FMT='("YOU WANT TO USE ICE CONC. VARIABLE Ci WHEREAS IT ",&
+               &          "IS NOT IN INITIAL FMFILE",/,                       &
+               &          "   Ci WILL BE INITIALIZED TO ZERO")')
+  CGETCIT='INIT'
+ELSE
+  IF (LUSECI) THEN
+    CGETCIT='READ'
+  ELSE
+    CGETCIT='SKIP'
+  END IF
+END IF
+!
+IF (LUSERS.AND. (.NOT.OUSERS)) THEN
+  WRITE(UNIT=ILUOUT,FMT=9001) KMI
+  WRITE(UNIT=ILUOUT,FMT='("YOU WANT TO USE SNOW VARIABLE Rs WHEREAS IT ",&
+                  &  "IS NOT IN INITIAL FMFILE",/,                       &
+                  &  " Rs WILL BE INITIALIZED TO ZERO")')
+  CGETRST='INIT'
+ELSE
+  IF (LUSERS) THEN
+    CGETRST='READ'
+!   IF ( (CCONF=='START').AND. CPROGRAM /= 'DIAG') CGETRST='INIT' 
+  ELSE
+    CGETRST='SKIP'
+  END IF
+END IF
+!
+IF (LUSERG.AND. (.NOT.OUSERG)) THEN
+  WRITE(UNIT=ILUOUT,FMT=9001) KMI
+  WRITE(UNIT=ILUOUT,FMT='("YOU WANT TO USE GRAUPEL VARIABLE Rg WHEREAS ",&
+                   & " IT IS NOTIN INITIAL FMFILE",/,                    &
+                   & "Rg WILL BE INITIALIZED TO ZERO")')
+  CGETRGT='INIT'
+ELSE
+  IF (LUSERG) THEN
+    CGETRGT='READ'
+!   IF ( (CCONF=='START') .AND. CPROGRAM /= 'DIAG') CGETRGT='INIT' 
+  ELSE
+    CGETRGT='SKIP'
+  END IF
+END IF
+!
+IF (LUSERH.AND. (.NOT.OUSERH)) THEN
+  WRITE(UNIT=ILUOUT,FMT=9001) KMI
+  WRITE(UNIT=ILUOUT,FMT='("YOU WANT TO USE HAIL VARIABLE Rh WHEREAS",&
+                  &  "IT IS NOT IN INITIAL FMFILE",/,                &
+                  & " Rh WILL BE INITIALIZED TO ZERO")')
+   CGETRHT='INIT'
+ELSE
+  IF (LUSERH) THEN
+    CGETRHT='READ'
+!   IF ( (CCONF=='START') .AND. CPROGRAM /= 'DIAG') CGETRHT='INIT' 
+  ELSE
+    CGETRHT='SKIP'
+  END IF
+END IF
+!
+IF (LUSERC.AND. (.NOT.OUSERC)) THEN
+  WRITE(UNIT=ILUOUT,FMT=9001) KMI
+  WRITE(UNIT=ILUOUT,FMT=*) 'THE CLOUD FRACTION WILL BE INITIALIZED ACCORDING'
+  WRITE(UNIT=ILUOUT,FMT=*) 'TO CLOUD MIXING RATIO VALUE OR SET TO 0'
+  CGETCLDFR = 'INIT'
+ELSE
+  IF ( LUSERC ) THEN
+    CGETCLDFR = 'READ'
+    IF ( (CCONF=='START') .AND. CPROGRAM /= 'DIAG') CGETCLDFR='INIT' 
+  ELSE
+    CGETCLDFR = 'SKIP'
+  END IF
+END IF
+!
+IF(CTURBLEN=='RM17') THEN
+  XCEDIS=0.34
+ELSE
+  XCEDIS=0.84
+END IF
+!
+!*       3.3  Moist turbulence
+!
+IF ( LUSERC .AND. CTURB /= 'NONE' ) THEN
+  IF ( .NOT. (OUSERC .AND. HTURB /= 'NONE') ) THEN
+    WRITE(UNIT=ILUOUT,FMT=9001) KMI
+    WRITE(UNIT=ILUOUT,FMT='("YOU WANT TO USE MOIST TURBULENCE WHEREAS IT ",/, &
+                 &   " WAS NOT THE CASE FOR THE INITIAL FMFILE GENERATION",/, &
+                 &    "SRC AND SIGS ARE INITIALIZED TO 0")')
+    CGETSRCT ='INIT'
+    CGETSIGS ='INIT'
+  ELSE
+    CGETSRCT ='READ'
+    IF ( (CCONF=='START') .AND. CPROGRAM /= 'DIAG') CGETSRCT ='INIT'
+    CGETSIGS ='READ'
+  END IF
+ELSE
+  CGETSRCT ='SKIP'
+  CGETSIGS ='SKIP'
+END IF
+!
+IF(NMODEL_CLOUD==KMI .AND. CTURBLEN_CLOUD/='NONE') THEN
+  IF (CTURB=='NONE' .OR. .NOT.LUSERC) THEN
+    WRITE(UNIT=ILUOUT,FMT=9001) KMI
+    WRITE(UNIT=ILUOUT,FMT='("YOU WANT TO COMPUTE A MIXING LENGTH FOR CLOUD=", &
+                 &   A4,/, &
+                 &   ", WHEREAS YOU DO NOT SPECIFY A TURBULENCE SCHEME OR ",  &
+                 &   "USE OF RC,",/," CTURBLEN_CLOUD IS SET TO NONE")')       &
+                 CTURBLEN_CLOUD
+    CTURBLEN_CLOUD='NONE'
+  END IF
+  IF( XCEI_MIN > XCEI_MAX ) THEN
+    WRITE(UNIT=ILUOUT,FMT=9003) KMI
+    WRITE(UNIT=ILUOUT,FMT='("PROBLEM OF CEI LIMITS FOR CLOUD MIXING  ",/, &
+                 &   "LENGTH COMPUTATION: XCEI_MIN=",E9.3,", XCEI_MAX=",E9.3)')&
+                 XCEI_MIN,XCEI_MAX
+ !callabortstop
+    CALL PRINT_MSG(NVERB_FATAL,'GEN','READ_EXSEG_n','')
+  END IF
+END IF
+!
+IF ( LSIGMAS ) THEN
+  WRITE(UNIT=ILUOUT,FMT=9001) KMI
+  WRITE(UNIT=ILUOUT,FMT='("YOU WANT TO USE SIGMA_S FROM TURBULENCE SCHEME",/, &
+                 &   " IN ICE SUBGRID CONDENSATION, SO YOUR SIGMA_S"/, &
+                 &   " MIGHT BE SMALL ABOVE PBL DEPENDING ON LENGTH SCALE")')
+END IF
+!
+IF (LSUBG_COND .AND. CTURB=='NONE' ) THEN
+  WRITE(UNIT=ILUOUT,FMT=9002) KMI
+  WRITE(UNIT=ILUOUT,FMT=*) 'YOU WANT TO USE SUBGRID CONDENSATION'
+  WRITE(UNIT=ILUOUT,FMT=*) ' WITHOUT TURBULENCE '                           
+  WRITE(UNIT=ILUOUT,FMT=*) 'THIS IS NOT ALLOWED: LSUBG_COND is SET to FALSE'
+  LSUBG_COND=.FALSE.
+END IF
+!
+IF (L1D .AND. CTURB/='NONE' .AND. CTURBDIM == '3DIM') THEN
+  WRITE(UNIT=ILUOUT,FMT=9002) KMI
+  WRITE(UNIT=ILUOUT,FMT=*) 'YOU WANT TO USE 3D TURBULENCE IN 1D CONFIGURATION '
+  WRITE(UNIT=ILUOUT,FMT=*) 'THIS IS NOT POSSIBLE: CTURBDIM IS SET TO 1DIM'
+  CTURBDIM = '1DIM'
+END IF
+!
+!*       3.4  Additional scalar variables 
+!
+IF (NSV_USER == KSV_USER) THEN
+  DO  JS = 1,KSV_USER             ! to read all the variables in initial file 
+    CGETSVT(JS)='READ'            ! and to initialize them 
+!   IF(CCONF=='START')CGETSVT(JS)='INIT'       ! with  these values  
+  END DO
+ELSEIF (NSV_USER > KSV_USER) THEN
+ IF (KSV_USER == 0) THEN
+    CGETSVT(1:NSV_USER)='INIT'
+ ELSE
+  WRITE(UNIT=ILUOUT,FMT=9001) KMI
+  WRITE(UNIT=ILUOUT,FMT='("YOU WANT TO USE MORE ADDITIONAL SCALAR  " ,&
+  &" VARIABLES THAN THERE ARE IN INITIAL FMFILE",/,                  &
+  & "THE SUPPLEMENTARY VARIABLES HAVE BEEN INITIALIZED TO ZERO ")') 
+  DO  JS = 1,KSV_USER             ! to read all the variables in initial file 
+    CGETSVT(JS)='READ'            ! and to initialize them
+!   IF(CCONF=='START')CGETSVT(JS)='INIT'        ! with  these values
+  END DO
+  DO JS = KSV_USER+1, NSV_USER    ! to initialize to zero supplementary
+    CGETSVT(JS)='INIT'            ! initial file)
+  END DO
+ END IF
+ELSE
+  WRITE(UNIT=ILUOUT,FMT=9000) KMI
+  WRITE(UNIT=ILUOUT,FMT='("YOU WANT TO USE LESS ADDITIONAL SCALAR  " ,&
+  &" VARIABLES THAN THERE ARE IN INITIAL FMFILE")')
+  DO  JS = 1,NSV_USER             ! to read the first NSV_USER variables in initial file 
+    CGETSVT(JS)='READ'            ! and to initialize with these values
+!   IF(CCONF=='START') CGETSVT(JS)='INIT'  
+  END DO 
+  DO  JS = NSV_USER + 1, KSV_USER ! to skip the last (KSV_USER-NSV_USER) variables
+    CGETSVT(JS)='SKIP' 
+  END DO
+END IF
+!
+! C2R2 and KHKO SV case
+!
+IF (CCLOUD == 'C2R2' .OR. CCLOUD == 'C3R5' .OR. CCLOUD == 'KHKO') THEN 
+  IF (HCLOUD == 'C2R2' .OR. HCLOUD == 'C3R5' .OR. HCLOUD == 'KHKO') THEN
+    CGETSVT(NSV_C2R2BEG:NSV_C2R2END)='READ'
+!   IF(CCONF=='START') CGETSVT(NSV_C2R2BEG:NSV_C2R2END)='INIT'
+  ELSE
+    WRITE(UNIT=ILUOUT,FMT=9001) KMI
+    WRITE(UNIT=ILUOUT,FMT='("THERE IS NO SCALAR VARIABLES FOR C2R2 &
+         & (or KHKO) SCHEME IN INITIAL FMFILE",/,&
+         & "THE C2R2 (or KHKO) VARIABLES HAVE BEEN INITIALIZED TO ZERO ")') 
+    CGETSVT(NSV_C2R2BEG:NSV_C2R2END)='INIT'
+  END IF
+END IF
+!
+! C3R5 SV case
+!
+IF (CCLOUD == 'C3R5') THEN 
+  IF (HCLOUD == 'C3R5') THEN
+    CGETSVT(NSV_C1R3BEG:NSV_C1R3END)='READ'
+!   IF(CCONF=='START') CGETSVT(NSV_C1R3BEG:NSV_C1R3END)='INIT'
+  ELSE
+    WRITE(UNIT=ILUOUT,FMT=9001) KMI
+    WRITE(UNIT=ILUOUT,FMT='("THERE IS NO SCALAR VARIABLES FOR C3R5 &
+         &SCHEME IN INITIAL FMFILE",/,&
+         & "THE C1R3 VARIABLES HAVE BEEN INITIALIZED TO ZERO ")') 
+    CGETSVT(NSV_C1R3BEG:NSV_C1R3END)='INIT'
+  END IF
+END IF
+!
+! LIMA SV case
+!
+IF (CCLOUD == 'LIMA') THEN
+  IF (HCLOUD == 'LIMA') THEN
+    CGETSVT(NSV_LIMA_BEG:NSV_LIMA_END)='READ'
+!!JPP    IF(HSTORAGE_TYPE=='TT') CGETSVT(NSV_LIMA_BEG:NSV_LIMA_END)='INIT'
+  ELSE
+    WRITE(UNIT=ILUOUT,FMT=9001) KMI
+    WRITE(UNIT=ILUOUT,FMT='("THERE IS NO SCALAR VARIABLES FOR LIMA &
+           & SCHEME IN INITIAL FMFILE",/,&
+           & "THE LIMA VARIABLES HAVE BEEN INITIALIZED TO ZERO ")') 
+    CGETSVT(NSV_LIMA_BEG:NSV_LIMA_END)='INIT'
+  END IF
+END IF
+!
+! Electrical SV case
+!
+IF (CELEC /= 'NONE') THEN 
+  IF (HELEC /= 'NONE') THEN
+    CGETSVT(NSV_ELECBEG:NSV_ELECEND)='READ'
+!   IF(CCONF=='START') CGETSVT(NSV_ELECBEG:NSV_ELECEND)='INIT'
+  ELSE
+    WRITE(UNIT=ILUOUT,FMT=9001) KMI
+    WRITE(UNIT=ILUOUT,FMT='("THERE IS NO SCALAR VARIABLES FOR ELECTRICAL &
+         &SCHEME IN INITIAL FMFILE",/,&
+         & "THE ELECTRICAL VARIABLES HAVE BEEN INITIALIZED TO ZERO ")') 
+    CGETSVT(NSV_ELECBEG:NSV_ELECEND)='INIT'
+  END IF
+END IF
+!
+! (explicit) LINOx SV case 
+!
+IF (CELEC /= 'NONE' .AND. LLNOX_EXPLICIT) THEN
+  IF (HELEC /= 'NONE' .AND. OLNOX_EXPLICIT) THEN
+    CGETSVT(NSV_LNOXBEG:NSV_LNOXEND)='READ' 
+  ELSE
+    WRITE(UNIT=ILUOUT,FMT=9001) KMI
+    WRITE(UNIT=ILUOUT,FMT='("THERE IS NO SCALAR VARIABLES FOR LINOX &
+         & IN INITIAL FMFILE",/,& 
+         & "THE LINOX VARIABLES HAVE BEEN INITIALIZED TO ZERO ")')  
+    CGETSVT(NSV_LNOXBEG:NSV_LNOXEND)='INIT' 
+  END IF
+END IF
+!
+! Chemical SV case (excluding aqueous chemical species)
+!
+IF (LUSECHEM) THEN
+  IF (OUSECHEM) THEN
+    CGETSVT(NSV_CHGSBEG:NSV_CHGSEND)='READ'
+    IF(CCONF=='START' .AND. LCH_INIT_FIELD ) CGETSVT(NSV_CHGSBEG:NSV_CHGSEND)='INIT'
+  ELSE
+    WRITE(UNIT=ILUOUT,FMT=9001) KMI
+    WRITE(UNIT=ILUOUT,FMT='("THERE IS NO SCALAR VARIABLES FOR CHEMICAL &
+         &SCHEME IN INITIAL FMFILE",/,&
+         & "THE CHEMICAL VARIABLES HAVE BEEN INITIALIZED TO ZERO ")') 
+    CGETSVT(NSV_CHGSBEG:NSV_CHGSEND)='INIT'
+  END IF
+END IF
+! add aqueous chemical species
+IF (LUSECHAQ) THEN
+  IF (OUSECHAQ) THEN
+    CGETSVT(NSV_CHACBEG:NSV_CHACEND)='READ'
+!    IF(CCONF=='START') CGETSVT(NSV_CHACBEG:NSV_CHACEND)='INIT'
+  ELSE
+    WRITE(UNIT=ILUOUT,FMT=9001) KMI
+    WRITE(UNIT=ILUOUT,FMT='("THERE IS NO SCALAR VARIABLES FOR CHEMICAL &
+         &SCHEME IN AQUEOUS PHASE IN INITIAL FMFILE",/,&
+         & "THE AQUEOUS PHASE CHEMICAL VARIABLES HAVE BEEN INITIALIZED TO ZERO ")') 
+    CGETSVT(NSV_CHACBEG:NSV_CHACEND)='INIT'
+  END IF
+END IF
+! add ice phase chemical species
+IF (LUSECHIC) THEN
+  IF (OUSECHIC) THEN
+    CGETSVT(NSV_CHICBEG:NSV_CHICEND)='READ'
+!   IF(CCONF=='START') CGETSVT(NSV_CHICBEG:NSV_CHICEND)='INIT'
+  ELSE
+    WRITE(UNIT=ILUOUT,FMT=9001) KMI
+    WRITE(UNIT=ILUOUT,FMT='("THERE IS NO SCALAR VARIABLES FOR CHEMICAL &
+         &SPECIES IN ICE PHASE IN INITIAL FMFILE",/,&
+         & "THE ICE PHASE CHEMICAL VARIABLES HAVE BEEN INITIALIZED TO ZERO ")')
+    CGETSVT(NSV_CHICBEG:NSV_CHICEND)='INIT'
+  END IF
+END IF
+! pH values = diagnostics
+IF (LCH_PH .AND. .NOT. OCH_PH) THEN
+  CGETPHC ='INIT'  !will be initialized to XCH_PHINIT
+  IF (LUSERR) THEN
+    CGETPHR = 'INIT' !idem
+  ELSE 
+    CGETPHR = 'SKIP'
+  ENDIF
+ELSE
+  IF (LCH_PH) THEN
+    CGETPHC ='READ'
+    IF (LUSERR) THEN
+      CGETPHR = 'READ'
+    ELSE
+      CGETPHR = 'SKIP'
+    ENDIF
+  ELSE
+    CGETPHC ='SKIP'
+    CGETPHR ='SKIP'
+  END IF
+END IF
+!
+! Dust case
+!
+IF (LDUST) THEN
+  IF (ODUST) THEN
+    CGETSVT(NSV_DSTBEG:NSV_DSTEND)='READ'
+!   IF(CCONF=='START') CGETSVT(NSV_DSTBEG:NSV_DSTEND)='INIT'
+  ELSE
+    WRITE(UNIT=ILUOUT,FMT=9001) KMI
+    WRITE(UNIT=ILUOUT,FMT='("THERE IS NO SCALAR VARIABLES FOR DUST &
+         &SCHEME IN INITIAL FMFILE",/,&
+         & "THE DUST VARIABLES HAVE BEEN INITIALIZED TO ZERO ")') 
+    CGETSVT(NSV_DSTBEG:NSV_DSTEND)='INIT'
+  END IF
+  IF (LDEPOS_DST(KMI)) THEN
+
+  IF((CCLOUD /= 'ICE3').AND.(CCLOUD /= 'ICE4').AND.(CCLOUD /= 'KESS')&
+  .AND.(CCLOUD /= 'KHKO').AND.(CCLOUD /= 'C2R2').AND.                &
+       (CPROGRAM/='SPAWN').AND.(CPROGRAM/='REAL'))  THEN
+    WRITE(UNIT=ILUOUT,FMT=9003) KMI
+    WRITE(UNIT=ILUOUT,FMT='("ERROR: WET DEPOSITION OF DUST IS ONLY CODED FOR THE",/,&
+         & "MICROPHYSICAL SCHEME as ICE3, ICE4, KESS, KHKO and C2R2")') 
+ !callabortstop
+    CALL PRINT_MSG(NVERB_FATAL,'GEN','READ_EXSEG_n','')
+  END IF  
+
+   IF (ODEPOS_DST(KMI) ) THEN
+    CGETSVT(NSV_DSTDEPBEG:NSV_DSTDEPEND)='READ'
+!   IF(CCONF=='START') CGETSVT(NSV_DSTDEPBEG:NSV_DSTDEPEND)='INIT'    
+   ELSE
+    WRITE(UNIT=ILUOUT,FMT=9001) KMI
+    WRITE(UNIT=ILUOUT,FMT='("THERE IS NO SCALAR VARIABLES FOR RAIN and CLOUD DUST &
+         &  SCHEME IN INITIAL FMFILE",/,&
+         & "THE MOIST DUST VARIABLES HAVE BEEN INITIALIZED TO ZERO ")') 
+    CGETSVT(NSV_DSTDEPBEG:NSV_DSTDEPEND)='INIT'    
+   END IF
+  END IF  
+
+  IF(NMODE_DST.GT.3 .OR. NMODE_DST.LT.1) THEN
+    WRITE(UNIT=ILUOUT,FMT=9003) KMI
+    WRITE(UNIT=ILUOUT,FMT='("DUST MODES MUST BE BETWEEN 1 and 3 ")') 
+ !callabortstop
+    CALL PRINT_MSG(NVERB_FATAL,'GEN','READ_EXSEG_n','')
+  END IF     
+  IF(.NOT.ALLOCATED(CDUSTNAMES)) THEN
+    IMOMENTS = (NSV_DSTEND - NSV_DSTBEG +1 )/NMODE_DST
+    ALLOCATE(CDUSTNAMES(IMOMENTS*NMODE_DST))
+    !Loop on all dust modes
+    IF (IMOMENTS == 1) THEN
+    DO JMODE=1,NMODE_DST
+      IMODEIDX=JPDUSTORDER(JMODE)
+      JSV_NAME = (IMODEIDX - 1)*3 + 2
+      CDUSTNAMES(JMODE) = YPDUST_INI(JSV_NAME)
+    END DO
+    ELSE
+    DO JMODE=1,NMODE_DST  
+      !Find which mode we are dealing with
+      IMODEIDX=JPDUSTORDER(JMODE)
+      DO JMOM=1,IMOMENTS
+        !Find which number this is of the list of scalars
+        JSV = (JMODE-1)*IMOMENTS + JMOM
+        !Find what name this corresponds to, always 3 moments assumed in YPDUST_INI
+        JSV_NAME = (IMODEIDX - 1)*3 + JMOM
+        !Get the right CDUSTNAMES which should follow the list of scalars transported in XSVM/XSVT
+        CDUSTNAMES(JSV) = YPDUST_INI(JSV_NAME)
+      ENDDO ! Loop on moments
+    ENDDO    ! Loop on dust modes
+    END IF 
+  END IF 
+  ! Initialization of deposition scheme
+  IF (LDEPOS_DST(KMI)) THEN
+    IF(.NOT.ALLOCATED(CDEDSTNAMES)) THEN
+      ALLOCATE(CDEDSTNAMES(NMODE_DST*2))
+      DO JMODE=1,NMODE_DST  
+        IMODEIDX=JPDUSTORDER(JMODE)
+        CDEDSTNAMES(JMODE) = YPDEDST_INI(IMODEIDX)
+        CDEDSTNAMES(NMODE_DST+JMODE) = YPDEDST_INI(NMODE_DST+IMODEIDX)
+      ENDDO
+    ENDIF    
+  ENDIF
+
+END IF 
+!
+! Sea Salt case
+!
+IF (LSALT) THEN
+  IF (OSALT) THEN
+    CGETSVT(NSV_SLTBEG:NSV_SLTEND)='READ'
+    CGETZWS='READ'
+!   IF(CCONF=='START') CGETSVT(NSV_SLTBEG:NSV_SLTEND)='INIT'
+  ELSE
+    WRITE(UNIT=ILUOUT,FMT=9001) KMI
+    WRITE(UNIT=ILUOUT,FMT='("THERE IS NO SCALAR VARIABLES FOR SALT &
+         &SCHEME IN INITIAL FMFILE",/,&
+         & "THE SALT VARIABLES HAVE BEEN INITIALIZED TO ZERO ")') 
+    CGETSVT(NSV_SLTBEG:NSV_SLTEND)='INIT'
+    CGETZWS='INIT'
+  END IF
+  IF (LDEPOS_SLT(KMI)) THEN
+
+  IF((CCLOUD /= 'ICE3').AND.(CCLOUD /= 'ICE4').AND.(CCLOUD /= 'KESS')&
+  .AND.(CCLOUD /= 'KHKO').AND.(CCLOUD /= 'C2R2').AND.                &
+       (CPROGRAM/='SPAWN').AND.(CPROGRAM/='REAL'))  THEN
+    WRITE(UNIT=ILUOUT,FMT=9003) KMI
+    WRITE(UNIT=ILUOUT,FMT='("ERROR: WET DEPOSITION OF SEA SALT AEROSOLS IS ONLY CODED FOR THE",/,&
+         & "MICROPHYSICAL SCHEME as ICE3, ICE4, KESS, KHKO and C2R2")') 
+ !callabortstop
+    CALL PRINT_MSG(NVERB_FATAL,'GEN','READ_EXSEG_n','')
+  END IF  
+
+   IF (ODEPOS_SLT(KMI) ) THEN
+    CGETSVT(NSV_SLTDEPBEG:NSV_SLTDEPEND)='READ'
+!   IF(CCONF=='START') CGETSVT(NSV_SLTDEPBEG:NSV_SLTDEPEND)='INIT'    
+   ELSE
+    WRITE(UNIT=ILUOUT,FMT=9001) KMI
+    WRITE(UNIT=ILUOUT,FMT='("THERE IS NO SCALAR VARIABLES FOR RAIN and CLOUD SEA SALT &
+         &  SCHEME IN INITIAL FMFILE",/,&
+         & "THE MOIST SEA SALT VARIABLES HAVE BEEN INITIALIZED TO ZERO ")') 
+    CGETSVT(NSV_SLTDEPBEG:NSV_SLTDEPEND)='INIT'    
+   END IF
+  END IF
+  IF(NMODE_SLT.GT.5 .OR. NMODE_SLT.LT.1) THEN
+    WRITE(UNIT=ILUOUT,FMT=9003) KMI
+    WRITE(UNIT=ILUOUT,FMT='("SALT MODES MUST BE BETWEEN 1 and 5 ")') 
+ !callabortstop
+    CALL PRINT_MSG(NVERB_FATAL,'GEN','READ_EXSEG_n','')
+  END IF     
+  IF(.NOT.ALLOCATED(CSALTNAMES)) THEN
+    IMOMENTS = (NSV_SLTEND - NSV_SLTBEG +1 )/NMODE_SLT
+    ALLOCATE(CSALTNAMES(IMOMENTS*NMODE_SLT))
+    !Loop on all dust modes
+    IF (IMOMENTS == 1) THEN
+    DO JMODE=1,NMODE_SLT
+      IMODEIDX=JPSALTORDER(JMODE)
+      JSV_NAME = (IMODEIDX - 1)*3 + 2
+      CSALTNAMES(JMODE) = YPSALT_INI(JSV_NAME)
+    END DO
+    ELSE
+    DO JMODE=1,NMODE_SLT  
+      !Find which mode we are dealing with
+      IMODEIDX=JPSALTORDER(JMODE)
+      DO JMOM=1,IMOMENTS
+        !Find which number this is of the list of scalars
+        JSV = (JMODE-1)*IMOMENTS + JMOM
+        !Find what name this corresponds to, always 3 moments assumed in YPSALT_INI
+        JSV_NAME = (IMODEIDX - 1)*3 + JMOM
+        !Get the right CSALTNAMES which should follow the list of scalars transported in XSVM/XSVT
+        CSALTNAMES(JSV) = YPSALT_INI(JSV_NAME)
+      ENDDO ! Loop on moments
+    ENDDO    ! Loop on dust modes
+    END IF
+  END IF 
+  ! Initialization of deposition scheme
+  IF (LDEPOS_SLT(KMI)) THEN
+    IF(.NOT.ALLOCATED(CDESLTNAMES)) THEN
+      ALLOCATE(CDESLTNAMES(NMODE_SLT*2))
+      DO JMODE=1,NMODE_SLT  
+        IMODEIDX=JPSALTORDER(JMODE)
+        CDESLTNAMES(JMODE) = YPDESLT_INI(IMODEIDX)
+        CDESLTNAMES(NMODE_SLT+JMODE) = YPDESLT_INI(NMODE_SLT+IMODEIDX)
+      ENDDO
+    ENDIF    
+  ENDIF
+END IF 
+!
+! Orilam SV case
+!
+IF (LORILAM) THEN
+  IF (OORILAM) THEN
+    CGETSVT(NSV_AERBEG:NSV_AEREND)='READ'
+!   IF(CCONF=='START') CGETSVT(NSV_AERBEG:NSV_AEREND)='INIT'
+  ELSE
+    WRITE(UNIT=ILUOUT,FMT=9001) KMI
+    WRITE(UNIT=ILUOUT,FMT='("THERE IS NO SCALAR VARIABLES FOR AEROSOL &
+         &SCHEME IN INITIAL FMFILE",/,&
+         & "THE AEROSOLS VARIABLES HAVE BEEN INITIALIZED TO ZERO ")') 
+    CGETSVT(NSV_AERBEG:NSV_AEREND)='INIT'
+  END IF
+  IF (LDEPOS_AER(KMI)) THEN
+
+  IF((CCLOUD /= 'ICE3').AND.(CCLOUD /= 'ICE4').AND.(CCLOUD /= 'KESS')&
+  .AND.(CCLOUD /= 'KHKO').AND.(CCLOUD /= 'C2R2').AND.                &
+       (CPROGRAM/='SPAWN').AND.(CPROGRAM/='REAL'))  THEN
+    WRITE(UNIT=ILUOUT,FMT=9003) KMI
+    WRITE(UNIT=ILUOUT,FMT='("ERROR: WET DEPOSITION OF ORILAM AEROSOLS IS ONLY CODED FOR THE",/,&
+         & "MICROPHYSICAL SCHEME as ICE3, ICE4, KESS, KHKO and C2R2")') 
+ !callabortstop
+    CALL PRINT_MSG(NVERB_FATAL,'GEN','READ_EXSEG_n','')
+  END IF  
+
+   IF (ODEPOS_AER(KMI) ) THEN
+    CGETSVT(NSV_AERDEPBEG:NSV_AERDEPEND)='READ'
+!   IF(CCONF=='START') CGETSVT(NSV_AERDEPBEG:NSV_AERDEPEND)='INIT'    
+   ELSE
+    WRITE(UNIT=ILUOUT,FMT=9001) KMI
+    WRITE(UNIT=ILUOUT,FMT='("THERE IS NO SCALAR VARIABLES FOR RAIN and IN CLOUD  &
+         &  AEROSOL SCHEME IN INITIAL FMFILE",/,&
+         & "THE MOIST AEROSOL VARIABLES HAVE BEEN INITIALIZED TO ZERO ")') 
+    CGETSVT(NSV_AERDEPBEG:NSV_AERDEPEND)='INIT'    
+   END IF
+  END IF
+! Initialization of deposition scheme
+  IF (LDEPOS_AER(KMI)) THEN
+    IF(.NOT.ALLOCATED(CDEAERNAMES)) THEN
+      ALLOCATE(CDEAERNAMES(JPMODE*2))
+        CDEAERNAMES(:) = YPDEAER_INI(:)
+    ENDIF    
+  ENDIF
+END IF
+!
+! Lagrangian variables
+!
+IF (LINIT_LG .AND. .NOT.(LLG)) THEN
+      WRITE(UNIT=ILUOUT,FMT=9001) KMI
+      WRITE(UNIT=ILUOUT,FMT='("IT IS INCOHERENT TO HAVE LINIT_LG=.T. AND LLG=.F.",/,&
+      & "IF YOU WANT LAGRANGIAN TRACERS CHANGE LLG TO .T. ")')
+ENDIF
+IF (LLG) THEN
+  IF (OLG .AND. .NOT.(LINIT_LG .AND. CPROGRAM=='MESONH')) THEN
+    CGETSVT(NSV_LGBEG:NSV_LGEND)='READ'
+!   IF(CCONF=='START') CGETSVT(NSV_LGBEG:NSV_LGEND)='INIT'
+  ELSE
+    IF(.NOT.(LINIT_LG) .AND. CPROGRAM=='MESONH') THEN
+      WRITE(UNIT=ILUOUT,FMT=9001) KMI
+      WRITE(UNIT=ILUOUT,FMT='("THERE IS NO LAGRANGIAN VARIABLES IN INITIAL FMFILE",/,&
+                       & "THE LAGRANGIAN VARIABLES HAVE BEEN REINITIALIZED")')
+      LINIT_LG=.TRUE.
+    ENDIF
+    CGETSVT(NSV_LGBEG:NSV_LGEND)='INIT'
+  END IF
+END IF
+!
+!
+! LINOx SV case
+!
+IF (.NOT.LUSECHEM .AND. LCH_CONV_LINOX) THEN
+  IF (.NOT.OUSECHEM .AND. OCH_CONV_LINOX) THEN
+    CGETSVT(NSV_LNOXBEG:NSV_LNOXEND)='READ'
+  ELSE
+    WRITE(UNIT=ILUOUT,FMT=9002) KMI
+    WRITE(UNIT=ILUOUT,FMT='("THERE IS NO SCALAR VARIABLES FOR LINOX &
+         &IN INITIAL FMFILE",/,&
+         & "THE LINOX VARIABLES HAVE BEEN INITIALIZED TO ZERO ")') 
+    CGETSVT(NSV_LNOXBEG:NSV_LNOXEND)='INIT'
+  END IF
+END IF
+!
+! Passive pollutant case
+!
+IF (LPASPOL) THEN
+  IF (OPASPOL) THEN
+    CGETSVT(NSV_PPBEG:NSV_PPEND)='READ'
+!   IF(CCONF=='START') CGETSVT(NSV_PPBEG:NSV_PPEND)='INIT'    
+  ELSE
+    WRITE(UNIT=ILUOUT,FMT=9001) KMI
+    WRITE(UNIT=ILUOUT,FMT='("THERE IS NO PASSIVE SCALAR VARIABLES IN INITIAL FMFILE",/,&
+                       & "THE VARIABLES HAVE BEEN INITIALIZED TO ZERO")')
+    CGETSVT(NSV_PPBEG:NSV_PPEND)='INIT'
+  END IF
+END IF
+!
+#ifdef MNH_FOREFIRE
+! ForeFire
+!
+IF (LFOREFIRE) THEN
+  IF (OFOREFIRE) THEN
+    CGETSVT(NSV_FFBEG:NSV_FFEND)='READ'
+    IF(HSTORAGE_TYPE=='TT') THEN
+      CGETSVT(NSV_FFBEG:NSV_FFEND)='INIT'
+    END IF
+  ELSE
+    WRITE(UNIT=ILUOUT,FMT=9001) KMI
+    WRITE(UNIT=ILUOUT,FMT='("THERE IS NO FOREFIRE SCALAR VARIABLES IN INITIAL FMFILE",/,&
+                       & "THE VARIABLES HAVE BEEN INITIALIZED TO ZERO")')
+    CGETSVT(NSV_FFBEG:NSV_FFEND)='INIT'
+  END IF
+END IF
+#endif
+!
+! Conditional sampling case
+!
+IF (LCONDSAMP) THEN
+  IF (OCONDSAMP) THEN
+    CGETSVT(NSV_CSBEG:NSV_CSEND)='READ'
+!   IF(CCONF=='START') CGETSVT(NSV_CSBEG:NSV_CSEND)='INIT'       
+  ELSE
+    WRITE(UNIT=ILUOUT,FMT=9001) KMI
+    WRITE(UNIT=ILUOUT,FMT='("THERE IS NO PASSIVE SCALAR VARIABLES IN INITIAL FMFILE",/,&
+                       & "THE VARIABLES HAVE BEEN INITIALIZED TO ZERO")')
+    CGETSVT(NSV_CSBEG:NSV_CSEND)='INIT'
+  END IF
+END IF
+!
+! Blowing snow scheme
+!
+IF (LBLOWSNOW) THEN
+  IF (OBLOWSNOW) THEN
+    CGETSVT(NSV_SNWBEG:NSV_SNWEND)='READ'
+  ELSE
+    WRITE(UNIT=ILUOUT,FMT=9001) KMI
+    WRITE(UNIT=ILUOUT,FMT='("THERE IS NO SCALAR VARIABLES FOR BLOWING SNOW &
+         &SCHEME IN INITIAL FMFILE",/,&
+         & "THE BLOWING SNOW VARIABLES HAVE BEEN INITIALIZED TO ZERO ")')
+    CGETSVT(NSV_SNWBEG:NSV_SNWEND)='INIT'
+  END IF
+  IF(.NOT.ALLOCATED(CSNOWNAMES)) THEN
+    IMOMENTS = (NSV_SNWEND - NSV_SNWBEG +1 )
+    ALLOCATE(CSNOWNAMES(IMOMENTS))
+    DO JMOM=1,IMOMENTS
+      CSNOWNAMES(JMOM) = YPSNOW_INI(JMOM)
+    ENDDO ! Loop on moments
+  END IF
+END IF
+!
+!
+!
+!*       3.5  Check coherence between the radiation control parameters
+!
+IF( CRAD == 'ECMW' .AND. CPROGRAM=='MESONH' ) THEN
+  IF(CLW == 'RRTM' .AND. COPILW == 'SMSH') THEN
+    WRITE(UNIT=ILUOUT,FMT=9003) KMI
+    WRITE(UNIT=ILUOUT,FMT=*) 'the SMSH parametrisation of LW optical properties for cloud ice'
+    WRITE(UNIT=ILUOUT,FMT=*) '(COPILW) can not be used with RRTM radiation scheme'
+ !callabortstop
+    CALL PRINT_MSG(NVERB_FATAL,'GEN','READ_EXSEG_n','')
+  ENDIF
+  IF(CLW == 'MORC' .AND. COPWLW == 'LILI') THEN
+    WRITE(UNIT=ILUOUT,FMT=9003) KMI
+    WRITE(UNIT=ILUOUT,FMT=*) 'the LILI parametrisation of LW optical properties for cloud water'
+    WRITE(UNIT=ILUOUT,FMT=*) '(COPWLW) can not be used with MORC radiation scheme'
+ !callabortstop
+    CALL PRINT_MSG(NVERB_FATAL,'GEN','READ_EXSEG_n','')
+  ENDIF
+  IF( .NOT. LSUBG_COND) THEN
+    WRITE(UNIT=ILUOUT,FMT=9000) KMI
+    WRITE(UNIT=ILUOUT,FMT=*) 'YOU DO NOT WANT TO USE SUBGRID CONDENSATION'             
+    WRITE(UNIT=ILUOUT,FMT=*) 'THE OVERLAP OPTION IS NOVLP=5 IN ini_radconf.f90'
+  ELSE IF (CLW == 'MORC') THEN
+    WRITE(UNIT=ILUOUT,FMT=9000) KMI
+    WRITE(UNIT=ILUOUT,FMT=*) 'YOU WANT TO USE MORCRETTE LW SCHEME'                   
+    WRITE(UNIT=ILUOUT,FMT=*) 'THE OVERLAP OPTION IS NOVLP=5 IN ini_radconf.f90'
+  ELSE
+    WRITE(UNIT=ILUOUT,FMT=9000) KMI
+    WRITE(UNIT=ILUOUT,FMT=*) 'THE OVERLAP OPTION IS NOVLP=6 IN ini_radconf.f90'
+  ENDIF
+!
+  IF( LCLEAR_SKY .AND. XDTRAD_CLONLY /= XDTRAD) THEN
+    ! Check the validity of the LCLEAR_SKY approximation
+    WRITE(UNIT=ILUOUT,FMT=9003) KMI
+    WRITE(UNIT=ILUOUT,FMT=*) 'YOU WANT TO USE BOTH THE CLEAR-SKY APPROXIMATION'
+    WRITE(UNIT=ILUOUT,FMT=*) '(i.e. AVERAGE THE WHOLE CLOUDFREE VERTICALS BUT KEEP'
+    WRITE(UNIT=ILUOUT,FMT=*) 'ALL THE CLOUDY VERTICALS) AND'
+    WRITE(UNIT=ILUOUT,FMT=*) 'THE CLOUD-ONLY APPROXIMATION (i.e. YOU CALL MORE OFTEN THE'
+    WRITE(UNIT=ILUOUT,FMT=*) 'RADIATIONS FOR THE CLOUDY VERTICALS THAN FOR CLOUDFREE ONES).'
+    WRITE(UNIT=ILUOUT,FMT=*) 'THIS IS NOT POSSIBLE, SO CHOOSE BETWEEN :'
+    WRITE(UNIT=ILUOUT,FMT=*) 'XDTRAD_CLONLY = XDTRAD and LCLEAR_SKY = FALSE'
+!
+ !callabortstop
+    CALL PRINT_MSG(NVERB_FATAL,'GEN','READ_EXSEG_n','')
+  END IF
+!
+  IF( XDTRAD_CLONLY > XDTRAD ) THEN
+    WRITE(UNIT=ILUOUT,FMT=9003) KMI
+    WRITE(UNIT=ILUOUT,FMT='("BAD USE OF THE CLOUD-ONLY APPROXIMATION   " ,&
+    &" XDTRAD SHOULD BE LARGER THAN XDTRAD_CLONLY                      ")')
+!
+ !callabortstop
+    CALL PRINT_MSG(NVERB_FATAL,'GEN','READ_EXSEG_n','')
+  END IF
+!
+  IF(( XDTRAD < XTSTEP ).OR. ( XDTRAD_CLONLY < XTSTEP )) THEN
+    WRITE(UNIT=ILUOUT,FMT=9003) KMI
+    WRITE(UNIT=ILUOUT,FMT='("THE RADIATION CALL XDTRAD OR XDTRAD_CLONLY " ,&
+    &" IS MORE FREQUENT THAN THE TIME STEP SO ADJUST XDTRAD OR XDTRAD_CLONLY ")')
+!
+ !callabortstop
+    CALL PRINT_MSG(NVERB_FATAL,'GEN','READ_EXSEG_n','')
+  END IF
+END IF
+!
+IF ( CRAD /= 'NONE' .AND. CPROGRAM=='MESONH' ) THEN
+  CGETRAD='READ'
+  IF( HRAD == 'NONE' .AND. CCONF=='RESTA') THEN
+    WRITE(UNIT=ILUOUT,FMT=9001) KMI
+    WRITE(UNIT=ILUOUT,FMT=*) 'YOU ARE PERFORMING A RESTART. FOR THIS SEGMENT, YOU ARE USING A RADIATION'
+    WRITE(UNIT=ILUOUT,FMT=*) 'SCHEME AND NO RADIATION SCHEME WAS USED FOR THE PREVIOUS SEGMENT.'
+    CGETRAD='INIT'
+  END IF
+  IF(CCONF=='START') THEN
+    CGETRAD='INIT'
+  END IF
+END IF
+!
+!        3.6  check the initialization of the deep convection scheme
+!
+IF ( (CDCONV /= 'KAFR') .AND. &
+      (CSCONV /= 'KAFR') .AND. LCHTRANS ) THEN
+   WRITE(UNIT=ILUOUT,FMT=9003) KMI
+   WRITE(UNIT=ILUOUT,FMT='("YOU WANT TO USE THE LCHTRANS OPTION= ",&
+    &"CONVECTIVE TRANSPORT OF TRACERS BUT  IT CAN ONLY",&
+    &"BE USED FOR THE KAIN FRITSCH SCHEME ")')
+ !callabortstop
+   CALL PRINT_MSG(NVERB_FATAL,'GEN','READ_EXSEG_n','')
+END IF
+!
+SELECT CASE ( CDCONV )
+  CASE( 'KAFR' )
+    IF (.NOT. ( LUSERV ) ) THEN
+      WRITE(UNIT=ILUOUT,FMT=9002) KMI
+      WRITE(UNIT=ILUOUT,FMT='("YOU WANT TO USE THE KAIN-FRITSCH DEEP CONV. ",&
+      &" SCHEME. YOU MUST HAVE VAPOR ",/,"LUSERV IS SET TO TRUE ")')
+      LUSERV=.TRUE.
+    ELSE IF (.NOT. ( LUSERI ) ) THEN
+      WRITE(UNIT=ILUOUT,FMT=9002) KMI
+      WRITE(UNIT=ILUOUT,FMT='("YOU WANT TO USE THE KAIN-FRITSCH",&
+      &" DEEP CONV. SCHEME. BUT THE DETRAINED CLOUD ICE WILL BE ADDED TO   ",&
+      &" THE CLOUD WATER  ")')
+    ELSE IF (.NOT. ( LUSERI.AND.LUSERC ) ) THEN
+      WRITE(UNIT=ILUOUT,FMT=9002) KMI
+      WRITE(UNIT=ILUOUT,FMT='("YOU WANT TO USE THE KAIN-FRITSCH",&
+      &" DEEP CONV. SCHEME. BUT THE DETRAINED CLOUD WATER AND CLOUD ICE    ",&
+      &" WILL BE ADDED TO THE WATER VAPOR FIELD  ")')
+    END IF
+    IF ( LCHTRANS .AND. NSV == 0 ) THEN
+      WRITE(UNIT=ILUOUT,FMT=9002) KMI
+      WRITE(UNIT=ILUOUT,FMT='("YOU WANT TO USE THE LCHTRANS OPTION= ",&
+      &"CONVECTIVE TRANSPORT OF TRACERS BUT YOUR TRACER ",&
+      &"NUMBER NSV IS ZERO ",/,"LCHTRANS IS SET TO FALSE")')
+      LCHTRANS=.FALSE.
+    END IF
+END SELECT
+!
+IF ( CDCONV == 'KAFR' .AND. LCHTRANS .AND. NSV > 0 ) THEN
+  IF( OCHTRANS ) THEN
+    CGETSVCONV='READ'
+  ELSE  
+    CGETSVCONV='INIT'
+  END IF
+END IF
+!
+SELECT CASE ( CSCONV )
+  CASE( 'KAFR' )
+    IF (.NOT. ( LUSERV ) ) THEN
+      WRITE(UNIT=ILUOUT,FMT=9002) KMI
+      WRITE(UNIT=ILUOUT,FMT='("YOU WANT TO USE THE KAIN-FRITSCH SHALLOW CONV. ",&
+      &" SCHEME. YOU MUST HAVE VAPOR ",/,"LUSERV IS SET TO TRUE ")')
+      LUSERV=.TRUE.
+    ELSE IF (.NOT. ( LUSERI ) ) THEN
+      WRITE(UNIT=ILUOUT,FMT=9002) KMI
+      WRITE(UNIT=ILUOUT,FMT='("YOU WANT TO USE THE KAIN-FRITSCH",&
+      &" SHALLOW CONV. SCHEME. BUT THE DETRAINED CLOUD ICE WILL BE ADDED TO   ",&
+      &" THE CLOUD WATER  ")')
+    ELSE IF (.NOT. ( LUSERI.AND.LUSERC ) ) THEN
+      WRITE(UNIT=ILUOUT,FMT=9002) KMI
+      WRITE(UNIT=ILUOUT,FMT='("YOU WANT TO USE THE KAIN-FRITSCH",&
+      &" SHALLOW CONV. SCHEME. BUT THE DETRAINED CLOUD WATER AND CLOUD ICE    ",&
+      &" WILL BE ADDED TO THE WATER VAPOR FIELD  ")')
+    END IF
+    IF ( LCHTRANS .AND. NSV == 0 ) THEN
+      WRITE(UNIT=ILUOUT,FMT=9002) KMI
+      WRITE(UNIT=ILUOUT,FMT='("YOU WANT TO USE THE LCHTRANS OPTION= ",&
+      &"CONVECTIVE TRANSPORT OF TRACERS BUT YOUR TRACER ",&
+      &"NUMBER NSV IS ZERO ",/,"LCHTRANS IS SET TO FALSE")')
+      LCHTRANS=.FALSE.
+    END IF
+ CASE( 'EDKF' )
+    IF (CTURB == 'NONE' ) THEN
+      WRITE(UNIT=ILUOUT,FMT=9003) KMI
+      WRITE(UNIT=ILUOUT,FMT='("YOU WANT TO USE THE EDKF ", & 
+      &"SHALLOW CONVECTION WITHOUT TURBULENCE SCHEME : ", &
+      &"IT IS NOT POSSIBLE")')
+!
+ !callabortstop
+      CALL PRINT_MSG(NVERB_FATAL,'GEN','READ_EXSEG_n','')
+    END IF
+END SELECT
+!
+!
+CGETCONV = 'SKIP'
+!
+IF ( (CDCONV /= 'NONE' .OR. CSCONV == 'KAFR' ) .AND. CPROGRAM=='MESONH') THEN
+  CGETCONV = 'READ'
+  IF( HDCONV == 'NONE' .AND. CCONF=='RESTA') THEN
+    WRITE(UNIT=ILUOUT,FMT=9001) KMI
+    WRITE(UNIT=ILUOUT,FMT='(" YOU ARE PERFORMING A RESTART. FOR THIS  ",&
+     &" SEGMENT, YOU ARE USING A DEEP CONVECTION SCHEME AND NO DEEP    ",&
+     &" CONVECTION SCHEME WAS USED FOR THE PREVIOUS SEGMENT. ")')
+!
+    CGETCONV = 'INIT'
+  END IF
+  IF(CCONF=='START') THEN
+    CGETCONV = 'INIT'
+  END IF
+END IF
+!
+!*       3.7  configuration and model version
+!
+IF (KMI == 1) THEN                                                
+! 
+  IF (L1D.AND.(CLBCX(1)/='CYCL'.AND.CLBCX(2)/='CYCL' &
+          .AND.CLBCY(1)/='CYCL'.AND.CLBCY(2)/='CYCL')) THEN
+    WRITE(UNIT=ILUOUT,FMT=9003) KMI
+    WRITE(UNIT=ILUOUT,FMT='("YOU WANT TO USE A 1D MODEL VERSION WITH NON-CYCL",&
+                & "CLBCX OR CLBCY VALUES")')
+ !callabortstop
+    CALL PRINT_MSG(NVERB_FATAL,'GEN','READ_EXSEG_n','')
+  END IF
+  IF (L2D.AND.(CLBCY(1)/='CYCL'.AND.CLBCY(2)/='CYCL')) THEN
+    WRITE(UNIT=ILUOUT,FMT=9003) KMI
+    WRITE(UNIT=ILUOUT,FMT='("YOU WANT TO USE A 2D MODEL VERSION WITH NON-CYCL",&
+                & " CLBCY VALUES")')
+ !callabortstop
+    CALL PRINT_MSG(NVERB_FATAL,'GEN','READ_EXSEG_n','')
+  END IF
+  !
+ IF ( (.NOT. LCARTESIAN) .AND. ( LCORIO) .AND. (.NOT. LGEOST_UV_FRC) ) THEN
+   WRITE(UNIT=ILUOUT,FMT=9002) KMI
+   WRITE(UNIT=ILUOUT,FMT='("BE CAREFUL YOU COULD HAVE SPURIOUS MOTIONS      " ,&
+        & " NEAR THE LBC AS LCORIO=T and  LGEOST_UV_FRC=F")')
+ END IF
+  !
+  IF ((.NOT.LFLAT).AND.OFLAT) THEN                                      
+    WRITE(UNIT=ILUOUT,FMT=9002) KMI 
+    WRITE(UNIT=ILUOUT,FMT=*) 'ZERO OROGRAPHY IN INITIAL FILE'
+    WRITE(UNIT=ILUOUT,FMT=*) '***** ALL TERMS HAVE BEEN NEVERTHELESS COMPUTED WITHOUT SIMPLIFICATION*****'
+    WRITE(UNIT=ILUOUT,FMT=*) 'THIS SHOULD LEAD TO ERRORS IN THE PRESSURE COMPUTATION'     
+  END IF
+  IF (LFLAT.AND.(.NOT.OFLAT)) THEN
+    WRITE(UNIT=ILUOUT,FMT=9002) KMI
+    WRITE(UNIT=ILUOUT,FMT='(" OROGRAPHY IS NOT EQUAL TO ZERO ",            &
+          & "IN INITIAL FILE" ,/,                                          &
+          & "******* OROGRAPHY HAS BEEN SET TO ZERO *********",/,          &
+          & "ACCORDING TO ZERO OROGRAPHY, SIMPLIFICATIONS  HAVE  ",        &
+          & "BEEN MADE IN  COMPUTATIONS")')
+  END IF 
+END IF
+!
+!*       3.8  System of equations
+!
+IF ( HEQNSYS /= CEQNSYS ) THEN
+  WRITE(UNIT=ILUOUT,FMT=9003) KMI
+  WRITE(ILUOUT,FMT=*) 'YOU HAVE CHANGED THE SYSTEM OF EQUATIONS'
+  WRITE(ILUOUT,FMT=*) 'THE ANELASTIC CONSTRAINT IS PERHAPS CHANGED :'
+  WRITE(ILUOUT,FMT=*) 'FOR THE INITIAL FILE YOU HAVE USED ',HEQNSYS
+  WRITE(ILUOUT,FMT=*) 'FOR THE RUN YOU PLAN TO USE ',CEQNSYS
+  WRITE(ILUOUT,FMT=*) 'THIS CAN LEAD TO A NUMERICAL EXPLOSION IN THE FIRST TIME STEPS'
+ !callabortstop
+  CALL PRINT_MSG(NVERB_FATAL,'GEN','READ_EXSEG_n','')
+END IF
+!
+!        3.9  Numerical schemes
+!
+IF ( (CUVW_ADV_SCHEME == 'CEN4TH') .AND. &
+      (CTEMP_SCHEME /= 'LEFR') .AND. (CTEMP_SCHEME /= 'RKC4') ) THEN
+   WRITE(UNIT=ILUOUT,FMT=9003) KMI
+   WRITE(UNIT=ILUOUT,FMT='("CEN4TH SCHEME HAS TO BE USED WITH ",&
+    &"CTEMP_SCHEME = LEFR of RKC4 ONLY")')   
+ !callabortstop
+   CALL PRINT_MSG(NVERB_FATAL,'GEN','READ_EXSEG_n','')
+END IF
+!
+IF ( (CUVW_ADV_SCHEME == 'WENO_K') .AND. LNUMDIFU ) THEN
+   WRITE(UNIT=ILUOUT,FMT=9002) KMI
+   WRITE(UNIT=ILUOUT,FMT='("YOU WANT TO USE NUMERICAL DIFFUSION ",&
+    &"WITH WENO SCHEME ALREADY DIFFUSIVE")')   
+END IF
+!-------------------------------------------------------------------------------
+!
+!*       4.    CHECK COHERENCE BETWEEN EXSEG VARIABLES
+!              ---------------------------------------
+!        
+!*       4.1  coherence between coupling variables in EXSEG file  
+!                      
+IF (KMI == 1) THEN
+  NCPL_NBR = 0
+  DO JCI = 1,JPCPLFILEMAX
+    IF (LEN_TRIM(CCPLFILE(JCI)) /= 0) THEN        ! Finds the number 
+      NCPL_NBR = NCPL_NBR + 1                     ! of coupling files
+    ENDIF
+    IF (JCI/=JPCPLFILEMAX) THEN                   ! Deplaces the coupling files
+      IF ((LEN_TRIM(CCPLFILE(JCI)) == 0) .AND.   &! names if one missing
+          (LEN_TRIM(CCPLFILE(JCI+1)) /= 0)) THEN
+        DO JI=JCI,JPCPLFILEMAX-1
+          CCPLFILE(JI)=CCPLFILE(JI+1)
+        END DO
+        CCPLFILE(JPCPLFILEMAX)='    '
+      END IF
+    END IF
+  END DO
+!
+  IF (NCPL_NBR /= 0) THEN         
+    LSTEADYLS = .FALSE.
+  ELSE
+    LSTEADYLS = .TRUE.
+  ENDIF 
+END IF
+!        
+!*       4.3   check consistency in forcing switches
+!
+IF ( LFORCING ) THEN
+  IF ( LRELAX_THRV_FRC .AND. ( LTEND_THRV_FRC .OR. LGEOST_TH_FRC ) ) THEN
+    WRITE(UNIT=ILUOUT,FMT=9002) KMI
+    WRITE(ILUOUT,FMT=*) 'YOU CHOSE A TEMPERATURE AND HUMIDITY RELAXATION'
+    WRITE(ILUOUT,FMT=*) 'TOGETHER WITH TENDENCY OR GEOSTROPHIC FORCING'
+    WRITE(ILUOUT,FMT=*) &
+  'YOU MIGHT CHECK YOUR SWITCHES:  LRELAX_THRV_FRC, LTEND_THRV_FRC, AND'
+    WRITE(ILUOUT,FMT=*) 'LGEOST_TH_FRC'
+  END IF
+!
+  IF ( LRELAX_UV_FRC .AND. LGEOST_UV_FRC ) THEN
+    WRITE(UNIT=ILUOUT,FMT=9003) KMI
+    WRITE(ILUOUT,FMT=*) 'YOU MUST NOT USE A WIND RELAXATION' 
+    WRITE(ILUOUT,FMT=*) 'TOGETHER WITH A GEOSTROPHIC FORCING'
+    WRITE(ILUOUT,FMT=*) 'CHECK SWITCHES:  LRELAX_UV_FRC, LGEOST_UV_FRC'
+ !callabortstop
+    CALL PRINT_MSG(NVERB_FATAL,'GEN','READ_EXSEG_n','')
+  END IF
+!
+  IF ( CRELAX_HEIGHT_TYPE.NE."FIXE" .AND. CRELAX_HEIGHT_TYPE.NE."THGR" ) THEN
+    WRITE(UNIT=ILUOUT,FMT=9003) KMI
+    WRITE(ILUOUT,FMT=*) 'CRELAX_HEIGHT_TYPE MUST BE EITHER "FIXE" OR "THGR"'
+    WRITE(ILUOUT,FMT=*) 'BUT IT IS "', CRELAX_HEIGHT_TYPE, '"'
+ !callabortstop
+    CALL PRINT_MSG(NVERB_FATAL,'GEN','READ_EXSEG_n','')
+  END IF
+!
+  IF ( .NOT.LCORIO .AND. LGEOST_UV_FRC ) THEN
+    WRITE(UNIT=ILUOUT,FMT=9003) KMI
+    WRITE(ILUOUT,FMT=*) 'YOU CANNOT HAVE A GEOSTROPHIC FORCING WITHOUT'
+    WRITE(ILUOUT,FMT=*) 'ACTIVATING LCORIOLIS OPTION'
+ !callabortstop
+    CALL PRINT_MSG(NVERB_FATAL,'GEN','READ_EXSEG_n','')
+  END IF
+!
+  IF ( LPGROUND_FRC ) THEN
+    WRITE(ILUOUT,FMT=*) 'SURFACE PRESSURE FORCING NOT YET IMPLEMENTED'
+ !callabortstop
+    CALL PRINT_MSG(NVERB_FATAL,'GEN','READ_EXSEG_n','')
+  END IF
+!
+END IF
+!
+IF (LTRANS .AND. .NOT. LFLAT ) THEN
+    WRITE(UNIT=ILUOUT,FMT=9003) KMI
+    WRITE(ILUOUT,FMT=*) 'YOU ASK FOR A CONSTANT SPEED DOMAIN TRANSLATION '
+    WRITE(ILUOUT,FMT=*) 'BUT NOT IN THE FLAT TERRAIN CASE:'
+    WRITE(ILUOUT,FMT=*) 'THIS IS NOT ALLOWED ACTUALLY'
+ !callabortstop
+    CALL PRINT_MSG(NVERB_FATAL,'GEN','READ_EXSEG_n','')
+END IF
+!
+!*       4.4  Check the coherence between the LUSERn and LHORELAX
+!
+IF (.NOT. LUSERV .AND. LHORELAX_RV) THEN
+  LHORELAX_RV=.FALSE.
+  WRITE(UNIT=ILUOUT,FMT=9002) KMI
+  WRITE(ILUOUT,FMT=*) 'YOU WANT TO RELAX RV FIELD BUT IT DOES NOT EXIST.'
+  WRITE(ILUOUT,FMT=*) 'THEREFORE LHORELAX_RV=FALSE'
+END IF
+!
+IF (.NOT. LUSERC .AND. LHORELAX_RC) THEN
+  LHORELAX_RC=.FALSE.
+  WRITE(UNIT=ILUOUT,FMT=9002) KMI
+  WRITE(ILUOUT,FMT=*) 'YOU WANT TO RELAX RC FIELD BUT IT DOES NOT EXIST.'
+  WRITE(ILUOUT,FMT=*) 'THEREFORE LHORELAX_RC=FALSE'
+END IF
+!
+IF (.NOT. LUSERR .AND. LHORELAX_RR) THEN
+  LHORELAX_RR=.FALSE.
+  WRITE(UNIT=ILUOUT,FMT=9002) KMI
+  WRITE(ILUOUT,FMT=*) 'YOU WANT TO RELAX RR FIELD BUT IT DOES NOT EXIST.'
+  WRITE(ILUOUT,FMT=*) 'THEREFORE LHORELAX_RR=FALSE'
+END IF
+!
+IF (.NOT. LUSERI .AND. LHORELAX_RI) THEN
+  LHORELAX_RI=.FALSE.
+  WRITE(UNIT=ILUOUT,FMT=9002) KMI
+  WRITE(ILUOUT,FMT=*) 'YOU WANT TO RELAX RI FIELD BUT IT DOES NOT EXIST.'
+  WRITE(ILUOUT,FMT=*) 'THEREFORE LHORELAX_RI=FALSE'
+END IF
+!
+IF (.NOT. LUSERS .AND. LHORELAX_RS) THEN
+  LHORELAX_RS=.FALSE.
+  WRITE(UNIT=ILUOUT,FMT=9002) KMI
+  WRITE(ILUOUT,FMT=*) 'YOU WANT TO RELAX RS FIELD BUT IT DOES NOT EXIST.'
+  WRITE(ILUOUT,FMT=*) 'THEREFORE LHORELAX_RS=FALSE'
+END IF
+!
+IF (.NOT. LUSERG .AND. LHORELAX_RG) THEN
+  LHORELAX_RG=.FALSE.
+  WRITE(UNIT=ILUOUT,FMT=9002) KMI
+  WRITE(ILUOUT,FMT=*) 'YOU WANT TO RELAX RG FIELD BUT IT DOES NOT EXIST.'
+  WRITE(ILUOUT,FMT=*) 'THEREFORE LHORELAX_RG=FALSE'
+END IF
+!
+IF (.NOT. LUSERH .AND. LHORELAX_RH) THEN
+  LHORELAX_RH=.FALSE.
+  WRITE(UNIT=ILUOUT,FMT=9002) KMI
+  WRITE(ILUOUT,FMT=*) 'YOU WANT TO RELAX RH FIELD BUT IT DOES NOT EXIST.'
+  WRITE(ILUOUT,FMT=*) 'THEREFORE LHORELAX_RH=FALSE'
+END IF
+!
+IF (CTURB=='NONE' .AND. LHORELAX_TKE) THEN
+  LHORELAX_TKE=.FALSE.
+  WRITE(UNIT=ILUOUT,FMT=9002) KMI
+  WRITE(ILUOUT,FMT=*) 'YOU WANT TO RELAX TKE FIELD BUT IT DOES NOT EXIST.'
+  WRITE(ILUOUT,FMT=*) 'THEREFORE LHORELAX_TKE=FALSE'
+END IF
+!
+!
+IF (CCLOUD/='C2R2'  .AND. CCLOUD/='KHKO'  .AND. LHORELAX_SVC2R2) THEN
+  LHORELAX_SVC2R2=.FALSE.
+  WRITE(UNIT=ILUOUT,FMT=9002) KMI
+  WRITE(ILUOUT,FMT=*) 'YOU WANT TO RELAX C2R2 or KHKO FIELD BUT IT DOES NOT EXIST.'
+  WRITE(ILUOUT,FMT=*) 'THEREFORE LHORELAX_SVC2R2=FALSE'
+END IF
+!
+IF (CCLOUD/='C3R5' .AND. LHORELAX_SVC1R3) THEN
+  LHORELAX_SVC1R3=.FALSE.
+  WRITE(UNIT=ILUOUT,FMT=9002) KMI
+  WRITE(ILUOUT,FMT=*) 'YOU WANT TO RELAX C3R5 FIELD BUT IT DOES NOT EXIST.'
+  WRITE(ILUOUT,FMT=*) 'THEREFORE LHORELAX_SVC1R3=FALSE'
+END IF
+!
+IF (CCLOUD/='LIMA' .AND. LHORELAX_SVLIMA) THEN
+  LHORELAX_SVLIMA=.FALSE.
+  WRITE(UNIT=ILUOUT,FMT=9002) KMI
+  WRITE(ILUOUT,FMT=*) 'YOU WANT TO RELAX LIMA FIELD BUT IT DOES NOT EXIST.'
+  WRITE(ILUOUT,FMT=*) 'THEREFORE LHORELAX_SVLIMA=FALSE'
+END IF
+!
+IF (CELEC(1:3) /= 'ELE' .AND. LHORELAX_SVELEC) THEN
+  LHORELAX_SVELEC=.FALSE.
+  WRITE(UNIT=ILUOUT,FMT=9002) KMI
+  WRITE(ILUOUT,FMT=*) 'YOU WANT TO RELAX ELEC FIELD BUT IT DOES NOT EXIST.'
+  WRITE(ILUOUT,FMT=*) 'THEREFORE LHORELAX_SVELEC=FALSE'
+END IF
+!
+IF (.NOT. LUSECHEM .AND. LHORELAX_SVCHEM) THEN
+  LHORELAX_SVCHEM=.FALSE.
+  WRITE(UNIT=ILUOUT,FMT=9002) KMI
+  WRITE(ILUOUT,FMT=*) 'YOU WANT TO RELAX CHEM FIELD BUT IT DOES NOT EXIST.'
+  WRITE(ILUOUT,FMT=*) 'THEREFORE LHORELAX_SVCHEM=FALSE'
+END IF
+!
+IF (.NOT. LUSECHIC .AND. LHORELAX_SVCHIC) THEN
+  LHORELAX_SVCHIC=.FALSE.
+  WRITE(UNIT=ILUOUT,FMT=9002) KMI
+  WRITE(ILUOUT,FMT=*) 'YOU WANT TO RELAX ICE CHEM FIELD BUT IT DOES NOT EXIST.'
+  WRITE(ILUOUT,FMT=*) 'THEREFORE LHORELAX_SVCHIC=FALSE'
+END IF
+!
+IF (.NOT. LORILAM .AND. LHORELAX_SVAER) THEN
+  LHORELAX_SVAER=.FALSE.
+  WRITE(UNIT=ILUOUT,FMT=9002) KMI
+  WRITE(ILUOUT,FMT=*) 'YOU WANT TO RELAX AEROSOL FIELD BUT IT DOES NOT EXIST.'
+  WRITE(ILUOUT,FMT=*) 'THEREFORE LHORELAX_SVAER=FALSE'
+END IF
+
+IF (.NOT. LDUST .AND. LHORELAX_SVDST) THEN
+  LHORELAX_SVDST=.FALSE.
+  WRITE(UNIT=ILUOUT,FMT=9002) KMI
+  WRITE(ILUOUT,FMT=*) 'YOU WANT TO RELAX DUST FIELD BUT IT DOES NOT EXIST.'
+  WRITE(ILUOUT,FMT=*) 'THEREFORE LHORELAX_SVDST=FALSE'
+END IF
+
+IF (.NOT. LSALT .AND. LHORELAX_SVSLT) THEN
+  LHORELAX_SVSLT=.FALSE.
+  WRITE(UNIT=ILUOUT,FMT=9002) KMI
+  WRITE(ILUOUT,FMT=*) 'YOU WANT TO RELAX SEA SALT FIELD BUT IT DOES NOT EXIST.'
+  WRITE(ILUOUT,FMT=*) 'THEREFORE LHORELAX_SVSLT=FALSE'
+END IF
+
+IF (.NOT. LPASPOL .AND. LHORELAX_SVPP) THEN
+  LHORELAX_SVPP=.FALSE.
+  WRITE(UNIT=ILUOUT,FMT=9002) KMI
+  WRITE(ILUOUT,FMT=*) 'YOU WANT TO RELAX PASSIVE POLLUTANT FIELD BUT IT DOES NOT EXIST.'
+  WRITE(ILUOUT,FMT=*) 'THEREFORE LHORELAX_SVPP=FALSE'
+END IF
+#ifdef MNH_FOREFIRE
+IF (.NOT. LFOREFIRE .AND. LHORELAX_SVFF) THEN
+  LHORELAX_SVFF=.FALSE.
+  WRITE(UNIT=ILUOUT,FMT=9002) KMI
+  WRITE(ILUOUT,FMT=*) 'YOU WANT TO RELAX FOREFIRE FLUXES BUT THEY DO NOT EXIST.'
+  WRITE(ILUOUT,FMT=*) 'THEREFORE LHORELAX_SVFF=FALSE'
+END IF
+#endif
+IF (.NOT. LCONDSAMP .AND. LHORELAX_SVCS) THEN
+  LHORELAX_SVCS=.FALSE.
+  WRITE(UNIT=ILUOUT,FMT=9002) KMI
+  WRITE(ILUOUT,FMT=*) 'YOU WANT TO RELAX CONDITIONAL SAMPLING FIELD BUT IT DOES NOT EXIST.'
+  WRITE(ILUOUT,FMT=*) 'THEREFORE LHORELAX_SVCS=FALSE'
+END IF
+
+IF (.NOT. LBLOWSNOW .AND. LHORELAX_SVSNW) THEN
+  LHORELAX_SVSNW=.FALSE.
+  WRITE(UNIT=ILUOUT,FMT=9002) KMI
+  WRITE(ILUOUT,FMT=*) 'YOU WANT TO RELAX BLOWING SNOW FIELD BUT IT DOES NOT EXIST.'
+  WRITE(ILUOUT,FMT=*) 'THEREFORE LHORELAX_SVSNW=FALSE'
+END IF
+
+IF (ANY(LHORELAX_SV(NSV+1:))) THEN
+  LHORELAX_SV(NSV+1:)=.FALSE.
+  WRITE(UNIT=ILUOUT,FMT=9002) KMI
+  WRITE(ILUOUT,FMT=*) 'YOU WANT TO RELAX SV(NSV+1:) FIELD BUT IT DOES NOT EXIST.'
+  WRITE(ILUOUT,FMT=*) 'THEREFORE LHORELAX_SV(NSV+1:)=FALSE'
+END IF
+!
+!*       4.5   check the number of points for the horizontal relaxation
+!
+IF ( NRIMX > KRIMX .AND. .NOT.LHORELAX_SVELEC ) THEN
+  NRIMX = KRIMX 
+  WRITE(UNIT=ILUOUT,FMT=9001) KMI
+  WRITE(ILUOUT,FMT=*) 'YOU WANT TO USE A LARGER NUMBER OF POINTS '
+  WRITE(ILUOUT,FMT=*) 'FOR THE HORIZONTAL RELAXATION THAN THE '
+  WRITE(ILUOUT,FMT=*) 'CORRESPONDING NUMBER OF LARGE SCALE FIELDS:'
+  WRITE(ILUOUT,FMT=*) 'IT IS THEREFORE REDUCED TO NRIMX =',NRIMX
+END IF
+!
+IF ( L2D .AND. KRIMY>0 ) THEN
+  NRIMY = 0 
+  WRITE(UNIT=ILUOUT,FMT=9001) KMI
+  WRITE(ILUOUT,FMT=*) 'YOU WANT TO USE A 2D MODEL THEREFORE  NRIMY=0 '
+END IF
+!
+IF ( NRIMY > KRIMY .AND. .NOT.LHORELAX_SVELEC ) THEN
+  NRIMY = KRIMY 
+  WRITE(UNIT=ILUOUT,FMT=9001) KMI
+  WRITE(ILUOUT,FMT=*) 'YOU WANT TO USE A LARGER NUMBER OF POINTS '
+  WRITE(ILUOUT,FMT=*) 'FOR THE HORIZONTAL RELAXATION THAN THE '
+  WRITE(ILUOUT,FMT=*) 'CORRESPONDING NUMBER OF LARGE SCALE FIELDS:'
+  WRITE(ILUOUT,FMT=*) 'IT IS THEREFORE REDUCED TO NRIMY =',NRIMY
+END IF
+!
+IF ( (.NOT. LHORELAX_UVWTH) .AND. (.NOT.(ANY(LHORELAX_SV))) .AND.  &
+     (.NOT. LHORELAX_SVC2R2).AND. (.NOT. LHORELAX_SVC1R3)   .AND.  &
+     (.NOT. LHORELAX_SVLIMA).AND.                                  &
+     (.NOT. LHORELAX_SVELEC).AND. (.NOT. LHORELAX_SVCHEM)   .AND.  &
+     (.NOT. LHORELAX_SVLG)  .AND. (.NOT. LHORELAX_SVPP)     .AND.  &
+     (.NOT. LHORELAX_SVCS)  .AND.                                  &
+#ifdef MNH_FOREFIRE
+     (.NOT. LHORELAX_SVFF)  .AND.                                  &
+#endif
+     (.NOT. LHORELAX_RV)    .AND. (.NOT. LHORELAX_RC)       .AND.  &
+     (.NOT. LHORELAX_RR)    .AND. (.NOT. LHORELAX_RI)       .AND.  &
+     (.NOT. LHORELAX_RS)    .AND. (.NOT. LHORELAX_RG)       .AND.  &
+     (.NOT. LHORELAX_RH)    .AND. (.NOT. LHORELAX_TKE)      .AND.  &
+     (.NOT. LHORELAX_SVCHIC).AND.                                  &
+                                  (NRIMX /= 0 .OR. NRIMY /= 0))  THEN  
+  WRITE(UNIT=ILUOUT,FMT=9001) KMI
+  WRITE(ILUOUT,FMT=*) 'YOU DO NOT WANT TO USE THE HORIZONTAL RELAXATION '
+  WRITE(ILUOUT,FMT=*) 'THEREFORE NRIMX=NRIMY=0     '
+  NRIMX=0
+  NRIMY=0
+END IF
+!
+IF ((LHORELAX_UVWTH  .OR. LHORELAX_SVPP   .OR.  &
+     LHORELAX_SVCS   .OR.                       &
+#ifdef MNH_FOREFIRE
+     LHORELAX_SVFF   .OR.                       &
+#endif
+     LHORELAX_SVC2R2 .OR. LHORELAX_SVC1R3 .OR.  &
+     LHORELAX_SVLIMA .OR.                       &
+     LHORELAX_SVELEC .OR. LHORELAX_SVCHEM .OR.  &
+     LHORELAX_SVLG   .OR. ANY(LHORELAX_SV) .OR. &
+     LHORELAX_RV     .OR. LHORELAX_RC .OR.      &
+     LHORELAX_RR     .OR. LHORELAX_RI .OR.      &
+     LHORELAX_RG     .OR. LHORELAX_RS .OR.      &
+     LHORELAX_RH     .OR. LHORELAX_TKE.OR.      &
+     LHORELAX_SVCHIC )                          &
+     .AND. (NRIMX==0 .OR. (NRIMY==0 .AND. .NOT.(L2D) ))) THEN
+  WRITE(UNIT=ILUOUT,FMT=9003) KMI
+  WRITE(ILUOUT,FMT=*) 'YOU WANT TO USE THE HORIZONTAL RELAXATION '
+  WRITE(ILUOUT,FMT=*) 'BUT NRIMX OR NRIMY=0 CHANGE YOUR VALUES   '
+  WRITE(ILUOUT,FMT=*) "LHORELAX_UVWTH=",LHORELAX_UVWTH
+  WRITE(ILUOUT,FMT=*) "LHORELAX_SVC2R2=",LHORELAX_SVC2R2
+  WRITE(ILUOUT,FMT=*) "LHORELAX_SVC1R3=",LHORELAX_SVC1R3
+  WRITE(ILUOUT,FMT=*) "LHORELAX_SVLIMA=",LHORELAX_SVLIMA
+  WRITE(ILUOUT,FMT=*) "LHORELAX_SVELEC=",LHORELAX_SVELEC
+  WRITE(ILUOUT,FMT=*) "LHORELAX_SVCHEM=",LHORELAX_SVCHEM
+  WRITE(ILUOUT,FMT=*) "LHORELAX_SVCHIC=",LHORELAX_SVCHIC
+  WRITE(ILUOUT,FMT=*) "LHORELAX_SVLG=",LHORELAX_SVLG
+  WRITE(ILUOUT,FMT=*) "LHORELAX_SVPP=",LHORELAX_SVPP
+#ifdef MNH_FOREFIRE
+  WRITE(ILUOUT,FMT=*) "LHORELAX_SVFF=",LHORELAX_SVFF
+#endif
+  WRITE(ILUOUT,FMT=*) "LHORELAX_SVCS=",LHORELAX_SVCS
+  WRITE(ILUOUT,FMT=*) "LHORELAX_SV=",LHORELAX_SV
+  WRITE(ILUOUT,FMT=*) "LHORELAX_RV=",LHORELAX_RV
+  WRITE(ILUOUT,FMT=*) "LHORELAX_RC=",LHORELAX_RC
+  WRITE(ILUOUT,FMT=*) "LHORELAX_RR=",LHORELAX_RR
+  WRITE(ILUOUT,FMT=*) "LHORELAX_RI=",LHORELAX_RI
+  WRITE(ILUOUT,FMT=*) "LHORELAX_RG=",LHORELAX_RG
+  WRITE(ILUOUT,FMT=*) "LHORELAX_RS=",LHORELAX_RS
+  WRITE(ILUOUT,FMT=*) "LHORELAX_RH=",LHORELAX_RH
+  WRITE(ILUOUT,FMT=*) "LHORELAX_TKE=", LHORELAX_TKE
+  WRITE(ILUOUT,FMT=*) "NRIMX=",NRIMX
+  WRITE(ILUOUT,FMT=*) "NRIMY=",NRIMY
+  WRITE(ILUOUT,FMT=*) "L2D=",L2D
+ !callabortstop
+  CALL PRINT_MSG(NVERB_FATAL,'GEN','READ_EXSEG_n','')
+END IF
+! 
+IF ((LHORELAX_UVWTH  .OR. LHORELAX_SVPP  .OR.   &
+     LHORELAX_SVCS   .OR.                       &
+#ifdef MNH_FOREFIRE
+     LHORELAX_SVFF   .OR.                       &
+#endif
+     LHORELAX_SVC2R2 .OR. LHORELAX_SVC1R3 .OR.  &
+     LHORELAX_SVLIMA .OR.                       &
+     LHORELAX_SVELEC .OR. LHORELAX_SVCHEM .OR.  &
+     LHORELAX_SVLG   .OR. ANY(LHORELAX_SV) .OR. &
+     LHORELAX_RV     .OR. LHORELAX_RC .OR.      &
+     LHORELAX_RR     .OR. LHORELAX_RI .OR.      &
+     LHORELAX_RG     .OR. LHORELAX_RS .OR.      &
+     LHORELAX_RH     .OR. LHORELAX_TKE.OR.      &
+     LHORELAX_SVCHIC )                          &
+     .AND. (KMI /=1)) THEN
+  WRITE(UNIT=ILUOUT,FMT=9003) KMI
+  WRITE(ILUOUT,FMT=*) 'YOU WANT TO USE THE HORIZONTAL RELAXATION '
+  WRITE(ILUOUT,FMT=*) 'FOR A NESTED MODEL BUT THE COUPLING IS ALREADY DONE' 
+  WRITE(ILUOUT,FMT=*) 'BY THE GRID NESTING. CHANGE LHORELAX TO FALSE'
+ !callabortstop
+  CALL PRINT_MSG(NVERB_FATAL,'GEN','READ_EXSEG_n','')
+END IF
+! 
+IF (KMI==1) THEN
+  GRELAX = .NOT.(OUSERV)  .AND.  LUSERV  .AND. LHORELAX_RV
+ELSE
+  GRELAX = .NOT.(LUSERV_G(NDAD(KMI)))  .AND.  LUSERV_G(KMI).AND. LHORELAX_RV 
+END IF 
+!
+IF ( GRELAX )  THEN
+  LHORELAX_RV=.FALSE.
+  WRITE(UNIT=ILUOUT,FMT=9001) KMI
+  WRITE(ILUOUT,FMT=*) 'YOU WANT TO RELAX THE RV FIELD'
+  WRITE(ILUOUT,FMT=*) 'TOWARDS THE LARGE SCALE FIELD OF MODEL',NDAD(KMI)
+  WRITE(ILUOUT,FMT=*) 'BUT IT DOES NOT EXIST.'
+  WRITE(ILUOUT,FMT=*) 'THEREFORE LHORELAX_RV=FALSE'
+END IF
+!
+IF (KMI==1) THEN
+  GRELAX = .NOT.(OUSERC)  .AND.  LUSERC  .AND. LHORELAX_RC
+ELSE
+  GRELAX = .NOT.(LUSERC_G(NDAD(KMI)))  .AND.  LUSERC_G(KMI).AND. LHORELAX_RC 
+END IF 
+!
+IF ( GRELAX )  THEN
+  LHORELAX_RC=.FALSE.
+  WRITE(UNIT=ILUOUT,FMT=9001) KMI
+  WRITE(ILUOUT,FMT=*) 'YOU WANT TO RELAX THE RC FIELD'
+  WRITE(ILUOUT,FMT=*) 'TOWARDS THE LARGE SCALE FIELD OF MODEL',NDAD(KMI)
+  WRITE(ILUOUT,FMT=*) 'BUT IT DOES NOT EXIST.'
+  WRITE(ILUOUT,FMT=*) 'THEREFORE LHORELAX_RC=FALSE'
+END IF
+!
+IF (KMI==1) THEN
+  GRELAX = .NOT.(OUSERR)  .AND.  LUSERR  .AND. LHORELAX_RR
+ELSE
+  GRELAX = .NOT.(LUSERR_G(NDAD(KMI)))  .AND.  LUSERR_G(KMI).AND. LHORELAX_RR 
+END IF 
+!
+IF ( GRELAX )  THEN
+  LHORELAX_RR=.FALSE.
+  WRITE(UNIT=ILUOUT,FMT=9001) KMI
+  WRITE(ILUOUT,FMT=*) 'YOU WANT TO RELAX THE RR FIELD'
+  WRITE(ILUOUT,FMT=*) 'TOWARDS THE LARGE SCALE FIELD OF MODEL',NDAD(KMI)
+  WRITE(ILUOUT,FMT=*) 'BUT IT DOES NOT EXIST.'
+  WRITE(ILUOUT,FMT=*) 'THEREFORE LHORELAX_RR=FALSE'
+END IF
+!
+IF (KMI==1) THEN
+  GRELAX = .NOT.(OUSERI)  .AND.  LUSERI  .AND. LHORELAX_RI
+ELSE
+  GRELAX = .NOT.(LUSERI_G(NDAD(KMI)))  .AND.  LUSERI_G(KMI).AND. LHORELAX_RI 
+END IF 
+!
+IF ( GRELAX )  THEN
+  LHORELAX_RI=.FALSE.
+  WRITE(UNIT=ILUOUT,FMT=9001) KMI
+  WRITE(ILUOUT,FMT=*) 'YOU WANT TO RELAX THE RI FIELD'
+  WRITE(ILUOUT,FMT=*) 'TOWARDS THE LARGE SCALE FIELD OF MODEL',NDAD(KMI)
+  WRITE(ILUOUT,FMT=*) 'BUT IT DOES NOT EXIST.'
+  WRITE(ILUOUT,FMT=*) 'THEREFORE LHORELAX_RI=FALSE'
+END IF
+!
+IF (KMI==1) THEN
+  GRELAX = .NOT.(OUSERG)  .AND.  LUSERG  .AND. LHORELAX_RG
+ELSE
+  GRELAX = .NOT.(LUSERG_G(NDAD(KMI)))  .AND.  LUSERG_G(KMI).AND. LHORELAX_RG 
+END IF 
+!
+IF ( GRELAX )  THEN
+  LHORELAX_RG=.FALSE.
+  WRITE(UNIT=ILUOUT,FMT=9001) KMI
+  WRITE(ILUOUT,FMT=*) 'YOU WANT TO RELAX THE RG FIELD'
+  WRITE(ILUOUT,FMT=*) 'TOWARDS THE LARGE SCALE FIELD OF MODEL',NDAD(KMI)
+  WRITE(ILUOUT,FMT=*) 'BUT IT DOES NOT EXIST.'
+  WRITE(ILUOUT,FMT=*) 'THEREFORE LHORELAX_RG=FALSE'
+END IF
+!
+IF (KMI==1) THEN
+  GRELAX = .NOT.(OUSERH)  .AND.  LUSERH  .AND. LHORELAX_RH
+ELSE
+  GRELAX = .NOT.(LUSERH_G(NDAD(KMI)))  .AND.  LUSERH_G(KMI).AND. LHORELAX_RH 
+END IF 
+!
+IF ( GRELAX )  THEN
+  LHORELAX_RH=.FALSE.
+  WRITE(UNIT=ILUOUT,FMT=9001) KMI
+  WRITE(ILUOUT,FMT=*) 'YOU WANT TO RELAX THE RH FIELD'
+  WRITE(ILUOUT,FMT=*) 'TOWARDS THE LARGE SCALE FIELD OF MODEL',NDAD(KMI)
+  WRITE(ILUOUT,FMT=*) 'BUT IT DOES NOT EXIST.'
+  WRITE(ILUOUT,FMT=*) 'THEREFORE LHORELAX_RH=FALSE'
+END IF
+!
+IF (KMI==1) THEN
+  GRELAX = .NOT.(OUSERS)  .AND.  LUSERS  .AND. LHORELAX_RS
+ELSE
+  GRELAX = .NOT.(LUSERS_G(NDAD(KMI)))  .AND.  LUSERS_G(KMI).AND. LHORELAX_RS 
+END IF 
+!
+IF ( GRELAX )  THEN
+  LHORELAX_RS=.FALSE.
+  WRITE(UNIT=ILUOUT,FMT=9001) KMI
+  WRITE(ILUOUT,FMT=*) 'YOU WANT TO RELAX THE RS FIELD'
+  WRITE(ILUOUT,FMT=*) 'TOWARDS THE LARGE SCALE FIELD OF MODEL',NDAD(KMI)
+  WRITE(ILUOUT,FMT=*) 'BUT IT DOES NOT EXIST.'
+  WRITE(ILUOUT,FMT=*) 'THEREFORE LHORELAX_RS=FALSE'
+END IF
+!
+IF (KMI==1) THEN
+  GRELAX = HTURB=='NONE'  .AND.  LUSETKE(1).AND. LHORELAX_TKE
+ELSE
+  GRELAX = .NOT.(LUSETKE(NDAD(KMI)))  .AND.  LUSETKE(KMI) .AND. LHORELAX_TKE 
+END IF 
+!
+IF ( GRELAX )  THEN
+  LHORELAX_TKE=.FALSE.
+  WRITE(UNIT=ILUOUT,FMT=9001) KMI
+  WRITE(ILUOUT,FMT=*) 'YOU WANT TO RELAX THE TKE FIELD'
+  WRITE(ILUOUT,FMT=*) 'TOWARDS THE LARGE SCALE FIELD OF MODEL',NDAD(KMI)
+  WRITE(ILUOUT,FMT=*) 'BUT IT DOES NOT EXIST.'
+  WRITE(ILUOUT,FMT=*) 'THEREFORE LHORELAX_TKE=FALSE'
+END IF
+!
+!
+DO JSV = 1,NSV_USER
+!
+  IF (KMI==1) THEN
+    GRELAX = KSV_USER<JSV  .AND.  LUSESV(JSV,1).AND.  LHORELAX_SV(JSV) 
+  ELSE
+    GRELAX = .NOT.(LUSESV(JSV,NDAD(KMI))) .AND. LUSESV(JSV,KMI) .AND. LHORELAX_SV(JSV)   
+  END IF 
+  !
+  IF ( GRELAX )  THEN
+  LHORELAX_SV(JSV)=.FALSE.
+  WRITE(UNIT=ILUOUT,FMT=9001) KMI
+  WRITE(ILUOUT,FMT=*) 'YOU WANT TO RELAX THE ',JSV,'  SV FIELD'
+  WRITE(ILUOUT,FMT=*) 'TOWARDS THE LARGE SCALE FIELD OF MODEL',NDAD(KMI)
+  WRITE(ILUOUT,FMT=*) 'BUT IT DOES NOT EXIST.'
+  WRITE(ILUOUT,FMT=*) 'THEREFORE LHORELAX_SV(',JSV,')=FALSE'
+ END IF
+END DO
+!
+!*       4.6   consistency in LES diagnostics choices
+!
+IF (CLES_NORM_TYPE=='EKMA' .AND. .NOT. LCORIO) THEN
+  WRITE(UNIT=ILUOUT,FMT=9002) KMI
+  WRITE(ILUOUT,FMT=*) 'YOU WANT TO USE THE EKMAN NORMALIZATION'
+  WRITE(ILUOUT,FMT=*) 'BUT CORIOLIS FORCE IS NOT USED (LCORIO=.FALSE.)'
+  WRITE(ILUOUT,FMT=*) 'THEN, NO NORMALIZATION IS PERFORMED'
+  CLES_NORM_TYPE='NONE'
+END IF
+!
+!*       4.7  Check the coherence with LNUMDIFF
+!
+IF (L1D .AND. (LNUMDIFU .OR. LNUMDIFTH .OR. LNUMDIFSV) ) THEN
+  WRITE(UNIT=ILUOUT,FMT=9002) KMI
+  WRITE(ILUOUT,FMT=*) 'YOU WANT TO USE HORIZONTAL DIFFUSION '
+  WRITE(ILUOUT,FMT=*) 'BUT YOU ARE IN A COLUMN MODEL (L1D=.TRUE.).'
+  WRITE(ILUOUT,FMT=*) 'THEREFORE LNUMDIFU and LNUMDIFTH and LNUMDIFSV'
+  WRITE(ILUOUT,FMT=*) 'ARE SET TO FALSE'
+  LNUMDIFU=.FALSE.
+  LNUMDIFTH=.FALSE.
+  LNUMDIFSV=.FALSE.
+END IF
+!
+IF (.NOT. LNUMDIFTH .AND. LZDIFFU) THEN
+  WRITE(UNIT=ILUOUT,FMT=9002) KMI
+  WRITE(ILUOUT,FMT=*) 'YOU DO NOT WANT TO USE HORIZONTAL DIFFUSION (LNUMDIFTH=F)'
+  WRITE(ILUOUT,FMT=*) 'BUT YOU WANT TO USE Z-NUMERICAL DIFFUSION  '
+  WRITE(ILUOUT,FMT=*) 'THEREFORE LNUMDIFTH IS SET TO TRUE'
+  LNUMDIFTH=.TRUE.
+END IF
+!
+!*       4.8  Other
+!
+IF (XTNUDGING < 4.*XTSTEP) THEN
+  XTNUDGING = 4.*XTSTEP
+  WRITE(UNIT=ILUOUT,FMT=9002) KMI
+  WRITE(UNIT=ILUOUT,FMT='("TIME SCALE FOR NUDGING CAN NOT BE SMALLER THAN",  &
+                 &   " FOUR TIMES THE TIME STEP")')
+  WRITE(ILUOUT,FMT=*) 'XTNUDGING is SET TO ',XTNUDGING
+END IF
+!
+!
+IF (XWAY(KMI) == 3. ) THEN
+  XWAY(KMI) = 2.
+  WRITE(UNIT=ILUOUT,FMT=9002) KMI
+  WRITE(UNIT=ILUOUT,FMT='("XWAY=3 DOES NOT EXIST ANYMORE; ", &                               
+                 &   " IT IS REPLACED BY XWAY=2 ")')
+END IF
+!
+IF ( (KMI == 1) .AND. XWAY(KMI) /= 0. ) THEN
+  XWAY(KMI) = 0.
+  WRITE(UNIT=ILUOUT,FMT=9002) KMI
+  WRITE(UNIT=ILUOUT,FMT='("XWAY MUST BE EQUAL TO 0 FOR DAD MODEL")')   
+END IF
+!
+!JUANZ ZRESI solver need BSPLITTING 
+IF ( CPRESOPT == 'ZRESI' .AND. CSPLIT /= 'BSPLITTING' ) THEN
+  WRITE(UNIT=ILUOUT,FMT=9003) KMI
+  WRITE(UNIT=ILUOUT,FMT='("Paralleliez in Z solver CPRESOPT=ZRESI need also CSPLIT=BSPLITTING ")')
+  WRITE(ILUOUT,FMT=*) ' ERROR you have to set also CSPLIT=BSPLITTING '
+ !callabortstop
+  CALL PRINT_MSG(NVERB_FATAL,'GEN','READ_EXSEG_n','')
+END IF
+!
+IF ( LEN_TRIM(HINIFILEPGD)>0 ) THEN
+  IF ( CINIFILEPGD/=HINIFILEPGD ) THEN 
+    WRITE(UNIT=ILUOUT,FMT=9001) KMI
+    WRITE(ILUOUT,FMT=*) ' ERROR : in EXSEG1.nam, in NAM_LUNITn you have CINIFILEPGD= ',CINIFILEPGD
+    WRITE(ILUOUT,FMT=*) ' whereas in .des you have CINIFILEPGD= ',HINIFILEPGD
+    WRITE(ILUOUT,FMT=*) ' Please check your Namelist '
+    WRITE(ILUOUT,FMT=*) ' For example, you may have specified the un-nested PGD file instead of the nested PGD file '
+    WRITE(ILUOUT,FMT=*) 
+    WRITE(ILUOUT,FMT=*) '###############'
+    WRITE(ILUOUT,FMT=*) ' MESONH ABORTS'
+    WRITE(ILUOUT,FMT=*) '###############'
+    WRITE(ILUOUT,FMT=*) 
+ !callabortstop
+    CALL PRINT_MSG(NVERB_FATAL,'GEN','READ_EXSEG_n','')
+  END IF
+ELSE
+  CINIFILEPGD = ''
+!* note that after a spawning, there is no value for CINIFILEPGD in the .des file,
+!  so the checking cannot be made if the user starts a simulation directly from
+!  a spawned file (without the prep_real_case stage)
+END IF
+!-------------------------------------------------------------------------------
+!
+!*       5.    WE DO NOT FORGET TO UPDATE ALL DOLLARN NAMELIST VARIABLES
+!              ---------------------------------------------------------
+!
+CALL UPDATE_NAM_LUNITN
+CALL UPDATE_NAM_CONFN
+CALL UPDATE_NAM_DYNN
+CALL UPDATE_NAM_ADVN
+CALL UPDATE_NAM_PARAMN
+CALL UPDATE_NAM_PARAM_RADN
+#ifdef MNH_ECRAD
+CALL UPDATE_NAM_PARAM_ECRADN
+#endif
+CALL UPDATE_NAM_PARAM_KAFRN
+CALL UPDATE_NAM_PARAM_MFSHALLN
+CALL UPDATE_NAM_LBCN
+CALL UPDATE_NAM_NUDGINGN
+CALL UPDATE_NAM_TURBN
+CALL UPDATE_NAM_CH_MNHCN
+CALL UPDATE_NAM_CH_SOLVERN
+CALL UPDATE_NAM_SERIESN
+CALL UPDATE_NAM_BLOWSNOWN
+!-------------------------------------------------------------------------------
+WRITE(UNIT=ILUOUT,FMT='(/)')
+!-------------------------------------------------------------------------------
+!
+!*       6.    FORMATS
+!              -------
+!
+9000  FORMAT(/,'NOTE  IN READ_EXSEG FOR MODEL ', I2, ' : ',/, &
+             '--------------------------------')
+9001  FORMAT(/,'CAUTION ERROR IN READ_EXSEG FOR MODEL ', I2,' : ',/, &
+             '----------------------------------------' )
+9002  FORMAT(/,'WARNING IN READ_EXSEG FOR MODEL ', I2,' : ',/, &
+             '----------------------------------' )
+9003  FORMAT(/,'FATAL ERROR IN READ_EXSEG FOR MODEL ', I2,' : ',/, &
+             '--------------------------------------' )
+!
+!-------------------------------------------------------------------------------
+!
+END SUBROUTINE READ_EXSEG_n
diff --git a/src/ZSOLVER/spectre.f90 b/src/ZSOLVER/spectre.f90
new file mode 100644
index 0000000000000000000000000000000000000000..545c60629410ef29c5a16bfd5289f96038c41e28
--- /dev/null
+++ b/src/ZSOLVER/spectre.f90
@@ -0,0 +1,217 @@
+!MNH_LIC Copyright 2011-2019 CNRS, Meteo-France and Universite Paul Sabatier
+!MNH_LIC This is part of the Meso-NH software governed by the CeCILL-C licence
+!MNH_LIC version 1. See LICENSE, CeCILL-C_V1-en.txt and CeCILL-C_V1-fr.txt
+!MNH_LIC for details. version 1.
+!-----------------------------------------------------------------
+!     ######spl
+      PROGRAM SPECTRE
+!     ############
+!
+!!****
+!!
+!!    PURPOSE
+!!    -------
+!!    compute energy spectra from a MESONH file
+!!
+!!
+!!
+!!
+!! Modifications:
+!!  Philippe Wautelet: 05/2016-04/2018: new data structures and calls for I/O
+!-------------------------------------------------------------------------------
+!
+!*       0.     DECLARATIONS
+!               ------------
+!
+!
+USE MODD_CONF
+USE MODD_IO, ONLY: NIO_VERB,NVERB_DEBUG,TFILEDATA
+USE MODD_LUNIT
+USE MODD_LUNIT_n
+USE MODD_TIME_n
+USE MODD_DIM_ll
+USE MODD_SPECTRE
+!
+USE MODI_SPECTRE_MESONH
+USE MODI_SPECTRE_AROME
+!
+USE MODE_MSG
+USE MODE_POS
+USE MODE_IO,               only: IO_Config_set, IO_Init
+USE MODE_IO_FILE,          only: IO_File_close, IO_File_open
+USE MODE_IO_MANAGE_STRUCT, only: IO_File_add2list, IO_Filelist_print
+use mode_init_ll,          only: END_PARA_ll
+USE MODE_MODELN_HANDLER
+!USE MODD_TYPE_DATE
+USE MODI_VERSION
+!
+USE MODN_CONFZ
+USE MODN_CONFIO, ONLY : NAM_CONFIO
+!
+IMPLICIT NONE
+!
+!*       0.1   declarations of local variables
+!
+CHARACTER (LEN=28), DIMENSION(1) :: YINIFILE      ! names of the INPUT FM-file
+CHARACTER (LEN=50)               :: YOUTFILE      ! names of the OUTPUT FM-file
+INTEGER                          :: IRESP         ! return code in FM routines
+INTEGER                          :: ILUOUT0       ! Logical unit number for the output listing
+INTEGER                          :: ILUNAM        ! Logical unit numbers for the namelist file
+                                                  ! and for output_listing file
+LOGICAL                          :: GFOUND        ! Return code when searching namelist
+!
+INTEGER                          :: IINFO_ll      ! return code for _ll routines 
+!
+REAL,DIMENSION(:,:,:),ALLOCATABLE:: ZWORK         ! work array
+REAL,DIMENSION(:,:,:),ALLOCATABLE:: ZWORKAROME    ! work array
+INTEGER :: NI,NJ,NK
+REAL    ::XDELTAX,XDELTAY
+TYPE(TFILEDATA),POINTER :: TZNMLFILE  => NULL()
+!
+NAMELIST/NAM_SPECTRE/ LSPECTRE_U,LSPECTRE_V,LSPECTRE_W,LSPECTRE_TH,LSPECTRE_RV,&
+                      LSPECTRE_LSU,LSPECTRE_LSV,LSPECTRE_LSW,LSPECTRE_LSTH,LSPECTRE_LSRV,LSMOOTH
+!
+NAMELIST/NAM_SPECTRE_FILE/ YINIFILE,CTYPEFILE,YOUTFILE,LSTAT 
+NAMELIST/NAM_ZOOM_SPECTRE/ LZOOM,NITOT,NJTOT,NXDEB,NYDEB 
+NAMELIST/NAM_DOMAIN_AROME/ NI,NJ,NK,XDELTAX,XDELTAY
+!
+!-------------------------------------------------------------------------------
+!
+!*       0.0   Initializations
+!              ---------------
+!
+!
+CALL GOTO_MODEL(1)
+!
+CALL VERSION
+CPROGRAM='SPEC  '
+!
+CALL IO_Init()
+!
+! initialization 
+YINIFILE(:)   = '                         '
+CTYPEFILE     = 'MESONH'
+LSPECTRE_U    = .FALSE.
+LSPECTRE_V    = .FALSE.
+LSPECTRE_W    = .FALSE.
+LSPECTRE_TH   = .FALSE.
+LSPECTRE_RV   = .FALSE.
+LSPECTRE_LSU  = .FALSE.
+LSPECTRE_LSV  = .FALSE.
+LSPECTRE_LSW  = .FALSE.
+LSPECTRE_LSTH = .FALSE.
+LSPECTRE_LSRV = .FALSE.
+LSMOOTH       = .FALSE.
+LZOOM         = .FALSE.
+YOUTFILE      = '                         '
+LSTAT         = .FALSE.
+NI=750
+NJ=720
+NK=60
+XDELTAX=2500.
+XDELTAY=2500.
+!
+!
+!-------------------------------------------------------------------------------
+!
+!*       1.0   Namelist reading
+!              ----------------
+!
+PRINT*, ' '
+PRINT*, '*********************************************************************'
+PRINT*, '*********************************************************************'
+PRINT*, ' '
+!
+CALL IO_File_add2list(TZNMLFILE,'SPEC1.nam','NML','READ')
+CALL IO_File_open(TZNMLFILE)
+ILUNAM = TZNMLFILE%NLU
+!
+PRINT*, 'READ THE SPEC1.NAM FILE'
+!
+CALL POSNAM(ILUNAM,'NAM_SPECTRE',GFOUND)
+IF (GFOUND) THEN
+  READ(UNIT=ILUNAM,NML=NAM_SPECTRE)
+  PRINT*, '  namelist NAM_SPECTRE read'
+END IF
+!
+!
+CALL POSNAM(ILUNAM,'NAM_SPECTRE_FILE',GFOUND)
+IF (GFOUND) THEN
+  READ(UNIT=ILUNAM,NML=NAM_SPECTRE_FILE)
+  PRINT*, '  namelist NAM_SPECTRE_FILE read'
+END IF
+!
+CALL POSNAM(ILUNAM,'NAM_ZOOM_SPECTRE',GFOUND)
+IF (GFOUND) THEN
+  READ(UNIT=ILUNAM,NML=NAM_ZOOM_SPECTRE)
+  PRINT*, '  namelist NAM_ZOOM_SPECTRE read'
+END IF
+!
+CALL POSNAM(ILUNAM,'NAM_DOMAIN_AROME',GFOUND)
+IF (GFOUND) THEN
+  READ(UNIT=ILUNAM,NML=NAM_DOMAIN_AROME)
+  PRINT*, '  namelist NAM_DOMAIN_AROME read'
+END IF
+!
+CALL POSNAM(ILUNAM,'NAM_CONFZ',GFOUND)
+IF (GFOUND) THEN
+  READ(UNIT=ILUNAM,NML=NAM_CONFZ)
+  PRINT*, '  namelist NAM_CONFZ read'
+END IF
+!
+CALL POSNAM(ILUNAM,'NAM_CONFIO',GFOUND)
+IF (GFOUND) THEN
+  READ(UNIT=ILUNAM,NML=NAM_CONFIO)
+  PRINT*, '  namelist NAM_CONFIO read'
+END IF
+CALL IO_Config_set()
+!
+CALL IO_File_close(TZNMLFILE)
+!
+CINIFILE = YINIFILE(1)
+!
+!-------------------------------------------------------------------------------
+!
+!*       2.0   file
+!              -----------
+!
+IF ( LEN_TRIM(CINIFILE)==0 ) THEN
+  CALL PRINT_MSG(NVERB_FATAL,'GEN','SPECTRE','LEN_TRIM(CINIFILE)==0')
+ENDIF
+!
+IF ( LEN_TRIM(YOUTFILE)==0 ) THEN
+  WRITE(YOUTFILE,FMT='(A,A)') "spectra_",TRIM(ADJUSTL(CINIFILE))
+ENDIF
+!
+!-------------------------------------------------------------------------------
+!
+!*       3.0   Fields initialization and spectra computation
+!
+IF (CTYPEFILE=='MESONH') THEN
+  CALL SPECTRE_MESONH(YOUTFILE)
+  !
+  CALL IO_File_close(LUNIT_MODEL(1)%TINIFILE)
+  IF(NIO_VERB>=NVERB_DEBUG) CALL IO_Filelist_print()
+  CALL IO_File_close(TLUOUT0)
+  CALL IO_File_close(TLUOUT)
+ELSEIF (CTYPEFILE=='AROME ')THEN
+ CALL SPECTRE_AROME(CINIFILE,YOUTFILE,XDELTAX,XDELTAY,NI,NJ,NK)
+ELSE
+  print*,"This type of file is not accept for SPECTRE PROGRAM"
+ENDIF
+!
+!-------------------------------------------------------------------------------
+!
+!*      4.    FINALIZE THE PARALLEL SESSION
+!              -----------------------------
+!
+CALL END_PARA_ll(IINFO_ll)
+!
+PRINT*, ' '
+PRINT*, '****************************************************'
+PRINT*, '*            EXIT  SPECTRE CORRECTLY          *'
+PRINT*, '****************************************************'
+PRINT*, ' '
+!-------------------------------------------------------------------------------
+END PROGRAM SPECTRE
+
diff --git a/src/ZSOLVER/tensorproductmultigrid_Source/communication.f90 b/src/ZSOLVER/tensorproductmultigrid_Source/communication.f90
new file mode 100644
index 0000000000000000000000000000000000000000..b7b1fef019a506cd0e79221c34ab869645069cc2
--- /dev/null
+++ b/src/ZSOLVER/tensorproductmultigrid_Source/communication.f90
@@ -0,0 +1,1552 @@
+!=== COPYRIGHT AND LICENSE STATEMENT ===
+!
+!  This file is part of the TensorProductMultigrid code.
+!  
+!  (c) The copyright relating to this work is owned jointly by the
+!  Crown, Met Office and NERC [2014]. However, it has been created
+!  with the help of the GungHo Consortium, whose members are identified
+!  at https://puma.nerc.ac.uk/trac/GungHo/wiki .
+!  
+!  Main Developer: Eike Mueller
+!  
+!  TensorProductMultigrid is free software: you can redistribute it and/or
+!  modify it under the terms of the GNU Lesser General Public License as
+!  published by the Free Software Foundation, either version 3 of the
+!  License, or (at your option) any later version.
+!  
+!  TensorProductMultigrid is distributed in the hope that it will be useful,
+!  but WITHOUT ANY WARRANTY; without even the implied warranty of
+!  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+!  GNU Lesser General Public License for more details.
+!  
+!  You should have received a copy of the GNU Lesser General Public License
+!  along with TensorProductMultigrid (see files COPYING and COPYING.LESSER).
+!  If not, see <http://www.gnu.org/licenses/>.
+!
+!=== COPYRIGHT AND LICENSE STATEMENT ===
+
+
+!==================================================================
+!
+!  MPI communication routines for multigrid code
+!
+!    Eike Mueller, University of Bath, Feb 2012
+!
+!==================================================================
+
+module communication
+  use messages
+  use datatypes
+
+#ifndef MNH
+  use mpi
+#else
+  use modd_mpif
+#endif   
+  use timer
+
+  implicit none
+
+public::comm_preinitialise
+public::comm_initialise
+public::comm_finalise
+public::scalarprod_mnh
+public::scalarprod
+public::print_scalaprod2
+public::boundary_mnh
+public::haloswap_mnh
+public::haloswap
+public::ihaloswap_mnh
+public::ihaloswap
+public::collect
+public::distribute
+public::i_am_master_mpi
+public::master_rank
+public::pproc
+public::MPI_COMM_HORIZ
+public::comm_parameters
+public::comm_measuretime
+
+
+  ! Number of processors
+  ! n_proc = 2^(2*pproc), with integer pproc
+  integer :: pproc
+
+! Rank of master process
+  integer, parameter :: master_rank = 0
+! Am I the master process?
+  logical :: i_am_master_mpi
+
+  integer, parameter :: dim = 3  ! Dimension
+  integer, parameter :: dim_horiz = 2  ! Horizontal dimension
+  integer :: MPI_COMM_HORIZ ! Communicator with horizontal partitioning
+
+private
+
+! Data types for halo exchange in both x- and y-direction
+  integer, dimension(:,:,:), allocatable :: halo_type
+
+! MPI vector data types
+  ! Halo for data exchange in north-south direction
+  integer, allocatable, dimension(:,:) :: halo_ns
+  integer, allocatable, dimension(:,:) :: halo_nst
+  integer, allocatable, dimension(:,:) :: halo_wet
+  ! Vector data type for interior of field a(level,m)
+  integer, allocatable, dimension(:,:) :: interior
+  integer, allocatable, dimension(:,:) :: interiorT 
+  ! Vector data type for one quarter of interior of field
+  ! at level a(level,m). This has the same size (and can be
+  ! used for communications with) the interior of a(level,m+1)
+  integer, allocatable, dimension(:,:) :: sub_interior
+  integer, allocatable, dimension(:,:) :: sub_interiorT 
+  ! Timer for halo swaps
+  type(time), allocatable, dimension(:,:) :: t_haloswap
+  ! Timer for collect and distribute
+  type(time), allocatable, dimension(:) :: t_collect
+  type(time), allocatable, dimension(:) :: t_distribute
+  ! Parallelisation parameters
+  ! Measure communication times?
+  logical :: comm_measuretime
+
+  ! Parallel communication parameters
+  type comm_parameters
+    ! Size of halos
+    integer :: halo_size
+  end type comm_parameters
+
+  type(comm_parameters) :: comm_param
+
+! Data layout
+! ===========
+!
+!  The number of processes has to be of the form nproc = 2^(2*pproc) to
+!  ensure that data can be distributed between processes.
+!  The processes are arranged in a (2^pproc) x (2^pproc) cartesian grid
+!  in the horizontal plane (i.e. vertical columns are always local to one
+!  process), which is implemented via the communicator MPI_COMM_HORIZ.
+!  This MPI_cart_rank() and MPI_cart_shift() can then be used to
+!  easily identify neighbouring processes.
+
+!  The number of data grid cells in each direction has to be a multiply
+!  of 2**(L-1) where L is the number of levels (including the coarse
+!  and fine level), with the coarse level corresponding to level=1.
+!  Also define L_split as the level where we start to pull together
+!  data. For levels > L_split each position in the cartesian grid is
+!  included in the work, below this only a subset of processes is
+!  used.
+!
+!  Each grid a(level,m) is identified by two numbers:
+!  (1) The multigrid level it belongs to (level)
+!  (2) The number of active processes that operate on it (2^(2*m)).
+!
+!  For level > L_split, m=procp. For L_split we store a(L_split,pproc) and
+!  a(L_split,pproc-1), and only processes with even coordinates in both
+!  horizontal directions use this grid.
+!  Below that level, store a(L_split-1,pproc-1) and a(L_split-1,pproc-2),
+!  where only processes for which both horiontal coordinates are
+!  multiples of four use the latter. This is continued until only on
+!  process is left.
+!
+!
+!  level
+!    L          a(L,pproc)
+!    L-1        a(L-1,pproc)
+!    ...
+!    L_split    a(L_split,pproc)    a(L_split  ,pproc-1)
+!    L_split-1                      a(L_split-1,pproc-1)  a(L_split-1,pproc-2)
+!
+!                                                                  ... a(3,1)
+!                                                                      a(2,1)
+!                                                                      a(1,1)
+!
+!  When moving from left to right in the above graph the total number of
+!  grid cells does not change, but the number of data points per process
+!  increases by a factor of 4.
+!
+! Parallel operations
+! ===================
+!
+!   (*)  Halo exchange. Update halo with data from neighbouring
+!        processors in cartesian grid on current (level,m)
+!   (*)  Collect data on all processes at (level,m) on those
+!        processes that are still active on (level,m-1).
+!   (*)  Distribute data at (level,m-1) and duplicate on all processes
+!        that are active at (level,m).
+!
+!   Note that in the cartesian processor grid the first coordinate
+!   is the North-South (y-) direction, the second coordinate is the
+!   East-West (x-) direction, i.e. the layout is this:
+!
+!   p_0 (0,0)   p_1 (0,1)   p_2 (0,2)   p_3 (0,3)
+!
+!   p_4 (1,0)   p_5 (1,1)   p_6 (1,2)   p_7 (1,3)
+!
+!   p_8 (2,0)   p_9 (2,1)   p_10 (2,2)  p_11 (2,3)
+!
+!                       [...]
+!
+!
+!   Normal multigrid restriction and prolongation are used to
+!   move between levels with fixed m.
+!
+!
+
+contains
+
+!==================================================================
+! Pre-initialise communication routines
+!==================================================================
+  subroutine comm_preinitialise()
+    implicit none
+    integer :: nproc, ierr, rank
+    call mpi_comm_size(MPI_COMM_WORLD, nproc, ierr)
+    call mpi_comm_rank(MPI_COMM_WORLD, rank, ierr)
+    i_am_master_mpi = (rank == master_rank)
+    ! Check that nproc = 2^(2*p)
+    pproc = floor(log(1.0d0*nproc)/log(4.0d0))
+    if ( (nproc - 4**pproc) .ne. 0) then
+      call fatalerror("Number of processors has to be 2^(2*pproc) with integer pproc.")
+    end if
+    if (i_am_master_mpi) then
+      write(STDOUT,'("PARALLEL RUN")')
+      write(STDOUT,'("Number of processors : 2^(2*pproc) = ",I10," with pproc = ",I6)') &
+        nproc, pproc
+    end if
+    ! Create halo data types
+
+  end subroutine comm_preinitialise
+
+!==================================================================
+! Initialise communication routines
+!==================================================================
+  subroutine comm_initialise(n_lev,        & !} multigrid parameters
+                            lev_split,     & !}
+                            grid_param,    & ! Grid parameters
+                            comm_param_in)   ! Parallel communication
+                                             ! parameters
+    implicit none
+    integer, intent(in) :: n_lev
+    integer, intent(in) :: lev_split
+    type(grid_parameters), intent(inout) :: grid_param
+    type(comm_parameters), intent(in)    :: comm_param_in
+    integer :: n
+    integer :: nz
+    integer :: rank, nproc, ierr
+    integer :: count, blocklength, stride
+    integer, dimension(2) :: p_horiz
+    integer :: m, level, nlocal
+    logical :: reduced_m
+    integer :: halo_size
+    character(len=32) :: t_label
+
+    integer,parameter    :: nb_dims=3
+    integer,dimension(nb_dims) :: profil_tab,profil_sous_tab,coord_debut
+
+    n = grid_param%n
+    nz = grid_param%nz
+
+    comm_param = comm_param_in
+    halo_size = comm_param%halo_size
+
+    call mpi_comm_size(MPI_COMM_WORLD, nproc, ierr)
+
+    ! Create cartesian topology
+    call mpi_cart_create(MPI_COMM_WORLD,        & ! Old communicator name
+                         dim_horiz,             & ! horizontal dimension
+                         (/2**pproc,2**pproc/), & ! extent in each horizontal direction
+                         (/.false.,.false./),   & ! periodic?
+                         .true.,                & ! reorder?
+                         MPI_COMM_HORIZ,        & ! Name of new communicator
+                         ierr)
+   ! calculate and display rank and corrdinates in cartesian grid
+    call mpi_comm_rank(MPI_COMM_HORIZ, rank, ierr)
+    call mpi_cart_coords(MPI_COMM_HORIZ,rank,dim_horiz,p_horiz,ierr)
+
+    ! Local size of (horizontal) grid
+    nlocal = n/2**pproc
+
+    ! === Set up data types ===
+    ! Halo for exchange in north-south direction
+    if (LUseO) allocate(halo_ns(n_lev,0:pproc))
+    if (LUseT) allocate(halo_nst(n_lev,0:pproc))
+    if (LUseT) allocate(halo_wet(n_lev,0:pproc))
+    ! Interior data types
+    if (LUseO) allocate(interior(n_lev,0:pproc))
+    if (LUseO) allocate(sub_interior(n_lev,0:pproc))
+    if (LUseT) allocate(interiorT(n_lev,0:pproc))
+    if (LUseT) allocate(sub_interiorT(n_lev,0:pproc))
+    ! Timer
+    allocate(t_haloswap(n_lev,0:pproc))
+    allocate(t_collect(0:pproc))
+    allocate(t_distribute(0:pproc))
+    do m=0,pproc
+      write(t_label,'("t_collect(",I3,")")') m
+      call initialise_timer(t_collect(m),t_label)
+      write(t_label,'("t_distribute(",I3,")")') m
+      call initialise_timer(t_distribute(m),t_label)
+    end do
+
+    m = pproc
+    level = n_lev
+    reduced_m = .false.
+    do while (level > 0)
+      ! --- Create halo data types ---
+      if (LUseO) then
+      ! NS- (y-) direction
+      count = nlocal
+      blocklength = (nz+2)*halo_size
+      stride = (nlocal+2*halo_size)*(nz+2)
+      call mpi_type_vector(count,blocklength,stride,MPI_DOUBLE_PRECISION, &
+                           halo_ns(level,m),ierr)
+      call mpi_type_commit(halo_ns(level,m),ierr)
+      endif
+      ! tranpose
+      if (LUseT) then
+      ! NS- (y-) transpose direction
+      count =        nz+2                                        ! nlocal
+      blocklength =  nlocal*halo_size                            ! (nz+2)*halo_size
+      stride =       (nlocal+2*halo_size) * (nlocal+2*halo_size) ! (nlocal+2*halo_size)*(nz+2)
+      call mpi_type_vector(count,blocklength,stride,MPI_DOUBLE_PRECISION, &
+                           halo_nst(level,m),ierr)
+      call mpi_type_commit(halo_nst(level,m),ierr)
+     ! WE- (x-) transpose direction
+      count =        (nz+2)*(nlocal+2*halo_size)*halo_size       ! nlocal
+      blocklength =  1*halo_size                                 ! (nz+2)*halo_size
+      stride =       nlocal+2*halo_size                          ! (nlocal+2*halo_size)*(nz+2)
+      call mpi_type_vector(count,blocklength,stride,MPI_DOUBLE_PRECISION, &
+                           halo_wet(level,m),ierr)
+      call mpi_type_commit(halo_wet(level,m),ierr)
+      endif
+#ifndef NDEBUG
+  if (ierr .ne. 0) &
+    call fatalerror("Commit halo_ns failed in mpi_type_commit().")
+#endif
+      ! --- Create interior data types ---
+      if (LUseO) then
+         count = nlocal
+         blocklength = nlocal*(nz+2)
+         stride = (nz+2)*(nlocal+2*halo_size)
+         call mpi_type_vector(count,blocklength,stride,MPI_DOUBLE_PRECISION,interior(level,m),ierr)
+         call mpi_type_commit(interior(level,m),ierr)
+         count = nlocal/2
+         blocklength = nlocal/2*(nz+2)
+         stride = (nlocal+2*halo_size)*(nz+2)
+         call mpi_type_vector(count,blocklength,stride,MPI_DOUBLE_PRECISION,sub_interior(level,m),ierr)
+         call mpi_type_commit(sub_interior(level,m),ierr)
+      end if
+      if (LUseT) then
+         ! interiorT
+         if ( nlocal /= 0 ) then
+            profil_tab      = (/ nlocal+2*halo_size , nlocal+2*halo_size , nz+2 /)
+            profil_sous_tab = (/ nlocal             , nlocal             , nz+2 /)
+            coord_debut     = (/ 0                  , 0                  , 0    /)
+            call MPI_TYPE_CREATE_SUBARRAY(nb_dims,profil_tab,profil_sous_tab,coord_debut,&
+                 MPI_ORDER_FORTRAN,MPI_DOUBLE_PRECISION,interiorT(level,m),ierr)
+            call mpi_type_commit(interiorT(level,m),ierr)
+         end if
+         ! sub_interiorT
+         if ( (nlocal/2) /= 0 ) then
+            profil_tab      = (/ nlocal+2*halo_size , nlocal+2*halo_size , nz+2 /)
+            profil_sous_tab = (/ nlocal/2           , nlocal/2           , nz+2 /)
+            coord_debut     = (/ 0                  , 0                  , 0    /)
+            call MPI_TYPE_CREATE_SUBARRAY(nb_dims,profil_tab,profil_sous_tab,coord_debut,&
+                 MPI_ORDER_FORTRAN,MPI_DOUBLE_PRECISION,sub_interiorT(level,m),ierr)
+            call mpi_type_commit(sub_interiorT(level,m),ierr)
+         end if
+      end if
+      ! --- Create timers ---
+      write(t_label,'("t_haloswap(",I3,",",I3,")")') level,m
+      call initialise_timer(t_haloswap(level,m),t_label)
+
+      ! If we are below L_split, split data
+      if ( (level .le. lev_split) .and. (m > 0) .and. (.not. reduced_m)) then
+        reduced_m = .true.
+        m = m-1
+        nlocal = 2*nlocal
+        cycle
+      end if
+      reduced_m = .false.
+      level = level-1
+      nlocal = nlocal/2
+    end do
+
+  end subroutine comm_initialise
+
+!==================================================================
+! Finalise communication routines
+!==================================================================
+  subroutine comm_finalise(n_lev,   &  ! } Multigrid parameters
+                           lev_split,  & !}
+                           grid_param )  ! } Grid parameters
+    implicit none
+    integer, intent(in) :: n_lev
+    integer, intent(in) :: lev_split
+    type(grid_parameters), intent(in) :: grid_param
+    ! local var
+    logical :: reduced_m
+    integer :: level, m
+    integer :: ierr
+    integer :: nlocal,n
+    character(len=80) :: s
+
+   ! Local size of (horizontal) grid
+    n = grid_param%n
+    nlocal = n/2**pproc
+
+    m = pproc
+    level = n_lev
+    reduced_m = .false.
+    if (i_am_master_mpi) then
+      write(STDOUT,'(" *** Finalising communications ***")')
+    end if
+    call print_timerinfo("--- Communication timing results ---")
+    do while (level > 0)
+      write(s,'("level = ",I3,", m = ",I3)') level, m
+      call print_timerinfo(s)
+      ! --- Print out timer information ---
+      call print_elapsed(t_haloswap(level,m),.True.,1.0_rl)
+      ! --- Free halo data types ---
+      if (LUseO) call mpi_type_free(halo_ns(level,m),ierr)
+      if (LUseT) call mpi_type_free(halo_nst(level,m),ierr)
+      if (LUseT) call mpi_type_free(halo_wet(level,m),ierr)
+      ! --- Free interior data types ---
+      if (LUseO) call mpi_type_free(interior(level,m),ierr)
+      if (LUseO) call mpi_type_free(sub_interior(level,m),ierr)
+      if (LUseT .and. (nlocal /= 0 ) ) call mpi_type_free(interiorT(level,m),ierr)
+      if (LUseT .and. ( (nlocal/2) /= 0 ) ) call mpi_type_free(sub_interiorT(level,m),ierr)
+      ! If we are below L_split, split data
+      if ( (level .le. lev_split) .and. (m > 0) .and. (.not. reduced_m)) then
+        reduced_m = .true.
+        m = m-1
+        nlocal = 2*nlocal
+        cycle
+      end if
+      reduced_m = .false.
+      level = level-1
+      nlocal = nlocal/2
+    end do
+    do m=pproc,0,-1
+      write(s,'("m = ",I3)') m
+      call print_timerinfo(s)
+      ! --- Print out timer information ---
+      call print_elapsed(t_collect(m),.True.,1.0_rl)
+      call print_elapsed(t_distribute(m),.True.,1.0_rl)
+    end do
+
+    ! Deallocate arrays
+    if (LUseO) deallocate(halo_ns)
+    if (LUseT) deallocate(halo_nst,halo_wet)
+    if (LUseO) deallocate(interior)
+    if (LUseO) deallocate(sub_interior)
+    if (LUseT) deallocate(interiorT)
+    if (LUseT) deallocate(sub_interiorT)
+
+    deallocate(t_haloswap)
+    deallocate(t_collect)
+    deallocate(t_distribute)
+    if (i_am_master_mpi) then
+      write(STDOUT,'("")')
+    end if
+
+  end subroutine comm_finalise
+
+!==================================================================
+!  Scalar product of two fields
+!==================================================================
+  subroutine scalarprod_mnh(m, a, b, s)
+    implicit none
+    integer, intent(in) :: m
+    type(scalar3d), intent(in) :: a
+    type(scalar3d), intent(in) :: b
+    real(kind=rl), intent(out) :: s
+    !local var
+    integer :: nprocs, rank, ierr
+    integer :: p_horiz(2)
+    integer :: stepsize
+    integer, parameter :: dim_horiz = 2
+    real(kind=rl) :: local_sum, global_sum 
+    real(kind=rl) :: local_sumt,global_sumt
+    integer :: nlocal, nz, i
+    integer :: ix,iy,iz
+    real(kind=rl) :: ddot
+
+    integer :: iy_min,iy_max, ix_min,ix_max
+    real , dimension(:,:,:) , pointer :: za_st,zb_st
+
+    nlocal = a%ix_max-a%ix_min+1
+    nz = a%grid_param%nz
+
+    iy_min = a%iy_min
+    iy_max = a%iy_max
+    ix_min = a%ix_min
+    ix_max = a%ix_max
+
+    ! Work out coordinates of processor
+    call mpi_comm_size(MPI_COMM_HORIZ,nprocs,ierr)
+    call mpi_comm_rank(MPI_COMM_HORIZ,rank,ierr)
+    stepsize = 2**(pproc-m)
+    if (nprocs > 1) then
+      ! Only inlcude local sum if the processor coordinates
+      ! are multiples of stepsize
+      call mpi_cart_coords(MPI_COMM_HORIZ,rank,dim_horiz,p_horiz,ierr)
+      if ( (stepsize == 1) .or.                   &
+           ( (stepsize > 1) .and.                 &
+             (mod(p_horiz(1),stepsize)==0) .and.  &
+             (mod(p_horiz(2),stepsize)==0) ) ) then
+        if (LUseO) then
+           local_sum = 0.0_rl
+           do i = 1, nlocal
+              local_sum = local_sum &
+                   + ddot((nz+2)*nlocal,a%s(0,1,i),1,b%s(0,1,i),1)
+           end do
+        end if
+        if (LUseT) then
+           local_sumt = 0.0_rl
+           do iz=0,nz+1
+              do iy=a%icompy_min,a%icompy_max
+                 do ix=a%icompx_min,a%icompx_max
+                    local_sumt = local_sumt &
+                         + a%st(ix,iy,iz)*b%st(ix,iy,iz)
+                 end do
+              end do
+           end do
+        end if
+      else
+        if (LUseO) local_sum = 0.0_rl
+        if (LUseT) local_sumt = 0.0_rl
+      end if
+      if (LUseO) call mpi_allreduce(local_sum,global_sum,1,MPI_DOUBLE_PRECISION, &
+                         MPI_SUM,MPI_COMM_HORIZ,ierr)
+      if (LUseT) call mpi_allreduce(local_sumt,global_sumt,1,MPI_DOUBLE_PRECISION, &
+                         MPI_SUM,MPI_COMM_HORIZ,ierr)
+    else
+      if (LUseO) then   
+      global_sum = 0.0_rl
+      do i = 1, nlocal
+        global_sum = global_sum &
+                   + ddot((nz+2)*nlocal,a%s(0,1,i),1,b%s(0,1,i),1)
+      end do
+      endif
+      if (LUseT) then
+      za_st => a%st
+      zb_st => b%st
+      global_sumt = 0.0_rl
+         !$acc kernels
+         do iz=0,nz+1
+            do iy=iy_min,iy_max
+               do ix=ix_min,ix_max
+                  global_sumt = global_sumt &
+                       + za_st(ix,iy,iz)*zb_st(ix,iy,iz)
+               end do
+            end do
+         end do
+         !$acc end kernels
+      endif
+    end if
+    if (LUseO) then
+       s = global_sum
+    else
+       s = global_sumt
+    end if
+    
+  end subroutine scalarprod_mnh
+!-------------------------------------------------------------------------------
+  subroutine scalarprod(m, a, b, s)
+    implicit none
+    integer, intent(in) :: m
+    type(scalar3d), intent(in) :: a
+    type(scalar3d), intent(in) :: b
+    real(kind=rl), intent(out) :: s
+    integer :: nprocs, rank, ierr
+    integer :: p_horiz(2)
+    integer :: stepsize
+    integer, parameter :: dim_horiz = 2
+    real(kind=rl) :: local_sum, global_sum
+    integer :: nlocal, nz, i
+    real(kind=rl) :: ddot
+
+    nlocal = a%ix_max-a%ix_min+1
+    nz = a%grid_param%nz
+    ! Work out coordinates of processor
+    call mpi_comm_size(MPI_COMM_HORIZ,nprocs,ierr)
+    call mpi_comm_rank(MPI_COMM_HORIZ,rank,ierr)
+    stepsize = 2**(pproc-m)
+    if (nprocs > 1) then
+      ! Only inlcude local sum if the processor coordinates
+      ! are multiples of stepsize
+      call mpi_cart_coords(MPI_COMM_HORIZ,rank,dim_horiz,p_horiz,ierr)
+      if ( (stepsize == 1) .or.                   &
+           ( (stepsize > 1) .and.                 &
+             (mod(p_horiz(1),stepsize)==0) .and.  &
+             (mod(p_horiz(2),stepsize)==0) ) ) then
+        local_sum = 0.0_rl
+        do i = 1, nlocal
+          local_sum = local_sum &
+                    + ddot((nz+2)*nlocal,a%s(0,1,i),1,b%s(0,1,i),1)
+        end do
+      else
+        local_sum = 0.0_rl
+      end if
+      call mpi_allreduce(local_sum,global_sum,1,MPI_DOUBLE_PRECISION, &
+                         MPI_SUM,MPI_COMM_HORIZ,ierr)
+    else
+      global_sum = 0.0_rl
+      do i = 1, nlocal
+        global_sum = global_sum &
+                   + ddot((nz+2)*nlocal,a%s(0,1,i),1,b%s(0,1,i),1)
+      end do
+    end if
+    s = global_sum
+  end subroutine scalarprod
+!==================================================================
+!  Pritn Scalar product^2  of 1 fields
+!==================================================================
+  subroutine print_scalaprod2(l,m, a, message )
+    implicit none
+    integer, intent(in) :: l,m
+    type(scalar3d), intent(in) :: a
+    character(len=*) , intent(in) :: message
+
+    !local 
+    real(kind=rl) :: s
+
+    call scalarprod_mnh(m, a, a, s)
+    s = sqrt(s)
+    if (i_am_master_mpi) then
+       write(STDOUT,'("Print_norm::",A,2I3,E23.15)') message, l,m,s
+       call flush(STDOUT)
+    end if
+
+  end subroutine print_scalaprod2
+!==================================================================
+! Boundary Neumann
+!==================================================================
+  subroutine boundary_mnh(a)              ! data field
+
+    implicit none
+ 
+    type(scalar3d), intent(inout) :: a
+
+    !local var
+    integer :: n, ix_min,ix_max,iy_min,iy_max
+    integer :: icompx_max,icompy_max
+
+    real , dimension(:,:,:) , pointer :: za_st
+    
+    ! Update Real Boundary for Newman case   u(0) = u(1) , etc ...
+
+    !return
+
+    n      = a%grid_param%n
+    ix_min = a%ix_min
+    ix_max = a%ix_max
+    iy_min = a%iy_min
+    iy_max = a%iy_max
+    if (LUseO) then 
+    if ( ix_min == 1 ) then
+       a%s(:,:,0) = a%s(:,:,1)
+    endif
+    if ( ix_max == n ) then
+       a%s(:,:,a%icompx_max+1) = a%s(:,:,a%icompx_max)
+    endif
+    if ( iy_min == 1 ) then
+       a%s(:,0,:) = a%s(:,1,:)
+    endif
+    if ( iy_max == n ) then
+       a%s(:,a%icompy_max+1,:) = a%s(:,a%icompy_max,:)
+    endif
+    endif
+    if (LUseT) then
+    !  transpose
+
+    za_st => a%st
+    icompx_max = a%icompx_max
+    icompy_max = a%icompy_max
+
+    !$acc kernels
+    if ( ix_min == 1 ) then
+       !acc kernels
+       za_st(0,:,:) = za_st(1,:,:)
+       !acc end kernels
+    endif
+    if ( ix_max == n ) then
+       !acc kernels
+       za_st(icompx_max+1,:,:) = za_st(icompx_max,:,:)
+       !acc end kernels
+    endif
+    if ( iy_min == 1 ) then
+       !acc kernels
+       za_st(:,0,:) = za_st(:,1,:)
+       !acc end kernels
+    endif
+    if ( iy_max == n ) then
+       !acc kernels
+       za_st(:,icompy_max+1,:) = za_st(:,icompy_max,:)
+       !acc end kernels
+    endif
+    !$acc end kernels
+   
+    endif
+
+  end subroutine boundary_mnh
+!==================================================================
+!  Initiate asynchronous halo exchange
+!
+!  For all processes with horizontal indices that are multiples
+!  of 2^(pproc-m), update halos with information held by
+!  neighbouring processes, e.g. for pproc-m = 1, stepsize=2
+!
+!                      N  (0,2)
+!                      ^
+!                      !
+!                      v
+!
+!      W (2,0) <-->  (2,2)  <-->  E (2,4)
+!
+!                      ^
+!                      !
+!                      v
+!                      S (4,2)
+!
+!==================================================================
+  subroutine ihaloswap_mnh(level,m,       &  ! multigrid- and processor- level
+                       a,             &  ! data field
+                       send_requests, &  ! send requests (OUT)
+                       recv_requests,  &  ! recv requests (OUT)
+                       send_requestsT, &  ! send requests T (OUT)
+                       recv_requestsT  &  ! recv requests T (OUT)
+                       )
+    implicit none
+    integer, intent(in) :: level
+    integer, intent(in) :: m
+    integer, intent(out), dimension(4) :: send_requests
+    integer, intent(out), dimension(4) :: recv_requests
+    integer, intent(out), dimension(4) :: send_requestsT
+    integer, intent(out), dimension(4) :: recv_requestsT
+    type(scalar3d), intent(inout) :: a
+    integer :: a_n  ! horizontal grid size
+    integer :: nz   ! vertical grid size
+    integer, dimension(2) :: p_horiz
+    integer :: stepsize
+    integer :: ierr, rank, sendtag, recvtag
+    integer :: stat(MPI_STATUS_SIZE)
+    integer :: halo_size
+    integer :: neighbour_n_rank
+    integer :: neighbour_s_rank
+    integer :: neighbour_e_rank
+    integer :: neighbour_w_rank
+    integer :: yoffset, blocklength
+
+    halo_size = comm_param%halo_size
+
+    ! Do nothing if we are only using one processor
+    if (m > 0) then
+      a_n = a%ix_max-a%ix_min+1
+      nz = a%grid_param%nz
+      stepsize = 2**(pproc-m)
+
+      ! Work out rank, only execute on relevant processes
+      call mpi_comm_rank(MPI_COMM_HORIZ, rank, ierr)
+      call mpi_cart_coords(MPI_COMM_HORIZ,rank,dim_horiz,p_horiz,ierr)
+
+      ! Work out ranks of neighbours
+      ! W -> E
+      call mpi_cart_shift(MPI_COMM_HORIZ,1, stepsize, &
+                          neighbour_w_rank,neighbour_e_rank,ierr)
+      ! N -> S
+      call mpi_cart_shift(MPI_COMM_HORIZ,0, stepsize, &
+                          neighbour_n_rank,neighbour_s_rank,ierr)
+      if ( (stepsize == 1) .or.                   &
+         (  (mod(p_horiz(1),stepsize) == 0) .and. &
+            (mod(p_horiz(2),stepsize) == 0) ) ) then
+        if (halo_size == 1) then
+          ! Do not include corners in send/recv
+          yoffset = 1
+          blocklength = a_n*(nz+2)*halo_size
+        else
+          yoffset = 1-halo_size
+          blocklength = (a_n+2*halo_size)*(nz+2)*halo_size
+        end if
+        ! Receive from north
+        recvtag = 1002
+        if (LUseO) call mpi_irecv(a%s(0,0-(halo_size-1),1),1,       &
+                       halo_ns(level,m),neighbour_n_rank,recvtag,   &
+                       MPI_COMM_HORIZ, recv_requests(1), ierr)
+        recvtag = 1012
+        if (LUseT) call mpi_irecv(a%st(1,0-(halo_size-1),0),1,      &
+                       halo_nst(level,m),neighbour_n_rank,recvtag,  &
+                       MPI_COMM_HORIZ, recv_requestsT(1), ierr)
+        ! Receive from south
+        recvtag = 1003
+        if (LUseO) call mpi_irecv(a%s(0,a_n+1,1),1,                 &
+                       halo_ns(level,m),neighbour_s_rank,recvtag,   &
+                       MPI_COMM_HORIZ, recv_requests(2), ierr)
+        recvtag = 1013
+        if (LUseT) call mpi_irecv(a%st(1,a_n+1,0),1,                &
+                       halo_nst(level,m),neighbour_s_rank,recvtag,  &
+                       MPI_COMM_HORIZ, recv_requestsT(2), ierr)
+        ! Send to south
+        sendtag = 1002
+        if (LUseO) call mpi_isend(a%s(0,a_n-(halo_size-1),1),1,     &
+                       halo_ns(level,m),neighbour_s_rank,sendtag,   &
+                       MPI_COMM_HORIZ, send_requests(1), ierr)
+        sendtag = 1012
+        if (LUseT) call mpi_isend(a%st(1,a_n-(halo_size-1),0),1,    &
+                       halo_nst(level,m),neighbour_s_rank,sendtag,  &
+                       MPI_COMM_HORIZ, send_requestsT(1), ierr)
+        ! Send to north
+        sendtag = 1003
+        if (LUseO) call mpi_isend(a%s(0,1,1),1,                     &
+                       halo_ns(level,m),neighbour_n_rank,sendtag,   &
+                       MPI_COMM_HORIZ, send_requests(2), ierr)
+        sendtag = 1013
+        if (LUseT) call mpi_isend(a%st(1,1,0),1,                    &
+                       halo_nst(level,m),neighbour_n_rank,sendtag,  &
+                       MPI_COMM_HORIZ, send_requestsT(2), ierr)
+        ! Receive from west
+        recvtag = 1000
+        if (LUseO) call mpi_irecv(a%s(0,yoffset,0-(halo_size-1)),blocklength,  &
+                       MPI_DOUBLE_PRECISION,neighbour_w_rank,recvtag, &
+                       MPI_COMM_HORIZ, recv_requests(3), ierr)
+        recvtag = 1010
+        if (LUseT) call mpi_irecv(a%st(0-(halo_size-1),0,0),1,  &
+                       halo_wet(level,m),neighbour_w_rank,recvtag, &
+                       MPI_COMM_HORIZ, recv_requestsT(3), ierr)
+        ! Receive from east
+        sendtag = 1001
+        if (LUseO) call mpi_irecv(a%s(0,yoffset,a_n+1),blocklength,          &
+                       MPI_DOUBLE_PRECISION,neighbour_e_rank,recvtag, &
+                       MPI_COMM_HORIZ, recv_requests(4), ierr)
+        sendtag = 1011
+        if (LUseT) call mpi_irecv(a%st(a_n+1,0,0),1,          &
+                       halo_wet(level,m),neighbour_e_rank,recvtag, &
+                       MPI_COMM_HORIZ, recv_requestsT(4), ierr)
+        ! Send to east
+        sendtag = 1000
+        if (LUseO) call mpi_isend(a%s(0,yoffset,a_n-(halo_size-1)),blocklength,  &
+                       MPI_DOUBLE_PRECISION,neighbour_e_rank,sendtag, &
+                       MPI_COMM_HORIZ, send_requests(3), ierr)
+        sendtag = 1010
+        if (LUseT) call mpi_isend(a%st(a_n-(halo_size-1),0,0),1,  &
+                       halo_wet(level,m),neighbour_e_rank,sendtag, &
+                       MPI_COMM_HORIZ, send_requestsT(3), ierr)
+        ! Send to west
+        recvtag = 1001
+        if (LUseO) call mpi_isend(a%s(0,yoffset,1),blocklength,                &
+                       MPI_DOUBLE_PRECISION,neighbour_w_rank,sendtag,   &
+                       MPI_COMM_HORIZ, send_requests(4), ierr)
+        recvtag = 1011
+        if (LUseT) call mpi_isend(a%st(1,0,0),1,                &
+                       halo_wet(level,m),neighbour_w_rank,sendtag,   &
+                       MPI_COMM_HORIZ, send_requestsT(4), ierr)
+      end if
+    end if
+  end subroutine ihaloswap_mnh
+!==================================================================
+  subroutine ihaloswap(level,m,       &  ! multigrid- and processor- level
+                       a,             &  ! data field
+                       send_requests, &  ! send requests (OUT)
+                       recv_requests  &  ! recv requests (OUT)
+                       )
+    implicit none
+    integer, intent(in) :: level
+    integer, intent(in) :: m
+    integer, intent(out), dimension(4) :: send_requests
+    integer, intent(out), dimension(4) :: recv_requests
+    type(scalar3d), intent(inout) :: a
+    integer :: a_n  ! horizontal grid size
+    integer :: nz   ! vertical grid size
+    integer, dimension(2) :: p_horiz
+    integer :: stepsize
+    integer :: ierr, rank, sendtag, recvtag
+    integer :: stat(MPI_STATUS_SIZE)
+    integer :: halo_size
+    integer :: neighbour_n_rank
+    integer :: neighbour_s_rank
+    integer :: neighbour_e_rank
+    integer :: neighbour_w_rank
+    integer :: yoffset, blocklength
+
+    halo_size = comm_param%halo_size
+
+    ! Do nothing if we are only using one processor
+    if (m > 0) then
+      a_n = a%ix_max-a%ix_min+1
+      nz = a%grid_param%nz
+      stepsize = 2**(pproc-m)
+
+      ! Work out rank, only execute on relevant processes
+      call mpi_comm_rank(MPI_COMM_HORIZ, rank, ierr)
+      call mpi_cart_coords(MPI_COMM_HORIZ,rank,dim_horiz,p_horiz,ierr)
+
+      ! Work out ranks of neighbours
+      ! W -> E
+      call mpi_cart_shift(MPI_COMM_HORIZ,1, stepsize, &
+                          neighbour_w_rank,neighbour_e_rank,ierr)
+      ! N -> S
+      call mpi_cart_shift(MPI_COMM_HORIZ,0, stepsize, &
+                          neighbour_n_rank,neighbour_s_rank,ierr)
+      if ( (stepsize == 1) .or.                   &
+         (  (mod(p_horiz(1),stepsize) == 0) .and. &
+            (mod(p_horiz(2),stepsize) == 0) ) ) then
+        if (halo_size == 1) then
+          ! Do not include corners in send/recv
+          yoffset = 1
+          blocklength = a_n*(nz+2)*halo_size
+        else
+          yoffset = 1-halo_size
+          blocklength = (a_n+2*halo_size)*(nz+2)*halo_size
+        end if
+        ! Receive from north
+        recvtag = 2
+        call mpi_irecv(a%s(0,0-(halo_size-1),1),1,                  &
+                       halo_ns(level,m),neighbour_n_rank,recvtag,   &
+                       MPI_COMM_HORIZ, recv_requests(1), ierr)
+        ! Receive from south
+        recvtag = 3
+        call mpi_irecv(a%s(0,a_n+1,1),1,                            &
+                       halo_ns(level,m),neighbour_s_rank,recvtag,   &
+                       MPI_COMM_HORIZ, recv_requests(2), ierr)
+        ! Send to south
+        sendtag = 2
+        call mpi_isend(a%s(0,a_n-(halo_size-1),1),1,                &
+                       halo_ns(level,m),neighbour_s_rank,sendtag,   &
+                       MPI_COMM_HORIZ, send_requests(1), ierr)
+        ! Send to north
+        sendtag = 3
+        call mpi_isend(a%s(0,1,1),1,                                &
+                       halo_ns(level,m),neighbour_n_rank,sendtag,   &
+                       MPI_COMM_HORIZ, send_requests(2), ierr)
+        ! Receive from west
+        recvtag = 0
+        call mpi_irecv(a%s(0,yoffset,0-(halo_size-1)),blocklength,    &
+                       MPI_DOUBLE_PRECISION,neighbour_w_rank,recvtag, &
+                       MPI_COMM_HORIZ, recv_requests(3), ierr)
+        ! Receive from east
+        sendtag = 1
+        call mpi_irecv(a%s(0,yoffset,a_n+1),blocklength,          &
+                       MPI_DOUBLE_PRECISION,neighbour_e_rank,recvtag, &
+                       MPI_COMM_HORIZ, recv_requests(4), ierr)
+        ! Send to east
+        sendtag = 0
+        call mpi_isend(a%s(0,yoffset,a_n-(halo_size-1)),blocklength,  &
+                       MPI_DOUBLE_PRECISION,neighbour_e_rank,sendtag, &
+                       MPI_COMM_HORIZ, send_requests(3), ierr)
+        ! Send to west
+        recvtag = 1
+        call mpi_isend(a%s(0,yoffset,1),blocklength,                &
+                       MPI_DOUBLE_PRECISION,neighbour_w_rank,sendtag,   &
+                       MPI_COMM_HORIZ, send_requests(4), ierr)
+      end if
+    end if
+  end subroutine ihaloswap
+
+!==================================================================
+!  Halo exchange
+!
+!  For all processes with horizontal indices that are multiples
+!  of 2^(pproc-m), update halos with information held by
+!  neighbouring processes, e.g. for pproc-m = 1, stepsize=2
+!
+!                      N  (0,2)
+!                      ^
+!                      !
+!                      v
+!
+!      W (2,0) <-->  (2,2)  <-->  E (2,4)
+!
+!                      ^
+!                      !
+!                      v
+!                      S (4,2)
+!
+!==================================================================
+  subroutine haloswap_mnh(level,m, &  ! multigrid- and processor- level
+                      a)          ! data field
+    implicit none
+    integer, intent(in) :: level
+    integer, intent(in) :: m
+    type(scalar3d), intent(inout) :: a
+    !local var
+    integer :: a_n  ! horizontal grid size
+    integer :: nz   ! vertical grid size
+    integer, dimension(2) :: p_horiz
+    integer :: stepsize
+    integer :: ierr, rank, sendtag, recvtag
+    integer :: stat(MPI_STATUS_SIZE)
+    integer :: halo_size
+    integer :: neighbour_n_rank
+    integer :: neighbour_s_rank
+    integer :: neighbour_e_rank
+    integer :: neighbour_w_rank
+    integer :: yoffset, blocklength
+    integer, dimension(4) :: requests_ns
+    integer, dimension(4) :: requests_ew
+    integer, dimension(4) :: requests_nsT
+    integer, dimension(4) :: requests_ewT
+
+    halo_size = comm_param%halo_size
+
+    ! Do nothing if we are only using one processor
+    if (m > 0) then
+      if (comm_measuretime) then
+        call start_timer(t_haloswap(level,m))
+      end if
+      a_n = a%ix_max-a%ix_min+1
+      nz = a%grid_param%nz
+      stepsize = 2**(pproc-m)
+
+      ! Work out rank, only execute on relevant processes
+      call mpi_comm_rank(MPI_COMM_HORIZ, rank, ierr)
+      call mpi_cart_coords(MPI_COMM_HORIZ,rank,dim_horiz,p_horiz,ierr)
+
+      ! Work out ranks of neighbours
+      ! W -> E
+      call mpi_cart_shift(MPI_COMM_HORIZ,1, stepsize, &
+                          neighbour_w_rank,neighbour_e_rank,ierr)
+      ! N -> S
+      call mpi_cart_shift(MPI_COMM_HORIZ,0, stepsize, &
+                          neighbour_n_rank,neighbour_s_rank,ierr)
+      if ( (stepsize == 1) .or.                   &
+         (  (mod(p_horiz(1),stepsize) == 0) .and. &
+            (mod(p_horiz(2),stepsize) == 0) ) ) then
+        if (halo_size == 1) then
+          ! Do not include corners in send/recv
+          yoffset = 1
+          blocklength = a_n*(nz+2)*halo_size
+        else
+          yoffset = 1-halo_size
+          blocklength = (a_n+2*halo_size)*(nz+2)*halo_size
+        end if
+        ! Receive from north
+        recvtag = 1002
+        if (LUseO) call mpi_irecv(a%s(0,0-(halo_size-1),1),1,       &
+                       halo_ns(level,m),neighbour_n_rank,recvtag,   &
+                       MPI_COMM_HORIZ, requests_ns(1), ierr)
+        recvtag = 1012
+        if (LUseT) call mpi_irecv(a%st(1,0-(halo_size-1),0),1,      &
+                       halo_nst(level,m),neighbour_n_rank,recvtag,  &
+                       MPI_COMM_HORIZ, requests_nsT(1), ierr)
+        ! Receive from south
+        recvtag = 1003
+        if (LUseO) call mpi_irecv(a%s(0,a_n+1,1),1,                 &
+                       halo_ns(level,m),neighbour_s_rank,recvtag,   &
+                       MPI_COMM_HORIZ, requests_ns(2), ierr)
+        recvtag = 1013
+        if (LUseT) call mpi_irecv(a%st(1,a_n+1,0),1,                &
+                       halo_nst(level,m),neighbour_s_rank,recvtag,  &
+                       MPI_COMM_HORIZ, requests_nsT(2), ierr)
+        ! Send to south
+        sendtag = 1002
+        if (LUseO) call mpi_isend(a%s(0,a_n-(halo_size-1),1),1,     &
+                       halo_ns(level,m),neighbour_s_rank,sendtag,   &
+                       MPI_COMM_HORIZ, requests_ns(3), ierr)
+        sendtag = 1012
+        if (LUseT) call mpi_isend(a%st(1,a_n-(halo_size-1),0),1,    &
+                       halo_nst(level,m),neighbour_s_rank,sendtag,  &
+                       MPI_COMM_HORIZ, requests_nsT(3), ierr)
+        ! Send to north
+        sendtag = 1003
+        if (LUseO) call mpi_isend(a%s(0,1,1),1,                     &
+                       halo_ns(level,m),neighbour_n_rank,sendtag,   &
+                       MPI_COMM_HORIZ, requests_ns(4), ierr)
+        sendtag = 1013
+        if (LUseT) call mpi_isend(a%st(1,1,0),1,                    &
+                       halo_nst(level,m),neighbour_n_rank,sendtag,  &
+                       MPI_COMM_HORIZ, requests_nsT(4), ierr)
+        if (halo_size > 1) then
+          ! Wait for North <-> South communication to complete
+          if (LUseO) call mpi_waitall(4,requests_ns, MPI_STATUSES_IGNORE, ierr)
+          if (LUseT) call mpi_waitall(4,requests_nsT, MPI_STATUSES_IGNORE, ierr)
+        end if
+        ! Receive from west
+        recvtag = 1000
+        if (LUseO) call mpi_irecv(a%s(0,yoffset,0-(halo_size-1)),blocklength,    &
+                       MPI_DOUBLE_PRECISION,neighbour_w_rank,recvtag, &
+                       MPI_COMM_HORIZ, requests_ew(1), ierr)
+        recvtag = 1010
+        if (LUseT) call mpi_irecv(a%st(0-(halo_size-1),0,0),1,  &
+                       halo_wet(level,m),neighbour_w_rank,recvtag, &
+                       MPI_COMM_HORIZ, requests_ewT(1), ierr)
+        ! Receive from east
+        sendtag = 1001
+        if (LUseO) call mpi_irecv(a%s(0,yoffset,a_n+1),blocklength,          &
+                       MPI_DOUBLE_PRECISION,neighbour_e_rank,recvtag, &
+                       MPI_COMM_HORIZ, requests_ew(2), ierr)
+        sendtag = 1011
+        if (LUseT) call mpi_irecv(a%st(a_n+1,0,0),1,          &
+                       halo_wet(level,m),neighbour_e_rank,recvtag, &
+                       MPI_COMM_HORIZ, requests_ewT(2), ierr)
+        ! Send to east
+        sendtag = 1000
+        if (LUseO) call mpi_isend(a%s(0,yoffset,a_n-(halo_size-1)),blocklength,  &
+                       MPI_DOUBLE_PRECISION,neighbour_e_rank,sendtag, &
+                       MPI_COMM_HORIZ, requests_ew(3), ierr)
+        sendtag = 1010
+        if (LUseT) call mpi_isend(a%st(a_n-(halo_size-1),0,0),1,  &
+                       halo_wet(level,m),neighbour_e_rank,sendtag, &
+                       MPI_COMM_HORIZ, requests_ewT(3), ierr)
+        ! Send to west
+        recvtag = 1001
+        if (LUseO) call mpi_isend(a%s(0,yoffset,1),blocklength,                &
+                       MPI_DOUBLE_PRECISION,neighbour_w_rank,sendtag,   &
+                       MPI_COMM_HORIZ, requests_ew(4), ierr)
+        recvtag = 1011
+        if (LUseT) call mpi_isend(a%st(1,0,0),1,                &
+                       halo_wet(level,m),neighbour_w_rank,sendtag,   &
+                       MPI_COMM_HORIZ, requests_ewT(4), ierr)
+        ! Wait for East <-> West communication to complete
+        if (halo_size == 1) then
+          ! Wait for North <-> South communication to complete
+          if (LUseO) call mpi_waitall(4,requests_ns, MPI_STATUSES_IGNORE, ierr)
+          if (LUseT) call mpi_waitall(4,requests_nsT, MPI_STATUSES_IGNORE, ierr)
+        end if
+        if (LUseO) call mpi_waitall(4,requests_ew, MPI_STATUSES_IGNORE, ierr)
+        if (LUseT) call mpi_waitall(4,requests_ewT, MPI_STATUSES_IGNORE, ierr)
+      end if
+      if (comm_measuretime) then
+        call finish_timer(t_haloswap(level,m))
+      end if
+    end if
+
+  end subroutine haloswap_mnh
+!==================================================================
+  subroutine haloswap(level,m, &  ! multigrid- and processor- level
+                      a)          ! data field
+    implicit none
+    integer, intent(in) :: level
+    integer, intent(in) :: m
+    type(scalar3d), intent(inout) :: a
+    integer :: a_n  ! horizontal grid size
+    integer :: nz   ! vertical grid size
+    integer, dimension(2) :: p_horiz
+    integer :: stepsize
+    integer :: ierr, rank, sendtag, recvtag
+    integer :: stat(MPI_STATUS_SIZE)
+    integer :: halo_size
+    integer :: neighbour_n_rank
+    integer :: neighbour_s_rank
+    integer :: neighbour_e_rank
+    integer :: neighbour_w_rank
+    integer :: yoffset, blocklength
+    integer, dimension(4) :: requests_ns
+    integer, dimension(4) :: requests_ew
+
+    halo_size = comm_param%halo_size
+
+    ! Do nothing if we are only using one processor
+    if (m > 0) then
+      if (comm_measuretime) then
+        call start_timer(t_haloswap(level,m))
+      end if
+      a_n = a%ix_max-a%ix_min+1
+      nz = a%grid_param%nz
+      stepsize = 2**(pproc-m)
+
+      ! Work out rank, only execute on relevant processes
+      call mpi_comm_rank(MPI_COMM_HORIZ, rank, ierr)
+      call mpi_cart_coords(MPI_COMM_HORIZ,rank,dim_horiz,p_horiz,ierr)
+
+      ! Work out ranks of neighbours
+      ! W -> E
+      call mpi_cart_shift(MPI_COMM_HORIZ,1, stepsize, &
+                          neighbour_w_rank,neighbour_e_rank,ierr)
+      ! N -> S
+      call mpi_cart_shift(MPI_COMM_HORIZ,0, stepsize, &
+                          neighbour_n_rank,neighbour_s_rank,ierr)
+      if ( (stepsize == 1) .or.                   &
+         (  (mod(p_horiz(1),stepsize) == 0) .and. &
+            (mod(p_horiz(2),stepsize) == 0) ) ) then
+        if (halo_size == 1) then
+          ! Do not include corners in send/recv
+          yoffset = 1
+          blocklength = a_n*(nz+2)*halo_size
+        else
+          yoffset = 1-halo_size
+          blocklength = (a_n+2*halo_size)*(nz+2)*halo_size
+        end if
+        ! Receive from north
+        recvtag = 2
+        call mpi_irecv(a%s(0,0-(halo_size-1),1),1,                  &
+                       halo_ns(level,m),neighbour_n_rank,recvtag,   &
+                       MPI_COMM_HORIZ, requests_ns(1), ierr)
+        ! Receive from south
+        recvtag = 3
+        call mpi_irecv(a%s(0,a_n+1,1),1,                            &
+                       halo_ns(level,m),neighbour_s_rank,recvtag,   &
+                       MPI_COMM_HORIZ, requests_ns(2), ierr)
+        ! Send to south
+        sendtag = 2
+        call mpi_isend(a%s(0,a_n-(halo_size-1),1),1,                &
+                       halo_ns(level,m),neighbour_s_rank,sendtag,   &
+                       MPI_COMM_HORIZ, requests_ns(3), ierr)
+        ! Send to north
+        sendtag = 3
+        call mpi_isend(a%s(0,1,1),1,                                &
+                       halo_ns(level,m),neighbour_n_rank,sendtag,   &
+                       MPI_COMM_HORIZ, requests_ns(4), ierr)
+        if (halo_size > 1) then
+          ! Wait for North <-> South communication to complete
+          call mpi_waitall(4,requests_ns, MPI_STATUSES_IGNORE, ierr)
+        end if
+        ! Receive from west
+        recvtag = 0
+        call mpi_irecv(a%s(0,yoffset,0-(halo_size-1)),blocklength,    &
+                       MPI_DOUBLE_PRECISION,neighbour_w_rank,recvtag, &
+                       MPI_COMM_HORIZ, requests_ew(1), ierr)
+        ! Receive from east
+        sendtag = 1
+        call mpi_irecv(a%s(0,yoffset,a_n+1),blocklength,          &
+                       MPI_DOUBLE_PRECISION,neighbour_e_rank,recvtag, &
+                       MPI_COMM_HORIZ, requests_ew(2), ierr)
+        ! Send to east
+        sendtag = 0
+        call mpi_isend(a%s(0,yoffset,a_n-(halo_size-1)),blocklength,  &
+                       MPI_DOUBLE_PRECISION,neighbour_e_rank,sendtag, &
+                       MPI_COMM_HORIZ, requests_ew(3), ierr)
+        ! Send to west
+        recvtag = 1
+        call mpi_isend(a%s(0,yoffset,1),blocklength,                &
+                       MPI_DOUBLE_PRECISION,neighbour_w_rank,sendtag,   &
+                       MPI_COMM_HORIZ, requests_ew(4), ierr)
+        ! Wait for East <-> West communication to complete
+        if (halo_size == 1) then
+          ! Wait for North <-> South communication to complete
+          call mpi_waitall(4,requests_ns, MPI_STATUSES_IGNORE, ierr)
+        end if
+        call mpi_waitall(4,requests_ew, MPI_STATUSES_IGNORE, ierr)
+      end if
+      if (comm_measuretime) then
+        call finish_timer(t_haloswap(level,m))
+      end if
+    end if
+  end subroutine haloswap
+!==================================================================
+!  Collect from a(level,m) and store on less processors
+!  in b(level,m-1)
+!
+!  Example for pproc-m = 1, i.e. stepsize = 2:
+!
+!   NW (0,0)  <--  NE (0,2)
+!
+!     ^      .
+!     !        .
+!                .
+!   SW (2,0)       SE (2,2) [send to 0,0]
+!
+!==================================================================
+  subroutine collect(level,m, &    ! multigrid and processor level
+                     a, &          ! IN: data on level (level,m)
+                     b)            ! OUT: data on level (level,m-1)
+    implicit none
+    integer, intent(in) :: level
+    integer, intent(in) :: m
+    type(scalar3d), intent(in) :: a
+    type(scalar3d), intent(inout) :: b
+    integer :: a_n, b_n   ! horizontal grid sizes
+    integer :: nz ! vertical grid size
+    integer, dimension(2) :: p_horiz
+    integer :: stepsize
+    integer :: ierr, source_rank, dest_rank, rank, recv_tag, send_tag, iz
+    logical :: corner_nw, corner_ne, corner_sw, corner_se
+    integer :: recv_request(3)
+    integer :: recv_requestT(3)
+
+    call start_timer(t_collect(m))
+
+    stepsize = 2**(pproc-m)
+
+    a_n = a%ix_max-a%ix_min+1
+    b_n = b%ix_max-b%ix_min+1
+    nz = b%grid_param%nz
+
+    ! Work out rank, only execute on relevant processes
+    call mpi_comm_rank(MPI_COMM_HORIZ, rank, ierr)
+    ! Store position in process grid in in p_horiz
+    ! Note we can NOT use cart_shift as we need diagonal neighburs as well
+    call mpi_cart_coords(MPI_COMM_HORIZ,rank,dim_horiz,p_horiz,ierr)
+
+    ! Ignore all processes that do not participate at this level
+    if ( (stepsize .eq. 1) .or. ((mod(p_horiz(1),stepsize) == 0) .and. (mod(p_horiz(2),stepsize)) == 0)) then
+      ! Determine position in local 2x2 block
+      if (stepsize .eq. 1) then
+        corner_nw = ((mod(p_horiz(1),2) == 0) .and. (mod(p_horiz(2),2) == 0))
+        corner_ne = ((mod(p_horiz(1),2) == 0) .and. (mod(p_horiz(2),2) == 1))
+        corner_sw = ((mod(p_horiz(1),2) == 1) .and. (mod(p_horiz(2),2) == 0))
+        corner_se = ((mod(p_horiz(1),2) == 1) .and. (mod(p_horiz(2),2) == 1))
+      else
+        corner_nw = ((mod(p_horiz(1)/stepsize,2) == 0) .and. (mod(p_horiz(2)/stepsize,2) == 0))
+        corner_ne = ((mod(p_horiz(1)/stepsize,2) == 0) .and. (mod(p_horiz(2)/stepsize,2) == 1))
+        corner_sw = ((mod(p_horiz(1)/stepsize,2) == 1) .and. (mod(p_horiz(2)/stepsize,2) == 0))
+        corner_se = ((mod(p_horiz(1)/stepsize,2) == 1) .and. (mod(p_horiz(2)/stepsize,2) == 1))
+      end if
+      ! NW receives from the other three processes
+      if ( corner_nw ) then
+        ! Receive from NE
+        call mpi_cart_rank(MPI_COMM_HORIZ, &
+                           (/p_horiz(1),p_horiz(2)+stepsize/), &
+                           source_rank, &
+                           ierr)
+        recv_tag = 1000
+        if (LUseO) call mpi_irecv(b%s(0,1,b_n/2+1),1,sub_interior(level,m-1), source_rank, recv_tag, MPI_COMM_HORIZ, &
+                           recv_request(1),ierr)
+        recv_tag = 1010
+        if (LUseT) call mpi_irecv(b%st(b_n/2+1,1,0),1,sub_interiorT(level,m-1), source_rank, recv_tag, MPI_COMM_HORIZ, &
+                           recv_requestT(1),ierr)
+#ifndef NDEBUG
+  if (ierr .ne. 0) &
+    call fatalerror("Collect: receive from NE failed in mpi_irecv().")
+#endif
+         ! Receive from SW
+        call mpi_cart_rank(MPI_COMM_HORIZ, &
+                           (/p_horiz(1)+stepsize,p_horiz(2)/), &
+                           source_rank, &
+                           ierr)
+        recv_tag = 1001
+        if (LUseO) call mpi_irecv(b%s(0,b_n/2+1,1),1,sub_interior(level,m-1), source_rank, recv_tag, MPI_COMM_HORIZ, &
+                           recv_request(2),ierr)
+        recv_tag = 1011
+        if (LUseT) call mpi_irecv(b%st(1,b_n/2+1,0),1,sub_interiorT(level,m-1), source_rank, recv_tag, MPI_COMM_HORIZ, &
+                           recv_requestT(2),ierr)
+
+#ifndef NDEBUG
+  if (ierr .ne. 0) &
+    call fatalerror("Collect: receive from SW failed in mpi_irecv().")
+#endif
+        ! Receive from SE
+        call mpi_cart_rank(MPI_COMM_HORIZ, &
+                           (/p_horiz(1)+stepsize,p_horiz(2)+stepsize/), &
+                           source_rank, &
+                           ierr)
+        recv_tag = 1002
+        if (LUseO) call mpi_irecv(b%s(0,b_n/2+1,b_n/2+1),1,sub_interior(level,m-1), source_rank, recv_tag, MPI_COMM_HORIZ, &
+                           recv_request(3),ierr)
+        recv_tag = 1012
+        if (LUseT) call mpi_irecv(b%st(b_n/2+1,b_n/2+1,0),1,sub_interiorT(level,m-1), source_rank, recv_tag, MPI_COMM_HORIZ, &
+                           recv_requestT(3),ierr)
+#ifndef NDEBUG
+  if (ierr .ne. 0) &
+    call fatalerror("Collect: receive from SE failed in mpi_irecv().")
+#endif
+        ! Copy local data while waiting for data from other processes
+        if (LUseO) b%s(0:nz+1,1:a_n,1:a_n) = a%s(0:nz+1,1:a_n,1:a_n)
+        if (LUseT) b%st(1:a_n,1:a_n,0:nz+1) = a%st(1:a_n,1:a_n,0:nz+1)
+        ! Wait for receives to complete before proceeding
+        if (LUseO) call mpi_waitall(3,recv_request,MPI_STATUSES_IGNORE,ierr)
+        if (LUseT) call mpi_waitall(3,recv_requestT,MPI_STATUSES_IGNORE,ierr)
+      end if
+      if ( corner_ne ) then
+        ! Send to NW
+        call mpi_cart_rank(MPI_COMM_HORIZ, &
+                           (/p_horiz(1),p_horiz(2)-stepsize/), &
+                           dest_rank, &
+                           ierr)
+        send_tag = 1000
+        if (LUseO) call mpi_send(a%s(0,1,1),1,interior(level,m),dest_rank,send_tag,MPI_COMM_HORIZ,ierr)
+        send_tag = 1010
+        if (LUseT) call mpi_send(a%st(1,1,0),1,interiorT(level,m),dest_rank,send_tag,MPI_COMM_HORIZ,ierr)
+#ifndef NDEBUG
+  if (ierr .ne. 0) &
+    call fatalerror("Collect: send from NE failed in mpi_send().")
+#endif
+      end if
+      if ( corner_sw ) then
+        ! Send to NW
+        call mpi_cart_rank(MPI_COMM_HORIZ, &
+                           (/p_horiz(1)-stepsize,p_horiz(2)/), &
+                           dest_rank, &
+                           ierr)
+        send_tag = 1001
+        if (LUseO) call mpi_send(a%s(0,1,1),1,interior(level,m),dest_rank,send_tag,MPI_COMM_HORIZ,ierr)
+        send_tag = 1011
+        if (LUseT) call mpi_send(a%st(1,1,0),1,interiorT(level,m),dest_rank,send_tag,MPI_COMM_HORIZ,ierr)
+#ifndef NDEBUG
+  if (ierr .ne. 0) &
+    call fatalerror("Collect: send from SW failed in mpi_send().")
+#endif
+      end if
+      if ( corner_se ) then
+        ! send to NW
+        call mpi_cart_rank(MPI_COMM_HORIZ, &
+                           (/p_horiz(1)-stepsize,p_horiz(2)-stepsize/), &
+                           dest_rank, &
+                           ierr)
+        send_tag = 1002
+        if (LUseO) call mpi_send(a%s(0,1,1),1,interior(level,m),dest_rank,send_tag,MPI_COMM_HORIZ,ierr)
+        send_tag = 1012
+        if (LUseT) call mpi_send(a%st(1,1,0),1,interiorT(level,m),dest_rank,send_tag,MPI_COMM_HORIZ,ierr)
+#ifndef NDEBUG
+  if (ierr .ne. 0) &
+    call fatalerror("Collect: send from SE failed in mpi_send().")
+#endif
+      end if
+
+    end if
+    call finish_timer(t_collect(m))
+
+  end subroutine collect
+
+!==================================================================
+!  Distribute data in a(level,m-1) and store in b(level,m)
+!
+!  Example for p-m = 1, i.e. stepsize = 2:
+!
+!   NW (0,0)  -->  NE (2,0)
+!
+!     !      .
+!     v        .
+!                .
+!   SW (0,2)       SE (2,2) [receive from to 0,0]
+!==================================================================
+  subroutine distribute(level,m, &  ! multigrid and processor level
+                        a,       &  ! IN: Data on level (level,m-1)
+                        b)          ! OUT: Data on level (level,m)
+    implicit none
+    integer, intent(in) :: level
+    integer, intent(in) :: m
+    type(scalar3d), intent(in) :: a
+    type(scalar3d), intent(inout) :: b
+    integer :: a_n, b_n   ! horizontal grid sizes
+    integer :: nz ! vertical grid size
+    integer, dimension(2) :: p_horiz
+    integer :: stepsize
+    integer :: ierr, source_rank, dest_rank, send_tag, recv_tag, rank, iz
+    integer :: stat(MPI_STATUS_SIZE)
+    integer :: send_request(3)
+    integer :: send_requestT(3)
+    logical :: corner_nw, corner_ne, corner_sw, corner_se
+
+    call start_timer(t_distribute(m))
+
+    stepsize = 2**(pproc-m)
+
+    a_n = a%ix_max-a%ix_min+1
+    b_n = b%ix_max-b%ix_min+1
+    nz = a%grid_param%nz
+
+    ! Work out rank, only execute on relevant processes
+    call mpi_comm_rank(MPI_COMM_HORIZ, rank, ierr)
+    call mpi_cart_coords(MPI_COMM_HORIZ,rank,dim_horiz,p_horiz,ierr)
+
+    ! Ignore all processes that do not participate at this level
+    if ( (stepsize .eq. 1) .or. ((mod(p_horiz(1),stepsize) == 0) .and. (mod(p_horiz(2),stepsize)) == 0)) then
+      ! Work out coordinates in local 2 x 2 block
+      if (stepsize .eq. 1) then
+        corner_nw = ((mod(p_horiz(1),2) == 0) .and. (mod(p_horiz(2),2) == 0))
+        corner_ne = ((mod(p_horiz(1),2) == 0) .and. (mod(p_horiz(2),2) == 1))
+        corner_sw = ((mod(p_horiz(1),2) == 1) .and. (mod(p_horiz(2),2) == 0))
+        corner_se = ((mod(p_horiz(1),2) == 1) .and. (mod(p_horiz(2),2) == 1))
+      else
+        corner_nw = ((mod(p_horiz(1)/stepsize,2) == 0) .and. (mod(p_horiz(2)/stepsize,2) == 0))
+        corner_ne = ((mod(p_horiz(1)/stepsize,2) == 0) .and. (mod(p_horiz(2)/stepsize,2) == 1))
+        corner_sw = ((mod(p_horiz(1)/stepsize,2) == 1) .and. (mod(p_horiz(2)/stepsize,2) == 0))
+        corner_se = ((mod(p_horiz(1)/stepsize,2) == 1) .and. (mod(p_horiz(2)/stepsize,2) == 1))
+      end if
+      if ( corner_nw ) then
+        ! (Asynchronous) send to NE
+        call mpi_cart_rank(MPI_COMM_HORIZ, &
+                           (/p_horiz(1),p_horiz(2)+stepsize/), &
+                           dest_rank, &
+                           ierr)
+
+        send_tag = 1000
+        if (LUseO) call mpi_isend(a%s(0,1,a_n/2+1), 1,sub_interior(level,m-1),dest_rank, send_tag, &
+                       MPI_COMM_HORIZ,send_request(1),ierr)
+        send_tag = 1010
+        if (LUseT) call mpi_isend(a%st(a_n/2+1,1,0), 1,sub_interiorT(level,m-1),dest_rank, send_tag, &
+                       MPI_COMM_HORIZ,send_requestT(1),ierr)
+#ifndef NDEBUG
+  if (ierr .ne. 0) &
+    call fatalerror("Distribute: send to NE failed in mpi_isend().")
+#endif
+        ! (Asynchronous) send to SW
+        call mpi_cart_rank(MPI_COMM_HORIZ, &
+                           (/p_horiz(1)+stepsize,p_horiz(2)/), &
+                           dest_rank, &
+                           ierr)
+        send_tag = 1001
+        if (LUseO) call mpi_isend(a%s(0,a_n/2+1,1),1,sub_interior(level,m-1), dest_rank, send_tag, &
+                       MPI_COMM_HORIZ, send_request(2), ierr)
+        send_tag = 1011
+        if (LUseT) call mpi_isend(a%st(1,a_n/2+1,0),1,sub_interiorT(level,m-1), dest_rank, send_tag, &
+                       MPI_COMM_HORIZ, send_requestT(2), ierr)
+
+#ifndef NDEBUG
+  if (ierr .ne. 0) &
+    call fatalerror("Distribute: send to SW failed in mpi_isend().")
+#endif
+        ! (Asynchronous) send to SE
+        call mpi_cart_rank(MPI_COMM_HORIZ, &
+                           (/p_horiz(1)+stepsize,p_horiz(2)+stepsize/), &
+                           dest_rank, &
+                           ierr)
+        send_tag = 1002
+        if (LUseO) call mpi_isend(a%s(0,a_n/2+1,a_n/2+1),1,sub_interior(level,m-1), dest_rank, send_tag, &
+                      MPI_COMM_HORIZ, send_request(3), ierr)
+        send_tag = 1012
+        if (LUseT) call mpi_isend(a%st(a_n/2+1,a_n/2+1,0),1,sub_interiorT(level,m-1), dest_rank, send_tag, &
+                      MPI_COMM_HORIZ, send_requestT(3), ierr)
+#ifndef NDEBUG
+  if (ierr .ne. 0) &
+    call fatalerror("Distribute: send to SE failed in mpi_isend().")
+#endif
+        ! While sending, copy local data
+        if (LUseO) b%s(0:nz+1,1:b_n,1:b_n) = a%s(0:nz+1,1:b_n,1:b_n)
+        if (LUseT) b%st(1:b_n,1:b_n,0:nz+1) = a%st(1:b_n,1:b_n,0:nz+1)
+        ! Only proceed when async sends to complete
+        if (LUseO) call mpi_waitall(3, send_request, MPI_STATUSES_IGNORE, ierr)
+        if (LUseT) call mpi_waitall(3, send_requestT, MPI_STATUSES_IGNORE, ierr)
+      end if
+      if ( corner_ne ) then
+
+        ! Receive from NW
+        call mpi_cart_rank(MPI_COMM_HORIZ, &
+                           (/p_horiz(1),p_horiz(2)-stepsize/), &
+                           source_rank, &
+                           ierr)
+        recv_tag = 1000
+        if (LUseO) call mpi_recv(b%s(0,1,1),1,interior(level,m),source_rank,recv_tag,MPI_COMM_HORIZ,stat,ierr)
+        recv_tag = 1010
+        if (LUseT) call mpi_recv(b%st(1,1,0),1,interiorT(level,m),source_rank,recv_tag,MPI_COMM_HORIZ,stat,ierr)
+#ifndef NDEBUG
+  if (ierr .ne. 0) &
+    call fatalerror("Distribute: receive on NE failed in mpi_recv().")
+#endif
+      end if
+      if ( corner_sw ) then
+        ! Receive from NW
+        call mpi_cart_rank(MPI_COMM_HORIZ, &
+                           (/p_horiz(1)-stepsize,p_horiz(2)/), &
+                           source_rank, &
+                           ierr)
+        recv_tag = 1001
+        if (LUseO) call mpi_recv(b%s(0,1,1),1,interior(level,m),source_rank,recv_tag,MPI_COMM_HORIZ,stat,ierr)
+        recv_tag = 1011
+        if (LUseT) call mpi_recv(b%st(1,1,0),1,interiorT(level,m),source_rank,recv_tag,MPI_COMM_HORIZ,stat,ierr)
+#ifndef NDEBUG
+  if (ierr .ne. 0) &
+    call fatalerror("Distribute: receive on SW failed in mpi_recv().")
+#endif
+      end if
+      if ( corner_se ) then
+        ! Receive from NW
+        call mpi_cart_rank(MPI_COMM_HORIZ, &
+                           (/p_horiz(1)-stepsize,p_horiz(2)-stepsize/), &
+                           source_rank, &
+                           ierr)
+        recv_tag = 1002
+        if (LUseO) call mpi_recv(b%s(0,1,1),1,interior(level,m),source_rank,recv_tag,MPI_COMM_HORIZ,stat,ierr)
+        recv_tag = 1012
+        if (LUseT) call mpi_recv(b%st(1,1,0),1,interiorT(level,m),source_rank,recv_tag,MPI_COMM_HORIZ,stat,ierr)
+#ifndef NDEBUG
+  if (ierr .ne. 0) &
+    call fatalerror("Distribute: receive on NW failed in mpi_recv().")
+#endif
+      end if
+
+    end if
+    call finish_timer(t_distribute(m))
+
+  end subroutine distribute
+
+end module communication
diff --git a/src/ZSOLVER/tensorproductmultigrid_Source/compile_tensor b/src/ZSOLVER/tensorproductmultigrid_Source/compile_tensor
new file mode 100755
index 0000000000000000000000000000000000000000..dae8a91858520b10115f0e5e281d9ffe23234594
--- /dev/null
+++ b/src/ZSOLVER/tensorproductmultigrid_Source/compile_tensor
@@ -0,0 +1,38 @@
+#!/bin/bash
+
+set -x
+set -e
+
+OPT_BASE="  -Mbackslash -Mextend -Kieee -nofma  -Mallocatable=95 "
+#OPT_BASE="  -Mbackslash -Mextend   -Mallocatable=95 "
+
+#OPTLEVEL="  -O2 -ta=multicore,tesla:nofma,managed "
+#OPTLEVEL="  -g -O2 -ta=multicore,tesla:managed "
+OPTLEVEL=" -tp=px -O2 -ta=multicore,tesla,nofma,cc35,cc50,cc70,cuda10.1,managed -Minfo=accel,ccff -Mprof=ccff  "
+#OPTLEVEL=" -O2 -ta=tesla:nofma,managed "
+
+OPT="-r8 -DCARTESIANGEOMETRY -DOVERLAPCOMMS -DPIECEWISELINEAR -Mpreprocess ${OPT_BASE} ${OPTLEVEL} "
+
+F90="mpif90 ${OPT} "
+
+rm -f *.o *.mod mg_main_mnh
+
+pgf90 -show ${OPT} mg_main_mnh.f90
+
+
+for file in parameters.f90 messages.f90 datatypes.f90 timer.f90 communication.f90 discretisation.f90 \
+            solver.f90 conjugategradient.f90 multigrid.f90 profiles.f90 mode_mg_read_param.f90 \
+	    mode_mg.f90 mode_mg_read_param.f90 \
+	    dblas.f90 
+do
+echo ====== file=$file
+${F90} -c $file
+done
+
+
+${F90} -o mg_main_mnh mg_main_mnh.f90 *.o
+
+rm -f *.o *.mod
+
+
+
diff --git a/src/ZSOLVER/tensorproductmultigrid_Source/conjugategradient.f90 b/src/ZSOLVER/tensorproductmultigrid_Source/conjugategradient.f90
new file mode 100644
index 0000000000000000000000000000000000000000..30277d8625ad6735444ad7335b761ab6ed369b7a
--- /dev/null
+++ b/src/ZSOLVER/tensorproductmultigrid_Source/conjugategradient.f90
@@ -0,0 +1,529 @@
+!=== COPYRIGHT AND LICENSE STATEMENT ===
+!
+!  This file is part of the TensorProductMultigrid code.
+!  
+!  (c) The copyright relating to this work is owned jointly by the
+!  Crown, Met Office and NERC [2014]. However, it has been created
+!  with the help of the GungHo Consortium, whose members are identified
+!  at https://puma.nerc.ac.uk/trac/GungHo/wiki .
+!  
+!  Main Developer: Eike Mueller
+!  
+!  TensorProductMultigrid is free software: you can redistribute it and/or
+!  modify it under the terms of the GNU Lesser General Public License as
+!  published by the Free Software Foundation, either version 3 of the
+!  License, or (at your option) any later version.
+!  
+!  TensorProductMultigrid is distributed in the hope that it will be useful,
+!  but WITHOUT ANY WARRANTY; without even the implied warranty of
+!  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+!  GNU Lesser General Public License for more details.
+!  
+!  You should have received a copy of the GNU Lesser General Public License
+!  along with TensorProductMultigrid (see files COPYING and COPYING.LESSER).
+!  If not, see <http://www.gnu.org/licenses/>.
+!
+!=== COPYRIGHT AND LICENSE STATEMENT ===
+
+
+!==================================================================
+!
+! Conjugate gradient solver
+!
+!    Eike Mueller, University of Bath, Feb 2012
+!
+!==================================================================
+module conjugategradient
+
+  use parameters
+  use datatypes
+  use discretisation
+  use messages
+  use communication
+#ifndef MNH
+  use mpi
+#else
+  use modd_mpif
+#endif
+
+  implicit none
+
+public::cg_parameters
+public::cg_initialise
+public::cg_finalise
+public::cg_solve_mnh
+public::cg_solve
+
+private
+
+  ! --- Conjugate gradient parameters type ---
+  type cg_parameters
+    ! Verbosity level
+    integer :: verbose
+    ! Maximal number of iterations
+    integer :: maxiter
+    ! Required residual reduction
+    real(kind=rl) :: resreduction
+    ! Smoother iterations in preconditioner
+    integer :: n_prec
+  end type cg_parameters
+
+! --- Parameters ---
+  type(cg_parameters) :: cg_param
+  type(grid_parameters) :: grid_param
+
+contains
+
+!==================================================================
+! Initialise conjugate gradient module,
+!==================================================================
+  subroutine cg_initialise(cg_param_in)    &  ! Conjugate gradient
+                                           &  ! parameters
+    implicit none
+    type(cg_parameters), intent(in)    :: cg_param_in
+
+    if (i_am_master_mpi) then
+      write(STDOUT,*) '*** Initialising Conjugate gradient ***'
+      write(STDOUT,*) ''
+    end if
+    cg_param = cg_param_in
+  end subroutine cg_initialise
+
+!==================================================================
+! Finalise conjugate gradient module,
+!==================================================================
+  subroutine cg_finalise()
+    implicit none
+
+    if (i_am_master_mpi) then
+      write(STDOUT,*) '*** Finalising Conjugate gradient ***'
+      write(STDOUT,*) ''
+    end if
+  end subroutine cg_finalise
+
+!==================================================================
+! Solve A.u = b.
+!==================================================================
+  subroutine cg_solve_mnh(level,m,b,u)
+    implicit none
+    integer, intent(in)           :: level
+    integer, intent(in)           :: m
+    type(scalar3d), intent(in)    :: b    ! RHS vector
+    type(scalar3d), intent(inout) :: u    ! solution vector
+    type(scalar3d)                :: p    ! } Auxilliary vectors
+    type(scalar3d)                :: r    ! } Auxilliary vectors
+    type(scalar3d)                :: Ap   ! }
+    type(scalar3d)                :: z    ! }
+    integer                       :: n_lin
+    real(kind=rl)                 :: res0, rz, rz_old, res, alpha
+    integer :: i
+    logical :: solver_converged = .false.
+    integer :: n, nz, nlocal, halo_size
+    real(kind=rl) :: pAp
+
+    ! Initialise auxiliary fields
+    p%grid_param = u%grid_param
+    p%ix_min = u%ix_min
+    p%ix_max = u%ix_max
+    p%iy_min = u%iy_min
+    p%iy_max = u%iy_max
+    p%icompx_min = u%icompx_min
+    p%icompx_max = u%icompx_max
+    p%icompy_min = u%icompy_min
+    p%icompy_max = u%icompy_max
+    p%halo_size = u%halo_size
+
+    r%grid_param = u%grid_param
+    r%ix_min = u%ix_min
+    r%ix_max = u%ix_max
+    r%iy_min = u%iy_min
+    r%iy_max = u%iy_max
+    r%icompx_min = u%icompx_min
+    r%icompx_max = u%icompx_max
+    r%icompy_min = u%icompy_min
+    r%icompy_max = u%icompy_max
+    r%halo_size = u%halo_size
+
+    z%grid_param = u%grid_param
+    z%ix_min = u%ix_min
+    z%ix_max = u%ix_max
+    z%iy_min = u%iy_min
+    z%iy_max = u%iy_max
+    z%icompx_min = u%icompx_min
+    z%icompx_max = u%icompx_max
+    z%icompy_min = u%icompy_min
+    z%icompy_max = u%icompy_max
+    z%halo_size = u%halo_size
+
+    Ap%grid_param = u%grid_param
+    Ap%ix_min = u%ix_min
+    Ap%ix_max = u%ix_max
+    Ap%iy_min = u%iy_min
+    Ap%iy_max = u%iy_max
+    Ap%icompx_min = u%icompx_min
+    Ap%icompx_max = u%icompx_max
+    Ap%icompy_min = u%icompy_min
+    Ap%icompy_max = u%icompy_max
+    Ap%halo_size = u%halo_size
+
+    n = u%ix_max-u%ix_min+1
+    nz = u%grid_param%nz
+
+    nlocal = u%ix_max - u%ix_min + 1
+    halo_size = u%halo_size
+
+    n_lin = (nlocal+2*halo_size)**2 * (nz+2)
+
+    if (LUseO) then
+    allocate(r%s(0:nz+1,                     &
+             1-halo_size:nlocal+halo_size,   &
+             1-halo_size:nlocal+halo_size) )
+    allocate(z%s(0:nz+1,                     &
+             1-halo_size:nlocal+halo_size,   &
+             1-halo_size:nlocal+halo_size) )
+    allocate(p%s(0:nz+1,                     &
+             1-halo_size:nlocal+halo_size,   &
+             1-halo_size:nlocal+halo_size) )
+    allocate(Ap%s(0:nz+1,                    &
+             1-halo_size:nlocal+halo_size,   &
+             1-halo_size:nlocal+halo_size) )
+    r%s = 0.0_rl
+    z%s = 0.0_rl
+    p%s = 0.0_rl
+    Ap%s = 0.0_rl
+    endif
+
+    if (LUseT) then
+    allocate(r%st(1-halo_size:nlocal+halo_size,   &
+                  1-halo_size:nlocal+halo_size,   &
+                  0:nz+1) )
+    allocate(z%st(1-halo_size:nlocal+halo_size,   &
+                  1-halo_size:nlocal+halo_size,   &
+                  0:nz+1) )
+    allocate(p%st(1-halo_size:nlocal+halo_size,   &
+                  1-halo_size:nlocal+halo_size,   &
+                  0:nz+1) )
+    allocate(Ap%st(1-halo_size:nlocal+halo_size,   &
+                   1-halo_size:nlocal+halo_size,   &
+                   0:nz+1) )
+    r%st = 0.0_rl
+    z%st = 0.0_rl
+    p%st = 0.0_rl
+    Ap%st = 0.0_rl
+    endif
+
+
+    ! Initialise
+    ! r <- b - A.u
+    call calculate_residual_mnh(level,m,b,u,r)
+    ! z <- M^{-1} r
+    if (cg_param%n_prec > 0) then
+      call smooth_mnh(level,m,cg_param%n_prec,DIRECTION_FORWARD,r,z)
+      call smooth_mnh(level,m,cg_param%n_prec,DIRECTION_BACKWARD,r,z)
+    else
+      if (LUseO) call dcopy(n_lin,r%s,1,z%s,1)
+      if (LUseT) call dcopy(n_lin,r%st,1,z%st,1)
+    end if
+    ! p <- z
+    if (LUseO) call dcopy(n_lin,z%s,1,p%s,1)
+    if (LUseT) call dcopy(n_lin,z%st,1,p%st,1)
+    ! rz_old = <r,z>
+    call scalarprod_mnh(m,r,z,rz_old)
+    ! res0 <- ||r||
+    call scalarprod_mnh(m,r,r,res0)
+    res0 = dsqrt(res0)
+    if (cg_param%verbose > 0) then
+      if (i_am_master_mpi) then
+        write(STDOUT,'("    *** CG Solver ( ",I10," dof ) ***")') n_lin
+        write(STDOUT,'("    <CG> Initial residual ||r_0|| = ",E12.6)') res0
+      end if
+    endif
+    if (res0 > tolerance) then
+      do i=1,cg_param%maxiter
+        ! Ap <- A.p
+        call haloswap_mnh(level,m,p)
+        call apply_mnh(p,Ap)
+        ! alpha <- res_old / <p,A.p>
+        call scalarprod_mnh(m,p,Ap,pAp)
+        alpha = rz_old/pAp
+        ! x <- x + alpha*p
+        if (LUseO) call daxpy(n_lin,alpha,p%s,1,u%s,1)
+        if (LUseT) call daxpy(n_lin,alpha,p%st,1,u%st,1)
+        ! r <- r - alpha*A.p
+        if (LUseO) call daxpy(n_lin,-alpha,Ap%s,1,r%s,1)
+        if (LUseT) call daxpy(n_lin,-alpha,Ap%st,1,r%st,1)
+        call scalarprod_mnh(m,r,r,res)
+        res = dsqrt(res)
+        if (cg_param%verbose > 1) then
+          if (i_am_master_mpi) then
+            write(STDOUT,'("    <CG> Iteration ",I6," ||r|| = ",E12.6)') &
+              i, res
+          end if
+        end if
+        if ( (res/res0 < cg_param%resreduction) .or. &
+             (res < tolerance ) ) then
+          solver_converged = .true.
+          exit
+        end if
+        ! z <- M^{-1} r
+        if (LUseO) z%s = 0.0_rl
+        if (LUseT) z%st = 0.0_rl
+        if (cg_param%n_prec > 0) then
+          call smooth_mnh(level,m,cg_param%n_prec,DIRECTION_FORWARD,r,z)
+          call smooth_mnh(level,m,cg_param%n_prec,DIRECTION_BACKWARD,r,z)
+        else
+          if (LUseO) call dcopy(n_lin,r%s,1,z%s,1)
+          if (LUseT) call dcopy(n_lin,r%st,1,z%st,1)
+        end if
+        call scalarprod_mnh(m,r,z,rz)
+        ! p <- res/res_old*p
+        if (LUseO) call dscal(n_lin,rz/rz_old,p%s,1)
+        if (LUseT) call dscal(n_lin,rz/rz_old,p%st,1)
+        ! p <- p + z
+        if (LUseO) call daxpy(n_lin,1.0_rl,z%s,1,p%s,1)
+        if (LUseT) call daxpy(n_lin,1.0_rl,z%st,1,p%st,1)
+        rz_old = rz
+      end do
+    else
+      res = res0
+      solver_converged = .true.
+    end if
+    if (cg_param%verbose>0) then
+      if (solver_converged) then
+        if (i_am_master_mpi) then
+          write(STDOUT,'("    <CG> Final residual    ||r|| = ",E12.6)') res
+          write(STDOUT,'("    <CG> CG solver converged after ",I6," iterations rho_avg = ",F10.6)') i, (res/res0)**(1.0_rl/i)
+        end if
+      else
+        call warning("    <CG> Solver did not converge")
+      endif
+    end if
+
+    if (LUseO) then
+    deallocate(r%s)
+    deallocate(z%s)
+    deallocate(p%s)
+    deallocate(Ap%s)
+    end if
+
+    if (LUseT) then
+    deallocate(r%st)
+    deallocate(z%st)
+    deallocate(p%st)
+    deallocate(Ap%st)
+    end if
+
+  end subroutine cg_solve_mnh
+!==================================================================
+! Solve A.u = b.
+!==================================================================
+  subroutine cg_solve(level,m,b,u)
+    implicit none
+    integer, intent(in)           :: level
+    integer, intent(in)           :: m
+    type(scalar3d), intent(in)    :: b    ! RHS vector
+    type(scalar3d), intent(inout) :: u    ! solution vector
+    type(scalar3d)                :: p    ! } Auxilliary vectors
+    type(scalar3d)                :: r    ! } Auxilliary vectors
+    type(scalar3d)                :: Ap   ! }
+    type(scalar3d)                :: z    ! }
+    integer                       :: n_lin
+    real(kind=rl)                 :: res0, rz, rz_old, res, alpha
+    integer :: i
+    logical :: solver_converged = .false.
+    integer :: n, nz, nlocal, halo_size
+    real(kind=rl) :: pAp
+
+    ! Initialise auxiliary fields
+    p%grid_param = u%grid_param
+    p%ix_min = u%ix_min
+    p%ix_max = u%ix_max
+    p%iy_min = u%iy_min
+    p%iy_max = u%iy_max
+    p%icompx_min = u%icompx_min
+    p%icompx_max = u%icompx_max
+    p%icompy_min = u%icompy_min
+    p%icompy_max = u%icompy_max
+    p%halo_size = u%halo_size
+
+    r%grid_param = u%grid_param
+    r%ix_min = u%ix_min
+    r%ix_max = u%ix_max
+    r%iy_min = u%iy_min
+    r%iy_max = u%iy_max
+    r%icompx_min = u%icompx_min
+    r%icompx_max = u%icompx_max
+    r%icompy_min = u%icompy_min
+    r%icompy_max = u%icompy_max
+    r%halo_size = u%halo_size
+
+    z%grid_param = u%grid_param
+    z%ix_min = u%ix_min
+    z%ix_max = u%ix_max
+    z%iy_min = u%iy_min
+    z%iy_max = u%iy_max
+    z%icompx_min = u%icompx_min
+    z%icompx_max = u%icompx_max
+    z%icompy_min = u%icompy_min
+    z%icompy_max = u%icompy_max
+    z%halo_size = u%halo_size
+
+    Ap%grid_param = u%grid_param
+    Ap%ix_min = u%ix_min
+    Ap%ix_max = u%ix_max
+    Ap%iy_min = u%iy_min
+    Ap%iy_max = u%iy_max
+    Ap%icompx_min = u%icompx_min
+    Ap%icompx_max = u%icompx_max
+    Ap%icompy_min = u%icompy_min
+    Ap%icompy_max = u%icompy_max
+    Ap%halo_size = u%halo_size
+
+    n = u%ix_max-u%ix_min+1
+    nz = u%grid_param%nz
+
+    nlocal = u%ix_max - u%ix_min + 1
+    halo_size = u%halo_size
+
+    n_lin = (nlocal+2*halo_size)**2 * (nz+2)
+
+    if (LUseO) then
+    allocate(r%s(0:nz+1,                     &
+             1-halo_size:nlocal+halo_size,   &
+             1-halo_size:nlocal+halo_size) )
+    allocate(z%s(0:nz+1,                     &
+             1-halo_size:nlocal+halo_size,   &
+             1-halo_size:nlocal+halo_size) )
+    allocate(p%s(0:nz+1,                     &
+             1-halo_size:nlocal+halo_size,   &
+             1-halo_size:nlocal+halo_size) )
+    allocate(Ap%s(0:nz+1,                    &
+             1-halo_size:nlocal+halo_size,   &
+             1-halo_size:nlocal+halo_size) )
+    r%s = 0.0_rl
+    z%s = 0.0_rl
+    p%s = 0.0_rl
+    Ap%s = 0.0_rl
+    end if
+
+    if (LUseT) then
+    allocate(r%st(1-halo_size:nlocal+halo_size,   &
+                  1-halo_size:nlocal+halo_size,   &
+                  0:nz+1) )
+    allocate(z%st(1-halo_size:nlocal+halo_size,   &
+                  1-halo_size:nlocal+halo_size,   &
+                  0:nz+1) )
+    allocate(p%st(1-halo_size:nlocal+halo_size,   &
+                  1-halo_size:nlocal+halo_size,   &
+                  0:nz+1) )
+    allocate(Ap%st(1-halo_size:nlocal+halo_size,  &
+                   1-halo_size:nlocal+halo_size,  &
+                   0:nz+1) )
+    r%st = 0.0_rl
+    z%st = 0.0_rl
+    p%st = 0.0_rl
+    Ap%st = 0.0_rl
+    end if
+
+    ! Initialise
+    ! r <- b - A.u
+    call calculate_residual(level,m,b,u,r)
+    ! z <- M^{-1} r
+    if (cg_param%n_prec > 0) then
+      call smooth(level,m,cg_param%n_prec,DIRECTION_FORWARD,r,z)
+      call smooth(level,m,cg_param%n_prec,DIRECTION_BACKWARD,r,z)
+    else
+      if (LUseO) call dcopy(n_lin,r%s,1,z%s,1)
+      if (LUseT) call dcopy(n_lin,r%st,1,z%st,1)
+    end if
+    ! p <- z
+    if (LUseO) call dcopy(n_lin,z%s,1,p%s,1)
+    if (LUseT) call dcopy(n_lin,z%st,1,p%st,1)
+    ! rz_old = <r,z>
+    call scalarprod(m,r,z,rz_old)
+    ! res0 <- ||r||
+    call scalarprod(m,r,r,res0)
+    res0 = dsqrt(res0)
+    if (cg_param%verbose > 0) then
+      if (i_am_master_mpi) then
+        write(STDOUT,'("    *** CG Solver ( ",I10," dof ) ***")') n_lin
+        write(STDOUT,'("    <CG> Initial residual ||r_0|| = ",E12.6)') res0
+      end if
+    endif
+    if (res0 > tolerance) then
+      do i=1,cg_param%maxiter
+        ! Ap <- A.p
+        call haloswap(level,m,p)
+        call apply(p,Ap)
+        ! alpha <- res_old / <p,A.p>
+        call scalarprod(m,p,Ap,pAp)
+        alpha = rz_old/pAp
+        ! x <- x + alpha*p
+        if (LUseO) call daxpy(n_lin,alpha,p%s,1,u%s,1)
+        if (LUseT) call daxpy(n_lin,alpha,p%st,1,u%st,1)
+        ! r <- r - alpha*A.p
+        if (LUseO) call daxpy(n_lin,-alpha,Ap%s,1,r%s,1)
+        if (LUseT) call daxpy(n_lin,-alpha,Ap%st,1,r%st,1)
+        call scalarprod(m,r,r,res)
+        res = dsqrt(res)
+        if (cg_param%verbose > 1) then
+          if (i_am_master_mpi) then
+            write(STDOUT,'("    <CG> Iteration ",I6," ||r|| = ",E12.6)') &
+              i, res
+          end if
+        end if
+        if ( (res/res0 < cg_param%resreduction) .or. &
+             (res < tolerance ) ) then
+          solver_converged = .true.
+          exit
+        end if
+        ! z <- M^{-1} r
+        if (LUseO) z%s = 0.0_rl
+        if (LUseT) z%st = 0.0_rl
+        if (cg_param%n_prec > 0) then
+          call smooth(level,m,cg_param%n_prec,DIRECTION_FORWARD,r,z)
+          call smooth(level,m,cg_param%n_prec,DIRECTION_BACKWARD,r,z)
+        else
+          if (LUseO) call dcopy(n_lin,r%s,1,z%s,1)
+          if (LUseT) call dcopy(n_lin,r%st,1,z%st,1)
+        end if
+        call scalarprod(m,r,z,rz)
+        ! p <- res/res_old*p
+        if (LUseO) call dscal(n_lin,rz/rz_old,p%s,1)
+        if (LUseT) call dscal(n_lin,rz/rz_old,p%st,1)
+        ! p <- p + z
+        if (LUseO) call daxpy(n_lin,1.0_rl,z%s,1,p%s,1)
+        if (LUseT) call daxpy(n_lin,1.0_rl,z%st,1,p%st,1)
+        rz_old = rz
+      end do
+    else
+      res = res0
+      solver_converged = .true.
+    end if
+    if (cg_param%verbose>0) then
+      if (solver_converged) then
+        if (i_am_master_mpi) then
+          write(STDOUT,'("    <CG> Final residual    ||r|| = ",E12.6)') res
+          write(STDOUT,'("    <CG> CG solver converged after ",I6," iterations rho_avg = ",F10.6)') i, (res/res0)**(1.0_rl/i)
+        end if
+      else
+        call warning("    <CG> Solver did not converge")
+      endif
+    end if
+
+    if (LUseO) then
+    deallocate(r%s)
+    deallocate(z%s)
+    deallocate(p%s)
+    deallocate(Ap%s)
+    end if
+    if (LUseT) then
+    deallocate(r%st)
+    deallocate(z%st)
+    deallocate(p%st)
+    deallocate(Ap%st)
+    end if
+  end subroutine cg_solve
+
+end module conjugategradient
+
diff --git a/src/ZSOLVER/tensorproductmultigrid_Source/datatypes.f90 b/src/ZSOLVER/tensorproductmultigrid_Source/datatypes.f90
new file mode 100644
index 0000000000000000000000000000000000000000..7f7c6eab07766a2a9978a089b07262f4e0b405f6
--- /dev/null
+++ b/src/ZSOLVER/tensorproductmultigrid_Source/datatypes.f90
@@ -0,0 +1,507 @@
+!=== COPYRIGHT AND LICENSE STATEMENT ===
+!
+!  This file is part of the TensorProductMultigrid code.
+!  
+!  (c) The copyright relating to this work is owned jointly by the
+!  Crown, Met Office and NERC [2014]. However, it has been created
+!  with the help of the GungHo Consortium, whose members are identified
+!  at https://puma.nerc.ac.uk/trac/GungHo/wiki .
+!  
+!  Main Developer: Eike Mueller
+!  
+!  TensorProductMultigrid is free software: you can redistribute it and/or
+!  modify it under the terms of the GNU Lesser General Public License as
+!  published by the Free Software Foundation, either version 3 of the
+!  License, or (at your option) any later version.
+!  
+!  TensorProductMultigrid is distributed in the hope that it will be useful,
+!  but WITHOUT ANY WARRANTY; without even the implied warranty of
+!  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+!  GNU Lesser General Public License for more details.
+!  
+!  You should have received a copy of the GNU Lesser General Public License
+!  along with TensorProductMultigrid (see files COPYING and COPYING.LESSER).
+!  If not, see <http://www.gnu.org/licenses/>.
+!
+!=== COPYRIGHT AND LICENSE STATEMENT ===
+
+
+!==================================================================
+!
+!   Grid data types for three dimensional cell centred grids.
+!   We always assume that the number of gridcells and size in
+!   the x- and y- direction is identical.
+!
+!    Eike Mueller, University of Bath, Feb 2012
+!
+!==================================================================
+
+
+module datatypes
+
+#ifndef MNH
+  use mpi
+#else
+  use modd_mpif
+#endif  
+  use parameters
+  use messages
+
+  implicit none
+
+! Vertical boundary conditions
+  integer, parameter :: VERTBC_DIRICHLET = 1
+  integer, parameter :: VERTBC_NEUMANN = 2
+
+! Parameters of three dimensional grid
+  type grid_parameters
+    integer :: n         ! Total number of grid cells in horizontal direction
+    integer :: nz        ! Total number of grid cells in vertical direction
+    real(kind=rl) :: L   ! Global extent of grid in horizontal direction
+    real(kind=rl) :: H   ! Global extent of grid in vertical direction
+    integer :: vertbc    ! Vertical boundary condition (see VERTBC_DIRICHLET
+                         ! and VERTBC_NEUMANN)
+    logical :: graded    ! Is the vertical grid graded?
+  end type grid_parameters
+
+! Three dimensional scalar field s(z,y,x)
+  type scalar3d
+    integer :: ix_min     ! } (Inclusive) range of locally owned cells
+    integer :: ix_max     ! } in the x-direction
+    integer :: iy_min     ! } (these ranges DO NOT include halo cells)
+    integer :: iy_max     ! } in the y-direction
+    integer :: icompx_min ! } (Inclusive) ranges of computational cells,
+    integer :: icompx_max ! } in local coords. All cells in these ranges
+    integer :: icompy_min ! } are included in calculations, e.g. in the
+    integer :: icompy_max ! } smoother. This allows duplicating operations
+                          ! } on part of the halo for RB Gauss Seidel
+    integer :: halo_size  ! Size of halos
+    logical :: isactive   ! Is this field active, i.e. used on one of the
+                          ! active processes on coarser grids?
+    real(kind=rl),allocatable :: s(:,:,:)
+    real(kind=rl),pointer :: st(:,:,:)
+    type(grid_parameters) :: grid_param
+  end type scalar3d
+
+public::VERTBC_DIRICHLET
+public::VERTBC_NEUMANN
+public::scalar3d
+public::grid_parameters
+public::L2norm_mnh
+public::L2norm
+public::daxpy_scalar3d
+public::save_scalar3d
+public::create_scalar3d
+public::volscale_scalar3d_mnh
+public::volscale_scalar3d
+public::destroy_scalar3d
+public::volume_of_element
+public::r_grid
+
+private
+
+  ! Vertical grid, this array of length n_z+1 stores the
+  ! vertices of the grid in the vertical direction
+  real(kind=rl), allocatable :: r_grid(:)
+
+  contains
+
+!==================================================================
+! volume of element on cubed sphere grid
+! NB: ix,iy are global indices
+!==================================================================
+  real(kind=rl) function volume_of_element(ix,iy,grid_param)
+    implicit none
+    integer, intent(in) :: ix
+    integer, intent(in) :: iy
+    type(grid_parameters), intent(in) :: grid_param
+    real(kind=rl) :: h
+    real(kind=rl) :: rho_i, sigma_j
+    h = 2.0_rl/grid_param%n
+    rho_i = 2.0_rl*(ix-0.5_rl)/grid_param%n-1.0_rl
+    sigma_j = 2.0_rl*(iy-0.5_rl)/grid_param%n-1.0_rl
+    volume_of_element = (1.0_rl+rho_i**2+sigma_j**2)**(-1.5_rl)*h**2
+  end function volume_of_element
+
+!==================================================================
+! Create scalar3d field on fine grid and set to zero
+!==================================================================
+  subroutine create_scalar3d(comm_horiz,grid_param, halo_size, phi)
+    implicit none
+
+    integer                             :: comm_horiz  ! Horizontal communicator
+    type(grid_parameters), intent(in)   :: grid_param  ! Grid parameters
+    integer, intent(in)                 :: halo_size   ! Halo size
+    type(scalar3d), intent(inout)       :: phi         ! Field to create
+    integer                             :: nproc       ! Number of processes
+    integer                             :: rank, ierr  ! rank and MPI error
+    integer, dimension(2)               :: p_horiz     ! position in 2d
+                                                       ! processor grid
+    integer                             :: nlocal      ! Local number of
+                                                       ! cells in horizontal
+                                                       ! direction
+    integer, parameter                  :: dim_horiz = 2 ! horiz. dimension
+
+    phi%grid_param = grid_param
+    call mpi_comm_size(comm_horiz, nproc, ierr)
+    nlocal = grid_param%n/sqrt(1.0*nproc)
+
+    ! Work out position in 2d processor grid
+    call mpi_comm_rank(comm_horiz, rank, ierr)
+    call mpi_cart_coords(comm_horiz,rank,dim_horiz,p_horiz,ierr)
+    ! Set local data ranges
+    ! NB: p_horiz stores (py,px) in that order (see comment in
+    ! communication module)
+    phi%iy_min = p_horiz(1)*nlocal + 1
+    phi%iy_max = (p_horiz(1)+1)*nlocal
+    phi%ix_min = p_horiz(2)*nlocal + 1
+    phi%ix_max = (p_horiz(2)+1)*nlocal
+    ! Set computational ranges. Note that these are different at
+    ! the edges of the domain!
+    if (p_horiz(1) == 0) then
+      phi%icompy_min = 1
+    else
+      phi%icompy_min = 1 - (halo_size - 1)
+    end if
+    if (p_horiz(1) == floor(sqrt(1.0_rl*nproc))-1) then
+      phi%icompy_max = nlocal
+    else
+      phi%icompy_max = nlocal + (halo_size - 1)
+    end if
+    if (p_horiz(2) == 0) then
+      phi%icompx_min = 1
+    else
+      phi%icompx_min = 1 - (halo_size - 1)
+    end if
+    if (p_horiz(2) == floor(sqrt(1.0_rl*nproc))-1) then
+      phi%icompx_max = nlocal
+    else
+      phi%icompx_max = nlocal + (halo_size - 1)
+    end if
+    ! Set halo size
+    phi%halo_size = halo_size
+    ! Set field to active
+    phi%isactive = .true.
+    ! Allocate memory
+    if (LUseO) then
+    allocate(phi%s(0:grid_param%nz+1,            &
+                   1-halo_size:nlocal+halo_size, &
+                   1-halo_size:nlocal+halo_size))
+    phi%s(:,:,:) = 0.0_rl
+    end if
+    if (LUseT) then
+    allocate(phi%st(1-halo_size:nlocal+halo_size, &
+                    1-halo_size:nlocal+halo_size, &
+                    0:grid_param%nz+1))
+    phi%st(:,:,:) = 0.0_rl
+    end if
+
+  end subroutine create_scalar3d
+
+!==================================================================
+! Destroy scalar3d field on fine grid
+!==================================================================
+  subroutine destroy_scalar3d(phi)
+    implicit none
+    type(scalar3d), intent(inout) :: phi
+
+    if (LUseO) deallocate(phi%s)
+    if (LUseT) deallocate(phi%st)
+
+  end subroutine destroy_scalar3d
+
+!==================================================================
+! Scale fields with volume of element
+! Either multiply with volume factor |T| v_k (power = 1)
+! or divide by it (power = -1)
+!==================================================================
+  subroutine volscale_scalar3d_mnh(phi,power)
+    implicit none
+    type(scalar3d), intent(inout) :: phi
+    integer, intent(in) :: power
+    integer :: ix, iy, iz
+    integer :: ierr
+    integer :: nlocalx, nlocaly, nz
+    real(kind=rl) :: vol_h, vol_r, h, tmp
+
+    if (.not. ( ( power .eq. 1) .or. (power .eq. -1) ) ) then
+      call fatalerror("power has to be -1 or 1 when volume-scaling fields")
+    end if
+
+    if (phi%isactive) then
+
+    nlocalx = phi%ix_max-phi%ix_min+1
+    nlocaly = phi%iy_max-phi%iy_min+1
+    nz      = phi%grid_param%nz
+
+    h = phi%grid_param%L/phi%grid_param%n
+    vol_h = h**2
+    vol_r = 1.0_rl ! r_grid(iz+1)-r_grid(iz)
+    if (power == 1) then
+       tmp = vol_h*vol_r
+    else
+       tmp = 1.0_rl/(vol_h*vol_r)
+    end if
+  
+    if (LUseO) phi%s (1:nz,1:nlocaly,1:nlocalx) = tmp*phi%s (1:nz,1:nlocaly,1:nlocalx)
+    if (LUseT) phi%st(1:nlocalx,1:nlocaly,1:nz) = tmp*phi%st(1:nlocalx,1:nlocaly,1:nz)
+
+    end if
+
+  end subroutine volscale_scalar3d_mnh
+
+!==================================================================
+! Scale fields with volume of element
+! Either multiply with volume factor |T| v_k (power = 1)
+! or divide by it (power = -1)
+!==================================================================
+  subroutine volscale_scalar3d(phi,power)
+    implicit none
+    type(scalar3d), intent(inout) :: phi
+    integer, intent(in) :: power
+    integer :: ix, iy, iz
+    integer :: ierr
+    integer :: nlocalx, nlocaly
+    real(kind=rl) :: vol_h, vol_r, h, tmp
+
+    if (.not. ( ( power .eq. 1) .or. (power .eq. -1) ) ) then
+      call fatalerror("power has to be -1 or 1 when volume-scaling fields")
+    end if
+
+    nlocalx = phi%ix_max-phi%ix_min+1
+    nlocaly = phi%iy_max-phi%iy_min+1
+
+    if (phi%isactive) then
+      do ix=1,nlocalx
+        do iy=1,nlocaly
+#ifdef CARTESIANGEOMETRY
+          h = phi%grid_param%L/phi%grid_param%n
+          vol_h = h**2
+#else
+          vol_h = volume_of_element(ix+(phi%ix_min-1), &
+                                    iy+(phi%iy_min-1), &
+                                    phi%grid_param)
+#endif
+          do iz=1,phi%grid_param%nz
+#ifdef CARTESIANGEOMETRY
+            vol_r = r_grid(iz+1)-r_grid(iz)
+#else
+            vol_r = (r_grid(iz+1)**3 - r_grid(iz)**3)/3.0_rl
+#endif
+            if (power == 1) then
+              tmp = vol_h*vol_r
+            else
+              tmp = 1.0_rl/(vol_h*vol_r)
+            end if
+             if (LUseO) phi%s(iz,iy,ix) = tmp*phi%s(iz,iy,ix)
+             if (LUseT) phi%st(ix,iy,iz) = tmp*phi%st(ix,iy,iz)
+          end do
+        end do
+      end do
+    end if
+
+  end subroutine volscale_scalar3d
+
+!==================================================================
+! Calculate L2 norm
+! If phi_is_volumeintegral is .true. then phi is interpreted
+! as the volume integral in a cell, otherwise it is interpreted as the
+! average value in a cell.
+!==================================================================
+  real(kind=rl) function l2norm_mnh(phi,phi_is_volumeintegral)
+    implicit none
+    type(scalar3d), intent(in) :: phi
+    logical, optional :: phi_is_volumeintegral
+    !local var
+    integer :: ix, iy, iz
+    real(kind=rl) :: tmp, global_tmp
+    real(kind=rl) :: tmpt, global_tmpt
+    integer :: ierr
+    integer :: nlocalx, nlocaly, nz
+    real(kind=rl) :: vol_h, vol_r, h
+    logical :: divide_by_volume
+    real(kind=rl) :: volume_factor
+
+    real , dimension(:,:,:) , pointer :: zphi_st
+
+    nlocalx = phi%ix_max-phi%ix_min+1
+    nlocaly = phi%iy_max-phi%iy_min+1
+    nz      = phi%grid_param%nz
+
+    tmp = 0.0_rl
+    tmpt = 0.0_rl
+    if (phi%isactive) then
+
+       if (LUseO) then
+          do ix=1,nlocalx
+             do iy=1,nlocaly
+                do iz=1,nz
+                   tmp = tmp + phi%s(iz,iy,ix)**2 ! * volume_factor
+                end do
+             end do
+          end do
+       end if
+       
+       if (LUseT) then
+          zphi_st => phi%st
+          !$acc kernels loop dtype(nvidia) collapse(3)
+          do iz=1,nz
+             do iy=1,nlocaly
+                do ix=1,nlocalx
+                   tmpt = tmpt + zphi_st(ix,iy,iz)**2 ! * volume_factor
+                end do
+             end do
+          end do
+          !$acc end kernels
+ 
+       end if
+    end if
+    
+    if (LUseO) then
+       call mpi_allreduce(tmp,global_tmp, 1, &
+            MPI_DOUBLE_PRECISION,MPI_SUM,MPI_COMM_WORLD,ierr)   
+       global_tmp = dsqrt(global_tmp)
+    endif
+    if (LUseT) then
+       call mpi_allreduce(tmpt,global_tmpt, 1, &
+            MPI_DOUBLE_PRECISION,MPI_SUM,MPI_COMM_WORLD,ierr)
+       global_tmpt = dsqrt(global_tmpt)
+    end if
+    if (LUseO) then
+       l2norm_mnh = global_tmp
+    else
+       l2norm_mnh = global_tmpt
+    endif
+
+  end function l2norm_mnh
+!----------------------------------------------------------------------------
+  real(kind=rl) function l2norm(phi,phi_is_volumeintegral)
+    implicit none
+    type(scalar3d), intent(in) :: phi
+    logical, optional :: phi_is_volumeintegral
+    integer :: ix, iy, iz
+    real(kind=rl) :: tmp, global_tmp
+    integer :: ierr
+    integer :: nlocalx, nlocaly
+    real(kind=rl) :: vol_h, vol_r, h
+    logical :: divide_by_volume
+    real(kind=rl) :: volume_factor
+    if (present(phi_is_volumeintegral)) then
+      divide_by_volume = phi_is_volumeintegral
+    else
+      divide_by_volume = .false.
+    end if
+
+    nlocalx = phi%ix_max-phi%ix_min+1
+    nlocaly = phi%iy_max-phi%iy_min+1
+
+    tmp = 0.0_rl
+    if (phi%isactive) then
+      do ix=1,nlocalx
+        do iy=1,nlocaly
+#ifdef CARTESIANGEOMETRY
+          h = phi%grid_param%L/phi%grid_param%n
+          vol_h = h**2
+#else
+          vol_h = volume_of_element(ix+(phi%ix_min-1), &
+                                    iy+(phi%iy_min-1), &
+                                    phi%grid_param)
+#endif
+          do iz=1,phi%grid_param%nz
+#ifdef CARTESIANGEOMETRY
+            vol_r = r_grid(iz+1)-r_grid(iz)
+#else
+            vol_r = (r_grid(iz+1)**3 - r_grid(iz)**3)/3.0_rl
+#endif
+            if (divide_by_volume) then
+              volume_factor = 1.0_rl/(vol_h*vol_r)
+            else
+              volume_factor = vol_h*vol_r
+            end if
+            tmp = tmp + volume_factor*phi%s(iz,iy,ix)**2
+          end do
+        end do
+      end do
+    end if
+
+    call mpi_allreduce(tmp,global_tmp, 1, &
+                       MPI_DOUBLE_PRECISION,MPI_SUM,MPI_COMM_WORLD,ierr)
+    l2norm = dsqrt(global_tmp)
+  end function l2norm
+
+!==================================================================
+! calculate phi <- phi + alpha*dphi
+!==================================================================
+  subroutine daxpy_scalar3d(alpha,dphi,phi)
+    implicit none
+    real(kind=rl), intent(in) :: alpha
+    type(scalar3d), intent(in) :: dphi
+    type(scalar3d), intent(inout) :: phi
+    integer :: nlin
+    integer :: nlocalx, nlocaly
+
+    nlocalx = phi%ix_max-phi%ix_min+1
+    nlocaly = phi%iy_max-phi%iy_min+1
+    nlin = (nlocalx+2*phi%halo_size) &
+         * (nlocaly+2*phi%halo_size) &
+         * (phi%grid_param%nz+2)
+
+    if (LUseO) call daxpy(nlin,alpha,dphi%s,1,phi%s,1)
+    if (LUseT) call daxpy(nlin,alpha,dphi%st,1,phi%st,1)
+    
+
+  end subroutine daxpy_scalar3d
+
+!==================================================================
+! Save scalar field to file
+!==================================================================
+  subroutine save_scalar3d(comm_horiz,phi,filename)
+    implicit none
+    integer, intent(in) :: comm_horiz
+    type(scalar3d), intent(in) :: phi
+    character(*), intent(in)   :: filename
+    integer :: file_id = 100
+    integer :: ix,iy,iz
+    integer :: nlocal
+    integer :: rank, nproc, ierr
+    character(len=21) :: s
+
+    nlocal = phi%ix_max-phi%ix_min+1
+
+    ! Get number of processes and rank
+    call mpi_comm_size(comm_horiz, nproc, ierr)
+    call mpi_comm_rank(comm_horiz, rank, ierr)
+
+    write(s,'(I10.10,"_",I10.10)') nproc, rank
+
+    open(unit=file_id,file=trim(filename)//"_"//trim(s)//".dat")
+    write(file_id,*) "# 3d scalar data file"
+    write(file_id,*) "# ==================="
+    write(file_id,*) "# Data is written as s(iz,iy,ix) "
+    write(file_id,*) "# with the leftmost index running fastest"
+    write(file_id,'(" n  = ",I8)') phi%grid_param%n
+    write(file_id,'(" nz = ",I8)') phi%grid_param%nz
+    write(file_id,'(" L  = ",F20.10)') phi%grid_param%L
+    write(file_id,'(" H  = ",F20.10)') phi%grid_param%H
+    write(file_id,'(" ix_min  = ",I10)') phi%ix_min
+    write(file_id,'(" ix_max  = ",I10)') phi%ix_max
+    write(file_id,'(" iy_min  = ",I10)') phi%iy_min
+    write(file_id,'(" iy_max  = ",I10)') phi%iy_max
+    write(file_id,'(" icompx_min  = ",I10)') phi%icompx_min
+    write(file_id,'(" icompx_max  = ",I10)') phi%icompx_max
+    write(file_id,'(" icompy_min  = ",I10)') phi%icompy_min
+    write(file_id,'(" icompy_max  = ",I10)') phi%icompy_max
+    write(file_id,'(" halosize    = ",I10)') phi%halo_size
+
+
+    do ix=1-phi%halo_size,nlocal+phi%halo_size
+      do iy=1-phi%halo_size,nlocal+phi%halo_size
+        do iz=0,phi%grid_param%nz+1
+          write(file_id,'(E24.15)') phi%s(iz,iy,ix)
+        end do
+      end do
+    end do
+    close(file_id)
+  end subroutine save_scalar3d
+
+end module datatypes
diff --git a/src/ZSOLVER/tensorproductmultigrid_Source/dblas.f90 b/src/ZSOLVER/tensorproductmultigrid_Source/dblas.f90
new file mode 100644
index 0000000000000000000000000000000000000000..48d5dcdce4f328566fd6e968cd8ba21311c5dd30
--- /dev/null
+++ b/src/ZSOLVER/tensorproductmultigrid_Source/dblas.f90
@@ -0,0 +1,241 @@
+subroutine dcopy(n,sx,incx,sy,incy)
+!
+!     copies a vector, x, to a vector, y.
+!     uses unrolled loops for increments equal to 1.
+!     jack dongarra, linpack, 3/11/78.
+!     modified 12/3/93, array(1) declarations changed to array(*)
+!     modified  12/12/00 change name to avoid confusion with spline routine
+!
+      real sx(*),sy(*)
+      integer i,incx,incy,ix,iy,m,mp1,n
+!
+      if(n.le.0)return
+      if(incx.eq.1.and.incy.eq.1)go to 20
+!
+!        code for unequal increments or equal increments
+!          not equal to 1
+!
+      ix = 1
+      iy = 1
+      if(incx.lt.0)ix = (-n+1)*incx + 1
+      if(incy.lt.0)iy = (-n+1)*incy + 1
+      do 10 i = 1,n
+        sy(iy) = sx(ix)
+        ix = ix + incx
+        iy = iy + incy
+   10 continue
+      return
+!
+!        code for both increments equal to 1
+!
+!
+!        clean-up loop
+!
+   20 m = mod(n,7)
+      if( m .eq. 0 ) go to 40
+      do 30 i = 1,m
+        sy(i) = sx(i)
+   30 continue
+      if( n .lt. 7 ) return
+   40 mp1 = m + 1
+      !$acc kernels
+      do 50 i = mp1,n,7
+        sy(i) = sx(i)
+        sy(i + 1) = sx(i + 1)
+        sy(i + 2) = sx(i + 2)
+        sy(i + 3) = sx(i + 3)
+        sy(i + 4) = sx(i + 4)
+        sy(i + 5) = sx(i + 5)
+        sy(i + 6) = sx(i + 6)
+       50 continue
+      !$acc end kernels
+      return
+
+end subroutine dcopy
+
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+SUBROUTINE DAXPY( N, SA, SX, INCX, SY, INCY )
+
+!          Y = A*X + Y  (X, Y = VECTORS, A = SCALAR)
+
+!  --INPUT--
+!        N  NUMBER OF ELEMENTS IN INPUT VECTORS 'X' AND 'Y'
+!       SA  SINGLE PRECISION SCALAR MULTIPLIER 'A'
+!       SX  SING-PREC ARRAY CONTAINING VECTOR 'X'
+!     INCX  SPACING OF ELEMENTS OF VECTOR 'X' IN 'SX'
+!       SY  SING-PREC ARRAY CONTAINING VECTOR 'Y'
+!     INCY  SPACING OF ELEMENTS OF VECTOR 'Y' IN 'SY'
+
+! --OUTPUT--
+!       SY   FOR I = 0 TO N-1, OVERWRITE  SY(LY+I*INCY) WITH 
+!                 SA*SX(LX+I*INCX) + SY(LY+I*INCY), 
+!            WHERE LX = 1          IF INCX .GE. 0,
+!                     = (-INCX)*N  IF INCX .LT. 0
+!            AND LY IS DEFINED IN A SIMILAR WAY USING INCY.
+
+	REAL SX(*), SY(*), SA
+
+
+	IF( N.LE.0 .OR. SA.EQ.0.0 ) RETURN
+
+	IF ( INCX.EQ.INCY .AND. INCX.GT.1 )  THEN
+
+	    DO 10  I = 1, 1+(N-1)*INCX, INCX
+	       SY(I) = SY(I) + SA * SX(I)
+   10     CONTINUE
+
+	ELSE IF ( INCX.EQ.INCY .AND. INCX.EQ.1 )  THEN
+
+!                                        ** EQUAL, UNIT INCREMENTS
+	   M = MOD(N,4)
+	   IF( M .NE. 0 ) THEN
+!                            ** CLEAN-UP LOOP SO REMAINING VECTOR LENGTH
+!                            ** IS A MULTIPLE OF 4.
+	      DO 20  I = 1, M
+	        SY(I) = SY(I) + SA * SX(I)
+   20       CONTINUE
+	   ENDIF
+!                              ** UNROLL LOOP FOR SPEED
+    !$acc kernels
+	   DO 30  I = M+1, N, 4
+	      SY(I)   = SY(I)   + SA * SX(I)
+	      SY(I+1) = SY(I+1) + SA * SX(I+1)
+	      SY(I+2) = SY(I+2) + SA * SX(I+2)
+	      SY(I+3) = SY(I+3) + SA * SX(I+3)
+   30    CONTINUE
+   !$acc end kernels
+
+	ELSE
+!               ** NONEQUAL OR NONPOSITIVE INCREMENTS.
+	   IX = 1
+	   IY = 1
+	   IF( INCX.LT.0 )  IX = 1 + (N-1)*(-INCX)
+	   IF( INCY.LT.0 )  IY = 1 + (N-1)*(-INCY)
+	   DO 40  I = 1, N
+	      SY(IY) = SY(IY) + SA*SX(IX)
+	      IX = IX + INCX
+	      IY = IY + INCY
+   40    CONTINUE
+
+	ENDIF
+
+	RETURN
+END SUBROUTINE DAXPY
+
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+SUBROUTINE  DSCAL( N, SA, SX, INCX )
+
+!         CALCULATE  X = A*X  (X = VECTOR, A = SCALAR)
+
+!  --INPUT--  N  NUMBER OF ELEMENTS IN VECTOR
+!            SA  SINGLE PRECISION SCALE FACTOR
+!            SX  SING-PREC ARRAY, LENGTH 1+(N-1)*INCX, CONTAINING VECTOR
+!          INCX  SPACING OF VECTOR ELEMENTS IN 'SX'
+
+! --OUTPUT-- SX  REPLACE  SX(1+I*INCX)  WITH  SA * SX(1+I*INCX) 
+!                FOR I = 0 TO N-1
+
+	REAL SA, SX(*)
+
+
+	IF( N.LE.0 ) RETURN
+
+	IF( INCX.NE.1 ) THEN
+
+	    DO 10  I = 1, 1+(N-1)*INCX, INCX
+	       SX(I) = SA * SX(I)
+   10     CONTINUE
+
+	ELSE
+
+	   M = MOD(N,5)
+	   IF( M.NE.0 ) THEN
+!                           ** CLEAN-UP LOOP SO REMAINING VECTOR LENGTH
+!                           ** IS A MULTIPLE OF 5.
+	      DO 30  I = 1, M
+	         SX(I) = SA * SX(I)
+   30       CONTINUE
+	   ENDIF
+!                             ** UNROLL LOOP FOR SPEED
+	   DO 50  I = M+1, N, 5
+	      SX(I)   = SA * SX(I)
+	      SX(I+1) = SA * SX(I+1)
+	      SX(I+2) = SA * SX(I+2)
+	      SX(I+3) = SA * SX(I+3)
+	      SX(I+4) = SA * SX(I+4)
+   50    CONTINUE
+
+	ENDIF
+
+	RETURN
+END SUBROUTINE  DSCAL
+
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+FUNCTION  DDOT( N, SX, INCX, SY, INCY )
+!     ##############################
+
+!          S.P. DOT PRODUCT OF VECTORS  'X'  AND  'Y'
+
+!  --INPUT--
+!        N  NUMBER OF ELEMENTS IN INPUT VECTORS 'X' AND 'Y'
+!       SX  SING-PREC ARRAY CONTAINING VECTOR 'X'
+!     INCX  SPACING OF ELEMENTS OF VECTOR 'X' IN 'SX'
+!       SY  SING-PREC ARRAY CONTAINING VECTOR 'Y'
+!     INCY  SPACING OF ELEMENTS OF VECTOR 'Y' IN 'SY'
+
+! --OUTPUT--
+!     DDOT   SUM FOR I = 0 TO N-1 OF  SX(LX+I*INCX) * SY(LY+I*INCY),
+!            WHERE  LX = 1          IF INCX .GE. 0, 
+!                      = (-INCX)*N  IF INCX .LT. 0,
+!            AND LY IS DEFINED IN A SIMILAR WAY USING INCY.
+
+        IMPLICIT NONE
+        INTEGER N,INCX,INCY
+	REAL SX(*), SY(*)
+        REAL DDOT
+        INTEGER I,M, IX, IY
+
+
+	DDOT = 0.0
+	IF( N.LE.0 )  RETURN
+
+	IF ( INCX.EQ.INCY .AND. INCX.GT.1 )  THEN
+
+	    DO 10  I = 1, 1+(N-1)*INCX, INCX
+	       DDOT = DDOT + SX(I) * SY(I)
+   10     CONTINUE
+
+	ELSE IF ( INCX.EQ.INCY .AND. INCX.EQ.1 )  THEN
+
+!                                        ** EQUAL, UNIT INCREMENTS
+	   M = MOD(N,5)
+	   IF( M .NE. 0 ) THEN
+!                            ** CLEAN-UP LOOP SO REMAINING VECTOR LENGTH
+!                            ** IS A MULTIPLE OF 4.
+	      DO 20  I = 1, M
+	         DDOT = DDOT + SX(I) * SY(I)
+   20       CONTINUE
+	   ENDIF
+!                              ** UNROLL LOOP FOR SPEED
+	   DO 30  I = M+1, N, 5
+	      DDOT = DDOT + SX(I)*SY(I)     + SX(I+1)*SY(I+1) &
+                          + SX(I+2)*SY(I+2) + SX(I+3)*SY(I+3) &
+                          + SX(I+4)*SY(I+4)
+   30    CONTINUE
+
+	ELSE
+!               ** NONEQUAL OR NONPOSITIVE INCREMENTS.
+	   IX = 1
+	   IY = 1
+	   IF( INCX.LT.0 )  IX = 1 + (N-1)*(-INCX)
+	   IF( INCY.LT.0 )  IY = 1 + (N-1)*(-INCY)
+	   DO 40  I = 1, N
+	      DDOT = DDOT + SX(IX) * SY(IY)
+	      IX = IX + INCX
+	      IY = IY + INCY
+   40    CONTINUE
+
+	ENDIF
+
+	RETURN
+END FUNCTION  DDOT
diff --git a/src/ZSOLVER/tensorproductmultigrid_Source/discretisation.f90 b/src/ZSOLVER/tensorproductmultigrid_Source/discretisation.f90
new file mode 100644
index 0000000000000000000000000000000000000000..9fa41dd2779aac88d52de2f14bc225b1351e1c0d
--- /dev/null
+++ b/src/ZSOLVER/tensorproductmultigrid_Source/discretisation.f90
@@ -0,0 +1,1959 @@
+!=== COPYRIGHT AND LICENSE STATEMENT ===
+!
+!  This file is part of the TensorProductMultigrid code.
+!  
+!  (c) The copyright relating to this work is owned jointly by the
+!  Crown, Met Office and NERC [2014]. However, it has been created
+!  with the help of the GungHo Consortium, whose members are identified
+!  at https://puma.nerc.ac.uk/trac/GungHo/wiki .
+!  
+!  Main Developer: Eike Mueller
+!  
+!  TensorProductMultigrid is free software: you can redistribute it and/or
+!  modify it under the terms of the GNU Lesser General Public License as
+!  published by the Free Software Foundation, either version 3 of the
+!  License, or (at your option) any later version.
+!  
+!  TensorProductMultigrid is distributed in the hope that it will be useful,
+!  but WITHOUT ANY WARRANTY; without even the implied warranty of
+!  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+!  GNU Lesser General Public License for more details.
+!  
+!  You should have received a copy of the GNU Lesser General Public License
+!  along with TensorProductMultigrid (see files COPYING and COPYING.LESSER).
+!  If not, see <http://www.gnu.org/licenses/>.
+!
+!=== COPYRIGHT AND LICENSE STATEMENT ===
+
+
+!==================================================================
+!
+!  Discretisation module of the model problem
+!
+!
+!  -omega2 * (d^2/dx^2 + d^2/dy^2 + lambda2 * d^2/dz^2 ) u
+!                                                + delta u = RHS
+!  [Cartesian]
+!
+!  or
+!
+!  -omega2 * (laplace_{2d} + lambda2/r^2 d/dr (r^2 d/dr)) u
+!                                                + delta u = RHS
+!  [Spherical]
+!
+!  We use a cell centered finite volume discretisation with
+!  The equation is discretised either in a unit cube or on 1/6th
+!  of a cubed sphere grid.
+!
+!  The vertical grid spacing is not necessarily uniform and can
+!  be chosen by specifying the vertical grid in a vector.
+!
+!  The following boundary conditions are used:
+!
+!  * Dirichlet in the horizontal
+!  * Neumann in the vertical
+!
+!  For delta = 0 the operator reduces to the Poisson operator.
+!
+!    Eike Mueller, University of Bath, Feb 2012
+!
+!==================================================================
+
+module discretisation
+
+  use parameters
+  use messages
+  use datatypes
+  use communication
+#ifndef MNH
+  use mpi
+#else
+  use modd_mpif
+#endif 
+
+  implicit none
+
+private
+
+  type model_parameters
+    real(kind=rl) :: omega2   ! omega^2
+    real(kind=rl) :: lambda2  ! lambda^2
+    real(kind=rl) :: delta    ! delta
+  end type model_parameters
+
+! --- Stencil ---
+!
+
+! Grid traversal direction in SOR
+  integer, parameter :: DIRECTION_FORWARD = 1
+  integer, parameter :: DIRECTION_BACKWARD = 2
+
+! Ordering in SOR
+  ! Lexicographic ordering
+  integer, parameter :: ORDERING_LEX = 1
+  ! Red-black ordering
+  integer, parameter :: ORDERING_RB = 2
+
+  type smoother_parameters
+    ! smoother
+    integer :: smoother
+    ! relaxation parameter
+    real(kind=rl) :: rho
+    ! ordering of degrees of freedom
+    integer :: ordering
+  end type smoother_parameters
+
+  ! Allowed smoothers
+  integer, parameter :: SMOOTHER_LINE_SOR = 3
+  integer, parameter :: SMOOTHER_LINE_SSOR = 4
+  integer, parameter :: SMOOTHER_LINE_JAC = 6
+
+  ! Number of levels
+  integer :: nlev
+
+  ! Grid parameters
+  type(grid_parameters) :: grid_param
+
+  ! Model parameters
+  type(model_parameters) :: model_param
+
+  ! Smoother parameters
+  type(smoother_parameters) :: smoother_param
+
+  ! Arrays for measuring the residual reduction
+  real(kind=rl), allocatable :: log_resreduction(:)
+  integer, allocatable :: nsmooth_total(:)
+
+  ! Data structure for storing the vertical discretisation
+  type vertical_coefficients
+    real(kind=rl), pointer :: a(:)
+    real(kind=rl), pointer :: b(:)
+    real(kind=rl), pointer :: c(:)
+    real(kind=rl), pointer :: d(:)
+  end type vertical_coefficients
+
+  ! Stoarge for vertical coefficients
+  type(vertical_coefficients) :: vert_coeff
+
+public::discretisation_initialise_mnh
+public::discretisation_initialise
+public::discretisation_finalise
+public::smooth_mnh
+public::smooth
+public::line_SOR
+public::line_SSOR
+public::line_jacobi_mnh
+public::line_jacobi
+public::calculate_residual_mnh
+public::calculate_residual
+public::apply_mnh
+public::apply
+public::model_parameters
+public::smoother_parameters
+public::volume_of_element
+public::SMOOTHER_LINE_SOR
+public::SMOOTHER_LINE_SSOR
+public::SMOOTHER_LINE_JAC
+public::DIRECTION_FORWARD
+public::DIRECTION_BACKWARD
+public::ORDERING_LEX
+public::ORDERING_RB
+
+contains
+
+!==================================================================
+! Initialise module
+!==================================================================
+ subroutine discretisation_initialise_mnh(grid_param_in, &
+                                       model_param_in, &
+                                       smoother_param_in, &
+                                       nlev_in, &
+                                       PA_K,PB_K,PC_K,PD_K)
+    implicit none
+    type(grid_parameters), intent(in)   :: grid_param_in
+    type(model_parameters), intent(in)   :: model_param_in
+    type(smoother_parameters), intent(in)   :: smoother_param_in
+    integer, intent(in) :: nlev_in
+    real(kind=rl) , optional , intent (in) :: PA_K(:),PB_K(:),PC_K(:),PD_K(:)
+
+    ! local var
+    integer :: k
+
+    grid_param = grid_param_in
+    model_param = model_param_in
+    smoother_param = smoother_param_in
+    nlev = nlev_in
+    allocate(log_resreduction(nlev))
+    allocate(nsmooth_total(nlev))
+    log_resreduction(:) = 0.0_rl
+    nsmooth_total(:) = 0
+    allocate(r_grid(grid_param%nz+1))
+    if (grid_param%graded) then
+      do k=1,grid_param%nz+1
+        r_grid(k) = grid_param%H*(1.0_rl*(k-1.0_rl)/grid_param%nz)**2
+      end do
+    else
+      do k=1,grid_param%nz+1
+        r_grid(k) = grid_param%H*(1.0_rl*(k-1.0_rl)/grid_param%nz)
+      end do
+    end if
+    ! Allocate arrays for vertical discretisation matrices
+    ! and calculate matrix entries
+    allocate(vert_coeff%a(grid_param%nz))
+    allocate(vert_coeff%b(grid_param%nz))
+    allocate(vert_coeff%c(grid_param%nz))
+    allocate(vert_coeff%d(grid_param%nz))
+    call construct_vertical_coeff_mnh(PA_K,PB_K,PC_K,PD_K)
+  end subroutine discretisation_initialise_mnh
+
+  subroutine discretisation_initialise(grid_param_in, &
+                                       model_param_in, &
+                                       smoother_param_in, &
+                                       nlev_in)
+    implicit none
+    type(grid_parameters), intent(in)   :: grid_param_in
+    type(model_parameters), intent(in)   :: model_param_in
+    type(smoother_parameters), intent(in)   :: smoother_param_in
+    integer, intent(in) :: nlev_in
+    integer :: k
+    grid_param = grid_param_in
+    model_param = model_param_in
+    smoother_param = smoother_param_in
+    nlev = nlev_in
+    allocate(log_resreduction(nlev))
+    allocate(nsmooth_total(nlev))
+    log_resreduction(:) = 0.0_rl
+    nsmooth_total(:) = 0
+    allocate(r_grid(grid_param%nz+1))
+    if (grid_param%graded) then
+      do k=1,grid_param%nz+1
+        r_grid(k) = grid_param%H*(1.0_rl*(k-1.0_rl)/grid_param%nz)**2
+      end do
+    else
+      do k=1,grid_param%nz+1
+        r_grid(k) = grid_param%H*(1.0_rl*(k-1.0_rl)/grid_param%nz)
+      end do
+    end if
+#ifdef CARTESIANGEOMETRY
+#else
+    r_grid(:) = 1.0_rl + r_grid(:)
+#endif
+    ! Allocate arrays for vertical discretisation matrices
+    ! and calculate matrix entries
+    allocate(vert_coeff%a(grid_param%nz))
+    allocate(vert_coeff%b(grid_param%nz))
+    allocate(vert_coeff%c(grid_param%nz))
+    allocate(vert_coeff%d(grid_param%nz))
+    call construct_vertical_coeff()
+  end subroutine discretisation_initialise
+
+!==================================================================
+! Finalise module
+!==================================================================
+  subroutine discretisation_finalise()
+    implicit none
+    integer :: level
+    real(kind=rl) :: rho_avg
+#ifdef MEASURESMOOTHINGRATE
+    if (i_am_master_mpi) then
+      write(STDOUT,'("Average smoothing rates:")')
+      do level=nlev,1,-1
+        if (nsmooth_total(level) > 0) then
+          rho_avg = exp(log_resreduction(level)/nsmooth_total(level))
+        else
+          rho_avg = 1.0_rl
+        end if
+        write(STDOUT,'("rho_{avg}(",I3,") = ",E10.4," ( ",I5," x )")') &
+          level, rho_avg, nsmooth_total(level)
+      end do
+    end if
+#endif
+    deallocate(log_resreduction)
+    deallocate(nsmooth_total)
+    deallocate(r_grid)
+    ! Deallocate storage for vertical discretisation matrices
+    deallocate(vert_coeff%a)
+    deallocate(vert_coeff%b)
+    deallocate(vert_coeff%c)
+    deallocate(vert_coeff%d)
+  end subroutine discretisation_finalise
+
+!==================================================================
+! Construct alpha_{i',j'} and |T_{ij}| needed for the
+! horizontal stencil
+! ( alpha_{i+1,j},
+!   alpha_{i-1,j},
+!   alpha_{i,j+1},
+!   alpha_{i,j-1},
+!   alpha_{ij})
+! (ix,iy) are LOCAL indices of the grid boxes, which are
+! converted to global indices
+!==================================================================
+  subroutine construct_alpha_T_mnh(grid_param,ix,iy,alpha_T,Tij)
+    implicit none
+    type(grid_parameters), intent(in) :: grid_param
+    integer, intent(in) :: ix
+    integer, intent(in) :: iy
+    real(kind=rl), intent(inout), dimension(5) :: alpha_T
+    real(kind=rl), intent(out) :: Tij
+
+    !local var
+    real(kind=rl)              :: h, rho_i, sigma_j
+    real(kind=rl)              :: xcoef 
+    logical                    :: l2nd       
+
+    h = grid_param%L/grid_param%n
+    ! Cartesian coefficients
+    Tij = h**2
+    ! optimisation for newman MNH case = all coef constant
+    alpha_T(1:4) = 1.0_rl
+    alpha_T(5) = 4.0_rl
+    return
+    xcoef = 0.5_rl ! 0.0
+    l2nd = .false. ! .true. ! .false.
+    alpha_T(1) = 1.0
+    alpha_T(2) = 1.0
+    if (ix == grid_param%n) then
+      alpha_T(1) = xcoef * 2.0_rl
+      if (l2nd) alpha_T(2) = 2.0_rl
+    end if
+    if (ix == 1) then
+      alpha_T(2) = xcoef * 2.0_rl
+      if (l2nd) alpha_T(1) = 2.0_rl
+    end if
+    alpha_T(3) = 1.0
+    alpha_T(4) = 1.0
+    if (iy == grid_param%n) then
+      alpha_T(3) = xcoef * 2.0_rl
+      if (l2nd) alpha_T(4) = 2.0
+    end if
+    if (iy == 1) then
+      alpha_T(4) = xcoef * 2.0_rl
+      if (l2nd) alpha_T(3) = 2.0
+    end if
+
+    alpha_T(5) = alpha_T(1) + alpha_T(2) + alpha_T(3) + alpha_T(4)
+  end subroutine construct_alpha_T_mnh
+! constant coef for MNH
+  subroutine construct_alpha_T_cst_mnh(grid_param,alpha_T,Tij)
+    implicit none
+    type(grid_parameters), intent(in) :: grid_param
+    real(kind=rl), intent(inout), dimension(5) :: alpha_T
+    real(kind=rl), intent(out) :: Tij
+
+    !local var
+    real(kind=rl)              :: h
+
+    h = grid_param%L/grid_param%n
+    ! Cartesian coefficients
+    Tij = h**2
+    ! optimisation for newman MNH case = all coef constant
+    alpha_T(1:4) = 1.0_rl
+    alpha_T(5) = 4.0_rl
+ 
+  end subroutine construct_alpha_T_cst_mnh
+!==================================================================
+  subroutine construct_alpha_T(grid_param,ix,iy,alpha_T,Tij)
+    implicit none
+    type(grid_parameters), intent(in) :: grid_param
+    integer, intent(in) :: ix
+    integer, intent(in) :: iy
+    real(kind=rl), intent(inout), dimension(5) :: alpha_T
+    real(kind=rl), intent(out) :: Tij
+    real(kind=rl)              :: h, rho_i, sigma_j
+#ifdef CARTESIANGEOMETRY
+    h = grid_param%L/grid_param%n
+    ! Cartesian coefficients
+    Tij = h**2
+    if (ix == grid_param%n) then
+      alpha_T(1) = 2.0_rl  
+    else
+      alpha_T(1) = 1.0_rl
+    end if
+    if (ix == 1) then
+      alpha_T(2) = 2.0_rl  
+    else
+      alpha_T(2) = 1.0_rl
+    end if
+    if (iy == grid_param%n) then
+      alpha_T(3) = 2.0_rl  
+    else
+      alpha_T(3) = 1.0_rl
+    end if
+    if (iy == 1) then
+      alpha_T(4) = 2.0_rl  
+    else
+      alpha_T(4) = 1.0_rl
+    end if
+#else
+    ! Coefficients in cubed sphere geometry
+    ! (rho_i,sigma_j) \in [-1,1] x [-1,1] are the coordinates of the
+    ! cubed sphere segment
+    h = 2.0_rl/grid_param%n
+    Tij = volume_of_element(ix,iy,grid_param)
+    rho_i = 2.0_rl*(1.0_rl*ix-0.5_rl)/grid_param%n-1.0_rl
+    sigma_j = 2.0_rl*(1.0_rl*iy-0.5_rl)/grid_param%n-1.0_rl
+    ! alpha_{i+1,j}
+    if (ix == grid_param%n) then
+      alpha_T(1) = 2.0_rl*DSQRT((1.0_rl+(rho_i+0.25_rl*h)**2)/(1.0_rl+sigma_j**2))
+    else
+      alpha_T(1) = DSQRT((1.0_rl+(rho_i+0.5_rl*h)**2)/(1.0_rl+sigma_j**2))
+    end if
+    ! alpha_{i-1,j}
+    if (ix == 1) then
+      alpha_T(2) = 2.0_rl*DSQRT((1.0_rl+(rho_i-0.25_rl*h)**2)/(1.0_rl+sigma_j**2))
+    else
+      alpha_T(2) = DSQRT((1.0_rl+(rho_i-0.5_rl*h)**2)/(1.0_rl+sigma_j**2))
+    end if
+    ! alpha_{i,j+1}
+    if (iy == grid_param%n) then
+      alpha_T(3) = 2.0_rl*DSQRT((1.0_rl+(sigma_j+0.25_rl*h)**2)/(1.0_rl+rho_i**2))
+    else
+      alpha_T(3) = DSQRT((1.0_rl+(sigma_j+0.5_rl*h)**2)/(1.0_rl+rho_i**2))
+    end if
+    ! alpha_{i,j-1}
+    if (iy == 1) then
+      alpha_T(4) = 2.0_rl*DSQRT((1.0_rl+(sigma_j-0.25_rl*h)**2)/(1.0_rl+rho_i**2))
+    else
+      alpha_T(4) = DSQRT((1.0_rl+(sigma_j-0.5_rl*h)**2)/(1.0_rl+rho_i**2))
+    end if
+#endif
+    alpha_T(5) = alpha_T(1) + alpha_T(2) + alpha_T(3) + alpha_T(4)
+  end subroutine construct_alpha_T
+!==================================================================
+! Construct coefficients of tridiagonal matrix A_T
+! describing the coupling in the vertical direction and the
+! diagonal matrix diag(d)
+!==================================================================
+subroutine construct_vertical_coeff_mnh(PA_K,PB_K,PC_K,PD_K)
+  implicit none
+  real(kind=rl) , optional , intent (in) :: PA_K(:),PB_K(:),PC_K(:),PD_K(:)
+  !local var
+  real(kind=rl) :: a_k_tmp, b_k_tmp, c_k_tmp, d_k_tmp
+  real(kind=rl) :: omega2, lambda2, delta, vol_r, surface_k, surface_kp1
+  integer :: k
+  
+  IF (.NOT. PRESENT(PA_K)) THEN
+  omega2 = model_param%omega2
+  lambda2 = model_param%lambda2
+  delta = model_param%delta
+  do k = 1, grid_param%nz
+
+    vol_r = r_grid(k+1)-r_grid(k)
+    surface_k = 1.0_rl
+    surface_kp1 = 1.0_rl
+
+    ! Diagonal element
+    a_k_tmp = delta*vol_r
+    ! off diagonal elements
+    ! Boundary conditions
+    ! Top
+    if (k == grid_param%nz) then
+      if (grid_param%vertbc == VERTBC_DIRICHLET) then
+        b_k_tmp = - 2.0_rl * omega2*lambda2 &
+                           * surface_kp1/(r_grid(k+1)-r_grid(k))
+      else
+        b_k_tmp = 0.0_rl
+      end if
+    else
+      b_k_tmp = - 2.0_rl*omega2*lambda2 &
+              * surface_kp1/(r_grid(k+2)-r_grid(k))
+    end if
+    ! Bottom
+    if (k == 1) then
+      if (grid_param%vertbc == VERTBC_DIRICHLET) then
+        c_k_tmp = - 2.0_rl * omega2*lambda2 &
+                           * surface_k/(r_grid(k+1)-r_grid(k))
+      else
+        c_k_tmp = 0.0_rl
+      end if
+    else
+      c_k_tmp = - 2.0_rl * omega2 * lambda2 &
+              * surface_k/(r_grid(k+1)-r_grid(k-1))
+    end if
+    ! Diagonal matrix d_k
+    d_k_tmp = - omega2 * (r_grid(k+1)-r_grid(k))
+    vert_coeff%a(k) = a_k_tmp/d_k_tmp
+    vert_coeff%b(k) = b_k_tmp/d_k_tmp
+    vert_coeff%c(k) = c_k_tmp/d_k_tmp
+    vert_coeff%d(k) = d_k_tmp
+  end do
+  ELSE
+  do k = 1, grid_param%nz
+    vert_coeff%a(k) = PA_K(k)
+    vert_coeff%b(k) = PB_K(k)
+    vert_coeff%c(k) = PC_K(k)
+    vert_coeff%d(k) = PD_K(k)
+  end do
+  ENDIF
+end subroutine construct_vertical_coeff_mnh
+
+subroutine construct_vertical_coeff()
+  implicit none
+  real(kind=rl) :: a_k_tmp, b_k_tmp, c_k_tmp, d_k_tmp
+  real(kind=rl) :: omega2, lambda2, delta, vol_r, surface_k, surface_kp1
+  integer :: k
+  omega2 = model_param%omega2
+  lambda2 = model_param%lambda2
+  delta = model_param%delta
+  do k = 1, grid_param%nz
+#ifdef  CARTESIANGEOMETRY
+    vol_r = r_grid(k+1)-r_grid(k)
+    surface_k = 1.0_rl
+    surface_kp1 = 1.0_rl
+#else
+    vol_r = (r_grid(k+1)**3 - r_grid(k)**3)/3.0_rl
+    surface_k = r_grid(k)**2
+    surface_kp1 = r_grid(k+1)**2
+#endif
+    ! Diagonal element
+    a_k_tmp = delta*vol_r
+    ! off diagonal elements
+    ! Boundary conditions
+    ! Top
+    if (k == grid_param%nz) then
+      if (grid_param%vertbc == VERTBC_DIRICHLET) then
+        b_k_tmp = - 2.0_rl * omega2*lambda2 &
+                           * surface_kp1/(r_grid(k+1)-r_grid(k))
+      else
+        b_k_tmp = 0.0_rl
+      end if
+    else
+      b_k_tmp = - 2.0_rl*omega2*lambda2 &
+              * surface_kp1/(r_grid(k+2)-r_grid(k))
+    end if
+    ! Bottom
+    if (k == 1) then
+      if (grid_param%vertbc == VERTBC_DIRICHLET) then
+        c_k_tmp = - 2.0_rl * omega2*lambda2 &
+                           * surface_k/(r_grid(k+1)-r_grid(k))
+      else
+        c_k_tmp = 0.0_rl
+      end if
+    else
+      c_k_tmp = - 2.0_rl * omega2 * lambda2 &
+              * surface_k/(r_grid(k+1)-r_grid(k-1))
+    end if
+    ! Diagonal matrix d_k
+    d_k_tmp = - omega2 * (r_grid(k+1)-r_grid(k))
+    vert_coeff%a(k) = a_k_tmp/d_k_tmp
+    vert_coeff%b(k) = b_k_tmp/d_k_tmp
+    vert_coeff%c(k) = c_k_tmp/d_k_tmp
+    vert_coeff%d(k) = d_k_tmp
+  end do
+end subroutine construct_vertical_coeff
+
+!==================================================================
+! Calculate local residual r = b - A.u
+!==================================================================
+  subroutine calculate_residual_mnh(level,m,b,u,r)
+    implicit none
+    integer, intent(in)                :: level
+    integer, intent(in)                :: m
+    type(scalar3d), intent(in)         :: b
+    type(scalar3d), intent(inout)      :: u
+    type(scalar3d), intent(inout)      :: r
+    integer :: ix,iy,iz
+    integer ::  iib,iie,ijb,ije,ikb,ike
+
+    real , dimension(:,:,:) , pointer :: zr_st , zb_st
+
+    ! r <- A.u
+    !call boundary_mnh(u)
+    call apply_mnh(u,r)
+    ! r <- b - r = b - A.u
+    if (LUseO) then
+       do ix=u%icompx_min,u%icompx_max
+          do iy=u%icompy_min,u%icompy_max
+             do iz=1,u%grid_param%nz
+                r%s(iz,iy,ix) = b%s(iz,iy,ix) - r%s(iz,iy,ix)
+             end do
+          end do
+       end do
+    endif
+    if (LUseT) then
+!!$       do iz=1,u%grid_param%nz
+!!$          do iy=u%icompy_min,u%icompy_max
+!!$             do ix=u%icompx_min,u%icompx_max
+!!$                r%st(ix,iy,iz) = b%st(ix,iy,iz) - r%st(ix,iy,iz)
+!!$             end do
+!!$          end do
+!!$       end do
+       !-----------------
+       iib=u%icompx_min
+       iie=u%icompx_max
+       ijb=u%icompy_min
+       ije=u%icompy_max
+       ikb=1
+       ike=u%grid_param%nz
+
+       zr_st => r%st
+       zb_st => b%st
+       !$acc kernels
+       zr_st(iib:iie,ijb:ije,ikb:ike) = zb_st(iib:iie,ijb:ije,ikb:ike) - zr_st(iib:iie,ijb:ije,ikb:ike)
+       !$acc end kernels
+    endif
+
+  end subroutine calculate_residual_mnh
+
+  subroutine calculate_residual(level,m,b,u,r)
+    implicit none
+    integer, intent(in)                :: level
+    integer, intent(in)                :: m
+    type(scalar3d), intent(in)         :: b
+    type(scalar3d), intent(inout)      :: u
+    type(scalar3d), intent(inout)      :: r
+    integer :: ix,iy,iz
+
+
+    ! r <- A.u
+    call apply(u,r)
+    ! r <- b - r = b - A.u
+    do ix=u%icompx_min,u%icompx_max
+      do iy=u%icompy_min,u%icompy_max
+        do iz=1,u%grid_param%nz
+          r%s(iz,iy,ix) = b%s(iz,iy,ix) - r%s(iz,iy,ix)
+        end do
+      end do
+    end do
+  end subroutine calculate_residual
+
+!==================================================================
+! Apply operator v = A.u
+!==================================================================
+  subroutine apply_mnh(u,v)
+    implicit none
+    type(scalar3d), intent(inout)      :: u
+    type(scalar3d), intent(inout)      :: v
+
+    ! local var
+    real(kind=rl), dimension(5) :: alpha_T
+    real(kind=rl) :: Tij
+    real(kind=rl) :: a_k, b_k, c_k, d_k
+    integer :: ix,iy,iz
+    real(kind=rl) :: tmp
+    integer :: iib,iie,ijb,ije
+
+    real(kind=rl), dimension(:,:,:) , pointer :: zv_st , zu_st  
+    real(kind=rl), dimension(:)     , pointer :: za_k, zb_k, zc_k, zd_k
+    integer :: ii,ij
+    integer :: ize
+
+    call boundary_mnh(u)
+
+    if (LUseO) then     
+       do ix=u%icompx_min,u%icompx_max
+          do iy=u%icompy_min,u%icompy_max
+             ! Construct horizontal part of stencil
+             call construct_alpha_T_mnh(u%grid_param,  &
+                  ix+u%ix_min-1, &
+                  iy+u%iy_min-1, &
+                  alpha_T,Tij)
+             do iz=1,u%grid_param%nz
+                a_k = vert_coeff%a(iz)
+                b_k = vert_coeff%b(iz)
+                c_k = vert_coeff%c(iz)
+                d_k = vert_coeff%d(iz)
+                tmp = ((a_k-b_k-c_k)*Tij ) * u%s(iz,iy,ix)
+                if (iz < grid_param%nz) then
+                   tmp = tmp + b_k*Tij * u%s(iz+1,iy,ix)
+                end if
+                if (iz > 1) then
+                   tmp = tmp + c_k*Tij * u%s(iz-1,iy,ix)
+                end if
+                if ((iz > 1) .and. (iz < grid_param%nz)) then
+                   tmp = tmp - alpha_T(5) * u%s(iz,  iy  ,ix  ) &
+                        + alpha_T(1) * u%s(iz,  iy  ,ix+1) &
+                        + alpha_T(2) * u%s(iz,  iy  ,ix-1) &
+                        + alpha_T(3) * u%s(iz,  iy+1,ix  ) &
+                        + alpha_T(4) * u%s(iz,  iy-1,ix  )
+                end if
+                v%s(iz,iy,ix) = d_k*tmp 
+             end do
+          end do
+       end do
+    endif
+    if (LUseT) then 
+       call construct_alpha_T_cst_mnh(u%grid_param,alpha_T,Tij)    
+       !-----------------------------------------------------------
+       iib=u%icompx_min
+       iie=u%icompx_max
+       ijb=u%icompy_min
+       ije=u%icompy_max
+       ize=u%grid_param%nz
+       !
+       zv_st => v%st
+       zu_st => u%st
+       zb_k => vert_coeff%b
+       zc_k => vert_coeff%c
+       zd_k => vert_coeff%d
+    
+       !$acc kernels 
+       iz=1
+       !$acc loop independent dtype(nvidia) collapse(2)
+       do ij=ijb,ije
+          do ii=iib,iie
+             zv_st(ii,ij,iz)   = zd_k(iz)* ( (-zb_k(iz)-zc_k(iz))*Tij * zu_st(ii,ij,iz  )  &
+                                              +zb_k(iz)          *Tij * zu_st(ii,ij,iz+1)  )
+          end do
+       end do
+       !
+       do iz=2,ize-1
+          !$acc loop independent dtype(nvidia) collapse(2)
+          do ij=ijb,ije
+             do ii=iib,iie
+                zv_st(ii,ij,iz) = zd_k(iz)* ( ((-zb_k(iz)-zc_k(iz))*Tij - 4.0_rl ) * zu_st(ii,ij,iz)    &
+                                                +zb_k(iz)          *Tij            * zu_st(ii,ij,iz+1)  &
+                                                         +zc_k(iz) *Tij            * zu_st(ii,ij,iz-1)  &
+                                           +                                         zu_st(ii+1,ij,iz) &
+                                           +                                         zu_st(ii-1,ij,iz) &
+                                           +                                         zu_st(ii,ij+1,iz) &
+                                           +                                         zu_st(ii,ij-1,iz) &
+                                       )
+             end do
+          end do
+       end do
+       !
+       iz=ize
+       !$acc loop independent dtype(nvidia) collapse(2)
+       do ij=ijb,ije
+          do ii=iib,iie
+             zv_st(ii,ij,iz) = zd_k(iz)*  (  (-zb_k(iz)-zc_k(iz))*Tij  * zu_st(ii,ij,iz)    &
+                                                       +zc_k(iz) *Tij  * zu_st(ii,ij,iz-1)  )
+          end do
+       end do
+
+       !$acc end kernels
+    endif
+    
+  end subroutine apply_mnh
+
+  subroutine apply(u,v)
+    implicit none
+    type(scalar3d), intent(in)         :: u
+    type(scalar3d), intent(inout)      :: v
+    real(kind=rl), dimension(5) :: alpha_T
+    real(kind=rl) :: Tij
+    real(kind=rl) :: a_k, b_k, c_k, d_k
+    integer :: ix,iy,iz
+    real(kind=rl) :: tmp
+
+    do ix=u%icompx_min,u%icompx_max
+      do iy=u%icompy_min,u%icompy_max
+        ! Construct horizontal part of stencil
+        call construct_alpha_T(u%grid_param,  &
+                               ix+u%ix_min-1, &
+                               iy+u%iy_min-1, &
+                               alpha_T,Tij)
+        do iz=1,u%grid_param%nz
+          a_k = vert_coeff%a(iz)
+          b_k = vert_coeff%b(iz)
+          c_k = vert_coeff%c(iz)
+          d_k = vert_coeff%d(iz)
+          tmp = ((a_k-b_k-c_k)*Tij - alpha_T(5)) * u%s(iz,iy,ix)
+          if (iz < grid_param%nz) then
+            tmp = tmp + b_k*Tij * u%s(iz+1,iy,ix)
+          end if
+          if (iz > 1) then
+            tmp = tmp + c_k*Tij * u%s(iz-1,iy,ix)
+          end if
+          tmp = tmp + alpha_T(1) * u%s(iz,  iy  ,ix+1) &
+                    + alpha_T(2) * u%s(iz,  iy  ,ix-1) &
+                    + alpha_T(3) * u%s(iz,  iy+1,ix  ) &
+                    + alpha_T(4) * u%s(iz,  iy-1,ix  )
+          v%s(iz,iy,ix) = d_k*tmp
+        end do
+      end do
+    end do
+  end subroutine apply
+!==================================================================
+!==================================================================
+!
+!     S M O O T H E R S
+!
+!==================================================================
+!==================================================================
+
+!==================================================================
+! Perform nsmooth smoother iterations
+!==================================================================
+  subroutine smooth_mnh(level,m,nsmooth,direction,b,u)
+    implicit none
+    integer, intent(in) :: level
+    integer, intent(in) :: m
+    integer, intent(in) :: nsmooth       ! Number of smoothing steps
+    integer, intent(in) :: direction     ! Direction
+    type(scalar3d), intent(inout) :: b   ! RHS
+    type(scalar3d), intent(inout) :: u   ! solution vector
+    integer :: i
+    real(kind=rl) :: log_res_initial, log_res_final
+    type(scalar3d) :: r
+    integer :: halo_size
+    integer :: nlocal, nz
+
+#ifdef MEASURESMOOTHINGRATE
+    r%ix_min = u%ix_min
+    r%ix_max = u%ix_max
+    r%iy_min = u%iy_min
+    r%iy_max = u%iy_max
+    r%icompx_min = u%icompx_min
+    r%icompx_max = u%icompx_max
+    r%icompy_min = u%icompy_min
+    r%icompy_max = u%icompy_max
+    r%halo_size = u%halo_size
+    r%isactive = u%isactive
+    r%grid_param = u%grid_param
+    nlocal = r%ix_max-r%ix_min+1
+    halo_size = r%halo_size
+    nz = r%grid_param%nz
+
+    if (LUseO) then
+       allocate(r%s(0:nz+1,                       &
+                    1-halo_size:nlocal+halo_size, &
+                    1-halo_size:nlocal+halo_size))
+    end if
+
+    if (LUseT) then
+       allocate(r%st(1-halo_size:nlocal+halo_size, &
+                     1-halo_size:nlocal+halo_size, &
+                     0:nz+1))
+    end if
+
+    call calculate_residual(level,m,b,u,r)
+    log_res_initial = log(l2norm(r))
+#endif
+    ! Carry out nsmooth iterations of the smoother
+    if (smoother_param%smoother == SMOOTHER_LINE_SOR) then
+      do i=1,nsmooth
+        call line_SOR_mnh(level,m,direction,b,u)
+      end do
+    else if (smoother_param%smoother == SMOOTHER_LINE_SSOR) then
+      do i=1,nsmooth
+        call line_SSOR_mnh(level,m,direction,b,u)
+      end do
+    else if (smoother_param%smoother == SMOOTHER_LINE_JAC) then
+      do i=1,nsmooth
+        call line_jacobi_mnh(level,m,b,u)
+      end do
+    end if
+#ifdef MEASURESMOOTHINGRATE
+    call calculate_residual_mnh(level,m,b,u,r)
+    log_res_final = log(l2norm(r))
+    log_resreduction(level) = log_resreduction(level) &
+                            + (log_res_final - log_res_initial)
+    nsmooth_total(level) = nsmooth_total(level) + nsmooth
+    if (LUseO) deallocate(r%s)
+    if (LUseT) deallocate(r%st)
+#endif
+  end subroutine smooth_mnh
+!==================================================================
+! Perform nsmooth smoother iterations
+!==================================================================
+  subroutine smooth(level,m,nsmooth,direction,b,u)
+    implicit none
+    integer, intent(in) :: level
+    integer, intent(in) :: m
+    integer, intent(in) :: nsmooth       ! Number of smoothing steps
+    integer, intent(in) :: direction     ! Direction
+    type(scalar3d), intent(inout) :: b   ! RHS
+    type(scalar3d), intent(inout) :: u   ! solution vector
+    integer :: i
+    real(kind=rl) :: log_res_initial, log_res_final
+    type(scalar3d) :: r
+    integer :: halo_size
+    integer :: nlocal, nz
+
+#ifdef MEASURESMOOTHINGRATE
+    r%ix_min = u%ix_min
+    r%ix_max = u%ix_max
+    r%iy_min = u%iy_min
+    r%iy_max = u%iy_max
+    r%icompx_min = u%icompx_min
+    r%icompx_max = u%icompx_max
+    r%icompy_min = u%icompy_min
+    r%icompy_max = u%icompy_max
+    r%halo_size = u%halo_size
+    r%isactive = u%isactive
+    r%grid_param = u%grid_param
+    nlocal = r%ix_max-r%ix_min+1
+    halo_size = r%halo_size
+    nz = r%grid_param%nz
+    if (LUseO) then
+    allocate(r%s(0:nz+1,                       &
+                 1-halo_size:nlocal+halo_size, &
+                 1-halo_size:nlocal+halo_size))
+    call calculate_residual(level,m,b,u,r)
+    endif
+    if (LUseT) then
+    allocate(r%st(1-halo_size:nlocal+halo_size,   &
+                  1-halo_size:nlocal+halo_size,   &
+                  0:nz+1) )
+    endif
+    log_res_initial = log(l2norm(r))
+#endif
+    ! Carry out nsmooth iterations of the smoother
+    if (smoother_param%smoother == SMOOTHER_LINE_SOR) then
+      do i=1,nsmooth
+        call line_SOR(level,m,direction,b,u)
+      end do
+    else if (smoother_param%smoother == SMOOTHER_LINE_SSOR) then
+      do i=1,nsmooth
+        call line_SSOR(level,m,direction,b,u)
+      end do
+    else if (smoother_param%smoother == SMOOTHER_LINE_JAC) then
+      do i=1,nsmooth
+        call line_jacobi(level,m,b,u)
+      end do
+    end if
+#ifdef MEASURESMOOTHINGRATE
+    call calculate_residual(level,m,b,u,r)
+    log_res_final = log(l2norm(r))
+    log_resreduction(level) = log_resreduction(level) &
+                            + (log_res_final - log_res_initial)
+    nsmooth_total(level) = nsmooth_total(level) + nsmooth
+    if (LUseO) deallocate(r%s)
+    if (LUseT) deallocate(r%st)
+#endif
+  end subroutine smooth
+!==================================================================
+! SOR line smoother mnh
+!==================================================================
+  subroutine line_SOR_mnh(level,m,direction,b,u)
+
+    implicit none
+
+    integer, intent(in)                :: level
+    integer, intent(in)                :: m
+    integer, intent(in)                :: direction
+    type(scalar3d), intent(in)         :: b
+    type(scalar3d), intent(inout)      :: u
+
+    !local Var
+    real(kind=rl), allocatable :: r(:)
+    integer :: nz, nlocal
+    real(kind=rl), allocatable :: c(:), utmp(:)
+    integer :: ixmin(5), ixmax(5), dix
+    integer :: iymin(5), iymax(5), diy
+    integer :: color
+    integer :: nsweeps, isweep
+    integer :: ordering
+    real(kind=rl) :: rho
+    integer, dimension(4) :: send_requests, recv_requests
+    integer, dimension(4) :: send_requestsT, recv_requestsT
+    integer :: tmp, ierr
+    integer :: iblock
+    logical :: overlap_comms
+
+    call boundary_mnh(u)
+
+    ordering = smoother_param%ordering
+    rho = smoother_param%rho
+
+    nz = u%grid_param%nz
+
+    ! Create residual vector
+    allocate(r(nz))
+    ! Allocate memory for auxiliary vectors for Thomas algorithm
+    allocate(c(nz))
+    allocate(utmp(nz))
+    nlocal = u%ix_max-u%ix_min+1
+#ifdef OVERLAPCOMMS
+    overlap_comms = (nlocal > 2)
+#else
+    overlap_comms = .false.
+#endif
+    ! Block 1 (N)
+    ixmin(1) = 1
+    ixmax(1) = nlocal
+    iymin(1) = 1
+    iymax(1) = 1
+    ! Block 2 (S)
+    ixmin(2) = 1
+    ixmax(2) = nlocal
+    iymin(2) = nlocal
+    iymax(2) = nlocal
+    ! Block 3 (W)
+    ixmin(3) = 1
+    ixmax(3) = 1
+    iymin(3) = 2
+    iymax(3) = nlocal-1
+    ! Block 4 (E)
+    ixmin(4) = nlocal
+    ixmax(4) = nlocal
+    iymin(4) = 2
+    iymax(4) = nlocal-1
+    ! Block 5 (INTERIOR)
+    if (overlap_comms) then
+      ixmin(5) = 2
+      ixmax(5) = nlocal-1
+      iymin(5) = 2
+      iymax(5) = nlocal-1
+    else
+      ! If there are no interior cells, do not overlap
+      ! communications and calculations, just loop over interior cells
+      ixmin(5) = 1
+      ixmax(5) = nlocal
+      iymin(5) = 1
+      iymax(5) = nlocal
+    end if
+    dix = +1
+    diy = +1
+    color = 1
+    ! When iteration backwards over the grid, reverse the direction
+    if (direction == DIRECTION_BACKWARD) then
+      do iblock = 1, 5
+        tmp = ixmax(iblock)
+        ixmax(iblock) = ixmin(iblock)
+        ixmin(iblock) = tmp
+        tmp = iymax(iblock)
+        iymax(iblock) = iymin(iblock)
+        iymin(iblock) = tmp
+      end do
+      dix = -1
+      diy = -1
+      color = 0
+    end if
+    nsweeps = 1
+    if (ordering == ORDERING_LEX) then
+      nsweeps = 1
+    else if (ordering == ORDERING_RB) then
+      nsweeps = 2
+    end if
+    do isweep = 1, nsweeps
+      if (overlap_comms) then
+        ! Loop over cells next to boundary (iblock = 1,...,4)
+        do iblock = 1, 4
+          call loop_over_grid_mnh(iblock)
+        end do
+        ! Initiate halo exchange
+        call ihaloswap_mnh(level,m,u,send_requests,recv_requests,send_requestsT,recv_requestsT)
+      end if
+      ! Loop over INTERIOR cells
+      iblock = 5
+      call loop_over_grid_mnh(iblock)
+      if (overlap_comms) then
+        if (m > 0) then
+          if (LUseO) call mpi_waitall(4,recv_requests, MPI_STATUSES_IGNORE, ierr)
+          if (LUseO) call mpi_waitall(4,send_requests, MPI_STATUSES_IGNORE, ierr)
+          if (LUseT) call mpi_waitall(4,recv_requestsT, MPI_STATUSES_IGNORE, ierr)
+          if (LUseT) call mpi_waitall(4,send_requestsT, MPI_STATUSES_IGNORE, ierr)
+        end if
+      else
+        call haloswap_mnh(level,m,u)
+      end if
+      color = 1-color
+    end do
+
+    ! Free memory again
+    deallocate(r)
+    deallocate(c)
+    deallocate(utmp)
+
+    contains
+
+    !------------------------------------------------------------------
+    ! Loop over grid, for a given block
+    !------------------------------------------------------------------
+    subroutine loop_over_grid_mnh(iblock)
+      implicit none
+      integer, intent(in) :: iblock
+      integer :: ix,iy,iz
+
+      if (LUseO) then
+         do ix=ixmin(iblock),ixmax(iblock),dix
+            do iy=iymin(iblock),iymax(iblock),diy
+               if (ordering == ORDERING_RB) then
+                  if (mod((ix+u%ix_min)+(iy+u%iy_min),2) .ne. color) cycle
+               end if
+               call apply_tridiag_solve_mnh(ix,iy,r,c,b,         &
+                    u%s(1:nz,iy  ,ix+1), &
+                    u%s(1:nz,iy  ,ix-1), &
+                    u%s(1:nz,iy+1,ix  ), &
+                    u%s(1:nz,iy-1,ix  ), &
+                    utmp)
+               ! Add to field with overrelaxation-factor
+               do iz=1,nz
+                  u%s(iz,iy,ix) = (1.0_rl-rho)*u%s(iz,iy,ix) + rho*utmp(iz)
+               end do
+            end do
+         end do
+      end if
+      if (LUseT) then
+         do ix=ixmin(iblock),ixmax(iblock),dix
+            do iy=iymin(iblock),iymax(iblock),diy
+               if (ordering == ORDERING_RB) then
+                  if (mod((ix+u%ix_min)+(iy+u%iy_min),2) .ne. color) cycle
+               end if
+               call apply_tridiag_solve_mnhT(ix,iy,r,c,b,         &
+                    u%st(ix+1,iy  ,1:nz), &
+                    u%st(ix-1,iy  ,1:nz), &
+                    u%st(ix  ,iy+1,1:nz), &
+                    u%st(ix  ,iy-1,1:nz), &
+                    utmp)
+               ! Add to field with overrelaxation-factor
+               do iz=1,nz
+                  u%st(ix,iy,iz) = (1.0_rl-rho)*u%st(ix,iy,iz) + rho*utmp(iz)
+               end do
+            end do
+         end do
+      end if   
+
+    end subroutine loop_over_grid_mnh
+
+  end subroutine line_SOR_mnh
+!==================================================================
+! SOR line smoother
+!==================================================================
+  subroutine line_SOR(level,m,direction,b,u)
+
+    implicit none
+
+    integer, intent(in)                :: level
+    integer, intent(in)                :: m
+    integer, intent(in)                :: direction
+    type(scalar3d), intent(in)         :: b
+    type(scalar3d), intent(inout)      :: u
+    real(kind=rl), allocatable :: r(:)
+    integer :: nz, nlocal
+    real(kind=rl), allocatable :: c(:), utmp(:)
+    integer :: ixmin(5), ixmax(5), dix
+    integer :: iymin(5), iymax(5), diy
+    integer :: color
+    integer :: nsweeps, isweep
+    integer :: ordering
+    real(kind=rl) :: rho
+    integer, dimension(4) :: send_requests, recv_requests
+    integer :: tmp, ierr
+    integer :: iblock
+    logical :: overlap_comms
+
+    ordering = smoother_param%ordering
+    rho = smoother_param%rho
+
+    nz = u%grid_param%nz
+
+    ! Create residual vector
+    allocate(r(nz))
+    ! Allocate memory for auxiliary vectors for Thomas algorithm
+    allocate(c(nz))
+    allocate(utmp(nz))
+    nlocal = u%ix_max-u%ix_min+1
+#ifdef OVERLAPCOMMS
+    overlap_comms = (nlocal > 2)
+#else
+    overlap_comms = .false.
+#endif
+    ! Block 1 (N)
+    ixmin(1) = 1
+    ixmax(1) = nlocal
+    iymin(1) = 1
+    iymax(1) = 1
+    ! Block 2 (S)
+    ixmin(2) = 1
+    ixmax(2) = nlocal
+    iymin(2) = nlocal
+    iymax(2) = nlocal
+    ! Block 3 (W)
+    ixmin(3) = 1
+    ixmax(3) = 1
+    iymin(3) = 2
+    iymax(3) = nlocal-1
+    ! Block 4 (E)
+    ixmin(4) = nlocal
+    ixmax(4) = nlocal
+    iymin(4) = 2
+    iymax(4) = nlocal-1
+    ! Block 5 (INTERIOR)
+    if (overlap_comms) then
+      ixmin(5) = 2
+      ixmax(5) = nlocal-1
+      iymin(5) = 2
+      iymax(5) = nlocal-1
+    else
+      ! If there are no interior cells, do not overlap
+      ! communications and calculations, just loop over interior cells
+      ixmin(5) = 1
+      ixmax(5) = nlocal
+      iymin(5) = 1
+      iymax(5) = nlocal
+    end if
+    dix = +1
+    diy = +1
+    color = 1
+    ! When iteration backwards over the grid, reverse the direction
+    if (direction == DIRECTION_BACKWARD) then
+      do iblock = 1, 5
+        tmp = ixmax(iblock)
+        ixmax(iblock) = ixmin(iblock)
+        ixmin(iblock) = tmp
+        tmp = iymax(iblock)
+        iymax(iblock) = iymin(iblock)
+        iymin(iblock) = tmp
+      end do
+      dix = -1
+      diy = -1
+      color = 0
+    end if
+    nsweeps = 1
+    if (ordering == ORDERING_LEX) then
+      nsweeps = 1
+    else if (ordering == ORDERING_RB) then
+      nsweeps = 2
+    end if
+    do isweep = 1, nsweeps
+      if (overlap_comms) then
+        ! Loop over cells next to boundary (iblock = 1,...,4)
+        do iblock = 1, 4
+          call loop_over_grid(iblock)
+        end do
+        ! Initiate halo exchange
+        call ihaloswap(level,m,u,send_requests,recv_requests)
+      end if
+      ! Loop over INTERIOR cells
+      iblock = 5
+      call loop_over_grid(iblock)
+      if (overlap_comms) then
+        if (m > 0) then
+          call mpi_waitall(4,recv_requests, MPI_STATUSES_IGNORE, ierr)
+        end if
+      else
+        call haloswap(level,m,u)
+      end if
+      color = 1-color
+    end do
+
+    ! Free memory again
+    deallocate(r)
+    deallocate(c)
+    deallocate(utmp)
+
+    contains
+
+    !------------------------------------------------------------------
+    ! Loop over grid, for a given block
+    !------------------------------------------------------------------
+    subroutine loop_over_grid(iblock)
+      implicit none
+      integer, intent(in) :: iblock
+      integer :: ix,iy,iz
+      do ix=ixmin(iblock),ixmax(iblock),dix
+        do iy=iymin(iblock),iymax(iblock),diy
+          if (ordering == ORDERING_RB) then
+            if (mod((ix+u%ix_min)+(iy+u%iy_min),2) .ne. color) cycle
+          end if
+          call apply_tridiag_solve(ix,iy,r,c,b,         &
+                                   u%s(1:nz,iy  ,ix+1), &
+                                   u%s(1:nz,iy  ,ix-1), &
+                                   u%s(1:nz,iy+1,ix  ), &
+                                   u%s(1:nz,iy-1,ix  ), &
+                                   utmp)
+           ! Add to field with overrelaxation-factor
+          do iz=1,nz
+            u%s(iz,iy,ix) = (1.0_rl-rho)*u%s(iz,iy,ix) + rho*utmp(iz)
+          end do
+        end do
+      end do
+    end subroutine loop_over_grid
+
+  end subroutine line_SOR
+
+!==================================================================
+! SSOR line smoother mnh
+!==================================================================
+  subroutine line_SSOR_mnh(level,m,direction,b,u)
+    implicit none
+    integer, intent(in)                :: level
+    integer, intent(in)                :: m
+    integer, intent(in)                :: direction
+    type(scalar3d), intent(in)         :: b
+    type(scalar3d), intent(inout)      :: u
+    if (direction == DIRECTION_FORWARD) then
+      call line_SOR_mnh(level,m,DIRECTION_FORWARD,b,u)
+      call line_SOR_mnh(level,m,DIRECTION_BACKWARD,b,u)
+    else
+      call line_SOR_mnh(level,m,DIRECTION_BACKWARD,b,u)
+      call line_SOR_mnh(level,m,DIRECTION_FORWARD,b,u)
+    end if
+  end subroutine line_SSOR_mnh
+
+!==================================================================
+! SSOR line smoother
+!==================================================================
+  subroutine line_SSOR(level,m,direction,b,u)
+    implicit none
+    integer, intent(in)                :: level
+    integer, intent(in)                :: m
+    integer, intent(in)                :: direction
+    type(scalar3d), intent(in)         :: b
+    type(scalar3d), intent(inout)      :: u
+    if (direction == DIRECTION_FORWARD) then
+      call line_SOR(level,m,DIRECTION_FORWARD,b,u)
+      call line_SOR(level,m,DIRECTION_BACKWARD,b,u)
+    else
+      call line_SOR(level,m,DIRECTION_BACKWARD,b,u)
+      call line_SOR(level,m,DIRECTION_FORWARD,b,u)
+    end if
+  end subroutine line_SSOR
+
+!==================================================================
+! Jacobi line smoother
+!==================================================================
+  subroutine line_Jacobi_mnh(level,m,b,u)
+    implicit none
+    integer, intent(in)                :: level
+    integer, intent(in)                :: m
+    type(scalar3d), intent(in)         :: b
+    type(scalar3d), intent(inout)      :: u
+    real(kind=rl), allocatable :: r(:)
+    integer :: ix,iy,iz, nz
+    real(kind=rl), dimension(5) :: alpha_T
+    real(kind=rl), allocatable :: c(:), utmp(:)
+    real(kind=rl), allocatable :: u0(:,:,:) 
+    real(kind=rl), allocatable :: ut0(:,:,:) 
+    integer :: nlocal, halo_size
+    real(kind=rl) :: rho
+    logical :: overlap_comms
+    integer, dimension(4) :: send_requests, recv_requests
+    integer, dimension(4) :: send_requestsT, recv_requestsT
+    integer :: ixmin(5), ixmax(5)
+    integer :: iymin(5), iymax(5)
+    integer :: iblock, ierr
+
+    integer :: iib,iie,ijb,ije
+    type(scalar3d) :: Sr,Sc,Sut0,Sutmp
+
+    real , dimension(:,:,:) , pointer :: zSut0_st , zu_st
+
+    call boundary_mnh(u)
+
+    ! Set optimal smoothing parameter on each level
+    !rho = 2.0_rl/(2.0_rl+4.0_rl*model_param%omega2*u%grid_param%n**2/(1.0_rl+4.0_rl*model_param%omega2*u%grid_param%n**2))
+    rho = smoother_param%rho
+
+    nz = u%grid_param%nz
+    nlocal = u%ix_max -u%ix_min + 1
+    halo_size = u%halo_size
+
+#ifdef OVERLAPCOMMS
+    overlap_comms = (nlocal > 2)
+#else
+    overlap_comms = .false.
+#endif
+
+    ! Block 1 (N)
+    ixmin(1) = 1
+    ixmax(1) = nlocal
+    iymin(1) = 1
+    iymax(1) = 1
+    ! Block 2 (S)
+    ixmin(2) = 1
+    ixmax(2) = nlocal
+    iymin(2) = nlocal
+    iymax(2) = nlocal
+    ! Block 3 (W)
+    ixmin(3) = 1
+    ixmax(3) = 1
+    iymin(3) = 2
+    iymax(3) = nlocal-1
+    ! Block 4 (E)
+    ixmin(4) = nlocal
+    ixmax(4) = nlocal
+    iymin(4) = 2
+    iymax(4) = nlocal-1
+    ! Block 5 (INTERIOR)
+    if (overlap_comms) then
+      ixmin(5) = 2
+      ixmax(5) = nlocal-1
+      iymin(5) = 2
+      iymax(5) = nlocal-1
+    else
+      ! If there are no interior cells, do not overlap
+      ! communications and calculations, just loop over interior cells
+      ixmin(5) = 1
+      ixmax(5) = nlocal
+      iymin(5) = 1
+      iymax(5) = nlocal
+    end if
+
+    ! Temporary vector
+    if (LUseO) allocate(u0(0:u%grid_param%nz+1,            &
+                1-halo_size:nlocal+halo_size,   &
+                1-halo_size:nlocal+halo_size) )
+    if (LUseT) allocate(ut0(1-halo_size:nlocal+halo_size,   &
+                            1-halo_size:nlocal+halo_size,   &
+                            0:u%grid_param%nz+1) )
+    if (LUseO) u0(:,:,:) = u%s(:,:,:)
+    if (LUseT) then
+       zu_st =>  u%st
+       !$acc kernels
+       ut0(:,:,:) = zu_st(:,:,:)
+       !$acc end kernels
+    end if
+    ! Create residual vector
+    allocate(r(nz))
+    ! Allocate memory for auxiliary vectors for Thomas algorithm
+    allocate(c(nz))
+    allocate(utmp(nz))
+    if (LUseT) then
+       allocate(Sr%st(1-halo_size:nlocal+halo_size,   &
+                            1-halo_size:nlocal+halo_size,   &
+                            0:u%grid_param%nz+1) )
+       allocate(Sut0%st(1-halo_size:nlocal+halo_size,   &
+                            1-halo_size:nlocal+halo_size,   &
+                            0:u%grid_param%nz+1) )
+
+       zSut0_st => Sut0%st
+       zu_st => u%st
+
+       !$acc kernels
+       zSut0_st(:,:,:) = zu_st(:,:,:)
+       !$acc end kernels
+
+       allocate(Sutmp%st(1-halo_size:nlocal+halo_size,   &
+                            1-halo_size:nlocal+halo_size,   &
+                            0:u%grid_param%nz+1) )
+       
+    endif
+
+    ! Loop over grid
+    if (overlap_comms) then
+    ! Loop over cells next to boundary (iblock = 1,...,4)
+      do iblock = 1, 4
+        call loop_over_grid_jacobi_mnh(iblock)
+      end do
+      ! Initiate halo exchange
+      call ihaloswap_mnh(level,m,u,send_requests,recv_requests,send_requestsT,recv_requestsT)
+    end if
+    ! Loop over INTERIOR cells
+    iblock = 5
+    call loop_over_grid_jacobi_mnh(iblock)
+    if (overlap_comms) then
+      if (m > 0) then
+        if (LUseO) call mpi_waitall(4,recv_requests, MPI_STATUSES_IGNORE, ierr)
+        if (LUseO) call mpi_waitall(4,send_requests, MPI_STATUSES_IGNORE, ierr)
+        if (LUseT) call mpi_waitall(4,recv_requestsT, MPI_STATUSES_IGNORE, ierr)
+        if (LUseT) call mpi_waitall(4,send_requestsT, MPI_STATUSES_IGNORE, ierr)
+      end if
+    else
+      call haloswap_mnh(level,m,u)
+    end if
+
+    ! Free memory again
+    deallocate(r)
+    deallocate(c)
+    if (LUseO) deallocate(u0)
+    if (LUseT) deallocate(ut0)
+    deallocate(utmp)
+    if (LUseT) deallocate(Sr%st,Sut0%st,Sutmp%st)
+
+  contains
+
+  subroutine loop_over_grid_jacobi_mnh(iblock)
+    implicit none
+    integer, intent(in) :: iblock
+    integer :: ix,iy,iz
+
+    real , dimension(:,:,:) , pointer :: zu_st , zSutmp_st , zSut0_st
+    
+    if (LUseO) then
+       do ix=ixmin(iblock),ixmax(iblock)
+          do iy=iymin(iblock),iymax(iblock)
+             call apply_tridiag_solve_mnh(ix,iy,r,c,b,        &
+                  u0(1:nz,iy  ,ix+1), &
+                  u0(1:nz,iy  ,ix-1), &
+                  u0(1:nz,iy+1,ix  ), &
+                  u0(1:nz,iy-1,ix  ), &
+                  utmp)
+             ! Add correction
+             do iz=1,nz
+                u%s(iz,iy,ix) = rho*utmp(iz) + (1.0_rl-rho)*u0(iz,iy,ix)
+             end do
+          end do
+       end do
+    end if
+   if (LUseT) then
+       iib=ixmin(iblock)
+       iie=ixmax(iblock)
+       ijb=iymin(iblock)
+       ije=iymax(iblock)
+
+       zu_st => u%st
+       zSutmp_st => Sutmp%st
+       zSut0_st => Sut0%st
+
+       call apply_tridiag_solve_mnh_allT(iib,iie,ijb,ije,Sr,c,b,        &
+                  Sut0, &
+                  Sutmp )
+       !$acc kernels
+       zu_st(iib:iie,ijb:ije,1:nz) = & 
+                         rho*zSutmp_st(iib:iie,ijb:ije,1:nz) & 
+                       + (1.0_rl-rho)*zSut0_st(iib:iie,ijb:ije,1:nz)
+       !$acc end kernels
+    end if
+
+  end subroutine loop_over_grid_jacobi_mnh
+
+end subroutine line_Jacobi_mnh
+!==================================================================
+! Jacobi line smoother
+!==================================================================
+  subroutine line_Jacobi(level,m,b,u)
+    implicit none
+    integer, intent(in)                :: level
+    integer, intent(in)                :: m
+    type(scalar3d), intent(in)         :: b
+    type(scalar3d), intent(inout)      :: u
+    real(kind=rl), allocatable :: r(:)
+    integer :: ix,iy,iz, nz
+    real(kind=rl), dimension(5) :: alpha_T
+    real(kind=rl), allocatable :: c(:), utmp(:)
+    real(kind=rl), allocatable :: u0(:,:,:)
+    integer :: nlocal, halo_size
+    real(kind=rl) :: rho
+    logical :: overlap_comms
+    integer, dimension(4) :: send_requests, recv_requests
+    integer :: ixmin(5), ixmax(5)
+    integer :: iymin(5), iymax(5)
+    integer :: iblock, ierr
+
+    ! Set optimal smoothing parameter on each level
+    rho = 2.0_rl/(2.0_rl+4.0_rl*model_param%omega2*u%grid_param%n**2/(1.0_rl+4.0_rl*model_param%omega2*u%grid_param%n**2))
+
+    nz = u%grid_param%nz
+    nlocal = u%ix_max -u%ix_min + 1
+    halo_size = u%halo_size
+
+#ifdef OVERLAPCOMMS
+    overlap_comms = (nlocal > 2)
+#else
+    overlap_comms = .false.
+#endif
+
+    ! Block 1 (N)
+    ixmin(1) = 1
+    ixmax(1) = nlocal
+    iymin(1) = 1
+    iymax(1) = 1
+    ! Block 2 (S)
+    ixmin(2) = 1
+    ixmax(2) = nlocal
+    iymin(2) = nlocal
+    iymax(2) = nlocal
+    ! Block 3 (W)
+    ixmin(3) = 1
+    ixmax(3) = 1
+    iymin(3) = 2
+    iymax(3) = nlocal-1
+    ! Block 4 (E)
+    ixmin(4) = nlocal
+    ixmax(4) = nlocal
+    iymin(4) = 2
+    iymax(4) = nlocal-1
+    ! Block 5 (INTERIOR)
+    if (overlap_comms) then
+      ixmin(5) = 2
+      ixmax(5) = nlocal-1
+      iymin(5) = 2
+      iymax(5) = nlocal-1
+    else
+      ! If there are no interior cells, do not overlap
+      ! communications and calculations, just loop over interior cells
+      ixmin(5) = 1
+      ixmax(5) = nlocal
+      iymin(5) = 1
+      iymax(5) = nlocal
+    end if
+
+    ! Temporary vector
+    allocate(u0(0:u%grid_param%nz+1,            &
+                1-halo_size:nlocal+halo_size,   &
+                1-halo_size:nlocal+halo_size) )
+    u0(:,:,:) = u%s(:,:,:)
+    ! Create residual vector
+    allocate(r(nz))
+    ! Allocate memory for auxiliary vectors for Thomas algorithm
+    allocate(c(nz))
+    allocate(utmp(nz))
+
+    ! Loop over grid
+    if (overlap_comms) then
+    ! Loop over cells next to boundary (iblock = 1,...,4)
+      do iblock = 1, 4
+        call loop_over_grid(iblock)
+      end do
+      ! Initiate halo exchange
+      call ihaloswap(level,m,u,send_requests,recv_requests)
+    end if
+    ! Loop over INTERIOR cells
+    iblock = 5
+    call loop_over_grid(iblock)
+    if (overlap_comms) then
+      if (m > 0) then
+        call mpi_waitall(4,recv_requests, MPI_STATUSES_IGNORE, ierr)
+      end if
+    else
+      call haloswap(level,m,u)
+    end if
+
+    ! Free memory again
+    deallocate(r)
+    deallocate(c)
+    deallocate(u0)
+    deallocate(utmp)
+
+  contains
+
+  subroutine loop_over_grid(iblock)
+    implicit none
+    integer, intent(in) :: iblock
+    integer :: ix,iy,iz
+    do ix=ixmin(iblock),ixmax(iblock)
+      do iy=iymin(iblock),iymax(iblock)
+        call apply_tridiag_solve(ix,iy,r,c,b,        &
+                                 u0(1:nz,iy  ,ix+1), &
+                                 u0(1:nz,iy  ,ix-1), &
+                                 u0(1:nz,iy+1,ix  ), &
+                                 u0(1:nz,iy-1,ix  ), &
+                                 utmp)
+        ! Add correction
+        do iz=1,nz
+          u%s(iz,iy,ix) = rho*utmp(iz) + (1.0_rl-rho)*u0(iz,iy,ix)
+        end do
+      end do
+    end do
+  end subroutine loop_over_grid
+
+  end subroutine line_Jacobi
+!==================================================================
+! At a given horizontal position (ix,iy) (local coordinates),
+! calculate
+!
+! u_out = T(ix,iy)^{-1} (b_(ix,iy)
+!       - sum_{ix',iy' != ix,iy} A_{(ix,iy),(ix',iy')}*u_in(ix',iy'))
+!
+!==================================================================
+  subroutine apply_tridiag_solve_mnh(ix,iy,r,c,b, &
+                                 u_in_1,      &
+                                 u_in_2,      &
+                                 u_in_3,      &
+                                 u_in_4,      &
+                                 u_out)
+
+    implicit none
+    integer, intent(in) :: ix
+    integer, intent(in) :: iy
+    real(kind=rl), intent(inout), dimension(:) :: r
+    real(kind=rl), intent(inout), dimension(:) :: c
+    type(scalar3d), intent(in) :: b
+    real(kind=rl), intent(in), dimension(:) :: u_in_1
+    real(kind=rl), intent(in), dimension(:) :: u_in_2
+    real(kind=rl), intent(in), dimension(:) :: u_in_3
+    real(kind=rl), intent(in), dimension(:) :: u_in_4
+    real(kind=rl), intent(inout), dimension(:) :: u_out
+    real(kind=rl), dimension(5) :: alpha_T
+    real(kind=rl) :: Tij
+    real(kind=rl) :: alpha_div_Tij, tmp, b_k_tmp, c_k_tmp
+    integer :: iz, nz
+
+    real(kind=rl) :: xctop_boot 
+
+    nz = b%grid_param%nz
+    xctop_boot = 0.0
+
+    call construct_alpha_T_mnh(b%grid_param,  &
+                           ix+b%ix_min-1, &
+                           iy+b%iy_min-1, &
+                           alpha_T,Tij)
+    ! Calculate r_i = b_i - A_{ij} u_i
+    !alpha_T(5) = 4
+    if (LUseO) then 
+       iz=1 
+       r(iz) = b%s(iz,iy,ix)
+       do iz=2,nz-1
+          r(iz) = b%s(iz,iy,ix) - vert_coeff%d(iz) * ( &
+               alpha_T(1) * u_in_1(iz) + &
+               alpha_T(2) * u_in_2(iz) + &
+               alpha_T(3) * u_in_3(iz) + &
+               alpha_T(4) * u_in_4(iz) )
+       end do
+       iz=nz
+       r(iz) = b%s(iz,iy,ix)
+       
+       ! Thomas algorithm
+       ! STEP 1: Create modified coefficients
+       iz = 1
+       alpha_div_Tij = alpha_T(5)/Tij
+       tmp = (vert_coeff%a(iz)-vert_coeff%b(iz)-vert_coeff%c(iz)) &
+            - xctop_boot*alpha_div_Tij
+       c(iz) = vert_coeff%b(iz)/tmp
+       u_out(iz) = r(iz) / (tmp*Tij*vert_coeff%d(iz))
+       do iz=2,nz-1
+          b_k_tmp = vert_coeff%b(iz)
+          c_k_tmp = vert_coeff%c(iz)
+          tmp = ((vert_coeff%a(iz)-b_k_tmp-c_k_tmp)-alpha_div_Tij) &
+               - c(iz-1)*c_k_tmp
+          c(iz) = b_k_tmp / tmp
+          u_out(iz) = (r(iz) / (Tij*vert_coeff%d(iz)) - u_out(iz-1)*c_k_tmp) / tmp
+       end do
+       iz=nz
+       b_k_tmp = vert_coeff%b(iz)
+       c_k_tmp = vert_coeff%c(iz)
+       tmp = ((vert_coeff%a(iz)-b_k_tmp-c_k_tmp)- xctop_boot*alpha_div_Tij) &
+            - c(iz-1)*c_k_tmp
+       c(iz) = b_k_tmp / tmp
+       u_out(iz) = (r(iz) / (Tij*vert_coeff%d(iz)) - u_out(iz-1)*c_k_tmp) / tmp
+       
+       ! STEP 2: back substitution
+       do iz=nz-1,1,-1
+          u_out(iz) = u_out(iz) - c(iz) * u_out(iz+1)
+       end do
+    end if
+    !
+
+  end subroutine apply_tridiag_solve_mnh
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+! tranpose version 
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+  subroutine apply_tridiag_solve_mnhT(ix,iy,r,c,b, &
+                                 u_in_1,      &
+                                 u_in_2,      &
+                                 u_in_3,      &
+                                 u_in_4,      &
+                                 u_out)
+
+    implicit none
+    integer, intent(in) :: ix
+    integer, intent(in) :: iy
+    real(kind=rl), intent(inout), dimension(:) :: r
+    real(kind=rl), intent(inout), dimension(:) :: c
+    type(scalar3d), intent(in) :: b
+    real(kind=rl), intent(in), dimension(:) :: u_in_1
+    real(kind=rl), intent(in), dimension(:) :: u_in_2
+    real(kind=rl), intent(in), dimension(:) :: u_in_3
+    real(kind=rl), intent(in), dimension(:) :: u_in_4
+    real(kind=rl), intent(inout), dimension(:) :: u_out
+    real(kind=rl), dimension(5) :: alpha_T
+    real(kind=rl) :: Tij
+    real(kind=rl) :: alpha_div_Tij, tmp, b_k_tmp, c_k_tmp
+    integer :: iz, nz
+
+    real(kind=rl) :: xctop_boot 
+
+    nz = b%grid_param%nz
+    xctop_boot = 0.0
+
+    call construct_alpha_T_cst_mnh(b%grid_param,alpha_T,Tij)
+    ! Calculate r_i = b_i - A_{ij} u_i
+    if (LUseT ) then 
+       iz=1 
+       r(iz) = b%st(ix,iy,iz)
+       do iz=2,nz-1
+          r(iz) = b%st(ix,iy,iz) - vert_coeff%d(iz) * ( &
+               alpha_T(1) * u_in_1(iz) + &
+               alpha_T(2) * u_in_2(iz) + &
+               alpha_T(3) * u_in_3(iz) + &
+               alpha_T(4) * u_in_4(iz) )
+       end do
+       iz=nz
+       r(iz) = b%st(ix,iy,iz)
+       
+       ! Thomas algorithm
+       ! STEP 1: Create modified coefficients
+       iz = 1
+       alpha_div_Tij = alpha_T(5)/Tij
+       tmp = (vert_coeff%a(iz)-vert_coeff%b(iz)-vert_coeff%c(iz)) &
+            - xctop_boot*alpha_div_Tij
+       c(iz) = vert_coeff%b(iz)/tmp
+       u_out(iz) = r(iz) / (tmp*Tij*vert_coeff%d(iz))
+       do iz=2,nz-1
+          b_k_tmp = vert_coeff%b(iz)
+          c_k_tmp = vert_coeff%c(iz)
+          tmp = ((vert_coeff%a(iz)-b_k_tmp-c_k_tmp)-alpha_div_Tij) &
+               - c(iz-1)*c_k_tmp
+          c(iz) = b_k_tmp / tmp
+          u_out(iz) = (r(iz) / (Tij*vert_coeff%d(iz)) - u_out(iz-1)*c_k_tmp) / tmp
+       end do
+       iz=nz
+       b_k_tmp = vert_coeff%b(iz)
+       c_k_tmp = vert_coeff%c(iz)
+       tmp = ((vert_coeff%a(iz)-b_k_tmp-c_k_tmp)- xctop_boot*alpha_div_Tij) &
+            - c(iz-1)*c_k_tmp
+       c(iz) = b_k_tmp / tmp
+       u_out(iz) = (r(iz) / (Tij*vert_coeff%d(iz)) - u_out(iz-1)*c_k_tmp) / tmp
+       
+       ! STEP 2: back substitution
+       do iz=nz-1,1,-1
+          u_out(iz) = u_out(iz) - c(iz) * u_out(iz+1)
+       end do
+    end if
+
+  end subroutine apply_tridiag_solve_mnhT
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+! tranpose version all xyz
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+  subroutine apply_tridiag_solve_mnh_allT(iib,iie,ijb,ije, &
+                                 Sr,c,b,Su_in,Su_out)
+
+    implicit none
+    integer, intent(in) :: iib,iie,ijb,ije
+    type(scalar3d), intent(inout) :: Sr
+    real(kind=rl), intent(inout), dimension(:) :: c
+    type(scalar3d), intent(in)    :: b
+    type(scalar3d), intent(in)    :: Su_in
+    type(scalar3d), intent(inout) :: Su_out
+
+    !local 
+    real(kind=rl), dimension(5) :: alpha_T
+    real(kind=rl) :: Tij
+    real(kind=rl) :: alpha_div_Tij, tmp, b_k_tmp, c_k_tmp
+    integer :: iz, nz
+
+    real, dimension(:,:,:) , pointer :: zSr_st , zb_st , zSu_in_st , zSu_out_st
+    real, dimension(:)     , pointer :: za_k, zb_k, zc_k, zd_k , tmp_k
+    integer :: ii,ij
+
+    nz = b%grid_param%nz
+
+    call construct_alpha_T_cst_mnh(b%grid_param,alpha_T,Tij)
+    ! Calculate r_i = b_i - A_{ij} u_i
+    if (LUseT ) then 
+
+      zSr_st => Sr%st
+      zb_st  => b%st
+      zSu_in_st => Su_in%st
+      zSu_out_st => Su_out%st
+      za_k  => vert_coeff%a
+      zb_k  => vert_coeff%b
+      zc_k  => vert_coeff%c
+      zd_k  => vert_coeff%d
+      allocate(tmp_k(size(zb_k)))
+
+      !$acc kernels
+       iz=1 
+       zSr_st(iib:iie,ijb:ije,iz) = zb_st(iib:iie,ijb:ije,iz)
+       do iz=2,nz-1
+          zSr_st(iib:iie,ijb:ije,iz) = zb_st(iib:iie,ijb:ije,iz) - zd_k(iz) * ( &
+                            zSu_in_st(iib+1:iie+1,ijb:ije,iz) + &
+                            zSu_in_st(iib-1:iie-1,ijb:ije,iz) + &
+                            zSu_in_st(iib:iie,ijb+1:ije+1,iz) + &
+                            zSu_in_st(iib:iie,ijb-1:ije-1,iz) )
+       end do
+       iz=nz
+       zSr_st(iib:iie,ijb:ije,iz) = zb_st(iib:iie,ijb:ije,iz)
+       
+       ! Thomas algorithm
+       ! STEP 1: Create modified coefficients
+       iz = 1
+       alpha_div_Tij = alpha_T(5)/Tij
+       tmp = (za_k(iz)-vert_coeff%b(iz)-vert_coeff%c(iz))
+       c(iz) = vert_coeff%b(iz)/tmp
+       zSu_out_st(iib:iie,ijb:ije,iz) = zSr_st(iib:iie,ijb:ije,iz) / (tmp*Tij*zd_k(iz))
+       !
+       do iz=2,nz-1
+          b_k_tmp = zb_k(iz)
+          c_k_tmp = zc_k(iz)
+          tmp_k(iz) = ((za_k(iz)-b_k_tmp-c_k_tmp)-alpha_div_Tij) &
+               - c(iz-1)*c_k_tmp
+          c(iz) = b_k_tmp / tmp_k(iz)
+       end do
+       do iz=2,nz-1
+          !$acc loop independent collapse(2)
+          do ij=ijb,ije
+             do ii=iib,iie
+                zSu_out_st(ii,ij,iz) = (zSr_st(ii,ij,iz) / (Tij*zd_k(iz)) & 
+                                     - zSu_out_st(ii,ij,iz-1)*c_k_tmp) / tmp_k(iz)
+             end do
+          end do          
+       end do
+       !
+       iz=nz
+       b_k_tmp = zb_k(iz)
+       c_k_tmp = zc_k(iz)
+       tmp = ((za_k(iz)-b_k_tmp-c_k_tmp)) &
+            - c(iz-1)*c_k_tmp
+       c(iz) = b_k_tmp / tmp
+       zSu_out_st(iib:iie,ijb:ije,iz) = (zSr_st(iib:iie,ijb:ije,iz) / (Tij*zd_k(iz)) &
+                                     -  zSu_out_st(iib:iie,ijb:ije,iz-1)*c_k_tmp) / tmp
+       
+       ! STEP 2: back substitution
+       do iz=nz-1,1,-1
+          zSu_out_st(iib:iie,ijb:ije,iz) = zSu_out_st(iib:iie,ijb:ije,iz) & 
+                                        - c(iz) * zSu_out_st(iib:iie,ijb:ije,iz+1)
+       end do
+       !$acc end kernels
+
+       deallocate(tmp_k)
+
+    end if
+
+  end subroutine apply_tridiag_solve_mnh_allT
+  !==================================================================
+! At a given horizontal position (ix,iy) (local coordinates),
+! calculate
+!
+! u_out = T(ix,iy)^{-1} (b_(ix,iy)
+!       - sum_{ix',iy' != ix,iy} A_{(ix,iy),(ix',iy')}*u_in(ix',iy'))
+!
+!==================================================================
+  subroutine apply_tridiag_solve(ix,iy,r,c,b, &
+                                 u_in_1,      &
+                                 u_in_2,      &
+                                 u_in_3,      &
+                                 u_in_4,      &
+                                 u_out)
+
+    implicit none
+    integer, intent(in) :: ix
+    integer, intent(in) :: iy
+    real(kind=rl), intent(inout), dimension(:) :: r
+    real(kind=rl), intent(inout), dimension(:) :: c
+    type(scalar3d), intent(in) :: b
+    real(kind=rl), intent(in), dimension(:) :: u_in_1
+    real(kind=rl), intent(in), dimension(:) :: u_in_2
+    real(kind=rl), intent(in), dimension(:) :: u_in_3
+    real(kind=rl), intent(in), dimension(:) :: u_in_4
+    real(kind=rl), intent(inout), dimension(:) :: u_out
+    real(kind=rl), dimension(5) :: alpha_T
+    real(kind=rl) :: Tij
+    real(kind=rl) :: alpha_div_Tij, tmp, b_k_tmp, c_k_tmp
+    integer :: iz, nz
+
+    nz = b%grid_param%nz
+
+    call construct_alpha_T(b%grid_param,  &
+                           ix+b%ix_min-1, &
+                           iy+b%iy_min-1, &
+                           alpha_T,Tij)
+    ! Calculate r_i = b_i - A_{ij} u_i
+    !alpha_T(5) = 4.0
+    do iz=1,nz
+      r(iz) = b%s(iz,iy,ix) - vert_coeff%d(iz) * ( &
+                alpha_T(1) * u_in_1(iz) + &
+                alpha_T(2) * u_in_2(iz) + &
+                alpha_T(3) * u_in_3(iz) + &
+                alpha_T(4) * u_in_4(iz) )
+    end do
+    !r(1:nz) = b%s(1:nz,iy,ix)
+    ! Thomas algorithm
+    ! STEP 1: Create modified coefficients
+    iz = 1
+    alpha_div_Tij = alpha_T(5)/Tij
+    tmp = (vert_coeff%a(iz)-vert_coeff%b(iz)-vert_coeff%c(iz)) &
+             - alpha_div_Tij
+    c(iz) = vert_coeff%b(iz)/tmp
+    u_out(iz) = r(iz) / (tmp*Tij*vert_coeff%d(iz))
+    do iz=2,nz
+      b_k_tmp = vert_coeff%b(iz)
+      c_k_tmp = vert_coeff%c(iz)
+      tmp = ((vert_coeff%a(iz)-b_k_tmp-c_k_tmp)-alpha_div_Tij) &
+          - c(iz-1)*c_k_tmp
+      c(iz) = b_k_tmp / tmp
+      u_out(iz) = (r(iz) / (Tij*vert_coeff%d(iz)) - u_out(iz-1)*c_k_tmp) / tmp
+    end do
+    ! STEP 2: back substitution
+    do iz=nz-1,1,-1
+      u_out(iz) = u_out(iz) - c(iz) * u_out(iz+1)
+    end do
+  end subroutine apply_tridiag_solve
+
+end module discretisation
diff --git a/src/ZSOLVER/tensorproductmultigrid_Source/messages.f90 b/src/ZSOLVER/tensorproductmultigrid_Source/messages.f90
new file mode 100644
index 0000000000000000000000000000000000000000..7b4345777a92dcb235e12c456284ecc66b06c980
--- /dev/null
+++ b/src/ZSOLVER/tensorproductmultigrid_Source/messages.f90
@@ -0,0 +1,104 @@
+!=== COPYRIGHT AND LICENSE STATEMENT ===
+!
+!  This file is part of the TensorProductMultigrid code.
+!  
+!  (c) The copyright relating to this work is owned jointly by the
+!  Crown, Met Office and NERC [2014]. However, it has been created
+!  with the help of the GungHo Consortium, whose members are identified
+!  at https://puma.nerc.ac.uk/trac/GungHo/wiki .
+!  
+!  Main Developer: Eike Mueller
+!  
+!  TensorProductMultigrid is free software: you can redistribute it and/or
+!  modify it under the terms of the GNU Lesser General Public License as
+!  published by the Free Software Foundation, either version 3 of the
+!  License, or (at your option) any later version.
+!  
+!  TensorProductMultigrid is distributed in the hope that it will be useful,
+!  but WITHOUT ANY WARRANTY; without even the implied warranty of
+!  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+!  GNU Lesser General Public License for more details.
+!  
+!  You should have received a copy of the GNU Lesser General Public License
+!  along with TensorProductMultigrid (see files COPYING and COPYING.LESSER).
+!  If not, see <http://www.gnu.org/licenses/>.
+!
+!=== COPYRIGHT AND LICENSE STATEMENT ===
+
+
+!==================================================================
+!
+!  Module for error/warning/info messages
+!
+!    Eike Mueller, University of Bath, Feb 2012
+!
+!==================================================================
+module messages
+
+  use parameters
+#ifndef MNH
+  use mpi
+#else
+  use modd_mpif
+#endif  
+
+  implicit none
+
+contains
+
+!==================================================================
+! Print error message and exit
+!==================================================================
+  subroutine fatalerror(message)
+    implicit none
+    character(len=*), intent(in) :: message
+    integer :: ierr, rank
+    integer, parameter :: errorcode = -1
+    call mpi_comm_rank(MPI_COMM_WORLD,rank,ierr)
+    if (rank == 0) then
+      write(STDERR,'("FATAL ERROR: ",A)') message
+    end if
+    call mpi_finalize(ierr)
+    STOP
+  end subroutine fatalerror
+
+!==================================================================
+! Print error message
+!==================================================================
+  subroutine error(message)
+    implicit none
+    character(len=*), intent(in) :: message
+    integer :: ierr, rank
+    call mpi_comm_rank(MPI_COMM_WORLD,rank,ierr)
+    if (rank == 0) then
+      write(STDERR,'("ERROR: ",A)') message
+    end if
+  end subroutine error
+
+!==================================================================
+! Print warning message
+!==================================================================
+  subroutine warning(message)
+    implicit none
+    character(len=*), intent(in) :: message
+    integer :: ierr, rank
+    call mpi_comm_rank(MPI_COMM_WORLD,rank,ierr)
+    if (rank == 0) then
+      write(STDERR,'("WARNING: ",A)') message
+    end if
+  end subroutine warning
+
+!==================================================================
+! Print info message
+!==================================================================
+  subroutine information(message)
+    implicit none
+    character(len=*), intent(in) :: message
+    integer :: ierr, rank
+    call mpi_comm_rank(MPI_COMM_WORLD,rank,ierr)
+    if (rank == 0) then
+      write(STDERR,'("INFO: ",A)') message
+    end if
+  end subroutine information
+
+end module messages
diff --git a/src/ZSOLVER/tensorproductmultigrid_Source/mg_main.f90 b/src/ZSOLVER/tensorproductmultigrid_Source/mg_main.f90
new file mode 100644
index 0000000000000000000000000000000000000000..a97d51b494603178c8f34336f074d49d4f8aa8ec
--- /dev/null
+++ b/src/ZSOLVER/tensorproductmultigrid_Source/mg_main.f90
@@ -0,0 +1,85 @@
+!=== COPYRIGHT AND LICENSE STATEMENT ===
+!
+!  This file is part of the TensorProductMultigrid code.
+!  
+!  (c) The copyright relating to this work is owned jointly by the
+!  Crown, Met Office and NERC [2014]. However, it has been created
+!  with the help of the GungHo Consortium, whose members are identified
+!  at https://puma.nerc.ac.uk/trac/GungHo/wiki .
+!  
+!  Main Developer: Eike Mueller
+!  
+!  TensorProductMultigrid is free software: you can redistribute it and/or
+!  modify it under the terms of the GNU Lesser General Public License as
+!  published by the Free Software Foundation, either version 3 of the
+!  License, or (at your option) any later version.
+!  
+!  TensorProductMultigrid is distributed in the hope that it will be useful,
+!  but WITHOUT ANY WARRANTY; without even the implied warranty of
+!  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+!  GNU Lesser General Public License for more details.
+!  
+!  You should have received a copy of the GNU Lesser General Public License
+!  along with TensorProductMultigrid (see files COPYING and COPYING.LESSER).
+!  If not, see <http://www.gnu.org/licenses/>.
+!
+!=== COPYRIGHT AND LICENSE STATEMENT ===
+
+
+!==================================================================
+!
+!  Main program for multigrid solver code for Helmholtz/Poisson
+!  equation, discretised in the cell centred finite volume scheme
+!
+!    Eike Mueller, University of Bath, Feb 2012
+!
+!==================================================================
+
+!==================================================================
+! Main program
+!==================================================================
+
+program mg_main
+
+  use discretisation
+  use parameters
+  use datatypes
+  use multigrid
+  use conjugategradient
+  use solver
+  use profiles
+  use messages
+  use communication
+  use timer
+#ifndef MNH
+  use mpi
+#else
+  use modd_mpif
+#endif
+
+  use mode_mg_read_param
+  use mode_mg
+
+  implicit none
+
+  call mg_init()
+
+  ! Initialise ghosts in initial solution, as mg_solve assumes that they
+  ! are up-to-date
+  call haloswap(mg_param%n_lev,pproc,xu_fine)
+
+  ! Solve using multigrid
+  call initialise_timer(t_solve,"t_solve")
+  call start_timer(t_solve)
+  comm_measuretime = .True.
+#ifdef MEASUREHALOSWAP
+  call measurehaloswap()
+#else
+  call mg_solve(xb_fine,xu_fine,solver_param)
+#endif
+  comm_measuretime = .False.
+  call finish_timer(t_solve)
+
+call mg_finalize()
+
+end program mg_main
diff --git a/src/ZSOLVER/tensorproductmultigrid_Source/mg_main_mnh.f90 b/src/ZSOLVER/tensorproductmultigrid_Source/mg_main_mnh.f90
new file mode 100644
index 0000000000000000000000000000000000000000..21999316883d4dcffe25e5fa84fd544f2485a6b7
--- /dev/null
+++ b/src/ZSOLVER/tensorproductmultigrid_Source/mg_main_mnh.f90
@@ -0,0 +1,203 @@
+!=== COPYRIGHT AND LICENSE STATEMENT ===
+!
+!  This file is part of the TensorProductMultigrid code.
+!  
+!  (c) The copyright relating to this work is owned jointly by the
+!  Crown, Met Office and NERC [2014]. However, it has been created
+!  with the help of the GungHo Consortium, whose members are identified
+!  at https://puma.nerc.ac.uk/trac/GungHo/wiki .
+!  
+!  Main Developer: Eike Mueller
+!  
+!  TensorProductMultigrid is free software: you can redistribute it and/or
+!  modify it under the terms of the GNU Lesser General Public License as
+!  published by the Free Software Foundation, either version 3 of the
+!  License, or (at your option) any later version.
+!  
+!  TensorProductMultigrid is distributed in the hope that it will be useful,
+!  but WITHOUT ANY WARRANTY; without even the implied warranty of
+!  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+!  GNU Lesser General Public License for more details.
+!  
+!  You should have received a copy of the GNU Lesser General Public License
+!  along with TensorProductMultigrid (see files COPYING and COPYING.LESSER).
+!  If not, see <http://www.gnu.org/licenses/>.
+!
+!=== COPYRIGHT AND LICENSE STATEMENT ===
+
+
+!==================================================================
+!
+!  Main program for multigrid solver code for Helmholtz/Poisson
+!  equation, discretised in the cell centred finite volume scheme
+!
+!    Eike Mueller, University of Bath, Feb 2012
+!
+!==================================================================
+
+!==================================================================
+! Main program
+!==================================================================
+
+module mode_mg_main_mnh
+
+  use discretisation
+  use parameters
+  use datatypes
+  use multigrid
+  use conjugategradient
+  use solver
+  use profiles
+  use messages
+  use communication
+  use timer
+#ifndef MNH
+  use mpi
+#else
+  use modd_mpif
+#endif
+
+  use mode_mg_read_param
+  use mode_mg
+
+contains
+
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+  subroutine mg_main_mnh_init(KN,KNZ,PL,PH,PA_K,PB_K,PC_K,PD_K)
+
+    use parameters , only : LMean
+    
+    implicit none
+
+    integer       , optional , intent (in) :: KN,KNZ
+    real(kind=rl) , optional , intent (in) :: PL,PH
+    real(kind=rl) , optional , intent (in) :: PA_K(:),PB_K(:),PC_K(:),PD_K(:)
+
+    call mg_init_mnh(KN,KNZ,PL,PH,PA_K,PB_K,PC_K,PD_K)
+
+    ! Initialise ghosts in initial solution, as mg_solve assumes that they
+    ! are up-to-date
+    call haloswap_mnh(mg_param%n_lev,pproc,xu_fine)
+
+    if (.NOT. PRESENT(KN)) then 
+       !
+       ! Force some parameter for Idealized StandAlone Newman Solver until convergence
+       !
+       ! -> Mean must by set to 0 for covergence with Newmann boundaries
+       LMean = .true.
+       ! -> converge up to 1e-10 in 50 iteration
+       solver_param%resreduction =  1.0d-10
+       solver_param%maxiter = 50
+       
+       if (i_am_master_mpi) then
+          call flush(STDOUT)
+          write(STDOUT,*)
+          write(STDOUT,*) "!!!!! WARNING mg_main_mnh_init !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! "
+          write(STDOUT,*) "!!!!! FORCED PARAMETER FOR StandAlone Newman Solver until convergence !!!! "
+          write(STDOUT,*) "!!!!! LMean                     = " , LMean
+          write(STDOUT,*) "!!!!! solver_param%resreduction = " , solver_param%resreduction
+          write(STDOUT,*) "!!!!! solver_param%maxiter      = " , solver_param%maxiter
+          write(STDOUT,*) "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! "
+          write(STDOUT,*)
+          call flush(STDOUT)
+       end if
+    endif
+    
+  end subroutine mg_main_mnh_init
+
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+subroutine mg_main_initialise_rhs_mnh(KIB,KIE,KIU,KJB,KJE,KJU,KKU,PY)
+
+implicit none
+
+integer       , optional , intent(in) :: KIB,KIE,KIU,KJB,KJE,KJU,KKU
+real(kind=rl) , optional , intent(in) :: PY(:,:,:)
+
+ call initialise_rhs_mnh(grid_param,model_param,xb_fine,KIB,KIE,KIU,KJB,KJE,KJU,KKU,PY)
+ call haloswap_mnh(mg_param%n_lev,pproc,xb_fine)
+
+end subroutine mg_main_initialise_rhs_mnh
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+subroutine mg_main_initialise_u_mnh(KIB,KIE,KIU,KJB,KJE,KJU,KKU,PU)
+
+implicit none
+
+integer       , optional , intent(in) :: KIB,KIE,KIU,KJB,KJE,KJU,KKU
+real(kind=rl) , optional , intent(in) :: PU(:,:,:)
+
+ call initialise_u_mnh(grid_param,model_param,xu_fine,KIB,KIE,KIU,KJB,KJE,KJU,KKU,PU)
+ call haloswap_mnh(mg_param%n_lev,pproc,xu_fine)
+
+end subroutine mg_main_initialise_u_mnh
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+subroutine mg_main_get_u_mnh(KIB,KIE,KIU,KJB,KJE,KJU,KKU,PU)
+
+implicit none
+
+integer       , optional , intent(in)    :: KIB,KIE,KIU,KJB,KJE,KJU,KKU
+real(kind=rl) , optional , intent(inout) :: PU(:,:,:)
+
+ call get_u_mnh(grid_param,model_param,xu_fine,KIB,KIE,KIU,KJB,KJE,KJU,KKU,PU)
+
+end subroutine mg_main_get_u_mnh
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+  subroutine mg_main_mnh_solve()
+
+    implicit none
+
+    ! Solve using multigrid
+    call initialise_timer(t_solve,"t_solve")
+    call start_timer(t_solve)
+    comm_measuretime = .True.
+
+    call mg_solve_mnh(xb_fine,xu_fine,solver_param)
+
+    comm_measuretime = .False.
+    call finish_timer(t_solve)
+
+  end subroutine mg_main_mnh_solve
+
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+  subroutine mg_main_mnh_finalize()
+
+
+  end subroutine mg_main_mnh_finalize
+
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+  subroutine mg_main_mnh
+
+    implicit none
+
+    integer :: it
+
+    call  mg_main_mnh_init()
+
+    DO it=1,1
+       
+       call mg_main_initialise_rhs_mnh()
+       call mg_main_initialise_u_mnh()
+
+       if (i_am_master_mpi) then
+          write(STDOUT,*),'************************ IT=',it,' ***************************'
+          call flush(STDOUT)
+       end if
+       
+       call mg_main_mnh_solve()
+       
+    ENDDO
+
+    call mg_finalize()
+
+  end subroutine mg_main_mnh
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+end module mode_mg_main_mnh
+
+program mg_main_mnh_all
+  
+  use  mode_mg_main_mnh
+  
+  call mg_main_mnh()
+  
+end program mg_main_mnh_all
diff --git a/src/ZSOLVER/tensorproductmultigrid_Source/mode_mg.f90 b/src/ZSOLVER/tensorproductmultigrid_Source/mode_mg.f90
new file mode 100644
index 0000000000000000000000000000000000000000..806825f1b47d9e14c0d528fe57666e2931faeb0e
--- /dev/null
+++ b/src/ZSOLVER/tensorproductmultigrid_Source/mode_mg.f90
@@ -0,0 +1,331 @@
+module mode_mg
+
+ use datatypes
+ use communication
+ use discretisation
+ use multigrid
+ use conjugategradient
+ use solver
+ use parameters
+ use timer
+#ifndef MNH
+  use mpi
+#else
+  use modd_mpif
+#endif
+ use profiles
+
+ use mode_mg_read_param
+
+implicit none
+
+  type(grid_parameters)     :: grid_param
+  type(comm_parameters)     :: comm_param
+  type(model_parameters)    :: model_param
+  type(smoother_parameters) :: smoother_param
+  type(mg_parameters)       :: mg_param
+  type(cg_parameters)       :: cg_param
+  type(solver_parameters)   :: solver_param
+
+  type(scalar3d) :: xu_fine
+  type(scalar3d) :: xb_fine
+  type(scalar3d) :: xr_fine
+#ifdef TESTCONVERGENCE
+  type(scalar3d) :: uerror
+  real(kind=rl) :: l2error
+#endif
+
+ ! --- Name of executable ---
+  character(len=256) :: executable
+
+ ! --- Parameter file ---
+  character(len=256) :: parameterfile
+
+ ! --- General parameters ---
+  logical :: savefields   ! Save fields to disk?
+
+  integer :: i, int_size
+  integer :: i_arg
+  integer :: ierr
+
+ ! Timers
+  type(time) :: t_solve
+  type(time) :: t_readparam
+  type(time) :: t_initialise
+  type(time) :: t_finalise
+
+contains
+
+subroutine mg_init_mnh(KN,KNZ,PL,PH,PA_K,PB_K,PC_K,PD_K)
+
+implicit none
+
+integer       , optional , intent (in) :: KN,KNZ
+real(kind=rl) , optional , intent (in) :: PL,PH
+real(kind=rl) , optional , intent (in) :: PA_K(:),PB_K(:),PC_K(:),PD_K(:)
+
+! local var
+
+logical :: gisinit
+
+ ! Initialise MPI ...
+  call mpi_initialized(gisinit, ierr )
+  if  (.not. gisinit ) then
+     call mpi_init(ierr)
+  end if
+
+  ! ... and pre initialise communication module
+  call comm_preinitialise()
+
+    parameterfile="parameters_mg.nam"
+
+  if (i_am_master_mpi) then
+    write(STDOUT,*) ''
+    write(STDOUT,*) 'Compile time parameters:'
+    write(STDOUT,*) ''
+#ifdef CARTESIANGEOMETRY
+    write(STDOUT,*) '  Geometry: Cartesian'
+#else
+    write(STDOUT,*) '  Geometry: Spherical'
+#endif
+#ifdef USELAPACK
+    write(STDOUT,*) '  Use Lapack: Yes'
+#else
+    write(STDOUT,*) '  Use Lapack: No'
+#endif
+#ifdef OVERLAPCOMMS
+    write(STDOUT,*) '  Overlap communications and calculation: Yes'
+#else
+    write(STDOUT,*) '  Overlap communications and calculation: No'
+#endif
+    write(STDOUT,*) ''
+
+  end if
+
+  ! Initialise timing module
+  call initialise_timing("timing.txt")
+
+  ! Read parameter files
+  call initialise_timer(t_readparam,"t_readparam")
+  call start_timer(t_readparam)
+  if (i_am_master_mpi) then
+    write(STDOUT,*) "Reading parameters from file '" // &
+                    trim(parameterfile) // "'"
+  end if
+  call read_general_parameters(parameterfile,savefields)
+  call read_solver_parameters(parameterfile,solver_param)
+  call read_grid_parameters_mnh(parameterfile,grid_param,KN,KNZ,PL,PH)
+  call read_comm_parameters(parameterfile,comm_param)
+  call read_model_parameters(parameterfile,model_param)
+  call read_smoother_parameters(parameterfile,smoother_param)
+  call read_multigrid_parameters(parameterfile,mg_param)
+  call read_conjugategradient_parameters(parameterfile,cg_param)
+  call finish_timer(t_readparam)
+
+  if (i_am_master_mpi) then
+    write(STDOUT,*) ''
+  end if
+
+  ! Initialise discretisation module
+  call discretisation_initialise_mnh(grid_param,     &
+                                 model_param,    &
+                                 smoother_param, &
+                                 mg_param%n_lev, &
+                                 PA_K,PB_K,PC_K,PD_K )
+
+  ! Initialise communication module
+  call initialise_timer(t_initialise,"t_initialise")
+  call start_timer(t_initialise)
+  call comm_initialise(mg_param%n_lev,     &
+                       mg_param%lev_split, &
+                       grid_param,         &
+                       comm_param)
+
+  ! Initialise multigrid
+  call mg_initialise(grid_param,       &
+                     comm_param,       &
+                     model_param,      &
+                     smoother_param,   &
+                     mg_param,         &
+                     cg_param          &
+                    )
+
+  call create_scalar3d(MPI_COMM_HORIZ,grid_param,comm_param%halo_size,xu_fine)
+  call create_scalar3d(MPI_COMM_HORIZ,grid_param,comm_param%halo_size,xb_fine)
+  call create_scalar3d(MPI_COMM_HORIZ,grid_param,comm_param%halo_size,xr_fine)
+ 
+!!$  call  mg_initialise_rhs_mnh()
+
+  call finish_timer(t_initialise)
+  if (i_am_master_mpi) then
+    write(STDOUT,*) ''
+  end if
+
+end subroutine mg_init_mnh
+
+subroutine mg_init()
+
+implicit none
+
+ ! Initialise MPI ...
+  call mpi_init(ierr)
+
+  ! ... and pre initialise communication module
+  call comm_preinitialise()
+
+    parameterfile="parameters_mg.nam"
+
+  if (i_am_master_mpi) then
+    write(STDOUT,*) ''
+    write(STDOUT,*) 'Compile time parameters:'
+    write(STDOUT,*) ''
+#ifdef CARTESIANGEOMETRY
+    write(STDOUT,*) '  Geometry: Cartesian'
+#else
+    write(STDOUT,*) '  Geometry: Spherical'
+#endif
+#ifdef USELAPACK
+    write(STDOUT,*) '  Use Lapack: Yes'
+#else
+    write(STDOUT,*) '  Use Lapack: No'
+#endif
+#ifdef OVERLAPCOMMS
+    write(STDOUT,*) '  Overlap communications and calculation: Yes'
+#else
+    write(STDOUT,*) '  Overlap communications and calculation: No'
+#endif
+    write(STDOUT,*) ''
+
+  end if
+
+  ! Initialise timing module
+  call initialise_timing("timing.txt")
+
+  ! Read parameter files
+  call initialise_timer(t_readparam,"t_readparam")
+  call start_timer(t_readparam)
+  if (i_am_master_mpi) then
+    write(STDOUT,*) "Reading parameters from file '" // &
+                    trim(parameterfile) // "'"
+  end if
+  call read_general_parameters(parameterfile,savefields)
+  call read_solver_parameters(parameterfile,solver_param)
+  call read_grid_parameters(parameterfile,grid_param)
+  call read_comm_parameters(parameterfile,comm_param)
+  call read_model_parameters(parameterfile,model_param)
+  call read_smoother_parameters(parameterfile,smoother_param)
+  call read_multigrid_parameters(parameterfile,mg_param)
+  call read_conjugategradient_parameters(parameterfile,cg_param)
+  call finish_timer(t_readparam)
+
+  if (i_am_master_mpi) then
+    write(STDOUT,*) ''
+  end if
+
+  ! Initialise discretisation module
+  call discretisation_initialise(grid_param,     &
+                                 model_param,    &
+                                 smoother_param, &
+                                 mg_param%n_lev )
+
+  ! Initialise communication module
+  call initialise_timer(t_initialise,"t_initialise")
+  call start_timer(t_initialise)
+  call comm_initialise(mg_param%n_lev,     &
+                       mg_param%lev_split, &
+                       grid_param,         &
+                       comm_param)
+
+  ! Initialise multigrid
+  call mg_initialise(grid_param,       &
+                     comm_param,       &
+                     model_param,      &
+                     smoother_param,   &
+                     mg_param,         &
+                     cg_param          &
+                    )
+
+  call create_scalar3d(MPI_COMM_HORIZ,grid_param,comm_param%halo_size,xu_fine)
+  call create_scalar3d(MPI_COMM_HORIZ,grid_param,comm_param%halo_size,xb_fine)
+  call create_scalar3d(MPI_COMM_HORIZ,grid_param,comm_param%halo_size,xr_fine)
+  call initialise_rhs(grid_param,model_param,xb_fine)
+#ifdef TESTCONVERGENCE
+  call create_scalar3d(MPI_COMM_HORIZ,grid_param,comm_param%halo_size,uerror)
+  call analytical_solution(grid_param,uerror)
+#endif
+  call finish_timer(t_initialise)
+  if (i_am_master_mpi) then
+    write(STDOUT,*) ''
+  end if
+
+end subroutine mg_init
+
+subroutine mg_finalize()
+
+implicit none
+
+#ifdef TESTCONVERGENCE
+  call daxpy_scalar3d(-1.0_rl,xu_fine,uerror)
+  call haloswap(mg_param%n_lev,pproc,uerror)
+  l2error = l2norm(uerror)
+  if (i_am_master_mpi) then
+    write(STDOUT,'("||error|| = ",E20.12," log_2(||error||) = ",E20.12)') &
+      l2error, log(l2error)/log(2.0_rl)
+  end if
+#endif
+
+#ifdef TESTCONVERGENCE
+  if (savefields) then
+    call save_scalar3d(MPI_COMM_HORIZ,uerror,"error")
+  end if
+#endif
+
+  ! Save fields to disk
+  if (savefields) then
+    call haloswap(mg_param%n_lev,pproc,xu_fine)
+    call save_scalar3d(MPI_COMM_HORIZ,xu_fine,"solution")
+    call volscale_scalar3d(xb_fine,1)
+    call calculate_residual(mg_param%n_lev,pproc,xb_fine,xu_fine,xr_fine)
+    call volscale_scalar3d(xb_fine,-1)
+    call volscale_scalar3d(xr_fine,-1)
+    call haloswap(mg_param%n_lev,pproc,xr_fine)
+    call save_scalar3d(MPI_COMM_HORIZ,xr_fine,"residual")
+  end if
+
+  if (i_am_master_mpi) then
+    write(STDOUT,*) ''
+  end if
+
+  call discretisation_finalise()
+
+  ! Finalise
+  call initialise_timer(t_finalise,"t_finalise")
+  call start_timer(t_finalise)
+  call mg_finalise()
+  call cg_finalise()
+  ! Deallocate memory
+  call destroy_scalar3d(xu_fine)
+  call destroy_scalar3d(xb_fine)
+  call destroy_scalar3d(xr_fine)
+#ifdef TESTCONVERGENCE
+  call destroy_scalar3d(uerror)
+#endif
+
+
+  ! Finalise communications ...
+  call comm_finalise(mg_param%n_lev,mg_param%lev_split,grid_param)
+  call finish_timer(t_finalise)
+  call print_timerinfo("# --- Main timing results ---")
+  call print_elapsed(t_readparam,.true.,1.0_rl)
+  call print_elapsed(t_initialise,.true.,1.0_rl)
+  call print_elapsed(t_solve,.true.,1.0_rl)
+  call print_elapsed(t_finalise,.true.,1.0_rl)
+  ! Finalise timing
+  call finalise_timing()
+  ! ... and MPI
+  call mpi_finalize(ierr)
+
+
+end subroutine mg_finalize
+
+end module mode_mg
diff --git a/src/ZSOLVER/tensorproductmultigrid_Source/mode_mg_read_param.f90 b/src/ZSOLVER/tensorproductmultigrid_Source/mode_mg_read_param.f90
new file mode 100644
index 0000000000000000000000000000000000000000..63c7f5ff7a00cc85146093b2641d84209fb2867d
--- /dev/null
+++ b/src/ZSOLVER/tensorproductmultigrid_Source/mode_mg_read_param.f90
@@ -0,0 +1,561 @@
+!=== COPYRIGHT AND LICENSE STATEMENT ===
+!
+!  This file is part of the TensorProductMultigrid code.
+!  
+!  (c) The copyright relating to this work is owned jointly by the
+!  Crown, Met Office and NERC [2014]. However, it has been created
+!  with the help of the GungHo Consortium, whose members are identified
+!  at https://puma.nerc.ac.uk/trac/GungHo/wiki .
+!  
+!  Main Developer: Eike Mueller
+!  
+!  TensorProductMultigrid is free software: you can redistribute it and/or
+!  modify it under the terms of the GNU Lesser General Public License as
+!  published by the Free Software Foundation, either version 3 of the
+!  License, or (at your option) any later version.
+!  
+!  TensorProductMultigrid is distributed in the hope that it will be useful,
+!  but WITHOUT ANY WARRANTY; without even the implied warranty of
+!  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+!  GNU Lesser General Public License for more details.
+!  
+!  You should have received a copy of the GNU Lesser General Public License
+!  along with TensorProductMultigrid (see files COPYING and COPYING.LESSER).
+!  If not, see <http://www.gnu.org/licenses/>.
+!
+!=== COPYRIGHT AND LICENSE STATEMENT ===
+
+module mode_mg_read_param
+
+contains
+
+!==================================================================
+! Read general parameters from namelist file
+!==================================================================
+subroutine read_general_parameters(filename,savefields_out)
+  use parameters
+  use communication
+  use messages
+#ifndef MNH
+  use mpi
+#else
+  use modd_mpif
+#endif 
+  implicit none
+  character(*), intent(in) :: filename
+  logical, intent(out) :: savefields_out
+  integer, parameter :: file_id = 16
+  logical :: savefields
+  integer :: ierr
+  namelist /parameters_general/ savefields
+  if (i_am_master_mpi) then
+    open(file_id,file=filename)
+    read(file_id,NML=parameters_general)
+    close(file_id)
+    write(STDOUT,NML=parameters_general)
+    write(STDOUT,'("---------------------------------------------- ")')
+    write(STDOUT,'("General parameters")')
+    write(STDOUT,'("    Save fields = ",L6)') savefields
+    write(STDOUT,'("---------------------------------------------- ")')
+    write(STDOUT,'("")')
+  end if
+  call mpi_bcast(savefields,1,MPI_LOGICAL,master_rank,MPI_COMM_WORLD,ierr)
+  savefields_out = savefields
+end subroutine read_general_parameters
+
+!==================================================================
+! Read solver parameters from namelist file
+!==================================================================
+subroutine read_solver_parameters(filename,solver_param_out)
+  use solver
+  use parameters
+  use communication
+  use messages
+#ifndef MNH
+  use mpi
+#else
+  use modd_mpif
+#endif
+  implicit none
+  character(*), intent(in) :: filename
+  type(solver_parameters), intent(out) :: solver_param_out
+  integer :: solvertype
+  real(kind=rl) :: resreduction
+  integer :: maxiter
+  integer, parameter :: file_id = 16
+  integer :: ierr
+  namelist /parameters_solver/ solvertype,resreduction, maxiter &
+                               ,  LUseO , LUseT , LMean
+  if (i_am_master_mpi) then
+    open(file_id,file=filename)
+    read(file_id,NML=parameters_solver)
+    close(file_id)
+    write(STDOUT,NML=parameters_solver)
+    write(STDOUT,'("---------------------------------------------- ")')
+    write(STDOUT,'("  LMean = ",L8)') LMean
+    write(STDOUT,'("  LUseO = ",L8)') LUseO
+    write(STDOUT,'("  LUseT = ",L8)') LUseT
+    write(STDOUT,'("Solver parameters ")')
+    if (solvertype == SOLVER_RICHARDSON) then
+      write(STDOUT,'("    solver       = Richardson")')
+    else if (solvertype == SOLVER_CG) then
+      write(STDOUT,'("    solver       = CG")')
+    else
+      call fatalerror("Unknown solver type")
+    end if
+    write(STDOUT,'("    maxiter      = ",I8)') maxiter
+    write(STDOUT,'("    resreduction = ",E15.6)') resreduction
+    write(STDOUT,'("---------------------------------------------- ")')
+    write(*,'("")')
+  end if
+  call mpi_bcast(solvertype,1,MPI_INTEGER,master_rank,MPI_COMM_WORLD,ierr)
+  call mpi_bcast(maxiter,1,MPI_INTEGER,master_rank,MPI_COMM_WORLD,ierr)
+  call mpi_bcast(resreduction,1,MPI_DOUBLE_PRECISION,master_rank,MPI_COMM_WORLD,ierr)
+  call mpi_bcast(LMean,1,MPI_LOGICAL,master_rank,MPI_COMM_WORLD,ierr)
+  call mpi_bcast(LUseO,1,MPI_LOGICAL,master_rank,MPI_COMM_WORLD,ierr)
+  call mpi_bcast(LUseT,1,MPI_LOGICAL,master_rank,MPI_COMM_WORLD,ierr)
+  solver_param_out%solvertype = solvertype
+  solver_param_out%maxiter = maxiter
+  solver_param_out%resreduction = resreduction
+end subroutine read_solver_parameters
+
+!==================================================================
+! Read grid parameters from namelist file
+!==================================================================
+subroutine read_grid_parameters_mnh(filename,grid_param,KN,KNZ,PL,PH)
+  use parameters
+  use datatypes
+  use communication
+  use messages
+#ifndef MNH
+  use mpi
+#else
+  use modd_mpif
+#endif 
+  implicit none
+  character(*), intent(in) :: filename
+  type(grid_parameters), intent(out) :: grid_param
+
+  integer       , optional , intent (in) :: KN,KNZ
+  real(kind=rl) , optional , intent (in) :: PL,PH
+
+  ! Grid parameters
+  integer :: n, nz
+  real(kind=rl) :: L, H
+  integer :: vertbc
+  logical :: graded
+  integer, parameter :: file_id = 106
+  integer :: ierr
+  namelist /parameters_grid/ n, nz, L, H, vertbc, graded
+  if (i_am_master_mpi) then
+    open(file_id,file=filename)
+    read(file_id,NML=parameters_grid)
+    close(file_id)
+
+    if (vertbc == VERTBC_DIRICHLET) then
+      write(STDOUT,'("    vertbc = DIRICHLET")')
+    else if (vertbc == VERTBC_NEUMANN) then
+      write(STDOUT,'("    vertbc = NEUMANN")')
+    else
+      vertbc = -1
+    end if
+    write(STDOUT,'("    graded =",L3)') graded
+    write(STDOUT,'("---------------------------------------------- ")')
+    write(STDOUT,'("")')
+  end if
+  call mpi_bcast(n,1,MPI_INTEGER,master_rank,MPI_COMM_WORLD,ierr)
+  call mpi_bcast(nz,1,MPI_INTEGER,master_rank,MPI_COMM_WORLD,ierr)
+  call mpi_bcast(L,1,MPI_DOUBLE_PRECISION,master_rank,MPI_COMM_WORLD,ierr)
+  call mpi_bcast(H,1,MPI_DOUBLE_PRECISION,master_rank,MPI_COMM_WORLD,ierr)
+  call mpi_bcast(vertbc,1,MPI_INTEGER,master_rank,MPI_COMM_WORLD,ierr)
+  call mpi_bcast(graded,1,MPI_LOGICAL,master_rank,MPI_COMM_WORLD,ierr)
+  IF (PRESENT(KN)) THEN
+     n = KN
+     nz = KNZ
+     L = PL
+     H = PH
+  END IF
+  if (i_am_master_mpi) then
+    write(STDOUT,NML=parameters_grid)
+    write(STDOUT,'("---------------------------------------------- ")')
+    write(STDOUT,'("Grid parameters")')
+    write(STDOUT,'("    n      = ",I15)') n
+    write(STDOUT,'("    nz     = ",I15)') nz
+    write(STDOUT,'("    L      = ",E15.6)') L
+    write(STDOUT,'("    H      = ",E15.6)') H
+  end if
+  grid_param%n = n
+  grid_param%nz = nz
+  grid_param%L = L
+  grid_param%H = H
+  grid_param%vertbc = vertbc
+  grid_param%graded = graded
+  if (vertbc == -1) then
+    call fatalerror("vertbc has to be either 1 (Dirichlet) or 2 (Neumann)")
+  end if
+end subroutine read_grid_parameters_mnh
+!==================================================================
+! Read grid parameters from namelist file
+!==================================================================
+subroutine read_grid_parameters(filename,grid_param)
+  use parameters
+  use datatypes
+  use communication
+  use messages
+#ifndef MNH
+  use mpi
+#else
+  use modd_mpif
+#endif
+  
+  implicit none
+  character(*), intent(in) :: filename
+  type(grid_parameters), intent(out) :: grid_param
+  ! Grid parameters
+  integer :: n, nz
+  real(kind=rl) :: L, H
+  integer :: vertbc
+  logical :: graded
+  integer, parameter :: file_id = 16
+  integer :: ierr
+  namelist /parameters_grid/ n, nz, L, H, vertbc, graded
+  if (i_am_master_mpi) then
+    open(file_id,file=filename)
+    read(file_id,NML=parameters_grid)
+    close(file_id)
+    write(STDOUT,NML=parameters_grid)
+    write(STDOUT,'("---------------------------------------------- ")')
+    write(STDOUT,'("Grid parameters")')
+    write(STDOUT,'("    n      = ",I15)') n
+    write(STDOUT,'("    nz     = ",I15)') nz
+    write(STDOUT,'("    L      = ",E15.6)') L
+    write(STDOUT,'("    H      = ",E15.6)') H
+    if (vertbc == VERTBC_DIRICHLET) then
+      write(STDOUT,'("    vertbc = DIRICHLET")')
+    else if (vertbc == VERTBC_NEUMANN) then
+      write(STDOUT,'("    vertbc = NEUMANN")')
+    else
+      vertbc = -1
+    end if
+    write(STDOUT,'("    graded =",L3)') graded
+    write(STDOUT,'("---------------------------------------------- ")')
+    write(STDOUT,'("")')
+  end if
+  call mpi_bcast(n,1,MPI_INTEGER,master_rank,MPI_COMM_WORLD,ierr)
+  call mpi_bcast(nz,1,MPI_INTEGER,master_rank,MPI_COMM_WORLD,ierr)
+  call mpi_bcast(L,1,MPI_DOUBLE_PRECISION,master_rank,MPI_COMM_WORLD,ierr)
+  call mpi_bcast(H,1,MPI_DOUBLE_PRECISION,master_rank,MPI_COMM_WORLD,ierr)
+  call mpi_bcast(vertbc,1,MPI_INTEGER,master_rank,MPI_COMM_WORLD,ierr)
+  call mpi_bcast(graded,1,MPI_LOGICAL,master_rank,MPI_COMM_WORLD,ierr)
+  grid_param%n = n
+  grid_param%nz = nz
+  grid_param%L = L
+  grid_param%H = H
+  grid_param%vertbc = vertbc
+  grid_param%graded = graded
+  if (vertbc == -1) then
+    call fatalerror("vertbc has to be either 1 (Dirichlet) or 2 (Neumann)")
+  end if
+end subroutine read_grid_parameters
+!==================================================================
+! Read parallel communication parameters from namelist file
+!==================================================================
+subroutine read_comm_parameters(filename,comm_param)
+  use parameters
+  use communication
+  use messages
+#ifndef MNH
+  use mpi
+#else
+  use modd_mpif
+#endif 
+  implicit none
+  character(*), intent(in) :: filename
+  type(comm_parameters), intent(out) :: comm_param
+  ! Grid parameters
+  integer :: halo_size
+  integer, parameter :: file_id = 16
+  integer :: ierr
+  namelist /parameters_communication/ halo_size
+  if (i_am_master_mpi) then
+    open(file_id,file=filename)
+    read(file_id,NML=parameters_communication)
+    close(file_id)
+    write(STDOUT,NML=parameters_communication)
+    write(STDOUT,'("---------------------------------------------- ")')
+    write(STDOUT,'("Communication parameters")')
+    write(STDOUT,'("    halosize  = ",I3)') halo_size
+    write(STDOUT,'("---------------------------------------------- ")')
+    write(STDOUT,'("")')
+    if ( (halo_size .ne. 1) ) then
+      halo_size = -1
+    end if
+  end if
+  call mpi_bcast(halo_size,1,MPI_INTEGER,master_rank,MPI_COMM_WORLD,ierr)
+  comm_param%halo_size = halo_size
+  if (halo_size == -1) then
+    call fatalerror("Halo size has to be 1.")
+  end if
+end subroutine read_comm_parameters
+
+!==================================================================
+! Read model parameters from namelist file
+!==================================================================
+subroutine read_model_parameters(filename,model_param)
+  use parameters
+  use discretisation
+  use communication
+  use messages
+#ifndef MNH
+  use mpi
+#else
+  use modd_mpif
+#endif 
+  implicit none
+  character(*), intent(in) :: filename
+  type(model_parameters), intent(out) :: model_param
+  real(kind=rl) :: omega2, lambda2, delta
+  integer, parameter :: file_id = 16
+  integer :: ierr
+  namelist /parameters_model/ omega2, lambda2, delta
+  if (i_am_master_mpi) then
+    open(file_id,file=filename)
+    read(file_id,NML=parameters_model)
+    close(file_id)
+    write(STDOUT,NML=parameters_model)
+    write(STDOUT,'("---------------------------------------------- ")')
+    write(STDOUT,'("Model parameters")')
+    write(STDOUT,'("    omega2  = ",E15.6)') omega2
+    write(STDOUT,'("    lambda2 = ",E15.6)') lambda2
+    write(STDOUT,'("    delta   = ",E15.6)') delta
+    write(STDOUT,'("---------------------------------------------- ")')
+    write(STDOUT,'("")')
+  end if
+  call mpi_bcast(omega2,1,MPI_DOUBLE_PRECISION,master_rank,MPI_COMM_WORLD,ierr)
+  call mpi_bcast(lambda2,1,MPI_DOUBLE_PRECISION,master_rank,MPI_COMM_WORLD,ierr)
+  call mpi_bcast(delta,1,MPI_DOUBLE_PRECISION,master_rank,MPI_COMM_WORLD,ierr)
+  model_param%omega2 = omega2
+  model_param%lambda2 = lambda2
+  model_param%delta = delta
+end subroutine read_model_parameters
+
+!==================================================================
+! Read smoother parameters from namelist file
+!==================================================================
+subroutine read_smoother_parameters(filename,smoother_param)
+  use parameters
+  use discretisation
+  use communication
+  use messages
+#ifndef MNH
+  use mpi
+#else
+  use modd_mpif
+#endif
+  implicit none
+  character(*), intent(in) :: filename
+  type(smoother_parameters), intent(out) :: smoother_param
+  integer, parameter :: file_id = 16
+  integer :: smoother, ordering
+  real(kind=rl) :: rho
+  integer :: ierr
+  namelist /parameters_smoother/ smoother,           &
+                                  ordering,           &
+                                  rho
+  if (i_am_master_mpi) then
+    open(file_id,file=filename)
+    read(file_id,NML=parameters_smoother)
+    close(file_id)
+    write(STDOUT,NML=parameters_smoother)
+
+    write(STDOUT,'("---------------------------------------------- ")')
+    write(STDOUT,'("Smoother parameters")')
+    ! Smoother
+    if (smoother == SMOOTHER_LINE_SOR) then
+      write(STDOUT,'("    smoother      = LINE_SOR")')
+    else if (smoother == SMOOTHER_LINE_SSOR) then
+      write(STDOUT,'("    smoother      = LINE_SSOR")')
+    else if (smoother == SMOOTHER_LINE_JAC) then
+      write(STDOUT,'("    smoother      = LINE_JACOBI")')
+    else
+      smoother = -1
+    end if
+
+    if (ordering == ORDERING_LEX) then
+      write(STDOUT,'("    ordering      = LEX")')
+    else if (ordering == ORDERING_RB) then
+      write(STDOUT,'("    ordering      = RB")')
+    else
+      ordering = -1
+    end if
+    write(STDOUT,'("    rho = ",E15.6)') rho
+    write(STDOUT,'("---------------------------------------------- ")')
+    write(STDOUT,'("")')
+  end if
+  call mpi_bcast(smoother,1,MPI_INTEGER,master_rank,MPI_COMM_WORLD,ierr)
+  call mpi_bcast(ordering,1,MPI_INTEGER,master_rank,MPI_COMM_WORLD,ierr)
+  call mpi_bcast(rho,1,MPI_DOUBLE_PRECISION,master_rank,MPI_COMM_WORLD,ierr)
+  smoother_param%smoother = smoother
+  smoother_param%ordering = ordering
+  smoother_param%rho = rho
+  if (smoother == -1) then
+    call fatalerror('Unknown smoother.')
+  end if
+  if (ordering == -1) then
+    call fatalerror('Unknown ordering.')
+  end if
+
+end subroutine read_smoother_parameters
+
+!==================================================================
+! Read multigrid parameters from namelist file
+!==================================================================
+subroutine read_multigrid_parameters(filename,mg_param)
+  use parameters
+  use multigrid
+  use communication
+  use messages
+#ifndef MNH
+  use mpi
+#else
+  use modd_mpif
+#endif 
+  implicit none
+  character(*), intent(in) :: filename
+  type(mg_parameters), intent(out) :: mg_param
+  integer, parameter :: file_id = 16
+  integer :: verbose, n_lev, lev_split, n_presmooth, n_postsmooth,    &
+             prolongation, restriction, n_coarsegridsmooth, &
+             coarsegridsolver
+  integer :: ierr
+  namelist /parameters_multigrid/ verbose,            &
+                                  n_lev,              &
+                                  lev_split,          &
+                                  n_presmooth,        &
+                                  n_postsmooth,       &
+                                  n_coarsegridsmooth, &
+                                  prolongation,       &
+                                  restriction,        &
+                                  coarsegridsolver
+  if (i_am_master_mpi) then
+    open(file_id,file=filename)
+    read(file_id,NML=parameters_multigrid)
+    close(file_id)
+    write(STDOUT,NML=parameters_multigrid)
+    write(STDOUT,'("---------------------------------------------- ")')
+    write(STDOUT,'("Multigrid parameters")')
+    write(STDOUT,'("    verbose      = ",L6)') verbose
+    write(STDOUT,'("    levels       = ",I3)') n_lev
+    write(STDOUT,'("    splitlevel   = ",I3)') lev_split
+    write(STDOUT,'("    n_presmooth  = ",I6)') n_presmooth
+    write(STDOUT,'("    n_postsmooth = ",I6)') n_postsmooth
+    if (restriction == REST_CELLAVERAGE) then
+      write(STDOUT,'("    restriction   = CELLAVERAGE")')
+   else if (restriction == REST_KHALIL) then
+      write(STDOUT,'("    restriction   = KHALIL ")')
+    else
+      restriction = -1
+    endif
+    if (prolongation == PROL_CONSTANT) then
+      write(STDOUT,'("    prolongation  = CONSTANT")')
+    else if (prolongation == PROL_TRILINEAR) then
+#ifdef PIECEWISELINEAR
+      write(STDOUT,'("    prolongation  = TRILINEAR (piecewise linear)")')
+#else
+      write(STDOUT,'("    prolongation  = TRILINEAR (regression plane)")')
+#endif
+    else
+      prolongation = -1
+    endif
+    if (coarsegridsolver == COARSEGRIDSOLVER_CG) then
+      write(STDOUT,'("    coarse solver = CG")')
+    else if (coarsegridsolver == COARSEGRIDSOLVER_SMOOTHER) then
+      write(STDOUT,'("    coarse solver = SMOOTHER (",I6," iterations)")') &
+        n_coarsegridsmooth
+    else
+      coarsegridsolver = -1
+    end if
+    write(STDOUT,'("---------------------------------------------- ")')
+    write(*,'("")')
+
+  end if
+  call mpi_bcast(verbose,1,MPI_INTEGER,master_rank,MPI_COMM_WORLD,ierr)
+  call mpi_bcast(n_lev,1,MPI_INTEGER,master_rank,MPI_COMM_WORLD,ierr)
+  call mpi_bcast(lev_split,1,MPI_INTEGER,master_rank,MPI_COMM_WORLD,ierr)
+  call mpi_bcast(n_presmooth,1,MPI_INTEGER,master_rank,MPI_COMM_WORLD,ierr)
+  call mpi_bcast(n_postsmooth,1,MPI_INTEGER,master_rank,MPI_COMM_WORLD,ierr)
+  call mpi_bcast(n_coarsegridsmooth,1,MPI_INTEGER,master_rank,MPI_COMM_WORLD, &
+                 ierr)
+  call mpi_bcast(prolongation,1,MPI_INTEGER,master_rank,MPI_COMM_WORLD,ierr)
+  call mpi_bcast(restriction,1,MPI_INTEGER,master_rank,MPI_COMM_WORLD,ierr)
+  call mpi_bcast(coarsegridsolver,1,MPI_Integer,master_rank,MPI_COMM_WORLD,ierr)
+  mg_param%verbose = verbose
+  mg_param%n_lev = n_lev
+  mg_param%lev_split = lev_split
+  mg_param%n_presmooth = n_presmooth
+  mg_param%n_postsmooth = n_postsmooth
+  mg_param%n_coarsegridsmooth = n_coarsegridsmooth
+  mg_param%prolongation = prolongation
+  mg_param%restriction = restriction
+  mg_param%coarsegridsolver = coarsegridsolver
+  if (restriction == -1) then
+    call fatalerror('Unknown restriction.')
+  end if
+  if (prolongation == -1) then
+    call fatalerror('Unknown prolongation.')
+  end if
+  if (coarsegridsolver == -1) then
+    call fatalerror('Unknown coarse grid solver.')
+  end if
+end subroutine read_multigrid_parameters
+
+!==================================================================
+! Read conjugate gradient parameters from namelist file
+!==================================================================
+subroutine read_conjugategradient_parameters(filename,cg_param)
+  use parameters
+  use communication
+  use conjugategradient
+  use communication
+  use messages
+#ifndef MNH
+  use mpi
+#else
+  use modd_mpif
+#endif 
+  implicit none
+  character(*), intent(in) :: filename
+  type(cg_parameters), intent(out) :: cg_param
+  integer, parameter :: file_id = 16
+  integer :: verbose, maxiter, n_prec
+  real(kind=rl) :: resreduction
+  integer :: ierr
+  namelist /parameters_conjugategradient/ verbose,      &
+                                          maxiter,      &
+                                          resreduction, &
+                                          n_prec
+  if (i_am_master_mpi) then
+    open(file_id,file=filename)
+    read(file_id,NML=parameters_conjugategradient)
+    close(file_id)
+    write(STDOUT,NML=parameters_conjugategradient)
+    write(STDOUT,'("---------------------------------------------- ")')
+    write(STDOUT,'("Conjugate gradient parameters")')
+    write(STDOUT,'("    verbose       = ",I6)') verbose
+    write(STDOUT,'("    maxiter       = ",I6)') maxiter
+    write(STDOUT,'("    resreduction  = ",E15.6)') resreduction
+    write(STDOUT,'("    n_prec        = ",I6)') n_prec
+    write(STDOUT,'("---------------------------------------------- ")')
+    write(STDOUT,'("")')
+  end if
+  call mpi_bcast(verbose,1,MPI_INTEGER,master_rank,MPI_COMM_WORLD,ierr)
+  call mpi_bcast(maxiter,1,MPI_INTEGER,master_rank,MPI_COMM_WORLD,ierr)
+  call mpi_bcast(resreduction,1,MPI_DOUBLE_PRECISION,master_rank,MPI_COMM_WORLD,ierr)
+  call mpi_bcast(n_prec,1,MPI_INTEGER,master_rank,MPI_COMM_WORLD,ierr)
+  cg_param%verbose = verbose
+  cg_param%maxiter = maxiter
+  cg_param%resreduction = resreduction
+  cg_param%n_prec = n_prec
+end subroutine read_conjugategradient_parameters
+
+end module mode_mg_read_param
diff --git a/src/ZSOLVER/tensorproductmultigrid_Source/multigrid.f90 b/src/ZSOLVER/tensorproductmultigrid_Source/multigrid.f90
new file mode 100644
index 0000000000000000000000000000000000000000..d00404df25f62bc23ed6844d84f92a913cd9ad39
--- /dev/null
+++ b/src/ZSOLVER/tensorproductmultigrid_Source/multigrid.f90
@@ -0,0 +1,1892 @@
+!=== COPYRIGHT AND LICENSE STATEMENT ===
+!
+!  This file is part of the TensorProductMultigrid code.
+!  
+!  (c) The copyright relating to this work is owned jointly by the
+!  Crown, Met Office and NERC [2014]. However, it has been created
+!  with the help of the GungHo Consortium, whose members are identified
+!  at https://puma.nerc.ac.uk/trac/GungHo/wiki .
+!  
+!  Main Developer: Eike Mueller
+!  
+!  TensorProductMultigrid is free software: you can redistribute it and/or
+!  modify it under the terms of the GNU Lesser General Public License as
+!  published by the Free Software Foundation, either version 3 of the
+!  License, or (at your option) any later version.
+!  
+!  TensorProductMultigrid is distributed in the hope that it will be useful,
+!  but WITHOUT ANY WARRANTY; without even the implied warranty of
+!  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+!  GNU Lesser General Public License for more details.
+!  
+!  You should have received a copy of the GNU Lesser General Public License
+!  along with TensorProductMultigrid (see files COPYING and COPYING.LESSER).
+!  If not, see <http://www.gnu.org/licenses/>.
+!
+!=== COPYRIGHT AND LICENSE STATEMENT ===
+
+
+!==================================================================
+!
+!  Geometric multigrid module for cell centred finite volume
+!  discretisation.
+!
+!    Eike Mueller, University of Bath, Feb 2012
+!
+!==================================================================
+module multigrid
+
+#ifndef MNH
+  use mpi
+#else
+  use modd_mpif
+#endif
+  use parameters
+  use datatypes
+  use discretisation
+  use messages
+  use solver
+  use conjugategradient
+  use communication
+  use timer
+
+  implicit none
+
+public::mg_parameters
+public::mg_initialise
+public::mg_finalise
+public::mg_solve_mnh
+public::mg_solve
+public::measurehaloswap
+public::REST_CELLAVERAGE
+public::REST_KHALIL
+public::PROL_CONSTANT
+public::PROL_TRILINEAR
+public::COARSEGRIDSOLVER_SMOOTHER
+public::COARSEGRIDSOLVER_CG
+
+private
+
+  ! --- multigrid parameter constants ---
+  ! restriction
+  integer, parameter :: REST_CELLAVERAGE = 1
+  integer, parameter :: REST_KHALIL      = 2
+  ! prolongation method
+  integer, parameter :: PROL_CONSTANT = 1
+  integer, parameter :: PROL_TRILINEAR = 2
+  ! Coarse grid solver
+  integer, parameter :: COARSEGRIDSOLVER_SMOOTHER = 1
+  integer, parameter :: COARSEGRIDSOLVER_CG = 2
+
+  ! --- Multigrid parameters type ---
+  type mg_parameters
+    ! Verbosity level
+    integer :: verbose
+    ! Number of MG levels
+    integer :: n_lev
+    ! First level where data is pulled together
+    integer :: lev_split
+    ! Number of presmoothing steps
+    integer :: n_presmooth
+    ! Number of postsmoothing steps
+    integer :: n_postsmooth
+    ! Number of smoothing steps on coarsest level
+    integer :: n_coarsegridsmooth
+    ! Prolongation (see PROL_... for allowed values)
+    integer :: prolongation
+    ! Restriction (see RESTR_... for allowed values)
+    integer :: restriction
+    ! Smoother (see SMOOTHER_... for allowed values)
+    integer :: smoother
+    ! Relaxation factor
+    real(kind=rl) :: omega
+    ! Smoother on coarse grid
+    integer :: coarsegridsolver
+    ! ordering of grid points for smoother
+    integer :: ordering
+  end type mg_parameters
+
+! --- Parameters ---
+  type(mg_parameters) :: mg_param
+  type(model_parameters) :: model_param
+  type(smoother_parameters) :: smoother_param
+  type(grid_parameters) :: grid_param
+  type(comm_parameters) :: comm_param
+  type(cg_parameters) :: cg_param
+
+
+! --- Gridded and scalar data structures ---
+  ! Solution vector
+  type(scalar3d), allocatable :: xu_mg(:,:)
+  ! RHS vector
+  type(scalar3d), allocatable :: xb_mg(:,:)
+  ! residual
+  type(scalar3d), allocatable :: xr_mg(:,:)
+
+! --- Timer ---
+  type(time), allocatable, dimension(:,:) :: t_restrict
+  type(time), allocatable, dimension(:,:) :: t_prolongate
+  type(time), allocatable, dimension(:,:) :: t_residual
+  type(time), allocatable, dimension(:,:) :: t_addcorr
+  type(time), allocatable, dimension(:,:) :: t_smooth
+  type(time), allocatable, dimension(:,:) :: t_coarsesolve
+  type(time), allocatable, dimension(:,:) :: t_total
+
+contains
+
+!==================================================================
+! Initialise multigrid module, check and print out out parameters
+!==================================================================
+  subroutine mg_initialise(grid_param_in,     &  ! Grid parameters
+                           comm_param_in,     &  ! Comm parameters
+                           model_param_in,    &  ! Model parameters
+                           smoother_param_in, &  ! Smoother parameters
+                           mg_param_in,       &  ! Multigrid parameters
+                           cg_param_in        &  ! CG parameters
+                           )
+    implicit none
+    type(grid_parameters), intent(in)  :: grid_param_in
+    type(comm_parameters), intent(in)  :: comm_param_in
+    type(model_parameters), intent(in) :: model_param_in
+    type(smoother_parameters), intent(in) :: smoother_param_in
+    type(mg_parameters), intent(in)    :: mg_param_in
+    type(cg_parameters), intent(in)    :: cg_param_in
+    real(kind=rl)                      :: L, H
+    integer                            :: n, nz, m, nlocal
+    logical                            :: reduced_m
+    integer                            :: level
+    integer                            :: rank, ierr
+    integer, dimension(2)              :: p_horiz
+    integer, parameter                 :: dim_horiz = 2
+    logical                            :: grid_active
+    integer                            :: ix_min, ix_max, iy_min, iy_max
+    integer                            :: icompx_min, icompx_max, &
+                                          icompy_min, icompy_max
+    integer                            :: halo_size
+    integer                            :: vertbc
+    character(len=32)                  :: t_label
+
+
+
+    if (i_am_master_mpi) &
+      write(STDOUT,*) '*** Initialising multigrid ***'
+    ! Check that cell counts are valid
+    grid_param = grid_param_in
+    comm_param = comm_param_in
+    mg_param = mg_param_in
+    model_param = model_param_in
+    smoother_param = smoother_param_in
+    cg_param = cg_param_in
+    halo_size = comm_param%halo_size
+    vertbc = grid_param%vertbc
+
+    ! Check parameters
+    if (grid_param%n < 2**(mg_param%n_lev-1) ) then
+      call fatalerror('Number of cells in x-/y- direction has to be at least 2^{n_lev-1}.')
+    endif
+
+    if (mod(grid_param%n,2**(mg_param%n_lev-1)) .ne. 0 ) then
+      call fatalerror('Number of cells in x-/y- direction is not a multiple of 2^{n_lev-1}.')
+    end if
+    if (i_am_master_mpi) &
+      write(STDOUT,*) ''
+
+    ! Allocate memory for timers
+    allocate(t_smooth(mg_param%n_lev,0:pproc))
+    allocate(t_total(mg_param%n_lev,0:pproc))
+    allocate(t_restrict(mg_param%n_lev,0:pproc))
+    allocate(t_residual(mg_param%n_lev,0:pproc))
+    allocate(t_prolongate(mg_param%n_lev,0:pproc))
+    allocate(t_addcorr(mg_param%n_lev,0:pproc))
+    allocate(t_coarsesolve(mg_param%n_lev,0:pproc))
+
+    ! Allocate memory for all levels and initialise fields
+    allocate(xu_mg(mg_param%n_lev,0:pproc))
+    allocate(xb_mg(mg_param%n_lev,0:pproc))
+    allocate(xr_mg(mg_param%n_lev,0:pproc))
+    n = grid_param%n
+    nlocal = n/(2**pproc)
+    nz = grid_param%nz
+    L = grid_param%L
+    H = grid_param%H
+    level = mg_param%n_lev
+    m = pproc
+    reduced_m = .false.
+    ! Work out local processor coordinates (this is necessary to identify
+    ! global coordinates)
+    call mpi_comm_rank(MPI_COMM_HORIZ,rank,ierr)
+    call mpi_cart_coords(MPI_COMM_HORIZ,rank,dim_horiz,p_horiz,ierr)
+    if (i_am_master_mpi) then
+      write(STDOUT, &
+        '(" Global gridsize (x,y,z) (pproc = ",I4," )      : ",I8," x ",I8," x ",I8)') &
+        pproc, n, n, nz
+    end if
+    do while (level > 0)
+      if (i_am_master_mpi) &
+        write(STDOUT, &
+          '(" Local gridsize (x,y,z) on level ",I3," m = ",I4," : ",I8," x ",I8," x ",I8)') &
+          level, m, nlocal, nlocal, nz
+      if (nlocal < 1) then
+        call fatalerror('Number of grid points < 1')
+      end if
+
+      ! Set sizes of computational grid (take care at boundaries)
+      if (p_horiz(1) == 0) then
+        icompy_min = 1
+      else
+        icompy_min = 1 - (halo_size - 1)
+      end if
+
+      if (p_horiz(2) == 0) then
+        icompx_min = 1
+      else
+        icompx_min = 1 - (halo_size - 1)
+      end if
+
+      if (p_horiz(1) == 2**pproc-1) then
+        icompy_max = nlocal
+      else
+        icompy_max = nlocal + (halo_size - 1)
+      end if
+
+      if (p_horiz(2) == 2**pproc-1) then
+        icompx_max = nlocal
+      else
+        icompx_max = nlocal + (halo_size - 1)
+      end if
+
+      ! Allocate data
+      if (LUseO) then
+      allocate(xu_mg(level,m)%s(0:nz+1,                       &
+                            1-halo_size:nlocal+halo_size, &
+                            1-halo_size:nlocal+halo_size))
+      allocate(xb_mg(level,m)%s(0:nz+1,                       &
+                            1-halo_size:nlocal+halo_size, &
+                            1-halo_size:nlocal+halo_size))
+      allocate(xr_mg(level,m)%s(0:nz+1,                       &
+                            1-halo_size:nlocal+halo_size, &
+                            1-halo_size:nlocal+halo_size))
+      xu_mg(level,m)%s(:,:,:) = 0.0_rl
+      xb_mg(level,m)%s(:,:,:) = 0.0_rl
+      xr_mg(level,m)%s(:,:,:) = 0.0_rl
+      endif
+
+      if (LUseT) then
+      allocate(xu_mg(level,m)%st(1-halo_size:nlocal+halo_size, &
+                                 1-halo_size:nlocal+halo_size, &
+                                 0:nz+1))
+      allocate(xb_mg(level,m)%st(1-halo_size:nlocal+halo_size, &
+                                 1-halo_size:nlocal+halo_size, &
+                                 0:nz+1))
+      allocate(xr_mg(level,m)%st(1-halo_size:nlocal+halo_size, &
+                                 1-halo_size:nlocal+halo_size, &
+                                 0:nz+1))
+      xu_mg(level,m)%st(:,:,:) = 0.0_rl
+      xb_mg(level,m)%st(:,:,:) = 0.0_rl
+      xr_mg(level,m)%st(:,:,:) = 0.0_rl
+      endif
+
+      ! NB: 1st coordinate is in the y-direction of the processor grid,
+      ! second coordinate is in the x-direction (see comments in
+      ! communication module)
+      iy_min = (p_horiz(1)/2**(pproc-m))*nlocal+1
+      iy_max = (p_horiz(1)/2**(pproc-m)+1)*nlocal
+      ix_min = p_horiz(2)/2**(pproc-m)*nlocal+1
+      ix_max = (p_horiz(2)/2**(pproc-m)+1)*nlocal
+      ! Set grid parameters and local data ranges
+      ! Note that only n (and possibly nz) change as we
+      ! move down the levels
+      xu_mg(level,m)%grid_param%L = L
+      xu_mg(level,m)%grid_param%H = H
+      xu_mg(level,m)%grid_param%n = n
+      xu_mg(level,m)%grid_param%nz = nz
+      xu_mg(level,m)%grid_param%vertbc = vertbc
+      xu_mg(level,m)%ix_min = ix_min
+      xu_mg(level,m)%ix_max = ix_max
+      xu_mg(level,m)%iy_min = iy_min
+      xu_mg(level,m)%iy_max = iy_max
+      xu_mg(level,m)%icompx_min = icompx_min
+      xu_mg(level,m)%icompx_max = icompx_max
+      xu_mg(level,m)%icompy_min = icompy_min
+      xu_mg(level,m)%icompy_max = icompy_max
+      xu_mg(level,m)%halo_size = halo_size
+
+      xb_mg(level,m)%grid_param%L = L
+      xb_mg(level,m)%grid_param%H = H
+      xb_mg(level,m)%grid_param%n = n
+      xb_mg(level,m)%grid_param%nz = nz
+      xb_mg(level,m)%grid_param%vertbc = vertbc
+      xb_mg(level,m)%ix_min = ix_min
+      xb_mg(level,m)%ix_max = ix_max
+      xb_mg(level,m)%iy_min = iy_min
+      xb_mg(level,m)%iy_max = iy_max
+      xb_mg(level,m)%icompx_min = icompx_min
+      xb_mg(level,m)%icompx_max = icompx_max
+      xb_mg(level,m)%icompy_min = icompy_min
+      xb_mg(level,m)%icompy_max = icompy_max
+      xb_mg(level,m)%halo_size = halo_size
+
+      xr_mg(level,m)%grid_param%L = L
+      xr_mg(level,m)%grid_param%H = H
+      xr_mg(level,m)%grid_param%n = n
+      xr_mg(level,m)%grid_param%nz = nz
+      xr_mg(level,m)%grid_param%vertbc = vertbc
+      xr_mg(level,m)%ix_min = ix_min
+      xr_mg(level,m)%ix_max = ix_max
+      xr_mg(level,m)%iy_min = iy_min
+      xr_mg(level,m)%iy_max = iy_max
+      xr_mg(level,m)%icompx_min = icompx_min
+      xr_mg(level,m)%icompx_max = icompx_max
+      xr_mg(level,m)%icompy_min = icompy_min
+      xr_mg(level,m)%icompy_max = icompy_max
+      xr_mg(level,m)%halo_size = halo_size
+
+      ! Are these grids active?
+      if ( (m == pproc) .or. &
+           ( (mod(p_horiz(1),2**(pproc-m)) == 0) .and. &
+             (mod(p_horiz(2),2**(pproc-m)) == 0) ) ) then
+        grid_active = .true.
+      else
+        grid_active = .false.
+      end if
+      xu_mg(level,m)%isactive = grid_active
+      xb_mg(level,m)%isactive = grid_active
+      xr_mg(level,m)%isactive = grid_active
+      write(t_label,'("t_total(",I3,",",I3,")")') level, m
+      call initialise_timer(t_total(level,m),t_label)
+      write(t_label,'("t_smooth(",I3,",",I3,")")') level, m
+      call initialise_timer(t_smooth(level,m),t_label)
+      write(t_label,'("t_restrict(",I3,",",I3,")")') level, m
+      call initialise_timer(t_restrict(level,m),t_label)
+      write(t_label,'("t_residual(",I3,",",I3,")")') level, m
+      call initialise_timer(t_residual(level,m),t_label)
+      write(t_label,'("t_prolongate(",I3,",",I3,")")') level, m
+      call initialise_timer(t_prolongate(level,m),t_label)
+      write(t_label,'("t_addcorrection(",I3,",",I3,")")') level, m
+      call initialise_timer(t_addcorr(level,m),t_label)
+      write(t_label,'("t_coarsegridsolver(",I3,",",I3,")")') level, m
+      call initialise_timer(t_coarsesolve(level,m),t_label)
+
+      ! If we are below L_split, split data
+      if ( (level .le. mg_param%lev_split) .and. &
+           (m > 0) .and. (.not. reduced_m) ) then
+        reduced_m = .true.
+        m = m-1
+        nlocal = 2*nlocal
+        cycle
+      end if
+      reduced_m = .false.
+      level = level-1
+      n = n/2
+      nlocal = nlocal/2
+    end do
+    if (i_am_master_mpi) &
+      write(STDOUT,*) ''
+    call cg_initialise(cg_param)
+  end subroutine mg_initialise
+
+!==================================================================
+! Finalise, free memory for all data structures
+!==================================================================
+  subroutine mg_finalise()
+    implicit none
+    integer :: level, m
+    logical :: reduced_m
+    character(len=80) :: s
+    integer :: ierr
+
+    if (i_am_master_mpi) &
+      write(STDOUT,*) '*** Finalising multigrid ***'
+    ! Deallocate memory
+    level = mg_param%n_lev
+    m = pproc
+    reduced_m = .false.
+    call print_timerinfo("--- V-cycle timing results ---")
+    do while (level > 0)
+      write(s,'("level = ",I3,", m = ",I3)') level,m
+      call print_timerinfo(s)
+      call print_elapsed(t_smooth(level,m),.True.,1.0_rl)
+      call print_elapsed(t_restrict(level,m),.True.,1.0_rl)
+      call print_elapsed(t_prolongate(level,m),.True.,1.0_rl)
+      call print_elapsed(t_residual(level,m),.True.,1.0_rl)
+      call print_elapsed(t_addcorr(level,m),.True.,1.0_rl)
+      call print_elapsed(t_coarsesolve(level,m),.True.,1.0_rl)
+      call print_elapsed(t_total(level,m),.True.,1.0_rl)
+
+      if (LUseO) then
+      deallocate(xu_mg(level,m)%s)
+      deallocate(xb_mg(level,m)%s)
+      deallocate(xr_mg(level,m)%s)
+      endif
+
+      if (LUseT) then
+      deallocate(xu_mg(level,m)%st)
+      deallocate(xb_mg(level,m)%st)
+      deallocate(xr_mg(level,m)%st)
+      endif
+
+      ! If we are below L_split, split data
+      if ( (level .le. mg_param%lev_split) .and. &
+           (m > 0) .and. (.not. reduced_m) ) then
+        reduced_m = .true.
+        m = m-1
+        cycle
+      end if
+      reduced_m = .false.
+      level = level-1
+    end do
+    deallocate(xu_mg)
+    deallocate(xb_mg)
+    deallocate(xr_mg)
+    deallocate(t_total)
+    deallocate(t_smooth)
+    deallocate(t_restrict)
+    deallocate(t_prolongate)
+    deallocate(t_residual)
+    deallocate(t_addcorr)
+    deallocate(t_coarsesolve)
+      if (i_am_master_mpi) write(STDOUT,'("")')
+  end subroutine mg_finalise
+
+!==================================================================
+! Restrict from fine -> coarse
+!==================================================================
+  subroutine restrict_mnh(phifine,phicoarse)
+    implicit none
+    type(scalar3d), intent(in)    :: phifine
+    type(scalar3d), intent(inout) :: phicoarse
+    ! local var
+    integer :: ix,iy,iz
+    integer :: ix_min, ix_max, iy_min, iy_max, n
+    real(kind=rl) :: xn,xs,xw,xe
+
+    real , dimension(:,:,:) , pointer :: zphifine_st , zphicoarse_st
+
+    n      = phicoarse%grid_param%n
+    ix_min = phicoarse%icompx_min
+    ix_max = phicoarse%icompx_max
+    iy_min = phicoarse%icompy_min
+    iy_max = phicoarse%icompy_max
+    ! three dimensional cell average
+    if (mg_param%restriction == REST_CELLAVERAGE) then
+      ! Do not coarsen in z-direction
+      if (LUseO) then 
+      do ix=ix_min,ix_max
+        do iy=iy_min,iy_max
+          do iz=1,phicoarse%grid_param%nz
+            phicoarse%s(iz,iy,ix) =  &
+              phifine%s(iz  ,2*iy  ,2*ix  ) + &
+              phifine%s(iz  ,2*iy-1,2*ix  ) + &
+              phifine%s(iz  ,2*iy  ,2*ix-1) + &
+              phifine%s(iz  ,2*iy-1,2*ix-1)
+          end do
+        end do
+      end do
+      endif
+      if (LUseT) then 
+         zphifine_st => phifine%st
+         zphicoarse_st => phicoarse%st
+         !$acc kernels loop independent dtype(nvidia) collapse(3)
+         do iz=1,phicoarse%grid_param%nz
+            do iy=iy_min,iy_max
+               do ix=ix_min,ix_max
+                  zphicoarse_st(ix,iy,iz) =  &
+                       zphifine_st(2*ix  ,2*iy  ,iz) + &
+                       zphifine_st(2*ix  ,2*iy-1,iz) + &
+                       zphifine_st(2*ix-1,2*iy  ,iz) + &
+                       zphifine_st(2*ix-1,2*iy-1,iz)
+               end do
+            end do
+         end do
+         !$acc end kernels
+      endif
+
+   elseif(mg_param%restriction == REST_KHALIL) then
+      if (LUseO) then 
+         do ix=ix_min,ix_max
+            xw=1.0
+            xe=1.0
+            if (ix==1) xw=0.0
+            if (ix==n) xe=0.0
+            do iy=iy_min,iy_max
+               xs=1.0
+               xn=1.0
+               if (iy==1) xs=0.0
+               if (iy==n) xn=0.0
+               do iz=1,phicoarse%grid_param%nz
+                  phicoarse%s(iz,iy,ix) = 0.25_rl *         ( &
+                       phifine%s(iz,2*iy+1,2*ix-1) * xn        + &
+                       phifine%s(iz,2*iy+1,2*ix  ) * xn        + &
+                       phifine%s(iz,2*iy  ,2*ix-2) * xw        + &
+                       phifine%s(iz,2*iy  ,2*ix-1) * (4-xw-xn) + &
+                       phifine%s(iz,2*iy  ,2*ix  ) * (4-xe-xn) + &
+                       phifine%s(iz,2*iy  ,2*ix+1) * xe        + &
+                       phifine%s(iz,2*iy-1,2*ix-2) * xw        + &
+                       phifine%s(iz,2*iy-1,2*ix-1) * (4-xw-xs) + &
+                       phifine%s(iz,2*iy-1,2*ix  ) * (4-xe-xs) + &
+                       phifine%s(iz,2*iy-2,2*ix-1) * xs        + &
+                       phifine%s(iz,2*iy-2,2*ix  ) * xs          &     
+                       & )   
+               end do
+            end do
+         end do
+      end if
+      if (LUseT) then 
+         do iz=1,phicoarse%grid_param%nz
+            do iy=iy_min,iy_max
+               xs=1.0
+               xn=1.0
+               if (iy==1) xs=0.0
+               if (iy==n) xn=0.0
+               do ix=ix_min,ix_max
+                  xw=1.0
+                  xe=1.0
+                  if (ix==1) xw=0.0
+                  if (ix==n) xe=0.0
+                  phicoarse%st(ix,iy,iz) = 0.25_rl *         ( &
+                       phifine%s(2*ix-1,2*iy+1,iz) * xn        + &
+                       phifine%s(2*ix  ,2*iy+1,iz) * xn        + &
+                       phifine%s(2*ix-2,2*iy  ,iz) * xw        + &
+                       phifine%s(2*ix-1,2*iy  ,iz) * (4-xw-xn) + &
+                       phifine%s(2*ix  ,2*iy  ,iz) * (4-xe-xn) + &
+                       phifine%s(2*ix+1,2*iy  ,iz) * xe        + &
+                       phifine%s(2*ix-2,2*iy-1,iz) * xw        + &
+                       phifine%s(2*ix-1,2*iy-1,iz) * (4-xw-xs) + &
+                       phifine%s(2*ix  ,2*iy-1,iz) * (4-xe-xs) + &
+                       phifine%s(2*ix-1,2*iy-2,iz) * xs        + &
+                       phifine%s(2*ix  ,2*iy-2,iz) * xs          &     
+                       & )                
+               end do
+            end do
+         end do
+      end if
+      
+    end if
+  end subroutine restrict_mnh
+!==================================================================
+! Restrict from fine -> coarse
+!==================================================================
+  subroutine restrict(phifine,phicoarse)
+    implicit none
+    type(scalar3d), intent(in)    :: phifine
+    type(scalar3d), intent(inout) :: phicoarse
+    integer :: ix,iy,iz
+    integer :: ix_min, ix_max, iy_min, iy_max
+
+    ix_min = phicoarse%icompx_min
+    ix_max = phicoarse%icompx_max
+    iy_min = phicoarse%icompy_min
+    iy_max = phicoarse%icompy_max
+    ! three dimensional cell average
+    if (mg_param%restriction == REST_CELLAVERAGE) then
+      ! Do not coarsen in z-direction
+      if (LUseO) then
+         do ix=ix_min,ix_max
+            do iy=iy_min,iy_max
+               do iz=1,phicoarse%grid_param%nz
+                  phicoarse%s(iz,iy,ix) =  &
+                       phifine%s(iz  ,2*iy  ,2*ix  ) + &
+                       phifine%s(iz  ,2*iy-1,2*ix  ) + &
+                       phifine%s(iz  ,2*iy  ,2*ix-1) + &
+                       phifine%s(iz  ,2*iy-1,2*ix-1)
+               end do
+            end do
+         end do
+      end if
+      if (LUseT) then 
+         do iz=1,phicoarse%grid_param%nz
+            do iy=iy_min,iy_max
+               do ix=ix_min,ix_max
+                  phicoarse%st(ix,iy,iz) =  &
+                       phifine%st(2*ix  ,2*iy  ,iz) + &
+                       phifine%st(2*ix  ,2*iy-1,iz) + &
+                       phifine%st(2*ix-1,2*iy  ,iz) + &
+                       phifine%st(2*ix-1,2*iy-1,iz)
+               end do
+            end do
+         end do
+      endif
+   end if
+ end subroutine restrict
+!==================================================================
+! Prolongate from coarse -> fine
+! level, m is the correspong to the fine grid level
+!==================================================================
+  subroutine prolongate_mnh(level,m,phicoarse,phifine)
+    implicit none
+    integer, intent(in) :: level
+    integer, intent(in) :: m
+    type(scalar3d), intent(in) :: phicoarse
+    type(scalar3d), intent(inout) :: phifine
+    real(kind=rl) :: tmp
+    integer :: nlocal
+    integer, dimension(5) :: ixmin, ixmax, iymin, iymax
+    integer :: n, nz
+    integer :: ix, iy, iz
+    integer :: dix, diy, diz
+    real(kind=rl) :: rhox, rhoy, rhoz
+    real(kind=rl) :: rho_i, sigma_j, h, c1, c2
+    logical :: overlap_comms
+    integer, dimension(4) :: send_requests, recv_requests
+    integer, dimension(4) :: send_requestsT, recv_requestsT
+    integer :: ierr
+    integer :: iblock
+
+    ! Needed for interpolation matrix
+#ifdef PIECEWISELINEAR
+#else
+    real(kind=rl) :: dx(4,3), A(3,3), dx_fine(4,2)
+    integer :: i,j,k
+    real(kind=rl) :: dxu(2), grad(2)
+    dx(1,3) = 1.0_rl
+    dx(2,3) = 1.0_rl
+    dx(3,3) = 1.0_rl
+    dx(4,3) = 1.0_rl
+#endif
+
+    nlocal = phicoarse%ix_max-phicoarse%ix_min+1
+    n = phicoarse%grid_param%n
+    nz = phicoarse%grid_param%nz
+
+#ifdef OVERLAPCOMMS
+    overlap_comms = (nlocal > 2)
+#else
+    overlap_comms = .false.
+#endif
+    ! Block 1 (N)
+    ixmin(1) = 1
+    ixmax(1) = nlocal
+    iymin(1) = 1
+    iymax(1) = 1
+    ! Block 2 (S)
+    ixmin(2) = 1
+    ixmax(2) = nlocal
+    iymin(2) = nlocal
+    iymax(2) = nlocal
+    ! Block 3 (W)
+    ixmin(3) = 1
+    ixmax(3) = 1
+    iymin(3) = 2
+    iymax(3) = nlocal-1
+    ! Block 4 (E)
+    ixmin(4) = nlocal
+    ixmax(4) = nlocal
+    iymin(4) = 2
+    iymax(4) = nlocal-1
+    ! Block 5 (INTERIOR)
+    if (overlap_comms) then
+      ixmin(5) = 2
+      ixmax(5) = nlocal-1
+      iymin(5) = 2
+      iymax(5) = nlocal-1
+    else
+      ! If there are no interior cells, do not overlap
+      ! communications and calculations, just loop over interior cells
+      ixmin(5) = 1
+      ixmax(5) = nlocal
+      iymin(5) = 1
+      iymax(5) = nlocal
+    end if
+
+    ! *** Constant prolongation or (tri-) linear prolongation ***
+    if ( (mg_param%prolongation == PROL_CONSTANT) .or. &
+         (mg_param%prolongation == PROL_TRILINEAR) ) then
+      if (overlap_comms) then
+        ! Loop over cells next to boundary (iblock = 1,...,4)
+        do iblock = 1, 4
+          if (mg_param%prolongation == PROL_CONSTANT) then
+            call loop_over_grid_constant_mnh(iblock)
+          end if
+          if (mg_param%prolongation == PROL_TRILINEAR) then
+            call loop_over_grid_linear_mnh(iblock)
+          end if
+        end do
+        ! Initiate halo exchange
+        call ihaloswap_mnh(level,m,phifine,send_requests,recv_requests,send_requestsT,recv_requestsT)
+      end if
+      ! Loop over INTERIOR cells
+      iblock = 5
+      if (mg_param%prolongation == PROL_CONSTANT) then
+        call loop_over_grid_constant_mnh(iblock)
+      end if
+      if (mg_param%prolongation == PROL_TRILINEAR) then
+        call loop_over_grid_linear_mnh(iblock)
+      end if
+      if (overlap_comms) then
+        if (m > 0) then
+          if (LUseO) call mpi_waitall(4,recv_requests, MPI_STATUSES_IGNORE, ierr)
+          if (LUseO) call mpi_waitall(4,send_requests, MPI_STATUSES_IGNORE, ierr)
+          if (LUseT) call mpi_waitall(4,recv_requestsT, MPI_STATUSES_IGNORE, ierr)
+          if (LUseT) call mpi_waitall(4,send_requestsT, MPI_STATUSES_IGNORE, ierr)
+        end if
+      else
+        call haloswap_mnh(level,m,phifine)
+      end if
+    else
+      call fatalerror("Unsupported prolongation.")
+    end if
+
+    contains
+
+    !------------------------------------------------------------------
+    ! The actual loops over the grid for the individual blocks,
+    ! when overlapping calculation and communication
+    !------------------------------------------------------------------
+
+    !------------------------------------------------------------------
+    ! (1) Constant interpolation
+    !------------------------------------------------------------------
+    subroutine loop_over_grid_constant_mnh(iblock)
+      implicit none
+      integer, intent(in) :: iblock
+      integer :: ix,iy,iz
+      
+      if (LUseO) then
+         do ix=ixmin(iblock),ixmax(iblock)
+            do iy=iymin(iblock),iymax(iblock)
+               do dix = -1,0
+                  do diy = -1,0
+                     do iz=1,phicoarse%grid_param%nz
+                        phifine%s(iz,2*iy+diy,2*ix+dix) = phicoarse%s(iz,iy,ix)
+                     end do
+                  end do
+               end do
+            end do
+         end do
+      end if
+     if (LUseT) then
+         do ix=ixmin(iblock),ixmax(iblock)
+            do iy=iymin(iblock),iymax(iblock)
+               do dix = -1,0
+                  do diy = -1,0
+                     do iz=1,phicoarse%grid_param%nz
+                        phifine%st(2*ix+dix,2*iy+diy,iz) = phicoarse%st(ix,iy,iz)
+                     end do
+                  end do
+               end do
+            end do
+         end do
+      end if
+
+    end subroutine loop_over_grid_constant_mnh
+
+    !------------------------------------------------------------------
+    ! (2) Linear interpolation
+    !------------------------------------------------------------------
+    subroutine loop_over_grid_linear_mnh(iblock)
+      implicit none
+      integer, intent(in) :: iblock
+      !local var
+      integer :: ix,iy,iz
+
+      real , dimension(:,:,:) , pointer :: zphifine_st , zphicoarse_st
+
+      ! optimisation for newman MNH case : all coef constant
+      rhox = 0.25_rl
+      rhoy = 0.25_rl
+
+      if (LUseO) then     
+         do ix=ixmin(iblock),ixmax(iblock)
+            do iy=iymin(iblock),iymax(iblock)
+               ! Piecewise linear interpolation
+               do iz=1,phicoarse%grid_param%nz
+                  do dix = -1,0
+                     do diy = -1,0
+                        phifine%s(iz,2*iy+diy,2*ix+dix) =      &
+                             phicoarse%s(iz,iy,ix) +                &
+                             rhox*(phicoarse%s(iz,iy,ix+(2*dix+1))  &
+                             - phicoarse%s(iz,iy,ix)) +       &
+                             rhoy*(phicoarse%s(iz,iy+(2*diy+1),ix)  &
+                             - phicoarse%s(iz,iy,ix))
+                     end do
+                  end do
+               end do
+            end do
+         end do
+      end if
+      if (LUseT) then  
+         ! Piecewise linear interpolation
+         
+         zphifine_st => phifine%st
+         zphicoarse_st => phicoarse%st
+
+         !$acc kernels loop independent dtype(nvidia) collapse(5)
+         do iz=1,phicoarse%grid_param%nz 
+            do diy = -1,0
+               do dix = -1,0
+                  do iy=iymin(iblock),iymax(iblock)
+                     do ix=ixmin(iblock),ixmax(iblock)
+                        zphifine_st(2*ix+dix,2*iy+diy,iz) =      &
+                             zphicoarse_st(ix,iy,iz) +                &
+                             rhox*(zphicoarse_st(ix+(2*dix+1),iy,iz)  &
+                             - zphicoarse_st(ix,iy,iz)) +       &
+                             rhoy*(zphicoarse_st(ix,iy+(2*diy+1),iz)  &
+                             - zphicoarse_st(ix,iy,iz))
+                     end do
+                  end do
+               end do
+            end do
+         end do
+         !$acc end kernels
+      end if
+
+    end subroutine loop_over_grid_linear_mnh
+
+  end subroutine prolongate_mnh
+!==================================================================
+! Prolongate from coarse -> fine
+! level, m is the correspong to the fine grid level
+!==================================================================
+  subroutine prolongate(level,m,phicoarse,phifine)
+    implicit none
+    integer, intent(in) :: level
+    integer, intent(in) :: m
+    type(scalar3d), intent(in) :: phicoarse
+    type(scalar3d), intent(inout) :: phifine
+    real(kind=rl) :: tmp
+    integer :: nlocal
+    integer, dimension(5) :: ixmin, ixmax, iymin, iymax
+    integer :: n, nz
+    integer :: ix, iy, iz
+    integer :: dix, diy, diz
+    real(kind=rl) :: rhox, rhoy, rhoz
+    real(kind=rl) :: rho_i, sigma_j, h, c1, c2
+    logical :: overlap_comms
+    integer, dimension(4) :: send_requests, recv_requests
+    integer :: ierr
+    integer :: iblock
+
+    ! Needed for interpolation matrix
+#ifdef PIECEWISELINEAR
+#else
+    real(kind=rl) :: dx(4,3), A(3,3), dx_fine(4,2)
+    integer :: i,j,k
+    real(kind=rl) :: dxu(2), grad(2)
+    dx(1,3) = 1.0_rl
+    dx(2,3) = 1.0_rl
+    dx(3,3) = 1.0_rl
+    dx(4,3) = 1.0_rl
+#endif
+
+    nlocal = phicoarse%ix_max-phicoarse%ix_min+1
+    n = phicoarse%grid_param%n
+    nz = phicoarse%grid_param%nz
+
+#ifdef OVERLAPCOMMS
+    overlap_comms = (nlocal > 2)
+#else
+    overlap_comms = .false.
+#endif
+    ! Block 1 (N)
+    ixmin(1) = 1
+    ixmax(1) = nlocal
+    iymin(1) = 1
+    iymax(1) = 1
+    ! Block 2 (S)
+    ixmin(2) = 1
+    ixmax(2) = nlocal
+    iymin(2) = nlocal
+    iymax(2) = nlocal
+    ! Block 3 (W)
+    ixmin(3) = 1
+    ixmax(3) = 1
+    iymin(3) = 2
+    iymax(3) = nlocal-1
+    ! Block 4 (E)
+    ixmin(4) = nlocal
+    ixmax(4) = nlocal
+    iymin(4) = 2
+    iymax(4) = nlocal-1
+    ! Block 5 (INTERIOR)
+    if (overlap_comms) then
+      ixmin(5) = 2
+      ixmax(5) = nlocal-1
+      iymin(5) = 2
+      iymax(5) = nlocal-1
+    else
+      ! If there are no interior cells, do not overlap
+      ! communications and calculations, just loop over interior cells
+      ixmin(5) = 1
+      ixmax(5) = nlocal
+      iymin(5) = 1
+      iymax(5) = nlocal
+    end if
+
+    ! *** Constant prolongation or (tri-) linear prolongation ***
+    if ( (mg_param%prolongation == PROL_CONSTANT) .or. &
+         (mg_param%prolongation == PROL_TRILINEAR) ) then
+      if (overlap_comms) then
+        ! Loop over cells next to boundary (iblock = 1,...,4)
+        do iblock = 1, 4
+          if (mg_param%prolongation == PROL_CONSTANT) then
+            call loop_over_grid_constant(iblock)
+          end if
+          if (mg_param%prolongation == PROL_TRILINEAR) then
+            call loop_over_grid_linear(iblock)
+          end if
+        end do
+        ! Initiate halo exchange
+        call ihaloswap(level,m,phifine,send_requests,recv_requests)
+      end if
+      ! Loop over INTERIOR cells
+      iblock = 5
+      if (mg_param%prolongation == PROL_CONSTANT) then
+        call loop_over_grid_constant(iblock)
+      end if
+      if (mg_param%prolongation == PROL_TRILINEAR) then
+        call loop_over_grid_linear(iblock)
+      end if
+      if (overlap_comms) then
+        if (m > 0) then
+          call mpi_waitall(4,recv_requests, MPI_STATUSES_IGNORE, ierr)
+        end if
+      else
+        call haloswap(level,m,phifine)
+      end if
+    else
+      call fatalerror("Unsupported prolongation.")
+    end if
+
+    contains
+
+    !------------------------------------------------------------------
+    ! The actual loops over the grid for the individual blocks,
+    ! when overlapping calculation and communication
+    !------------------------------------------------------------------
+
+    !------------------------------------------------------------------
+    ! (1) Constant interpolation
+    !------------------------------------------------------------------
+    subroutine loop_over_grid_constant(iblock)
+      implicit none
+      integer, intent(in) :: iblock
+      integer :: ix,iy,iz
+      do ix=ixmin(iblock),ixmax(iblock)
+        do iy=iymin(iblock),iymax(iblock)
+          do dix = -1,0
+            do diy = -1,0
+              do iz=1,phicoarse%grid_param%nz
+                phifine%s(iz,2*iy+diy,2*ix+dix) = phicoarse%s(iz,iy,ix)
+              end do
+            end do
+          end do
+        end do
+      end do
+    end subroutine loop_over_grid_constant
+
+    !------------------------------------------------------------------
+    ! (2) Linear interpolation
+    !------------------------------------------------------------------
+    subroutine loop_over_grid_linear(iblock)
+      implicit none
+      integer, intent(in) :: iblock
+      integer :: ix,iy,iz
+      do ix=ixmin(iblock),ixmax(iblock)
+        do iy=iymin(iblock),iymax(iblock)
+#ifdef PIECEWISELINEAR
+          ! Piecewise linear interpolation
+          do iz=1,phicoarse%grid_param%nz
+            do dix = -1,0
+              do diy = -1,0
+                if ( (ix+(2*dix+1)+phicoarse%ix_min-1  < 1 ) .or. &
+                     (ix+(2*dix+1)+phicoarse%ix_min-1  > n ) ) then
+                  rhox = 0.5_rl
+                else
+                  rhox = 0.25_rl
+                end if
+                if ( (iy+(2*diy+1)+phicoarse%iy_min-1  < 1 ) .or. &
+                     (iy+(2*diy+1)+phicoarse%iy_min-1  > n ) ) then
+                  rhoy = 0.5_rl
+                else
+                  rhoy = 0.25_rl
+                end if
+                 phifine%s(iz,2*iy+diy,2*ix+dix) =      &
+                  phicoarse%s(iz,iy,ix) +                &
+                  rhox*(phicoarse%s(iz,iy,ix+(2*dix+1))  &
+                        - phicoarse%s(iz,iy,ix)) +       &
+                  rhoy*(phicoarse%s(iz,iy+(2*diy+1),ix)  &
+                        - phicoarse%s(iz,iy,ix))
+              end do
+            end do
+          end do
+#else
+          ! Fit a plane through the four neighbours of each
+          ! coarse grid point. Use the gradient of this plane and
+          ! the value of the field on the coarse grid point for
+          ! the linear interpolation
+          ! Calculate the displacement vectors
+#ifdef CARTESIANGEOMETRY
+          ! (ix-1, iy)
+          dx(1,1) = -1.0_rl
+          dx(1,2) =  0.0_rl
+          ! (ix+1, iy)
+          dx(2,1) = +1.0_rl
+          dx(2,2) =  0.0_rl
+          ! (ix, iy-1)
+          dx(3,1) =  0.0_rl
+          dx(3,2) = -1.0_rl
+          ! (ix, iy+1)
+          dx(4,1) =  0.0_rl
+          dx(4,2) = +1.0_rl
+#else
+          rho_i = 2.0_rl*(ix+(phicoarse%ix_min-1)-0.5_rl)/n-1.0_rl
+          sigma_j = 2.0_rl*(iy+(phicoarse%iy_min-1)-0.5_rl)/n-1.0_rl
+          if (abs(rho_i**2+sigma_j**2) > 1.0E-12) then
+            c1 = (1.0_rl+rho_i**2+sigma_j**2)/sqrt(rho_i**2+sigma_j**2)
+            c2 = sqrt(1.0_rl+rho_i**2+sigma_j**2)/sqrt(rho_i**2+sigma_j**2)
+          else
+            rho_i = 1.0_rl
+            sigma_j = 1.0_rl
+            c1 = sqrt(0.5_rl)
+            c2 = sqrt(0.5_rl)
+          end if
+          ! (ix-1, iy)
+          dx(1,1) = -c1*rho_i
+          dx(1,2) = +c2*sigma_j
+          ! (ix+1, iy)
+          dx(2,1) = +c1*rho_i
+          dx(2,2) = -c2*sigma_j
+          ! (ix, iy-1)
+          dx(3,1) = -c1*sigma_j
+          dx(3,2) = -c2*rho_i
+          ! (ix, iy+1)
+          dx(4,1) = +c1*sigma_j
+          dx(4,2) = +c2*rho_i
+          dx_fine(1,1) = 0.25_rl*(dx(1,1)+dx(3,1))
+          dx_fine(1,2) = 0.25_rl*(dx(1,2)+dx(3,2))
+          dx_fine(2,1) = 0.25_rl*(dx(2,1)+dx(3,1))
+          dx_fine(2,2) = 0.25_rl*(dx(2,2)+dx(3,2))
+          dx_fine(3,1) = 0.25_rl*(dx(1,1)+dx(4,1))
+          dx_fine(3,2) = 0.25_rl*(dx(1,2)+dx(4,2))
+          dx_fine(4,1) = 0.25_rl*(dx(2,1)+dx(4,1))
+          dx_fine(4,2) = 0.25_rl*(dx(2,2)+dx(4,2))
+#endif
+          ! Boundaries
+          if (ix-1+phicoarse%ix_min-1  < 1 ) then
+            dx(1,1) = 0.5_rl*dx(1,1)
+            dx(1,2) = 0.5_rl*dx(1,2)
+          end if
+          if (ix+1+phicoarse%ix_min-1  > n ) then
+            dx(2,1) = 0.5_rl*dx(2,1)
+            dx(2,2) = 0.5_rl*dx(2,2)
+          end if
+          if (iy-1+phicoarse%iy_min-1  < 1 ) then
+            dx(3,1) = 0.5_rl*dx(3,1)
+            dx(3,2) = 0.5_rl*dx(3,2)
+          end if
+          if (iy+1+phicoarse%iy_min-1  > n ) then
+            dx(4,1) = 0.5_rl*dx(4,1)
+            dx(4,2) = 0.5_rl*dx(4,2)
+          end if
+          ! Calculate matrix used for least squares linear fit
+          A(:,:) = 0.0_rl
+          do i = 1,4
+            do j=1,3
+              do k=1,3
+                A(j,k) = A(j,k) + dx(i,j)*dx(i,k)
+              end do
+            end do
+          end do
+          ! invert A
+          call invertA(A)
+          do iz=1,phicoarse%grid_param%nz
+            ! Calculate gradient on each level
+            dxu(1:2) = dx(1,1:2)*phicoarse%s(iz,iy  ,ix-1) &
+                     + dx(2,1:2)*phicoarse%s(iz,iy  ,ix+1) &
+                     + dx(3,1:2)*phicoarse%s(iz,iy-1,ix  ) &
+                     + dx(4,1:2)*phicoarse%s(iz,iy+1,ix  )
+            grad(:) = 0.0_rl
+            do j=1,2
+              do k=1,2
+                grad(j) = grad(j) + A(j,k)*dxu(k)
+              end do
+            end do
+            ! Use the gradient and the field value in the centre of
+            ! the coarse grid cell to interpolate to the fine grid
+            ! cells
+#ifdef CARTESIANGEOMETRY
+            do dix=-1,0
+              do diy=-1,0
+                phifine%s(iz,2*iy+diy,2*ix+dix) =       &
+                  phicoarse%s(iz,iy,ix)                 &
+                  + 0.25_rl*( grad(1)*(2.0*dix+1)    &
+                            + grad(2)*(2.0*diy+1))
+              end do
+            end do
+#else
+            phifine%s(iz,2*iy-1, 2*ix-1) = phicoarse%s(iz,iy,ix) + &
+                                         ( grad(1)*dx_fine(1,1)  + &
+                                           grad(2)*dx_fine(1,2) )
+            phifine%s(iz,2*iy-1, 2*ix  ) = phicoarse%s(iz,iy,ix) + &
+                                         ( grad(1)*dx_fine(2,1)  + &
+                                           grad(2)*dx_fine(2,2) )
+            phifine%s(iz,2*iy  , 2*ix-1) = phicoarse%s(iz,iy,ix) + &
+                                         ( grad(1)*dx_fine(3,1)  + &
+                                           grad(2)*dx_fine(3,2) )
+            phifine%s(iz,2*iy  , 2*ix  ) = phicoarse%s(iz,iy,ix) + &
+                                         ( grad(1)*dx_fine(4,1)  + &
+                                           grad(2)*dx_fine(4,2) )
+#endif
+          end do
+#endif
+        end do
+      end do
+    end subroutine loop_over_grid_linear
+
+  end subroutine prolongate
+  !------------------------------------------------------------------
+  ! Invert the 3x3 matrix A either using LaPack or the explicit
+  ! formula
+  !------------------------------------------------------------------
+  subroutine invertA(A)
+    implicit none
+    real(kind=rl), intent(inout), dimension(3,3) :: A
+    real(kind=rl), dimension(3,3) :: Anew
+    real(kind=rl) :: invdetA
+    integer :: ipiv(3), info
+    real(kind=rl) :: work(3)
+#ifdef USELAPACK
+    call DGETRF( 3, 3, A, 3, ipiv, info )
+    call DGETRI( 3, A, 3, ipiv, work, 3, info )
+#else
+    invdetA = 1.0_rl / ( A(1,1) * (A(3,3)*A(2,2) - A(3,2)*A(2,3)) &
+                       - A(2,1) * (A(3,3)*A(1,2) - A(3,2)*A(1,3)) &
+                       + A(3,1) * (A(2,3)*A(1,2) - A(2,2)*A(1,3)) )
+    Anew(1,1) =     A(3,3)*A(2,2) - A(3,2)*A(2,3)
+    Anew(1,2) = - ( A(3,3)*A(1,2) - A(3,2)*A(1,3) )
+    Anew(1,3) =     A(2,3)*A(1,2) - A(2,2)*A(1,3)
+    Anew(2,1) = - ( A(3,3)*A(2,1) - A(3,1)*A(2,3) )
+    Anew(2,2) =     A(3,3)*A(1,1) - A(3,1)*A(1,3)
+    Anew(2,3) = - ( A(2,3)*A(1,1) - A(2,1)*A(1,3) )
+    Anew(3,1) =     A(3,2)*A(2,1) - A(3,1)*A(2,2)
+    Anew(3,2) = - ( A(3,2)*A(1,1) - A(3,1)*A(1,2) )
+    Anew(3,3) =     A(2,2)*A(1,1) - A(2,1)*A(1,2)
+    A(:,:) = invdetA*Anew(:,:)
+#endif
+  end subroutine invertA
+
+!==================================================================
+! Multigrid V-cycle
+!==================================================================
+  recursive subroutine mg_vcycle_mnh(b,u,r,finelevel,splitlevel,level,m)
+    implicit none
+    integer, intent(in)                                     :: finelevel
+    type(scalar3d), intent(inout), dimension(finelevel,0:pproc) :: b
+    type(scalar3d), intent(inout), dimension(finelevel,0:pproc) :: u
+    type(scalar3d), intent(inout), dimension(finelevel,0:pproc) :: r
+    integer, intent(in)                                     :: splitlevel
+    integer, intent(in)                                     :: level
+    integer, intent(in)                                     :: m
+    !local var
+    integer                                                 :: n_gridpoints
+    integer                                                 :: nlocalx, nlocaly
+    integer                                                 :: halo_size
+
+     real , dimension(:,:,:) , pointer ::  zu_level_1_m_st
+
+    nlocalx = u(level,m)%ix_max-u(level,m)%ix_min+1
+    nlocaly = u(level,m)%iy_max-u(level,m)%iy_min+1
+    halo_size = u(level,m)%halo_size
+    n_gridpoints = (nlocalx+2*halo_size) &
+                 * (nlocaly+2*halo_size) &
+                 * (u(level,m)%grid_param%nz+2)
+
+    if (level > 1) then
+      ! Perform n_presmooth smoothing steps
+      call start_timer(t_smooth(level,m))
+      call start_timer(t_total(level,m))
+      call smooth_mnh(level,m,mg_param%n_presmooth, &
+                  DIRECTION_FORWARD, &
+                  b(level,m),u(level,m))
+      call finish_timer(t_total(level,m))
+      call finish_timer(t_smooth(level,m))
+      ! Calculate residual
+      call start_timer(t_residual(level,m))
+      call start_timer(t_total(level,m))
+      call calculate_residual_mnh(level,m,b(level,m),u(level,m),r(level,m))
+      call finish_timer(t_total(level,m))
+      call finish_timer(t_residual(level,m))
+      ! Restrict residual
+      call start_timer(t_restrict(level,m))
+      call start_timer(t_total(level,m))
+      call restrict_mnh(r(level,m),b(level-1,m))
+      call finish_timer(t_total(level,m))
+      call finish_timer(t_restrict(level,m))
+      if ( ((level-1) .le. splitlevel) .and. (m > 0) ) then
+        ! Collect data on coarser level
+        call start_timer(t_total(level,m))
+        call collect(level-1,m,b(level-1,m),b(level-1,m-1))
+!!$        call print_scalaprod2(level-1, m  , b(level-1,m)  , "After collect b(level-1,m  )=" )
+!!$        call print_scalaprod2(level-1, m-1, b(level-1,m-1), "After collect b(level-1,m-1)=" )
+        call finish_timer(t_total(level,m))
+        ! Set initial solution on coarser level to zero (incl. halos!)
+        if (LUseO) u(level-1,m-1)%s(:,:,:) = 0.0_rl
+        if (LUseT) u(level-1,m-1)%st(:,:,:) = 0.0_rl
+        ! solve on coarser grid
+        call mg_vcycle_mnh(b,u,r,finelevel,splitlevel,level-1,m-1)
+        ! Distribute data on coarser grid
+        call start_timer(t_total(level,m))
+        call distribute(level-1,m,u(level-1,m-1),u(level-1,m))
+!!$        call print_scalaprod2(level-1, m  , u(level-1,m)  , "After distribute u(level-1,m  )=" )
+!!$        call print_scalaprod2(level-1, m-1, u(level-1,m-1), "After distribute u(level-1,m-1)=" )       
+        call finish_timer(t_total(level,m))
+      else
+        ! Set initial solution on coarser level to zero (incl. halos!)
+        if (LUseO) u(level-1,m)%s(:,:,:) = 0.0_rl
+        if (LUseT) then
+           zu_level_1_m_st =>  u(level-1,m)%st(:,:,:)
+           !$acc kernels 
+           zu_level_1_m_st(:,:,:) = 0.0_rl
+           !$acc end kernels
+        end if
+        ! solve on coarser grid
+        call mg_vcycle_mnh(b,u,r,finelevel,splitlevel,level-1,m)
+      end if
+      ! Prolongate error
+      call start_timer(t_prolongate(level,m))
+      call start_timer(t_total(level,m))
+      call haloswap_mnh(level-1,m,u(level-1,m))
+      call boundary_mnh(u(level-1,m))
+!!$      call print_scalaprod2(level-1 , m  , u(level-1,m)  , "Befor prolongate_mnh u(level-1,m  )=" )
+!!$      call print_scalaprod2(level   , m  , r(level  ,m)  , "Befor prolongate_mnh r(level  ,m  )=" )
+      call prolongate_mnh(level,m,u(level-1,m),r(level,m))
+!!$      call print_scalaprod2(level-1 , m  , u(level-1,m)  , "After prolongate_mnh u(level-1,m  )=" )
+!!$      call print_scalaprod2(level   , m  , r(level  ,m)  , "After prolongate_mnh r(level  ,m  )=" )
+      call finish_timer(t_total(level,m))
+      call finish_timer(t_prolongate(level,m))
+      ! Add error to fine grid solution
+      call start_timer(t_addcorr(level,m))
+      call start_timer(t_total(level,m))
+      if (LUseO) call daxpy(n_gridpoints,1.0_rl,r(level,m)%s,1,u(level,m)%s,1)
+      if (LUseT) call daxpy(n_gridpoints,1.0_rl,r(level,m)%st,1,u(level,m)%st,1)
+      call finish_timer(t_total(level,m))
+      call finish_timer(t_addcorr(level,m))
+      ! Perform n_postsmooth smoothing steps
+      call start_timer(t_smooth(level,m))
+      call start_timer(t_total(level,m))
+      call smooth_mnh(level,m, &
+                  mg_param%n_postsmooth, &
+                  DIRECTION_BACKWARD, &
+                  b(level,m),u(level,m))
+      call finish_timer(t_total(level,m))
+      call finish_timer(t_smooth(level,m))
+    else
+      call start_timer(t_coarsesolve(level,m))
+      call start_timer(t_total(level,m))
+      if (mg_param%coarsegridsolver == COARSEGRIDSOLVER_CG) then
+        call cg_solve_mnh(level,m,b(level,m),u(level,m))
+!!$        call print_scalaprod2(level, m , u(level,m), "After cg_solve_mnh u=(level,m)" )
+      else if (mg_param%coarsegridsolver == COARSEGRIDSOLVER_SMOOTHER) then
+        ! Smooth on coarsest level
+        call smooth_mnh(level,m, &
+                    mg_param%n_coarsegridsmooth,     &
+                    DIRECTION_FORWARD, &
+                    b(level,m),u(level,m))
+      end if
+      call finish_timer(t_total(level,m))
+      call finish_timer(t_coarsesolve(level,m))
+    end if
+
+  end subroutine mg_vcycle_mnh
+!==================================================================
+! Multigrid V-cycle
+!==================================================================
+  recursive subroutine mg_vcycle(b,u,r,finelevel,splitlevel,level,m)
+    implicit none
+    integer, intent(in)                                     :: finelevel
+    type(scalar3d), intent(inout), dimension(finelevel,0:pproc) :: b
+    type(scalar3d), intent(inout), dimension(finelevel,0:pproc) :: u
+    type(scalar3d), intent(inout), dimension(finelevel,0:pproc) :: r
+    integer, intent(in)                                     :: splitlevel
+    integer, intent(in)                                     :: level
+    integer, intent(in)                                     :: m
+    integer                                                 :: n_gridpoints
+    integer                                                 :: nlocalx, nlocaly
+    integer                                                 :: halo_size
+
+    nlocalx = u(level,m)%ix_max-u(level,m)%ix_min+1
+    nlocaly = u(level,m)%iy_max-u(level,m)%iy_min+1
+    halo_size = u(level,m)%halo_size
+    n_gridpoints = (nlocalx+2*halo_size) &
+                 * (nlocaly+2*halo_size) &
+                 * (u(level,m)%grid_param%nz+2)
+
+    if (level > 1) then
+      ! Perform n_presmooth smoothing steps
+      call start_timer(t_smooth(level,m))
+      call start_timer(t_total(level,m))
+      call smooth(level,m,mg_param%n_presmooth, &
+                  DIRECTION_FORWARD, &
+                  b(level,m),u(level,m))
+      call finish_timer(t_total(level,m))
+      call finish_timer(t_smooth(level,m))
+      ! Calculate residual
+      call start_timer(t_residual(level,m))
+      call start_timer(t_total(level,m))
+      call calculate_residual(level,m,b(level,m),u(level,m),r(level,m))
+      call finish_timer(t_total(level,m))
+      call finish_timer(t_residual(level,m))
+      ! Restrict residual
+      call start_timer(t_restrict(level,m))
+      call start_timer(t_total(level,m))
+      call restrict(r(level,m),b(level-1,m))
+      call finish_timer(t_total(level,m))
+      call finish_timer(t_restrict(level,m))
+      if ( ((level-1) .le. splitlevel) .and. (m > 0) ) then
+        ! Collect data on coarser level
+        call start_timer(t_total(level,m))
+        call collect(level-1,m,b(level-1,m),b(level-1,m-1))
+        call haloswap_mnh(level-1,m-1,b(level-1,m-1))
+        call finish_timer(t_total(level,m))
+        ! Set initial solution on coarser level to zero (incl. halos!)
+        if (LUseO) u(level-1,m-1)%s(:,:,:) = 0.0_rl
+        if (LUseT) u(level-1,m-1)%st(:,:,:) = 0.0_rl
+        ! solve on coarser grid
+        call mg_vcycle(b,u,r,finelevel,splitlevel,level-1,m-1)
+        ! Distribute data on coarser grid
+        call start_timer(t_total(level,m))
+        call distribute(level-1,m,u(level-1,m-1),u(level-1,m))
+        call haloswap(level-1,m,u(level-1,m))
+        call finish_timer(t_total(level,m))
+      else
+        ! Set initial solution on coarser level to zero (incl. halos!)
+        if (LUseO) u(level-1,m)%s(:,:,:) = 0.0_rl
+        if (LUseT) u(level-1,m)%st(:,:,:) = 0.0_rl
+        ! solve on coarser grid
+        call mg_vcycle(b,u,r,finelevel,splitlevel,level-1,m)
+      end if
+      ! Prolongate error
+      call start_timer(t_prolongate(level,m))
+      call start_timer(t_total(level,m))
+      call prolongate(level,m,u(level-1,m),r(level,m))
+      call finish_timer(t_total(level,m))
+      call finish_timer(t_prolongate(level,m))
+      ! Add error to fine grid solution
+      call start_timer(t_addcorr(level,m))
+      call start_timer(t_total(level,m))
+      if (LUseO) call daxpy(n_gridpoints,1.0_rl,r(level,m)%s,1,u(level,m)%s,1)
+      if (LUseT) call daxpy(n_gridpoints,1.0_rl,r(level,m)%st,1,u(level,m)%st,1)
+      call finish_timer(t_total(level,m))
+      call finish_timer(t_addcorr(level,m))
+      ! Perform n_postsmooth smoothing steps
+      call start_timer(t_smooth(level,m))
+      call start_timer(t_total(level,m))
+      call smooth(level,m, &
+                  mg_param%n_postsmooth, &
+                  DIRECTION_BACKWARD, &
+                  b(level,m),u(level,m))
+      call finish_timer(t_total(level,m))
+      call finish_timer(t_smooth(level,m))
+    else
+      call start_timer(t_coarsesolve(level,m))
+      call start_timer(t_total(level,m))
+      if (mg_param%coarsegridsolver == COARSEGRIDSOLVER_CG) then
+        call cg_solve(level,m,b(level,m),u(level,m))
+      else if (mg_param%coarsegridsolver == COARSEGRIDSOLVER_SMOOTHER) then
+        ! Smooth on coarsest level
+        call smooth(level,m, &
+                    mg_param%n_coarsegridsmooth,     &
+                    DIRECTION_FORWARD, &
+                    b(level,m),u(level,m))
+      end if
+      call finish_timer(t_total(level,m))
+      call finish_timer(t_coarsesolve(level,m))
+    end if
+
+  end subroutine mg_vcycle
+
+!==================================================================
+! Test halo exchanges
+!==================================================================
+  recursive subroutine mg_vcyclehaloswaponly(b,u,r,finelevel,splitlevel,level,m)
+    implicit none
+    integer, intent(in)                                     :: finelevel
+    type(scalar3d), intent(inout), dimension(finelevel,0:pproc) :: b
+    type(scalar3d), intent(inout), dimension(finelevel,0:pproc) :: u
+    type(scalar3d), intent(inout), dimension(finelevel,0:pproc) :: r
+    integer, intent(in)                                     :: splitlevel
+    integer, intent(in)                                     :: level
+    integer, intent(in)                                     :: m
+    integer, parameter :: nhaloswap = 100
+    integer :: i
+    integer :: ierr
+
+    if (level > 1) then
+      call mpi_barrier(MPI_COMM_HORIZ,ierr)
+      do i=1,nhaloswap
+        call haloswap(level,m,u(level,m))
+      end do
+      call mpi_barrier(MPI_COMM_HORIZ,ierr)
+      if ( ((level-1) .le. splitlevel) .and. (m > 0) ) then
+        call mpi_barrier(MPI_COMM_HORIZ,ierr)
+        do i=1,nhaloswap
+          call haloswap(level-1,m,u(level-1,m))
+        end do
+        call mpi_barrier(MPI_COMM_HORIZ,ierr)
+        call mg_vcyclehaloswaponly(b,u,r,finelevel,splitlevel,level-1,m-1)
+      else
+        call mg_vcyclehaloswaponly(b,u,r,finelevel,splitlevel,level-1,m)
+      end if
+    else
+      ! Haloswap on coarsest level
+      call mpi_barrier(MPI_COMM_HORIZ,ierr)
+      do i=1,nhaloswap
+        call haloswap(level,m,u(level,m))
+      end do
+      call mpi_barrier(MPI_COMM_HORIZ,ierr)
+    end if
+
+  end subroutine mg_vcyclehaloswaponly
+
+!==================================================================
+! Multigrid solve
+! Assumes that ghosts in initial solution are up-to-date
+!==================================================================
+  subroutine mg_solve_mnh(bRHS,usolution,solver_param)
+    implicit none
+    type(scalar3d), intent(in)      :: bRHS
+    type(scalar3d), intent(inout)   :: usolution
+    type(solver_parameters), intent(in) :: solver_param
+    integer :: solvertype
+    real(kind=rl)  :: resreduction
+    integer :: maxiter
+    integer :: n_gridpoints
+    integer :: iter, level, finelevel, splitlevel
+    real(kind=rl) :: res_old, res_new, res_initial , mean_initial , norm_initial
+    logical :: solverconverged = .false.
+    integer :: nlocalx, nlocaly
+    integer :: halo_size
+    type(time) :: t_prec, t_res, t_apply, t_l2norm, t_scalprod, t_mainloop
+    type(scalar3d) :: pp
+    type(scalar3d) :: q
+    type(scalar3d) :: z_one 
+    real(kind=rl) :: alpha, beta, pq, rz, rz_old
+    integer :: ierr
+
+    solvertype = solver_param%solvertype
+    resreduction = solver_param%resreduction
+    maxiter = solver_param%maxiter
+    nlocalx = usolution%ix_max - usolution%ix_min+1
+    nlocaly = usolution%iy_max - usolution%iy_min+1
+    halo_size = usolution%halo_size
+
+    level = mg_param%n_lev
+    finelevel = level
+    splitlevel = mg_param%lev_split
+
+    ! Initialise timers
+    call initialise_timer(t_prec,"t_prec")
+    call initialise_timer(t_apply,"t_apply")
+    call initialise_timer(t_l2norm,"t_l2norm")
+    call initialise_timer(t_scalprod,"t_scalarprod")
+    call initialise_timer(t_res,"t_residual")
+    call initialise_timer(t_mainloop,"t_mainloop")
+
+    n_gridpoints = (nlocalx+2*halo_size) &
+                 * (nlocaly+2*halo_size) &
+                 * (usolution%grid_param%nz+2)
+    !
+    ! Init 1 vector = z_one
+    call create_scalar3d(MPI_COMM_HORIZ,bRHS%grid_param,halo_size,z_one)
+    if (LUseO) then
+       z_one%s(:,:,:) = 0.0_rl
+       z_one%s(1:z_one%grid_param%nz,1:z_one%icompy_max,1:z_one%icompx_max) = 1.0_rl
+    end if
+    if (LUseT) then
+       z_one%st(:,:,:) = 0.0_rl
+       z_one%st(1:z_one%icompx_max,1:z_one%icompy_max,1:z_one%grid_param%nz) = 1.0_rl
+    end if
+    !   Mean / Norm of B
+    call scalarprod_mnh(pproc,z_one,z_one, mean_initial ) 
+    call scalarprod_mnh(pproc,z_one,bRHS, mean_initial ) 
+    norm_initial =  l2norm_mnh(bRHS,.true.)
+    mean_initial =  mean_initial / (( z_one%grid_param%nz ) * ( z_one%grid_param%n )**2)
+    norm_initial =  mean_initial / norm_initial
+    if (LMean) then
+       ! b <- b -mean_initial * z_one
+       if (LUseO) call daxpy(n_gridpoints,-mean_initial,z_one%s,1,bRHS%s,1)
+       if (LUseT) call daxpy(n_gridpoints,-mean_initial,z_one%st,1,bRHS%st,1)
+       call scalarprod_mnh(pproc,z_one,bRHS, mean_initial ) 
+    endif
+    !
+    ! Copy b to b(1)
+    ! Copy usolution to u(1)
+    if (LUseO) call dcopy(n_gridpoints,bRHS%s,1,xb_mg(level,pproc)%s,1)
+    if (LUseT) call dcopy(n_gridpoints,bRHS%st,1,xb_mg(level,pproc)%st,1)
+    if (LUseO) call dcopy(n_gridpoints,usolution%s,1,xu_mg(level,pproc)%s,1)
+    if (LUseT) call dcopy(n_gridpoints,usolution%st,1,xu_mg(level,pproc)%st,1)
+
+! Scale with volume of grid cells
+    call volscale_scalar3d_mnh(xb_mg(level,pproc),1)
+    call scalarprod_mnh(pproc,z_one,xb_mg(level,pproc), mean_initial )
+
+    call start_timer(t_res)
+    call calculate_residual_mnh(level, pproc, &
+                            xb_mg(level,pproc),xu_mg(level,pproc),xr_mg(level,pproc))
+    call finish_timer(t_res)
+    call start_timer(t_l2norm)
+    res_initial = l2norm_mnh(xr_mg(level,pproc),.true.)
+    call finish_timer(t_l2norm)
+    res_old = res_initial
+    if (mg_param%verbose > 0) then
+      if (i_am_master_mpi) then
+        write(STDOUT,'(" *** Multigrid solver ***")')
+        write(STDOUT,'(" <MG> Initial residual : ",E10.5)') res_initial
+      end if
+    end if
+    if (mg_param%verbose > 0) then
+      if (i_am_master_mpi) then
+        write(STDOUT,'(" <MG>   iter :   residual         rho")')
+        write(STDOUT,'(" <MG> --------------------------------")')
+      end if
+    end if
+
+    call mpi_barrier(MPI_COMM_WORLD,ierr)
+    call start_timer(t_mainloop)
+    if (solvertype == SOLVER_CG) then
+      ! NB: b(level,pproc) will be used as r in the following
+      call create_scalar3d(MPI_COMM_HORIZ,bRHS%grid_param,halo_size,pp)
+      call create_scalar3d(MPI_COMM_HORIZ,bRHS%grid_param,halo_size,q)
+      ! Apply preconditioner: Calculate p = M^{-1} r
+      ! (1) copy b <- r
+      if (LUseO) call dcopy(n_gridpoints,xr_mg(level,pproc)%s,1,xb_mg(level,pproc)%s,1)
+      if (LUseT) call dcopy(n_gridpoints,xr_mg(level,pproc)%st,1,xb_mg(level,pproc)%st,1)
+      ! (2) set u <- 0
+      if (LUseO) xu_mg(level,pproc)%s(:,:,:) = 0.0_rl
+      if (LUseT) xu_mg(level,pproc)%st(:,:,:) = 0.0_rl
+      ! (3) Call MG Vcycle
+      call start_timer(t_prec)
+      call mg_vcycle_mnh(xb_mg,xu_mg,xr_mg,finelevel,splitlevel,level,pproc)
+      call finish_timer(t_prec)
+      ! (4) copy pp <- u (=solution from MG Vcycle)
+      if (LUseO) call dcopy(n_gridpoints,xu_mg(level,pproc)%s,1,pp%s,1)
+      if (LUseT) call dcopy(n_gridpoints,xu_mg(level,pproc)%st,1,pp%st,1)
+      ! Calculate rz_old = <pp,b>
+      call start_timer(t_scalprod)
+      call scalarprod_mnh(pproc,pp,xb_mg(level,pproc),rz_old)
+      call finish_timer(t_scalprod)
+      do iter = 1, maxiter
+        ! Apply matrix q <- A.pp
+        call start_timer(t_apply)
+        call apply_mnh(pp,q)
+        call finish_timer(t_apply)
+        ! Calculate pq <- <pp,q>
+        call start_timer(t_scalprod)
+        call scalarprod_mnh(pproc,pp,q,pq)
+        call finish_timer(t_scalprod)
+        alpha = rz_old/pq
+        ! x <- x + alpha*p
+        if (LUseO) call daxpy(n_gridpoints,alpha,pp%s,1,usolution%s,1)
+        if (LUseT) call daxpy(n_gridpoints,alpha,pp%st,1,usolution%st,1)
+        ! b <- b - alpha*q
+        if (LUseO) call daxpy(n_gridpoints,-alpha,q%s,1,xb_mg(level,pproc)%s,1)
+        if (LUseT) call daxpy(n_gridpoints,-alpha,q%st,1,xb_mg(level,pproc)%st,1)
+        ! Calculate norm of residual and exit if it has been
+        ! reduced sufficiently
+        call start_timer(t_l2norm)
+        res_new = l2norm_mnh(xb_mg(level,pproc),.true.)
+        call finish_timer(t_l2norm)
+        if (mg_param%verbose > 1) then
+          if (i_am_master_mpi) then
+            write(STDOUT,'(" <MG> ",I7," : ",E10.5,"  ",F10.5)') iter, res_new, res_new/res_old
+          end if
+        end if
+        if (res_new/res_initial < resreduction) then
+          solverconverged = .true.
+          exit
+        end if
+        res_old = res_new
+        ! Apply preconditioner q <- M^{-1} b
+        ! (1) Initialise solution u <- 0
+        if (LUseO) xu_mg(level,pproc)%s(:,:,:) = 0.0_rl
+        if (LUseT) xu_mg(level,pproc)%st(:,:,:) = 0.0_rl
+        ! (2) Call MG Vcycle
+        call start_timer(t_prec)
+        call mg_vcycle_mnh(xb_mg,xu_mg,xr_mg,finelevel,splitlevel,level,pproc)
+        call finish_timer(t_prec)
+        ! (3) copy q <- u (solution from MG Vcycle)
+        if (LUseO) call dcopy(n_gridpoints,xu_mg(level,pproc)%s,1,q%s,1)
+        if (LUseT) call dcopy(n_gridpoints,xu_mg(level,pproc)%st,1,q%st,1)
+        call start_timer(t_scalprod)
+        call scalarprod_mnh(pproc,q,xb_mg(level,pproc),rz)
+        call finish_timer(t_scalprod)
+        beta = rz/rz_old
+        ! p <- beta*p
+        if (LUseO) call dscal(n_gridpoints,beta,pp%s,1)
+        if (LUseT) call dscal(n_gridpoints,beta,pp%st,1)
+        ! p <- p+q
+        if (LUseO) call daxpy(n_gridpoints,1.0_rl,q%s,1,pp%s,1)
+        if (LUseT) call daxpy(n_gridpoints,1.0_rl,q%st,1,pp%st,1)
+        rz_old = rz
+      end do
+      call destroy_scalar3d(pp)
+      call destroy_scalar3d(q)
+    else if (solvertype == SOLVER_RICHARDSON) then
+      ! Iterate until convergence
+      do iter=1,maxiter
+        call start_timer(t_prec)
+        call mg_vcycle_mnh(xb_mg,xu_mg,xr_mg,finelevel,splitlevel,level,pproc)
+        call finish_timer(t_prec)
+        call start_timer(t_res)
+        ! Ghosts are up-to-date here, so no need for halo exchange
+        call calculate_residual_mnh(level, pproc, &
+                                xb_mg(level,pproc),xu_mg(level,pproc),xr_mg(level,pproc))
+        call finish_timer(t_res)
+        call start_timer(t_l2norm)
+        res_new = l2norm_mnh(xr_mg(level,pproc),.true.)
+        call finish_timer(t_l2norm)
+        if (mg_param%verbose > 1) then
+          if (i_am_master_mpi) then
+            write(STDOUT,'(" <MG> ",I7," : ",E10.5,"  ",F10.5)') iter, res_new, res_new/res_old
+          end if
+        end if
+        if (res_new/res_initial < resreduction) then
+          solverconverged = .true.
+          exit
+        end if
+        res_old = res_new
+      end do
+      ! Copy u(1) to usolution
+      if (LUseO) call dcopy(n_gridpoints,xu_mg(level,pproc)%s,1,usolution%s,1)
+      if (LUseT) call dcopy(n_gridpoints,xu_mg(level,pproc)%st,1,usolution%st,1)
+    end if
+
+    call destroy_scalar3d(z_one)
+
+    call finish_timer(t_mainloop)
+
+    ! Print out solver information
+    if (mg_param%verbose > 0) then
+      if (solverconverged) then
+        if (i_am_master_mpi) then
+          write(STDOUT,'(" <MG> Final residual    ||r|| = ",E12.6)') res_new
+          write(STDOUT,'(" <MG> Solver converged in ",I7," iterations rho_{avg} = ",F10.5)') &
+          iter, (res_new/res_initial)**(1./(iter))
+        end if
+      else
+        if (i_am_master_mpi) then
+          write(STDOUT,'(" <MG> Solver failed to converge after ",I7," iterations rho_{avg} = ",F10.5)') &
+          maxiter, (res_new/res_initial)**(1./(iter))
+        end if
+      end if
+    end if
+    call print_timerinfo("--- Main iteration timing results ---")
+    call print_elapsed(t_apply,.True.,1.0_rl)
+    call print_elapsed(t_res,.True.,1.0_rl)
+    call print_elapsed(t_prec,.True.,1.0_rl)
+    call print_elapsed(t_l2norm,.True.,1.0_rl)
+    call print_elapsed(t_scalprod,.True.,1.0_rl)
+    call print_elapsed(t_mainloop,.True.,1.0_rl)
+    if (i_am_master_mpi) write(STDOUT,'("")')
+  end subroutine mg_solve_mnh
+
+  subroutine mg_solve(bRHS,usolution,solver_param)
+    implicit none
+    type(scalar3d), intent(in)      :: bRHS
+    type(scalar3d), intent(inout)   :: usolution
+    type(solver_parameters), intent(in) :: solver_param
+    integer :: solvertype
+    real(kind=rl)  :: resreduction
+    integer :: maxiter
+    integer :: n_gridpoints
+    integer :: iter, level, finelevel, splitlevel
+    real(kind=rl) :: res_old, res_new, res_initial
+    logical :: solverconverged = .false.
+    integer :: nlocalx, nlocaly
+    integer :: halo_size
+    type(time) :: t_prec, t_res, t_apply, t_l2norm, t_scalprod, t_mainloop
+    type(scalar3d) :: pp
+    type(scalar3d) :: q
+    real(kind=rl) :: alpha, beta, pq, rz, rz_old
+    integer :: ierr
+
+    solvertype = solver_param%solvertype
+    resreduction = solver_param%resreduction
+    maxiter = solver_param%maxiter
+    nlocalx = usolution%ix_max - usolution%ix_min+1
+    nlocaly = usolution%iy_max - usolution%iy_min+1
+    halo_size = usolution%halo_size
+
+    level = mg_param%n_lev
+    finelevel = level
+    splitlevel = mg_param%lev_split
+
+    ! Initialise timers
+    call initialise_timer(t_prec,"t_prec")
+    call initialise_timer(t_apply,"t_apply")
+    call initialise_timer(t_l2norm,"t_l2norm")
+    call initialise_timer(t_scalprod,"t_scalarprod")
+    call initialise_timer(t_res,"t_residual")
+    call initialise_timer(t_mainloop,"t_mainloop")
+
+    ! Copy b to b(1)
+    ! Copy usolution to u(1)
+    n_gridpoints = (nlocalx+2*halo_size) &
+                 * (nlocaly+2*halo_size) &
+                 * (usolution%grid_param%nz+2)
+    call dcopy(n_gridpoints,bRHS%s,1,xb_mg(level,pproc)%s,1)
+    call dcopy(n_gridpoints,usolution%s,1,xu_mg(level,pproc)%s,1)
+! Scale with volume of grid cells
+    call volscale_scalar3d(xb_mg(level,pproc),1)
+    call start_timer(t_res)
+    call calculate_residual(level, pproc, &
+                            xb_mg(level,pproc),xu_mg(level,pproc),xr_mg(level,pproc))
+    call finish_timer(t_res)
+    call start_timer(t_l2norm)
+    res_initial = l2norm(xr_mg(level,pproc),.true.)
+    call finish_timer(t_l2norm)
+    res_old = res_initial
+    if (mg_param%verbose > 0) then
+      if (i_am_master_mpi) then
+        write(STDOUT,'(" *** Multigrid solver ***")')
+        write(STDOUT,'(" <MG> Initial residual : ",E10.5)') res_initial
+      end if
+    end if
+    if (mg_param%verbose > 0) then
+      if (i_am_master_mpi) then
+        write(STDOUT,'(" <MG>   iter :   residual         rho")')
+        write(STDOUT,'(" <MG> --------------------------------")')
+      end if
+    end if
+
+    call mpi_barrier(MPI_COMM_WORLD,ierr)
+    call start_timer(t_mainloop)
+    if (solvertype == SOLVER_CG) then
+      ! NB: b(level,pproc) will be used as r in the following
+      call create_scalar3d(MPI_COMM_HORIZ,bRHS%grid_param,halo_size,pp)
+      call create_scalar3d(MPI_COMM_HORIZ,bRHS%grid_param,halo_size,q)
+      ! Apply preconditioner: Calculate p = M^{-1} r
+      ! (1) copy b <- r
+      call dcopy(n_gridpoints,xr_mg(level,pproc)%s,1,xb_mg(level,pproc)%s,1)
+      ! (2) set u <- 0
+      xu_mg(level,pproc)%s(:,:,:) = 0.0_rl
+      ! (3) Call MG Vcycle
+      call start_timer(t_prec)
+      call mg_vcycle(xb_mg,xu_mg,xr_mg,finelevel,splitlevel,level,pproc)
+      call finish_timer(t_prec)
+      ! (4) copy pp <- u (=solution from MG Vcycle)
+      call dcopy(n_gridpoints,xu_mg(level,pproc)%s,1,pp%s,1)
+      ! Calculate rz_old = <pp,b>
+      call start_timer(t_scalprod)
+      call scalarprod(pproc,pp,xb_mg(level,pproc),rz_old)
+      call finish_timer(t_scalprod)
+      do iter = 1, maxiter
+        ! Apply matrix q <- A.pp
+        call start_timer(t_apply)
+        call apply(pp,q)
+        call finish_timer(t_apply)
+        ! Calculate pq <- <pp,q>
+        call start_timer(t_scalprod)
+        call scalarprod(pproc,pp,q,pq)
+        call finish_timer(t_scalprod)
+        alpha = rz_old/pq
+        ! x <- x + alpha*p
+        call daxpy(n_gridpoints,alpha,pp%s,1,usolution%s,1)
+        ! b <- b - alpha*q
+        call daxpy(n_gridpoints,-alpha,q%s,1,xb_mg(level,pproc)%s,1)
+        ! Calculate norm of residual and exit if it has been
+        ! reduced sufficiently
+        call start_timer(t_l2norm)
+        res_new = l2norm(xb_mg(level,pproc),.true.)
+        call finish_timer(t_l2norm)
+        if (mg_param%verbose > 1) then
+          if (i_am_master_mpi) then
+            write(STDOUT,'(" <MG> ",I7," : ",E10.5,"  ",F10.5)') iter, res_new, res_new/res_old
+          end if
+        end if
+        if (res_new/res_initial < resreduction) then
+          solverconverged = .true.
+          exit
+        end if
+        res_old = res_new
+        ! Apply preconditioner q <- M^{-1} b
+        ! (1) Initialise solution u <- 0
+        xu_mg(level,pproc)%s(:,:,:) = 0.0_rl
+        ! (2) Call MG Vcycle
+        call start_timer(t_prec)
+        call mg_vcycle(xb_mg,xu_mg,xr_mg,finelevel,splitlevel,level,pproc)
+        call finish_timer(t_prec)
+        ! (3) copy q <- u (solution from MG Vcycle)
+        call dcopy(n_gridpoints,xu_mg(level,pproc)%s,1,q%s,1)
+        call start_timer(t_scalprod)
+        call scalarprod(pproc,q,xb_mg(level,pproc),rz)
+        call finish_timer(t_scalprod)
+        beta = rz/rz_old
+        ! p <- beta*p
+        call dscal(n_gridpoints,beta,pp%s,1)
+        ! p <- p+q
+        call daxpy(n_gridpoints,1.0_rl,q%s,1,pp%s,1)
+        rz_old = rz
+      end do
+      call destroy_scalar3d(pp)
+      call destroy_scalar3d(q)
+    else if (solvertype == SOLVER_RICHARDSON) then
+      ! Iterate until convergence
+      do iter=1,maxiter
+        call start_timer(t_prec)
+        call mg_vcycle(xb_mg,xu_mg,xr_mg,finelevel,splitlevel,level,pproc)
+        call finish_timer(t_prec)
+        call start_timer(t_res)
+        ! Ghosts are up-to-date here, so no need for halo exchange
+        call calculate_residual(level, pproc, &
+                                xb_mg(level,pproc),xu_mg(level,pproc),xr_mg(level,pproc))
+        call finish_timer(t_res)
+        call start_timer(t_l2norm)
+        res_new = l2norm(xr_mg(level,pproc),.true.)
+        call finish_timer(t_l2norm)
+        if (mg_param%verbose > 1) then
+          if (i_am_master_mpi) then
+            write(STDOUT,'(" <MG> ",I7," : ",E10.5,"  ",F10.5)') iter, res_new, res_new/res_old
+          end if
+        end if
+        if (res_new/res_initial < resreduction) then
+          solverconverged = .true.
+          exit
+        end if
+        res_old = res_new
+      end do
+      ! Copy u(1) to usolution
+      call dcopy(n_gridpoints,xu_mg(level,pproc)%s,1,usolution%s,1)
+    end if
+    call finish_timer(t_mainloop)
+
+    ! Print out solver information
+    if (mg_param%verbose > 0) then
+      if (solverconverged) then
+        if (i_am_master_mpi) then
+          write(STDOUT,'(" <MG> Final residual    ||r|| = ",E12.6)') res_new
+          write(STDOUT,'(" <MG> Solver converged in ",I7," iterations rho_{avg} = ",F10.5)') &
+          iter, (res_new/res_initial)**(1./(iter))
+        end if
+      else
+        if (i_am_master_mpi) then
+          write(STDOUT,'(" <MG> Solver failed to converge after ",I7," iterations rho_{avg} = ",F10.5)') &
+          maxiter, (res_new/res_initial)**(1./(iter))
+        end if
+      end if
+    end if
+    call print_timerinfo("--- Main iteration timing results ---")
+    call print_elapsed(t_apply,.True.,1.0_rl)
+    call print_elapsed(t_res,.True.,1.0_rl)
+    call print_elapsed(t_prec,.True.,1.0_rl)
+    call print_elapsed(t_l2norm,.True.,1.0_rl)
+    call print_elapsed(t_scalprod,.True.,1.0_rl)
+    call print_elapsed(t_mainloop,.True.,1.0_rl)
+    if (i_am_master_mpi) write(STDOUT,'("")')
+  end subroutine mg_solve
+
+!==================================================================
+! Test haloswap on all levels
+!==================================================================
+  subroutine measurehaloswap()
+    implicit none
+    integer :: iter, level, finelevel, splitlevel
+
+    level = mg_param%n_lev
+    finelevel = level
+    splitlevel = mg_param%lev_split
+    call mg_vcyclehaloswaponly(xb_mg,xu_mg,xr_mg,finelevel,splitlevel,level,pproc)
+  end subroutine measurehaloswap
+
+end module multigrid
+
diff --git a/src/ZSOLVER/tensorproductmultigrid_Source/parameters.f90 b/src/ZSOLVER/tensorproductmultigrid_Source/parameters.f90
new file mode 100644
index 0000000000000000000000000000000000000000..5195982fdeffc44390f2a2fa9fd116f6e0d76660
--- /dev/null
+++ b/src/ZSOLVER/tensorproductmultigrid_Source/parameters.f90
@@ -0,0 +1,64 @@
+!=== COPYRIGHT AND LICENSE STATEMENT ===
+!
+!  This file is part of the TensorProductMultigrid code.
+!  
+!  (c) The copyright relating to this work is owned jointly by the
+!  Crown, Met Office and NERC [2014]. However, it has been created
+!  with the help of the GungHo Consortium, whose members are identified
+!  at https://puma.nerc.ac.uk/trac/GungHo/wiki .
+!  
+!  Main Developer: Eike Mueller
+!  
+!  TensorProductMultigrid is free software: you can redistribute it and/or
+!  modify it under the terms of the GNU Lesser General Public License as
+!  published by the Free Software Foundation, either version 3 of the
+!  License, or (at your option) any later version.
+!  
+!  TensorProductMultigrid is distributed in the hope that it will be useful,
+!  but WITHOUT ANY WARRANTY; without even the implied warranty of
+!  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+!  GNU Lesser General Public License for more details.
+!  
+!  You should have received a copy of the GNU Lesser General Public License
+!  along with TensorProductMultigrid (see files COPYING and COPYING.LESSER).
+!  If not, see <http://www.gnu.org/licenses/>.
+!
+!=== COPYRIGHT AND LICENSE STATEMENT ===
+
+
+!==================================================================
+!
+!  General parameters
+!
+!    Eike Mueller, University of Bath, Feb 2012
+!
+!==================================================================
+
+module parameters
+
+  implicit none
+
+! floating point precision. Always use rl_kind in code
+  integer, parameter :: single_precision=4        ! single precision
+  integer, parameter :: double_precision=8        ! double precision
+  integer, parameter :: rl=double_precision       ! global switch between
+                                                  ! single/double precision
+! NOTE: As we still use BLAS subroutines, these need to be
+!       replaced as well when switching between double and
+!       single precision!
+  real(kind=rl), parameter :: Tolerance = 1.0e-15
+
+! Output units
+  integer, parameter :: STDOUT = 6
+  integer, parameter :: STDERR = 0
+
+! Numerical constants
+  real(kind=rl), parameter :: two_pi = 6.2831853071795862_rl
+
+! Use Original (K,J,I)  or Transposed (I,J,K) array
+  logical :: LUseO = .false.
+  logical :: LUseT = .true. ! .false. ! .true.
+! Remove mean to B = Right Hand side 
+  logical :: LMean = .false.
+
+end module parameters
diff --git a/src/ZSOLVER/tensorproductmultigrid_Source/profiles.f90 b/src/ZSOLVER/tensorproductmultigrid_Source/profiles.f90
new file mode 100644
index 0000000000000000000000000000000000000000..489210645307e67cfc4c21e87f668963db60cbf4
--- /dev/null
+++ b/src/ZSOLVER/tensorproductmultigrid_Source/profiles.f90
@@ -0,0 +1,334 @@
+!=== COPYRIGHT AND LICENSE STATEMENT ===
+!
+!  This file is part of the TensorProductMultigrid code.
+!  
+!  (c) The copyright relating to this work is owned jointly by the
+!  Crown, Met Office and NERC [2014]. However, it has been created
+!  with the help of the GungHo Consortium, whose members are identified
+!  at https://puma.nerc.ac.uk/trac/GungHo/wiki .
+!  
+!  Main Developer: Eike Mueller
+!  
+!  TensorProductMultigrid is free software: you can redistribute it and/or
+!  modify it under the terms of the GNU Lesser General Public License as
+!  published by the Free Software Foundation, either version 3 of the
+!  License, or (at your option) any later version.
+!  
+!  TensorProductMultigrid is distributed in the hope that it will be useful,
+!  but WITHOUT ANY WARRANTY; without even the implied warranty of
+!  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+!  GNU Lesser General Public License for more details.
+!  
+!  You should have received a copy of the GNU Lesser General Public License
+!  along with TensorProductMultigrid (see files COPYING and COPYING.LESSER).
+!  If not, see <http://www.gnu.org/licenses/>.
+!
+!=== COPYRIGHT AND LICENSE STATEMENT ===
+
+
+!==================================================================
+!
+!  Analytical forms of RHS vectors
+!
+!    Eike Mueller, University of Bath, Feb 2012
+!
+!==================================================================
+module profiles
+
+  use communication
+  use parameters
+  use datatypes
+  use discretisation
+
+  implicit none
+
+  public::initialise_u_mnh
+  public::get_u_mnh
+  public::initialise_rhs_mnh
+  public::initialise_rhs
+  public::analytical_solution
+
+private
+  contains
+!==================================================================
+! Initialise U vector
+!==================================================================
+  subroutine initialise_u_mnh(grid_param,model_param,u,KIB,KIE,KIU,KJB,KJE,KJU,KKU,PU)
+    implicit none
+    type(grid_parameters), intent(in) :: grid_param
+    type(model_parameters), intent(in) :: model_param
+    type(scalar3d), intent(inout) :: u
+    integer :: ix, iy, iz, ix_min, ix_max, iy_min, iy_max
+    real(kind=rl) :: x, y, z
+    real(kind=rl) :: rho, sigma, theta, phi, r, b_low, b_up, pi
+
+    integer       , optional, intent(in) :: KIB,KIE,KIU,KJB,KJE,KJU,KKU
+    real(kind=rl) , optional, intent(in) :: PU(:,:,:)
+
+    ix_min = u%ix_min
+    ix_max = u%ix_max
+    iy_min = u%iy_min
+    iy_max = u%iy_max
+    IF (.NOT. PRESENT(KIB) ) THEN
+    ! Initialise RHS
+    do ix=ix_min, ix_max
+      do iy=iy_min, iy_max
+        do iz=1,u%grid_param%nz
+ 
+           if (LUseO) u%s(iz,iy-iy_min+1,ix-ix_min+1) = 0.0_rl
+           if (LUseT) u%st(ix-ix_min+1,iy-iy_min+1,iz) = 0.0_rl
+
+        end do
+      end do
+    end do
+    ELSE
+   ! Initialise RHS
+       if (LUseO) then
+          do ix=ix_min, ix_max
+             do iy=iy_min, iy_max
+                do iz=1,u%grid_param%nz
+                   u%s(iz,iy-iy_min+1,ix-ix_min+1) = PU(IX-ix_min+KIB,IY-iy_min+KJB,IZ)
+                end do
+             end do
+          end do
+       end if
+       if (LUseT) then
+          do iz=1,u%grid_param%nz
+             do iy=iy_min, iy_max
+                do ix=ix_min, ix_max
+                   u%st(ix-ix_min+1,iy-iy_min+1,iz) = PU(IX-ix_min+KIB,IY-iy_min+KJB,IZ)
+                end do
+             end do
+          end do
+       end if
+    END IF
+  end subroutine initialise_u_mnh
+!==================================================================
+! Get U vector
+!==================================================================
+  subroutine get_u_mnh(grid_param,model_param,u,KIB,KIE,KIU,KJB,KJE,KJU,KKU,PU)
+    implicit none
+    type(grid_parameters), intent(in) :: grid_param
+    type(model_parameters), intent(in) :: model_param
+    type(scalar3d), intent(inout) :: u
+    integer :: ix, iy, iz, ix_min, ix_max, iy_min, iy_max
+    real(kind=rl) :: x, y, z
+    real(kind=rl) :: rho, sigma, theta, phi, r, b_low, b_up, pi
+
+    integer       , optional, intent(in)    :: KIB,KIE,KIU,KJB,KJE,KJU,KKU
+    real(kind=rl) , optional, intent(inout) :: PU(:,:,:)
+
+    ix_min = u%ix_min
+    ix_max = u%ix_max
+    iy_min = u%iy_min
+    iy_max = u%iy_max
+    IF (.NOT. PRESENT(KIB) ) THEN
+    ! 
+    ELSE
+   ! Get PU
+       if (LUseO) then
+          do ix=ix_min, ix_max
+             do iy=iy_min, iy_max
+                do iz=1,u%grid_param%nz
+                   PU(IX-ix_min+KIB,IY-iy_min+KJB,IZ) =  u%s(iz,iy-iy_min+1,ix-ix_min+1)
+                end do
+             end do
+          end do
+       else
+          do iz=1,u%grid_param%nz
+             do iy=iy_min, iy_max
+                do ix=ix_min, ix_max
+                   PU(IX-ix_min+KIB,IY-iy_min+KJB,IZ) =  u%st(ix-ix_min+1,iy-iy_min+1,iz)
+                end do
+             end do
+          end do
+       end if
+    END IF
+  end subroutine get_u_mnh
+!==================================================================
+! Initialise RHS vector
+!==================================================================
+  subroutine initialise_rhs_mnh(grid_param,model_param,b,KIB,KIE,KIU,KJB,KJE,KJU,KKU,PY)
+    implicit none
+    type(grid_parameters), intent(in) :: grid_param
+    type(model_parameters), intent(in) :: model_param
+    type(scalar3d), intent(inout) :: b
+    integer :: ix, iy, iz, ix_min, ix_max, iy_min, iy_max
+    real(kind=rl) :: x, y, z
+    real(kind=rl) :: rho, sigma, theta, phi, r, b_low, b_up, pi
+
+    integer       , optional, intent(in) :: KIB,KIE,KIU,KJB,KJE,KJU,KKU
+    real(kind=rl) , optional, intent(in) :: PY(:,:,:)
+
+    ix_min = b%ix_min
+    ix_max = b%ix_max
+    iy_min = b%iy_min
+    iy_max = b%iy_max
+    IF (.NOT. PRESENT(KIB) ) THEN
+    ! Initialise RHS
+    do ix=ix_min, ix_max
+      do iy=iy_min, iy_max
+        do iz=1,b%grid_param%nz
+          x = 1.0_rl*((ix-0.5_rl)/(1.0_rl*b%grid_param%n))
+          y = 1.0_rl*((iy-0.5_rl)/(1.0_rl*b%grid_param%n))
+          z = 1.0_rl*((iz-0.5_rl)/(1.0_rl*b%grid_param%nz))
+
+          if (LUseO) b%s(iz,iy-iy_min+1,ix-ix_min+1) = 0.0_rl
+          if (LUseT) b%st(ix-ix_min+1,iy-iy_min+1,iz) = 0.0_rl
+
+          if ( ( x .ge. 0.1_rl ) .and. ( x .le. 0.4_rl ) &
+            .and. (y .ge. 0.3_rl ) .and. ( y .le. 0.6_rl ) &
+            .and. (z .ge. 0.2_rl ) .and. ( z .le. 0.7_rl ) ) &
+            then
+            if (LUseO) b%s(iz,iy-iy_min+1,ix-ix_min+1) = 1.0_rl 
+            if (LUseT) b%st(ix-ix_min+1,iy-iy_min+1,iz) = 1.0_rl 
+          end if
+
+        end do
+      end do
+    end do
+    ELSE
+   ! Initialise RHS
+      if (LUseO) then    
+         do ix=ix_min, ix_max
+            do iy=iy_min, iy_max
+               do iz=1,b%grid_param%nz
+                  b%s(iz,iy-iy_min+1,ix-ix_min+1) = PY(IX-ix_min+KIB,IY-iy_min+KJB,IZ)
+               end do
+            end do
+         end do
+      end if
+     if (LUseT) then   
+        do iz=1,b%grid_param%nz 
+           do iy=iy_min, iy_max
+              do ix=ix_min, ix_max
+                  b%st(ix-ix_min+1,iy-iy_min+1,iz) = PY(IX-ix_min+KIB,IY-iy_min+KJB,IZ)
+               end do
+            end do
+         end do
+      end if
+    END IF
+  end subroutine initialise_rhs_mnh
+!==================================================================
+! Initialise RHS vector
+!==================================================================
+  subroutine initialise_rhs(grid_param,model_param,b)
+    implicit none
+    type(grid_parameters), intent(in) :: grid_param
+    type(model_parameters), intent(in) :: model_param
+    type(scalar3d), intent(inout) :: b
+    integer :: ix, iy, iz, ix_min, ix_max, iy_min, iy_max
+    real(kind=rl) :: x, y, z
+    real(kind=rl) :: rho, sigma, theta, phi, r, b_low, b_up, pi
+
+#ifdef TESTCONVERGENCE
+    real(kind=rl) :: px,py,pz
+#endif
+
+    ix_min = b%ix_min
+    ix_max = b%ix_max
+    iy_min = b%iy_min
+    iy_max = b%iy_max
+    b_low = 1.0_rl+0.25*b%grid_param%H
+    b_up = 1.0_rl+0.75*b%grid_param%H
+    pi = 4.0_rl*atan2(1.0_rl,1.0_rl)
+    ! Initialise RHS
+    do ix=ix_min, ix_max
+      do iy=iy_min, iy_max
+        do iz=1,b%grid_param%nz
+          x = 1.0_rl*((ix-0.5_rl)/(1.0_rl*b%grid_param%n))
+          y = 1.0_rl*((iy-0.5_rl)/(1.0_rl*b%grid_param%n))
+          z = 1.0_rl*((iz-0.5_rl)/(1.0_rl*b%grid_param%nz))
+#ifdef TESTCONVERGENCE
+          ! RHS for analytical solution x*(1-x)*y*(1-y)*z*(1-z)
+          if (grid_param%vertbc == VERTBC_DIRICHLET) then
+            px = x*(1.0_rl-x)
+            py = y*(1.0_rl-y)
+            pz = z*(1.0_rl-z)
+            b%s(iz,iy-iy_min+1,ix-ix_min+1) = &
+              ( 2.0_rl*model_param%omega2*((px+py)*pz &
+              + model_param%lambda2*px*py)+model_param%delta*px*py*pz)
+          else
+            px = x*(1.0_rl-x)
+            py = y*(1.0_rl-y)
+            pz = 1.0_rl
+            b%s(iz,iy-iy_min+1,ix-ix_min+1) = &
+              ( 2.0_rl*model_param%omega2*((px+py)*pz)+model_param%delta*px*py*pz)
+          end if
+#else
+          b%s(iz,iy-iy_min+1,ix-ix_min+1) = 0.0_rl
+#ifdef CARTESIANGEOMETRY
+          if ( ( x .ge. 0.1_rl ) .and. ( x .le. 0.4_rl ) &
+            .and. (y .ge. 0.3_rl ) .and. ( y .le. 0.6_rl ) &
+            .and. (z .ge. 0.2_rl ) .and. ( z .le. 0.7_rl ) ) &
+            then
+            b%s(iz,iy-iy_min+1,ix-ix_min+1) = 1.0_rl
+          end if
+#else
+          rho = 2.0_rl*(1.0_rl*ix-0.5_rl)/grid_param%n-1.0_rl
+          sigma = 2.0_rl*(1.0_rl*iy-0.5_rl)/grid_param%n-1.0_rl
+          phi = atan(sigma)
+          theta = atan(rho/sqrt(1.0_rl+sigma**2))
+          x = sin(theta)
+          y = cos(theta)*sin(phi)
+          z = cos(theta)*cos(phi)
+          phi = atan2(x,y)
+          theta = atan2(sqrt(x**2+y**2),z)
+          r = 0.5_rl*(r_grid(iz)+r_grid(iz+1))
+          if (( (r > b_low) .and. (r < b_up) ) .and. &
+              (((theta>pi/10.0_rl) .and. (theta<pi/5.0_rl )) .or. &
+               ((theta>3.0_rl*pi/8.0_rl) .and. (theta<5.0_rl*pi/8.0_rl )) .or. &
+               ((theta>4.0_rl*pi/5.0_rl) .and. (theta<9.0_rl*pi/10.0_rl)))) then
+            b%s(iz,iy-iy_min+1,ix-ix_min+1) = 1.0_rl
+          end if
+!    RHS used in GPU code:
+!          if ( (r > b_low) .and. (r < b_up) .and. &
+!               (rho > -0.5) .and. (rho < 0.5) .and. &
+!               (sigma > -0.5).and. (sigma < 0.5) ) then
+!            b%s(iz,iy-iy_min+1,ix-ix_min+1) = 1.0_rl
+!          end if
+#endif
+#endif
+        end do
+      end do
+    end do
+  end subroutine initialise_rhs
+!==================================================================
+! Exact solution for test problem
+!  u(x,y,z) = x*(1-x)*y*(1-y)*z*(1-z)
+!==================================================================
+  subroutine analytical_solution(grid_param,u)
+    implicit none
+    type(grid_parameters), intent(in) :: grid_param
+    type(scalar3d), intent(inout) :: u
+    integer :: ix, iy, iz, ix_min, ix_max, iy_min, iy_max
+    real(kind=rl) :: x, y, z
+
+    ix_min = u%ix_min
+    ix_max = u%ix_max
+    iy_min = u%iy_min
+    iy_max = u%iy_max
+
+    ! Initialise RHS
+    do ix=ix_min, ix_max
+      do iy=iy_min, iy_max
+        do iz=1,u%grid_param%nz
+          x = u%grid_param%L*((ix-0.5_rl)/(1.0_rl*u%grid_param%n))
+          y = u%grid_param%L*((iy-0.5_rl)/(1.0_rl*u%grid_param%n))
+          z = u%grid_param%H*((iz-0.5_rl)/(1.0_rl*u%grid_param%nz))
+          if (grid_param%vertbc == VERTBC_DIRICHLET) then
+            u%s(iz,iy-iy_min+1,ix-ix_min+1) &
+              = x*(1.0_rl-x) &
+              * y*(1.0_rl-y) &
+              * z*(1.0_rl-z)
+          else
+            u%s(iz,iy-iy_min+1,ix-ix_min+1) &
+              = x*(1.0_rl-x) &
+              * y*(1.0_rl-y)
+          end if
+        end do
+      end do
+    end do
+  end subroutine analytical_solution
+
+end module profiles
diff --git a/src/ZSOLVER/tensorproductmultigrid_Source/solver.f90 b/src/ZSOLVER/tensorproductmultigrid_Source/solver.f90
new file mode 100644
index 0000000000000000000000000000000000000000..97f5a7b840cc0030902eaf39b55bb1d9c0460041
--- /dev/null
+++ b/src/ZSOLVER/tensorproductmultigrid_Source/solver.f90
@@ -0,0 +1,61 @@
+!=== COPYRIGHT AND LICENSE STATEMENT ===
+!
+!  This file is part of the TensorProductMultigrid code.
+!  
+!  (c) The copyright relating to this work is owned jointly by the
+!  Crown, Met Office and NERC [2014]. However, it has been created
+!  with the help of the GungHo Consortium, whose members are identified
+!  at https://puma.nerc.ac.uk/trac/GungHo/wiki .
+!  
+!  Main Developer: Eike Mueller
+!  
+!  TensorProductMultigrid is free software: you can redistribute it and/or
+!  modify it under the terms of the GNU Lesser General Public License as
+!  published by the Free Software Foundation, either version 3 of the
+!  License, or (at your option) any later version.
+!  
+!  TensorProductMultigrid is distributed in the hope that it will be useful,
+!  but WITHOUT ANY WARRANTY; without even the implied warranty of
+!  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+!  GNU Lesser General Public License for more details.
+!  
+!  You should have received a copy of the GNU Lesser General Public License
+!  along with TensorProductMultigrid (see files COPYING and COPYING.LESSER).
+!  If not, see <http://www.gnu.org/licenses/>.
+!
+!=== COPYRIGHT AND LICENSE STATEMENT ===
+
+
+!==================================================================
+!
+! Solver parameters
+!
+!    Eike Mueller, University of Bath, May 2012
+!
+!==================================================================
+module solver
+
+  use parameters
+  use datatypes
+
+  implicit none
+
+public::solver_parameters
+public::SOLVER_RICHARDSON
+public::SOLVER_CG
+
+private
+
+  integer, parameter :: SOLVER_RICHARDSON = 1
+  integer, parameter :: SOLVER_CG = 2
+
+
+  ! --- Solver parameters ---
+  type solver_parameters
+    integer :: solvertype ! Type of solver
+    real(kind=rl) :: resreduction ! Required relative residual reduction
+    integer :: maxiter    ! Maximal number of iterations
+  end type solver_parameters
+
+end module solver
+
diff --git a/src/ZSOLVER/tensorproductmultigrid_Source/timer.f90 b/src/ZSOLVER/tensorproductmultigrid_Source/timer.f90
new file mode 100644
index 0000000000000000000000000000000000000000..da0f17907a28016c0aad1fee4b78d348cf72ecfd
--- /dev/null
+++ b/src/ZSOLVER/tensorproductmultigrid_Source/timer.f90
@@ -0,0 +1,193 @@
+!=== COPYRIGHT AND LICENSE STATEMENT ===
+!
+!  This file is part of the TensorProductMultigrid code.
+!  
+!  (c) The copyright relating to this work is owned jointly by the
+!  Crown, Met Office and NERC [2014]. However, it has been created
+!  with the help of the GungHo Consortium, whose members are identified
+!  at https://puma.nerc.ac.uk/trac/GungHo/wiki .
+!  
+!  Main Developer: Eike Mueller
+!  
+!  TensorProductMultigrid is free software: you can redistribute it and/or
+!  modify it under the terms of the GNU Lesser General Public License as
+!  published by the Free Software Foundation, either version 3 of the
+!  License, or (at your option) any later version.
+!  
+!  TensorProductMultigrid is distributed in the hope that it will be useful,
+!  but WITHOUT ANY WARRANTY; without even the implied warranty of
+!  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+!  GNU Lesser General Public License for more details.
+!  
+!  You should have received a copy of the GNU Lesser General Public License
+!  along with TensorProductMultigrid (see files COPYING and COPYING.LESSER).
+!  If not, see <http://www.gnu.org/licenses/>.
+!
+!=== COPYRIGHT AND LICENSE STATEMENT ===
+
+
+!==================================================================
+!
+!  Timer module
+!
+!    Eike Mueller, University of Bath, Feb 2012
+!
+!==================================================================
+
+module timer
+
+#ifndef MNH
+  use mpi
+#else
+  use modd_mpif
+#endif 
+  use parameters
+
+  implicit none
+
+public::initialise_timing
+public::finalise_timing
+public::time
+public::initialise_timer
+public::start_timer
+public::finish_timer
+public::print_timerinfo
+public::print_elapsed
+
+private
+
+! Timer type
+  type time
+    character(len=32) :: label
+    real(kind=rl) :: start
+    real(kind=rl) :: finish
+    integer :: ncall
+    real(kind=rl) :: elapsed
+  end type time
+
+  ! id of timer output file
+  integer, parameter :: TIMEROUT = 9
+
+  ! used my MPI
+  integer :: rank, ierr
+
+contains
+
+!==================================================================
+! Initialise timer module
+!==================================================================
+  subroutine initialise_timing(filename)
+    implicit none
+    character(len=*), intent(in) :: filename
+    call mpi_comm_rank(MPI_COMM_WORLD,rank,ierr)
+    if (rank==0) then
+      open(UNIT=TIMEROUT,FILE=trim(filename))
+      write(STDOUT,'("Writing timer information to file ",A40)') filename
+      write(TIMEROUT,'("# ----------------------------------------------")')
+      write(TIMEROUT,'("# Timer information for geometric multigrid code")')
+      write(TIMEROUT,'("# ----------------------------------------------")')
+    end if
+  end subroutine initialise_timing
+
+!==================================================================
+! Finalise timer module
+!==================================================================
+  subroutine finalise_timing()
+    implicit none
+    if (rank==0) then
+      close(TIMEROUT)
+    end if
+  end subroutine finalise_timing
+
+!==================================================================
+! Initialise timer
+!==================================================================
+  subroutine initialise_timer(t,label)
+    implicit none
+    type(time), intent(inout) :: t
+    character(len=*), intent(in) :: label
+    t%label = label
+    t%start = 0.0_rl
+    t%ncall = 0
+    t%finish = 0.0_rl
+    t%elapsed = 0.0_rl
+  end subroutine initialise_timer
+
+!==================================================================
+! Start timer
+!==================================================================
+  subroutine start_timer(t)
+    implicit none
+    type(time), intent(inout) :: t
+    t%start = mpi_wtime()
+  end subroutine start_timer
+
+!==================================================================
+! Finish timer
+!==================================================================
+  subroutine finish_timer(t)
+    implicit none
+    type(time), intent(inout) :: t
+    t%finish = mpi_wtime()
+    t%elapsed = t%elapsed + (t%finish-t%start)
+    t%ncall = t%ncall + 1
+  end subroutine finish_timer
+
+!==================================================================
+! Print to timer file
+!==================================================================
+  subroutine print_timerinfo(msg)
+    implicit none
+    character(len=*), intent(in) :: msg
+    if (rank == 0) then
+      write(TIMEROUT,*) "# " // trim(msg)
+    end if
+  end subroutine print_timerinfo
+
+!==================================================================
+! Print timer information
+!==================================================================
+  subroutine print_elapsed(t,summaryonly,factor)
+    implicit none
+    type(time), intent(in)        :: t
+    logical, intent(in)           :: summaryonly
+    real(kind=rl), intent(in)     :: factor
+    real(kind=rl) :: elapsedtime
+    real(kind=rl) :: t_min
+    real(kind=rl) :: t_max
+    real(kind=rl) :: t_avg
+    integer :: rank, nprocs, ierr
+    integer :: nc
+
+    t_min = 0.0_rl
+    t_max = 0.0_rl
+    t_avg = 0.0_rl
+
+
+    elapsedtime = (t%elapsed) * factor
+    call mpi_reduce(elapsedtime,t_min,1,MPI_DOUBLE_PRECISION, &
+                    MPI_MIN, 0, MPI_COMM_WORLD,ierr)
+    call mpi_reduce(elapsedtime,t_avg,1,MPI_DOUBLE_PRECISION, &
+                    MPI_SUM, 0, MPI_COMM_WORLD,ierr)
+    call mpi_reduce(elapsedtime,t_max,1,MPI_DOUBLE_PRECISION, &
+                    MPI_MAX, 0, MPI_COMM_WORLD,ierr)
+    call mpi_comm_size(MPI_COMM_WORLD,nprocs,ierr)
+    call mpi_comm_rank(MPI_COMM_WORLD,rank,ierr)
+    t_avg = t_avg/nprocs
+    nc = t%ncall
+    if (nc == 0) nc = 1
+    if (summaryonly) then
+      if (rank == 0) then
+        write(TIMEROUT,'(A32," [",I7,"]: ",E10.4," / ",E10.4," / ",E10.4," (min/avg/max)")') &
+          t%label,t%ncall,t_min,t_avg,t_max
+        write(TIMEROUT,'(A32,"    t/call: ",E10.4," / ",E10.4," / ",E10.4," (min/avg/max)")') &
+          t%label,t_min/nc,t_avg/nc,t_max/nc
+      end if
+    else
+      write(TIMEROUT,'(A32," : ",I8," calls ",E10.4," (rank ",I8,")")') &
+        t%label,elapsedtime, rank
+    end if
+    write(TIMEROUT,'("")')
+  end subroutine print_elapsed
+
+end module timer
diff --git a/src/ZSOLVER/tridz.f90 b/src/ZSOLVER/tridz.f90
new file mode 100644
index 0000000000000000000000000000000000000000..203c413f8251bcfb5bd4d6e242198a7923efd16d
--- /dev/null
+++ b/src/ZSOLVER/tridz.f90
@@ -0,0 +1,848 @@
+!MNH_LIC Copyright 1994-2019 CNRS, Meteo-France and Universite Paul Sabatier
+!MNH_LIC This is part of the Meso-NH software governed by the CeCILL-C licence
+!MNH_LIC version 1. See LICENSE, CeCILL-C_V1-en.txt and CeCILL-C_V1-fr.txt
+!MNH_LIC for details. version 1.
+!-----------------------------------------------------------------
+!     ################
+      MODULE MODI_TRIDZ
+!     ################
+!
+INTERFACE
+!
+      SUBROUTINE TRIDZ(HLBCX,HLBCY,                                     &
+                      PMAP,PDXHAT,PDYHAT,HPRESOPT,                      &
+                      PDXHATM,PDYHATM,PRHOM,                            &
+                      PAF,PCF,PTRIGSX,PTRIGSY,KIFAXX,KIFAXY,            &
+                      PRHODJ,PTHVREF,PZZ,PBFY,PBFB,                     &
+                      PBF_SXP2_YP1_Z,                                   &
+                      PAF_ZS,PBF_ZS,PCF_ZS,                             &
+                      PDXATH_ZS,PDYATH_ZS,PRHO_ZS,                      &
+                      A_K,B_K,C_K,D_K) !JUAN  FULL ZSOLVER
+!
+IMPLICIT NONE
+!
+CHARACTER (LEN=4), DIMENSION(2), INTENT(IN) :: HLBCX    ! x-direction LBC type
+CHARACTER (LEN=4), DIMENSION(2), INTENT(IN) :: HLBCY    ! y-direction LBC type
+!
+REAL, DIMENSION(:,:,:),   INTENT(IN)    :: PRHODJ     ! density of reference * J
+REAL, DIMENSION(:,:,:),   INTENT(IN)    :: PTHVREF    ! Virtual Potential
+                                        ! Temperature of the reference state
+!
+REAL, DIMENSION(:,:), INTENT(IN) :: PMAP         ! scale factor
+!
+REAL, DIMENSION(:,:,:), INTENT(IN) :: PZZ        ! height z
+!
+REAL, DIMENSION(:), INTENT(IN) :: PDXHAT          ! Stretching in x direction
+REAL, DIMENSION(:), INTENT(IN) :: PDYHAT          ! Stretching in y direction
+CHARACTER (LEN=5), INTENT(IN) :: HPRESOPT        ! choice of the pressure solver
+!
+REAL, INTENT(OUT) :: PDXHATM                     ! mean grid increment in the x
+                                                 ! direction
+REAL, INTENT(OUT) :: PDYHATM                     ! mean grid increment in the y
+                                                 ! direction
+!
+REAL, DIMENSION (:), INTENT(OUT) :: PRHOM        !  mean of XRHODJ on the plane
+                                                 !  x y localized at a mass 
+                                                 !  level
+!
+REAL, DIMENSION(:), INTENT(OUT)     :: PAF,PCF  ! vectors giving the nonvanishing
+REAL, DIMENSION(:,:,:), INTENT(OUT) :: PBFY     ! elements (yslice) of the tri-diag.
+                                                ! matrix in the pressure eq. 
+!JUAN
+REAL, DIMENSION(:,:,:), INTENT(OUT) :: PBFB     ! elements (bsplit slide) of the tri-diag.
+                                                ! matrix in the pressure eq. 
+REAL, DIMENSION(:,:,:), INTENT(OUT) :: PBF_SXP2_YP1_Z ! elements of the tri-diag. SXP2_YP1_Z-slide 
+                                                   ! matrix in the pressure eq
+REAL, DIMENSION(:,:,:), INTENT(OUT) :: PAF_ZS,PBF_ZS,PCF_ZS
+REAL, DIMENSION(:,:)  , INTENT(OUT) :: PDXATH_ZS,PDYATH_ZS
+REAL, DIMENSION(:,:,:), INTENT(OUT) :: PRHO_ZS
+REAL, DIMENSION(:)    , INTENT(OUT) :: A_K,B_K,C_K,D_K
+!JUAN
+!
+                                                 ! arrays of sin or cos values
+                                                 ! for the FFT :
+REAL, DIMENSION(:), INTENT(OUT) :: PTRIGSX       ! - along x
+REAL, DIMENSION(:), INTENT(OUT) :: PTRIGSY       ! - along y
+!
+                                                 ! decomposition in prime
+                                                 ! numbers for the FFT:
+INTEGER, DIMENSION(19), INTENT(OUT) :: KIFAXX      ! - along x
+INTEGER, DIMENSION(19), INTENT(OUT) :: KIFAXY      ! - along y
+
+!
+END SUBROUTINE TRIDZ
+!
+END INTERFACE
+!
+END MODULE MODI_TRIDZ
+!
+!     ###################################################################
+      SUBROUTINE TRIDZ(HLBCX,HLBCY,                                     &
+                      PMAP,PDXHAT,PDYHAT,HPRESOPT,                      &
+                      PDXHATM,PDYHATM,PRHOM,                            &
+                      PAF,PCF,PTRIGSX,PTRIGSY,KIFAXX,KIFAXY,            &
+                      PRHODJ,PTHVREF,PZZ,PBFY,PBFB,                     &
+                      PBF_SXP2_YP1_Z,                                   &
+                      PAF_ZS,PBF_ZS,PCF_ZS,                             &
+                      PDXATH_ZS,PDYATH_ZS,PRHO_ZS,                      &
+                      A_K,B_K,C_K,D_K) !JUAN  FULL ZSOLVER      
+!    ####################################################################
+!
+!!****  *TRIDZ * - Compute coefficients for the flat operator
+!!
+!!    PURPOSE
+!!    -------
+!       The purpose of this routine is to compute the vertical time independent 
+!     coefficients a(k), b(k), c(k) required for the calculation of the "flat"  
+!     (i.e. neglecting the orography) operator Laplacian.  RHOJ is averaged on 
+!     the whole horizontal domain. The form of the eigenvalues  of the flat 
+!     operator depends on the lateral boundary conditions. Furthermore, this
+!     routine initializes TRIGS and IFAX arrays required for the FFT transform 
+!     used in the routine PRECOND.
+!
+!!**  METHOD
+!!    ------
+!!     The forms of the eigenvalues of the horizontal Laplacian are given by:
+!!     Cyclic conditions:
+!!     -----------------
+!!                    <rhoj>        2 ( pi     )       <rhoj>      2 (  pi    )
+!!     b(m,n) = -4 -----------   sin  (----- m ) -4 ----------- sin  (----- n )
+!!                 <dxx> <dxx>        ( imax   )    <dyy> <dyy>      ( jmax   )
+!!
+!!     Open conditions:
+!!     -----------------
+!!                    <rhoj>        2 ( pi     )       <rhoj>      2 (  pi    )
+!!     b(m,n) = -4 -----------   sin  (----- m ) -4 ----------- sin  (----- n )
+!!                 <dxx> <dxx>        ( 2imax  )    <dyy> <dyy>      ( 2jmax  )
+!!      
+!!     Cyclic condition along x and open condition along y:
+!!     ------------------------------------------------------
+!!                    <rhoj>        2 ( pi     )       <rhoj>      2 (  pi    )
+!!     b(m,n) = -4 -----------   sin  (----- m ) -4 ----------- sin  (----- n )
+!!                 <dxx> <dxx>        ( imax   )    <dyy> <dyy>      ( 2jmax  )
+!!
+!!     Open condition along x and cyclic condition along y:
+!!     ------------------------------------------------------
+!!                    <rhoj>        2 ( pi     )       <rhoj>      2 (  pi    )
+!!     b(m,n) = -4 -----------   sin  (----- m ) -4 ----------- sin  (----- n )
+!!                 <dxx> <dxx>        ( 2imax  )    <dyy> <dyy>      ( jmax   )
+!!
+!!     where m = 0,1,2....imax-1, n = 0,1,2....jmax-1
+!!     Note that rhoj contains the Jacobian J = Deltax*Deltay*Deltaz = volume of
+!!     an elementary mesh.
+
+!!
+!!    EXTERNAL
+!!    --------
+!!      Function FFTFAX: initialization of TRIGSX,IFAXX,TRIGSY,IFAXY for  
+!!      the FFT transform
+!!      GET_DIM_EXT_ll    : get extended sub-domain sizes
+!!      GET_INDICE_ll     : get physical sub-domain bounds 
+!!      GET_DIM_PHYS_ll   : get physical sub-domain sizes
+!!      GET_GLOBALDIMS_ll : get physical global domain sizes
+!!      GET_OR_ll         : get origine coordonates of the physical sub-domain in global indices
+!!      REDUCESUM_ll      : sum into a scalar variable
+!!      GET_SLICE_ll    : get a slice of the global domain
+!!
+!!    IMPLICIT ARGUMENTS
+!!    ------------------ 
+!!      Module MODD_CST : define constants
+!!         XPI : pi
+!!         XCPD
+!!      Module MODD_PARAMETERS: declaration of parameter variables
+!!        JPHEXT, JPVEXT: define the number of marginal points out of the 
+!!        physical domain along horizontal and vertical directions respectively
+!!      Module MODD_CONF: model configurations 
+!!         LCARTESIAN: logical for CARTESIAN geometry
+!!                     .TRUE. = Cartesian geometry used
+!!         L2D: logical for 2D model version
+!!  
+!!    REFERENCE
+!!    ---------
+!!      Book2 of documentation (routine TRIDZ)
+!!      
+!!    AUTHOR
+!!    ------
+!!	P. HÃ…reil and J. Stein       * Meteo France *
+!!
+!!    MODIFICATIONS
+!!    -------------
+!!      Original    25/07/94 
+!!                  14/04/95  (J. Stein) bug in the ZDZM computation
+!!                                        ( stretched case)  
+!!                   8/07/96  (P. Jabouille) change the FFT initialization
+!!                            which now works for odd number.
+!!                  14/01/97 Durran anelastic equation (Stein,Lafore)
+!!                  15/06/98  (D.Lugato, R.Guivarch) Parallelisation
+!!                  10/08/98 (N. Asencio) add parallel code
+!!                                        use PDXHAT, PDYHAT and not PXHAT,PYHAT
+!!                                        PBFY is initialized
+!!                  20/08/00 (J. Stein, J. Escobar) optimisation of the solver
+!!                                        PBFY transposition
+!!                  14/03/02 (P. Jabouille) set values for meaningless spectral coefficients
+!!                                       (to avoid problem in bouissinesq configuration)
+!!   J.Escobar : 15/09/2015 : WENO5 & JPHEXT <> 1
+!!  Philippe Wautelet: 05/2016-04/2018: new data structures and calls for I/O
+!------------------------------------------------------------------------------
+!
+!*       0.    DECLARATIONS
+!              ------------
+USE MODD_CST
+USE MODD_CONF
+USE MODD_LUNIT_n, ONLY: TLUOUT
+USE MODD_PARAMETERS
+!
+USE MODE_ll
+USE MODE_MSG
+!JUAN P1/P2 SPLITTING
+USE MODE_SPLITTINGZ_ll , ONLY : GET_DIM_EXTZ_ll,GET_ORZ_ll,LWESTZ_ll,LSOUTHZ_ll
+!JUAN
+!
+!JUAN
+USE MODE_REPRO_SUM
+!JUAN
+USE MODE_MPPDB
+!
+USE mode_mg_main_mnh
+!
+IMPLICIT NONE
+!
+!
+!*       0.1   declarations of arguments
+!
+!
+!
+CHARACTER (LEN=4), DIMENSION(2), INTENT(IN) :: HLBCX    ! x-direction LBC type
+CHARACTER (LEN=4), DIMENSION(2), INTENT(IN) :: HLBCY    ! y-direction LBC type
+!
+REAL, DIMENSION(:,:,:),   INTENT(IN)    :: PRHODJ     ! density of reference * J
+REAL, DIMENSION(:,:,:),   INTENT(IN)    :: PTHVREF    ! Virtual Potential
+                                        ! Temperature of the reference state
+!
+REAL, DIMENSION(:,:), INTENT(IN) :: PMAP         ! scale factor
+!
+REAL, DIMENSION(:,:,:), INTENT(IN) :: PZZ        ! height z
+!
+REAL, DIMENSION(:), INTENT(IN) :: PDXHAT          ! Stretching in x direction
+REAL, DIMENSION(:), INTENT(IN) :: PDYHAT          ! Stretching in y direction
+CHARACTER (LEN=5), INTENT(IN) :: HPRESOPT         ! choice of the pressure solver
+!
+REAL, INTENT(OUT) :: PDXHATM                     ! mean grid increment in the x
+                                                 ! direction
+REAL, INTENT(OUT) :: PDYHATM                     ! mean grid increment in the y
+                                                 ! direction
+!
+REAL, DIMENSION (:), INTENT(OUT) :: PRHOM        !  mean of XRHODJ on the plane
+                                                 !  x y localized at a mass 
+                                                 !  level
+!
+REAL, DIMENSION(:), INTENT(OUT)     :: PAF,PCF  ! vectors giving the nonvanishing
+REAL, DIMENSION(:,:,:), INTENT(OUT) :: PBFY     ! elements (yslice) of the tri-diag.
+! matrix in the pressure eq. which is transposed. PBFY is a y-slices structure
+!JUAN
+REAL, DIMENSION(:,:,:), INTENT(OUT) :: PBFB     ! elements (bsplit slide) of the tri-diag.
+                                                ! matrix in the pressure eq. 
+REAL, DIMENSION(:,:,:), INTENT(OUT) :: PBF_SXP2_YP1_Z ! elements of the tri-diag. SXP2_YP1_Z-slide 
+                                                   ! matrix in the pressure eq.
+REAL, DIMENSION(:,:,:), INTENT(OUT) :: PAF_ZS,PBF_ZS,PCF_ZS
+REAL, DIMENSION(:,:)  , INTENT(OUT) :: PDXATH_ZS,PDYATH_ZS
+REAL, DIMENSION(:,:,:), INTENT(OUT) :: PRHO_ZS
+REAL, DIMENSION(:)    , INTENT(OUT) :: A_K,B_K,C_K,D_K
+!JUAN
+!                                 
+                                                 ! arrays of sin or cos values
+                                                 ! for the FFT :
+REAL, DIMENSION(:), INTENT(OUT) :: PTRIGSX       ! - along x
+REAL, DIMENSION(:), INTENT(OUT) :: PTRIGSY       ! - along y
+!
+                                                 ! decomposition in prime
+                                                 ! numbers for the FFT:
+INTEGER, DIMENSION(19), INTENT(OUT) :: KIFAXX      ! - along x
+INTEGER, DIMENSION(19), INTENT(OUT) :: KIFAXY      ! - along y
+
+!
+!*       0.2   declarations of local variables
+!
+INTEGER                         ::  IRESP    ! FM return code
+INTEGER                         :: ILUOUT    ! Logical unit number for
+                                             ! output-listing   
+INTEGER :: IIB,IIE,IJB,IJE,IKB,IKE     ! indice values of the physical subdomain
+INTEGER :: IKU ,  IKBE                      ! size of the arrays along z
+INTEGER :: IIB_ll,IIE_ll,IJB_ll,IJE_ll !  indice values of the physical global domain
+INTEGER :: IIMAX,IJMAX       ! Number of points of the physical subdomain
+INTEGER :: IIMAX_ll,IJMAX_ll ! Number of points of Global physical domain
+!
+INTEGER :: JI,JJ,JK                                    ! loop indexes
+!
+INTEGER :: INN        ! temporary result for the computation of array TRIGS
+!
+REAL, DIMENSION (:,:), ALLOCATABLE  :: ZEIGEN_ll  ! eigenvalues b(m,n) in global representation
+REAL, DIMENSION (:),   ALLOCATABLE  :: ZEIGENX_ll ! used for the computation of ZEIGEN_ll 
+!
+REAL, DIMENSION( SIZE(PDXHAT))  :: ZWORKX  ! work array to compute PDXHATM
+REAL, DIMENSION( SIZE(PDYHAT))  :: ZWORKY  ! work array to compute PDYHATM
+!
+REAL :: ZGWNX,ZGWNY           ! greater wave numbers allowed by the model 
+                              ! configuration in x and y directions respectively
+!
+REAL, DIMENSION (SIZE(PZZ,3)) :: ZDZM      !  mean of deltaz on the plane x y
+                                           !  localized at a w-level
+!
+REAL :: ZANGLE,ZDEL ! needed for the initialization of the arrays used by the FFT
+!
+REAL :: ZINVMEAN ! inverse of inner points number in an horizontal grid
+!
+INTEGER ::  IINFO_ll         ! return code of parallel routine
+REAL, DIMENSION (SIZE(PMAP,1)) :: ZXMAP ! extraction of PMAP array along x
+REAL, DIMENSION (SIZE(PMAP,2)) :: ZYMAP ! extraction of PMAP array along y
+INTEGER :: IORXY_ll,IORYY_ll     ! origin's coordinates of the y-slices subdomain
+INTEGER :: IIUY_ll,IJUY_ll       ! dimensions of the y-slices subdomain
+INTEGER :: IXMODE_ll,IYMODE_ll   ! number of modes in the x and y direction for global point of view
+INTEGER :: IXMODEY_ll,IYMODEY_ll ! number of modes in the x and y direction for y_slice point of view
+!JUAN Z_SPLITTING
+INTEGER :: IORXB_ll,IORYB_ll     ! origin's coordinates of the b-slices subdomain
+INTEGER :: IIUB_ll,IJUB_ll       ! dimensions of the b-slices subdomain
+INTEGER :: IXMODEB_ll,IYMODEB_ll ! number of modes in the x and y direction for b_slice point of view
+!
+INTEGER :: IORX_SXP2_YP1_Z_ll,IORY_SXP2_YP1_Z_ll     ! origin's coordinates of the b-slices subdomain
+INTEGER :: IIU_SXP2_YP1_Z_ll,IJU_SXP2_YP1_Z_ll,IKU_SXP2_YP1_Z_ll       ! dimensions of the b-slices subdomain
+INTEGER :: IXMODE_SXP2_YP1_Z_ll,IYMODE_SXP2_YP1_Z_ll ! number of modes in the x and y direction for b_slice point of view
+!JUAN Z_SPLITTING
+!JUAN16
+!TYPE(DOUBLE_DOUBLE)  , DIMENSION (SIZE(PZZ,3)) :: ZRHOM_ll   , ZDZM_ll
+REAL, ALLOCATABLE, DIMENSION(:,:)              :: ZRHOM_2D   , ZDZM_2D
+REAL, ALLOCATABLE, DIMENSION(:,:,:)            :: ZDZM_ZS
+!JUAN16
+!
+!
+!
+!
+!
+!------------------------------------------------------------------------------
+!
+!*       1.    INITIALIZATION
+!              --------------
+!
+!*       1.1  retrieve a logical unit number
+!             ------------------------------
+!
+ILUOUT = TLUOUT%NLU
+!
+!*       1.2  compute loop bounds
+!             -------------------
+!
+!  extended sub-domain
+CALL GET_DIM_EXT_ll ('Y',IIUY_ll,IJUY_ll)
+!JUAN Z_SPLITTING
+CALL GET_DIM_EXT_ll ('B',IIUB_ll,IJUB_ll)
+! P1/P2 splitting
+CALL GET_DIM_EXTZ_ll('SXP2_YP1_Z',IIU_SXP2_YP1_Z_ll,IJU_SXP2_YP1_Z_ll,IKU_SXP2_YP1_Z_ll)
+!JUAN Z_SPLITTING
+IKU=SIZE(PRHODJ,3)                        
+!
+CALL GET_INDICE_ll (IIB,IJB,IIE,IJE)
+IKB=1   +JPVEXT                          
+IKE=IKU -JPVEXT
+!  physical sub-domain
+CALL GET_DIM_PHYS_ll ( 'B',IIMAX,IJMAX)
+!
+!  global physical domain limits
+CALL GET_GLOBALDIMS_ll ( IIMAX_ll, IJMAX_ll)
+IIB_ll = 1 + JPHEXT
+IIE_ll = IIMAX_ll  + JPHEXT
+IJB_ll = 1 + JPHEXT
+IJE_ll = IJMAX_ll + JPHEXT
+!
+!     the use of local array ZEIGENX and ZEIGEN would require some technical modifications
+!
+ALLOCATE (ZEIGENX_ll(IIMAX_ll+2*JPHEXT))
+ALLOCATE (ZEIGEN_ll(IIMAX_ll+2*JPHEXT,IJMAX_ll+2*JPHEXT))
+
+ZEIGEN_ll = 0.0
+!  Get the origin coordinates of the extended sub-domain in global landmarks
+CALL GET_OR_ll('Y',IORXY_ll,IORYY_ll)
+!JUAN Z_SPLITING
+CALL GET_OR_ll('B',IORXB_ll,IORYB_ll)
+! P1/P2 Splitting
+CALL GET_ORZ_ll('SXP2_YP1_Z',IORX_SXP2_YP1_Z_ll,IORY_SXP2_YP1_Z_ll)
+!JUAN Z_SPLITING
+!
+!*       1.3 allocate x-slice array
+
+!
+!*       1.4 variables for the eigenvalues computation
+!
+ZGWNX = XPI/REAL(IIMAX_ll)
+ZGWNY = XPI/REAL(IJMAX_ll)
+!
+!------------------------------------------------------------------------------
+!
+!*       2.    COMPUTE THE AVERAGE OF RHOJ*CPD*THETAVREF ALONG XY
+!              --------------------------------------------------
+!
+ZINVMEAN = 1./REAL(IIMAX_ll*IJMAX_ll)
+!JUAN16
+ALLOCATE(ZRHOM_2D(IIB:IIE, IJB:IJE)) 
+PRHO_ZS = 1.0
+!
+DO JK = 1,SIZE(PZZ,3)
+   IF ( CEQNSYS == 'DUR' .OR. CEQNSYS == 'MAE' ) THEN
+      DO JJ = IJB,IJE
+         DO JI = IIB,IIE
+            ZRHOM_2D(JI,JJ)    = PRHODJ(JI,JJ,JK)*XCPD*PTHVREF(JI,JJ,JK)
+            PRHO_ZS(JI,JJ,JK) = ZRHOM_2D(JI,JJ)
+         END DO
+      END DO
+   ELSEIF ( CEQNSYS == 'LHE' ) THEN
+      DO JJ = IJB,IJE
+         DO JI = IIB,IIE
+            ZRHOM_2D(JI,JJ)    = PRHODJ(JI,JJ,JK)  
+            PRHO_ZS(JI,JJ,JK) = ZRHOM_2D(JI,JJ)
+         END DO
+      END DO
+   END IF
+   !  global sum
+   PRHOM(JK) =  SUM_DD_R2_ll(ZRHOM_2D) * ZINVMEAN 
+END DO
+
+!
+!------------------------------------------------------------------------------
+!
+!*       3.    COMPUTE THE MEAN INCREMENT BETWEEN Z LEVELS
+!              -------------------------------------------
+!
+ALLOCATE(ZDZM_2D(IIB:IIE, IJB:IJE))
+ALLOCATE(ZDZM_ZS(IIB:IIE, IJB:IJE,IKU))
+ZDZM_ZS = 1.0
+!
+DO JK = IKB-1,IKE
+   DO JJ = IJB,IJE
+      DO JI = IIB,IIE
+         ZDZM_2D(JI,JJ) = (PZZ(JI,JJ,JK+1)-PZZ(JI,JJ,JK))
+         ZDZM_ZS(JI,JJ,JK) = ZDZM_2D(JI,JJ)
+      END DO
+   END DO
+   ZDZM(JK)  =  SUM_DD_R2_ll(ZDZM_2D) * ZINVMEAN
+END DO
+ZDZM(IKE+1) = ZDZM(IKE)
+ZDZM_ZS(:,:,IKE+1) = ZDZM_ZS(:,:,IKE)
+!
+! vertical average to arrive at a w-level 
+DO JK = IKE+1,IKB,-1
+  ZDZM(JK) = (ZDZM(JK) + ZDZM(JK-1))*0.5
+  ZDZM_ZS(IIB:IIE,IJB:IJE,JK) = (ZDZM_ZS(IIB:IIE,IJB:IJE,JK) + ZDZM_ZS(IIB:IIE,IJB:IJE,JK-1)) * 0.5
+END DO
+!
+ZDZM(IKB-1) = -999.
+ZDZM_ZS(IIB:IIE,IJB:IJE,IKB-1) = -999.
+!
+!------------------------------------------------------------------------------
+!
+!*       4.    COMPUTE THE MEAN INCREMENT BETWEEN X LEVELS
+!              -------------------------------------------
+!
+PDXHATM =0.
+!     . local sum
+IF (LCARTESIAN) THEN
+  PDXHATM = SUM_1DFIELD_ll ( PDXHAT,'X',IIB_ll,IIE_ll,IINFO_ll)
+  DO JJ=1,SIZE(PDXATH_ZS,2)
+     PDXATH_ZS(:,JJ) = PDXHAT(:)
+  END DO
+ELSE
+  ! Extraction of x-slice PMAP at j=(IJB_ll+IJE_ll)/2
+  CALL GET_SLICE_ll (PMAP,'X',(IJB_ll+IJE_ll)/2,ZXMAP(IIB:IIE) &
+                       ,IIB,IIE,IINFO_ll)
+  ! initialize the work array = PDXHAT/ZXMAP
+  ZWORKX(IIB:IIE) = PDXHAT(IIB:IIE)/ ZXMAP (IIB:IIE)
+  PDXHATM = SUM_1DFIELD_ll ( ZWORKX,'X',IIB_ll,IIE_ll,IINFO_ll)
+  DO JJ=1,SIZE(PDXATH_ZS,2)
+     PDXATH_ZS(:,JJ) = PDXHAT(:) / PMAP(:,JJ)
+  END DO
+END IF
+!    . division to complete sum
+PDXHATM = PDXHATM /  REAL(IIMAX_ll)
+!
+!------------------------------------------------------------------------------
+!
+!*       5.    COMPUTE THE MEAN INCREMENT BETWEEN Y LEVELS
+!              -------------------------------------------
+!
+PDYHATM = 0.
+IF (LCARTESIAN) THEN
+  PDYHATM = SUM_1DFIELD_ll ( PDYHAT,'Y',IJB_ll,IJE_ll,IINFO_ll)
+  DO JI=1,SIZE(PDYATH_ZS,1)
+     PDYATH_ZS(JI,:) = PDYHAT(:)
+  END DO
+ELSE
+  ! Extraction of y-slice PMAP at i=IIB_ll+IIE_ll/2 
+  CALL GET_SLICE_ll (PMAP,'Y',(IIB_ll+IIE_ll)/2,ZYMAP(IJB:IJE) &
+                       ,IJB,IJE,IINFO_ll)
+  ! initialize the work array = PDYHAT / ZYMAP
+  ZWORKY(IJB:IJE) = PDYHAT(IJB:IJE) / ZYMAP (IJB:IJE)
+  PDYHATM = SUM_1DFIELD_ll ( ZWORKY,'Y',IJB_ll,IJE_ll,IINFO_ll)
+  DO JI=1,SIZE(PDYATH_ZS,1)
+     PDYATH_ZS(JI,:) = PDYHAT(:) / PMAP(JI,:)
+  END DO
+END IF
+!    . division to complete sum
+PDYHATM= PDYHATM / REAL(IJMAX_ll)
+!
+!------------------------------------------------------------------------------
+!
+!*      6.    COMPUTE THE OUT-DIAGONAL ELEMENTS A AND C OF THE MATRIX
+!             -------------------------------------------------------
+!
+PAF_ZS = 1.0
+PCF_ZS = 1.0
+A_K = 0.0
+B_K = 0.0
+C_K = 0.0
+DO JK = IKB,IKE
+  PAF(JK) = 0.5 * ( PRHOM(JK-1) + PRHOM(JK)   ) / ZDZM(JK)   **2 
+  PCF(JK) = 0.5 * ( PRHOM(JK)   + PRHOM(JK+1) ) / ZDZM(JK+1) **2 
+
+  PAF_ZS(IIB:IIE,IJB:IJE,JK) = 0.5 * ( PRHO_ZS(IIB:IIE,IJB:IJE,JK-1) + PRHO_ZS(IIB:IIE,IJB:IJE,JK)   ) &
+                                     / ZDZM_ZS(IIB:IIE,IJB:IJE,JK)   **2 
+  PCF_ZS(IIB:IIE,IJB:IJE,JK) = 0.5 * ( PRHO_ZS(IIB:IIE,IJB:IJE,JK) + PRHO_ZS(IIB:IIE,IJB:IJE,JK+1)   ) &
+                                     / ZDZM_ZS(IIB:IIE,IJB:IJE,JK+1) **2 
+
+  D_K(JK) = PRHOM(JK) ! / ZDZM(JK)
+  B_K(JK) = PCF(JK) / D_K(JK)
+  C_K(JK) = PAF(JK) / D_K(JK)
+
+END DO
+
+!
+! at the upper and lower levels PAF and PCF are computed using the Neumann 
+! conditions applying on the vertical component of the gradient
+!            
+PAF(IKE+1) = -0.5 * ( PRHOM(IKE)   + PRHOM(IKE+1) ) / ZDZM(IKE+1) **2 
+D_K(IKE+1) = PRHOM(IKE+1) ! / ZDZM(IKE+1)
+C_K(IKE+1) = PAF(IKE+1) / D_K(IKE+1)
+
+PCF(IKB-1) =  0.5 * ( PRHOM(IKB-1) + PRHOM(IKB)   ) / ZDZM(IKB)   **2 
+D_K(IKB-1) = PRHOM(IKB-1) ! / ZDZM(IKB-1)
+B_K(IKB-1) = PCF(IKB-1) / D_K(IKB-1)
+
+!
+PAF(IKB-1) =  0.0 ! 0.5 * ( PRHOM(IKB-1) + PRHOM(IKB)   ) / ZDZM(IKB)   **2
+C_K(IKB-1) =  0.0
+
+PCF(IKE+1) =  0.0 ! 0.5 * ( PRHOM(IKE)   + PRHOM(IKE+1) ) / ZDZM(IKE+1) **2
+B_K(IKE+1) =  0.0
+
+PAF_ZS(IIB:IIE,IJB:IJE,IKE+1) = -0.5 * ( PRHO_ZS(IIB:IIE,IJB:IJE,IKE) + PRHO_ZS(IIB:IIE,IJB:IJE,IKE+1)   ) &
+                                     / ZDZM_ZS(IIB:IIE,IJB:IJE,IKE+1)   **2 
+PCF_ZS(IIB:IIE,IJB:IJE,IKB-1) =  0.5 * ( PRHO_ZS(IIB:IIE,IJB:IJE,IKB-1) + PRHO_ZS(IIB:IIE,IJB:IJE,IKB)   ) &
+                                     / ZDZM_ZS(IIB:IIE,IJB:IJE,IKB) **2 
+
+PAF_ZS(IIB:IIE,IJB:IJE,IKB-1) = 0.0
+PCF_ZS(IIB:IIE,IJB:IJE,IKE+1) = 0.0
+
+IKBE = IKU
+
+IF ( HPRESOPT == 'ZSOLV' ) THEN
+   call mg_main_mnh_init(IIMAX_ll,IKBE,PDXHATM*IIMAX_ll,ZDZM(IKB)*IKBE,&
+        A_K,B_K,C_K,D_K)
+END IF
+
+!------------------------------------------------------------------------------
+!*       7.    COMPUTE THE DIAGONAL ELEMENTS B OF THE MATRIX
+!              ---------------------------------------------
+!
+!*       7.1   compute the horizontal eigenvalues 
+!
+!
+!*       7.1.1   compute the eigenvalues along the x direction 
+!
+SELECT CASE (HLBCX(1))
+! in the cyclic case, the eigenvalues are the same for two following JM values:
+! it corresponds to the real and complex parts of the FFT
+  CASE('CYCL')                     ! cyclic case
+    IXMODE_ll = IIMAX_ll+2*JPHEXT ! +2
+    IXMODEY_ll = IIUY_ll
+    IXMODEB_ll = IIUB_ll !JUAN Z_SPLITTING
+!
+    DO JI = 1,IXMODE_ll
+      ZEIGENX_ll(JI) = - (   2. * SIN ( (JI-1)/2*ZGWNX ) / PDXHATM )**2
+    END DO
+  CASE DEFAULT                !    other cases
+    IXMODE_ll = IIMAX_ll
+!
+!
+    IF (LEAST_ll(HSPLITTING='Y')) THEN
+      IXMODEY_ll = IIUY_ll - 2*JPHEXT  ! -2
+    ELSE
+      IXMODEY_ll = IIUY_ll
+    END IF
+!JUAN Z_SPLITTING
+    IF (LEAST_ll(HSPLITTING='B')) THEN
+      IXMODEB_ll = IIUB_ll - 2*JPHEXT  ! -2
+    ELSE
+      IXMODEB_ll = IIUB_ll
+    END IF
+!JUAN Z_SPLITTING
+!
+!
+    DO JI = 1,IXMODE_ll
+      ZEIGENX_ll(JI) = - (   2. *SIN (0.5*REAL(JI-1)*ZGWNX ) / PDXHATM  )**2
+    END DO
+END SELECT
+!
+!*       7.1.2   compute the eventual eigenvalues along the y direction
+!
+IF (.NOT. L2D) THEN
+!
+! y lateral boundary conditions for three-dimensional cases
+!
+  SELECT CASE (HLBCY(1))
+! in the cyclic case, the eigenvalues are the same for two following JN values:
+! it corresponds to the real and complex parts of the FFT result
+!
+    CASE('CYCL')                      ! 3D cyclic case
+      IYMODE_ll = IJMAX_ll+2*JPHEXT ! +2
+      IYMODEY_ll = IJUY_ll
+      IYMODEB_ll = IJUB_ll !JUAN Z_SPLITTING
+!
+      DO JJ = 1,IYMODE_ll
+        DO JI = 1,IXMODE_ll
+          ZEIGEN_ll(JI,JJ) = ZEIGENX_ll(JI) -    &
+                         (  2.* SIN ( (JJ-1)/2*ZGWNY ) / PDYHATM  )**2
+        END DO
+      END DO
+!
+    CASE DEFAULT                      ! 3D non-cyclic cases
+      IYMODE_ll = IJMAX_ll
+      IYMODEY_ll = IJUY_ll - 2*JPHEXT ! -2
+      IYMODEB_ll = IJUB_ll - 2*JPHEXT ! -2 JUAN Z_SPLITTING
+!
+      DO JJ = 1,IYMODE_ll
+        DO JI = 1,IXMODE_ll
+          ZEIGEN_ll(JI,JJ) = ZEIGENX_ll(JI) - (  2.* SIN (0.5*REAL(JJ-1)*ZGWNY ) / &
+                                                 PDYHATM   )**2
+        END DO
+      END DO
+!
+  END SELECT
+ELSE
+!
+!  copy the x eigenvalue array in a 2D array for a 2D case
+!
+  IYMODE_ll = 1
+  IYMODEY_ll = 1
+  ZEIGEN_ll(1:IXMODE_ll,1)=ZEIGENX_ll(1:IXMODE_ll)
+!
+END IF
+!
+DEALLOCATE(ZEIGENX_ll)
+!
+!CALL MPPDB_CHECK2D(ZEIGEN_ll,"TRIDZ::ZEIGEN_ll",PRECISION)
+!
+!
+!*       7.2   compute the matrix diagonal elements
+!
+!
+PBFY = 1.
+PBFB = 1.  ! JUAN Z_SLIDE
+PBF_SXP2_YP1_Z = 1.  ! JUAN Z_SLIDE
+!
+IF (L2D) THEN
+  DO JK= IKB,IKE
+    DO JJ= 1, IYMODEY_ll
+      DO JI= 1, IXMODEY_ll
+        PBFY(JI,JJ,JK) = PRHOM(JK)* ZEIGEN_ll(JI+IORXY_ll-1,JJ+IORYY_ll-1) - 0.5 * &
+        ( ( PRHOM(JK-1) + PRHOM(JK)   ) / ZDZM(JK)  **2                          &
+         +( PRHOM(JK)   + PRHOM(JK+1) ) / ZDZM(JK+1)**2 )
+      END DO
+    END DO
+  END DO
+! at the upper and lower levels PBFY is computed using the Neumann
+! condition
+!
+  PBFY(1:IXMODEY_ll,1:IYMODEY_ll,IKB-1) = -0.5 * ( PRHOM(IKB-1) + PRHOM(IKB)   ) /  &
+                               ZDZM(IKB)   **2
+  !
+  PBFY(1:IXMODEY_ll,1:IYMODEY_ll,IKE+1) =  0.5 * ( PRHOM(IKE)   + PRHOM(IKE+1) ) /  &
+                               ZDZM(IKE+1) **2
+  !
+ELSE
+  DO JK= IKB,IKE
+    DO JJ= 1, IYMODEY_ll
+      DO JI= 1, IXMODEY_ll
+        PBFY(JJ,JI,JK) = PRHOM(JK)* ZEIGEN_ll(JI+IORXY_ll-1,JJ+IORYY_ll-1) - 0.5 * &
+        ( ( PRHOM(JK-1) + PRHOM(JK)   ) / ZDZM(JK)  **2                          &
+         +( PRHOM(JK)   + PRHOM(JK+1) ) / ZDZM(JK+1)**2 )
+      END DO
+    END DO
+  END DO
+! at the upper and lower levels PBFY is computed using the Neumann
+! condition
+!
+  PBFY(1:IYMODEY_ll,1:IXMODEY_ll,IKB-1) = -0.5 * ( PRHOM(IKB-1) + PRHOM(IKB)   ) /  &
+                               ZDZM(IKB)   **2
+  !
+  PBFY(1:IYMODEY_ll,1:IXMODEY_ll,IKE+1) =  0.5 * ( PRHOM(IKE)   + PRHOM(IKE+1) ) /  &
+                               ZDZM(IKE+1) **2
+  !
+
+!JUAN Z_SPLITTING
+!JUAN for Z splitting we need to do the vertical substitution
+!JUAN in Bsplitting slides so need PBFB 
+PBF_ZS = 1.0
+  DO JK= IKB,IKE
+    DO JJ= IJB,IJE
+      DO JI= IIB,IIE
+
+         PBFB(JI,JJ,JK) =  PRHOM(JK)* ( -2.0 / PDXHATM**2  -2.0 /PDYHATM**2  )       - 0.5 * &
+        ( ( PRHOM(JK-1) + PRHOM(JK)   ) / ZDZM(JK)  **2                                      &
+         +( PRHOM(JK)   + PRHOM(JK+1) ) / ZDZM(JK+1)**2 )
+
+         PBF_ZS(JI,JJ,JK) = PRHO_ZS(JI,JJ,JK)* ( -2.0 / PDXATH_ZS(JI,JJ)**2  -2.0 /PDYATH_ZS(JI,JJ)**2  )   - 0.5 * &
+        ( ( PRHO_ZS(JI,JJ,JK-1) + PRHO_ZS(JI,JJ,JK)   ) / ZDZM_ZS(JI,JJ,JK)  **2                                    &
+         +( PRHO_ZS(JI,JJ,JK)   + PRHO_ZS(JI,JJ,JK+1) ) / ZDZM_ZS(JI,JJ,JK+1)**2 )
+
+      END DO
+    END DO
+  END DO
+! at the upper and lower levels PBFB is computed using the Neumann
+! condition
+!
+  PBFB(IIB:IIE,IJB:IJE,IKB-1) = - 0.5 * ( PRHOM(IKB-1) + PRHOM(IKB)   ) / ZDZM(IKB)   **2
+  !
+  PBFB(IIB:IIE,IJB:IJE,IKE+1) = + 0.5 * ( PRHOM(IKE)   + PRHOM(IKE+1) ) / ZDZM(IKE+1) **2
+
+  PBF_ZS(IIB:IIE,IJB:IJE,IKB-1) = - 0.5 * ( PRHO_ZS(IIB:IIE,IJB:IJE,IKB-1) + PRHO_ZS(IIB:IIE,IJB:IJE,IKB)   ) &
+                                  / ZDZM_ZS(IIB:IIE,IJB:IJE,IKB)**2 
+
+  PBF_ZS(IIB:IIE,IJB:IJE,IKE+1) =   0.5 * ( PRHO_ZS(IIB:IIE,IJB:IJE,IKE)   + PRHO_ZS(IIB:IIE,IJB:IJE,IKE+1) ) &
+                                  / ZDZM_ZS(IIB:IIE,IJB:IJE,IKE+1)**2                         
+!
+IF (HLBCX(1) == 'CYCL' .AND. .NOT.(L2D) ) THEN
+   !JUAN
+   ! fil unused 2 coef with NI+1 coef (lost in Z transposition elsewhere )
+   JI = IXMODE_ll -1
+   ZEIGEN_ll(2,:)  = ZEIGEN_ll(JI,:)
+END IF
+IF (HLBCY(1) == 'CYCL' .AND. .NOT.(L2D) ) THEN
+   !JUAN
+   ! fill unused (:,2,:) coef with NJ+1 coef (lost in Z transposition elsewhere )
+   JJ = IYMODE_ll -1
+   ZEIGEN_ll(:,2)  = ZEIGEN_ll(:,JJ)
+END IF
+  !
+!JUAN Z_SPLITTING
+!JUAN Z_SPLITTING
+!JUAN for Z splitting we need to do the vertical substitution
+!JUAN in _SXP2_YP1_Zsplitting slides so need PBF_SXP2_YP1_Z 
+  DO JK=IKB,IKE
+    DO JJ= 1, IJU_SXP2_YP1_Z_ll
+      DO JI= 1, IIU_SXP2_YP1_Z_ll
+        PBF_SXP2_YP1_Z(JI,JJ,JK) = PRHOM(JK)* ZEIGEN_ll(JI+IORX_SXP2_YP1_Z_ll-IIB_ll,JJ+IORY_SXP2_YP1_Z_ll-IJB_ll) - 0.5 * &
+        ( ( PRHOM(JK-1) + PRHOM(JK)   ) / ZDZM(JK)  **2                          &
+         +( PRHOM(JK)   + PRHOM(JK+1) ) / ZDZM(JK+1)**2 )
+      END DO
+    END DO
+  END DO
+! at the upper and lower levels PBFB is computed using the Neumann
+! condition
+!
+  PBF_SXP2_YP1_Z(1:IIU_SXP2_YP1_Z_ll,1:IJU_SXP2_YP1_Z_ll,IKB-1) = -0.5 * ( PRHOM(IKB-1) + PRHOM(IKB)   ) /  &
+                               ZDZM(IKB)   **2
+  !
+  PBF_SXP2_YP1_Z(1:IIU_SXP2_YP1_Z_ll,1:IJU_SXP2_YP1_Z_ll,IKE+1) =  0.5 * ( PRHOM(IKE)   + PRHOM(IKE+1) ) /  &
+                               ZDZM(IKE+1) **2
+  !
+!JUAN Z_SPLITTING
+END IF
+!
+! second coefficent is meaningless in cyclic case
+IF (HLBCX(1) == 'CYCL' .AND. L2D .AND. SIZE(PBFY,1) .GE. 2 ) PBFY(2,:,:)=1.
+IF (HLBCX(1) == 'CYCL' .AND. .NOT.(L2D) .AND. LWEST_ll(HSPLITTING='Y') .AND. SIZE(PBFY,2) .GE.2 ) &
+    PBFY(:,2,:)=1.
+IF (HLBCY(1) == 'CYCL' .AND. .NOT.(L2D) .AND. SIZE(PBFY,1) .GE. 2  ) PBFY(2,:,:)=1.
+!JUAN Z_SPLITTING
+! second coefficent is meaningless in cyclic case
+!IF (HLBCX(1) == 'CYCL' .AND. L2D  .AND. SIZE(PBFB,1) .GE. 2  ) PBFB(2,:,:)=1.
+!IF (HLBCX(1) == 'CYCL' .AND. .NOT.(L2D) .AND. LWEST_ll(HSPLITTING='B')  .AND. SIZE(PBFB,2) .GE.2 ) &
+!    PBFB(:,2,:)=1.
+!IF (HLBCY(1) == 'CYCL' .AND. .NOT.(L2D)  .AND. SIZE(PBFB,1) .GE. 2 ) PBFB(2,:,:)=1.
+!JUAN Z_SPLITTING
+!
+DEALLOCATE(ZEIGEN_ll)
+!
+!
+!------------------------------------------------------------------------------
+!*       8.    INITIALIZATION OF THE TRIGS AND IFAX ARRAYS FOR THE FFT 
+!              -------------------------------------------------------
+!
+!        8.1 x lateral boundary conditions
+!                  
+CALL SET99(PTRIGSX,KIFAXX,IIMAX_ll)
+!
+! test on the value of KIMAX: KIMAX must be factorizable as a product
+! of powers of 2,3 and 5. KIFAXX(10) is equal to IIMAX if the decomposition 
+! is correct, then KIFAXX(1) contains the number of decomposition factors
+! of KIMAX.
+!
+IF (KIFAXX(10) /=  IIMAX_ll) THEN
+      WRITE(UNIT=ILUOUT,FMT="('   ERROR',/,                               &
+      &'     : THE FORM OF THE FFT USED FOR THE INVERSION OF THE FLAT ',/,&
+      &'    OPERATOR REQUIRES THAT KIMAX MUST BE FACTORIZABLE'         ,/,&
+      & '         AS A PRODUCT OF POWERS OF 2, 3 AND 5.')")
+ !callabortstop
+      CALL PRINT_MSG(NVERB_FATAL,'GEN','TRIDZ','')
+END IF 
+!
+IF (HLBCX(1) /= 'CYCL') THEN
+!
+!     extra trigs for shifted (co) sine transform (FFT55)
+!
+  INN=2*(IIMAX_ll)
+  ZDEL=ASIN(1.0)/REAL(IIMAX_ll)
+  DO JI=1,IIMAX_ll
+    ZANGLE=REAL(JI)*ZDEL
+    PTRIGSX(INN+JI)=SIN(ZANGLE)
+  END DO
+!
+ENDIF
+!
+!       8.2 y lateral boundary conditions
+!
+IF (.NOT. L2D) THEN 
+  CALL SET99(PTRIGSY,KIFAXY,IJMAX_ll)
+  !
+  ! test on the value of KJMAX: KJMAX must be factorizable as a product
+  ! of powers of 2,3 and 5. KIFAXY(10) is equal to IJMAX_ll if the decomposition 
+  ! is correct, then KIFAXX(1) contains the number of decomposition factors
+  ! of IIMAX_ll.
+  !
+  IF (KIFAXY(10) /= IJMAX_ll) THEN
+      WRITE(UNIT=ILUOUT,FMT="('   ERROR',/,                               &
+      &'     : THE FORM OF THE FFT USED FOR THE INVERSION OF THE FLAT ',/,&
+      &'    OPERATOR REQUIRES THAT KJMAX MUST BE FACTORIZABLE'         ,/,&
+      & '         AS A PRODUCT OF POWERS OF 2, 3 AND 5.')")
+ !callabortstop
+      CALL PRINT_MSG(NVERB_FATAL,'GEN','TRIDZ','')
+ END IF 
+ !
+ !
+ !     other cases 
+ !
+ IF (HLBCY(1) /= 'CYCL') THEN                
+ !
+ !     extra trigs for shifted (co) sine transform
+ !
+   INN=2*(IJMAX_ll)
+   ZDEL=ASIN(1.0)/REAL(IJMAX_ll)
+   DO JJ=1,IJMAX_ll
+     ZANGLE=REAL(JJ)*ZDEL
+     PTRIGSY(INN+JJ)=SIN(ZANGLE)
+   END DO
+ !
+ ENDIF
+ !
+ENDIF
+!
+!------------------------------------------------------------------------------
+!
+END SUBROUTINE TRIDZ
diff --git a/src/ZSOLVER/zconjgrad.f90 b/src/ZSOLVER/zconjgrad.f90
new file mode 100644
index 0000000000000000000000000000000000000000..35d82862f990a91586103de8401beed89b72f1a0
--- /dev/null
+++ b/src/ZSOLVER/zconjgrad.f90
@@ -0,0 +1,292 @@
+!MNH_LIC Copyright 1994-2014 CNRS, Meteo-France and Universite Paul Sabatier
+!MNH_LIC This is part of the Meso-NH software governed by the CeCILL-C licence
+!MNH_LIC version 1. See LICENSE, CeCILL-C_V1-en.txt and CeCILL-C_V1-fr.txt  
+!MNH_LIC for details. version 1.
+!-----------------------------------------------------------------
+!--------------- special set of characters for RCS information
+!-----------------------------------------------------------------
+! $Source$ $Revision$
+! MASDEV4_7 solver 2006/05/18 13:07:25
+!-----------------------------------------------------------------
+!     ####################
+      MODULE MODI_ZCONJGRAD
+!     ####################
+!
+INTERFACE
+!
+      SUBROUTINE ZCONJGRAD(HLBCX,HLBCY,PDXX,PDYY,PDZX,PDZY,PDZZ,PRHODJ,PTHETAV, &
+      PDXHATM,PDYHATM,PRHOM,PAF,PBF,PCF,PTRIGSX,PTRIGSY,KIFAXX,KIFAXY,         &
+      KITR,PY,PPHI)
+!  
+IMPLICIT NONE
+!
+CHARACTER (LEN=4), DIMENSION(2), INTENT(IN) :: HLBCX    ! x-direction LBC type 
+CHARACTER (LEN=4), DIMENSION(2), INTENT(IN) :: HLBCY    ! y-direction LBC type 
+!
+                                                 ! Metric coefficients:
+REAL, DIMENSION(:,:,:), INTENT(IN)  :: PDXX      ! d*xx 
+REAL, DIMENSION(:,:,:), INTENT(IN)  :: PDYY      ! d*yy 
+REAL, DIMENSION(:,:,:), INTENT(IN)  :: PDZX      ! d*zx 
+REAL, DIMENSION(:,:,:), INTENT(IN)  :: PDZY      ! d*zy 
+REAL, DIMENSION(:,:,:), INTENT(IN)  :: PDZZ      ! d*zz
+!
+REAL, DIMENSION(:,:,:), INTENT(IN)  :: PRHODJ    ! density of reference * J
+REAL, DIMENSION(:,:,:), INTENT(IN)  :: PTHETAV   ! virtual potential temp. at time t
+!
+REAL, INTENT(IN) :: PDXHATM                     ! mean grid increment in the x
+                                                ! direction
+REAL, INTENT(IN) :: PDYHATM                     ! mean grid increment in the y
+                                                ! direction
+!
+REAL, DIMENSION (:), INTENT(IN) :: PRHOM         !  mean of XRHODJ on the plane x y 
+                                                 !  localized at a mass level
+!
+REAL, DIMENSION(:), INTENT(IN)     :: PAF,PCF    ! vectors giving the nonvanishing
+REAL, DIMENSION(:,:,:), INTENT(IN) :: PBF        ! elements of the tri-diag. 
+                                                 ! matrix in the pressure eq.
+!
+                                                 ! arrays of sin or cos values
+                                                 ! for the FFT :
+REAL, DIMENSION(:), INTENT(IN) :: PTRIGSX        ! - along x
+REAL, DIMENSION(:), INTENT(IN) :: PTRIGSY        ! - along y
+!
+                                                 ! decomposition in prime 
+                                                 ! numbers for the FFT:
+INTEGER, DIMENSION(19), INTENT(IN) :: KIFAXX      ! - along x
+INTEGER, DIMENSION(19), INTENT(IN) :: KIFAXY      ! - along y
+!
+INTEGER, INTENT(IN) :: KITR                      ! number of iterations for the
+                                                 ! pressure solver
+!
+REAL, DIMENSION(:,:,:), INTENT(IN) :: PY         ! RHS of the equation
+!          
+REAL, DIMENSION(:,:,:), INTENT(INOUT) :: PPHI    ! solution of the equation 
+!
+END SUBROUTINE ZCONJGRAD
+!
+END INTERFACE
+!
+END  MODULE MODI_ZCONJGRAD
+!
+!
+!
+!     #########################################################################
+      SUBROUTINE ZCONJGRAD(HLBCX,HLBCY,PDXX,PDYY,PDZX,PDZY,PDZZ,PRHODJ,PTHETAV, &
+      PDXHATM,PDYHATM,PRHOM,PAF,PBF,PCF,PTRIGSX,PTRIGSY,KIFAXX,KIFAXY,         &
+      KITR,PY,PPHI)
+!     #########################################################################
+!
+!!****  *CONJGRAD * - solve an elliptic equation by the conjugate gradient 
+!!       method
+!!
+!!    PURPOSE
+!!    -------
+!       The purpose of this routine is to solve an elliptic equation using 
+!     the preditioned conjugate gradient (CG) method. This is a version of the 
+!     CG called ORTHOMIN (Young and Jea 1980).
+!     
+!!**  METHOD
+!!    ------
+!!      The equation to be solved reads:
+!!
+!!             Q (PHI) = Y
+!!
+!!    where Q is the quasi-Laplacian ( subroutine QLAP ) and PHI the pressure
+!!    function.
+!!    We precondition the problem by the operator F :
+!!             -1               -1 
+!!            F   * Q (PHI) = F    (Y)
+!!    F represents the flat Laplacian ie. without orography. Its inversion is 
+!!    realized in the routine FLAT_INV. This equation is solved with a Conjugate 
+!!    Gradient method.
+!!    The initial guess is given by the pressure at the previous time step.
+!!    The resolution stops after ITR iterations of the solver.
+!!
+!!    EXTERNAL
+!!    --------
+!!      Subroutine GDIV: compute J times the divergence of 1/J times a vector
+!!      Function QLAP: compute the complete quasi-Laplacian Q
+!!      Subroutine FLAT_INV : invert the flat quasi-laplacien F
+!!      Function DOTPROD: compute the dot product of 2 vectors
+!!
+!!    IMPLICIT ARGUMENTS
+!!    ------------------ 
+!!      Module MODI_GDIV: interface for the subroutine GDIV
+!!      Module MODI_QLAP: interface for the function QLAP
+!!      Module MODI_FLAT_INV: interface for the subroutine FLAT_INV
+!!      Module MODI_DOTPROD: interface for the function DOTPROD
+!!
+!!    REFERENCE
+!!    ---------
+!!      Book2 of documentation (routine CONJGRAD)
+!!      Kapitza and Eppel (1992) Beit. Physik ...
+!!      Young and Jea (1980) ....
+!!      
+!!    AUTHOR
+!!    ------
+!!	P. HÃ…reil and J. Stein       * Meteo France *
+!!
+!!    MODIFICATIONS
+!!    -------------
+!!      Original    25/07/94 
+!!
+!!                  14/01/97 Durran anelastic equation (Stein,Lafore)
+!-------------------------------------------------------------------------------
+!
+!*       0.     DECLARATIONS
+!               ------------
+!
+USE MODI_GDIV
+USE MODI_QLAP
+USE MODI_FLAT_INV
+USE MODI_DOTPROD
+USE MODI_ZSOLVER_INV
+!
+IMPLICIT NONE
+!
+!*      0.1    declarations of arguments
+!
+!
+CHARACTER (LEN=4), DIMENSION(2), INTENT(IN) :: HLBCX    ! x-direction LBC type 
+CHARACTER (LEN=4), DIMENSION(2), INTENT(IN) :: HLBCY    ! y-direction LBC type 
+!
+                                                 ! Metric coefficients:
+REAL, DIMENSION(:,:,:), INTENT(IN)  :: PDXX      ! d*xx 
+REAL, DIMENSION(:,:,:), INTENT(IN)  :: PDYY      ! d*yy 
+REAL, DIMENSION(:,:,:), INTENT(IN)  :: PDZX      ! d*zx 
+REAL, DIMENSION(:,:,:), INTENT(IN)  :: PDZY      ! d*zy 
+REAL, DIMENSION(:,:,:), INTENT(IN)  :: PDZZ      ! d*zz
+!
+REAL, DIMENSION(:,:,:), INTENT(IN)  :: PRHODJ    ! density of reference * J
+REAL, DIMENSION(:,:,:), INTENT(IN)  :: PTHETAV   ! virtual potential temp. at time t
+!
+REAL, INTENT(IN) :: PDXHATM                     ! mean grid increment in the x
+                                                ! direction
+REAL, INTENT(IN) :: PDYHATM                     ! mean grid increment in the y
+                                                ! direction
+!
+REAL, DIMENSION (:), INTENT(IN) :: PRHOM         !  mean of XRHODJ on the plane x y 
+                                                 !  localized at a mass level
+!
+REAL, DIMENSION(:), INTENT(IN)     :: PAF,PCF    ! vectors giving the nonvanishing
+REAL, DIMENSION(:,:,:), INTENT(IN) :: PBF        ! elements of the tri-diag. 
+                                                 ! matrix in the pressure eq.
+!
+                                                 ! arrays of sin or cos values
+                                                 ! for the FFT :
+REAL, DIMENSION(:), INTENT(IN) :: PTRIGSX        ! - along x
+REAL, DIMENSION(:), INTENT(IN) :: PTRIGSY        ! - along y
+!
+                                                 ! decomposition in prime 
+                                                 ! numbers for the FFT:
+INTEGER, DIMENSION(19), INTENT(IN) :: KIFAXX      ! - along x
+INTEGER, DIMENSION(19), INTENT(IN) :: KIFAXY      ! - along y
+!
+INTEGER, INTENT(IN) :: KITR                      ! number of iterations for the
+                                                 ! pressure solver
+!
+REAL, DIMENSION(:,:,:), INTENT(IN) :: PY         ! RHS of the equation
+!          
+REAL, DIMENSION(:,:,:), INTENT(INOUT) :: PPHI    ! solution of the equation 
+!
+!*      0.2    declarations of local variables
+!
+INTEGER :: JM                                    ! loop index   
+!
+REAL, DIMENSION(SIZE(PPHI,1),SIZE(PPHI,2),SIZE(PPHI,3)) :: ZDELTA  
+     ! array containing the auxilary field DELTA of the CG method
+!
+REAL, DIMENSION(SIZE(PPHI,1),SIZE(PPHI,2),SIZE(PPHI,3)) :: ZP  
+     ! array containing the auxilary field P of the CG method
+!
+REAL, DIMENSION(SIZE(PPHI,1),SIZE(PPHI,2),SIZE(PPHI,3)) :: ZWORK ! work 
+     ! array containing the source term to be multiplied by the F inverse
+!
+REAL, DIMENSION(SIZE(PPHI,1),SIZE(PPHI,2),SIZE(PPHI,3)) :: ZWORKD ! work 
+     ! array containing the result of the F inversion * Q (DELTA)
+!
+REAL, DIMENSION(SIZE(PPHI,1),SIZE(PPHI,2),SIZE(PPHI,3)) :: ZWORKP ! work 
+     ! array containing the result of the F inversion * Q (P)
+!
+REAL :: ZALPHA, ZLAMBDA      ! amplitude of the descent in the Conjugate
+                             ! directions
+REAL :: ZDOTPP               ! dot product of ZWORKP by itself
+!
+!-------------------------------------------------------------------------------
+!
+!*       1.    INITIALIZATIONS
+!              ---------------
+!
+ZLAMBDA = 0.
+ZP = 0.
+!
+!-------------------------------------------------------------------------------
+!
+!*       2.    ITERATIVE LOOP
+!              --------------
+!
+DO JM = 1,KITR                                                         
+!
+!*       2.1    compute the new pressure function
+!
+  PPHI = PPHI + ZLAMBDA * ZP     !   the case JM =0 is special because 
+                                 !   PPHI is not changed
+!
+!*       2.2    compute the auxiliary field DELTA
+!
+!                                -1
+!   compute the vector DELTA = F  * ( Y - Q ( PHI ) )
+!    
+  ZWORK = QLAP(HLBCX,HLBCY,PDXX,PDYY,PDZX,PDZY,PDZZ,PRHODJ,PTHETAV,PPHI) 
+                                                               ! Q (PHI)
+!                       
+  ZWORK = PY - ZWORK                                           ! Y - Q (PHI)
+!
+  CALL FLAT_INV(HLBCX,HLBCY,PDXHATM,PDYHATM,PRHOM,PAF,PBF,PCF, &!  -1
+                  PTRIGSX,PTRIGSY,KIFAXX,KIFAXY,ZWORK,ZDELTA)   ! F  (Y - Q (PHI)))
+!   
+!*      2.3     compute the auxiliary field P
+!
+!                                         -1
+!   compute the vector P = DELTA + alpha F  * Q ( DELTA ) 
+!  
+  IF (JM == 1) THEN
+    ZP = ZDELTA          ! P = DELTA at the first solver iteration
+  ELSE
+    ZWORK  = QLAP(HLBCX,HLBCY,PDXX,PDYY,PDZX,PDZY,  &
+                PDZZ,PRHODJ,PTHETAV,ZDELTA)                         ! Q ( DELTA )
+    CALL FLAT_INV(HLBCX,HLBCY,PDXHATM,PDYHATM,PRHOM,PAF,PBF,PCF,  & !  -1
+            PTRIGSX,PTRIGSY,KIFAXX,KIFAXY,ZWORK,ZWORKD)             ! F  * Q ( DELTA ) 
+!
+    ZALPHA = - DOTPROD(ZWORKD,ZWORKP,HLBCX,HLBCY)/ZDOTPP   ! ZWORKP,ZDOTPP come 
+                     ! from the previous solver iteration  (section 2.4)
+    ZP = ZDELTA + ZALPHA * ZP                              ! new vector P
+!
+  END IF
+!
+!*      2.4     compute LAMBDA
+!
+!
+  ZWORK = QLAP(HLBCX,HLBCY,PDXX,PDYY,PDZX,PDZY,&
+  PDZZ,PRHODJ,PTHETAV,ZP)                                       ! Q ( P )
+  CALL FLAT_INV(HLBCX,HLBCY,PDXHATM,PDYHATM,PRHOM,PAF,PBF,PCF,& !  -1
+  PTRIGSX,PTRIGSY,KIFAXX,KIFAXY,ZWORK,ZWORKP)                   ! F  * Q ( P )
+!
+!    store the scalar product to compute lambda and next P
+  ZDOTPP = DOTPROD(ZWORKP,ZWORKP,HLBCX,HLBCY)   
+!
+  ZLAMBDA = DOTPROD(ZDELTA,ZWORKP,HLBCX,HLBCY) / ZDOTPP   ! lambda
+!
+!
+END DO              ! end of the loop for the iterative solver
+!
+!-------------------------------------------------------------------------------
+!
+!*       3.    COMPUTE THE FINAL PRESSURE FUNCTION
+!              -----------------------------------
+!
+PPHI = PPHI + ZLAMBDA * ZP
+!  
+!-------------------------------------------------------------------------------
+!
+END SUBROUTINE ZCONJGRAD
diff --git a/src/ZSOLVER/zsolver.f90 b/src/ZSOLVER/zsolver.f90
new file mode 100644
index 0000000000000000000000000000000000000000..67c35779264fbbf9c63b31a89c940a7c27ad8c41
--- /dev/null
+++ b/src/ZSOLVER/zsolver.f90
@@ -0,0 +1,295 @@
+!MNH_LIC Copyright 1994-2014 CNRS, Meteo-France and Universite Paul Sabatier
+!MNH_LIC This is part of the Meso-NH software governed by the CeCILL-C licence
+!MNH_LIC version 1. See LICENSE, CeCILL-C_V1-en.txt and CeCILL-C_V1-fr.txt  
+!MNH_LIC for details. version 1.
+!-----------------------------------------------------------------
+!--------------- special set of characters for RCS information
+!-----------------------------------------------------------------
+! $Source$ $Revision$
+! MASDEV4_7 solver 2006/05/18 13:07:25
+!-----------------------------------------------------------------
+!     ####################
+      MODULE MODI_ZSOLVER
+!     ####################
+!
+INTERFACE
+!
+      SUBROUTINE ZSOLVER(HLBCX,HLBCY,PDXX,PDYY,PDZX,PDZY,PDZZ,PRHODJ,PTHETAV, &
+      PDXHATM,PDYHATM,PRHOM,PAF,PBF,PCF,PTRIGSX,PTRIGSY,KIFAXX,KIFAXY,        &
+      KITR,PY,PPHI,                                                           &
+      PAF_ZS,PBF_ZS,PCF_ZS,                                                   &
+      PDXATH_ZS,PDYATH_ZS,PRHO_ZS,PBFB,                                     &
+      A_K,B_K,C_K,D_K) !JUAN FULL ZSOLVER
+!  
+IMPLICIT NONE
+!
+CHARACTER (LEN=4), DIMENSION(2), INTENT(IN) :: HLBCX    ! x-direction LBC type 
+CHARACTER (LEN=4), DIMENSION(2), INTENT(IN) :: HLBCY    ! y-direction LBC type 
+!
+                                                 ! Metric coefficients:
+REAL, DIMENSION(:,:,:), INTENT(IN)  :: PDXX      ! d*xx 
+REAL, DIMENSION(:,:,:), INTENT(IN)  :: PDYY      ! d*yy 
+REAL, DIMENSION(:,:,:), INTENT(IN)  :: PDZX      ! d*zx 
+REAL, DIMENSION(:,:,:), INTENT(IN)  :: PDZY      ! d*zy 
+REAL, DIMENSION(:,:,:), INTENT(IN)  :: PDZZ      ! d*zz
+!
+REAL, DIMENSION(:,:,:), INTENT(IN)  :: PRHODJ    ! density of reference * J
+REAL, DIMENSION(:,:,:), INTENT(IN)  :: PTHETAV   ! virtual pot. temp. at time t
+!
+REAL, INTENT(IN) :: PDXHATM                     ! mean grid increment in the x
+                                                ! direction
+REAL, INTENT(IN) :: PDYHATM                     ! mean grid increment in the y
+                                                ! direction
+!
+REAL, DIMENSION (:), INTENT(IN) :: PRHOM         !  XRHODJ mean on the X Y plane
+                                                 !  localized at a mass level
+!
+REAL, DIMENSION(:), INTENT(IN)     :: PAF,PCF    ! vectors giving the nonvanishing
+REAL, DIMENSION(:,:,:), INTENT(IN) :: PBF        ! elements of the tri-diag. 
+                                                 ! matrix in the pressure eq.
+!
+                                                 ! arrays of sin or cos values
+                                                 ! for the FFT :
+REAL, DIMENSION(:), INTENT(IN) :: PTRIGSX        ! - along x
+REAL, DIMENSION(:), INTENT(IN) :: PTRIGSY        ! - along y
+!
+                                                 ! decomposition in prime 
+                                                 ! numbers for the FFT:
+INTEGER, DIMENSION(19), INTENT(IN) :: KIFAXX      ! - along x
+INTEGER, DIMENSION(19), INTENT(IN) :: KIFAXY      ! - along y
+!
+INTEGER, INTENT(IN) :: KITR                      ! number of iterations for the
+                                                 ! pressure solver
+!
+REAL, DIMENSION(:,:,:), INTENT(IN) :: PY         ! RHS of the equation
+!          
+REAL, DIMENSION(:,:,:), INTENT(INOUT) :: PPHI    ! solution of the equation 
+
+REAL, DIMENSION(:,:,:), INTENT(IN) :: PAF_ZS,PBF_ZS,PCF_ZS
+REAL, DIMENSION(:,:)  , INTENT(IN) :: PDXATH_ZS,PDYATH_ZS
+REAL, DIMENSION(:,:,:), INTENT(IN) :: PRHO_ZS,PBFB
+REAL, DIMENSION(:)    , INTENT(IN) :: A_K,B_K,C_K,D_K
+!
+END SUBROUTINE ZSOLVER
+!
+END INTERFACE
+!
+END  MODULE MODI_ZSOLVER
+!
+!
+!
+!     #########################################################################
+      SUBROUTINE ZSOLVER(HLBCX,HLBCY,PDXX,PDYY,PDZX,PDZY,PDZZ,PRHODJ,PTHETAV, &
+      PDXHATM,PDYHATM,PRHOM,PAF,PBF,PCF,PTRIGSX,PTRIGSY,KIFAXX,KIFAXY,        &
+      KITR,PY,PPHI,                                                           &
+      PAF_ZS,PBF_ZS,PCF_ZS,                                                   &
+      PDXATH_ZS,PDYATH_ZS,PRHO_ZS,PBFB,                                       &
+      A_K,B_K,C_K,D_K)
+!     #########################################################################
+!
+!!****  *CONRESOL * - solve an elliptic equation by the conjugate residual
+!!       method
+!!
+!!    PURPOSE
+!!    -------
+!       The purpose of this routine is to solve an elliptic equation using 
+!     the preconditioned conjugate residual (CR) method. This is a version
+!     of the scheme proposed by Skamarock, Smolarkiewicz and Klemp (MWR, 1997).
+!     
+!!**  METHOD
+!!    ------
+!!      The equation to be solved reads:
+!!
+!!             Q (PHI) = Y
+!!
+!!    where Q is the quasi-Laplacian ( subroutine QLAP ) and PHI the pressure
+!!    function.
+!!    We precondition the problem by the operator F :
+!!             -1               -1 
+!!            F   * Q (PHI) = F    (Y)
+!!    F represents the flat Laplacian ie. without orography. Its inversion is 
+!!    realized in the routine FLAT_INV. This equation is solved with a Conjugate
+!!    Residual method.
+!!    The initial guess is given by the pressure at the previous time step.
+!!    The resolution stops after ITR iterations of the solver.
+!!
+!!    EXTERNAL
+!!    --------
+!!      Subroutine GDIV: compute J times the divergence of 1/J times a vector
+!!      Function QLAP: compute the complete quasi-Laplacian Q
+!!      Subroutine FLAT_INV : invert the flat quasi-laplacien F
+!!      Function DOTPROD: compute the dot product of 2 vectors
+!!
+!!    IMPLICIT ARGUMENTS
+!!    ------------------ 
+!!      Module MODI_GDIV: interface for the subroutine GDIV
+!!      Module MODI_QLAP: interface for the function QLAP
+!!      Module MODI_FLAT_INV: interface for the subroutine FLAT_INV
+!!      Module MODI_DOTPROD: interface for the function DOTPROD
+!!
+!!    REFERENCE
+!!    ---------
+!!      Book2 of documentation (routine CONRESOL)
+!!      Skamarock, Smolarkiewicz and Klemp (1997) MWR
+!!      
+!!    AUTHOR
+!!    ------
+!!	J.-P. Pinty *Laboratoire d'Aerologie*
+!!
+!!    MODIFICATIONS
+!!    -------------
+!!      Original    25/08/99 
+!!      J.-P. Pinty & P. Jabouille
+!!                  11/07/00 bug in ZALPHA
+!!
+!-------------------------------------------------------------------------------
+!
+!*       0.     DECLARATIONS
+!               ------------
+!
+USE MODI_GDIV
+USE MODI_QLAP
+USE MODI_FLAT_INV
+USE MODI_ZSOLVER_INV
+USE MODI_DOTPROD
+!
+IMPLICIT NONE
+!
+!*      0.1    declarations of arguments
+!
+!
+CHARACTER (LEN=4), DIMENSION(2), INTENT(IN) :: HLBCX    ! x-direction LBC type 
+CHARACTER (LEN=4), DIMENSION(2), INTENT(IN) :: HLBCY    ! y-direction LBC type 
+!
+                                                 ! Metric coefficients:
+REAL, DIMENSION(:,:,:), INTENT(IN)  :: PDXX      ! d*xx 
+REAL, DIMENSION(:,:,:), INTENT(IN)  :: PDYY      ! d*yy 
+REAL, DIMENSION(:,:,:), INTENT(IN)  :: PDZX      ! d*zx 
+REAL, DIMENSION(:,:,:), INTENT(IN)  :: PDZY      ! d*zy 
+REAL, DIMENSION(:,:,:), INTENT(IN)  :: PDZZ      ! d*zz
+!
+REAL, DIMENSION(:,:,:), INTENT(IN)  :: PRHODJ    ! density of reference * J
+REAL, DIMENSION(:,:,:), INTENT(IN)  :: PTHETAV   ! virtual pot. temp. at time t
+!
+REAL, INTENT(IN) :: PDXHATM                     ! mean grid increment in the x
+                                                ! direction
+REAL, INTENT(IN) :: PDYHATM                     ! mean grid increment in the y
+                                                ! direction
+!
+REAL, DIMENSION (:), INTENT(IN) :: PRHOM         !  mean of XRHODJ on the plane x y 
+                                                 !  localized at a mass level
+!
+REAL, DIMENSION(:), INTENT(IN)     :: PAF,PCF    ! vectors giving the nonvanishing
+REAL, DIMENSION(:,:,:), INTENT(IN) :: PBF        ! elements of the tri-diag. 
+                                                 ! matrix in the pressure eq.
+!
+                                                 ! arrays of sin or cos values
+                                                 ! for the FFT :
+REAL, DIMENSION(:), INTENT(IN) :: PTRIGSX        ! - along x
+REAL, DIMENSION(:), INTENT(IN) :: PTRIGSY        ! - along y
+!
+                                                 ! decomposition in prime 
+                                                 ! numbers for the FFT:
+INTEGER, DIMENSION(19), INTENT(IN) :: KIFAXX      ! - along x
+INTEGER, DIMENSION(19), INTENT(IN) :: KIFAXY      ! - along y
+!
+INTEGER, INTENT(IN) :: KITR                      ! number of iterations for the
+                                                 ! pressure solver
+!
+REAL, DIMENSION(:,:,:), INTENT(IN) :: PY         ! RHS of the equation
+!          
+REAL, DIMENSION(:,:,:), INTENT(INOUT) :: PPHI    ! solution of the equation 
+
+REAL, DIMENSION(:,:,:), INTENT(IN) :: PAF_ZS,PBF_ZS,PCF_ZS
+REAL, DIMENSION(:,:)  , INTENT(IN) :: PDXATH_ZS,PDYATH_ZS
+REAL, DIMENSION(:,:,:), INTENT(IN) :: PRHO_ZS,PBFB
+REAL, DIMENSION(:)    , INTENT(IN) :: A_K,B_K,C_K,D_K
+!
+!*      0.2    declarations of local variables
+!
+INTEGER :: JM                                    ! loop index   
+!
+REAL, DIMENSION(SIZE(PPHI,1),SIZE(PPHI,2),SIZE(PPHI,3)) :: ZDELTA, ZKSI  
+     ! array containing the auxilary fields DELTA and KSI of the CR method
+REAL, DIMENSION(SIZE(PPHI,1),SIZE(PPHI,2),SIZE(PPHI,3)) :: ZP, ZQ  
+     ! array containing the auxilary fields P and Q of the CR method
+REAL, DIMENSION(SIZE(PPHI,1),SIZE(PPHI,2),SIZE(PPHI,3)) :: ZRESIDUE
+     ! array containing the error field at each iteration Q(PHI) - Y
+!
+REAL :: ZALPHA, ZLAMBDA      ! amplitude of the descent in the Conjugate
+                             ! directions
+REAL :: ZDOT_DELTA           ! dot product of ZDELTA by itself
+!
+!-------------------------------------------------------------------------------
+!
+!*       1.    INITIALIZATIONS
+!              ---------------
+!
+!                             
+!*       1.1    compute the vector: r^(0) =  Q(PHI) - Y
+!    
+ZRESIDUE = QLAP(HLBCX,HLBCY,PDXX,PDYY,PDZX,PDZY,PDZZ,PRHODJ,PTHETAV,PPHI) - PY
+!
+!*       1.2    compute the vector: p^(0) = F^(-1)*( Q(PHI) - Y )
+!    
+CALL ZSOLVER_INV(HLBCX,HLBCY,PDXHATM,PDYHATM,PRHOM,PAF,PBF,PCF,  &
+                     PTRIGSX,PTRIGSY,KIFAXX,KIFAXY,ZRESIDUE,ZP,  &
+                     PAF_ZS,PBF_ZS,PCF_ZS,                       &
+                     PDXATH_ZS,PDYATH_ZS,PRHO_ZS,PBFB,           &
+                     A_K,B_K,C_K,D_K)
+!
+!*       1.3    compute the vector: delta^(0) = Q ( p^(0) )
+!
+ZDELTA = QLAP(HLBCX,HLBCY,PDXX,PDYY,PDZX,PDZY,PDZZ,PRHODJ,PTHETAV,ZP)
+!
+!-------------------------------------------------------------------------------
+!
+!*       2.    ITERATIVE LOOP
+!              --------------
+!
+DO JM = 1,KITR                                                         
+!
+!*       2.1    compute the step LAMBDA
+!
+  ZDOT_DELTA = DOTPROD(ZDELTA,  ZDELTA,HLBCX,HLBCY)            ! norm of DELTA
+  ZLAMBDA  = - DOTPROD(ZRESIDUE,ZDELTA,HLBCX,HLBCY) / ZDOT_DELTA
+!
+!*       2.2    update the pressure function PHI
+!
+  PPHI = PPHI + ZLAMBDA * ZP
+!
+!
+  IF( JM == KITR ) EXIT
+!
+!
+!*       2.3    update the residual error: r
+!
+  ZRESIDUE = ZRESIDUE + ZLAMBDA * ZDELTA
+!                        
+!*       2.4    compute the vector: q = F^(-1)*( Q(PHI) - Y )
+!    
+  CALL ZSOLVER_INV(HLBCX,HLBCY,PDXHATM,PDYHATM,PRHOM,PAF,PBF,PCF,  &
+                       PTRIGSX,PTRIGSY,KIFAXX,KIFAXY,ZRESIDUE,ZQ,  &
+                       PAF_ZS,PBF_ZS,PCF_ZS,                       &
+                       PDXATH_ZS,PDYATH_ZS,PRHO_ZS,PBFB,           &
+                       A_K,B_K,C_K,D_K)
+!   
+!*       2.5     compute the auxiliary field: ksi = Q ( q )
+!
+  ZKSI= QLAP(HLBCX,HLBCY,PDXX,PDYY,PDZX,PDZY,PDZZ,PRHODJ,PTHETAV,ZQ)
+!                                         -1
+!*       2.6     compute the step ALPHA
+!  
+  ZALPHA = - DOTPROD(ZKSI,ZDELTA,HLBCX,HLBCY) / ZDOT_DELTA   ! lambda
+!
+!*       2.7     update p and DELTA
+!
+  ZP     = ZQ   + ZALPHA * ZP
+  ZDELTA = ZKSI + ZALPHA * ZDELTA
+!
+END DO              ! end of the loop for the iterative solver
+!
+!  
+!-------------------------------------------------------------------------------
+!
+END SUBROUTINE ZSOLVER
diff --git a/src/ZSOLVER/zsolver_inv.f90 b/src/ZSOLVER/zsolver_inv.f90
new file mode 100644
index 0000000000000000000000000000000000000000..781ebb8f4f98ea8a6436e84983805513ca65fc5e
--- /dev/null
+++ b/src/ZSOLVER/zsolver_inv.f90
@@ -0,0 +1,1132 @@
+!MNH_LIC Copyright 1994-2014 CNRS, Meteo-France and Universite Paul Sabatier
+!MNH_LIC This is part of the Meso-NH software governed by the CeCILL-C licence
+!MNH_LIC version 1. See LICENSE, CeCILL-C_V1-en.txt and CeCILL-C_V1-fr.txt  
+!MNH_LIC for details. version 1.
+!-----------------------------------------------------------------
+!--------------- special set of characters for RCS information
+!-----------------------------------------------------------------
+! $Source$ $Revision$
+! MASDEV4_7 solver 2006/05/18 13:07:25
+!-----------------------------------------------------------------
+!     ####################
+      MODULE MODI_ZSOLVER_INV
+!     ####################
+!
+INTERFACE
+!
+      SUBROUTINE ZSOLVER_INV(HLBCX,HLBCY,PDXHATM,PDYHATM,PRHOM,PAF,PBF,PCF, &
+      PTRIGSX,PTRIGSY,KIFAXX,KIFAXY,PY,PF_1_Y,                              &
+      PAF_ZS,PBF_ZS,PCF_ZS,                                                 &
+      PDXATH_ZS,PDYATH_ZS,PRHO_ZS,PBFB,                                     &
+      A_K,B_K,C_K,D_K)
+!
+!  
+IMPLICIT NONE
+!
+CHARACTER (LEN=4), DIMENSION(2), INTENT(IN) :: HLBCX    ! x-direction LBC type 
+CHARACTER (LEN=4), DIMENSION(2), INTENT(IN) :: HLBCY    ! y-direction LBC type 
+!
+REAL, INTENT(IN) :: PDXHATM                     ! mean grid increment in the x
+                                                ! direction
+REAL, INTENT(IN) :: PDYHATM                     ! mean grid increment in the y
+                                                ! direction
+!
+REAL, DIMENSION (:), INTENT(IN) :: PRHOM         !  mean of XRHODJ on the plane x y 
+                                                 !  localized at a mass level
+!
+REAL, DIMENSION(:), INTENT(IN)     :: PAF,PCF    ! vectors giving the nonvanishing
+REAL, DIMENSION(:,:,:), INTENT(IN) :: PBF        ! elements of the tri-diag. 
+                                                 ! matrix in the pressure eq.
+!
+                                                 ! arrays of sin or cos values
+                                                 ! for the FFT :
+REAL, DIMENSION(:), INTENT(IN) :: PTRIGSX        ! - along x
+REAL, DIMENSION(:), INTENT(IN) :: PTRIGSY        ! - along y
+!
+                                                 ! decomposition in prime 
+                                                 ! numbers for the FFT:
+INTEGER, DIMENSION(19), INTENT(IN) :: KIFAXX      ! - along x
+INTEGER, DIMENSION(19), INTENT(IN) :: KIFAXY      ! - along y
+!
+REAL, DIMENSION(:,:,:), INTENT(IN) :: PY         ! RHS of the equation
+!                                                         
+REAL, DIMENSION(:,:,:), INTENT(OUT):: PF_1_Y     ! solution of the equation
+!
+REAL, DIMENSION(:,:,:), INTENT(IN) :: PAF_ZS,PBF_ZS,PCF_ZS
+REAL, DIMENSION(:,:)  , INTENT(IN) :: PDXATH_ZS,PDYATH_ZS
+REAL, DIMENSION(:,:,:), INTENT(IN) :: PRHO_ZS,PBFB
+REAL, DIMENSION(:)    , INTENT(IN) :: A_K,B_K,C_K,D_K
+!
+!
+END SUBROUTINE ZSOLVER_INV
+!
+END INTERFACE
+!
+END MODULE MODI_ZSOLVER_INV
+!     ######################################################################
+SUBROUTINE ZSOLVER_INV(HLBCX,HLBCY,PDXHATM,PDYHATM,PRHOM,PAF,PBF,PCF, &
+     PTRIGSX,PTRIGSY,KIFAXX,KIFAXY,PY,PF_1_Y,                              &
+     PAF_ZS,PBF_ZS,PCF_ZS,                                                 &
+     PDXATH_ZS,PDYATH_ZS,PRHO_ZS,PBFB,                                     &
+     A_K,B_K,C_K,D_K)
+  !     ######################################################################
+  !
+  !!****  *FLAT_INV * - Invert the flat quasi-laplacian operator
+  !!
+  !!    PURPOSE
+  !!    -------
+  !       This routine solves the following equation:
+  !                    F ( F_1_Y ) =  Y 
+  !     where F represents the quasi-laplacian without orography. The solution is 
+  !     F_1_Y.
+  !
+  !!**  METHOD
+  !!    ------
+  !!      The horizontal part of F is inverted with a FFT transform. For each 
+  !!    horizontal direction, the FFT form depends on the lateral boundary 
+  !!    conditions :
+  !!    - CRAY intrinsic function RFFTMLT in the cyclic case 
+  !!    - fast cosine transform called FFT55 for all other boundary condtions.
+  !!    Then, in the wavenumber space, we invert for each 
+  !!    horizontal mode i,j a tridiagonal matrix by a classical double sweep 
+  !!    method.  The singular mean mode (i,j)=(0,0) corresponds to the 
+  !!    undetermination of the pressure to within a constant and is treated apart.
+  !!    To fix this degree of freedom, we set the horizontal mean value of the 
+  !!    pressure perturbation to 0 at the upper level of the model. 
+  !!       
+  !!    EXTERNAL
+  !!    --------
+  !!      Subroutine FFT55 : aplly multiple fast real staggered (shifted) 
+  !!    cosine transform
+  !!      Subroutine RFFTMLT : apply real-to-complex or complex-to-real Fast 
+  !!    Fourier Transform (FFT) on multiple input vectors.
+  !!      Subroutine FFT991  : equivalent to RFFTMLT
+  !!
+  !!    IMPLICIT ARGUMENTS
+  !!    ------------------ 
+  !!      Module MODD_PARAMETERS: declaration of parameter variables
+  !!        JPHEXT, JPVEXT: define the number of marginal points out of the 
+  !!        physical domain along horizontal and vertical directions respectively
+  !!      Module MODD_CONF: model configurations
+  !!        L2D: logical for 2D model version
+  !!
+  !!    REFERENCE
+  !!    ---------
+  !!      Book2 of documentation (subroutine FLAT_INV)     
+  !!
+  !!    AUTHOR
+  !!    ------
+  !!	P. Hereil and J. Stein       * Meteo France *
+  !!
+  !!    MODIFICATIONS
+  !!    -------------
+  !!      Original    20/07/94 
+  !!      Revision  Jabouille (juillet 96) replace the CRAY intrinsic function
+  !!                             RFFTMLT by the arpege routine FFT991
+  !!                  17/07/97  ( J. Stein and V. Masson) initialize the corner
+  !!                             verticals
+  !!                  17/07/97  ( J. Stein and V. Masson) initialize the corner
+  !!                             verticals
+  !!      Revision  Jabouille (septembre 97) suppress the particular case for
+  !!                                         tridiagonal inversion
+  !!                Stein     ( January 98 ) faster computation for the unused 
+  !!                                points under the ground and out of the domain  
+  !!      Modification   Lugato, Guivarch (June 1998) Parallelisation
+  !!                     Escobar, Stein   (July 2000) optimisation
+  !-------------------------------------------------------------------------------
+  !
+  !*       0.    DECLARATIONS
+  !              ------------
+  !
+  USE MODD_PARAMETERS
+  USE MODD_CONF
+  !
+  USE MODE_ll
+  USE MODD_ARGSLIST_ll, ONLY : LIST_ll
+  !
+  USE MODI_FFT55
+  USE MODI_GET_HALO
+  USE MODI_FLAT_INV
+  USE MODI_DOTPROD
+  !
+  USE mode_mg_main_mnh
+  !
+  IMPLICIT NONE
+  !
+  !*       0.1   declarations of arguments
+  !
+  CHARACTER (LEN=4), DIMENSION(2), INTENT(IN) :: HLBCX    ! x-direction LBC type 
+  CHARACTER (LEN=4), DIMENSION(2), INTENT(IN) :: HLBCY    ! y-direction LBC type 
+  !
+  REAL, INTENT(IN) :: PDXHATM                     ! mean grid increment in the x
+  ! direction
+  REAL, INTENT(IN) :: PDYHATM                     ! mean grid increment in the y
+  ! direction
+  !
+  REAL, DIMENSION (:), INTENT(IN) :: PRHOM         !  mean of XRHODJ on the plane x y 
+  !  localized at a mass level
+  !
+  REAL, DIMENSION(:), INTENT(IN)     :: PAF,PCF    ! vectors giving the nonvanishing
+  REAL, DIMENSION(:,:,:), INTENT(IN) :: PBF        ! elements of the tri-diag. 
+  ! matrix in the pressure eq.
+  !
+  ! arrays of sin or cos values
+  ! for the FFT :
+  REAL, DIMENSION(:), INTENT(IN) :: PTRIGSX        ! - along x
+  REAL, DIMENSION(:), INTENT(IN) :: PTRIGSY        ! - along y
+  !
+  ! decomposition in prime 
+  ! numbers for the FFT:
+  INTEGER, DIMENSION(19), INTENT(IN) :: KIFAXX      ! - along x
+  INTEGER, DIMENSION(19), INTENT(IN) :: KIFAXY      ! - along y
+  !
+  REAL, DIMENSION(:,:,:), INTENT(IN) :: PY         ! RHS of the equation
+  !                                                         
+  REAL, DIMENSION(:,:,:), INTENT(OUT):: PF_1_Y     ! solution of the equation
+  !
+  REAL, DIMENSION(:,:,:), INTENT(IN) :: PAF_ZS,PBF_ZS,PCF_ZS
+  REAL, DIMENSION(:,:)  , INTENT(IN) :: PDXATH_ZS,PDYATH_ZS
+  REAL, DIMENSION(:,:,:), INTENT(IN) :: PRHO_ZS,PBFB
+  REAL, DIMENSION(:)    , INTENT(IN) :: A_K,B_K,C_K,D_K
+  !
+  !*       0.2   declaration of local variables
+  !
+  REAL, DIMENSION(SIZE(PY,1),SIZE(PY,2),SIZE(PY,3)) :: ZY ! work array to store 
+  ! the RHS of the equation
+  !
+  !REAL, DIMENSION(SIZE(PY,1),SIZE(PY,2),SIZE(PY,3)) :: ZWORK ! work array used by 
+  ! the FFT. It has been enlarged in order to be sufficient for 2D and 3D cases
+  !
+  REAL, DIMENSION(SIZE(PBF,1),SIZE(PBF,2),SIZE(PBF,3)) :: ZAF ! work array to
+  !                                                        ! expand PAF
+  INTEGER :: IIB          ! indice I for the first inner mass point along x
+  INTEGER :: IIE          ! indice I for the last inner mass point along x
+  INTEGER :: IIMAX        ! number of inner mass points along the x direction
+  INTEGER :: IJB          ! indice J for the first inner mass point along y
+  INTEGER :: IJE          ! indice J for the last inner mass point along y
+  INTEGER :: IJMAX        ! number of inner mass points along the y direction
+  INTEGER :: IKB          ! indice K for the first inner mass point along z
+  INTEGER :: IKE          ! indice K for the last inner mass point along z
+  INTEGER :: IKU          ! size of the arrays along z
+  INTEGER :: IKMAX        ! number of inner mass points along the z direction
+  !
+  REAL :: ZDXM2,ZDYM2     ! respectively equal to PDXHATM*PDXHATM 
+  ! and PDYHATM*PDYHATM                         
+  INTEGER :: JI,JJ,JK     ! loop indexes along x, y, z respectively
+  !
+  !
+  INTEGER :: IIE_INT,IJE_INT   ! highest indice I  and J values for the x y modes.
+  ! They  depend on the l.b.c. !
+  !
+  INTEGER :: ILOTX,ILOTY ! number of data vectors along x, y resp. computed 
+  ! in parallel during the FFT process 
+  !
+  INTEGER :: INC1X,INC1Y ! increment within each data vector for the FFT along
+  ! x, y resp.
+  !
+  INTEGER :: INC2X,INC2Y ! increment between the start of one data vector and 
+  ! the next for the FFT along x,y resp.
+  !
+  !
+  REAL, DIMENSION(:,:,:), ALLOCATABLE :: ZWORKX ! work array used by
+  ! the FFT. It has been enlarged in order to be sufficient for 2D and 3D cases
+  REAL, DIMENSION(:,:,:), ALLOCATABLE :: ZWORKY ! work array used by
+  ! the FFT. It has been enlarged in order to be sufficient for 2D and 3D cases
+  !
+  REAL, DIMENSION(:,:,:), ALLOCATABLE :: ZGAM
+  ! intermediate arrays
+  REAL, DIMENSION(:,:), ALLOCATABLE   :: ZBETX            ! for the tridiag.
+  ! matrix inversion
+  REAL, DIMENSION(:,:,:), ALLOCATABLE :: ZBAND_X  ! array in X slices distribution
+  REAL, DIMENSION(:,:,:), ALLOCATABLE :: ZBAND_Y  ! array in Y slices distribution
+  REAL, DIMENSION(:,:,:), ALLOCATABLE :: ZBAND_YR ! array in Y slices distribution
+  !
+  INTEGER :: IINFO_ll           ! return code of parallel routine
+  !
+  INTEGER :: IIX,IJX,IIY,IJY ! dimensions of the extended x or y slices subdomain
+  !
+  REAL, DIMENSION(:,:,:), ALLOCATABLE :: ZBAND_YT  ! array in Y slices distribution transpose
+  REAL, DIMENSION(:,:,:), ALLOCATABLE :: ZBAND_YRT ! array in Y slices distribution transpose
+  !
+  REAL, DIMENSION(:,:,:), ALLOCATABLE :: ZF_1_Y,ZCORREC,ZP
+  !
+  REAL, DIMENSION(:,:,:), ALLOCATABLE :: ZRESIDUE,ZDELTA,ZQ,ZKSI
+  !
+  REAL                                ::  ZDOT_DELTA,ZLAMBDA,ZALPHA 
+  !
+  REAL, DIMENSION(:,:,:), ALLOCATABLE :: ZY_RES_FLAT,ZF_1_Y_FLAT
+  !
+  REAL, DIMENSION(:,:,:), ALLOCATABLE :: ZY_K , ZF_1_Y_K , ZPF_1_Y_K , ZP_K, ZCORREC_K
+  !
+  REAL, DIMENSION(:,:,:), ALLOCATABLE ::  ZY_MG,ZPF_1_Y_MG
+  !
+  INTEGER  :: JM , KITR
+  !
+  LOGICAL  :: GRICHARDSON , GMG_K
+  !
+  LOGICAL,SAVE  :: GFIRST_CALL_ZSOL = .TRUE.
+  !
+  INTEGER :: IIU,IJU
+  REAL    :: ZMEAN
+  INTEGER  :: IT , NT 
+  REAL     :: ZOMEGA 
+  !
+  REAL , DIMENSION(5)     :: Alpha_T
+  !-------------------------------------------------------------------------------
+  !
+  !*       1.    COMPUTE LOOP BOUNDS
+  !              -------------------
+  !
+  !CALL GET_PHYSICAL_ll(IIB,IJB,IIE,IJE)
+  CALL GET_INDICE_ll(IIB,IJB,IIE,IJE)
+  CALL GET_DIM_EXT_ll('X',IIX,IJX)
+  CALL GET_DIM_EXT_ll('Y',IIY,IJY)
+  CALL GET_DIM_EXT_ll('B',IIU,IJU)
+  IIMAX = IIX-2*JPHEXT
+  IJMAX = IJY-2*JPHEXT
+  !
+  IKU=SIZE(PY,3)
+  IKB=1+JPVEXT
+  IKE=IKU - JPVEXT
+  IKMAX=IKE-IKB+1
+  !
+  !!
+  ALLOCATE(ZBAND_X(IIX,IJX,IKU))
+  ALLOCATE(ZBAND_Y(IIY,IJY,IKU))
+  ALLOCATE(ZBAND_YR(IIY,IJY,IKU))
+  ALLOCATE(ZWORKX(IIX,IJX,IKU))
+  ALLOCATE(ZWORKY(IIY,IJY,IKU))
+  ALLOCATE(ZBETX(IIU,IJU))
+  ALLOCATE(ZGAM(IIU,IJU,IKU))
+  IF (.NOT. L2D) THEN
+     ALLOCATE(ZBAND_YT(IJY,IIY,IKU))
+     ALLOCATE(ZBAND_YRT(IJY,IIY,IKU))
+  END IF
+  ALLOCATE(ZF_1_Y(IIU,IJU,IKU))
+  ALLOCATE(ZCORREC(IIU,IJU,IKU))
+  ALLOCATE(ZP(IIU,IJU,IKU))
+  ALLOCATE(ZRESIDUE(IIU,IJU,IKU))
+  ALLOCATE(ZDELTA(IIU,IJU,IKU))
+  ALLOCATE(ZQ(IIU,IJU,IKU))
+  ALLOCATE(ZKSI(IIU,IJU,IKU))
+  ALLOCATE(ZY_RES_FLAT(IIU,IJU,IKU))
+  ALLOCATE(ZF_1_Y_FLAT(IIU,IJU,IKU))
+  !
+  ALLOCATE(ZY_K(IIU,IJU,IKU))
+  ALLOCATE(ZF_1_Y_K(IIU,IJU,IKU))
+  ALLOCATE(ZPF_1_Y_K(IIU,IJU,IKU))
+  ALLOCATE(ZCORREC_K(IIU,IJU,IKU))
+  ALLOCATE(ZP_K(IIU,IJU,IKU))
+  ALLOCATE(ZY_MG(IIU,IJU,IKU))
+  ALLOCATE(ZPF_1_Y_MG(IIU,IJU,IKU))
+  !
+  ZDXM2 = PDXHATM*PDXHATM
+  ZDYM2 = PDYHATM*PDYHATM
+  !
+  !
+!!$  CALL FLAT_INV(HLBCX,HLBCY,PDXHATM,PDYHATM,PRHOM,PAF,PBF,PCF, &!  -1
+!!$                  PTRIGSX,PTRIGSY,KIFAXX,KIFAXY,PY,ZF_1_Y_FLAT)      ! F  (Y - Q (PHI)))
+!!$  CALL  PF(ZY_RES_FLAT,ZF_1_Y_FLAT)
+!!$  ZY_RES_FLAT = ZY_RES_FLAT - PY
+!!$
+!!$  ZPF_1_Y_K = 0.0
+!!$  ZF_1_Y_K = 0.0
+!!$  ZF_1_Y_K(IIB:IIE,IJB:IJE,:) =  ZF_1_Y_FLAT(IIB:IIE,IJB:IJE,:)
+!!$
+!!$
+!!$  CALL PF_K(ZY_K,ZF_1_Y_K)
+!!$  !ZY_K =  ZY_K / ZDXM2   
+!!$  ZY_K =  ZY_K - PY
+
+  !
+  !-------------------------------------------------------------------------------
+  !
+  !*      3.    FORM HOMOGENEOUS BOUNDARY CONDITIONS FOR A NONCYCLIC CASE
+  !             ---------------------------------------------------------
+  !
+  !
+  !*      3.1 copy the RHS in a local array REMAP functions will shift the indices for the FFT
+  !
+  !PF_1_Y = 0.
+  ZY = PY
+  !
+  !*      3.2 form homogeneous boundary condition used by the FFT for non-periodic
+  !           cases
+  !
+  !  modify the RHS in the x direction
+  !
+  IF (HLBCX(1) /= 'CYCL') THEN
+     !
+     IF (LWEST_ll(HSPLITTING='B')) THEN
+        DO JK=IKB,IKE                    
+           DO JJ = IJB, IJE
+              ZY(IIB,JJ,JK)     = ZY(IIB,JJ,JK)     + PY(IIB-1,JJ,JK)
+              !ZY(IIB,JJ,JK)    = 2.0 * ZY(IIB+2,JJ,JK) - ZY(IIB+1,JJ,JK)    
+           END DO
+        END DO
+     END IF
+     !
+     IF (LEAST_ll(HSPLITTING='B')) THEN
+        DO JK=IKB,IKE
+           DO JJ = IJB, IJE
+              ZY(IIE,JJ,JK)     = ZY(IIE,JJ,JK)     - PY(IIE+1,JJ,JK)
+              !ZY(IIE,JJ,JK)  = 2.0 * ZY(IIE-2,JJ,JK) - ZY(IIE-1,JJ,JK)
+           END DO
+        END DO
+     END IF
+  END IF
+  !
+  ! modify the RHS in the same way along y
+  !
+  IF (HLBCY(1) /= 'CYCL'.AND. (.NOT. L2D)) THEN
+     IF (LSOUTH_ll(HSPLITTING='B')) THEN
+        DO JK=IKB,IKE
+           DO JI = IIB, IIE
+              ZY(JI,IJB,JK)     = ZY(JI,IJB,JK)     + PY(JI,IJB-1,JK)
+              !ZY(JI,IJB,JK)   = 2.0 * ZY(JI,IJB+2,JK)  -  ZY(JI,IJB+1,JK)
+           END DO
+        END DO
+     END IF
+     !
+     IF (LNORTH_ll(HSPLITTING='B')) THEN
+        DO JK=IKB,IKE
+           DO JI = IIB, IIE
+              ZY(JI,IJE,JK)     = ZY(JI,IJE,JK)     - PY(JI,IJE+1,JK)
+              !ZY(JI,IJE,JK)     = 2.0 * ZY(JI,IJE-2,JK) - ZY(JI,IJE-1,JK)
+           END DO
+        END DO
+     END IF
+  END IF
+  !
+  !-------------------------------------------------------------------------------
+  !
+  !*      5.    MATRIX INVERSION FOR THE FLAT OPERATOR
+  !             --------------------------------------
+  !
+  IF (L2D) THEN
+     CALL FAST_SUBSTITUTION_2D(ZBAND_YR,ZBETX,PBFB,ZGAM,PCF,ZAF &
+          ,ZBAND_Y,IIY,IJY,IKU)
+  ELSE
+
+  call mg_main_initialise_rhs_mnh(IIB,IIE,IIU,IJB,IJE,IJU,IKU,ZY)
+  ZPF_1_Y_MG = 0.
+  call mg_main_initialise_u_mnh(IIB,IIE,IIU,IJB,IJE,IJU,IKU,ZPF_1_Y_MG)
+
+  !print*,'************************ mg_main_mnh_solve ***************************'
+       
+  call mg_main_mnh_solve()  
+  call mg_main_get_u_mnh(IIB,IIE,IIU,IJB,IJE,IJU,IKU,ZPF_1_Y_MG)
+
+  PF_1_Y = ZPF_1_Y_MG
+  !goto 10000
+
+!!$  CALL PF_K(ZY_MG,ZPF_1_Y_MG)
+!!$  !ZY_MG =  ZY_MG / ZDXM2   
+!!$  ZY_MG =  ZY_MG - PY
+  goto 10000
+
+GMG_K = .TRUE. ! .FALSE. ! .TRUE.
+
+ IF (GMG_K) THEN
+    ZY_K = ZY
+    CALL TRIDIAG_SOLVE_K(ZY_K,ZF_1_Y_K)
+    CALL GET_HALO(ZF_1_Y_K)
+ ELSE
+     CALL FAST_SUBSTITUTION_3D(ZF_1_Y,ZBETX,PBFB,ZGAM,PCF,PAF &
+          ,ZY,IIU,IJU,IKU)
+     CALL PF_1_Y_BOUND(ZF_1_Y)
+
+     CALL GET_HALO(ZF_1_Y)
+  END IF
+
+ IF (GFIRST_CALL_ZSOL) THEN
+    !GFIRST_CALL_ZSOL = .FALSE.
+    IF (GMG_K) THEN
+       ZPF_1_Y_K = ZF_1_Y_K
+    ELSE
+       PF_1_Y = ZF_1_Y   ! when no first guess is available, we take the solution
+    END IF
+    ! for the flat problem 
+ END IF
+!
+!
+GRICHARDSON =  .FALSE. ! .FALSE. ! .TRUE.
+                        ! FLAT_INV ::  4IT 3D_128X128 /  5IT REU 128x128
+ KITR = 11              ! CONRES   :: 16IT 3D 128X128 /  7IT REU 128x128
+ NT = 11 ; ZOMEGA = 1.0 ! RICH     :: 36IT 3D 128X128 / 26IT REU 128x128
+IF ( GRICHARDSON ) THEN
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!! RICHARDSON 
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+ !NT = 1000 ; ZOMEGA = 1.0 
+ !NT = 11 ; ZOMEGA = 1.0 ! 12IT
+ !NT = 101 ; ZOMEGA = 1.0 ! 6IT 
+ NT = 401 ; ZOMEGA = 1.0 ! 1.0 ! 5IT
+
+IF (GMG_K) THEN
+
+DO IT = 1,NT        
+!
+  CALL PF_K(ZP_K,ZPF_1_Y_K)          !         Q (PF_1_Y)   
+!
+  ZCORREC_K = 0.
+!
+  CALL TRIDIAG_SOLVE_K(ZP_K,ZCORREC_K)   ! zcorrec = F-1 * Q (PF_1_Y) 
+!                                                       -1       -1
+!    update the iterative solution PHI = PHI + relax* (F  (Y) - F  * Q (PHI))
+!
+  ZP_K = ZF_1_Y_K - ZCORREC_K ! for totalview
+  ZPF_1_Y_K = ZPF_1_Y_K + ZOMEGA * (ZF_1_Y_K - ZCORREC_K) 
+  CALL GET_HALO(ZPF_1_Y_K)
+!        
+END DO
+
+PF_1_Y = ZPF_1_Y_K
+
+ELSE
+
+DO IT = 1,NT        
+!
+  CALL PF(ZP,PF_1_Y)          !         Q (PF_1_Y)   
+!
+  ZCORREC = 0.
+!
+  CALL FAST_SUBSTITUTION_3D(ZCORREC,ZBETX,PBFB,ZGAM,PCF,PAF &
+          ,ZP,IIU,IJU,IKU)   ! zcorrec = F-1 * Q (PF_1_Y)
+  CALL PF_1_Y_BOUND(ZCORREC)  
+!                                                       -1       -1
+!    update the iterative solution PHI = PHI + relax* (F  (Y) - F  * Q (PHI))
+!
+  ZP = ZF_1_Y - ZCORREC ! for totalview
+  PF_1_Y = PF_1_Y + ZOMEGA * (ZF_1_Y - ZCORREC) 
+  CALL PF_1_Y_BOUND(PF_1_Y)
+  CALL GET_HALO(PF_1_Y)
+!        
+END DO
+
+ENDIF
+
+ELSE
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!! CONJUGE RESIDUAL 
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+!!$KITR = 101
+ZRESIDUE = 0.0
+ZP=0.0
+ZDELTA=0.0
+ZQ=0.0
+ZKSI=0.0
+
+IF (GMG_K) THEN
+!-------------------------------------------------------------------------------
+!
+!*       1.    INITIALIZATIONS
+!              ---------------
+!
+!                             
+!*       1.1    compute the vector: r^(0) =  Q(PHI) - Y
+!    
+CALL PF_K(ZRESIDUE,ZPF_1_Y_K)
+ZRESIDUE = ZRESIDUE - ZY_K 
+!
+!*       1.2    compute the vector: p^(0) = F^(-1)*( Q(PHI) - Y )
+!    
+CALL TRIDIAG_SOLVE_K(ZRESIDUE,ZP)
+CALL GET_HALO(ZP)
+!
+!*       1.3    compute the vector: delta^(0) = Q ( p^(0) )
+!
+CALL PF_K(ZDELTA,ZP) 
+!
+!-------------------------------------------------------------------------------
+!
+!*       2.    ITERATIVE LOOP
+!              --------------
+!
+DO JM = 1,KITR                                                        
+   !
+   !*       2.1    compute the step LAMBDA
+   !
+   ZDOT_DELTA = DOTPROD(ZDELTA,  ZDELTA,HLBCX,HLBCY)            ! norm of DELTA
+   ZLAMBDA  = - DOTPROD(ZRESIDUE,ZDELTA,HLBCX,HLBCY) / ZDOT_DELTA
+   !
+   !*       2.2    update the pressure function PHI
+   !
+   ZPF_1_Y_K = ZPF_1_Y_K + ZLAMBDA * ZP
+   CALL GET_HALO(ZPF_1_Y_K)
+   !
+   !
+   IF( JM == KITR ) EXIT
+   !
+   !
+   !*       2.3    update the residual error: r
+   !
+   ZRESIDUE = ZRESIDUE + ZLAMBDA * ZDELTA
+   !                        
+   !*       2.4    compute the vector: q = F^(-1)*( Q(PHI) - Y )
+   !    
+   CALL TRIDIAG_SOLVE_K(ZRESIDUE,ZQ)
+   CALL GET_HALO(ZQ)
+   !   
+   !*       2.5     compute the auxiliary field: ksi = Q ( q )
+   !
+   CALL PF_K(ZKSI,ZQ) 
+   !                                         -1
+   !*       2.6     compute the step ALPHA
+   !  
+   ZALPHA = - DOTPROD(ZKSI,ZDELTA,HLBCX,HLBCY) / ZDOT_DELTA   ! lambda
+   !
+   !*       2.7     update p and DELTA
+   !
+   ZP     = ZQ   + ZALPHA * ZP
+   ZDELTA = ZKSI + ZALPHA * ZDELTA
+   !
+END DO              ! end of the loop for the iterative solver
+
+PF_1_Y = ZPF_1_Y_K
+
+ELSE
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!! CONJUGE RESIDUAL 
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!-------------------------------------------------------------------------------
+!
+!*       1.    INITIALIZATIONS
+!              ---------------
+!
+!                             
+!*       1.1    compute the vector: r^(0) =  Q(PHI) - Y
+!    
+CALL PF(ZRESIDUE,PF_1_Y)
+ZRESIDUE = ZRESIDUE - PY 
+!
+!*       1.2    compute the vector: p^(0) = F^(-1)*( Q(PHI) - Y )
+!    
+CALL FAST_SUBSTITUTION_3D(ZP,ZBETX,PBFB,ZGAM,PCF,PAF &
+     ,ZRESIDUE,IIU,IJU,IKU)
+CALL PF_1_Y_BOUND(ZP)
+CALL GET_HALO(ZP)
+!
+!*       1.3    compute the vector: delta^(0) = Q ( p^(0) )
+!
+CALL PF(ZDELTA,ZP) 
+!
+!-------------------------------------------------------------------------------
+!
+!*       2.    ITERATIVE LOOP
+!              --------------
+!
+DO JM = 1,KITR                                                        
+   !
+   !*       2.1    compute the step LAMBDA
+   !
+   ZDOT_DELTA = DOTPROD(ZDELTA,  ZDELTA,HLBCX,HLBCY)            ! norm of DELTA
+   ZLAMBDA  = - DOTPROD(ZRESIDUE,ZDELTA,HLBCX,HLBCY) / ZDOT_DELTA
+   !
+   !*       2.2    update the pressure function PHI
+   !
+   PF_1_Y = PF_1_Y + ZLAMBDA * ZP
+   CALL PF_1_Y_BOUND(PF_1_Y)
+   CALL GET_HALO(PF_1_Y)
+   !
+   !
+   IF( JM == KITR ) EXIT
+   !
+   !
+   !*       2.3    update the residual error: r
+   !
+   ZRESIDUE = ZRESIDUE + ZLAMBDA * ZDELTA
+   !                        
+   !*       2.4    compute the vector: q = F^(-1)*( Q(PHI) - Y )
+   !    
+   !CALL FLAT_INVZ(HLBCX,HLBCY,PDXHATM,PDYHATM,PRHOM,PAF,PBF,PCF,  &
+   !                 PTRIGSX,PTRIGSY,KIFAXX,KIFAXY,ZRESIDUE,ZQ,    &
+   !                 PBFB,&
+   !                 PBF_SXP2_YP1_Z) !JUAN Z_SPLITTING
+   CALL FAST_SUBSTITUTION_3D(ZQ,ZBETX,PBFB,ZGAM,PCF,PAF &
+        ,ZRESIDUE,IIU,IJU,IKU)
+   CALL PF_1_Y_BOUND(ZQ)
+   CALL GET_HALO(ZQ)
+   !   
+   !*       2.5     compute the auxiliary field: ksi = Q ( q )
+   !
+   ! ZKSI= QLAP(HLBCX,HLBCY,PDXX,PDYY,PDZX,PDZY,PDZZ,PRHODJ,PTHETAV,ZQ)
+   CALL PF(ZKSI,ZQ) 
+   !                                         -1
+   !*       2.6     compute the step ALPHA
+   !  
+   ZALPHA = - DOTPROD(ZKSI,ZDELTA,HLBCX,HLBCY) / ZDOT_DELTA   ! lambda
+   !
+   !*       2.7     update p and DELTA
+   !
+   ZP     = ZQ   + ZALPHA * ZP
+   ZDELTA = ZKSI + ZALPHA * ZDELTA
+   !
+END DO              ! end of the loop for the iterative solver
+
+ENDIF ! CRESI
+
+ENDIF ! GMG_K
+
+!!$ZMEAN = SUM ( PF_1_Y(IIB:IIE,IJB:IJE,IKU) ) / FLOAT( (IIE-IIB+1)*(IJE-IJB+1) )
+!!$PF_1_Y(IIB:IIE,IJB:IJE,:) = PF_1_Y(IIB:IIE,IJB:IJE,:) - ZMEAN
+!CALL PF_1_Y_BOUND(PF_1_Y)
+!CALL GET_HALO(PF_1_Y)
+
+
+
+  END IF
+  !  
+
+10000 CONTINUE
+  CALL PF_1_Y_BOUND(PF_1_Y)
+  !
+  DEALLOCATE(ZBAND_X)
+  DEALLOCATE(ZBAND_Y)
+  IF (.NOT. L2D) THEN
+     DEALLOCATE(ZBAND_YT)
+     DEALLOCATE(ZBAND_YRT)
+  END IF
+  DEALLOCATE(ZBAND_YR)
+  DEALLOCATE(ZWORKX)
+  DEALLOCATE(ZWORKY)
+  DEALLOCATE(ZBETX)
+  DEALLOCATE(ZGAM)
+  !
+  !PF_1_Y = ZF_1_Y 
+  !
+!!$  CALL PF(ZRESIDUE,PF_1_Y) ! for totalview
+!!$  ZRESIDUE = ZRESIDUE - ZY
+  !
+  CALL GET_HALO(PF_1_Y)
+  !-------------------------------------------------------------------------------
+  !
+CONTAINS
+
+  SUBROUTINE CONSTRUCT_ALPHA(JI,JJ)
+    IMPLICIT NONE
+    INTEGER, INTENT(IN) :: JI,JJ
+
+         IF ( (HLBCX(1) /= 'CYCL') .AND. ( JI == IIE ) .AND. LEAST_ll(HSPLITTING='B' ) )  THEN
+            Alpha_T(1) = 0.0 ! 2.0
+         ELSE
+            Alpha_T(1) = 1.0
+         END IF
+         IF ( (HLBCX(1) /= 'CYCL') .AND. ( JI == IIB ) .AND. LWEST_ll(HSPLITTING='B' ) )  THEN
+            Alpha_T(2) = 0.0 ! 2.0
+         ELSE
+            Alpha_T(2) = 1.0
+         END IF
+         IF ( (HLBCY(1) /= 'CYCL') .AND. ( JJ == IJE ) .AND. LNORTH_ll(HSPLITTING='B' ) )  THEN
+            Alpha_T(3) = 0.0 ! 2.0
+         ELSE
+            Alpha_T(3) = 1.0
+         END IF
+         IF ( (HLBCY(1) /= 'CYCL') .AND. ( JJ == IJB ) .AND. LSOUTH_ll(HSPLITTING='B' ) )  THEN
+            Alpha_T(4) = 0.0 ! 2.0
+         ELSE
+            Alpha_T(4) = 1.0
+         END IF
+
+         Alpha_T(5) =  Alpha_T(1) +  Alpha_T(2) +  Alpha_T(3) +  Alpha_T(4)
+
+  END SUBROUTINE CONSTRUCT_ALPHA
+
+SUBROUTINE  PF_K(PY,PF_1_Y)
+IMPLICIT NONE
+
+REAL , DIMENSION(:,:,:) , INTENT(INOUT) :: PY
+REAL , DIMENSION(:,:,:) , INTENT(IN)    :: PF_1_Y
+
+REAL                    :: Tij
+
+Tij = ZDXM2
+
+PY = 0.0 
+
+   DO JJ=IJB,IJE
+      DO JI=IIB,IIE
+         CALL CONSTRUCT_ALPHA(JI,JJ)
+         DO JK=IKB-1,IKE+1
+            PY(JI,JJ,JK)  =                   ( (A_K(JK) -B_K(JK) -C_K(JK) )*Tij             ) * PF_1_Y(JI,JJ,JK)   
+            IF ( (JK >= IKB) .AND. (JK <= IKE) ) THEN
+            PY(JI,JJ,JK)  =  PY(JI,JJ,JK)  -                                      Alpha_T(5)   * PF_1_Y(JI,JJ,JK)   &
+                                           +                                      Alpha_T(1)   * PF_1_Y(JI+1,JJ,JK) &
+                                           +                                      Alpha_T(2)   * PF_1_Y(JI-1,JJ,JK) &
+                                           +                                      Alpha_T(3)   * PF_1_Y(JI,JJ+1,JK) &
+                                           +                                      Alpha_T(4)   * PF_1_Y(JI,JJ-1,JK)   
+            END IF
+            IF (JK >= IKB ) THEN
+            PY(JI,JJ,JK)  =  PY(JI,JJ,JK)  +                       C_K(JK)  *Tij               * PF_1_Y(JI,JJ,JK-1) 
+            END IF
+
+            IF (JK <= IKE ) THEN
+            PY(JI,JJ,JK)  =  PY(JI,JJ,JK)  +              B_K(JK)           *Tij               * PF_1_Y(JI,JJ,JK+1) 
+            ENDIF
+
+            PY(JI,JJ,JK)  = D_K(JK) * PY(JI,JJ,JK) /  ZDXM2  !  /ZDXM2 <=> Temporaire pour comparer avec MNH FAST_SUB
+            
+         END DO
+
+      END DO
+   END DO
+
+!  
+CALL GET_HALO(PY)
+!
+END SUBROUTINE PF_K
+
+SUBROUTINE  TRIDIAG_SOLVE_K(PY,PF_1_Y)
+IMPLICIT NONE
+
+REAL , DIMENSION(:,:,:) ,INTENT(IN)    :: PY
+REAL , DIMENSION(:,:,:) ,INTENT(INOUT) :: PF_1_Y
+
+! local var
+
+REAL, DIMENSION(SIZE(PY,3)) :: C, u_out
+REAL                        :: Tij , tmp , alpha_div_Tij , b_k_tmp , c_k_tmp , xctop_boot
+
+INTEGER :: JI,JJ,JK,iz
+
+Tij = ZDXM2
+xctop_boot = 0.0
+
+PF_1_Y = 0.0 
+
+   DO JJ=IJB,IJE
+      DO JI=IIB,IIE
+         CALL CONSTRUCT_ALPHA(JI,JJ)
+         alpha_T(5) = 4.0 ! temporaire to compare to MNH FLATINV
+         ! Calculate r_i = b_i - A_{ij} u_i
+         ! do iz= IKB,IKE ! 1,nz
+         !   r(iz) = b%s(iz,iy,ix) - vert_coeff%d(iz) * ( &
+         !        alpha_T(1) * u_in_1(iz) + &
+         !        alpha_T(2) * u_in_2(iz) + &
+         !        alpha_T(3) * u_in_3(iz) + &
+         !        alpha_T(4) * u_in_4(iz) )
+         ! end do
+         !
+         ! Thomas algorithm
+         ! STEP 1: Create modified coefficients
+         iz = IKB-1 ! 1
+         alpha_div_Tij = alpha_T(5)/Tij
+         tmp = (A_K(iz)-B_K(iz)-C_K(iz)) &
+               - xctop_boot*alpha_div_Tij
+         c(iz) = B_K(iz)/tmp
+         u_out(iz) = PY(JI,JJ,iz) / (tmp*Tij*D_K(iz))
+
+         do iz=IKB,IKE! 2,nz
+            b_k_tmp = B_K(iz)
+            c_k_tmp = C_K(iz)
+            tmp = ((A_K(iz)-b_k_tmp-c_k_tmp)-alpha_div_Tij) &
+                 - c(iz-1)*c_k_tmp
+            c(iz) = b_k_tmp / tmp
+            u_out(iz) = (PY(JI,JJ,iz) / (Tij*D_K(iz)) - u_out(iz-1)*c_k_tmp) / tmp
+         end do
+
+         iz=IKE+1
+         b_k_tmp = B_K(iz)
+         c_k_tmp = C_K(iz)
+         tmp = ((A_K(iz)-b_k_tmp-c_k_tmp) - xctop_boot*alpha_div_Tij) &
+              - c(iz-1)*c_k_tmp
+         c(iz) = b_k_tmp / tmp
+         u_out(iz) = (PY(JI,JJ,iz) / (Tij*D_K(iz)) - u_out(iz-1)*c_k_tmp) / tmp
+
+         ! STEP 2: back substitution
+         do iz=IKE,IKB-1,-1 ! nz-1,1,-1
+            u_out(iz) = u_out(iz) - c(iz) * u_out(iz+1)
+         end do
+
+       PF_1_Y(JI,JJ,:) = u_out(:)  * ZDXM2  ! * ZDXM2 <=> Temporaire pour comparer avec MNH FAST_SUB
+
+      END DO
+   END DO
+
+!  
+CALL GET_HALO(PF_1_Y)
+!
+END SUBROUTINE TRIDIAG_SOLVE_K
+
+SUBROUTINE  PF(PY,PF_1_Y)
+IMPLICIT NONE
+
+REAL , DIMENSION(:,:,:) :: PY,PF_1_Y
+
+PY = 0.0 
+DO JK=IKB,IKE
+   DO JJ=IJB,IJE
+      DO JI=IIB,IIE
+         PY(JI,JJ,JK)  =   &
+                PBFB(JI,JJ,JK)                               * PF_1_Y(JI,JJ,JK)    &
+              + PAF(JK)                                      * PF_1_Y(JI,JJ,JK-1)  &
+              + PCF(JK)                                      * PF_1_Y(JI,JJ,JK+1)  &
+              + PRHOM(JK) / ZDXM2                            * PF_1_Y(JI+1,JJ,JK)  &
+              + PRHOM(JK) / ZDXM2                            * PF_1_Y(JI-1,JJ,JK)  &
+              + PRHOM(JK) / ZDYM2                            * PF_1_Y(JI,JJ+1,JK)  & 
+              + PRHOM(JK) / ZDYM2                            * PF_1_Y(JI,JJ-1,JK)  
+      END DO
+   END DO
+END DO
+PY(IIB:IIE,IJB:IJE,IKB-1)  =  PBFB(IIB:IIE,IJB:IJE,IKB-1) * PF_1_Y(IIB:IIE,IJB:IJE,IKB-1)   &
+                           +  PCF(IKB-1)                  * PF_1_Y(IIB:IIE,IJB:IJE,IKB)     
+PY(IIB:IIE,IJB:IJE,IKE+1)  =  PAF(IKE+1)                  * PF_1_Y(IIB:IIE,IJB:IJE,IKE)     &
+                           +  PBFB(IIB:IIE,IJB:IJE,IKE+1) * PF_1_Y(IIB:IIE,IJB:IJE,IKE+1)  
+!  
+CALL GET_HALO(PY)
+!
+END SUBROUTINE PF
+
+
+SUBROUTINE PF_1_Y_BOUND(PF_1_Y)
+
+IMPLICIT NONE
+
+REAL , DIMENSION (:,:,:) :: PF_1_Y
+
+  !-------------------------------------------------------------------------------
+  !
+  !*      7.    RETURN TO A NON HOMOGENEOUS NEUMAN CONDITION FOR NON-CYCLIC CASES
+  !             -----------------------------------------------------------------
+  !
+  !*      7.2 complete the lateral boundaries
+  !
+  IF (HLBCX(1) /= 'CYCL') THEN
+     !
+     !*      7.2.1 return to a non-homogeneous case in the x direction
+     ! 
+     ZDXM2 = PDXHATM*PDXHATM
+     !
+     IF (LWEST_ll(HSPLITTING='B')) THEN
+        DO JK=IKB,IKE
+           DO JJ = IJB,IJE
+              PF_1_Y(IIB-1,JJ,JK) = PF_1_Y(IIB,JJ,JK) - PY(IIB-1,JJ,JK)*ZDXM2/PRHOM(JK)
+           END DO
+        END DO
+     END IF
+     !
+     IF (LEAST_ll(HSPLITTING='B')) THEN
+        DO JK=IKB,IKE
+           DO JJ = IJB,IJE
+              PF_1_Y(IIE+1,JJ,JK) = PF_1_Y(IIE,JJ,JK) + PY(IIE+1,JJ,JK)*ZDXM2/PRHOM(JK)
+           END DO
+        END DO
+     END IF
+     !
+     !    we set the solution at the corner point by the condition:
+     !    dxm ( P ) = 0
+     IF (LWEST_ll(HSPLITTING='B')) THEN
+        DO JJ = IJB,IJE
+           PF_1_Y(IIB-1,JJ,IKB-1) = PF_1_Y(IIB,JJ,IKB-1) 
+           PF_1_Y(IIB-1,JJ,IKE+1) = PF_1_Y(IIB,JJ,IKE+1)
+        END DO
+     END IF
+     IF (LEAST_ll(HSPLITTING='B')) THEN
+        DO JJ = IJB,IJE
+           PF_1_Y(IIE+1,JJ,IKB-1) = PF_1_Y(IIE,JJ,IKB-1)
+           PF_1_Y(IIE+1,JJ,IKE+1) = PF_1_Y(IIE,JJ,IKE+1)
+        END DO
+     END IF
+     !
+  ELSE
+     !
+     !*      7.2.2 periodize the pressure function field along the x direction
+     !
+     ! in fact this part is useless because it is done in the routine
+     ! REMAP_X_2WAY.
+     !
+  END IF
+!!$!
+  IF (.NOT.L2D) THEN
+     IF (HLBCY(1) /= 'CYCL') THEN
+        !
+        !*      7.2.3 return to a non-homogeneous case in the y direction
+        !
+        ZDYM2 = PDYHATM*PDYHATM 
+        !
+        IF (LSOUTH_ll(HSPLITTING='B')) THEN
+           DO JK=IKB,IKE
+              DO JI = IIB,IIE
+                 PF_1_Y(JI,IJB-1,JK) = PF_1_Y(JI,IJB,JK) - PY(JI,IJB-1,JK)*ZDYM2/PRHOM(JK)
+              END DO
+           END DO
+        END IF
+        !
+        IF (LNORTH_ll(HSPLITTING='B')) THEN
+           DO JK=IKB,IKE
+              DO JI = IIB,IIE
+                 PF_1_Y(JI,IJE+1,JK) = PF_1_Y(JI,IJE,JK) + PY(JI,IJE+1,JK)*ZDYM2/PRHOM(JK)
+              END DO
+           END DO
+        END IF
+        !    we set the solution at the corner point by the condition:
+        !    dym ( P )  = 0
+        !
+        IF (LSOUTH_ll(HSPLITTING='B')) THEN
+           DO JI = IIB,IIE
+              PF_1_Y(JI,IJB-1,IKB-1) = PF_1_Y(JI,IJB,IKB-1)
+              PF_1_Y(JI,IJB-1,IKE+1) = PF_1_Y(JI,IJB,IKE+1)
+           END DO
+        END IF
+        !
+        IF (LNORTH_ll(HSPLITTING='B')) THEN
+           DO JI = IIB,IIE
+              PF_1_Y(JI,IJE+1,IKB-1) = PF_1_Y(JI,IJE,IKB-1)
+              PF_1_Y(JI,IJE+1,IKE+1) = PF_1_Y(JI,IJE,IKE+1)
+           END DO
+        END IF
+     ELSE
+        !
+        !*      7.2.4 periodize the pressure function field along the y direction
+        !
+        !
+        ! in fact this part is useless because it is done in the routine
+        ! REMAP_X_2WAY.
+        !
+     END IF
+     !
+  END IF
+  !
+  IF (.NOT. L2D .AND. HLBCX(1)/='CYCL' .AND. HLBCY(1)/='CYCL') THEN
+     ! the following verticals are not used
+     IF ( (LWEST_ll(HSPLITTING='B')).AND.(LSOUTH_ll(HSPLITTING='B')) ) THEN
+        PF_1_Y(IIB-1,IJB-1,:)= PF_1_Y(IIB,IJB,:) ! 0.0
+     END IF
+     !
+     IF ( (LWEST_ll(HSPLITTING='B')).AND.(LNORTH_ll(HSPLITTING='B')) ) THEN
+        PF_1_Y(IIB-1,IJE+1,:)= PF_1_Y(IIB,IJE,:) ! 0.0
+     END IF
+     !
+     IF ( (LEAST_ll(HSPLITTING='B')).AND.(LSOUTH_ll(HSPLITTING='B')) ) THEN
+        PF_1_Y(IIE+1,IJB-1,:)= PF_1_Y(IIE,IJB,:) ! 0.0
+     END IF
+     !
+     IF ( (LEAST_ll(HSPLITTING='B')).AND.(LNORTH_ll(HSPLITTING='B')) ) THEN
+        PF_1_Y(IIE+1,IJE+1,:)= PF_1_Y(IIE,IJE,:) ! 0.0
+     END IF
+  END IF
+END SUBROUTINE PF_1_Y_BOUND
+
+  SUBROUTINE FAST_SUBSTITUTION_3D_ZS(PBAND_YR,PBETX,PPBF,PGAM,PPCF,PAF &
+       ,PBAND_Y,KIY,KJY,KKU)
+    INTEGER                        :: KIY,KJY,KKU
+    REAL, DIMENSION (KIY*KJY,KKU)  :: PBAND_YR,PBAND_Y,PPBF,PGAM
+    REAL, DIMENSION (KIY*KJY)      :: PBETX
+    REAL, DIMENSION (KIY*KJY,KKU)  :: PPCF,PAF
+    INTEGER                        :: JK
+    !
+    !
+    !       initialization 
+    !
+    !
+    PBAND_YR = 0.0
+    PBETX(:) =            PPBF(:,IKB-1)
+    PBAND_YR(:,IKB-1) = PBAND_Y(:,IKB-1)  &
+         / PBETX(:)
+    !
+    !        decomposition and forward substitution
+    !
+    DO JK = IKB,IKE+1
+       !
+       PGAM(:,JK) = PPCF(:,JK-1) / PBETX(:)
+       !
+       PBETX(:) =         PPBF(:,JK)        -   PAF(:,JK)*PGAM(:,JK)
+       !
+       PBAND_YR(:,JK) = ( PBAND_Y(:,JK) - PAF(:,JK)*PBAND_YR(:,JK- 1) ) /PBETX(:)
+       !
+    END DO
+    !
+    !       backsubstitution
+    !
+    DO JK = IKE,IKB-1,-1
+       PBAND_YR(:,JK) = PBAND_YR(:,JK) -    &
+            PGAM(:,JK+1)*PBAND_YR(:,JK+1)
+    END DO
+    !  
+    !
+  END SUBROUTINE FAST_SUBSTITUTION_3D_ZS
+
+  SUBROUTINE FAST_SUBSTITUTION_3D(PBAND_YR,PBETX,PPBF,PGAM,PPCF,PAF &
+       ,PBAND_Y,KIY,KJY,KKU)
+    INTEGER                        :: KIY,KJY,KKU
+    REAL, DIMENSION (KIY*KJY,KKU)  :: PBAND_YR,PBAND_Y,PPBF,PGAM
+    REAL, DIMENSION (KIY*KJY)      :: PBETX
+    REAL, DIMENSION (KKU)          :: PPCF,PAF
+    INTEGER                        :: JK
+    !
+    !
+    !       initialization 
+    !
+    !
+    PBAND_YR = 0.0
+    PBETX(:) =            PPBF(:,IKB-1)
+    PBAND_YR(:,IKB-1) = PBAND_Y(:,IKB-1)  &
+         / PBETX(:)
+    !
+    !        decomposition and forward substitution
+    !
+    DO JK = IKB,IKE+1
+       !
+       PGAM(:,JK) = PPCF(JK-1) / PBETX(:)
+       !
+       PBETX(:) =         PPBF(:,JK)        -   PAF(JK)*PGAM(:,JK)
+       !
+       PBAND_YR(:,JK) = ( PBAND_Y(:,JK) - PAF(JK)*PBAND_YR(:,JK- 1) ) /PBETX(:)
+       !
+    END DO
+    !
+    !       backsubstitution
+    !
+    DO JK = IKE,IKB-1,-1
+       PBAND_YR(:,JK) = PBAND_YR(:,JK) -    &
+            PGAM(:,JK+1)*PBAND_YR(:,JK+1)
+    END DO
+    !  
+    !
+  END SUBROUTINE FAST_SUBSTITUTION_3D
+  !
+  SUBROUTINE FAST_SUBSTITUTION_2D(PBAND_YR,PBETX,PPBF,PGAM,PPCF,PAF &
+       ,PBAND_Y,KIY,KJY,KKU)
+    INTEGER                        :: KIY,KJY,KKU
+    REAL, DIMENSION (KIY,KJY,KKU)  :: PBAND_YR,PBAND_Y,PPBF,PGAM,PAF
+    REAL, DIMENSION (KIY,KJY)      :: PBETX
+    REAL, DIMENSION (KKU)          :: PPCF
+    INTEGER                        :: JK
+    !
+    !
+    !       initialization 
+    !
+    !
+    PBAND_YR = 0.0
+    PBETX(:,1) = PPBF(:,1,IKB-1)
+    PBAND_YR(:,1,IKB-1) = PBAND_Y(:,1,IKB-1)  &
+         / PBETX(:,1)
+    !
+    !        decomposition and forward substitution
+    !
+    DO JK = IKB,IKE+1
+       PGAM(:,1,JK) = PPCF(JK-1) / PBETX(:,1)
+       !
+       PBETX(:,1) = PPBF(:,1,JK) -              &      
+            PAF(:,1,JK)*PGAM(:,1,JK)
+       !
+       PBAND_YR(:,1,JK) = ( PBAND_Y(:,1,JK) -  &
+            PAF(:,1,JK)*PBAND_YR(:,1,JK- 1) )  &
+            /PBETX(:,1)
+       !
+    END DO
+    !
+    !       backsubstitution
+    !
+    DO JK = IKE,IKB-1,-1
+       PBAND_YR(:,1,JK) = PBAND_YR(:,1,JK) -    &
+            PGAM(:,1,JK+1)*PBAND_YR(:,1,JK+1)
+    END DO
+    !  
+    !
+  END SUBROUTINE FAST_SUBSTITUTION_2D
+
+  !------------------------------------------------------------------------------  
+END SUBROUTINE ZSOLVER_INV