From d011b2a4744b5c8bd6e637cda25ec533ff6462a1 Mon Sep 17 00:00:00 2001 From: adamhb Date: Wed, 23 Jun 2021 13:01:11 -0700 Subject: [PATCH 01/81] testing git workflow; made a comment in PRTAllometricCarbonMod.F90 --- parteh/PRTAllometricCarbonMod.F90 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/parteh/PRTAllometricCarbonMod.F90 b/parteh/PRTAllometricCarbonMod.F90 index 5bdf624502..f0e3e87589 100644 --- a/parteh/PRTAllometricCarbonMod.F90 +++ b/parteh/PRTAllometricCarbonMod.F90 @@ -940,6 +940,8 @@ function AllomCGrowthDeriv(c_pools,c_mask,cbalance,intgr_params) result(dCdx) call bstore_allom(dbh,ipft,canopy_trim,ct_store,ct_dstoredd) ! fraction of carbon going towards reproduction + ! Adam will make changes to this section of code + if (dbh <= prt_params%dbh_repro_threshold(ipft)) then ! cap on leaf biomass repro_fraction = prt_params%seed_alloc(ipft) else From 474e5e505a4ef7e7a14829c2424e71aaf042e226 Mon Sep 17 00:00:00 2001 From: adamhb Date: Wed, 30 Jun 2021 12:31:49 -0700 Subject: [PATCH 02/81] made small change as a test, code is working --- parteh/PRTAllometricCarbonMod.F90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/parteh/PRTAllometricCarbonMod.F90 b/parteh/PRTAllometricCarbonMod.F90 index f0e3e87589..a4f3e495a2 100644 --- a/parteh/PRTAllometricCarbonMod.F90 +++ b/parteh/PRTAllometricCarbonMod.F90 @@ -940,10 +940,10 @@ function AllomCGrowthDeriv(c_pools,c_mask,cbalance,intgr_params) result(dCdx) call bstore_allom(dbh,ipft,canopy_trim,ct_store,ct_dstoredd) ! fraction of carbon going towards reproduction - ! Adam will make changes to this section of code + ! Adam has changed this section if (dbh <= prt_params%dbh_repro_threshold(ipft)) then ! cap on leaf biomass - repro_fraction = prt_params%seed_alloc(ipft) + repro_fraction = prt_params%seed_alloc(ipft) / 4.0_r8 ! ahb added / 4.0_r8 else repro_fraction = prt_params%seed_alloc(ipft) + prt_params%seed_alloc_mature(ipft) end if From 13d1e4b0b189efa953016895a29527bf24a742f5 Mon Sep 17 00:00:00 2001 From: adamhb Date: Wed, 30 Jun 2021 13:27:46 -0700 Subject: [PATCH 03/81] reproductive allocation working, no changes to param file yet --- parteh/PRTAllometricCarbonMod.F90 | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/parteh/PRTAllometricCarbonMod.F90 b/parteh/PRTAllometricCarbonMod.F90 index a4f3e495a2..a0cc4e6796 100644 --- a/parteh/PRTAllometricCarbonMod.F90 +++ b/parteh/PRTAllometricCarbonMod.F90 @@ -908,7 +908,7 @@ function AllomCGrowthDeriv(c_pools,c_mask,cbalance,intgr_params) result(dCdx) real(r8) :: ct_ddeaddd ! target structural biomass derivative wrt diameter, (kgC/cm) real(r8) :: ct_dtotaldd ! target total (not reproductive) biomass derivative wrt diameter, (kgC/cm) real(r8) :: repro_fraction ! fraction of carbon balance directed towards reproduction (kgC/kgC) - + real(r8), parameter :: repro_alloc_a = 0.0058, repro_alloc_b = -3.1380 !ahb added this 6/30/2021 associate( dbh => c_pools(dbh_id), & cleaf => c_pools(leaf_c_id), & @@ -942,11 +942,20 @@ function AllomCGrowthDeriv(c_pools,c_mask,cbalance,intgr_params) result(dCdx) ! fraction of carbon going towards reproduction ! Adam has changed this section - if (dbh <= prt_params%dbh_repro_threshold(ipft)) then ! cap on leaf biomass - repro_fraction = prt_params%seed_alloc(ipft) / 4.0_r8 ! ahb added / 4.0_r8 - else - repro_fraction = prt_params%seed_alloc(ipft) + prt_params%seed_alloc_mature(ipft) - end if + !original code + !-------------------------------------------------------------------------------------! + !if (dbh <= prt_params%dbh_repro_threshold(ipft)) then ! cap on leaf biomass + ! repro_fraction = prt_params%seed_alloc(ipft) + !else + ! repro_fraction = prt_params%seed_alloc(ipft) + prt_params%seed_alloc_mature(ipft) + !end if + !-------------------------------------------------------------------------------------! + + !new code + !-------------------------------------------------------------------------------------! + repro_fraction = prt_params%seed_alloc(ipft) * & + (exp(repro_alloc_b+repro_alloc_a*dbh*10.0_r8) / (1 + exp(repro_alloc_b+repro_alloc_a*dbh*10.0_r8))) + !-------------------------------------------------------------------------------------! dCdx = 0.0_r8 From be9180cc43606a74b0786ae4b88ed56d3c7888ba Mon Sep 17 00:00:00 2001 From: adamhb Date: Thu, 1 Jul 2021 12:26:50 -0700 Subject: [PATCH 04/81] added reproductive allocation function with new reproductive allocation parameters, passed ahb's tests successfully --- parteh/PRTAllometricCarbonMod.F90 | 9 +++++---- parteh/PRTParametersMod.F90 | 3 ++- parteh/PRTParamsFATESMod.F90 | 23 +++++++++++++++++++++++ 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/parteh/PRTAllometricCarbonMod.F90 b/parteh/PRTAllometricCarbonMod.F90 index a0cc4e6796..22f9bad601 100644 --- a/parteh/PRTAllometricCarbonMod.F90 +++ b/parteh/PRTAllometricCarbonMod.F90 @@ -908,7 +908,7 @@ function AllomCGrowthDeriv(c_pools,c_mask,cbalance,intgr_params) result(dCdx) real(r8) :: ct_ddeaddd ! target structural biomass derivative wrt diameter, (kgC/cm) real(r8) :: ct_dtotaldd ! target total (not reproductive) biomass derivative wrt diameter, (kgC/cm) real(r8) :: repro_fraction ! fraction of carbon balance directed towards reproduction (kgC/kgC) - real(r8), parameter :: repro_alloc_a = 0.0058, repro_alloc_b = -3.1380 !ahb added this 6/30/2021 + !real(r8), parameter :: repro_alloc_a = 0.0058, repro_alloc_b = -3.1380 !ahb added this 6/30/2021 associate( dbh => c_pools(dbh_id), & cleaf => c_pools(leaf_c_id), & @@ -940,7 +940,7 @@ function AllomCGrowthDeriv(c_pools,c_mask,cbalance,intgr_params) result(dCdx) call bstore_allom(dbh,ipft,canopy_trim,ct_store,ct_dstoredd) ! fraction of carbon going towards reproduction - ! Adam has changed this section + ! ahb changed this section !original code !-------------------------------------------------------------------------------------! @@ -951,10 +951,11 @@ function AllomCGrowthDeriv(c_pools,c_mask,cbalance,intgr_params) result(dCdx) !end if !-------------------------------------------------------------------------------------! - !new code + !new regeneration code (ahb) !-------------------------------------------------------------------------------------! repro_fraction = prt_params%seed_alloc(ipft) * & - (exp(repro_alloc_b+repro_alloc_a*dbh*10.0_r8) / (1 + exp(repro_alloc_b+repro_alloc_a*dbh*10.0_r8))) + (exp(prt_params%repro_alloc_b(ipft) + prt_params%repro_alloc_a(ipft)*dbh*10.0_r8) / & + (1 + exp(prt_params%repro_alloc_b(ipft) + prt_params%repro_alloc_b(ipft)*dbh*10.0_r8))) !-------------------------------------------------------------------------------------! dCdx = 0.0_r8 diff --git a/parteh/PRTParametersMod.F90 b/parteh/PRTParametersMod.F90 index 6e2c17ac66..200da09613 100644 --- a/parteh/PRTParametersMod.F90 +++ b/parteh/PRTParametersMod.F90 @@ -73,7 +73,8 @@ module PRTParametersMod real(r8), allocatable :: seed_alloc_mature(:) ! fraction of carbon balance allocated to ! clonal reproduction. real(r8), allocatable :: seed_alloc(:) ! fraction of carbon balance allocated to seeds. - + real(r8), allocatable :: repro_alloc_a(:) ! ahb added this; sigmoidal shape param relating dbh to seed allocation fraction + real(r8), allocatable :: repro_alloc_b(:) ! ahb added this; intercept param relating dbh to seed allocation fraction ! Derived parameters diff --git a/parteh/PRTParamsFATESMod.F90 b/parteh/PRTParamsFATESMod.F90 index 4442c090e8..1774900b85 100644 --- a/parteh/PRTParamsFATESMod.F90 +++ b/parteh/PRTParamsFATESMod.F90 @@ -223,6 +223,16 @@ subroutine PRTRegisterPFT(fates_params) call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) + !ahb added the params below + !------------------------------------------------------------------------------------- + name = 'fates_repro_alloc_a' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + + name = 'fates_repro_alloc_b' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + !-------------------------------------------------------------------------------------- name = 'fates_c2b' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) @@ -447,6 +457,17 @@ subroutine PRTReceivePFT(fates_params) call fates_params%RetreiveParameterAllocate(name=name, & data=prt_params%seed_alloc) + !ahb added the code below + !-------------------------------------------------------- + name = 'fates_repro_alloc_a' + call fates_params%RetreiveParameterAllocate(name=name, & + data=prt_params%repro_alloc_a) + + name = 'fates_repro_alloc_b' + call fates_params%RetreiveParameterAllocate(name=name, & + data=prt_params%repro_alloc_b) + !--------------------------------------------------------- + name = 'fates_c2b' call fates_params%RetreiveParameterAllocate(name=name, & data=prt_params%c2b) @@ -820,6 +841,8 @@ subroutine FatesReportPFTParams(is_master) write(fates_log(),fmt0) 'senleaf_long_fdrought = ',prt_params%senleaf_long_fdrought write(fates_log(),fmt0) 'seed_alloc_mature = ',prt_params%seed_alloc_mature write(fates_log(),fmt0) 'seed_alloc = ',prt_params%seed_alloc + write(fates_log(),fmt0) 'repro_alloc_a = ',prt_params%repro_alloc_a !ahb added this + write(fates_log(),fmt0) 'repro_alloc_b = ',prt_params%repro_alloc_b !ahb added this write(fates_log(),fmt0) 'slamax = ',prt_params%slamax write(fates_log(),fmt0) 'slatop = ',prt_params%slatop write(fates_log(),fmt0) 'allom_sai_scaler = ',prt_params%allom_sai_scaler From a35dfb2398821b82966b7246c096c0e9f8c78375 Mon Sep 17 00:00:00 2001 From: adamhb Date: Tue, 6 Jul 2021 12:56:16 -0700 Subject: [PATCH 05/81] made a hard coded test change to the germination function; this does affect the recruitment rates --- biogeochem/EDPhysiologyMod.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/biogeochem/EDPhysiologyMod.F90 b/biogeochem/EDPhysiologyMod.F90 index fe184dd343..5a3c37a902 100644 --- a/biogeochem/EDPhysiologyMod.F90 +++ b/biogeochem/EDPhysiologyMod.F90 @@ -1541,7 +1541,7 @@ subroutine SeedGermination( litt, cold_stat, drought_stat ) ! that times the ratio of (hypothetical) seed mass to recruit biomass do pft = 1,numpft - litt%seed_germ_in(pft) = min(litt%seed(pft) * EDPftvarcon_inst%germination_rate(pft), & + litt%seed_germ_in(pft) = min(litt%seed(pft) * EDPftvarcon_inst%germination_rate(pft) / 4.0_r8, & !ahb added / 4.0_r8 as a test max_germination)*years_per_day !set the germination only under the growing season...c.xu From bdda7251a367dd7333ab4253f225876d33b3851d Mon Sep 17 00:00:00 2001 From: adamhb Date: Wed, 7 Jul 2021 16:24:06 -0700 Subject: [PATCH 06/81] pre changing reproductive release parameter in Physiology mod; reproductive allocation is working --- main/FatesConstantsMod.F90 | 3 +++ parteh/PRTAllometricCarbonMod.F90 | 14 +++++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/main/FatesConstantsMod.F90 b/main/FatesConstantsMod.F90 index 7e19856aa2..2688f91fd1 100644 --- a/main/FatesConstantsMod.F90 +++ b/main/FatesConstantsMod.F90 @@ -141,6 +141,9 @@ module FatesConstantsMod ! Conversion factor: milimeters per meter real(fates_r8), parameter, public :: mm_per_m = 1.0E3_fates_r8 + ! Conversion factor: milimeters per centimeter ahb added this 7/7/2021 + ! read(fates_r8), parameter, public :: mm_per_cm = 1.0E1_fates_r8 + ! Conversion factor: m2 per ha real(fates_r8), parameter, public :: m2_per_ha = 1.0e4_fates_r8 diff --git a/parteh/PRTAllometricCarbonMod.F90 b/parteh/PRTAllometricCarbonMod.F90 index 22f9bad601..3d39a207cb 100644 --- a/parteh/PRTAllometricCarbonMod.F90 +++ b/parteh/PRTAllometricCarbonMod.F90 @@ -42,6 +42,7 @@ module PRTAllometricCarbonMod use FatesConstantsMod , only : r8 => fates_r8 use FatesConstantsMod , only : i4 => fates_int use FatesConstantsMod , only : sec_per_day + !use FatesConstantsMod , only : mm_per_cm !ahb added this 7/7/2021 use FatesIntegratorsMod , only : RKF45 use FatesIntegratorsMod , only : Euler use FatesConstantsMod , only : calloc_abs_error @@ -908,7 +909,7 @@ function AllomCGrowthDeriv(c_pools,c_mask,cbalance,intgr_params) result(dCdx) real(r8) :: ct_ddeaddd ! target structural biomass derivative wrt diameter, (kgC/cm) real(r8) :: ct_dtotaldd ! target total (not reproductive) biomass derivative wrt diameter, (kgC/cm) real(r8) :: repro_fraction ! fraction of carbon balance directed towards reproduction (kgC/kgC) - !real(r8), parameter :: repro_alloc_a = 0.0058, repro_alloc_b = -3.1380 !ahb added this 6/30/2021 + real(r8), parameter :: mm_per_cm = 10.0_r8 !ahb added this; this is temporary. Need to add this to the FATES constants file associate( dbh => c_pools(dbh_id), & cleaf => c_pools(leaf_c_id), & @@ -940,7 +941,8 @@ function AllomCGrowthDeriv(c_pools,c_mask,cbalance,intgr_params) result(dCdx) call bstore_allom(dbh,ipft,canopy_trim,ct_store,ct_dstoredd) ! fraction of carbon going towards reproduction - ! ahb changed this section + + !START ahb's changes !original code !-------------------------------------------------------------------------------------! @@ -951,13 +953,15 @@ function AllomCGrowthDeriv(c_pools,c_mask,cbalance,intgr_params) result(dCdx) !end if !-------------------------------------------------------------------------------------! - !new regeneration code (ahb) + !new regeneration code (ahb, July 2021) !-------------------------------------------------------------------------------------! repro_fraction = prt_params%seed_alloc(ipft) * & - (exp(prt_params%repro_alloc_b(ipft) + prt_params%repro_alloc_a(ipft)*dbh*10.0_r8) / & - (1 + exp(prt_params%repro_alloc_b(ipft) + prt_params%repro_alloc_b(ipft)*dbh*10.0_r8))) + (exp(prt_params%repro_alloc_b(ipft) + prt_params%repro_alloc_a(ipft)*dbh*mm_per_cm) / & + (1 + exp(prt_params%repro_alloc_b(ipft) + prt_params%repro_alloc_b(ipft)*dbh*mm_per_cm))) !-------------------------------------------------------------------------------------! + !END ahb's changes + dCdx = 0.0_r8 ct_dtotaldd = ct_ddeaddd From a993ccccfb406107a811dac8d6dafc21cec09fa9 Mon Sep 17 00:00:00 2001 From: adamhb Date: Thu, 8 Jul 2021 18:26:54 -0700 Subject: [PATCH 07/81] all changes to non-seed reproductive allocation commented out; model working. added new litter pool for non-seed reproductive allocation, but I don't use them. I have to delete code that creates this new litter pool if I don't end up using it --- biogeochem/EDPatchDynamicsMod.F90 | 3 ++ biogeochem/EDPhysiologyMod.F90 | 36 +++++++++++++++++++++--- biogeochem/FatesLitterMod.F90 | 8 ++++++ biogeochem/FatesSoilBGCFluxMod.F90 | 44 +++++++++++++++++++++--------- main/FatesConstantsMod.F90 | 4 +-- parteh/PRTAllometricCarbonMod.F90 | 3 +- 6 files changed, 77 insertions(+), 21 deletions(-) diff --git a/biogeochem/EDPatchDynamicsMod.F90 b/biogeochem/EDPatchDynamicsMod.F90 index 60716b23dd..34a38555b4 100644 --- a/biogeochem/EDPatchDynamicsMod.F90 +++ b/biogeochem/EDPatchDynamicsMod.F90 @@ -1392,6 +1392,9 @@ subroutine TransLitterNewPatch(currentSite, & new_litt%seed_decay(pft) = new_litt%seed_decay(pft) + & curr_litt%seed_decay(pft)*patch_site_areadis/newPatch%area + new_litt%non_seed_repro_mass_decay(pft) = new_litt%non_seed_repro_mass_decay(pft) + & !ahb added this + curr_litt%non_seed_repro_mass_decay(pft)*patch_site_areadis/newPatch%area !ahb added this + new_litt%seed_germ_decay(pft) = new_litt%seed_germ_decay(pft) + & curr_litt%seed_germ_decay(pft)*patch_site_areadis/newPatch%area diff --git a/biogeochem/EDPhysiologyMod.F90 b/biogeochem/EDPhysiologyMod.F90 index 5a3c37a902..794a44fd20 100644 --- a/biogeochem/EDPhysiologyMod.F90 +++ b/biogeochem/EDPhysiologyMod.F90 @@ -252,6 +252,7 @@ subroutine PreDisturbanceLitterFluxes( currentSite, currentPatch, bc_in ) 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%non_seed_repro_mass_decay) + & !ahb added this line on 7/8/2021 sum(litt%seed_decay) + sum(litt%seed_germ_decay)) end do @@ -1365,6 +1366,7 @@ subroutine SeedIn( currentSite, bc_in ) real(r8) :: site_seed_rain(maxpft) ! This is the sum of seed-rain for the site [kg/site/day] real(r8) :: seed_in_external ! Mass of externally generated seeds [kg/m2/day] real(r8) :: seed_stoich ! Mass ratio of nutrient per C12 in seeds [kg/kg] + real(r8) :: repro_mass_prod ! Mass of reproductive material produced [kg/day] ; added by ahb 7/8/2021 real(r8) :: seed_prod ! Seed produced in this dynamics step [kg/day] integer :: n_litt_types ! number of litter element types (c,n,p, etc) integer :: el ! loop counter for litter element types @@ -1403,9 +1405,35 @@ subroutine SeedIn( currentSite, bc_in ) ! specified as input. This routine will also remove the mass ! from the parteh state-variable. - call PRTReproRelease(currentCohort%prt,repro_organ,element_id, & - 1.0_r8, seed_prod) + !START ahb changes + !-------------------------------------------------------------------------- + !original code + !call PRTReproRelease(currentCohort%prt,repro_organ,element_id, & + ! 1.0_r8, seed_prod) + !-------------------------------------------------------------------------- + + !-------------------------------------------------------------------------- + !ahb's new code + !the original code sends all reproductive tissue to seed + !This new code, added by ahb, is designed to send some reproductive biomass + !straight to the leaf litter pool to account for non-seed reproductive + !biomass. For now, ahb does this after the call to the + !PRTReproRelease function, but a better solution would probably be to do + !this within the PRTReproRelease module in parteh/PRTLossFluxesMod.F90::L342 + !by adding new live reproductive organs (ahb needs help with this). + + call PRTReproRelease(currentCohort%prt,repro_organ,element_id, & + 1.0_r8, repro_mass_prod) !ahb changed from seed_prod to repro_mass_prod + + seed_prod = repro_mass_prod ! * 0.5_r8 ! only a fraction of reproductive carbon is seed (ahb) + + ! the remainder goes to non-seed reproductive litter + !litt%non_seed_repro_mass_decay(pft) = repro_mass_prod * (1.0_r8 - 0.5_r8) ! ahb + !--------------------------------------------------------------------------- + + !END ahb changes + if(element_id==carbon12_element)then currentcohort%seed_prod = seed_prod end if @@ -1496,7 +1524,7 @@ subroutine SeedDecay( litt ) ! Assume that decay rates are same for all chemical species do pft = 1,numpft - litt%seed_decay(pft) = litt%seed(pft) * & + litt%seed_decay(pft) = litt%seed(pft) * & EDPftvarcon_inst%seed_decay_rate(pft)*years_per_day litt%seed_germ_decay(pft) = litt%seed_germ(pft) * & @@ -1541,7 +1569,7 @@ subroutine SeedGermination( litt, cold_stat, drought_stat ) ! that times the ratio of (hypothetical) seed mass to recruit biomass do pft = 1,numpft - litt%seed_germ_in(pft) = min(litt%seed(pft) * EDPftvarcon_inst%germination_rate(pft) / 4.0_r8, & !ahb added / 4.0_r8 as a test + litt%seed_germ_in(pft) = min(litt%seed(pft) * EDPftvarcon_inst%germination_rate(pft), & max_germination)*years_per_day !set the germination only under the growing season...c.xu diff --git a/biogeochem/FatesLitterMod.F90 b/biogeochem/FatesLitterMod.F90 index be5ec48aa9..dbcf05a9d4 100644 --- a/biogeochem/FatesLitterMod.F90 +++ b/biogeochem/FatesLitterMod.F90 @@ -105,6 +105,7 @@ module FatesLitterMod real(r8),allocatable :: root_fines_frag(:,:) ! kg/m2/day real(r8), allocatable :: seed_decay(:) ! decay of viable seeds to litter [kg/m2/day] + real(r8), allocatable :: non_seed_repro_mass_decay(:) ! ahb, decay of non-seed reproductive mass [kg/m2/day] real(r8), allocatable :: seed_germ_decay(:) ! decay of germinated seeds to litter [kg/m2/day] real(r8), allocatable :: seed_germ_in(:) ! flux from viable to germinated seed [kg/m2/day] @@ -193,6 +194,8 @@ subroutine FuseLitter(this,self_area,donor_area,donor_litt) this%seed_decay(pft) = this%seed_decay(pft) * self_weight + & donor_litt%seed_decay(pft) * donor_weight + this%non_seed_repro_mass_decay(pft) = this%non_seed_repro_mass_decay(pft) * self_weight + & !ahb + donor_litt%non_seed_repro_mass_decay(pft) * donor_weight !ahb this%seed_germ_decay(pft) = this%seed_germ_decay(pft) * self_weight + & donor_litt%seed_germ_decay(pft) * donor_weight this%seed_germ_in(pft) = this%seed_germ_in(pft) * self_weight + & @@ -252,6 +255,7 @@ subroutine CopyLitter(this,donor_litt) this%leaf_fines_frag(:) = donor_litt%leaf_fines_frag(:) this%seed_decay(:) = donor_litt%seed_decay(:) + this%non_seed_repro_mass_decay(:) = donor_litt%non_seed_repro_mass_decay(:) !ahb this%seed_germ_decay(:) = donor_litt%seed_germ_decay(:) this%seed_germ_in(:) = donor_litt%seed_germ_in(:) this%root_fines(:,:) = donor_litt%root_fines(:,:) @@ -289,6 +293,7 @@ subroutine InitAllocate(this,numpft,numlevsoil,element_id) allocate(this%seed_germ(numpft)) allocate(this%seed_germ_in(numpft)) allocate(this%seed_germ_decay(numpft)) + allocate(this%non_seed_repro_mass_decay(numpft)) !ahb allocate(this%seed_decay(numpft)) ! Initialize everything to a nonsense flag @@ -312,6 +317,7 @@ subroutine InitAllocate(this,numpft,numlevsoil,element_id) this%root_fines_frag(:,:) = fates_unset_r8 this%seed_decay(:) = fates_unset_r8 + this%non_seed_repro_mass_decay(:) = fates_unset_r8 !ahb this%seed_germ_decay(:) = fates_unset_r8 this%seed_germ_in(:) = fates_unset_r8 @@ -376,6 +382,7 @@ subroutine DeallocateLitt(this) deallocate(this%root_fines_frag) deallocate(this%seed_decay) + deallocate(this%non_seed_repro_mass_decay) deallocate(this%seed_germ_decay) deallocate(this%seed_germ_in) @@ -402,6 +409,7 @@ subroutine ZeroFlux(this) this%seed_germ_in(:) = 0._r8 this%seed_decay(:) = 0._r8 + this%non_seed_repro_mass_decay = 0._r8 this%seed_germ_decay(:) = 0._r8 diff --git a/biogeochem/FatesSoilBGCFluxMod.F90 b/biogeochem/FatesSoilBGCFluxMod.F90 index a8d535e114..50e379aa45 100644 --- a/biogeochem/FatesSoilBGCFluxMod.F90 +++ b/biogeochem/FatesSoilBGCFluxMod.F90 @@ -1099,21 +1099,39 @@ subroutine FluxIntoLitterPools(csite, bc_in, bc_out) ! decaying seeds from the litter pool do ipft = 1,numpft do id = 1,nlev_eff_decomp - - flux_lab_si(id) = flux_lab_si(id) + & - (litt%seed_decay(ipft) + litt%seed_germ_decay(ipft)) * & - EDPftvarcon_inst%lf_flab(ipft) * area_frac* surface_prof(id) - - flux_cel_si(id) = flux_cel_si(id) + & - (litt%seed_decay(ipft) + litt%seed_germ_decay(ipft)) * & - EDPftvarcon_inst%lf_fcel(ipft) * area_frac* surface_prof(id) - - flux_lig_si(id) = flux_lig_si(id) + & - (litt%seed_decay(ipft) + litt%seed_germ_decay(ipft)) * & - EDPftvarcon_inst%lf_flig(ipft) * area_frac* surface_prof(id) + !ahb START + !original code + !------------------------------------------------------------------------ + ! flux_lab_si(id) = flux_lab_si(id) + & + ! (litt%seed_decay(ipft) + litt%seed_germ_decay(ipft)) * & + ! EDPftvarcon_inst%lf_flab(ipft) * area_frac* surface_prof(id) + + ! flux_cel_si(id) = flux_cel_si(id) + & + ! (litt%seed_decay(ipft) + litt%seed_germ_decay(ipft)) * & + ! EDPftvarcon_inst%lf_fcel(ipft) * area_frac* surface_prof(id) + + ! flux_lig_si(id) = flux_lig_si(id) + & + ! (litt%seed_decay(ipft) + litt%seed_germ_decay(ipft)) * & + ! EDPftvarcon_inst%lf_flig(ipft) * area_frac* surface_prof(id) + !------------------------------------------------------------------------- + + !new code + !------------------------------------------------------------------------- + flux_lab_si(id) = flux_lab_si(id) + & + (litt%seed_decay(ipft) + litt%seed_germ_decay(ipft) + litt%non_seed_repro_mass_decay(ipft)) * & + EDPftvarcon_inst%lf_flab(ipft) * area_frac* surface_prof(id) + + flux_cel_si(id) = flux_cel_si(id) + & + (litt%seed_decay(ipft) + litt%seed_germ_decay(ipft) + litt%non_seed_repro_mass_decay(ipft)) * & + EDPftvarcon_inst%lf_fcel(ipft) * area_frac* surface_prof(id) + + flux_lig_si(id) = flux_lig_si(id) + & + (litt%seed_decay(ipft) + litt%seed_germ_decay(ipft) + litt%non_seed_repro_mass_decay(ipft)) * & + EDPftvarcon_inst%lf_flig(ipft) * area_frac* surface_prof(id) + !------------------------------------------------------------------------- end do end do - + !END ahb mods do j = 1, nlev_eff_soil diff --git a/main/FatesConstantsMod.F90 b/main/FatesConstantsMod.F90 index 2688f91fd1..06eafc3d5c 100644 --- a/main/FatesConstantsMod.F90 +++ b/main/FatesConstantsMod.F90 @@ -141,8 +141,8 @@ module FatesConstantsMod ! Conversion factor: milimeters per meter real(fates_r8), parameter, public :: mm_per_m = 1.0E3_fates_r8 - ! Conversion factor: milimeters per centimeter ahb added this 7/7/2021 - ! read(fates_r8), parameter, public :: mm_per_cm = 1.0E1_fates_r8 + ! Conversion factor: millimeters per centimeter (ahb added this 7/7/2021) + real(fates_r8), parameter, public :: mm_per_cm = 10.0_fates_r8 ! Conversion factor: m2 per ha real(fates_r8), parameter, public :: m2_per_ha = 1.0e4_fates_r8 diff --git a/parteh/PRTAllometricCarbonMod.F90 b/parteh/PRTAllometricCarbonMod.F90 index 3d39a207cb..7ade02af5c 100644 --- a/parteh/PRTAllometricCarbonMod.F90 +++ b/parteh/PRTAllometricCarbonMod.F90 @@ -42,7 +42,7 @@ module PRTAllometricCarbonMod use FatesConstantsMod , only : r8 => fates_r8 use FatesConstantsMod , only : i4 => fates_int use FatesConstantsMod , only : sec_per_day - !use FatesConstantsMod , only : mm_per_cm !ahb added this 7/7/2021 + use FatesConstantsMod , only : mm_per_cm !ahb added this 7/7/2021 use FatesIntegratorsMod , only : RKF45 use FatesIntegratorsMod , only : Euler use FatesConstantsMod , only : calloc_abs_error @@ -909,7 +909,6 @@ function AllomCGrowthDeriv(c_pools,c_mask,cbalance,intgr_params) result(dCdx) real(r8) :: ct_ddeaddd ! target structural biomass derivative wrt diameter, (kgC/cm) real(r8) :: ct_dtotaldd ! target total (not reproductive) biomass derivative wrt diameter, (kgC/cm) real(r8) :: repro_fraction ! fraction of carbon balance directed towards reproduction (kgC/kgC) - real(r8), parameter :: mm_per_cm = 10.0_r8 !ahb added this; this is temporary. Need to add this to the FATES constants file associate( dbh => c_pools(dbh_id), & cleaf => c_pools(leaf_c_id), & From 2e287ce9543284bd46ea183c2991037dd1af354d Mon Sep 17 00:00:00 2001 From: adamhb Date: Fri, 9 Jul 2021 09:44:09 -0700 Subject: [PATCH 08/81] model working well, before changes to non-seed reproductive carbon --- biogeochem/EDPhysiologyMod.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/biogeochem/EDPhysiologyMod.F90 b/biogeochem/EDPhysiologyMod.F90 index 794a44fd20..a06ac4a25a 100644 --- a/biogeochem/EDPhysiologyMod.F90 +++ b/biogeochem/EDPhysiologyMod.F90 @@ -1426,7 +1426,7 @@ subroutine SeedIn( currentSite, bc_in ) call PRTReproRelease(currentCohort%prt,repro_organ,element_id, & 1.0_r8, repro_mass_prod) !ahb changed from seed_prod to repro_mass_prod - seed_prod = repro_mass_prod ! * 0.5_r8 ! only a fraction of reproductive carbon is seed (ahb) + seed_prod = repro_mass_prod ! only a fraction of reproductive carbon is seed (ahb) ! the remainder goes to non-seed reproductive litter !litt%non_seed_repro_mass_decay(pft) = repro_mass_prod * (1.0_r8 - 0.5_r8) ! ahb From cb85933af7578490038d8a83cc700f556968ae2d Mon Sep 17 00:00:00 2001 From: adamhb Date: Fri, 9 Jul 2021 10:04:06 -0700 Subject: [PATCH 09/81] added the reference to the reproductive allocation function --- parteh/PRTAllometricCarbonMod.F90 | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/parteh/PRTAllometricCarbonMod.F90 b/parteh/PRTAllometricCarbonMod.F90 index 7ade02af5c..87ec4769c7 100644 --- a/parteh/PRTAllometricCarbonMod.F90 +++ b/parteh/PRTAllometricCarbonMod.F90 @@ -944,15 +944,23 @@ function AllomCGrowthDeriv(c_pools,c_mask,cbalance,intgr_params) result(dCdx) !START ahb's changes !original code - !-------------------------------------------------------------------------------------! + !------------------------------------------------------------------------------------- !if (dbh <= prt_params%dbh_repro_threshold(ipft)) then ! cap on leaf biomass ! repro_fraction = prt_params%seed_alloc(ipft) !else ! repro_fraction = prt_params%seed_alloc(ipft) + prt_params%seed_alloc_mature(ipft) !end if - !-------------------------------------------------------------------------------------! - - !new regeneration code (ahb, July 2021) + !------------------------------------------------------------------------------------- + + !new code + !------------------------------------------------------------------------------------- + !This reproductive allocation function calculates the fraction of available carbon + !allocated to reproductive tissue based on a cohort's size. This function is based on + !empirical data and analysis at BCI (Visser et al., 2016). + + !Visser MD, Bruijning M, Wright SJ, Muller-Landau HC, Jongejans E, Comita LS, + !de Kroon H. 2016. Functional traits as predictors of vital rates across the life cycle + !of tropical trees. Functional Ecology 30: 168–180. !-------------------------------------------------------------------------------------! repro_fraction = prt_params%seed_alloc(ipft) * & (exp(prt_params%repro_alloc_b(ipft) + prt_params%repro_alloc_a(ipft)*dbh*mm_per_cm) / & From e53f03b82c470a28d117acd0beffcb372d619638 Mon Sep 17 00:00:00 2001 From: adamhb Date: Fri, 9 Jul 2021 14:11:33 -0700 Subject: [PATCH 10/81] removed my changes to the biogeochem/FatesSoilBGCFluxMod.F90 module --- biogeochem/FatesSoilBGCFluxMod.F90 | 42 ++++++++---------------------- 1 file changed, 11 insertions(+), 31 deletions(-) diff --git a/biogeochem/FatesSoilBGCFluxMod.F90 b/biogeochem/FatesSoilBGCFluxMod.F90 index 50e379aa45..d37cce013e 100644 --- a/biogeochem/FatesSoilBGCFluxMod.F90 +++ b/biogeochem/FatesSoilBGCFluxMod.F90 @@ -1099,39 +1099,19 @@ subroutine FluxIntoLitterPools(csite, bc_in, bc_out) ! decaying seeds from the litter pool do ipft = 1,numpft do id = 1,nlev_eff_decomp - !ahb START - !original code - !------------------------------------------------------------------------ - ! flux_lab_si(id) = flux_lab_si(id) + & - ! (litt%seed_decay(ipft) + litt%seed_germ_decay(ipft)) * & - ! EDPftvarcon_inst%lf_flab(ipft) * area_frac* surface_prof(id) - - ! flux_cel_si(id) = flux_cel_si(id) + & - ! (litt%seed_decay(ipft) + litt%seed_germ_decay(ipft)) * & - ! EDPftvarcon_inst%lf_fcel(ipft) * area_frac* surface_prof(id) - - ! flux_lig_si(id) = flux_lig_si(id) + & - ! (litt%seed_decay(ipft) + litt%seed_germ_decay(ipft)) * & - ! EDPftvarcon_inst%lf_flig(ipft) * area_frac* surface_prof(id) - !------------------------------------------------------------------------- - - !new code - !------------------------------------------------------------------------- - flux_lab_si(id) = flux_lab_si(id) + & - (litt%seed_decay(ipft) + litt%seed_germ_decay(ipft) + litt%non_seed_repro_mass_decay(ipft)) * & - EDPftvarcon_inst%lf_flab(ipft) * area_frac* surface_prof(id) - - flux_cel_si(id) = flux_cel_si(id) + & - (litt%seed_decay(ipft) + litt%seed_germ_decay(ipft) + litt%non_seed_repro_mass_decay(ipft)) * & - EDPftvarcon_inst%lf_fcel(ipft) * area_frac* surface_prof(id) - - flux_lig_si(id) = flux_lig_si(id) + & - (litt%seed_decay(ipft) + litt%seed_germ_decay(ipft) + litt%non_seed_repro_mass_decay(ipft)) * & - EDPftvarcon_inst%lf_flig(ipft) * area_frac* surface_prof(id) - !------------------------------------------------------------------------- + flux_lab_si(id) = flux_lab_si(id) + & + (litt%seed_decay(ipft) + litt%seed_germ_decay(ipft)) * & + EDPftvarcon_inst%lf_flab(ipft) * area_frac* surface_prof(id) + + flux_cel_si(id) = flux_cel_si(id) + & + (litt%seed_decay(ipft) + litt%seed_germ_decay(ipft)) * & + EDPftvarcon_inst%lf_fcel(ipft) * area_frac* surface_prof(id) + + flux_lig_si(id) = flux_lig_si(id) + & + (litt%seed_decay(ipft) + litt%seed_germ_decay(ipft)) * & + EDPftvarcon_inst%lf_flig(ipft) * area_frac* surface_prof(id) end do end do - !END ahb mods do j = 1, nlev_eff_soil From 8e5373248e34bd24e375fc513465a44297226a45 Mon Sep 17 00:00:00 2001 From: adamhb Date: Tue, 13 Jul 2021 13:36:22 -0700 Subject: [PATCH 11/81] model working --- biogeochem/EDPhysiologyMod.F90 | 38 ++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/biogeochem/EDPhysiologyMod.F90 b/biogeochem/EDPhysiologyMod.F90 index a06ac4a25a..ed7c98ddc6 100644 --- a/biogeochem/EDPhysiologyMod.F90 +++ b/biogeochem/EDPhysiologyMod.F90 @@ -1367,7 +1367,9 @@ subroutine SeedIn( currentSite, bc_in ) real(r8) :: seed_in_external ! Mass of externally generated seeds [kg/m2/day] real(r8) :: seed_stoich ! Mass ratio of nutrient per C12 in seeds [kg/kg] real(r8) :: repro_mass_prod ! Mass of reproductive material produced [kg/day] ; added by ahb 7/8/2021 + !real(r8), parameter :: repro_frac_seed = 0.5 !added by ahb 7/12/2021 real(r8) :: seed_prod ! Seed produced in this dynamics step [kg/day] + real(r8) :: non_seed_repro_prod ! Mass of non-seed reproductive material produced [kg/day] ; added by ahb 7/10/2021 integer :: n_litt_types ! number of litter element types (c,n,p, etc) integer :: el ! loop counter for litter element types integer :: element_id ! element id consistent with parteh/PRTGenericMod.F90 @@ -1386,6 +1388,7 @@ subroutine SeedIn( currentSite, bc_in ) do while (associated(currentPatch)) currentCohort => currentPatch%tallest + !litt => currentPatch%litter(el) !added by ahb do while (associated(currentCohort)) pft = currentCohort%pft @@ -1405,12 +1408,16 @@ subroutine SeedIn( currentSite, bc_in ) ! specified as input. This routine will also remove the mass ! from the parteh state-variable. + + + + !START ahb changes !-------------------------------------------------------------------------- !original code - !call PRTReproRelease(currentCohort%prt,repro_organ,element_id, & - ! 1.0_r8, seed_prod) + call PRTReproRelease(currentCohort%prt,repro_organ,element_id, & + 1.0_r8, seed_prod) !-------------------------------------------------------------------------- !-------------------------------------------------------------------------- @@ -1423,23 +1430,31 @@ subroutine SeedIn( currentSite, bc_in ) !this within the PRTReproRelease module in parteh/PRTLossFluxesMod.F90::L342 !by adding new live reproductive organs (ahb needs help with this). - call PRTReproRelease(currentCohort%prt,repro_organ,element_id, & - 1.0_r8, repro_mass_prod) !ahb changed from seed_prod to repro_mass_prod + !call PRTReproRelease(currentCohort%prt,repro_organ,element_id, & + ! 1.0_r8, repro_mass_prod) !ahb changed from seed_prod to repro_mass_prod - seed_prod = repro_mass_prod ! only a fraction of reproductive carbon is seed (ahb) + !seed_prod = repro_mass_prod * repro_frac_seed ! seed production per ind. (ahb) + ! only a fraction of reproductive (ahb) + ! mass is seed (ahb) + + !non_seed_repro_prod = repro_mass_prod * (1.0_r8 - repro_frac_seed) !non-seed repro (ahb) + !mass per ind. (ahb) - ! the remainder goes to non-seed reproductive litter - !litt%non_seed_repro_mass_decay(pft) = repro_mass_prod * (1.0_r8 - 0.5_r8) ! ahb + !litt%seed_decay(pft) = non_seed_repro_prod * currentCohort%n / area !send non-seed repro mass to seed decay pool !--------------------------------------------------------------------------- !END ahb changes + + + + if(element_id==carbon12_element)then - currentcohort%seed_prod = seed_prod + currentcohort%seed_prod = seed_prod end if site_seed_rain(pft) = site_seed_rain(pft) + & - (seed_prod * currentCohort%n + store_m_to_repro) + (seed_prod * currentCohort%n + store_m_to_repro) currentCohort => currentCohort%shorter enddo !cohort loop @@ -1525,7 +1540,8 @@ subroutine SeedDecay( litt ) do pft = 1,numpft litt%seed_decay(pft) = litt%seed(pft) * & - EDPftvarcon_inst%seed_decay_rate(pft)*years_per_day + EDPftvarcon_inst%seed_decay_rate(pft)*years_per_day ! + & ! "+ &" added by ahb (7/10/2021) + ! litt%seed_decay(pft) ! whole line added by ahb (7/10/2021) litt%seed_germ_decay(pft) = litt%seed_germ(pft) * & EDPftvarcon_inst%seed_decay_rate(pft)*years_per_day @@ -1569,7 +1585,7 @@ subroutine SeedGermination( litt, cold_stat, drought_stat ) ! that times the ratio of (hypothetical) seed mass to recruit biomass do pft = 1,numpft - litt%seed_germ_in(pft) = min(litt%seed(pft) * EDPftvarcon_inst%germination_rate(pft), & + litt%seed_germ_in(pft) = min(litt%seed(pft) * EDPftvarcon_inst%germination_rate(pft), & max_germination)*years_per_day !set the germination only under the growing season...c.xu From 3c488956c0ba77135300051cbc56b668296a9247 Mon Sep 17 00:00:00 2001 From: adamhb Date: Wed, 14 Jul 2021 14:35:16 -0700 Subject: [PATCH 12/81] added seedling emergence notes --- biogeochem/EDPhysiologyMod.F90 | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/biogeochem/EDPhysiologyMod.F90 b/biogeochem/EDPhysiologyMod.F90 index ed7c98ddc6..1baa11dabb 100644 --- a/biogeochem/EDPhysiologyMod.F90 +++ b/biogeochem/EDPhysiologyMod.F90 @@ -1584,11 +1584,32 @@ subroutine SeedGermination( litt, cold_stat, drought_stat ) ! and thus the mortality rate (in units of individuals) is the product of ! that times the ratio of (hypothetical) seed mass to recruit biomass + !ORIGINAL CODE + !------------------------------------------------------------------------------------------- do pft = 1,numpft litt%seed_germ_in(pft) = min(litt%seed(pft) * EDPftvarcon_inst%germination_rate(pft), & max_germination)*years_per_day - - !set the germination only under the growing season...c.xu + !------------------------------------------------------------------------------------------- + + !ahb NEW CODE + !------------------------------------------------------------------------------------------- + !Step 1. Define a variable that is the mean SMP in the top 6 cm over the prior 14 days + + !real(r8),parameter :: demerg_soil_depth = 0.06_r8 + !ilayer_swater_emerg = minloc(abs(bc_in%z_sisl(:)-demerg_soil_depth),dim=1) + !smp_emerg_today = bc_in%smp_sl(ilayer_swater_emerg) + !currentSite%water_memory_emerg(1) = smp_emerg_today + !NEED TO BUILD OUT THIS WATER MEMORY MORE + + !do pft = 1,numpft + ! litt%seed_germ_in(pft) = min(litt%seed(pft) * EDPftvarcon_inst%germination_rate(pft), & + ! max_germination)*years_per_day + !------------------------------------------------------------------------------------------- + + + + + !set the germination only under the growing season...c.xu if ((prt_params%season_decid(pft) == itrue ) .and. & (any(cold_stat == [phen_cstat_nevercold,phen_cstat_iscold]))) then From 26a8bfb06da829ad0ed9420382626f01482f3fa3 Mon Sep 17 00:00:00 2001 From: adamhb Date: Thu, 15 Jul 2021 12:37:08 -0700 Subject: [PATCH 13/81] model working with moving a fraction of the seed rain to decay immediately --- biogeochem/EDPhysiologyMod.F90 | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/biogeochem/EDPhysiologyMod.F90 b/biogeochem/EDPhysiologyMod.F90 index ed7c98ddc6..523cfe8ba4 100644 --- a/biogeochem/EDPhysiologyMod.F90 +++ b/biogeochem/EDPhysiologyMod.F90 @@ -1484,6 +1484,11 @@ subroutine SeedIn( currentSite, bc_in ) ! Seed input from local sources (within site) litt%seed_in_local(pft) = litt%seed_in_local(pft) + site_seed_rain(pft)/area + !new code 7/14/2021 ahb + !-------------------------------- + litt%seed_decay(pft) = litt%seed_in_local(pft) * 0.5_r8 + !-------------------------------- + ! If there is forced external seed rain, we calculate the input mass flux ! from the different elements, usung the seed optimal stoichiometry ! for non-carbon From ab9625aae316043213514c5f9122f99cddf73d9f Mon Sep 17 00:00:00 2001 From: adamhb Date: Thu, 15 Jul 2021 19:59:42 -0700 Subject: [PATCH 14/81] Adam Hanbury-Brown added a reproductive allocation scheme to fates. Reproductive allocation is a function of size in this new scheme. Changes are made in AllomCGrowthDeriv function in parteh. The SeedIn subroutine is alos modified so that only a fraction of reproductive carbon goes to the seed bank, while the remainder goes to the litter pool (via the "seed_decay" flux). These changes also required a change to the SeedDecay subroutine so that the non-seed reproductive mass flux from the SeedIn subroutine is added to the decay_decay flux from actual decaying seeds. Three new parameters were added to the fates parameter file for these updates: fates_repro_alloc_a, fates_repro_alloc_b, fates_repro_frac_seed. Fixes: None User interface changes?: No Code review: Adam Hanbury-Brown Test suite: COMPILER=gnu, MACHINE=lobata Test baseline: Test namelist changes: Test answer changes: [bit for bit, roundoff, climate changing] Test summary: COMPILER=gnu, MACHINE=lobata. No formal tests were done. This version of the model is working for a run at BCI. --- biogeochem/EDPhysiologyMod.F90 | 9 +++++---- main/EDPftvarcon.F90 | 10 ++++++++++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/biogeochem/EDPhysiologyMod.F90 b/biogeochem/EDPhysiologyMod.F90 index 523cfe8ba4..cebae23862 100644 --- a/biogeochem/EDPhysiologyMod.F90 +++ b/biogeochem/EDPhysiologyMod.F90 @@ -1367,7 +1367,7 @@ subroutine SeedIn( currentSite, bc_in ) real(r8) :: seed_in_external ! Mass of externally generated seeds [kg/m2/day] real(r8) :: seed_stoich ! Mass ratio of nutrient per C12 in seeds [kg/kg] real(r8) :: repro_mass_prod ! Mass of reproductive material produced [kg/day] ; added by ahb 7/8/2021 - !real(r8), parameter :: repro_frac_seed = 0.5 !added by ahb 7/12/2021 + real(r8), parameter :: repro_frac_seed = 0.5 !added by ahb 7/12/2021; move this to param file real(r8) :: seed_prod ! Seed produced in this dynamics step [kg/day] real(r8) :: non_seed_repro_prod ! Mass of non-seed reproductive material produced [kg/day] ; added by ahb 7/10/2021 integer :: n_litt_types ! number of litter element types (c,n,p, etc) @@ -1486,7 +1486,7 @@ subroutine SeedIn( currentSite, bc_in ) !new code 7/14/2021 ahb !-------------------------------- - litt%seed_decay(pft) = litt%seed_in_local(pft) * 0.5_r8 + litt%seed_decay(pft) = litt%seed_in_local(pft) * (1.0_r8 - EDPftvarcon_inst%repro_frac_seed(pft)) !ahb !-------------------------------- ! If there is forced external seed rain, we calculate the input mass flux @@ -1545,8 +1545,9 @@ subroutine SeedDecay( litt ) do pft = 1,numpft litt%seed_decay(pft) = litt%seed(pft) * & - EDPftvarcon_inst%seed_decay_rate(pft)*years_per_day ! + & ! "+ &" added by ahb (7/10/2021) - ! litt%seed_decay(pft) ! whole line added by ahb (7/10/2021) + EDPftvarcon_inst%seed_decay_rate(pft)*years_per_day + & ! "+ &" added by ahb (7/10/2021) + litt%seed_decay(pft) ! line added by ahb so that the flux from non-seed reproductive + ! biomass (from SeedIn subroutine) is not lost (7/10/2021) litt%seed_germ_decay(pft) = litt%seed_germ(pft) * & EDPftvarcon_inst%seed_decay_rate(pft)*years_per_day diff --git a/main/EDPftvarcon.F90 b/main/EDPftvarcon.F90 index 61f095a758..4934f3920a 100644 --- a/main/EDPftvarcon.F90 +++ b/main/EDPftvarcon.F90 @@ -103,6 +103,7 @@ module EDPftvarcon real(r8), allocatable :: seed_decay_rate(:) ! Fraction of seed mass (both germinated and ! ungerminated), decaying per year (yr-1) + real(r8), allocatable :: repro_frac_seed(:) ! added by ahb 7/15/2021 real(r8), allocatable :: trim_limit(:) ! Limit to reductions in leaf area w stress (m2/m2) real(r8), allocatable :: trim_inc(:) ! Incremental change in trimming function (m2/m2) real(r8), allocatable :: rhol(:, :) @@ -513,6 +514,10 @@ subroutine Register_PFT(this, fates_params) call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) + name = 'fates_repro_frac_seed' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + name = 'fates_seed_decay_rate' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) @@ -844,6 +849,10 @@ subroutine Receive_PFT(this, fates_params) call fates_params%RetreiveParameterAllocate(name=name, & data=this%germination_rate) + name = 'fates_repro_frac_seed' + call fates_params%RetreiveParameterAllocate(name=name, & + data=this%repro_frac_seed) + name = 'fates_seed_decay_rate' call fates_params%RetreiveParameterAllocate(name=name, & data=this%seed_decay_rate) @@ -1330,6 +1339,7 @@ subroutine FatesReportPFTParams(is_master) write(fates_log(),fmt0) 'jmaxse = ',EDPftvarcon_inst%jmaxse write(fates_log(),fmt0) 'germination_timescale = ',EDPftvarcon_inst%germination_rate write(fates_log(),fmt0) 'seed_decay_turnover = ',EDPftvarcon_inst%seed_decay_rate + write(fates_log(),fmt0) 'repro_frac_seed = ',EDPftvarcon_inst%repro_frac_seed write(fates_log(),fmt0) 'trim_limit = ',EDPftvarcon_inst%trim_limit write(fates_log(),fmt0) 'trim_inc = ',EDPftvarcon_inst%trim_inc write(fates_log(),fmt0) 'rhol = ',EDPftvarcon_inst%rhol From b2e0a1f8d9d79f019f802504dd651636fae0a2ba Mon Sep 17 00:00:00 2001 From: adamhb Date: Thu, 15 Jul 2021 20:25:48 -0700 Subject: [PATCH 15/81] AHB cleaned up code and updated the comments of the reproductive allocation scheme. Fixes: None User interface changes?: No Code review: Adam Hanbury-Brown Test summary: None --- parteh/PRTAllometricCarbonMod.F90 | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/parteh/PRTAllometricCarbonMod.F90 b/parteh/PRTAllometricCarbonMod.F90 index 87ec4769c7..c988bb9a30 100644 --- a/parteh/PRTAllometricCarbonMod.F90 +++ b/parteh/PRTAllometricCarbonMod.F90 @@ -942,7 +942,6 @@ function AllomCGrowthDeriv(c_pools,c_mask,cbalance,intgr_params) result(dCdx) ! fraction of carbon going towards reproduction !START ahb's changes - !original code !------------------------------------------------------------------------------------- !if (dbh <= prt_params%dbh_repro_threshold(ipft)) then ! cap on leaf biomass @@ -952,7 +951,7 @@ function AllomCGrowthDeriv(c_pools,c_mask,cbalance,intgr_params) result(dCdx) !end if !------------------------------------------------------------------------------------- - !new code + !new regeneration code !------------------------------------------------------------------------------------- !This reproductive allocation function calculates the fraction of available carbon !allocated to reproductive tissue based on a cohort's size. This function is based on @@ -961,7 +960,7 @@ function AllomCGrowthDeriv(c_pools,c_mask,cbalance,intgr_params) result(dCdx) !Visser MD, Bruijning M, Wright SJ, Muller-Landau HC, Jongejans E, Comita LS, !de Kroon H. 2016. Functional traits as predictors of vital rates across the life cycle !of tropical trees. Functional Ecology 30: 168–180. - !-------------------------------------------------------------------------------------! + !------------------------------------------------------------------------------------- repro_fraction = prt_params%seed_alloc(ipft) * & (exp(prt_params%repro_alloc_b(ipft) + prt_params%repro_alloc_a(ipft)*dbh*mm_per_cm) / & (1 + exp(prt_params%repro_alloc_b(ipft) + prt_params%repro_alloc_b(ipft)*dbh*mm_per_cm))) From 32c6146f744d40e0b6c80cc61ec06b779f6f8aee Mon Sep 17 00:00:00 2001 From: adamhb Date: Thu, 15 Jul 2021 20:29:30 -0700 Subject: [PATCH 16/81] Cleaned up comments to the reproductive allocation scheme and the SeedIn subroutine. Fixes: none User interface changes?: No Code review: Adam Hanbury-Brown Tests: none --- biogeochem/EDPhysiologyMod.F90 | 45 +++++----------------------------- 1 file changed, 6 insertions(+), 39 deletions(-) diff --git a/biogeochem/EDPhysiologyMod.F90 b/biogeochem/EDPhysiologyMod.F90 index cebae23862..b5f24bffb2 100644 --- a/biogeochem/EDPhysiologyMod.F90 +++ b/biogeochem/EDPhysiologyMod.F90 @@ -1407,47 +1407,9 @@ subroutine SeedIn( currentSite, bc_in ) ! of seeds [kg] released by the plant, per the mass_fraction ! specified as input. This routine will also remove the mass ! from the parteh state-variable. - - - - - - !START ahb changes - !-------------------------------------------------------------------------- - !original code call PRTReproRelease(currentCohort%prt,repro_organ,element_id, & 1.0_r8, seed_prod) - !-------------------------------------------------------------------------- - - !-------------------------------------------------------------------------- - !ahb's new code - !the original code sends all reproductive tissue to seed - !This new code, added by ahb, is designed to send some reproductive biomass - !straight to the leaf litter pool to account for non-seed reproductive - !biomass. For now, ahb does this after the call to the - !PRTReproRelease function, but a better solution would probably be to do - !this within the PRTReproRelease module in parteh/PRTLossFluxesMod.F90::L342 - !by adding new live reproductive organs (ahb needs help with this). - - !call PRTReproRelease(currentCohort%prt,repro_organ,element_id, & - ! 1.0_r8, repro_mass_prod) !ahb changed from seed_prod to repro_mass_prod - - !seed_prod = repro_mass_prod * repro_frac_seed ! seed production per ind. (ahb) - ! only a fraction of reproductive (ahb) - ! mass is seed (ahb) - - !non_seed_repro_prod = repro_mass_prod * (1.0_r8 - repro_frac_seed) !non-seed repro (ahb) - !mass per ind. (ahb) - - !litt%seed_decay(pft) = non_seed_repro_prod * currentCohort%n / area !send non-seed repro mass to seed decay pool - !--------------------------------------------------------------------------- - - !END ahb changes - - - - if(element_id==carbon12_element)then currentcohort%seed_prod = seed_prod @@ -1484,7 +1446,12 @@ subroutine SeedIn( currentSite, bc_in ) ! Seed input from local sources (within site) litt%seed_in_local(pft) = litt%seed_in_local(pft) + site_seed_rain(pft)/area - !new code 7/14/2021 ahb + !New regeneration code added by ahb on 7/15/2021 + !The original code sends all reproductive tissue to seed + !This new code is designed to send some reproductive biomass + !straight to the leaf litter pool to account for non-seed reproductive + !biomass. Also see small change to SeedDecay subroutine. + !This can be turned off by commenting out line 1456. !-------------------------------- litt%seed_decay(pft) = litt%seed_in_local(pft) * (1.0_r8 - EDPftvarcon_inst%repro_frac_seed(pft)) !ahb !-------------------------------- From 0e476131b78df1f3eec612f84d44df77021e9853 Mon Sep 17 00:00:00 2001 From: adamhb Date: Fri, 16 Jul 2021 10:54:00 -0700 Subject: [PATCH 17/81] commit prior to the creation of a seedling pool --- biogeochem/EDPhysiologyMod.F90.save | 2396 +++++++++++++++++++++++++++ 1 file changed, 2396 insertions(+) create mode 100644 biogeochem/EDPhysiologyMod.F90.save diff --git a/biogeochem/EDPhysiologyMod.F90.save b/biogeochem/EDPhysiologyMod.F90.save new file mode 100644 index 0000000000..9a068eb85c --- /dev/null +++ b/biogeochem/EDPhysiologyMod.F90.save @@ -0,0 +1,2396 @@ +module EDPhysiologyMod + +#include "shr_assert.h" + + ! ============================================================================ + ! Miscellaneous physiology routines from ED. + ! ============================================================================ + + use FatesGlobals, only : fates_log + use FatesInterfaceTypesMod, only : hlm_days_per_year + use FatesInterfaceTypesMod, only : hlm_model_day + use FatesInterfaceTypesMod, only : hlm_freq_day + use FatesInterfaceTypesMod, only : hlm_day_of_year + use FatesInterfaceTypesMod, only : numpft + use FatesInterfaceTypesMod, only : nleafage + use FatesInterfaceTypesMod, only : hlm_use_planthydro + use FatesInterfaceTypesMod, only : hlm_parteh_mode + use FatesInterfaceTypesMod, only : hlm_nitrogen_spec + use FatesInterfaceTypesMod, only : hlm_phosphorus_spec + use FatesConstantsMod, only : r8 => fates_r8 + use FatesConstantsMod, only : nearzero + use EDPftvarcon , only : EDPftvarcon_inst + use PRTParametersMod , only : prt_params + use EDPftvarcon , only : GetDecompyFrac + use FatesInterfaceTypesMod, only : bc_in_type + use FatesInterfaceTypesMod, only : bc_out_type + use EDCohortDynamicsMod , only : zero_cohort + use EDCohortDynamicsMod , only : create_cohort, sort_cohorts + use EDCohortDynamicsMod , only : InitPRTObject + use FatesAllometryMod , only : tree_lai + use FatesAllometryMod , only : tree_sai + use FatesAllometryMod , only : decay_coeff_kn + use FatesLitterMod , only : litter_type + use EDTypesMod , only : site_massbal_type + use EDTypesMod , only : numlevsoil_max + use EDTypesMod , only : numWaterMem + use EDTypesMod , only : dl_sf, dinc_ed, area_inv + use FatesLitterMod , only : ncwd + use FatesLitterMod , only : ndcmpy + use FatesLitterMod , only : ilabile + use FatesLitterMod , only : ilignin + use FatesLitterMod , only : icellulose + use EDTypesMod , only : AREA,AREA_INV + use EDTypesMod , only : nlevleaf + use EDTypesMod , only : num_vegtemp_mem + use EDTypesMod , only : maxpft + use EDTypesMod , only : ed_site_type, ed_patch_type, ed_cohort_type + use EDTypesMod , only : leaves_on + use EDTypesMod , only : leaves_off + use EDTypesMod , only : min_n_safemath + use PRTGenericMod , only : num_elements + use PRTGenericMod , only : element_list + use PRTGenericMod , only : element_pos + use EDTypesMod , only : site_fluxdiags_type + use EDTypesMod , only : phen_cstat_nevercold + use EDTypesMod , only : phen_cstat_iscold + use EDTypesMod , only : phen_cstat_notcold + use EDTypesMod , only : phen_dstat_timeoff + use EDTypesMod , only : phen_dstat_moistoff + use EDTypesMod , only : phen_dstat_moiston + use EDTypesMod , only : phen_dstat_timeon + use EDTypesMod , only : init_recruit_trim + use shr_log_mod , only : errMsg => shr_log_errMsg + use FatesGlobals , only : fates_log + use FatesGlobals , only : endrun => fates_endrun + use EDParamsMod , only : fates_mortality_disturbance_fraction + use EDParamsMod , only : q10_mr + use EDParamsMod , only : q10_froz + use EDParamsMod , only : logging_export_frac + use FatesPlantHydraulicsMod , only : AccumulateMortalityWaterStorage + use FatesConstantsMod , only : itrue,ifalse + use FatesConstantsMod , only : calloc_abs_error + use FatesConstantsMod , only : years_per_day + use FatesAllometryMod , only : h_allom + use FatesAllometryMod , only : h2d_allom + use FatesAllometryMod , only : bagw_allom + use FatesAllometryMod , only : bsap_allom + use FatesAllometryMod , only : bleaf + use FatesAllometryMod , only : bfineroot + use FatesAllometryMod , only : bdead_allom + use FatesAllometryMod , only : bstore_allom + use FatesAllometryMod , only : bbgw_allom + use FatesAllometryMod , only : carea_allom + use FatesAllometryMod , only : CheckIntegratedAllometries + use FatesAllometryMod, only : set_root_fraction + use PRTGenericMod, only : prt_carbon_allom_hyp + use PRTGenericMod, only : prt_cnp_flex_allom_hyp + use PRTGenericMod, only : prt_vartypes + use PRTGenericMod, only : leaf_organ + use PRTGenericMod, only : sapw_organ, struct_organ + use PRTGenericMod, only : all_carbon_elements + 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 + use PRTGenericMod, only : store_organ + use PRTGenericMod, only : repro_organ + use PRTGenericMod, only : struct_organ + use PRTGenericMod, only : SetState + use PRTLossFluxesMod, only : PRTPhenologyFlush + use PRTLossFluxesMod, only : PRTDeciduousTurnover + use PRTLossFluxesMod, only : PRTReproRelease + use PRTGenericMod, only : StorageNutrientTarget + + implicit none + private + + public :: trim_canopy + public :: phenology + public :: recruitment + public :: ZeroLitterFluxes + + public :: ZeroAllocationRates + public :: PreDisturbanceLitterFluxes + public :: PreDisturbanceIntegrateLitter + public :: SeedIn + + logical, parameter :: debug = .false. ! local debug flag + character(len=*), parameter, private :: sourcefile = & + __FILE__ + + integer, parameter :: dleafon_drycheck = 100 ! Drought deciduous leaves max days on check parameter + + + ! ============================================================================ + +contains + + subroutine ZeroLitterFluxes( currentSite ) + + ! This routine loops through all patches in a site + ! and zero's the flux terms for the litter pools. + ! This is typically called at the beginning of the dynamics + ! call sequence. + + + ! !ARGUMENTS + type(ed_site_type), intent(inout), target :: currentSite + type(ed_patch_type), pointer :: currentPatch + + integer :: el + + currentPatch => currentSite%youngest_patch + do while(associated(currentPatch)) + do el=1,num_elements + call currentPatch%litter(el)%ZeroFlux() + end do + currentPatch => currentPatch%older + end do + + + return + end subroutine ZeroLitterFluxes + + ! ===================================================================================== + + subroutine ZeroAllocationRates( currentSite ) + + ! !ARGUMENTS + type(ed_site_type), intent(inout), target :: currentSite + type(ed_patch_type), pointer :: currentPatch + type(ed_cohort_type), pointer :: currentCohort + + currentPatch => currentSite%youngest_patch + do while(associated(currentPatch)) + + currentCohort => currentPatch%tallest + do while (associated(currentCohort)) + + ! This sets turnover and growth rates to zero + call currentCohort%prt%ZeroRates() + + currentCohort => currentCohort%shorter + enddo + currentPatch => currentPatch%older + end do + + return + end subroutine ZeroAllocationRates + + + ! ============================================================================ + + subroutine PreDisturbanceLitterFluxes( currentSite, currentPatch, bc_in ) + + ! ----------------------------------------------------------------------------------- + ! + ! This subroutine calculates all of the different litter input and output fluxes + ! associated with seed turnover, seed influx, litterfall from live and + ! dead plants, germination, and fragmentation. + ! + ! At this time we do not have explicit herbivory, and burning losses to litter + ! are handled elsewhere. + ! + ! Note: The processes conducted here DO NOT handle litter fluxes associated + ! with disturbance. Those fluxes are handled elsewhere (EDPatchDynamcisMod) + ! because the fluxes are potentially cross patch, and also dealing + ! patch areas that are changing. + ! + ! ----------------------------------------------------------------------------------- + + + ! !ARGUMENTS + type(ed_site_type), intent(inout) :: currentSite + type(ed_patch_type), intent(inout) :: currentPatch + type(bc_in_type), intent(in) :: 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 + !------------------------------------------------------------------------------------ + + ! Calculate the fragmentation rates + call fragmentation_scaler(currentPatch, bc_in) + + + do el = 1, num_elements + + litt => currentPatch%litter(el) + + ! Calculate loss rate of viable seeds to litter + call SeedDecay(litt) + + ! 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) + + ! 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) + + + 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%non_seed_repro_mass_decay) + & !ahb added this line on 7/8/2021 + sum(litt%seed_decay) + sum(litt%seed_germ_decay)) + + end do + + + return + end subroutine PreDisturbanceLitterFluxes + + ! ===================================================================================== + + subroutine PreDisturbanceIntegrateLitter(currentPatch) + + ! ----------------------------------------------------------------------------------- + ! + ! This step applies the litter fluxes to the prognostic state variables. + ! This procedure is called in response to fluxes generated from: + ! 1) seed rain, + ! 2) non-disturbance generating turnover + ! 3) litter fall from living plants + ! 4) fragmentation + ! + ! This routine does NOT accomodate the litter fluxes associated with + ! disturbance generation. That will happen after this call. + ! Fluxes associated with FIRE also happen after this step. + ! + ! All states are in units kg/m2 + ! All fluxes are in units kg/m2/day + ! The integration step is 1 day, thus time is implied + ! + ! ----------------------------------------------------------------------------------- + + ! Arguments + type(ed_patch_type),intent(inout),target :: currentPatch + + + ! Locals + type(litter_type), pointer :: litt + integer :: el ! Loop counter for litter element type + integer :: pft ! pft loop counter + integer :: c ! CWD loop counter + integer :: nlevsoil ! number of soil layers + integer :: ilyr ! soil layer loop counter + integer :: dcmpy ! decomposability index + + do el = 1, num_elements + + litt => currentPatch%litter(el) + + ! Update the bank of viable seeds + ! ----------------------------------------------------------------------------------- + + do pft = 1,numpft + litt%seed(pft) = litt%seed(pft) + & + litt%seed_in_local(pft) + & + litt%seed_in_extern(pft) - & + litt%seed_decay(pft) - & + litt%seed_germ_in(pft) + + ! Note that the recruitment scheme will use seed_germ + ! for its construction costs. + litt%seed_germ(pft) = litt%seed_germ(pft) + & + litt%seed_germ_in(pft) - & + litt%seed_germ_decay(pft) + + + enddo + + ! Update the Coarse Woody Debris pools (above and below) + ! ----------------------------------------------------------------------------------- + nlevsoil = size(litt%bg_cwd,dim=2) + do c = 1,ncwd + litt%ag_cwd(c) = litt%ag_cwd(c) + litt%ag_cwd_in(c) - litt%ag_cwd_frag(c) + do ilyr=1,nlevsoil + litt%bg_cwd(c,ilyr) = litt%bg_cwd(c,ilyr) & + + litt%bg_cwd_in(c,ilyr) & + - litt%bg_cwd_frag(c,ilyr) + enddo + end do + + ! Update the fine litter pools from leaves and fine-roots + ! ----------------------------------------------------------------------------------- + + do dcmpy = 1,ndcmpy + + litt%leaf_fines(dcmpy) = litt%leaf_fines(dcmpy) & + + litt%leaf_fines_in(dcmpy) & + - litt%leaf_fines_frag(dcmpy) + do ilyr=1,nlevsoil + litt%root_fines(dcmpy,ilyr) = litt%root_fines(dcmpy,ilyr) & + + litt%root_fines_in(dcmpy,ilyr) & + - litt%root_fines_frag(dcmpy,ilyr) + enddo + + end do + + end do ! litter element loop + + return + end subroutine PreDisturbanceIntegrateLitter + + + + ! ============================================================================ + + subroutine trim_canopy( currentSite ) + ! + ! !DESCRIPTION: + ! Canopy trimming / leaf optimisation. Removes leaves in negative annual carbon balance. + ! + ! !USES: + + ! !ARGUMENTS + type (ed_site_type),intent(inout), target :: currentSite + ! + ! !LOCAL VARIABLES: + type (ed_cohort_type) , pointer :: currentCohort + type (ed_patch_type) , pointer :: currentPatch + + integer :: z ! leaf layer + integer :: ipft ! pft index + logical :: trimmed ! was this layer trimmed in this year? If not expand the canopy. + real(r8) :: tar_bl ! target leaf biomass (leaves flushed, trimmed) + real(r8) :: tar_bfr ! target fine-root biomass (leaves flushed, trimmed) + real(r8) :: bfr_per_bleaf ! ratio of fine root per leaf biomass + real(r8) :: sla_levleaf ! sla at leaf level z + real(r8) :: nscaler_levleaf ! nscaler value at leaf level z + integer :: cl ! canopy layer index + real(r8) :: kn ! nitrogen decay coefficient + real(r8) :: sla_max ! Observational constraint on how large sla (m2/gC) can become + real(r8) :: leaf_c ! leaf carbon [kg] + real(r8) :: sapw_c ! sapwood carbon [kg] + real(r8) :: store_c ! storage carbon [kg] + real(r8) :: struct_c ! structure carbon [kg] + real(r8) :: leaf_inc ! LAI-only portion of the vegetation increment of dinc_ed + real(r8) :: lai_canopy_above ! the LAI in the canopy layers above the layer of interest + real(r8) :: lai_layers_above ! the LAI in the leaf layers, within the current canopy, + ! above the leaf layer of interest + real(r8) :: lai_current ! the LAI in the current leaf layer + real(r8) :: cumulative_lai ! whole canopy cumulative LAI, top down, to the leaf layer of interest + real(r8) :: cumulative_lai_cohort ! cumulative LAI within the current cohort only + + ! Temporary diagnostic ouptut + integer :: ipatch + integer :: icohort + + ! LAPACK linear least squares fit variables + ! The standard equation for a linear fit, y = mx + b, is converted to a linear system, AX=B and has + ! the form: [n sum(x); sum(x) sum(x^2)] * [b; m] = [sum(y); sum(x*y)] where + ! n is the number of leaf layers + ! x is yearly_net_uptake minus the leaf cost aka the net-net uptake + ! y is the cumulative lai for the current cohort + ! b is the y-intercept i.e. the cumulative lai that has zero net-net uptake + ! m is the slope of the linear fit + integer :: nll = 3 ! Number of leaf layers to fit a regression to for calculating the optimum lai + character(1) :: trans = 'N' ! Input matrix is not transposed + + integer, parameter :: m = 2, n = 2 ! Number of rows and columns, respectively, in matrix A + integer, parameter :: nrhs = 1 ! Number of columns in matrix B and X + integer, parameter :: workmax = 100 ! Maximum iterations to minimize work + + integer :: lda = m, ldb = n ! Leading dimension of A and B, respectively + integer :: lwork ! Dimension of work array + integer :: info ! Procedure diagnostic ouput + + real(r8) :: nnu_clai_a(m,n) ! LHS of linear least squares fit, A matrix + real(r8) :: nnu_clai_b(m,nrhs) ! RHS of linear least squares fit, B matrix + real(r8) :: work(workmax) ! work array + + real(r8) :: initial_trim ! Initial trim + real(r8) :: optimum_trim ! Optimum trim value + real(r8) :: initial_laimem ! Initial laimemory + real(r8) :: optimum_laimem ! Optimum laimemory + + !---------------------------------------------------------------------- + + ipatch = 1 ! Start counting patches + + currentPatch => currentSite%youngest_patch + do while(associated(currentPatch)) + + ! Add debug diagnstic output to determine which patch + if (debug) then + write(fates_log(),*) 'Current patch:', ipatch + write(fates_log(),*) 'Current patch cohorts:', currentPatch%countcohorts + endif + + icohort = 1 + + currentCohort => currentPatch%tallest + do while (associated(currentCohort)) + + ! Save off the incoming trim and laimemory + initial_trim = currentCohort%canopy_trim + initial_laimem = currentCohort%laimemory + + ! Add debug diagnstic output to determine which cohort + if (debug) then + write(fates_log(),*) 'Current cohort:', icohort + write(fates_log(),*) 'Starting canopy trim:', initial_trim + write(fates_log(),*) 'Starting laimemory:', currentCohort%laimemory + endif + + trimmed = .false. + ipft = currentCohort%pft + call carea_allom(currentCohort%dbh,currentCohort%n,currentSite%spread,currentCohort%pft,currentCohort%c_area) + + leaf_c = currentCohort%prt%GetState(leaf_organ, all_carbon_elements) + + currentCohort%treelai = tree_lai(leaf_c, currentCohort%pft, currentCohort%c_area, & + currentCohort%n, currentCohort%canopy_layer, & + currentPatch%canopy_layer_tlai,currentCohort%vcmax25top ) + + currentCohort%treesai = tree_sai(currentCohort%pft, currentCohort%dbh, currentCohort%canopy_trim, & + currentCohort%c_area, currentCohort%n, currentCohort%canopy_layer, & + currentPatch%canopy_layer_tlai, currentCohort%treelai, & + currentCohort%vcmax25top,0 ) + + currentCohort%nv = ceiling((currentCohort%treelai+currentCohort%treesai)/dinc_ed) + + if (currentCohort%nv > nlevleaf)then + write(fates_log(),*) 'nv > nlevleaf',currentCohort%nv, & + currentCohort%treelai,currentCohort%treesai, & + currentCohort%c_area,currentCohort%n,leaf_c + call endrun(msg=errMsg(sourcefile, __LINE__)) + endif + + call bleaf(currentcohort%dbh,ipft,currentcohort%canopy_trim,tar_bl) + + if ( int(prt_params%allom_fmode(ipft)) .eq. 1 ) then + ! only query fine root biomass if using a fine root allometric model that takes leaf trim into account + call bfineroot(currentcohort%dbh,ipft,currentcohort%canopy_trim,tar_bfr) + bfr_per_bleaf = tar_bfr/tar_bl + endif + + ! Identify current canopy layer (cl) + cl = currentCohort%canopy_layer + + ! PFT-level maximum SLA value, even if under a thick canopy (same units as slatop) + sla_max = prt_params%slamax(ipft) + + ! Initialize nnu_clai_a + nnu_clai_a(:,:) = 0._r8 + nnu_clai_b(:,:) = 0._r8 + + !Leaf cost vs netuptake for each leaf layer. + do z = 1, currentCohort%nv + + ! Calculate the cumulative total vegetation area index (no snow occlusion, stems and leaves) + + leaf_inc = dinc_ed * & + currentCohort%treelai/(currentCohort%treelai+currentCohort%treesai) + + ! Now calculate the cumulative top-down lai of the current layer's midpoint within the current cohort + lai_layers_above = leaf_inc * (z-1) + lai_current = min(leaf_inc, currentCohort%treelai - lai_layers_above) + cumulative_lai_cohort = lai_layers_above + 0.5*lai_current + + ! Now add in the lai above the current cohort for calculating the sla leaf level + lai_canopy_above = sum(currentPatch%canopy_layer_tlai(1:cl-1)) + cumulative_lai = lai_canopy_above + cumulative_lai_cohort + + ! There was activity this year in this leaf layer. This should only occur for bottom most leaf layer + if (currentCohort%year_net_uptake(z) /= 999._r8)then + + ! Calculate sla_levleaf following the sla profile with overlying leaf area + ! Scale for leaf nitrogen profile + kn = decay_coeff_kn(ipft,currentCohort%vcmax25top) + ! Nscaler value at leaf level z + nscaler_levleaf = exp(-kn * cumulative_lai) + ! Sla value at leaf level z after nitrogen profile scaling (m2/gC) + sla_levleaf = prt_params%slatop(ipft)/nscaler_levleaf + + if(sla_levleaf > sla_max)then + sla_levleaf = sla_max + end if + + !Leaf Cost kgC/m2/year-1 + !decidous costs. + if (prt_params%season_decid(ipft) == itrue .or. & + prt_params%stress_decid(ipft) == itrue )then + + ! Leaf cost at leaf level z accounting for sla profile (kgC/m2) + currentCohort%leaf_cost = 1._r8/(sla_levleaf*1000.0_r8) + + if ( int(prt_params%allom_fmode(ipft)) .eq. 1 ) then + ! if using trimmed leaf for fine root biomass allometry, add the cost of the root increment + ! to the leaf increment; otherwise do not. + currentCohort%leaf_cost = currentCohort%leaf_cost + & + 1.0_r8/(sla_levleaf*1000.0_r8) * & + bfr_per_bleaf / prt_params%root_long(ipft) + endif + + currentCohort%leaf_cost = currentCohort%leaf_cost * & + (prt_params%grperc(ipft) + 1._r8) + else !evergreen costs + + ! Leaf cost at leaf level z accounting for sla profile + currentCohort%leaf_cost = 1.0_r8/(sla_levleaf* & + sum(prt_params%leaf_long(ipft,:))*1000.0_r8) !convert from sla in m2g-1 to m2kg-1 + + + if ( int(prt_params%allom_fmode(ipft)) .eq. 1 ) then + ! if using trimmed leaf for fine root biomass allometry, add the cost of the root increment + ! to the leaf increment; otherwise do not. + currentCohort%leaf_cost = currentCohort%leaf_cost + & + 1.0_r8/(sla_levleaf*1000.0_r8) * & + bfr_per_bleaf / prt_params%root_long(ipft) + endif + currentCohort%leaf_cost = currentCohort%leaf_cost * & + (prt_params%grperc(ipft) + 1._r8) + endif + + ! Construct the arrays for a least square fit of the net_net_uptake versus the cumulative lai + ! if at least nll leaf layers are present in the current cohort and only for the bottom nll + ! leaf layers. + if (currentCohort%nv > nll .and. currentCohort%nv - z < nll) then + + ! Build the A matrix for the LHS of the linear system. A = [n sum(x); sum(x) sum(x^2)] + ! where n = nll and x = yearly_net_uptake-leafcost + nnu_clai_a(1,1) = nnu_clai_a(1,1) + 1 ! Increment for each layer used + nnu_clai_a(1,2) = nnu_clai_a(1,2) + currentCohort%year_net_uptake(z) - currentCohort%leaf_cost + nnu_clai_a(2,1) = nnu_clai_a(1,2) + nnu_clai_a(2,2) = nnu_clai_a(2,2) + (currentCohort%year_net_uptake(z) - currentCohort%leaf_cost)**2 + + ! Build the B matrix for the RHS of the linear system. B = [sum(y); sum(x*y)] + ! where x = yearly_net_uptake-leafcost and y = cumulative_lai_cohort + nnu_clai_b(1,1) = nnu_clai_b(1,1) + cumulative_lai_cohort + nnu_clai_b(2,1) = nnu_clai_b(2,1) + (cumulative_lai_cohort * & + (currentCohort%year_net_uptake(z) - currentCohort%leaf_cost)) + end if + + ! Check leaf cost against the yearly net uptake for that cohort leaf layer + if (currentCohort%year_net_uptake(z) < currentCohort%leaf_cost) then + ! Make sure the cohort trim fraction is great than the pft trim limit + if (currentCohort%canopy_trim > EDPftvarcon_inst%trim_limit(ipft)) then + + ! if ( debug ) then + ! write(fates_log(),*) 'trimming leaves', & + ! currentCohort%canopy_trim,currentCohort%leaf_cost + ! endif + + ! keep trimming until none of the canopy is in negative carbon balance. + if (currentCohort%hite > EDPftvarcon_inst%hgt_min(ipft)) then + currentCohort%canopy_trim = currentCohort%canopy_trim - & + EDPftvarcon_inst%trim_inc(ipft) + if (prt_params%evergreen(ipft) /= 1)then + currentCohort%laimemory = currentCohort%laimemory * & + (1.0_r8 - EDPftvarcon_inst%trim_inc(ipft)) + endif + + trimmed = .true. + + endif ! hite check + endif ! trim limit check + endif ! net uptake check + endif ! leaf activity check + enddo ! z, leaf layer loop + + ! Compute the optimal cumulative lai based on the cohort net-net uptake profile if at least 2 leaf layers + if (nnu_clai_a(1,1) > 1) then + + ! Compute the optimum size of the work array + lwork = -1 ! Ask sgels to compute optimal number of entries for work + call dgels(trans, m, n, nrhs, nnu_clai_a, lda, nnu_clai_b, ldb, work, lwork, info) + lwork = int(work(1)) ! Pick the optimum. TBD, can work(1) come back with greater than work size? + + ! if (debug) then + ! write(fates_log(),*) 'LLSF lwork output (info, lwork):', info, lwork + ! endif + + ! Compute the minimum of 2-norm of of the least squares fit to solve for X + ! Note that dgels returns the solution by overwriting the nnu_clai_b array. + ! The result has the form: X = [b; m] + ! where b = y-intercept (i.e. the cohort lai that has zero yearly net-net uptake) + ! and m is the slope of the linear fit + call dgels(trans, m, n, nrhs, nnu_clai_a, lda, nnu_clai_b, ldb, work, lwork, info) + + if (info < 0) then + write(fates_log(),*) 'LLSF optimium LAI calculation returned illegal value' + call endrun(msg=errMsg(sourcefile, __LINE__)) + endif + + if (debug) then + write(fates_log(),*) 'LLSF optimium LAI (intercept,slope):', nnu_clai_b + write(fates_log(),*) 'LLSF optimium LAI:', nnu_clai_b(1,1) + write(fates_log(),*) 'LLSF optimium LAI info:', info + write(fates_log(),*) 'LAI fraction (optimum_lai/cumulative_lai):', nnu_clai_b(1,1) / cumulative_lai_cohort + endif + + ! Calculate the optimum trim based on the initial canopy trim value + if (cumulative_lai_cohort > 0._r8) then ! Sometime cumulative_lai comes in at 0.0? + + ! + optimum_trim = (nnu_clai_b(1,1) / cumulative_lai_cohort) * initial_trim + optimum_laimem = (nnu_clai_b(1,1) / cumulative_lai_cohort) * initial_laimem + + ! Determine if the optimum trim value makes sense. The smallest cohorts tend to have unrealistic fits. + if (optimum_trim > 0. .and. optimum_trim < 1.) then + currentCohort%canopy_trim = optimum_trim + + ! If the cohort pft is not evergreen we reduce the laimemory as well + if (prt_params%evergreen(ipft) /= 1) then + currentCohort%laimemory = optimum_laimem + endif + + trimmed = .true. + + endif + endif + endif + + ! Reset activity for the cohort for the start of the next year + currentCohort%year_net_uptake(:) = 999.0_r8 + + ! Add to trim fraction if cohort not trimmed at all + if ( (.not.trimmed) .and.currentCohort%canopy_trim < 1.0_r8)then + currentCohort%canopy_trim = currentCohort%canopy_trim + EDPftvarcon_inst%trim_inc(ipft) + endif + + if ( debug ) then + write(fates_log(),*) 'trimming:',currentCohort%canopy_trim + endif + + ! currentCohort%canopy_trim = 1.0_r8 !FIX(RF,032414) this turns off ctrim for now. + currentCohort => currentCohort%shorter + icohort = icohort + 1 + enddo + currentPatch => currentPatch%older + ipatch = ipatch + 1 + enddo + + end subroutine trim_canopy + + ! ============================================================================ + subroutine phenology( currentSite, bc_in ) + ! + ! !DESCRIPTION: + ! Phenology. + ! + ! !USES: + use FatesConstantsMod, only : tfrz => t_water_freeze_k_1atm + use EDParamsMod, only : ED_val_phen_drought_threshold, ED_val_phen_doff_time + use EDParamsMod, only : ED_val_phen_a, ED_val_phen_b, ED_val_phen_c, ED_val_phen_chiltemp + use EDParamsMod, only : ED_val_phen_mindayson, ED_val_phen_ncolddayslim, ED_val_phen_coldtemp + + + ! + ! !ARGUMENTS: + type(ed_site_type), intent(inout), target :: currentSite + type(bc_in_type), intent(in) :: bc_in + + ! + ! !LOCAL VARIABLES: + + type(ed_patch_type),pointer :: cpatch + integer :: model_day_int ! integer model day 1 - inf + integer :: ncolddays ! no days underneath the threshold for leaf drop + integer :: i_wmem ! Loop counter for water mem days + integer :: i_tmem ! Loop counter for veg temp mem days + integer :: dayssincedleafon ! Days since drought-decid leaf-on started + integer :: dayssincedleafoff ! Days since drought-decid leaf-off started + integer :: dayssincecleafon ! Days since cold-decid leaf-on started + integer :: dayssincecleafoff ! Days since cold-decid leaf-off started + real(r8) :: mean_10day_liqvol ! mean liquid volume (m3/m3) over last 10 days + real(r8) :: leaf_c ! leaf carbon [kg] + real(r8) :: fnrt_c ! fineroot carbon [kg] + real(r8) :: sapw_c ! sapwood carbon [kg] + real(r8) :: store_c ! storage carbon [kg] + real(r8) :: struct_c ! structure carbon [kg] + real(r8) :: gdd_threshold ! GDD accumulation function, + integer :: ilayer_swater ! Layer index for soil water + ! which also depends on chilling days. + integer :: ncdstart ! beginning of counting period for chilling degree days. + integer :: gddstart ! beginning of counting period for growing degree days. + real(r8) :: temp_in_C ! daily averaged temperature in celcius + + integer, parameter :: canopy_leaf_lifespan = 365 ! Maximum lifespan of drought decid leaves + + integer, parameter :: min_daysoff_dforcedflush = 30 ! THis is the number of days that must had elapsed + ! since leaves had dropped, in order to forcably + ! flush leaves again. This does not impact flushing + ! due to real moisture constraints, and will prevent + ! drought deciduous in perennially wet environments + ! that have been forced to drop their leaves, from + ! flushing them back immediately. + + real(r8),parameter :: dphen_soil_depth = 0.1 ! Use liquid soil water that is + ! closest to this depth [m] + + ! This is the integer model day. The first day of the simulation is 1, and it + ! continues monotonically, indefinitely + model_day_int = nint(hlm_model_day) + + + ! Use the following layer index to calculate drought conditions + ilayer_swater = minloc(abs(bc_in%z_sisl(:)-dphen_soil_depth),dim=1) + + + ! Parameter of drought decid leaf loss in mm in top layer...FIX(RF,032414) + ! - this is arbitrary and poorly understood. Needs work. ED_ + !Parameters: defaults from Botta et al. 2000 GCB,6 709-725 + !Parameters, default from from SDGVM model of senesence + + temp_in_C = 0._r8 + cpatch => CurrentSite%oldest_patch + do while(associated(cpatch)) + temp_in_C = temp_in_C + bc_in%t_veg24_pa(cpatch%patchno)*cpatch%area + cpatch => cpatch%younger + end do + temp_in_C = temp_in_C * area_inv - tfrz + + + !-----------------Cold Phenology--------------------! + + !Zero growing degree and chilling day counters + if (currentSite%lat > 0)then + ncdstart = 270 !Northern Hemisphere begining November + gddstart = 1 !Northern Hemisphere begining January + else + ncdstart = 120 !Southern Hemisphere beginning May + gddstart = 181 !Northern Hemisphere begining July + endif + + ! Count the number of chilling days over a seasonal window. + ! For comparing against GDD, we start calculating chilling + ! in the late autumn. + ! This value is used to determine the GDD exceedance threshold + if (hlm_day_of_year == ncdstart)then + currentSite%nchilldays = 0 + endif + + !Accumulate growing/chilling days after start of counting period + if (temp_in_C < ED_val_phen_chiltemp)then + currentSite%nchilldays = currentSite%nchilldays + 1 + endif + + !GDD accumulation function, which also depends on chilling days. + ! -68 + 638 * (-0.001 * ncd) + gdd_threshold = ED_val_phen_a + ED_val_phen_b*exp(ED_val_phen_c*real(currentSite%nchilldays,r8)) + + !Accumulate temperature of last 10 days. + currentSite%vegtemp_memory(2:num_vegtemp_mem) = currentSite%vegtemp_memory(1:num_vegtemp_mem-1) + currentSite%vegtemp_memory(1) = temp_in_C + + !count number of days for leaves off + ncolddays = 0 + do i_tmem = 1,num_vegtemp_mem + if (currentSite%vegtemp_memory(i_tmem) < ED_val_phen_coldtemp)then + ncolddays = ncolddays + 1 + endif + enddo + + ! Here is where we do the GDD accumulation calculation + ! + ! reset GDD on set dates + if (hlm_day_of_year == gddstart)then + currentSite%grow_deg_days = 0._r8 + endif + ! + ! accumulate the GDD using daily mean temperatures + ! Don't accumulate GDD during the growing season (that wouldn't make sense) + if (temp_in_C .gt. 0._r8 .and. currentSite%cstatus == phen_cstat_iscold) then + currentSite%grow_deg_days = currentSite%grow_deg_days + temp_in_C + endif + + !this logic is to prevent GDD accumulating after the leaves have fallen and before the + ! beginnning of the accumulation period, to prevend erroneous autumn leaf flushing. + if(model_day_int>365)then !only do this after the first year to prevent odd behaviour + + if(currentSite%lat .gt. 0.0_r8)then !Northern Hemisphere + ! In the north, don't accumulate when we are past the leaf fall date. + ! Accumulation starts on day 1 of year in NH. + ! The 180 is to prevent going into an 'always off' state after initialization + if( model_day_int .gt. currentSite%cleafoffdate.and.hlm_day_of_year.gt.180)then ! + currentSite%grow_deg_days = 0._r8 + endif + else !Southern Hemisphere + ! In the South, don't accumulate after the leaf off date, and before the start of + ! the accumulation phase (day 181). + if(model_day_int .gt. currentSite%cleafoffdate.and.hlm_day_of_year.lt.gddstart) then! + currentSite%grow_deg_days = 0._r8 + endif + endif + endif !year1 + + ! Calculate the number of days since the leaves last came on + ! and off. If this is the beginning of the simulation, that day might + ! not had occured yet, so set it to last year to get things rolling + + if (model_day_int < currentSite%cleafoffdate) then + dayssincecleafoff = model_day_int - (currentSite%cleafoffdate - 365) + else + dayssincecleafoff = model_day_int - currentSite%cleafoffdate + end if + + if (model_day_int < currentSite%cleafondate) then + dayssincecleafon = model_day_int - (currentSite%cleafondate-365) + else + dayssincecleafon = model_day_int - currentSite%cleafondate + end if + + + + !LEAF ON: COLD DECIDUOUS. Needs to + !1) have exceeded the growing degree day threshold + !2) The leaves should not be on already + !3) There should have been at least one chilling day in the counting period. + ! this prevents tropical or warm climate plants that are "cold-deciduous" + ! from ever re-flushing after they have reached their maximum age (thus + ! preventing them from competing + + if ( (currentSite%cstatus == phen_cstat_iscold .or. & + currentSite%cstatus == phen_cstat_nevercold) .and. & + (currentSite%grow_deg_days > gdd_threshold) .and. & + (dayssincecleafoff > ED_val_phen_mindayson) .and. & + (currentSite%nchilldays >= 1)) then + currentSite%cstatus = phen_cstat_notcold ! Set to not-cold status (leaves can come on) + currentSite%cleafondate = model_day_int + dayssincecleafon = 0 + currentSite%grow_deg_days = 0._r8 ! zero GDD for the rest of the year until counting season begins. + if ( debug ) write(fates_log(),*) 'leaves on' + endif !GDD + + + + + !LEAF OFF: COLD THRESHOLD + !Needs to: + !1) have exceeded the number of cold days threshold + !2) have exceeded the minimum leafon time. + !3) The leaves should not be off already + !4) The day of simulation should be larger than the counting period. + + + if ( (currentSite%cstatus == phen_cstat_notcold) .and. & + (model_day_int > num_vegtemp_mem) .and. & + (ncolddays > ED_val_phen_ncolddayslim) .and. & + (dayssincecleafon > ED_val_phen_mindayson) )then + + currentSite%grow_deg_days = 0._r8 ! The equations for Botta et al + ! are for calculations of + ! first flush, but if we dont + ! clear this value, it will cause + ! leaves to flush later in the year + currentSite%cstatus = phen_cstat_iscold ! alter status of site to 'leaves off' + currentSite%cleafoffdate = model_day_int ! record leaf off date + + if ( debug ) write(fates_log(),*) 'leaves off' + endif + + ! LEAF OFF: COLD LIFESPAN THRESHOLD + ! NOTE: Some areas of the planet will never generate a cold day + ! and thus %nchilldays will never go from zero to 1. The following logic + ! when coupled with this fact will essentially prevent cold-deciduous + ! plants from re-emerging in areas without at least some cold days + + if( (currentSite%cstatus == phen_cstat_notcold) .and. & + (dayssincecleafoff > 400)) then ! remove leaves after a whole year + ! when there is no 'off' period. + currentSite%grow_deg_days = 0._r8 + + currentSite%cstatus = phen_cstat_nevercold ! alter status of site to imply that this + ! site is never really cold enough + ! for cold deciduous + currentSite%cleafoffdate = model_day_int ! record leaf off date + + if ( debug ) write(fates_log(),*) 'leaves off' + endif + + !-----------------Drought Phenology--------------------! + ! Principles of drought-deciduos phenology model... + ! The 'is_drought' flag is false when leaves are on, and true when leaves area off. + ! The following sets those site-level flags, which are acted on in phenology_deciduos. + ! A* The leaves live for either the length of time the soil moisture is over the threshold + ! or the lifetime of the leaves, whichever is shorter. + ! B*: If the soil is only wet for a very short time, then the leaves stay on for 100 days + ! C*: The leaves are only permitted to come ON for a 60 day window around when they last came on, + ! to prevent 'flickering' on in response to wet season storms + ! D*: We don't allow anything to happen in the first ten days to allow the water memory window + ! to come into equlibirium. + ! E*: If the soil is always wet, the leaves come on at the beginning of the window, and then + ! last for their lifespan. + ! ISSUES + ! 1. It's not clear what water content we should track. Here we are tracking the top layer, + ! but we probably should track something like BTRAN, but BTRAN is defined for each PFT, + ! and there could potentially be more than one stress-dec PFT.... ? + ! 2. In the beginning, the window is set at an arbitrary time of the year, so the leaves + ! might come on in the dry season, using up stored reserves + ! for the stress-dec plants, and potentially killing them. To get around this, + ! we need to read in the 'leaf on' date from some kind of start-up file + ! but we would need that to happen for every resolution, etc. + ! 3. Will this methodology properly kill off the stress-dec trees where there is no + ! water stress? What about where the wet period coincides with the warm period? + ! We would just get them overlapping with the cold-dec trees, even though that isn't appropriate + ! Why don't the drought deciduous trees grow in the North? + ! Is cold decidousness maybe even the same as drought deciduosness there (and so does this + ! distinction actually matter??).... + + ! Accumulate surface water memory of last 10 days. + ! Liquid volume in ground layer (m3/m3) + do i_wmem = 1,numWaterMem-1 !shift memory along one + currentSite%water_memory(numWaterMem+1-i_wmem) = currentSite%water_memory(numWaterMem-i_wmem) + enddo + currentSite%water_memory(1) = bc_in%h2o_liqvol_sl(ilayer_swater) + + ! Calculate the mean water content over the last 10 days (m3/m3) + mean_10day_liqvol = sum(currentSite%water_memory(1:numWaterMem))/real(numWaterMem,r8) + + ! In drought phenology, we often need to force the leaves to stay + ! on or off as moisture fluctuates... + + ! Calculate days since leaves have come off, but make a provision + ! for the first year of simulation, we have to assume a leaf drop + ! date to start, so if that is in the future, set it to last year + + if (model_day_int < currentSite%dleafoffdate) then + dayssincedleafoff = model_day_int - (currentSite%dleafoffdate-365) + else + dayssincedleafoff = model_day_int - currentSite%dleafoffdate + endif + + ! the leaves are on. How long have they been on? + if (model_day_int < currentSite%dleafondate) then + dayssincedleafon = model_day_int - (currentSite%dleafondate-365) + else + dayssincedleafon = model_day_int - currentSite%dleafondate + endif + + ! LEAF ON: DROUGHT DECIDUOUS WETNESS + ! Here, we used a window of oppurtunity to determine if we are + ! close to the time when then leaves came on last year + + ! Has it been ... + ! a) a year, plus or minus 1 month since we last had leaf-on? + ! b) Has there also been at least a nominaly short amount of "leaf-off" + ! c) is the model day at least > 10 (let soil water spin-up) + ! Note that cold-starts begin in the "leaf-on" + ! status + if ( (currentSite%dstatus == phen_dstat_timeoff .or. & + currentSite%dstatus == phen_dstat_moistoff) .and. & + (model_day_int > numWaterMem) .and. & + (dayssincedleafon >= 365-30 .and. dayssincedleafon <= 365+30 ) .and. & + (dayssincedleafoff > ED_val_phen_doff_time) ) then + + ! If leaves are off, and have been off for at least a few days + ! and the time is consistent with the correct + ! time window... test if the moisture conditions allow for leaf-on + + if ( mean_10day_liqvol >= ED_val_phen_drought_threshold ) then + currentSite%dstatus = phen_dstat_moiston ! set status to leaf-on + currentSite%dleafondate = model_day_int ! save the model day we start flushing + dayssincedleafon = 0 + endif + endif + + ! LEAF ON: DROUGHT DECIDUOUS TIME EXCEEDANCE + ! If we still haven't done budburst by end of window, then force it + + ! If the status is "phen_dstat_moistoff", it means this site currently has + ! leaves off due to actual moisture limitations. + ! So we trigger bud-burst at the end of the month since + ! last year's bud-burst. If this is imposed, then we set the new + ! status to indicate bud-burst was forced by timing + + if( currentSite%dstatus == phen_dstat_moistoff ) then + if ( dayssincedleafon > 365+30 ) then + currentSite%dstatus = phen_dstat_timeon ! force budburst! + currentSite%dleafondate = model_day_int ! record leaf on date + dayssincedleafon = 0 + end if + end if + + ! But if leaves are off due to time, then we enforce + ! a longer cool-down (because this is a perrenially wet system) + + if(currentSite%dstatus == phen_dstat_timeoff ) then + if (dayssincedleafoff > min_daysoff_dforcedflush) then + currentSite%dstatus = phen_dstat_timeon ! force budburst! + currentSite%dleafondate = model_day_int ! record leaf on date + dayssincedleafon = 0 + end if + end if + + ! LEAF OFF: DROUGHT DECIDUOUS LIFESPAN - if the leaf gets to + ! the end of its useful life. A*, E* + ! i.e. Are the leaves rouhgly at the end of their lives? + + if ( (currentSite%dstatus == phen_dstat_moiston .or. & + currentSite%dstatus == phen_dstat_timeon ) .and. & + (dayssincedleafon > canopy_leaf_lifespan) )then + currentSite%dstatus = phen_dstat_timeoff !alter status of site to 'leaves off' + currentSite%dleafoffdate = model_day_int !record leaf on date + endif + + ! LEAF OFF: DROUGHT DECIDUOUS DRYNESS - if the soil gets too dry, + ! and the leaves have already been on a while... + + if ( (currentSite%dstatus == phen_dstat_moiston .or. & + currentSite%dstatus == phen_dstat_timeon ) .and. & + (model_day_int > numWaterMem) .and. & + (mean_10day_liqvol <= ED_val_phen_drought_threshold) .and. & + (dayssincedleafon > dleafon_drycheck ) ) then + currentSite%dstatus = phen_dstat_moistoff ! alter status of site to 'leaves off' + currentSite%dleafoffdate = model_day_int ! record leaf on date + endif + + call phenology_leafonoff(currentSite) + + end subroutine phenology + + ! ============================================================================ + subroutine phenology_leafonoff(currentSite) + ! + ! !DESCRIPTION: + ! Controls the leaf on and off economics + ! + ! !USES: + ! + ! !ARGUMENTS: + type(ed_site_type), intent(inout), target :: currentSite + ! + ! !LOCAL VARIABLES: + type(ed_patch_type) , pointer :: currentPatch + type(ed_cohort_type), pointer :: currentCohort + + real(r8) :: leaf_c ! leaf carbon [kg] + real(r8) :: sapw_c ! sapwood carbon [kg] + real(r8) :: struct_c ! structural wood carbon [kg] + real(r8) :: store_c ! storage carbon [kg] + real(r8) :: store_c_transfer_frac ! Fraction of storage carbon used to flush leaves + real(r8) :: totalmemory ! total memory of carbon [kg] + integer :: ipft + real(r8), parameter :: leaf_drop_fraction = 1.0_r8 + real(r8), parameter :: carbon_store_buffer = 0.10_r8 + real(r8) :: stem_drop_fraction + !------------------------------------------------------------------------ + + currentPatch => CurrentSite%oldest_patch + + do while(associated(currentPatch)) + currentCohort => currentPatch%tallest + do while(associated(currentCohort)) + + ipft = currentCohort%pft + + ! Retrieve existing leaf and storage carbon + + if(debug) call currentCohort%prt%CheckMassConservation(ipft,0) + + store_c = currentCohort%prt%GetState(store_organ, all_carbon_elements) + leaf_c = currentCohort%prt%GetState(leaf_organ, all_carbon_elements) + sapw_c = currentCohort%prt%GetState(sapw_organ, all_carbon_elements) + struct_c = currentCohort%prt%GetState(struct_organ, all_carbon_elements) + + stem_drop_fraction = EDPftvarcon_inst%phen_stem_drop_fraction(ipft) + + ! COLD LEAF ON + ! The site level flags signify that it is no-longer too cold + ! for leaves. Time to signal flushing + + if (prt_params%season_decid(ipft) == itrue)then + if ( currentSite%cstatus == phen_cstat_notcold )then ! we have just moved to leaves being on . + if (currentCohort%status_coh == leaves_off)then ! Are the leaves currently off? + currentCohort%status_coh = leaves_on ! Leaves are on, so change status to + ! stop flow of carbon out of bstore. + + if(store_c>nearzero) then + ! flush either the amount required from the laimemory, or -most- of the storage pool + ! RF: added a criterion to stop the entire store pool emptying and triggering termination mortality + ! n.b. this might not be necessary if we adopted a more gradual approach to leaf flushing... + store_c_transfer_frac = min((EDPftvarcon_inst%phenflush_fraction(ipft)* & + currentCohort%laimemory)/store_c,(1.0_r8-carbon_store_buffer)) + + if(prt_params%woody(ipft).ne.itrue)then + totalmemory=currentCohort%laimemory+currentCohort%sapwmemory+currentCohort%structmemory + store_c_transfer_frac = min((EDPftvarcon_inst%phenflush_fraction(ipft)* & + totalmemory)/store_c, (1.0_r8-carbon_store_buffer)) + endif + + else + store_c_transfer_frac = 0.0_r8 + end if + + ! This call will request that storage carbon will be transferred to + ! leaf tissues. It is specified as a fraction of the available storage + if(prt_params%woody(ipft) == itrue) then + + call PRTPhenologyFlush(currentCohort%prt, ipft, leaf_organ, store_c_transfer_frac) + currentCohort%laimemory = 0.0_r8 + + else + + ! Check that the stem drop fraction is set to non-zero amount otherwise flush all carbon store to leaves + if (stem_drop_fraction .gt. 0.0_r8) then + + call PRTPhenologyFlush(currentCohort%prt, ipft, leaf_organ, & + store_c_transfer_frac*currentCohort%laimemory/totalmemory) + + call PRTPhenologyFlush(currentCohort%prt, ipft, sapw_organ, & + store_c_transfer_frac*currentCohort%sapwmemory/totalmemory) + + call PRTPhenologyFlush(currentCohort%prt, ipft, struct_organ, & + store_c_transfer_frac*currentCohort%structmemory/totalmemory) + + else + + call PRTPhenologyFlush(currentCohort%prt, ipft, leaf_organ, & + store_c_transfer_frac) + + end if + + currentCohort%laimemory = 0.0_r8 + currentCohort%structmemory = 0.0_r8 + currentCohort%sapwmemory = 0.0_r8 + + endif + endif !pft phenology + endif ! growing season + + !COLD LEAF OFF + if (currentSite%cstatus == phen_cstat_nevercold .or. & + currentSite%cstatus == phen_cstat_iscold) then ! past leaf drop day? Leaves still on tree? + + if (currentCohort%status_coh == leaves_on) then ! leaves have not dropped + + ! leaf off occur on individuals bigger than specific size for grass + if (currentCohort%dbh > EDPftvarcon_inst%phen_cold_size_threshold(ipft) & + .or. prt_params%woody(ipft)==itrue) then + + ! This sets the cohort to the "leaves off" flag + currentCohort%status_coh = leaves_off + + ! Remember what the lai was (leaf mass actually) was for next year + ! the same amount back on in the spring... + + currentCohort%laimemory = leaf_c + + ! Drop Leaves (this routine will update the leaf state variables, + ! for carbon and any other element that are prognostic. It will + ! also track the turnover masses that will be sent to litter later on) + + call PRTDeciduousTurnover(currentCohort%prt,ipft, & + leaf_organ, leaf_drop_fraction) + + if(prt_params%woody(ipft).ne.itrue)then + + currentCohort%sapwmemory = sapw_c * stem_drop_fraction + + currentCohort%structmemory = struct_c * stem_drop_fraction + + call PRTDeciduousTurnover(currentCohort%prt,ipft, & + sapw_organ, stem_drop_fraction) + + call PRTDeciduousTurnover(currentCohort%prt,ipft, & + struct_organ, stem_drop_fraction) + + endif ! woody plant check + endif ! individual dbh size check + endif !leaf status + endif !currentSite status + endif !season_decid + + ! DROUGHT LEAF ON + ! Site level flag indicates it is no longer in drought condition + ! deciduous plants can flush + + if (prt_params%stress_decid(ipft) == itrue )then + + if (currentSite%dstatus == phen_dstat_moiston .or. & + currentSite%dstatus == phen_dstat_timeon )then + + ! we have just moved to leaves being on . + if (currentCohort%status_coh == leaves_off)then + + !is it the leaf-on day? Are the leaves currently off? + + currentCohort%status_coh = leaves_on ! Leaves are on, so change status to + ! stop flow of carbon out of bstore. + + if(store_c>nearzero) then + + store_c_transfer_frac = & + min((EDPftvarcon_inst%phenflush_fraction(ipft)*currentCohort%laimemory)/store_c, & + (1.0_r8-carbon_store_buffer)) + + if(prt_params%woody(ipft).ne.itrue)then + + totalmemory=currentCohort%laimemory+currentCohort%sapwmemory+currentCohort%structmemory + store_c_transfer_frac = min(EDPftvarcon_inst%phenflush_fraction(ipft)*totalmemory/store_c, & + (1.0_r8-carbon_store_buffer)) + + endif + + else + store_c_transfer_frac = 0.0_r8 + endif + + ! This call will request that storage carbon will be transferred to + ! leaf tissues. It is specified as a fraction of the available storage + if(prt_params%woody(ipft) == itrue) then + + call PRTPhenologyFlush(currentCohort%prt, ipft, & + leaf_organ, store_c_transfer_frac) + + currentCohort%laimemory = 0.0_r8 + + else + + ! Check that the stem drop fraction is set to non-zero amount otherwise flush all carbon store to leaves + if (stem_drop_fraction .gt. 0.0_r8) then + + call PRTPhenologyFlush(currentCohort%prt, ipft, leaf_organ, & + store_c_transfer_frac*currentCohort%laimemory/totalmemory) + + call PRTPhenologyFlush(currentCohort%prt, ipft, sapw_organ, & + store_c_transfer_frac*currentCohort%sapwmemory/totalmemory) + + call PRTPhenologyFlush(currentCohort%prt, ipft, struct_organ, & + store_c_transfer_frac*currentCohort%structmemory/totalmemory) + + else + + call PRTPhenologyFlush(currentCohort%prt, ipft, leaf_organ, & + store_c_transfer_frac) + + end if + + currentCohort%laimemory = 0.0_r8 + currentCohort%structmemory = 0.0_r8 + currentCohort%sapwmemory = 0.0_r8 + + endif ! woody plant check + endif !currentCohort status again? + endif !currentSite status + + !DROUGHT LEAF OFF + if (currentSite%dstatus == phen_dstat_moistoff .or. & + currentSite%dstatus == phen_dstat_timeoff) then + + if (currentCohort%status_coh == leaves_on) then ! leaves have not dropped + + ! This sets the cohort to the "leaves off" flag + currentCohort%status_coh = leaves_off + + ! Remember what the lai (leaf mass actually) was for next year + currentCohort%laimemory = leaf_c + + call PRTDeciduousTurnover(currentCohort%prt,ipft, & + leaf_organ, leaf_drop_fraction) + + if(prt_params%woody(ipft).ne.itrue)then + + currentCohort%sapwmemory = sapw_c * stem_drop_fraction + currentCohort%structmemory = struct_c * stem_drop_fraction + + call PRTDeciduousTurnover(currentCohort%prt,ipft, & + sapw_organ, stem_drop_fraction) + + call PRTDeciduousTurnover(currentCohort%prt,ipft, & + struct_organ, stem_drop_fraction) + endif + + endif + endif !status + endif !drought dec. + + if(debug) call currentCohort%prt%CheckMassConservation(ipft,1) + + currentCohort => currentCohort%shorter + enddo !currentCohort + + currentPatch => currentPatch%younger + + enddo !currentPatch + + end subroutine phenology_leafonoff + + + ! ===================================================================================== + + subroutine SeedIn( currentSite, bc_in ) + + ! ----------------------------------------------------------------------------------- + ! Flux from plants into the seed pool. + ! It is assumed that allocation to seed on living pools has already been calculated + ! at the daily time step. + ! Note: Some seed generation can occur during disturbance. It is assumed that + ! some plants use their storage upon death to create seeds, but this in only + ! triggered during non-fire and non-logging events. See + ! subroutine mortality_litter_fluxes() and DistributeSeeds(), look for + ! parameter allom_frbstor_repro + ! ----------------------------------------------------------------------------------- + + + ! !USES: + use EDTypesMod, only : area + use EDTypesMod, only : homogenize_seed_pfts + !use FatesInterfaceTypesMod, only : hlm_use_fixed_biogeog ! For future reduced complexity? + ! + ! !ARGUMENTS + type(ed_site_type), intent(inout), target :: currentSite + type(bc_in_type), intent(in) :: bc_in + + type(ed_patch_type), pointer :: currentPatch + type(litter_type), pointer :: litt + type(ed_cohort_type), pointer :: currentCohort + type(site_massbal_type), pointer :: site_mass + + integer :: pft + real(r8) :: store_m_to_repro ! mass sent from storage to reproduction upon death [kg/plant] + real(r8) :: site_seed_rain(maxpft) ! This is the sum of seed-rain for the site [kg/site/day] + real(r8) :: seed_in_external ! Mass of externally generated seeds [kg/m2/day] + real(r8) :: seed_stoich ! Mass ratio of nutrient per C12 in seeds [kg/kg] + real(r8) :: repro_mass_prod ! Mass of reproductive material produced [kg/day] ; added by ahb 7/8/2021 + real(r8), parameter :: repro_frac_seed = 0.5 !added by ahb 7/12/2021; move this to param file + real(r8) :: seed_prod ! Seed produced in this dynamics step [kg/day] + real(r8) :: non_seed_repro_prod ! Mass of non-seed reproductive material produced [kg/day] ; added by ahb 7/10/2021 + integer :: n_litt_types ! number of litter element types (c,n,p, etc) + integer :: el ! loop counter for litter element types + integer :: element_id ! element id consistent with parteh/PRTGenericMod.F90 + !------------------------------------------------------------------------------------ + + do el = 1, num_elements + + site_seed_rain(:) = 0._r8 + + element_id = element_list(el) + + site_mass => currentSite%mass_balance(el) + + ! Loop over all patches and sum up the seed input for each PFT + currentPatch => currentSite%oldest_patch + do while (associated(currentPatch)) + + currentCohort => currentPatch%tallest + !litt => currentPatch%litter(el) !added by ahb + do while (associated(currentCohort)) + + pft = currentCohort%pft + + ! a certain fraction of bstore might go to clonal reproduction when plants die + ! (since this is only applied to the dying portion of the cohort + ! we do not actually pair down the storage via PARTEH, instead + ! we just make sure that we don't send a portion of the storage + ! to the litter in CWDInput) + ! units = [kg/ha/day] = [kg] * [fraction] * [plants/ha/year] * [year/day] + store_m_to_repro = -currentCohort%prt%GetState(store_organ,element_id) * & + EDPftvarcon_inst%allom_frbstor_repro(pft)*currentCohort%dndt*years_per_day + + ! Transfer all reproductive tissues into seed production + ! The following call to PRTReproRelease, will return the mass + ! of seeds [kg] released by the plant, per the mass_fraction + ! specified as input. This routine will also remove the mass + ! from the parteh state-variable. + + + + + + !START ahb changes + + !-------------------------------------------------------------------------- + !original code + call PRTReproRelease(currentCohort%prt,repro_organ,element_id, & + 1.0_r8, seed_prod) + !-------------------------------------------------------------------------- + + !-------------------------------------------------------------------------- + !ahb's new code + !the original code sends all reproductive tissue to seed + !This new code, added by ahb, is designed to send some reproductive biomass + !straight to the leaf litter pool to account for non-seed reproductive + !biomass. For now, ahb does this after the call to the + !PRTReproRelease function, but a better solution would probably be to do + !this within the PRTReproRelease module in parteh/PRTLossFluxesMod.F90::L342 + !by adding new live reproductive organs (ahb needs help with this). + + !call PRTReproRelease(currentCohort%prt,repro_organ,element_id, & + ! 1.0_r8, repro_mass_prod) !ahb changed from seed_prod to repro_mass_prod + + !seed_prod = repro_mass_prod * repro_frac_seed ! seed production per ind. (ahb) + ! only a fraction of reproductive (ahb) + ! mass is seed (ahb) + + !non_seed_repro_prod = repro_mass_prod * (1.0_r8 - repro_frac_seed) !non-seed repro (ahb) + !mass per ind. (ahb) + + !litt%seed_decay(pft) = non_seed_repro_prod * currentCohort%n / area !send non-seed repro mass to seed decay pool + !--------------------------------------------------------------------------- + + !END ahb changes + + + + + + if(element_id==carbon12_element)then + currentcohort%seed_prod = seed_prod + end if + + site_seed_rain(pft) = site_seed_rain(pft) + & + (seed_prod * currentCohort%n + store_m_to_repro) + + currentCohort => currentCohort%shorter + enddo !cohort loop + + currentPatch => currentPatch%younger + enddo + + ! We can choose to homogenize seeds. This is simple, we just + ! add up all the seed from each pft at the site level, and then + ! equally distribute to the PFT pools + if ( homogenize_seed_pfts ) then + site_seed_rain(1:numpft) = sum(site_seed_rain(:))/real(numpft,r8) + end if + + + ! Loop over all patches again and disperse the mixed seeds into the input flux + ! arrays + + ! Loop over all patches and sum up the seed input for each PFT + currentPatch => currentSite%oldest_patch + do while (associated(currentPatch)) + + litt => currentPatch%litter(el) + do pft = 1,numpft + + if(currentSite%use_this_pft(pft).eq.itrue)then + ! Seed input from local sources (within site) + litt%seed_in_local(pft) = litt%seed_in_local(pft) + site_seed_rain(pft)/area + + !new code 7/14/2021 ahb + !-------------------------------- + litt%seed_decay(pft) = litt%seed_in_local(pft) * (1.0_r8 - repro_frac_seed) !ahb + !-------------------------------- + + ! If there is forced external seed rain, we calculate the input mass flux + ! from the different elements, usung the seed optimal stoichiometry + ! for non-carbon + select case(element_id) + case(carbon12_element) + seed_stoich = 1._r8 + case(nitrogen_element) + seed_stoich = prt_params%nitr_recr_stoich(pft) + case(phosphorus_element) + seed_stoich = prt_params%phos_recr_stoich(pft) + case default + write(fates_log(), *) 'undefined element specified' + write(fates_log(), *) 'while defining forced external seed mass flux' + call endrun(msg=errMsg(sourcefile, __LINE__)) + end select + + ! Seed input from external sources (user param seed rain, or dispersal model) + seed_in_external = seed_stoich*EDPftvarcon_inst%seed_suppl(pft)*years_per_day + litt%seed_in_extern(pft) = litt%seed_in_extern(pft) + seed_in_external + + ! Seeds entering externally [kg/site/day] + site_mass%seed_in = site_mass%seed_in + seed_in_external*currentPatch%area + end if !use this pft + enddo + + + currentPatch => currentPatch%younger + enddo + + end do + + return + end subroutine SeedIn + + ! ============================================================================ + + subroutine SeedDecay( litt ) + ! + ! !DESCRIPTION: + ! Flux from seed pool into leaf litter pool + ! + ! !ARGUMENTS + type(litter_type) :: litt + ! + ! !LOCAL VARIABLES: + integer :: pft + !---------------------------------------------------------------------- + + ! default value from Liscke and Loffler 2006 ; making this a PFT-specific parameter + ! decays the seed pool according to exponential model + ! seed_decay_rate is in yr-1 + ! seed_decay is kg/day + ! Assume that decay rates are same for all chemical species + + do pft = 1,numpft + litt%seed_decay(pft) = litt%seed(pft) * & + EDPftvarcon_inst%seed_decay_rate(pft)*years_per_day + & ! "+ &" added by ahb (7/10/2021) + litt%seed_decay(pft) ! line added by ahb so that the flux from non-seed reproductive + ! biomass (from SeedIn subroutine) is not lost (7/10/2021) + + litt%seed_germ_decay(pft) = litt%seed_germ(pft) * & + EDPftvarcon_inst%seed_decay_rate(pft)*years_per_day + + enddo + + return + end subroutine SeedDecay + + ! ============================================================================ + subroutine SeedGermination( litt, cold_stat, drought_stat ) + ! + ! !DESCRIPTION: + ! Flux from seed pool into sapling pool + ! + ! !USES: + + ! + ! !ARGUMENTS + type(litter_type) :: litt + integer, intent(in) :: cold_stat ! Is the site in cold leaf-off status? + integer, intent(in) :: drought_stat ! Is the site in drought leaf-off status? + ! + ! !LOCAL VARIABLES: + integer :: pft + + + real(r8), parameter :: max_germination = 1.0_r8 ! Cap on germination rates. + ! KgC/m2/yr Lishcke et al. 2009 + + ! Turning of this cap? because the cap will impose changes on proportionality + ! of nutrients. (RGK 02-2019) + !real(r8), parameter :: max_germination = 1.e6_r8 ! Force to very high number + + !---------------------------------------------------------------------- + + ! germination_rate is being pulled to PFT parameter; units are 1/yr + ! thus the mortality rate of seed -> recruit (in units of carbon) + ! is seed_decay_rate(p)/germination_rate(p) + ! and thus the mortality rate (in units of individuals) is the product of + ! that times the ratio of (hypothetical) seed mass to recruit biomass + + do pft = 1,numpft + litt%seed_germ_in(pft) = min(litt%seed(pft) * EDPftvarcon_inst%germination_rate(pft), & + max_germination)*years_per_day + + !set the germination only under the growing season...c.xu + + if ((prt_params%season_decid(pft) == itrue ) .and. & + (any(cold_stat == [phen_cstat_nevercold,phen_cstat_iscold]))) then + litt%seed_germ_in(pft) = 0.0_r8 + endif + if ((prt_params%stress_decid(pft) == itrue ) .and. & + (any(drought_stat == [phen_dstat_timeoff,phen_dstat_moistoff]))) then + litt%seed_germ_in(pft) = 0.0_r8 + end if + + + enddo + + end subroutine SeedGermination + + ! ===================================================================================== + + + + + + ! ===================================================================================== + + subroutine recruitment( currentSite, currentPatch, bc_in ) + ! + ! !DESCRIPTION: + ! spawn new cohorts of juveniles of each PFT + ! + ! !USES: + use FatesInterfaceTypesMod, only : hlm_use_ed_prescribed_phys + ! + ! !ARGUMENTS + type(ed_site_type), intent(inout), target :: currentSite + type(ed_patch_type), intent(inout), pointer :: currentPatch + type(bc_in_type), intent(in) :: bc_in + ! + ! !LOCAL VARIABLES: + class(prt_vartypes), pointer :: prt + integer :: ft + type (ed_cohort_type) , pointer :: temp_cohort + type (litter_type), pointer :: litt ! The litter object (carbon right now) + type(site_massbal_type), pointer :: site_mass ! For accounting total in-out mass fluxes + integer :: cohortstatus + integer :: el ! loop counter for element + integer :: element_id ! element index consistent with definitions in PRTGenericMod + integer :: iage ! age loop counter for leaf age bins + integer,parameter :: recruitstatus = 1 !weather it the new created cohorts is recruited or initialized + real(r8) :: c_leaf ! target leaf biomass [kgC] + real(r8) :: c_fnrt ! target fine root biomass [kgC] + real(r8) :: c_sapw ! target sapwood biomass [kgC] + real(r8) :: a_sapw ! target sapwood cross section are [m2] (dummy) + real(r8) :: c_agw ! target Above ground biomass [kgC] + real(r8) :: c_bgw ! target Below ground biomass [kgC] + real(r8) :: c_struct ! target Structural biomass [kgc] + real(r8) :: c_store ! target Storage biomass [kgC] + real(r8) :: m_leaf ! leaf mass (element agnostic) [kg] + real(r8) :: m_fnrt ! fine-root mass (element agnostic) [kg] + real(r8) :: m_sapw ! sapwood mass (element agnostic) [kg] + real(r8) :: m_agw ! AG wood mass (element agnostic) [kg] + real(r8) :: m_bgw ! BG wood mass (element agnostic) [kg] + real(r8) :: m_struct ! structural mass (element agnostic) [kg] + real(r8) :: m_store ! storage mass (element agnostic) [kg] + real(r8) :: m_repro ! reproductive mass (element agnostic) [kg] + real(r8) :: mass_avail ! The mass of each nutrient/carbon available in the seed_germination pool [kg] + real(r8) :: mass_demand ! Total mass demanded by the plant to achieve the stoichiometric targets + ! of all the organs in the recruits. Used for both [kg per plant] and [kg per cohort] + real(r8) :: stem_drop_fraction + + !---------------------------------------------------------------------- + + allocate(temp_cohort) ! create temporary cohort + call zero_cohort(temp_cohort) + + + do ft = 1,numpft + if(currentSite%use_this_pft(ft).eq.itrue)then + temp_cohort%canopy_trim = init_recruit_trim + temp_cohort%pft = ft + temp_cohort%hite = EDPftvarcon_inst%hgt_min(ft) + temp_cohort%coage = 0.0_r8 + stem_drop_fraction = EDPftvarcon_inst%phen_stem_drop_fraction(ft) + + call h2d_allom(temp_cohort%hite,ft,temp_cohort%dbh) + + ! Initialize live pools + call bleaf(temp_cohort%dbh,ft,temp_cohort%canopy_trim,c_leaf) + call bfineroot(temp_cohort%dbh,ft,temp_cohort%canopy_trim,c_fnrt) + call bsap_allom(temp_cohort%dbh,ft,temp_cohort%canopy_trim,a_sapw, c_sapw) + call bagw_allom(temp_cohort%dbh,ft,c_agw) + call bbgw_allom(temp_cohort%dbh,ft,c_bgw) + call bdead_allom(c_agw,c_bgw,c_sapw,ft,c_struct) + call bstore_allom(temp_cohort%dbh,ft,temp_cohort%canopy_trim,c_store) + + ! Default assumption is that leaves are on + cohortstatus = leaves_on + temp_cohort%laimemory = 0.0_r8 + temp_cohort%sapwmemory = 0.0_r8 + temp_cohort%structmemory = 0.0_r8 + + + ! But if the plant is seasonally (cold) deciduous, and the site status is flagged + ! as "cold", then set the cohort's status to leaves_off, and remember the leaf biomass + if ((prt_params%season_decid(ft) == itrue) .and. & + (any(currentSite%cstatus == [phen_cstat_nevercold,phen_cstat_iscold]))) then + temp_cohort%laimemory = c_leaf + c_leaf = 0.0_r8 + + ! If plant is not woody then set sapwood and structural biomass as well + if (prt_params%woody(ft).ne.itrue) then + temp_cohort%sapwmemory = c_sapw * stem_drop_fraction + temp_cohort%structmemory = c_struct * stem_drop_fraction + c_sapw = (1.0_r8 - stem_drop_fraction) * c_sapw + c_struct = (1.0_r8 - stem_drop_fraction) * c_struct + endif + cohortstatus = leaves_off + endif + + ! Or.. if the plant is drought deciduous, and the site status is flagged as + ! "in a drought", then likewise, set the cohort's status to leaves_off, and remember leaf + ! biomass + if ((prt_params%stress_decid(ft) == itrue) .and. & + (any(currentSite%dstatus == [phen_dstat_timeoff,phen_dstat_moistoff]))) then + temp_cohort%laimemory = c_leaf + c_leaf = 0.0_r8 + + ! If plant is not woody then set sapwood and structural biomass as well + if(prt_params%woody(ft).ne.itrue)then + temp_cohort%sapwmemory = c_sapw * stem_drop_fraction + temp_cohort%structmemory = c_struct * stem_drop_fraction + c_sapw = (1.0_r8 - stem_drop_fraction) * c_sapw + c_struct = (1.0_r8 - stem_drop_fraction) * c_struct + endif + cohortstatus = leaves_off + endif + + + ! Cycle through available carbon and nutrients, find the limiting element + ! to dictate the total number of plants that can be generated + + if ( (hlm_use_ed_prescribed_phys .eq. ifalse) .or. & + (EDPftvarcon_inst%prescribed_recruitment(ft) .lt. 0._r8) ) then + + temp_cohort%n = 1.e20_r8 + + do el = 1,num_elements + + element_id = element_list(el) + select case(element_id) + case(carbon12_element) + + mass_demand = c_struct+c_leaf+c_fnrt+c_sapw+c_store + + case(nitrogen_element) + + mass_demand = & + c_struct*prt_params%nitr_stoich_p2(ft,prt_params%organ_param_id(struct_organ)) + & + c_leaf*prt_params%nitr_stoich_p2(ft,prt_params%organ_param_id(leaf_organ)) + & + c_fnrt*prt_params%nitr_stoich_p2(ft,prt_params%organ_param_id(fnrt_organ)) + & + c_sapw*prt_params%nitr_stoich_p2(ft,prt_params%organ_param_id(sapw_organ)) + & + StorageNutrientTarget(ft, element_id, & + c_leaf*prt_params%nitr_stoich_p2(ft,prt_params%organ_param_id(leaf_organ)), & + c_fnrt*prt_params%nitr_stoich_p2(ft,prt_params%organ_param_id(fnrt_organ)), & + c_sapw*prt_params%nitr_stoich_p2(ft,prt_params%organ_param_id(sapw_organ)), & + c_struct*prt_params%nitr_stoich_p2(ft,prt_params%organ_param_id(struct_organ))) + + case(phosphorus_element) + + mass_demand = & + c_struct*prt_params%phos_stoich_p2(ft,prt_params%organ_param_id(struct_organ)) + & + c_leaf*prt_params%phos_stoich_p2(ft,prt_params%organ_param_id(leaf_organ)) + & + c_fnrt*prt_params%phos_stoich_p2(ft,prt_params%organ_param_id(fnrt_organ)) + & + c_sapw*prt_params%phos_stoich_p2(ft,prt_params%organ_param_id(sapw_organ)) + & + StorageNutrientTarget(ft, element_id, & + c_leaf*prt_params%phos_stoich_p2(ft,prt_params%organ_param_id(leaf_organ)), & + c_fnrt*prt_params%phos_stoich_p2(ft,prt_params%organ_param_id(fnrt_organ)), & + c_sapw*prt_params%phos_stoich_p2(ft,prt_params%organ_param_id(sapw_organ)), & + c_struct*prt_params%phos_stoich_p2(ft,prt_params%organ_param_id(struct_organ))) + + case default + write(fates_log(),*) 'Undefined element type in recruitment' + call endrun(msg=errMsg(sourcefile, __LINE__)) + end select + + mass_avail = currentPatch%area * currentPatch%litter(el)%seed_germ(ft) + + ! ------------------------------------------------------------------------ + ! Update number density if this is the limiting mass + ! ------------------------------------------------------------------------ + + temp_cohort%n = min(temp_cohort%n, mass_avail/mass_demand) + + end do + + + else + ! prescribed recruitment rates. number per sq. meter per year + temp_cohort%n = currentPatch%area * & + EDPftvarcon_inst%prescribed_recruitment(ft) * & + hlm_freq_day + endif + + ! Only bother allocating a new cohort if there is a reasonable amount of it + any_recruits: if (temp_cohort%n > min_n_safemath )then + + ! ----------------------------------------------------------------------------- + ! PART II. + ! Initialize the PARTEH object, and determine the initial masses of all + ! organs and elements. + ! ----------------------------------------------------------------------------- + prt => null() + call InitPRTObject(prt) + + do el = 1,num_elements + + element_id = element_list(el) + + ! If this is carbon12, then the initialization is straight forward + ! otherwise, we use stoichiometric ratios + select case(element_id) + case(carbon12_element) + + m_struct = c_struct + m_leaf = c_leaf + m_fnrt = c_fnrt + m_sapw = c_sapw + m_store = c_store + m_repro = 0._r8 + + case(nitrogen_element) + + m_struct = c_struct*prt_params%nitr_stoich_p2(ft,prt_params%organ_param_id(struct_organ)) + m_leaf = c_leaf*prt_params%nitr_stoich_p2(ft,prt_params%organ_param_id(leaf_organ)) + m_fnrt = c_fnrt*prt_params%nitr_stoich_p2(ft,prt_params%organ_param_id(fnrt_organ)) + m_sapw = c_sapw*prt_params%nitr_stoich_p2(ft,prt_params%organ_param_id(sapw_organ)) + m_store = StorageNutrientTarget(ft, element_id, m_leaf, m_fnrt, m_sapw, m_struct ) + m_repro = 0._r8 + + case(phosphorus_element) + + m_struct = c_struct*prt_params%phos_stoich_p2(ft,prt_params%organ_param_id(struct_organ)) + m_leaf = c_leaf*prt_params%phos_stoich_p2(ft,prt_params%organ_param_id(leaf_organ)) + m_fnrt = c_fnrt*prt_params%phos_stoich_p2(ft,prt_params%organ_param_id(fnrt_organ)) + m_sapw = c_sapw*prt_params%phos_stoich_p2(ft,prt_params%organ_param_id(sapw_organ)) + m_store = StorageNutrientTarget(ft, element_id, m_leaf, m_fnrt, m_sapw, m_struct ) + m_repro = 0._r8 + + end select + + select case(hlm_parteh_mode) + case (prt_carbon_allom_hyp,prt_cnp_flex_allom_hyp ) + + ! Put all of the leaf mass into the first bin + call SetState(prt,leaf_organ, element_id,m_leaf,1) + do iage = 2,nleafage + call SetState(prt,leaf_organ, element_id,0._r8,iage) + end do + + call SetState(prt,fnrt_organ, element_id, m_fnrt) + call SetState(prt,sapw_organ, element_id, m_sapw) + call SetState(prt,store_organ, element_id, m_store) + call SetState(prt,struct_organ, element_id, m_struct) + call SetState(prt,repro_organ, element_id, m_repro) + + case default + write(fates_log(),*) 'Unspecified PARTEH module during create_cohort' + call endrun(msg=errMsg(sourcefile, __LINE__)) + end select + + site_mass => currentSite%mass_balance(el) + + ! Remove mass from the germination pool. However, if we are use prescribed physiology, + ! AND the forced recruitment model, then we are not realling using the prognostic + ! seed_germination model, so we have to short circuit things. We send all of the + ! seed germination mass to an outflux pool, and use an arbitrary generic input flux + ! to balance out the new recruits. + + if ( (hlm_use_ed_prescribed_phys .eq. itrue ) .and. & + (EDPftvarcon_inst%prescribed_recruitment(ft) .ge. 0._r8 )) then + + site_mass%flux_generic_in = site_mass%flux_generic_in + & + temp_cohort%n*(m_struct + m_leaf + m_fnrt + m_sapw + m_store + m_repro) + + site_mass%flux_generic_out = site_mass%flux_generic_out + & + currentPatch%area * currentPatch%litter(el)%seed_germ(ft) + + currentPatch%litter(el)%seed_germ(ft) = 0._r8 + + + else + + currentPatch%litter(el)%seed_germ(ft) = currentPatch%litter(el)%seed_germ(ft) - & + temp_cohort%n / currentPatch%area * & + (m_struct + m_leaf + m_fnrt + m_sapw + m_store + m_repro) + + end if + + + + end do + + ! This call cycles through the initial conditions, and makes sure that they + ! are all initialized. + ! ----------------------------------------------------------------------------------- + + call prt%CheckInitialConditions() + + ! This initializes the cohort + call create_cohort(currentSite,currentPatch, temp_cohort%pft, temp_cohort%n, & + temp_cohort%hite, temp_cohort%coage, temp_cohort%dbh, prt, & + temp_cohort%laimemory, temp_cohort%sapwmemory, temp_cohort%structmemory, & + cohortstatus, recruitstatus, & + temp_cohort%canopy_trim, currentPatch%NCL_p, currentSite%spread, bc_in) + + ! Note that if hydraulics is on, the number of cohorts may had + ! changed due to hydraulic constraints. + ! This constaint is applied during "create_cohort" subroutine. + + ! keep track of how many individuals were recruited for passing to history + currentSite%recruitment_rate(ft) = currentSite%recruitment_rate(ft) + temp_cohort%n + + + endif any_recruits + endif !use_this_pft + enddo !pft loop + + deallocate(temp_cohort) ! delete temporary cohort + + end subroutine recruitment + + ! ============================================================================ + + subroutine CWDInput( currentSite, currentPatch, litt, bc_in) + + ! + ! !DESCRIPTION: + ! Generate litter fields from turnover. + ! Note, that the when this is called, the number density of the plants + ! has not been reduced from non-mortal turnover yet. + ! Thus, we need to avoid double counting losses from dying trees + ! and turnover in dying trees. + ! + ! !USES: + use SFParamsMod , only : SF_val_CWD_frac + + ! + ! !ARGUMENTS + type(ed_site_type), intent(inout), target :: currentSite + type(ed_patch_type),intent(inout), target :: currentPatch + type(litter_type),intent(inout),target :: litt + type(bc_in_type),intent(in) :: bc_in + + ! + ! !LOCAL VARIABLES: + type(ed_cohort_type), pointer :: currentCohort + type(site_fluxdiags_type), pointer :: flux_diags + type(site_massbal_type), pointer :: site_mass + integer :: c + real(r8) :: dead_n ! total understorey dead tree density + real(r8) :: dead_n_dlogging ! direct logging understory dead-tree density + real(r8) :: dead_n_ilogging ! indirect understory dead-tree density (logging) + real(r8) :: dead_n_natural ! understory dead density not associated + ! with direct logging + real(r8) :: leaf_m ! mass of the element of interest in the + ! leaf [kg] + real(r8) :: fnrt_m ! fine-root [kg] + real(r8) :: sapw_m ! sapwood [kg] + real(r8) :: struct_m ! structural [kg] + real(r8) :: store_m ! storage [kg] + real(r8) :: repro_m ! reproductive [kg] + real(r8) :: leaf_m_turnover ! leaf turnover [kg] + real(r8) :: fnrt_m_turnover + real(r8) :: sapw_m_turnover + real(r8) :: struct_m_turnover + real(r8) :: store_m_turnover + real(r8) :: repro_m_turnover + real(r8) :: dcmpy_frac ! Fraction of mass sent to decomposability pool + real(r8) :: plant_dens ! Number of plants per m2 + real(r8) :: bg_cwd_tot ! Total below-ground coarse woody debris + ! input flux + real(r8) :: root_fines_tot ! Total below-ground fine root coarse + ! woody debris + integer :: element_id ! element id consistent with parteh/PRTGenericMod.F90 + + real(r8) :: trunk_wood ! carbon flux into trunk products kgC/day/site + integer :: ilyr + integer :: pft + integer :: dcmpy ! decomposability pool index + integer :: numlevsoil ! Actual number of soil layers + !---------------------------------------------------------------------- + + ! ----------------------------------------------------------------------------------- + ! Other direct litter fluxes happen in phenology and in spawn_patches. + ! ----------------------------------------------------------------------------------- + + numlevsoil = currentSite%nlevsoil + + element_id = litt%element_id + + ! Object tracking flux diagnostics for each element + flux_diags => currentSite%flux_diags(element_pos(element_id)) + + ! Object tracking site level mass balance for each element + site_mass => currentSite%mass_balance(element_pos(element_id)) + + currentCohort => currentPatch%shortest + do while(associated(currentCohort)) + pft = currentCohort%pft + + call set_root_fraction(currentSite%rootfrac_scr, pft, currentSite%zi_soil, & + bc_in%max_rooting_depth_index_col) + + leaf_m_turnover = currentCohort%prt%GetTurnover(leaf_organ,element_id) + store_m_turnover = currentCohort%prt%GetTurnover(store_organ,element_id) + fnrt_m_turnover = currentCohort%prt%GetTurnover(fnrt_organ,element_id) + sapw_m_turnover = currentCohort%prt%GetTurnover(sapw_organ,element_id) + struct_m_turnover = currentCohort%prt%GetTurnover(struct_organ,element_id) + repro_m_turnover = currentCohort%prt%GetTurnover(repro_organ,element_id) + + leaf_m = currentCohort%prt%GetState(leaf_organ,element_id) + store_m = currentCohort%prt%GetState(store_organ,element_id) + fnrt_m = currentCohort%prt%GetState(fnrt_organ,element_id) + sapw_m = currentCohort%prt%GetState(sapw_organ,element_id) + struct_m = currentCohort%prt%GetState(struct_organ,element_id) + repro_m = currentCohort%prt%GetState(repro_organ,element_id) + + plant_dens = currentCohort%n/currentPatch%area + + ! --------------------------------------------------------------------------------- + ! PART 1 Litter fluxes from non-mortal tissue turnovers Kg/m2/day + ! Important note: Turnover has already been removed from the cohorts. + ! So, in the next part of this algorithm, when we send the biomass + ! from dying trees to the litter pools, we don't have to worry + ! about double counting. + ! --------------------------------------------------------------------------------- + + flux_diags%leaf_litter_input(pft) = & + flux_diags%leaf_litter_input(pft) + & + leaf_m_turnover * currentCohort%n + + root_fines_tot = (fnrt_m_turnover + store_m_turnover ) * & + plant_dens + + do dcmpy=1,ndcmpy + dcmpy_frac = GetDecompyFrac(pft,leaf_organ,dcmpy) + litt%leaf_fines_in(dcmpy) = litt%leaf_fines_in(dcmpy) + & + (leaf_m_turnover+repro_m_turnover) * plant_dens * dcmpy_frac + + dcmpy_frac = GetDecompyFrac(pft,fnrt_organ,dcmpy) + do ilyr = 1, numlevsoil + litt%root_fines_in(dcmpy,ilyr) = litt%root_fines_in(dcmpy,ilyr) + & + currentSite%rootfrac_scr(ilyr) * root_fines_tot * dcmpy_frac + end do + end do + + flux_diags%root_litter_input(pft) = & + flux_diags%root_litter_input(pft) + & + (fnrt_m_turnover + store_m_turnover ) * currentCohort%n + + + ! Assumption: turnover from deadwood and sapwood are lumped together in CWD pool + + do c = 1,ncwd + litt%ag_cwd_in(c) = litt%ag_cwd_in(c) + & + (sapw_m_turnover + struct_m_turnover) * & + SF_val_CWD_frac(c) * plant_dens * & + prt_params%allom_agb_frac(pft) + + flux_diags%cwd_ag_input(c) = flux_diags%cwd_ag_input(c) + & + (struct_m_turnover + sapw_m_turnover) * SF_val_CWD_frac(c) * & + prt_params%allom_agb_frac(pft) * currentCohort%n + + bg_cwd_tot = (sapw_m_turnover + struct_m_turnover) * & + SF_val_CWD_frac(c) * plant_dens * & + (1.0_r8-prt_params%allom_agb_frac(pft)) + + do ilyr = 1, numlevsoil + litt%bg_cwd_in(c,ilyr) = litt%bg_cwd_in(c,ilyr) + & + bg_cwd_tot * currentSite%rootfrac_scr(ilyr) + end do + + flux_diags%cwd_bg_input(c) = flux_diags%cwd_bg_input(c) + & + bg_cwd_tot*currentPatch%area + + enddo + + + ! --------------------------------------------------------------------------------- + ! PART 2 Litter fluxes from non-disturbance inducing mortality. Kg/m2/day + ! --------------------------------------------------------------------------------- + + ! Total number of dead (n/m2/day) + dead_n = -1.0_r8 * currentCohort%dndt/currentPatch%area*years_per_day + + if(currentCohort%canopy_layer > 1)then + + ! Total number of dead understory from direct logging + ! (it is possible that large harvestable trees are in the understory) + dead_n_dlogging = currentCohort%lmort_direct * & + currentCohort%n/currentPatch%area + + ! Total number of dead understory from indirect logging + dead_n_ilogging = (currentCohort%lmort_collateral + currentCohort%lmort_infra) * & + currentCohort%n/currentPatch%area + + else + + ! All mortality from logging in the canopy is + ! is disturbance generating + + dead_n_dlogging = 0._r8 + dead_n_ilogging = 0._r8 + + end if + + 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 + + root_fines_tot = dead_n * (fnrt_m + & + store_m*(1._r8-EDPftvarcon_inst%allom_frbstor_repro(pft)) ) + + do dcmpy=1,ndcmpy + + dcmpy_frac = GetDecompyFrac(pft,leaf_organ,dcmpy) + litt%leaf_fines_in(dcmpy) = litt%leaf_fines_in(dcmpy) + & + (leaf_m+repro_m) * dead_n * dcmpy_frac + + dcmpy_frac = GetDecompyFrac(pft,fnrt_organ,dcmpy) + do ilyr = 1, numlevsoil + litt%root_fines_in(dcmpy,ilyr) = litt%root_fines_in(dcmpy,ilyr) + & + root_fines_tot * currentSite%rootfrac_scr(ilyr) * dcmpy_frac + end do + end do + + flux_diags%root_litter_input(pft) = & + flux_diags%root_litter_input(pft) + & + root_fines_tot*currentPatch%area + + ! Track CWD inputs from dead plants + + do c = 1,ncwd + + ! Below-ground + + bg_cwd_tot = (struct_m + sapw_m) * & + SF_val_CWD_frac(c) * dead_n * & + (1.0_r8-prt_params%allom_agb_frac(pft)) + + do ilyr = 1, numlevsoil + litt%bg_cwd_in(c,ilyr) = litt%bg_cwd_in(c,ilyr) + & + currentSite%rootfrac_scr(ilyr) * bg_cwd_tot + end do + + flux_diags%cwd_bg_input(c) = flux_diags%cwd_bg_input(c) + & + bg_cwd_tot * currentPatch%area + + ! Send AGB component of boles from logging activities into the litter. + ! This includes fluxes from indirect modes of death, as well as the + ! non-exported boles due to direct harvesting. + + if (c==ncwd) then + + + trunk_wood = (struct_m + sapw_m) * & + SF_val_CWD_frac(c) * dead_n_dlogging * & + prt_params%allom_agb_frac(pft) + + site_mass%wood_product = site_mass%wood_product + & + trunk_wood * currentPatch%area * logging_export_frac + + ! Add AG wood to litter from the non-exported fraction of wood + ! from direct anthro sources + + 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) + & + trunk_wood * (1._r8-logging_export_frac) * currentPatch%area + + ! Add AG wood to litter from indirect anthro sources + + litt%ag_cwd_in(c) = litt%ag_cwd_in(c) + (struct_m + sapw_m) * & + SF_val_CWD_frac(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(c) * (dead_n_natural+dead_n_ilogging) * & + currentPatch%area * prt_params%allom_agb_frac(pft) + + else + + litt%ag_cwd_in(c) = litt%ag_cwd_in(c) + (struct_m + sapw_m) * & + SF_val_CWD_frac(c) * dead_n * & + prt_params%allom_agb_frac(pft) + + flux_diags%cwd_ag_input(c) = flux_diags%cwd_ag_input(c) + & + SF_val_CWD_frac(c) * dead_n * (struct_m + sapw_m) * & + currentPatch%area * prt_params%allom_agb_frac(pft) + + end if + + end do + + + ! Update diagnostics that track resource management + + if( element_id .eq. carbon12_element ) then + + currentSite%resources_management%delta_litter_stock = & + currentSite%resources_management%delta_litter_stock + & + (leaf_m + fnrt_m + store_m ) * & + (dead_n_ilogging+dead_n_dlogging) * currentPatch%area + + currentSite%resources_management%delta_biomass_stock = & + currentSite%resources_management%delta_biomass_stock + & + (leaf_m + fnrt_m + store_m ) * & + (dead_n_ilogging+dead_n_dlogging) *currentPatch%area + + currentSite%resources_management%trunk_product_site = & + currentSite%resources_management%trunk_product_site + & + trunk_wood * logging_export_frac * currentPatch%area + + do c = 1,ncwd + currentSite%resources_management%delta_litter_stock = & + currentSite%resources_management%delta_litter_stock + & + (struct_m + sapw_m) * & + SF_val_CWD_frac(c) * (dead_n_natural+dead_n_ilogging) * & + currentPatch%area + + currentSite%resources_management%delta_biomass_stock = & + currentSite%resources_management%delta_biomass_stock + & + (struct_m + sapw_m) * & + SF_val_CWD_frac(c) * dead_n * currentPatch%area + end do + + ! Update diagnostics that track resource management + currentSite%resources_management%delta_individual = & + currentSite%resources_management%delta_individual + & + (dead_n_dlogging+dead_n_ilogging) * hlm_freq_day * currentPatch%area + end if + + + currentCohort => currentCohort%taller + enddo ! end loop over cohorts + + + return + end subroutine CWDInput + + ! ===================================================================================== + + + subroutine fragmentation_scaler( currentPatch, bc_in) + ! + ! !DESCRIPTION: + ! Simple CWD fragmentation Model + ! FIX(SPM, 091914) this should be a function as it returns a value in + ! currentPatch%fragmentation_scaler + ! + ! !USES: + + use FatesSynchronizedParamsMod , only : FatesSynchronizedParamsInst + use FatesConstantsMod, only : tfrz => t_water_freeze_k_1atm + use FatesConstantsMod, only : pi => pi_const + ! + ! !ARGUMENTS + type(ed_patch_type), intent(inout) :: currentPatch + type(bc_in_type), intent(in) :: bc_in + + ! + ! !LOCAL VARIABLES: + logical :: use_century_tfunc = .false. + logical :: use_hlm_soil_scalar = .true. ! Use hlm input decomp fraction scalars + integer :: j + integer :: ifp ! Index of a FATES Patch "ifp" + real(r8) :: t_scalar ! temperature scalar + real(r8) :: w_scalar ! moisture scalar + real(r8) :: catanf ! hyperbolic temperature function from CENTURY + real(r8) :: catanf_30 ! hyperbolic temperature function from CENTURY + real(r8) :: t1 ! temperature argument + !---------------------------------------------------------------------- + + catanf(t1) = 11.75_r8 +(29.7_r8 / pi) * atan( pi * 0.031_r8 * ( t1 - 15.4_r8 )) + catanf_30 = catanf(30._r8) + + ifp = currentPatch%patchno + + ! Use the hlm temp and moisture decomp fractions by default + if ( use_hlm_soil_scalar ) then + + ! Calculate the fragmentation_scaler + currentPatch%fragmentation_scaler = min(1.0_r8,max(0.0_r8,bc_in%t_scalar_sisl * bc_in%w_scalar_sisl)) + + else + + if ( .not. use_century_tfunc ) then + !calculate rate constant scalar for soil temperature,assuming that the base rate constants + !are assigned for non-moisture limiting conditions at 25C. + if (bc_in%t_veg24_pa(ifp) >= tfrz) then + t_scalar = q10_mr**((bc_in%t_veg24_pa(ifp)-(tfrz+25._r8))/10._r8) + ! Q10**((t_soisno(c,j)-(tfrz+25._r8))/10._r8) + else + t_scalar = (q10_mr**(-25._r8/10._r8))*(q10_froz**((bc_in%t_veg24_pa(ifp)-tfrz)/10._r8)) + !Q10**(-25._r8/10._r8))*(froz_q10**((t_soisno(c,j)-tfrz)/10._r8) + endif + else + ! original century uses an arctangent function to calculate the + ! temperature dependence of decomposition + t_scalar = max(catanf(bc_in%t_veg24_pa(ifp)-tfrz)/catanf_30,0.01_r8) + endif + + !Moisture Limitations + !BTRAN APPROACH - is quite simple, but max's out decomp at all unstressed + !soil moisture values, which is not realistic. + !litter decomp is proportional to water limitation on average... + w_scalar = sum(currentPatch%btran_ft(1:numpft))/real(numpft,r8) + + ! Calculate the fragmentation_scaler + currentPatch%fragmentation_scaler(:) = min(1.0_r8,max(0.0_r8,t_scalar * w_scalar)) + + endif + + + end subroutine fragmentation_scaler + + ! ============================================================================ + + subroutine CWDOut( litt, fragmentation_scaler, nlev_eff_decomp ) + ! + ! !DESCRIPTION: + ! Simple CWD fragmentation Model + ! spawn new cohorts of juveniles of each PFT + ! + ! !USES: + use SFParamsMod, only : SF_val_max_decomp + + ! + ! !ARGUMENTS + type(litter_type),intent(inout),target :: litt + real(r8),intent(in) :: fragmentation_scaler(:) + + ! This is not necessarily every soil layer, this is the number + ! of effective layers that are active and can be sent + ! to the soil decomposition model + integer,intent(in) :: nlev_eff_decomp + + ! + ! !LOCAL VARIABLES: + integer :: c ! Fuel size class index + integer :: ilyr ! Soil layer index + integer :: dcmpy ! Decomposibility pool indexer + integer :: soil_layer_index = 1 ! Soil layer index associated with above ground litter + !---------------------------------------------------------------------- + + + ! Above ground litters are associated with the top soil layer temperature and + ! moisture scalars and fragmentation scalar associated with specified index value + ! is used for ag_cwd_frag and root_fines_frag calculations. + + do c = 1,ncwd + + litt%ag_cwd_frag(c) = litt%ag_cwd(c) * SF_val_max_decomp(c) * & + years_per_day * fragmentation_scaler(soil_layer_index) + + do ilyr = 1,nlev_eff_decomp + + litt%bg_cwd_frag(c,ilyr) = litt%bg_cwd(c,ilyr) * SF_val_max_decomp(c) * & + years_per_day * fragmentation_scaler(ilyr) + + enddo + end do + + ! this is the rate at which dropped leaves stop being part of the burnable pool + ! and begin to be part of the decomposing pool. This should probably be highly + ! sensitive to moisture, but also to the type of leaf thick leaves can dry out + ! before they are decomposed, for example. This section needs further scientific input. + + do dcmpy = 1,ndcmpy + + litt%leaf_fines_frag(dcmpy) = litt%leaf_fines(dcmpy) * & + years_per_day * SF_val_max_decomp(dl_sf) * fragmentation_scaler(soil_layer_index) + + do ilyr = 1,nlev_eff_decomp + litt%root_fines_frag(dcmpy,ilyr) = litt%root_fines(dcmpy,ilyr) * & + years_per_day * SF_val_max_decomp(dl_sf) * fragmentation_scaler(ilyr) + end do + enddo + + end subroutine CWDOut + +end module EDPhysiologyMod From b096c8d662ac0cec73c025110c9cbbe6356d6803 Mon Sep 17 00:00:00 2001 From: adamhb Date: Mon, 19 Jul 2021 14:26:53 -0700 Subject: [PATCH 18/81] The new emergence function is working well. Added light and moisture sensitive seedling emergence. The current implementation does not use time averages at this time (instantaneous values). Fixes: none User interface changes?: No Code review: Adam Hanbury-Brown Test summary: no testing --- biogeochem/EDPhysiologyMod.F90 | 67 +++++++++++++++++++++++----------- 1 file changed, 46 insertions(+), 21 deletions(-) diff --git a/biogeochem/EDPhysiologyMod.F90 b/biogeochem/EDPhysiologyMod.F90 index c748dfdb8b..7523d32d45 100644 --- a/biogeochem/EDPhysiologyMod.F90 +++ b/biogeochem/EDPhysiologyMod.F90 @@ -231,7 +231,8 @@ subroutine PreDisturbanceLitterFluxes( currentSite, 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) + call SeedGermination(litt, currentSite%cstatus, currentSite%dstatus, bc_in, currentPatch) !ahb added currentPatch + ! Send fluxes from newly created litter into the litter pools ! This litter flux is from non-disturbance inducing mortality, as well @@ -1525,18 +1526,20 @@ subroutine SeedDecay( litt ) end subroutine SeedDecay ! ============================================================================ - subroutine SeedGermination( litt, cold_stat, drought_stat ) + subroutine SeedGermination( litt, cold_stat, drought_stat, bc_in, currentPatch ) !ahb added currentPatch ! ! !DESCRIPTION: - ! Flux from seed pool into sapling pool + ! Flux from seed bank into the seedling pool ! ! !USES: ! ! !ARGUMENTS type(litter_type) :: litt - integer, intent(in) :: cold_stat ! Is the site in cold leaf-off status? - integer, intent(in) :: drought_stat ! Is the site in drought leaf-off status? + integer, intent(in) :: cold_stat ! Is the site in cold leaf-off status? + integer, intent(in) :: drought_stat ! Is the site in drought leaf-off status? + type(bc_in_type), intent(in) :: bc_in ! ahb added this + type(ed_patch_type), intent(in) :: currentPatch ! ! !LOCAL VARIABLES: integer :: pft @@ -1545,6 +1548,23 @@ subroutine SeedGermination( litt, cold_stat, drought_stat ) real(r8), parameter :: max_germination = 1.0_r8 ! Cap on germination rates. ! KgC/m2/yr Lishcke et al. 2009 + + !New seedling emergence parameters (ahb) + + real(r8), parameter :: emerg_soil_depth = 0.06 !soil depth (m) for emergence + real(r8), parameter :: mpa_per_mm_suction = 1.e-5 + real(r8), parameter :: a_emerg = 0.0006 + real(r8), parameter :: b_emerg = 1.6 + integer :: ilayer_swater_emerg + real(r8) :: f_PAR + real(r8), parameter :: PAR_crit = 70 + real(r8) :: wetness_index + real(r8) :: f_emerg + real(r8) :: SMP_seed !SMP at emerg_soil_depth + real(r8) :: PAR_seed !PAR at seedling layer + + + ! Turning of this cap? because the cap will impose changes on proportionality ! of nutrients. (RGK 02-2019) !real(r8), parameter :: max_germination = 1.e6_r8 ! Force to very high number @@ -1559,29 +1579,34 @@ subroutine SeedGermination( litt, cold_stat, drought_stat ) !ORIGINAL CODE !------------------------------------------------------------------------------------------- - do pft = 1,numpft - litt%seed_germ_in(pft) = min(litt%seed(pft) * EDPftvarcon_inst%germination_rate(pft), & - max_germination)*years_per_day + !do pft = 1,numpft + ! litt%seed_germ_in(pft) = min(litt%seed(pft) * EDPftvarcon_inst%germination_rate(pft), & + ! max_germination)*years_per_day !------------------------------------------------------------------------------------------- !ahb NEW CODE !------------------------------------------------------------------------------------------- - !Step 1. Define a variable that is the mean SMP in the top 6 cm over the prior 14 days - - !real(r8),parameter :: demerg_soil_depth = 0.06_r8 - !ilayer_swater_emerg = minloc(abs(bc_in%z_sisl(:)-demerg_soil_depth),dim=1) - !smp_emerg_today = bc_in%smp_sl(ilayer_swater_emerg) - !currentSite%water_memory_emerg(1) = smp_emerg_today - !NEED TO BUILD OUT THIS WATER MEMORY MORE - - !do pft = 1,numpft - ! litt%seed_germ_in(pft) = min(litt%seed(pft) * EDPftvarcon_inst%germination_rate(pft), & - ! max_germination)*years_per_day + !Step 1. calculate the photoblastic germination rate modifier + PAR_seed = currentPatch%parprof_pft_dir_z(1,1,1) !(ican, pft, ileaf) !PAR at lowest layer? + !W-M2... (mean over 24 hrs?) + PAR_seed = PAR_seed * 4.6 !covert to umol s-1 of PAR + f_PAR = PAR_seed / (PAR_seed + PAR_crit) !calculate photoblastic germ rate + !modifier + !Step 2. calculate the soil matric potential at 'emerg_soil_depth' (m) + ilayer_swater_emerg = minloc(abs(bc_in%z_sisl(:)-emerg_soil_depth),dim=1) !define soil layer + SMP_seed = bc_in%smp_sl(ilayer_swater_emerg) !calculate smp (mm H20 suction?) + wetness_index = 1.0_r8 / (SMP_seed * -1.0_r8 * mpa_per_mm_suction) !calculate wetness + + !Step 3. calculate the seedling emergence rate based on SMP_seed and f_PAR + f_emerg = f_PAR * a_emerg * wetness_index**b_emerg + + !Step 4. calculate the 'seed_germ_in' flux !put all code inside loop + !when params become pft-specific + do pft = 1,numpft + litt%seed_germ_in(pft) = min(litt%seed(pft) * f_emerg, max_germination) !------------------------------------------------------------------------------------------- - - !set the germination only under the growing season...c.xu if ((prt_params%season_decid(pft) == itrue ) .and. & From 4fca97f812f258f6da916d048ab1ef0d0f898331 Mon Sep 17 00:00:00 2001 From: adamhb Date: Mon, 19 Jul 2021 15:26:59 -0700 Subject: [PATCH 19/81] moved pft-specific parameters into (instantaneous) emergence function --- biogeochem/EDPhysiologyMod.F90 | 22 ++++++++++++---------- main/EDPftvarcon.F90 | 30 ++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 10 deletions(-) diff --git a/biogeochem/EDPhysiologyMod.F90 b/biogeochem/EDPhysiologyMod.F90 index 7523d32d45..2c9afe0b1e 100644 --- a/biogeochem/EDPhysiologyMod.F90 +++ b/biogeochem/EDPhysiologyMod.F90 @@ -1552,12 +1552,12 @@ subroutine SeedGermination( litt, cold_stat, drought_stat, bc_in, currentPatch ) !New seedling emergence parameters (ahb) real(r8), parameter :: emerg_soil_depth = 0.06 !soil depth (m) for emergence - real(r8), parameter :: mpa_per_mm_suction = 1.e-5 - real(r8), parameter :: a_emerg = 0.0006 - real(r8), parameter :: b_emerg = 1.6 + real(r8), parameter :: mpa_per_mm_suction = 1.e-5 ! move this to FATES globals once sure of smp units + !real(r8), parameter :: a_emerg = 0.0006 + !real(r8), parameter :: b_emerg = 1.6 integer :: ilayer_swater_emerg real(r8) :: f_PAR - real(r8), parameter :: PAR_crit = 70 + !real(r8), parameter :: PAR_crit = 70 real(r8) :: wetness_index real(r8) :: f_emerg real(r8) :: SMP_seed !SMP at emerg_soil_depth @@ -1579,18 +1579,20 @@ subroutine SeedGermination( litt, cold_stat, drought_stat, bc_in, currentPatch ) !ORIGINAL CODE !------------------------------------------------------------------------------------------- - !do pft = 1,numpft + do pft = 1,numpft ! litt%seed_germ_in(pft) = min(litt%seed(pft) * EDPftvarcon_inst%germination_rate(pft), & ! max_germination)*years_per_day !------------------------------------------------------------------------------------------- !ahb NEW CODE + !This new code adds light and moisture-sensitive seedling emergence functions. It replaces + !the old prescribed seed germination rate parameter. !------------------------------------------------------------------------------------------- !Step 1. calculate the photoblastic germination rate modifier - PAR_seed = currentPatch%parprof_pft_dir_z(1,1,1) !(ican, pft, ileaf) !PAR at lowest layer? - !W-M2... (mean over 24 hrs?) + PAR_seed = currentPatch%parprof_pft_dir_z(1,1,1) + & !(ican, pft, ileaf) !PAR at lowest layer? + currentPatch%parprof_pft_dif_z(1,1,1) !W-M2... (mean over 24 hrs?) PAR_seed = PAR_seed * 4.6 !covert to umol s-1 of PAR - f_PAR = PAR_seed / (PAR_seed + PAR_crit) !calculate photoblastic germ rate + f_PAR = PAR_seed / (PAR_seed + EDPftvarcon_inst%par_crit_germ(pft)) !calculate photoblastic germ rate !modifier !Step 2. calculate the soil matric potential at 'emerg_soil_depth' (m) ilayer_swater_emerg = minloc(abs(bc_in%z_sisl(:)-emerg_soil_depth),dim=1) !define soil layer @@ -1598,11 +1600,11 @@ subroutine SeedGermination( litt, cold_stat, drought_stat, bc_in, currentPatch ) wetness_index = 1.0_r8 / (SMP_seed * -1.0_r8 * mpa_per_mm_suction) !calculate wetness !Step 3. calculate the seedling emergence rate based on SMP_seed and f_PAR - f_emerg = f_PAR * a_emerg * wetness_index**b_emerg + f_emerg = f_PAR * EDPftvarcon_inst%a_emerg(pft) * wetness_index**EDPftvarcon_inst%b_emerg(pft) !Step 4. calculate the 'seed_germ_in' flux !put all code inside loop !when params become pft-specific - do pft = 1,numpft + !do pft = 1,numpft litt%seed_germ_in(pft) = min(litt%seed(pft) * f_emerg, max_germination) !------------------------------------------------------------------------------------------- diff --git a/main/EDPftvarcon.F90 b/main/EDPftvarcon.F90 index 4934f3920a..bd0317163d 100644 --- a/main/EDPftvarcon.F90 +++ b/main/EDPftvarcon.F90 @@ -104,6 +104,9 @@ module EDPftvarcon ! ungerminated), decaying per year (yr-1) real(r8), allocatable :: repro_frac_seed(:) ! added by ahb 7/15/2021 + real(r8), allocatable :: a_emerg(:) ! added by ahb 7/19/2021 + real(r8), allocatable :: b_emerg(:) ! added by ahb 7/19/2021 + real(r8), allocatable :: par_crit_germ(:) ! added by ahb 7/19/2021 real(r8), allocatable :: trim_limit(:) ! Limit to reductions in leaf area w stress (m2/m2) real(r8), allocatable :: trim_inc(:) ! Incremental change in trimming function (m2/m2) real(r8), allocatable :: rhol(:, :) @@ -518,6 +521,18 @@ subroutine Register_PFT(this, fates_params) call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) + name = 'fates_a_emerg' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + + name = 'fates_b_emerg' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + + name = 'fates_par_crit_germ' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + name = 'fates_seed_decay_rate' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) @@ -853,6 +868,18 @@ subroutine Receive_PFT(this, fates_params) call fates_params%RetreiveParameterAllocate(name=name, & data=this%repro_frac_seed) + name = 'fates_a_emerg' + call fates_params%RetreiveParameterAllocate(name=name, & + data=this%a_emerg) + + name = 'fates_b_emerg' + call fates_params%RetreiveParameterAllocate(name=name, & + data=this%b_emerg) + + name = 'fates_par_crit_germ' + call fates_params%RetreiveParameterAllocate(name=name, & + data=this%par_crit_germ) + name = 'fates_seed_decay_rate' call fates_params%RetreiveParameterAllocate(name=name, & data=this%seed_decay_rate) @@ -1340,6 +1367,9 @@ subroutine FatesReportPFTParams(is_master) write(fates_log(),fmt0) 'germination_timescale = ',EDPftvarcon_inst%germination_rate write(fates_log(),fmt0) 'seed_decay_turnover = ',EDPftvarcon_inst%seed_decay_rate write(fates_log(),fmt0) 'repro_frac_seed = ',EDPftvarcon_inst%repro_frac_seed + write(fates_log(),fmt0) 'a_emerg = ',EDPftvarcon_inst%a_emerg + write(fates_log(),fmt0) 'b_emerg = ',EDPftvarcon_inst%b_emerg + write(fates_log(),fmt0) 'par_crit_germ = ',EDPftvarcon_inst%par_crit_germ write(fates_log(),fmt0) 'trim_limit = ',EDPftvarcon_inst%trim_limit write(fates_log(),fmt0) 'trim_inc = ',EDPftvarcon_inst%trim_inc write(fates_log(),fmt0) 'rhol = ',EDPftvarcon_inst%rhol From 12863bf952449862f1cbc00057196c7a1248c198 Mon Sep 17 00:00:00 2001 From: adamhb Date: Mon, 19 Jul 2021 18:25:56 -0700 Subject: [PATCH 20/81] changed which par profile variable was being used by the seedling emergence subroutine --- biogeochem/EDPhysiologyMod.F90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/biogeochem/EDPhysiologyMod.F90 b/biogeochem/EDPhysiologyMod.F90 index 2c9afe0b1e..4955a208aa 100644 --- a/biogeochem/EDPhysiologyMod.F90 +++ b/biogeochem/EDPhysiologyMod.F90 @@ -1589,8 +1589,8 @@ subroutine SeedGermination( litt, cold_stat, drought_stat, bc_in, currentPatch ) !the old prescribed seed germination rate parameter. !------------------------------------------------------------------------------------------- !Step 1. calculate the photoblastic germination rate modifier - PAR_seed = currentPatch%parprof_pft_dir_z(1,1,1) + & !(ican, pft, ileaf) !PAR at lowest layer? - currentPatch%parprof_pft_dif_z(1,1,1) !W-M2... (mean over 24 hrs?) + PAR_seed = currentPatch%parprof_dir_z(1,1) + & !(ican, ileaf) !is 1,1 PAR at lowest layer? + currentPatch%parprof_dif_z(1,1) !W-M2... (mean over 24 hrs?) PAR_seed = PAR_seed * 4.6 !covert to umol s-1 of PAR f_PAR = PAR_seed / (PAR_seed + EDPftvarcon_inst%par_crit_germ(pft)) !calculate photoblastic germ rate !modifier From 99321aa28a890093a82bac8276023310e6ef1019 Mon Sep 17 00:00:00 2001 From: adamhb Date: Mon, 26 Jul 2021 12:52:12 -0700 Subject: [PATCH 21/81] deleted old comments --- biogeochem/EDPhysiologyMod.F90 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/biogeochem/EDPhysiologyMod.F90 b/biogeochem/EDPhysiologyMod.F90 index 4955a208aa..2d5d8ed273 100644 --- a/biogeochem/EDPhysiologyMod.F90 +++ b/biogeochem/EDPhysiologyMod.F90 @@ -1591,7 +1591,7 @@ subroutine SeedGermination( litt, cold_stat, drought_stat, bc_in, currentPatch ) !Step 1. calculate the photoblastic germination rate modifier PAR_seed = currentPatch%parprof_dir_z(1,1) + & !(ican, ileaf) !is 1,1 PAR at lowest layer? currentPatch%parprof_dif_z(1,1) !W-M2... (mean over 24 hrs?) - PAR_seed = PAR_seed * 4.6 !covert to umol s-1 of PAR + PAR_seed = PAR_seed * 4.6_r8 !covert to umol s-1 of PAR f_PAR = PAR_seed / (PAR_seed + EDPftvarcon_inst%par_crit_germ(pft)) !calculate photoblastic germ rate !modifier !Step 2. calculate the soil matric potential at 'emerg_soil_depth' (m) @@ -1602,8 +1602,8 @@ subroutine SeedGermination( litt, cold_stat, drought_stat, bc_in, currentPatch ) !Step 3. calculate the seedling emergence rate based on SMP_seed and f_PAR f_emerg = f_PAR * EDPftvarcon_inst%a_emerg(pft) * wetness_index**EDPftvarcon_inst%b_emerg(pft) - !Step 4. calculate the 'seed_germ_in' flux !put all code inside loop - !when params become pft-specific + !Step 4. calculate the 'seed_germ_in' flux + !do pft = 1,numpft litt%seed_germ_in(pft) = min(litt%seed(pft) * f_emerg, max_germination) !------------------------------------------------------------------------------------------- From 1c29442f52a17648543864953e0710c638f2f786 Mon Sep 17 00:00:00 2001 From: adamhb Date: Tue, 27 Jul 2021 14:49:44 -0700 Subject: [PATCH 22/81] added light-based seedling mortality the seed_germ pool is now treated as a seedling pool which can lose carbon from seedling mortality. this commit includes new code for light-based seedling mortality. This is important to capture the affect of understory light on recruitment rates. Fixes: none User interface changes?: No Code review: Adam Hanbury-Brown Test suite: ahb's account on Lobata Test summary: just did a simple test to see if the model would run at bci. it does. --- biogeochem/EDPhysiologyMod.F90 | 42 +++++++++++++++++++++++++++++----- main/EDPftvarcon.F90 | 33 +++++++++++++++++++++++--- main/FatesConstantsMod.F90 | 3 +++ 3 files changed, 69 insertions(+), 9 deletions(-) diff --git a/biogeochem/EDPhysiologyMod.F90 b/biogeochem/EDPhysiologyMod.F90 index 2d5d8ed273..7b81109f9b 100644 --- a/biogeochem/EDPhysiologyMod.F90 +++ b/biogeochem/EDPhysiologyMod.F90 @@ -19,6 +19,8 @@ module EDPhysiologyMod use FatesInterfaceTypesMod, only : hlm_phosphorus_spec use FatesConstantsMod, only : r8 => fates_r8 use FatesConstantsMod, only : nearzero + use FatesConstantsMod, only : sec_per_day + use FatesConstantsMod, only : megajoules_per_joule use EDPftvarcon , only : EDPftvarcon_inst use PRTParametersMod , only : prt_params use EDPftvarcon , only : GetDecompyFrac @@ -226,7 +228,7 @@ subroutine PreDisturbanceLitterFluxes( currentSite, currentPatch, bc_in ) litt => currentPatch%litter(el) ! Calculate loss rate of viable seeds to litter - call SeedDecay(litt) + call SeedDecay(litt, currentPatch, bc_in) ! Calculate seed germination rate, the status flags prevent ! germination from occuring when the site is in a drought @@ -1452,7 +1454,6 @@ subroutine SeedIn( currentSite, bc_in ) !This new code is designed to send some reproductive biomass !straight to the leaf litter pool to account for non-seed reproductive !biomass. Also see small change to SeedDecay subroutine. - !This can be turned off by commenting out line 1456. !-------------------------------- litt%seed_decay(pft) = litt%seed_in_local(pft) * (1.0_r8 - EDPftvarcon_inst%repro_frac_seed(pft)) !ahb !-------------------------------- @@ -1493,16 +1494,22 @@ end subroutine SeedIn ! ============================================================================ - subroutine SeedDecay( litt ) + subroutine SeedDecay( litt , currentPatch, bc_in ) ! ! !DESCRIPTION: ! Flux from seed pool into leaf litter pool ! ! !ARGUMENTS type(litter_type) :: litt + type(ed_patch_type), intent(in) :: currentPatch ! ahb added this + type(bc_in_type), intent(in) :: bc_in ! ahb added this ! ! !LOCAL VARIABLES: integer :: pft + real(r8) :: cumulative_light_seedling !cumulative light at the seedling layer (MJ) over prior 64 days + !this 64 day window is hard-coded for now because param values + !would need to change if the window changes + real(r8) :: seedling_light_mort_rate !the daily seedling mortality rate from light stress !---------------------------------------------------------------------- ! default value from Liscke and Loffler 2006 ; making this a PFT-specific parameter @@ -1516,9 +1523,32 @@ subroutine SeedDecay( litt ) EDPftvarcon_inst%seed_decay_rate(pft)*years_per_day + & ! "+ &" added by ahb (7/10/2021) litt%seed_decay(pft) ! line added by ahb so that the flux from non-seed reproductive ! biomass (from SeedIn subroutine) is not lost (7/10/2021) + !START ahb's changes + !ORIGINAL CODE + !---------------------------------------------------------------------- + ! litt%seed_germ_decay(pft) = litt%seed_germ(pft) * & + ! EDPftvarcon_inst%seed_decay_rate(pft)*years_per_day + !---------------------------------------------------------------------- + + !---------------------------------------------------------------------- + !NEW CODE FOR ENVIRONMENTALLY SENSITIVE SEEDLING MORTALITY + !Step 1. Calculate the daily seedling mortality rate from light stress + cumulative_light_seedling = ( currentPatch%parprof_dir_z(1,1) + & !indices: (ican, ileaf); is 1,1 PAR at lowest layer? + currentPatch%parprof_dif_z(1,1) ) * & + megajoules_per_joule * sec_per_day * 64.0_r8 !this is a placeholder until I get + !cumulative sum over prior 64 days working - litt%seed_germ_decay(pft) = litt%seed_germ(pft) * & - EDPftvarcon_inst%seed_decay_rate(pft)*years_per_day + seedling_light_mort_rate = exp(EDPftvarcon_inst%seedling_light_mort_a(pft) * & + cumulative_light_seedling + EDPftvarcon_inst%seedling_light_mort_b(pft)) + + + litt%seed_germ_decay(pft) = (litt%seed_germ(pft) * seedling_light_mort_rate) !+ & + !(litt%seed_germ(pft) * seedling_h2o_mort_rate) + & + !(litt%seed_germ(pft) * EDPftvarcon_inst%background_seedling_mort(pft) & + !*years_per_day) + + !----------------------------------------------------------------------- + !END ahb's changes enddo @@ -1526,7 +1556,7 @@ subroutine SeedDecay( litt ) end subroutine SeedDecay ! ============================================================================ - subroutine SeedGermination( litt, cold_stat, drought_stat, bc_in, currentPatch ) !ahb added currentPatch + subroutine SeedGermination( litt, cold_stat, drought_stat, bc_in, currentPatch ) !ahb added currentPatch and bc_in ! ! !DESCRIPTION: ! Flux from seed bank into the seedling pool diff --git a/main/EDPftvarcon.F90 b/main/EDPftvarcon.F90 index 29daf9534c..1d8f0e1834 100644 --- a/main/EDPftvarcon.F90 +++ b/main/EDPftvarcon.F90 @@ -103,9 +103,12 @@ module EDPftvarcon ! ungerminated), decaying per year (yr-1) real(r8), allocatable :: repro_frac_seed(:) ! added by ahb 7/15/2021 - real(r8), allocatable :: a_emerg(:) ! added by ahb 7/19/2021 - real(r8), allocatable :: b_emerg(:) ! added by ahb 7/19/2021 - real(r8), allocatable :: par_crit_germ(:) ! added by ahb 7/19/2021 + real(r8), allocatable :: a_emerg(:) !added by ahb 7/19/2021 + real(r8), allocatable :: b_emerg(:) !added by ahb 7/19/2021 + real(r8), allocatable :: par_crit_germ(:) !added by ahb 7/19/2021 + real(r8), allocatable :: seedling_light_mort_a(:) !added by ahb on 7/27/2021 + real(r8), allocatable :: seedling_light_mort_b(:) !added by ahb on 7/27/2021 + real(r8), allocatable :: background_seedling_mort(:)!added by ahb on 7/27/2021 real(r8), allocatable :: trim_limit(:) ! Limit to reductions in leaf area w stress (m2/m2) real(r8), allocatable :: trim_inc(:) ! Incremental change in trimming function (m2/m2) real(r8), allocatable :: rhol(:, :) @@ -561,7 +564,19 @@ subroutine Register_PFT(this, fates_params) name = 'fates_par_crit_germ' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) + + name = 'fates_seedling_light_mort_a' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + name = 'fates_seedling_light_mort_b' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + + name = 'fates_background_seedling_mort' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + name = 'fates_seed_decay_rate' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) @@ -924,6 +939,18 @@ subroutine Receive_PFT(this, fates_params) name = 'fates_par_crit_germ' call fates_params%RetreiveParameterAllocate(name=name, & data=this%par_crit_germ) + + name = 'fates_seedling_light_mort_a' + call fates_params%RetreiveParameterAllocate(name=name, & + data=this%seedling_light_mort_a) + + name = 'fates_seedling_light_mort_b' + call fates_params%RetreiveParameterAllocate(name=name, & + data=this%seedling_light_mort_b) + + name = 'fates_background_seedling_mort' + call fates_params%RetreiveParameterAllocate(name=name, & + data=this%background_seedling_mort) name = 'fates_seed_decay_rate' call fates_params%RetreiveParameterAllocate(name=name, & diff --git a/main/FatesConstantsMod.F90 b/main/FatesConstantsMod.F90 index 06eafc3d5c..ce6bb4f212 100644 --- a/main/FatesConstantsMod.F90 +++ b/main/FatesConstantsMod.F90 @@ -167,6 +167,9 @@ module FatesConstantsMod ! Conversion: seconds per day real(fates_r8), parameter, public :: sec_per_day = 86400.0_fates_r8 + ! Conversion: megajoules per joule + real(fates_r8), parameter, public :: megajoules_per_joule = 1.0E-6_fates_r8 + ! Conversion: days per second real(fates_r8), parameter, public :: days_per_sec = 1.0_fates_r8/86400.0_fates_r8 From 7338ec2c885e895e412c4bf55df1e457224c6493 Mon Sep 17 00:00:00 2001 From: adamhb Date: Tue, 27 Jul 2021 18:33:22 -0700 Subject: [PATCH 23/81] started to add code for moisture deficit days --- biogeochem/EDPhysiologyMod.F90 | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/biogeochem/EDPhysiologyMod.F90 b/biogeochem/EDPhysiologyMod.F90 index 7b81109f9b..a104426c34 100644 --- a/biogeochem/EDPhysiologyMod.F90 +++ b/biogeochem/EDPhysiologyMod.F90 @@ -1533,6 +1533,8 @@ subroutine SeedDecay( litt , currentPatch, bc_in ) !---------------------------------------------------------------------- !NEW CODE FOR ENVIRONMENTALLY SENSITIVE SEEDLING MORTALITY !Step 1. Calculate the daily seedling mortality rate from light stress + + !ADD CODE FOR CUMULATIVE LIGHT cumulative_light_seedling = ( currentPatch%parprof_dir_z(1,1) + & !indices: (ican, ileaf); is 1,1 PAR at lowest layer? currentPatch%parprof_dif_z(1,1) ) * & megajoules_per_joule * sec_per_day * 64.0_r8 !this is a placeholder until I get @@ -1541,7 +1543,27 @@ subroutine SeedDecay( litt , currentPatch, bc_in ) seedling_light_mort_rate = exp(EDPftvarcon_inst%seedling_light_mort_a(pft) * & cumulative_light_seedling + EDPftvarcon_inst%seedling_light_mort_b(pft)) + !Step 2. Calculate the moisture deficit days !this code is a placeholder for now + + !ilayer_swater_emerg = minloc(abs(bc_in%z_sisl(:)-emerg_soil_depth),dim=1) !define soil layer + + !moisture_def_days = abs(bc_in%smp_sl(ilayer_swater_emerg) * mpa_per_mm_suction) - & !calculate smp (mm H20 suction?) + ! abs(EDPftvarcon_inst%seedling_smp_crit(pft)) + + + !Step 3. Calculate the daily seedling mortality rate from moisture stress + + !seedling_h2o_mort_rate = EDPftvarcon_inst%seedling_h2o_mort_a(pft) * moisture_def_days**2 + & + ! EDPftvarcon_inst%seedling_h2o_mort_b(pft) * moisture_def_days + & + ! EDPftvarcon_inst%seedling_h2o_mort_c(pft) + + !if (moisture_def_days < EDPftvarcon_inst%moisture_dd_crit(pft) ) then + ! seedling_h2o_mort_rate = 0.0_r8 + !end if + + + !Step 4. Add background mortality and send seedling carbon to litter flux (i.e. to 'seed_germ_decay' flux) litt%seed_germ_decay(pft) = (litt%seed_germ(pft) * seedling_light_mort_rate) !+ & !(litt%seed_germ(pft) * seedling_h2o_mort_rate) + & !(litt%seed_germ(pft) * EDPftvarcon_inst%background_seedling_mort(pft) & From 19413273a3fbf0a28e50439ff66224dc48ab4fe1 Mon Sep 17 00:00:00 2001 From: adamhb Date: Tue, 27 Jul 2021 19:31:19 -0700 Subject: [PATCH 24/81] germination not working --- biogeochem/EDPhysiologyMod.F90 | 45 +++++++++++++++------------------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/biogeochem/EDPhysiologyMod.F90 b/biogeochem/EDPhysiologyMod.F90 index a104426c34..978c01faab 100644 --- a/biogeochem/EDPhysiologyMod.F90 +++ b/biogeochem/EDPhysiologyMod.F90 @@ -1595,26 +1595,21 @@ subroutine SeedGermination( litt, cold_stat, drought_stat, bc_in, currentPatch ) ! ! !LOCAL VARIABLES: integer :: pft - - real(r8), parameter :: max_germination = 1.0_r8 ! Cap on germination rates. ! KgC/m2/yr Lishcke et al. 2009 - - !New seedling emergence parameters (ahb) - - real(r8), parameter :: emerg_soil_depth = 0.06 !soil depth (m) for emergence - real(r8), parameter :: mpa_per_mm_suction = 1.e-5 ! move this to FATES globals once sure of smp units - !real(r8), parameter :: a_emerg = 0.0006 - !real(r8), parameter :: b_emerg = 1.6 - integer :: ilayer_swater_emerg - real(r8) :: f_PAR - !real(r8), parameter :: PAR_crit = 70 - real(r8) :: wetness_index - real(r8) :: f_emerg - real(r8) :: SMP_seed !SMP at emerg_soil_depth - real(r8) :: PAR_seed !PAR at seedling layer - + !Light and moisture-sensitive seedling emergence variables (ahb) + !------------------------------------------------------------------------------------------------------------ + real(r8), parameter :: root_depth = 0.06 + real(r8), parameter :: mpa_per_mm_suction = 1.e-5 ! move this to FATES globals once sure of smp units + integer :: ilayer_swater_emerg ! the soil layer used for seedling moisture functions + real(r8) :: f_PAR ! emergence rate modifier for light-sensitive germination + real(r8) :: wetness_index ! a soil 'wetness index' calculated from smp + ! used in the moisture-sensitive emergence function + real(r8) :: f_emerg ! the fraction of the seed bank emerging in the current time step + real(r8) :: SMP_seed ! soil matric potential at seedling rooting depth + real(r8) :: PAR_seed ! photosynthetically active radiation at the seedling layer + !------------------------------------------------------------------------------------------------------------- ! Turning of this cap? because the cap will impose changes on proportionality @@ -1641,15 +1636,15 @@ subroutine SeedGermination( litt, cold_stat, drought_stat, bc_in, currentPatch ) !the old prescribed seed germination rate parameter. !------------------------------------------------------------------------------------------- !Step 1. calculate the photoblastic germination rate modifier - PAR_seed = currentPatch%parprof_dir_z(1,1) + & !(ican, ileaf) !is 1,1 PAR at lowest layer? - currentPatch%parprof_dif_z(1,1) !W-M2... (mean over 24 hrs?) + PAR_seed = currentPatch%parprof_dir_z(1,1) + & !(ican, ileaf) !is 1,1 PAR at lowest layer? + currentPatch%parprof_dif_z(1,1) !W-M2... (mean over 24 hrs?) PAR_seed = PAR_seed * 4.6_r8 !covert to umol s-1 of PAR - f_PAR = PAR_seed / (PAR_seed + EDPftvarcon_inst%par_crit_germ(pft)) !calculate photoblastic germ rate - !modifier - !Step 2. calculate the soil matric potential at 'emerg_soil_depth' (m) - ilayer_swater_emerg = minloc(abs(bc_in%z_sisl(:)-emerg_soil_depth),dim=1) !define soil layer - SMP_seed = bc_in%smp_sl(ilayer_swater_emerg) !calculate smp (mm H20 suction?) - wetness_index = 1.0_r8 / (SMP_seed * -1.0_r8 * mpa_per_mm_suction) !calculate wetness + f_PAR = PAR_seed / (PAR_seed + EDPftvarcon_inst%par_crit_germ(pft)) !calculate photoblastic germ rate + !modifier + !Step 2. calculate the soil matric potential at the seedling root depth + ilayer_swater_emerg = minloc(abs(bc_in%z_sisl(:)-root_depth),dim=1) !define soil layer + SMP_seed = bc_in%smp_sl(ilayer_swater_emerg) !calculate smp (mm H20 suction?) + wetness_index = 1.0_r8 / (SMP_seed * (-1.0_r8) * mpa_per_mm_suction) !calculate wetness !Step 3. calculate the seedling emergence rate based on SMP_seed and f_PAR f_emerg = f_PAR * EDPftvarcon_inst%a_emerg(pft) * wetness_index**EDPftvarcon_inst%b_emerg(pft) From 316467d3e5ed78bfd4d051f02265b009ca0d68e6 Mon Sep 17 00:00:00 2001 From: adamhb Date: Tue, 27 Jul 2021 19:33:36 -0700 Subject: [PATCH 25/81] germination not working --- main/EDPftvarcon.F90 | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/main/EDPftvarcon.F90 b/main/EDPftvarcon.F90 index 1d8f0e1834..42f193772e 100644 --- a/main/EDPftvarcon.F90 +++ b/main/EDPftvarcon.F90 @@ -106,6 +106,7 @@ module EDPftvarcon real(r8), allocatable :: a_emerg(:) !added by ahb 7/19/2021 real(r8), allocatable :: b_emerg(:) !added by ahb 7/19/2021 real(r8), allocatable :: par_crit_germ(:) !added by ahb 7/19/2021 + real(r8), allocatable :: seedling_root_depth(:) !added by ahb 7/27/2021 real(r8), allocatable :: seedling_light_mort_a(:) !added by ahb on 7/27/2021 real(r8), allocatable :: seedling_light_mort_b(:) !added by ahb on 7/27/2021 real(r8), allocatable :: background_seedling_mort(:)!added by ahb on 7/27/2021 @@ -564,7 +565,11 @@ subroutine Register_PFT(this, fates_params) name = 'fates_par_crit_germ' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - + + name = 'fates_seedling_root_depth' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + name = 'fates_seedling_light_mort_a' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) @@ -939,7 +944,11 @@ subroutine Receive_PFT(this, fates_params) name = 'fates_par_crit_germ' call fates_params%RetreiveParameterAllocate(name=name, & data=this%par_crit_germ) - + + name = 'fates_seedling_root_depth' + call fates_params%RetreiveParameterAllocate(name=name, & + data=this%seedling_root_depth) + name = 'fates_seedling_light_mort_a' call fates_params%RetreiveParameterAllocate(name=name, & data=this%seedling_light_mort_a) @@ -1498,6 +1507,7 @@ subroutine FatesReportPFTParams(is_master) write(fates_log(),fmt0) 'a_emerg = ',EDPftvarcon_inst%a_emerg write(fates_log(),fmt0) 'b_emerg = ',EDPftvarcon_inst%b_emerg write(fates_log(),fmt0) 'par_crit_germ = ',EDPftvarcon_inst%par_crit_germ + write(fates_log(),fmt0) 'seedling_root_depth = ',EDPftvarcon_inst%seedling_root_depth write(fates_log(),fmt0) 'trim_limit = ',EDPftvarcon_inst%trim_limit write(fates_log(),fmt0) 'trim_inc = ',EDPftvarcon_inst%trim_inc write(fates_log(),fmt0) 'rhol = ',EDPftvarcon_inst%rhol From 36c331cb23b9fb9d10804b7734e94c3904866e5c Mon Sep 17 00:00:00 2001 From: adamhb Date: Tue, 27 Jul 2021 19:40:21 -0700 Subject: [PATCH 26/81] mass balance issue --- biogeochem/EDPhysiologyMod.F90 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/biogeochem/EDPhysiologyMod.F90 b/biogeochem/EDPhysiologyMod.F90 index 978c01faab..e026a02878 100644 --- a/biogeochem/EDPhysiologyMod.F90 +++ b/biogeochem/EDPhysiologyMod.F90 @@ -1643,11 +1643,11 @@ subroutine SeedGermination( litt, cold_stat, drought_stat, bc_in, currentPatch ) !modifier !Step 2. calculate the soil matric potential at the seedling root depth ilayer_swater_emerg = minloc(abs(bc_in%z_sisl(:)-root_depth),dim=1) !define soil layer - SMP_seed = bc_in%smp_sl(ilayer_swater_emerg) !calculate smp (mm H20 suction?) - wetness_index = 1.0_r8 / (SMP_seed * (-1.0_r8) * mpa_per_mm_suction) !calculate wetness + SMP_seed = bc_in%smp_sl(ilayer_swater_emerg) !calculate smp (mm H20 suction?) + wetness_index = 1.0_r8 / (SMP_seed * (-1.0_r8) * mpa_per_mm_suction) !calculate wetness !Step 3. calculate the seedling emergence rate based on SMP_seed and f_PAR - f_emerg = f_PAR * EDPftvarcon_inst%a_emerg(pft) * wetness_index**EDPftvarcon_inst%b_emerg(pft) + f_emerg = f_PAR * EDPftvarcon_inst%a_emerg(pft) * wetness_index**EDPftvarcon_inst%b_emerg(pft) !Step 4. calculate the 'seed_germ_in' flux From d7ea5b6129779ca76b0b3754d0fdbc4113d9b881 Mon Sep 17 00:00:00 2001 From: adamhb Date: Tue, 27 Jul 2021 19:50:09 -0700 Subject: [PATCH 27/81] fixed mass balance issue --- biogeochem/EDPhysiologyMod.F90 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/biogeochem/EDPhysiologyMod.F90 b/biogeochem/EDPhysiologyMod.F90 index e026a02878..ebbd354463 100644 --- a/biogeochem/EDPhysiologyMod.F90 +++ b/biogeochem/EDPhysiologyMod.F90 @@ -1526,8 +1526,8 @@ subroutine SeedDecay( litt , currentPatch, bc_in ) !START ahb's changes !ORIGINAL CODE !---------------------------------------------------------------------- - ! litt%seed_germ_decay(pft) = litt%seed_germ(pft) * & - ! EDPftvarcon_inst%seed_decay_rate(pft)*years_per_day + litt%seed_germ_decay(pft) = litt%seed_germ(pft) * & + EDPftvarcon_inst%seed_decay_rate(pft)*years_per_day !---------------------------------------------------------------------- !---------------------------------------------------------------------- @@ -1564,7 +1564,7 @@ subroutine SeedDecay( litt , currentPatch, bc_in ) !Step 4. Add background mortality and send seedling carbon to litter flux (i.e. to 'seed_germ_decay' flux) - litt%seed_germ_decay(pft) = (litt%seed_germ(pft) * seedling_light_mort_rate) !+ & + !litt%seed_germ_decay(pft) = (litt%seed_germ(pft) * seedling_light_mort_rate) !+ & !(litt%seed_germ(pft) * seedling_h2o_mort_rate) + & !(litt%seed_germ(pft) * EDPftvarcon_inst%background_seedling_mort(pft) & !*years_per_day) From 3c78d6bb63edb480d5ca12d9cd17031e0ee9db3b Mon Sep 17 00:00:00 2001 From: adamhb Date: Wed, 28 Jul 2021 12:13:37 -0700 Subject: [PATCH 28/81] testing --- biogeochem/EDPhysiologyMod.F90 | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/biogeochem/EDPhysiologyMod.F90 b/biogeochem/EDPhysiologyMod.F90 index ebbd354463..ccaca53170 100644 --- a/biogeochem/EDPhysiologyMod.F90 +++ b/biogeochem/EDPhysiologyMod.F90 @@ -1506,10 +1506,11 @@ subroutine SeedDecay( litt , currentPatch, bc_in ) ! ! !LOCAL VARIABLES: integer :: pft - real(r8) :: cumulative_light_seedling !cumulative light at the seedling layer (MJ) over prior 64 days - !this 64 day window is hard-coded for now because param values - !would need to change if the window changes - real(r8) :: seedling_light_mort_rate !the daily seedling mortality rate from light stress + real(r8) :: cumulative_light_seedling !cumulative light at the seedling layer (MJ) over prior 64 days + !this 64 day window is hard-coded for now because param values + !would need to change if the window changes + real(r8) :: seedling_light_mort_rate !the daily seedling mortality rate from light stress + real(r8), parameter :: mpa_per_mm_suction = 1.0e5_r8 !---------------------------------------------------------------------- ! default value from Liscke and Loffler 2006 ; making this a PFT-specific parameter @@ -1588,10 +1589,10 @@ subroutine SeedGermination( litt, cold_stat, drought_stat, bc_in, currentPatch ) ! ! !ARGUMENTS type(litter_type) :: litt - integer, intent(in) :: cold_stat ! Is the site in cold leaf-off status? - integer, intent(in) :: drought_stat ! Is the site in drought leaf-off status? - type(bc_in_type), intent(in) :: bc_in ! ahb added this - type(ed_patch_type), intent(in) :: currentPatch + integer, intent(in) :: cold_stat ! Is the site in cold leaf-off status? + integer, intent(in) :: drought_stat ! Is the site in drought leaf-off status? + type(bc_in_type), intent(in) :: bc_in ! ahb added this July 2021 + type(ed_patch_type), intent(in) :: currentPatch ! ahb added this July 2021 ! ! !LOCAL VARIABLES: integer :: pft @@ -1642,7 +1643,7 @@ subroutine SeedGermination( litt, cold_stat, drought_stat, bc_in, currentPatch ) f_PAR = PAR_seed / (PAR_seed + EDPftvarcon_inst%par_crit_germ(pft)) !calculate photoblastic germ rate !modifier !Step 2. calculate the soil matric potential at the seedling root depth - ilayer_swater_emerg = minloc(abs(bc_in%z_sisl(:)-root_depth),dim=1) !define soil layer + ilayer_swater_emerg = minloc(abs(bc_in%z_sisl(:)-EDPftvarcon_inst%seedling_root_depth(pft)),dim=1) !define soil layer SMP_seed = bc_in%smp_sl(ilayer_swater_emerg) !calculate smp (mm H20 suction?) wetness_index = 1.0_r8 / (SMP_seed * (-1.0_r8) * mpa_per_mm_suction) !calculate wetness From 16f148d3b7d7d04c6adba6a83ab8737d4ea1e5cd Mon Sep 17 00:00:00 2001 From: adamhb Date: Thu, 29 Jul 2021 10:50:32 -0700 Subject: [PATCH 29/81] added comments to end of germination code chunk --- biogeochem/EDPhysiologyMod.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/biogeochem/EDPhysiologyMod.F90 b/biogeochem/EDPhysiologyMod.F90 index 2d5d8ed273..dccccab29f 100644 --- a/biogeochem/EDPhysiologyMod.F90 +++ b/biogeochem/EDPhysiologyMod.F90 @@ -1607,7 +1607,7 @@ subroutine SeedGermination( litt, cold_stat, drought_stat, bc_in, currentPatch ) !do pft = 1,numpft litt%seed_germ_in(pft) = min(litt%seed(pft) * f_emerg, max_germination) !------------------------------------------------------------------------------------------- - + !END ahb's new code !set the germination only under the growing season...c.xu From b9e3ed969ed416b5fe2a9353825508cc3160172f Mon Sep 17 00:00:00 2001 From: adamhb Date: Fri, 30 Jul 2021 18:08:56 -0700 Subject: [PATCH 30/81] working, but parprof arrays are all zeroes --- biogeochem/EDPhysiologyMod.F90 | 112 +++++++++++++++++++++------------ main/EDMainMod.F90 | 5 +- main/EDTypesMod.F90 | 2 + main/FatesConstantsMod.F90 | 5 +- main/FatesRunningMeanMod.F90 | 7 ++- 5 files changed, 85 insertions(+), 46 deletions(-) diff --git a/biogeochem/EDPhysiologyMod.F90 b/biogeochem/EDPhysiologyMod.F90 index e6b7f86bbe..f7a760ca32 100644 --- a/biogeochem/EDPhysiologyMod.F90 +++ b/biogeochem/EDPhysiologyMod.F90 @@ -21,6 +21,7 @@ module EDPhysiologyMod use FatesConstantsMod, only : nearzero use FatesConstantsMod, only : sec_per_day use FatesConstantsMod, only : megajoules_per_joule + use FatesConstantsMod, only : mpa_per_mm_suction use EDPftvarcon , only : EDPftvarcon_inst use PRTParametersMod , only : prt_params use EDPftvarcon , only : GetDecompyFrac @@ -1498,7 +1499,8 @@ end subroutine SeedIn subroutine SeedDecay( litt , currentPatch, bc_in ) ! ! !DESCRIPTION: - ! Flux from seed pool into leaf litter pool + ! 1. Flux from seed pool into leaf litter pool + ! 2. Flux from seedling pool into leaf litter pool ! ! !ARGUMENTS type(litter_type) :: litt @@ -1507,26 +1509,31 @@ subroutine SeedDecay( litt , currentPatch, bc_in ) ! ! !LOCAL VARIABLES: integer :: pft - real(r8) :: cumulative_light_seedling !cumulative light at the seedling layer (MJ) over prior 64 days - !this 64 day window is hard-coded for now because param values - !would need to change if the window changes + real(r8) :: seedling_layer_par !cumulative light at the seedling layer (MJ) over prior window of days + !(defined by 'light_mort_window' param) + real(r8), parameter :: seedling_light_mort_window = 64.0 !days; move to pft-level parameter real(r8) :: seedling_light_mort_rate !the daily seedling mortality rate from light stress - real(r8), parameter :: mpa_per_mm_suction = 1.0e5_r8 !---------------------------------------------------------------------- + + ! 1. Flux from seed pool into leaf litter pool + ! default value from Liscke and Loffler 2006 ; making this a PFT-specific parameter ! decays the seed pool according to exponential model ! seed_decay_rate is in yr-1 ! seed_decay is kg/day ! Assume that decay rates are same for all chemical species + ! START ahb's changes do pft = 1,numpft litt%seed_decay(pft) = litt%seed(pft) * & EDPftvarcon_inst%seed_decay_rate(pft)*years_per_day + & ! "+ &" added by ahb (7/10/2021) litt%seed_decay(pft) ! line added by ahb so that the flux from non-seed reproductive ! biomass (from SeedIn subroutine) is not lost (7/10/2021) - !START ahb's changes - !ORIGINAL CODE + + ! 2. Flux from seedling pool into leaf litter pool + + ! ORIGINAL CODE !---------------------------------------------------------------------- litt%seed_germ_decay(pft) = litt%seed_germ(pft) * & EDPftvarcon_inst%seed_decay_rate(pft)*years_per_day @@ -1537,13 +1544,17 @@ subroutine SeedDecay( litt , currentPatch, bc_in ) !Step 1. Calculate the daily seedling mortality rate from light stress !ADD CODE FOR CUMULATIVE LIGHT - cumulative_light_seedling = ( currentPatch%parprof_dir_z(1,1) + & !indices: (ican, ileaf); is 1,1 PAR at lowest layer? - currentPatch%parprof_dif_z(1,1) ) * & - megajoules_per_joule * sec_per_day * 64.0_r8 !this is a placeholder until I get - !cumulative sum over prior 64 days working + ! seedling_layer_par = ( currentPatch%parprof_dir_z(currentPatch%ncl_p,max(currentPatch%ncan(currentPatch%ncl_p,:))) ) ! + & + ! currentPatch%parprof_dif_z(currentPatch%ncl_p,max(currentPatch%ncan(currentPatch%ncl_p,:))) ) + ! * & + ! megajoules_per_joule * sec_per_day * seedling_light_mort_window + + ! seedling_light_mort_rate = exp(EDPftvarcon_inst%seedling_light_mort_a(pft) * & + ! seedling_layer_par + EDPftvarcon_inst%seedling_light_mort_b(pft)) + - seedling_light_mort_rate = exp(EDPftvarcon_inst%seedling_light_mort_a(pft) * & - cumulative_light_seedling + EDPftvarcon_inst%seedling_light_mort_b(pft)) + ! write(fates_log(),*) 'seedling layer par ', seedling_layer_par + ! write(fates_log(),*) 'seedling light mort rate ', seedling_light_mort_rate !Step 2. Calculate the moisture deficit days !this code is a placeholder for now @@ -1602,15 +1613,14 @@ subroutine SeedGermination( litt, cold_stat, drought_stat, bc_in, currentPatch ) !Light and moisture-sensitive seedling emergence variables (ahb) !------------------------------------------------------------------------------------------------------------ - real(r8), parameter :: root_depth = 0.06 - real(r8), parameter :: mpa_per_mm_suction = 1.e-5 ! move this to FATES globals once sure of smp units - integer :: ilayer_swater_emerg ! the soil layer used for seedling moisture functions - real(r8) :: f_PAR ! emergence rate modifier for light-sensitive germination - real(r8) :: wetness_index ! a soil 'wetness index' calculated from smp - ! used in the moisture-sensitive emergence function - real(r8) :: f_emerg ! the fraction of the seed bank emerging in the current time step - real(r8) :: SMP_seed ! soil matric potential at seedling rooting depth - real(r8) :: PAR_seed ! photosynthetically active radiation at the seedling layer + integer :: ilayer_seedling_root ! the soil layer at seedling rooting depth + real(r8) :: seedling_layer_smp ! soil matric potential at seedling rooting depth + real(r8) :: wetness_index ! a soil 'wetness index' calculated from soil matric potential + + real(r8) :: seedling_layer_par ! photosynthetically active radiation at the seedling layer + real(r8) :: photoblastic_germ_modifier ! seedling emergence rate modifier for light-sensitive germination + ! used in the moisture-sensitive emergence function + real(r8) :: seedling_emerg_rate ! the fraction of the seed bank emerging in the current time step !------------------------------------------------------------------------------------------------------------- @@ -1625,7 +1635,8 @@ subroutine SeedGermination( litt, cold_stat, drought_stat, bc_in, currentPatch ) ! is seed_decay_rate(p)/germination_rate(p) ! and thus the mortality rate (in units of individuals) is the product of ! that times the ratio of (hypothetical) seed mass to recruit biomass - + + !START ahb's CHANGES !ORIGINAL CODE !------------------------------------------------------------------------------------------- do pft = 1,numpft @@ -1633,30 +1644,51 @@ subroutine SeedGermination( litt, cold_stat, drought_stat, bc_in, currentPatch ) ! max_germination)*years_per_day !------------------------------------------------------------------------------------------- - !ahb NEW CODE - !This new code adds light and moisture-sensitive seedling emergence functions. It replaces - !the old prescribed seed germination rate parameter. + !This code adds light and moisture-sensitive seedling emergence from the seed bank. + !It replaces the old prescribed seed germination rate parameter. !------------------------------------------------------------------------------------------- !Step 1. calculate the photoblastic germination rate modifier - PAR_seed = currentPatch%parprof_dir_z(1,1) + & !(ican, ileaf) !is 1,1 PAR at lowest layer? - currentPatch%parprof_dif_z(1,1) !W-M2... (mean over 24 hrs?) - PAR_seed = PAR_seed * 4.6_r8 !covert to umol s-1 of PAR - f_PAR = PAR_seed / (PAR_seed + EDPftvarcon_inst%par_crit_germ(pft)) !calculate photoblastic germ rate - !modifier - !Step 2. calculate the soil matric potential at the seedling root depth - ilayer_swater_emerg = minloc(abs(bc_in%z_sisl(:)-EDPftvarcon_inst%seedling_root_depth(pft)),dim=1) !define soil layer - SMP_seed = bc_in%smp_sl(ilayer_swater_emerg) !calculate smp (mm H20 suction?) - wetness_index = 1.0_r8 / (SMP_seed * (-1.0_r8) * mpa_per_mm_suction) !calculate wetness - - !Step 3. calculate the seedling emergence rate based on SMP_seed and f_PAR - f_emerg = f_PAR * EDPftvarcon_inst%a_emerg(pft) * wetness_index**EDPftvarcon_inst%b_emerg(pft) + + seedling_layer_par = & + ( currentPatch%parprof_dir_z(currentPatch%ncl_p,maxval(currentPatch%ncan(currentPatch%ncl_p,:))) + & + currentPatch%parprof_dif_z(currentPatch%ncl_p,maxval(currentPatch%ncan(currentPatch%ncl_p,:))) + & + currentPatch%parprof_dif_z(1,1) & + ) + + + write(fates_log(),*) 'nrm parprof', currentPatch%nrmlzd_parprof_dir_z(:,:,:) + !write(fates_log(),*) 'parprof', currentPatch%parprof_dif_z(1,:) + !write(fates_log(),*) 'number_leaf_layers_in_second_canopy_layer', maxval(currentPatch%ncan(currentPatch%ncl_p,:)) + + !write(fates_log(),*) 'seedling_layer_par_raw', seedling_layer_par + + seedling_layer_par = seedling_layer_par * 4.6_r8 !covert to umol s-1 of PAR + !1 W/m2 ≈ 4.6 μmole.m2/s + + photoblastic_germ_modifier = seedling_layer_par / & + (seedling_layer_par + EDPftvarcon_inst%par_crit_germ(pft)) + + !Step 2. calculate the soil matric potential at the seedling root depth + + !define soil layer + ilayer_seedling_root = minloc(abs(bc_in%z_sisl(:)-EDPftvarcon_inst%seedling_root_depth(pft)),dim=1) + + !get soil matric potential (mm of H2O suction) at the seedling rooting depth + seedling_layer_smp = bc_in%smp_sl(ilayer_seedling_root) + + !calculate a soil wetness index, which is used by the moisture-based seedling mortality function + wetness_index = 1.0_r8 / (seedling_layer_smp * (-1.0_r8) * mpa_per_mm_suction) + + !Step 3. calculate the seedling emergence rate based on soil moisture and par + seedling_emerg_rate = photoblastic_germ_modifier * EDPftvarcon_inst%a_emerg(pft) * & + wetness_index**EDPftvarcon_inst%b_emerg(pft) !Step 4. calculate the 'seed_germ_in' flux !do pft = 1,numpft - litt%seed_germ_in(pft) = min(litt%seed(pft) * f_emerg, max_germination) + litt%seed_germ_in(pft) = min(litt%seed(pft) * seedling_emerg_rate, max_germination) !------------------------------------------------------------------------------------------- - + !END ahb changes !set the germination only under the growing season...c.xu diff --git a/main/EDMainMod.F90 b/main/EDMainMod.F90 index 0518c1b34e..6d6d742de1 100644 --- a/main/EDMainMod.F90 +++ b/main/EDMainMod.F90 @@ -95,7 +95,7 @@ module EDMainMod use FatesHistoryInterfaceMod, only : ih_nh4uptake_si, ih_no3uptake_si, ih_puptake_si use FatesHistoryInterfaceMod, only : ih_nh4uptake_scpf, ih_no3uptake_scpf, ih_puptake_scpf use FatesHistoryInterfaceMod, only : fates_hist - + ! CIME Globals use shr_log_mod , only : errMsg => shr_log_errMsg use shr_infnan_mod , only : nan => shr_infnan_nan, assignment(=) @@ -584,7 +584,8 @@ subroutine ed_integrate_state_variables(currentSite, bc_in, bc_out ) ! we will calculate this as a group call SeedIn(currentSite,bc_in) - + + ! Calculate all other litter fluxes ! ----------------------------------------------------------------------------------- diff --git a/main/EDTypesMod.F90 b/main/EDTypesMod.F90 index 05a4178da9..6c0f21626a 100644 --- a/main/EDTypesMod.F90 +++ b/main/EDTypesMod.F90 @@ -426,6 +426,8 @@ module EDTypesMod class(rmean_type), pointer :: tveg_lpa ! Running mean of vegetation temperature at the ! leaf photosynthesis acclimation timescale [K] + class(rmean_type), pointer :: seedling_layer_par ! photosynthetically active radiation at the seedling layer (w-m2) + ! LEAF ORGANIZATION real(r8) :: pft_agb_profile(maxpft,n_dbh_bins) ! binned above ground biomass, for patch fusion: KgC/m2 real(r8) :: canopy_layer_tlai(nclmax) ! total leaf area index of each canopy layer diff --git a/main/FatesConstantsMod.F90 b/main/FatesConstantsMod.F90 index ce6bb4f212..c1363fe98d 100644 --- a/main/FatesConstantsMod.F90 +++ b/main/FatesConstantsMod.F90 @@ -169,7 +169,10 @@ module FatesConstantsMod ! Conversion: megajoules per joule real(fates_r8), parameter, public :: megajoules_per_joule = 1.0E-6_fates_r8 - + + ! Conversion: megapascals per mm H2O suction + real(fates_r8), parameter, public :: mpa_per_mm_suction = 1.0E-5_fates_r8 + ! Conversion: days per second real(fates_r8), parameter, public :: days_per_sec = 1.0_fates_r8/86400.0_fates_r8 diff --git a/main/FatesRunningMeanMod.F90 b/main/FatesRunningMeanMod.F90 index df1c12c7be..28d39c6995 100644 --- a/main/FatesRunningMeanMod.F90 +++ b/main/FatesRunningMeanMod.F90 @@ -88,9 +88,10 @@ module FatesRunningMeanMod ! Define the time methods that we want to have available to us - class(rmean_def_type), public, pointer :: ema_24hr ! Exponential moving average - 24hr window - class(rmean_def_type), public, pointer :: fixed_24hr ! Fixed, 24-hour window - class(rmean_def_type), public, pointer :: ema_lpa ! Exponential moving average - leaf photo acclimation + class(rmean_def_type), public, pointer :: ema_24hr ! Exponential moving average - 24hr window + class(rmean_def_type), public, pointer :: fixed_24hr ! Fixed, 24-hour window + class(rmean_def_type), public, pointer :: ema_lpa ! Exponential moving average - leaf photo acclimation + class(rmean_def_type), public, pointer :: moving_64day ! Moving, 64-day window; added by ahb contains From 7842661c940653a887379ac2194c7bc8e5198174 Mon Sep 17 00:00:00 2001 From: adamhb Date: Tue, 3 Aug 2021 10:42:15 -0700 Subject: [PATCH 31/81] indexed par at the seedling layer --- biogeochem/EDPhysiologyMod.F90 | 6 ++---- main/FatesInterfaceMod.F90 | 13 +++++++++++++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/biogeochem/EDPhysiologyMod.F90 b/biogeochem/EDPhysiologyMod.F90 index f7a760ca32..ddbc4b2c15 100644 --- a/biogeochem/EDPhysiologyMod.F90 +++ b/biogeochem/EDPhysiologyMod.F90 @@ -1651,12 +1651,10 @@ subroutine SeedGermination( litt, cold_stat, drought_stat, bc_in, currentPatch ) seedling_layer_par = & ( currentPatch%parprof_dir_z(currentPatch%ncl_p,maxval(currentPatch%ncan(currentPatch%ncl_p,:))) + & - currentPatch%parprof_dif_z(currentPatch%ncl_p,maxval(currentPatch%ncan(currentPatch%ncl_p,:))) + & - currentPatch%parprof_dif_z(1,1) & - ) + currentPatch%parprof_dif_z(currentPatch%ncl_p,maxval(currentPatch%ncan(currentPatch%ncl_p,:))) ) - write(fates_log(),*) 'nrm parprof', currentPatch%nrmlzd_parprof_dir_z(:,:,:) + !write(fates_log(),*) 'nrm parprof', currentPatch%nrmlzd_parprof_dir_z(:,:,:) !write(fates_log(),*) 'parprof', currentPatch%parprof_dif_z(1,:) !write(fates_log(),*) 'number_leaf_layers_in_second_canopy_layer', maxval(currentPatch%ncan(currentPatch%ncl_p,:)) diff --git a/main/FatesInterfaceMod.F90 b/main/FatesInterfaceMod.F90 index d5273a9ca7..7f6630e571 100644 --- a/main/FatesInterfaceMod.F90 +++ b/main/FatesInterfaceMod.F90 @@ -1846,6 +1846,8 @@ subroutine UpdateFatesRMeansTStep(sites,bc_in) type(ed_patch_type), pointer :: cpatch type(ed_cohort_type), pointer :: ccohort integer :: s, ifp, io_si + real(r8) :: seedling_layer_par + do s = 1,size(sites,dim=1) @@ -1856,11 +1858,22 @@ subroutine UpdateFatesRMeansTStep(sites,bc_in) call cpatch%tveg24%UpdateRMean(bc_in(s)%t_veg_pa(ifp)) call cpatch%tveg_lpa%UpdateRMean(bc_in(s)%t_veg_pa(ifp)) + !ahb wrote these lines here + seedling_layer_par = ( cpatch%parprof_dir_z(cpatch%ncl_p,maxval(cpatch%ncan(cpatch%ncl_p,:)) -1.0_r8 ) ) ! + & + ! cpatch%parprof_dif_z(cpatch%ncl_p,maxval(cpatch%ncan(cpatch%ncl_p,:))) ) + write(fates_log(),*) 'patch number', cpatch%patchno + write(fates_log(),*) 'canopy layers', cpatch%ncl_p + write(fates_log(),*) 'leaf layers', maxval(cpatch%ncan(cpatch%ncl_p,:)) + write(fates_log(),*) 'cat parprof', seedling_layer_par + + ccohort => cpatch%tallest + do while (associated(ccohort)) call ccohort%tveg_lpa%UpdateRMean(bc_in(s)%t_veg_pa(ifp)) ccohort => ccohort%shorter end do + cpatch => cpatch%younger enddo From 5f152f7242ebd07ed766da96041527d3102ccda8 Mon Sep 17 00:00:00 2001 From: adamhb Date: Thu, 5 Aug 2021 16:54:10 -0700 Subject: [PATCH 32/81] added moving fixed window (24 hr) average of par at the seedling layer as a patch-level variable --- biogeochem/EDPatchDynamicsMod.F90 | 18 ++++++++++++---- biogeochem/EDPhysiologyMod.F90 | 18 +++++++--------- main/EDTypesMod.F90 | 3 ++- main/FatesInterfaceMod.F90 | 36 +++++++++++++++++++++++-------- main/FatesRestartInterfaceMod.F90 | 12 ++++++++--- main/FatesRunningMeanMod.F90 | 3 ++- 6 files changed, 62 insertions(+), 28 deletions(-) diff --git a/biogeochem/EDPatchDynamicsMod.F90 b/biogeochem/EDPatchDynamicsMod.F90 index beeedab46b..f53d978ff2 100644 --- a/biogeochem/EDPatchDynamicsMod.F90 +++ b/biogeochem/EDPatchDynamicsMod.F90 @@ -678,7 +678,7 @@ subroutine spawn_patches( currentSite, bc_in) ! -------------------------------------------------------------------------- call new_patch%tveg24%CopyFromDonor(currentPatch%tveg24) call new_patch%tveg_lpa%CopyFromDonor(currentPatch%tveg_lpa) - + call new_patch%seedling_layer_par24%CopyFromDonor(currentPatch%seedling_layer_par24) ! -------------------------------------------------------------------------- ! The newly formed patch from disturbance (new_patch), has now been given @@ -2002,6 +2002,8 @@ subroutine create_patch(currentSite, new_patch, age, areap, label) ! Until bc's are pointed to by sites give veg temp a default temp [K] real(r8), parameter :: temp_init_veg = 15._r8+t_water_freeze_k_1atm + real(r8), parameter :: init_seedling_par = 5.0_r8 !arbtrary initialization, ahb + ! !LOCAL VARIABLES: !--------------------------------------------------------------------- integer :: el ! element loop index @@ -2021,7 +2023,13 @@ subroutine create_patch(currentSite, new_patch, age, areap, label) call new_patch%tveg24%InitRMean(fixed_24hr,init_value=temp_init_veg,init_offset=real(hlm_current_tod,r8) ) allocate(new_patch%tveg_lpa) call new_patch%tveg_lpa%InitRmean(ema_lpa,init_value=temp_init_veg) - + + + allocate(new_patch%seedling_layer_par24) + call new_patch%seedling_layer_par24%InitRMean(fixed_24hr,init_value=init_seedling_par,init_offset=real(hlm_current_tod,r8) ) + + + ! Litter ! Allocate, Zero Fluxes, and Initialize to "unset" values @@ -2526,7 +2534,8 @@ subroutine fuse_2_patches(csite, dp, rp) ! Weighted mean of the running means call rp%tveg24%FuseRMean(dp%tveg24,rp%area*inv_sum_area) call rp%tveg_lpa%FuseRMean(dp%tveg_lpa,rp%area*inv_sum_area) - + call rp%seedling_layer_par24%FuseRMean(dp%seedling_layer_par24,rp%area*inv_sum_area) !ahb + rp%fuel_eff_moist = (dp%fuel_eff_moist*dp%area + rp%fuel_eff_moist*rp%area) * inv_sum_area rp%livegrass = (dp%livegrass*dp%area + rp%livegrass*rp%area) * inv_sum_area rp%sum_fuel = (dp%sum_fuel*dp%area + rp%sum_fuel*rp%area) * inv_sum_area @@ -2868,7 +2877,8 @@ subroutine dealloc_patch(cpatch) ! Deallocate any running means deallocate(cpatch%tveg24) deallocate(cpatch%tveg_lpa) - + deallocate(cpatch%seedling_layer_par24) + return end subroutine dealloc_patch diff --git a/biogeochem/EDPhysiologyMod.F90 b/biogeochem/EDPhysiologyMod.F90 index ddbc4b2c15..c9038c8a14 100644 --- a/biogeochem/EDPhysiologyMod.F90 +++ b/biogeochem/EDPhysiologyMod.F90 @@ -1617,7 +1617,7 @@ subroutine SeedGermination( litt, cold_stat, drought_stat, bc_in, currentPatch ) real(r8) :: seedling_layer_smp ! soil matric potential at seedling rooting depth real(r8) :: wetness_index ! a soil 'wetness index' calculated from soil matric potential - real(r8) :: seedling_layer_par ! photosynthetically active radiation at the seedling layer + real(r8) :: seedling_layer_par ! photosynthetically active radiation at the seedling layer real(r8) :: photoblastic_germ_modifier ! seedling emergence rate modifier for light-sensitive germination ! used in the moisture-sensitive emergence function real(r8) :: seedling_emerg_rate ! the fraction of the seed bank emerging in the current time step @@ -1649,16 +1649,14 @@ subroutine SeedGermination( litt, cold_stat, drought_stat, bc_in, currentPatch ) !------------------------------------------------------------------------------------------- !Step 1. calculate the photoblastic germination rate modifier - seedling_layer_par = & - ( currentPatch%parprof_dir_z(currentPatch%ncl_p,maxval(currentPatch%ncan(currentPatch%ncl_p,:))) + & - currentPatch%parprof_dif_z(currentPatch%ncl_p,maxval(currentPatch%ncan(currentPatch%ncl_p,:))) ) - - - !write(fates_log(),*) 'nrm parprof', currentPatch%nrmlzd_parprof_dir_z(:,:,:) - !write(fates_log(),*) 'parprof', currentPatch%parprof_dif_z(1,:) - !write(fates_log(),*) 'number_leaf_layers_in_second_canopy_layer', maxval(currentPatch%ncan(currentPatch%ncl_p,:)) + seedling_layer_par = currentPatch%seedling_layer_par24%GetMean() + + ! write(fates_log(),*) 'nrm parprof', currentPatch%nrmlzd_parprof_dir_z(:,:,:) + ! write(fates_log(),*) 'parprof', currentPatch%parprof_dif_z(1,:) + ! write(fates_log(),*) 'number_leaf_layers_in_second_canopy_layer', maxval(currentPatch%ncan(currentPatch%ncl_p,:)) - !write(fates_log(),*) 'seedling_layer_par_raw', seedling_layer_par + write(fates_log(),*) 'patchno', currentPatch%patchno + write(fates_log(),*) 'seedling_layer_par', seedling_layer_par seedling_layer_par = seedling_layer_par * 4.6_r8 !covert to umol s-1 of PAR !1 W/m2 ≈ 4.6 μmole.m2/s diff --git a/main/EDTypesMod.F90 b/main/EDTypesMod.F90 index 6c0f21626a..3783bc4084 100644 --- a/main/EDTypesMod.F90 +++ b/main/EDTypesMod.F90 @@ -426,7 +426,8 @@ module EDTypesMod class(rmean_type), pointer :: tveg_lpa ! Running mean of vegetation temperature at the ! leaf photosynthesis acclimation timescale [K] - class(rmean_type), pointer :: seedling_layer_par ! photosynthetically active radiation at the seedling layer (w-m2) + class(rmean_type), pointer :: seedling_layer_par24 ! 24-hour mean of photosynthetically active radiation + ! at the seedling layer (w-m2) ! LEAF ORGANIZATION real(r8) :: pft_agb_profile(maxpft,n_dbh_bins) ! binned above ground biomass, for patch fusion: KgC/m2 diff --git a/main/FatesInterfaceMod.F90 b/main/FatesInterfaceMod.F90 index 7f6630e571..7230ae606b 100644 --- a/main/FatesInterfaceMod.F90 +++ b/main/FatesInterfaceMod.F90 @@ -1846,8 +1846,10 @@ subroutine UpdateFatesRMeansTStep(sites,bc_in) type(ed_patch_type), pointer :: cpatch type(ed_cohort_type), pointer :: ccohort integer :: s, ifp, io_si - real(r8) :: seedling_layer_par - + real(r8) :: new_seedling_layer_par !seedling layer par in the current timestep + integer :: n_leaf !number of leaf layers per canopy layer in patch + real(r8) :: lai_sun_frac + real(r8) :: lai_shade_frac do s = 1,size(sites,dim=1) @@ -1857,14 +1859,30 @@ subroutine UpdateFatesRMeansTStep(sites,bc_in) ifp=ifp+1 call cpatch%tveg24%UpdateRMean(bc_in(s)%t_veg_pa(ifp)) call cpatch%tveg_lpa%UpdateRMean(bc_in(s)%t_veg_pa(ifp)) + + !updating seedling layer par; ahb, August 2021 + !--------------------------------------------------------------------------------------- - !ahb wrote these lines here - seedling_layer_par = ( cpatch%parprof_dir_z(cpatch%ncl_p,maxval(cpatch%ncan(cpatch%ncl_p,:)) -1.0_r8 ) ) ! + & - ! cpatch%parprof_dif_z(cpatch%ncl_p,maxval(cpatch%ncan(cpatch%ncl_p,:))) ) - write(fates_log(),*) 'patch number', cpatch%patchno - write(fates_log(),*) 'canopy layers', cpatch%ncl_p - write(fates_log(),*) 'leaf layers', maxval(cpatch%ncan(cpatch%ncl_p,:)) - write(fates_log(),*) 'cat parprof', seedling_layer_par + n_leaf = maxval(cpatch%ncan(cpatch%ncl_p,:)) !calculating the number of leaf layers + !in the lowest canopy layer + + !calculating the fraction of total lai (summed across pfts) in sun vs. shade + !at the lowest leaf level of the lowest canopy level + lai_sun_frac = sum(cpatch%ed_laisun_z(cpatch%ncl_p,:,n_leaf)) & + / ( sum(cpatch%ed_laisun_z(cpatch%ncl_p,:,n_leaf)) + & !summed across pfts + sum(cpatch%ed_laisha_z(cpatch%ncl_p,:,n_leaf)) ) !summed across pfts + + lai_shade_frac = 1.0_r8 - lai_sun_frac + + !calculating seedling layer par for the current time step + !using the weighted average of direct and diffuse par profiles + + new_seedling_layer_par = & + (cpatch%parprof_dir_z(cpatch%ncl_p,n_leaf) * lai_sun_frac) + & + (cpatch%parprof_dif_z(cpatch%ncl_p,n_leaf) * (1.0_r8 - lai_sun_frac)) + + call cpatch%seedling_layer_par24%UpdateRMean(new_seedling_layer_par) + !--------------------------------------------------------------------------------------- ccohort => cpatch%tallest diff --git a/main/FatesRestartInterfaceMod.F90 b/main/FatesRestartInterfaceMod.F90 index 04a17e1a1c..55f46fb5d5 100644 --- a/main/FatesRestartInterfaceMod.F90 +++ b/main/FatesRestartInterfaceMod.F90 @@ -142,6 +142,7 @@ module FatesRestartInterfaceMod integer :: ir_tveg24_pa integer :: ir_tveglpa_pa integer :: ir_tveglpa_co + integer :: ir_seedling_layer_par24_pa !ahb integer :: ir_ddbhdt_co integer :: ir_resp_tstep_co @@ -1215,13 +1216,16 @@ subroutine define_restart_vars(this, initialize_variables) call this%set_restart_var(vname='fates_promcflux', vtype=site_r8, & long_name='fates diagnostic promotion carbon flux ', & units='', flushval = flushzero, & - hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_promcflux_si ) - + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_promcflux_si ) call this%DefineRMeanRestartVar(vname='fates_tveg24patch',vtype=cohort_r8, & long_name='24-hour patch veg temp', & units='K', initialize=initialize_variables,ivar=ivar, index = ir_tveg24_pa) + call this%DefineRMeanRestartVar(vname='fates_seedling_layer_par24',vtype=cohort_r8, & + long_name='24-hour seedling layer PAR', & + units='K', initialize=initialize_variables,ivar=ivar, index = ir_seedling_layer_par24_pa) + call this%DefineRMeanRestartVar(vname='fates_tveglpapatch',vtype=cohort_r8, & long_name='running average (EMA) of patch veg temp for photo acclim', & units='K', initialize=initialize_variables,ivar=ivar, index = ir_tveglpa_pa) @@ -2030,6 +2034,7 @@ subroutine set_restart_vectors(this,nc,nsites,sites) ! Patch level running means call this%SetRMeanRestartVar(cpatch%tveg24, ir_tveg24_pa, io_idx_co_1st) call this%SetRMeanRestartVar(cpatch%tveg_lpa, ir_tveglpa_pa, io_idx_co_1st) + call this%SetRMeanRestartVar(cpatch%seedling_layer_par24, ir_seedling_layer_par24_pa, io_idx_co_1st) ! set cohorts per patch for IO rio_ncohort_pa( io_idx_co_1st ) = cohortsperpatch @@ -2816,7 +2821,8 @@ subroutine get_restart_vectors(this, nc, nsites, sites) call this%GetRMeanRestartVar(cpatch%tveg24, ir_tveg24_pa, io_idx_co_1st) call this%GetRMeanRestartVar(cpatch%tveg_lpa, ir_tveglpa_pa, io_idx_co_1st) - + call this%GetRMeanRestartVar(cpatch%seedling_layer_par24, ir_seedling_layer_par24_pa, io_idx_co_1st) + ! set cohorts per patch for IO if ( debug ) then diff --git a/main/FatesRunningMeanMod.F90 b/main/FatesRunningMeanMod.F90 index 28d39c6995..600703954a 100644 --- a/main/FatesRunningMeanMod.F90 +++ b/main/FatesRunningMeanMod.F90 @@ -91,7 +91,8 @@ module FatesRunningMeanMod class(rmean_def_type), public, pointer :: ema_24hr ! Exponential moving average - 24hr window class(rmean_def_type), public, pointer :: fixed_24hr ! Fixed, 24-hour window class(rmean_def_type), public, pointer :: ema_lpa ! Exponential moving average - leaf photo acclimation - class(rmean_def_type), public, pointer :: moving_64day ! Moving, 64-day window; added by ahb + class(rmean_def_type), public, pointer :: ema_seedling_mort ! Exponential moving average + ! seedling mort from light contains From 61756c8f4c844e4ec8491de5873daba1b904d4f3 Mon Sep 17 00:00:00 2001 From: adamhb Date: Tue, 10 Aug 2021 14:39:41 -0700 Subject: [PATCH 33/81] added running means for par and smp; model crashing --- biogeochem/EDPatchDynamicsMod.F90 | 34 ++++++++++++++++++++- biogeochem/EDPhysiologyMod.F90 | 5 +++- main/EDParamsMod.F90 | 47 +++++++++++++++++++++++++++++ main/EDTypesMod.F90 | 16 ++++++++++ main/FatesInterfaceMod.F90 | 49 +++++++++++++++++++++++++++++-- main/FatesRestartInterfaceMod.F90 | 27 ++++++++++++++++- main/FatesRunningMeanMod.F90 | 11 ++++--- 7 files changed, 180 insertions(+), 9 deletions(-) diff --git a/biogeochem/EDPatchDynamicsMod.F90 b/biogeochem/EDPatchDynamicsMod.F90 index f53d978ff2..a5d79c41c0 100644 --- a/biogeochem/EDPatchDynamicsMod.F90 +++ b/biogeochem/EDPatchDynamicsMod.F90 @@ -87,6 +87,7 @@ module EDPatchDynamicsMod use EDParamsMod, only : logging_event_code use EDParamsMod, only : logging_export_frac use FatesRunningMeanMod, only : ema_24hr, fixed_24hr, ema_lpa + use FatesRunningMeanMod, only : ema_sdlng_emerg_h2o, ema_sdlng_mort_par, ema_sdlng2sap_par ! CIME globals use shr_infnan_mod , only : nan => shr_infnan_nan, assignment(=) @@ -679,6 +680,9 @@ subroutine spawn_patches( currentSite, bc_in) call new_patch%tveg24%CopyFromDonor(currentPatch%tveg24) call new_patch%tveg_lpa%CopyFromDonor(currentPatch%tveg_lpa) call new_patch%seedling_layer_par24%CopyFromDonor(currentPatch%seedling_layer_par24) + call new_patch%sdlng_emerg_smp%CopyFromDonor(currentPatch%sdlng_emerg_smp) + call new_patch%sdlng_mort_par%CopyFromDonor(currentPatch%sdlng_mort_par) + call new_patch%sdlng2sap_par%CopyFromDonor(currentPatch%sdlng2sap_par) ! -------------------------------------------------------------------------- ! The newly formed patch from disturbance (new_patch), has now been given @@ -2002,7 +2006,11 @@ subroutine create_patch(currentSite, new_patch, age, areap, label) ! Until bc's are pointed to by sites give veg temp a default temp [K] real(r8), parameter :: temp_init_veg = 15._r8+t_water_freeze_k_1atm - real(r8), parameter :: init_seedling_par = 5.0_r8 !arbtrary initialization, ahb + real(r8), parameter :: init_seedling_par = 5.0_r8 !arbtrary initialization, ahb + + real(r8), parameter :: init_seedling_smp = -26652.0_r8 !mean smp (mm) from prior ED2 + !simulation at BCI (arbitrary) + ! !LOCAL VARIABLES: !--------------------------------------------------------------------- @@ -2028,6 +2036,22 @@ subroutine create_patch(currentSite, new_patch, age, areap, label) allocate(new_patch%seedling_layer_par24) call new_patch%seedling_layer_par24%InitRMean(fixed_24hr,init_value=init_seedling_par,init_offset=real(hlm_current_tod,r8) ) + allocate(new_patch%sdlng_emerg_smp) + call new_patch%sdlng_emerg_smp%InitRMean(ema_sdlng_emerg_h2o, & + init_value=init_seedling_smp,init_offset=real(hlm_current_tod,r8) ) + + allocate(new_patch%sdlng_mort_par) + call new_patch%sdlng_mort_par%InitRMean(ema_sdlng_mort_par, & + init_value=init_seedling_par,init_offset=real(hlm_current_tod,r8) ) + + !allocate(new_patch%sdlng_mdd) + !call new_patch%sdlng_mdd%InitRMean(ema_sdlng_mdd, & + ! init_value=0.0_r8,init_offset=real(hlm_current_tod,r8) ) + + allocate(new_patch%sdlng2sap_par) + call new_patch%sdlng2sap_par%InitRMean(ema_sdlng2sap_par, & + init_value=init_seedling_par,init_offset=real(hlm_current_tod,r8) ) + ! Litter @@ -2535,6 +2559,9 @@ subroutine fuse_2_patches(csite, dp, rp) call rp%tveg24%FuseRMean(dp%tveg24,rp%area*inv_sum_area) call rp%tveg_lpa%FuseRMean(dp%tveg_lpa,rp%area*inv_sum_area) call rp%seedling_layer_par24%FuseRMean(dp%seedling_layer_par24,rp%area*inv_sum_area) !ahb + call rp%sdlng_emerg_smp%FuseRMean(dp%sdlng_emerg_smp,rp%area*inv_sum_area) !ahb + call rp%sdlng_mort_par%FuseRMean(dp%sdlng_mort_par,rp%area*inv_sum_area) !ahb + call rp%sdlng2sap_par%FuseRMean(dp%sdlng2sap_par,rp%area*inv_sum_area) !ahb rp%fuel_eff_moist = (dp%fuel_eff_moist*dp%area + rp%fuel_eff_moist*rp%area) * inv_sum_area rp%livegrass = (dp%livegrass*dp%area + rp%livegrass*rp%area) * inv_sum_area @@ -2878,6 +2905,11 @@ subroutine dealloc_patch(cpatch) deallocate(cpatch%tveg24) deallocate(cpatch%tveg_lpa) deallocate(cpatch%seedling_layer_par24) + deallocate(cpatch%sdlng_emerg_smp) + deallocate(cpatch%sdlng_mort_par) + deallocate(cpatch%sdlng_mdd) + deallocate(cpatch%sdlng2sap_par) + return end subroutine dealloc_patch diff --git a/biogeochem/EDPhysiologyMod.F90 b/biogeochem/EDPhysiologyMod.F90 index c9038c8a14..11184a9878 100644 --- a/biogeochem/EDPhysiologyMod.F90 +++ b/biogeochem/EDPhysiologyMod.F90 @@ -1657,7 +1657,10 @@ subroutine SeedGermination( litt, cold_stat, drought_stat, bc_in, currentPatch ) write(fates_log(),*) 'patchno', currentPatch%patchno write(fates_log(),*) 'seedling_layer_par', seedling_layer_par - + write(fates_log(),*) 'seedling_emerg_smp', currentPatch%sdlng_emerg_smp%GetMean() + write(fates_log(),*) 'seedling_mort_par', currentPatch%sdlng_mort_par%GetMean() + write(fates_log(),*) 'seedling2sap_trans_par', currentPatch%sdlng2sap_par%GetMean() + seedling_layer_par = seedling_layer_par * 4.6_r8 !covert to umol s-1 of PAR !1 W/m2 ≈ 4.6 μmole.m2/s diff --git a/main/EDParamsMod.F90 b/main/EDParamsMod.F90 index 1f10aa2c7f..ea12daabe3 100644 --- a/main/EDParamsMod.F90 +++ b/main/EDParamsMod.F90 @@ -31,6 +31,17 @@ module EDParamsMod ! of vegetation temperature used in photosynthesis ! temperature acclimation (NOT YET IMPLEMENTED) + real(r8),protected, public :: sdlng_emerg_h2o_timescale !Length of the window for the exponential moving + !average of smp used to calculate seedling emergence + real(r8),protected, public :: sdlng_mort_par_timescale !Length of the window for the exponential moving average + !of par at the seedling layer used to calculate + !seedling mortality + real(r8),protected, public :: sdlng_mdd_timescale !Length of the window for the exponential moving average + ! of moisture deficit days used to calculate seedling mortality + real(r8),protected, public :: sdlng2sap_par_timescale !Length of the window for the exponential + !moving average of par at the seedling layer used to + !calculate seedling to sapling transition rates + integer,protected, public :: maintresp_model ! switch for choosing between leaf maintenance ! respiration model. 1=Ryan (1991) (NOT YET IMPLEMENTED) integer,protected, public :: photo_tempsens_model ! switch for choosing the model that defines the temperature @@ -94,6 +105,10 @@ module EDParamsMod character(len=param_string_length),parameter,public :: ED_name_vai_top_bin_width = "fates_vai_top_bin_width" character(len=param_string_length),parameter,public :: ED_name_vai_width_increase_factor = "fates_vai_width_increase_factor" character(len=param_string_length),parameter,public :: ED_name_photo_temp_acclim_timescale = "fates_photo_temp_acclim_timescale" + character(len=param_string_length),parameter,public :: ED_name_sdlng_emerg_h2o_timescale = "fates_sdlng_emerg_h2o_timescale" + character(len=param_string_length),parameter,public :: ED_name_sdlng_mort_par_timescale = "fates_sdlng_mort_par_timescale" + character(len=param_string_length),parameter,public :: ED_name_sdlng_mdd_timescale = "fates_sdlng_mdd_timescale" + character(len=param_string_length),parameter,public :: ED_name_sdlng2sap_par_timescale = "fates_sdlng2sap_par_timescale" character(len=param_string_length),parameter,public :: name_photo_tempsens_model = "fates_photo_tempsens_model" character(len=param_string_length),parameter,public :: name_maintresp_model = "fates_maintresp_model" character(len=param_string_length),parameter,public :: ED_name_hydr_htftype_node = "fates_hydr_htftype_node" @@ -212,6 +227,10 @@ subroutine FatesParamsInit() vai_top_bin_width = nan vai_width_increase_factor = nan photo_temp_acclim_timescale = nan + sdlng_emerg_h2o_timescale = nan + sdlng_mort_par_timescale = nan + sdlng_mdd_timescale = nan + sdlng2sap_par_timescale = nan photo_tempsens_model = -9 maintresp_model = -9 fates_mortality_disturbance_fraction = nan @@ -292,6 +311,18 @@ subroutine FatesRegisterParams(fates_params) call fates_params%RegisterParameter(name=ED_name_photo_temp_acclim_timescale, dimension_shape=dimension_shape_scalar, & dimension_names=dim_names_scalar) + call fates_params%RegisterParameter(name=ED_name_sdlng_emerg_h2o_timescale, dimension_shape=dimension_shape_scalar, & + dimension_names=dim_names_scalar) + + call fates_params%RegisterParameter(name=ED_name_sdlng_mort_par_timescale, dimension_shape=dimension_shape_scalar, & + dimension_names=dim_names_scalar) + + call fates_params%RegisterParameter(name=ED_name_sdlng_mdd_timescale, dimension_shape=dimension_shape_scalar, & + dimension_names=dim_names_scalar) + + call fates_params%RegisterParameter(name=ED_name_sdlng2sap_par_timescale, dimension_shape=dimension_shape_scalar, & + dimension_names=dim_names_scalar) + call fates_params%RegisterParameter(name=name_photo_tempsens_model,dimension_shape=dimension_shape_scalar, & dimension_names=dim_names_scalar) @@ -472,6 +503,18 @@ subroutine FatesReceiveParams(fates_params) call fates_params%RetreiveParameter(name=ED_name_photo_temp_acclim_timescale, & data=photo_temp_acclim_timescale) + call fates_params%RetreiveParameter(name=ED_name_sdlng_emerg_h2o_timescale, & + data=sdlng_emerg_h2o_timescale) + + call fates_params%RetreiveParameter(name=ED_name_sdlng_mort_par_timescale, & + data=sdlng_mort_par_timescale) + + call fates_params%RetreiveParameter(name=ED_name_sdlng_mdd_timescale, & + data=sdlng_mdd_timescale) + + call fates_params%RetreiveParameter(name=ED_name_sdlng2sap_par_timescale, & + data=sdlng2sap_par_timescale) + call fates_params%RetreiveParameter(name=name_photo_tempsens_model, & data=tmpreal) photo_tempsens_model = nint(tmpreal) @@ -651,6 +694,10 @@ subroutine FatesReportParams(is_master) write(fates_log(),fmt0) 'vai_top_bin_width = ',vai_top_bin_width write(fates_log(),fmt0) 'vai_width_increase_factor = ',vai_width_increase_factor write(fates_log(),fmt0) 'photo_temp_acclim_timescale = ',photo_temp_acclim_timescale + write(fates_log(),fmt0) 'sdlng_emerg_h2o_timescale = ', sdlng_emerg_h2o_timescale + write(fates_log(),fmt0) 'sdlng_mort_par_timescale = ', sdlng_mort_par_timescale + write(fates_log(),fmt0) 'sdlng_mdd_timescale = ', sdlng_mdd_timescale + write(fates_log(),fmt0) 'sdlng2sap_par_timescale = ', sdlng2sap_par_timescale write(fates_log(),fmti) 'hydr_htftype_node = ',hydr_htftype_node write(fates_log(),fmt0) 'fates_mortality_disturbance_fraction = ',fates_mortality_disturbance_fraction write(fates_log(),fmt0) 'ED_val_comp_excln = ',ED_val_comp_excln diff --git a/main/EDTypesMod.F90 b/main/EDTypesMod.F90 index 3783bc4084..18549d27bb 100644 --- a/main/EDTypesMod.F90 +++ b/main/EDTypesMod.F90 @@ -429,6 +429,22 @@ module EDTypesMod class(rmean_type), pointer :: seedling_layer_par24 ! 24-hour mean of photosynthetically active radiation ! at the seedling layer (w-m2) + class(rmean_type), pointer :: sdlng_emerg_smp ! Running mean of soil matric potential at the seedling + ! rooting depth at the h2o seedling emergence + ! timescale (see sdlng_emerg_h2o_timescale parameter) + class(rmean_type), pointer :: sdlng_mort_par ! Running mean of photosythetically active radiation + ! at the seedling layer and at the par-based seedling + ! mortality timescale (sdlng_mort_par_timescale) + class(rmean_type), pointer :: sdlng_mdd ! Running mean of moisture deficit days + ! at the seedling layer and at the mdd-based seedling + ! mortality timescale (sdlng_mdd_timescale) + ! (sdlng2sap_par_timescale) + class(rmean_type), pointer :: sdlng2sap_par ! Running mean of photosythetically active radiation + ! at the seedling layer and at the par-based seedling + ! to sapling transition timescale + ! (sdlng2sap_par_timescale) + + ! LEAF ORGANIZATION real(r8) :: pft_agb_profile(maxpft,n_dbh_bins) ! binned above ground biomass, for patch fusion: KgC/m2 real(r8) :: canopy_layer_tlai(nclmax) ! total leaf area index of each canopy layer diff --git a/main/FatesInterfaceMod.F90 b/main/FatesInterfaceMod.F90 index 7230ae606b..c2a6e1375f 100644 --- a/main/FatesInterfaceMod.F90 +++ b/main/FatesInterfaceMod.F90 @@ -42,6 +42,9 @@ module FatesInterfaceMod use EDParamsMod , only : bgc_soil_salinity use FatesPlantHydraulicsMod , only : InitHydroGlobals use EDParamsMod , only : photo_temp_acclim_timescale + use EDParamsMod , only : sdlng_emerg_h2o_timescale + use EDParamsMod , only : sdlng_mort_par_timescale + use EDParamsMod , only : sdlng2sap_par_timescale use EDParamsMod , only : ED_val_history_sizeclass_bin_edges use EDParamsMod , only : ED_val_history_ageclass_bin_edges use EDParamsMod , only : ED_val_history_height_bin_edges @@ -74,6 +77,8 @@ module FatesInterfaceMod use PRTAllometricCarbonMod , only : InitPRTGlobalAllometricCarbon use PRTAllometricCNPMod , only : InitPRTGlobalAllometricCNP use FatesRunningMeanMod , only : ema_24hr + use FatesRunningMeanMod , only : ema_sdlng_emerg_h2o, ema_sdlng_mort_par + use FatesRunningMeanMod , only : ema_sdlng_mdd, ema_sdlng2sap_par use FatesRunningMeanMod , only : fixed_24hr use FatesRunningMeanMod , only : ema_lpa use FatesRunningMeanMod , only : moving_ema_window @@ -872,6 +877,20 @@ subroutine SetFatesGlobalElements(use_fates) allocate(ema_lpa) call ema_lpa%define(photo_temp_acclim_timescale*sec_per_day, & hlm_stepsize,moving_ema_window) + allocate(ema_sdlng_emerg_h2o) + call ema_sdlng_emerg_h2o%define(sdlng_emerg_h2o_timescale*sec_per_day, & + hlm_stepsize,moving_ema_window) + allocate(ema_sdlng_mort_par) + call ema_sdlng_mort_par%define(sdlng_mort_par_timescale*sec_per_day, & + hlm_stepsize,moving_ema_window) + !allocate(ema_sdlng_mdd) + !call ema_sdlng_mdd%define(sdlng_mdd_timescale*sec_per_day, & + ! hlm_stepsize,moving_ema_window) + allocate(ema_sdlng2sap_par) + call ema_sdlng2sap_par%define(sdlng2sap_par_timescale*sec_per_day, & + hlm_stepsize,moving_ema_window) + + else ! If we are not using FATES, the cohort dimension is still @@ -1847,6 +1866,14 @@ subroutine UpdateFatesRMeansTStep(sites,bc_in) type(ed_cohort_type), pointer :: ccohort integer :: s, ifp, io_si real(r8) :: new_seedling_layer_par !seedling layer par in the current timestep + real(r8) :: new_seedling_layer_smp !seedling layer smp in the current timestep + !real(r8) :: new_seedling_mdd !seedling layer moisture deficit days in the current timestep + + !real(r8), parameter :: seedling_smp_crit = -175912.9_r8 !seedling soil moisture stress + !threshold at which point + !the seedling layer starts accumulating moisture + !deficit days; move to pft-specific param if works + integer :: ilayer_seedling_root !the soil layer at seedling rooting depth integer :: n_leaf !number of leaf layers per canopy layer in patch real(r8) :: lai_sun_frac real(r8) :: lai_shade_frac @@ -1860,7 +1887,8 @@ subroutine UpdateFatesRMeansTStep(sites,bc_in) call cpatch%tveg24%UpdateRMean(bc_in(s)%t_veg_pa(ifp)) call cpatch%tveg_lpa%UpdateRMean(bc_in(s)%t_veg_pa(ifp)) - !updating seedling layer par; ahb, August 2021 + !updating seedling layer par, soil matric potential and + !moisture deficit days (mdd) in the seedling layer; ahb, August 2021 !--------------------------------------------------------------------------------------- n_leaf = maxval(cpatch%ncan(cpatch%ncl_p,:)) !calculating the number of leaf layers @@ -1880,8 +1908,25 @@ subroutine UpdateFatesRMeansTStep(sites,bc_in) new_seedling_layer_par = & (cpatch%parprof_dir_z(cpatch%ncl_p,n_leaf) * lai_sun_frac) + & (cpatch%parprof_dif_z(cpatch%ncl_p,n_leaf) * (1.0_r8 - lai_sun_frac)) - + call cpatch%seedling_layer_par24%UpdateRMean(new_seedling_layer_par) + call cpatch%sdlng_mort_par%UpdateRMean(new_seedling_layer_par) + call cpatch%sdlng2sap_par%UpdateRMean(new_seedling_layer_par) + + !calculating seedling layer soil matric potential for the current time step + !note: need to make this a pft-specific running mean... + ilayer_seedling_root = minloc(abs(bc_in(s)%z_sisl(:)-EDPftvarcon_inst%seedling_root_depth(1)),dim=1) + new_seedling_layer_smp = bc_in(s)%smp_sl(ilayer_seedling_root) + + !updating the soil matric potential moving averages + call cpatch%sdlng_emerg_smp%UpdateRMean(new_seedling_layer_smp) + + !calculating moisture deficit days in the seedling layer + !new_seedling_mdd = 0.0_r8 + + ! new_seedling_mdd = (abs(seedling_smp_crit) - abs(new_seedling_layer_smp)) * -1.0_r8 + + !--------------------------------------------------------------------------------------- diff --git a/main/FatesRestartInterfaceMod.F90 b/main/FatesRestartInterfaceMod.F90 index 55f46fb5d5..8da2a096cc 100644 --- a/main/FatesRestartInterfaceMod.F90 +++ b/main/FatesRestartInterfaceMod.F90 @@ -143,7 +143,13 @@ module FatesRestartInterfaceMod integer :: ir_tveglpa_pa integer :: ir_tveglpa_co integer :: ir_seedling_layer_par24_pa !ahb + integer :: ir_sdlng_emerg_smp_pa !ahb + integer :: ir_sdlng_mort_par_pa ! ahb + integer :: ir_sdlng2sap_par_pa ! ahb + + + integer :: ir_ddbhdt_co integer :: ir_resp_tstep_co integer :: ir_pft_co @@ -1224,7 +1230,19 @@ subroutine define_restart_vars(this, initialize_variables) call this%DefineRMeanRestartVar(vname='fates_seedling_layer_par24',vtype=cohort_r8, & long_name='24-hour seedling layer PAR', & - units='K', initialize=initialize_variables,ivar=ivar, index = ir_seedling_layer_par24_pa) + units='W m2-1', initialize=initialize_variables,ivar=ivar, index = ir_seedling_layer_par24_pa) + + call this%DefineRMeanRestartVar(vname='fates_sdlng_emerg_smp',vtype=cohort_r8, & + long_name='seedling layer PAR on the seedling emergence timescale', & + units='mm suction', initialize=initialize_variables,ivar=ivar, index = ir_sdlng_emerg_smp_pa) + + call this%DefineRMeanRestartVar(vname='fates_sdlng_mort_par',vtype=cohort_r8, & + long_name='seedling layer PAR on the seedling mortality timescale', & + units='W m2-1', initialize=initialize_variables,ivar=ivar, index = ir_sdlng_mort_par_pa) + + call this%DefineRMeanRestartVar(vname='fates_sdlng2sap_par',vtype=cohort_r8, & + long_name='seedling layer PAR on the seedling to sapling transition timescale', & + units='W m2-1', initialize=initialize_variables,ivar=ivar, index = ir_sdlng2sap_par_pa) call this%DefineRMeanRestartVar(vname='fates_tveglpapatch',vtype=cohort_r8, & long_name='running average (EMA) of patch veg temp for photo acclim', & @@ -2035,6 +2053,9 @@ subroutine set_restart_vectors(this,nc,nsites,sites) call this%SetRMeanRestartVar(cpatch%tveg24, ir_tveg24_pa, io_idx_co_1st) call this%SetRMeanRestartVar(cpatch%tveg_lpa, ir_tveglpa_pa, io_idx_co_1st) call this%SetRMeanRestartVar(cpatch%seedling_layer_par24, ir_seedling_layer_par24_pa, io_idx_co_1st) + call this%SetRMeanRestartVar(cpatch%sdlng_emerg_smp, ir_sdlng_emerg_smp_pa,io_idx_co_1st) + call this%SetRMeanRestartVar(cpatch%sdlng_mort_par, ir_sdlng_mort_par_pa,io_idx_co_1st) + call this%SetRMeanRestartVar(cpatch%sdlng2sap_par, ir_sdlng2sap_par_pa,io_idx_co_1st) ! set cohorts per patch for IO rio_ncohort_pa( io_idx_co_1st ) = cohortsperpatch @@ -2822,6 +2843,10 @@ subroutine get_restart_vectors(this, nc, nsites, sites) call this%GetRMeanRestartVar(cpatch%tveg24, ir_tveg24_pa, io_idx_co_1st) call this%GetRMeanRestartVar(cpatch%tveg_lpa, ir_tveglpa_pa, io_idx_co_1st) call this%GetRMeanRestartVar(cpatch%seedling_layer_par24, ir_seedling_layer_par24_pa, io_idx_co_1st) + call this%GetRMeanRestartVar(cpatch%sdlng_emerg_smp, ir_sdlng_emerg_smp_pa,io_idx_co_1st) + call this%GetRMeanRestartVar(cpatch%sdlng_mort_par, ir_sdlng_mort_par_pa,io_idx_co_1st) + call this%GetRMeanRestartVar(cpatch%sdlng2sap_par, ir_sdlng2sap_par_pa,io_idx_co_1st) + ! set cohorts per patch for IO diff --git a/main/FatesRunningMeanMod.F90 b/main/FatesRunningMeanMod.F90 index 600703954a..cd54e3ca25 100644 --- a/main/FatesRunningMeanMod.F90 +++ b/main/FatesRunningMeanMod.F90 @@ -90,10 +90,13 @@ module FatesRunningMeanMod class(rmean_def_type), public, pointer :: ema_24hr ! Exponential moving average - 24hr window class(rmean_def_type), public, pointer :: fixed_24hr ! Fixed, 24-hour window - class(rmean_def_type), public, pointer :: ema_lpa ! Exponential moving average - leaf photo acclimation - class(rmean_def_type), public, pointer :: ema_seedling_mort ! Exponential moving average - ! seedling mort from light - + class(rmean_def_type), public, pointer :: ema_lpa ! Exponential moving average (EMA) - leaf photo acclimation + class(rmean_def_type), public, pointer :: ema_sdlng_emerg_h2o ! EMA for moisture-based seedling emergence + class(rmean_def_type), public, pointer :: ema_sdlng_mort_par ! EMA for seedling mort from light stress + class(rmean_def_type), public, pointer :: ema_sdlng_mdd ! EMA for seedling moisture deficit days + class(rmean_def_type), public, pointer :: ema_sdlng2sap_par ! EMA for seedling to sapling transition rates + ! based in par + contains From 989da81f8dbeb5bd8199a499b78682843d3026f9 Mon Sep 17 00:00:00 2001 From: adamhb Date: Thu, 12 Aug 2021 17:38:03 -0700 Subject: [PATCH 34/81] the running means are working --- biogeochem/EDPatchDynamicsMod.F90 | 65 +++++++++++++--------- biogeochem/EDPhysiologyMod.F90 | 20 ++++--- main/EDTypesMod.F90 | 7 +-- main/FatesInterfaceMod.F90 | 89 ++++++++++++++++++++++--------- main/FatesRestartInterfaceMod.F90 | 24 +++++++-- main/FatesRunningMeanMod.F90 | 5 ++ 6 files changed, 145 insertions(+), 65 deletions(-) diff --git a/biogeochem/EDPatchDynamicsMod.F90 b/biogeochem/EDPatchDynamicsMod.F90 index a5d79c41c0..92cb737bf4 100644 --- a/biogeochem/EDPatchDynamicsMod.F90 +++ b/biogeochem/EDPatchDynamicsMod.F90 @@ -86,7 +86,7 @@ module EDPatchDynamicsMod use SFParamsMod, only : SF_VAL_CWD_FRAC use EDParamsMod, only : logging_event_code use EDParamsMod, only : logging_export_frac - use FatesRunningMeanMod, only : ema_24hr, fixed_24hr, ema_lpa + use FatesRunningMeanMod, only : ema_24hr, fixed_24hr, ema_lpa, ema_sdlng_mdd use FatesRunningMeanMod, only : ema_sdlng_emerg_h2o, ema_sdlng_mort_par, ema_sdlng2sap_par ! CIME globals @@ -473,6 +473,7 @@ subroutine spawn_patches( currentSite, bc_in) real(r8) :: patch_site_areadis ! total area disturbed in m2 per patch per day real(r8) :: age ! notional age of this patch in years integer :: el ! element loop index + integer :: pft ! pft loop index integer :: tnull ! is there a tallest cohort? integer :: snull ! is there a shortest cohort? integer :: levcan ! canopy level @@ -680,10 +681,16 @@ subroutine spawn_patches( currentSite, bc_in) call new_patch%tveg24%CopyFromDonor(currentPatch%tveg24) call new_patch%tveg_lpa%CopyFromDonor(currentPatch%tveg_lpa) call new_patch%seedling_layer_par24%CopyFromDonor(currentPatch%seedling_layer_par24) - call new_patch%sdlng_emerg_smp%CopyFromDonor(currentPatch%sdlng_emerg_smp) call new_patch%sdlng_mort_par%CopyFromDonor(currentPatch%sdlng_mort_par) call new_patch%sdlng2sap_par%CopyFromDonor(currentPatch%sdlng2sap_par) + + do pft = 1,maxpft + call new_patch%sdlng_emerg_smp(pft)%p%CopyFromDonor(currentPatch%sdlng_emerg_smp(pft)%p) !ahb + call new_patch%sdlng_mdd(pft)%p%CopyFromDonor(currentPatch%sdlng_mdd(pft)%p) !ahb + enddo + + ! -------------------------------------------------------------------------- ! 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. @@ -2010,7 +2017,7 @@ subroutine create_patch(currentSite, new_patch, age, areap, label) real(r8), parameter :: init_seedling_smp = -26652.0_r8 !mean smp (mm) from prior ED2 !simulation at BCI (arbitrary) - + integer :: pft !pft index ! !LOCAL VARIABLES: !--------------------------------------------------------------------- @@ -2031,28 +2038,24 @@ subroutine create_patch(currentSite, new_patch, age, areap, label) call new_patch%tveg24%InitRMean(fixed_24hr,init_value=temp_init_veg,init_offset=real(hlm_current_tod,r8) ) allocate(new_patch%tveg_lpa) call new_patch%tveg_lpa%InitRmean(ema_lpa,init_value=temp_init_veg) - - allocate(new_patch%seedling_layer_par24) - call new_patch%seedling_layer_par24%InitRMean(fixed_24hr,init_value=init_seedling_par,init_offset=real(hlm_current_tod,r8) ) - - allocate(new_patch%sdlng_emerg_smp) - call new_patch%sdlng_emerg_smp%InitRMean(ema_sdlng_emerg_h2o, & - init_value=init_seedling_smp,init_offset=real(hlm_current_tod,r8) ) - + call new_patch%seedling_layer_par24%InitRMean(fixed_24hr,init_value=init_seedling_par, init_offset=real(hlm_current_tod,r8)) allocate(new_patch%sdlng_mort_par) - call new_patch%sdlng_mort_par%InitRMean(ema_sdlng_mort_par, & - init_value=init_seedling_par,init_offset=real(hlm_current_tod,r8) ) - - !allocate(new_patch%sdlng_mdd) - !call new_patch%sdlng_mdd%InitRMean(ema_sdlng_mdd, & - ! init_value=0.0_r8,init_offset=real(hlm_current_tod,r8) ) - + call new_patch%sdlng_mort_par%InitRMean(ema_sdlng_mort_par,init_value=temp_init_veg) allocate(new_patch%sdlng2sap_par) - call new_patch%sdlng2sap_par%InitRMean(ema_sdlng2sap_par, & - init_value=init_seedling_par,init_offset=real(hlm_current_tod,r8) ) - + call new_patch%sdlng2sap_par%InitRMean(ema_sdlng2sap_par,init_value=init_seedling_par) + + allocate(new_patch%sdlng_mdd(maxpft)) + allocate(new_patch%sdlng_emerg_smp(maxpft)) + + do pft = 1,maxpft + allocate(new_patch%sdlng_mdd(pft)%p) + call new_patch%sdlng_mdd(pft)%p%InitRMean(ema_sdlng_mdd, init_value=0.0_r8) + allocate(new_patch%sdlng_emerg_smp(pft)%p) + call new_patch%sdlng_emerg_smp(pft)%p%InitRMean(ema_sdlng_emerg_h2o,init_value=init_seedling_smp) + enddo + ! Litter ! Allocate, Zero Fluxes, and Initialize to "unset" values @@ -2528,7 +2531,7 @@ subroutine fuse_2_patches(csite, dp, rp) type (ed_cohort_type), pointer :: nextc ! Remembers next cohort in list type (ed_cohort_type), pointer :: storesmallcohort type (ed_cohort_type), pointer :: storebigcohort - integer :: c,p !counters for pft and litter size class. + integer :: c,p,pft !counters for pft and litter size class. ahb added pft here. integer :: tnull,snull ! are the tallest and shortest cohorts associated? integer :: el ! loop counting index for elements type(ed_patch_type), pointer :: youngerp ! pointer to the patch younger than donor @@ -2559,7 +2562,12 @@ subroutine fuse_2_patches(csite, dp, rp) call rp%tveg24%FuseRMean(dp%tveg24,rp%area*inv_sum_area) call rp%tveg_lpa%FuseRMean(dp%tveg_lpa,rp%area*inv_sum_area) call rp%seedling_layer_par24%FuseRMean(dp%seedling_layer_par24,rp%area*inv_sum_area) !ahb - call rp%sdlng_emerg_smp%FuseRMean(dp%sdlng_emerg_smp,rp%area*inv_sum_area) !ahb + + do pft = 1,maxpft + call rp%sdlng_emerg_smp(pft)%p%FuseRMean(dp%sdlng_emerg_smp(pft)%p,rp%area*inv_sum_area) !ahb + call rp%sdlng_mdd(pft)%p%FuseRMean(dp%sdlng_mdd(pft)%p,rp%area*inv_sum_area) !ahb + enddo + call rp%sdlng_mort_par%FuseRMean(dp%sdlng_mort_par,rp%area*inv_sum_area) !ahb call rp%sdlng2sap_par%FuseRMean(dp%sdlng2sap_par,rp%area*inv_sum_area) !ahb @@ -2866,7 +2874,7 @@ subroutine dealloc_patch(cpatch) type(ed_cohort_type), pointer :: ccohort ! current type(ed_cohort_type), pointer :: ncohort ! next - integer :: el ! loop counter for elements + integer :: el,pft ! loop counter for elements and pfts ! First Deallocate the cohort space ! ----------------------------------------------------------------------------------- @@ -2905,11 +2913,16 @@ subroutine dealloc_patch(cpatch) deallocate(cpatch%tveg24) deallocate(cpatch%tveg_lpa) deallocate(cpatch%seedling_layer_par24) - deallocate(cpatch%sdlng_emerg_smp) deallocate(cpatch%sdlng_mort_par) - deallocate(cpatch%sdlng_mdd) deallocate(cpatch%sdlng2sap_par) + do pft = 1, maxpft + deallocate(cpatch%sdlng_mdd(pft)%p) + deallocate(cpatch%sdlng_emerg_smp(pft)%p) + enddo + + deallocate(cpatch%sdlng_mdd) + deallocate(cpatch%sdlng_emerg_smp) return end subroutine dealloc_patch diff --git a/biogeochem/EDPhysiologyMod.F90 b/biogeochem/EDPhysiologyMod.F90 index 11184a9878..50b4da3413 100644 --- a/biogeochem/EDPhysiologyMod.F90 +++ b/biogeochem/EDPhysiologyMod.F90 @@ -1618,6 +1618,10 @@ subroutine SeedGermination( litt, cold_stat, drought_stat, bc_in, currentPatch ) real(r8) :: wetness_index ! a soil 'wetness index' calculated from soil matric potential real(r8) :: seedling_layer_par ! photosynthetically active radiation at the seedling layer + real(r8) :: slsmp_emerg + real(r8) :: slparmort + real(r8) :: slpartrans + real(r8) :: photoblastic_germ_modifier ! seedling emergence rate modifier for light-sensitive germination ! used in the moisture-sensitive emergence function real(r8) :: seedling_emerg_rate ! the fraction of the seed bank emerging in the current time step @@ -1650,16 +1654,20 @@ subroutine SeedGermination( litt, cold_stat, drought_stat, bc_in, currentPatch ) !Step 1. calculate the photoblastic germination rate modifier seedling_layer_par = currentPatch%seedling_layer_par24%GetMean() - + !slsmp_emerg = currentPatch%sdlng_emerg_smp%GetMean() + !slparmort = currentPatch%sdlng_mort_par%GetMean() + !slpartrans = currentPatch%sdlng2sap_par%GetMean() + ! write(fates_log(),*) 'nrm parprof', currentPatch%nrmlzd_parprof_dir_z(:,:,:) ! write(fates_log(),*) 'parprof', currentPatch%parprof_dif_z(1,:) ! write(fates_log(),*) 'number_leaf_layers_in_second_canopy_layer', maxval(currentPatch%ncan(currentPatch%ncl_p,:)) - write(fates_log(),*) 'patchno', currentPatch%patchno - write(fates_log(),*) 'seedling_layer_par', seedling_layer_par - write(fates_log(),*) 'seedling_emerg_smp', currentPatch%sdlng_emerg_smp%GetMean() - write(fates_log(),*) 'seedling_mort_par', currentPatch%sdlng_mort_par%GetMean() - write(fates_log(),*) 'seedling2sap_trans_par', currentPatch%sdlng2sap_par%GetMean() + ! write(fates_log(),*) 'patchno', currentPatch%patchno + ! write(fates_log(),*) 'seedling_layer_par', seedling_layer_par + ! write(fates_log(),*) 'seedling_emerg_smp', slsmp_emerg + ! write(fates_log(),*) 'seedling_mort_par', slparmort + ! write(fates_log(),*) 'seedling2sap_trans_par', slpartrans + ! write(fates_log(),*) 'tveg_lpa', currentPatch%tveg_lpa%GetMean() seedling_layer_par = seedling_layer_par * 4.6_r8 !covert to umol s-1 of PAR !1 W/m2 ≈ 4.6 μmole.m2/s diff --git a/main/EDTypesMod.F90 b/main/EDTypesMod.F90 index 18549d27bb..3e426d30fb 100644 --- a/main/EDTypesMod.F90 +++ b/main/EDTypesMod.F90 @@ -18,7 +18,7 @@ module EDTypesMod use FatesLitterMod, only : ncwd use FatesConstantsMod, only : n_anthro_disturbance_categories use FatesConstantsMod, only : days_per_year - use FatesRunningMeanMod, only : rmean_type + use FatesRunningMeanMod, only : rmean_type,rmean_arr_type use FatesInterfaceTypesMod,only : bc_in_type use FatesInterfaceTypesMod,only : bc_out_type @@ -429,13 +429,14 @@ module EDTypesMod class(rmean_type), pointer :: seedling_layer_par24 ! 24-hour mean of photosynthetically active radiation ! at the seedling layer (w-m2) - class(rmean_type), pointer :: sdlng_emerg_smp ! Running mean of soil matric potential at the seedling + class(rmean_arr_type), pointer :: sdlng_emerg_smp(:) + ! Running mean of soil matric potential at the seedling ! rooting depth at the h2o seedling emergence ! timescale (see sdlng_emerg_h2o_timescale parameter) class(rmean_type), pointer :: sdlng_mort_par ! Running mean of photosythetically active radiation ! at the seedling layer and at the par-based seedling ! mortality timescale (sdlng_mort_par_timescale) - class(rmean_type), pointer :: sdlng_mdd ! Running mean of moisture deficit days + class(rmean_arr_type), pointer :: sdlng_mdd(:) ! Running mean of moisture deficit days ! at the seedling layer and at the mdd-based seedling ! mortality timescale (sdlng_mdd_timescale) ! (sdlng2sap_par_timescale) diff --git a/main/FatesInterfaceMod.F90 b/main/FatesInterfaceMod.F90 index c2a6e1375f..09dea6fa87 100644 --- a/main/FatesInterfaceMod.F90 +++ b/main/FatesInterfaceMod.F90 @@ -45,6 +45,7 @@ module FatesInterfaceMod use EDParamsMod , only : sdlng_emerg_h2o_timescale use EDParamsMod , only : sdlng_mort_par_timescale use EDParamsMod , only : sdlng2sap_par_timescale + use EDParamsMod , only : sdlng_mdd_timescale use EDParamsMod , only : ED_val_history_sizeclass_bin_edges use EDParamsMod , only : ED_val_history_ageclass_bin_edges use EDParamsMod , only : ED_val_history_height_bin_edges @@ -883,12 +884,12 @@ subroutine SetFatesGlobalElements(use_fates) allocate(ema_sdlng_mort_par) call ema_sdlng_mort_par%define(sdlng_mort_par_timescale*sec_per_day, & hlm_stepsize,moving_ema_window) - !allocate(ema_sdlng_mdd) - !call ema_sdlng_mdd%define(sdlng_mdd_timescale*sec_per_day, & - ! hlm_stepsize,moving_ema_window) allocate(ema_sdlng2sap_par) call ema_sdlng2sap_par%define(sdlng2sap_par_timescale*sec_per_day, & hlm_stepsize,moving_ema_window) + allocate(ema_sdlng_mdd) + call ema_sdlng_mdd%define(sdlng_mdd_timescale*sec_per_day, & + hlm_stepsize,moving_ema_window) @@ -1864,19 +1865,20 @@ subroutine UpdateFatesRMeansTStep(sites,bc_in) type(ed_patch_type), pointer :: cpatch type(ed_cohort_type), pointer :: ccohort - integer :: s, ifp, io_si - real(r8) :: new_seedling_layer_par !seedling layer par in the current timestep - real(r8) :: new_seedling_layer_smp !seedling layer smp in the current timestep - !real(r8) :: new_seedling_mdd !seedling layer moisture deficit days in the current timestep + integer :: s, ifp, io_si, pft + real(r8) :: new_seedling_layer_par !seedling layer par in the current timestep + real(r8) :: new_seedling_layer_smp(maxpft) !seedling layer smp in the current timestep + real(r8) :: new_seedling_mdd(maxpft) !seedling layer moisture deficit days in the current timestep - !real(r8), parameter :: seedling_smp_crit = -175912.9_r8 !seedling soil moisture stress - !threshold at which point - !the seedling layer starts accumulating moisture - !deficit days; move to pft-specific param if works - integer :: ilayer_seedling_root !the soil layer at seedling rooting depth + real(r8), parameter :: seedling_smp_crit = -175912.9_r8 !seedling soil moisture stress + !threshold at which point + !the seedling layer starts accumulating moisture + !deficit days; move to pft-specific param if works + integer :: ilayer_seedling_root(maxpft) !the soil layer at seedling rooting depth integer :: n_leaf !number of leaf layers per canopy layer in patch real(r8) :: lai_sun_frac real(r8) :: lai_shade_frac + integer,parameter :: ipar = 1 !solar radiation in the shortwave band (i.e. par) do s = 1,size(sites,dim=1) @@ -1899,7 +1901,7 @@ subroutine UpdateFatesRMeansTStep(sites,bc_in) lai_sun_frac = sum(cpatch%ed_laisun_z(cpatch%ncl_p,:,n_leaf)) & / ( sum(cpatch%ed_laisun_z(cpatch%ncl_p,:,n_leaf)) + & !summed across pfts sum(cpatch%ed_laisha_z(cpatch%ncl_p,:,n_leaf)) ) !summed across pfts - + lai_shade_frac = 1.0_r8 - lai_sun_frac !calculating seedling layer par for the current time step @@ -1908,25 +1910,62 @@ subroutine UpdateFatesRMeansTStep(sites,bc_in) new_seedling_layer_par = & (cpatch%parprof_dir_z(cpatch%ncl_p,n_leaf) * lai_sun_frac) + & (cpatch%parprof_dif_z(cpatch%ncl_p,n_leaf) * (1.0_r8 - lai_sun_frac)) + + ! if there is no lai in the patch (i.e. no vegetation) then the lai_sun_frac + ! and lai_shade frac vars become nan, causing seedling layer par to be nan. + ! which messes up the running means. This say's that if there is no lai, the + ! par at the seedling layer is taken from the ctsm boundary conditions + if (new_seedling_layer_par /= new_seedling_layer_par) then + new_seedling_layer_par = bc_in(s)%solad_parb(ifp,ipar) + bc_in(s)%solai_parb(ifp,ipar) + end if + ! update the par running means call cpatch%seedling_layer_par24%UpdateRMean(new_seedling_layer_par) call cpatch%sdlng_mort_par%UpdateRMean(new_seedling_layer_par) call cpatch%sdlng2sap_par%UpdateRMean(new_seedling_layer_par) - !calculating seedling layer soil matric potential for the current time step - !note: need to make this a pft-specific running mean... - ilayer_seedling_root = minloc(abs(bc_in(s)%z_sisl(:)-EDPftvarcon_inst%seedling_root_depth(1)),dim=1) - new_seedling_layer_smp = bc_in(s)%smp_sl(ilayer_seedling_root) + !write(fates_log(),*) 'patchno', cpatch%patchno + !write(fates_log(),*) 'patcharea', cpatch%area + !write(fates_log(),*) 'laiSun',sum(cpatch%ed_laisun_z(cpatch%ncl_p,:,n_leaf)) + !write(fates_log(),*) 'laiShade',sum(cpatch%ed_laisha_z(cpatch%ncl_p,:,n_leaf)) + !write(fates_log(),*) 'patchlaiSunFrac', lai_sun_frac + !write(fates_log(),*) 'patchlaiShadeFrac', lai_shade_frac + !write(fates_log(),*) 'parprof_dir', cpatch%parprof_dir_z(cpatch%ncl_p,n_leaf) + !write(fates_log(),*) 'parprof_dif', cpatch%parprof_dif_z(cpatch%ncl_p,n_leaf) + !write(fates_log(),*) 'bc_in par d', bc_in(s)%solad_parb(ifp,ipar) + !write(fates_log(),*) 'bc_in par i', bc_in(s)%solad_parb(ifp,ipar) + !write(fates_log(),*) 'new_seedling_layer_par', new_seedling_layer_par + !write(fates_log(),*) 'par24', cpatch%seedling_layer_par24%GetMean() + !write(fates_log(),*) 'parMort', cpatch%sdlng_mort_par%GetMean() + + + do pft = 1,numpft + !calculate the soil moisture at the seedling rooting depth for each pft + + ilayer_seedling_root(pft) = minloc(abs(bc_in(s)%z_sisl(:)-EDPftvarcon_inst%seedling_root_depth(pft)),dim=1) + new_seedling_layer_smp(pft) = bc_in(s)%smp_sl(ilayer_seedling_root(pft)) + + !calculate the new moisture deficit day (mdd) value for each pft + new_seedling_mdd(pft) = (abs(seedling_smp_crit) - abs(new_seedling_layer_smp(pft))) * (-1.0_r8) - !updating the soil matric potential moving averages - call cpatch%sdlng_emerg_smp%UpdateRMean(new_seedling_layer_smp) - - !calculating moisture deficit days in the seedling layer - !new_seedling_mdd = 0.0_r8 + ! if mdds are negative then it means that soil is wetter than smp_crit and the moisture + ! deficit is 0 + if (new_seedling_mdd(pft) < 0.0_r8) then + new_seedling_mdd(pft) = 0.0_r8 + endif + + !update the smp and mdd running means + call cpatch%sdlng_emerg_smp(pft)%p%UpdateRMean(new_seedling_layer_smp(pft)) + call cpatch%sdlng_mdd(pft)%p%UpdateRMean(new_seedling_mdd(pft)) - ! new_seedling_mdd = (abs(seedling_smp_crit) - abs(new_seedling_layer_smp)) * -1.0_r8 - - + + !write(fates_log(),*) 'new_seedling_layer_smp', new_seedling_layer_smp(pft) + !write(fates_log(),*) 'smpEmerg', cpatch%sdlng_emerg_smp(pft)%p%GetMean() + !write(fates_log(),*) 'new_sdling_mdd', new_seedling_mdd(pft) + !write(fates_log(),*) 'sdling_mdd', cpatch%sdlng_mdd(pft)%p%GetMean() + + enddo + !END ahb's changes !--------------------------------------------------------------------------------------- diff --git a/main/FatesRestartInterfaceMod.F90 b/main/FatesRestartInterfaceMod.F90 index 8da2a096cc..b3875e8cc1 100644 --- a/main/FatesRestartInterfaceMod.F90 +++ b/main/FatesRestartInterfaceMod.F90 @@ -146,6 +146,7 @@ module FatesRestartInterfaceMod integer :: ir_sdlng_emerg_smp_pa !ahb integer :: ir_sdlng_mort_par_pa ! ahb integer :: ir_sdlng2sap_par_pa ! ahb + integer :: ir_sdlng_mdd_pa ! ahb @@ -1244,6 +1245,10 @@ subroutine define_restart_vars(this, initialize_variables) long_name='seedling layer PAR on the seedling to sapling transition timescale', & units='W m2-1', initialize=initialize_variables,ivar=ivar, index = ir_sdlng2sap_par_pa) + call this%DefineRMeanRestartVar(vname='fates_sdlng_mdd',vtype=cohort_r8, & + long_name='seedling moisture deficit days', & + units='mm days', initialize=initialize_variables,ivar=ivar, index = ir_sdlng_mdd_pa) + call this%DefineRMeanRestartVar(vname='fates_tveglpapatch',vtype=cohort_r8, & long_name='running average (EMA) of patch veg temp for photo acclim', & units='K', initialize=initialize_variables,ivar=ivar, index = ir_tveglpa_pa) @@ -1661,6 +1666,7 @@ subroutine set_restart_vectors(this,nc,nsites,sites) use EDTypesMod, only : maxSWb use EDTypesMod, only : numWaterMem use EDTypesMod, only : num_vegtemp_mem + use EDTypesMod, only : maxpft ! Arguments class(fates_restart_interface_type) :: this @@ -2053,10 +2059,14 @@ subroutine set_restart_vectors(this,nc,nsites,sites) call this%SetRMeanRestartVar(cpatch%tveg24, ir_tveg24_pa, io_idx_co_1st) call this%SetRMeanRestartVar(cpatch%tveg_lpa, ir_tveglpa_pa, io_idx_co_1st) call this%SetRMeanRestartVar(cpatch%seedling_layer_par24, ir_seedling_layer_par24_pa, io_idx_co_1st) - call this%SetRMeanRestartVar(cpatch%sdlng_emerg_smp, ir_sdlng_emerg_smp_pa,io_idx_co_1st) call this%SetRMeanRestartVar(cpatch%sdlng_mort_par, ir_sdlng_mort_par_pa,io_idx_co_1st) call this%SetRMeanRestartVar(cpatch%sdlng2sap_par, ir_sdlng2sap_par_pa,io_idx_co_1st) - + + do i_pft = 1, maxpft + call this%SetRMeanRestartVar(cpatch%sdlng_mdd(i_pft)%p, ir_sdlng_mdd_pa,io_idx_co_1st) + call this%SetRMeanRestartVar(cpatch%sdlng_emerg_smp(i_pft)%p, ir_sdlng_emerg_smp_pa,io_idx_co_1st) + enddo + ! set cohorts per patch for IO rio_ncohort_pa( io_idx_co_1st ) = cohortsperpatch @@ -2461,6 +2471,7 @@ subroutine get_restart_vectors(this, nc, nsites, sites) use FatesInterfaceTypesMod, only : numpft use FatesInterfaceTypesMod, only : fates_maxElementsPerPatch use EDTypesMod, only : numWaterMem + use EDTypesMod, only : maxpft use EDTypesMod, only : num_vegtemp_mem use FatesSizeAgeTypeIndicesMod, only : get_age_class_index @@ -2478,7 +2489,7 @@ subroutine get_restart_vectors(this, nc, nsites, sites) type(ed_cohort_type),pointer :: ccohort ! current cohort type(litter_type), pointer :: litt ! litter object on the current patch ! loop indices - integer :: s, i, j, k + integer :: s, i, j, k, pft ! ---------------------------------------------------------------------------------- ! The following group of integers indicate the positional index (idx) @@ -2843,10 +2854,13 @@ subroutine get_restart_vectors(this, nc, nsites, sites) call this%GetRMeanRestartVar(cpatch%tveg24, ir_tveg24_pa, io_idx_co_1st) call this%GetRMeanRestartVar(cpatch%tveg_lpa, ir_tveglpa_pa, io_idx_co_1st) call this%GetRMeanRestartVar(cpatch%seedling_layer_par24, ir_seedling_layer_par24_pa, io_idx_co_1st) - call this%GetRMeanRestartVar(cpatch%sdlng_emerg_smp, ir_sdlng_emerg_smp_pa,io_idx_co_1st) call this%GetRMeanRestartVar(cpatch%sdlng_mort_par, ir_sdlng_mort_par_pa,io_idx_co_1st) call this%GetRMeanRestartVar(cpatch%sdlng2sap_par, ir_sdlng2sap_par_pa,io_idx_co_1st) - + + do pft = 1, maxpft + call this%GetRMeanRestartVar(cpatch%sdlng_mdd(pft)%p, ir_sdlng_mdd_pa,io_idx_co_1st) + call this%GetRMeanRestartVar(cpatch%sdlng_emerg_smp(pft)%p, ir_sdlng_emerg_smp_pa,io_idx_co_1st) + enddo ! set cohorts per patch for IO diff --git a/main/FatesRunningMeanMod.F90 b/main/FatesRunningMeanMod.F90 index cd54e3ca25..8a7b7a21ea 100644 --- a/main/FatesRunningMeanMod.F90 +++ b/main/FatesRunningMeanMod.F90 @@ -80,6 +80,11 @@ module FatesRunningMeanMod end type rmean_type + type, public :: rmean_arr_type + class(rmean_type), pointer :: p + end type rmean_arr_type + + logical, parameter :: debug = .true. character(len=*), parameter, private :: sourcefile = & From 827fe3062a820b6295e86c0940d4395a03fd1408 Mon Sep 17 00:00:00 2001 From: adamhb Date: Thu, 16 Dec 2021 13:10:51 -0800 Subject: [PATCH 35/81] fixed parameter mixup in reproductive allocation scheme --- biogeochem/EDPhysiologyMod.F90 | 11 ++++------- parteh/PRTAllometricCarbonMod.F90 | 20 ++++++++++++++------ 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/biogeochem/EDPhysiologyMod.F90 b/biogeochem/EDPhysiologyMod.F90 index 50b4da3413..b1404fc7a1 100644 --- a/biogeochem/EDPhysiologyMod.F90 +++ b/biogeochem/EDPhysiologyMod.F90 @@ -1371,10 +1371,7 @@ subroutine SeedIn( currentSite, bc_in ) real(r8) :: site_seed_rain(maxpft) ! This is the sum of seed-rain for the site [kg/site/day] real(r8) :: seed_in_external ! Mass of externally generated seeds [kg/m2/day] real(r8) :: seed_stoich ! Mass ratio of nutrient per C12 in seeds [kg/kg] - real(r8) :: repro_mass_prod ! Mass of reproductive material produced [kg/day] ; added by ahb 7/8/2021 - real(r8), parameter :: repro_frac_seed = 0.5 !added by ahb 7/12/2021; move this to param file real(r8) :: seed_prod ! Seed produced in this dynamics step [kg/day] - real(r8) :: non_seed_repro_prod ! Mass of non-seed reproductive material produced [kg/day] ; added by ahb 7/10/2021 integer :: n_litt_types ! number of litter element types (c,n,p, etc) integer :: el ! loop counter for litter element types integer :: element_id ! element id consistent with parteh/PRTGenericMod.F90 @@ -1452,10 +1449,10 @@ subroutine SeedIn( currentSite, bc_in ) litt%seed_in_local(pft) = litt%seed_in_local(pft) + site_seed_rain(pft)/area !New regeneration code added by ahb on 7/15/2021 - !The original code sends all reproductive tissue to seed - !This new code is designed to send some reproductive biomass - !straight to the leaf litter pool to account for non-seed reproductive - !biomass. Also see small change to SeedDecay subroutine. + !The original code sent all reproductive carbon to seed + !The code below sends a fraction of reproductive carbon to the leaf litter pool + !to account for non-seed reproductive carbon (e.g. flower, fruit, etc.) + !PICK UP HERE WITH ADDING SWITCH !-------------------------------- litt%seed_decay(pft) = litt%seed_in_local(pft) * (1.0_r8 - EDPftvarcon_inst%repro_frac_seed(pft)) !ahb !-------------------------------- diff --git a/parteh/PRTAllometricCarbonMod.F90 b/parteh/PRTAllometricCarbonMod.F90 index c988bb9a30..54a7804ade 100644 --- a/parteh/PRTAllometricCarbonMod.F90 +++ b/parteh/PRTAllometricCarbonMod.F90 @@ -909,6 +909,7 @@ function AllomCGrowthDeriv(c_pools,c_mask,cbalance,intgr_params) result(dCdx) real(r8) :: ct_ddeaddd ! target structural biomass derivative wrt diameter, (kgC/cm) real(r8) :: ct_dtotaldd ! target total (not reproductive) biomass derivative wrt diameter, (kgC/cm) real(r8) :: repro_fraction ! fraction of carbon balance directed towards reproduction (kgC/kgC) + integer :: regen_model=2 associate( dbh => c_pools(dbh_id), & cleaf => c_pools(leaf_c_id), & @@ -941,16 +942,22 @@ function AllomCGrowthDeriv(c_pools,c_mask,cbalance,intgr_params) result(dCdx) ! fraction of carbon going towards reproduction + !START ahb's changes + if ( regen_model == 1 .or. ipft > 6) then !the Tree Recruitment Scheme is not parameterized + !to work with non-tree pfts + !original code !------------------------------------------------------------------------------------- - !if (dbh <= prt_params%dbh_repro_threshold(ipft)) then ! cap on leaf biomass - ! repro_fraction = prt_params%seed_alloc(ipft) - !else - ! repro_fraction = prt_params%seed_alloc(ipft) + prt_params%seed_alloc_mature(ipft) - !end if + if (dbh <= prt_params%dbh_repro_threshold(ipft)) then ! cap on leaf biomass + repro_fraction = prt_params%seed_alloc(ipft) + else + repro_fraction = prt_params%seed_alloc(ipft) + prt_params%seed_alloc_mature(ipft) + end if !------------------------------------------------------------------------------------- + else if ( regen_model == 2 .and. ipft < 7) then !tree pfts only + !new regeneration code !------------------------------------------------------------------------------------- !This reproductive allocation function calculates the fraction of available carbon @@ -963,9 +970,10 @@ function AllomCGrowthDeriv(c_pools,c_mask,cbalance,intgr_params) result(dCdx) !------------------------------------------------------------------------------------- repro_fraction = prt_params%seed_alloc(ipft) * & (exp(prt_params%repro_alloc_b(ipft) + prt_params%repro_alloc_a(ipft)*dbh*mm_per_cm) / & - (1 + exp(prt_params%repro_alloc_b(ipft) + prt_params%repro_alloc_b(ipft)*dbh*mm_per_cm))) + (1 + exp(prt_params%repro_alloc_b(ipft) + prt_params%repro_alloc_a(ipft)*dbh*mm_per_cm))) !-------------------------------------------------------------------------------------! + end if !regen model switch !END ahb's changes dCdx = 0.0_r8 From 212bd7dd225ad9b3ecc9483f2ebeb922cd157db7 Mon Sep 17 00:00:00 2001 From: adamhb Date: Thu, 16 Dec 2021 14:22:53 -0800 Subject: [PATCH 36/81] added regeneration switch to reproductive allocation --- parteh/PRTAllometricCarbonMod.F90 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/parteh/PRTAllometricCarbonMod.F90 b/parteh/PRTAllometricCarbonMod.F90 index 54a7804ade..8fdca37449 100644 --- a/parteh/PRTAllometricCarbonMod.F90 +++ b/parteh/PRTAllometricCarbonMod.F90 @@ -944,10 +944,10 @@ function AllomCGrowthDeriv(c_pools,c_mask,cbalance,intgr_params) result(dCdx) !START ahb's changes - if ( regen_model == 1 .or. ipft > 6) then !the Tree Recruitment Scheme is not parameterized + if ( regen_model == 1 .or. ipft > 6) then !The Tree Recruitment Scheme is not parameterized !to work with non-tree pfts - !original code + !Original code !------------------------------------------------------------------------------------- if (dbh <= prt_params%dbh_repro_threshold(ipft)) then ! cap on leaf biomass repro_fraction = prt_params%seed_alloc(ipft) @@ -958,7 +958,7 @@ function AllomCGrowthDeriv(c_pools,c_mask,cbalance,intgr_params) result(dCdx) else if ( regen_model == 2 .and. ipft < 7) then !tree pfts only - !new regeneration code + !New regeneration code !------------------------------------------------------------------------------------- !This reproductive allocation function calculates the fraction of available carbon !allocated to reproductive tissue based on a cohort's size. This function is based on From 91cff2ff411a853058dc743d82acd5b6b58aa431 Mon Sep 17 00:00:00 2001 From: adamhb Date: Fri, 17 Dec 2021 13:12:47 -0800 Subject: [PATCH 37/81] fixed bugs in the regeneration running means --- main/FatesInterfaceMod.F90 | 32 ++++++++++++-------------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/main/FatesInterfaceMod.F90 b/main/FatesInterfaceMod.F90 index 978a02a178..d6747de5a0 100644 --- a/main/FatesInterfaceMod.F90 +++ b/main/FatesInterfaceMod.F90 @@ -883,26 +883,6 @@ subroutine SetFatesGlobalElements(use_fates) call fates_history_maps() - ! Instantiate the time-averaging method globals - allocate(ema_24hr) - call ema_24hr%define(sec_per_day, hlm_stepsize, moving_ema_window) - allocate(fixed_24hr) - call fixed_24hr%define(sec_per_day, hlm_stepsize, fixed_window) - allocate(ema_lpa) - call ema_lpa%define(photo_temp_acclim_timescale*sec_per_day, & - hlm_stepsize,moving_ema_window) - allocate(ema_sdlng_emerg_h2o) - call ema_sdlng_emerg_h2o%define(sdlng_emerg_h2o_timescale*sec_per_day, & - hlm_stepsize,moving_ema_window) - allocate(ema_sdlng_mort_par) - call ema_sdlng_mort_par%define(sdlng_mort_par_timescale*sec_per_day, & - hlm_stepsize,moving_ema_window) - allocate(ema_sdlng2sap_par) - call ema_sdlng2sap_par%define(sdlng2sap_par_timescale*sec_per_day, & - hlm_stepsize,moving_ema_window) - allocate(ema_sdlng_mdd) - call ema_sdlng_mdd%define(sdlng_mdd_timescale*sec_per_day, & - hlm_stepsize,moving_ema_window) @@ -938,6 +918,18 @@ subroutine InitTimeAveragingGlobals() allocate(ema_lpa) call ema_lpa%define(photo_temp_acclim_timescale*sec_per_day, & hlm_stepsize,moving_ema_window) + allocate(ema_sdlng_emerg_h2o) + call ema_sdlng_emerg_h2o%define(sdlng_emerg_h2o_timescale*sec_per_day, & + hlm_stepsize,moving_ema_window) + allocate(ema_sdlng_mort_par) + call ema_sdlng_mort_par%define(sdlng_mort_par_timescale*sec_per_day, & + hlm_stepsize,moving_ema_window) + allocate(ema_sdlng2sap_par) + call ema_sdlng2sap_par%define(sdlng2sap_par_timescale*sec_per_day, & + hlm_stepsize,moving_ema_window) + allocate(ema_sdlng_mdd) + call ema_sdlng_mdd%define(sdlng_mdd_timescale*sec_per_day, & + hlm_stepsize,moving_ema_window) return end subroutine InitTimeAveragingGlobals From 31b7719f5cc11830dbfcfb860b8c8d650e806b97 Mon Sep 17 00:00:00 2001 From: adamhb Date: Fri, 17 Dec 2021 15:47:19 -0800 Subject: [PATCH 38/81] added a parameter that allows uses to switch between the Tree Recruitment Scheme and the default fates regeneration scheme --- main/EDParamsMod.F90 | 15 +++++++++++++++ parteh/PRTAllometricCarbonMod.F90 | 22 +++++++++++++--------- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/main/EDParamsMod.F90 b/main/EDParamsMod.F90 index ea12daabe3..7bb8c14c94 100644 --- a/main/EDParamsMod.F90 +++ b/main/EDParamsMod.F90 @@ -70,6 +70,10 @@ module EDParamsMod real(r8),protected, public :: ED_val_patch_fusion_tol real(r8),protected, public :: ED_val_canopy_closure_thresh ! site-level canopy closure point where trees take on forest (narrow) versus savannah (wide) crown allometry integer,protected, public :: stomatal_model !switch for choosing between stomatal conductance models, 1 for Ball-Berry, 2 for Medlyn + integer,protected, public :: regeneration_model !switch for choosing between regeneration models, 1 for Fates basic, 2 for the Tree Recruitment Scheme + !Hanbury-Brown et al., 2022 + + logical,protected, public :: active_crown_fire ! flag, 1=active crown fire 0=no active crown fire character(len=param_string_length),parameter :: fates_name_active_crown_fire = "fates_fire_active_crown_fire" @@ -134,6 +138,7 @@ module EDParamsMod character(len=param_string_length),parameter,public :: ED_name_patch_fusion_tol= "fates_patch_fusion_tol" character(len=param_string_length),parameter,public :: ED_name_canopy_closure_thresh= "fates_canopy_closure_thresh" character(len=param_string_length),parameter,public :: ED_name_stomatal_model= "fates_leaf_stomatal_model" + character(len=param_string_length),parameter,public :: ED_name_regeneration_model= "fates_regeneration_model" character(len=param_string_length),parameter,public :: name_theta_cj_c3 = "fates_theta_cj_c3" character(len=param_string_length),parameter,public :: name_theta_cj_c4 = "fates_theta_cj_c4" @@ -255,6 +260,7 @@ subroutine FatesParamsInit() ED_val_patch_fusion_tol = nan ED_val_canopy_closure_thresh = nan stomatal_model = -9 + regeneration_model = -9 hydr_kmax_rsurf1 = nan hydr_kmax_rsurf2 = nan hydr_psi0 = nan @@ -401,6 +407,9 @@ subroutine FatesRegisterParams(fates_params) call fates_params%RegisterParameter(name=ED_name_stomatal_model, dimension_shape=dimension_shape_scalar, & dimension_names=dim_names_scalar) + call fates_params%RegisterParameter(name=ED_name_regeneration_model, dimension_shape=dimension_shape_scalar, & + dimension_names=dim_names_scalar) + call fates_params%RegisterParameter(name=hydr_name_kmax_rsurf1, dimension_shape=dimension_shape_scalar, & dimension_names=dim_names_scalar) @@ -590,6 +599,10 @@ subroutine FatesReceiveParams(fates_params) data=tmpreal) stomatal_model = nint(tmpreal) + call fates_params%RetreiveParameter(name=ED_name_regeneration_model, & + data=tmpreal) + regeneration_model = nint(tmpreal) + call fates_params%RetreiveParameter(name=hydr_name_kmax_rsurf1, & data=hydr_kmax_rsurf1) @@ -721,6 +734,8 @@ subroutine FatesReportParams(is_master) write(fates_log(),fmt0) 'ED_val_patch_fusion_tol = ',ED_val_patch_fusion_tol write(fates_log(),fmt0) 'ED_val_canopy_closure_thresh = ',ED_val_canopy_closure_thresh write(fates_log(),fmt0) 'stomatal_model = ',stomatal_model + write(fates_log(),fmt0) 'regeneration_model = ',regeneration_model + write(fates_log(),fmt0) 'hydr_kmax_rsurf1 = ',hydr_kmax_rsurf1 write(fates_log(),fmt0) 'hydr_kmax_rsurf1 = ',hydr_kmax_rsurf1 write(fates_log(),fmt0) 'hydr_kmax_rsurf2 = ',hydr_kmax_rsurf2 write(fates_log(),fmt0) 'hydr_psi0 = ',hydr_psi0 diff --git a/parteh/PRTAllometricCarbonMod.F90 b/parteh/PRTAllometricCarbonMod.F90 index 8fdca37449..c5fa8eb6ce 100644 --- a/parteh/PRTAllometricCarbonMod.F90 +++ b/parteh/PRTAllometricCarbonMod.F90 @@ -51,6 +51,7 @@ module PRTAllometricCarbonMod use FatesConstantsMod , only : years_per_day use PRTParametersMod , only : prt_params + use EDParamsMod , only : regeneration_model implicit none private @@ -909,7 +910,9 @@ function AllomCGrowthDeriv(c_pools,c_mask,cbalance,intgr_params) result(dCdx) real(r8) :: ct_ddeaddd ! target structural biomass derivative wrt diameter, (kgC/cm) real(r8) :: ct_dtotaldd ! target total (not reproductive) biomass derivative wrt diameter, (kgC/cm) real(r8) :: repro_fraction ! fraction of carbon balance directed towards reproduction (kgC/kgC) - integer :: regen_model=2 + integer, parameter :: TRS = 2 !Switch option to use the Tree Recruitment Scheme + integer, parameter :: default_regeneration = 1 !Switch option to use the FATES's default regeneration scheme + associate( dbh => c_pools(dbh_id), & cleaf => c_pools(leaf_c_id), & @@ -944,10 +947,10 @@ function AllomCGrowthDeriv(c_pools,c_mask,cbalance,intgr_params) result(dCdx) !START ahb's changes - if ( regen_model == 1 .or. ipft > 6) then !The Tree Recruitment Scheme is not parameterized - !to work with non-tree pfts + if ( regeneration_model == default_regeneration .or. ipft > 6) then !The Tree Recruitment Scheme + !is only for tree pfts - !Original code + !Default reproductive allocation !------------------------------------------------------------------------------------- if (dbh <= prt_params%dbh_repro_threshold(ipft)) then ! cap on leaf biomass repro_fraction = prt_params%seed_alloc(ipft) @@ -956,13 +959,14 @@ function AllomCGrowthDeriv(c_pools,c_mask,cbalance,intgr_params) result(dCdx) end if !------------------------------------------------------------------------------------- - else if ( regen_model == 2 .and. ipft < 7) then !tree pfts only + else if ( regeneration_model == TRS .and. ipft < 7) then - !New regeneration code + !Use Tree Recruitment Scheme's (TRS) approach to reproductive allocation !------------------------------------------------------------------------------------- !This reproductive allocation function calculates the fraction of available carbon - !allocated to reproductive tissue based on a cohort's size. This function is based on - !empirical data and analysis at BCI (Visser et al., 2016). + !allocated to reproductive tissue based on a cohort's dbh (mm). This function is based on + !empirical data and analysis at BCI (Visser et al., 2016). See Hanbury-Brown et al., 2022 + !for more details. !Visser MD, Bruijning M, Wright SJ, Muller-Landau HC, Jongejans E, Comita LS, !de Kroon H. 2016. Functional traits as predictors of vital rates across the life cycle @@ -973,7 +977,7 @@ function AllomCGrowthDeriv(c_pools,c_mask,cbalance,intgr_params) result(dCdx) (1 + exp(prt_params%repro_alloc_b(ipft) + prt_params%repro_alloc_a(ipft)*dbh*mm_per_cm))) !-------------------------------------------------------------------------------------! - end if !regen model switch + end if !regeneration model switch !END ahb's changes dCdx = 0.0_r8 From 34dc02ca982e65f8c038d2a08ed21b43be71cab9 Mon Sep 17 00:00:00 2001 From: adamhb Date: Fri, 17 Dec 2021 16:52:21 -0800 Subject: [PATCH 39/81] added switch to allocation to non-seed reproductive carbon --- biogeochem/EDPhysiologyMod.F90 | 29 ++++++++++++++++++++--------- parteh/PRTAllometricCarbonMod.F90 | 10 ++++------ 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/biogeochem/EDPhysiologyMod.F90 b/biogeochem/EDPhysiologyMod.F90 index e340e63790..86d8bd97f7 100644 --- a/biogeochem/EDPhysiologyMod.F90 +++ b/biogeochem/EDPhysiologyMod.F90 @@ -74,6 +74,7 @@ module EDPhysiologyMod use EDParamsMod , only : q10_mr use EDParamsMod , only : q10_froz use EDParamsMod , only : logging_export_frac + use EDParamsMod , only : regeneration_model use FatesPlantHydraulicsMod , only : AccumulateMortalityWaterStorage use FatesConstantsMod , only : itrue,ifalse use FatesConstantsMod , only : calloc_abs_error @@ -274,7 +275,6 @@ end subroutine PreDisturbanceLitterFluxes subroutine PreDisturbanceIntegrateLitter(currentPatch) ! ----------------------------------------------------------------------------------- - ! ! This step applies the litter fluxes to the prognostic state variables. ! This procedure is called in response to fluxes generated from: ! 1) seed rain, @@ -1609,6 +1609,8 @@ subroutine SeedIn( currentSite, bc_in ) integer :: n_litt_types ! number of litter element types (c,n,p, etc) integer :: el ! loop counter for litter element types integer :: element_id ! element id consistent with parteh/PRTGenericMod.F90 + integer, parameter :: TRS = 2 ! Switch option to use the Tree Recruitment Scheme + integer, parameter :: default_regeneration = 1 !Switch option to use FATES's default regeneration scheme !------------------------------------------------------------------------------------ do el = 1, num_elements @@ -1682,14 +1684,23 @@ subroutine SeedIn( currentSite, bc_in ) ! Seed input from local sources (within site) litt%seed_in_local(pft) = litt%seed_in_local(pft) + site_seed_rain(pft)/area - !New regeneration code added by ahb on 7/15/2021 - !The original code sent all reproductive carbon to seed - !The code below sends a fraction of reproductive carbon to the leaf litter pool - !to account for non-seed reproductive carbon (e.g. flower, fruit, etc.) - !PICK UP HERE WITH ADDING SWITCH - !-------------------------------- - litt%seed_decay(pft) = litt%seed_in_local(pft) * (1.0_r8 - EDPftvarcon_inst%repro_frac_seed(pft)) !ahb - !-------------------------------- + + !START ahb's changes + + if ( regeneration_model == TRS .and. pft < 7) then + + !Send a fraction of reproductive carbon to litter to account for + !non-seed reproductive carbon (e.g. flowers, fruit, etc.) + !If using default_regeneration then all reproductive carbon becomes seed + !This process will be more important if/when FATES fixes the structural issue + !that all carbon used to make recruits comes from reproductive carbon. + + litt%seed_decay(pft) = litt%seed_in_local(pft) * (1.0_r8 - EDPftvarcon_inst%repro_frac_seed(pft)) + + end if + + !Default regeneration scheme sends all reproductive carbon to seed + !END ahb's changes ! If there is forced external seed rain, we calculate the input mass flux ! from the different elements, usung the seed optimal stoichiometry diff --git a/parteh/PRTAllometricCarbonMod.F90 b/parteh/PRTAllometricCarbonMod.F90 index c5fa8eb6ce..e46a0a543a 100644 --- a/parteh/PRTAllometricCarbonMod.F90 +++ b/parteh/PRTAllometricCarbonMod.F90 @@ -942,27 +942,25 @@ function AllomCGrowthDeriv(c_pools,c_mask,cbalance,intgr_params) result(dCdx) call bdead_allom(ct_agw,ct_bgw, ct_sap, ipft, ct_dead, & ct_dagwdd, ct_dbgwdd, ct_dsapdd, ct_ddeaddd) call bstore_allom(dbh,ipft,canopy_trim,ct_store,ct_dstoredd) - + + ! fraction of carbon going towards reproduction - !START ahb's changes if ( regeneration_model == default_regeneration .or. ipft > 6) then !The Tree Recruitment Scheme !is only for tree pfts !Default reproductive allocation - !------------------------------------------------------------------------------------- if (dbh <= prt_params%dbh_repro_threshold(ipft)) then ! cap on leaf biomass repro_fraction = prt_params%seed_alloc(ipft) else repro_fraction = prt_params%seed_alloc(ipft) + prt_params%seed_alloc_mature(ipft) end if - !------------------------------------------------------------------------------------- else if ( regeneration_model == TRS .and. ipft < 7) then - !Use Tree Recruitment Scheme's (TRS) approach to reproductive allocation !------------------------------------------------------------------------------------- + !Use Tree Recruitment Scheme's (TRS) approach to reproductive allocation. !This reproductive allocation function calculates the fraction of available carbon !allocated to reproductive tissue based on a cohort's dbh (mm). This function is based on !empirical data and analysis at BCI (Visser et al., 2016). See Hanbury-Brown et al., 2022 @@ -972,10 +970,10 @@ function AllomCGrowthDeriv(c_pools,c_mask,cbalance,intgr_params) result(dCdx) !de Kroon H. 2016. Functional traits as predictors of vital rates across the life cycle !of tropical trees. Functional Ecology 30: 168–180. !------------------------------------------------------------------------------------- + repro_fraction = prt_params%seed_alloc(ipft) * & (exp(prt_params%repro_alloc_b(ipft) + prt_params%repro_alloc_a(ipft)*dbh*mm_per_cm) / & (1 + exp(prt_params%repro_alloc_b(ipft) + prt_params%repro_alloc_a(ipft)*dbh*mm_per_cm))) - !-------------------------------------------------------------------------------------! end if !regeneration model switch !END ahb's changes From 05e25472aa4a497004d5cc0a32c191244921850a Mon Sep 17 00:00:00 2001 From: adamhb Date: Mon, 20 Dec 2021 14:09:18 -0800 Subject: [PATCH 40/81] updated the TRS switch --- biogeochem/EDPhysiologyMod.F90 | 40 +++++++++++++++++++++---------- main/FatesConstantsMod.F90 | 8 +++++++ parteh/PRTAllometricCarbonMod.F90 | 16 +++++++------ 3 files changed, 44 insertions(+), 20 deletions(-) diff --git a/biogeochem/EDPhysiologyMod.F90 b/biogeochem/EDPhysiologyMod.F90 index 86d8bd97f7..4da7ec85fc 100644 --- a/biogeochem/EDPhysiologyMod.F90 +++ b/biogeochem/EDPhysiologyMod.F90 @@ -22,6 +22,9 @@ module EDPhysiologyMod use FatesConstantsMod, only : r8 => fates_r8 use FatesConstantsMod, only : nearzero use FatesConstantsMod, only : sec_per_day + use FatesConstantsMod, only : TRS + use FatesConstantsMod, only : default_regeneration + use FatesConstantsMod, only : min_max_dbh_for_trees use FatesConstantsMod, only : megajoules_per_joule use FatesConstantsMod, only : mpa_per_mm_suction use EDPftvarcon , only : EDPftvarcon_inst @@ -1687,7 +1690,8 @@ subroutine SeedIn( currentSite, bc_in ) !START ahb's changes - if ( regeneration_model == TRS .and. pft < 7) then + if ( regeneration_model == TRS .and. & + prt_params%allom_dbh_maxheight(pft) > min_max_dbh_for_trees) then !Send a fraction of reproductive carbon to litter to account for !non-seed reproductive carbon (e.g. flowers, fruit, etc.) @@ -1699,7 +1703,7 @@ subroutine SeedIn( currentSite, bc_in ) end if - !Default regeneration scheme sends all reproductive carbon to seed + !Default regeneration scheme sends all reproductive carbon to seed (i.e. do nothing here) !END ahb's changes ! If there is forced external seed rain, we calculate the input mass flux @@ -1742,7 +1746,7 @@ subroutine SeedDecay( litt , currentPatch, bc_in ) ! ! !DESCRIPTION: ! 1. Flux from seed pool into leaf litter pool - ! 2. Flux from seedling pool into leaf litter pool + ! 2. (if TRS is on) Seedling mortality (i.e. flux from seedling pool into leaf litter pool) ! ! !ARGUMENTS type(litter_type) :: litt @@ -1767,20 +1771,30 @@ subroutine SeedDecay( litt , currentPatch, bc_in ) ! Assume that decay rates are same for all chemical species ! START ahb's changes + !===================================================================================== do pft = 1,numpft - litt%seed_decay(pft) = litt%seed(pft) * & - EDPftvarcon_inst%seed_decay_rate(pft)*years_per_day + & ! "+ &" added by ahb (7/10/2021) - litt%seed_decay(pft) ! line added by ahb so that the flux from non-seed reproductive - ! biomass (from SeedIn subroutine) is not lost (7/10/2021) - - ! 2. Flux from seedling pool into leaf litter pool - - ! ORIGINAL CODE - !---------------------------------------------------------------------- + + !If the TRS is switched off or the pft is not a tree then use the default + !regeneration scheme. + if ( regeneration_model == default_regeneration .or. & + prt_params%allom_dbh_maxheight(ipft) < min_max_dbh_for_trees ) + + !Default seed decay scheme (original code) litt%seed_germ_decay(pft) = litt%seed_germ(pft) * & EDPftvarcon_inst%seed_decay_rate(pft)*years_per_day - !---------------------------------------------------------------------- + !If the TRS is switched on and the pft is a tree then use the TRS + else if ( regeneration_model == TRS .and. & + prt_params%allom_dbh_maxheight(ipft) > min_max_dbh_for_trees ) then + + !---------------------------------------------------------------------- + !With respect to seed decay, the only difference with the TRS here is adding the flux + !from non-seed reproductive biomass (which was sent to litt%seed_decay in the SeedIn subroutine) + + litt%seed_decay(pft) = litt%seed_decay(pft) + &!from non-seed reproductive biomass; working? + litt%seed(pft) * EDPftvarcon_inst%seed_decay_rate(pft)*years_per_day + + ! 2. Flux from seedling pool into leaf litter pool !---------------------------------------------------------------------- !NEW CODE FOR ENVIRONMENTALLY SENSITIVE SEEDLING MORTALITY !Step 1. Calculate the daily seedling mortality rate from light stress diff --git a/main/FatesConstantsMod.F90 b/main/FatesConstantsMod.F90 index 8f2b296feb..08b7a463de 100644 --- a/main/FatesConstantsMod.F90 +++ b/main/FatesConstantsMod.F90 @@ -46,6 +46,14 @@ module FatesConstantsMod integer, public, parameter :: prescribed_n_uptake = 1 integer, public, parameter :: coupled_n_uptake = 2 + !Flags specifying how tree regeneration works + integer, public, parameter :: TRS = 2 !Constant defining the Tree Recruitment Scheme switch + integer, public, parameter :: default_regeneration = 1 !Constant defining FATES's default regeneration scheme switch + real(fates_r8), public, parameter :: min_max_dbh_for_trees = 15._fates_r8 !cm; if pfts have a max dbh less + !than this value FATES + !will use the default regeneration scheme. This is to avoid + !the TRS being used for shrubs and grasses. + integer, public, parameter :: cohort_np_comp_scaling = 1 ! This flag definition indicates that EVERY cohort on ! the column should compete independently in the soil diff --git a/parteh/PRTAllometricCarbonMod.F90 b/parteh/PRTAllometricCarbonMod.F90 index e46a0a543a..904342520e 100644 --- a/parteh/PRTAllometricCarbonMod.F90 +++ b/parteh/PRTAllometricCarbonMod.F90 @@ -42,7 +42,10 @@ module PRTAllometricCarbonMod use FatesConstantsMod , only : r8 => fates_r8 use FatesConstantsMod , only : i4 => fates_int use FatesConstantsMod , only : sec_per_day - use FatesConstantsMod , only : mm_per_cm !ahb added this 7/7/2021 + use FatesConstantsMod , only : mm_per_cm !ahb + use FatesConstantsMod , only : TRS !ahb + use FatesConstantsMod , only : default_regeneration !ahb + use FatesConstantsMod , only : min_max_dbh_for_trees !ahb use FatesIntegratorsMod , only : RKF45 use FatesIntegratorsMod , only : Euler use FatesConstantsMod , only : calloc_abs_error @@ -910,9 +913,6 @@ function AllomCGrowthDeriv(c_pools,c_mask,cbalance,intgr_params) result(dCdx) real(r8) :: ct_ddeaddd ! target structural biomass derivative wrt diameter, (kgC/cm) real(r8) :: ct_dtotaldd ! target total (not reproductive) biomass derivative wrt diameter, (kgC/cm) real(r8) :: repro_fraction ! fraction of carbon balance directed towards reproduction (kgC/kgC) - integer, parameter :: TRS = 2 !Switch option to use the Tree Recruitment Scheme - integer, parameter :: default_regeneration = 1 !Switch option to use the FATES's default regeneration scheme - associate( dbh => c_pools(dbh_id), & cleaf => c_pools(leaf_c_id), & @@ -947,8 +947,9 @@ function AllomCGrowthDeriv(c_pools,c_mask,cbalance,intgr_params) result(dCdx) ! fraction of carbon going towards reproduction !START ahb's changes - if ( regeneration_model == default_regeneration .or. ipft > 6) then !The Tree Recruitment Scheme - !is only for tree pfts + if ( regeneration_model == default_regeneration .or. & + prt_params%allom_dbh_maxheight(ipft) < min_max_dbh_for_trees ) then !The Tree Recruitment Scheme + !is only for tree pfts !Default reproductive allocation if (dbh <= prt_params%dbh_repro_threshold(ipft)) then ! cap on leaf biomass @@ -957,7 +958,8 @@ function AllomCGrowthDeriv(c_pools,c_mask,cbalance,intgr_params) result(dCdx) repro_fraction = prt_params%seed_alloc(ipft) + prt_params%seed_alloc_mature(ipft) end if - else if ( regeneration_model == TRS .and. ipft < 7) then + else if ( regeneration_model == TRS .and. & + prt_params%allom_dbh_maxheight(ipft) > min_max_dbh_for_trees ) then !------------------------------------------------------------------------------------- !Use Tree Recruitment Scheme's (TRS) approach to reproductive allocation. From 4b13b5b3de79bae9a70b68d61f479190b3f1934a Mon Sep 17 00:00:00 2001 From: adamhb Date: Mon, 20 Dec 2021 16:54:18 -0800 Subject: [PATCH 41/81] updated light and moisture-based seedling germination rates in SeedGermination subroutine --- biogeochem/EDPhysiologyMod.F90 | 197 ++++++++++++++++++--------------- 1 file changed, 105 insertions(+), 92 deletions(-) diff --git a/biogeochem/EDPhysiologyMod.F90 b/biogeochem/EDPhysiologyMod.F90 index 4da7ec85fc..1942aed90b 100644 --- a/biogeochem/EDPhysiologyMod.F90 +++ b/biogeochem/EDPhysiologyMod.F90 @@ -1762,7 +1762,7 @@ subroutine SeedDecay( litt , currentPatch, bc_in ) !---------------------------------------------------------------------- - ! 1. Flux from seed pool into leaf litter pool + ! 1. Seed mortality (i.e. flux from seed bank to litter) ! default value from Liscke and Loffler 2006 ; making this a PFT-specific parameter ! decays the seed pool according to exponential model @@ -1774,65 +1774,67 @@ subroutine SeedDecay( litt , currentPatch, bc_in ) !===================================================================================== do pft = 1,numpft - !If the TRS is switched off or the pft is not a tree then use the default - !regeneration scheme. - if ( regeneration_model == default_regeneration .or. & - prt_params%allom_dbh_maxheight(ipft) < min_max_dbh_for_trees ) + !If the TRS is switched off or the pft is not a tree then use the default + !regeneration scheme. + if ( regeneration_model == default_regeneration .or. & + prt_params%allom_dbh_maxheight(pft) < min_max_dbh_for_trees ) then - !Default seed decay scheme (original code) - litt%seed_germ_decay(pft) = litt%seed_germ(pft) * & + !Default seed decay scheme (original code) + litt%seed_decay(pft) = litt%seed(pft) * & EDPftvarcon_inst%seed_decay_rate(pft)*years_per_day - !If the TRS is switched on and the pft is a tree then use the TRS - else if ( regeneration_model == TRS .and. & - prt_params%allom_dbh_maxheight(ipft) > min_max_dbh_for_trees ) then + !If the TRS is switched on and the pft is a tree then use the TRS + else if ( regeneration_model == TRS .and. & + prt_params%allom_dbh_maxheight(pft) > min_max_dbh_for_trees ) then - !---------------------------------------------------------------------- - !With respect to seed decay, the only difference with the TRS here is adding the flux - !from non-seed reproductive biomass (which was sent to litt%seed_decay in the SeedIn subroutine) + !---------------------------------------------------------------------- + !With respect to seed decay, the only difference with the TRS here is adding the flux + !from non-seed reproductive biomass (which was sent to litt%seed_decay in the SeedIn subroutine) litt%seed_decay(pft) = litt%seed_decay(pft) + &!from non-seed reproductive biomass; working? litt%seed(pft) * EDPftvarcon_inst%seed_decay_rate(pft)*years_per_day - - ! 2. Flux from seedling pool into leaf litter pool - !---------------------------------------------------------------------- - !NEW CODE FOR ENVIRONMENTALLY SENSITIVE SEEDLING MORTALITY - !Step 1. Calculate the daily seedling mortality rate from light stress + + end if !regeneration model switch + + ! 2. Seedling mortality (i.e. fluxes from seedling pool (seed_germ) to litter) + !---------------------------------------------------------------------- + !NEW CODE FOR ENVIRONMENTALLY SENSITIVE SEEDLING MORTALITY + !Step 1. Calculate the daily seedling mortality rate from light stress - !ADD CODE FOR CUMULATIVE LIGHT - ! seedling_layer_par = ( currentPatch%parprof_dir_z(currentPatch%ncl_p,max(currentPatch%ncan(currentPatch%ncl_p,:))) ) ! + & + !ADD CODE FOR CUMULATIVE LIGHT + !seedling_layer_par = ( currentPatch%parprof_dir_z(currentPatch%ncl_p,max(currentPatch%ncan(currentPatch%ncl_p,:))) ) ! + & ! currentPatch%parprof_dif_z(currentPatch%ncl_p,max(currentPatch%ncan(currentPatch%ncl_p,:))) ) ! * & ! megajoules_per_joule * sec_per_day * seedling_light_mort_window - ! seedling_light_mort_rate = exp(EDPftvarcon_inst%seedling_light_mort_a(pft) * & - ! seedling_layer_par + EDPftvarcon_inst%seedling_light_mort_b(pft)) + !seedling_light_mort_rate = exp(EDPftvarcon_inst%seedling_light_mort_a(pft) * & + !seedling_layer_par + EDPftvarcon_inst%seedling_light_mort_b(pft)) - ! write(fates_log(),*) 'seedling layer par ', seedling_layer_par - ! write(fates_log(),*) 'seedling light mort rate ', seedling_light_mort_rate + !write(fates_log(),*) 'seedling layer par ', seedling_layer_par + !write(fates_log(),*) 'seedling light mort rate ', seedling_light_mort_rate - !Step 2. Calculate the moisture deficit days !this code is a placeholder for now + !Step 2. Calculate the moisture deficit days !this code is a placeholder for now - !ilayer_swater_emerg = minloc(abs(bc_in%z_sisl(:)-emerg_soil_depth),dim=1) !define soil layer + !ilayer_swater_emerg = minloc(abs(bc_in%z_sisl(:)-emerg_soil_depth),dim=1) !define soil layer - !moisture_def_days = abs(bc_in%smp_sl(ilayer_swater_emerg) * mpa_per_mm_suction) - & !calculate smp (mm H20 suction?) - ! abs(EDPftvarcon_inst%seedling_smp_crit(pft)) + !moisture_def_days = abs(bc_in%smp_sl(ilayer_swater_emerg) * mpa_per_mm_suction) - & !calculate smp (mm H20 suction?) + ! abs(EDPftvarcon_inst%seedling_smp_crit(pft)) - !Step 3. Calculate the daily seedling mortality rate from moisture stress + !Step 3. Calculate the daily seedling mortality rate from moisture stress - !seedling_h2o_mort_rate = EDPftvarcon_inst%seedling_h2o_mort_a(pft) * moisture_def_days**2 + & - ! EDPftvarcon_inst%seedling_h2o_mort_b(pft) * moisture_def_days + & - ! EDPftvarcon_inst%seedling_h2o_mort_c(pft) + !seedling_h2o_mort_rate = EDPftvarcon_inst%seedling_h2o_mort_a(pft) * moisture_def_days**2 + & + ! EDPftvarcon_inst%seedling_h2o_mort_b(pft) * moisture_def_days + & + ! EDPftvarcon_inst%seedling_h2o_mort_c(pft) - !if (moisture_def_days < EDPftvarcon_inst%moisture_dd_crit(pft) ) then - ! seedling_h2o_mort_rate = 0.0_r8 - !end if + !if (moisture_def_days < EDPftvarcon_inst%moisture_dd_crit(pft) ) then + ! seedling_h2o_mort_rate = 0.0_r8 + !end if - !Step 4. Add background mortality and send seedling carbon to litter flux (i.e. to 'seed_germ_decay' flux) + !Step 4. Add background mortality and send seedling carbon to litter flux (i.e. to 'seed_germ_decay' flux) !litt%seed_germ_decay(pft) = (litt%seed_germ(pft) * seedling_light_mort_rate) !+ & !(litt%seed_germ(pft) * seedling_h2o_mort_rate) + & !(litt%seed_germ(pft) * EDPftvarcon_inst%background_seedling_mort(pft) & @@ -1871,15 +1873,12 @@ subroutine SeedGermination( litt, cold_stat, drought_stat, bc_in, currentPatch ) !------------------------------------------------------------------------------------------------------------ integer :: ilayer_seedling_root ! the soil layer at seedling rooting depth real(r8) :: seedling_layer_smp ! soil matric potential at seedling rooting depth - real(r8) :: wetness_index ! a soil 'wetness index' calculated from soil matric potential - - real(r8) :: seedling_layer_par ! photosynthetically active radiation at the seedling layer - real(r8) :: slsmp_emerg - real(r8) :: slparmort - real(r8) :: slpartrans - + real(r8) :: wetness_index ! a soil 'wetness index' (1 / - SoilMatricPotetial (MPa) ) + real(r8) :: seedling_layer_par ! par at the seedling layer (MJ m-2 day-1) + real(r8) :: slsmp_emerg !temp + real(r8) :: slparmort !temp + real(r8) :: slpartrans !temp real(r8) :: photoblastic_germ_modifier ! seedling emergence rate modifier for light-sensitive germination - ! used in the moisture-sensitive emergence function real(r8) :: seedling_emerg_rate ! the fraction of the seed bank emerging in the current time step !------------------------------------------------------------------------------------------------------------- @@ -1897,22 +1896,62 @@ subroutine SeedGermination( litt, cold_stat, drought_stat, bc_in, currentPatch ) ! that times the ratio of (hypothetical) seed mass to recruit biomass !START ahb's CHANGES - !ORIGINAL CODE - !------------------------------------------------------------------------------------------- - do pft = 1,numpft - ! litt%seed_germ_in(pft) = min(litt%seed(pft) * EDPftvarcon_inst%germination_rate(pft), & - ! max_germination)*years_per_day - !------------------------------------------------------------------------------------------- - - !This code adds light and moisture-sensitive seedling emergence from the seed bank. - !It replaces the old prescribed seed germination rate parameter. - !------------------------------------------------------------------------------------------- - !Step 1. calculate the photoblastic germination rate modifier + !============================================================================================== + do pft = 1,numpft + if ( regeneration_model == default_regeneration .or. & + prt_params%allom_dbh_maxheight(pft) < min_max_dbh_for_trees ) then + + !FATES default germination scheme + litt%seed_germ_in(pft) = min(litt%seed(pft) * EDPftvarcon_inst%germination_rate(pft), & + max_germination)*years_per_day + + else if ( regeneration_model == TRS .and. & + prt_params%allom_dbh_maxheight(pft) > min_max_dbh_for_trees ) then + + !------------------------------------------------------------------------------------------- + !The Tree Recruitment Scheme calculates seedling emergence (i.e. germination) as a pft-specific + !function of understory light and soil moisture + + !Step 1. Calculate how germination rate is modified by understory light. + ! This applies to photoblastic germinators (e.g. many tropical pioneers) + + !Calculate par at the seedling layer (MJ m-2 day-1) + !The running mean variable is in W m-2 over prior 24 hours. It is converted to MJ m-2 day-1 + !to work with the TRS function. + + seedling_layer_par = currentPatch%seedling_layer_par24%GetMean() * sec_per_day * megajoules_per_joule + + !Calculate the photoblastic germination rate modifier (see eqn. 3 of Hanbury-Brown et al., 2022) + photoblastic_germ_modifier = seedling_layer_par / & + (seedling_layer_par + EDPftvarcon_inst%par_crit_germ(pft)) + + !Step 2. Calculate the soil matric potential at the seedling rooting depth + + !Define soil layer based on pft-specific rooting depth + !ilayer_seedling_root = minloc(abs(bc_in%z_sisl(:)-EDPftvarcon_inst%seedling_root_depth(pft)),dim=1) + + !Get running mean of soil matric potential (mm of H2O suction) at the seedling rooting depth + seedling_layer_smp = currentPatch%sdlng_emerg_smp(pft)%p%GetMean() - seedling_layer_par = currentPatch%seedling_layer_par24%GetMean() - !slsmp_emerg = currentPatch%sdlng_emerg_smp%GetMean() - !slparmort = currentPatch%sdlng_mort_par%GetMean() - !slpartrans = currentPatch%sdlng2sap_par%GetMean() + !Calculate a soil wetness index (1 / -soil matric pontential (MPa) ) used by the TRS moisture-based + !seedling mortality function + wetness_index = 1.0_r8 / (seedling_layer_smp * (-1.0_r8) * mpa_per_mm_suction) + + !Step 3. Calculate the seedling emergence rate based on soil moisture and germination + ! rate modifier (i.e. Step 1). See eqn. 4 of Hanbury-Brown et al., 2022 + + seedling_emerg_rate = photoblastic_germ_modifier * EDPftvarcon_inst%a_emerg(pft) * & + wetness_index**EDPftvarcon_inst%b_emerg(pft) + + !Step 4. Calculate the amount of carbon germinating out of the seed bank + litt%seed_germ_in(pft) = litt%seed(pft) * seedling_emerg_rate + + end if !regeneration model switch + !-------------------------------------------------------------------------------------------- + !TEMP + !slsmp_emerg = currentPatch%sdlng_emerg_smp%GetMean() + !slparmort = currentPatch%sdlng_mort_par%GetMean() + !slpartrans = currentPatch%sdlng2sap_par%GetMean() ! write(fates_log(),*) 'nrm parprof', currentPatch%nrmlzd_parprof_dir_z(:,:,:) ! write(fates_log(),*) 'parprof', currentPatch%parprof_dif_z(1,:) @@ -1924,45 +1963,19 @@ subroutine SeedGermination( litt, cold_stat, drought_stat, bc_in, currentPatch ) ! write(fates_log(),*) 'seedling_mort_par', slparmort ! write(fates_log(),*) 'seedling2sap_trans_par', slpartrans ! write(fates_log(),*) 'tveg_lpa', currentPatch%tveg_lpa%GetMean() - - seedling_layer_par = seedling_layer_par * 4.6_r8 !covert to umol s-1 of PAR - !1 W/m2 ≈ 4.6 μmole.m2/s - - photoblastic_germ_modifier = seedling_layer_par / & - (seedling_layer_par + EDPftvarcon_inst%par_crit_germ(pft)) - - !Step 2. calculate the soil matric potential at the seedling root depth - - !define soil layer - ilayer_seedling_root = minloc(abs(bc_in%z_sisl(:)-EDPftvarcon_inst%seedling_root_depth(pft)),dim=1) - - !get soil matric potential (mm of H2O suction) at the seedling rooting depth - seedling_layer_smp = bc_in%smp_sl(ilayer_seedling_root) + !================================================================================================ + !END ahb changes - !calculate a soil wetness index, which is used by the moisture-based seedling mortality function - wetness_index = 1.0_r8 / (seedling_layer_smp * (-1.0_r8) * mpa_per_mm_suction) - - !Step 3. calculate the seedling emergence rate based on soil moisture and par - seedling_emerg_rate = photoblastic_germ_modifier * EDPftvarcon_inst%a_emerg(pft) * & - wetness_index**EDPftvarcon_inst%b_emerg(pft) - - !Step 4. calculate the 'seed_germ_in' flux - - !do pft = 1,numpft - litt%seed_germ_in(pft) = min(litt%seed(pft) * seedling_emerg_rate, max_germination) - !------------------------------------------------------------------------------------------- - !END ahb changes + !set the germination only under the growing season...c.xu - !set the germination only under the growing season...c.xu - - if ((prt_params%season_decid(pft) == itrue ) .and. & + if ((prt_params%season_decid(pft) == itrue ) .and. & (any(cold_stat == [phen_cstat_nevercold,phen_cstat_iscold]))) then litt%seed_germ_in(pft) = 0.0_r8 - endif - if ((prt_params%stress_decid(pft) == itrue ) .and. & + endif + if ((prt_params%stress_decid(pft) == itrue ) .and. & (any(drought_stat == [phen_dstat_timeoff,phen_dstat_moistoff]))) then litt%seed_germ_in(pft) = 0.0_r8 - end if + end if enddo From 7d7b52dba3f9ead1fb887bcae2bf60007e8f7efd Mon Sep 17 00:00:00 2001 From: adamhb Date: Tue, 21 Dec 2021 18:50:04 -0800 Subject: [PATCH 42/81] finished seedling germination functions; fates-trs working --- biogeochem/EDPhysiologyMod.F90 | 23 +++++++++++++++-------- main/EDPftvarcon.F90 | 10 ++++++++++ 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/biogeochem/EDPhysiologyMod.F90 b/biogeochem/EDPhysiologyMod.F90 index 1942aed90b..f481be8f73 100644 --- a/biogeochem/EDPhysiologyMod.F90 +++ b/biogeochem/EDPhysiologyMod.F90 @@ -1904,13 +1904,14 @@ subroutine SeedGermination( litt, cold_stat, drought_stat, bc_in, currentPatch ) !FATES default germination scheme litt%seed_germ_in(pft) = min(litt%seed(pft) * EDPftvarcon_inst%germination_rate(pft), & max_germination)*years_per_day - - else if ( regeneration_model == TRS .and. & - prt_params%allom_dbh_maxheight(pft) > min_max_dbh_for_trees ) then - + !end FATES default germination scheme + !------------------------------------------------------------------------------------------- !The Tree Recruitment Scheme calculates seedling emergence (i.e. germination) as a pft-specific !function of understory light and soil moisture + + else if ( regeneration_model == TRS .and. & + prt_params%allom_dbh_maxheight(pft) > min_max_dbh_for_trees ) then !Step 1. Calculate how germination rate is modified by understory light. ! This applies to photoblastic germinators (e.g. many tropical pioneers) @@ -1939,12 +1940,18 @@ subroutine SeedGermination( litt, cold_stat, drought_stat, bc_in, currentPatch ) !Step 3. Calculate the seedling emergence rate based on soil moisture and germination ! rate modifier (i.e. Step 1). See eqn. 4 of Hanbury-Brown et al., 2022 - + + if ( seedling_layer_smp * mpa_per_mm_suction .GE. EDPftvarcon_inst%seedling_psi_emerg(pft) ) then seedling_emerg_rate = photoblastic_germ_modifier * EDPftvarcon_inst%a_emerg(pft) * & wetness_index**EDPftvarcon_inst%b_emerg(pft) - - !Step 4. Calculate the amount of carbon germinating out of the seed bank - litt%seed_germ_in(pft) = litt%seed(pft) * seedling_emerg_rate + else + + seedling_emerg_rate = 0.0_r8 + + end if !soil-moisture based seedling emergence rate + + !Step 4. Calculate the amount of carbon germinating out of the seed bank + litt%seed_germ_in(pft) = litt%seed(pft) * seedling_emerg_rate end if !regeneration model switch !-------------------------------------------------------------------------------------------- diff --git a/main/EDPftvarcon.F90 b/main/EDPftvarcon.F90 index 4c56b4e004..431b472565 100644 --- a/main/EDPftvarcon.F90 +++ b/main/EDPftvarcon.F90 @@ -104,6 +104,7 @@ module EDPftvarcon real(r8), allocatable :: a_emerg(:) !added by ahb 7/19/2021 real(r8), allocatable :: b_emerg(:) !added by ahb 7/19/2021 real(r8), allocatable :: par_crit_germ(:) !added by ahb 7/19/2021 + real(r8), allocatable :: seedling_psi_emerg(:) !added by ahb 7/19/2021 real(r8), allocatable :: seedling_root_depth(:) !added by ahb 7/27/2021 real(r8), allocatable :: seedling_light_mort_a(:) !added by ahb on 7/27/2021 real(r8), allocatable :: seedling_light_mort_b(:) !added by ahb on 7/27/2021 @@ -559,6 +560,10 @@ subroutine Register_PFT(this, fates_params) call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) + name = 'fates_seedling_psi_emerg' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + name = 'fates_seedling_root_depth' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) @@ -938,6 +943,10 @@ subroutine Receive_PFT(this, fates_params) call fates_params%RetreiveParameterAllocate(name=name, & data=this%par_crit_germ) + name = 'fates_seedling_psi_emerg' + call fates_params%RetreiveParameterAllocate(name=name, & + data=this%seedling_psi_emerg) + name = 'fates_seedling_root_depth' call fates_params%RetreiveParameterAllocate(name=name, & data=this%seedling_root_depth) @@ -1502,6 +1511,7 @@ subroutine FatesReportPFTParams(is_master) write(fates_log(),fmt0) 'a_emerg = ',EDPftvarcon_inst%a_emerg write(fates_log(),fmt0) 'b_emerg = ',EDPftvarcon_inst%b_emerg write(fates_log(),fmt0) 'par_crit_germ = ',EDPftvarcon_inst%par_crit_germ + write(fates_log(),fmt0) 'seedling_psi_emerg = ',EDPftvarcon_inst%seedling_psi_emerg write(fates_log(),fmt0) 'seedling_root_depth = ',EDPftvarcon_inst%seedling_root_depth write(fates_log(),fmt0) 'trim_limit = ',EDPftvarcon_inst%trim_limit write(fates_log(),fmt0) 'trim_inc = ',EDPftvarcon_inst%trim_inc From 35fcdb3e53279dcc1c0c21cc2c308dc22b12183c Mon Sep 17 00:00:00 2001 From: adamhb Date: Tue, 21 Dec 2021 20:52:50 -0800 Subject: [PATCH 43/81] added light based seedling mortality; model working --- biogeochem/EDPhysiologyMod.F90 | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/biogeochem/EDPhysiologyMod.F90 b/biogeochem/EDPhysiologyMod.F90 index f481be8f73..49bbf9ca84 100644 --- a/biogeochem/EDPhysiologyMod.F90 +++ b/biogeochem/EDPhysiologyMod.F90 @@ -78,6 +78,7 @@ module EDPhysiologyMod use EDParamsMod , only : q10_froz use EDParamsMod , only : logging_export_frac use EDParamsMod , only : regeneration_model + use EDParamsMod , only : sdlng_mort_par_timescale use FatesPlantHydraulicsMod , only : AccumulateMortalityWaterStorage use FatesConstantsMod , only : itrue,ifalse use FatesConstantsMod , only : calloc_abs_error @@ -1798,29 +1799,25 @@ subroutine SeedDecay( litt , currentPatch, bc_in ) ! 2. Seedling mortality (i.e. fluxes from seedling pool (seed_germ) to litter) !---------------------------------------------------------------------- - !NEW CODE FOR ENVIRONMENTALLY SENSITIVE SEEDLING MORTALITY !Step 1. Calculate the daily seedling mortality rate from light stress - !ADD CODE FOR CUMULATIVE LIGHT - !seedling_layer_par = ( currentPatch%parprof_dir_z(currentPatch%ncl_p,max(currentPatch%ncan(currentPatch%ncl_p,:))) ) ! + & - ! currentPatch%parprof_dif_z(currentPatch%ncl_p,max(currentPatch%ncan(currentPatch%ncl_p,:))) ) - ! * & - ! megajoules_per_joule * sec_per_day * seedling_light_mort_window + !Calculate the cumulative light at the seedling layer over a prior number of + !days set by the "sdlng_mort_par_timescale" parameter - !seedling_light_mort_rate = exp(EDPftvarcon_inst%seedling_light_mort_a(pft) * & - !seedling_layer_par + EDPftvarcon_inst%seedling_light_mort_b(pft)) - + seedling_layer_par = currentPatch%sdlng_mort_par%GetMean() * megajoules_per_joule * & + sec_per_day * sdlng_mort_par_timescale + seedling_light_mort_rate = exp( EDPftvarcon_inst%seedling_light_mort_a(pft) * & + seedling_layer_par + EDPftvarcon_inst%seedling_light_mort_b(pft )) + + !TEMP !write(fates_log(),*) 'seedling layer par ', seedling_layer_par !write(fates_log(),*) 'seedling light mort rate ', seedling_light_mort_rate - !Step 2. Calculate the moisture deficit days !this code is a placeholder for now + !Step 2. Calculate the seedling moisture deficit days - !ilayer_swater_emerg = minloc(abs(bc_in%z_sisl(:)-emerg_soil_depth),dim=1) !define soil layer - !moisture_def_days = abs(bc_in%smp_sl(ilayer_swater_emerg) * mpa_per_mm_suction) - & !calculate smp (mm H20 suction?) - ! abs(EDPftvarcon_inst%seedling_smp_crit(pft)) !Step 3. Calculate the daily seedling mortality rate from moisture stress From 0c81c9c6870c1175c15f8f9463937d3c356dec11 Mon Sep 17 00:00:00 2001 From: adamhb Date: Wed, 22 Dec 2021 12:13:50 -0800 Subject: [PATCH 44/81] adding seedling mortality functions; fates-trs working --- biogeochem/EDPhysiologyMod.F90 | 47 ++++++++++++++++--------------- main/EDPftvarcon.F90 | 51 ++++++++++++++++++++++++++++++++++ main/FatesInterfaceMod.F90 | 5 ++-- 3 files changed, 78 insertions(+), 25 deletions(-) diff --git a/biogeochem/EDPhysiologyMod.F90 b/biogeochem/EDPhysiologyMod.F90 index 49bbf9ca84..514142e685 100644 --- a/biogeochem/EDPhysiologyMod.F90 +++ b/biogeochem/EDPhysiologyMod.F90 @@ -1758,8 +1758,10 @@ subroutine SeedDecay( litt , currentPatch, bc_in ) integer :: pft real(r8) :: seedling_layer_par !cumulative light at the seedling layer (MJ) over prior window of days !(defined by 'light_mort_window' param) - real(r8), parameter :: seedling_light_mort_window = 64.0 !days; move to pft-level parameter real(r8) :: seedling_light_mort_rate !the daily seedling mortality rate from light stress + real(r8) :: seedling_h2o_mort_rate !the daily seedling mortality rate from moisture stress + real(r8) :: seedling_mdds !moisture deficit days accumulated in the seedling layer + !---------------------------------------------------------------------- @@ -1808,34 +1810,33 @@ subroutine SeedDecay( litt , currentPatch, bc_in ) sec_per_day * sdlng_mort_par_timescale seedling_light_mort_rate = exp( EDPftvarcon_inst%seedling_light_mort_a(pft) * & - seedling_layer_par + EDPftvarcon_inst%seedling_light_mort_b(pft )) + seedling_layer_par + EDPftvarcon_inst%seedling_light_mort_b(pft) ) !TEMP !write(fates_log(),*) 'seedling layer par ', seedling_layer_par !write(fates_log(),*) 'seedling light mort rate ', seedling_light_mort_rate - - !Step 2. Calculate the seedling moisture deficit days - - - - !Step 3. Calculate the daily seedling mortality rate from moisture stress - - !seedling_h2o_mort_rate = EDPftvarcon_inst%seedling_h2o_mort_a(pft) * moisture_def_days**2 + & - ! EDPftvarcon_inst%seedling_h2o_mort_b(pft) * moisture_def_days + & - ! EDPftvarcon_inst%seedling_h2o_mort_c(pft) - - !if (moisture_def_days < EDPftvarcon_inst%moisture_dd_crit(pft) ) then - ! seedling_h2o_mort_rate = 0.0_r8 - !end if - + + !Get the current seedling moisture deficit days + !Calculated as (abs(seedling_psi_crit) - abs(seedling_layer_smp))* -1 * mddWindow + + seedling_mdds = currentPatch%sdlng_mdd(pft)%p%GetMean() - !Step 4. Add background mortality and send seedling carbon to litter flux (i.e. to 'seed_germ_decay' flux) - !litt%seed_germ_decay(pft) = (litt%seed_germ(pft) * seedling_light_mort_rate) !+ & - !(litt%seed_germ(pft) * seedling_h2o_mort_rate) + & - !(litt%seed_germ(pft) * EDPftvarcon_inst%background_seedling_mort(pft) & - !*years_per_day) + !Calculate seedling mortality as a function of moisture deficit days + seedling_h2o_mort_rate = EDPftvarcon_inst%seedling_h2o_mort_a(pft) * seedling_mdds**2 + & + EDPftvarcon_inst%seedling_h2o_mort_b(pft) * seedling_mdds + & + EDPftvarcon_inst%seedling_h2o_mort_c(pft) + + if (seedling_mdds < EDPftvarcon_inst%seedling_mdd_crit(pft)) then + seedling_h2o_mort_rate = 0.0_r8 + end if + + !Step 4. Add background mortality and send dead seedling carbon to litter (i.e. to seed_germ_decay flux) + litt%seed_germ_decay(pft) = (litt%seed_germ(pft) * seedling_light_mort_rate) + & + (litt%seed_germ(pft) * seedling_h2o_mort_rate) + & + (litt%seed_germ(pft) * EDPftvarcon_inst%background_seedling_mort(pft) & + * years_per_day) !----------------------------------------------------------------------- !END ahb's changes @@ -1938,7 +1939,7 @@ subroutine SeedGermination( litt, cold_stat, drought_stat, bc_in, currentPatch ) !Step 3. Calculate the seedling emergence rate based on soil moisture and germination ! rate modifier (i.e. Step 1). See eqn. 4 of Hanbury-Brown et al., 2022 - if ( seedling_layer_smp * mpa_per_mm_suction .GE. EDPftvarcon_inst%seedling_psi_emerg(pft) ) then + if ( seedling_layer_smp .GE. EDPftvarcon_inst%seedling_psi_emerg(pft) ) then seedling_emerg_rate = photoblastic_germ_modifier * EDPftvarcon_inst%a_emerg(pft) * & wetness_index**EDPftvarcon_inst%b_emerg(pft) else diff --git a/main/EDPftvarcon.F90 b/main/EDPftvarcon.F90 index 431b472565..60888a3549 100644 --- a/main/EDPftvarcon.F90 +++ b/main/EDPftvarcon.F90 @@ -105,6 +105,11 @@ module EDPftvarcon real(r8), allocatable :: b_emerg(:) !added by ahb 7/19/2021 real(r8), allocatable :: par_crit_germ(:) !added by ahb 7/19/2021 real(r8), allocatable :: seedling_psi_emerg(:) !added by ahb 7/19/2021 + real(r8), allocatable :: seedling_psi_crit(:) !added by ahb 7/19/2021 + real(r8), allocatable :: seedling_mdd_crit(:) !added by ahb 7/19/2021 + real(r8), allocatable :: seedling_h2o_mort_a(:) !added by ahb 7/19/2021 + real(r8), allocatable :: seedling_h2o_mort_b(:) !added by ahb 7/19/2021 + real(r8), allocatable :: seedling_h2o_mort_c(:) !added by ahb 7/19/2021 real(r8), allocatable :: seedling_root_depth(:) !added by ahb 7/27/2021 real(r8), allocatable :: seedling_light_mort_a(:) !added by ahb on 7/27/2021 real(r8), allocatable :: seedling_light_mort_b(:) !added by ahb on 7/27/2021 @@ -563,6 +568,26 @@ subroutine Register_PFT(this, fates_params) name = 'fates_seedling_psi_emerg' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) + + name = 'fates_seedling_psi_crit' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + + name = 'fates_seedling_mdd_crit' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + + name = 'fates_seedling_h2o_mort_a' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + + name = 'fates_seedling_h2o_mort_b' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + + name = 'fates_seedling_h2o_mort_c' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) name = 'fates_seedling_root_depth' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & @@ -946,6 +971,26 @@ subroutine Receive_PFT(this, fates_params) name = 'fates_seedling_psi_emerg' call fates_params%RetreiveParameterAllocate(name=name, & data=this%seedling_psi_emerg) + + name = 'fates_seedling_psi_crit' + call fates_params%RetreiveParameterAllocate(name=name, & + data=this%seedling_psi_crit) + + name = 'fates_seedling_mdd_crit' + call fates_params%RetreiveParameterAllocate(name=name, & + data=this%seedling_mdd_crit) + + name = 'fates_seedling_h2o_mort_a' + call fates_params%RetreiveParameterAllocate(name=name, & + data=this%seedling_h2o_mort_a) + + name = 'fates_seedling_h2o_mort_b' + call fates_params%RetreiveParameterAllocate(name=name, & + data=this%seedling_h2o_mort_b) + + name = 'fates_seedling_h2o_mort_c' + call fates_params%RetreiveParameterAllocate(name=name, & + data=this%seedling_h2o_mort_c) name = 'fates_seedling_root_depth' call fates_params%RetreiveParameterAllocate(name=name, & @@ -1512,7 +1557,13 @@ subroutine FatesReportPFTParams(is_master) write(fates_log(),fmt0) 'b_emerg = ',EDPftvarcon_inst%b_emerg write(fates_log(),fmt0) 'par_crit_germ = ',EDPftvarcon_inst%par_crit_germ write(fates_log(),fmt0) 'seedling_psi_emerg = ',EDPftvarcon_inst%seedling_psi_emerg + write(fates_log(),fmt0) 'seedling_psi_crit = ',EDPftvarcon_inst%seedling_psi_crit + write(fates_log(),fmt0) 'seedling_mdd_crit = ',EDPftvarcon_inst%seedling_mdd_crit + write(fates_log(),fmt0) 'background_seedling_mort = ',EDPftvarcon_inst%background_seedling_mort write(fates_log(),fmt0) 'seedling_root_depth = ',EDPftvarcon_inst%seedling_root_depth + write(fates_log(),fmt0) 'seedling_h2o_mort_a = ',EDPftvarcon_inst%seedling_h2o_mort_a + write(fates_log(),fmt0) 'seedling_h2o_mort_b = ',EDPftvarcon_inst%seedling_h2o_mort_b + write(fates_log(),fmt0) 'seedling_h2o_mort_c = ',EDPftvarcon_inst%seedling_h2o_mort_c write(fates_log(),fmt0) 'trim_limit = ',EDPftvarcon_inst%trim_limit write(fates_log(),fmt0) 'trim_inc = ',EDPftvarcon_inst%trim_inc write(fates_log(),fmt0) 'rhol = ',EDPftvarcon_inst%rhol diff --git a/main/FatesInterfaceMod.F90 b/main/FatesInterfaceMod.F90 index d6747de5a0..d37086a818 100644 --- a/main/FatesInterfaceMod.F90 +++ b/main/FatesInterfaceMod.F90 @@ -1981,8 +1981,9 @@ subroutine UpdateFatesRMeansTStep(sites,bc_in) new_seedling_layer_smp(pft) = bc_in(s)%smp_sl(ilayer_seedling_root(pft)) !calculate the new moisture deficit day (mdd) value for each pft - new_seedling_mdd(pft) = (abs(seedling_smp_crit) - abs(new_seedling_layer_smp(pft))) * (-1.0_r8) - + new_seedling_mdd(pft) = (abs(EDPftvarcon_inst%seedling_psi_crit(pft)) - abs(new_seedling_layer_smp(pft))) & + * (-1.0_r8) * sdlng_mdd_timescale + ! if mdds are negative then it means that soil is wetter than smp_crit and the moisture ! deficit is 0 if (new_seedling_mdd(pft) < 0.0_r8) then From 6177e63247c1ba088a89808394c0a75f085dfe47 Mon Sep 17 00:00:00 2001 From: adamhb Date: Wed, 22 Dec 2021 16:45:13 -0800 Subject: [PATCH 45/81] finished adding all TRS processes; model working --- biogeochem/EDPhysiologyMod.F90 | 33 ++++++++++++++++++++++++++++++++- main/EDPftvarcon.F90 | 22 +++++++++++++++++++++- 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/biogeochem/EDPhysiologyMod.F90 b/biogeochem/EDPhysiologyMod.F90 index 514142e685..8f20576c3a 100644 --- a/biogeochem/EDPhysiologyMod.F90 +++ b/biogeochem/EDPhysiologyMod.F90 @@ -2039,7 +2039,9 @@ subroutine recruitment( currentSite, currentPatch, bc_in ) real(r8) :: mass_demand ! Total mass demanded by the plant to achieve the stoichiometric targets ! of all the organs in the recruits. Used for both [kg per plant] and [kg per cohort] real(r8) :: stem_drop_fraction - + real(r8) :: sdlng2sap_par ! running mean of par at the seedlng layer [MJ m-2 day-1] + real(r8) :: seedling_layer_smp !soil matric potential at seedling rooting depth [mm H20 suction] + integer :: ilayer_seedling_root ! the soil layer at seedling rooting depth !---------------------------------------------------------------------- allocate(temp_cohort) ! create temporary cohort @@ -2163,8 +2165,37 @@ subroutine recruitment( currentSite, currentPatch, bc_in ) call endrun(msg=errMsg(sourcefile, __LINE__)) end select + !START ahb's changes + !================================================================================= + if ( regeneration_model == default_regeneration .or. & + prt_params%allom_dbh_maxheight(ft) < min_max_dbh_for_trees ) then + mass_avail = currentPatch%area * currentPatch%litter(el)%seed_germ(ft) + else if ( regeneration_model == TRS .and. & + prt_params%allom_dbh_maxheight(ft) > min_max_dbh_for_trees ) then + + sdlng2sap_par = currentPatch%sdlng2sap_par%GetMean() * sec_per_day * megajoules_per_joule + + mass_avail = currentPatch%area * currentPatch%litter(el)%seed_germ(ft) * & + EDPftvarcon_inst%seedling_light_rec_a(ft) * & + sdlng2sap_par**EDPftvarcon_inst%seedling_light_rec_b(ft) + + !If soil moisture is below the moisture stress threshold recruitment does not occur + ilayer_seedling_root = minloc(abs(bc_in%z_sisl(:)-EDPftvarcon_inst%seedling_root_depth(ft)),dim=1) + + seedling_layer_smp = bc_in%smp_sl(ilayer_seedling_root) + + if ( seedling_layer_smp < EDPftvarcon_inst%seedling_psi_crit(ft) ) then + + mass_avail = 0.0_r8 + + end if !check on soil moisture + + end if !regeneration model + + !================================================================================== + !END ahb's changes ! ------------------------------------------------------------------------ ! Update number density if this is the limiting mass ! ------------------------------------------------------------------------ diff --git a/main/EDPftvarcon.F90 b/main/EDPftvarcon.F90 index 60888a3549..ba88de9760 100644 --- a/main/EDPftvarcon.F90 +++ b/main/EDPftvarcon.F90 @@ -106,6 +106,8 @@ module EDPftvarcon real(r8), allocatable :: par_crit_germ(:) !added by ahb 7/19/2021 real(r8), allocatable :: seedling_psi_emerg(:) !added by ahb 7/19/2021 real(r8), allocatable :: seedling_psi_crit(:) !added by ahb 7/19/2021 + real(r8), allocatable :: seedling_light_rec_a(:) !added by ahb 7/19/2021 + real(r8), allocatable :: seedling_light_rec_b(:) !added by ahb 7/19/2021 real(r8), allocatable :: seedling_mdd_crit(:) !added by ahb 7/19/2021 real(r8), allocatable :: seedling_h2o_mort_a(:) !added by ahb 7/19/2021 real(r8), allocatable :: seedling_h2o_mort_b(:) !added by ahb 7/19/2021 @@ -573,6 +575,14 @@ subroutine Register_PFT(this, fates_params) call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) + name = 'fates_seedling_light_rec_a' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + + name = 'fates_seedling_light_rec_b' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + name = 'fates_seedling_mdd_crit' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) @@ -975,7 +985,15 @@ subroutine Receive_PFT(this, fates_params) name = 'fates_seedling_psi_crit' call fates_params%RetreiveParameterAllocate(name=name, & data=this%seedling_psi_crit) - + + name = 'fates_seedling_light_rec_a' + call fates_params%RetreiveParameterAllocate(name=name, & + data=this%seedling_light_rec_a) + + name = 'fates_seedling_light_rec_b' + call fates_params%RetreiveParameterAllocate(name=name, & + data=this%seedling_light_rec_b) + name = 'fates_seedling_mdd_crit' call fates_params%RetreiveParameterAllocate(name=name, & data=this%seedling_mdd_crit) @@ -1559,6 +1577,8 @@ subroutine FatesReportPFTParams(is_master) write(fates_log(),fmt0) 'seedling_psi_emerg = ',EDPftvarcon_inst%seedling_psi_emerg write(fates_log(),fmt0) 'seedling_psi_crit = ',EDPftvarcon_inst%seedling_psi_crit write(fates_log(),fmt0) 'seedling_mdd_crit = ',EDPftvarcon_inst%seedling_mdd_crit + write(fates_log(),fmt0) 'seedling_light_rec_a = ',EDPftvarcon_inst%seedling_light_rec_a + write(fates_log(),fmt0) 'seedling_light_rec_b = ',EDPftvarcon_inst%seedling_light_rec_b write(fates_log(),fmt0) 'background_seedling_mort = ',EDPftvarcon_inst%background_seedling_mort write(fates_log(),fmt0) 'seedling_root_depth = ',EDPftvarcon_inst%seedling_root_depth write(fates_log(),fmt0) 'seedling_h2o_mort_a = ',EDPftvarcon_inst%seedling_h2o_mort_a From 31918cf456fa217cff8d82fb4871507954426c2b Mon Sep 17 00:00:00 2001 From: adamhb Date: Tue, 11 Jan 2022 16:08:07 -0800 Subject: [PATCH 46/81] started diagnostics --- biogeochem/EDPhysiologyMod.F90 | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/biogeochem/EDPhysiologyMod.F90 b/biogeochem/EDPhysiologyMod.F90 index 8f20576c3a..04a9f416b4 100644 --- a/biogeochem/EDPhysiologyMod.F90 +++ b/biogeochem/EDPhysiologyMod.F90 @@ -2065,7 +2065,14 @@ subroutine recruitment( currentSite, currentPatch, bc_in ) stem_drop_fraction = EDPftvarcon_inst%phen_stem_drop_fraction(ft) call h2d_allom(temp_cohort%hite,ft,temp_cohort%dbh) + + !ahb diagnostic + if (hlm_day_of_year == 40) then + write(fates_log(),*) 'min_dbh:', temp_cohort%dbh + end if + !end ahb diagnostic + ! Initialize live pools call bleaf(temp_cohort%dbh,ft,temp_cohort%canopy_trim,c_leaf) call bfineroot(temp_cohort%dbh,ft,temp_cohort%canopy_trim,c_fnrt) @@ -2133,6 +2140,12 @@ subroutine recruitment( currentSite, currentPatch, bc_in ) case(carbon12_element) mass_demand = c_struct+c_leaf+c_fnrt+c_sapw+c_store + + !ahb diagnostic + if (hlm_day_of_year == 40) then + write(fates_log(),*) 'mass demand:', mass_demand + end if + !end ahb diagnostic case(nitrogen_element) From 7b3a7ac2879641310ef7fd5980fed54943c522bf Mon Sep 17 00:00:00 2001 From: adamhb Date: Wed, 12 Jan 2022 08:55:10 -0800 Subject: [PATCH 47/81] made new regeneration parameter file the default on this branch' --- parameter_files/fates_params_default.cdl | 420 +++++++++++++++-------- 1 file changed, 277 insertions(+), 143 deletions(-) diff --git a/parameter_files/fates_params_default.cdl b/parameter_files/fates_params_default.cdl index 6d5fa2cb4e..89d89cdf2a 100644 --- a/parameter_files/fates_params_default.cdl +++ b/parameter_files/fates_params_default.cdl @@ -137,19 +137,19 @@ variables: fates_allom_stmode:possible_values = "1: target storage proportional to trimmed maximum leaf biomass." ; 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" ; + fates_allom_zroot_k:long_name = "scale coefficient of logistic rooting depth model (NOT USED)" ; 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" ; + fates_allom_zroot_max_dbh:long_name = "dbh at which a plant reaches the maximum value for its maximum rooting depth (NOT USED)" ; 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" ; + fates_allom_zroot_max_z:long_name = "the maximum rooting depth defined at dbh = fates_allom_zroot_max_dbh (NOT USED). 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" ; + fates_allom_zroot_min_dbh:long_name = "dbh at which the maximum rooting depth for a recruit is defined (NOT USED)" ; 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" ; + fates_allom_zroot_min_z:long_name = "the maximum rooting depth defined at dbh = fates_allom_zroot_min_dbh (NOT USED) note: max_z=min_z=large, sets rooting depth to soil depth" ; double fates_branch_turnover(fates_pft) ; fates_branch_turnover:units = "yr" ; fates_branch_turnover:long_name = "turnover time of branches" ; @@ -431,10 +431,10 @@ variables: 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_prescribed_nuptake(fates_pft) ; - fates_prescribed_nuptake:units = "fraction" ; + fates_prescribed_nuptake:units = "fraction" ; fates_prescribed_nuptake:long_name = "Prescribed N uptake flux. 0=fully coupled simulation >0=prescribed (experimental)" ; double fates_prescribed_puptake(fates_pft) ; - fates_prescribed_puptake:units = "fraction" ; + fates_prescribed_puptake:units = "fraction" ; fates_prescribed_puptake:long_name = "Prescribed P uptake flux. 0=fully coupled simulation, >0=prescribed (experimental)" ; double fates_prescribed_recruitment(fates_pft) ; fates_prescribed_recruitment:units = "n/yr" ; @@ -478,7 +478,61 @@ variables: double fates_seed_alloc(fates_pft) ; fates_seed_alloc:units = "fraction" ; fates_seed_alloc:long_name = "fraction of available carbon balance allocated to seeds" ; - double fates_seed_alloc_mature(fates_pft) ; + double fates_repro_alloc_a(fates_pft) ; + fates_repro_alloc_a:units = "fraction" ; + fates_repro_alloc_a:long_name = "shape parameter for sigmoidal function relating dbh to reproductive allocation" ; + double fates_repro_alloc_b(fates_pft) ; + fates_repro_alloc_b:units = "fraction" ; + fates_repro_alloc_b:long_name = "intercept parameter for sigmoidal function relating dbh to reproductive allocation" ; + double fates_repro_frac_seed(fates_pft) ; + fates_repro_frac_seed:units = "fraction" ; + fates_repro_frac_seed:long_name = "fraction of reproductive mass that is seed" ; + double fates_a_emerg(fates_pft) ; + fates_a_emerg:units = "day -1" ; + fates_a_emerg:long_name = "mean fraction of seed bank emerging" ; + double fates_b_emerg(fates_pft) ; + fates_b_emerg:units = "day -1" ; + fates_b_emerg:long_name = "seedling emergence sensitivity to soil moisture" ; + double fates_par_crit_germ(fates_pft) ; + fates_par_crit_germ:units = "Megajoules m2-1 day-1 " ; + fates_par_crit_germ:long_name = "critical light level for germination" ; + double fates_seedling_root_depth(fates_pft) ; + fates_seedling_root_depth:units = "m" ; + fates_seedling_root_depth:long_name = "rooting depth of seedlings" ; + double fates_seedling_psi_emerg(fates_pft) ; + fates_seedling_psi_emerg:units = "mm h20 suction" ; + fates_seedling_psi_emerg:long_name = "critical soil moisture for seedling emergence" ; + double fates_seedling_psi_crit(fates_pft) ; + fates_seedling_psi_crit:units = "mm h20 suction" ; + fates_seedling_psi_crit:long_name = "critical soil moisture for seedling stress" ; + double fates_seedling_mdd_crit(fates_pft) ; + fates_seedling_mdd_crit:units = "moisture deficit days (mm h2o suction * days)" ; + fates_seedling_mdd_crit:long_name = "critical moisture deficit day accumulation for seedling moisture-based seedling mortality to begin" ; + double fates_seedling_h2o_mort_a(fates_pft) ; + fates_seedling_h2o_mort_a:units = "-" ; + fates_seedling_h2o_mort_a:long_name = "coefficient in moisture-based seedling mortality" ; + double fates_seedling_h2o_mort_b(fates_pft) ; + fates_seedling_h2o_mort_b:units = "-" ; + fates_seedling_h2o_mort_b:long_name = "coefficient in moisture-based seedling mortality" ; + double fates_seedling_h2o_mort_c(fates_pft) ; + fates_seedling_h2o_mort_c:units = "-" ; + fates_seedling_h2o_mort_c:long_name = "coefficient in moisture-based seedling mortality" ; + double fates_seedling_light_mort_a(fates_pft) ; + fates_seedling_light_mort_a:units = "-" ; + fates_seedling_light_mort_a:long_name = "light-based seedling mortality coefficient" ; + double fates_seedling_light_mort_b(fates_pft) ; + fates_seedling_light_mort_b:units = "-" ; + fates_seedling_light_mort_b:long_name = "light-based seedling mortality coefficient" ; + double fates_background_seedling_mort(fates_pft) ; + fates_background_seedling_mort:units = "yr-1" ; + fates_background_seedling_mort:long_name = "background seedling mortality rate" ; + double fates_seedling_light_rec_a(fates_pft) ; + fates_seedling_light_rec_a:units = "-" ; + fates_seedling_light_rec_a:long_name = "coefficient in light-based seedling to sapling transition" ; + double fates_seedling_light_rec_b(fates_pft) ; + fates_seedling_light_rec_b:units = "-" ; + fates_seedling_light_rec_b:long_name = "coefficient in light-based seedling to sapling transition" ; + double fates_seed_alloc_mature(fates_pft) ; fates_seed_alloc_mature:units = "fraction" ; fates_seed_alloc_mature:long_name = "fraction of available carbon balance allocated to seeds in mature plants (adds to fates_seed_alloc)" ; double fates_seed_dbh_repro_threshold(fates_pft) ; @@ -542,9 +596,9 @@ variables: double fates_z0mr(fates_pft) ; fates_z0mr:units = "unitless" ; fates_z0mr:long_name = "Ratio of momentum roughness length to canopy top height" ; - 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_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" ; @@ -662,7 +716,10 @@ variables: 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_logging_coll_under_frac ; + double fates_regeneration_model ; + fates_regeneration_model:units = "unitless" ; + fates_regeneration_model:long_name = "switch for choosing between FATES's default regeneration scheme (1) or the Tree Recruitment Scheme (Hanbury-Brown et al., 2022;2)" ; + double fates_logging_coll_under_frac ; fates_logging_coll_under_frac:units = "fraction" ; fates_logging_coll_under_frac:long_name = "Fraction of stems killed in the understory when logging generates disturbance" ; double fates_logging_collateral_frac ; @@ -731,6 +788,18 @@ variables: double fates_photo_temp_acclim_timescale ; fates_photo_temp_acclim_timescale:units = "days" ; fates_photo_temp_acclim_timescale:long_name = "Length of the window for the exponential moving average (ema) of vegetation temperature used in photosynthesis temperature acclimation (NOT USED)" ; + double fates_sdlng_emerg_h2o_timescale ; + fates_sdlng_emerg_h2o_timescale:units = "days" ; + fates_sdlng_emerg_h2o_timescale:long_name = "Length of the window for the exponential moving average of smp used to calculate seedling emergence" ; + double fates_sdlng_mort_par_timescale ; + fates_sdlng_mort_par_timescale:units = "days" ; + fates_sdlng_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_sdlng_mdd_timescale ; + fates_sdlng_mdd_timescale:units = "days" ; + fates_sdlng_mdd_timescale:long_name = "Length of the window for the exponential moving average of moisture deficit days used to calculate seedling mortality" ; + double fates_sdlng2sap_par_timescale ; + fates_sdlng2sap_par_timescale:units = "days" ; + fates_sdlng2sap_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_photo_tempsens_model ; fates_photo_tempsens_model:units = "unitless" ; fates_photo_tempsens_model:long_name = "switch for choosing the model that defines the temperature sensitivity of photosynthetic parameters (vcmax, jmax). 1=non-acclimating (NOT USED)" ; @@ -766,7 +835,7 @@ data: fates_history_height_bin_edges = 0, 0.1, 0.3, 1, 3, 10 ; - fates_history_sizeclass_bin_edges = 0, 5, 10, 15, 20, 30, 40, 50, 60, 70, + fates_history_sizeclass_bin_edges = 0, 5, 10, 15, 20, 30, 40, 50, 60, 70, 80, 90, 100 ; fates_hydr_htftype_node = 1, 1, 1, 1 ; @@ -807,22 +876,22 @@ data: "sapwood ", "structure " ; - fates_alloc_storage_cushion = 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, + fates_alloc_storage_cushion = 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_allom_agb1 = 0.06896, 0.06896, 0.06896, 0.06896, 0.06896, 0.06896, + 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, + 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, + 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, + 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, + 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 ; @@ -831,30 +900,30 @@ data: fates_allom_cmode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; - fates_allom_d2bl1 = 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, 90, 90, 90, 90, 90, 3, 3, 2, 0.35, 0.35, 0.35 ; @@ -867,14 +936,14 @@ data: 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, + 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, + 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 ; @@ -885,13 +954,13 @@ data: 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, + 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, + 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, + fates_allom_zroot_min_z = 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100 ; fates_branch_turnover = 150, 150, 150, 150, 150, 150, 150, 150, 150, 0, 0, 0 ; @@ -900,19 +969,19 @@ data: fates_dev_arbitrary_pft = _, _, _, _, _, _, _, _, _, _, _, _ ; - fates_displar = 0.67, 0.67, 0.67, 0.67, 0.67, 0.67, 0.67, 0.67, 0.67, 0.67, + fates_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_eca_alpha_ptase = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + fates_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_eca_decompmicc = 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + fates_eca_decompmicc = 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280 ; - fates_eca_km_nh4 = 0.14, 0.14, 0.14, 0.14, 0.14, 0.14, 0.14, 0.14, 0.14, + fates_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_eca_km_no3 = 0.27, 0.27, 0.27, 0.27, 0.27, 0.27, 0.27, 0.27, 0.27, + fates_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_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 ; @@ -921,28 +990,28 @@ data: fates_eca_lambda_ptase = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; - fates_eca_vmax_nh4 = 1.5e-07, 1.5e-07, 1.5e-07, 1.5e-07, 1.5e-07, 1.5e-07, + fates_eca_vmax_nh4 = 1.5e-07, 1.5e-07, 1.5e-07, 1.5e-07, 1.5e-07, 1.5e-07, 1.5e-07, 1.5e-07, 1.5e-07, 1.5e-07, 1.5e-07, 1.5e-07 ; - fates_eca_vmax_no3 = 1.5e-08, 1.5e-08, 1.5e-08, 1.5e-08, 1.5e-08, 1.5e-08, + fates_eca_vmax_no3 = 1.5e-08, 1.5e-08, 1.5e-08, 1.5e-08, 1.5e-08, 1.5e-08, 1.5e-08, 1.5e-08, 1.5e-08, 1.5e-08, 1.5e-08, 1.5e-08 ; - fates_eca_vmax_p = 1.5e-09, 1.5e-09, 1.5e-09, 1.5e-09, 1.5e-09, 1.5e-09, + fates_eca_vmax_p = 1.5e-09, 1.5e-09, 1.5e-09, 1.5e-09, 1.5e-09, 1.5e-09, 1.5e-09, 1.5e-09, 1.5e-09, 1.5e-09, 1.5e-09, 1.5e-09 ; - fates_eca_vmax_ptase = 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, + fates_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_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, + 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, + 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_depth_frac = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.95, 0.95, + fates_fire_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_fire_crown_kill = 0.775, 0.775, 0.775, 0.775, 0.775, 0.775, 0.775, + 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_fnrt_prof_a = 7, 7, 7, 7, 6, 6, 7, 7, 7, 11, 11, 11 ; @@ -953,16 +1022,16 @@ data: fates_fr_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_fr_flab = 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + fates_fr_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_fr_flig = 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + fates_fr_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_grperc = 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, + 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_hydr_avuln_gs = 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, + fates_hydr_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_hydr_avuln_node = @@ -991,34 +1060,34 @@ data: -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_hydr_p50_gs = -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, + fates_hydr_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_hydr_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, -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_hydr_p_taper = 0.333, 0.333, 0.333, 0.333, 0.333, 0.333, 0.333, 0.333, + fates_hydr_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_hydr_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.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.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, -1.043478, -1.043478, -1.043478, -1.043478, -1.043478, -1.043478 ; fates_hydr_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.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, @@ -1030,10 +1099,10 @@ data: 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_hydr_rfrac_stem = 0.625, 0.625, 0.625, 0.625, 0.625, 0.625, 0.625, + fates_hydr_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_hydr_rs2 = 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, + fates_hydr_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_hydr_srl = 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25 ; @@ -1045,13 +1114,13 @@ data: 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_hydr_vg_alpha_node = - 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 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.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.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.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.005, 0.005, 0.005, 0.005, 0.005, 0.005, 0.005 ; fates_hydr_vg_m_node = @@ -1068,79 +1137,79 @@ data: fates_leaf_c3psn = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 ; - fates_leaf_clumping_index = 0.85, 0.85, 0.8, 0.85, 0.85, 0.9, 0.85, 0.9, + fates_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_leaf_diameter = 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, + fates_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_leaf_jmaxha = 43540, 43540, 43540, 43540, 43540, 43540, 43540, 43540, + 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, + 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, + fates_leaf_jmaxse = 495, 495, 495, 495, 495, 495, 495, 495, 495, 495, 495, 495 ; fates_leaf_long = 1.5, 4, 1, 1.5, 1, 1, 1.5, 1, 1, 1, 1, 1 ; - fates_leaf_slamax = 0.0954, 0.0954, 0.0954, 0.0954, 0.0954, 0.0954, 0.012, + 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.01, 0.024, 0.012, 0.03, 0.03, 0.012, 0.03, + fates_leaf_slatop = 0.012, 0.01, 0.024, 0.012, 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, + 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, + 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_stor_priority = 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, + fates_leaf_stor_priority = 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_leaf_vcmax25top = 50, 65, 39, 62, 41, 58, 62, 54, 54, 78, 78, 78 ; - fates_leaf_vcmaxha = 65330, 65330, 65330, 65330, 65330, 65330, 65330, 65330, + 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, + 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, + fates_leaf_vcmaxse = 485, 485, 485, 485, 485, 485, 485, 485, 485, 485, 485, 485 ; - fates_leaf_xl = 0.1, 0.01, 0.01, 0.1, 0.01, 0.25, 0.01, 0.25, 0.25, -0.3, + fates_leaf_xl = 0.1, 0.01, 0.01, 0.1, 0.01, 0.25, 0.01, 0.25, 0.25, -0.3, -0.3, -0.3 ; fates_lf_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_lf_flab = 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + fates_lf_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_lf_flig = 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + fates_lf_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_maintresp_reduction_curvature = 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, + 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_mort_bmort = 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, + 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, -30, -60, -10, -80, -80, + fates_mort_freezetol = 2.5, -55, -80, -30, 2.5, -30, -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, + 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, + 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 = _, _, _, _, _, _, _, _, _, _, _, _ ; @@ -1153,17 +1222,17 @@ data: 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, + 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, + 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_nfix1 = _, _, _, _, _, _, _, _, _, _, _, _ ; fates_nfix2 = _, _, _, _, _, _, _, _, _, _, _, _ ; - fates_nitr_store_ratio = 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, + fates_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_phen_cold_size_threshold = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; @@ -1178,26 +1247,26 @@ data: fates_phenflush_fraction = _, _, 0.5, _, 0.5, 0.5, _, 0.5, 0.5, 0.5, 0.5, 0.5 ; - fates_phos_store_ratio = 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, + fates_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_prescribed_mortality_canopy = 0.0194, 0.0194, 0.0194, 0.0194, 0.0194, + fates_prescribed_mortality_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_prescribed_mortality_understory = 0.025, 0.025, 0.025, 0.025, 0.025, + fates_prescribed_mortality_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_prescribed_npp_canopy = 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, + 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, + 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_prescribed_nuptake = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; fates_prescribed_puptake = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; - fates_prescribed_recruitment = 0.02, 0.02, 0.02, 0.02, 0.02, 0.02, 0.02, + fates_prescribed_recruitment = 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_prt_alloc_priority = @@ -1208,97 +1277,152 @@ data: fates_prt_nitr_stoich_p1 = 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, 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, 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, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047 ; fates_prt_nitr_stoich_p2 = 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, 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, 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, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047 ; fates_prt_phos_stoich_p1 = - 0.0033, 0.0029, 0.004, 0.0033, 0.004, 0.004, 0.0033, 0.004, 0.004, 0.004, + 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, 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, 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, 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, 0.00047 ; fates_prt_phos_stoich_p2 = - 0.0033, 0.0029, 0.004, 0.0033, 0.004, 0.004, 0.0033, 0.004, 0.004, 0.004, + 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, 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, 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, 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, 0.00047 ; - fates_recruit_hgt_min = 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 0.75, 0.75, 0.75, + fates_recruit_hgt_min = 2.3, 1.3, 1.3, 1.3, 1.3, 1.3, 0.75, 0.75, 0.75, 0.125, 0.125, 0.125 ; - fates_recruit_initd = 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, + fates_recruit_initd = 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_rholnir = 0.45, 0.35, 0.35, 0.45, 0.45, 0.45, 0.35, 0.45, 0.45, 0.35, + fates_rholnir = 0.45, 0.35, 0.35, 0.45, 0.45, 0.45, 0.35, 0.45, 0.45, 0.35, 0.35, 0.35 ; fates_rholvis = 0.1, 0.07, 0.07, 0.1, 0.1, 0.1, 0.07, 0.1, 0.1, 0.1, 0.1, 0.1 ; - fates_rhosnir = 0.39, 0.39, 0.39, 0.39, 0.39, 0.39, 0.39, 0.39, 0.39, 0.53, + fates_rhosnir = 0.39, 0.39, 0.39, 0.39, 0.39, 0.39, 0.39, 0.39, 0.39, 0.53, 0.53, 0.53 ; - fates_rhosvis = 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.31, + fates_rhosvis = 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.31, 0.31, 0.31 ; fates_root_long = 1, 2, 1, 1.5, 1, 1, 1.5, 1, 1, 1, 1, 1 ; fates_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_repro_alloc_a = 0.0058, 0.0058, 0.0058, 0.0058, 0.0058, 0.0058, 0.0058, + 0.0058, 0.0058, 0.0058, 0.0058, 0.0058 ; + + fates_repro_alloc_b = -3.138, -3.138, -3.138, -3.138, + -3.138, -3.138, -3.138, -3.138, -3.138, -3.138, -3.138, -3.138 ; + + fates_repro_frac_seed = 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_a_emerg = 0.0006, 0.0006, 0.0006, 0.0006, + 0.0006, 0.0006, 0.0006, 0.0006, 0.0006, 0.0006, 0.0006, 0.0006 ; + + fates_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_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_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_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_seedling_mdd_crit = 1400000.0, 1400000.0, 1400000.0, 1400000.0, 1400000.0, + 1400000.0, 1400000.0, 1400000.0, 1400000.0, 1400000.0, 1400000.0, 1400000.0 ; + + fates_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_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_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_seedling_light_mort_a = -0.0099, -0.0099, -0.0099, -0.0099, -0.0099, -0.0099, -0.0099, + -0.0099, -0.0099, -0.0099, -0.0099, -0.0099 ; + + fates_seedling_light_mort_b = -7.148243, -7.148243, -7.148243, -7.148243, -7.148243, -7.148243, + -7.148243, -7.148243, -7.148243, -7.148243, -7.148243, -7.148243 ; + + fates_background_seedling_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_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_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_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_seed_alloc_mature = 0, 0, 0, 0, 0, 0, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9 ; - fates_seed_dbh_repro_threshold = 150, 90, 90, 90, 90, 90, 3, 3, 2, 1.47, + fates_seed_dbh_repro_threshold = 150, 90, 90, 90, 90, 90, 3, 3, 2, 1.47, 1.47, 1.47 ; - fates_seed_decay_rate = 0.51, 0.51, 0.51, 0.51, 0.51, 0.51, 0.51, 0.51, + fates_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_seed_germination_rate = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + fates_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_seed_suppl = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; fates_senleaf_long_fdrought = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; - fates_smpsc = -255000, -255000, -255000, -255000, -255000, -255000, -255000, + fates_smpsc = -255000, -255000, -255000, -255000, -255000, -255000, -255000, -255000, -255000, -255000, -255000, -255000 ; - fates_smpso = -66000, -66000, -66000, -66000, -66000, -66000, -66000, + fates_smpso = -66000, -66000, -66000, -66000, -66000, -66000, -66000, -66000, -66000, -66000, -66000, -66000 ; - fates_taulnir = 0.25, 0.1, 0.1, 0.25, 0.25, 0.25, 0.1, 0.25, 0.25, 0.34, + fates_taulnir = 0.25, 0.1, 0.1, 0.25, 0.25, 0.25, 0.1, 0.25, 0.25, 0.34, 0.34, 0.34 ; - fates_taulvis = 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, + fates_taulvis = 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05 ; - fates_tausnir = 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, + fates_tausnir = 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_tausvis = 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, + fates_tausvis = 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_trim_inc = 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, + 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 ; @@ -1323,29 +1447,29 @@ data: fates_turnover_retrans_mode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; - fates_wood_density = 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, + fates_wood_density = 0.7, 0.7, 0.7, 0.7, 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_z0mr = 0.055, 0.055, 0.055, 0.055, 0.055, 0.055, 0.055, 0.055, 0.055, + fates_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_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 ; + 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 ; @@ -1425,6 +1549,8 @@ data: fates_leaf_stomatal_model = 1 ; + fates_regeneration_model = 2 ; + fates_logging_coll_under_frac = 0.55983 ; fates_logging_collateral_frac = 0.05 ; @@ -1471,6 +1597,14 @@ data: fates_photo_temp_acclim_timescale = 30 ; + fates_sdlng_emerg_h2o_timescale = 14 ; + + fates_sdlng_mort_par_timescale = 64 ; + + fates_sdlng_mdd_timescale = 126 ; + + fates_sdlng2sap_par_timescale = 64 ; + fates_photo_tempsens_model = 1 ; fates_q10_froz = 1.5 ; From 49a4d4ecebd2a18a59059597fcc4fc93ccfd59d7 Mon Sep 17 00:00:00 2001 From: adamhb Date: Wed, 12 Jan 2022 13:14:37 -0800 Subject: [PATCH 48/81] updated the fates-trs default param file --- parameter_files/fates_params_default.cdl | 32 ++++++------ .../patch_TRS_bciopt_1_12_2022.xml | 52 +++++++++++++++++++ 2 files changed, 69 insertions(+), 15 deletions(-) create mode 100644 parameter_files/patch_TRS_bciopt_1_12_2022.xml diff --git a/parameter_files/fates_params_default.cdl b/parameter_files/fates_params_default.cdl index 89d89cdf2a..a8a614cf36 100644 --- a/parameter_files/fates_params_default.cdl +++ b/parameter_files/fates_params_default.cdl @@ -1313,7 +1313,7 @@ data: 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_recruit_hgt_min = 2.3, 1.3, 1.3, 1.3, 1.3, 1.3, 0.75, 0.75, 0.75, + fates_recruit_hgt_min = 2.345, 2.345, 2.345, 2.345, 2.345, 2.345, 0.75, 0.75, 0.75, 0.125, 0.125, 0.125 ; fates_recruit_initd = 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, @@ -1334,16 +1334,17 @@ data: fates_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_repro_alloc_a = 0.0058, 0.0058, 0.0058, 0.0058, 0.0058, 0.0058, 0.0058, - 0.0058, 0.0058, 0.0058, 0.0058, 0.0058 ; + fates_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_repro_alloc_b = -3.138, -3.138, -3.138, -3.138, - -3.138, -3.138, -3.138, -3.138, -3.138, -3.138, -3.138, -3.138 ; + fates_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_repro_frac_seed = 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_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_a_emerg = 0.0006, 0.0006, 0.0006, 0.0006, - 0.0006, 0.0006, 0.0006, 0.0006, 0.0006, 0.0006, 0.0006, 0.0006 ; + fates_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_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 ; @@ -1371,11 +1372,12 @@ data: 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_seedling_light_mort_a = -0.0099, -0.0099, -0.0099, -0.0099, -0.0099, -0.0099, -0.0099, - -0.0099, -0.0099, -0.0099, -0.0099, -0.0099 ; + fates_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_seedling_light_mort_b = -7.148243, -7.148243, -7.148243, -7.148243, -7.148243, -7.148243, - -7.148243, -7.148243, -7.148243, -7.148243, -7.148243, -7.148243 ; + fates_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_background_seedling_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 ; @@ -1597,13 +1599,13 @@ data: fates_photo_temp_acclim_timescale = 30 ; - fates_sdlng_emerg_h2o_timescale = 14 ; + fates_sdlng_emerg_h2o_timescale = 7 ; - fates_sdlng_mort_par_timescale = 64 ; + fates_sdlng_mort_par_timescale = 32 ; fates_sdlng_mdd_timescale = 126 ; - fates_sdlng2sap_par_timescale = 64 ; + fates_sdlng2sap_par_timescale = 32 ; fates_photo_tempsens_model = 1 ; diff --git a/parameter_files/patch_TRS_bciopt_1_12_2022.xml b/parameter_files/patch_TRS_bciopt_1_12_2022.xml new file mode 100644 index 0000000000..4e135f9d5b --- /dev/null +++ b/parameter_files/patch_TRS_bciopt_1_12_2022.xml @@ -0,0 +1,52 @@ + + + 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_TRS_bci_opt224_vmn6phi_011222.cdl + 1 + + 0 + 0 + 1,1,3,4 + 0.03347526,0.024,1e-08,0.0047 + 0.03347526,0.024,1e-08,0.0047 + 0.025,0,0,0 + 0.45,0.25,0,0 + 0.8012471 + 30.94711 + 0.0673 + 0.976 + -9 + -9 + 3 + 0.1266844 + 1.281329 + -9 + 0.768654 + 0.768654 + 57.6 + 0.74 + 21.6 + 200 + 2 + 5 + 0.4863088 + 3 + 3e-06 + 3e-06 + 3e-07 + 3e-08 + 0.03991654 + 0.01995827 + 0.01303514 + 0.02955703 + 3 + 3 + 0.04680188 + 0.001 + 0.8374751 + -1 + 0.5 + 1 + + From 41c8837a1255e479a2593c917c835b117093bd80 Mon Sep 17 00:00:00 2001 From: adamhb Date: Wed, 12 Jan 2022 16:11:06 -0800 Subject: [PATCH 49/81] =?UTF-8?q?added=20diagnostic=20print=20statements?= =?UTF-8?q?=20to=20write=20to=20fates=20log=20and=20the=20following=20hist?= =?UTF-8?q?ory=20vars:=20FATES=5FSEED=5FBANK=5FTRS','FATES=5FSEEDLING=5FPO?= =?UTF-8?q?OL=5FTRS=E2=80=99,=E2=80=99FATES=5FSEEDS=5FIN=5FLOCAL'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- biogeochem/EDPhysiologyMod.F90 | 62 +++++++++++++++++++++++++++---- main/FatesHistoryInterfaceMod.F90 | 51 ++++++++++++++++++++++--- parteh/PRTAllometricCarbonMod.F90 | 18 +++++++++ 3 files changed, 119 insertions(+), 12 deletions(-) diff --git a/biogeochem/EDPhysiologyMod.F90 b/biogeochem/EDPhysiologyMod.F90 index 04a9f416b4..494e352840 100644 --- a/biogeochem/EDPhysiologyMod.F90 +++ b/biogeochem/EDPhysiologyMod.F90 @@ -132,10 +132,11 @@ module EDPhysiologyMod public :: SeedIn logical, parameter :: debug = .false. ! local debug flag + logical, parameter :: debug_trs = .true. ! local debug flag character(len=*), parameter, private :: sourcefile = & __FILE__ - integer, parameter :: dleafon_drycheck = 100 ! Drought deciduous leaves max days on check parameter + integer, parameter :: dleafon_drycheck = 100 ! drought deciduous leaves max days on check parameter ! ============================================================================ @@ -1837,7 +1838,20 @@ subroutine SeedDecay( litt , currentPatch, bc_in ) (litt%seed_germ(pft) * seedling_h2o_mort_rate) + & (litt%seed_germ(pft) * EDPftvarcon_inst%background_seedling_mort(pft) & * years_per_day) - + !ahb diagnostic + if (debug_trs) then + if (hlm_day_of_year == 40 .OR. hlm_day_of_year == 270) then + write(fates_log(),*) 'day_of_year:', hlm_day_of_year + write(fates_log(),*) 'patch_age:', currentPatch%age + write(fates_log(),*) 'pft', pft + write(fates_log(),*) 'seedling_light_mort_rate (day -1):', seedling_light_mort_rate + write(fates_log(),*) 'seedling_h2o_mort_rate (day -1):', seedling_h2o_mort_rate + write(fates_log(),*) 'seedling mdds ([0,1]):', seedling_mdds + end if + + end if !debug flag + !end ahb diagnostic + !----------------------------------------------------------------------- !END ahb's changes @@ -1919,7 +1933,7 @@ subroutine SeedGermination( litt, cold_stat, drought_stat, bc_in, currentPatch ) !to work with the TRS function. seedling_layer_par = currentPatch%seedling_layer_par24%GetMean() * sec_per_day * megajoules_per_joule - + !Calculate the photoblastic germination rate modifier (see eqn. 3 of Hanbury-Brown et al., 2022) photoblastic_germ_modifier = seedling_layer_par / & (seedling_layer_par + EDPftvarcon_inst%par_crit_germ(pft)) @@ -1950,7 +1964,22 @@ subroutine SeedGermination( litt, cold_stat, drought_stat, bc_in, currentPatch ) !Step 4. Calculate the amount of carbon germinating out of the seed bank litt%seed_germ_in(pft) = litt%seed(pft) * seedling_emerg_rate - + + !ahb diagnostic + if (debug_trs) then + if (hlm_day_of_year == 40 .OR. hlm_day_of_year == 270) then + write(fates_log(),*) 'day_of_year:', hlm_day_of_year + write(fates_log(),*) 'patch_age:', currentPatch%age + write(fates_log(),*) 'pft', pft + write(fates_log(),*) 'seedling_layer_par (MJ m-2 day-1):', seedling_layer_par + write(fates_log(),*) 'seedling_layer_smp (mm h2o suction):', seedling_layer_smp + write(fates_log(),*) 'photoblastic_germ_modifier ([0,1]):', photoblastic_germ_modifier + write(fates_log(),*) 'seedling_emerg_rate (day-1):', seedling_emerg_rate + end if + + end if !debug flag + !end ahb diagnostic + end if !regeneration model switch !-------------------------------------------------------------------------------------------- !TEMP @@ -2067,9 +2096,11 @@ subroutine recruitment( currentSite, currentPatch, bc_in ) call h2d_allom(temp_cohort%hite,ft,temp_cohort%dbh) !ahb diagnostic - if (hlm_day_of_year == 40) then + if (debug_trs) then + if (hlm_day_of_year == 40 .OR. hlm_day_of_year == 270) then write(fates_log(),*) 'min_dbh:', temp_cohort%dbh - end if + end if !day condition + end if !debug condition !end ahb diagnostic @@ -2193,7 +2224,24 @@ subroutine recruitment( currentSite, currentPatch, bc_in ) mass_avail = currentPatch%area * currentPatch%litter(el)%seed_germ(ft) * & EDPftvarcon_inst%seedling_light_rec_a(ft) * & sdlng2sap_par**EDPftvarcon_inst%seedling_light_rec_b(ft) - + + + !ahb diagnostic + if (debug_trs) then + if (hlm_day_of_year == 40 .OR. hlm_day_of_year == 270) then + write(fates_log(),*) 'day_of_year:', hlm_day_of_year + write(fates_log(),*) 'patch_age:', currentPatch%age + write(fates_log(),*) 'pft', ft + write(fates_log(),*) 'sdlng2sap_par (MJ m-2 day-1):', sdlng2sap_par + write(fates_log(),*) 'seedling_2_sapling_transition_rate (day -1):', & + EDPftvarcon_inst%seedling_light_rec_a(ft) * & + sdlng2sap_par**EDPftvarcon_inst%seedling_light_rec_b(ft) + end if + end if !debug flag + !end ahb diagnostic + + + !If soil moisture is below the moisture stress threshold recruitment does not occur ilayer_seedling_root = minloc(abs(bc_in%z_sisl(:)-EDPftvarcon_inst%seedling_root_depth(ft)),dim=1) diff --git a/main/FatesHistoryInterfaceMod.F90 b/main/FatesHistoryInterfaceMod.F90 index 20918251d2..dc8da2a166 100644 --- a/main/FatesHistoryInterfaceMod.F90 +++ b/main/FatesHistoryInterfaceMod.F90 @@ -194,11 +194,14 @@ module FatesHistoryInterfaceMod integer :: ih_cwd_elcwd - integer :: ih_litter_in_si ! carbon only - integer :: ih_litter_out_si ! carbon only - integer :: ih_seed_bank_si ! carbon only - integer :: ih_seeds_in_si ! carbon only - + integer :: ih_litter_in_si ! carbon only + integer :: ih_litter_out_si ! carbon only + integer :: ih_seed_bank_si ! carbon only + integer :: ih_seeds_in_si ! carbon only + integer :: ih_seeds_in_local_si ! carbon only + integer :: ih_seed_bank_trs_si ! carbon only + integer :: ih_seedling_pool_trs_si ! carbon only + integer :: ih_litter_in_elem integer :: ih_litter_out_elem integer :: ih_seed_bank_elem @@ -1863,7 +1866,10 @@ subroutine update_history_dyn(this,nc,nsites,sites) hio_litter_in_si => this%hvars(ih_litter_in_si)%r81d, & hio_litter_out_si => this%hvars(ih_litter_out_si)%r81d, & hio_seed_bank_si => this%hvars(ih_seed_bank_si)%r81d, & + hio_seed_bank_trs_si => this%hvars(ih_seed_bank_trs_si)%r81d, & + hio_seedling_pool_trs_si => this%hvars(ih_seedling_pool_trs_si)%r81d, & hio_seeds_in_si => this%hvars(ih_seeds_in_si)%r81d, & + hio_seeds_in_local_si => this%hvars(ih_seeds_in_local_si)%r81d, & hio_litter_in_elem => this%hvars(ih_litter_in_elem)%r82d, & hio_litter_out_elem => this%hvars(ih_litter_out_elem)%r82d, & hio_seed_bank_elem => this%hvars(ih_seed_bank_elem)%r82d, & @@ -3107,7 +3113,10 @@ subroutine update_history_dyn(this,nc,nsites,sites) hio_litter_out_si(io_si) = 0._r8 hio_seed_bank_si(io_si) = 0._r8 + hio_seed_bank_trs_si(io_si) = 0._r8 + hio_seedling_pool_trs_si(io_si) = 0._r8 hio_seeds_in_si(io_si) = 0._r8 + hio_seeds_in_local_si(io_si) = 0._r8 cpatch => sites(s)%oldest_patch do while(associated(cpatch)) @@ -3128,11 +3137,25 @@ subroutine update_history_dyn(this,nc,nsites,sites) hio_seed_bank_si(io_si) = hio_seed_bank_si(io_si) + & (sum(litt%seed(:))+sum(litt%seed_germ(:))) * & area_frac * days_per_sec + + ! Sum up total seed bank (just ungerminated) + hio_seed_bank_trs_si(io_si) = hio_seed_bank_trs_si(io_si) + & + sum(litt%seed(:)) * area_frac + + ! Sum up total seedling pool + hio_seedling_pool_trs_si(io_si) = hio_seedling_pool_trs_si(io_si) + & + sum(litt%seed_germ(:)) * area_frac ! Sum up the input flux into the seed bank (local and external) hio_seeds_in_si(io_si) = hio_seeds_in_si(io_si) + & (sum(litt%seed_in_local(:)) + sum(litt%seed_in_extern(:))) * & area_frac * days_per_sec + + hio_seeds_in_si(io_si) = hio_seeds_in_si(io_si) + & + sum(litt%seed_in_local(:)) * & + area_frac * days_per_sec + + cpatch => cpatch%younger end do @@ -4785,6 +4808,18 @@ subroutine define_history_vars(this, initialize_variables) use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=1, ivar=ivar, initialize=initialize_variables, & index = ih_seed_bank_si) + + call this%set_history_var(vname='FATES_SEED_BANK_TRS', units='kg m-2', & + long='total seed mass of all PFTs in kg carbon per m2 land area', & + use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & + upfreq=1, ivar=ivar, initialize=initialize_variables, & + index = ih_seed_bank_trs_si) + + call this%set_history_var(vname='FATES_SEEDLING_POOL_TRS', units='kg m-2', & + long='total seed mass of all PFTs in kg carbon per m2 land area', & + use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & + upfreq=1, ivar=ivar, initialize=initialize_variables, & + index = ih_seedling_pool_trs_si) call this%set_history_var(vname='FATES_SEEDS_IN', units='kg m-2 s-1', & long='seed production rate in kg carbon per m2 second', & @@ -4792,6 +4827,12 @@ subroutine define_history_vars(this, initialize_variables) upfreq=1, ivar=ivar, initialize=initialize_variables, & index = ih_seeds_in_si) + call this%set_history_var(vname='FATES_SEEDS_IN_LOCAL', units='kg m-2 s-1', & + long='local seed production rate in kg carbon per m2 second', & + use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & + upfreq=1, ivar=ivar, initialize=initialize_variables, & + index = ih_seeds_in_local_si) + call this%set_history_var(vname='FATES_LITTER_IN_EL', units='kg m-2 s-1', & long='litter flux in in kg element per m2 per second', & use_default='active', avgflag='A', vtype=site_elem_r8, & diff --git a/parteh/PRTAllometricCarbonMod.F90 b/parteh/PRTAllometricCarbonMod.F90 index 904342520e..8cbc30494b 100644 --- a/parteh/PRTAllometricCarbonMod.F90 +++ b/parteh/PRTAllometricCarbonMod.F90 @@ -52,6 +52,8 @@ module PRTAllometricCarbonMod use FatesConstantsMod , only : nearzero use FatesConstantsMod , only : itrue use FatesConstantsMod , only : years_per_day + use FatesInterfaceTypesMod, only : hlm_day_of_year + use PRTParametersMod , only : prt_params use EDParamsMod , only : regeneration_model @@ -72,6 +74,7 @@ module PRTAllometricCarbonMod integer, parameter :: repro_c_id = 5 ! Unique object index for reproductive carbon integer, parameter :: struct_c_id = 6 ! Unique object index for structural carbon integer, parameter :: num_vars = 6 ! THIS MUST MATCH THE LARGEST INDEX ABOVE + logical, parameter :: debug_trs = .true. ! local debug flag ! For this hypothesis, we integrate dbh along with the other 6. Since this @@ -977,6 +980,21 @@ function AllomCGrowthDeriv(c_pools,c_mask,cbalance,intgr_params) result(dCdx) (exp(prt_params%repro_alloc_b(ipft) + prt_params%repro_alloc_a(ipft)*dbh*mm_per_cm) / & (1 + exp(prt_params%repro_alloc_b(ipft) + prt_params%repro_alloc_a(ipft)*dbh*mm_per_cm))) + + !ahb diagnostic + if (debug_trs) then + if (hlm_day_of_year == 40 .OR. hlm_day_of_year == 270) then + + write(fates_log(),*) 'day_of_year:', hlm_day_of_year + write(fates_log(),*) 'pft:', ipft + write(fates_log(),*) 'dbh (cm):', dbh + write(fates_log(),*) 'repro_fraction:', repro_fraction + + end if !day condition + end if !debug condition + !end ahb diagnostic + + end if !regeneration model switch !END ahb's changes From 96758c40d8b8f6e6c88d19d9eab3afe9206a12d4 Mon Sep 17 00:00:00 2001 From: adamhb Date: Thu, 13 Jan 2022 15:23:18 -0800 Subject: [PATCH 50/81] fixed typos in the FatesHistoryInterfaceMod; fates-trs is working well! Its predictions of recruitment are in line with observations at BCI and the offline-trs --- main/FatesHistoryInterfaceMod.F90 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/main/FatesHistoryInterfaceMod.F90 b/main/FatesHistoryInterfaceMod.F90 index dc8da2a166..61cb0ed86e 100644 --- a/main/FatesHistoryInterfaceMod.F90 +++ b/main/FatesHistoryInterfaceMod.F90 @@ -3151,7 +3151,7 @@ subroutine update_history_dyn(this,nc,nsites,sites) (sum(litt%seed_in_local(:)) + sum(litt%seed_in_extern(:))) * & area_frac * days_per_sec - hio_seeds_in_si(io_si) = hio_seeds_in_si(io_si) + & + hio_seeds_in_local_si(io_si) = hio_seeds_in_local_si(io_si) + & sum(litt%seed_in_local(:)) * & area_frac * days_per_sec @@ -4533,7 +4533,7 @@ subroutine define_history_vars(this, initialize_variables) upfreq=1, ivar=ivar, initialize=initialize_variables, & index=ih_gpp_si_pft) - call this%set_history_var(vname='FATES_NPP_PF', units='kg m-2 yr-1', & + call this%set_history_var(vname='FATES_NPP_PF', units='kg m-2 s-1', & long='total PFT-level NPP in kg carbon per m2 land area per second', & use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & upfreq=1, ivar=ivar, initialize=initialize_variables, & @@ -4816,7 +4816,7 @@ subroutine define_history_vars(this, initialize_variables) index = ih_seed_bank_trs_si) call this%set_history_var(vname='FATES_SEEDLING_POOL_TRS', units='kg m-2', & - long='total seed mass of all PFTs in kg carbon per m2 land area', & + long='total seedling mass of all PFTs in kg carbon per m2 land area', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=1, ivar=ivar, initialize=initialize_variables, & index = ih_seedling_pool_trs_si) From 97ad792be8ee2b984fd0a9a90fb09b15b7f0cab2 Mon Sep 17 00:00:00 2001 From: adamhb Date: Thu, 21 Jul 2022 15:00:34 -0700 Subject: [PATCH 51/81] fixed retrieve spelling --- main/EDParamsMod.F90 | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/main/EDParamsMod.F90 b/main/EDParamsMod.F90 index 1f69977e34..fb07c4a87a 100644 --- a/main/EDParamsMod.F90 +++ b/main/EDParamsMod.F90 @@ -467,7 +467,8 @@ subroutine FatesRegisterParams(fates_params) dimension_names=dim_names_scalar) call fates_params%RegisterParameter(name=ED_name_regeneration_model, dimension_shape=dimension_shape_scalar, & - + dimension_names=dim_names_scalar) + call fates_params%RegisterParameter(name=stomatal_assim_name, dimension_shape=dimension_shape_scalar, & dimension_names=dim_names_scalar) @@ -590,16 +591,16 @@ subroutine FatesReceiveParams(fates_params) call fates_params%RetrieveParameter(name=ED_name_photo_temp_acclim_timescale, & data=photo_temp_acclim_timescale) - call fates_params%RetreiveParameter(name=ED_name_sdlng_emerg_h2o_timescale, & + call fates_params%RetrieveParameter(name=ED_name_sdlng_emerg_h2o_timescale, & data=sdlng_emerg_h2o_timescale) - call fates_params%RetreiveParameter(name=ED_name_sdlng_mort_par_timescale, & + call fates_params%RetrieveParameter(name=ED_name_sdlng_mort_par_timescale, & data=sdlng_mort_par_timescale) - call fates_params%RetreiveParameter(name=ED_name_sdlng_mdd_timescale, & + call fates_params%RetrieveParameter(name=ED_name_sdlng_mdd_timescale, & data=sdlng_mdd_timescale) - call fates_params%RetreiveParameter(name=ED_name_sdlng2sap_par_timescale, & + call fates_params%RetrieveParameter(name=ED_name_sdlng2sap_par_timescale, & data=sdlng2sap_par_timescale) call fates_params%RetrieveParameter(name=name_photo_tempsens_model, & From 21a7927237d47f6244244727068c74c75365dc63 Mon Sep 17 00:00:00 2001 From: adamhb Date: Thu, 21 Jul 2022 20:43:56 -0700 Subject: [PATCH 52/81] fixed retrieve spelling in params mod --- main/EDParamsMod.F90 | 2 +- main/EDPftvarcon.F90 | 32 ++++++++++++++++---------------- parteh/PRTParamsFATESMod.F90 | 4 ++-- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/main/EDParamsMod.F90 b/main/EDParamsMod.F90 index fb07c4a87a..2e56062d91 100644 --- a/main/EDParamsMod.F90 +++ b/main/EDParamsMod.F90 @@ -681,7 +681,7 @@ subroutine FatesReceiveParams(fates_params) data=tmpreal) stomatal_model = nint(tmpreal) - call fates_params%RetreiveParameter(name=ED_name_regeneration_model, & + call fates_params%RetrieveParameter(name=ED_name_regeneration_model, & data=tmpreal) regeneration_model = nint(tmpreal) diff --git a/main/EDPftvarcon.F90 b/main/EDPftvarcon.F90 index 04df78b1ea..4b5cc5ac57 100644 --- a/main/EDPftvarcon.F90 +++ b/main/EDPftvarcon.F90 @@ -959,67 +959,67 @@ subroutine Receive_PFT(this, fates_params) data=this%germination_rate) name = 'fates_repro_frac_seed' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=this%repro_frac_seed) name = 'fates_a_emerg' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=this%a_emerg) name = 'fates_b_emerg' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=this%b_emerg) name = 'fates_par_crit_germ' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=this%par_crit_germ) name = 'fates_seedling_psi_emerg' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=this%seedling_psi_emerg) name = 'fates_seedling_psi_crit' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=this%seedling_psi_crit) name = 'fates_seedling_light_rec_a' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=this%seedling_light_rec_a) name = 'fates_seedling_light_rec_b' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=this%seedling_light_rec_b) name = 'fates_seedling_mdd_crit' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=this%seedling_mdd_crit) name = 'fates_seedling_h2o_mort_a' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=this%seedling_h2o_mort_a) name = 'fates_seedling_h2o_mort_b' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=this%seedling_h2o_mort_b) name = 'fates_seedling_h2o_mort_c' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=this%seedling_h2o_mort_c) name = 'fates_seedling_root_depth' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=this%seedling_root_depth) name = 'fates_seedling_light_mort_a' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=this%seedling_light_mort_a) name = 'fates_seedling_light_mort_b' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=this%seedling_light_mort_b) name = 'fates_background_seedling_mort' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=this%background_seedling_mort) name = 'fates_frag_seed_decay_rate' diff --git a/parteh/PRTParamsFATESMod.F90 b/parteh/PRTParamsFATESMod.F90 index 7591006b73..473b833399 100644 --- a/parteh/PRTParamsFATESMod.F90 +++ b/parteh/PRTParamsFATESMod.F90 @@ -487,11 +487,11 @@ subroutine PRTReceivePFT(fates_params) !ahb added the code below !-------------------------------------------------------- name = 'fates_repro_alloc_a' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%repro_alloc_a) name = 'fates_repro_alloc_b' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%repro_alloc_b) !--------------------------------------------------------- From 166ba8a2f3ce9c6b866f41ee679f0db291a7bb53 Mon Sep 17 00:00:00 2001 From: Adam Hanbury-Brown Date: Fri, 7 Apr 2023 14:10:01 -0600 Subject: [PATCH 53/81] fixed bugs related to the merge with fates main api 25 --- biogeochem/EDPatchDynamicsMod.F90 | 8 +++++--- main/EDTypesMod.F90 | 2 -- main/FatesRestartInterfaceMod.F90 | 1 - main/FatesRunningMeanMod.F90 | 16 ++++++---------- parteh/PRTAllometricCarbonMod.F90 | 2 +- 5 files changed, 12 insertions(+), 17 deletions(-) diff --git a/biogeochem/EDPatchDynamicsMod.F90 b/biogeochem/EDPatchDynamicsMod.F90 index d75a1faece..f1194ee084 100644 --- a/biogeochem/EDPatchDynamicsMod.F90 +++ b/biogeochem/EDPatchDynamicsMod.F90 @@ -3115,14 +3115,17 @@ subroutine dealloc_patch(cpatch) deallocate(cpatch%seedling_layer_par24) deallocate(cpatch%sdlng_mort_par) deallocate(cpatch%sdlng2sap_par) - deallocate(cpatch%sdlng_mdd) - deallocate(cpatch%sdlng_emerg_smp) do pft = 1, maxpft deallocate(cpatch%sdlng_mdd(pft)%p) deallocate(cpatch%sdlng_emerg_smp(pft)%p) enddo + + deallocate(cpatch%sdlng_mdd) + deallocate(cpatch%sdlng_emerg_smp) + + deallocate(cpatch%tveg24, stat=istat, errmsg=smsg) if (istat/=0) then write(fates_log(),*) 'dealloc010: fail on deallocate(cpatch%tveg24):'//trim(smsg) @@ -3138,7 +3141,6 @@ subroutine dealloc_patch(cpatch) write(fates_log(),*) 'dealloc012: fail on deallocate(cpatch%tveg_longterm):'//trim(smsg) call endrun(msg=errMsg(sourcefile, __LINE__)) endif - return end subroutine dealloc_patch diff --git a/main/EDTypesMod.F90 b/main/EDTypesMod.F90 index 4281ebfe18..2d38bd635f 100644 --- a/main/EDTypesMod.F90 +++ b/main/EDTypesMod.F90 @@ -471,8 +471,6 @@ module EDTypesMod ! to sapling transition timescale ! (sdlng2sap_par_timescale) - integer :: nocomp_pft_label ! where nocomp is active, use this label for patch ID. - ! LEAF ORGANIZATION real(r8) :: pft_agb_profile(maxpft,n_dbh_bins) ! binned above ground biomass, for patch fusion: KgC/m2 real(r8) :: canopy_layer_tlai(nclmax) ! total leaf area index of each canopy layer diff --git a/main/FatesRestartInterfaceMod.F90 b/main/FatesRestartInterfaceMod.F90 index e682e6d24e..96b4ad3ab4 100644 --- a/main/FatesRestartInterfaceMod.F90 +++ b/main/FatesRestartInterfaceMod.F90 @@ -1405,7 +1405,6 @@ subroutine define_restart_vars(this, initialize_variables) long_name='fates area lost from damage each year', & units='m2/ha/year', flushval = flushzero, & hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_crownarea_usto_si) ->>>>>>> main call this%DefineRMeanRestartVar(vname='fates_tveg24patch',vtype=cohort_r8, & long_name='24-hour patch veg temp', & diff --git a/main/FatesRunningMeanMod.F90 b/main/FatesRunningMeanMod.F90 index 6ab59a43f0..7ef7866d62 100644 --- a/main/FatesRunningMeanMod.F90 +++ b/main/FatesRunningMeanMod.F90 @@ -79,12 +79,6 @@ module FatesRunningMeanMod end type rmean_type - - type, public :: rmean_arr_type - class(rmean_type), pointer :: p - end type rmean_arr_type - - logical, parameter :: debug = .true. character(len=*), parameter, private :: sourcefile = & @@ -100,18 +94,20 @@ module FatesRunningMeanMod class(rmean_def_type), public, pointer :: ema_60day ! Exponential moving average, 60 day ! Updated daily class(rmean_def_type), public, pointer :: ema_storemem ! EMA used for smoothing N/C and P/C storage - class(rmean_def_type), public, pointer :: ema_sdlng_emerg_h2o ! EMA for moisture-based seedling emergence class(rmean_def_type), public, pointer :: ema_sdlng_mort_par ! EMA for seedling mort from light stress - class(rmean_def_type), public, pointer :: ema_sdlng_mdd ! EMA for seedling moisture deficit days class(rmean_def_type), public, pointer :: ema_sdlng2sap_par ! EMA for seedling to sapling transition rates ! based in par - + class(rmean_def_type), public, pointer :: ema_sdlng_emerg_h2o ! EMA for moisture-based seedling emergence + class(rmean_def_type), public, pointer :: ema_sdlng_mdd ! EMA for seedling moisture deficit days + + ! If we want to have different running mean specs based on ! pft or other types of constants type, public :: rmean_arr_type - class(rmean_def_type), pointer :: p + class(rmean_type), pointer :: p end type rmean_arr_type + contains diff --git a/parteh/PRTAllometricCarbonMod.F90 b/parteh/PRTAllometricCarbonMod.F90 index 153c3857ba..d51cedbd2d 100644 --- a/parteh/PRTAllometricCarbonMod.F90 +++ b/parteh/PRTAllometricCarbonMod.F90 @@ -974,8 +974,8 @@ function AllomCGrowthDeriv(c_pools,c_mask,cbalance,intgr_params) result(dCdx) call bbgw_allom(dbh,ipft,ct_bgw, ct_dbgwdd) call bdead_allom(ct_agw,ct_bgw, ct_sap, ipft, ct_dead, & ct_dagwdd, ct_dbgwdd, ct_dsapdd, ct_ddeaddd) - call bstore_allom(dbh,ipft,canopy_trim,ct_store,ct_dstoredd) call bstore_allom(dbh,ipft,crowndamage, canopy_trim,ct_store,ct_dstoredd) + ! fraction of carbon going towards reproduction !START ahb's changes From b0fdcb4a5d0da04f48d2b11dfe2c7d3b97f206e4 Mon Sep 17 00:00:00 2001 From: Adam Hanbury-Brown Date: Fri, 7 Apr 2023 17:16:22 -0600 Subject: [PATCH 54/81] adding regeneration switch --- biogeochem/EDPhysiologyMod.F90 | 4 ++-- main/FatesConstantsMod.F90 | 2 ++ parameter_files/fates_params_default.cdl | 4 ++-- parteh/PRTAllometricCarbonMod.F90 | 18 +++++++++--------- 4 files changed, 15 insertions(+), 13 deletions(-) diff --git a/biogeochem/EDPhysiologyMod.F90 b/biogeochem/EDPhysiologyMod.F90 index 60097d4075..7536860599 100644 --- a/biogeochem/EDPhysiologyMod.F90 +++ b/biogeochem/EDPhysiologyMod.F90 @@ -1861,7 +1861,7 @@ subroutine SeedIn( currentSite, bc_in ) litt%seed_in_local(pft) = litt%seed_in_local(pft) + site_seed_rain(pft)/area !START ahb's changes - if ( regeneration_model == TRS .and. & + if ( regeneration_model >= TRS .and. & prt_params%allom_dbh_maxheight(pft) > min_max_dbh_for_trees) then !Send a fraction of reproductive carbon to litter to account for @@ -1957,7 +1957,7 @@ subroutine SeedDecay( litt , currentPatch, bc_in ) EDPftvarcon_inst%seed_decay_rate(pft)*years_per_day !If the TRS is switched on and the pft is a tree then use the TRS - else if ( regeneration_model == TRS .and. & + else if ( regeneration_model >= TRS .and. & prt_params%allom_dbh_maxheight(pft) > min_max_dbh_for_trees ) then !---------------------------------------------------------------------- diff --git a/main/FatesConstantsMod.F90 b/main/FatesConstantsMod.F90 index 6790845c3e..e324414eca 100644 --- a/main/FatesConstantsMod.F90 +++ b/main/FatesConstantsMod.F90 @@ -50,6 +50,8 @@ module FatesConstantsMod integer, public, parameter :: coupled_np_comp_scaling = 1 ! This flag signals that at least 1 chemical element (ie N or P) !Flags specifying how tree regeneration works + + integer, public, parameter :: TRS_no_seedling_dyn = 3 !Constant defining the Tree Recruitment Scheme switch integer, public, parameter :: TRS = 2 !Constant defining the Tree Recruitment Scheme switch integer, public, parameter :: default_regeneration = 1 !Constant defining FATES's default regeneration scheme switch real(fates_r8), public, parameter :: min_max_dbh_for_trees = 15._fates_r8 !cm; if pfts have a max dbh less diff --git a/parameter_files/fates_params_default.cdl b/parameter_files/fates_params_default.cdl index 501095d9c9..8aa3c65217 100644 --- a/parameter_files/fates_params_default.cdl +++ b/parameter_files/fates_params_default.cdl @@ -775,7 +775,7 @@ variables: fates_leaf_stomatal_model:long_name = "switch for choosing between Ball-Berry (1) stomatal conductance model and Medlyn (2) model" ; double fates_regeneration_model ; fates_regeneration_model:units = "unitless" ; - fates_regeneration_model:long_name = "switch for choosing between FATES's default regeneration scheme (1) or the Tree Recruitment Scheme (Hanbury-Brown et al., 2022;2)" ; + fates_regeneration_model:long_name = "switch for choosing between FATES's default regeneration scheme (1), the full Tree Recruitment Scheme (2; Hanbury-Brown et al., 2022), or (3) the Tree Recruitment Scheme without seedling dynamics" ; 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" ; @@ -1603,7 +1603,7 @@ data: fates_landuse_logging_coll_under_frac = 0.55983 ; - fates_regeneration_model = 2 ; + fates_regeneration_model = 1 ; fates_landuse_logging_collateral_frac = 0.05 ; diff --git a/parteh/PRTAllometricCarbonMod.F90 b/parteh/PRTAllometricCarbonMod.F90 index d51cedbd2d..cc9b0d9af5 100644 --- a/parteh/PRTAllometricCarbonMod.F90 +++ b/parteh/PRTAllometricCarbonMod.F90 @@ -990,7 +990,7 @@ function AllomCGrowthDeriv(c_pools,c_mask,cbalance,intgr_params) result(dCdx) repro_fraction = prt_params%seed_alloc(ipft) + prt_params%seed_alloc_mature(ipft) end if - else if ( regeneration_model == TRS .and. & + else if ( regeneration_model >= TRS .and. & prt_params%allom_dbh_maxheight(ipft) > min_max_dbh_for_trees ) then !------------------------------------------------------------------------------------- @@ -1011,16 +1011,16 @@ function AllomCGrowthDeriv(c_pools,c_mask,cbalance,intgr_params) result(dCdx) !ahb diagnostic - if (debug_trs) then - if (hlm_day_of_year == 40 .OR. hlm_day_of_year == 270) then + !if (debug_trs) then + !if (hlm_day_of_year == 40 .OR. hlm_day_of_year == 270) then - write(fates_log(),*) 'day_of_year:', hlm_day_of_year - write(fates_log(),*) 'pft:', ipft - write(fates_log(),*) 'dbh (cm):', dbh - write(fates_log(),*) 'repro_fraction:', repro_fraction + ! write(fates_log(),*) 'day_of_year:', hlm_day_of_year + ! write(fates_log(),*) 'pft:', ipft + ! write(fates_log(),*) 'dbh (cm):', dbh + ! write(fates_log(),*) 'repro_fraction:', repro_fraction - end if !day condition - end if !debug condition + !end if !day condition + !end if !debug condition !end ahb diagnostic From e1f7b47c7ac4814fa74518f0f9554a7dd4a8e126 Mon Sep 17 00:00:00 2001 From: Adam Hanbury-Brown Date: Fri, 7 Apr 2023 17:31:48 -0600 Subject: [PATCH 55/81] updated regen switch in Seed Decay subroutine --- biogeochem/EDPhysiologyMod.F90 | 53 +++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/biogeochem/EDPhysiologyMod.F90 b/biogeochem/EDPhysiologyMod.F90 index 7536860599..92de75b7ce 100644 --- a/biogeochem/EDPhysiologyMod.F90 +++ b/biogeochem/EDPhysiologyMod.F90 @@ -1956,20 +1956,30 @@ subroutine SeedDecay( litt , currentPatch, bc_in ) litt%seed_decay(pft) = litt%seed(pft) * & EDPftvarcon_inst%seed_decay_rate(pft)*years_per_day - !If the TRS is switched on and the pft is a tree then use the TRS - else if ( regeneration_model >= TRS .and. & + end if !end default regeneration model + + ! If the TRS is fully switched on, or if it is switched on without seedling dynamics + ! (regeneration_model = TRS_no_seedling_dyn), + ! and the pft is a tree then make sure the non-seed reproductive biomass is added the + ! the seed decay flux. + if ( regeneration_model >= TRS .and. & prt_params%allom_dbh_maxheight(pft) > min_max_dbh_for_trees ) then !---------------------------------------------------------------------- !With respect to seed decay, the only difference with the TRS here is adding the flux !from non-seed reproductive biomass (which was sent to litt%seed_decay in the SeedIn subroutine) - litt%seed_decay(pft) = litt%seed_decay(pft) + &!from non-seed reproductive biomass; working? + litt%seed_decay(pft) = litt%seed_decay(pft) + &!from non-seed reproductive biomass. litt%seed(pft) * EDPftvarcon_inst%seed_decay_rate(pft)*years_per_day - end if !regeneration model switch + end if !Send non-seed reproductive biomass to seed decay flux. + - ! 2. Seedling mortality (i.e. fluxes from seedling pool (seed_germ) to litter) + ! If the full TRS model is switch on (regeneration_model == TRS) then calculate seedling mortality. + if ( regeneration_model == TRS .and. & + prt_params%allom_dbh_maxheight(pft) > min_max_dbh_for_trees ) then + + !Seedling mortality (i.e. fluxes from seedling pool (seed_germ) to litter) !---------------------------------------------------------------------- !Step 1. Calculate the daily seedling mortality rate from light stress @@ -1982,15 +1992,10 @@ subroutine SeedDecay( litt , currentPatch, bc_in ) seedling_light_mort_rate = exp( EDPftvarcon_inst%seedling_light_mort_a(pft) * & seedling_layer_par + EDPftvarcon_inst%seedling_light_mort_b(pft) ) - !TEMP - !write(fates_log(),*) 'seedling layer par ', seedling_layer_par - !write(fates_log(),*) 'seedling light mort rate ', seedling_light_mort_rate - !Step 3. Calculate the daily seedling mortality rate from moisture stress !Get the current seedling moisture deficit days !Calculated as (abs(seedling_psi_crit) - abs(seedling_layer_smp))* -1 * mddWindow - seedling_mdds = currentPatch%sdlng_mdd(pft)%p%GetMean() !Calculate seedling mortality as a function of moisture deficit days @@ -2000,26 +2005,28 @@ subroutine SeedDecay( litt , currentPatch, bc_in ) if (seedling_mdds < EDPftvarcon_inst%seedling_mdd_crit(pft)) then seedling_h2o_mort_rate = 0.0_r8 - end if + end if !mdd threshold check !Step 4. Add background mortality and send dead seedling carbon to litter (i.e. to seed_germ_decay flux) litt%seed_germ_decay(pft) = (litt%seed_germ(pft) * seedling_light_mort_rate) + & (litt%seed_germ(pft) * seedling_h2o_mort_rate) + & (litt%seed_germ(pft) * EDPftvarcon_inst%background_seedling_mort(pft) & * years_per_day) - !ahb diagnostic - if (debug_trs) then - if (hlm_day_of_year == 40 .OR. hlm_day_of_year == 270) then - write(fates_log(),*) 'day_of_year:', hlm_day_of_year - write(fates_log(),*) 'patch_age:', currentPatch%age - write(fates_log(),*) 'pft', pft - write(fates_log(),*) 'seedling_light_mort_rate (day -1):', seedling_light_mort_rate - write(fates_log(),*) 'seedling_h2o_mort_rate (day -1):', seedling_h2o_mort_rate - write(fates_log(),*) 'seedling mdds ([0,1]):', seedling_mdds - end if + end if !Use full TRS - end if !debug flag - !end ahb diagnostic + !ahb diagnostic + ! if (debug_trs) then + ! if (hlm_day_of_year == 40 .OR. hlm_day_of_year == 270) then + ! write(fates_log(),*) 'day_of_year:', hlm_day_of_year + ! write(fates_log(),*) 'patch_age:', currentPatch%age + ! write(fates_log(),*) 'pft', pft + ! write(fates_log(),*) 'seedling_light_mort_rate (day -1):', seedling_light_mort_rate + ! write(fates_log(),*) 'seedling_h2o_mort_rate (day -1):', seedling_h2o_mort_rate + ! write(fates_log(),*) 'seedling mdds ([0,1]):', seedling_mdds + ! end if + + ! end if !debug flag + !end ahb diagnostic !----------------------------------------------------------------------- !END ahb's changes From 3f47c3106cd03794673eeaf3f952204c49e0009b Mon Sep 17 00:00:00 2001 From: Adam Hanbury-Brown Date: Tue, 11 Apr 2023 12:27:25 -0600 Subject: [PATCH 56/81] added more organized parameter namespacing for trs parameters --- biogeochem/EDPhysiologyMod.F90 | 34 ++--- main/EDParamsMod.F90 | 8 +- main/EDPftvarcon.F90 | 64 ++++----- main/FatesConstantsMod.F90 | 8 +- parameter_files/fates_params_default.cdl | 176 +++++++++++------------ parteh/PRTParamsFATESMod.F90 | 8 +- 6 files changed, 151 insertions(+), 147 deletions(-) diff --git a/biogeochem/EDPhysiologyMod.F90 b/biogeochem/EDPhysiologyMod.F90 index 92de75b7ce..468ecda3af 100644 --- a/biogeochem/EDPhysiologyMod.F90 +++ b/biogeochem/EDPhysiologyMod.F90 @@ -24,8 +24,9 @@ module EDPhysiologyMod use FatesConstantsMod, only : r8 => fates_r8 use FatesConstantsMod, only : nearzero use FatesConstantsMod, only : sec_per_day - use FatesConstantsMod, only : TRS use FatesConstantsMod, only : default_regeneration + use FatesConstantsMod, only : TRS + use FatesConstantsMod, only : TRS_no_seedling_dyn use FatesConstantsMod, only : min_max_dbh_for_trees use FatesConstantsMod, only : megajoules_per_joule use FatesConstantsMod, only : mpa_per_mm_suction @@ -1785,8 +1786,6 @@ subroutine SeedIn( currentSite, bc_in ) integer :: n_litt_types ! number of litter element types (c,n,p, etc) integer :: el ! loop counter for litter element types integer :: element_id ! element id consistent with parteh/PRTGenericMod.F90 - integer, parameter :: TRS = 2 ! Switch option to use the Tree Recruitment Scheme - integer, parameter :: default_regeneration = 1 !Switch option to use FATES's default regeneration scheme !------------------------------------------------------------------------------------ do el = 1, num_elements @@ -2087,7 +2086,8 @@ subroutine SeedGermination( litt, cold_stat, drought_stat, bc_in, currentPatch ) !============================================================================================== do pft = 1,numpft if ( regeneration_model == default_regeneration .or. & - prt_params%allom_dbh_maxheight(pft) < min_max_dbh_for_trees ) then + regeneration_model == TRS_no_seedling_dyn .or. & + prt_params%allom_dbh_maxheight(pft) < min_max_dbh_for_trees ) then !FATES default germination scheme litt%seed_germ_in(pft) = min(litt%seed(pft) * EDPftvarcon_inst%germination_rate(pft), & @@ -2141,19 +2141,20 @@ subroutine SeedGermination( litt, cold_stat, drought_stat, bc_in, currentPatch ) !Step 4. Calculate the amount of carbon germinating out of the seed bank litt%seed_germ_in(pft) = litt%seed(pft) * seedling_emerg_rate - !ahb diagnostic - if (debug_trs) then - if (hlm_day_of_year == 40 .OR. hlm_day_of_year == 270) then - write(fates_log(),*) 'day_of_year:', hlm_day_of_year - write(fates_log(),*) 'patch_age:', currentPatch%age - write(fates_log(),*) 'pft', pft - write(fates_log(),*) 'seedling_layer_par (MJ m-2 day-1):', seedling_layer_par - write(fates_log(),*) 'seedling_layer_smp (mm h2o suction):', seedling_layer_smp - write(fates_log(),*) 'photoblastic_germ_modifier ([0,1]):', photoblastic_germ_modifier - write(fates_log(),*) 'seedling_emerg_rate (day-1):', seedling_emerg_rate - end if + ! !ahb diagnostic + ! if (debug_trs) then + ! if (hlm_day_of_year == 40 .OR. hlm_day_of_year == 270) then + ! write(fates_log(),*) 'day_of_year:', hlm_day_of_year + ! write(fates_log(),*) 'patch_age:', currentPatch%age + ! write(fates_log(),*) 'pft', pft + + ! write(fates_log(),*) 'seedling_layer_par (MJ m-2 day-1):', seedling_layer_par + ! write(fates_log(),*) 'seedling_layer_smp (mm h2o suction):', seedling_layer_smp + ! write(fates_log(),*) 'photoblastic_germ_modifier ([0,1]):', photoblastic_germ_modifier + ! write(fates_log(),*) 'seedling_emerg_rate (day-1):', seedling_emerg_rate + ! end if - end if !debug flag + ! end if !debug flag !end ahb diagnostic end if !regeneration model switch @@ -2386,6 +2387,7 @@ subroutine recruitment( currentSite, currentPatch, bc_in ) !START ahb's changes !================================================================================= if ( regeneration_model == default_regeneration .or. & + regeneration_model == TRS_no_seedling_dyn .or. & prt_params%allom_dbh_maxheight(ft) < min_max_dbh_for_trees ) then mass_avail = currentPatch%area * currentPatch%litter(el)%seed_germ(ft) diff --git a/main/EDParamsMod.F90 b/main/EDParamsMod.F90 index eddbbcaed8..23e3b62170 100644 --- a/main/EDParamsMod.F90 +++ b/main/EDParamsMod.F90 @@ -104,10 +104,10 @@ module EDParamsMod ! to be used at each node (compartment/organ) ! 1 = Christofferson et al. 2016 (TFS), 2 = Van Genuchten 1980 - character(len=param_string_length),parameter,public :: ED_name_sdlng_emerg_h2o_timescale = "fates_sdlng_emerg_h2o_timescale" - character(len=param_string_length),parameter,public :: ED_name_sdlng_mort_par_timescale = "fates_sdlng_mort_par_timescale" - character(len=param_string_length),parameter,public :: ED_name_sdlng_mdd_timescale = "fates_sdlng_mdd_timescale" - character(len=param_string_length),parameter,public :: ED_name_sdlng2sap_par_timescale = "fates_sdlng2sap_par_timescale" + character(len=param_string_length),parameter,public :: ED_name_sdlng_emerg_h2o_timescale = "fates_trs_seedling_emerg_h2o_timescale" + character(len=param_string_length),parameter,public :: ED_name_sdlng_mort_par_timescale = "fates_trs_seedling_mort_par_timescale" + character(len=param_string_length),parameter,public :: ED_name_sdlng_mdd_timescale = "fates_trs_seedling_mdd_timescale" + character(len=param_string_length),parameter,public :: ED_name_sdlng2sap_par_timescale = "fates_trs_seedling2sap_par_timescale" integer, protected,allocatable,public :: hydr_htftype_node(:) character(len=param_string_length),parameter,public :: ED_name_photo_temp_acclim_timescale = "fates_leaf_photo_temp_acclim_timescale" character(len=param_string_length),parameter,public :: ED_name_photo_temp_acclim_thome_time = "fates_leaf_photo_temp_acclim_thome_time" diff --git a/main/EDPftvarcon.F90 b/main/EDPftvarcon.F90 index 2ab3e5279c..041c80b92e 100644 --- a/main/EDPftvarcon.F90 +++ b/main/EDPftvarcon.F90 @@ -597,67 +597,67 @@ subroutine Register_PFT(this, fates_params) call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_repro_frac_seed' + name = 'fates_trs_repro_frac_seed' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_a_emerg' + name = 'fates_trs_seedling_a_emerg' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_b_emerg' + name = 'fates_trs_seedling_b_emerg' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_par_crit_germ' + name = 'fates_trs_seedling_par_crit_germ' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_seedling_psi_emerg' + name = 'fates_trs_seedling_psi_emerg' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_seedling_psi_crit' + name = 'fates_trs_seedling_psi_crit' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_seedling_light_rec_a' + name = 'fates_trs_seedling_light_rec_a' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_seedling_light_rec_b' + name = 'fates_trs_seedling_light_rec_b' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_seedling_mdd_crit' + name = 'fates_trs_seedling_mdd_crit' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_seedling_h2o_mort_a' + name = 'fates_trs_seedling_h2o_mort_a' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_seedling_h2o_mort_b' + name = 'fates_trs_seedling_h2o_mort_b' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_seedling_h2o_mort_c' + name = 'fates_trs_seedling_h2o_mort_c' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_seedling_root_depth' + name = 'fates_trs_seedling_root_depth' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_seedling_light_mort_a' + name = 'fates_trs_seedling_light_mort_a' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_seedling_light_mort_b' + name = 'fates_trs_seedling_light_mort_b' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_background_seedling_mort' + name = 'fates_trs_seedling_background_mort' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) @@ -1027,67 +1027,67 @@ subroutine Receive_PFT(this, fates_params) call fates_params%RetrieveParameterAllocate(name=name, & data=this%germination_rate) - name = 'fates_repro_frac_seed' + name = 'fates_trs_repro_frac_seed' call fates_params%RetrieveParameterAllocate(name=name, & data=this%repro_frac_seed) - name = 'fates_a_emerg' + name = 'fates_trs_seedling_a_emerg' call fates_params%RetrieveParameterAllocate(name=name, & data=this%a_emerg) - name = 'fates_b_emerg' + name = 'fates_trs_seedling_b_emerg' call fates_params%RetrieveParameterAllocate(name=name, & data=this%b_emerg) - name = 'fates_par_crit_germ' + name = 'fates_trs_seedling_par_crit_germ' call fates_params%RetrieveParameterAllocate(name=name, & data=this%par_crit_germ) - name = 'fates_seedling_psi_emerg' + name = 'fates_trs_seedling_psi_emerg' call fates_params%RetrieveParameterAllocate(name=name, & data=this%seedling_psi_emerg) - name = 'fates_seedling_psi_crit' + name = 'fates_trs_seedling_psi_crit' call fates_params%RetrieveParameterAllocate(name=name, & data=this%seedling_psi_crit) - name = 'fates_seedling_light_rec_a' + name = 'fates_trs_seedling_light_rec_a' call fates_params%RetrieveParameterAllocate(name=name, & data=this%seedling_light_rec_a) - name = 'fates_seedling_light_rec_b' + name = 'fates_trs_seedling_light_rec_b' call fates_params%RetrieveParameterAllocate(name=name, & data=this%seedling_light_rec_b) - name = 'fates_seedling_mdd_crit' + name = 'fates_trs_seedling_mdd_crit' call fates_params%RetrieveParameterAllocate(name=name, & data=this%seedling_mdd_crit) - name = 'fates_seedling_h2o_mort_a' + name = 'fates_trs_seedling_h2o_mort_a' call fates_params%RetrieveParameterAllocate(name=name, & data=this%seedling_h2o_mort_a) - name = 'fates_seedling_h2o_mort_b' + name = 'fates_trs_seedling_h2o_mort_b' call fates_params%RetrieveParameterAllocate(name=name, & data=this%seedling_h2o_mort_b) - name = 'fates_seedling_h2o_mort_c' + name = 'fates_trs_seedling_h2o_mort_c' call fates_params%RetrieveParameterAllocate(name=name, & data=this%seedling_h2o_mort_c) - name = 'fates_seedling_root_depth' + name = 'fates_trs_seedling_root_depth' call fates_params%RetrieveParameterAllocate(name=name, & data=this%seedling_root_depth) - name = 'fates_seedling_light_mort_a' + name = 'fates_trs_seedling_light_mort_a' call fates_params%RetrieveParameterAllocate(name=name, & data=this%seedling_light_mort_a) - name = 'fates_seedling_light_mort_b' + name = 'fates_trs_seedling_light_mort_b' call fates_params%RetrieveParameterAllocate(name=name, & data=this%seedling_light_mort_b) - name = 'fates_background_seedling_mort' + name = 'fates_trs_seedling_background_mort' call fates_params%RetrieveParameterAllocate(name=name, & data=this%background_seedling_mort) diff --git a/main/FatesConstantsMod.F90 b/main/FatesConstantsMod.F90 index e324414eca..ff35efef52 100644 --- a/main/FatesConstantsMod.F90 +++ b/main/FatesConstantsMod.F90 @@ -51,9 +51,11 @@ module FatesConstantsMod !Flags specifying how tree regeneration works - integer, public, parameter :: TRS_no_seedling_dyn = 3 !Constant defining the Tree Recruitment Scheme switch - integer, public, parameter :: TRS = 2 !Constant defining the Tree Recruitment Scheme switch - integer, public, parameter :: default_regeneration = 1 !Constant defining FATES's default regeneration scheme switch + integer, public, parameter :: TRS_no_seedling_dyn = 3 ! Constant defining the Tree Recruitment Scheme switch. This value + ! turns on size-based reproductive allocation and allocation to non-seed + ! reproductive biomass, but does not turn on seedling dynamics. + integer, public, parameter :: TRS = 2 !Constant defining the Tree Recruitment Scheme switch. This value turns on the full TRS. + integer, public, parameter :: default_regeneration = 1 !Constant defining FATES's default regeneration scheme switch. real(fates_r8), public, parameter :: min_max_dbh_for_trees = 15._fates_r8 !cm; if pfts have a max dbh less !than this value FATES !will use the default regeneration scheme. This is to avoid diff --git a/parameter_files/fates_params_default.cdl b/parameter_files/fates_params_default.cdl index 8aa3c65217..74757c560b 100644 --- a/parameter_files/fates_params_default.cdl +++ b/parameter_files/fates_params_default.cdl @@ -461,60 +461,60 @@ variables: 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_repro_alloc_a(fates_pft) ; - fates_repro_alloc_a:units = "fraction" ; - fates_repro_alloc_a:long_name = "shape parameter for sigmoidal function relating dbh to reproductive allocation" ; - double fates_repro_alloc_b(fates_pft) ; - fates_repro_alloc_b:units = "fraction" ; - fates_repro_alloc_b:long_name = "intercept parameter for sigmoidal function relating dbh to reproductive allocation" ; - double fates_repro_frac_seed(fates_pft) ; - fates_repro_frac_seed:units = "fraction" ; - fates_repro_frac_seed:long_name = "fraction of reproductive mass that is seed" ; - double fates_a_emerg(fates_pft) ; - fates_a_emerg:units = "day -1" ; - fates_a_emerg:long_name = "mean fraction of seed bank emerging" ; - double fates_b_emerg(fates_pft) ; - fates_b_emerg:units = "day -1" ; - fates_b_emerg:long_name = "seedling emergence sensitivity to soil moisture" ; - double fates_par_crit_germ(fates_pft) ; - fates_par_crit_germ:units = "Megajoules m2-1 day-1 " ; - fates_par_crit_germ:long_name = "critical light level for germination" ; - double fates_seedling_root_depth(fates_pft) ; - fates_seedling_root_depth:units = "m" ; - fates_seedling_root_depth:long_name = "rooting depth of seedlings" ; - double fates_seedling_psi_emerg(fates_pft) ; - fates_seedling_psi_emerg:units = "mm h20 suction" ; - fates_seedling_psi_emerg:long_name = "critical soil moisture for seedling emergence" ; - double fates_seedling_psi_crit(fates_pft) ; - fates_seedling_psi_crit:units = "mm h20 suction" ; - fates_seedling_psi_crit:long_name = "critical soil moisture for seedling stress" ; - double fates_seedling_mdd_crit(fates_pft) ; - fates_seedling_mdd_crit:units = "moisture deficit days (mm h2o suction * days)" ; - fates_seedling_mdd_crit:long_name = "critical moisture deficit day accumulation for seedling moisture-based seedling mortality to begin" ; - double fates_seedling_h2o_mort_a(fates_pft) ; - fates_seedling_h2o_mort_a:units = "-" ; - fates_seedling_h2o_mort_a:long_name = "coefficient in moisture-based seedling mortality" ; - double fates_seedling_h2o_mort_b(fates_pft) ; - fates_seedling_h2o_mort_b:units = "-" ; - fates_seedling_h2o_mort_b:long_name = "coefficient in moisture-based seedling mortality" ; - double fates_seedling_h2o_mort_c(fates_pft) ; - fates_seedling_h2o_mort_c:units = "-" ; - fates_seedling_h2o_mort_c:long_name = "coefficient in moisture-based seedling mortality" ; - double fates_seedling_light_mort_a(fates_pft) ; - fates_seedling_light_mort_a:units = "-" ; - fates_seedling_light_mort_a:long_name = "light-based seedling mortality coefficient" ; - double fates_seedling_light_mort_b(fates_pft) ; - fates_seedling_light_mort_b:units = "-" ; - fates_seedling_light_mort_b:long_name = "light-based seedling mortality coefficient" ; - double fates_background_seedling_mort(fates_pft) ; - fates_background_seedling_mort:units = "yr-1" ; - fates_background_seedling_mort:long_name = "background seedling mortality rate" ; - double fates_seedling_light_rec_a(fates_pft) ; - fates_seedling_light_rec_a:units = "-" ; - fates_seedling_light_rec_a:long_name = "coefficient in light-based seedling to sapling transition" ; - double fates_seedling_light_rec_b(fates_pft) ; - fates_seedling_light_rec_b:units = "-" ; - fates_seedling_light_rec_b:long_name = "coefficient in light-based seedling to sapling transition" ; + 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_par_crit_germ(fates_pft) ; + fates_trs_seedling_par_crit_germ:units = "Megajoules m2-1 day-1 " ; + fates_trs_seedling_par_crit_germ:long_name = "critical light level for germination" ; + 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_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_psi_crit(fates_pft) ; + fates_trs_seedling_psi_crit:units = "mm h20 suction" ; + fates_trs_seedling_psi_crit:long_name = "critical soil moisture for seedling stress" ; + double fates_trs_seedling_mdd_crit(fates_pft) ; + fates_trs_seedling_mdd_crit:units = "moisture deficit days (mm h2o suction * days)" ; + fates_trs_seedling_mdd_crit:long_name = "critical moisture deficit day accumulation for seedling moisture-based seedling mortality to begin" ; + 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_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_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_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" ; @@ -839,18 +839,18 @@ variables: double fates_phen_ncolddayslim ; fates_phen_ncolddayslim:units = "days" ; fates_phen_ncolddayslim:long_name = "day threshold exceedance for temperature leaf-drop" ; - double fates_sdlng_emerg_h2o_timescale ; - fates_sdlng_emerg_h2o_timescale:units = "days" ; - fates_sdlng_emerg_h2o_timescale:long_name = "Length of the window for the exponential moving average of smp used to calculate seedling emergence" ; - double fates_sdlng_mort_par_timescale ; - fates_sdlng_mort_par_timescale:units = "days" ; - fates_sdlng_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_sdlng_mdd_timescale ; - fates_sdlng_mdd_timescale:units = "days" ; - fates_sdlng_mdd_timescale:long_name = "Length of the window for the exponential moving average of moisture deficit days used to calculate seedling mortality" ; - double fates_sdlng2sap_par_timescale ; - fates_sdlng2sap_par_timescale:units = "days" ; - fates_sdlng2sap_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_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_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_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_q10_froz ; fates_q10_froz:units = "unitless" ; fates_q10_froz:long_name = "Q10 for frozen-soil respiration rates" ; @@ -1389,61 +1389,61 @@ data: 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_repro_alloc_a = 0.0049, 0.0049, 0.0049, 0.0049, 0.0049, 0.0049, 0.0049, + 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_repro_alloc_b = -2.6171, -2.6171, -2.6171, -2.6171, -2.6171, -2.6171, + 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_repro_frac_seed = 0.24, 0.24, 0.24, 0.24, 0.24, 0.24, 0.24, 0.24, 0.24, + 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_a_emerg = 0.0003, 0.0003, 0.0003, 0.0003, 0.0003, 0.0003, 0.0003, 0.0003, + 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_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_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_par_crit_germ = 0.656, 0.656, 0.656, 0.656, 0.656, 0.656, + 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_seedling_psi_emerg = -15744.65, -15744.65, -15744.65, -15744.65, -15744.65, + 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_seedling_psi_crit = -251995.7, -251995.7, -251995.7, -251995.7, -251995.7, + 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_seedling_mdd_crit = 1400000.0, 1400000.0, 1400000.0, 1400000.0, 1400000.0, + fates_trs_seedling_mdd_crit = 1400000.0, 1400000.0, 1400000.0, 1400000.0, 1400000.0, 1400000.0, 1400000.0, 1400000.0, 1400000.0, 1400000.0, 1400000.0, 1400000.0 ; - fates_seedling_h2o_mort_a = 4.070565e-17, 4.070565e-17, 4.070565e-17, + 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_seedling_h2o_mort_b = -6.390757e-11, -6.390757e-11, -6.390757e-11, + 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_seedling_h2o_mort_c = 1.268992e-05, 1.268992e-05, 1.268992e-05, 1.268992e-05, + 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_seedling_light_mort_a = -0.009897694, -0.009897694, -0.009897694, -0.009897694, + 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_seedling_light_mort_b = -7.154063, -7.154063, -7.154063, -7.154063, -7.154063, + 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_background_seedling_mort = 0.1085371, 0.1085371, 0.1085371, 0.1085371, 0.1085371, + 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_seedling_root_depth = 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, + 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_seedling_light_rec_a = 0.007, 0.007, 0.007, 0.007, 0.007, 0.007, 0.007, 0.007, 0.007, + 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_seedling_light_rec_b = 0.8615, 0.8615, 0.8615, 0.8615, 0.8615, + 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_recruit_seed_alloc = 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, @@ -1673,13 +1673,13 @@ data: fates_phen_moist_threshold = 0.18 ; - fates_sdlng_emerg_h2o_timescale = 7 ; + fates_trs_seedling_emerg_h2o_timescale = 7 ; - fates_sdlng_mort_par_timescale = 32 ; + fates_trs_seedling_mort_par_timescale = 32 ; - fates_sdlng_mdd_timescale = 126 ; + fates_trs_seedling_mdd_timescale = 126 ; - fates_sdlng2sap_par_timescale = 32 ; + fates_trs_seedling2sap_par_timescale = 32 ; fates_phen_ncolddayslim = 5 ; diff --git a/parteh/PRTParamsFATESMod.F90 b/parteh/PRTParamsFATESMod.F90 index 1f790eaf29..f525452fbc 100644 --- a/parteh/PRTParamsFATESMod.F90 +++ b/parteh/PRTParamsFATESMod.F90 @@ -230,11 +230,11 @@ subroutine PRTRegisterPFT(fates_params) !ahb added the params below !------------------------------------------------------------------------------------- - name = 'fates_repro_alloc_a' + name = 'fates_trs_repro_alloc_a' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_repro_alloc_b' + name = 'fates_trs_repro_alloc_b' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) !-------------------------------------------------------------------------------------- @@ -507,11 +507,11 @@ subroutine PRTReceivePFT(fates_params) !ahb added the code below !-------------------------------------------------------- - name = 'fates_repro_alloc_a' + name = 'fates_trs_repro_alloc_a' call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%repro_alloc_a) - name = 'fates_repro_alloc_b' + name = 'fates_trs_repro_alloc_b' call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%repro_alloc_b) !--------------------------------------------------------- From c5d85126bb8790ff281422e66a54874147d22198 Mon Sep 17 00:00:00 2001 From: Adam Hanbury-Brown Date: Tue, 11 Apr 2023 14:53:51 -0600 Subject: [PATCH 57/81] started adding recruitment_appf history variable --- biogeochem/EDPhysiologyMod.F90 | 1 - main/EDTypesMod.F90 | 1 - 2 files changed, 2 deletions(-) diff --git a/biogeochem/EDPhysiologyMod.F90 b/biogeochem/EDPhysiologyMod.F90 index 468ecda3af..8e90015032 100644 --- a/biogeochem/EDPhysiologyMod.F90 +++ b/biogeochem/EDPhysiologyMod.F90 @@ -2571,7 +2571,6 @@ subroutine recruitment( currentSite, currentPatch, bc_in ) ! keep track of how many individuals were recruited for passing to history currentSite%recruitment_rate(ft) = currentSite%recruitment_rate(ft) + temp_cohort%n - endif any_recruits endif !use_this_pft enddo !pft loop diff --git a/main/EDTypesMod.F90 b/main/EDTypesMod.F90 index 2d38bd635f..c015ea86d4 100644 --- a/main/EDTypesMod.F90 +++ b/main/EDTypesMod.F90 @@ -624,7 +624,6 @@ module EDTypesMod ! PLANT HYDRAULICS (not currently used in hydraulics RGK 03-2018) ! type(ed_patch_hydr_type) , pointer :: pa_hydr ! All patch hydraulics data, see FatesHydraulicsMemMod.F90 - end type ed_patch_type From e5d45bfd62922306d17de5d5343e5e05d4a2577f Mon Sep 17 00:00:00 2001 From: Adam Hanbury-Brown Date: Tue, 11 Apr 2023 17:23:30 -0600 Subject: [PATCH 58/81] cleaned up comments prior to pull request --- biogeochem/EDPatchDynamicsMod.F90 | 18 +- biogeochem/EDPhysiologyMod.F90 | 269 +-- biogeochem/EDPhysiologyMod.F90.save | 2396 --------------------------- biogeochem/FatesLitterMod.F90 | 8 - main/EDParamsMod.F90 | 6 +- main/EDPftvarcon.F90 | 33 +- main/FatesConstantsMod.F90 | 23 +- main/FatesInterfaceMod.F90 | 67 +- parteh/PRTAllometricCarbonMod.F90 | 50 +- 9 files changed, 173 insertions(+), 2697 deletions(-) delete mode 100644 biogeochem/EDPhysiologyMod.F90.save diff --git a/biogeochem/EDPatchDynamicsMod.F90 b/biogeochem/EDPatchDynamicsMod.F90 index f1194ee084..8b39565909 100644 --- a/biogeochem/EDPatchDynamicsMod.F90 +++ b/biogeochem/EDPatchDynamicsMod.F90 @@ -663,11 +663,10 @@ subroutine spawn_patches( currentSite, bc_in) 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,maxpft - call new_patch%sdlng_emerg_smp(pft)%p%CopyFromDonor(currentPatch%sdlng_emerg_smp(pft)%p) !ahb - call new_patch%sdlng_mdd(pft)%p%CopyFromDonor(currentPatch%sdlng_mdd(pft)%p) !ahb + 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 call new_patch%tveg_longterm%CopyFromDonor(currentPatch%tveg_longterm) @@ -1482,9 +1481,6 @@ subroutine TransLitterNewPatch(currentSite, & new_litt%seed_decay(pft) = new_litt%seed_decay(pft) + & curr_litt%seed_decay(pft)*patch_site_areadis/newPatch%area - new_litt%non_seed_repro_mass_decay(pft) = new_litt%non_seed_repro_mass_decay(pft) + & !ahb added this - curr_litt%non_seed_repro_mass_decay(pft)*patch_site_areadis/newPatch%area !ahb added this - new_litt%seed_germ_decay(pft) = new_litt%seed_germ_decay(pft) + & curr_litt%seed_germ_decay(pft)*patch_site_areadis/newPatch%area @@ -2104,11 +2100,11 @@ subroutine create_patch(currentSite, new_patch, age, areap, label,nocomp_pft) ! Until bc's are pointed to by sites give veg a default temp [K] real(r8), parameter :: temp_init_veg = 15._r8+t_water_freeze_k_1atm - real(r8), parameter :: init_seedling_par = 5.0_r8 !arbtrary initialization, ahb + real(r8), parameter :: init_seedling_par = 5.0_r8 !arbtrary initialization for + !seedling layer PAR [MJ m-2 d-1] - real(r8), parameter :: init_seedling_smp = -26652.0_r8 !mean smp (mm) from prior ED2 - !simulation at BCI (arbitrary) - integer :: pft !pft index + real(r8), parameter :: init_seedling_smp = -26652.0_r8 !arbitrary initialization of smp [mm] + integer :: pft !pft index ! !LOCAL VARIABLES: !--------------------------------------------------------------------- @@ -2682,7 +2678,7 @@ subroutine fuse_2_patches(csite, dp, rp) type (ed_cohort_type), pointer :: nextc ! Remembers next cohort in list type (ed_cohort_type), pointer :: storesmallcohort type (ed_cohort_type), pointer :: storebigcohort - integer :: c,p,pft !counters for pft and litter size class. ahb added pft here. + integer :: c,p,pft ! counters for pft and litter size class integer :: tnull,snull ! are the tallest and shortest cohorts associated? integer :: el ! loop counting index for elements type(ed_patch_type), pointer :: youngerp ! pointer to the patch younger than donor diff --git a/biogeochem/EDPhysiologyMod.F90 b/biogeochem/EDPhysiologyMod.F90 index 8e90015032..fdb112c439 100644 --- a/biogeochem/EDPhysiologyMod.F90 +++ b/biogeochem/EDPhysiologyMod.F90 @@ -150,7 +150,6 @@ module EDPhysiologyMod public :: SetRecruitL2FR logical, parameter :: debug = .false. ! local debug flag - logical, parameter :: debug_trs = .true. ! local debug flag character(len=*), parameter, private :: sourcefile = & __FILE__ @@ -436,7 +435,7 @@ subroutine PreDisturbanceLitterFluxes( currentSite, currentPatch, bc_in ) ! 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, bc_in, currentPatch) !ahb added currentPatch + call SeedGermination(litt, currentSite%cstatus, currentSite%dstatus, bc_in, currentPatch) ! Send fluxes from newly created litter into the litter pools ! This litter flux is from non-disturbance inducing mortality, as well @@ -455,7 +454,6 @@ subroutine PreDisturbanceLitterFluxes( currentSite, currentPatch, bc_in ) 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%non_seed_repro_mass_decay) + & !ahb added this line on 7/8/2021 sum(litt%seed_decay) + sum(litt%seed_germ_decay)) end do @@ -1801,7 +1799,6 @@ subroutine SeedIn( currentSite, bc_in ) do while (associated(currentPatch)) currentCohort => currentPatch%tallest - !litt => currentPatch%litter(el) !added by ahb do while (associated(currentCohort)) pft = currentCohort%pft @@ -1856,24 +1853,21 @@ subroutine SeedIn( currentSite, bc_in ) do pft = 1,numpft if(currentSite%use_this_pft(pft).eq.itrue)then + ! Seed input from local sources (within site) litt%seed_in_local(pft) = litt%seed_in_local(pft) + site_seed_rain(pft)/area - !START ahb's changes + ! If we are using the Tree Recruitment Scheme (TRS) with or w/o seedling dynamics if ( regeneration_model >= TRS .and. & prt_params%allom_dbh_maxheight(pft) > min_max_dbh_for_trees) then - !Send a fraction of reproductive carbon to litter to account for - !non-seed reproductive carbon (e.g. flowers, fruit, etc.) - !If using default_regeneration then all reproductive carbon becomes seed - !This process will be more important if/when FATES fixes the structural issue - !that all carbon used to make recruits comes from reproductive carbon. + ! Send a fraction of reproductive carbon to litter to account for + ! non-seed reproductive carbon (e.g. flowers, fruit, etc.) litt%seed_decay(pft) = litt%seed_in_local(pft) * (1.0_r8 - EDPftvarcon_inst%repro_frac_seed(pft)) + ! Note: The default regeneration scheme sends all reproductive carbon to seed end if !Use TRS - !Default regeneration scheme sends all reproductive carbon to seed (i.e. do nothing here) - !END ahb's changes ! If there is forced external seed rain, we calculate the input mass flux ! from the different elements, using the mean stoichiometry of new @@ -1916,7 +1910,9 @@ subroutine SeedDecay( litt , currentPatch, bc_in ) ! ! !DESCRIPTION: ! 1. Flux from seed pool into leaf litter pool - ! 2. (if TRS is on) Seedling mortality (i.e. flux from seedling pool into leaf litter pool) + ! 2. If the TRS with seedling dynamics is on (regeneration_model = 3) + ! then we calculate seedling mortality here (i.e. flux from seedling pool + ! (into leaf litter pool) ! ! !ARGUMENTS type(litter_type) :: litt @@ -1925,11 +1921,12 @@ subroutine SeedDecay( litt , currentPatch, bc_in ) ! ! !LOCAL VARIABLES: integer :: pft - real(r8) :: seedling_layer_par !cumulative light at the seedling layer (MJ) over prior window of days - !(defined by 'light_mort_window' param) - real(r8) :: seedling_light_mort_rate !the daily seedling mortality rate from light stress - real(r8) :: seedling_h2o_mort_rate !the daily seedling mortality rate from moisture stress - real(r8) :: seedling_mdds !moisture deficit days accumulated in the seedling layer + real(r8) :: seedling_layer_par ! cumulative sum of PAR at the seedling layer (MJ) + ! over prior window of days defined by + ! fates_trs_seedling_mort_par_timescale + real(r8) :: seedling_light_mort_rate ! daily seedling mortality rate from light stress + real(r8) :: seedling_h2o_mort_rate ! daily seedling mortality rate from moisture stress + real(r8) :: seedling_mdds ! moisture deficit days accumulated in the seedling layer !---------------------------------------------------------------------- @@ -1942,93 +1939,76 @@ subroutine SeedDecay( litt , currentPatch, bc_in ) ! seed_decay is kg/day ! Assume that decay rates are same for all chemical species - ! START ahb's changes !===================================================================================== do pft = 1,numpft - !If the TRS is switched off or the pft is not a tree then use the default - !regeneration scheme. + ! If the TRS is switched off or the pft can't get big enough to be considered a tree + ! then use FATES default regeneration. if ( regeneration_model == default_regeneration .or. & prt_params%allom_dbh_maxheight(pft) < min_max_dbh_for_trees ) then - !Default seed decay scheme (original code) + ! Default seed decay (TRS is off) litt%seed_decay(pft) = litt%seed(pft) * & EDPftvarcon_inst%seed_decay_rate(pft)*years_per_day - end if !end default regeneration model + end if ! End default regeneration model - ! If the TRS is fully switched on, or if it is switched on without seedling dynamics - ! (regeneration_model = TRS_no_seedling_dyn), - ! and the pft is a tree then make sure the non-seed reproductive biomass is added the - ! the seed decay flux. + ! If the TRS is switched on and the pft is a tree then add non-seed reproductive biomass + ! to the seed decay flux. This was added to litt%seed_decay in the previously called SeedIn + ! subroutine if ( regeneration_model >= TRS .and. & prt_params%allom_dbh_maxheight(pft) > min_max_dbh_for_trees ) then - !---------------------------------------------------------------------- - !With respect to seed decay, the only difference with the TRS here is adding the flux - !from non-seed reproductive biomass (which was sent to litt%seed_decay in the SeedIn subroutine) - - litt%seed_decay(pft) = litt%seed_decay(pft) + &!from non-seed reproductive biomass. + litt%seed_decay(pft) = litt%seed_decay(pft) + &! From non-seed reproductive biomass (added in + ! in the SeedIn subroutine. litt%seed(pft) * EDPftvarcon_inst%seed_decay_rate(pft)*years_per_day - end if !Send non-seed reproductive biomass to seed decay flux. + end if ! End use TRS - ! If the full TRS model is switch on (regeneration_model == TRS) then calculate seedling mortality. + ! If the TRS is switched on with seedling dynamics (regeneration_model = 3) + ! then calculate seedling mortality. if ( regeneration_model == TRS .and. & prt_params%allom_dbh_maxheight(pft) > min_max_dbh_for_trees ) then - !Seedling mortality (i.e. fluxes from seedling pool (seed_germ) to litter) !---------------------------------------------------------------------- - !Step 1. Calculate the daily seedling mortality rate from light stress - - !Calculate the cumulative light at the seedling layer over a prior number of - !days set by the "sdlng_mort_par_timescale" parameter + ! Seedling mortality (flux from seedling pool to litter) + ! Note: The TRS uses the litt%seed_germ data struture to track seedlings + + ! Step 1. Calculate the daily seedling mortality rate from light stress + ! Calculate the cumulative light at the seedling layer over a prior number of + ! days determined by the "fates_tres_seedling_mort_par_timescale" parameter. seedling_layer_par = currentPatch%sdlng_mort_par%GetMean() * megajoules_per_joule * & sec_per_day * sdlng_mort_par_timescale + ! Calculate daily seedling mortality rate from light seedling_light_mort_rate = exp( EDPftvarcon_inst%seedling_light_mort_a(pft) * & seedling_layer_par + EDPftvarcon_inst%seedling_light_mort_b(pft) ) - !Step 3. Calculate the daily seedling mortality rate from moisture stress + ! Step 2. Calculate the daily seedling mortality rate from moisture stress - !Get the current seedling moisture deficit days - !Calculated as (abs(seedling_psi_crit) - abs(seedling_layer_smp))* -1 * mddWindow + ! Get the current seedling moisture deficit days (tracked as a pft-specific exponential + ! average) seedling_mdds = currentPatch%sdlng_mdd(pft)%p%GetMean() - !Calculate seedling mortality as a function of moisture deficit days + ! Calculate seedling mortality as a function of moisture deficit days (mdd) seedling_h2o_mort_rate = EDPftvarcon_inst%seedling_h2o_mort_a(pft) * seedling_mdds**2 + & EDPftvarcon_inst%seedling_h2o_mort_b(pft) * seedling_mdds + & EDPftvarcon_inst%seedling_h2o_mort_c(pft) + ! If the seedling mmd value is below a critical threshold then moisture-based mortality is zero if (seedling_mdds < EDPftvarcon_inst%seedling_mdd_crit(pft)) then seedling_h2o_mort_rate = 0.0_r8 - end if !mdd threshold check + end if ! mdd threshold check - !Step 4. Add background mortality and send dead seedling carbon to litter (i.e. to seed_germ_decay flux) + ! Step 3. Sum modes of mortality (including background mortality) and send dead seedlings + ! to litter litt%seed_germ_decay(pft) = (litt%seed_germ(pft) * seedling_light_mort_rate) + & (litt%seed_germ(pft) * seedling_h2o_mort_rate) + & (litt%seed_germ(pft) * EDPftvarcon_inst%background_seedling_mort(pft) & * years_per_day) - end if !Use full TRS - - !ahb diagnostic - ! if (debug_trs) then - ! if (hlm_day_of_year == 40 .OR. hlm_day_of_year == 270) then - ! write(fates_log(),*) 'day_of_year:', hlm_day_of_year - ! write(fates_log(),*) 'patch_age:', currentPatch%age - ! write(fates_log(),*) 'pft', pft - ! write(fates_log(),*) 'seedling_light_mort_rate (day -1):', seedling_light_mort_rate - ! write(fates_log(),*) 'seedling_h2o_mort_rate (day -1):', seedling_h2o_mort_rate - ! write(fates_log(),*) 'seedling mdds ([0,1]):', seedling_mdds - ! end if - - ! end if !debug flag - !end ahb diagnostic - - !----------------------------------------------------------------------- - !END ahb's changes + end if ! End use TRS with seedling dynamics enddo @@ -2036,7 +2016,7 @@ subroutine SeedDecay( litt , currentPatch, bc_in ) end subroutine SeedDecay ! ============================================================================ - subroutine SeedGermination( litt, cold_stat, drought_stat, bc_in, currentPatch ) !ahb added currentPatch and bc_in + subroutine SeedGermination( litt, cold_stat, drought_stat, bc_in, currentPatch ) ! ! !DESCRIPTION: ! Flux from seed bank into the seedling pool @@ -2048,8 +2028,8 @@ subroutine SeedGermination( litt, cold_stat, drought_stat, bc_in, currentPatch ) type(litter_type) :: litt integer, intent(in) :: cold_stat ! Is the site in cold leaf-off status? integer, intent(in) :: drought_stat ! Is the site in drought leaf-off status? - type(bc_in_type), intent(in) :: bc_in ! ahb added this July 2021 - type(ed_patch_type), intent(in) :: currentPatch ! ahb added this July 2021 + type(bc_in_type), intent(in) :: bc_in + type(ed_patch_type), intent(in) :: currentPatch ! ! !LOCAL VARIABLES: integer :: pft @@ -2058,15 +2038,15 @@ subroutine SeedGermination( litt, cold_stat, drought_stat, bc_in, currentPatch ) !Light and moisture-sensitive seedling emergence variables (ahb) !------------------------------------------------------------------------------------------------------------ - integer :: ilayer_seedling_root ! the soil layer at seedling rooting depth - real(r8) :: seedling_layer_smp ! soil matric potential at seedling rooting depth - real(r8) :: wetness_index ! a soil 'wetness index' (1 / - SoilMatricPotetial (MPa) ) - real(r8) :: seedling_layer_par ! par at the seedling layer (MJ m-2 day-1) - real(r8) :: slsmp_emerg !temp - real(r8) :: slparmort !temp - real(r8) :: slpartrans !temp - real(r8) :: photoblastic_germ_modifier ! seedling emergence rate modifier for light-sensitive germination - real(r8) :: seedling_emerg_rate ! the fraction of the seed bank emerging in the current time step + integer :: ilayer_seedling_root ! the soil layer at seedling rooting depth + real(r8) :: seedling_layer_smp ! soil matric potential at seedling rooting depth + real(r8) :: wetness_index ! a soil 'wetness index' (1 / - SoilMatricPotetial (MPa) ) + real(r8) :: seedling_layer_par ! par at the seedling layer (MJ m-2 day-1) + real(r8) :: slsmp_emerg ! temp + real(r8) :: slparmort ! temp + real(r8) :: slpartrans ! temp + real(r8) :: photoblastic_germ_modifier ! seedling emergence rate modifier for light-sensitive germination + real(r8) :: seedling_emerg_rate ! the fraction of the seed bank emerging in the current time step !------------------------------------------------------------------------------------------------------------- @@ -2082,53 +2062,49 @@ subroutine SeedGermination( litt, cold_stat, drought_stat, bc_in, currentPatch ) ! and thus the mortality rate (in units of individuals) is the product of ! that times the ratio of (hypothetical) seed mass to recruit biomass - !START ahb's CHANGES !============================================================================================== do pft = 1,numpft + + ! If the TRS's seedling dynamics is switched off, then we use FATES's default approach + ! to germination if ( regeneration_model == default_regeneration .or. & regeneration_model == TRS_no_seedling_dyn .or. & prt_params%allom_dbh_maxheight(pft) < min_max_dbh_for_trees ) then - !FATES default germination scheme litt%seed_germ_in(pft) = min(litt%seed(pft) * EDPftvarcon_inst%germination_rate(pft), & max_germination)*years_per_day - !end FATES default germination scheme - !------------------------------------------------------------------------------------------- - !The Tree Recruitment Scheme calculates seedling emergence (i.e. germination) as a pft-specific - !function of understory light and soil moisture - + ! If TRS seedling dynamics is switched on we calculate seedling emergence (i.e. germination) + ! as a pft-specific function of understory light and soil moisture. else if ( regeneration_model == TRS .and. & prt_params%allom_dbh_maxheight(pft) > min_max_dbh_for_trees ) then - !Step 1. Calculate how germination rate is modified by understory light. - ! This applies to photoblastic germinators (e.g. many tropical pioneers) + ! Step 1. Calculate how germination rate is modified by understory light + ! This applies to photoblastic germinators (e.g. many tropical pioneers) - !Calculate par at the seedling layer (MJ m-2 day-1) - !The running mean variable is in W m-2 over prior 24 hours. It is converted to MJ m-2 day-1 - !to work with the TRS function. - + ! Calculate mean PAR at the seedling layer (MJ m-2 day-1) over the prior 24 hours seedling_layer_par = currentPatch%seedling_layer_par24%GetMean() * sec_per_day * megajoules_per_joule - !Calculate the photoblastic germination rate modifier (see eqn. 3 of Hanbury-Brown et al., 2022) + ! Calculate the photoblastic germination rate modifier (Eq. 3 Hanbury-Brown et al., 2022) photoblastic_germ_modifier = seedling_layer_par / & (seedling_layer_par + EDPftvarcon_inst%par_crit_germ(pft)) - !Step 2. Calculate the soil matric potential at the seedling rooting depth - - !Define soil layer based on pft-specific rooting depth - !ilayer_seedling_root = minloc(abs(bc_in%z_sisl(:)-EDPftvarcon_inst%seedling_root_depth(pft)),dim=1) + ! Step 2. Calculate how germination rate is modified by soil moisture in the rooting zone of + ! the seedlings. This is a pft-specific running mean based on pft-specific seedling rooting + ! depth. - !Get running mean of soil matric potential (mm of H2O suction) at the seedling rooting depth + ! Get running mean of soil matric potential (mm of H2O suction) at the seedling rooting depth + ! This running mean based on pft-specific seedling rooting depth. seedling_layer_smp = currentPatch%sdlng_emerg_smp(pft)%p%GetMean() - !Calculate a soil wetness index (1 / -soil matric pontential (MPa) ) used by the TRS moisture-based - !seedling mortality function + ! Calculate a soil wetness index (1 / -soil matric pontential (MPa) ) used by the TRS + ! to calculate seedling mortality from moisture stress. wetness_index = 1.0_r8 / (seedling_layer_smp * (-1.0_r8) * mpa_per_mm_suction) - !Step 3. Calculate the seedling emergence rate based on soil moisture and germination - ! rate modifier (i.e. Step 1). See eqn. 4 of Hanbury-Brown et al., 2022 + ! Step 3. Calculate the seedling emergence rate based on soil moisture and germination + ! rate modifier (Step 1). See Eq. 4 of Hanbury-Brown et al., 2022 + ! If SMP is below a pft-specific value, then no germination occurs if ( seedling_layer_smp .GE. EDPftvarcon_inst%seedling_psi_emerg(pft) ) then seedling_emerg_rate = photoblastic_germ_modifier * EDPftvarcon_inst%a_emerg(pft) * & wetness_index**EDPftvarcon_inst%b_emerg(pft) @@ -2136,47 +2112,13 @@ subroutine SeedGermination( litt, cold_stat, drought_stat, bc_in, currentPatch ) seedling_emerg_rate = 0.0_r8 - end if !soil-moisture based seedling emergence rate + end if ! End soil-moisture based seedling emergence rate - !Step 4. Calculate the amount of carbon germinating out of the seed bank + ! Step 4. Calculate the amount of carbon germinating out of the seed bank litt%seed_germ_in(pft) = litt%seed(pft) * seedling_emerg_rate - - ! !ahb diagnostic - ! if (debug_trs) then - ! if (hlm_day_of_year == 40 .OR. hlm_day_of_year == 270) then - ! write(fates_log(),*) 'day_of_year:', hlm_day_of_year - ! write(fates_log(),*) 'patch_age:', currentPatch%age - ! write(fates_log(),*) 'pft', pft - - ! write(fates_log(),*) 'seedling_layer_par (MJ m-2 day-1):', seedling_layer_par - ! write(fates_log(),*) 'seedling_layer_smp (mm h2o suction):', seedling_layer_smp - ! write(fates_log(),*) 'photoblastic_germ_modifier ([0,1]):', photoblastic_germ_modifier - ! write(fates_log(),*) 'seedling_emerg_rate (day-1):', seedling_emerg_rate - ! end if - - ! end if !debug flag - !end ahb diagnostic - - end if !regeneration model switch - !-------------------------------------------------------------------------------------------- - !TEMP - !slsmp_emerg = currentPatch%sdlng_emerg_smp%GetMean() - !slparmort = currentPatch%sdlng_mort_par%GetMean() - !slpartrans = currentPatch%sdlng2sap_par%GetMean() - - ! write(fates_log(),*) 'nrm parprof', currentPatch%nrmlzd_parprof_dir_z(:,:,:) - ! write(fates_log(),*) 'parprof', currentPatch%parprof_dif_z(1,:) - ! write(fates_log(),*) 'number_leaf_layers_in_second_canopy_layer', maxval(currentPatch%ncan(currentPatch%ncl_p,:)) - - ! write(fates_log(),*) 'patchno', currentPatch%patchno - ! write(fates_log(),*) 'seedling_layer_par', seedling_layer_par - ! write(fates_log(),*) 'seedling_emerg_smp', slsmp_emerg - ! write(fates_log(),*) 'seedling_mort_par', slparmort - ! write(fates_log(),*) 'seedling2sap_trans_par', slpartrans - ! write(fates_log(),*) 'tveg_lpa', currentPatch%tveg_lpa%GetMean() - !================================================================================================ - !END ahb changes - + + end if !End use TRS with seedling dynamics + !set the germination only under the growing season...c.xu if ((prt_params%season_decid(pft) == itrue ) .and. & @@ -2277,15 +2219,7 @@ subroutine recruitment( currentSite, currentPatch, bc_in ) temp_cohort%crowndamage = 1 ! new recruits are undamaged call h2d_allom(temp_cohort%hite,ft,temp_cohort%dbh) - - !ahb diagnostic - if (debug_trs) then - if (hlm_day_of_year == 40 .OR. hlm_day_of_year == 270) then - write(fates_log(),*) 'min_dbh:', temp_cohort%dbh - end if !day condition - end if !debug condition - !end ahb diagnostic - + ! Initialize live pools call bleaf(temp_cohort%dbh,ft,temp_cohort%crowndamage,& temp_cohort%canopy_trim,c_leaf) @@ -2347,12 +2281,6 @@ subroutine recruitment( currentSite, currentPatch, bc_in ) mass_demand = c_struct+c_leaf+c_fnrt+c_sapw+c_store - !ahb diagnostic - if (hlm_day_of_year == 40) then - write(fates_log(),*) 'mass demand:', mass_demand - end if - !end ahb diagnostic - case(nitrogen_element) mass_demand = & @@ -2384,14 +2312,16 @@ subroutine recruitment( currentSite, currentPatch, bc_in ) call endrun(msg=errMsg(sourcefile, __LINE__)) end select - !START ahb's changes - !================================================================================= + ! If TRS seedling dynamics is switched off then the available mass to make new recruits + ! is everything in the seed_germ pool. if ( regeneration_model == default_regeneration .or. & regeneration_model == TRS_no_seedling_dyn .or. & prt_params%allom_dbh_maxheight(ft) < min_max_dbh_for_trees ) then mass_avail = currentPatch%area * currentPatch%litter(el)%seed_germ(ft) - + + ! If TRS seedling dynamics is on then calculate the available mass to make new recruits + ! as a pft-specific function of light and soil moisture in the seedling layer. else if ( regeneration_model == TRS .and. & prt_params%allom_dbh_maxheight(ft) > min_max_dbh_for_trees ) then @@ -2401,24 +2331,9 @@ subroutine recruitment( currentSite, currentPatch, bc_in ) EDPftvarcon_inst%seedling_light_rec_a(ft) * & sdlng2sap_par**EDPftvarcon_inst%seedling_light_rec_b(ft) - - !ahb diagnostic - if (debug_trs) then - if (hlm_day_of_year == 40 .OR. hlm_day_of_year == 270) then - write(fates_log(),*) 'day_of_year:', hlm_day_of_year - write(fates_log(),*) 'patch_age:', currentPatch%age - write(fates_log(),*) 'pft', ft - write(fates_log(),*) 'sdlng2sap_par (MJ m-2 day-1):', sdlng2sap_par - write(fates_log(),*) 'seedling_2_sapling_transition_rate (day -1):', & - EDPftvarcon_inst%seedling_light_rec_a(ft) * & - sdlng2sap_par**EDPftvarcon_inst%seedling_light_rec_b(ft) - end if - end if !debug flag - !end ahb diagnostic - - - - !If soil moisture is below the moisture stress threshold recruitment does not occur + + ! If soil moisture is below pft-specific seedling moisture stress threshold the + ! recruitment does not occur. ilayer_seedling_root = minloc(abs(bc_in%z_sisl(:)-EDPftvarcon_inst%seedling_root_depth(ft)),dim=1) seedling_layer_smp = bc_in%smp_sl(ilayer_seedling_root) @@ -2427,12 +2342,10 @@ subroutine recruitment( currentSite, currentPatch, bc_in ) mass_avail = 0.0_r8 - end if !check on soil moisture + end if ! End check if soil moisture is sufficient for recruitment + + end if ! End use TRS with seedling dynamics - end if !regeneration model - - !================================================================================== - !END ahb's changes ! ------------------------------------------------------------------------ ! Update number density if this is the limiting mass ! ------------------------------------------------------------------------ diff --git a/biogeochem/EDPhysiologyMod.F90.save b/biogeochem/EDPhysiologyMod.F90.save deleted file mode 100644 index 9a068eb85c..0000000000 --- a/biogeochem/EDPhysiologyMod.F90.save +++ /dev/null @@ -1,2396 +0,0 @@ -module EDPhysiologyMod - -#include "shr_assert.h" - - ! ============================================================================ - ! Miscellaneous physiology routines from ED. - ! ============================================================================ - - use FatesGlobals, only : fates_log - use FatesInterfaceTypesMod, only : hlm_days_per_year - use FatesInterfaceTypesMod, only : hlm_model_day - use FatesInterfaceTypesMod, only : hlm_freq_day - use FatesInterfaceTypesMod, only : hlm_day_of_year - use FatesInterfaceTypesMod, only : numpft - use FatesInterfaceTypesMod, only : nleafage - use FatesInterfaceTypesMod, only : hlm_use_planthydro - use FatesInterfaceTypesMod, only : hlm_parteh_mode - use FatesInterfaceTypesMod, only : hlm_nitrogen_spec - use FatesInterfaceTypesMod, only : hlm_phosphorus_spec - use FatesConstantsMod, only : r8 => fates_r8 - use FatesConstantsMod, only : nearzero - use EDPftvarcon , only : EDPftvarcon_inst - use PRTParametersMod , only : prt_params - use EDPftvarcon , only : GetDecompyFrac - use FatesInterfaceTypesMod, only : bc_in_type - use FatesInterfaceTypesMod, only : bc_out_type - use EDCohortDynamicsMod , only : zero_cohort - use EDCohortDynamicsMod , only : create_cohort, sort_cohorts - use EDCohortDynamicsMod , only : InitPRTObject - use FatesAllometryMod , only : tree_lai - use FatesAllometryMod , only : tree_sai - use FatesAllometryMod , only : decay_coeff_kn - use FatesLitterMod , only : litter_type - use EDTypesMod , only : site_massbal_type - use EDTypesMod , only : numlevsoil_max - use EDTypesMod , only : numWaterMem - use EDTypesMod , only : dl_sf, dinc_ed, area_inv - use FatesLitterMod , only : ncwd - use FatesLitterMod , only : ndcmpy - use FatesLitterMod , only : ilabile - use FatesLitterMod , only : ilignin - use FatesLitterMod , only : icellulose - use EDTypesMod , only : AREA,AREA_INV - use EDTypesMod , only : nlevleaf - use EDTypesMod , only : num_vegtemp_mem - use EDTypesMod , only : maxpft - use EDTypesMod , only : ed_site_type, ed_patch_type, ed_cohort_type - use EDTypesMod , only : leaves_on - use EDTypesMod , only : leaves_off - use EDTypesMod , only : min_n_safemath - use PRTGenericMod , only : num_elements - use PRTGenericMod , only : element_list - use PRTGenericMod , only : element_pos - use EDTypesMod , only : site_fluxdiags_type - use EDTypesMod , only : phen_cstat_nevercold - use EDTypesMod , only : phen_cstat_iscold - use EDTypesMod , only : phen_cstat_notcold - use EDTypesMod , only : phen_dstat_timeoff - use EDTypesMod , only : phen_dstat_moistoff - use EDTypesMod , only : phen_dstat_moiston - use EDTypesMod , only : phen_dstat_timeon - use EDTypesMod , only : init_recruit_trim - use shr_log_mod , only : errMsg => shr_log_errMsg - use FatesGlobals , only : fates_log - use FatesGlobals , only : endrun => fates_endrun - use EDParamsMod , only : fates_mortality_disturbance_fraction - use EDParamsMod , only : q10_mr - use EDParamsMod , only : q10_froz - use EDParamsMod , only : logging_export_frac - use FatesPlantHydraulicsMod , only : AccumulateMortalityWaterStorage - use FatesConstantsMod , only : itrue,ifalse - use FatesConstantsMod , only : calloc_abs_error - use FatesConstantsMod , only : years_per_day - use FatesAllometryMod , only : h_allom - use FatesAllometryMod , only : h2d_allom - use FatesAllometryMod , only : bagw_allom - use FatesAllometryMod , only : bsap_allom - use FatesAllometryMod , only : bleaf - use FatesAllometryMod , only : bfineroot - use FatesAllometryMod , only : bdead_allom - use FatesAllometryMod , only : bstore_allom - use FatesAllometryMod , only : bbgw_allom - use FatesAllometryMod , only : carea_allom - use FatesAllometryMod , only : CheckIntegratedAllometries - use FatesAllometryMod, only : set_root_fraction - use PRTGenericMod, only : prt_carbon_allom_hyp - use PRTGenericMod, only : prt_cnp_flex_allom_hyp - use PRTGenericMod, only : prt_vartypes - use PRTGenericMod, only : leaf_organ - use PRTGenericMod, only : sapw_organ, struct_organ - use PRTGenericMod, only : all_carbon_elements - 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 - use PRTGenericMod, only : store_organ - use PRTGenericMod, only : repro_organ - use PRTGenericMod, only : struct_organ - use PRTGenericMod, only : SetState - use PRTLossFluxesMod, only : PRTPhenologyFlush - use PRTLossFluxesMod, only : PRTDeciduousTurnover - use PRTLossFluxesMod, only : PRTReproRelease - use PRTGenericMod, only : StorageNutrientTarget - - implicit none - private - - public :: trim_canopy - public :: phenology - public :: recruitment - public :: ZeroLitterFluxes - - public :: ZeroAllocationRates - public :: PreDisturbanceLitterFluxes - public :: PreDisturbanceIntegrateLitter - public :: SeedIn - - logical, parameter :: debug = .false. ! local debug flag - character(len=*), parameter, private :: sourcefile = & - __FILE__ - - integer, parameter :: dleafon_drycheck = 100 ! Drought deciduous leaves max days on check parameter - - - ! ============================================================================ - -contains - - subroutine ZeroLitterFluxes( currentSite ) - - ! This routine loops through all patches in a site - ! and zero's the flux terms for the litter pools. - ! This is typically called at the beginning of the dynamics - ! call sequence. - - - ! !ARGUMENTS - type(ed_site_type), intent(inout), target :: currentSite - type(ed_patch_type), pointer :: currentPatch - - integer :: el - - currentPatch => currentSite%youngest_patch - do while(associated(currentPatch)) - do el=1,num_elements - call currentPatch%litter(el)%ZeroFlux() - end do - currentPatch => currentPatch%older - end do - - - return - end subroutine ZeroLitterFluxes - - ! ===================================================================================== - - subroutine ZeroAllocationRates( currentSite ) - - ! !ARGUMENTS - type(ed_site_type), intent(inout), target :: currentSite - type(ed_patch_type), pointer :: currentPatch - type(ed_cohort_type), pointer :: currentCohort - - currentPatch => currentSite%youngest_patch - do while(associated(currentPatch)) - - currentCohort => currentPatch%tallest - do while (associated(currentCohort)) - - ! This sets turnover and growth rates to zero - call currentCohort%prt%ZeroRates() - - currentCohort => currentCohort%shorter - enddo - currentPatch => currentPatch%older - end do - - return - end subroutine ZeroAllocationRates - - - ! ============================================================================ - - subroutine PreDisturbanceLitterFluxes( currentSite, currentPatch, bc_in ) - - ! ----------------------------------------------------------------------------------- - ! - ! This subroutine calculates all of the different litter input and output fluxes - ! associated with seed turnover, seed influx, litterfall from live and - ! dead plants, germination, and fragmentation. - ! - ! At this time we do not have explicit herbivory, and burning losses to litter - ! are handled elsewhere. - ! - ! Note: The processes conducted here DO NOT handle litter fluxes associated - ! with disturbance. Those fluxes are handled elsewhere (EDPatchDynamcisMod) - ! because the fluxes are potentially cross patch, and also dealing - ! patch areas that are changing. - ! - ! ----------------------------------------------------------------------------------- - - - ! !ARGUMENTS - type(ed_site_type), intent(inout) :: currentSite - type(ed_patch_type), intent(inout) :: currentPatch - type(bc_in_type), intent(in) :: 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 - !------------------------------------------------------------------------------------ - - ! Calculate the fragmentation rates - call fragmentation_scaler(currentPatch, bc_in) - - - do el = 1, num_elements - - litt => currentPatch%litter(el) - - ! Calculate loss rate of viable seeds to litter - call SeedDecay(litt) - - ! 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) - - ! 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) - - - 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%non_seed_repro_mass_decay) + & !ahb added this line on 7/8/2021 - sum(litt%seed_decay) + sum(litt%seed_germ_decay)) - - end do - - - return - end subroutine PreDisturbanceLitterFluxes - - ! ===================================================================================== - - subroutine PreDisturbanceIntegrateLitter(currentPatch) - - ! ----------------------------------------------------------------------------------- - ! - ! This step applies the litter fluxes to the prognostic state variables. - ! This procedure is called in response to fluxes generated from: - ! 1) seed rain, - ! 2) non-disturbance generating turnover - ! 3) litter fall from living plants - ! 4) fragmentation - ! - ! This routine does NOT accomodate the litter fluxes associated with - ! disturbance generation. That will happen after this call. - ! Fluxes associated with FIRE also happen after this step. - ! - ! All states are in units kg/m2 - ! All fluxes are in units kg/m2/day - ! The integration step is 1 day, thus time is implied - ! - ! ----------------------------------------------------------------------------------- - - ! Arguments - type(ed_patch_type),intent(inout),target :: currentPatch - - - ! Locals - type(litter_type), pointer :: litt - integer :: el ! Loop counter for litter element type - integer :: pft ! pft loop counter - integer :: c ! CWD loop counter - integer :: nlevsoil ! number of soil layers - integer :: ilyr ! soil layer loop counter - integer :: dcmpy ! decomposability index - - do el = 1, num_elements - - litt => currentPatch%litter(el) - - ! Update the bank of viable seeds - ! ----------------------------------------------------------------------------------- - - do pft = 1,numpft - litt%seed(pft) = litt%seed(pft) + & - litt%seed_in_local(pft) + & - litt%seed_in_extern(pft) - & - litt%seed_decay(pft) - & - litt%seed_germ_in(pft) - - ! Note that the recruitment scheme will use seed_germ - ! for its construction costs. - litt%seed_germ(pft) = litt%seed_germ(pft) + & - litt%seed_germ_in(pft) - & - litt%seed_germ_decay(pft) - - - enddo - - ! Update the Coarse Woody Debris pools (above and below) - ! ----------------------------------------------------------------------------------- - nlevsoil = size(litt%bg_cwd,dim=2) - do c = 1,ncwd - litt%ag_cwd(c) = litt%ag_cwd(c) + litt%ag_cwd_in(c) - litt%ag_cwd_frag(c) - do ilyr=1,nlevsoil - litt%bg_cwd(c,ilyr) = litt%bg_cwd(c,ilyr) & - + litt%bg_cwd_in(c,ilyr) & - - litt%bg_cwd_frag(c,ilyr) - enddo - end do - - ! Update the fine litter pools from leaves and fine-roots - ! ----------------------------------------------------------------------------------- - - do dcmpy = 1,ndcmpy - - litt%leaf_fines(dcmpy) = litt%leaf_fines(dcmpy) & - + litt%leaf_fines_in(dcmpy) & - - litt%leaf_fines_frag(dcmpy) - do ilyr=1,nlevsoil - litt%root_fines(dcmpy,ilyr) = litt%root_fines(dcmpy,ilyr) & - + litt%root_fines_in(dcmpy,ilyr) & - - litt%root_fines_frag(dcmpy,ilyr) - enddo - - end do - - end do ! litter element loop - - return - end subroutine PreDisturbanceIntegrateLitter - - - - ! ============================================================================ - - subroutine trim_canopy( currentSite ) - ! - ! !DESCRIPTION: - ! Canopy trimming / leaf optimisation. Removes leaves in negative annual carbon balance. - ! - ! !USES: - - ! !ARGUMENTS - type (ed_site_type),intent(inout), target :: currentSite - ! - ! !LOCAL VARIABLES: - type (ed_cohort_type) , pointer :: currentCohort - type (ed_patch_type) , pointer :: currentPatch - - integer :: z ! leaf layer - integer :: ipft ! pft index - logical :: trimmed ! was this layer trimmed in this year? If not expand the canopy. - real(r8) :: tar_bl ! target leaf biomass (leaves flushed, trimmed) - real(r8) :: tar_bfr ! target fine-root biomass (leaves flushed, trimmed) - real(r8) :: bfr_per_bleaf ! ratio of fine root per leaf biomass - real(r8) :: sla_levleaf ! sla at leaf level z - real(r8) :: nscaler_levleaf ! nscaler value at leaf level z - integer :: cl ! canopy layer index - real(r8) :: kn ! nitrogen decay coefficient - real(r8) :: sla_max ! Observational constraint on how large sla (m2/gC) can become - real(r8) :: leaf_c ! leaf carbon [kg] - real(r8) :: sapw_c ! sapwood carbon [kg] - real(r8) :: store_c ! storage carbon [kg] - real(r8) :: struct_c ! structure carbon [kg] - real(r8) :: leaf_inc ! LAI-only portion of the vegetation increment of dinc_ed - real(r8) :: lai_canopy_above ! the LAI in the canopy layers above the layer of interest - real(r8) :: lai_layers_above ! the LAI in the leaf layers, within the current canopy, - ! above the leaf layer of interest - real(r8) :: lai_current ! the LAI in the current leaf layer - real(r8) :: cumulative_lai ! whole canopy cumulative LAI, top down, to the leaf layer of interest - real(r8) :: cumulative_lai_cohort ! cumulative LAI within the current cohort only - - ! Temporary diagnostic ouptut - integer :: ipatch - integer :: icohort - - ! LAPACK linear least squares fit variables - ! The standard equation for a linear fit, y = mx + b, is converted to a linear system, AX=B and has - ! the form: [n sum(x); sum(x) sum(x^2)] * [b; m] = [sum(y); sum(x*y)] where - ! n is the number of leaf layers - ! x is yearly_net_uptake minus the leaf cost aka the net-net uptake - ! y is the cumulative lai for the current cohort - ! b is the y-intercept i.e. the cumulative lai that has zero net-net uptake - ! m is the slope of the linear fit - integer :: nll = 3 ! Number of leaf layers to fit a regression to for calculating the optimum lai - character(1) :: trans = 'N' ! Input matrix is not transposed - - integer, parameter :: m = 2, n = 2 ! Number of rows and columns, respectively, in matrix A - integer, parameter :: nrhs = 1 ! Number of columns in matrix B and X - integer, parameter :: workmax = 100 ! Maximum iterations to minimize work - - integer :: lda = m, ldb = n ! Leading dimension of A and B, respectively - integer :: lwork ! Dimension of work array - integer :: info ! Procedure diagnostic ouput - - real(r8) :: nnu_clai_a(m,n) ! LHS of linear least squares fit, A matrix - real(r8) :: nnu_clai_b(m,nrhs) ! RHS of linear least squares fit, B matrix - real(r8) :: work(workmax) ! work array - - real(r8) :: initial_trim ! Initial trim - real(r8) :: optimum_trim ! Optimum trim value - real(r8) :: initial_laimem ! Initial laimemory - real(r8) :: optimum_laimem ! Optimum laimemory - - !---------------------------------------------------------------------- - - ipatch = 1 ! Start counting patches - - currentPatch => currentSite%youngest_patch - do while(associated(currentPatch)) - - ! Add debug diagnstic output to determine which patch - if (debug) then - write(fates_log(),*) 'Current patch:', ipatch - write(fates_log(),*) 'Current patch cohorts:', currentPatch%countcohorts - endif - - icohort = 1 - - currentCohort => currentPatch%tallest - do while (associated(currentCohort)) - - ! Save off the incoming trim and laimemory - initial_trim = currentCohort%canopy_trim - initial_laimem = currentCohort%laimemory - - ! Add debug diagnstic output to determine which cohort - if (debug) then - write(fates_log(),*) 'Current cohort:', icohort - write(fates_log(),*) 'Starting canopy trim:', initial_trim - write(fates_log(),*) 'Starting laimemory:', currentCohort%laimemory - endif - - trimmed = .false. - ipft = currentCohort%pft - call carea_allom(currentCohort%dbh,currentCohort%n,currentSite%spread,currentCohort%pft,currentCohort%c_area) - - leaf_c = currentCohort%prt%GetState(leaf_organ, all_carbon_elements) - - currentCohort%treelai = tree_lai(leaf_c, currentCohort%pft, currentCohort%c_area, & - currentCohort%n, currentCohort%canopy_layer, & - currentPatch%canopy_layer_tlai,currentCohort%vcmax25top ) - - currentCohort%treesai = tree_sai(currentCohort%pft, currentCohort%dbh, currentCohort%canopy_trim, & - currentCohort%c_area, currentCohort%n, currentCohort%canopy_layer, & - currentPatch%canopy_layer_tlai, currentCohort%treelai, & - currentCohort%vcmax25top,0 ) - - currentCohort%nv = ceiling((currentCohort%treelai+currentCohort%treesai)/dinc_ed) - - if (currentCohort%nv > nlevleaf)then - write(fates_log(),*) 'nv > nlevleaf',currentCohort%nv, & - currentCohort%treelai,currentCohort%treesai, & - currentCohort%c_area,currentCohort%n,leaf_c - call endrun(msg=errMsg(sourcefile, __LINE__)) - endif - - call bleaf(currentcohort%dbh,ipft,currentcohort%canopy_trim,tar_bl) - - if ( int(prt_params%allom_fmode(ipft)) .eq. 1 ) then - ! only query fine root biomass if using a fine root allometric model that takes leaf trim into account - call bfineroot(currentcohort%dbh,ipft,currentcohort%canopy_trim,tar_bfr) - bfr_per_bleaf = tar_bfr/tar_bl - endif - - ! Identify current canopy layer (cl) - cl = currentCohort%canopy_layer - - ! PFT-level maximum SLA value, even if under a thick canopy (same units as slatop) - sla_max = prt_params%slamax(ipft) - - ! Initialize nnu_clai_a - nnu_clai_a(:,:) = 0._r8 - nnu_clai_b(:,:) = 0._r8 - - !Leaf cost vs netuptake for each leaf layer. - do z = 1, currentCohort%nv - - ! Calculate the cumulative total vegetation area index (no snow occlusion, stems and leaves) - - leaf_inc = dinc_ed * & - currentCohort%treelai/(currentCohort%treelai+currentCohort%treesai) - - ! Now calculate the cumulative top-down lai of the current layer's midpoint within the current cohort - lai_layers_above = leaf_inc * (z-1) - lai_current = min(leaf_inc, currentCohort%treelai - lai_layers_above) - cumulative_lai_cohort = lai_layers_above + 0.5*lai_current - - ! Now add in the lai above the current cohort for calculating the sla leaf level - lai_canopy_above = sum(currentPatch%canopy_layer_tlai(1:cl-1)) - cumulative_lai = lai_canopy_above + cumulative_lai_cohort - - ! There was activity this year in this leaf layer. This should only occur for bottom most leaf layer - if (currentCohort%year_net_uptake(z) /= 999._r8)then - - ! Calculate sla_levleaf following the sla profile with overlying leaf area - ! Scale for leaf nitrogen profile - kn = decay_coeff_kn(ipft,currentCohort%vcmax25top) - ! Nscaler value at leaf level z - nscaler_levleaf = exp(-kn * cumulative_lai) - ! Sla value at leaf level z after nitrogen profile scaling (m2/gC) - sla_levleaf = prt_params%slatop(ipft)/nscaler_levleaf - - if(sla_levleaf > sla_max)then - sla_levleaf = sla_max - end if - - !Leaf Cost kgC/m2/year-1 - !decidous costs. - if (prt_params%season_decid(ipft) == itrue .or. & - prt_params%stress_decid(ipft) == itrue )then - - ! Leaf cost at leaf level z accounting for sla profile (kgC/m2) - currentCohort%leaf_cost = 1._r8/(sla_levleaf*1000.0_r8) - - if ( int(prt_params%allom_fmode(ipft)) .eq. 1 ) then - ! if using trimmed leaf for fine root biomass allometry, add the cost of the root increment - ! to the leaf increment; otherwise do not. - currentCohort%leaf_cost = currentCohort%leaf_cost + & - 1.0_r8/(sla_levleaf*1000.0_r8) * & - bfr_per_bleaf / prt_params%root_long(ipft) - endif - - currentCohort%leaf_cost = currentCohort%leaf_cost * & - (prt_params%grperc(ipft) + 1._r8) - else !evergreen costs - - ! Leaf cost at leaf level z accounting for sla profile - currentCohort%leaf_cost = 1.0_r8/(sla_levleaf* & - sum(prt_params%leaf_long(ipft,:))*1000.0_r8) !convert from sla in m2g-1 to m2kg-1 - - - if ( int(prt_params%allom_fmode(ipft)) .eq. 1 ) then - ! if using trimmed leaf for fine root biomass allometry, add the cost of the root increment - ! to the leaf increment; otherwise do not. - currentCohort%leaf_cost = currentCohort%leaf_cost + & - 1.0_r8/(sla_levleaf*1000.0_r8) * & - bfr_per_bleaf / prt_params%root_long(ipft) - endif - currentCohort%leaf_cost = currentCohort%leaf_cost * & - (prt_params%grperc(ipft) + 1._r8) - endif - - ! Construct the arrays for a least square fit of the net_net_uptake versus the cumulative lai - ! if at least nll leaf layers are present in the current cohort and only for the bottom nll - ! leaf layers. - if (currentCohort%nv > nll .and. currentCohort%nv - z < nll) then - - ! Build the A matrix for the LHS of the linear system. A = [n sum(x); sum(x) sum(x^2)] - ! where n = nll and x = yearly_net_uptake-leafcost - nnu_clai_a(1,1) = nnu_clai_a(1,1) + 1 ! Increment for each layer used - nnu_clai_a(1,2) = nnu_clai_a(1,2) + currentCohort%year_net_uptake(z) - currentCohort%leaf_cost - nnu_clai_a(2,1) = nnu_clai_a(1,2) - nnu_clai_a(2,2) = nnu_clai_a(2,2) + (currentCohort%year_net_uptake(z) - currentCohort%leaf_cost)**2 - - ! Build the B matrix for the RHS of the linear system. B = [sum(y); sum(x*y)] - ! where x = yearly_net_uptake-leafcost and y = cumulative_lai_cohort - nnu_clai_b(1,1) = nnu_clai_b(1,1) + cumulative_lai_cohort - nnu_clai_b(2,1) = nnu_clai_b(2,1) + (cumulative_lai_cohort * & - (currentCohort%year_net_uptake(z) - currentCohort%leaf_cost)) - end if - - ! Check leaf cost against the yearly net uptake for that cohort leaf layer - if (currentCohort%year_net_uptake(z) < currentCohort%leaf_cost) then - ! Make sure the cohort trim fraction is great than the pft trim limit - if (currentCohort%canopy_trim > EDPftvarcon_inst%trim_limit(ipft)) then - - ! if ( debug ) then - ! write(fates_log(),*) 'trimming leaves', & - ! currentCohort%canopy_trim,currentCohort%leaf_cost - ! endif - - ! keep trimming until none of the canopy is in negative carbon balance. - if (currentCohort%hite > EDPftvarcon_inst%hgt_min(ipft)) then - currentCohort%canopy_trim = currentCohort%canopy_trim - & - EDPftvarcon_inst%trim_inc(ipft) - if (prt_params%evergreen(ipft) /= 1)then - currentCohort%laimemory = currentCohort%laimemory * & - (1.0_r8 - EDPftvarcon_inst%trim_inc(ipft)) - endif - - trimmed = .true. - - endif ! hite check - endif ! trim limit check - endif ! net uptake check - endif ! leaf activity check - enddo ! z, leaf layer loop - - ! Compute the optimal cumulative lai based on the cohort net-net uptake profile if at least 2 leaf layers - if (nnu_clai_a(1,1) > 1) then - - ! Compute the optimum size of the work array - lwork = -1 ! Ask sgels to compute optimal number of entries for work - call dgels(trans, m, n, nrhs, nnu_clai_a, lda, nnu_clai_b, ldb, work, lwork, info) - lwork = int(work(1)) ! Pick the optimum. TBD, can work(1) come back with greater than work size? - - ! if (debug) then - ! write(fates_log(),*) 'LLSF lwork output (info, lwork):', info, lwork - ! endif - - ! Compute the minimum of 2-norm of of the least squares fit to solve for X - ! Note that dgels returns the solution by overwriting the nnu_clai_b array. - ! The result has the form: X = [b; m] - ! where b = y-intercept (i.e. the cohort lai that has zero yearly net-net uptake) - ! and m is the slope of the linear fit - call dgels(trans, m, n, nrhs, nnu_clai_a, lda, nnu_clai_b, ldb, work, lwork, info) - - if (info < 0) then - write(fates_log(),*) 'LLSF optimium LAI calculation returned illegal value' - call endrun(msg=errMsg(sourcefile, __LINE__)) - endif - - if (debug) then - write(fates_log(),*) 'LLSF optimium LAI (intercept,slope):', nnu_clai_b - write(fates_log(),*) 'LLSF optimium LAI:', nnu_clai_b(1,1) - write(fates_log(),*) 'LLSF optimium LAI info:', info - write(fates_log(),*) 'LAI fraction (optimum_lai/cumulative_lai):', nnu_clai_b(1,1) / cumulative_lai_cohort - endif - - ! Calculate the optimum trim based on the initial canopy trim value - if (cumulative_lai_cohort > 0._r8) then ! Sometime cumulative_lai comes in at 0.0? - - ! - optimum_trim = (nnu_clai_b(1,1) / cumulative_lai_cohort) * initial_trim - optimum_laimem = (nnu_clai_b(1,1) / cumulative_lai_cohort) * initial_laimem - - ! Determine if the optimum trim value makes sense. The smallest cohorts tend to have unrealistic fits. - if (optimum_trim > 0. .and. optimum_trim < 1.) then - currentCohort%canopy_trim = optimum_trim - - ! If the cohort pft is not evergreen we reduce the laimemory as well - if (prt_params%evergreen(ipft) /= 1) then - currentCohort%laimemory = optimum_laimem - endif - - trimmed = .true. - - endif - endif - endif - - ! Reset activity for the cohort for the start of the next year - currentCohort%year_net_uptake(:) = 999.0_r8 - - ! Add to trim fraction if cohort not trimmed at all - if ( (.not.trimmed) .and.currentCohort%canopy_trim < 1.0_r8)then - currentCohort%canopy_trim = currentCohort%canopy_trim + EDPftvarcon_inst%trim_inc(ipft) - endif - - if ( debug ) then - write(fates_log(),*) 'trimming:',currentCohort%canopy_trim - endif - - ! currentCohort%canopy_trim = 1.0_r8 !FIX(RF,032414) this turns off ctrim for now. - currentCohort => currentCohort%shorter - icohort = icohort + 1 - enddo - currentPatch => currentPatch%older - ipatch = ipatch + 1 - enddo - - end subroutine trim_canopy - - ! ============================================================================ - subroutine phenology( currentSite, bc_in ) - ! - ! !DESCRIPTION: - ! Phenology. - ! - ! !USES: - use FatesConstantsMod, only : tfrz => t_water_freeze_k_1atm - use EDParamsMod, only : ED_val_phen_drought_threshold, ED_val_phen_doff_time - use EDParamsMod, only : ED_val_phen_a, ED_val_phen_b, ED_val_phen_c, ED_val_phen_chiltemp - use EDParamsMod, only : ED_val_phen_mindayson, ED_val_phen_ncolddayslim, ED_val_phen_coldtemp - - - ! - ! !ARGUMENTS: - type(ed_site_type), intent(inout), target :: currentSite - type(bc_in_type), intent(in) :: bc_in - - ! - ! !LOCAL VARIABLES: - - type(ed_patch_type),pointer :: cpatch - integer :: model_day_int ! integer model day 1 - inf - integer :: ncolddays ! no days underneath the threshold for leaf drop - integer :: i_wmem ! Loop counter for water mem days - integer :: i_tmem ! Loop counter for veg temp mem days - integer :: dayssincedleafon ! Days since drought-decid leaf-on started - integer :: dayssincedleafoff ! Days since drought-decid leaf-off started - integer :: dayssincecleafon ! Days since cold-decid leaf-on started - integer :: dayssincecleafoff ! Days since cold-decid leaf-off started - real(r8) :: mean_10day_liqvol ! mean liquid volume (m3/m3) over last 10 days - real(r8) :: leaf_c ! leaf carbon [kg] - real(r8) :: fnrt_c ! fineroot carbon [kg] - real(r8) :: sapw_c ! sapwood carbon [kg] - real(r8) :: store_c ! storage carbon [kg] - real(r8) :: struct_c ! structure carbon [kg] - real(r8) :: gdd_threshold ! GDD accumulation function, - integer :: ilayer_swater ! Layer index for soil water - ! which also depends on chilling days. - integer :: ncdstart ! beginning of counting period for chilling degree days. - integer :: gddstart ! beginning of counting period for growing degree days. - real(r8) :: temp_in_C ! daily averaged temperature in celcius - - integer, parameter :: canopy_leaf_lifespan = 365 ! Maximum lifespan of drought decid leaves - - integer, parameter :: min_daysoff_dforcedflush = 30 ! THis is the number of days that must had elapsed - ! since leaves had dropped, in order to forcably - ! flush leaves again. This does not impact flushing - ! due to real moisture constraints, and will prevent - ! drought deciduous in perennially wet environments - ! that have been forced to drop their leaves, from - ! flushing them back immediately. - - real(r8),parameter :: dphen_soil_depth = 0.1 ! Use liquid soil water that is - ! closest to this depth [m] - - ! This is the integer model day. The first day of the simulation is 1, and it - ! continues monotonically, indefinitely - model_day_int = nint(hlm_model_day) - - - ! Use the following layer index to calculate drought conditions - ilayer_swater = minloc(abs(bc_in%z_sisl(:)-dphen_soil_depth),dim=1) - - - ! Parameter of drought decid leaf loss in mm in top layer...FIX(RF,032414) - ! - this is arbitrary and poorly understood. Needs work. ED_ - !Parameters: defaults from Botta et al. 2000 GCB,6 709-725 - !Parameters, default from from SDGVM model of senesence - - temp_in_C = 0._r8 - cpatch => CurrentSite%oldest_patch - do while(associated(cpatch)) - temp_in_C = temp_in_C + bc_in%t_veg24_pa(cpatch%patchno)*cpatch%area - cpatch => cpatch%younger - end do - temp_in_C = temp_in_C * area_inv - tfrz - - - !-----------------Cold Phenology--------------------! - - !Zero growing degree and chilling day counters - if (currentSite%lat > 0)then - ncdstart = 270 !Northern Hemisphere begining November - gddstart = 1 !Northern Hemisphere begining January - else - ncdstart = 120 !Southern Hemisphere beginning May - gddstart = 181 !Northern Hemisphere begining July - endif - - ! Count the number of chilling days over a seasonal window. - ! For comparing against GDD, we start calculating chilling - ! in the late autumn. - ! This value is used to determine the GDD exceedance threshold - if (hlm_day_of_year == ncdstart)then - currentSite%nchilldays = 0 - endif - - !Accumulate growing/chilling days after start of counting period - if (temp_in_C < ED_val_phen_chiltemp)then - currentSite%nchilldays = currentSite%nchilldays + 1 - endif - - !GDD accumulation function, which also depends on chilling days. - ! -68 + 638 * (-0.001 * ncd) - gdd_threshold = ED_val_phen_a + ED_val_phen_b*exp(ED_val_phen_c*real(currentSite%nchilldays,r8)) - - !Accumulate temperature of last 10 days. - currentSite%vegtemp_memory(2:num_vegtemp_mem) = currentSite%vegtemp_memory(1:num_vegtemp_mem-1) - currentSite%vegtemp_memory(1) = temp_in_C - - !count number of days for leaves off - ncolddays = 0 - do i_tmem = 1,num_vegtemp_mem - if (currentSite%vegtemp_memory(i_tmem) < ED_val_phen_coldtemp)then - ncolddays = ncolddays + 1 - endif - enddo - - ! Here is where we do the GDD accumulation calculation - ! - ! reset GDD on set dates - if (hlm_day_of_year == gddstart)then - currentSite%grow_deg_days = 0._r8 - endif - ! - ! accumulate the GDD using daily mean temperatures - ! Don't accumulate GDD during the growing season (that wouldn't make sense) - if (temp_in_C .gt. 0._r8 .and. currentSite%cstatus == phen_cstat_iscold) then - currentSite%grow_deg_days = currentSite%grow_deg_days + temp_in_C - endif - - !this logic is to prevent GDD accumulating after the leaves have fallen and before the - ! beginnning of the accumulation period, to prevend erroneous autumn leaf flushing. - if(model_day_int>365)then !only do this after the first year to prevent odd behaviour - - if(currentSite%lat .gt. 0.0_r8)then !Northern Hemisphere - ! In the north, don't accumulate when we are past the leaf fall date. - ! Accumulation starts on day 1 of year in NH. - ! The 180 is to prevent going into an 'always off' state after initialization - if( model_day_int .gt. currentSite%cleafoffdate.and.hlm_day_of_year.gt.180)then ! - currentSite%grow_deg_days = 0._r8 - endif - else !Southern Hemisphere - ! In the South, don't accumulate after the leaf off date, and before the start of - ! the accumulation phase (day 181). - if(model_day_int .gt. currentSite%cleafoffdate.and.hlm_day_of_year.lt.gddstart) then! - currentSite%grow_deg_days = 0._r8 - endif - endif - endif !year1 - - ! Calculate the number of days since the leaves last came on - ! and off. If this is the beginning of the simulation, that day might - ! not had occured yet, so set it to last year to get things rolling - - if (model_day_int < currentSite%cleafoffdate) then - dayssincecleafoff = model_day_int - (currentSite%cleafoffdate - 365) - else - dayssincecleafoff = model_day_int - currentSite%cleafoffdate - end if - - if (model_day_int < currentSite%cleafondate) then - dayssincecleafon = model_day_int - (currentSite%cleafondate-365) - else - dayssincecleafon = model_day_int - currentSite%cleafondate - end if - - - - !LEAF ON: COLD DECIDUOUS. Needs to - !1) have exceeded the growing degree day threshold - !2) The leaves should not be on already - !3) There should have been at least one chilling day in the counting period. - ! this prevents tropical or warm climate plants that are "cold-deciduous" - ! from ever re-flushing after they have reached their maximum age (thus - ! preventing them from competing - - if ( (currentSite%cstatus == phen_cstat_iscold .or. & - currentSite%cstatus == phen_cstat_nevercold) .and. & - (currentSite%grow_deg_days > gdd_threshold) .and. & - (dayssincecleafoff > ED_val_phen_mindayson) .and. & - (currentSite%nchilldays >= 1)) then - currentSite%cstatus = phen_cstat_notcold ! Set to not-cold status (leaves can come on) - currentSite%cleafondate = model_day_int - dayssincecleafon = 0 - currentSite%grow_deg_days = 0._r8 ! zero GDD for the rest of the year until counting season begins. - if ( debug ) write(fates_log(),*) 'leaves on' - endif !GDD - - - - - !LEAF OFF: COLD THRESHOLD - !Needs to: - !1) have exceeded the number of cold days threshold - !2) have exceeded the minimum leafon time. - !3) The leaves should not be off already - !4) The day of simulation should be larger than the counting period. - - - if ( (currentSite%cstatus == phen_cstat_notcold) .and. & - (model_day_int > num_vegtemp_mem) .and. & - (ncolddays > ED_val_phen_ncolddayslim) .and. & - (dayssincecleafon > ED_val_phen_mindayson) )then - - currentSite%grow_deg_days = 0._r8 ! The equations for Botta et al - ! are for calculations of - ! first flush, but if we dont - ! clear this value, it will cause - ! leaves to flush later in the year - currentSite%cstatus = phen_cstat_iscold ! alter status of site to 'leaves off' - currentSite%cleafoffdate = model_day_int ! record leaf off date - - if ( debug ) write(fates_log(),*) 'leaves off' - endif - - ! LEAF OFF: COLD LIFESPAN THRESHOLD - ! NOTE: Some areas of the planet will never generate a cold day - ! and thus %nchilldays will never go from zero to 1. The following logic - ! when coupled with this fact will essentially prevent cold-deciduous - ! plants from re-emerging in areas without at least some cold days - - if( (currentSite%cstatus == phen_cstat_notcold) .and. & - (dayssincecleafoff > 400)) then ! remove leaves after a whole year - ! when there is no 'off' period. - currentSite%grow_deg_days = 0._r8 - - currentSite%cstatus = phen_cstat_nevercold ! alter status of site to imply that this - ! site is never really cold enough - ! for cold deciduous - currentSite%cleafoffdate = model_day_int ! record leaf off date - - if ( debug ) write(fates_log(),*) 'leaves off' - endif - - !-----------------Drought Phenology--------------------! - ! Principles of drought-deciduos phenology model... - ! The 'is_drought' flag is false when leaves are on, and true when leaves area off. - ! The following sets those site-level flags, which are acted on in phenology_deciduos. - ! A* The leaves live for either the length of time the soil moisture is over the threshold - ! or the lifetime of the leaves, whichever is shorter. - ! B*: If the soil is only wet for a very short time, then the leaves stay on for 100 days - ! C*: The leaves are only permitted to come ON for a 60 day window around when they last came on, - ! to prevent 'flickering' on in response to wet season storms - ! D*: We don't allow anything to happen in the first ten days to allow the water memory window - ! to come into equlibirium. - ! E*: If the soil is always wet, the leaves come on at the beginning of the window, and then - ! last for their lifespan. - ! ISSUES - ! 1. It's not clear what water content we should track. Here we are tracking the top layer, - ! but we probably should track something like BTRAN, but BTRAN is defined for each PFT, - ! and there could potentially be more than one stress-dec PFT.... ? - ! 2. In the beginning, the window is set at an arbitrary time of the year, so the leaves - ! might come on in the dry season, using up stored reserves - ! for the stress-dec plants, and potentially killing them. To get around this, - ! we need to read in the 'leaf on' date from some kind of start-up file - ! but we would need that to happen for every resolution, etc. - ! 3. Will this methodology properly kill off the stress-dec trees where there is no - ! water stress? What about where the wet period coincides with the warm period? - ! We would just get them overlapping with the cold-dec trees, even though that isn't appropriate - ! Why don't the drought deciduous trees grow in the North? - ! Is cold decidousness maybe even the same as drought deciduosness there (and so does this - ! distinction actually matter??).... - - ! Accumulate surface water memory of last 10 days. - ! Liquid volume in ground layer (m3/m3) - do i_wmem = 1,numWaterMem-1 !shift memory along one - currentSite%water_memory(numWaterMem+1-i_wmem) = currentSite%water_memory(numWaterMem-i_wmem) - enddo - currentSite%water_memory(1) = bc_in%h2o_liqvol_sl(ilayer_swater) - - ! Calculate the mean water content over the last 10 days (m3/m3) - mean_10day_liqvol = sum(currentSite%water_memory(1:numWaterMem))/real(numWaterMem,r8) - - ! In drought phenology, we often need to force the leaves to stay - ! on or off as moisture fluctuates... - - ! Calculate days since leaves have come off, but make a provision - ! for the first year of simulation, we have to assume a leaf drop - ! date to start, so if that is in the future, set it to last year - - if (model_day_int < currentSite%dleafoffdate) then - dayssincedleafoff = model_day_int - (currentSite%dleafoffdate-365) - else - dayssincedleafoff = model_day_int - currentSite%dleafoffdate - endif - - ! the leaves are on. How long have they been on? - if (model_day_int < currentSite%dleafondate) then - dayssincedleafon = model_day_int - (currentSite%dleafondate-365) - else - dayssincedleafon = model_day_int - currentSite%dleafondate - endif - - ! LEAF ON: DROUGHT DECIDUOUS WETNESS - ! Here, we used a window of oppurtunity to determine if we are - ! close to the time when then leaves came on last year - - ! Has it been ... - ! a) a year, plus or minus 1 month since we last had leaf-on? - ! b) Has there also been at least a nominaly short amount of "leaf-off" - ! c) is the model day at least > 10 (let soil water spin-up) - ! Note that cold-starts begin in the "leaf-on" - ! status - if ( (currentSite%dstatus == phen_dstat_timeoff .or. & - currentSite%dstatus == phen_dstat_moistoff) .and. & - (model_day_int > numWaterMem) .and. & - (dayssincedleafon >= 365-30 .and. dayssincedleafon <= 365+30 ) .and. & - (dayssincedleafoff > ED_val_phen_doff_time) ) then - - ! If leaves are off, and have been off for at least a few days - ! and the time is consistent with the correct - ! time window... test if the moisture conditions allow for leaf-on - - if ( mean_10day_liqvol >= ED_val_phen_drought_threshold ) then - currentSite%dstatus = phen_dstat_moiston ! set status to leaf-on - currentSite%dleafondate = model_day_int ! save the model day we start flushing - dayssincedleafon = 0 - endif - endif - - ! LEAF ON: DROUGHT DECIDUOUS TIME EXCEEDANCE - ! If we still haven't done budburst by end of window, then force it - - ! If the status is "phen_dstat_moistoff", it means this site currently has - ! leaves off due to actual moisture limitations. - ! So we trigger bud-burst at the end of the month since - ! last year's bud-burst. If this is imposed, then we set the new - ! status to indicate bud-burst was forced by timing - - if( currentSite%dstatus == phen_dstat_moistoff ) then - if ( dayssincedleafon > 365+30 ) then - currentSite%dstatus = phen_dstat_timeon ! force budburst! - currentSite%dleafondate = model_day_int ! record leaf on date - dayssincedleafon = 0 - end if - end if - - ! But if leaves are off due to time, then we enforce - ! a longer cool-down (because this is a perrenially wet system) - - if(currentSite%dstatus == phen_dstat_timeoff ) then - if (dayssincedleafoff > min_daysoff_dforcedflush) then - currentSite%dstatus = phen_dstat_timeon ! force budburst! - currentSite%dleafondate = model_day_int ! record leaf on date - dayssincedleafon = 0 - end if - end if - - ! LEAF OFF: DROUGHT DECIDUOUS LIFESPAN - if the leaf gets to - ! the end of its useful life. A*, E* - ! i.e. Are the leaves rouhgly at the end of their lives? - - if ( (currentSite%dstatus == phen_dstat_moiston .or. & - currentSite%dstatus == phen_dstat_timeon ) .and. & - (dayssincedleafon > canopy_leaf_lifespan) )then - currentSite%dstatus = phen_dstat_timeoff !alter status of site to 'leaves off' - currentSite%dleafoffdate = model_day_int !record leaf on date - endif - - ! LEAF OFF: DROUGHT DECIDUOUS DRYNESS - if the soil gets too dry, - ! and the leaves have already been on a while... - - if ( (currentSite%dstatus == phen_dstat_moiston .or. & - currentSite%dstatus == phen_dstat_timeon ) .and. & - (model_day_int > numWaterMem) .and. & - (mean_10day_liqvol <= ED_val_phen_drought_threshold) .and. & - (dayssincedleafon > dleafon_drycheck ) ) then - currentSite%dstatus = phen_dstat_moistoff ! alter status of site to 'leaves off' - currentSite%dleafoffdate = model_day_int ! record leaf on date - endif - - call phenology_leafonoff(currentSite) - - end subroutine phenology - - ! ============================================================================ - subroutine phenology_leafonoff(currentSite) - ! - ! !DESCRIPTION: - ! Controls the leaf on and off economics - ! - ! !USES: - ! - ! !ARGUMENTS: - type(ed_site_type), intent(inout), target :: currentSite - ! - ! !LOCAL VARIABLES: - type(ed_patch_type) , pointer :: currentPatch - type(ed_cohort_type), pointer :: currentCohort - - real(r8) :: leaf_c ! leaf carbon [kg] - real(r8) :: sapw_c ! sapwood carbon [kg] - real(r8) :: struct_c ! structural wood carbon [kg] - real(r8) :: store_c ! storage carbon [kg] - real(r8) :: store_c_transfer_frac ! Fraction of storage carbon used to flush leaves - real(r8) :: totalmemory ! total memory of carbon [kg] - integer :: ipft - real(r8), parameter :: leaf_drop_fraction = 1.0_r8 - real(r8), parameter :: carbon_store_buffer = 0.10_r8 - real(r8) :: stem_drop_fraction - !------------------------------------------------------------------------ - - currentPatch => CurrentSite%oldest_patch - - do while(associated(currentPatch)) - currentCohort => currentPatch%tallest - do while(associated(currentCohort)) - - ipft = currentCohort%pft - - ! Retrieve existing leaf and storage carbon - - if(debug) call currentCohort%prt%CheckMassConservation(ipft,0) - - store_c = currentCohort%prt%GetState(store_organ, all_carbon_elements) - leaf_c = currentCohort%prt%GetState(leaf_organ, all_carbon_elements) - sapw_c = currentCohort%prt%GetState(sapw_organ, all_carbon_elements) - struct_c = currentCohort%prt%GetState(struct_organ, all_carbon_elements) - - stem_drop_fraction = EDPftvarcon_inst%phen_stem_drop_fraction(ipft) - - ! COLD LEAF ON - ! The site level flags signify that it is no-longer too cold - ! for leaves. Time to signal flushing - - if (prt_params%season_decid(ipft) == itrue)then - if ( currentSite%cstatus == phen_cstat_notcold )then ! we have just moved to leaves being on . - if (currentCohort%status_coh == leaves_off)then ! Are the leaves currently off? - currentCohort%status_coh = leaves_on ! Leaves are on, so change status to - ! stop flow of carbon out of bstore. - - if(store_c>nearzero) then - ! flush either the amount required from the laimemory, or -most- of the storage pool - ! RF: added a criterion to stop the entire store pool emptying and triggering termination mortality - ! n.b. this might not be necessary if we adopted a more gradual approach to leaf flushing... - store_c_transfer_frac = min((EDPftvarcon_inst%phenflush_fraction(ipft)* & - currentCohort%laimemory)/store_c,(1.0_r8-carbon_store_buffer)) - - if(prt_params%woody(ipft).ne.itrue)then - totalmemory=currentCohort%laimemory+currentCohort%sapwmemory+currentCohort%structmemory - store_c_transfer_frac = min((EDPftvarcon_inst%phenflush_fraction(ipft)* & - totalmemory)/store_c, (1.0_r8-carbon_store_buffer)) - endif - - else - store_c_transfer_frac = 0.0_r8 - end if - - ! This call will request that storage carbon will be transferred to - ! leaf tissues. It is specified as a fraction of the available storage - if(prt_params%woody(ipft) == itrue) then - - call PRTPhenologyFlush(currentCohort%prt, ipft, leaf_organ, store_c_transfer_frac) - currentCohort%laimemory = 0.0_r8 - - else - - ! Check that the stem drop fraction is set to non-zero amount otherwise flush all carbon store to leaves - if (stem_drop_fraction .gt. 0.0_r8) then - - call PRTPhenologyFlush(currentCohort%prt, ipft, leaf_organ, & - store_c_transfer_frac*currentCohort%laimemory/totalmemory) - - call PRTPhenologyFlush(currentCohort%prt, ipft, sapw_organ, & - store_c_transfer_frac*currentCohort%sapwmemory/totalmemory) - - call PRTPhenologyFlush(currentCohort%prt, ipft, struct_organ, & - store_c_transfer_frac*currentCohort%structmemory/totalmemory) - - else - - call PRTPhenologyFlush(currentCohort%prt, ipft, leaf_organ, & - store_c_transfer_frac) - - end if - - currentCohort%laimemory = 0.0_r8 - currentCohort%structmemory = 0.0_r8 - currentCohort%sapwmemory = 0.0_r8 - - endif - endif !pft phenology - endif ! growing season - - !COLD LEAF OFF - if (currentSite%cstatus == phen_cstat_nevercold .or. & - currentSite%cstatus == phen_cstat_iscold) then ! past leaf drop day? Leaves still on tree? - - if (currentCohort%status_coh == leaves_on) then ! leaves have not dropped - - ! leaf off occur on individuals bigger than specific size for grass - if (currentCohort%dbh > EDPftvarcon_inst%phen_cold_size_threshold(ipft) & - .or. prt_params%woody(ipft)==itrue) then - - ! This sets the cohort to the "leaves off" flag - currentCohort%status_coh = leaves_off - - ! Remember what the lai was (leaf mass actually) was for next year - ! the same amount back on in the spring... - - currentCohort%laimemory = leaf_c - - ! Drop Leaves (this routine will update the leaf state variables, - ! for carbon and any other element that are prognostic. It will - ! also track the turnover masses that will be sent to litter later on) - - call PRTDeciduousTurnover(currentCohort%prt,ipft, & - leaf_organ, leaf_drop_fraction) - - if(prt_params%woody(ipft).ne.itrue)then - - currentCohort%sapwmemory = sapw_c * stem_drop_fraction - - currentCohort%structmemory = struct_c * stem_drop_fraction - - call PRTDeciduousTurnover(currentCohort%prt,ipft, & - sapw_organ, stem_drop_fraction) - - call PRTDeciduousTurnover(currentCohort%prt,ipft, & - struct_organ, stem_drop_fraction) - - endif ! woody plant check - endif ! individual dbh size check - endif !leaf status - endif !currentSite status - endif !season_decid - - ! DROUGHT LEAF ON - ! Site level flag indicates it is no longer in drought condition - ! deciduous plants can flush - - if (prt_params%stress_decid(ipft) == itrue )then - - if (currentSite%dstatus == phen_dstat_moiston .or. & - currentSite%dstatus == phen_dstat_timeon )then - - ! we have just moved to leaves being on . - if (currentCohort%status_coh == leaves_off)then - - !is it the leaf-on day? Are the leaves currently off? - - currentCohort%status_coh = leaves_on ! Leaves are on, so change status to - ! stop flow of carbon out of bstore. - - if(store_c>nearzero) then - - store_c_transfer_frac = & - min((EDPftvarcon_inst%phenflush_fraction(ipft)*currentCohort%laimemory)/store_c, & - (1.0_r8-carbon_store_buffer)) - - if(prt_params%woody(ipft).ne.itrue)then - - totalmemory=currentCohort%laimemory+currentCohort%sapwmemory+currentCohort%structmemory - store_c_transfer_frac = min(EDPftvarcon_inst%phenflush_fraction(ipft)*totalmemory/store_c, & - (1.0_r8-carbon_store_buffer)) - - endif - - else - store_c_transfer_frac = 0.0_r8 - endif - - ! This call will request that storage carbon will be transferred to - ! leaf tissues. It is specified as a fraction of the available storage - if(prt_params%woody(ipft) == itrue) then - - call PRTPhenologyFlush(currentCohort%prt, ipft, & - leaf_organ, store_c_transfer_frac) - - currentCohort%laimemory = 0.0_r8 - - else - - ! Check that the stem drop fraction is set to non-zero amount otherwise flush all carbon store to leaves - if (stem_drop_fraction .gt. 0.0_r8) then - - call PRTPhenologyFlush(currentCohort%prt, ipft, leaf_organ, & - store_c_transfer_frac*currentCohort%laimemory/totalmemory) - - call PRTPhenologyFlush(currentCohort%prt, ipft, sapw_organ, & - store_c_transfer_frac*currentCohort%sapwmemory/totalmemory) - - call PRTPhenologyFlush(currentCohort%prt, ipft, struct_organ, & - store_c_transfer_frac*currentCohort%structmemory/totalmemory) - - else - - call PRTPhenologyFlush(currentCohort%prt, ipft, leaf_organ, & - store_c_transfer_frac) - - end if - - currentCohort%laimemory = 0.0_r8 - currentCohort%structmemory = 0.0_r8 - currentCohort%sapwmemory = 0.0_r8 - - endif ! woody plant check - endif !currentCohort status again? - endif !currentSite status - - !DROUGHT LEAF OFF - if (currentSite%dstatus == phen_dstat_moistoff .or. & - currentSite%dstatus == phen_dstat_timeoff) then - - if (currentCohort%status_coh == leaves_on) then ! leaves have not dropped - - ! This sets the cohort to the "leaves off" flag - currentCohort%status_coh = leaves_off - - ! Remember what the lai (leaf mass actually) was for next year - currentCohort%laimemory = leaf_c - - call PRTDeciduousTurnover(currentCohort%prt,ipft, & - leaf_organ, leaf_drop_fraction) - - if(prt_params%woody(ipft).ne.itrue)then - - currentCohort%sapwmemory = sapw_c * stem_drop_fraction - currentCohort%structmemory = struct_c * stem_drop_fraction - - call PRTDeciduousTurnover(currentCohort%prt,ipft, & - sapw_organ, stem_drop_fraction) - - call PRTDeciduousTurnover(currentCohort%prt,ipft, & - struct_organ, stem_drop_fraction) - endif - - endif - endif !status - endif !drought dec. - - if(debug) call currentCohort%prt%CheckMassConservation(ipft,1) - - currentCohort => currentCohort%shorter - enddo !currentCohort - - currentPatch => currentPatch%younger - - enddo !currentPatch - - end subroutine phenology_leafonoff - - - ! ===================================================================================== - - subroutine SeedIn( currentSite, bc_in ) - - ! ----------------------------------------------------------------------------------- - ! Flux from plants into the seed pool. - ! It is assumed that allocation to seed on living pools has already been calculated - ! at the daily time step. - ! Note: Some seed generation can occur during disturbance. It is assumed that - ! some plants use their storage upon death to create seeds, but this in only - ! triggered during non-fire and non-logging events. See - ! subroutine mortality_litter_fluxes() and DistributeSeeds(), look for - ! parameter allom_frbstor_repro - ! ----------------------------------------------------------------------------------- - - - ! !USES: - use EDTypesMod, only : area - use EDTypesMod, only : homogenize_seed_pfts - !use FatesInterfaceTypesMod, only : hlm_use_fixed_biogeog ! For future reduced complexity? - ! - ! !ARGUMENTS - type(ed_site_type), intent(inout), target :: currentSite - type(bc_in_type), intent(in) :: bc_in - - type(ed_patch_type), pointer :: currentPatch - type(litter_type), pointer :: litt - type(ed_cohort_type), pointer :: currentCohort - type(site_massbal_type), pointer :: site_mass - - integer :: pft - real(r8) :: store_m_to_repro ! mass sent from storage to reproduction upon death [kg/plant] - real(r8) :: site_seed_rain(maxpft) ! This is the sum of seed-rain for the site [kg/site/day] - real(r8) :: seed_in_external ! Mass of externally generated seeds [kg/m2/day] - real(r8) :: seed_stoich ! Mass ratio of nutrient per C12 in seeds [kg/kg] - real(r8) :: repro_mass_prod ! Mass of reproductive material produced [kg/day] ; added by ahb 7/8/2021 - real(r8), parameter :: repro_frac_seed = 0.5 !added by ahb 7/12/2021; move this to param file - real(r8) :: seed_prod ! Seed produced in this dynamics step [kg/day] - real(r8) :: non_seed_repro_prod ! Mass of non-seed reproductive material produced [kg/day] ; added by ahb 7/10/2021 - integer :: n_litt_types ! number of litter element types (c,n,p, etc) - integer :: el ! loop counter for litter element types - integer :: element_id ! element id consistent with parteh/PRTGenericMod.F90 - !------------------------------------------------------------------------------------ - - do el = 1, num_elements - - site_seed_rain(:) = 0._r8 - - element_id = element_list(el) - - site_mass => currentSite%mass_balance(el) - - ! Loop over all patches and sum up the seed input for each PFT - currentPatch => currentSite%oldest_patch - do while (associated(currentPatch)) - - currentCohort => currentPatch%tallest - !litt => currentPatch%litter(el) !added by ahb - do while (associated(currentCohort)) - - pft = currentCohort%pft - - ! a certain fraction of bstore might go to clonal reproduction when plants die - ! (since this is only applied to the dying portion of the cohort - ! we do not actually pair down the storage via PARTEH, instead - ! we just make sure that we don't send a portion of the storage - ! to the litter in CWDInput) - ! units = [kg/ha/day] = [kg] * [fraction] * [plants/ha/year] * [year/day] - store_m_to_repro = -currentCohort%prt%GetState(store_organ,element_id) * & - EDPftvarcon_inst%allom_frbstor_repro(pft)*currentCohort%dndt*years_per_day - - ! Transfer all reproductive tissues into seed production - ! The following call to PRTReproRelease, will return the mass - ! of seeds [kg] released by the plant, per the mass_fraction - ! specified as input. This routine will also remove the mass - ! from the parteh state-variable. - - - - - - !START ahb changes - - !-------------------------------------------------------------------------- - !original code - call PRTReproRelease(currentCohort%prt,repro_organ,element_id, & - 1.0_r8, seed_prod) - !-------------------------------------------------------------------------- - - !-------------------------------------------------------------------------- - !ahb's new code - !the original code sends all reproductive tissue to seed - !This new code, added by ahb, is designed to send some reproductive biomass - !straight to the leaf litter pool to account for non-seed reproductive - !biomass. For now, ahb does this after the call to the - !PRTReproRelease function, but a better solution would probably be to do - !this within the PRTReproRelease module in parteh/PRTLossFluxesMod.F90::L342 - !by adding new live reproductive organs (ahb needs help with this). - - !call PRTReproRelease(currentCohort%prt,repro_organ,element_id, & - ! 1.0_r8, repro_mass_prod) !ahb changed from seed_prod to repro_mass_prod - - !seed_prod = repro_mass_prod * repro_frac_seed ! seed production per ind. (ahb) - ! only a fraction of reproductive (ahb) - ! mass is seed (ahb) - - !non_seed_repro_prod = repro_mass_prod * (1.0_r8 - repro_frac_seed) !non-seed repro (ahb) - !mass per ind. (ahb) - - !litt%seed_decay(pft) = non_seed_repro_prod * currentCohort%n / area !send non-seed repro mass to seed decay pool - !--------------------------------------------------------------------------- - - !END ahb changes - - - - - - if(element_id==carbon12_element)then - currentcohort%seed_prod = seed_prod - end if - - site_seed_rain(pft) = site_seed_rain(pft) + & - (seed_prod * currentCohort%n + store_m_to_repro) - - currentCohort => currentCohort%shorter - enddo !cohort loop - - currentPatch => currentPatch%younger - enddo - - ! We can choose to homogenize seeds. This is simple, we just - ! add up all the seed from each pft at the site level, and then - ! equally distribute to the PFT pools - if ( homogenize_seed_pfts ) then - site_seed_rain(1:numpft) = sum(site_seed_rain(:))/real(numpft,r8) - end if - - - ! Loop over all patches again and disperse the mixed seeds into the input flux - ! arrays - - ! Loop over all patches and sum up the seed input for each PFT - currentPatch => currentSite%oldest_patch - do while (associated(currentPatch)) - - litt => currentPatch%litter(el) - do pft = 1,numpft - - if(currentSite%use_this_pft(pft).eq.itrue)then - ! Seed input from local sources (within site) - litt%seed_in_local(pft) = litt%seed_in_local(pft) + site_seed_rain(pft)/area - - !new code 7/14/2021 ahb - !-------------------------------- - litt%seed_decay(pft) = litt%seed_in_local(pft) * (1.0_r8 - repro_frac_seed) !ahb - !-------------------------------- - - ! If there is forced external seed rain, we calculate the input mass flux - ! from the different elements, usung the seed optimal stoichiometry - ! for non-carbon - select case(element_id) - case(carbon12_element) - seed_stoich = 1._r8 - case(nitrogen_element) - seed_stoich = prt_params%nitr_recr_stoich(pft) - case(phosphorus_element) - seed_stoich = prt_params%phos_recr_stoich(pft) - case default - write(fates_log(), *) 'undefined element specified' - write(fates_log(), *) 'while defining forced external seed mass flux' - call endrun(msg=errMsg(sourcefile, __LINE__)) - end select - - ! Seed input from external sources (user param seed rain, or dispersal model) - seed_in_external = seed_stoich*EDPftvarcon_inst%seed_suppl(pft)*years_per_day - litt%seed_in_extern(pft) = litt%seed_in_extern(pft) + seed_in_external - - ! Seeds entering externally [kg/site/day] - site_mass%seed_in = site_mass%seed_in + seed_in_external*currentPatch%area - end if !use this pft - enddo - - - currentPatch => currentPatch%younger - enddo - - end do - - return - end subroutine SeedIn - - ! ============================================================================ - - subroutine SeedDecay( litt ) - ! - ! !DESCRIPTION: - ! Flux from seed pool into leaf litter pool - ! - ! !ARGUMENTS - type(litter_type) :: litt - ! - ! !LOCAL VARIABLES: - integer :: pft - !---------------------------------------------------------------------- - - ! default value from Liscke and Loffler 2006 ; making this a PFT-specific parameter - ! decays the seed pool according to exponential model - ! seed_decay_rate is in yr-1 - ! seed_decay is kg/day - ! Assume that decay rates are same for all chemical species - - do pft = 1,numpft - litt%seed_decay(pft) = litt%seed(pft) * & - EDPftvarcon_inst%seed_decay_rate(pft)*years_per_day + & ! "+ &" added by ahb (7/10/2021) - litt%seed_decay(pft) ! line added by ahb so that the flux from non-seed reproductive - ! biomass (from SeedIn subroutine) is not lost (7/10/2021) - - litt%seed_germ_decay(pft) = litt%seed_germ(pft) * & - EDPftvarcon_inst%seed_decay_rate(pft)*years_per_day - - enddo - - return - end subroutine SeedDecay - - ! ============================================================================ - subroutine SeedGermination( litt, cold_stat, drought_stat ) - ! - ! !DESCRIPTION: - ! Flux from seed pool into sapling pool - ! - ! !USES: - - ! - ! !ARGUMENTS - type(litter_type) :: litt - integer, intent(in) :: cold_stat ! Is the site in cold leaf-off status? - integer, intent(in) :: drought_stat ! Is the site in drought leaf-off status? - ! - ! !LOCAL VARIABLES: - integer :: pft - - - real(r8), parameter :: max_germination = 1.0_r8 ! Cap on germination rates. - ! KgC/m2/yr Lishcke et al. 2009 - - ! Turning of this cap? because the cap will impose changes on proportionality - ! of nutrients. (RGK 02-2019) - !real(r8), parameter :: max_germination = 1.e6_r8 ! Force to very high number - - !---------------------------------------------------------------------- - - ! germination_rate is being pulled to PFT parameter; units are 1/yr - ! thus the mortality rate of seed -> recruit (in units of carbon) - ! is seed_decay_rate(p)/germination_rate(p) - ! and thus the mortality rate (in units of individuals) is the product of - ! that times the ratio of (hypothetical) seed mass to recruit biomass - - do pft = 1,numpft - litt%seed_germ_in(pft) = min(litt%seed(pft) * EDPftvarcon_inst%germination_rate(pft), & - max_germination)*years_per_day - - !set the germination only under the growing season...c.xu - - if ((prt_params%season_decid(pft) == itrue ) .and. & - (any(cold_stat == [phen_cstat_nevercold,phen_cstat_iscold]))) then - litt%seed_germ_in(pft) = 0.0_r8 - endif - if ((prt_params%stress_decid(pft) == itrue ) .and. & - (any(drought_stat == [phen_dstat_timeoff,phen_dstat_moistoff]))) then - litt%seed_germ_in(pft) = 0.0_r8 - end if - - - enddo - - end subroutine SeedGermination - - ! ===================================================================================== - - - - - - ! ===================================================================================== - - subroutine recruitment( currentSite, currentPatch, bc_in ) - ! - ! !DESCRIPTION: - ! spawn new cohorts of juveniles of each PFT - ! - ! !USES: - use FatesInterfaceTypesMod, only : hlm_use_ed_prescribed_phys - ! - ! !ARGUMENTS - type(ed_site_type), intent(inout), target :: currentSite - type(ed_patch_type), intent(inout), pointer :: currentPatch - type(bc_in_type), intent(in) :: bc_in - ! - ! !LOCAL VARIABLES: - class(prt_vartypes), pointer :: prt - integer :: ft - type (ed_cohort_type) , pointer :: temp_cohort - type (litter_type), pointer :: litt ! The litter object (carbon right now) - type(site_massbal_type), pointer :: site_mass ! For accounting total in-out mass fluxes - integer :: cohortstatus - integer :: el ! loop counter for element - integer :: element_id ! element index consistent with definitions in PRTGenericMod - integer :: iage ! age loop counter for leaf age bins - integer,parameter :: recruitstatus = 1 !weather it the new created cohorts is recruited or initialized - real(r8) :: c_leaf ! target leaf biomass [kgC] - real(r8) :: c_fnrt ! target fine root biomass [kgC] - real(r8) :: c_sapw ! target sapwood biomass [kgC] - real(r8) :: a_sapw ! target sapwood cross section are [m2] (dummy) - real(r8) :: c_agw ! target Above ground biomass [kgC] - real(r8) :: c_bgw ! target Below ground biomass [kgC] - real(r8) :: c_struct ! target Structural biomass [kgc] - real(r8) :: c_store ! target Storage biomass [kgC] - real(r8) :: m_leaf ! leaf mass (element agnostic) [kg] - real(r8) :: m_fnrt ! fine-root mass (element agnostic) [kg] - real(r8) :: m_sapw ! sapwood mass (element agnostic) [kg] - real(r8) :: m_agw ! AG wood mass (element agnostic) [kg] - real(r8) :: m_bgw ! BG wood mass (element agnostic) [kg] - real(r8) :: m_struct ! structural mass (element agnostic) [kg] - real(r8) :: m_store ! storage mass (element agnostic) [kg] - real(r8) :: m_repro ! reproductive mass (element agnostic) [kg] - real(r8) :: mass_avail ! The mass of each nutrient/carbon available in the seed_germination pool [kg] - real(r8) :: mass_demand ! Total mass demanded by the plant to achieve the stoichiometric targets - ! of all the organs in the recruits. Used for both [kg per plant] and [kg per cohort] - real(r8) :: stem_drop_fraction - - !---------------------------------------------------------------------- - - allocate(temp_cohort) ! create temporary cohort - call zero_cohort(temp_cohort) - - - do ft = 1,numpft - if(currentSite%use_this_pft(ft).eq.itrue)then - temp_cohort%canopy_trim = init_recruit_trim - temp_cohort%pft = ft - temp_cohort%hite = EDPftvarcon_inst%hgt_min(ft) - temp_cohort%coage = 0.0_r8 - stem_drop_fraction = EDPftvarcon_inst%phen_stem_drop_fraction(ft) - - call h2d_allom(temp_cohort%hite,ft,temp_cohort%dbh) - - ! Initialize live pools - call bleaf(temp_cohort%dbh,ft,temp_cohort%canopy_trim,c_leaf) - call bfineroot(temp_cohort%dbh,ft,temp_cohort%canopy_trim,c_fnrt) - call bsap_allom(temp_cohort%dbh,ft,temp_cohort%canopy_trim,a_sapw, c_sapw) - call bagw_allom(temp_cohort%dbh,ft,c_agw) - call bbgw_allom(temp_cohort%dbh,ft,c_bgw) - call bdead_allom(c_agw,c_bgw,c_sapw,ft,c_struct) - call bstore_allom(temp_cohort%dbh,ft,temp_cohort%canopy_trim,c_store) - - ! Default assumption is that leaves are on - cohortstatus = leaves_on - temp_cohort%laimemory = 0.0_r8 - temp_cohort%sapwmemory = 0.0_r8 - temp_cohort%structmemory = 0.0_r8 - - - ! But if the plant is seasonally (cold) deciduous, and the site status is flagged - ! as "cold", then set the cohort's status to leaves_off, and remember the leaf biomass - if ((prt_params%season_decid(ft) == itrue) .and. & - (any(currentSite%cstatus == [phen_cstat_nevercold,phen_cstat_iscold]))) then - temp_cohort%laimemory = c_leaf - c_leaf = 0.0_r8 - - ! If plant is not woody then set sapwood and structural biomass as well - if (prt_params%woody(ft).ne.itrue) then - temp_cohort%sapwmemory = c_sapw * stem_drop_fraction - temp_cohort%structmemory = c_struct * stem_drop_fraction - c_sapw = (1.0_r8 - stem_drop_fraction) * c_sapw - c_struct = (1.0_r8 - stem_drop_fraction) * c_struct - endif - cohortstatus = leaves_off - endif - - ! Or.. if the plant is drought deciduous, and the site status is flagged as - ! "in a drought", then likewise, set the cohort's status to leaves_off, and remember leaf - ! biomass - if ((prt_params%stress_decid(ft) == itrue) .and. & - (any(currentSite%dstatus == [phen_dstat_timeoff,phen_dstat_moistoff]))) then - temp_cohort%laimemory = c_leaf - c_leaf = 0.0_r8 - - ! If plant is not woody then set sapwood and structural biomass as well - if(prt_params%woody(ft).ne.itrue)then - temp_cohort%sapwmemory = c_sapw * stem_drop_fraction - temp_cohort%structmemory = c_struct * stem_drop_fraction - c_sapw = (1.0_r8 - stem_drop_fraction) * c_sapw - c_struct = (1.0_r8 - stem_drop_fraction) * c_struct - endif - cohortstatus = leaves_off - endif - - - ! Cycle through available carbon and nutrients, find the limiting element - ! to dictate the total number of plants that can be generated - - if ( (hlm_use_ed_prescribed_phys .eq. ifalse) .or. & - (EDPftvarcon_inst%prescribed_recruitment(ft) .lt. 0._r8) ) then - - temp_cohort%n = 1.e20_r8 - - do el = 1,num_elements - - element_id = element_list(el) - select case(element_id) - case(carbon12_element) - - mass_demand = c_struct+c_leaf+c_fnrt+c_sapw+c_store - - case(nitrogen_element) - - mass_demand = & - c_struct*prt_params%nitr_stoich_p2(ft,prt_params%organ_param_id(struct_organ)) + & - c_leaf*prt_params%nitr_stoich_p2(ft,prt_params%organ_param_id(leaf_organ)) + & - c_fnrt*prt_params%nitr_stoich_p2(ft,prt_params%organ_param_id(fnrt_organ)) + & - c_sapw*prt_params%nitr_stoich_p2(ft,prt_params%organ_param_id(sapw_organ)) + & - StorageNutrientTarget(ft, element_id, & - c_leaf*prt_params%nitr_stoich_p2(ft,prt_params%organ_param_id(leaf_organ)), & - c_fnrt*prt_params%nitr_stoich_p2(ft,prt_params%organ_param_id(fnrt_organ)), & - c_sapw*prt_params%nitr_stoich_p2(ft,prt_params%organ_param_id(sapw_organ)), & - c_struct*prt_params%nitr_stoich_p2(ft,prt_params%organ_param_id(struct_organ))) - - case(phosphorus_element) - - mass_demand = & - c_struct*prt_params%phos_stoich_p2(ft,prt_params%organ_param_id(struct_organ)) + & - c_leaf*prt_params%phos_stoich_p2(ft,prt_params%organ_param_id(leaf_organ)) + & - c_fnrt*prt_params%phos_stoich_p2(ft,prt_params%organ_param_id(fnrt_organ)) + & - c_sapw*prt_params%phos_stoich_p2(ft,prt_params%organ_param_id(sapw_organ)) + & - StorageNutrientTarget(ft, element_id, & - c_leaf*prt_params%phos_stoich_p2(ft,prt_params%organ_param_id(leaf_organ)), & - c_fnrt*prt_params%phos_stoich_p2(ft,prt_params%organ_param_id(fnrt_organ)), & - c_sapw*prt_params%phos_stoich_p2(ft,prt_params%organ_param_id(sapw_organ)), & - c_struct*prt_params%phos_stoich_p2(ft,prt_params%organ_param_id(struct_organ))) - - case default - write(fates_log(),*) 'Undefined element type in recruitment' - call endrun(msg=errMsg(sourcefile, __LINE__)) - end select - - mass_avail = currentPatch%area * currentPatch%litter(el)%seed_germ(ft) - - ! ------------------------------------------------------------------------ - ! Update number density if this is the limiting mass - ! ------------------------------------------------------------------------ - - temp_cohort%n = min(temp_cohort%n, mass_avail/mass_demand) - - end do - - - else - ! prescribed recruitment rates. number per sq. meter per year - temp_cohort%n = currentPatch%area * & - EDPftvarcon_inst%prescribed_recruitment(ft) * & - hlm_freq_day - endif - - ! Only bother allocating a new cohort if there is a reasonable amount of it - any_recruits: if (temp_cohort%n > min_n_safemath )then - - ! ----------------------------------------------------------------------------- - ! PART II. - ! Initialize the PARTEH object, and determine the initial masses of all - ! organs and elements. - ! ----------------------------------------------------------------------------- - prt => null() - call InitPRTObject(prt) - - do el = 1,num_elements - - element_id = element_list(el) - - ! If this is carbon12, then the initialization is straight forward - ! otherwise, we use stoichiometric ratios - select case(element_id) - case(carbon12_element) - - m_struct = c_struct - m_leaf = c_leaf - m_fnrt = c_fnrt - m_sapw = c_sapw - m_store = c_store - m_repro = 0._r8 - - case(nitrogen_element) - - m_struct = c_struct*prt_params%nitr_stoich_p2(ft,prt_params%organ_param_id(struct_organ)) - m_leaf = c_leaf*prt_params%nitr_stoich_p2(ft,prt_params%organ_param_id(leaf_organ)) - m_fnrt = c_fnrt*prt_params%nitr_stoich_p2(ft,prt_params%organ_param_id(fnrt_organ)) - m_sapw = c_sapw*prt_params%nitr_stoich_p2(ft,prt_params%organ_param_id(sapw_organ)) - m_store = StorageNutrientTarget(ft, element_id, m_leaf, m_fnrt, m_sapw, m_struct ) - m_repro = 0._r8 - - case(phosphorus_element) - - m_struct = c_struct*prt_params%phos_stoich_p2(ft,prt_params%organ_param_id(struct_organ)) - m_leaf = c_leaf*prt_params%phos_stoich_p2(ft,prt_params%organ_param_id(leaf_organ)) - m_fnrt = c_fnrt*prt_params%phos_stoich_p2(ft,prt_params%organ_param_id(fnrt_organ)) - m_sapw = c_sapw*prt_params%phos_stoich_p2(ft,prt_params%organ_param_id(sapw_organ)) - m_store = StorageNutrientTarget(ft, element_id, m_leaf, m_fnrt, m_sapw, m_struct ) - m_repro = 0._r8 - - end select - - select case(hlm_parteh_mode) - case (prt_carbon_allom_hyp,prt_cnp_flex_allom_hyp ) - - ! Put all of the leaf mass into the first bin - call SetState(prt,leaf_organ, element_id,m_leaf,1) - do iage = 2,nleafage - call SetState(prt,leaf_organ, element_id,0._r8,iage) - end do - - call SetState(prt,fnrt_organ, element_id, m_fnrt) - call SetState(prt,sapw_organ, element_id, m_sapw) - call SetState(prt,store_organ, element_id, m_store) - call SetState(prt,struct_organ, element_id, m_struct) - call SetState(prt,repro_organ, element_id, m_repro) - - case default - write(fates_log(),*) 'Unspecified PARTEH module during create_cohort' - call endrun(msg=errMsg(sourcefile, __LINE__)) - end select - - site_mass => currentSite%mass_balance(el) - - ! Remove mass from the germination pool. However, if we are use prescribed physiology, - ! AND the forced recruitment model, then we are not realling using the prognostic - ! seed_germination model, so we have to short circuit things. We send all of the - ! seed germination mass to an outflux pool, and use an arbitrary generic input flux - ! to balance out the new recruits. - - if ( (hlm_use_ed_prescribed_phys .eq. itrue ) .and. & - (EDPftvarcon_inst%prescribed_recruitment(ft) .ge. 0._r8 )) then - - site_mass%flux_generic_in = site_mass%flux_generic_in + & - temp_cohort%n*(m_struct + m_leaf + m_fnrt + m_sapw + m_store + m_repro) - - site_mass%flux_generic_out = site_mass%flux_generic_out + & - currentPatch%area * currentPatch%litter(el)%seed_germ(ft) - - currentPatch%litter(el)%seed_germ(ft) = 0._r8 - - - else - - currentPatch%litter(el)%seed_germ(ft) = currentPatch%litter(el)%seed_germ(ft) - & - temp_cohort%n / currentPatch%area * & - (m_struct + m_leaf + m_fnrt + m_sapw + m_store + m_repro) - - end if - - - - end do - - ! This call cycles through the initial conditions, and makes sure that they - ! are all initialized. - ! ----------------------------------------------------------------------------------- - - call prt%CheckInitialConditions() - - ! This initializes the cohort - call create_cohort(currentSite,currentPatch, temp_cohort%pft, temp_cohort%n, & - temp_cohort%hite, temp_cohort%coage, temp_cohort%dbh, prt, & - temp_cohort%laimemory, temp_cohort%sapwmemory, temp_cohort%structmemory, & - cohortstatus, recruitstatus, & - temp_cohort%canopy_trim, currentPatch%NCL_p, currentSite%spread, bc_in) - - ! Note that if hydraulics is on, the number of cohorts may had - ! changed due to hydraulic constraints. - ! This constaint is applied during "create_cohort" subroutine. - - ! keep track of how many individuals were recruited for passing to history - currentSite%recruitment_rate(ft) = currentSite%recruitment_rate(ft) + temp_cohort%n - - - endif any_recruits - endif !use_this_pft - enddo !pft loop - - deallocate(temp_cohort) ! delete temporary cohort - - end subroutine recruitment - - ! ============================================================================ - - subroutine CWDInput( currentSite, currentPatch, litt, bc_in) - - ! - ! !DESCRIPTION: - ! Generate litter fields from turnover. - ! Note, that the when this is called, the number density of the plants - ! has not been reduced from non-mortal turnover yet. - ! Thus, we need to avoid double counting losses from dying trees - ! and turnover in dying trees. - ! - ! !USES: - use SFParamsMod , only : SF_val_CWD_frac - - ! - ! !ARGUMENTS - type(ed_site_type), intent(inout), target :: currentSite - type(ed_patch_type),intent(inout), target :: currentPatch - type(litter_type),intent(inout),target :: litt - type(bc_in_type),intent(in) :: bc_in - - ! - ! !LOCAL VARIABLES: - type(ed_cohort_type), pointer :: currentCohort - type(site_fluxdiags_type), pointer :: flux_diags - type(site_massbal_type), pointer :: site_mass - integer :: c - real(r8) :: dead_n ! total understorey dead tree density - real(r8) :: dead_n_dlogging ! direct logging understory dead-tree density - real(r8) :: dead_n_ilogging ! indirect understory dead-tree density (logging) - real(r8) :: dead_n_natural ! understory dead density not associated - ! with direct logging - real(r8) :: leaf_m ! mass of the element of interest in the - ! leaf [kg] - real(r8) :: fnrt_m ! fine-root [kg] - real(r8) :: sapw_m ! sapwood [kg] - real(r8) :: struct_m ! structural [kg] - real(r8) :: store_m ! storage [kg] - real(r8) :: repro_m ! reproductive [kg] - real(r8) :: leaf_m_turnover ! leaf turnover [kg] - real(r8) :: fnrt_m_turnover - real(r8) :: sapw_m_turnover - real(r8) :: struct_m_turnover - real(r8) :: store_m_turnover - real(r8) :: repro_m_turnover - real(r8) :: dcmpy_frac ! Fraction of mass sent to decomposability pool - real(r8) :: plant_dens ! Number of plants per m2 - real(r8) :: bg_cwd_tot ! Total below-ground coarse woody debris - ! input flux - real(r8) :: root_fines_tot ! Total below-ground fine root coarse - ! woody debris - integer :: element_id ! element id consistent with parteh/PRTGenericMod.F90 - - real(r8) :: trunk_wood ! carbon flux into trunk products kgC/day/site - integer :: ilyr - integer :: pft - integer :: dcmpy ! decomposability pool index - integer :: numlevsoil ! Actual number of soil layers - !---------------------------------------------------------------------- - - ! ----------------------------------------------------------------------------------- - ! Other direct litter fluxes happen in phenology and in spawn_patches. - ! ----------------------------------------------------------------------------------- - - numlevsoil = currentSite%nlevsoil - - element_id = litt%element_id - - ! Object tracking flux diagnostics for each element - flux_diags => currentSite%flux_diags(element_pos(element_id)) - - ! Object tracking site level mass balance for each element - site_mass => currentSite%mass_balance(element_pos(element_id)) - - currentCohort => currentPatch%shortest - do while(associated(currentCohort)) - pft = currentCohort%pft - - call set_root_fraction(currentSite%rootfrac_scr, pft, currentSite%zi_soil, & - bc_in%max_rooting_depth_index_col) - - leaf_m_turnover = currentCohort%prt%GetTurnover(leaf_organ,element_id) - store_m_turnover = currentCohort%prt%GetTurnover(store_organ,element_id) - fnrt_m_turnover = currentCohort%prt%GetTurnover(fnrt_organ,element_id) - sapw_m_turnover = currentCohort%prt%GetTurnover(sapw_organ,element_id) - struct_m_turnover = currentCohort%prt%GetTurnover(struct_organ,element_id) - repro_m_turnover = currentCohort%prt%GetTurnover(repro_organ,element_id) - - leaf_m = currentCohort%prt%GetState(leaf_organ,element_id) - store_m = currentCohort%prt%GetState(store_organ,element_id) - fnrt_m = currentCohort%prt%GetState(fnrt_organ,element_id) - sapw_m = currentCohort%prt%GetState(sapw_organ,element_id) - struct_m = currentCohort%prt%GetState(struct_organ,element_id) - repro_m = currentCohort%prt%GetState(repro_organ,element_id) - - plant_dens = currentCohort%n/currentPatch%area - - ! --------------------------------------------------------------------------------- - ! PART 1 Litter fluxes from non-mortal tissue turnovers Kg/m2/day - ! Important note: Turnover has already been removed from the cohorts. - ! So, in the next part of this algorithm, when we send the biomass - ! from dying trees to the litter pools, we don't have to worry - ! about double counting. - ! --------------------------------------------------------------------------------- - - flux_diags%leaf_litter_input(pft) = & - flux_diags%leaf_litter_input(pft) + & - leaf_m_turnover * currentCohort%n - - root_fines_tot = (fnrt_m_turnover + store_m_turnover ) * & - plant_dens - - do dcmpy=1,ndcmpy - dcmpy_frac = GetDecompyFrac(pft,leaf_organ,dcmpy) - litt%leaf_fines_in(dcmpy) = litt%leaf_fines_in(dcmpy) + & - (leaf_m_turnover+repro_m_turnover) * plant_dens * dcmpy_frac - - dcmpy_frac = GetDecompyFrac(pft,fnrt_organ,dcmpy) - do ilyr = 1, numlevsoil - litt%root_fines_in(dcmpy,ilyr) = litt%root_fines_in(dcmpy,ilyr) + & - currentSite%rootfrac_scr(ilyr) * root_fines_tot * dcmpy_frac - end do - end do - - flux_diags%root_litter_input(pft) = & - flux_diags%root_litter_input(pft) + & - (fnrt_m_turnover + store_m_turnover ) * currentCohort%n - - - ! Assumption: turnover from deadwood and sapwood are lumped together in CWD pool - - do c = 1,ncwd - litt%ag_cwd_in(c) = litt%ag_cwd_in(c) + & - (sapw_m_turnover + struct_m_turnover) * & - SF_val_CWD_frac(c) * plant_dens * & - prt_params%allom_agb_frac(pft) - - flux_diags%cwd_ag_input(c) = flux_diags%cwd_ag_input(c) + & - (struct_m_turnover + sapw_m_turnover) * SF_val_CWD_frac(c) * & - prt_params%allom_agb_frac(pft) * currentCohort%n - - bg_cwd_tot = (sapw_m_turnover + struct_m_turnover) * & - SF_val_CWD_frac(c) * plant_dens * & - (1.0_r8-prt_params%allom_agb_frac(pft)) - - do ilyr = 1, numlevsoil - litt%bg_cwd_in(c,ilyr) = litt%bg_cwd_in(c,ilyr) + & - bg_cwd_tot * currentSite%rootfrac_scr(ilyr) - end do - - flux_diags%cwd_bg_input(c) = flux_diags%cwd_bg_input(c) + & - bg_cwd_tot*currentPatch%area - - enddo - - - ! --------------------------------------------------------------------------------- - ! PART 2 Litter fluxes from non-disturbance inducing mortality. Kg/m2/day - ! --------------------------------------------------------------------------------- - - ! Total number of dead (n/m2/day) - dead_n = -1.0_r8 * currentCohort%dndt/currentPatch%area*years_per_day - - if(currentCohort%canopy_layer > 1)then - - ! Total number of dead understory from direct logging - ! (it is possible that large harvestable trees are in the understory) - dead_n_dlogging = currentCohort%lmort_direct * & - currentCohort%n/currentPatch%area - - ! Total number of dead understory from indirect logging - dead_n_ilogging = (currentCohort%lmort_collateral + currentCohort%lmort_infra) * & - currentCohort%n/currentPatch%area - - else - - ! All mortality from logging in the canopy is - ! is disturbance generating - - dead_n_dlogging = 0._r8 - dead_n_ilogging = 0._r8 - - end if - - 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 - - root_fines_tot = dead_n * (fnrt_m + & - store_m*(1._r8-EDPftvarcon_inst%allom_frbstor_repro(pft)) ) - - do dcmpy=1,ndcmpy - - dcmpy_frac = GetDecompyFrac(pft,leaf_organ,dcmpy) - litt%leaf_fines_in(dcmpy) = litt%leaf_fines_in(dcmpy) + & - (leaf_m+repro_m) * dead_n * dcmpy_frac - - dcmpy_frac = GetDecompyFrac(pft,fnrt_organ,dcmpy) - do ilyr = 1, numlevsoil - litt%root_fines_in(dcmpy,ilyr) = litt%root_fines_in(dcmpy,ilyr) + & - root_fines_tot * currentSite%rootfrac_scr(ilyr) * dcmpy_frac - end do - end do - - flux_diags%root_litter_input(pft) = & - flux_diags%root_litter_input(pft) + & - root_fines_tot*currentPatch%area - - ! Track CWD inputs from dead plants - - do c = 1,ncwd - - ! Below-ground - - bg_cwd_tot = (struct_m + sapw_m) * & - SF_val_CWD_frac(c) * dead_n * & - (1.0_r8-prt_params%allom_agb_frac(pft)) - - do ilyr = 1, numlevsoil - litt%bg_cwd_in(c,ilyr) = litt%bg_cwd_in(c,ilyr) + & - currentSite%rootfrac_scr(ilyr) * bg_cwd_tot - end do - - flux_diags%cwd_bg_input(c) = flux_diags%cwd_bg_input(c) + & - bg_cwd_tot * currentPatch%area - - ! Send AGB component of boles from logging activities into the litter. - ! This includes fluxes from indirect modes of death, as well as the - ! non-exported boles due to direct harvesting. - - if (c==ncwd) then - - - trunk_wood = (struct_m + sapw_m) * & - SF_val_CWD_frac(c) * dead_n_dlogging * & - prt_params%allom_agb_frac(pft) - - site_mass%wood_product = site_mass%wood_product + & - trunk_wood * currentPatch%area * logging_export_frac - - ! Add AG wood to litter from the non-exported fraction of wood - ! from direct anthro sources - - 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) + & - trunk_wood * (1._r8-logging_export_frac) * currentPatch%area - - ! Add AG wood to litter from indirect anthro sources - - litt%ag_cwd_in(c) = litt%ag_cwd_in(c) + (struct_m + sapw_m) * & - SF_val_CWD_frac(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(c) * (dead_n_natural+dead_n_ilogging) * & - currentPatch%area * prt_params%allom_agb_frac(pft) - - else - - litt%ag_cwd_in(c) = litt%ag_cwd_in(c) + (struct_m + sapw_m) * & - SF_val_CWD_frac(c) * dead_n * & - prt_params%allom_agb_frac(pft) - - flux_diags%cwd_ag_input(c) = flux_diags%cwd_ag_input(c) + & - SF_val_CWD_frac(c) * dead_n * (struct_m + sapw_m) * & - currentPatch%area * prt_params%allom_agb_frac(pft) - - end if - - end do - - - ! Update diagnostics that track resource management - - if( element_id .eq. carbon12_element ) then - - currentSite%resources_management%delta_litter_stock = & - currentSite%resources_management%delta_litter_stock + & - (leaf_m + fnrt_m + store_m ) * & - (dead_n_ilogging+dead_n_dlogging) * currentPatch%area - - currentSite%resources_management%delta_biomass_stock = & - currentSite%resources_management%delta_biomass_stock + & - (leaf_m + fnrt_m + store_m ) * & - (dead_n_ilogging+dead_n_dlogging) *currentPatch%area - - currentSite%resources_management%trunk_product_site = & - currentSite%resources_management%trunk_product_site + & - trunk_wood * logging_export_frac * currentPatch%area - - do c = 1,ncwd - currentSite%resources_management%delta_litter_stock = & - currentSite%resources_management%delta_litter_stock + & - (struct_m + sapw_m) * & - SF_val_CWD_frac(c) * (dead_n_natural+dead_n_ilogging) * & - currentPatch%area - - currentSite%resources_management%delta_biomass_stock = & - currentSite%resources_management%delta_biomass_stock + & - (struct_m + sapw_m) * & - SF_val_CWD_frac(c) * dead_n * currentPatch%area - end do - - ! Update diagnostics that track resource management - currentSite%resources_management%delta_individual = & - currentSite%resources_management%delta_individual + & - (dead_n_dlogging+dead_n_ilogging) * hlm_freq_day * currentPatch%area - end if - - - currentCohort => currentCohort%taller - enddo ! end loop over cohorts - - - return - end subroutine CWDInput - - ! ===================================================================================== - - - subroutine fragmentation_scaler( currentPatch, bc_in) - ! - ! !DESCRIPTION: - ! Simple CWD fragmentation Model - ! FIX(SPM, 091914) this should be a function as it returns a value in - ! currentPatch%fragmentation_scaler - ! - ! !USES: - - use FatesSynchronizedParamsMod , only : FatesSynchronizedParamsInst - use FatesConstantsMod, only : tfrz => t_water_freeze_k_1atm - use FatesConstantsMod, only : pi => pi_const - ! - ! !ARGUMENTS - type(ed_patch_type), intent(inout) :: currentPatch - type(bc_in_type), intent(in) :: bc_in - - ! - ! !LOCAL VARIABLES: - logical :: use_century_tfunc = .false. - logical :: use_hlm_soil_scalar = .true. ! Use hlm input decomp fraction scalars - integer :: j - integer :: ifp ! Index of a FATES Patch "ifp" - real(r8) :: t_scalar ! temperature scalar - real(r8) :: w_scalar ! moisture scalar - real(r8) :: catanf ! hyperbolic temperature function from CENTURY - real(r8) :: catanf_30 ! hyperbolic temperature function from CENTURY - real(r8) :: t1 ! temperature argument - !---------------------------------------------------------------------- - - catanf(t1) = 11.75_r8 +(29.7_r8 / pi) * atan( pi * 0.031_r8 * ( t1 - 15.4_r8 )) - catanf_30 = catanf(30._r8) - - ifp = currentPatch%patchno - - ! Use the hlm temp and moisture decomp fractions by default - if ( use_hlm_soil_scalar ) then - - ! Calculate the fragmentation_scaler - currentPatch%fragmentation_scaler = min(1.0_r8,max(0.0_r8,bc_in%t_scalar_sisl * bc_in%w_scalar_sisl)) - - else - - if ( .not. use_century_tfunc ) then - !calculate rate constant scalar for soil temperature,assuming that the base rate constants - !are assigned for non-moisture limiting conditions at 25C. - if (bc_in%t_veg24_pa(ifp) >= tfrz) then - t_scalar = q10_mr**((bc_in%t_veg24_pa(ifp)-(tfrz+25._r8))/10._r8) - ! Q10**((t_soisno(c,j)-(tfrz+25._r8))/10._r8) - else - t_scalar = (q10_mr**(-25._r8/10._r8))*(q10_froz**((bc_in%t_veg24_pa(ifp)-tfrz)/10._r8)) - !Q10**(-25._r8/10._r8))*(froz_q10**((t_soisno(c,j)-tfrz)/10._r8) - endif - else - ! original century uses an arctangent function to calculate the - ! temperature dependence of decomposition - t_scalar = max(catanf(bc_in%t_veg24_pa(ifp)-tfrz)/catanf_30,0.01_r8) - endif - - !Moisture Limitations - !BTRAN APPROACH - is quite simple, but max's out decomp at all unstressed - !soil moisture values, which is not realistic. - !litter decomp is proportional to water limitation on average... - w_scalar = sum(currentPatch%btran_ft(1:numpft))/real(numpft,r8) - - ! Calculate the fragmentation_scaler - currentPatch%fragmentation_scaler(:) = min(1.0_r8,max(0.0_r8,t_scalar * w_scalar)) - - endif - - - end subroutine fragmentation_scaler - - ! ============================================================================ - - subroutine CWDOut( litt, fragmentation_scaler, nlev_eff_decomp ) - ! - ! !DESCRIPTION: - ! Simple CWD fragmentation Model - ! spawn new cohorts of juveniles of each PFT - ! - ! !USES: - use SFParamsMod, only : SF_val_max_decomp - - ! - ! !ARGUMENTS - type(litter_type),intent(inout),target :: litt - real(r8),intent(in) :: fragmentation_scaler(:) - - ! This is not necessarily every soil layer, this is the number - ! of effective layers that are active and can be sent - ! to the soil decomposition model - integer,intent(in) :: nlev_eff_decomp - - ! - ! !LOCAL VARIABLES: - integer :: c ! Fuel size class index - integer :: ilyr ! Soil layer index - integer :: dcmpy ! Decomposibility pool indexer - integer :: soil_layer_index = 1 ! Soil layer index associated with above ground litter - !---------------------------------------------------------------------- - - - ! Above ground litters are associated with the top soil layer temperature and - ! moisture scalars and fragmentation scalar associated with specified index value - ! is used for ag_cwd_frag and root_fines_frag calculations. - - do c = 1,ncwd - - litt%ag_cwd_frag(c) = litt%ag_cwd(c) * SF_val_max_decomp(c) * & - years_per_day * fragmentation_scaler(soil_layer_index) - - do ilyr = 1,nlev_eff_decomp - - litt%bg_cwd_frag(c,ilyr) = litt%bg_cwd(c,ilyr) * SF_val_max_decomp(c) * & - years_per_day * fragmentation_scaler(ilyr) - - enddo - end do - - ! this is the rate at which dropped leaves stop being part of the burnable pool - ! and begin to be part of the decomposing pool. This should probably be highly - ! sensitive to moisture, but also to the type of leaf thick leaves can dry out - ! before they are decomposed, for example. This section needs further scientific input. - - do dcmpy = 1,ndcmpy - - litt%leaf_fines_frag(dcmpy) = litt%leaf_fines(dcmpy) * & - years_per_day * SF_val_max_decomp(dl_sf) * fragmentation_scaler(soil_layer_index) - - do ilyr = 1,nlev_eff_decomp - litt%root_fines_frag(dcmpy,ilyr) = litt%root_fines(dcmpy,ilyr) * & - years_per_day * SF_val_max_decomp(dl_sf) * fragmentation_scaler(ilyr) - end do - enddo - - end subroutine CWDOut - -end module EDPhysiologyMod diff --git a/biogeochem/FatesLitterMod.F90 b/biogeochem/FatesLitterMod.F90 index dbcf05a9d4..be5ec48aa9 100644 --- a/biogeochem/FatesLitterMod.F90 +++ b/biogeochem/FatesLitterMod.F90 @@ -105,7 +105,6 @@ module FatesLitterMod real(r8),allocatable :: root_fines_frag(:,:) ! kg/m2/day real(r8), allocatable :: seed_decay(:) ! decay of viable seeds to litter [kg/m2/day] - real(r8), allocatable :: non_seed_repro_mass_decay(:) ! ahb, decay of non-seed reproductive mass [kg/m2/day] real(r8), allocatable :: seed_germ_decay(:) ! decay of germinated seeds to litter [kg/m2/day] real(r8), allocatable :: seed_germ_in(:) ! flux from viable to germinated seed [kg/m2/day] @@ -194,8 +193,6 @@ subroutine FuseLitter(this,self_area,donor_area,donor_litt) this%seed_decay(pft) = this%seed_decay(pft) * self_weight + & donor_litt%seed_decay(pft) * donor_weight - this%non_seed_repro_mass_decay(pft) = this%non_seed_repro_mass_decay(pft) * self_weight + & !ahb - donor_litt%non_seed_repro_mass_decay(pft) * donor_weight !ahb this%seed_germ_decay(pft) = this%seed_germ_decay(pft) * self_weight + & donor_litt%seed_germ_decay(pft) * donor_weight this%seed_germ_in(pft) = this%seed_germ_in(pft) * self_weight + & @@ -255,7 +252,6 @@ subroutine CopyLitter(this,donor_litt) this%leaf_fines_frag(:) = donor_litt%leaf_fines_frag(:) this%seed_decay(:) = donor_litt%seed_decay(:) - this%non_seed_repro_mass_decay(:) = donor_litt%non_seed_repro_mass_decay(:) !ahb this%seed_germ_decay(:) = donor_litt%seed_germ_decay(:) this%seed_germ_in(:) = donor_litt%seed_germ_in(:) this%root_fines(:,:) = donor_litt%root_fines(:,:) @@ -293,7 +289,6 @@ subroutine InitAllocate(this,numpft,numlevsoil,element_id) allocate(this%seed_germ(numpft)) allocate(this%seed_germ_in(numpft)) allocate(this%seed_germ_decay(numpft)) - allocate(this%non_seed_repro_mass_decay(numpft)) !ahb allocate(this%seed_decay(numpft)) ! Initialize everything to a nonsense flag @@ -317,7 +312,6 @@ subroutine InitAllocate(this,numpft,numlevsoil,element_id) this%root_fines_frag(:,:) = fates_unset_r8 this%seed_decay(:) = fates_unset_r8 - this%non_seed_repro_mass_decay(:) = fates_unset_r8 !ahb this%seed_germ_decay(:) = fates_unset_r8 this%seed_germ_in(:) = fates_unset_r8 @@ -382,7 +376,6 @@ subroutine DeallocateLitt(this) deallocate(this%root_fines_frag) deallocate(this%seed_decay) - deallocate(this%non_seed_repro_mass_decay) deallocate(this%seed_germ_decay) deallocate(this%seed_germ_in) @@ -409,7 +402,6 @@ subroutine ZeroFlux(this) this%seed_germ_in(:) = 0._r8 this%seed_decay(:) = 0._r8 - this%non_seed_repro_mass_decay = 0._r8 this%seed_germ_decay(:) = 0._r8 diff --git a/main/EDParamsMod.F90 b/main/EDParamsMod.F90 index 23e3b62170..8ed8be696e 100644 --- a/main/EDParamsMod.F90 +++ b/main/EDParamsMod.F90 @@ -70,8 +70,10 @@ module EDParamsMod real(r8),protected, public :: ED_val_patch_fusion_tol ! minimum fraction in difference in profiles between patches real(r8),protected, public :: ED_val_canopy_closure_thresh ! site-level canopy closure point where trees take on forest (narrow) versus savannah (wide) crown allometry integer,protected, public :: stomatal_model ! switch for choosing between stomatal conductance models, 1 for Ball-Berry, 2 for Medlyn - integer,protected, public :: regeneration_model ! switch for choosing between regeneration models, 1 for Fates basic, 2 for the Tree Recruitment Scheme - ! Hanbury-Brown et al., 2022 + integer,protected, public :: regeneration_model ! Switch for choosing between regeneration models: + ! (1) for Fates default + ! (2) for the Tree Recruitment Scheme (Hanbury-Brown et al., 2022) + ! (3) for the Tree Recruitment Scheme without seedling dynamics logical,protected, public :: active_crown_fire ! flag, 1=active crown fire 0=no active crown fire diff --git a/main/EDPftvarcon.F90 b/main/EDPftvarcon.F90 index 041c80b92e..e8ff0e2791 100644 --- a/main/EDPftvarcon.F90 +++ b/main/EDPftvarcon.F90 @@ -106,22 +106,23 @@ module EDPftvarcon real(r8), allocatable :: seed_decay_rate(:) ! Fraction of seed mass (both germinated and ! ungerminated), decaying per year (yr-1) - real(r8), allocatable :: repro_frac_seed(:) ! added by ahb 7/15/2021 - real(r8), allocatable :: a_emerg(:) !added by ahb 7/19/2021 - real(r8), allocatable :: b_emerg(:) !added by ahb 7/19/2021 - real(r8), allocatable :: par_crit_germ(:) !added by ahb 7/19/2021 - real(r8), allocatable :: seedling_psi_emerg(:) !added by ahb 7/19/2021 - real(r8), allocatable :: seedling_psi_crit(:) !added by ahb 7/19/2021 - real(r8), allocatable :: seedling_light_rec_a(:) !added by ahb 7/19/2021 - real(r8), allocatable :: seedling_light_rec_b(:) !added by ahb 7/19/2021 - real(r8), allocatable :: seedling_mdd_crit(:) !added by ahb 7/19/2021 - real(r8), allocatable :: seedling_h2o_mort_a(:) !added by ahb 7/19/2021 - real(r8), allocatable :: seedling_h2o_mort_b(:) !added by ahb 7/19/2021 - real(r8), allocatable :: seedling_h2o_mort_c(:) !added by ahb 7/19/2021 - real(r8), allocatable :: seedling_root_depth(:) !added by ahb 7/27/2021 - real(r8), allocatable :: seedling_light_mort_a(:) !added by ahb on 7/27/2021 - real(r8), allocatable :: seedling_light_mort_b(:) !added by ahb on 7/27/2021 - real(r8), allocatable :: background_seedling_mort(:)!added by ahb on 7/27/2021 + real(r8), allocatable :: repro_frac_seed(:) ! fraciton of reproductive carbon that is seed + real(r8), allocatable :: a_emerg(:) ! mean fraction of seed bank emerging [day-1] + real(r8), allocatable :: b_emerg(:) ! seedling emergence sensitivity to soil moisture + real(r8), allocatable :: par_crit_germ(:) ! critical light level for germination [MJ m2-1 day-1] + real(r8), allocatable :: seedling_psi_emerg(:) ! critical soil moisture for seedling emergence [mm h2o suction] + real(r8), allocatable :: seedling_psi_crit(:) ! critical soil moisture initiating seedling stress + real(r8), allocatable :: seedling_light_rec_a(:) ! coefficient in light-based seedling to sapling transition rate + real(r8), allocatable :: seedling_light_rec_b(:) ! coefficient in light-based seedling to sapling transition rate + real(r8), allocatable :: seedling_mdd_crit(:) ! critical moisture deficit day accumulation for seedling moisture-based + ! seedling mortality to begin + real(r8), allocatable :: seedling_h2o_mort_a(:) ! coefficient in moisture-based seedling mortality + real(r8), allocatable :: seedling_h2o_mort_b(:) ! coefficient in moisture-based seedling mortality + real(r8), allocatable :: seedling_h2o_mort_c(:) ! coefficient in moisture-based seedling mortality + real(r8), allocatable :: seedling_root_depth(:) ! rooting depth of seedlings [m] + real(r8), allocatable :: seedling_light_mort_a(:) ! light-based seedling mortality coefficient + real(r8), allocatable :: seedling_light_mort_b(:) ! light-based seedling mortality coefficient + real(r8), allocatable :: background_seedling_mort(:)! background seedling mortality [yr-1] real(r8), allocatable :: trim_limit(:) ! Limit to reductions in leaf area w stress (m2/m2) real(r8), allocatable :: trim_inc(:) ! Incremental change in trimming function (m2/m2) diff --git a/main/FatesConstantsMod.F90 b/main/FatesConstantsMod.F90 index ff35efef52..a662050f68 100644 --- a/main/FatesConstantsMod.F90 +++ b/main/FatesConstantsMod.F90 @@ -51,15 +51,20 @@ module FatesConstantsMod !Flags specifying how tree regeneration works - integer, public, parameter :: TRS_no_seedling_dyn = 3 ! Constant defining the Tree Recruitment Scheme switch. This value - ! turns on size-based reproductive allocation and allocation to non-seed - ! reproductive biomass, but does not turn on seedling dynamics. - integer, public, parameter :: TRS = 2 !Constant defining the Tree Recruitment Scheme switch. This value turns on the full TRS. - integer, public, parameter :: default_regeneration = 1 !Constant defining FATES's default regeneration scheme switch. - real(fates_r8), public, parameter :: min_max_dbh_for_trees = 15._fates_r8 !cm; if pfts have a max dbh less - !than this value FATES - !will use the default regeneration scheme. This is to avoid - !the TRS being used for shrubs and grasses. + integer, public, parameter :: TRS_no_seedling_dyn = 3 ! Constant defining the Tree Recruitment + ! Scheme switch. This value turns on + ! size-based reproductive allocation + ! and allocation to non-seed + ! reproductive biomass, but does not turn + ! on seedling dynamics. + integer, public, parameter :: TRS = 2 ! Constant defining the Tree Recruitment + ! Scheme switch. Turns on full TRS. + integer, public, parameter :: default_regeneration = 1 ! Constant defining FATES's default + ! regeneration scheme switch. + real(fates_r8), public, parameter :: min_max_dbh_for_trees = 15._fates_r8 ! If pfts have a max dbh less + ! than this value FATES + ! will use the default regeneration scheme. + ! Avoids TRS for shrubs / grasses. integer, public, parameter :: trivial_np_comp_scaling = 2 ! This flag definition indicates that either ! nutrients are turned off in FATES, or, that the diff --git a/main/FatesInterfaceMod.F90 b/main/FatesInterfaceMod.F90 index 7287916eca..2f6a8c47f6 100644 --- a/main/FatesInterfaceMod.F90 +++ b/main/FatesInterfaceMod.F90 @@ -1969,16 +1969,11 @@ subroutine UpdateFatesRMeansTStep(sites,bc_in) real(r8) :: new_seedling_layer_par !seedling layer par in the current timestep real(r8) :: new_seedling_layer_smp(maxpft) !seedling layer smp in the current timestep real(r8) :: new_seedling_mdd(maxpft) !seedling layer moisture deficit days in the current timestep - - real(r8), parameter :: seedling_smp_crit = -175912.9_r8 !seedling soil moisture stress - !threshold at which point - !the seedling layer starts accumulating moisture - !deficit days; move to pft-specific param if works - integer :: ilayer_seedling_root(maxpft) !the soil layer at seedling rooting depth - integer :: n_leaf !number of leaf layers per canopy layer in patch + integer :: ilayer_seedling_root(maxpft) !the soil layer at seedling rooting depth + integer :: n_leaf !number of leaf layers per canopy layer in patch real(r8) :: lai_sun_frac real(r8) :: lai_shade_frac - integer,parameter :: ipar = 1 !solar radiation in the shortwave band (i.e. par) + integer,parameter :: ipar = 1 !solar radiation in the shortwave band (i.e. par) do s = 1,size(sites,dim=1) @@ -1991,37 +1986,41 @@ subroutine UpdateFatesRMeansTStep(sites,bc_in) call cpatch%tveg_lpa%UpdateRMean(bc_in(s)%t_veg_pa(ifp)) call cpatch%tveg_longterm%UpdateRMean(bc_in(s)%t_veg_pa(ifp)) - !updating seedling layer par, soil matric potential and - !moisture deficit days (mdd) in the seedling layer; ahb, August 2021 - !--------------------------------------------------------------------------------------- - - n_leaf = maxval(cpatch%ncan(cpatch%ncl_p,:)) !calculating the number of leaf layers - !in the lowest canopy layer + ! Update seedling layer running means of PAR, soil matric potential and + ! moisture deficit days (mdd). + n_leaf = maxval(cpatch%ncan(cpatch%ncl_p,:)) ! Calculate the number of leaf layers + ! in the lowest canopy layer - !calculating the fraction of total lai (summed across pfts) in sun vs. shade - !at the lowest leaf level of the lowest canopy level + ! Calculate the fraction of total lai (summed across pfts) in sun vs. shade + ! at the lowest leaf level of the lowest canopy level lai_sun_frac = sum(cpatch%ed_laisun_z(cpatch%ncl_p,:,n_leaf)) & / ( sum(cpatch%ed_laisun_z(cpatch%ncl_p,:,n_leaf)) + & !summed across pfts sum(cpatch%ed_laisha_z(cpatch%ncl_p,:,n_leaf)) ) !summed across pfts lai_shade_frac = 1.0_r8 - lai_sun_frac - !calculating seedling layer par for the current time step - !using the weighted average of direct and diffuse par profiles - + ! Calculate new_seedling_layer_par (total PAR at the lowest leaf layer of the lowest canopy layer) + ! using the weighted average of direct and diffuse par. + + ! Notes to code reviewers on calculating "new_seedling_layer_par" (4-11-2023): + ! 1. Charlie or Ryan, can you please verify that weighted-avg approach is indeed getting + ! *total* par at the lowest leaf layer of the lowest canopy layer? + ! 2. This variable currently might create a seedling layer par that is too dark because + ! it assumes that all seedlings are hiding under larger trees? Where the canopy is closed this is + ! OK, but in open forest it will overesimtae shade expected by seedlings I think? + ! What if the sun_frac weight above were multiplied by bc_in(s)%solad_parb(ifp,ipar) instead? new_seedling_layer_par = & (cpatch%parprof_dir_z(cpatch%ncl_p,n_leaf) * lai_sun_frac) + & (cpatch%parprof_dif_z(cpatch%ncl_p,n_leaf) * (1.0_r8 - lai_sun_frac)) - ! if there is no lai in the patch (i.e. no vegetation) then the lai_sun_frac - ! and lai_shade frac vars become nan, causing seedling layer par to be nan. - ! which messes up the running means. This say's that if there is no lai, the - ! par at the seedling layer is taken from the ctsm boundary conditions + ! If there is no lai on the patch then new seedling layer par becomes nan (because + ! lai_sun_frac is Inf). If this is the case then PAR at the seedling layer is + ! taken from the hlm boundary conditions (i.e. same as top of canopy). if (new_seedling_layer_par /= new_seedling_layer_par) then new_seedling_layer_par = bc_in(s)%solad_parb(ifp,ipar) + bc_in(s)%solai_parb(ifp,ipar) end if - ! update the par running means + ! Update the seedling layer par running means call cpatch%seedling_layer_par24%UpdateRMean(new_seedling_layer_par) call cpatch%sdlng_mort_par%UpdateRMean(new_seedling_layer_par) call cpatch%sdlng2sap_par%UpdateRMean(new_seedling_layer_par) @@ -2029,34 +2028,26 @@ subroutine UpdateFatesRMeansTStep(sites,bc_in) !write(fates_log(),*) 'new_seedling_layer_par', new_seedling_layer_par do pft = 1,numpft - !calculate the soil moisture at the seedling rooting depth for each pft + + ! Calculate the soil moisture at the seedling rooting depth for each pft ilayer_seedling_root(pft) = minloc(abs(bc_in(s)%z_sisl(:)-EDPftvarcon_inst%seedling_root_depth(pft)),dim=1) new_seedling_layer_smp(pft) = bc_in(s)%smp_sl(ilayer_seedling_root(pft)) - !calculate the new moisture deficit day (mdd) value for each pft + ! Calculate the new moisture deficit day (mdd) value for each pft new_seedling_mdd(pft) = (abs(EDPftvarcon_inst%seedling_psi_crit(pft)) - abs(new_seedling_layer_smp(pft))) & * (-1.0_r8) * sdlng_mdd_timescale - ! if mdds are negative then it means that soil is wetter than smp_crit and the moisture + ! If mdds are negative then it means that soil is wetter than smp_crit and the moisture ! deficit is 0 if (new_seedling_mdd(pft) < 0.0_r8) then new_seedling_mdd(pft) = 0.0_r8 endif - !update the smp and mdd running means + ! Update the seedling layer smp and mdd running means call cpatch%sdlng_emerg_smp(pft)%p%UpdateRMean(new_seedling_layer_smp(pft)) call cpatch%sdlng_mdd(pft)%p%UpdateRMean(new_seedling_mdd(pft)) - - - !write(fates_log(),*) 'new_seedling_layer_smp', new_seedling_layer_smp(pft) - !write(fates_log(),*) 'smpEmerg', cpatch%sdlng_emerg_smp(pft)%p%GetMean() - !write(fates_log(),*) 'new_sdling_mdd', new_seedling_mdd(pft) - !write(fates_log(),*) 'sdling_mdd', cpatch%sdlng_mdd(pft)%p%GetMean() - - enddo - !END ahb's changes - !--------------------------------------------------------------------------------------- + enddo ! !ccohort => cpatch%tallest !do while (associated(ccohort)) diff --git a/parteh/PRTAllometricCarbonMod.F90 b/parteh/PRTAllometricCarbonMod.F90 index cc9b0d9af5..14197a34d7 100644 --- a/parteh/PRTAllometricCarbonMod.F90 +++ b/parteh/PRTAllometricCarbonMod.F90 @@ -42,10 +42,10 @@ module PRTAllometricCarbonMod use FatesConstantsMod , only : r8 => fates_r8 use FatesConstantsMod , only : i4 => fates_int use FatesConstantsMod , only : sec_per_day - use FatesConstantsMod , only : mm_per_cm !ahb - use FatesConstantsMod , only : TRS !ahb - use FatesConstantsMod , only : default_regeneration !ahb - use FatesConstantsMod , only : min_max_dbh_for_trees !ahb + use FatesConstantsMod , only : mm_per_cm + use FatesConstantsMod , only : TRS + use FatesConstantsMod , only : default_regeneration + use FatesConstantsMod , only : min_max_dbh_for_trees use FatesIntegratorsMod , only : RKF45 use FatesIntegratorsMod , only : Euler use FatesConstantsMod , only : calloc_abs_error @@ -77,7 +77,6 @@ module PRTAllometricCarbonMod integer, parameter :: repro_c_id = 5 ! Unique object index for reproductive carbon integer, parameter :: struct_c_id = 6 ! Unique object index for structural carbon integer, parameter :: num_vars = 6 ! THIS MUST MATCH THE LARGEST INDEX ABOVE - logical, parameter :: debug_trs = .true. ! local debug flag ! For this hypothesis, we integrate dbh along with the other 6. Since this @@ -976,56 +975,29 @@ function AllomCGrowthDeriv(c_pools,c_mask,cbalance,intgr_params) result(dCdx) ct_dagwdd, ct_dbgwdd, ct_dsapdd, ct_ddeaddd) call bstore_allom(dbh,ipft,crowndamage, canopy_trim,ct_store,ct_dstoredd) - ! fraction of carbon going towards reproduction - !START ahb's changes + ! If the TRS is switched off then we use FATES's default reproductive allocation. if ( regeneration_model == default_regeneration .or. & prt_params%allom_dbh_maxheight(ipft) < min_max_dbh_for_trees ) then !The Tree Recruitment Scheme !is only for tree pfts - - !Default reproductive allocation + ! Calculate fraction of carbon going towards reproduction if (dbh <= prt_params%dbh_repro_threshold(ipft)) then ! cap on leaf biomass repro_fraction = prt_params%seed_alloc(ipft) else repro_fraction = prt_params%seed_alloc(ipft) + prt_params%seed_alloc_mature(ipft) - end if + end if ! End dbh check on if to add additional carbon to reproduction. + ! If the TRS is switched on (with or w/o seedling dynamics) then reproductive allocation is + ! a pft-specific function of dbh. This allows for the representation of different + ! reproductive schedules (Wenk and Falster, 2015) else if ( regeneration_model >= TRS .and. & prt_params%allom_dbh_maxheight(ipft) > min_max_dbh_for_trees ) then - !------------------------------------------------------------------------------------- - !Use Tree Recruitment Scheme's (TRS) approach to reproductive allocation. - !This reproductive allocation function calculates the fraction of available carbon - !allocated to reproductive tissue based on a cohort's dbh (mm). This function is based on - !empirical data and analysis at BCI (Visser et al., 2016). See Hanbury-Brown et al., 2022 - !for more details. - - !Visser MD, Bruijning M, Wright SJ, Muller-Landau HC, Jongejans E, Comita LS, - !de Kroon H. 2016. Functional traits as predictors of vital rates across the life cycle - !of tropical trees. Functional Ecology 30: 168–180. - !------------------------------------------------------------------------------------- - repro_fraction = prt_params%seed_alloc(ipft) * & (exp(prt_params%repro_alloc_b(ipft) + prt_params%repro_alloc_a(ipft)*dbh*mm_per_cm) / & (1 + exp(prt_params%repro_alloc_b(ipft) + prt_params%repro_alloc_a(ipft)*dbh*mm_per_cm))) - - !ahb diagnostic - !if (debug_trs) then - !if (hlm_day_of_year == 40 .OR. hlm_day_of_year == 270) then - - ! write(fates_log(),*) 'day_of_year:', hlm_day_of_year - ! write(fates_log(),*) 'pft:', ipft - ! write(fates_log(),*) 'dbh (cm):', dbh - ! write(fates_log(),*) 'repro_fraction:', repro_fraction - - !end if !day condition - !end if !debug condition - !end ahb diagnostic - - - end if !regeneration model switch - !END ahb's changes + end if ! TRS switch dCdx = 0.0_r8 From 765a6a7d595740c763f7b0be30977542f4b01540 Mon Sep 17 00:00:00 2001 From: Adam Hanbury-Brown Date: Tue, 11 Apr 2023 17:27:51 -0600 Subject: [PATCH 59/81] fixed switch name error in comments --- biogeochem/EDPhysiologyMod.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/biogeochem/EDPhysiologyMod.F90 b/biogeochem/EDPhysiologyMod.F90 index fdb112c439..42f16d2ce7 100644 --- a/biogeochem/EDPhysiologyMod.F90 +++ b/biogeochem/EDPhysiologyMod.F90 @@ -1966,7 +1966,7 @@ subroutine SeedDecay( litt , currentPatch, bc_in ) end if ! End use TRS - ! If the TRS is switched on with seedling dynamics (regeneration_model = 3) + ! If the TRS is switched on with seedling dynamics (regeneration_model = 2) ! then calculate seedling mortality. if ( regeneration_model == TRS .and. & prt_params%allom_dbh_maxheight(pft) > min_max_dbh_for_trees ) then From 34f804b3ff359c55862b320a973ce8557448c61a Mon Sep 17 00:00:00 2001 From: Adam Hanbury-Brown Date: Wed, 17 May 2023 10:27:14 -0700 Subject: [PATCH 60/81] Update biogeochem/EDPatchDynamicsMod.F90 fixed spelling of comments Co-authored-by: Marcos Longo <5891904+mpaiao@users.noreply.github.com> --- biogeochem/EDPatchDynamicsMod.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/biogeochem/EDPatchDynamicsMod.F90 b/biogeochem/EDPatchDynamicsMod.F90 index 8b39565909..32b0535a48 100644 --- a/biogeochem/EDPatchDynamicsMod.F90 +++ b/biogeochem/EDPatchDynamicsMod.F90 @@ -2100,7 +2100,7 @@ subroutine create_patch(currentSite, new_patch, age, areap, label,nocomp_pft) ! Until bc's are pointed to by sites give veg a default temp [K] real(r8), parameter :: temp_init_veg = 15._r8+t_water_freeze_k_1atm - real(r8), parameter :: init_seedling_par = 5.0_r8 !arbtrary initialization for + real(r8), parameter :: init_seedling_par = 5.0_r8 !arbitrary initialization for !seedling layer PAR [MJ m-2 d-1] real(r8), parameter :: init_seedling_smp = -26652.0_r8 !arbitrary initialization of smp [mm] From fe98bd0e5a0df9515a7c9f83c36fb9027bb57e12 Mon Sep 17 00:00:00 2001 From: Adam Hanbury-Brown Date: Wed, 17 May 2023 10:30:00 -0700 Subject: [PATCH 61/81] Update biogeochem/EDPhysiologyMod.F90 update regeneration_model flag Co-authored-by: Marcos Longo <5891904+mpaiao@users.noreply.github.com> --- biogeochem/EDPhysiologyMod.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/biogeochem/EDPhysiologyMod.F90 b/biogeochem/EDPhysiologyMod.F90 index 42f16d2ce7..1012c92480 100644 --- a/biogeochem/EDPhysiologyMod.F90 +++ b/biogeochem/EDPhysiologyMod.F90 @@ -1858,7 +1858,7 @@ subroutine SeedIn( currentSite, bc_in ) litt%seed_in_local(pft) = litt%seed_in_local(pft) + site_seed_rain(pft)/area ! If we are using the Tree Recruitment Scheme (TRS) with or w/o seedling dynamics - if ( regeneration_model >= TRS .and. & + if ( any(regeneration_model == [TRS, TRS_no_seedling_dyn]) .and. & prt_params%allom_dbh_maxheight(pft) > min_max_dbh_for_trees) then ! Send a fraction of reproductive carbon to litter to account for From f3dfcb1fc332568f6871938017264f4676dcafbb Mon Sep 17 00:00:00 2001 From: Adam Hanbury-Brown Date: Wed, 17 May 2023 10:30:21 -0700 Subject: [PATCH 62/81] Update biogeochem/EDPhysiologyMod.F90 update regeneration model flag Co-authored-by: Marcos Longo <5891904+mpaiao@users.noreply.github.com> --- biogeochem/EDPhysiologyMod.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/biogeochem/EDPhysiologyMod.F90 b/biogeochem/EDPhysiologyMod.F90 index 1012c92480..c1f7f8fbe0 100644 --- a/biogeochem/EDPhysiologyMod.F90 +++ b/biogeochem/EDPhysiologyMod.F90 @@ -1956,7 +1956,7 @@ subroutine SeedDecay( litt , currentPatch, bc_in ) ! If the TRS is switched on and the pft is a tree then add non-seed reproductive biomass ! to the seed decay flux. This was added to litt%seed_decay in the previously called SeedIn ! subroutine - if ( regeneration_model >= TRS .and. & + if ( any(regeneration_model == [TRS, TRS_no_seedling_dyn]) .and. & prt_params%allom_dbh_maxheight(pft) > min_max_dbh_for_trees ) then litt%seed_decay(pft) = litt%seed_decay(pft) + &! From non-seed reproductive biomass (added in From e3e60df0daf61c1365574e8c7ec27d9c4d5d158b Mon Sep 17 00:00:00 2001 From: Adam Hanbury-Brown Date: Wed, 17 May 2023 10:43:38 -0700 Subject: [PATCH 63/81] Update biogeochem/EDPhysiologyMod.F90 avoid calculating seedling mort rate when it is not needed Co-authored-by: Marcos Longo <5891904+mpaiao@users.noreply.github.com> --- biogeochem/EDPhysiologyMod.F90 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/biogeochem/EDPhysiologyMod.F90 b/biogeochem/EDPhysiologyMod.F90 index c1f7f8fbe0..1fbeb13293 100644 --- a/biogeochem/EDPhysiologyMod.F90 +++ b/biogeochem/EDPhysiologyMod.F90 @@ -1993,13 +1993,13 @@ subroutine SeedDecay( litt , currentPatch, bc_in ) seedling_mdds = currentPatch%sdlng_mdd(pft)%p%GetMean() ! Calculate seedling mortality as a function of moisture deficit days (mdd) - seedling_h2o_mort_rate = EDPftvarcon_inst%seedling_h2o_mort_a(pft) * seedling_mdds**2 + & - EDPftvarcon_inst%seedling_h2o_mort_b(pft) * seedling_mdds + & - EDPftvarcon_inst%seedling_h2o_mort_c(pft) - ! If the seedling mmd value is below a critical threshold then moisture-based mortality is zero if (seedling_mdds < EDPftvarcon_inst%seedling_mdd_crit(pft)) then seedling_h2o_mort_rate = 0.0_r8 + else + seedling_h2o_mort_rate = EDPftvarcon_inst%seedling_h2o_mort_a(pft) * seedling_mdds**2 + & + EDPftvarcon_inst%seedling_h2o_mort_b(pft) * seedling_mdds + & + EDPftvarcon_inst%seedling_h2o_mort_c(pft) end if ! mdd threshold check ! Step 3. Sum modes of mortality (including background mortality) and send dead seedlings From 89b7cb0238f40416c55e02aef88331e28bb7f793 Mon Sep 17 00:00:00 2001 From: Adam Hanbury-Brown Date: Wed, 17 May 2023 12:10:53 -0700 Subject: [PATCH 64/81] Update parteh/PRTAllometricCarbonMod.F90 update the regeneration_model flag Co-authored-by: Marcos Longo <5891904+mpaiao@users.noreply.github.com> --- parteh/PRTAllometricCarbonMod.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parteh/PRTAllometricCarbonMod.F90 b/parteh/PRTAllometricCarbonMod.F90 index 14197a34d7..d02a9f8e7f 100644 --- a/parteh/PRTAllometricCarbonMod.F90 +++ b/parteh/PRTAllometricCarbonMod.F90 @@ -990,7 +990,7 @@ function AllomCGrowthDeriv(c_pools,c_mask,cbalance,intgr_params) result(dCdx) ! If the TRS is switched on (with or w/o seedling dynamics) then reproductive allocation is ! a pft-specific function of dbh. This allows for the representation of different ! reproductive schedules (Wenk and Falster, 2015) - else if ( regeneration_model >= TRS .and. & + else if ( any(regeneration_model == [TRS, TRS_no_seedling_dyn]) .and. & prt_params%allom_dbh_maxheight(ipft) > min_max_dbh_for_trees ) then repro_fraction = prt_params%seed_alloc(ipft) * & From 384255d2695d8ed6d17ba673ad6c98fffc88c631 Mon Sep 17 00:00:00 2001 From: Adam Hanbury-Brown Date: Wed, 17 May 2023 13:13:11 -0600 Subject: [PATCH 65/81] small updates made to comments, indents, and the regeneration model switch in response to code review --- main/FatesConstantsMod.F90 | 8 ++++-- main/FatesInterfaceMod.F90 | 46 ++++++++++++++----------------- main/FatesRestartInterfaceMod.F90 | 4 +-- 3 files changed, 27 insertions(+), 31 deletions(-) diff --git a/main/FatesConstantsMod.F90 b/main/FatesConstantsMod.F90 index a662050f68..a3c0047bb3 100644 --- a/main/FatesConstantsMod.F90 +++ b/main/FatesConstantsMod.F90 @@ -197,9 +197,7 @@ module FatesConstantsMod ! Conversion: megajoules per joule real(fates_r8), parameter, public :: megajoules_per_joule = 1.0E-6_fates_r8 - ! Conversion: megapascals per mm H2O suction - real(fates_r8), parameter, public :: mpa_per_mm_suction = 1.0E-5_fates_r8 - + ! Conversion: days per second real(fates_r8), parameter, public :: days_per_sec = 1.0_fates_r8/86400.0_fates_r8 @@ -249,6 +247,10 @@ module FatesConstantsMod ! Pascals to megapascals real(fates_r8), parameter, public :: mpa_per_pa = 1.e-6_fates_r8 + ! Conversion: megapascals per mm H2O suction + real(fates_r8), parameter, public :: mpa_per_mm_suction = dens_fresh_liquid_water * & + grav_earth * 1.0E-9_fates_r8 + ! For numerical inquiry real(fates_r8), parameter, public :: fates_huge = huge(g_per_kg) diff --git a/main/FatesInterfaceMod.F90 b/main/FatesInterfaceMod.F90 index 02ab768fcd..39e54bfe0c 100644 --- a/main/FatesInterfaceMod.F90 +++ b/main/FatesInterfaceMod.F90 @@ -1990,13 +1990,6 @@ subroutine UpdateFatesRMeansTStep(sites,bc_in) ! Calculate new_seedling_layer_par (total PAR at the lowest leaf layer of the lowest canopy layer) ! using the weighted average of direct and diffuse par. - ! Notes to code reviewers on calculating "new_seedling_layer_par" (4-11-2023): - ! 1. Charlie or Ryan, can you please verify that weighted-avg approach is indeed getting - ! *total* par at the lowest leaf layer of the lowest canopy layer? - ! 2. This variable currently might create a seedling layer par that is too dark because - ! it assumes that all seedlings are hiding under larger trees? Where the canopy is closed this is - ! OK, but in open forest it will overesimtae shade expected by seedlings I think? - ! What if the sun_frac weight above were multiplied by bc_in(s)%solad_parb(ifp,ipar) instead? new_seedling_layer_par = & (cpatch%parprof_dir_z(cpatch%ncl_p,n_leaf) * lai_sun_frac) + & (cpatch%parprof_dif_z(cpatch%ncl_p,n_leaf) * (1.0_r8 - lai_sun_frac)) @@ -2016,26 +2009,27 @@ subroutine UpdateFatesRMeansTStep(sites,bc_in) !write(fates_log(),*) 'new_seedling_layer_par', new_seedling_layer_par do pft = 1,numpft + + ! Calculate the soil moisture at the seedling rooting depth for each pft + + ilayer_seedling_root(pft) = minloc(abs(bc_in(s)%z_sisl(:)-EDPftvarcon_inst%seedling_root_depth(pft)),dim=1) + new_seedling_layer_smp(pft) = bc_in(s)%smp_sl(ilayer_seedling_root(pft)) + + ! Calculate the new moisture deficit day (mdd) value for each pft + new_seedling_mdd(pft) = (abs(EDPftvarcon_inst%seedling_psi_crit(pft)) - abs(new_seedling_layer_smp(pft))) & + * (-1.0_r8) * sdlng_mdd_timescale + + ! If mdds are negative then it means that soil is wetter than smp_crit and the moisture + ! deficit is 0 + if (new_seedling_mdd(pft) < 0.0_r8) then + new_seedling_mdd(pft) = 0.0_r8 + endif + + ! Update the seedling layer smp and mdd running means + call cpatch%sdlng_emerg_smp(pft)%p%UpdateRMean(new_seedling_layer_smp(pft)) + call cpatch%sdlng_mdd(pft)%p%UpdateRMean(new_seedling_mdd(pft)) - ! Calculate the soil moisture at the seedling rooting depth for each pft - - ilayer_seedling_root(pft) = minloc(abs(bc_in(s)%z_sisl(:)-EDPftvarcon_inst%seedling_root_depth(pft)),dim=1) - new_seedling_layer_smp(pft) = bc_in(s)%smp_sl(ilayer_seedling_root(pft)) - - ! Calculate the new moisture deficit day (mdd) value for each pft - new_seedling_mdd(pft) = (abs(EDPftvarcon_inst%seedling_psi_crit(pft)) - abs(new_seedling_layer_smp(pft))) & - * (-1.0_r8) * sdlng_mdd_timescale - - ! If mdds are negative then it means that soil is wetter than smp_crit and the moisture - ! deficit is 0 - if (new_seedling_mdd(pft) < 0.0_r8) then - new_seedling_mdd(pft) = 0.0_r8 - endif - - ! Update the seedling layer smp and mdd running means - call cpatch%sdlng_emerg_smp(pft)%p%UpdateRMean(new_seedling_layer_smp(pft)) - call cpatch%sdlng_mdd(pft)%p%UpdateRMean(new_seedling_mdd(pft)) - enddo ! + enddo !end pft loop !ccohort => cpatch%tallest !do while (associated(ccohort)) diff --git a/main/FatesRestartInterfaceMod.F90 b/main/FatesRestartInterfaceMod.F90 index 7b36de7a21..6109bd8a6b 100644 --- a/main/FatesRestartInterfaceMod.F90 +++ b/main/FatesRestartInterfaceMod.F90 @@ -3179,8 +3179,8 @@ subroutine get_restart_vectors(this, nc, nsites, sites) call this%GetRMeanRestartVar(cpatch%sdlng2sap_par, ir_sdlng2sap_par_pa,io_idx_co_1st) do pft = 1, maxpft - call this%GetRMeanRestartVar(cpatch%sdlng_mdd(pft)%p, ir_sdlng_mdd_pa,io_idx_co_1st) - call this%GetRMeanRestartVar(cpatch%sdlng_emerg_smp(pft)%p, ir_sdlng_emerg_smp_pa,io_idx_co_1st) + call this%GetRMeanRestartVar(cpatch%sdlng_mdd(pft)%p, ir_sdlng_mdd_pa,io_idx_co_1st) + call this%GetRMeanRestartVar(cpatch%sdlng_emerg_smp(pft)%p, ir_sdlng_emerg_smp_pa,io_idx_co_1st) enddo ! set cohorts per patch for IO From 66d37975b6c053b711884af6c05776003a97875a Mon Sep 17 00:00:00 2001 From: Adam Hanbury-Brown Date: Thu, 8 Jun 2023 18:14:37 -0600 Subject: [PATCH 66/81] changes in response to Ryan's comments --- biogeochem/EDPhysiologyMod.F90 | 12 ++-- main/FatesConstantsMod.F90 | 2 +- parteh/PRTAllometricCNPMod.F90 | 102 ++++++++++++++++++++++++------ parteh/PRTAllometricCarbonMod.F90 | 5 +- 4 files changed, 91 insertions(+), 30 deletions(-) diff --git a/biogeochem/EDPhysiologyMod.F90 b/biogeochem/EDPhysiologyMod.F90 index 1fbeb13293..9b5fe78682 100644 --- a/biogeochem/EDPhysiologyMod.F90 +++ b/biogeochem/EDPhysiologyMod.F90 @@ -25,7 +25,7 @@ module EDPhysiologyMod use FatesConstantsMod, only : nearzero use FatesConstantsMod, only : sec_per_day use FatesConstantsMod, only : default_regeneration - use FatesConstantsMod, only : TRS + use FatesConstantsMod, only : TRS_regeneration use FatesConstantsMod, only : TRS_no_seedling_dyn use FatesConstantsMod, only : min_max_dbh_for_trees use FatesConstantsMod, only : megajoules_per_joule @@ -1858,7 +1858,7 @@ subroutine SeedIn( currentSite, bc_in ) litt%seed_in_local(pft) = litt%seed_in_local(pft) + site_seed_rain(pft)/area ! If we are using the Tree Recruitment Scheme (TRS) with or w/o seedling dynamics - if ( any(regeneration_model == [TRS, TRS_no_seedling_dyn]) .and. & + if ( any(regeneration_model == [TRS_regeneration, TRS_no_seedling_dyn]) .and. & prt_params%allom_dbh_maxheight(pft) > min_max_dbh_for_trees) then ! Send a fraction of reproductive carbon to litter to account for @@ -1956,7 +1956,7 @@ subroutine SeedDecay( litt , currentPatch, bc_in ) ! If the TRS is switched on and the pft is a tree then add non-seed reproductive biomass ! to the seed decay flux. This was added to litt%seed_decay in the previously called SeedIn ! subroutine - if ( any(regeneration_model == [TRS, TRS_no_seedling_dyn]) .and. & + if ( any(regeneration_model == [TRS_regeneration, TRS_no_seedling_dyn]) .and. & prt_params%allom_dbh_maxheight(pft) > min_max_dbh_for_trees ) then litt%seed_decay(pft) = litt%seed_decay(pft) + &! From non-seed reproductive biomass (added in @@ -1968,7 +1968,7 @@ subroutine SeedDecay( litt , currentPatch, bc_in ) ! If the TRS is switched on with seedling dynamics (regeneration_model = 2) ! then calculate seedling mortality. - if ( regeneration_model == TRS .and. & + if ( regeneration_model == TRS_regeneration .and. & prt_params%allom_dbh_maxheight(pft) > min_max_dbh_for_trees ) then !---------------------------------------------------------------------- @@ -2076,7 +2076,7 @@ subroutine SeedGermination( litt, cold_stat, drought_stat, bc_in, currentPatch ) ! If TRS seedling dynamics is switched on we calculate seedling emergence (i.e. germination) ! as a pft-specific function of understory light and soil moisture. - else if ( regeneration_model == TRS .and. & + else if ( regeneration_model == TRS_regeneration .and. & prt_params%allom_dbh_maxheight(pft) > min_max_dbh_for_trees ) then ! Step 1. Calculate how germination rate is modified by understory light @@ -2322,7 +2322,7 @@ subroutine recruitment( currentSite, currentPatch, bc_in ) ! If TRS seedling dynamics is on then calculate the available mass to make new recruits ! as a pft-specific function of light and soil moisture in the seedling layer. - else if ( regeneration_model == TRS .and. & + else if ( regeneration_model == TRS_regeneration .and. & prt_params%allom_dbh_maxheight(ft) > min_max_dbh_for_trees ) then sdlng2sap_par = currentPatch%sdlng2sap_par%GetMean() * sec_per_day * megajoules_per_joule diff --git a/main/FatesConstantsMod.F90 b/main/FatesConstantsMod.F90 index a3c0047bb3..e189e67a64 100644 --- a/main/FatesConstantsMod.F90 +++ b/main/FatesConstantsMod.F90 @@ -57,7 +57,7 @@ module FatesConstantsMod ! and allocation to non-seed ! reproductive biomass, but does not turn ! on seedling dynamics. - integer, public, parameter :: TRS = 2 ! Constant defining the Tree Recruitment + integer, public, parameter :: TRS_regeneration = 2 ! Constant defining the Tree Recruitment ! Scheme switch. Turns on full TRS. integer, public, parameter :: default_regeneration = 1 ! Constant defining FATES's default ! regeneration scheme switch. diff --git a/parteh/PRTAllometricCNPMod.F90 b/parteh/PRTAllometricCNPMod.F90 index 0f4b29b4b6..a4ecccddd3 100644 --- a/parteh/PRTAllometricCNPMod.F90 +++ b/parteh/PRTAllometricCNPMod.F90 @@ -47,6 +47,7 @@ module PRTAllometricCNPMod use FatesConstantsMod , only : calloc_abs_error use FatesConstantsMod , only : rsnbl_math_prec use FatesConstantsMod , only : years_per_day + use FatesConstantsMod , only : mm_per_cm use FatesIntegratorsMod , only : RKF45 use FatesIntegratorsMod , only : Euler use FatesConstantsMod , only : calloc_abs_error @@ -55,6 +56,10 @@ module PRTAllometricCNPMod use FatesConstantsMod , only : fates_unset_r8 use FatesConstantsMod , only : fates_unset_int use FatesConstantsMod , only : sec_per_day + use FatesConstantsMod , only : TRS_regeneration + use FatesConstantsMod , only : default_regeneration + use FatesConstantsMod , only : TRS_no_seedling_dyn + use FatesConstantsMod , only : min_max_dbh_for_trees use PRTParametersMod , only : prt_params use EDTypesMod , only : leaves_on,leaves_off use EDTypesMod , only : p_uptake_mode @@ -62,6 +67,9 @@ module PRTAllometricCNPMod use FatesConstantsMod , only : prescribed_p_uptake use FatesConstantsMod , only : prescribed_n_uptake use EDPftvarcon, only : EDPftvarcon_inst + use EDParamsMod , only : regeneration_model + + implicit none private @@ -1452,13 +1460,30 @@ subroutine CNPStatureGrowth(this,c_gain, n_gain, p_gain, & ! just different from the other pools. It is not based on proportionality, ! so its mask is set differently. We (inefficiently) just included ! reproduction in the previous loop, but oh well, we over-write now. + + ! If the TRS is switched off then we use FATES's default reproductive allocation. + if ( regeneration_model == default_regeneration .or. & + prt_params%allom_dbh_maxheight(ipft) < min_max_dbh_for_trees ) then ! The Tree Recruitment Scheme + ! is only for trees + if (dbh <= prt_params%dbh_repro_threshold(ipft)) then + repro_c_frac = prt_params%seed_alloc(ipft) + else + repro_c_frac = prt_params%seed_alloc(ipft) + prt_params%seed_alloc_mature(ipft) + end if - if (dbh <= prt_params%dbh_repro_threshold(ipft)) then - repro_c_frac = prt_params%seed_alloc(ipft) - else - repro_c_frac = prt_params%seed_alloc(ipft) + prt_params%seed_alloc_mature(ipft) - end if - + ! If the TRS is switched on (with or w/o seedling dynamics) then reproductive allocation is + ! a pft-specific function of dbh. This allows for the representation of different + ! reproductive schedules (Wenk and Falster, 2015) + else if ( any(regeneration_model == [TRS_regeneration, TRS_no_seedling_dyn]) .and. & + prt_params%allom_dbh_maxheight(ipft) > min_max_dbh_for_trees ) then + + repro_c_frac = prt_params%seed_alloc(ipft) * & + (exp(prt_params%repro_alloc_b(ipft) + prt_params%repro_alloc_a(ipft)*dbh*mm_per_cm) / & + (1 + exp(prt_params%repro_alloc_b(ipft) + prt_params%repro_alloc_a(ipft)*dbh*mm_per_cm))) + + end if ! regeneration switch + + if(repro_c_frac>nearzero)then state_mask(repro_id) = .true. n_mask_organs = n_mask_organs + 1 @@ -2253,15 +2278,32 @@ function AllomCNPGrowthDeriv(l_state_array,l_state_mask,cbalance,intgr_params) r call bstore_allom(dbh,ipft,crown_damage,canopy_trim,store_c_target,store_dcdd_target) if (mask_repro) then - ! fraction of carbon going towards reproduction - if (dbh <= prt_params%dbh_repro_threshold(ipft)) then - repro_fraction = prt_params%seed_alloc(ipft) - else - repro_fraction = prt_params%seed_alloc(ipft) + prt_params%seed_alloc_mature(ipft) - end if - else + + ! If the TRS is switched off then we use FATES's default reproductive allocation. + if ( regeneration_model == default_regeneration .or. & + prt_params%allom_dbh_maxheight(ipft) < min_max_dbh_for_trees ) then ! The Tree Recruitment Scheme + ! is only for trees + if (dbh <= prt_params%dbh_repro_threshold(ipft)) then + repro_fraction = prt_params%seed_alloc(ipft) + else + repro_fraction = prt_params%seed_alloc(ipft) + prt_params%seed_alloc_mature(ipft) + end if + + ! If the TRS is switched on (with or w/o seedling dynamics) then reproductive allocation is + ! a pft-specific function of dbh. This allows for the representation of different + ! reproductive schedules (Wenk and Falster, 2015) + else if ( any(regeneration_model == [TRS_regeneration, TRS_no_seedling_dyn]) .and. & + prt_params%allom_dbh_maxheight(ipft) > min_max_dbh_for_trees ) then + + repro_fraction = prt_params%seed_alloc(ipft) * & + (exp(prt_params%repro_alloc_b(ipft) + prt_params%repro_alloc_a(ipft)*dbh*mm_per_cm) / & + (1 + exp(prt_params%repro_alloc_b(ipft) + prt_params%repro_alloc_a(ipft)*dbh*mm_per_cm))) + + end if ! regeneration switch + + else ! mask repro repro_fraction = 0._r8 - end if + end if !mask repro total_dcostdd = 0._r8 if (mask_struct) then @@ -2369,14 +2411,32 @@ subroutine EstimateGrowthNC(this,target_c,target_dcdd,state_mask,avg_nc,avg_pc) pc_repro => this%bc_in(acnp_bc_in_id_pc_repro)%rval) if(state_mask(repro_id)) then - if (dbh <= prt_params%dbh_repro_threshold(ipft)) then - repro_c_frac = prt_params%seed_alloc(ipft) - else - repro_c_frac = prt_params%seed_alloc(ipft) + prt_params%seed_alloc_mature(ipft) - end if - else + + ! If the TRS is switched off then we use FATES's default reproductive allocation. + if ( regeneration_model == default_regeneration .or. & + prt_params%allom_dbh_maxheight(ipft) < min_max_dbh_for_trees ) then ! The Tree Recruitment Scheme + ! is only for trees + if (dbh <= prt_params%dbh_repro_threshold(ipft)) then + repro_c_frac = prt_params%seed_alloc(ipft) + else + repro_c_frac = prt_params%seed_alloc(ipft) + prt_params%seed_alloc_mature(ipft) + end if + + ! If the TRS is switched on (with or w/o seedling dynamics) then reproductive allocation is + ! a pft-specific function of dbh. This allows for the representation of different + ! reproductive schedules (Wenk and Falster, 2015) + else if ( any(regeneration_model == [TRS_regeneration, TRS_no_seedling_dyn]) .and. & + prt_params%allom_dbh_maxheight(ipft) > min_max_dbh_for_trees ) then + + repro_c_frac = prt_params%seed_alloc(ipft) * & + (exp(prt_params%repro_alloc_b(ipft) + prt_params%repro_alloc_a(ipft)*dbh*mm_per_cm) / & + (1 + exp(prt_params%repro_alloc_b(ipft) + prt_params%repro_alloc_a(ipft)*dbh*mm_per_cm))) + + end if ! regeneration switch + + else ! state mask repro_c_frac = 0._r8 - end if + end if ! state mask ! Estimate the total weight total_w = 0._r8 diff --git a/parteh/PRTAllometricCarbonMod.F90 b/parteh/PRTAllometricCarbonMod.F90 index d02a9f8e7f..92a7c606c1 100644 --- a/parteh/PRTAllometricCarbonMod.F90 +++ b/parteh/PRTAllometricCarbonMod.F90 @@ -43,8 +43,9 @@ module PRTAllometricCarbonMod use FatesConstantsMod , only : i4 => fates_int use FatesConstantsMod , only : sec_per_day use FatesConstantsMod , only : mm_per_cm - use FatesConstantsMod , only : TRS + use FatesConstantsMod , only : TRS_regeneration use FatesConstantsMod , only : default_regeneration + use FatesConstantsMod , only : TRS_no_seedling_dyn use FatesConstantsMod , only : min_max_dbh_for_trees use FatesIntegratorsMod , only : RKF45 use FatesIntegratorsMod , only : Euler @@ -990,7 +991,7 @@ function AllomCGrowthDeriv(c_pools,c_mask,cbalance,intgr_params) result(dCdx) ! If the TRS is switched on (with or w/o seedling dynamics) then reproductive allocation is ! a pft-specific function of dbh. This allows for the representation of different ! reproductive schedules (Wenk and Falster, 2015) - else if ( any(regeneration_model == [TRS, TRS_no_seedling_dyn]) .and. & + else if ( any(regeneration_model == [TRS_regeneration, TRS_no_seedling_dyn]) .and. & prt_params%allom_dbh_maxheight(ipft) > min_max_dbh_for_trees ) then repro_fraction = prt_params%seed_alloc(ipft) * & From 635fccea53ee061c3b06d30adaa2326409e362e7 Mon Sep 17 00:00:00 2001 From: Ryan Knox Date: Tue, 13 Jun 2023 12:08:19 -0400 Subject: [PATCH 67/81] Made special routine to calculate forest floor light levels for seedlings --- main/EDTypesMod.F90 | 96 ++++++++++++++++++++++++++++++++++++++ main/FatesInterfaceMod.F90 | 38 ++++++--------- 2 files changed, 109 insertions(+), 25 deletions(-) diff --git a/main/EDTypesMod.F90 b/main/EDTypesMod.F90 index c015ea86d4..466ad12147 100644 --- a/main/EDTypesMod.F90 +++ b/main/EDTypesMod.F90 @@ -1235,4 +1235,100 @@ subroutine dump_cohort_hydr(ccohort) return end subroutine dump_cohort_hydr + ! ======================================================================================== + + subroutine SeedlingParPatch(cpatch, & + atm_par, & + seedling_par_high, par_high_frac, & + seedling_par_low, par_low_frac) + + ! Calculate the intensity of PAR for seedlings in the current patch. + ! To do this, we need to get a weighted average of light penetrating + ! though (parprof) the lowest leaf layers. We will need to identify + ! how closed (area) the lowest canopy layer is, because we will use + ! an area weighted average of the light coming from the canopy above + ! and an area weighted average of the light penetrating through the + ! existing portino of the lowest layer. + ! + ! This routine will generate two intensities, light levels on the exposed + ! ground in the lowest layer, and light levels under the existing + ! vegetation in the lowest layer, along with the area fraction + ! of those two (which should sum to unity). + + ! Arguments + type(ed_patch_type) :: cpatch + real(r8), intent(in) :: atm_par ! direct+diffuse PAR at canopy top [W/m2] + real(r8), intent(out) :: seedling_par_high ! High intensity PAR for seedlings [W/m2] + real(r8), intent(out) :: par_high_frac ! Area fraction with high intensity + real(r8), intent(out) :: seedling_par_low ! Low intensity PAR for seedlings [W/m2] + real(r8), intent(out) :: par_low_frac ! Area fraction with low intensity + + ! Locals + real(r8) :: upper_par ! The PAR intensity coming from the canopy layer above [w/m2] + real(r8) :: upper_area ! The area fraction of the upper canopy + real(r8) :: lower_par ! The PAR intensity under the lower-most canopy [W/m2] + real(r8) :: lower_area ! The area fractino of the lower canopy + integer :: cl ! current canopy layer + integer :: ipft ! current PFT index + integer :: iv ! lower-most leaf layer index for the cl & pft combo + + ! Radiation intensity exiting the layer above the bottom-most + upper_par = 0._r8 + upper_area = 0._r8 + cl = max(1,cpatch%NCL_p-1) + do ipft = 1,numpft + iv = cpatch%ncan(cl,ft) + upper_par = upper_par + cpatch%canopy_area_profile(cl,ifpt,1)*& + (cpatch%parprof_pft_dir_z(cl,ipft,iv)+cpatch%parprof_pft_dif_z(cl,ipft,iv)) + upper_area = upper_area + cpatch%canopy_area_profile(cl,ifpt,1) + end do + if(upper_area>nearzero)then + upper_par = upper_par/upper_area + else + upper_par = 0._r8 + end if + + ! If we do have more than one layer, then we need to figure out + ! the average of light on the exposed ground under the veg + + if(cpatch%NCL_p>1) then + + ! Factor in atmospheric downwelling radiation if the upper + ! layer happens to be the top-most + if(cl==1)then + upper_par = cpatch%total_canopy_area*upper_par + & + (1._r8-cpatch%total_canopy_area)*(bc_in(s)%solad_parb(ifp,ipar)+bc_in(s)%solai_parb(ifp,ipar)) + end if + + cl = cpatch%NCL_p + lower_area = 0._r8 + lower_par = 0._r8 + do ipft = 1,numpft + iv = cpatch%ncan(cl,ft) + lower_area = lower_area+cpatch%canopy_area_profile(cl,ifpt,1) + par_bottom = cpatch%parprof_pft_dir_z(cl,ipft,iv) + & + cpatch%parprof_pft_dif_z(cl,ipft,iv) + lower_par = lower_par + cpatch%canopy_area_profile(cl,ifpt,1)*par_bottom + end do + if(lower_area>nearzero)then + lower_par = lower_par / lower_area + else + lower_par = 0._r8 + end if + + seedling_par_high = upper_par + par_high_frac = (1._r8-lower_area) + seedling_par_low = lower_par/lower_ara + par_low_frac = lower_area + + else + + seedling_par_high = bc_in(s)%solad_parb(ifp,ipar)+bc_in(s)%solai_parb(ifp,ipar) + par_high_frac = 1._r8-cpatch%total_canopy_area + seedling_par_low = upper_par + par_low_frac = cpatch%total_canopy_area + + end if + + return end module EDTypesMod diff --git a/main/FatesInterfaceMod.F90 b/main/FatesInterfaceMod.F90 index 39e54bfe0c..734392147b 100644 --- a/main/FatesInterfaceMod.F90 +++ b/main/FatesInterfaceMod.F90 @@ -1973,33 +1973,21 @@ subroutine UpdateFatesRMeansTStep(sites,bc_in) call cpatch%tveg24%UpdateRMean(bc_in(s)%t_veg_pa(ifp)) call cpatch%tveg_lpa%UpdateRMean(bc_in(s)%t_veg_pa(ifp)) call cpatch%tveg_longterm%UpdateRMean(bc_in(s)%t_veg_pa(ifp)) + + ! Return the par intensity at the ground. This routine + ! breaks it up into high and low light levels. The high + ! levels are the light on the exposed ground at the surface + ! and the low levels are the intensity under the bottom-most + ! vegetation. - ! Update seedling layer running means of PAR, soil matric potential and - ! moisture deficit days (mdd). - n_leaf = maxval(cpatch%ncan(cpatch%ncl_p,:)) ! Calculate the number of leaf layers - ! in the lowest canopy layer - - ! Calculate the fraction of total lai (summed across pfts) in sun vs. shade - ! at the lowest leaf level of the lowest canopy level - lai_sun_frac = sum(cpatch%ed_laisun_z(cpatch%ncl_p,:,n_leaf)) & - / ( sum(cpatch%ed_laisun_z(cpatch%ncl_p,:,n_leaf)) + & !summed across pfts - sum(cpatch%ed_laisha_z(cpatch%ncl_p,:,n_leaf)) ) !summed across pfts - - lai_shade_frac = 1.0_r8 - lai_sun_frac - - ! Calculate new_seedling_layer_par (total PAR at the lowest leaf layer of the lowest canopy layer) - ! using the weighted average of direct and diffuse par. - - new_seedling_layer_par = & - (cpatch%parprof_dir_z(cpatch%ncl_p,n_leaf) * lai_sun_frac) + & - (cpatch%parprof_dif_z(cpatch%ncl_p,n_leaf) * (1.0_r8 - lai_sun_frac)) + call SeedlingParPatch(cpatch, & + bc_in(s)%solad_parb(ifp,ipar) + bc_in(s)%solai_parb(ifp,ipar), & + seedling_par_high, & + par_high_frac, & + seedling_par_low, & + par_low_frac) - ! If there is no lai on the patch then new seedling layer par becomes nan (because - ! lai_sun_frac is Inf). If this is the case then PAR at the seedling layer is - ! taken from the hlm boundary conditions (i.e. same as top of canopy). - if (new_seedling_layer_par /= new_seedling_layer_par) then - new_seedling_layer_par = bc_in(s)%solad_parb(ifp,ipar) + bc_in(s)%solai_parb(ifp,ipar) - end if + new_seedling_layer_par = seedling_par_high*par_high_frac + seedling_par_low*par_low_frac ! Update the seedling layer par running means call cpatch%seedling_layer_par24%UpdateRMean(new_seedling_layer_par) From e57df0d19f6803145e9c99cd02417a3b6943f2ea Mon Sep 17 00:00:00 2001 From: Ryan Knox Date: Tue, 13 Jun 2023 17:53:53 -0400 Subject: [PATCH 68/81] Added seedling light intensity subroutine --- main/EDTypesMod.F90 | 97 +--------------------------- main/FatesInterfaceMod.F90 | 128 ++++++++++++++++++++++++++++++++----- 2 files changed, 112 insertions(+), 113 deletions(-) diff --git a/main/EDTypesMod.F90 b/main/EDTypesMod.F90 index 466ad12147..ce9dd74617 100644 --- a/main/EDTypesMod.F90 +++ b/main/EDTypesMod.F90 @@ -1235,100 +1235,5 @@ subroutine dump_cohort_hydr(ccohort) return end subroutine dump_cohort_hydr - ! ======================================================================================== - - subroutine SeedlingParPatch(cpatch, & - atm_par, & - seedling_par_high, par_high_frac, & - seedling_par_low, par_low_frac) - - ! Calculate the intensity of PAR for seedlings in the current patch. - ! To do this, we need to get a weighted average of light penetrating - ! though (parprof) the lowest leaf layers. We will need to identify - ! how closed (area) the lowest canopy layer is, because we will use - ! an area weighted average of the light coming from the canopy above - ! and an area weighted average of the light penetrating through the - ! existing portino of the lowest layer. - ! - ! This routine will generate two intensities, light levels on the exposed - ! ground in the lowest layer, and light levels under the existing - ! vegetation in the lowest layer, along with the area fraction - ! of those two (which should sum to unity). - - ! Arguments - type(ed_patch_type) :: cpatch - real(r8), intent(in) :: atm_par ! direct+diffuse PAR at canopy top [W/m2] - real(r8), intent(out) :: seedling_par_high ! High intensity PAR for seedlings [W/m2] - real(r8), intent(out) :: par_high_frac ! Area fraction with high intensity - real(r8), intent(out) :: seedling_par_low ! Low intensity PAR for seedlings [W/m2] - real(r8), intent(out) :: par_low_frac ! Area fraction with low intensity - - ! Locals - real(r8) :: upper_par ! The PAR intensity coming from the canopy layer above [w/m2] - real(r8) :: upper_area ! The area fraction of the upper canopy - real(r8) :: lower_par ! The PAR intensity under the lower-most canopy [W/m2] - real(r8) :: lower_area ! The area fractino of the lower canopy - integer :: cl ! current canopy layer - integer :: ipft ! current PFT index - integer :: iv ! lower-most leaf layer index for the cl & pft combo - - ! Radiation intensity exiting the layer above the bottom-most - upper_par = 0._r8 - upper_area = 0._r8 - cl = max(1,cpatch%NCL_p-1) - do ipft = 1,numpft - iv = cpatch%ncan(cl,ft) - upper_par = upper_par + cpatch%canopy_area_profile(cl,ifpt,1)*& - (cpatch%parprof_pft_dir_z(cl,ipft,iv)+cpatch%parprof_pft_dif_z(cl,ipft,iv)) - upper_area = upper_area + cpatch%canopy_area_profile(cl,ifpt,1) - end do - if(upper_area>nearzero)then - upper_par = upper_par/upper_area - else - upper_par = 0._r8 - end if - - ! If we do have more than one layer, then we need to figure out - ! the average of light on the exposed ground under the veg - - if(cpatch%NCL_p>1) then - - ! Factor in atmospheric downwelling radiation if the upper - ! layer happens to be the top-most - if(cl==1)then - upper_par = cpatch%total_canopy_area*upper_par + & - (1._r8-cpatch%total_canopy_area)*(bc_in(s)%solad_parb(ifp,ipar)+bc_in(s)%solai_parb(ifp,ipar)) - end if - - cl = cpatch%NCL_p - lower_area = 0._r8 - lower_par = 0._r8 - do ipft = 1,numpft - iv = cpatch%ncan(cl,ft) - lower_area = lower_area+cpatch%canopy_area_profile(cl,ifpt,1) - par_bottom = cpatch%parprof_pft_dir_z(cl,ipft,iv) + & - cpatch%parprof_pft_dif_z(cl,ipft,iv) - lower_par = lower_par + cpatch%canopy_area_profile(cl,ifpt,1)*par_bottom - end do - if(lower_area>nearzero)then - lower_par = lower_par / lower_area - else - lower_par = 0._r8 - end if - - seedling_par_high = upper_par - par_high_frac = (1._r8-lower_area) - seedling_par_low = lower_par/lower_ara - par_low_frac = lower_area - - else - - seedling_par_high = bc_in(s)%solad_parb(ifp,ipar)+bc_in(s)%solai_parb(ifp,ipar) - par_high_frac = 1._r8-cpatch%total_canopy_area - seedling_par_low = upper_par - par_low_frac = cpatch%total_canopy_area - - end if - - return + end module EDTypesMod diff --git a/main/FatesInterfaceMod.F90 b/main/FatesInterfaceMod.F90 index 734392147b..78ea664d0e 100644 --- a/main/FatesInterfaceMod.F90 +++ b/main/FatesInterfaceMod.F90 @@ -1954,14 +1954,16 @@ subroutine UpdateFatesRMeansTStep(sites,bc_in) type(ed_patch_type), pointer :: cpatch type(ed_cohort_type), pointer :: ccohort integer :: s, ifp, io_si, pft - real(r8) :: new_seedling_layer_par !seedling layer par in the current timestep - real(r8) :: new_seedling_layer_smp(maxpft) !seedling layer smp in the current timestep - real(r8) :: new_seedling_mdd(maxpft) !seedling layer moisture deficit days in the current timestep - integer :: ilayer_seedling_root(maxpft) !the soil layer at seedling rooting depth - integer :: n_leaf !number of leaf layers per canopy layer in patch - real(r8) :: lai_sun_frac - real(r8) :: lai_shade_frac - integer,parameter :: ipar = 1 !solar radiation in the shortwave band (i.e. par) + real(r8) :: new_seedling_layer_par ! seedling layer par in the current timestep + real(r8) :: new_seedling_layer_smp(maxpft) ! seedling layer smp in the current timestep + real(r8) :: new_seedling_mdd(maxpft) ! seedling layer moisture deficit days in the current timestep + integer :: ilayer_seedling_root(maxpft) ! the soil layer at seedling rooting depth + integer :: n_leaf ! number of leaf layers per canopy layer in patch + real(r8) :: seedling_par_high ! higher intensity par for seedlings (par at exposed ground) [W/m2] + real(r8) :: par_high_frac ! fraction of ground where PAR is high + real(r8) :: seedling_par_low ! lower intensity par for seedlings (par under the undergrowth) [W/m2] + real(r8) :: par_low_frac ! fraction of ground where PAR is low + integer,parameter :: ipar = 1 ! solar radiation in the shortwave band (i.e. par) do s = 1,size(sites,dim=1) @@ -2010,7 +2012,7 @@ subroutine UpdateFatesRMeansTStep(sites,bc_in) ! If mdds are negative then it means that soil is wetter than smp_crit and the moisture ! deficit is 0 if (new_seedling_mdd(pft) < 0.0_r8) then - new_seedling_mdd(pft) = 0.0_r8 + new_seedling_mdd(pft) = 0.0_r8 endif ! Update the seedling layer smp and mdd running means @@ -2024,13 +2026,105 @@ subroutine UpdateFatesRMeansTStep(sites,bc_in) ! call ccohort%tveg_lpa%UpdateRMean(bc_in(s)%t_veg_pa(ifp)) ! ccohort => ccohort%shorter !end do - end if - - cpatch => cpatch%younger - enddo + end if + + cpatch => cpatch%younger + enddo + end do + + return +end subroutine UpdateFatesRMeansTStep + +! ======================================================================================== + +subroutine SeedlingParPatch(cpatch, & + atm_par, & + seedling_par_high, par_high_frac, & + seedling_par_low, par_low_frac) + + ! Calculate the intensity of PAR for seedlings in the current patch. + ! To do this, we need to get a weighted average of light penetrating + ! though (parprof) the lowest leaf layers. We will need to identify + ! how closed (area) the lowest canopy layer is, because we will use + ! an area weighted average of the light coming from the canopy above + ! and an area weighted average of the light penetrating through the + ! existing portino of the lowest layer. + ! + ! This routine will generate two intensities, light levels on the exposed + ! ground in the lowest layer, and light levels under the existing + ! vegetation in the lowest layer, along with the area fraction + ! of those two (which should sum to unity). + + ! Arguments + type(ed_patch_type) :: cpatch ! the current patch + real(r8), intent(in) :: atm_par ! direct+diffuse PAR at canopy top [W/m2] + real(r8), intent(out) :: seedling_par_high ! High intensity PAR for seedlings [W/m2] + real(r8), intent(out) :: par_high_frac ! Area fraction with high intensity + real(r8), intent(out) :: seedling_par_low ! Low intensity PAR for seedlings [W/m2] + real(r8), intent(out) :: par_low_frac ! Area fraction with low intensity + + ! Locals + real(r8) :: upper_par ! The PAR intensity coming from the canopy layer above [w/m2] + real(r8) :: upper_area ! The area fraction of the upper canopy + real(r8) :: lower_par ! The PAR intensity under the lower-most canopy [W/m2] + real(r8) :: lower_area ! The area fractino of the lower canopy + integer :: cl ! current canopy layer + integer :: ipft ! current PFT index + integer :: iv ! lower-most leaf layer index for the cl & pft combo + + ! Radiation intensity exiting the layer above the bottom-most + upper_par = 0._r8 + upper_area = 0._r8 + cl = max(1,cpatch%NCL_p-1) + do ipft = 1,numpft + iv = cpatch%ncan(cl,ipft) + upper_par = upper_par + cpatch%canopy_area_profile(cl,ipft,1)* & + (cpatch%parprof_pft_dir_z(cl,ipft,iv)+cpatch%parprof_pft_dif_z(cl,ipft,iv)) + upper_area = upper_area + cpatch%canopy_area_profile(cl,ipft,1) + end do + if(upper_area>nearzero)then + upper_par = upper_par/upper_area + else + upper_par = 0._r8 + end if + + ! If we do have more than one layer, then we need to figure out + ! the average of light on the exposed ground under the veg + + if(cpatch%NCL_p>1) then + + cl = cpatch%NCL_p + lower_area = 0._r8 + lower_par = 0._r8 + do ipft = 1,numpft + iv = cpatch%ncan(cl,ipft) + lower_area = lower_area+cpatch%canopy_area_profile(cl,ipft,1) + lower_par = lower_par + & + cpatch%canopy_area_profile(cl,ipft,1)*& + (cpatch%parprof_pft_dir_z(cl,ipft,iv) + cpatch%parprof_pft_dif_z(cl,ipft,iv)) end do + if(lower_area>nearzero)then + lower_par = lower_par / lower_area + else + lower_par = 0._r8 + end if - return - end subroutine UpdateFatesRMeansTStep - - end module FatesInterfaceMod + seedling_par_high = upper_par + par_high_frac = (1._r8-lower_area) + seedling_par_low = lower_par/lower_area + par_low_frac = lower_area + + else + + seedling_par_high = atm_par + par_high_frac = 1._r8-cpatch%total_canopy_area + seedling_par_low = upper_par + par_low_frac = cpatch%total_canopy_area + + end if + + return +end subroutine SeedlingParPatch + + +end module FatesInterfaceMod From c276459897303884948c3de213da57fb3a862356 Mon Sep 17 00:00:00 2001 From: Ryan Knox Date: Tue, 13 Jun 2023 17:56:25 -0400 Subject: [PATCH 69/81] removed unused variable --- main/FatesInterfaceMod.F90 | 1 - 1 file changed, 1 deletion(-) diff --git a/main/FatesInterfaceMod.F90 b/main/FatesInterfaceMod.F90 index 78ea664d0e..3593f5b143 100644 --- a/main/FatesInterfaceMod.F90 +++ b/main/FatesInterfaceMod.F90 @@ -1958,7 +1958,6 @@ subroutine UpdateFatesRMeansTStep(sites,bc_in) real(r8) :: new_seedling_layer_smp(maxpft) ! seedling layer smp in the current timestep real(r8) :: new_seedling_mdd(maxpft) ! seedling layer moisture deficit days in the current timestep integer :: ilayer_seedling_root(maxpft) ! the soil layer at seedling rooting depth - integer :: n_leaf ! number of leaf layers per canopy layer in patch real(r8) :: seedling_par_high ! higher intensity par for seedlings (par at exposed ground) [W/m2] real(r8) :: par_high_frac ! fraction of ground where PAR is high real(r8) :: seedling_par_low ! lower intensity par for seedlings (par under the undergrowth) [W/m2] From 3fb867309b2a81a7e0eac9ce05a8439f1586e364 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Fri, 30 Jun 2023 15:10:21 -0700 Subject: [PATCH 70/81] remove regeneration model setting check This came in with a previous pull request that included multiple pull request updates to the default parameter file. This protection is no longer needed for this specific pull request. --- main/EDPftvarcon.F90 | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/main/EDPftvarcon.F90 b/main/EDPftvarcon.F90 index da5a064ca7..31c9a08ad5 100644 --- a/main/EDPftvarcon.F90 +++ b/main/EDPftvarcon.F90 @@ -1718,7 +1718,6 @@ subroutine FatesCheckParams(is_master) use EDParamsMod , only : logging_mechanical_frac, logging_collateral_frac use EDParamsMod , only : logging_direct_frac,logging_export_frac use EDParamsMod , only : radiation_model - use EDParamsMod , only : regeneration_model use FatesInterfaceTypesMod, only : hlm_use_fixed_biogeog,hlm_use_sp, hlm_name use FatesInterfaceTypesMod, only : hlm_use_inventory_init @@ -1750,16 +1749,6 @@ subroutine FatesCheckParams(is_master) call endrun(msg=errMsg(sourcefile, __LINE__)) end if - if(regeneration_model.ne.1) then - write(fates_log(),*) 'The only available regeneration model' - write(fates_log(),*) 'is the default, ie 1' - write(fates_log(),*) 'The Hanbury-Brown models are not available yet' - write(fates_log(),*) 'You specified fates_regeneration_model = ',regeneration_model - write(fates_log(),*) 'Aborting' - call endrun(msg=errMsg(sourcefile, __LINE__)) - end if - - select case (hlm_parteh_mode) case (prt_cnp_flex_allom_hyp) From 7395273ce1e6b52989d376c84ae36a2d2a9c3948 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Thu, 6 Jul 2023 11:45:43 -0700 Subject: [PATCH 71/81] update seedlingparpatch to handle newly spawned patches Newly spawned patches that have treefall disturbance in the first canopy will not have cohorts until the recruitment step after this update. As such, avoid indexing via ncan which will be zero. --- main/FatesInterfaceMod.F90 | 45 +++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/main/FatesInterfaceMod.F90 b/main/FatesInterfaceMod.F90 index fac69a1716..01a5c49f55 100644 --- a/main/FatesInterfaceMod.F90 +++ b/main/FatesInterfaceMod.F90 @@ -1983,10 +1983,8 @@ subroutine UpdateFatesRMeansTStep(sites,bc_in) call SeedlingParPatch(cpatch, & bc_in(s)%solad_parb(ifp,ipar) + bc_in(s)%solai_parb(ifp,ipar), & - seedling_par_high, & - par_high_frac, & - seedling_par_low, & - par_low_frac) + seedling_par_high, par_high_frac, seedling_par_low,& + & par_low_frac) new_seedling_layer_par = seedling_par_high*par_high_frac + seedling_par_low*par_low_frac @@ -2071,25 +2069,34 @@ subroutine SeedlingParPatch(cpatch, & integer :: ipft ! current PFT index integer :: iv ! lower-most leaf layer index for the cl & pft combo - ! Radiation intensity exiting the layer above the bottom-most - upper_par = 0._r8 - upper_area = 0._r8 - cl = max(1,cpatch%NCL_p-1) - do ipft = 1,numpft - iv = cpatch%ncan(cl,ipft) - upper_par = upper_par + cpatch%canopy_area_profile(cl,ipft,1)* & - (cpatch%parprof_pft_dir_z(cl,ipft,iv)+cpatch%parprof_pft_dif_z(cl,ipft,iv)) - upper_area = upper_area + cpatch%canopy_area_profile(cl,ipft,1) - end do - if(upper_area>nearzero)then - upper_par = upper_par/upper_area - else + + ! Check that there are cohorts on the current patch as this calculation is + ! not relevant in that case (and will result in an index error due to ncan being zero) + if (cpatch%countcohorts .gt. 0) then + + ! Radiation intensity exiting the layer above the bottom-most upper_par = 0._r8 + upper_area = 0._r8 + cl = max(1,cpatch%NCL_p-1) + do ipft = 1,numpft + iv = cpatch%ncan(cl,ipft) + upper_par = upper_par + cpatch%canopy_area_profile(cl,ipft,1)* & + (cpatch%parprof_pft_dir_z(cl,ipft,iv)+cpatch%parprof_pft_dif_z(cl,ipft,iv)) + upper_area = upper_area + cpatch%canopy_area_profile(cl,ipft,1) + end do + if(upper_area>nearzero)then + upper_par = upper_par/upper_area + else + upper_par = 0._r8 + end if + else + upper_par = fates_unset_r8 end if ! If we do have more than one layer, then we need to figure out ! the average of light on the exposed ground under the veg - + ! Note that newly spawned patches without cohorts have a default + ! NCL_p of one. if(cpatch%NCL_p>1) then cl = cpatch%NCL_p @@ -2115,6 +2122,8 @@ subroutine SeedlingParPatch(cpatch, & else + ! In the case where the patch is newly spawned and has no cohorts, + ! total_canopy_area should be zero seedling_par_high = atm_par par_high_frac = 1._r8-cpatch%total_canopy_area seedling_par_low = upper_par From 537301019b998e6130f347072143c00f2801dfde Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Thu, 6 Jul 2023 17:08:11 -0700 Subject: [PATCH 72/81] initial refactor of seedlingparpatch This refactor attempts to reduce repeated lines of code --- main/FatesInterfaceMod.F90 | 70 ++++++++++++-------------------------- 1 file changed, 22 insertions(+), 48 deletions(-) diff --git a/main/FatesInterfaceMod.F90 b/main/FatesInterfaceMod.F90 index 01a5c49f55..82d6e39f70 100644 --- a/main/FatesInterfaceMod.F90 +++ b/main/FatesInterfaceMod.F90 @@ -2069,68 +2069,42 @@ subroutine SeedlingParPatch(cpatch, & integer :: ipft ! current PFT index integer :: iv ! lower-most leaf layer index for the cl & pft combo + ! Assuming there is a single canopy layer + seedling_par_high = atm_par + par_high_frac = 1._r8-cpatch%total_canopy_area + par_low_frac = cpatch%total_canopy_area - ! Check that there are cohorts on the current patch as this calculation is - ! not relevant in that case (and will result in an index error due to ncan being zero) - if (cpatch%countcohorts .gt. 0) then - - ! Radiation intensity exiting the layer above the bottom-most + do cl = cpatch%NCL_p,max(1,cpatch%NCL_p-1),-1 upper_par = 0._r8 upper_area = 0._r8 - cl = max(1,cpatch%NCL_p-1) do ipft = 1,numpft iv = cpatch%ncan(cl,ipft) - upper_par = upper_par + cpatch%canopy_area_profile(cl,ipft,1)* & - (cpatch%parprof_pft_dir_z(cl,ipft,iv)+cpatch%parprof_pft_dif_z(cl,ipft,iv)) - upper_area = upper_area + cpatch%canopy_area_profile(cl,ipft,1) + ! Avoid calculating when there are no leaf layers for the given pft + if (iv .ne. 0) then + upper_par = upper_par + cpatch%canopy_area_profile(cl,ipft,1)* & + (cpatch%parprof_pft_dir_z(cl,ipft,iv)+cpatch%parprof_pft_dif_z(cl,ipft,iv)) + upper_area = upper_area + cpatch%canopy_area_profile(cl,ipft,1) + end if end do if(upper_area>nearzero)then upper_par = upper_par/upper_area else upper_par = 0._r8 end if - else - upper_par = fates_unset_r8 - end if - - ! If we do have more than one layer, then we need to figure out - ! the average of light on the exposed ground under the veg - ! Note that newly spawned patches without cohorts have a default - ! NCL_p of one. - if(cpatch%NCL_p>1) then - - cl = cpatch%NCL_p - lower_area = 0._r8 - lower_par = 0._r8 - do ipft = 1,numpft - iv = cpatch%ncan(cl,ipft) - lower_area = lower_area+cpatch%canopy_area_profile(cl,ipft,1) - lower_par = lower_par + & - cpatch%canopy_area_profile(cl,ipft,1)*& - (cpatch%parprof_pft_dir_z(cl,ipft,iv) + cpatch%parprof_pft_dif_z(cl,ipft,iv)) - end do - if(lower_area>nearzero)then - lower_par = lower_par / lower_area + + ! If we do have more than one layer, then we need to figure out + ! the average of light on the exposed ground under the veg + ! Note that newly spawned patches without cohorts have a default + ! NCL_p of one. + if(cl .lt. cpatch%NCL_p) then + seedling_par_high = seedling_par_low + par_high_frac = (1._r8-upper_area) + seedling_par_low = upper_par/upper_area + par_low_frac = upper_area else - lower_par = 0._r8 + seedling_par_low = upper_par end if - seedling_par_high = upper_par - par_high_frac = (1._r8-lower_area) - seedling_par_low = lower_par/lower_area - par_low_frac = lower_area - - else - - ! In the case where the patch is newly spawned and has no cohorts, - ! total_canopy_area should be zero - seedling_par_high = atm_par - par_high_frac = 1._r8-cpatch%total_canopy_area - seedling_par_low = upper_par - par_low_frac = cpatch%total_canopy_area - - end if - return end subroutine SeedlingParPatch From 06b92a97eba85d0ca918c5593acb907e0df7b0a5 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Thu, 6 Jul 2023 23:19:19 -0600 Subject: [PATCH 73/81] add missing end do --- main/FatesInterfaceMod.F90 | 1 + 1 file changed, 1 insertion(+) diff --git a/main/FatesInterfaceMod.F90 b/main/FatesInterfaceMod.F90 index 82d6e39f70..1fca2e0269 100644 --- a/main/FatesInterfaceMod.F90 +++ b/main/FatesInterfaceMod.F90 @@ -2104,6 +2104,7 @@ subroutine SeedlingParPatch(cpatch, & else seedling_par_low = upper_par end if + end do return end subroutine SeedlingParPatch From 53cd4a13e1d11a313174eb34682f450146dd5073 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Thu, 6 Jul 2023 23:32:13 -0700 Subject: [PATCH 74/81] update SeedlingParPatch to avoid zero ncan per pft --- main/FatesInterfaceMod.F90 | 40 ++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/main/FatesInterfaceMod.F90 b/main/FatesInterfaceMod.F90 index 01a5c49f55..5d7e96a6a8 100644 --- a/main/FatesInterfaceMod.F90 +++ b/main/FatesInterfaceMod.F90 @@ -2069,28 +2069,23 @@ subroutine SeedlingParPatch(cpatch, & integer :: ipft ! current PFT index integer :: iv ! lower-most leaf layer index for the cl & pft combo - - ! Check that there are cohorts on the current patch as this calculation is - ! not relevant in that case (and will result in an index error due to ncan being zero) - if (cpatch%countcohorts .gt. 0) then - - ! Radiation intensity exiting the layer above the bottom-most - upper_par = 0._r8 - upper_area = 0._r8 - cl = max(1,cpatch%NCL_p-1) - do ipft = 1,numpft - iv = cpatch%ncan(cl,ipft) + ! Radiation intensity exiting the layer above the bottom-most + upper_par = 0._r8 + upper_area = 0._r8 + cl = max(1,cpatch%NCL_p-1) + do ipft = 1,numpft + iv = cpatch%ncan(cl,ipft) + ! Avoid cases where ncan is zero for a given pft + if (iv .ne. 0) then upper_par = upper_par + cpatch%canopy_area_profile(cl,ipft,1)* & (cpatch%parprof_pft_dir_z(cl,ipft,iv)+cpatch%parprof_pft_dif_z(cl,ipft,iv)) upper_area = upper_area + cpatch%canopy_area_profile(cl,ipft,1) - end do - if(upper_area>nearzero)then - upper_par = upper_par/upper_area - else - upper_par = 0._r8 end if + end do + if(upper_area>nearzero)then + upper_par = upper_par/upper_area else - upper_par = fates_unset_r8 + upper_par = 0._r8 end if ! If we do have more than one layer, then we need to figure out @@ -2104,10 +2099,13 @@ subroutine SeedlingParPatch(cpatch, & lower_par = 0._r8 do ipft = 1,numpft iv = cpatch%ncan(cl,ipft) - lower_area = lower_area+cpatch%canopy_area_profile(cl,ipft,1) - lower_par = lower_par + & - cpatch%canopy_area_profile(cl,ipft,1)*& - (cpatch%parprof_pft_dir_z(cl,ipft,iv) + cpatch%parprof_pft_dif_z(cl,ipft,iv)) + ! Avoid cases where ncan is zero for a given pft + if (iv .ne. 0) then + lower_area = lower_area+cpatch%canopy_area_profile(cl,ipft,1) + lower_par = lower_par + & + cpatch%canopy_area_profile(cl,ipft,1)*& + (cpatch%parprof_pft_dir_z(cl,ipft,iv) + cpatch%parprof_pft_dif_z(cl,ipft,iv)) + end if end do if(lower_area>nearzero)then lower_par = lower_par / lower_area From 7eb363d79b8c79dcb0ea0c3d5631f10e9fc8fcf5 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Fri, 7 Jul 2023 00:37:24 -0600 Subject: [PATCH 75/81] update names and remove old code --- main/FatesInterfaceMod.F90 | 42 +++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/main/FatesInterfaceMod.F90 b/main/FatesInterfaceMod.F90 index 1fca2e0269..3dd713f5fb 100644 --- a/main/FatesInterfaceMod.F90 +++ b/main/FatesInterfaceMod.F90 @@ -2061,49 +2061,53 @@ subroutine SeedlingParPatch(cpatch, & real(r8), intent(out) :: par_low_frac ! Area fraction with low intensity ! Locals - real(r8) :: upper_par ! The PAR intensity coming from the canopy layer above [w/m2] - real(r8) :: upper_area ! The area fraction of the upper canopy - real(r8) :: lower_par ! The PAR intensity under the lower-most canopy [W/m2] - real(r8) :: lower_area ! The area fractino of the lower canopy + real(r8) :: cl_par ! The PAR intensity coming from the canopy layer [w/m2] + real(r8) :: cl_area ! The area fraction of the given canopy layer integer :: cl ! current canopy layer integer :: ipft ! current PFT index integer :: iv ! lower-most leaf layer index for the cl & pft combo - ! Assuming there is a single canopy layer + ! Start with the assumption that there is a single canopy layer seedling_par_high = atm_par par_high_frac = 1._r8-cpatch%total_canopy_area par_low_frac = cpatch%total_canopy_area + ! Work up through the canopy layers from the bottom layer do cl = cpatch%NCL_p,max(1,cpatch%NCL_p-1),-1 - upper_par = 0._r8 - upper_area = 0._r8 + cl_par = 0._r8 + cl_area = 0._r8 do ipft = 1,numpft iv = cpatch%ncan(cl,ipft) - ! Avoid calculating when there are no leaf layers for the given pft + ! Avoid calculating when there are no leaf layers for the given pft in the current canopy layer if (iv .ne. 0) then - upper_par = upper_par + cpatch%canopy_area_profile(cl,ipft,1)* & + cl_par = cl_par + cpatch%canopy_area_profile(cl,ipft,1)* & (cpatch%parprof_pft_dir_z(cl,ipft,iv)+cpatch%parprof_pft_dif_z(cl,ipft,iv)) - upper_area = upper_area + cpatch%canopy_area_profile(cl,ipft,1) + cl_area = cl_area + cpatch%canopy_area_profile(cl,ipft,1) end if end do - if(upper_area>nearzero)then - upper_par = upper_par/upper_area + + ! Set the cl_par to zero if the area is near zero. Otherwise scale the par by the area + if(cl_area>nearzero)then + cl_par = cl_par/cl_area else - upper_par = 0._r8 + cl_par = 0._r8 end if ! If we do have more than one layer, then we need to figure out ! the average of light on the exposed ground under the veg - ! Note that newly spawned patches without cohorts have a default - ! NCL_p of one. + ! Since we are working up through the canopy layers from the ground, + ! set the par_high to the previous par_low value and update + ! the par_low to the new cl_par value if(cl .lt. cpatch%NCL_p) then seedling_par_high = seedling_par_low - par_high_frac = (1._r8-upper_area) - seedling_par_low = upper_par/upper_area - par_low_frac = upper_area + par_high_frac = (1._r8-cl_area) + seedling_par_low = cl_par + par_low_frac = cl_area + ! If we only have one layer, only set the seedling_par_low else - seedling_par_low = upper_par + seedling_par_low = cl_par end if + end do return From c295e3eb55b10c5d46de93c1a35fffcb8d736097 Mon Sep 17 00:00:00 2001 From: Ryan Knox Date: Tue, 18 Jul 2023 15:16:20 -0400 Subject: [PATCH 76/81] Added allocation restrictions on TRS running means, reduced memory usage, fixed restarts for TRS --- biogeochem/EDPatchDynamicsMod.F90 | 97 +++++++++++++------------ biogeochem/EDPhysiologyMod.F90 | 86 +++++++++++----------- main/FatesInterfaceMod.F90 | 100 +++++++++++++------------- main/FatesRestartInterfaceMod.F90 | 116 +++++++++++++++++------------- parteh/PRTAllometricCNPMod.F90 | 28 ++++++-- parteh/PRTAllometricCarbonMod.F90 | 44 +++++++----- 6 files changed, 261 insertions(+), 210 deletions(-) diff --git a/biogeochem/EDPatchDynamicsMod.F90 b/biogeochem/EDPatchDynamicsMod.F90 index c4282f524c..81caad2b28 100644 --- a/biogeochem/EDPatchDynamicsMod.F90 +++ b/biogeochem/EDPatchDynamicsMod.F90 @@ -54,6 +54,7 @@ module EDPatchDynamicsMod use FatesConstantsMod , only : r8 => fates_r8 use FatesConstantsMod , only : itrue, ifalse use FatesConstantsMod , only : t_water_freeze_k_1atm + use FatesConstantsMod , only : TRS_regeneration use FatesPlantHydraulicsMod, only : InitHydrCohort use FatesPlantHydraulicsMod, only : AccumulateMortalityWaterStorage use FatesPlantHydraulicsMod, only : DeallocateHydrCohort @@ -64,6 +65,7 @@ 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 @@ -661,17 +663,19 @@ subroutine spawn_patches( currentSite, bc_in) ! -------------------------------------------------------------------------- call new_patch%tveg24%CopyFromDonor(currentPatch%tveg24) call new_patch%tveg_lpa%CopyFromDonor(currentPatch%tveg_lpa) - 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,maxpft - 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 + 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. @@ -2139,22 +2143,25 @@ subroutine create_patch(currentSite, new_patch, age, areap, label,nocomp_pft) call new_patch%tveg24%InitRMean(fixed_24hr,init_value=temp_init_veg,init_offset=real(hlm_current_tod,r8) ) allocate(new_patch%tveg_lpa) call new_patch%tveg_lpa%InitRmean(ema_lpa,init_value=temp_init_veg) - allocate(new_patch%seedling_layer_par24) - call new_patch%seedling_layer_par24%InitRMean(fixed_24hr,init_value=init_seedling_par, init_offset=real(hlm_current_tod,r8)) - allocate(new_patch%sdlng_mort_par) - call new_patch%sdlng_mort_par%InitRMean(ema_sdlng_mort_par,init_value=temp_init_veg) - allocate(new_patch%sdlng2sap_par) - call new_patch%sdlng2sap_par%InitRMean(ema_sdlng2sap_par,init_value=init_seedling_par) + - allocate(new_patch%sdlng_mdd(maxpft)) - allocate(new_patch%sdlng_emerg_smp(maxpft)) - - do pft = 1,maxpft - allocate(new_patch%sdlng_mdd(pft)%p) - call new_patch%sdlng_mdd(pft)%p%InitRMean(ema_sdlng_mdd, init_value=0.0_r8) - allocate(new_patch%sdlng_emerg_smp(pft)%p) - call new_patch%sdlng_emerg_smp(pft)%p%InitRMean(ema_sdlng_emerg_h2o,init_value=init_seedling_smp) - enddo + if ( regeneration_model == TRS_regeneration ) then + allocate(new_patch%seedling_layer_par24) + call new_patch%seedling_layer_par24%InitRMean(fixed_24hr,init_value=init_seedling_par, init_offset=real(hlm_current_tod,r8)) + allocate(new_patch%sdlng_mort_par) + call new_patch%sdlng_mort_par%InitRMean(ema_sdlng_mort_par,init_value=temp_init_veg) + allocate(new_patch%sdlng2sap_par) + call new_patch%sdlng2sap_par%InitRMean(ema_sdlng2sap_par,init_value=init_seedling_par) + allocate(new_patch%sdlng_mdd(numpft)) + allocate(new_patch%sdlng_emerg_smp(numpft)) + do pft = 1,numpft + allocate(new_patch%sdlng_mdd(pft)%p) + call new_patch%sdlng_mdd(pft)%p%InitRMean(ema_sdlng_mdd, init_value=0.0_r8) + allocate(new_patch%sdlng_emerg_smp(pft)%p) + call new_patch%sdlng_emerg_smp(pft)%p%InitRMean(ema_sdlng_emerg_h2o,init_value=init_seedling_smp) + enddo + end if + allocate(new_patch%tveg_longterm) call new_patch%tveg_longterm%InitRmean(ema_longterm,init_value=temp_init_veg) @@ -2730,16 +2737,18 @@ subroutine fuse_2_patches(csite, dp, rp) ! Weighted mean of the running means call rp%tveg24%FuseRMean(dp%tveg24,rp%area*inv_sum_area) call rp%tveg_lpa%FuseRMean(dp%tveg_lpa,rp%area*inv_sum_area) - call rp%seedling_layer_par24%FuseRMean(dp%seedling_layer_par24,rp%area*inv_sum_area) !ahb - call rp%tveg_longterm%FuseRMean(dp%tveg_longterm,rp%area*inv_sum_area) - - do pft = 1,maxpft - call rp%sdlng_emerg_smp(pft)%p%FuseRMean(dp%sdlng_emerg_smp(pft)%p,rp%area*inv_sum_area) !ahb - call rp%sdlng_mdd(pft)%p%FuseRMean(dp%sdlng_mdd(pft)%p,rp%area*inv_sum_area) !ahb - enddo - call rp%sdlng_mort_par%FuseRMean(dp%sdlng_mort_par,rp%area*inv_sum_area) !ahb - call rp%sdlng2sap_par%FuseRMean(dp%sdlng2sap_par,rp%area*inv_sum_area) !ahb + if ( regeneration_model == TRS_regeneration ) then + call rp%seedling_layer_par24%FuseRMean(dp%seedling_layer_par24,rp%area*inv_sum_area) + call rp%sdlng_mort_par%FuseRMean(dp%sdlng_mort_par,rp%area*inv_sum_area) + call rp%sdlng2sap_par%FuseRMean(dp%sdlng2sap_par,rp%area*inv_sum_area) + do pft = 1,numpft + call rp%sdlng_emerg_smp(pft)%p%FuseRMean(dp%sdlng_emerg_smp(pft)%p,rp%area*inv_sum_area) + call rp%sdlng_mdd(pft)%p%FuseRMean(dp%sdlng_mdd(pft)%p,rp%area*inv_sum_area) + enddo + end if + + call rp%tveg_longterm%FuseRMean(dp%tveg_longterm,rp%area*inv_sum_area) rp%fuel_eff_moist = (dp%fuel_eff_moist*dp%area + rp%fuel_eff_moist*rp%area) * inv_sum_area rp%livegrass = (dp%livegrass*dp%area + rp%livegrass*rp%area) * inv_sum_area @@ -3122,19 +3131,17 @@ subroutine dealloc_patch(cpatch) endif ! Deallocate any running means - deallocate(cpatch%seedling_layer_par24) - deallocate(cpatch%sdlng_mort_par) - deallocate(cpatch%sdlng2sap_par) - - do pft = 1, maxpft - deallocate(cpatch%sdlng_mdd(pft)%p) - deallocate(cpatch%sdlng_emerg_smp(pft)%p) - enddo - - - deallocate(cpatch%sdlng_mdd) - deallocate(cpatch%sdlng_emerg_smp) - + if ( regeneration_model == TRS_regeneration ) then + deallocate(cpatch%seedling_layer_par24) + deallocate(cpatch%sdlng_mort_par) + deallocate(cpatch%sdlng2sap_par) + do pft = 1, numpft + deallocate(cpatch%sdlng_mdd(pft)%p) + deallocate(cpatch%sdlng_emerg_smp(pft)%p) + enddo + deallocate(cpatch%sdlng_mdd) + deallocate(cpatch%sdlng_emerg_smp) + end if deallocate(cpatch%tveg24, stat=istat, errmsg=smsg) if (istat/=0) then diff --git a/biogeochem/EDPhysiologyMod.F90 b/biogeochem/EDPhysiologyMod.F90 index 3f70ff2f1d..cff1632775 100644 --- a/biogeochem/EDPhysiologyMod.F90 +++ b/biogeochem/EDPhysiologyMod.F90 @@ -2312,61 +2312,61 @@ subroutine SeedGermination( litt, cold_stat, drought_stat, bc_in, currentPatch ) ! that times the ratio of (hypothetical) seed mass to recruit biomass !============================================================================================== - do pft = 1,numpft - + do pft = 1,numpft + ! If the TRS's seedling dynamics is switched off, then we use FATES's default approach ! to germination - if ( regeneration_model == default_regeneration .or. & + if_tfs_or_def: if ( regeneration_model == default_regeneration .or. & regeneration_model == TRS_no_seedling_dyn .or. & prt_params%allom_dbh_maxheight(pft) < min_max_dbh_for_trees ) then - litt%seed_germ_in(pft) = min(litt%seed(pft) * EDPftvarcon_inst%germination_rate(pft), & - max_germination)*years_per_day - - ! If TRS seedling dynamics is switched on we calculate seedling emergence (i.e. germination) - ! as a pft-specific function of understory light and soil moisture. + litt%seed_germ_in(pft) = min(litt%seed(pft) * EDPftvarcon_inst%germination_rate(pft), & + max_germination)*years_per_day + + ! If TRS seedling dynamics is switched on we calculate seedling emergence (i.e. germination) + ! as a pft-specific function of understory light and soil moisture. else if ( regeneration_model == TRS_regeneration .and. & - prt_params%allom_dbh_maxheight(pft) > min_max_dbh_for_trees ) then - - ! Step 1. Calculate how germination rate is modified by understory light - ! This applies to photoblastic germinators (e.g. many tropical pioneers) + prt_params%allom_dbh_maxheight(pft) > min_max_dbh_for_trees ) then - ! Calculate mean PAR at the seedling layer (MJ m-2 day-1) over the prior 24 hours - seedling_layer_par = currentPatch%seedling_layer_par24%GetMean() * sec_per_day * megajoules_per_joule + ! Step 1. Calculate how germination rate is modified by understory light + ! This applies to photoblastic germinators (e.g. many tropical pioneers) - ! Calculate the photoblastic germination rate modifier (Eq. 3 Hanbury-Brown et al., 2022) - photoblastic_germ_modifier = seedling_layer_par / & - (seedling_layer_par + EDPftvarcon_inst%par_crit_germ(pft)) + ! Calculate mean PAR at the seedling layer (MJ m-2 day-1) over the prior 24 hours + seedling_layer_par = currentPatch%seedling_layer_par24%GetMean() * sec_per_day * megajoules_per_joule - ! Step 2. Calculate how germination rate is modified by soil moisture in the rooting zone of - ! the seedlings. This is a pft-specific running mean based on pft-specific seedling rooting - ! depth. + ! Calculate the photoblastic germination rate modifier (Eq. 3 Hanbury-Brown et al., 2022) + photoblastic_germ_modifier = seedling_layer_par / & + (seedling_layer_par + EDPftvarcon_inst%par_crit_germ(pft)) - ! Get running mean of soil matric potential (mm of H2O suction) at the seedling rooting depth - ! This running mean based on pft-specific seedling rooting depth. - seedling_layer_smp = currentPatch%sdlng_emerg_smp(pft)%p%GetMean() + ! Step 2. Calculate how germination rate is modified by soil moisture in the rooting zone of + ! the seedlings. This is a pft-specific running mean based on pft-specific seedling rooting + ! depth. - ! Calculate a soil wetness index (1 / -soil matric pontential (MPa) ) used by the TRS - ! to calculate seedling mortality from moisture stress. - wetness_index = 1.0_r8 / (seedling_layer_smp * (-1.0_r8) * mpa_per_mm_suction) + ! Get running mean of soil matric potential (mm of H2O suction) at the seedling rooting depth + ! This running mean based on pft-specific seedling rooting depth. + seedling_layer_smp = currentPatch%sdlng_emerg_smp(pft)%p%GetMean() - ! Step 3. Calculate the seedling emergence rate based on soil moisture and germination - ! rate modifier (Step 1). See Eq. 4 of Hanbury-Brown et al., 2022 - - ! If SMP is below a pft-specific value, then no germination occurs - if ( seedling_layer_smp .GE. EDPftvarcon_inst%seedling_psi_emerg(pft) ) then - seedling_emerg_rate = photoblastic_germ_modifier * EDPftvarcon_inst%a_emerg(pft) * & - wetness_index**EDPftvarcon_inst%b_emerg(pft) - else - - seedling_emerg_rate = 0.0_r8 - - end if ! End soil-moisture based seedling emergence rate - - ! Step 4. Calculate the amount of carbon germinating out of the seed bank - litt%seed_germ_in(pft) = litt%seed(pft) * seedling_emerg_rate - - end if !End use TRS with seedling dynamics + ! Calculate a soil wetness index (1 / -soil matric pontential (MPa) ) used by the TRS + ! to calculate seedling mortality from moisture stress. + wetness_index = 1.0_r8 / (seedling_layer_smp * (-1.0_r8) * mpa_per_mm_suction) + + ! Step 3. Calculate the seedling emergence rate based on soil moisture and germination + ! rate modifier (Step 1). See Eq. 4 of Hanbury-Brown et al., 2022 + + ! If SMP is below a pft-specific value, then no germination occurs + if ( seedling_layer_smp .GE. EDPftvarcon_inst%seedling_psi_emerg(pft) ) then + seedling_emerg_rate = photoblastic_germ_modifier * EDPftvarcon_inst%a_emerg(pft) * & + wetness_index**EDPftvarcon_inst%b_emerg(pft) + else + + seedling_emerg_rate = 0.0_r8 + + end if ! End soil-moisture based seedling emergence rate + + ! Step 4. Calculate the amount of carbon germinating out of the seed bank + litt%seed_germ_in(pft) = litt%seed(pft) * seedling_emerg_rate + + end if if_tfs_or_def !set the germination only under the growing season...c.xu diff --git a/main/FatesInterfaceMod.F90 b/main/FatesInterfaceMod.F90 index 3dd713f5fb..0544fba060 100644 --- a/main/FatesInterfaceMod.F90 +++ b/main/FatesInterfaceMod.F90 @@ -1954,15 +1954,15 @@ subroutine UpdateFatesRMeansTStep(sites,bc_in) type(ed_patch_type), pointer :: cpatch type(ed_cohort_type), pointer :: ccohort integer :: s, ifp, io_si, pft - real(r8) :: new_seedling_layer_par ! seedling layer par in the current timestep - real(r8) :: new_seedling_layer_smp(maxpft) ! seedling layer smp in the current timestep - real(r8) :: new_seedling_mdd(maxpft) ! seedling layer moisture deficit days in the current timestep - integer :: ilayer_seedling_root(maxpft) ! the soil layer at seedling rooting depth - real(r8) :: seedling_par_high ! higher intensity par for seedlings (par at exposed ground) [W/m2] - real(r8) :: par_high_frac ! fraction of ground where PAR is high - real(r8) :: seedling_par_low ! lower intensity par for seedlings (par under the undergrowth) [W/m2] - real(r8) :: par_low_frac ! fraction of ground where PAR is low - integer,parameter :: ipar = 1 ! solar radiation in the shortwave band (i.e. par) + real(r8) :: new_seedling_layer_par ! seedling layer par in the current timestep + real(r8) :: new_seedling_layer_smp ! seedling layer smp in the current timestep + real(r8) :: new_seedling_mdd ! seedling layer moisture deficit days in the current timestep + integer :: ilayer_seedling_root ! the soil layer at seedling rooting depth + real(r8) :: seedling_par_high ! higher intensity par for seedlings (par at exposed ground) [W/m2] + real(r8) :: par_high_frac ! fraction of ground where PAR is high + real(r8) :: seedling_par_low ! lower intensity par for seedlings (par under the undergrowth) [W/m2] + real(r8) :: par_low_frac ! fraction of ground where PAR is low + integer,parameter :: ipar = 1 ! solar radiation in the shortwave band (i.e. par) do s = 1,size(sites,dim=1) @@ -1975,49 +1975,53 @@ subroutine UpdateFatesRMeansTStep(sites,bc_in) call cpatch%tveg_lpa%UpdateRMean(bc_in(s)%t_veg_pa(ifp)) call cpatch%tveg_longterm%UpdateRMean(bc_in(s)%t_veg_pa(ifp)) - ! Return the par intensity at the ground. This routine - ! breaks it up into high and low light levels. The high - ! levels are the light on the exposed ground at the surface - ! and the low levels are the intensity under the bottom-most - ! vegetation. - - call SeedlingParPatch(cpatch, & - bc_in(s)%solad_parb(ifp,ipar) + bc_in(s)%solai_parb(ifp,ipar), & - seedling_par_high, par_high_frac, seedling_par_low,& - & par_low_frac) - - new_seedling_layer_par = seedling_par_high*par_high_frac + seedling_par_low*par_low_frac + ! Update the seedling layer par running means - call cpatch%seedling_layer_par24%UpdateRMean(new_seedling_layer_par) - call cpatch%sdlng_mort_par%UpdateRMean(new_seedling_layer_par) - call cpatch%sdlng2sap_par%UpdateRMean(new_seedling_layer_par) + if ( regeneration_model == TRS_regeneration ) then - !write(fates_log(),*) 'new_seedling_layer_par', new_seedling_layer_par + ! Return the par intensity at the ground. This routine + ! breaks it up into high and low light levels. The high + ! levels are the light on the exposed ground at the surface + ! and the low levels are the intensity under the bottom-most + ! vegetation. + + call SeedlingParPatch(cpatch, & + bc_in(s)%solad_parb(ifp,ipar) + bc_in(s)%solai_parb(ifp,ipar), & + seedling_par_high, par_high_frac, seedling_par_low,& + & par_low_frac) + + new_seedling_layer_par = seedling_par_high*par_high_frac + seedling_par_low*par_low_frac + + call cpatch%seedling_layer_par24%UpdateRMean(new_seedling_layer_par) + call cpatch%sdlng_mort_par%UpdateRMean(new_seedling_layer_par) + call cpatch%sdlng2sap_par%UpdateRMean(new_seedling_layer_par) + + do pft = 1,numpft + + ! Calculate the soil moisture at the seedling rooting depth for each pft + + ilayer_seedling_root = minloc(abs(bc_in(s)%z_sisl(:)-EDPftvarcon_inst%seedling_root_depth(pft)),dim=1) + new_seedling_layer_smp = bc_in(s)%smp_sl(ilayer_seedling_root) + + ! Calculate the new moisture deficit day (mdd) value for each pft + new_seedling_mdd = (abs(EDPftvarcon_inst%seedling_psi_crit(pft)) - abs(new_seedling_layer_smp)) & + * (-1.0_r8) * sdlng_mdd_timescale + + ! If mdds are negative then it means that soil is wetter than smp_crit and the moisture + ! deficit is 0 + if (new_seedling_mdd < 0.0_r8) then + new_seedling_mdd = 0.0_r8 + endif + + ! Update the seedling layer smp and mdd running means + call cpatch%sdlng_emerg_smp(pft)%p%UpdateRMean(new_seedling_layer_smp) + call cpatch%sdlng_mdd(pft)%p%UpdateRMean(new_seedling_mdd) + + enddo !end pft loop + + end if - do pft = 1,numpft - - ! Calculate the soil moisture at the seedling rooting depth for each pft - - ilayer_seedling_root(pft) = minloc(abs(bc_in(s)%z_sisl(:)-EDPftvarcon_inst%seedling_root_depth(pft)),dim=1) - new_seedling_layer_smp(pft) = bc_in(s)%smp_sl(ilayer_seedling_root(pft)) - - ! Calculate the new moisture deficit day (mdd) value for each pft - new_seedling_mdd(pft) = (abs(EDPftvarcon_inst%seedling_psi_crit(pft)) - abs(new_seedling_layer_smp(pft))) & - * (-1.0_r8) * sdlng_mdd_timescale - - ! If mdds are negative then it means that soil is wetter than smp_crit and the moisture - ! deficit is 0 - if (new_seedling_mdd(pft) < 0.0_r8) then - new_seedling_mdd(pft) = 0.0_r8 - endif - - ! Update the seedling layer smp and mdd running means - call cpatch%sdlng_emerg_smp(pft)%p%UpdateRMean(new_seedling_layer_smp(pft)) - call cpatch%sdlng_mdd(pft)%p%UpdateRMean(new_seedling_mdd(pft)) - - enddo !end pft loop - !ccohort => cpatch%tallest !do while (associated(ccohort)) ! call ccohort%tveg_lpa%UpdateRMean(bc_in(s)%t_veg_pa(ifp)) diff --git a/main/FatesRestartInterfaceMod.F90 b/main/FatesRestartInterfaceMod.F90 index 29395c56d5..ed77ae1d6f 100644 --- a/main/FatesRestartInterfaceMod.F90 +++ b/main/FatesRestartInterfaceMod.F90 @@ -1,15 +1,17 @@ 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 : 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 FatesGlobals, only : fates_log use FatesGlobals, only : endrun => fates_endrun use FatesIODimensionsMod, only : fates_io_dimension_type @@ -47,7 +49,8 @@ module FatesRestartInterfaceMod use PRTGenericMod, only : num_elements use FatesRunningMeanMod, only : rmean_type use FatesRunningMeanMod, only : ema_lpa - + use EDParamsMod, only : regeneration_model + ! CIME GLOBALS use shr_log_mod , only : errMsg => shr_log_errMsg @@ -157,12 +160,13 @@ module FatesRestartInterfaceMod ! Running Means integer :: ir_tveg24_pa integer :: ir_tveglpa_pa - integer :: ir_seedling_layer_par24_pa !ahb - integer :: ir_sdlng_emerg_smp_pa !ahb - integer :: ir_sdlng_mort_par_pa ! ahb - integer :: ir_sdlng2sap_par_pa ! ahb - integer :: ir_sdlng_mdd_pa ! ahb + integer :: ir_seedling_layer_par24_pa + integer :: ir_sdlng_emerg_smp_pa + integer :: ir_sdlng_mort_par_pa + integer :: ir_sdlng2sap_par_pa + integer :: ir_sdlng_mdd_pa integer :: ir_tveglongterm_pa + ! (Keeping as an example) !!integer :: ir_tveglpa_co @@ -1461,26 +1465,30 @@ 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_seedling_layer_par24',vtype=cohort_r8, & - long_name='24-hour seedling layer PAR', & - units='W m2-1', initialize=initialize_variables,ivar=ivar, index = ir_seedling_layer_par24_pa) - - call this%DefineRMeanRestartVar(vname='fates_sdlng_emerg_smp',vtype=cohort_r8, & - long_name='seedling layer PAR on the seedling emergence timescale', & - units='mm suction', initialize=initialize_variables,ivar=ivar, index = ir_sdlng_emerg_smp_pa) - - call this%DefineRMeanRestartVar(vname='fates_sdlng_mort_par',vtype=cohort_r8, & - long_name='seedling layer PAR on the seedling mortality timescale', & - units='W m2-1', initialize=initialize_variables,ivar=ivar, index = ir_sdlng_mort_par_pa) - - call this%DefineRMeanRestartVar(vname='fates_sdlng2sap_par',vtype=cohort_r8, & - long_name='seedling layer PAR on the seedling to sapling transition timescale', & - units='W m2-1', initialize=initialize_variables,ivar=ivar, index = ir_sdlng2sap_par_pa) - - call this%DefineRMeanRestartVar(vname='fates_sdlng_mdd',vtype=cohort_r8, & - long_name='seedling moisture deficit days', & - units='mm days', initialize=initialize_variables,ivar=ivar, index = ir_sdlng_mdd_pa) + if ( regeneration_model == TRS_regeneration ) then + + call this%DefineRMeanRestartVar(vname='fates_seedling_layer_par24',vtype=cohort_r8, & + long_name='24-hour seedling layer PAR', & + units='W m2-1', initialize=initialize_variables,ivar=ivar, index = ir_seedling_layer_par24_pa) + + call this%DefineRMeanRestartVar(vname='fates_sdlng_emerg_smp',vtype=cohort_r8, & + long_name='seedling layer PAR on the seedling emergence timescale', & + units='mm suction', initialize=initialize_variables,ivar=ivar, index = ir_sdlng_emerg_smp_pa) + + call this%DefineRMeanRestartVar(vname='fates_sdlng_mort_par',vtype=cohort_r8, & + long_name='seedling layer PAR on the seedling mortality timescale', & + units='W m2-1', initialize=initialize_variables,ivar=ivar, index = ir_sdlng_mort_par_pa) + + call this%DefineRMeanRestartVar(vname='fates_sdlng2sap_par',vtype=cohort_r8, & + long_name='seedling layer PAR on the seedling to sapling transition timescale', & + units='W m2-1', initialize=initialize_variables,ivar=ivar, index = ir_sdlng2sap_par_pa) + + call this%DefineRMeanRestartVar(vname='fates_sdlng_mdd',vtype=cohort_r8, & + long_name='seedling moisture deficit days', & + units='mm days', initialize=initialize_variables,ivar=ivar, index = ir_sdlng_mdd_pa) + end if + call this%DefineRMeanRestartVar(vname='fates_tveglpapatch',vtype=cohort_r8, & long_name='running average (EMA) of patch veg temp for photo acclim', & units='K', initialize=initialize_variables,ivar=ivar, index = ir_tveglpa_pa) @@ -2360,14 +2368,18 @@ subroutine set_restart_vectors(this,nc,nsites,sites) call this%SetRMeanRestartVar(cpatch%tveg24, ir_tveg24_pa, io_idx_co_1st) call this%SetRMeanRestartVar(cpatch%tveg_lpa, ir_tveglpa_pa, io_idx_co_1st) call this%SetRMeanRestartVar(cpatch%tveg_longterm, ir_tveglongterm_pa, io_idx_co_1st) - call this%SetRMeanRestartVar(cpatch%seedling_layer_par24, ir_seedling_layer_par24_pa, io_idx_co_1st) - call this%SetRMeanRestartVar(cpatch%sdlng_mort_par, ir_sdlng_mort_par_pa,io_idx_co_1st) - call this%SetRMeanRestartVar(cpatch%sdlng2sap_par, ir_sdlng2sap_par_pa,io_idx_co_1st) - - do i_pft = 1, maxpft - call this%SetRMeanRestartVar(cpatch%sdlng_mdd(i_pft)%p, ir_sdlng_mdd_pa,io_idx_co_1st) - call this%SetRMeanRestartVar(cpatch%sdlng_emerg_smp(i_pft)%p, ir_sdlng_emerg_smp_pa,io_idx_co_1st) - enddo + + if ( regeneration_model == TRS_regeneration ) then + call this%SetRMeanRestartVar(cpatch%seedling_layer_par24, ir_seedling_layer_par24_pa, io_idx_co_1st) + call this%SetRMeanRestartVar(cpatch%sdlng_mort_par, ir_sdlng_mort_par_pa,io_idx_co_1st) + call this%SetRMeanRestartVar(cpatch%sdlng2sap_par, ir_sdlng2sap_par_pa,io_idx_co_1st) + io_idx_pa_pft = io_idx_co_1st + do i_pft = 1, numpft + call this%SetRMeanRestartVar(cpatch%sdlng_mdd(i_pft)%p, ir_sdlng_mdd_pa,io_idx_pa_pft) + call this%SetRMeanRestartVar(cpatch%sdlng_emerg_smp(i_pft)%p, ir_sdlng_emerg_smp_pa,io_idx_pa_pft) + io_idx_pa_pft = io_idx_pa_pft + 1 + enddo + end if ! set cohorts per patch for IO rio_ncohort_pa( io_idx_co_1st ) = cohortsperpatch @@ -3291,14 +3303,18 @@ subroutine get_restart_vectors(this, nc, nsites, sites) call this%GetRMeanRestartVar(cpatch%tveg24, ir_tveg24_pa, io_idx_co_1st) call this%GetRMeanRestartVar(cpatch%tveg_lpa, ir_tveglpa_pa, io_idx_co_1st) call this%GetRMeanRestartVar(cpatch%tveg_longterm, ir_tveglongterm_pa, io_idx_co_1st) - call this%GetRMeanRestartVar(cpatch%seedling_layer_par24, ir_seedling_layer_par24_pa, io_idx_co_1st) - call this%GetRMeanRestartVar(cpatch%sdlng_mort_par, ir_sdlng_mort_par_pa,io_idx_co_1st) - call this%GetRMeanRestartVar(cpatch%sdlng2sap_par, ir_sdlng2sap_par_pa,io_idx_co_1st) - - do pft = 1, maxpft - call this%GetRMeanRestartVar(cpatch%sdlng_mdd(pft)%p, ir_sdlng_mdd_pa,io_idx_co_1st) - call this%GetRMeanRestartVar(cpatch%sdlng_emerg_smp(pft)%p, ir_sdlng_emerg_smp_pa,io_idx_co_1st) - enddo + + if ( regeneration_model == TRS_regeneration ) then + call this%GetRMeanRestartVar(cpatch%seedling_layer_par24, ir_seedling_layer_par24_pa, io_idx_co_1st) + call this%GetRMeanRestartVar(cpatch%sdlng_mort_par, ir_sdlng_mort_par_pa,io_idx_co_1st) + call this%GetRMeanRestartVar(cpatch%sdlng2sap_par, ir_sdlng2sap_par_pa,io_idx_co_1st) + io_idx_pa_pft = io_idx_co_1st + do pft = 1, numpft + call this%GetRMeanRestartVar(cpatch%sdlng_mdd(pft)%p, ir_sdlng_mdd_pa,io_idx_pa_pft) + call this%GetRMeanRestartVar(cpatch%sdlng_emerg_smp(pft)%p, ir_sdlng_emerg_smp_pa,io_idx_pa_pft) + io_idx_pa_pft = io_idx_pa_pft + 1 + enddo + end if ! set cohorts per patch for IO diff --git a/parteh/PRTAllometricCNPMod.F90 b/parteh/PRTAllometricCNPMod.F90 index 113d9b95a2..b97bfe68cd 100644 --- a/parteh/PRTAllometricCNPMod.F90 +++ b/parteh/PRTAllometricCNPMod.F90 @@ -1487,11 +1487,15 @@ subroutine CNPStatureGrowth(this,c_gain, n_gain, p_gain, & ! just different from the other pools. It is not based on proportionality, ! so its mask is set differently. We (inefficiently) just included ! reproduction in the previous loop, but oh well, we over-write now. - - ! If the TRS is switched off then we use FATES's default reproductive allocation. + + ! If the TRS is switched off, or if the plant is a shrub or grass + ! then we use FATES's default reproductive allocation. + ! We designate a plant a shrub or grass if its dbh at maximum height + ! is less than 15 cm + if ( regeneration_model == default_regeneration .or. & - prt_params%allom_dbh_maxheight(ipft) < min_max_dbh_for_trees ) then ! The Tree Recruitment Scheme - ! is only for trees + prt_params%allom_dbh_maxheight(ipft) < min_max_dbh_for_trees ) then + if (dbh <= prt_params%dbh_repro_threshold(ipft)) then repro_c_frac = prt_params%seed_alloc(ipft) else @@ -1508,6 +1512,12 @@ subroutine CNPStatureGrowth(this,c_gain, n_gain, p_gain, & (exp(prt_params%repro_alloc_b(ipft) + prt_params%repro_alloc_a(ipft)*dbh*mm_per_cm) / & (1 + exp(prt_params%repro_alloc_b(ipft) + prt_params%repro_alloc_a(ipft)*dbh*mm_per_cm))) + else + + write(fates_log(),*) 'unknown seed allocation and regeneration model, exiting' + write(fates_log(),*) 'regeneration_model: ',regeneration_model + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if ! regeneration switch @@ -2342,7 +2352,10 @@ function AllomCNPGrowthDeriv(l_state_array,l_state_mask,cbalance,intgr_params) r repro_fraction = prt_params%seed_alloc(ipft) * & (exp(prt_params%repro_alloc_b(ipft) + prt_params%repro_alloc_a(ipft)*dbh*mm_per_cm) / & (1 + exp(prt_params%repro_alloc_b(ipft) + prt_params%repro_alloc_a(ipft)*dbh*mm_per_cm))) - + else + write(fates_log(),*) 'unknown seed allocation and regeneration model, exiting' + write(fates_log(),*) 'regeneration_model: ',regeneration_model + call endrun(msg=errMsg(sourcefile, __LINE__)) end if ! regeneration switch else ! mask repro @@ -2475,7 +2488,10 @@ subroutine EstimateGrowthNC(this,target_c,target_dcdd,state_mask,avg_nc,avg_pc) repro_c_frac = prt_params%seed_alloc(ipft) * & (exp(prt_params%repro_alloc_b(ipft) + prt_params%repro_alloc_a(ipft)*dbh*mm_per_cm) / & (1 + exp(prt_params%repro_alloc_b(ipft) + prt_params%repro_alloc_a(ipft)*dbh*mm_per_cm))) - + else + write(fates_log(),*) 'unknown seed allocation and regeneration model, exiting' + write(fates_log(),*) 'regeneration_model: ',regeneration_model + call endrun(msg=errMsg(sourcefile, __LINE__)) end if ! regeneration switch else ! state mask diff --git a/parteh/PRTAllometricCarbonMod.F90 b/parteh/PRTAllometricCarbonMod.F90 index 6a1c7ab7a1..a9b3ea2ab8 100644 --- a/parteh/PRTAllometricCarbonMod.F90 +++ b/parteh/PRTAllometricCarbonMod.F90 @@ -1061,27 +1061,35 @@ function AllomCGrowthDeriv(c_pools,c_mask,cbalance,intgr_params) result(dCdx) ct_dagwdd, ct_dbgwdd, ct_dsapdd, ct_ddeaddd) call bstore_allom(dbh,ipft,crowndamage, canopy_trim,ct_store,ct_dstoredd) - ! If the TRS is switched off then we use FATES's default reproductive allocation. - if ( regeneration_model == default_regeneration .or. & - prt_params%allom_dbh_maxheight(ipft) < min_max_dbh_for_trees ) then !The Tree Recruitment Scheme - !is only for tree pfts - ! Calculate fraction of carbon going towards reproduction - if (dbh <= prt_params%dbh_repro_threshold(ipft)) then ! cap on leaf biomass - repro_fraction = prt_params%seed_alloc(ipft) - else - repro_fraction = prt_params%seed_alloc(ipft) + prt_params%seed_alloc_mature(ipft) - end if ! End dbh check on if to add additional carbon to reproduction. + ! If the TRS is switched off, or if the plant is a shrub or grass + ! then we use FATES's default reproductive allocation. + ! We designate a plant a shrub or grass if its dbh at maximum height + ! is less than 15 cm - ! If the TRS is switched on (with or w/o seedling dynamics) then reproductive allocation is - ! a pft-specific function of dbh. This allows for the representation of different - ! reproductive schedules (Wenk and Falster, 2015) - else if ( any(regeneration_model == [TRS_regeneration, TRS_no_seedling_dyn]) .and. & - prt_params%allom_dbh_maxheight(ipft) > min_max_dbh_for_trees ) then + if ( regeneration_model == default_regeneration .or. & + prt_params%allom_dbh_maxheight(ipft) < min_max_dbh_for_trees ) then - repro_fraction = prt_params%seed_alloc(ipft) * & - (exp(prt_params%repro_alloc_b(ipft) + prt_params%repro_alloc_a(ipft)*dbh*mm_per_cm) / & - (1 + exp(prt_params%repro_alloc_b(ipft) + prt_params%repro_alloc_a(ipft)*dbh*mm_per_cm))) + ! TRS is only for tree pfts + ! Calculate fraction of carbon going towards reproduction + if (dbh <= prt_params%dbh_repro_threshold(ipft)) then ! cap on leaf biomass + repro_fraction = prt_params%seed_alloc(ipft) + else + repro_fraction = prt_params%seed_alloc(ipft) + prt_params%seed_alloc_mature(ipft) + end if ! End dbh check on if to add additional carbon to reproduction. + + ! If the TRS is switched on (with or w/o seedling dynamics) then reproductive allocation is + ! a pft-specific function of dbh. This allows for the representation of different + ! reproductive schedules (Wenk and Falster, 2015) + else if ( any(regeneration_model == [TRS_regeneration, TRS_no_seedling_dyn]) .and. & + prt_params%allom_dbh_maxheight(ipft) > min_max_dbh_for_trees ) then + repro_fraction = prt_params%seed_alloc(ipft) * & + (exp(prt_params%repro_alloc_b(ipft) + prt_params%repro_alloc_a(ipft)*dbh*mm_per_cm) / & + (1 + exp(prt_params%repro_alloc_b(ipft) + prt_params%repro_alloc_a(ipft)*dbh*mm_per_cm))) + else + write(fates_log(),*) 'unknown seed allocation and regeneration model, exiting' + write(fates_log(),*) 'regeneration_model: ',regeneration_model + call endrun(msg=errMsg(sourcefile, __LINE__)) end if ! TRS switch dCdx = 0.0_r8 From 3f6b2be28483bc51127ef6f6b743f200be35e78b Mon Sep 17 00:00:00 2001 From: Ryan Knox Date: Tue, 18 Jul 2023 18:57:55 -0600 Subject: [PATCH 77/81] added use statement --- main/FatesInterfaceMod.F90 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/main/FatesInterfaceMod.F90 b/main/FatesInterfaceMod.F90 index 0544fba060..91308e9cf0 100644 --- a/main/FatesInterfaceMod.F90 +++ b/main/FatesInterfaceMod.F90 @@ -19,6 +19,7 @@ module FatesInterfaceMod use EDParamsMod , only : maxpatch_primary use EDParamsMod , only : maxpatch_secondary use EDParamsMod , only : max_cohort_per_patch + use EDParamsMod , only : regeneration_model use EDTypesMod , only : maxSWb use EDTypesMod , only : ivis use EDTypesMod , only : inir @@ -38,6 +39,7 @@ module FatesInterfaceMod use FatesConstantsMod , only : nearzero use FatesConstantsMod , only : sec_per_day use FatesConstantsMod , only : days_per_year + use FatesConstantsMod , only : TRS_regeneration use FatesGlobals , only : fates_global_verbose use FatesGlobals , only : fates_log use FatesGlobals , only : endrun => fates_endrun From 8d7764fe8fe0ad902daaf221128cec4647d93ab4 Mon Sep 17 00:00:00 2001 From: Ryan Knox Date: Wed, 19 Jul 2023 20:57:02 -0600 Subject: [PATCH 78/81] fix on germinated seed mortality, a switch check and history field names and units for seed_bank stuff --- biogeochem/EDPhysiologyMod.F90 | 234 +++++++++++++++--------------- main/EDPftvarcon.F90 | 16 +- main/FatesHistoryInterfaceMod.F90 | 32 ++-- 3 files changed, 152 insertions(+), 130 deletions(-) diff --git a/biogeochem/EDPhysiologyMod.F90 b/biogeochem/EDPhysiologyMod.F90 index cff1632775..a62a3c1f62 100644 --- a/biogeochem/EDPhysiologyMod.F90 +++ b/biogeochem/EDPhysiologyMod.F90 @@ -2103,47 +2103,46 @@ subroutine SeedIn( currentSite, bc_in ) if(currentSite%use_this_pft(pft).eq.itrue)then - ! Seed input from local sources (within site) - litt%seed_in_local(pft) = litt%seed_in_local(pft) + site_seed_rain(pft)/area - - ! 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. & - prt_params%allom_dbh_maxheight(pft) > min_max_dbh_for_trees) then - - ! Send a fraction of reproductive carbon to litter to account for - ! non-seed reproductive carbon (e.g. flowers, fruit, etc.) - litt%seed_decay(pft) = litt%seed_in_local(pft) * (1.0_r8 - EDPftvarcon_inst%repro_frac_seed(pft)) - - ! Note: The default regeneration scheme sends all reproductive carbon to seed - end if !Use TRS - - - ! If there is forced external seed rain, we calculate the input mass flux - ! from the different elements, using the mean stoichiometry of new - ! recruits for the current patch and lowest canopy position - - select case(element_id) - case(carbon12_element) - seed_stoich = 1._r8 - case(nitrogen_element) - seed_stoich = currentPatch%nitr_repro_stoich(pft) - case(phosphorus_element) - seed_stoich = currentPatch%phos_repro_stoich(pft) - case default - write(fates_log(), *) 'undefined element specified' - write(fates_log(), *) 'while defining forced external seed mass flux' - call endrun(msg=errMsg(sourcefile, __LINE__)) - end select - - ! Seed input from external sources (user param seed rain, or dispersal model) - seed_in_external = seed_stoich*EDPftvarcon_inst%seed_suppl(pft)*years_per_day - litt%seed_in_extern(pft) = litt%seed_in_extern(pft) + seed_in_external - - ! Seeds entering externally [kg/site/day] - site_mass%seed_in = site_mass%seed_in + seed_in_external*currentPatch%area - end if !use this pft + ! Seed input from local sources (within site) + litt%seed_in_local(pft) = litt%seed_in_local(pft) + site_seed_rain(pft)/area + + ! 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. & + prt_params%allom_dbh_maxheight(pft) > min_max_dbh_for_trees) then + + ! Send a fraction of reproductive carbon to litter to account for + ! non-seed reproductive carbon (e.g. flowers, fruit, etc.) + litt%seed_decay(pft) = litt%seed_in_local(pft) * (1.0_r8 - EDPftvarcon_inst%repro_frac_seed(pft)) + + ! Note: The default regeneration scheme sends all reproductive carbon to seed + end if !Use TRS + + ! If there is forced external seed rain, we calculate the input mass flux + ! from the different elements, using the mean stoichiometry of new + ! recruits for the current patch and lowest canopy position + + select case(element_id) + case(carbon12_element) + seed_stoich = 1._r8 + case(nitrogen_element) + seed_stoich = currentPatch%nitr_repro_stoich(pft) + case(phosphorus_element) + seed_stoich = currentPatch%phos_repro_stoich(pft) + case default + write(fates_log(), *) 'undefined element specified' + write(fates_log(), *) 'while defining forced external seed mass flux' + call endrun(msg=errMsg(sourcefile, __LINE__)) + end select + + ! Seed input from external sources (user param seed rain, or dispersal model) + seed_in_external = seed_stoich*EDPftvarcon_inst%seed_suppl(pft)*years_per_day + litt%seed_in_extern(pft) = litt%seed_in_extern(pft) + seed_in_external + + ! Seeds entering externally [kg/site/day] + site_mass%seed_in = site_mass%seed_in + seed_in_external*currentPatch%area + end if !use this pft enddo - + currentPatch => currentPatch%younger enddo @@ -2196,71 +2195,78 @@ subroutine SeedDecay( litt , currentPatch, bc_in ) if ( regeneration_model == default_regeneration .or. & prt_params%allom_dbh_maxheight(pft) < min_max_dbh_for_trees ) then - ! Default seed decay (TRS is off) - litt%seed_decay(pft) = litt%seed(pft) * & - EDPftvarcon_inst%seed_decay_rate(pft)*years_per_day + ! Default seed decay (TRS is off) + litt%seed_decay(pft) = litt%seed(pft) * & + EDPftvarcon_inst%seed_decay_rate(pft)*years_per_day - end if ! End default regeneration model + end if ! If the TRS is switched on and the pft is a tree then add non-seed reproductive biomass ! to the seed decay flux. This was added to litt%seed_decay in the previously called SeedIn ! subroutine if ( any(regeneration_model == [TRS_regeneration, TRS_no_seedling_dyn]) .and. & - prt_params%allom_dbh_maxheight(pft) > min_max_dbh_for_trees ) then - - litt%seed_decay(pft) = litt%seed_decay(pft) + &! From non-seed reproductive biomass (added in - ! in the SeedIn subroutine. - litt%seed(pft) * EDPftvarcon_inst%seed_decay_rate(pft)*years_per_day - - end if ! End use TRS + prt_params%allom_dbh_maxheight(pft) > min_max_dbh_for_trees ) then + + litt%seed_decay(pft) = litt%seed_decay(pft) + &! From non-seed reproductive biomass (added in + ! in the SeedIn subroutine. + litt%seed(pft) * EDPftvarcon_inst%seed_decay_rate(pft)*years_per_day + + end if ! If the TRS is switched on with seedling dynamics (regeneration_model = 2) ! then calculate seedling mortality. - if ( regeneration_model == TRS_regeneration .and. & - prt_params%allom_dbh_maxheight(pft) > min_max_dbh_for_trees ) then - - !---------------------------------------------------------------------- - ! Seedling mortality (flux from seedling pool to litter) - ! Note: The TRS uses the litt%seed_germ data struture to track seedlings - - ! Step 1. Calculate the daily seedling mortality rate from light stress - - ! Calculate the cumulative light at the seedling layer over a prior number of - ! days determined by the "fates_tres_seedling_mort_par_timescale" parameter. - seedling_layer_par = currentPatch%sdlng_mort_par%GetMean() * megajoules_per_joule * & - sec_per_day * sdlng_mort_par_timescale + if_trs_germ_decay: if ( regeneration_model == TRS_regeneration .and. & + prt_params%allom_dbh_maxheight(pft) > min_max_dbh_for_trees ) then + + !---------------------------------------------------------------------- + ! Seedling mortality (flux from seedling pool to litter) + ! Note: The TRS uses the litt%seed_germ data struture to track seedlings + ! + ! Step 1. Calculate the daily seedling mortality rate from light stress + ! + ! Calculate the cumulative light at the seedling layer over a prior number of + ! days determined by the "fates_tres_seedling_mort_par_timescale" parameter. - ! Calculate daily seedling mortality rate from light - seedling_light_mort_rate = exp( EDPftvarcon_inst%seedling_light_mort_a(pft) * & - seedling_layer_par + EDPftvarcon_inst%seedling_light_mort_b(pft) ) + seedling_layer_par = currentPatch%sdlng_mort_par%GetMean() * megajoules_per_joule * & + sec_per_day * sdlng_mort_par_timescale + + ! Calculate daily seedling mortality rate from light + seedling_light_mort_rate = exp( EDPftvarcon_inst%seedling_light_mort_a(pft) * & + seedling_layer_par + EDPftvarcon_inst%seedling_light_mort_b(pft) ) - ! Step 2. Calculate the daily seedling mortality rate from moisture stress + ! Step 2. Calculate the daily seedling mortality rate from moisture stress + + ! Get the current seedling moisture deficit days (tracked as a pft-specific exponential + ! average) + seedling_mdds = currentPatch%sdlng_mdd(pft)%p%GetMean() + + ! Calculate seedling mortality as a function of moisture deficit days (mdd) + ! If the seedling mmd value is below a critical threshold then moisture-based mortality is zero + if (seedling_mdds < EDPftvarcon_inst%seedling_mdd_crit(pft)) then + seedling_h2o_mort_rate = 0.0_r8 + else + seedling_h2o_mort_rate = EDPftvarcon_inst%seedling_h2o_mort_a(pft) * seedling_mdds**2 + & + EDPftvarcon_inst%seedling_h2o_mort_b(pft) * seedling_mdds + & + EDPftvarcon_inst%seedling_h2o_mort_c(pft) + end if ! mdd threshold check + + ! Step 3. Sum modes of mortality (including background mortality) and send dead seedlings + ! to litter + litt%seed_germ_decay(pft) = (litt%seed_germ(pft) * seedling_light_mort_rate) + & + (litt%seed_germ(pft) * seedling_h2o_mort_rate) + & + (litt%seed_germ(pft) * EDPftvarcon_inst%background_seedling_mort(pft) & + * years_per_day) - ! Get the current seedling moisture deficit days (tracked as a pft-specific exponential - ! average) - seedling_mdds = currentPatch%sdlng_mdd(pft)%p%GetMean() - - ! Calculate seedling mortality as a function of moisture deficit days (mdd) - ! If the seedling mmd value is below a critical threshold then moisture-based mortality is zero - if (seedling_mdds < EDPftvarcon_inst%seedling_mdd_crit(pft)) then - seedling_h2o_mort_rate = 0.0_r8 - else - seedling_h2o_mort_rate = EDPftvarcon_inst%seedling_h2o_mort_a(pft) * seedling_mdds**2 + & - EDPftvarcon_inst%seedling_h2o_mort_b(pft) * seedling_mdds + & - EDPftvarcon_inst%seedling_h2o_mort_c(pft) - end if ! mdd threshold check - - ! Step 3. Sum modes of mortality (including background mortality) and send dead seedlings - ! to litter - litt%seed_germ_decay(pft) = (litt%seed_germ(pft) * seedling_light_mort_rate) + & - (litt%seed_germ(pft) * seedling_h2o_mort_rate) + & - (litt%seed_germ(pft) * EDPftvarcon_inst%background_seedling_mort(pft) & - * years_per_day) - end if ! End use TRS with seedling dynamics + else + + litt%seed_germ_decay(pft) = litt%seed_germ(pft) * & + EDPftvarcon_inst%seed_decay_rate(pft)*years_per_day + end if if_trs_germ_decay + enddo - + return end subroutine SeedDecay @@ -2530,12 +2536,12 @@ subroutine recruitment( currentSite, currentPatch, bc_in ) ! Cycle through available carbon and nutrients, find the limiting element ! to dictate the total number of plants that can be generated - if ( (hlm_use_ed_prescribed_phys .eq. ifalse) .or. & + if_not_presribed: if ( (hlm_use_ed_prescribed_phys .eq. ifalse) .or. & (EDPftvarcon_inst%prescribed_recruitment(ft) .lt. 0._r8) ) then - temp_cohort%n = 1.e20_r8 + temp_cohort%n = 1.e20_r8 - do el = 1,num_elements + do_elem: do el = 1,num_elements element_id = element_list(el) select case(element_id) @@ -2580,32 +2586,32 @@ subroutine recruitment( currentSite, currentPatch, bc_in ) regeneration_model == TRS_no_seedling_dyn .or. & prt_params%allom_dbh_maxheight(ft) < min_max_dbh_for_trees ) then - mass_avail = currentPatch%area * currentPatch%litter(el)%seed_germ(ft) + mass_avail = currentPatch%area * currentPatch%litter(el)%seed_germ(ft) ! If TRS seedling dynamics is on then calculate the available mass to make new recruits ! as a pft-specific function of light and soil moisture in the seedling layer. else if ( regeneration_model == TRS_regeneration .and. & prt_params%allom_dbh_maxheight(ft) > min_max_dbh_for_trees ) then - sdlng2sap_par = currentPatch%sdlng2sap_par%GetMean() * sec_per_day * megajoules_per_joule - - mass_avail = currentPatch%area * currentPatch%litter(el)%seed_germ(ft) * & - EDPftvarcon_inst%seedling_light_rec_a(ft) * & - sdlng2sap_par**EDPftvarcon_inst%seedling_light_rec_b(ft) + sdlng2sap_par = currentPatch%sdlng2sap_par%GetMean() * sec_per_day * megajoules_per_joule + + mass_avail = currentPatch%area * currentPatch%litter(el)%seed_germ(ft) * & + EDPftvarcon_inst%seedling_light_rec_a(ft) * & + sdlng2sap_par**EDPftvarcon_inst%seedling_light_rec_b(ft) - ! If soil moisture is below pft-specific seedling moisture stress threshold the - ! recruitment does not occur. - ilayer_seedling_root = minloc(abs(bc_in%z_sisl(:)-EDPftvarcon_inst%seedling_root_depth(ft)),dim=1) - - seedling_layer_smp = bc_in%smp_sl(ilayer_seedling_root) - - if ( seedling_layer_smp < EDPftvarcon_inst%seedling_psi_crit(ft) ) then - - mass_avail = 0.0_r8 - - end if ! End check if soil moisture is sufficient for recruitment - + ! If soil moisture is below pft-specific seedling moisture stress threshold the + ! recruitment does not occur. + ilayer_seedling_root = minloc(abs(bc_in%z_sisl(:)-EDPftvarcon_inst%seedling_root_depth(ft)),dim=1) + + seedling_layer_smp = bc_in%smp_sl(ilayer_seedling_root) + + if ( seedling_layer_smp < EDPftvarcon_inst%seedling_psi_crit(ft) ) then + + mass_avail = 0.0_r8 + + end if ! End check if soil moisture is sufficient for recruitment + end if ! End use TRS with seedling dynamics ! ------------------------------------------------------------------------ @@ -2614,15 +2620,17 @@ subroutine recruitment( currentSite, currentPatch, bc_in ) temp_cohort%n = min(temp_cohort%n, mass_avail/mass_demand) - end do + end do do_elem else + ! prescribed recruitment rates. number per sq. meter per year temp_cohort%n = currentPatch%area * & EDPftvarcon_inst%prescribed_recruitment(ft) * & hlm_freq_day - endif + + endif if_not_presribed ! Only bother allocating a new cohort if there is a reasonable amount of it any_recruits: if (temp_cohort%n > min_n_safemath )then diff --git a/main/EDPftvarcon.F90 b/main/EDPftvarcon.F90 index 31c9a08ad5..22add34b3a 100644 --- a/main/EDPftvarcon.F90 +++ b/main/EDPftvarcon.F90 @@ -25,7 +25,10 @@ module EDPftvarcon use FatesConstantsMod , only : prescribed_n_uptake use FatesConstantsMod , only : coupled_p_uptake use FatesConstantsMod , only : coupled_n_uptake - + use FatesConstantsMod , only : default_regeneration + use FatesConstantsMod , only : TRS_regeneration + use FatesConstantsMod , only : TRS_no_seedling_dyn + use EDParamsMod , only : regeneration_model ! CIME Globals use shr_log_mod , only : errMsg => shr_log_errMsg @@ -1749,6 +1752,17 @@ subroutine FatesCheckParams(is_master) call endrun(msg=errMsg(sourcefile, __LINE__)) end if + if(.not.any(regeneration_model == [default_regeneration, & + TRS_regeneration, & + TRS_no_seedling_dyn] )) then + write(fates_log(),*) 'The regeneration model must be set to a known model type' + write(fates_log(),*) 'the default is 1, and the Hanbury-Brown models are 2 and 3' + write(fates_log(),*) 'You specified fates_regeneration_model = ',regeneration_model + write(fates_log(),*) 'Aborting' + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + + select case (hlm_parteh_mode) case (prt_cnp_flex_allom_hyp) diff --git a/main/FatesHistoryInterfaceMod.F90 b/main/FatesHistoryInterfaceMod.F90 index 45ed876bf6..0594c77506 100644 --- a/main/FatesHistoryInterfaceMod.F90 +++ b/main/FatesHistoryInterfaceMod.F90 @@ -251,8 +251,8 @@ module FatesHistoryInterfaceMod integer :: ih_seed_bank_si ! carbon only integer :: ih_seeds_in_si ! carbon only integer :: ih_seeds_in_local_si ! carbon only - integer :: ih_seed_bank_trs_si ! carbon only - integer :: ih_seedling_pool_trs_si ! carbon only + integer :: ih_ungerm_seed_bank_si ! carbon only + integer :: ih_seedling_pool_si ! carbon only integer :: ih_ba_weighted_height_si integer :: ih_ca_weighted_height_si integer :: ih_seeds_in_local_elem @@ -2265,10 +2265,10 @@ subroutine update_history_dyn(this,nc,nsites,sites,bc_in) hio_litter_in_si => this%hvars(ih_litter_in_si)%r81d, & hio_litter_out_si => this%hvars(ih_litter_out_si)%r81d, & hio_seed_bank_si => this%hvars(ih_seed_bank_si)%r81d, & - hio_seed_bank_trs_si => this%hvars(ih_seed_bank_trs_si)%r81d, & - hio_seedling_pool_trs_si => this%hvars(ih_seedling_pool_trs_si)%r81d, & + hio_ungerm_seed_bank_si => this%hvars(ih_ungerm_seed_bank_si)%r81d, & + hio_seedling_pool_si => this%hvars(ih_seedling_pool_si)%r81d, & hio_seeds_in_si => this%hvars(ih_seeds_in_si)%r81d, & - hio_seeds_in_local_si => this%hvars(ih_seeds_in_local_si)%r81d, & + hio_seeds_in_local_si => this%hvars(ih_seeds_in_local_si)%r81d, & hio_litter_in_elem => this%hvars(ih_litter_in_elem)%r82d, & hio_litter_out_elem => this%hvars(ih_litter_out_elem)%r82d, & hio_seed_bank_elem => this%hvars(ih_seed_bank_elem)%r82d, & @@ -4000,8 +4000,8 @@ subroutine update_history_dyn(this,nc,nsites,sites,bc_in) hio_litter_out_si(io_si) = 0._r8 hio_seed_bank_si(io_si) = 0._r8 - hio_seed_bank_trs_si(io_si) = 0._r8 - hio_seedling_pool_trs_si(io_si) = 0._r8 + hio_ungerm_seed_bank_si(io_si) = 0._r8 + hio_seedling_pool_si(io_si) = 0._r8 hio_seeds_in_si(io_si) = 0._r8 hio_seeds_in_local_si(io_si) = 0._r8 @@ -4025,14 +4025,14 @@ subroutine update_history_dyn(this,nc,nsites,sites,bc_in) ! Sum up total seed bank (germinated and ungerminated) hio_seed_bank_si(io_si) = hio_seed_bank_si(io_si) + & (sum(litt%seed(:))+sum(litt%seed_germ(:))) * & - area_frac * days_per_sec + area_frac ! Sum up total seed bank (just ungerminated) - hio_seed_bank_trs_si(io_si) = hio_seed_bank_trs_si(io_si) + & + hio_ungerm_seed_bank_si(io_si) = hio_ungerm_seed_bank_si(io_si) + & sum(litt%seed(:)) * area_frac ! Sum up total seedling pool - hio_seedling_pool_trs_si(io_si) = hio_seedling_pool_trs_si(io_si) + & + hio_seedling_pool_si(io_si) = hio_seedling_pool_si(io_si) + & sum(litt%seed_germ(:)) * area_frac ! Sum up the input flux into the seed bank (local and external) @@ -5831,17 +5831,17 @@ subroutine define_history_vars(this, initialize_variables) upfreq=1, ivar=ivar, initialize=initialize_variables, & index = ih_seed_bank_si) - call this%set_history_var(vname='FATES_SEED_BANK_TRS', units='kg m-2', & - long='total seed mass of all PFTs in kg carbon per m2 land area', & + call this%set_history_var(vname='FATES_UNGERM_SEED_BANK', units='kg m-2', & + long='ungerminated seed mass of all PFTs in kg carbon per m2 land area', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=1, ivar=ivar, initialize=initialize_variables, & - index = ih_seed_bank_trs_si) + index = ih_ungerm_seed_bank_si) - call this%set_history_var(vname='FATES_SEEDLING_POOL_TRS', units='kg m-2', & - long='total seedling mass of all PFTs in kg carbon per m2 land area', & + call this%set_history_var(vname='FATES_SEEDLING_POOL', units='kg m-2', & + long='total seedling (ie germinated seeds) mass of all PFTs in kg carbon per m2 land area', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=1, ivar=ivar, initialize=initialize_variables, & - index = ih_seedling_pool_trs_si) + index = ih_seedling_pool_si) call this%set_history_var(vname='FATES_SEEDS_IN', units='kg m-2 s-1', & long='seed production rate in kg carbon per m2 second', & From a3a8c5d988fa5e5f246203eb6dc44a54a782e3b3 Mon Sep 17 00:00:00 2001 From: Ryan Knox Date: Thu, 20 Jul 2023 14:00:51 -0600 Subject: [PATCH 79/81] changed litter initialization to invalid for cold-start SP runs --- main/EDInitMod.F90 | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/main/EDInitMod.F90 b/main/EDInitMod.F90 index 5e5693cf21..caf0c5843b 100644 --- a/main/EDInitMod.F90 +++ b/main/EDInitMod.F90 @@ -8,6 +8,7 @@ module EDInitMod use FatesConstantsMod , only : ifalse use FatesConstantsMod , only : itrue use FatesConstantsMod , only : fates_unset_int + use FatesConstantsMod , only : fates_unset_r8 use FatesConstantsMod , only : primaryforest use FatesConstantsMod , only : nearzero use FatesGlobals , only : endrun => fates_endrun @@ -553,6 +554,7 @@ subroutine init_patches( nsites, sites, bc_in) integer :: nocomp_pft real(r8) :: newparea real(r8) :: tota !check on area + real(r8) :: litt_init !invalid for satphen, 0 otherwise integer :: is_first_patch type(ed_site_type), pointer :: sitep @@ -665,13 +667,18 @@ subroutine init_patches( nsites, sites, bc_in) ! 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=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) + 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) From e3fc66d7ecd9370709493d875569ad99b8b61640 Mon Sep 17 00:00:00 2001 From: Ryan Knox Date: Thu, 20 Jul 2023 14:25:33 -0600 Subject: [PATCH 80/81] the changes to default parameter file had already been implemented in a prior PR, reverting duplicate additions for TRS variables --- parameter_files/fates_params_default.cdl | 136 +---------------------- 1 file changed, 4 insertions(+), 132 deletions(-) diff --git a/parameter_files/fates_params_default.cdl b/parameter_files/fates_params_default.cdl index f13f05d329..f170fe2275 100644 --- a/parameter_files/fates_params_default.cdl +++ b/parameter_files/fates_params_default.cdl @@ -151,16 +151,16 @@ variables: 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 (NOT USED)" ; + 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 (NOT USED)" ; + 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 (NOT USED). note: max_z=min_z=large, sets rooting depth to soil depth" ; + 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 (NOT USED)" ; + 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" ; @@ -476,60 +476,6 @@ variables: 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_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_par_crit_germ(fates_pft) ; - fates_trs_seedling_par_crit_germ:units = "Megajoules m2-1 day-1 " ; - fates_trs_seedling_par_crit_germ:long_name = "critical light level for germination" ; - 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_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_psi_crit(fates_pft) ; - fates_trs_seedling_psi_crit:units = "mm h20 suction" ; - fates_trs_seedling_psi_crit:long_name = "critical soil moisture for seedling stress" ; - double fates_trs_seedling_mdd_crit(fates_pft) ; - fates_trs_seedling_mdd_crit:units = "moisture deficit days (mm h2o suction * days)" ; - fates_trs_seedling_mdd_crit:long_name = "critical moisture deficit day accumulation for seedling moisture-based seedling mortality to begin" ; - 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_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_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_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" ; @@ -854,9 +800,6 @@ variables: 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_regeneration_model ; - fates_regeneration_model:units = "unitless" ; - fates_regeneration_model:long_name = "switch for choosing between FATES's default regeneration scheme (1), the full Tree Recruitment Scheme (2; Hanbury-Brown et al., 2022), or (3) the Tree Recruitment Scheme without seedling dynamics" ; 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" ; @@ -908,18 +851,6 @@ variables: double fates_phen_ncolddayslim ; fates_phen_ncolddayslim:units = "days" ; fates_phen_ncolddayslim:long_name = "day threshold exceedance for temperature leaf-drop" ; - 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_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_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_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_q10_froz ; fates_q10_froz:units = "unitless" ; fates_q10_froz:long_name = "Q10 for frozen-soil respiration rates" ; @@ -1491,63 +1422,6 @@ data: 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_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_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_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_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_mdd_crit = 1400000.0, 1400000.0, 1400000.0, 1400000.0, 1400000.0, - 1400000.0, 1400000.0, 1400000.0, 1400000.0, 1400000.0, 1400000.0, 1400000.0 ; - - 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_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_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_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_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 ; @@ -1775,8 +1649,6 @@ data: fates_landuse_logging_coll_under_frac = 0.55983 ; - fates_regeneration_model = 1 ; - fates_landuse_logging_collateral_frac = 0.05 ; fates_landuse_logging_dbhmax = _ ; From d09b149ea550690e25d5877c550c1ac5f51123a1 Mon Sep 17 00:00:00 2001 From: Ryan Knox Date: Thu, 20 Jul 2023 19:02:32 -0600 Subject: [PATCH 81/81] removed xml patch file --- .../patch_TRS_bciopt_1_12_2022.xml | 52 ------------------- 1 file changed, 52 deletions(-) delete mode 100644 parameter_files/patch_TRS_bciopt_1_12_2022.xml diff --git a/parameter_files/patch_TRS_bciopt_1_12_2022.xml b/parameter_files/patch_TRS_bciopt_1_12_2022.xml deleted file mode 100644 index 4e135f9d5b..0000000000 --- a/parameter_files/patch_TRS_bciopt_1_12_2022.xml +++ /dev/null @@ -1,52 +0,0 @@ - - - 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_TRS_bci_opt224_vmn6phi_011222.cdl - 1 - - 0 - 0 - 1,1,3,4 - 0.03347526,0.024,1e-08,0.0047 - 0.03347526,0.024,1e-08,0.0047 - 0.025,0,0,0 - 0.45,0.25,0,0 - 0.8012471 - 30.94711 - 0.0673 - 0.976 - -9 - -9 - 3 - 0.1266844 - 1.281329 - -9 - 0.768654 - 0.768654 - 57.6 - 0.74 - 21.6 - 200 - 2 - 5 - 0.4863088 - 3 - 3e-06 - 3e-06 - 3e-07 - 3e-08 - 0.03991654 - 0.01995827 - 0.01303514 - 0.02955703 - 3 - 3 - 0.04680188 - 0.001 - 0.8374751 - -1 - 0.5 - 1 - -