diff --git a/biogeochem/EDCohortDynamicsMod.F90 b/biogeochem/EDCohortDynamicsMod.F90 index ef87851ec1..39929612e3 100644 --- a/biogeochem/EDCohortDynamicsMod.F90 +++ b/biogeochem/EDCohortDynamicsMod.F90 @@ -45,6 +45,7 @@ Module EDCohortDynamicsMod use PRTGenericMod , only : max_nleafage use FatesConstantsMod , only : ican_upper use EDTypesMod , only : site_fluxdiags_type + use EDTypesMod , only : elem_diag_type use PRTGenericMod , only : num_elements use FatesConstantsMod , only : leaves_on use FatesConstantsMod , only : leaves_off @@ -602,7 +603,7 @@ subroutine SendCohortToLitter(csite,cpatch,ccohort,nplant,bc_in) type(bc_in_type), intent(in) :: bc_in type(litter_type), pointer :: litt ! Litter object for each element - type(site_fluxdiags_type),pointer :: flux_diags + type(elem_diag_type),pointer :: elflux_diags real(r8) :: leaf_m ! leaf mass [kg] real(r8) :: store_m ! storage mass [kg] @@ -646,7 +647,7 @@ subroutine SendCohortToLitter(csite,cpatch,ccohort,nplant,bc_in) endif litt => cpatch%litter(el) - flux_diags => csite%flux_diags(el) + elflux_diags => csite%flux_diags%elem(el) !adjust how wood is partitioned between the cwd classes based on cohort dbh call adjust_SF_CWD_frac(ccohort%dbh,ncwd,SF_val_CWD_frac,SF_val_CWD_frac_adj) @@ -667,12 +668,12 @@ subroutine SendCohortToLitter(csite,cpatch,ccohort,nplant,bc_in) enddo ! above ground - flux_diags%cwd_ag_input(c) = flux_diags%cwd_ag_input(c) + & + elflux_diags%cwd_ag_input(c) = elflux_diags%cwd_ag_input(c) + & (struct_m+sapw_m) * SF_val_CWD_frac_adj(c) * & prt_params%allom_agb_frac(pft) * nplant ! below ground - flux_diags%cwd_bg_input(c) = flux_diags%cwd_bg_input(c) + & + elflux_diags%cwd_bg_input(c) = elflux_diags%cwd_bg_input(c) + & (struct_m + sapw_m) * SF_val_CWD_frac_adj(c) * & (1.0_r8 - prt_params%allom_agb_frac(pft)) * nplant @@ -692,11 +693,11 @@ subroutine SendCohortToLitter(csite,cpatch,ccohort,nplant,bc_in) end do - flux_diags%leaf_litter_input(pft) = & - flux_diags%leaf_litter_input(pft) + & + elflux_diags%surf_fine_litter_input(pft) = & + elflux_diags%surf_fine_litter_input(pft) + & (leaf_m+repro_m) * nplant - flux_diags%root_litter_input(pft) = & - flux_diags%root_litter_input(pft) + & + elflux_diags%root_litter_input(pft) = & + elflux_diags%root_litter_input(pft) + & (fnrt_m+store_m) * nplant diff --git a/biogeochem/EDLoggingMortalityMod.F90 b/biogeochem/EDLoggingMortalityMod.F90 index 6d373e995a..7ff878dbc6 100644 --- a/biogeochem/EDLoggingMortalityMod.F90 +++ b/biogeochem/EDLoggingMortalityMod.F90 @@ -19,6 +19,7 @@ module EDLoggingMortalityMod use FatesPatchMod , only : fates_patch_type use EDTypesMod , only : site_massbal_type use EDTypesMod , only : site_fluxdiags_type + use EDTypesMod , only : elem_diag_type use FatesLitterMod , only : ncwd use FatesLitterMod , only : ndcmpy use FatesLitterMod , only : litter_type @@ -28,6 +29,7 @@ module EDLoggingMortalityMod use FatesConstantsMod , only : dtype_ilog use FatesConstantsMod , only : dtype_ifall use FatesConstantsMod , only : dtype_ifire + use EDTypesMod , only : area_inv use FatesConstantsMod , only : n_landuse_cats use EDPftvarcon , only : EDPftvarcon_inst use EDPftvarcon , only : GetDecompyFrac @@ -502,8 +504,6 @@ subroutine get_harvestable_carbon (csite, site_area, hlm_harvest_catnames, harve !USES: use SFParamsMod, only : SF_val_cwd_frac - use EDTypesMod, only : AREA_INV - ! ------------------------------------------------------------------------------------------- ! @@ -556,7 +556,7 @@ subroutine get_harvestable_carbon (csite, site_area, hlm_harvest_catnames, harve harvestable_cohort_c = logging_direct_frac * ( sapw_m + struct_m ) * & prt_params%allom_agb_frac(currentCohort%pft) * & SF_val_CWD_frac(ncwd) * logging_export_frac * & - currentCohort%n * AREA_INV * site_area + currentCohort%n * area_inv * site_area ! No harvest for trees without canopy if (currentCohort%canopy_layer>=1) then @@ -795,9 +795,9 @@ subroutine logging_litter_fluxes(currentSite, currentPatch, newPatch, patch_site !LOCAL VARIABLES: - type(fates_cohort_type), pointer :: currentCohort + type(fates_cohort_type), pointer :: currentCohort type(site_massbal_type), pointer :: site_mass - type(site_fluxdiags_type), pointer :: flux_diags + type(elem_diag_type), pointer :: elflux_diags type(litter_type),pointer :: new_litt type(litter_type),pointer :: cur_litt @@ -855,12 +855,12 @@ subroutine logging_litter_fluxes(currentSite, currentPatch, newPatch, patch_site do el = 1,num_elements - + element_id = element_list(el) site_mass => currentSite%mass_balance(el) - flux_diags=> currentSite%flux_diags(el) + elflux_diags=> currentSite%flux_diags%elem(el) cur_litt => currentPatch%litter(el) ! Litter pool of "current" patch - new_litt => newPatch%litter(el) ! Litter pool of "new" patch + new_litt => newPatch%litter(el) ! Litter pool of "new" patch ! Zero some site level accumulator diagnsotics trunk_product_site = 0.0_r8 @@ -958,10 +958,10 @@ subroutine logging_litter_fluxes(currentSite, currentPatch, newPatch, patch_site ! Diagnostics on fluxes into the AG and BG CWD pools - flux_diags%cwd_ag_input(c) = flux_diags%cwd_ag_input(c) + & + elflux_diags%cwd_ag_input(c) = elflux_diags%cwd_ag_input(c) + & SF_val_CWD_frac_adj(c) * ag_wood - flux_diags%cwd_bg_input(c) = flux_diags%cwd_bg_input(c) + & + elflux_diags%cwd_bg_input(c) = elflux_diags%cwd_bg_input(c) + & SF_val_CWD_frac_adj(c) * bg_wood ! Diagnostic specific to resource management code @@ -999,10 +999,10 @@ subroutine logging_litter_fluxes(currentSite, currentPatch, newPatch, patch_site end do - flux_diags%cwd_ag_input(ncwd) = flux_diags%cwd_ag_input(ncwd) + & + elflux_diags%cwd_ag_input(ncwd) = elflux_diags%cwd_ag_input(ncwd) + & SF_val_CWD_frac_adj(ncwd) * ag_wood - flux_diags%cwd_bg_input(ncwd) = flux_diags%cwd_bg_input(ncwd) + & + elflux_diags%cwd_bg_input(ncwd) = elflux_diags%cwd_bg_input(ncwd) + & SF_val_CWD_frac_adj(ncwd) * bg_wood if( element_id .eq. carbon12_element) then @@ -1027,7 +1027,7 @@ subroutine logging_litter_fluxes(currentSite, currentPatch, newPatch, patch_site retain_m2 end do - flux_diags%cwd_bg_input(ncwd) = flux_diags%cwd_bg_input(ncwd) + & + elflux_diags%cwd_bg_input(ncwd) = elflux_diags%cwd_bg_input(ncwd) + & bg_wood ! ---------------------------------------------------------------------------------------- @@ -1088,10 +1088,10 @@ subroutine logging_litter_fluxes(currentSite, currentPatch, newPatch, patch_site end do ! track as diagnostic fluxes - flux_diags%leaf_litter_input(pft) = flux_diags%leaf_litter_input(pft) + & + elflux_diags%surf_fine_litter_input(pft) = elflux_diags%surf_fine_litter_input(pft) + & leaf_litter - flux_diags%root_litter_input(pft) = flux_diags%root_litter_input(pft) + & + elflux_diags%root_litter_input(pft) = elflux_diags%root_litter_input(pft) + & root_litter ! Logging specific diagnostics @@ -1116,6 +1116,10 @@ subroutine logging_litter_fluxes(currentSite, currentPatch, newPatch, patch_site currentCohort => currentCohort%taller end do + ! Amount of trunk mass exported off site [kg/m2] + elflux_diags%exported_harvest = elflux_diags%exported_harvest + & + trunk_product_site * area_inv + ! Update the amount of carbon exported from the site through logging ! operations. Currently we assume only above-ground portion ! of the tree bole that experienced "direct" logging is exported @@ -1166,7 +1170,6 @@ subroutine UpdateHarvestC(currentSite,bc_out) ! Harvested C flux in HLM. ! ---------------------------------------------------------------------------------- use EDtypesMod , only : ed_site_type - use EDTypesMod , only : AREA_INV use PRTGenericMod , only : element_pos use PRTGenericMod , only : carbon12_element use FatesInterfaceTypesMod , only : bc_out_type @@ -1191,20 +1194,20 @@ subroutine UpdateHarvestC(currentSite,bc_out) do i_pft = 1,numpft bc_out%hrv_deadstemc_to_prod10c = bc_out%hrv_deadstemc_to_prod10c + & currentSite%mass_balance(element_pos(carbon12_element))%wood_product_harvest(i_pft) * & - AREA_INV * EDPftvarcon_inst%harvest_pprod10(i_pft) * unit_trans_factor + area_inv * EDPftvarcon_inst%harvest_pprod10(i_pft) * unit_trans_factor bc_out%hrv_deadstemc_to_prod100c = bc_out%hrv_deadstemc_to_prod100c + & currentSite%mass_balance(element_pos(carbon12_element))%wood_product_harvest(i_pft) * & - AREA_INV * (1._r8 - EDPftvarcon_inst%harvest_pprod10(i_pft)) * unit_trans_factor + area_inv * (1._r8 - EDPftvarcon_inst%harvest_pprod10(i_pft)) * unit_trans_factor end do ! land-use-change-associated wood product pools do i_pft = 1,numpft bc_out%hrv_deadstemc_to_prod10c = bc_out%hrv_deadstemc_to_prod10c + & currentSite%mass_balance(element_pos(carbon12_element))%wood_product_landusechange(i_pft) * & - AREA_INV * EDPftvarcon_inst%landusechange_pprod10(i_pft) * unit_trans_factor + area_inv * EDPftvarcon_inst%landusechange_pprod10(i_pft) * unit_trans_factor bc_out%hrv_deadstemc_to_prod100c = bc_out%hrv_deadstemc_to_prod100c + & currentSite%mass_balance(element_pos(carbon12_element))%wood_product_landusechange(i_pft) * & - AREA_INV * (1._r8 - EDPftvarcon_inst%landusechange_pprod10(i_pft)) * unit_trans_factor + area_inv * (1._r8 - EDPftvarcon_inst%landusechange_pprod10(i_pft)) * unit_trans_factor end do return diff --git a/biogeochem/EDPatchDynamicsMod.F90 b/biogeochem/EDPatchDynamicsMod.F90 index 3dedd6e98c..196b40ba15 100644 --- a/biogeochem/EDPatchDynamicsMod.F90 +++ b/biogeochem/EDPatchDynamicsMod.F90 @@ -26,6 +26,7 @@ module EDPatchDynamicsMod use FatesCohortMod , only : fates_cohort_type use EDTypesMod , only : site_massbal_type use EDTypesMod , only : site_fluxdiags_type + use EDTypesMod , only : elem_diag_type use EDTypesMod , only : min_patch_area use EDTypesMod , only : min_patch_area_forced use EDParamsMod , only : regeneration_model @@ -1088,6 +1089,12 @@ subroutine spawn_patches( currentSite, bc_in) currentSite%mass_balance(el)%burn_flux_to_atm = & currentSite%mass_balance(el)%burn_flux_to_atm + & leaf_burn_frac * leaf_m * nc%n + + ! This diagnostic only tracks + currentSite%flux_diags%elem(el)%burned_liveveg = & + currentSite%flux_diags%elem(el)%burned_liveveg + & + leaf_burn_frac * leaf_m * nc%n * area_inv + end do ! Here the mass is removed from the plant @@ -2186,7 +2193,7 @@ subroutine fire_litter_fluxes(currentSite, currentPatch, & 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 + type(elem_diag_type), pointer :: elflux_diags real(r8) :: donatable_mass ! non-burned litter mass provided by the donor [kg] ! some may or may not be retained by the donor @@ -2259,7 +2266,7 @@ subroutine fire_litter_fluxes(currentSite, currentPatch, & element_id = element_list(el) site_mass => currentSite%mass_balance(el) - flux_diags => currentSite%flux_diags(el) + elflux_diags => currentSite%flux_diags%elem(el) curr_litt => currentPatch%litter(el) ! Litter pool of "current" patch new_litt => newPatch%litter(el) ! Litter pool of "new" patch @@ -2319,6 +2326,8 @@ subroutine fire_litter_fluxes(currentSite, currentPatch, & 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) @@ -2335,12 +2344,12 @@ subroutine fire_litter_fluxes(currentSite, currentPatch, & end do ! Track as diagnostic fluxes - flux_diags%leaf_litter_input(pft) = & - flux_diags%leaf_litter_input(pft) + & + elflux_diags%surf_fine_litter_input(pft) = & + elflux_diags%surf_fine_litter_input(pft) + & num_dead_trees * (leaf_m+repro_m) * (1.0_r8-currentCohort%fraction_crown_burned) - flux_diags%root_litter_input(pft) = & - flux_diags%root_litter_input(pft) + & + elflux_diags%root_litter_input(pft) = & + elflux_diags%root_litter_input(pft) + & (fnrt_m + store_m) * num_dead_trees ! coarse root biomass per tree @@ -2362,9 +2371,9 @@ subroutine fire_litter_fluxes(currentSite, currentPatch, & donatable_mass * retain_m2 ! track diagnostics - flux_diags%cwd_bg_input(c) = & - flux_diags%cwd_bg_input(c) + & - donatable_mass + elflux_diags%cwd_bg_input(c) = & + elflux_diags%cwd_bg_input(c) + & + donatable_mass enddo end do @@ -2383,7 +2392,7 @@ subroutine fire_litter_fluxes(currentSite, currentPatch, & 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 + elflux_diags%cwd_ag_input(c) = elflux_diags%cwd_ag_input(c) + donatable_mass enddo @@ -2426,7 +2435,7 @@ subroutine mortality_litter_fluxes(currentSite, currentPatch, & 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 + type(elem_diag_type), pointer :: elflux_diags real(r8) :: remainder_area ! amount of area remaining in patch after donation real(r8) :: num_dead @@ -2473,7 +2482,7 @@ subroutine mortality_litter_fluxes(currentSite, currentPatch, & element_id = element_list(el) site_mass => currentSite%mass_balance(el) - flux_diags => currentSite%flux_diags(el) + elflux_diags => currentSite%flux_diags%elem(el) curr_litt => currentPatch%litter(el) ! Litter pool of "current" patch new_litt => newPatch%litter(el) ! Litter pool of "new" patch @@ -2603,17 +2612,17 @@ subroutine mortality_litter_fluxes(currentSite, currentPatch, & ! track diagnostic fluxes do c=1,ncwd - flux_diags%cwd_ag_input(c) = & - flux_diags%cwd_ag_input(c) + SF_val_CWD_frac_adj(c) * ag_wood + elflux_diags%cwd_ag_input(c) = & + elflux_diags%cwd_ag_input(c) + SF_val_CWD_frac_adj(c) * ag_wood - flux_diags%cwd_bg_input(c) = & - flux_diags%cwd_bg_input(c) + SF_val_CWD_frac_adj(c) * bg_wood + elflux_diags%cwd_bg_input(c) = & + elflux_diags%cwd_bg_input(c) + SF_val_CWD_frac_adj(c) * bg_wood end do - flux_diags%leaf_litter_input(pft) = flux_diags%leaf_litter_input(pft) + & + elflux_diags%surf_fine_litter_input(pft) = elflux_diags%surf_fine_litter_input(pft) + & num_dead*(leaf_m + repro_m) - flux_diags%root_litter_input(pft) = flux_diags%root_litter_input(pft) + & + elflux_diags%root_litter_input(pft) = elflux_diags%root_litter_input(pft) + & num_dead * (fnrt_m + store_m*(1.0_r8-EDPftvarcon_inst%allom_frbstor_repro(pft))) @@ -2656,7 +2665,7 @@ subroutine landusechange_litter_fluxes(currentSite, currentPatch, & 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 + type(elem_diag_type), pointer :: elflux_diags real(r8) :: donatable_mass ! non-burned litter mass provided by the donor [kg] ! some may or may not be retained by the donor @@ -2733,7 +2742,7 @@ subroutine landusechange_litter_fluxes(currentSite, currentPatch, & element_id = element_list(el) site_mass => currentSite%mass_balance(el) - flux_diags => currentSite%flux_diags(el) + elflux_diags => currentSite%flux_diags%elem(el) curr_litt => currentPatch%litter(el) ! Litter pool of "current" patch new_litt => newPatch%litter(el) ! Litter pool of "new" patch @@ -2790,7 +2799,7 @@ subroutine landusechange_litter_fluxes(currentSite, currentPatch, & 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) @@ -2807,12 +2816,12 @@ subroutine landusechange_litter_fluxes(currentSite, currentPatch, & end do ! Track as diagnostic fluxes - flux_diags%leaf_litter_input(pft) = & - flux_diags%leaf_litter_input(pft) + & + elflux_diags%surf_fine_litter_input(pft) = & + elflux_diags%surf_fine_litter_input(pft) + & num_dead_trees * (leaf_m+repro_m) * (1.0_r8-EDPftvarcon_inst%landusechange_frac_burned(pft)) - flux_diags%root_litter_input(pft) = & - flux_diags%root_litter_input(pft) + & + elflux_diags%root_litter_input(pft) = & + elflux_diags%root_litter_input(pft) + & (fnrt_m + store_m) * num_dead_trees ! coarse root biomass per tree @@ -2830,8 +2839,8 @@ subroutine landusechange_litter_fluxes(currentSite, currentPatch, & donatable_mass * retain_m2 ! track diagnostics - flux_diags%cwd_bg_input(c) = & - flux_diags%cwd_bg_input(c) + & + elflux_diags%cwd_bg_input(c) = & + elflux_diags%cwd_bg_input(c) + & donatable_mass enddo end do @@ -2866,12 +2875,17 @@ subroutine landusechange_litter_fluxes(currentSite, currentPatch, & trunk_product_site = trunk_product_site + & woodproduct_mass + ! Amount of trunk mass exported off site [kg/m2] + elflux_diags%exported_harvest = elflux_diags%exported_harvest + & + woodproduct_mass * area_inv + site_mass%wood_product_landusechange(pft) = site_mass%wood_product_landusechange(pft) + & woodproduct_mass + endif new_litt%ag_cwd(c) = new_litt%ag_cwd(c) + donatable_mass * donate_m2 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 + elflux_diags%cwd_ag_input(c) = elflux_diags%cwd_ag_input(c) + donatable_mass enddo currentCohort => currentCohort%taller diff --git a/biogeochem/EDPhysiologyMod.F90 b/biogeochem/EDPhysiologyMod.F90 index 94f47ac083..dddfd83113 100644 --- a/biogeochem/EDPhysiologyMod.F90 +++ b/biogeochem/EDPhysiologyMod.F90 @@ -53,6 +53,7 @@ module EDPhysiologyMod use EDTypesMod , only : site_massbal_type use EDTypesMod , only : numlevsoil_max use EDTypesMod , only : numWaterMem + use EDTypesMod , only : elem_diag_type use FatesLitterMod , only : dl_sf use EDParamsMod , only : dinc_vai, dlower_vai use EDTypesMod , only : area_inv @@ -269,7 +270,7 @@ subroutine GenerateDamageAndLitterFluxes( csite, cpatch, bc_in ) type(fates_cohort_type), pointer :: ccohort ! Current cohort type(fates_cohort_type), pointer :: ndcohort ! New damage-class cohort type(litter_type), pointer :: litt ! Points to the litter object - type(site_fluxdiags_type), pointer :: flux_diags ! pointer to site level flux diagnostics object + type(elem_diag_type), pointer :: elflux_diags ! pointer to site level flux diagnostics object integer :: cd ! Damage class index integer :: el ! Element index integer :: dcmpy ! Decomposition pool index @@ -346,7 +347,7 @@ subroutine GenerateDamageAndLitterFluxes( csite, cpatch, bc_in ) do_element: do el = 1, num_elements litt => cpatch%litter(el) - flux_diags => csite%flux_diags(el) + elflux_diags => csite%flux_diags%elem(el) ! Reduce the mass of the newly damaged cohort ! Fine-roots are not damaged as of yet @@ -372,8 +373,8 @@ subroutine GenerateDamageAndLitterFluxes( csite, cpatch, bc_in ) ndcohort%n * dcmpy_frac / cpatch%area end do - flux_diags%leaf_litter_input(ipft) = & - flux_diags%leaf_litter_input(ipft) + & + elflux_diags%surf_fine_litter_input(ipft) = & + elflux_diags%surf_fine_litter_input(ipft) + & (store_loss+leaf_loss+repro_loss) * ndcohort%n call adjust_SF_CWD_frac(ndcohort%dbh,ncwd,SF_val_CWD_frac,SF_val_CWD_frac_adj) @@ -384,7 +385,7 @@ subroutine GenerateDamageAndLitterFluxes( csite, cpatch, bc_in ) SF_val_CWD_frac_adj(c) * ndcohort%n / & cpatch%area - flux_diags%cwd_ag_input(c) = flux_diags%cwd_ag_input(c) + & + elflux_diags%cwd_ag_input(c) = elflux_diags%cwd_ag_input(c) + & (struct_loss + sapw_loss) * & SF_val_CWD_frac_adj(c) * ndcohort%n end do @@ -455,9 +456,7 @@ subroutine PreDisturbanceLitterFluxes( currentSite, currentPatch, bc_in ) ! ! !LOCAL VARIABLES: - type(site_massbal_type), pointer :: site_mass - type(litter_type), pointer :: litt ! Points to the litter object for - ! the different element types + integer :: el ! Litter element loop index integer :: nlev_eff_decomp ! Number of active layers over which ! fragmentation fluxes are transfered @@ -468,36 +467,40 @@ subroutine PreDisturbanceLitterFluxes( currentSite, currentPatch, bc_in ) do el = 1, num_elements - litt => currentPatch%litter(el) - - ! Calculate loss rate of viable seeds to litter - call SeedDecay(litt, currentPatch, bc_in) - - - ! Calculate seed germination rate, the status flags prevent - ! germination from occuring when the site is in a drought - ! (for drought deciduous) or too cold (for cold deciduous) - call SeedGermination(litt, currentSite%cstatus, currentSite%dstatus(1:numpft), bc_in, currentPatch) - - ! Send fluxes from newly created litter into the litter pools - ! This litter flux is from non-disturbance inducing mortality, as well - ! as litter fluxes from live trees - call CWDInput(currentSite, currentPatch, litt,bc_in) + associate( litt => currentPatch%litter(el), & + site_mass => currentSite%mass_balance(el), & + diag => currentSite%flux_diags%elem(el)) - ! Only calculate fragmentation flux over layers that are active - ! (RGK-Mar2019) SHOULD WE MAX THIS AT 1? DONT HAVE TO - - nlev_eff_decomp = max(bc_in%max_rooting_depth_index_col, 1) - call CWDOut(litt,currentPatch%fragmentation_scaler,nlev_eff_decomp) - - site_mass => currentSite%mass_balance(el) - - ! Fragmentation flux to soil decomposition model [kg/site/day] - site_mass%frag_out = site_mass%frag_out + currentPatch%area * & - ( sum(litt%ag_cwd_frag) + sum(litt%bg_cwd_frag) + & - sum(litt%leaf_fines_frag) + sum(litt%root_fines_frag) + & - sum(litt%seed_decay) + sum(litt%seed_germ_decay)) + ! Calculate loss rate of viable seeds to litter + call SeedDecay(litt, currentPatch, bc_in) + + ! Calculate seed germination rate, the status flags prevent + ! germination from occuring when the site is in a drought + ! (for drought deciduous) or too cold (for cold deciduous) + call SeedGermination(litt, currentSite%cstatus, currentSite%dstatus(1:numpft), bc_in, currentPatch) + + ! Send fluxes from newly created litter into the litter pools + ! This litter flux is from non-disturbance inducing mortality, as well + ! as litter fluxes from live trees + call CWDInput(currentSite, currentPatch, litt,bc_in) + + ! Only calculate fragmentation flux over layers that are active + ! (RGK-Mar2019) SHOULD WE MAX THIS AT 1? DONT HAVE TO + + nlev_eff_decomp = max(bc_in%max_rooting_depth_index_col, 1) + call CWDOut(litt,currentPatch%fragmentation_scaler,nlev_eff_decomp) + + ! Fragmentation flux to soil decomposition model [kg/site/day] + site_mass%frag_out = site_mass%frag_out + currentPatch%area * & + ( sum(litt%ag_cwd_frag) + sum(litt%bg_cwd_frag) + & + sum(litt%leaf_fines_frag) + sum(litt%root_fines_frag) + & + sum(litt%seed_decay) + sum(litt%seed_germ_decay)) + + ! Track total seed decay diagnostic in [kg/m2/day] + diag%tot_seed_turnover = diag%tot_seed_turnover + & + (sum(litt%seed_decay) + sum(litt%seed_germ_decay))*currentPatch%area*area_inv + end associate end do @@ -1763,6 +1766,7 @@ subroutine phenology_leafonoff(currentSite) call PRTDeciduousTurnover(currentCohort%prt,ipft,sapw_organ , eff_sapw_drop_fraction ) call PRTDeciduousTurnover(currentCohort%prt,ipft,struct_organ, eff_struct_drop_fraction) end if + end if shed_block if(debug) call currentCohort%prt%CheckMassConservation(ipft,1) @@ -2154,7 +2158,7 @@ subroutine SeedUpdate( currentSite ) ! Seed input from local sources (within site). Note that a fraction of the ! internal seed rain is sent out to neighboring gridcells. - litt%seed_in_local(pft) = litt%seed_in_local(pft) + site_seed_rain(pft)*(1-site_disp_frac(pft))/area ![kg/m2/day] + litt%seed_in_local(pft) = litt%seed_in_local(pft) + site_seed_rain(pft)*(1.0_r8-site_disp_frac(pft))/area ![kg/m2/day] ! If we are using the Tree Recruitment Scheme (TRS) with or w/o seedling dynamics if ( any(regeneration_model == [TRS_regeneration, TRS_no_seedling_dyn]) .and. & @@ -2719,6 +2723,7 @@ subroutine recruitment(currentSite, currentPatch, bc_in) m_repro = 0._r8 end select + select case(hlm_parteh_mode) case (prt_carbon_allom_hyp, prt_cnp_flex_allom_hyp) @@ -2761,6 +2766,7 @@ subroutine recruitment(currentSite, currentPatch, bc_in) currentPatch%litter(el)%seed_germ(ft) - cohort_n / currentPatch%area * & (m_struct + m_leaf + m_fnrt + m_sapw + m_store + m_repro) end if + end do ! cycle through the initial conditions, and makes sure that they are all initialized @@ -2807,7 +2813,7 @@ subroutine CWDInput( currentSite, currentPatch, litt, bc_in) ! ! !LOCAL VARIABLES: type(fates_cohort_type), pointer :: currentCohort - type(site_fluxdiags_type), pointer :: flux_diags + type(elem_diag_type), pointer :: elflux_diags type(site_massbal_type), pointer :: site_mass integer :: c real(r8) :: dead_n ! total understorey dead tree density @@ -2854,11 +2860,13 @@ subroutine CWDInput( currentSite, currentPatch, litt, bc_in) element_id = litt%element_id ! Object tracking flux diagnostics for each element - flux_diags => currentSite%flux_diags(element_pos(element_id)) + elflux_diags => currentSite%flux_diags%elem(element_pos(element_id)) ! Object tracking site level mass balance for each element site_mass => currentSite%mass_balance(element_pos(element_id)) + ! Transfer litter from turnover of living plants + currentCohort => currentPatch%shortest do while(associated(currentCohort)) @@ -2869,7 +2877,9 @@ subroutine CWDInput( currentSite, currentPatch, litt, bc_in) store_m_turnover = currentCohort%prt%GetTurnover(store_organ,element_id) fnrt_m_turnover = currentCohort%prt%GetTurnover(fnrt_organ,element_id) repro_m_turnover = currentCohort%prt%GetTurnover(repro_organ,element_id) + + store_m = currentCohort%prt%GetState(store_organ,element_id) fnrt_m = currentCohort%prt%GetState(fnrt_organ,element_id) repro_m = currentCohort%prt%GetState(repro_organ,element_id) @@ -2908,9 +2918,9 @@ subroutine CWDInput( currentSite, currentPatch, litt, bc_in) ! about double counting. ! --------------------------------------------------------------------------------- - flux_diags%leaf_litter_input(pft) = & - flux_diags%leaf_litter_input(pft) + & - leaf_m_turnover * currentCohort%n + elflux_diags%surf_fine_litter_input(pft) = & + elflux_diags%surf_fine_litter_input(pft) + & + (leaf_m_turnover+repro_m_turnover) * currentCohort%n root_fines_tot = (fnrt_m_turnover + store_m_turnover ) * & plant_dens @@ -2927,8 +2937,8 @@ subroutine CWDInput( currentSite, currentPatch, litt, bc_in) end do end do - flux_diags%root_litter_input(pft) = & - flux_diags%root_litter_input(pft) + & + elflux_diags%root_litter_input(pft) = & + elflux_diags%root_litter_input(pft) + & (fnrt_m_turnover + store_m_turnover ) * currentCohort%n @@ -2944,7 +2954,7 @@ subroutine CWDInput( currentSite, currentPatch, litt, bc_in) SF_val_CWD_frac_adj(c) * plant_dens * & prt_params%allom_agb_frac(pft) - flux_diags%cwd_ag_input(c) = flux_diags%cwd_ag_input(c) + & + elflux_diags%cwd_ag_input(c) = elflux_diags%cwd_ag_input(c) + & (struct_m_turnover + sapw_m_turnover) * SF_val_CWD_frac_adj(c) * & prt_params%allom_agb_frac(pft) * currentCohort%n @@ -2957,7 +2967,7 @@ subroutine CWDInput( currentSite, currentPatch, litt, bc_in) bg_cwd_tot * currentSite%rootfrac_scr(ilyr) end do - flux_diags%cwd_bg_input(c) = flux_diags%cwd_bg_input(c) + & + elflux_diags%cwd_bg_input(c) = elflux_diags%cwd_bg_input(c) + & bg_cwd_tot*currentPatch%area enddo @@ -2993,12 +3003,6 @@ subroutine CWDInput( currentSite, currentPatch, litt, bc_in) dead_n_natural = dead_n - dead_n_dlogging - dead_n_ilogging - - flux_diags%leaf_litter_input(pft) = & - flux_diags%leaf_litter_input(pft) + & - leaf_m * dead_n*currentPatch%area - - ! %n has not been updated due to mortality yet, thus ! the litter flux has already been counted since it captured ! the losses of live trees and those flagged for death @@ -3019,8 +3023,12 @@ subroutine CWDInput( currentSite, currentPatch, litt, bc_in) end do end do - flux_diags%root_litter_input(pft) = & - flux_diags%root_litter_input(pft) + & + elflux_diags%surf_fine_litter_input(pft) = & + elflux_diags%surf_fine_litter_input(pft) + & + (leaf_m+repro_m) * dead_n*currentPatch%area + + elflux_diags%root_litter_input(pft) = & + elflux_diags%root_litter_input(pft) + & root_fines_tot*currentPatch%area ! Track CWD inputs from dead plants @@ -3038,7 +3046,7 @@ subroutine CWDInput( currentSite, currentPatch, litt, bc_in) currentSite%rootfrac_scr(ilyr) * bg_cwd_tot end do - flux_diags%cwd_bg_input(c) = flux_diags%cwd_bg_input(c) + & + elflux_diags%cwd_bg_input(c) = elflux_diags%cwd_bg_input(c) + & bg_cwd_tot * currentPatch%area ! Send AGB component of boles from logging activities into the litter. @@ -3061,7 +3069,7 @@ subroutine CWDInput( currentSite, currentPatch, litt, bc_in) litt%ag_cwd_in(c) = litt%ag_cwd_in(c) + & trunk_wood * (1._r8-logging_export_frac) - flux_diags%cwd_ag_input(c) = flux_diags%cwd_ag_input(c) + & + elflux_diags%cwd_ag_input(c) = elflux_diags%cwd_ag_input(c) + & trunk_wood * (1._r8-logging_export_frac) * currentPatch%area ! Add AG wood to litter from indirect anthro sources @@ -3070,8 +3078,8 @@ subroutine CWDInput( currentSite, currentPatch, litt, bc_in) SF_val_CWD_frac_adj(c) * (dead_n_natural+dead_n_ilogging) * & prt_params%allom_agb_frac(pft) - flux_diags%cwd_ag_input(c) = flux_diags%cwd_ag_input(c) + & - SF_val_CWD_frac_adj(c) * (dead_n_natural+dead_n_ilogging) * & + elflux_diags%cwd_ag_input(c) = elflux_diags%cwd_ag_input(c) + & + (struct_m + sapw_m) * SF_val_CWD_frac_adj(c) * (dead_n_natural+dead_n_ilogging) * & currentPatch%area * prt_params%allom_agb_frac(pft) else @@ -3080,7 +3088,7 @@ subroutine CWDInput( currentSite, currentPatch, litt, bc_in) SF_val_CWD_frac_adj(c) * dead_n * & prt_params%allom_agb_frac(pft) - flux_diags%cwd_ag_input(c) = flux_diags%cwd_ag_input(c) + & + elflux_diags%cwd_ag_input(c) = elflux_diags%cwd_ag_input(c) + & SF_val_CWD_frac_adj(c) * dead_n * (struct_m + sapw_m) * & currentPatch%area * prt_params%allom_agb_frac(pft) diff --git a/biogeochem/FatesSoilBGCFluxMod.F90 b/biogeochem/FatesSoilBGCFluxMod.F90 index 2c5b7d9b18..5cc25c697a 100644 --- a/biogeochem/FatesSoilBGCFluxMod.F90 +++ b/biogeochem/FatesSoilBGCFluxMod.F90 @@ -219,13 +219,14 @@ subroutine UnPackNutrientAquisitionBCs(sites, bc_in) ccohort%daily_p_demand = fnrt_c * EDPftvarcon_inst%vmax_p(pft) * sec_per_day ! P Uptake: Convert g/m2/day -> kg/plant/day ccohort%daily_p_gain = bc_in(s)%plant_p_uptake_flux(icomp,1)*kg_per_g*AREA/ccohort%n + ccohort => ccohort%shorter end do cpatch => cpatch%younger end do end if - + ! These can now be zero'd bc_in(s)%plant_nh4_uptake_flux(:,:) = 0._r8 bc_in(s)%plant_no3_uptake_flux(:,:) = 0._r8 diff --git a/main/ChecksBalancesMod.F90 b/main/ChecksBalancesMod.F90 index df671a52ac..325a1089e8 100644 --- a/main/ChecksBalancesMod.F90 +++ b/main/ChecksBalancesMod.F90 @@ -5,7 +5,7 @@ module ChecksBalancesMod use EDtypesMod, only : ed_site_type use FatesPatchMod, only : fates_patch_type use FatesCohortMod, only : fates_cohort_type - use EDTypesMod, only : AREA + use EDTypesMod, only : AREA, area_inv use EDTypesMod, only : site_massbal_type use PRTGenericMod, only : num_elements use PRTGenericMod, only : element_list @@ -16,6 +16,8 @@ module ChecksBalancesMod use FatesLitterMod, only : ncwd use FatesLitterMod, only : ndcmpy use PRTGenericMod, only : carbon12_element + use PRTGenericMod, only : nitrogen_element + use PRTGenericMod, only : phosphorus_element use PRTGenericMod, only : leaf_organ use PRTGenericMod, only : fnrt_organ use PRTGenericMod, only : sapw_organ @@ -31,7 +33,8 @@ module ChecksBalancesMod private public :: SiteMassStock public :: PatchMassStock - + public :: CheckIntegratedMassPools + character(len=*), parameter, private :: sourcefile = & __FILE__ @@ -240,7 +243,137 @@ subroutine CheckLitterPools(currentSite,bc_in) return end subroutine CheckLitterPools + ! ================================================================== + + subroutine CheckIntegratedMassPools(site) + + ! ----------------------------------------------------------------------------------- + ! + ! This subroutine checks that the time integrated net fluxes in and out of + ! the vegetation and the litter actually match the quantity in those pools. + ! + ! ----------------------------------------------------------------------------------- + + type(ed_site_type), intent(inout) :: site + + !integer :: nsites + integer :: el + integer :: s + real(r8) :: tot_veg_turnover + real(r8) :: tot_litter_input + real(r8) :: net_uptake + real(r8) :: biomass_stock + real(r8) :: seed_stock + real(r8) :: litter_stock + real(r8) :: total_stock + + logical,parameter :: check_iflux_bal = .true. + + if(check_iflux_bal) then + + ! For carbon balance checks, we need to initialize the + ! total carbon stock + do el=1,num_elements + call SiteMassStock(site,el,total_stock, & + biomass_stock,litter_stock,seed_stock) + + associate(ibal => site%iflux_balance(el), & + ediag => site%flux_diags%elem(el), & + diag => site%flux_diags, & + site_mass => site%mass_balance(el)) + + ! Initialize the integrated flux balance diagnostics + ! No need to initialize the instantaneous states, those are re-calculated + + ibal%state_liveveg = (biomass_stock + seed_stock)*area_inv + ibal%state_litter = litter_stock * area_inv + + ! Flux for live veg: net uptake (either NPP or net nutrient uptake) + + ! net spatial seed flux - + ! veg turnover to litter - + ! veg loss to fire (SEEDS DONT BURN) - + ! veg loss from exported harvest - + ! seed turnover + tot_litter_input = (sum(ediag%surf_fine_litter_input(:)) + & + sum(ediag%root_litter_input(:)) + & + sum(ediag%cwd_ag_input(:)) + & + sum(ediag%cwd_bg_input(:)))*area_inv + + select case(element_list(el)) + case(carbon12_element) + net_uptake = diag%npp + site_mass%net_root_uptake*area_inv + case(nitrogen_element) + net_uptake = site_mass%net_root_uptake*area_inv + case(phosphorus_element) + net_uptake = site_mass%net_root_uptake*area_inv + case default + write(fates_log(),*) 'FATES: an invalid chemical species was detected' + call endrun(msg=errMsg(sourcefile, __LINE__)) + end select + + ! Fluxes are in [kg/m2/day] so they can be added, + ! the frequency is /day so no conversion necessary + ! to integrate to [kg/m2] + ibal%iflux_liveveg = ibal%iflux_liveveg + & + ( net_uptake & + - tot_litter_input & + - ediag%burned_liveveg & + - ediag%exported_harvest & + + site_mass%seed_in*area_inv & + - site_mass%seed_out*area_inv & + - ediag%tot_seed_turnover) + + ! Flux for litter: veg turnover + seed turnover - "these are tot_litter_input" + ! fragmentation - + ! burned litter + + ibal%iflux_litter = ibal%iflux_litter + & + tot_litter_input - & + (site_mass%frag_out*area_inv - ediag%tot_seed_turnover) - & + (site_mass%burn_flux_to_atm*area_inv - ediag%burned_liveveg) + + + ediag%err_liveveg = ibal%iflux_liveveg - ibal%state_liveveg + + ediag%err_litter = ibal%iflux_litter - ibal%state_litter + + + ! Perform the comparison between integrated flux and state + !if(abs(ediag%err_liveveg) > iflux_tol(el) ) then + ! write(fates_log(),*) 'The fluxes in to an out of live vegetation are integrated' + ! write(fates_log(),*) 'in time over the length of the FATES simulation.' + ! write(fates_log(),*) 'This integrated quantity is compared with the instantaneous' + ! write(fates_log(),*) 'assessment of the total mass, they should be the same quanitity' + ! write(fates_log(),*) 'within a tolerance, but there is a discrepancy.' + ! write(fates_log(),*) 'state_liveveg: ',ibal%state_liveveg + ! write(fates_log(),*) 'iflux_liveveg: ',ibal%iflux_liveveg + ! write(fates_log(),*) 'state - iflux: ',ibal%state_liveveg - & + ! ibal%iflux_liveveg + ! call endrun(msg=errMsg(sourcefile, __LINE__)) + !end if + + !if(abs(ibal%state_litter - ibal%iflux_litter) > iflux_tol(el) ) then + ! write(fates_log(),*) 'The fluxes in to an out of litter are integrated' + ! write(fates_log(),*) 'in time over the length of the FATES simulation.' + ! write(fates_log(),*) 'This integrated quantity is compared with the instantaneous' + ! write(fates_log(),*) 'assessment of the total mass, they should be the same quanitity' + ! write(fates_log(),*) 'within a tolerance, but there is a discrepancy.' + ! write(fates_log(),*) 'state_litter: ',ibal%state_litter + ! write(fates_log(),*) 'iflux_litter: ',ibal%iflux_litter + ! write(fates_log(),*) 'state - iflux: ',ibal%state_litter - & + ! ibal%iflux_litter + ! call endrun(msg=errMsg(sourcefile, __LINE__)) + !end if + + + end associate + end do + + end if + + return + end subroutine CheckIntegratedMassPools diff --git a/main/EDInitMod.F90 b/main/EDInitMod.F90 index 15bbb3934c..d529a0e123 100644 --- a/main/EDInitMod.F90 +++ b/main/EDInitMod.F90 @@ -36,7 +36,7 @@ module EDInitMod use FatesCohortMod , only : fates_cohort_type use EDTypesMod , only : numWaterMem use EDTypesMod , only : num_vegtemp_mem - use EDTypesMod , only : AREA + use EDTypesMod , only : area, area_inv use EDTypesMod , only : init_spread_near_bare_ground use EDTypesMod , only : init_spread_inventory use FatesConstantsMod , only : leaves_on @@ -152,7 +152,7 @@ subroutine init_site_vars( site_in, bc_in, bc_out ) allocate(site_in%fmort_rate_crown(1:nlevsclass,1:numpft)) allocate(site_in%growthflux_fusion(1:nlevsclass,1:numpft)) allocate(site_in%mass_balance(1:num_elements)) - allocate(site_in%flux_diags(1:num_elements)) + allocate(site_in%iflux_balance(1:num_elements)) if (hlm_use_tree_damage .eq. itrue) then allocate(site_in%term_nindivs_canopy_damage(1:nlevdamage, 1:nlevsclass, 1:numpft)) @@ -210,10 +210,21 @@ subroutine init_site_vars( site_in, bc_in, bc_out ) allocate(site_in%sp_tsai(1:numpft)) allocate(site_in%sp_htop(1:numpft)) + ! Allocate site-level flux diagnostics + ! ----------------------------------------------------------------------- + allocate(site_in%flux_diags%elem(1:num_elements)) do el=1,num_elements - allocate(site_in%flux_diags(el)%leaf_litter_input(1:numpft)) - allocate(site_in%flux_diags(el)%root_litter_input(1:numpft)) + allocate(site_in%flux_diags%elem(el)%surf_fine_litter_input(1:numpft)) + allocate(site_in%flux_diags%elem(el)%root_litter_input(1:numpft)) end do + allocate(site_in%flux_diags%nh4_uptake_scpf(numpft*nlevsclass)) + allocate(site_in%flux_diags%no3_uptake_scpf(numpft*nlevsclass)) + allocate(site_in%flux_diags%sym_nfix_scpf(numpft*nlevsclass)) + allocate(site_in%flux_diags%n_efflux_scpf(numpft*nlevsclass)) + allocate(site_in%flux_diags%p_uptake_scpf(numpft*nlevsclass)) + allocate(site_in%flux_diags%p_efflux_scpf(numpft*nlevsclass)) + + ! Initialize the static soil ! arrays from the boundary (initial) condition @@ -287,9 +298,10 @@ subroutine zero_site( site_in ) ! Zero the state variables used for checking mass conservation call site_in%mass_balance(el)%ZeroMassBalState() call site_in%mass_balance(el)%ZeroMassBalFlux() - call site_in%flux_diags(el)%ZeroFluxDiags() end do + call site_in%flux_diags%ZeroFluxDiags() + ! This will be initialized in FatesSoilBGCFluxMod:PrepCH4BCs() ! It checks to see if the value is below -9000. If it is, ! it will assume the first value of the smoother is set @@ -960,6 +972,13 @@ subroutine init_patches( nsites, sites, bc_in) do el=1,num_elements call SiteMassStock(sites(s),el,sites(s)%mass_balance(el)%old_stock, & biomass_stock,litter_stock,seed_stock) + + ! Initialize the integrated flux balance diagnostics + ! No need to initialize the instantaneous states, those are re-calculated + sites(s)%iflux_balance(el)%iflux_liveveg = & + (biomass_stock + seed_stock)*area_inv + sites(s)%iflux_balance(el)%iflux_litter = litter_stock * area_inv + end do call set_patchno(sites(s)) diff --git a/main/EDMainMod.F90 b/main/EDMainMod.F90 index 6ea01d3618..e69d1e9bcb 100644 --- a/main/EDMainMod.F90 +++ b/main/EDMainMod.F90 @@ -91,6 +91,7 @@ module EDMainMod use DamageMainMod , only : IsItDamageTime use FatesGlobals , only : endrun => fates_endrun use ChecksBalancesMod , only : SiteMassStock + use ChecksBalancesMod , only : CheckIntegratedMassPools use EDMortalityFunctionsMod , only : Mortality_Derivative use EDTypesMod , only : AREA_INV use PRTGenericMod, only : carbon12_element @@ -101,7 +102,6 @@ module EDMainMod use PRTGenericMod, only : repro_organ use PRTGenericMod, only : struct_organ use PRTLossFluxesMod, only : PRTMaintTurnover - use PRTLossFluxesMod, only : PRTReproRelease use EDPftvarcon, only : EDPftvarcon_inst use FatesHistoryInterfaceMod, only : fates_hist @@ -163,9 +163,10 @@ subroutine ed_ecosystem_dynamics(currentSite, bc_in, bc_out) do el = 1,num_elements call currentSite%mass_balance(el)%ZeroMassBalFlux() - call currentSite%flux_diags(el)%ZeroFluxDiags() end do + call currentSite%flux_diags%ZeroFluxDiags() + ! Call a routine that simply identifies if logging should occur ! This is limited to a global event until more structured event handling is enabled call IsItLoggingTime(hlm_masterproc,currentSite) @@ -312,7 +313,11 @@ subroutine ed_ecosystem_dynamics(currentSite, bc_in, bc_out) call terminate_patches(currentSite, bc_in) end if + ! Final instantaneous mass balance check call TotalBalanceCheck(currentSite,5) + + + end subroutine ed_ecosystem_dynamics @@ -624,6 +629,11 @@ subroutine ed_integrate_state_variables(currentSite, bc_in, bc_out ) currentSite%mass_balance(element_pos(carbon12_element))%net_root_uptake = & currentSite%mass_balance(element_pos(carbon12_element))%net_root_uptake - & currentCohort%daily_c_efflux*currentCohort%n + + ! Save NPP diagnostic for flux accounting [kg/m2/day] + + currentSite%flux_diags%npp = currentSite%flux_diags%npp + & + (currentCohort%npp_acc_hold/hlm_days_per_year - currentCohort%resp_excess) * currentCohort%n * area_inv ! And simultaneously add the input fluxes to mass balance accounting site_cmass%gpp_acc = site_cmass%gpp_acc + & @@ -822,6 +832,9 @@ subroutine ed_update_site( currentSite, bc_in, bc_out, is_restarting ) currentPatch => currentPatch%younger enddo + + ! Check to see if the time integrated fluxes match the state + call CheckIntegratedMassPools(currentSite) ! The HLMs need to know about nutrient demand, and/or ! root mass and affinities diff --git a/main/EDTypesMod.F90 b/main/EDTypesMod.F90 index 10ef14734c..61878db1ef 100644 --- a/main/EDTypesMod.F90 +++ b/main/EDTypesMod.F90 @@ -151,7 +151,7 @@ module EDTypesMod ! ===================================================================================== - type, public :: site_fluxdiags_type + type, public :: elem_diag_type ! ---------------------------------------------------------------------------------- ! Diagnostics of fluxes @@ -159,25 +159,101 @@ module EDTypesMod ! file after number densities of plants have changed. They also ! allow the history flux diagnostics to be rebuilt during restart ! - ! ! Litter fluxes are the total from ! (1) turnover from living plants ! (2) mass transfer from non-disturbance inducing mortality events ! (3) mass transfer from disturbance inducing mortality events ! [kg / ha / day] ! --------------------------------------------------------------------------------- - + real(r8) :: cwd_ag_input(1:ncwd) real(r8) :: cwd_bg_input(1:ncwd) - real(r8),allocatable :: leaf_litter_input(:) + real(r8),allocatable :: surf_fine_litter_input(:) real(r8),allocatable :: root_litter_input(:) + real(r8) :: tot_seed_turnover ! decay of living seed bank to + ! fragmented litter [kg/m2/day] + real(r8) :: exported_harvest ! mass of harvested vegetation exported and not sent to litter [kg/m2/day] + real(r8) :: burned_liveveg ! Amount of mass burned from living plants [kg/m2/day] + + ! Integrated Error Terms ( Int. Flux - State ) + + real(r8) :: err_liveveg ! Error from comparing [state-integrated flux] + ! in live vegetation [kg/m2] + real(r8) :: err_litter ! Net change in litter [kg/m2] + + + end type elem_diag_type + + ! ------------------------------------------------------------------------- + + type, public :: site_ifluxbal_type + + ! The combination of living vegetation and litter accounts + ! for all of the mass that is tracked by FATES. We use these + ! data structures to ensure that an instantaneous assessment + ! of the mass of live vegetation and litter, is the same + ! as the initial condition plus the integrated fluxes in and + ! out of those pools over the duration of the simulation. + + ! Mass in living vegetation, this includes: + ! All organs on living plants, including non respiring tissues + ! and heartwood. + ! The live seed pool + + real(r8) :: state_liveveg ! Assessed instanteously [kg/m2] + real(r8) :: iflux_liveveg ! Integrated daily [kg/m2] + + ! Mass in all litter tracked by FATES + ! This includes only the unfragmented litter, litter that + ! has fragmented is tracked by the host models + + real(r8) :: state_litter ! Assessed instantaneously [kg/m2] + real(r8) :: iflux_litter ! Integrated daily [kg/m2] + + end type site_ifluxbal_type + + ! ------------------------------------------------------------------------- + + type, public :: site_fluxdiags_type + + + ! This is for all diagnostics that are uniform over all elements (C,N,P) + + type(elem_diag_type), pointer :: elem(:) + ! This variable is slated as to-do, but the fluxdiags type needs ! to be refactored first. Currently this type is allocated ! by chemical species (ie C, N or P). GPP is C, but not N or P (RGK 0524) ! Previous day GPP [kgC/m2/year], partitioned by size x pft !real(r8),allocatable :: gpp_prev_scpf(:) + + real(r8) :: npp ! kg m-2 day-1 + ! Nutrient Flux Diagnostics + + real(r8) :: resp_excess ! plant carbon respired due to carbon overflow + ! this happens when nutrients are limiting construction + ! of new tissues kg m-2 s-1 + real(r8) :: nh4_uptake ! plant nh4 uptake, kg m-2 s-1 + real(r8) :: no3_uptake ! plant no3 uptake, kg m-2 s-1 + real(r8) :: sym_nfix ! plant N uptake via symbiotic fixation kg m-2 s-1 + real(r8) :: n_efflux ! efflux of unusable N from plant to soil labile pool kg m-2 s-1 + real(r8) :: p_uptake ! po4 uptake, kg m-2 s-1 + real(r8) :: p_efflux ! efflux of unusable P from plant to soil labile pool kg m-2 s-1 + + ! Size by PFT delineated nutrient flux diagnostics (same units as above) + ! These are only allocated if both complex history diagnostics, and the + ! species of interest (N or P) is requested + + real(r8),allocatable :: nh4_uptake_scpf(:) + real(r8),allocatable :: no3_uptake_scpf(:) + real(r8),allocatable :: sym_nfix_scpf(:) + real(r8),allocatable :: n_efflux_scpf(:) + real(r8),allocatable :: p_uptake_scpf(:) + real(r8),allocatable :: p_efflux_scpf(:) + + contains @@ -310,13 +386,25 @@ module EDTypesMod real(r8), allocatable :: sp_tsai(:) ! target TSAI per FATES pft real(r8), allocatable :: sp_htop(:) ! target HTOP per FATES pft - ! Mass Balance (allocation for each element) + ! Instantaneous Mass Balance (allocation for each element) type(site_massbal_type), pointer :: mass_balance(:) - ! Flux diagnostics (allocation for each element) + ! Integrated Mass Balance checks, i.e. do the integrated + ! fluxes match the state? One is for live vegetation, + ! one if for litter - type(site_fluxdiags_type), pointer :: flux_diags(:) + type(site_ifluxbal_type), pointer :: iflux_balance(:) + + + ! Flux diagnostics + ! These are used to write history output based on fluxes + ! that are calculated before mortality and cohort/patch restructuring + ! but are written after patch structure. This structure also allows for + ! accurate restarting of the history + + type(site_fluxdiags_type) :: flux_diags + ! PHENOLOGY real(r8) :: grow_deg_days ! Phenology growing degree days @@ -490,19 +578,44 @@ module EDTypesMod subroutine ZeroFluxDiags(this) class(site_fluxdiags_type) :: this + integer :: el - this%cwd_ag_input(:) = 0._r8 - this%cwd_bg_input(:) = 0._r8 - this%leaf_litter_input(:) = 0._r8 - this%root_litter_input(:) = 0._r8 - - ! We don't zero gpp_prev_scpf because this is not - ! incremented like others, it is assigned at the end - ! of the daily history write process - + do el = 1,num_elements + this%elem(el)%cwd_ag_input(:) = 0._r8 + this%elem(el)%cwd_bg_input(:) = 0._r8 + this%elem(el)%surf_fine_litter_input(:) = 0._r8 + this%elem(el)%root_litter_input(:) = 0._r8 + this%elem(el)%burned_liveveg = 0._r8 + this%elem(el)%tot_seed_turnover = 0._r8 + this%elem(el)%exported_harvest = 0._r8 + this%elem(el)%err_liveveg = 0._r8 + this%elem(el)%err_litter = 0._r8 + + end do + + this%npp = 0._r8 + this%resp_excess = 0._r8 + this%nh4_uptake = 0._r8 + this%no3_uptake = 0._r8 + this%sym_nfix = 0._r8 + this%n_efflux = 0._r8 + this%p_uptake = 0._r8 + this%p_efflux = 0._r8 + + this%nh4_uptake_scpf(:) = 0._r8 + this%no3_uptake_scpf(:) = 0._r8 + this%sym_nfix_scpf(:) = 0._r8 + this%n_efflux_scpf(:) = 0._r8 + this%p_uptake_scpf(:) = 0._r8 + this%p_efflux_scpf(:) = 0._r8 - return - end subroutine ZeroFluxDiags + ! We don't zero gpp_prev_scpf because this is not + ! incremented like others, it is assigned at the end + ! of the daily history write process + + + return + end subroutine ZeroFluxDiags ! ===================================================================================== diff --git a/main/FatesHistoryInterfaceMod.F90 b/main/FatesHistoryInterfaceMod.F90 index 1f23c18951..739ea30503 100644 --- a/main/FatesHistoryInterfaceMod.F90 +++ b/main/FatesHistoryInterfaceMod.F90 @@ -23,6 +23,7 @@ module FatesHistoryInterfaceMod use PRTGenericMod , only : num_elements use PRTGenericMod , only : prt_cnp_flex_allom_hyp use EDTypesMod , only : site_fluxdiags_type + use EDTypesMod , only : elem_diag_type use EDtypesMod , only : ed_site_type use FatesCohortMod , only : fates_cohort_type use FatesPatchMod , only : fates_patch_type @@ -279,13 +280,13 @@ module FatesHistoryInterfaceMod integer :: ih_pefflux_si integer :: ih_nefflux_scpf integer :: ih_pefflux_scpf + integer :: ih_nfix_si + integer :: ih_nfix_scpf integer :: ih_ndemand_si integer :: ih_ndemand_scpf integer :: ih_pdemand_si integer :: ih_pdemand_scpf - integer :: ih_nfix_si - integer :: ih_nfix_scpf - + integer :: ih_trimming_si integer :: ih_area_plant_si integer :: ih_area_trees_si @@ -400,7 +401,8 @@ module FatesHistoryInterfaceMod integer :: ih_vis_rad_err_si integer :: ih_nir_rad_err_si integer :: ih_fire_c_to_atm_si - + integer :: ih_interr_liveveg_elem + integer :: ih_interr_litter_elem integer :: ih_cbal_err_fates_si integer :: ih_err_fates_elem @@ -2184,7 +2186,7 @@ subroutine update_history_nutrflux(this,csite) this%hvars(ih_ndemand_si)%r81d(io_si) = & this%hvars(ih_ndemand_si)%r81d(io_si) + & ccohort%daily_n_demand*uconv - + case (phosphorus_element) ! Mineralized uptake of PO4 @@ -2272,9 +2274,9 @@ subroutine update_history_nutrflux(this,csite) ! Demand this%hvars(ih_ndemand_scpf)%r82d(io_si,iscpf) = & - this%hvars(ih_ndemand_scpf)%r82d(io_si,iscpf) + & + this%hvars(ih_ndemand_scpf)%r82d(io_si,iscpf) + & ccohort%daily_n_demand*uconv - + case (phosphorus_element) ! Mineralized uptake of PO4 @@ -2286,12 +2288,12 @@ subroutine update_history_nutrflux(this,csite) this%hvars(ih_pefflux_scpf)%r82d(io_si,iscpf) = & this%hvars(ih_pefflux_scpf)%r82d(io_si,iscpf) + & ccohort%daily_p_efflux*uconv - + ! Demand this%hvars(ih_pdemand_scpf)%r82d(io_si,iscpf) = & this%hvars(ih_pdemand_scpf)%r82d(io_si,iscpf) + & ccohort%daily_p_demand*uconv - + end select end do @@ -2339,6 +2341,9 @@ subroutine update_history_dyn(this,nc,nsites,sites,bc_in) call update_history_dyn2(this,nc,nsites,sites,bc_in) end if end if + + + return end subroutine update_history_dyn @@ -2357,7 +2362,7 @@ subroutine update_history_dyn1(this,nc,nsites,sites,bc_in) type(fates_cohort_type), pointer :: ccohort type(fates_patch_type), pointer :: cpatch - type(site_fluxdiags_type), pointer :: flux_diags_c ! Pointer to site level carbon fluxes + type(elem_diag_type), pointer :: elflux_diags_c ! Pointer to site level carbon fluxes type(litter_type), pointer :: litt ! Generic pointer to any litter pool integer :: s ! site counter @@ -2487,6 +2492,8 @@ subroutine update_history_dyn1(this,nc,nsites,sites,bc_in) hio_cbal_err_fates_si(io_si) = & sites(s)%mass_balance(element_pos(carbon12_element))%err_fates / sec_per_day + + ! Total carbon lost to atmosphere from burning (kgC/site/day -> kgC/m2/s) hio_fire_c_to_atm_si(io_si) = & sites(s)%mass_balance(element_pos(carbon12_element))%burn_flux_to_atm * & @@ -2608,13 +2615,14 @@ subroutine update_history_dyn1(this,nc,nsites,sites,bc_in) sites(s)%fmort_crownarea_ustory + & sites(s)%term_crownarea_ustory * days_per_year + & sites(s)%imort_crownarea - - flux_diags_c => sites(s)%flux_diags(element_pos(carbon12_element)) - hio_litter_in_si(io_si) = (sum(flux_diags_c%cwd_ag_input(:)) + & - sum(flux_diags_c%cwd_bg_input(:)) + & - sum(flux_diags_c%leaf_litter_input(:)) + & - sum(flux_diags_c%root_litter_input(:))) * & + + elflux_diags_c => sites(s)%flux_diags%elem(element_pos(carbon12_element)) + + hio_litter_in_si(io_si) = (sum(elflux_diags_c%cwd_ag_input(:)) + & + sum(elflux_diags_c%cwd_bg_input(:)) + & + sum(elflux_diags_c%surf_fine_litter_input(:)) + & + sum(elflux_diags_c%root_litter_input(:))) * & AREA_INV * days_per_sec ! Loop through patches to sum up diagonistics @@ -3087,8 +3095,8 @@ subroutine update_history_dyn2(this,nc,nsites,sites,bc_in) integer :: i_dist, j_dist - type(site_fluxdiags_type), pointer :: flux_diags - type(site_fluxdiags_type), pointer :: flux_diags_c + type(elem_diag_type), pointer :: elflux_diags + type(elem_diag_type), pointer :: elflux_diags_c real(r8), parameter :: reallytalltrees = 1000. ! some large number (m) @@ -3307,8 +3315,11 @@ subroutine update_history_dyn2(this,nc,nsites,sites,bc_in) hio_nplant_understory_si_scag => this%hvars(ih_nplant_understory_si_scag)%r82d, & hio_disturbance_rate_si_lulu => this%hvars(ih_disturbance_rate_si_lulu)%r82d, & hio_cstarvmortality_continuous_carbonflux_si_pft => this%hvars(ih_cstarvmortality_continuous_carbonflux_si_pft)%r82d, & + hio_interr_liveveg_elem => this%hvars(ih_interr_liveveg_elem)%r82d, & + hio_interr_litter_elem => this%hvars(ih_interr_litter_elem)%r82d, & hio_transition_matrix_si_lulu => this%hvars(ih_transition_matrix_si_lulu)%r82d) + model_day_int = nint(hlm_model_day) ! --------------------------------------------------------------------------------- @@ -3355,6 +3366,10 @@ subroutine update_history_dyn2(this,nc,nsites,sites,bc_in) ! Total model error [kg/day -> kg/s] (all elements) hio_err_fates_elem(io_si,el) = sites(s)%mass_balance(el)%err_fates / sec_per_day + hio_interr_liveveg_elem(io_si,el) = sites(s)%flux_diags%elem(el)%err_liveveg + + hio_interr_litter_elem(io_si,el) = sites(s)%flux_diags%elem(el)%err_litter + ! Total element lost to atmosphere from burning (kg/site/day -> kg/m2/s) hio_burn_flux_elem(io_si,el) = & sites(s)%mass_balance(el)%burn_flux_to_atm * ha_per_m2 * & @@ -4052,7 +4067,7 @@ subroutine update_history_dyn2(this,nc,nsites,sites,bc_in) hio_bdead_md_canopy_si_scls(io_si,scls) = hio_bdead_md_canopy_si_scls(io_si,scls) + & struct_m_turnover * ccohort%n / m2_per_ha / days_per_year / sec_per_day hio_seed_prod_canopy_si_scls(io_si,scls) = hio_seed_prod_canopy_si_scls(io_si,scls) + & - ccohort%seed_prod * ccohort%n / m2_per_ha / days_per_year / sec_per_day + ccohort%seed_prod * ccohort%n / m2_per_ha / sec_per_day hio_npp_leaf_canopy_si_scls(io_si,scls) = hio_npp_leaf_canopy_si_scls(io_si,scls) + & leaf_m_net_alloc * ccohort%n / m2_per_ha / days_per_year / sec_per_day @@ -4189,7 +4204,7 @@ subroutine update_history_dyn2(this,nc,nsites,sites,bc_in) hio_bdead_md_understory_si_scls(io_si,scls) = hio_bdead_md_understory_si_scls(io_si,scls) + & struct_m_turnover * ccohort%n / m2_per_ha / days_per_year / sec_per_day hio_seed_prod_understory_si_scls(io_si,scls) = hio_seed_prod_understory_si_scls(io_si,scls) + & - ccohort%seed_prod * ccohort%n / m2_per_ha / days_per_year / sec_per_day + ccohort%seed_prod * ccohort%n / m2_per_ha / sec_per_day hio_npp_leaf_understory_si_scls(io_si,scls) = hio_npp_leaf_understory_si_scls(io_si,scls) + & leaf_m_net_alloc * ccohort%n / m2_per_ha / days_per_year / sec_per_day @@ -4582,7 +4597,7 @@ subroutine update_history_dyn2(this,nc,nsites,sites,bc_in) ! Some carbon only litter diagnostics (legacy) ! ------------------------------------------------------------------------------ - flux_diags_c => sites(s)%flux_diags(element_pos(carbon12_element)) + elflux_diags_c => sites(s)%flux_diags%elem(element_pos(carbon12_element)) ! ------------------------------------------------------------------------------ ! Diagnostics discretized by element type @@ -4590,12 +4605,12 @@ subroutine update_history_dyn2(this,nc,nsites,sites,bc_in) do el = 1, num_elements - flux_diags => sites(s)%flux_diags(el) + elflux_diags => sites(s)%flux_diags%elem(el) ! Sum up all input litter fluxes (above below, fines, cwd) [kg/ha/day] - hio_litter_in_elem(io_si, el) = (sum(flux_diags%cwd_ag_input(:)) + & - sum(flux_diags%cwd_bg_input(:)) + sum(flux_diags%leaf_litter_input(:)) + & - sum(flux_diags%root_litter_input(:))) / m2_per_ha / sec_per_day + hio_litter_in_elem(io_si, el) = (sum(elflux_diags%cwd_ag_input(:)) + & + sum(elflux_diags%cwd_bg_input(:)) + sum(elflux_diags%surf_fine_litter_input(:)) + & + sum(elflux_diags%root_litter_input(:))) / m2_per_ha / sec_per_day ! Plant multi-element states and fluxes @@ -4843,10 +4858,10 @@ subroutine update_history_dyn2(this,nc,nsites,sites,bc_in) do i_cwd = 1, ncwd hio_cwd_ag_in_si_cwdsc(io_si, i_cwd) = hio_cwd_ag_in_si_cwdsc(io_si, i_cwd) + & - flux_diags_c%cwd_ag_input(i_cwd) / days_per_year / sec_per_day + elflux_diags_c%cwd_ag_input(i_cwd) / days_per_year / sec_per_day hio_cwd_bg_in_si_cwdsc(io_si, i_cwd) = hio_cwd_bg_in_si_cwdsc(io_si, i_cwd) + & - flux_diags_c%cwd_bg_input(i_cwd) / days_per_year / sec_per_day + elflux_diags_c%cwd_bg_input(i_cwd) / days_per_year / sec_per_day end do @@ -6448,7 +6463,7 @@ subroutine define_history_vars(this, initialize_variables) use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_nflx_simple, ivar=ivar, initialize=initialize_variables, & index = ih_ndemand_si) - + call this%set_history_var(vname='FATES_NFIX_SYM', units='kg m-2 s-1', & long='symbiotic dinitrogen fixation in kg N per m2 per second', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & @@ -6551,6 +6566,7 @@ subroutine define_history_vars(this, initialize_variables) use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_nflx_simple, ivar=ivar, initialize=initialize_variables, & index = ih_pdemand_si) + end if phosphorus_active_if0 call this%set_history_var(vname='FATES_STRUCTC', units='kg m-2', & @@ -6718,6 +6734,8 @@ subroutine define_history_vars(this, initialize_variables) upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index = ih_cbal_err_fates_si) + + call this%set_history_var(vname='FATES_LEAF_ALLOC', units='kg m-2 s-1', & long='allocation to leaves in kg carbon per m2 per second', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & @@ -7207,7 +7225,7 @@ subroutine define_history_vars(this, initialize_variables) use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_nflx_complx, ivar=ivar, & initialize=initialize_variables, index = ih_ndemand_scpf) - + call this%set_history_var(vname='FATES_NFIX_SYM_SZPF', units='kg m-2 s-1', & long='symbiotic dinitrogen fixation, by size-class x pft in kg N per m2 per second', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & @@ -7332,13 +7350,13 @@ subroutine define_history_vars(this, initialize_variables) use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_nflx_complx, ivar=ivar, & initialize=initialize_variables, index = ih_pefflux_scpf) - + call this%set_history_var(vname='FATES_PDEMAND_SZPF', units='kg m-2 s-1', & long='plant P need (algorithm dependent), by size-class x pft in kg P per m2 per second', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_nflx_complx, ivar=ivar, & initialize=initialize_variables, index = ih_pdemand_scpf) - + end if phosphorus_active_if1 call this%set_history_var(vname='FATES_CROWNAREA_CLLL', units='m2 m-2', & @@ -8451,6 +8469,18 @@ subroutine define_history_vars(this, initialize_variables) hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_err_fates_elem) + call this%set_history_var(vname='FATES_INTERR_LIVEVEG_EL',units='kg m-2', & + long='Bias error between integrated flux and (minus) state in live vegetation ', & + use_default='active', avgflag='A', vtype=site_elem_r8, hlms='CLM:ALM', & + upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & + index = ih_interr_liveveg_elem) + + call this%set_history_var(vname='FATES_INTERR_LITTER_EL',units='kg m-2', & + long='Bias error between integrated flux and (minus) state in litter ', & + use_default='active', avgflag='A', vtype=site_elem_r8, hlms='CLM:ALM', & + upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & + index = ih_interr_litter_elem) + call this%set_history_var(vname='FATES_LITTER_AG_FINE_EL', units='kg m-2', & long='mass of aboveground litter in fines (leaves, nonviable seed) by element', & use_default='active', avgflag='A', vtype=site_elem_r8, & diff --git a/main/FatesRestartInterfaceMod.F90 b/main/FatesRestartInterfaceMod.F90 index 8e8ac61ee5..6236f4ef29 100644 --- a/main/FatesRestartInterfaceMod.F90 +++ b/main/FatesRestartInterfaceMod.F90 @@ -272,6 +272,10 @@ module FatesRestartInterfaceMod integer :: ir_rootlittin_flxdg integer :: ir_oldstock_mbal integer :: ir_errfates_mbal + integer :: ir_liveveg_intflux_el + integer :: ir_liveveg_err_el + integer :: ir_litter_intflux_el + integer :: ir_litter_err_el integer :: ir_woodprod_harvest_mbal integer :: ir_woodprod_landusechange_mbal integer :: ir_prt_base ! Base index for all PRT variables @@ -1059,6 +1063,7 @@ subroutine define_restart_vars(this, initialize_variables) ! Patch Level Litter Pools are potentially multi-element if(hlm_use_sp.eq.ifalse)then + call this%RegisterCohortVector(symbol_base='fates_ag_cwd', vtype=cohort_r8, & long_name_base='above ground CWD', & units='kg/m2', veclength=num_elements, flushval = flushzero, & @@ -1155,6 +1160,28 @@ subroutine define_restart_vars(this, initialize_variables) units='kg/ha', veclength=num_elements, flushval = flushzero, & hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_errfates_mbal) + + ! Time integrated mass balance accounting [kg/m2] + call this%RegisterCohortVector(symbol_base='fates_liveveg_intflux', vtype=site_r8, & + long_name_base='total mass of live vegetation of each chemical species, integrated from fluxes', & + units='kg/m2', veclength=num_elements, flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_liveveg_intflux_el) + + call this%RegisterCohortVector(symbol_base='fates_liveveg_err', vtype=site_r8, & + long_name_base='total mass error of live vegetation of each chemical species, from integrated fluxes', & + units='kg/m2', veclength=num_elements, flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_liveveg_err_el) + + call this%RegisterCohortVector(symbol_base='fates_litter_intflux', vtype=site_r8, & + long_name_base='total mass of litter of each chemical species, integrated from fluxes', & + units='kg/m2', veclength=num_elements, flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_litter_intflux_el) + + call this%RegisterCohortVector(symbol_base='fates_litter_err', vtype=site_r8, & + long_name_base='total mass error of litter of each chemical species, from integrated fluxes', & + units='kg/m2', veclength=num_elements, flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_litter_err_el) + end if call this%RegisterCohortVector(symbol_base='fates_woodprod_harv', vtype=cohort_r8, & @@ -2305,14 +2332,14 @@ subroutine set_restart_vectors(this,nc,nsites,sites) io_idx_si_scpf = io_idx_co_1st do i_cwd=1,ncwd - this%rvars(ir_cwdagin_flxdg+el-1)%r81d(io_idx_si_cwd) = sites(s)%flux_diags(el)%cwd_ag_input(i_cwd) - this%rvars(ir_cwdbgin_flxdg+el-1)%r81d(io_idx_si_cwd) = sites(s)%flux_diags(el)%cwd_bg_input(i_cwd) + this%rvars(ir_cwdagin_flxdg+el-1)%r81d(io_idx_si_cwd) = sites(s)%flux_diags%elem(el)%cwd_ag_input(i_cwd) + this%rvars(ir_cwdbgin_flxdg+el-1)%r81d(io_idx_si_cwd) = sites(s)%flux_diags%elem(el)%cwd_bg_input(i_cwd) io_idx_si_cwd = io_idx_si_cwd + 1 end do do i_pft=1,numpft - this%rvars(ir_leaflittin_flxdg+el-1)%r81d(io_idx_si_pft) = sites(s)%flux_diags(el)%leaf_litter_input(i_pft) - this%rvars(ir_rootlittin_flxdg+el-1)%r81d(io_idx_si_pft) = sites(s)%flux_diags(el)%root_litter_input(i_pft) + this%rvars(ir_leaflittin_flxdg+el-1)%r81d(io_idx_si_pft) = sites(s)%flux_diags%elem(el)%surf_fine_litter_input(i_pft) + this%rvars(ir_rootlittin_flxdg+el-1)%r81d(io_idx_si_pft) = sites(s)%flux_diags%elem(el)%root_litter_input(i_pft) this%rvars(ir_woodprod_harvest_mbal+el-1)%r81d(io_idx_si_pft) = sites(s)%mass_balance(el)%wood_product_harvest(i_pft) this%rvars(ir_woodprod_landusechange_mbal+el-1)%r81d(io_idx_si_pft) = sites(s)%mass_balance(el)%wood_product_landusechange(i_pft) io_idx_si_pft = io_idx_si_pft + 1 @@ -2321,6 +2348,12 @@ subroutine set_restart_vectors(this,nc,nsites,sites) this%rvars(ir_oldstock_mbal+el-1)%r81d(io_idx_si) = sites(s)%mass_balance(el)%old_stock this%rvars(ir_errfates_mbal+el-1)%r81d(io_idx_si) = sites(s)%mass_balance(el)%err_fates + this%rvars(ir_liveveg_intflux_el+el-1)%r81d(io_idx_si) = sites(s)%iflux_balance(el)%iflux_liveveg + this%rvars(ir_liveveg_err_el+el-1)%r81d(io_idx_si) = sites(s)%flux_diags%elem(el)%err_liveveg + + this%rvars(ir_litter_intflux_el+el-1)%r81d(io_idx_si) = sites(s)%iflux_balance(el)%iflux_litter + this%rvars(ir_litter_err_el+el-1)%r81d(io_idx_si) = sites(s)%flux_diags%elem(el)%err_litter + end do end if @@ -3288,14 +3321,14 @@ subroutine get_restart_vectors(this, nc, nsites, sites) io_idx_si_scpf = io_idx_co_1st do i_cwd=1,ncwd - sites(s)%flux_diags(el)%cwd_ag_input(i_cwd) = this%rvars(ir_cwdagin_flxdg+el-1)%r81d(io_idx_si_cwd) - sites(s)%flux_diags(el)%cwd_bg_input(i_cwd) = this%rvars(ir_cwdbgin_flxdg+el-1)%r81d(io_idx_si_cwd) + sites(s)%flux_diags%elem(el)%cwd_ag_input(i_cwd) = this%rvars(ir_cwdagin_flxdg+el-1)%r81d(io_idx_si_cwd) + sites(s)%flux_diags%elem(el)%cwd_bg_input(i_cwd) = this%rvars(ir_cwdbgin_flxdg+el-1)%r81d(io_idx_si_cwd) io_idx_si_cwd = io_idx_si_cwd + 1 end do do i_pft=1,numpft - sites(s)%flux_diags(el)%leaf_litter_input(i_pft) = this%rvars(ir_leaflittin_flxdg+el-1)%r81d(io_idx_si_pft) - sites(s)%flux_diags(el)%root_litter_input(i_pft) = this%rvars(ir_rootlittin_flxdg+el-1)%r81d(io_idx_si_pft) + sites(s)%flux_diags%elem(el)%surf_fine_litter_input(i_pft) = this%rvars(ir_leaflittin_flxdg+el-1)%r81d(io_idx_si_pft) + sites(s)%flux_diags%elem(el)%root_litter_input(i_pft) = this%rvars(ir_rootlittin_flxdg+el-1)%r81d(io_idx_si_pft) sites(s)%mass_balance(el)%wood_product_harvest(i_pft) = this%rvars(ir_woodprod_harvest_mbal+el-1)%r81d(io_idx_si_pft) sites(s)%mass_balance(el)%wood_product_landusechange(i_pft) = this%rvars(ir_woodprod_landusechange_mbal+el-1)%r81d(io_idx_si_pft) io_idx_si_pft = io_idx_si_pft + 1 @@ -3303,6 +3336,13 @@ subroutine get_restart_vectors(this, nc, nsites, sites) sites(s)%mass_balance(el)%old_stock = this%rvars(ir_oldstock_mbal+el-1)%r81d(io_idx_si) sites(s)%mass_balance(el)%err_fates = this%rvars(ir_errfates_mbal+el-1)%r81d(io_idx_si) + + sites(s)%iflux_balance(el)%iflux_liveveg = this%rvars(ir_liveveg_intflux_el+el-1)%r81d(io_idx_si) + sites(s)%flux_diags%elem(el)%err_liveveg = this%rvars(ir_liveveg_err_el+el-1)%r81d(io_idx_si) + + sites(s)%iflux_balance(el)%iflux_litter = this%rvars(ir_litter_intflux_el+el-1)%r81d(io_idx_si) + sites(s)%flux_diags%elem(el)%err_litter = this%rvars(ir_litter_err_el+el-1)%r81d(io_idx_si) + end do end if diff --git a/parameter_files/patch_default_bciopt224.xml b/parameter_files/patch_default_bciopt224.xml index b1ec419f64..73ab594ff8 100644 --- a/parameter_files/patch_default_bciopt224.xml +++ b/parameter_files/patch_default_bciopt224.xml @@ -2,7 +2,7 @@ This parameter dataset was created by Ryan Knox rgknox@lbl.gov. Please contact if using in published work. The calibration uses the following datasets: [1] Ely et al. 2019. Leaf mass area, Panama. NGEE-Tropics data collection.http://dx.doi.org/10.15486/ngt/1411973 and [2] Condit et al. 2019. Complete data from the Barro Colorado 50-ha plot. https://doi.org/10.15146/5xcp-0d46. [3] Koven et al. 2019. Benchmarking and parameter sensitivity of physiological and vegetation dynamics using the functionally assembled terrestrial ecosystem simulator. Biogeosciences. The ECA nutrient aquisition parmeters are unconstrained, the file output naming convention vmn6phi is shorthand for vmax for nitrogen uptake is order e-6 and for phosphorus is excessively high. These parameters were calibrated with the special fates modification in main/EDTypesMod.F90: nclmax = 3 fates_params_default.cdl - fates_params_opt224_092023_api26.cdl + fates_params_opt224_0424_api34.cdl 1