Line data Source code
1 : !---------------------------------------------------------------------------
2 : ! $Id$
3 : !===============================================================================
4 : module sponge_layer_damping
5 :
6 : ! Description:
7 : ! This module is used for damping variables in upper altitudes of the grid.
8 : !
9 : ! References:
10 : ! None
11 : !-------------------------------------------------------------------------
12 :
13 : use clubb_precision, only: &
14 : core_rknd ! Variable(s)
15 :
16 : implicit none
17 :
18 : public :: sponge_damp_xm, & ! Procedure(s)
19 : sponge_damp_xp2, &
20 : sponge_damp_xp3, &
21 : initialize_tau_sponge_damp, &
22 : finalize_tau_sponge_damp, &
23 : sponge_damp_settings, & ! Variable type(s)
24 : sponge_damp_profile
25 :
26 :
27 : type sponge_damp_settings
28 :
29 : real( kind = core_rknd ) :: &
30 : tau_sponge_damp_min, & ! Minimum damping time scale (model top) [s]
31 : tau_sponge_damp_max, & ! Maximum damping time scale (damp layer base) [s]
32 : sponge_damp_depth ! Damping depth as a fraction of domain height [-]
33 :
34 : logical :: &
35 : l_sponge_damping ! True if damping is being used
36 :
37 : end type sponge_damp_settings
38 :
39 : type sponge_damp_profile
40 :
41 : real( kind = core_rknd ), allocatable, dimension(:) :: &
42 : tau_sponge_damp ! Damping time scale [1/s]
43 :
44 : real( kind = core_rknd ) :: &
45 : sponge_layer_depth ! Depth of sponge damping layer [m]
46 :
47 : end type sponge_damp_profile
48 :
49 :
50 : type(sponge_damp_settings), public :: &
51 : thlm_sponge_damp_settings, & ! Variable(s)
52 : rtm_sponge_damp_settings, &
53 : uv_sponge_damp_settings, &
54 : wp2_sponge_damp_settings, &
55 : wp3_sponge_damp_settings, &
56 : up2_vp2_sponge_damp_settings
57 : !$omp threadprivate( thlm_sponge_damp_settings, rtm_sponge_damp_settings, &
58 : !$omp uv_sponge_damp_settings, wp2_sponge_damp_settings, &
59 : !$omp wp3_sponge_damp_settings, up2_vp2_sponge_damp_settings )
60 :
61 : type(sponge_damp_profile), public :: &
62 : thlm_sponge_damp_profile, & ! Variable(s)
63 : rtm_sponge_damp_profile, &
64 : uv_sponge_damp_profile, &
65 : wp2_sponge_damp_profile, &
66 : wp3_sponge_damp_profile, &
67 : up2_vp2_sponge_damp_profile
68 : !$omp threadprivate( thlm_sponge_damp_profile, rtm_sponge_damp_profile, &
69 : !$omp uv_sponge_damp_profile, wp2_sponge_damp_profile, &
70 : !$omp wp3_sponge_damp_profile, up2_vp2_sponge_damp_profile )
71 :
72 :
73 : private
74 :
75 : contains
76 :
77 : !=============================================================================
78 0 : function sponge_damp_xm( nz, dt, z, zm, &
79 0 : xm_ref, xm, damping_profile ) result( xm_p )
80 :
81 : ! Description:
82 : ! Damps specified mean field toward a reference profile. The module must be
83 : ! initialized for this function to work. Otherwise a stop is issued.
84 :
85 : ! References:
86 : ! None
87 : !-----------------------------------------------------------------------
88 :
89 : ! "Sponge"-layer damping at the domain top region
90 :
91 : use clubb_precision, only: &
92 : core_rknd ! Variable(s)
93 :
94 : implicit none
95 :
96 : integer, intent(in) :: &
97 : nz
98 :
99 : ! External
100 : intrinsic :: allocated
101 :
102 : ! Input Variable(s)
103 : real( kind = core_rknd ), intent(in) :: &
104 : dt ! Model Timestep [s]
105 :
106 : real( kind = core_rknd ), dimension(nz), intent(in) :: &
107 : z, & ! Height of model grid levels [m]
108 : xm_ref, & ! Reference profile of x to damp xm towards [units vary]
109 : xm, & ! Mean field being damped [units vary]
110 : zm ! Momentum grid
111 :
112 : type(sponge_damp_profile), intent(in) :: &
113 : damping_profile
114 :
115 : ! Output Variable
116 : real( kind = core_rknd ), dimension(nz) :: &
117 : xm_p ! Damped value of xm [units_vary]
118 :
119 : ! Local Variable(s)
120 : real( kind = core_rknd ) :: &
121 : dt_on_tau ! Ratio of timestep to damping timescale [-]
122 :
123 : integer :: k
124 :
125 : ! ---- Begin Code ----
126 :
127 0 : if ( allocated( damping_profile%tau_sponge_damp ) ) then
128 :
129 0 : xm_p = xm
130 :
131 0 : do k = nz, 1, -1
132 :
133 : ! The height of the model top is zm(nz).
134 0 : if ( zm(nz) - z(k) < damping_profile%sponge_layer_depth ) then
135 :
136 : ! Vince Larson used implicit discretization in order to
137 : ! reduce noise in rtm in cloud_feedback_s12 (CGILS)
138 : !xm_p(k) = xm(k) - real( ( ( xm(k) - xm_ref(k) ) / &
139 : ! damping_profile%tau_sponge_damp(k) ) * dt )
140 0 : dt_on_tau = dt / damping_profile%tau_sponge_damp(k)
141 :
142 : ! Really, we should be using xm_ref at time n+1 rather than n.
143 : ! However, for steady profiles of xm_ref, it won't matter.
144 : xm_p(k) = ( xm(k) + dt_on_tau * xm_ref(k) ) / &
145 0 : ( 1.0_core_rknd + dt_on_tau )
146 : ! End Vince Larson's change
147 :
148 : else ! zm(nz) - z(k) >= damping_profile%sponge_layer_depth
149 :
150 : ! Below sponge damping layer; exit loop.
151 : exit
152 :
153 : endif ! zm(nz) - z(k) < damping_profile%sponge_layer_depth
154 :
155 :
156 : enddo ! k = nz, 1, -1
157 :
158 : else
159 :
160 0 : error stop "tau_sponge_damp in sponge_damp_xm used before initialization"
161 :
162 : endif
163 :
164 :
165 0 : return
166 :
167 0 : end function sponge_damp_xm
168 :
169 : !=============================================================================
170 0 : function sponge_damp_xp2( nz, dt, zm, xp2, x_tol_sqd, &
171 : damping_profile ) &
172 0 : result( xp2_damped )
173 :
174 : ! Description:
175 : ! Calculates the effects of "sponge"-layer damping on the variance of x,
176 : ! xp2.
177 : !
178 : ! Sponge damping on a local value of x is given by the equation:
179 : !
180 : ! x_d = x - ( delta_t / tau ) * ( x - <x> ),
181 : !
182 : ! where x is the local value prior to damping, x_d is the damped local value
183 : ! of x, <x> is the grid-level mean value of x, delta_t is the model time
184 : ! step duration, and tau is the damping time scale. Since delta_t / tau has
185 : ! the same value everywhere at a grid level, the grid-level mean of x does
186 : ! not change as a result of damping.
187 : !
188 : ! Subtracting <x> from both sides:
189 : !
190 : ! x_d - <x> = ( x - <x> ) - ( delta_t / tau ) * ( x - <x> ),
191 : !
192 : ! which results in:
193 : !
194 : ! x_d - <x> = ( 1 - delta_t / tau ) * ( x - <x> ).
195 : !
196 : ! Squaring both sides:
197 : !
198 : ! ( x_d - <x> )^2 = ( 1 - delta_t / tau )^2 * ( x - <x> )^2.
199 : !
200 : ! After averaging both sides, the damped value of xp2 is:
201 : !
202 : ! < x_d'^2 > = ( 1 - delta_t / tau )^2 * < x'^2 >.
203 : !
204 : ! Any sponge damping is applied to (predictive) xp2 after the field has been
205 : ! advanced in time. This allows sponge damping to be applied in an implicit
206 : ! manner. The damped value of xp2 must also be limited at a minimum value
207 : ! of x_tol^2.
208 :
209 : ! References:
210 : !-----------------------------------------------------------------------
211 :
212 : use constants_clubb, only: &
213 : one ! Constant(s)
214 :
215 : use clubb_precision, only: &
216 : core_rknd ! Variable(s)
217 :
218 : implicit none
219 :
220 : integer, intent(in) :: &
221 : nz
222 :
223 : ! Input Variable(s)
224 : real( kind = core_rknd ), intent(in) :: &
225 : dt ! Model Timestep [s]
226 :
227 : real( kind = core_rknd ), dimension(nz), intent(in) :: &
228 : zm, & ! Height of model grid levels [m]
229 : xp2 ! Variance of x, <x'^2>, prior to damping [units vary]
230 :
231 : real( kind = core_rknd ), intent(in) :: &
232 : x_tol_sqd ! Square of the tolerance value of x [units vary]
233 :
234 : type(sponge_damp_profile), intent(in) :: &
235 : damping_profile
236 :
237 : ! Output Variable
238 : real( kind = core_rknd ), dimension(nz) :: &
239 : xp2_damped ! Variance of x, <x'^2>, after damping [units vary]
240 :
241 : ! Local Variable(s)
242 : real( kind = core_rknd ) :: &
243 : dt_on_tau ! Ratio of model time step duration to damping timescale [-]
244 :
245 : integer :: &
246 : k ! Loop index
247 :
248 :
249 0 : if ( allocated( damping_profile%tau_sponge_damp ) ) then
250 :
251 : ! Set the entire profile of <x'^2> after damping to the profile of <x'^2>
252 : ! before damping. The values of <x'^2> after damping will be overwritten
253 : ! at any levels where "sponge"-layer damping occurs.
254 0 : xp2_damped = xp2
255 :
256 0 : do k = nz, 1, -1
257 :
258 : ! The height of the model top is zm(nz).
259 0 : if ( zm(nz) - zm(k) < damping_profile%sponge_layer_depth ) then
260 :
261 : ! Calculate the value of delta_t / tau at the grid level.
262 0 : dt_on_tau = dt / damping_profile%tau_sponge_damp(k)
263 :
264 : ! Calculate the damped value of <x'^2>.
265 0 : xp2_damped(k) = ( one - dt_on_tau )**2 * xp2(k)
266 :
267 : ! The damped value of <x'^2> needs to be greater than or equal to
268 : ! x_tol^2.
269 0 : xp2_damped(k) = max( xp2_damped(k), x_tol_sqd )
270 :
271 : else ! zm(nz) - zm(k) >= damping_profile%sponge_layer_depth
272 :
273 : ! Below sponge damping layer; exit loop.
274 : exit
275 :
276 : endif ! zm(nz) - zm(k) < damping_profile%sponge_layer_depth
277 :
278 :
279 : enddo ! k = nz, 1, -1
280 :
281 : else
282 :
283 0 : error stop "tau_sponge_damp in sponge_damp_xp2 used before initialization"
284 :
285 : endif
286 :
287 :
288 0 : return
289 :
290 0 : end function sponge_damp_xp2
291 :
292 : !=============================================================================
293 0 : function sponge_damp_xp3( nz, dt, z, zm, xp3, &
294 : damping_profile ) &
295 0 : result( xp3_damped )
296 :
297 : ! Description:
298 : ! Calculates the effects of "sponge"-layer damping on xp3.
299 : !
300 : ! Sponge damping on a local value of x is given by the equation:
301 : !
302 : ! x_d = x - ( delta_t / tau ) * ( x - <x> ),
303 : !
304 : ! where x is the local value prior to damping, x_d is the damped local value
305 : ! of x, <x> is the grid-level mean value of x, delta_t is the model time
306 : ! step duration, and tau is the damping time scale. Since delta_t / tau has
307 : ! the same value everywhere at a grid level, the grid-level mean of x does
308 : ! not change as a result of damping.
309 : !
310 : ! Subtracting <x> from both sides:
311 : !
312 : ! x_d - <x> = ( x - <x> ) - ( delta_t / tau ) * ( x - <x> ),
313 : !
314 : ! which results in:
315 : !
316 : ! x_d - <x> = ( 1 - delta_t / tau ) * ( x - <x> ).
317 : !
318 : ! Taking both sides to the third power:
319 : !
320 : ! ( x_d - <x> )^3 = ( 1 - delta_t / tau )^3 * ( x - <x> )^3.
321 : !
322 : ! After averaging both sides, the damped value of xp3 is:
323 : !
324 : ! < x_d'^3 > = ( 1 - delta_t / tau )^3 * < x'^3 >.
325 : !
326 : ! Any sponge damping is applied to (predictive) xp3 after the field has been
327 : ! advanced in time. This allows sponge damping to be applied in an implicit
328 : ! manner.
329 :
330 : ! References:
331 : !-----------------------------------------------------------------------
332 :
333 : use constants_clubb, only: &
334 : one ! Constant(s)
335 :
336 : use clubb_precision, only: &
337 : core_rknd ! Variable(s)
338 :
339 : implicit none
340 :
341 : integer, intent(in) :: &
342 : nz
343 :
344 : ! Input Variable(s)
345 : real( kind = core_rknd ), intent(in) :: &
346 : dt ! Model Timestep [s]
347 :
348 : real( kind = core_rknd ), dimension(nz), intent(in) :: &
349 : z, & ! Height of model grid levels [m]
350 : xp3, & ! <x'^3> prior to damping [units vary]
351 : zm ! Momentum grid
352 :
353 : type(sponge_damp_profile), intent(in) :: &
354 : damping_profile
355 :
356 : ! Output Variable
357 : real( kind = core_rknd ), dimension(nz) :: &
358 : xp3_damped ! <x'^3> after damping [units vary]
359 :
360 : ! Local Variable(s)
361 : real( kind = core_rknd ) :: &
362 : dt_on_tau ! Ratio of model time step duration to damping timescale [-]
363 :
364 : integer :: &
365 : k ! Loop index
366 :
367 :
368 0 : if ( allocated( damping_profile%tau_sponge_damp ) ) then
369 :
370 : ! Set the entire profile of <x'^3> after damping to the profile of <x'^3>
371 : ! before damping. The values of <x'^3> after damping will be overwritten
372 : ! at any levels where "sponge"-layer damping occurs.
373 0 : xp3_damped = xp3
374 :
375 0 : do k = nz, 1, -1
376 :
377 : ! The height of the model top is zm(nz).
378 0 : if ( zm(nz) - z(k) < damping_profile%sponge_layer_depth ) then
379 :
380 : ! Calculate the value of delta_t / tau at the grid level.
381 0 : dt_on_tau = dt / damping_profile%tau_sponge_damp(k)
382 :
383 : ! Calculate the damped value of <x'^3>.
384 0 : xp3_damped(k) = ( one - dt_on_tau )**3 * xp3(k)
385 :
386 : else ! zm(nz) - z(k) >= damping_profile%sponge_layer_depth
387 :
388 : ! Below sponge damping layer; exit loop.
389 : exit
390 :
391 : endif ! zm(nz) - z(k) < damping_profile%sponge_layer_depth
392 :
393 :
394 : enddo ! k = nz, 1, -1
395 :
396 : else
397 :
398 0 : error stop "tau_sponge_damp in sponge_damp_xp3 used before initialization"
399 :
400 : endif
401 :
402 :
403 0 : return
404 :
405 0 : end function sponge_damp_xp3
406 :
407 : !=============================================================================
408 0 : subroutine initialize_tau_sponge_damp( gr, dt, z, settings, &
409 : damping_profile )
410 :
411 : ! Description:
412 : ! Initialize time scale, tau_sponge_damp, used for damping. The time scale
413 : ! attains its maximum value, tau_sponge_damp_max, at the bottom of the
414 : ! "sponge" damping layer, which results in minimal damping. Likewise, the
415 : ! time scale attains its minimum value, tau_sponge_damp_min, at the top of
416 : ! the model, which results in maximum damping. At levels in-between the top
417 : ! of the model and the base of the sponge damping layer, the value of
418 : ! tau_sponge_damp is in-between tau_sponge_damp_min and tau_sponge_damp_max,
419 : ! as calculated by an interpolation formula.
420 :
421 : ! References:
422 : ! None
423 : !-----------------------------------------------------------------------
424 :
425 : use clubb_precision, only: &
426 : core_rknd ! Variable(s)
427 :
428 : use constants_clubb, only: &
429 : two, & ! Constant(s)
430 : fstderr
431 :
432 : use grid_class, only: &
433 : grid ! Type
434 :
435 : ! use interpolation, only: &
436 : ! lin_interpolate_two_points ! Procedure(s)
437 :
438 : implicit none
439 :
440 : type (grid), target, intent(in) :: gr
441 :
442 : ! Input Variable(s)
443 : real( kind = core_rknd ), intent(in) :: &
444 : dt ! Model Timestep [s]
445 :
446 : real( kind = core_rknd ), dimension(gr%nz), intent(in) :: &
447 : z ! Height of model grid levels [m]
448 :
449 : type(sponge_damp_settings), intent(in) :: &
450 : settings
451 :
452 : ! Output Variable(s)
453 : type(sponge_damp_profile), intent(out) :: &
454 : damping_profile
455 :
456 : ! Local Variable(s)
457 : real( kind = core_rknd ) :: &
458 : tau_sponge_damp_exponent ! Exponent in calculation of tau_sponge_damp [-]
459 :
460 : integer :: &
461 : k ! Loop index
462 :
463 : ! ---- Begin Code ----
464 :
465 : ! Allocate the damping time scale.
466 0 : allocate( damping_profile%tau_sponge_damp(1:gr%nz) )
467 :
468 : ! Calculate the depth of the sponge layer.
469 : ! The height of the model top is gr%zm(1,gr%nz).
470 : damping_profile%sponge_layer_depth &
471 0 : = settings%sponge_damp_depth * gr%zm(1,gr%nz)
472 :
473 : ! Check the value of tau_sponge_damp_min.
474 0 : if ( settings%tau_sponge_damp_min < two * dt ) then
475 0 : write(fstderr,*) "Error: tau_sponge_damp_min is too small!"
476 0 : write(fstderr,*) "It must be at least 2.0 * dt"
477 0 : error stop
478 : endif
479 :
480 : ! Calculate the value of the damping time scale, tau_sponge_damp, at levels
481 : ! that are within the sponge damping layer.
482 0 : do k = gr%nz, 1, -1
483 :
484 : ! The height of the model top is gr%zm(1,gr%nz).
485 0 : if ( gr%zm(1,gr%nz) - z(k) < damping_profile%sponge_layer_depth ) then
486 :
487 : ! Vince Larson added code to use standard linear interpolation.
488 : ! Brian Griffin reverted the linear interpolation in order to use code
489 : ! that is similar to what is found in SAM LES.
490 :
491 : tau_sponge_damp_exponent &
492 0 : = ( gr%zm(1,gr%nz) - z(k) ) / damping_profile%sponge_layer_depth
493 :
494 0 : damping_profile%tau_sponge_damp(k) &
495 : = settings%tau_sponge_damp_min &
496 : * ( settings%tau_sponge_damp_max &
497 0 : / settings%tau_sponge_damp_min )**tau_sponge_damp_exponent
498 :
499 : !damping_profile%tau_sponge_damp(k) &
500 : != lin_interpolate_two_points( z(k), gr%zm(1,gr%nz), &
501 : ! gr%zm(1,gr%nz) &
502 : ! - damping_profile%sponge_layer_depth, &
503 : ! settings%tau_sponge_damp_min, &
504 : ! settings%tau_sponge_damp_max )
505 :
506 : ! End Vince Larson's change
507 : ! End Brian Griffin's rebellious reversion.
508 :
509 : else ! gr%zm(1,gr%nz) - z(k) >= damping_profile%sponge_layer_depth
510 :
511 : ! Below sponge damping layer; exit loop.
512 : exit
513 :
514 : endif ! gr%zm(1,gr%nz) - z(k) < damping_profile%sponge_layer_depth
515 :
516 : enddo ! k = gr%nz, 1, -1
517 :
518 :
519 0 : return
520 :
521 : end subroutine initialize_tau_sponge_damp
522 :
523 : !=============================================================================
524 0 : subroutine finalize_tau_sponge_damp( damping_profile )
525 :
526 : ! Description:
527 : ! Frees memory allocated in initialize_tau_sponge_damp
528 : !
529 : ! References:
530 : ! None
531 : !-----------------------------------------------------------------------
532 :
533 : implicit none
534 :
535 : ! Input/Output Variable(s)
536 : type(sponge_damp_profile), intent(inout) :: &
537 : damping_profile ! Information for damping the profile
538 :
539 : ! ---- Begin Code ----
540 :
541 : ! Deallocate the damping time scale.
542 0 : deallocate( damping_profile%tau_sponge_damp )
543 :
544 :
545 0 : return
546 :
547 : end subroutine finalize_tau_sponge_damp
548 :
549 : !===============================================================================
550 :
551 0 : end module sponge_layer_damping
|