FE-Project
Loading...
Searching...
No Matches
scale_atm_phy_bl_dgm_mynn_lv2.F90
Go to the documentation of this file.
1!> module FElib / Atmosphere / Physics / boundary layer turbulence
2!!
3!! @par Description
4!! A module to provide routines to calculate turbulent diffusion coefficients based on the Mellor-Yamada-Nakanishi-Niino (MYNN) Level 2 closure.
5!!
6!! This implementation uses the Level 2 diagnostic closure only. Prognostic turbulent kinetic energy, nonlocal mixing, and the MY Level 2.5 equations are not included.
7!!
8!! @par Reference
9!! Mellor, G. L. and T. Yamada, 1982:
10!! Development of a turbulence closure model for geophysical fluid problems.
11!! Reviews of Geophysics and Space Physics, 20, 851-875.
12!!
13!! Nakanishi, M. and H. Niino, 2009:
14!! Development of an improved turbulence closure model for the atmospheric boundary layer.
15!! Journal of the Meteorological Society of Japan, 87, 895-912.
16!!
17!! Blackadar, A. K., 1962:
18!! The vertical distribution of wind and turbulent exchange in a neutral atmosphere.
19!! Journal of Geophysical Research, 67, 3095-3102.
20!!
21!!
22!! @author Yuta Kawai, Team SCALE
23!!
24!<
25!-------------------------------------------------------------------------------
26#include "scaleFElib.h"
28 !-----------------------------------------------------------------------------
29 !
30 !++ Used modules
31 !
32 use scale_precision
33 use scale_io
34 use scale_prc
35 use scale_prof
36 use scale_const, only: &
37 eps => const_eps, &
38 grav => const_grav, &
39 rdry => const_rdry, &
40 cpdry => const_cpdry, &
41 cvdry => const_cvdry, &
42 pres00 => const_pre00, &
43 karman => const_karman, &
44 rplanet => const_radius
46 use scale_element_base, only: &
54
55 !-----------------------------------------------------------------------------
56 implicit none
57 private
58 !-----------------------------------------------------------------------------
59 !
60 !++ Public procedures
61 !
65
66 !-----------------------------------------------------------------------------
67 !
68 !++ Private procedure
69 !
70
71 !-----------------------------------------------------------------------------
72 !
73 !++ Private parameters & variables
74 !
75
76 !- MYNN closure constants -----------
77
78 real(RP), parameter :: A1 = 1.18_rp
79 real(RP), parameter :: A2 = 0.665_rp
80
81 real(RP), parameter :: B1 = 24.0_rp
82 real(RP), parameter :: B2 = 15.0_rp
83
84 real(RP), parameter :: C1 = 0.137_rp
85 real(RP), parameter :: C2 = 0.75_rp
86 real(RP), parameter :: C3 = 0.352_rp
87 real(RP), parameter :: C5 = 0.2_rp
88
89 real(RP), parameter :: G1 = 0.235_rp
90
91 ! Derived constants
92 real(RP) :: G2
93 real(RP) :: F2
94 real(RP) :: Rf2
95 real(RP) :: RFc
96
97 ! Limiter with mixing length
98 real(RP) :: L_INF = 100.0_rp
99 real(RP) :: L_MIN = 1.0e-6_rp
100
101contains
102 !> Initialize a module of MYNN Level 2 PBL turbulence parameterization
103!OCL SERIAL
105 implicit none
106 class(meshbase3d), intent(in) :: mesh
107
108 namelist / param_atmos_phy_bl_dgm_mynn_lv2 / &
109 l_inf, l_min
110
111 integer :: ierr
112 !--------------------------------------------------------------------------------
113
114 log_newline
115 log_info("ATMOS_PHY_BL_DGM_MYNN_LV2_setup",*) 'Setup'
116 log_info("ATMOS_PHY_BL_DGM_MYNN_LV2_setup",*) 'MYNN Level 2 PBL turbulence parameterization'
117
118 !--- read namelist
119 rewind(io_fid_conf)
120 read(io_fid_conf,nml=param_atmos_phy_bl_dgm_mynn_lv2,iostat=ierr)
121 if( ierr < 0 ) then !--- missing
122 log_info("ATMOS_PHY_BL_DGM_MYNN_LV2_setup",*) 'Not found namelist. Default used.'
123 elseif( ierr > 0 ) then !--- fatal error
124 log_error("ATMOS_PHY_BL_DGM_MYNN_LV2_setup",*) 'Not appropriate names in namelist PARAM_ATMOS_PHY_BL_DGM_MYNN_LV2. Check!'
125 call prc_abort
126 endif
127 log_nml(param_atmos_phy_bl_dgm_mynn_lv2)
128
129 !-
130
131 g2 = ( 2.0_rp * a1 * ( 3.0_rp - 2.0_rp * c2 ) &
132 + b2 * ( 1.0_rp - c3 ) &
133 ) / b1
134
135 f2 = b1 * ( g1 + g2 ) &
136 - 3.0_rp * a1 * ( 1.0_rp - c2 )
137
138 rf2 = b1 * g1 / f2
139
140 rfc = g1 / ( g1 + g2 )
141 return
142 end subroutine atm_phy_bl_dgm_mynn_lv2_init
143
144 !> Finalize a module of MYNN Level 2 PBL turbulence parameterization
145!OCL SERIAL
147 implicit none
148 !--------------------------------------------------------------------------------
149 return
150 end subroutine atm_phy_bl_dgm_mynn_lv2_final
151
152!OCL SERIAL
154 Nu, Kh, TKE, & ! (out)
155 ddens_, momx_, momy_, momz_, drhot_, dens_hyd, pres_hyd, & ! (in)
156 rtot, pres, pt, & ! (in)
157 dz, lift, lmesh, elem, is_bound ) ! (in)
158 implicit none
159 class(localmesh3d), intent(in) :: lmesh
160 class(elementbase3d), intent(in) :: elem
161 real(rp), intent(out) :: nu(elem%np,lmesh%nea) !< Vertical eddy viscosity
162 real(rp), intent(out) :: kh(elem%np,lmesh%nea) !< Vertical eddy diffusivity
163 real(rp), intent(out) :: tke(elem%np,lmesh%nea) !< Turbulent kinetic energy
164 real(rp), intent(in) :: ddens_(elem%np,lmesh%nea) !< Density perturbation
165 real(rp), intent(in) :: momx_ (elem%np,lmesh%nea) !< Momentum in x1 direction
166 real(rp), intent(in) :: momy_ (elem%np,lmesh%nea) !< Momentum in x2 direction
167 real(rp), intent(in) :: momz_ (elem%np,lmesh%nea) !< Momentum in x3 direction
168 real(rp), intent(in) :: drhot_(elem%np,lmesh%nea) !< Density x potential temperature perturbation
169 real(rp), intent(in) :: dens_hyd(elem%np,lmesh%nea) !< Reference density in hydrostatic balance
170 real(rp), intent(in) :: pres_hyd(elem%np,lmesh%nea) !< Reference pressure in hydrostatic balance
171 real(rp), intent(in) :: rtot(elem%np,lmesh%nea) !< Gas constant
172 real(rp), intent(in) :: pres(elem%np,lmesh%nea) !< Pressure
173 real(rp), intent(in) :: pt(elem%np,lmesh%nea) !< Potential temperature
174 type(sparsemat), intent(in) :: dz, lift
175 logical, intent(in) :: is_bound(elem%nfptot,lmesh%ne) !< Flag whether nodes are located at domain boundaries
176
177 real(rp) :: fz(elem%np), liftdelflx(elem%np)
178 real(rp) :: dens(elem%np), rdens(elem%np), rhot(elem%np), q(elem%np)
179 real(rp) :: ddensdz(elem%np), dveldz(elem%np,3), dptdz(elem%np), drtotdz(elem%np)
180
181 real(rp) :: del_flux_rho (elem%nfptot,lmesh%ne)
182 real(rp) :: del_flux_mom (elem%nfptot,lmesh%ne,3)
183 real(rp) :: del_flux_rhot(elem%nfptot,lmesh%ne)
184 real(rp) :: del_flux_rtot(elem%nfptot,lmesh%ne)
185
186 real(rp) :: s2(elem%np) ! Square of vertical shear of horizontal wind
187 real(rp) :: n2 ! Square of Brunt-Vaisala frequency
188 real(rp) :: ri ! Richardson number
189 real(rp) :: rf(elem%np) ! Flux Richardson number
190
191 real(rp) :: a2_loc
192 real(rp) :: f1
193 real(rp) :: rf1
194 real(rp) :: af12
195 real(rp) :: discriminant
196 real(rp) :: denom_h
197 real(rp) :: denom_m
198 real(rp) :: s_m(elem%np), s_h(elem%np) ! Stability functions for momentum and heat
199
200 real(rp) :: mixlen(elem%np) ! Mixing length
201 real(rp) :: zsfc(elem%nnode_h1d**2,lmesh%ne2d) ! Surface height
202 real(rp) :: dz1(elem%nnode_h1d**2,lmesh%ne2d) ! Vertical grid spacing at the first layer
203 integer :: hslice_b(elem%nnode_h1d**2)
204 integer :: hslice_t(elem%nnode_h1d**2)
205
206 real(rp) :: kz
207
208 integer :: ke, ke2d
209 integer :: p, ph, pz
210 class(localmesh2d), pointer :: lmesh2d
211 class(elementbase2d), pointer :: elem2d
212
213 real(rp), parameter :: eps_rf = 1.0e-10_rp
214 real(rp), parameter :: eps_disc = 1.0e-14_rp
215 !--------------------------------------------------------------------------------
216
217 ! For standard case of NN2009, these parameter are independent of Ri.
218 ! If we will implement the K2010 correction in the future,
219 ! these parameter should be calculated in the ke loop because they depend on Ri (i.e., A2_loc = A_2/(1+Ri)).
220 a2_loc = a2
221
222 f1 = b1 * ( g1 - c1 ) &
223 + 2.0_rp * a1 * ( 3.0_rp - 2.0_rp * c2 ) &
224 + 3.0_rp * a2_loc * ( 1.0_rp - c3 ) * ( 1.0_rp - c5 )
225
226 rf1 = b1 * ( g1 - c1 ) / f1
227
228 af12 = a1 * f1 / ( a2_loc * f2 )
229
230 lmesh2d => lmesh%lcmesh2D
231 elem2d => lmesh2d%refElem2D
232
233 hslice_b(:) = elem%Hslice(:,1)
234 hslice_t(:) = elem%Hslice(:,elem%Nnode_v)
235
236 !---------------------------------
237
238 call cal_del_flux_grad( del_flux_rho, del_flux_mom, del_flux_rhot, del_flux_rtot, & ! (out)
239 ddens_, momx_, momy_, momz_, drhot_, rtot, dens_hyd, pres_hyd, pt, & ! (in)
240 lmesh%normal_fn(:,:,3), lmesh%Fscale, lmesh%vmapM, lmesh%vmapP, & ! (in)
241 lmesh, elem, is_bound ) ! (in)
242
243 !$omp parallel &
244 !$omp private( ke2D, Fz, LiftDelFlx, DENS, RDENS, RHOT, Q, DdensDz, DVelDz, DptDz, DrtotDz, &
245 !$omp N2, S2, Ri, Rf, discriminant, denom_m, denom_h, S_M, S_H, mixlen, kz )
246
247 !$omp do
248 do ke2d=lmesh2d%NeS, lmesh2d%NeE
249 zsfc(:,ke2d) = lmesh%zlev(hslice_b,ke2d)
250 dz1(:,ke2d) = ( lmesh%zlev(hslice_t,ke2d) - lmesh%zlev(hslice_b,ke2d) ) / real(elem%Nnode_v,kind=rp) * 0.5_rp
251 end do
252 !$omp end do
253 !$omp do
254 do ke=lmesh%NeS, lmesh%NeE
255 dens(:) = dens_hyd(:,ke) + ddens_(:,ke)
256 rdens(:) = 1.0_rp / dens(:)
257 rhot(:) = dens(:) * pt(:,ke)
258
259 ! gradient of density
260 call sparsemat_matmul( dz, dens, fz )
261 call sparsemat_matmul( lift, del_flux_rho(:,ke), liftdelflx )
262 ddensdz(:) = lmesh%Escale(:,ke,3,3) * fz(:) + liftdelflx(:)
263
264 ! gradient of u
265 q(:) = momx_(:,ke) * rdens(:)
266 call sparsemat_matmul( dz, momx_(:,ke), fz )
267 call sparsemat_matmul( lift, del_flux_mom(:,ke,1), liftdelflx )
268 dveldz(:,1) = ( lmesh%Escale(:,ke,3,3) * fz(:) + liftdelflx(:) - q(:) * ddensdz(:) ) * rdens(:)
269
270 ! gradient of v
271 q(:) = momy_(:,ke) * rdens(:)
272 call sparsemat_matmul( dz, momy_(:,ke), fz )
273 call sparsemat_matmul( lift, del_flux_mom(:,ke,2), liftdelflx )
274 dveldz(:,2) = ( lmesh%Escale(:,ke,3,3) * fz(:) + liftdelflx(:) - q(:) * ddensdz(:) ) * rdens(:)
275
276 ! gradient of pt
277 q(:) = rhot(:) * rdens(:)
278 call sparsemat_matmul( dz, rhot(:) , fz )
279 call sparsemat_matmul( lift, del_flux_rhot(:,ke), liftdelflx )
280 dptdz(:) = ( lmesh%Escale(:,ke,3,3) * fz(:) + liftdelflx(:) - q(:) * ddensdz(:) ) * rdens(:)
281
282 ! gradient of Rtot
283 call sparsemat_matmul( dz, rtot(:,ke), fz )
284 call sparsemat_matmul( lift, del_flux_rtot(:,ke), liftdelflx )
285 drtotdz(:) = lmesh%Escale(:,ke,3,3) * fz(:) + liftdelflx(:)
286
287 ! Calculate flux Richardson number: Rf
288 do p=1, elem%Np
289 n2 = grav * ( dptdz(p) / pt(p,ke) + drtotdz(p) / rtot(p,ke) )
290
291 s2(p) = dveldz(p,1)**2 + dveldz(p,2)**2
292 ri = n2 / max(s2(p), eps)
293
294 discriminant = ri * ri &
295 + 2.0_rp * af12 * ( rf1 - 2.0_rp * rf2 ) * ri &
296 + ( af12 * rf1 )**2
297 discriminant = max( discriminant, 0.0_rp )
298
299 rf(p) = 0.5_rp / af12 * ( ri + af12 * rf1 - sqrt(discriminant) )
300 rf(p) = min( rf(p), rfc - eps_rf )
301 end do
302
303 ! Calculate stability function: S_M and S_H
304 do p=1, elem%Np
305 denom_h = max( 1.0_rp - rf(p), eps_rf )
306 s_h(p) = 3.0_rp * a2_loc * ( g1 + g2 ) * ( rfc - rf(p) ) / denom_h
307
308 denom_m = rf2 - rf(p)
309 if ( abs(denom_m) < eps_rf ) then
310 denom_m = sign(eps_rf, denom_m)
311 end if
312 s_m(p) = s_h(p) * af12 * ( rf1 - rf(p) ) / denom_m
313
314 s_m(p) = max( s_m(p), 0.0_rp )
315 s_h(p) = max( s_h(p), 0.0_rp )
316 end do
317
318 ! Calculate mixing length
319
320 ke2d = lmesh%EMap3Dto2D(ke)
321 do pz=1, elem%Nnode_v
322 do ph=1, elem%Nnode_h1D**2
323 p = ph + (pz-1)*elem%Nnode_h1D**2
324 kz = karman * max( lmesh%zlev(p,ke) - zsfc(ph,ke2d), dz1(ph,ke2d) )
325
326 mixlen(p) = kz * l_inf / max( kz + l_inf, l_min )
327 end do
328 end do
329
330 ! Calculate eddy viscosity and diffusivity
331 do p=1, elem%Np
332 ! q^2
333 q(p) = b1 * mixlen(p)**2 &
334 * s_m(p) * max( 1.0_rp - rf(p), 0.0_rp ) * s2(p)
335 tke(p,ke) = 0.5_rp * max( q(p), 0.0_rp )
336
337 q(p) = sqrt( 2.0_rp * tke(p,ke) )
338 kh(p,ke) = mixlen(p) * q(p) * s_h(p)
339 nu(p,ke) = mixlen(p) * q(p) * s_m(p)
340 end do
341 end do
342 !$omp end do
343 !$omp end parallel
344
345 return
347
348!-- private --------------------------------------------------------
349
350!OCL SERIAL
351 subroutine cal_del_flux_grad( del_flux_rho, del_flux_mom, del_flux_rhot, del_flux_Rtot, & ! (out)
352 ddens_, momx_, momy_, momz_, drhot_, rtot, dens_hyd, pres_hyd, pt_, & ! (in)
353 nz, fscale, vmapm, vmapp, lmesh, elem, is_bound ) ! (in)
354
355 implicit none
356
357 class(localmesh3d), intent(in) :: lmesh
358 class(elementbase3d), intent(in) :: elem
359 real(rp), intent(out) :: del_flux_rho(elem%nfptot*lmesh%ne)
360 real(rp), intent(out) :: del_flux_mom(elem%nfptot*lmesh%ne,3)
361 real(rp), intent(out) :: del_flux_rhot(elem%nfptot*lmesh%ne)
362 real(rp), intent(out) :: del_flux_rtot(elem%nfptot*lmesh%ne)
363 real(rp), intent(in) :: ddens_(elem%np*lmesh%nea)
364 real(rp), intent(in) :: momx_(elem%np*lmesh%nea)
365 real(rp), intent(in) :: momy_(elem%np*lmesh%nea)
366 real(rp), intent(in) :: momz_(elem%np*lmesh%nea)
367 real(rp), intent(in) :: drhot_(elem%np*lmesh%nea)
368 real(rp), intent(in) :: rtot(elem%np*lmesh%nea)
369 real(rp), intent(in) :: dens_hyd(elem%np*lmesh%nea)
370 real(rp), intent(in) :: pres_hyd(elem%np*lmesh%nea)
371 real(rp), intent(in) :: pt_(elem%np*lmesh%nea)
372 real(rp), intent(in) :: nz(elem%nfptot*lmesh%ne)
373 real(rp), intent(in) :: fscale(elem%nfptot*lmesh%ne)
374 integer, intent(in) :: vmapm(elem%nfptot*lmesh%ne)
375 integer, intent(in) :: vmapp(elem%nfptot*lmesh%ne)
376 logical, intent(in) :: is_bound(elem%nfptot*lmesh%ne)
377
378 integer :: i, ip, im
379 real(rp) :: densm, densp
380 real(rp) :: facz
381 !------------------------------------------------------------------------
382
383 !$omp parallel do private ( iM, iP, densM, densP, facz )
384 do i=1, elem%NfpTot * lmesh%Ne
385 im = vmapm(i); ip = vmapp(i)
386
387 densm = ddens_(im) + dens_hyd(im)
388 densp = ddens_(ip) + dens_hyd(ip)
389
390 if ( is_bound(i) ) then
391 facz = 0.5_rp * fscale(i) * nz(i)
392 else
393 ! facz = ( 1.0_RP - sign(1.0_RP,nz(i)) ) * Fscale(i) * nz(i)
394 facz = 0.5_rp * fscale(i) * nz(i)
395 end if
396
397 del_flux_rho(i) = facz * ( densp - densm )
398
399 del_flux_mom(i,1) = facz * ( momx_(ip) - momx_(im) )
400 del_flux_mom(i,2) = facz * ( momy_(ip) - momy_(im) )
401 del_flux_mom(i,3) = facz * ( momz_(ip) - momz_(im) )
402
403 del_flux_rhot(i) = facz * ( densp * pt_(ip) - densm * pt_(im) )
404 del_flux_rtot(i) = facz * ( rtot(ip) - rtot(im) )
405 end do
406
407 return
408 end subroutine cal_del_flux_grad
module FElib / Atmosphere / Physics / boundary layer turbulence
subroutine, public atm_phy_bl_dgm_mynn_lv2_init(mesh)
Initialize a module of MYNN Level 2 PBL turbulence parameterization.
subroutine, public atm_phy_bl_dgm_mynn_lv2_cal_vviscdiffcoef(nu, kh, tke, ddens_, momx_, momy_, momz_, drhot_, dens_hyd, pres_hyd, rtot, pres, pt, dz, lift, lmesh, elem, is_bound)
subroutine, public atm_phy_bl_dgm_mynn_lv2_final()
Finalize a module of MYNN Level 2 PBL turbulence parameterization.
module FElib / Element / Base
module FElib / Element / hexahedron
module FElib / Mesh / Local 2D
module FElib / Mesh / Local 3D
module FElib / Mesh / Base 3D
module FElib / Data / base
Module common / sparsemat.
Derived type representing a 2D reference element.
Derived type representing a 3D reference element.
Derived type representing a hexahedral element.
Derived type representing a local mesh for 2D domain.
Derived type to manage a local 3D computational domain.
Derived type representing a field with 3D local mesh.
Derived type to manage a computational mesh (base type for 3D domain)
Derived type representing a field with 3D mesh.
Derived type to manage a sparse matrix.