Newer
Older
!< @brief dynamic pacanowski-philander scheme
! --------------------------------------------------------------------------------
! --------------------------------------------------------------------------------
#ifdef USE_CONFIG_PARSER
use iso_c_binding, only: C_NULL_CHAR
use config_parser
#endif
! --------------------------------------------------------------------------------
private
! public interface
! --------------------------------------------------------------------------------
public :: init_turbulence_closure
public :: advance_turbulence_closure
public :: define_stability_functions
public :: get_eddy_viscosity, get_eddy_diffusivity
public :: get_eddy_viscosity_vec, get_eddy_diffusivity_vec
! --------------------------------------------------------------------------------
!> @brief Pacanowski-Philander dynamic parameters
type, public :: pphDynParamType
real :: alpha = 4.0 !< constant, *: default = 5.0
real :: n = 2.0 !< constant
real :: Km_b = 0.0001 !< background eddy viscosity, [m**2 / s], *: INMCM: 5 * 10**(-6)
real :: Kh_b = 0.00001 !< background eddy diffusivity, [m**2 / s]
real :: C_l = 4.0 / 9.0 !< length scale tuning constant, [n/d], *: = (4.0 / pi^2) in Obukhov length scale
real :: kappa = 0.4 !< von Karman constant
real :: PrT0 = 1.0 !< turbulent Prandtl number, *: probably redundant
real :: c_S2_min = 1e-5 !< min shear frequency, [(1/s)**2]
! --------------------------------------------------------------------------------
subroutine define_stability_functions(param, bc, grid)
!< @brief advance stability functions: N**2, S**2, Ri-gradient
! ----------------------------------------------------------------------------
use obl_state
type(pphDynParamType), intent(in) :: param
type(oblBcType), intent(in) :: bc
type (gridDataType), intent(in) :: grid
! --------------------------------------------------------------------------------
call get_N2(N2, Rho, bc%Rho_dyn0, bc%Rho_dynH, &
param%kappa, param%PrT0, grid)
call get_S2(S2, U, V, bc%U_dyn0, bc%U_dynH, &
param%kappa, grid)
call get_Ri_gradient(Ri_grad, N2, S2, param%c_S2_min, grid)
! --------------------------------------------------------------------------------
subroutine init_turbulence_closure(param, bc, grid)
!< @brief advance turbulence closure
! ----------------------------------------------------------------------------
use obl_state
type(pphDynParamType), intent(in) :: param
type(oblBcType), intent(in) :: bc
type (gridDataType), intent(in) :: grid
real :: mld
! --------------------------------------------------------------------------------
call get_mld(mld, N2, grid%dz, grid%cz)
call get_eddy_viscosity(Km, Ri_grad, &
bc%U_dynH, mld, param, grid)
call get_eddy_diffusivity(Kh, Ri_grad, &
bc%U_dynH, mld, param, grid)
end subroutine
! --------------------------------------------------------------------------------
subroutine advance_turbulence_closure(param, bc, grid, dt)
!< @brief advance turbulence closure
! ----------------------------------------------------------------------------
use obl_state
type(pphDynParamType), intent(in) :: param
type(oblBcType), intent(in) :: bc
type (gridDataType), intent(in) :: grid
real, intent(in) :: dt
real :: mld
! --------------------------------------------------------------------------------
call get_TKE_production(TKE_production, Km, S2, grid)
call get_TKE_buoyancy(TKE_buoyancy, Kh, N2, grid)
call get_mld(mld, N2, grid%dz, grid%cz)
call get_eddy_viscosity(Km, Ri_grad, &
bc%U_dynH, mld, param, grid)
call get_eddy_diffusivity(Kh, Ri_grad, &
bc%U_dynH, mld, param, grid)
end subroutine
! --------------------------------------------------------------------------------
subroutine get_eddy_viscosity(Km, Ri_grad, U_dynH, mld, param, grid)
!< @brief calculate eddy viscosity
! ----------------------------------------------------------------------------
type(pphDynParamType), intent(in) :: param
type (gridDataType), intent(in) :: grid
real, dimension(grid%cz), intent(out) :: Km !< eddy viscosity, [m**2 / s]
real, dimension(grid%cz), intent(in) :: Ri_grad !< Richardson gradient number, [n/d]
real, intent(in) :: U_dynH !< dynamic velocity, [m/s]
real, intent(in) :: mld !< mixed layer depth, [m]
! ----------------------------------------------------------------------------
call get_eddy_viscosity_vec(Km, Ri_grad, U_dynH, mld, param, grid%cz)
end subroutine
subroutine get_eddy_viscosity_vec(Km, Ri_grad, U_dynH, mld, param, cz)
!< @brief calculate eddy viscosity
! ----------------------------------------------------------------------------
type(pphDynParamType), intent(in) :: param
integer, intent(in) :: cz !< grid size
real, dimension(cz), intent(out) :: Km !< eddy viscosity, [m**2 / s]
real, dimension(cz), intent(in) :: Ri_grad !< Richardson gradient number, [n/d]
real, intent(in) :: U_dynH !< dynamic velocity, [m/s]
real, intent(in) :: mld !< mixed layer depth, [m]
real :: Km_0 !< neutral eddy viscosity, [m**2 / s]
integer :: k
! ----------------------------------------------------------------------------
Km_0 = param%C_l * U_dynH * param%kappa * mld / 2.0
Km(k) = Km_0 / (1.0 + param%alpha * Ri_grad(k))**(param%n) + param%Km_b
! --------------------------------------------------------------------------------
subroutine get_eddy_diffusivity(Kh, Ri_grad, U_dynH, mld, param, grid)
!< @brief calculate eddy diffusivity
! ----------------------------------------------------------------------------
type(pphDynParamType), intent(in) :: param
type (gridDataType), intent(in) :: grid
real, dimension(grid%cz), intent(out) :: Kh !< eddy diffusivity, [m**2 / s]
real, dimension(grid%cz), intent(in) :: Ri_grad !< Richardson gradient number, [n/d]
real, intent(in) :: U_dynH !< dynamic velocity, [m/s]
real, intent(in) :: mld !< mixed layer depth, [m]
! ----------------------------------------------------------------------------
call get_eddy_diffusivity_vec(Kh, Ri_grad, U_dynH, mld, param, grid%cz)
end subroutine
subroutine get_eddy_diffusivity_vec(Kh, Ri_grad, U_dynH, mld, param, cz)
!< @brief calculate eddy diffusivity
! ----------------------------------------------------------------------------
type(pphDynParamType), intent(in) :: param
integer, intent(in) :: cz !< grid size
real, dimension(cz), intent(out) :: Kh !< eddy diffusivity, [m**2 / s]
real, dimension(cz), intent(in) :: Ri_grad !< Richardson gradient number, [n/d]
real, intent(in) :: U_dynH !< dynamic velocity, [m/s]
real, intent(in) :: mld !< mixed layer depth, [m]
real :: Kh_0 !< neutral eddy diffusivity, [m**2 / s]
integer :: k
! ----------------------------------------------------------------------------
Kh_0 = param%C_l * U_dynH * param%kappa * mld / 2.0
do k = 1, cz
Kh(k) = Kh_0 / (1.0 + param%alpha * Ri_grad(k))**(param%n + 1.0) + param%Kh_b
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
! --------------------------------------------------------------------------------
subroutine set_config_param(param, tag, ierr)
!< @brief set turbulence closure parameters
! ----------------------------------------------------------------------------
type(pphDynParamType), intent(out) :: param
integer, intent(out) :: ierr
character(len = *), intent(in) :: tag
integer :: status
! --------------------------------------------------------------------------------
ierr = 0 ! = OK
#ifdef USE_CONFIG_PARSER
call c_config_is_varname(trim(tag)//".alpha"//C_NULL_CHAR, status)
if (status /= 0) then
call c_config_get_float(trim(tag)//".alpha"//C_NULL_CHAR, param%alpha, status)
if (status == 0) then
ierr = 1 ! signal ERROR
return
end if
endif
call c_config_is_varname(trim(tag)//".n"//C_NULL_CHAR, status)
if (status /= 0) then
call c_config_get_float(trim(tag)//".n"//C_NULL_CHAR, param%n, status)
if (status == 0) then
ierr = 1 ! signal ERROR
return
end if
endif
call c_config_is_varname(trim(tag)//".Km_b"//C_NULL_CHAR, status)
if (status /= 0) then
call c_config_get_float(trim(tag)//".Km_b"//C_NULL_CHAR, param%Km_b, status)
if (status == 0) then
ierr = 1 ! signal ERROR
return
end if
endif
call c_config_is_varname(trim(tag)//".Kh_b"//C_NULL_CHAR, status)
if (status /= 0) then
call c_config_get_float(trim(tag)//".Kh_b"//C_NULL_CHAR, param%Kh_b, status)
if (status == 0) then
ierr = 1 ! signal ERROR
return
end if
endif
call c_config_is_varname(trim(tag)//".C_l"//C_NULL_CHAR, status)
if (status /= 0) then
call c_config_get_float(trim(tag)//".C_l"//C_NULL_CHAR, param%C_l, status)
if (status == 0) then
ierr = 1 ! signal ERROR
return
end if
endif
call c_config_is_varname(trim(tag)//".kappa"//C_NULL_CHAR, status)
if (status /= 0) then
call c_config_get_float(trim(tag)//".kappa"//C_NULL_CHAR, param%kappa, status)
if (status == 0) then
ierr = 1 ! signal ERROR
return
end if
endif
call c_config_is_varname(trim(tag)//".PrT0"//C_NULL_CHAR, status)
if (status /= 0) then
call c_config_get_float(trim(tag)//".PrT0"//C_NULL_CHAR, param%PrT0, status)
if (status == 0) then
ierr = 1 ! signal ERROR
return
end if
endif
call c_config_is_varname(trim(tag)//".c_S2_min"//C_NULL_CHAR, status)
if (status /= 0) then
call c_config_get_float(trim(tag)//".c_S2_min"//C_NULL_CHAR, param%c_S2_min, status)
if (status == 0) then
ierr = 1 ! signal ERROR
return
end if
endif
#else
!> *: just skipping setup without configuration file
#endif
end subroutine