!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! !!
!! GNU General Public License !!
!! !!
!! This file is part of the Flexible Modeling System (FMS). !!
!! !!
!! FMS is free software; you can redistribute it and/or modify !!
!! it and are expected to follow the terms of the GNU General Public !!
!! License as published by the Free Software Foundation. !!
!! !!
!! FMS is distributed in the hope that it will be useful, !!
!! but WITHOUT ANY WARRANTY; without even the implied warranty of !!
!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the !!
!! GNU General Public License for more details. !!
!! !!
!! You should have received a copy of the GNU General Public License !!
!! along with FMS; if not, write to: !!
!! Free Software Foundation, Inc. !!
!! 59 Temple Place, Suite 330 !!
!! Boston, MA 02111-1307 USA !!
!! or see: !!
!! http://www.gnu.org/licenses/gpl.txt !!
!! !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
module ocean_convect_mod
!
! Stephen M. Griffies
!
!
! R. Fiedler
!
!
!
! Vertically adjusts gravitationally unstable columns of ocean fluid.
!
!
!
! This module vertically adjusts gravitationally unstable columns of
! ocean fluid. Three algorithms are available:
!
! 1. Full convection from Rahmstorf. The algorithm produces a fully
! stable fluid column. Since most convection propagates downward, the
! scheme looks downward first and follows any instability (upward or
! downward) before checking the other direction. The routine mixes
! passive tracers only after the entire instability is found.
!
! 2. Full convection from Rahmstorf as optimized for vector machines
! by Russ Fiedler.
!
! 3. The Cox (1984) NCON-scheme. This scheme is recommended only
! for those wishing to maintain legacy code.
!
!
!
!
!
!
! Stefan Rahmstorf (Ocean Modelling, 1993 vol 101 pages 9-11)
!
!
!
! Implementation of the full convection scheme is
! based on mom2/3 code by Stefan Rahmstorf
! (rahmstorf@pik-potsdam.de). But modified slightly
! for efficiency purposes in mom3.1
! by M. Eby (eby@uvic.ca) in June 2000. Notably, Eby
! eliminated goto statements.
!
!
!
! The Eby code was ported to mom4 by Griffies (Stephen.Griffies@noaa.gov).
!
!
!
! To recover the exact same numerical values as the original
! Rahmstorf code, look for the two "Rahmstorf" comments in the code.
!
!
!
!
!
! Must be true to use this module. Default is false.
!
!
!
! If true, will use the old NCON convection scheme from Cox. Recommended only
! if wishing to reproduce old results.
!
!
! Number of passes through the NCON-scheme.
!
!
! If true, will use the full convection scheme as implemented at GFDL for scalar
! machines.
!
!
! If true, will use the full convection scheme as optimized for vector machines
! by Russ Fiedler.
!
!
!
use diag_manager_mod, only: register_diag_field, send_data
use fms_mod, only: open_namelist_file, check_nml_error
use fms_mod, only: write_version_number, close_file
use fms_mod, only: mpp_error, FATAL, stdout, stdlog
use ocean_density_mod, only: density
use ocean_domains_mod, only: get_local_indices
use ocean_parameters_mod, only: missing_value
use ocean_types_mod, only: ocean_time_type, ocean_grid_type, ocean_domain_type, ocean_options_type
use ocean_types_mod, only: ocean_density_type, ocean_prog_tracer_type, ocean_thickness_type
use ocean_workspace_mod, only: wrk1
implicit none
private
public ocean_convect_init
public convection
private convection_ncon
private convection_full_scalar
private convection_full_vector
! for diagnostics
integer :: id_ktot=-1
integer :: id_kven=-1
integer, allocatable, dimension(:) :: id_convect
logical :: used
integer :: nkm1
integer :: index_temp=-1
integer :: index_salt=-1
real :: dtimer
type(ocean_grid_type), pointer :: Grd =>NULL()
type(ocean_domain_type), pointer :: Dom =>NULL()
integer :: isd, ied, jsd, jed, isc, iec, jsc, jec, nk
character(len=128) :: version=&
'$Id: ocean_convect.F90,v 16.0.108.1 2009/10/10 00:42:17 nnz Exp $'
character (len=128) :: tagname = &
'$Name: mom4p1_pubrel_dec2009_nnz $'
logical :: module_is_initialized=.FALSE.
logical :: use_this_module =.false.
logical :: convect_ncon =.false. ! for Cox ncon scheme. if false, use Rahmstorf full convection
logical :: convect_full_scalar =.false. ! for full convection scheme implemented at GFDL on scalar machines
logical :: convect_full_vector =.false. ! for full convection scheme implemented at CSIRO on vector machines
integer :: ncon=7 ! number of passes through a column for convect_ncon=.true.
namelist /ocean_convect_nml/ use_this_module, convect_ncon, ncon, convect_full_scalar, convect_full_vector
contains
!#######################################################################
!
!
!
!
! Initialize the convection module.
!
! For the full convection module, we register two fields
! for diagnostic output.
!
! ktot = number of levels convected in a vertical column
!
! kven = number of levels ventilated in a vertical column
!
! Note that ktot can in rare cases count some levels twice, if they
! get involved in two originally separate, but then
! overlapping convection areas in the water column. The field
! kven is 0 on land, 1 on ocean points with no
! convection, and any value up to nk on convecting points.
!
!
subroutine ocean_convect_init (Grid, Domain, Time, T_prog, Ocean_options, dtime)
type(ocean_grid_type), intent(in), target :: Grid
type(ocean_domain_type), intent(in), target :: Domain
type(ocean_time_type), intent(in) :: Time
type(ocean_prog_tracer_type), intent(inout) :: T_prog(:)
type(ocean_options_type), intent(inout) :: Ocean_options
real, intent(in) :: dtime
integer :: n, num_prog_tracers, ioun, ierr, io_status
integer :: stdoutunit,stdlogunit
stdoutunit=stdout();stdlogunit=stdlog()
if ( module_is_initialized ) then
call mpp_error(FATAL,&
'==>Error in ocean_convect_mod (ocean_convect_init): module already initialized')
endif
module_is_initialized = .TRUE.
call write_version_number( version, tagname )
num_prog_tracers = size(T_prog(:))
allocate( id_convect(num_prog_tracers) )
id_convect(:) = -1
do n=1,num_prog_tracers
if (T_prog(n)%name == 'temp') index_temp = n
if (T_prog(n)%name == 'salt') index_salt = n
enddo
Grd => Grid
Dom => Domain
call get_local_indices(Dom, isd, ied, jsd, jed, isc, iec, jsc, jec)
nk = Grd%nk
nkm1 = nk-1
! provide for namelist over-ride of default values
ioun = open_namelist_file()
read (ioun,ocean_convect_nml,IOSTAT=io_status)
write (stdoutunit,'(/)')
write (stdoutunit,ocean_convect_nml)
write (stdlogunit,ocean_convect_nml)
ierr = check_nml_error(io_status,'ocean_convect_nml')
call close_file (ioun)
if(use_this_module) then
write(stdoutunit,'(a)') &
'==>Note: Using convective adjustment to stabilize gravitationally unstable water columns.'
Ocean_options%convective_adjustment = 'Used convective adjustment.'
else
write(stdoutunit,'(a)') &
'==>Note: NOT using convective adjustment in gravitationally unstable water columns.'
Ocean_options%convective_adjustment = 'Did NOT use convective adjustment.'
return
endif
if(convect_ncon) then
write(stdoutunit,'(a,i3)')' ==>Note: Using the Cox NCON convection scheme with ncon= ', ncon
elseif(convect_full_vector .or. convect_full_scalar) then
write(stdoutunit,'(a)')' ==>Note: Using the Rahmstorf full convection scheme'
if(convect_full_scalar .and. convect_full_vector) then
call mpp_error(FATAL,&
'==>Error in ocean_convect_mod: "convect_full_vector" and "convect_full_scalar" cannot both be true.')
endif
if(convect_full_vector) then
write(stdoutunit,'(a)')' as implemented on vector machines at CSIRO/Hobart.'
endif
if(convect_full_scalar) then
write(stdoutunit,'(a)')' as implemented on scalar machines at GFDL.'
endif
else
write(stdoutunit,'(a)')&
'==>Error in ocean_convect_mod: no convective adjustment selected, yet use_this_module=.true.. '
write(stdoutunit,'(a)')&
' Choose one of the following: "convect_ncon", "convect_full_vector", or "convect_full_scalar"'
call mpp_error(FATAL,&
'==>ocean_convect_mod: convective adjustment not chosen. Must choose a scheme since use_this_module=.true.')
endif
! register fields for diagnostic output
dtimer = 1.0/dtime
do n=1,num_prog_tracers
id_convect(n) = -1
if (n == index_temp) then
id_convect(n) = register_diag_field ('ocean_model', 'convect_heating', &
Grid%tracer_axes(1:3), Time%model_time, 'heating due to convection', &
'Watts/m^2', missing_value=missing_value, range=(/-1.e10,1.e10/))
else
id_convect(n) = register_diag_field ('ocean_model', 'convect_'//trim(T_prog(n)%name), &
Grid%tracer_axes(1:3), Time%model_time, 'rho*dzt*th_tendency due to convection', &
'm*kg/sec', missing_value=missing_value, range=(/-1.e10,1.e10/))
endif
enddo
id_ktot = register_diag_field ('ocean_model', 'ktot', Grid%tracer_axes(1:2), Time%model_time, &
'number convecting levels', 'number', missing_value=missing_value, range=(/-10.0,1.e20/))
id_kven = register_diag_field ('ocean_model', 'kven', Grid%tracer_axes(1:2), Time%model_time, &
'number ventilated levels', 'number', missing_value=missing_value, range=(/-10.0,1.e20/))
end subroutine ocean_convect_init
! NAME="ocean_convect_init"
!#######################################################################
!
!
!
! Subroutine calls one of the two possible convection schemes.
!
!
subroutine convection (Time, Thickness, T_prog, Dens)
type(ocean_time_type), intent(in) :: Time
type(ocean_thickness_type), intent(in) :: Thickness
type(ocean_prog_tracer_type), intent(inout) :: T_prog(:)
type(ocean_density_type), intent(in) :: Dens
if (.not. use_this_module) return
if (.not. module_is_initialized ) then
call mpp_error(FATAL,'==>Error in ocean_convect_mod (convection): module needs to be initialized')
endif
if(convect_ncon) then
call convection_ncon(Time, Thickness, T_prog, Dens)
else
if(convect_full_scalar) call convection_full_scalar(Time, Thickness, T_prog, Dens)
if(convect_full_vector) call convection_full_vector(Time, Thickness, T_prog, Dens)
endif
end subroutine convection
! NAME="convection"
!#######################################################################
!
!
!
! Subroutine to vertically adjust gravitationally unstable columns of ocean fluid.
! Produces updated values for all the tracers. Code implemented on scalar
! machines at GFDL. Has been found to be slow on vector machines. Use
! convection_full_vector for vector machines.
!
! internal variables:
!
! chk_la = logical flag to check level above kt
!
! chk_lb = logical flag to check level below kb
!
! kb = bottom level of (potential) instability
!
! kbo = bottom level of ocean
!
! kt = top level of (potential) instability
!
! la = test level above kt
!
! lb = test level below kb
!
! rl = lower level density referenced to lower level
!
! ru = upper level density referenced to lower level
!
! tmx = mixed tracer (1=temp, 2=salt, 3=other)
!
! tsm = sum of tracers (weighted by thickness) in the instability
!
! zsm = total thickness of the instability
!
!
!
subroutine convection_full_scalar (Time, Thickness, T_prog, Dens)
type(ocean_time_type), intent(in) :: Time
type(ocean_thickness_type), intent(in) :: Thickness
type(ocean_prog_tracer_type), intent(inout) :: T_prog(:)
type(ocean_density_type), intent(in) :: Dens
real, dimension(3) :: tmx, tsm
real, dimension(isc:iec,jsc:jec) :: ktot, kven
integer :: i, j, k, n, kb, kbo, kt, la, lb, taup1, tau
real :: rl, ru, zsm
logical :: chk_la, chk_lb
if (.not. module_is_initialized ) then
call mpp_error(FATAL,'==>Error in ocean_convect_mod (convection_full_scalar): module needs to be initialized')
endif
! for diagnostics, save initial value of the tracers
taup1 = Time%taup1
tau = Time%tau
do n=1, size(T_prog(:))
T_prog(n)%wrk1(:,:,:) = T_prog(n)%field(:,:,:,taup1)
enddo
do j=jsc,jec
do i=isc,iec
kbo = Grd%kmt(i,j)
ktot(i,j) = 0.0
kven(i,j) = 0.0
! search for unstable regions starting from the top
kt = 1
kb = 2
do while (kt < kbo)
ru = density (T_prog(index_salt)%field(i,j,kt,taup1),&
T_prog(index_temp)%field(i,j,kt,taup1),&
Dens%pressure_at_depth(i,j,kb))
rl = density (T_prog(index_salt)%field(i,j,kb,taup1),&
T_prog(index_temp)%field(i,j,kb,taup1),&
Dens%pressure_at_depth(i,j,kb))
! sum the first pair found in an unstable region
if (ru > rl) then
chk_la = .true.
chk_lb = .true.
zsm = Thickness%rho_dzt(i,j,kt,taup1) + Thickness%rho_dzt(i,j,kb,taup1)
tsm(1) = T_prog(index_temp)%field(i,j,kt,taup1)*Thickness%rho_dzt(i,j,kt,taup1) &
+ T_prog(index_temp)%field(i,j,kb,taup1)*Thickness%rho_dzt(i,j,kb,taup1)
tmx(1) = tsm(1)/zsm
tsm(2) = T_prog(index_salt)%field(i,j,kt,taup1)*Thickness%rho_dzt(i,j,kt,taup1) &
+ T_prog(index_salt)%field(i,j,kb,taup1)*Thickness%rho_dzt(i,j,kb,taup1)
tmx(2) = tsm(2)/zsm
do while (chk_lb .or. chk_la)
! check for an unstable level (lb) below kb
if (kb >= kbo) chk_lb = .false.
do while (chk_lb)
chk_lb = .false.
lb = kb + 1
ru = density (tmx(2) ,tmx(1) ,Dens%pressure_at_depth(i,j,lb))
rl = density (T_prog(index_salt)%field(i,j,lb,taup1),&
T_prog(index_temp)%field(i,j,lb,taup1),&
Dens%pressure_at_depth(i,j,lb))
if (ru > rl) then
! add new level to sums
kb = lb
zsm = zsm + Thickness%rho_dzt(i,j,kb,taup1)
tsm(1) = tsm(1) + T_prog(index_temp)%field(i,j,kb,taup1)*Thickness%rho_dzt(i,j,kb,taup1)
tmx(1) = tsm(1)/zsm
tsm(2) = tsm(2) + T_prog(index_salt)%field(i,j,kb,taup1)*Thickness%rho_dzt(i,j,kb,taup1)
tmx(2) = tsm(2)/zsm
chk_la = .true.
if (kb < kbo) chk_lb = .true.
endif
enddo
! check for an unstable level (la) above kt
! To get equivalent of original Rahmstorf code, uncomment next line
! chk_la = .true.
if (kt <= 1) chk_la = .false.
do while (chk_la)
chk_la = .false.
la = kt - 1
ru = density (T_prog(index_salt)%field(i,j,la,taup1),&
T_prog(index_temp)%field(i,j,la,taup1),&
Dens%pressure_at_depth(i,j,kt))
rl = density (tmx(2), tmx(1), Dens%pressure_at_depth(i,j,kt))
if (ru > rl) then
! add new level to sums
kt = la
zsm = zsm + Thickness%rho_dzt(i,j,kt,taup1)
tsm(1) = tsm(1) + T_prog(index_temp)%field(i,j,kt,taup1)*Thickness%rho_dzt(i,j,kt,taup1)
tmx(1) = tsm(1)/zsm
tsm(2) = tsm(2) + T_prog(index_salt)%field(i,j,kt,taup1)*Thickness%rho_dzt(i,j,kt,taup1)
tmx(2) = tsm(2)/zsm
chk_lb = .true.
! to get equivalent of original Rahmstorf code, comment out next line
if (kt > 1) chk_la = .true.
endif
enddo
enddo
! mix all tracers from kt to kb
do k=kt,kb
T_prog(index_temp)%field(i,j,k,taup1) = tmx(1)
T_prog(index_salt)%field(i,j,k,taup1) = tmx(2)
enddo
do n=1,size(T_prog(:))
if (n /= index_temp .and. n /= index_salt) then
tsm(3) = 0.0
do k=kt,kb
tsm(3) = tsm(3) + T_prog(n)%field(i,j,k,taup1)*Thickness%rho_dzt(i,j,k,taup1)
enddo
tmx(3) = tsm(3)/zsm
do k=kt,kb
T_prog(n)%field(i,j,k,taup1) = tmx(3)
enddo
endif
enddo
! compute diagnostic fields
ktot(i,j) = ktot(i,j) + kb - kt + 1
if (kt == 1) kven(i,j) = kb
kt = kb + 1
else
kt = kb
endif
! continue the search for other unstable regions
kb = kt + 1
enddo ! while (kt < kbo)
enddo ! i=isc,iec
enddo ! j=jsc,jec
if (id_ktot > 0) used = send_data (id_ktot, ktot(isc:iec,jsc:jec), &
Time%model_time, rmask=Grd%tmask(isc:iec,jsc:jec,1))
if (id_kven > 0) used = send_data (id_kven, kven(isc:iec,jsc:jec), &
Time%model_time, rmask=Grd%tmask(isc:iec,jsc:jec,1))
do n=1,size(T_prog(:))
if (id_convect(n) > 0) then
do k=1,nk
do j=jsc,jec
do i=isc,iec
T_prog(n)%wrk1(i,j,k) = dtimer*(T_prog(n)%field(i,j,k,taup1) - T_prog(n)%wrk1(i,j,k))
enddo
enddo
T_prog(n)%wrk1(isc:iec,jsc:jec,k) = T_prog(n)%wrk1(isc:iec,jsc:jec,k)*&
T_prog(n)%conversion*Thickness%rho_dzt(isc:iec,jsc:jec,k,taup1)
enddo
used = send_data(id_convect(n), T_prog(n)%wrk1(:,:,:), &
Time%model_time, rmask=Grd%tmask(:,:,:), &
is_in=isc, js_in=jsc, ks_in=1, ie_in=iec, je_in=jec, ke_in=nk)
endif
enddo
end subroutine convection_full_scalar
! NAME="convection_full_scalar"
!#######################################################################
!
!
!
! Subroutine to vertically adjust gravitationally unstable columns of ocean fluid.
! Produces updated values for all the tracers. Code implemented on vector
! machines at CSIRO. Has been found to be faster on these machines than
! convection_full_scalar. Answers differ, but not significantly.
!
! Code written by russell.fiedler@csiro.au
! most recently modified Aug2005
!
! internal variables:
!
! chk_la = logical flag to check level above kt
!
! chk_lb = logical flag to check level below kb
!
! kb = bottom level of (potential) instability
!
! kbo = bottom level of ocean
!
! kt = top level of (potential) instability
!
! la = test level above kt
!
! lb = test level below kb
!
! rl = lower level density referenced to lower level
!
! ru = upper level density referenced to lower level
!
! tmx = mixed tracer (1=temp, 2=salt, 3=other)
!
! tsm = sum of tracers (weighted by thickness) in the instability
!
! zsm = total thickness of the instability
!
!
!
subroutine convection_full_vector (Time, Thickness, T_prog, Dens)
type(ocean_time_type), intent(in) :: Time
type(ocean_thickness_type), intent(in) :: Thickness
type(ocean_prog_tracer_type), intent(inout) :: T_prog(:)
type(ocean_density_type), intent(in) :: Dens
real, dimension(3) :: tmx, tsm
real, dimension(isc:iec,jsc:jec) :: ktot, kven
integer :: i, j, k, n, kb, kbo, kt, la, lb, taup1, tau
real :: rl, ru, zsm
logical :: chk_la, chk_lb
! additions for vectorised code
logical :: unstable(isc:iec)
integer :: ikven(isc:iec,jsc:jec), kt_temp(isc:iec)
real :: zsum(isc:iec),zsum1(isc:iec)
real :: rl_line(isd:ied), ru_line(isd:ied)
real :: ratio1(isc:iec),ratio2(isc:iec)
integer :: ikunstable, nunstable
integer,dimension((iec-isc+1)*nk) :: iindex,kindex
if (.not. module_is_initialized ) then
call mpp_error(FATAL,'==>Error in ocean_convect_mod (convection_full_vector): module needs to be initialized')
endif
! for diagnostics, save initial value of the tracers
taup1 = Time%taup1
tau = Time%tau
do n=1, size(T_prog(:))
T_prog(n)%wrk1(:,:,:) = T_prog(n)%field(:,:,:,taup1)
enddo
!
! First we treat instabilities arising at the surface.
!
do j=jsc,jec
!
! Initialise instability flag. Mask land points.
!
do i=isc,iec
if(Grd%kmt(i,j) .ne. 0) then
unstable(i)=.true.
else
unstable(i)=.false.
endif
ikven(i,j)=0
zsum1(i)=Thickness%rho_dzt(i,j,1,taup1)
enddo
do k=1,nk-1
!
! Calculate depth of this cell and the one below it; If we hit land column has
! been stabilised.
!
do i=isc,iec
zsum(i)=zsum1(i)
zsum1(i)=zsum1(i)+Thickness%rho_dzt(i,j,k+1,taup1)
ratio1(i)=zsum(i)/zsum1(i)
ratio2(i)=1.0-ratio1(i)
if(k >= Grd%kmt(i,j)) then
unstable(i) = .false.
endif
enddo
!
! Check if entire row has been stabilised.
!
if(.not.any(unstable(:))) exit
!
! Main part.
! calculate densities for this row and the one below it
! If unstable, mix the layers and mark the depth to which convection has
! occured.
!
ru_line = density(T_prog(index_salt)%field(:,j,k,taup1),&
T_prog(index_temp)%field(:,j,k,taup1),&
Dens%pressure_at_depth(:,j,k+1))
rl_line = density(T_prog(index_salt)%field(:,j,k+1,taup1),&
T_prog(index_temp)%field(:,j,k+1,taup1),&
Dens%pressure_at_depth(:,j,k+1))
do n=1,size(T_prog(:))
do i=isc,iec
if(unstable(i)) then
if(ru_line(i) > rl_line(i)) then
T_prog(n)%field(i,j,k+1,taup1) = T_prog(n)%field(i,j,k+1,taup1)*ratio2(i) + &
T_prog(n)%field(i,j,k,taup1)*ratio1(i)
ikven(i,j)=k+1
else
unstable(i)=.false.
endif
endif
enddo
enddo
if(.not. any(unstable(:))) exit
enddo
!
! Now adjust all the layerabove the bottom of the instablity
!
do n=1,size(T_prog(:))
do k=1,maxval(ikven(:,j))-1
do i=isc,iec
if(k <= ikven(i,j)-1) then
T_prog(n)%field(i,j,k,taup1)=T_prog(n)%field(i,j,ikven(i,j),taup1)
endif
enddo
enddo
enddo
enddo
!
! Now procede to treating instabilies arising within the water column.
!
ktot=0.0
kven=0.0
jloop: do j=jsc,jec
!
! Preliminary sweep through density field to eliminate stable columns
! Note that top level is necessarily stable from initial sweep.
!
kt_temp=nk
nunstable=0
iindex=0
kindex=0
kloop: do k=2,maxval(Grd%kmt(isc:iec,j))-1
ru_line = density(T_prog(index_salt)%field(:,j,k,taup1),&
T_prog(index_temp)%field(:,j,k,taup1),&
Dens%pressure_at_depth(:,j,k+1))
rl_line = density(T_prog(index_salt)%field(:,j,k+1,taup1),&
T_prog(index_temp)%field(:,j,k+1,taup1),&
Dens%pressure_at_depth(:,j,k+1))
!
! If an instability occurs anywhere at this level exit to the main loop
! and process as normal.
!
do i=isc,iec
if(k < Grd%kmt(i,j) .and. ru_line(i) > rl_line(i)) then
nunstable=nunstable+1
iindex(nunstable)=i
kindex(nunstable)=k
endif
enddo
enddo kloop
if(nunstable .eq. 0) cycle jloop
do ikunstable=1,nunstable
i = iindex(ikunstable)
kt = kindex(ikunstable)
kbo = Grd%kmt(i,j)
kb = kt+1
ru = density (T_prog(index_salt)%field(i,j,kt,taup1),&
T_prog(index_temp)%field(i,j,kt,taup1),&
Dens%pressure_at_depth(i,j,kb))
rl = density (T_prog(index_salt)%field(i,j,kb,taup1),&
T_prog(index_temp)%field(i,j,kb,taup1),&
Dens%pressure_at_depth(i,j,kb))
! sum the first pair found in an unstable region
if (ru > rl) then
chk_la = .true.
chk_lb = .true.
zsm = Thickness%rho_dzt(i,j,kt,taup1) + Thickness%rho_dzt(i,j,kb,taup1)
tsm(1) = T_prog(index_temp)%field(i,j,kt,taup1)*Thickness%rho_dzt(i,j,kt,taup1) &
+ T_prog(index_temp)%field(i,j,kb,taup1)*Thickness%rho_dzt(i,j,kb,taup1)
tmx(1) = tsm(1)/zsm
tsm(2) = T_prog(index_salt)%field(i,j,kt,taup1)*Thickness%rho_dzt(i,j,kt,taup1) &
+ T_prog(index_salt)%field(i,j,kb,taup1)*Thickness%rho_dzt(i,j,kb,taup1)
tmx(2) = tsm(2)/zsm
do while (chk_lb .or. chk_la)
! check for an unstable level (lb) below kb
if (kb >= kbo) chk_lb = .false.
do while (chk_lb)
chk_lb = .false.
lb = kb + 1
ru = density (tmx(2), tmx(1), Dens%pressure_at_depth(i,j,lb))
rl = density (T_prog(index_salt)%field(i,j,lb,taup1),&
T_prog(index_temp)%field(i,j,lb,taup1),&
Dens%pressure_at_depth(i,j,lb))
if (ru > rl) then
! add new level to sums
kb = lb
zsm = zsm + Thickness%rho_dzt(i,j,kb,taup1)
tsm(1) = tsm(1) + T_prog(index_temp)%field(i,j,kb,taup1)*Thickness%rho_dzt(i,j,kb,taup1)
tmx(1) = tsm(1)/zsm
tsm(2) = tsm(2) + T_prog(index_salt)%field(i,j,kb,taup1)*Thickness%rho_dzt(i,j,kb,taup1)
tmx(2) = tsm(2)/zsm
chk_la = .true.
if (kb < kbo) chk_lb = .true.
endif
enddo
! check for an unstable level (la) above kt
! To get equivalent of original Rahmstorf code, uncomment next line
! chk_la = .true.
if (kt <= 1) chk_la = .false.
do while (chk_la)
chk_la = .false.
la = kt - 1
ru = density (T_prog(index_salt)%field(i,j,la,taup1),&
T_prog(index_temp)%field(i,j,la,taup1),&
Dens%pressure_at_depth(i,j,kt))
rl = density (tmx(2), tmx(1), Dens%pressure_at_depth(i,j,kt))
if (ru > rl) then
! add new level to sums
kt = la
zsm = zsm + Thickness%rho_dzt(i,j,kt,taup1)
tsm(1) = tsm(1) + T_prog(index_temp)%field(i,j,kt,taup1)*Thickness%rho_dzt(i,j,kt,taup1)
tmx(1) = tsm(1)/zsm
tsm(2) = tsm(2) + T_prog(index_salt)%field(i,j,kt,taup1)*Thickness%rho_dzt(i,j,kt,taup1)
tmx(2) = tsm(2)/zsm
chk_lb = .true.
! to get equivalent of original Rahmstorf code, comment out next line
if (kt > 1) chk_la = .true.
endif
enddo
enddo
! mix all tracers from kt to kb
do k=kt,kb
T_prog(index_temp)%field(i,j,k,taup1) = tmx(1)
T_prog(index_salt)%field(i,j,k,taup1) = tmx(2)
enddo
do n=1,size(T_prog(:))
if (n /= index_temp .and. n /= index_salt) then
tsm(3) = 0.0
do k=kt,kb
tsm(3) = tsm(3) + T_prog(n)%field(i,j,k,taup1)*Thickness%rho_dzt(i,j,k,taup1)
enddo
tmx(3) = tsm(3)/zsm
do k=kt,kb
T_prog(n)%field(i,j,k,taup1) = tmx(3)
enddo
endif
enddo
! compute diagnostic fields
ktot(i,j) = ktot(i,j) + kb - kt + 1
if (kt == 1) kven(i,j) = kb
endif
enddo !ikunstable
enddo jloop ! j=jsc,jec
! Merge diagnostic info.
do j=jsc,jec
do i=isc,iec
if(real(ikven(i,j)) > kven(i,j)) then
kven(i,j)=ikven(i,j)
ktot(i,j)=ikven(i,j)
endif
enddo
enddo
if (id_ktot > 0) used = send_data (id_ktot, ktot(isc:iec,jsc:jec), &
Time%model_time, rmask=Grd%tmask(isc:iec,jsc:jec,1))
if (id_kven > 0) used = send_data (id_kven, kven(isc:iec,jsc:jec), &
Time%model_time, rmask=Grd%tmask(isc:iec,jsc:jec,1))
do n=1,size(T_prog(:))
if (id_convect(n) > 0) then
do k=1,nk
do j=jsc,jec
do i=isc,iec
T_prog(n)%wrk1(i,j,k) = dtimer*(T_prog(n)%field(i,j,k,taup1) - T_prog(n)%wrk1(i,j,k))
enddo
enddo
T_prog(n)%wrk1(isc:iec,jsc:jec,k) = T_prog(n)%wrk1(isc:iec,jsc:jec,k)*&
T_prog(n)%conversion*Thickness%rho_dzt(isc:iec,jsc:jec,k,taup1)
enddo
used = send_data(id_convect(n), T_prog(n)%wrk1(:,:,:), &
Time%model_time, rmask=Grd%tmask(:,:,:), &
is_in=isc, js_in=jsc, ks_in=1, ie_in=iec, je_in=jec, ke_in=nk)
endif
enddo
end subroutine convection_full_vector
! NAME="convection_full_vector"
!#######################################################################
!
!
!
! "ncon" convection scheme
!
! Convectively adjust water column if gravitationally unstable.
! Based on algorithm from Mike Cox used in his code from 1984.
! Algorithm has well known problems with incomplete homogenization
! and sensitivity to the ncon parameter.
!
! Coded in mom4 for legacy purposes by Stephen.Griffies@noaa.gov
! April 2001
!
!
!
subroutine convection_ncon (Time, Thickness, T_prog, Dens)
type(ocean_time_type), intent(in) :: Time
type(ocean_thickness_type), intent(in) :: Thickness
type(ocean_prog_tracer_type), intent(inout) :: T_prog(:)
type(ocean_density_type), intent(in) :: Dens
integer :: i, j, k, l, ks, n, nn
integer :: tau, taup1
real :: dense
taup1 = Time%taup1
tau = Time%tau
do n=1, size(T_prog(:))
T_Prog(n)%wrk1(:,:,:) = T_prog(n)%field(:,:,:,taup1)
enddo
wrk1 = 0.0
! ks=1: compare levels 1 to 2; 3 to 4; etc.
! ks=2: compare levels 2 to 3; 4 to 5; etc.
do nn=1,ncon
do ks=1,2
! find density with reference pressure determined by vertical pairs
do j=jsc,jec
do l=1,nk,2
if (ks .eq. 1) then
k = min(l+1,nk)
else
k = l
endif
do i=isc,iec
wrk1(i,j,l)=density(T_prog(index_salt)%field(i,j,l,taup1),&
T_prog(index_temp)%field(i,j,l,taup1),&
Dens%pressure_at_depth(i,j,k))
enddo
enddo
enddo
do j=jsc,jec
do l=2,nk,2
if (ks .eq. 1) then
k = l
else
k = min(l+1,nk)
endif
do i=isc,iec
wrk1(i,j,l)=density(T_prog(index_salt)%field(i,j,l,taup1),&
T_prog(index_temp)%field(i,j,l,taup1),&
Dens%pressure_at_depth(i,j,k))
enddo
enddo
enddo
! set "heavy water" in land to stop convection
dense = 1.e30
do j=jsc,jec
do i=isc,iec
k = Grd%kmt(i,j) + 1
if (k .le. nk) wrk1(i,j,k) = dense
enddo
enddo
!if unstable, then mix tracers on adjoining levels
do n=1,size(T_prog(:))
do j=jsc,jec
do k=ks,nkm1,2
do i=isc,iec
if (wrk1(i,j,k) .gt. wrk1(i,j,k+1)) then
T_prog(n)%field(i,j,k,taup1) = ( Thickness%rho_dzt(i,j,k,taup1)*T_prog(n)%field(i,j,k,taup1) &
+Thickness%rho_dzt(i,j,k+1,taup1)*T_prog(n)%field(i,j,k+1,taup1)) &
/(Thickness%rho_dzt(i,j,k,taup1) + Thickness%rho_dzt(i,j,k+1,taup1))
T_prog(n)%field(i,j,k+1,taup1) = T_prog(n)%field(i,j,k,taup1)
endif
enddo
enddo
enddo
enddo
enddo !ks=1,2
enddo !nn=1,ncon
do n=1,size(T_prog(:))
if (id_convect(n) > 0) then
do k=1,nk
do j=jsc,jec
do i=isc,iec
T_prog(n)%wrk1(i,j,k) = dtimer*(T_prog(n)%field(i,j,k,taup1) - T_prog(n)%wrk1(i,j,k))
enddo
enddo
T_prog(n)%wrk1(isc:iec,jsc:jec,k) = T_prog(n)%wrk1(isc:iec,jsc:jec,k)*&
T_prog(n)%conversion*Thickness%rho_dzt(isc:iec,jsc:jec,k,taup1)
enddo
used = send_data(id_convect(n), T_prog(n)%wrk1(:,:,:), &
Time%model_time, rmask=Grd%tmask(:,:,:), &
is_in=isc, js_in=jsc, ks_in=1, ie_in=iec, je_in=jec, ke_in=nk)
endif
enddo
end subroutine convection_ncon
! NAME="convection_ncon"
end module ocean_convect_mod