Line data Source code
1 : module gw_rdg
2 :
3 : !
4 : ! This module handles gravity waves from orographic sources, and was
5 : ! extracted from gw_drag in May 2013.
6 : !
7 : use shr_const_mod, only: pii => shr_const_pi
8 : use gw_utils, only: r8
9 : use gw_common, only: pver
10 : use coords_1d, only: Coords1D
11 : use spmd_utils,only: masterproc
12 : use cam_abortutils, only: endrun
13 :
14 :
15 : implicit none
16 : private
17 : save
18 :
19 : ! Public interface
20 : public :: gw_rdg_readnl
21 : public :: gw_rdg_src
22 : public :: gw_rdg_resid_src
23 : public :: gw_rdg_belowpeak
24 : public :: gw_rdg_break_trap
25 : public :: gw_rdg_do_vdiff
26 :
27 : ! Tunable Parameters
28 : !--------------------
29 : logical :: do_divstream
30 :
31 : !===========================================
32 : ! Parameters for DS2017 (do_divstream=.T.)
33 : !===========================================
34 : ! Amplification factor - 1.0 for
35 : ! high-drag/windstorm regime
36 : real(r8), protected :: C_BetaMax_DS
37 :
38 : ! Max Ratio Fr2:Fr1 - 1.0
39 : real(r8), protected :: C_GammaMax
40 :
41 : ! Normalized limits for Fr2(Frx) function
42 : real(r8), protected :: Frx0
43 : real(r8), protected :: Frx1
44 :
45 :
46 : !===========================================
47 : ! Parameters for SM2000
48 : !===========================================
49 : ! Amplification factor - 1.0 for
50 : ! high-drag/windstorm regime
51 : real(r8), protected :: C_BetaMax_SM
52 :
53 :
54 :
55 : ! NOTE: Critical inverse Froude number Fr_c is
56 : ! 1./(SQRT(2.)~0.707 in SM2000
57 : ! (should be <= 1)
58 : real(r8), protected :: Fr_c
59 :
60 : logical, protected :: gw_rdg_do_vdiff=.true.
61 :
62 : logical :: do_smooth_regimes
63 : logical :: do_adjust_tauoro
64 : logical :: do_backward_compat
65 :
66 :
67 : ! Limiters (min/max values)
68 : ! min surface displacement height for orographic waves (m)
69 : real(r8), protected :: orohmin
70 : ! min wind speed for orographic waves
71 : real(r8), protected :: orovmin
72 : ! min stratification allowing wave behavior
73 : real(r8), protected :: orostratmin
74 : ! min stratification allowing wave behavior
75 : real(r8), protected :: orom2min
76 :
77 : !==========================================================================
78 : contains
79 : !==========================================================================
80 :
81 2304 : subroutine gw_rdg_readnl(nlfile)
82 : use namelist_utils, only: find_group_name
83 : use units, only: getunit, freeunit
84 : use spmd_utils, only: mpicom, mstrid=>masterprocid, mpi_real8, mpi_logical
85 :
86 : ! File containing namelist input.
87 : character(len=*), intent(in) :: nlfile
88 :
89 : ! Local variables
90 : integer :: unitn, ierr
91 : character(len=*), parameter :: sub = 'gw_rdg_readnl'
92 :
93 : logical :: gw_rdg_do_divstream, gw_rdg_do_smooth_regimes, gw_rdg_do_adjust_tauoro, &
94 : gw_rdg_do_backward_compat
95 :
96 :
97 : real(r8) :: gw_rdg_C_BetaMax_DS, gw_rdg_C_GammaMax, &
98 : gw_rdg_Frx0, gw_rdg_Frx1, gw_rdg_C_BetaMax_SM, gw_rdg_Fr_c, &
99 : gw_rdg_orohmin, gw_rdg_orovmin, gw_rdg_orostratmin, gw_rdg_orom2min
100 :
101 : namelist /gw_rdg_nl/ gw_rdg_do_divstream, gw_rdg_C_BetaMax_DS, gw_rdg_C_GammaMax, &
102 : gw_rdg_Frx0, gw_rdg_Frx1, gw_rdg_C_BetaMax_SM, gw_rdg_Fr_c, &
103 : gw_rdg_do_smooth_regimes, gw_rdg_do_adjust_tauoro, &
104 : gw_rdg_do_backward_compat, gw_rdg_orohmin, gw_rdg_orovmin, &
105 : gw_rdg_orostratmin, gw_rdg_orom2min, gw_rdg_do_vdiff
106 :
107 : !----------------------------------------------------------------------
108 :
109 2304 : if (masterproc) then
110 3 : unitn = getunit()
111 3 : open( unitn, file=trim(nlfile), status='old' )
112 3 : call find_group_name(unitn, 'gw_rdg_nl', status=ierr)
113 3 : if (ierr == 0) then
114 3 : read(unitn, gw_rdg_nl, iostat=ierr)
115 3 : if (ierr /= 0) then
116 0 : call endrun(sub // ':: ERROR reading namelist')
117 : end if
118 : end if
119 3 : close(unitn)
120 3 : call freeunit(unitn)
121 :
122 : ! Set the local variables
123 3 : do_divstream = gw_rdg_do_divstream
124 3 : C_BetaMax_DS = gw_rdg_C_BetaMax_DS
125 3 : C_GammaMax = gw_rdg_C_GammaMax
126 3 : Frx0 = gw_rdg_Frx0
127 3 : Frx1 = gw_rdg_Frx1
128 3 : C_BetaMax_SM = gw_rdg_C_BetaMax_SM
129 3 : Fr_c = gw_rdg_Fr_c
130 3 : do_smooth_regimes = gw_rdg_do_smooth_regimes
131 3 : do_adjust_tauoro = gw_rdg_do_adjust_tauoro
132 3 : do_backward_compat = gw_rdg_do_backward_compat
133 3 : orohmin = gw_rdg_orohmin
134 3 : orovmin = gw_rdg_orovmin
135 3 : orostratmin = gw_rdg_orostratmin
136 3 : orom2min = gw_rdg_orom2min
137 : end if
138 :
139 : ! Broadcast the local variables
140 :
141 2304 : call mpi_bcast(do_divstream, 1, mpi_logical, mstrid, mpicom, ierr)
142 2304 : if (ierr /= 0) call endrun(sub//": FATAL: mpi_bcast: do_divstream")
143 2304 : call mpi_bcast(do_smooth_regimes, 1, mpi_logical, mstrid, mpicom, ierr)
144 2304 : if (ierr /= 0) call endrun(sub//": FATAL: mpi_bcast: do_smooth_regimes")
145 2304 : call mpi_bcast(do_adjust_tauoro, 1, mpi_logical, mstrid, mpicom, ierr)
146 2304 : if (ierr /= 0) call endrun(sub//": FATAL: mpi_bcast: do_adjust_tauoro")
147 2304 : call mpi_bcast(do_backward_compat, 1, mpi_logical, mstrid, mpicom, ierr)
148 2304 : if (ierr /= 0) call endrun(sub//": FATAL: mpi_bcast: do_backward_compat")
149 :
150 2304 : call mpi_bcast(C_BetaMax_DS, 1, mpi_real8, mstrid, mpicom, ierr)
151 2304 : if (ierr /= 0) call endrun(sub//": FATAL: mpi_bcast: C_BetaMax_DS")
152 2304 : call mpi_bcast(C_GammaMax, 1, mpi_real8, mstrid, mpicom, ierr)
153 2304 : if (ierr /= 0) call endrun(sub//": FATAL: mpi_bcast: C_GammaMax")
154 2304 : call mpi_bcast(Frx0, 1, mpi_real8, mstrid, mpicom, ierr)
155 2304 : if (ierr /= 0) call endrun(sub//": FATAL: mpi_bcast: Frx0")
156 2304 : call mpi_bcast(Frx1, 1, mpi_real8, mstrid, mpicom, ierr)
157 2304 : if (ierr /= 0) call endrun(sub//": FATAL: mpi_bcast: Frx1")
158 2304 : call mpi_bcast(C_BetaMax_SM, 1, mpi_real8, mstrid, mpicom, ierr)
159 2304 : if (ierr /= 0) call endrun(sub//": FATAL: mpi_bcast: C_BetaMax_SM")
160 2304 : call mpi_bcast(Fr_c, 1, mpi_real8, mstrid, mpicom, ierr)
161 2304 : if (ierr /= 0) call endrun(sub//": FATAL: mpi_bcast: Fr_c")
162 2304 : call mpi_bcast(orohmin, 1, mpi_real8, mstrid, mpicom, ierr)
163 2304 : if (ierr /= 0) call endrun(sub//": FATAL: mpi_bcast: orohmin")
164 2304 : call mpi_bcast(orovmin, 1, mpi_real8, mstrid, mpicom, ierr)
165 2304 : if (ierr /= 0) call endrun(sub//": FATAL: mpi_bcast: orovmin")
166 2304 : call mpi_bcast(orostratmin, 1, mpi_real8, mstrid, mpicom, ierr)
167 2304 : if (ierr /= 0) call endrun(sub//": FATAL: mpi_bcast: orostratmin")
168 2304 : call mpi_bcast(orom2min, 1, mpi_real8, mstrid, mpicom, ierr)
169 2304 : if (ierr /= 0) call endrun(sub//": FATAL: mpi_bcast: orom2min")
170 :
171 2304 : call mpi_bcast(gw_rdg_do_vdiff, 1, mpi_logical, mstrid, mpicom, ierr)
172 2304 : if (ierr /= 0) call endrun(sub//": FATAL: mpi_bcast: gw_rdg_do_vdiff")
173 :
174 2304 : if (Fr_c > 1.0_r8) call endrun(sub//": FATAL: Fr_c must be <= 1")
175 :
176 2304 : end subroutine gw_rdg_readnl
177 :
178 :
179 : !==========================================================================
180 0 : subroutine gw_rdg_resid_src(ncol, band, p, &
181 0 : u, v, t, mxdis, kwvrdg, zi, nm, &
182 0 : src_level, tend_level, tau, ubm, ubi, xv, yv, &
183 0 : ubmsrc, usrc, vsrc, nsrc, rsrc, m2src, c, tauoro )
184 : use gw_common, only: rair, GWBand
185 : use gw_utils, only: dot_2d, midpoint_interp, get_unit_vector
186 : !-----------------------------------------------------------------------
187 : ! Orographic source for multiple gravity wave drag parameterization.
188 : !
189 : ! The stress is returned for a single wave with c=0, over orography.
190 : ! For points where the orographic variance is small (including ocean),
191 : ! the returned stress is zero.
192 : !------------------------------Arguments--------------------------------
193 : ! Column dimension.
194 : integer, intent(in) :: ncol
195 :
196 : ! Band to emit orographic waves in.
197 : ! Regardless, we will only ever emit into l = 0.
198 : type(GWBand), intent(in) :: band
199 : ! Pressure coordinates.
200 : type(Coords1D), intent(in) :: p
201 :
202 :
203 : ! Midpoint zonal/meridional winds. ( m s-1)
204 : real(r8), intent(in) :: u(ncol,pver), v(ncol,pver)
205 : ! Midpoint temperatures. (K)
206 : real(r8), intent(in) :: t(ncol,pver)
207 : ! Height estimate for ridge (m) [anisotropic orography].
208 : real(r8), intent(in) :: mxdis(ncol)
209 : ! horiz wavenumber [anisotropic orography].
210 : real(r8), intent(in) :: kwvrdg(ncol)
211 : ! Interface altitudes above ground (m).
212 : real(r8), intent(in) :: zi(ncol,pver+1)
213 : ! Midpoint Brunt-Vaisalla frequencies (s-1).
214 : real(r8), intent(in) :: nm(ncol,pver)
215 :
216 : ! Indices of top gravity wave source level and lowest level where wind
217 : ! tendencies are allowed.
218 : integer, intent(out) :: src_level(ncol)
219 : integer, intent(out) :: tend_level(ncol)
220 :
221 : ! Averages over source region.
222 : real(r8), intent(out) :: nsrc(ncol) ! B-V frequency.
223 : real(r8), intent(out) :: rsrc(ncol) ! Density.
224 : real(r8), intent(out) :: usrc(ncol) ! Zonal wind.
225 : real(r8), intent(out) :: vsrc(ncol) ! Meridional wind.
226 : real(r8), intent(out) :: ubmsrc(ncol) ! On-obstacle wind.
227 : ! normalized wavenumber
228 : real(r8), intent(out) :: m2src(ncol)
229 :
230 :
231 : ! Wave Reynolds stress.
232 : real(r8), intent(out) :: tau(ncol,-band%ngwv:band%ngwv,pver+1)
233 : ! Projection of wind at midpoints and interfaces.
234 : real(r8), intent(out) :: ubm(ncol,pver), ubi(ncol,pver+1)
235 : ! Unit vectors of source wind (zonal and meridional components).
236 : real(r8), intent(out) :: xv(ncol), yv(ncol)
237 : ! Phase speeds.
238 : real(r8), intent(out) :: c(ncol,-band%ngwv:band%ngwv)
239 : ! source level mom. flux
240 : real(r8), intent(out) :: tauoro(ncol)
241 :
242 : !---------------------------Local Storage-------------------------------
243 : ! Column and level indices.
244 : integer :: i, k
245 :
246 : ! Surface streamline displacement height (2*sgh).
247 0 : real(r8) :: hdsp(ncol)
248 :
249 : ! Difference in interface pressure across source region.
250 0 : real(r8) :: dpsrc(ncol)
251 : ! Thickness of downslope wind region.
252 : real(r8) :: ddw(ncol)
253 : ! Thickness of linear wave region.
254 : real(r8) :: dwv(ncol)
255 : ! Wind speed in source region.
256 0 : real(r8) :: wmsrc(ncol)
257 :
258 : real(r8) :: ragl(ncol)
259 : real(r8) :: Fcrit_res,sghmax
260 :
261 : !--------------------------------------------------------------------------
262 : ! Check that ngwav is equal to zero, otherwise end the job
263 : !--------------------------------------------------------------------------
264 0 : if (band%ngwv /= 0) call endrun(' gw_rdg_src :: ERROR - band%ngwv must be zero and it is not')
265 :
266 : !--------------------------------------------------------------------------
267 : ! Average the basic state variables for the wave source over the depth of
268 : ! the orographic standard deviation. Here we assume that the appropiate
269 : ! values of wind, stability, etc. for determining the wave source are
270 : ! averages over the depth of the atmosphere penterated by the typical
271 : ! mountain.
272 : ! Reduces to the bottom midpoint values when mxdis=0, such as over ocean.
273 : !--------------------------------------------------------------------------
274 :
275 0 : Fcrit_res = 1.0_r8
276 0 : hdsp = mxdis ! no longer multipied by 2
277 0 : where(hdsp < 10._r8)
278 : hdsp = 0._r8
279 : end where
280 :
281 0 : src_level = pver+1
282 :
283 0 : tau(:,0,:) = 0.0_r8
284 :
285 : ! Find depth of "source layer" for mountain waves
286 : ! i.e., between ground and mountain top
287 0 : do k = pver, 1, -1
288 0 : do i = 1, ncol
289 : ! Need to have h >= z(k+1) here or code will bomb when h=0.
290 0 : if ( (hdsp(i) >= zi(i,k+1)) .and. (hdsp(i) < zi(i,k)) ) then
291 0 : src_level(i) = k
292 : end if
293 : end do
294 : end do
295 :
296 0 : rsrc = 0._r8
297 0 : usrc = 0._r8
298 0 : vsrc = 0._r8
299 0 : nsrc = 0._r8
300 0 : do i = 1, ncol
301 0 : do k = pver, src_level(i), -1
302 0 : rsrc(i) = rsrc(i) + p%mid(i,k) / (rair*t(i,k))* p%del(i,k)
303 0 : usrc(i) = usrc(i) + u(i,k) * p%del(i,k)
304 0 : vsrc(i) = vsrc(i) + v(i,k) * p%del(i,k)
305 0 : nsrc(i) = nsrc(i) + nm(i,k)* p%del(i,k)
306 : end do
307 : end do
308 :
309 :
310 0 : do i = 1, ncol
311 0 : dpsrc(i) = p%ifc(i,pver+1) - p%ifc(i,src_level(i))
312 : end do
313 :
314 0 : rsrc = rsrc / dpsrc
315 0 : usrc = usrc / dpsrc
316 0 : vsrc = vsrc / dpsrc
317 0 : nsrc = nsrc / dpsrc
318 :
319 : ! Get the unit vector components and magnitude at the surface.
320 0 : call get_unit_vector(usrc, vsrc, xv, yv, wmsrc )
321 :
322 0 : ubmsrc = wmsrc
323 :
324 : ! Project the local wind at midpoints onto the source wind.
325 0 : do k = 1, pver
326 0 : ubm(:,k) = dot_2d(u(:,k), v(:,k), xv, yv)
327 : end do
328 :
329 : ! Compute the interface wind projection by averaging the midpoint winds.
330 : ! Use the top level wind at the top interface.
331 0 : ubi(:,1) = ubm(:,1)
332 :
333 0 : ubi(:,2:pver) = midpoint_interp(ubm)
334 :
335 : ! The minimum stratification allowing GW behavior
336 : ! should really depend on horizontal scale since
337 : !
338 : ! m^2 ~ (N/U)^2 - k^2
339 : !
340 :
341 0 : m2src = ( (nsrc/(ubmsrc+0.01_r8))**2 - kwvrdg**2 ) /((nsrc/(ubmsrc+0.01_r8))**2)
342 :
343 : ! Compute the interface wind projection by averaging the midpoint winds.
344 : ! Use the top level wind at the top interface.
345 0 : ubi(:,1) = ubm(:,1)
346 0 : ubi(:,2:pver) = midpoint_interp(ubm)
347 0 : ubi(:,pver+1) = ubm(:,pver)
348 :
349 :
350 :
351 : ! Determine the orographic c=0 source term following McFarlane (1987).
352 : ! (DOI: https://doi.org/10.1175/1520-0469(1987)044<1775:TEOOEG>2.0.CO;2)
353 : ! Set the source top interface index to pver, if the orographic term is
354 : ! zero.
355 0 : do i = 1, ncol
356 0 : if ( ( src_level(i) > 0 ) .and. ( m2src(i) > orom2min ) ) then
357 0 : sghmax = Fcrit_res * (ubmsrc(i) / nsrc(i))**2
358 : tauoro(i) = 0.5_r8 * kwvrdg(i) * min(hdsp(i)**2, sghmax) * &
359 0 : rsrc(i) * nsrc(i) * ubmsrc(i)
360 : else
361 0 : tauoro(i) = 0._r8
362 : end if
363 : end do
364 :
365 0 : do i = 1, ncol
366 0 : do k=src_level(i),pver+1
367 0 : tau(i,0,k) = tauoro(i)
368 : end do
369 : end do
370 :
371 :
372 : ! Allow wind tendencies all the way to the model bottom.
373 0 : tend_level = pver
374 :
375 : ! No spectrum; phase speed is just 0.
376 0 : c = 0._r8
377 :
378 0 : end subroutine gw_rdg_resid_src
379 :
380 :
381 : !==========================================================================
382 :
383 897840 : subroutine gw_rdg_src(ncol, band, p, &
384 897840 : u, v, t, mxdis, angxy, anixy, kwvrdg, iso, zi, nm, &
385 897840 : src_level, tend_level, bwv_level ,tlb_level , tau, ubm, ubi, xv, yv, &
386 897840 : ubmsrc, usrc, vsrc, nsrc, rsrc, m2src, tlb, bwv, Fr1, Fr2, Frx, c)
387 : use gw_common, only: rair, GWBand
388 : use gw_utils, only: dot_2d, midpoint_interp
389 : !-----------------------------------------------------------------------
390 : ! Orographic source for multiple gravity wave drag parameterization.
391 : !
392 : ! The stress is returned for a single wave with c=0, over orography.
393 : ! For points where the orographic variance is small (including ocean),
394 : ! the returned stress is zero.
395 : !------------------------------Arguments--------------------------------
396 : ! Column dimension.
397 : integer, intent(in) :: ncol
398 :
399 : ! Band to emit orographic waves in.
400 : ! Regardless, we will only ever emit into l = 0.
401 : type(GWBand), intent(in) :: band
402 : ! Pressure coordinates.
403 : type(Coords1D), intent(in) :: p
404 :
405 :
406 : ! Midpoint zonal/meridional winds. ( m s-1)
407 : real(r8), intent(in) :: u(ncol,pver), v(ncol,pver)
408 : ! Midpoint temperatures. (K)
409 : real(r8), intent(in) :: t(ncol,pver)
410 : ! Height estimate for ridge (m) [anisotropic orography].
411 : real(r8), intent(in) :: mxdis(ncol)
412 : ! Angle of ridge axis w/resp to north (degrees) [anisotropic orography].
413 : real(r8), intent(in) :: angxy(ncol)
414 : ! Anisotropy parameter [anisotropic orography].
415 : real(r8), intent(in) :: anixy(ncol)
416 : ! horiz wavenumber [anisotropic orography].
417 : real(r8), intent(in) :: kwvrdg(ncol)
418 : ! Isotropic source flag [anisotropic orography].
419 : integer, intent(in) :: iso(ncol)
420 : ! Interface altitudes above ground (m).
421 : real(r8), intent(in) :: zi(ncol,pver+1)
422 : ! Midpoint Brunt-Vaisalla frequencies (s-1).
423 : real(r8), intent(in) :: nm(ncol,pver)
424 :
425 : ! Indices of top gravity wave source level and lowest level where wind
426 : ! tendencies are allowed.
427 : integer, intent(out) :: src_level(ncol)
428 : integer, intent(out) :: tend_level(ncol)
429 : integer, intent(out) :: bwv_level(ncol),tlb_level(ncol)
430 :
431 : ! Averages over source region.
432 : real(r8), intent(out) :: nsrc(ncol) ! B-V frequency.
433 : real(r8), intent(out) :: rsrc(ncol) ! Density.
434 : real(r8), intent(out) :: usrc(ncol) ! Zonal wind.
435 : real(r8), intent(out) :: vsrc(ncol) ! Meridional wind.
436 : real(r8), intent(out) :: ubmsrc(ncol) ! On-ridge wind.
437 : ! Top of low-level flow layer.
438 : real(r8), intent(out) :: tlb(ncol)
439 : ! Bottom of linear wave region.
440 : real(r8), intent(out) :: bwv(ncol)
441 : ! normalized wavenumber
442 : real(r8), intent(out) :: m2src(ncol)
443 :
444 :
445 : ! Wave Reynolds stress.
446 : real(r8), intent(out) :: tau(ncol,-band%ngwv:band%ngwv,pver+1)
447 : ! Projection of wind at midpoints and interfaces.
448 : real(r8), intent(out) :: ubm(ncol,pver), ubi(ncol,pver+1)
449 : ! Unit vectors of source wind (zonal and meridional components).
450 : real(r8), intent(out) :: xv(ncol), yv(ncol)
451 : ! Phase speeds.
452 : real(r8), intent(out) :: c(ncol,-band%ngwv:band%ngwv)
453 : ! Froude numbers for flow/drag regimes
454 : real(r8), intent(out) :: Fr1(ncol), Fr2(ncol), Frx(ncol)
455 :
456 : !---------------------------Local Storage-------------------------------
457 : ! Column and level indices.
458 : integer :: i, k
459 :
460 : ! Surface streamline displacement height (2*sgh).
461 1795680 : real(r8) :: hdsp(ncol)
462 :
463 : ! Difference in interface pressure across source region.
464 1795680 : real(r8) :: dpsrc(ncol)
465 : ! Thickness of downslope wind region.
466 1795680 : real(r8) :: ddw(ncol)
467 : ! Thickness of linear wave region.
468 1795680 : real(r8) :: dwv(ncol)
469 : ! Wind speed in source region.
470 1795680 : real(r8) :: wmsrc(ncol)
471 :
472 1795680 : real(r8) :: ragl(ncol)
473 :
474 : !--------------------------------------------------------------------------
475 : ! Check that ngwav is equal to zero, otherwise end the job
476 : !--------------------------------------------------------------------------
477 897840 : if (band%ngwv /= 0) call endrun(' gw_rdg_src :: ERROR - band%ngwv must be zero and it is not')
478 :
479 : !--------------------------------------------------------------------------
480 : ! Average the basic state variables for the wave source over the depth of
481 : ! the orographic standard deviation. Here we assume that the appropiate
482 : ! values of wind, stability, etc. for determining the wave source are
483 : ! averages over the depth of the atmosphere penterated by the typical
484 : ! mountain.
485 : ! Reduces to the bottom midpoint values when mxdis=0, such as over ocean.
486 : !--------------------------------------------------------------------------
487 :
488 14991840 : hdsp = mxdis ! no longer multipied by 2
489 14991840 : src_level = pver+1
490 14991840 : bwv_level = -1
491 14991840 : tlb_level = -1
492 :
493 1410130800 : tau(:,0,:) = 0.0_r8
494 :
495 : ! Find depth of "source layer" for mountain waves
496 : ! i.e., between ground and mountain top
497 84396960 : do k = pver, 1, -1
498 1395138960 : do i = 1, ncol
499 : ! Need to have h >= z(k+1) here or code will bomb when h=0.
500 1394241120 : if ( (hdsp(i) >= zi(i,k+1)) .and. (hdsp(i) < zi(i,k)) ) then
501 14094000 : src_level(i) = k
502 : end if
503 : end do
504 : end do
505 :
506 14991840 : rsrc = 0._r8
507 14991840 : usrc = 0._r8
508 14991840 : vsrc = 0._r8
509 14991840 : nsrc = 0._r8
510 14991840 : do i = 1, ncol
511 33126218 : do k = pver, src_level(i), -1
512 18134378 : rsrc(i) = rsrc(i) + p%mid(i,k) / (rair*t(i,k))* p%del(i,k)
513 18134378 : usrc(i) = usrc(i) + u(i,k) * p%del(i,k)
514 18134378 : vsrc(i) = vsrc(i) + v(i,k) * p%del(i,k)
515 32228378 : nsrc(i) = nsrc(i) + nm(i,k)* p%del(i,k)
516 : end do
517 : end do
518 :
519 :
520 14991840 : do i = 1, ncol
521 14991840 : dpsrc(i) = p%ifc(i,pver+1) - p%ifc(i,src_level(i))
522 : end do
523 :
524 14991840 : rsrc = rsrc / dpsrc
525 14991840 : usrc = usrc / dpsrc
526 14991840 : vsrc = vsrc / dpsrc
527 14991840 : nsrc = nsrc / dpsrc
528 :
529 14991840 : wmsrc = sqrt( usrc**2 + vsrc**2 )
530 :
531 :
532 : ! Get the unit vector components
533 : ! Want agl=0 with U>0 to give xv=1
534 :
535 14991840 : ragl = angxy * pii/180._r8
536 :
537 : ! protect from wierd "bad" angles
538 : ! that may occur if hdsp is zero
539 14991840 : where( hdsp <= orohmin )
540 : ragl = 0._r8
541 : end where
542 :
543 14991840 : yv =-sin( ragl )
544 14991840 : xv = cos( ragl )
545 :
546 :
547 : ! Kluge in possible "isotropic" obstacle.
548 43179840 : where( ( iso == 1 ) .and. (wmsrc > orovmin) )
549 : xv = usrc/wmsrc
550 : yv = vsrc/wmsrc
551 : end where
552 :
553 :
554 : ! Project the local wind at midpoints into the on-ridge direction
555 84396960 : do k = 1, pver
556 84396960 : ubm(:,k) = dot_2d(u(:,k), v(:,k), xv, yv)
557 : end do
558 897840 : ubmsrc = dot_2d(usrc , vsrc , xv, yv)
559 :
560 : ! Ensure on-ridge wind is positive at source level
561 84396960 : do k = 1, pver
562 1395138960 : ubm(:,k) = sign( ubmsrc*0._r8+1._r8 , ubmsrc ) * ubm(:,k)
563 : end do
564 :
565 : ! Sean says just use 1._r8 as
566 : ! first argument
567 14991840 : xv = sign( ubmsrc*0._r8+1._r8 , ubmsrc ) * xv
568 14991840 : yv = sign( ubmsrc*0._r8+1._r8 , ubmsrc ) * yv
569 :
570 : ! Now make ubmsrc positive and protect
571 : ! against zero
572 14991840 : ubmsrc = abs(ubmsrc)
573 14991840 : ubmsrc = max( 0.01_r8 , ubmsrc )
574 :
575 :
576 : ! The minimum stratification allowing GW behavior
577 : ! should really depend on horizontal scale since
578 : !
579 : ! m^2 ~ (N/U)^2 - k^2
580 : !
581 : ! Should also think about parameterizing
582 : ! trapped lee-waves.
583 :
584 :
585 : ! This needs to be made constistent with later
586 : ! treatment of nonhydrostatic effects.
587 14991840 : m2src = ( (nsrc/(ubmsrc+0.01_r8))**2 - kwvrdg**2 ) /((nsrc/(ubmsrc+0.01_r8))**2)
588 :
589 :
590 : !-------------------------------------------------------------
591 : ! Calculate provisional limits (in Z [m]) for 3 regimes. This
592 : ! will modified later if wave breaking or trapping are
593 : ! diagnosed
594 : !
595 : ! ^
596 : ! | *** linear propagation ***
597 : ! (H) -------- mountain top ------------- | *** or wave breaking ****
598 : ! | *** regimes *************
599 : ! (BWV)------ bottom of linear waves ---- |
600 : ! : |
601 : ! ******* |
602 : ! : |
603 : ! (TLB)--- top of flow diversion layer--- '
604 : ! :
605 : ! **** flow diversion *****
606 : ! :
607 : !============================================
608 :
609 : !============================================
610 : ! For Dividing streamline para (DS2017)
611 : !--------------------------------------------
612 : ! High-drag downslope wind regime exists
613 : ! between bottom of linear waves and top of
614 : ! flow diversion. Linear waves can only
615 : ! attain vertical displacment of f1*U/N. So,
616 : ! bottom of linear waves is given by
617 : !
618 : ! BWV = H - Fr1*U/N
619 : !
620 : ! Downslope wind layer begins at BWV and
621 : ! extends below it until some maximum high
622 : ! drag obstacle height Fr2*U/N is attained
623 : ! (where Fr2 >= f1). Below downslope wind
624 : ! there is flow diversion, so top of
625 : ! diversion layer (TLB) is equivalent to
626 : ! bottom of downslope wind layer and is;
627 : !
628 : ! TLB = H - Fr2*U/N
629 : !
630 : !-----------------------------------------
631 :
632 : ! Critical inverse Froude number
633 : !-----------------------------------------------
634 14991840 : Fr1(:) = Fr_c * 1.00_r8
635 14991840 : Frx(:) = hdsp(:)*nsrc(:)/abs( ubmsrc(:) ) / Fr_c
636 :
637 897840 : if ( do_divstream ) then
638 : !------------------------------------------------
639 : ! Calculate Fr2(Frx) for DS2017
640 : !------------------------------------------------
641 85461840 : where(Frx <= Frx0)
642 : Fr2(:) = Fr1(:) + Fr1(:)* C_GammaMax * anixy(:)
643 : elsewhere((Frx > Frx0).and.(Frx <= Frx1) )
644 : Fr2(:) = Fr1(:) + Fr1(:)* C_GammaMax * anixy(:) &
645 : * (Frx1 - Frx(:))/(Frx1-Frx0)
646 : elsewhere(Frx > Frx1)
647 : Fr2(:)=Fr1(:)
648 : endwhere
649 : else
650 : !------------------------------------------
651 : ! Regime distinctions entirely carried by
652 : ! amplification of taudsw (next subr)
653 : !------------------------------------------
654 0 : Fr2(:)=Fr1(:)
655 : end if
656 :
657 :
658 :
659 14991840 : where( m2src > orom2min )
660 : ddw = Fr2 * ( abs(ubmsrc) )/nsrc
661 : elsewhere
662 : ddw = 0._r8
663 : endwhere
664 :
665 :
666 : ! If TLB is less than zero then obstacle is not
667 : ! high enough to produce an low-level diversion layer
668 14991840 : tlb = mxdis - ddw
669 14991840 : where( tlb < 0._r8)
670 : tlb = 0._r8
671 : endwhere
672 43994160 : do k = pver, pver/2, -1
673 720506160 : do i = 1, ncol
674 719608320 : if ( (tlb(i) > zi(i,k+1)) .and. (tlb(i) <= zi(i,k)) ) then
675 363338 : tlb_level(i) = k
676 : end if
677 : end do
678 : end do
679 :
680 :
681 : ! Find *BOTTOM* of linear wave layer (BWV)
682 : !where ( nsrc > orostratmin )
683 14991840 : where( m2src > orom2min )
684 : dwv = Fr1 * ( abs(ubmsrc) )/nsrc
685 : elsewhere
686 : dwv = -9.999e9_r8 ! if weak strat - no waves
687 : endwhere
688 :
689 14991840 : bwv = mxdis - dwv
690 14991840 : where(( bwv < 0._r8) .or. (dwv < 0._r8) )
691 : bwv = 0._r8
692 : endwhere
693 84396960 : do k = pver,1, -1
694 1395138960 : do i = 1, ncol
695 1394241120 : if ( (bwv(i) > zi(i,k+1)) .and. (bwv(i) <= zi(i,k)) ) then
696 581501 : bwv_level(i) = k+1
697 : end if
698 : end do
699 : end do
700 :
701 :
702 :
703 : ! Compute the interface wind projection by averaging the midpoint winds.
704 : ! Use the top level wind at the top interface.
705 14991840 : ubi(:,1) = ubm(:,1)
706 897840 : ubi(:,2:pver) = midpoint_interp(ubm)
707 14991840 : ubi(:,pver+1) = ubm(:,pver)
708 :
709 : ! Allow wind tendencies all the way to the model bottom.
710 14991840 : tend_level = pver
711 :
712 : ! No spectrum; phase speed is just 0.
713 15889680 : c = 0._r8
714 :
715 43179840 : where( m2src < orom2min )
716 : tlb = mxdis
717 : tlb_level = src_level
718 : endwhere
719 :
720 :
721 897840 : end subroutine gw_rdg_src
722 :
723 :
724 : !==========================================================================
725 :
726 897840 : subroutine gw_rdg_belowpeak(ncol, band, rdg_cd_llb, &
727 897840 : t, mxdis, anixy, kwvrdg, zi, nm, ni, rhoi, &
728 897840 : src_level , tau, &
729 897840 : ubmsrc, nsrc, rsrc, m2src,tlb,bwv,Fr1,Fr2,Frx, &
730 897840 : tauoro,taudsw, hdspwv,hdspdw )
731 :
732 : use gw_common, only: GWBand
733 : !-----------------------------------------------------------------------
734 : ! Orographic source for multiple gravity wave drag parameterization.
735 : !
736 : ! The stress is returned for a single wave with c=0, over orography.
737 : ! For points where the orographic variance is small (including ocean),
738 : ! the returned stress is zero.
739 : !------------------------------Arguments--------------------------------
740 : ! Column dimension.
741 : integer, intent(in) :: ncol
742 : ! Band to emit orographic waves in.
743 : ! Regardless, we will only ever emit into l = 0.
744 : type(GWBand), intent(in) :: band
745 : ! Drag coefficient for low-level flow
746 : real(r8), intent(in) :: rdg_cd_llb
747 :
748 :
749 : ! Midpoint temperatures. (K)
750 : real(r8), intent(in) :: t(ncol,pver)
751 : ! Height estimate for ridge (m) [anisotropic orography].
752 : real(r8), intent(in) :: mxdis(ncol)
753 : ! Anisotropy parameter [0-1] [anisotropic orography].
754 : real(r8), intent(in) :: anixy(ncol)
755 : ! Inverse cross-ridge lengthscale (m-1) [anisotropic orography].
756 : real(r8), intent(inout) :: kwvrdg(ncol)
757 : ! Interface altitudes above ground (m).
758 : real(r8), intent(in) :: zi(ncol,pver+1)
759 : ! Midpoint Brunt-Vaisalla frequencies (s-1).
760 : real(r8), intent(in) :: nm(ncol,pver)
761 : ! Interface Brunt-Vaisalla frequencies (s-1).
762 : real(r8), intent(in) :: ni(ncol,pver+1)
763 : ! Interface density (kg m-3).
764 : real(r8), intent(in) :: rhoi(ncol,pver+1)
765 :
766 : ! Indices of top gravity wave source level
767 : integer, intent(inout) :: src_level(ncol)
768 :
769 : ! Wave Reynolds stress.
770 : real(r8), intent(inout) :: tau(ncol,-band%ngwv:band%ngwv,pver+1)
771 : ! Top of low-level flow layer.
772 : real(r8), intent(in) :: tlb(ncol)
773 : ! Bottom of linear wave region.
774 : real(r8), intent(in) :: bwv(ncol)
775 : ! surface stress from linear waves.
776 : real(r8), intent(out) :: tauoro(ncol)
777 : ! surface stress for downslope wind regime.
778 : real(r8), intent(out) :: taudsw(ncol)
779 :
780 : ! Surface streamline displacement height for linear waves.
781 : real(r8), intent(out) :: hdspwv(ncol)
782 : ! Surface streamline displacement height for downslope wind regime.
783 : real(r8), intent(out) :: hdspdw(ncol)
784 :
785 :
786 :
787 : ! Froude numbers for flow/drag regimes
788 : real(r8), intent(in) :: Fr1(ncol), Fr2(ncol),Frx(ncol)
789 :
790 : ! Averages over source region.
791 : real(r8), intent(in) :: m2src(ncol) ! normalized non-hydro wavenumber
792 : real(r8), intent(in) :: nsrc(ncol) ! B-V frequency.
793 : real(r8), intent(in) :: rsrc(ncol) ! Density.
794 : real(r8), intent(in) :: ubmsrc(ncol) ! On-ridge wind.
795 :
796 :
797 : !logical, intent(in), optional :: forcetlb
798 :
799 : !---------------------------Local Storage-------------------------------
800 : ! Column and level indices.
801 : integer :: i, k
802 :
803 1795680 : real(r8) :: Coeff_LB(ncol),tausat,ubsrcx(ncol),dswamp
804 1795680 : real(r8) :: taulin(ncol),BetaMax
805 :
806 : ! ubsrcx introduced to account for situations with high shear, strong strat.
807 14991840 : do i = 1, ncol
808 14991840 : ubsrcx(i) = max( ubmsrc(i) , 0._r8 )
809 : end do
810 :
811 14991840 : do i = 1, ncol
812 14991840 : if ( m2src(i) > orom2min ) then
813 1020198 : hdspwv(i) = min( mxdis(i) , Fr1(i) * ubsrcx(i) / nsrc(i) )
814 : else
815 13073802 : hdspwv(i) = 0._r8
816 : end if
817 : end do
818 :
819 897840 : if (do_divstream) then
820 14991840 : do i = 1, ncol
821 14991840 : if ( m2src(i) > orom2min ) then
822 1020198 : hdspdw(i) = min( mxdis(i) , Fr2(i) * ubsrcx(i) / nsrc(i) )
823 : else
824 13073802 : hdspdw(i) = 0._r8
825 : end if
826 : end do
827 : else
828 0 : do i = 1, ncol
829 : ! Needed only to mark where a DSW occurs
830 0 : if ( m2src(i) > orom2min ) then
831 0 : hdspdw(i) = mxdis(i)
832 : else
833 0 : hdspdw(i) = 0._r8
834 : end if
835 : end do
836 : end if
837 :
838 : ! Calculate form drag coefficient ("CD")
839 : !--------------------------------------
840 14991840 : Coeff_LB = rdg_cd_llb*anixy
841 :
842 : ! Determine the orographic c=0 source term following McFarlane (1987).
843 : ! Set the source top interface index to pver, if the orographic term is
844 : ! zero.
845 : !
846 : ! This formula is basically from
847 : !
848 : ! tau(src) = rho * u' * w'
849 : ! where
850 : ! u' ~ N*h' and w' ~ U*h'/b (b="breite")
851 : !
852 : ! and 1/b has been replaced with k (kwvrdg)
853 : !
854 14991840 : do i = 1, ncol
855 14991840 : if ( ( src_level(i) > 0 ) .and. ( m2src(i) > orom2min ) ) then
856 : tauoro(i) = kwvrdg(i) * ( hdspwv(i)**2 ) * rsrc(i) * nsrc(i) &
857 1020198 : * ubsrcx(i)
858 : taudsw(i) = kwvrdg(i) * ( hdspdw(i)**2 ) * rsrc(i) * nsrc(i) &
859 1020198 : * ubsrcx(i)
860 : else
861 13073802 : tauoro(i) = 0._r8
862 13073802 : taudsw(i) = 0._r8
863 : end if
864 : end do
865 :
866 897840 : if (do_divstream) then
867 14991840 : do i = 1, ncol
868 14991840 : taulin(i) = 0._r8
869 : end do
870 : !---------------------------------------
871 : ! Need linear drag when divstream is not used is used
872 : !---------------------------------------
873 : else
874 0 : do i = 1, ncol
875 0 : if ( ( src_level(i) > 0 ) .and. ( m2src(i) > orom2min ) ) then
876 : taulin(i) = kwvrdg(i) * ( mxdis(i)**2 ) * rsrc(i) * nsrc(i) &
877 0 : * ubsrcx(i)
878 : else
879 0 : taulin(i) = 0._r8
880 : end if
881 : end do
882 : end if
883 :
884 897840 : if ( do_divstream ) then
885 : ! Amplify DSW between Frx=1. and Frx=Frx1
886 14991840 : do i = 1,ncol
887 14094000 : dswamp=0._r8
888 14094000 : BetaMax = C_BetaMax_DS * anixy(i)
889 14094000 : if ( (Frx(i)>1._r8).and.(Frx(i)<=Frx1)) then
890 288383 : dswamp = (Frx(i)-1._r8)*(Frx1-Frx(i))/(0.25_r8*(Frx1-1._r8)**2)
891 : end if
892 14991840 : taudsw(i) = (1._r8 + BetaMax*dswamp)*taudsw(i)
893 : end do
894 : else
895 : !-------------------
896 : ! Scinocca&McFarlane
897 : !--------------------
898 0 : do i = 1, ncol
899 0 : BetaMax = C_BetaMax_SM * anixy(i)
900 0 : if ( (Frx(i) >=1._r8) .and. (Frx(i) < 1.5_r8) ) then
901 0 : dswamp = 2._r8 * BetaMax * (Frx(i) -1._r8)
902 0 : else if ( ( Frx(i) >= 1.5_r8 ) .and. (Frx(i) < 3._r8 ) ) then
903 : dswamp = ( 1._r8 + BetaMax - (0.666_r8**2) ) * ( 0.666_r8*(3._r8 - Frx(i) ))**2 &
904 0 : + ( 1._r8 / Frx(i) )**2 -1._r8
905 : else
906 : dswamp = 0._r8
907 : end if
908 0 : if ( (Frx(i) >=1._r8) .and. (Frx(i) < 3._r8) ) then
909 0 : taudsw(i) = (1._r8 + dswamp )*taulin(i) - tauoro(i)
910 : else
911 0 : taudsw(i) = 0._r8
912 : endif
913 : ! This code defines "taudsw" as SUM of freely-propagating
914 : ! DSW enhancement. Different than in SM2000
915 0 : taudsw(i) = taudsw(i) + tauoro(i)
916 : end do
917 : !----------------------------------------------------
918 : end if
919 :
920 :
921 14991840 : do i = 1, ncol
922 14991840 : if ( m2src(i) > orom2min ) then
923 385634844 : where ( ( zi(i,:) < mxdis(i) ) .and. ( zi(i,:) >= bwv(i) ) )
924 1020198 : tau(i,0,:) = tauoro(i)
925 : else where ( ( zi(i,:) < bwv(i) ) .and. ( zi(i,:) >= tlb(i) ) )
926 : tau(i,0,:) = tauoro(i) +( taudsw(i)-tauoro(i) )* &
927 : ( bwv(i) - zi(i,:) ) / &
928 : ( bwv(i) - tlb(i) )
929 : endwhere
930 : ! low-level form drag on obstacle. Quantity kwvrdg (~1/b) appears for consistency
931 : ! with tauoro and taudsw forms. Should be weighted by L*b/A_g before applied to flow.
932 96918810 : where ( ( zi(i,:) < tlb(i) ) .and. ( zi(i,:) >= 0._r8 ) )
933 : tau(i,0,:) = taudsw(i) + &
934 : Coeff_LB(i) * kwvrdg(i) * rsrc(i) * 0.5_r8 * (ubsrcx(i)**2) * ( tlb(i) - zi(i,:) )
935 : endwhere
936 :
937 1020198 : if (do_smooth_regimes) then
938 : ! This blocks accounts for case where both mxdis and tlb fall
939 : ! between adjacent edges
940 0 : do k=1,pver
941 0 : if ( (zi(i,k) >= tlb(i)).and.(zi(i,k+1) < tlb(i)).and. &
942 0 : (zi(i,k) >= mxdis(i)).and.(zi(i,k+1) < mxdis(i)) ) then
943 0 : src_level(i) = src_level(i)-1
944 0 : tau(i,0,k) = tauoro(i)
945 : end if
946 : end do
947 : end if
948 :
949 : else !----------------------------------------------
950 : ! This block allows low-level dynamics to occur
951 : ! even if m2 is less than orom2min
952 1242011190 : where ( ( zi(i,:) < tlb(i) ) .and. ( zi(i,:) >= 0._r8 ) )
953 13073802 : tau(i,0,:) = taudsw(i) + &
954 : Coeff_LB(i) * kwvrdg(i) * rsrc(i) * 0.5_r8 * &
955 : (ubsrcx(i)**2) * ( tlb(i) - zi(i,:) )
956 : endwhere
957 : endif
958 : end do
959 :
960 : ! This may be redundant with newest version of gw_drag_prof.
961 : ! That code reaches down to level k=src_level+1. (jtb 1/5/16)
962 14991840 : do i = 1, ncol
963 14094000 : k=src_level(i)
964 14094000 : if ( ni(i,k) > orostratmin ) then
965 : tausat = (Fr_c**2) * kwvrdg(i) * rhoi(i,k) * ubsrcx(i)**3 / &
966 14094000 : (1._r8*ni(i,k))
967 : else
968 : tausat = 0._r8
969 : endif
970 14991840 : tau(i,0,src_level(i)) = min( tauoro(i), tausat )
971 : end do
972 :
973 :
974 :
975 : ! Final clean-up. Do nothing if obstacle less than orohmin
976 14991840 : do i = 1, ncol
977 14991840 : if ( mxdis(i) < orohmin ) then
978 1244056065 : tau(i,0,:) = 0._r8
979 13095327 : tauoro(i) = 0._r8
980 13095327 : taudsw(i) = 0._r8
981 : endif
982 : end do
983 :
984 : ! Disable vertical propagation if Scorer param is
985 : ! too small.
986 14991840 : do i = 1, ncol
987 14991840 : if ( m2src(i) <= orom2min ) then
988 13073802 : src_level(i)=1
989 : endif
990 : end do
991 :
992 :
993 :
994 897840 : end subroutine gw_rdg_belowpeak
995 :
996 : !==========================================================================
997 897840 : subroutine gw_rdg_break_trap(ncol, band, &
998 897840 : zi, nm, ni, ubm, ubi, rhoi, kwvrdg, bwv, tlb, wbr, &
999 897840 : src_level, tlb_level, &
1000 897840 : hdspwv, hdspdw, mxdis, &
1001 897840 : tauoro, taudsw, tau, &
1002 : ldo_trapped_waves, wdth_kwv_scale_in )
1003 : use gw_common, only: GWBand
1004 : !-----------------------------------------------------------------------
1005 : ! Parameterization of high-drag regimes and trapped lee-waves for CAM
1006 : !
1007 : !------------------------------Arguments--------------------------------
1008 : ! Column dimension.
1009 : integer, intent(in) :: ncol
1010 : ! Band to emit orographic waves in.
1011 : ! Regardless, we will only ever emit into l = 0.
1012 : type(GWBand), intent(in) :: band
1013 :
1014 :
1015 : ! Height estimate for ridge (m) [anisotropic orography].
1016 : !real(r8), intent(in) :: mxdis(ncol)
1017 : ! Horz wavenumber for ridge (1/m) [anisotropic orography].
1018 : real(r8), intent(in) :: kwvrdg(ncol)
1019 : ! Interface altitudes above ground (m).
1020 : real(r8), intent(in) :: zi(ncol,pver+1)
1021 : ! Midpoint Brunt-Vaisalla frequencies (s-1).
1022 : real(r8), intent(in) :: nm(ncol,pver)
1023 : ! Interface Brunt-Vaisalla frequencies (s-1).
1024 : real(r8), intent(in) :: ni(ncol,pver+1)
1025 :
1026 : ! Indices of gravity wave sources.
1027 : integer, intent(inout) :: src_level(ncol), tlb_level(ncol)
1028 :
1029 : ! Wave Reynolds stress.
1030 : real(r8), intent(inout) :: tau(ncol,-band%ngwv:band%ngwv,pver+1)
1031 : ! Wave Reynolds stresses at source.
1032 : real(r8), intent(in) :: taudsw(ncol)
1033 : real(r8), intent(inout) :: tauoro(ncol)
1034 : ! Projection of wind at midpoints and interfaces.
1035 : real(r8), intent(in) :: ubm(ncol,pver)
1036 : real(r8), intent(in) :: ubi(ncol,pver+1)
1037 : ! Interface density (kg m-3).
1038 : real(r8), intent(in) :: rhoi(ncol,pver+1)
1039 :
1040 : ! Top of low-level flow layer.
1041 : real(r8), intent(in) :: tlb(ncol)
1042 : ! Bottom of linear wave region.
1043 : real(r8), intent(in) :: bwv(ncol)
1044 :
1045 : ! Surface streamline displacement height for linear waves.
1046 : real(r8), intent(in) :: hdspwv(ncol)
1047 : ! Surface streamline displacement height for downslope wind regime.
1048 : real(r8), intent(in) :: hdspdw(ncol)
1049 : ! Ridge height.
1050 : real(r8), intent(in) :: mxdis(ncol)
1051 :
1052 :
1053 : ! Wave breaking level
1054 : real(r8), intent(out) :: wbr(ncol)
1055 :
1056 : logical, intent(in), optional :: ldo_trapped_waves
1057 : real(r8), intent(in), optional :: wdth_kwv_scale_in
1058 :
1059 : !---------------------------Local Storage-------------------------------
1060 : ! Column and level indices.
1061 : integer :: i, k, kp1, non_hydro
1062 1795680 : real(r8):: m2(ncol,pver),delz(ncol),tausat(ncol),trn(ncol)
1063 1795680 : real(r8):: wbrx(ncol)
1064 1795680 : real(r8):: phswkb(ncol,pver+1)
1065 : logical :: lldo_trapped_waves
1066 : real(r8):: wdth_kwv_scale
1067 : ! Indices of important levels.
1068 1795680 : integer :: trn_level(ncol)
1069 :
1070 897840 : if (present(ldo_trapped_waves)) then
1071 897840 : lldo_trapped_waves = ldo_trapped_waves
1072 897840 : if(lldo_trapped_waves) then
1073 : non_hydro = 1
1074 : else
1075 897840 : non_hydro = 0
1076 : endif
1077 : else
1078 : lldo_trapped_waves = .false.
1079 : non_hydro = 0
1080 : endif
1081 :
1082 897840 : if (present(wdth_kwv_scale_in)) then
1083 0 : wdth_kwv_scale = wdth_kwv_scale_in
1084 : else
1085 : wdth_kwv_scale = 1._r8
1086 : endif
1087 :
1088 : ! Calculate vertical wavenumber**2
1089 : !---------------------------------
1090 1395138960 : m2 = (nm / (abs(ubm)+.01_r8))**2
1091 84396960 : do k=pver,1,-1
1092 1394241120 : m2(:,k) = m2(:,k) - non_hydro*(wdth_kwv_scale*kwvrdg)**2
1093 : ! sweeping up, zero out m2 above first occurence
1094 : ! of m2(:,k)<=0
1095 83499120 : kp1=min( k+1, pver )
1096 1395138960 : where( (m2(:,k) <= 0.0_r8 ).or.(m2(:,kp1) <= 0.0_r8 ) )
1097 : m2(:,k) = 0._r8
1098 : endwhere
1099 : end do
1100 :
1101 : ! Take square root of m**2 and
1102 : ! do vertical integral to find
1103 : ! WKB phase.
1104 : !-----------------------------
1105 1395138960 : m2 = SQRT( m2 )
1106 1410130800 : phswkb(:,:)=0
1107 84396960 : do k=pver,1,-1
1108 4183621200 : where( zi(:,k) > tlb(:) )
1109 83499120 : delz(:) = min( zi(:,k)-zi(:,k+1) , zi(:,k)-tlb(:) )
1110 83499120 : phswkb(:,k) = phswkb(:,k+1) + m2(:,k)*delz(:)
1111 : endwhere
1112 : end do
1113 :
1114 : ! Identify top edge of layer in which phswkb reaches 3*pi/2
1115 : ! - approximately the "breaking level"
1116 : !----------------------------------------------------------
1117 14991840 : wbr(:)=0._r8
1118 14991840 : wbrx(:)=0._r8
1119 897840 : if (do_smooth_regimes) then
1120 0 : do k=pver,1,-1
1121 0 : where( (phswkb(:,k+1)<1.5_r8*pii).and.(phswkb(:,k)>=1.5_r8*pii) &
1122 0 : .and.(hdspdw(:)>hdspwv(:)) )
1123 : wbr(:) = zi(:,k)
1124 : ! Extrapolation to make regime
1125 : ! transitions smoother
1126 : wbrx(:) = zi(:,k) - ( phswkb(:,k) - 1.5_r8*pii ) &
1127 0 : / ( m2(:,k) + 1.e-6_r8 )
1128 : src_level(:) = k-1
1129 : endwhere
1130 : end do
1131 : else
1132 84396960 : do k=pver,1,-1
1133 166998240 : where( (phswkb(:,k+1)<1.5_r8*pii).and.(phswkb(:,k)>=1.5_r8*pii) &
1134 4183621200 : .and.(hdspdw(:)>hdspwv(:)) )
1135 : wbr(:) = zi(:,k)
1136 : src_level(:) = k
1137 : endwhere
1138 : end do
1139 : end if
1140 :
1141 : ! Adjust tauoro at new source levels if needed.
1142 : ! This is problematic if Fr_c<1.0. Not sure why.
1143 : !----------------------------------------------------------
1144 897840 : if (do_adjust_tauoro) then
1145 14991840 : do i = 1,ncol
1146 14991840 : if (wbr(i) > 0._r8 ) then
1147 288383 : tausat(i) = (Fr_c**2) * kwvrdg(i) * rhoi( i, src_level(i) ) &
1148 : * abs(ubi(i , src_level(i) ))**3 &
1149 288383 : / ni( i , src_level(i) )
1150 288383 : tauoro(i) = min( tauoro(i), tausat(i) )
1151 : end if
1152 : end do
1153 : end if
1154 :
1155 897840 : if (do_smooth_regimes) then
1156 0 : do i = 1, ncol
1157 0 : do k=1,pver+1
1158 0 : if ( ( zi(i,k) <= wbr(i) ) .and. ( zi(i,k) > tlb(i) ) ) then
1159 0 : tau(i,0,k) = tauoro(i) + (taudsw(i)-tauoro(i)) * &
1160 : ( wbrx(i) - zi(i,k) ) / &
1161 0 : ( wbrx(i) - tlb(i) )
1162 0 : tau(i,0,k) = max( tau(i,0,k), tauoro(i) )
1163 : endif
1164 : end do
1165 : end do
1166 : else
1167 : ! Following is for backwards B4B compatibility with earlier versions
1168 : ! ("N1" and "N5" -- Note: "N5" used do_backward_compat=.true.)
1169 897840 : if (.not.do_backward_compat) then
1170 14991840 : do i = 1, ncol
1171 1339827840 : do k=1,pver+1
1172 1338930000 : if ( ( zi(i,k) < wbr(i) ) .and. ( zi(i,k) >= tlb(i) ) ) then
1173 2907092 : tau(i,0,k) = tauoro(i) + (taudsw(i)-tauoro(i)) * &
1174 : ( wbr(i) - zi(i,k) ) / &
1175 2907092 : ( wbr(i) - tlb(i) )
1176 : endif
1177 : end do
1178 : end do
1179 : else
1180 0 : do i = 1, ncol
1181 0 : do k=1,pver+1
1182 0 : if ( ( zi(i,k) <= wbr(i) ) .and. ( zi(i,k) > tlb(i) ) ) then
1183 0 : tau(i,0,k) = tauoro(i) + (taudsw(i)-tauoro(i)) * &
1184 : ( wbr(i) - zi(i,k) ) / &
1185 0 : ( wbr(i) - tlb(i) )
1186 : endif
1187 : end do
1188 : end do
1189 : end if
1190 : end if
1191 :
1192 897840 : if (lldo_trapped_waves) then
1193 :
1194 : ! Identify top edge of layer in which Scorer param drops below 0
1195 : ! - approximately the "turning level"
1196 : !----------------------------------------------------------
1197 0 : trn(:)=1.e8_r8
1198 0 : trn_level(:) = 0 ! pver+1
1199 0 : where( m2(:,pver)<= 0._r8 )
1200 0 : trn(:) = zi(:,pver)
1201 : trn_level(:) = pver
1202 : endwhere
1203 0 : do k=pver-1,1,-1
1204 0 : where( (m2(:,k+1)> 0._r8).and.(m2(:,k)<= 0._r8) )
1205 0 : trn(:) = zi(:,k)
1206 : trn_level(:) = k
1207 : endwhere
1208 : end do
1209 :
1210 0 : do i = 1,ncol
1211 : ! Case: Turning below mountain top
1212 0 : if ( (trn(i) < mxdis(i)).and.(trn_level(i)>=1) ) then
1213 0 : tau(i,0,:) = tau(i,0,:) - max( tauoro(i),taudsw(i) )
1214 0 : tau(i,0,:) = max( tau(i,0,:) , 0._r8 )
1215 0 : tau(i,0,1:tlb_level(i))=0._r8
1216 0 : src_level(i) = 1 ! disable any more tau calculation
1217 : end if
1218 : ! Case: Turning but no breaking
1219 0 : if ( (wbr(i) == 0._r8 ).and.(trn(i)>mxdis(i)).and.(trn_level(i)>=1) ) then
1220 0 : where ( ( zi(i,:) <= trn(i) ) .and. ( zi(i,:) >= bwv(i) ) )
1221 0 : tau(i,0,:) = tauoro(i) * &
1222 : ( trn(i) - zi(i,:) ) / &
1223 : ( trn(i) - bwv(i) )
1224 : end where
1225 0 : src_level(i) = 1 ! disable any more tau calculation
1226 : end if
1227 : ! Case: Turning AND breaking. Turning ABOVE breaking
1228 0 : if ( (wbr(i) > 0._r8 ).and.(trn(i) >= wbr(i)).and.(trn_level(i)>=1) ) then
1229 0 : where ( ( zi(i,:) <= trn(i) ) .and. ( zi(i,:) >= wbr(i) ) )
1230 0 : tau(i,0,:) = tauoro(i) * &
1231 : ( trn(i) - zi(i,:) ) / &
1232 : ( trn(i) - wbr(i) )
1233 : endwhere
1234 0 : src_level(i) = 1 ! disable any more tau calculation
1235 : end if
1236 : ! Case: Turning AND breaking. Turning BELOW breaking
1237 0 : if ( (wbr(i) > 0._r8 ).and.(trn(i) < wbr(i)).and.(trn_level(i)>=1) ) then
1238 0 : tauoro(i) = 0._r8
1239 0 : where ( ( zi(i,:) < wbr(i) ) .and. ( zi(i,:) >= tlb(i) ) )
1240 0 : tau(i,0,:) = tauoro(i) + (taudsw(i)-tauoro(i)) * &
1241 : ( wbr(i) - zi(i,:) ) / &
1242 : ( wbr(i) - tlb(i) )
1243 : endwhere
1244 0 : src_level(i) = 1 ! disable any more tau calculation
1245 : end if
1246 : end do
1247 : end if
1248 :
1249 897840 : end subroutine gw_rdg_break_trap
1250 : !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1251 :
1252 :
1253 :
1254 : end module gw_rdg
|