

module pyOM_module   
!=======================================================================
!      Main module for pyOM
!=======================================================================
      implicit none
      real*8, parameter :: version = 1.1
!---------------------------------------------------------------------------------
!      variable model parameter
!---------------------------------------------------------------------------------
      integer  :: nx=0,nz=0,ny=0         ! Number of grid points in x,y,z direction
      real*8 :: dx=0,dz=0,dt=0           ! Delta z, Delta x in m and Delta t in s
      real*8 :: K_h=0, K_v=0             ! horizontal and vertical diffusivitis in m^2/s
      real*8 :: A_h=0, A_v=0             ! horizontal and vertical viscosities in m^2/s
      real*8 :: cdbot=0                  ! Bottom friction in 1/s
      real*8 :: cdint=0                  ! interior friction in 1/s
      real*8 :: Khbi = .0, Kvbi =.0      ! hor/vert biharmonic diffusivities in m^4/s
      real*8 :: Ahbi = .0, Avbi=.0       ! same for biharmonic viscosities
      real*8 :: eps2d_sor=0              ! cut off values for 2-D Poisson solver
      real*8 :: eps3d_sor=0.             ! cut off values for 3-D Poisson solver
      real*8 :: gamma=0.01               ! value for Roberts time filter
      real*8 :: dtex                     ! time step for external mode 
!---------------------------------------------------------------------------------
!      domain decomposition for parallel execution
!---------------------------------------------------------------------------------
      integer :: n_pes_j = 1    ! number of PEs in meridional (y) direction
      integer :: my_blk_j= 1    ! number of domain in meridional (y) direction
      integer :: js_pe   = 1    ! start j-index of domain of this PE
      integer :: je_pe   = 1    ! end of j_index of domain of this PE
      integer :: j_blk   = 1    ! number of j-rows at this PE
      integer :: my_pe          ! ordinal number of PE
      integer :: n_pes          ! total number of PEs
      integer :: my_comm=0      ! MPI communication for PEs
!---------------------------------------------------------------------------------
!      main model variables, units are SI
!---------------------------------------------------------------------------------
      real*8, allocatable, dimension(:,:,:,:)   :: u,v,w   ! velocicity components for three time levels
      real*8, allocatable, dimension(:,:,:,:)   :: b       ! (negative) buoyancy for three time levels
      real*8, allocatable, dimension(:,:,:,:)   :: p_full  ! full pressure for three time levels
      real*8, allocatable, dimension(:,:,:)     :: p_hydro ! hydrostatic pressure at time level tau
      real*8, allocatable, dimension(:,:,:)     :: psi     ! non-hdrostatic pressure at time level tau
      real*8, allocatable, dimension(:,:)       :: p_surf  ! surface pressure
      real*8, allocatable, dimension(:,:,:)     :: eta     ! free surface elevation
      real*8, allocatable, dimension(:,:,:)     :: bu   ! barotropic zonal velocity  (only for enable_expl_free_surf)
      real*8, allocatable, dimension(:,:,:)     :: bv   ! barotropic meridonal velocity (only for enable_expl_free_surf)
!---------------------------------------------------------------------------------
!      auxilliary model variables 
!---------------------------------------------------------------------------------
      real*8, allocatable, dimension(:,:,:)     :: K_b     ! vertical diffusivity set in case of static instability
      real*8, allocatable, dimension(:,:,:)     :: maskT   ! mask for T-grid (1 in water, 0 at land)
      real*8, allocatable, dimension(:,:,:)     :: maskU   ! same for U-grid
      real*8, allocatable, dimension(:,:,:)     :: maskV   ! same for V-grid
      real*8, allocatable, dimension(:,:,:)     :: maskW   ! same for W-grid
      real*8, allocatable, dimension(:,:,:)     :: fu      ! time tendency of u except pressure gradient
      real*8, allocatable, dimension(:,:,:)     :: fv      ! time tendency of v except pressure gradient
      real*8, allocatable, dimension(:,:,:)     :: fw      ! time tendency of w except pressure gradient
      real*8, allocatable, dimension(:)         :: coriolis_t    ! vertical coriolis parameter
      real*8, allocatable, dimension(:)         :: coriolis_hor  ! horizontal coriolis parameter
      real*8, allocatable,dimension(:,:)        :: surface_flux  ! surface buoyancy flux
      real*8, allocatable,dimension(:,:)        :: bottom_flux   ! bottom buoyancy flux
      real*8, allocatable,dimension(:,:)        :: surface_taux  ! surface flux of zonal momentum 
      real*8, allocatable,dimension(:,:)        :: surface_tauy  ! surface flux of meridional momentum 
      real*8, allocatable,dimension(:,:)        :: bottom_taux   ! bottom flux of zonal momentum
      real*8, allocatable,dimension(:,:)        :: bottom_tauy   ! bottom flux of meridional momentum 
      real*8, allocatable :: cf2D(:,:,:,:)      ! array containing coefficients to solve 2D Poisson equation
      real*8, allocatable :: cf3D(:,:,:,:,:,:)  ! array containing coefficients to solve 3D Poisson equation
!---------------------------------------------------------------------------------
!      model grid variables  
!---------------------------------------------------------------------------------
      real*8, allocatable, dimension(:)   :: zt  ! depth of T-grid point  (positive upward) in meters
      real*8, allocatable, dimension(:)   :: zw  ! depth of W-grid point in meters
      real*8, allocatable, dimension(:)   :: xt  ! zonal (x) coordinate of T-grid point in meters
      real*8, allocatable, dimension(:)   :: xu  ! zonal (x) coordinate of U-grid point in meters
      real*8, allocatable, dimension(:)   :: yt  ! meridional (y) coordinate of T-grid point in meters
      real*8, allocatable, dimension(:)   :: yu  ! meridional (y) coordinate of V-grid point in meters
      real*8, allocatable, dimension(:,:) :: hu  ! depth of water column at U-grid points
      real*8, allocatable, dimension(:,:) :: hv  ! depth of water column at V-grid points
      real*8, allocatable, dimension(:,:) :: ht  ! depth of water column at T-grid points
      integer,allocatable,dimension(:,:)  :: k_bottom_u ! number of verticel levels at U grid points
      integer,allocatable,dimension(:,:)  :: k_bottom_v ! number of verticel levels at V grid points
!---------------------------------------------------------------------------------
!       switches to configure model setup
!---------------------------------------------------------------------------------
      logical :: enable_noslip                = .false.  ! no lateral slip for momentum
      logical :: enable_bottom_noslip         = .false.  ! also for bottom 
      logical :: enable_cyclic_x              = .false.  ! periodic boundary condition in x
      logical :: enable_cyclic_y              = .false.  ! periodic boundary condition in y
      logical :: enable_quicker_advection     = .false.  ! quicker advection scheme for buoyancy
      logical :: enable_4th_advection         = .false.  ! 4. order advection scheme for buoyancy
      logical :: enable_upwind_advection      = .false.  ! upwind advection scheme for buoyancy
      logical :: enable_4th_mom_advection     = .false.  ! momentum advection
      logical :: enable_quicker_mom_advection = .false.  ! momentum advection
      logical :: enable_no_mom_advection      = .false.  ! no momentum advection at all
      logical :: enable_bottom_stress         = .false.  ! Bottom stress
      logical :: enable_interior_stress       = .false.  ! interior stress
      logical :: enable_biharmonic_friction   = .false.  ! biharmonic horizontal friction
      logical :: enable_vert_biha_friction    = .false.  ! biharmonic vertical  friction
      logical :: enable_biharmonic_diffusion  = .false.  ! same for diffusion
      logical :: enable_vert_biha_diffusion   = .false.  ! biharmonic vertical friction
      logical :: enable_free_surface          = .false.  ! implicit free surface
      logical :: enable_hydrostatic           = .true.   ! hydrostatic approximation
      logical :: enable_expl_free_surf        = .false.  ! explicit free surface
!---------------------------------------------------------------------------------
!      other stuff
!---------------------------------------------------------------------------------
      integer     :: tau,taum1,taup1   ! pointer for time levels
      real*8      :: c2dt              ! two times time step 
      integer     :: sor2D_itts        ! number of iterations of 2D Poisson solver
      integer     :: sor3D_itts        ! number of iterations of 3D Poisson solver
!-----------------------------------------------------------------------
!     residual momentum formulation
!-----------------------------------------------------------------------
      logical :: enable_vert_friction_trm   = .false.  ! vertical friction for residual momentum formulation
      real*8, allocatable :: A_trm(:,:,:) ! vertical viscosity
      real*8 :: K_gm      = 1000.0        ! GM mixing parameter
      real*8 :: aidif_trm = 1.0           ! choose implicit (=1)/explicit(=0) formulation 
      real*8 :: N_min     = 1d-5          ! minimal threshold for stability freq. N
      real*8 :: fNsqr_max = 0.01          ! limit f^2/N^2 by this value
!-----------------------------------------------------------------------
!     background stratification
!-----------------------------------------------------------------------
      logical :: enable_back_state           = .false.
      logical :: enable_back_zonal_flow      = .false.
      logical :: enable_back_meridional_flow = .false.
      real*8, allocatable :: back(:,:,:,:)  ! background stratification B, depends on
                                            ! time and x/y only for technical reasons
      real*8, allocatable :: u0(:,:,:)      ! background zonal/meridional advection U
!-----------------------------------------------------------------------
!     passive tracer stuff
!-----------------------------------------------------------------------
      real*8, allocatable, dimension(:,:,:,:,:) :: tr ! passive tracers
      integer :: nt=0                                 ! number of passive tracer
      logical :: enable_diag_tracer         = .false. ! passive tracer 
      logical :: delimit_tracer_fluxes      = .false. ! prevent spurious under shooting by advection of passive tracer
                                                      ! works only for positive tracer like concentrations
      logical :: enable_isopycnal_diffusion = .false. ! use isopycnal diffusion for effect of meso-scale eddies
      real*8 :: iso_dslope=0.0008          ! parameters controlling max allowed isopycnal slopes
      real*8 :: iso_slopec=0.005           ! parameters controlling max allowed isopycnal slopes
 end module pyOM_module   



 subroutine check_pyOM_module(ierr)
!---------------------------------------------------------------------------------
! some mild checks
!---------------------------------------------------------------------------------
 use pyOM_module   
 implicit none
 integer, intent(out) :: ierr

 ierr = 0

 if (nx==0 .or. ny==0 .or. nz==0) then
   print*,' ERROR: model dimensions are not defined'
   ierr=-3
   return
 endif

 if (tau>3 .or. tau<1 .or. taup1>3 .or. taup1<1 .or. taum1>3 .or. taum1<1 ) then
   print*,' ERROR: time levels are not valid'
   ierr=-4
   return
 endif

 if (allocated(u)) then
  if ( size(u,1)/=nx .or. size(u,2)/=ny .or. size(u,3)/=nz .or. size(u,4)/=3 ) then
   print*,' ERROR: dimension of variable u does not match'
   ierr=-2
   return  
  endif
 else
   print*,' ERROR: variable u is not allocated'
   ierr=-1
   return
 endif

 if (allocated(v)) then
  if ( size(v,1)/=nx .or. size(v,2)/=ny .or. size(v,3)/=nz .or. size(v,4)/=3 ) then
   print*,' ERROR: dimension of variable v does not match'
   ierr=-2
   return  
  endif
 else
   print*,' ERROR: variable v is not allocated'
   ierr=-1
   return
 endif

 if (allocated(w)) then
  if ( size(w,1)/=nx .or. size(w,2)/=ny .or. size(w,3)/=nz .or. size(w,4)/=3 ) then
   print*,' ERROR: dimension of variable w does not match'
   ierr=-2
   return  
  endif
 else
   print*,' ERROR: variable w is not allocated'
   ierr=-1
   return
 endif

 if (allocated(b)) then
  if ( size(b,1)/=nx .or. size(b,2)/=ny .or. size(b,3)/=nz .or. size(b,4)/=3 ) then
   print*,' ERROR: dimension of variable b does not match'
   ierr=-2
   return  
  endif
 else
   print*,' ERROR: variable b is not allocated'
   ierr=-1
   return
 endif
 
 if (allocated(p_full)) then
  if ( size(p_full,1)/=nx .or. size(p_full,2)/=ny .or. size(p_full,3)/=nz .or. size(p_full,4)/=3 ) then
   print*,' ERROR: dimension of variable p_full does not match'
   ierr=-2
   return  
  endif
 else
   print*,' ERROR: variable p_full is not allocated'
   ierr=-1
   return
 endif

 end subroutine check_pyOM_module   


