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

Land Use Fixes #1273

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
Open
68 changes: 45 additions & 23 deletions biogeochem/EDLoggingMortalityMod.F90
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ module EDLoggingMortalityMod
use PRTGenericMod , only : sapw_organ, struct_organ, leaf_organ
use PRTGenericMod , only : fnrt_organ, store_organ, repro_organ
use FatesAllometryMod , only : set_root_fraction
use FatesConstantsMod , only : primaryland, secondaryland, secondary_age_threshold
use FatesConstantsMod , only : primaryland, secondaryland, secondary_age_threshold, nocomp_bareground_land
use FatesConstantsMod , only : fates_tiny
use FatesConstantsMod , only : months_per_year, days_per_sec, years_per_day, g_per_kg
use FatesConstantsMod , only : hlm_harvest_area_fraction
Expand Down Expand Up @@ -207,7 +207,7 @@ subroutine LoggingMortality_frac( currentSite, bc_in, pft_i, dbh, canopy_layer,
hlm_harvest_rates, hlm_harvest_catnames, &
hlm_harvest_units, &
patch_land_use_label, secondary_age, &
frac_site_primary, frac_site_secondary, harvestable_forest_c, &
current_fates_landuse_state_vector, harvestable_forest_c, &
harvest_tag)

! Arguments
Expand All @@ -223,8 +223,7 @@ subroutine LoggingMortality_frac( currentSite, bc_in, pft_i, dbh, canopy_layer,
real(r8), intent(in) :: secondary_age ! patch level age_since_anthro_disturbance
real(r8), intent(in) :: harvestable_forest_c(:) ! total harvestable forest carbon
! of all hlm harvest categories
real(r8), intent(in) :: frac_site_primary
real(r8), intent(in) :: frac_site_secondary
real(r8), intent(in) :: current_fates_landuse_state_vector(n_landuse_cats) ! [m2/m2]
real(r8), intent(out) :: lmort_direct ! direct (harvestable) mortality fraction
real(r8), intent(out) :: lmort_collateral ! collateral damage mortality fraction
real(r8), intent(out) :: lmort_infra ! infrastructure mortality fraction
Expand Down Expand Up @@ -299,17 +298,22 @@ subroutine LoggingMortality_frac( currentSite, bc_in, pft_i, dbh, canopy_layer,
! Definitions of the underlying harvest land category variables
! these are hardcoded to match the LUH input data via landuse.timseries file (see dynHarvestMod)
! these are fractions of vegetated area harvested, split into five land category variables

! if using the classic CLM/ELM surface file, the variable names are:
! HARVEST_VH1 = harvest from primary forest
! HARVEST_VH2 = harvest from primary non-forest
! HARVEST_SH1 = harvest from secondary mature forest
! HARVEST_SH2 = harvest from secondary young forest
! HARVEST_SH3 = harvest from secondary non-forest (assume this is young for biomass)

! if using the direct LUH2 drivers, the variable names are instead (if using area-based logging):
! 'primf_harv', 'primn_harv', 'secmf_harv', 'secyf_harv', 'secnf_harv'

secondary_young_fraction = currentSite%get_secondary_young_fraction()

! Get the area-based harvest rates based on info passed to FATES from the boundary condition
call get_harvest_rate_area (patch_land_use_label, hlm_harvest_catnames, &
hlm_harvest_rates, frac_site_primary, frac_site_secondary, secondary_young_fraction, secondary_age, harvest_rate)
hlm_harvest_rates, current_fates_landuse_state_vector, secondary_young_fraction, secondary_age, harvest_rate)

! For area-based harvest, harvest_tag shall always be 2 (not applicable).
harvest_tag = 2
Expand Down Expand Up @@ -387,16 +391,24 @@ subroutine LoggingMortality_frac( currentSite, bc_in, pft_i, dbh, canopy_layer,
endif

else
call GetInitLanduseHarvestRate(bc_in, currentSite%min_allowed_landuse_fraction, &
harvest_rate, currentSite%landuse_vector_gt_min)
! the logic below is mainly to prevent conversion of bare ground land; everything else should be primary at this point.
lmort_direct = 0.0_r8
lmort_collateral = 0.0_r8
lmort_infra = 0.0_r8
l_degrad = 0.0_r8
if(prt_params%woody(pft_i) == itrue)then
lmort_direct = harvest_rate
else if (canopy_layer .eq. 1) then
l_degrad = harvest_rate
if ( patch_land_use_label .eq. primaryland ) then
call GetInitLanduseHarvestRate(bc_in, currentSite%min_allowed_landuse_fraction, &
harvest_rate, currentSite%landuse_vector_gt_min)
if(prt_params%woody(pft_i) == itrue)then
lmort_direct = harvest_rate
else if (canopy_layer .eq. 1) then
l_degrad = harvest_rate
endif
else if ( patch_land_use_label .ne. nocomp_bareground_land ) then
write(fates_log(),*) 'trying to transition away from something that isnt either primary or bare ground,'
write(fates_log(),*) 'on what should be a first timestep away from potential vaegetatino. this shouldnt happen.'
write(fates_log(),*) 'exiting'
call endrun(msg=errMsg(sourcefile, __LINE__))
endif
endif

Expand All @@ -406,7 +418,7 @@ end subroutine LoggingMortality_frac
! ============================================================================

subroutine get_harvest_rate_area (patch_land_use_label, hlm_harvest_catnames, hlm_harvest_rates, &
frac_site_primary, frac_site_secondary, secondary_young_fraction, secondary_age, harvest_rate)
current_fates_landuse_state_vector, secondary_young_fraction, secondary_age, harvest_rate)


! -------------------------------------------------------------------------------------------
Expand All @@ -420,33 +432,39 @@ subroutine get_harvest_rate_area (patch_land_use_label, hlm_harvest_catnames, hl
character(len=64), intent(in) :: hlm_harvest_catnames(:) ! names of hlm harvest categories
integer, intent(in) :: patch_land_use_label ! patch level land_use_label
real(r8), intent(in) :: secondary_age ! patch level age_since_anthro_disturbance
real(r8), intent(in) :: frac_site_primary
real(r8), intent(in) :: frac_site_secondary
real(r8), intent(in) :: current_fates_landuse_state_vector(n_landuse_cats) ! [m2/m2]
real(r8), intent(in) :: secondary_young_fraction ! what fraction of secondary land is young secondary land
real(r8), intent(out) :: harvest_rate

! Local Variables
integer :: h_index ! for looping over harvest categories
integer :: icode ! Integer equivalent of the event code (parameter file only allows reals)
real(r8) :: frac_site_primary
real(r8) :: frac_site_secondary
real(r8) :: frac_not_bareground

! Loop around harvest categories to determine the annual hlm harvest rate for the current cohort based on patch history info
! We do account forest only since non-forest harvest has geographical mismatch to LUH2 dataset
harvest_rate = 0._r8
do h_index = 1,hlm_num_lu_harvest_cats
if (patch_land_use_label .eq. primaryland) then
if(hlm_harvest_catnames(h_index) .eq. "HARVEST_VH1" .or. &
hlm_harvest_catnames(h_index) .eq. "HARVEST_VH2") then
hlm_harvest_catnames(h_index) .eq. "HARVEST_VH2" .or. &
hlm_harvest_catnames(h_index) .eq. "primf_harv" .or. &
hlm_harvest_catnames(h_index) .eq. "primn_harv") then
harvest_rate = harvest_rate + hlm_harvest_rates(h_index)
endif
else if (patch_land_use_label .eq. secondaryland .and. &
secondary_age >= secondary_age_threshold) then
if(hlm_harvest_catnames(h_index) .eq. "HARVEST_SH1") then
if(hlm_harvest_catnames(h_index) .eq. "HARVEST_SH1" .or. &
hlm_harvest_catnames(h_index) .eq. "secmf_harv") then
harvest_rate = harvest_rate + hlm_harvest_rates(h_index)
endif
else if (patch_land_use_label .eq. secondaryland .and. &
secondary_age < secondary_age_threshold) then
if(hlm_harvest_catnames(h_index) .eq. "HARVEST_SH2" .or. &
hlm_harvest_catnames(h_index) .eq. "HARVEST_SH3") then
hlm_harvest_catnames(h_index) .eq. "HARVEST_SH3" .or. &
hlm_harvest_catnames(h_index) .eq. "secyf_harv" .or. &
hlm_harvest_catnames(h_index) .eq. "secnf_harv") then
harvest_rate = harvest_rate + hlm_harvest_rates(h_index)
endif
endif
Expand All @@ -456,19 +474,23 @@ subroutine get_harvest_rate_area (patch_land_use_label, hlm_harvest_catnames, hl
! since harvest_rate is specified as a fraction of the gridcell
! also need to put a cap so as not to harvest more primary or secondary area than there is in a gridcell
! For secondary, also need to normalize by the young/old fraction.
! Lastly, we need to remove the bare ground fraction since the harvest rates are per unit area of the not-bare-ground fraction.
frac_site_primary = current_fates_landuse_state_vector(primaryland)
frac_site_secondary = current_fates_landuse_state_vector(secondaryland)
frac_not_bareground = sum(current_fates_landuse_state_vector(:))
if (patch_land_use_label .eq. primaryland) then
if (frac_site_primary .gt. fates_tiny) then
harvest_rate = min((harvest_rate / frac_site_primary),1._r8)
if (frac_site_primary .gt. fates_tiny .and. frac_not_bareground .gt. fates_tiny) then
harvest_rate = min((harvest_rate / (frac_site_primary / frac_not_bareground)),1._r8)
else
harvest_rate = 0._r8
endif
else if (patch_land_use_label .eq. secondaryland) then
! the .gt. -0.5 in the next line is because frac_site_secondary returns -1 if no secondary area.
if (frac_site_secondary .gt. fates_tiny .and. frac_site_secondary .gt. -0.5_r8) then
if (frac_site_secondary .gt. fates_tiny .and. frac_site_secondary .gt. -0.5_r8 .and. frac_not_bareground .gt. fates_tiny) then
if (secondary_age .lt. secondary_age_threshold) then
harvest_rate = min((harvest_rate / (frac_site_secondary * secondary_young_fraction)), 1._r8)
harvest_rate = min((harvest_rate / ((frac_site_secondary / frac_not_bareground) * secondary_young_fraction)), 1._r8)
else
harvest_rate = min((harvest_rate / (frac_site_secondary * (1._r8 - secondary_young_fraction))), 1._r8)
harvest_rate = min((harvest_rate / ((frac_site_secondary / frac_not_bareground) * (1._r8 - secondary_young_fraction))), 1._r8)
endif
else
harvest_rate = 0._r8
Expand Down
11 changes: 5 additions & 6 deletions biogeochem/EDMortalityFunctionsMod.F90
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ module EDMortalityFunctionsMod
use FatesInterfaceTypesMod , only : hlm_use_tree_damage
use EDLoggingMortalityMod , only : LoggingMortality_frac
use EDParamsMod , only : fates_mortality_disturbance_fraction

use FatesConstantsMod , only : n_landuse_cats
use PRTGenericMod, only : carbon12_element
use PRTGenericMod, only : store_organ
use PRTParametersMod , only : prt_params
Expand Down Expand Up @@ -281,7 +281,7 @@ end subroutine mortality_rates

subroutine Mortality_Derivative( currentSite, currentCohort, bc_in, btran_ft, &
mean_temp, land_use_label, age_since_anthro_disturbance, &
frac_site_primary, frac_site_secondary, harvestable_forest_c, harvest_tag)
current_fates_landuse_state_vector, harvestable_forest_c, harvest_tag)

!
! !DESCRIPTION:
Expand All @@ -300,9 +300,8 @@ subroutine Mortality_Derivative( currentSite, currentCohort, bc_in, btran_ft, &
real(r8), intent(in) :: mean_temp
integer, intent(in) :: land_use_label
real(r8), intent(in) :: age_since_anthro_disturbance
real(r8), intent(in) :: frac_site_primary
real(r8), intent(in) :: frac_site_secondary

real(r8), intent(in) :: current_fates_landuse_state_vector(n_landuse_cats)

real(r8), intent(in) :: harvestable_forest_c(:) ! total carbon available for logging, kgC site-1
integer, intent(out) :: harvest_tag(:) ! tag to record the harvest status
! for the calculation of harvest debt in C-based
Expand Down Expand Up @@ -340,7 +339,7 @@ subroutine Mortality_Derivative( currentSite, currentCohort, bc_in, btran_ft, &
bc_in%hlm_harvest_units, &
land_use_label, &
age_since_anthro_disturbance, &
frac_site_primary, frac_site_secondary, harvestable_forest_c, harvest_tag)
current_fates_landuse_state_vector, harvestable_forest_c, harvest_tag)

if (currentCohort%canopy_layer > 1)then
! Include understory logging mortality rates not associated with disturbance
Expand Down
17 changes: 8 additions & 9 deletions biogeochem/EDPatchDynamicsMod.F90
Original file line number Diff line number Diff line change
Expand Up @@ -271,8 +271,7 @@ subroutine disturbance_rates( site_in, bc_in)
bc_in%hlm_harvest_units, &
currentPatch%land_use_label, &
currentPatch%age_since_anthro_disturbance, &
current_fates_landuse_state_vector(primaryland), &
current_fates_landuse_state_vector(secondaryland), &
current_fates_landuse_state_vector, &
harvestable_forest_c, &
harvest_tag)

Expand Down Expand Up @@ -401,8 +400,7 @@ subroutine disturbance_rates( site_in, bc_in)
harvest_rate, harvest_tag)
else
call get_harvest_rate_area (currentPatch%land_use_label, bc_in%hlm_harvest_catnames, &
bc_in%hlm_harvest_rates, current_fates_landuse_state_vector(primaryland), &
current_fates_landuse_state_vector(secondaryland), secondary_young_fraction, &
bc_in%hlm_harvest_rates, current_fates_landuse_state_vector, secondary_young_fraction, &
currentPatch%age_since_anthro_disturbance, harvest_rate)
end if

Expand Down Expand Up @@ -430,11 +428,12 @@ subroutine disturbance_rates( site_in, bc_in)
(currentPatch%area - currentPatch%total_canopy_area) * harvest_rate / currentPatch%area
endif

! For nocomp mode, we need to prevent producing too small patches, which may produce small patches
if ((hlm_use_nocomp .eq. itrue) .and. &
(currentPatch%disturbance_rates(dtype_ilog)*currentPatch%area .lt. min_patch_area_forced)) then
currentPatch%disturbance_rates(dtype_ilog) = 0._r8
end if
! cdk. Oct. 24, 2024. I don't think we need this anymore. commenting out.
! ! For nocomp mode, we need to prevent producing too small patches, which may produce small patches
! if ((hlm_use_nocomp .eq. itrue) .and. &
! (currentPatch%disturbance_rates(dtype_ilog)*currentPatch%area .lt. min_patch_area_forced)) then
! currentPatch%disturbance_rates(dtype_ilog) = 0._r8
! end if

! fraction of the logging disturbance rate that is non-harvested
if (currentPatch%disturbance_rates(dtype_ilog) .gt. nearzero) then
Expand Down
2 changes: 2 additions & 0 deletions biogeochem/FatesLandUseChangeMod.F90
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,8 @@ subroutine GetInitLanduseHarvestRate(bc_in, min_allowed_landuse_fraction, harves
if ( state_vector(secondaryland) .gt. min_allowed_landuse_fraction) then
harvest_rate = state_vector(secondaryland)
landuse_vector_gt_min(secondaryland) = .true.
else
harvest_rate = 0._r8
endif

end subroutine GetInitLanduseHarvestRate
Expand Down
4 changes: 2 additions & 2 deletions main/EDMainMod.F90
Original file line number Diff line number Diff line change
Expand Up @@ -478,8 +478,8 @@ subroutine ed_integrate_state_variables(currentSite, bc_in, bc_out )
call Mortality_Derivative(currentSite, currentCohort, bc_in, &
currentPatch%btran_ft, mean_temp, &
currentPatch%land_use_label, &
currentPatch%age_since_anthro_disturbance, current_fates_landuse_state_vector(primaryland), &
current_fates_landuse_state_vector(secondaryland), harvestable_forest_c, harvest_tag)
currentPatch%age_since_anthro_disturbance, current_fates_landuse_state_vector, &
harvestable_forest_c, harvest_tag)

! -----------------------------------------------------------------------------
! Apply Plant Allocation and Reactive Transport
Expand Down
Loading