!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||


      module hmix_gm 1,19

!BOP
! !MODULE: hmix_gm

! !DESCRIPTION:
!  This module contains routines for computing horizontal mixing
!  using the Gent-McWilliams eddy transport parameterization
!  and isopycnal diffusion.

! !REVISION HISTORY:
!  SVN:$Id: hmix_gm.F90 22835 2010-05-07 23:11:58Z njn01 $

! !USES:

      use kinds_mod
      use blocks
      use distribution
      use domain
      use constants
      use broadcast
      use grid
      use io
      use vertical_mix
      use vmix_kpp
      use state_mod
      use time_management
      use tavg
      use diagnostics
      use exit_mod
      use registry
      use hmix_gm_submeso_share

#ifdef CCSMCOUPLED
   use shr_sys_mod
#endif
      use timers, only: timer_start, timer_stop, get_timer


      implicit none
      private
      save

! !PUBLIC MEMBER FUNCTIONS:

      public :: init_gm,   &
                hdifft_gm

!EOP
!BOC
!-----------------------------------------------------------------------
!
!     variables to save from one call to next
!
!-----------------------------------------------------------------------

      integer (int_kind), parameter :: &
         ktp = 1, kbt = 2     ! refer to the top and bottom halves of a
                              !  grid cell, respectively

      real (r8), dimension(:), allocatable :: &
         kappa_depth          ! depth dependence for KAPPA 

      real (r8), dimension(:,:,:), allocatable :: &
         HYXW, HXYS, &        ! west and south-shifted values of above
         RB,         &        ! Rossby radius
         RBR,        &        ! inverse of Rossby radius
         BTP,        &        ! beta plane approximation
         BL_DEPTH,   &        ! boundary layer depth
         UIT, VIT,   &        ! work arrays for isopycnal mixing velocities
         WTOP_ISOP, WBOT_ISOP ! vertical component of isopycnal velocities

      real (r8), dimension(:,:,:,:,:,:), allocatable :: &
         SF_SLX, SF_SLY       ! components of the merged streamfunction

      real (r8), dimension(:,:,:,:,:), allocatable :: &
         SLA_SAVE             ! isopycnal slopes

      real (r8), dimension(:,:,:,:), allocatable :: &
         FZTOP                ! vertical flux

      logical (log_kind), dimension(:), allocatable :: &
         compute_kappa        ! compute spatially varying coefficients
                              !  this time step?

      logical (log_kind) ::   &
         diff_tapering,       &   ! different tapering for two diffusivities
         cancellation_occurs, &   ! specified choices for the isopycnal and
                                  !  thickness diffusion coefficients result in 
                                  !  cancellation of some tensor elements
         read_n2_data             ! if .true., use climatological N^2 data 
                                  !  instead of model dependent N^2

!-----------------------------------------------------------------------
!
!     KAPPA_LATERAL and KAPPA_VERTICAL are 2D and 3D arrays, respectively,
!     containing the spatial variations of the isopycnal (KAPPA_ISOP)
!     and thickness (KAPPA_THIC) diffusion coefficients. Except in kappa_type_eg,
!     KAPPA_LATERAL has the actual diffusion coefficient values in cm^2/s,
!     whereas KAPPA_VERTICAL is unitless. So, the total coefficients are
!     constructed using
!
!      KAPPA_ISOP or KAPPA_THIC (:,:,:,k,bid) ~ KAPPA_LATERAL(:,:,bid)
!                                             * KAPPA_VERTICAL(:,:,k,bid)
!
!     When kappa_type_eg, KAPPA_VERTICAL contains the isopycnal diffusivity
!     coefficients in cm^2/s and KAPPA_LATERAL is not used!
!
!-----------------------------------------------------------------------

      real (r8), dimension(:,:,:,:,:), allocatable :: &
         KAPPA_ISOP, &      ! 3D isopycnal diffusion coefficient
                            !  for top and bottom half of a grid cell
         KAPPA_THIC, &      ! 3D thickness diffusion coefficient
                            !  for top and bottom half of a grid cell
         HOR_DIFF           ! 3D horizontal diffusion coefficient
                            !  for top and bottom half of a grid cell

      real (r8), dimension(:,:,:), allocatable :: &
         KAPPA_LATERAL      ! horizontal variation of KAPPA in cm^2/s

      real (r8), dimension(:,:,:,:), allocatable :: &
         KAPPA_VERTICAL     ! vertical variation of KAPPA (unitless),
                            !  e.g. normalized buoyancy frequency dependent 
                            !  profiles at the tracer grid points
                            !  ( = N^2 / N_ref^2 ) OR a time-independent
                            !  user-specified function

      real (r8), dimension(:,:,:,:), allocatable :: &
         BUOY_FREQ_SQ,    & ! N^2 defined at level interfaces
         SIGMA_TOPO_MASK    ! bottom topography mask used with kappa_type_eg

!-----------------------------------------------------------------------
!
!     GM specific options
!
!     kappa_freq = how often spatial variations of the diffusion 
!                  coefficients are computed. Same frequency is 
!                  used for both coefficients.
!     slope_control = tanh function (Danabasoglu and McWilliams 1995) or
!                     DM95 with replacement function to tanh or
!                     slope clipping or
!                     method of Gerdes et al (1991)
!     diag_gm_bolus = .true. for diagnostic bolus velocity computation.
!
!-----------------------------------------------------------------------

      integer (int_kind), parameter ::   &
         kappa_type_const         = 1,   &
         kappa_type_depth         = 2,   &
         kappa_type_vmhs          = 3,   &
         kappa_type_hdgr          = 4,   &
         kappa_type_dradius       = 5,   &
         kappa_type_bfreq         = 6,   &
         kappa_type_bfreq_vmhs    = 7,   &
         kappa_type_bfreq_hdgr    = 8,   &
         kappa_type_bfreq_dradius = 9,   &
         kappa_type_eg            = 10,  &
         slope_control_tanh   = 1,       &
         slope_control_notanh = 2,       &
         slope_control_clip   = 3,       &
         slope_control_Gerd   = 4,       &
         kappa_freq_never           = 1, &
         kappa_freq_every_time_step = 2, &
         kappa_freq_once_a_day      = 3  

      integer (int_kind) :: &
         kappa_isop_type,   &   ! choice of KAPPA_ISOP
         kappa_thic_type,   &   ! choice of KAPPA_THIC
         kappa_freq,        &   ! frequency of KAPPA computations
         slope_control          ! choice for slope control

      logical (log_kind) ::  &
         diag_gm_bolus          ! true for diagnostic bolus velocity computation 

!-----------------------------------------------------------------------
!
!     if use_const_ah_bkg_srfbl = .true., then the specified constant
!     value of ah_bkg_srfbl is used as the "maximum" background horizontal 
!     diffusivity within the surface boundary layer. Otherwise,
!     KAPPA_ISOP is utilized as this "maximum".
!
!-----------------------------------------------------------------------
  
      logical (log_kind) ::      &
         use_const_ah_bkg_srfbl, & ! see above 
         transition_layer_on       ! control for transition layer parameterization
                               
      real (r8) ::      &
         ah,            &       ! isopycnal diffusivity
         ah_bolus,      &       ! thickness (GM bolus) diffusivity
         ah_bkg_bottom, &       ! backgroud horizontal diffusivity at k = KMT
         ah_bkg_srfbl,  &       ! backgroud horizontal diffusivity within the
                                !  surface boundary layer
         slm_r,         &       ! max. slope allowed for redi diffusion
         slm_b                  ! max. slope allowed for bolus transport

!-----------------------------------------------------------------------
!
!     the following set of variables are used in Eden and Greatbatch 
!     (2008) KAPPA formulation. They are in the input namelist.
!
!-----------------------------------------------------------------------

      real (r8) ::      &
         const_eg,      &  ! tuning parameter (unitless)
         gamma_eg,      &  ! (> 0) effective upper limit for inverse eddy 
                           !  time scale (unitless)
         kappa_min_eg,  &  ! minimum KAPPA (cm^2/s)
         kappa_max_eg      ! maximum KAPPA (cm^2/s)

!-----------------------------------------------------------------------
!
!     transition layer type variables
!
!----------------------------------------------------------------------- 

      type tlt_info
        real (r8), dimension(nx_block,ny_block,max_blocks_clinic) :: &
           DIABATIC_DEPTH,  &   ! depth of the diabatic region at the
                                !  surface, i.e. mean mixed or boundary layer
                                !  depth
           THICKNESS,       &   ! transition layer thickness
           INTERIOR_DEPTH       ! depth at which the interior, adiabatic
                                !  region starts, i.e.
                                !   = TLT%DIABATIC_DEPTH + TLT%THICKNESS
        integer (int_kind), &
              dimension(nx_block,ny_block,max_blocks_clinic) :: &
           K_LEVEL,  &          ! k level at or below which the interior,
                                !  adiabatic region starts
           ZTW                  ! designates if the interior region
                                !  starts below depth zt or zw.
                                !  ( = 1 for zt, = 2 for zw )
      end type tlt_info

      type (tlt_info) :: &
         TLT                    ! transition layer thickness related fields 

!-----------------------------------------------------------------------
!
!     tavg ids for tavg diagnostics related to diffusivities and
!     isopycnal velocities. Zonal and meridional refer here to logical 
!     space only.
!
!-----------------------------------------------------------------------

      integer (int_kind) :: &
         tavg_UISOP,        &   ! zonal      isopycnal velocity
         tavg_VISOP,        &   ! meridional isopycnal velocity
         tavg_WISOP,        &   ! vertical   isopycnal velocity
         tavg_KAPPA_ISOP,   &   ! isopycnal  diffusion coefficient 
         tavg_KAPPA_THIC,   &   ! thickness  diffusion coefficient
         tavg_HOR_DIFF,     &   ! horizontal diffusion coefficient
         tavg_DIA_DEPTH,    &   ! depth of the diabatic region at the surface
         tavg_TLT,          &   ! transition layer thickness
         tavg_INT_DEPTH,    &   ! depth at which the interior region starts
         tavg_ADVT_ISOP,    &   ! vertically-integrated T eddy-induced
                                !  advection tendency
         tavg_ADVS_ISOP,    &   ! vertically-integrated S eddy-induced
                                !  advection tendency
         tavg_VNT_ISOP,     &   ! heat flux tendency in grid-y direction
                                !  due to eddy-induced velocity
         tavg_VNS_ISOP          ! salt flux tendency in grid-y direction
                                !  due to eddy-induced velocity

!-----------------------------------------------------------------------
!
!  timers
!
!-----------------------------------------------------------------------

   integer (int_kind) :: &
      timer_nloop         ! main n loop

!EOC
!***********************************************************************

      contains

!***********************************************************************
!BOP
! !IROUTINE: init_gm
! !INTERFACE:


      subroutine init_gm 1,67

! !DESCRIPTION:
!  Initializes various choices and allocates necessary space.
!  Also computes some time-independent arrays.
!
! !REVISION HISTORY:
!  same as module

!EOP
!BOC
!-----------------------------------------------------------------------
!
!     local variables
!
!-----------------------------------------------------------------------

   type (block) :: &
      this_block         ! block information for current block

   character (char_len) ::    &
      buoyancy_freq_filename, &! file name for the time-independent
                               !  buoyancy frequency squared
      buoyancy_freq_fmt,      &! format (bin or netcdf) of buoyancy file
      message                  ! string to hold error message

   type (datafile) :: &
      buoyancy_freq_data_file  ! data file descriptor for buoyancy freq data

   type (io_field_desc) :: &
      buoyancy_freq_data_in  ! io field descriptor for input buoyancy freq data

   type (io_dim) :: &
      i_dim, j_dim, &  ! dimension descriptors for horiz dims
      k_dim            ! dimension descriptor  for depth

!-----------------------------------------------------------------------
!
!     input namelist for setting various GM options
!
!-----------------------------------------------------------------------

   integer (int_kind) :: &
      nml_error,         &  ! error flag for namelist
      k,                 &  ! vertical level index
      iblock,            &  ! block index
      i, j                  ! lateral indices

   real (r8) ::          &
      kappa_depth_1,     &  ! parameters for variation of KAPPA 
      kappa_depth_2,     &  !  with depth used with the kappa_type_depth
      kappa_depth_scale     !  option

   character (char_len) :: &
      kappa_choice,        &  ! (generic) choice for KAPPA
      kappa_freq_choice,   &  ! frequency choice for KAPPA computation
      kappa_isop_choice,   &  ! choice for KAPPA_ISOP
      kappa_thic_choice,   &  ! choice for KAPPA_THIC
      slope_control_choice    ! choice for slope control

   namelist /hmix_gm_nml/ kappa_isop_choice,                     &
                          kappa_thic_choice,                     &
                          kappa_freq_choice,                     &
                          slope_control_choice,                  &
                          kappa_depth_1, kappa_depth_2,          &
                          kappa_depth_scale, ah, ah_bolus,       &
                          use_const_ah_bkg_srfbl, ah_bkg_srfbl,  &
                          ah_bkg_bottom,                         &
                          slm_r, slm_b, diag_gm_bolus,           &
                          transition_layer_on, read_n2_data,     &
                          buoyancy_freq_filename,                &
                          buoyancy_freq_fmt,                     &
                          const_eg, gamma_eg,                    &
                          kappa_min_eg, kappa_max_eg

!-----------------------------------------------------------------------
!
!     read input namelist for additional GM options
!
!     DEFAULT SETUP: 
!     KAPPA_ISOP      : constant (= ah)
!     KAPPA_THIC      : constant (= ah_bolus)
!     kappa_freq      : never
!     slope control   : method by DM95 with replacing tanh by polynomial
!                        (= slope_control_notanh)
!
!     variation of kappa with depth used with kappa_type_depth is
!       kappa_depth_1 + kappa_depth_2*exp(-z/kappa_depth_scale)
!
!      with kappa_depth_1 = 1, kappa_depth_2 = 0, and 
!      kappa_depth_scale = 150000 cm, i.e. no depth variation
!
!     ah_bolus        : thickness diffusion coefficient (= 0.8e07 cm^2/s)
!     ah_bkg_bottom   : background horizontal diffusion at k=KMT (= 0)
!     use_const_ah_bkg_srfbl : use ah_bkg_srfbl value
!     ah_bkg_srfbl    : background horizontal diffusion within the
!                        surface boundary layer (= 0.8e07 cm^2/s)
!     slm_r           : max. slope allowed for isopycnal (redi) diffusion (= 0.3)
!     slm_b           : max. slope allowed for thickness (bolus) diffusion (= 0.3)
!     diag_gm_bolus   : .true.
!     transition_layer_on: .false.
!     read_n2_data    : .false.
!     const_eg        : 1.
!     gamma_eg        : 300.
!     kappa_min_eg    : 0.35e07 cm^2/s
!     kappa_max_eg    : 5.00e07 cm^2/s
!
!-----------------------------------------------------------------------

!-----------------------------------------------------------------------
!
!     register init_gm
!
!-----------------------------------------------------------------------

   call register_string('init_gm')
 
   kappa_isop_type = kappa_type_const
   kappa_thic_type = kappa_type_const
   kappa_freq    = kappa_freq_never
   slope_control = slope_control_notanh
   kappa_depth_1 = c1
   kappa_depth_2 = c0
   kappa_depth_scale = 150000.0_r8
   ah            = 0.8e7_r8
   ah_bolus      = 0.8e7_r8
   ah_bkg_bottom = c0
   ah_bkg_srfbl  = 0.8e7_r8
   slm_r = 0.3_r8
   slm_b = 0.3_r8
   diag_gm_bolus          = .true.
   use_const_ah_bkg_srfbl = .true.
   transition_layer_on    = .false.
   read_n2_data           = .false.
   buoyancy_freq_filename = 'unknown-buoyancy'
   buoyancy_freq_fmt      = 'nc'
   const_eg               = c1 
   gamma_eg               = 300.0_r8 
   kappa_min_eg           = 0.35e7_r8
   kappa_max_eg           = 5.0e7_r8

   if (my_task == master_task) then
     open (nml_in, file=nml_filename, status='old',iostat=nml_error)
     if (nml_error /= 0) then
       nml_error = -1
     else
       nml_error =  1
     endif
     do while (nml_error > 0)
       read(nml_in, nml=hmix_gm_nml,iostat=nml_error)
     end do
     if (nml_error == 0) close(nml_in)
   endif

   call broadcast_scalar(nml_error, master_task)
   if (nml_error /= 0) then
     call exit_POP(sigAbort,'ERROR reading hmix_gm_nml')
   endif

   if (my_task == master_task) then

     write(stdout,*) ' '
     write(stdout,*) ' Document Namelist Parameters:'
     write(stdout,*) ' ============================ '
     write(stdout,*) ' '
     write(stdout,  hmix_gm_nml)
     write(stdout,*) ' '

     write(stdout,*) '  Gent-McWilliams options:'
     write(stdout,*) '    kappa_isop choice is ',  &
                     trim(kappa_isop_choice)
     write(stdout,*) '    kappa_thic choice is ',  &
                     trim(kappa_thic_choice)
     write(stdout,*) '    kappa computation frequency choice is ',  &
                     trim(kappa_freq_choice)
     write(stdout,*) '    slope control choice is ',  &
                                    trim(slope_control_choice)
     write(stdout,'(a28,1pe13.6)') ' isopycnal diffusion      = ',  &
                                     ah
     write(stdout,'(a28,1pe13.6)') ' thickness diffusion      = ',  &
                                     ah_bolus
     write(stdout,'(a28,1pe13.6)') ' backgroud diff. (bottom) = ',  &
                                     ah_bkg_bottom
     write(stdout,'(a28,1pe13.6)') ' backgroud diff. (srfbl)  = ',  &
                                     ah_bkg_srfbl
     write(stdout,'(a28,1pe13.6)') ' max. slope for redi      = ',  &
                                     slm_r
     write(stdout,'(a28,1pe13.6)') ' max. slope for bolus     = ',  &
                                     slm_b
     if ( diag_gm_bolus ) then
       write(stdout,'(a47)')  &
           '    diagnostic bolus velocity computation is on'
     endif

     if ( use_const_ah_bkg_srfbl ) then
       write(stdout,1001)
     else
       write(stdout,1002)
     endif
 1001   format(/,' Maximum horizontal background diffusion ', &
                 'coefficient', /,                            &
           '  within the boundary layer is constant at ah_bkg_srfbl.')
 1002   format(/,' Maximum horizontal background diffusion ', &
                 'coefficient', /,                            &
           '  within the boundary layer depends on KAPPA_ISOP.')

     if ( transition_layer_on ) then
       write(stdout,'(a33)') '  transition layer scheme is on. '
     endif

     select case (kappa_isop_choice(1:4))
     case ('cons')
       kappa_isop_type = kappa_type_const
     case ('dept')
       kappa_isop_type = kappa_type_depth
     case ('vmhs')
       kappa_isop_type = kappa_type_vmhs
     case ('hdgr')
       kappa_isop_type = kappa_type_hdgr
     case ('drad')
       kappa_isop_type = kappa_type_dradius 
     case ('bfre')
       kappa_isop_type = kappa_type_bfreq 
     case ('bfvm')
       kappa_isop_type = kappa_type_bfreq_vmhs
     case ('bfhd')
       kappa_isop_type = kappa_type_bfreq_hdgr
     case ('bfdr')
       kappa_isop_type = kappa_type_bfreq_dradius
     case ('edgr')
       kappa_isop_type = kappa_type_eg
     case default
       kappa_isop_type = -1000
     end select

     select case (kappa_thic_choice(1:4))
     case ('cons')
       kappa_thic_type = kappa_type_const
     case ('dept')
       kappa_thic_type = kappa_type_depth
     case ('vmhs')
       kappa_thic_type = kappa_type_vmhs
     case ('hdgr')
       kappa_thic_type = kappa_type_hdgr
     case ('drad')
       kappa_thic_type = kappa_type_dradius
     case ('bfre')
       kappa_thic_type = kappa_type_bfreq
     case ('bfvm')
       kappa_thic_type = kappa_type_bfreq_vmhs
     case ('bfhd')
       kappa_thic_type = kappa_type_bfreq_hdgr
     case ('bfdr')
       kappa_thic_type = kappa_type_bfreq_dradius
     case ('edgr')
       kappa_thic_type = kappa_type_eg
     case default
       kappa_thic_type = -1000
     end select

     select case (kappa_freq_choice(1:3))
     case ('nev')
       kappa_freq = kappa_freq_never
     case ('eve')
       kappa_freq = kappa_freq_every_time_step
     case ('onc')
       kappa_freq = kappa_freq_once_a_day
     case default
       kappa_freq = -1000
     end select

     select case (slope_control_choice(1:4))
     case ('tanh')
       slope_control = slope_control_tanh
     case ('nota')
       slope_control = slope_control_notanh
     case ('clip')
       slope_control = slope_control_clip
     case ('Gerd')
       slope_control = slope_control_Gerd
     case default
       slope_control = -1000
     end select

     if ( kappa_isop_type == kappa_type_bfreq          .or.  &
          kappa_isop_type == kappa_type_bfreq_vmhs     .or.  &
          kappa_isop_type == kappa_type_bfreq_hdgr     .or.  &
          kappa_isop_type == kappa_type_bfreq_dradius  .or.  &
          kappa_thic_type == kappa_type_bfreq          .or.  &
          kappa_thic_type == kappa_type_bfreq_vmhs     .or.  &
          kappa_thic_type == kappa_type_bfreq_hdgr     .or.  &
          kappa_thic_type == kappa_type_bfreq_dradius ) then
       if ( read_n2_data ) then
         write(stdout,'(a32)') ' using climatological N^2 data. '
       else
         write(stdout,'(a34)') ' using model data to compute N^2. '
       endif
      endif

     if ( kappa_isop_type == kappa_type_depth  .or.  &
          kappa_thic_type == kappa_type_depth ) then

       if ( kappa_isop_type == kappa_type_depth )  &
         write(stdout,'(a30)') ' KAPPA_ISOP varies with depth.'

       if ( kappa_thic_type == kappa_type_depth )  &
         write(stdout,'(a30)') ' KAPPA_THIC varies with depth.'

       write(stdout,'(a20,1pe13.6)') '    kappa_depth_1 = ',  &
                                          kappa_depth_1
       write(stdout,'(a20,1pe13.6)') '    kappa_depth_2 = ',  &
                                          kappa_depth_2
       write(stdout,'(a24,1pe13.6)') '    kappa_depth_scale = ',  &
                                          kappa_depth_scale

     endif

     if ( kappa_isop_type == kappa_type_eg  .or.  &
          kappa_thic_type == kappa_type_eg ) then

       write(stdout,'(a16,1pe13.6)') '     const_eg = ',  &
                                           const_eg 
       write(stdout,'(a16,1pe13.6)') '     gamma_eg = ',  &
                                           gamma_eg
       write(stdout,'(a16,1pe13.6)') ' kappa_min_eg = ',  &
                                       kappa_min_eg
       write(stdout,'(a16,1pe13.6)') ' kappa_max_eg = ',  &
                                       kappa_max_eg

     endif

   endif

   call broadcast_scalar(kappa_isop_type,        master_task)
   call broadcast_scalar(kappa_thic_type,        master_task)
   call broadcast_scalar(kappa_freq,             master_task)
   call broadcast_scalar(slope_control,          master_task)
   call broadcast_scalar(kappa_depth_1,          master_task)
   call broadcast_scalar(kappa_depth_2,          master_task)
   call broadcast_scalar(kappa_depth_scale,      master_task)
   call broadcast_scalar(ah,                     master_task)
   call broadcast_scalar(ah_bolus,               master_task)
   call broadcast_scalar(ah_bkg_bottom,          master_task)
   call broadcast_scalar(ah_bkg_srfbl,           master_task)
   call broadcast_scalar(slm_r,                  master_task)
   call broadcast_scalar(slm_b,                  master_task)
   call broadcast_scalar(diag_gm_bolus,          master_task)
   call broadcast_scalar(use_const_ah_bkg_srfbl, master_task)
   call broadcast_scalar(transition_layer_on,    master_task)
   call broadcast_scalar(read_n2_data,           master_task)
   call broadcast_scalar(buoyancy_freq_filename, master_task)
   call broadcast_scalar(buoyancy_freq_fmt,      master_task)
   call broadcast_scalar(const_eg,               master_task)
   call broadcast_scalar(gamma_eg,               master_task)
   call broadcast_scalar(kappa_min_eg,           master_task)
   call broadcast_scalar(kappa_max_eg,           master_task)

!-----------------------------------------------------------------------
!
!  error checking
!
!-----------------------------------------------------------------------

   if ( kappa_isop_type == -1000 ) then
     call exit_POP(sigAbort,  &
                   'unknown type for KAPPA_ISOP in GM setup')
   endif
   if ( kappa_thic_type == -1000 ) then
    call exit_POP(sigAbort,  &
                  'unknown type for KAPPA_THIC in GM setup')
   endif
   if ( kappa_freq == -1000 ) then
     call exit_POP(sigAbort,                                       &
                  'unknown type for KAPPA computation frequency in GM setup')
   endif
   if ( slope_control == -1000 ) then
     call exit_POP(sigAbort,  &
                   'unknown slope control method in GM setup')
   endif

   if ( kappa_isop_type == kappa_type_depth  .and.      &
        ( kappa_thic_type /= kappa_type_const  .and.     &
          kappa_thic_type /= kappa_type_depth ) ) then   
     message = 'when kappa_isop_type is kappa_type_depth, kappa_thic_type '/&
           &/  'should be either kappa_type_const or kappa_type_depth.'
     call exit_POP(sigAbort, message)
   endif

   if ( kappa_thic_type == kappa_type_depth  .and.      &
        ( kappa_isop_type /= kappa_type_const  .and.     &
          kappa_isop_type /= kappa_type_depth ) ) then   
     message = 'when kappa_thic_type is kappa_type_depth, kappa_isop_type ' /&
            &/ 'should be either kappa_type_const or kappa_type_depth.'
     call exit_POP(sigAbort, message)
   endif

   if ( ( ( kappa_isop_type /= kappa_type_const   .and.     &
            kappa_isop_type /= kappa_type_depth ) .and.     &
          ( kappa_thic_type /= kappa_type_const   .and.     &
            kappa_thic_type /= kappa_type_depth  ) ) .and.  &
          ( kappa_isop_type /= kappa_thic_type ) ) then
     message = 'kappa_isop_type and kappa_thic_type should be the same ' /&
           &/  'if they are BOTH model fields dependent.'
     call exit_POP(sigAbort, message)
   endif

   if ( ( ( kappa_isop_type == kappa_type_vmhs           .and.     &
            kappa_thic_type == kappa_type_vmhs )          .or.     &
          ( kappa_isop_type == kappa_type_bfreq_vmhs     .and.     &
            kappa_thic_type == kappa_type_bfreq_vmhs )    .or.     &
          ( kappa_isop_type == kappa_type_dradius        .and.     &
            kappa_thic_type == kappa_type_dradius )       .or.     &
          ( kappa_isop_type == kappa_type_bfreq_dradius  .and.     &
            kappa_thic_type == kappa_type_bfreq_dradius ) ) .and.  &
         ah /= ah_bolus ) then
     message = 'ah and ah_bolus should be equal when vmhs or dradius '  /&
          &/ ' related dependencies are used.'
     call exit_POP(sigAbort, message)
   endif

   if ( ( kappa_isop_type == kappa_type_depth   .or.  &
          kappa_thic_type == kappa_type_depth ) .and. & 
        kappa_depth_2 == c0 ) then
     message = 'kappa_depth_2 should be non-zero if a time-independent '  /&
          &/   'depth variation is requested.'
     call exit_POP(sigAbort, message)
      endif

   if ( ( kappa_isop_type == kappa_type_vmhs         .or.   &
          kappa_thic_type == kappa_type_vmhs         .or.   &
          kappa_isop_type == kappa_type_bfreq_vmhs   .or.   &
          kappa_thic_type == kappa_type_bfreq_vmhs   .or.   &
          kappa_isop_type == kappa_type_hdgr         .or.   &
          kappa_thic_type == kappa_type_hdgr         .or.   &
          kappa_isop_type == kappa_type_bfreq_hdgr   .or.   &
          kappa_thic_type == kappa_type_bfreq_hdgr ) .and.  &
                    zt(km) <= 2.0e5_r8 ) then
     message = 'the max bottom depth should be > 2000.0 m' /&
           &/ ' when vmhs or hdgr dependency is chosen.'
     call exit_POP(sigAbort, message)
   endif

   if ( ( kappa_isop_type == kappa_type_eg    .or.  &
          kappa_thic_type == kappa_type_eg )  .and. &
          use_const_ah_bkg_srfbl ) then
     message = 'use_const_ah_bkg_srfbl should be false when ' /&
            &/ 'kappa_type_eg is used.'
     call exit_POP(sigAbort, message)
   endif

   if ( ( kappa_isop_type == kappa_type_vmhs           .or.    &
          kappa_thic_type == kappa_type_vmhs           .or.    &
          kappa_isop_type == kappa_type_hdgr           .or.    &
          kappa_thic_type == kappa_type_hdgr           .or.    &
          kappa_isop_type == kappa_type_dradius        .or.    &
          kappa_thic_type == kappa_type_dradius        .or.    &
          kappa_isop_type == kappa_type_bfreq_vmhs     .or.    &
          kappa_thic_type == kappa_type_bfreq_vmhs     .or.    &
          kappa_isop_type == kappa_type_bfreq_hdgr     .or.    &
          kappa_thic_type == kappa_type_bfreq_hdgr     .or.    &
          kappa_isop_type == kappa_type_bfreq_dradius  .or.    &
          kappa_thic_type == kappa_type_bfreq_dradius  .or.    &
          kappa_isop_type == kappa_type_eg             .or.    &
          kappa_thic_type == kappa_type_eg             .or.    &
          ( ( kappa_isop_type == kappa_type_bfreq  .or.        &
              kappa_thic_type == kappa_type_bfreq ) .and.      &
            .not. read_n2_data ) )                    .and.    &
          kappa_freq == kappa_freq_never ) then

     message = 'kappa_freq should not be set to never when model ' /&
            &/ 'fields dependent kappa types are chosen.'
     call exit_POP(sigAbort, message)
   endif

   if ( partial_bottom_cells ) then
     call exit_POP(sigAbort, &
       'hmix_gm currently incompatible with partial bottom cells')
   endif

   if (read_n2_data .and. trim(buoyancy_freq_filename) == 'unknown-buoyancy' ) then
     call exit_POP(sigAbort,  &
                   'Must define buoyancy_freq_filename if read_n2_data is .true.')
   endif

!-----------------------------------------------------------------------
!
!  allocate GM arrays
!
!-----------------------------------------------------------------------

    allocate (HYXW(nx_block,ny_block,nblocks_clinic),    &
             HXYS(nx_block,ny_block,nblocks_clinic),    &
             RBR (nx_block,ny_block,nblocks_clinic),    &
             BTP (nx_block,ny_block,nblocks_clinic),    &
             BL_DEPTH(nx_block,ny_block,nblocks_clinic))

    allocate (SF_SLX(nx_block,ny_block,2,2,km,nblocks_clinic),  &
             SF_SLY(nx_block,ny_block,2,2,km,nblocks_clinic))
    
    allocate (FZTOP(nx_block,ny_block,nt,nblocks_clinic))

    allocate (kappa_depth(km))

    allocate (KAPPA_ISOP(nx_block,ny_block,2,km,nblocks_clinic),  &
             KAPPA_THIC(nx_block,ny_block,2,km,nblocks_clinic),  &
             HOR_DIFF  (nx_block,ny_block,2,km,nblocks_clinic))

    allocate (KAPPA_LATERAL (nx_block,ny_block,nblocks_clinic),  &
             KAPPA_VERTICAL(nx_block,ny_block,km,nblocks_clinic))

    allocate (BUOY_FREQ_SQ(nx_block,ny_block,km,nblocks_clinic))

    allocate (VDC_GM(nx_block,ny_block,km,nblocks_clinic))

    allocate (compute_kappa(nblocks_clinic))

   HYXW     = c0
   HXYS     = c0
   RBR      = c0
   BTP      = c0
   BL_DEPTH = c0
   SF_SLX   = c0
   SF_SLY   = c0
   FZTOP    = c0
   VDC_GM   = c0

   if ( transition_layer_on ) then
     allocate (SLA_SAVE(nx_block,ny_block,2,km,nblocks_clinic))
     allocate (RB(nx_block,ny_block,nblocks_clinic))
     SLA_SAVE = c0
     RB = c0
   endif

!-----------------------------------------------------------------------
!
!  initialize various time-independent arrays
!
!-----------------------------------------------------------------------

   do k=1,km
     kappa_depth(k) = kappa_depth_1  &
                    + kappa_depth_2  &
                     *exp(-zt(k)/kappa_depth_scale)
   enddo

   do iblock = 1,nblocks_clinic

     this_block = get_block(blocks_clinic(iblock),iblock)

     KAPPA_LATERAL(:,:,iblock)    = ah
     KAPPA_VERTICAL(:,:,:,iblock) = c1

     KAPPA_ISOP(:,:,:,:,iblock) = ah
     KAPPA_THIC(:,:,:,:,iblock) = ah_bolus
     HOR_DIFF(:,:,:,:,iblock)   = ah

     if ( kappa_isop_type == kappa_type_depth  .or.  &
          kappa_thic_type == kappa_type_depth ) then

       do k=1,km 
         KAPPA_VERTICAL(:,:,k,iblock) = kappa_depth(k)
       enddo

     endif


     HYXW(:,:,iblock) = eoshift(HYX(:,:,iblock), dim=1, shift=-1)
     HXYS(:,:,iblock) = eoshift(HXY(:,:,iblock), dim=2, shift=-1)

!-----------------------------------------------------------------------
!  compute the Rossby radius which will be used to
!  contol KAPPA [Large et al (1997), JPO, 27,
!  pp 2418-2447]. Rossby radius = c/(2*omg*sin(latitude))
!  where c=200cm/s is the first baroclinic wave speed.
!  15km < Rossby radius < 100km
!-----------------------------------------------------------------------

     !*** Inverse of Rossby radius

     RBR(:,:,iblock) = abs(FCORT(:,:,iblock))  &
                       / 200.0_r8             ! |f|/Cg, Cg = 2 m/s = 200 cm/s
     RBR(:,:,iblock) = min(RBR(:,:,iblock),    &
                           c1/1.5e+6_r8)      ! Cg/|f| .ge. 15 km = 1.5e+6 cm
     RBR(:,:,iblock) = max(RBR(:,:,iblock),    &
                           1.e-7_r8)          ! Cg/|f| .le. 100 km = 1.e+7 cm

     if ( transition_layer_on ) then
       RB(:,:,iblock) = c1 / RBR(:,:,iblock)
     endif

     !*** beta at t-points

     call ugrid_to_tgrid(BTP(:,:,iblock),ULAT(:,:,iblock),iblock)
      
     BTP(:,:,iblock) = c2*omega*cos(BTP(:,:,iblock))/radius

   enddo

!-----------------------------------------------------------------------
!  HYXW, HXYS only needed in physical domain and should
!  be defined correctly there.  BTP invalid on south
!  and westernmost ghost cells, but not needed there
!  as long as number of ghost cells is >1
!-----------------------------------------------------------------------
 
!  call update_ghost_cells(HYXW, bndy_clinic, field_loc_t,     &
!                                             field_type_scalar)
!  call update_ghost_cells(HXYS, bndy_clinic, field_loc_t,     &
!                                             field_type_scalar)
!  call update_ghost_cells(BTP , bndy_clinic, field_loc_t,     &
!                                             field_type_scalar)

   BUOY_FREQ_SQ = c0

   if ( read_n2_data ) then

     buoyancy_freq_filename = '/home/bluesky/gokhan/buoyancy_freq.nc'

     buoyancy_freq_data_file = construct_file ( 'nc',         &
                          full_name=trim(buoyancy_freq_filename) )

     call data_set(buoyancy_freq_data_file, 'open_read')

     i_dim = construct_io_dim ( 'i', nx_global )
     j_dim = construct_io_dim ( 'j', ny_global )
     k_dim = construct_io_dim ( 'k', km )

     buoyancy_freq_data_in = construct_io_field                &
                         ('BUOYANCY_FREQUENCY',                &
                          dim1=i_dim, dim2=j_dim, dim3=k_dim,  &
                          field_loc = field_loc_center,        &
                          field_type = field_type_scalar,      &
                          d3d_array = BUOY_FREQ_SQ)

     call data_set (buoyancy_freq_data_file, 'define', &
                    buoyancy_freq_data_in)
     call data_set (buoyancy_freq_data_file, 'read',   &
                    buoyancy_freq_data_in)
     call data_set (buoyancy_freq_data_file, 'close')
     call destroy_io_field (buoyancy_freq_data_in)
     call destroy_file (buoyancy_freq_data_file)

     if (my_task == master_task) then
       write(stdout,blank_fmt)
       write(stdout,'(a43,a)')                                 &
               ' Buoyancy frequency climatology file read: ',  &
                              trim(buoyancy_freq_filename)
     endif

   endif

   compute_kappa = .false.

   if (slm_r /= slm_b) then
     diff_tapering = .true.
   else
     diff_tapering = .false.
   endif

   cancellation_occurs = .true.

   if ( ( kappa_isop_type /= kappa_thic_type )  .or.     &
       ( diff_tapering )  .or.                           &
       ( ( kappa_isop_type == kappa_type_const  .and.    &
           kappa_thic_type == kappa_type_const )  .and.  &
         ah /= ah_bolus )  .or.                          &
       ( ( kappa_isop_type == kappa_type_depth  .and.    &
           kappa_thic_type == kappa_type_depth )  .and.  &
         ah /= ah_bolus )  .or.                          &
       ( ( kappa_isop_type == kappa_type_bfreq  .and.    &
           kappa_thic_type == kappa_type_bfreq )  .and.  &
         ah /= ah_bolus ) )                              &
    cancellation_occurs = .false. 

    !*** for transition layer cases, the following will always be true!!

   if ( transition_layer_on )  cancellation_occurs = .false.

!-----------------------------------------------------------------------
!
!  initialize topography mask used with kappa_type_eg. This mask eliminates
!  excessively large values of KAPPA near sloping topography.
!
!-----------------------------------------------------------------------

   if ( kappa_isop_type == kappa_type_eg  .or.  &
        kappa_thic_type == kappa_type_eg ) then 

     allocate (SIGMA_TOPO_MASK(nx_block,ny_block,km,nblocks_clinic))

     do iblock=1,nblocks_clinic

       do k=1,km
         where ( k < KMT(:,:,iblock) ) 
           SIGMA_TOPO_MASK(:,:,k,iblock) = c1
         elsewhere
           SIGMA_TOPO_MASK(:,:,k,iblock) = c0
         endwhere
       enddo

       do k=1,km-1
         do j=2,ny_block-1
           do i=2,nx_block-1 
             if ( k < KMT(i,j,iblock) ) then
               if ( k == KMT(i-1,j+1,iblock)  .or.  &
                    k == KMT(i  ,j+1,iblock)  .or.  &
                    k == KMT(i+1,j+1,iblock)  .or.  &
                    k == KMT(i-1,j  ,iblock)  .or.  &
                    k == KMT(i+1,j  ,iblock)  .or.  &
                    k == KMT(i-1,j-1,iblock)  .or.  &
                    k == KMT(i  ,j-1,iblock)  .or.  &
                    k == KMT(i+1,j-1,iblock) )      &
                 SIGMA_TOPO_MASK(i,j,k,iblock) = c0 
             endif
           enddo
         enddo
       enddo

     enddo

   endif

!-----------------------------------------------------------------------
!
!  define tavg fields related to diffusivities 
!
!-----------------------------------------------------------------------

   call define_tavg_field (tavg_KAPPA_ISOP, 'KAPPA_ISOP', 3,     &
                   long_name='Isopycnal diffusion coefficient',  &
                   units='cm^2/s', grid_loc='3111',              &
                   coordinates='TLONG TLAT z_t time')

   call define_tavg_field (tavg_KAPPA_THIC, 'KAPPA_THIC', 3,     &
                   long_name='Thickness diffusion coefficient',  &
                   units='cm^2/s', grid_loc='3111',              &
                   coordinates='TLONG TLAT z_t time')

   call define_tavg_field (tavg_HOR_DIFF, 'HOR_DIFF', 3,         &
                   long_name='Horizontal diffusion coefficient', &
                   units='cm^2/s', grid_loc='3111',              &
                   coordinates='TLONG TLAT z_t time')

!-----------------------------------------------------------------------
!
!  define tavg fields related to the near-surface eddy flux
!  parameterization (i.e. transition layer is on). 
!
!-----------------------------------------------------------------------

   if ( transition_layer_on ) then

     call define_tavg_field (tavg_DIA_DEPTH, 'DIA_DEPTH', 2,       &
         long_name='Depth of the Diabatic Region at the Surface',  &
                     units='cm', grid_loc='2110',                  &
                     coordinates='TLONG TLAT time')

     call define_tavg_field (tavg_TLT, 'TLT', 2,                   &
         long_name='Transition Layer Thickness',                   &
                     units='cm', grid_loc='2110',                  &
                     coordinates='TLONG TLAT time')

     call define_tavg_field (tavg_INT_DEPTH, 'INT_DEPTH', 2,       &
         long_name='Depth at which the Interior Region Starts',    &
                     units='cm', grid_loc='2110',                  &
                     coordinates='TLONG TLAT time')

   endif

!-----------------------------------------------------------------------
!
!  allocate and initialize bolus velocity arrays if requested
!  define tavg fields related to bolus velocity
!
!-----------------------------------------------------------------------

   if ( diag_gm_bolus ) then

     call register_string ('diag_gm_bolus')

     allocate(WTOP_ISOP(nx_block,ny_block,nblocks_clinic), &
              WBOT_ISOP(nx_block,ny_block,nblocks_clinic), &
                    UIT(nx_block,ny_block,nblocks_clinic), &
                    VIT(nx_block,ny_block,nblocks_clinic))

     WTOP_ISOP = c0
     WBOT_ISOP = c0
     UIT       = c0
     VIT       = c0

     call define_tavg_field (tavg_UISOP, 'UISOP', 3,                &
      long_name='Bolus Velocity in grid-x direction (diagnostic)',  &
                   units='cm/s', grid_loc='3211',                   &
                   coordinates='ULONG TLAT z_t time')

     call define_tavg_field (tavg_VISOP, 'VISOP', 3,                &
      long_name='Bolus Velocity in grid-y direction (diagnostic)',  &
                   units='cm/s', grid_loc='3121',                   &
                   coordinates='TLONG ULAT z_t time')

     call define_tavg_field (tavg_WISOP, 'WISOP', 3,                &
      long_name='Vertical Bolus Velocity (diagnostic)',             &
                   units='cm/s', grid_loc='3112',                   &
                   coordinates='TLONG TLAT z_w time')

     call define_tavg_field (tavg_ADVT_ISOP, 'ADVT_ISOP', 2,                            &
      long_name='Vertically-Integrated T Eddy-Induced Advection Tendency (diagnostic)', &
                   units='cm degC/s', grid_loc='2110',                                  &
                   coordinates='TLONG TLAT time')

     call define_tavg_field (tavg_ADVS_ISOP, 'ADVS_ISOP', 2,                            &
      long_name='Vertically-Integrated S Eddy-Induced Advection Tendency (diagnostic)', &
                   scale_factor=1000.0_rtavg,                                           &
                   units='cm gram/kilogram/s', grid_loc='2110',                         &
                   coordinates='TLONG TLAT time')

     call define_tavg_field (tavg_VNT_ISOP, 'VNT_ISOP', 3,                               &
      long_name='Heat Flux Tendency in grid-y Dir due to Eddy-Induced Vel (diagnostic)', &
                   units='degC/s', grid_loc='3121',                                      &
                   coordinates='TLONG ULAT z_t time')

     call define_tavg_field (tavg_VNS_ISOP, 'VNS_ISOP', 3,                               &
      long_name='Salt Flux Tendency in grid-y Dir due to Eddy-Induced Vel (diagnostic)', &
                   scale_factor=1000.0_rtavg,                                            &
                   units='gram/kilogram/s', grid_loc='3121',                             &
                   coordinates='TLONG ULAT z_t time')

   endif

      call get_timer(timer_nloop,'HMIX_TRACER_GM_NLOOP', &
                                  nblocks_clinic, distrb_clinic%nprocs)


!-----------------------------------------------------------------------
!EOC

   end subroutine init_gm

!***********************************************************************
!BOP
! !IROUTINE: hdifft_gm
! !INTERFACE:


      subroutine hdifft_gm (k, GTK, TMIX, UMIX, VMIX, tavg_HDIFE_TRACER, & 1,63
                            tavg_HDIFN_TRACER, tavg_HDIFB_TRACER, this_block)

! !DESCRIPTION:
!  Gent-McWilliams eddy transport parameterization
!  and isopycnal diffusion.
!
!  This routine must be called successively with k = 1,2,3,...
!
! !REVISION HISTORY:
!  same as module

! !INPUT PARAMETERS:

      integer (int_kind), intent(in) :: k  ! depth level index

      real (r8), dimension(nx_block,ny_block,km,nt), intent(in) :: &
         TMIX                  ! tracers at all vertical levels
                               !   at mixing time level

      real (r8), dimension(nx_block,ny_block,km), intent(in) :: &
         UMIX, VMIX            ! U,V  at all vertical levels
                               !   at mixing time level

      integer (int_kind), dimension(nt), intent(in) :: &
         tavg_HDIFE_TRACER, &! tavg id for east face diffusive flux of tracer
         tavg_HDIFN_TRACER, &! tavg id for north face diffusive flux of tracer
         tavg_HDIFB_TRACER   ! tavg id for bottom face diffusive flux of tracer

      type (block), intent(in) :: &
         this_block            ! block info for this sub block

! !OUTPUT PARAMETERS:

      real (r8), dimension(nx_block,ny_block,nt), intent(out) :: &
         GTK     ! diffusion+bolus advection for nth tracer at level k

!EOP
!BOC
!-----------------------------------------------------------------------
!
!     local variables
!
!-----------------------------------------------------------------------

      integer (int_kind), parameter :: &
         ieast  = 1, iwest  = 2,       &
         jnorth = 1, jsouth = 2

      integer (int_kind) :: &
         i,j,n,kk,          &! dummy loop counters
         kid,ktmp,          &! array indices
         kk_sub, kp1,       & 
         bid,               &! local block address for this sub block
         tavg_stream         ! temporary stream id

      real (r8) :: &
         fz, dz_bottom, factor

      real (r8), dimension(nx_block,ny_block) :: &
         CX, CY,                  &
         RZ,                      &! Dz(rho)
         SLA,                     &! absolute value of slope
         WORK1, WORK2,            &! local work space
         WORK3, WORK4,            &! local work space
         KMASK,                   &! ocean mask
         TAPER1, TAPER2, TAPER3,  &! tapering factors
         UIB, VIB,                &! work arrays for isopycnal mixing velocities
         U_ISOP, V_ISOP            ! horizontal components of isopycnal velocities

      real (r8), dimension(nx_block,ny_block,nt) :: &
         FX, FY                     ! fluxes across east, north faces

      real (r8), dimension(2) :: &
         reference_depth

!-----------------------------------------------------------------------
!
!     initialize various quantities
!
!-----------------------------------------------------------------------

      bid = this_block%local_id

      U_ISOP = c0
      V_ISOP = c0
      WORK1  = c0
      WORK2  = c0
      WORK3  = c0
      WORK4  = c0

      if ( .not. implicit_vertical_mix )  &
        call exit_POP (sigAbort, &
         'implicit vertical mixing must be used with GM horiz mixing')

      if ( k == 1 ) then

        if ( diag_gm_bolus ) then
          UIB = c0
          VIB = c0
          UIT(:,:,bid) = c0
          VIT(:,:,bid) = c0
          WBOT_ISOP(:,:,bid) = c0
        endif

        HOR_DIFF(:,:,ktp,k,bid) = ah_bkg_srfbl

        BL_DEPTH(:,:,bid) = zw(k)
        if ( vmix_itype == vmix_type_kpp )  &
                    BL_DEPTH(:,:,bid) = KPP_HBLT(:,:,bid)

      endif

      if (diag_gm_bolus)  WTOP_ISOP(:,:,bid) = WBOT_ISOP(:,:,bid)

      CX = merge(HYX(:,:,bid)*p25, c0, (k <= KMT (:,:,bid))   &
                                 .and. (k <= KMTE(:,:,bid)))
      CY = merge(HXY(:,:,bid)*p25, c0, (k <= KMT (:,:,bid))   &
                                 .and. (k <= KMTN(:,:,bid)))

      if ( k == 1 ) then

        if ( transition_layer_on ) then

          if ( vmix_itype == vmix_type_kpp ) then

            call smooth_hblt ( .false., .true., bid,  &
                               SMOOTH_OUT=TLT%DIABATIC_DEPTH(:,:,bid) )
          else
            TLT%DIABATIC_DEPTH(:,:,bid) = zw(k)
          endif

          do kk=1,km
            do kk_sub = ktp,kbt
              kid = kk + kk_sub - 2
              SLA_SAVE(:,:,kk_sub,kk,bid) = dzw(kid)*sqrt(p5*(       &
                     (SLX(:,:,1,kk_sub,kk,bid)**2                    &
                    + SLX(:,:,2,kk_sub,kk,bid)**2)/DXT(:,:,bid)**2   &
                   + (SLY(:,:,1,kk_sub,kk,bid)**2                    &
                    + SLY(:,:,2,kk_sub,kk,bid)**2)/DYT(:,:,bid)**2)) &
                   + eps
            enddo
          enddo

          call transition_layer ( this_block )

        endif

	

!-----------------------------------------------------------------------
!
!     compute isopycnal and thickness diffusion coefficients if
!     they depend on the model fields
!
!-----------------------------------------------------------------------
        
	if ( ( kappa_isop_type == kappa_type_vmhs           .or.    &
               kappa_thic_type == kappa_type_vmhs           .or.    &
               kappa_isop_type == kappa_type_hdgr           .or.    &
               kappa_thic_type == kappa_type_hdgr           .or.    &
               kappa_isop_type == kappa_type_dradius        .or.    &
               kappa_thic_type == kappa_type_dradius        .or.    &
               kappa_isop_type == kappa_type_bfreq          .or.    &
               kappa_thic_type == kappa_type_bfreq          .or.    &
               kappa_isop_type == kappa_type_bfreq_vmhs     .or.    &
               kappa_thic_type == kappa_type_bfreq_vmhs     .or.    &
               kappa_isop_type == kappa_type_bfreq_hdgr     .or.    &
               kappa_thic_type == kappa_type_bfreq_hdgr     .or.    &
               kappa_isop_type == kappa_type_bfreq_dradius  .or.    &
               kappa_thic_type == kappa_type_bfreq_dradius  .or.    &
               kappa_isop_type == kappa_type_eg             .or.    &
               kappa_thic_type == kappa_type_eg )            .and.  &
           ( ( kappa_freq == kappa_freq_every_time_step )           &
        .or. ( kappa_freq == kappa_freq_once_a_day .and. eod_last ) &
        .or. ( nsteps_total == 1 ) ) )  compute_kappa(bid) = .true.

        if ( compute_kappa(bid) ) then

          if ( kappa_isop_type == kappa_type_vmhs        .or.  &
               kappa_thic_type == kappa_type_vmhs        .or.  &
               kappa_isop_type == kappa_type_bfreq_vmhs  .or.  & 
               kappa_thic_type == kappa_type_bfreq_vmhs ) then

            if ( nsteps_total == 1 ) then
              KAPPA_LATERAL(:,:,bid) = ah
              if ( kappa_isop_type == kappa_type_const )  &
                KAPPA_LATERAL(:,:,bid) = ah_bolus
            else
              call kappa_lon_lat_vmhs (TMIX, UMIX, VMIX, this_block)
            endif

          endif

          if ( kappa_isop_type == kappa_type_hdgr        .or.  &
               kappa_thic_type == kappa_type_hdgr        .or.  &
               kappa_isop_type == kappa_type_bfreq_hdgr  .or.  &
               kappa_thic_type == kappa_type_bfreq_hdgr )      &
            call kappa_lon_lat_hdgr (TMIX, this_block)

          if ( kappa_isop_type == kappa_type_dradius        .or.  &
               kappa_thic_type == kappa_type_dradius        .or.  &
               kappa_isop_type == kappa_type_bfreq_dradius  .or.  &
               kappa_thic_type == kappa_type_bfreq_dradius )      &
            call kappa_lon_lat_dradius (this_block)

          if ( kappa_isop_type == kappa_type_bfreq          .or.  &
               kappa_thic_type == kappa_type_bfreq          .or.  &
               kappa_isop_type == kappa_type_bfreq_vmhs     .or.  &
               kappa_thic_type == kappa_type_bfreq_vmhs     .or.  &
               kappa_isop_type == kappa_type_bfreq_hdgr     .or.  &
               kappa_thic_type == kappa_type_bfreq_hdgr     .or.  &
               kappa_isop_type == kappa_type_bfreq_dradius  .or.  &
               kappa_thic_type == kappa_type_bfreq_dradius )      &
            call buoyancy_frequency_dependent_profile (TMIX, this_block)

          if ( kappa_isop_type == kappa_type_eg  .or.  &
               kappa_thic_type == kappa_type_eg ) &
            call kappa_eg (TMIX, UMIX, VMIX, this_block) 

          compute_kappa(bid) = .false.

        endif  ! end of ( compute_kappa ) if statement


!-----------------------------------------------------------------------
!
!     reinitialize the diffusivity coefficients 
!
!-----------------------------------------------------------------------
	
        if ( kappa_isop_type == kappa_type_const ) then
          KAPPA_ISOP(:,:,:,:,bid) = ah
        elseif ( kappa_isop_type == kappa_type_eg ) then
          do kk_sub=ktp,kbt
            do kk=1,km
              KAPPA_ISOP(:,:,kk_sub,kk,bid) = KAPPA_VERTICAL(:,:,kk,bid)
            enddo
          enddo
        else
          do kk_sub=ktp,kbt
            do kk=1,km
              KAPPA_ISOP(:,:,kk_sub,kk,bid) =  KAPPA_LATERAL(:,:,bid)  &
                                         * KAPPA_VERTICAL(:,:,kk,bid)
            enddo
          enddo
        endif

        if ( .not. use_const_ah_bkg_srfbl )  &
          HOR_DIFF(:,:,ktp,k,bid) = KAPPA_ISOP(:,:,ktp,k,bid) 

        if ( kappa_thic_type == kappa_type_const ) then
          KAPPA_THIC(:,:,:,:,bid) = ah_bolus
        else if ( kappa_thic_type == kappa_type_depth  .or.  &
                  kappa_thic_type == kappa_type_bfreq ) then
          do kk_sub=ktp,kbt
            do kk=1,km
              KAPPA_THIC(:,:,kk_sub,kk,bid) =  ah_bolus  &
                                        * KAPPA_VERTICAL(:,:,kk,bid)
            enddo
          enddo 
        else if ( kappa_thic_type == kappa_type_eg ) then
          KAPPA_THIC(:,:,:,:,bid) = KAPPA_ISOP(:,:,:,:,bid)
        else
          do kk_sub=ktp,kbt
            do kk=1,km
              KAPPA_THIC(:,:,kk_sub,kk,bid) = KAPPA_LATERAL(:,:,bid)  &
                                        * KAPPA_VERTICAL(:,:,kk,bid)
            enddo
          enddo
        endif


!-----------------------------------------------------------------------
!
!     control slope of isopycnal surfaces or KAPPA
!
!-----------------------------------------------------------------------
	
        do kk=1,km

          kp1 = min(kk+1,km)
          reference_depth(ktp) = zt(kp1)
          reference_depth(kbt) = zw(kp1)
          if ( kk == km )  reference_depth(ktp) = zw(kp1)

          do kk_sub = ktp,kbt 

            kid = kk + kk_sub - 2

!-----------------------------------------------------------------------
!
!     control KAPPA to reduce the isopycnal mixing near the
!     ocean surface Large et al (1997), JPO, 27, pp 2418-2447.
!     WORK1 = ratio between the depth of water parcel and
!     the vertical displacement of isopycnal surfaces
!     where the vertical displacement =
!     Rossby radius * slope of isopycnal surfaces
!
!-----------------------------------------------------------------------

            if ( transition_layer_on ) then
              SLA = SLA_SAVE(:,:,kk_sub,kk,bid)
            else
              SLA = dzw(kid)*sqrt(p5*(                               &
                     (SLX(:,:,1,kk_sub,kk,bid)**2                    & 
                    + SLX(:,:,2,kk_sub,kk,bid)**2)/DXT(:,:,bid)**2   &
                   + (SLY(:,:,1,kk_sub,kk,bid)**2                    &
                    + SLY(:,:,2,kk_sub,kk,bid)**2)/DYT(:,:,bid)**2)) &
                   + eps
            endif

            TAPER1 = c1 
            if ( .not. transition_layer_on ) then

              if ( kk == 1 ) then
                dz_bottom = c0
              else
                dz_bottom = zt(kk-1)
              endif

              if (slope_control == slope_control_tanh) then

                WORK1 = min(c1,zt(kk)*RBR(:,:,bid)/SLA)
                TAPER1 = p5*(c1+sin(pi*(WORK1-p5)))

!     use the Rossby deformation radius tapering
!     only within the boundary layer

                TAPER1 = merge(TAPER1, c1,  &
                               dz_bottom <= BL_DEPTH(:,:,bid))

              else

!     sine function is replaced by
!     function = 4.*x*(1.-abs(x)) for |x|<0.5

                WORK1 = min(c1,zt(kk)*RBR(:,:,bid)/SLA)
                TAPER1 = (p5+c2*(WORK1-p5)*(c1-abs(WORK1-p5)))

                TAPER1 = merge(TAPER1, c1,  &
                               dz_bottom <= BL_DEPTH(:,:,bid))

              endif

            endif

!-----------------------------------------------------------------------
!
!     control KAPPA for numerical stability
!
!-----------------------------------------------------------------------
!-----------------------------------------------------------------------
!
!     methods to control slope
!
!-----------------------------------------------------------------------

            TAPER2 = c1 
            TAPER3 = c1 

            select case (slope_control)
            case (slope_control_tanh)

!     method by Danabasoglu & Mcwilliams (1995)

              TAPER2 = merge(p5*  &
                 (c1-tanh(c10*SLA/slm_r-c4)), c0, SLA < slm_r)

              if ( diff_tapering ) then
                TAPER3 = merge(p5*  &
                 (c1-tanh(c10*SLA/slm_b-c4)), c0, SLA < slm_b)
              else
                TAPER3 = TAPER2
              endif

            case (slope_control_notanh)

!     similar to DM95 except replacing tanh by
!     function = x*(1.-0.25*abs(x)) for |x|<2
!              = sign(x)            for |x|>2
!     (faster than DM95)

              do j=1,ny_block
                do i=1,nx_block
                  if (SLA(i,j) > 0.2_r8*slm_r .and. &
                      SLA(i,j) < 0.6_r8*slm_r) then
                    TAPER2(i,j) = &
                       p5*(c1-(2.5_r8*SLA(i,j)/slm_r-c1)*  &
                          (c4-abs(c10*SLA(i,j)/slm_r-c4)))
                  else if (SLA(i,j) >= 0.6_r8*slm_r) then
                    TAPER2(i,j) = c0
                  endif
                enddo
              enddo

              if ( diff_tapering ) then
                do j=1,ny_block
                  do i=1,nx_block
                    if (SLA(i,j) > 0.2_r8*slm_b .and. &
                        SLA(i,j) < 0.6_r8*slm_b) then
                      TAPER3(i,j) = &
                         p5*(c1-(2.5_r8*SLA(i,j)/slm_b-c1)* &
                            (c4-abs(c10*SLA(i,j)/slm_b-c4)))
                    else if (SLA(i,j) >= 0.6_r8*slm_b) then
                      TAPER3(i,j) = c0
                    endif
                  end do
                end do
              else
                TAPER3 = TAPER2
              endif

            case (slope_control_clip)

!     slope clipping

              do n=1,2
                do j=1,ny_block
                  do i=1,nx_block
                    if (abs(SLX(i,j,n,kk_sub,kk,bid)  &
                          * dzw(kid) / HUS(i,j,bid)) > slm_r) then
                      SLX(i,j,n,kk_sub,kk,bid) =             &
                                  sign(slm_r * HUS(i,j,bid)  &
                                     * dzwr(kid),            &
                                  SLX(i,j,n,kk_sub,kk,bid))
                    endif
                  enddo
                enddo
              enddo

              do n=1,2
                do j=1,ny_block
                  do i=1,nx_block
                    if (abs(SLY(i,j,n,kk_sub,kk,bid)  &
                          * dzw(kid) / HUW(i,j,bid)) > slm_r) then  
                      SLY(i,j,n,kk_sub,kk,bid) =             &
                                  sign(slm_r * HUW(i,j,bid)  &
                                     * dzwr(kid),            &
                                  SLY(i,j,n,kk_sub,kk,bid))
                    endif
                  enddo
                enddo
              enddo

            case (slope_control_Gerd)

!     method by Gerdes et al (1991)

              do j=1,ny_block
                do i=1,nx_block
                  if (SLA(i,j) > slm_r)  &
                    TAPER2(i,j) = (slm_r/SLA(i,j))**2
                enddo
              enddo

              if (diff_tapering) then
                do j=1,ny_block
                  do i=1,nx_block
                    if (SLA(i,j) > slm_b)  &
                      TAPER3(i,j) = (slm_b/SLA(i,j))**2
                  enddo
                enddo
              else
                TAPER3 = TAPER2
              endif

            end select

            if ( transition_layer_on ) then
              TAPER2 = merge(c1, TAPER2, reference_depth(kk_sub) &
                                         <= TLT%DIABATIC_DEPTH(:,:,bid))
              TAPER3 = merge(c1, TAPER3, reference_depth(kk_sub) &
                                         <= TLT%DIABATIC_DEPTH(:,:,bid))
            endif

            if ( transition_layer_on  .and.  use_const_ah_bkg_srfbl ) then

              HOR_DIFF(:,:,kk_sub,kk,bid) = ah_bkg_srfbl

            else if ( transition_layer_on .and.               &
                    ( .not. use_const_ah_bkg_srfbl      .or.  &
                      kappa_isop_type == kappa_type_eg  .or.  &
                      kappa_thic_type == kappa_type_eg ) ) then

              HOR_DIFF(:,:,kk_sub,kk,bid) = KAPPA_ISOP(:,:,kk_sub,kk,bid) 

            else

              if ( .not. ( kk == 1 .and. kk_sub == ktp ) ) then 

                if ( use_const_ah_bkg_srfbl ) then 
                  HOR_DIFF(:,:,kk_sub,kk,bid) =                       &
                       merge( ah_bkg_srfbl * (c1 - TAPER1 * TAPER2)   &
                              * KAPPA_VERTICAL(:,:,kk,bid),           &
                              c0, dz_bottom <= BL_DEPTH(:,:,bid) )
                else
                  HOR_DIFF(:,:,kk_sub,kk,bid) =                &
                         merge( KAPPA_ISOP(:,:,kk_sub,kk,bid)  &
                               * (c1 - TAPER1 * TAPER2),       &
                              c0, dz_bottom <= BL_DEPTH(:,:,bid) )
                endif

              endif

            endif

            KAPPA_ISOP(:,:,kk_sub,kk,bid) =  &
                  TAPER1 * TAPER2 * KAPPA_ISOP(:,:,kk_sub,kk,bid)
            KAPPA_THIC(:,:,kk_sub,kk,bid) =  &
                  TAPER1 * TAPER3 * KAPPA_THIC(:,:,kk_sub,kk,bid)

          end do  ! end of kk_sub loop


!-----------------------------------------------------------------------
!
!     impose the boundary conditions by setting KAPPA=0
!     in the quarter cells adjacent to rigid boundaries.
!     bottom B.C.s are considered within the kk-loop.
!
!-----------------------------------------------------------------------

!     B.C. at the bottom

          where (kk == KMT(:,:,bid))
            KAPPA_ISOP(:,:,kbt,kk,bid) = c0
            KAPPA_THIC(:,:,kbt,kk,bid) = c0
          end where

        enddo              ! end of kk-loop

!     B.C. at the top

        KAPPA_ISOP(:,:,ktp,1,bid) = c0
        KAPPA_THIC(:,:,ktp,1,bid) = c0

        FZTOP(:,:,:,bid) = c0        ! zero flux B.C. at the surface

        if ( transition_layer_on ) then

          call merged_streamfunction ( this_block )

          call apply_vertical_profile_to_isop_hor_diff ( this_block ) 

        else

          TLT%DIABATIC_DEPTH(:,:,bid) = c0
          TLT%THICKNESS(:,:,bid)      = c0
          TLT%INTERIOR_DEPTH(:,:,bid) = c0

          do kk=1,km

            do kk_sub=ktp,kbt

              where ( kk <= KMT(:,:,bid) ) 

                SF_SLX(:,:,1,kk_sub,kk,bid) =          &
                        KAPPA_THIC(:,:,kk_sub,kk,bid)  &
                      * SLX(:,:,1,kk_sub,kk,bid) * dz(kk)

                SF_SLX(:,:,2,kk_sub,kk,bid) =          &
                        KAPPA_THIC(:,:,kk_sub,kk,bid)  &
                      * SLX(:,:,2,kk_sub,kk,bid) * dz(kk)

                SF_SLY(:,:,1,kk_sub,kk,bid) =          &
                        KAPPA_THIC(:,:,kk_sub,kk,bid)  &
                      * SLY(:,:,1,kk_sub,kk,bid) * dz(kk)

                SF_SLY(:,:,2,kk_sub,kk,bid) =          &
                        KAPPA_THIC(:,:,kk_sub,kk,bid)  &
                      * SLY(:,:,2,kk_sub,kk,bid) * dz(kk)

              endwhere

            enddo  ! end of kk_sub-loop

          enddo    ! end of kk-loop

        endif

      endif  ! end of k==1 if statement

      KMASK = merge(c1, c0, k < KMT(:,:,bid))
      

!-----------------------------------------------------------------------
!
!     calculate effective vertical diffusion coefficient
!     NOTE: it is assumed that VDC has been set before this
!           in vmix_coeffs or something similar.
!
!     Dz(VDC * Dz(T)) where D is derivative rather than difference
!     VDC = (Az(dz*Ax(KAPPA*HYX*SLX**2)) + Az(dz*Ay(KAPPA*HXY*SLY**2)))*
!           dzw/TAREA
!
!-----------------------------------------------------------------------

      
      if ( k < km ) then

        WORK1 = dzw(k)*KMASK*TAREA_R(:,:,bid)*                &
                (dz(k  )*p25*KAPPA_ISOP(:,:,kbt,k,  bid)*     &
              (HYX (:,:,bid)*SLX(:,:,ieast, kbt,k,  bid)**2   &
             + HYXW(:,:,bid)*SLX(:,:,iwest, kbt,k,  bid)**2   &
             + HXY (:,:,bid)*SLY(:,:,jnorth,kbt,k,  bid)**2   &
             + HXYS(:,:,bid)*SLY(:,:,jsouth,kbt,k,  bid)**2)  &
                +dz(k+1)*p25*KAPPA_ISOP(:,:,ktp,k+1,bid)*     &
              (HYX (:,:,bid)*SLX(:,:,ieast, ktp,k+1,bid)**2   &
             + HYXW(:,:,bid)*SLX(:,:,iwest, ktp,k+1,bid)**2   &
             + HXY (:,:,bid)*SLY(:,:,jnorth,ktp,k+1,bid)**2   &
             + HXYS(:,:,bid)*SLY(:,:,jsouth,ktp,k+1,bid)**2))

        do n=1,size(VDC,DIM=4)
          VDC_GM(:,:,k,bid) = WORK1
          VDC(:,:,k,n,bid) = VDC(:,:,k,n,bid) + WORK1
        end do

      end if

!-----------------------------------------------------------------------
!
!     check if some horizontal diffusion needs to be added to the
!     bottom half of the bottom cell
!
!-----------------------------------------------------------------------

      if ( ah_bkg_bottom /= c0 ) then
        where ( k == KMT(:,:,bid) ) 
          HOR_DIFF(:,:,kbt,k,bid) = ah_bkg_bottom
        endwhere
      endif

!-----------------------------------------------------------------------
!
!     combine isopycnal and horizontal diffusion coefficients
!
!-----------------------------------------------------------------------

      do j=1,ny_block
        do i=1,nx_block-1
          WORK3(i,j) = KAPPA_ISOP(i,  j,ktp,k,bid)  &
                     + HOR_DIFF  (i,  j,ktp,k,bid)  &
                     + KAPPA_ISOP(i,  j,kbt,k,bid)  &
                     + HOR_DIFF  (i,  j,kbt,k,bid)  &
                     + KAPPA_ISOP(i+1,j,ktp,k,bid)  &
                     + HOR_DIFF  (i+1,j,ktp,k,bid)  &
                     + KAPPA_ISOP(i+1,j,kbt,k,bid)  &
                     + HOR_DIFF  (i+1,j,kbt,k,bid)
        enddo
      enddo
      
      do j=1,ny_block-1
        do i=1,nx_block
          WORK4(i,j) = KAPPA_ISOP(i,j,  ktp,k,bid)  &
                     + HOR_DIFF  (i,j,  ktp,k,bid)  & 
                     + KAPPA_ISOP(i,j,  kbt,k,bid)  &
                     + HOR_DIFF  (i,j,  kbt,k,bid)  &
                     + KAPPA_ISOP(i,j+1,ktp,k,bid)  &
                     + HOR_DIFF  (i,j+1,ktp,k,bid)  &
                     + KAPPA_ISOP(i,j+1,kbt,k,bid)  &
                     + HOR_DIFF  (i,j+1,kbt,k,bid)
        enddo
      enddo
      

!-----------------------------------------------------------------------
!
!     start loop over tracers
!
!-----------------------------------------------------------------------

      kp1 = k + 1
      if ( k == km )  kp1 = k

      if ( k < km ) then
        dz_bottom = dz(kp1)
        factor    = c1
      else
        dz_bottom = c0
        factor    = c0
      endif

      call timer_start(timer_nloop, block_id=this_block%local_id)

      do n = 1,nt

!-----------------------------------------------------------------------
!
!     calculate horizontal fluxes thru vertical faces of T-cell
!     FX = dz*HYX*Ax(Az(KAPPA))*Dx(T) : flux in x-direction
!     FY = dz*HXY*Ay(Az(KAPPA))*Dy(T) : flux in y-direction
!
!-----------------------------------------------------------------------

        FX(:,:,n) = dz(k) * CX * TX(:,:,k,n,bid) * WORK3
        FY(:,:,n) = dz(k) * CY * TY(:,:,k,n,bid) * WORK4 

      end do

      if ( .not. cancellation_occurs ) then

        do j=1,ny_block
          do i=1,nx_block-1
            WORK1(i,j) = KAPPA_ISOP(i,j,ktp,k,bid)                     &
                         * SLX(i,j,ieast,ktp,k,bid) * dz(k)            &
                         - SF_SLX(i,j,ieast,ktp,k,bid)
            WORK2(i,j) = KAPPA_ISOP(i,j,kbt,k,bid)                     &
                         * SLX(i,j,ieast,kbt,k,bid) * dz(k)            &
                         - SF_SLX(i,j,ieast,kbt,k,bid)
            WORK3(i,j) = KAPPA_ISOP(i+1,j,ktp,k,bid)                   &
                         * SLX(i+1,j,iwest,ktp,k,bid) * dz(k)          &
                         - SF_SLX(i+1,j,iwest,ktp,k,bid)
            WORK4(i,j) = KAPPA_ISOP(i+1,j,kbt,k,bid)                   &
                         * SLX(i+1,j,iwest,kbt,k,bid) * dz(k)          &
                         - SF_SLX(i+1,j,iwest,kbt,k,bid)
          enddo
        enddo
	
	do n = 1,nt

          if (n > 2 .and. k < km)  &
            TZ(:,:,k+1,n,bid) = TMIX(:,:,k  ,n) - TMIX(:,:,k+1,n)

          do j=1,ny_block
            do i=1,nx_block-1
              FX(i,j,n) = FX(i,j,n) - CX(i,j)                          &
               * ( WORK1(i,j) * TZ(i,j,k,n,bid)                        &
                   + WORK2(i,j) * TZ(i,j,kp1,n,bid)                    &
                   + WORK3(i,j) * TZ(i+1,j,k,n,bid)                    &
                   + WORK4(i,j) * TZ(i+1,j,kp1,n,bid) )
            enddo
          enddo

        end do


        do j=1,ny_block-1
          do i=1,nx_block
            WORK1(i,j) = KAPPA_ISOP(i,j,ktp,k,bid)                     &
                         * SLY(i,j,jnorth,ktp,k,bid) * dz(k)           &
                         - SF_SLY(i,j,jnorth,ktp,k,bid)
            WORK2(i,j) = KAPPA_ISOP(i,j,kbt,k,bid)                     &
                         * SLY(i,j,jnorth,kbt,k,bid) * dz(k)           &
                         - SF_SLY(i,j,jnorth,kbt,k,bid)
            WORK3(i,j) = KAPPA_ISOP(i,j+1,ktp,k,bid)                   &
                         * SLY(i,j+1,jsouth,ktp,k,bid) * dz(k)         &
                         - SF_SLY(i,j+1,jsouth,ktp,k,bid)
            WORK4(i,j) = KAPPA_ISOP(i,j+1,kbt,k,bid)                   &
                         * SLY(i,j+1,jsouth,kbt,k,bid) * dz(k)         &
                         - SF_SLY(i,j+1,jsouth,kbt,k,bid)
          enddo
        enddo

        do n = 1,nt

          do j=1,ny_block-1
            do i=1,nx_block
              FY(i,j,n) = FY(i,j,n) - CY(i,j)                          &
               * ( WORK1(i,j) * TZ(i,j,k,n,bid)                        &
                   + WORK2(i,j) * TZ(i,j,kp1,n,bid)                    &
                   + WORK3(i,j) * TZ(i,j+1,k,n,bid)                    &
                   + WORK4(i,j) * TZ(i,j+1,kp1,n,bid) )
            enddo
          enddo

        end do

      endif

      do n = 1,nt

!-----------------------------------------------------------------------
!
!     calculate vertical fluxes thru horizontal faces of T-cell
!     - Az(dz*Ax(HYX*KAPPA*SLX*TX)) - Az(dz*Ay(HXY*KAPPA*SLY*TY))
!     calculate isopycnal diffusion from flux differences
!     DTK = (Dx(FX)+Dy(FY)+Dz(FZ)) / volume
!
!-----------------------------------------------------------------------

        GTK(:,:,n) = c0

        if ( k < km ) then
          
          WORK3 = c0

          if ( .not. cancellation_occurs ) then

!pw loop split to improve performance  -- 2

            do j=this_block%jb,this_block%je
              do i=this_block%ib,this_block%ie

                WORK3(i,j) = WORK3(i,j)                               &
                    + ( dz(k) * KAPPA_ISOP(i,j,kbt,k,bid)             &
                    * ( SLX(i,j,ieast ,kbt,k  ,bid)                   &
                       * HYX(i  ,j  ,bid) * TX(i  ,j  ,k  ,n,bid)     &
                      + SLY(i,j,jnorth,kbt,k  ,bid)                   &
                       * HXY(i  ,j  ,bid) * TY(i  ,j  ,k  ,n,bid)     &
                      + SLX(i,j,iwest ,kbt,k  ,bid)                   &
                       * HYX(i-1,j  ,bid) * TX(i-1,j  ,k  ,n,bid)     &
                      + SLY(i,j,jsouth,kbt,k  ,bid)                   &
                       * HXY(i  ,j-1,bid) * TY(i  ,j-1,k  ,n,bid) ) )

               enddo
             enddo

            do j=this_block%jb,this_block%je
              do i=this_block%ib,this_block%ie

                WORK3(i,j) = WORK3(i,j)                               &
                    + ( SF_SLX(i  ,j  ,ieast ,kbt,k  ,bid)            &
                       * HYX(i  ,j  ,bid) * TX(i  ,j  ,k  ,n,bid)     &
                      + SF_SLY(i  ,j  ,jnorth,kbt,k  ,bid)            &
                       * HXY(i  ,j  ,bid) * TY(i  ,j  ,k  ,n,bid)     &
                      + SF_SLX(i  ,j  ,iwest ,kbt,k  ,bid)            &
                       * HYX(i-1,j  ,bid) * TX(i-1,j  ,k  ,n,bid)     &
                      + SF_SLY(i  ,j  ,jsouth,kbt,k  ,bid)            &
                       * HXY(i  ,j-1,bid) * TY(i  ,j-1,k  ,n,bid) )

               enddo
             enddo

            do j=this_block%jb,this_block%je
              do i=this_block%ib,this_block%ie

                WORK3(i,j) = WORK3(i,j)                               &
                    + ( dz_bottom * KAPPA_ISOP(i,j,ktp,kp1,bid)       &
                    * ( SLX(i  ,j  ,ieast ,ktp,kp1,bid)               &
                       * HYX(i  ,j  ,bid) * TX(i  ,j  ,kp1,n,bid)     &
                      + SLY(i  ,j  ,jnorth,ktp,kp1,bid)               &
                       * HXY(i  ,j  ,bid) * TY(i  ,j  ,kp1,n,bid)     &
                      + SLX(i  ,j  ,iwest ,ktp,kp1,bid)               &
                       * HYX(i-1,j  ,bid) * TX(i-1,j  ,kp1,n,bid)     &
                      + SLY(i  ,j  ,jsouth,ktp,kp1,bid)               &
                       * HXY(i  ,j-1,bid) * TY(i  ,j-1,kp1,n,bid) ) )

               enddo
             enddo

            do j=this_block%jb,this_block%je
              do i=this_block%ib,this_block%ie

                 WORK3(i,j) = WORK3(i,j)                              &
                    + ( factor                                        &
                    * ( SF_SLX(i  ,j  ,ieast ,ktp,kp1,bid)            &
                       * HYX(i  ,j  ,bid) * TX(i  ,j  ,kp1,n,bid)     &
                      + SF_SLY(i  ,j  ,jnorth,ktp,kp1,bid)            &
                       * HXY(i  ,j  ,bid) * TY(i  ,j  ,kp1,n,bid)     &
                      + SF_SLX(i  ,j  ,iwest ,ktp,kp1,bid)            &
                       * HYX(i-1,j  ,bid) * TX(i-1,j  ,kp1,n,bid)     &
                      + SF_SLY(i  ,j  ,jsouth,ktp,kp1,bid)            &
                       * HXY(i  ,j-1,bid) * TY(i  ,j-1,kp1,n,bid) ) )

               enddo
             enddo

            do j=this_block%jb,this_block%je
              do i=this_block%ib,this_block%ie

                fz = -KMASK(i,j) * p25 * WORK3(i,j)

                GTK(i,j,n) = ( FX(i,j,n) - FX(i-1,j,n)  &
                             + FY(i,j,n) - FY(i,j-1,n)  &
                      + FZTOP(i,j,n,bid) - fz )*dzr(k)*TAREA_R(i,j,bid)

                FZTOP(i,j,n,bid) = fz

              enddo
            enddo

          else

!pw loop split to improve performance

            do j=this_block%jb,this_block%je
              do i=this_block%ib,this_block%ie

               WORK3(i,j) =                                           &
                   ( dz(k) * KAPPA_ISOP(i,j,kbt,k,bid)                &
                   * (  SLX(i,j,ieast ,kbt,k  ,bid)                   &
                       * HYX(i  ,j  ,bid) * TX(i  ,j  ,k  ,n,bid)     &
                      + SLY(i,j,jnorth,kbt,k  ,bid)                   &
                       * HXY(i  ,j  ,bid) * TY(i  ,j  ,k  ,n,bid)     &
                      + SLX(i,j,iwest ,kbt,k  ,bid)                   &
                       * HYX(i-1,j  ,bid) * TX(i-1,j  ,k  ,n,bid)     &
                      + SLY(i,j,jsouth,kbt,k  ,bid)                   &
                       * HXY(i  ,j-1,bid) * TY(i  ,j-1,k  ,n,bid) ) )

              enddo
            enddo

            do j=this_block%jb,this_block%je
              do i=this_block%ib,this_block%ie

                WORK3(i,j) = WORK3(i,j)                               &
                    + ( dz_bottom * KAPPA_ISOP(i,j,ktp,kp1,bid)       &
                    * ( SLX(i  ,j  ,ieast ,ktp,kp1,bid)               &
                       * HYX(i  ,j  ,bid) * TX(i  ,j  ,kp1,n,bid)     &
                      + SLY(i  ,j  ,jnorth,ktp,kp1,bid)               &
                       * HXY(i  ,j  ,bid) * TY(i  ,j  ,kp1,n,bid)     &
                      + SLX(i  ,j  ,iwest ,ktp,kp1,bid)               &
                       * HYX(i-1,j  ,bid) * TX(i-1,j  ,kp1,n,bid)     &
                      + SLY(i  ,j  ,jsouth,ktp,kp1,bid)               &
                       * HXY(i  ,j-1,bid) * TY(i  ,j-1,kp1,n,bid) ) )

              enddo
            enddo

            do j=this_block%jb,this_block%je
              do i=this_block%ib,this_block%ie

                fz = -KMASK(i,j) * p5 * WORK3(i,j)

                GTK(i,j,n) = ( FX(i,j,n) - FX(i-1,j,n)  &
                             + FY(i,j,n) - FY(i,j-1,n)  &
                      + FZTOP(i,j,n,bid) - fz )*dzr(k)*TAREA_R(i,j,bid)

                FZTOP(i,j,n,bid) = fz

              enddo
            enddo

          endif

        else                 ! k = km

          do j=this_block%jb,this_block%je
            do i=this_block%ib,this_block%ie

              GTK(i,j,n) = ( FX(i,j,n) - FX(i-1,j,n)  &
                           + FY(i,j,n) - FY(i,j-1,n)  &
                    + FZTOP(i,j,n,bid) )*dzr(k)*TAREA_R(i,j,bid)

              FZTOP(i,j,n,bid) = c0 

            enddo
          enddo

        endif

!-----------------------------------------------------------------------
!
!     end of tracer loop
!
!-----------------------------------------------------------------------

      enddo

      call timer_stop(timer_nloop, block_id=this_block%local_id)

!-----------------------------------------------------------------------
!
!     diagnostic computation of the bolus velocities 
!
!-----------------------------------------------------------------------
      
      if ( diag_gm_bolus ) then

        do j=1,ny_block-1
          do i=1,nx_block-1

            WORK1(i,j) = (   SF_SLX(i  ,j,ieast,kbt,k,  bid)    &
                  + factor * SF_SLX(i  ,j,ieast,ktp,kp1,bid)    &
                           + SF_SLX(i+1,j,iwest,kbt,k,  bid)    &
                  + factor * SF_SLX(i+1,j,iwest,ktp,kp1,bid))   &
                   * p25 * HYX(i,j,bid)

            WORK2(i,j) = (   SF_SLY(i,j  ,jnorth,kbt,k,  bid)   &
                  + factor * SF_SLY(i,j  ,jnorth,ktp,kp1,bid)   &
                           + SF_SLY(i,j+1,jsouth,kbt,k,  bid)   &
                  + factor * SF_SLY(i,j+1,jsouth,ktp,kp1,bid))  &
                   * p25 * HXY(i,j,bid)

          enddo
        enddo

        UIB = merge( WORK1, c0, k < KMT(:,:,bid)  &
                          .and. k < KMTE(:,:,bid) )
        VIB = merge( WORK2, c0, k < KMT(:,:,bid)  &
                          .and. k < KMTN(:,:,bid) )

        WORK1 = merge( UIT(:,:,bid) - UIB, c0, k <= KMT(:,:,bid)  &
                                         .and. k <= KMTE(:,:,bid) )
        WORK2 = merge( VIT(:,:,bid) - VIB, c0, k <= KMT(:,:,bid)  &
                                         .and. k <= KMTN(:,:,bid) )

        U_ISOP = WORK1 * dzr(k) / HTE(:,:,bid)
        V_ISOP = WORK2 * dzr(k) / HTN(:,:,bid)

        if ( linertial .and. k == 2 ) then
          BOLUS_SP(:,:,bid) = 50.0_r8 * sqrt(U_ISOP**c2 + V_ISOP**c2)  
        endif

        do j=this_block%jb,this_block%je
          do i=this_block%ib,this_block%ie

            if ( k < KMT(i,j,bid) ) then
              WBOT_ISOP(i,j,bid) = WTOP_ISOP(i,j,bid)          &
                                   + TAREA_R(i,j,bid)          &
                               * ( WORK1(i,j) - WORK1(i-1,j)   &
                                 + WORK2(i,j) - WORK2(i,j-1) )
            else
              WBOT_ISOP(i,j,bid) = c0
            endif

          enddo
        enddo

      endif


!-----------------------------------------------------------------------
!
!     update remaining bottom-face fields to top-face fields for next
!     pass
!
!-----------------------------------------------------------------------

      
      if ( diag_gm_bolus ) then
        UIT(:,:,bid) = UIB
        VIT(:,:,bid) = VIB
      endif

!-----------------------------------------------------------------------
!
!     compute isopycnal diffusion cfl diagnostics if required
!
!-----------------------------------------------------------------------

      if (ldiag_cfl) then

        WORK2 = p5 * (KAPPA_ISOP(:,:,ktp,k,bid)  &
                    + KAPPA_ISOP(:,:,kbt,k,bid)) 

        WORK1 = merge(c4*WORK2*(DXTR(:,:,bid)**2 + DYTR(:,:,bid)**2),  &
                      c0, KMT(:,:,bid) > k)
        WORK2 = abs(WORK1)
        call cfl_hdiff (k,bid,WORK2,1,this_block)

      endif

!-----------------------------------------------------------------------
!
!     accumulate time average if necessary
!
!-----------------------------------------------------------------------

      if ( mix_pass /= 1 ) then


        tavg_stream = tavg_in_which_stream(tavg_KAPPA_ISOP)
        if (ltavg_on(tavg_stream) .and. tavg_requested(tavg_KAPPA_ISOP)) then
          call accumulate_tavg_field                      &
                   (p5 * (KAPPA_ISOP(:,:,ktp,k,bid)    &
                       +  KAPPA_ISOP(:,:,kbt,k,bid)),  &
                          tavg_KAPPA_ISOP, bid, k)
        endif

        tavg_stream = tavg_in_which_stream(tavg_KAPPA_THIC)
        if (ltavg_on(tavg_stream) .and. tavg_requested(tavg_KAPPA_THIC)) then
          call accumulate_tavg_field                      &
                   (p5 * (KAPPA_THIC(:,:,ktp,k,bid)    &
                       +  KAPPA_THIC(:,:,kbt,k,bid)),  &
                          tavg_KAPPA_THIC, bid, k)
        endif

        tavg_stream = tavg_in_which_stream(tavg_HOR_DIFF)
        if (ltavg_on(tavg_stream) .and. tavg_requested(tavg_HOR_DIFF)) then
          call accumulate_tavg_field                      &
                   (p5 * (HOR_DIFF(:,:,ktp,k,bid)      &
                       +  HOR_DIFF(:,:,kbt,k,bid)),    &
                          tavg_HOR_DIFF, bid, k)
        endif

        if ( transition_layer_on  .and.  k == 1 ) then

          tavg_stream = tavg_in_which_stream(tavg_DIA_DEPTH)
          if (ltavg_on(tavg_stream) .and. tavg_requested(tavg_DIA_DEPTH)) then
            call accumulate_tavg_field (TLT%DIABATIC_DEPTH(:,:,bid),  &
                                        tavg_DIA_DEPTH, bid, 1)  
          endif

          tavg_stream = tavg_in_which_stream(tavg_TLT)
          if (ltavg_on(tavg_stream) .and. tavg_requested(tavg_TLT)) then
            call accumulate_tavg_field (TLT%THICKNESS(:,:,bid),       &
                                        tavg_TLT, bid, 1)  
          endif

          tavg_stream = tavg_in_which_stream(tavg_INT_DEPTH)
          if (ltavg_on(tavg_stream) .and. tavg_requested(tavg_INT_DEPTH)) then
            call accumulate_tavg_field (TLT%INTERIOR_DEPTH(:,:,bid),  &
                                        tavg_INT_DEPTH, bid, 1)  
          endif

        endif

        if ( diag_gm_bolus ) then

          tavg_stream = tavg_in_which_stream(tavg_UISOP)
          if (ltavg_on(tavg_stream) .and. tavg_requested(tavg_UISOP)) then
            call accumulate_tavg_field (U_ISOP, tavg_UISOP, bid, k) 
          endif

          tavg_stream = tavg_in_which_stream(tavg_VISOP)
          if (ltavg_on(tavg_stream) .and. tavg_requested(tavg_VISOP)) then
            call accumulate_tavg_field (V_ISOP, tavg_VISOP, bid, k) 
          endif

          tavg_stream = tavg_in_which_stream(tavg_WISOP)
          if (ltavg_on(tavg_stream) .and. tavg_requested(tavg_WISOP)) then
            call accumulate_tavg_field (WTOP_ISOP(:,:,bid), tavg_WISOP,&
                                        bid, k)
          endif

          tavg_stream = tavg_in_which_stream(tavg_ADVT_ISOP)
          if (ltavg_on(tavg_stream) .and. tavg_requested(tavg_ADVT_ISOP)) then

            WORK1 = p5 * HTE(:,:,bid) * U_ISOP * ( TMIX(:,:,k,1)  &
                      + eoshift(TMIX(:,:,k,1), dim=1, shift=1) )
            WORK2 = eoshift(WORK1, dim=1, shift=-1)
            WORK3 = WORK1 - WORK2

            WORK1 = p5 * HTN(:,:,bid) * V_ISOP * ( TMIX(:,:,k,1)  &
                      + eoshift(TMIX(:,:,k,1), dim=2, shift=1) )  
            WORK2 = eoshift(WORK1, dim=2, shift=-1)
            WORK3 = WORK3 + WORK1 - WORK2

            WORK1 = c0
            do j=this_block%jb,this_block%je
              do i=this_block%ib,this_block%ie
                if ( k <= KMT(i,j,bid) ) then
                  WORK1(i,j) = - dz(k) * TAREA_R(i,j,bid) * WORK3(i,j)
                endif
              enddo
            enddo

            call accumulate_tavg_field (WORK1, tavg_ADVT_ISOP, bid, k)

          endif

          tavg_stream = tavg_in_which_stream(tavg_ADVS_ISOP)
          if (ltavg_on(tavg_stream) .and. tavg_requested(tavg_ADVS_ISOP)) then

            WORK1 = p5 * HTE(:,:,bid) * U_ISOP * ( TMIX(:,:,k,2)  &
                      + eoshift(TMIX(:,:,k,2), dim=1, shift=1) )
            WORK2 = eoshift(WORK1, dim=1, shift=-1)
            WORK3 = WORK1 - WORK2

            WORK1 = p5 * HTN(:,:,bid) * V_ISOP * ( TMIX(:,:,k,2)  &
                      + eoshift(TMIX(:,:,k,2), dim=2, shift=1) )
            WORK2 = eoshift(WORK1, dim=2, shift=-1)
            WORK3 = WORK3 + WORK1 - WORK2

            WORK1 = c0
            do j=this_block%jb,this_block%je
              do i=this_block%ib,this_block%ie
                if ( k <= KMT(i,j,bid) ) then
                  WORK1(i,j) = - dz(k) * TAREA_R(i,j,bid) * WORK3(i,j)
                endif
              enddo
            enddo

            call accumulate_tavg_field (WORK1, tavg_ADVS_ISOP, bid, k)

          endif

          if ( tavg_requested(tavg_VNT_ISOP)  .or.  &
               tavg_requested(tavg_VNS_ISOP) ) then

            WORK1 = p5 * V_ISOP * HTN(:,:,bid) * TAREA_R(:,:,bid) 

            tavg_stream = tavg_in_which_stream(tavg_VNT_ISOP)
            if (ltavg_on(tavg_stream) .and. tavg_requested(tavg_VNT_ISOP)) then

              WORK2 = WORK1 * (    TMIX(:,:,k,1)  &
                         + eoshift(TMIX(:,:,k,1), dim=2, shift=1) )

              call accumulate_tavg_field (WORK2, tavg_VNT_ISOP, bid, k) 

            endif

            tavg_stream = tavg_in_which_stream(tavg_VNS_ISOP)
            if (ltavg_on(tavg_stream) .and. tavg_requested(tavg_VNS_ISOP)) then

              WORK2 = WORK1 * (    TMIX(:,:,k,2)  &
                         + eoshift(TMIX(:,:,k,2), dim=2, shift=1) )

              call accumulate_tavg_field (WORK2, tavg_VNS_ISOP, bid, k)
  
            endif

          endif

        endif ! bolus velocity option on

        do n = 1,nt
          if (tavg_requested(tavg_HDIFE_TRACER(n))) then
          if (ltavg_on(tavg_in_which_stream(tavg_HDIFE_TRACER(n)))) then
            do j=this_block%jb,this_block%je
            do i=this_block%ib,this_block%ie
              WORK1(i,j) = FX(i,j,n)*dzr(k)*TAREA_R(i,j,bid)
            enddo
            enddo
            call accumulate_tavg_field(WORK1,tavg_HDIFE_TRACER(n),bid,k)
          endif
          endif

          if (tavg_requested(tavg_HDIFN_TRACER(n))) then
          if (ltavg_on(tavg_in_which_stream(tavg_HDIFN_TRACER(n)))) then
            do j=this_block%jb,this_block%je
            do i=this_block%ib,this_block%ie
              WORK1(i,j) = FY(i,j,n)*dzr(k)*TAREA_R(i,j,bid)
            enddo
            enddo
            call accumulate_tavg_field(WORK1,tavg_HDIFN_TRACER(n),bid,k)
          endif
          endif

          if (tavg_requested(tavg_HDIFB_TRACER(n))) then
          if (ltavg_on(tavg_in_which_stream(tavg_HDIFB_TRACER(n)))) then
            do j=this_block%jb,this_block%je
            do i=this_block%ib,this_block%ie
              WORK1(i,j) = FZTOP(i,j,n,bid)*dzr(k)*TAREA_R(i,j,bid)
            enddo
            enddo
            call accumulate_tavg_field(WORK1,tavg_HDIFB_TRACER(n),bid,k)
          endif
          endif
        enddo

      endif   ! mix_pass ne 1


!-----------------------------------------------------------------------
!EOC

      end subroutine hdifft_gm

!***********************************************************************
!BOP
! !IROUTINE: kappa_lon_lat_vmhs 
! !INTERFACE:


      subroutine kappa_lon_lat_vmhs (TMIX, UMIX, VMIX, this_block) 1,5

! !DESCRIPTION:
!  Variable kappa parameterization by Visbeck et al (1997):
!  \begin{equation}
!     KAPPA_LATERAL = C {{l^2}\over{T}},
!  \end{equation}
!  where $C$ is a constant, $T$ is the (Eady) time scale
!  $f/\surd\overline{Ri}$ and $l$ is the Rossby radius.
!
! !REVISION HISTORY:
!  same as module

! !INPUT PARAMETERS:

      real (r8), dimension(nx_block,ny_block,km,nt), intent(in) :: &
         TMIX               ! tracers at all vertical levels
                            !  at mixing time level

      real (r8), dimension(nx_block,ny_block,km), intent(in) :: &
         UMIX, VMIX         ! U,V  at all vertical levels
                            !  at mixing time level

      type (block), intent(in) :: &
         this_block         ! block info for this sub block

!EOP
!BOC
!-----------------------------------------------------------------------
!
!  local variables
!
!-----------------------------------------------------------------------

      integer (int_kind) :: &
         kp1,i,j,kk,k,      &
         k1,k2,             &
         bid                ! local block address for this sub block

      real (r8) :: &
         const, zmin1, zmin2

      real (r8), dimension(nx_block,ny_block) :: &
         UKT, VKT,                               &
         UKPT, VKPT, RNUM,                       &
         WORK1, WORK2, WORK3, WORK4,             &
         TK, TKP,                                & 
         RHOT, RHOS,                             &
         GRATE, LSC                              

!-----------------------------------------------------------------------
!  initialization
!-----------------------------------------------------------------------

      bid = this_block%local_id

      GRATE = c0
      LSC = c0
      k1 = 0
      k2 = 0

      vert_loop: do k=1,km

!     -2000m < z < -100m

        if ( zt(k) >= 1.0e4_r8 .and. zt(k) <= 2.0e5_r8 ) then

!-----------------------------------------------------------------------
!
!     start computing the Richardson number and the baroclinic wave speed 
!     average velocities at T points of level k
!
!-----------------------------------------------------------------------

          if ( k1 == 0 ) then

            k1 = k              ! k1 is the upper limit for integration

            call ugrid_to_tgrid(UKT,UMIX(:,:,k),bid)
            call ugrid_to_tgrid(VKT,VMIX(:,:,k),bid)

            TK = max(-c2, TMIX(:,:,k,1))

          endif

!-----------------------------------------------------------------------
!
!     compute RZ=Dz(rho) at k=k
!
!-----------------------------------------------------------------------

          if ( k < km ) then
            kp1 = k + 1
          else
            kp1 = km
          endif

          call state (k,kp1,TMIX(:,:,k,1),TMIX(:,:,k,2), &
                      this_block, DRHODT=RHOT, DRHODS=RHOS)

          TKP = max(-c2, TMIX(:,:,kp1,1))

          WORK1 = TK - TKP
          WORK2 = TMIX(:,:,k,2) - TMIX(:,:,kp1,2)

          WORK3 = RHOT * WORK1 + RHOS * WORK2
          WORK3 = min(WORK3,-eps2)

!-----------------------------------------------------------------------
!
!     average velocities at T points of level k+1
!
!-----------------------------------------------------------------------

          call ugrid_to_tgrid(UKPT,UMIX(:,:,kp1),bid)
          call ugrid_to_tgrid(VKPT,VMIX(:,:,kp1),bid)

!-----------------------------------------------------------------------
!
!     local Richardson number at the bottom of T box, level k
!     = -g*Dz(RHO)/RHO_0/(Dz(u)**2+Dz(v)**2)
!
!-----------------------------------------------------------------------

          if (partial_bottom_cells) then

            where (k < KMT(:,:,bid))

!     RHO_0 = 1 in denominator (approximately) in cgs unit.

              WORK4 = p5*(dz(k) + DZT(:,:,k+1,bid))  ! dzw equivalent

              RNUM = -WORK4/((UKT - UKPT)**2 + (VKT - VKPT)**2 + eps)
              GRATE = GRATE + grav*RNUM*WORK4*WORK3
              LSC = LSC - grav*WORK3

            end where

          else ! no partial bottom cells

            where (k < KMT(:,:,bid))

!     RHO_0 = 1 in denominator (approximately) in cgs unit.

              RNUM = -dzw(k)/((UKT - UKPT)**2 + (VKT - VKPT)**2 + eps)
              GRATE = GRATE + grav*RNUM*dzw(k)*WORK3
              LSC = LSC - grav*WORK3

            end where

          endif ! partial bottom cells

!-----------------------------------------------------------------------
!
!     bottom values become top values for next pass
!
!-----------------------------------------------------------------------

          UKT = UKPT
          VKT = VKPT
          TK  = TKP

        else

          if ( k1 /= 0 .and. k2 == 0 ) then
            k2 = k                ! k2 is the lower limit for integration
            exit vert_loop
          endif

        endif                     ! if(zt(k).ge.1.0e4.and.zt(k).lt.2.0e5)

      end do vert_loop

      do j=1,ny_block
        do i=1,nx_block
          kk = KMT(i,j,bid)
          if ( kk > 0 ) then
            zmin1 = min(zt(k1),zt(kk))
            zmin2 = min(zt(k2),zt(kk))
            GRATE(i,j) = GRATE(i,j)/(zmin2-zmin1+eps) ! Ri
            LSC(i,j) = LSC(i,j)*(zmin2-zmin1)         ! c_g^2=N^2*H^2
          else
            GRATE(i,j) = c0
            LSC(i,j)   = c0
          endif
        end do
      end do

!     equatorial inverse of time scale and square of length scale

      WORK1 = sqrt(c2*sqrt(LSC)*BTP(:,:,bid)) ! sqrt(c_g*2*beta)
      WORK2 = sqrt(LSC)/(c2*BTP(:,:,bid))     ! c_g/(2 beta)

!     inverse of time scale

      WORK1 = max(abs(FCORT(:,:,bid)),WORK1)
      GRATE = WORK1/sqrt(GRATE+eps)           ! 1/T = f/sqrt(Ri)

!     square of length scale

      LSC = LSC/(FCORT(:,:,bid)+eps)**2       ! L^2 = c_g^2/f^2
      LSC = min(LSC,WORK2)

!     grid size = lower limit of length scale

      WORK1 = min(DXT(:,:,bid)**2,DYT(:,:,bid)**2)
      LSC = max(LSC,WORK1)

!-----------------------------------------------------------------------
!
!     compute KAPPA_LATERAL
!
!-----------------------------------------------------------------------

!     const = 0.015_r8  ! constant taken from Visbeck et al (1997)
      const = 0.13_r8   
      WORK1 = const*GRATE*LSC                 ! const*L**2/T

!     KAPPA_LATERAL is bounded by 3.0e6 < KAPPA_LATERAL < 4.0e7

      KAPPA_LATERAL(:,:,bid) = min(4.0e7_r8,WORK1)
      KAPPA_LATERAL(:,:,bid) = max(3.0e6_r8,KAPPA_LATERAL(:,:,bid))

      where (KMT(:,:,bid) <= k1)     ! KAPPA_LATERAL=3.0e6 when depth < 100m
        KAPPA_LATERAL(:,:,bid) = 3.0e6_r8
      end where

!-----------------------------------------------------------------------
!EOC

      end subroutine kappa_lon_lat_vmhs 

!***********************************************************************
!BOP
! !IROUTINE: kappa_eg
! !INTERFACE:


      subroutine kappa_eg (TMIX, UMIX, VMIX, this_block) 1,2

! !DESCRIPTION:
!  Variable kappa parameterization by Eden and Greatbatch 
!  (2008, Ocean Modelling, v. 20, 223-239):
!  \begin{equation}
!     KAPPA_ISOP = KAPPA_THIC = c {{L^2}*{\sigma}},
!  \end{equation}
!  where $c$ is a tuning parameter (=const_eg), $\sigma$ is the inverse eddy 
!  time scale, and $L$ is the minimum of the Rossby deformation radius and
!  Rhines scale.
!
!  This subroutine returns KAPPA_ISOP in KAPPA_VERTICAL. Here, KAPPA_VERTICAL
!  serves as a temporary array because this subroutine may be called less
!  frequently than every time step and KAPPA_ISOP is modified in each time step.
!
! !REVISION HISTORY:
!  same as module

! !INPUT PARAMETERS:

      real (r8), dimension(nx_block,ny_block,km,nt), intent(in) :: &
         TMIX               ! tracers at all vertical levels
                            !  at mixing time level

      real (r8), dimension(nx_block,ny_block,km), intent(in) :: &
         UMIX, VMIX         ! U,V at all vertical levels
                            !  at mixing time level

      type (block), intent(in) :: &
         this_block         ! block info for this sub block

!EOP
!BOC
!-----------------------------------------------------------------------
!
!  local variables
!
!-----------------------------------------------------------------------

      integer (int_kind) :: &
         k, kp1,            &  ! vertical level index
         bid                   ! local block address for this sub block

      real (r8), dimension(nx_block,ny_block) :: &
         TK, TKP,                                &  ! level k and k+1 TMIX
         WORK1, WORK2, WORK3,                    &  ! work arrays
         C_ROSSBY,                               &  ! first baroclinic Rossby wave speed
         L_ROSSBY,                               &  ! Rossby deformation radius
         RHOT, RHOS                                 ! dRHOdT and dRHOdS


      real (r8), dimension(nx_block,ny_block,km) :: &
         SIGMA,         &  ! inverse eddy time scale
         RI_NO             ! local Richardson number 

!-----------------------------------------------------------------------
!  initialization
!-----------------------------------------------------------------------

      bid = this_block%local_id

      SIGMA = c0
      RI_NO = c0

      BUOY_FREQ_SQ(:,:,:,bid) = c0

!-----------------------------------------------------------------------
!
!     compute buoyancy frequency and Richardson number at the bottom of 
!     T box:
!             Ri = -g*Dz(RHO)/RHO_0/(Dz(u)**2+Dz(v)**2)
!
!     RHO_0 ~ 1 in cgs units.
!
!-----------------------------------------------------------------------

      do k=1,km-1

        if ( k == 1 ) then
          TK = max(-c2, TMIX(:,:,k,1))
        endif

        kp1 = k+1

        call state (k, kp1, TMIX(:,:,k,1), TMIX(:,:,k,2), &
                    this_block, DRHODT=RHOT, DRHODS=RHOS)

        TKP = max(-c2, TMIX(:,:,kp1,1))

        WORK1 = TK - TKP
        WORK2 = TMIX(:,:,k,2) - TMIX(:,:,kp1,2)
        WORK3 = RHOT * WORK1 + RHOS * WORK2
        WORK3 = min(WORK3,-eps2)

        WORK1 =  (UMIX(:,:,k) - UMIX(:,:,kp1))**2  &
               + (VMIX(:,:,k) - VMIX(:,:,kp1))**2

        call ugrid_to_tgrid (WORK2, WORK1, bid)

        where (k < KMT(:,:,bid))
          BUOY_FREQ_SQ(:,:,k,bid) = - grav * WORK3 * dzwr(k)
          WORK1 = dzw(k)**2 / ( WORK2 + eps2 )
          RI_NO(:,:,k) = WORK1 * BUOY_FREQ_SQ(:,:,k,bid) 
        end where

        TK  = TKP

      end do

!-----------------------------------------------------------------------
!
!     compute the first baroclinic gravity-wave phase speed.
!     Computation of Rossby deformation radius follows Chelton et al.(1998)
!
!-----------------------------------------------------------------------

      C_ROSSBY = c0

      k = 1
      where ( k < KMT(:,:,bid) )
        C_ROSSBY = C_ROSSBY + sqrt(BUOY_FREQ_SQ(:,:,k,bid)) * dzw(k-1)
      endwhere

      do k=1,km
        where ( k < KMT(:,:,bid) )
          C_ROSSBY = C_ROSSBY + sqrt(BUOY_FREQ_SQ(:,:,k,bid)) * dzw(k)
        endwhere
        where ( k > 1  .and.  k == KMT(:,:,bid) )
          C_ROSSBY = C_ROSSBY + sqrt(BUOY_FREQ_SQ(:,:,k-1,bid)) * dzw(k)
        endwhere
      enddo

      C_ROSSBY = C_ROSSBY / pi

      L_ROSSBY = min( C_ROSSBY / (abs(FCORT(:,:,bid))+eps), &
                      sqrt( C_ROSSBY / (c2*BTP(:,:,bid)) ) )

!-----------------------------------------------------------------------
!
!     compute the inverse time scale
!
!-----------------------------------------------------------------------

      do k=1,km-1
        WORK1 = max( abs( FCORT(:,:,bid) ), sqrt(C_ROSSBY * c2 * BTP(:,:,bid)) )
        where (k < KMT(:,:,bid))
          SIGMA(:,:,k) = SIGMA_TOPO_MASK(:,:,k,bid) * WORK1  &
                        / sqrt( RI_NO(:,:,k) + gamma_eg )
        end where
      enddo

!----------------------------------------------------------------------
!
!     compute KAPPA_ISOP = c_kappa * sigma * min( Rossby_radius, Rhines scales)^2.
!     note that KAPPA_ISOP is stored in KAPPA_VERTICAL. KAPPA_VERTICAL is
!     located at the T-grid points. in the following, KAPPA_ISOP computed at
!     the lower interface of a T-grid box is assigned to the T-grid point 
!     just above this interface for simplicity.
!
!-----------------------------------------------------------------------

      do k=1,km

        WORK1 = min(L_ROSSBY, SIGMA(:,:,k)/BTP(:,:,bid))

        KAPPA_VERTICAL(:,:,k,bid) = const_eg * SIGMA(:,:,k) * WORK1**2 

      enddo

!----------------------------------------------------------------------
!
!     use below-diabatic-layer values of KAPPA_ISOP within the surface 
!     diabatic layer
!
!----------------------------------------------------------------------

      WORK1 = BL_DEPTH(:,:,bid)
      if ( transition_layer_on )  &
        WORK1 = TLT%DIABATIC_DEPTH(:,:,bid)

      do k=km-1,1,-1
        where ( zw(k) <= WORK1 )
          KAPPA_VERTICAL(:,:,k,bid) = KAPPA_VERTICAL(:,:,k+1,bid)
        endwhere
      enddo

!----------------------------------------------------------------------
!
!     impose lower and upper limits on KAPPA
!
!----------------------------------------------------------------------

      KAPPA_VERTICAL(:,:,:,bid) = max(kappa_min_eg, KAPPA_VERTICAL(:,:,:,bid))
      KAPPA_VERTICAL(:,:,:,bid) = min(kappa_max_eg, KAPPA_VERTICAL(:,:,:,bid))

      end subroutine kappa_eg

!***********************************************************************
!BOP
! !IROUTINE: kappa_lon_lat_hdgr 
! !INTERFACE:


      subroutine kappa_lon_lat_hdgr (TMIX, this_block) 1,1

! !DESCRIPTION:
!  Variable kappa parameterization based on the vertically averaged
!  horizontal density gradients as a measure of baroclinicity. This
!  approach is from GFDL. 
!
! !REVISION HISTORY:
!  same as module

! !INPUT PARAMETERS:

      real (r8), dimension(nx_block,ny_block,km,nt), intent(in) :: &
         TMIX                  ! tracers at all vertical levels
                               !   at mixing time level

      type (block), intent(in) :: &
         this_block            ! block info for this sub block

!EOP
!BOC
!-----------------------------------------------------------------------
!
!     local variables
!
!-----------------------------------------------------------------------

      integer (int_kind) :: &
         k_min, k_max,  & ! min and max vertical indices for the vertical average
         k,             & ! vertical loop index
         i, j,          & ! horizontal loop indices
         kk,            & ! temporary value of KMT
         bid              ! local block address for this sub block

      real (r8), dimension(nx_block,ny_block) :: &
         KMASKE, KMASKN, &  ! ocean masks for the east and north faces of a T-cell
         WORK,           &  ! work array
         RHOT,           &  ! dRHO/dT
         RHOS,           &  ! dRHO/dS
         RHO_X,          &  ! grid x-direction density difference
         RHO_Y,          &  ! grid y-direction density difference
         RHO_XY_AVG         ! vertically averaged horizontal density gradient

      real (r8), dimension(nx_block,ny_block,2) :: &
         TRACER_X,       &  ! grid x-direction T and S differences
         TRACER_Y           ! grid y-direction T and S differences

      real (r8) :: &
         depth_min, depth_max, & ! actual min and max depths (reflecting model
                                 !  discretization) for computing vertical
                                 !  averages at every horizontal grid point
         depth_w_min,    &       ! protection against k_min = k_max = 0 in
         depth_w_max,    &       !  array zw
         scaling_coefficient     ! multiplicative factor

!-----------------------------------------------------------------------
!
!     parameter values for the formulation 
!
!-----------------------------------------------------------------------

      real (r8), parameter :: &
         tuning_const      = 2.0_r8,    & ! dimensionless tuning constant 
         length_scale_ref  = 50.0e5_r8, & ! constant length scale in cm
         buoyancy_freq_ref = 4.0e-3_r8, & ! constant buoyancy frequency in 1/s
         vert_average_min  = 1.0e4_r8,  & ! min and max depth range for the
         vert_average_max  = 2.0e5_r8,  & !  vertical average in cm
         kappa_min         = 3.0e6_r8,  & ! min KAPPA_LATERAL value in cm^2/s
         kappa_max         = 4.0e7_r8     ! max KAPPA_LATERAL value in cm^2/s

!-----------------------------------------------------------------------
!
!     initialization
!
!-----------------------------------------------------------------------

      bid = this_block%local_id

      k_min = -1 
      k_max =  0

      TRACER_X   = c0
      TRACER_Y   = c0
      RHO_X      = c0
      RHO_Y      = c0
      RHO_XY_AVG = c0

      scaling_coefficient = tuning_const * (length_scale_ref**2) * grav &
                           / ( rho_sw * buoyancy_freq_ref ) 

      vert_average_loop: do k=1,km

        if ( zt(k) >= vert_average_min  .and. &
             zt(k) <= vert_average_max ) then

!-----------------------------------------------------------------------
!
!     start computing the vertical average of the horizontal density 
!     gradients 
!
!-----------------------------------------------------------------------

          if ( k_min == -1 )  k_min = k-1 ! k_min is the upper limit for averaging 

          KMASKE = merge(c1, c0, k <= KMT(:,:,bid) .and. &
                         k <= KMTE(:,:,bid))
          KMASKN = merge(c1, c0, k <= KMT(:,:,bid) .and. &
                         k <= KMTN(:,:,bid))

          WORK = max(-c2, TMIX(:,:,k,1))

!-----------------------------------------------------------------------
!
!     compute tracer horizontal differences 
!
!-----------------------------------------------------------------------

          do j=1,ny_block
            do i=1,nx_block-1
              TRACER_X(i,j,1) = KMASKE(i,j) * ( WORK(i+1,j) &
                                              - WORK(i,j) )
              TRACER_X(i,j,2) = KMASKE(i,j)                 &
                          * ( TMIX(i+1,j,k,2) - TMIX(i,j,k,2) )
            enddo
          enddo

          do j=1,ny_block-1
            do i=1,nx_block
              TRACER_Y(i,j,1) = KMASKN(i,j) * ( WORK(i,j+1) &
                                              - WORK(i,j) )
              TRACER_Y(i,j,2) = KMASKN(i,j)                 &
                          * ( TMIX(i,j+1,k,2) - TMIX(i,j,k,2) )
            enddo
          enddo

!-----------------------------------------------------------------------
!
!     now compute horizontal density differences
!
!-----------------------------------------------------------------------

          call state( k, k, TMIX(:,:,k,1), TMIX(:,:,k,2), &
                      this_block, DRHODT=RHOT, DRHODS=RHOS )

          RHO_X = RHOT * TRACER_X(:,:,1) + RHOS * TRACER_X(:,:,2)
          RHO_Y = RHOT * TRACER_Y(:,:,1) + RHOS * TRACER_Y(:,:,2)

!-----------------------------------------------------------------------
!
!     compute horizontal density gradients and perform their vertical 
!     integral 
!
!-----------------------------------------------------------------------

          do j=2,ny_block-1
            do i=2,nx_block-1
              RHO_XY_AVG(i,j) = RHO_XY_AVG(i,j) + dz(k) * sqrt( p5 &
                       * ( ( RHO_X(i,j)**2 + RHO_X(i-1,j)**2 )     &
                          * DXTR(i,j,bid)**2 )                         & 
                       + ( ( RHO_Y(i,j)**2 + RHO_Y(i,j-1)**2 )     &  
                          * DYTR(i,j,bid)**2 ) ) 
            enddo
          enddo

        else

          if ( k_min >= 0  .and.  k_max == 0 ) then
            k_max = k-1            ! k_max is the lower limit for averaging 
            exit vert_average_loop 
          endif

        endif 

      enddo vert_average_loop 

!-----------------------------------------------------------------------
!
!     compute the vertical average of horizontal density gradients for 
!     the specified vertical range
!
!-----------------------------------------------------------------------

      depth_w_min = c0
      depth_w_max = c0
      if ( k_min  > 0 )  depth_w_min = zw(k_min) 
      if ( k_max /= 0 )  depth_w_max = zw(k_max)

      do j=2,ny_block-1
        do i=2,nx_block-1
          kk = KMT(i,j,bid)
          if ( kk > 0 ) then
            depth_min = min( depth_w_min, zw(kk) )
            depth_max = min( depth_w_max, zw(kk) )
            RHO_XY_AVG(i,j) = RHO_XY_AVG(i,j)        &
                             / ( depth_max - depth_min + eps )
          else
            RHO_XY_AVG(i,j) = c0
          endif
        enddo
      enddo

!-----------------------------------------------------------------------
!
!     set KAPPA_LATERAL and enforce the limits 
!
!-----------------------------------------------------------------------

      KAPPA_LATERAL(:,:,bid) = scaling_coefficient * RHO_XY_AVG

      KAPPA_LATERAL(:,:,bid) = min( kappa_max, KAPPA_LATERAL(:,:,bid) )
      KAPPA_LATERAL(:,:,bid) = max( kappa_min, KAPPA_LATERAL(:,:,bid) )

      where ( KMT(:,:,bid) <= k_min )        ! KAPPA_LATERAL = kappa_min 
        KAPPA_LATERAL(:,:,bid) = kappa_min   !  when depth < vert_average_min
      endwhere

!-----------------------------------------------------------------------
!EOC

      end subroutine kappa_lon_lat_hdgr

!***********************************************************************
!BOP
! !IROUTINE: kappa_lon_lat_dradius 
! !INTERFACE:


      subroutine kappa_lon_lat_dradius (this_block) 1

! !DESCRIPTION:
!  Variable kappa parameterization based on
!  \begin{equation}
!      KAPPA_LATERAL = KAPPA_REF {LENGTH_SCALE \over LENGTH_SCALE_REF}
!  \end{equation}
!  where $LENGTH_SCALE=$ min (Rossby deformation radius, sqrt(TAREA)).
!  Computation of Rossby deformation radius follows Chelton et al.(1998)
!
! !REVISION HISTORY:
!  same as module

! !INPUT PARAMETERS:

      type (block), intent(in) :: &
         this_block            ! block info for this sub block

!EOP
!BOC
!-----------------------------------------------------------------------
!
!     local variables
!
!-----------------------------------------------------------------------

      integer (int_kind) :: &
         k,            &    ! vertical loop index
         bid                ! local block address for this sub block

      real (r8), dimension(nx_block,ny_block) :: &
         WORK1,        &    ! work array
         LENGTH_SCALE       ! mostly used as a temporary array,
                            !  but the final content is a length scale

      real (r8), parameter :: &
         length_scale_ref = 15.0e+5_r8, &  ! reference length scale in cm
         kappa_lateral_min = 0.1e+7_r8, &  ! minimum kappa in cm^2/s
         kappa_lateral_max = 8.0e+7_r8     ! maximum kappa in cm^2/s

!-----------------------------------------------------------------------
!
!     compute the first baroclinic gravity-wave phase speed, considering
!     the full-depth integral of N (consider pi later)
!
!-----------------------------------------------------------------------

      bid = this_block%local_id

      LENGTH_SCALE = c0

      k = 1
      where ( k < KMT(:,:,bid) )
        LENGTH_SCALE = LENGTH_SCALE  &
                      + sqrt(BUOY_FREQ_SQ(:,:,k,bid)) * dzw(k-1)
      endwhere

      do k=1,km
        where ( k < KMT(:,:,bid) )
          LENGTH_SCALE = LENGTH_SCALE  &
                        + sqrt(BUOY_FREQ_SQ(:,:,k,bid)) * dzw(k)
        endwhere
        where ( k == KMT(:,:,bid) )
          LENGTH_SCALE = LENGTH_SCALE  &
                        + sqrt(BUOY_FREQ_SQ(:,:,k,bid)) * p5 * dz(k)
        endwhere
      enddo

!-----------------------------------------------------------------------
!
!     now compute the Rossby radius of deformation
!
!-----------------------------------------------------------------------

      where ( abs(TLAT(:,:,bid)) > c5 / radian )
        LENGTH_SCALE = LENGTH_SCALE / ( pi * abs(FCORT(:,:,bid)) )
      elsewhere
        LENGTH_SCALE = sqrt( LENGTH_SCALE / ( c2 * pi * BTP(:,:,bid) ) )
      endwhere

!-----------------------------------------------------------------------
!
!     consider grid size as a possible lower limit of length scale.
!     note that if the vertical integral of BUOY_FREQ_SQ is zero, then
!     LENGTH_SCALE = 0. we choose to enforce limits on KAPPA later, rather
!     then on LENGTH_SCALE below.
!
!-----------------------------------------------------------------------

      WORK1 = min( DXT(:,:,bid), DYT(:,:,bid) )
      LENGTH_SCALE = min( LENGTH_SCALE, WORK1 )

!-----------------------------------------------------------------------
!
!     now compute KAPPA_LATERAL
!
!-----------------------------------------------------------------------

      KAPPA_LATERAL(:,:,bid) = ah * LENGTH_SCALE / length_scale_ref

      if ( kappa_isop_type == kappa_type_const )          &
        KAPPA_LATERAL(:,:,bid) = ah_bolus * LENGTH_SCALE  &
                                / length_scale_ref

      KAPPA_LATERAL(:,:,bid) = min(KAPPA_LATERAL(:,:,bid), &
                                   kappa_lateral_max)
      KAPPA_LATERAL(:,:,bid) = max(KAPPA_LATERAL(:,:,bid), &
                                   kappa_lateral_min)

!-----------------------------------------------------------------------
!EOC

      end subroutine kappa_lon_lat_dradius

!***********************************************************************
!BOP
! !IROUTINE: buoyancy_frequency_dependent_profile 
! !INTERFACE:


      subroutine buoyancy_frequency_dependent_profile (TMIX, this_block) 1,1

! !DESCRIPTION:
!  Computes normalized buoyancy frequency ($N$) dependent profiles that 
!  are used to represent the vertical variation of the isopycnal and/or
!  thickness diffusion coefficients. We use 
!  \begin{equation}
!   KAPPA_VERTICAL = {{N^2}\over {N_ref^2}}, 
!  \end{equation}
!  where $N_ref$ is the value of $N$ "just" below the surface diabatic
!  layer (SDL) provided that $N^2 > 0$ there. Otherwise, $N_ref$ is the
!  first stable $N^2$ below SDL. KAPPA_VERTICAL is set to unity for shallower
!  depths. Also, 0.1 <= KAPPA_VERTICAL <= 1.0 is enforced. Note that
!  this implies KAPPA_VERTICAL = 0.1 if the local $N^2 \le 0$.
!  KAPPA_VERTICAL is located at the model tracer points.
!
! !REVISION HISTORY:
!  same as module

! !INPUT PARAMETERS:

      real (r8), dimension(nx_block,ny_block,km,nt), intent(in) :: &
         TMIX                  ! tracers at all vertical levels
                               !   at mixing time level

      type (block), intent(in) :: &
         this_block            ! block info for this sub block

!EOP
!BOC
!-----------------------------------------------------------------------
!
!     local variables
!
!-----------------------------------------------------------------------

      integer (int_kind) :: &
         k,        &          ! vertical loop index
         bid                  ! local block address for this sub block

      integer (int_kind), dimension(nx_block,ny_block) :: &
         K_MIN                ! k index below SDL 

      real (r8), dimension(nx_block,ny_block) :: &
         TEMP_K,           &  ! temperature at level k
         TEMP_KP1,         &  ! temperature at level k+1
         RHOT,             &  ! dRHO/dT
         RHOS,             &  ! dRHO/dS
         BUOY_FREQ_SQ_REF, &  ! reference (normalization) value
                              !  of N^2
         SDL                  ! surface diabatic layer (see below)

      real (r8), dimension(nx_block,ny_block,km) :: &
         BUOY_FREQ_SQ_NORM    ! normalized N^2 defined at level interfaces

!-----------------------------------------------------------------------
!
!     initialize variables
!
!     note that "km+1" value in K_MIN is used as a flag, i.e. it indicates
!     that a minimum value has not been found yet or that it does not
!     exist.
!
!-----------------------------------------------------------------------

      bid = this_block%local_id

      BUOY_FREQ_SQ_NORM         = c0
      BUOY_FREQ_SQ_REF          = c0
      KAPPA_VERTICAL(:,:,:,bid) = c1

      K_MIN = merge( km+1, 0, KMT(:,:,bid) /= 0 )  

      SDL = zw(1)
      if ( vmix_itype == vmix_type_kpp )  SDL = KPP_HBLT(:,:,bid) 
      if ( transition_layer_on )    SDL = TLT%INTERIOR_DEPTH(:,:,bid)

      if ( .not. read_n2_data ) then

!-----------------------------------------------------------------------
!
!     compute N^2
!
!-----------------------------------------------------------------------

        do k=1,km-1

          if ( k == 1 ) &
            TEMP_K = max( -c2, TMIX(:,:,k,1) )

          TEMP_KP1 = max( -c2, TMIX(:,:,k+1,1) )

          call state( k, k+1, TMIX(:,:,k,1), TMIX(:,:,k,2), &
                      this_block, DRHODT=RHOT, DRHODS=RHOS )

          where ( k < KMT(:,:,bid) ) 
            BUOY_FREQ_SQ(:,:,k,bid) = max( c0, - grav * dzwr(k) &
                * ( RHOT * ( TEMP_K - TEMP_KP1 )                &
                  + RHOS * ( TMIX(:,:,k,  2) - TMIX(:,:,k+1,2) ) ) )
          endwhere

          TEMP_K = TEMP_KP1

        enddo

      endif

!-----------------------------------------------------------------------
!
!     determine the reference buoyancy frequency and the associated 
!     level index (most likely just below SDL)
!
!-----------------------------------------------------------------------

      do k=1,km-1
        where ( ( K_MIN == km+1 ) .and. ( zw(k) > SDL ) .and.  &
                ( k <= KMT(:,:,bid) )  .and.                   &
                ( BUOY_FREQ_SQ(:,:,k,bid) > c0 ) ) 
          BUOY_FREQ_SQ_REF = BUOY_FREQ_SQ(:,:,k,bid)
          K_MIN = k
        endwhere
      enddo
        
!-----------------------------------------------------------------------
!
!     now compute the normalized profiles at the interfaces 
!
!-----------------------------------------------------------------------

      do k=1,km-1
        where ( ( k >= K_MIN ) .and. ( k < KMT(:,:,bid) ) .and. &
               ( BUOY_FREQ_SQ_REF /= c0 ) )
          BUOY_FREQ_SQ_NORM(:,:,k) =  &
              max( BUOY_FREQ_SQ(:,:,k,bid) / BUOY_FREQ_SQ_REF, 0.1_r8 )
          BUOY_FREQ_SQ_NORM(:,:,k) =  &
              min( BUOY_FREQ_SQ_NORM(:,:,k), c1 ) 
        elsewhere
          BUOY_FREQ_SQ_NORM(:,:,k) = c1
        endwhere
      enddo

      do k=1,km-1
        where ( k == KMT(:,:,bid)-1 ) 
          BUOY_FREQ_SQ_NORM(:,:,k+1) = BUOY_FREQ_SQ_NORM(:,:,k)
        endwhere
      enddo

!-----------------------------------------------------------------------
!
!     finally, do not average interface values of BUOY_FREQ_SQ_NORM to
!     the tracer points, but instead copy from above to preserve the 
!     extrema. 
!
!-----------------------------------------------------------------------

      do k=2,km
        where ( ( k > K_MIN ) .and. ( k <= KMT(:,:,bid) ) )
          KAPPA_VERTICAL(:,:,k,bid) = BUOY_FREQ_SQ_NORM(:,:,k-1)
        endwhere
      enddo

!-----------------------------------------------------------------------
!EOC

      end subroutine buoyancy_frequency_dependent_profile

!***********************************************************************
!BOP
! !IROUTINE: transition_layer 
! !INTERFACE:


      subroutine transition_layer ( this_block ) 1,3

! !DESCRIPTION:
!  Compute transition layer related fields. the related algorithms
!  should work even with zero transition layer depth.
!
! !REVISION HISTORY:
!  same as module

! !INPUT PARAMETERS:

      type (block), intent(in) :: &
         this_block          ! block info for this sub block

!EOP
!BOC
!-----------------------------------------------------------------------
!
!     local variables
!
!-----------------------------------------------------------------------

      integer (int_kind) :: &
         k, kk,     &        ! loop indices
         bid                 ! local block address for this sub block

      integer (int_kind), dimension(nx_block,ny_block) :: &
         K_START,   &        ! work arrays for TLT%K_LEVEL and 
         K_SUB               !  TLT%ZTW, respectively

      logical (log_kind), dimension(nx_block,ny_block) :: &
         COMPUTE_TLT         ! flag

      real (r8), dimension(nx_block,ny_block) :: &
         WORK                ! work space for TLT%THICKNESS

      real (r8), dimension(2) :: &
         reference_depth     ! zt or zw

!-----------------------------------------------------------------------
!
!     initialize various quantities
!
!-----------------------------------------------------------------------

      bid = this_block%local_id

      K_START = 0
      K_SUB   = 0

      TLT%THICKNESS(:,:,bid)      = c0
      TLT%INTERIOR_DEPTH(:,:,bid) = c0
      TLT%K_LEVEL(:,:,bid)        = 0
      TLT%ZTW(:,:,bid)            = 0

      COMPUTE_TLT = merge(.true., .false., KMT(:,:,bid) /= 0)

!-----------------------------------------------------------------------
!
!     initial pass to determine the minimum transition layer thickness.
!     the vertical level at or below which the interior region starts
!     is also computed.
!
!-----------------------------------------------------------------------

      do k=1,km

        where ( COMPUTE_TLT  .and.  &
                TLT%DIABATIC_DEPTH(:,:,bid) < zw(k) )

          K_START = k+1
          K_SUB   = ktp

          TLT%THICKNESS(:,:,bid) = zw(k) - TLT%DIABATIC_DEPTH(:,:,bid)
          TLT%K_LEVEL(:,:,bid)   = k
          TLT%ZTW(:,:,bid)       = 2

          COMPUTE_TLT = .false.

        endwhere

        where ( k /= 1  .and.  K_START == k+1  .and. &
                TLT%DIABATIC_DEPTH(:,:,bid) < zt(k) )

          K_START = k
          K_SUB   = kbt

          TLT%THICKNESS(:,:,bid) = zt(k) - TLT%DIABATIC_DEPTH(:,:,bid)
          TLT%K_LEVEL(:,:,bid)   = k
          TLT%ZTW(:,:,bid)       = 1

        endwhere

      enddo

#ifdef CCSMCOUPLED
#ifndef _HIRES
      if ( any(COMPUTE_TLT) ) then
        call shr_sys_abort ('Incorrect DIABATIC_DEPTH value in TLT'  &
                        //  ' computation')
      endif
#endif
#endif

!-----------------------------------------------------------------------
!
!     using R * |S| as the vertical displacement length scale associated
!     with a horizontal displacement equivalent to the Rossby deformation
!     radius, R, determine if the transition layer thickness needs to be
!     modified. |S| is the absolute value of the slope of the isopycnal
!     surfaces. First, start with columns where K_SUB = kbt.
!
!-----------------------------------------------------------------------

      where ( KMT(:,:,bid) == 0  .or.  K_START > KMT(:,:,bid)  .or.  &
              ( K_START == KMT(:,:,bid)  .and.  K_SUB == kbt ) )
        COMPUTE_TLT = .false.
      elsewhere
        COMPUTE_TLT = .true.
      endwhere

      do k=1,km-1

        WORK = c0

        where ( COMPUTE_TLT  .and.  K_SUB == kbt  .and.  &
                K_START < KMT(:,:,bid)  .and.  K_START == k )
          WORK = max(SLA_SAVE(:,:,kbt,k,bid), &
                     SLA_SAVE(:,:,ktp,k+1,bid)) * RB(:,:,bid)
        endwhere

        where ( WORK /= c0  .and.  &
                TLT%DIABATIC_DEPTH(:,:,bid) <  (zw(k) - WORK) )
          COMPUTE_TLT = .false.
        endwhere

        where ( WORK /= c0  .and.  &
                TLT%DIABATIC_DEPTH(:,:,bid) >= (zw(k) - WORK) )

          K_START = K_START + 1
          K_SUB   = ktp

          TLT%THICKNESS(:,:,bid) = zw(k) - TLT%DIABATIC_DEPTH(:,:,bid)
          TLT%K_LEVEL(:,:,bid)   = k
          TLT%ZTW(:,:,bid)       = 2

        endwhere

      enddo

!-----------------------------------------------------------------------
!
!     now consider the deeper levels
!
!-----------------------------------------------------------------------

      do k=2,km

        reference_depth(ktp) = zt(k)
        reference_depth(kbt) = zw(k)

        do kk=ktp,kbt

          WORK = c0

          if (kk == ktp) then
            where ( COMPUTE_TLT  .and.  K_START <= KMT(:,:,bid)  .and. &
                    K_START == k )
              WORK = max(SLA_SAVE(:,:,ktp,k,bid), &
                         SLA_SAVE(:,:,kbt,k,bid)) * RB(:,:,bid)
            endwhere
          else
            where ( COMPUTE_TLT  .and.  K_START < KMT(:,:,bid)  .and. &
                    K_START == k )
              WORK = max(SLA_SAVE(:,:,kbt,k,bid), &
                         SLA_SAVE(:,:,ktp,k+1,bid)) * RB(:,:,bid)
            endwhere
            where ( COMPUTE_TLT  .and.  K_START == KMT(:,:,bid)  .and. &
                    K_START == k )
              WORK = SLA_SAVE(:,:,kbt,k,bid) * RB(:,:,bid)
            endwhere
          endif

          where ( WORK /= c0  .and.  &
           TLT%DIABATIC_DEPTH(:,:,bid) <  (reference_depth(kk) - WORK) )
            COMPUTE_TLT = .false.
          endwhere

          where ( WORK /= c0  .and.  &
           TLT%DIABATIC_DEPTH(:,:,bid) >= (reference_depth(kk) - WORK) )
            TLT%THICKNESS(:,:,bid) = reference_depth(kk)  &
                                    - TLT%DIABATIC_DEPTH(:,:,bid)
            TLT%K_LEVEL(:,:,bid)   = k
            TLT%ZTW(:,:,bid)       = kk
          endwhere

        enddo

        where ( COMPUTE_TLT  .and.  K_START == k )
          K_START = K_START + 1
        endwhere

      enddo

#ifdef CCSMCOUPLED
#ifndef _HIRES
      if ( any(COMPUTE_TLT) ) then
        call shr_sys_abort ('Incorrect TLT computations')
      endif
#endif
#endif

!-----------------------------------------------------------------------
!
!     compute the depth at which the interior, adiabatic region starts
!
!-----------------------------------------------------------------------

      do k=1,km
        where ( TLT%K_LEVEL(:,:,bid) == k  .and.  &
                TLT%ZTW(:,:,bid) == 1 )
          TLT%INTERIOR_DEPTH(:,:,bid) = zt(k)
        endwhere
        where ( TLT%K_LEVEL(:,:,bid) == k  .and.  &
                TLT%ZTW(:,:,bid) == 2 )
          TLT%INTERIOR_DEPTH(:,:,bid) = zw(k)
        endwhere
      enddo

      COMPUTE_TLT = .false.
      where ( KMT(:,:,bid) /= 0  .and.  &
              TLT%INTERIOR_DEPTH(:,:,bid) == c0 )  &
        COMPUTE_TLT = .true.
      where ( KMT(:,:,bid) == 0  .and.  &
              TLT%INTERIOR_DEPTH(:,:,bid) /= c0 )  &
        COMPUTE_TLT = .true.

#ifdef CCSMCOUPLED
#ifndef _HIRES
      if ( any(COMPUTE_TLT) ) then
        call shr_sys_abort ('Incorrect TLT%INTERIOR_DEPTH computation')
      endif
#endif
#endif

!-----------------------------------------------------------------------
!EOC

      end subroutine transition_layer

!***********************************************************************
!BOP
! !IROUTINE: merged_streamfunction 
! !INTERFACE:


      subroutine merged_streamfunction ( this_block ) 1

! !DESCRIPTION:
!  Construct a merged streamfunction that has the appropriate
!  behavior in the surface diabatic region, transition layer, and
!  adiabatic interior
!
! !REVISION HISTORY:
!  same as module

! !INPUT PARAMETERS:

      type (block), intent(in) :: &
         this_block          ! block info for this sub block

!EOP
!BOC
!-----------------------------------------------------------------------
!
!     local variables
!
!-----------------------------------------------------------------------

      integer (int_kind) :: &
         k, kk,     &        ! loop indices
         bid                 ! local block address for this sub block
 
      real (r8), dimension(nx_block,ny_block,2) :: &
         WORK1, WORK2, WORK3, WORK4   ! work arrays

      real (r8), dimension(nx_block,ny_block) :: &
         WORK2_NEXT, WORK4_NEXT       ! WORK2 or WORK4 at next level

      real (r8), dimension(nx_block,ny_block) :: &
         WORK5, WORK6, WORK7          ! more work arrays

      logical (log_kind), dimension(nx_block,ny_block) :: &
         LMASK               ! flag

      real (r8), dimension(2) :: &
         reference_depth              ! zt or zw

!-----------------------------------------------------------------------
!
!     initialize various quantities
!
!-----------------------------------------------------------------------

      bid = this_block%local_id

      SF_SLX(:,:,:,:,:,bid) = c0
      SF_SLY(:,:,:,:,:,bid) = c0

      WORK1 = c0
      WORK2 = c0
      WORK3 = c0
      WORK4 = c0
      WORK5 = c0
      WORK6 = c0
      WORK7 = c0
      WORK2_NEXT = c0
      WORK4_NEXT = c0

!-----------------------------------------------------------------------
!
!     compute the interior streamfunction and its first derivative at the
!     INTERIOR_DEPTH level. WORK1 and WORK2 contain the streamfunction
!     and its first derivative, respectively, for the zonal component
!     for the east and west sides of a grid cell. WORK3 and WORK4 are
!     the corresponding fields for the meridional component for the
!     north and south sides of a grid cell. Note that these definitions
!     include a "dz". Also, the first derivative computations assume 
!     that the streamfunctions are located in the middle of the top or
!     bottom half of a grid cell, hence a factor of two in WORK2 and
!     WORK4 calculations. 
!
!-----------------------------------------------------------------------

      do k=1,km-1

        do kk=1,2

          LMASK = TLT%K_LEVEL(:,:,bid) == k  .and.            &
                  TLT%K_LEVEL(:,:,bid) < KMT(:,:,bid)  .and.  &
                  TLT%ZTW(:,:,bid) == 1

          where ( LMASK ) 

            WORK1(:,:,kk) =  KAPPA_THIC(:,:,kbt,k,bid)  &
                           * SLX(:,:,kk,kbt,k,bid) * dz(k)
            WORK2(:,:,kk) = c2 * dzwr(k) * ( WORK1(:,:,kk)            &
              - KAPPA_THIC(:,:,ktp,k+1,bid) * SLX(:,:,kk,ktp,k+1,bid) &
                                            * dz(k+1) )

            WORK2_NEXT = c2 * ( &
              KAPPA_THIC(:,:,ktp,k+1,bid) * SLX(:,:,kk,ktp,k+1,bid) - &
              KAPPA_THIC(:,:,kbt,k+1,bid) * SLX(:,:,kk,kbt,k+1,bid) )

            WORK3(:,:,kk) =  KAPPA_THIC(:,:,kbt,k,bid)  &
                           * SLY(:,:,kk,kbt,k,bid) * dz(k)
            WORK4(:,:,kk) = c2 * dzwr(k) * ( WORK3(:,:,kk)            &
              - KAPPA_THIC(:,:,ktp,k+1,bid) * SLY(:,:,kk,ktp,k+1,bid) &
                                            * dz(k+1) )

            WORK4_NEXT = c2 * ( &
              KAPPA_THIC(:,:,ktp,k+1,bid) * SLY(:,:,kk,ktp,k+1,bid) - &
              KAPPA_THIC(:,:,kbt,k+1,bid) * SLY(:,:,kk,kbt,k+1,bid) )

          endwhere

          where ( LMASK .and. abs(WORK2_NEXT) < abs(WORK2(:,:,kk)) ) &
            WORK2(:,:,kk) = WORK2_NEXT

          where ( LMASK .and. abs(WORK4_NEXT) < abs(WORK4(:,:,kk)) ) &
            WORK4(:,:,kk) = WORK4_NEXT

          LMASK = TLT%K_LEVEL(:,:,bid) == k  .and.           &
                  TLT%K_LEVEL(:,:,bid) < KMT(:,:,bid)  .and. &
                  TLT%ZTW(:,:,bid) == 2

          where ( LMASK )

            WORK1(:,:,kk) =  KAPPA_THIC(:,:,ktp,k+1,bid)     & 
                           * SLX(:,:,kk,ktp,k+1,bid)
            WORK2(:,:,kk) =  c2 * ( WORK1(:,:,kk)                 &
                           - ( KAPPA_THIC(:,:,kbt,k+1,bid)        &
                              * SLX(:,:,kk,kbt,k+1,bid) ) )
            WORK1(:,:,kk) = WORK1(:,:,kk) * dz(k+1)

            WORK3(:,:,kk) =  KAPPA_THIC(:,:,ktp,k+1,bid)     &
                           * SLY(:,:,kk,ktp,k+1,bid)
            WORK4(:,:,kk) =  c2 * ( WORK3(:,:,kk)                 &
                           - ( KAPPA_THIC(:,:,kbt,k+1,bid)        &
                              * SLY(:,:,kk,kbt,k+1,bid) ) )
            WORK3(:,:,kk) = WORK3(:,:,kk) * dz(k+1)

          endwhere

          LMASK = LMASK .and. TLT%K_LEVEL(:,:,bid) + 1 < KMT(:,:,bid)

          where ( LMASK )

            WORK2_NEXT = c2 * dzwr(k+1) * ( &
              KAPPA_THIC(:,:,kbt,k+1,bid) * SLX(:,:,kk,kbt,k+1,bid) * dz(k+1) - &
              KAPPA_THIC(:,:,ktp,k+2,bid) * SLX(:,:,kk,ktp,k+2,bid) * dz(k+2))

            WORK4_NEXT = c2 * dzwr(k+1) * ( &
              KAPPA_THIC(:,:,kbt,k+1,bid) * SLY(:,:,kk,kbt,k+1,bid) * dz(k+1) - &
              KAPPA_THIC(:,:,ktp,k+2,bid) * SLY(:,:,kk,ktp,k+2,bid) * dz(k+2))

          endwhere

          where ( LMASK .and. abs(WORK2_NEXT) < abs(WORK2(:,:,kk)) ) &
            WORK2(:,:,kk) = WORK2_NEXT

          where ( LMASK .and. abs(WORK4_NEXT) < abs(WORK4(:,:,kk)) ) &
            WORK4(:,:,kk) = WORK4_NEXT

        enddo

      enddo

!-----------------------------------------------------------------------
!
!     compute the depth independent interpolation factors used in the 
!     linear and quadratic interpolations within the diabatic and 
!     transition regions, respectively.
!
!-----------------------------------------------------------------------

      WORK5 = c0
      where (KMT(:,:,bid) /= 0)
        WORK5(:,:) = c1 / ( c2 * TLT%DIABATIC_DEPTH(:,:,bid) &
                   + TLT%THICKNESS(:,:,bid) )
      endwhere

      WORK6 = c0
      where ((KMT(:,:,bid) /= 0) .AND. (TLT%THICKNESS(:,:,bid) > eps))
        WORK6(:,:) = WORK5(:,:) / TLT%THICKNESS(:,:,bid)
      endwhere

!-----------------------------------------------------------------------
!
!     start of interpolation to construct the merged streamfunction
!
!-----------------------------------------------------------------------

      do k=1,km

        reference_depth(ktp) = zt(k) - p25 * dz(k)
        reference_depth(kbt) = zt(k) + p25 * dz(k)

        do kk=ktp,kbt

!-----------------------------------------------------------------------
!
!     diabatic region: use linear interpolation (in streamfunction) 
!
!-----------------------------------------------------------------------

          where ( reference_depth(kk) <= TLT%DIABATIC_DEPTH(:,:,bid)  &
                  .and.  k <= KMT(:,:,bid) ) 

            SF_SLX(:,:,1,kk,k,bid) = reference_depth(kk) * WORK5  &
                  * ( c2 * WORK1(:,:,1) + TLT%THICKNESS(:,:,bid)  &
                     * WORK2(:,:,1) )

            SF_SLX(:,:,2,kk,k,bid) = reference_depth(kk) * WORK5  &
                  * ( c2 * WORK1(:,:,2) + TLT%THICKNESS(:,:,bid)  &
                     * WORK2(:,:,2) )

            SF_SLY(:,:,1,kk,k,bid) = reference_depth(kk) * WORK5  &
                  * ( c2 * WORK3(:,:,1) + TLT%THICKNESS(:,:,bid)  &
                     * WORK4(:,:,1) )

            SF_SLY(:,:,2,kk,k,bid) = reference_depth(kk) * WORK5  &
                  * ( c2 * WORK3(:,:,2) + TLT%THICKNESS(:,:,bid)  &
                     * WORK4(:,:,2) )

          endwhere

!-----------------------------------------------------------------------
!
!     transition layer: use quadratic interpolation (in streamfunction) 
!
!-----------------------------------------------------------------------

          where ( reference_depth(kk) > TLT%DIABATIC_DEPTH(:,:,bid)   &
            .and.  reference_depth(kk) <= TLT%INTERIOR_DEPTH(:,:,bid) &
            .and.  k <= KMT(:,:,bid) )

            WORK7 = (TLT%DIABATIC_DEPTH(:,:,bid)  &
                     - reference_depth(kk))**2

            SF_SLX(:,:,1,kk,k,bid) = - WORK7 * WORK6            &
                * ( WORK1(:,:,1) + TLT%INTERIOR_DEPTH(:,:,bid)  &
                   * WORK2(:,:,1) )                             &
               + reference_depth(kk) * WORK5                    &
                * ( c2 * WORK1(:,:,1) + TLT%THICKNESS(:,:,bid)  &
                   * WORK2(:,:,1) )

            SF_SLX(:,:,2,kk,k,bid) = - WORK7 * WORK6            &
                * ( WORK1(:,:,2) + TLT%INTERIOR_DEPTH(:,:,bid)  &
                   * WORK2(:,:,2) )                             &
               + reference_depth(kk) * WORK5                    &
                * ( c2 * WORK1(:,:,2) + TLT%THICKNESS(:,:,bid)  &
                   * WORK2(:,:,2) )

            SF_SLY(:,:,1,kk,k,bid) = - WORK7 * WORK6            &
                * ( WORK3(:,:,1) + TLT%INTERIOR_DEPTH(:,:,bid)  &
                   * WORK4(:,:,1) )                             &
               + reference_depth(kk) * WORK5                    &
                * ( c2 * WORK3(:,:,1) + TLT%THICKNESS(:,:,bid)  &
                   * WORK4(:,:,1) )

            SF_SLY(:,:,2,kk,k,bid) = - WORK7 * WORK6            &
                * ( WORK3(:,:,2) + TLT%INTERIOR_DEPTH(:,:,bid)  &
                   * WORK4(:,:,2) )                             &
               + reference_depth(kk) * WORK5                    &
                * ( c2 * WORK3(:,:,2) + TLT%THICKNESS(:,:,bid)  &
                   * WORK4(:,:,2) )

          endwhere

!-----------------------------------------------------------------------
!
!     interior, adiabatic region: no interpolation is needed. note that
!     "dzw" is introduced here, too, for consistency. 
!
!-----------------------------------------------------------------------

          where ( reference_depth(kk) > TLT%INTERIOR_DEPTH(:,:,bid)  & 
                  .and.  k <= KMT(:,:,bid) )

            SF_SLX(:,:,1,kk,k,bid) =  KAPPA_THIC(:,:,kk,k,bid)  &
                              * SLX(:,:,1,kk,k,bid) * dz(k)

            SF_SLX(:,:,2,kk,k,bid) =  KAPPA_THIC(:,:,kk,k,bid)  &
                              * SLX(:,:,2,kk,k,bid) * dz(k)

            SF_SLY(:,:,1,kk,k,bid) =  KAPPA_THIC(:,:,kk,k,bid)  &
                              * SLY(:,:,1,kk,k,bid) * dz(k)

            SF_SLY(:,:,2,kk,k,bid) =  KAPPA_THIC(:,:,kk,k,bid)  &
                              * SLY(:,:,2,kk,k,bid) * dz(k)

          endwhere

        enddo  ! end of kk-loop

      enddo    ! end of k-loop

!-----------------------------------------------------------------------
!EOC

      end subroutine merged_streamfunction

!***********************************************************************
!BOP
! !IROUTINE: apply_vertical_profile_to_isop_hor_diff 
! !INTERFACE:


      subroutine apply_vertical_profile_to_isop_hor_diff ( this_block )  1

! !DESCRIPTION:
!  Apply vertical tapers to KAPPA_ISOP and HOR_DIFF based on their
!  vertical location with respect to the diabatic, transition, and
!  adiabatic regions.
!
! !REVISION HISTORY:
!  same as module

! !INPUT PARAMETERS:

      type (block), intent(in) :: &
         this_block          ! block info for this sub block

!EOP
!BOC
!-----------------------------------------------------------------------
!
!     local variables
!
!-----------------------------------------------------------------------

      integer (int_kind) :: &
         k, kk,     &        ! loop indices
         bid                 ! local block address for this sub block

      real (r8), dimension(2) :: &
         reference_depth

      bid = this_block%local_id

!-----------------------------------------------------------------------
!
!     start of tapering
!
!-----------------------------------------------------------------------

      do k=1,km

        reference_depth(ktp) = zt(k) - p25 * dz(k)
        reference_depth(kbt) = zt(k) + p25 * dz(k)

        do kk=ktp,kbt

!-----------------------------------------------------------------------
!
!     diabatic region: no isopycnal diffusion 
!
!-----------------------------------------------------------------------

          where ( reference_depth(kk) <= TLT%DIABATIC_DEPTH(:,:,bid)  &
                  .and.  k <= KMT(:,:,bid) ) 
            KAPPA_ISOP(:,:,kk,k,bid) = c0
          endwhere

!-----------------------------------------------------------------------
!
!      transition layer: a linear combination of isopcynal and horizontal
!      diffusion coefficients 
!
!-----------------------------------------------------------------------

          where ( reference_depth(kk) > TLT%DIABATIC_DEPTH(:,:,bid)   &
            .and.  reference_depth(kk) <= TLT%INTERIOR_DEPTH(:,:,bid) &
            .and.  k <= KMT(:,:,bid)  .and.                           &
                   TLT%THICKNESS(:,:,bid) > eps )

            HOR_DIFF(:,:,kk,k,bid) = ( TLT%INTERIOR_DEPTH(:,:,bid)  &
                  - reference_depth(kk) ) * HOR_DIFF(:,:,kk,k,bid)  &
                  / TLT%THICKNESS(:,:,bid)
            KAPPA_ISOP(:,:,kk,k,bid) = ( reference_depth(kk)        &
                                   - TLT%DIABATIC_DEPTH(:,:,bid) )  &
                 * KAPPA_ISOP(:,:,kk,k,bid) / TLT%THICKNESS(:,:,bid)

          endwhere

!-----------------------------------------------------------------------
!
!     interior region: no horizontal diffusion
!
!-----------------------------------------------------------------------

          where ( reference_depth(kk) > TLT%INTERIOR_DEPTH(:,:,bid)  &
                  .and.  k <= KMT(:,:,bid) )
            HOR_DIFF(:,:,kk,k,bid) = c0
          endwhere

        enddo  ! end of kk-loop

      enddo    ! end of k-loop

!-----------------------------------------------------------------------
!EOC

      end subroutine apply_vertical_profile_to_isop_hor_diff

!***********************************************************************

      end module hmix_gm

!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||