Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create driver data structure for SP mode #2952

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
160 changes: 106 additions & 54 deletions src/biogeochem/SatellitePhenologyMod.F90
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ module SatellitePhenologyMod
private
!
! !PUBLIC MEMBER FUNCTIONS:
public :: SatellitePhenology ! CLMSP Ecosystem dynamics: phenology, vegetation
public :: GetSatellitePhenologyInputs ! put the data into the correct format
public :: SetSPModeCanopyStructs ! CLM(BGC)-SP phenology and vegetation
public :: SatellitePhenologyInit ! Dynamically allocate memory
public :: interpMonthlyVeg ! interpolate monthly vegetation data
public :: readAnnualVegetation ! Read in annual vegetation (needed for Dry-deposition)
Expand Down Expand Up @@ -88,8 +89,7 @@ subroutine SatellitePhenologyInit (bounds)
end subroutine SatellitePhenologyInit

!================================================================
subroutine SatellitePhenology(bounds, num_filter, filter, &
waterdiagnosticbulk_inst, canopystate_inst)
subroutine GetSatellitePhenologyInputs(bounds, num_filter, filter, canopystate_inst)
!
! !DESCRIPTION:
! Ecosystem dynamics: phenology, vegetation
Expand All @@ -107,25 +107,17 @@ subroutine SatellitePhenology(bounds, num_filter, filter, &
type(bounds_type) , intent(in) :: bounds
integer , intent(in) :: num_filter ! number of column points in patch filter
integer , intent(in) :: filter(bounds%endp-bounds%begp+1) ! patch filter points
type(waterdiagnosticbulk_type) , intent(in) :: waterdiagnosticbulk_inst
type(canopystate_type) , intent(inout) :: canopystate_inst
!
! !LOCAL VARIABLES:
integer :: fp,p,c ! indices
real(r8) :: ol ! thickness of canopy layer covered by snow (m)
real(r8) :: fb ! fraction of canopy layer covered by snow
!-----------------------------------------------------------------------

associate( &
frac_sno => waterdiagnosticbulk_inst%frac_sno_col , & ! Input: [real(r8) (:) ] fraction of ground covered by snow (0 to 1)
snow_depth => waterdiagnosticbulk_inst%snow_depth_col , & ! Input: [real(r8) (:) ] snow height (m)
tlai => canopystate_inst%tlai_patch , & ! Output: [real(r8) (:) ] one-sided leaf area index, no burying by snow
tsai => canopystate_inst%tsai_patch , & ! Output: [real(r8) (:) ] one-sided stem area index, no burying by snow
elai => canopystate_inst%elai_patch , & ! Output: [real(r8) (:) ] one-sided leaf area index with burying by snow
esai => canopystate_inst%esai_patch , & ! Output: [real(r8) (:) ] one-sided stem area index with burying by snow
htop => canopystate_inst%htop_patch , & ! Output: [real(r8) (:) ] canopy top (m)
hbot => canopystate_inst%hbot_patch , & ! Output: [real(r8) (:) ] canopy bottom (m)
frac_veg_nosno_alb => canopystate_inst%frac_veg_nosno_alb_patch & ! Output: [integer (:) ] fraction of vegetation not covered by snow (0 OR 1) [-]
tlai_tinterp => canopystate_inst%tlai_input_patch , & ! Output: [real(r8) (:) ] one-sided leaf area index, no burying by snow
tsai_tinterp => canopystate_inst%tsai_input_patch , & ! Output: [real(r8) (:) ] one-sided stem area index, no burying by snow
htop_tinterp => canopystate_inst%htop_input_patch , & ! Output: [real(r8) (:) ] canopy top (m)
hbot_tinterp => canopystate_inst%hbot_input_patch & ! Output: [real(r8) (:) ] canopy bottom (m)
)

if (use_lai_streams) then
Expand Down Expand Up @@ -153,53 +145,113 @@ subroutine SatellitePhenology(bounds, num_filter, filter, &
! bottom height HBOT <- mhvb1 and mhvb2

if (.not. use_lai_streams) then
tlai(p) = timwt(1)*mlai2t(p,1) + timwt(2)*mlai2t(p,2)
endif

tsai(p) = timwt(1)*msai2t(p,1) + timwt(2)*msai2t(p,2)
htop(p) = timwt(1)*mhvt2t(p,1) + timwt(2)*mhvt2t(p,2)
hbot(p) = timwt(1)*mhvb2t(p,1) + timwt(2)*mhvb2t(p,2)

! adjust lai and sai for burying by snow. if exposed lai and sai
! are less than 0.05, set equal to zero to prevent numerical
! problems associated with very small lai and sai.

! snow burial fraction for short vegetation (e.g. grasses, crops) changes with vegetation height
! accounts for a 20% bending factor, as used in Lombardozzi et al. (2018) GRL 45(18), 9889-9897

! NOTE: The following snow burial code is duplicated in CNVegStructUpdateMod.
! Changes in one place should be accompanied by similar changes in the other.

if (patch%itype(p) > noveg .and. patch%itype(p) <= nbrdlf_dcd_brl_shrub ) then
ol = min( max(snow_depth(c)-hbot(p), 0._r8), htop(p)-hbot(p))
fb = 1._r8 - ol / max(1.e-06_r8, htop(p)-hbot(p))
else
fb = 1._r8 - (max(min(snow_depth(c),max(0.05,htop(p)*0.8_r8)),0._r8)/(max(0.05,htop(p)*0.8_r8)))
tlai_tinterp(p) = timwt(1)*mlai2t(p,1) + timwt(2)*mlai2t(p,2)
endif

! area weight by snow covered fraction
if(.not.use_fates_sp)then
tsai_tinterp(p) = timwt(1)*msai2t(p,1) + timwt(2)*msai2t(p,2)
htop_tinterp(p) = timwt(1)*mhvt2t(p,1) + timwt(2)*mhvt2t(p,2)
hbot_tinterp(p) = timwt(1)*mhvb2t(p,1) + timwt(2)*mhvb2t(p,2)

end do
end associate

end subroutine GetSatellitePhenologyInputs

!==============================================================================

subroutine SetSatellitePhenologyBGCCanopyStructs(bounds, num_filter, filter, &
waterdiagnosticbulk_inst, canopystate_inst)
!
! !DESCRIPTION:
! Ecosystem dynamics: phenology, vegetation
! Sets the canopystate_inst% data structure for non-FATES runs
!
! !USES:
use pftconMod , only : noveg, nbrdlf_dcd_brl_shrub
use WaterDiagnosticBulkType , only : waterdiagnosticbulk_type
use CanopyStateType , only : canopystate_type
use PatchType , only : patch
use clm_varctl , only : use_fates_sp

!
! !ARGUMENTS:
type(bounds_type) , intent(in) :: bounds
integer , intent(in) :: num_filter ! number of column points in patch filter
integer , intent(in) :: filter(bounds%endp-bounds%begp+1) ! patch filter points
type(waterdiagnosticbulk_type) , intent(in) :: waterdiagnosticbulk_inst
type(canopystate_type) , intent(inout) :: canopystate_inst
!
! !LOCAL VARIABLES:
integer :: fp,p,c ! indices
real(r8) :: ol ! thickness of canopy layer covered by snow (m)
real(r8) :: fb ! fraction of canopy layer covered by snow

if (use_fates_sp) then
write(iulog,*) 'SetSatellitePhenologyBGCCanopyStructs', 'should not be calling this method when use_fates_sp == .true.'
call endrun(msg=errMsg(sourcefile, __LINE__))
end if

associate( &
frac_sno => waterdiagnosticbulk_inst%frac_sno_col , & ! Input: [real(r8) (:) ] fraction of ground covered by snow (0 to 1)
snow_depth => waterdiagnosticbulk_inst%snow_depth_col , & ! Input: [real(r8) (:) ] snow height (m)
tlai_driver => canopystate_inst%tlai_input_patch , & ! Input: [real(r8) (:) ] SP driver data for one-sided leaf area index, no burying by snow
tsai_driver => canopystate_inst%tsai_input_patch , & ! Input: [real(r8) (:) ] SP driver data for one-sided stem area index, no burying by snow
tlai => canopystate_inst%tlai_patch, & ! Output: [real(r8) (:)] one-sided leaf area index, no burying by snow
tsai => canopystate_inst%tsai_patch, & ! Output: [real(r8) (:)] one-sided stem area index, no burying by snow
elai => canopystate_inst%elai_patch , & ! Output: [real(r8) (:) ] one-sided leaf area index with burying by snow
esai => canopystate_inst%esai_patch , & ! Output: [real(r8) (:) ] one-sided stem area index with burying by snow
htop_driver => canopystate_inst%htop_input_patch , & ! Input: [real(r8) (:) ] SP driver data for canopy top (m)
hbot_driver => canopystate_inst%hbot_input_patch , & ! Input: [real(r8) (:) ] SP driver data for canopy bottom (m)
htop => canopystate_inst%htop_patch , & ! Output: [real(r8) (:) ] canopy top (m)
hbot => canopystate_inst%hbot_patch , & ! Output: [real(r8) (:) ] canopy bottom (m)
frac_veg_nosno_alb => canopystate_inst%frac_veg_nosno_alb_patch & ! Output: [integer (:) ] fraction of vegetation not covered by snow (0 OR 1) [-]
)

do fp = 1, num_filter

p = filter(fp)
c = patch%column(p)

! for regular CLM (non-FATES), this is just a 1:1 mapping
tlai(p) = tlai_driver(p)
tsai(p) = tsai_driver(p)
htop(p) = htop_driver(p)
hbot(p) = hbot_driver(p)

! adjust lai and sai for burying by snow. if exposed lai and sai
! are less than 0.05, set equal to zero to prevent numerical
! problems associated with very small lai and sai.

! snow burial fraction for short vegetation (e.g. grasses, crops) changes with vegetation height
! accounts for a 20% bending factor, as used in Lombardozzi et al. (2018) GRL 45(18), 9889-9897

! NOTE: The following snow burial code is duplicated in CNVegStructUpdateMod.
! Changes in one place should be accompanied by similar changes in the other.

if (patch%itype(p) > noveg .and. patch%itype(p) <= nbrdlf_dcd_brl_shrub) then
ol = min(max(snow_depth(c) - hbot(p), 0.0_r8), htop(p) - hbot(p))
fb = 1._r8 - ol / max(1.e-06_r8, htop(p)-hbot(p))
else
fb = 1._r8 - (max(min(snow_depth(c),max(0.05,htop(p)*0.8_r8)),0._r8)/(max(0.05,htop(p)*0.8_r8)))
endif

! Do not set these in FATES_SP mode as they turn on the 'vegsol' filter and also
! are duplicated by the FATE variables (in the FATES IFP indexing space)
elai(p) = max(tlai(p)*(1.0_r8 - frac_sno(c)) + tlai(p)*fb*frac_sno(c), 0.0_r8)
esai(p) = max(tsai(p)*(1.0_r8 - frac_sno(c)) + tsai(p)*fb*frac_sno(c), 0.0_r8)
if (elai(p) < 0.05_r8) elai(p) = 0._r8
if (esai(p) < 0.05_r8) esai(p) = 0._r8
elai(p) = max(tlai(p)*(1.0_r8 - frac_sno(c)) + tlai(p)*fb*frac_sno(c), 0.0_r8)
esai(p) = max(tsai(p)*(1.0_r8 - frac_sno(c)) + tsai(p)*fb*frac_sno(c), 0.0_r8)
if (elai(p) < 0.05_r8) elai(p) = 0._r8
if (esai(p) < 0.05_r8) esai(p) = 0._r8

! Fraction of vegetation free of snow
! Fraction of vegetation free of snow
if ((elai(p) + esai(p)) >= 0.05_r8) then
frac_veg_nosno_alb(p) = 1
else
frac_veg_nosno_alb(p) = 0
end if

if ((elai(p) + esai(p)) >= 0.05_r8) then
frac_veg_nosno_alb(p) = 1
else
frac_veg_nosno_alb(p) = 0
end if
endif !fates_sp
end do ! end of patch loop
end do ! end of patch loop

end associate

end subroutine SatellitePhenology
end subroutine SetSatellitePhenologyBGCCanopyStructs

!==============================================================================
subroutine interpMonthlyVeg (bounds, canopystate_inst)
Expand Down
33 changes: 18 additions & 15 deletions src/biogeophys/CanopyStateType.F90
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,10 @@ module CanopyStateType
real(r8) , pointer :: elai_patch (:) ! patch canopy one-sided leaf area index with burying by snow
real(r8) , pointer :: esai_patch (:) ! patch canopy one-sided stem area index with burying by snow

real(r8) , pointer :: tlai_hist_patch (:) ! patch canopy one-sided leaf area index, for SP mode
real(r8) , pointer :: tsai_hist_patch (:) ! patch canopy one-sided stem area index, for SP mode
real(r8) , pointer :: htop_hist_patch (:) ! patch canopy height, for SP mode
real(r8) , pointer :: tlai_input_patch (:) ! patch canopy one-sided leaf area index driver data for SP mode (no burying by snow)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hist was a confusing suffix to have here, so I'm glad you are changing it. So input again means it's the value from the dataset?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

well yes, input, plus interpolated?

real(r8) , pointer :: tsai_input_patch (:) ! patch canopy one-sided stem area index driver data for SP mode (no burying by snow)
real(r8) , pointer :: htop_input_patch (:) ! patch canopy height driver data for SP mode
real(r8) , pointer :: hbot_input_patch (:) ! patch canopy bottom driver data for SP mode

real(r8) , pointer :: elai240_patch (:) ! patch canopy one-sided leaf area index with burying by snow average over 10days
real(r8) , pointer :: laisun_patch (:) ! patch patch sunlit projected leaf area index
Expand Down Expand Up @@ -119,9 +120,10 @@ subroutine InitAllocate(this, bounds)

allocate(this%frac_veg_nosno_patch (begp:endp)) ; this%frac_veg_nosno_patch (:) = huge(1)
allocate(this%frac_veg_nosno_alb_patch (begp:endp)) ; this%frac_veg_nosno_alb_patch (:) = 0
allocate(this%tlai_hist_patch (begp:endp)) ; this%tlai_hist_patch (:) = nan
allocate(this%tsai_hist_patch (begp:endp)) ; this%tsai_hist_patch (:) = nan
allocate(this%htop_hist_patch (begp:endp)) ; this%htop_hist_patch (:) = nan
allocate(this%tlai_input_patch (begp:endp)) ; this%tlai_input_patch (:) = nan
allocate(this%tsai_input_patch (begp:endp)) ; this%tsai_input_patch (:) = nan
allocate(this%htop_input_patch (begp:endp)) ; this%htop_input_patch (:) = nan
allocate(this%hbot_input_patch (begp:endp)) ; this%hbot_input_patch (:) = nan
allocate(this%tlai_patch (begp:endp)) ; this%tlai_patch (:) = nan
allocate(this%tsai_patch (begp:endp)) ; this%tsai_patch (:) = nan
allocate(this%elai_patch (begp:endp)) ; this%elai_patch (:) = nan
Expand Down Expand Up @@ -217,10 +219,10 @@ subroutine InitHistory(this, bounds)
ptr_patch=this%displa_patch, default='inactive', l2g_scale_type='veg')

if(use_fates_sp)then
this%htop_hist_patch(begp:endp) = spval
this%htop_input_patch(begp:endp) = spval
call hist_addfld1d (fname='HTOP', units='m', &
avgflag='A', long_name='HTOP weights for SP mode', &
ptr_patch=this%htop_hist_patch)
ptr_patch=this%htop_input_patch)
else
this%htop_patch(begp:endp) = spval
call hist_addfld1d (fname='HTOP', units='m', &
Expand All @@ -230,15 +232,15 @@ subroutine InitHistory(this, bounds)
endif

if(use_fates_sp)then
this%tlai_hist_patch(begp:endp) = spval
this%tlai_input_patch(begp:endp) = spval
call hist_addfld1d (fname='TLAI', units='m', &
avgflag='A', long_name='TLAI weights for SP mode', &
ptr_patch=this%tlai_hist_patch)
ptr_patch=this%tlai_input_patch)

this%tsai_hist_patch(begp:endp) = spval
this%tsai_input_patch(begp:endp) = spval
call hist_addfld1d (fname='TSAI', units='m', &
avgflag='A', long_name='TSAI weights for SP mode', &
ptr_patch=this%tsai_hist_patch)
ptr_patch=this%tsai_input_patch)

else
this%tlai_patch(begp:endp) = spval
Expand Down Expand Up @@ -541,9 +543,10 @@ subroutine InitCold(this, bounds)
this%laisha_patch(p) = 0._r8
end if

this%tlai_hist_patch(p) = 0._r8
this%tsai_hist_patch(p) = 0._r8
this%htop_hist_patch(p) = 0._r8
this%tlai_input_patch(p) = 0._r8
this%tsai_input_patch(p) = 0._r8
this%htop_input_patch(p) = 0._r8
this%hbot_input_patch(p) = 0._r8

! needs to be initialized to spval to avoid problems when averaging for the accum
! field
Expand Down
4 changes: 2 additions & 2 deletions src/cpl/share_esmf/laiStreamMod.F90
Original file line number Diff line number Diff line change
Expand Up @@ -259,10 +259,10 @@ subroutine lai_interp(bounds, canopystate_inst)
if (ivt /= noveg) then
! vegetated pft
ig = g_to_ig(patch%gridcell(p))
canopystate_inst%tlai_patch(p) = dataptr2d(ig,ivt)
canopystate_inst%tlai_input_patch(p) = dataptr2d(ig,ivt)
else
! non-vegetated pft
canopystate_inst%tlai_patch(p) = 0._r8
canopystate_inst%tlai_input_patch(p) = 0._r8
endif
end do
deallocate(dataptr2d)
Expand Down
11 changes: 6 additions & 5 deletions src/main/clm_driver.F90
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ module clm_driver
use UrbanRadiationMod , only : UrbanRadiation
!
use SoilBiogeochemVerticalProfileMod , only : SoilBiogeochemVerticalProfile
use SatellitePhenologyMod , only : SatellitePhenology, interpMonthlyVeg
use SatellitePhenologyMod , only : GetSatellitePhenologyInputs, interpMonthlyVeg, SetSPModeCanopyStructs
use ndepStreamMod , only : ndep_interp
use cropcalStreamMod , only : cropcal_advance, cropcal_interp
use ch4Mod , only : ch4, ch4_init_gridcell_balance_check, ch4_init_column_balance_check
Expand Down Expand Up @@ -1044,7 +1044,9 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro

if (((.not. use_cn) .and. (.not. use_fates) .and. (doalb))) then
call t_startf('SatellitePhenology')
call SatellitePhenology(bounds_clump, filter(nc)%num_nolakep, filter(nc)%nolakep, &
call GetSatellitePhenologyInputs(bounds_clump, filter(nc)%num_nolakep, filter(nc)%nolakep, &
canopystate_inst)
call SetSPModeCanopyStructs(bounds_clump, filter(nc)%num_nolakep, filter(nc)%nolakep, &
water_inst%waterdiagnosticbulk_inst, canopystate_inst)
call t_stopf('SatellitePhenology')
end if
Expand All @@ -1057,9 +1059,8 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro
! E.g. in FATES, an active PFT vector of 1, 0, 0, 0, 1, 0, 1, 0 would be mapped into
! the host land model as 1, 1, 1, 0, 0, 0, 0. As such, the 'active' filter would only
! use the first three points, which would incorrectly represent the interpolated values.
call SatellitePhenology(bounds_clump, &
filter_inactive_and_active(nc)%num_soilp, filter_inactive_and_active(nc)%soilp, &
water_inst%waterdiagnosticbulk_inst, canopystate_inst)
call GetSatellitePhenologyInputs(bounds_clump, filter(nc)%num_nolakep, filter(nc)%nolakep, &
canopystate_inst)
call t_stopf('SatellitePhenology')

end if
Expand Down
Loading