Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
99ca9a7
Adding option to smooth Ri using a 1-2-1 filter
gustavo-marques Apr 10, 2018
b14213a
Fill Ri_grad in vanished layers with adjacent value, just when Ri smo…
gustavo-marques Apr 12, 2018
c4f1f55
Update CVMix
gustavo-marques Apr 12, 2018
0c363ae
Always allocate CS%OBLdepth since other modules may need to know OBLd…
gustavo-marques Apr 13, 2018
60f7d66
Initialize visc%Kv_slow and update halos
gustavo-marques Apr 13, 2018
d774e5f
Add "slow" vertical viscosity in vertvisc_coef
gustavo-marques Apr 16, 2018
fd23f91
Set visc%Kv_slow to zero in diabatic
gustavo-marques Apr 16, 2018
1488b78
Add option to save Kv_slow and Kv
gustavo-marques Apr 16, 2018
69c2c96
Remove trailing space
gustavo-marques Apr 16, 2018
d5be1f8
Attempt to add diag. for total vertical visc.
gustavo-marques Apr 16, 2018
dcfb722
Bug fix in MOM_bkgnd_mixing
gustavo-marques Apr 17, 2018
d09e809
Add option to diagnose Kv at u and v points
gustavo-marques Apr 17, 2018
901c301
Add option to post diags for bkgnd_mixing
gustavo-marques Apr 17, 2018
f6a21e7
Merge branch 'dev/ncar' into adding_cvmix_part2
gustavo-marques Apr 17, 2018
a0358fb
Fix bug in MOM_cvmix_conv
gustavo-marques Apr 17, 2018
9d6cb46
Rename variable in register_diag_field
gustavo-marques Apr 17, 2018
78656bb
Add missing halo update for visc%Kv_slow
gustavo-marques Apr 19, 2018
3385857
Initialize Kd, Kd_int and Kv_slow using interior values specified by …
gustavo-marques Apr 19, 2018
191b5be
Add a factor of 2 when adding Kv_slow into Kv_add
gustavo-marques Apr 19, 2018
02acd12
Doxygenize subroutine differential_diffuse_T_S
gustavo-marques May 16, 2018
507d34e
First version of Double-diffusion via CVMix
gustavo-marques May 17, 2018
81265e6
Doxygenize MOM_diabatic_aux
gustavo-marques May 18, 2018
05daede
Fix indentation
gustavo-marques May 18, 2018
d5ce7a4
Avoid NaNs when computing stratification parameter
gustavo-marques May 18, 2018
abd620c
Move description to the end of the module
gustavo-marques May 18, 2018
152a707
Change cvmix to CVMix
gustavo-marques May 18, 2018
cc27362
Clean up spaces and comments
gustavo-marques May 18, 2018
148a944
Merge branch 'dev/ncar' into double_diffusion_cvmix
gustavo-marques May 18, 2018
70d88e4
Add a flag to control if visc%Kv_slow is used
gustavo-marques May 21, 2018
8877c17
Rename MOM_cvmix_ddiff.F90 -> MOM_CVMix_ddiff.F90
gustavo-marques May 22, 2018
bf6c003
Clean the ddiff code and improve comments
gustavo-marques May 22, 2018
1e6cb67
Merge branch 'dev/ncar' into double_diffusion_cvmix
gustavo-marques May 22, 2018
884dd3a
Merge remote-tracking branch 'gustavo/double_diffusion_cvmix2' into d…
gustavo-marques May 22, 2018
198d755
Delete visc%kv_slow=0 since this is done in set_diffusivity
gustavo-marques May 23, 2018
720dbc0
Doxygenize set_diff + read background kinematic viscosity
gustavo-marques May 23, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/core/MOM.F90
Original file line number Diff line number Diff line change
Expand Up @@ -2378,6 +2378,9 @@ subroutine initialize_MOM(Time, Time_init, param_file, dirs, CS, restart_CSp, &
if (associated(CS%visc%Kv_shear)) &
call pass_var(CS%visc%Kv_shear, G%Domain, To_All+Omit_Corners, halo=1)

if (associated(CS%visc%Kv_slow)) &
call pass_var(CS%visc%Kv_slow, G%Domain, To_All+Omit_Corners, halo=1)

call cpu_clock_end(id_clock_pass_init)

call register_obsolete_diagnostics(param_file, CS%diag)
Expand Down
3 changes: 3 additions & 0 deletions src/core/MOM_variables.F90
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,9 @@ module MOM_variables
!! convection etc).
TKE_turb => NULL() !< The turbulent kinetic energy per unit mass defined
!! at the interfaces between each layer, in m2 s-2.
logical :: add_Kv_slow !< If True, adds Kv_slow when calculating the
!! 'coupling coefficient' (a[k]) at the interfaces.
!! This is done in find_coupling_coef.
end type vertvisc_type

!> The BT_cont_type structure contains information about the summed layer
Expand Down
1 change: 1 addition & 0 deletions src/parameterizations/vertical/MOM_CVMix_conv.F90
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ subroutine calculate_CVMix_conv(h, tv, G, GV, CS, hbl)
iFaceHeight(k+1) = iFaceHeight(k) - dh
enddo

! gets index of the level and interface above hbl
kOBL = CVMix_kpp_compute_kOBL_depth(iFaceHeight, cellHeight,hbl(i,j))

call CVMix_coeffs_conv(Mdiff_out=CS%kv_conv(i,j,:), &
Expand Down
301 changes: 301 additions & 0 deletions src/parameterizations/vertical/MOM_CVMix_ddiff.F90
Original file line number Diff line number Diff line change
@@ -0,0 +1,301 @@
!> Interface to CVMix double diffusion scheme.
module MOM_CVMix_ddiff

! This file is part of MOM6. See LICENSE.md for the license.

use MOM_diag_mediator, only : diag_ctrl, time_type, register_diag_field
use MOM_diag_mediator, only : post_data
use MOM_EOS, only : calculate_density_derivs
use MOM_variables, only : thermo_var_ptrs
use MOM_error_handler, only : MOM_error, is_root_pe, FATAL, WARNING, NOTE
use MOM_file_parser, only : openParameterBlock, closeParameterBlock
use MOM_debugging, only : hchksum
use MOM_grid, only : ocean_grid_type
use MOM_verticalGrid, only : verticalGrid_type
use MOM_file_parser, only : get_param, log_version, param_file_type
use cvmix_ddiff, only : cvmix_init_ddiff, CVMix_coeffs_ddiff
use cvmix_kpp, only : CVmix_kpp_compute_kOBL_depth
implicit none ; private

#include <MOM_memory.h>

public CVMix_ddiff_init, CVMix_ddiff_end, CVMix_ddiff_is_used, compute_ddiff_coeffs

!> Control structure including parameters for CVMix double diffusion.
type, public :: CVMix_ddiff_cs

! Parameters
real :: strat_param_max !< maximum value for the stratification parameter (nondim)
real :: kappa_ddiff_s !< leading coefficient in formula for salt-fingering regime
!! for salinity diffusion (m^2/s)
real :: ddiff_exp1 !< interior exponent in salt-fingering regime formula (nondim)
real :: ddiff_exp2 !< exterior exponent in salt-fingering regime formula (nondim)
real :: mol_diff !< molecular diffusivity (m^2/s)
real :: kappa_ddiff_param1 !< exterior coefficient in diffusive convection regime (nondim)
real :: kappa_ddiff_param2 !< middle coefficient in diffusive convection regime (nondim)
real :: kappa_ddiff_param3 !< interior coefficient in diffusive convection regime (nondim)
real :: min_thickness !< Minimum thickness allowed (m)
character(len=4) :: diff_conv_type !< type of diffusive convection to use. Options are Marmorino &
!! Caldwell 1976 ("MC76"; default) and Kelley 1988, 1990 ("K90")
logical :: debug !< If true, turn on debugging

! Daignostic handles and pointers
type(diag_ctrl), pointer :: diag => NULL()
integer :: id_KT_extra = -1, id_KS_extra = -1, id_R_rho = -1

! Diagnostics arrays
real, allocatable, dimension(:,:,:) :: KT_extra !< double diffusion diffusivity for temp (m2/s)
real, allocatable, dimension(:,:,:) :: KS_extra !< double diffusion diffusivity for salt (m2/s)
real, allocatable, dimension(:,:,:) :: R_rho !< double-diffusion density ratio (nondim)

end type CVMix_ddiff_cs

character(len=40) :: mdl = "MOM_CVMix_ddiff" !< This module's name.

contains

!> Initialized the CVMix double diffusion module.
logical function CVMix_ddiff_init(Time, G, GV, param_file, diag, CS)

type(time_type), intent(in) :: Time !< The current time.
type(ocean_grid_type), intent(in) :: G !< Grid structure.
type(verticalGrid_type), intent(in) :: GV !< Vertical grid structure.
type(param_file_type), intent(in) :: param_file !< Run-time parameter file handle
type(diag_ctrl), target, intent(inout) :: diag !< Diagnostics control structure.
type(CVMix_ddiff_cs), pointer :: CS !< This module's control structure.

! This include declares and sets the variable "version".
#include "version_variable.h"

if (associated(CS)) then
call MOM_error(WARNING, "CVMix_ddiff_init called with an associated "// &
"control structure.")
return
endif
allocate(CS)

! Read parameters
call log_version(param_file, mdl, version, &
"Parameterization of mixing due to double diffusion processes via CVMix")
call get_param(param_file, mdl, "USE_CVMIX_DDIFF", CVMix_ddiff_init, &
"If true, turns on double diffusive processes via CVMix. \n"// &
"Note that double diffusive processes on viscosity are ignored \n"// &
"in CVMix, see http://cvmix.github.io/ for justification.",&
default=.false.)

if (.not. CVMix_ddiff_init) return

call get_param(param_file, mdl, 'DEBUG', CS%debug, default=.False., do_not_log=.True.)

call get_param(param_file, mdl, 'MIN_THICKNESS', CS%min_thickness, default=0.001, do_not_log=.True.)

call openParameterBlock(param_file,'CVMIX_DDIFF')

call get_param(param_file, mdl, "STRAT_PARAM_MAX", CS%strat_param_max, &
"The maximum value for the double dissusion stratification parameter", &
units="nondim", default=2.55)

call get_param(param_file, mdl, "KAPPA_DDIFF_S", CS%kappa_ddiff_s, &
"Leading coefficient in formula for salt-fingering regime \n"// &
"for salinity diffusion.", units="m2 s-1", default=1.0e-4)

call get_param(param_file, mdl, "DDIFF_EXP1", CS%ddiff_exp1, &
"Interior exponent in salt-fingering regime formula.", &
units="nondim", default=1.0)

call get_param(param_file, mdl, "DDIFF_EXP2", CS%ddiff_exp2, &
"Exterior exponent in salt-fingering regime formula.", &
units="nondim", default=3.0)

call get_param(param_file, mdl, "KAPPA_DDIFF_PARAM1", CS%kappa_ddiff_param1, &
"Exterior coefficient in diffusive convection regime.", &
units="nondim", default=0.909)

call get_param(param_file, mdl, "KAPPA_DDIFF_PARAM2", CS%kappa_ddiff_param2, &
"Middle coefficient in diffusive convection regime.", &
units="nondim", default=4.6)

call get_param(param_file, mdl, "KAPPA_DDIFF_PARAM3", CS%kappa_ddiff_param3, &
"Interior coefficient in diffusive convection regime.", &
units="nondim", default=-0.54)

call get_param(param_file, mdl, "MOL_DIFF", CS%mol_diff, &
"Molecular diffusivity used in CVMix double diffusion.", &
units="m2 s-1", default=1.5e-6)

call get_param(param_file, mdl, "DIFF_CONV_TYPE", CS%diff_conv_type, &
"type of diffusive convection to use. Options are Marmorino \n" //&
"and Caldwell 1976 (MC76) and Kelley 1988, 1990 (K90).", &
default="MC76")

call closeParameterBlock(param_file)

! Register diagnostics
CS%diag => diag

CS%id_KT_extra = register_diag_field('ocean_model','KT_extra',diag%axesTi,Time, &
'Double-diffusive diffusivity for temperature', 'm2 s-1')

CS%id_KS_extra = register_diag_field('ocean_model','KS_extra',diag%axesTi,Time, &
'Double-diffusive diffusivity for salinity', 'm2 s-1')

CS%id_R_rho = register_diag_field('ocean_model','R_rho',diag%axesTi,Time, &
'Double-diffusion density ratio', 'nondim')
if (CS%id_R_rho > 0) &
allocate(CS%R_rho( SZI_(G), SZJ_(G), SZK_(G)+1)); CS%R_rho(:,:,:) = 0.0

call cvmix_init_ddiff(strat_param_max=CS%strat_param_max, &
kappa_ddiff_s=CS%kappa_ddiff_s, &
ddiff_exp1=CS%ddiff_exp1, &
ddiff_exp2=CS%ddiff_exp2, &
mol_diff=CS%mol_diff, &
kappa_ddiff_param1=CS%kappa_ddiff_param1, &
kappa_ddiff_param2=CS%kappa_ddiff_param2, &
kappa_ddiff_param3=CS%kappa_ddiff_param3, &
diff_conv_type=CS%diff_conv_type)

end function CVMix_ddiff_init

!> Subroutine for computing vertical diffusion coefficients for the
!! double diffusion mixing parameterization.
subroutine compute_ddiff_coeffs(h, tv, G, GV, j, Kd_T, Kd_S, CS)

type(ocean_grid_type), intent(in) :: G !< Grid structure.
type(verticalGrid_type), intent(in) :: GV !< Vertical grid structure.
real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h !< Layer thickness, in m or kg m-2.
type(thermo_var_ptrs), intent(in) :: tv !< Thermodynamics structure.
real, dimension(SZI_(G),SZJ_(G),SZK_(G)+1), intent(out) :: Kd_T !< Interface double diffusion diapycnal
!! diffusivity for temp (m2/sec).
real, dimension(SZI_(G),SZJ_(G),SZK_(G)+1), intent(out) :: Kd_S !< Interface double diffusion diapycnal
!! diffusivity for salt (m2/sec).
type(CVMix_ddiff_cs), pointer :: CS !< The control structure returned
!! by a previous call to CVMix_ddiff_init.
integer, intent(in) :: j !< Meridional grid indice.
! real, dimension(:,:), optional, pointer :: hbl !< Depth of ocean boundary layer (m)

! local variables
real, dimension(SZK_(G)) :: &
cellHeight, & !< Height of cell centers (m)
dRho_dT, & !< partial derivatives of density wrt temp (kg m-3 degC-1)
dRho_dS, & !< partial derivatives of density wrt saln (kg m-3 PPT-1)
pres_int, & !< pressure at each interface (Pa)
temp_int, & !< temp and at interfaces (degC)
salt_int, & !< salt at at interfaces
alpha_dT, & !< alpha*dT across interfaces
beta_dS, & !< beta*dS across interfaces
dT, & !< temp. difference between adjacent layers (degC)
dS !< salt difference between adjacent layers

real, dimension(SZK_(G)+1) :: iFaceHeight !< Height of interfaces (m)
integer :: kOBL !< level of OBL extent
real :: pref, g_o_rho0, rhok, rhokm1, dz, dh, hcorr
integer :: i, k

! initialize dummy variables
pres_int(:) = 0.0; temp_int(:) = 0.0; salt_int(:) = 0.0
alpha_dT(:) = 0.0; beta_dS(:) = 0.0; dRho_dT(:) = 0.0
dRho_dS(:) = 0.0; dT(:) = 0.0; dS(:) = 0.0

! set Kd_T and Kd_S to zero to avoid passing values from previous call
Kd_T(:,j,:) = 0.0; Kd_S(:,j,:) = 0.0

! GMM, I am leaving some code commented below. We need to pass BLD to
! this soubroutine to avoid adding diffusivity above that. This needs
! to be done once we re-structure the order of the calls.
!if (.not. associated(hbl)) then
! allocate(hbl(SZI_(G), SZJ_(G)));
! hbl(:,:) = 0.0
!endif

do i = G%isc, G%iec

! skip calling at land points
if (G%mask2dT(i,j) == 0.) cycle

pRef = 0.
pres_int(1) = pRef
! we don't have SST and SSS, so let's use values at top-most layer
temp_int(1) = TV%T(i,j,1); salt_int(1) = TV%S(i,j,1)
do k=2,G%ke
! pressure at interface
pres_int(k) = pRef + GV%H_to_Pa * h(i,j,k-1)
! temp and salt at interface
! for temp: (t1*h1 + t2*h2)/(h1+h2)
temp_int(k) = (TV%T(i,j,k-1)*h(i,j,k-1) + TV%T(i,j,k)*h(i,j,k))/(h(i,j,k-1)+h(i,j,k))
salt_int(k) = (TV%S(i,j,k-1)*h(i,j,k-1) + TV%S(i,j,k)*h(i,j,k))/(h(i,j,k-1)+h(i,j,k))
! dT and dS
dT(k) = (TV%T(i,j,k-1)-TV%T(i,j,k))
dS(k) = (TV%S(i,j,k-1)-TV%S(i,j,k))
pRef = pRef + GV%H_to_Pa * h(i,j,k-1)
enddo ! k-loop finishes

call calculate_density_derivs(temp_int(:), salt_int(:), pres_int(:), drho_dT(:), drho_dS(:), 1, G%ke, TV%EQN_OF_STATE)

! The "-1.0" below is needed so that the following criteria is satisfied:
! if ((alpha_dT > beta_dS) .and. (beta_dS > 0.0)) then "salt finger"
! if ((alpha_dT < 0.) .and. (beta_dS < 0.) .and. (alpha_dT > beta_dS)) then "diffusive convection"
do k=1,G%ke
alpha_dT(k) = -1.0*drho_dT(k) * dT(k)
beta_dS(k) = drho_dS(k) * dS(k)
enddo

if (CS%id_R_rho > 0.0) then
do k=1,G%ke
CS%R_rho(i,j,k) = alpha_dT(k)/beta_dS(k)
! avoid NaN's
if(CS%R_rho(i,j,k) /= CS%R_rho(i,j,k)) CS%R_rho(i,j,k) = 0.0
enddo
endif

iFaceHeight(1) = 0.0 ! BBL is all relative to the surface
hcorr = 0.0
! compute heights at cell center and interfaces
do k=1,G%ke
dh = h(i,j,k) * GV%H_to_m ! Nominal thickness to use for increment
dh = dh + hcorr ! Take away the accumulated error (could temporarily make dh<0)
hcorr = min( dh - CS%min_thickness, 0. ) ! If inflating then hcorr<0
dh = max( dh, CS%min_thickness ) ! Limit increment dh>=min_thickness
cellHeight(k) = iFaceHeight(k) - 0.5 * dh
iFaceHeight(k+1) = iFaceHeight(k) - dh
enddo

! gets index of the level and interface above hbl
!kOBL = CVmix_kpp_compute_kOBL_depth(iFaceHeight, cellHeight,hbl(i,j))

call CVMix_coeffs_ddiff(Tdiff_out=Kd_T(i,j,:), &
Sdiff_out=Kd_S(i,j,:), &
strat_param_num=alpha_dT(:), &
strat_param_denom=beta_dS(:), &
nlev=G%ke, &
max_nlev=G%ke)

! Do not apply mixing due to convection within the boundary layer
!do k=1,kOBL
! Kd_T(i,j,k) = 0.0
! Kd_S(i,j,k) = 0.0
!enddo

enddo ! i-loop

end subroutine compute_ddiff_coeffs

!> Reads the parameter "USE_CVMIX_DDIFF" and returns state.
!! This function allows other modules to know whether this parameterization will
!! be used without needing to duplicate the log entry.
logical function CVMix_ddiff_is_used(param_file)
type(param_file_type), intent(in) :: param_file !< A structure to parse for run-time parameters
call get_param(param_file, mdl, "USE_CVMIX_DDIFF", CVMix_ddiff_is_used, &
default=.false., do_not_log = .true.)

end function CVMix_ddiff_is_used

!> Clear pointers and dealocate memory
subroutine CVMix_ddiff_end(CS)
type(CVMix_ddiff_cs), pointer :: CS ! Control structure

deallocate(CS)

end subroutine CVMix_ddiff_end


end module MOM_CVMix_ddiff
Loading