LCOV - code coverage report
Current view: top level - physics/clubb/src/CLUBB_core - sponge_layer_damping.F90 (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 51 0.0 %
Date: 2025-03-13 18:42:46 Functions: 0 8 0.0 %

          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

Generated by: LCOV version 1.14