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

Merged
merged 24 commits into from
Jan 31, 2025
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
6dc557e
fixed harvest rates when bare ground >0
ckoven Oct 22, 2024
dacea7c
added primary lands age dist history diagnostic, and updated some var…
ckoven Oct 22, 2024
1895896
adding variable names from luh2 harvest drivers
ckoven Oct 25, 2024
59be470
handling open canopy initial landuse harvest conversion case
ckoven Oct 25, 2024
e1711ab
removing logic that prevents harvest at too-small rates
ckoven Oct 25, 2024
cff1005
deleting most of the secondary-specific hist vars, in prep for adding…
ckoven Oct 25, 2024
a580785
added two new hist vars: biomass and burned area, by land use type
ckoven Oct 25, 2024
5688237
added two more hist vars: GPP and NPP, by land use type
ckoven Oct 25, 2024
52462b5
Fix typo in comment.
samsrabin Nov 1, 2024
f19848b
Simplify "prevent conversion of bare ground land" logic.
samsrabin Nov 1, 2024
111278a
Undo an indentation change.
samsrabin Nov 1, 2024
6f4f3f6
Merge pull request #25 from samsrabin/landuse_fixes-ssr
ckoven Nov 1, 2024
73838b3
Merge tag 'sci.1.80.6_api.37.0.0' into landuse_fixes-deconflict
glemieux Jan 4, 2025
96aeedb
fix npp by age calculation
glemieux Jan 6, 2025
cd6931f
fix bad merge deconflict and remove old secondary history variable
glemieux Jan 6, 2025
69e7433
remove npp by age from high frequency history
glemieux Jan 7, 2025
e4a163d
move npp by land use out of high frequency section
glemieux Jan 7, 2025
70c21a3
fix update frequency setting for FATES_NPP_LU
glemieux Jan 10, 2025
33dcdf6
Update biogeochem/EDLoggingMortalityMod.F90
glemieux Jan 10, 2025
22f7249
Merge pull request #26 from glemieux/landuse_fixes-deconflict
ckoven Jan 13, 2025
ee0e47f
fix typos in FatesHistoryInterfaceMod.F90
ckoven Jan 17, 2025
e118d40
delete commented-out text in EDPatchDynamicsMod.F90
ckoven Jan 17, 2025
9e8473b
Merge tag 'sci.1.80.10_api.37.0.0' into landuse_fixes
glemieux Jan 30, 2025
694e806
correct location of FATES_NPP_LU calculation
glemieux Jan 30, 2025
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
81 changes: 54 additions & 27 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 variabel names are instead (if using area-based logging):
samsrabin marked this conversation as resolved.
Show resolved Hide resolved
! '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,29 @@ 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)
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
! the logic below is mainly to prevent conversion of bare ground land; everything else should be primary at this point.
if ( patch_land_use_label .eq. primaryland ) then
call GetInitLanduseHarvestRate(bc_in, currentSite%min_allowed_landuse_fraction, &
harvest_rate, currentSite%landuse_vector_gt_min)
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
endif
else if ( patch_land_use_label .eq. nocomp_bareground_land ) then
lmort_direct = 0.0_r8
lmort_collateral = 0.0_r8
lmort_infra = 0.0_r8
l_degrad = 0.0_r8
samsrabin marked this conversation as resolved.
Show resolved Hide resolved
else
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.'
glemieux marked this conversation as resolved.
Show resolved Hide resolved
write(fates_log(),*) 'exiting'
call endrun(msg=errMsg(sourcefile, __LINE__))
endif
endif

Expand All @@ -406,7 +423,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 +437,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 +479,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
ckoven marked this conversation as resolved.
Show resolved Hide resolved

! 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