!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!                                                                   !!
!!                   GNU General Public License                      !!
!!                                                                   !!
!! This file is part of the Flexible Modeling System (FMS).          !!
!!                                                                   !!
!! FMS is free software; you can redistribute it and/or modify       !!
!! it and are expected to follow the terms of the GNU General Public !!
!! License as published by the Free Software Foundation.             !!
!!                                                                   !!
!! FMS 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 General Public License for more details.                      !!
!!                                                                   !!
!! You should have received a copy of the GNU General Public License !!
!! along with FMS; if not, write to:                                 !!
!!          Free Software Foundation, Inc.                           !!
!!          59 Temple Place, Suite 330                               !!
!!          Boston, MA  02111-1307  USA                              !!
!! or see:                                                           !!
!!          http://www.gnu.org/licenses/gpl.txt                      !!
!!                                                                   !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
module ocean_pressure_mod
!  
! 
! S.M. Griffies 
! 
!
! R.C. Pacanowski
!
!
! 
! A. Rosati 
! 
!
!
! Compute the hydrostatic pressure and forces from pressure. 
!
!
!
! This module computes hydrostatic pressure and the pressure force
! acting at a velocity point (traditional finite difference approach).
! This force is used for the linear momentum equation.  
!
! This module takes account of the vertical coordinate,
! which determines details of the calculation.  
!
!
! 
!
! 
! "Elements of mom4p1"
!  S.M. Griffies, (2007)
! 
!
! 
!
!
!  
!  For debugging. 
!   
!
!  
!  For debugging it is often useful to zero the contribution to the 
!  pressure gradient that arises from the "correction" term. 
!  Implemented only for depth based vertical coordinate models.
!   
!  
!  For debugging it is often useful to zero the contribution to the 
!  pressure gradient that arises from the along k-level gradient.
!  Implemented only for depth based vertical coordinate models.
!   
!  
!  For debugging it is often useful to zero the pressure force
!  to zero.  
!   
!  
!  For debugging zstar, we drop any eta/H contribution to 
!  the hydrostatic pressure.  This is wrong physically, but 
!  useful for certain tests.   
!   
!
!
use constants_mod,    only: grav, c2dbars, epsln 
use diag_manager_mod, only: register_diag_field, send_data
use fms_mod,          only: open_namelist_file, check_nml_error, close_file, write_version_number
use mpp_io_mod,       only: mpp_open, mpp_close, MPP_RDONLY, MPP_ASCII
use mpp_mod,          only: mpp_error, FATAL, stdout, stdlog, mpp_chksum
use ocean_domains_mod,    only: get_local_indices
use ocean_operators_mod,  only: FAY, FAX, FDX_NT, FDY_ET 
use ocean_parameters_mod, only: GEOPOTENTIAL, ZSTAR, ZSIGMA
use ocean_parameters_mod, only: PRESSURE, PSTAR, PSIGMA
use ocean_parameters_mod, only: DEPTH_BASED, PRESSURE_BASED
use ocean_parameters_mod, only: ENERGETIC, FINITEVOLUME
use ocean_parameters_mod, only: missing_value, rho0, rho0r
use ocean_types_mod,      only: ocean_domain_type, ocean_grid_type
use ocean_types_mod,      only: ocean_time_type, ocean_velocity_type
use ocean_types_mod,      only: ocean_thickness_type, ocean_density_type
use ocean_util_mod,       only: write_timestamp
use ocean_workspace_mod,  only: wrk1, wrk2, wrk1_zw, wrk2_zw, wrk1_v, wrk2_v, wrk1_2d
use ocean_obc_mod,        only: store_ocean_obc_pressure_grad
implicit none
private
public ocean_pressure_init
public pressure_in_dbars
public pressure_force
public hydrostatic_pressure
public geopotential_anomaly 
private pressure_gradient_force_depth
private pressure_gradient_force_press
#include 
type(ocean_domain_type), pointer :: Dom =>NULL()
type(ocean_grid_type), pointer   :: Grd =>NULL()
character(len=128) :: version = &
     '$Id: ocean_pressure.F90,v 16.0.108.1 2009/10/10 00:41:59 nnz Exp $'
character (len=128) :: tagname = &
     '$Name: mom4p1_pubrel_dec2009_nnz $'
! for vertical coordinate
integer :: vert_coordinate 
integer :: vert_coordinate_class
! useful constants
real :: grav_rho0r
real :: grav_rho0
real :: p5grav
real :: p5gravr
real :: p5grav_rho0r
real :: dbars2pa
! for computing geopotential at T-cell bottom from depth_zwt
real :: geopotential_switch=0.0
! for diagnostics
integer :: id_geopotential   =-1
integer :: id_anomgeopot     =-1
integer :: id_anomgeopot_zwt =-1
integer :: id_anompress      =-1
integer :: id_anompress_zwt  =-1
integer :: id_press_force(2)           =-1
integer :: id_pgrad_klev(2)            =-1
integer :: id_rhoprime_geograd_klev(2) =-1
integer :: id_rhoprime_pgrad_klev(2)   =-1
integer :: id_rho_geogradprime_klev(2) =-1
logical :: used
logical :: debug_this_module         =.false. 
logical :: zero_pressure_force       =.false.
logical :: zero_correction_term_grad =.false.
logical :: zero_diagonal_press_grad  =.false.
logical :: module_is_initialized     =.false.
logical :: have_obc                  =.false. 
logical :: zero_eta_over_h_zstar_pressure = .false. 
namelist /ocean_pressure_nml/ debug_this_module, zero_pressure_force, &
         zero_correction_term_grad, zero_diagonal_press_grad,         &
         zero_eta_over_h_zstar_pressure
contains
!#######################################################################
! 
!
! 
! Initialize the pressure module
! 
!
subroutine ocean_pressure_init(Grid, Domain, Time, ver_coordinate, &
                               ver_coordinate_class, obc, debug)
  type(ocean_grid_type),   target, intent(in) :: Grid
  type(ocean_domain_type), target, intent(in) :: Domain
  type(ocean_time_type),           intent(in) :: Time
  integer,                         intent(in) :: ver_coordinate
  integer,                         intent(in) :: ver_coordinate_class
  logical,                         intent(in) :: obc
  logical,               optional, intent(in) :: debug
  integer :: ioun, io_status, ierr
  integer :: stdoutunit,stdlogunit 
  stdoutunit=stdout();stdlogunit=stdlog() 
  if ( module_is_initialized ) then 
    call mpp_error( FATAL, &
    '==>Error: ocean_pressure_mod (ocean_pressure_init): module already initialized')
  endif 
  module_is_initialized = .TRUE.
  call write_version_number( version, tagname )
  have_obc              = obc
  vert_coordinate       = ver_coordinate
  vert_coordinate_class = ver_coordinate_class
  grav_rho0    = grav*rho0
  grav_rho0r   = grav*rho0r
  p5grav       = 0.5*grav
  p5gravr      = 0.5/grav
  p5grav_rho0r = 0.5*grav*rho0r 
  dbars2pa     = 1.0/c2dbars
  ioun = open_namelist_file()
  read  (ioun, ocean_pressure_nml,iostat=io_status)
  write (stdoutunit,'(/)')
  write (stdoutunit, ocean_pressure_nml)
  write (stdlogunit, ocean_pressure_nml)
  ierr = check_nml_error(io_status, 'ocean_pressure_nml')
  call close_file(ioun)
#ifndef MOM4_STATIC_ARRAYS
  call get_local_indices(Domain,isd, ied, jsd, jed, isc, iec, jsc, jec)
  nk = Grid%nk
#endif
  Dom => Domain
  Grd => Grid
  if (PRESENT(debug) .and. .not. debug_this_module) then
    debug_this_module = debug
  endif 
  if(debug_this_module) then 
    write(stdoutunit,'(a)') '==>Note: running ocean_pressure_mod with debug_this_module=.true.'  
  endif 
  if(zero_pressure_force) then 
    write(stdoutunit,*) &
    '==>Warning: Running mom4 with zero horizontal pressure force. Unrealistic simulation.'
  endif 
  if(vert_coordinate==GEOPOTENTIAL) then 
     geopotential_switch=0.0
  else
     geopotential_switch=1.0
  endif
  write(stdoutunit,*) &
       '==>NOTE: Running mom4p1 with finite difference formulation of pressure force.'
  if(zero_correction_term_grad) then 
      write(stdoutunit,*) &
           '==>Warning: Running mom4p1 with zero_correction_term_grad=.true. Unrealistic simulation.'
  endif
  if(zero_diagonal_press_grad) then 
      write(stdoutunit,*) &
           '==>Warning: Running mom4p1 with zero_diagonal_press_grad=.true. Unrealistic simulation.'
  endif
  ! register fields
  id_geopotential = register_diag_field ('ocean_model', 'geopotential', Grd%tracer_axes(1:3),&
   Time%model_time, 'geopotential at T-point', 'm^2/s^2',                                    &
   missing_value=missing_value, range=(/-1e8,1e8/))
  id_anompress = register_diag_field ('ocean_model', 'anompress', Grd%tracer_axes(1:3),&
   Time%model_time, 'anomalous hydrostatic pressure at T-point', 'Pa',                 &
   missing_value=missing_value, range=(/-1e8,1e8/))
  id_anompress_zwt = register_diag_field ('ocean_model', 'anompress_zwt', Grd%tracer_axes(1:3),&
   Time%model_time, 'anomalous hydrostatic pressure at T-cell bottom', 'Pa',                   &
   missing_value=missing_value, range=(/-1e8,1e8/))
  id_anomgeopot = register_diag_field ('ocean_model', 'anomgeopot', Grd%tracer_axes(1:3),&
   Time%model_time, 'anomalous geopotential at T-point', 'm^2/s^2',                      &
   missing_value=missing_value, range=(/-1e8,1e8/))
  id_anomgeopot_zwt = register_diag_field ('ocean_model', 'anomgeopot_zwt', Grd%tracer_axes(1:3),&
   Time%model_time, 'anomalous geopotential at T-cell bottom', 'm^2/s^2',                        &
   missing_value=missing_value, range=(/-1e8,1e8/))
  id_pgrad_klev(1) = register_diag_field ('ocean_model', 'dzupgrad_x_klev', Grd%vel_axes_uv(1:3), &
     Time%model_time, 'dzu*dp_dx on k-level', 'Pa', missing_value=missing_value, range=(/-1e9,1e9/))
  id_pgrad_klev(2) = register_diag_field ('ocean_model', 'dzupgrad_y_klev', Grd%vel_axes_uv(1:3), &
     Time%model_time, 'dzu*dp_dy on k-level', 'Pa', missing_value=missing_value, range=(/-1e9,1e9/))
  id_rhoprime_geograd_klev(1) = register_diag_field ('ocean_model', 'dzurhoprime_geograd_x_klev', &
     Grd%vel_axes_uv(1:3), Time%model_time, 'dzu*rhoprime*d(geopot)/dx on k-level', 'Pa',         &
     missing_value=missing_value, range=(/-1e9,1e9/))
  id_rhoprime_geograd_klev(2) = register_diag_field ('ocean_model', 'dzurhoprime_geograd_y_klev', &
    Grd%vel_axes_uv(1:3), Time%model_time, 'dzu*rhoprime*d(geopot)/dx on k-level', 'Pa',          &
    missing_value=missing_value, range=(/-1e9,1e9/))
  id_rhoprime_pgrad_klev(1) = register_diag_field ('ocean_model', 'dzurhoprime_pgrad_x_klev', &
     Grd%vel_axes_uv(1:3), Time%model_time, 'dzu*(rhoprime/rho0)*dp/dx on k-level', 'Pa',     &
     missing_value=missing_value, range=(/-1e9,1e9/))
  id_rhoprime_pgrad_klev(2) = register_diag_field ('ocean_model', 'dzurhoprime_pgrad_y_klev', &
     Grd%vel_axes_uv(1:3), Time%model_time, 'dzu*(rhoprime/rho0)*dp/dy on k-level', 'Pa',     &
     missing_value=missing_value, range=(/-1e9,1e9/))
  id_rho_geogradprime_klev(1) = register_diag_field ('ocean_model', 'dzurho_geogradprime_x_klev',&
    Grd%vel_axes_uv(1:3), Time%model_time, 'dzu*rho*d(geopot_prime)/dx on k-level', 'Pa',        &
    missing_value=missing_value, range=(/-1e9,1e9/))
  id_rho_geogradprime_klev(2) = register_diag_field ('ocean_model', 'dzurho_geogradprime_y_klev',&
    Grd%vel_axes_uv(1:3), Time%model_time, 'dzu*rho*d(geopot_prime)/dy on k-level', 'Pa/m',      &
    missing_value=missing_value, range=(/-1e9,1e9/))
  id_press_force(1) = register_diag_field ('ocean_model', 'press_force_u',  &
     Grd%vel_axes_uv(1:3), Time%model_time, 'i-directed pressure force',    &
     'Pa', missing_value=missing_value, range=(/-1e9,1e9/))
  id_press_force(2) = register_diag_field ('ocean_model', 'press_force_v', &
     Grd%vel_axes_uv(1:3), Time%model_time, 'j-directed pressure force',   &
     'Pa', missing_value=missing_value, range=(/-1e9,1e9/))
 
end subroutine ocean_pressure_init
!  NAME="ocean_pressure_init"
!#######################################################################
! 
!
! 
! Compute the horizontal force [Pa=N/m^2] from pressure. 
!
! Use the traditional approach whereby the pressure force
! is computed as a finite difference gradient centred 
! at the U-cell point. 
!
! 
!
subroutine pressure_force(Time, Thickness, Dens, Velocity, rho)
  type(ocean_time_type),          intent(in)    :: Time
  type(ocean_thickness_type),     intent(in)    :: Thickness
  type(ocean_density_type),       intent(in)    :: Dens
  type(ocean_velocity_type),      intent(inout) :: Velocity
  real, dimension(isd:,jsd:,:),   intent(in)    :: rho
  integer :: tau 
 
  integer :: stdoutunit 
  stdoutunit=stdout() 
  tau = Time%tau 
  if ( .not. module_is_initialized ) then 
    call mpp_error(FATAL, &
    '==>Error in ocean_pressure_mod (pressure_force): module must be initialized')
  endif 
  if(vert_coordinate_class==DEPTH_BASED) then 
      call pressure_gradient_force_depth(Time, Thickness, Velocity, rho)
  else 
      call pressure_gradient_force_press(Time, Thickness, Dens, Velocity, rho)
  endif
  ! for debugging 
  if(zero_pressure_force) then 
      Velocity%press_force = 0.0
  endif
  ! for open boundaries 
  if (have_obc) call store_ocean_obc_pressure_grad(Thickness, Velocity%press_force, tau) 
  ! send some diagnostics 
  if(id_geopotential > 0) used = send_data( id_geopotential, -grav*Thickness%geodepth_zt(:,:,:), &
       Time%model_time, rmask=Grd%tmask(:,:,:),                                                  &
       is_in=isc, js_in=jsc, ks_in=1, ie_in=iec, je_in=jec, ke_in=nk)
  if (id_press_force(1) > 0) then 
       used = send_data( id_press_force(1), Velocity%press_force(:,:,:,1), &
       Time%model_time, rmask=Grd%umask(:,:,:),                            &
       is_in=isc, js_in=jsc, ks_in=1, ie_in=iec, je_in=jec, ke_in=nk)
  endif 
  if (id_press_force(2) > 0) then 
       used = send_data( id_press_force(2), Velocity%press_force(:,:,:,2), &
       Time%model_time, rmask=Grd%umask(:,:,:),                            &
       is_in=isc, js_in=jsc, ks_in=1, ie_in=iec, je_in=jec, ke_in=nk)
  endif 
  ! more debugging 
  if(debug_this_module) then 
      write(stdoutunit,*)' '
      write(stdoutunit,*) 'From ocean_pressure_mod: pressure chksums'
      call write_timestamp(Time%model_time)
      write(stdoutunit,*) 'rho_dzu(tau)   = ', &
       mpp_chksum(Thickness%rho_dzu(isc:iec,jsc:jec,:,tau)*Grd%umask(isc:iec,jsc:jec,:))
      write(stdoutunit,*) 'press_force(1) = ', &
       mpp_chksum(Velocity%press_force(isc:iec,jsc:jec,:,1)*Grd%umask(isc:iec,jsc:jec,:))
      write(stdoutunit,*) 'press_force(2) = ', &
       mpp_chksum(Velocity%press_force(isc:iec,jsc:jec,:,2)*Grd%umask(isc:iec,jsc:jec,:))
  endif 
end subroutine pressure_force
!  NAME="pressure_force"
!#######################################################################
! 
!
! 
! Compute the force from pressure using a finite difference method
! to compute the thickness weighted pressure gradient at the 
! velocity cell point. 
!
! For depth-like vertical coordinates, we exclude surface and applied 
! pressures (i.e., we are computing here the gradient of the baroclinic 
! pressure).  Account is taken of variable partial cell thickness.
! 1 = dp/dx; 2 = dp/dy
!
! Thickness weight since this is what we wish to use in update of 
! the velocity. Resulting thickness weighted pressure gradient has 
! dimensions of Pa = N/m^2 = kg/(m*s^2).
!
! Thickness%dzu should be at tau.
!
! 
!
subroutine pressure_gradient_force_depth(Time, Thickness, Velocity, rho)
  type(ocean_time_type),          intent(in)    :: Time
  type(ocean_thickness_type),     intent(in)    :: Thickness
  type(ocean_velocity_type),      intent(inout) :: Velocity
  real, dimension(isd:,jsd:,:),   intent(in)    :: rho
  real, dimension(isd:ied,jsd:jed) :: diff_geo_x
  real, dimension(isd:ied,jsd:jed) :: diff_geo_y
  real, dimension(isd:ied,jsd:jed) :: tmp1
  real, dimension(isd:ied,jsd:jed) :: tmp2
  integer :: i, j, k
  integer :: tau
  if ( .not. module_is_initialized ) then 
    call mpp_error(FATAL, &
    '==>Error in ocean_pressure_mod (pressure_gradient_force_depth): module must be initialized')
  endif 
  tau    = Time%tau
  tmp1   = 0.0
  tmp2   = 0.0
  wrk1_v = 0.0
  wrk2_v = 0.0
  ! use density anomaly to improve accuracy 
  do k=1,nk
     do j=jsd,jed
        do i=isd,ied
           wrk2(i,j,k) = Grd%tmask(i,j,k)*(rho(i,j,k)-rho0)
        enddo
     enddo
  enddo
  
  ! compute hydrostatic pressure anomaly at T-point 
  ! ( Pa=N/m^2=kg/(m*s^2) )
  wrk1(:,:,:) = hydrostatic_pressure(Thickness, wrk2(:,:,:))  
  if(id_anompress > 0) then 
      used = send_data( id_anompress, wrk1(:,:,:),  &
           Time%model_time, rmask=Grd%tmask(:,:,:), &
           is_in=isc, js_in=jsc, ks_in=1, ie_in=iec, je_in=jec, ke_in=nk)
  endif
  diff_geo_x(:,:) = 0.0
  diff_geo_y(:,:) = 0.0
  do k=1,nk
     do j=jsd,jed
        do i=isd,iec
           diff_geo_x(i,j) = -grav*(Thickness%geodepth_zt(i+1,j,k)-Thickness%geodepth_zt(i,j,k))
        enddo
     enddo
     do j=jsd,jec
        do i=isd,ied
           diff_geo_y(i,j) = -grav*(Thickness%geodepth_zt(i,j+1,k)-Thickness%geodepth_zt(i,j,k))
        enddo
     enddo
     ! density anomaly times geopotential gradient on k-levels 
     ! (dzurhoprime_geograd_x_klev,dzurhoprime_geograd_y_klev)
     tmp1(:,:) = FAY(FAX(wrk2(:,:,k))*diff_geo_x(:,:))
     tmp2(:,:) = FAX(FAY(wrk2(:,:,k))*diff_geo_y(:,:))
     do j=jsc,jec
        do i=isc,iec
           wrk1_v(i,j,k,1) = tmp1(i,j)*Grd%dxur(i,j)*Thickness%dzu(i,j,k)
           wrk1_v(i,j,k,2) = tmp2(i,j)*Grd%dyur(i,j)*Thickness%dzu(i,j,k)
        enddo
     enddo
     if(zero_correction_term_grad) then 
         wrk1_v(:,:,:,:) = 0.0
     endif
     ! gradient of anomalous baroclinic pressure on k-levels 
     ! (dzupgrad_x_klev,dzupgrad_y_klev)
     tmp1(:,:) = FDX_NT(FAY(wrk1(:,:,k)))
     tmp2(:,:) = FDY_ET(FAX(wrk1(:,:,k)))
     do j=jsc,jec
        do i=isc,iec
           wrk2_v(i,j,k,1) = tmp1(i,j)*Thickness%dzu(i,j,k)
           wrk2_v(i,j,k,2) = tmp2(i,j)*Thickness%dzu(i,j,k)
        enddo
     enddo
     if(zero_diagonal_press_grad) then 
         wrk2_v(:,:,:,:) = 0.0
     endif
     ! thickness weighted baroclinic pressure gradient on z-levels
     ! (dzu_pgrad_u,dzu_pgrad_v)
     do j=jsc,jec
        do i=isc,iec    
           Velocity%press_force(i,j,k,1) = -Grd%umask(i,j,k)*( wrk1_v(i,j,k,1) + wrk2_v(i,j,k,1) )
           Velocity%press_force(i,j,k,2) = -Grd%umask(i,j,k)*( wrk1_v(i,j,k,2) + wrk2_v(i,j,k,2) )
        enddo
     enddo
  enddo   ! k do-loop finish 
  ! (dzurhoprime_geograd_x_klev,dzurhoprime_geograd_y_klev)
  if (id_rhoprime_geograd_klev(1) > 0) then 
      used=send_data( id_rhoprime_geograd_klev(1),wrk1_v(:,:,:,1), &
           Time%model_time, rmask=Grd%umask(:,:,:),                &
           is_in=isc, js_in=jsc, ks_in=1, ie_in=iec, je_in=jec, ke_in=nk)
  endif
  if (id_rhoprime_geograd_klev(2) > 0) then 
      used=send_data( id_rhoprime_geograd_klev(2),wrk1_v(:,:,:,2), &
           Time%model_time, rmask=Grd%umask(:,:,:),                &
           is_in=isc, js_in=jsc, ks_in=1, ie_in=iec, je_in=jec, ke_in=nk)
  endif
  ! (dzupgrad_x_klev,dzupgrad_y_klev)
  if (id_pgrad_klev(1) > 0) then 
      used = send_data( id_pgrad_klev(1), wrk2_v(:,:,:,1), &
           Time%model_time, rmask=Grd%umask(:,:,:),        &
           is_in=isc, js_in=jsc, ks_in=1, ie_in=iec, je_in=jec, ke_in=nk)
  endif
  if (id_pgrad_klev(2) > 0) then 
      used = send_data( id_pgrad_klev(2), wrk2_v(:,:,:,2), &
           Time%model_time, rmask=Grd%umask(:,:,:),        &
           is_in=isc, js_in=jsc, ks_in=1, ie_in=iec, je_in=jec, ke_in=nk)
  endif
end subroutine pressure_gradient_force_depth
!  NAME="pressure_gradient_force_depth"
!#######################################################################
! 
!
! 
! Compute the force from pressure using a finite difference method
! to compute the thickness weighted pressure gradient at the 
! velocity cell point. 
!
! For pressure-like vertical coordinates, we omit the bottom pressure
! and bottom geopotential.  Account is taken of variable partial cell
! thickness.  1 = dp/dx; 2 = dp/dy
!
! Thickness weight since this is what we wish to use in update of 
! the velocity. Resulting thickness weighted pressure gradient has 
! dimensions of Pa = N/m^2 = kg/(m*s^2).
!
! Thickness%dzu should be at tau.
!
! 
!
subroutine pressure_gradient_force_press(Time, Thickness, Dens, Velocity, rho)
  type(ocean_time_type),          intent(in)    :: Time
  type(ocean_thickness_type),     intent(in)    :: Thickness
  type(ocean_density_type),       intent(in)    :: Dens
  type(ocean_velocity_type),      intent(inout) :: Velocity
  real, dimension(isd:,jsd:,:),   intent(in)    :: rho
  real, dimension(isd:ied,jsd:jed) :: diff_press_x
  real, dimension(isd:ied,jsd:jed) :: diff_press_y
  real, dimension(isd:ied,jsd:jed) :: tmp1
  real, dimension(isd:ied,jsd:jed) :: tmp2
  integer :: i, j, k
  integer :: tau
  if ( .not. module_is_initialized ) then 
    call mpp_error(FATAL, &
    '==>Error in ocean_pressure_mod (pressure_gradient_force_press): module must be initialized')
  endif 
  tau    = Time%tau
  tmp1   = 0.0
  tmp2   = 0.0
  wrk1_v = 0.0
  wrk2_v = 0.0
  ! use density anomaly to improve accuracy 
  do k=1,nk
     do j=jsd,jed
        do i=isd,ied
           wrk2(i,j,k) = Grd%tmask(i,j,k)*(rho(i,j,k)-rho0)
        enddo
     enddo
  enddo
  ! compute geopotential anomaly (m^2/s^2) at T-cell point 
  wrk1(:,:,:) = geopotential_anomaly(Thickness, wrk2(:,:,:)) 
  if(id_anomgeopot > 0) then 
      used = send_data( id_anomgeopot, wrk1(:,:,:), &
           Time%model_time, rmask=Grd%tmask(:,:,:), &
           is_in=isc, js_in=jsc, ks_in=1, ie_in=iec, je_in=jec, ke_in=nk)
  endif
  diff_press_x(:,:) = 0.0
  diff_press_y(:,:) = 0.0
  do k=1,nk
     do j=jsd,jed
        do i=isd,iec
           diff_press_x(i,j) = -dbars2pa*(Dens%pressure_at_depth(i+1,j,k)-Dens%pressure_at_depth(i,j,k))
        enddo
     enddo
     do j=jsd,jec
        do i=isd,ied
           diff_press_y(i,j) = -dbars2pa*(Dens%pressure_at_depth(i,j+1,k)-Dens%pressure_at_depth(i,j,k))
        enddo
     enddo
     ! anomalous density times gradient of pressure on k-level               
     ! (dzurhoprime_pgrad_x_klev,dzurhoprime_pgrad_y_klev)
     tmp1(:,:) = rho0r*FAY(FAX(wrk2(:,:,k))*diff_press_x(:,:))
     tmp2(:,:) = rho0r*FAX(FAY(wrk2(:,:,k))*diff_press_y(:,:))
     do j=jsc,jec
        do i=isc,iec
           wrk1_v(i,j,k,1) = tmp1(i,j)*Grd%dxur(i,j)*Thickness%dzu(i,j,k)
           wrk1_v(i,j,k,2) = tmp2(i,j)*Grd%dyur(i,j)*Thickness%dzu(i,j,k)
        enddo
     enddo
     ! density times gradient of anomalous geopotential on k-level
     ! (dzurho_geogradprime_x_klev,dzurho_geogradprime_y_klev) 
     tmp1(:,:) = FDX_NT(FAY(wrk1(:,:,k)))
     tmp2(:,:) = FDY_ET(FAX(wrk1(:,:,k)))
     do j=jsc,jec
        do i=isc,iec
           wrk2_v(i,j,k,1) = tmp1(i,j)*Thickness%rho_dzu(i,j,k,tau)
           wrk2_v(i,j,k,2) = tmp2(i,j)*Thickness%rho_dzu(i,j,k,tau)
        enddo
     enddo
     ! thickness weighted baroclinic pressure gradient on z-levels
     ! (dzu_pgrad_u,dzu_pgrad_v)
     do j=jsc,jec
        do i=isc,iec    
           Velocity%press_force(i,j,k,1) = -Grd%umask(i,j,k)*( wrk1_v(i,j,k,1) + wrk2_v(i,j,k,1) )
           Velocity%press_force(i,j,k,2) = -Grd%umask(i,j,k)*( wrk1_v(i,j,k,2) + wrk2_v(i,j,k,2) )
        enddo
     enddo
  enddo  ! k do-loop finish 
  ! (dzurhoprime_pgrad_x_klev,dzurhoprime_pgrad_y_klev)
  if (id_rhoprime_pgrad_klev(1) > 0) then 
      used = send_data(id_rhoprime_pgrad_klev(1),wrk1_v(:,:,:,1), &
           Time%model_time, rmask=Grd%umask(:,:,:),               &
           is_in=isc, js_in=jsc, ks_in=1, ie_in=iec, je_in=jec, ke_in=nk)
  endif
  if (id_rhoprime_pgrad_klev(2) > 0) then 
      used = send_data(id_rhoprime_pgrad_klev(2),wrk1_v(:,:,:,2), &
           Time%model_time, rmask=Grd%umask(:,:,:),               &
           is_in=isc, js_in=jsc, ks_in=1, ie_in=iec, je_in=jec, ke_in=nk)
  endif
  ! (dzurho_geogradprime_x_klev,dzurho_geogradprime_y_klev)
  if (id_rho_geogradprime_klev(1) > 0) then 
      used=send_data(id_rho_geogradprime_klev(1),wrk2_v(:,:,:,1), &
           Time%model_time, rmask=Grd%umask(:,:,:),               &
           is_in=isc, js_in=jsc, ks_in=1, ie_in=iec, je_in=jec, ke_in=nk)
  endif
  if (id_rho_geogradprime_klev(2) > 0) then 
      used=send_data(id_rho_geogradprime_klev(2),wrk2_v(:,:,:,2), &
           Time%model_time, rmask=Grd%umask(:,:,:),               &
           is_in=isc, js_in=jsc, ks_in=1, ie_in=iec, je_in=jec, ke_in=nk)
  endif
end subroutine pressure_gradient_force_press
!  NAME="pressure_gradient_force_press"
!#######################################################################
! 
!
! 
! Compute pressure (dbars) exerted at T cell grid point by weight of
! water column above the grid point. 
!
! rho = density in kg/m^3
!
! psurf = surface pressure in Pa= kg/(m*s^2) = hydrostatic pressure 
! at z=0 associated with fluid between z=0 and z=eta_t.
! Also include pressure from atmosphere and ice, both of which 
! are part of the patm array. 
!
! This routine is used by ocean_density to compute the pressure 
! used in the equation of state.  It is only called when the 
! vertical coordinate is DEPTH_BASED.
!
! 
function pressure_in_dbars (Thickness, rho, psurf)
  type(ocean_thickness_type),   intent(in) :: Thickness
  real, dimension(isd:,jsd:,:), intent(in) :: rho   
  real, dimension(isd:,jsd:),   intent(in) :: psurf 
  real, dimension(isd:ied,jsd:jed,nk)      :: pressure_in_dbars
  integer :: k
  if ( .not. module_is_initialized ) then   
    call mpp_error(FATAL, &
    '==>Error in ocean_pressure_mod (pressure_in_dbars): module must be initialized')
  endif 
  pressure_in_dbars(:,:,:) = hydrostatic_pressure (Thickness, rho(:,:,:))*c2dbars
  ! add pressure from free surface height and loading from atmosphere and/or sea ice
  do k=1,nk
     pressure_in_dbars(:,:,k) = pressure_in_dbars(:,:,k) + psurf(:,:)*c2dbars 
  enddo
end function pressure_in_dbars
!  NAME="pressure_in_dbars"
!#######################################################################
! 
!
! 
! Hydrostatic pressure [Pa=N/m^2=kg/(m*s^2)] at T cell grid points.
!
! For GEOPOTENTIAL vertical coordinate, integration is 
! from z=0 to depth of grid point.  This integration results in  
! the so-called "baroclinic" pressure. 
!
! For ZSTAR or ZSIGMA, vertical coordinate, integration is from z=eta to 
! depth of grid point.  This is allowed because ZSTAR and ZSIGMA 
! absorb the undulations of the surface height into their definition.
!
! If the input density "rho" is an anomoly, the resulting presure 
! will be a hydrostatic pressure anomoly. If "rho" is full density, 
! the presure will be a full hydrostatic pressure.
!
! 
!
function hydrostatic_pressure (Thickness, rho)
  type(ocean_thickness_type),   intent(in) :: Thickness
  real, dimension(isd:,jsd:,:), intent(in) :: rho
  integer :: i, j, k
  real, dimension(isd:ied,jsd:jed,nk) :: hydrostatic_pressure
  if(vert_coordinate==GEOPOTENTIAL) then 
      do j=jsd,jed
         do i=isd,ied
            hydrostatic_pressure(i,j,1) = rho(i,j,1)*grav*Grd%dzw(0)
         enddo
      enddo
  elseif(vert_coordinate==ZSTAR .or. vert_coordinate==ZSIGMA) then 
      do j=jsd,jed
         do i=isd,ied
            hydrostatic_pressure(i,j,1) = rho(i,j,1)*grav*Thickness%dzwt(i,j,0)
         enddo
      enddo
  endif
  if(Thickness%method==ENERGETIC) then 
      do k=2,nk
         do j=jsd,jed
            do i=isd,ied
               hydrostatic_pressure(i,j,k) = hydrostatic_pressure(i,j,k-1) &
               + Grd%tmask(i,j,k)*p5grav                                   &
                *(rho(i,j,k-1)+rho(i,j,k))*Thickness%dzwt(i,j,k-1) 
            enddo
         enddo
      enddo
  elseif(Thickness%method==FINITEVOLUME) then 
      do k=2,nk
         do j=jsd,jed
            do i=isd,ied
               hydrostatic_pressure(i,j,k) = hydrostatic_pressure(i,j,k-1) &
               + Grd%tmask(i,j,k)*grav                                     &
                *(Thickness%dztlo(i,j,k-1)*rho(i,j,k-1)+Thickness%dztup(i,j,k)*rho(i,j,k)) 
            enddo
         enddo
      enddo
  endif
  ! For some debugging...we here drop the contribution from a 
  ! nonzero eta in the calculation of hydrostatic_pressure. 
  ! This is wrong physically, but it is useful for certain tests
  ! of the zstar vertical coordinate.  
  if(vert_coordinate==ZSTAR .and. zero_eta_over_h_zstar_pressure) then 
      do j=jsd,jed
         do i=isd,ied
            hydrostatic_pressure(i,j,1) = rho(i,j,1)*grav*Thickness%dswt(i,j,0)
         enddo
      enddo
      do k=2,nk
         do j=jsd,jed
            do i=isd,ied
               hydrostatic_pressure(i,j,k) = hydrostatic_pressure(i,j,k-1) &
               + Grd%tmask(i,j,k)*p5grav                                   &
                *(rho(i,j,k-1)+rho(i,j,k))*Thickness%dswt(i,j,k-1) 
            enddo
         enddo
      enddo
  endif 
end function hydrostatic_pressure
!  NAME="hydrostatic_pressure"
!#######################################################################
! 
!
! 
! Geopotential anomaly [m^2/s^2] at T cell grid points.
! Integration here is from z=-H to depth of grid point.  
!
! Input should be density anomaly rhoprime = rho-rho0.
!
! This function is needed when computing pressure gradient
! for PRESSURE_BASED vertical coordinates. 
!
! WARNING: Thickness%method==FINITEVOLUME has been found to be 
! problematic.  It remains under development.  It is NOT 
! supported for general use. 
! 
! 
!
function geopotential_anomaly (Thickness, rhoprime)
  type(ocean_thickness_type),   intent(in) :: Thickness
  real, dimension(isd:,jsd:,:), intent(in) :: rhoprime
  integer :: i, j, k, kbot
  real, dimension(isd:ied,jsd:jed,nk) :: geopotential_anomaly 
  
  geopotential_anomaly(:,:,:) = 0.0
  if(Thickness%method==ENERGETIC) then 
      do j=jsd,jed
         do i=isd,ied
            kbot=Grd%kmt(i,j)
            if(kbot > 1) then  
                k=kbot
                geopotential_anomaly(i,j,k) = -grav_rho0r*rhoprime(i,j,k)*Thickness%dzwt(i,j,k) 
                do k=kbot-1,1,-1
                   geopotential_anomaly(i,j,k) = geopotential_anomaly(i,j,k+1) &
                   -p5grav_rho0r*(rhoprime(i,j,k+1)+rhoprime(i,j,k))*Thickness%dzwt(i,j,k)
                enddo
            endif
         enddo
      enddo
  elseif(Thickness%method==FINITEVOLUME) then 
      do j=jsd,jed
         do i=isd,ied
            kbot=Grd%kmt(i,j)
            if(kbot > 1) then
                k=kbot
                geopotential_anomaly(i,j,k) = -grav_rho0r*rhoprime(i,j,k)*Thickness%dztlo(i,j,k)   
                do k=kbot-1,1,-1
                   geopotential_anomaly(i,j,k) = geopotential_anomaly(i,j,k+1) &
                   -grav_rho0r*(Thickness%dztlo(i,j,k)*rhoprime(i,j,k)+Thickness%dztup(i,j,k+1)*rhoprime(i,j,k+1)) 
                enddo
            endif
         enddo
      enddo
  endif
end function geopotential_anomaly
!  NAME="geopotential_anomaly"
end module ocean_pressure_mod