diff --git a/biogeochem/EDLoggingMortalityMod.F90 b/biogeochem/EDLoggingMortalityMod.F90 index a4703ae840..bf6ab7443c 100644 --- a/biogeochem/EDLoggingMortalityMod.F90 +++ b/biogeochem/EDLoggingMortalityMod.F90 @@ -63,7 +63,7 @@ module EDLoggingMortalityMod use PRTGenericMod , only : sapw_organ, struct_organ, leaf_organ use PRTGenericMod , only : fnrt_organ, store_organ, repro_organ use FatesAllometryMod , only : set_root_fraction - use FatesConstantsMod , only : primaryforest, secondaryforest, secondary_age_threshold + use FatesConstantsMod , only : primaryland, secondaryland, secondary_age_threshold use FatesConstantsMod , only : fates_tiny use FatesConstantsMod , only : months_per_year, days_per_sec, years_per_day, g_per_kg use FatesConstantsMod , only : hlm_harvest_area_fraction @@ -199,7 +199,7 @@ subroutine LoggingMortality_frac( pft_i, dbh, canopy_layer, lmort_direct, & lmort_collateral,lmort_infra, l_degrad, & hlm_harvest_rates, hlm_harvest_catnames, & hlm_harvest_units, & - patch_anthro_disturbance_label, secondary_age, & + patch_land_use_label, secondary_age, & frac_site_primary, harvestable_forest_c, & harvest_tag) @@ -210,7 +210,7 @@ subroutine LoggingMortality_frac( pft_i, dbh, canopy_layer, lmort_direct, & real(r8), intent(in) :: hlm_harvest_rates(:) ! annual harvest rate per hlm category character(len=64), intent(in) :: hlm_harvest_catnames(:) ! names of hlm harvest categories integer, intent(in) :: hlm_harvest_units ! unit type of hlm harvest rates: [area vs. mass] - integer, intent(in) :: patch_anthro_disturbance_label ! patch level anthro_disturbance_label + 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) :: harvestable_forest_c(:) ! total harvestable forest carbon ! of all hlm harvest categories @@ -265,7 +265,7 @@ subroutine LoggingMortality_frac( pft_i, dbh, canopy_layer, lmort_direct, & ! 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_anthro_disturbance_label, hlm_harvest_catnames, & + call get_harvest_rate_area (patch_land_use_label, hlm_harvest_catnames, & hlm_harvest_rates, frac_site_primary, secondary_age, harvest_rate) ! For area-based harvest, harvest_tag shall always be 2 (not applicable). @@ -280,7 +280,7 @@ subroutine LoggingMortality_frac( pft_i, dbh, canopy_layer, lmort_direct, & ! 2=use carbon from hlm ! shall call another subroutine, which transfers biomass/carbon into fraction - call get_harvest_rate_carbon (patch_anthro_disturbance_label, hlm_harvest_catnames, & + 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) @@ -348,7 +348,7 @@ end subroutine LoggingMortality_frac ! ============================================================================ - subroutine get_harvest_rate_area (patch_anthro_disturbance_label, hlm_harvest_catnames, hlm_harvest_rates, & + subroutine get_harvest_rate_area (patch_land_use_label, hlm_harvest_catnames, hlm_harvest_rates, & frac_site_primary, secondary_age, harvest_rate) @@ -361,7 +361,7 @@ subroutine get_harvest_rate_area (patch_anthro_disturbance_label, hlm_harvest_ca ! Arguments real(r8), intent(in) :: hlm_harvest_rates(:) ! annual harvest rate per hlm category character(len=64), intent(in) :: hlm_harvest_catnames(:) ! names of hlm harvest categories - integer, intent(in) :: patch_anthro_disturbance_label ! patch level anthro_disturbance_label + 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(out) :: harvest_rate @@ -374,17 +374,17 @@ subroutine get_harvest_rate_area (patch_anthro_disturbance_label, hlm_harvest_ca ! We do account forest only since non-forest harvest has geographical mismatch to LUH2 dataset harvest_rate = 0._r8 do h_index = 1,hlm_num_lu_harvest_cats - if (patch_anthro_disturbance_label .eq. primaryforest) then + if (patch_land_use_label .eq. primaryland) then if(hlm_harvest_catnames(h_index) .eq. "HARVEST_VH1" .or. & hlm_harvest_catnames(h_index) .eq. "HARVEST_VH2") then harvest_rate = harvest_rate + hlm_harvest_rates(h_index) endif - else if (patch_anthro_disturbance_label .eq. secondaryforest .and. & + else if (patch_land_use_label .eq. secondaryland .and. & secondary_age >= secondary_age_threshold) then if(hlm_harvest_catnames(h_index) .eq. "HARVEST_SH1") then harvest_rate = harvest_rate + hlm_harvest_rates(h_index) endif - else if (patch_anthro_disturbance_label .eq. secondaryforest .and. & + else if (patch_land_use_label .eq. secondaryland .and. & secondary_age < secondary_age_threshold) then if(hlm_harvest_catnames(h_index) .eq. "HARVEST_SH2" .or. & hlm_harvest_catnames(h_index) .eq. "HARVEST_SH3") then @@ -396,7 +396,7 @@ subroutine get_harvest_rate_area (patch_anthro_disturbance_label, hlm_harvest_ca ! 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 - if (patch_anthro_disturbance_label .eq. primaryforest) then + 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) else @@ -511,18 +511,18 @@ subroutine get_harvestable_carbon (csite, site_area, hlm_harvest_catnames, harve ! since we have not separated forest vs. non-forest ! all carbon belongs to the forest categories do h_index = 1,hlm_num_lu_harvest_cats - if (currentPatch%anthro_disturbance_label .eq. primaryforest) then + if (currentPatch%land_use_label .eq. primaryland) then ! Primary if(hlm_harvest_catnames(h_index) .eq. "HARVEST_VH1") then harvestable_forest_c(h_index) = harvestable_forest_c(h_index) + harvestable_patch_c end if - else if (currentPatch%anthro_disturbance_label .eq. secondaryforest .and. & + else if (currentPatch%land_use_label .eq. secondaryland .and. & currentPatch%age_since_anthro_disturbance >= secondary_age_threshold) then ! Secondary mature if(hlm_harvest_catnames(h_index) .eq. "HARVEST_SH1") then harvestable_forest_c(h_index) = harvestable_forest_c(h_index) + harvestable_patch_c end if - else if (currentPatch%anthro_disturbance_label .eq. secondaryforest .and. & + else if (currentPatch%land_use_label .eq. secondaryland .and. & currentPatch%age_since_anthro_disturbance < secondary_age_threshold) then ! Secondary young if(hlm_harvest_catnames(h_index) .eq. "HARVEST_SH2") then @@ -537,7 +537,7 @@ end subroutine get_harvestable_carbon ! ============================================================================ - subroutine get_harvest_rate_carbon (patch_anthro_disturbance_label, hlm_harvest_catnames, & + subroutine 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) @@ -550,7 +550,7 @@ subroutine get_harvest_rate_carbon (patch_anthro_disturbance_label, hlm_harvest_ ! Arguments real(r8), intent(in) :: hlm_harvest_rates(:) ! annual harvest rate per hlm category character(len=64), intent(in) :: hlm_harvest_catnames(:) ! names of hlm harvest categories - integer, intent(in) :: patch_anthro_disturbance_label ! patch level anthro_disturbance_label + 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) :: harvestable_forest_c(:) ! site level forest c matching criteria available for harvest, kgC site-1 real(r8), intent(out) :: harvest_rate ! area fraction @@ -584,17 +584,17 @@ subroutine get_harvest_rate_carbon (patch_anthro_disturbance_label, hlm_harvest_ ! mature and secondary young). ! Get the harvest rate from HLM do h_index = 1,hlm_num_lu_harvest_cats - if (patch_anthro_disturbance_label .eq. primaryforest) then + if (patch_land_use_label .eq. primaryland) then if(hlm_harvest_catnames(h_index) .eq. "HARVEST_VH1" .or. & hlm_harvest_catnames(h_index) .eq. "HARVEST_VH2") then harvest_rate_c = harvest_rate_c + hlm_harvest_rates(h_index) endif - else if (patch_anthro_disturbance_label .eq. secondaryforest .and. & + else if (patch_land_use_label .eq. secondaryland .and. & secondary_age >= secondary_age_threshold) then if(hlm_harvest_catnames(h_index) .eq. "HARVEST_SH1") then harvest_rate_c = harvest_rate_c + hlm_harvest_rates(h_index) endif - else if (patch_anthro_disturbance_label .eq. secondaryforest .and. & + else if (patch_land_use_label .eq. secondaryland .and. & secondary_age < secondary_age_threshold) then if(hlm_harvest_catnames(h_index) .eq. "HARVEST_SH2" .or. & hlm_harvest_catnames(h_index) .eq. "HARVEST_SH3") then @@ -606,7 +606,7 @@ subroutine get_harvest_rate_carbon (patch_anthro_disturbance_label, hlm_harvest_ ! Determine harvest status (succesful or not) ! Here only three categories are used do h_index = 1,hlm_num_lu_harvest_cats - if (patch_anthro_disturbance_label .eq. primaryforest) then + if (patch_land_use_label .eq. primaryland) then if(hlm_harvest_catnames(h_index) .eq. "HARVEST_VH1" ) then if(harvestable_forest_c(h_index) >= harvest_rate_c) then harvest_rate_supply = harvest_rate_supply + harvestable_forest_c(h_index) @@ -615,7 +615,7 @@ subroutine get_harvest_rate_carbon (patch_anthro_disturbance_label, hlm_harvest_ harvest_tag(h_index) = 1 end if end if - else if (patch_anthro_disturbance_label .eq. secondaryforest .and. & + else if (patch_land_use_label .eq. secondaryland .and. & secondary_age >= secondary_age_threshold) then if(hlm_harvest_catnames(h_index) .eq. "HARVEST_SH1" ) then if(harvestable_forest_c(h_index) >= harvest_rate_c) then @@ -625,7 +625,7 @@ subroutine get_harvest_rate_carbon (patch_anthro_disturbance_label, hlm_harvest_ harvest_tag(h_index) = 1 end if end if - else if (patch_anthro_disturbance_label .eq. secondaryforest .and. & + else if (patch_land_use_label .eq. secondaryland .and. & secondary_age < secondary_age_threshold) then if(hlm_harvest_catnames(h_index) .eq. "HARVEST_SH2" ) then if(harvestable_forest_c(h_index) >= harvest_rate_c) then diff --git a/biogeochem/EDMortalityFunctionsMod.F90 b/biogeochem/EDMortalityFunctionsMod.F90 index d849121c0e..fc941d0371 100644 --- a/biogeochem/EDMortalityFunctionsMod.F90 +++ b/biogeochem/EDMortalityFunctionsMod.F90 @@ -234,7 +234,7 @@ end subroutine mortality_rates ! ============================================================================ subroutine Mortality_Derivative( currentSite, currentCohort, bc_in, btran_ft, & - mean_temp, anthro_disturbance_label, age_since_anthro_disturbance, & + mean_temp, land_use_label, age_since_anthro_disturbance, & frac_site_primary, harvestable_forest_c, harvest_tag) ! @@ -252,7 +252,7 @@ subroutine Mortality_Derivative( currentSite, currentCohort, bc_in, btran_ft, & type(bc_in_type), intent(in) :: bc_in real(r8), intent(in) :: btran_ft(maxpft) real(r8), intent(in) :: mean_temp - integer, intent(in) :: anthro_disturbance_label + integer, intent(in) :: land_use_label real(r8), intent(in) :: age_since_anthro_disturbance real(r8), intent(in) :: frac_site_primary @@ -291,7 +291,7 @@ subroutine Mortality_Derivative( currentSite, currentCohort, bc_in, btran_ft, & bc_in%hlm_harvest_rates, & bc_in%hlm_harvest_catnames, & bc_in%hlm_harvest_units, & - anthro_disturbance_label, & + land_use_label, & age_since_anthro_disturbance, & frac_site_primary, harvestable_forest_c, harvest_tag) diff --git a/biogeochem/EDPatchDynamicsMod.F90 b/biogeochem/EDPatchDynamicsMod.F90 index 6f022ccfbd..ec234bef76 100644 --- a/biogeochem/EDPatchDynamicsMod.F90 +++ b/biogeochem/EDPatchDynamicsMod.F90 @@ -1,5 +1,5 @@ -module EDPatchDynamicsMod +module EDPatchDynamicsMod ! ============================================================================ ! Controls formation, creation, fusing and termination of patch level processes. ! ============================================================================ @@ -35,6 +35,7 @@ module EDPatchDynamicsMod use FatesConstantsMod , only : dtype_ifall use FatesConstantsMod , only : dtype_ilog use FatesConstantsMod , only : dtype_ifire + use FatesConstantsMod , only : dtype_ilandusechange use FatesConstantsMod , only : ican_upper use PRTGenericMod , only : num_elements use PRTGenericMod , only : element_list @@ -54,6 +55,9 @@ module EDPatchDynamicsMod use FatesInterfaceTypesMod , only : hlm_use_nocomp use FatesInterfaceTypesMod , only : hlm_use_fixed_biogeog use FatesInterfaceTypesMod , only : hlm_num_lu_harvest_cats + use FatesInterfaceTypesMod , only : hlm_use_luh + use FatesInterfaceTypesMod , only : hlm_num_luh2_states + use FatesInterfaceTypesMod , only : hlm_num_luh2_transitions use FatesGlobals , only : endrun => fates_endrun use FatesConstantsMod , only : r8 => fates_r8 use FatesConstantsMod , only : itrue, ifalse @@ -69,7 +73,6 @@ module EDPatchDynamicsMod use EDLoggingMortalityMod, only : get_harvestable_carbon use EDLoggingMortalityMod, only : get_harvest_debt use EDParamsMod , only : fates_mortality_disturbance_fraction - use EDParamsMod , only : regeneration_model use FatesAllometryMod , only : carea_allom use FatesAllometryMod , only : set_root_fraction use FatesConstantsMod , only : g_per_kg @@ -77,8 +80,9 @@ module EDPatchDynamicsMod use FatesConstantsMod , only : days_per_sec use FatesConstantsMod , only : years_per_day use FatesConstantsMod , only : nearzero - use FatesConstantsMod , only : primaryforest, secondaryforest - use FatesConstantsMod , only : n_anthro_disturbance_categories + use FatesConstantsMod , only : primaryland, secondaryland, pastureland, rangeland, cropland + use FatesConstantsMod , only : n_landuse_cats + use FatesLandUseChangeMod, only : get_landuse_transition_rates use FatesConstantsMod , only : fates_unset_r8 use FatesConstantsMod , only : fates_unset_int use FatesConstantsMod , only : hlm_harvest_carbon @@ -98,11 +102,9 @@ module EDPatchDynamicsMod use SFParamsMod, only : SF_VAL_CWD_FRAC use EDParamsMod, only : logging_event_code use EDParamsMod, only : logging_export_frac + use EDParamsMod, only : maxpatches_by_landuse use FatesRunningMeanMod, only : ema_sdlng_mdd use FatesRunningMeanMod, only : ema_sdlng_emerg_h2o, ema_sdlng_mort_par, ema_sdlng2sap_par - use EDParamsMod, only : maxpatch_primary - use EDParamsMod, only : maxpatch_secondary - use EDParamsMod, only : maxpatch_total use FatesRunningMeanMod, only : ema_24hr, fixed_24hr, ema_lpa, ema_longterm ! CIME globals @@ -146,6 +148,7 @@ module EDPatchDynamicsMod real(r8), parameter :: existing_litt_localization = 1.0_r8 real(r8), parameter :: treefall_localization = 0.0_r8 real(r8), parameter :: burn_localization = 0.0_r8 + real(r8), parameter :: landusechange_localization = 1.0_r8 integer :: istat ! return status code character(len=255) :: smsg ! Message string for deallocation errors @@ -207,13 +210,14 @@ subroutine disturbance_rates( site_in, bc_in) 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] !---------------------------------------------------------------------------------------------- ! 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 fractino of the site that is primary land + ! first calculate the fraction of the site that is primary land call get_frac_site_primary(site_in, frac_site_primary) ! get available biomass for harvest for all patches @@ -247,7 +251,7 @@ subroutine disturbance_rates( site_in, bc_in) bc_in%hlm_harvest_rates, & bc_in%hlm_harvest_catnames, & bc_in%hlm_harvest_units, & - currentPatch%anthro_disturbance_label, & + currentPatch%land_use_label, & currentPatch%age_since_anthro_disturbance, & frac_site_primary, & harvestable_forest_c, & @@ -266,13 +270,26 @@ 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) + else + 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 ! --------------------------------------------------------------------------------------------- - ! zero the diagnostic disturbance rate fields - site_in%potential_disturbance_rates(1:N_DIST_TYPES) = 0._r8 - ! Recalculate total canopy area prior to resolving the disturbance currentPatch => site_in%oldest_patch do while (associated(currentPatch)) @@ -295,6 +312,15 @@ subroutine disturbance_rates( site_in, bc_in) currentPatch%disturbance_rates(dtype_ifire) = 0.0_r8 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 + currentPatch%landuse_transition_rates(1:n_landuse_cats) = min(1._r8, & + landuse_transition_matrix(currentPatch%land_use_label,1:n_landuse_cats) / & + current_fates_landuse_state_vector(currentPatch%land_use_label)) + else + currentPatch%landuse_transition_rates = 0.0_r8 + end if currentCohort => currentPatch%shortest do while(associated(currentCohort)) @@ -336,11 +362,11 @@ subroutine disturbance_rates( site_in, bc_in) ! The canopy is NOT closed. if(bc_in%hlm_harvest_units == hlm_harvest_carbon) then - call get_harvest_rate_carbon (currentPatch%anthro_disturbance_label, bc_in%hlm_harvest_catnames, & + 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%anthro_disturbance_label, bc_in%hlm_harvest_catnames, & + 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 @@ -367,12 +393,6 @@ subroutine disturbance_rates( site_in, bc_in) ! Fire Disturbance Rate currentPatch%disturbance_rates(dtype_ifire) = currentPatch%frac_burnt - ! calculate a disgnostic sum of disturbance rates for different classes of disturbance across all patches in this site. - do i_dist = 1,N_DIST_TYPES - site_in%potential_disturbance_rates(i_dist) = site_in%potential_disturbance_rates(i_dist) + & - currentPatch%disturbance_rates(i_dist) * currentPatch%area * AREA_INV - end do - ! Fires can't burn the whole patch, as this causes /0 errors. if (currentPatch%disturbance_rates(dtype_ifire) > 0.98_r8)then msg = 'very high fire areas'//trim(A2S(currentPatch%disturbance_rates(:)))//trim(N2S(currentPatch%frac_burnt)) @@ -380,11 +400,14 @@ subroutine disturbance_rates( site_in, bc_in) 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(:)) .gt. 1.0_r8 ) then - tempsum = sum(currentPatch%disturbance_rates(:)) + if ( (sum(currentPatch%disturbance_rates(:)) + sum(currentPatch%landuse_transition_rates(1:n_landuse_cats))) .gt. 1.0_r8 ) 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 end do + do i_dist = 1,n_landuse_cats + currentPatch%landuse_transition_rates(i_dist) = currentPatch%landuse_transition_rates(i_dist) / tempsum + end do endif currentPatch => currentPatch%younger @@ -398,7 +421,9 @@ end subroutine disturbance_rates subroutine spawn_patches( currentSite, bc_in) ! ! !DESCRIPTION: - ! In this subroutine, the following happens + ! In this subroutine, the following happens, + ! all of which within a complex loop structure of (from outermost to innermost loop), + ! nocomp-PFT, disturbance type, donor patch land use label, and receiver patch land use label: ! 1) the total area disturbed is calculated ! 2) a new patch is created ! 3) properties are averaged @@ -411,28 +436,28 @@ subroutine spawn_patches( currentSite, bc_in) ! 10) Area checked, and patchno recalculated. ! ! !USES: - - use EDParamsMod , only : ED_val_understorey_death, logging_coll_under_frac - use EDCohortDynamicsMod , only : terminate_cohorts - use FatesConstantsMod , only : rsnbl_math_prec + 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 ! ! !ARGUMENTS: type (ed_site_type), intent(inout) :: currentSite type (bc_in_type), intent(in) :: bc_in ! ! !LOCAL VARIABLES: - type (fates_patch_type) , pointer :: new_patch - type (fates_patch_type) , pointer :: new_patch_primary - type (fates_patch_type) , pointer :: new_patch_secondary + type (fates_patch_type) , pointer :: newPatch type (fates_patch_type) , pointer :: currentPatch type (fates_cohort_type), pointer :: currentCohort type (fates_cohort_type), pointer :: nc type (fates_cohort_type), pointer :: storesmallcohort type (fates_cohort_type), pointer :: storebigcohort real(r8) :: site_areadis_primary ! total area disturbed (to primary forest) in m2 per site per day - real(r8) :: site_areadis_secondary ! total area disturbed (to secondary forest) in m2 per site per day + real(r8) :: site_areadis_secondary ! total area disturbed (to secondary forest) in m2 per site per day real(r8) :: patch_site_areadis ! total area disturbed in m2 per patch per day + real(r8) :: site_areadis ! total site area disturbed in m2 per day real(r8) :: age ! notional age of this patch in years integer :: el ! element loop index integer :: pft ! pft loop index @@ -446,13 +471,18 @@ subroutine spawn_patches( currentSite, bc_in) real(r8) :: struct_c ! structure carbon [kg] real(r8) :: total_c ! total carbon of plant [kg] real(r8) :: leaf_burn_frac ! fraction of leaves burned in fire - ! for both woody and grass species + ! for both woody and grass species real(r8) :: leaf_m ! leaf mass during partial burn calculations - logical :: found_youngest_primary ! logical for finding the first primary forest patch integer :: min_nocomp_pft, max_nocomp_pft, i_nocomp_pft integer :: i_disturbance_type, i_dist2 ! iterators for looping over disturbance types + integer :: i_landusechange_receiverpatchlabel ! iterator for the land use change types + integer :: i_donorpatch_landuse_type ! iterator for the land use change types donor patch + integer :: start_receiver_lulabel ! starting bound for receiver landuse label type loop + integer :: end_receiver_lulabel ! ending bound for receiver landuse label type loop 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? + !--------------------------------------------------------------------- storesmallcohort => null() ! storage of the smallest cohort for insertion routine @@ -467,9 +497,10 @@ subroutine spawn_patches( currentSite, bc_in) endif ! zero the diagnostic disturbance rate fields - currentSite%disturbance_rates_primary_to_primary(1:N_DIST_TYPES) = 0._r8 - currentSite%disturbance_rates_primary_to_secondary(1:N_DIST_TYPES) = 0._r8 - currentSite%disturbance_rates_secondary_to_secondary(1:N_DIST_TYPES) = 0._r8 + currentSite%disturbance_rates(:,:,:) = 0._r8 + + ! get rules for vegetation clearing during land use change + call get_landusechange_rules(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 @@ -477,330 +508,443 @@ subroutine spawn_patches( currentSite, bc_in) ! If nocomp is not enabled, then this is not much of a loop, it only passes through once. nocomp_pft_loop: do i_nocomp_pft = min_nocomp_pft,max_nocomp_pft + ! 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 - ! calculate area of disturbed land, in this timestep, by summing contributions from each existing patch. - currentPatch => currentSite%youngest_patch - - site_areadis_primary = 0.0_r8 - site_areadis_secondary = 0.0_r8 + ! 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 + + ! figure out what land use label(s) the receiver patch for disturbance from patches with + ! this disturbance label and disturbance of this type will have, and set receiver label loop bounds accordingly. + + ! 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. + + select case(i_disturbance_type) + case(dtype_ifire) + start_receiver_lulabel = i_donorpatch_landuse_type + end_receiver_lulabel = i_donorpatch_landuse_type + case(dtype_ifall) + start_receiver_lulabel = i_donorpatch_landuse_type + end_receiver_lulabel = i_donorpatch_landuse_type + case(dtype_ilog) + 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 + end_receiver_lulabel = n_landuse_cats + 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 + + ! 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 + + ! 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. + + ! 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. + 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. + patchloop_areadis: do while(associated(currentPatch)) + + cp_nocomp_matches_1_if: if ( hlm_use_nocomp .eq. ifalse .or. & + currentPatch%nocomp_pft_label .eq. i_nocomp_pft ) then + + patchlabel_matches_lutype_if_areadis: if (currentPatch%land_use_label .eq. i_donorpatch_landuse_type) then + + disturbance_rate = 0.0_r8 + if ( i_disturbance_type .ne. dtype_ilandusechange) then + disturbance_rate = currentPatch%disturbance_rates(i_disturbance_type) + else + disturbance_rate = currentPatch%landuse_transition_rates(i_landusechange_receiverpatchlabel) + endif + + if(disturbance_rate > (1.0_r8 + rsnbl_math_prec)) then + write(fates_log(),*) 'patch disturbance rate > 1 ?',disturbance_rate + call currentPatch%Dump() + call endrun(msg=errMsg(sourcefile, __LINE__)) + else if (disturbance_rate > 1.0_r8) then + disturbance_rate = 1.0_r8 + end if + + ! Only create new patches that have non-negligible amount of land + if((currentPatch%area*disturbance_rate) > nearzero ) then + + site_areadis = site_areadis + currentPatch%area * disturbance_rate + + ! track disturbance rates to output to history + currentSite%disturbance_rates(i_disturbance_type,i_donorpatch_landuse_type,i_landusechange_receiverpatchlabel) = & + currentSite%disturbance_rates(i_disturbance_type,i_donorpatch_landuse_type,i_landusechange_receiverpatchlabel) + & + currentPatch%area * disturbance_rate * AREA_INV + end if + + end if patchlabel_matches_lutype_if_areadis + end if cp_nocomp_matches_1_if + currentPatch => currentPatch%older + enddo patchloop_areadis! end loop over patches. sum area disturbed for all patches. + + ! It is possible that no disturbance area was generated + if ( site_areadis > nearzero) then + + age = 0.0_r8 + + ! create an empty patch, to absorb newly disturbed area + allocate(newPatch) + + call newPatch%Create(age, site_areadis, i_landusechange_receiverpatchlabel, i_nocomp_pft, & + hlm_numSWb, numpft, currentSite%nlevsoil, hlm_current_tod, & + regeneration_model) + + ! Initialize the litter pools to zero, these + ! pools will be populated by looping over the existing patches + ! and transfering in mass + do el=1,num_elements + call newPatch%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 + newPatch%tallest => null() + newPatch%shortest => null() - do while(associated(currentPatch)) + endif - cp_nocomp_matches_1_if: if ( hlm_use_nocomp .eq. ifalse .or. & - currentPatch%nocomp_pft_label .eq. i_nocomp_pft ) then + ! we now have a new patch and know its area, but it is otherwise empty. Next, we + ! loop round all the patches that contribute surviving individuals and litter + ! pools to the new patch. We only loop the pre-existing patches, so + ! quit the loop if the current patch is null, and ignore the patch if the patch's categorical variables do not + ! match those of the outermost set of loops (i.e. the patch's land-use label or nocomp-PFT label + ! are not what we are resolving right now). - disturbance_rate = currentPatch%disturbance_rates(i_disturbance_type) + currentPatch => currentSite%oldest_patch + patchloop: do while(associated(currentPatch)) - if(disturbance_rate > (1.0_r8 + rsnbl_math_prec)) then - write(fates_log(),*) 'patch disturbance rate > 1 ?',disturbance_rate - call currentPatch%Dump() - call endrun(msg=errMsg(sourcefile, __LINE__)) - end if + cp_nocomp_matches_2_if: if ( hlm_use_nocomp .eq. ifalse .or. & + currentPatch%nocomp_pft_label .eq. i_nocomp_pft ) then - ! Only create new patches that have non-negligible amount of land - if((currentPatch%area*disturbance_rate) > nearzero ) then + patchlabel_matches_lutype_if: if (currentPatch%land_use_label .eq. i_donorpatch_landuse_type) then - ! figure out whether the receiver patch for disturbance from this patch will be - ! primary or secondary land receiver patch is primary forest only if both the - ! donor patch is primary forest and the current disturbance type is not logging - if ( currentPatch%anthro_disturbance_label .eq. primaryforest .and. & - (i_disturbance_type .ne. dtype_ilog) ) then - site_areadis_primary = site_areadis_primary + currentPatch%area * disturbance_rate + ! disturbance_rate is the fraction of the patch's area that is disturbed and donated + disturbance_rate = 0.0_r8 + if ( i_disturbance_type .ne. dtype_ilandusechange) then + disturbance_rate = currentPatch%disturbance_rates(i_disturbance_type) + else + disturbance_rate = currentPatch%landuse_transition_rates(i_landusechange_receiverpatchlabel) + endif - ! track disturbance rates to output to history - currentSite%disturbance_rates_primary_to_primary(i_disturbance_type) = & - currentSite%disturbance_rates_primary_to_primary(i_disturbance_type) + & - currentPatch%area * disturbance_rate * AREA_INV + ! patch_site_areadis is the absolute amount of the patch's area that is disturbed and donated + patch_site_areadis = currentPatch%area * disturbance_rate + + areadis_gt_zero_if: if ( patch_site_areadis > nearzero ) then - else - site_areadis_secondary = site_areadis_secondary + currentPatch%area * disturbance_rate + if(.not.associated(newPatch))then + write(fates_log(),*) 'Patch spawning has attempted to point to' + write(fates_log(),*) 'an un-allocated patch' + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if - ! track disturbance rates to output to history - if (currentPatch%anthro_disturbance_label .eq. secondaryforest) then - currentSite%disturbance_rates_secondary_to_secondary(i_disturbance_type) = & - currentSite%disturbance_rates_secondary_to_secondary(i_disturbance_type) + & - currentPatch%area * disturbance_rate * AREA_INV + ! for the case where the donating patch is not primary, and + ! the current disturbance from this patch is non-anthropogenic, + ! then we need to average in the time-since-anthropogenic-disturbance + ! from the donor patch into that of the receiver patch + if ( currentPatch%land_use_label .gt. primaryland .and. & + (i_disturbance_type .lt. dtype_ilog) ) then - else - currentSite%disturbance_rates_primary_to_secondary(i_disturbance_type) = & - currentSite%disturbance_rates_primary_to_secondary(i_disturbance_type) + & - currentPatch%area * disturbance_rate * AREA_INV - endif + newPatch%age_since_anthro_disturbance = newPatch%age_since_anthro_disturbance + & + currentPatch%age_since_anthro_disturbance * (patch_site_areadis / site_areadis) + + endif - endif + ! Transfer the litter existing already in the donor patch to the new patch + ! This call will only transfer non-burned litter to new patch + ! and burned litter to atmosphere. Thus it is important to zero burnt_frac_litter when + ! fire is not the current disturbance regime. - end if + if(i_disturbance_type .ne. dtype_ifire) then + currentPatch%burnt_frac_litter(:) = 0._r8 + end if - end if cp_nocomp_matches_1_if - currentPatch => currentPatch%older - enddo ! end loop over patches. sum area disturbed for all patches. - - ! It is possible that no disturbance area was generated - if ( (site_areadis_primary + site_areadis_secondary) > nearzero) then - - age = 0.0_r8 - - ! create two empty patches, to absorb newly disturbed primary and secondary forest area - ! first create patch to receive primary forest area - if ( site_areadis_primary .gt. nearzero ) then - allocate(new_patch_primary) - call new_patch_primary%Create(age, site_areadis_primary, & - primaryforest, i_nocomp_pft, hlm_numSWb, numpft, & - currentSite%nlevsoil, hlm_current_tod, regeneration_model) - - ! Initialize the litter pools to zero, these - ! pools will be populated by looping over the existing patches - ! and transfering in mass - do el=1,num_elements - call new_patch_primary%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_primary%tallest => null() - new_patch_primary%shortest => null() + 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) + case (dtype_ifire) + call fire_litter_fluxes(currentSite, currentPatch, & + newPatch, patch_site_areadis,bc_in) + case (dtype_ifall) + call mortality_litter_fluxes(currentSite, currentPatch, & + newPatch, patch_site_areadis,bc_in) + case (dtype_ilandusechange) + call landusechange_litter_fluxes(currentSite, currentPatch, & + newPatch, patch_site_areadis,bc_in, & + clearing_matrix(i_donorpatch_landuse_type,i_landusechange_receiverpatchlabel)) + 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 - endif - ! next create patch to receive secondary forest area - if (site_areadis_secondary .gt. nearzero) then - allocate(new_patch_secondary) - call new_patch_secondary%Create(age, site_areadis_secondary, & - secondaryforest, i_nocomp_pft, hlm_numSWb, numpft, & - currentSite%nlevsoil, hlm_current_tod, regeneration_model) - - ! Initialize the litter pools to zero, these - ! pools will be populated by looping over the existing patches - ! and transfering in mass - do el=1,num_elements - call new_patch_secondary%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_secondary%tallest => null() - new_patch_secondary%shortest => null() + ! 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) - endif - ! loop round all the patches that contribute surviving indivduals and litter - ! pools to the new patch. We only loop the pre-existing patches, so - ! quit the loop if the current patch is either null, or matches the - ! two new pointers. - - currentPatch => currentSite%oldest_patch - do while(associated(currentPatch)) - - cp_nocomp_matches_2_if: if ( hlm_use_nocomp .eq. ifalse .or. & - currentPatch%nocomp_pft_label .eq. i_nocomp_pft ) then - - ! This is the amount of patch area that is disturbed, and donated by the donor - disturbance_rate = currentPatch%disturbance_rates(i_disturbance_type) - patch_site_areadis = currentPatch%area * disturbance_rate - - - if ( patch_site_areadis > nearzero ) then - - ! figure out whether the receiver patch for disturbance from this patch - ! will be primary or secondary land receiver patch is primary forest - ! only if both the donor patch is primary forest and the current - ! disturbance type is not logging - if (currentPatch%anthro_disturbance_label .eq. primaryforest .and. & - (i_disturbance_type .ne. dtype_ilog)) then - new_patch => new_patch_primary - else - new_patch => new_patch_secondary - endif - - if(.not.associated(new_patch))then - write(fates_log(),*) 'Patch spawning has attempted to point to' - write(fates_log(),*) 'an un-allocated patch' - call endrun(msg=errMsg(sourcefile, __LINE__)) - end if - - ! for the case where the donating patch is secondary forest, if - ! the current disturbance from this patch is non-anthropogenic, - ! we need to average in the time-since-anthropogenic-disturbance - ! from the donor patch into that of the receiver patch - if ( currentPatch%anthro_disturbance_label .eq. secondaryforest .and. & - (i_disturbance_type .ne. dtype_ilog) ) then - - new_patch%age_since_anthro_disturbance = new_patch%age_since_anthro_disturbance + & - currentPatch%age_since_anthro_disturbance * (patch_site_areadis / site_areadis_secondary) - - endif - - - ! Transfer the litter existing already in the donor patch to the new patch - ! This call will only transfer non-burned litter to new patch - ! and burned litter to atmosphere. Thus it is important to zero burnt_frac_litter when - ! fire is not the current disturbance regime. - - if(i_disturbance_type .ne. dtype_ifire) then - currentPatch%burnt_frac_litter(:) = 0._r8 - end if - - call TransLitterNewPatch( currentSite, currentPatch, new_patch, patch_site_areadis) - - ! Transfer in litter fluxes from plants in various contexts of death and destruction - - if(i_disturbance_type .eq. dtype_ilog) then - call logging_litter_fluxes(currentSite, currentPatch, & - new_patch, patch_site_areadis,bc_in) - elseif(i_disturbance_type .eq. dtype_ifire) then - call fire_litter_fluxes(currentSite, currentPatch, & - new_patch, patch_site_areadis,bc_in) - else - call mortality_litter_fluxes(currentSite, currentPatch, & - new_patch, patch_site_areadis,bc_in) - endif - - - ! Copy any means or timers from the original patch to the new patch - ! These values will inherit all info from the original patch - ! -------------------------------------------------------------------------- - call new_patch%tveg24%CopyFromDonor(currentPatch%tveg24) - call new_patch%tveg_lpa%CopyFromDonor(currentPatch%tveg_lpa) - - if ( regeneration_model == TRS_regeneration ) then - call new_patch%seedling_layer_par24%CopyFromDonor(currentPatch%seedling_layer_par24) - call new_patch%sdlng_mort_par%CopyFromDonor(currentPatch%sdlng_mort_par) - call new_patch%sdlng2sap_par%CopyFromDonor(currentPatch%sdlng2sap_par) - do pft = 1,numpft - call new_patch%sdlng_emerg_smp(pft)%p%CopyFromDonor(currentPatch%sdlng_emerg_smp(pft)%p) - call new_patch%sdlng_mdd(pft)%p%CopyFromDonor(currentPatch%sdlng_mdd(pft)%p) - enddo - end if - - call new_patch%tveg_longterm%CopyFromDonor(currentPatch%tveg_longterm) - - ! -------------------------------------------------------------------------- - ! The newly formed patch from disturbance (new_patch), has now been given - ! some litter from dead plants and pre-existing litter from the donor patches. - ! - ! 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) - - !this is the case as the new patch probably doesn't have a closed canopy, and - ! even if it does, that will be sorted out in canopy_structure. - nc%canopy_layer = 1 - nc%canopy_layer_yesterday = 1._r8 - - sapw_c = currentCohort%prt%GetState(sapw_organ, carbon12_element) - struct_c = currentCohort%prt%GetState(struct_organ, carbon12_element) - leaf_c = currentCohort%prt%GetState(leaf_organ, carbon12_element) - fnrt_c = currentCohort%prt%GetState(fnrt_organ, carbon12_element) - store_c = currentCohort%prt%GetState(store_organ, carbon12_element) - total_c = sapw_c + struct_c + leaf_c + fnrt_c + store_c - - ! treefall mortality is the current disturbance - if(i_disturbance_type .eq. dtype_ifall) then - - if(currentCohort%canopy_layer == 1)then - - ! In the donor patch we are left with fewer trees because the area has decreased - ! the plant density for large trees does not actually decrease in the donor patch - ! because this is the part of the original patch where no trees have actually fallen - ! The diagnostic cmort,bmort,hmort, and frmort rates have already been saved - - currentCohort%n = currentCohort%n * (1.0_r8 - fates_mortality_disturbance_fraction * & - min(1.0_r8,currentCohort%dmort * hlm_freq_day)) - - nc%n = 0.0_r8 ! kill all of the trees who caused the disturbance. - - nc%cmort = nan ! The mortality diagnostics are set to nan - ! because the cohort should dissappear - nc%hmort = nan - nc%bmort = nan - nc%frmort = nan - nc%smort = nan - nc%asmort = nan - nc%dgmort = nan - nc%lmort_direct = nan - nc%lmort_collateral = nan - nc%lmort_infra = nan - nc%l_degrad = nan + 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 - else - ! small trees - if( prt_params%woody(currentCohort%pft) == itrue)then + 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. + ! + ! 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 + cohortloop: 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=newPatch%tveg_lpa%GetMean()) + + call nc%ZeroValues() + + ! nc is the new cohort that goes in the disturbed patch (newPatch)... currentCohort + ! is the curent cohort that stays in the donor patch (currentPatch) + call currentCohort%Copy(nc) + + !this is the case as the new patch probably doesn't have a closed canopy, and + ! even if it does, that will be sorted out in canopy_structure. + nc%canopy_layer = 1 + nc%canopy_layer_yesterday = 1._r8 + + sapw_c = currentCohort%prt%GetState(sapw_organ, carbon12_element) + struct_c = currentCohort%prt%GetState(struct_organ, carbon12_element) + leaf_c = currentCohort%prt%GetState(leaf_organ, carbon12_element) + fnrt_c = currentCohort%prt%GetState(fnrt_organ, carbon12_element) + 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. + + disttype_case: select case(i_disturbance_type) + + ! treefall mortality is the current disturbance + case (dtype_ifall) + + in_canopy_if_falldtype: if(currentCohort%canopy_layer == 1)then + + ! In the donor patch we are left with fewer trees because the area has decreased + ! the plant density for large trees does not actually decrease in the donor patch + ! because this is the part of the original patch where no trees have actually fallen + ! The diagnostic cmort,bmort,hmort, and frmort rates have already been saved + + currentCohort%n = currentCohort%n * (1.0_r8 - fates_mortality_disturbance_fraction * & + min(1.0_r8,currentCohort%dmort * hlm_freq_day)) + + nc%n = 0.0_r8 ! kill all of the trees who caused the disturbance. + + nc%cmort = nan ! The mortality diagnostics are set to nan + ! because the cohort should dissappear + nc%hmort = nan + nc%bmort = nan + nc%frmort = nan + nc%smort = nan + nc%asmort = nan + nc%dgmort = nan + nc%lmort_direct = nan + nc%lmort_collateral = nan + nc%lmort_infra = nan + nc%l_degrad = nan + + else + ! understory trees + woody_if_falldtype: if( prt_params%woody(currentCohort%pft) == itrue)then + + + ! Survivorship of undestory woody plants. Two step process. + ! Step 1: Reduce current number of plants to reflect the + ! change in area. + ! The number density per square are doesn't change, + ! but since the patch is smaller and cohort counts + ! are absolute, reduce this number. + + nc%n = currentCohort%n * patch_site_areadis/currentPatch%area + + ! because the mortality rate due to impact for the cohorts which + ! had been in the understory and are now in the newly- + ! disturbed patch is very high, passing the imort directly to history + ! results in large numerical errors, on account of the sharply + ! reduced number densities. so instead pass this info via a + ! site-level diagnostic variable before reducing the number density. + + currentSite%imort_rate(currentCohort%size_class, currentCohort%pft) = & + currentSite%imort_rate(currentCohort%size_class, currentCohort%pft) + & + nc%n * ED_val_understorey_death / hlm_freq_day + + + currentSite%imort_carbonflux(currentCohort%pft) = & + currentSite%imort_carbonflux(currentCohort%pft) + & + (nc%n * ED_val_understorey_death / hlm_freq_day ) * & + total_c * g_per_kg * days_per_sec * years_per_day * ha_per_m2 + + currentSite%imort_abg_flux(currentCohort%size_class, currentCohort%pft) = & + currentSite%imort_abg_flux(currentCohort%size_class, currentCohort%pft) + & + (nc%n * ED_val_understorey_death / hlm_freq_day ) * & + ( (sapw_c + struct_c + store_c) * prt_params%allom_agb_frac(currentCohort%pft) + & + leaf_c ) * & + g_per_kg * days_per_sec * years_per_day * ha_per_m2 + + + ! Step 2: Apply survivor ship function based on the understory death fraction + ! remaining of understory plants of those that are knocked over + ! by the overstorey trees dying... + nc%n = nc%n * (1.0_r8 - ED_val_understorey_death) + + ! since the donor patch split and sent a fraction of its members + ! to the new patch and a fraction to be preserved in itself, + ! when reporting diagnostic rates, we must carry over the mortality rates from + ! the donor that were applied before the patch split. Remember this is only + ! for diagnostics. But think of it this way, the rates are weighted by + ! number density in EDCLMLink, and the number density of this new patch is donated + ! so with the number density must come the effective mortality rates. + + nc%cmort = currentCohort%cmort + nc%hmort = currentCohort%hmort + nc%bmort = currentCohort%bmort + nc%frmort = currentCohort%frmort + nc%smort = currentCohort%smort + nc%asmort = currentCohort%asmort + nc%dgmort = currentCohort%dgmort + nc%dmort = currentCohort%dmort + nc%lmort_direct = currentCohort%lmort_direct + nc%lmort_collateral = currentCohort%lmort_collateral + nc%lmort_infra = currentCohort%lmort_infra + + ! understory trees that might potentially be knocked over in the disturbance. + ! The existing (donor) patch should not have any impact mortality, it should + ! only lose cohorts due to the decrease in area. This is not mortality. + ! Besides, the current and newly created patch sum to unity + + currentCohort%n = currentCohort%n * (1._r8 - patch_site_areadis/currentPatch%area) + + else + ! grass is not killed by mortality disturbance events. Just move it into the new patch area. + ! Just split the grass into the existing and new patch structures + nc%n = currentCohort%n * patch_site_areadis/currentPatch%area + + ! Those remaining in the existing + currentCohort%n = currentCohort%n * (1._r8 - patch_site_areadis/currentPatch%area) + + nc%cmort = currentCohort%cmort + nc%hmort = currentCohort%hmort + nc%bmort = currentCohort%bmort + nc%frmort = currentCohort%frmort + nc%smort = currentCohort%smort + nc%asmort = currentCohort%asmort + nc%dgmort = currentCohort%dgmort + nc%dmort = currentCohort%dmort + nc%lmort_direct = currentCohort%lmort_direct + nc%lmort_collateral = currentCohort%lmort_collateral + nc%lmort_infra = currentCohort%lmort_infra + + endif woody_if_falldtype + endif in_canopy_if_falldtype + + ! Fire is the current disturbance + case (dtype_ifire) + + ! Number of members in the new patch, before we impose fire survivorship + nc%n = currentCohort%n * patch_site_areadis/currentPatch%area + ! loss of individuals from source patch due to area shrinking + currentCohort%n = currentCohort%n * (1._r8 - patch_site_areadis/currentPatch%area) - ! Survivorship of undestory woody plants. Two step process. - ! Step 1: Reduce current number of plants to reflect the - ! change in area. - ! The number density per square are doesn't change, - ! but since the patch is smaller and cohort counts - ! are absolute, reduce this number. + levcan = currentCohort%canopy_layer - nc%n = currentCohort%n * patch_site_areadis/currentPatch%area + if(levcan==ican_upper) then - ! because the mortality rate due to impact for the cohorts which - ! had been in the understory and are now in the newly- - ! disturbed patch is very high, passing the imort directly to history - ! results in large numerical errors, on account of the sharply - ! reduced number densities. so instead pass this info via a - ! site-level diagnostic variable before reducing the number density. + ! before changing number densities, track total rate of trees that died + ! due to fire, as well as from each fire mortality term + currentSite%fmort_rate_canopy(currentCohort%size_class, currentCohort%pft) = & + currentSite%fmort_rate_canopy(currentCohort%size_class, currentCohort%pft) + & + nc%n * currentCohort%fire_mort / hlm_freq_day - currentSite%imort_rate(currentCohort%size_class, currentCohort%pft) = & - currentSite%imort_rate(currentCohort%size_class, currentCohort%pft) + & - nc%n * ED_val_understorey_death / hlm_freq_day + currentSite%fmort_carbonflux_canopy(currentCohort%pft) = & + currentSite%fmort_carbonflux_canopy(currentCohort%pft) + & + (nc%n * currentCohort%fire_mort) * & + total_c * g_per_kg * days_per_sec * ha_per_m2 + else + ! understory + currentSite%fmort_rate_ustory(currentCohort%size_class, currentCohort%pft) = & + currentSite%fmort_rate_ustory(currentCohort%size_class, currentCohort%pft) + & + nc%n * currentCohort%fire_mort / hlm_freq_day - currentSite%imort_carbonflux(currentCohort%pft) = & - currentSite%imort_carbonflux(currentCohort%pft) + & - (nc%n * ED_val_understorey_death / hlm_freq_day ) * & - total_c * days_per_sec * years_per_day * ha_per_m2 + currentSite%fmort_carbonflux_ustory(currentCohort%pft) = & + currentSite%fmort_carbonflux_ustory(currentCohort%pft) + & + (nc%n * currentCohort%fire_mort) * & + total_c * g_per_kg * days_per_sec * ha_per_m2 + end if - currentSite%imort_abg_flux(currentCohort%size_class, currentCohort%pft) = & - currentSite%imort_abg_flux(currentCohort%size_class, currentCohort%pft) + & - (nc%n * ED_val_understorey_death / hlm_freq_day ) * & + currentSite%fmort_abg_flux(currentCohort%size_class, currentCohort%pft) = & + currentSite%fmort_abg_flux(currentCohort%size_class, currentCohort%pft) + & + (nc%n * currentCohort%fire_mort) * & ( (sapw_c + struct_c + store_c) * prt_params%allom_agb_frac(currentCohort%pft) + & - leaf_c ) * days_per_sec * years_per_day * ha_per_m2 + leaf_c ) * & + g_per_kg * days_per_sec * ha_per_m2 - ! Step 2: Apply survivor ship function based on the understory death fraction - ! remaining of understory plants of those that are knocked over - ! by the overstorey trees dying... - nc%n = nc%n * (1.0_r8 - ED_val_understorey_death) + currentSite%fmort_rate_cambial(currentCohort%size_class, currentCohort%pft) = & + currentSite%fmort_rate_cambial(currentCohort%size_class, currentCohort%pft) + & + nc%n * currentCohort%cambial_mort / hlm_freq_day + currentSite%fmort_rate_crown(currentCohort%size_class, currentCohort%pft) = & + currentSite%fmort_rate_crown(currentCohort%size_class, currentCohort%pft) + & + nc%n * currentCohort%crownfire_mort / hlm_freq_day - ! since the donor patch split and sent a fraction of its members - ! to the new patch and a fraction to be preserved in itself, - ! when reporting diagnostic rates, we must carry over the mortality rates from - ! the donor that were applied before the patch split. Remember this is only - ! for diagnostics. But think of it this way, the rates are weighted by - ! number density in EDCLMLink, and the number density of this new patch is donated - ! so with the number density must come the effective mortality rates. + ! loss of individual from fire in new patch. + nc%n = nc%n * (1.0_r8 - currentCohort%fire_mort) nc%cmort = currentCohort%cmort nc%hmort = currentCohort%hmort @@ -814,444 +958,325 @@ subroutine spawn_patches( currentSite, bc_in) nc%lmort_collateral = currentCohort%lmort_collateral nc%lmort_infra = currentCohort%lmort_infra - ! understory trees that might potentially be knocked over in the disturbance. - ! The existing (donor) patch should not have any impact mortality, it should - ! only lose cohorts due to the decrease in area. This is not mortality. - ! Besides, the current and newly created patch sum to unity - - currentCohort%n = currentCohort%n * (1._r8 - patch_site_areadis/currentPatch%area) - - else - ! grass is not killed by mortality disturbance events. Just move it into the new patch area. - ! Just split the grass into the existing and new patch structures - nc%n = currentCohort%n * patch_site_areadis/currentPatch%area - - ! Those remaining in the existing - currentCohort%n = currentCohort%n * (1._r8 - patch_site_areadis/currentPatch%area) - - nc%cmort = currentCohort%cmort - nc%hmort = currentCohort%hmort - nc%bmort = currentCohort%bmort - nc%frmort = currentCohort%frmort - nc%smort = currentCohort%smort - nc%asmort = currentCohort%asmort - nc%dgmort = currentCohort%dgmort - nc%dmort = currentCohort%dmort - nc%lmort_direct = currentCohort%lmort_direct - nc%lmort_collateral = currentCohort%lmort_collateral - nc%lmort_infra = currentCohort%lmort_infra - - endif - endif - - ! Fire is the current disturbance - elseif (i_disturbance_type .eq. dtype_ifire ) then - - ! Number of members in the new patch, before we impose fire survivorship - nc%n = currentCohort%n * patch_site_areadis/currentPatch%area - - ! loss of individuals from source patch due to area shrinking - currentCohort%n = currentCohort%n * (1._r8 - patch_site_areadis/currentPatch%area) - - levcan = currentCohort%canopy_layer - - if(levcan==ican_upper) then - - ! before changing number densities, track total rate of trees that died - ! due to fire, as well as from each fire mortality term - currentSite%fmort_rate_canopy(currentCohort%size_class, currentCohort%pft) = & - currentSite%fmort_rate_canopy(currentCohort%size_class, currentCohort%pft) + & - nc%n * currentCohort%fire_mort / hlm_freq_day - - currentSite%fmort_carbonflux_canopy(currentCohort%pft) = & - currentSite%fmort_carbonflux_canopy(currentCohort%pft) + & - (nc%n * currentCohort%fire_mort) * & - total_c * g_per_kg * days_per_sec * ha_per_m2 - - else - currentSite%fmort_rate_ustory(currentCohort%size_class, currentCohort%pft) = & - currentSite%fmort_rate_ustory(currentCohort%size_class, currentCohort%pft) + & - nc%n * currentCohort%fire_mort / hlm_freq_day - - currentSite%fmort_carbonflux_ustory(currentCohort%pft) = & - currentSite%fmort_carbonflux_ustory(currentCohort%pft) + & - (nc%n * currentCohort%fire_mort) * & - total_c * g_per_kg * days_per_sec * ha_per_m2 - end if - - currentSite%fmort_abg_flux(currentCohort%size_class, currentCohort%pft) = & - currentSite%fmort_abg_flux(currentCohort%size_class, currentCohort%pft) + & - (nc%n * currentCohort%fire_mort) * & - ( (sapw_c + struct_c + store_c) * prt_params%allom_agb_frac(currentCohort%pft) + & - leaf_c ) * & - g_per_kg * days_per_sec * ha_per_m2 - - - currentSite%fmort_rate_cambial(currentCohort%size_class, currentCohort%pft) = & - currentSite%fmort_rate_cambial(currentCohort%size_class, currentCohort%pft) + & - nc%n * currentCohort%cambial_mort / hlm_freq_day - currentSite%fmort_rate_crown(currentCohort%size_class, currentCohort%pft) = & - currentSite%fmort_rate_crown(currentCohort%size_class, currentCohort%pft) + & - nc%n * currentCohort%crownfire_mort / hlm_freq_day - - ! loss of individual from fire in new patch. - nc%n = nc%n * (1.0_r8 - currentCohort%fire_mort) - - nc%cmort = currentCohort%cmort - nc%hmort = currentCohort%hmort - nc%bmort = currentCohort%bmort - nc%frmort = currentCohort%frmort - nc%smort = currentCohort%smort - nc%asmort = currentCohort%asmort - nc%dgmort = currentCohort%dgmort - nc%dmort = currentCohort%dmort - nc%lmort_direct = currentCohort%lmort_direct - nc%lmort_collateral = currentCohort%lmort_collateral - nc%lmort_infra = currentCohort%lmort_infra - - - ! Some of of the leaf mass from living plants has been - ! burned off. Here, we remove that mass, and - ! tally it in the flux we sent to the atmosphere - - if(prt_params%woody(currentCohort%pft) == itrue)then - leaf_burn_frac = currentCohort%fraction_crown_burned - else - - ! Grasses determine their fraction of leaves burned here - - leaf_burn_frac = currentPatch%burnt_frac_litter(lg_sf) - endif - - ! Perform a check to make sure that spitfire gave - ! us reasonable mortality and burn fraction rates - - if( (leaf_burn_frac < 0._r8) .or. & - (leaf_burn_frac > 1._r8) .or. & - (currentCohort%fire_mort < 0._r8) .or. & - (currentCohort%fire_mort > 1._r8)) then - write(fates_log(),*) 'unexpected fire fractions' - write(fates_log(),*) prt_params%woody(currentCohort%pft) - write(fates_log(),*) leaf_burn_frac - write(fates_log(),*) currentCohort%fire_mort - call endrun(msg=errMsg(sourcefile, __LINE__)) - end if - - do el = 1,num_elements - - leaf_m = nc%prt%GetState(leaf_organ, element_list(el)) - ! for woody plants burn only leaves - if(int(prt_params%woody(currentCohort%pft)) == itrue)then - - leaf_m = nc%prt%GetState(leaf_organ, element_list(el)) - - else - ! for grasses burn all aboveground tissues - leaf_m = nc%prt%GetState(leaf_organ, element_list(el)) + & - nc%prt%GetState(sapw_organ, element_list(el)) + & - nc%prt%GetState(struct_organ, element_list(el)) - - endif - - currentSite%mass_balance(el)%burn_flux_to_atm = & - currentSite%mass_balance(el)%burn_flux_to_atm + & - leaf_burn_frac * leaf_m * nc%n - end do - - ! Here the mass is removed from the plant - - if(int(prt_params%woody(currentCohort%pft)) == itrue)then - call PRTBurnLosses(nc%prt, leaf_organ, leaf_burn_frac) - else - call PRTBurnLosses(nc%prt, leaf_organ, leaf_burn_frac) - call PRTBurnLosses(nc%prt, sapw_organ, leaf_burn_frac) - call PRTBurnLosses(nc%prt, struct_organ, leaf_burn_frac) - endif - - currentCohort%fraction_crown_burned = 0.0_r8 - nc%fraction_crown_burned = 0.0_r8 - - - - ! Logging is the current disturbance - elseif (i_disturbance_type .eq. dtype_ilog ) then - ! If this cohort is in the upper canopy. It generated - if(currentCohort%canopy_layer == 1)then + ! Some of of the leaf mass from living plants has been + ! burned off. Here, we remove that mass, and + ! tally it in the flux we sent to the atmosphere - ! calculate the survivorship of disturbed trees because non-harvested - nc%n = currentCohort%n * currentCohort%l_degrad - ! nc%n = (currentCohort%l_degrad / (currentCohort%l_degrad + & - ! currentCohort%lmort_direct + currentCohort%lmort_collateral + - ! currentCohort%lmort_infra) ) * & - ! currentCohort%n * patch_site_areadis/currentPatch%area + if(prt_params%woody(currentCohort%pft) == itrue)then + leaf_burn_frac = currentCohort%fraction_crown_burned + else - ! Reduce counts in the existing/donor patch according to the logging rate - currentCohort%n = currentCohort%n * & - (1.0_r8 - min(1.0_r8,(currentCohort%lmort_direct + & - currentCohort%lmort_collateral + & - currentCohort%lmort_infra + currentCohort%l_degrad))) + ! Grasses determine their fraction of leaves burned here - nc%cmort = currentCohort%cmort - nc%hmort = currentCohort%hmort - nc%bmort = currentCohort%bmort - nc%frmort = currentCohort%frmort - nc%smort = currentCohort%smort - nc%asmort = currentCohort%asmort - nc%dgmort = currentCohort%dgmort - nc%dmort = currentCohort%dmort + leaf_burn_frac = currentPatch%burnt_frac_litter(lg_sf) + endif - ! since these are the ones that weren't logged, - ! set the logging mortality rates as zero - nc%lmort_direct = 0._r8 - nc%lmort_collateral = 0._r8 - nc%lmort_infra = 0._r8 + ! Perform a check to make sure that spitfire gave + ! us reasonable mortality and burn fraction rates - else - - ! What to do with cohorts in the understory of a logging generated - ! disturbance patch? - - if(prt_params%woody(currentCohort%pft) == itrue)then - - - ! Survivorship of undestory woody plants. Two step process. - ! Step 1: Reduce current number of plants to reflect the - ! change in area. - ! The number density per square are doesn't change, - ! but since the patch is smaller - ! and cohort counts are absolute, reduce this number. - nc%n = currentCohort%n * patch_site_areadis/currentPatch%area - - ! because the mortality rate due to impact for the cohorts which had - ! been in the understory and are now in the newly- - ! disturbed patch is very high, passing the imort directly to - ! history results in large numerical errors, on account - ! of the sharply reduced number densities. so instead pass this info - ! via a site-level diagnostic variable before reducing - ! the number density. - currentSite%imort_rate(currentCohort%size_class, currentCohort%pft) = & - currentSite%imort_rate(currentCohort%size_class, currentCohort%pft) + & - nc%n * currentPatch%fract_ldist_not_harvested * & - logging_coll_under_frac / hlm_freq_day - - currentSite%imort_carbonflux(currentCohort%pft) = & - currentSite%imort_carbonflux(currentCohort%pft) + & - (nc%n * currentPatch%fract_ldist_not_harvested * & - logging_coll_under_frac/ hlm_freq_day ) * & - total_c * days_per_sec * years_per_day * ha_per_m2 - - currentSite%imort_abg_flux(currentCohort%size_class, currentCohort%pft) = & - currentSite%imort_abg_flux(currentCohort%size_class, currentCohort%pft) + & - (nc%n * currentPatch%fract_ldist_not_harvested * & - logging_coll_under_frac/ hlm_freq_day ) * & - ( ( sapw_c + struct_c + store_c) * prt_params%allom_agb_frac(currentCohort%pft) + & - leaf_c ) * days_per_sec * years_per_day * ha_per_m2 - - - ! Step 2: Apply survivor ship function based on the understory death fraction - - ! remaining of understory plants of those that are knocked - ! over by the overstorey trees dying... - ! LOGGING SURVIVORSHIP OF UNDERSTORY PLANTS IS SET AS A NEW PARAMETER - ! in the fatesparameter files - nc%n = nc%n * (1.0_r8 - & - (1.0_r8-currentPatch%fract_ldist_not_harvested) * logging_coll_under_frac) - - ! Step 3: Reduce the number count of cohorts in the - ! original/donor/non-disturbed patch to reflect the area change - currentCohort%n = currentCohort%n * (1._r8 - patch_site_areadis/currentPatch%area) - - nc%cmort = currentCohort%cmort - nc%hmort = currentCohort%hmort - nc%bmort = currentCohort%bmort - nc%frmort = currentCohort%frmort - nc%smort = currentCohort%smort - nc%asmort = currentCohort%asmort - nc%dgmort = currentCohort%dgmort - nc%dmort = currentCohort%dmort - nc%lmort_direct = currentCohort%lmort_direct - nc%lmort_collateral = currentCohort%lmort_collateral - nc%lmort_infra = currentCohort%lmort_infra - - else - - ! grass is not killed by mortality disturbance events. - ! Just move it into the new patch area. - ! Just split the grass into the existing and new patch structures + if( (leaf_burn_frac < 0._r8) .or. & + (leaf_burn_frac > 1._r8) .or. & + (currentCohort%fire_mort < 0._r8) .or. & + (currentCohort%fire_mort > 1._r8)) then + write(fates_log(),*) 'unexpected fire fractions' + write(fates_log(),*) prt_params%woody(currentCohort%pft) + write(fates_log(),*) leaf_burn_frac + write(fates_log(),*) currentCohort%fire_mort + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + + do el = 1,num_elements + + leaf_m = nc%prt%GetState(leaf_organ, element_list(el)) + ! for woody plants burn only leaves + if(int(prt_params%woody(currentCohort%pft)) == itrue)then + + leaf_m = nc%prt%GetState(leaf_organ, element_list(el)) + + else + ! for grasses burn all aboveground tissues + leaf_m = nc%prt%GetState(leaf_organ, element_list(el)) + & + nc%prt%GetState(sapw_organ, element_list(el)) + & + nc%prt%GetState(struct_organ, element_list(el)) + + endif + + currentSite%mass_balance(el)%burn_flux_to_atm = & + currentSite%mass_balance(el)%burn_flux_to_atm + & + leaf_burn_frac * leaf_m * nc%n + end do + + ! Here the mass is removed from the plant + + if(int(prt_params%woody(currentCohort%pft)) == itrue)then + call PRTBurnLosses(nc%prt, leaf_organ, leaf_burn_frac) + else + call PRTBurnLosses(nc%prt, leaf_organ, leaf_burn_frac) + call PRTBurnLosses(nc%prt, sapw_organ, leaf_burn_frac) + call PRTBurnLosses(nc%prt, struct_organ, leaf_burn_frac) + endif + + currentCohort%fraction_crown_burned = 0.0_r8 + nc%fraction_crown_burned = 0.0_r8 + + + + ! Logging is the current disturbance + case (dtype_ilog) + + ! If this cohort is in the upper canopy. It generated + in_canopy_if_logdtype: if(currentCohort%canopy_layer == 1)then + + ! calculate the survivorship of disturbed trees because non-harvested + nc%n = currentCohort%n * currentCohort%l_degrad + ! nc%n = (currentCohort%l_degrad / (currentCohort%l_degrad + & + ! currentCohort%lmort_direct + currentCohort%lmort_collateral + + ! currentCohort%lmort_infra) ) * & + ! currentCohort%n * patch_site_areadis/currentPatch%area + + ! Reduce counts in the existing/donor patch according to the logging rate + currentCohort%n = currentCohort%n * & + (1.0_r8 - min(1.0_r8,(currentCohort%lmort_direct + & + currentCohort%lmort_collateral + & + currentCohort%lmort_infra + currentCohort%l_degrad))) + + nc%cmort = currentCohort%cmort + nc%hmort = currentCohort%hmort + nc%bmort = currentCohort%bmort + nc%frmort = currentCohort%frmort + nc%smort = currentCohort%smort + nc%asmort = currentCohort%asmort + nc%dgmort = currentCohort%dgmort + nc%dmort = currentCohort%dmort + + ! since these are the ones that weren't logged, + ! set the logging mortality rates as zero + nc%lmort_direct = 0._r8 + nc%lmort_collateral = 0._r8 + nc%lmort_infra = 0._r8 + + else + + ! What to do with cohorts in the understory of a logging generated + ! disturbance patch? + + woody_if_logdtype: if(prt_params%woody(currentCohort%pft) == itrue)then + + + ! Survivorship of undestory woody plants. Two step process. + ! Step 1: Reduce current number of plants to reflect the + ! change in area. + ! The number density per square are doesn't change, + ! but since the patch is smaller + ! and cohort counts are absolute, reduce this number. + nc%n = currentCohort%n * patch_site_areadis/currentPatch%area + + ! because the mortality rate due to impact for the cohorts which had + ! been in the understory and are now in the newly- + ! disturbed patch is very high, passing the imort directly to + ! history results in large numerical errors, on account + ! of the sharply reduced number densities. so instead pass this info + ! via a site-level diagnostic variable before reducing + ! the number density. + currentSite%imort_rate(currentCohort%size_class, currentCohort%pft) = & + currentSite%imort_rate(currentCohort%size_class, currentCohort%pft) + & + nc%n * currentPatch%fract_ldist_not_harvested * & + logging_coll_under_frac / hlm_freq_day + + currentSite%imort_carbonflux(currentCohort%pft) = & + currentSite%imort_carbonflux(currentCohort%pft) + & + (nc%n * currentPatch%fract_ldist_not_harvested * & + logging_coll_under_frac/ hlm_freq_day ) * & + total_c * g_per_kg * days_per_sec * years_per_day * ha_per_m2 + + currentSite%imort_abg_flux(currentCohort%size_class, currentCohort%pft) = & + currentSite%imort_abg_flux(currentCohort%size_class, currentCohort%pft) + & + (nc%n * currentPatch%fract_ldist_not_harvested * & + logging_coll_under_frac/ hlm_freq_day ) * & + ( ( sapw_c + struct_c + store_c) * prt_params%allom_agb_frac(currentCohort%pft) + & + leaf_c ) * days_per_sec * years_per_day * ha_per_m2 + + ! Step 2: Apply survivor ship function based on the understory death fraction + + ! remaining of understory plants of those that are knocked + ! over by the overstorey trees dying... + ! LOGGING SURVIVORSHIP OF UNDERSTORY PLANTS IS SET AS A NEW PARAMETER + ! in the fatesparameter files + nc%n = nc%n * (1.0_r8 - & + (1.0_r8-currentPatch%fract_ldist_not_harvested) * logging_coll_under_frac) + + ! Step 3: Reduce the number count of cohorts in the + ! original/donor/non-disturbed patch to reflect the area change + currentCohort%n = currentCohort%n * (1._r8 - patch_site_areadis/currentPatch%area) + + nc%cmort = currentCohort%cmort + nc%hmort = currentCohort%hmort + nc%bmort = currentCohort%bmort + nc%frmort = currentCohort%frmort + nc%smort = currentCohort%smort + nc%asmort = currentCohort%asmort + nc%dgmort = currentCohort%dgmort + nc%dmort = currentCohort%dmort + nc%lmort_direct = currentCohort%lmort_direct + nc%lmort_collateral = currentCohort%lmort_collateral + nc%lmort_infra = currentCohort%lmort_infra + + else + + ! grass is not killed by mortality disturbance events. + ! Just move it into the new patch area. + ! Just split the grass into the existing and new patch structures + nc%n = currentCohort%n * patch_site_areadis/currentPatch%area + + ! Those remaining in the existing + currentCohort%n = currentCohort%n * (1._r8 - patch_site_areadis/currentPatch%area) + + ! No grass impact mortality imposed on the newly created patch + nc%cmort = currentCohort%cmort + nc%hmort = currentCohort%hmort + nc%bmort = currentCohort%bmort + nc%frmort = currentCohort%frmort + nc%smort = currentCohort%smort + nc%asmort = currentCohort%asmort + nc%dgmort = currentCohort%dgmort + nc%dmort = currentCohort%dmort + nc%lmort_direct = currentCohort%lmort_direct + nc%lmort_collateral = currentCohort%lmort_collateral + nc%lmort_infra = currentCohort%lmort_infra + + endif woody_if_logdtype ! is/is-not woody + + endif in_canopy_if_logdtype ! Select canopy layer + + ! Land use change is the current disturbance type + case (dtype_ilandusechange) + + ! Number of members in the new patch, before we impose LUC survivorship nc%n = currentCohort%n * patch_site_areadis/currentPatch%area - ! Those remaining in the existing + ! loss of individuals from source patch due to area shrinking currentCohort%n = currentCohort%n * (1._r8 - patch_site_areadis/currentPatch%area) - ! No grass impact mortality imposed on the newly created patch - nc%cmort = currentCohort%cmort - nc%hmort = currentCohort%hmort - nc%bmort = currentCohort%bmort - nc%frmort = currentCohort%frmort - nc%smort = currentCohort%smort - nc%asmort = currentCohort%asmort - nc%dgmort = currentCohort%dgmort - nc%dmort = currentCohort%dmort - nc%lmort_direct = currentCohort%lmort_direct - nc%lmort_collateral = currentCohort%lmort_collateral - nc%lmort_infra = currentCohort%lmort_infra + ! now apply survivorship based on the type of landuse transition + if ( clearing_matrix(i_donorpatch_landuse_type,i_landusechange_receiverpatchlabel) ) then + ! kill everything + nc%n = 0._r8 + end if + + 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 disttype_case ! Select disturbance mode + + ! if some plants in the new temporary cohort survived the transfer to the new patch, + ! then put the cohort into the linked list. + cohort_n_gt_zero: if (nc%n > 0.0_r8) then + storebigcohort => newPatch%tallest + storesmallcohort => newPatch%shortest + if(associated(newPatch%tallest))then + tnull = 0 + else + tnull = 1 + newPatch%tallest => nc + nc%taller => null() + endif + + if(associated(newPatch%shortest))then + snull = 0 + else + snull = 1 + newPatch%shortest => nc + nc%shorter => null() + endif + !nc%patchptr => new_patch + call insert_cohort(newPatch, nc, newPatch%tallest, newPatch%shortest, & + tnull, snull, storebigcohort, storesmallcohort) + + newPatch%tallest => storebigcohort + newPatch%shortest => storesmallcohort - endif ! is/is-not woody - - endif ! Select canopy layer - - else - write(fates_log(),*) 'unknown disturbance mode?' - write(fates_log(),*) 'i_disturbance_type: ',i_disturbance_type - call endrun(msg=errMsg(sourcefile, __LINE__)) - end if ! Select disturbance mode - - if (nc%n > 0.0_r8) then - storebigcohort => new_patch%tallest - storesmallcohort => new_patch%shortest - if(associated(new_patch%tallest))then - tnull = 0 + else + ! sadly, no plants in the cohort survived. on the bright side, we can deallocate their memory. + call nc%FreeMemory() + deallocate(nc, stat=istat, errmsg=smsg) + if (istat/=0) then + write(fates_log(),*) 'dealloc005: fail on deallocate(nc):'//trim(smsg) + call endrun(msg=errMsg(sourcefile, __LINE__)) + endif + endif cohort_n_gt_zero + + currentCohort => currentCohort%taller + enddo cohortloop + + call sort_cohorts(currentPatch) + + !update area of donor patch + oldarea = currentPatch%area + currentPatch%area = currentPatch%area - patch_site_areadis + + ! for all disturbance rates that haven't been resolved yet, increase their amount so that + ! they are the same amount of gridcell-scale disturbance relative to the original patch size + if (i_disturbance_type .lt. N_DIST_TYPES) then + do i_dist2 = i_disturbance_type+1,N_DIST_TYPES-1 + currentPatch%disturbance_rates(i_dist2) = currentPatch%disturbance_rates(i_dist2) & + * oldarea / currentPatch%area + end do + do i_dist2 = 1,n_landuse_cats + currentPatch%landuse_transition_rates(i_dist2) = currentPatch%landuse_transition_rates(i_dist2) & + * oldarea / currentPatch%area + end do else - tnull = 1 - new_patch%tallest => nc - nc%taller => null() - endif + do i_dist2 = i_landusechange_receiverpatchlabel+1,n_landuse_cats + currentPatch%landuse_transition_rates(i_dist2) = currentPatch%landuse_transition_rates(i_dist2) & + * oldarea / currentPatch%area + end do + end if - if(associated(new_patch%shortest))then - snull = 0 - else - snull = 1 - new_patch%shortest => nc - nc%shorter => null() - endif - !nc%patchptr => new_patch - call insert_cohort(new_patch, nc, new_patch%tallest, new_patch%shortest, & - tnull, snull, storebigcohort, storesmallcohort) + ! sort out the cohorts, since some of them may be so small as to need removing. + ! the first call to terminate cohorts removes sparse number densities, + ! the second call removes for all other reasons (sparse culling must happen + ! before fusion) + call terminate_cohorts(currentSite, currentPatch, 1,16,bc_in) + call fuse_cohorts(currentSite,currentPatch, bc_in) + call terminate_cohorts(currentSite, currentPatch, 2,16,bc_in) + call sort_cohorts(currentPatch) - new_patch%tallest => storebigcohort - new_patch%shortest => storesmallcohort - else + end if areadis_gt_zero_if ! if ( newPatch%area > nearzero ) then - ! Get rid of the new temporary cohort - call nc%FreeMemory() - deallocate(nc, stat=istat, errmsg=smsg) - if (istat/=0) then - write(fates_log(),*) 'dealloc005: fail on deallocate(nc):'//trim(smsg) - call endrun(msg=errMsg(sourcefile, __LINE__)) - endif - endif + end if patchlabel_matches_lutype_if - currentCohort => currentCohort%taller - enddo ! currentCohort - call sort_cohorts(currentPatch) - - !update area of donor patch - oldarea = currentPatch%area - currentPatch%area = currentPatch%area - patch_site_areadis - - ! for all disturbance rates that haven't been resolved yet, increase their amount so that - ! they are the same amount of gridcell-scale disturbance relative to the original patch size - if (i_disturbance_type .ne. N_DIST_TYPES) then - do i_dist2 = i_disturbance_type+1,N_DIST_TYPES - currentPatch%disturbance_rates(i_dist2) = currentPatch%disturbance_rates(i_dist2) & - * oldarea / currentPatch%area - end do - end if - - ! sort out the cohorts, since some of them may be so small as to need removing. - ! the first call to terminate cohorts removes sparse number densities, - ! the second call removes for all other reasons (sparse culling must happen - ! before fusion) - call terminate_cohorts(currentSite, currentPatch, 1,16,bc_in) - call fuse_cohorts(currentSite,currentPatch, bc_in) - call terminate_cohorts(currentSite, currentPatch, 2,16,bc_in) - call sort_cohorts(currentPatch) - - end if ! if ( new_patch%area > nearzero ) then - - end if cp_nocomp_matches_2_if - currentPatch => currentPatch%younger - - enddo ! currentPatch patch loop. - - !*************************/ - !** INSERT NEW PATCH(ES) INTO LINKED LIST - !*************************/ - - if ( site_areadis_primary .gt. nearzero) then - currentPatch => currentSite%youngest_patch - ! insert new youngest primary patch after all the secondary patches, if there are any. - ! this requires first finding the current youngest primary to insert the new one ahead of - if (currentPatch%anthro_disturbance_label .eq. secondaryforest ) then - found_youngest_primary = .false. - do while(associated(currentPatch) .and. .not. found_youngest_primary) - currentPatch => currentPatch%older - if (associated(currentPatch)) then - if (currentPatch%anthro_disturbance_label .eq. primaryforest) then - found_youngest_primary = .true. - endif - endif - end do - if (associated(currentPatch)) then - ! the case where we've found a youngest primary patch - new_patch_primary%older => currentPatch - new_patch_primary%younger => currentPatch%younger - currentPatch%younger%older => new_patch_primary - currentPatch%younger => new_patch_primary - else - ! the case where we haven't, because the patches are all secondaary, - ! and are putting a primary patch at the oldest end of the - ! linked list (not sure how this could happen, but who knows...) - new_patch_primary%older => null() - new_patch_primary%younger => currentSite%oldest_patch - currentSite%oldest_patch%older => new_patch_primary - currentSite%oldest_patch => new_patch_primary - endif - else - ! the case where there are no secondary patches at the start of the linked list (prior logic) - new_patch_primary%older => currentPatch - new_patch_primary%younger => null() - currentPatch%younger => new_patch_primary - currentSite%youngest_patch => new_patch_primary - endif - endif + end if cp_nocomp_matches_2_if + currentPatch => currentPatch%younger - ! insert first secondary at the start of the list - if ( site_areadis_secondary .gt. nearzero) then - currentPatch => currentSite%youngest_patch - new_patch_secondary%older => currentPatch - new_patch_secondary%younger=> null() - currentPatch%younger => new_patch_secondary - currentSite%youngest_patch => new_patch_secondary - endif + enddo patchloop ! currentPatch patch loop. + !*************************/ + !** INSERT NEW PATCH(ES) INTO LINKED LIST + !*************************/ - ! sort out the cohorts, since some of them may be so small as to need removing. - ! the first call to terminate cohorts removes sparse number densities, - ! the second call removes for all other reasons (sparse culling must happen - ! before fusion) + if ( site_areadis .gt. nearzero) then - if ( site_areadis_primary .gt. nearzero) then - call terminate_cohorts(currentSite, new_patch_primary, 1,17, bc_in) - call fuse_cohorts(currentSite,new_patch_primary, bc_in) - call terminate_cohorts(currentSite, new_patch_primary, 2,17, bc_in) - call sort_cohorts(new_patch_primary) - endif + call InsertPatch(currentSite, newPatch) - if ( site_areadis_secondary .gt. nearzero) then - call terminate_cohorts(currentSite, new_patch_secondary, 1,18,bc_in) - call fuse_cohorts(currentSite,new_patch_secondary, bc_in) - call terminate_cohorts(currentSite, new_patch_secondary, 2,18,bc_in) - call sort_cohorts(new_patch_secondary) - endif + ! sort out the cohorts, since some of them may be so small as to need removing. + ! the first call to terminate cohorts removes sparse number densities, + ! the second call removes for all other reasons (sparse culling must happen + ! before fusion) - endif !end new_patch area + call terminate_cohorts(currentSite, newPatch, 1,17, bc_in) + call fuse_cohorts(currentSite,newPatch, bc_in) + call terminate_cohorts(currentSite, newPatch, 2,17, bc_in) + call sort_cohorts(newPatch) + endif - call check_patch_area(currentSite) - call set_patchno(currentSite) + call check_patch_area(currentSite) + call set_patchno(currentSite) + end do landusechange_receiverpatchlabel_loop + end do landuse_donortype_loop end do disturbance_type_loop end do nocomp_pft_loop @@ -2098,8 +2123,269 @@ subroutine mortality_litter_fluxes(currentSite, currentPatch, & return end subroutine mortality_litter_fluxes + ! ============================================================================ + + subroutine landusechange_litter_fluxes(currentSite, currentPatch, & + newPatch, patch_site_areadis, bc_in, & + clearing_matrix_element) + ! + ! !DESCRIPTION: + ! CWD pool from land use change. + ! Carbon going from felled trees into CWD pool + ! Either kill everything or nothing on disturbed land, depending on clearing matrix + ! + ! !USES: + use SFParamsMod, only : SF_VAL_CWD_FRAC + ! + ! !ARGUMENTS: + type(ed_site_type) , intent(inout), target :: currentSite + type(fates_patch_type) , intent(inout), target :: currentPatch ! Donor Patch + type(fates_patch_type) , intent(inout), target :: newPatch ! New Patch + real(r8) , intent(in) :: patch_site_areadis ! Area being donated + type(bc_in_type) , intent(in) :: bc_in + logical , intent(in) :: clearing_matrix_element ! whether or not to clear vegetation + + ! + ! !LOCAL VARIABLES: + + type(fates_cohort_type), pointer :: currentCohort + type(litter_type), pointer :: new_litt + type(litter_type), pointer :: curr_litt + type(site_massbal_type), pointer :: site_mass + type(site_fluxdiags_type), pointer :: flux_diags + + real(r8) :: donatable_mass ! non-burned litter mass provided by the donor [kg] + ! some may or may not be retained by the donor + real(r8) :: burned_mass ! the mass of litter that was supposed to be provided + ! by the donor, but was burned [kg] + real(r8) :: remainder_area ! current patch's remaining area after donation [m2] + real(r8) :: retain_frac ! the fraction of litter mass retained by the donor patch + real(r8) :: bcroot ! amount of below ground coarse root per cohort kg + real(r8) :: bstem ! amount of above ground stem biomass per cohort kg + real(r8) :: leaf_burn_frac ! fraction of leaves burned + real(r8) :: leaf_m ! leaf mass [kg] + real(r8) :: fnrt_m ! fineroot mass [kg] + real(r8) :: sapw_m ! sapwood mass [kg] + real(r8) :: store_m ! storage mass [kg] + real(r8) :: struct_m ! structure mass [kg] + real(r8) :: repro_m ! Reproductive mass (seeds/flowers) [kg] + real(r8) :: num_dead_trees ! total number of dead trees passed in with the burn area + real(r8) :: num_live_trees ! total number of live trees passed in with the burn area + real(r8) :: donate_m2 ! area normalization for litter mass destined to new patch [m-2] + real(r8) :: retain_m2 ! area normalization for litter mass staying in donor patch [m-2] + real(r8) :: dcmpy_frac ! fraction of mass going to each decomposability partition + integer :: el ! element loop index + integer :: sl ! soil layer index + integer :: c ! loop index for coarse woody debris pools + integer :: pft ! loop index for plant functional types + integer :: dcmpy ! loop index for decomposability pool + integer :: element_id ! parteh compatible global element index + real(r8) :: trunk_product_site ! flux of carbon in trunk products exported off site [ kgC/site ] + ! (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 + + ! If plant hydraulics are turned on, account for water leaving the plant-soil + ! mass balance through the dead trees + if (hlm_use_planthydro == itrue) then + currentCohort => currentPatch%shortest + do while(associated(currentCohort)) + num_dead_trees = (currentCohort%n*patch_site_areadis/currentPatch%area) + call AccumulateMortalityWaterStorage(currentSite,currentCohort,num_dead_trees) + currentCohort => currentCohort%taller + end do + end if + + + ! If/when sending litter fluxes to the donor patch, we divide the total + ! mass sent to that patch, by the area it will have remaining + ! after it donates area. + ! i.e. subtract the area it is donating. + + remainder_area = currentPatch%area - patch_site_areadis + + ! Calculate the fraction of litter to be retained versus donated + ! vis-a-vis the new and donor patch (if the area remaining + ! in the original donor patch is small, don't bother + ! retaining anything.) + retain_frac = (1.0_r8-landusechange_localization) * & + remainder_area/(newPatch%area+remainder_area) + + if(remainder_area > rsnbl_math_prec) then + retain_m2 = retain_frac/remainder_area + donate_m2 = (1.0_r8-retain_frac)/newPatch%area + else + retain_m2 = 0._r8 + donate_m2 = 1.0_r8/newPatch%area + end if + + do el = 1,num_elements + + ! Zero some site level accumulator diagnsotics + trunk_product_site = 0.0_r8 + + element_id = element_list(el) + site_mass => currentSite%mass_balance(el) + flux_diags => currentSite%flux_diags(el) + curr_litt => currentPatch%litter(el) ! Litter pool of "current" patch + new_litt => newPatch%litter(el) ! Litter pool of "new" patch + + ! ----------------------------------------------------------------------------- + ! PART 1) Handle mass fluxes associated with plants that died in the land use transition + ! ------------------------------------------------------------------------------ + + currentCohort => currentPatch%shortest + do while(associated(currentCohort)) + + pft = currentCohort%pft + + ! Number of trees that died because of the land use transition, per m2 of ground. + ! Divide their litter into the four litter streams, and spread + ! across ground surface. + ! ----------------------------------------------------------------------- + + fnrt_m = currentCohort%prt%GetState(fnrt_organ, element_id) + store_m = currentCohort%prt%GetState(store_organ, element_id) + repro_m = currentCohort%prt%GetState(repro_organ, element_id) + + if (prt_params%woody(currentCohort%pft) == itrue) then + ! Assumption: for woody plants fluxes from deadwood and sapwood go together in CWD pool + leaf_m = currentCohort%prt%GetState(leaf_organ,element_id) + sapw_m = currentCohort%prt%GetState(sapw_organ,element_id) + struct_m = currentCohort%prt%GetState(struct_organ,element_id) + else + ! for non-woody plants all stem fluxes go into the same leaf litter pool + leaf_m = currentCohort%prt%GetState(leaf_organ,element_id) + & + currentCohort%prt%GetState(sapw_organ,element_id) + & + currentCohort%prt%GetState(struct_organ,element_id) + sapw_m = 0._r8 + struct_m = 0._r8 + end if + + + ! Absolute number of dead trees being transfered in with the donated area + num_dead_trees = (currentCohort%n * & + patch_site_areadis/currentPatch%area) + + ! Contribution of dead trees to leaf litter + donatable_mass = num_dead_trees * (leaf_m+repro_m) * & + (1.0_r8-burn_frac_landusetransition) + + ! Contribution of dead trees to leaf burn-flux + burned_mass = num_dead_trees * (leaf_m+repro_m) * burn_frac_landusetransition + + do dcmpy=1,ndcmpy + dcmpy_frac = GetDecompyFrac(pft,leaf_organ,dcmpy) + new_litt%leaf_fines(dcmpy) = new_litt%leaf_fines(dcmpy) + & + donatable_mass*donate_m2*dcmpy_frac + curr_litt%leaf_fines(dcmpy) = curr_litt%leaf_fines(dcmpy) + & + donatable_mass*retain_m2*dcmpy_frac + end do + + site_mass%burn_flux_to_atm = site_mass%burn_flux_to_atm + burned_mass + + call set_root_fraction(currentSite%rootfrac_scr, pft, currentSite%zi_soil, & + bc_in%max_rooting_depth_index_col) + + ! Contribution of dead trees to root litter (no root burn flux to atm) + do dcmpy=1,ndcmpy + dcmpy_frac = GetDecompyFrac(pft,fnrt_organ,dcmpy) + do sl = 1,currentSite%nlevsoil + donatable_mass = num_dead_trees * (fnrt_m+store_m) * currentSite%rootfrac_scr(sl) + new_litt%root_fines(dcmpy,sl) = new_litt%root_fines(dcmpy,sl) + & + donatable_mass*donate_m2*dcmpy_frac + curr_litt%root_fines(dcmpy,sl) = curr_litt%root_fines(dcmpy,sl) + & + donatable_mass*retain_m2*dcmpy_frac + end do + end do + + ! 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) + + flux_diags%root_litter_input(pft) = & + flux_diags%root_litter_input(pft) + & + (fnrt_m + store_m) * num_dead_trees + + ! coarse root biomass per tree + bcroot = (sapw_m + struct_m) * (1.0_r8 - prt_params%allom_agb_frac(pft) ) + + ! below ground coarse woody debris from felled trees + do c = 1,ncwd + do sl = 1,currentSite%nlevsoil + donatable_mass = num_dead_trees * SF_val_CWD_frac(c) * & + bcroot * currentSite%rootfrac_scr(sl) + + new_litt%bg_cwd(c,sl) = new_litt%bg_cwd(c,sl) + & + donatable_mass * donate_m2 + curr_litt%bg_cwd(c,sl) = curr_litt%bg_cwd(c,sl) + & + donatable_mass * retain_m2 + + ! track diagnostics + flux_diags%cwd_bg_input(c) = & + flux_diags%cwd_bg_input(c) + & + donatable_mass + enddo + end do + + ! stem biomass per tree + bstem = (sapw_m + struct_m) * prt_params%allom_agb_frac(pft) + + ! Above ground coarse woody debris from twigs and small branches + ! a portion of this pool may burn + ! a portion may also be carried offsite as wood product + 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) + burned_mass = num_dead_trees * SF_val_CWD_frac(c) * bstem * & + burn_frac_landusetransition + + 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) + + woodproduct_mass = num_dead_trees * SF_val_CWD_frac(c) * bstem * & + woodproduct_frac_landusetransition + + trunk_product_site = trunk_product_site + & + woodproduct_mass + + site_mass%wood_product = site_mass%wood_product + & + woodproduct_mass + endif + new_litt%ag_cwd(c) = new_litt%ag_cwd(c) + donatable_mass * donate_m2 + curr_litt%ag_cwd(c) = curr_litt%ag_cwd(c) + donatable_mass * retain_m2 + flux_diags%cwd_ag_input(c) = flux_diags%cwd_ag_input(c) + donatable_mass + enddo + + currentCohort => currentCohort%taller + enddo + + ! Update the amount of carbon exported from the site through logging. + + if(element_id .eq. carbon12_element) then + currentSite%resources_management%trunk_product_site = & + currentSite%resources_management%trunk_product_site + & + trunk_product_site + end if + + + end do + + end if clear_veg_if + return + end subroutine landusechange_litter_fluxes + ! ============================================================================ - subroutine fuse_patches( csite, bc_in ) ! ! !DESCRIPTION: @@ -2120,14 +2406,13 @@ subroutine fuse_patches( csite, bc_in ) integer :: ft,z !counters for pft and height class real(r8) :: norm !normalized difference between biomass profiles real(r8) :: profiletol !tolerance of patch fusion routine. Starts off high and is reduced if there are too many patches. - integer :: nopatches(n_anthro_disturbance_categories) !number of patches presently in gridcell + integer :: nopatches(n_landuse_cats) !number of patches presently in gridcell integer :: iterate !switch of patch reduction iteration scheme. 1 to keep going, 0 to stop integer :: fuse_flag !do patches get fused (1) or not (0). - integer :: i_disttype !iterator over anthropogenic disturbance categories + integer :: i_lulabel !iterator over anthropogenic disturbance categories integer :: i_pftlabel !nocomp pft iterator real(r8) :: primary_land_fraction_beforefusion,primary_land_fraction_afterfusion integer :: pftlabelmin, pftlabelmax - real(r8) :: maxpatches(n_anthro_disturbance_categories) ! !--------------------------------------------------------------------- @@ -2138,31 +2423,14 @@ subroutine fuse_patches( csite, bc_in ) primary_land_fraction_beforefusion = 0._r8 primary_land_fraction_afterfusion = 0._r8 - nopatches(1:n_anthro_disturbance_categories) = 0 - - ! Its possible that, in nocomp modes, there are more categorically distinct patches than we allow as - ! primary patches in non-nocomp mode. So if this is the case, bump up the maximum number of primary patches - ! to let there be one for each type of nocomp PFT on the site. this is likely to lead to problems - ! if anthropogenic disturance is enabled. - if (hlm_use_nocomp.eq.itrue) then - maxpatches(primaryforest) = max(maxpatch_primary, sum(csite%use_this_pft)) - maxpatches(secondaryforest) = maxpatch_total - maxpatches(primaryforest) - if (maxpatch_total .lt. maxpatches(primaryforest)) then - write(fates_log(),*) 'too many PFTs and not enough patches for nocomp w/o fixed biogeog' - write(fates_log(),*) 'maxpatch_total,numpft',maxpatch_total,numpft, sum(csite%use_this_pft) - call endrun(msg=errMsg(sourcefile, __LINE__)) - endif - else - maxpatches(primaryforest) = maxpatch_primary - maxpatches(secondaryforest) = maxpatch_secondary - endif + nopatches(1:n_landuse_cats) = 0 currentPatch => currentSite%youngest_patch do while(associated(currentPatch)) - nopatches(currentPatch%anthro_disturbance_label) = & - nopatches(currentPatch%anthro_disturbance_label) + 1 + nopatches(currentPatch%land_use_label) = & + nopatches(currentPatch%land_use_label) + 1 - if (currentPatch%anthro_disturbance_label .eq. primaryforest) then + if (currentPatch%land_use_label .eq. primaryland) then primary_land_fraction_beforefusion = primary_land_fraction_beforefusion + & currentPatch%area * AREA_INV endif @@ -2178,10 +2446,10 @@ subroutine fuse_patches( csite, bc_in ) endif !---------------------------------------------------------------------! - ! iterate over anthropogenic disturbance categories + ! iterate over land use categories !---------------------------------------------------------------------! - disttype_loop: do i_disttype = 1, n_anthro_disturbance_categories + lulabel_loop: do i_lulabel = 1, n_landuse_cats !---------------------------------------------------------------------! ! We only really care about fusing patches if nopatches > 1 ! @@ -2190,7 +2458,7 @@ subroutine fuse_patches( csite, bc_in ) iterate = 1 !---------------------------------------------------------------------! - ! Keep doing this until nopatches <= maxpatch_total ! + ! Keep doing this until nopatches <= maxpatches_by_landuse(i_lulabel)! !---------------------------------------------------------------------! iterate_eq_1_loop: do while(iterate == 1) @@ -2223,8 +2491,8 @@ subroutine fuse_patches( csite, bc_in ) ! only fuse patches whose anthropogenic disturbance category matches ! ! that of the outer loop that we are in ! !--------------------------------------------------------------------! - anthro_dist_labels_match_if: if ( tpp%anthro_disturbance_label .eq. i_disttype .and. & - currentPatch%anthro_disturbance_label .eq. i_disttype) then + landuse_labels_match_if: if ( tpp%land_use_label .eq. i_lulabel .and. & + currentPatch%land_use_label .eq. i_lulabel) then nocomp_pft_labels_match_if: if (hlm_use_nocomp .eq. ifalse .or. & (tpp%nocomp_pft_label .eq. i_pftlabel .and. & @@ -2327,10 +2595,10 @@ subroutine fuse_patches( csite, bc_in ) ! a patch x patch loop, reset the patch fusion tolerance to the starting ! ! value so that any subsequent fusions in this loop are done with that ! ! value. otherwise we can end up in a situation where we've loosened the ! - ! fusion tolerance to get nopatches <= maxpatch_total, but then, ! + ! fusion tolerance to get nopatches <= maxpatches_by_landuse(i_lulabel), but then, ! ! having accomplished that, we continue through all the patch x patch ! ! combinations and then all the patches get fused, ending up with ! - ! nopatches << maxpatch_total and losing all heterogeneity. ! + ! nopatches << maxpatches_by_landuse(i_lulabel) and losing all heterogeneity. ! !------------------------------------------------------------------------! profiletol = ED_val_patch_fusion_tol @@ -2338,7 +2606,7 @@ subroutine fuse_patches( csite, bc_in ) endif fuseflagset_if endif different_patches_if endif nocomp_pft_labels_match_if - endif anthro_dist_labels_match_if + endif landuse_labels_match_if endif both_associated_if tpp => tpp%older @@ -2357,16 +2625,16 @@ subroutine fuse_patches( csite, bc_in ) !---------------------------------------------------------------------! ! Is the number of patches larger than the maximum? ! !---------------------------------------------------------------------! - nopatches(i_disttype) = 0 + nopatches(i_lulabel) = 0 currentPatch => currentSite%youngest_patch do while(associated(currentPatch)) - if (currentPatch%anthro_disturbance_label .eq. i_disttype) then - nopatches(i_disttype) = nopatches(i_disttype) +1 + if (currentPatch%land_use_label .eq. i_lulabel) then + nopatches(i_lulabel) = nopatches(i_lulabel) +1 endif currentPatch => currentPatch%older enddo - if(nopatches(i_disttype) > maxpatches(i_disttype))then + if(nopatches(i_lulabel) > maxpatches_by_landuse(i_lulabel))then iterate = 1 profiletol = profiletol * patch_fusion_tolerance_relaxation_increment @@ -2389,14 +2657,14 @@ subroutine fuse_patches( csite, bc_in ) iterate = 0 endif - enddo iterate_eq_1_loop ! iterate .eq. 1 ==> nopatches>maxpatch_total + enddo iterate_eq_1_loop ! iterate .eq. 1 ==> nopatches>maxpatches_by_landuse(i_lulabel) - end do disttype_loop + end do lulabel_loop currentPatch => currentSite%youngest_patch do while(associated(currentPatch)) - if (currentPatch%anthro_disturbance_label .eq. primaryforest) then + if (currentPatch%land_use_label .eq. primaryland) then primary_land_fraction_afterfusion = primary_land_fraction_afterfusion + & currentPatch%area * AREA_INV endif @@ -2455,8 +2723,8 @@ subroutine fuse_2_patches(csite, dp, rp) call rp%litter(el)%FuseLitter(rp%area,dp%area,dp%litter(el)) end do - if ( rp%anthro_disturbance_label .ne. dp%anthro_disturbance_label) then - write(fates_log(),*) 'trying to fuse patches with different anthro_disturbance_label values' + if ( rp%land_use_label .ne. dp%land_use_label) then + write(fates_log(),*) 'trying to fuse patches with different land_use_label values' call endrun(msg=errMsg(sourcefile, __LINE__)) endif @@ -2625,16 +2893,19 @@ subroutine terminate_patches(currentSite) ! You should had fused integer :: count_cycles logical :: gotfused + logical :: current_patch_is_youngest_lutype real(r8) areatot ! variable for checking whether the total patch area is wrong. !--------------------------------------------------------------------- - + + ! Initialize the count cycles count_cycles = 0 + ! Start at the youngest patch in the list and assume that the largest patch is this patch currentPatch => currentSite%youngest_patch - do while(associated(currentPatch)) + do while(associated(currentPatch)) lessthan_min_patcharea_if: if(currentPatch%area <= min_patch_area)then - + nocomp_if: if (hlm_use_nocomp .eq. itrue) then gotfused = .false. @@ -2642,7 +2913,7 @@ subroutine terminate_patches(currentSite) do while(associated(patchpointer)) if ( .not.associated(currentPatch,patchpointer) .and. & patchpointer%nocomp_pft_label .eq. currentPatch%nocomp_pft_label .and. & - patchpointer%anthro_disturbance_label .eq. currentPatch%anthro_disturbance_label .and. & + patchpointer%land_use_label .eq. currentPatch%land_use_label .and. & .not. gotfused) then call fuse_2_patches(currentSite, patchpointer, currentPatch) @@ -2656,82 +2927,90 @@ 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%anthro_disturbance_label + currentPatch%nocomp_pft_label, currentPatch%land_use_label endif else nocomp_if - ! Even if the patch area is small, avoid fusing it into its neighbor - ! if it is the youngest of all patches. We do this in attempts to maintain - ! a discrete patch for very young patches - ! However, if the patch to be fused is excessivlely small, then fuse - ! at all costs. If it is not fused, it will make + ! Even if the patch area is small, avoid fusing it into its neighbor + ! if it is the youngest of all patches. We do this in attempts to maintain + ! a discrete patch for very young patches. + ! However, if the patch to be fused is excessively small, then fuse + ! at all costs. - notyoungest_if: if ( .not.associated(currentPatch,currentSite%youngest_patch) .or. & + notyoungest_if: if ( .not.associated(currentPatch,currentSite%youngest_patch) .or. & currentPatch%area <= min_patch_area_forced ) then - - gotfused = .false. - associated_older_if: if(associated(currentPatch%older) )then - - if(debug) & - write(fates_log(),*) 'fusing to older patch because this one is too small',& - currentPatch%area, & - currentPatch%older%area - - ! We set a pointer to this patch, because - ! it will be returned by the subroutine as de-referenced - - olderPatch => currentPatch%older - - distlabel_1_if: if (currentPatch%anthro_disturbance_label .eq. olderPatch%anthro_disturbance_label) then - - call fuse_2_patches(currentSite, olderPatch, currentPatch) - - ! The fusion process has updated the "older" pointer on currentPatch - ! for us. - - ! This logic checks to make sure that the younger patch is not the youngest - ! patch. As mentioned earlier, we try not to fuse it. - - gotfused = .true. - else distlabel_1_if !i.e. anthro labels of two patches are not the same - countcycles_if: if (count_cycles .gt. 0) then - ! if we're having an incredibly hard time fusing patches because of their differing anthropogenic disturbance labels, - ! since the size is so small, let's sweep the problem under the rug and change the tiny patch's label to that of its older sibling - ! and then allow them to fuse together. - currentPatch%anthro_disturbance_label = olderPatch%anthro_disturbance_label + gotfused = .false. + + associated_older_if: if(associated(currentPatch%older)) then + + if(debug) & + write(fates_log(),*) 'fusing to older patch because this one is too small',& + currentPatch%area, & + currentPatch%older%area + + ! We set a pointer to this patch, because + ! it will be returned by the subroutine as de-referenced + + olderPatch => currentPatch%older + + ! If the older patch has the same landuse label fuse the older (donor) patch into the current patch + distlabel_1_if: if (currentPatch%land_use_label .eq. olderPatch%land_use_label) then + + if(debug) & + write(fates_log(),*) 'terminate: fused to older patch, same label: ', currentPatch%land_use_label, olderPatch%land_use_label + call fuse_2_patches(currentSite, olderPatch, currentPatch) + + ! The fusion process has updated the "older" pointer on currentPatch + ! for us. + + ! This logic checks to make sure that the younger patch is not the youngest + ! patch. As mentioned earlier, we try not to fuse it. + gotfused = .true. - endif countcycles_if - endif distlabel_1_if - endif associated_older_if - - not_gotfused_if: if( .not. gotfused .and. associated(currentPatch%younger) ) then - - if(debug) & - write(fates_log(),*) 'fusing to younger patch because oldest one is too small', & - currentPatch%area + else distlabel_1_if !i.e. anthro labels of two patches are not the same + countcycles_if: if (count_cycles .gt. 0) then + ! if we're having an incredibly hard time fusing patches because of their differing anthropogenic disturbance labels, + ! since the size is so small, let's sweep the problem under the rug and change the tiny patch's label to that of its older sibling + ! and then allow them to fuse together. + currentPatch%land_use_label = olderPatch%land_use_label + currentPatch%age_since_anthro_disturbance = olderPatch%age_since_anthro_disturbance + call fuse_2_patches(currentSite, olderPatch, currentPatch) + gotfused = .true. + endif countcycles_if + endif distlabel_1_if + endif associated_older_if - youngerPatch => currentPatch%younger + not_gotfused_if: if( .not. gotfused .and. associated(currentPatch%younger) ) then + + if(debug) & + write(fates_log(),*) 'fusing to younger patch because oldest one is too small', & + currentPatch%area + + youngerPatch => currentPatch%younger + + distlabel_2_if: if (currentPatch%land_use_label .eq. youngerPatch%land_use_label) then - distlabel_2_if: if (currentPatch%anthro_disturbance_label .eq. youngerPatch% anthro_disturbance_label) then - - call fuse_2_patches(currentSite, youngerPatch, currentPatch) - - ! The fusion process has updated the "younger" pointer on currentPatch - - else distlabel_2_if - if (count_cycles .gt. 0) then - ! if we're having an incredibly hard time fusing patches because of their differing anthropogenic disturbance labels, - ! since the size is so small, let's sweep the problem under the rug and change the tiny patch's label to that of its younger sibling - currentPatch%anthro_disturbance_label = youngerPatch%anthro_disturbance_label call fuse_2_patches(currentSite, youngerPatch, currentPatch) + + ! The fusion process has updated the "younger" pointer on currentPatch + gotfused = .true. - endif ! count cycles - endif distlabel_2_if ! anthro labels - endif not_gotfused_if ! has an older patch - endif notyoungest_if ! is not the youngest patch + + else distlabel_2_if + if (count_cycles .gt. 0) then + ! if we're having an incredibly hard time fusing patches because of their differing anthropogenic disturbance labels, + ! since the size is so small, let's sweep the problem under the rug and change the tiny patch's label to that of its younger sibling + currentPatch%land_use_label = youngerPatch%land_use_label + currentPatch%age_since_anthro_disturbance = youngerPatch%age_since_anthro_disturbance + call fuse_2_patches(currentSite, youngerPatch, currentPatch) + gotfused = .true. + endif ! count cycles + endif distlabel_2_if ! anthro labels + endif not_gotfused_if ! has an older patch + endif notyoungest_if ! is not the youngest patch endif nocomp_if endif lessthan_min_patcharea_if ! very small patch @@ -2914,7 +3193,7 @@ subroutine get_frac_site_primary(site_in, frac_site_primary) frac_site_primary = 0._r8 currentPatch => site_in%oldest_patch do while (associated(currentPatch)) - if (currentPatch%anthro_disturbance_label .eq. primaryforest) then + if (currentPatch%land_use_label .eq. primaryland) then frac_site_primary = frac_site_primary + currentPatch%area * AREA_INV endif currentPatch => currentPatch%younger @@ -2922,4 +3201,170 @@ subroutine get_frac_site_primary(site_in, frac_site_primary) end subroutine get_frac_site_primary + ! ===================================================================================== + + subroutine InsertPatch(currentSite, newPatch) + + ! !DESCRIPTION: + ! Insert patch into linked list + ! + ! !USES: + ! + ! !ARGUMENTS: + type (ed_site_type), intent(inout) :: currentSite + type (fates_patch_type), intent(inout), pointer :: newPatch + + ! !LOCAL VARIABLES: + type (fates_patch_type), pointer :: currentPatch + integer :: insert_method ! Temporary dev + logical :: found_landuselabel_match + integer, parameter :: unordered_lul_groups= 1 + integer, parameter :: primaryland_oldest_group = 2 + integer, parameter :: numerical_order_lul_groups = 3 + integer, parameter :: age_order_only = 4 + + ! Insert new patch case options: + ! Option 1: Group the landuse types together, but the group order doesn't matter + ! Option 2: Option 1, but primarylands are forced to be the oldest group + ! Option 3: Option 1, but groups are in numerical order according to land use label index integer + ! (i.e. primarylands=1, secondarylands=2, ..., croplands=5) + ! Option 4: Don't group the patches by land use label. Simply add new patches to the youngest end. + + ! Hardcode the default insertion method. The options developed during FATES V1 land use are + ! currently being held for potential future usage. + insert_method = primaryland_oldest_group + + ! Start from the youngest patch and work to oldest, regarless of insertion_method + currentPatch => currentSite%youngest_patch + + ! For the three grouped cases, if the land use label of the youngest patch on the site + ! is a match to the new patch land use label, simply insert it as the new youngest. + ! This is applicable to the non-grouped option 4 method as well. + if (currentPatch%land_use_label .eq. newPatch%land_use_label ) then + newPatch%older => currentPatch + newPatch%younger => null() + currentPatch%younger => newPatch + currentSite%youngest_patch => newPatch + else + + ! If the current site youngest patch land use label doesn't match the new patch + ! land use label then work through the list until you find the matching type. + ! Since we've just checked the youngest patch, move to the next patch and + ! initialize the match flag to false. + found_landuselabel_match = .false. + currentPatch => currentPatch%older + select case(insert_method) + + ! Option 1 - order of land use label groups does not matter + case (unordered_lul_groups) + + do while(associated(currentPatch) .and. .not. found_landuselabel_match) + if (currentPatch%land_use_label .eq. newPatch%land_use_label) then + found_landuselabel_match = .true. + else + currentPatch => currentPatch%older + end if + end do + + ! In the case where we've found a land use label matching the new patch label, + ! insert the newPatch will as the youngest patch for that land use type. + if (associated(currentPatch)) then + newPatch%older => currentPatch + newPatch%younger => currentPatch%younger + currentPatch%younger%older => newPatch + currentPatch%younger => newPatch + else + ! In the case in which we get to the end of the list and haven't found + ! a landuse label match simply add the new patch to the youngest end. + newPatch%older => currentSite%youngest_patch + newPatch%younger => null() + currentSite%youngest_patch%younger => newPatch + currentSite%youngest_patch => newPatch + endif + + ! Option 2 - primaryland group must be on the oldest end + case (primaryland_oldest_group) + + do while(associated(currentPatch) .and. .not. found_landuselabel_match) + if (currentPatch%land_use_label .eq. newPatch%land_use_label) then + found_landuselabel_match = .true. + else + currentPatch => currentPatch%older + end if + end do + + ! In the case where we've found a land use label matching the new patch label, + ! insert the newPatch will as the youngest patch for that land use type. + if (associated(currentPatch)) then + newPatch%older => currentPatch + newPatch%younger => currentPatch%younger + currentPatch%younger%older => newPatch + currentPatch%younger => newPatch + else + ! 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 (newPatch%land_use_label .eq. primaryland) then + newPatch%older => null() + newPatch%younger => currentSite%oldest_patch + currentSite%oldest_patch%older => newPatch + currentSite%oldest_patch => newPatch + else + ! If the new patch land use type is not primaryland and we are at the + ! oldest end of the list, add it to the youngest end + newPatch%older => currentSite%youngest_patch + newPatch%younger => null() + currentSite%youngest_patch%younger => newPatch + currentSite%youngest_patch => newPatch + endif + endif + + ! Option 3 - groups are numerically ordered with primaryland group starting at oldest end. + case (numerical_order_lul_groups) + + ! If the youngest patch landuse label number is greater than the new + ! patch land use label number, the new patch must be inserted somewhere + ! in between oldest and youngest + do while(associated(currentPatch) .and. .not. found_landuselabel_match) + if (currentPatch%land_use_label .eq. newPatch%land_use_label .or. & + currentPatch%land_use_label .lt. newPatch%land_use_label) then + found_landuselabel_match = .true. + else + currentPatch => currentPatch%older + endif + end do + + ! In the case where we've found a landuse label matching the new patch label + ! insert the newPatch will as the youngest patch for that land use type. + if (associated(currentPatch)) then + + newPatch%older => currentPatch + newPatch%younger => currentPatch%younger + currentPatch%younger%older => newPatch + currentPatch%younger => newPatch + + else + + ! In the case were we get to the end, the new patch + ! must be numerically the smallest, so put it at the oldest position + newPatch%older => null() + newPatch%younger => currentSite%oldest_patch + currentSite%oldest_patch%older => newPatch + currentSite%oldest_patch => newPatch + + endif + + ! Option 4 - always add the new patch as the youngest regardless of land use label + case (age_order_only) + ! Set the current patch to the youngest patch + newPatch%older => currentSite%youngest_patch + newPatch%younger => null() + currentSite%youngest_patch%younger => newPatch + currentSite%youngest_patch => newPatch + end select + end if + + end subroutine InsertPatch + end module EDPatchDynamicsMod diff --git a/biogeochem/FatesLandUseChangeMod.F90 b/biogeochem/FatesLandUseChangeMod.F90 new file mode 100644 index 0000000000..1999cfabc7 --- /dev/null +++ b/biogeochem/FatesLandUseChangeMod.F90 @@ -0,0 +1,318 @@ +module FatesLandUseChangeMod + + ! Controls the transfer and initialization of patch structure to land use types + + use FatesGlobals , only : fates_log + use FatesConstantsMod , only : primaryland, secondaryland, pastureland, rangeland, cropland + use FatesConstantsMod , only : n_landuse_cats + use FatesConstantsMod , only : nearzero + use FatesGlobals , only : endrun => fates_endrun + use FatesConstantsMod , only : r8 => fates_r8 + use FatesConstantsMod , only : itrue, ifalse + use FatesConstantsMod , only : fates_unset_int + use FatesConstantsMod , only : years_per_day + use FatesInterfaceTypesMod , only : bc_in_type + use FatesInterfaceTypesMod , only : hlm_use_luh + use FatesInterfaceTypesMod , only : hlm_num_luh2_states + use FatesInterfaceTypesMod , only : hlm_num_luh2_transitions + use FatesUtilsMod , only : FindIndex + use EDTypesMod , only : area_site => area + + ! CIME globals + use shr_log_mod , only : errMsg => shr_log_errMsg + + ! + implicit none + private + + character(len=*), parameter :: sourcefile = __FILE__ + + public :: get_landuse_transition_rates + public :: get_landusechange_rules + public :: get_luh_statedata + + + ! module data + integer, parameter :: max_luh2_types_per_fates_lu_type = 5 + + ! Define the mapping from the luh2 state names to the aggregated fates land use categories + type :: luh2_fates_lutype_map + + character(len=5), dimension(12) :: state_names = & + [character(len=5) :: 'primf','primn','secdf','secdn', & + 'pastr','range', 'urban', & + 'c3ann','c4ann','c3per','c4per','c3nfx'] + integer, dimension(12) :: landuse_categories = & + [primaryland, primaryland, secondaryland, secondaryland, & + pastureland, rangeland, fates_unset_int, & + cropland, cropland, cropland, cropland, cropland] + + contains + + procedure :: GetIndex => GetLUCategoryFromStateName + + end type luh2_fates_lutype_map + + + ! 03/10/2023 Created By Charlie Koven + ! ============================================================================ + +contains + + ! ============================================================================ + subroutine get_landuse_transition_rates(bc_in, landuse_transition_matrix) + + + ! 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] + + ! !LOCAL VARIABLES: + type(luh2_fates_lutype_map) :: lumap + integer :: i_donor, i_receiver, i_luh2_transitions, i_luh2_states, i_urban + character(5) :: donor_name, receiver_name + character(14) :: transition_name + real(r8) :: urban_fraction + real(r8) :: temp_vector(hlm_num_luh2_transitions) + logical :: modified_flag + + ! 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) + + end if + end do transitions_loop + + end subroutine get_landuse_transition_rates + + !---------------------------------------------------------------------------------------------------- + + function GetLUCategoryFromStateName(this, state_name) result(landuse_category) + + class(luh2_fates_lutype_map) :: this + character(len=5), intent(in) :: state_name + integer :: landuse_category + integer :: index_statename + + index_statename = FindIndex(this%state_names,state_name) + + ! Check that the result from the landuse_categories is not zero, which indicates that no + ! match was found. + if (index_statename .eq. 0) then + write(fates_log(),*) 'The input state name from the HLM does not match the FATES landuse state name options' + write(fates_log(),*) 'input state name: ', state_name + write(fates_log(),*) 'state name options: ', this%state_names + call endrun(msg=errMsg(sourcefile, __LINE__)) + else + landuse_category = this%landuse_categories(index_statename) + end if + + end function GetLUCategoryFromStateName + + !---------------------------------------------------------------------------------------------------- + + subroutine get_landusechange_rules(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 + + 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 + + ! 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. + + select case(ruleset) + + 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. + clearing_matrix(:,cropland) = .true. + clearing_matrix(:,pastureland) = .true. + clearing_matrix(primaryland,rangeland) = .true. + clearing_matrix(secondaryland,rangeland) = .true. + + case(2) + + ! see comment on number 1 above + clearing_matrix(:,cropland) = .true. + clearing_matrix(primaryland,pastureland) = .true. + clearing_matrix(secondaryland,pastureland) = .true. + clearing_matrix(primaryland,rangeland) = .true. + clearing_matrix(secondaryland,rangeland) = .true. + + case(3) + + clearing_matrix(:,cropland) = .true. + clearing_matrix(:,pastureland) = .true. + clearing_matrix(:,rangeland) = .true. + + case(4) + + clearing_matrix(:,cropland) = .true. + clearing_matrix(:,pastureland) = .true. + clearing_matrix(:,rangeland) = .false. + + case(5) + + clearing_matrix(:,cropland) = .true. + clearing_matrix(:,pastureland) = .false. + clearing_matrix(:,rangeland) = .true. + + case(6) + + clearing_matrix(:,cropland) = .true. + clearing_matrix(:,pastureland) = .false. + clearing_matrix(:,rangeland) = .false. + + case(7) + + clearing_matrix(:,cropland) = .false. + clearing_matrix(:,pastureland) = .true. + clearing_matrix(:,rangeland) = .true. + + case(8) + + clearing_matrix(:,cropland) = .false. + clearing_matrix(:,pastureland) = .true. + clearing_matrix(:,rangeland) = .false. + + case(9) + + clearing_matrix(:,cropland) = .false. + clearing_matrix(:,pastureland) = .false. + clearing_matrix(:,rangeland) = .true. + + case default + + write(fates_log(),*) 'unknown clearing ruleset?' + write(fates_log(),*) 'ruleset: ', ruleset + call endrun(msg=errMsg(sourcefile, __LINE__)) + + end select + + end subroutine get_landusechange_rules + + !---------------------------------------------------------------------------------------------------- + + subroutine get_luh_statedata(bc_in, state_vector) + + type(bc_in_type) , intent(in) :: bc_in + real(r8), intent(out) :: state_vector(n_landuse_cats) ! [m2/m2] + + ! LOCALS + type(luh2_fates_lutype_map) :: lumap + real(r8) :: temp_vector(hlm_num_luh2_states) ! [m2/m2] + real(r8) :: urban_fraction + integer :: i_luh2_states + integer :: ii + character(5) :: state_name + logical :: modified_flag + + ! zero state vector and urban fraction + 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) + 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) + end if + + end subroutine get_luh_statedata + + !---------------------------------------------------------------------------------------------------- + + subroutine CheckLUHData(luh_vector,modified_flag) + + use shr_infnan_mod , only : isnan => shr_infnan_isnan + + real(r8), intent(inout) :: luh_vector(:) ! [m2/m2] + logical, intent(out) :: 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, + ! 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. + + modified_flag = .false. + if (all(isnan(luh_vector))) then + luh_vector(:) = 0._r8 + ! Check if this is a state vector, otherwise leave transitions as zero + if (size(luh_vector) .eq. hlm_num_luh2_states) then + 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 + else if (any(isnan(luh_vector))) then + if (any(.not. isnan(luh_vector))) then + write(fates_log(),*) 'ERROR: land use vector has NaN' + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + end if + + end subroutine CheckLUHData + +end module FatesLandUseChangeMod diff --git a/biogeochem/FatesPatchMod.F90 b/biogeochem/FatesPatchMod.F90 index 8a38366217..fbef6dcfc4 100644 --- a/biogeochem/FatesPatchMod.F90 +++ b/biogeochem/FatesPatchMod.F90 @@ -3,7 +3,8 @@ module FatesPatchMod use FatesConstantsMod, only : r8 => fates_r8 use FatesConstantsMod, only : fates_unset_r8 use FatesConstantsMod, only : fates_unset_int - use FatesConstantsMod, only : primaryforest, secondaryforest + use FatesConstantsMod, only : primaryland, secondaryland + use FatesConstantsMod, only : n_landuse_cats use FatesConstantsMod, only : TRS_regeneration use FatesGlobals, only : fates_log use FatesGlobals, only : endrun => fates_endrun @@ -59,7 +60,7 @@ module FatesPatchMod real(r8) :: area ! patch area [m2] integer :: countcohorts ! number of cohorts in patch integer :: ncl_p ! number of occupied canopy layers - integer :: anthro_disturbance_label ! patch label for anthropogenic disturbance classification + 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] !--------------------------------------------------------------------------- @@ -169,10 +170,12 @@ module FatesPatchMod !--------------------------------------------------------------------------- ! DISTURBANCE - real(r8) :: disturbance_rates(n_dist_types) ! disturbance rate [0-1/day] from 1) mortality - ! 2) fire - ! 3) logging mortatliy - real(r8) :: fract_ldist_not_harvested ! fraction of logged area that is canopy trees that weren't harvested [0-1] + real(r8) :: disturbance_rates(n_dist_types) ! disturbance rate [0-1/day] from 1) mortality + ! 2) fire + ! 3) logging mortatliy + ! 4) land use change + real(r8) :: landuse_transition_rates(n_landuse_cats) ! land use tranision rate + real(r8) :: fract_ldist_not_harvested ! fraction of logged area that is canopy trees that weren't harvested [0-1] !--------------------------------------------------------------------------- @@ -296,7 +299,7 @@ subroutine NanValues(this) this%area = nan this%countcohorts = fates_unset_int this%ncl_p = fates_unset_int - this%anthro_disturbance_label = fates_unset_int + this%land_use_label = fates_unset_int this%age_since_anthro_disturbance = nan ! LEAF ORGANIZATION @@ -362,7 +365,10 @@ subroutine NanValues(this) ! DISTURBANCE this%disturbance_rates(:) = nan - this%fract_ldist_not_harvested = nan + this%fract_ldist_not_harvested = nan + + ! LAND USE + this%landuse_transition_rates(:) = nan ! LITTER AND COARSE WOODY DEBRIS this%fragmentation_scaler(:) = nan @@ -386,8 +392,8 @@ subroutine NanValues(this) this%scorch_ht(:) = nan this%frac_burnt = nan this%tfc_ros = nan - this%burnt_frac_litter(:) = nan - + this%burnt_frac_litter(:) = nan + end subroutine NanValues !=========================================================================== @@ -440,6 +446,9 @@ subroutine ZeroValues(this) this%disturbance_rates(:) = 0.0_r8 this%fract_ldist_not_harvested = 0.0_r8 + ! LAND USE + this%landuse_transition_rates(:) = 0.0_r8 + ! LITTER AND COARSE WOODY DEBRIS this%fragmentation_scaler(:) = 0.0_r8 @@ -589,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%anthro_disturbance_label = label - if (label .eq. secondaryforest) then + this%land_use_label = label + if (label .eq. secondaryland) then this%age_since_anthro_disturbance = age else this%age_since_anthro_disturbance = fates_unset_r8 @@ -732,7 +741,7 @@ subroutine Dump(this) write(fates_log(),*) 'pa%c_stomata = ',this%c_stomata write(fates_log(),*) 'pa%c_lblayer = ',this%c_lblayer write(fates_log(),*) 'pa%disturbance_rates = ',this%disturbance_rates(:) - write(fates_log(),*) 'pa%anthro_disturbance_label = ',this%anthro_disturbance_label + write(fates_log(),*) 'pa%land_use_label = ',this%land_use_label write(fates_log(),*) '----------------------------------------' do el = 1, num_elements @@ -806,4 +815,4 @@ end subroutine CheckVars !=========================================================================== -end module FatesPatchMod \ No newline at end of file +end module FatesPatchMod diff --git a/main/EDInitMod.F90 b/main/EDInitMod.F90 index 5e4a76f698..06973ac9a9 100644 --- a/main/EDInitMod.F90 +++ b/main/EDInitMod.F90 @@ -8,8 +8,10 @@ module EDInitMod use FatesConstantsMod , only : ifalse use FatesConstantsMod , only : itrue use FatesConstantsMod , only : fates_unset_int + use FatesConstantsMod , only : primaryland + use FatesConstantsMod , only : nearzero + use FatesConstantsMod , only : n_landuse_cats use FatesConstantsMod , only : fates_unset_r8 - use FatesConstantsMod , only : primaryforest use FatesConstantsMod , only : nearzero, area_error_4, area_error_3 use FatesGlobals , only : endrun => fates_endrun use EDParamsMod , only : nclmax @@ -52,6 +54,7 @@ module EDInitMod use FatesInterfaceTypesMod , only : hlm_use_fixed_biogeog use FatesInterfaceTypesMod , only : hlm_use_tree_damage use FatesInterfaceTypesMod , only : hlm_use_sp + use FatesInterfaceTypesMod , only : hlm_use_luh use FatesInterfaceTypesMod , only : numpft use FatesInterfaceTypesMod , only : nleafage use FatesInterfaceTypesMod , only : nlevsclass @@ -87,6 +90,7 @@ module EDInitMod use PRTGenericMod, only : SetState use FatesSizeAgeTypeIndicesMod,only : get_age_class_index use DamageMainMod, only : undamaged_class + use FatesInterfaceTypesMod , only : hlm_num_luh2_transitions ! CIME GLOBALS use shr_log_mod , only : errMsg => shr_log_errMsg @@ -263,10 +267,7 @@ subroutine zero_site( site_in ) ! Disturbance rates tracking site_in%primary_land_patchfusion_error = 0.0_r8 - site_in%potential_disturbance_rates(:) = 0.0_r8 - site_in%disturbance_rates_secondary_to_secondary(:) = 0.0_r8 - site_in%disturbance_rates_primary_to_secondary(:) = 0.0_r8 - site_in%disturbance_rates_primary_to_primary(:) = 0.0_r8 + site_in%disturbance_rates(:,:,:) = 0.0_r8 ! FIRE site_in%acc_ni = 0.0_r8 ! daily nesterov index accumulating over time. time unlimited theoretically. @@ -540,6 +541,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 ! ! !ARGUMENTS @@ -562,11 +564,17 @@ subroutine init_patches( nsites, sites, bc_in) integer :: start_patch integer :: num_new_patches integer :: nocomp_pft - real(r8) :: newparea + real(r8) :: newparea, newparea_withlanduse real(r8) :: total !check on area - real(r8) :: litt_init + real(r8) :: litt_init !invalid for satphen, 0 otherwise real(r8) :: old_carea integer :: 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 + type(ed_site_type), pointer :: sitep type(fates_patch_type), pointer :: newppft(:) @@ -606,7 +614,9 @@ subroutine init_patches( nsites, sites, bc_in) else - do s = 1, nsites + ! state_vector(:) = 0._r8 + + sites_loop: do s = 1, nsites sites(s)%sp_tlai(:) = 0._r8 sites(s)%sp_tsai(:) = 0._r8 sites(s)%sp_htop(:) = 0._r8 @@ -627,8 +637,36 @@ subroutine init_patches( nsites, sites, bc_in) 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 + + ! Set the number of active land use categories to the maximum number + ! 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 + else + ! If LUH2 data is not being used, we initialize with primarylands, + ! i.e. array index equals '1' + n_active_landuse_cats = primaryland + state_vector(:) = 0._r8 + state_vector(primaryland) = 1._r8 + endif + is_first_patch = itrue - do n = start_patch, num_new_patches + ! luh_state_counter = 0 + new_patch_nocomp_loop: do n = start_patch, num_new_patches ! set the PFT index for patches if in nocomp mode. if(hlm_use_nocomp.eq.itrue)then @@ -653,57 +691,66 @@ subroutine init_patches( nsites, sites, bc_in) newparea = area end if !nocomp mode - if(newparea.gt.0._r8)then ! Stop patches being initilialized when PFT not present in nocomop mode - allocate(newp) - call newp%Create(age, newparea, primaryforest, nocomp_pft, & - hlm_numSWb, 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 - 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 - 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 - - 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)) - end if - else ! normal non SP case always call init cohorts - call init_cohorts(sitep, newp, bc_in(s)) - end if - end if - end do !no new patches + 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, & + hlm_numSWb, 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 + 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 + + 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)) + end if + else ! normal non SP case always call init cohorts + call init_cohorts(sitep, newp, bc_in(s)) + end if + end if new_patch_area_gt_zero + end if lu_state_present_if + end do luh_state_loop + end do new_patch_nocomp_loop !no new patches !check if the total area adds to the same as site area total = 0.0_r8 @@ -757,7 +804,7 @@ subroutine init_patches( nsites, sites, bc_in) call set_patchno(sites(s)) - enddo !s + enddo sites_loop !s end if ! zero all the patch fire variables for the first timestep diff --git a/main/EDMainMod.F90 b/main/EDMainMod.F90 index 59e3096409..159e942c6a 100644 --- a/main/EDMainMod.F90 +++ b/main/EDMainMod.F90 @@ -74,7 +74,7 @@ module EDMainMod use EDTypesMod , only : phen_dstat_moiston use EDTypesMod , only : phen_dstat_timeon use FatesConstantsMod , only : itrue,ifalse - use FatesConstantsMod , only : primaryforest, secondaryforest + use FatesConstantsMod , only : primaryland, secondaryland use FatesConstantsMod , only : nearzero use FatesConstantsMod , only : m2_per_ha use FatesConstantsMod , only : sec_per_day @@ -439,7 +439,7 @@ subroutine ed_integrate_state_variables(currentSite, bc_in, bc_out ) endif ! add age increment to secondary forest patches as well - if (currentPatch%anthro_disturbance_label .eq. secondaryforest) then + if (currentPatch%land_use_label .ne. primaryland) then currentPatch%age_since_anthro_disturbance = & currentPatch%age_since_anthro_disturbance + hlm_freq_day endif @@ -472,7 +472,7 @@ subroutine ed_integrate_state_variables(currentSite, bc_in, bc_out ) mean_temp = currentPatch%tveg24%GetMean() call Mortality_Derivative(currentSite, currentCohort, bc_in, & currentPatch%btran_ft, mean_temp, & - currentPatch%anthro_disturbance_label, & + currentPatch%land_use_label, & currentPatch%age_since_anthro_disturbance, frac_site_primary, & harvestable_forest_c, harvest_tag) @@ -969,7 +969,7 @@ subroutine TotalBalanceCheck (currentSite, call_index ) write(fates_log(),*) 'BG CWD (by layer): ', sum(litt%bg_cwd,dim=1) write(fates_log(),*) 'leaf litter:',sum(litt%leaf_fines) write(fates_log(),*) 'root litter (by layer): ',sum(litt%root_fines,dim=1) - write(fates_log(),*) 'anthro_disturbance_label: ',currentPatch%anthro_disturbance_label + write(fates_log(),*) 'land_use_label: ',currentPatch%land_use_label write(fates_log(),*) 'use_this_pft: ', currentSite%use_this_pft(:) if(print_cohorts)then write(fates_log(),*) '---- Biomass by cohort and organ -----' diff --git a/main/EDParamsMod.F90 b/main/EDParamsMod.F90 index 215d4c3ee7..b9b9e06544 100644 --- a/main/EDParamsMod.F90 +++ b/main/EDParamsMod.F90 @@ -10,6 +10,7 @@ module EDParamsMod use FatesGlobals , only : fates_log use FatesGlobals , only : endrun => fates_endrun use FatesConstantsMod, only : fates_unset_r8 + use FatesConstantsMod, only : n_landuse_cats ! CIME Globals use shr_log_mod , only : errMsg => shr_log_errMsg @@ -199,6 +200,7 @@ 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_maxpatches_by_landuse = "fates_maxpatches_by_landuse" ! Hydraulics Control Parameters (ONLY RELEVANT WHEN USE_FATES_HYDR = TRUE) ! ---------------------------------------------------------------------------------------------- @@ -249,13 +251,9 @@ module EDParamsMod ! The number of patches specified in the parameter file may be over-written. ! For instance, in SP mode, we want the same number of primary patches as the number of PFTs ! in the fates parameter file, and zero secondary. + ! thus they are not protected here. - integer, public :: maxpatch_primary - character(len=param_string_length), parameter, public :: maxpatch_primary_name = "fates_maxpatch_primary" - - integer, public :: maxpatch_secondary - character(len=param_string_length), parameter, public :: maxpatch_secondary_name = "fates_maxpatch_secondary" - + integer, public :: maxpatches_by_landuse(n_landuse_cats) integer, public :: maxpatch_total ! Maximum allowable cohorts per patch @@ -361,8 +359,6 @@ subroutine FatesParamsInit() stomatal_model = -9 regeneration_model = -9 stomatal_assim_model = -9 - maxpatch_primary = -9 - maxpatch_secondary = -9 max_cohort_per_patch = -9 hydr_kmax_rsurf1 = nan hydr_kmax_rsurf2 = nan @@ -399,7 +395,7 @@ subroutine FatesRegisterParams(fates_params) use FatesParametersInterface, only : dimension_name_history_size_bins, dimension_name_history_age_bins use FatesParametersInterface, only : dimension_name_history_height_bins, dimension_name_hydr_organs use FatesParametersInterface, only : dimension_name_history_coage_bins, dimension_name_history_damage_bins - use FatesParametersInterface, only : dimension_shape_scalar + use FatesParametersInterface, only : dimension_shape_scalar, dimension_name_landuse implicit none @@ -413,6 +409,7 @@ subroutine FatesRegisterParams(fates_params) character(len=param_string_length), parameter :: dim_names_coageclass(1) = (/dimension_name_history_coage_bins/) character(len=param_string_length), parameter :: dim_names_hydro_organs(1) = (/dimension_name_hydr_organs/) character(len=param_string_length), parameter :: dim_names_damageclass(1)= (/dimension_name_history_damage_bins/) + character(len=param_string_length), parameter :: dim_names_landuse(1)= (/dimension_name_landuse/) call FatesParamsInit() @@ -518,12 +515,6 @@ subroutine FatesRegisterParams(fates_params) call fates_params%RegisterParameter(name=stomatal_assim_name, dimension_shape=dimension_shape_scalar, & dimension_names=dim_names_scalar) - call fates_params%RegisterParameter(name=maxpatch_primary_name, dimension_shape=dimension_shape_scalar, & - dimension_names=dim_names_scalar) - - call fates_params%RegisterParameter(name=maxpatch_secondary_name, dimension_shape=dimension_shape_scalar, & - dimension_names=dim_names_scalar) - call fates_params%RegisterParameter(name=maxcohort_name, dimension_shape=dimension_shape_scalar, & dimension_names=dim_names_scalar) @@ -619,6 +610,9 @@ 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_maxpatches_by_landuse, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names_landuse) + end subroutine FatesRegisterParams @@ -626,6 +620,7 @@ end subroutine FatesRegisterParams subroutine FatesReceiveParams(fates_params) use FatesParametersInterface, only : fates_parameters_type, dimension_name_scalar + use FatesConstantsMod, only: primaryland, secondaryland, rangeland, pastureland, cropland implicit none @@ -633,6 +628,7 @@ 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 call fates_params%RetrieveParameter(name=ED_name_photo_temp_acclim_timescale, & data=photo_temp_acclim_timescale) @@ -735,16 +731,6 @@ subroutine FatesReceiveParams(fates_params) call fates_params%RetrieveParameter(name=stomatal_assim_name, & data=tmpreal) stomatal_assim_model = nint(tmpreal) - - call fates_params%RetrieveParameter(name=maxpatch_primary_name, & - data=tmpreal) - maxpatch_primary = nint(tmpreal) - - call fates_params%RetrieveParameter(name=maxpatch_secondary_name, & - data=tmpreal) - maxpatch_secondary = nint(tmpreal) - - maxpatch_total = maxpatch_primary+maxpatch_secondary call fates_params%RetrieveParameter(name=maxcohort_name, & data=tmpreal) @@ -848,6 +834,12 @@ 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) + + maxpatches_by_landuse(:) = nint(tmp_vector_by_landuse(:)) + maxpatch_total = sum(maxpatches_by_landuse(:)) + call fates_params%RetrieveParameterAllocate(name=ED_name_hydr_htftype_node, & data=hydr_htftype_real) allocate(hydr_htftype_node(size(hydr_htftype_real))) diff --git a/main/EDTypesMod.F90 b/main/EDTypesMod.F90 index ca524dfcb9..c585a88f9b 100644 --- a/main/EDTypesMod.F90 +++ b/main/EDTypesMod.F90 @@ -19,12 +19,12 @@ module EDTypesMod use PRTGenericMod, only : carbon12_element use FatesLitterMod, only : litter_type use FatesLitterMod, only : ncwd, NFSC - use FatesConstantsMod, only : n_anthro_disturbance_categories use FatesConstantsMod, only : days_per_year use FatesRunningMeanMod, only : rmean_type,rmean_arr_type use FatesConstantsMod, only : fates_unset_r8 use FatesInterfaceTypesMod,only : bc_in_type use FatesInterfaceTypesMod,only : bc_out_type + use FatesConstantsMod , only : n_landuse_cats use FatesInterfaceTypesMod,only : hlm_parteh_mode use FatesCohortMod, only : fates_cohort_type use FatesPatchMod, only : fates_patch_type @@ -87,7 +87,6 @@ module EDTypesMod ! BIOLOGY/BIOGEOCHEMISTRY integer , parameter, public :: num_vegtemp_mem = 10 ! Window of time over which we track temp for cold sensecence (days) - ! Phenology status flag definitions (cold type is cstat, dry type is dstat) integer, parameter, public :: phen_cstat_nevercold = 0 ! This (location/plant) has not experienced a cold period over a large number @@ -426,12 +425,10 @@ module EDTypesMod real(r8), allocatable :: seed_in(:) ! amount of seed dispersed into the site from neighbouring cells [kg/site/day] ! site-level variables to keep track of the disturbance rates, both actual and "potential" - real(r8) :: disturbance_rates_primary_to_primary(N_DIST_TYPES) ! actual disturbance rates from primary patches to primary patches [m2/m2/day] - real(r8) :: disturbance_rates_primary_to_secondary(N_DIST_TYPES) ! actual disturbance rates from primary patches to secondary patches [m2/m2/day] - real(r8) :: disturbance_rates_secondary_to_secondary(N_DIST_TYPES) ! actual disturbance rates from secondary patches to secondary patches [m2/m2/day] - real(r8) :: potential_disturbance_rates(N_DIST_TYPES) ! "potential" disturb rates (i.e. prior to the "which is most" logic) [m2/m2/day] - real(r8) :: primary_land_patchfusion_error ! error term in total area of primary patches associated with patch fusion [m2/m2/day] - + real(r8) :: disturbance_rates(N_DIST_TYPES,n_landuse_cats, n_landuse_cats) ! actual disturbance rates for each disturbance type [m2/m2/day] + 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] + end type ed_site_type ! Make public necessary subroutines and functions @@ -502,6 +499,6 @@ subroutine dump_site(csite) return end subroutine dump_site - + end module EDTypesMod diff --git a/main/FatesConstantsMod.F90 b/main/FatesConstantsMod.F90 index fbc4e96c29..4ce33eb839 100644 --- a/main/FatesConstantsMod.F90 +++ b/main/FatesConstantsMod.F90 @@ -41,15 +41,19 @@ module FatesConstantsMod (/0._fates_r8, 5._fates_r8, 20._fates_r8, 50._fates_r8, 100._fates_r8, 150._fates_r8/) ! array of bin lower edges for comparing patches - integer , parameter, public :: N_DIST_TYPES = 3 ! Disturbance Modes 1) tree-fall, 2) fire, 3) logging + integer , parameter, public :: N_DIST_TYPES = 4 ! Disturbance Modes 1) tree-fall, 2) fire, 3) logging, 4) land-use change integer , parameter, public :: dtype_ifall = 1 ! index for naturally occuring tree-fall generated event integer , parameter, public :: dtype_ifire = 2 ! index for fire generated disturbance event 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 - integer, parameter, public :: n_anthro_disturbance_categories = 2 - integer, parameter, public :: primaryforest = 1 - integer, parameter, public :: secondaryforest = 2 + 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 integer, parameter, public :: leaves_on = 2 ! Flag specifying that a deciduous plant has leaves diff --git a/main/FatesHistoryInterfaceMod.F90 b/main/FatesHistoryInterfaceMod.F90 index c530656bda..c985b427f3 100644 --- a/main/FatesHistoryInterfaceMod.F90 +++ b/main/FatesHistoryInterfaceMod.F90 @@ -84,7 +84,7 @@ module FatesHistoryInterfaceMod use FatesConstantsMod , only : dens_fresh_liquid_water use FatesConstantsMod , only : grav_earth use FatesLitterMod , only : litter_type - use FatesConstantsMod , only : secondaryforest + use FatesConstantsMod , only : secondaryland use PRTGenericMod , only : leaf_organ, fnrt_organ, sapw_organ use PRTGenericMod , only : struct_organ, store_organ, repro_organ @@ -308,13 +308,11 @@ module FatesHistoryInterfaceMod integer :: ih_growth_resp_secondary_si integer :: ih_primaryland_fusion_error_si - integer :: ih_disturbance_rate_p2p_si - integer :: ih_disturbance_rate_p2s_si - integer :: ih_disturbance_rate_s2s_si + integer :: ih_area_si_landuse + integer :: ih_disturbance_rate_si_lulu integer :: ih_fire_disturbance_rate_si integer :: ih_logging_disturbance_rate_si integer :: ih_fall_disturbance_rate_si - integer :: ih_potential_disturbance_rate_si integer :: ih_harvest_carbonflux_si integer :: ih_harvest_debt_si integer :: ih_harvest_debt_sec_si @@ -606,7 +604,7 @@ module FatesHistoryInterfaceMod integer :: ih_c_stomata_si_age integer :: ih_c_lblayer_si_age integer :: ih_agesince_anthrodist_si_age - integer :: ih_secondaryforest_area_si_age + integer :: ih_secondarylands_area_si_age integer :: ih_area_burnt_si_age ! integer :: ih_fire_rate_of_spread_front_si_age integer :: ih_fire_intensity_si_age @@ -771,6 +769,7 @@ module FatesHistoryInterfaceMod integer, private :: levelcwd_index_, levelage_index_ integer, private :: levcacls_index_, levcapf_index_ integer, private :: levclscpf_index_ + integer, private :: levlanduse_index_, levlulu_index_, levlupft_index_ contains @@ -813,6 +812,9 @@ module FatesHistoryInterfaceMod procedure :: levelage_index procedure :: levagefuel_index procedure :: levclscpf_index + procedure :: levlanduse_index + procedure :: levlulu_index + procedure :: levlupft_index ! private work functions procedure, private :: define_history_vars @@ -841,6 +843,9 @@ module FatesHistoryInterfaceMod procedure, private :: set_levheight_index procedure, private :: set_levagefuel_index procedure, private :: set_levclscpf_index + procedure, private :: set_levlanduse_index + procedure, private :: set_levlulu_index + procedure, private :: set_levlupft_index procedure, private :: set_levelem_index procedure, private :: set_levelpft_index @@ -879,6 +884,7 @@ subroutine Init(this, num_threads, fates_bounds) use FatesIODimensionsMod, only : levelem, levelpft use FatesIODimensionsMod, only : levelcwd, levelage, levclscpf use FatesIODimensionsMod, only : levcdpf, levcdsc, levcdam + use FatesIODimensionsMod, only : levlanduse, levlulu, levlupft implicit none @@ -1018,6 +1024,21 @@ subroutine Init(this, num_threads, fates_bounds) call this%dim_bounds(dim_count)%Init(levclscpf, num_threads, & fates_bounds%clscpf_begin, fates_bounds%clscpf_end) + dim_count = dim_count + 1 + call this%set_levlanduse_index(dim_count) + call this%dim_bounds(dim_count)%Init(levlanduse, num_threads, & + fates_bounds%landuse_begin, fates_bounds%landuse_end) + + dim_count = dim_count + 1 + call this%set_levlulu_index(dim_count) + call this%dim_bounds(dim_count)%Init(levlulu, num_threads, & + fates_bounds%lulu_begin, fates_bounds%lulu_end) + + dim_count = dim_count + 1 + call this%set_levlupft_index(dim_count) + call this%dim_bounds(dim_count)%Init(levlupft, num_threads, & + fates_bounds%lupft_begin, fates_bounds%lupft_end) + end subroutine Init ! ====================================================================== @@ -1138,6 +1159,18 @@ subroutine SetThreadBoundsEach(this, thread_index, thread_bounds) call this%dim_bounds(index)%SetThreadBounds(thread_index, & thread_bounds%clscpf_begin, thread_bounds%clscpf_end) + index = this%levlanduse_index() + call this%dim_bounds(index)%SetThreadBounds(thread_index, & + thread_bounds%landuse_begin, thread_bounds%landuse_end) + + index = this%levlulu_index() + call this%dim_bounds(index)%SetThreadBounds(thread_index, & + thread_bounds%lulu_begin, thread_bounds%lulu_end) + + index = this%levlupft_index() + call this%dim_bounds(index)%SetThreadBounds(thread_index, & + thread_bounds%lupft_begin, thread_bounds%lupft_end) + end subroutine SetThreadBoundsEach ! =================================================================================== @@ -1153,6 +1186,7 @@ subroutine assemble_history_output_types(this) use FatesIOVariableKindMod, only : site_elem_r8, site_elpft_r8 use FatesIOVariableKindMod, only : site_elcwd_r8, site_elage_r8, site_clscpf_r8 use FatesIOVariableKindMod, only : site_cdpf_r8, site_cdsc_r8, site_cdam_r8 + use FatesIOVariableKindMod, only : site_landuse_r8, site_lulu_r8, site_lupft_r8 implicit none @@ -1236,7 +1270,16 @@ subroutine assemble_history_output_types(this) call this%set_dim_indices(site_clscpf_r8, 1, this%column_index()) call this%set_dim_indices(site_clscpf_r8, 2, this%levclscpf_index()) - + + call this%set_dim_indices(site_landuse_r8, 1, this%column_index()) + call this%set_dim_indices(site_landuse_r8, 2, this%levlanduse_index()) + + call this%set_dim_indices(site_lulu_r8, 1, this%column_index()) + call this%set_dim_indices(site_lulu_r8, 2, this%levlulu_index()) + + call this%set_dim_indices(site_lupft_r8, 1, this%column_index()) + call this%set_dim_indices(site_lupft_r8, 2, this%levlupft_index()) + end subroutine assemble_history_output_types ! =================================================================================== @@ -1650,6 +1693,51 @@ end function levclscpf_index ! ====================================================================================== + subroutine set_levlanduse_index(this, index) + implicit none + class(fates_history_interface_type), intent(inout) :: this + integer, intent(in) :: index + this%levlanduse_index_ = index + end subroutine set_levlanduse_index + + integer function levlanduse_index(this) + implicit none + class(fates_history_interface_type), intent(in) :: this + levlanduse_index = this%levlanduse_index_ + end function levlanduse_index + + ! ====================================================================================== + + subroutine set_levlulu_index(this, index) + implicit none + class(fates_history_interface_type), intent(inout) :: this + integer, intent(in) :: index + this%levlulu_index_ = index + end subroutine set_levlulu_index + + integer function levlulu_index(this) + implicit none + class(fates_history_interface_type), intent(in) :: this + levlulu_index = this%levlulu_index_ + end function levlulu_index + + ! ====================================================================================== + + subroutine set_levlupft_index(this, index) + implicit none + class(fates_history_interface_type), intent(inout) :: this + integer, intent(in) :: index + this%levlupft_index_ = index + end subroutine set_levlupft_index + + integer function levlupft_index(this) + implicit none + class(fates_history_interface_type), intent(in) :: this + levlupft_index = this%levlupft_index_ + end function levlupft_index + + ! ====================================================================================== + subroutine zero_site_hvars(this, currentSite, upfreq_in) ! This routine zero's a history diagnostic variable @@ -1796,6 +1884,7 @@ subroutine init_dim_kinds_maps(this) use FatesIOVariableKindMod, only : site_elem_r8, site_elpft_r8 use FatesIOVariableKindMod, only : site_elcwd_r8, site_elage_r8, site_clscpf_r8 use FatesIOVariableKindMod, only : site_cdpf_r8, site_cdsc_r8, site_cdam_r8 + use FatesIOVariableKindMod, only : site_landuse_r8, site_lulu_r8, site_lupft_r8 implicit none @@ -1909,6 +1998,18 @@ subroutine init_dim_kinds_maps(this) index = index + 1 call this%dim_kinds(index)%Init(site_clscpf_r8, 2) + ! site x land use class + index = index + 1 + call this%dim_kinds(index)%Init(site_landuse_r8, 2) + + ! site x land use x land use class + index = index + 1 + call this%dim_kinds(index)%Init(site_lulu_r8, 2) + + ! site x land use x pft + index = index + 1 + call this%dim_kinds(index)%Init(site_lupft_r8, 2) + ! FIXME(bja, 2016-10) assert(index == fates_history_num_dim_kinds) end subroutine init_dim_kinds_maps @@ -2117,6 +2218,7 @@ subroutine update_history_dyn(this,nc,nsites,sites,bc_in) use FatesLitterMod , only : ncwd use FatesConstantsMod , only : ican_upper use FatesConstantsMod , only : ican_ustory + use FatesConstantsMod , only : n_landuse_cats use FatesSizeAgeTypeIndicesMod, only : get_sizeage_class_index use FatesSizeAgeTypeIndicesMod, only : get_sizeagepft_class_index use FatesSizeAgeTypeIndicesMod, only : get_agepft_class_index @@ -2212,6 +2314,7 @@ subroutine update_history_dyn(this,nc,nsites,sites,bc_in) real(r8) :: storec_understory_scpf(numpft*nlevsclass) integer :: return_code + integer :: i_dist, j_dist type(fates_patch_type),pointer :: cpatch type(fates_cohort_type),pointer :: ccohort @@ -2286,13 +2389,10 @@ subroutine update_history_dyn(this,nc,nsites,sites,bc_in) hio_canopy_biomass_si => this%hvars(ih_canopy_biomass_si)%r81d, & hio_understory_biomass_si => this%hvars(ih_understory_biomass_si)%r81d, & hio_primaryland_fusion_error_si => this%hvars(ih_primaryland_fusion_error_si)%r81d, & - hio_disturbance_rate_p2p_si => this%hvars(ih_disturbance_rate_p2p_si)%r81d, & - hio_disturbance_rate_p2s_si => this%hvars(ih_disturbance_rate_p2s_si)%r81d, & - hio_disturbance_rate_s2s_si => this%hvars(ih_disturbance_rate_s2s_si)%r81d, & + hio_disturbance_rate_si_lulu => this%hvars(ih_disturbance_rate_si_lulu)%r82d, & 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_potential_disturbance_rate_si => this%hvars(ih_potential_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, & @@ -2449,6 +2549,7 @@ subroutine update_history_dyn(this,nc,nsites,sites,bc_in) hio_yesterdaycanopylevel_canopy_si_scls => this%hvars(ih_yesterdaycanopylevel_canopy_si_scls)%r82d, & hio_yesterdaycanopylevel_understory_si_scls => this%hvars(ih_yesterdaycanopylevel_understory_si_scls)%r82d, & hio_area_si_age => this%hvars(ih_area_si_age)%r82d, & + hio_area_si_landuse => this%hvars(ih_area_si_landuse)%r82d, & hio_lai_si_age => this%hvars(ih_lai_si_age)%r82d, & hio_lai_secondary_si => this%hvars(ih_lai_secondary_si)%r81d, & hio_canopy_area_si_age => this%hvars(ih_canopy_area_si_age)%r82d, & @@ -2460,7 +2561,7 @@ subroutine update_history_dyn(this,nc,nsites,sites,bc_in) hio_biomass_secondary_forest_si => this%hvars(ih_biomass_secondary_forest_si)%r81d, & hio_woodproduct_si => this%hvars(ih_woodproduct_si)%r81d, & hio_agesince_anthrodist_si_age => this%hvars(ih_agesince_anthrodist_si_age)%r82d, & - hio_secondaryforest_area_si_age => this%hvars(ih_secondaryforest_area_si_age)%r82d, & + hio_secondarylands_area_si_age => this%hvars(ih_secondarylands_area_si_age)%r82d, & hio_area_burnt_si_age => this%hvars(ih_area_burnt_si_age)%r82d, & ! hio_fire_rate_of_spread_front_si_age => this%hvars(ih_fire_rate_of_spread_front_si_age)%r82d, & hio_fire_intensity_si_age => this%hvars(ih_fire_intensity_si_age)%r82d, & @@ -2643,27 +2744,24 @@ subroutine update_history_dyn(this,nc,nsites,sites,bc_in) ! error in primary lands from patch fusion [m2 m-2 day-1] -> [m2 m-2 yr-1] hio_primaryland_fusion_error_si(io_si) = sites(s)%primary_land_patchfusion_error * days_per_year - ! output site-level disturbance rates [m2 m-2 day-1] -> [m2 m-2 yr-1] - hio_disturbance_rate_p2p_si(io_si) = sum(sites(s)%disturbance_rates_primary_to_primary(1:N_DIST_TYPES)) * days_per_year - hio_disturbance_rate_p2s_si(io_si) = sum(sites(s)%disturbance_rates_primary_to_secondary(1:N_DIST_TYPES)) * days_per_year - hio_disturbance_rate_s2s_si(io_si) = sum(sites(s)%disturbance_rates_secondary_to_secondary(1:N_DIST_TYPES)) * days_per_year + ! 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 + 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 + end do + end do - hio_fire_disturbance_rate_si(io_si) = (sites(s)%disturbance_rates_primary_to_primary(dtype_ifire) + & - sites(s)%disturbance_rates_primary_to_secondary(dtype_ifire) + & - sites(s)%disturbance_rates_secondary_to_secondary(dtype_ifire)) * & - days_per_year + ! output site-level disturbance rates [m2 m-2 day-1] -> [m2 m-2 yr-1] - TO DO rework this - hio_logging_disturbance_rate_si(io_si) = (sites(s)%disturbance_rates_primary_to_primary(dtype_ilog) + & - sites(s)%disturbance_rates_primary_to_secondary(dtype_ilog) + & - sites(s)%disturbance_rates_secondary_to_secondary(dtype_ilog)) * & - days_per_year + hio_fire_disturbance_rate_si(io_si) = sum(sites(s)%disturbance_rates(dtype_ifire,1:n_landuse_cats,1:n_landuse_cats)) * & + days_per_year - hio_fall_disturbance_rate_si(io_si) = (sites(s)%disturbance_rates_primary_to_primary(dtype_ifall) + & - sites(s)%disturbance_rates_primary_to_secondary(dtype_ifall) + & - sites(s)%disturbance_rates_secondary_to_secondary(dtype_ifall)) * & - days_per_year + hio_logging_disturbance_rate_si(io_si) = sum(sites(s)%disturbance_rates(dtype_ilog,1:n_landuse_cats,1:n_landuse_cats)) * & + days_per_year - hio_potential_disturbance_rate_si(io_si) = sum(sites(s)%potential_disturbance_rates(1:N_DIST_TYPES)) * days_per_year + hio_fall_disturbance_rate_si(io_si) = 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 @@ -2674,7 +2772,7 @@ subroutine update_history_dyn(this,nc,nsites,sites,bc_in) ! Increment the number of patches per site hio_npatches_si(io_si) = hio_npatches_si(io_si) + 1._r8 - if ( cpatch%anthro_disturbance_label .eq. secondaryforest ) then + if ( cpatch%land_use_label .eq. secondaryland ) then hio_npatches_sec_si(io_si) = hio_npatches_sec_si(io_si) + 1._r8 end if @@ -2684,6 +2782,9 @@ subroutine update_history_dyn(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 + ! 24hr veg temperature hio_tveg24(io_si) = hio_tveg24(io_si) + & (cpatch%tveg24%GetMean()- t_water_freeze_k_1atm)*cpatch%area*AREA_INV @@ -2713,7 +2814,7 @@ subroutine update_history_dyn(this,nc,nsites,sites,bc_in) endif ! some diagnostics on secondary forest area and its age distribution - if ( cpatch%anthro_disturbance_label .eq. secondaryforest ) then + if ( cpatch%land_use_label .eq. secondaryland ) then hio_fraction_secondary_forest_si(io_si) = hio_fraction_secondary_forest_si(io_si) + & cpatch%area * AREA_INV @@ -2723,13 +2824,10 @@ subroutine update_history_dyn(this,nc,nsites,sites,bc_in) hio_agesince_anthrodist_si_age(io_si,ageclass_since_anthrodist) & + cpatch%area * AREA_INV - hio_secondaryforest_area_si_age(io_si,cpatch%age_class) = & - hio_secondaryforest_area_si_age(io_si,cpatch%age_class) & + hio_secondarylands_area_si_age(io_si,cpatch%age_class) = & + hio_secondarylands_area_si_age(io_si,cpatch%age_class) & + cpatch%area * AREA_INV - endif - ! Secondary forest mean LAI - if ( cpatch%anthro_disturbance_label .eq. secondaryforest ) then hio_lai_secondary_si(io_si) = hio_lai_secondary_si(io_si) & + sum(cpatch%tlai_profile(:,:,:)) * cpatch%total_canopy_area end if @@ -2799,7 +2897,7 @@ subroutine update_history_dyn(this,nc,nsites,sites,bc_in) ! Increment the number of cohorts per site hio_ncohorts_si(io_si) = hio_ncohorts_si(io_si) + 1._r8 - if ( cpatch%anthro_disturbance_label .eq. secondaryforest ) then + if ( cpatch%land_use_label .eq. secondaryland ) then hio_ncohorts_sec_si(io_si) = hio_ncohorts_sec_si(io_si) + 1._r8 end if @@ -2915,7 +3013,7 @@ subroutine update_history_dyn(this,nc,nsites,sites,bc_in) hio_nindivs_si_pft(io_si,ft) = hio_nindivs_si_pft(io_si,ft) + & ccohort%n * AREA_INV - if ( cpatch%anthro_disturbance_label .eq. secondaryforest ) then + if ( cpatch%land_use_label .eq. secondaryland ) then hio_nindivs_sec_si_pft(io_si,ft) = hio_nindivs_sec_si_pft(io_si,ft) + & ccohort%n * AREA_INV end if @@ -2923,7 +3021,7 @@ subroutine update_history_dyn(this,nc,nsites,sites,bc_in) hio_biomass_si_pft(io_si, ft) = hio_biomass_si_pft(io_si, ft) + & (ccohort%n * AREA_INV) * total_m - if ( cpatch%anthro_disturbance_label .eq. secondaryforest ) then + if ( cpatch%land_use_label .eq. secondaryland ) then hio_biomass_sec_si_pft(io_si, ft) = hio_biomass_sec_si_pft(io_si, ft) + & (ccohort%n * AREA_INV) * total_m end if @@ -2933,7 +3031,7 @@ subroutine update_history_dyn(this,nc,nsites,sites,bc_in) + total_m * ccohort%n * AREA_INV ! track the total biomass on all secondary lands - if ( cpatch%anthro_disturbance_label .eq. secondaryforest ) then + if ( cpatch%land_use_label .eq. secondaryland ) then hio_biomass_secondary_forest_si(io_si) = hio_biomass_secondary_forest_si(io_si) + & total_m * ccohort%n * AREA_INV endif @@ -3063,7 +3161,7 @@ subroutine update_history_dyn(this,nc,nsites,sites,bc_in) hio_npp_si_pft(io_si, ft) = hio_npp_si_pft(io_si, ft) + & ccohort%npp_acc_hold * n_perm2 / days_per_year / sec_per_day - if ( cpatch%anthro_disturbance_label .eq. secondaryforest ) then + if ( cpatch%land_use_label .eq. secondaryland ) then hio_gpp_sec_si_pft(io_si, ft) = hio_gpp_sec_si_pft(io_si, ft) + & ccohort%gpp_acc_hold * n_perm2 / days_per_year / sec_per_day hio_npp_sec_si_pft(io_si, ft) = hio_npp_sec_si_pft(io_si, ft) + & @@ -3204,7 +3302,7 @@ subroutine update_history_dyn(this,nc,nsites,sites,bc_in) hio_m9_si_scls(io_si,scls) = hio_m9_si_scls(io_si,scls) + ccohort%smort*ccohort%n / m2_per_ha ! Examine secondary forest mortality and mortality rates - if(cpatch%anthro_disturbance_label .eq. secondaryforest) then + if(cpatch%land_use_label .eq. secondaryland) then if (hlm_use_cohort_age_tracking .eq.itrue) then hio_m10_sec_si_scls(io_si,scls) = hio_m10_sec_si_scls(io_si,scls) + & @@ -3516,7 +3614,7 @@ subroutine update_history_dyn(this,nc,nsites,sites,bc_in) hio_m3_mortality_understory_si_scpf(io_si,scpf) = hio_m3_mortality_understory_si_scpf(io_si,scpf) + & ccohort%cmort * ccohort%n / m2_per_ha - if ( cpatch%anthro_disturbance_label .eq. secondaryforest ) then + if ( cpatch%land_use_label .eq. secondaryland ) then hio_mortality_canopy_secondary_si_scls(io_si,scls) = hio_mortality_canopy_secondary_si_scls(io_si,scls) + & (ccohort%bmort + ccohort%hmort + ccohort%cmort + & ccohort%frmort + ccohort%smort + ccohort%asmort) * ccohort%n / m2_per_ha + & @@ -3836,7 +3934,7 @@ subroutine update_history_dyn(this,nc,nsites,sites,bc_in) sites(s)%fmort_rate_canopy(i_scls, i_pft) / m2_per_ha ! Shijie: Think about how to add later? - !if ( cpatch%anthro_disturbance_label .eq. secondaryforest ) then + !if ( cpatch%land_use_label .eq. secondaryland ) then ! hio_mortality_canopy_secondary_si_scls(io_si,i_scls) = hio_mortality_canopy_secondary_si_scls(io_si,i_scls) + & ! sites(s)%term_nindivs_canopy(i_scls,i_pft) * days_per_year / m2_per_ha !end if @@ -4594,7 +4692,7 @@ subroutine update_history_hifrq(this,nc,nsites,sites,bc_in,dt_tstep) ccohort%resp_m_unreduced * n_perm2 * per_dt_tstep ! Secondary forest only - if ( cpatch%anthro_disturbance_label .eq. secondaryforest ) then + if ( cpatch%land_use_label .eq. secondaryland ) then hio_npp_secondary_si(io_si) = hio_npp_secondary_si(io_si) + & npp * n_perm2 * per_dt_tstep hio_gpp_secondary_si(io_si) = hio_gpp_secondary_si(io_si) + & @@ -5280,6 +5378,7 @@ subroutine define_history_vars(this, initialize_variables) use FatesIOVariableKindMod, only : site_scagpft_r8, site_agepft_r8 use FatesIOVariableKindMod, only : site_elem_r8, site_elpft_r8, site_clscpf_r8 use FatesIOVariableKindMod, only : site_elcwd_r8, site_elage_r8 + use FatesIOVariableKindMod, only : site_landuse_r8, site_lulu_r8 implicit none @@ -5660,6 +5759,17 @@ subroutine define_history_vars(this, initialize_variables) hlms='CLM:ALM', upfreq=1, ivar=ivar, initialize=initialize_variables, & index=ih_biomass_si_age) + ! land use type resolved variables + 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=1, 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=1, ivar=ivar, & + initialize=initialize_variables, index=ih_disturbance_rate_si_lulu) + ! Secondary forest area and age diagnostics call this%set_history_var(vname='FATES_SECONDARY_FOREST_FRACTION', & @@ -5693,7 +5803,7 @@ subroutine define_history_vars(this, initialize_variables) long='secondary forest patch area age distribution since any kind of disturbance', & use_default='inactive', avgflag='A', vtype=site_age_r8, & hlms='CLM:ALM', upfreq=1, ivar=ivar, initialize=initialize_variables, & - index=ih_secondaryforest_area_si_age) + index=ih_secondarylands_area_si_age) ! Fire Variables @@ -6336,27 +6446,6 @@ subroutine define_history_vars(this, initialize_variables) upfreq=1, ivar=ivar, initialize=initialize_variables, & index = ih_primaryland_fusion_error_si) - call this%set_history_var(vname='FATES_DISTURBANCE_RATE_P2P', & - units='m2 m-2 yr-1', & - long='disturbance rate from primary to primary lands', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index = ih_disturbance_rate_p2p_si) - - call this%set_history_var(vname='FATES_DISTURBANCE_RATE_P2S', & - units='m2 m-2 yr-1', & - long='disturbance rate from primary to secondary lands', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index = ih_disturbance_rate_p2s_si ) - - call this%set_history_var(vname='FATES_DISTURBANCE_RATE_S2S', & - units='m2 m-2 yr-1', & - long='disturbance rate from secondary to secondary lands', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index = ih_disturbance_rate_s2s_si) - call this%set_history_var(vname='FATES_DISTURBANCE_RATE_FIRE', & units='m2 m-2 yr-1', long='disturbance rate from fire', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & @@ -6375,13 +6464,6 @@ subroutine define_history_vars(this, initialize_variables) upfreq=1, ivar=ivar, initialize=initialize_variables, & index = ih_fall_disturbance_rate_si) - call this%set_history_var(vname='FATES_DISTURBANCE_RATE_POTENTIAL', & - units='m2 m-2 yr-1', & - long='potential (i.e., including unresolved) disturbance rate', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index = ih_potential_disturbance_rate_si) - call this%set_history_var(vname='FATES_HARVEST_CARBON_FLUX', & units='kg m-2 yr-1', & long='harvest carbon flux in kg carbon per m2 per year', & diff --git a/main/FatesHistoryVariableType.F90 b/main/FatesHistoryVariableType.F90 index 5902496a2c..83cbdb8c1c 100644 --- a/main/FatesHistoryVariableType.F90 +++ b/main/FatesHistoryVariableType.F90 @@ -16,6 +16,7 @@ module FatesHistoryVariableType use FatesIOVariableKindMod, only : site_elem_r8, site_elpft_r8 use FatesIOVariableKindMod, only : site_elcwd_r8, site_elage_r8 use FatesIOVariableKindMod, only : iotype_index, site_agefuel_r8, site_clscpf_r8 + use FatesIOVariableKindMod, only : site_landuse_r8, site_lulu_r8 use shr_log_mod , only : errMsg => shr_log_errMsg @@ -31,7 +32,7 @@ module FatesHistoryVariableType ! This type is instanteated in the HLM-FATES interface (clmfates_interfaceMod.F90) type, public :: fates_history_variable_type - character(len=32) :: vname + character(len=40) :: vname character(len=24) :: units character(len=128) :: long character(len=24) :: use_default ! States whether a variable should be turned @@ -208,6 +209,14 @@ subroutine Init(this, vname, units, long, use_default, & allocate(this%r82d(lb1:ub1, lb2:ub2)) this%r82d(:,:) = flushval + case(site_landuse_r8) + allocate(this%r82d(lb1:ub1, lb2:ub2)) + this%r82d(:,:) = flushval + + case(site_lulu_r8) + allocate(this%r82d(lb1:ub1, lb2:ub2)) + this%r82d(:,:) = flushval + case(site_clscpf_r8) allocate(this%r82d(lb1:ub1, lb2:ub2)) this%r82d(:,:) = flushval @@ -338,6 +347,11 @@ subroutine Flush(this, thread, dim_bounds, dim_kinds) this%r82d(lb1:ub1, lb2:ub2) = this%flushval case(site_clscpf_r8) this%r82d(lb1:ub1, lb2:ub2) = this%flushval + case(site_landuse_r8) + this%r82d(lb1:ub1, lb2:ub2) = this%flushval + case(site_lulu_r8) + this%r82d(lb1:ub1, lb2:ub2) = this%flushval + case default write(fates_log(),*) 'fates history variable type undefined while flushing history variables' call endrun(msg=errMsg(sourcefile, __LINE__)) diff --git a/main/FatesIODimensionsMod.F90 b/main/FatesIODimensionsMod.F90 index 92488d00a9..ed487d7eed 100644 --- a/main/FatesIODimensionsMod.F90 +++ b/main/FatesIODimensionsMod.F90 @@ -35,6 +35,9 @@ module FatesIODimensionsMod character(*), parameter, public :: levelpft = 'fates_levelpft' character(*), parameter, public :: levelcwd = 'fates_levelcwd' character(*), parameter, public :: levelage = 'fates_levelage' + character(*), parameter, public :: levlanduse = 'fates_levlanduse' + character(*), parameter, public :: levlulu = 'fates_levlulu' + character(*), parameter, public :: levlupft = 'fates_levlupft' ! column = This is a structure that records where FATES column boundaries ! on each thread point to in the host IO array, this structure @@ -115,7 +118,16 @@ module FatesIODimensionsMod ! levcdam = This is the structure that records the boundaries for the ! number of crown damage classes dimension - + + ! levlanduse = this is the structure that records the boundaries for the + ! land use class dimension + + ! levlulu = this is the structure that records the boundaries for the + ! (land use class) x (land use class) dimension + + ! levlupft = this is the structure that records the boundaries for the + ! (land use class) x pft dimension + type, public :: fates_bounds_type integer :: cohort_begin integer :: cohort_end @@ -171,6 +183,12 @@ module FatesIODimensionsMod integer :: agefuel_end integer :: clscpf_begin integer :: clscpf_end + integer :: landuse_begin + integer :: landuse_end + integer :: lulu_begin + integer :: lulu_end + integer :: lupft_begin + integer :: lupft_end end type fates_bounds_type diff --git a/main/FatesIOVariableKindMod.F90 b/main/FatesIOVariableKindMod.F90 index 84dd8e692f..2455939e6f 100644 --- a/main/FatesIOVariableKindMod.F90 +++ b/main/FatesIOVariableKindMod.F90 @@ -41,6 +41,9 @@ module FatesIOVariableKindMod character(*), parameter, public :: site_agepft_r8 = 'SI_AGEPFT_R8' character(*), parameter, public :: site_agefuel_r8 = 'SI_AGEFUEL_R8' character(*), parameter, public :: site_clscpf_r8 = 'SI_CLSCPF_R8' + character(*), parameter, public :: site_landuse_r8 = 'SI_LANDUSE_R8' + character(*), parameter, public :: site_lulu_r8 = 'SI_LULU_R8' + character(*), parameter, public :: site_lupft_r8 = 'SI_LUPFT_R8' ! Element, and multiplexed element dimensions character(*), parameter, public :: site_elem_r8 = 'SI_ELEM_R8' diff --git a/main/FatesInterfaceMod.F90 b/main/FatesInterfaceMod.F90 index bb3021cb4a..d1a0e85722 100644 --- a/main/FatesInterfaceMod.F90 +++ b/main/FatesInterfaceMod.F90 @@ -16,8 +16,7 @@ module FatesInterfaceMod use EDParamsMod , only : ED_val_vai_width_increase_factor use EDParamsMod , only : ED_val_history_damage_bin_edges use EDParamsMod , only : maxpatch_total - use EDParamsMod , only : maxpatch_primary - use EDParamsMod , only : maxpatch_secondary + use EDParamsMod , only : maxpatches_by_landuse use EDParamsMod , only : max_cohort_per_patch use EDParamsMod , only : regeneration_model use EDParamsMod , only : maxSWb @@ -41,6 +40,9 @@ module FatesInterfaceMod use FatesConstantsMod , only : days_per_year use FatesConstantsMod , only : TRS_regeneration use FatesConstantsMod , only : g_per_kg + use FatesConstantsMod , only : n_landuse_cats + use FatesConstantsMod , only : primaryland + use FatesConstantsMod , only : secondaryland use FatesGlobals , only : fates_global_verbose use FatesGlobals , only : fates_log use FatesGlobals , only : endrun => fates_endrun @@ -404,12 +406,18 @@ subroutine zero_bcs(fates,s) fates%bc_out(s)%hrv_deadstemc_to_prod10c = 0.0_r8 fates%bc_out(s)%hrv_deadstemc_to_prod100c = 0.0_r8 + if (hlm_use_luh .eq. itrue) then + fates%bc_in(s)%hlm_luh_states(:) = 0.0_r8 + fates%bc_in(s)%hlm_luh_transitions(:) = 0.0_r8 + end if + return end subroutine zero_bcs ! =========================================================================== - subroutine allocate_bcin(bc_in, nlevsoil_in, nlevdecomp_in, num_lu_harvest_cats,natpft_lb,natpft_ub) + subroutine allocate_bcin(bc_in, nlevsoil_in, nlevdecomp_in, num_lu_harvest_cats, num_luh2_states, & + num_luh2_transitions, natpft_lb,natpft_ub) ! --------------------------------------------------------------------------------- ! Allocate and Initialze the FATES boundary condition vectors @@ -420,6 +428,8 @@ subroutine allocate_bcin(bc_in, nlevsoil_in, nlevdecomp_in, num_lu_harvest_cats, integer,intent(in) :: nlevsoil_in integer,intent(in) :: nlevdecomp_in 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 ! Allocate input boundaries @@ -555,6 +565,14 @@ subroutine allocate_bcin(bc_in, nlevsoil_in, nlevdecomp_in, num_lu_harvest_cats, allocate(bc_in%pft_areafrac(natpft_lb:natpft_ub)) + ! LUH2 state and transition data + if (hlm_use_luh .eq. itrue) then + allocate(bc_in%hlm_luh_states(num_luh2_states)) + allocate(bc_in%hlm_luh_state_names(num_luh2_states)) + allocate(bc_in%hlm_luh_transitions(num_luh2_transitions)) + allocate(bc_in%hlm_luh_transition_names(num_luh2_transitions)) + end if + ! Variables for SP mode. if(hlm_use_sp.eq.itrue) then allocate(bc_in%hlm_sp_tlai(natpft_lb:natpft_ub)) @@ -765,8 +783,8 @@ subroutine SetFatesGlobalElements1(use_fates,surf_numpft,surf_numcft,param_reade ! to hold all PFTs. So create the same number of ! patches as the number of PFTs - maxpatch_primary = fates_numpft - maxpatch_secondary = 0 + maxpatches_by_landuse(primaryland) = fates_numpft + maxpatches_by_landuse(secondaryland:n_landuse_cats) = 0 maxpatch_total = fates_numpft ! If this is an SP run, we actually need enough patches on the @@ -781,13 +799,14 @@ subroutine SetFatesGlobalElements1(use_fates,surf_numpft,surf_numcft,param_reade else ! If we are using fixed biogeography or no-comp then we - ! can also apply those constraints to maxpatch_primary and secondary + ! can also apply those constraints to maxpatch_primaryland and secondary ! and that value will match fates_maxPatchesPerSite if(hlm_use_nocomp==itrue) then - maxpatch_primary = max(maxpatch_primary,fates_numpft) - maxpatch_total = maxpatch_primary + maxpatch_secondary + maxpatches_by_landuse(primaryland) = max(maxpatches_by_landuse(primaryland),fates_numpft) + maxpatch_total = sum(maxpatches_by_landuse(:)) + !if(maxpatch_primary= 0, exiting' + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + + if ( (hlm_num_luh2_transitions .lt. 0) ) then + write(fates_log(), *) 'The FATES number of hlm luh state transition cats must be >= 0, exiting' + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + if ( .not.((hlm_use_logging .eq.1).or.(hlm_use_logging.eq.0)) ) then write(fates_log(), *) 'The FATES namelist use_logging flag must be 0 or 1, exiting' call endrun(msg=errMsg(sourcefile, __LINE__)) @@ -1871,6 +1909,24 @@ subroutine set_fates_ctrlparms(tag,ival,rval,cval) write(fates_log(),*) 'Transfering hlm_num_lu_harvest_cats= ',ival,' to FATES' end if + case('use_luh2') + hlm_use_luh = ival + if (fates_global_verbose()) then + write(fates_log(),*) 'Transfering hlm_use_luh = ',ival,' to FATES' + end if + + case('num_luh2_states') + hlm_num_luh2_states = ival + if (fates_global_verbose()) then + write(fates_log(),*) 'Transfering hlm_num_luh2_states= ',ival,' to FATES' + end if + + case('num_luh2_transitions') + hlm_num_luh2_transitions = ival + if (fates_global_verbose()) then + write(fates_log(),*) 'Transfering hlm_num_luh2_transitions= ',ival,' to FATES' + end if + case('use_cohort_age_tracking') hlm_use_cohort_age_tracking = ival if (fates_global_verbose()) then diff --git a/main/FatesInterfaceTypesMod.F90 b/main/FatesInterfaceTypesMod.F90 index 29a4ec2ba0..3178b140b1 100644 --- a/main/FatesInterfaceTypesMod.F90 +++ b/main/FatesInterfaceTypesMod.F90 @@ -123,6 +123,11 @@ module FatesInterfaceTypesMod ! harvest_rates in dynHarvestMod ! 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_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 + integer, public :: hlm_sf_nofire_def ! Definition of a no-fire case for hlm_spitfire_mode integer, public :: hlm_sf_scalar_lightning_def ! Definition of a scalar-lightning case for hlm_spitfire_mode @@ -258,6 +263,7 @@ module FatesInterfaceTypesMod real(r8), public, allocatable :: fates_hdim_levage(:) ! patch age lower bound dimension real(r8), public, allocatable :: fates_hdim_levheight(:) ! height lower bound dimension integer , public, allocatable :: fates_hdim_levpft(:) ! plant pft dimension + integer , public, allocatable :: fates_hdim_levlanduse(:) ! land use label dimension integer , public, allocatable :: fates_hdim_levfuel(:) ! fire fuel size class (fsc) dimension integer , public, allocatable :: fates_hdim_levcwdsc(:) ! cwd class dimension integer , public, allocatable :: fates_hdim_levcan(:) ! canopy-layer dimension @@ -543,8 +549,12 @@ module FatesInterfaceTypesMod ! Land use ! --------------------------------------------------------------------------------- real(r8),allocatable :: hlm_harvest_rates(:) ! annual harvest rate per cat from hlm for a site - character(len=64), allocatable :: hlm_harvest_catnames(:) ! names of hlm_harvest d1 + real(r8),allocatable :: hlm_luh_states(:) + character(len=64),allocatable :: hlm_luh_state_names(:) + real(r8),allocatable :: hlm_luh_transitions(:) + character(len=64),allocatable :: hlm_luh_transition_names(:) + integer :: hlm_harvest_units ! what units are the harvest rates specified in? [area vs carbon] diff --git a/main/FatesInventoryInitMod.F90 b/main/FatesInventoryInitMod.F90 index 304c40cfb0..d5ad38342a 100644 --- a/main/FatesInventoryInitMod.F90 +++ b/main/FatesInventoryInitMod.F90 @@ -71,7 +71,7 @@ module FatesInventoryInitMod use PRTGenericMod, only : nitrogen_element use PRTGenericMod, only : phosphorus_element use PRTGenericMod, only : SetState - use FatesConstantsMod, only : primaryforest + use FatesConstantsMod, only : primaryland use FatesRunningMeanMod, only : ema_lpa use PRTGenericMod, only : StorageNutrientTarget use FatesConstantsMod, only : fates_unset_int @@ -284,7 +284,7 @@ subroutine initialize_sites_by_inventory(nsites,sites,bc_in) age_init = 0.0_r8 area_init = 0.0_r8 allocate(newpatch) - call newpatch%Create(age_init, area_init, primaryforest, & + call newpatch%Create(age_init, area_init, primaryland, & fates_unset_int, hlm_numSWb, numpft, sites(s)%nlevsoil, & hlm_current_tod, regeneration_model) @@ -292,7 +292,6 @@ subroutine initialize_sites_by_inventory(nsites,sites,bc_in) newpatch%younger => null() newpatch%older => null() - if( inv_format_list(invsite) == 1 ) then call set_inventory_patch_type1(newpatch,pss_file_unit,ipa,ios,patch_name) end if diff --git a/main/FatesParametersInterface.F90 b/main/FatesParametersInterface.F90 index c559ec4cb4..aa0ef85287 100644 --- a/main/FatesParametersInterface.F90 +++ b/main/FatesParametersInterface.F90 @@ -38,6 +38,7 @@ module FatesParametersInterface character(len=*), parameter, public :: dimension_name_hlm_pftno = 'fates_hlm_pftno' character(len=*), parameter, public :: dimension_name_history_damage_bins = 'fates_history_damage_bins' character(len=*), parameter, public :: dimension_name_damage = 'fates_damage_class' + character(len=*), parameter, public :: dimension_name_landuse = 'fates_landuseclass' ! Dimensions in the host namespace: character(len=*), parameter, public :: dimension_name_host_allpfts = 'allpfts' diff --git a/main/FatesRestartInterfaceMod.F90 b/main/FatesRestartInterfaceMod.F90 index 36a571516b..bbc6dd1328 100644 --- a/main/FatesRestartInterfaceMod.F90 +++ b/main/FatesRestartInterfaceMod.F90 @@ -1,31 +1,31 @@ module FatesRestartInterfaceMod - use FatesConstantsMod, only : r8 => fates_r8 - use FatesConstantsMod, only : fates_avg_flag_length - use FatesConstantsMod, only : fates_short_string_length - use FatesConstantsMod, only : fates_long_string_length - use FatesConstantsMod, only : itrue - use FatesConstantsMod, only : ifalse - use FatesConstantsMod, only : fates_unset_r8, fates_unset_int - use FatesConstantsMod, only : primaryforest - use FatesConstantsMod, only : nearzero - use FatesConstantsMod, only : default_regeneration - use FatesConstantsMod, only : TRS_regeneration + use FatesConstantsMod, only : r8 => fates_r8 + use FatesConstantsMod, only : fates_avg_flag_length + use FatesConstantsMod, only : fates_short_string_length + use FatesConstantsMod, only : fates_long_string_length + use FatesConstantsMod, only : itrue + use FatesConstantsMod, only : ifalse + use FatesConstantsMod, only : fates_unset_r8, fates_unset_int + use FatesConstantsMod, only : primaryland + use FatesConstantsMod, only : nearzero + use FatesConstantsMod, only : default_regeneration + use FatesConstantsMod, only : TRS_regeneration use FatesGlobals, only : fates_log use FatesGlobals, only : endrun => fates_endrun use FatesIODimensionsMod, only : fates_io_dimension_type use FatesIOVariableKindMod, only : fates_io_variable_kind_type use FatesRestartVariableMod, only : fates_restart_variable_type - use FatesInterfaceTypesMod, only : nlevcoage - use FatesInterfaceTypesMod, only : bc_in_type - use FatesInterfaceTypesMod, only : bc_out_type - use FatesInterfaceTypesMod, only : hlm_use_planthydro - 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 : fates_maxElementsPerSite - use FatesInterfaceTypesMod, only : hlm_use_tree_damage + use FatesInterfaceTypesMod, only : nlevcoage + use FatesInterfaceTypesMod, only : bc_in_type + use FatesInterfaceTypesMod, only : bc_out_type + use FatesInterfaceTypesMod, only : hlm_use_planthydro + 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 : fates_maxElementsPerSite + use FatesInterfaceTypesMod, only : hlm_use_tree_damage use FatesHydraulicsMemMod, only : nshell use FatesHydraulicsMemMod, only : n_hypool_ag use FatesHydraulicsMemMod, only : n_hypool_troot @@ -35,7 +35,7 @@ module FatesRestartInterfaceMod use PRTGenericMod, only : prt_cnp_flex_allom_hyp use EDCohortDynamicsMod, only : InitPRTObject use FatesPlantHydraulicsMod, only : InitHydrCohort - use FatesInterfaceTypesMod, only : nlevsclass + use FatesInterfaceTypesMod, only : nlevsclass use FatesInterfaceTypesMod, only : nlevdamage use FatesLitterMod, only : litter_type use FatesLitterMod, only : ncwd, nfsc @@ -47,6 +47,8 @@ module FatesRestartInterfaceMod use FatesRunningMeanMod, only : rmean_type use FatesRunningMeanMod, only : ema_lpa use EDParamsMod, only : regeneration_model + use FatesConstantsMod, only : n_landuse_cats + use FatesConstantsMod, only : N_DIST_TYPES ! CIME GLOBALS use shr_log_mod , only : errMsg => shr_log_errMsg @@ -253,6 +255,8 @@ module FatesRestartInterfaceMod integer :: ir_abg_imort_flux_siscpf integer :: ir_abg_fmort_flux_siscpf + integer :: ir_disturbance_rates_siluludi + integer :: ir_cwdagin_flxdg integer :: ir_cwdbgin_flxdg integer :: ir_leaflittin_flxdg @@ -1501,6 +1505,10 @@ subroutine define_restart_vars(this, initialize_variables) long_name='24-hour patch veg temp', & units='K', initialize=initialize_variables,ivar=ivar, index = ir_tveg24_pa) + call this%DefineRMeanRestartVar(vname='fates_disturbance_rates',vtype=cohort_r8, & + long_name='disturbance rates by donor land-use type, receiver land-use type, and disturbance type', & + units='1/day', initialize=initialize_variables,ivar=ivar, index = ir_disturbance_rates_siluludi) + if ( regeneration_model == TRS_regeneration ) then call this%DefineRMeanRestartVar(vname='fates_seedling_layer_par24',vtype=cohort_r8, & @@ -1981,6 +1989,7 @@ subroutine set_restart_vectors(this,nc,nsites,sites) integer :: io_idx_si_pft ! each site-pft index integer :: io_idx_si_vtmem ! indices for veg-temp memory at site integer :: io_idx_pa_ncl ! each canopy layer within each patch + integer :: io_idx_si_luludi ! site-level lu x lu x ndist index ! Some counters (for checking mostly) integer :: totalcohorts ! total cohort count on this thread (diagnostic) @@ -2003,6 +2012,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_lu_donor, i_lu_receiver, i_dist ! loop counters for land use and disturbance type(fates_restart_variable_type) :: rvar type(fates_patch_type),pointer :: cpatch @@ -2113,6 +2123,7 @@ subroutine set_restart_vectors(this,nc,nsites,sites) rio_abg_imort_flux_siscpf => this%rvars(ir_abg_imort_flux_siscpf)%r81d, & 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_imortrate_sicdpf => this%rvars(ir_imortrate_sicdpf)%r81d, & rio_imortcflux_sicdsc => this%rvars(ir_imortcflux_sicdsc)%r81d, & @@ -2162,6 +2173,7 @@ subroutine set_restart_vectors(this,nc,nsites,sites) io_idx_si_cdpf = io_idx_co_1st io_idx_si_scpf = io_idx_co_1st io_idx_si_pft = io_idx_co_1st + io_idx_si_luludi = io_idx_co_1st ! recruitment rate do i_pft = 1,numpft @@ -2210,6 +2222,16 @@ subroutine set_restart_vectors(this,nc,nsites,sites) io_idx_si_pft = io_idx_si_pft + 1 end do + ! site-level disturbance rate diagnostic + do i_lu_donor = 1, n_landuse_cats + do i_lu_receiver = 1, n_landuse_cats + do i_dist = 1, n_dist_types + rio_disturbance_rates_siluludi(io_idx_si_luludi) = sites(s)%disturbance_rates(i_dist,i_lu_donor, i_lu_receiver) + io_idx_si_luludi = io_idx_si_luludi + 1 + end do + end do + end do + if(hlm_use_sp.eq.ifalse)then do el = 1, num_elements @@ -2399,7 +2421,7 @@ subroutine set_restart_vectors(this,nc,nsites,sites) ! rio_livegrass_pa(io_idx_co_1st) = cpatch%livegrass rio_age_pa(io_idx_co_1st) = cpatch%age - rio_patchdistturbcat_pa(io_idx_co_1st) = cpatch%anthro_disturbance_label + rio_patchdistturbcat_pa(io_idx_co_1st) = cpatch%land_use_label rio_agesinceanthrodist_pa(io_idx_co_1st) = cpatch%age_since_anthro_disturbance rio_nocomp_pft_label_pa(io_idx_co_1st)= cpatch%nocomp_pft_label rio_area_pa(io_idx_co_1st) = cpatch%area @@ -2753,7 +2775,7 @@ subroutine create_patchcohort_structure(this, nc, nsites, sites, bc_in, bc_out) nocomp_pft = fates_unset_int ! the nocomp_pft label is set after patch creation has occured in 'get_restart_vectors' ! make new patch - call newp%Create(fates_unset_r8, fates_unset_r8, primaryforest, & + call newp%Create(fates_unset_r8, fates_unset_r8, primaryland, & nocomp_pft, hlm_numSWb, numpft, sites(s)%nlevsoil, & hlm_current_tod, regeneration_model) @@ -2933,6 +2955,7 @@ subroutine get_restart_vectors(this, nc, nsites, sites) integer :: io_idx_si_cdpf ! damage x size x pft within site integer :: io_idx_pa_ncl ! each canopy layer within each patch + integer :: io_idx_si_luludi ! site-level lu x lu x ndist index ! Some counters (for checking mostly) integer :: totalcohorts ! total cohort count on this thread (diagnostic) @@ -2952,6 +2975,7 @@ 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_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, & @@ -3036,6 +3060,7 @@ subroutine get_restart_vectors(this, nc, nsites, sites) rio_imortrate_siscpf => this%rvars(ir_imortrate_siscpf)%r81d, & rio_fmortrate_crown_siscpf => this%rvars(ir_fmortrate_crown_siscpf)%r81d, & rio_fmortrate_cambi_siscpf => this%rvars(ir_fmortrate_cambi_siscpf)%r81d, & + rio_disturbance_rates_siluludi => this%rvars(ir_disturbance_rates_siluludi)%r81d, & rio_termnindiv_cano_siscpf => this%rvars(ir_termnindiv_cano_siscpf)%r81d, & rio_termnindiv_usto_siscpf => this%rvars(ir_termnindiv_usto_siscpf)%r81d, & rio_growflx_fusion_siscpf => this%rvars(ir_growflx_fusion_siscpf)%r81d, & @@ -3096,7 +3121,8 @@ subroutine get_restart_vectors(this, nc, nsites, sites) io_idx_si_cdpf = io_idx_co_1st io_idx_si_scpf = io_idx_co_1st io_idx_si_pft = io_idx_co_1st - + io_idx_si_luludi = io_idx_co_1st + ! read seed_bank info(site-level, but PFT-resolved) do i_pft = 1,numpft sites(s)%recruitment_rate(i_pft) = rio_recrate_sift(io_idx_co_1st+i_pft-1) @@ -3151,6 +3177,16 @@ subroutine get_restart_vectors(this, nc, nsites, sites) io_idx_si_pft = io_idx_si_pft + 1 end do + ! site-level disturbance rate diagnostic + do i_lu_donor = 1, n_landuse_cats + do i_lu_receiver = 1, n_landuse_cats + do i_dist = 1, n_dist_types + sites(s)%disturbance_rates(i_dist,i_lu_donor, i_lu_receiver) = rio_disturbance_rates_siluludi(io_idx_si_luludi) + io_idx_si_luludi = io_idx_si_luludi + 1 + end do + end do + end do + ! Mass balance and diagnostics across elements at the site level if(hlm_use_sp.eq.ifalse)then do el = 1, num_elements @@ -3333,7 +3369,7 @@ subroutine get_restart_vectors(this, nc, nsites, sites) ! cpatch%livegrass = rio_livegrass_pa(io_idx_co_1st) cpatch%age = rio_age_pa(io_idx_co_1st) - cpatch%anthro_disturbance_label = rio_patchdistturbcat_pa(io_idx_co_1st) + cpatch%land_use_label = rio_patchdistturbcat_pa(io_idx_co_1st) cpatch%age_since_anthro_disturbance = rio_agesinceanthrodist_pa(io_idx_co_1st) cpatch%nocomp_pft_label = rio_nocomp_pft_label_pa(io_idx_co_1st) cpatch%area = rio_area_pa(io_idx_co_1st) diff --git a/main/FatesUtilsMod.F90 b/main/FatesUtilsMod.F90 index 3310b5d6a4..4699a6aa60 100644 --- a/main/FatesUtilsMod.F90 +++ b/main/FatesUtilsMod.F90 @@ -13,6 +13,7 @@ module FatesUtilsMod public :: check_hlm_list public :: check_var_real public :: GetNeighborDistance + public :: FindIndex contains @@ -135,8 +136,6 @@ function GetNeighborDistance(gi,gj,latc,lonc) result(gcd) integer, intent(in) :: gi,gj ! indices of gridcells real(r8), intent(in) :: latc(:),lonc(:) ! lat/lon of gridcells real(r8) :: gcd - - ! write(fates_log(),*)'neighborhood: size ldomain latc/lonc: ', size(ldomain%latc), size(ldomain%lonc) gcd = GreatCircleDist(lonc(gi),lonc(gj), & latc(gi),latc(gj)) @@ -144,5 +143,39 @@ function GetNeighborDistance(gi,gj,latc,lonc) result(gcd) end function GetNeighborDistance ! ====================================================================================== + + function FindIndex(input_string_array,string_to_match) result(array_index) + + ! --------------------------------------------------------------------------------- + ! This simple function is a standin for the intrinsic FINDLOC which is not available + ! with some compilers such as NAG prior to v7.0. As with FINDLOC, the + ! function will return zero if a match is not found. + ! + ! Limitations compared to FINDLOC: + ! - Only takes one dimensional arrays + ! - Only take arrays of characters + ! - Does not allow masking + ! --------------------------------------------------------------------------------- + + ! Input and output + character(len=*), intent(in) :: input_string_array(:) + character(len=*), intent(in) :: string_to_match + integer :: array_index + + ! Locals + integer :: i + ! Initialize return index as zero + array_index = 0 + + ! Loop throught the array and compare strings + do i = 1, size(input_string_array) + if (trim(input_string_array(i)) .eq. trim(string_to_match)) then + array_index = i + end if + end do + + end function FindIndex + + ! ====================================================================================== end module FatesUtilsMod diff --git a/parameter_files/archive/api25.5.0_080923_fates_params_default.cdl b/parameter_files/archive/api25.5.0_080923_fates_params_default.cdl new file mode 100644 index 0000000000..f170fe2275 --- /dev/null +++ b/parameter_files/archive/api25.5.0_080923_fates_params_default.cdl @@ -0,0 +1,1735 @@ +netcdf fates_params_default { +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_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_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_crown_depth_frac(fates_pft) ; + fates_allom_crown_depth_frac:units = "fraction" ; + fates_allom_crown_depth_frac:long_name = "the depth of a cohort crown as a fraction of its height" ; + 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_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_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 = "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 = "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_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_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 = "Binary flag for stress-deciduous leaf habit" ; + 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_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_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_a ; + fates_fire_fdi_a:units = "NA" ; + fates_fire_fdi_a:long_name = "spitfire parameter, fire danger index, EQ 5 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_fdi_b ; + fates_fire_fdi_b:units = "NA" ; + fates_fire_fdi_b:long_name = "spitfire parameter, fire danger index, EQ 5 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_maxpatch_primary ; + fates_maxpatch_primary:units = "count" ; + fates_maxpatch_primary:long_name = "maximum number of primary vegetation patches per site" ; + double fates_maxpatch_secondary ; + fates_maxpatch_secondary:units = "count" ; + fates_maxpatch_secondary:long_name = "maximum number of secondary vegetation patches per site" ; + 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_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.06896, 0.06896, 0.06896, 0.06896, 0.06896, 0.06896, + 0.06896, 0.06896, 0.06896, 0.01, 0.01, 0.01 ; + + fates_allom_agb2 = 0.572, 0.572, 0.572, 0.572, 0.572, 0.572, 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 = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_blca_expnt_diff = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_allom_cmode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_crown_depth_frac = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.95, 0.95, + 0.95, 1, 1, 1 ; + + fates_allom_d2bl1 = 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_allom_d2bl2 = 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 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.6568464, 0.6568464, 0.6568464, + 0.6568464, 0.6568464, 0.6568464, 0.6568464, 0.6568464, 0.6568464, + 0.6568464, 0.6568464, 0.6568464 ; + + fates_allom_d2ca_coefficient_min = 0.3381119, 0.3381119, 0.3381119, + 0.3381119, 0.3381119, 0.3381119, 0.3381119, 0.3381119, 0.3381119, + 0.3381119, 0.3381119, 0.3381119 ; + + fates_allom_d2h1 = 0.64, 0.64, 0.64, 0.64, 0.64, 0.64, 0.64, 0.64, 0.64, + 0.64, 0.64, 0.64 ; + + fates_allom_d2h2 = 0.37, 0.37, 0.37, 0.37, 0.37, 0.37, 0.37, 0.37, 0.37, + 0.37, 0.37, 0.37 ; + + fates_allom_d2h3 = -999.9, -999.9, -999.9, -999.9, -999.9, -999.9, -999.9, + -999.9, -999.9, -999.9, -999.9, -999.9 ; + + fates_allom_dbh_maxheight = 90, 80, 80, 80, 90, 80, 3, 3, 2, 0.35, 0.35, 0.35 ; + + 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_hmode = 1, 1, 1, 1, 1, 1, 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 = 1, 1, 1, 1, 1, 1, 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.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5 ; + + 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 = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + 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_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_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.7, 0.4, 0.7, 0.53, 0.7, 0.7, 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_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_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_a = 17.62 ; + + fates_fire_fdi_alpha = 0.00037 ; + + fates_fire_fdi_b = 243.12 ; + + 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_maxpatch_primary = 10 ; + + fates_maxpatch_secondary = 4 ; + + 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/api32.0.0_231215_luh2.xml b/parameter_files/archive/api32.0.0_231215_luh2.xml new file mode 100644 index 0000000000..ab0e8f33db --- /dev/null +++ b/parameter_files/archive/api32.0.0_231215_luh2.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + archive/api25.5.0_080923_fates_params_default.cdl + fates_params_default.cdl + 1,2,3,4,5,6,7,8,9,10,11,12 + + + fates_maxpatch_primary + + + fates_maxpatch_secondary + + + fates_landuseclass + 5 + + + fates_maxpatches_by_landuse + fates_landuseclass + count + maximum number of patches per site on each land use type + 9, 4, 1, 1, 1 + + + fates_landuseclass_name + fates_landuseclass, fates_string_length + unitless - string + Name of the land use classes, for variables associated with dimension fates_landuseclass + primaryland, secondaryland, rangeland, pastureland, cropland + + + diff --git a/parameter_files/fates_params_default.cdl b/parameter_files/fates_params_default.cdl index f170fe2275..e288664751 100644 --- a/parameter_files/fates_params_default.cdl +++ b/parameter_files/fates_params_default.cdl @@ -13,6 +13,7 @@ dimensions: fates_pft = 12 ; fates_plant_organs = 4 ; fates_string_length = 60 ; + fates_landuseclass = 5 ; variables: double fates_history_ageclass_bin_edges(fates_history_age_bins) ; fates_history_ageclass_bin_edges:units = "yr" ; @@ -44,6 +45,9 @@ variables: 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" ; @@ -668,6 +672,9 @@ 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_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" ; @@ -815,12 +822,6 @@ variables: 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_maxpatch_primary ; - fates_maxpatch_primary:units = "count" ; - fates_maxpatch_primary:long_name = "maximum number of primary vegetation patches per site" ; - double fates_maxpatch_secondary ; - fates_maxpatch_secondary:units = "count" ; - fates_maxpatch_secondary:long_name = "maximum number of secondary vegetation patches per site" ; 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)" ; @@ -930,6 +931,13 @@ data: "sapwood", "structure" ; + fates_landuseclass_name = + "primaryland", + "secondaryland", + "rangeland", + "pastureland", + "cropland" ; + fates_litterclass_name = "twig ", "small branch ", @@ -1589,6 +1597,8 @@ data: 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 ; @@ -1687,10 +1697,6 @@ data: fates_maxcohort = 100 ; - fates_maxpatch_primary = 10 ; - - fates_maxpatch_secondary = 4 ; - fates_mort_disturb_frac = 1 ; fates_mort_understorey_death = 0.55983 ; diff --git a/tools/UpdateParamAPI.py b/tools/UpdateParamAPI.py index f23ef5d24c..7f49412eff 100755 --- a/tools/UpdateParamAPI.py +++ b/tools/UpdateParamAPI.py @@ -298,16 +298,19 @@ def main(): # print("no data type (dt), exiting");exit(2) try: + # print("trying dimnames: {}".format(paramname)) dimnames = tuple(mod.find('di').text.replace(" ","").split(',')) except: print("no data type (di), exiting");exit(2) try: + # print("trying units: {}".format(paramname)) units = mod.find('un').text.strip() except: print("no units (un), exiting");exit(2) try: + # print("trying ln: {}".format(paramname)) longname = mod.find('ln').text.strip() except: print("no long-name (ln), exiting");exit(2) @@ -315,30 +318,31 @@ def main(): ncfile = netcdf.netcdf_file(base_nc,"a",mmap=False) try: - values = str2fvec(mod.find('val').text.strip()) - except: - # try: - if(isinstance(mod.find('val').text,type(None))): - # values = mod.find('val').text.strip() - # except: + # print("trying val: {}".format(paramname)) + valstring = mod.find('val').text.strip() + values = str2fvec(valstring) + except Exception as emsg: + # print("type: {}".format(type(valstring))) + if(isinstance(valstring,type(None))): print("Warning: no values (val). Setting undefined (i.e. '_'): {}\n".format(paramname)) sel_values = ncfile.variables['fates_dev_arbitrary_pft'].data dcode = "d" - else: - print("unknown values (val), exiting");exit(2) + elif(isinstance(valstring,str)): + dcode = "c" + values = valstring.split(',') + for i,val in enumerate(values): + values[i] = val.strip() + print("value: {},{}".format(i,values[i])) + sel_values = selectvalues(ncfile,list(dimnames),ipft_list,values,dcode) + else: + print("exception, unknown values (val), exiting: {}".format(emsg));exit(2) #print("no values (val), exiting");exit(2) else: #code.interact(local=dict(globals(), **locals())) if(dimnames[0]=='scalar' or dimnames[0]=='none' or dimnames[0]==''): dimnames = () - - if(isinstance(values[0],str)): - dcode = "c" - values = values.split(',') - for i,val in enumerate(values): - values[i] = val.strip() elif(isinstance(values[0],float)): dcode = "d" else: diff --git a/tools/modify_fates_paramfile.py b/tools/modify_fates_paramfile.py index adacb2457b..85f7c449ea 100755 --- a/tools/modify_fates_paramfile.py +++ b/tools/modify_fates_paramfile.py @@ -141,7 +141,7 @@ def main(): 'fates_history_damage_bins', 'fates_NCWD','fates_litterclass','fates_leafage_class', \ 'fates_plant_organs','fates_hydr_organs','fates_hlm_pftno', \ - 'fates_leafage_class']: + 'fates_leafage_class','fates_landuse_class']: otherdimpresent = True otherdimname = var.dimensions[i] otherdimlength = var.shape[i] diff --git a/tools/ncvarsort.py b/tools/ncvarsort.py index 327dd84a96..6583700ae3 100755 --- a/tools/ncvarsort.py +++ b/tools/ncvarsort.py @@ -30,7 +30,7 @@ def main(): # make empty lists to hold the variable names in. the first of these is a list of sub-lists, # one for each type of variable (based on dimensionality). # the second is the master list that will contain all variables. - varnames_list = [[],[],[],[],[],[],[],[],[],[],[],[],[]] + varnames_list = [[],[],[],[],[],[],[],[],[],[],[],[],[],[]] varnames_list_sorted = [] # # sort the variables by dimensionality, but mix the PFT x other dimension in with the regular PFT-indexed variables @@ -48,6 +48,7 @@ def main(): (u'fates_prt_organs', u'fates_string_length'):7, (u'fates_plant_organs', u'fates_string_length'):7, (u'fates_litterclass', u'fates_string_length'):7, + (u'fates_landuseclass', u'fates_string_length'):7, (u'fates_pft',):8, (u'fates_hydr_organs', u'fates_pft'):8, (u'fates_leafage_class', u'fates_pft'):8, @@ -56,7 +57,9 @@ def main(): (u'fates_hlm_pftno', u'fates_pft'):9, (u'fates_litterclass',):10, (u'fates_NCWD',):11, - ():12} + (u'fates_landuseclass',):12, + (u'fates_landuseclass', u'fates_pft'):12, + ():13} # # go through each of the variables and assign it to one of the sub-lists based on its dimensionality for v_name, varin in dsin.variables.items():