ActiveLayerMod.F90 Source File


Source Code

module ActiveLayerMod
  
  !-----------------------------------------------------------------------
  ! !DESCRIPTION:
  ! Module holding routines for calculation of active layer dynamics
  !
  ! !USES:
  use shr_kind_mod    , only : r8 => shr_kind_r8
  use shr_const_mod   , only : SHR_CONST_TKFRZ
  use clm_varctl      , only : iulog
  use TemperatureType , only : temperature_type
  use CanopyStateType , only : canopystate_type
  use GridcellType    , only : grc       
  use ColumnType      , only : col       
  !
  implicit none
  save
  private
  !
  ! !PUBLIC MEMBER FUNCTIONS:
  public:: alt_calc
  !-----------------------------------------------------------------------
  
contains

  !-----------------------------------------------------------------------
  subroutine alt_calc(num_soilc, filter_soilc, &
       temperature_inst, canopystate_inst) 
    !
    ! !DESCRIPTION:
    !  define active layer thickness similarly to frost_table, except set as deepest thawed layer and define on nlevgrnd
    !  also update annual maxima, and keep track of prior year for rooting memory
    !
    ! BUG(wjs, 2014-12-15, bugz 2107) Because of this routine's placement in the driver
    ! sequence (it is called very early in each timestep, before weights are adjusted and
    ! filters are updated), it may be necessary for this routine to compute values over
    ! inactive as well as active points (since some inactive points may soon become
    ! active) - so that's what is done now. Currently, it seems to be okay to do this,
    ! because the variables computed here seem to only depend on quantities that are valid
    ! over inactive as well as active points.
    !
    ! !USES:
    use shr_const_mod    , only : SHR_CONST_TKFRZ
    use clm_varpar       , only : nlevgrnd
    use clm_time_manager , only : get_curr_date, get_step_size
    use clm_varctl       , only : iulog
    use clm_varcon       , only : zsoi
    !
    ! !ARGUMENTS:
    integer                , intent(in)    :: num_soilc       ! number of soil columns in filter
    integer                , intent(in)    :: filter_soilc(:) ! filter for soil columns
    type(temperature_type) , intent(in)    :: temperature_inst
    type(canopystate_type) , intent(inout) :: canopystate_inst
    !
    ! !LOCAL VARIABLES:
    integer  :: c, j, fc, g                     ! counters
    integer  :: alt_ind                         ! index of base of activel layer
    integer  :: year                            ! year (0, ...) for nstep+1
    integer  :: mon                             ! month (1, ..., 12) for nstep+1
    integer  :: day                             ! day of month (1, ..., 31) for nstep+1
    integer  :: sec                             ! seconds into current date for nstep+1
    integer  :: dtime                           ! time step length in seconds
    integer  :: k_frz                           ! index of first nonfrozen soil layer
    logical  :: found_thawlayer                 ! used to break loop when first unfrozen layer reached
    real(r8) :: t1, t2, z1, z2                  ! temporary variables
    !-----------------------------------------------------------------------

    associate(                                                                & 
         t_soisno             =>    temperature_inst%t_soisno_col        ,    & ! Input:   [real(r8) (:,:) ]  soil temperature (Kelvin)  (-nlevsno+1:nlevgrnd)                    
         
         alt                  =>    canopystate_inst%alt_col             ,    & ! Output:  [real(r8) (:)   ]  current depth of thaw                                                 
         altmax               =>    canopystate_inst%altmax_col          ,    & ! Output:  [real(r8) (:)   ]  maximum annual depth of thaw                                          
         altmax_lastyear      =>    canopystate_inst%altmax_lastyear_col ,    & ! Output:  [real(r8) (:)   ]  prior year maximum annual depth of thaw                               
         alt_indx             =>    canopystate_inst%alt_indx_col        ,    & ! Output:  [integer  (:)   ]  current depth of thaw                                                  
         altmax_indx          =>    canopystate_inst%altmax_indx_col     ,    & ! Output:  [integer  (:)   ]  maximum annual depth of thaw                                           
         altmax_lastyear_indx =>    canopystate_inst%altmax_lastyear_indx_col & ! Output:  [integer  (:)   ]  prior year maximum annual depth of thaw                                
         )

      ! on a set annual timestep, update annual maxima
      ! make this 1 January for NH columns, 1 July for SH columns
      call get_curr_date(year, mon, day, sec)
      dtime =  get_step_size()
      if ( (mon .eq. 1) .and. (day .eq. 1) .and. ( sec / dtime .eq. 1) ) then
         do fc = 1,num_soilc
            c = filter_soilc(fc)
            g = col%gridcell(c)
            if ( grc%lat(g) > 0. ) then 
               altmax_lastyear(c) = altmax(c)
               altmax_lastyear_indx(c) = altmax_indx(c)
               altmax(c) = 0.
               altmax_indx(c) = 0
            endif
         end do
      endif
      if ( (mon .eq. 7) .and. (day .eq. 1) .and. ( sec / dtime .eq. 1) ) then
         do fc = 1,num_soilc
            c = filter_soilc(fc)
            g = col%gridcell(c)
            if ( grc%lat(g) <= 0. ) then 
               altmax_lastyear(c) = altmax(c)
               altmax_lastyear_indx(c) = altmax_indx(c)
               altmax(c) = 0.
               altmax_indx(c) = 0
            endif
         end do
      endif

      do fc = 1,num_soilc
         c = filter_soilc(fc)

         ! calculate alt for a given timestep
         ! start from base of soil and search upwards for first thawed layer.
         ! note that this will put talik in with active layer
         ! a different way of doing this could be to keep track of how long a given layer has ben frozen for, and define ALT as the first layer that has been frozen for less than 2 years.
         if (t_soisno(c,nlevgrnd) > SHR_CONST_TKFRZ ) then
            alt(c) = zsoi(nlevgrnd)
            alt_indx(c) = nlevgrnd
         else
            k_frz=0
            found_thawlayer = .false.
            do j=nlevgrnd-1,1,-1
               if ( ( t_soisno(c,j) > SHR_CONST_TKFRZ ) .and. .not. found_thawlayer ) then
                  k_frz=j
                  found_thawlayer = .true.
               endif
            end do

            if ( k_frz > 0 ) then
               ! define active layer as the depth at which the linearly interpolated temperature line intersects with zero
               z1 = zsoi(k_frz)
               z2 = zsoi(k_frz+1)
               t1 = t_soisno(c,k_frz)
               t2 = t_soisno(c,k_frz+1)
               alt(c) = z1 + (t1-SHR_CONST_TKFRZ)*(z2-z1)/(t1-t2)
               alt_indx(c) = k_frz
            else
               alt(c)=0._r8
               alt_indx(c) = 0
            endif
         endif


         ! if appropriate, update maximum annual active layer thickness
         if (alt(c) > altmax(c)) then
            altmax(c) = alt(c)
            altmax_indx(c) = alt_indx(c)
         endif

      end do

    end associate 

  end subroutine alt_calc
  
end module ActiveLayerMod