diff --git a/biogeochem/EDLoggingMortalityMod.F90 b/biogeochem/EDLoggingMortalityMod.F90 index bf6ab7443c..6d373e995a 100644 --- a/biogeochem/EDLoggingMortalityMod.F90 +++ b/biogeochem/EDLoggingMortalityMod.F90 @@ -28,6 +28,7 @@ module EDLoggingMortalityMod use FatesConstantsMod , only : dtype_ilog use FatesConstantsMod , only : dtype_ifall use FatesConstantsMod , only : dtype_ifire + use FatesConstantsMod , only : n_landuse_cats use EDPftvarcon , only : EDPftvarcon_inst use EDPftvarcon , only : GetDecompyFrac use PRTParametersMod , only : prt_params @@ -53,6 +54,7 @@ module EDLoggingMortalityMod use FatesInterfaceTypesMod , only : hlm_num_lu_harvest_cats use FatesInterfaceTypesMod , only : hlm_use_logging use FatesInterfaceTypesMod , only : hlm_use_planthydro + use FatesInterfaceTypesMod , only : hlm_use_luh use FatesConstantsMod , only : itrue,ifalse use FatesGlobals , only : endrun => fates_endrun use FatesGlobals , only : fates_log @@ -69,7 +71,10 @@ module EDLoggingMortalityMod use FatesConstantsMod , only : hlm_harvest_area_fraction use FatesConstantsMod , only : hlm_harvest_carbon use FatesConstantsMod, only : fates_check_param_set - + use FatesInterfaceTypesMod , only : numpft + use FatesLandUseChangeMod, only : GetInitLanduseHarvestRate + use FatesLandUseChangeMod, only : GetLUHStatedata + implicit none private @@ -195,15 +200,17 @@ end subroutine IsItLoggingTime ! ====================================================================================== - subroutine LoggingMortality_frac( pft_i, dbh, canopy_layer, lmort_direct, & + subroutine LoggingMortality_frac( currentSite, bc_in, pft_i, dbh, canopy_layer, lmort_direct, & lmort_collateral,lmort_infra, l_degrad, & hlm_harvest_rates, hlm_harvest_catnames, & hlm_harvest_units, & patch_land_use_label, secondary_age, & - frac_site_primary, harvestable_forest_c, & + frac_site_primary, frac_site_secondary, harvestable_forest_c, & harvest_tag) - ! Arguments + ! Arguments + type(ed_site_type), intent(inout), target :: currentSite ! site structure + type(bc_in_type), intent(in) :: bc_in integer, intent(in) :: pft_i ! pft index real(r8), intent(in) :: dbh ! diameter at breast height (cm) integer, intent(in) :: canopy_layer ! canopy layer of this cohort @@ -215,6 +222,7 @@ subroutine LoggingMortality_frac( pft_i, dbh, canopy_layer, lmort_direct, & 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(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 @@ -232,6 +240,9 @@ subroutine LoggingMortality_frac( pft_i, dbh, canopy_layer, lmort_direct, & ! Local variables integer :: cur_harvest_tag ! the harvest tag of the cohort today real(r8) :: harvest_rate ! the final harvest rate to apply to this cohort today + real(r8) :: state_vector(n_landuse_cats) + logical :: site_secondaryland_first_exceeding_min + real(r8) :: secondary_young_fraction ! what fraction of secondary land is young secondary land ! todo: probably lower the dbhmin default value to 30 cm ! todo: change the default logging_event_code to 1 september (-244) @@ -239,55 +250,92 @@ subroutine LoggingMortality_frac( pft_i, dbh, canopy_layer, lmort_direct, & ! todo: check outputs against the LUH2 carbon data ! todo: eventually set up distinct harvest practices, each with a set of input paramaeters ! todo: implement harvested carbon inputs - - if (logging_time) then - ! Pass logging rates to cohort level - - if (hlm_use_lu_harvest == ifalse) then - ! 0=use fates logging parameters directly when logging_time == .true. - ! this means harvest the whole cohort area - harvest_rate = 1._r8 - - else if (hlm_use_lu_harvest == itrue .and. hlm_harvest_units == hlm_harvest_area_fraction) then - ! We are harvesting based on areal fraction, not carbon/biomass terms. - ! 1=use area fraction from hlm - ! combine forest and non-forest fracs and then apply: - ! primary and secondary area fractions to the logging rates, which are fates parameters - - ! 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 - ! 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) - - ! 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, secondary_age, harvest_rate) + ! The transition_landuse_from_off_to_on is for handling the special case of the first timestep after leaving potential + ! vegetation mode. In this case, all prior historical land-use, including harvest, needs to be applied on that first day. + ! So logging rates on that day are what is required to deforest exactly the amount of primary lands that will give the + ! amount of secondary lands dictated by the land use state vector for that year, rather than whatever the continuous + ! logging rate for that year is supposed to be according to the land use transition matrix. + if (.not. currentSite%transition_landuse_from_off_to_on) then + + ! Check if the secondaryland exceeds the minimum if in landuse mode + site_secondaryland_first_exceeding_min = .false. + if (hlm_use_luh .eq. itrue) then + call GetLUHStatedata(bc_in, state_vector) + site_secondaryland_first_exceeding_min = (state_vector(secondaryland) .gt. currentSite%min_allowed_landuse_fraction) & + .and. (.not. currentSite%landuse_vector_gt_min(secondaryland)) + end if + + ! if the total intended area of secondary lands are less than what we can consider without having too-small patches, + ! or if that was the case until just now, then there is special logic + if (site_secondaryland_first_exceeding_min) then + if ( patch_land_use_label .eq. primaryland) then + harvest_rate = state_vector(secondaryland) / state_vector(primaryland) + write(fates_log(), *) 'applying state_vector(secondaryland) to plants.', pft_i + else + harvest_rate = 0._r8 + endif ! For area-based harvest, harvest_tag shall always be 2 (not applicable). harvest_tag = 2 cur_harvest_tag = 2 + elseif (logging_time) then + + ! Pass logging rates to cohort level + + if (hlm_use_lu_harvest == ifalse) then + ! 0=use fates logging parameters directly when logging_time == .true. + ! this means harvest the whole cohort area + harvest_rate = 1._r8 + + else if (hlm_use_lu_harvest == itrue .and. hlm_harvest_units == hlm_harvest_area_fraction) then + ! We are harvesting based on areal fraction, not carbon/biomass terms. + ! 1=use area fraction from hlm + ! combine forest and non-forest fracs and then apply: + ! primary and secondary area fractions to the logging rates, which are fates parameters + + ! 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 + ! 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) + + 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) + + ! For area-based harvest, harvest_tag shall always be 2 (not applicable). + harvest_tag = 2 + cur_harvest_tag = 2 + + if (fates_global_verbose()) then + write(fates_log(), *) 'Successfully Read Harvest Rate from HLM.', hlm_harvest_rates(:), harvest_rate + end if - if (fates_global_verbose()) then - write(fates_log(), *) 'Successfully Read Harvest Rate from HLM.', hlm_harvest_rates(:), harvest_rate - end if + else if (hlm_use_lu_harvest == itrue .and. hlm_harvest_units == hlm_harvest_carbon) then + ! 2=use carbon from hlm + ! shall call another subroutine, which transfers biomass/carbon into fraction - else if (hlm_use_lu_harvest == itrue .and. hlm_harvest_units == hlm_harvest_carbon) then - ! 2=use carbon from hlm - ! shall call another subroutine, which transfers biomass/carbon into fraction + call get_harvest_rate_carbon (patch_land_use_label, hlm_harvest_catnames, & + hlm_harvest_rates, secondary_age, harvestable_forest_c, & + harvest_rate, harvest_tag, cur_harvest_tag) - call get_harvest_rate_carbon (patch_land_use_label, hlm_harvest_catnames, & - hlm_harvest_rates, secondary_age, harvestable_forest_c, & - harvest_rate, harvest_tag, cur_harvest_tag) + if (fates_global_verbose()) then + write(fates_log(), *) 'Successfully Read Harvest Rate from HLM.', hlm_harvest_rates(:), harvest_rate, harvestable_forest_c + end if - if (fates_global_verbose()) then - write(fates_log(), *) 'Successfully Read Harvest Rate from HLM.', hlm_harvest_rates(:), harvest_rate, harvestable_forest_c - end if - + endif + + else + harvest_rate = 0._r8 + ! For area-based harvest, harvest_tag shall always be 2 (not applicable). + harvest_tag = 2 + cur_harvest_tag = 2 endif ! transfer of area to secondary land is based on overall area affected, not just logged crown area @@ -296,7 +344,7 @@ subroutine LoggingMortality_frac( pft_i, dbh, canopy_layer, lmort_direct, & if (cur_harvest_tag == 0) then ! direct logging rates, based on dbh min and max criteria if (dbh >= logging_dbhmin .and. .not. & - ((logging_dbhmax < fates_check_param_set) .and. (dbh >= logging_dbhmax )) ) then + ((logging_dbhmax < fates_check_param_set) .and. (dbh >= logging_dbhmax )) ) then ! the logic of the above line is a bit unintuitive but allows turning off the dbhmax comparison entirely. ! since there is an .and. .not. after the first conditional, the dbh:dbhmax comparison needs to be ! the opposite of what would otherwise be expected... @@ -305,7 +353,7 @@ subroutine LoggingMortality_frac( pft_i, dbh, canopy_layer, lmort_direct, & lmort_direct = 0.0_r8 end if else - lmort_direct = 0.0_r8 + lmort_direct = 0.0_r8 end if ! infrastructure (roads, skid trails, etc) mortality rates @@ -335,13 +383,20 @@ subroutine LoggingMortality_frac( pft_i, dbh, canopy_layer, lmort_direct, & else l_degrad = 0._r8 endif - - else - lmort_direct = 0.0_r8 + + 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 - end if + if(prt_params%woody(pft_i) == itrue)then + lmort_direct = harvest_rate + else if (canopy_layer .eq. 1) then + l_degrad = harvest_rate + endif + endif end subroutine LoggingMortality_frac @@ -349,13 +404,13 @@ end subroutine LoggingMortality_frac ! ============================================================================ subroutine get_harvest_rate_area (patch_land_use_label, hlm_harvest_catnames, hlm_harvest_rates, & - frac_site_primary, secondary_age, harvest_rate) + frac_site_primary, frac_site_secondary, secondary_young_fraction, secondary_age, harvest_rate) ! ------------------------------------------------------------------------------------------- ! ! DESCRIPTION: - ! get the area-based harvest rates based on info passed to FATES from the bioundary conditions in. + ! get the area-based harvest rates based on info passed to FATES from the boundary conditions in. ! assumes logging_time == true ! Arguments @@ -364,6 +419,8 @@ subroutine get_harvest_rate_area (patch_land_use_label, hlm_harvest_catnames, hl 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) :: secondary_young_fraction ! what fraction of secondary land is young secondary land real(r8), intent(out) :: harvest_rate ! Local Variables @@ -396,19 +453,26 @@ subroutine get_harvest_rate_area (patch_land_use_label, hlm_harvest_catnames, hl ! Normalize by site-level primary or secondary forest fraction ! 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. if (patch_land_use_label .eq. primaryland) then if (frac_site_primary .gt. fates_tiny) then - harvest_rate = min((harvest_rate / frac_site_primary),frac_site_primary) + harvest_rate = min((harvest_rate / frac_site_primary),1._r8) else harvest_rate = 0._r8 endif - else - if ((1._r8-frac_site_primary) .gt. fates_tiny) then - harvest_rate = min((harvest_rate / (1._r8-frac_site_primary)),& - (1._r8-frac_site_primary)) + 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 (secondary_age .lt. secondary_age_threshold) then + harvest_rate = min((harvest_rate / (frac_site_secondary * secondary_young_fraction)), 1._r8) + else + harvest_rate = min((harvest_rate / (frac_site_secondary * (1._r8 - secondary_young_fraction))), 1._r8) + endif else harvest_rate = 0._r8 endif + else + harvest_rate = 0._r8 endif ! calculate today's harvest rate @@ -983,7 +1047,7 @@ subroutine logging_litter_fluxes(currentSite, currentPatch, newPatch, patch_site ag_wood * logging_export_frac ! This is for checking the total mass balance [kg/site/day] - site_mass%wood_product = site_mass%wood_product + & + site_mass%wood_product_harvest(pft) = site_mass%wood_product_harvest(pft) + & ag_wood * logging_export_frac new_litt%ag_cwd(ncwd) = new_litt%ag_cwd(ncwd) + ag_wood * & @@ -1106,13 +1170,13 @@ subroutine UpdateHarvestC(currentSite,bc_out) use PRTGenericMod , only : element_pos use PRTGenericMod , only : carbon12_element use FatesInterfaceTypesMod , only : bc_out_type - use EDParamsMod , only : pprodharv10_forest_mean ! Arguments type(ed_site_type), intent(inout), target :: currentSite ! site structure type(bc_out_type), intent(inout) :: bc_out integer :: icode + integer :: i_pft real(r8) :: unit_trans_factor @@ -1123,13 +1187,26 @@ subroutine UpdateHarvestC(currentSite,bc_out) ! Calculate the unit transfer factor (from kgC m-2 day-1 to gC m-2 s-1) unit_trans_factor = g_per_kg * days_per_sec - bc_out%hrv_deadstemc_to_prod10c = bc_out%hrv_deadstemc_to_prod10c + & - currentSite%mass_balance(element_pos(carbon12_element))%wood_product * & - AREA_INV * pprodharv10_forest_mean * unit_trans_factor - bc_out%hrv_deadstemc_to_prod100c = bc_out%hrv_deadstemc_to_prod100c + & - currentSite%mass_balance(element_pos(carbon12_element))%wood_product * & - AREA_INV * (1._r8 - pprodharv10_forest_mean) * unit_trans_factor - + ! harvest-associated wood product pools + do i_pft = 1,numpft + bc_out%hrv_deadstemc_to_prod10c = bc_out%hrv_deadstemc_to_prod10c + & + currentSite%mass_balance(element_pos(carbon12_element))%wood_product_harvest(i_pft) * & + AREA_INV * EDPftvarcon_inst%harvest_pprod10(i_pft) * unit_trans_factor + bc_out%hrv_deadstemc_to_prod100c = bc_out%hrv_deadstemc_to_prod100c + & + currentSite%mass_balance(element_pos(carbon12_element))%wood_product_harvest(i_pft) * & + AREA_INV * (1._r8 - EDPftvarcon_inst%harvest_pprod10(i_pft)) * unit_trans_factor + end do + + ! land-use-change-associated wood product pools + do i_pft = 1,numpft + bc_out%hrv_deadstemc_to_prod10c = bc_out%hrv_deadstemc_to_prod10c + & + currentSite%mass_balance(element_pos(carbon12_element))%wood_product_landusechange(i_pft) * & + AREA_INV * EDPftvarcon_inst%landusechange_pprod10(i_pft) * unit_trans_factor + bc_out%hrv_deadstemc_to_prod100c = bc_out%hrv_deadstemc_to_prod100c + & + currentSite%mass_balance(element_pos(carbon12_element))%wood_product_landusechange(i_pft) * & + AREA_INV * (1._r8 - EDPftvarcon_inst%landusechange_pprod10(i_pft)) * unit_trans_factor + end do + return end subroutine UpdateHarvestC diff --git a/biogeochem/EDMortalityFunctionsMod.F90 b/biogeochem/EDMortalityFunctionsMod.F90 index 6abb19013b..2778f3c0b7 100644 --- a/biogeochem/EDMortalityFunctionsMod.F90 +++ b/biogeochem/EDMortalityFunctionsMod.F90 @@ -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, harvestable_forest_c, harvest_tag) + frac_site_primary, frac_site_secondary, harvestable_forest_c, harvest_tag) ! ! !DESCRIPTION: @@ -301,6 +301,7 @@ subroutine Mortality_Derivative( currentSite, currentCohort, bc_in, btran_ft, & 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) :: harvestable_forest_c(:) ! total carbon available for logging, kgC site-1 integer, intent(out) :: harvest_tag(:) ! tag to record the harvest status @@ -329,7 +330,7 @@ subroutine Mortality_Derivative( currentSite, currentCohort, bc_in, btran_ft, & !if trees are in the canopy, then their death is 'disturbance'. This probably needs a different terminology call mortality_rates(currentCohort,bc_in,btran_ft, mean_temp, & cmort,hmort,bmort,frmort, smort, asmort, dgmort) - call LoggingMortality_frac(ipft, currentCohort%dbh, currentCohort%canopy_layer, & + call LoggingMortality_frac(currentSite, bc_in, ipft, currentCohort%dbh, currentCohort%canopy_layer, & currentCohort%lmort_direct, & currentCohort%lmort_collateral, & currentCohort%lmort_infra, & @@ -339,7 +340,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, harvestable_forest_c, harvest_tag) + frac_site_primary, frac_site_secondary, harvestable_forest_c, harvest_tag) if (currentCohort%canopy_layer > 1)then ! Include understory logging mortality rates not associated with disturbance diff --git a/biogeochem/EDPatchDynamicsMod.F90 b/biogeochem/EDPatchDynamicsMod.F90 index 140c108d66..55f7ba1311 100644 --- a/biogeochem/EDPatchDynamicsMod.F90 +++ b/biogeochem/EDPatchDynamicsMod.F90 @@ -1,4 +1,3 @@ - module EDPatchDynamicsMod ! ============================================================================ ! Controls formation, creation, fusing and termination of patch level processes. @@ -43,6 +42,7 @@ module EDPatchDynamicsMod use FatesLitterMod , only : dl_sf use FatesConstantsMod , only : N_DIST_TYPES use EDTypesMod , only : AREA_INV + use EDTypesMod , only : dump_site use FatesConstantsMod , only : rsnbl_math_prec use FatesConstantsMod , only : fates_tiny use FatesConstantsMod , only : nocomp_bareground @@ -71,6 +71,7 @@ module EDPatchDynamicsMod use EDLoggingMortalityMod, only : get_harvest_rate_carbon use EDLoggingMortalityMod, only : get_harvestable_carbon use EDLoggingMortalityMod, only : get_harvest_debt + use FatesLandUseChangeMod, only : GetInitLanduseHarvestRate use EDParamsMod , only : fates_mortality_disturbance_fraction use FatesAllometryMod , only : carea_allom use FatesAllometryMod , only : set_root_fraction @@ -80,8 +81,11 @@ module EDPatchDynamicsMod use FatesConstantsMod , only : years_per_day use FatesConstantsMod , only : nearzero use FatesConstantsMod , only : primaryland, secondaryland, pastureland, rangeland, cropland + use FatesConstantsMod , only : nocomp_bareground_land use FatesConstantsMod , only : n_landuse_cats - use FatesLandUseChangeMod, only : get_landuse_transition_rates + use FatesLandUseChangeMod, only : GetLanduseTransitionRates + use FatesLandUseChangeMod, only : GetInitLanduseTransitionRates + use FatesLandUseChangeMod, only : GetLUHStatedata use FatesConstantsMod , only : fates_unset_r8 use FatesConstantsMod , only : fates_unset_int use FatesConstantsMod , only : hlm_harvest_carbon @@ -106,7 +110,7 @@ module EDPatchDynamicsMod use FatesRunningMeanMod, only : ema_sdlng_emerg_h2o, ema_sdlng_mort_par, ema_sdlng2sap_par use FatesRunningMeanMod, only : ema_24hr, fixed_24hr, ema_lpa, ema_longterm use FatesRadiationMemMod, only : num_swb - + ! CIME globals use shr_infnan_mod , only : nan => shr_infnan_nan, assignment(=) use shr_log_mod , only : errMsg => shr_log_errMsg @@ -123,7 +127,6 @@ module EDPatchDynamicsMod public :: check_patch_area public :: set_patchno private:: fuse_2_patches - public :: get_frac_site_primary character(len=*), parameter, private :: sourcefile = & __FILE__ @@ -204,21 +207,35 @@ subroutine disturbance_rates( site_in, bc_in) integer :: threshold_sizeclass integer :: i_dist integer :: h_index - real(r8) :: frac_site_primary real(r8) :: harvest_rate real(r8) :: tempsum real(r8) :: mean_temp real(r8) :: harvestable_forest_c(hlm_num_lu_harvest_cats) integer :: harvest_tag(hlm_num_lu_harvest_cats) - real(r8) :: landuse_transition_matrix(n_landuse_cats, n_landuse_cats) ! [m2/m2/day] real(r8) :: current_fates_landuse_state_vector(n_landuse_cats) ! [m2/m2] + real(r8) :: state_vector(n_landuse_cats) + real(r8), parameter :: max_daily_disturbance_rate = 0.999_r8 + logical :: site_secondaryland_first_exceeding_min + real(r8) :: secondary_young_fraction ! what fraction of secondary land is young secondary land !---------------------------------------------------------------------------------------------- ! Calculate Mortality Rates (these were previously calculated during growth derivatives) ! And the same rates in understory plants have already been applied to %dndt !---------------------------------------------------------------------------------------------- ! first calculate the fraction of the site that is primary land - call get_frac_site_primary(site_in, frac_site_primary) + current_fates_landuse_state_vector = site_in%get_current_landuse_statevector() + + ! and get the fraction of secondary land that is young secondary land + secondary_young_fraction = site_in%get_secondary_young_fraction() + + ! check status of transition_landuse_from_off_to_on flag, and do some error checking on it + if(site_in%transition_landuse_from_off_to_on) then + if (sum(current_fates_landuse_state_vector(secondaryland:cropland)) .gt. nearzero) then + write(fates_log(),*) 'flag for transition_landuse_from_off_to_on is set to true but site is not entirely primaryland' + write(fates_log(), *) current_fates_landuse_state_vector + call endrun(msg=errMsg(sourcefile, __LINE__)) + endif + endif ! get available biomass for harvest for all patches call get_harvestable_carbon(site_in, bc_in%site_area, bc_in%hlm_harvest_catnames, harvestable_forest_c) @@ -246,14 +263,16 @@ subroutine disturbance_rates( site_in, bc_in) currentCohort%asmort = asmort currentCohort%dgmort = dgmort - call LoggingMortality_frac(currentCohort%pft, currentCohort%dbh, currentCohort%canopy_layer, & + call LoggingMortality_frac(site_in, bc_in, currentCohort%pft, & + currentCohort%dbh, currentCohort%canopy_layer, & lmort_direct,lmort_collateral,lmort_infra,l_degrad,& bc_in%hlm_harvest_rates, & bc_in%hlm_harvest_catnames, & bc_in%hlm_harvest_units, & currentPatch%land_use_label, & currentPatch%age_since_anthro_disturbance, & - frac_site_primary, & + current_fates_landuse_state_vector(primaryland), & + current_fates_landuse_state_vector(secondaryland), & harvestable_forest_c, & harvest_tag) @@ -271,21 +290,17 @@ subroutine disturbance_rates( site_in, bc_in) call get_harvest_debt(site_in, bc_in, harvest_tag) if ( hlm_use_luh .eq. itrue ) then - call get_landuse_transition_rates(bc_in, landuse_transition_matrix) + if(.not. site_in%transition_landuse_from_off_to_on) then + call GetLanduseTransitionRates(bc_in, site_in%min_allowed_landuse_fraction, & + site_in%landuse_transition_matrix, site_in%landuse_vector_gt_min) + else + call GetInitLanduseTransitionRates(bc_in, site_in%min_allowed_landuse_fraction, & + site_in%landuse_transition_matrix, site_in%landuse_vector_gt_min) + endif else - landuse_transition_matrix(:,:) = 0._r8 + site_in%landuse_transition_matrix(:,:) = 0._r8 endif - ! calculate total area in each landuse category - current_fates_landuse_state_vector(:) = 0._r8 - currentPatch => site_in%oldest_patch - do while (associated(currentPatch)) - current_fates_landuse_state_vector(currentPatch%land_use_label) = & - current_fates_landuse_state_vector(currentPatch%land_use_label) + & - currentPatch%area/AREA - currentPatch => currentPatch%younger - end do - ! --------------------------------------------------------------------------------------------- ! Calculate Disturbance Rates based on the mortality rates just calculated ! --------------------------------------------------------------------------------------------- @@ -304,6 +319,14 @@ subroutine disturbance_rates( site_in, bc_in) currentPatch => currentPatch%younger end do + ! get some info needed to determine whether or not to apply land use change + site_secondaryland_first_exceeding_min = .false. + if (hlm_use_luh .eq. itrue) then + call GetLUHStatedata(bc_in, state_vector) + site_secondaryland_first_exceeding_min = (state_vector(secondaryland) .gt. site_in%min_allowed_landuse_fraction) & + .and. (.not. site_in%landuse_vector_gt_min(secondaryland)) + end if + currentPatch => site_in%oldest_patch do while (associated(currentPatch)) @@ -313,10 +336,18 @@ subroutine disturbance_rates( site_in, bc_in) dist_rate_ldist_notharvested = 0.0_r8 - ! Avoid this calculation to avoid NaN due to division by zero result if luh is not used - if (hlm_use_luh .eq. itrue) then + ! transition matrix has units of area transitioned per unit area of the whole gridcell per time; + ! need to change to area transitioned per unit area of that land-use type per time; + ! because the land use state vector sums to one minus area bareground, need to also divide by that + ! (or rather, multiply since it is in the denominator of the denominator) + ! Avoid this calculation to avoid NaN due to division by zero result if luh is not used or applying + ! to bare ground note that an alternative here might be to use what LUH thinks the state vector + ! should be instead of what the FATES state vector is, in order to not amplify small deviations + ! between the two... + if (hlm_use_luh .eq. itrue .and. currentPatch%land_use_label .gt. nocomp_bareground_land) then currentPatch%landuse_transition_rates(1:n_landuse_cats) = min(1._r8, & - landuse_transition_matrix(currentPatch%land_use_label,1:n_landuse_cats) / & + site_in%landuse_transition_matrix(currentPatch%land_use_label,1:n_landuse_cats) & + * (1._r8 - site_in%area_bareground) / & current_fates_landuse_state_vector(currentPatch%land_use_label)) else currentPatch%landuse_transition_rates = 0.0_r8 @@ -357,18 +388,37 @@ subroutine disturbance_rates( site_in, bc_in) ! for non-closed-canopy areas subject to logging, add an additional increment of area disturbed ! equivalent to the fraction logged to account for transfer of interstitial ground area to new secondary lands - if ( logging_time .and. & + if ( (logging_time .or. site_in%transition_landuse_from_off_to_on .or. site_secondaryland_first_exceeding_min) .and. & (currentPatch%area - currentPatch%total_canopy_area) .gt. fates_tiny ) then ! The canopy is NOT closed. - if(bc_in%hlm_harvest_units == hlm_harvest_carbon) then - call get_harvest_rate_carbon (currentPatch%land_use_label, bc_in%hlm_harvest_catnames, & - bc_in%hlm_harvest_rates, currentPatch%age_since_anthro_disturbance, harvestable_forest_c, & - harvest_rate, harvest_tag) + if (.not. site_in%transition_landuse_from_off_to_on) then + if(bc_in%hlm_harvest_units == hlm_harvest_carbon) then + call get_harvest_rate_carbon (currentPatch%land_use_label, bc_in%hlm_harvest_catnames, & + bc_in%hlm_harvest_rates, currentPatch%age_since_anthro_disturbance, harvestable_forest_c, & + 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, & + currentPatch%age_since_anthro_disturbance, harvest_rate) + end if + + ! if the total intended area of secondary lands are less than what we can consider + ! without having too-small patches, or if that was the case until just now, + ! then there is special logic + if (state_vector(secondaryland) .le. site_in%min_allowed_landuse_fraction) then + harvest_rate = 0._r8 + else if (currentPatch%land_use_label .eq. primaryland .and. .not. & + site_in%landuse_vector_gt_min(secondaryland)) then + harvest_rate = state_vector(secondaryland) / sum(state_vector(:)) + else + harvest_rate = 0._r8 + end if else - call get_harvest_rate_area (currentPatch%land_use_label, bc_in%hlm_harvest_catnames, & - bc_in%hlm_harvest_rates, frac_site_primary, currentPatch%age_since_anthro_disturbance, harvest_rate) - end if + call GetInitLanduseHarvestRate(bc_in, site_in%min_allowed_landuse_fraction, & + harvest_rate, site_in%landuse_vector_gt_min) + endif currentPatch%disturbance_rates(dtype_ilog) = currentPatch%disturbance_rates(dtype_ilog) + & (currentPatch%area - currentPatch%total_canopy_area) * harvest_rate / currentPatch%area @@ -399,20 +449,42 @@ subroutine disturbance_rates( site_in, bc_in) call FatesWarn(msg,index=2) endif - ! if the sum of all disturbance rates is such that they will exceed total patch area on this day, then reduce them all proportionally. - if ( (sum(currentPatch%disturbance_rates(:)) + sum(currentPatch%landuse_transition_rates(1:n_landuse_cats))) .gt. 1.0_r8 ) then + ! if the sum of all disturbance rates is such that they will exceed total patch area on this day, + ! then reduce them all proportionally. + + if ( (sum(currentPatch%disturbance_rates(:)) + sum(currentPatch%landuse_transition_rates(1:n_landuse_cats))) .gt. & + max_daily_disturbance_rate ) then tempsum = sum(currentPatch%disturbance_rates(:)) + sum(currentPatch%landuse_transition_rates(1:n_landuse_cats)) do i_dist = 1,N_DIST_TYPES - currentPatch%disturbance_rates(i_dist) = currentPatch%disturbance_rates(i_dist) / tempsum + currentPatch%disturbance_rates(i_dist) = max_daily_disturbance_rate * currentPatch%disturbance_rates(i_dist) & + / tempsum end do do i_dist = 1,n_landuse_cats - currentPatch%landuse_transition_rates(i_dist) = currentPatch%landuse_transition_rates(i_dist) / tempsum + currentPatch%landuse_transition_rates(i_dist) = max_daily_disturbance_rate * & + currentPatch%landuse_transition_rates(i_dist) / tempsum end do endif currentPatch => currentPatch%younger - enddo !patch loop + enddo !patch loop + + ! if the area of secondary land has just exceeded the minimum below which we ignore things, + ! set the flag to keep track of that. + if ( (state_vector(secondaryland) .gt. site_in%min_allowed_landuse_fraction) .and. & + (.not. site_in%landuse_vector_gt_min(secondaryland)) ) then + site_in%landuse_vector_gt_min(secondaryland) = .true. + write(fates_log(),*) 'setting site_in%landuse_vector_gt_min(secondaryland) = .true.' + if (debug) then + currentPatch => site_in%oldest_patch + do while (associated(currentPatch)) + write(fates_log(),*) 'cpatch area, LU, distrates(ilog): ', currentPatch%area, currentPatch%land_use_label, & + currentPatch%nocomp_pft_label, currentPatch%disturbance_rates(dtype_ilog), & + currentPatch%area - currentPatch%total_canopy_area + currentPatch => currentPatch%younger + end do + end if + end if end subroutine disturbance_rates @@ -440,8 +512,7 @@ subroutine spawn_patches( currentSite, bc_in) use EDParamsMod , only : ED_val_understorey_death, logging_coll_under_frac use EDCohortDynamicsMod , only : terminate_cohorts use FatesConstantsMod , only : rsnbl_math_prec - use FatesLandUseChangeMod, only : get_landuse_transition_rates - use FatesLandUseChangeMod, only : get_landusechange_rules + use FatesLandUseChangeMod, only : GetLanduseChangeRules ! ! !ARGUMENTS: type (ed_site_type), intent(inout) :: currentSite @@ -482,7 +553,20 @@ subroutine spawn_patches( currentSite, bc_in) real(r8) :: disturbance_rate ! rate of disturbance being resolved [fraction of patch area / day] real(r8) :: oldarea ! old patch area prior to disturbance logical :: clearing_matrix(n_landuse_cats,n_landuse_cats) ! do we clear vegetation when transferring from one LU type to another? - + type (fates_patch_type) , pointer :: buffer_patch, temp_patch, copyPatch, previousPatch + real(r8) :: nocomp_pft_area_vector(numpft) + real(r8) :: nocomp_pft_area_vector_filled(numpft) + real(r8) :: nocomp_pft_area_vector_alt(numpft) + real(r8) :: newp_area_buffer_frac(numpft) + real(r8) :: newp_area_vector(numpft) + real(r8) :: max_val + integer :: i_land_use_label + integer :: i_pft + real(r8) :: newp_area, area_to_keep, fraction_to_keep + logical :: buffer_patch_in_linked_list + integer :: n_pfts_by_landuse + integer :: which_pft_allowed + logical :: buffer_patch_used !--------------------------------------------------------------------- storesmallcohort => null() ! storage of the smallest cohort for insertion routine @@ -500,8 +584,8 @@ subroutine spawn_patches( currentSite, bc_in) currentSite%disturbance_rates(:,:,:) = 0._r8 ! get rules for vegetation clearing during land use change - call get_landusechange_rules(clearing_matrix) - + call GetLanduseChangeRules(clearing_matrix) + ! in the nocomp cases, since every patch has a PFT identity, it can only receive patch area from patches ! that have the same identity. In order to allow this, we have this very high level loop over nocomp PFTs ! and only do the disturbance for any patches that have that nocomp PFT identity. @@ -511,7 +595,8 @@ subroutine spawn_patches( currentSite, bc_in) ! we want at the second-outermost loop to go through all disturbance types, because we resolve each of these separately disturbance_type_loop: do i_disturbance_type = 1,N_DIST_TYPES - ! the next loop level is to go through patches that have a specific land-use type. the reason to do this is because the combination of + ! the next loop level is to go through patches that have a specific land-use type. the reason to do this + ! is because the combination of ! disturbance type and donor land-use type uniquly define the land-use type of the receiver patch. landuse_donortype_loop: do i_donorpatch_landuse_type = 1, n_landuse_cats @@ -520,7 +605,8 @@ subroutine spawn_patches( currentSite, bc_in) ! for fire and treefall disturbance, receiver land-use type is whatever the donor land-use type is. ! for logging disturbance, receiver land-use type is always secondary lands - ! for land-use-change disturbance, we need to loop over all possible transition types for land-use-change from the current land-use type. + ! for land-use-change disturbance, we need to loop over all possible transition types for land-use-change from + ! the current land-use type. select case(i_disturbance_type) case(dtype_ifire) @@ -533,7 +619,8 @@ subroutine spawn_patches( currentSite, bc_in) start_receiver_lulabel = secondaryland end_receiver_lulabel = secondaryland case(dtype_ilandusechange) - start_receiver_lulabel = 1 ! this could actually maybe be 2, as primaryland column of matrix should all be zeros, but leave as 1 for now + start_receiver_lulabel = 1 ! this could actually maybe be 2, as primaryland column of matrix should + ! all be zeros, but leave as 1 for now end_receiver_lulabel = n_landuse_cats case default write(fates_log(),*) 'unknown disturbance mode?' @@ -543,19 +630,24 @@ subroutine spawn_patches( currentSite, bc_in) ! next loop level is the set of possible receiver patch land use types. ! for disturbance types other than land use change, this is sort of a dummy loop, per the above logic. - landusechange_receiverpatchlabel_loop: do i_landusechange_receiverpatchlabel = start_receiver_lulabel, end_receiver_lulabel + landusechange_receiverpatchlabel_loop: do i_landusechange_receiverpatchlabel = start_receiver_lulabel, & + end_receiver_lulabel ! now we want to begin resolving all of the disturbance given the above categorical criteria of: - ! nocomp-PFT, disturbance type, donor patch land use label, and receiver patch land use label. All of the disturbed area that meets these - ! criteria (if any) will be put into a new patch whose area and properties are taken from one or more donor patches. + ! nocomp-PFT, disturbance type, donor patch land use label, and receiver patch land use label. + ! All of the disturbed area that meets these criteria (if any) will be put into a new patch whose area and + ! properties are taken from one or more donor patches. - ! calculate area of disturbed land that meets the above criteria, in this timestep, by summing contributions from each existing patch. + ! calculate area of disturbed land that meets the above criteria, in this timestep, by summing contributions + ! from each existing patch. currentPatch => currentSite%youngest_patch - ! this variable site_areadis holds all the newly disturbed area from all patches for all disturbance being resolved now. + ! this variable site_areadis holds all the newly disturbed area from all patches for all disturbance being + ! resolved now. site_areadis = 0.0_r8 - ! loop over all patches to figure out the total patch area generated as a result of all disturbance being resolved now. + ! loop over all patches to figure out the total patch area generated as a result of all disturbance being + ! resolved now. patchloop_areadis: do while(associated(currentPatch)) cp_nocomp_matches_1_if: if ( hlm_use_nocomp .eq. ifalse .or. & @@ -678,14 +770,21 @@ subroutine spawn_patches( currentSite, bc_in) currentPatch%burnt_frac_litter(:) = 0._r8 end if + call CopyPatchMeansTimers(currentPatch, newPatch) + call TransLitterNewPatch( currentSite, currentPatch, newPatch, patch_site_areadis) ! Transfer in litter fluxes from plants in various contexts of death and destruction - select case(i_disturbance_type) case (dtype_ilog) call logging_litter_fluxes(currentSite, currentPatch, & newPatch, patch_site_areadis,bc_in) + + ! if transitioning from primary to secondary, then may need to change nocomp pft, + ! so tag as having transitioned LU + if ( i_disturbance_type .eq. dtype_ilog .and. i_donorpatch_landuse_type .eq. primaryland) then + newPatch%changed_landuse_this_ts = .true. + end if case (dtype_ifire) call fire_litter_fluxes(currentSite, currentPatch, & newPatch, patch_site_areadis,bc_in) @@ -696,33 +795,15 @@ subroutine spawn_patches( currentSite, bc_in) call landusechange_litter_fluxes(currentSite, currentPatch, & newPatch, patch_site_areadis,bc_in, & clearing_matrix(i_donorpatch_landuse_type,i_landusechange_receiverpatchlabel)) + + ! if land use change, then may need to change nocomp pft, so tag as having transitioned LU + newPatch%changed_landuse_this_ts = .true. case default write(fates_log(),*) 'unknown disturbance mode?' write(fates_log(),*) 'i_disturbance_type: ',i_disturbance_type call endrun(msg=errMsg(sourcefile, __LINE__)) end select - - ! Copy any means or timers from the original patch to the new patch - ! These values will inherit all info from the original patch - ! -------------------------------------------------------------------------- - call newPatch%tveg24%CopyFromDonor(currentPatch%tveg24) - call newPatch%tveg_lpa%CopyFromDonor(currentPatch%tveg_lpa) - call newPatch%tveg_longterm%CopyFromDonor(currentPatch%tveg_longterm) - - - if ( regeneration_model == TRS_regeneration ) then - call newPatch%seedling_layer_par24%CopyFromDonor(currentPatch%seedling_layer_par24) - call newPatch%sdlng_mort_par%CopyFromDonor(currentPatch%sdlng_mort_par) - call newPatch%sdlng2sap_par%CopyFromDonor(currentPatch%sdlng2sap_par) - do pft = 1,numpft - call newPatch%sdlng_emerg_smp(pft)%p%CopyFromDonor(currentPatch%sdlng_emerg_smp(pft)%p) - call newPatch%sdlng_mdd(pft)%p%CopyFromDonor(currentPatch%sdlng_mdd(pft)%p) - enddo - end if - - call newPatch%tveg_longterm%CopyFromDonor(currentPatch%tveg_longterm) - ! -------------------------------------------------------------------------- ! The newly formed patch from disturbance (newPatch), has now been given ! some litter from dead plants and pre-existing litter from the donor patches. @@ -766,7 +847,8 @@ subroutine spawn_patches( currentSite, bc_in) store_c = currentCohort%prt%GetState(store_organ, carbon12_element) total_c = sapw_c + struct_c + leaf_c + fnrt_c + store_c - ! survivorship of plants in both the disturbed and undisturbed cohorts depends on what type of disturbance is happening. + ! survivorship of plants in both the disturbed and undisturbed cohorts depends on what type of + ! disturbance is happening. disttype_case: select case(i_disturbance_type) @@ -1190,7 +1272,7 @@ subroutine spawn_patches( currentSite, bc_in) newPatch%shortest => nc nc%shorter => null() endif - !nc%patchptr => new_patch + call insert_cohort(newPatch, nc, newPatch%tallest, newPatch%shortest, & tnull, snull, storebigcohort, storesmallcohort) @@ -1281,6 +1363,296 @@ subroutine spawn_patches( currentSite, bc_in) end do nocomp_pft_loop + nocomp_and_luh_if: if ( hlm_use_nocomp .eq. itrue .and. hlm_use_luh .eq. itrue ) then + ! disturbance has just happened, and now the nocomp PFT identities of the newly-disturbed patches + ! need to be remapped to those associated with the new land use type. + + ! logic: loop over land use types. figure out the nocomp PFT fractions for all newly-disturbed patches that have become that land use type. + ! if the + + lu_loop: do i_land_use_label = n_landuse_cats, 1, -1 + + nocomp_pft_area_vector(:) = 0._r8 + nocomp_pft_area_vector_filled(:) = 0._r8 + + currentPatch => currentSite%oldest_patch + do while(associated(currentPatch)) + if (currentPatch%changed_landuse_this_ts .and. currentPatch%land_use_label .eq. i_land_use_label) then + nocomp_pft_area_vector(currentPatch%nocomp_pft_label) = nocomp_pft_area_vector(currentPatch%nocomp_pft_label) + currentPatch%area + copyPatch => currentPatch + end if + currentPatch => currentPatch%younger + end do + + ! figure out how may PFTs on each land use type. if only 1, then the next calculation is much simpler: we just need to know which PFT is allowed. + n_pfts_by_landuse = 0 + do i_pft = 1,numpft + if ( currentSite%area_pft(i_pft,i_land_use_label) .gt. nearzero) then + n_pfts_by_landuse = n_pfts_by_landuse + 1 + which_pft_allowed = i_pft + end if + end do + if ( n_pfts_by_landuse .ne. 1) then + which_pft_allowed = fates_unset_int + endif + + patch_area_to_reallocate_if: if ( sum(nocomp_pft_area_vector(:)) .gt. nearzero ) then + more_than_1_pft_to_handle_if: if ( n_pfts_by_landuse .ne. 1 ) then + ! create buffer patch to put all of the pieces carved off of other patches + allocate(buffer_patch) + + call buffer_patch%Create(0._r8, 0._r8, i_land_use_label, 0, & + num_swb, numpft, currentSite%nlevsoil, hlm_current_tod, & + regeneration_model) + + ! Initialize the litter pools to zero + do el=1,num_elements + call buffer_patch%litter(el)%InitConditions(init_leaf_fines=0._r8, & + init_root_fines=0._r8, & + init_ag_cwd=0._r8, & + init_bg_cwd=0._r8, & + init_seed=0._r8, & + init_seed_germ=0._r8) + end do + buffer_patch%tallest => null() + buffer_patch%shortest => null() + + call CopyPatchMeansTimers(copyPatch, buffer_patch) + + ! make a note that this buffer patch has not been put into the linked list + buffer_patch_in_linked_list = .false. + buffer_patch_used = .false. + + currentPatch => currentSite%oldest_patch + do while(associated(currentPatch)) + if (currentPatch%changed_landuse_this_ts .and. currentPatch%land_use_label .eq. i_land_use_label) then + + ! Calculate the areas to be given to potentially give to the buffer patch and those to keep in the current patch + area_to_keep = currentSite%area_pft(currentPatch%nocomp_pft_label,i_land_use_label) * sum(nocomp_pft_area_vector(:)) - & + nocomp_pft_area_vector_filled(currentPatch%nocomp_pft_label) + newp_area = currentPatch%area - area_to_keep + fraction_to_keep = area_to_keep / currentPatch%area + + if (fraction_to_keep .le. nearzero .or. area_to_keep .lt. rsnbl_math_prec) then + ! we don't want any patch area with this PFT identity at all anymore. Fuse it into the buffer patch. + + currentPatch%nocomp_pft_label = 0 + if (associated(currentPatch%older)) then + previousPatch => currentPatch%older + else + previousPatch => currentPatch + endif + + call fuse_2_patches(currentSite, currentPatch, buffer_patch) + currentPatch => previousPatch + + buffer_patch_used = .true. + + elseif ( area_to_keep .ge. rsnbl_math_prec .and. newp_area .ge. rsnbl_math_prec) then + ! we have more patch are of this PFT than we want, but we do want to keep some of it. + ! we want to split the patch into two here. leave one patch as-is, and put the rest into the buffer patch. + + allocate(temp_patch) + + call split_patch(currentSite, currentPatch, temp_patch, fraction_to_keep, newp_area) + ! + temp_patch%nocomp_pft_label = 0 + + call fuse_2_patches(currentSite, temp_patch, buffer_patch) + ! + nocomp_pft_area_vector_filled(currentPatch%nocomp_pft_label) = & + nocomp_pft_area_vector_filled(currentPatch%nocomp_pft_label) + currentPatch%area + + currentPatch%changed_landuse_this_ts = .false. + + buffer_patch_used = .true. + else + ! we want to keep all of this patch (and possibly more) + + nocomp_pft_area_vector_filled(currentPatch%nocomp_pft_label) = & + nocomp_pft_area_vector_filled(currentPatch%nocomp_pft_label) + currentPatch%area + currentPatch%changed_landuse_this_ts = .false. + + endif + end if + + currentPatch => currentPatch%younger + end do + + buffer_patch_used_if: if ( buffer_patch_used ) then + ! at this point, lets check that the total patch area remaining to be relabelled equals what we think that it is. + if (abs(sum(nocomp_pft_area_vector(:) - nocomp_pft_area_vector_filled(:)) - buffer_patch%area) .gt. rsnbl_math_prec) then + write(fates_log(),*) 'midway through patch reallocation and things are already not adding up.', i_land_use_label + write(fates_log(),*) currentSite%area_pft(:,i_land_use_label) + write(fates_log(),*) '-----' + write(fates_log(),*) nocomp_pft_area_vector_filled + write(fates_log(),*) '-----' + write(fates_log(),*) nocomp_pft_area_vector + write(fates_log(),*) '-----' + write(fates_log(),*) buffer_patch%area, buffer_patch%land_use_label, buffer_patch%nocomp_pft_label + write(fates_log(),*) sum(nocomp_pft_area_vector(:)), sum(nocomp_pft_area_vector_filled(:)), buffer_patch%area + currentPatch => currentSite%oldest_patch + do while(associated(currentPatch)) + write(fates_log(),*) currentPatch%area, currentPatch%land_use_label, currentPatch%nocomp_pft_label + currentPatch => currentPatch%younger + end do + call dump_site(currentSite) + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + + ! It's possible that we only need to move all of the buffer into one patch, so first determine what the new patch areas look + ! like and compare to the buffer patch area + newp_area_vector(:)= (currentSite%area_pft(:,i_land_use_label) * sum(nocomp_pft_area_vector(:))) - nocomp_pft_area_vector_filled(:) + newp_area_buffer_frac(:) = newp_area_vector(:) / buffer_patch%area + + ! Find the maximum value of the vector + max_val = maxval(newp_area_buffer_frac) + + ! If the max value is the only value in the array then loop through the array to find the max value pft index and insert buffer + if (abs(sum(newp_area_buffer_frac(:)) - max_val) .le. nearzero) then + i_pft = 1 + do while(.not. buffer_patch_in_linked_list) + if (abs(newp_area_buffer_frac(i_pft) - max_val) .le. nearzero) then + + ! give the buffer patch the intended nocomp PFT label + buffer_patch%nocomp_pft_label = i_pft + + ! track that we have added this patch area + nocomp_pft_area_vector_filled(i_pft) = nocomp_pft_area_vector_filled(i_pft) + buffer_patch%area + + ! put the buffer patch directly into the linked list + call InsertPatch(currentSite, buffer_patch) + + ! Set flag to skip the next pft loop + buffer_patch_in_linked_list = .true. + end if + i_pft = i_pft + 1 + end do + end if + + ! Now we need to loop through the nocomp PFTs, and split the buffer patch into a set of patches to put back in the linked list + ! if not already done so above + nocomp_pft_loop_2: do i_pft = 1, numpft + + ! Check the area fraction to makes sure that this pft should have area. Also make sure that the buffer patch hasn't been + ! added to the linked list already + if ( currentSite%area_pft(i_pft,i_land_use_label) .gt. nearzero .and. .not. buffer_patch_in_linked_list) then + + ! Slightly complicated way of making sure that the same pfts are subtracted from each other which may help to avoid precision + ! errors due to differencing between very large and very small areas + nocomp_pft_area_vector_alt(:) = nocomp_pft_area_vector(:) + nocomp_pft_area_vector_alt(i_pft) = 0._r8 + newp_area = (currentSite%area_pft(i_pft,i_land_use_label) * nocomp_pft_area_vector(i_pft)) - nocomp_pft_area_vector_filled(i_pft) + newp_area = newp_area + sum(currentSite%area_pft(i_pft,i_land_use_label)*nocomp_pft_area_vector_alt(:)) + + ! Compute area and fraction to keep in buffer + area_to_keep = buffer_patch%area - newp_area + fraction_to_keep = area_to_keep / buffer_patch%area + + ! only bother doing this if the new new patch area needed is greater than some tiny amount + if ( newp_area .gt. rsnbl_math_prec * 0.01_r8) then + + if (area_to_keep .gt. rsnbl_math_prec) then + + ! split buffer patch in two, keeping the smaller buffer patch to put into new patches + allocate(temp_patch) + + call split_patch(currentSite, buffer_patch, temp_patch, fraction_to_keep, newp_area) + + ! give the new patch the intended nocomp PFT label + temp_patch%nocomp_pft_label = i_pft + + ! track that we have added this patch area + nocomp_pft_area_vector_filled(i_pft) = nocomp_pft_area_vector_filled(i_pft) + temp_patch%area + + ! put the new patch into the linked list + call InsertPatch(currentSite, temp_patch) + + else + ! give the buffer patch the intended nocomp PFT label + buffer_patch%nocomp_pft_label = i_pft + + ! track that we have added this patch area + nocomp_pft_area_vector_filled(i_pft) = nocomp_pft_area_vector_filled(i_pft) + buffer_patch%area + + ! put the buffer patch directly into the linked list + call InsertPatch(currentSite, buffer_patch) + + buffer_patch_in_linked_list = .true. + + end if + end if + end if + end do nocomp_pft_loop_2 + + ! now we want to make sure that either the buffer_patch has zero area (presumably it was never used), + ! in which case it should be deallocated, or else it does have area but it has been put into the site + ! linked list. if either of those, that means everything worked properly, if not, then something has gone wrong. + if ( .not. buffer_patch_in_linked_list) then + if (buffer_patch%area .lt. rsnbl_math_prec) then + ! here we need to deallocate the buffer patch so that we don't get a memory leak. + call buffer_patch%FreeMemory(regeneration_model, numpft) + deallocate(buffer_patch, stat=istat, errmsg=smsg) + if (istat/=0) then + write(fates_log(),*) 'dealloc: fail on deallocate(dp):'//trim(smsg) + call endrun(msg=errMsg(sourcefile, __LINE__)) + endif + else + write(fates_log(),*) 'Buffer patch still has area and it wasnt put into the linked list' + write(fates_log(),*) 'buffer_patch%area', buffer_patch%area + write(fates_log(),*) sum(nocomp_pft_area_vector_filled(:)), sum(nocomp_pft_area_vector(:)) + write(fates_log(),*) sum(nocomp_pft_area_vector_filled(:) - nocomp_pft_area_vector(:)) + + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + end if + else + ! buffer patch was never even used. deallocate. + call buffer_patch%FreeMemory(regeneration_model, numpft) + deallocate(buffer_patch, stat=istat, errmsg=smsg) + if (istat/=0) then + write(fates_log(),*) 'dealloc: fail on deallocate(dp):'//trim(smsg) + call endrun(msg=errMsg(sourcefile, __LINE__)) + endif + end if buffer_patch_used_if + + ! check that the area we have added is the same as the area we have taken away. if not, crash. + if ( abs(sum(nocomp_pft_area_vector_filled(:) - nocomp_pft_area_vector(:))) .gt. rsnbl_math_prec) then + write(fates_log(),*) 'patch reallocation logic doesnt add up. difference is: ', sum(nocomp_pft_area_vector_filled(:) - nocomp_pft_area_vector(:)) + write(fates_log(),*) nocomp_pft_area_vector_filled + write(fates_log(),*) nocomp_pft_area_vector + write(fates_log(),*) i_land_use_label + currentPatch => currentSite%oldest_patch + do while(associated(currentPatch)) + write(fates_log(),*) currentPatch%area, currentPatch%land_use_label, currentPatch%nocomp_pft_label + currentPatch => currentPatch%younger + end do + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + else + ! if there is only one PFT allowed on this land use type, then all we need to do is relabel all of the patches that just changed + ! land use type and let patch fusion take care of the rest. + currentPatch => currentSite%oldest_patch + do while(associated(currentPatch)) + if (currentPatch%changed_landuse_this_ts .and. currentPatch%land_use_label .eq. i_land_use_label) then + currentPatch%nocomp_pft_label = which_pft_allowed + currentPatch%changed_landuse_this_ts = .false. + end if + currentPatch => currentPatch%younger + end do + endif more_than_1_pft_to_handle_if + end if patch_area_to_reallocate_if + call check_patch_area(currentSite) + end do lu_loop + else + ! if not using a configuration where the changed_landuse_this_ts is relevant, loop through all patches and reset it + currentPatch => currentSite%oldest_patch + do while(associated(currentPatch)) + currentPatch%changed_landuse_this_ts = .false. + currentPatch => currentPatch%younger + end do + endif nocomp_and_luh_if + !zero disturbance rate trackers on all patches currentPatch => currentSite%oldest_patch do while(associated(currentPatch)) @@ -1292,6 +1664,130 @@ subroutine spawn_patches( currentSite, bc_in) return end subroutine spawn_patches + ! ----------------------------------------------------------------------------------------- + + subroutine split_patch(currentSite, currentPatch, new_patch, fraction_to_keep, area_to_remove) + ! + ! !DESCRIPTION: + ! Split a patch into two patches that are identical except in their areas + ! + ! !ARGUMENTS: + type(ed_site_type),intent(inout) :: currentSite + type(fates_patch_type) , intent(inout), pointer :: currentPatch ! Donor Patch + type(fates_patch_type) , intent(inout), pointer :: new_patch ! New Patch + real(r8), intent(in) :: fraction_to_keep ! fraction of currentPatch to keep, the rest goes to newpatch + real(r8), intent(in), optional :: area_to_remove ! area of currentPatch to remove, the rest goes to newpatch + ! + ! !LOCAL VARIABLES: + integer :: el ! element loop index + type (fates_cohort_type), pointer :: nc + type (fates_cohort_type), pointer :: storesmallcohort + type (fates_cohort_type), pointer :: storebigcohort + type (fates_cohort_type), pointer :: currentCohort + integer :: tnull ! is there a tallest cohort? + integer :: snull ! is there a shortest cohort? + integer :: pft + real(r8) :: temp_area + + temp_area = 0._r8 + if (present(area_to_remove)) then + temp_area = area_to_remove + else + temp_area = currentPatch%area - (currentPatch%area * fraction_to_keep) + end if + + ! first we need to make the new patch + call new_patch%Create(0._r8, temp_area, & + currentPatch%land_use_label, currentPatch%nocomp_pft_label, & + num_swb, numpft, currentSite%nlevsoil, hlm_current_tod, & + regeneration_model) + + ! Initialize the litter pools to zero, these + ! pools will be populated shortly + do el=1,num_elements + call new_patch%litter(el)%InitConditions(init_leaf_fines=0._r8, & + init_root_fines=0._r8, & + init_ag_cwd=0._r8, & + init_bg_cwd=0._r8, & + init_seed=0._r8, & + init_seed_germ=0._r8) + end do + new_patch%tallest => null() + new_patch%shortest => null() + + call CopyPatchMeansTimers(currentPatch, new_patch) + + call TransLitterNewPatch( currentSite, currentPatch, new_patch, temp_area) + + currentPatch%burnt_frac_litter(:) = 0._r8 + + ! Next, we loop through the cohorts in the donor patch, copy them with + ! area modified number density into the new-patch, and apply survivorship. + ! ------------------------------------------------------------------------- + + currentCohort => currentPatch%shortest + do while(associated(currentCohort)) + + allocate(nc) + if(hlm_use_planthydro.eq.itrue) call InitHydrCohort(CurrentSite,nc) + + ! Initialize the PARTEH object and point to the + ! correct boundary condition fields + nc%prt => null() + call InitPRTObject(nc%prt) + call nc%InitPRTBoundaryConditions() + + ! (Keeping as an example) + ! Allocate running mean functions + !allocate(nc%tveg_lpa) + !call nc%tveg_lpa%InitRMean(ema_lpa,init_value=new_patch%tveg_lpa%GetMean()) + + call nc%ZeroValues() + + ! nc is the new cohort that goes in the disturbed patch (new_patch)... currentCohort + ! is the curent cohort that stays in the donor patch (currentPatch) + call currentCohort%Copy(nc) + + ! Number of members in the new patch + nc%n = currentCohort%n * (1._r8 - fraction_to_keep) + + ! loss of individuals from source patch due to area shrinking + currentCohort%n = currentCohort%n * fraction_to_keep + + storebigcohort => new_patch%tallest + storesmallcohort => new_patch%shortest + if(associated(new_patch%tallest))then + tnull = 0 + else + tnull = 1 + new_patch%tallest => nc + nc%taller => null() + endif + + if(associated(new_patch%shortest))then + snull = 0 + else + snull = 1 + new_patch%shortest => nc + nc%shorter => null() + endif + + call insert_cohort(new_patch, nc, new_patch%tallest, new_patch%shortest, & + tnull, snull, storebigcohort, storesmallcohort) + + new_patch%tallest => storebigcohort + new_patch%shortest => storesmallcohort + + currentCohort => currentCohort%taller + enddo ! currentCohort + + call sort_cohorts(currentPatch) + + !update area of donor patch + currentPatch%area = currentPatch%area - temp_area + + end subroutine split_patch + ! ============================================================================ subroutine check_patch_area( currentSite ) @@ -1337,6 +1833,13 @@ subroutine check_patch_area( currentSite ) if ( abs(areatot-area_site) > area_error_fail ) then write(fates_log(),*) 'Patch areas do not sum to 10000 within tolerance' write(fates_log(),*) 'Total area: ',areatot,'absolute error: ',areatot-area_site + + currentPatch => currentSite%oldest_patch + do while(associated(currentPatch)) + write(fates_log(),*) 'area, LU, PFT', currentPatch%area, currentPatch%land_use_label, currentPatch%nocomp_pft_label + currentPatch => currentPatch%younger + end do + call endrun(msg=errMsg(sourcefile, __LINE__)) end if @@ -2184,10 +2687,6 @@ subroutine landusechange_litter_fluxes(currentSite, currentPatch, & ! (note we are accumulating over the patch, but scale is site level) real(r8) :: woodproduct_mass ! mass that ends up in wood products [kg] - ! the following two parameters are new to this logic. - real(r8), parameter :: burn_frac_landusetransition = 0.5_r8 ! what fraction of plant fines are burned during a land use transition? - real(r8), parameter :: woodproduct_frac_landusetransition = 0.5_r8 ! what fraction of trunk carbon is turned into wood products during a land use transition? - !--------------------------------------------------------------------- clear_veg_if: if (clearing_matrix_element) then @@ -2276,10 +2775,10 @@ subroutine landusechange_litter_fluxes(currentSite, currentPatch, & ! Contribution of dead trees to leaf litter donatable_mass = num_dead_trees * (leaf_m+repro_m) * & - (1.0_r8-burn_frac_landusetransition) + (1.0_r8-EDPftvarcon_inst%landusechange_frac_burned(pft)) ! Contribution of dead trees to leaf burn-flux - burned_mass = num_dead_trees * (leaf_m+repro_m) * burn_frac_landusetransition + burned_mass = num_dead_trees * (leaf_m+repro_m) * EDPftvarcon_inst%landusechange_frac_burned(pft) do dcmpy=1,ndcmpy dcmpy_frac = GetDecompyFrac(pft,leaf_organ,dcmpy) @@ -2309,7 +2808,7 @@ subroutine landusechange_litter_fluxes(currentSite, currentPatch, & ! Track as diagnostic fluxes flux_diags%leaf_litter_input(pft) = & flux_diags%leaf_litter_input(pft) + & - num_dead_trees * (leaf_m+repro_m) * (1.0_r8-burn_frac_landusetransition) + num_dead_trees * (leaf_m+repro_m) * (1.0_r8-EDPftvarcon_inst%landusechange_frac_burned(pft)) flux_diags%root_litter_input(pft) = & flux_diags%root_litter_input(pft) + & @@ -2345,21 +2844,28 @@ subroutine landusechange_litter_fluxes(currentSite, currentPatch, & do c = 1,ncwd donatable_mass = num_dead_trees * SF_val_CWD_frac(c) * bstem if (c == 1 .or. c == 2) then ! these pools can burn - donatable_mass = donatable_mass * (1.0_r8-burn_frac_landusetransition) + donatable_mass = donatable_mass * (1.0_r8-EDPftvarcon_inst%landusechange_frac_burned(pft)) burned_mass = num_dead_trees * SF_val_CWD_frac(c) * bstem * & - burn_frac_landusetransition + EDPftvarcon_inst%landusechange_frac_burned(pft) site_mass%burn_flux_to_atm = site_mass%burn_flux_to_atm + burned_mass - else ! all other pools can end up as timber products but not burn - donatable_mass = donatable_mass * (1.0_r8-woodproduct_frac_landusetransition) + else ! all other pools can end up as timber products or burn or go to litter + donatable_mass = donatable_mass * (1.0_r8-EDPftvarcon_inst%landusechange_frac_exported(pft)) * & + (1.0_r8-EDPftvarcon_inst%landusechange_frac_burned(pft)) + + burned_mass = num_dead_trees * SF_val_CWD_frac(c) * bstem * & + (1.0_r8-EDPftvarcon_inst%landusechange_frac_exported(pft)) * & + EDPftvarcon_inst%landusechange_frac_burned(pft) woodproduct_mass = num_dead_trees * SF_val_CWD_frac(c) * bstem * & - woodproduct_frac_landusetransition + EDPftvarcon_inst%landusechange_frac_exported(pft) + + site_mass%burn_flux_to_atm = site_mass%burn_flux_to_atm + burned_mass trunk_product_site = trunk_product_site + & woodproduct_mass - site_mass%wood_product = site_mass%wood_product + & + site_mass%wood_product_landusechange(pft) = site_mass%wood_product_landusechange(pft) + & woodproduct_mass endif new_litt%ag_cwd(c) = new_litt%ag_cwd(c) + donatable_mass * donate_m2 @@ -2386,6 +2892,7 @@ subroutine landusechange_litter_fluxes(currentSite, currentPatch, & end subroutine landusechange_litter_fluxes ! ============================================================================ + subroutine fuse_patches( csite, bc_in ) ! ! !DESCRIPTION: @@ -2413,6 +2920,8 @@ subroutine fuse_patches( csite, bc_in ) integer :: i_pftlabel !nocomp pft iterator real(r8) :: primary_land_fraction_beforefusion,primary_land_fraction_afterfusion integer :: pftlabelmin, pftlabelmax + integer :: num_bareground_patches + integer :: i ! !--------------------------------------------------------------------- @@ -2424,20 +2933,29 @@ subroutine fuse_patches( csite, bc_in ) primary_land_fraction_afterfusion = 0._r8 nopatches(1:n_landuse_cats) = 0 - + num_bareground_patches = 0 + currentPatch => currentSite%youngest_patch do while(associated(currentPatch)) - nopatches(currentPatch%land_use_label) = & - nopatches(currentPatch%land_use_label) + 1 + if ( currentPatch%land_use_label .gt. nocomp_bareground_land) then + nopatches(currentPatch%land_use_label) = & + nopatches(currentPatch%land_use_label) + 1 - if (currentPatch%land_use_label .eq. primaryland) then - primary_land_fraction_beforefusion = primary_land_fraction_beforefusion + & - currentPatch%area * AREA_INV + if (currentPatch%land_use_label .eq. primaryland) then + primary_land_fraction_beforefusion = primary_land_fraction_beforefusion + & + currentPatch%area * AREA_INV + endif + else + num_bareground_patches = num_bareground_patches + 1 endif - currentPatch => currentPatch%older enddo + if (num_bareground_patches .gt. 1 ) then + write(fates_log(),*) 'somehow there is more than one bare ground patch. this shouldnt have happened.' + call endrun(msg=errMsg(sourcefile, __LINE__)) + endif + pftlabelmin = 0 if ( hlm_use_nocomp .eq. itrue ) then pftlabelmax = numpft @@ -2651,6 +3169,17 @@ subroutine fuse_patches( csite, bc_in ) write(fates_log(),*) 'profile tolerance is too big, this shouldnt happen.' write(fates_log(),*) 'probably this means there are too many distinct categorical ' write(fates_log(),*) 'patch types for the maximum number of patches' + call dump_site(currentSite) + write(fates_log(),*) 'currentSite%area_bareground', currentSite%area_bareground + do i = 1, n_landuse_cats + write(fates_log(),*) 'i, currentSite%area_pft(:,i)',i, currentSite%area_pft(:,i) + end do + tmpptr => currentSite%youngest_patch + do while(associated(tmpptr)) + write(fates_log(),*) tmpptr%area, tmpptr%nocomp_pft_label, tmpptr%land_use_label + tmpptr => tmpptr%older + end do + call endrun(msg=errMsg(sourcefile, __LINE__)) endif else @@ -2718,7 +3247,7 @@ subroutine fuse_2_patches(csite, dp, rp) + rp%age_since_anthro_disturbance * rp%area) * inv_sum_area rp%age_class = get_age_class_index(rp%age) - + do el = 1,num_elements call rp%litter(el)%FuseLitter(rp%area,dp%area,dp%litter(el)) end do @@ -2848,35 +3377,39 @@ subroutine fuse_2_patches(csite, dp, rp) call endrun(msg=errMsg(sourcefile, __LINE__)) endif - if(associated(youngerp))then - ! Update the younger patch's new older patch (because it isn't dp anymore) - youngerp%older => olderp - else - ! There was no younger patch than dp, so the head of the young order needs - ! to be set, and it is set as the patch older than dp. That patch - ! already knows it's older patch (so no need to set or change it) - csite%youngest_patch => olderp - olderp%younger => null() - end if + ! if neither youngerp nor olderp are associated, that means that the patch we are fusing into + ! is not part of the linked-list structure, and so no further action needs to be taken. + if(associated(youngerp) .or. associated(olderp))then - - if(associated(olderp))then - ! Update the older patch's new younger patch (becuase it isn't dp anymore) - olderp%younger => youngerp - else - ! There was no patch older than dp, so the head of the old patch order needs - ! to be set, and it is set as the patch younger than dp. That patch already - ! knows it's younger patch, no need to set - csite%oldest_patch => youngerp - youngerp%older => null() - end if + if(associated(youngerp))then + ! Update the younger patch's new older patch (because it isn't dp anymore) + youngerp%older => olderp + else + ! There was no younger patch than dp, so the head of the young order needs + ! to be set, and it is set as the patch older than dp. That patch + ! already knows it's older patch (so no need to set or change it) + csite%youngest_patch => olderp + olderp%younger => null() + end if + if(associated(olderp))then + ! Update the older patch's new younger patch (becuase it isn't dp anymore) + olderp%younger => youngerp + else + ! There was no patch older than dp, so the head of the old patch order needs + ! to be set, and it is set as the patch younger than dp. That patch already + ! knows it's younger patch, no need to set + csite%oldest_patch => youngerp + youngerp%older => null() + end if + end if + end subroutine fuse_2_patches ! ============================================================================ - subroutine terminate_patches(currentSite) + subroutine terminate_patches(currentSite, bc_in) ! ! !DESCRIPTION: ! Terminate Patches if they are too small @@ -2884,19 +3417,25 @@ subroutine terminate_patches(currentSite) ! ! !ARGUMENTS: type(ed_site_type), target, intent(inout) :: currentSite + type(bc_in_type), intent(in) :: bc_in ! ! !LOCAL VARIABLES: type(fates_patch_type), pointer :: currentPatch type(fates_patch_type), pointer :: olderPatch type(fates_patch_type), pointer :: youngerPatch type(fates_patch_type), pointer :: patchpointer + type(fates_patch_type), pointer :: largest_patch integer, parameter :: max_cycles = 10 ! After 10 loops through ! You should had fused integer :: count_cycles logical :: gotfused logical :: current_patch_is_youngest_lutype + integer :: i_landuse, i_pft + integer :: land_use_type_to_remove - real(r8) areatot ! variable for checking whether the total patch area is wrong. + real(r8) areatot ! variable for checking whether the total patch area is wrong. + real(r8) :: state_vector_driver(n_landuse_cats) ! [m2/m2] + real(r8) :: state_vector_internal(n_landuse_cats) ! [m2/m2] !--------------------------------------------------------------------- ! Initialize the count cycles @@ -2928,7 +3467,7 @@ subroutine terminate_patches(currentSite) if ( .not. gotfused ) then !! somehow didn't find a patch to fuse with. write(fates_log(),*) 'Warning. small nocomp patch wasnt able to find another patch to fuse with.', & - currentPatch%nocomp_pft_label, currentPatch%land_use_label + currentPatch%nocomp_pft_label, currentPatch%land_use_label, currentPatch%area endif else nocomp_if @@ -3037,14 +3576,88 @@ subroutine terminate_patches(currentSite) write(fates_log(),*) 'is very very small. You can test your luck by' write(fates_log(),*) 'disabling the endrun statement following this message.' write(fates_log(),*) 'FATES may or may not continue to operate within error' - write(fates_log(),*) 'tolerances, but will generate another fail if it does not.' - call endrun(msg=errMsg(sourcefile, __LINE__)) + write(fates_log(),*) 'tolerances, but will generate another fail if it does not.' + write(fates_log(),*) 'otherwise, dumping some diagnostics.' + write(fates_log(),*) currentPatch%area, currentPatch%nocomp_pft_label, currentPatch%land_use_label + call dump_site(currentSite) + + write(fates_log(),*) 'currentSite%area_bareground', currentSite%area_bareground + write(fates_log(),*) 'currentSite%area_pft(:,:)', currentSite%area_pft(:,:) + patchpointer => currentSite%youngest_patch + do while(associated(patchpointer)) + write(fates_log(),*) patchpointer%area, patchpointer%nocomp_pft_label, patchpointer%land_use_label + patchpointer => patchpointer%older + end do + state_vector_internal = currentSite%get_current_landuse_statevector() + write(fates_log(),*) 'current landuse state vector: ', state_vector_internal + write(fates_log(),*) 'current landuse state vector (not including bare gruond): ', state_vector_internal/(1._r8-currentSite%area_bareground) + call GetLUHStatedata(bc_in, state_vector_driver) + write(fates_log(),*) 'driver data landuse state vector: ', state_vector_driver + write(fates_log(),*) 'min_allowed_landuse_fraction: ', currentSite%min_allowed_landuse_fraction + write(fates_log(),*) 'landuse_vector_gt_min: ', currentSite%landuse_vector_gt_min + do i_landuse = 1, n_landuse_cats + write(fates_log(),*) 'trans matrix from: ', i_landuse, currentSite%landuse_transition_matrix(i_landuse,:) + end do + + if ( (state_vector_driver(currentPatch%land_use_label) .lt. currentSite%min_allowed_landuse_fraction ) .or. & + (state_vector_internal(currentPatch%land_use_label) .lt. currentSite%min_allowed_landuse_fraction ) ) then + + ! try fusing all of the patches with this land use label into the largest patch on the site. + land_use_type_to_remove = currentPatch%land_use_label + + write(fates_log(),*) 'removing all patches with land use type ',land_use_type_to_remove + + ! first find the largest patch on the site + patchpointer => currentSite%youngest_patch + largest_patch => currentSite%youngest_patch + do while(associated(patchpointer)) + if (patchpointer%area .gt. largest_patch%area .and. patchpointer%nocomp_pft_label .ne. nocomp_bareground) then + largest_patch => patchpointer + endif + patchpointer => patchpointer%older + end do + + ! now go and fuse all patches that have the land use type we are removing into that patch + patchpointer => currentSite%youngest_patch + do while(associated(patchpointer)) + if ( patchpointer%land_use_label .eq. land_use_type_to_remove ) then + + write(fates_log(),*) 'fusing into patch with types, age, and size of:', largest_patch%land_use_label, & + largest_patch%nocomp_pft_label, largest_patch%age, largest_patch%area + + write(fates_log(),*) 'fusing away patch with types, age, and size of:', patchpointer%land_use_label, & + patchpointer%nocomp_pft_label, patchpointer%age, patchpointer%area + + ! reset the categorical properties of the patch and fuse it into the largest patch + patchpointer%land_use_label = largest_patch%land_use_label + patchpointer%nocomp_pft_label = largest_patch%nocomp_pft_label + patchpointer%age_since_anthro_disturbance = largest_patch%age_since_anthro_disturbance + call fuse_2_patches(currentSite, patchpointer, largest_patch) + + ! start over in the loop to make sure we are removing every patch with the targeted land use type + patchpointer => currentSite%youngest_patch + + else + patchpointer => patchpointer%older + endif + end do + + write(fates_log(),*) 'resetting currentSite%landuse_vector_gt_min(i) to .false.' + ! now reset the allowed land use vector element so that we don't make any more such patches unless they exceed the min area + currentSite%landuse_vector_gt_min(land_use_type_to_remove) = .false. + count_cycles = 0 + currentPatch => currentSite%youngest_patch + else + write(fates_log(),*) 'this isnt because the land use was less than allowed' + + call endrun(msg=errMsg(sourcefile, __LINE__)) - ! Note to user. If you DO decide to remove the end-run above this line - ! Make sure that you keep the pointer below this line, or you will get - ! an infinite loop. - currentPatch => currentPatch%older - count_cycles = 0 + ! Note to user. If you DO decide to remove the end-run above this line + ! Make sure that you keep the pointer below this line, or you will get + ! an infinite loop. + currentPatch => currentPatch%older + count_cycles = 0 + endif end if !count cycles enddo ! current patch loop @@ -3175,35 +3788,6 @@ end function countPatches ! ===================================================================================== - subroutine get_frac_site_primary(site_in, frac_site_primary) - - ! - ! !DESCRIPTION: - ! Calculate how much of a site is primary land - ! - ! !USES: - use EDTypesMod , only : ed_site_type - ! - ! !ARGUMENTS: - type(ed_site_type) , intent(in), target :: site_in - real(r8) , intent(out) :: frac_site_primary - - ! !LOCAL VARIABLES: - type (fates_patch_type), pointer :: currentPatch - - frac_site_primary = 0._r8 - currentPatch => site_in%oldest_patch - do while (associated(currentPatch)) - if (currentPatch%land_use_label .eq. primaryland) then - frac_site_primary = frac_site_primary + currentPatch%area * AREA_INV - endif - currentPatch => currentPatch%younger - end do - - end subroutine get_frac_site_primary - - ! ===================================================================================== - subroutine InsertPatch(currentSite, newPatch) ! !DESCRIPTION: @@ -3305,7 +3889,7 @@ subroutine InsertPatch(currentSite, newPatch) ! In the case in which we get to the end of the list and haven't found ! a landuse label match. - ! If the new patch is primarylands add it to the oldest end of the list + ! If the new patch is primaryland add it to the oldest end of the list if (newPatch%land_use_label .eq. primaryland) then newPatch%older => null() newPatch%younger => currentSite%oldest_patch @@ -3368,4 +3952,36 @@ subroutine InsertPatch(currentSite, newPatch) end subroutine InsertPatch + ! ===================================================================================== + + subroutine CopyPatchMeansTimers(dp, rp) + + ! !DESCRIPTION: + ! Copy any means or timers from the original patch to the new patch + ! These values will inherit all info from the original patch + ! -------------------------------------------------------------------------- + ! + ! !ARGUMENTS: + type (fates_patch_type), intent(in) :: dp ! Donor Patch + type (fates_patch_type), intent(inout) :: rp ! Recipient Patch + + ! LOCAL: + integer :: ipft ! pft index + + call rp%tveg24%CopyFromDonor(dp%tveg24) + call rp%tveg_lpa%CopyFromDonor(dp%tveg_lpa) + call rp%tveg_longterm%CopyFromDonor(dp%tveg_longterm) + + if ( regeneration_model == TRS_regeneration ) then + call rp%seedling_layer_par24%CopyFromDonor(dp%seedling_layer_par24) + call rp%sdlng_mort_par%CopyFromDonor(dp%sdlng_mort_par) + call rp%sdlng2sap_par%CopyFromDonor(dp%sdlng2sap_par) + do ipft = 1,numpft + call rp%sdlng_emerg_smp(ipft)%p%CopyFromDonor(dp%sdlng_emerg_smp(ipft)%p) + call rp%sdlng_mdd(ipft)%p%CopyFromDonor(dp%sdlng_mdd(ipft)%p) + enddo + end if + + end subroutine CopyPatchMeansTimers + end module EDPatchDynamicsMod diff --git a/biogeochem/EDPhysiologyMod.F90 b/biogeochem/EDPhysiologyMod.F90 index e25a722f7a..0f080127c9 100644 --- a/biogeochem/EDPhysiologyMod.F90 +++ b/biogeochem/EDPhysiologyMod.F90 @@ -18,6 +18,7 @@ module EDPhysiologyMod use FatesInterfaceTypesMod, only : hlm_parteh_mode use FatesInterfaceTypesMod, only : hlm_use_fixed_biogeog use FatesInterfaceTypesMod, only : hlm_use_nocomp + use EDParamsMod , only : crop_lu_pft_vector use FatesInterfaceTypesMod, only : hlm_nitrogen_spec use FatesInterfaceTypesMod, only : hlm_phosphorus_spec use FatesInterfaceTypesMod, only : hlm_use_tree_damage @@ -34,6 +35,8 @@ module EDPhysiologyMod use FatesConstantsMod, only : g_per_kg use FatesConstantsMod, only : ndays_per_year use FatesConstantsMod, only : nocomp_bareground + use FatesConstantsMod, only : nocomp_bareground_land + use FatesConstantsMod, only : is_crop use FatesConstantsMod, only : area_error_2 use EDPftvarcon , only : EDPftvarcon_inst use PRTParametersMod , only : prt_params @@ -140,7 +143,8 @@ module EDPhysiologyMod use FatesParameterDerivedMod, only : param_derived use FatesPlantHydraulicsMod, only : InitHydrCohort use PRTInitParamsFatesMod, only : NewRecruitTotalStoichiometry - + use FatesInterfaceTypesMod , only : hlm_use_luh + implicit none private @@ -2492,20 +2496,35 @@ subroutine recruitment(currentSite, currentPatch, bc_in) real(r8) :: seedling_layer_smp ! soil matric potential at seedling rooting depth [mm H2O suction] integer, parameter :: recruitstatus = 1 ! whether the newly created cohorts are recruited or initialized integer :: ilayer_seedling_root ! the soil layer at seedling rooting depth - + logical :: use_this_pft ! logical flag for whether or not to allow a given PFT to recruit !--------------------------------------------------------------------------- do ft = 1, numpft - ! The following if block is for the prescribed biogeography and/or nocomp modes. - ! Since currentSite%use_this_pft is a site-level quantity and thus only limits whether a given PFT - ! is permitted on a given gridcell or not, it applies to the prescribed biogeography case only. - ! If nocomp is enabled, then we must determine whether a given PFT is allowed on a given patch or not. + ! The following if block is for the prescribed biogeography and/or nocomp modes and/or crop land use types + ! Since currentSite%use_this_pft is a site-level quantity and thus only limits whether a given PFT + ! is permitted on a given gridcell or not, it applies to the prescribed biogeography case only. + ! If nocomp is enabled, then we must determine whether a given PFT is allowed on a given patch or not. + ! Whether or not nocomp or prescribed biogeography is enabled, if land use change is enabled, then we only want to + ! allow crop PFTs on patches with crop land use types + + use_this_pft = .false. + if(currentSite%use_this_pft(ft).eq.itrue & + .and. ((hlm_use_nocomp .eq. ifalse) .or. (ft .eq. currentPatch%nocomp_pft_label)))then + use_this_pft = .true. + end if - if (currentSite%use_this_pft(ft) .eq. itrue .and. & - ((hlm_use_nocomp .eq. ifalse) .or. & - (ft .eq. currentPatch%nocomp_pft_label))) then + if ( currentPatch%land_use_label .ne. nocomp_bareground_land ) then ! cdk + if ((hlm_use_luh .eq. itrue) .and. (is_crop(currentPatch%land_use_label))) then + if ( crop_lu_pft_vector(currentPatch%land_use_label) .eq. ft ) then + use_this_pft = .true. + else + use_this_pft = .false. + end if + end if + endif + use_this_pft_if: if(use_this_pft) then height = EDPftvarcon_inst%hgt_min(ft) stem_drop_fraction = prt_params%phen_stem_drop_fraction(ft) fnrt_drop_fraction = prt_params%phen_fnrt_drop_fraction(ft) @@ -2749,11 +2768,11 @@ subroutine recruitment(currentSite, currentPatch, bc_in) currentSite%recruitment_rate(ft) = currentSite%recruitment_rate(ft) + cohort_n endif any_recruits - endif !use_this_pft + endif use_this_pft_if enddo !pft loop end subroutine recruitment - ! ====================================================================================== + ! ====================================================================================== subroutine CWDInput( currentSite, currentPatch, litt, bc_in) @@ -3022,7 +3041,7 @@ subroutine CWDInput( currentSite, currentPatch, litt, bc_in) SF_val_CWD_frac_adj(c) * dead_n_dlogging * & prt_params%allom_agb_frac(pft) - site_mass%wood_product = site_mass%wood_product + & + site_mass%wood_product_harvest(pft) = site_mass%wood_product_harvest(pft) + & trunk_wood * currentPatch%area * logging_export_frac ! Add AG wood to litter from the non-exported fraction of wood diff --git a/biogeochem/FatesLandUseChangeMod.F90 b/biogeochem/FatesLandUseChangeMod.F90 index 1999cfabc7..5873da97eb 100644 --- a/biogeochem/FatesLandUseChangeMod.F90 +++ b/biogeochem/FatesLandUseChangeMod.F90 @@ -15,6 +15,7 @@ module FatesLandUseChangeMod use FatesInterfaceTypesMod , only : hlm_use_luh use FatesInterfaceTypesMod , only : hlm_num_luh2_states use FatesInterfaceTypesMod , only : hlm_num_luh2_transitions + use FatesInterfaceTypesMod , only : hlm_use_potentialveg use FatesUtilsMod , only : FindIndex use EDTypesMod , only : area_site => area @@ -27,10 +28,11 @@ module FatesLandUseChangeMod character(len=*), parameter :: sourcefile = __FILE__ - public :: get_landuse_transition_rates - public :: get_landusechange_rules - public :: get_luh_statedata - + public :: GetLanduseTransitionRates + public :: GetLanduseChangeRules + public :: GetLUHStatedata + public :: GetInitLanduseTransitionRates + public :: GetInitLanduseHarvestRate ! module data integer, parameter :: max_luh2_types_per_fates_lu_type = 5 @@ -60,16 +62,19 @@ module FatesLandUseChangeMod contains ! ============================================================================ - subroutine get_landuse_transition_rates(bc_in, landuse_transition_matrix) + subroutine GetLanduseTransitionRates(bc_in, min_allowed_landuse_fraction, landuse_transition_matrix, & + landuse_vector_gt_min) - ! The purpose of this routine is to ingest the land use transition rate information that the host model has read in from a dataset, - ! aggregate land use types to those being used in the simulation, and output a transition matrix that can be used to drive patch - ! disturbance rates. + ! The purpose of this routine is to ingest the land use transition rate information that the host + ! model has read in from a dataset,aggregate land use types to those being used in the simulation, + ! and output a transition matrix that can be used to drive patch disturbance rates. ! !ARGUMENTS: type(bc_in_type) , intent(in) :: bc_in - real(r8), intent(inout) :: landuse_transition_matrix(n_landuse_cats, n_landuse_cats) ! [m2/m2/day] + real(r8), intent(in) :: min_allowed_landuse_fraction + real(r8), intent(inout) :: landuse_transition_matrix(n_landuse_cats, n_landuse_cats) ! [m2/m2/day] + logical, intent(inout) :: landuse_vector_gt_min(n_landuse_cats) ! !LOCAL VARIABLES: type(luh2_fates_lutype_map) :: lumap @@ -79,42 +84,67 @@ subroutine get_landuse_transition_rates(bc_in, landuse_transition_matrix) real(r8) :: urban_fraction real(r8) :: temp_vector(hlm_num_luh2_transitions) logical :: modified_flag + real(r8) :: state_vector(n_landuse_cats) ! [m2/m2] + integer :: i_lu ! zero the transition matrix and the urban fraction landuse_transition_matrix(:,:) = 0._r8 urban_fraction = 0._r8 - ! Check the LUH data incoming to see if any of the transitions are NaN - temp_vector = bc_in%hlm_luh_transitions - call CheckLUHData(temp_vector,modified_flag) - if (.not. modified_flag) then - ! identify urban fraction so that it can be factored into the land use state output - urban_fraction = bc_in%hlm_luh_states(FindIndex(bc_in%hlm_luh_state_names,'urban')) - end if - - !!TODO: may need some logic here to ask whether or not ot perform land use change on this timestep. current code occurs every day. - !!If not doing transition every day, need to update units. - - transitions_loop: do i_luh2_transitions = 1, hlm_num_luh2_transitions - - ! transition names are written in form xxxxx_to_yyyyy where x and y are donor and receiver state names - transition_name = bc_in%hlm_luh_transition_names(i_luh2_transitions) - donor_name = transition_name(1:5) - receiver_name = transition_name(10:14) - - ! Get the fates land use type index associated with the luh2 state types - i_donor= lumap%GetIndex(donor_name) - i_receiver = lumap%GetIndex(receiver_name) - - ! Avoid transitions with 'urban' as those are handled seperately - if (.not.(i_donor .eq. fates_unset_int .or. i_receiver .eq. fates_unset_int)) then - landuse_transition_matrix(i_donor,i_receiver) = & - landuse_transition_matrix(i_donor,i_receiver) + temp_vector(i_luh2_transitions) * years_per_day / (1._r8 - urban_fraction) + ! if we are using potential veg only, then keep all transitions equal to zero. + if (hlm_use_potentialveg .eq. ifalse) then + ! Check the LUH data incoming to see if any of the transitions are NaN + temp_vector = bc_in%hlm_luh_transitions + call CheckLUHData(temp_vector,modified_flag) + if (.not. modified_flag) then + ! identify urban fraction so that it can be factored into the land use state output + urban_fraction = bc_in%hlm_luh_states(FindIndex(bc_in%hlm_luh_state_names,'urban')) end if - end do transitions_loop - end subroutine get_landuse_transition_rates + !! TODO: may need some logic here to ask whether or not ot perform land use change on this timestep. + !! current code occurs every day. If not doing transition every day, need to update units. + + transitions_loop: do i_luh2_transitions = 1, hlm_num_luh2_transitions + + ! transition names are written in form xxxxx_to_yyyyy where x and y are donor and receiver state names + transition_name = bc_in%hlm_luh_transition_names(i_luh2_transitions) + donor_name = transition_name(1:5) + receiver_name = transition_name(10:14) + + ! Get the fates land use type index associated with the luh2 state types + i_donor= lumap%GetIndex(donor_name) + i_receiver = lumap%GetIndex(receiver_name) + + ! Avoid transitions with 'urban' as those are handled seperately + ! Also ignore diagonal elements of transition matrix. + if (.not.(i_donor .eq. fates_unset_int .or. i_receiver .eq. fates_unset_int .or. & + i_donor .eq. i_receiver)) then + landuse_transition_matrix(i_donor,i_receiver) = & + landuse_transition_matrix(i_donor,i_receiver) + temp_vector(i_luh2_transitions) & + * years_per_day / (1._r8 - urban_fraction) + + end if + end do transitions_loop + + ! zero all transitions where the receiving land use type state vector is less than the minimum allowed, + ! and otherwise if this is the first timestep where the minimum was exceeded, + ! then apply all transitions from primary to this type and reset the flag + ! note that the flag resetting should not happen for secondary lands, as this is handled in the + ! logging logic + call GetLUHStatedata(bc_in, state_vector) + do i_lu = secondaryland, n_landuse_cats + if ( state_vector(i_lu) .le. min_allowed_landuse_fraction ) then + landuse_transition_matrix(:,i_lu) = 0._r8 + else if ((.not. landuse_vector_gt_min(i_lu)) .and. (i_lu .ne. secondaryland)) then + landuse_transition_matrix(:,i_lu) = 0._r8 + landuse_transition_matrix(primaryland,i_lu) = state_vector(i_lu) + landuse_vector_gt_min(i_lu) = .true. + end if + end do + end if + + end subroutine GetLanduseTransitionRates !---------------------------------------------------------------------------------------------------- @@ -142,18 +172,20 @@ end function GetLUCategoryFromStateName !---------------------------------------------------------------------------------------------------- - subroutine get_landusechange_rules(clearing_matrix) + subroutine GetLanduseChangeRules(clearing_matrix) - ! the purpose of this is to define a ruleset for when to clear the vegetation in transitioning from one land use type to another + ! the purpose of this is to define a ruleset for when to clear the vegetation in transitioning + ! from one land use type to another logical, intent(out) :: clearing_matrix(n_landuse_cats,n_landuse_cats) - ! default value of ruleset 4 above means that plants are not cleared during land use change transitions to rangeland, whereas plants are - ! cleared in transitions to pasturelands and croplands. - integer, parameter :: ruleset = 4 ! ruleset to apply from table 1 of Ma et al (2020) https://doi.org/10.5194/gmd-13-3203-2020 + ! default value of ruleset 4 above means that plants are not cleared during land use change + ! transitions to rangeland, whereas plants are cleared in transitions to pasturelands and croplands. + integer, parameter :: ruleset = 4 ! ruleset to apply from table 1 of Ma et al (2020) + ! https://doi.org/10.5194/gmd-13-3203-2020 - ! clearing matrix applies from the donor to the receiver land use type of the newly-transferred patch area - ! values of clearing matrix: false => do not clear; true => clear + ! clearing matrix applies from the donor to the receiver land use type of the newly-transferred + ! patch area values of clearing matrix: false => do not clear; true => clear clearing_matrix(:,:) = .false. @@ -161,8 +193,10 @@ subroutine get_landusechange_rules(clearing_matrix) case(1) - ! note that this ruleset isnt exactly what is in Ma et al. rulesets 1 and 2, because FATES does not make the distinction - ! between forested and non-forested lands from a land use/land cover perspective. + ! note that this ruleset isnt exactly what is in Ma et al. rulesets 1 and 2, because FATES + ! does not make the distinction between forested and non-forested lands from a land use/land + ! cover perspective. + clearing_matrix(:,cropland) = .true. clearing_matrix(:,pastureland) = .true. clearing_matrix(primaryland,rangeland) = .true. @@ -227,11 +261,11 @@ subroutine get_landusechange_rules(clearing_matrix) end select - end subroutine get_landusechange_rules + end subroutine GetLanduseChangeRules !---------------------------------------------------------------------------------------------------- - subroutine get_luh_statedata(bc_in, state_vector) + subroutine GetLUHStatedata(bc_in, state_vector) type(bc_in_type) , intent(in) :: bc_in real(r8), intent(out) :: state_vector(n_landuse_cats) ! [m2/m2] @@ -249,36 +283,45 @@ subroutine get_luh_statedata(bc_in, state_vector) state_vector(:) = 0._r8 urban_fraction = 0._r8 - ! Check to see if the incoming state vector is NaN. - temp_vector = bc_in%hlm_luh_states - call CheckLUHData(temp_vector,modified_flag) - if (.not. modified_flag) then - ! identify urban fraction so that it can be factored into the land use state output - urban_fraction = bc_in%hlm_luh_states(FindIndex(bc_in%hlm_luh_state_names,'urban')) - end if - - ! loop over all states and add up the ones that correspond to a given fates land use type - do i_luh2_states = 1, hlm_num_luh2_states - - ! Get the luh2 state name and determine fates aggregated land use - ! type index from the state to lutype map - state_name = bc_in%hlm_luh_state_names(i_luh2_states) - ii = lumap%GetIndex(state_name) - - ! Avoid 'urban' states whose indices have been given unset values - if (ii .ne. fates_unset_int) then - state_vector(ii) = state_vector(ii) + & - temp_vector(i_luh2_states) / (1._r8 - urban_fraction) + if (hlm_use_potentialveg .eq. itrue) then + state_vector(primaryland) = 1._r8 + else + ! Check to see if the incoming state vector is NaN. + temp_vector = bc_in%hlm_luh_states + call CheckLUHData(temp_vector,modified_flag) + if (.not. modified_flag) then + ! identify urban fraction so that it can be factored into the land use state output + urban_fraction = bc_in%hlm_luh_states(FindIndex(bc_in%hlm_luh_state_names,'urban')) end if - end do - ! check to ensure total area == 1, and correct if not - if ( abs(sum(state_vector(:)) - 1._r8) .gt. nearzero ) then - write(fates_log(),*) 'warning: sum(state_vector) = ', sum(state_vector(:)) - state_vector = state_vector / sum(state_vector) + ! loop over all states and add up the ones that correspond to a given fates land use type + do i_luh2_states = 1, hlm_num_luh2_states + + ! Get the luh2 state name and determine fates aggregated land use + ! type index from the state to lutype map + state_name = bc_in%hlm_luh_state_names(i_luh2_states) + ii = lumap%GetIndex(state_name) + + ! Avoid 'urban' states whose indices have been given unset values + if (ii .ne. fates_unset_int) then + state_vector(ii) = state_vector(ii) + & + temp_vector(i_luh2_states) / (1._r8 - urban_fraction) + end if + end do + + ! if all zeros, make all primary lands + if ( sum(state_vector(:)) .gt. nearzero ) then + + ! check to ensure total area == 1, and correct if not + if ( abs(sum(state_vector(:)) - 1._r8) .gt. nearzero ) then + state_vector(:) = state_vector(:) / sum(state_vector(:)) + end if + else + state_vector(primaryland) = 1._r8 + endif end if - end subroutine get_luh_statedata + end subroutine GetLUHStatedata !---------------------------------------------------------------------------------------------------- @@ -291,8 +334,8 @@ subroutine CheckLUHData(luh_vector,modified_flag) ! Check to see if the incoming luh2 vector is NaN. ! This suggests that there is a discepency where the HLM and LUH2 states - ! there is vegetated ground. E.g. LUH2 data is missing for glacier-margin regions such as Antarctica. - ! In this case, states should be Nan. If so, + ! there is vegetated ground. E.g. LUH2 data is missing for glacier-margin + ! regions such as Antarctica. In this case, states should be Nan. If so, ! set the current state to be all primary forest, and all transitions to be zero. ! If only a portion of the vector is NaN, there is something amiss with ! the data, so end the run. @@ -305,7 +348,8 @@ subroutine CheckLUHData(luh_vector,modified_flag) luh_vector(primaryland) = 1._r8 end if modified_flag = .true. - !write(fates_log(),*) 'WARNING: land use state is all NaN; setting state as all primary forest.' ! GL DIAG + !write(fates_log(),*) 'WARNING: land use state is all NaN; + !setting state as all primary forest.' ! GL DIAG else if (any(isnan(luh_vector))) then if (any(.not. isnan(luh_vector))) then write(fates_log(),*) 'ERROR: land use vector has NaN' @@ -315,4 +359,69 @@ subroutine CheckLUHData(luh_vector,modified_flag) end subroutine CheckLUHData + + subroutine GetInitLanduseHarvestRate(bc_in, min_allowed_landuse_fraction, harvest_rate, & + landuse_vector_gt_min) + + ! the purpose of this subroutine is, only under the case where we are transitioning from a spinup + ! run that did not have land use to a run that does, to apply the land-use changes needed to get + ! to the state vector in a single daily instance. this is for the hrvest rate from primary lands, + ! i.e. the transition from primary to secondary lands. thus instead of using the harvest dataset + ! itself, it only uses the state vector for what land use compositoin we want to achieve, and log + ! the forests accordingly. + + ! !ARGUMENTS: + type(bc_in_type) , intent(in) :: bc_in + real(r8), intent(in) :: min_allowed_landuse_fraction + real(r8), intent(out) :: harvest_rate ! [m2/ m2 / day] + logical, intent(inout) :: landuse_vector_gt_min(n_landuse_cats) + + ! LOCALS + real(r8) :: state_vector(n_landuse_cats) ! [m2/m2] + + call GetLUHStatedata(bc_in, state_vector) + + ! only do this if the state vector exceeds the minimum viable patch size, and if so, note that in the + ! landuse_vector_gt_min flag (which will be coming in as .false. because of the use_potentialveg logic). + if ( state_vector(secondaryland) .gt. min_allowed_landuse_fraction) then + harvest_rate = state_vector(secondaryland) + landuse_vector_gt_min(secondaryland) = .true. + endif + + end subroutine GetInitLanduseHarvestRate + + subroutine GetInitLanduseTransitionRates(bc_in, min_allowed_landuse_fraction, & + landuse_transition_matrix, landuse_vector_gt_min) + + ! The purpose of this subroutine is, only under the case where we are transitioning from a spinup + ! run that did not have land use to a run that does, to apply the land-use changes needed to get + ! to the state vector in a single daily instance. This is for the transitions other than harvest, + ! i.e. from primary lands to all other categories aside from secondary lands. + + ! !ARGUMENTS: + type(bc_in_type) , intent(in) :: bc_in + real(r8), intent(in) :: min_allowed_landuse_fraction + real(r8), intent(inout) :: landuse_transition_matrix(n_landuse_cats, n_landuse_cats) ! [m2/m2/day] + logical, intent(inout) :: landuse_vector_gt_min(n_landuse_cats) + + ! LOCALS + real(r8) :: state_vector(n_landuse_cats) ! [m2/m2] + integer :: i + + landuse_transition_matrix(:,:) = 0._r8 + + call GetLUHStatedata(bc_in, state_vector) + + ! only do this if the state vector exceeds the minimum viable patch size, and if so, note that + ! in the landuse_vector_gt_min flag (which will be coming in as .false. because of the + ! use_potentialveg logic). + do i = secondaryland+1,n_landuse_cats + if ( state_vector(i) .gt. min_allowed_landuse_fraction) then + landuse_transition_matrix(primaryland,i) = state_vector(i) + landuse_vector_gt_min(i) = .true. + end if + end do + + end subroutine GetInitLanduseTransitionRates + end module FatesLandUseChangeMod diff --git a/biogeochem/FatesPatchMod.F90 b/biogeochem/FatesPatchMod.F90 index d86e5c5d51..b5489f6e82 100644 --- a/biogeochem/FatesPatchMod.F90 +++ b/biogeochem/FatesPatchMod.F90 @@ -64,6 +64,7 @@ module FatesPatchMod integer :: ncl_p ! number of occupied canopy layers integer :: land_use_label ! patch label for land use classification (primaryland, secondaryland, etc) real(r8) :: age_since_anthro_disturbance ! average age for secondary forest since last anthropogenic disturbance [years] + logical :: changed_landuse_this_ts ! logical flag to track patches that have just undergone land use change [only used with nocomp and land use change] !--------------------------------------------------------------------------- @@ -558,7 +559,7 @@ end subroutine InitLitter !=========================================================================== - subroutine Create(this, age, area, label, nocomp_pft, num_swb, num_pft, & + subroutine Create(this, age, area, land_use_label, nocomp_pft, num_swb, num_pft, & num_levsoil, current_tod, regeneration_model) ! ! DESCRIPTION: @@ -569,7 +570,7 @@ subroutine Create(this, age, area, label, nocomp_pft, num_swb, num_pft, & class(fates_patch_type), intent(inout) :: this ! patch object real(r8), intent(in) :: age ! notional age of this patch in years real(r8), intent(in) :: area ! initial area of this patch in m2. - integer, intent(in) :: label ! anthropogenic disturbance label + integer, intent(in) :: land_use_label ! land use label integer, intent(in) :: nocomp_pft ! no-competition mode pft label integer, intent(in) :: num_swb ! number of shortwave broad-bands to track integer, intent(in) :: num_pft ! number of pfts to simulate @@ -597,8 +598,8 @@ subroutine Create(this, age, area, label, nocomp_pft, num_swb, num_pft, & this%area = area ! assign anthropgenic disturbance category and label - this%land_use_label = label - if (label .eq. secondaryland) then + this%land_use_label = land_use_label + if (land_use_label .eq. secondaryland) then this%age_since_anthro_disturbance = age else this%age_since_anthro_disturbance = fates_unset_r8 @@ -609,6 +610,8 @@ subroutine Create(this, age, area, label, nocomp_pft, num_swb, num_pft, & this%tr_soil_dif(:) = 1.0_r8 this%NCL_p = 1 + this%changed_landuse_this_ts = .false. + end subroutine Create !=========================================================================== diff --git a/biogeochem/FatesSoilBGCFluxMod.F90 b/biogeochem/FatesSoilBGCFluxMod.F90 index 9d813c32b3..2c5b7d9b18 100644 --- a/biogeochem/FatesSoilBGCFluxMod.F90 +++ b/biogeochem/FatesSoilBGCFluxMod.F90 @@ -69,6 +69,7 @@ module FatesSoilBGCFluxMod use FatesConstantsMod, only : sec_per_day use FatesConstantsMod, only : years_per_day use FatesConstantsMod, only : itrue + use FatesConstantsMod, only : nocomp_bareground use FatesLitterMod, only : litter_type use FatesLitterMod , only : ncwd use FatesLitterMod , only : ndcmpy @@ -287,107 +288,107 @@ subroutine PrepCH4BCs(csite,bc_in,bc_out) fp = 0 cpatch => csite%oldest_patch do while (associated(cpatch)) - - ! Patch ordering when passing boundary conditions - ! always goes from oldest to youngest, following - ! the convention of EDPatchDynamics::set_patchno() - - fp = fp + 1 - - agnpp = 0._r8 - bgnpp = 0._r8 - woody_area = 0._r8 - plant_area = 0._r8 - - ccohort => cpatch%tallest - do while (associated(ccohort)) + if_notbare: if(cpatch%nocomp_pft_label .ne. nocomp_bareground)then + ! Patch ordering when passing boundary conditions + ! always goes from oldest to youngest, following + ! the convention of EDPatchDynamics::set_patchno() - ! For consistency, only apply calculations to non-new - ! cohorts. New cohorts will not have respiration rates - ! at this point in the call sequence. + fp = fp + 1 - if(.not.ccohort%isnew) then - - pft = ccohort%pft - - call set_root_fraction(csite%rootfrac_scr, pft, csite%zi_soil, & - bc_in%max_rooting_depth_index_col ) - - fnrt_c = ccohort%prt%GetState(fnrt_organ, carbon12_element) - - ! [kgC/day] - sapw_net_alloc = ccohort%prt%GetNetAlloc(sapw_organ, carbon12_element) * days_per_sec - store_net_alloc = ccohort%prt%GetNetAlloc(store_organ, carbon12_element) * days_per_sec - leaf_net_alloc = ccohort%prt%GetNetAlloc(leaf_organ, carbon12_element) * days_per_sec - fnrt_net_alloc = ccohort%prt%GetNetAlloc(fnrt_organ, carbon12_element) * days_per_sec - struct_net_alloc = ccohort%prt%GetNetAlloc(struct_organ, carbon12_element) * days_per_sec - repro_net_alloc = ccohort%prt%GetNetAlloc(repro_organ, carbon12_element) * days_per_sec - - ! [kgC/plant/day] -> [gC/m2/s] - agnpp = agnpp + ccohort%n/cpatch%area * (leaf_net_alloc + repro_net_alloc + & - prt_params%allom_agb_frac(pft)*(sapw_net_alloc+store_net_alloc+struct_net_alloc)) * g_per_kg + agnpp = 0._r8 + bgnpp = 0._r8 + woody_area = 0._r8 + plant_area = 0._r8 + + ccohort => cpatch%tallest + do while (associated(ccohort)) - ! [kgC/plant/day] -> [gC/m2/s] - bgnpp = bgnpp + ccohort%n/cpatch%area * (fnrt_net_alloc + & - (1._r8-prt_params%allom_agb_frac(pft))*(sapw_net_alloc+store_net_alloc+struct_net_alloc)) * g_per_kg + ! For consistency, only apply calculations to non-new + ! cohorts. New cohorts will not have respiration rates + ! at this point in the call sequence. - if(hlm_use_ch4==itrue)then + if(.not.ccohort%isnew) then - ! Fine root fraction over depth - bc_out%rootfr_pa(fp,1:bc_in%nlevsoil) = & - bc_out%rootfr_pa(fp,1:bc_in%nlevsoil) + & - csite%rootfrac_scr(1:bc_in%nlevsoil) + pft = ccohort%pft + + call set_root_fraction(csite%rootfrac_scr, pft, csite%zi_soil, & + bc_in%max_rooting_depth_index_col ) + + fnrt_c = ccohort%prt%GetState(fnrt_organ, carbon12_element) + + ! [kgC/day] + sapw_net_alloc = ccohort%prt%GetNetAlloc(sapw_organ, carbon12_element) * days_per_sec + store_net_alloc = ccohort%prt%GetNetAlloc(store_organ, carbon12_element) * days_per_sec + leaf_net_alloc = ccohort%prt%GetNetAlloc(leaf_organ, carbon12_element) * days_per_sec + fnrt_net_alloc = ccohort%prt%GetNetAlloc(fnrt_organ, carbon12_element) * days_per_sec + struct_net_alloc = ccohort%prt%GetNetAlloc(struct_organ, carbon12_element) * days_per_sec + repro_net_alloc = ccohort%prt%GetNetAlloc(repro_organ, carbon12_element) * days_per_sec + + ! [kgC/plant/day] -> [gC/m2/s] + agnpp = agnpp + ccohort%n/cpatch%area * (leaf_net_alloc + repro_net_alloc + & + prt_params%allom_agb_frac(pft)*(sapw_net_alloc+store_net_alloc+struct_net_alloc)) * g_per_kg + + ! [kgC/plant/day] -> [gC/m2/s] + bgnpp = bgnpp + ccohort%n/cpatch%area * (fnrt_net_alloc + & + (1._r8-prt_params%allom_agb_frac(pft))*(sapw_net_alloc+store_net_alloc+struct_net_alloc)) * g_per_kg - ! Fine root carbon, convert [kg/plant] -> [g/m2] - bc_out%frootc_pa(fp) = & - bc_out%frootc_pa(fp) + & - fnrt_c*ccohort%n/cpatch%area * g_per_kg + if(hlm_use_ch4==itrue)then + + ! Fine root fraction over depth + bc_out%rootfr_pa(fp,1:bc_in%nlevsoil) = & + bc_out%rootfr_pa(fp,1:bc_in%nlevsoil) + & + csite%rootfrac_scr(1:bc_in%nlevsoil) + + ! Fine root carbon, convert [kg/plant] -> [g/m2] + bc_out%frootc_pa(fp) = & + bc_out%frootc_pa(fp) + & + fnrt_c*ccohort%n/cpatch%area * g_per_kg + + ! (gC/m2/s) root respiration (fine root MR + total root GR) + ! RGK: We do not save root respiration and average over the day. Until we do + ! this is a best (bad) guess at fine root MR + total root GR + ! (kgC/indiv/yr) -> gC/m2/s + bc_out%root_resp(1:bc_in%nlevsoil) = bc_out%root_resp(1:bc_in%nlevsoil) + & + ccohort%resp_acc_hold*years_per_day*g_per_kg*days_per_sec* & + ccohort%n*area_inv*(1._r8-prt_params%allom_agb_frac(pft)) * csite%rootfrac_scr(1:bc_in%nlevsoil) + + end if + + if( prt_params%woody(pft)==itrue ) then + woody_area = woody_area + ccohort%c_area + end if + plant_area = plant_area + ccohort%c_area - ! (gC/m2/s) root respiration (fine root MR + total root GR) - ! RGK: We do not save root respiration and average over the day. Until we do - ! this is a best (bad) guess at fine root MR + total root GR - ! (kgC/indiv/yr) -> gC/m2/s - bc_out%root_resp(1:bc_in%nlevsoil) = bc_out%root_resp(1:bc_in%nlevsoil) + & - ccohort%resp_acc_hold*years_per_day*g_per_kg*days_per_sec* & - ccohort%n*area_inv*(1._r8-prt_params%allom_agb_frac(pft)) * csite%rootfrac_scr(1:bc_in%nlevsoil) end if - if( prt_params%woody(pft)==itrue ) then - woody_area = woody_area + ccohort%c_area + ccohort => ccohort%shorter + end do + + if(hlm_use_ch4==itrue)then + if( sum(bc_out%rootfr_pa(fp,1:bc_in%nlevsoil)) > nearzero) then + bc_out%rootfr_pa(fp,1:bc_in%nlevsoil) = & + bc_out%rootfr_pa(fp,1:bc_in%nlevsoil) / & + sum(bc_out%rootfr_pa(fp,1:bc_in%nlevsoil)) end if - plant_area = plant_area + ccohort%c_area + ! RGK: These averages should switch to the new patch averaging methods + ! when available. Right now we are not doing any time averaging + ! because it would be mixing the memory of patches, which + ! would be arguably worse than just using the instantaneous value - end if - - ccohort => ccohort%shorter - end do - - if(hlm_use_ch4==itrue)then - if( sum(bc_out%rootfr_pa(fp,1:bc_in%nlevsoil)) > nearzero) then - bc_out%rootfr_pa(fp,1:bc_in%nlevsoil) = & - bc_out%rootfr_pa(fp,1:bc_in%nlevsoil) / & - sum(bc_out%rootfr_pa(fp,1:bc_in%nlevsoil)) - end if - - ! RGK: These averages should switch to the new patch averaging methods - ! when available. Right now we are not doing any time averaging - ! because it would be mixing the memory of patches, which - ! would be arguably worse than just using the instantaneous value - - ! gC/m2/s - bc_out%annavg_agnpp_pa(fp) = agnpp - bc_out%annavg_bgnpp_pa(fp) = bgnpp - ! gc/m2/yr - bc_out%annsum_npp_pa(fp) = (bgnpp+agnpp)*days_per_year*sec_per_day - - if(plant_area>nearzero) then - bc_out%woody_frac_aere_pa(fp) = woody_area/plant_area - end if + ! gC/m2/s + bc_out%annavg_agnpp_pa(fp) = agnpp + bc_out%annavg_bgnpp_pa(fp) = bgnpp + ! gc/m2/yr + bc_out%annsum_npp_pa(fp) = (bgnpp+agnpp)*days_per_year*sec_per_day + + if(plant_area>nearzero) then + bc_out%woody_frac_aere_pa(fp) = woody_area/plant_area + end if - end if - + end if + end if if_notbare cpatch => cpatch%younger end do diff --git a/main/EDInitMod.F90 b/main/EDInitMod.F90 index e33ee5e7ec..ce76ba9017 100644 --- a/main/EDInitMod.F90 +++ b/main/EDInitMod.F90 @@ -10,7 +10,10 @@ module EDInitMod use FatesConstantsMod , only : fates_unset_int use FatesConstantsMod , only : primaryland use FatesConstantsMod , only : nearzero + use FatesConstantsMod , only : rsnbl_math_prec + use EDTypesMod , only : min_patch_area_forced use FatesConstantsMod , only : n_landuse_cats + use FatesConstantsMod , only : is_crop use FatesConstantsMod , only : fates_unset_r8 use FatesConstantsMod , only : nearzero, area_error_4, area_error_3 use FatesGlobals , only : endrun => fates_endrun @@ -62,7 +65,6 @@ module EDInitMod use FatesInterfaceTypesMod , only : nlevdamage use FatesInterfaceTypesMod , only : hlm_use_nocomp use FatesInterfaceTypesMod , only : nlevage - use FatesAllometryMod , only : h2d_allom use FatesAllometryMod , only : h_allom use FatesAllometryMod , only : bagw_allom @@ -91,11 +93,16 @@ module EDInitMod use FatesSizeAgeTypeIndicesMod,only : get_age_class_index use DamageMainMod, only : undamaged_class use FatesConstantsMod, only : n_term_mort_types - use FatesInterfaceTypesMod , only : hlm_num_luh2_transitions + use FatesInterfaceTypesMod, only : hlm_num_luh2_transitions + use FatesConstantsMod, only : nocomp_bareground_land, nocomp_bareground + use FatesConstantsMod, only : min_nocomp_pftfrac_perlanduse + use EdTypesMod, only : dump_site use SFNesterovMod, only : nesterov_index + ! CIME GLOBALS use shr_log_mod , only : errMsg => shr_log_errMsg + use shr_infnan_mod , only : isnan => shr_infnan_isnan implicit none private @@ -187,11 +194,8 @@ subroutine init_site_vars( site_in, bc_in, bc_out ) allocate(site_in%dz_soil(site_in%nlevsoil)) allocate(site_in%z_soil(site_in%nlevsoil)) - if (hlm_use_nocomp .eq. itrue .and. hlm_use_fixed_biogeog .eq. itrue) then - allocate(site_in%area_pft(0:numpft)) - else ! SP and nocomp require a bare-ground patch. - allocate(site_in%area_pft(1:numpft)) - endif + allocate(site_in%area_pft(1:numpft,1:n_landuse_cats)) + allocate(site_in%landuse_vector_gt_min(1:n_landuse_cats)) allocate(site_in%use_this_pft(1:numpft)) allocate(site_in%area_by_age(1:nlevage)) @@ -344,14 +348,19 @@ subroutine zero_site( site_in ) ! canopy spread site_in%spread = 0._r8 + + site_in%area_pft(:,:) = 0._r8 + site_in%area_bareground = 0._r8 + ! Seed dispersal site_in%seed_in(:) = 0.0_r8 site_in%seed_out(:) = 0.0_r8 - site_in%area_pft(:) = 0._r8 site_in%use_this_pft(:) = fates_unset_int site_in%area_by_age(:) = 0._r8 + site_in%transition_landuse_from_off_to_on = .false. + end subroutine zero_site ! ============================================================================ @@ -360,6 +369,8 @@ subroutine set_site_properties( nsites, sites,bc_in ) ! !DESCRIPTION: ! ! !USES: + use EDParamsMod, only : crop_lu_pft_vector + use EDParamsMod, only : max_nocomp_pfts_by_landuse ! ! !ARGUMENTS @@ -387,6 +398,9 @@ subroutine set_site_properties( nsites, sites,bc_in ) real(r8) :: sumarea ! area of PFTs in nocomp mode. integer :: hlm_pft ! used in fixed biogeog mode integer :: fates_pft ! used in fixed biogeog mode + integer :: i_landusetype + real(r8) :: temp_vec(numpft) ! temporary vector + integer :: i_pftcount !---------------------------------------------------------------------- @@ -439,7 +453,7 @@ subroutine set_site_properties( nsites, sites,bc_in ) sites(s)%NF = 0.0_r8 sites(s)%NF_successful = 0.0_r8 - sites(s)%area_pft(:) = 0.0_r8 + sites(s)%area_pft(:,:) = 0.0_r8 do ft = 1,numpft sites(s)%rec_l2fr(ft,:) = prt_params%allom_l2fr(ft) @@ -450,66 +464,121 @@ subroutine set_site_properties( nsites, sites,bc_in ) sites(s)%ema_npp = -9999._r8 if(hlm_use_fixed_biogeog.eq.itrue)then - ! MAPPING OF FATES PFTs on to HLM_PFTs - ! add up the area associated with each FATES PFT - ! where pft_areafrac is the area of land in each HLM PFT and (from surface dataset) - ! hlm_pft_map is the area of that land in each FATES PFT (from param file) - - do hlm_pft = 1,size( EDPftvarcon_inst%hlm_pft_map,2) - do fates_pft = 1,numpft ! loop round all fates pfts for all hlm pfts - sites(s)%area_pft(fates_pft) = sites(s)%area_pft(fates_pft) + & - EDPftvarcon_inst%hlm_pft_map(fates_pft,hlm_pft) * bc_in(s)%pft_areafrac(hlm_pft) - end do - end do !hlm_pft - do ft = 1,numpft - if(sites(s)%area_pft(ft).lt.0.01_r8.and.sites(s)%area_pft(ft).gt.0.0_r8)then - if(debug) write(fates_log(),*) 'removing small pft patches',s,ft,sites(s)%area_pft(ft) - sites(s)%area_pft(ft)=0.0_r8 - ! remove tiny patches to prevent numerical errors in terminate patches + use_fates_luh_if: if (hlm_use_luh .eq. itrue) then + ! MAPPING OF FATES PFTs on to HLM_PFTs with land use + ! add up the area associated with each FATES PFT + ! where pft_areafrac_lu is the area of land in each HLM PFT and land use type (from surface dataset) + ! hlm_pft_map is the area of that land in each FATES PFT (from param file) + + ! First check for NaNs in bc_in(s)%pft_areafrac_lu. If so, make everything bare ground. + if ( .not. (any( isnan( bc_in(s)%pft_areafrac_lu (:,:) )) .or. isnan( bc_in(s)%baregroundfrac))) then + do i_landusetype = 1, n_landuse_cats + if (.not. is_crop(i_landusetype)) then + do hlm_pft = 1,size( EDPftvarcon_inst%hlm_pft_map,2) + do fates_pft = 1,numpft ! loop round all fates pfts for all hlm pfts + sites(s)%area_pft(fates_pft,i_landusetype) = sites(s)%area_pft(fates_pft,i_landusetype) + & + EDPftvarcon_inst%hlm_pft_map(fates_pft,hlm_pft) * bc_in(s)%pft_areafrac_lu(hlm_pft,i_landusetype) + end do + end do !hlm_pft + else + ! for crops, we need to use different logic because the bc_in(s)%pft_areafrac_lu() information only exists for natural PFTs + sites(s)%area_pft(crop_lu_pft_vector(i_landusetype),i_landusetype) = 1._r8 + endif + end do + + sites(s)%area_bareground = bc_in(s)%baregroundfrac + else + !if ( all( isnan( bc_in(s)%pft_areafrac_lu (:,:))) .and. isnan(bc_in(s)%baregroundfrac)) then + ! if given all NaNs, then make everything bare ground + sites(s)%area_bareground = 1._r8 + sites(s)%area_pft(:,:) = 0._r8 + write(fates_log(),*) 'Nan values for pftareafrac. dumping site info.' + call dump_site(sites(s)) + !else + ! ! if only some things are NaN but not all, then something terrible has probably happened. crash. + ! write(fates_log(),*) 'some but, not all, of the data in the PFT by LU matrix at this site is NaN.' + ! write(fates_log(),*) 'recommend checking the dataset to see what has happened.' + ! call endrun(msg=errMsg(sourcefile, __LINE__)) + !endif endif - if(sites(s)%area_pft(ft).lt.0._r8)then - write(fates_log(),*) 'negative area',s,ft,sites(s)%area_pft(ft) - call endrun(msg=errMsg(sourcefile, __LINE__)) - end if - sites(s)%area_pft(ft)= sites(s)%area_pft(ft) * AREA ! rescale units to m2. + + else + ! MAPPING OF FATES PFTs on to HLM_PFTs + ! add up the area associated with each FATES PFT + ! where pft_areafrac is the area of land in each HLM PFT and (from surface dataset) + ! hlm_pft_map is the area of that land in each FATES PFT (from param file) + + do hlm_pft = 1,size( EDPftvarcon_inst%hlm_pft_map,2) + do fates_pft = 1,numpft ! loop round all fates pfts for all hlm pfts + sites(s)%area_pft(fates_pft,primaryland) = sites(s)%area_pft(fates_pft,primaryland) + & + EDPftvarcon_inst%hlm_pft_map(fates_pft,hlm_pft) * bc_in(s)%pft_areafrac(hlm_pft) + end do + sites(s)%area_bareground = bc_in(s)%pft_areafrac(0) + end do !hlm_pft + + endif use_fates_luh_if + + ! handle some edge cases + do i_landusetype = 1, n_landuse_cats + do ft = 1,numpft + + ! remove tiny patches to prevent numerical errors in terminate patches + if (sites(s)%area_pft(ft, i_landusetype) .lt. min_nocomp_pftfrac_perlanduse & + .and. sites(s)%area_pft(ft, i_landusetype) .gt. nearzero) then + if(debug) write(fates_log(),*) 'removing small numbers in site%area_pft',s,ft,i_landusetype,sites(s)%area_pft(ft, i_landusetype) + sites(s)%area_pft(ft, i_landusetype)=0.0_r8 + endif + + ! if any areas are negative, then end run + if(sites(s)%area_pft(ft, i_landusetype).lt.0._r8)then + write(fates_log(),*) 'negative area',s,ft,i_landusetype,sites(s)%area_pft(ft, i_landusetype) + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + end do end do - ! re-normalize PFT area to ensure it sums to one. - ! note that in areas of 'bare ground' (PFT 0 in CLM/ELM) - ! the bare ground will no longer be proscribed and should emerge from FATES - ! this may or may not be the right way to deal with this? + ! if in nocomp mode, and the number of nocomp PFTs of a given land use type is greater than the maximum number of patches + ! allowed to be allocated for that land use type, then only keep the number of PFTs correspondign to the number of patches + ! allowed on that land use type, starting with the PFTs with greatest area coverage and working down + if (hlm_use_nocomp .eq. itrue) then + do i_landusetype = 1, n_landuse_cats + ! count how many PFTs have areas greater than zero and compare to the number of patches allowed + if (COUNT(sites(s)%area_pft(:, i_landusetype) .gt. 0._r8) > max_nocomp_pfts_by_landuse(i_landusetype)) then + ! write current vector to log file + if(debug) write(fates_log(),*) 'too many PFTs for LU type ', i_landusetype, sites(s)%area_pft(:, i_landusetype) + + ! start from largest area, put that PFT's area into a temp vector, and then work down to successively smaller-area PFTs, + ! at the end replace the original vector with the temp vector + temp_vec(:) = 0._r8 + do i_pftcount = 1, max_nocomp_pfts_by_landuse(i_landusetype) + temp_vec(MAXLOC(sites(s)%area_pft(:, i_landusetype))) = & + sites(s)%area_pft(MAXLOC(sites(s)%area_pft(:, i_landusetype)), i_landusetype) + sites(s)%area_pft(MAXLOC(sites(s)%area_pft(:, i_landusetype)), i_landusetype) = 0._r8 + end do + sites(s)%area_pft(:, i_landusetype) = temp_vec(:) - if(hlm_use_nocomp.eq.ifalse)then ! when not in nocomp (i.e. or SP) mode, - ! subsume bare ground evenly into the existing patches. + ! write adjusted vector to log file + if(debug) write(fates_log(),*) 'new PFT vector for LU type', i_landusetype, sites(s)%area_pft(:, i_landusetype) + endif + end do + end if - sumarea = sum(sites(s)%area_pft(1:numpft)) - do ft = 1,numpft - if(sumarea.gt.0._r8)then - sites(s)%area_pft(ft) = area * sites(s)%area_pft(ft)/sumarea - else - sites(s)%area_pft(ft) = area/numpft - ! in nocomp mode where there is only bare ground, we assign equal area to - ! all pfts and let the model figure out whether land should be bare or not. - end if - end do !ft - else ! for sp and nocomp mode, assert a bare ground patch if needed - sumarea = sum(sites(s)%area_pft(1:numpft)) - - ! In all the other FATES modes, bareground is the area in which plants - ! do not grow of their own accord. In SP mode we assert that the canopy is full for - ! each PFT patch. Thus, we also need to assert a bare ground area in - ! order to not have all of the ground filled by leaves. - - ! Further to that, one could calculate bare ground as the remaining area when - ! all fhe canopies are accounted for, but this means we don't pass balance checks - ! on canopy are inside FATES, and so in SP mode, we define the bare groud - ! patch as having a PFT identifier as zero. - - if(sumarea.lt.area)then !make some bare ground - sites(s)%area_pft(0) = area - sumarea + ! re-normalize PFT area to ensure it sums to one for each (active) land use type + ! for nocomp cases, track bare ground area as a separate quantity + do i_landusetype = 1, n_landuse_cats + sumarea = sum(sites(s)%area_pft(:,i_landusetype)) + if(sumarea.gt.nearzero)then + sites(s)%area_pft(:, i_landusetype) = sites(s)%area_pft(:, i_landusetype)/sumarea + else + ! if no PFT area in primary lands, set bare ground fraction to one. + if ( i_landusetype .eq. primaryland) then + sites(s)%area_bareground = 1._r8 + sites(s)%area_pft(:, i_landusetype) = 0._r8 + endif end if - end if !sp mode + end do + end if !fixed biogeog do ft = 1,numpft @@ -517,13 +586,27 @@ subroutine set_site_properties( nsites, sites,bc_in ) ! are used for nocomp with no biogeog sites(s)%use_this_pft(ft) = itrue if(hlm_use_fixed_biogeog.eq.itrue)then - if(sites(s)%area_pft(ft).gt.0.0_r8)then + if(any(sites(s)%area_pft(ft,:).gt.0.0_r8))then sites(s)%use_this_pft(ft) = itrue else sites(s)%use_this_pft(ft) = ifalse end if !area end if !SBG end do !ft + + ! need to set the minimum amount of allowable land-use fraction on a given site. this is a function of the minimum allowable patch size, + ! and for nocomp simulations also the bare ground fraction and the minimum pft fraction for a given land-use type. + if (hlm_use_nocomp .eq. itrue ) then + if ( (1._r8 - sites(s)%area_bareground) .gt. nearzero) then + sites(s)%min_allowed_landuse_fraction = min_patch_area_forced / (AREA * min_nocomp_pftfrac_perlanduse * (1._r8 - sites(s)%area_bareground)) + else + ! if all bare ground, shouldn't matter. but make it one anyway to really ignore land use (which should all be NaNs anyway) + sites(s)%min_allowed_landuse_fraction = 1._r8 + endif + else + sites(s)%min_allowed_landuse_fraction = min_patch_area_forced / AREA + endif + end do !site loop end if !restart @@ -541,7 +624,7 @@ subroutine init_patches( nsites, sites, bc_in) use FatesPlantHydraulicsMod, only : updateSizeDepRhizHydProps use FatesInventoryInitMod, only : initialize_sites_by_inventory - use FatesLandUseChangeMod, only : get_luh_statedata + use FatesLandUseChangeMod, only : GetLUHStatedata ! ! !ARGUMENTS @@ -555,6 +638,7 @@ subroutine init_patches( nsites, sites, bc_in) real(r8) :: age !notional age of this patch integer :: ageclass real(r8) :: area_diff + real(r8) :: area_error ! dummy locals real(r8) :: biomass_stock @@ -562,19 +646,19 @@ subroutine init_patches( nsites, sites, bc_in) real(r8) :: seed_stock integer :: n integer :: start_patch - integer :: num_new_patches + integer :: num_nocomp_pfts integer :: nocomp_pft real(r8) :: newparea, newparea_withlanduse real(r8) :: total !check on area real(r8) :: litt_init !invalid for satphen, 0 otherwise real(r8) :: old_carea - integer :: is_first_patch + logical :: is_first_patch ! integer :: n_luh_states ! integer :: luh_state_counter real(r8) :: state_vector(n_landuse_cats) ! [m2/m2] integer :: i_lu, i_lu_state integer :: n_active_landuse_cats - + integer :: end_landuse_idx type(ed_site_type), pointer :: sitep type(fates_patch_type), pointer :: newppft(:) @@ -615,7 +699,11 @@ subroutine init_patches( nsites, sites, bc_in) else - ! state_vector(:) = 0._r8 + if(hlm_use_nocomp.eq.itrue)then + num_nocomp_pfts = numpft + else !default + num_nocomp_pfts = 1 + end if !nocomp sites_loop: do s = 1, nsites sites(s)%sp_tlai(:) = 0._r8 @@ -627,17 +715,6 @@ subroutine init_patches( nsites, sites, bc_in) ! have smaller spread factors than bare ground (they are crowded) sites(s)%spread = init_spread_near_bare_ground - start_patch = 1 ! start at the first vegetated patch - if(hlm_use_nocomp.eq.itrue)then - num_new_patches = numpft - if( hlm_use_fixed_biogeog .eq.itrue )then - start_patch = 0 ! start at the bare ground patch - endif - ! allocate(newppft(numpft)) - else !default - num_new_patches = 1 - end if !nocomp - ! read in luh state data to determine initial land use types if (hlm_use_luh .eq. itrue) then @@ -645,18 +722,18 @@ subroutine init_patches( nsites, sites, bc_in) ! This could be updated in the future to allow a variable number of ! categories based on which states are zero n_active_landuse_cats = n_landuse_cats - call get_luh_statedata(bc_in(s), state_vector) - ! n_luh_states = 0 - ! do i_lu = 1, hlm_num_luh2_transitions - ! if ( state_vector(i_lu) .gt. nearzero ) then - ! n_luh_states = n_luh_states +1 - ! end if - ! end do - - ! if (n_luh_states .eq. 0) then - ! write(fates_log(),*) 'error. n_luh_states .eq. 0.' - ! call endrun(msg=errMsg(sourcefile, __LINE__)) - ! endif + call GetLUHStatedata(bc_in(s), state_vector) + + ! if the land use state vector is greater than the minimum value, set landuse_vector_gt_min flag to true + ! otherwise set to false. + do i_lu_state = 1, n_landuse_cats + if (state_vector(i_lu_state) .gt. sites(s)%min_allowed_landuse_fraction) then + sites(s)%landuse_vector_gt_min(i_lu_state) = .true. + else + sites(s)%landuse_vector_gt_min(i_lu_state) = .false. + end if + end do + else ! If LUH2 data is not being used, we initialize with primarylands, ! i.e. array index equals '1' @@ -665,94 +742,163 @@ subroutine init_patches( nsites, sites, bc_in) state_vector(primaryland) = 1._r8 endif - is_first_patch = itrue - ! luh_state_counter = 0 - new_patch_nocomp_loop: do n = start_patch, num_new_patches + ! confirm that state vector sums to 1. + if (abs(sum(state_vector(:))-1._r8) .gt. rsnbl_math_prec) then + write(fates_log(),*) 'error that the state vector must sum to 1, but doesnt' + write(fates_log(),*) 'sum(state_vector)', sum(state_vector) + write(fates_log(),*) state_vector + call endrun(msg=errMsg(sourcefile, __LINE__)) + endif - ! set the PFT index for patches if in nocomp mode. - if(hlm_use_nocomp.eq.itrue)then - nocomp_pft = n - else - nocomp_pft = fates_unset_int - end if + is_first_patch = .true. + + area_error = 0._r8 + ! first make a bare-ground patch if one is needed. + make_bareground_patch_if: if (hlm_use_nocomp.eq.itrue .and. hlm_use_fixed_biogeog .eq.itrue) then + + newparea = area * sites(s)%area_bareground + if (newparea .gt. min_patch_area_forced) then + + allocate(newp) + + call newp%Create(age, newparea, nocomp_bareground_land, nocomp_bareground, & + num_swb, numpft, sites(s)%nlevsoil, hlm_current_tod, & + regeneration_model) + + ! set pointers for first patch (or only patch, if nocomp is false) + newp%patchno = 1 + newp%younger => null() + newp%older => null() + sites(s)%youngest_patch => newp + sites(s)%oldest_patch => newp + is_first_patch = .false. + + ! Initialize the litter pools to zero, these + ! pools will be populated by looping over the existing patches + ! and transfering in mass + if(hlm_use_sp.eq.itrue)then + litt_init = fates_unset_r8 + else + litt_init = 0._r8 + end if + do el=1,num_elements + call newp%litter(el)%InitConditions(init_leaf_fines=litt_init, & + init_root_fines=litt_init, & + init_ag_cwd=litt_init, & + init_bg_cwd=litt_init, & + init_seed=litt_init, & + init_seed_germ=litt_init) + end do - if(hlm_use_nocomp.eq.itrue)then - ! In no competition mode, if we are using the fixed_biogeog filter - ! then each PFT has the area dictated by the surface dataset. + else + area_error = area_error + newparea + endif + endif make_bareground_patch_if - ! If we are not using fixed biogeog model, each PFT gets the same area. - ! i.e. each grid cell is divided exactly into the number of FATES PFTs. + if (hlm_use_luh .eq. itrue) then + end_landuse_idx = n_landuse_cats + else + end_landuse_idx = 1 + endif - if(hlm_use_fixed_biogeog.eq.itrue)then - newparea = sites(s)%area_pft(nocomp_pft) - else - newparea = area / numpft - end if - else ! The default case is initialized w/ one patch with the area of the whole site. - newparea = area - end if !nocomp mode - - luh_state_loop: do i_lu_state = 1, n_active_landuse_cats - lu_state_present_if: if ( state_vector(i_lu_state) .gt. nearzero ) then - - newparea_withlanduse = newparea * state_vector(i_lu_state) - - ! for now, spread nocomp PFTs evenly across land use types - new_patch_area_gt_zero: if(newparea_withlanduse.gt.0._r8)then ! Stop patches being initilialized when PFT not present in nocomop mode - allocate(newp) - - call newp%Create(age, newparea_withlanduse, i_lu_state, nocomp_pft, & - num_swb, numpft, sites(s)%nlevsoil, hlm_current_tod, & - regeneration_model) - - if(is_first_patch.eq.itrue)then !is this the first patch? - ! set poointers for first patch (or only patch, if nocomp is false) - newp%patchno = 1 - newp%younger => null() - newp%older => null() - sites(s)%youngest_patch => newp - sites(s)%oldest_patch => newp - is_first_patch = ifalse - else - ! Set pointers for N>1 patches. Note this only happens when nocomp mode s on. - ! The new patch is the 'youngest' one, arbitrarily. - newp%patchno = nocomp_pft + (i_lu_state-1) * numpft - newp%older => sites(s)%youngest_patch - newp%younger => null() - sites(s)%youngest_patch%younger => newp - sites(s)%youngest_patch => newp - end if - ! Initialize the litter pools to zero, these - ! pools will be populated by looping over the existing patches - ! and transfering in mass - if(hlm_use_sp.eq.itrue)then - litt_init = fates_unset_r8 + ! Next, create the non-bareground patches. We do this for either of two scenarios: + ! If 1) we are not doing both nocomp & fixed-biogeo + ! 2) we are, but there is some non-zero bare-ground area + not_all_bare_if: if( ((1._r8 - sites(s)%area_bareground) > nearzero) .or. & + (.not.(hlm_use_nocomp.eq.itrue .and. hlm_use_fixed_biogeog.eq.itrue)) ) then + + ! now make one or more vegetated patches based on nocomp and land use logic + luh_state_loop: do i_lu_state = 1, end_landuse_idx + lu_state_present_if: if (state_vector(i_lu_state) .gt. nearzero) then + new_patch_nocomp_loop: do n = 1, num_nocomp_pfts + ! set the PFT index for patches if in nocomp mode. + if(hlm_use_nocomp.eq.itrue)then + nocomp_pft = n else - litt_init = 0._r8 + nocomp_pft = fates_unset_int end if - do el=1,num_elements - call newp%litter(el)%InitConditions(init_leaf_fines=litt_init, & - init_root_fines=litt_init, & - init_ag_cwd=litt_init, & - init_bg_cwd=litt_init, & - init_seed=litt_init, & - init_seed_germ=litt_init) - end do + + if(hlm_use_nocomp.eq.itrue)then + ! In no competition mode, if we are using the fixed_biogeog filter + ! then each PFT has the area dictated by the surface dataset. + + ! If we are not using fixed biogeog model, each PFT gets the same area. + ! i.e. each grid cell is divided exactly into the number of FATES PFTs. + + if(hlm_use_fixed_biogeog.eq.itrue)then + newparea = sites(s)%area_pft(nocomp_pft,i_lu_state) * area * state_vector(i_lu_state) & + * (1._r8 - sites(s)%area_bareground) + else + newparea = area * state_vector(i_lu_state) / numpft + end if + else ! The default case is initialized w/ one patch with the area of the whole site. + newparea = area * state_vector(i_lu_state) + end if !nocomp mode + + ! Stop patches being initilialized when PFT not present in nocomop mode + new_patch_area_gt_zero: if(newparea .gt. min_patch_area_forced) then + allocate(newp) + + call newp%Create(age, newparea, i_lu_state, nocomp_pft, & + num_swb, numpft, sites(s)%nlevsoil, hlm_current_tod, & + regeneration_model) + + if (is_first_patch) then !is this the first patch? + ! set pointers for first patch (or only patch, if nocomp is false) + newp%patchno = 1 + newp%younger => null() + newp%older => null() + sites(s)%youngest_patch => newp + sites(s)%oldest_patch => newp + is_first_patch = .false. + else + ! Set pointers for N>1 patches. Note this only happens when nocomp mode is on, or land use is on. + ! The new patch is the 'youngest' one, arbitrarily. + newp%patchno = nocomp_pft + (i_lu_state-1) * numpft + newp%older => sites(s)%youngest_patch + newp%younger => null() + sites(s)%youngest_patch%younger => newp + sites(s)%youngest_patch => newp + end if - sitep => sites(s) - if(hlm_use_sp.eq.itrue)then - if(nocomp_pft.ne.0)then !don't initialize cohorts for SP bare ground patch - call init_cohorts(sitep, newp, bc_in(s)) + ! Initialize the litter pools to zero, these + ! pools will be populated by looping over the existing patches + ! and transfering in mass + if(hlm_use_sp.eq.itrue)then + litt_init = fates_unset_r8 + else + litt_init = 0._r8 end if - else ! normal non SP case always call init cohorts + do el=1,num_elements + call newp%litter(el)%InitConditions(init_leaf_fines=litt_init, & + init_root_fines=litt_init, & + init_ag_cwd=litt_init, & + init_bg_cwd=litt_init, & + init_seed=litt_init, & + init_seed_germ=litt_init) + end do + + sitep => sites(s) call init_cohorts(sitep, newp, bc_in(s)) - end if - end if new_patch_area_gt_zero + + else + area_error = area_error+ newparea + end if new_patch_area_gt_zero + end do new_patch_nocomp_loop end if lu_state_present_if end do luh_state_loop - end do new_patch_nocomp_loop !no new patches - + end if not_all_bare_if + + ! if we had to skip small patches above, resize things accordingly + if ( area_error .gt. nearzero) then + newp => sites(s)%oldest_patch + do while (associated(newp)) + newp%area = newp%area * area/ (area - area_error) + newp => newp%younger + end do + endif + !check if the total area adds to the same as site area total = 0.0_r8 newp => sites(s)%oldest_patch @@ -764,22 +910,34 @@ subroutine init_patches( nsites, sites, bc_in) area_diff = total - area if (abs(area_diff) > nearzero) then if (abs(area_diff) < area_error_4) then ! this is a precision error - if (sites(s)%oldest_patch%area > area_diff + nearzero) then - ! remove or add extra area - ! if the oldest patch has enough area, use that - sites(s)%oldest_patch%area = sites(s)%oldest_patch%area - area_diff - if (debug) write(fates_log(),*) 'fixing patch precision - oldest', s, area_diff - else ! or otherwise take the area from the youngest patch. - sites(s)%youngest_patch%area = sites(s)%youngest_patch%area - area_diff - if (debug) write(fates_log(),*) 'fixing patch precision -youngest ', s, area_diff - end if + + ! adjust areas of all patches so that they add up to total area + newp => sites(s)%oldest_patch + do while (associated(newp)) + newp%area = newp%area * (area / total) + newp => newp%younger + end do + else !this is a big error not just a precision error. - write(fates_log(),*) 'issue with patch area in EDinit', area_diff, total + write(fates_log(),*) 'issue with patch area in EDinit', area_diff, total,sites(s)%lat,sites(s)%lon + write(fates_log(),*) 'hlm_use_nocomp: ',hlm_use_nocomp + write(fates_log(),*) 'hlm_use_fixed_biogeog: ',hlm_use_fixed_biogeog + newp => sites(s)%oldest_patch + do while (associated(newp)) + write(fates_log(),*) newp%area, newp%nocomp_pft_label, newp%land_use_label + newp => newp%younger + end do + write(fates_log(),*) 'state_vector', state_vector + write(fates_log(),*) 'area_error', area_error + write(fates_log(),*) 'area_bareground', sites(s)%area_bareground + do i_lu_state = 1, end_landuse_idx + write(fates_log(),*) 'sites(s)%area_pft(:,i_lu_state)',i_lu_state, sites(s)%area_pft(:,i_lu_state) + end do call endrun(msg=errMsg(sourcefile, __LINE__)) end if ! big error end if ! too much patch area - ! we might have messed up patch area now - need to correct if SP mode + ! we might have messed up crown areas now - need to correct if SP mode if (hlm_use_sp .eq. itrue) then newp => sites(s)%oldest_patch do while (associated(newp)) @@ -847,6 +1005,18 @@ subroutine init_patches( nsites, sites, bc_in) end do end if + ! check to make sure there are no very tiny patches + do s = 1, nsites + currentPatch => sites(s)%youngest_patch + do while(associated(currentPatch)) + if (currentPatch%area .lt. min_patch_area_forced) then + write(fates_log(),*) 'edinit somehow making tiny patches',currentPatch%land_use_label, currentPatch%nocomp_pft_label, currentPatch%area + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + currentPatch => currentPatch%older + end do + end do + return end subroutine init_patches diff --git a/main/EDMainMod.F90 b/main/EDMainMod.F90 index 06e4b74c80..06058b8f63 100644 --- a/main/EDMainMod.F90 +++ b/main/EDMainMod.F90 @@ -75,6 +75,7 @@ module EDMainMod use EDTypesMod , only : phen_dstat_timeon use FatesConstantsMod , only : itrue,ifalse use FatesConstantsMod , only : primaryland, secondaryland + use FatesConstantsMod , only : n_landuse_cats use FatesConstantsMod , only : nearzero use FatesConstantsMod , only : m2_per_ha use FatesConstantsMod , only : sec_per_day @@ -88,7 +89,6 @@ module EDMainMod use EDLoggingMortalityMod , only : IsItLoggingTime use EDLoggingMortalityMod , only : get_harvestable_carbon use DamageMainMod , only : IsItDamageTime - use EDPatchDynamicsMod , only : get_frac_site_primary use FatesGlobals , only : endrun => fates_endrun use ChecksBalancesMod , only : SiteMassStock use EDMortalityFunctionsMod , only : Mortality_Derivative @@ -219,6 +219,11 @@ subroutine ed_ecosystem_dynamics(currentSite, bc_in, bc_out) ! Integrate state variables from annual rates to daily timestep call ed_integrate_state_variables(currentSite, bc_in, bc_out ) + ! at this point in the call sequence, if flag to transition_landuse_from_off_to_on was set, unset it as it is no longer needed + if(currentSite%transition_landuse_from_off_to_on) then + currentSite%transition_landuse_from_off_to_on = .false. + endif + else ! ed_intergrate_state_variables is where the new cohort flag ! is set. This flag designates wether a cohort has @@ -283,6 +288,7 @@ subroutine ed_ecosystem_dynamics(currentSite, bc_in, bc_out) ! make new patches from disturbed land if (do_patch_dynamics.eq.itrue ) then + call spawn_patches(currentSite, bc_in) call TotalBalanceCheck(currentSite,3) @@ -303,7 +309,7 @@ subroutine ed_ecosystem_dynamics(currentSite, bc_in, bc_out) call TotalBalanceCheck(currentSite,4) ! kill patches that are too small - call terminate_patches(currentSite) + call terminate_patches(currentSite, bc_in) end if call TotalBalanceCheck(currentSite,5) @@ -366,7 +372,7 @@ subroutine ed_integrate_state_variables(currentSite, bc_in, bc_out ) ! a lowered damage state. This cohort should bypass several calculations ! because it inherited them (such as daily carbon balance) real(r8) :: target_leaf_c - real(r8) :: frac_site_primary + real(r8) :: current_fates_landuse_state_vector(n_landuse_cats) real(r8) :: harvestable_forest_c(hlm_num_lu_harvest_cats) integer :: harvest_tag(hlm_num_lu_harvest_cats) @@ -402,7 +408,7 @@ subroutine ed_integrate_state_variables(currentSite, bc_in, bc_out ) !----------------------------------------------------------------------- - call get_frac_site_primary(currentSite, frac_site_primary) + current_fates_landuse_state_vector = currentSite%get_current_landuse_statevector() ! Clear site GPP and AR passing to HLM bc_out%gpp_site = 0._r8 @@ -467,8 +473,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, frac_site_primary, & - harvestable_forest_c, harvest_tag) + currentPatch%age_since_anthro_disturbance, current_fates_landuse_state_vector(primaryland), & + current_fates_landuse_state_vector(secondaryland), harvestable_forest_c, harvest_tag) ! ----------------------------------------------------------------------------- ! Apply Plant Allocation and Reactive Transport @@ -906,7 +912,8 @@ subroutine TotalBalanceCheck (currentSite, call_index ) site_mass%flux_generic_in + & site_mass%patch_resize_err - flux_out = site_mass%wood_product + & + flux_out = sum(site_mass%wood_product_harvest(:)) + & + sum(site_mass%wood_product_landusechange(:)) + & site_mass%burn_flux_to_atm + & site_mass%seed_out + & site_mass%flux_generic_out + & @@ -936,7 +943,8 @@ subroutine TotalBalanceCheck (currentSite, call_index ) write(fates_log(),*) 'net_root_uptake: ',site_mass%net_root_uptake write(fates_log(),*) 'gpp_acc: ',site_mass%gpp_acc write(fates_log(),*) 'flux_generic_in: ',site_mass%flux_generic_in - write(fates_log(),*) 'wood_product: ',site_mass%wood_product + write(fates_log(),*) 'wood_product_harvest: ',site_mass%wood_product_harvest(:) + write(fates_log(),*) 'wood_product_landusechange: ',site_mass%wood_product_landusechange(:) write(fates_log(),*) 'error from patch resizing: ',site_mass%patch_resize_err write(fates_log(),*) 'burn_flux_to_atm: ',site_mass%burn_flux_to_atm write(fates_log(),*) 'seed_out: ',site_mass%seed_out diff --git a/main/EDParamsMod.F90 b/main/EDParamsMod.F90 index 1389e1c489..c3d8a76273 100644 --- a/main/EDParamsMod.F90 +++ b/main/EDParamsMod.F90 @@ -182,7 +182,9 @@ module EDParamsMod character(len=param_string_length),parameter,public :: ED_name_history_height_bin_edges= "fates_history_height_bin_edges" character(len=param_string_length),parameter,public :: ED_name_history_coageclass_bin_edges = "fates_history_coageclass_bin_edges" character(len=param_string_length),parameter,public :: ED_name_history_damage_bin_edges = "fates_history_damage_bin_edges" + character(len=param_string_length),parameter,public :: ED_name_crop_lu_pft_vector = "fates_landuse_crop_lu_pft_vector" character(len=param_string_length),parameter,public :: ED_name_maxpatches_by_landuse = "fates_maxpatches_by_landuse" + character(len=param_string_length),parameter,public :: ED_name_max_nocomp_pfts_by_landuse = "fates_max_nocomp_pfts_by_landuse" ! Hydraulics Control Parameters (ONLY RELEVANT WHEN USE_FATES_HYDR = TRUE) ! ---------------------------------------------------------------------------------------------- @@ -236,8 +238,12 @@ module EDParamsMod ! thus they are not protected here. integer, public :: maxpatches_by_landuse(n_landuse_cats) + integer, public :: max_nocomp_pfts_by_landuse(n_landuse_cats) integer, public :: maxpatch_total + ! which crops can be grown on a given crop land use type + integer,protected,public :: crop_lu_pft_vector(n_landuse_cats) + ! Maximum allowable cohorts per patch integer, protected, public :: max_cohort_per_patch character(len=param_string_length), parameter, public :: maxcohort_name = "fates_maxcohort" @@ -279,10 +285,6 @@ module EDParamsMod ! leftovers will be left onsite as large CWD character(len=param_string_length),parameter,public :: logging_name_export_frac ="fates_landuse_logging_export_frac" - real(r8),protected,public :: pprodharv10_forest_mean ! "mean harvest mortality proportion of deadstem to 10-yr - ! product pool (pprodharv10) of all woody PFT types - character(len=param_string_length),parameter,public :: logging_name_pprodharv10="fates_landuse_pprodharv10_forest_mean" - real(r8),protected,public :: eca_plant_escalar ! scaling factor for plant fine root biomass to ! calculate nutrient carrier enzyme abundance (ECA) @@ -358,7 +360,6 @@ subroutine FatesParamsInit() logging_event_code = nan logging_dbhmax_infra = nan logging_export_frac = nan - pprodharv10_forest_mean = nan eca_plant_escalar = nan q10_mr = nan q10_froz = nan @@ -553,9 +554,6 @@ subroutine FatesRegisterParams(fates_params) call fates_params%RegisterParameter(name=logging_name_export_frac, dimension_shape=dimension_shape_scalar, & dimension_names=dim_names_scalar) - call fates_params%RegisterParameter(name=logging_name_pprodharv10, dimension_shape=dimension_shape_scalar, & - dimension_names=dim_names_scalar) - call fates_params%RegisterParameter(name=eca_name_plant_escalar, dimension_shape=dimension_shape_scalar, & dimension_names=dim_names_scalar) @@ -600,9 +598,15 @@ subroutine FatesRegisterParams(fates_params) call fates_params%RegisterParameter(name=ED_name_history_damage_bin_edges, dimension_shape=dimension_shape_1d, & dimension_names=dim_names_damageclass) + call fates_params%RegisterParameter(name=ED_name_crop_lu_pft_vector, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names_landuse) + call fates_params%RegisterParameter(name=ED_name_maxpatches_by_landuse, dimension_shape=dimension_shape_1d, & dimension_names=dim_names_landuse) + call fates_params%RegisterParameter(name=ED_name_max_nocomp_pfts_by_landuse, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names_landuse) + end subroutine FatesRegisterParams @@ -618,8 +622,10 @@ subroutine FatesReceiveParams(fates_params) real(r8) :: tmpreal ! local real variable for changing type on read real(r8), allocatable :: hydr_htftype_real(:) - real(r8) :: tmp_vector_by_landuse(n_landuse_cats) ! local real vector for changing type on read - + real(r8), allocatable :: tmp_vector_by_landuse1(:) ! local real vector for changing type on read + real(r8), allocatable :: tmp_vector_by_landuse2(:) ! local real vector for changing type on read + real(r8), allocatable :: tmp_vector_by_landuse3(:) ! local real vector for changing type on read + call fates_params%RetrieveParameter(name=ED_name_photo_temp_acclim_timescale, & data=photo_temp_acclim_timescale) @@ -780,9 +786,6 @@ subroutine FatesReceiveParams(fates_params) call fates_params%RetrieveParameter(name=logging_name_export_frac, & data=logging_export_frac) - call fates_params%RetrieveParameter(name=logging_name_pprodharv10, & - data=pprodharv10_forest_mean) - call fates_params%RetrieveParameter(name=eca_name_plant_escalar, & data=eca_plant_escalar) @@ -832,11 +835,24 @@ subroutine FatesReceiveParams(fates_params) call fates_params%RetrieveParameterAllocate(name=ED_name_history_damage_bin_edges, & data=ED_val_history_damage_bin_edges) - call fates_params%RetrieveParameter(name=ED_name_maxpatches_by_landuse, & - data=tmp_vector_by_landuse) + call fates_params%RetrieveParameterAllocate(name=ED_name_crop_lu_pft_vector, & + data=tmp_vector_by_landuse1) + + crop_lu_pft_vector(:) = nint(tmp_vector_by_landuse1(:)) + deallocate(tmp_vector_by_landuse1) - maxpatches_by_landuse(:) = nint(tmp_vector_by_landuse(:)) + call fates_params%RetrieveParameterAllocate(name=ED_name_maxpatches_by_landuse, & + data=tmp_vector_by_landuse2) + + maxpatches_by_landuse(:) = nint(tmp_vector_by_landuse2(:)) maxpatch_total = sum(maxpatches_by_landuse(:)) + deallocate(tmp_vector_by_landuse2) + + call fates_params%RetrieveParameterAllocate(name=ED_name_max_nocomp_pfts_by_landuse, & + data=tmp_vector_by_landuse3) + + max_nocomp_pfts_by_landuse(:) = nint(tmp_vector_by_landuse3(:)) + deallocate(tmp_vector_by_landuse3) call fates_params%RetrieveParameterAllocate(name=ED_name_hydr_htftype_node, & data=hydr_htftype_real) diff --git a/main/EDPftvarcon.F90 b/main/EDPftvarcon.F90 index 98367a30ff..8e10ebdcf7 100644 --- a/main/EDPftvarcon.F90 +++ b/main/EDPftvarcon.F90 @@ -277,9 +277,14 @@ module EDPftvarcon real(r8), allocatable :: hydr_thetas_node(:,:) ! saturated water content (cm3/cm3) ! Table that maps HLM pfts to FATES pfts for fixed biogeography mode - ! The values are area fractions (NOT IMPLEMENTED) + ! The values are area fractions real(r8), allocatable :: hlm_pft_map(:,:) + ! Land-use and land-use change related PFT parameters + real(r8), allocatable :: harvest_pprod10(:) ! fraction of harvest wood product that goes to 10-year product pool (remainder goes to 100-year pool) + real(r8), allocatable :: landusechange_frac_burned(:) ! fraction of land use change-generated and not-exported material that is burned (the remainder goes to litter) + real(r8), allocatable :: landusechange_frac_exported(:) ! fraction of land use change-generated wood material that is exported to wood product (the remainder is either burned or goes to litter) + real(r8), allocatable :: landusechange_pprod10(:) ! fraction of land use change wood product that goes to 10-year product pool (remainder goes to 100-year pool) contains procedure, public :: Init => EDpftconInit @@ -798,6 +803,22 @@ subroutine Register_PFT(this, fates_params) call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) + name = 'fates_landuse_harvest_pprod10' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + + name = 'fates_landuse_luc_frac_burned' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + + name = 'fates_landuse_luc_frac_exported' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + + name = 'fates_landuse_luc_pprod10' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + name = 'fates_dev_arbitrary_pft' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) @@ -1266,6 +1287,22 @@ subroutine Receive_PFT(this, fates_params) call fates_params%RetrieveParameterAllocate(name=name, & data=this%hlm_pft_map) + name = 'fates_landuse_harvest_pprod10' + call fates_params%RetrieveParameterAllocate(name=name, & + data=this%harvest_pprod10) + + name = 'fates_landuse_luc_frac_burned' + call fates_params%RetrieveParameterAllocate(name=name, & + data=this%landusechange_frac_burned) + + name = 'fates_landuse_luc_frac_exported' + call fates_params%RetrieveParameterAllocate(name=name, & + data=this%landusechange_frac_exported) + + name = 'fates_landuse_luc_pprod10' + call fates_params%RetrieveParameterAllocate(name=name, & + data=this%landusechange_pprod10) + end subroutine Receive_PFT !----------------------------------------------------------------------- @@ -1793,7 +1830,10 @@ subroutine FatesCheckParams(is_master) use EDParamsMod , only : radiation_model, dayl_switch use FatesInterfaceTypesMod, only : hlm_use_fixed_biogeog,hlm_use_sp, hlm_name use FatesInterfaceTypesMod, only : hlm_use_inventory_init - + use FatesInterfaceTypesMod, only : hlm_use_nocomp + use EDParamsMod , only : max_nocomp_pfts_by_landuse, maxpatches_by_landuse + use FatesConstantsMod , only : n_landuse_cats + ! Argument logical, intent(in) :: is_master ! Only log if this is the master proc @@ -1806,6 +1846,7 @@ subroutine FatesCheckParams(is_master) integer :: norgans ! size of the plant organ dimension integer :: hlm_pft ! used in fixed biogeog mode integer :: fates_pft ! used in fixed biogeog mode + integer :: i_lu ! land use index real(r8) :: sumarea ! area of PFTs in nocomp mode. real(r8) :: neg_lmr_temp ! temperature at which lmr would got negative @@ -2195,6 +2236,25 @@ subroutine FatesCheckParams(is_master) end do !ipft + ! if nocomp is enabled, check to make sure the max number of nocomp PFTs per land use is + ! less than or equal to the max number of patches per land use. (unless this is an + ! SP run, then all PFTS are tracked on the primary LU and the others are allocated + ! zero patch space + + if ( hlm_use_nocomp .eq. itrue .and. hlm_use_sp.eq.ifalse) then + do i_lu = 1, n_landuse_cats + if (max_nocomp_pfts_by_landuse(i_lu) .gt. maxpatches_by_landuse(i_lu)) then + write(fates_log(),*) 'The max number of nocomp PFTs must all be less than or equal to the number of patches, for a given land use type' + write(fates_log(),*) 'land use index:',i_lu + write(fates_log(),*) 'max_nocomp_pfts_by_landuse(i_lu):', max_nocomp_pfts_by_landuse(i_lu) + write(fates_log(),*) 'maxpatches_by_landuse(i_lu):', maxpatches_by_landuse(i_lu) + write(fates_log(),*) 'Aborting' + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + end do + endif + + ! Check the temperature at which Rdark would become negative for each PFT - ! given their parameters !------------------------------------------------------------------------------------ diff --git a/main/EDTypesMod.F90 b/main/EDTypesMod.F90 index b482370058..14865a56bd 100644 --- a/main/EDTypesMod.F90 +++ b/main/EDTypesMod.F90 @@ -4,6 +4,10 @@ module EDTypesMod use FatesGlobals, only : endrun => fates_endrun use FatesConstantsMod, only : ifalse use FatesConstantsMod, only : itrue + use FatesConstantsMod, only : nocomp_bareground_land + use FatesConstantsMod, only : secondaryland + use FatesConstantsMod, only : secondary_age_threshold + use FatesConstantsMod, only : nearzero use FatesGlobals, only : fates_log use FatesHydraulicsMemMod, only : ed_cohort_hydr_type use FatesHydraulicsMemMod, only : ed_site_hydr_type @@ -217,7 +221,10 @@ module EDTypesMod real(r8) :: frag_out ! Litter and coarse woody debris fragmentation flux [kg/site/day] - real(r8) :: wood_product ! Total mass exported as wood product [kg/site/day] + real(r8) :: wood_product_harvest(maxpft) ! Total mass exported as wood product from wood harvest [kg/site/day] + + real(r8) :: wood_product_landusechange(maxpft) ! Total mass exported as wood product from land use change [kg/site/day] + real(r8) :: burn_flux_to_atm ! Total mass burned and exported to the atmosphere [kg/site/day] real(r8) :: flux_generic_in ! Used for prescribed or artificial input fluxes @@ -262,7 +269,9 @@ module EDTypesMod real(r8) :: lon ! longitude: degrees ! Fixed Biogeography mode inputs - real(r8), allocatable :: area_PFT(:) ! Area allocated to individual PFTs + real(r8), allocatable :: area_PFT(:,:) ! Area allocated to individual PFTs, indexed by land use class [ha/ha of non-bareground area] + real(r8) :: area_bareground ! Area allocated to bare ground in nocomp configurations (corresponds to HLM PFT 0) [ha/ha] + integer, allocatable :: use_this_pft(:) ! Is area_PFT > 0 ? (1=yes, 0=no) ! Total area of patches in each age bin [m2] @@ -459,6 +468,15 @@ module EDTypesMod real(r8) :: primary_land_patchfusion_error ! error term in total area of primary patches associated with patch fusion [m2/m2/day] real(r8) :: landuse_transition_matrix(n_landuse_cats, n_landuse_cats) ! land use transition matrix as read in from HLM and aggregated to FATES land use types [m2/m2/year] + real(r8) :: min_allowed_landuse_fraction ! minimum amount of land-use type below which the resulting patches would be too small [m2/m2] + logical, allocatable :: landuse_vector_gt_min(:) ! is the land use state vector for each land use type greater than the minimum below which we ignore? + logical :: transition_landuse_from_off_to_on ! special flag to use only when reading restarts, which triggers procedure to initialize land use + + contains + + procedure, public :: get_current_landuse_statevector + procedure, public :: get_secondary_young_fraction + end type ed_site_type ! Make public necessary subroutines and functions @@ -507,7 +525,8 @@ subroutine ZeroMassBalFlux(this) this%seed_in = 0._r8 this%seed_out = 0._r8 this%frag_out = 0._r8 - this%wood_product = 0._r8 + this%wood_product_harvest(:) = 0._r8 + this%wood_product_landusechange(:) = 0._r8 this%burn_flux_to_atm = 0._r8 this%flux_generic_in = 0._r8 this%flux_generic_out = 0._r8 @@ -533,7 +552,82 @@ subroutine dump_site(csite) write(fates_log(),*) '----------------------------------------' return -end subroutine dump_site + end subroutine dump_site + + ! ===================================================================================== + + function get_current_landuse_statevector(this) result(current_state_vector) + + ! + ! !DESCRIPTION: + ! Calculate how much of a site is each land use category. + ! this does not include bare ground when nocomp + fixed biogeography is on, + ! so will not sum to one in that case. otherwise it will sum to one. + ! + ! !USES: + ! + ! !ARGUMENTS: + class(ed_site_type) :: this + real(r8) :: current_state_vector(n_landuse_cats) + + ! !LOCAL VARIABLES: + type(fates_patch_type), pointer :: currentPatch + + current_state_vector(:) = 0._r8 + + currentPatch => this%oldest_patch + do while (associated(currentPatch)) + if (currentPatch%land_use_label .gt. nocomp_bareground_land) then + current_state_vector(currentPatch%land_use_label) = & + current_state_vector(currentPatch%land_use_label) + & + currentPatch%area/AREA + end if + currentPatch => currentPatch%younger + end do + + end function get_current_landuse_statevector + + ! ===================================================================================== + + function get_secondary_young_fraction(this) result(secondary_young_fraction) + + ! + ! !DESCRIPTION: + ! Calculate how much of the secondary area is "young", i.e. below the age threshold. + ! If no seconday patch area at all, return -1. + ! + ! !USES: + ! + ! !ARGUMENTS: + class(ed_site_type) :: this + real(r8) :: secondary_young_fraction + real(r8) :: secondary_young_area + real(r8) :: secondary_old_area + + ! !LOCAL VARIABLES: + type(fates_patch_type), pointer :: currentPatch + + secondary_young_area = 0._r8 + secondary_old_area = 0._r8 + + currentPatch => this%oldest_patch + do while (associated(currentPatch)) + if (currentPatch%land_use_label .eq. secondaryland) then + if ( currentPatch%age .ge. secondary_age_threshold ) then + secondary_old_area = secondary_old_area + currentPatch%area + else + secondary_young_area = secondary_young_area + currentPatch%area + end if + end if + currentPatch => currentPatch%younger + end do + + if ( (secondary_young_area + secondary_old_area) .gt. nearzero ) then + secondary_young_fraction = secondary_young_area / (secondary_young_area + secondary_old_area) + else + secondary_young_fraction = -1._r8 + endif + + end function get_secondary_young_fraction - end module EDTypesMod diff --git a/main/FatesConstantsMod.F90 b/main/FatesConstantsMod.F90 index b531957096..90033cb549 100644 --- a/main/FatesConstantsMod.F90 +++ b/main/FatesConstantsMod.F90 @@ -45,14 +45,21 @@ module FatesConstantsMod integer , parameter, public :: dtype_ilog = 3 ! index for logging generated disturbance event integer , parameter, public :: dtype_ilandusechange = 4 ! index for land use change disturbance (not including logging) - ! Labels for patch disturbance history + ! Labels for patch land use type information integer, parameter, public :: n_landuse_cats = 5 integer, parameter, public :: primaryland = 1 integer, parameter, public :: secondaryland = 2 integer, parameter, public :: rangeland = 3 integer, parameter, public :: pastureland = 4 integer, parameter, public :: cropland = 5 + logical, parameter, dimension(n_landuse_cats), public :: is_crop = [.false., .false.,.false.,.false.,.true.] + integer, parameter, public :: n_crop_lu_types = 1 + ! Bareground nocomp land use label + integer, parameter, public :: nocomp_bareground_land = 0 ! not a real land use type, only for labeling any bare-ground nocomp patches + + ! Bareground nocomp PFT label for no competition mode + integer, parameter, public :: nocomp_bareground = 0 integer, parameter, public :: leaves_on = 2 ! Flag specifying that a deciduous plant has leaves ! and should be allocating to them as well @@ -83,9 +90,6 @@ module FatesConstantsMod integer, parameter, public :: ican_ustory = 2 ! nominal index for diagnostics that refer to understory layers ! (all layers that are not the top canopy layer) - ! Bareground label for no competition mode - integer, parameter, public :: nocomp_bareground = 0 - ! Flags specifying how phosphorous uptake and turnover interacts ! with the host model. integer, public, parameter :: prescribed_p_uptake = 1 @@ -169,6 +173,9 @@ module FatesConstantsMod ! of magnitude of buffer error (ie instead of 1e-15) real(fates_r8), parameter, public :: rsnbl_math_prec = 1.0e-12_fates_r8 + ! in nocomp simulations, what is the minimum PFT fraction for any given land use type? + real(fates_r8), parameter, public :: min_nocomp_pftfrac_perlanduse = 0.01_fates_r8 + ! This is the precision of 8byte reals (~1e-308) real(fates_r8), parameter, public :: tinyr8 = tiny(1.0_fates_r8) diff --git a/main/FatesHistoryInterfaceMod.F90 b/main/FatesHistoryInterfaceMod.F90 index 6c34f48292..c5b48735f6 100644 --- a/main/FatesHistoryInterfaceMod.F90 +++ b/main/FatesHistoryInterfaceMod.F90 @@ -14,6 +14,7 @@ module FatesHistoryInterfaceMod use FatesConstantsMod , only : i_term_mort_type_cstarv use FatesConstantsMod , only : i_term_mort_type_canlev use FatesConstantsMod , only : i_term_mort_type_numdens + use FatesConstantsMod , only : nocomp_bareground_land use FatesGlobals , only : fates_log use FatesGlobals , only : endrun => fates_endrun use EDParamsMod , only : nclmax, maxpft @@ -88,6 +89,7 @@ module FatesHistoryInterfaceMod ! CIME Globals use shr_log_mod , only : errMsg => shr_log_errMsg use shr_infnan_mod , only : isnan => shr_infnan_isnan + use FatesConstantsMod , only : g_per_kg use FatesConstantsMod , only : kg_per_g use FatesConstantsMod , only : ha_per_m2 @@ -132,8 +134,6 @@ module FatesHistoryInterfaceMod use FatesSizeAgeTypeIndicesMod, only : get_cdamagesize_class_index use FatesSizeAgeTypeIndicesMod, only : get_cdamagesizepft_class_index use FatesSizeAgeTypeIndicesMod, only : coagetype_class_index - use FatesInterfaceTypesMod , only : nlevdamage - implicit none private ! By default everything is private @@ -360,14 +360,16 @@ module FatesHistoryInterfaceMod integer :: ih_area_si_landuse integer :: ih_disturbance_rate_si_lulu - + integer :: ih_transition_matrix_si_lulu + integer :: ih_fire_disturbance_rate_si integer :: ih_logging_disturbance_rate_si integer :: ih_fall_disturbance_rate_si - integer :: ih_harvest_carbonflux_si integer :: ih_harvest_debt_si integer :: ih_harvest_debt_sec_si - + integer :: ih_harvest_woodprod_carbonflux_si + integer :: ih_luchange_woodprod_carbonflux_si + ! Indices to site by size-class by age variables integer :: ih_nplant_si_scag integer :: ih_nplant_canopy_si_scag @@ -2430,7 +2432,6 @@ subroutine update_history_dyn1(this,nc,nsites,sites,bc_in) hio_fire_disturbance_rate_si => this%hvars(ih_fire_disturbance_rate_si)%r81d, & hio_logging_disturbance_rate_si => this%hvars(ih_logging_disturbance_rate_si)%r81d, & hio_fall_disturbance_rate_si => this%hvars(ih_fall_disturbance_rate_si)%r81d, & - hio_harvest_carbonflux_si => this%hvars(ih_harvest_carbonflux_si)%r81d, & hio_harvest_debt_si => this%hvars(ih_harvest_debt_si)%r81d, & hio_harvest_debt_sec_si => this%hvars(ih_harvest_debt_sec_si)%r81d, & hio_npp_leaf_si => this%hvars(ih_npp_leaf_si)%r81d, & @@ -2461,8 +2462,9 @@ subroutine update_history_dyn1(this,nc,nsites,sites,bc_in) hio_tlongterm => this%hvars(ih_tlongterm_si)%r81d, & hio_tgrowth => this%hvars(ih_tgrowth_si)%r81d, & hio_lai_si => this%hvars(ih_lai_si)%r81d, & - hio_elai_si => this%hvars(ih_elai_si)%r81d) - + hio_elai_si => this%hvars(ih_elai_si)%r81d, & + hio_harvest_woodprod_carbonflux_si => this%hvars(ih_harvest_woodprod_carbonflux_si)%r81d, & + hio_luchange_woodprod_carbonflux_si => this%hvars(ih_luchange_woodprod_carbonflux_si)%r81d) ! --------------------------------------------------------------------------------- ! Loop through the FATES scale hierarchy and fill the history IO arrays @@ -2564,9 +2566,12 @@ subroutine update_history_dyn1(this,nc,nsites,sites,bc_in) sum(sites(s)%disturbance_rates(dtype_ifall,1:n_landuse_cats,1:n_landuse_cats)) * & days_per_year - hio_harvest_carbonflux_si(io_si) = & - sites(s)%mass_balance(element_pos(carbon12_element))%wood_product * AREA_INV + hio_harvest_woodprod_carbonflux_si(io_si) = AREA_INV * & + sum(sites(s)%mass_balance(element_pos(carbon12_element))%wood_product_harvest(1:numpft)) + hio_luchange_woodprod_carbonflux_si(io_si) = AREA_INV * & + sum(sites(s)%mass_balance(element_pos(carbon12_element))%wood_product_landusechange(1:numpft)) + ! carbon flux associated with mortality of trees dying by fire hio_canopy_mortality_carbonflux_si(io_si) = hio_canopy_mortality_carbonflux_si(io_si) + & @@ -3300,7 +3305,8 @@ subroutine update_history_dyn2(this,nc,nsites,sites,bc_in) hio_nplant_canopy_si_scag => this%hvars(ih_nplant_canopy_si_scag)%r82d, & hio_nplant_understory_si_scag => this%hvars(ih_nplant_understory_si_scag)%r82d, & hio_disturbance_rate_si_lulu => this%hvars(ih_disturbance_rate_si_lulu)%r82d, & - hio_cstarvmortality_continuous_carbonflux_si_pft => this%hvars(ih_cstarvmortality_continuous_carbonflux_si_pft)%r82d) + hio_cstarvmortality_continuous_carbonflux_si_pft => this%hvars(ih_cstarvmortality_continuous_carbonflux_si_pft)%r82d, & + hio_transition_matrix_si_lulu => this%hvars(ih_transition_matrix_si_lulu)%r82d) model_day_int = nint(hlm_model_day) @@ -3327,17 +3333,22 @@ subroutine update_history_dyn2(this,nc,nsites,sites,bc_in) storep_understory_scpf(:) = 0._r8 storec_canopy_scpf(:) = 0._r8 storec_understory_scpf(:) = 0._r8 - - ! roll up disturbance rates in land-use x land-use array into a single dimension + do i_dist = 1, n_landuse_cats do j_dist = 1, n_landuse_cats + + ! roll up disturbance rates in land-use x land-use array into a single dimension hio_disturbance_rate_si_lulu(io_si, i_dist+n_landuse_cats*(j_dist-1)) = & sum(sites(s)%disturbance_rates(1:n_dist_types,i_dist, j_dist)) * & days_per_year + + ! get the land use transition matrix and output that to history. + ! (mainly a sanity check, can maybe remove before integration) + hio_transition_matrix_si_lulu(io_si, i_dist+n_landuse_cats*(j_dist-1)) = & + sites(s)%landuse_transition_matrix(i_dist, j_dist) end do end do - - + do el = 1, num_elements ! Total model error [kg/day -> kg/s] (all elements) @@ -3387,10 +3398,13 @@ subroutine update_history_dyn2(this,nc,nsites,sites,bc_in) hio_area_si_age(io_si,cpatch%age_class) = hio_area_si_age(io_si,cpatch%age_class) & + cpatch%area * AREA_INV - hio_area_si_landuse(io_si, cpatch%land_use_label) = & - hio_area_si_landuse(io_si, cpatch%land_use_label) & - + cpatch%area * AREA_INV - + ! ignore land use info on nocomp bareground (where landuse label = 0) + if (cpatch%land_use_label .gt. nocomp_bareground_land) then + hio_area_si_landuse(io_si, cpatch%land_use_label) = & + hio_area_si_landuse(io_si, cpatch%land_use_label) & + + cpatch%area * AREA_INV + end if + ! Increment some patch-age-resolved diagnostics hio_lai_si_age(io_si,cpatch%age_class) = hio_lai_si_age(io_si,cpatch%age_class) & + sum(cpatch%tlai_profile(:,:,:) * cpatch%canopy_area_profile(:,:,:) ) * cpatch%total_canopy_area @@ -5001,14 +5015,17 @@ subroutine update_history_hifrq1(this,nc,nsites,sites,bc_in,bc_out,dt_tstep) ! Diagnostics that are only relevant if there is vegetation present on this site ! ie, non-zero canopy area - - site_area_veg_inv = 0._r8 - cpatch => sites(s)%oldest_patch - do while(associated(cpatch)) - site_area_veg_inv = site_area_veg_inv + cpatch%total_canopy_area - cpatch => cpatch%younger - end do !patch loop - + if (hlm_use_nocomp .eq. itrue .and. hlm_use_fixed_biogeog .eq. itrue) then + site_area_veg_inv = area - sites(s)%area_bareground * area + else + site_area_veg_inv = 0._r8 + cpatch => sites(s)%oldest_patch + do while(associated(cpatch)) + site_area_veg_inv = site_area_veg_inv + cpatch%total_canopy_area + cpatch => cpatch%younger + end do !patch loop + end if + if_veg_area: if(site_area_veg_inv < nearzero) then hio_c_stomata_si(io_si) = hlm_hio_ignore_val @@ -6204,15 +6221,7 @@ subroutine define_history_vars(this, initialize_variables) upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index=ih_lai_secondary_si) - call this%set_history_var(vname='FATES_PATCHAREA_LU', units='m2 m-2', & - long='patch area by land use type', use_default='active', & - avgflag='A', vtype=site_landuse_r8, hlms='CLM:ALM', upfreq=group_dyna_simple, ivar=ivar, & - initialize=initialize_variables, index=ih_area_si_landuse) - - call this%set_history_var(vname='FATES_DISTURBANCE_RATE_MATRIX_LULU', units='m2 m-2 yr-1', & - long='disturbance rates by land use type x land use type matrix', use_default='active', & - avgflag='A', vtype=site_lulu_r8, hlms='CLM:ALM', upfreq=group_dyna_simple, ivar=ivar, & - initialize=initialize_variables, index=ih_disturbance_rate_si_lulu) + ! Secondary forest area and age diagnostics @@ -6599,14 +6608,21 @@ subroutine define_history_vars(this, initialize_variables) use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index = ih_fall_disturbance_rate_si) - - call this%set_history_var(vname='FATES_HARVEST_CARBON_FLUX', & + + call this%set_history_var(vname='FATES_HARVEST_WOODPROD_C_FLUX', & units='kg m-2 yr-1', & - long='harvest carbon flux in kg carbon per m2 per year', & + long='harvest-associated wood product carbon flux in kg C per m2 per year', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & - index = ih_harvest_carbonflux_si) - + index = ih_harvest_woodprod_carbonflux_si) + + call this%set_history_var(vname='FATES_LUCHANGE_WOODPROD_C_FLUX', & + units='kg m-2 yr-1', & + long='land-use-change-associated wood product carbon flux in kg C per m2 per year', & + use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & + upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & + index = ih_luchange_woodprod_carbonflux_si) + call this%set_history_var(vname='FATES_TVEG24', units='degree_Celsius', & long='fates 24-hr running mean vegetation temperature by site', & use_default='active', & @@ -6775,6 +6791,21 @@ subroutine define_history_vars(this, initialize_variables) if_dyn1: if(hlm_hist_level_dynam>1) then + call this%set_history_var(vname='FATES_PATCHAREA_LU', units='m2 m-2', & + long='patch area by land use type', use_default='active', & + avgflag='A', vtype=site_landuse_r8, hlms='CLM:ALM', upfreq=group_dyna_complx, & + ivar=ivar, initialize=initialize_variables, index=ih_area_si_landuse) + + call this%set_history_var(vname='FATES_TRANSITION_MATRIX_LULU', units='m2 m-2 yr-1', & + long='land use transition matrix', use_default='active', & + avgflag='A', vtype=site_lulu_r8, hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & + initialize=initialize_variables, index=ih_transition_matrix_si_lulu) + + call this%set_history_var(vname='FATES_DISTURBANCE_RATE_MATRIX_LULU', units='m2 m-2 yr-1', & + long='disturbance rates by land use type x land use type matrix', use_default='active', & + avgflag='A', vtype=site_lulu_r8, hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & + initialize=initialize_variables, index=ih_disturbance_rate_si_lulu) + call this%set_history_var(vname='FATES_VEGC_PF', units='kg m-2', & long='total PFT-level biomass in kg of carbon per land area', & use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & diff --git a/main/FatesInterfaceMod.F90 b/main/FatesInterfaceMod.F90 index 99e13fa5f4..eea65eaa0a 100644 --- a/main/FatesInterfaceMod.F90 +++ b/main/FatesInterfaceMod.F90 @@ -41,6 +41,7 @@ module FatesInterfaceMod use FatesConstantsMod , only : n_landuse_cats use FatesConstantsMod , only : primaryland use FatesConstantsMod , only : secondaryland + use FatesConstantsMod , only : n_crop_lu_types use FatesConstantsMod , only : n_term_mort_types use FatesGlobals , only : fates_global_verbose use FatesGlobals , only : fates_log @@ -417,7 +418,7 @@ end subroutine zero_bcs ! =========================================================================== subroutine allocate_bcin(bc_in, nlevsoil_in, nlevdecomp_in, num_lu_harvest_cats, num_luh2_states, & - num_luh2_transitions, natpft_lb,natpft_ub) + num_luh2_transitions, surfpft_lb,surfpft_ub) ! --------------------------------------------------------------------------------- ! Allocate and Initialze the FATES boundary condition vectors @@ -430,7 +431,7 @@ subroutine allocate_bcin(bc_in, nlevsoil_in, nlevdecomp_in, num_lu_harvest_cats, integer,intent(in) :: num_lu_harvest_cats integer,intent(in) :: num_luh2_states integer,intent(in) :: num_luh2_transitions - integer,intent(in) :: natpft_lb,natpft_ub ! dimension bounds of the array holding surface file pft data + integer,intent(in) :: surfpft_lb,surfpft_ub ! dimension bounds of the array holding surface file pft data ! Allocate input boundaries @@ -563,7 +564,13 @@ subroutine allocate_bcin(bc_in, nlevsoil_in, nlevdecomp_in, num_lu_harvest_cats, allocate(bc_in%hlm_harvest_catnames(0)) end if - allocate(bc_in%pft_areafrac(natpft_lb:natpft_ub)) + if ( hlm_use_fixed_biogeog .eq. itrue) then + if (hlm_use_luh .eq. itrue ) then + allocate(bc_in%pft_areafrac_lu(size( EDPftvarcon_inst%hlm_pft_map,2),n_landuse_cats-n_crop_lu_types)) + else + allocate(bc_in%pft_areafrac(surfpft_lb:surfpft_ub)) + endif + endif ! LUH2 state and transition data if (hlm_use_luh .eq. itrue) then @@ -575,10 +582,11 @@ subroutine allocate_bcin(bc_in, nlevsoil_in, nlevdecomp_in, num_lu_harvest_cats, ! Variables for SP mode. if(hlm_use_sp.eq.itrue) then - allocate(bc_in%hlm_sp_tlai(natpft_lb:natpft_ub)) - allocate(bc_in%hlm_sp_tsai(natpft_lb:natpft_ub)) - allocate(bc_in%hlm_sp_htop(natpft_lb:natpft_ub)) - end if + allocate(bc_in%hlm_sp_tlai(surfpft_lb:surfpft_ub)) + allocate(bc_in%hlm_sp_tsai(surfpft_lb:surfpft_ub)) + allocate(bc_in%hlm_sp_htop(surfpft_lb:surfpft_ub)) + end if + return end subroutine allocate_bcin @@ -611,14 +619,13 @@ subroutine allocate_bcout(bc_out, nlevsoil_in, nlevdecomp_in) allocate(bc_out%rssha_pa(maxpatch_total)) ! Canopy Radiation - allocate(bc_out%albd_parb(maxpatch_total,num_swb)) - allocate(bc_out%albi_parb(maxpatch_total,num_swb)) - allocate(bc_out%fabd_parb(maxpatch_total,num_swb)) - allocate(bc_out%fabi_parb(maxpatch_total,num_swb)) - allocate(bc_out%ftdd_parb(maxpatch_total,num_swb)) - allocate(bc_out%ftid_parb(maxpatch_total,num_swb)) - allocate(bc_out%ftii_parb(maxpatch_total,num_swb)) - + allocate(bc_out%albd_parb(fates_maxPatchesPerSite,num_swb)) + allocate(bc_out%albi_parb(fates_maxPatchesPerSite,num_swb)) + allocate(bc_out%fabd_parb(fates_maxPatchesPerSite,num_swb)) + allocate(bc_out%fabi_parb(fates_maxPatchesPerSite,num_swb)) + allocate(bc_out%ftdd_parb(fates_maxPatchesPerSite,num_swb)) + allocate(bc_out%ftid_parb(fates_maxPatchesPerSite,num_swb)) + allocate(bc_out%ftii_parb(fates_maxPatchesPerSite,num_swb)) ! We allocate the boundary conditions to the BGC ! model, regardless of what scheme we use. The BGC @@ -1930,6 +1937,12 @@ subroutine set_fates_ctrlparms(tag,ival,rval,cval) write(fates_log(),*) 'Transfering hlm_use_luh = ',ival,' to FATES' end if + case('use_fates_potentialveg') + hlm_use_potentialveg = ival + if (fates_global_verbose()) then + write(fates_log(),*) 'Transfering hlm_use_potentialveg = ',ival,' to FATES' + end if + case('num_luh2_states') hlm_num_luh2_states = ival if (fates_global_verbose()) then diff --git a/main/FatesInterfaceTypesMod.F90 b/main/FatesInterfaceTypesMod.F90 index a36d5195f4..75e64307a5 100644 --- a/main/FatesInterfaceTypesMod.F90 +++ b/main/FatesInterfaceTypesMod.F90 @@ -124,6 +124,8 @@ module FatesInterfaceTypesMod ! bc_in%hlm_harvest_rates and bc_in%hlm_harvest_catnames integer, public :: hlm_use_luh ! flag to signal whether or not to use luh2 drivers + integer, public :: hlm_use_potentialveg ! flag to signal whether or not to use potential vegetation only + ! (i.e., no land use and instead force all lands to be primary) integer, public :: hlm_num_luh2_states ! number of land use state types provided in LUH2 forcing dataset integer, public :: hlm_num_luh2_transitions ! number of land use transition types provided in LUH2 forcing dataset @@ -240,7 +242,7 @@ module FatesInterfaceTypesMod ! dataset than the number of PFTs in FATES, we have to allocate with ! the prior so that we can hold the LAI data integer, public :: fates_maxPatchesPerSite - + integer, public :: max_comp_per_site ! This is the maximum number of nutrient aquisition ! competitors that will be generated on each site @@ -572,7 +574,12 @@ module FatesInterfaceTypesMod real(r8) :: site_area ! Actual area of current site [m2], only used in carbon-based harvest ! Fixed biogeography mode - real(r8), allocatable :: pft_areafrac(:) ! Fractional area of the FATES column occupied by each PFT + real(r8), allocatable :: pft_areafrac(:) ! Fractional area of the FATES column occupied by each PFT + + ! Fixed biogeography mode with land use active + real(r8), allocatable :: pft_areafrac_lu(:,:) ! Fractional area occupied by each PFT on each land use type + real(r8) :: baregroundfrac ! fractional area held as bare-ground + ! Satellite Phenology (SP) input variables. (where each patch only has one PFT) ! --------------------------------------------------------------------------------- diff --git a/main/FatesRestartInterfaceMod.F90 b/main/FatesRestartInterfaceMod.F90 index ffef39eb6f..3f7e8375fe 100644 --- a/main/FatesRestartInterfaceMod.F90 +++ b/main/FatesRestartInterfaceMod.F90 @@ -10,6 +10,7 @@ module FatesRestartInterfaceMod use FatesConstantsMod, only : fates_unset_r8, fates_unset_int use FatesConstantsMod, only : primaryland use FatesConstantsMod, only : nearzero + use FatesConstantsMod, only : n_landuse_cats use FatesConstantsMod, only : default_regeneration use FatesConstantsMod, only : TRS_regeneration use FatesGlobals, only : fates_log @@ -24,6 +25,7 @@ module FatesRestartInterfaceMod use FatesInterfaceTypesMod, only : hlm_parteh_mode use FatesInterfaceTypesMod, only : hlm_use_sp use FatesInterfaceTypesMod, only : hlm_use_nocomp, hlm_use_fixed_biogeog + use FatesInterfaceTypesMod, only : hlm_use_potentialveg use FatesInterfaceTypesMod, only : fates_maxElementsPerSite use FatesInterfaceTypesMod, only : hlm_use_tree_damage use FatesHydraulicsMemMod, only : nshell @@ -101,9 +103,12 @@ module FatesRestartInterfaceMod integer :: ir_phenmodeldate_si integer :: ir_fireweather_index_si integer :: ir_gdd_si + integer :: ir_min_allowed_landuse_fraction_si + integer :: ir_landuse_vector_gt_min_si + integer :: ir_area_bareground_si integer :: ir_snow_depth_si integer :: ir_trunk_product_si - + integer :: ir_landuse_config_si integer :: ir_ncohort_pa integer :: ir_canopy_layer_co integer :: ir_canopy_layer_yesterday_co @@ -267,7 +272,8 @@ module FatesRestartInterfaceMod integer :: ir_rootlittin_flxdg integer :: ir_oldstock_mbal integer :: ir_errfates_mbal - integer :: ir_woodprod_mbal + integer :: ir_woodprod_harvest_mbal + integer :: ir_woodprod_landusechange_mbal integer :: ir_prt_base ! Base index for all PRT variables ! site-level input seed from dispersal @@ -710,6 +716,18 @@ subroutine define_restart_vars(this, initialize_variables) long_name='growing degree days at each site', units='degC days', flushval = flushzero, & hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_gdd_si ) + call this%set_restart_var(vname='fates_min_allowed_landuse_fraction_site', vtype=site_r8, & + long_name='minimum allowed land use fraction at each site', units='fraction', flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_min_allowed_landuse_fraction_si ) + + call this%set_restart_var(vname='fates_landuse_vector_gt_min_site', vtype=cohort_int, & + long_name='minimum allowed land use fraction at each site', units='logical', flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_landuse_vector_gt_min_si ) + + call this%set_restart_var(vname='fates_area_bareground_site', vtype=site_r8, & + long_name='minimum allowed land use fraction at each site', units='fraction', flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_area_bareground_si ) + call this%set_restart_var(vname='fates_snow_depth_site', vtype=site_r8, & long_name='average snow depth', units='m', flushval = flushzero, & hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_snow_depth_si ) @@ -719,6 +737,11 @@ subroutine define_restart_vars(this, initialize_variables) units='kgC/m2', flushval = flushzero, & hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_trunk_product_si ) + call this%set_restart_var(vname='fates_landuse_config_site', vtype=site_int, & + long_name='hlm_use_potentialveg status of run that created this restart file', & + units='kgC/m2', flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_landuse_config_si ) + ! ----------------------------------------------------------------------------------- ! Variables stored within cohort vectors ! Note: Some of these are multi-dimensional variables in the patch/site dimension @@ -1134,10 +1157,15 @@ subroutine define_restart_vars(this, initialize_variables) end if - call this%RegisterCohortVector(symbol_base='fates_woodproduct', vtype=site_r8, & - long_name_base='Current wood product flux', & + call this%RegisterCohortVector(symbol_base='fates_woodprod_harv', vtype=cohort_r8, & + long_name_base='Current wood product flux from harvest', & + units='kg/m2/day', veclength=num_elements, flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_woodprod_harvest_mbal) + + call this%RegisterCohortVector(symbol_base='fates_woodprod_luc', vtype=cohort_r8, & + long_name_base='Current wood product flux from land use change', & units='kg/m2/day', veclength=num_elements, flushval = flushzero, & - hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_woodprod_mbal) + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_woodprod_landusechange_mbal) ! Only register satellite phenology related restart variables if it is turned on! @@ -1995,6 +2023,7 @@ subroutine set_restart_vectors(this,nc,nsites,sites) integer :: io_idx_si_scpf_term ! loop counter for scls, pft, and termination type integer :: io_idx_si_pft_term ! loop counter for pft, and termination type integer :: io_idx_si_luludi ! site-level lu x lu x ndist index + integer :: io_idx_si_lu ! site-level lu index ! Some counters (for checking mostly) integer :: totalcohorts ! total cohort count on this thread (diagnostic) @@ -2017,6 +2046,7 @@ subroutine set_restart_vectors(this,nc,nsites,sites) integer :: i_cdam ! loop counter for damage integer :: icdi ! loop counter for damage integer :: icdj ! loop counter for damage + integer :: i_landuse,i_pflu ! loop counter for land use class integer :: i_term_type ! loop counter for termination type integer :: i_lu_donor, i_lu_receiver, i_dist ! loop counters for land use and disturbance @@ -2036,8 +2066,12 @@ subroutine set_restart_vectors(this,nc,nsites,sites) rio_phenmodeldate_si => this%rvars(ir_phenmodeldate_si)%int1d, & rio_fireweather_index_si => this%rvars(ir_fireweather_index_si)%r81d, & rio_gdd_si => this%rvars(ir_gdd_si)%r81d, & + rio_min_allowed_landuse_fraction_si => this%rvars(ir_min_allowed_landuse_fraction_si)%r81d, & + rio_landuse_vector_gt_min_si => this%rvars(ir_landuse_vector_gt_min_si)%int1d, & + rio_area_bareground_si => this%rvars(ir_area_bareground_si)%r81d, & rio_snow_depth_si => this%rvars(ir_snow_depth_si)%r81d, & rio_trunk_product_si => this%rvars(ir_trunk_product_si)%r81d, & + rio_landuse_config_s => this%rvars(ir_landuse_config_si)%int1d, & rio_ncohort_pa => this%rvars(ir_ncohort_pa)%int1d, & rio_fcansno_pa => this%rvars(ir_fcansno_pa)%r81d, & rio_solar_zenith_flag_pa => this%rvars(ir_solar_zenith_flag_pa)%int1d, & @@ -2130,6 +2164,7 @@ subroutine set_restart_vectors(this,nc,nsites,sites) rio_abg_fmort_flux_siscpf => this%rvars(ir_abg_fmort_flux_siscpf)%r81d, & rio_abg_term_flux_siscpf => this%rvars(ir_abg_term_flux_siscpf)%r81d, & rio_disturbance_rates_siluludi => this%rvars(ir_disturbance_rates_siluludi)%r81d, & + rio_landuse_config_si => this%rvars(ir_landuse_config_si)%int1d, & rio_imortrate_sicdpf => this%rvars(ir_imortrate_sicdpf)%r81d, & rio_imortcflux_sicdsc => this%rvars(ir_imortcflux_sicdsc)%r81d, & @@ -2182,6 +2217,7 @@ subroutine set_restart_vectors(this,nc,nsites,sites) io_idx_si_scpf_term = io_idx_co_1st io_idx_si_pft_term = io_idx_co_1st io_idx_si_luludi = io_idx_co_1st + io_idx_si_lu = io_idx_co_1st ! recruitment rate do i_pft = 1,numpft @@ -2193,9 +2229,24 @@ subroutine set_restart_vectors(this,nc,nsites,sites) end do do i_pft = 1,numpft - rio_area_pft_sift(io_idx_co_1st+i_pft-1) = sites(s)%area_pft(i_pft) + do i_landuse = 1, n_landuse_cats + i_pflu = i_landuse + (i_pft - 1) * n_landuse_cats + rio_area_pft_sift(io_idx_co_1st+i_pflu-1) = sites(s)%area_pft(i_pft, i_landuse) + end do end do + rio_min_allowed_landuse_fraction_si(io_idx_si) = sites(s)%min_allowed_landuse_fraction + do i_landuse = 1, n_landuse_cats + if ( sites(s)%landuse_vector_gt_min(i_landuse)) then + rio_landuse_vector_gt_min_si(io_idx_si_lu) = itrue + else + rio_landuse_vector_gt_min_si(io_idx_si_lu) = ifalse + endif + io_idx_si_lu = io_idx_si_lu + 1 + end do + + rio_area_bareground_si(io_idx_si) = sites(s)%area_bareground + do i_scls = 1, nlevsclass do i_pft = 1, numpft rio_fmortrate_cano_siscpf(io_idx_si_scpf) = sites(s)%fmort_rate_canopy(i_scls, i_pft) @@ -2262,12 +2313,13 @@ subroutine set_restart_vectors(this,nc,nsites,sites) do i_pft=1,numpft this%rvars(ir_leaflittin_flxdg+el-1)%r81d(io_idx_si_pft) = sites(s)%flux_diags(el)%leaf_litter_input(i_pft) this%rvars(ir_rootlittin_flxdg+el-1)%r81d(io_idx_si_pft) = sites(s)%flux_diags(el)%root_litter_input(i_pft) + this%rvars(ir_woodprod_harvest_mbal+el-1)%r81d(io_idx_si_pft) = sites(s)%mass_balance(el)%wood_product_harvest(i_pft) + this%rvars(ir_woodprod_landusechange_mbal+el-1)%r81d(io_idx_si_pft) = sites(s)%mass_balance(el)%wood_product_landusechange(i_pft) io_idx_si_pft = io_idx_si_pft + 1 end do this%rvars(ir_oldstock_mbal+el-1)%r81d(io_idx_si) = sites(s)%mass_balance(el)%old_stock this%rvars(ir_errfates_mbal+el-1)%r81d(io_idx_si) = sites(s)%mass_balance(el)%err_fates - this%rvars(ir_woodprod_mbal+el-1)%r81d(io_idx_si) = sites(s)%mass_balance(el)%wood_product end do end if @@ -2643,6 +2695,10 @@ subroutine set_restart_vectors(this,nc,nsites,sites) ! Accumulated trunk product rio_trunk_product_si(io_idx_si) = sites(s)%resources_management%trunk_product_site + + ! land use flag + rio_landuse_config_si(io_idx_si) = hlm_use_potentialveg + ! set numpatches for this column rio_npatch_si(io_idx_si) = patchespersite @@ -2970,6 +3026,7 @@ subroutine get_restart_vectors(this, nc, nsites, sites) integer :: io_idx_si_scpf_term ! loop counter for scls, pft, and termination type integer :: io_idx_si_pft_term ! loop counter for pft, and termination type integer :: io_idx_si_luludi ! site-level lu x lu x ndist index + integer :: io_idx_si_lu ! site-level lu x lu x ndist index ! Some counters (for checking mostly) integer :: totalcohorts ! total cohort count on this thread (diagnostic) @@ -2989,8 +3046,9 @@ subroutine get_restart_vectors(this, nc, nsites, sites) integer :: i_cdam ! loop counter for damage class integer :: icdj ! loop counter for damage class integer :: icdi ! loop counter for damage class + integer :: i_landuse,i_pflu ! loop counter for land use class + integer :: i_lu_donor, i_lu_receiver, i_dist ! loop counters for land use and disturbance integer :: i_term_type ! loop counter for termination type - integer :: i_lu_donor, i_lu_receiver, i_dist ! loop counters for land use and disturbance associate( rio_npatch_si => this%rvars(ir_npatch_si)%int1d, & rio_cd_status_si => this%rvars(ir_cd_status_si)%int1d, & @@ -3003,8 +3061,12 @@ subroutine get_restart_vectors(this, nc, nsites, sites) rio_phenmodeldate_si => this%rvars(ir_phenmodeldate_si)%int1d, & rio_fireweather_index_si => this%rvars(ir_fireweather_index_si)%r81d, & rio_gdd_si => this%rvars(ir_gdd_si)%r81d, & + rio_min_allowed_landuse_fraction_si => this%rvars(ir_min_allowed_landuse_fraction_si)%r81d, & + rio_landuse_vector_gt_min_si => this%rvars(ir_landuse_vector_gt_min_si)%int1d, & + rio_area_bareground_si => this%rvars(ir_area_bareground_si)%r81d, & rio_snow_depth_si => this%rvars(ir_snow_depth_si)%r81d, & rio_trunk_product_si => this%rvars(ir_trunk_product_si)%r81d, & + rio_landuse_config_si => this%rvars(ir_landuse_config_si)%int1d, & rio_ncohort_pa => this%rvars(ir_ncohort_pa)%int1d, & rio_fcansno_pa => this%rvars(ir_fcansno_pa)%r81d, & rio_solar_zenith_flag_pa => this%rvars(ir_solar_zenith_flag_pa)%int1d, & @@ -3140,6 +3202,7 @@ subroutine get_restart_vectors(this, nc, nsites, sites) io_idx_si_pft_term = io_idx_co_1st io_idx_si_luludi = io_idx_co_1st + io_idx_si_lu = io_idx_co_1st ! read seed_bank info(site-level, but PFT-resolved) do i_pft = 1,numpft @@ -3149,17 +3212,22 @@ subroutine get_restart_vectors(this, nc, nsites, sites) ! variables for fixed biogeography mode. These are currently used in restart even when this is off. do i_pft = 1,numpft sites(s)%use_this_pft(i_pft) = rio_use_this_pft_sift(io_idx_co_1st+i_pft-1) - sites(s)%area_pft(i_pft) = rio_area_pft_sift(io_idx_co_1st+i_pft-1) + do i_landuse = 1, n_landuse_cats + i_pflu = i_landuse + (i_pft - 1) * n_landuse_cats + sites(s)%area_pft(i_pft, i_landuse) = rio_area_pft_sift(io_idx_co_1st+i_pflu-1) + end do enddo - ! calculate the bareground area for the pft in no competition + fixed biogeo modes - if (hlm_use_nocomp .eq. itrue .and. hlm_use_fixed_biogeog .eq. itrue) then - if (area-sum(sites(s)%area_pft(1:numpft)) .gt. nearzero) then - sites(s)%area_pft(0) = area - sum(sites(s)%area_pft(1:numpft)) + sites(s)%min_allowed_landuse_fraction = rio_min_allowed_landuse_fraction_si(io_idx_si) + do i_landuse = 1, n_landuse_cats + if ( rio_landuse_vector_gt_min_si(io_idx_si_lu) .eq. itrue ) then + sites(s)%landuse_vector_gt_min(i_landuse) = .true. else - sites(s)%area_pft(0) = 0.0_r8 + sites(s)%landuse_vector_gt_min(i_landuse) = .false. endif - endif + io_idx_si_lu = io_idx_si_lu + 1 + end do + sites(s)%area_bareground = rio_area_bareground_si(io_idx_si) do i_scls = 1,nlevsclass do i_pft = 1, numpft @@ -3228,12 +3296,13 @@ subroutine get_restart_vectors(this, nc, nsites, sites) do i_pft=1,numpft sites(s)%flux_diags(el)%leaf_litter_input(i_pft) = this%rvars(ir_leaflittin_flxdg+el-1)%r81d(io_idx_si_pft) sites(s)%flux_diags(el)%root_litter_input(i_pft) = this%rvars(ir_rootlittin_flxdg+el-1)%r81d(io_idx_si_pft) + sites(s)%mass_balance(el)%wood_product_harvest(i_pft) = this%rvars(ir_woodprod_harvest_mbal+el-1)%r81d(io_idx_si_pft) + sites(s)%mass_balance(el)%wood_product_landusechange(i_pft) = this%rvars(ir_woodprod_landusechange_mbal+el-1)%r81d(io_idx_si_pft) io_idx_si_pft = io_idx_si_pft + 1 end do sites(s)%mass_balance(el)%old_stock = this%rvars(ir_oldstock_mbal+el-1)%r81d(io_idx_si) sites(s)%mass_balance(el)%err_fates = this%rvars(ir_errfates_mbal+el-1)%r81d(io_idx_si) - sites(s)%mass_balance(el)%wood_product = this%rvars(ir_woodprod_mbal+el-1)%r81d(io_idx_si) end do end if @@ -3647,6 +3716,18 @@ subroutine get_restart_vectors(this, nc, nsites, sites) sites(s)%snow_depth = rio_snow_depth_si(io_idx_si) sites(s)%resources_management%trunk_product_site = rio_trunk_product_si(io_idx_si) + ! if needed, trigger the special procedure to initialize land use structure from a + ! restart run that did not include land use. + if (rio_landuse_config_si(io_idx_si) .eq. itrue .and. hlm_use_potentialveg .eq. ifalse) then + sites(s)%transition_landuse_from_off_to_on = .true. + else if ( rio_landuse_config_si(io_idx_si) .ne. hlm_use_potentialveg ) then + ! can't go back into potential vegetation mode, it is a one-way thing. + write(fates_log(),*) 'this combination of rio_landuse_config_si(io_idx_si) and hlm_use_potentialveg is not permitted' + write(fates_log(),*) 'rio_landuse_config_si(io_idx_si)', rio_landuse_config_si(io_idx_si) + write(fates_log(),*) 'hlm_use_potentialveg', hlm_use_potentialveg + call endrun(msg=errMsg(sourcefile, __LINE__)) + endif + end do if ( debug ) then diff --git a/main/FatesRunningMeanMod.F90 b/main/FatesRunningMeanMod.F90 index 7ef7866d62..721030b974 100644 --- a/main/FatesRunningMeanMod.F90 +++ b/main/FatesRunningMeanMod.F90 @@ -328,6 +328,9 @@ subroutine FuseRMean(this,donor,recip_wgt) if (this%c_index .ne. donor%c_index) then write(fates_log(), *) 'trying to fuse two fixed-window averages' write(fates_log(), *) 'that are at different points in the window?' + write(fates_log(), *) 'c_mean', this%c_mean, donor%c_mean + write(fates_log(), *) 'l_mean', this%l_mean, donor%l_mean + write(fates_log(), *) 'c_index', this%c_index, donor%c_index call endrun(msg=errMsg(sourcefile, __LINE__)) end if end if diff --git a/parameter_files/archive/api36.0.0_051724_params_default.cdl b/parameter_files/archive/api36.0.0_051724_params_default.cdl new file mode 100644 index 0000000000..2a909ee340 --- /dev/null +++ b/parameter_files/archive/api36.0.0_051724_params_default.cdl @@ -0,0 +1,1776 @@ +netcdf tmp { +dimensions: + fates_NCWD = 4 ; + fates_history_age_bins = 7 ; + fates_history_coage_bins = 2 ; + fates_history_damage_bins = 2 ; + fates_history_height_bins = 6 ; + fates_history_size_bins = 13 ; + fates_hlm_pftno = 14 ; + fates_hydr_organs = 4 ; + fates_landuseclass = 5 ; + fates_leafage_class = 1 ; + fates_litterclass = 6 ; + fates_pft = 12 ; + fates_plant_organs = 4 ; + fates_string_length = 60 ; +variables: + double fates_history_ageclass_bin_edges(fates_history_age_bins) ; + fates_history_ageclass_bin_edges:units = "yr" ; + fates_history_ageclass_bin_edges:long_name = "Lower edges for age class bins used in age-resolved patch history output" ; + double fates_history_coageclass_bin_edges(fates_history_coage_bins) ; + fates_history_coageclass_bin_edges:units = "years" ; + fates_history_coageclass_bin_edges:long_name = "Lower edges for cohort age class bins used in cohort age resolved history output" ; + double fates_history_height_bin_edges(fates_history_height_bins) ; + fates_history_height_bin_edges:units = "m" ; + fates_history_height_bin_edges:long_name = "Lower edges for height bins used in height-resolved history output" ; + double fates_history_damage_bin_edges(fates_history_damage_bins) ; + fates_history_damage_bin_edges:units = "% crown loss" ; + fates_history_damage_bin_edges:long_name = "Lower edges for damage class bins used in cohort history output" ; + double fates_history_sizeclass_bin_edges(fates_history_size_bins) ; + fates_history_sizeclass_bin_edges:units = "cm" ; + fates_history_sizeclass_bin_edges:long_name = "Lower edges for DBH size class bins used in size-resolved cohort history output" ; + double fates_alloc_organ_id(fates_plant_organs) ; + fates_alloc_organ_id:units = "unitless" ; + fates_alloc_organ_id:long_name = "This is the global index that the organ in this file is associated with, values match those in parteh/PRTGenericMod.F90" ; + double fates_hydro_htftype_node(fates_hydr_organs) ; + fates_hydro_htftype_node:units = "unitless" ; + fates_hydro_htftype_node:long_name = "Switch that defines the hydraulic transfer functions for each organ." ; + char fates_pftname(fates_pft, fates_string_length) ; + fates_pftname:units = "unitless - string" ; + fates_pftname:long_name = "Description of plant type" ; + char fates_hydro_organ_name(fates_hydr_organs, fates_string_length) ; + fates_hydro_organ_name:units = "unitless - string" ; + fates_hydro_organ_name:long_name = "Name of plant hydraulics organs (DONT CHANGE, order matches media list in FatesHydraulicsMemMod.F90)" ; + char fates_alloc_organ_name(fates_plant_organs, fates_string_length) ; + fates_alloc_organ_name:units = "unitless - string" ; + fates_alloc_organ_name:long_name = "Name of plant organs (with alloc_organ_id, must match PRTGenericMod.F90)" ; + char fates_landuseclass_name(fates_landuseclass, fates_string_length) ; + fates_landuseclass_name:units = "unitless - string" ; + fates_landuseclass_name:long_name = "Name of the land use classes, for variables associated with dimension fates_landuseclass" ; + char fates_litterclass_name(fates_litterclass, fates_string_length) ; + fates_litterclass_name:units = "unitless - string" ; + fates_litterclass_name:long_name = "Name of the litter classes, for variables associated with dimension fates_litterclass" ; + double fates_alloc_organ_priority(fates_plant_organs, fates_pft) ; + fates_alloc_organ_priority:units = "index" ; + fates_alloc_organ_priority:long_name = "Priority level for allocation, 1: replaces turnover from storage, 2: same priority as storage use/replacement, 3: ascending in order of least importance" ; + double fates_alloc_storage_cushion(fates_pft) ; + fates_alloc_storage_cushion:units = "fraction" ; + fates_alloc_storage_cushion:long_name = "maximum size of storage C pool, relative to maximum size of leaf C pool" ; + double fates_alloc_store_priority_frac(fates_pft) ; + fates_alloc_store_priority_frac:units = "unitless" ; + fates_alloc_store_priority_frac:long_name = "for high-priority organs, the fraction of their turnover demand that is gauranteed to be replaced, and if need-be by storage" ; + double fates_allom_agb1(fates_pft) ; + fates_allom_agb1:units = "variable" ; + fates_allom_agb1:long_name = "Parameter 1 for agb allometry" ; + double fates_allom_agb2(fates_pft) ; + fates_allom_agb2:units = "variable" ; + fates_allom_agb2:long_name = "Parameter 2 for agb allometry" ; + double fates_allom_agb3(fates_pft) ; + fates_allom_agb3:units = "variable" ; + fates_allom_agb3:long_name = "Parameter 3 for agb allometry" ; + double fates_allom_agb4(fates_pft) ; + fates_allom_agb4:units = "variable" ; + fates_allom_agb4:long_name = "Parameter 4 for agb allometry" ; + double fates_allom_agb_frac(fates_pft) ; + fates_allom_agb_frac:units = "fraction" ; + fates_allom_agb_frac:long_name = "Fraction of woody biomass that is above ground" ; + double fates_allom_amode(fates_pft) ; + fates_allom_amode:units = "index" ; + fates_allom_amode:long_name = "AGB allometry function index." ; + double fates_allom_blca_expnt_diff(fates_pft) ; + fates_allom_blca_expnt_diff:units = "unitless" ; + fates_allom_blca_expnt_diff:long_name = "difference between allometric DBH:bleaf and DBH:crown area exponents" ; + double fates_allom_cmode(fates_pft) ; + fates_allom_cmode:units = "index" ; + fates_allom_cmode:long_name = "coarse root biomass allometry function index." ; + double fates_allom_d2bl1(fates_pft) ; + fates_allom_d2bl1:units = "variable" ; + fates_allom_d2bl1:long_name = "Parameter 1 for d2bl allometry" ; + double fates_allom_d2bl2(fates_pft) ; + fates_allom_d2bl2:units = "variable" ; + fates_allom_d2bl2:long_name = "Parameter 2 for d2bl allometry" ; + double fates_allom_d2bl3(fates_pft) ; + fates_allom_d2bl3:units = "unitless" ; + fates_allom_d2bl3:long_name = "Parameter 3 for d2bl allometry" ; + double fates_allom_d2ca_coefficient_max(fates_pft) ; + fates_allom_d2ca_coefficient_max:units = "m2 cm^(-1/beta)" ; + fates_allom_d2ca_coefficient_max:long_name = "max (savanna) dbh to area multiplier factor where: area = n*d2ca_coeff*dbh^beta" ; + double fates_allom_d2ca_coefficient_min(fates_pft) ; + fates_allom_d2ca_coefficient_min:units = "m2 cm^(-1/beta)" ; + fates_allom_d2ca_coefficient_min:long_name = "min (forest) dbh to area multiplier factor where: area = n*d2ca_coeff*dbh^beta" ; + double fates_allom_d2h1(fates_pft) ; + fates_allom_d2h1:units = "variable" ; + fates_allom_d2h1:long_name = "Parameter 1 for d2h allometry (intercept, or c)" ; + double fates_allom_d2h2(fates_pft) ; + fates_allom_d2h2:units = "variable" ; + fates_allom_d2h2:long_name = "Parameter 2 for d2h allometry (slope, or m)" ; + double fates_allom_d2h3(fates_pft) ; + fates_allom_d2h3:units = "variable" ; + fates_allom_d2h3:long_name = "Parameter 3 for d2h allometry (optional)" ; + double fates_allom_dbh_maxheight(fates_pft) ; + fates_allom_dbh_maxheight:units = "cm" ; + fates_allom_dbh_maxheight:long_name = "the diameter (if any) corresponding to maximum height, diameters may increase beyond this" ; + double fates_allom_dmode(fates_pft) ; + fates_allom_dmode:units = "index" ; + fates_allom_dmode:long_name = "crown depth allometry function index" ; + double fates_allom_fmode(fates_pft) ; + fates_allom_fmode:units = "index" ; + fates_allom_fmode:long_name = "fine root biomass allometry function index." ; + double fates_allom_fnrt_prof_a(fates_pft) ; + fates_allom_fnrt_prof_a:units = "unitless" ; + fates_allom_fnrt_prof_a:long_name = "Fine root profile function, parameter a" ; + double fates_allom_fnrt_prof_b(fates_pft) ; + fates_allom_fnrt_prof_b:units = "unitless" ; + fates_allom_fnrt_prof_b:long_name = "Fine root profile function, parameter b" ; + double fates_allom_fnrt_prof_mode(fates_pft) ; + fates_allom_fnrt_prof_mode:units = "index" ; + fates_allom_fnrt_prof_mode:long_name = "Index to select fine root profile function: 1) Jackson Beta, 2) 1-param exponential 3) 2-param exponential" ; + double fates_allom_frbstor_repro(fates_pft) ; + fates_allom_frbstor_repro:units = "fraction" ; + fates_allom_frbstor_repro:long_name = "fraction of bstore goes to reproduction after plant dies" ; + double fates_allom_h2cd1(fates_pft) ; + fates_allom_h2cd1:units = "variable" ; + fates_allom_h2cd1:long_name = "Parameter 1 for h2cd allometry (exp(log-intercept) or scaling). If allom_dmode=1; this is the same as former crown_depth_frac parameter" ; + double fates_allom_h2cd2(fates_pft) ; + fates_allom_h2cd2:units = "variable" ; + fates_allom_h2cd2:long_name = "Parameter 2 for h2cd allometry (log-slope or exponent). If allom_dmode=1; this is not needed (as exponent is assumed 1)" ; + double fates_allom_hmode(fates_pft) ; + fates_allom_hmode:units = "index" ; + fates_allom_hmode:long_name = "height allometry function index." ; + double fates_allom_l2fr(fates_pft) ; + fates_allom_l2fr:units = "gC/gC" ; + fates_allom_l2fr:long_name = "Allocation parameter: fine root C per leaf C" ; + double fates_allom_la_per_sa_int(fates_pft) ; + fates_allom_la_per_sa_int:units = "m2/cm2" ; + fates_allom_la_per_sa_int:long_name = "Leaf area per sapwood area, intercept" ; + double fates_allom_la_per_sa_slp(fates_pft) ; + fates_allom_la_per_sa_slp:units = "m2/cm2/m" ; + fates_allom_la_per_sa_slp:long_name = "Leaf area per sapwood area rate of change with height, slope (optional)" ; + double fates_allom_lmode(fates_pft) ; + fates_allom_lmode:units = "index" ; + fates_allom_lmode:long_name = "leaf biomass allometry function index." ; + double fates_allom_sai_scaler(fates_pft) ; + fates_allom_sai_scaler:units = "m2/m2" ; + fates_allom_sai_scaler:long_name = "allometric ratio of SAI per LAI" ; + double fates_allom_smode(fates_pft) ; + fates_allom_smode:units = "index" ; + fates_allom_smode:long_name = "sapwood allometry function index." ; + double fates_allom_stmode(fates_pft) ; + fates_allom_stmode:units = "index" ; + fates_allom_stmode:long_name = "storage allometry function index: 1) Storage proportional to leaf biomass (with trimming), 2) Storage proportional to maximum leaf biomass (not trimmed)" ; + double fates_allom_zroot_k(fates_pft) ; + fates_allom_zroot_k:units = "unitless" ; + fates_allom_zroot_k:long_name = "scale coefficient of logistic rooting depth model" ; + double fates_allom_zroot_max_dbh(fates_pft) ; + fates_allom_zroot_max_dbh:units = "cm" ; + fates_allom_zroot_max_dbh:long_name = "dbh at which a plant reaches the maximum value for its maximum rooting depth" ; + double fates_allom_zroot_max_z(fates_pft) ; + fates_allom_zroot_max_z:units = "m" ; + fates_allom_zroot_max_z:long_name = "the maximum rooting depth defined at dbh = fates_allom_zroot_max_dbh. note: max_z=min_z=large, sets rooting depth to soil depth" ; + double fates_allom_zroot_min_dbh(fates_pft) ; + fates_allom_zroot_min_dbh:units = "cm" ; + fates_allom_zroot_min_dbh:long_name = "dbh at which the maximum rooting depth for a recruit is defined" ; + double fates_allom_zroot_min_z(fates_pft) ; + fates_allom_zroot_min_z:units = "m" ; + fates_allom_zroot_min_z:long_name = "the maximum rooting depth defined at dbh = fates_allom_zroot_min_dbh. note: max_z=min_z=large, sets rooting depth to soil depth" ; + double fates_c2b(fates_pft) ; + fates_c2b:units = "ratio" ; + fates_c2b:long_name = "Carbon to biomass multiplier of bulk structural tissues" ; + double fates_cnp_eca_alpha_ptase(fates_pft) ; + fates_cnp_eca_alpha_ptase:units = "g/m3" ; + fates_cnp_eca_alpha_ptase:long_name = "(INACTIVE, KEEP AT 0) fraction of P from ptase activity sent directly to plant (ECA)" ; + double fates_cnp_eca_decompmicc(fates_pft) ; + fates_cnp_eca_decompmicc:units = "gC/m3" ; + fates_cnp_eca_decompmicc:long_name = "maximum soil microbial decomposer biomass found over depth (will be applied at a reference depth w/ exponential attenuation) (ECA)" ; + double fates_cnp_eca_km_nh4(fates_pft) ; + fates_cnp_eca_km_nh4:units = "gN/m3" ; + fates_cnp_eca_km_nh4:long_name = "half-saturation constant for plant nh4 uptake (ECA)" ; + double fates_cnp_eca_km_no3(fates_pft) ; + fates_cnp_eca_km_no3:units = "gN/m3" ; + fates_cnp_eca_km_no3:long_name = "half-saturation constant for plant no3 uptake (ECA)" ; + double fates_cnp_eca_km_p(fates_pft) ; + fates_cnp_eca_km_p:units = "gP/m3" ; + fates_cnp_eca_km_p:long_name = "half-saturation constant for plant p uptake (ECA)" ; + double fates_cnp_eca_km_ptase(fates_pft) ; + fates_cnp_eca_km_ptase:units = "gP/m3" ; + fates_cnp_eca_km_ptase:long_name = "half-saturation constant for biochemical P (ECA)" ; + double fates_cnp_eca_lambda_ptase(fates_pft) ; + fates_cnp_eca_lambda_ptase:units = "g/m3" ; + fates_cnp_eca_lambda_ptase:long_name = "(INACTIVE, KEEP AT 0) critical value for biochemical production (ECA)" ; + double fates_cnp_eca_vmax_ptase(fates_pft) ; + fates_cnp_eca_vmax_ptase:units = "gP/m2/s" ; + fates_cnp_eca_vmax_ptase:long_name = "maximum production rate for biochemical P (per m2) (ECA)" ; + double fates_cnp_nfix1(fates_pft) ; + fates_cnp_nfix1:units = "fraction" ; + fates_cnp_nfix1:long_name = "fractional surcharge added to maintenance respiration that drives symbiotic fixation" ; + double fates_cnp_nitr_store_ratio(fates_pft) ; + fates_cnp_nitr_store_ratio:units = "(gN/gN)" ; + fates_cnp_nitr_store_ratio:long_name = "storeable (labile) N, as a ratio compared to the N bound in cell structures of other organs (see code)" ; + double fates_cnp_phos_store_ratio(fates_pft) ; + fates_cnp_phos_store_ratio:units = "(gP/gP)" ; + fates_cnp_phos_store_ratio:long_name = "storeable (labile) P, as a ratio compared to the P bound in cell structures of other organs (see code)" ; + double fates_cnp_pid_kd(fates_pft) ; + fates_cnp_pid_kd:units = "unknown" ; + fates_cnp_pid_kd:long_name = "derivative constant of the PID controller on adaptive fine-root biomass" ; + double fates_cnp_pid_ki(fates_pft) ; + fates_cnp_pid_ki:units = "unknown" ; + fates_cnp_pid_ki:long_name = "integral constant of the PID controller on adaptive fine-root biomass" ; + double fates_cnp_pid_kp(fates_pft) ; + fates_cnp_pid_kp:units = "unknown" ; + fates_cnp_pid_kp:long_name = "proportional constant of the PID controller on adaptive fine-root biomass" ; + double fates_cnp_prescribed_nuptake(fates_pft) ; + fates_cnp_prescribed_nuptake:units = "fraction" ; + fates_cnp_prescribed_nuptake:long_name = "Prescribed N uptake flux. 0=fully coupled simulation >0=prescribed (experimental)" ; + double fates_cnp_prescribed_puptake(fates_pft) ; + fates_cnp_prescribed_puptake:units = "fraction" ; + fates_cnp_prescribed_puptake:long_name = "Prescribed P uptake flux. 0=fully coupled simulation, >0=prescribed (experimental)" ; + double fates_cnp_store_ovrflw_frac(fates_pft) ; + fates_cnp_store_ovrflw_frac:units = "fraction" ; + fates_cnp_store_ovrflw_frac:long_name = "size of overflow storage (for excess C,N or P) as a fraction of storage target" ; + double fates_cnp_turnover_nitr_retrans(fates_plant_organs, fates_pft) ; + fates_cnp_turnover_nitr_retrans:units = "fraction" ; + fates_cnp_turnover_nitr_retrans:long_name = "retranslocation (reabsorbtion) fraction of nitrogen in turnover of scenescing tissues" ; + double fates_cnp_turnover_phos_retrans(fates_plant_organs, fates_pft) ; + fates_cnp_turnover_phos_retrans:units = "fraction" ; + fates_cnp_turnover_phos_retrans:long_name = "retranslocation (reabsorbtion) fraction of phosphorus in turnover of scenescing tissues" ; + double fates_cnp_vmax_nh4(fates_pft) ; + fates_cnp_vmax_nh4:units = "gN/gC/s" ; + fates_cnp_vmax_nh4:long_name = "maximum (potential) uptake rate of NH4 per gC of fineroot biomass (see main/EDPftvarcon.F90 vmax_nh4 for usage)" ; + double fates_cnp_vmax_no3(fates_pft) ; + fates_cnp_vmax_no3:units = "gN/gC/s" ; + fates_cnp_vmax_no3:long_name = "maximum (potential) uptake rate of NO3 per gC of fineroot biomass (see main/EDPftvarcon.F90 vmax_no3 for usage)" ; + double fates_cnp_vmax_p(fates_pft) ; + fates_cnp_vmax_p:units = "gP/gC/s" ; + fates_cnp_vmax_p:long_name = "maximum production rate for phosphorus (ECA and RD)" ; + double fates_damage_frac(fates_pft) ; + fates_damage_frac:units = "fraction" ; + fates_damage_frac:long_name = "fraction of cohort damaged in each damage event (event frequency specified in the is_it_damage_time subroutine)" ; + double fates_damage_mort_p1(fates_pft) ; + fates_damage_mort_p1:units = "fraction" ; + fates_damage_mort_p1:long_name = "inflection point of damage mortality function, a value of 0.8 means 50% mortality with 80% loss of crown, turn off with a large number" ; + double fates_damage_mort_p2(fates_pft) ; + fates_damage_mort_p2:units = "unitless" ; + fates_damage_mort_p2:long_name = "rate of mortality increase with damage" ; + double fates_damage_recovery_scalar(fates_pft) ; + fates_damage_recovery_scalar:units = "unitless" ; + fates_damage_recovery_scalar:long_name = "fraction of the cohort that recovers from damage" ; + double fates_dev_arbitrary_pft(fates_pft) ; + fates_dev_arbitrary_pft:units = "unknown" ; + fates_dev_arbitrary_pft:long_name = "Unassociated pft dimensioned free parameter that developers can use for testing arbitrary new hypotheses" ; + double fates_fire_alpha_SH(fates_pft) ; + fates_fire_alpha_SH:units = "m / (kw/m)**(2/3)" ; + fates_fire_alpha_SH:long_name = "spitfire parameter, alpha scorch height, Equation 16 Thonicke et al 2010" ; + double fates_fire_bark_scaler(fates_pft) ; + fates_fire_bark_scaler:units = "fraction" ; + fates_fire_bark_scaler:long_name = "the thickness of a cohorts bark as a fraction of its dbh" ; + double fates_fire_crown_kill(fates_pft) ; + fates_fire_crown_kill:units = "NA" ; + fates_fire_crown_kill:long_name = "fire parameter, see equation 22 in Thonicke et al 2010" ; + double fates_frag_fnrt_fcel(fates_pft) ; + fates_frag_fnrt_fcel:units = "fraction" ; + fates_frag_fnrt_fcel:long_name = "Fine root litter cellulose fraction" ; + double fates_frag_fnrt_flab(fates_pft) ; + fates_frag_fnrt_flab:units = "fraction" ; + fates_frag_fnrt_flab:long_name = "Fine root litter labile fraction" ; + double fates_frag_fnrt_flig(fates_pft) ; + fates_frag_fnrt_flig:units = "fraction" ; + fates_frag_fnrt_flig:long_name = "Fine root litter lignin fraction" ; + double fates_frag_leaf_fcel(fates_pft) ; + fates_frag_leaf_fcel:units = "fraction" ; + fates_frag_leaf_fcel:long_name = "Leaf litter cellulose fraction" ; + double fates_frag_leaf_flab(fates_pft) ; + fates_frag_leaf_flab:units = "fraction" ; + fates_frag_leaf_flab:long_name = "Leaf litter labile fraction" ; + double fates_frag_leaf_flig(fates_pft) ; + fates_frag_leaf_flig:units = "fraction" ; + fates_frag_leaf_flig:long_name = "Leaf litter lignin fraction" ; + double fates_frag_seed_decay_rate(fates_pft) ; + fates_frag_seed_decay_rate:units = "yr-1" ; + fates_frag_seed_decay_rate:long_name = "fraction of seeds that decay per year" ; + double fates_grperc(fates_pft) ; + fates_grperc:units = "unitless" ; + fates_grperc:long_name = "Growth respiration factor" ; + double fates_hydro_avuln_gs(fates_pft) ; + fates_hydro_avuln_gs:units = "unitless" ; + fates_hydro_avuln_gs:long_name = "shape parameter for stomatal control of water vapor exiting leaf" ; + double fates_hydro_avuln_node(fates_hydr_organs, fates_pft) ; + fates_hydro_avuln_node:units = "unitless" ; + fates_hydro_avuln_node:long_name = "xylem vulnerability curve shape parameter" ; + double fates_hydro_epsil_node(fates_hydr_organs, fates_pft) ; + fates_hydro_epsil_node:units = "MPa" ; + fates_hydro_epsil_node:long_name = "bulk elastic modulus" ; + double fates_hydro_fcap_node(fates_hydr_organs, fates_pft) ; + fates_hydro_fcap_node:units = "unitless" ; + fates_hydro_fcap_node:long_name = "fraction of non-residual water that is capillary in source" ; + double fates_hydro_k_lwp(fates_pft) ; + fates_hydro_k_lwp:units = "unitless" ; + fates_hydro_k_lwp:long_name = "inner leaf humidity scaling coefficient" ; + double fates_hydro_kmax_node(fates_hydr_organs, fates_pft) ; + fates_hydro_kmax_node:units = "kg/MPa/m/s" ; + fates_hydro_kmax_node:long_name = "maximum xylem conductivity per unit conducting xylem area" ; + double fates_hydro_p50_gs(fates_pft) ; + fates_hydro_p50_gs:units = "MPa" ; + fates_hydro_p50_gs:long_name = "water potential at 50% loss of stomatal conductance" ; + double fates_hydro_p50_node(fates_hydr_organs, fates_pft) ; + fates_hydro_p50_node:units = "MPa" ; + fates_hydro_p50_node:long_name = "xylem water potential at 50% loss of conductivity" ; + double fates_hydro_p_taper(fates_pft) ; + fates_hydro_p_taper:units = "unitless" ; + fates_hydro_p_taper:long_name = "xylem taper exponent" ; + double fates_hydro_pinot_node(fates_hydr_organs, fates_pft) ; + fates_hydro_pinot_node:units = "MPa" ; + fates_hydro_pinot_node:long_name = "osmotic potential at full turgor" ; + double fates_hydro_pitlp_node(fates_hydr_organs, fates_pft) ; + fates_hydro_pitlp_node:units = "MPa" ; + fates_hydro_pitlp_node:long_name = "turgor loss point" ; + double fates_hydro_resid_node(fates_hydr_organs, fates_pft) ; + fates_hydro_resid_node:units = "cm3/cm3" ; + fates_hydro_resid_node:long_name = "residual water conent" ; + double fates_hydro_rfrac_stem(fates_pft) ; + fates_hydro_rfrac_stem:units = "fraction" ; + fates_hydro_rfrac_stem:long_name = "fraction of total tree resistance from troot to canopy" ; + double fates_hydro_rs2(fates_pft) ; + fates_hydro_rs2:units = "m" ; + fates_hydro_rs2:long_name = "absorbing root radius" ; + double fates_hydro_srl(fates_pft) ; + fates_hydro_srl:units = "m g-1" ; + fates_hydro_srl:long_name = "specific root length" ; + double fates_hydro_thetas_node(fates_hydr_organs, fates_pft) ; + fates_hydro_thetas_node:units = "cm3/cm3" ; + fates_hydro_thetas_node:long_name = "saturated water content" ; + double fates_hydro_vg_alpha_node(fates_hydr_organs, fates_pft) ; + fates_hydro_vg_alpha_node:units = "MPa-1" ; + fates_hydro_vg_alpha_node:long_name = "(used if hydr_htftype_node = 2), capillary length parameter in van Genuchten model" ; + double fates_hydro_vg_m_node(fates_hydr_organs, fates_pft) ; + fates_hydro_vg_m_node:units = "unitless" ; + fates_hydro_vg_m_node:long_name = "(used if hydr_htftype_node = 2),m in van Genuchten 1980 model, 2nd pore size distribution parameter" ; + double fates_hydro_vg_n_node(fates_hydr_organs, fates_pft) ; + fates_hydro_vg_n_node:units = "unitless" ; + fates_hydro_vg_n_node:long_name = "(used if hydr_htftype_node = 2),n in van Genuchten 1980 model, pore size distribution parameter" ; + double fates_leaf_c3psn(fates_pft) ; + fates_leaf_c3psn:units = "flag" ; + fates_leaf_c3psn:long_name = "Photosynthetic pathway (1=c3, 0=c4)" ; + double fates_leaf_jmaxha(fates_pft) ; + fates_leaf_jmaxha:units = "J/mol" ; + fates_leaf_jmaxha:long_name = "activation energy for jmax. NOTE: if fates_leaf_photo_tempsens_model=2 then these values are NOT USED" ; + double fates_leaf_jmaxhd(fates_pft) ; + fates_leaf_jmaxhd:units = "J/mol" ; + fates_leaf_jmaxhd:long_name = "deactivation energy for jmax. NOTE: if fates_leaf_photo_tempsens_model=2 then these values are NOT USED" ; + double fates_leaf_jmaxse(fates_pft) ; + fates_leaf_jmaxse:units = "J/mol/K" ; + fates_leaf_jmaxse:long_name = "entropy term for jmax. NOTE: if fates_leaf_photo_tempsens_model=2 then these values are NOT USED" ; + double fates_leaf_slamax(fates_pft) ; + fates_leaf_slamax:units = "m^2/gC" ; + fates_leaf_slamax:long_name = "Maximum Specific Leaf Area (SLA), even if under a dense canopy" ; + double fates_leaf_slatop(fates_pft) ; + fates_leaf_slatop:units = "m^2/gC" ; + fates_leaf_slatop:long_name = "Specific Leaf Area (SLA) at top of canopy, projected area basis" ; + double fates_leaf_stomatal_intercept(fates_pft) ; + fates_leaf_stomatal_intercept:units = "umol H2O/m**2/s" ; + fates_leaf_stomatal_intercept:long_name = "Minimum unstressed stomatal conductance for Ball-Berry model and Medlyn model" ; + double fates_leaf_stomatal_slope_ballberry(fates_pft) ; + fates_leaf_stomatal_slope_ballberry:units = "unitless" ; + fates_leaf_stomatal_slope_ballberry:long_name = "stomatal slope parameter, as per Ball-Berry" ; + double fates_leaf_stomatal_slope_medlyn(fates_pft) ; + fates_leaf_stomatal_slope_medlyn:units = "KPa**0.5" ; + fates_leaf_stomatal_slope_medlyn:long_name = "stomatal slope parameter, as per Medlyn" ; + double fates_leaf_vcmax25top(fates_leafage_class, fates_pft) ; + fates_leaf_vcmax25top:units = "umol CO2/m^2/s" ; + fates_leaf_vcmax25top:long_name = "maximum carboxylation rate of Rub. at 25C, canopy top" ; + double fates_leaf_vcmaxha(fates_pft) ; + fates_leaf_vcmaxha:units = "J/mol" ; + fates_leaf_vcmaxha:long_name = "activation energy for vcmax. NOTE: if fates_leaf_photo_tempsens_model=2 then these values are NOT USED" ; + double fates_leaf_vcmaxhd(fates_pft) ; + fates_leaf_vcmaxhd:units = "J/mol" ; + fates_leaf_vcmaxhd:long_name = "deactivation energy for vcmax. NOTE: if fates_leaf_photo_tempsens_model=2 then these values are NOT USED" ; + double fates_leaf_vcmaxse(fates_pft) ; + fates_leaf_vcmaxse:units = "J/mol/K" ; + fates_leaf_vcmaxse:long_name = "entropy term for vcmax. NOTE: if fates_leaf_photo_tempsens_model=2 then these values are NOT USED" ; + double fates_leafn_vert_scaler_coeff1(fates_pft) ; + fates_leafn_vert_scaler_coeff1:units = "unitless" ; + fates_leafn_vert_scaler_coeff1:long_name = "Coefficient one for decrease in leaf nitrogen through the canopy, from Lloyd et al. 2010." ; + double fates_leafn_vert_scaler_coeff2(fates_pft) ; + fates_leafn_vert_scaler_coeff2:units = "unitless" ; + fates_leafn_vert_scaler_coeff2:long_name = "Coefficient two for decrease in leaf nitrogen through the canopy, from Lloyd et al. 2010." ; + double fates_maintresp_leaf_atkin2017_baserate(fates_pft) ; + fates_maintresp_leaf_atkin2017_baserate:units = "umol CO2/m^2/s" ; + fates_maintresp_leaf_atkin2017_baserate:long_name = "Leaf maintenance respiration base rate parameter (r0) per Atkin et al 2017" ; + double fates_maintresp_leaf_ryan1991_baserate(fates_pft) ; + fates_maintresp_leaf_ryan1991_baserate:units = "gC/gN/s" ; + fates_maintresp_leaf_ryan1991_baserate:long_name = "Leaf maintenance respiration base rate per Ryan et al 1991" ; + double fates_maintresp_leaf_vert_scaler_coeff1(fates_pft) ; + fates_maintresp_leaf_vert_scaler_coeff1:units = "unitless" ; + fates_maintresp_leaf_vert_scaler_coeff1:long_name = "Leaf maintenance respiration decrease through the canopy. Only applies to Atkin et al. 2017. For proportionality between photosynthesis and respiration through the canopy, match with fates_leafn_vert_scaler_coeff1." ; + double fates_maintresp_leaf_vert_scaler_coeff2(fates_pft) ; + fates_maintresp_leaf_vert_scaler_coeff2:units = "unitless" ; + fates_maintresp_leaf_vert_scaler_coeff2:long_name = "Leaf maintenance respiration decrease through the canopy. Only applies to Atkin et al. 2017. For proportionality between photosynthesis and respiration through the canopy, match with fates_leafn_vert_scaler_coeff2." ; + double fates_maintresp_reduction_curvature(fates_pft) ; + fates_maintresp_reduction_curvature:units = "unitless (0-1)" ; + fates_maintresp_reduction_curvature:long_name = "curvature of MR reduction as f(carbon storage), 1=linear, 0=very curved" ; + double fates_maintresp_reduction_intercept(fates_pft) ; + fates_maintresp_reduction_intercept:units = "unitless (0-1)" ; + fates_maintresp_reduction_intercept:long_name = "intercept of MR reduction as f(carbon storage), 0=no throttling, 1=max throttling" ; + double fates_maintresp_reduction_upthresh(fates_pft) ; + fates_maintresp_reduction_upthresh:units = "unitless (0-1)" ; + fates_maintresp_reduction_upthresh:long_name = "upper threshold for storage biomass (relative to leaf biomass) above which MR is not reduced" ; + double fates_mort_bmort(fates_pft) ; + fates_mort_bmort:units = "1/yr" ; + fates_mort_bmort:long_name = "background mortality rate" ; + double fates_mort_freezetol(fates_pft) ; + fates_mort_freezetol:units = "degrees C" ; + fates_mort_freezetol:long_name = "minimum temperature tolerance" ; + double fates_mort_hf_flc_threshold(fates_pft) ; + fates_mort_hf_flc_threshold:units = "fraction" ; + fates_mort_hf_flc_threshold:long_name = "plant fractional loss of conductivity at which drought mortality begins for hydraulic model" ; + double fates_mort_hf_sm_threshold(fates_pft) ; + fates_mort_hf_sm_threshold:units = "unitless" ; + fates_mort_hf_sm_threshold:long_name = "soil moisture (btran units) at which drought mortality begins for non-hydraulic model" ; + double fates_mort_ip_age_senescence(fates_pft) ; + fates_mort_ip_age_senescence:units = "years" ; + fates_mort_ip_age_senescence:long_name = "Mortality cohort age senescence inflection point. If _ this mortality term is off. Setting this value turns on age dependent mortality. " ; + double fates_mort_ip_size_senescence(fates_pft) ; + fates_mort_ip_size_senescence:units = "dbh cm" ; + fates_mort_ip_size_senescence:long_name = "Mortality dbh senescence inflection point. If _ this mortality term is off. Setting this value turns on size dependent mortality" ; + double fates_mort_prescribed_canopy(fates_pft) ; + fates_mort_prescribed_canopy:units = "1/yr" ; + fates_mort_prescribed_canopy:long_name = "mortality rate of canopy trees for prescribed physiology mode" ; + double fates_mort_prescribed_understory(fates_pft) ; + fates_mort_prescribed_understory:units = "1/yr" ; + fates_mort_prescribed_understory:long_name = "mortality rate of understory trees for prescribed physiology mode" ; + double fates_mort_r_age_senescence(fates_pft) ; + fates_mort_r_age_senescence:units = "mortality rate year^-1" ; + fates_mort_r_age_senescence:long_name = "Mortality age senescence rate of change. Sensible range is around 0.03-0.06. Larger values givesteeper mortality curves." ; + double fates_mort_r_size_senescence(fates_pft) ; + fates_mort_r_size_senescence:units = "mortality rate dbh^-1" ; + fates_mort_r_size_senescence:long_name = "Mortality dbh senescence rate of change. Sensible range is around 0.03-0.06. Larger values give steeper mortality curves." ; + double fates_mort_scalar_coldstress(fates_pft) ; + fates_mort_scalar_coldstress:units = "1/yr" ; + fates_mort_scalar_coldstress:long_name = "maximum mortality rate from cold stress" ; + double fates_mort_scalar_cstarvation(fates_pft) ; + fates_mort_scalar_cstarvation:units = "1/yr" ; + fates_mort_scalar_cstarvation:long_name = "maximum mortality rate from carbon starvation" ; + double fates_mort_scalar_hydrfailure(fates_pft) ; + fates_mort_scalar_hydrfailure:units = "1/yr" ; + fates_mort_scalar_hydrfailure:long_name = "maximum mortality rate from hydraulic failure" ; + double fates_mort_upthresh_cstarvation(fates_pft) ; + fates_mort_upthresh_cstarvation:units = "unitless" ; + fates_mort_upthresh_cstarvation:long_name = "threshold for storage biomass (relative to target leaf biomass) above which carbon starvation is zero" ; + double fates_nonhydro_smpsc(fates_pft) ; + fates_nonhydro_smpsc:units = "mm" ; + fates_nonhydro_smpsc:long_name = "Soil water potential at full stomatal closure" ; + double fates_nonhydro_smpso(fates_pft) ; + fates_nonhydro_smpso:units = "mm" ; + fates_nonhydro_smpso:long_name = "Soil water potential at full stomatal opening" ; + double fates_phen_cold_size_threshold(fates_pft) ; + fates_phen_cold_size_threshold:units = "cm" ; + fates_phen_cold_size_threshold:long_name = "the dbh size above which will lead to phenology-related stem and leaf drop" ; + double fates_phen_drought_threshold(fates_pft) ; + fates_phen_drought_threshold:units = "m3/m3 or mm" ; + fates_phen_drought_threshold:long_name = "threshold for drought phenology (or lower threshold for semi-deciduous PFTs); the quantity depends on the sign: if positive, the threshold is volumetric soil moisture (m3/m3). If negative, the threshold is soil matric potentical (mm)" ; + double fates_phen_evergreen(fates_pft) ; + fates_phen_evergreen:units = "logical flag" ; + fates_phen_evergreen:long_name = "Binary flag for evergreen leaf habit" ; + double fates_phen_flush_fraction(fates_pft) ; + fates_phen_flush_fraction:units = "fraction" ; + fates_phen_flush_fraction:long_name = "Upon bud-burst, the maximum fraction of storage carbon used for flushing leaves" ; + double fates_phen_fnrt_drop_fraction(fates_pft) ; + fates_phen_fnrt_drop_fraction:units = "fraction" ; + fates_phen_fnrt_drop_fraction:long_name = "fraction of fine roots to drop during drought/cold" ; + double fates_phen_mindaysoff(fates_pft) ; + fates_phen_mindaysoff:units = "days" ; + fates_phen_mindaysoff:long_name = "day threshold compared against days since leaves abscised (shed)" ; + double fates_phen_moist_threshold(fates_pft) ; + fates_phen_moist_threshold:units = "m3/m3 or mm" ; + fates_phen_moist_threshold:long_name = "upper threshold for drought phenology (only for drought semi-deciduous PFTs); the quantity depends on the sign: if positive, the threshold is volumetric soil moisture (m3/m3). If negative, the threshold is soil matric potentical (mm)" ; + double fates_phen_season_decid(fates_pft) ; + fates_phen_season_decid:units = "logical flag" ; + fates_phen_season_decid:long_name = "Binary flag for seasonal-deciduous leaf habit" ; + double fates_phen_stem_drop_fraction(fates_pft) ; + fates_phen_stem_drop_fraction:units = "fraction" ; + fates_phen_stem_drop_fraction:long_name = "fraction of stems to drop for non-woody species during drought/cold" ; + double fates_phen_stress_decid(fates_pft) ; + fates_phen_stress_decid:units = "logical flag" ; + fates_phen_stress_decid:long_name = "Flag for stress/drought-deciduous leaf habit. 0 - not stress deciduous; 1 - default drought deciduous (two target states only, fully flushed or fully abscised); 2 - semi-deciduous" ; + double fates_prescribed_npp_canopy(fates_pft) ; + fates_prescribed_npp_canopy:units = "kgC / m^2 / yr" ; + fates_prescribed_npp_canopy:long_name = "NPP per unit crown area of canopy trees for prescribed physiology mode" ; + double fates_prescribed_npp_understory(fates_pft) ; + fates_prescribed_npp_understory:units = "kgC / m^2 / yr" ; + fates_prescribed_npp_understory:long_name = "NPP per unit crown area of understory trees for prescribed physiology mode" ; + double fates_rad_leaf_clumping_index(fates_pft) ; + fates_rad_leaf_clumping_index:units = "fraction (0-1)" ; + fates_rad_leaf_clumping_index:long_name = "factor describing how much self-occlusion of leaf scattering elements decreases light interception" ; + double fates_rad_leaf_rhonir(fates_pft) ; + fates_rad_leaf_rhonir:units = "fraction" ; + fates_rad_leaf_rhonir:long_name = "Leaf reflectance: near-IR" ; + double fates_rad_leaf_rhovis(fates_pft) ; + fates_rad_leaf_rhovis:units = "fraction" ; + fates_rad_leaf_rhovis:long_name = "Leaf reflectance: visible" ; + double fates_rad_leaf_taunir(fates_pft) ; + fates_rad_leaf_taunir:units = "fraction" ; + fates_rad_leaf_taunir:long_name = "Leaf transmittance: near-IR" ; + double fates_rad_leaf_tauvis(fates_pft) ; + fates_rad_leaf_tauvis:units = "fraction" ; + fates_rad_leaf_tauvis:long_name = "Leaf transmittance: visible" ; + double fates_rad_leaf_xl(fates_pft) ; + fates_rad_leaf_xl:units = "unitless" ; + fates_rad_leaf_xl:long_name = "Leaf/stem orientation index" ; + double fates_rad_stem_rhonir(fates_pft) ; + fates_rad_stem_rhonir:units = "fraction" ; + fates_rad_stem_rhonir:long_name = "Stem reflectance: near-IR" ; + double fates_rad_stem_rhovis(fates_pft) ; + fates_rad_stem_rhovis:units = "fraction" ; + fates_rad_stem_rhovis:long_name = "Stem reflectance: visible" ; + double fates_rad_stem_taunir(fates_pft) ; + fates_rad_stem_taunir:units = "fraction" ; + fates_rad_stem_taunir:long_name = "Stem transmittance: near-IR" ; + double fates_rad_stem_tauvis(fates_pft) ; + fates_rad_stem_tauvis:units = "fraction" ; + fates_rad_stem_tauvis:long_name = "Stem transmittance: visible" ; + double fates_recruit_height_min(fates_pft) ; + fates_recruit_height_min:units = "m" ; + fates_recruit_height_min:long_name = "the minimum height (ie starting height) of a newly recruited plant" ; + double fates_recruit_init_density(fates_pft) ; + fates_recruit_init_density:units = "stems/m2" ; + fates_recruit_init_density:long_name = "initial seedling density for a cold-start near-bare-ground simulation. If negative sets initial tree dbh - only to be used in nocomp mode" ; + double fates_recruit_prescribed_rate(fates_pft) ; + fates_recruit_prescribed_rate:units = "n/yr" ; + fates_recruit_prescribed_rate:long_name = "recruitment rate for prescribed physiology mode" ; + double fates_recruit_seed_alloc(fates_pft) ; + fates_recruit_seed_alloc:units = "fraction" ; + fates_recruit_seed_alloc:long_name = "fraction of available carbon balance allocated to seeds" ; + double fates_recruit_seed_alloc_mature(fates_pft) ; + fates_recruit_seed_alloc_mature:units = "fraction" ; + fates_recruit_seed_alloc_mature:long_name = "fraction of available carbon balance allocated to seeds in mature plants (adds to fates_seed_alloc)" ; + double fates_recruit_seed_dbh_repro_threshold(fates_pft) ; + fates_recruit_seed_dbh_repro_threshold:units = "cm" ; + fates_recruit_seed_dbh_repro_threshold:long_name = "the diameter where the plant will increase allocation to the seed pool by fraction: fates_recruit_seed_alloc_mature" ; + double fates_recruit_seed_germination_rate(fates_pft) ; + fates_recruit_seed_germination_rate:units = "yr-1" ; + fates_recruit_seed_germination_rate:long_name = "fraction of seeds that germinate per year" ; + double fates_recruit_seed_supplement(fates_pft) ; + fates_recruit_seed_supplement:units = "KgC/m2/yr" ; + fates_recruit_seed_supplement:long_name = "Supplemental external seed rain source term (non-mass conserving)" ; + double fates_seed_dispersal_fraction(fates_pft) ; + fates_seed_dispersal_fraction:units = "fraction" ; + fates_seed_dispersal_fraction:long_name = "fraction of seed rain to be dispersed to other grid cells" ; + double fates_seed_dispersal_max_dist(fates_pft) ; + fates_seed_dispersal_max_dist:units = "m" ; + fates_seed_dispersal_max_dist:long_name = "maximum seed dispersal distance for a given pft" ; + double fates_seed_dispersal_pdf_scale(fates_pft) ; + fates_seed_dispersal_pdf_scale:units = "unitless" ; + fates_seed_dispersal_pdf_scale:long_name = "seed dispersal probability density function scale parameter, A, Table 1 Bullock et al 2016" ; + double fates_seed_dispersal_pdf_shape(fates_pft) ; + fates_seed_dispersal_pdf_shape:units = "unitless" ; + fates_seed_dispersal_pdf_shape:long_name = "seed dispersal probability density function shape parameter, B, Table 1 Bullock et al 2016" ; + double fates_stoich_nitr(fates_plant_organs, fates_pft) ; + fates_stoich_nitr:units = "gN/gC" ; + fates_stoich_nitr:long_name = "target nitrogen concentration (ratio with carbon) of organs" ; + double fates_stoich_phos(fates_plant_organs, fates_pft) ; + fates_stoich_phos:units = "gP/gC" ; + fates_stoich_phos:long_name = "target phosphorus concentration (ratio with carbon) of organs" ; + double fates_trim_inc(fates_pft) ; + fates_trim_inc:units = "m2/m2" ; + fates_trim_inc:long_name = "Arbitrary incremental change in trimming function." ; + double fates_trim_limit(fates_pft) ; + fates_trim_limit:units = "m2/m2" ; + fates_trim_limit:long_name = "Arbitrary limit to reductions in leaf area with stress" ; + double fates_trs_repro_alloc_a(fates_pft) ; + fates_trs_repro_alloc_a:units = "fraction" ; + fates_trs_repro_alloc_a:long_name = "shape parameter for sigmoidal function relating dbh to reproductive allocation" ; + double fates_trs_repro_alloc_b(fates_pft) ; + fates_trs_repro_alloc_b:units = "fraction" ; + fates_trs_repro_alloc_b:long_name = "intercept parameter for sigmoidal function relating dbh to reproductive allocation" ; + double fates_trs_repro_frac_seed(fates_pft) ; + fates_trs_repro_frac_seed:units = "fraction" ; + fates_trs_repro_frac_seed:long_name = "fraction of reproductive mass that is seed" ; + double fates_trs_seedling_a_emerg(fates_pft) ; + fates_trs_seedling_a_emerg:units = "day -1" ; + fates_trs_seedling_a_emerg:long_name = "mean fraction of seed bank emerging" ; + double fates_trs_seedling_b_emerg(fates_pft) ; + fates_trs_seedling_b_emerg:units = "day -1" ; + fates_trs_seedling_b_emerg:long_name = "seedling emergence sensitivity to soil moisture" ; + double fates_trs_seedling_background_mort(fates_pft) ; + fates_trs_seedling_background_mort:units = "yr-1" ; + fates_trs_seedling_background_mort:long_name = "background seedling mortality rate" ; + double fates_trs_seedling_h2o_mort_a(fates_pft) ; + fates_trs_seedling_h2o_mort_a:units = "-" ; + fates_trs_seedling_h2o_mort_a:long_name = "coefficient in moisture-based seedling mortality" ; + double fates_trs_seedling_h2o_mort_b(fates_pft) ; + fates_trs_seedling_h2o_mort_b:units = "-" ; + fates_trs_seedling_h2o_mort_b:long_name = "coefficient in moisture-based seedling mortality" ; + double fates_trs_seedling_h2o_mort_c(fates_pft) ; + fates_trs_seedling_h2o_mort_c:units = "-" ; + fates_trs_seedling_h2o_mort_c:long_name = "coefficient in moisture-based seedling mortality" ; + double fates_trs_seedling_light_mort_a(fates_pft) ; + fates_trs_seedling_light_mort_a:units = "-" ; + fates_trs_seedling_light_mort_a:long_name = "light-based seedling mortality coefficient" ; + double fates_trs_seedling_light_mort_b(fates_pft) ; + fates_trs_seedling_light_mort_b:units = "-" ; + fates_trs_seedling_light_mort_b:long_name = "light-based seedling mortality coefficient" ; + double fates_trs_seedling_light_rec_a(fates_pft) ; + fates_trs_seedling_light_rec_a:units = "-" ; + fates_trs_seedling_light_rec_a:long_name = "coefficient in light-based seedling to sapling transition" ; + double fates_trs_seedling_light_rec_b(fates_pft) ; + fates_trs_seedling_light_rec_b:units = "-" ; + fates_trs_seedling_light_rec_b:long_name = "coefficient in light-based seedling to sapling transition" ; + double fates_trs_seedling_mdd_crit(fates_pft) ; + fates_trs_seedling_mdd_crit:units = "mm H2O day" ; + fates_trs_seedling_mdd_crit:long_name = "critical moisture deficit (suction) day accumulation for seedling moisture-based seedling mortality to begin" ; + double fates_trs_seedling_par_crit_germ(fates_pft) ; + fates_trs_seedling_par_crit_germ:units = "MJ m-2 day-1" ; + fates_trs_seedling_par_crit_germ:long_name = "critical light level for germination" ; + double fates_trs_seedling_psi_crit(fates_pft) ; + fates_trs_seedling_psi_crit:units = "mm H2O" ; + fates_trs_seedling_psi_crit:long_name = "critical soil moisture (suction) for seedling stress" ; + double fates_trs_seedling_psi_emerg(fates_pft) ; + fates_trs_seedling_psi_emerg:units = "mm h20 suction" ; + fates_trs_seedling_psi_emerg:long_name = "critical soil moisture for seedling emergence" ; + double fates_trs_seedling_root_depth(fates_pft) ; + fates_trs_seedling_root_depth:units = "m" ; + fates_trs_seedling_root_depth:long_name = "rooting depth of seedlings" ; + double fates_turb_displar(fates_pft) ; + fates_turb_displar:units = "unitless" ; + fates_turb_displar:long_name = "Ratio of displacement height to canopy top height" ; + double fates_turb_leaf_diameter(fates_pft) ; + fates_turb_leaf_diameter:units = "m" ; + fates_turb_leaf_diameter:long_name = "Characteristic leaf dimension" ; + double fates_turb_z0mr(fates_pft) ; + fates_turb_z0mr:units = "unitless" ; + fates_turb_z0mr:long_name = "Ratio of momentum roughness length to canopy top height" ; + double fates_turnover_branch(fates_pft) ; + fates_turnover_branch:units = "yr" ; + fates_turnover_branch:long_name = "turnover time of branches" ; + double fates_turnover_fnrt(fates_pft) ; + fates_turnover_fnrt:units = "yr" ; + fates_turnover_fnrt:long_name = "root longevity (alternatively, turnover time)" ; + double fates_turnover_leaf(fates_leafage_class, fates_pft) ; + fates_turnover_leaf:units = "yr" ; + fates_turnover_leaf:long_name = "Leaf longevity (ie turnover timescale). For drought-deciduous PFTs, this also indicates the maximum length of the growing (i.e., leaves on) season." ; + double fates_turnover_senleaf_fdrought(fates_pft) ; + fates_turnover_senleaf_fdrought:units = "unitless[0-1]" ; + fates_turnover_senleaf_fdrought:long_name = "multiplication factor for leaf longevity of senescent leaves during drought" ; + double fates_wood_density(fates_pft) ; + fates_wood_density:units = "g/cm3" ; + fates_wood_density:long_name = "mean density of woody tissue in plant" ; + double fates_woody(fates_pft) ; + fates_woody:units = "logical flag" ; + fates_woody:long_name = "Binary woody lifeform flag" ; + double fates_hlm_pft_map(fates_hlm_pftno, fates_pft) ; + fates_hlm_pft_map:units = "area fraction" ; + fates_hlm_pft_map:long_name = "In fixed biogeog mode, fraction of HLM area associated with each FATES PFT" ; + double fates_fire_FBD(fates_litterclass) ; + fates_fire_FBD:units = "kg Biomass/m3" ; + fates_fire_FBD:long_name = "fuel bulk density" ; + double fates_fire_low_moisture_Coeff(fates_litterclass) ; + fates_fire_low_moisture_Coeff:units = "NA" ; + fates_fire_low_moisture_Coeff:long_name = "spitfire parameter, equation B1 Thonicke et al 2010" ; + double fates_fire_low_moisture_Slope(fates_litterclass) ; + fates_fire_low_moisture_Slope:units = "NA" ; + fates_fire_low_moisture_Slope:long_name = "spitfire parameter, equation B1 Thonicke et al 2010" ; + double fates_fire_mid_moisture(fates_litterclass) ; + fates_fire_mid_moisture:units = "NA" ; + fates_fire_mid_moisture:long_name = "spitfire litter moisture threshold to be considered medium dry" ; + double fates_fire_mid_moisture_Coeff(fates_litterclass) ; + fates_fire_mid_moisture_Coeff:units = "NA" ; + fates_fire_mid_moisture_Coeff:long_name = "spitfire parameter, equation B1 Thonicke et al 2010" ; + double fates_fire_mid_moisture_Slope(fates_litterclass) ; + fates_fire_mid_moisture_Slope:units = "NA" ; + fates_fire_mid_moisture_Slope:long_name = "spitfire parameter, equation B1 Thonicke et al 2010" ; + double fates_fire_min_moisture(fates_litterclass) ; + fates_fire_min_moisture:units = "NA" ; + fates_fire_min_moisture:long_name = "spitfire litter moisture threshold to be considered very dry" ; + double fates_fire_SAV(fates_litterclass) ; + fates_fire_SAV:units = "cm-1" ; + fates_fire_SAV:long_name = "fuel surface area to volume ratio" ; + double fates_frag_maxdecomp(fates_litterclass) ; + fates_frag_maxdecomp:units = "yr-1" ; + fates_frag_maxdecomp:long_name = "maximum rate of litter & CWD transfer from non-decomposing class into decomposing class" ; + double fates_frag_cwd_frac(fates_NCWD) ; + fates_frag_cwd_frac:units = "fraction" ; + fates_frag_cwd_frac:long_name = "fraction of woody (bdead+bsw) biomass destined for CWD pool" ; + double fates_maxpatches_by_landuse(fates_landuseclass) ; + fates_maxpatches_by_landuse:units = "count" ; + fates_maxpatches_by_landuse:long_name = "maximum number of patches per site on each land use type" ; + double fates_canopy_closure_thresh ; + fates_canopy_closure_thresh:units = "unitless" ; + fates_canopy_closure_thresh:long_name = "tree canopy coverage at which crown area allometry changes from savanna to forest value" ; + double fates_cnp_eca_plant_escalar ; + fates_cnp_eca_plant_escalar:units = "" ; + fates_cnp_eca_plant_escalar:long_name = "scaling factor for plant fine root biomass to calculate nutrient carrier enzyme abundance (ECA)" ; + double fates_cohort_age_fusion_tol ; + fates_cohort_age_fusion_tol:units = "unitless" ; + fates_cohort_age_fusion_tol:long_name = "minimum fraction in differece in cohort age between cohorts." ; + double fates_cohort_size_fusion_tol ; + fates_cohort_size_fusion_tol:units = "unitless" ; + fates_cohort_size_fusion_tol:long_name = "minimum fraction in difference in dbh between cohorts" ; + double fates_comp_excln ; + fates_comp_excln:units = "none" ; + fates_comp_excln:long_name = "IF POSITIVE: weighting factor (exponent on dbh) for canopy layer exclusion and promotion, IF NEGATIVE: switch to use deterministic height sorting" ; + double fates_damage_canopy_layer_code ; + fates_damage_canopy_layer_code:units = "unitless" ; + fates_damage_canopy_layer_code:long_name = "Integer code that decides whether damage affects canopy trees (1), understory trees (2)" ; + double fates_damage_event_code ; + fates_damage_event_code:units = "unitless" ; + fates_damage_event_code:long_name = "Integer code that options how damage events are structured" ; + double fates_daylength_factor_switch ; + fates_daylength_factor_switch:units = "unitless" ; + fates_daylength_factor_switch:long_name = "user switch for turning on (1) or off (0) the day length factor scaling for photosynthetic parameters (ie scale vcmax and jmax)" ; + double fates_dev_arbitrary ; + fates_dev_arbitrary:units = "unknown" ; + fates_dev_arbitrary:long_name = "Unassociated free parameter that developers can use for testing arbitrary new hypotheses" ; + double fates_fire_active_crown_fire ; + fates_fire_active_crown_fire:units = "0 or 1" ; + fates_fire_active_crown_fire:long_name = "flag, 1=active crown fire 0=no active crown fire" ; + double fates_fire_cg_strikes ; + fates_fire_cg_strikes:units = "fraction (0-1)" ; + fates_fire_cg_strikes:long_name = "fraction of cloud to ground lightning strikes" ; + double fates_fire_drying_ratio ; + fates_fire_drying_ratio:units = "NA" ; + fates_fire_drying_ratio:long_name = "spitfire parameter, fire drying ratio for fuel moisture, alpha_FMC EQ 6 Thonicke et al 2010" ; + double fates_fire_durat_slope ; + fates_fire_durat_slope:units = "NA" ; + fates_fire_durat_slope:long_name = "spitfire parameter, fire max duration slope, Equation 14 Thonicke et al 2010" ; + double fates_fire_fdi_alpha ; + fates_fire_fdi_alpha:units = "NA" ; + fates_fire_fdi_alpha:long_name = "spitfire parameter, EQ 7 Venevsky et al. GCB 2002,(modified EQ 8 Thonicke et al. 2010) " ; + double fates_fire_fuel_energy ; + fates_fire_fuel_energy:units = "kJ/kg" ; + fates_fire_fuel_energy:long_name = "spitfire parameter, heat content of fuel" ; + double fates_fire_max_durat ; + fates_fire_max_durat:units = "minutes" ; + fates_fire_max_durat:long_name = "spitfire parameter, fire maximum duration, Equation 14 Thonicke et al 2010" ; + double fates_fire_miner_damp ; + fates_fire_miner_damp:units = "NA" ; + fates_fire_miner_damp:long_name = "spitfire parameter, mineral-dampening coefficient EQ A1 Thonicke et al 2010 " ; + double fates_fire_miner_total ; + fates_fire_miner_total:units = "fraction" ; + fates_fire_miner_total:long_name = "spitfire parameter, total mineral content, Table A1 Thonicke et al 2010" ; + double fates_fire_nignitions ; + fates_fire_nignitions:units = "ignitions per year per km2" ; + fates_fire_nignitions:long_name = "number of annual ignitions per square km" ; + double fates_fire_part_dens ; + fates_fire_part_dens:units = "kg/m2" ; + fates_fire_part_dens:long_name = "spitfire parameter, oven dry particle density, Table A1 Thonicke et al 2010" ; + double fates_fire_threshold ; + fates_fire_threshold:units = "kW/m" ; + fates_fire_threshold:long_name = "spitfire parameter, fire intensity threshold for tracking fires that spread" ; + double fates_frag_cwd_fcel ; + fates_frag_cwd_fcel:units = "unitless" ; + fates_frag_cwd_fcel:long_name = "Cellulose fraction for CWD" ; + double fates_frag_cwd_flig ; + fates_frag_cwd_flig:units = "unitless" ; + fates_frag_cwd_flig:long_name = "Lignin fraction of coarse woody debris" ; + double fates_hydro_kmax_rsurf1 ; + fates_hydro_kmax_rsurf1:units = "kg water/m2 root area/Mpa/s" ; + fates_hydro_kmax_rsurf1:long_name = "maximum conducitivity for unit root surface (into root)" ; + double fates_hydro_kmax_rsurf2 ; + fates_hydro_kmax_rsurf2:units = "kg water/m2 root area/Mpa/s" ; + fates_hydro_kmax_rsurf2:long_name = "maximum conducitivity for unit root surface (out of root)" ; + double fates_hydro_psi0 ; + fates_hydro_psi0:units = "MPa" ; + fates_hydro_psi0:long_name = "sapwood water potential at saturation" ; + double fates_hydro_psicap ; + fates_hydro_psicap:units = "MPa" ; + fates_hydro_psicap:long_name = "sapwood water potential at which capillary reserves exhausted" ; + double fates_hydro_solver ; + fates_hydro_solver:units = "unitless" ; + fates_hydro_solver:long_name = "switch designating which numerical solver for plant hydraulics, 1 = 1D taylor, 2 = 2D Picard, 3 = 2D Newton (deprecated)" ; + double fates_landuse_logging_coll_under_frac ; + fates_landuse_logging_coll_under_frac:units = "fraction" ; + fates_landuse_logging_coll_under_frac:long_name = "Fraction of stems killed in the understory when logging generates disturbance" ; + double fates_landuse_logging_collateral_frac ; + fates_landuse_logging_collateral_frac:units = "fraction" ; + fates_landuse_logging_collateral_frac:long_name = "Fraction of large stems in upperstory that die from logging collateral damage" ; + double fates_landuse_logging_dbhmax ; + fates_landuse_logging_dbhmax:units = "cm" ; + fates_landuse_logging_dbhmax:long_name = "Maximum dbh below which logging is applied (unset values flag this to be unused)" ; + double fates_landuse_logging_dbhmax_infra ; + fates_landuse_logging_dbhmax_infra:units = "cm" ; + fates_landuse_logging_dbhmax_infra:long_name = "Tree diameter, above which infrastructure from logging does not impact damage or mortality." ; + double fates_landuse_logging_dbhmin ; + fates_landuse_logging_dbhmin:units = "cm" ; + fates_landuse_logging_dbhmin:long_name = "Minimum dbh at which logging is applied" ; + double fates_landuse_logging_direct_frac ; + fates_landuse_logging_direct_frac:units = "fraction" ; + fates_landuse_logging_direct_frac:long_name = "Fraction of stems logged directly per event" ; + double fates_landuse_logging_event_code ; + fates_landuse_logging_event_code:units = "unitless" ; + fates_landuse_logging_event_code:long_name = "Integer code that options how logging events are structured" ; + double fates_landuse_logging_export_frac ; + fates_landuse_logging_export_frac:units = "fraction" ; + fates_landuse_logging_export_frac:long_name = "fraction of trunk product being shipped offsite, the leftovers will be left onsite as large CWD" ; + double fates_landuse_logging_mechanical_frac ; + fates_landuse_logging_mechanical_frac:units = "fraction" ; + fates_landuse_logging_mechanical_frac:long_name = "Fraction of stems killed due infrastructure an other mechanical means" ; + double fates_landuse_pprodharv10_forest_mean ; + fates_landuse_pprodharv10_forest_mean:units = "fraction" ; + fates_landuse_pprodharv10_forest_mean:long_name = "mean harvest mortality proportion of deadstem to 10-yr product (pprodharv10) of all woody PFT types" ; + double fates_leaf_photo_temp_acclim_thome_time ; + fates_leaf_photo_temp_acclim_thome_time:units = "years" ; + fates_leaf_photo_temp_acclim_thome_time:long_name = "Length of the window for the long-term (i.e. T_home in Kumarathunge et al 2019) exponential moving average (ema) of vegetation temperature used in photosynthesis temperature acclimation (used if fates_leaf_photo_tempsens_model = 2)" ; + double fates_leaf_photo_temp_acclim_timescale ; + fates_leaf_photo_temp_acclim_timescale:units = "days" ; + fates_leaf_photo_temp_acclim_timescale:long_name = "Length of the window for the exponential moving average (ema) of vegetation temperature used in photosynthesis temperature acclimation (used if fates_maintresp_leaf_model=2 or fates_leaf_photo_tempsens_model = 2)" ; + double fates_leaf_photo_tempsens_model ; + fates_leaf_photo_tempsens_model:units = "unitless" ; + fates_leaf_photo_tempsens_model:long_name = "switch for choosing the model that defines the temperature sensitivity of photosynthetic parameters (vcmax, jmax). 1=non-acclimating; 2=Kumarathunge et al 2019" ; + double fates_leaf_stomatal_assim_model ; + fates_leaf_stomatal_assim_model:units = "unitless" ; + fates_leaf_stomatal_assim_model:long_name = "a switch designating whether to use net (1) or gross (2) assimilation in the stomatal model" ; + double fates_leaf_stomatal_model ; + fates_leaf_stomatal_model:units = "unitless" ; + fates_leaf_stomatal_model:long_name = "switch for choosing between Ball-Berry (1) stomatal conductance model and Medlyn (2) model" ; + double fates_leaf_theta_cj_c3 ; + fates_leaf_theta_cj_c3:units = "unitless" ; + fates_leaf_theta_cj_c3:long_name = "Empirical curvature parameter for ac, aj photosynthesis co-limitation in c3 plants" ; + double fates_leaf_theta_cj_c4 ; + fates_leaf_theta_cj_c4:units = "unitless" ; + fates_leaf_theta_cj_c4:long_name = "Empirical curvature parameter for ac, aj photosynthesis co-limitation in c4 plants" ; + double fates_maintresp_leaf_model ; + fates_maintresp_leaf_model:units = "unitless" ; + fates_maintresp_leaf_model:long_name = "switch for choosing between maintenance respiration models. 1=Ryan (1991), 2=Atkin et al., (2017)" ; + double fates_maintresp_nonleaf_baserate ; + fates_maintresp_nonleaf_baserate:units = "gC/gN/s" ; + fates_maintresp_nonleaf_baserate:long_name = "Base maintenance respiration rate for plant tissues, using Ryan 1991" ; + double fates_maxcohort ; + fates_maxcohort:units = "count" ; + fates_maxcohort:long_name = "maximum number of cohorts per patch. Actual number of cohorts also depend on cohort fusion tolerances" ; + double fates_mort_cstarvation_model ; + fates_mort_cstarvation_model:units = "unitless" ; + fates_mort_cstarvation_model:long_name = "switch defining the carbon starvation model ( 1) Linear or 2) Exponential) in the mortality_rates function." ; + double fates_mort_disturb_frac ; + fates_mort_disturb_frac:units = "fraction" ; + fates_mort_disturb_frac:long_name = "fraction of canopy mortality that results in disturbance (i.e. transfer of area from new to old patch)" ; + double fates_mort_understorey_death ; + fates_mort_understorey_death:units = "fraction" ; + fates_mort_understorey_death:long_name = "fraction of plants in understorey cohort impacted by overstorey tree-fall" ; + double fates_patch_fusion_tol ; + fates_patch_fusion_tol:units = "unitless" ; + fates_patch_fusion_tol:long_name = "minimum fraction in difference in profiles between patches" ; + double fates_phen_chilltemp ; + fates_phen_chilltemp:units = "degrees C" ; + fates_phen_chilltemp:long_name = "chilling day counting threshold for vegetation" ; + double fates_phen_coldtemp ; + fates_phen_coldtemp:units = "degrees C" ; + fates_phen_coldtemp:long_name = "vegetation temperature exceedance that flags a cold-day for leaf-drop" ; + double fates_phen_gddthresh_a ; + fates_phen_gddthresh_a:units = "none" ; + fates_phen_gddthresh_a:long_name = "GDD accumulation function, intercept parameter: gdd_thesh = a + b exp(c*ncd)" ; + double fates_phen_gddthresh_b ; + fates_phen_gddthresh_b:units = "none" ; + fates_phen_gddthresh_b:long_name = "GDD accumulation function, multiplier parameter: gdd_thesh = a + b exp(c*ncd)" ; + double fates_phen_gddthresh_c ; + fates_phen_gddthresh_c:units = "none" ; + fates_phen_gddthresh_c:long_name = "GDD accumulation function, exponent parameter: gdd_thesh = a + b exp(c*ncd)" ; + double fates_phen_mindayson ; + fates_phen_mindayson:units = "days" ; + fates_phen_mindayson:long_name = "day threshold compared against days since leaves became on-allometry" ; + double fates_phen_ncolddayslim ; + fates_phen_ncolddayslim:units = "days" ; + fates_phen_ncolddayslim:long_name = "day threshold exceedance for temperature leaf-drop" ; + double fates_q10_froz ; + fates_q10_froz:units = "unitless" ; + fates_q10_froz:long_name = "Q10 for frozen-soil respiration rates" ; + double fates_q10_mr ; + fates_q10_mr:units = "unitless" ; + fates_q10_mr:long_name = "Q10 for maintenance respiration" ; + double fates_rad_model ; + fates_rad_model:units = "unitless" ; + fates_rad_model:long_name = "switch designating the model for canopy radiation, 1 = Norman, 2 = Two-stream (experimental)" ; + double fates_regeneration_model ; + fates_regeneration_model:units = "-" ; + fates_regeneration_model:long_name = "switch for choosing between FATES\'s: 1) default regeneration scheme , 2) the Tree Recruitment Scheme (Hanbury-Brown et al., 2022), or (3) the Tree Recruitment Scheme without seedling dynamics" ; + double fates_soil_salinity ; + fates_soil_salinity:units = "ppt" ; + fates_soil_salinity:long_name = "soil salinity used for model when not coupled to dynamic soil salinity" ; + double fates_trs_seedling2sap_par_timescale ; + fates_trs_seedling2sap_par_timescale:units = "days" ; + fates_trs_seedling2sap_par_timescale:long_name = "Length of the window for the exponential moving average of par at the seedling layer used to calculate seedling to sapling transition rates" ; + double fates_trs_seedling_emerg_h2o_timescale ; + fates_trs_seedling_emerg_h2o_timescale:units = "days" ; + fates_trs_seedling_emerg_h2o_timescale:long_name = "Length of the window for the exponential moving average of smp used to calculate seedling emergence" ; + double fates_trs_seedling_mdd_timescale ; + fates_trs_seedling_mdd_timescale:units = "days" ; + fates_trs_seedling_mdd_timescale:long_name = "Length of the window for the exponential moving average of moisture deficit days used to calculate seedling mortality" ; + double fates_trs_seedling_mort_par_timescale ; + fates_trs_seedling_mort_par_timescale:units = "days" ; + fates_trs_seedling_mort_par_timescale:long_name = "Length of the window for the exponential moving average of par at the seedling layer used to calculate seedling mortality" ; + double fates_vai_top_bin_width ; + fates_vai_top_bin_width:units = "m2/m2" ; + fates_vai_top_bin_width:long_name = "width in VAI units of uppermost leaf+stem layer scattering element in each canopy layer" ; + double fates_vai_width_increase_factor ; + fates_vai_width_increase_factor:units = "unitless" ; + fates_vai_width_increase_factor:long_name = "factor by which each leaf+stem scattering element increases in VAI width (1 = uniform spacing)" ; + +// global attributes: + :history = "This file was generated by BatchPatchParams.py:\nCDL Base File = archive/api24.1.0_101722_fates_params_default.cdl\nXML patch file = archive/api24.1.0_101722_patch_params.xml" ; +data: + + fates_history_ageclass_bin_edges = 0, 1, 2, 5, 10, 20, 50 ; + + fates_history_coageclass_bin_edges = 0, 5 ; + + fates_history_height_bin_edges = 0, 0.1, 0.3, 1, 3, 10 ; + + fates_history_damage_bin_edges = 0, 80 ; + + fates_history_sizeclass_bin_edges = 0, 5, 10, 15, 20, 30, 40, 50, 60, 70, + 80, 90, 100 ; + + fates_alloc_organ_id = 1, 2, 3, 6 ; + + fates_hydro_htftype_node = 1, 1, 1, 1 ; + + fates_pftname = + "broadleaf_evergreen_tropical_tree ", + "needleleaf_evergreen_extratrop_tree ", + "needleleaf_colddecid_extratrop_tree ", + "broadleaf_evergreen_extratrop_tree ", + "broadleaf_hydrodecid_tropical_tree ", + "broadleaf_colddecid_extratrop_tree ", + "broadleaf_evergreen_extratrop_shrub ", + "broadleaf_hydrodecid_extratrop_shrub ", + "broadleaf_colddecid_extratrop_shrub ", + "arctic_c3_grass ", + "cool_c3_grass ", + "c4_grass " ; + + fates_hydro_organ_name = + "leaf ", + "stem ", + "transporting root ", + "absorbing root " ; + + fates_alloc_organ_name = + "leaf", + "fine root", + "sapwood", + "structure" ; + + fates_landuseclass_name = + "primaryland", + "secondaryland", + "rangeland", + "pastureland", + "cropland" ; + + fates_litterclass_name = + "twig ", + "small branch ", + "large branch ", + "trunk ", + "dead leaves ", + "live grass " ; + + fates_alloc_organ_priority = + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 ; + + fates_alloc_storage_cushion = 1.2, 1.2, 1.2, 1.2, 2.4, 1.2, 1.2, 2.4, 1.2, + 1.2, 1.2, 1.2 ; + + fates_alloc_store_priority_frac = 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, + 0.8, 0.8, 0.8, 0.8 ; + + fates_allom_agb1 = 0.0673, 0.1364012, 0.0393057, 0.2653695, 0.0673, + 0.0728698, 0.06896, 0.06896, 0.06896, 0.01, 0.01, 0.01 ; + + fates_allom_agb2 = 0.976, 0.9449041, 1.087335, 0.8321321, 0.976, 1.0373211, + 0.572, 0.572, 0.572, 0.572, 0.572, 0.572 ; + + fates_allom_agb3 = 1.94, 1.94, 1.94, 1.94, 1.94, 1.94, 1.94, 1.94, 1.94, + 1.94, 1.94, 1.94 ; + + fates_allom_agb4 = 0.931, 0.931, 0.931, 0.931, 0.931, 0.931, 0.931, 0.931, + 0.931, 0.931, 0.931, 0.931 ; + + fates_allom_agb_frac = 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, + 0.6, 0.6 ; + + fates_allom_amode = 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1 ; + + fates_allom_blca_expnt_diff = -0.12, -0.34, -0.32, -0.22, -0.12, -0.35, 0, + 0, 0, 0, 0, 0 ; + + fates_allom_cmode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_d2bl1 = 0.04, 0.07, 0.07, 0.01, 0.04, 0.07, 0.07, 0.07, 0.07, + 0.07, 0.07, 0.07 ; + + fates_allom_d2bl2 = 1.6019679, 1.5234373, 1.3051237, 1.9621397, 1.6019679, + 1.3998939, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3 ; + + fates_allom_d2bl3 = 0.55, 0.55, 0.55, 0.55, 0.55, 0.55, 0.55, 0.55, 0.55, + 0.55, 0.55, 0.55 ; + + fates_allom_d2ca_coefficient_max = 0.2715891, 0.3693718, 1.0787259, + 0.0579297, 0.2715891, 1.1553612, 0.6568464, 0.6568464, 0.6568464, + 0.6568464, 0.6568464, 0.6568464 ; + + fates_allom_d2ca_coefficient_min = 0.2715891, 0.3693718, 1.0787259, + 0.0579297, 0.2715891, 1.1553612, 0.6568464, 0.6568464, 0.6568464, + 0.6568464, 0.6568464, 0.6568464 ; + + fates_allom_d2h1 = 78.4087704, 306.842667, 106.8745821, 104.3586841, + 78.4087704, 31.4557047, 0.64, 0.64, 0.64, 0.64, 0.64, 0.64 ; + + fates_allom_d2h2 = 0.8124383, 0.752377, 0.9471302, 1.1146973, 0.8124383, + 0.9734088, 0.37, 0.37, 0.37, 0.37, 0.37, 0.37 ; + + fates_allom_d2h3 = 47.6666164, 196.6865691, 93.9790461, 160.6835089, + 47.6666164, 16.5928174, -999.9, -999.9, -999.9, -999.9, -999.9, -999.9 ; + + fates_allom_dbh_maxheight = 1000, 1000, 1000, 1000, 1000, 1000, 3, 3, 2, + 0.35, 0.35, 0.35 ; + + fates_allom_dmode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_fmode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_fnrt_prof_a = 7, 7, 7, 7, 6, 6, 7, 7, 7, 11, 11, 11 ; + + fates_allom_fnrt_prof_b = 1, 2, 2, 1, 2, 2, 1.5, 1.5, 1.5, 2, 2, 2 ; + + fates_allom_fnrt_prof_mode = 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 ; + + fates_allom_frbstor_repro = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_allom_h2cd1 = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.95, 0.95, 0.95, 1, 1, 1 ; + + fates_allom_h2cd2 = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_hmode = 5, 5, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1 ; + + fates_allom_l2fr = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_la_per_sa_int = 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, + 0.8, 0.8, 0.8 ; + + fates_allom_la_per_sa_slp = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_allom_lmode = 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1 ; + + fates_allom_sai_scaler = 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, + 0.1, 0.1 ; + + fates_allom_smode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_stmode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_zroot_k = 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10 ; + + fates_allom_zroot_max_dbh = 100, 100, 100, 100, 100, 100, 2, 2, 2, 2, 2, 2 ; + + fates_allom_zroot_max_z = 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, + 100, 100 ; + + fates_allom_zroot_min_dbh = 1, 1, 1, 2.5, 2.5, 2.5, 0.1, 0.1, 0.1, 0.1, 0.1, + 0.1 ; + + fates_allom_zroot_min_z = 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, + 100, 100 ; + + fates_c2b = 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ; + + fates_cnp_eca_alpha_ptase = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_cnp_eca_decompmicc = 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280 ; + + fates_cnp_eca_km_nh4 = 0.14, 0.14, 0.14, 0.14, 0.14, 0.14, 0.14, 0.14, 0.14, + 0.14, 0.14, 0.14 ; + + fates_cnp_eca_km_no3 = 0.27, 0.27, 0.27, 0.27, 0.27, 0.27, 0.27, 0.27, 0.27, + 0.27, 0.27, 0.27 ; + + fates_cnp_eca_km_p = 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, + 0.1 ; + + fates_cnp_eca_km_ptase = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_cnp_eca_lambda_ptase = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_cnp_eca_vmax_ptase = 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, + 5e-09, 5e-09, 5e-09, 5e-09, 5e-09 ; + + fates_cnp_nfix1 = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_cnp_nitr_store_ratio = 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, + 1.5, 1.5, 1.5 ; + + fates_cnp_phos_store_ratio = 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, + 1.5, 1.5, 1.5 ; + + fates_cnp_pid_kd = 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1 ; + + fates_cnp_pid_ki = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_cnp_pid_kp = 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, + 0.0005, 0.0005, 0.0005, 0.0005, 0.0005 ; + + fates_cnp_prescribed_nuptake = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_cnp_prescribed_puptake = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_cnp_store_ovrflw_frac = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_cnp_turnover_nitr_retrans = + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_cnp_turnover_phos_retrans = + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_cnp_vmax_nh4 = 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, + 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09 ; + + fates_cnp_vmax_no3 = 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, + 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09 ; + + fates_cnp_vmax_p = 5e-10, 5e-10, 5e-10, 5e-10, 5e-10, 5e-10, 5e-10, 5e-10, + 5e-10, 5e-10, 5e-10, 5e-10 ; + + fates_damage_frac = 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, + 0.01, 0.01, 0.01 ; + + fates_damage_mort_p1 = 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 ; + + fates_damage_mort_p2 = 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, + 5.5, 5.5 ; + + fates_damage_recovery_scalar = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_dev_arbitrary_pft = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_fire_alpha_SH = 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, + 0.2 ; + + fates_fire_bark_scaler = 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, + 0.07, 0.07, 0.07, 0.07 ; + + fates_fire_crown_kill = 0.775, 0.775, 0.775, 0.775, 0.775, 0.775, 0.775, + 0.775, 0.775, 0.775, 0.775, 0.775 ; + + fates_frag_fnrt_fcel = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5 ; + + fates_frag_fnrt_flab = 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25 ; + + fates_frag_fnrt_flig = 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25 ; + + fates_frag_leaf_fcel = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5 ; + + fates_frag_leaf_flab = 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25 ; + + fates_frag_leaf_flig = 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25 ; + + fates_frag_seed_decay_rate = 0.51, 0.51, 0.51, 0.51, 0.51, 0.51, 0.51, 0.51, + 0.51, 0.51, 0.51, 0.51 ; + + fates_grperc = 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, + 0.11, 0.11 ; + + fates_hydro_avuln_gs = 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, + 2.5, 2.5 ; + + fates_hydro_avuln_node = + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ; + + fates_hydro_epsil_node = + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 ; + + fates_hydro_fcap_node = + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, + 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_hydro_k_lwp = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_hydro_kmax_node = + -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999 ; + + fates_hydro_p50_gs = -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, + -1.5, -1.5, -1.5 ; + + fates_hydro_p50_node = + -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, + -2.25, -2.25, + -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, + -2.25, -2.25, + -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, + -2.25, -2.25, + -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, + -2.25, -2.25 ; + + fates_hydro_p_taper = 0.333, 0.333, 0.333, 0.333, 0.333, 0.333, 0.333, + 0.333, 0.333, 0.333, 0.333, 0.333 ; + + fates_hydro_pinot_node = + -1.465984, -1.465984, -1.465984, -1.465984, -1.465984, -1.465984, + -1.465984, -1.465984, -1.465984, -1.465984, -1.465984, -1.465984, + -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, + -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, + -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, + -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, + -1.043478, -1.043478, -1.043478, -1.043478, -1.043478, -1.043478, + -1.043478, -1.043478, -1.043478, -1.043478, -1.043478, -1.043478 ; + + fates_hydro_pitlp_node = + -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, + -1.67, -1.67, + -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, + -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, + -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2 ; + + fates_hydro_resid_node = + 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, + 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, + 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, + 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11 ; + + fates_hydro_rfrac_stem = 0.625, 0.625, 0.625, 0.625, 0.625, 0.625, 0.625, + 0.625, 0.625, 0.625, 0.625, 0.625 ; + + fates_hydro_rs2 = 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, + 0.0001, 0.0001, 0.0001, 0.0001, 0.0001 ; + + fates_hydro_srl = 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25 ; + + fates_hydro_thetas_node = + 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, + 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, + 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, + 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75 ; + + fates_hydro_vg_alpha_node = + 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.005, 0.005, 0.005, 0.005, 0.005, + 0.005, 0.005, + 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.005, 0.005, 0.005, 0.005, 0.005, + 0.005, 0.005, + 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.005, 0.005, 0.005, 0.005, 0.005, + 0.005, 0.005, + 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.005, 0.005, 0.005, 0.005, 0.005, + 0.005, 0.005 ; + + fates_hydro_vg_m_node = + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5 ; + + fates_hydro_vg_n_node = + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ; + + fates_leaf_c3psn = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 ; + + fates_leaf_jmaxha = 43540, 43540, 43540, 43540, 43540, 43540, 43540, 43540, + 43540, 43540, 43540, 43540 ; + + fates_leaf_jmaxhd = 152040, 152040, 152040, 152040, 152040, 152040, 152040, + 152040, 152040, 152040, 152040, 152040 ; + + fates_leaf_jmaxse = 495, 495, 495, 495, 495, 495, 495, 495, 495, 495, 495, + 495 ; + + fates_leaf_slamax = 0.0954, 0.0954, 0.0954, 0.0954, 0.0954, 0.0954, 0.012, + 0.03, 0.03, 0.03, 0.03, 0.03 ; + + fates_leaf_slatop = 0.012, 0.005, 0.024, 0.009, 0.03, 0.03, 0.012, 0.03, + 0.03, 0.03, 0.03, 0.03 ; + + fates_leaf_stomatal_intercept = 10000, 10000, 10000, 10000, 10000, 10000, + 10000, 10000, 10000, 10000, 10000, 40000 ; + + fates_leaf_stomatal_slope_ballberry = 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 ; + + fates_leaf_stomatal_slope_medlyn = 4.1, 2.3, 2.3, 4.1, 4.4, 4.4, 4.7, 4.7, + 4.7, 2.2, 5.3, 1.6 ; + + fates_leaf_vcmax25top = + 50, 62, 39, 61, 58, 58, 62, 54, 54, 78, 78, 78 ; + + fates_leaf_vcmaxha = 65330, 65330, 65330, 65330, 65330, 65330, 65330, 65330, + 65330, 65330, 65330, 65330 ; + + fates_leaf_vcmaxhd = 149250, 149250, 149250, 149250, 149250, 149250, 149250, + 149250, 149250, 149250, 149250, 149250 ; + + fates_leaf_vcmaxse = 485, 485, 485, 485, 485, 485, 485, 485, 485, 485, 485, + 485 ; + + fates_leafn_vert_scaler_coeff1 = 0.00963, 0.00963, 0.00963, 0.00963, + 0.00963, 0.00963, 0.00963, 0.00963, 0.00963, 0.00963, 0.00963, 0.00963 ; + + fates_leafn_vert_scaler_coeff2 = 2.43, 2.43, 2.43, 2.43, 2.43, 2.43, 2.43, + 2.43, 2.43, 2.43, 2.43, 2.43 ; + + fates_maintresp_leaf_atkin2017_baserate = 1.756, 1.4995, 1.4995, 1.756, + 1.756, 1.756, 2.0749, 2.0749, 2.0749, 2.1956, 2.1956, 2.1956 ; + + fates_maintresp_leaf_ryan1991_baserate = 2.525e-06, 2.525e-06, 2.525e-06, + 2.525e-06, 2.525e-06, 2.525e-06, 2.525e-06, 2.525e-06, 2.525e-06, + 2.525e-06, 2.525e-06, 2.525e-06 ; + + fates_maintresp_leaf_vert_scaler_coeff1 = 0.00963, 0.00963, 0.00963, + 0.00963, 0.00963, 0.00963, 0.00963, 0.00963, 0.00963, 0.00963, 0.00963, + 0.00963 ; + + fates_maintresp_leaf_vert_scaler_coeff2 = 2.43, 2.43, 2.43, 2.43, 2.43, + 2.43, 2.43, 2.43, 2.43, 2.43, 2.43, 2.43 ; + + fates_maintresp_reduction_curvature = 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, + 0.01, 0.01, 0.01, 0.01, 0.01, 0.01 ; + + fates_maintresp_reduction_intercept = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_maintresp_reduction_upthresh = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_mort_bmort = 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, + 0.014, 0.014, 0.014, 0.014 ; + + fates_mort_freezetol = 2.5, -55, -80, -30, 2.5, -80, -60, -10, -80, -80, + -20, 2.5 ; + + fates_mort_hf_flc_threshold = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5 ; + + fates_mort_hf_sm_threshold = 1e-06, 1e-06, 1e-06, 1e-06, 1e-06, 1e-06, + 1e-06, 1e-06, 1e-06, 1e-06, 1e-06, 1e-06 ; + + fates_mort_ip_age_senescence = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_mort_ip_size_senescence = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_mort_prescribed_canopy = 0.0194, 0.0194, 0.0194, 0.0194, 0.0194, + 0.0194, 0.0194, 0.0194, 0.0194, 0.0194, 0.0194, 0.0194 ; + + fates_mort_prescribed_understory = 0.025, 0.025, 0.025, 0.025, 0.025, 0.025, + 0.025, 0.025, 0.025, 0.025, 0.025, 0.025 ; + + fates_mort_r_age_senescence = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_mort_r_size_senescence = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_mort_scalar_coldstress = 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 ; + + fates_mort_scalar_cstarvation = 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, + 0.6, 0.6, 0.6 ; + + fates_mort_scalar_hydrfailure = 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, + 0.6, 0.6, 0.6 ; + + fates_mort_upthresh_cstarvation = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_nonhydro_smpsc = -255000, -255000, -255000, -255000, -255000, -255000, + -255000, -255000, -255000, -255000, -255000, -255000 ; + + fates_nonhydro_smpso = -66000, -66000, -66000, -66000, -66000, -66000, + -66000, -66000, -66000, -66000, -66000, -66000 ; + + fates_phen_cold_size_threshold = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_phen_drought_threshold = -152957.4, -152957.4, -152957.4, -152957.4, + -152957.4, -152957.4, -152957.4, -152957.4, -152957.4, -152957.4, + -152957.4, -152957.4 ; + + fates_phen_evergreen = 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 ; + + fates_phen_flush_fraction = _, _, 0.5, _, 0.5, 0.5, _, 0.5, 0.5, 0.5, 0.5, + 0.5 ; + + fates_phen_fnrt_drop_fraction = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_phen_mindaysoff = 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, + 100, 100 ; + + fates_phen_moist_threshold = -122365.9, -122365.9, -122365.9, -122365.9, + -122365.9, -122365.9, -122365.9, -122365.9, -122365.9, -122365.9, + -122365.9, -122365.9 ; + + fates_phen_season_decid = 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0 ; + + fates_phen_stem_drop_fraction = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_phen_stress_decid = 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1 ; + + fates_prescribed_npp_canopy = 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, + 0.4, 0.4, 0.4 ; + + fates_prescribed_npp_understory = 0.03125, 0.03125, 0.03125, 0.03125, + 0.03125, 0.03125, 0.03125, 0.03125, 0.03125, 0.03125, 0.03125, 0.03125 ; + + fates_rad_leaf_clumping_index = 0.85, 0.85, 0.8, 0.85, 0.85, 0.9, 0.85, 0.9, + 0.9, 0.75, 0.75, 0.75 ; + + fates_rad_leaf_rhonir = 0.46, 0.41, 0.39, 0.46, 0.41, 0.41, 0.46, 0.41, + 0.41, 0.28, 0.28, 0.28 ; + + fates_rad_leaf_rhovis = 0.11, 0.09, 0.08, 0.11, 0.08, 0.08, 0.11, 0.08, + 0.08, 0.05, 0.05, 0.05 ; + + fates_rad_leaf_taunir = 0.33, 0.32, 0.42, 0.33, 0.43, 0.43, 0.33, 0.43, + 0.43, 0.4, 0.4, 0.4 ; + + fates_rad_leaf_tauvis = 0.06, 0.04, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, + 0.06, 0.05, 0.05, 0.05 ; + + fates_rad_leaf_xl = 0.32, 0.01, 0.01, 0.32, 0.2, 0.59, 0.32, 0.59, 0.59, + -0.23, -0.23, -0.23 ; + + fates_rad_stem_rhonir = 0.49, 0.36, 0.36, 0.49, 0.49, 0.49, 0.49, 0.49, + 0.49, 0.53, 0.53, 0.53 ; + + fates_rad_stem_rhovis = 0.21, 0.12, 0.12, 0.21, 0.21, 0.21, 0.21, 0.21, + 0.21, 0.31, 0.31, 0.31 ; + + fates_rad_stem_taunir = 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, + 0.001, 0.001, 0.25, 0.25, 0.25 ; + + fates_rad_stem_tauvis = 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, + 0.001, 0.001, 0.12, 0.12, 0.12 ; + + fates_recruit_height_min = 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 0.2, 0.2, 0.2, + 0.125, 0.125, 0.125 ; + + fates_recruit_init_density = 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, + 0.2, 0.2, 0.2 ; + + fates_recruit_prescribed_rate = 0.02, 0.02, 0.02, 0.02, 0.02, 0.02, 0.02, + 0.02, 0.02, 0.02, 0.02, 0.02 ; + + fates_recruit_seed_alloc = 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, + 0.1, 0.1 ; + + fates_recruit_seed_alloc_mature = 0, 0, 0, 0, 0, 0, 0.9, 0.9, 0.9, 0.9, 0.9, + 0.9 ; + + fates_recruit_seed_dbh_repro_threshold = 90, 80, 80, 80, 90, 80, 3, 3, 2, + 0.35, 0.35, 0.35 ; + + fates_recruit_seed_germination_rate = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5 ; + + fates_recruit_seed_supplement = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_seed_dispersal_fraction = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_seed_dispersal_max_dist = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_seed_dispersal_pdf_scale = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_seed_dispersal_pdf_shape = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_stoich_nitr = + 0.033, 0.029, 0.04, 0.033, 0.04, 0.04, 0.033, 0.04, 0.04, 0.04, 0.04, 0.04, + 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, + 0.024, 0.024, + 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, + 1e-08, 1e-08, + 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, + 0.0047, 0.0047, 0.0047 ; + + fates_stoich_phos = + 0.0033, 0.0029, 0.004, 0.0033, 0.004, 0.004, 0.0033, 0.004, 0.004, 0.004, + 0.004, 0.004, + 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, + 0.0024, 0.0024, 0.0024, + 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, + 1e-09, 1e-09, + 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, + 0.00047, 0.00047, 0.00047, 0.00047 ; + + fates_trim_inc = 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, + 0.03, 0.03 ; + + fates_trim_limit = 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3 ; + + fates_trs_repro_alloc_a = 0.0049, 0.0049, 0.0049, 0.0049, 0.0049, 0.0049, + 0.0049, 0.0049, 0.0049, 0.0049, 0.0049, 0.0049 ; + + fates_trs_repro_alloc_b = -2.6171, -2.6171, -2.6171, -2.6171, -2.6171, + -2.6171, -2.6171, -2.6171, -2.6171, -2.6171, -2.6171, -2.6171 ; + + fates_trs_repro_frac_seed = 0.24, 0.24, 0.24, 0.24, 0.24, 0.24, 0.24, 0.24, + 0.24, 0.24, 0.24, 0.24 ; + + fates_trs_seedling_a_emerg = 0.0003, 0.0003, 0.0003, 0.0003, 0.0003, 0.0003, + 0.0003, 0.0003, 0.0003, 0.0003, 0.0003, 0.0003 ; + + fates_trs_seedling_b_emerg = 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, + 1.2, 1.2, 1.2 ; + + fates_trs_seedling_background_mort = 0.1085371, 0.1085371, 0.1085371, + 0.1085371, 0.1085371, 0.1085371, 0.1085371, 0.1085371, 0.1085371, + 0.1085371, 0.1085371, 0.1085371 ; + + fates_trs_seedling_h2o_mort_a = 4.070565e-17, 4.070565e-17, 4.070565e-17, + 4.070565e-17, 4.070565e-17, 4.070565e-17, 4.070565e-17, 4.070565e-17, + 4.070565e-17, 4.070565e-17, 4.070565e-17, 4.070565e-17 ; + + fates_trs_seedling_h2o_mort_b = -6.390757e-11, -6.390757e-11, -6.390757e-11, + -6.390757e-11, -6.390757e-11, -6.390757e-11, -6.390757e-11, + -6.390757e-11, -6.390757e-11, -6.390757e-11, -6.390757e-11, -6.390757e-11 ; + + fates_trs_seedling_h2o_mort_c = 1.268992e-05, 1.268992e-05, 1.268992e-05, + 1.268992e-05, 1.268992e-05, 1.268992e-05, 1.268992e-05, 1.268992e-05, + 1.268992e-05, 1.268992e-05, 1.268992e-05, 1.268992e-05 ; + + fates_trs_seedling_light_mort_a = -0.009897694, -0.009897694, -0.009897694, + -0.009897694, -0.009897694, -0.009897694, -0.009897694, -0.009897694, + -0.009897694, -0.009897694, -0.009897694, -0.009897694 ; + + fates_trs_seedling_light_mort_b = -7.154063, -7.154063, -7.154063, + -7.154063, -7.154063, -7.154063, -7.154063, -7.154063, -7.154063, + -7.154063, -7.154063, -7.154063 ; + + fates_trs_seedling_light_rec_a = 0.007, 0.007, 0.007, 0.007, 0.007, 0.007, + 0.007, 0.007, 0.007, 0.007, 0.007, 0.007 ; + + fates_trs_seedling_light_rec_b = 0.8615, 0.8615, 0.8615, 0.8615, 0.8615, + 0.8615, 0.8615, 0.8615, 0.8615, 0.8615, 0.8615, 0.8615 ; + + fates_trs_seedling_mdd_crit = 1400000, 1400000, 1400000, 1400000, 1400000, + 1400000, 1400000, 1400000, 1400000, 1400000, 1400000, 1400000 ; + + fates_trs_seedling_par_crit_germ = 0.656, 0.656, 0.656, 0.656, 0.656, 0.656, + 0.656, 0.656, 0.656, 0.656, 0.656, 0.656 ; + + fates_trs_seedling_psi_crit = -251995.7, -251995.7, -251995.7, -251995.7, + -251995.7, -251995.7, -251995.7, -251995.7, -251995.7, -251995.7, + -251995.7, -251995.7 ; + + fates_trs_seedling_psi_emerg = -15744.65, -15744.65, -15744.65, -15744.65, + -15744.65, -15744.65, -15744.65, -15744.65, -15744.65, -15744.65, + -15744.65, -15744.65 ; + + fates_trs_seedling_root_depth = 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, + 0.06, 0.06, 0.06, 0.06, 0.06 ; + + fates_turb_displar = 0.67, 0.67, 0.67, 0.67, 0.67, 0.67, 0.67, 0.67, 0.67, + 0.67, 0.67, 0.67 ; + + fates_turb_leaf_diameter = 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, + 0.04, 0.04, 0.04, 0.04 ; + + fates_turb_z0mr = 0.055, 0.055, 0.055, 0.055, 0.055, 0.055, 0.055, 0.055, + 0.055, 0.055, 0.055, 0.055 ; + + fates_turnover_branch = 150, 150, 150, 150, 150, 150, 150, 150, 150, 0, 0, 0 ; + + fates_turnover_fnrt = 1, 2, 1, 1.5, 1, 1, 1.5, 1, 1, 1, 1, 1 ; + + fates_turnover_leaf = + 1.5, 4, 1, 1.5, 1, 1, 1.5, 1, 1, 1, 1, 1 ; + + fates_turnover_senleaf_fdrought = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_wood_density = 0.548327, 0.44235, 0.454845, 0.754336, 0.548327, + 0.566452, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7 ; + + fates_woody = 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 ; + + fates_hlm_pft_map = + 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 ; + + fates_fire_FBD = 15.4, 16.8, 19.6, 999, 4, 4 ; + + fates_fire_low_moisture_Coeff = 1.12, 1.09, 0.98, 0.8, 1.15, 1.15 ; + + fates_fire_low_moisture_Slope = 0.62, 0.72, 0.85, 0.8, 0.62, 0.62 ; + + fates_fire_mid_moisture = 0.72, 0.51, 0.38, 1, 0.8, 0.8 ; + + fates_fire_mid_moisture_Coeff = 2.35, 1.47, 1.06, 0.8, 3.2, 3.2 ; + + fates_fire_mid_moisture_Slope = 2.35, 1.47, 1.06, 0.8, 3.2, 3.2 ; + + fates_fire_min_moisture = 0.18, 0.12, 0, 0, 0.24, 0.24 ; + + fates_fire_SAV = 13, 3.58, 0.98, 0.2, 66, 66 ; + + fates_frag_maxdecomp = 0.52, 0.383, 0.383, 0.19, 1, 999 ; + + fates_frag_cwd_frac = 0.045, 0.075, 0.21, 0.67 ; + + fates_maxpatches_by_landuse = 9, 4, 1, 1, 1 ; + + fates_canopy_closure_thresh = 0.8 ; + + fates_cnp_eca_plant_escalar = 1.25e-05 ; + + fates_cohort_age_fusion_tol = 0.08 ; + + fates_cohort_size_fusion_tol = 0.08 ; + + fates_comp_excln = 3 ; + + fates_damage_canopy_layer_code = 1 ; + + fates_damage_event_code = 1 ; + + fates_daylength_factor_switch = 1 ; + + fates_dev_arbitrary = _ ; + + fates_fire_active_crown_fire = 0 ; + + fates_fire_cg_strikes = 0.2 ; + + fates_fire_drying_ratio = 66000 ; + + fates_fire_durat_slope = -11.06 ; + + fates_fire_fdi_alpha = 0.00037 ; + + fates_fire_fuel_energy = 18000 ; + + fates_fire_max_durat = 240 ; + + fates_fire_miner_damp = 0.41739 ; + + fates_fire_miner_total = 0.055 ; + + fates_fire_nignitions = 15 ; + + fates_fire_part_dens = 513 ; + + fates_fire_threshold = 50 ; + + fates_frag_cwd_fcel = 0.76 ; + + fates_frag_cwd_flig = 0.24 ; + + fates_hydro_kmax_rsurf1 = 20 ; + + fates_hydro_kmax_rsurf2 = 0.0001 ; + + fates_hydro_psi0 = 0 ; + + fates_hydro_psicap = -0.6 ; + + fates_hydro_solver = 1 ; + + fates_landuse_logging_coll_under_frac = 0.55983 ; + + fates_landuse_logging_collateral_frac = 0.05 ; + + fates_landuse_logging_dbhmax = _ ; + + fates_landuse_logging_dbhmax_infra = 35 ; + + fates_landuse_logging_dbhmin = 50 ; + + fates_landuse_logging_direct_frac = 0.15 ; + + fates_landuse_logging_event_code = -30 ; + + fates_landuse_logging_export_frac = 0.8 ; + + fates_landuse_logging_mechanical_frac = 0.05 ; + + fates_landuse_pprodharv10_forest_mean = 0.8125 ; + + fates_leaf_photo_temp_acclim_thome_time = 30 ; + + fates_leaf_photo_temp_acclim_timescale = 30 ; + + fates_leaf_photo_tempsens_model = 1 ; + + fates_leaf_stomatal_assim_model = 1 ; + + fates_leaf_stomatal_model = 1 ; + + fates_leaf_theta_cj_c3 = 0.999 ; + + fates_leaf_theta_cj_c4 = 0.999 ; + + fates_maintresp_leaf_model = 1 ; + + fates_maintresp_nonleaf_baserate = 2.525e-06 ; + + fates_maxcohort = 100 ; + + fates_mort_cstarvation_model = 1 ; + + fates_mort_disturb_frac = 1 ; + + fates_mort_understorey_death = 0.55983 ; + + fates_patch_fusion_tol = 0.05 ; + + fates_phen_chilltemp = 5 ; + + fates_phen_coldtemp = 7.5 ; + + fates_phen_gddthresh_a = -68 ; + + fates_phen_gddthresh_b = 638 ; + + fates_phen_gddthresh_c = -0.01 ; + + fates_phen_mindayson = 90 ; + + fates_phen_ncolddayslim = 5 ; + + fates_q10_froz = 1.5 ; + + fates_q10_mr = 1.5 ; + + fates_rad_model = 1 ; + + fates_regeneration_model = 1 ; + + fates_soil_salinity = 0.4 ; + + fates_trs_seedling2sap_par_timescale = 32 ; + + fates_trs_seedling_emerg_h2o_timescale = 7 ; + + fates_trs_seedling_mdd_timescale = 126 ; + + fates_trs_seedling_mort_par_timescale = 32 ; + + fates_vai_top_bin_width = 1 ; + + fates_vai_width_increase_factor = 1 ; +} diff --git a/parameter_files/archive/api36.0.0_051724_patch_params.xml b/parameter_files/archive/api36.0.0_051724_patch_params.xml new file mode 100644 index 0000000000..3af518bde2 --- /dev/null +++ b/parameter_files/archive/api36.0.0_051724_patch_params.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + archive/api36.0.0_051724_params_default.xml + fates_params_default.cdl + 1,2,3,4,5,6,7,8,9,10,11,12 + + + fates_landuse_harvest_pprod10 + fates_pft + fraction + fraction of harvest wood product that goes to 10-year product pool (remainder goes to 100-year pool) + 1, 0.75, 0.75, 0.75, 1, 0.75, 1, 1, 1, 1, 1, 1 + + + fates_landuse_luc_frac_burned + fates_pft + fraction + fraction of land use change-generated and not-exported material that is burned (the remainder goes to litter) + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5 + + + fates_landuse_luc_frac_exported + fates_pft + fraction + fraction of land use change-generated wood material that is exported to wood product (the remainder is either burned or goes to litter) + 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.2, 0.2, 0.2, 0, 0, 0 + + + fates_landuse_luc_pprod10 + fates_pft + fraction + fraction of land use change wood product that goes to 10-year product pool (remainder goes to 100-year pool) + 1, 0.75, 0.75, 0.75, 1, 0.75, 1, 1, 1, 1, 1, 1 + + + fates_landuse_crop_lu_pft_vector + fates_landuseclass + NA + the FATES PFT index to use on a given crop land-use type (dummy value of -999 for non-crop types) + -999, -999, -999, -999, 11 + + + fates_max_nocomp_pfts_by_landuse + fates_landuseclass + count + maximum number of nocomp PFTs on each land use type (only used in nocomp mode) + 4, 4, 1, 1, 1 + + + fates_landuse_pprodharv10_forest_mean + + + diff --git a/parameter_files/fates_params_default.cdl b/parameter_files/fates_params_default.cdl index 2a909ee340..b66336bbf2 100644 --- a/parameter_files/fates_params_default.cdl +++ b/parameter_files/fates_params_default.cdl @@ -348,6 +348,18 @@ variables: double fates_hydro_vg_n_node(fates_hydr_organs, fates_pft) ; fates_hydro_vg_n_node:units = "unitless" ; fates_hydro_vg_n_node:long_name = "(used if hydr_htftype_node = 2),n in van Genuchten 1980 model, pore size distribution parameter" ; + double fates_landuse_harvest_pprod10(fates_pft) ; + fates_landuse_harvest_pprod10:units = "fraction" ; + fates_landuse_harvest_pprod10:long_name = "fraction of harvest wood product that goes to 10-year product pool (remainder goes to 100-year pool)" ; + double fates_landuse_luc_frac_burned(fates_pft) ; + fates_landuse_luc_frac_burned:units = "fraction" ; + fates_landuse_luc_frac_burned:long_name = "fraction of land use change-generated and not-exported material that is burned (the remainder goes to litter)" ; + double fates_landuse_luc_frac_exported(fates_pft) ; + fates_landuse_luc_frac_exported:units = "fraction" ; + fates_landuse_luc_frac_exported:long_name = "fraction of land use change-generated wood material that is exported to wood product (the remainder is either burned or goes to litter)" ; + double fates_landuse_luc_pprod10(fates_pft) ; + fates_landuse_luc_pprod10:units = "fraction" ; + fates_landuse_luc_pprod10:long_name = "fraction of land use change wood product that goes to 10-year product pool (remainder goes to 100-year pool)" ; double fates_leaf_c3psn(fates_pft) ; fates_leaf_c3psn:units = "flag" ; fates_leaf_c3psn:long_name = "Photosynthetic pathway (1=c3, 0=c4)" ; @@ -690,6 +702,12 @@ variables: double fates_frag_cwd_frac(fates_NCWD) ; fates_frag_cwd_frac:units = "fraction" ; fates_frag_cwd_frac:long_name = "fraction of woody (bdead+bsw) biomass destined for CWD pool" ; + double fates_landuse_crop_lu_pft_vector(fates_landuseclass) ; + fates_landuse_crop_lu_pft_vector:units = "NA" ; + fates_landuse_crop_lu_pft_vector:long_name = "the FATES PFT index to use on a given crop land-use type (dummy value of -999 for non-crop types)" ; + double fates_max_nocomp_pfts_by_landuse(fates_landuseclass) ; + fates_max_nocomp_pfts_by_landuse:units = "count" ; + fates_max_nocomp_pfts_by_landuse:long_name = "maximum number of nocomp PFTs on each land use type (only used in nocomp mode)" ; double fates_maxpatches_by_landuse(fates_landuseclass) ; fates_maxpatches_by_landuse:units = "count" ; fates_maxpatches_by_landuse:long_name = "maximum number of patches per site on each land use type" ; @@ -804,9 +822,6 @@ variables: double fates_landuse_logging_mechanical_frac ; fates_landuse_logging_mechanical_frac:units = "fraction" ; fates_landuse_logging_mechanical_frac:long_name = "Fraction of stems killed due infrastructure an other mechanical means" ; - double fates_landuse_pprodharv10_forest_mean ; - fates_landuse_pprodharv10_forest_mean:units = "fraction" ; - fates_landuse_pprodharv10_forest_mean:long_name = "mean harvest mortality proportion of deadstem to 10-yr product (pprodharv10) of all woody PFT types" ; double fates_leaf_photo_temp_acclim_thome_time ; fates_leaf_photo_temp_acclim_thome_time:units = "years" ; fates_leaf_photo_temp_acclim_thome_time:long_name = "Length of the window for the long-term (i.e. T_home in Kumarathunge et al 2019) exponential moving average (ema) of vegetation temperature used in photosynthesis temperature acclimation (used if fates_leaf_photo_tempsens_model = 2)" ; @@ -1288,6 +1303,16 @@ data: 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ; + fates_landuse_harvest_pprod10 = 1, 0.75, 0.75, 0.75, 1, 0.75, 1, 1, 1, 1, 1, 1 ; + + fates_landuse_luc_frac_burned = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5 ; + + fates_landuse_luc_frac_exported = 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.2, 0.2, + 0.2, 0, 0, 0 ; + + fates_landuse_luc_pprod10 = 1, 0.75, 0.75, 0.75, 1, 0.75, 1, 1, 1, 1, 1, 1 ; + fates_leaf_c3psn = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 ; fates_leaf_jmaxha = 43540, 43540, 43540, 43540, 43540, 43540, 43540, 43540, @@ -1632,6 +1657,10 @@ data: fates_frag_cwd_frac = 0.045, 0.075, 0.21, 0.67 ; + fates_landuse_crop_lu_pft_vector = -999, -999, -999, -999, 11 ; + + fates_max_nocomp_pfts_by_landuse = 4, 4, 1, 1, 1 ; + fates_maxpatches_by_landuse = 9, 4, 1, 1, 1 ; fates_canopy_closure_thresh = 0.8 ; @@ -1708,8 +1737,6 @@ data: fates_landuse_logging_mechanical_frac = 0.05 ; - fates_landuse_pprodharv10_forest_mean = 0.8125 ; - fates_leaf_photo_temp_acclim_thome_time = 30 ; fates_leaf_photo_temp_acclim_timescale = 30 ;