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