diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 8efa4c7b77..87f6468203 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -14,29 +14,39 @@ - -### Checklist: +### Checklist -- [ ] My change requires a change to the documentation. -- [ ] I have updated the in-code documentation .AND. (the [technical note](https://github.com/NGEET/fates-docs) .OR. the wiki) accordingly. -- [ ] I have read the [**CONTRIBUTING**](https://github.com/NGEET/fates/blob/master/CONTRIBUTING.md) document. +*If this is your first time contributing, please read the [**CONTRIBUTING**](https://github.com/NGEET/fates/blob/main/CONTRIBUTING.md) document.* + +All checklist items must be checked to enable merging this pull request: + +*Contributor* +- [ ] The in-code documentation has been updated with descriptive comments +- [ ] The documentation has been assessed to determine if updates are necessary + +*Integrator* - [ ] FATES PASS/FAIL regression tests were run -- [ ] If answers were expected to change, evaluation was performed and provided +- [ ] Evaluation of test results for answer changes was performed and results provided +### Documentation + + +- [Technical Note](https://github.com/NGEET/fates-docs) update: +- [User's Guide](https://github.com/NGEET/fates-users-guide) update: ### Test Results: -CTSM (or) E3SM (specify which) test hash-tag: +*CTSM (or) E3SM (specify which) test hash-tag:* -CTSM (or) E3SM (specify which) baseline hash-tag: +*CTSM (or) E3SM (specify which) baseline hash-tag:* -FATES baseline hash-tag: +*FATES baseline hash-tag:* -Test Output: +*Test Output:* diff --git a/.github/workflows/add-to-gh_projects.yml b/.github/workflows/add-to-gh_projects.yml new file mode 100644 index 0000000000..8c34dd6922 --- /dev/null +++ b/.github/workflows/add-to-gh_projects.yml @@ -0,0 +1,23 @@ +# This is a basic workflow to help you get started with Actions + +name: Add issue to github project issue triage board + +# Controls when the workflow will run +on: + issues: + types: + - opened + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + add-to-project: + name: add issue to issue triage board project + runs-on: ubuntu-latest + steps: + - uses: actions/add-to-project@v0.3.0 + with: + # URL of the project to add issues to + project-url: https://github.com/orgs/NGEET/projects/1 + # A GitHub personal access token with write access to the project + github-token: ${{ secrets.ADD_TO_PROJECT_PAT }} + diff --git a/README.md b/README.md index a7688d60fa..3129042304 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,11 @@ This repository holds the Functionally Assembled Terrestrial Ecosystem Simulator (FATES). FATES is a numerical terrestrial ecosystem model. Its development and support is primarily supported by the Department of Energy's Office of Science, through the Next Generation Ecosystem Experiment - Tropics ([NGEE-T](https://ngee-tropics.lbl.gov/)) project. -For more information on the FATES model, see our [User's Guide](https://fates-users-guide.readthedocs.io/en/latest/) and [technical documentation](https://fates-docs.readthedocs.io/en/latest/index.html). +For more information on the FATES model, see our [User's Guide](https://fates-users-guide.readthedocs.io/en/latest/) and [technical documentation](https://fates-docs.readthedocs.io/en/latest/index.html). +Please submit any questions you may have to the [FATES Github Discussions board](https://github.com/NGEET/fates/discussions). + +To receive email updates about forthcoming release tags, regular meeting notifications, and other important announcements, please join the [FATES Google group](https://groups.google.com/g/fates_model). ## Important Guides: ------------------------------ @@ -21,7 +24,6 @@ For more information on the FATES model, see our [User's Guide](https://fates-us [Code of Conduct](https://github.com/NGEET/fates/blob/master/CODE_OF_CONDUCT.md) - ## Important Note: ------------------------------ @@ -33,13 +35,4 @@ https://github.com/E3SM-Project/E3SM https://github.com/ESCOMP/cesm -## Important Note About Host-Models and Compatible Branches: ------------------------------------------------------------- - -The FATES and E3SM teams maintain compatability of the NGEET/FATES master branch with the **E3SM master** branch. When changes to the FATES API force compatability updates with E3SM, there may be some modest lag time. - -The FATES team maintains compatability of the NGEET/FATES master branch with the **CTSM fates_next_api** branch. Since the FATES team uses this branch for its internal testing, this compatability is tightly (immediately) maintained and these two should always be in sync. However, CTSM master may become out of sync with FATES master for large periods (months) of time. - - - - +The FATES, E3SM and CTSM teams maintain compatability of the NGEET/FATES master branch with the E3SM master and CTSM master branches respectively. There may be some modest lag time in which the latest commit on the FATES master branch is available to these host land models (HLM) by default. This is typically correlated with FATES development updates forcing necessary changes to the FATES API. See the table of [FATES API/HLM compatibility](https://fates-users-guide.readthedocs.io/en/latest/user/Table-of-FATES-API-and-HLM-STATUS.html) for information on which fates tag corresponds to which HLM tag or commit. diff --git a/biogeochem/DamageMainMod.F90 b/biogeochem/DamageMainMod.F90 new file mode 100644 index 0000000000..11de5d1799 --- /dev/null +++ b/biogeochem/DamageMainMod.F90 @@ -0,0 +1,225 @@ +module DamageMainMod + + use FatesConstantsMod , only : r8 => fates_r8 + use FatesConstantsMod , only : i4 => fates_int + use FatesConstantsMod , only : itrue, ifalse + use FatesConstantsMod , only : years_per_day + use FatesConstantsMod , only : nearzero + use FatesGlobals , only : fates_log + use FatesGlobals , only : endrun => fates_endrun + use shr_log_mod , only : errMsg => shr_log_errMsg + use EDPftvarcon , only : EDPftvarcon_inst + use EDParamsMod , only : damage_event_code + use EDParamsMod , only : ED_val_history_damage_bin_edges + use FatesInterfaceTypesMod, only : hlm_current_day + use FatesInterfaceTypesMod, only : hlm_current_month + use FatesInterfaceTypesMod, only : hlm_current_year + use FatesInterfaceTypesMod, only : hlm_model_day + use FatesInterfaceTypesMod, only : hlm_day_of_year + + implicit none + private + + logical, protected :: damage_time ! if true then damage occurs during current time step + + character(len=*), parameter, private :: sourcefile = & + __FILE__ + + public :: GetCrownReduction + public :: GetDamageFrac + public :: IsItDamageTime + public :: damage_time + public :: GetDamageMortality + + + logical :: debug = .false. ! for debugging + + + ! The following is the special classification for undamaged plants + ! and is used in contexts where cohort%damageclass is used. This is + ! to flag to the user that an undamaged plant is assumed in those contexts + + integer, parameter, public :: undamaged_class = 1 + + + ! ============================================================================ + ! ============================================================================ + +contains + + + + + subroutine IsItDamageTime(is_master) + + !---------------------------------------------------------------------------- + ! This subroutine determines whether damage should occur (it is called daily) + ! This is almost an exact replica of the IsItLoggingTime subroutine + !----------------------------------------------------------------------------- + + + integer, intent(in) :: is_master + !type(ed_site_type), intent(inout), target :: currentSite + + integer :: icode ! Integer equivalent of the event code (parameter file only allows reals) + integer :: damage_date ! Day of month for damage extracted from event code + integer :: damage_month ! Month of year for damage extracted from event code + integer :: damage_year ! Year for damage extracted from event code + integer :: model_day_int ! Model day + + character(len=64) :: fmt = '(a,i2.2,a,i2.2,a,i4.4)' + + damage_time = .false. + icode = int(damage_event_code) + + model_day_int = int(hlm_model_day) + + if(icode .eq. 1) then + ! Damage is turned off + damage_time = .false. + + else if(icode .eq. 2) then + ! Damage event on first time step + if(model_day_int .eq.1) then + damage_time = .true. + end if + + else if(icode .eq. 3) then + ! Damage event every day - this is not recommended as it will result in a very large + ! number of cohorts which will likely be terminated + damage_time = .true. + + else if(icode .eq. 4) then + ! Damage event once a month + if(hlm_current_day.eq.1 ) then + damage_time = .true. + end if + + else if(icode < 0 .and. icode > -366) then + ! Damage event every year on a specific day of the year + ! specified as negative day of year + if(hlm_day_of_year .eq. abs(icode) ) then + damage_time = .true. + end if + + else if(icode > 10000 ) then + ! Specific Event: YYYYMMDD + damage_date = icode - int(100* floor(real(icode,r8)/100._r8)) + damage_year = floor(real(icode,r8)/10000._r8) + damage_month = floor(real(icode,r8)/100._r8) - damage_year*100 + + if(hlm_current_day .eq. damage_date .and. & + hlm_current_month .eq. damage_month .and. & + hlm_current_year .eq. damage_year ) then + damage_time = .true. + end if + + else + ! Bad damage event flag + write(fates_log(),*) 'An invalid damage code was specified in fates_params' + write(fates_log(),*) 'Check DamageMainMod.F90:IsItDamageTime()' + write(fates_log(),*) 'for a breakdown of the valid codes and change' + write(fates_log(),*) 'fates_damage_event_code in the file accordingly.' + write(fates_log(),*) 'exiting' + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + + if(damage_time .and. (is_master.eq.itrue) ) then + write(fates_log(),fmt) 'Damage Event Enacted on date: ', & + hlm_current_month,'-', hlm_current_day,'-',hlm_current_year + end if + + return + + end subroutine IsItDamageTime + + !---------------------------------------------------------------------------- + + subroutine GetDamageFrac(cc_cd, nc_cd, pft, dist_frac) + + + ! Given the current cohort damage class find the fraction of individuals + ! going to the new damage class. + ! This subroutine consults a look up table of transitions from param derived. + + ! USES + use FatesParameterDerivedMod, only : param_derived + + + ! ARGUMENTS + integer, intent(in) :: cc_cd ! current cohort crown damage + integer, intent(in) :: nc_cd ! new cohort crown damage + integer, intent(in) :: pft ! plant functional type + real(r8), intent(out) :: dist_frac ! fraction of current cohort moving to + ! new damage level + + dist_frac = param_derived%damage_transitions(cc_cd, nc_cd, pft) + + end subroutine GetDamageFrac + + !------------------------------------------------------- + + subroutine GetCrownReduction(crowndamage, crown_reduction) + + !------------------------------------------------------------------ + ! This subroutine takes the crown damage class of a cohort (integer) + ! and returns the fraction of the crown that is lost. + !------------------------------------------------------------------- + + integer(i4), intent(in) :: crowndamage ! crown damage class of the cohort + real(r8), intent(out) :: crown_reduction ! fraction of crown lost from damage + + crown_reduction = ED_val_history_damage_bin_edges(crowndamage)/100.0_r8 + + return + end subroutine GetCrownReduction + + + !---------------------------------------------------------------------------------------- + + + subroutine GetDamageMortality(crowndamage,pft, dgmort) + + !------------------------------------------------------------------ + ! This subroutine calculates damage-dependent mortality. + ! Not all damage related mortality will be captured by mechanisms in FATES + ! (e.g. carbon starvation mortality). Damage could also lead to damage + ! due to unrepresented mechanisms such as pathogens or increased + ! vulnerability to wind throws. This function captures mortality due to + ! those unrepresented mechanisms. + !------------------------------------------------------------------ + + use EDPftvarcon , only : EDPftvarcon_inst + + integer(i4), intent(in) :: crowndamage ! crown damage class of the cohort + integer(i4), intent(in) :: pft ! plant functional type + real(r8), intent(out) :: dgmort ! mortality directly associated with damage + + ! local variables + real(r8) :: damage_mort_p1 ! inflection point of the damage mortalty relationship + real(r8) :: damage_mort_p2 ! rate parameter for the damage mortality relationship + real(r8) :: crown_loss ! fraction of crown lost + + damage_mort_p1 = EDPftvarcon_inst%damage_mort_p1(pft) + damage_mort_p2 = EDPftvarcon_inst%damage_mort_p2(pft) + + ! make damage mortality a function of crownloss and not crowndamage + ! class so that it doesn't need to be re-parameterised if the number + ! of damage classes change. + crown_loss = ED_val_history_damage_bin_edges(crowndamage)/100.0_r8 + + if (crowndamage .eq. 1 ) then + dgmort = 0.0_r8 + else + dgmort = 1.0_r8 / (1.0_r8 + exp(-1.0_r8 * damage_mort_p2 * & + (crown_loss - damage_mort_p1) ) ) + + end if + + return + end subroutine GetDamageMortality + !---------------------------------------------------------------------------------------- + + +end module DamageMainMod + diff --git a/biogeochem/EDCanopyStructureMod.F90 b/biogeochem/EDCanopyStructureMod.F90 index c12ec2edda..a52be9a30e 100644 --- a/biogeochem/EDCanopyStructureMod.F90 +++ b/biogeochem/EDCanopyStructureMod.F90 @@ -8,21 +8,24 @@ module EDCanopyStructureMod use FatesConstantsMod , only : r8 => fates_r8 use FatesConstantsMod , only : itrue, ifalse use FatesConstantsMod , only : tinyr8 - use FatesConstantsMod , only : nearzero + use FatesConstantsMod , only : nearzero, area_error_1 use FatesConstantsMod , only : rsnbl_math_prec + use FatesConstantsMod , only : nocomp_bareground use FatesGlobals , only : fates_log use EDPftvarcon , only : EDPftvarcon_inst use PRTParametersMod , only : prt_params use FatesAllometryMod , only : carea_allom - use EDCohortDynamicsMod , only : copy_cohort, terminate_cohorts, terminate_cohort, fuse_cohorts + use EDCohortDynamicsMod , only : terminate_cohorts, terminate_cohort, fuse_cohorts use EDCohortDynamicsMod , only : InitPRTObject - use EDCohortDynamicsMod , only : InitPRTBoundaryConditions use FatesAllometryMod , only : tree_lai use FatesAllometryMod , only : tree_sai - use EDtypesMod , only : ed_site_type, ed_patch_type, ed_cohort_type - use EDTypesMod , only : nclmax - use EDTypesMod , only : nlevleaf + use EDtypesMod , only : ed_site_type + use FatesPatchMod, only : fates_patch_type + use FatesCohortMod, only : fates_cohort_type + use EDParamsMod , only : nclmax + use EDParamsMod , only : nlevleaf use EDtypesMod , only : AREA + use EDLoggingMortalityMod , only : UpdateHarvestC use FatesGlobals , only : endrun => fates_endrun use FatesInterfaceTypesMod , only : hlm_days_per_year use FatesInterfaceTypesMod , only : hlm_use_planthydro @@ -31,9 +34,7 @@ module EDCanopyStructureMod use FatesInterfaceTypesMod , only : numpft use FatesInterfaceTypesMod, only : bc_in_type use FatesPlantHydraulicsMod, only : UpdateH2OVeg,InitHydrCohort, RecruitWaterStorage - use EDTypesMod , only : maxCohortsPerPatch use PRTGenericMod, only : leaf_organ - use PRTGenericMod, only : all_carbon_elements use PRTGenericMod, only : leaf_organ use PRTGenericMod, only : fnrt_organ use PRTGenericMod, only : sapw_organ @@ -41,7 +42,7 @@ module EDCanopyStructureMod use PRTGenericMod, only : repro_organ use PRTGenericMod, only : struct_organ use PRTGenericMod, only : SetState - use FatesRunningMeanMod, only : ema_lpa + use PRTGenericMod, only : carbon12_element ! CIME Globals use shr_log_mod , only : errMsg => shr_log_errMsg @@ -55,12 +56,17 @@ module EDCanopyStructureMod public :: canopy_summarization public :: update_hlm_dynamics public :: UpdateFatesAvgSnowDepth + public :: UpdatePatchLAI + public :: UpdateCohortLAI logical, parameter :: debug=.false. character(len=*), parameter, private :: sourcefile = & __FILE__ + integer :: istat ! return status code + character(len=255) :: smsg ! Message string for deallocation errors + real(r8), parameter :: area_target_precision = 1.0E-11_r8 ! Area conservation ! will attempt to reduce errors ! below this level @@ -131,8 +137,8 @@ subroutine canopy_structure( currentSite , bc_in ) ! ! !LOCAL VARIABLES: - type(ed_patch_type) , pointer :: currentPatch - type(ed_cohort_type), pointer :: currentCohort + type(fates_patch_type) , pointer :: currentPatch + type(fates_cohort_type), pointer :: currentCohort integer :: i_lyr ! current layer index integer :: z ! Current number of canopy layers. (1= canopy, 2 = understorey) integer :: ipft @@ -141,7 +147,6 @@ subroutine canopy_structure( currentSite , bc_in ) logical :: area_not_balanced ! logical controlling if the patch layer areas ! have successfully been redistributed integer :: return_code ! math checks on variables will return>0 if problems exist - ! We only iterate because of possible imprecisions generated by the cohort ! termination process. These should be super small, so at the most ! try to re-balance 3 times. If that doesn't give layer areas @@ -312,14 +317,14 @@ subroutine canopy_structure( currentSite , bc_in ) if(currentCohort%canopy_layer .eq. 2)then if (associated(currentCohort%taller)) then if (currentCohort%taller%canopy_layer .eq. 1 ) then - currentPatch%zstar = currentCohort%taller%hite + currentPatch%zstar = currentCohort%taller%height endif endif endif currentCohort => currentCohort%shorter enddo endif - + currentPatch => currentPatch%younger enddo !patch @@ -333,18 +338,17 @@ end subroutine canopy_structure subroutine DemoteFromLayer(currentSite,currentPatch,i_lyr,bc_in) use EDParamsMod, only : ED_val_comp_excln - use SFParamsMod, only : SF_val_CWD_frac ! !ARGUMENTS - type(ed_site_type), intent(inout), target :: currentSite - type(ed_patch_type), intent(inout), target :: currentPatch - integer, intent(in) :: i_lyr ! Current canopy layer of interest - type(bc_in_type), intent(in) :: bc_in + type(ed_site_type), intent(inout) :: currentSite + type(fates_patch_type), intent(inout) :: currentPatch + integer, intent(in) :: i_lyr ! Current canopy layer of interest + type(bc_in_type), intent(in) :: bc_in ! !LOCAL VARIABLES: - type(ed_cohort_type), pointer :: currentCohort - type(ed_cohort_type), pointer :: copyc - type(ed_cohort_type), pointer :: nextc ! The next cohort in line + type(fates_cohort_type), pointer :: currentCohort + type(fates_cohort_type), pointer :: copyc + type(fates_cohort_type), pointer :: nextc ! The next cohort in line integer :: i_cwd ! Index for CWD pool real(r8) :: cc_loss ! cohort crown area loss in demotion (m2) real(r8) :: leaf_c ! leaf carbon [kg] @@ -380,7 +384,8 @@ subroutine DemoteFromLayer(currentSite,currentPatch,i_lyr,bc_in) currentCohort => currentPatch%shortest do while (associated(currentCohort)) call carea_allom(currentCohort%dbh,currentCohort%n, & - currentSite%spread,currentCohort%pft,currentCohort%c_area) + currentSite%spread,currentCohort%pft, & + currentCohort%crowndamage, currentCohort%c_area) if(debug) then if(currentCohort%c_area<0._r8)then @@ -402,7 +407,7 @@ subroutine DemoteFromLayer(currentSite,currentPatch,i_lyr,bc_in) ! to the understory. ! ---------------------------------------------------------- - currentCohort%excl_weight = 1._r8 / (currentCohort%hite**ED_val_comp_excln) + currentCohort%excl_weight = 1._r8 / (currentCohort%height**ED_val_comp_excln) sumweights = sumweights + currentCohort%excl_weight else @@ -423,7 +428,7 @@ subroutine DemoteFromLayer(currentSite,currentPatch,i_lyr,bc_in) tied_size_with_neighbors = .false. nextc => currentCohort%taller do while (associated(nextc)) - if ( abs(nextc%hite - currentCohort%hite) < similar_height_tol ) then + if ( abs(nextc%height - currentCohort%height) < similar_height_tol ) then if( nextc%canopy_layer .eq. currentCohort%canopy_layer ) then tied_size_with_neighbors = .true. total_crownarea_of_tied_cohorts = & @@ -446,7 +451,7 @@ subroutine DemoteFromLayer(currentSite,currentPatch,i_lyr,bc_in) nextc => currentCohort%taller do while (associated(nextc)) - if ( abs(nextc%hite - currentCohort%hite) < similar_height_tol ) then + if ( abs(nextc%height - currentCohort%height) < similar_height_tol ) then if (nextc%canopy_layer .eq. currentCohort%canopy_layer ) then ! now we know the total crown area of all equal-sized, ! equal-canopy-layer cohorts @@ -626,11 +631,11 @@ subroutine DemoteFromLayer(currentSite,currentPatch,i_lyr,bc_in) if(currentCohort%canopy_layer == i_lyr )then cc_loss = currentCohort%excl_weight - leaf_c = currentCohort%prt%GetState(leaf_organ,all_carbon_elements) - store_c = currentCohort%prt%GetState(store_organ,all_carbon_elements) - fnrt_c = currentCohort%prt%GetState(fnrt_organ,all_carbon_elements) - sapw_c = currentCohort%prt%GetState(sapw_organ,all_carbon_elements) - struct_c = currentCohort%prt%GetState(struct_organ,all_carbon_elements) + leaf_c = currentCohort%prt%GetState(leaf_organ,carbon12_element) + store_c = currentCohort%prt%GetState(store_organ,carbon12_element) + fnrt_c = currentCohort%prt%GetState(fnrt_organ,carbon12_element) + sapw_c = currentCohort%prt%GetState(sapw_organ,carbon12_element) + struct_c = currentCohort%prt%GetState(struct_organ,carbon12_element) if ( (cc_loss-currentCohort%c_area) > -nearzero .and. & (cc_loss-currentCohort%c_area) < area_target_precision ) then @@ -660,24 +665,26 @@ subroutine DemoteFromLayer(currentSite,currentPatch,i_lyr,bc_in) allocate(copyc) + ! (keep as an example) + ! Initialize running means + !allocate(copyc%tveg_lpa) + !!allocate(copyc%l2fr_ema) + ! Note, no need to give a starter value here, + ! that will be taken care of in copy() + !!call copyc%l2fr_ema%InitRMean(ema_60day) + ! Initialize the PARTEH object and point to the ! correct boundary condition fields copyc%prt => null() call InitPRTObject(copyc%prt) - call InitPRTBoundaryConditions(copyc) if( hlm_use_planthydro.eq.itrue ) then call InitHydrCohort(currentSite,copyc) endif - ! (keep as an example) - ! Initialize running means - !allocate(copyc%tveg_lpa) - !call copyc%tveg_lpa%InitRMean(ema_lpa, & - ! init_value=currentPatch%tveg_lpa%GetMean()) + call currentCohort%Copy(copyc) + call copyc%InitPRTBoundaryConditions() - call copy_cohort(currentCohort, copyc) - newarea = currentCohort%c_area - cc_loss copyc%n = currentCohort%n*newarea/currentCohort%c_area currentCohort%n = currentCohort%n - copyc%n @@ -693,9 +700,10 @@ subroutine DemoteFromLayer(currentSite,currentPatch,i_lyr,bc_in) currentSite%demotion_carbonflux = currentSite%demotion_carbonflux + & (leaf_c + store_c + fnrt_c + sapw_c + struct_c) * currentCohort%n - call carea_allom(copyc%dbh,copyc%n,currentSite%spread,copyc%pft,copyc%c_area) + call carea_allom(copyc%dbh,copyc%n,currentSite%spread,copyc%pft, & + copyc%crowndamage, copyc%c_area) call carea_allom(currentCohort%dbh,currentCohort%n,currentSite%spread, & - currentCohort%pft,currentCohort%c_area) + currentCohort%pft,currentCohort%crowndamage, currentCohort%c_area) !----------- Insert copy into linked list ------------------------! copyc%shorter => currentCohort @@ -719,14 +727,25 @@ subroutine DemoteFromLayer(currentSite,currentPatch,i_lyr,bc_in) end if ! kill the ones which go into canopy layers that are not allowed + ! USE THIS OVERRIDE IF YOU ARE FORCING A ONE COHORT SIMULATION + ! (also make sure to turn off germination, external seed rain, + ! (use only one PFT, and make sure disturb_frac is 0) + ! (RGK-0822) + !if(currentCohort%canopy_layer>1) then + if(currentCohort%canopy_layer>nclmax )then ! put the litter from the terminated cohorts ! straight into the fragmenting pools call terminate_cohort(currentSite,currentPatch,currentCohort,bc_in) - deallocate(currentCohort) + deallocate(currentCohort, stat=istat, errmsg=smsg) + if (istat/=0) then + write(fates_log(),*) 'dealloc012: fail on deallocate(currentCohort):'//trim(smsg) + call endrun(msg=errMsg(sourcefile, __LINE__)) + endif else call carea_allom(currentCohort%dbh,currentCohort%n, & - currentSite%spread,currentCohort%pft,currentCohort%c_area) + currentSite%spread,currentCohort%pft,currentCohort%crowndamage, & + currentCohort%c_area) end if endif !canopy layer = i_ly @@ -778,13 +797,13 @@ subroutine PromoteIntoLayer(currentSite,currentPatch,i_lyr) ! !ARGUMENTS type(ed_site_type), intent(inout), target :: currentSite - type(ed_patch_type), intent(inout), target :: currentPatch + type(fates_patch_type), intent(inout), target :: currentPatch integer, intent(in) :: i_lyr ! Current canopy layer of interest ! !LOCAL VARIABLES: - type(ed_cohort_type), pointer :: currentCohort - type(ed_cohort_type), pointer :: copyc - type(ed_cohort_type), pointer :: nextc ! the next cohort, or used for looping + type(fates_cohort_type), pointer :: currentCohort + type(fates_cohort_type), pointer :: copyc + type(fates_cohort_type), pointer :: nextc ! the next cohort, or used for looping ! cohorts against the current real(r8) :: scale_factor ! for prob. exclusion - scales weight to a fraction @@ -829,15 +848,15 @@ subroutine PromoteIntoLayer(currentSite,currentPatch,i_lyr) !look at the cohorts in the canopy layer below... if(currentCohort%canopy_layer == i_lyr+1)then - leaf_c = currentCohort%prt%GetState(leaf_organ,all_carbon_elements) - store_c = currentCohort%prt%GetState(store_organ,all_carbon_elements) - fnrt_c = currentCohort%prt%GetState(fnrt_organ,all_carbon_elements) - sapw_c = currentCohort%prt%GetState(sapw_organ,all_carbon_elements) - struct_c = currentCohort%prt%GetState(struct_organ,all_carbon_elements) + leaf_c = currentCohort%prt%GetState(leaf_organ,carbon12_element) + store_c = currentCohort%prt%GetState(store_organ,carbon12_element) + fnrt_c = currentCohort%prt%GetState(fnrt_organ,carbon12_element) + sapw_c = currentCohort%prt%GetState(sapw_organ,carbon12_element) + struct_c = currentCohort%prt%GetState(struct_organ,carbon12_element) currentCohort%canopy_layer = i_lyr call carea_allom(currentCohort%dbh,currentCohort%n,currentSite%spread, & - currentCohort%pft,currentCohort%c_area) + currentCohort%pft,currentCohort%crowndamage, currentCohort%c_area) ! keep track of number and biomass of promoted cohort currentSite%promotion_rate(currentCohort%size_class) = & currentSite%promotion_rate(currentCohort%size_class) + currentCohort%n @@ -863,7 +882,7 @@ subroutine PromoteIntoLayer(currentSite,currentPatch,i_lyr) currentCohort => currentPatch%tallest do while (associated(currentCohort)) call carea_allom(currentCohort%dbh,currentCohort%n,currentSite%spread, & - currentCohort%pft,currentCohort%c_area) + currentCohort%pft,currentCohort%crowndamage,currentCohort%c_area) if(currentCohort%canopy_layer == i_lyr+1)then !look at the cohorts in the canopy layer below... if (ED_val_comp_excln .ge. 0.0_r8 ) then @@ -872,7 +891,7 @@ subroutine PromoteIntoLayer(currentSite,currentPatch,i_lyr) ! Stochastic case, as above (in demotion portion of code) ! ------------------------------------------------------------------ - currentCohort%prom_weight = currentCohort%hite**ED_val_comp_excln + currentCohort%prom_weight = currentCohort%height**ED_val_comp_excln sumweights = sumweights + currentCohort%prom_weight else @@ -891,7 +910,7 @@ subroutine PromoteIntoLayer(currentSite,currentPatch,i_lyr) tied_size_with_neighbors = .false. nextc => currentCohort%shorter do while (associated(nextc)) - if ( abs(nextc%hite - currentCohort%hite) < similar_height_tol ) then + if ( abs(nextc%height - currentCohort%height) < similar_height_tol ) then if( nextc%canopy_layer .eq. currentCohort%canopy_layer ) then tied_size_with_neighbors = .true. total_crownarea_of_tied_cohorts = & @@ -913,7 +932,7 @@ subroutine PromoteIntoLayer(currentSite,currentPatch,i_lyr) nextc => currentCohort%shorter do while (associated(nextc)) - if ( abs(nextc%hite - currentCohort%hite) < similar_height_tol ) then + if ( abs(nextc%height - currentCohort%height) < similar_height_tol ) then if (nextc%canopy_layer .eq. currentCohort%canopy_layer ) then ! now we know the total crown area of all equal-sized, ! equal-canopy-layer cohorts @@ -1093,11 +1112,11 @@ subroutine PromoteIntoLayer(currentSite,currentPatch,i_lyr) if( (currentCohort%canopy_layer == i_lyr+1) ) then cc_gain = currentCohort%prom_weight - leaf_c = currentCohort%prt%GetState(leaf_organ,all_carbon_elements) - store_c = currentCohort%prt%GetState(store_organ,all_carbon_elements) - fnrt_c = currentCohort%prt%GetState(fnrt_organ,all_carbon_elements) - sapw_c = currentCohort%prt%GetState(sapw_organ,all_carbon_elements) - struct_c = currentCohort%prt%GetState(struct_organ,all_carbon_elements) + leaf_c = currentCohort%prt%GetState(leaf_organ,carbon12_element) + store_c = currentCohort%prt%GetState(store_organ,carbon12_element) + fnrt_c = currentCohort%prt%GetState(fnrt_organ,carbon12_element) + sapw_c = currentCohort%prt%GetState(sapw_organ,carbon12_element) + struct_c = currentCohort%prt%GetState(struct_organ,carbon12_element) if ( (cc_gain-currentCohort%c_area) > -nearzero .and. & (cc_gain-currentCohort%c_area) < area_target_precision ) then @@ -1116,11 +1135,17 @@ subroutine PromoteIntoLayer(currentSite,currentPatch,i_lyr) allocate(copyc) + + !!allocate(copyc%l2fr_ema) + ! Note, no need to give a starter value here, + ! that will be taken care of in copy() + !!call copyc%l2fr_ema%InitRMean(ema_60day) + ! Initialize the PARTEH object and point to the ! correct boundary condition fields copyc%prt => null() call InitPRTObject(copyc%prt) - call InitPRTBoundaryConditions(copyc) + if( hlm_use_planthydro.eq.itrue ) then call InitHydrCohort(CurrentSite,copyc) @@ -1132,12 +1157,13 @@ subroutine PromoteIntoLayer(currentSite,currentPatch,i_lyr) !call copyc%tveg_lpa%InitRMean(ema_lpa,& ! init_value=currentPatch%tveg_lpa%GetMean()) - call copy_cohort(currentCohort, copyc) !makes an identical copy... - + call currentCohort%Copy(copyc) !makes an identical copy... + call copyc%InitPRTBoundaryConditions() + newarea = currentCohort%c_area - cc_gain !new area of existing cohort call carea_allom(currentCohort%dbh,currentCohort%n,currentSite%spread, & - currentCohort%pft,currentCohort%c_area) + currentCohort%pft,currentCohort%crowndamage, currentCohort%c_area) ! number of individuals in promoted cohort. copyc%n = currentCohort%n*cc_gain/currentCohort%c_area @@ -1156,8 +1182,9 @@ subroutine PromoteIntoLayer(currentSite,currentPatch,i_lyr) (leaf_c + fnrt_c + store_c + sapw_c + struct_c) * copyc%n call carea_allom(currentCohort%dbh,currentCohort%n,currentSite%spread, & - currentCohort%pft,currentCohort%c_area) - call carea_allom(copyc%dbh,copyc%n,currentSite%spread,copyc%pft,copyc%c_area) + currentCohort%pft,currentCohort%crowndamage, currentCohort%c_area) + call carea_allom(copyc%dbh,copyc%n,currentSite%spread,copyc%pft,& + copyc%crowndamage,copyc%c_area) !----------- Insert copy into linked list ------------------------! copyc%shorter => currentCohort @@ -1216,8 +1243,8 @@ subroutine canopy_spread( currentSite ) type (ed_site_type), intent(inout), target :: currentSite ! ! !LOCAL VARIABLES: - type (ed_cohort_type), pointer :: currentCohort - type (ed_patch_type) , pointer :: currentPatch + type (fates_cohort_type), pointer :: currentCohort + type (fates_patch_type) , pointer :: currentPatch real(r8) :: sitelevel_canopyarea ! Amount of canopy in top layer at the site level real(r8) :: inc ! Arbitrary daily incremental change in canopy area integer :: z @@ -1234,8 +1261,8 @@ subroutine canopy_spread( currentSite ) currentCohort => currentPatch%tallest do while (associated(currentCohort)) call carea_allom(currentCohort%dbh,currentCohort%n, & - currentSite%spread,currentCohort%pft,currentCohort%c_area) - if( ( int(prt_params%woody(currentCohort%pft)) .eq. itrue ) .and. & + currentSite%spread,currentCohort%pft,currentCohort%crowndamage,currentCohort%c_area) + if( ( prt_params%woody(currentCohort%pft) .eq. itrue ) .and. & (currentCohort%canopy_layer .eq. 1 ) ) then sitelevel_canopyarea = sitelevel_canopyarea + currentCohort%c_area endif @@ -1281,8 +1308,8 @@ subroutine canopy_summarization( nsites, sites, bc_in ) type(bc_in_type) , intent(in) :: bc_in(nsites) ! ! !LOCAL VARIABLES: - type (ed_patch_type) , pointer :: currentPatch - type (ed_cohort_type) , pointer :: currentCohort + type (fates_patch_type) , pointer :: currentPatch + type (fates_cohort_type) , pointer :: currentCohort integer :: s integer :: ft ! plant functional type integer :: ifp ! the number of the vegetated patch (1,2,3). In SP mode bareground patch is 0 @@ -1321,13 +1348,11 @@ subroutine canopy_summarization( nsites, sites, bc_in ) do while(associated(currentCohort)) ft = currentCohort%pft - - - 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) - fnrt_c = currentCohort%prt%GetState(fnrt_organ, all_carbon_elements) - store_c = currentCohort%prt%GetState(store_organ, all_carbon_elements) + leaf_c = currentCohort%prt%GetState(leaf_organ, carbon12_element) + sapw_c = currentCohort%prt%GetState(sapw_organ, carbon12_element) + struct_c = currentCohort%prt%GetState(struct_organ, carbon12_element) + fnrt_c = currentCohort%prt%GetState(fnrt_organ, carbon12_element) + store_c = currentCohort%prt%GetState(store_organ, carbon12_element) ! Update the cohort's index within the size bin classes ! Update the cohort's index within the SCPF classification system @@ -1341,18 +1366,18 @@ subroutine canopy_summarization( nsites, sites, bc_in ) if(hlm_use_sp.eq.ifalse)then call carea_allom(currentCohort%dbh,currentCohort%n,sites(s)%spread,& - currentCohort%pft,currentCohort%c_area) + currentCohort%pft,currentCohort%crowndamage, currentCohort%c_area) endif if(currentCohort%canopy_layer==1)then currentPatch%total_canopy_area = currentPatch%total_canopy_area + currentCohort%c_area - if( int(prt_params%woody(ft))==itrue)then + if( prt_params%woody(ft) == itrue)then currentPatch%total_tree_area = currentPatch%total_tree_area + currentCohort%c_area endif endif ! adding checks for SP and NOCOMP modes. - if(currentPatch%nocomp_pft_label.eq.0)then + if(currentPatch%nocomp_pft_label.eq.nocomp_bareground)then write(fates_log(),*) 'cohorts in barepatch',currentPatch%total_canopy_area,currentPatch%nocomp_pft_label call endrun(msg=errMsg(sourcefile, __LINE__)) end if @@ -1364,9 +1389,9 @@ subroutine canopy_summarization( nsites, sites, bc_in ) call endrun(msg=errMsg(sourcefile, __LINE__)) end if - if(currentPatch%total_canopy_area-currentPatch%area.gt.1.0e-16)then - write(fates_log(),*) 'too much canopy in summary',s, & - currentPatch%nocomp_pft_label, currentPatch%total_canopy_area-currentPatch%area + if (currentPatch%total_canopy_area - currentPatch%area > area_error_1) then + write(fates_log(),*) 'too much canopy in summary', s, & + currentPatch%nocomp_pft_label, currentPatch%total_canopy_area - currentPatch%area call endrun(msg=errMsg(sourcefile, __LINE__)) end if end if !sp mode @@ -1407,6 +1432,8 @@ subroutine canopy_summarization( nsites, sites, bc_in ) currentPatch => currentPatch%younger end do !patch loop + + call leaf_area_profile(sites(s)) end do ! site loop @@ -1447,8 +1474,6 @@ subroutine leaf_area_profile( currentSite ) ! ! currentCohort%treelai ! LAI per unit crown area (m2/m2) ! currentCohort%treesai ! SAI per unit crown area (m2/m2) - ! currentCohort%lai ! LAI per unit canopy area (m2/m2) - ! currentCohort%sai ! SAI per unit canopy area (m2/m2) ! currentCohort%NV ! The number of discrete vegetation ! ! layers needed to describe this crown ! @@ -1474,8 +1499,9 @@ subroutine leaf_area_profile( currentSite ) ! !USES: - use EDtypesMod , only : area, dinc_vai, dlower_vai, hitemax, n_hite_bins - + use EDtypesMod , only : area, heightmax, n_height_bins + use EDParamsMod, only : dinc_vai, dlower_vai + ! ! !ARGUMENTS type(ed_site_type) , intent(inout) :: currentSite @@ -1483,30 +1509,27 @@ subroutine leaf_area_profile( currentSite ) ! ! !LOCAL VARIABLES: - type (ed_patch_type) , pointer :: currentPatch - type (ed_cohort_type) , pointer :: currentCohort + type (fates_patch_type) , pointer :: currentPatch + type (fates_cohort_type) , pointer :: currentCohort real(r8) :: remainder !Thickness of layer at bottom of canopy. real(r8) :: fleaf ! fraction of cohort incepting area that is leaves. integer :: ft ! Plant functional type index. integer :: iv ! Vertical leaf layer index integer :: cl ! Canopy layer index real(r8) :: fraction_exposed ! how much of this layer is not covered by snow? - real(r8) :: layer_top_hite ! notional top height of this canopy layer (m) - real(r8) :: layer_bottom_hite ! notional bottom height of this canopy layer (m) - integer :: smooth_leaf_distribution ! is the leaf distribution this option (1) or not (0) - real(r8) :: frac_canopy(N_HITE_BINS) ! amount of canopy in each height class - real(r8) :: patch_lai ! LAI summed over the patch in m2/m2 of canopy area - real(r8) :: minh(N_HITE_BINS) ! minimum height in height class (m) - real(r8) :: maxh(N_HITE_BINS) ! maximum height in height class (m) + real(r8) :: layer_top_height ! notional top height of this canopy layer (m) + real(r8) :: layer_bottom_height ! notional bottom height of this canopy layer (m) + real(r8) :: frac_canopy(N_HEIGHT_BINS) ! amount of canopy in each height class + real(r8) :: minh(N_HEIGHT_BINS) ! minimum height in height class (m) + real(r8) :: maxh(N_HEIGHT_BINS) ! maximum height in height class (m) real(r8) :: dh ! vertical detph of height class (m) - real(r8) :: min_chite ! bottom of cohort canopy (m) - real(r8) :: max_chite ! top of cohort canopy (m) - real(r8) :: lai ! summed lai for checking m2 m-2 - real(r8) :: leaf_c ! leaf carbon [kg] + real(r8) :: min_cheight ! bottom of cohort canopy (m) + real(r8) :: max_cheight ! top of cohort canopy (m) + real(r8) :: lai ! leaf area per canopy area + real(r8) :: sai ! stem area per canopy area !---------------------------------------------------------------------- - smooth_leaf_distribution = 0 ! Here we are trying to generate a profile of leaf area, indexed by 'z' and by pft ! We assume that each point in the canopy recieved the light attenuated by the average @@ -1524,7 +1547,6 @@ subroutine leaf_area_profile( currentSite ) currentPatch%canopy_layer_tlai(:) = 0._r8 currentPatch%ncan(:,:) = 0 currentPatch%nrad(:,:) = 0 - patch_lai = 0._r8 currentPatch%tlai_profile(:,:,:) = 0._r8 currentPatch%tsai_profile(:,:,:) = 0._r8 currentPatch%elai_profile(:,:,:) = 0._r8 @@ -1532,7 +1554,7 @@ subroutine leaf_area_profile( currentSite ) currentPatch%layer_height_profile(:,:,:) = 0._r8 currentPatch%canopy_area_profile(:,:,:) = 0._r8 currentPatch%canopy_mask(:,:) = 0 - + ! ------------------------------------------------------------------------------ ! It is remotely possible that in deserts we will not have any canopy ! area, ie not plants at all... @@ -1540,345 +1562,227 @@ subroutine leaf_area_profile( currentSite ) if (currentPatch%total_canopy_area > nearzero ) then + call UpdatePatchLAI(currentPatch) - currentCohort => currentPatch%tallest - do while(associated(currentCohort)) + ! ----------------------------------------------------------------------------- + ! Standard canopy layering model. + ! Go through all cohorts and add their leaf area + ! and canopy area to the accumulators. + ! ----------------------------------------------------------------------------- + currentCohort => currentPatch%shortest + do while(associated(currentCohort)) ft = currentCohort%pft cl = currentCohort%canopy_layer - ! Calculate LAI of layers above - ! Note that the canopy_layer_lai is also calculated in this loop - ! but since we go top down in terms of plant size, we should be okay - - leaf_c = currentCohort%prt%GetState(leaf_organ,all_carbon_elements) + ! ---------------------------------------------------------------- + ! How much of each tree is stem area index? Assuming that there is + ! This may indeed be zero if there is a sensecent grass + ! ---------------------------------------------------------------- + lai = currentCohort%treelai * currentCohort%c_area/currentPatch%total_canopy_area + sai = currentCohort%treesai * currentCohort%c_area/currentPatch%total_canopy_area + if( (currentCohort%treelai+currentCohort%treesai) > nearzero)then + + ! See issue: https://github.com/NGEET/fates/issues/899 + ! fleaf = currentCohort%treelai / (currentCohort%treelai + currentCohort%treesai) + fleaf = lai / (lai+sai) + else + fleaf = 0._r8 + endif - currentCohort%treelai = tree_lai(leaf_c, currentCohort%pft, currentCohort%c_area, & - currentCohort%n, currentCohort%canopy_layer, & - currentPatch%canopy_layer_tlai,currentCohort%vcmax25top ) + currentPatch%nrad(cl,ft) = currentPatch%ncan(cl,ft) - if (hlm_use_sp .eq. ifalse) then - 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,4) + if (currentPatch%nrad(cl,ft) > nlevleaf ) then + write(fates_log(), *) 'Number of radiative leaf layers is larger' + write(fates_log(), *) ' than the maximum allowed.' + write(fates_log(), *) ' cl: ',cl + write(fates_log(), *) ' ft: ',ft + write(fates_log(), *) ' nlevleaf: ',nlevleaf + write(fates_log(), *) ' currentPatch%nrad(cl,ft): ', currentPatch%nrad(cl,ft) + call endrun(msg=errMsg(sourcefile, __LINE__)) end if - currentCohort%lai = currentCohort%treelai *currentCohort%c_area/currentPatch%total_canopy_area - currentCohort%sai = currentCohort%treesai *currentCohort%c_area/currentPatch%total_canopy_area - - ! Number of actual vegetation layers in this cohort's crown - currentCohort%nv = count((currentCohort%treelai+currentCohort%treesai) .gt. dlower_vai(:)) + 1 - - currentPatch%ncan(cl,ft) = max(currentPatch%ncan(cl,ft),currentCohort%NV) - patch_lai = patch_lai + currentCohort%lai - - currentPatch%canopy_layer_tlai(cl) = currentPatch%canopy_layer_tlai(cl) + currentCohort%lai + ! -------------------------------------------------------------------------- + ! Whole layers. Make a weighted average of the leaf area in each layer + ! before dividing it by the total area. Fill up layer for whole layers. + ! -------------------------------------------------------------------------- - currentCohort => currentCohort%shorter + do iv = 1,currentCohort%NV - enddo !currentCohort + ! This loop builds the arrays that define the effective (not snow covered) + ! and total (includes snow covered) area indices for leaves and stems + ! We calculate the absolute elevation of each layer to help determine if the layer + ! is obscured by snow. - if(smooth_leaf_distribution == 1)then + layer_top_height = currentCohort%height - & + ( real(iv-1,r8)/currentCohort%NV * currentCohort%height * & + prt_params%crown_depth_frac(currentCohort%pft) ) - ! ----------------------------------------------------------------------------- - ! we are going to ignore the concept of canopy layers, and put all of the leaf - ! area into height banded bins. using the same domains as we had before, except - ! that CL always = 1 - ! ----------------------------------------------------------------------------- + layer_bottom_height = currentCohort%height - & + ( real(iv,r8)/currentCohort%NV * currentCohort%height * & + prt_params%crown_depth_frac(currentCohort%pft) ) - ! this is a crude way of dividing up the bins. Should it be a function of actual maximum height? - dh = 1.0_r8*(HITEMAX/N_HITE_BINS) - do iv = 1,N_HITE_BINS - if (iv == 1) then - minh(iv) = 0.0_r8 - maxh(iv) = dh - else - minh(iv) = (iv-1)*dh - maxh(iv) = (iv)*dh + fraction_exposed = 1.0_r8 + if(currentSite%snow_depth > layer_top_height)then + fraction_exposed = 0._r8 + endif + if(currentSite%snow_depth < layer_bottom_height)then + fraction_exposed = 1._r8 + endif + if(currentSite%snow_depth >= layer_bottom_height .and. & + currentSite%snow_depth <= layer_top_height) then !only partly hidden... + fraction_exposed = 1._r8 - max(0._r8,(min(1.0_r8,(currentSite%snow_depth -layer_bottom_height)/ & + (layer_top_height-layer_bottom_height )))) endif - enddo - - currentCohort => currentPatch%shortest - do while(associated(currentCohort)) - ft = currentCohort%pft - min_chite = currentCohort%hite - currentCohort%hite * prt_params%crown(ft) - max_chite = currentCohort%hite - do iv = 1,N_HITE_BINS - frac_canopy(iv) = 0.0_r8 - ! this layer is in the middle of the canopy - if(max_chite > maxh(iv).and.min_chite < minh(iv))then - frac_canopy(iv)= min(1.0_r8,dh / (currentCohort%hite*prt_params%crown(ft))) - ! this is the layer with the bottom of the canopy in it. - elseif(min_chite < maxh(iv).and.min_chite > minh(iv).and.max_chite > maxh(iv))then - frac_canopy(iv) = (maxh(iv) -min_chite ) / (currentCohort%hite*prt_params%crown(ft)) - ! this is the layer with the top of the canopy in it. - elseif(max_chite > minh(iv).and.max_chite < maxh(iv).and.min_chite < minh(iv))then - frac_canopy(iv) = (max_chite - minh(iv)) / (currentCohort%hite*prt_params%crown(ft)) - elseif(max_chite < maxh(iv).and.min_chite > minh(iv))then !the whole cohort is within this layer. - frac_canopy(iv) = 1.0_r8 - endif - ! no m2 of leaf per m2 of ground in each height class - currentPatch%tlai_profile(1,ft,iv) = currentPatch%tlai_profile(1,ft,iv) + frac_canopy(iv) * & - currentCohort%lai - currentPatch%tsai_profile(1,ft,iv) = currentPatch%tsai_profile(1,ft,iv) + frac_canopy(iv) * & - currentCohort%sai + if(iv==currentCohort%NV) then + remainder = (currentCohort%treelai + currentCohort%treesai) - & + (dlower_vai(iv) - dinc_vai(iv)) + if(remainder > dinc_vai(iv) )then + write(fates_log(), *)'ED: issue with remainder', & + currentCohort%treelai,currentCohort%treesai,dinc_vai(iv), & + currentCohort%NV,remainder - !snow burial - if(currentSite%snow_depth > maxh(iv))then - fraction_exposed = 0._r8 - endif - if(currentSite%snow_depth < minh(iv))then - fraction_exposed = 1._r8 - endif - if(currentSite%snow_depth >= minh(iv) .and. currentSite%snow_depth <= maxh(iv)) then !only partly hidden... - fraction_exposed = 1._r8 - max(0._r8,(min(1.0_r8,(currentSite%snow_depth-minh(iv))/dh))) + call endrun(msg=errMsg(sourcefile, __LINE__)) endif - - currentPatch%elai_profile(1,ft,iv) = currentPatch%tlai_profile(1,ft,iv) * fraction_exposed - currentPatch%esai_profile(1,ft,iv) = currentPatch%tsai_profile(1,ft,iv) * fraction_exposed - - enddo ! (iv) hite bins - - currentCohort => currentCohort%taller - - enddo !currentCohort - - ! ----------------------------------------------------------------------------- - ! Perform a leaf area conservation check on the LAI profile - lai = 0.0_r8 - do ft = 1,numpft - lai = lai+ sum(currentPatch%tlai_profile(1,ft,:)) - enddo - - if(lai > patch_lai)then - write(fates_log(), *) 'FATES: problem with lai assignments' - call endrun(msg=errMsg(sourcefile, __LINE__)) - endif - - - else ! smooth leaf distribution - - ! ----------------------------------------------------------------------------- - ! Standard canopy layering model. - ! Go through all cohorts and add their leaf area - ! and canopy area to the accumulators. - ! ----------------------------------------------------------------------------- - - - currentCohort => currentPatch%shortest - do while(associated(currentCohort)) - ft = currentCohort%pft - cl = currentCohort%canopy_layer - - ! ---------------------------------------------------------------- - ! How much of each tree is stem area index? Assuming that there is - ! This may indeed be zero if there is a sensecent grass - ! ---------------------------------------------------------------- - - if( (currentCohort%treelai+currentCohort%treesai) > 0._r8)then - fleaf = currentCohort%lai / (currentCohort%lai + currentCohort%sai) else - fleaf = 0._r8 - endif - - currentPatch%nrad(cl,ft) = currentPatch%ncan(cl,ft) - - if (currentPatch%nrad(cl,ft) > nlevleaf ) then - write(fates_log(), *) 'Number of radiative leaf layers is larger' - write(fates_log(), *) ' than the maximum allowed.' - write(fates_log(), *) ' cl: ',cl - write(fates_log(), *) ' ft: ',ft - write(fates_log(), *) ' nlevleaf: ',nlevleaf - write(fates_log(), *) ' currentPatch%nrad(cl,ft): ', currentPatch%nrad(cl,ft) - call endrun(msg=errMsg(sourcefile, __LINE__)) + remainder = dinc_vai(iv) end if + currentPatch%tlai_profile(cl,ft,iv) = currentPatch%tlai_profile(cl,ft,iv) + & + remainder * fleaf * currentCohort%c_area/currentPatch%total_canopy_area - ! -------------------------------------------------------------------------- - ! Whole layers. Make a weighted average of the leaf area in each layer - ! before dividing it by the total area. Fill up layer for whole layers. - ! -------------------------------------------------------------------------- - - do iv = 1,currentCohort%NV + currentPatch%elai_profile(cl,ft,iv) = currentPatch%elai_profile(cl,ft,iv) + & + remainder * fleaf * currentCohort%c_area/currentPatch%total_canopy_area * & + fraction_exposed - ! This loop builds the arrays that define the effective (not snow covered) - ! and total (includes snow covered) area indices for leaves and stems - ! We calculate the absolute elevation of each layer to help determine if the layer - ! is obscured by snow. + currentPatch%tsai_profile(cl,ft,iv) = currentPatch%tsai_profile(cl,ft,iv) + & + remainder * (1._r8 - fleaf) * currentCohort%c_area/currentPatch%total_canopy_area - layer_top_hite = currentCohort%hite - & - ( real(iv-1,r8)/currentCohort%NV * currentCohort%hite * & - prt_params%crown(currentCohort%pft) ) + currentPatch%esai_profile(cl,ft,iv) = currentPatch%esai_profile(cl,ft,iv) + & + remainder * (1._r8 - fleaf) * currentCohort%c_area/currentPatch%total_canopy_area * & + fraction_exposed - layer_bottom_hite = currentCohort%hite - & - ( real(iv,r8)/currentCohort%NV * currentCohort%hite * & - prt_params%crown(currentCohort%pft) ) + currentPatch%canopy_area_profile(cl,ft,iv) = currentPatch%canopy_area_profile(cl,ft,iv) + & + currentCohort%c_area/currentPatch%total_canopy_area - fraction_exposed = 1.0_r8 - if(currentSite%snow_depth > layer_top_hite)then - fraction_exposed = 0._r8 - endif - if(currentSite%snow_depth < layer_bottom_hite)then - fraction_exposed = 1._r8 - endif - if(currentSite%snow_depth >= layer_bottom_hite .and. & - currentSite%snow_depth <= layer_top_hite) then !only partly hidden... - fraction_exposed = 1._r8 - max(0._r8,(min(1.0_r8,(currentSite%snow_depth -layer_bottom_hite)/ & - (layer_top_hite-layer_bottom_hite )))) - endif + currentPatch%layer_height_profile(cl,ft,iv) = currentPatch%layer_height_profile(cl,ft,iv) + & + (remainder * fleaf * currentCohort%c_area/currentPatch%total_canopy_area * & + (layer_top_height+layer_bottom_height)/2.0_r8) !average height of layer. - if(iv==currentCohort%NV) then - remainder = (currentCohort%treelai + currentCohort%treesai) - & - (dlower_vai(iv) - dinc_vai(iv)) - if(remainder > dinc_vai(iv) )then - write(fates_log(), *)'ED: issue with remainder', & - currentCohort%treelai,currentCohort%treesai,dinc_vai(iv), & - currentCohort%NV,remainder - - call endrun(msg=errMsg(sourcefile, __LINE__)) - endif - else - remainder = dinc_vai(iv) - end if + end do - currentPatch%tlai_profile(cl,ft,iv) = currentPatch%tlai_profile(cl,ft,iv) + & - remainder * fleaf * currentCohort%c_area/currentPatch%total_canopy_area + currentCohort => currentCohort%taller - currentPatch%elai_profile(cl,ft,iv) = currentPatch%elai_profile(cl,ft,iv) + & - remainder * fleaf * currentCohort%c_area/currentPatch%total_canopy_area * & - fraction_exposed + enddo !cohort - currentPatch%tsai_profile(cl,ft,iv) = currentPatch%tsai_profile(cl,ft,iv) + & - remainder * (1._r8 - fleaf) * currentCohort%c_area/currentPatch%total_canopy_area + ! -------------------------------------------------------------------------- - currentPatch%esai_profile(cl,ft,iv) = currentPatch%esai_profile(cl,ft,iv) + & - remainder * (1._r8 - fleaf) * currentCohort%c_area/currentPatch%total_canopy_area * & - fraction_exposed + ! If there is an upper-story, the top canopy layer + ! should have a value of exactly 1.0 in its top leaf layer + ! -------------------------------------------------------------------------- - currentPatch%canopy_area_profile(cl,ft,iv) = currentPatch%canopy_area_profile(cl,ft,iv) + & + if ( (currentPatch%NCL_p > 1) .and. & + (sum(currentPatch%canopy_area_profile(1,:,1)) < 0.9999 )) then + write(fates_log(), *) 'FATES: canopy_area_profile was less than 1 at the canopy top' + write(fates_log(), *) 'cl: ',1 + write(fates_log(), *) 'iv: ',1 + write(fates_log(), *) 'sum(cpatch%canopy_area_profile(1,:,1)): ', & + sum(currentPatch%canopy_area_profile(1,:,1)) + currentCohort => currentPatch%shortest + do while(associated(currentCohort)) + if(currentCohort%canopy_layer==1)then + write(fates_log(), *) 'FATES: cohorts',currentCohort%dbh,currentCohort%c_area, & + currentPatch%total_canopy_area,currentPatch%area + write(fates_log(), *) 'ED: fracarea', currentCohort%pft, & currentCohort%c_area/currentPatch%total_canopy_area - - currentPatch%layer_height_profile(cl,ft,iv) = currentPatch%layer_height_profile(cl,ft,iv) + & - (remainder * fleaf * currentCohort%c_area/currentPatch%total_canopy_area * & - (layer_top_hite+layer_bottom_hite)/2.0_r8) !average height of layer. - - end do - + endif currentCohort => currentCohort%taller + enddo !currentCohort + call endrun(msg=errMsg(sourcefile, __LINE__)) - enddo !cohort - - ! -------------------------------------------------------------------------- + end if - ! If there is an upper-story, the top canopy layer - ! should have a value of exactly 1.0 in its top leaf layer - ! -------------------------------------------------------------------------- - if ( (currentPatch%NCL_p > 1) .and. & - (sum(currentPatch%canopy_area_profile(1,:,1)) < 0.9999 )) then - write(fates_log(), *) 'FATES: canopy_area_profile was less than 1 at the canopy top' - write(fates_log(), *) 'cl: ',1 - write(fates_log(), *) 'iv: ',1 - write(fates_log(), *) 'sum(cpatch%canopy_area_profile(1,:,1)): ', & - sum(currentPatch%canopy_area_profile(1,:,1)) - currentCohort => currentPatch%shortest - do while(associated(currentCohort)) - if(currentCohort%canopy_layer==1)then - write(fates_log(), *) 'FATES: cohorts',currentCohort%dbh,currentCohort%c_area, & - currentPatch%total_canopy_area,currentPatch%area - write(fates_log(), *) 'ED: fracarea', currentCohort%pft, & - currentCohort%c_area/currentPatch%total_canopy_area - endif - currentCohort => currentCohort%taller - enddo !currentCohort - call endrun(msg=errMsg(sourcefile, __LINE__)) + ! -------------------------------------------------------------------------- + ! In the following loop we are now normalizing the effective and + ! total area profiles to convert from units of leaf/stem area per vegetated + ! canopy area, into leaf/stem area per area of their own radiative column + ! which is typically the footprint of all cohorts contained in the canopy + ! layer x pft bins. + ! Also perform some checks on area normalization. + ! Check the area of each leaf layer, across pfts. + ! It should never be larger than 1 or less than 0. + ! -------------------------------------------------------------------------- - end if + do cl = 1,currentPatch%NCL_p + do iv = 1,currentPatch%ncan(cl,ft) + if( debug .and. sum(currentPatch%canopy_area_profile(cl,:,iv)) > 1.0001_r8 ) then - ! -------------------------------------------------------------------------- - ! In the following loop we are now normalizing the effective and - ! total area profiles to convert from units of leaf/stem area per vegetated - ! canopy area, into leaf/stem area per area of their own radiative column - ! which is typically the footprint of all cohorts contained in the canopy - ! layer x pft bins. - ! Also perform some checks on area normalization. - ! Check the area of each leaf layer, across pfts. - ! It should never be larger than 1 or less than 0. - ! -------------------------------------------------------------------------- + write(fates_log(), *) 'FATES: A canopy_area_profile exceeded 1.0' + write(fates_log(), *) 'cl: ',cl + write(fates_log(), *) 'iv: ',iv + write(fates_log(), *) 'sum(cpatch%canopy_area_profile(cl,:,iv)): ', & + sum(currentPatch%canopy_area_profile(cl,:,iv)) + currentCohort => currentPatch%shortest + do while(associated(currentCohort)) + if(currentCohort%canopy_layer==cl)then + write(fates_log(), *) 'FATES: cohorts in layer cl = ',cl, & + currentCohort%dbh,currentCohort%c_area, & + currentPatch%total_canopy_area,currentPatch%area + write(fates_log(), *) 'ED: fracarea', currentCohort%pft, & + currentCohort%c_area/currentPatch%total_canopy_area + endif + currentCohort => currentCohort%taller + enddo !currentCohort + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + end do - do cl = 1,currentPatch%NCL_p + do ft = 1,numpft do iv = 1,currentPatch%ncan(cl,ft) - if( debug .and. sum(currentPatch%canopy_area_profile(cl,:,iv)) > 1.0001_r8 ) then - - write(fates_log(), *) 'FATES: A canopy_area_profile exceeded 1.0' - write(fates_log(), *) 'cl: ',cl - write(fates_log(), *) 'iv: ',iv - write(fates_log(), *) 'sum(cpatch%canopy_area_profile(cl,:,iv)): ', & - sum(currentPatch%canopy_area_profile(cl,:,iv)) - currentCohort => currentPatch%shortest - do while(associated(currentCohort)) - if(currentCohort%canopy_layer==cl)then - write(fates_log(), *) 'FATES: cohorts in layer cl = ',cl, & - currentCohort%dbh,currentCohort%c_area, & - currentPatch%total_canopy_area,currentPatch%area - write(fates_log(), *) 'ED: fracarea', currentCohort%pft, & - currentCohort%c_area/currentPatch%total_canopy_area - endif - currentCohort => currentCohort%taller - enddo !currentCohort - call endrun(msg=errMsg(sourcefile, __LINE__)) - end if - end do - - do ft = 1,numpft - do iv = 1,currentPatch%ncan(cl,ft) - - if( currentPatch%canopy_area_profile(cl,ft,iv) > nearzero ) then + if( currentPatch%canopy_area_profile(cl,ft,iv) > nearzero ) then - currentPatch%tlai_profile(cl,ft,iv) = currentPatch%tlai_profile(cl,ft,iv) / & - currentPatch%canopy_area_profile(cl,ft,iv) + currentPatch%tlai_profile(cl,ft,iv) = currentPatch%tlai_profile(cl,ft,iv) / & + currentPatch%canopy_area_profile(cl,ft,iv) - currentPatch%tsai_profile(cl,ft,iv) = currentPatch%tsai_profile(cl,ft,iv) / & - currentPatch%canopy_area_profile(cl,ft,iv) + currentPatch%tsai_profile(cl,ft,iv) = currentPatch%tsai_profile(cl,ft,iv) / & + currentPatch%canopy_area_profile(cl,ft,iv) - currentPatch%elai_profile(cl,ft,iv) = currentPatch%elai_profile(cl,ft,iv) / & - currentPatch%canopy_area_profile(cl,ft,iv) + currentPatch%elai_profile(cl,ft,iv) = currentPatch%elai_profile(cl,ft,iv) / & + currentPatch%canopy_area_profile(cl,ft,iv) - currentPatch%esai_profile(cl,ft,iv) = currentPatch%esai_profile(cl,ft,iv) / & - currentPatch%canopy_area_profile(cl,ft,iv) - end if - - if(currentPatch%tlai_profile(cl,ft,iv)>nearzero )then - currentPatch%layer_height_profile(cl,ft,iv) = currentPatch%layer_height_profile(cl,ft,iv) & - /currentPatch%tlai_profile(cl,ft,iv) - end if + currentPatch%esai_profile(cl,ft,iv) = currentPatch%esai_profile(cl,ft,iv) / & + currentPatch%canopy_area_profile(cl,ft,iv) + end if - enddo + if(currentPatch%tlai_profile(cl,ft,iv)>nearzero )then + currentPatch%layer_height_profile(cl,ft,iv) = currentPatch%layer_height_profile(cl,ft,iv) & + /currentPatch%tlai_profile(cl,ft,iv) + end if enddo - enddo - ! -------------------------------------------------------------------------- - ! Set the mask that identifies which PFT x can-layer combinations have - ! scattering elements in them. - ! -------------------------------------------------------------------------- + enddo + enddo - do cl = 1,currentPatch%NCL_p - do ft = 1,numpft - do iv = 1, currentPatch%nrad(cl,ft) - if(currentPatch%canopy_area_profile(cl,ft,iv) > 0._r8)then - currentPatch%canopy_mask(cl,ft) = 1 - endif - end do !iv - enddo !ft - enddo ! loop over cl + ! -------------------------------------------------------------------------- + ! Set the mask that identifies which PFT x can-layer combinations have + ! scattering elements in them. + ! -------------------------------------------------------------------------- - endif !leaf distribution + do cl = 1,currentPatch%NCL_p + do ft = 1,numpft + do iv = 1, currentPatch%nrad(cl,ft) + if(currentPatch%canopy_area_profile(cl,ft,iv) > 0._r8)then + currentPatch%canopy_mask(cl,ft) = 1 + endif + end do !iv + enddo !ft + enddo ! loop over cl end if @@ -1898,8 +1802,8 @@ subroutine update_hlm_dynamics(nsites,sites,fcolumn,bc_out) ! to vegetation coverage to the host land model. ! ---------------------------------------------------------------------------------- - use EDTypesMod , only : ed_patch_type, ed_cohort_type, & - ed_site_type, AREA + use EDTypesMod , only : ed_site_type, AREA + use FatesPatchMod, only : fates_patch_type use FatesInterfaceTypesMod , only : bc_out_type ! @@ -1910,15 +1814,15 @@ subroutine update_hlm_dynamics(nsites,sites,fcolumn,bc_out) type(bc_out_type), intent(inout) :: bc_out(nsites) ! Locals - type (ed_cohort_type) , pointer :: currentCohort + type (fates_cohort_type) , pointer :: currentCohort integer :: s, ifp, c, p - type (ed_patch_type) , pointer :: currentPatch + type (fates_patch_type) , pointer :: currentPatch real(r8) :: bare_frac_area real(r8) :: total_patch_area real(r8) :: total_canopy_area real(r8) :: total_patch_leaf_stem_area real(r8) :: weight ! Weighting for cohort variables in patch - + do s = 1,nsites ifp = 0 @@ -1933,17 +1837,20 @@ subroutine update_hlm_dynamics(nsites,sites,fcolumn,bc_out) c = fcolumn(s) do while(associated(currentPatch)) - if(currentPatch%nocomp_pft_label.ne.0)then ! ignore the bare-ground-PFT patch entirely for these BC outs + if(currentPatch%nocomp_pft_label.ne.nocomp_bareground)then ! ignore the bare-ground-PFT patch entirely for these BC outs ifp = ifp+1 if ( currentPatch%total_canopy_area-currentPatch%area > 0.000001_r8 ) then - write(fates_log(),*) 'ED: canopy area bigger than area',currentPatch%total_canopy_area ,currentPatch%area + if(debug)then + write(fates_log(),*) 'ED: canopy area bigger than area', & + currentPatch%total_canopy_area ,currentPatch%area + end if currentPatch%total_canopy_area = currentPatch%area endif if (associated(currentPatch%tallest)) then - bc_out(s)%htop_pa(ifp) = currentPatch%tallest%hite + bc_out(s)%htop_pa(ifp) = currentPatch%tallest%height else ! FIX(RF,040113) - should this be a parameter for the minimum possible vegetation height? bc_out(s)%htop_pa(ifp) = 0.1_r8 @@ -1963,9 +1870,9 @@ subroutine update_hlm_dynamics(nsites,sites,fcolumn,bc_out) if (currentCohort%canopy_layer .eq. 1) then weight = min(1.0_r8,currentCohort%c_area/currentPatch%total_canopy_area) bc_out(s)%z0m_pa(ifp) = bc_out(s)%z0m_pa(ifp) + & - EDPftvarcon_inst%z0mr(currentCohort%pft) * currentCohort%hite * weight + EDPftvarcon_inst%z0mr(currentCohort%pft) * currentCohort%height * weight bc_out(s)%displa_pa(ifp) = bc_out(s)%displa_pa(ifp) + & - EDPftvarcon_inst%displar(currentCohort%pft) * currentCohort%hite * weight + EDPftvarcon_inst%displar(currentCohort%pft) * currentCohort%height * weight endif currentCohort => currentCohort%taller end do @@ -1974,22 +1881,6 @@ subroutine update_hlm_dynamics(nsites,sites,fcolumn,bc_out) total_patch_leaf_stem_area = 0._r8 currentCohort => currentPatch%shortest do while(associated(currentCohort)) - - if (hlm_use_sp.eq.ifalse) then - ! make sure that allometries are correct - call carea_allom(currentCohort%dbh,currentCohort%n,sites(s)%spread,& - currentCohort%pft,currentCohort%c_area) - - currentCohort%treelai = tree_lai(currentCohort%prt%GetState(leaf_organ, all_carbon_elements), & - 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,4) - endif - total_patch_leaf_stem_area = total_patch_leaf_stem_area + & (currentCohort%treelai + currentCohort%treesai) * currentCohort%c_area currentCohort => currentCohort%taller @@ -2088,7 +1979,7 @@ subroutine update_hlm_dynamics(nsites,sites,fcolumn,bc_out) currentPatch => sites(s)%oldest_patch ifp = 0 do while(associated(currentPatch)) - if(currentPatch%nocomp_pft_label.ne.0)then ! for vegetated patches only + if(currentPatch%nocomp_pft_label.ne.nocomp_bareground)then ! for vegetated patches only ifp = ifp+1 bc_out(s)%canopy_fraction_pa(ifp) = bc_out(s)%canopy_fraction_pa(ifp)/total_patch_area endif ! veg patch @@ -2110,6 +2001,9 @@ subroutine update_hlm_dynamics(nsites,sites,fcolumn,bc_out) call UpdateH2OVeg(sites(s),bc_out(s),bc_out(s)%plant_stored_h2o_si,1) end if + ! Pass FATES Harvested C to bc_out. + call UpdateHarvestC(sites(s),bc_out(s)) + end do ! This call to RecruitWaterStorage() makes an accounting of @@ -2123,7 +2017,6 @@ subroutine update_hlm_dynamics(nsites,sites,fcolumn,bc_out) call RecruitWaterStorage(nsites,sites,bc_out) end if - end subroutine update_hlm_dynamics ! ===================================================================================== @@ -2139,7 +2032,7 @@ function calc_areaindex(cpatch,ai_type) result(ai) ! ---------------------------------------------------------------------------------- ! Arguments - type(ed_patch_type),intent(in), target :: cpatch + type(fates_patch_type),intent(in), target :: cpatch character(len=*),intent(in) :: ai_type integer :: cl,ft @@ -2203,27 +2096,115 @@ subroutine CanopyLayerArea(currentPatch,site_spread,layer_index,layer_area) ! --------------------------------------------------------------------------------------------- ! Arguments - type(ed_patch_type),intent(inout), target :: currentPatch + type(fates_patch_type),intent(inout), target :: currentPatch real(r8),intent(in) :: site_spread integer,intent(in) :: layer_index real(r8),intent(inout) :: layer_area - type(ed_cohort_type), pointer :: currentCohort - - + type(fates_cohort_type), pointer :: currentCohort + + layer_area = 0.0_r8 currentCohort => currentPatch%tallest do while (associated(currentCohort)) call carea_allom(currentCohort%dbh,currentCohort%n,site_spread, & - currentCohort%pft,currentCohort%c_area) + currentCohort%pft,currentCohort%crowndamage, currentCohort%c_area) if (currentCohort%canopy_layer .eq. layer_index) then layer_area = layer_area + currentCohort%c_area end if currentCohort => currentCohort%shorter enddo return - end subroutine CanopyLayerArea + end subroutine CanopyLayerArea + + ! =============================================================================================== + subroutine UpdatePatchLAI(currentPatch) + + ! -------------------------------------------------------------------------------------------- + ! This subroutine works through the current patch cohorts and updates the canopy_layer_tlai + ! and related variables + ! --------------------------------------------------------------------------------------------- + + ! Arguments + type(fates_patch_type),intent(inout), target :: currentPatch + + ! Local Variables + type(fates_cohort_type), pointer :: currentCohort + integer :: cl ! Canopy layer index + integer :: ft ! Plant functional type index + + ! Calculate LAI of layers above. Because it is possible for some understory cohorts + ! to be taller than cohorts in the top canopy layer, we must iterate through the + ! patch by canopy layer first. Given that canopy_layer_tlai is a patch level variable + ! we could iterate through each cohort in any direction as long as we go down through + ! the canopy layers. + + canopyloop: do cl = 1,nclmax + currentCohort => currentPatch%tallest + cohortloop: do while(associated(currentCohort)) + + ! Only update the current cohort tree lai if lai of the above layers have been calculated + if (currentCohort%canopy_layer .eq. cl) then + ft = currentCohort%pft + + ! Update the cohort level lai and related variables + call UpdateCohortLAI(currentCohort,currentPatch%canopy_layer_tlai, & + currentPatch%total_canopy_area) + + ! Update the number of number of vegetation layers + currentPatch%ncan(cl,ft) = max(currentPatch%ncan(cl,ft),currentCohort%NV) + + ! Update the patch canopy layer tlai (LAI per canopy area) + currentPatch%canopy_layer_tlai(cl) = currentPatch%canopy_layer_tlai(cl) + & + currentCohort%treelai *currentCohort%c_area/currentPatch%total_canopy_area + + end if + currentCohort => currentCohort%shorter + + end do cohortloop + end do canopyloop + + end subroutine UpdatePatchLAI + ! =============================================================================================== + + subroutine UpdateCohortLAI(currentCohort, canopy_layer_tlai, total_canopy_area) + + ! Update LAI and related variables for a given cohort + + ! Uses + use EDParamsMod, only : dlower_vai + + ! Arguments + type(fates_cohort_type),intent(inout), target :: currentCohort + real(r8), intent(in) :: canopy_layer_tlai(nclmax) ! total leaf area index of each canopy layer + real(r8), intent(in) :: total_canopy_area ! either patch%total_canopy_area or patch%area + + ! Local variables + real(r8) :: leaf_c ! leaf carbon [kg] + + ! Obtain the leaf carbon + leaf_c = currentCohort%prt%GetState(leaf_organ,carbon12_element) + + + ! Note that tree_lai has an internal check on the canopy locatoin + currentCohort%treelai = tree_lai(leaf_c, currentCohort%pft, currentCohort%c_area, & + currentCohort%n, currentCohort%canopy_layer, & + canopy_layer_tlai,currentCohort%vcmax25top ) + + if (hlm_use_sp .eq. ifalse) then + currentCohort%treesai = tree_sai(currentCohort%pft, currentCohort%dbh, currentCohort%crowndamage, & + currentCohort%canopy_trim, currentCohort%efstem_coh, & + currentCohort%c_area, currentCohort%n, currentCohort%canopy_layer, & + canopy_layer_tlai, currentCohort%treelai , & + currentCohort%vcmax25top,4) + end if + + ! Number of actual vegetation layers in this cohort's crown + currentCohort%nv = count((currentCohort%treelai+currentCohort%treesai) .gt. dlower_vai(:)) + 1 + + end subroutine UpdateCohortLAI + ! =============================================================================================== function NumPotentialCanopyLayers(currentPatch,site_spread,include_substory) result(z) @@ -2237,11 +2218,11 @@ function NumPotentialCanopyLayers(currentPatch,site_spread,include_substory) res ! the understory in the event the understory has reached maximum allowable area. ! -------------------------------------------------------------------------------------------- - type(ed_patch_type),target :: currentPatch + type(fates_patch_type),target :: currentPatch real(r8),intent(in) :: site_spread logical :: include_substory - type(ed_cohort_type),pointer :: currentCohort + type(fates_cohort_type),pointer :: currentCohort integer :: z real(r8) :: c_area @@ -2259,7 +2240,8 @@ function NumPotentialCanopyLayers(currentPatch,site_spread,include_substory) res currentCohort => currentPatch%tallest do while (associated(currentCohort)) if(currentCohort%canopy_layer == z) then - call carea_allom(currentCohort%dbh,currentCohort%n,site_spread,currentCohort%pft,c_area) + call carea_allom(currentCohort%dbh,currentCohort%n,site_spread,currentCohort%pft, & + currentCohort%crowndamage, c_area) arealayer = arealayer + c_area end if currentCohort => currentCohort%shorter @@ -2270,7 +2252,9 @@ function NumPotentialCanopyLayers(currentPatch,site_spread,include_substory) res if(arealayer > currentPatch%area)then z = z + 1 if(hlm_use_sp.eq.itrue)then - write(fates_log(),*) 'SPmode, canopy_layer full:',arealayer,currentPatch%area + if(debug)then + write(fates_log(),*) 'SPmode, canopy_layer full:',arealayer,currentPatch%area + end if end if endif diff --git a/biogeochem/EDCohortDynamicsMod.F90 b/biogeochem/EDCohortDynamicsMod.F90 index 4318ee469f..12385a8f9d 100644 --- a/biogeochem/EDCohortDynamicsMod.F90 +++ b/biogeochem/EDCohortDynamicsMod.F90 @@ -1,9 +1,10 @@ -module EDCohortDynamicsMod +Module EDCohortDynamicsMod ! - ! !DESCRIPTION: - ! Cohort stuctures in ED. + ! DESCRIPTION: + ! Cohort stuctures in FATES ! - ! !USES: + + ! USES: use FatesGlobals , only : endrun => fates_endrun use FatesGlobals , only : fates_log use FatesInterfaceTypesMod , only : hlm_freq_day @@ -11,6 +12,7 @@ module EDCohortDynamicsMod use FatesInterfaceTypesMod , only : hlm_use_planthydro use FatesInterfaceTypesMod , only : hlm_use_sp use FatesInterfaceTypesMod , only : hlm_use_cohort_age_tracking + use FatesInterfaceTypesMod , only : hlm_use_tree_damage use FatesInterfaceTypesMod , only : hlm_is_restart use FatesConstantsMod , only : r8 => fates_r8 use FatesConstantsMod , only : fates_unset_int @@ -18,7 +20,6 @@ module EDCohortDynamicsMod use FatesConstantsMod , only : fates_unset_r8 use FatesConstantsMod , only : nearzero use FatesConstantsMod , only : calloc_abs_error - use FatesRunningMeanMod , only : ema_lpa use FatesInterfaceTypesMod , only : hlm_days_per_year use FatesInterfaceTypesMod , only : nleafage use SFParamsMod , only : SF_val_CWD_frac @@ -26,26 +27,34 @@ module EDCohortDynamicsMod use EDPftvarcon , only : GetDecompyFrac use PRTParametersMod , only : prt_params use FatesParameterDerivedMod, only : param_derived - use EDTypesMod , only : ed_site_type, ed_patch_type, ed_cohort_type - use EDTypesMod , only : nclmax + use EDTypesMod , only : ed_site_type + use FatesPatchMod, only : fates_patch_type + use FatesCohortMod , only : fates_cohort_type + use EDParamsMod , only : nclmax use PRTGenericMod , only : element_list + use PRTGenericMod , only : StorageNutrientTarget use FatesLitterMod , only : ncwd use FatesLitterMod , only : ndcmpy use FatesLitterMod , only : litter_type - use EDTypesMod , only : maxCohortsPerPatch + use FatesLitterMod , only : adjust_SF_CWD_frac + use EDParamsMod , only : max_cohort_per_patch use EDTypesMod , only : AREA use EDTypesMod , only : min_npm2, min_nppatch use EDTypesMod , only : min_n_safemath - use EDTypesMod , only : nlevleaf + use EDParamsMod , only : nlevleaf use PRTGenericMod , only : max_nleafage - use EDTypesMod , only : ican_upper + use FatesConstantsMod , only : ican_upper use EDTypesMod , only : site_fluxdiags_type - use PRTGenericMod , only : num_elements + use PRTGenericMod , only : num_elements + use FatesConstantsMod , only : leaves_on + use FatesConstantsMod , only : leaves_off + use FatesConstantsMod , only : leaves_shedding + use FatesConstantsMod , only : ihard_stress_decid + use FatesConstantsMod , only : isemi_stress_decid use EDParamsMod , only : ED_val_cohort_age_fusion_tol use FatesInterfaceTypesMod , only : hlm_use_planthydro use FatesInterfaceTypesMod , only : hlm_parteh_mode use FatesPlantHydraulicsMod, only : FuseCohortHydraulics - use FatesPlantHydraulicsMod, only : CopyCohortHydraulics use FatesPlantHydraulicsMod, only : UpdateSizeDepPlantHydProps use FatesPlantHydraulicsMod, only : InitPlantHydStates use FatesPlantHydraulicsMod, only : InitHydrCohort @@ -66,13 +75,13 @@ module EDCohortDynamicsMod use FatesAllometryMod , only : bdead_allom use FatesAllometryMod , only : h_allom use FatesAllometryMod , only : carea_allom + use FatesAllometryMod , only : bstore_allom use FatesAllometryMod , only : ForceDBH use FatesAllometryMod , only : tree_lai, tree_sai 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 : all_carbon_elements use PRTGenericMod, only : carbon12_element use PRTGenericMod, only : nitrogen_element use PRTGenericMod, only : phosphorus_element @@ -83,51 +92,56 @@ module EDCohortDynamicsMod use PRTGenericMod, only : repro_organ use PRTGenericMod, only : struct_organ use PRTGenericMod, only : SetState - use PRTAllometricCarbonMod, only : callom_prt_vartypes use PRTAllometricCarbonMod, only : ac_bc_inout_id_netdc use PRTAllometricCarbonMod, only : ac_bc_in_id_pft use PRTAllometricCarbonMod, only : ac_bc_in_id_ctrim use PRTAllometricCarbonMod, only : ac_bc_inout_id_dbh use PRTAllometricCarbonMod, only : ac_bc_in_id_lstat + use PRTAllometricCarbonMod, only : ac_bc_in_id_cdamage + use PRTAllometricCarbonMod, only : ac_bc_in_id_efleaf + use PRTAllometricCarbonMod, only : ac_bc_in_id_effnrt + use PRTAllometricCarbonMod, only : ac_bc_in_id_efstem use PRTAllometricCNPMod, only : cnp_allom_prt_vartypes use PRTAllometricCNPMod, only : acnp_bc_in_id_pft, acnp_bc_in_id_ctrim use PRTAllometricCNPMod, only : acnp_bc_in_id_lstat, acnp_bc_inout_id_dbh - use PRTAllometricCNPMod, only : acnp_bc_inout_id_rmaint_def, acnp_bc_in_id_netdc - use PRTAllometricCNPMod, only : acnp_bc_in_id_netdnh4, acnp_bc_in_id_netdno3, acnp_bc_in_id_netdp + use PRTAllometricCNPMod, only : acnp_bc_in_id_efleaf + use PRTAllometricCNPMod, only : acnp_bc_in_id_effnrt + use PRTAllometricCNPMod, only : acnp_bc_in_id_efstem + use PRTAllometricCNPMod, only : acnp_bc_inout_id_l2fr + use PRTAllometricCNPMod, only : acnp_bc_inout_id_cx_int + use PRTAllometricCNPMod, only : acnp_bc_inout_id_cx0 + use PRTAllometricCNPMod, only : acnp_bc_inout_id_emadcxdt + use PRTAllometricCNPMod, only : acnp_bc_in_id_nc_repro + use PRTAllometricCNPMod, only : acnp_bc_in_id_pc_repro + use PRTAllometricCNPMod, only : acnp_bc_inout_id_resp_excess, acnp_bc_in_id_netdc + use PRTAllometricCNPMod, only : acnp_bc_inout_id_netdn, acnp_bc_inout_id_netdp use PRTAllometricCNPMod, only : acnp_bc_out_id_cefflux, acnp_bc_out_id_nefflux - use PRTAllometricCNPMod, only : acnp_bc_out_id_pefflux - use PRTAllometricCNPMod, only : acnp_bc_out_id_nneed - use PRTAllometricCNPMod, only : acnp_bc_out_id_pneed + use PRTAllometricCNPMod, only : acnp_bc_out_id_pefflux, acnp_bc_out_id_limiter + use PRTAllometricCNPMod, only : acnp_bc_in_id_cdamage + use DamageMainMod, only : undamaged_class + use shr_infnan_mod, only : nan => shr_infnan_nan, assignment(=) + use shr_log_mod, only : errMsg => shr_log_errMsg - use shr_infnan_mod, only : nan => shr_infnan_nan, assignment(=) - - ! CIME globals - use shr_log_mod , only : errMsg => shr_log_errMsg ! implicit none private ! public :: create_cohort - public :: zero_cohort - public :: nan_cohort public :: terminate_cohorts public :: terminate_cohort public :: fuse_cohorts public :: insert_cohort public :: sort_cohorts - public :: copy_cohort public :: count_cohorts public :: InitPRTObject - public :: InitPRTBoundaryConditions public :: SendCohortToLitter - public :: UpdateCohortBioPhysRates - public :: DeallocateCohort public :: EvaluateAndCorrectDBH - + public :: DamageRecovery + logical, parameter :: debug = .false. ! local debug flag - + character(len=*), parameter, private :: sourcefile = & __FILE__ @@ -143,305 +157,138 @@ module EDCohortDynamicsMod contains !-------------------------------------------------------------------------------------! +subroutine create_cohort(currentSite, patchptr, pft, nn, height, coage, dbh, & + prt, elongf_leaf, elongf_fnrt, elongf_stem, status, recruitstatus, ctrim, & + carea, clayer, crowndamage, spread, bc_in) + +! +! DESCRIPTION: +! create new cohort +! There are 4 places this is called +! 1) Initializing new cohorts at the beginning of a cold-start simulation +! 2) Initializing new recruits during dynamics +! 3) Initializing new cohorts at the beginning of a inventory read +! 4) Initializing new cohorts during restart +! +! It is assumed that in the first 3, this is called with a reasonable amount of starter information. +! + +! ARGUMENTS: +type(ed_site_type), intent(inout), target :: currentSite ! site object +type(fates_patch_type), intent(inout), pointer :: patchptr ! pointer to patch object +integer, intent(in) :: pft ! cohort Plant Functional Type +integer, intent(in) :: crowndamage ! cohort damage class +integer, intent(in) :: clayer ! canopy status of cohort [1=canopy; 2=understorey] +integer, intent(in) :: status ! growth status of plant [1=leaves off; 2=leaves on] +integer, intent(in) :: recruitstatus ! recruit status of plant [1 = recruitment , 0 = other] +real(r8), intent(in) :: nn ! number of individuals in cohort [/m2] +real(r8), intent(in) :: height ! cohort height [m] +real(r8), intent(in) :: coage ! cohort age [m] +real(r8), intent(in) :: dbh ! cohort diameter at breast height [cm] +real(r8), intent(in) :: elongf_leaf ! leaf elongation factor [fraction] - 0: fully abscissed; 1: fully flushed +real(r8), intent(in) :: elongf_fnrt ! fine-root "elongation factor" [fraction] +real(r8), intent(in) :: elongf_stem ! stem "elongation factor" [fraction] +class(prt_vartypes), intent(inout), pointer :: prt ! allocated PARTEH object +real(r8), intent(in) :: ctrim ! fraction of the maximum leaf biomass we are targeting +real(r8), intent(in) :: spread ! how spread crowns are in horizontal space +real(r8), intent(in) :: carea ! area of cohort - ONLY USED IN SP MODE [m2] +type(bc_in_type), intent(in) :: bc_in ! external boundary conditions + +! LOCAL VARIABLES: +type(fates_cohort_type), pointer :: newCohort ! pointer to New Cohort structure. +type(fates_cohort_type), pointer :: storesmallcohort +type(fates_cohort_type), pointer :: storebigcohort +real(r8) :: rmean_temp ! running mean temperature +integer :: tnull, snull ! are the tallest and shortest cohorts allocate +integer :: nlevrhiz ! number of rhizosphere layers + +!---------------------------------------------------------------------- + +! create new cohort +allocate(newCohort) +call newCohort%Create(prt, pft, nn, height, coage, dbh, status, ctrim, carea, & + clayer, crowndamage, spread, patchptr%canopy_layer_tlai, elongf_leaf, elongf_fnrt, & + elongf_stem) + + +! Put cohort at the right place in the linked list +storebigcohort => patchptr%tallest +storesmallcohort => patchptr%shortest + +if (associated(patchptr%tallest)) then + tnull = 0 +else + tnull = 1 + patchptr%tallest => newCohort +endif + +if (associated(patchptr%shortest)) then + snull = 0 +else + snull = 1 + patchptr%shortest => newCohort +endif + +! Allocate running mean functions + +! (Keeping as an example) +!! allocate(newCohort%tveg_lpa) +!! call newCohort%tveg_lpa%InitRMean(ema_lpa,init_value=patchptr%tveg_lpa%GetMean()) + +if (hlm_use_planthydro .eq. itrue) then + + nlevrhiz = currentSite%si_hydr%nlevrhiz + + ! This allocates array spaces + call InitHydrCohort(currentSite, newCohort) + + ! zero out the water balance error + newCohort%co_hydr%errh2o = 0._r8 + + ! This calculates node heights + call UpdatePlantHydrNodes(newCohort, newCohort%pft, & + newCohort%height,currentSite%si_hydr) + + ! This calculates volumes and lengths + call UpdatePlantHydrLenVol(newCohort,currentSite%si_hydr) + + ! This updates the Kmax's of the plant's compartments + call UpdatePlantKmax(newCohort%co_hydr,newCohort,currentSite%si_hydr) + + ! Since this is a newly initialized plant, we set the previous compartment-size + ! equal to the ones we just calculated. + call SavePreviousCompartmentVolumes(newCohort%co_hydr) + + ! This comes up with starter suctions and then water contents + ! based on the soil values + call InitPlantHydStates(currentSite,newCohort) + + if(recruitstatus==1)then + + newCohort%co_hydr%is_newly_recruited = .true. + + ! If plant hydraulics is active, we must constrain the + ! number density of the new recruits based on the moisture + ! available to be subsumed in the new plant tissues. + ! So we go through the process of pre-initializing the hydraulic + ! states in the temporary cohort, to calculate this new number density + rmean_temp = patchptr%tveg24%GetMean() + call ConstrainRecruitNumber(currentSite, newCohort, patchptr, & + bc_in, rmean_temp) + endif +endif - subroutine create_cohort(currentSite, patchptr, pft, nn, hite, coage, dbh, & - prt, laimemory, sapwmemory, structmemory, & - status, recruitstatus,ctrim, carea, clayer, spread, bc_in) - ! - ! !DESCRIPTION: - ! create new cohort - ! There are 4 places this is called - ! 1) Initializing new cohorts at the beginning of a cold-start simulation - ! 2) Initializing new recruits during dynamics - ! 3) Initializing new cohorts at the beginning of a inventory read - ! 4) Initializing new cohorts during restart - ! - ! It is assumed that in the first 3, this is called with a reasonable amount of starter information. - ! - ! !USES: - ! - ! !ARGUMENTS - - type(ed_site_type), intent(inout), target :: currentSite - type(ed_patch_type), intent(inout), pointer :: patchptr - - integer, intent(in) :: pft ! Cohort Plant Functional Type - integer, intent(in) :: clayer ! canopy status of cohort - ! (1 = canopy, 2 = understorey, etc.) - integer, intent(in) :: status ! growth status of plant - ! (2 = leaves on , 1 = leaves off) - integer, intent(in) :: recruitstatus ! recruit status of plant - ! (1 = recruitment , 0 = other) - real(r8), intent(in) :: nn ! number of individuals in cohort - ! per 'area' (10000m2 default) - real(r8), intent(in) :: hite ! height: meters - real(r8), intent(in) :: coage ! cohort age in years - real(r8), intent(in) :: dbh ! dbh: cm - class(prt_vartypes),target :: prt ! The allocated PARTEH - ! object - real(r8), intent(in) :: laimemory ! target leaf biomass- set from - ! previous year: kGC per indiv - real(r8), intent(in) :: sapwmemory ! target sapwood biomass- set from - ! previous year: kGC per indiv - real(r8), intent(in) :: structmemory ! target structural biomass- set from - ! previous year: kGC per indiv - real(r8), intent(in) :: ctrim ! What is the fraction of the maximum - ! leaf biomass that we are targeting? - real(r8), intent(in) :: spread ! The community assembly effects how - ! spread crowns are in horizontal space - real(r8), intent(in) :: carea ! area of cohort ONLY USED IN SP MODE. - type(bc_in_type), intent(in) :: bc_in ! External boundary conditions - - - ! !LOCAL VARIABLES: - type(ed_cohort_type), pointer :: new_cohort ! Pointer to New Cohort structure. - type(ed_cohort_type), pointer :: storesmallcohort - type(ed_cohort_type), pointer :: storebigcohort - integer :: iage ! loop counter for leaf age classes - real(r8) :: leaf_c ! total leaf carbon - integer :: tnull,snull ! are the tallest and shortest cohorts allocate - integer :: nlevrhiz ! number of rhizosphere layers - - !---------------------------------------------------------------------- - - allocate(new_cohort) - - call nan_cohort(new_cohort) ! Make everything in the cohort not-a-number - call zero_cohort(new_cohort) ! Zero things that need to be zeroed. - - ! Point to the PARTEH object - new_cohort%prt => prt - - ! The PARTEH cohort object should be allocated and already - ! initialized in this routine. - call new_cohort%prt%CheckInitialConditions() - - - !**********************/ - ! Define cohort state variable - !**********************/ - - new_cohort%indexnumber = fates_unset_int ! Cohort indexing was not thread-safe, setting - ! bogus value for the time being (RGK-012017) - - new_cohort%patchptr => patchptr - - new_cohort%pft = pft - new_cohort%status_coh = status - new_cohort%n = nn - new_cohort%hite = hite - new_cohort%dbh = dbh - new_cohort%coage = coage - new_cohort%canopy_trim = ctrim - new_cohort%canopy_layer = clayer - new_cohort%canopy_layer_yesterday = real(clayer, r8) - new_cohort%laimemory = laimemory - new_cohort%sapwmemory = sapwmemory - new_cohort%structmemory = structmemory - - ! This sets things like vcmax25top, that depend on the - ! leaf age fractions (which are defined by PARTEH) - call UpdateCohortBioPhysRates(new_cohort) - - call sizetype_class_index(new_cohort%dbh, new_cohort%pft, & - new_cohort%size_class,new_cohort%size_by_pft_class) - - ! If cohort age trackign is off we call this here once - ! just so everythin is in the first bin - - ! this makes it easier to copy and terminate cohorts later - ! we don't need to update this ever if cohort age tracking is off - call coagetype_class_index(new_cohort%coage, new_cohort%pft, & - new_cohort%coage_class,new_cohort%coage_by_pft_class) - - ! This routine may be called during restarts, and at this point in the call sequence - ! the actual cohort data is unknown, as this is really only used for allocation - ! In these cases, testing if things like biomass are reasonable is pre-mature - ! However, in this part of the code, we will pass in nominal values for size, number and type - - if (new_cohort%dbh <= 0._r8 .or. new_cohort%n == 0._r8 .or. new_cohort%pft == 0 ) then - write(fates_log(),*) 'ED: something is zero in create_cohort', & - new_cohort%dbh,new_cohort%n, & - new_cohort%pft - call endrun(msg=errMsg(sourcefile, __LINE__)) - endif - - ! Assign canopy extent and depth - if(hlm_use_sp.eq.ifalse)then - call carea_allom(new_cohort%dbh,new_cohort%n,spread,new_cohort%pft,new_cohort%c_area) - else - new_cohort%c_area = carea ! set this from previously precision-controlled value in SP mode - endif - ! Query PARTEH for the leaf carbon [kg] - leaf_c = new_cohort%prt%GetState(leaf_organ,carbon12_element) - - - new_cohort%treelai = tree_lai(leaf_c, new_cohort%pft, new_cohort%c_area, & - new_cohort%n, new_cohort%canopy_layer, & - patchptr%canopy_layer_tlai,new_cohort%vcmax25top ) - - if(hlm_use_sp.eq.ifalse)then - new_cohort%treesai = tree_sai(new_cohort%pft, new_cohort%dbh, new_cohort%canopy_trim, & - new_cohort%c_area, new_cohort%n, new_cohort%canopy_layer, & - patchptr%canopy_layer_tlai, new_cohort%treelai,new_cohort%vcmax25top,2 ) - end if - - new_cohort%lai = new_cohort%treelai * new_cohort%c_area/patchptr%area - - - ! Put cohort at the right place in the linked list - storebigcohort => patchptr%tallest - storesmallcohort => patchptr%shortest - - if (associated(patchptr%tallest)) then - tnull = 0 - else - tnull = 1 - patchptr%tallest => new_cohort - endif - - if (associated(patchptr%shortest)) then - snull = 0 - else - snull = 1 - patchptr%shortest => new_cohort - endif - - call InitPRTBoundaryConditions(new_cohort) - - - ! Allocate running mean functions - - ! (Keeping as an example) - !! allocate(new_cohort%tveg_lpa) - !! call new_cohort%tveg_lpa%InitRMean(ema_lpa,init_value=patchptr%tveg_lpa%GetMean()) - - - ! Recuits do not have mortality rates, nor have they moved any - ! carbon when they are created. They will bias our statistics - ! until they have experienced a full day. We need a newly recruited flag. - ! This flag will be set to false after it has experienced - ! growth, disturbance and mortality. - new_cohort%isnew = .true. - - if( hlm_use_planthydro.eq.itrue ) then - - nlevrhiz = currentSite%si_hydr%nlevrhiz - - ! This allocates array spaces - call InitHydrCohort(currentSite,new_cohort) - - ! This calculates node heights - call UpdatePlantHydrNodes(new_cohort,new_cohort%pft, & - new_cohort%hite,currentSite%si_hydr) - - ! This calculates volumes and lengths - call UpdatePlantHydrLenVol(new_cohort,currentSite%si_hydr) - - ! This updates the Kmax's of the plant's compartments - call UpdatePlantKmax(new_cohort%co_hydr,new_cohort,currentSite%si_hydr) - - ! Since this is a newly initialized plant, we set the previous compartment-size - ! equal to the ones we just calculated. - call SavePreviousCompartmentVolumes(new_cohort%co_hydr) - - ! This comes up with starter suctions and then water contents - ! based on the soil values - call InitPlantHydStates(currentSite,new_cohort) - - if(recruitstatus==1)then - - new_cohort%co_hydr%is_newly_recruited = .true. - - ! If plant hydraulics is active, we must constrain the - ! number density of the new recruits based on the moisture - ! available to be subsumed in the new plant tissues. - ! So we go through the process of pre-initializing the hydraulic - ! states in the temporary cohort, to calculate this new number density - - call ConstrainRecruitNumber(currentSite,new_cohort, bc_in) - - endif - - endif - - call insert_cohort(new_cohort, patchptr%tallest, patchptr%shortest, tnull, snull, & - storebigcohort, storesmallcohort) - - patchptr%tallest => storebigcohort - patchptr%shortest => storesmallcohort - - end subroutine create_cohort - - ! ------------------------------------------------------------------------------------- - - subroutine InitPRTBoundaryConditions(new_cohort) - - ! Set the boundary conditions that flow in an out of the PARTEH - ! allocation hypotheses. Each of these calls to "RegsterBC" are simply - ! setting pointers. - ! For instance, if the hypothesis wants to know what - ! the DBH of the plant is, then we pass in the dbh as an argument (new_cohort%dbh), - ! and also tell it which boundary condition we are talking about (which is - ! defined by an integer index (ac_bc_inout_id_dbh) - ! - ! Again, elaborated Example: - ! "ac_bc_inout_id_dbh" is the unique integer that defines the object index - ! for the allometric carbon "ac" boundary condition "bc" for DBH "dbh" - ! that is classified as input and output "inout". - ! See PRTAllometricCarbonMod.F90 to track its usage. - ! bc_rval is used as the optional argument identifyer to specify a real - ! value boundary condition. - ! bc_ival is used as the optional argument identifyer to specify an integer - ! value boundary condition. - - type(ed_cohort_type), intent(inout), target :: new_cohort - - - select case(hlm_parteh_mode) - case (prt_carbon_allom_hyp) - - ! Register boundary conditions for the Carbon Only Allometric Hypothesis - - call new_cohort%prt%RegisterBCInOut(ac_bc_inout_id_dbh,bc_rval = new_cohort%dbh) - call new_cohort%prt%RegisterBCInOut(ac_bc_inout_id_netdc,bc_rval = new_cohort%npp_acc) - call new_cohort%prt%RegisterBCIn(ac_bc_in_id_pft,bc_ival = new_cohort%pft) - call new_cohort%prt%RegisterBCIn(ac_bc_in_id_ctrim,bc_rval = new_cohort%canopy_trim) - call new_cohort%prt%RegisterBCIn(ac_bc_in_id_lstat,bc_ival = new_cohort%status_coh) - - case (prt_cnp_flex_allom_hyp) - - call new_cohort%prt%RegisterBCIn(acnp_bc_in_id_pft,bc_ival = new_cohort%pft) - call new_cohort%prt%RegisterBCIn(acnp_bc_in_id_ctrim,bc_rval = new_cohort%canopy_trim) - call new_cohort%prt%RegisterBCIn(acnp_bc_in_id_lstat,bc_ival = new_cohort%status_coh) - call new_cohort%prt%RegisterBCIn(acnp_bc_in_id_netdc, bc_rval = new_cohort%npp_acc) - call new_cohort%prt%RegisterBCIn(acnp_bc_in_id_netdnh4, bc_rval = new_cohort%daily_nh4_uptake) - call new_cohort%prt%RegisterBCIn(acnp_bc_in_id_netdno3, bc_rval = new_cohort%daily_no3_uptake) - call new_cohort%prt%RegisterBCIn(acnp_bc_in_id_netdp, bc_rval = new_cohort%daily_p_uptake) - - call new_cohort%prt%RegisterBCInOut(acnp_bc_inout_id_dbh,bc_rval = new_cohort%dbh) - call new_cohort%prt%RegisterBCInOut(acnp_bc_inout_id_rmaint_def,bc_rval = new_cohort%resp_m_def) - - call new_cohort%prt%RegisterBCOut(acnp_bc_out_id_cefflux, bc_rval = new_cohort%daily_c_efflux) - call new_cohort%prt%RegisterBCOut(acnp_bc_out_id_nefflux, bc_rval = new_cohort%daily_n_efflux) - call new_cohort%prt%RegisterBCOut(acnp_bc_out_id_pefflux, bc_rval = new_cohort%daily_p_efflux) - call new_cohort%prt%RegisterBCOut(acnp_bc_out_id_nneed, bc_rval = new_cohort%daily_n_need) - call new_cohort%prt%RegisterBCOut(acnp_bc_out_id_pneed, bc_rval = new_cohort%daily_p_need) - - - case DEFAULT - - write(fates_log(),*) 'You specified an unknown PRT module' - write(fates_log(),*) 'Aborting' - call endrun(msg=errMsg(sourcefile, __LINE__)) - - end select +call insert_cohort(patchptr, newCohort, patchptr%tallest, patchptr%shortest, tnull, snull, & + storebigcohort, storesmallcohort) +patchptr%tallest => storebigcohort +patchptr%shortest => storesmallcohort - end subroutine InitPRTBoundaryConditions +end subroutine create_cohort - ! ------------------------------------------------------------------------------------! +! ------------------------------------------------------------------------------------! subroutine InitPRTObject(prt) @@ -497,233 +344,20 @@ end subroutine InitPRTObject !-------------------------------------------------------------------------------------! - subroutine nan_cohort(cc_p) - ! - ! !DESCRIPTION: - ! Make all the cohort variables NaN so they aren't used before defined. - ! - ! !USES: - - use FatesConstantsMod, only : fates_unset_int - - ! - ! !ARGUMENTS - type (ed_cohort_type), intent(inout), target :: cc_p - ! - ! !LOCAL VARIABLES: - type (ed_cohort_type) , pointer :: currentCohort - !---------------------------------------------------------------------- - - currentCohort => cc_p - - currentCohort%taller => null() ! pointer to next tallest cohort - currentCohort%shorter => null() ! pointer to next shorter cohort - currentCohort%patchptr => null() ! pointer to patch that cohort is in - - nullify(currentCohort%taller) - nullify(currentCohort%shorter) - nullify(currentCohort%patchptr) - - ! VEGETATION STRUCTURE - currentCohort%pft = fates_unset_int ! pft number - currentCohort%indexnumber = fates_unset_int ! unique number for each cohort. (within clump?) - currentCohort%canopy_layer = fates_unset_int ! canopy status of cohort (1 = canopy, 2 = understorey, etc.) - currentCohort%canopy_layer_yesterday = nan ! recent canopy status of cohort (1 = canopy, 2 = understorey, etc.) - currentCohort%NV = fates_unset_int ! Number of leaf layers: - - currentCohort%status_coh = fates_unset_int ! growth status of plant (2 = leaves on , 1 = leaves off) - currentCohort%size_class = fates_unset_int ! size class index - currentCohort%size_class_lasttimestep = fates_unset_int ! size class index - currentCohort%size_by_pft_class = fates_unset_int ! size by pft classification index - currentCohort%coage_class = fates_unset_int ! cohort age class index - currentCohort%coage_by_pft_class = fates_unset_int ! cohort age by pft class index - - currentCohort%n = nan ! number of individuals in cohort per 'area' (10000m2 default) - currentCohort%dbh = nan ! 'diameter at breast height' in cm - currentCohort%coage = nan ! age of the cohort in years - currentCohort%hite = nan ! height: meters - currentCohort%laimemory = nan ! target leaf biomass- set from previous year: kGC per indiv - currentCohort%sapwmemory = nan ! target sapwood biomass- set from previous year: kGC per indiv - currentCohort%structmemory = nan ! target structural biomass- set from previous year: kGC per indiv - currentCohort%lai = nan ! leaf area index of cohort m2/m2 - currentCohort%sai = nan ! stem area index of cohort m2/m2 - currentCohort%g_sb_laweight = nan ! Total leaf conductance of cohort (stomata+blayer) weighted by leaf-area [m/s]*[m2] - currentCohort%canopy_trim = nan ! What is the fraction of the maximum leaf biomass that we are targeting? :- - currentCohort%leaf_cost = nan ! How much does it cost to maintain leaves: kgC/m2/year-1 - currentCohort%excl_weight = nan ! How much of this cohort is demoted each year, as a proportion of all cohorts:- - currentCohort%prom_weight = nan ! How much of this cohort is promoted each year, as a proportion of all cohorts:- - currentCohort%c_area = nan ! areal extent of canopy (m2) - currentCohort%treelai = nan ! lai of tree (total leaf area (m2) / canopy area (m2) - currentCohort%treesai = nan ! stem area index of tree (total stem area (m2) / canopy area (m2) - currentCohort%seed_prod = nan - currentCohort%vcmax25top = nan - currentCohort%jmax25top = nan - currentCohort%tpu25top = nan - currentCohort%kp25top = nan - - ! CARBON FLUXES - currentCohort%gpp_acc_hold = nan ! GPP: kgC/indiv/year - currentCohort%gpp_tstep = nan ! GPP: kgC/indiv/timestep - currentCohort%gpp_acc = nan ! GPP: kgC/indiv/day - currentCohort%npp_acc_hold = nan ! NPP: kgC/indiv/year - currentCohort%npp_tstep = nan ! NPP: kGC/indiv/timestep - currentCohort%npp_acc = nan ! NPP: kgC/indiv/day - currentCohort%year_net_uptake(:) = nan ! Net uptake of individual leaf layers kgC/m2/year - currentCohort%ts_net_uptake(:) = nan ! Net uptake of individual leaf layers kgC/m2/s - currentCohort%resp_acc_hold = nan ! RESP: kgC/indiv/year - currentCohort%resp_tstep = nan ! RESP: kgC/indiv/timestep - currentCohort%resp_acc = nan ! RESP: kGC/cohort/day - - ! Fluxes from nutrient allocation - currentCohort%daily_nh4_uptake = nan - currentCohort%daily_no3_uptake = nan - currentCohort%daily_p_uptake = nan - currentCohort%daily_c_efflux = nan - currentCohort%daily_n_efflux = nan - currentCohort%daily_p_efflux = nan - currentCohort%daily_n_need = nan - currentCohort%daily_p_need = nan - currentCohort%daily_n_demand = nan - currentCohort%daily_p_demand = nan - - - currentCohort%c13disc_clm = nan ! C13 discrimination, per mil at indiv/timestep - currentCohort%c13disc_acc = nan ! C13 discrimination, per mil at indiv/timestep at indiv/daily at the end of a day - - !RESPIRATION - currentCohort%rdark = nan - currentCohort%resp_m = nan ! Maintenance respiration. kGC/cohort/year - currentCohort%resp_m_def = nan ! Maintenance respiration deficit kgC/plant - currentCohort%livestem_mr = nan ! Live stem maintenance respiration. kgC/indiv/s-1 - currentCohort%livecroot_mr = nan ! Coarse root maintenance respiration. kgC/indiv/s-1 - currentCohort%froot_mr = nan ! Fine root maintenance respiration. kgC/indiv/s-1 - currentCohort%resp_g_tstep = nan ! Growth respiration. kGC/indiv/timestep - - - ! ALLOCATION - currentCohort%dmort = nan ! proportional mortality rate. (year-1) - - ! logging - currentCohort%lmort_direct = nan - currentCohort%lmort_infra = nan - currentCohort%lmort_collateral = nan - currentCohort%l_degrad = nan - - currentCohort%c_area = nan ! areal extent of canopy (m2) - currentCohort%treelai = nan ! lai of tree (total leaf area (m2) / canopy area (m2) - currentCohort%treesai = nan ! stem area index of tree (total stem area (m2) / canopy area (m2) - - - ! VARIABLES NEEDED FOR INTEGRATION - currentCohort%dndt = nan ! time derivative of cohort size - currentCohort%dhdt = nan ! time derivative of height - currentCohort%ddbhdt = nan ! time derivative of dbh - - ! FIRE - currentCohort%fraction_crown_burned = nan ! proportion of crown affected by fire - currentCohort%cambial_mort = nan ! probability that trees dies due to cambial char P&R (1986) - currentCohort%crownfire_mort = nan ! probability of tree post-fire mortality due to crown scorch - currentCohort%fire_mort = nan ! post-fire mortality from cambial and crown damage assuming two are independent - - end subroutine nan_cohort - - !-------------------------------------------------------------------------------------! - - subroutine zero_cohort(cc_p) - ! - ! !DESCRIPTION: - ! Zero variables that need to be accounted for if - ! this cohort is altered before they are defined. - ! - ! !USES: - ! - ! !ARGUMENTS - type (ed_cohort_type), intent(inout), target :: cc_p - ! - ! !LOCAL VARIABLES: - type (ed_cohort_type) , pointer :: currentCohort - !---------------------------------------------------------------------- - - currentCohort => cc_p - - currentCohort%NV = 0 - currentCohort%status_coh = 0 - currentCohort%rdark = 0._r8 - currentCohort%resp_m = 0._r8 - currentCohort%resp_m_def = 0._r8 - currentCohort%resp_g_tstep = 0._r8 - currentCohort%livestem_mr = 0._r8 - currentCohort%livecroot_mr = 0._r8 - currentCohort%froot_mr = 0._r8 - currentCohort%fire_mort = 0._r8 - currentcohort%npp_acc = 0._r8 - currentcohort%gpp_acc = 0._r8 - currentcohort%resp_acc = 0._r8 - currentcohort%npp_tstep = 0._r8 - currentcohort%gpp_tstep = 0._r8 - currentcohort%resp_tstep = 0._r8 - currentcohort%resp_acc_hold = 0._r8 - - currentcohort%year_net_uptake(:) = 999._r8 ! this needs to be 999, or trimming of new cohorts will break. - currentcohort%ts_net_uptake(:) = 0._r8 - currentcohort%fraction_crown_burned = 0._r8 - currentCohort%size_class = 1 - currentCohort%coage_class = 1 - currentCohort%seed_prod = 0._r8 - currentCohort%size_class_lasttimestep = 0 - currentcohort%npp_acc_hold = 0._r8 - currentcohort%gpp_acc_hold = 0._r8 - currentcohort%dmort = 0._r8 - currentcohort%g_sb_laweight = 0._r8 - currentcohort%treesai = 0._r8 - currentCohort%lmort_direct = 0._r8 - currentCohort%lmort_infra = 0._r8 - currentCohort%lmort_collateral = 0._r8 - currentCohort%l_degrad = 0._r8 - currentCohort%leaf_cost = 0._r8 - currentcohort%excl_weight = 0._r8 - currentcohort%prom_weight = 0._r8 - currentcohort%crownfire_mort = 0._r8 - currentcohort%cambial_mort = 0._r8 - currentCohort%c13disc_clm = 0._r8 - currentCohort%c13disc_acc = 0._r8 - - ! Daily nutrient fluxes are INTEGRATED over the course of the - ! day. This variable MUST be zerod upon creation AND - ! after allocation. These variables exist in - ! carbon-only mode but are not used. - - currentCohort%daily_nh4_uptake = 0._r8 - currentCohort%daily_no3_uptake = 0._r8 - currentCohort%daily_p_uptake = 0._r8 - - currentCohort%daily_c_efflux = 0._r8 - currentCohort%daily_n_efflux = 0._r8 - currentCohort%daily_p_efflux = 0._r8 - - currentCohort%daily_n_need = 0._r8 - currentCohort%daily_p_need = 0._r8 - - ! Initialize these as negative - currentCohort%daily_p_demand = -9._r8 - currentCohort%daily_n_demand = -9._r8 - - - end subroutine zero_cohort - - !-------------------------------------------------------------------------------------! subroutine terminate_cohorts( currentSite, currentPatch, level , call_index, bc_in) ! ! !DESCRIPTION: ! terminates all cohorts when they get too small ! ! !USES: + ! ! !ARGUMENTS - type (ed_site_type) , intent(inout), target :: currentSite - type (ed_patch_type), intent(inout), target :: currentPatch - integer , intent(in) :: level - integer :: call_index - type(bc_in_type), intent(in) :: bc_in + type (ed_site_type) , intent(inout) :: currentSite + type (fates_patch_type), intent(inout) :: currentPatch + integer , intent(in) :: level + integer :: call_index + type(bc_in_type), intent(in) :: bc_in ! Important point regarding termination levels. Termination is typically ! called after fusion. We do this so that we can re-capture the biomass that would @@ -735,9 +369,9 @@ subroutine terminate_cohorts( currentSite, currentPatch, level , call_index, bc_ ! ! !LOCAL VARIABLES: - type (ed_cohort_type) , pointer :: currentCohort - type (ed_cohort_type) , pointer :: shorterCohort - type (ed_cohort_type) , pointer :: tallerCohort + type (fates_cohort_type) , pointer :: currentCohort + type (fates_cohort_type) , pointer :: shorterCohort + type (fates_cohort_type) , pointer :: tallerCohort real(r8) :: leaf_c ! leaf carbon [kg] real(r8) :: store_c ! storage carbon [kg] @@ -746,6 +380,8 @@ subroutine terminate_cohorts( currentSite, currentPatch, level , call_index, bc_ real(r8) :: repro_c ! reproductive carbon [kg] real(r8) :: struct_c ! structural carbon [kg] integer :: terminate ! do we terminate (itrue) or not (ifalse) + integer :: istat ! return status code + character(len=255) :: smsg !---------------------------------------------------------------------- currentCohort => currentPatch%shortest @@ -765,7 +401,7 @@ subroutine terminate_cohorts( currentSite, currentPatch, level , call_index, bc_ if (currentcohort%n < min_n_safemath .and. level == 1) then terminate = itrue if ( debug ) then - write(fates_log(),*) 'terminating cohorts 0',currentCohort%n/currentPatch%area,currentCohort%dbh,call_index + write(fates_log(),*) 'terminating cohorts 0',currentCohort%n/currentPatch%area,currentCohort%dbh,currentCohort%pft,call_index endif endif @@ -778,7 +414,7 @@ subroutine terminate_cohorts( currentSite, currentPatch, level , call_index, bc_ (currentCohort%dbh < 0.00001_r8 .and. store_c < 0._r8) ) then terminate = itrue if ( debug ) then - write(fates_log(),*) 'terminating cohorts 1',currentCohort%n/currentPatch%area,currentCohort%dbh,call_index + write(fates_log(),*) 'terminating cohorts 1',currentCohort%n/currentPatch%area,currentCohort%dbh,currentCohort%pft,call_index endif endif @@ -786,7 +422,7 @@ subroutine terminate_cohorts( currentSite, currentPatch, level , call_index, bc_ if (currentCohort%canopy_layer > nclmax ) then terminate = itrue if ( debug ) then - write(fates_log(),*) 'terminating cohorts 2', currentCohort%canopy_layer,call_index + write(fates_log(),*) 'terminating cohorts 2', currentCohort%canopy_layer,currentCohort%pft,call_index endif endif @@ -796,7 +432,7 @@ subroutine terminate_cohorts( currentSite, currentPatch, level , call_index, bc_ terminate = itrue if ( debug ) then write(fates_log(),*) 'terminating cohorts 3', & - sapw_c,leaf_c,fnrt_c,store_c,call_index + sapw_c,leaf_c,fnrt_c,store_c,currentCohort%pft,call_index endif endif @@ -805,7 +441,7 @@ subroutine terminate_cohorts( currentSite, currentPatch, level , call_index, bc_ terminate = itrue if ( debug ) then write(fates_log(),*) 'terminating cohorts 4', & - struct_c,sapw_c,leaf_c,fnrt_c,store_c,call_index + struct_c,sapw_c,leaf_c,fnrt_c,store_c,currentCohort%pft,call_index endif endif @@ -813,10 +449,14 @@ subroutine terminate_cohorts( currentSite, currentPatch, level , call_index, bc_ if (terminate == itrue) then call terminate_cohort(currentSite, currentPatch, currentCohort, bc_in) - deallocate(currentCohort) + deallocate(currentCohort, stat=istat, errmsg=smsg) + if (istat/=0) then + write(fates_log(),*) 'dealloc001: fail on terminate_cohorts:deallocate(currentCohort):'//trim(smsg) + call endrun(msg=errMsg(sourcefile, __LINE__)) + endif endif currentCohort => tallerCohort - enddo + enddo end subroutine terminate_cohorts @@ -831,13 +471,13 @@ subroutine terminate_cohort(currentSite, currentPatch, currentCohort, bc_in) ! ! !ARGUMENTS type (ed_site_type) , intent(inout), target :: currentSite - type (ed_patch_type) , intent(inout), target :: currentPatch - type (ed_cohort_type), intent(inout), target :: currentCohort + type (fates_patch_type) , intent(inout), target :: currentPatch + type (fates_cohort_type), intent(inout), target :: currentCohort type(bc_in_type), intent(in) :: bc_in ! !LOCAL VARIABLES: - type (ed_cohort_type) , pointer :: shorterCohort - type (ed_cohort_type) , pointer :: tallerCohort + type (fates_cohort_type) , pointer :: shorterCohort + type (fates_cohort_type) , pointer :: tallerCohort real(r8) :: leaf_c ! leaf carbon [kg] real(r8) :: store_c ! storage carbon [kg] @@ -848,6 +488,7 @@ subroutine terminate_cohort(currentSite, currentPatch, currentCohort, bc_in) integer :: terminate ! do we terminate (itrue) or not (ifalse) integer :: c ! counter for litter size class. integer :: levcan ! canopy level + !---------------------------------------------------------------------- leaf_c = currentCohort%prt%GetState(leaf_organ, carbon12_element) @@ -868,16 +509,22 @@ subroutine terminate_cohort(currentSite, currentPatch, currentCohort, bc_in) currentSite%term_nindivs_canopy(currentCohort%size_class,currentCohort%pft) = & currentSite%term_nindivs_canopy(currentCohort%size_class,currentCohort%pft) + currentCohort%n - currentSite%term_carbonflux_canopy = currentSite%term_carbonflux_canopy + & + currentSite%term_carbonflux_canopy(currentCohort%pft) = currentSite%term_carbonflux_canopy(currentCohort%pft) + & currentCohort%n * (struct_c+sapw_c+leaf_c+fnrt_c+store_c+repro_c) else currentSite%term_nindivs_ustory(currentCohort%size_class,currentCohort%pft) = & currentSite%term_nindivs_ustory(currentCohort%size_class,currentCohort%pft) + currentCohort%n - currentSite%term_carbonflux_ustory = currentSite%term_carbonflux_ustory + & + currentSite%term_carbonflux_ustory(currentCohort%pft) = currentSite%term_carbonflux_ustory(currentCohort%pft) + & currentCohort%n * (struct_c+sapw_c+leaf_c+fnrt_c+store_c+repro_c) end if + currentSite%term_abg_flux(currentCohort%size_class, currentCohort%pft) = & + currentSite%term_abg_flux(currentCohort%size_class, currentCohort%pft) + & + currentCohort%n * ( (struct_c+sapw_c+store_c) * prt_params%allom_agb_frac(currentCohort%pft) + & + leaf_c ) + + ! put the litter from the terminated cohorts ! straight into the fragmenting pools @@ -904,7 +551,7 @@ subroutine terminate_cohort(currentSite, currentPatch, currentCohort, bc_in) shorterCohort%taller => tallerCohort endif - call DeallocateCohort(currentCohort) + call currentCohort%FreeMemory() end subroutine terminate_cohort @@ -930,8 +577,8 @@ subroutine SendCohortToLitter(csite,cpatch,ccohort,nplant,bc_in) ! Arguments type (ed_site_type) , target :: csite - type (ed_patch_type) , target :: cpatch - type (ed_cohort_type) , target :: ccohort + type (fates_patch_type) , target :: cpatch + type (fates_cohort_type) , target :: ccohort real(r8) :: nplant ! Number (absolute) ! of plants to transfer type(bc_in_type), intent(in) :: bc_in @@ -950,9 +597,10 @@ subroutine SendCohortToLitter(csite,cpatch,ccohort,nplant,bc_in) integer :: el ! loop index for elements integer :: c ! loop index for CWD integer :: pft ! pft index of the cohort + integer :: crowndamage ! the crown damage class of the cohort integer :: sl ! loop index for soil layers integer :: dcmpy ! loop index for decomposability - + real(r8) :: SF_val_CWD_frac_adj(4) !Updated wood partitioning to CWD based on dbh !---------------------------------------------------------------------- pft = ccohort%pft @@ -964,39 +612,50 @@ subroutine SendCohortToLitter(csite,cpatch,ccohort,nplant,bc_in) do el=1,num_elements - leaf_m = ccohort%prt%GetState(leaf_organ, element_list(el)) store_m = ccohort%prt%GetState(store_organ, element_list(el)) - sapw_m = ccohort%prt%GetState(sapw_organ, element_list(el)) fnrt_m = ccohort%prt%GetState(fnrt_organ, element_list(el)) - struct_m = ccohort%prt%GetState(struct_organ, element_list(el)) repro_m = ccohort%prt%GetState(repro_organ, element_list(el)) + if (prt_params%woody(ccohort%pft) == itrue) then + leaf_m = ccohort%prt%GetState(leaf_organ, element_list(el)) + sapw_m = ccohort%prt%GetState(sapw_organ, element_list(el)) + struct_m = ccohort%prt%GetState(struct_organ, element_list(el)) + else + leaf_m = ccohort%prt%GetState(leaf_organ, element_list(el)) + & + ccohort%prt%GetState(sapw_organ, element_list(el)) + & + ccohort%prt%GetState(struct_organ, element_list(el)) + sapw_m = 0._r8 + struct_m = 0._r8 + endif litt => cpatch%litter(el) flux_diags => csite%flux_diags(el) + !adjust how wood is partitioned between the cwd classes based on cohort dbh + call adjust_SF_CWD_frac(ccohort%dbh,ncwd,SF_val_CWD_frac,SF_val_CWD_frac_adj) + do c=1,ncwd ! above ground CWD litt%ag_cwd(c) = litt%ag_cwd(c) + plant_dens * & - (struct_m+sapw_m) * SF_val_CWD_frac(c) * & + (struct_m+sapw_m) * SF_val_CWD_frac_adj(c) * & prt_params%allom_agb_frac(pft) ! below ground CWD do sl=1,csite%nlevsoil litt%bg_cwd(c,sl) = litt%bg_cwd(c,sl) + plant_dens * & - (struct_m+sapw_m) * SF_val_CWD_frac(c) * & + (struct_m+sapw_m) * SF_val_CWD_frac_adj(c) * & (1.0_r8 - prt_params%allom_agb_frac(pft)) * & csite%rootfrac_scr(sl) enddo ! above ground flux_diags%cwd_ag_input(c) = flux_diags%cwd_ag_input(c) + & - (struct_m+sapw_m) * SF_val_CWD_frac(c) * & + (struct_m+sapw_m) * SF_val_CWD_frac_adj(c) * & prt_params%allom_agb_frac(pft) * nplant ! below ground flux_diags%cwd_bg_input(c) = flux_diags%cwd_bg_input(c) + & - (struct_m + sapw_m) * SF_val_CWD_frac(c) * & + (struct_m + sapw_m) * SF_val_CWD_frac_adj(c) * & (1.0_r8 - prt_params%allom_agb_frac(pft)) * nplant enddo @@ -1028,38 +687,10 @@ subroutine SendCohortToLitter(csite,cpatch,ccohort,nplant,bc_in) return end subroutine SendCohortToLitter - !-------------------------------------------------------------------------------------- - subroutine DeallocateCohort(currentCohort) - - ! ---------------------------------------------------------------------------------- - ! This subroutine deallocates all dynamic memory and objects - ! inside the cohort structure. This DOES NOT deallocate - ! the cohort structure itself. - ! ---------------------------------------------------------------------------------- - - type(ed_cohort_type),intent(inout) :: currentCohort - - ! (Keeping as an example) - ! Remove the running mean structure - ! deallocate(currentCohort%tveg_lpa) - - ! At this point, nothing should be pointing to current Cohort - if (hlm_use_planthydro.eq.itrue) call DeallocateHydrCohort(currentCohort) - - ! Deallocate the cohort's PRT structures - call currentCohort%prt%DeallocatePRTVartypes() - - ! Deallocate the PRT object - deallocate(currentCohort%prt) - - return - end subroutine DeallocateCohort - - subroutine fuse_cohorts(currentSite, currentPatch, bc_in) ! @@ -1072,22 +703,22 @@ subroutine fuse_cohorts(currentSite, currentPatch, bc_in) use FatesInterfaceTypesMod , only : hlm_use_cohort_age_tracking use FatesConstantsMod , only : itrue use FatesConstantsMod, only : days_per_year - use EDTypesMod , only : maxCohortsPerPatch + ! ! !ARGUMENTS - type (ed_site_type), intent(inout), target :: currentSite - type (ed_patch_type), intent(inout), target :: currentPatch - type (bc_in_type), intent(in) :: bc_in + type (ed_site_type), intent(inout) :: currentSite + type (fates_patch_type), intent(inout), pointer :: currentPatch + type (bc_in_type), intent(in) :: bc_in ! ! !LOCAL VARIABLES: - type (ed_cohort_type) , pointer :: currentCohort - type (ed_cohort_type) , pointer :: nextc - type (ed_cohort_type) , pointer :: nextnextc + type (fates_cohort_type) , pointer :: currentCohort + type (fates_cohort_type) , pointer :: nextc + type (fates_cohort_type) , pointer :: nextnextc - type (ed_cohort_type) , pointer :: shorterCohort - type (ed_cohort_type) , pointer :: tallerCohort + type (fates_cohort_type) , pointer :: shorterCohort + type (fates_cohort_type) , pointer :: tallerCohort integer :: i integer :: fusion_took_place @@ -1103,14 +734,18 @@ subroutine fuse_cohorts(currentSite, currentPatch, bc_in) real(r8) :: dynamic_age_fusion_tolerance real(r8) :: dbh real(r8) :: leaf_c ! leaf carbon [kg] - + real(r8) :: target_storec ! Target storage C + integer :: largersc, smallersc, sc_i ! indices for tracking the growth flux caused by fusion real(r8) :: larger_n, smaller_n integer :: oldercacls, youngercacls, cacls_i ! indices for tracking the age flux caused by fusion real(r8) :: older_n, younger_n + real(r8) :: crown_reduction logical, parameter :: fuse_debug = .false. ! This debug is over-verbose ! and gets its own flag + integer :: istat ! return status code + character(len=255) :: smsg !---------------------------------------------------------------------- @@ -1133,7 +768,7 @@ subroutine fuse_cohorts(currentSite, currentPatch, bc_in) !---------------------------------------------------------------------! ! Keep doing this until nocohorts <= maxcohorts ! !---------------------------------------------------------------------! - + if (associated(currentPatch%shortest)) then do while(iterate == 1) @@ -1174,6 +809,9 @@ subroutine fuse_cohorts(currentSite, currentPatch, bc_in) if (currentCohort%pft == nextc%pft) then + ! check cohorts have same damage class before fusing + if (currentCohort%crowndamage == nextc%crowndamage) then + ! check cohorts in same c. layer. before fusing if (currentCohort%canopy_layer == nextc%canopy_layer) then @@ -1196,11 +834,11 @@ subroutine fuse_cohorts(currentSite, currentPatch, bc_in) write(fates_log(),*) 'Cohort I, Cohort II' write(fates_log(),*) 'n:',currentCohort%n,nextc%n write(fates_log(),*) 'isnew:',currentCohort%isnew,nextc%isnew - write(fates_log(),*) 'laimemory:',currentCohort%laimemory,nextc%laimemory - write(fates_log(),*) 'hite:',currentCohort%hite,nextc%hite + write(fates_log(),*) 'height:',currentCohort%height,nextc%height write(fates_log(),*) 'coage:',currentCohort%coage,nextc%coage write(fates_log(),*) 'dbh:',currentCohort%dbh,nextc%dbh write(fates_log(),*) 'pft:',currentCohort%pft,nextc%pft + write(fates_log(),*) 'crowndamage:',currentCohort%crowndamage,nextc%crowndamage write(fates_log(),*) 'canopy_trim:',currentCohort%canopy_trim,nextc%canopy_trim write(fates_log(),*) 'canopy_layer_yesterday:', & currentCohort%canopy_layer_yesterday,nextc%canopy_layer_yesterday @@ -1210,11 +848,9 @@ subroutine fuse_cohorts(currentSite, currentPatch, bc_in) end do end if - ! (Keeping as an example) - ! Running mean fuses based on number density fraction just - ! like other variables - !!call currentCohort%tveg_lpa%FuseRMean(nextc%tveg_lpa,currentCohort%n/newn) + + ! new cohort age is weighted mean of two cohorts currentCohort%coage = & (currentCohort%coage * (currentCohort%n/(currentCohort%n + nextc%n))) + & @@ -1232,16 +868,10 @@ subroutine fuse_cohorts(currentSite, currentPatch, bc_in) ! Leaf biophysical rates (use leaf mass weighting) ! ----------------------------------------------------------------- - call UpdateCohortBioPhysRates(currentCohort) - - currentCohort%laimemory = (currentCohort%n*currentCohort%laimemory & - + nextc%n*nextc%laimemory)/newn - - currentCohort%sapwmemory = (currentCohort%n*currentCohort%sapwmemory & - + nextc%n*nextc%sapwmemory)/newn - - currentCohort%structmemory = (currentCohort%n*currentCohort%structmemory & - + nextc%n*nextc%structmemory)/newn + call currentCohort%UpdateCohortBioPhysRates() + + currentCohort%l2fr = (currentCohort%n*currentCohort%l2fr & + + nextc%n*nextc%l2fr)/newn currentCohort%canopy_trim = (currentCohort%n*currentCohort%canopy_trim & + nextc%n*nextc%canopy_trim)/newn @@ -1283,10 +913,12 @@ subroutine fuse_cohorts(currentSite, currentPatch, bc_in) call carea_allom(currentCohort%dbh,currentCohort%n, & currentSite%spread,currentCohort%pft,& + currentCohort%crowndamage, & currentCohort%c_area,inverse=.false.) call carea_allom(nextc%dbh,nextc%n, & currentSite%spread,nextc%pft,& + nextc%crowndamage, & nextc%c_area,inverse=.false.) currentCohort%c_area = currentCohort%c_area + nextc%c_area @@ -1294,7 +926,7 @@ subroutine fuse_cohorts(currentSite, currentPatch, bc_in) ! dbh = currentCohort%dbh call carea_allom(dbh,newn,currentSite%spread,currentCohort%pft,& - currentCohort%c_area,inverse=.true.) + currentCohort%crowndamage,currentCohort%c_area,inverse=.true.) ! if (abs(dbh-fates_unset_r8) currentCohort%n) currentCohort%cnp_limiter = nextc%cnp_limiter + + currentCohort%cx_int = (currentCohort%n*currentCohort%cx_int + & + nextc%n*nextc%cx_int)/newn + currentCohort%ema_dcxdt = (currentCohort%n*currentCohort%ema_dcxdt + & + nextc%n*nextc%ema_dcxdt)/newn + currentCohort%cx0 = (currentCohort%n*currentCohort%cx0 + & + nextc%n*nextc%cx0)/newn + + ! These variables do not need to be rescaled because they + ! are written to history immediately after calculation + + currentCohort%daily_nh4_uptake = (currentCohort%n*currentCohort%daily_nh4_uptake + & + nextc%n*nextc%daily_nh4_uptake)/newn + currentCohort%daily_no3_uptake = (currentCohort%n*currentCohort%daily_no3_uptake + & + nextc%n*nextc%daily_no3_uptake)/newn + currentCohort%sym_nfix_daily = (currentCohort%n*currentCohort%sym_nfix_daily + & + nextc%n*nextc%sym_nfix_daily)/newn + currentCohort%daily_n_gain = (currentCohort%n*currentCohort%daily_n_gain + & + nextc%n*nextc%daily_n_gain)/newn + currentCohort%daily_p_gain = (currentCohort%n*currentCohort%daily_p_gain + & + nextc%n*nextc%daily_p_gain)/newn + currentCohort%daily_p_demand = (currentCohort%n*currentCohort%daily_p_demand + & + nextc%n*nextc%daily_p_demand)/newn + currentCohort%daily_n_demand = (currentCohort%n*currentCohort%daily_n_demand + & + nextc%n*nextc%daily_n_demand)/newn + currentCohort%daily_c_efflux = (currentCohort%n*currentCohort%daily_c_efflux + & + nextc%n*nextc%daily_c_efflux)/newn + currentCohort%daily_n_efflux = (currentCohort%n*currentCohort%daily_n_efflux + & + nextc%n*nextc%daily_n_efflux)/newn + currentCohort%daily_p_efflux = (currentCohort%n*currentCohort%daily_p_efflux + & + nextc%n*nextc%daily_p_efflux)/newn + end if + ! logging mortality, Yi Xu currentCohort%lmort_direct = (currentCohort%n*currentCohort%lmort_direct + & @@ -1529,26 +1163,22 @@ subroutine fuse_cohorts(currentSite, currentPatch, bc_in) endif ! At this point, nothing should be pointing to current Cohort - ! update hydraulics quantities that are functions of hite & biomasses + ! update hydraulics quantities that are functions of height & biomasses ! deallocate the hydro structure of nextc if (hlm_use_planthydro.eq.itrue) then - call carea_allom(currentCohort%dbh,currentCohort%n,currentSite%spread, & - currentCohort%pft,currentCohort%c_area) - leaf_c = currentCohort%prt%GetState(leaf_organ, carbon12_element) - currentCohort%treelai = tree_lai(leaf_c, & - currentCohort%pft, currentCohort%c_area, currentCohort%n, & - currentCohort%canopy_layer, currentPatch%canopy_layer_tlai, & - currentCohort%vcmax25top ) call UpdateSizeDepPlantHydProps(currentSite,currentCohort, bc_in) endif - call DeallocateCohort(nextc) - deallocate(nextc) - nullify(nextc) - + call nextc%FreeMemory() + deallocate(nextc, stat=istat, errmsg=smsg) + if (istat/=0) then + write(fates_log(),*) 'dealloc003: fail on deallocate(nextc):'//trim(smsg) + call endrun(msg=errMsg(sourcefile, __LINE__)) + endif endif ! if( currentCohort%isnew.eqv.nextc%isnew ) then endif !canopy layer + endif ! crowndamage endif !pft endif !index no. endif ! cohort age diff @@ -1583,14 +1213,13 @@ subroutine fuse_cohorts(currentSite, currentPatch, bc_in) if ( hlm_use_cohort_age_tracking .eq.itrue) then - if ( nocohorts > maxCohortsPerPatch ) then + if ( nocohorts > max_cohort_per_patch ) then iterate = 1 !---------------------------------------------------------------------! ! Making profile tolerance larger means that more fusion will happen ! !---------------------------------------------------------------------! dynamic_size_fusion_tolerance = dynamic_size_fusion_tolerance * 1.1_r8 dynamic_age_fusion_tolerance = dynamic_age_fusion_tolerance * 1.1_r8 - !write(fates_log(),*) 'maxcohorts exceeded',dynamic_fusion_tolerance else @@ -1599,13 +1228,12 @@ subroutine fuse_cohorts(currentSite, currentPatch, bc_in) else - if (nocohorts > maxCohortsPerPatch) then + if (nocohorts > max_cohort_per_patch) then iterate = 1 !---------------------------------------------------------------------! ! Making profile tolerance larger means that more fusion will happen ! !---------------------------------------------------------------------! dynamic_size_fusion_tolerance = dynamic_size_fusion_tolerance * 1.1_r8 - !write(fates_log(),*) 'maxcohorts exceeded',dynamic_fusion_tolerance else @@ -1645,13 +1273,13 @@ subroutine sort_cohorts(patchptr) ! sort cohorts into the correct order DO NOT CHANGE THIS IT WILL BREAK ! ============================================================================ - type(ed_patch_type) , intent(inout), target :: patchptr + type(fates_patch_type) , intent(inout), target :: patchptr - type(ed_patch_type) , pointer :: current_patch - type(ed_cohort_type), pointer :: current_c, next_c - type(ed_cohort_type), pointer :: shortestc, tallestc - type(ed_cohort_type), pointer :: storesmallcohort - type(ed_cohort_type), pointer :: storebigcohort + type(fates_patch_type) , pointer :: current_patch + type(fates_cohort_type), pointer :: current_c, next_c + type(fates_cohort_type), pointer :: shortestc, tallestc + type(fates_cohort_type), pointer :: storesmallcohort + type(fates_cohort_type), pointer :: storebigcohort integer :: snull,tnull current_patch => patchptr @@ -1679,7 +1307,8 @@ subroutine sort_cohorts(patchptr) shortestc => current_c endif - call insert_cohort(current_c, tallestc, shortestc, tnull, snull, storebigcohort, storesmallcohort) + call insert_cohort(current_patch, current_c, tallestc, shortestc, & + tnull, snull, storebigcohort, storesmallcohort) current_patch%tallest => storebigcohort current_patch%shortest => storesmallcohort @@ -1690,7 +1319,7 @@ subroutine sort_cohorts(patchptr) end subroutine sort_cohorts !-------------------------------------------------------------------------------------! - subroutine insert_cohort(pcc, ptall, pshort, tnull, snull, storebigcohort, storesmallcohort) + subroutine insert_cohort(currentPatch, pcc, ptall, pshort, tnull, snull, storebigcohort, storesmallcohort) ! ! !DESCRIPTION: ! Insert cohort into linked list @@ -1698,24 +1327,24 @@ subroutine insert_cohort(pcc, ptall, pshort, tnull, snull, storebigcohort, store ! !USES: ! ! !ARGUMENTS - type(ed_cohort_type) , intent(inout), target :: pcc - type(ed_cohort_type) , intent(inout), target :: ptall - type(ed_cohort_type) , intent(inout), target :: pshort + type(fates_patch_type), intent(inout), target :: currentPatch + type(fates_cohort_type) , intent(inout), pointer :: pcc + type(fates_cohort_type) , intent(inout), pointer :: ptall + type(fates_cohort_type) , intent(inout), pointer :: pshort integer , intent(in) :: tnull integer , intent(in) :: snull - type(ed_cohort_type) , intent(inout),pointer,optional :: storesmallcohort ! storage of the smallest cohort for insertion routine - type(ed_cohort_type) , intent(inout),pointer,optional :: storebigcohort ! storage of the largest cohort for insertion routine + type(fates_cohort_type) , intent(inout),pointer,optional :: storesmallcohort ! storage of the smallest cohort for insertion routine + type(fates_cohort_type) , intent(inout),pointer,optional :: storebigcohort ! storage of the largest cohort for insertion routine ! ! !LOCAL VARIABLES: - type(ed_patch_type), pointer :: currentPatch - type(ed_cohort_type), pointer :: current - type(ed_cohort_type), pointer :: tallptr, shortptr, icohort - type(ed_cohort_type), pointer :: ptallest, pshortest + !type(fates_patch_type), pointer :: currentPatch + type(fates_cohort_type), pointer :: current + type(fates_cohort_type), pointer :: tallptr, shortptr, icohort + type(fates_cohort_type), pointer :: ptallest, pshortest real(r8) :: tsp integer :: tallptrnull,exitloop !---------------------------------------------------------------------- - currentPatch => pcc%patchptr ptallest => ptall pshortest => pshort @@ -1729,7 +1358,7 @@ subroutine insert_cohort(pcc, ptall, pshort, tnull, snull, storebigcohort, store icohort => pcc ! assign address to icohort local name !place in the correct place in the linked list of heights !begin by finding cohort that is just taller than the new cohort - tsp = icohort%hite + tsp = icohort%height current => pshortest exitloop = 0 @@ -1737,7 +1366,7 @@ subroutine insert_cohort(pcc, ptall, pshort, tnull, snull, storebigcohort, store !taller than tree being considered and return its pointer if (associated(current)) then do while (associated(current).and.exitloop == 0) - if (current%hite < tsp) then + if (current%height < tsp) then current => current%taller else exitloop = 1 @@ -1764,7 +1393,6 @@ subroutine insert_cohort(pcc, ptall, pshort, tnull, snull, storebigcohort, store storebigcohort => icohort end if currentPatch%tallest => icohort - icohort%patchptr%tallest => icohort !new cohort is not tallest else !next shorter cohort to new cohort is the next shorter cohort @@ -1785,7 +1413,6 @@ subroutine insert_cohort(pcc, ptall, pshort, tnull, snull, storebigcohort, store storesmallcohort => icohort end if currentPatch%shortest => icohort - icohort%patchptr%shortest => icohort else !new cohort is not shortest and becomes next taller cohort !to the cohort just below it as defined in the previous block @@ -1802,164 +1429,7 @@ subroutine insert_cohort(pcc, ptall, pshort, tnull, snull, storebigcohort, store end subroutine insert_cohort !-------------------------------------------------------------------------------------! - subroutine copy_cohort( currentCohort,copyc ) - ! - ! !DESCRIPTION: - ! Copies all the variables in one cohort into another empty cohort - ! - ! !USES: - ! - ! !ARGUMENTS - type(ed_cohort_type), intent(inout) , target :: copyc ! New cohort argument. - type(ed_cohort_type), intent(in) , target :: currentCohort ! Old cohort argument. - ! - ! !LOCAL VARIABLES: - type(ed_cohort_type), pointer :: n,o ! New and old cohort pointers - !---------------------------------------------------------------------- - o => currentCohort - n => copyc - - n%indexnumber = fates_unset_int - - ! VEGETATION STRUCTURE - n%pft = o%pft - n%n = o%n - n%dbh = o%dbh - n%coage = o%coage - n%hite = o%hite - n%laimemory = o%laimemory - n%sapwmemory = o%sapwmemory - n%structmemory = o%structmemory - n%lai = o%lai - n%sai = o%sai - n%g_sb_laweight = o%g_sb_laweight - n%leaf_cost = o%leaf_cost - n%canopy_layer = o%canopy_layer - n%canopy_layer_yesterday = o%canopy_layer_yesterday - n%nv = o%nv - n%status_coh = o%status_coh - n%canopy_trim = o%canopy_trim - n%excl_weight = o%excl_weight - n%prom_weight = o%prom_weight - n%size_class = o%size_class - n%size_class_lasttimestep = o%size_class_lasttimestep - n%size_by_pft_class = o%size_by_pft_class - n%coage_class = o%coage_class - n%coage_by_pft_class = o%coage_by_pft_class - - ! This transfers the PRT objects over. - call n%prt%CopyPRTVartypes(o%prt) - - ! Leaf biophysical rates - n%vcmax25top = o%vcmax25top - n%jmax25top = o%jmax25top - n%tpu25top = o%tpu25top - n%kp25top = o%kp25top - - ! (Keeping as an example) - ! Copy over running means - ! call n%tveg_lpa%CopyFromDonor(o%tveg_lpa) - - ! CARBON FLUXES - n%gpp_acc_hold = o%gpp_acc_hold - n%gpp_acc = o%gpp_acc - n%gpp_tstep = o%gpp_tstep - - n%npp_acc_hold = o%npp_acc_hold - n%npp_tstep = o%npp_tstep - n%npp_acc = o%npp_acc - - if ( debug .and. .not.o%isnew ) write(fates_log(),*) 'EDcohortDyn Ia ',o%npp_acc - if ( debug .and. .not.o%isnew ) write(fates_log(),*) 'EDcohortDyn Ib ',o%resp_acc - - n%resp_tstep = o%resp_tstep - n%resp_acc = o%resp_acc - n%resp_acc_hold = o%resp_acc_hold - n%year_net_uptake = o%year_net_uptake - n%ts_net_uptake = o%ts_net_uptake - - n%daily_nh4_uptake = o%daily_nh4_uptake - n%daily_no3_uptake = o%daily_no3_uptake - n%daily_p_uptake = o%daily_p_uptake - n%daily_c_efflux = o%daily_c_efflux - n%daily_n_efflux = o%daily_n_efflux - n%daily_p_efflux = o%daily_p_efflux - n%daily_n_need = o%daily_n_need - n%daily_p_need = o%daily_p_need - n%daily_n_demand = o%daily_n_demand - n%daily_p_demand = o%daily_p_demand - - ! C13 discrimination - n%c13disc_clm = o%c13disc_clm - n%c13disc_acc = o%c13disc_acc - - !RESPIRATION - n%rdark = o%rdark - n%resp_m = o%resp_m - n%resp_m_def = o%resp_m_def - n%resp_g_tstep = o%resp_g_tstep - n%livestem_mr = o%livestem_mr - n%livecroot_mr = o%livecroot_mr - n%froot_mr = o%froot_mr - - ! ALLOCATION - n%dmort = o%dmort - n%seed_prod = o%seed_prod - - n%treelai = o%treelai - n%treesai = o%treesai - n%c_area = o%c_area - - ! Mortality diagnostics - n%cmort = o%cmort - n%bmort = o%bmort - n%hmort = o%hmort - n%smort = o%smort - n%asmort = o%asmort - n%frmort = o%frmort - - ! logging mortalities, Yi Xu - n%lmort_direct =o%lmort_direct - n%lmort_collateral =o%lmort_collateral - n%lmort_infra =o%lmort_infra - n%l_degrad =o%l_degrad - - ! Flags - n%isnew = o%isnew - - ! VARIABLES NEEDED FOR INTEGRATION - n%dndt = o%dndt - n%dhdt = o%dhdt - n%ddbhdt = o%ddbhdt - - ! FIRE - n%fraction_crown_burned = o%fraction_crown_burned - n%fire_mort = o%fire_mort - n%crownfire_mort = o%crownfire_mort - n%cambial_mort = o%cambial_mort - - ! Plant Hydraulics - - if( hlm_use_planthydro.eq.itrue ) then - call CopyCohortHydraulics(n,o) - endif - - ! indices for binning - n%size_class = o%size_class - n%size_class_lasttimestep = o%size_class_lasttimestep - n%size_by_pft_class = o%size_by_pft_class - n%coage_class = o%coage_class - n%coage_by_pft_class = o%coage_by_pft_class - - !Pointers - n%taller => NULL() ! pointer to next tallest cohort - n%shorter => NULL() ! pointer to next shorter cohort - n%patchptr => o%patchptr ! pointer to patch that cohort is in - - end subroutine copy_cohort - - !-------------------------------------------------------------------------------------! subroutine count_cohorts( currentPatch ) ! ! !DESCRIPTION: @@ -1967,10 +1437,10 @@ subroutine count_cohorts( currentPatch ) ! !USES: ! ! !ARGUMENTS - type(ed_patch_type), intent(inout), target :: currentPatch !new site + type(fates_patch_type), intent(inout), target :: currentPatch !new site ! ! !LOCAL VARIABLES: - type(ed_cohort_type), pointer :: currentCohort !new patch + type(fates_cohort_type), pointer :: currentCohort !new patch integer :: backcount !---------------------------------------------------------------------- @@ -1989,107 +1459,36 @@ subroutine count_cohorts( currentPatch ) currentCohort => currentCohort%shorter enddo - if (backcount /= currentPatch%countcohorts) then - write(fates_log(),*) 'problem with linked list, not symmetrical' - endif - + if(debug) then + if (backcount /= currentPatch%countcohorts) then + write(fates_log(),*) 'problem with linked list, not symmetrical' + call endrun(msg=errMsg(sourcefile, __LINE__)) + endif + end if + end subroutine count_cohorts ! =================================================================================== - subroutine UpdateCohortBioPhysRates(currentCohort) - - ! -------------------------------------------------------------------------------- - ! This routine updates the four key biophysical rates of leaves - ! based on the changes in a cohort's leaf age proportions - ! - ! This should be called after growth. Growth occurs - ! after turnover and damage states are applied to the tree. - ! Therefore, following growth, the leaf mass fractions - ! of different age classes are unchanged until the next day. - ! -------------------------------------------------------------------------------- - - type(ed_cohort_type),intent(inout) :: currentCohort - - - real(r8) :: frac_leaf_aclass(max_nleafage) ! Fraction of leaves in each age-class - integer :: iage ! loop index for leaf ages - integer :: ipft ! plant functional type index - - ! First, calculate the fraction of leaves in each age class - ! It is assumed that each class has the same proportion - ! across leaf layers - - do iage = 1, nleafage - frac_leaf_aclass(iage) = & - currentCohort%prt%GetState(leaf_organ, all_carbon_elements,iage) - end do - - ! If there are leaves, then perform proportional weighting on the four rates - ! We assume that leaf age does not effect the specific leaf area, so the mass - ! fractions are applicable to these rates - - ipft = currentCohort%pft - - if(sum(frac_leaf_aclass(1:nleafage))>nearzero .and. hlm_use_sp .eq. ifalse) then - - frac_leaf_aclass(1:nleafage) = frac_leaf_aclass(1:nleafage) / & - sum(frac_leaf_aclass(1:nleafage)) - - currentCohort%vcmax25top = sum(EDPftvarcon_inst%vcmax25top(ipft,1:nleafage) * & - frac_leaf_aclass(1:nleafage)) - - currentCohort%jmax25top = sum(param_derived%jmax25top(ipft,1:nleafage) * & - frac_leaf_aclass(1:nleafage)) - - currentCohort%tpu25top = sum(param_derived%tpu25top(ipft,1:nleafage) * & - frac_leaf_aclass(1:nleafage)) - - currentCohort%kp25top = sum(param_derived%kp25top(ipft,1:nleafage) * & - frac_leaf_aclass(1:nleafage)) - - elseif (hlm_use_sp .eq. itrue) then - - currentCohort%vcmax25top = EDPftvarcon_inst%vcmax25top(ipft,1) - currentCohort%jmax25top = param_derived%jmax25top(ipft,1) - currentCohort%tpu25top = param_derived%tpu25top(ipft,1) - currentCohort%kp25top = param_derived%kp25top(ipft,1) - - else - - currentCohort%vcmax25top = 0._r8 - currentCohort%jmax25top = 0._r8 - currentCohort%tpu25top = 0._r8 - currentCohort%kp25top = 0._r8 - - end if - - - return - end subroutine UpdateCohortBioPhysRates - - - ! ============================================================================ - - - subroutine EvaluateAndCorrectDBH(currentCohort,delta_dbh,delta_hite) + subroutine EvaluateAndCorrectDBH(currentCohort,delta_dbh,delta_height) ! ----------------------------------------------------------------------------------- ! If the current diameter of a plant is somehow less than what is allometrically ! consistent with stuctural biomass (or, in the case of grasses, leaf biomass) ! then correct (increase) the dbh to match that. ! ----------------------------------------------------------------------------------- - + ! argument - type(ed_cohort_type),intent(inout) :: currentCohort + type(fates_cohort_type),intent(inout) :: currentCohort real(r8),intent(out) :: delta_dbh - real(r8),intent(out) :: delta_hite + real(r8),intent(out) :: delta_height ! locals real(r8) :: dbh real(r8) :: canopy_trim integer :: ipft + integer :: icrowndamage real(r8) :: sapw_area real(r8) :: target_sapw_c real(r8) :: target_agw_c @@ -2097,28 +1496,36 @@ subroutine EvaluateAndCorrectDBH(currentCohort,delta_dbh,delta_hite) real(r8) :: target_struct_c real(r8) :: target_leaf_c real(r8) :: struct_c - real(r8) :: hite_out + real(r8) :: height_out real(r8) :: leaf_c - + real(r8) :: crown_reduction + real(r8) :: elongf_leaf + real(r8) :: elongf_stem + dbh = currentCohort%dbh ipft = currentCohort%pft + icrowndamage = currentCohort%crowndamage canopy_trim = currentCohort%canopy_trim + elongf_leaf = currentCohort%efleaf_coh + elongf_stem = currentCohort%efstem_coh delta_dbh = 0._r8 - delta_hite = 0._r8 - - if( int(prt_params%woody(currentCohort%pft)) == itrue) then + delta_height = 0._r8 - struct_c = currentCohort%prt%GetState(struct_organ, all_carbon_elements) + if( prt_params%woody(currentCohort%pft) == itrue) then - ! Target sapwood biomass according to allometry and trimming [kgC] - call bsap_allom(dbh,ipft,canopy_trim,sapw_area,target_sapw_c) - - ! Target total above ground biomass in woody/fibrous tissues [kgC] - call bagw_allom(dbh,ipft,target_agw_c) + struct_c = currentCohort%prt%GetState(struct_organ, carbon12_element) - ! Target total below ground biomass in woody/fibrous tissues [kgC] - call bbgw_allom(dbh,ipft,target_bgw_c) + ! Target sapwood biomass according to allometry, trimming and phenology [kgC] + call bsap_allom(dbh,ipft,icrowndamage,canopy_trim, elongf_stem, sapw_area,target_sapw_c) + + ! Target total above ground biomass in woody/fibrous tissues + ! according to allometry, trimming and phenology [kgC] + call bagw_allom(dbh,ipft, icrowndamage, elongf_stem, target_agw_c) + + ! Target total below ground biomass in woody/fibrous tissues + ! according to allometry, trimming and phenology [kgC] + call bbgw_allom(dbh,ipft, elongf_stem, target_bgw_c) ! Target total dead (structrual) biomass [kgC] call bdead_allom( target_agw_c, target_bgw_c, target_sapw_c, ipft, target_struct_c) @@ -2130,32 +1537,299 @@ subroutine EvaluateAndCorrectDBH(currentCohort,delta_dbh,delta_hite) ! ----------------------------------------------------------------------------------- if( (struct_c - target_struct_c ) > calloc_abs_error ) then - call ForceDBH( ipft, canopy_trim, dbh, hite_out, bdead=struct_c ) - delta_dbh = dbh - currentCohort%dbh - delta_hite = hite_out - currentCohort%hite + + call ForceDBH( ipft,icrowndamage,canopy_trim, elongf_leaf, elongf_stem, & + dbh, height_out, bdead=struct_c) + + delta_dbh = dbh - currentCohort%dbh + delta_height = height_out - currentCohort%height currentCohort%dbh = dbh - currentCohort%hite = hite_out + currentCohort%height = height_out end if else ! This returns the sum of leaf carbon over all (age) bins - leaf_c = currentCohort%prt%GetState(leaf_organ, all_carbon_elements) + leaf_c = currentCohort%prt%GetState(leaf_organ, carbon12_element) - ! Target leaf biomass according to allometry and trimming - call bleaf(dbh,ipft,canopy_trim,target_leaf_c) + ! Target leaf biomass according to allometry, trimming and phenology + call bleaf(dbh,ipft,icrowndamage, canopy_trim, elongf_leaf, target_leaf_c) if( ( leaf_c - target_leaf_c ) > calloc_abs_error ) then - call ForceDBH( ipft, canopy_trim, dbh, hite_out, bl=leaf_c ) + call ForceDBH( ipft, icrowndamage, canopy_trim, elongf_leaf, elongf_stem, & + dbh, height_out, bl=leaf_c ) delta_dbh = dbh - currentCohort%dbh - delta_hite = hite_out - currentCohort%hite + delta_height = height_out - currentCohort%height currentCohort%dbh = dbh - currentCohort%hite = hite_out + currentCohort%height = height_out end if end if return end subroutine EvaluateAndCorrectDBH + !------------------------------------------------------------------------------------ + + subroutine DamageRecovery(csite,cpatch,ccohort,newly_recovered) + + !--------------------------------------------------------------------------- + ! JN March 2021 + ! At this point it is possible that damaged cohorts have reached their + ! target allometries. There is a choice now - if they have excess carbon, + ! they can use it to grow along their reduced allometric targets - i.e. + ! dbh and all carbon pools grow out together. OR they can use excess carbon to + ! jump to a lower damage class by changing their target allometry and growing + ! to meet new C pools for same dbh. + ! + ! d = damage class + ! -------------------------------------------------------------------------- + + type(ed_site_type) :: csite ! Site of the current cohort + type(fates_patch_type) :: cpatch ! patch of the current cohort + type(fates_cohort_type),pointer :: ccohort ! Current (damaged) cohort + logical :: newly_recovered ! true if we create a new cohort + + ! locals + type(fates_cohort_type), pointer :: rcohort ! New cohort that recovers by + ! having a lower damage class + real(r8) :: sapw_area ! sapwood area + real(r8) :: target_sapw_c,target_sapw_m ! sapwood mass, C and N/P + real(r8) :: target_agw_c ! target above ground wood + real(r8) :: target_bgw_c ! target below ground wood + real(r8) :: target_struct_c,target_struct_m ! target structural C and N/P + real(r8) :: target_fnrt_c,target_fnrt_m ! target fine-root C and N/P + real(r8) :: target_leaf_c,target_leaf_m ! target leaf C and N/P + real(r8) :: target_store_c,target_store_m ! target storage C and N/P + real(r8) :: target_repro_m ! target reproductive C/N/P + real(r8) :: leaf_m,fnrt_m,sapw_m ! actual masses in organs C/N/P + real(r8) :: struct_m,store_m,repro_m ! actual masses in organs C/N/P + real(r8) :: mass_d ! intermediate term for nplant_recover + real(r8) :: mass_dminus1 ! intermediate term for nplant_recover + real(r8) :: available_m ! available mass that can be used to + ! improve damage class + real(r8) :: recovery_demand ! amount of mass needed to get to + ! the target of the next damage class + real(r8) :: max_recover_nplant ! max number of plants that could get to + ! target of next class + real(r8) :: nplant_recover ! number of plants in cohort that will + ! recover to the next class + integer :: el ! element loop counter + + logical :: is_hydecid_dormant ! Flag to signal that the cohort is drought deciduous and dormant + logical :: is_sedecid_dormant ! Flag to signal this is a deciduous PFT + + associate(dbh => ccohort%dbh, & + ipft => ccohort%pft, & + canopy_trim => ccohort%canopy_trim, & + elongf_leaf => ccohort%efleaf_coh, & + elongf_fnrt => ccohort%effnrt_coh, & + elongf_stem => ccohort%efstem_coh) + + ! If we are currently undamaged, no recovery + ! necessary, do nothing and return a null pointer + ! If the damage_recovery_scalar is zero, which + ! would be an unusual testing case, but possible, + ! then no recovery is possible, do nothing and + ! return a null pointer + if ((ccohort%crowndamage == undamaged_class) .or. & + (EDPftvarcon_inst%damage_recovery_scalar(ipft) < nearzero) ) then + newly_recovered = .false. + return + end if + + + !--- Set some logical flags to simplify "if" blocks + is_hydecid_dormant = & + any(prt_params%stress_decid(ipft) == [ihard_stress_decid,isemi_stress_decid] ) & + .and. any(ccohort%status_coh == [leaves_off,leaves_shedding] ) + is_sedecid_dormant = & + ( prt_params%season_decid(ipft) == itrue ) & + .and. any(ccohort%status_coh == [leaves_off,leaves_shedding] ) + + ! If plants are drought deciduous and are losing or lost all leaves, they cannot + ! allocate carbon to any growth or recovery. Return a null pointer and wait until + ! the growing season. + if (is_hydecid_dormant) then + newly_recovered = .false. + return + end if + + + ! If we have not returned, then this cohort both has + ! a damaged status, and the ability to recover from that damage + ! ----------------------------------------------------------------- + + ! To determine recovery, the first priority is to determine how much + ! resources (C,N,P) are required to recover the plant to the target + ! pool sizes of the next (less) damage class + + ! Target sapwood biomass according to allometry, trimming and phenology [kgC] + call bsap_allom(dbh,ipft, ccohort%crowndamage-1, canopy_trim, elongf_stem, & + sapw_area,target_sapw_c) + ! Target total above ground biomass in woody/fibrous tissues + ! according to allometry, trimming and phenology [kgC] + call bagw_allom(dbh,ipft, ccohort%crowndamage-1, elongf_stem, target_agw_c) + ! Target total below ground biomass in woody/fibrous tissues + ! according to allometry, trimming and phenology [kgC] + call bbgw_allom(dbh,ipft, elongf_stem, target_bgw_c) + ! Target total dead (structrual) biomass [kgC] + call bdead_allom( target_agw_c, target_bgw_c, target_sapw_c, ipft, target_struct_c) + ! Target fine-root biomass according to allometry, trimming and phenology [kgC] + call bfineroot(dbh,ipft,canopy_trim,ccohort%l2fr, elongf_fnrt, target_fnrt_c) + ! Target storage carbon [kgC] + call bstore_allom(dbh,ipft,ccohort%crowndamage-1, canopy_trim,target_store_c) + ! Target leaf biomass according to allometry, trimming and phenology [kgC] + call bleaf(dbh,ipft,ccohort%crowndamage-1, canopy_trim, elongf_leaf, target_leaf_c) + + + ! If plants are cold deciduous, we do not let them recover leaves, but we allow + ! them to recover other tissues. This is due to back-compatibility, but we may + ! want to revisit this later. + if (is_sedecid_dormant) then + target_leaf_c = 0._r8 + end if + + ! We will be taking the number of recovering plants + ! based on minimum of available resources for C/N/P (initialize high) + nplant_recover = 1.e10_r8 + + do el=1,num_elements + + ! Actual mass of chemical species in the organs + leaf_m = ccohort%prt%GetState(leaf_organ, element_list(el)) + store_m = ccohort%prt%GetState(store_organ, element_list(el)) + sapw_m = ccohort%prt%GetState(sapw_organ, element_list(el)) + fnrt_m = ccohort%prt%GetState(fnrt_organ, element_list(el)) + struct_m = ccohort%prt%GetState(struct_organ, element_list(el)) + repro_m = ccohort%prt%GetState(repro_organ, element_list(el)) + + ! Target mass of chemical species in organs, based on stature, + ! allometry and stoichiometry parameters + select case (element_list(el)) + case (carbon12_element) + target_store_m = target_store_c + target_leaf_m = target_leaf_c + target_fnrt_m = target_fnrt_c + target_struct_m = target_struct_c + target_sapw_m = target_sapw_c + target_repro_m = 0._r8 + available_m = ccohort%npp_acc + case (nitrogen_element) + target_struct_m = target_struct_c * & + prt_params%nitr_stoich_p1(ipft,prt_params%organ_param_id(struct_organ)) + target_leaf_m = target_leaf_c * & + prt_params%nitr_stoich_p1(ipft,prt_params%organ_param_id(leaf_organ)) + target_fnrt_m = target_fnrt_c * & + prt_params%nitr_stoich_p1(ipft,prt_params%organ_param_id(fnrt_organ)) + target_sapw_m = target_sapw_c * & + prt_params%nitr_stoich_p1(ipft,prt_params%organ_param_id(sapw_organ)) + target_repro_m = 0._r8 + target_store_m = StorageNutrientTarget(ipft, element_list(el), & + target_leaf_m, target_fnrt_m, target_sapw_m, target_struct_m) + ! For nutrients, all uptake is immediately put into storage, so just swap + ! them and assume storage is what is available, but needs to be filled up + available_m = store_m + store_m = 0._r8 + case (phosphorus_element) + target_struct_m = target_struct_c * & + prt_params%phos_stoich_p1(ipft,prt_params%organ_param_id(struct_organ)) + target_leaf_m = target_leaf_c * & + prt_params%phos_stoich_p1(ipft,prt_params%organ_param_id(leaf_organ)) + target_fnrt_m = target_fnrt_c * & + prt_params%phos_stoich_p1(ipft,prt_params%organ_param_id(fnrt_organ)) + target_sapw_m = target_sapw_c * & + prt_params%phos_stoich_p1(ipft,prt_params%organ_param_id(sapw_organ)) + target_repro_m = 0._r8 + target_store_m = StorageNutrientTarget(ipft, element_list(el), & + target_leaf_m, target_fnrt_m, target_sapw_m, target_struct_m) + ! For nutrients, all uptake is immediately put into storage, so just swap + ! them and assume storage is what is available, but needs to be filled up + available_m = store_m + store_m = 0._r8 + end select + + ! 1. What is excess carbon? + ! carbon_balance + + ! 2. What is biomass required to go from current + ! damage level to next damage level? + + ! mass of this damage class + mass_d = leaf_m + store_m + sapw_m + fnrt_m + struct_m + repro_m + + mass_dminus1 = max(leaf_m, target_leaf_m) + max(fnrt_m, target_fnrt_m) + & + max(store_m, target_store_m) + max(sapw_m, target_sapw_m) + & + max(struct_m, target_struct_m) + + ! Mass needed to get from current mass to allometric + ! target mass of next damage class up + recovery_demand = mass_dminus1 - mass_d + + ! 3. How many trees can get there with excess carbon? + max_recover_nplant = available_m * ccohort%n / recovery_demand + + ! 4. Use the scalar to decide how many to recover + nplant_recover = min(nplant_recover,min(ccohort%n,max(0._r8,max_recover_nplant * & + EDPftvarcon_inst%damage_recovery_scalar(ipft) ))) + + end do + + if(nplant_recover < nearzero) then + + newly_recovered = .false. + return + + else + newly_recovered = .true. + allocate(rcohort) + if(hlm_use_planthydro .eq. itrue) call InitHydrCohort(csite,rcohort) + ! Initialize the PARTEH object and point to the + ! correct boundary condition fields + rcohort%prt => null() + call InitPRTObject(rcohort%prt) + call rcohort%InitPRTBoundaryConditions() + call ccohort%Copy(rcohort) + + rcohort%n = nplant_recover + + rcohort%crowndamage = ccohort%crowndamage - 1 + + ! Need to adjust the crown area which is NOT on a per individual basis + call carea_allom(dbh,rcohort%n,csite%spread,ipft,rcohort%crowndamage,rcohort%c_area) + + ! Update properties of the un-recovered (donor) cohort + ccohort%n = ccohort%n - rcohort%n + ccohort%c_area = ccohort%c_area * ccohort%n / (ccohort%n+rcohort%n) + + !----------- Insert copy into linked list ----------------------! + ! This subroutine is called within a loop in EDMain that + ! proceeds short to tall. We want the newly created cohort + ! to have an opportunity to experience the list, so we add + ! it in the list in a position taller than the current cohort + ! --------------------------------------------------------------! + + rcohort%shorter => ccohort + if(associated(ccohort%taller))then + rcohort%taller => ccohort%taller + ccohort%taller%shorter => rcohort + else + cpatch%tallest => rcohort + rcohort%taller => null() + endif + ccohort%taller => rcohort + + end if ! end if greater than nearzero + + end associate + + return + end subroutine DamageRecovery + + + + +!:.........................................................................: + + end module EDCohortDynamicsMod diff --git a/biogeochem/EDLoggingMortalityMod.F90 b/biogeochem/EDLoggingMortalityMod.F90 index f1f23d9f33..a4703ae840 100644 --- a/biogeochem/EDLoggingMortalityMod.F90 +++ b/biogeochem/EDLoggingMortalityMod.F90 @@ -14,18 +14,20 @@ module EDLoggingMortalityMod ! ==================================================================================== use FatesConstantsMod , only : r8 => fates_r8 - use EDTypesMod , only : ed_cohort_type - use EDTypesMod , only : ed_patch_type + use FatesConstantsMod , only : rsnbl_math_prec + use FatesCohortMod , only : fates_cohort_type + use FatesPatchMod , only : fates_patch_type use EDTypesMod , only : site_massbal_type use EDTypesMod , only : site_fluxdiags_type use FatesLitterMod , only : ncwd use FatesLitterMod , only : ndcmpy use FatesLitterMod , only : litter_type + use FatesLitterMod , only : adjust_SF_CWD_frac use EDTypesMod , only : ed_site_type use EDTypesMod , only : ed_resources_management_type - use EDTypesMod , only : dtype_ilog - use EDTypesMod , only : dtype_ifall - use EDTypesMod , only : dtype_ifire + use FatesConstantsMod , only : dtype_ilog + use FatesConstantsMod , only : dtype_ifall + use FatesConstantsMod , only : dtype_ifire use EDPftvarcon , only : EDPftvarcon_inst use EDPftvarcon , only : GetDecompyFrac use PRTParametersMod , only : prt_params @@ -54,15 +56,16 @@ module EDLoggingMortalityMod use FatesConstantsMod , only : itrue,ifalse use FatesGlobals , only : endrun => fates_endrun use FatesGlobals , only : fates_log + use FatesGlobals , only : fates_global_verbose use shr_log_mod , only : errMsg => shr_log_errMsg use FatesPlantHydraulicsMod, only : AccumulateMortalityWaterStorage - use PRTGenericMod , only : all_carbon_elements,carbon12_element + use PRTGenericMod , only : carbon12_element use PRTGenericMod , only : sapw_organ, struct_organ, leaf_organ use PRTGenericMod , only : fnrt_organ, store_organ, repro_organ use FatesAllometryMod , only : set_root_fraction use FatesConstantsMod , only : primaryforest, secondaryforest, secondary_age_threshold use FatesConstantsMod , only : fates_tiny - use FatesConstantsMod , only : months_per_year + use FatesConstantsMod , only : months_per_year, days_per_sec, years_per_day, g_per_kg use FatesConstantsMod , only : hlm_harvest_area_fraction use FatesConstantsMod , only : hlm_harvest_carbon use FatesConstantsMod, only : fates_check_param_set @@ -73,7 +76,8 @@ module EDLoggingMortalityMod logical, protected :: logging_time ! If true, logging should be ! performed during the current time-step - + logical, parameter :: debug = .false. + ! harvest litter localization specifies how much of the litter from a falling ! tree lands within the newly generated patch, and how much lands outside of ! the new patch, and thus in the original patch. By setting this to zero, @@ -92,6 +96,10 @@ module EDLoggingMortalityMod public :: logging_time public :: IsItLoggingTime public :: get_harvest_rate_area + public :: get_harvestable_carbon + public :: get_harvest_rate_carbon + public :: get_harvest_debt + public :: UpdateHarvestC contains @@ -184,6 +192,7 @@ subroutine IsItLoggingTime(is_master,currentSite) return end subroutine IsItLoggingTime + ! ====================================================================================== subroutine LoggingMortality_frac( pft_i, dbh, canopy_layer, lmort_direct, & @@ -191,7 +200,8 @@ subroutine LoggingMortality_frac( pft_i, dbh, canopy_layer, lmort_direct, & hlm_harvest_rates, hlm_harvest_catnames, & hlm_harvest_units, & patch_anthro_disturbance_label, secondary_age, & - frac_site_primary) + frac_site_primary, harvestable_forest_c, & + harvest_tag) ! Arguments integer, intent(in) :: pft_i ! pft index @@ -202,6 +212,9 @@ subroutine LoggingMortality_frac( pft_i, dbh, canopy_layer, lmort_direct, & integer, intent(in) :: hlm_harvest_units ! unit type of hlm harvest rates: [area vs. mass] integer, intent(in) :: patch_anthro_disturbance_label ! patch level anthro_disturbance_label real(r8), intent(in) :: secondary_age ! patch level age_since_anthro_disturbance + real(r8), intent(in) :: harvestable_forest_c(:) ! total harvestable forest carbon + ! of all hlm harvest categories + real(r8), intent(in) :: frac_site_primary real(r8), intent(out) :: lmort_direct ! direct (harvestable) mortality fraction real(r8), intent(out) :: lmort_collateral ! collateral damage mortality fraction real(r8), intent(out) :: lmort_infra ! infrastructure mortality fraction @@ -209,9 +222,15 @@ subroutine LoggingMortality_frac( pft_i, dbh, canopy_layer, lmort_direct, & ! but suffer from forest degradation (i.e. they ! are moved to newly-anthro-disturbed secondary ! forest patch) - real(r8), intent(in) :: frac_site_primary + integer, intent(out) :: harvest_tag(:) ! tag to record the harvest status + ! for the calculation of harvest debt in C-based + ! harvest mode + ! 0 - successful; + ! 1 - unsuccessful since not enough carbon + ! 2 - not applicable ! Local variables + integer :: cur_harvest_tag ! the harvest tag of the cohort today real(r8) :: harvest_rate ! the final harvest rate to apply to this cohort today ! todo: probably lower the dbhmin default value to 30 cm @@ -249,27 +268,44 @@ subroutine LoggingMortality_frac( pft_i, dbh, canopy_layer, lmort_direct, & call get_harvest_rate_area (patch_anthro_disturbance_label, hlm_harvest_catnames, & hlm_harvest_rates, frac_site_primary, secondary_age, harvest_rate) + ! For area-based harvest, harvest_tag shall always be 2 (not applicable). + harvest_tag = 2 + cur_harvest_tag = 2 + + if (fates_global_verbose()) then + write(fates_log(), *) 'Successfully Read Harvest Rate from HLM.', hlm_harvest_rates(:), harvest_rate + end if + else if (hlm_use_lu_harvest == itrue .and. hlm_harvest_units == hlm_harvest_carbon) then ! 2=use carbon from hlm - ! not implemented yet - write(fates_log(),*) 'HLM harvest carbon data not implemented yet. Exiting.' - call endrun(msg=errMsg(sourcefile, __LINE__)) + ! shall call another subroutine, which transfers biomass/carbon into fraction + + call get_harvest_rate_carbon (patch_anthro_disturbance_label, hlm_harvest_catnames, & + hlm_harvest_rates, secondary_age, harvestable_forest_c, & + harvest_rate, harvest_tag, cur_harvest_tag) + + if (fates_global_verbose()) then + write(fates_log(), *) 'Successfully Read Harvest Rate from HLM.', hlm_harvest_rates(:), harvest_rate, harvestable_forest_c + end if + endif ! transfer of area to secondary land is based on overall area affected, not just logged crown area ! l_degrad accounts for the affected area between logged crowns - if(int(prt_params%woody(pft_i)) == 1)then ! only set logging rates for trees - - ! direct logging rates, based on dbh min and max criteria - if (dbh >= logging_dbhmin .and. .not. & - ((logging_dbhmax < fates_check_param_set) .and. (dbh >= logging_dbhmax )) ) then - ! the logic of the above line is a bit unintuitive but allows turning off the dbhmax comparison entirely. - ! since there is an .and. .not. after the first conditional, the dbh:dbhmax comparison needs to be - ! the opposite of what would otherwise be expected... - lmort_direct = harvest_rate * logging_direct_frac - + if(prt_params%woody(pft_i) == itrue)then ! only set logging rates for trees + if (cur_harvest_tag == 0) then + ! direct logging rates, based on dbh min and max criteria + if (dbh >= logging_dbhmin .and. .not. & + ((logging_dbhmax < fates_check_param_set) .and. (dbh >= logging_dbhmax )) ) then + ! the logic of the above line is a bit unintuitive but allows turning off the dbhmax comparison entirely. + ! since there is an .and. .not. after the first conditional, the dbh:dbhmax comparison needs to be + ! the opposite of what would otherwise be expected... + lmort_direct = harvest_rate * logging_direct_frac + else + lmort_direct = 0.0_r8 + end if else - lmort_direct = 0.0_r8 + lmort_direct = 0.0_r8 end if ! infrastructure (roads, skid trails, etc) mortality rates @@ -309,6 +345,7 @@ subroutine LoggingMortality_frac( pft_i, dbh, canopy_layer, lmort_direct, & end subroutine LoggingMortality_frac + ! ============================================================================ subroutine get_harvest_rate_area (patch_anthro_disturbance_label, hlm_harvest_catnames, hlm_harvest_rates, & @@ -333,11 +370,12 @@ subroutine get_harvest_rate_area (patch_anthro_disturbance_label, hlm_harvest_ca integer :: h_index ! for looping over harvest categories integer :: icode ! Integer equivalent of the event code (parameter file only allows reals) - ! Loop around harvest categories to determine the annual hlm harvest rate for the current cohort based on patch history info + ! Loop around harvest categories to determine the annual hlm harvest rate for the current cohort based on patch history info + ! We do account forest only since non-forest harvest has geographical mismatch to LUH2 dataset harvest_rate = 0._r8 do h_index = 1,hlm_num_lu_harvest_cats if (patch_anthro_disturbance_label .eq. primaryforest) then - if(hlm_harvest_catnames(h_index) .eq. "HARVEST_VH1" .or. & + if(hlm_harvest_catnames(h_index) .eq. "HARVEST_VH1" .or. & hlm_harvest_catnames(h_index) .eq. "HARVEST_VH2") then harvest_rate = harvest_rate + hlm_harvest_rates(h_index) endif @@ -357,7 +395,7 @@ subroutine get_harvest_rate_area (patch_anthro_disturbance_label, hlm_harvest_ca ! Normalize by site-level primary or secondary forest fraction ! since harvest_rate is specified as a fraction of the gridcell - ! also need to put a cap so as not to harvest more primary or secondary area than there is in a gridcell + ! also need to put a cap so as not to harvest more primary or secondary area than there is in a gridcell if (patch_anthro_disturbance_label .eq. primaryforest) then if (frac_site_primary .gt. fates_tiny) then harvest_rate = min((harvest_rate / frac_site_primary),frac_site_primary) @@ -386,13 +424,261 @@ subroutine get_harvest_rate_area (patch_anthro_disturbance_label, hlm_harvest_ca harvest_rate = harvest_rate / hlm_days_per_year else if(icode .eq. 4) then ! logging event once a month - if(hlm_current_day.eq.1 ) then + if(hlm_current_day.eq.1) then harvest_rate = harvest_rate / months_per_year end if end if end subroutine get_harvest_rate_area + + ! ============================================================================ + + subroutine get_harvestable_carbon (csite, site_area, hlm_harvest_catnames, harvestable_forest_c ) + + !USES: + use SFParamsMod, only : SF_val_cwd_frac + use EDTypesMod, only : AREA_INV + + + ! ------------------------------------------------------------------------------------------- + ! + ! DESCRIPTION: + ! get the total carbon availale for harvest for three different harvest categories: + ! primary forest, secondary mature forest and secondary young forest + ! under two different scenarios: + ! harvestable carbon: aggregate all cohorts matching the dbhmin harvest criteria + ! + ! this subroutine shall be called outside the patch loop + ! output will be used to estimate the area-based harvest rate (get_harvest_rate_carbon) + ! for each cohort. + + ! Arguments + type(ed_site_type), intent(in), target :: csite + real(r8), intent(in) :: site_area ! temporary variable + character(len=64), intent(in) :: hlm_harvest_catnames(:) ! names of hlm harvest categories + + real(r8), intent(out) :: harvestable_forest_c(hlm_num_lu_harvest_cats) + + ! Local Variables + type(fates_patch_type), pointer :: currentPatch + type(fates_cohort_type), pointer :: currentCohort + real(r8) :: harvestable_patch_c ! patch level total carbon available for harvest, kgC site-1 + real(r8) :: harvestable_cohort_c ! cohort level total carbon available for harvest, kgC site-1 + real(r8) :: sapw_m ! Biomass of sap wood + real(r8) :: struct_m ! Biomass of structural organs + integer :: pft ! Index of plant functional type + integer :: h_index ! for looping over harvest categories + + ! Initialization + harvestable_forest_c = 0._r8 + + ! loop over patches + currentPatch => csite%oldest_patch + do while (associated(currentPatch)) + harvestable_patch_c = 0._r8 + currentCohort => currentPatch%tallest + + do while (associated(currentCohort)) + pft = currentCohort%pft + + ! only account for cohorts matching the following conditions + if(int(prt_params%woody(pft)) == 1)then ! only set logging rates for trees + sapw_m = currentCohort%prt%GetState(sapw_organ, carbon12_element) + struct_m = currentCohort%prt%GetState(struct_organ, carbon12_element) + ! logging_direct_frac shall be 1 for LUH2 driven simulation and global simulation + ! in site level study logging_direct_frac shall be surveyed + ! unit: [kgC ] = [kgC/plant] * [plant/ha] * [ha/ 10k m2] * [ m2 area ] + harvestable_cohort_c = logging_direct_frac * ( sapw_m + struct_m ) * & + prt_params%allom_agb_frac(currentCohort%pft) * & + SF_val_CWD_frac(ncwd) * logging_export_frac * & + currentCohort%n * AREA_INV * site_area + + ! No harvest for trees without canopy + if (currentCohort%canopy_layer>=1) then + ! logging amount are based on dbh min and max criteria + if (currentCohort%dbh >= logging_dbhmin .and. .not. & + ((logging_dbhmax < fates_check_param_set) .and. (currentCohort%dbh >= logging_dbhmax )) ) then + ! Harvestable C: aggregate cohorts fit the criteria + harvestable_patch_c = harvestable_patch_c + harvestable_cohort_c + end if + end if + end if + currentCohort => currentCohort%shorter + end do + + ! judge which category the current patch belong to + ! since we have not separated forest vs. non-forest + ! all carbon belongs to the forest categories + do h_index = 1,hlm_num_lu_harvest_cats + if (currentPatch%anthro_disturbance_label .eq. primaryforest) then + ! Primary + if(hlm_harvest_catnames(h_index) .eq. "HARVEST_VH1") then + harvestable_forest_c(h_index) = harvestable_forest_c(h_index) + harvestable_patch_c + end if + else if (currentPatch%anthro_disturbance_label .eq. secondaryforest .and. & + currentPatch%age_since_anthro_disturbance >= secondary_age_threshold) then + ! Secondary mature + if(hlm_harvest_catnames(h_index) .eq. "HARVEST_SH1") then + harvestable_forest_c(h_index) = harvestable_forest_c(h_index) + harvestable_patch_c + end if + else if (currentPatch%anthro_disturbance_label .eq. secondaryforest .and. & + currentPatch%age_since_anthro_disturbance < secondary_age_threshold) then + ! Secondary young + if(hlm_harvest_catnames(h_index) .eq. "HARVEST_SH2") then + harvestable_forest_c(h_index) = harvestable_forest_c(h_index) + harvestable_patch_c + end if + end if + end do + currentPatch => currentPatch%younger + end do + + end subroutine get_harvestable_carbon + + ! ============================================================================ + + subroutine get_harvest_rate_carbon (patch_anthro_disturbance_label, hlm_harvest_catnames, & + hlm_harvest_rates, secondary_age, harvestable_forest_c, & + harvest_rate, harvest_tag, cur_harvest_tag) + + ! ------------------------------------------------------------------------------------------- + ! + ! DESCRIPTION: + ! get the carbon-based harvest rates based on info passed to FATES from the boundary conditions in. + ! assumes logging_time == true + + ! Arguments + real(r8), intent(in) :: hlm_harvest_rates(:) ! annual harvest rate per hlm category + character(len=64), intent(in) :: hlm_harvest_catnames(:) ! names of hlm harvest categories + integer, intent(in) :: patch_anthro_disturbance_label ! patch level anthro_disturbance_label + real(r8), intent(in) :: secondary_age ! patch level age_since_anthro_disturbance + real(r8), intent(in) :: harvestable_forest_c(:) ! site level forest c matching criteria available for harvest, kgC site-1 + real(r8), intent(out) :: harvest_rate ! area fraction + integer, intent(inout) :: harvest_tag(:) ! 0. normal harvest; 1. current site does not have enough C but + ! can perform harvest by ignoring criteria; 2. current site does + ! not have enough carbon + ! This harvest tag shall be a patch level variable but since all + ! logging functions happen within cohort loop we can only put the + ! calculation here. Can think about optimizing the logging calculation + ! in the future. + integer, intent(out), optional :: cur_harvest_tag ! harvest tag of the current cohort + + ! Local Variables + integer :: h_index ! for looping over harvest categories + integer :: icode ! Integer equivalent of the event code (parameter file only allows reals) + real(r8) :: harvest_rate_c ! Temporary variable, kgC site-1 + real(r8) :: harvest_rate_supply ! Temporary variable, kgC site-1 + + ! This subroutine follows the same logic of get_harvest_rate_area + ! Loop over harvest categories to determine the hlm harvest rate demand and actual harvest rate for the + ! current cohort based on patch history info + + ! Initialize local variables + harvest_rate = 0._r8 + harvest_rate_c = 0._r8 + harvest_rate_supply = 0._r8 + harvest_tag(:) = 2 + + ! Since we have five harvest categories from forcing data but in FATES non-forest harvest + ! is merged with forest harvest, we only have three logging type in FATES (primary, secondary + ! mature and secondary young). + ! Get the harvest rate from HLM + do h_index = 1,hlm_num_lu_harvest_cats + if (patch_anthro_disturbance_label .eq. primaryforest) then + if(hlm_harvest_catnames(h_index) .eq. "HARVEST_VH1" .or. & + hlm_harvest_catnames(h_index) .eq. "HARVEST_VH2") then + harvest_rate_c = harvest_rate_c + hlm_harvest_rates(h_index) + endif + else if (patch_anthro_disturbance_label .eq. secondaryforest .and. & + secondary_age >= secondary_age_threshold) then + if(hlm_harvest_catnames(h_index) .eq. "HARVEST_SH1") then + harvest_rate_c = harvest_rate_c + hlm_harvest_rates(h_index) + endif + else if (patch_anthro_disturbance_label .eq. secondaryforest .and. & + secondary_age < secondary_age_threshold) then + if(hlm_harvest_catnames(h_index) .eq. "HARVEST_SH2" .or. & + hlm_harvest_catnames(h_index) .eq. "HARVEST_SH3") then + harvest_rate_c = harvest_rate_c + hlm_harvest_rates(h_index) + endif + endif + end do + + ! Determine harvest status (succesful or not) + ! Here only three categories are used + do h_index = 1,hlm_num_lu_harvest_cats + if (patch_anthro_disturbance_label .eq. primaryforest) then + if(hlm_harvest_catnames(h_index) .eq. "HARVEST_VH1" ) then + if(harvestable_forest_c(h_index) >= harvest_rate_c) then + harvest_rate_supply = harvest_rate_supply + harvestable_forest_c(h_index) + harvest_tag(h_index) = 0 + else + harvest_tag(h_index) = 1 + end if + end if + else if (patch_anthro_disturbance_label .eq. secondaryforest .and. & + secondary_age >= secondary_age_threshold) then + if(hlm_harvest_catnames(h_index) .eq. "HARVEST_SH1" ) then + if(harvestable_forest_c(h_index) >= harvest_rate_c) then + harvest_rate_supply = harvest_rate_supply + harvestable_forest_c(h_index) + harvest_tag(h_index) = 0 + else + harvest_tag(h_index) = 1 + end if + end if + else if (patch_anthro_disturbance_label .eq. secondaryforest .and. & + secondary_age < secondary_age_threshold) then + if(hlm_harvest_catnames(h_index) .eq. "HARVEST_SH2" ) then + if(harvestable_forest_c(h_index) >= harvest_rate_c) then + harvest_rate_supply = harvest_rate_supply + harvestable_forest_c(h_index) + harvest_tag(h_index) = 0 + else + harvest_tag(h_index) = 1 + end if + end if + end if + end do + + ! If any harvest category available, assign to cur_harvest_tag and trigger logging event + if(present(cur_harvest_tag))then + cur_harvest_tag = minval(harvest_tag) + end if + + ! Transfer carbon-based harvest rate to area-based harvest rate + if (harvest_rate_supply > rsnbl_math_prec .and. harvest_rate_supply > harvest_rate_c) then + harvest_rate = harvest_rate_c / harvest_rate_supply + else + ! If we force harvest rate to 1 when we don't have enough C, we will produce + ! primary patch with no area, which cannot be terminated under nocomp mode. + ! So we still keep the harvest rate to 0 for now. + harvest_rate = 0._r8 + end if + + ! Prevent the generation of tiny secondary patches + if(harvest_rate < 1e-8) harvest_rate = 0._r8 + + ! For carbon-based harvest rate, normalizing by site-level primary or secondary forest fraction + ! is not needed + + ! calculate today's harvest rate + ! whether to harvest today has already been determined by IsItLoggingTime + ! for icode == 2, icode < 0, and icode > 10000 apply the annual rate one time (no calc) + ! Bad logging event flag is caught in IsItLoggingTime, so don't check it here + icode = int(logging_event_code) + if(icode .eq. 1) then + ! Logging is turned off - not sure why we need another switch + harvest_rate = 0._r8 + else if(icode .eq. 3) then + ! Logging event every day - this may not work due to the mortality exclusivity + harvest_rate = harvest_rate / hlm_days_per_year + else if(icode .eq. 4) then + ! logging event once a month + if(hlm_current_day.eq.1 ) then + harvest_rate = harvest_rate / months_per_year + end if + end if + + end subroutine get_harvest_rate_carbon + ! ============================================================================ subroutine logging_litter_fluxes(currentSite, currentPatch, newPatch, patch_site_areadis, bc_in) @@ -428,58 +714,59 @@ subroutine logging_litter_fluxes(currentSite, currentPatch, newPatch, patch_site !USES: - use SFParamsMod, only : SF_val_cwd_frac - use EDtypesMod, only : area - use EDtypesMod, only : ed_site_type - use EDtypesMod, only : ed_patch_type - use EDtypesMod, only : ed_cohort_type - use FatesAllometryMod , only : carea_allom + use SFParamsMod, only : SF_val_cwd_frac + use EDtypesMod, only : area + use EDtypesMod, only : ed_site_type + use FatesCohortMod, only : fates_cohort_type + use FatesConstantsMod, only : rsnbl_math_prec + use FatesAllometryMod, only : carea_allom ! !ARGUMENTS: type(ed_site_type) , intent(inout), target :: currentSite - type(ed_patch_type) , intent(inout), target :: currentPatch - type(ed_patch_type) , intent(inout), target :: newPatch + type(fates_patch_type) , intent(inout), target :: currentPatch + type(fates_patch_type) , intent(inout), target :: newPatch real(r8) , intent(in) :: patch_site_areadis type(bc_in_type) , intent(in) :: bc_in !LOCAL VARIABLES: - type(ed_cohort_type), pointer :: currentCohort + type(fates_cohort_type), pointer :: currentCohort type(site_massbal_type), pointer :: site_mass type(site_fluxdiags_type), pointer :: flux_diags type(litter_type),pointer :: new_litt type(litter_type),pointer :: cur_litt - real(r8) :: direct_dead ! Mortality count through direct logging - real(r8) :: indirect_dead ! Mortality count through: impacts, infrastructure and collateral damage - real(r8) :: trunk_product_site ! flux of carbon in trunk products exported off site [ kgC/site ] - ! (note we are accumulating over the patch, but scale is site level) - real(r8) :: delta_litter_stock ! flux of carbon in total litter flux [ kgC/site ] - real(r8) :: delta_biomass_stock ! total flux of carbon through mortality (litter+product) [ kgC/site ] - real(r8) :: delta_individual ! change in plant number through mortality [ plants/site ] - real(r8) :: leaf_litter ! Leafy biomass transferred through mortality [kgC/site] - real(r8) :: root_litter ! Rooty + storage biomass transferred through mort [kgC/site] - real(r8) :: ag_wood ! above ground wood mass [kg] - real(r8) :: bg_wood ! below ground wood mass [kg] - real(r8) :: remainder_area ! current patch's remaining area after donation [m2] - real(r8) :: leaf_m ! leaf element mass [kg] - real(r8) :: fnrt_m ! fineroot element mass [kg] - real(r8) :: sapw_m ! sapwood element mass [kg] - real(r8) :: store_m ! storage element mass [kg] - real(r8) :: struct_m ! structure element mass [kg] - real(r8) :: repro_m ! reproductive mass [kg] - real(r8) :: retain_frac ! fraction of litter retained in the donor patch - real(r8) :: donate_frac ! fraction of litter sent to newly formed patch - real(r8) :: dcmpy_frac ! fraction going into each decomposability pool - integer :: dcmpy ! index for decomposability pools - integer :: element_id ! parteh global element index - integer :: pft ! pft index - integer :: c ! cwd index - integer :: nlevsoil ! number of soil layers - integer :: ilyr ! soil layer loop index - integer :: el ! elemend loop index - + real(r8) :: direct_dead ! Mortality count through direct logging + real(r8) :: indirect_dead ! Mortality count through: impacts, infrastructure and collateral damage + real(r8) :: trunk_product_site ! flux of carbon in trunk products exported off site [ kgC/site ] + ! (note we are accumulating over the patch, but scale is site level) + real(r8) :: delta_litter_stock ! flux of carbon in total litter flux [ kgC/site ] + real(r8) :: delta_biomass_stock ! total flux of carbon through mortality (litter+product) [ kgC/site ] + real(r8) :: delta_individual ! change in plant number through mortality [ plants/site ] + real(r8) :: leaf_litter ! Leafy biomass transferred through mortality [kgC/site] + real(r8) :: root_litter ! Rooty + storage biomass transferred through mort [kgC/site] + real(r8) :: ag_wood ! above ground wood mass [kg] + real(r8) :: bg_wood ! below ground wood mass [kg] + real(r8) :: remainder_area ! current patch's remaining area after donation [m2] + real(r8) :: leaf_m ! leaf element mass [kg] + real(r8) :: fnrt_m ! fineroot element mass [kg] + real(r8) :: sapw_m ! sapwood element mass [kg] + real(r8) :: store_m ! storage element mass [kg] + real(r8) :: struct_m ! structure element mass [kg] + real(r8) :: repro_m ! reproductive mass [kg] + real(r8) :: retain_frac ! fraction of litter retained in the donor patch + real(r8) :: retain_m2 ! area normalization for litter mass destined to old patch [m-2] + real(r8) :: donate_m2 ! area normalization for litter mass destined to new patch [m-2] + real(r8) :: dcmpy_frac ! fraction going into each decomposability pool + integer :: dcmpy ! index for decomposability pools + integer :: element_id ! parteh global element index + integer :: pft ! pft index + integer :: c ! cwd index + integer :: nlevsoil ! number of soil layers + integer :: ilyr ! soil layer loop index + integer :: el ! elemend loop index + real(r8) :: SF_val_CWD_frac_adj(4) !Updated wood partitioning to CWD based on dbh nlevsoil = currentSite%nlevsoil @@ -487,17 +774,22 @@ subroutine logging_litter_fluxes(currentSite, currentPatch, newPatch, patch_site ! mass sent to that patch, by the area it will have remaining ! after it donates area. ! i.e. subtract the area it is donating. - remainder_area = currentPatch%area - patch_site_areadis - ! Calculate the fraction of litter to be retained versus donated ! vis-a-vis the new and donor patch - retain_frac = (1.0_r8-harvest_litter_localization) * & remainder_area/(newPatch%area+remainder_area) - donate_frac = 1.0_r8-retain_frac + if(remainder_area > rsnbl_math_prec) then + retain_m2 = retain_frac/remainder_area + donate_m2 = (1.0_r8-retain_frac)/newPatch%area + else + retain_m2 = 0._r8 + donate_m2 = 1._r8/newPatch%area + end if + + do el = 1,num_elements element_id = element_list(el) @@ -506,13 +798,13 @@ subroutine logging_litter_fluxes(currentSite, currentPatch, newPatch, patch_site cur_litt => currentPatch%litter(el) ! Litter pool of "current" patch new_litt => newPatch%litter(el) ! Litter pool of "new" patch - ! Zero some site level accumulator diagnsotics trunk_product_site = 0.0_r8 delta_litter_stock = 0.0_r8 delta_biomass_stock = 0.0_r8 delta_individual = 0.0_r8 + ! ----------------------------------------------------------------------------- ! Part 1: Send parts of dying plants to the litter pool. ! ----------------------------------------------------------------------------- @@ -542,7 +834,7 @@ subroutine logging_litter_fluxes(currentSite, currentPatch, newPatch, patch_site ! plants that were impacted. Thus, no direct dead can occur ! here, and indirect are impacts. - if(int(prt_params%woody(pft)) == itrue) then + if(prt_params%woody(pft) == itrue) then direct_dead = 0.0_r8 indirect_dead = logging_coll_under_frac * & (1._r8-currentPatch%fract_ldist_not_harvested) * currentCohort%n * & @@ -578,37 +870,40 @@ subroutine logging_litter_fluxes(currentSite, currentPatch, newPatch, patch_site prt_params%allom_agb_frac(currentCohort%pft) bg_wood = (direct_dead+indirect_dead) * (struct_m + sapw_m ) * & (1._r8 - prt_params%allom_agb_frac(currentCohort%pft)) - - do c = 1,ncwd-1 + + !adjust how wood is partitioned between the cwd classes based on cohort dbh + call adjust_SF_CWD_frac(currentCohort%dbh,ncwd,SF_val_CWD_frac,SF_val_CWD_frac_adj) + + do c = 1,ncwd-1 new_litt%ag_cwd(c) = new_litt%ag_cwd(c) + & - ag_wood * SF_val_CWD_frac(c) * donate_frac/newPatch%area + ag_wood * SF_val_CWD_frac_adj(c) * donate_m2 cur_litt%ag_cwd(c) = cur_litt%ag_cwd(c) + & - ag_wood * SF_val_CWD_frac(c) * retain_frac/remainder_area + ag_wood * SF_val_CWD_frac_adj(c) * retain_m2 do ilyr = 1,nlevsoil new_litt%bg_cwd(c,ilyr) = new_litt%bg_cwd(c,ilyr) + & bg_wood * currentSite%rootfrac_scr(ilyr) * & - SF_val_CWD_frac(c) * donate_frac/newPatch%area + SF_val_CWD_frac_adj(c) * donate_m2 cur_litt%bg_cwd(c,ilyr) = cur_litt%bg_cwd(c,ilyr) + & bg_wood * currentSite%rootfrac_scr(ilyr) * & - SF_val_CWD_frac(c) * retain_frac/remainder_area + SF_val_CWD_frac_adj(c) * retain_m2 end do ! Diagnostics on fluxes into the AG and BG CWD pools flux_diags%cwd_ag_input(c) = flux_diags%cwd_ag_input(c) + & - SF_val_CWD_frac(c) * ag_wood + SF_val_CWD_frac_adj(c) * ag_wood flux_diags%cwd_bg_input(c) = flux_diags%cwd_bg_input(c) + & - SF_val_CWD_frac(c) * bg_wood + SF_val_CWD_frac_adj(c) * bg_wood ! Diagnostic specific to resource management code if( element_id .eq. carbon12_element) then delta_litter_stock = delta_litter_stock + & - (ag_wood + bg_wood) * SF_val_CWD_frac(c) + (ag_wood + bg_wood) * SF_val_CWD_frac_adj(c) end if enddo @@ -623,49 +918,49 @@ subroutine logging_litter_fluxes(currentSite, currentPatch, newPatch, patch_site (1._r8 - prt_params%allom_agb_frac(currentCohort%pft)) new_litt%ag_cwd(ncwd) = new_litt%ag_cwd(ncwd) + ag_wood * & - SF_val_CWD_frac(ncwd) * donate_frac/newPatch%area + SF_val_CWD_frac_adj(ncwd) * donate_m2 cur_litt%ag_cwd(ncwd) = cur_litt%ag_cwd(ncwd) + ag_wood * & - SF_val_CWD_frac(ncwd) * retain_frac/remainder_area + SF_val_CWD_frac_adj(ncwd) * retain_m2 do ilyr = 1,nlevsoil new_litt%bg_cwd(ncwd,ilyr) = new_litt%bg_cwd(ncwd,ilyr) + & bg_wood * currentSite%rootfrac_scr(ilyr) * & - SF_val_CWD_frac(ncwd) * donate_frac/newPatch%area + SF_val_CWD_frac_adj(ncwd) * donate_m2 cur_litt%bg_cwd(ncwd,ilyr) = cur_litt%bg_cwd(ncwd,ilyr) + & bg_wood * currentSite%rootfrac_scr(ilyr) * & - SF_val_CWD_frac(ncwd) * retain_frac/remainder_area + SF_val_CWD_frac_adj(ncwd) * retain_m2 end do flux_diags%cwd_ag_input(ncwd) = flux_diags%cwd_ag_input(ncwd) + & - SF_val_CWD_frac(ncwd) * ag_wood + SF_val_CWD_frac_adj(ncwd) * ag_wood flux_diags%cwd_bg_input(ncwd) = flux_diags%cwd_bg_input(ncwd) + & - SF_val_CWD_frac(ncwd) * bg_wood + SF_val_CWD_frac_adj(ncwd) * bg_wood if( element_id .eq. carbon12_element) then delta_litter_stock = delta_litter_stock + & - (ag_wood+bg_wood) * SF_val_CWD_frac(ncwd) + (ag_wood+bg_wood) * SF_val_CWD_frac_adj(ncwd) end if ! --------------------------------------------------------------------------------------- ! Handle below-ground trunk flux for directly logged trees (c = ncwd) ! ---------------------------------------------------------------------------------------- - bg_wood = direct_dead * (struct_m + sapw_m ) * SF_val_CWD_frac(ncwd) * & + bg_wood = direct_dead * (struct_m + sapw_m ) * SF_val_CWD_frac_adj(ncwd) * & (1._r8 - prt_params%allom_agb_frac(currentCohort%pft)) do ilyr = 1,nlevsoil new_litt%bg_cwd(ncwd,ilyr) = new_litt%bg_cwd(ncwd,ilyr) + & bg_wood * currentSite%rootfrac_scr(ilyr) * & - donate_frac/newPatch%area + donate_m2 cur_litt%bg_cwd(ncwd,ilyr) = cur_litt%bg_cwd(ncwd,ilyr) + & bg_wood * currentSite%rootfrac_scr(ilyr) * & - retain_frac/remainder_area + retain_m2 end do flux_diags%cwd_bg_input(ncwd) = flux_diags%cwd_bg_input(ncwd) + & @@ -682,7 +977,7 @@ subroutine logging_litter_fluxes(currentSite, currentPatch, newPatch, patch_site ag_wood = direct_dead * (struct_m + sapw_m ) * & prt_params%allom_agb_frac(currentCohort%pft) * & - SF_val_CWD_frac(ncwd) + SF_val_CWD_frac_adj(ncwd) trunk_product_site = trunk_product_site + & ag_wood * logging_export_frac @@ -690,12 +985,12 @@ subroutine logging_litter_fluxes(currentSite, currentPatch, newPatch, patch_site ! This is for checking the total mass balance [kg/site/day] site_mass%wood_product = site_mass%wood_product + & ag_wood * logging_export_frac - + new_litt%ag_cwd(ncwd) = new_litt%ag_cwd(ncwd) + ag_wood * & - (1._r8-logging_export_frac)*donate_frac/newPatch%area + (1._r8-logging_export_frac)*donate_m2 cur_litt%ag_cwd(ncwd) = cur_litt%ag_cwd(ncwd) + ag_wood * & - (1._r8-logging_export_frac)*retain_frac/remainder_area + (1._r8-logging_export_frac)*retain_m2 ! --------------------------------------------------------------------------- ! Handle fluxes of leaf, root and storage carbon into litter pools. @@ -711,20 +1006,20 @@ subroutine logging_litter_fluxes(currentSite, currentPatch, newPatch, patch_site dcmpy_frac = GetDecompyFrac(pft,leaf_organ,dcmpy) new_litt%leaf_fines(dcmpy) = new_litt%leaf_fines(dcmpy) + & - leaf_litter * donate_frac/newPatch%area * dcmpy_frac + leaf_litter * donate_m2 * dcmpy_frac cur_litt%leaf_fines(dcmpy) = cur_litt%leaf_fines(dcmpy) + & - leaf_litter * retain_frac/remainder_area * dcmpy_frac + leaf_litter * retain_m2 * dcmpy_frac dcmpy_frac = GetDecompyFrac(pft,fnrt_organ,dcmpy) do ilyr = 1,nlevsoil new_litt%root_fines(dcmpy,ilyr) = new_litt%root_fines(dcmpy,ilyr) + & root_litter * currentSite%rootfrac_scr(ilyr) * dcmpy_frac * & - donate_frac/newPatch%area + donate_m2 cur_litt%root_fines(dcmpy,ilyr) = cur_litt%root_fines(dcmpy,ilyr) + & root_litter * currentSite%rootfrac_scr(ilyr) * dcmpy_frac * & - retain_frac/remainder_area + retain_m2 end do end do @@ -789,11 +1084,123 @@ subroutine logging_litter_fluxes(currentSite, currentPatch, newPatch, patch_site currentCohort => newPatch%shortest do while(associated(currentCohort)) call carea_allom(currentCohort%dbh,currentCohort%n,currentSite%spread, & - currentCohort%pft,currentCohort%c_area) + currentCohort%pft,currentCohort%crowndamage,currentCohort%c_area) currentCohort => currentCohort%taller enddo return end subroutine logging_litter_fluxes + + ! ===================================================================================== + + subroutine UpdateHarvestC(currentSite,bc_out) + + ! ---------------------------------------------------------------------------------- + ! Added by Shijie Shu. + ! This subroutine is called when logging is completed and need to update + ! Harvested C flux in HLM. + ! ---------------------------------------------------------------------------------- + use EDtypesMod , only : ed_site_type + use EDTypesMod , only : AREA_INV + use PRTGenericMod , only : element_pos + use PRTGenericMod , only : carbon12_element + use FatesInterfaceTypesMod , only : bc_out_type + use EDParamsMod , only : pprodharv10_forest_mean + + ! Arguments + type(ed_site_type), intent(inout), target :: currentSite ! site structure + type(bc_out_type), intent(inout) :: bc_out + + integer :: icode + real(r8) :: unit_trans_factor + + + ! Flush the older value before update + bc_out%hrv_deadstemc_to_prod10c = 0._r8 + bc_out%hrv_deadstemc_to_prod100c = 0._r8 + + ! Calculate the unit transfer factor (from kgC m-2 day-1 to gC m-2 s-1) + unit_trans_factor = g_per_kg * days_per_sec + + bc_out%hrv_deadstemc_to_prod10c = bc_out%hrv_deadstemc_to_prod10c + & + currentSite%mass_balance(element_pos(carbon12_element))%wood_product * & + AREA_INV * pprodharv10_forest_mean * unit_trans_factor + bc_out%hrv_deadstemc_to_prod100c = bc_out%hrv_deadstemc_to_prod100c + & + currentSite%mass_balance(element_pos(carbon12_element))%wood_product * & + AREA_INV * (1._r8 - pprodharv10_forest_mean) * unit_trans_factor + + return + + end subroutine UpdateHarvestC + + subroutine get_harvest_debt(site_in, bc_in, harvest_tag) + + ! + ! !DESCRIPTION: + ! + ! Calculate if we have harvest debt for primary and secondary land + ! Harvest debt is the accumulated total carbon + ! deficiency once the carbon amount available for harvest + ! is smaller than the harvest rate of forcing data. + ! Harvest debt is calculated on site level + ! TODO: we can define harvest debt as a fraction of the + ! harvest rate in the future + ! Note: Non-forest harvest is accounted for under forest + ! harvest, thus the harvest tag for non-forest is not applicable (= 2) + ! + ! !ARGUMENTS: + type(ed_site_type) , intent(inout), target :: site_in + type(bc_in_type), intent(in) :: bc_in + integer :: harvest_tag(hlm_num_lu_harvest_cats) + + ! !LOCAL VARIABLES: + integer :: h_index + real(r8) :: harvest_debt_pri + real(r8) :: harvest_debt_sec_mature + real(r8) :: harvest_debt_sec_young + + if(logging_time) then + + ! Initialize the local variables + harvest_debt_pri = 0._r8 + harvest_debt_sec_mature = 0._r8 + harvest_debt_sec_young = 0._r8 + + ! First we need to get harvest rate for all three categories + do h_index = 1, hlm_num_lu_harvest_cats + ! Primary forest harvest rate + if(bc_in%hlm_harvest_catnames(h_index) .eq. "HARVEST_VH1" .or. & + bc_in%hlm_harvest_catnames(h_index) .eq. "HARVEST_VH2" ) then + harvest_debt_pri = harvest_debt_pri + bc_in%hlm_harvest_rates(h_index) + else if(bc_in%hlm_harvest_catnames(h_index) .eq. "HARVEST_SH1") then + harvest_debt_sec_mature = harvest_debt_sec_mature + bc_in%hlm_harvest_rates(h_index) + else if(bc_in%hlm_harvest_catnames(h_index) .eq. "HARVEST_SH2" .or. & + bc_in%hlm_harvest_catnames(h_index) .eq. "HARVEST_SH3") then + harvest_debt_sec_young = harvest_debt_sec_young + bc_in%hlm_harvest_rates(h_index) + end if + end do + ! Next we get the harvest debt through the harvest tag + do h_index = 1, hlm_num_lu_harvest_cats + if (harvest_tag(h_index) .eq. 1) then + if(bc_in%hlm_harvest_catnames(h_index) .eq. "HARVEST_VH1") then + site_in%resources_management%harvest_debt = site_in%resources_management%harvest_debt + & + harvest_debt_pri + else if(bc_in%hlm_harvest_catnames(h_index) .eq. "HARVEST_SH1") then + site_in%resources_management%harvest_debt = site_in%resources_management%harvest_debt + & + harvest_debt_sec_mature + site_in%resources_management%harvest_debt_sec = site_in%resources_management%harvest_debt_sec + & + harvest_debt_sec_mature + else if(bc_in%hlm_harvest_catnames(h_index) .eq. "HARVEST_SH2") then + site_in%resources_management%harvest_debt = site_in%resources_management%harvest_debt + & + harvest_debt_sec_young + site_in%resources_management%harvest_debt_sec = site_in%resources_management%harvest_debt_sec + & + harvest_debt_sec_young + end if + end if + end do + end if + + end subroutine get_harvest_debt + end module EDLoggingMortalityMod diff --git a/biogeochem/EDMortalityFunctionsMod.F90 b/biogeochem/EDMortalityFunctionsMod.F90 index e4a0b3c138..bf47a5cce3 100644 --- a/biogeochem/EDMortalityFunctionsMod.F90 +++ b/biogeochem/EDMortalityFunctionsMod.F90 @@ -6,10 +6,12 @@ module EDMortalityFunctionsMod use FatesConstantsMod , only : r8 => fates_r8 use FatesGlobals , only : fates_log + use FatesGlobals , only : endrun => fates_endrun + use FatesGlobals , only : fates_log use EDPftvarcon , only : EDPftvarcon_inst - use EDTypesMod , only : ed_cohort_type + use FatesCohortMod , only : fates_cohort_type use EDTypesMod , only : ed_site_type - use EDTypesMod , only : ed_patch_type + use EDParamsMod, only : maxpft use FatesConstantsMod , only : itrue,ifalse use FatesAllometryMod , only : bleaf use FatesAllometryMod , only : storage_fraction_of_target @@ -17,18 +19,25 @@ module EDMortalityFunctionsMod use FatesInterfaceTypesMod , only : hlm_use_ed_prescribed_phys use FatesInterfaceTypesMod , only : hlm_freq_day use FatesInterfaceTypesMod , only : hlm_use_planthydro + use FatesInterfaceTypesMod , only : hlm_use_tree_damage use EDLoggingMortalityMod , only : LoggingMortality_frac use EDParamsMod , only : fates_mortality_disturbance_fraction - use PRTGenericMod, only : all_carbon_elements + use PRTGenericMod, only : carbon12_element use PRTGenericMod, only : store_organ - + use shr_log_mod , only : errMsg => shr_log_errMsg + implicit none private + + logical, parameter :: debug = .false. + character(len=*), parameter, private :: sourcefile = & + __FILE__ public :: mortality_rates public :: Mortality_Derivative + public :: ExemptTreefallDist ! ============================================================================ @@ -39,30 +48,33 @@ module EDMortalityFunctionsMod contains - - - subroutine mortality_rates( cohort_in,bc_in,cmort,hmort,bmort,frmort,smort,asmort ) + subroutine mortality_rates( cohort_in,bc_in,btran_ft, mean_temp, & + cmort,hmort,bmort, frmort,smort,asmort,dgmort ) ! ============================================================================ ! Calculate mortality rates from carbon storage, hydraulic cavitation, ! background and freezing and size and age dependent senescence ! ============================================================================ - use FatesConstantsMod, only : tfrz => t_water_freeze_k_1atm - use FatesInterfaceTypesMod , only : hlm_hio_ignore_val + use FatesConstantsMod, only : tfrz => t_water_freeze_k_1atm use FatesConstantsMod, only : fates_check_param_set + use DamageMainMod, only : GetDamageMortality - type (ed_cohort_type), intent(in) :: cohort_in + type (fates_cohort_type), intent(in) :: cohort_in type (bc_in_type), intent(in) :: bc_in + real(r8), intent(in) :: btran_ft(maxpft) + real(r8), intent(in) :: mean_temp real(r8),intent(out) :: bmort ! background mortality : Fraction per year real(r8),intent(out) :: cmort ! carbon starvation mortality real(r8),intent(out) :: hmort ! hydraulic failure mortality real(r8),intent(out) :: frmort ! freezing stress mortality real(r8),intent(out) :: smort ! size dependent senescence term - real(r8),intent(out) :: asmort ! age dependent senescence term + real(r8),intent(out) :: asmort ! age dependent senescence term + real(r8),intent(out) :: dgmort ! damage dependent mortality real(r8) :: frac ! relativised stored carbohydrate - real(r8) :: leaf_c_target ! target leaf biomass kgC + real(r8) :: target_leaf_c ! target leaf biomass for the current trim status and + ! damage class [kgC] real(r8) :: store_c real(r8) :: hf_sm_threshold ! hydraulic failure soil moisture threshold real(r8) :: hf_flc_threshold ! hydraulic failure fractional loss of conductivity threshold @@ -81,7 +93,9 @@ subroutine mortality_rates( cohort_in,bc_in,cmort,hmort,bmort,frmort,smort,asmor logical, parameter :: test_zero_mortality = .false. ! Developer test which ! may help to debug carbon imbalances ! and the like - + + + ! Size Dependent Senescence ! rate (r) and inflection point (ip) define the increase in mortality rate with dbh mort_r_size_senescence = EDPftvarcon_inst%mort_r_size_senescence(cohort_in%pft) @@ -96,9 +110,6 @@ subroutine mortality_rates( cohort_in,bc_in,cmort,hmort,bmort,frmort,smort,asmor end if ! if param values have been set then calculate asmort - - - mort_r_age_senescence = EDPftvarcon_inst%mort_r_age_senescence(cohort_in%pft) mort_ip_age_senescence = EDPftvarcon_inst%mort_ip_age_senescence(cohort_in%pft) @@ -112,76 +123,89 @@ subroutine mortality_rates( cohort_in,bc_in,cmort,hmort,bmort,frmort,smort,asmor asmort = 0.0_r8 end if + ! Damage dependent mortality + if (hlm_use_tree_damage .eq. itrue) then + call GetDamageMortality(cohort_in%crowndamage, cohort_in%pft, dgmort) + else + dgmort = 0.0_r8 + end if -if (hlm_use_ed_prescribed_phys .eq. ifalse) then + if (hlm_use_ed_prescribed_phys .eq. ifalse) then + + ! 'Background' mortality (can vary as a function of + ! density as in ED1.0 and ED2.0, but doesn't here for tractability) - ! 'Background' mortality (can vary as a function of - ! density as in ED1.0 and ED2.0, but doesn't here for tractability) - bmort = EDPftvarcon_inst%bmort(cohort_in%pft) - ! Proxy for hydraulic failure induced mortality. - hf_sm_threshold = EDPftvarcon_inst%hf_sm_threshold(cohort_in%pft) - hf_flc_threshold = EDPftvarcon_inst%hf_flc_threshold(cohort_in%pft) - if(hlm_use_planthydro.eq.itrue)then - !note the flc is set as the fraction of max conductivity in hydro - min_fmc_ag = minval(cohort_in%co_hydr%ftc_ag(:)) - min_fmc_tr = cohort_in%co_hydr%ftc_troot - min_fmc_ar = minval(cohort_in%co_hydr%ftc_aroot(:)) - min_fmc = min(min_fmc_ag, min_fmc_tr) - min_fmc = min(min_fmc, min_fmc_ar) - flc = 1.0_r8-min_fmc - if(flc >= hf_flc_threshold .and. hf_flc_threshold < 1.0_r8 )then - hmort = (flc-hf_flc_threshold)/(1.0_r8-hf_flc_threshold) * & - EDPftvarcon_inst%mort_scalar_hydrfailure(cohort_in%pft) - else - hmort = 0.0_r8 - endif - else - if(cohort_in%patchptr%btran_ft(cohort_in%pft) <= hf_sm_threshold)then - hmort = EDPftvarcon_inst%mort_scalar_hydrfailure(cohort_in%pft) - else - hmort = 0.0_r8 - endif - endif - - ! Carbon Starvation induced mortality. - if ( cohort_in%dbh > 0._r8 ) then + ! Proxy for hydraulic failure induced mortality. + hf_sm_threshold = EDPftvarcon_inst%hf_sm_threshold(cohort_in%pft) + hf_flc_threshold = EDPftvarcon_inst%hf_flc_threshold(cohort_in%pft) + if(hlm_use_planthydro.eq.itrue)then + !note the flc is set as the fraction of max conductivity in hydro + min_fmc_ag = minval(cohort_in%co_hydr%ftc_ag(:)) + min_fmc_tr = cohort_in%co_hydr%ftc_troot + min_fmc_ar = minval(cohort_in%co_hydr%ftc_aroot(:)) + min_fmc = min(min_fmc_ag, min_fmc_tr) + min_fmc = min(min_fmc, min_fmc_ar) + flc = 1.0_r8-min_fmc + if(flc >= hf_flc_threshold .and. hf_flc_threshold < 1.0_r8 )then + hmort = (flc-hf_flc_threshold)/(1.0_r8-hf_flc_threshold) * & + EDPftvarcon_inst%mort_scalar_hydrfailure(cohort_in%pft) + else + hmort = 0.0_r8 + endif + else + if(btran_ft(cohort_in%pft) <= hf_sm_threshold)then + hmort = EDPftvarcon_inst%mort_scalar_hydrfailure(cohort_in%pft) + else + hmort = 0.0_r8 + endif + endif - call bleaf(cohort_in%dbh,cohort_in%pft,cohort_in%canopy_trim,leaf_c_target) - store_c = cohort_in%prt%GetState(store_organ,all_carbon_elements) + ! Carbon Starvation induced mortality. + if ( cohort_in%dbh > 0._r8 ) then + + ! We compare storage with leaf biomass if plant were fully flushed, otherwise + ! mortality would be underestimated for plants that lost all leaves and have no + ! storage to flush new ones. + ! MLO. Why isn't this comparing with storage allometry (i.e., accounting for + ! cushion)? + call bleaf(cohort_in%dbh,cohort_in%pft,cohort_in%crowndamage,cohort_in%canopy_trim, & + 1.0_r8, target_leaf_c) + store_c = cohort_in%prt%GetState(store_organ,carbon12_element) + + call storage_fraction_of_target(target_leaf_c, store_c, frac) + if( frac .lt. 1._r8) then + cmort = max(0.0_r8,EDPftvarcon_inst%mort_scalar_cstarvation(cohort_in%pft) * & + (1.0_r8 - frac)) + else + cmort = 0.0_r8 + endif - call storage_fraction_of_target(leaf_c_target, store_c, frac) - if( frac .lt. 1._r8) then - cmort = max(0.0_r8,EDPftvarcon_inst%mort_scalar_cstarvation(cohort_in%pft) * & - (1.0_r8 - frac)) + else - cmort = 0.0_r8 + write(fates_log(),*) 'dbh problem in mortality_rates', & + cohort_in%dbh,cohort_in%pft,cohort_in%n,cohort_in%canopy_layer + call endrun(msg=errMsg(sourcefile, __LINE__)) endif - - else - write(fates_log(),*) 'dbh problem in mortality_rates', & - cohort_in%dbh,cohort_in%pft,cohort_in%n,cohort_in%canopy_layer - endif - !-------------------------------------------------------------------------------- - ! Mortality due to cold and freezing stress (frmort), based on ED2 and: - ! Albani, M.; D. Medvigy; G. C. Hurtt; P. R. Moorcroft, 2006: The contributions - ! of land-use change, CO2 fertilization, and climate variability to the - ! Eastern US carbon sink. Glob. Change Biol., 12, 2370-2390, - ! doi: 10.1111/j.1365-2486.2006.01254.x - - temp_in_C = cohort_in%patchptr%tveg24%GetMean() - tfrz + !-------------------------------------------------------------------------------- + ! Mortality due to cold and freezing stress (frmort), based on ED2 and: + ! Albani, M.; D. Medvigy; G. C. Hurtt; P. R. Moorcroft, 2006: The contributions + ! of land-use change, CO2 fertilization, and climate variability to the + ! Eastern US carbon sink. Glob. Change Biol., 12, 2370-2390, + ! doi: 10.1111/j.1365-2486.2006.01254.x + + temp_in_C = mean_temp - tfrz - temp_dep_fraction = max(0.0_r8, min(1.0_r8, 1.0_r8 - (temp_in_C - & - EDPftvarcon_inst%freezetol(cohort_in%pft))/frost_mort_buffer) ) - frmort = EDPftvarcon_inst%mort_scalar_coldstress(cohort_in%pft) * temp_dep_fraction + temp_dep_fraction = max(0.0_r8, min(1.0_r8, 1.0_r8 - (temp_in_C - & + EDPftvarcon_inst%freezetol(cohort_in%pft))/frost_mort_buffer) ) + frmort = EDPftvarcon_inst%mort_scalar_coldstress(cohort_in%pft) * temp_dep_fraction + !mortality_rates = bmort + hmort + cmort - !mortality_rates = bmort + hmort + cmort + else ! i.e. hlm_use_ed_prescribed_phys is true - else ! i.e. hlm_use_ed_prescribed_phys is true - if ( cohort_in%canopy_layer .eq. 1) then bmort = EDPftvarcon_inst%prescribed_mortality_canopy(cohort_in%pft) else @@ -199,14 +223,17 @@ subroutine mortality_rates( cohort_in,bc_in,cmort,hmort,bmort,frmort,smort,asmor bmort = 0.0_r8 smort = 0.0_r8 asmort = 0.0_r8 + dgmort = 0.0_r8 end if - + return end subroutine mortality_rates ! ============================================================================ - subroutine Mortality_Derivative( currentSite, currentCohort, bc_in, frac_site_primary) + subroutine Mortality_Derivative( currentSite, currentCohort, bc_in, btran_ft, & + mean_temp, anthro_disturbance_label, age_since_anthro_disturbance, & + frac_site_primary, harvestable_forest_c, harvest_tag) ! ! !DESCRIPTION: @@ -215,14 +242,25 @@ subroutine Mortality_Derivative( currentSite, currentCohort, bc_in, frac_site_pr ! elsewhere). ! ! !USES: - use FatesInterfaceTypesMod, only : hlm_freq_day ! ! !ARGUMENTS type(ed_site_type), intent(inout), target :: currentSite - type(ed_cohort_type),intent(inout), target :: currentCohort + type(fates_cohort_type),intent(inout), target :: currentCohort type(bc_in_type), intent(in) :: bc_in - real(r8), intent(in) :: frac_site_primary + real(r8), intent(in) :: btran_ft(maxpft) + real(r8), intent(in) :: mean_temp + integer, intent(in) :: anthro_disturbance_label + real(r8), intent(in) :: age_since_anthro_disturbance + real(r8), intent(in) :: frac_site_primary + + real(r8), intent(in) :: harvestable_forest_c(:) ! total carbon available for logging, kgC site-1 + integer, intent(out) :: harvest_tag(:) ! tag to record the harvest status + ! for the calculation of harvest debt in C-based + ! harvest mode + ! 0 - successful; + ! 1 - unsuccessful since not enough carbon + ! 2 - not applicable ! ! !LOCAL VARIABLES: real(r8) :: cmort ! starvation mortality rate (fraction per year) @@ -231,15 +269,18 @@ subroutine Mortality_Derivative( currentSite, currentCohort, bc_in, frac_site_pr real(r8) :: frmort ! freezing mortality rate (fraction per year) real(r8) :: smort ! size dependent senescence mortality rate (fraction per year) real(r8) :: asmort ! age dependent senescence mortality rate (fraction per year) + real(r8) :: dgmort ! damage mortality (fraction per year) real(r8) :: dndt_logging ! Mortality rate (per day) associated with the a logging event integer :: ipft ! local copy of the pft index - !---------------------------------------------------------------------- + + !---------------------------------------------------------------------- ipft = currentCohort%pft ! Mortality for trees in the understorey. !if trees are in the canopy, then their death is 'disturbance'. This probably needs a different terminology - call mortality_rates(currentCohort,bc_in,cmort,hmort,bmort,frmort,smort, asmort) + call mortality_rates(currentCohort,bc_in,btran_ft, mean_temp, & + cmort,hmort,bmort,frmort, smort, asmort, dgmort) call LoggingMortality_frac(ipft, currentCohort%dbh, currentCohort%canopy_layer, & currentCohort%lmort_direct, & currentCohort%lmort_collateral, & @@ -248,12 +289,9 @@ subroutine Mortality_Derivative( currentSite, currentCohort, bc_in, frac_site_pr bc_in%hlm_harvest_rates, & bc_in%hlm_harvest_catnames, & bc_in%hlm_harvest_units, & - currentCohort%patchptr%anthro_disturbance_label, & - currentCohort%patchptr%age_since_anthro_disturbance, & - frac_site_primary) - - - + anthro_disturbance_label, & + age_since_anthro_disturbance, & + frac_site_primary, harvestable_forest_c, harvest_tag) if (currentCohort%canopy_layer > 1)then ! Include understory logging mortality rates not associated with disturbance @@ -263,17 +301,20 @@ subroutine Mortality_Derivative( currentSite, currentCohort, bc_in, frac_site_pr currentCohort%dndt = -1.0_r8 * & - (cmort+hmort+bmort+frmort+smort+asmort + dndt_logging) & + (cmort+hmort+bmort+frmort+smort+asmort+dgmort + dndt_logging) & * currentCohort%n else - - ! Mortality from logging in the canopy is ONLY disturbance generating, don't ! update number densities via non-disturbance inducing death - currentCohort%dndt= -(1.0_r8-fates_mortality_disturbance_fraction) & - * (cmort+hmort+bmort+frmort+smort+asmort) * & - currentCohort%n + ! for plants whose death is not considered disturbance (i.e. grasses), + ! need to include all of their mortality here rather than part of it here + ! and part in disturbance routine. + + currentCohort%dndt= -(cmort+hmort+bmort+frmort+smort+asmort+dgmort) * currentCohort%n + if ( .not. ExemptTreefallDist(currentCohort)) then + currentCohort%dndt = (1.0_r8-fates_mortality_disturbance_fraction) * currentCohort%dndt + endif endif @@ -281,4 +322,32 @@ subroutine Mortality_Derivative( currentSite, currentCohort, bc_in, frac_site_pr end subroutine Mortality_Derivative + ! ============================================================================ + + function ExemptTreefallDist(ccohort) result(is_exempt) + + use PRTParametersMod , only : prt_params + + ! ============================================================================ + ! Determine whether or not to consider some fraction of a cohort's crown + ! area as disturbed patch area when individuals of that cohort die. + ! ============================================================================ + + ! Arguments + type(fates_cohort_type),intent(in), target :: ccohort + + logical :: is_exempt ! if true, then treat all mortality from this cohort as non-disturbance-generating + + !! current logic is only to exempt non-woody plants + + if ( prt_params%woody(ccohort%pft) == ifalse ) then + is_exempt = .true. + else + is_exempt = .false. + endif + + return + + end function ExemptTreefallDist + end module EDMortalityFunctionsMod diff --git a/biogeochem/EDPatchDynamicsMod.F90 b/biogeochem/EDPatchDynamicsMod.F90 index 0236e91f08..e84658ef86 100644 --- a/biogeochem/EDPatchDynamicsMod.F90 +++ b/biogeochem/EDPatchDynamicsMod.F90 @@ -3,63 +3,73 @@ module EDPatchDynamicsMod ! ============================================================================ ! Controls formation, creation, fusing and termination of patch level processes. ! ============================================================================ - use FatesGlobals , only : fates_log - use FatesInterfaceTypesMod , only : hlm_freq_day + use FatesGlobals , only : fates_log + use FatesGlobals , only : FatesWarn,N2S,A2S + use FatesInterfaceTypesMod, only : hlm_freq_day + use FatesInterfaceTypesMod, only : hlm_current_tod use EDPftvarcon , only : EDPftvarcon_inst use EDPftvarcon , only : GetDecompyFrac use PRTParametersMod , only : prt_params use EDCohortDynamicsMod , only : fuse_cohorts, sort_cohorts, insert_cohort - use EDCohortDynamicsMod , only : DeallocateCohort use EDTypesMod , only : area_site => area use ChecksBalancesMod , only : PatchMassStock use FatesLitterMod , only : ncwd use FatesLitterMod , only : ndcmpy use FatesLitterMod , only : litter_type + use FatesConstantsMod , only : n_dbh_bins + use FatesLitterMod , only : adjust_SF_CWD_frac use EDTypesMod , only : homogenize_seed_pfts - use EDTypesMod , only : n_dbh_bins, area, patchfusion_dbhbin_loweredges + use EDTypesMod , only : area + use FatesConstantsMod , only : patchfusion_dbhbin_loweredges use EDtypesMod , only : force_patchfuse_min_biomass - use EDTypesMod , only : maxPatchesPerSite - use EDTypesMod , only : maxPatchesPerSite_by_disttype - use EDTypesMod , only : ed_site_type, ed_patch_type, ed_cohort_type + use EDTypesMod , only : ed_site_type + use FatesPatchMod, only : fates_patch_type + use FatesCohortMod , only : fates_cohort_type use EDTypesMod , only : site_massbal_type use EDTypesMod , only : site_fluxdiags_type use EDTypesMod , only : min_patch_area use EDTypesMod , only : min_patch_area_forced - use EDTypesMod , only : nclmax - use EDTypesMod , only : maxpft - use EDTypesMod , only : dtype_ifall - use EDTypesMod , only : dtype_ilog - use EDTypesMod , only : dtype_ifire - use EDTypesMod , only : ican_upper + use EDParamsMod , only : nclmax + use EDParamsMod , only : regeneration_model + use FatesInterfaceTypesMod, only : numpft + use FatesConstantsMod , only : dtype_ifall + use FatesConstantsMod , only : dtype_ilog + use FatesConstantsMod , only : dtype_ifire + use FatesConstantsMod , only : ican_upper use PRTGenericMod , only : num_elements use PRTGenericMod , only : element_list - use EDTypesMod , only : lg_sf - use EDTypesMod , only : dl_sf - use EDTypesMod , only : dump_patch - use EDTypesMod , only : N_DIST_TYPES + use FatesLitterMod , only : lg_sf + use FatesLitterMod , only : dl_sf + use FatesConstantsMod , only : N_DIST_TYPES use EDTypesMod , only : AREA_INV use FatesConstantsMod , only : rsnbl_math_prec use FatesConstantsMod , only : fates_tiny + use FatesConstantsMod , only : nocomp_bareground use FatesInterfaceTypesMod , only : hlm_use_planthydro use FatesInterfaceTypesMod , only : hlm_numSWb use FatesInterfaceTypesMod , only : bc_in_type - use FatesInterfaceTypesMod , only : hlm_days_per_year use FatesInterfaceTypesMod , only : numpft use FatesInterfaceTypesMod , only : hlm_stepsize use FatesInterfaceTypesMod , only : hlm_use_sp use FatesInterfaceTypesMod , only : hlm_use_nocomp use FatesInterfaceTypesMod , only : hlm_use_fixed_biogeog + use FatesInterfaceTypesMod , only : hlm_num_lu_harvest_cats use FatesGlobals , only : endrun => fates_endrun 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 use EDLoggingMortalityMod, only : logging_litter_fluxes use EDLoggingMortalityMod, only : logging_time use EDLoggingMortalityMod, only : get_harvest_rate_area + use EDLoggingMortalityMod, only : get_harvest_rate_carbon + 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 @@ -71,10 +81,9 @@ module EDPatchDynamicsMod use FatesConstantsMod , only : n_anthro_disturbance_categories use FatesConstantsMod , only : fates_unset_r8 use FatesConstantsMod , only : fates_unset_int + use FatesConstantsMod , only : hlm_harvest_carbon use EDCohortDynamicsMod , only : InitPRTObject - use EDCohortDynamicsMod , only : InitPRTBoundaryConditions use ChecksBalancesMod, only : SiteMassStock - use PRTGenericMod, only : all_carbon_elements use PRTGenericMod, only : carbon12_element use PRTGenericMod, only : leaf_organ use PRTGenericMod, only : fnrt_organ @@ -89,7 +98,12 @@ 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_sdlng_mdd + use FatesRunningMeanMod, only : ema_sdlng_emerg_h2o, ema_sdlng_mort_par, ema_sdlng2sap_par + use EDParamsMod, only : maxpatch_primary + use EDParamsMod, only : maxpatch_secondary + use EDParamsMod, only : maxpatch_total + use FatesRunningMeanMod, only : ema_24hr, fixed_24hr, ema_lpa, ema_longterm ! CIME globals use shr_infnan_mod , only : nan => shr_infnan_nan, assignment(=) @@ -98,10 +112,8 @@ module EDPatchDynamicsMod ! implicit none private - ! - public :: create_patch + public :: spawn_patches - public :: zero_patch public :: fuse_patches public :: terminate_patches public :: patch_pft_size_profile @@ -135,7 +147,10 @@ module EDPatchDynamicsMod real(r8), parameter :: treefall_localization = 0.0_r8 real(r8), parameter :: burn_localization = 0.0_r8 - + integer :: istat ! return status code + character(len=255) :: smsg ! Message string for deallocation errors + character(len=512) :: msg ! Message string for warnings and logging + ! 10/30/09: Created by Rosie Fisher ! ============================================================================ @@ -155,17 +170,18 @@ subroutine disturbance_rates( site_in, bc_in) ! !USES: use EDMortalityFunctionsMod , only : mortality_rates + use EDMortalityFunctionsMod , only : ExemptTreefallDist ! loging flux use EDLoggingMortalityMod , only : LoggingMortality_frac ! !ARGUMENTS: - type(ed_site_type) , intent(inout), target :: site_in + type(ed_site_type) , intent(inout) :: site_in type(bc_in_type) , intent(in) :: bc_in ! ! !LOCAL VARIABLES: - type (ed_patch_type) , pointer :: currentPatch - type (ed_cohort_type), pointer :: currentCohort + type (fates_patch_type) , pointer :: currentPatch + type (fates_cohort_type), pointer :: currentCohort real(r8) :: cmort real(r8) :: bmort @@ -173,7 +189,8 @@ subroutine disturbance_rates( site_in, bc_in) real(r8) :: frmort real(r8) :: smort real(r8) :: asmort - + real(r8) :: dgmort + real(r8) :: lmort_direct real(r8) :: lmort_collateral real(r8) :: lmort_infra @@ -183,8 +200,13 @@ subroutine disturbance_rates( site_in, bc_in) real(r8) :: dist_rate_ldist_notharvested integer :: threshold_sizeclass integer :: i_dist + integer :: h_index real(r8) :: frac_site_primary real(r8) :: harvest_rate + real(r8) :: tempsum + real(r8) :: mean_temp + real(r8) :: harvestable_forest_c(hlm_num_lu_harvest_cats) + integer :: harvest_tag(hlm_num_lu_harvest_cats) !---------------------------------------------------------------------------------------------- ! Calculate Mortality Rates (these were previously calculated during growth derivatives) @@ -193,21 +215,23 @@ subroutine disturbance_rates( site_in, bc_in) ! first calculate the fractino of the site that is primary land call get_frac_site_primary(site_in, frac_site_primary) - - site_in%harvest_carbon_flux = 0._r8 + ! get available biomass for harvest for all patches + call get_harvestable_carbon(site_in, bc_in%site_area, bc_in%hlm_harvest_catnames, harvestable_forest_c) + currentPatch => site_in%oldest_patch do while (associated(currentPatch)) currentCohort => currentPatch%shortest do while(associated(currentCohort)) ! Mortality for trees in the understorey. - currentCohort%patchptr => currentPatch - - call mortality_rates(currentCohort,bc_in,cmort,hmort,bmort,frmort,smort,asmort) - currentCohort%dmort = cmort+hmort+bmort+frmort+smort+asmort + !currentCohort%patchptr => currentPatch + mean_temp = currentPatch%tveg24%GetMean() + call mortality_rates(currentCohort,bc_in,currentPatch%btran_ft, & + mean_temp, cmort,hmort,bmort,frmort,smort,asmort,dgmort) + currentCohort%dmort = cmort+hmort+bmort+frmort+smort+asmort+dgmort call carea_allom(currentCohort%dbh,currentCohort%n,site_in%spread,currentCohort%pft, & - currentCohort%c_area) + currentCohort%crowndamage,currentCohort%c_area) ! Initialize diagnostic mortality rates currentCohort%cmort = cmort @@ -216,7 +240,8 @@ subroutine disturbance_rates( site_in, bc_in) currentCohort%frmort = frmort currentCohort%smort = smort currentCohort%asmort = asmort - + currentCohort%dgmort = dgmort + call LoggingMortality_frac(currentCohort%pft, currentCohort%dbh, currentCohort%canopy_layer, & lmort_direct,lmort_collateral,lmort_infra,l_degrad,& bc_in%hlm_harvest_rates, & @@ -224,29 +249,23 @@ subroutine disturbance_rates( site_in, bc_in) bc_in%hlm_harvest_units, & currentPatch%anthro_disturbance_label, & currentPatch%age_since_anthro_disturbance, & - frac_site_primary) + frac_site_primary, & + harvestable_forest_c, & + harvest_tag) currentCohort%lmort_direct = lmort_direct currentCohort%lmort_collateral = lmort_collateral currentCohort%lmort_infra = lmort_infra currentCohort%l_degrad = l_degrad - ! estimate the wood product (trunk_product_site) - if (currentCohort%canopy_layer>=1) then - site_in%harvest_carbon_flux = site_in%harvest_carbon_flux + & - currentCohort%lmort_direct * currentCohort%n * & - ( currentCohort%prt%GetState(sapw_organ, all_carbon_elements) + & - currentCohort%prt%GetState(struct_organ, all_carbon_elements)) * & - prt_params%allom_agb_frac(currentCohort%pft) * & - SF_val_CWD_frac(ncwd) * logging_export_frac - endif - currentCohort => currentCohort%taller end do - currentPatch%disturbance_mode = fates_unset_int + currentPatch => currentPatch%younger end do + call get_harvest_debt(site_in, bc_in, harvest_tag) + ! --------------------------------------------------------------------------------------------- ! Calculate Disturbance Rates based on the mortality rates just calculated ! --------------------------------------------------------------------------------------------- @@ -282,10 +301,12 @@ subroutine disturbance_rates( site_in, bc_in) if(currentCohort%canopy_layer == 1)then - ! Treefall Disturbance Rate - currentPatch%disturbance_rates(dtype_ifall) = currentPatch%disturbance_rates(dtype_ifall) + & - fates_mortality_disturbance_fraction * & - min(1.0_r8,currentCohort%dmort)*hlm_freq_day*currentCohort%c_area/currentPatch%area + ! Treefall Disturbance Rate. Only count this for trees, not grasses + if ( .not. ExemptTreefallDist(currentCohort) ) then + currentPatch%disturbance_rates(dtype_ifall) = currentPatch%disturbance_rates(dtype_ifall) + & + fates_mortality_disturbance_fraction * & + min(1.0_r8,currentCohort%dmort)*hlm_freq_day*currentCohort%c_area/currentPatch%area + end if ! Logging Disturbance Rate currentPatch%disturbance_rates(dtype_ilog) = currentPatch%disturbance_rates(dtype_ilog) + & @@ -294,6 +315,11 @@ subroutine disturbance_rates( site_in, bc_in) currentCohort%lmort_infra + & currentCohort%l_degrad ) * & currentCohort%c_area/currentPatch%area + + if(currentPatch%disturbance_rates(dtype_ilog)>1.0) then + write(fates_log(),*) 'See luc mortalities:', currentCohort%lmort_direct, & + currentCohort%lmort_collateral, currentCohort%lmort_infra, currentCohort%l_degrad + end if ! Non-harvested part of the logging disturbance rate dist_rate_ldist_notharvested = dist_rate_ldist_notharvested + currentCohort%l_degrad * & @@ -304,13 +330,19 @@ subroutine disturbance_rates( site_in, bc_in) enddo !currentCohort ! for non-closed-canopy areas subject to logging, add an additional increment of area disturbed - ! equivalent to the fradction loged to account for transfer of interstitial ground area to new secondary lands + ! equivalent to the fraction logged to account for transfer of interstitial ground area to new secondary lands if ( logging_time .and. & (currentPatch%area - currentPatch%total_canopy_area) .gt. fates_tiny ) then ! The canopy is NOT closed. - call get_harvest_rate_area (currentPatch%anthro_disturbance_label, bc_in%hlm_harvest_catnames, & - bc_in%hlm_harvest_rates, frac_site_primary, currentPatch%age_since_anthro_disturbance, harvest_rate) + if(bc_in%hlm_harvest_units == hlm_harvest_carbon) then + call get_harvest_rate_carbon (currentPatch%anthro_disturbance_label, bc_in%hlm_harvest_catnames, & + bc_in%hlm_harvest_rates, currentPatch%age_since_anthro_disturbance, harvestable_forest_c, & + harvest_rate, harvest_tag) + else + call get_harvest_rate_area (currentPatch%anthro_disturbance_label, bc_in%hlm_harvest_catnames, & + bc_in%hlm_harvest_rates, frac_site_primary, currentPatch%age_since_anthro_disturbance, harvest_rate) + end if currentPatch%disturbance_rates(dtype_ilog) = currentPatch%disturbance_rates(dtype_ilog) + & (currentPatch%area - currentPatch%total_canopy_area) * harvest_rate / currentPatch%area @@ -320,6 +352,12 @@ subroutine disturbance_rates( site_in, bc_in) (currentPatch%area - currentPatch%total_canopy_area) * harvest_rate / currentPatch%area endif + ! For nocomp mode, we need to prevent producing too small patches, which may produce small patches + if ((hlm_use_nocomp .eq. itrue) .and. & + (currentPatch%disturbance_rates(dtype_ilog)*currentPatch%area .lt. min_patch_area_forced)) then + currentPatch%disturbance_rates(dtype_ilog) = 0._r8 + end if + ! fraction of the logging disturbance rate that is non-harvested if (currentPatch%disturbance_rates(dtype_ilog) .gt. nearzero) then currentPatch%fract_ldist_not_harvested = dist_rate_ldist_notharvested / & @@ -336,96 +374,17 @@ subroutine disturbance_rates( site_in, bc_in) end do ! Fires can't burn the whole patch, as this causes /0 errors. - if (debug) then - if (currentPatch%disturbance_rates(dtype_ifire) > 0.98_r8)then - write(fates_log(),*) 'very high fire areas', & - currentPatch%disturbance_rates(dtype_ifire),currentPatch%frac_burnt - endif + if (currentPatch%disturbance_rates(dtype_ifire) > 0.98_r8)then + msg = 'very high fire areas'//trim(A2S(currentPatch%disturbance_rates(:)))//trim(N2S(currentPatch%frac_burnt)) + call FatesWarn(msg,index=2) endif - - - ! ------------------------------------------------------------------------------------------ - ! Determine which disturbance is dominant, and force mortality diagnostics in the upper - ! canopy to be zero for the non-dominant mode. Note: upper-canopy tree-fall mortality is - ! not always disturbance generating, so when tree-fall mort is non-dominant, make sure - ! to still diagnose and track the non-disturbance rate - ! ------------------------------------------------------------------------------------------ - - ! DISTURBANCE IS LOGGING - if (currentPatch%disturbance_rates(dtype_ilog) > currentPatch%disturbance_rates(dtype_ifall) .and. & - currentPatch%disturbance_rates(dtype_ilog) > currentPatch%disturbance_rates(dtype_ifire) ) then - - currentPatch%disturbance_rate = currentPatch%disturbance_rates(dtype_ilog) - currentPatch%disturbance_mode = dtype_ilog - - ! Update diagnostics - currentCohort => currentPatch%shortest - do while(associated(currentCohort)) - if(currentCohort%canopy_layer == 1)then - currentCohort%cmort = currentCohort%cmort*(1.0_r8 - fates_mortality_disturbance_fraction) - currentCohort%hmort = currentCohort%hmort*(1.0_r8 - fates_mortality_disturbance_fraction) - currentCohort%bmort = currentCohort%bmort*(1.0_r8 - fates_mortality_disturbance_fraction) - currentCohort%dmort = currentCohort%dmort*(1.0_r8 - fates_mortality_disturbance_fraction) - currentCohort%frmort = currentCohort%frmort*(1.0_r8 - fates_mortality_disturbance_fraction) - currentCohort%smort = currentCohort%smort*(1.0_r8 - fates_mortality_disturbance_fraction) - currentCohort%asmort = currentCohort%asmort*(1.0_r8 - fates_mortality_disturbance_fraction) - end if - currentCohort => currentCohort%taller - enddo !currentCohort - - ! DISTURBANCE IS FIRE - elseif (currentPatch%disturbance_rates(dtype_ifire) > currentPatch%disturbance_rates(dtype_ifall) .and. & - currentPatch%disturbance_rates(dtype_ifire) > currentPatch%disturbance_rates(dtype_ilog) ) then - - currentPatch%disturbance_rate = currentPatch%disturbance_rates(dtype_ifire) - currentPatch%disturbance_mode = dtype_ifire - - ! Update diagnostics, zero non-fire mortality rates - currentCohort => currentPatch%shortest - do while(associated(currentCohort)) - if(currentCohort%canopy_layer == 1)then - currentCohort%cmort = currentCohort%cmort*(1.0_r8 - fates_mortality_disturbance_fraction) - currentCohort%hmort = currentCohort%hmort*(1.0_r8 - fates_mortality_disturbance_fraction) - currentCohort%bmort = currentCohort%bmort*(1.0_r8 - fates_mortality_disturbance_fraction) - currentCohort%dmort = currentCohort%dmort*(1.0_r8 - fates_mortality_disturbance_fraction) - currentCohort%frmort = currentCohort%frmort*(1.0_r8 - fates_mortality_disturbance_fraction) - currentCohort%smort = currentCohort%smort*(1.0_r8 - fates_mortality_disturbance_fraction) - currentCohort%asmort = currentCohort%asmort*(1.0_r8 - fates_mortality_disturbance_fraction) - currentCohort%lmort_direct = 0.0_r8 - currentCohort%lmort_collateral = 0.0_r8 - currentCohort%lmort_infra = 0.0_r8 - currentCohort%l_degrad = 0.0_r8 - end if - - ! This may be counter-intuitive, but the diagnostic fire-mortality rate - ! will stay zero in the patch that undergoes fire, this is because - ! the actual cohorts who experience the fire are only those in the - ! newly created patch so currentCohort%fmort = 0.0_r8 - ! Don't worry, the cohorts in the newly created patch will reflect burn - - currentCohort => currentCohort%taller - enddo !currentCohort - - else ! If fire and logging are not greater than treefall, just set disturbance rate to tree-fall - ! which is most likely a 0.0 - - currentPatch%disturbance_rate = currentPatch%disturbance_rates(dtype_ifall) - currentPatch%disturbance_mode = dtype_ifall - - ! Update diagnostics, zero non-treefall mortality rates - currentCohort => currentPatch%shortest - do while(associated(currentCohort)) - if(currentCohort%canopy_layer == 1)then - currentCohort%lmort_direct = 0.0_r8 - currentCohort%lmort_collateral = 0.0_r8 - currentCohort%lmort_infra = 0.0_r8 - currentCohort%l_degrad = 0.0_r8 - end if - currentCohort => currentCohort%taller - enddo !currentCohort - - + ! if the sum of all disturbance rates is such that they will exceed total patch area on this day, then reduce them all proportionally. + if ( sum(currentPatch%disturbance_rates(:)) .gt. 1.0_r8 ) then + tempsum = sum(currentPatch%disturbance_rates(:)) + do i_dist = 1,N_DIST_TYPES + currentPatch%disturbance_rates(i_dist) = currentPatch%disturbance_rates(i_dist) / tempsum + end do endif currentPatch => currentPatch%younger @@ -454,28 +413,29 @@ subroutine spawn_patches( currentSite, bc_in) ! !USES: use EDParamsMod , only : ED_val_understorey_death, logging_coll_under_frac - use EDCohortDynamicsMod , only : zero_cohort, copy_cohort, terminate_cohorts + use EDCohortDynamicsMod , only : terminate_cohorts use FatesConstantsMod , only : rsnbl_math_prec ! ! !ARGUMENTS: - type (ed_site_type), intent(inout), target :: currentSite - type (bc_in_type), intent(in) :: bc_in + type (ed_site_type), intent(inout) :: currentSite + type (bc_in_type), intent(in) :: bc_in ! ! !LOCAL VARIABLES: - type (ed_patch_type) , pointer :: new_patch - type (ed_patch_type) , pointer :: new_patch_primary - type (ed_patch_type) , pointer :: new_patch_secondary - type (ed_patch_type) , pointer :: currentPatch - type (ed_cohort_type), pointer :: currentCohort - type (ed_cohort_type), pointer :: nc - type (ed_cohort_type), pointer :: storesmallcohort - type (ed_cohort_type), pointer :: storebigcohort + type (fates_patch_type) , pointer :: new_patch + type (fates_patch_type) , pointer :: new_patch_primary + type (fates_patch_type) , pointer :: new_patch_secondary + type (fates_patch_type) , pointer :: currentPatch + type (fates_cohort_type), pointer :: currentCohort + type (fates_cohort_type), pointer :: nc + type (fates_cohort_type), pointer :: storesmallcohort + type (fates_cohort_type), pointer :: storebigcohort real(r8) :: site_areadis_primary ! total area disturbed (to primary forest) in m2 per site per day real(r8) :: site_areadis_secondary ! total area disturbed (to secondary forest) in m2 per site per day real(r8) :: 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 @@ -490,6 +450,9 @@ subroutine spawn_patches( currentSite, bc_in) real(r8) :: leaf_m ! leaf mass during partial burn calculations logical :: found_youngest_primary ! logical for finding the first primary forest patch integer :: min_nocomp_pft, max_nocomp_pft, i_nocomp_pft + integer :: i_disturbance_type, i_dist2 ! iterators for looping over disturbance types + real(r8) :: disturbance_rate ! rate of disturbance being resolved [fraction of patch area / day] + real(r8) :: oldarea ! old patch area prior to disturbance !--------------------------------------------------------------------- storesmallcohort => null() ! storage of the smallest cohort for insertion routine @@ -510,714 +473,797 @@ subroutine spawn_patches( currentSite, bc_in) ! in the nocomp cases, since every patch has a PFT identity, it can only receive patch area from patches ! that have the same identity. In order to allow this, we have this very high level loop over nocomp PFTs - ! and only do the disturbance for any patches that have that nocomp PFT identity. + ! and only do the disturbance for any patches that have that nocomp PFT identity. ! If nocomp is not enabled, then this is not much of a loop, it only passes through once. nocomp_pft_loop: do i_nocomp_pft = min_nocomp_pft,max_nocomp_pft - ! calculate area of disturbed land, in this timestep, by summing contributions from each existing patch. - currentPatch => currentSite%youngest_patch + disturbance_type_loop: do i_disturbance_type = 1,N_DIST_TYPES - site_areadis_primary = 0.0_r8 - site_areadis_secondary = 0.0_r8 + ! calculate area of disturbed land, in this timestep, by summing contributions from each existing patch. + currentPatch => currentSite%youngest_patch - do while(associated(currentPatch)) + site_areadis_primary = 0.0_r8 + site_areadis_secondary = 0.0_r8 - cp_nocomp_matches_1_if: if ( hlm_use_nocomp .eq. ifalse .or. & - currentPatch%nocomp_pft_label .eq. i_nocomp_pft ) then - - if(currentPatch%disturbance_rate > (1.0_r8 + rsnbl_math_prec)) then - write(fates_log(),*) 'patch disturbance rate > 1 ?',currentPatch%disturbance_rate - call dump_patch(currentPatch) - call endrun(msg=errMsg(sourcefile, __LINE__)) - end if + do while(associated(currentPatch)) - ! Check to make sure that the disturbance mode of the patch is set - if( .not.any(currentPatch%disturbance_mode == [dtype_ilog,dtype_ifall,dtype_ifire])) then - write(fates_log(),*) 'undefined disturbance mode? : ',currentPatch%disturbance_mode - call endrun(msg=errMsg(sourcefile, __LINE__)) - end if + cp_nocomp_matches_1_if: if ( hlm_use_nocomp .eq. ifalse .or. & + currentPatch%nocomp_pft_label .eq. i_nocomp_pft ) then + disturbance_rate = currentPatch%disturbance_rates(i_disturbance_type) - ! Only create new patches that have non-negligible amount of land - if((currentPatch%area*currentPatch%disturbance_rate) > nearzero ) then - - ! figure out whether the receiver patch for disturbance from this patch will be - ! primary or secondary land receiver patch is primary forest only if both the - ! donor patch is primary forest and the dominant disturbance type is not logging - if ( currentPatch%anthro_disturbance_label .eq. primaryforest .and. & - (currentPatch%disturbance_mode .ne. dtype_ilog) ) then - - site_areadis_primary = site_areadis_primary + currentPatch%area * currentPatch%disturbance_rate + if(disturbance_rate > (1.0_r8 + rsnbl_math_prec)) then + write(fates_log(),*) 'patch disturbance rate > 1 ?',disturbance_rate + call currentPatch%Dump() + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if - ! track disturbance rates to output to history - currentSite%disturbance_rates_primary_to_primary(currentPatch%disturbance_mode) = & - currentSite%disturbance_rates_primary_to_primary(currentPatch%disturbance_mode) + & - currentPatch%area * currentPatch%disturbance_rate * AREA_INV - else - site_areadis_secondary = site_areadis_secondary + currentPatch%area * currentPatch%disturbance_rate + ! Only create new patches that have non-negligible amount of land + if((currentPatch%area*disturbance_rate) > nearzero ) then - ! track disturbance rates to output to history - if (currentPatch%anthro_disturbance_label .eq. secondaryforest) then - currentSite%disturbance_rates_secondary_to_secondary(currentPatch%disturbance_mode) = & - currentSite%disturbance_rates_secondary_to_secondary(currentPatch%disturbance_mode) + & - currentPatch%area * currentPatch%disturbance_rate * AREA_INV - else - currentSite%disturbance_rates_primary_to_secondary(currentPatch%disturbance_mode) = & - currentSite%disturbance_rates_primary_to_secondary(currentPatch%disturbance_mode) + & - currentPatch%area * currentPatch%disturbance_rate * AREA_INV - endif + ! figure out whether the receiver patch for disturbance from this patch will be + ! primary or secondary land receiver patch is primary forest only if both the + ! donor patch is primary forest and the current disturbance type is not logging + if ( currentPatch%anthro_disturbance_label .eq. primaryforest .and. & + (i_disturbance_type .ne. dtype_ilog) ) then - endif - - end if - - end if cp_nocomp_matches_1_if - currentPatch => currentPatch%older - enddo ! end loop over patches. sum area disturbed for all patches. + site_areadis_primary = site_areadis_primary + currentPatch%area * disturbance_rate - ! It is possible that no disturbance area was generated - if ( (site_areadis_primary + site_areadis_secondary) > nearzero) then - - age = 0.0_r8 + ! track disturbance rates to output to history + currentSite%disturbance_rates_primary_to_primary(i_disturbance_type) = & + currentSite%disturbance_rates_primary_to_primary(i_disturbance_type) + & + currentPatch%area * disturbance_rate * AREA_INV - ! create two empty patches, to absorb newly disturbed primary and secondary forest area - ! first create patch to receive primary forest area - if ( site_areadis_primary .gt. nearzero ) then - allocate(new_patch_primary) - - call create_patch(currentSite, new_patch_primary, age, & - site_areadis_primary, primaryforest, i_nocomp_pft) - - ! Initialize the litter pools to zero, these - ! pools will be populated by looping over the existing patches - ! and transfering in mass - do el=1,num_elements - call new_patch_primary%litter(el)%InitConditions(init_leaf_fines=0._r8, & - init_root_fines=0._r8, & - init_ag_cwd=0._r8, & - init_bg_cwd=0._r8, & - init_seed=0._r8, & - init_seed_germ=0._r8) - end do - new_patch_primary%tallest => null() - new_patch_primary%shortest => null() + else + site_areadis_secondary = site_areadis_secondary + currentPatch%area * disturbance_rate - endif + ! track disturbance rates to output to history + if (currentPatch%anthro_disturbance_label .eq. secondaryforest) then + currentSite%disturbance_rates_secondary_to_secondary(i_disturbance_type) = & + currentSite%disturbance_rates_secondary_to_secondary(i_disturbance_type) + & + currentPatch%area * disturbance_rate * AREA_INV - ! next create patch to receive secondary forest area - if ( site_areadis_secondary .gt. nearzero) then - allocate(new_patch_secondary) - call create_patch(currentSite, new_patch_secondary, age, & - site_areadis_secondary, secondaryforest,i_nocomp_pft) - - ! Initialize the litter pools to zero, these - ! pools will be populated by looping over the existing patches - ! and transfering in mass - do el=1,num_elements - call new_patch_secondary%litter(el)%InitConditions(init_leaf_fines=0._r8, & - init_root_fines=0._r8, & - init_ag_cwd=0._r8, & - init_bg_cwd=0._r8, & - init_seed=0._r8, & - init_seed_germ=0._r8) - end do - new_patch_secondary%tallest => null() - new_patch_secondary%shortest => null() + else + currentSite%disturbance_rates_primary_to_secondary(i_disturbance_type) = & + currentSite%disturbance_rates_primary_to_secondary(i_disturbance_type) + & + currentPatch%area * disturbance_rate * AREA_INV + endif - endif - - ! loop round all the patches that contribute surviving indivduals and litter - ! pools to the new patch. We only loop the pre-existing patches, so - ! quit the loop if the current patch is either null, or matches the - ! two new pointers. + endif - currentPatch => currentSite%oldest_patch - do while(associated(currentPatch)) + end if - cp_nocomp_matches_2_if: if ( hlm_use_nocomp .eq. ifalse .or. & - currentPatch%nocomp_pft_label .eq. i_nocomp_pft ) then + end if cp_nocomp_matches_1_if + currentPatch => currentPatch%older + enddo ! end loop over patches. sum area disturbed for all patches. + + ! It is possible that no disturbance area was generated + if ( (site_areadis_primary + site_areadis_secondary) > nearzero) then + + age = 0.0_r8 + + ! create two empty patches, to absorb newly disturbed primary and secondary forest area + ! first create patch to receive primary forest area + if ( site_areadis_primary .gt. nearzero ) then + allocate(new_patch_primary) + call new_patch_primary%Create(age, site_areadis_primary, & + primaryforest, i_nocomp_pft, hlm_numSWb, numpft, & + currentSite%nlevsoil, hlm_current_tod, regeneration_model) + + ! Initialize the litter pools to zero, these + ! pools will be populated by looping over the existing patches + ! and transfering in mass + do el=1,num_elements + call new_patch_primary%litter(el)%InitConditions(init_leaf_fines=0._r8, & + init_root_fines=0._r8, & + init_ag_cwd=0._r8, & + init_bg_cwd=0._r8, & + init_seed=0._r8, & + init_seed_germ=0._r8) + end do + new_patch_primary%tallest => null() + new_patch_primary%shortest => null() - ! This is the amount of patch area that is disturbed, and donated by the donor - patch_site_areadis = currentPatch%area * currentPatch%disturbance_rate + endif - - if ( patch_site_areadis > nearzero ) then - - ! figure out whether the receiver patch for disturbance from this patch - ! will be primary or secondary land receiver patch is primary forest - ! only if both the donor patch is primary forest and the dominant - ! disturbance type is not logging - if (currentPatch%anthro_disturbance_label .eq. primaryforest .and. & - (currentPatch%disturbance_mode .ne. dtype_ilog)) then - new_patch => new_patch_primary - else - new_patch => new_patch_secondary - endif - - if(.not.associated(new_patch))then - write(fates_log(),*) 'Patch spawning has attempted to point to' - write(fates_log(),*) 'an un-allocated patch' - call endrun(msg=errMsg(sourcefile, __LINE__)) - end if - - ! for the case where the donating patch is secondary forest, if - ! the dominant disturbance from this patch is non-anthropogenic, - ! we need to average in the time-since-anthropogenic-disturbance - ! from the donor patch into that of the receiver patch - if ( currentPatch%anthro_disturbance_label .eq. secondaryforest .and. & - (currentPatch%disturbance_mode .ne. dtype_ilog) ) then - - new_patch%age_since_anthro_disturbance = new_patch%age_since_anthro_disturbance + & - currentPatch%age_since_anthro_disturbance * (patch_site_areadis / site_areadis_secondary) + ! next create patch to receive secondary forest area + if (site_areadis_secondary .gt. nearzero) then + allocate(new_patch_secondary) + call new_patch_secondary%Create(age, site_areadis_secondary, & + secondaryforest, i_nocomp_pft, hlm_numSWb, numpft, & + currentSite%nlevsoil, hlm_current_tod, regeneration_model) + + ! Initialize the litter pools to zero, these + ! pools will be populated by looping over the existing patches + ! and transfering in mass + do el=1,num_elements + call new_patch_secondary%litter(el)%InitConditions(init_leaf_fines=0._r8, & + init_root_fines=0._r8, & + init_ag_cwd=0._r8, & + init_bg_cwd=0._r8, & + init_seed=0._r8, & + init_seed_germ=0._r8) + end do + new_patch_secondary%tallest => null() + new_patch_secondary%shortest => null() endif - - - ! Transfer the litter existing already in the donor patch to the new patch - ! This call will only transfer non-burned litter to new patch - ! and burned litter to atmosphere. Thus it is important to zero burnt_frac_litter when - ! fire is not the dominant disturbance regime. - if(currentPatch%disturbance_mode .ne. dtype_ifire) then - currentPatch%burnt_frac_litter(:) = 0._r8 - end if + ! loop round all the patches that contribute surviving indivduals and litter + ! pools to the new patch. We only loop the pre-existing patches, so + ! quit the loop if the current patch is either null, or matches the + ! two new pointers. - call TransLitterNewPatch( currentSite, currentPatch, new_patch, patch_site_areadis) + currentPatch => currentSite%oldest_patch + do while(associated(currentPatch)) - ! Transfer in litter fluxes from plants in various contexts of death and destruction + cp_nocomp_matches_2_if: if ( hlm_use_nocomp .eq. ifalse .or. & + currentPatch%nocomp_pft_label .eq. i_nocomp_pft ) then - if(currentPatch%disturbance_mode .eq. dtype_ilog) then - call logging_litter_fluxes(currentSite, currentPatch, & - new_patch, patch_site_areadis,bc_in) - elseif(currentPatch%disturbance_mode .eq. dtype_ifire) then - call fire_litter_fluxes(currentSite, currentPatch, & - new_patch, patch_site_areadis,bc_in) - else - call mortality_litter_fluxes(currentSite, currentPatch, & - new_patch, patch_site_areadis,bc_in) - endif + ! This is the amount of patch area that is disturbed, and donated by the donor + disturbance_rate = currentPatch%disturbance_rates(i_disturbance_type) + patch_site_areadis = currentPatch%area * disturbance_rate - ! Copy any means or timers from the original patch to the new patch - ! These values will inherit all info from the original patch - ! -------------------------------------------------------------------------- - call new_patch%tveg24%CopyFromDonor(currentPatch%tveg24) - call new_patch%tveg_lpa%CopyFromDonor(currentPatch%tveg_lpa) - - - ! -------------------------------------------------------------------------- - ! The newly formed patch from disturbance (new_patch), has now been given - ! some litter from dead plants and pre-existing litter from the donor patches. - ! - ! Next, we loop through the cohorts in the donor patch, copy them with - ! area modified number density into the new-patch, and apply survivorship. - ! ------------------------------------------------------------------------- - - currentCohort => currentPatch%shortest - do while(associated(currentCohort)) - - allocate(nc) - if(hlm_use_planthydro.eq.itrue) call InitHydrCohort(CurrentSite,nc) - - ! Initialize the PARTEH object and point to the - ! correct boundary condition fields - nc%prt => null() - call InitPRTObject(nc%prt) - call InitPRTBoundaryConditions(nc) - - ! (Keeping as an example) - ! Allocate running mean functions - !allocate(nc%tveg_lpa) - !call nc%tveg_lpa%InitRMean(ema_lpa,init_value=new_patch%tveg_lpa%GetMean()) - - call zero_cohort(nc) - - ! nc is the new cohort that goes in the disturbed patch (new_patch)... currentCohort - ! is the curent cohort that stays in the donor patch (currentPatch) - call copy_cohort(currentCohort, nc) - - !this is the case as the new patch probably doesn't have a closed canopy, and - ! even if it does, that will be sorted out in canopy_structure. - nc%canopy_layer = 1 - nc%canopy_layer_yesterday = 1._r8 - - sapw_c = currentCohort%prt%GetState(sapw_organ, all_carbon_elements) - struct_c = currentCohort%prt%GetState(struct_organ, all_carbon_elements) - leaf_c = currentCohort%prt%GetState(leaf_organ, all_carbon_elements) - fnrt_c = currentCohort%prt%GetState(fnrt_organ, all_carbon_elements) - store_c = currentCohort%prt%GetState(store_organ, all_carbon_elements) - total_c = sapw_c + struct_c + leaf_c + fnrt_c + store_c - - ! treefall mortality is the dominant disturbance - if(currentPatch%disturbance_mode .eq. dtype_ifall) then - - if(currentCohort%canopy_layer == 1)then + if ( patch_site_areadis > nearzero ) then - ! In the donor patch we are left with fewer trees because the area has decreased - ! the plant density for large trees does not actually decrease in the donor patch - ! because this is the part of the original patch where no trees have actually fallen - ! The diagnostic cmort,bmort,hmort, and frmort rates have already been saved - - currentCohort%n = currentCohort%n * (1.0_r8 - fates_mortality_disturbance_fraction * & - min(1.0_r8,currentCohort%dmort * hlm_freq_day)) - - nc%n = 0.0_r8 ! kill all of the trees who caused the disturbance. - - nc%cmort = nan ! The mortality diagnostics are set to nan - ! because the cohort should dissappear - nc%hmort = nan - nc%bmort = nan - nc%frmort = nan - nc%smort = nan - nc%asmort = nan - nc%lmort_direct = nan - nc%lmort_collateral = nan - nc%lmort_infra = nan - nc%l_degrad = nan - - else - ! small trees - if( int(prt_params%woody(currentCohort%pft)) == itrue)then - - - ! Survivorship of undestory woody plants. Two step process. - ! Step 1: Reduce current number of plants to reflect the - ! change in area. - ! The number density per square are doesn't change, - ! but since the patch is smaller and cohort counts - ! are absolute, reduce this number. - - nc%n = currentCohort%n * patch_site_areadis/currentPatch%area - - ! because the mortality rate due to impact for the cohorts which - ! had been in the understory and are now in the newly- - ! disturbed patch is very high, passing the imort directly to history - ! results in large numerical errors, on account of the sharply - ! reduced number densities. so instead pass this info via a - ! site-level diagnostic variable before reducing the number density. - - currentSite%imort_rate(currentCohort%size_class, currentCohort%pft) = & - currentSite%imort_rate(currentCohort%size_class, currentCohort%pft) + & - nc%n * ED_val_understorey_death / hlm_freq_day - - - currentSite%imort_carbonflux = currentSite%imort_carbonflux + & - (nc%n * ED_val_understorey_death / hlm_freq_day ) * & - total_c * g_per_kg * days_per_sec * years_per_day * ha_per_m2 - - ! Step 2: Apply survivor ship function based on the understory death fraction - ! remaining of understory plants of those that are knocked over - ! by the overstorey trees dying... - nc%n = nc%n * (1.0_r8 - ED_val_understorey_death) - - ! since the donor patch split and sent a fraction of its members - ! to the new patch and a fraction to be preserved in itself, - ! when reporting diagnostic rates, we must carry over the mortality rates from - ! the donor that were applied before the patch split. Remember this is only - ! for diagnostics. But think of it this way, the rates are weighted by - ! number density in EDCLMLink, and the number density of this new patch is donated - ! so with the number density must come the effective mortality rates. - - nc%cmort = currentCohort%cmort - nc%hmort = currentCohort%hmort - nc%bmort = currentCohort%bmort - nc%frmort = currentCohort%frmort - nc%smort = currentCohort%smort - nc%asmort = currentCohort%asmort - nc%dmort = currentCohort%dmort - nc%lmort_direct = currentCohort%lmort_direct - nc%lmort_collateral = currentCohort%lmort_collateral - nc%lmort_infra = currentCohort%lmort_infra - - ! understory trees that might potentially be knocked over in the disturbance. - ! The existing (donor) patch should not have any impact mortality, it should - ! only lose cohorts due to the decrease in area. This is not mortality. - ! Besides, the current and newly created patch sum to unity - - currentCohort%n = currentCohort%n * (1._r8 - patch_site_areadis/currentPatch%area) - - else - ! grass is not killed by mortality disturbance events. Just move it into the new patch area. - ! Just split the grass into the existing and new patch structures - nc%n = currentCohort%n * patch_site_areadis/currentPatch%area - - ! Those remaining in the existing - currentCohort%n = currentCohort%n * (1._r8 - patch_site_areadis/currentPatch%area) - - nc%cmort = currentCohort%cmort - nc%hmort = currentCohort%hmort - nc%bmort = currentCohort%bmort - nc%frmort = currentCohort%frmort - nc%smort = currentCohort%smort - nc%asmort = currentCohort%asmort - nc%dmort = currentCohort%dmort - nc%lmort_direct = currentCohort%lmort_direct - nc%lmort_collateral = currentCohort%lmort_collateral - nc%lmort_infra = currentCohort%lmort_infra - + ! figure out whether the receiver patch for disturbance from this patch + ! will be primary or secondary land receiver patch is primary forest + ! only if both the donor patch is primary forest and the current + ! disturbance type is not logging + if (currentPatch%anthro_disturbance_label .eq. primaryforest .and. & + (i_disturbance_type .ne. dtype_ilog)) then + new_patch => new_patch_primary + else + new_patch => new_patch_secondary endif - endif - - ! Fire is the dominant disturbance - elseif (currentPatch%disturbance_mode .eq. dtype_ifire ) then - - ! Number of members in the new patch, before we impose fire survivorship - nc%n = currentCohort%n * patch_site_areadis/currentPatch%area - - ! loss of individuals from source patch due to area shrinking - currentCohort%n = currentCohort%n * (1._r8 - patch_site_areadis/currentPatch%area) - - levcan = currentCohort%canopy_layer - - if(levcan==ican_upper) then - - ! before changing number densities, track total rate of trees that died - ! due to fire, as well as from each fire mortality term - currentSite%fmort_rate_canopy(currentCohort%size_class, currentCohort%pft) = & - currentSite%fmort_rate_canopy(currentCohort%size_class, currentCohort%pft) + & - nc%n * currentCohort%fire_mort / hlm_freq_day - - currentSite%fmort_carbonflux_canopy = currentSite%fmort_carbonflux_canopy + & - (nc%n * currentCohort%fire_mort) * & - total_c * g_per_kg * days_per_sec * ha_per_m2 - - else - currentSite%fmort_rate_ustory(currentCohort%size_class, currentCohort%pft) = & - currentSite%fmort_rate_ustory(currentCohort%size_class, currentCohort%pft) + & - nc%n * currentCohort%fire_mort / hlm_freq_day - - currentSite%fmort_carbonflux_ustory = currentSite%fmort_carbonflux_ustory + & - (nc%n * currentCohort%fire_mort) * & - total_c * g_per_kg * days_per_sec * ha_per_m2 - end if - - currentSite%fmort_rate_cambial(currentCohort%size_class, currentCohort%pft) = & - currentSite%fmort_rate_cambial(currentCohort%size_class, currentCohort%pft) + & - nc%n * currentCohort%cambial_mort / hlm_freq_day - currentSite%fmort_rate_crown(currentCohort%size_class, currentCohort%pft) = & - currentSite%fmort_rate_crown(currentCohort%size_class, currentCohort%pft) + & - nc%n * currentCohort%crownfire_mort / hlm_freq_day - - ! loss of individual from fire in new patch. - nc%n = nc%n * (1.0_r8 - currentCohort%fire_mort) - - nc%cmort = currentCohort%cmort - nc%hmort = currentCohort%hmort - nc%bmort = currentCohort%bmort - nc%frmort = currentCohort%frmort - nc%smort = currentCohort%smort - nc%asmort = currentCohort%asmort - nc%dmort = currentCohort%dmort - nc%lmort_direct = currentCohort%lmort_direct - nc%lmort_collateral = currentCohort%lmort_collateral - nc%lmort_infra = currentCohort%lmort_infra - - - ! Some of of the leaf mass from living plants has been - ! burned off. Here, we remove that mass, and - ! tally it in the flux we sent to the atmosphere - - if(int(prt_params%woody(currentCohort%pft)) == itrue)then - leaf_burn_frac = currentCohort%fraction_crown_burned - else - ! Grasses determine their fraction of leaves burned here + if(.not.associated(new_patch))then + write(fates_log(),*) 'Patch spawning has attempted to point to' + write(fates_log(),*) 'an un-allocated patch' + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if - leaf_burn_frac = currentPatch%burnt_frac_litter(lg_sf) - endif - - ! Perform a check to make sure that spitfire gave - ! us reasonable mortality and burn fraction rates - - if( (leaf_burn_frac < 0._r8) .or. & - (leaf_burn_frac > 1._r8) .or. & - (currentCohort%fire_mort < 0._r8) .or. & - (currentCohort%fire_mort > 1._r8)) then - write(fates_log(),*) 'unexpected fire fractions' - write(fates_log(),*) prt_params%woody(currentCohort%pft) - write(fates_log(),*) leaf_burn_frac - write(fates_log(),*) currentCohort%fire_mort - call endrun(msg=errMsg(sourcefile, __LINE__)) - end if - - do el = 1,num_elements - - leaf_m = nc%prt%GetState(leaf_organ, element_list(el)) - - currentSite%mass_balance(el)%burn_flux_to_atm = & - currentSite%mass_balance(el)%burn_flux_to_atm + & - leaf_burn_frac * leaf_m * nc%n - end do + ! for the case where the donating patch is secondary forest, if + ! the current disturbance from this patch is non-anthropogenic, + ! we need to average in the time-since-anthropogenic-disturbance + ! from the donor patch into that of the receiver patch + if ( currentPatch%anthro_disturbance_label .eq. secondaryforest .and. & + (i_disturbance_type .ne. dtype_ilog) ) then - ! Here the mass is removed from the plant + new_patch%age_since_anthro_disturbance = new_patch%age_since_anthro_disturbance + & + currentPatch%age_since_anthro_disturbance * (patch_site_areadis / site_areadis_secondary) - call PRTBurnLosses(nc%prt, leaf_organ, leaf_burn_frac) - currentCohort%fraction_crown_burned = 0.0_r8 - nc%fraction_crown_burned = 0.0_r8 + endif + ! Transfer the litter existing already in the donor patch to the new patch + ! This call will only transfer non-burned litter to new patch + ! and burned litter to atmosphere. Thus it is important to zero burnt_frac_litter when + ! fire is not the current disturbance regime. - ! Logging is the dominant disturbance - elseif (currentPatch%disturbance_mode .eq. dtype_ilog ) then - - ! If this cohort is in the upper canopy. It generated - if(currentCohort%canopy_layer == 1)then - - ! calculate the survivorship of disturbed trees because non-harvested - nc%n = currentCohort%n * currentCohort%l_degrad - ! nc%n = (currentCohort%l_degrad / (currentCohort%l_degrad + & - ! currentCohort%lmort_direct + currentCohort%lmort_collateral + - ! currentCohort%lmort_infra) ) * & - ! currentCohort%n * patch_site_areadis/currentPatch%area - - ! Reduce counts in the existing/donor patch according to the logging rate - currentCohort%n = currentCohort%n * & - (1.0_r8 - min(1.0_r8,(currentCohort%lmort_direct + & - currentCohort%lmort_collateral + & - currentCohort%lmort_infra + currentCohort%l_degrad))) - - nc%cmort = currentCohort%cmort - nc%hmort = currentCohort%hmort - nc%bmort = currentCohort%bmort - nc%frmort = currentCohort%frmort - nc%smort = currentCohort%smort - nc%asmort = currentCohort%asmort - nc%dmort = currentCohort%dmort - - ! since these are the ones that weren't logged, - ! set the logging mortality rates as zero - nc%lmort_direct = 0._r8 - nc%lmort_collateral = 0._r8 - nc%lmort_infra = 0._r8 - - else - - ! WHat to do with cohorts in the understory of a logging generated - ! disturbance patch? - - if(int(prt_params%woody(currentCohort%pft)) == itrue)then - - - ! Survivorship of undestory woody plants. Two step process. - ! Step 1: Reduce current number of plants to reflect the - ! change in area. - ! The number density per square are doesn't change, - ! but since the patch is smaller - ! and cohort counts are absolute, reduce this number. - nc%n = currentCohort%n * patch_site_areadis/currentPatch%area - - ! because the mortality rate due to impact for the cohorts which had - ! been in the understory and are now in the newly- - ! disturbed patch is very high, passing the imort directly to - ! history results in large numerical errors, on account - ! of the sharply reduced number densities. so instead pass this info - ! via a site-level diagnostic variable before reducing - ! the number density. - currentSite%imort_rate(currentCohort%size_class, currentCohort%pft) = & - currentSite%imort_rate(currentCohort%size_class, currentCohort%pft) + & - nc%n * currentPatch%fract_ldist_not_harvested * & - logging_coll_under_frac / hlm_freq_day - - currentSite%imort_carbonflux = currentSite%imort_carbonflux + & - (nc%n * currentPatch%fract_ldist_not_harvested * & - logging_coll_under_frac/ hlm_freq_day ) * & - total_c * g_per_kg * days_per_sec * years_per_day * ha_per_m2 - - - ! Step 2: Apply survivor ship function based on the understory death fraction - - ! remaining of understory plants of those that are knocked - ! over by the overstorey trees dying... - ! LOGGING SURVIVORSHIP OF UNDERSTORY PLANTS IS SET AS A NEW PARAMETER - ! in the fatesparameter files - nc%n = nc%n * (1.0_r8 - & - (1.0_r8-currentPatch%fract_ldist_not_harvested) * logging_coll_under_frac) - - ! Step 3: Reduce the number count of cohorts in the - ! original/donor/non-disturbed patch to reflect the area change - currentCohort%n = currentCohort%n * (1._r8 - patch_site_areadis/currentPatch%area) - - nc%cmort = currentCohort%cmort - nc%hmort = currentCohort%hmort - nc%bmort = currentCohort%bmort - nc%frmort = currentCohort%frmort - nc%smort = currentCohort%smort - nc%asmort = currentCohort%asmort - nc%dmort = currentCohort%dmort - nc%lmort_direct = currentCohort%lmort_direct - nc%lmort_collateral = currentCohort%lmort_collateral - nc%lmort_infra = currentCohort%lmort_infra - + if(i_disturbance_type .ne. dtype_ifire) then + currentPatch%burnt_frac_litter(:) = 0._r8 + end if + + call TransLitterNewPatch( currentSite, currentPatch, new_patch, patch_site_areadis) + + ! Transfer in litter fluxes from plants in various contexts of death and destruction + + if(i_disturbance_type .eq. dtype_ilog) then + call logging_litter_fluxes(currentSite, currentPatch, & + new_patch, patch_site_areadis,bc_in) + elseif(i_disturbance_type .eq. dtype_ifire) then + call fire_litter_fluxes(currentSite, currentPatch, & + new_patch, patch_site_areadis,bc_in) else - - ! grass is not killed by mortality disturbance events. - ! Just move it into the new patch area. - ! Just split the grass into the existing and new patch structures - nc%n = currentCohort%n * patch_site_areadis/currentPatch%area - - ! Those remaining in the existing - currentCohort%n = currentCohort%n * (1._r8 - patch_site_areadis/currentPatch%area) - - ! No grass impact mortality imposed on the newly created patch - nc%cmort = currentCohort%cmort - nc%hmort = currentCohort%hmort - nc%bmort = currentCohort%bmort - nc%frmort = currentCohort%frmort - nc%smort = currentCohort%smort - nc%asmort = currentCohort%asmort - nc%dmort = currentCohort%dmort - nc%lmort_direct = currentCohort%lmort_direct - nc%lmort_collateral = currentCohort%lmort_collateral - nc%lmort_infra = currentCohort%lmort_infra - - endif ! is/is-not woody + call mortality_litter_fluxes(currentSite, currentPatch, & + new_patch, patch_site_areadis,bc_in) + endif + + + ! Copy any means or timers from the original patch to the new patch + ! These values will inherit all info from the original patch + ! -------------------------------------------------------------------------- + call new_patch%tveg24%CopyFromDonor(currentPatch%tveg24) + call new_patch%tveg_lpa%CopyFromDonor(currentPatch%tveg_lpa) + + if ( regeneration_model == TRS_regeneration ) then + call new_patch%seedling_layer_par24%CopyFromDonor(currentPatch%seedling_layer_par24) + call new_patch%sdlng_mort_par%CopyFromDonor(currentPatch%sdlng_mort_par) + call new_patch%sdlng2sap_par%CopyFromDonor(currentPatch%sdlng2sap_par) + do pft = 1,numpft + call new_patch%sdlng_emerg_smp(pft)%p%CopyFromDonor(currentPatch%sdlng_emerg_smp(pft)%p) + call new_patch%sdlng_mdd(pft)%p%CopyFromDonor(currentPatch%sdlng_mdd(pft)%p) + enddo + end if + + call new_patch%tveg_longterm%CopyFromDonor(currentPatch%tveg_longterm) - endif ! Select canopy layer - - else - write(fates_log(),*) 'unknown disturbance mode?' - write(fates_log(),*) 'disturbance_mode: ',currentPatch%disturbance_mode - call endrun(msg=errMsg(sourcefile, __LINE__)) - end if ! Select disturbance mode - - if (nc%n > 0.0_r8) then - storebigcohort => new_patch%tallest - storesmallcohort => new_patch%shortest - if(associated(new_patch%tallest))then - tnull = 0 - else - tnull = 1 - new_patch%tallest => nc - nc%taller => null() - endif - - if(associated(new_patch%shortest))then - snull = 0 + ! -------------------------------------------------------------------------- + ! The newly formed patch from disturbance (new_patch), has now been given + ! some litter from dead plants and pre-existing litter from the donor patches. + ! + ! Next, we loop through the cohorts in the donor patch, copy them with + ! area modified number density into the new-patch, and apply survivorship. + ! ------------------------------------------------------------------------- + + currentCohort => currentPatch%shortest + do while(associated(currentCohort)) + + allocate(nc) + if(hlm_use_planthydro.eq.itrue) call InitHydrCohort(CurrentSite,nc) + + ! Initialize the PARTEH object and point to the + ! correct boundary condition fields + nc%prt => null() + call InitPRTObject(nc%prt) + call nc%InitPRTBoundaryConditions() + + ! (Keeping as an example) + ! Allocate running mean functions + !allocate(nc%tveg_lpa) + !call nc%tveg_lpa%InitRMean(ema_lpa,init_value=new_patch%tveg_lpa%GetMean()) + + call nc%ZeroValues() + + ! nc is the new cohort that goes in the disturbed patch (new_patch)... currentCohort + ! is the curent cohort that stays in the donor patch (currentPatch) + call currentCohort%Copy(nc) + + !this is the case as the new patch probably doesn't have a closed canopy, and + ! even if it does, that will be sorted out in canopy_structure. + nc%canopy_layer = 1 + nc%canopy_layer_yesterday = 1._r8 + + sapw_c = currentCohort%prt%GetState(sapw_organ, carbon12_element) + struct_c = currentCohort%prt%GetState(struct_organ, carbon12_element) + leaf_c = currentCohort%prt%GetState(leaf_organ, carbon12_element) + fnrt_c = currentCohort%prt%GetState(fnrt_organ, carbon12_element) + store_c = currentCohort%prt%GetState(store_organ, carbon12_element) + total_c = sapw_c + struct_c + leaf_c + fnrt_c + store_c + + ! treefall mortality is the current disturbance + if(i_disturbance_type .eq. dtype_ifall) then + + if(currentCohort%canopy_layer == 1)then + + ! In the donor patch we are left with fewer trees because the area has decreased + ! the plant density for large trees does not actually decrease in the donor patch + ! because this is the part of the original patch where no trees have actually fallen + ! The diagnostic cmort,bmort,hmort, and frmort rates have already been saved + + currentCohort%n = currentCohort%n * (1.0_r8 - fates_mortality_disturbance_fraction * & + min(1.0_r8,currentCohort%dmort * hlm_freq_day)) + + nc%n = 0.0_r8 ! kill all of the trees who caused the disturbance. + + nc%cmort = nan ! The mortality diagnostics are set to nan + ! because the cohort should dissappear + nc%hmort = nan + nc%bmort = nan + nc%frmort = nan + nc%smort = nan + nc%asmort = nan + nc%dgmort = nan + nc%lmort_direct = nan + nc%lmort_collateral = nan + nc%lmort_infra = nan + nc%l_degrad = nan + + else + ! small trees + if( prt_params%woody(currentCohort%pft) == itrue)then + + + ! Survivorship of undestory woody plants. Two step process. + ! Step 1: Reduce current number of plants to reflect the + ! change in area. + ! The number density per square are doesn't change, + ! but since the patch is smaller and cohort counts + ! are absolute, reduce this number. + + nc%n = currentCohort%n * patch_site_areadis/currentPatch%area + + ! because the mortality rate due to impact for the cohorts which + ! had been in the understory and are now in the newly- + ! disturbed patch is very high, passing the imort directly to history + ! results in large numerical errors, on account of the sharply + ! reduced number densities. so instead pass this info via a + ! site-level diagnostic variable before reducing the number density. + + currentSite%imort_rate(currentCohort%size_class, currentCohort%pft) = & + currentSite%imort_rate(currentCohort%size_class, currentCohort%pft) + & + nc%n * ED_val_understorey_death / hlm_freq_day + + + currentSite%imort_carbonflux(currentCohort%pft) = & + currentSite%imort_carbonflux(currentCohort%pft) + & + (nc%n * ED_val_understorey_death / hlm_freq_day ) * & + total_c * days_per_sec * years_per_day * ha_per_m2 + + currentSite%imort_abg_flux(currentCohort%size_class, currentCohort%pft) = & + currentSite%imort_abg_flux(currentCohort%size_class, currentCohort%pft) + & + (nc%n * ED_val_understorey_death / hlm_freq_day ) * & + ( (sapw_c + struct_c + store_c) * prt_params%allom_agb_frac(currentCohort%pft) + & + leaf_c ) * days_per_sec * years_per_day * ha_per_m2 + + + ! Step 2: Apply survivor ship function based on the understory death fraction + ! remaining of understory plants of those that are knocked over + ! by the overstorey trees dying... + nc%n = nc%n * (1.0_r8 - ED_val_understorey_death) + + ! since the donor patch split and sent a fraction of its members + ! to the new patch and a fraction to be preserved in itself, + ! when reporting diagnostic rates, we must carry over the mortality rates from + ! the donor that were applied before the patch split. Remember this is only + ! for diagnostics. But think of it this way, the rates are weighted by + ! number density in EDCLMLink, and the number density of this new patch is donated + ! so with the number density must come the effective mortality rates. + + nc%cmort = currentCohort%cmort + nc%hmort = currentCohort%hmort + nc%bmort = currentCohort%bmort + nc%frmort = currentCohort%frmort + nc%smort = currentCohort%smort + nc%asmort = currentCohort%asmort + nc%dgmort = currentCohort%dgmort + nc%dmort = currentCohort%dmort + nc%lmort_direct = currentCohort%lmort_direct + nc%lmort_collateral = currentCohort%lmort_collateral + nc%lmort_infra = currentCohort%lmort_infra + + ! understory trees that might potentially be knocked over in the disturbance. + ! The existing (donor) patch should not have any impact mortality, it should + ! only lose cohorts due to the decrease in area. This is not mortality. + ! Besides, the current and newly created patch sum to unity + + currentCohort%n = currentCohort%n * (1._r8 - patch_site_areadis/currentPatch%area) + + else + ! grass is not killed by mortality disturbance events. Just move it into the new patch area. + ! Just split the grass into the existing and new patch structures + nc%n = currentCohort%n * patch_site_areadis/currentPatch%area + + ! Those remaining in the existing + currentCohort%n = currentCohort%n * (1._r8 - patch_site_areadis/currentPatch%area) + + nc%cmort = currentCohort%cmort + nc%hmort = currentCohort%hmort + nc%bmort = currentCohort%bmort + nc%frmort = currentCohort%frmort + nc%smort = currentCohort%smort + nc%asmort = currentCohort%asmort + nc%dgmort = currentCohort%dgmort + nc%dmort = currentCohort%dmort + nc%lmort_direct = currentCohort%lmort_direct + nc%lmort_collateral = currentCohort%lmort_collateral + nc%lmort_infra = currentCohort%lmort_infra + + endif + endif + + ! Fire is the current disturbance + elseif (i_disturbance_type .eq. dtype_ifire ) then + + ! Number of members in the new patch, before we impose fire survivorship + nc%n = currentCohort%n * patch_site_areadis/currentPatch%area + + ! loss of individuals from source patch due to area shrinking + currentCohort%n = currentCohort%n * (1._r8 - patch_site_areadis/currentPatch%area) + + levcan = currentCohort%canopy_layer + + if(levcan==ican_upper) then + + ! before changing number densities, track total rate of trees that died + ! due to fire, as well as from each fire mortality term + currentSite%fmort_rate_canopy(currentCohort%size_class, currentCohort%pft) = & + currentSite%fmort_rate_canopy(currentCohort%size_class, currentCohort%pft) + & + nc%n * currentCohort%fire_mort / hlm_freq_day + + currentSite%fmort_carbonflux_canopy(currentCohort%pft) = & + currentSite%fmort_carbonflux_canopy(currentCohort%pft) + & + (nc%n * currentCohort%fire_mort) * & + total_c * g_per_kg * days_per_sec * ha_per_m2 + + else + currentSite%fmort_rate_ustory(currentCohort%size_class, currentCohort%pft) = & + currentSite%fmort_rate_ustory(currentCohort%size_class, currentCohort%pft) + & + nc%n * currentCohort%fire_mort / hlm_freq_day + + currentSite%fmort_carbonflux_ustory(currentCohort%pft) = & + currentSite%fmort_carbonflux_ustory(currentCohort%pft) + & + (nc%n * currentCohort%fire_mort) * & + total_c * g_per_kg * days_per_sec * ha_per_m2 + end if + + currentSite%fmort_abg_flux(currentCohort%size_class, currentCohort%pft) = & + currentSite%fmort_abg_flux(currentCohort%size_class, currentCohort%pft) + & + (nc%n * currentCohort%fire_mort) * & + ( (sapw_c + struct_c + store_c) * prt_params%allom_agb_frac(currentCohort%pft) + & + leaf_c ) * & + g_per_kg * days_per_sec * ha_per_m2 + + + currentSite%fmort_rate_cambial(currentCohort%size_class, currentCohort%pft) = & + currentSite%fmort_rate_cambial(currentCohort%size_class, currentCohort%pft) + & + nc%n * currentCohort%cambial_mort / hlm_freq_day + currentSite%fmort_rate_crown(currentCohort%size_class, currentCohort%pft) = & + currentSite%fmort_rate_crown(currentCohort%size_class, currentCohort%pft) + & + nc%n * currentCohort%crownfire_mort / hlm_freq_day + + ! loss of individual from fire in new patch. + nc%n = nc%n * (1.0_r8 - currentCohort%fire_mort) + + nc%cmort = currentCohort%cmort + nc%hmort = currentCohort%hmort + nc%bmort = currentCohort%bmort + nc%frmort = currentCohort%frmort + nc%smort = currentCohort%smort + nc%asmort = currentCohort%asmort + nc%dgmort = currentCohort%dgmort + nc%dmort = currentCohort%dmort + nc%lmort_direct = currentCohort%lmort_direct + nc%lmort_collateral = currentCohort%lmort_collateral + nc%lmort_infra = currentCohort%lmort_infra + + + ! Some of of the leaf mass from living plants has been + ! burned off. Here, we remove that mass, and + ! tally it in the flux we sent to the atmosphere + + if(prt_params%woody(currentCohort%pft) == itrue)then + leaf_burn_frac = currentCohort%fraction_crown_burned + else + + ! Grasses determine their fraction of leaves burned here + + leaf_burn_frac = currentPatch%burnt_frac_litter(lg_sf) + endif + + ! Perform a check to make sure that spitfire gave + ! us reasonable mortality and burn fraction rates + + if( (leaf_burn_frac < 0._r8) .or. & + (leaf_burn_frac > 1._r8) .or. & + (currentCohort%fire_mort < 0._r8) .or. & + (currentCohort%fire_mort > 1._r8)) then + write(fates_log(),*) 'unexpected fire fractions' + write(fates_log(),*) prt_params%woody(currentCohort%pft) + write(fates_log(),*) leaf_burn_frac + write(fates_log(),*) currentCohort%fire_mort + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + + do el = 1,num_elements + + leaf_m = nc%prt%GetState(leaf_organ, element_list(el)) + ! for woody plants burn only leaves + if(int(prt_params%woody(currentCohort%pft)) == itrue)then + + leaf_m = nc%prt%GetState(leaf_organ, element_list(el)) + + else + ! for grasses burn all aboveground tissues + leaf_m = nc%prt%GetState(leaf_organ, element_list(el)) + & + nc%prt%GetState(sapw_organ, element_list(el)) + & + nc%prt%GetState(struct_organ, element_list(el)) + + endif + + currentSite%mass_balance(el)%burn_flux_to_atm = & + currentSite%mass_balance(el)%burn_flux_to_atm + & + leaf_burn_frac * leaf_m * nc%n + end do + + ! Here the mass is removed from the plant + + if(int(prt_params%woody(currentCohort%pft)) == itrue)then + call PRTBurnLosses(nc%prt, leaf_organ, leaf_burn_frac) + else + call PRTBurnLosses(nc%prt, leaf_organ, leaf_burn_frac) + call PRTBurnLosses(nc%prt, sapw_organ, leaf_burn_frac) + call PRTBurnLosses(nc%prt, struct_organ, leaf_burn_frac) + endif + + currentCohort%fraction_crown_burned = 0.0_r8 + nc%fraction_crown_burned = 0.0_r8 + + + + ! Logging is the current disturbance + elseif (i_disturbance_type .eq. dtype_ilog ) then + + ! If this cohort is in the upper canopy. It generated + if(currentCohort%canopy_layer == 1)then + + ! calculate the survivorship of disturbed trees because non-harvested + nc%n = currentCohort%n * currentCohort%l_degrad + ! nc%n = (currentCohort%l_degrad / (currentCohort%l_degrad + & + ! currentCohort%lmort_direct + currentCohort%lmort_collateral + + ! currentCohort%lmort_infra) ) * & + ! currentCohort%n * patch_site_areadis/currentPatch%area + + ! Reduce counts in the existing/donor patch according to the logging rate + currentCohort%n = currentCohort%n * & + (1.0_r8 - min(1.0_r8,(currentCohort%lmort_direct + & + currentCohort%lmort_collateral + & + currentCohort%lmort_infra + currentCohort%l_degrad))) + + nc%cmort = currentCohort%cmort + nc%hmort = currentCohort%hmort + nc%bmort = currentCohort%bmort + nc%frmort = currentCohort%frmort + nc%smort = currentCohort%smort + nc%asmort = currentCohort%asmort + nc%dgmort = currentCohort%dgmort + nc%dmort = currentCohort%dmort + + ! since these are the ones that weren't logged, + ! set the logging mortality rates as zero + nc%lmort_direct = 0._r8 + nc%lmort_collateral = 0._r8 + nc%lmort_infra = 0._r8 + + else + + ! What to do with cohorts in the understory of a logging generated + ! disturbance patch? + + if(prt_params%woody(currentCohort%pft) == itrue)then + + + ! Survivorship of undestory woody plants. Two step process. + ! Step 1: Reduce current number of plants to reflect the + ! change in area. + ! The number density per square are doesn't change, + ! but since the patch is smaller + ! and cohort counts are absolute, reduce this number. + nc%n = currentCohort%n * patch_site_areadis/currentPatch%area + + ! because the mortality rate due to impact for the cohorts which had + ! been in the understory and are now in the newly- + ! disturbed patch is very high, passing the imort directly to + ! history results in large numerical errors, on account + ! of the sharply reduced number densities. so instead pass this info + ! via a site-level diagnostic variable before reducing + ! the number density. + currentSite%imort_rate(currentCohort%size_class, currentCohort%pft) = & + currentSite%imort_rate(currentCohort%size_class, currentCohort%pft) + & + nc%n * currentPatch%fract_ldist_not_harvested * & + logging_coll_under_frac / hlm_freq_day + + currentSite%imort_carbonflux(currentCohort%pft) = & + currentSite%imort_carbonflux(currentCohort%pft) + & + (nc%n * currentPatch%fract_ldist_not_harvested * & + logging_coll_under_frac/ hlm_freq_day ) * & + total_c * days_per_sec * years_per_day * ha_per_m2 + + currentSite%imort_abg_flux(currentCohort%size_class, currentCohort%pft) = & + currentSite%imort_abg_flux(currentCohort%size_class, currentCohort%pft) + & + (nc%n * currentPatch%fract_ldist_not_harvested * & + logging_coll_under_frac/ hlm_freq_day ) * & + ( ( sapw_c + struct_c + store_c) * prt_params%allom_agb_frac(currentCohort%pft) + & + leaf_c ) * days_per_sec * years_per_day * ha_per_m2 + + + ! Step 2: Apply survivor ship function based on the understory death fraction + + ! remaining of understory plants of those that are knocked + ! over by the overstorey trees dying... + ! LOGGING SURVIVORSHIP OF UNDERSTORY PLANTS IS SET AS A NEW PARAMETER + ! in the fatesparameter files + nc%n = nc%n * (1.0_r8 - & + (1.0_r8-currentPatch%fract_ldist_not_harvested) * logging_coll_under_frac) + + ! Step 3: Reduce the number count of cohorts in the + ! original/donor/non-disturbed patch to reflect the area change + currentCohort%n = currentCohort%n * (1._r8 - patch_site_areadis/currentPatch%area) + + nc%cmort = currentCohort%cmort + nc%hmort = currentCohort%hmort + nc%bmort = currentCohort%bmort + nc%frmort = currentCohort%frmort + nc%smort = currentCohort%smort + nc%asmort = currentCohort%asmort + nc%dgmort = currentCohort%dgmort + nc%dmort = currentCohort%dmort + nc%lmort_direct = currentCohort%lmort_direct + nc%lmort_collateral = currentCohort%lmort_collateral + nc%lmort_infra = currentCohort%lmort_infra + + else + + ! grass is not killed by mortality disturbance events. + ! Just move it into the new patch area. + ! Just split the grass into the existing and new patch structures + nc%n = currentCohort%n * patch_site_areadis/currentPatch%area + + ! Those remaining in the existing + currentCohort%n = currentCohort%n * (1._r8 - patch_site_areadis/currentPatch%area) + + ! No grass impact mortality imposed on the newly created patch + nc%cmort = currentCohort%cmort + nc%hmort = currentCohort%hmort + nc%bmort = currentCohort%bmort + nc%frmort = currentCohort%frmort + nc%smort = currentCohort%smort + nc%asmort = currentCohort%asmort + nc%dgmort = currentCohort%dgmort + nc%dmort = currentCohort%dmort + nc%lmort_direct = currentCohort%lmort_direct + nc%lmort_collateral = currentCohort%lmort_collateral + nc%lmort_infra = currentCohort%lmort_infra + + endif ! is/is-not woody + + endif ! Select canopy layer + + else + write(fates_log(),*) 'unknown disturbance mode?' + write(fates_log(),*) 'i_disturbance_type: ',i_disturbance_type + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if ! Select disturbance mode + + if (nc%n > 0.0_r8) then + storebigcohort => new_patch%tallest + storesmallcohort => new_patch%shortest + if(associated(new_patch%tallest))then + tnull = 0 + else + tnull = 1 + new_patch%tallest => nc + nc%taller => null() + endif + + if(associated(new_patch%shortest))then + snull = 0 + else + snull = 1 + new_patch%shortest => nc + nc%shorter => null() + endif + !nc%patchptr => new_patch + call insert_cohort(new_patch, nc, new_patch%tallest, new_patch%shortest, & + tnull, snull, storebigcohort, storesmallcohort) + + new_patch%tallest => storebigcohort + new_patch%shortest => storesmallcohort + else + + ! Get rid of the new temporary cohort + call nc%FreeMemory() + deallocate(nc, stat=istat, errmsg=smsg) + if (istat/=0) then + write(fates_log(),*) 'dealloc005: fail on deallocate(nc):'//trim(smsg) + call endrun(msg=errMsg(sourcefile, __LINE__)) + endif + endif + + currentCohort => currentCohort%taller + enddo ! currentCohort + call sort_cohorts(currentPatch) + + !update area of donor patch + oldarea = currentPatch%area + currentPatch%area = currentPatch%area - patch_site_areadis + + ! for all disturbance rates that haven't been resolved yet, increase their amount so that + ! they are the same amount of gridcell-scale disturbance relative to the original patch size + if (i_disturbance_type .ne. N_DIST_TYPES) then + do i_dist2 = i_disturbance_type+1,N_DIST_TYPES + currentPatch%disturbance_rates(i_dist2) = currentPatch%disturbance_rates(i_dist2) & + * oldarea / currentPatch%area + end do + end if + + ! sort out the cohorts, since some of them may be so small as to need removing. + ! the first call to terminate cohorts removes sparse number densities, + ! the second call removes for all other reasons (sparse culling must happen + ! before fusion) + call terminate_cohorts(currentSite, currentPatch, 1,16,bc_in) + call fuse_cohorts(currentSite,currentPatch, bc_in) + call terminate_cohorts(currentSite, currentPatch, 2,16,bc_in) + call sort_cohorts(currentPatch) + + end if ! if ( new_patch%area > nearzero ) then + + end if cp_nocomp_matches_2_if + currentPatch => currentPatch%younger + + enddo ! currentPatch patch loop. + + !*************************/ + !** INSERT NEW PATCH(ES) INTO LINKED LIST + !*************************/ + + if ( site_areadis_primary .gt. nearzero) then + currentPatch => currentSite%youngest_patch + ! insert new youngest primary patch after all the secondary patches, if there are any. + ! this requires first finding the current youngest primary to insert the new one ahead of + if (currentPatch%anthro_disturbance_label .eq. secondaryforest ) then + found_youngest_primary = .false. + do while(associated(currentPatch) .and. .not. found_youngest_primary) + currentPatch => currentPatch%older + if (associated(currentPatch)) then + if (currentPatch%anthro_disturbance_label .eq. primaryforest) then + found_youngest_primary = .true. + endif + endif + end do + if (associated(currentPatch)) then + ! the case where we've found a youngest primary patch + new_patch_primary%older => currentPatch + new_patch_primary%younger => currentPatch%younger + currentPatch%younger%older => new_patch_primary + currentPatch%younger => new_patch_primary else - snull = 1 - new_patch%shortest => nc - nc%shorter => null() + ! the case where we haven't, because the patches are all secondaary, + ! and are putting a primary patch at the oldest end of the + ! linked list (not sure how this could happen, but who knows...) + new_patch_primary%older => null() + new_patch_primary%younger => currentSite%oldest_patch + currentSite%oldest_patch%older => new_patch_primary + currentSite%oldest_patch => new_patch_primary endif - nc%patchptr => new_patch - call insert_cohort(nc, new_patch%tallest, new_patch%shortest, & - tnull, snull, storebigcohort, storesmallcohort) - - new_patch%tallest => storebigcohort - new_patch%shortest => storesmallcohort else - - ! Get rid of the new temporary cohort - call DeallocateCohort(nc) - deallocate(nc) - + ! the case where there are no secondary patches at the start of the linked list (prior logic) + new_patch_primary%older => currentPatch + new_patch_primary%younger => null() + currentPatch%younger => new_patch_primary + currentSite%youngest_patch => new_patch_primary endif - - currentCohort => currentCohort%taller - enddo ! currentCohort - call sort_cohorts(currentPatch) - - !update area of donor patch - currentPatch%area = currentPatch%area - patch_site_areadis + endif + + ! insert first secondary at the start of the list + if ( site_areadis_secondary .gt. nearzero) then + currentPatch => currentSite%youngest_patch + new_patch_secondary%older => currentPatch + new_patch_secondary%younger=> null() + currentPatch%younger => new_patch_secondary + currentSite%youngest_patch => new_patch_secondary + endif - ! sort out the cohorts, since some of them may be so small as to need removing. + + ! sort out the cohorts, since some of them may be so small as to need removing. ! the first call to terminate cohorts removes sparse number densities, ! the second call removes for all other reasons (sparse culling must happen ! before fusion) - call terminate_cohorts(currentSite, currentPatch, 1,16,bc_in) - call fuse_cohorts(currentSite,currentPatch, bc_in) - call terminate_cohorts(currentSite, currentPatch, 2,16,bc_in) - call sort_cohorts(currentPatch) - - end if ! if ( new_patch%area > nearzero ) then - - !zero disturbance rate trackers - currentPatch%disturbance_rate = 0._r8 - currentPatch%disturbance_rates = 0._r8 - currentPatch%fract_ldist_not_harvested = 0._r8 - end if cp_nocomp_matches_2_if - currentPatch => currentPatch%younger - - enddo ! currentPatch patch loop. + if ( site_areadis_primary .gt. nearzero) then + call terminate_cohorts(currentSite, new_patch_primary, 1,17, bc_in) + call fuse_cohorts(currentSite,new_patch_primary, bc_in) + call terminate_cohorts(currentSite, new_patch_primary, 2,17, bc_in) + call sort_cohorts(new_patch_primary) + endif - !*************************/ - !** INSERT NEW PATCH(ES) INTO LINKED LIST - !*************************/ - - if ( site_areadis_primary .gt. nearzero) then - currentPatch => currentSite%youngest_patch - ! insert new youngest primary patch after all the secondary patches, if there are any. - ! this requires first finding the current youngest primary to insert the new one ahead of - if (currentPatch%anthro_disturbance_label .eq. secondaryforest ) then - found_youngest_primary = .false. - do while(associated(currentPatch) .and. .not. found_youngest_primary) - currentPatch => currentPatch%older - if (associated(currentPatch)) then - if (currentPatch%anthro_disturbance_label .eq. primaryforest) then - found_youngest_primary = .true. - endif - endif - end do - if (associated(currentPatch)) then - ! the case where we've found a youngest primary patch - new_patch_primary%older => currentPatch - new_patch_primary%younger => currentPatch%younger - currentPatch%younger%older => new_patch_primary - currentPatch%younger => new_patch_primary - else - ! the case where we haven't, because the patches are all secondaary, - ! and are putting a primary patch at the oldest end of the - ! linked list (not sure how this could happen, but who knows...) - new_patch_primary%older => null() - new_patch_primary%younger => currentSite%oldest_patch - currentSite%oldest_patch%older => new_patch_primary - currentSite%oldest_patch => new_patch_primary + if ( site_areadis_secondary .gt. nearzero) then + call terminate_cohorts(currentSite, new_patch_secondary, 1,18,bc_in) + call fuse_cohorts(currentSite,new_patch_secondary, bc_in) + call terminate_cohorts(currentSite, new_patch_secondary, 2,18,bc_in) + call sort_cohorts(new_patch_secondary) endif - else - ! the case where there are no secondary patches at the start of the linked list (prior logic) - new_patch_primary%older => currentPatch - new_patch_primary%younger => null() - currentPatch%younger => new_patch_primary - currentSite%youngest_patch => new_patch_primary - endif - endif - - ! insert first secondary at the start of the list - if ( site_areadis_secondary .gt. nearzero) then - currentPatch => currentSite%youngest_patch - new_patch_secondary%older => currentPatch - new_patch_secondary%younger=> null() - currentPatch%younger => new_patch_secondary - currentSite%youngest_patch => new_patch_secondary - endif - - - ! sort out the cohorts, since some of them may be so small as to need removing. - ! the first call to terminate cohorts removes sparse number densities, - ! the second call removes for all other reasons (sparse culling must happen - ! before fusion) - - if ( site_areadis_primary .gt. nearzero) then - call terminate_cohorts(currentSite, new_patch_primary, 1,17, bc_in) - call fuse_cohorts(currentSite,new_patch_primary, bc_in) - call terminate_cohorts(currentSite, new_patch_primary, 2,17, bc_in) - call sort_cohorts(new_patch_primary) - endif - - if ( site_areadis_secondary .gt. nearzero) then - call terminate_cohorts(currentSite, new_patch_secondary, 1,18,bc_in) - call fuse_cohorts(currentSite,new_patch_secondary, bc_in) - call terminate_cohorts(currentSite, new_patch_secondary, 2,18,bc_in) - call sort_cohorts(new_patch_secondary) - endif - - endif !end new_patch area - - - call check_patch_area(currentSite) - call set_patchno(currentSite) - + + endif !end new_patch area + + + call check_patch_area(currentSite) + call set_patchno(currentSite) + + end do disturbance_type_loop + end do nocomp_pft_loop + + !zero disturbance rate trackers on all patches + currentPatch => currentSite%oldest_patch + do while(associated(currentPatch)) + currentPatch%disturbance_rates(:) = 0._r8 + currentPatch%fract_ldist_not_harvested = 0._r8 + currentPatch => currentPatch%younger + end do + return end subroutine spawn_patches @@ -1231,12 +1277,12 @@ subroutine check_patch_area( currentSite ) ! !USES: ! ! !ARGUMENTS: - type(ed_site_type), intent(inout), target :: currentSite + type(ed_site_type), intent(inout) :: currentSite ! ! !LOCAL VARIABLES: real(r8) :: areatot - type(ed_patch_type), pointer :: currentPatch - type(ed_patch_type), pointer :: largestPatch + type(fates_patch_type), pointer :: currentPatch + type(fates_patch_type), pointer :: largestPatch real(r8) :: largest_area integer :: el real(r8) :: live_stock @@ -1303,10 +1349,10 @@ subroutine set_patchno( currentSite ) ! !USES: ! ! !ARGUMENTS: - type(ed_site_type),intent(in), target :: currentSite + type(ed_site_type),intent(in) :: currentSite ! ! !LOCAL VARIABLES: - type(ed_patch_type), pointer :: currentPatch + type(fates_patch_type), pointer :: currentPatch integer patchno !--------------------------------------------------------------------- @@ -1318,11 +1364,11 @@ subroutine set_patchno( currentSite ) currentPatch => currentPatch%younger enddo - if(hlm_use_sp.eq.itrue)then + if(hlm_use_fixed_biogeog.eq.itrue .and. hlm_use_nocomp.eq.itrue)then patchno = 1 currentPatch => currentSite%oldest_patch do while(associated(currentPatch)) - if(currentPatch%nocomp_pft_label.eq.0)then + if(currentPatch%nocomp_pft_label.eq.nocomp_bareground)then ! for bareground patch, we make the patch number 0 ! we also do not count this in the veg. patch numbering scheme. currentPatch%patchno = 0 @@ -1385,11 +1431,11 @@ subroutine TransLitterNewPatch(currentSite, & ! !USES: ! ! !ARGUMENTS: - type(ed_site_type) , intent(in), target :: currentSite ! site - type(ed_patch_type) , intent(in), target :: currentPatch ! Donor patch - type(ed_patch_type) , intent(inout) :: newPatch ! New patch - real(r8) , intent(in) :: patch_site_areadis ! Area being donated - ! by current patch + type(ed_site_type) , intent(in) :: currentSite ! site + type(fates_patch_type) , intent(in) :: currentPatch ! Donor patch + type(fates_patch_type) , intent(inout) :: newPatch ! New patch + real(r8) , intent(in) :: patch_site_areadis ! Area being donated + ! by current patch ! locals @@ -1599,15 +1645,15 @@ subroutine fire_litter_fluxes(currentSite, currentPatch, & ! ! !ARGUMENTS: type(ed_site_type) , intent(inout), target :: currentSite - type(ed_patch_type) , intent(inout), target :: currentPatch ! Donor Patch - type(ed_patch_type) , intent(inout), target :: newPatch ! New Patch + type(fates_patch_type) , intent(inout), target :: currentPatch ! Donor Patch + type(fates_patch_type) , intent(inout), target :: newPatch ! New Patch real(r8) , intent(in) :: patch_site_areadis ! Area being donated type(bc_in_type) , intent(in) :: bc_in ! ! !LOCAL VARIABLES: - type(ed_cohort_type), pointer :: currentCohort + type(fates_cohort_type), pointer :: currentCohort type(litter_type), pointer :: new_litt type(litter_type), pointer :: curr_litt type(site_massbal_type), pointer :: site_mass @@ -1639,7 +1685,7 @@ subroutine fire_litter_fluxes(currentSite, currentPatch, & integer :: pft ! loop index for plant functional types integer :: dcmpy ! loop index for decomposability pool integer :: element_id ! parteh compatible global element index - + real(r8) :: SF_val_CWD_frac_adj(4) !Updated wood partitioning to CWD based on dbh !--------------------------------------------------------------------- ! Only do this if there was a fire in this actual patch. @@ -1698,19 +1744,31 @@ subroutine fire_litter_fluxes(currentSite, currentPatch, & do while(associated(currentCohort)) pft = currentCohort%pft - + ! Number of trees that died because of the fire, per m2 of ground. ! Divide their litter into the four litter streams, and spread ! across ground surface. ! ----------------------------------------------------------------------- - - sapw_m = currentCohort%prt%GetState(sapw_organ, element_id) - struct_m = currentCohort%prt%GetState(struct_organ, element_id) - leaf_m = currentCohort%prt%GetState(leaf_organ, element_id) + fnrt_m = currentCohort%prt%GetState(fnrt_organ, element_id) store_m = currentCohort%prt%GetState(store_organ, element_id) repro_m = currentCohort%prt%GetState(repro_organ, element_id) - + + if (prt_params%woody(currentCohort%pft) == itrue) then + ! Assumption: for woody plants fluxes from deadwood and sapwood go together in CWD pool + leaf_m = currentCohort%prt%GetState(leaf_organ,element_id) + sapw_m = currentCohort%prt%GetState(sapw_organ,element_id) + struct_m = currentCohort%prt%GetState(struct_organ,element_id) + else + ! for non-woody plants all stem fluxes go into the same leaf litter pool + leaf_m = currentCohort%prt%GetState(leaf_organ,element_id) + & + currentCohort%prt%GetState(sapw_organ,element_id) + & + currentCohort%prt%GetState(struct_organ,element_id) + sapw_m = 0._r8 + struct_m = 0._r8 + end if + + ! Absolute number of dead trees being transfered in with the donated area num_dead_trees = (currentCohort%fire_mort*currentCohort%n * & patch_site_areadis/currentPatch%area) @@ -1721,7 +1779,7 @@ subroutine fire_litter_fluxes(currentSite, currentPatch, & ! Contribution of dead trees to leaf burn-flux burned_mass = num_dead_trees * (leaf_m+repro_m) * currentCohort%fraction_crown_burned - + do dcmpy=1,ndcmpy dcmpy_frac = GetDecompyFrac(pft,leaf_organ,dcmpy) new_litt%leaf_fines(dcmpy) = new_litt%leaf_fines(dcmpy) + & @@ -1755,14 +1813,18 @@ subroutine fire_litter_fluxes(currentSite, currentPatch, & flux_diags%root_litter_input(pft) = & flux_diags%root_litter_input(pft) + & (fnrt_m + store_m) * num_dead_trees - + ! coarse root biomass per tree bcroot = (sapw_m + struct_m) * (1.0_r8 - prt_params%allom_agb_frac(pft) ) - + ! below ground coarse woody debris from burned trees + + !adjust the how wood is partitioned between the cwd classes based on cohort dbh + call adjust_SF_CWD_frac(currentCohort%dbh,ncwd,SF_val_CWD_frac,SF_val_CWD_frac_adj) + do c = 1,ncwd do sl = 1,currentSite%nlevsoil - donatable_mass = num_dead_trees * SF_val_CWD_frac(c) * & + donatable_mass = num_dead_trees * SF_val_CWD_frac_adj(c) * & bcroot * currentSite%rootfrac_scr(sl) new_litt%bg_cwd(c,sl) = new_litt%bg_cwd(c,sl) + & @@ -1783,18 +1845,18 @@ subroutine fire_litter_fluxes(currentSite, currentPatch, & ! Above ground coarse woody debris from twigs and small branches ! a portion of this pool may burn do c = 1,ncwd - donatable_mass = num_dead_trees * SF_val_CWD_frac(c) * bstem + donatable_mass = num_dead_trees * SF_val_CWD_frac_adj(c) * bstem if (c == 1 .or. c == 2) then donatable_mass = donatable_mass * (1.0_r8-currentCohort%fraction_crown_burned) - burned_mass = num_dead_trees * SF_val_CWD_frac(c) * bstem * & + burned_mass = num_dead_trees * SF_val_CWD_frac_adj(c) * bstem * & currentCohort%fraction_crown_burned site_mass%burn_flux_to_atm = site_mass%burn_flux_to_atm + burned_mass endif new_litt%ag_cwd(c) = new_litt%ag_cwd(c) + donatable_mass * donate_m2 curr_litt%ag_cwd(c) = curr_litt%ag_cwd(c) + donatable_mass * retain_m2 flux_diags%cwd_ag_input(c) = flux_diags%cwd_ag_input(c) + donatable_mass - enddo - + enddo + currentCohort => currentCohort%taller enddo @@ -1825,13 +1887,13 @@ subroutine mortality_litter_fluxes(currentSite, currentPatch, & ! ! !ARGUMENTS: type(ed_site_type) , intent(inout), target :: currentSite - type(ed_patch_type) , intent(inout), target :: currentPatch - type(ed_patch_type) , intent(inout), target :: newPatch + type(fates_patch_type) , intent(inout), target :: currentPatch + type(fates_patch_type) , intent(inout), target :: newPatch real(r8) , intent(in) :: patch_site_areadis type(bc_in_type) , intent(in) :: bc_in ! ! !LOCAL VARIABLES: - type(ed_cohort_type), pointer :: currentCohort + type(fates_cohort_type), pointer :: currentCohort type(litter_type), pointer :: new_litt type(litter_type), pointer :: curr_litt type(site_massbal_type), pointer :: site_mass @@ -1859,7 +1921,8 @@ subroutine mortality_litter_fluxes(currentSite, currentPatch, & integer :: el ! element loop index integer :: sl ! soil layer index integer :: element_id ! parteh compatible global element index - real(r8) :: dcmpy_frac ! decomposability fraction + real(r8) :: dcmpy_frac ! decomposability fraction + real(r8) :: SF_val_CWD_frac_adj(4) !Updated wood partitioning to CWD based on dbh !--------------------------------------------------------------------- remainder_area = currentPatch%area - patch_site_areadis @@ -1890,13 +1953,24 @@ subroutine mortality_litter_fluxes(currentSite, currentPatch, & pft = currentCohort%pft - sapw_m = currentCohort%prt%GetState(sapw_organ, element_id) - struct_m = currentCohort%prt%GetState(struct_organ, element_id) - leaf_m = currentCohort%prt%GetState(leaf_organ, element_id) fnrt_m = currentCohort%prt%GetState(fnrt_organ, element_id) store_m = currentCohort%prt%GetState(store_organ, element_id) repro_m = currentCohort%prt%GetState(repro_organ, element_id) + if (prt_params%woody(currentCohort%pft) == itrue) then + ! Assumption: for woody plants fluxes from deadwood and sapwood go together in CWD pool + leaf_m = currentCohort%prt%GetState(leaf_organ,element_id) + sapw_m = currentCohort%prt%GetState(sapw_organ,element_id) + struct_m = currentCohort%prt%GetState(struct_organ,element_id) + else + ! for non-woody plants all stem fluxes go into the same leaf litter pool + leaf_m = currentCohort%prt%GetState(leaf_organ,element_id) + & + currentCohort%prt%GetState(sapw_organ,element_id) + & + currentCohort%prt%GetState(struct_organ,element_id) + sapw_m = 0._r8 + struct_m = 0._r8 + end if + if(currentCohort%canopy_layer == 1)then ! Upper canopy trees. The total dead is based on their disturbance @@ -1905,7 +1979,7 @@ subroutine mortality_litter_fluxes(currentSite, currentPatch, & num_dead = currentCohort%n * min(1.0_r8,currentCohort%dmort * & hlm_freq_day * fates_mortality_disturbance_fraction) - elseif(int(prt_params%woody(pft)) == itrue) then + elseif(prt_params%woody(pft) == itrue) then ! Understorey trees. The total dead is based on their survivorship ! function, and the total area of disturbance. @@ -1946,24 +2020,26 @@ subroutine mortality_litter_fluxes(currentSite, currentPatch, & call set_root_fraction(currentSite%rootfrac_scr, pft, currentSite%zi_soil, & bc_in%max_rooting_depth_index_col) + ! Adjust how wood is partitioned between the cwd classes based on cohort dbh + call adjust_SF_CWD_frac(currentCohort%dbh,ncwd,SF_val_CWD_frac,SF_val_CWD_frac_adj) do c=1,ncwd - + ! Transfer wood of dying trees to AG CWD pools new_litt%ag_cwd(c) = new_litt%ag_cwd(c) + ag_wood * & - SF_val_CWD_frac(c) * donate_m2 + SF_val_CWD_frac_adj(c) * donate_m2 curr_litt%ag_cwd(c) = curr_litt%ag_cwd(c) + ag_wood * & - SF_val_CWD_frac(c) * retain_m2 + SF_val_CWD_frac_adj(c) * retain_m2 ! Transfer wood of dying trees to BG CWD pools do sl = 1,currentSite%nlevsoil new_litt%bg_cwd(c,sl) = new_litt%bg_cwd(c,sl) + bg_wood * & - currentSite%rootfrac_scr(sl) * SF_val_CWD_frac(c) * & + currentSite%rootfrac_scr(sl) * SF_val_CWD_frac_adj(c) * & donate_m2 curr_litt%bg_cwd(c,sl) = curr_litt%bg_cwd(c,sl) + bg_wood * & - currentSite%rootfrac_scr(sl) * SF_val_CWD_frac(c) * & + currentSite%rootfrac_scr(sl) * SF_val_CWD_frac_adj(c) * & retain_m2 end do end do @@ -1999,10 +2075,10 @@ subroutine mortality_litter_fluxes(currentSite, currentPatch, & ! track diagnostic fluxes do c=1,ncwd flux_diags%cwd_ag_input(c) = & - flux_diags%cwd_ag_input(c) + SF_val_CWD_frac(c) * ag_wood + flux_diags%cwd_ag_input(c) + SF_val_CWD_frac_adj(c) * ag_wood flux_diags%cwd_bg_input(c) = & - flux_diags%cwd_bg_input(c) + SF_val_CWD_frac(c) * bg_wood + flux_diags%cwd_bg_input(c) + SF_val_CWD_frac_adj(c) * bg_wood end do flux_diags%leaf_litter_input(pft) = flux_diags%leaf_litter_input(pft) + & @@ -2023,253 +2099,7 @@ subroutine mortality_litter_fluxes(currentSite, currentPatch, & end subroutine mortality_litter_fluxes ! ============================================================================ - - subroutine create_patch(currentSite, new_patch, age, areap, label,nocomp_pft) - - use FatesInterfaceTypesMod, only : hlm_current_tod,hlm_current_date,hlm_reference_date - - ! - ! !DESCRIPTION: - ! Set default values for creating a new patch - ! - ! !USES: - ! - ! !ARGUMENTS: - type(ed_site_type) , intent(inout), target :: currentSite - type(ed_patch_type), intent(inout), target :: new_patch - real(r8), intent(in) :: age ! notional age of this patch in years - real(r8), intent(in) :: areap ! initial area of this patch in m2. - integer, intent(in) :: label ! anthropogenic disturbance label - integer, intent(in) :: 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 - - - ! !LOCAL VARIABLES: - !--------------------------------------------------------------------- - integer :: el ! element loop index - - - allocate(new_patch%tr_soil_dir(hlm_numSWb)) - allocate(new_patch%tr_soil_dif(hlm_numSWb)) - allocate(new_patch%tr_soil_dir_dif(hlm_numSWb)) - allocate(new_patch%fab(hlm_numSWb)) - allocate(new_patch%fabd(hlm_numSWb)) - allocate(new_patch%fabi(hlm_numSWb)) - allocate(new_patch%sabs_dir(hlm_numSWb)) - allocate(new_patch%sabs_dif(hlm_numSWb)) - allocate(new_patch%fragmentation_scaler(currentSite%nlevsoil)) - - allocate(new_patch%tveg24) - 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) - - ! Litter - ! Allocate, Zero Fluxes, and Initialize to "unset" values - - allocate(new_patch%litter(num_elements)) - do el=1,num_elements - call new_patch%litter(el)%InitAllocate(numpft,currentSite%nlevsoil,element_list(el)) - call new_patch%litter(el)%ZeroFlux() - call new_patch%litter(el)%InitConditions(init_leaf_fines = fates_unset_r8, & - init_root_fines = fates_unset_r8, & - init_ag_cwd = fates_unset_r8, & - init_bg_cwd = fates_unset_r8, & - init_seed = fates_unset_r8, & - init_seed_germ = fates_unset_r8) - end do - - call zero_patch(new_patch) !The nan value in here is not working?? - - new_patch%tallest => null() ! pointer to patch's tallest cohort - new_patch%shortest => null() ! pointer to patch's shortest cohort - new_patch%older => null() ! pointer to next older patch - new_patch%younger => null() ! pointer to next shorter patch - - ! assign known patch attributes - - new_patch%age = age - new_patch%age_class = 1 - new_patch%area = areap - - ! assign anthropgenic disturbance category and label - new_patch%anthro_disturbance_label = label - if (label .eq. secondaryforest) then - new_patch%age_since_anthro_disturbance = age - else - new_patch%age_since_anthro_disturbance = fates_unset_r8 - endif - new_patch%nocomp_pft_label = nocomp_pft - - ! This new value will be generated when the calculate disturbance - ! rates routine is called. This does not need to be remembered or in the restart file. - new_patch%disturbance_mode = fates_unset_int - - new_patch%f_sun = 0._r8 - new_patch%ed_laisun_z(:,:,:) = 0._r8 - new_patch%ed_laisha_z(:,:,:) = 0._r8 - new_patch%ed_parsun_z(:,:,:) = 0._r8 - new_patch%ed_parsha_z(:,:,:) = 0._r8 - new_patch%fabi = 0._r8 - new_patch%fabd = 0._r8 - new_patch%tr_soil_dir(:) = 1._r8 - new_patch%tr_soil_dif(:) = 1._r8 - new_patch%tr_soil_dir_dif(:) = 0._r8 - new_patch%fabd_sun_z(:,:,:) = 0._r8 - new_patch%fabd_sha_z(:,:,:) = 0._r8 - new_patch%fabi_sun_z(:,:,:) = 0._r8 - new_patch%fabi_sha_z(:,:,:) = 0._r8 - new_patch%scorch_ht(:) = 0._r8 - new_patch%frac_burnt = 0._r8 - new_patch%litter_moisture(:) = 0._r8 - new_patch%fuel_eff_moist = 0._r8 - new_patch%livegrass = 0._r8 - new_patch%sum_fuel = 0._r8 - new_patch%fuel_bulkd = 0._r8 - new_patch%fuel_sav = 0._r8 - new_patch%fuel_mef = 0._r8 - new_patch%ros_front = 0._r8 - new_patch%effect_wspeed = 0._r8 - new_patch%tau_l = 0._r8 - new_patch%fuel_frac(:) = 0._r8 - new_patch%tfc_ros = 0._r8 - new_patch%fi = 0._r8 - new_patch%fd = 0._r8 - new_patch%ros_back = 0._r8 - new_patch%scorch_ht(:) = 0._r8 - new_patch%burnt_frac_litter(:) = 0._r8 - new_patch%total_tree_area = 0.0_r8 - new_patch%NCL_p = 1 - - - return - end subroutine create_patch - - ! ============================================================================ - subroutine zero_patch(cp_p) - ! - ! !DESCRIPTION: - ! Sets all the variables in the patch to nan or zero - ! (this needs to be two seperate routines, one for nan & one for zero - ! - ! !USES: - ! - ! !ARGUMENTS: - type(ed_patch_type), intent(inout), target :: cp_p - ! - ! !LOCAL VARIABLES: - type(ed_patch_type), pointer :: currentPatch - !--------------------------------------------------------------------- - - currentPatch => cp_p - - currentPatch%tallest => null() - currentPatch%shortest => null() - currentPatch%older => null() - currentPatch%younger => null() - - currentPatch%patchno = 999 - - currentPatch%age = nan - currentPatch%age_class = 1 - currentPatch%area = nan - currentPatch%canopy_layer_tlai(:) = nan - currentPatch%total_canopy_area = nan - - currentPatch%tlai_profile(:,:,:) = nan - currentPatch%elai_profile(:,:,:) = 0._r8 - currentPatch%tsai_profile(:,:,:) = nan - currentPatch%esai_profile(:,:,:) = nan - currentPatch%canopy_area_profile(:,:,:) = nan - - currentPatch%fabd_sun_z(:,:,:) = nan - currentPatch%fabd_sha_z(:,:,:) = nan - currentPatch%fabi_sun_z(:,:,:) = nan - currentPatch%fabi_sha_z(:,:,:) = nan - - currentPatch%ed_laisun_z(:,:,:) = nan - currentPatch%ed_laisha_z(:,:,:) = nan - currentPatch%ed_parsun_z(:,:,:) = nan - currentPatch%ed_parsha_z(:,:,:) = nan - currentPatch%psn_z(:,:,:) = 0._r8 - - currentPatch%f_sun(:,:,:) = nan - currentPatch%tr_soil_dir(:) = nan ! fraction of incoming direct radiation that is transmitted to the soil as direct - currentPatch%tr_soil_dif(:) = nan ! fraction of incoming diffuse radiation that is transmitted to the soil as diffuse - currentPatch%tr_soil_dir_dif(:) = nan ! fraction of incoming direct radiation that is transmitted to the soil as diffuse - currentPatch%fabd(:) = nan ! fraction of incoming direct radiation that is absorbed by the canopy - currentPatch%fabi(:) = nan ! fraction of incoming diffuse radiation that is absorbed by the canopy - - currentPatch%canopy_mask(:,:) = 999 ! is there any of this pft in this layer? - currentPatch%nrad(:,:) = 999 ! number of exposed leaf layers for each canopy layer and pft - currentPatch%ncan(:,:) = 999 ! number of total leaf layers for each canopy layer and pft - currentPatch%pft_agb_profile(:,:) = nan - - ! DISTURBANCE - currentPatch%disturbance_rates = 0._r8 - currentPatch%disturbance_rate = 0._r8 - currentPatch%fract_ldist_not_harvested = 0._r8 - - - ! FIRE - currentPatch%litter_moisture(:) = nan ! litter moisture - currentPatch%fuel_eff_moist = nan ! average fuel moisture content of the ground fuel - ! (incl. live grasses. omits 1000hr fuels) - currentPatch%livegrass = nan ! total ag grass biomass in patch. 1=c3 grass, 2=c4 grass. gc/m2 - currentPatch%sum_fuel = nan ! total ground fuel related to ros (omits 1000hr fuels). gc/m2 - currentPatch%fuel_bulkd = nan ! average fuel bulk density of the ground fuel - ! (incl. live grasses. omits 1000hr fuels). kgc/m3 - currentPatch%fuel_sav = nan ! average surface area to volume ratio of the ground fuel - ! (incl. live grasses. omits 1000hr fuels). - currentPatch%fuel_mef = nan ! average moisture of extinction factor of the ground fuel - ! (incl. live grasses. omits 1000hr fuels). - currentPatch%ros_front = nan ! average rate of forward spread of each fire in the patch. m/min. - currentPatch%effect_wspeed = nan ! dailywind modified by fraction of relative grass and tree cover. m/min. - currentPatch%tau_l = nan ! mins p&r(1986) - currentPatch%fuel_frac(:) = nan ! fraction of each litter class in the sum_fuel - !- for purposes of calculating weighted averages. - currentPatch%tfc_ros = nan ! used in fi calc - currentPatch%fi = nan ! average fire intensity of flaming front during day. - ! backward ros plays no role. kj/m/s or kw/m. - currentPatch%fire = 999 ! sr decide_fire.1=fire hot enough to proceed. 0=stop everything- no fires today - currentPatch%active_crown_fire_flg = 9999 ! flag to indicate active crown fire ignition - currentPatch%fd = nan ! fire duration (mins) - currentPatch%ros_back = nan ! backward ros (m/min) - currentPatch%scorch_ht(:) = nan ! scorch height of flames on a given PFT - currentPatch%frac_burnt = nan ! fraction burnt daily - currentPatch%burnt_frac_litter(:) = nan - currentPatch%btran_ft(:) = 0.0_r8 - - currentPatch%canopy_layer_tlai(:) = 0.0_r8 - - currentPatch%fab(:) = 0.0_r8 - currentPatch%sabs_dir(:) = 0.0_r8 - currentPatch%sabs_dif(:) = 0.0_r8 - currentPatch%zstar = 0.0_r8 - currentPatch%c_stomata = 0.0_r8 ! This is calculated immediately before use - currentPatch%c_lblayer = 0.0_r8 - currentPatch%fragmentation_scaler(:) = 0.0_r8 - currentPatch%radiation_error = 0.0_r8 - - ! diagnostic radiation profiles - currentPatch%nrmlzd_parprof_pft_dir_z(:,:,:,:) = 0._r8 - currentPatch%nrmlzd_parprof_pft_dif_z(:,:,:,:) = 0._r8 - currentPatch%nrmlzd_parprof_dir_z(:,:,:) = 0._r8 - currentPatch%nrmlzd_parprof_dif_z(:,:,:) = 0._r8 - - currentPatch%solar_zenith_flag = .false. - currentPatch%solar_zenith_angle = nan - currentPatch%fcansno = nan - - currentPatch%gnd_alb_dir(:) = nan - currentPatch%gnd_alb_dif(:) = nan - - end subroutine zero_patch - - ! ============================================================================ + subroutine fuse_patches( csite, bc_in ) ! ! !DESCRIPTION: @@ -2286,7 +2116,7 @@ subroutine fuse_patches( csite, bc_in ) ! ! !LOCAL VARIABLES: type(ed_site_type) , pointer :: currentSite - type(ed_patch_type), pointer :: currentPatch,tpp,tmpptr + type(fates_patch_type), pointer :: currentPatch,tpp,tmpptr integer :: ft,z !counters for pft and height class real(r8) :: norm !normalized difference between biomass profiles real(r8) :: profiletol !tolerance of patch fusion routine. Starts off high and is reduced if there are too many patches. @@ -2315,15 +2145,16 @@ subroutine fuse_patches( csite, bc_in ) ! to let there be one for each type of nocomp PFT on the site. this is likely to lead to problems ! if anthropogenic disturance is enabled. if (hlm_use_nocomp.eq.itrue) then - maxpatches(primaryforest) = max(maxPatchesPerSite_by_disttype(primaryforest), sum(csite%use_this_pft)) - maxpatches(secondaryforest) = maxPatchesPerSite - maxpatches(primaryforest) - if (maxPatchesPerSite .lt. maxpatches(primaryforest)) then + maxpatches(primaryforest) = max(maxpatch_primary, sum(csite%use_this_pft)) + maxpatches(secondaryforest) = maxpatch_total - maxpatches(primaryforest) + if (maxpatch_total .lt. maxpatches(primaryforest)) then write(fates_log(),*) 'too many PFTs and not enough patches for nocomp w/o fixed biogeog' - write(fates_log(),*) 'maxPatchesPerSite,numpft',maxPatchesPerSite,numpft, sum(csite%use_this_pft) + write(fates_log(),*) 'maxpatch_total,numpft',maxpatch_total,numpft, sum(csite%use_this_pft) call endrun(msg=errMsg(sourcefile, __LINE__)) endif else - maxpatches(:) = maxPatchesPerSite_by_disttype(:) + maxpatches(primaryforest) = maxpatch_primary + maxpatches(secondaryforest) = maxpatch_secondary endif currentPatch => currentSite%youngest_patch @@ -2359,7 +2190,7 @@ subroutine fuse_patches( csite, bc_in ) iterate = 1 !---------------------------------------------------------------------! - ! Keep doing this until nopatches <= maxPatchesPerSite ! + ! Keep doing this until nopatches <= maxpatch_total ! !---------------------------------------------------------------------! iterate_eq_1_loop: do while(iterate == 1) @@ -2387,10 +2218,6 @@ subroutine fuse_patches( csite, bc_in ) tpp => currentSite%youngest_patch tpp_loop: do while(associated(tpp)) - if(.not.associated(currentPatch))then - write(fates_log(),*) 'ED: issue with currentPatch' - endif - both_associated_if: if(associated(tpp).and.associated(currentPatch))then !--------------------------------------------------------------------! ! only fuse patches whose anthropogenic disturbance category matches ! @@ -2500,19 +2327,20 @@ subroutine fuse_patches( csite, bc_in ) ! a patch x patch loop, reset the patch fusion tolerance to the starting ! ! value so that any subsequent fusions in this loop are done with that ! ! value. otherwise we can end up in a situation where we've loosened the ! - ! fusion tolerance to get nopatches <= maxPatchesPerSite, but then, ! + ! fusion tolerance to get nopatches <= maxpatch_total, but then, ! ! having accomplished that, we continue through all the patch x patch ! ! combinations and then all the patches get fused, ending up with ! - ! nopatches << maxPatchesPerSite and losing all heterogeneity. ! + ! nopatches << maxpatch_total and losing all heterogeneity. ! !------------------------------------------------------------------------! profiletol = ED_val_patch_fusion_tol - + endif fuseflagset_if endif different_patches_if endif nocomp_pft_labels_match_if endif anthro_dist_labels_match_if endif both_associated_if + tpp => tpp%older enddo tpp_loop @@ -2561,7 +2389,7 @@ subroutine fuse_patches( csite, bc_in ) iterate = 0 endif - enddo iterate_eq_1_loop ! iterate .eq. 1 ==> nopatches>maxPatchesPerSite + enddo iterate_eq_1_loop ! iterate .eq. 1 ==> nopatches>maxpatch_total end do disttype_loop @@ -2595,20 +2423,21 @@ subroutine fuse_2_patches(csite, dp, rp) ! ! !ARGUMENTS: type (ed_site_type), intent(inout),target :: csite ! Current site - type (ed_patch_type) , pointer :: dp ! Donor Patch - type (ed_patch_type) , target, intent(inout) :: rp ! Recipient Patch + type (fates_patch_type) , pointer :: dp ! Donor Patch + type (fates_patch_type) , target, intent(inout) :: rp ! Recipient Patch ! ! !LOCAL VARIABLES: - type (ed_cohort_type), pointer :: currentCohort ! Current Cohort - type (ed_cohort_type), pointer :: nextc ! Remembers next cohort in list - type (ed_cohort_type), pointer :: storesmallcohort - type (ed_cohort_type), pointer :: storebigcohort + type (fates_cohort_type), pointer :: currentCohort ! Current Cohort + type (fates_cohort_type), pointer :: nextc ! Remembers next cohort in list + type (fates_cohort_type), pointer :: storesmallcohort + type (fates_cohort_type), pointer :: storebigcohort integer :: c,p !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 - type(ed_patch_type), pointer :: olderp ! pointer to the patch older than donor + integer :: pft ! loop counter for pfts + type(fates_patch_type), pointer :: youngerp ! pointer to the patch younger than donor + type(fates_patch_type), pointer :: olderp ! pointer to the patch older than donor real(r8) :: inv_sum_area ! Inverse of the sum of the two patches areas !----------------------------------------------------------------------------------------------- @@ -2642,7 +2471,19 @@ 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) + + 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 rp%sum_fuel = (dp%sum_fuel*dp%area + rp%sum_fuel*rp%area) * inv_sum_area @@ -2659,6 +2500,7 @@ subroutine fuse_2_patches(csite, dp, rp) rp%ros_back = (dp%ros_back*dp%area + rp%ros_back*rp%area) * inv_sum_area rp%scorch_ht(:) = (dp%scorch_ht(:)*dp%area + rp%scorch_ht(:)*rp%area) * inv_sum_area rp%frac_burnt = (dp%frac_burnt*dp%area + rp%frac_burnt*rp%area) * inv_sum_area + rp%canopy_bulk_density = (dp%canopy_bulk_density*dp%area + rp%canopy_bulk_density*rp%area) * inv_sum_area rp%burnt_frac_litter(:) = (dp%burnt_frac_litter(:)*dp%area + rp%burnt_frac_litter(:)*rp%area) * inv_sum_area rp%btran_ft(:) = (dp%btran_ft(:)*dp%area + rp%btran_ft(:)*rp%area) * inv_sum_area rp%zstar = (dp%zstar*dp%area + rp%zstar*rp%area) * inv_sum_area @@ -2695,12 +2537,13 @@ subroutine fuse_2_patches(csite, dp, rp) rp%shortest => currentCohort endif - call insert_cohort(currentCohort, rp%tallest, rp%shortest, tnull, snull, storebigcohort, storesmallcohort) + call insert_cohort(rp, currentCohort, rp%tallest, rp%shortest, & + tnull, snull, storebigcohort, storesmallcohort) rp%tallest => storebigcohort rp%shortest => storesmallcohort - currentCohort%patchptr => rp + !currentCohort%patchptr => rp currentCohort => nextc @@ -2730,9 +2573,12 @@ subroutine fuse_2_patches(csite, dp, rp) end if ! We have no need for the dp pointer anymore, we have passed on it's legacy - call dealloc_patch(dp) - deallocate(dp) - + call dp%FreeMemory(regeneration_model, numpft) + deallocate(dp, stat=istat, errmsg=smsg) + if (istat/=0) then + write(fates_log(),*) 'dealloc006: fail on deallocate(dp):'//trim(smsg) + call endrun(msg=errMsg(sourcefile, __LINE__)) + endif if(associated(youngerp))then ! Update the younger patch's new older patch (because it isn't dp anymore) @@ -2772,10 +2618,10 @@ subroutine terminate_patches(currentSite) type(ed_site_type), target, intent(inout) :: currentSite ! ! !LOCAL VARIABLES: - type(ed_patch_type), pointer :: currentPatch - type(ed_patch_type), pointer :: olderPatch - type(ed_patch_type), pointer :: youngerPatch - type(ed_patch_type), pointer :: patchpointer + type(fates_patch_type), pointer :: currentPatch + type(fates_patch_type), pointer :: olderPatch + type(fates_patch_type), pointer :: youngerPatch + type(fates_patch_type), pointer :: patchpointer integer, parameter :: max_cycles = 10 ! After 10 loops through ! You should had fused integer :: count_cycles @@ -2941,7 +2787,7 @@ subroutine DistributeSeeds(currentSite,seed_mass,el,pft) integer, intent(in) :: pft ! pft index ! !LOCAL VARIABLES: - type(ed_patch_type), pointer :: currentPatch + type(fates_patch_type), pointer :: currentPatch type(litter_type), pointer :: litt @@ -2962,61 +2808,6 @@ subroutine DistributeSeeds(currentSite,seed_mass,el,pft) return end subroutine DistributeSeeds - - ! ===================================================================================== - - subroutine dealloc_patch(cpatch) - - ! This Subroutine is intended to de-allocate the allocatable memory that is pointed - ! to via the patch structure. This subroutine DOES NOT deallocate the patch - ! structure itself. - - type(ed_patch_type), target :: cpatch - - type(ed_cohort_type), pointer :: ccohort ! current - type(ed_cohort_type), pointer :: ncohort ! next - integer :: el ! loop counter for elements - - ! First Deallocate the cohort space - ! ----------------------------------------------------------------------------------- - ccohort => cpatch%shortest - do while(associated(ccohort)) - - ncohort => ccohort%taller - - call DeallocateCohort(ccohort) - deallocate(ccohort) - ccohort => ncohort - - end do - - ! Deallocate all litter objects - do el=1,num_elements - call cpatch%litter(el)%DeallocateLitt() - end do - deallocate(cpatch%litter) - - ! Secondly, and lastly, deallocate the allocatable vector spaces in the patch - if(allocated(cpatch%tr_soil_dir))then - deallocate(cpatch%tr_soil_dir) - deallocate(cpatch%tr_soil_dif) - deallocate(cpatch%tr_soil_dir_dif) - deallocate(cpatch%fab) - deallocate(cpatch%fabd) - deallocate(cpatch%fabi) - deallocate(cpatch%sabs_dir) - deallocate(cpatch%sabs_dif) - deallocate(cpatch%fragmentation_scaler) - end if - - - ! Deallocate any running means - deallocate(cpatch%tveg24) - deallocate(cpatch%tveg_lpa) - - return - end subroutine dealloc_patch - ! ============================================================================ subroutine patch_pft_size_profile(cp_pnt) ! @@ -3026,11 +2817,11 @@ subroutine patch_pft_size_profile(cp_pnt) ! !USES: ! ! !ARGUMENTS: - type(ed_patch_type), target, intent(inout) :: cp_pnt + type(fates_patch_type), target, intent(inout) :: cp_pnt ! ! !LOCAL VARIABLES: - type(ed_patch_type) , pointer :: currentPatch - type(ed_cohort_type), pointer :: currentCohort + type(fates_patch_type) , pointer :: currentPatch + type(fates_cohort_type), pointer :: currentCohort real(r8) :: mind(N_DBH_BINS) ! Bottom of DBH bin real(r8) :: maxd(N_DBH_BINS) ! Top of DBH bin real(r8) :: delta_dbh ! Size of DBH bin @@ -3060,7 +2851,7 @@ subroutine patch_pft_size_profile(cp_pnt) currentPatch%pft_agb_profile(currentCohort%pft,j) = & currentPatch%pft_agb_profile(currentCohort%pft,j) + & - currentCohort%prt%GetState(struct_organ, all_carbon_elements) * & + currentCohort%prt%GetState(struct_organ, carbon12_element) * & currentCohort%n/currentPatch%area endif @@ -3086,7 +2877,7 @@ function countPatches( nsites, sites ) result ( totNumPatches ) type(ed_site_type) , intent(inout), target :: sites(nsites) ! ! !LOCAL VARIABLES: - type (ed_patch_type), pointer :: currentPatch + type (fates_patch_type), pointer :: currentPatch integer :: totNumPatches ! total number of patches. integer :: s !--------------------------------------------------------------------- @@ -3119,7 +2910,7 @@ subroutine get_frac_site_primary(site_in, frac_site_primary) real(r8) , intent(out) :: frac_site_primary ! !LOCAL VARIABLES: - type (ed_patch_type), pointer :: currentPatch + type (fates_patch_type), pointer :: currentPatch frac_site_primary = 0._r8 currentPatch => site_in%oldest_patch diff --git a/biogeochem/EDPhysiologyMod.F90 b/biogeochem/EDPhysiologyMod.F90 index 5d66f56d39..727aaa7370 100644 --- a/biogeochem/EDPhysiologyMod.F90 +++ b/biogeochem/EDPhysiologyMod.F90 @@ -13,20 +13,33 @@ module EDPhysiologyMod use FatesInterfaceTypesMod, only : hlm_day_of_year use FatesInterfaceTypesMod, only : numpft use FatesInterfaceTypesMod, only : nleafage + use FatesInterfaceTypesMod, only : nlevdamage use FatesInterfaceTypesMod, only : hlm_use_planthydro use FatesInterfaceTypesMod, only : hlm_parteh_mode use FatesInterfaceTypesMod, only : hlm_use_fixed_biogeog use FatesInterfaceTypesMod, only : hlm_use_nocomp use FatesInterfaceTypesMod, only : hlm_nitrogen_spec use FatesInterfaceTypesMod, only : hlm_phosphorus_spec + use FatesInterfaceTypesMod, only : hlm_use_tree_damage + use FatesInterfaceTypesMod, only : hlm_use_ed_prescribed_phys use FatesConstantsMod, only : r8 => fates_r8 use FatesConstantsMod, only : nearzero + use FatesConstantsMod, only : sec_per_day + use FatesConstantsMod, only : default_regeneration + 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 + use FatesConstantsMod, only : mpa_per_mm_suction + use FatesConstantsMod, only : g_per_kg + use FatesConstantsMod, only : ndays_per_year + use FatesConstantsMod, only : nocomp_bareground + use FatesConstantsMod, only : area_error_2 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 @@ -37,20 +50,29 @@ module EDPhysiologyMod use EDTypesMod , only : site_massbal_type use EDTypesMod , only : numlevsoil_max use EDTypesMod , only : numWaterMem - use EDTypesMod , only : dl_sf, dinc_vai, dlower_vai, area_inv + use FatesLitterMod , only : dl_sf + use EDParamsMod , only : dinc_vai, dlower_vai + use EDTypesMod , only : area_inv use EDTypesMod , only : AREA use FatesLitterMod , only : ncwd use FatesLitterMod , only : ndcmpy use FatesLitterMod , only : ilabile use FatesLitterMod , only : ilignin use FatesLitterMod , only : icellulose + use FatesLitterMod , only : adjust_SF_CWD_frac + use EDParamsMod , only : nclmax use EDTypesMod , only : AREA,AREA_INV - use EDTypesMod , only : nlevleaf + use FatesConstantsMod , only : leaves_shedding + use FatesConstantsMod , only : ihard_stress_decid + use FatesConstantsMod , only : isemi_stress_decid + use EDParamsMod , 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 EDParamsMod , only : maxpft + use EDTypesMod , only : ed_site_type + use FatesPatchMod, only : fates_patch_type + use FatesCohortMod, only : fates_cohort_type + use FatesConstantsMod , only : leaves_on + use FatesConstantsMod , only : leaves_off use EDTypesMod , only : min_n_safemath use PRTGenericMod , only : num_elements use PRTGenericMod , only : element_list @@ -63,6 +85,8 @@ module EDPhysiologyMod use EDTypesMod , only : phen_dstat_moistoff use EDTypesMod , only : phen_dstat_moiston use EDTypesMod , only : phen_dstat_timeon + use EDTypesMod , only : phen_dstat_pshed + use EDTypesMod , only : phen_dstat_pshed use EDTypesMod , only : init_recruit_trim use shr_log_mod , only : errMsg => shr_log_errMsg use FatesGlobals , only : fates_log @@ -71,9 +95,11 @@ module EDPhysiologyMod use EDParamsMod , only : q10_mr 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 + use FatesConstantsMod , only : area_error_3 use FatesConstantsMod , only : years_per_day use FatesAllometryMod , only : h_allom use FatesAllometryMod , only : h2d_allom @@ -92,7 +118,6 @@ module EDPhysiologyMod 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 @@ -103,11 +128,19 @@ module EDPhysiologyMod 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 - + use PRTLossFluxesMod, only : PRTPhenologyFlush + use PRTLossFluxesMod, only : PRTDeciduousTurnover + use PRTLossFluxesMod, only : PRTReproRelease + use PRTLossFluxesMod, only : PRTDamageLosses + use PRTGenericMod, only : StorageNutrientTarget + use DamageMainMod, only : damage_time + use DamageMainMod, only : GetCrownReduction + use DamageMainMod, only : GetDamageFrac + use SFParamsMod, only : SF_val_CWD_frac + use FatesParameterDerivedMod, only : param_derived + use FatesPlantHydraulicsMod, only : InitHydrCohort + use PRTInitParamsFatesMod, only : NewRecruitTotalStoichiometry + implicit none private @@ -115,21 +148,53 @@ module EDPhysiologyMod public :: phenology public :: satellite_phenology public :: assign_cohort_SP_properties + public :: calculate_SP_properties public :: recruitment public :: ZeroLitterFluxes public :: ZeroAllocationRates public :: PreDisturbanceLitterFluxes public :: PreDisturbanceIntegrateLitter - public :: SeedIn - + public :: GenerateDamageAndLitterFluxes + public :: SeedUpdate + public :: UpdateRecruitL2FR + public :: UpdateRecruitStoicH + public :: SetRecruitL2FR + logical, parameter :: debug = .false. ! local debug flag character(len=*), parameter, private :: sourcefile = & __FILE__ + integer :: istat ! return status code + character(len=255) :: smsg ! Message string for deallocation errors + integer, parameter :: dleafon_drycheck = 100 ! Drought deciduous leaves max days on check parameter - + real(r8), parameter :: decid_leaf_long_max = 1.0_r8 ! Maximum leaf lifespan for + ! deciduous PFTs [years] + + 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. + + integer, parameter :: dd_offon_toler = 30 ! When flushing or shedding leaves, we check that + ! the dates are near last year's dates. This controls + ! the tolerance for deviating from last year. + + real(r8), parameter :: elongf_min = 0.05_r8 ! Minimum elongation factor. If elongation factor + ! reaches or falls below elongf_min, we assume + ! complete abscission. This avoids carrying out + ! a residual amount of leaves, which may create + ! computational problems. The current threshold + ! is the same used in ED-2.2. + + real(r8), parameter :: smp_lwr_bound = -1000000._r8 ! Imposed soil matric potential lower bound for + ! frozen or excessively dry soils, used when + ! computing water stress. ! ============================================================================ contains @@ -144,7 +209,7 @@ subroutine ZeroLitterFluxes( currentSite ) ! !ARGUMENTS type(ed_site_type), intent(inout), target :: currentSite - type(ed_patch_type), pointer :: currentPatch + type(fates_patch_type), pointer :: currentPatch integer :: el @@ -166,8 +231,8 @@ subroutine ZeroAllocationRates( currentSite ) ! !ARGUMENTS type(ed_site_type), intent(inout), target :: currentSite - type(ed_patch_type), pointer :: currentPatch - type(ed_cohort_type), pointer :: currentCohort + type(fates_patch_type), pointer :: currentPatch + type(fates_cohort_type), pointer :: currentCohort currentPatch => currentSite%youngest_patch do while(associated(currentPatch)) @@ -186,6 +251,177 @@ subroutine ZeroAllocationRates( currentSite ) return end subroutine ZeroAllocationRates + ! ============================================================================ + + subroutine GenerateDamageAndLitterFluxes( csite, cpatch, bc_in ) + + ! Arguments + type(ed_site_type) :: csite + type(fates_patch_type) :: cpatch + type(bc_in_type), intent(in) :: bc_in + + + ! Locals + type(fates_cohort_type), pointer :: ccohort ! Current cohort + type(fates_cohort_type), pointer :: ndcohort ! New damage-class cohort + type(litter_type), pointer :: litt ! Points to the litter object + type(site_fluxdiags_type), pointer :: flux_diags ! pointer to site level flux diagnostics object + integer :: cd ! Damage class index + integer :: el ! Element index + integer :: dcmpy ! Decomposition pool index + integer :: c ! CWD pool index + real(r8) :: cd_frac ! Fraction of trees damaged in this class transition + real(r8) :: num_trees_cd ! Number of trees to spawn into the new damage class cohort + real(r8) :: crown_loss_frac ! Fraction of crown lost from one damage class to next + real(r8) :: branch_loss_frac ! Fraction of sap, structure and storage lost in branch + ! fall during damage + real(r8) :: leaf_loss ! Mass lost to each organ during damage [kg] + real(r8) :: repro_loss ! "" [kg] + real(r8) :: sapw_loss ! "" [kg] + real(r8) :: store_loss ! "" [kg] + real(r8) :: struct_loss ! "" [kg] + real(r8) :: dcmpy_frac ! fraction of mass going to each decomposition pool + real(r8) :: SF_val_CWD_frac_adj(4) !SF_val_CWD_frac adjusted based on cohort dbh + + if(hlm_use_tree_damage .ne. itrue) return + + if(.not.damage_time) return + + ccohort => cpatch%tallest + do while (associated(ccohort)) + + ! Ignore damage to new plants and non-woody plants + if(prt_params%woody(ccohort%pft)==ifalse ) cycle + if(ccohort%isnew ) cycle + + associate( ipft => ccohort%pft, & + agb_frac => prt_params%allom_agb_frac(ccohort%pft), & + branch_frac => param_derived%branch_frac(ccohort%pft)) + + do_dclass: do cd = ccohort%crowndamage+1, nlevdamage + + call GetDamageFrac(ccohort%crowndamage, cd, ipft, cd_frac) + + ! now to get the number of damaged trees we multiply by damage frac + num_trees_cd = ccohort%n * cd_frac + + ! if non negligable lets create a new cohort and generate some litter + if_numtrees: if (num_trees_cd > nearzero ) then + + ! Create a new damaged cohort + allocate(ndcohort) ! new cohort surviving but damaged + if(hlm_use_planthydro.eq.itrue) call InitHydrCohort(csite,ndcohort) + + ! Initialize the PARTEH object and point to the + ! correct boundary condition fields + ndcohort%prt => null() + + call InitPRTObject(ndcohort%prt) + call ndcohort%InitPRTBoundaryConditions() + call ndcohort%ZeroValues() + + ! nc_canopy_d is the new cohort that gets damaged + call ccohort%Copy(ndcohort) + + ! new number densities - we just do damaged cohort here - + ! undamaged at the end of the cohort loop once we know how many damaged to + ! subtract + + ndcohort%n = num_trees_cd + ndcohort%crowndamage = cd + + ! Remove these trees from the donor cohort + ccohort%n = ccohort%n - num_trees_cd + + ! update crown area here - for cohort fusion and canopy organisation below + call carea_allom(ndcohort%dbh, ndcohort%n, csite%spread, & + ipft, ndcohort%crowndamage, ndcohort%c_area) + + call GetCrownReduction(cd-ccohort%crowndamage, crown_loss_frac) + + do_element: do el = 1, num_elements + + litt => cpatch%litter(el) + flux_diags => csite%flux_diags(el) + + ! Reduce the mass of the newly damaged cohort + ! Fine-roots are not damaged as of yet + ! only above-ground sapwood,structure and storage in + ! branches is damaged/removed + branch_loss_frac = crown_loss_frac * branch_frac * agb_frac + + leaf_loss = ndcohort%prt%GetState(leaf_organ,element_list(el))*crown_loss_frac + repro_loss = ndcohort%prt%GetState(repro_organ,element_list(el))*crown_loss_frac + sapw_loss = ndcohort%prt%GetState(sapw_organ,element_list(el))*branch_loss_frac + store_loss = ndcohort%prt%GetState(store_organ,element_list(el))*branch_loss_frac + struct_loss = ndcohort%prt%GetState(struct_organ,element_list(el))*branch_loss_frac + + ! ------------------------------------------------------ + ! Transfer the biomass from the cohort's + ! damage to the litter input fluxes + ! ------------------------------------------------------ + + do dcmpy=1,ndcmpy + dcmpy_frac = GetDecompyFrac(ipft,leaf_organ,dcmpy) + litt%leaf_fines_in(dcmpy) = litt%leaf_fines_in(dcmpy) + & + (store_loss+leaf_loss+repro_loss) * & + ndcohort%n * dcmpy_frac / cpatch%area + end do + + flux_diags%leaf_litter_input(ipft) = & + flux_diags%leaf_litter_input(ipft) + & + (store_loss+leaf_loss+repro_loss) * ndcohort%n + + call adjust_SF_CWD_frac(ndcohort%dbh,ncwd,SF_val_CWD_frac,SF_val_CWD_frac_adj) + + do c = 1,ncwd + litt%ag_cwd_in(c) = litt%ag_cwd_in(c) + & + (sapw_loss + struct_loss) * & + SF_val_CWD_frac_adj(c) * ndcohort%n / & + cpatch%area + + flux_diags%cwd_ag_input(c) = flux_diags%cwd_ag_input(c) + & + (struct_loss + sapw_loss) * & + SF_val_CWD_frac_adj(c) * ndcohort%n + end do + + end do do_element + + ! Applying the damage to the cohort, does not need to happen + ! in the element loop, it will loop inside that call + call PRTDamageLosses(ndcohort%prt, leaf_organ, crown_loss_frac) + call PRTDamageLosses(ndcohort%prt, repro_organ, crown_loss_frac) + call PRTDamageLosses(ndcohort%prt, sapw_organ, branch_loss_frac) + call PRTDamageLosses(ndcohort%prt, store_organ, branch_loss_frac) + call PRTDamageLosses(ndcohort%prt, struct_organ, branch_loss_frac) + + + !----------- Insert new cohort into the linked list + ! This list is going tall to short, lets add this new + ! cohort into a taller position so we don't hit it again + ! as the loop traverses + ! --------------------------------------------------------------! + + ndcohort%shorter => ccohort + if(associated(ccohort%taller))then + ndcohort%taller => ccohort%taller + ccohort%taller%shorter => ndcohort + else + cpatch%tallest => ndcohort + ndcohort%taller => null() + endif + ccohort%taller => ndcohort + + end if if_numtrees + + end do do_dclass + + end associate + ccohort => ccohort%shorter + enddo + + return + end subroutine GenerateDamageAndLitterFluxes ! ============================================================================ @@ -210,7 +446,7 @@ subroutine PreDisturbanceLitterFluxes( currentSite, currentPatch, bc_in ) ! !ARGUMENTS type(ed_site_type), intent(inout) :: currentSite - type(ed_patch_type), intent(inout) :: currentPatch + type(fates_patch_type), intent(inout) :: currentPatch type(bc_in_type), intent(in) :: bc_in ! @@ -231,12 +467,13 @@ 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 ! (for drought deciduous) or too cold (for cold deciduous) - call SeedGermination(litt, currentSite%cstatus, currentSite%dstatus) + call SeedGermination(litt, currentSite%cstatus, currentSite%dstatus(1:numpft), bc_in, currentPatch) ! Send fluxes from newly created litter into the litter pools ! This litter flux is from non-disturbance inducing mortality, as well @@ -268,7 +505,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, @@ -287,7 +523,7 @@ subroutine PreDisturbanceIntegrateLitter(currentPatch) ! ----------------------------------------------------------------------------------- ! Arguments - type(ed_patch_type),intent(inout),target :: currentPatch + type(fates_patch_type),intent(inout),target :: currentPatch ! Locals @@ -319,7 +555,6 @@ subroutine PreDisturbanceIntegrateLitter(currentPatch) litt%seed_germ_in(pft) - & litt%seed_germ_decay(pft) - enddo ! Update the Coarse Woody Debris pools (above and below) @@ -370,8 +605,8 @@ subroutine trim_canopy( currentSite ) type (ed_site_type),intent(inout), target :: currentSite ! ! !LOCAL VARIABLES: - type (ed_cohort_type) , pointer :: currentCohort - type (ed_patch_type) , pointer :: currentPatch + type (fates_cohort_type) , pointer :: currentCohort + type (fates_patch_type) , pointer :: currentPatch integer :: z ! leaf layer integer :: ipft ! pft index @@ -425,9 +660,10 @@ subroutine trim_canopy( currentSite ) 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 + real(r8) :: target_c_area + + real(r8) :: pft_leaf_lifespan ! Leaf lifespan of each PFT [years] !---------------------------------------------------------------------- ipatch = 1 ! Start counting patches @@ -446,31 +682,35 @@ subroutine trim_canopy( currentSite ) currentCohort => currentPatch%tallest do while (associated(currentCohort)) - ! Save off the incoming trim and laimemory + ! Save off the incoming trim initial_trim = currentCohort%canopy_trim - initial_laimem = currentCohort%laimemory - ! Add debug diagnstic output to determine which cohort + + ! Add debug diagnostic 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) + call carea_allom(currentCohort%dbh,currentCohort%n,currentSite%spread,currentCohort%pft,& + currentCohort%crowndamage, currentCohort%c_area) - leaf_c = currentCohort%prt%GetState(leaf_organ, all_carbon_elements) + leaf_c = currentCohort%prt%GetState(leaf_organ, carbon12_element) 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, & + ! We don't need to check on sp mode here since we don't trim_canopy with sp mode + currentCohort%treesai = tree_sai(currentCohort%pft, & + currentCohort%dbh, currentCohort%crowndamage, & + currentCohort%canopy_trim, & + currentCohort%efstem_coh, & + currentCohort%c_area, currentCohort%n,currentCohort%canopy_layer,& currentPatch%canopy_layer_tlai, currentCohort%treelai, & - currentCohort%vcmax25top,0 ) + currentCohort%vcmax25top,0 ) currentCohort%nv = count((currentCohort%treelai+currentCohort%treesai) .gt. dlower_vai(:)) + 1 @@ -481,11 +721,15 @@ subroutine trim_canopy( currentSite ) call endrun(msg=errMsg(sourcefile, __LINE__)) endif - call bleaf(currentcohort%dbh,ipft,currentcohort%canopy_trim,tar_bl) + ! Find target leaf biomass. Here we assume that leaves would be fully flushed + ! (elongation factor = 1) + call bleaf(currentcohort%dbh,ipft,& + currentCohort%crowndamage, currentcohort%canopy_trim,1.0_r8, 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) + call bfineroot(currentcohort%dbh,ipft,currentcohort%canopy_trim, & + currentcohort%l2fr,1.0_r8, tar_bfr) bfr_per_bleaf = tar_bfr/tar_bl endif @@ -499,7 +743,7 @@ subroutine trim_canopy( currentSite ) nnu_clai_a(:,:) = 0._r8 nnu_clai_b(:,:) = 0._r8 - !Leaf cost vs netuptake for each leaf layer. + !Leaf cost vs net uptake for each leaf layer. do z = 1, currentCohort%nv ! Calculate the cumulative total vegetation area index (no snow occlusion, stems and leaves) @@ -525,47 +769,39 @@ subroutine trim_canopy( currentSite ) ! 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 + sla_levleaf = min(sla_max,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) + ! Find the realised leaf lifespan, depending on the leaf phenology. + if (prt_params%season_decid(ipft) == itrue) then + ! Cold-deciduous costs. Assume time-span to be 1 year to be consistent + ! with FATES default + pft_leaf_lifespan = decid_leaf_long_max - 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 + elseif (any(prt_params%stress_decid(ipft) == [ihard_stress_decid,isemi_stress_decid]) )then + ! Drought-decidous costs. Assume time-span to be the least between + ! 1 year and the life span provided by the parameter file. + pft_leaf_lifespan = & + min(decid_leaf_long_max,sum(prt_params%leaf_long(ipft,:))) - currentCohort%leaf_cost = currentCohort%leaf_cost * & - (prt_params%grperc(ipft) + 1._r8) else !evergreen costs + pft_leaf_lifespan = sum(prt_params%leaf_long(ipft,:)) + end if - ! 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 + ! Leaf cost at leaf level z (kgC m-2 year-1) accounting for sla profile + ! (Convert from SLA in m2g-1 to m2kg-1) + currentCohort%leaf_cost = & + 1.0_r8/(sla_levleaf*pft_leaf_lifespan*g_per_kg) - 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 + if ( int(prt_params%allom_fmode(ipft)) == 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*g_per_kg) * & + bfr_per_bleaf / prt_params%root_long(ipft) + end if + currentCohort%leaf_cost = currentCohort%leaf_cost * & + (prt_params%grperc(ipft) + 1._r8) ! 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 @@ -591,23 +827,14 @@ subroutine trim_canopy( currentSite ) ! 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 + if (currentCohort%height > 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 ! height check endif ! trim limit check endif ! net uptake check endif ! leaf activity check @@ -621,10 +848,6 @@ subroutine trim_canopy( currentSite ) 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] @@ -649,17 +872,11 @@ subroutine trim_canopy( currentSite ) ! 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 @@ -696,11 +913,12 @@ subroutine phenology( currentSite, bc_in ) ! ! !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 - - + use EDParamsMod, only : ED_val_phen_a, ED_val_phen_b, ED_val_phen_c + use EDParamsMod, only : ED_val_phen_chiltemp + use EDParamsMod, only : ED_val_phen_mindayson + use EDParamsMod, only : ED_val_phen_ncolddayslim + use EDParamsMod, only : ED_val_phen_coldtemp + use EDBtranMod, only : check_layer_water ! ! !ARGUMENTS: type(ed_site_type), intent(inout), target :: currentSite @@ -709,48 +927,71 @@ subroutine phenology( currentSite, bc_in ) ! ! !LOCAL VARIABLES: - type(ed_patch_type),pointer :: cpatch + type(fates_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 + integer :: ipft ! plant functional type index + integer :: j ! Soil layer index + real(r8) :: mean_10day_liqvol ! mean soil liquid volume over last 10 days [m3/m3] + real(r8) :: mean_10day_smp ! mean soil matric potential over last 10 days [mm] 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. + real(r8) :: rootfrac_notop ! Total rooting fraction excluding the top soil layer 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. + integer :: nlevroot ! Number of rooting levels to consider + real(r8) :: temp_in_C ! daily averaged temperature in celsius + real(r8) :: elongf_prev ! Elongation factor from previous time + real(r8) :: elongf_1st ! First guess for elongation factor + integer :: ndays_pft_leaf_lifespan ! PFT life span of drought deciduous [days]. + ! This is the shortest between the PFT leaf + ! lifespan and the maximum lifespan of drought + ! deciduous (see parameter decid_leaf_long_max + ! at the beginning of this file). + real(r8) :: phen_drought_threshold ! For drought hard-deciduous, this is the threshold + ! below which plants will abscise leaves, and + ! above which plants will flush leaves. For semi- + ! deciduous plants, this is the threshold below + ! which abscission will be complete. This depends + ! on the sign. If positive, these are soil + ! volumetric water content [m3/m3]. If negative, + ! the values are soil matric potential [mm]. Not + ! used for non-deciduous plants. Ignored for + ! non-deciduous plants. + real(r8) :: phen_moist_threshold ! For semi-deciduous, this is the threshold above + ! which flushing will be complete. This depends + ! on the sign. If positive, these are soil + ! volumetric water content [m3/m3]. If negative, + ! the values are soil matric potential [mm]. + ! Ignored for hard-deciduous and evergreen + ! plants. + real(r8) :: phen_doff_time ! Minimum number of days that plants must remain + ! leafless before flushing leaves again. + + ! Logical tests to make code more readable + logical :: smoist_below_threshold ! Is soil moisture below threshold? + logical :: recent_flush ! Last full flushing event is still very recent. + logical :: recent_abscission ! Last abscission event is still very recent. + logical :: exceed_min_on_period ! Have leaves been flushed for a minimum period of time? + logical :: exceed_min_off_period ! Have leaves been off for a minimum period of time? + logical :: prolonged_on_period ! Has leaves been flushed for too long? + logical :: prolonged_off_period ! Have leaves been abscissed for too long? + logical :: last_flush_long_ago ! Has it been a very long time since last flushing? - 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) + ! Advance it. (this should be a global, no reason + ! for site level, but we don't have global scalars in the + ! restart file) + currentSite%phen_model_date = currentSite%phen_model_date + 1 + model_day_int = currentSite%phen_model_date ! Parameter of drought decid leaf loss in mm in top layer...FIX(RF,032414) @@ -822,7 +1063,7 @@ subroutine phenology( currentSite, bc_in ) !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(model_day_int> ndays_per_year)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. @@ -845,15 +1086,15 @@ subroutine phenology( currentSite, bc_in ) ! 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) + currentSite%cndaysleafoff = model_day_int - (currentSite%cleafoffdate - ndays_per_year) else - dayssincecleafoff = model_day_int - currentSite%cleafoffdate + currentSite%cndaysleafoff = model_day_int - currentSite%cleafoffdate end if if (model_day_int < currentSite%cleafondate) then - dayssincecleafon = model_day_int - (currentSite%cleafondate-365) + currentSite%cndaysleafon = model_day_int - (currentSite%cleafondate - ndays_per_year) else - dayssincecleafon = model_day_int - currentSite%cleafondate + currentSite%cndaysleafon = model_day_int - currentSite%cleafondate end if @@ -866,14 +1107,13 @@ subroutine phenology( currentSite, bc_in ) ! 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. & + if ( any(currentSite%cstatus == [phen_cstat_iscold,phen_cstat_nevercold]) .and. & (currentSite%grow_deg_days > gdd_threshold) .and. & - (dayssincecleafoff > ED_val_phen_mindayson) .and. & + (currentSite%cndaysleafoff > 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%cndaysleafon = 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 @@ -892,7 +1132,7 @@ subroutine phenology( currentSite, bc_in ) 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%cndaysleafon > ED_val_phen_mindayson) )then currentSite%grow_deg_days = 0._r8 ! The equations for Botta et al ! are for calculations of @@ -901,6 +1141,7 @@ subroutine phenology( currentSite, bc_in ) ! 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 + currentSite%cndaysleafoff = 0 if ( debug ) write(fates_log(),*) 'leaves off' endif @@ -910,159 +1151,377 @@ subroutine phenology( currentSite, bc_in ) ! 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%cndaysleafoff > 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 + currentSite%cndaysleafoff = 0 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... + ! Loop through every PFT to assign the elongation factor. + ! Add PFT look to account for different PFT rooting depth profiles. + pft_elong_loop: do ipft=1,numpft - ! 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 + ! Copy values to a local variable to make code more legible. + phen_drought_threshold = prt_params%phen_drought_threshold(ipft) + phen_moist_threshold = prt_params%phen_moist_threshold (ipft) + phen_doff_time = prt_params%phen_doff_time (ipft) - 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 + ! Update soil moisture information memory (we always track the last 10 days) + do i_wmem = numWaterMem,2,-1 !shift memory to previous day, to make room for current day + currentSite%liqvol_memory(i_wmem,ipft) = currentSite%liqvol_memory(i_wmem-1,ipft) + currentSite%smp_memory (i_wmem,ipft) = currentSite%smp_memory (i_wmem-1,ipft) + end do - ! LEAF ON: DROUGHT DECIDUOUS TIME EXCEEDANCE - ! If we still haven't done budburst by end of window, then force it + ! Find the rooting depth distribution for PFT + call set_root_fraction( currentSite%rootfrac_scr, ipft, currentSite%zi_soil, & + bc_in%max_rooting_depth_index_col ) + nlevroot = max(2,min(ubound(currentSite%zi_soil,1),bc_in%max_rooting_depth_index_col)) + + ! The top most layer is typically very thin (~ 2cm) and dries rather quickly. Despite + ! being thin, it can have a non-negligible rooting fraction (e.g., using + ! exponential_2p_root_profile with default parameters make the top layer to contain + ! about 7% of the total fine root density). To avoid overestimating dryness, we + ! ignore the top layer when calculating the memory. + rootfrac_notop = sum(currentSite%rootfrac_scr(2:nlevroot)) + if ( rootfrac_notop <= nearzero ) then + ! Unlikely, but just in case all roots are in the first layer, we use the second + ! layer the second layer (to avoid FPE issues). + currentSite%rootfrac_scr(2) = 1.0_r8 + rootfrac_notop = 1.0_r8 + end if - ! 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 + ! Set the memory to be the weighted average of the soil properties, using the + ! root fraction of each layer (except the topmost one) as the weighting factor. + + currentSite%liqvol_memory(1,ipft) = sum( bc_in%h2o_liqvol_sl (2:nlevroot) * & + currentSite%rootfrac_scr(2:nlevroot) ) / & + rootfrac_notop + currentSite%smp_memory (1,ipft) = 0._r8 + do j = 2,nlevroot + if(check_layer_water(bc_in%h2o_liqvol_sl(j),bc_in%tempk_sl(j)) ) then + currentSite%smp_memory (1,ipft) = currentSite%smp_memory (1,ipft) + & + bc_in%smp_sl (j) * & + currentSite%rootfrac_scr(j) / & + rootfrac_notop + else + ! Nominal extreme suction for frozen or unreasonably dry soil + currentSite%smp_memory (1,ipft) = currentSite%smp_memory (1,ipft) + & + smp_lwr_bound * & + currentSite%rootfrac_scr(j) / & + rootfrac_notop + end if + end do - 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 + ! Calculate the mean soil moisture ( liquid volume (m3/m3) and matric potential (mm)) + ! over the last 10 days + mean_10day_liqvol = sum(currentSite%liqvol_memory(1:numWaterMem,ipft)) / & + real(numWaterMem,r8) + mean_10day_smp = sum(currentSite%smp_memory (1:numWaterMem,ipft)) / & + real(numWaterMem,r8) + + ! Compare the moisture with the threshold. + if ( phen_drought_threshold >= 0. ) then + ! Liquid volume in reference layer (m3/m3) + smoist_below_threshold = mean_10day_liqvol < phen_drought_threshold + else + ! Soil matric potential in reference layer (mm) + smoist_below_threshold = mean_10day_smp < phen_drought_threshold 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 + ! Calculate days since last flushing and shedding event, but make a provision + ! for the first year of simulation, we have to assume leaf drop / leaf flush + ! dates to start, so if that is in the future, set it to last year + if (model_day_int < currentSite%dleafoffdate(ipft)) then + currentSite%dndaysleafoff(ipft) = model_day_int - (currentSite%dleafoffdate(ipft)-ndays_per_year) + else + currentSite%dndaysleafoff(ipft) = model_day_int - currentSite%dleafoffdate(ipft) + end if + if (model_day_int < currentSite%dleafondate(ipft)) then + currentSite%dndaysleafon(ipft) = model_day_int - (currentSite%dleafondate(ipft)-ndays_per_year) + else + currentSite%dndaysleafon(ipft) = model_day_int - currentSite%dleafondate(ipft) 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... + ! Elongation factor from the previous step. + elongf_prev = currentSite%elong_factor(ipft) + + + ! PFT leaf lifespan in days. This is the shortest between the leaf longevity + ! (defined as a PFT parameter) and the maximum canopy leaf life span allowed + ! for drought deciduous (local parameter). The sum term accounts for the + ! total leaf life span of this cohort. + ndays_pft_leaf_lifespan = & + nint(ndays_per_year*min(decid_leaf_long_max,sum(prt_params%leaf_long(ipft,:)))) + + + !---~--- + ! Find elongation factors by comparing the moisture with the thresholds. For each + ! tissue --- leaves, fine roots, and stems (sapwood+heartwood) --- elongation factor + ! is the maximum fraction of biomass (relative to maximum biomass given allometry) + ! that can be allocated to each tissue due to phenology. In this select case, we + ! define the elongation factor based on the PFT-specific phenology strategy of this + ! each PFT. Options are evergreen, "hard deciduous", or semi-deciduous: + ! - Evergreen: elongation factors shall be 1 at all times (fully flushed tissues). + ! - "Hard-deciduous": elongation factors are either 0 (fully abscised tissues) or + ! 1 (fully flushed tissues) + ! - Semi-deciduous: elongation factors can be any value between 0 and 1 (including + ! 0 and 1). For example, if elongation factor for leaves of a cohort is 0.4, then + ! the leaf biomass will be capped at 40% of the biomass the cohort would have if + ! it were in well-watered conditions. + !---~--- + case_drought_phen: select case (prt_params%stress_decid(ipft)) + case (ihard_stress_decid) + !---~--- + ! Default ("hard") drought deciduous phenology. The decision on whether to + ! abscise (shed) or flush leaves is in principle defined by the soil moisture + ! in the rooting zone. However, we must also account the time since last + ! abscission or flushing event, to avoid excessive "flickering" of the leaf + ! elongation factor if soil moisture is right at the threshold. + ! + ! (MLO thought: maybe we should define moisture equivalents of GDD and chilling + ! days to simplify the cases a bit...) + !---~--- + + + !---~--- + ! Save some conditions in logical variables to simplify code below + !---~--- + ! Leaves have been "on" for longer than the minimum number of days. + exceed_min_on_period = & + any( currentSite%dstatus(ipft) == [phen_dstat_timeon,phen_dstat_moiston] ) .and. & + (currentSite%dndaysleafon(ipft) > dleafon_drycheck) + ! Leaves have been "off" for longer than the minimum number of days. + exceed_min_off_period = & + ( currentSite%dstatus(ipft) == phen_dstat_timeoff ) .and. & + ( currentSite%dndaysleafoff(ipft) > min_daysoff_dforcedflush ) + ! Leaves have been "on" for longer than the leaf lifetime. + prolonged_on_period = & + any( currentSite%dstatus(ipft) == [phen_dstat_timeon,phen_dstat_moiston] ) .and. & + ( currentSite%dndaysleafon(ipft) > ndays_pft_leaf_lifespan ) + ! Leaves have been "off" for a sufficiently long time and the last flushing + ! was about one year ago (+/- tolerance). + prolonged_off_period = & + any( currentSite%dstatus(ipft) == [phen_dstat_timeoff,phen_dstat_moistoff] ) .and. & + ( currentSite%dndaysleafoff(ipft) > phen_doff_time ) .and. & + ( currentSite%dndaysleafon(ipft) >= ndays_per_year-dd_offon_toler ) .and. & + ( currentSite%dndaysleafon(ipft) <= ndays_per_year+dd_offon_toler ) + ! Last flushing was a very long time ago. + last_flush_long_ago = & + ( currentSite%dstatus(ipft) == phen_dstat_moistoff ) .and. & + ( currentSite%dndaysleafon(ipft) > ndays_per_year+dd_offon_toler ) + !---~--- + + + !---~--- + ! Revision of the conditions, added an if/elseif/else structure to ensure only + ! up to one change occurs at any given time. Also, prevent changes until the + ! soil moisture memory is populated (the outer if check). + !---~--- + past_spinup_ifelse: if (model_day_int > numWaterMem) then + drought_smoist_ifelse: if ( prolonged_off_period .and. & + ( .not. smoist_below_threshold ) ) then + ! 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 + ! The following conditions must be met + ! 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 soil moisture sufficiently high? + currentSite%dstatus(ipft) = phen_dstat_moiston ! set status to leaf-on + currentSite%dleafondate(ipft) = model_day_int ! save the model day we start flushing + currentSite%dndaysleafon(ipft) = 0 + currentSite%elong_factor(ipft) = 1. + + elseif ( last_flush_long_ago ) then + ! 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 + currentSite%dstatus(ipft) = phen_dstat_timeon ! force budburst! + currentSite%dleafondate(ipft) = model_day_int ! record leaf on date + currentSite%dndaysleafon(ipft) = 0 + currentSite%elong_factor(ipft) = 1. + + elseif ( exceed_min_off_period ) then + ! LEAF ON: DROUGHT DECIDUOUS EXCEEDED MINIMUM OFF PERIOD + ! Leaves were off due to time, not really moisture, so we allow them to + ! flush again as soon as they exceed a minimum off time + ! This typically occurs in a perennially wet system. + currentSite%dstatus(ipft) = phen_dstat_timeon ! force budburst! + currentSite%dleafondate(ipft) = model_day_int ! record leaf on date + currentSite%dndaysleafon(ipft) = 0 + currentSite%elong_factor(ipft) = 1. + + elseif ( prolonged_on_period ) then + ! LEAF OFF: DROUGHT DECIDUOUS LIFESPAN + ! Are the leaves rouhgly at the end of their lives? If so, shed leaves + ! even if it is not dry. + currentSite%dstatus(ipft) = phen_dstat_timeoff !alter status of site to 'leaves off' + currentSite%dleafoffdate(ipft) = model_day_int !record leaf on date + currentSite%dndaysleafoff(ipft) = 0 + currentSite%elong_factor(ipft) = 0. + + elseif ( exceed_min_on_period .and. smoist_below_threshold ) then + ! LEAF OFF: DROUGHT DECIDUOUS DRYNESS - if the soil gets too dry, + ! and the leaves have already been on a while... + currentSite%dstatus(ipft) = phen_dstat_moistoff ! alter status of site to 'leaves off' + currentSite%dleafoffdate(ipft) = model_day_int ! record leaf on date + currentSite%dndaysleafoff(ipft) = 0 + currentSite%elong_factor(ipft) = 0. + end if drought_smoist_ifelse + end if past_spinup_ifelse + !---~--- + + + case (isemi_stress_decid) + !---~--- + ! Semi-deciduous PFT, based on ED2. We compare the moisture with the lower + ! and upper thresholds. If the moisture is in between the thresholds, we must + ! also check whether or not the drought is developing or regressing. + !---~--- + + + !---~--- + ! First guess elongation factor, solely based on rooting-zone moisture. + ! These values may be adjusted based on the time since last flushing and/or + ! abscising event. + !---~--- + if (phen_drought_threshold >= 0.) then + elongf_1st = elongf_min + (1.0_r8 - elongf_min ) * & + ( mean_10day_liqvol - phen_drought_threshold ) / & + ( phen_moist_threshold - phen_drought_threshold ) + else + elongf_1st = elongf_min + (1.0_r8 - elongf_min ) * & + ( mean_10day_smp - phen_drought_threshold ) / & + ( phen_moist_threshold - phen_drought_threshold ) + end if + elongf_1st = max(0.0_r8,min(1.0_r8,elongf_1st)) + !---~--- + + + + !---~--- + ! Save some conditions in logical variables to simplify code below + !---~--- + ! Leaves have been flushing for a short period of time. + recent_flush = elongf_prev >= elongf_min .and. & + ( currentSite%dndaysleafon(ipft) <= dleafon_drycheck ) + ! Leaves have been abscissing for a short period of time. + recent_abscission = elongf_prev < elongf_min .and. & + ( currentSite%dndaysleafoff(ipft) <= min_daysoff_dforcedflush ) + ! Leaves have been flushing for longer than their time span. + prolonged_on_period = all( [elongf_prev,elongf_1st] >= elongf_min ) .and. & + ( currentSite%dndaysleafon(ipft) > ndays_pft_leaf_lifespan ) + ! It's been a long time since the plants had flushed their leaves. + last_flush_long_ago = all( [elongf_prev,elongf_1st] < elongf_min ) .and. & + ( currentSite%dndaysleafon(ipft) > ndays_per_year+dd_offon_toler ) + !---~--- + + + ! Make sure elongation factor is bounded and check for special cases. + drought_gradual_ifelse: if ( model_day_int <= numWaterMem ) then + ! Too early in the simulation, keep the same elongation factor as the day before. + currentSite%elong_factor(ipft) = elongf_prev + + elseif ( prolonged_on_period ) then + ! Leaves have been on for too long and exceeded leaf lifespan. Force abscission + currentSite%elong_factor(ipft) = 0.0_r8 ! Force full budburst + currentSite%dstatus(ipft) = phen_dstat_timeoff ! Flag that this has been forced + currentSite%dleafoffdate(ipft) = model_day_int ! Record leaf off date + currentSite%dndaysleafoff(ipft) = 0 ! Reset clock + + elseif ( last_flush_long_ago ) then + ! Plant has not flushed at all for a very long time. Force flushing + currentSite%elong_factor(ipft) = elongf_min ! Force minimum budburst + currentSite%dstatus(ipft) = phen_dstat_timeon ! Flag that this has been forced + currentSite%dleafondate(ipft) = model_day_int ! Record leaf on date + currentSite%dndaysleafon(ipft) = 0 ! Reset clock + + elseif ( recent_flush .and. elongf_1st < elongf_prev ) then + ! Leaves have only recently reached flushed status. Elongation factor cannot decrease + currentSite%elong_factor(ipft) = elongf_prev ! Elongation factor cannot decrease + currentSite%dstatus(ipft) = phen_dstat_timeon ! Flag that this has been forced + + elseif ( recent_abscission .and. elongf_1st > elongf_min ) then + ! Leaves have only recently abscissed. Prevent plant to flush leaves. + currentSite%elong_factor(ipft) = 0.0_r8 ! Elongation factor must remain 0. + currentSite%dstatus(ipft) = phen_dstat_timeoff ! Flag that this has been forced + + elseif ( elongf_1st < elongf_min ) then + ! First guess of elongation factor below minimum. Impose full abscission. + currentSite%elong_factor(ipft) = 0.0_r8 + + if (elongf_prev >= elongf_min ) then + ! This is the first day moisture fell below minimum. Flag change of status. + currentSite%dstatus(ipft) = phen_dstat_moistoff ! Flag that this has not been forced + currentSite%dleafoffdate(ipft) = model_day_int ! Record leaf off date + currentSite%dndaysleafoff(ipft) = 0 ! Reset clock + end if - 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 + else + ! First guess of elongation factor is valid, use it. + currentSite%elong_factor(ipft) = elongf_1st + + + if (elongf_prev < elongf_min ) then + ! This is the first day moisture allows leaves to exist. Flag change of status. + currentSite%dstatus(ipft) = phen_dstat_moiston ! Flag that this has not been forced + currentSite%dleafondate(ipft) = model_day_int ! Record leaf on date + currentSite%dndaysleafon(ipft) = 0 ! Reset clock + elseif (elongf_1st < elongf_prev) then + currentSite%dstatus(ipft) = phen_dstat_pshed ! Flag partial shedding, + ! but do not reset the clock + end if + end if drought_gradual_ifelse + + + case default + ! Neither hard deciduous or semi-deciduous. For now we treat this as synonym + ! of non-drought deciduous. In the future we may consider other drought deciduous + ! strategies (e.g., abscission driven by moisture, flushing driven by photo- + ! period). + currentSite%dstatus(ipft) = phen_dstat_moiston + + ! Assign elongation factors for non-drought deciduous PFTs, which will be used + ! to define the cohort status. + case_cold_phen: select case(prt_params%season_decid(ipft)) + case (ifalse) + ! Evergreen, ensure that elongation factor is always one. + currentSite%elong_factor(ipft) = 1.0_r8 + case (itrue) + ! Cold-deciduous. Define elongation factor based on cold status + select case (currentSite%cstatus) + case (phen_cstat_nevercold,phen_cstat_iscold) + currentSite%elong_factor(ipft) = 0.0_r8 + case (phen_cstat_notcold) + currentSite%elong_factor(ipft) = 1.0_r8 + end select + end select case_cold_phen + + end select case_drought_phen + + end do pft_elong_loop call phenology_leafonoff(currentSite) + return end subroutine phenology @@ -1078,26 +1537,53 @@ subroutine phenology_leafonoff(currentSite) 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 + type(fates_patch_type) , pointer :: currentPatch + type(fates_cohort_type), pointer :: currentCohort + + real(r8) :: leaf_c ! leaf carbon [kg] + real(r8) :: fnrt_c ! fine root 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) :: leaf_deficit_c ! leaf carbon deficit (relative to target) [kg] + real(r8) :: fnrt_deficit_c ! fine root carbon deficit (relative to target) [kg] + real(r8) :: sapw_deficit_c ! sapwood carbon deficit (relative to target) [kg] + real(r8) :: struct_deficit_c ! structural wood carbon deficit (relative to target) [kg] + real(r8) :: total_deficit_c ! total carbon deficit (relative to target) [kg] + + real(r8) :: target_leaf_c ! target leaf carbon (allometry scaled by elongation factor) [kg] + real(r8) :: target_fnrt_c ! target fine root carbon (allometry scaled by elongation factor) [kg] + real(r8) :: target_sapw_c ! target sapwood carbon (allometry scaled by elongation factor) [kg] + real(r8) :: target_agw_c ! target Above ground biomass [kgC] + real(r8) :: target_bgw_c ! target Below ground biomass [kgC] + real(r8) :: target_struct_c ! target structural wood carbon (allometry scaled by elongation factor) [kg] + + real(r8) :: sapw_area ! Sapwood area + + real(r8) :: eff_leaf_drop_fraction ! Effective leaf drop fraction + real(r8) :: eff_fnrt_drop_fraction ! Effective fine-root drop fraction + real(r8) :: eff_sapw_drop_fraction ! Effective sapwood drop fraction + real(r8) :: eff_struct_drop_fraction ! Effective structural wood drop fraction + + logical :: is_flushing_time ! Time to flush leaves + logical :: is_shedding_time ! Time to shed leaves + + real(r8) :: fnrt_drop_fraction ! Fine root relative drop fraction (0 = no drop, 1 = as much as leaves) + real(r8) :: stem_drop_fraction ! Stem drop relative fraction (0 = no drop, 1 = as much as leaves) + real(r8) :: l2fr ! Leaf to fineroot biomass multiplier + + integer :: ipft ! Plant functional type index + 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)) + patch_loop: do while(associated(currentPatch)) currentCohort => currentPatch%tallest - do while(associated(currentCohort)) + cohort_loop: do while(associated(currentCohort)) ipft = currentCohort%pft @@ -1105,231 +1591,170 @@ subroutine phenology_leafonoff(currentSite) 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 + store_c = currentCohort%prt%GetState(store_organ , carbon12_element) + leaf_c = currentCohort%prt%GetState(leaf_organ , carbon12_element) + fnrt_c = currentCohort%prt%GetState(fnrt_organ , carbon12_element) + sapw_c = currentCohort%prt%GetState(sapw_organ , carbon12_element) + struct_c = currentCohort%prt%GetState(struct_organ, carbon12_element) + + fnrt_drop_fraction = prt_params%phen_fnrt_drop_fraction(ipft) + stem_drop_fraction = prt_params%phen_stem_drop_fraction(ipft) + l2fr = prt_params%allom_l2fr(ipft) + + ! MLO. To avoid duplicating code for drought and cold deciduous PFTs, we first + ! check whether or not it's time to flush or time to shed leaves, then + ! use a common code for flushing or shedding leaves. + is_time_block: if (prt_params%season_decid(ipft) == itrue) then ! Cold deciduous + + ! A. Is this the time for COLD LEAVES to switch to ON? + is_flushing_time = ( currentSite%cstatus == phen_cstat_notcold .and. & ! We just moved to leaves being on + currentCohort%status_coh == leaves_off ) ! Leaves are currently off + ! B. Is this the time for COLD LEAVES to switch to OFF? + is_shedding_time = any(currentSite%cstatus == [phen_cstat_nevercold,phen_cstat_iscold]) .and. & ! Past leaf drop day or too cold + currentCohort%status_coh == leaves_on .and. & ! Leaves have not dropped yet + ( currentCohort%dbh > EDPftvarcon_inst%phen_cold_size_threshold(ipft) .or. & ! Grasses are big enough or... + prt_params%woody(ipft) == itrue ) ! this is a woody PFT. + + elseif (any(prt_params%stress_decid(ipft) == [ihard_stress_decid,isemi_stress_decid]) ) then ! Drought deciduous + + ! A. Is this the time for DROUGHT LEAVES to switch to ON? + is_flushing_time = any( currentSite%dstatus(ipft) == [phen_dstat_moiston,phen_dstat_timeon] ) .and. & ! Leaf flushing time (moisture or time) + any( currentCohort%status_coh == [leaves_off,leaves_shedding] ) + ! B. Is this the time for DROUGHT LEAVES to switch to OFF? + ! This will be true when leaves are abscissing (partially or fully) due to moisture or time + is_shedding_time = any( currentSite%dstatus(ipft) == [phen_dstat_moistoff,phen_dstat_timeoff,phen_dstat_pshed] ) .and. & + any( currentCohort%status_coh == [leaves_on,leaves_shedding] ) + else + ! This PFT is not deciduous. + is_flushing_time = .false. + is_shedding_time = .false. + end if is_time_block + + + + ! Elongation factor for leaves is always the same as the site- and + ! PFT-dependent factor computed in subroutine phenology. For evergreen + ! PFTs, this value should be always 1.0. + currentCohort%efleaf_coh = currentSite%elong_factor(ipft) + + ! Find the effective "elongation factor" for fine roots and stems. The effective elongation + ! factor is a combination of the PFT leaf elongation factor (efleaf_coh) and the tissue drop + ! fraction relative to leaves (xxxx_drop_fraction). When xxxx_drop_fraction is 0, the biomass + ! of tissue xxxx will not be impacted by phenology. If xxxx_drop_fraction is 1, the biomass + ! of tissue xxxx will be as impacted by phenology as leaf biomass. Intermediate values will + ! allow a more moderate impact of phenology in tissue xxxx relative to leaves. + currentCohort%effnrt_coh = 1.0_r8 - (1.0_r8 - currentCohort%efleaf_coh ) * fnrt_drop_fraction + currentCohort%efstem_coh = 1.0_r8 - (1.0_r8 - currentCohort%efleaf_coh ) * stem_drop_fraction + + ! Find the target biomass for each tissue when accounting for elongation + ! factors. Note that the target works for both flushing and shedding leaves. + call bleaf(currentCohort%dbh,currentCohort%pft,currentCohort%crowndamage, & + currentCohort%canopy_trim,currentCohort%efleaf_coh,target_leaf_c) + call bfineroot(currentCohort%dbh,currentCohort%pft, & + currentCohort%canopy_trim,l2fr,currentCohort%effnrt_coh,target_fnrt_c) + call bsap_allom(currentCohort%dbh,currentCohort%pft,currentCohort%crowndamage, & + currentCohort%canopy_trim,currentCohort%efstem_coh,sapw_area,target_sapw_c) + call bagw_allom(currentCohort%dbh,currentCohort%pft,currentCohort%crowndamage,& + currentCohort%efstem_coh,target_agw_c) + call bbgw_allom(currentCohort%dbh,currentCohort%pft,currentCohort%efstem_coh,target_bgw_c) + call bdead_allom( target_agw_c, target_bgw_c, target_sapw_c, & + currentCohort%pft, target_struct_c) + + + ! A. This is time to switch to (COLD or DROUGHT) LEAF ON + flush_block: if (is_flushing_time) then + currentCohort%status_coh = leaves_on ! Leaves are on, so change status to + ! stop flow of carbon out of bstore. + + ! Transfer carbon from storage to living tissues (only if there is any carbon in storage) + transf_block: if ( store_c > nearzero ) then + ! Find the total deficit. We no longer distinguish between woody and non-woody + ! PFTs here (as sapwmemory is the same as sapw_c if this is a woody tissue). + leaf_deficit_c = max(0.0_r8, target_leaf_c - leaf_c ) + fnrt_deficit_c = max(0.0_r8, target_fnrt_c - fnrt_c ) + sapw_deficit_c = max(0.0_r8, target_sapw_c - sapw_c ) + struct_deficit_c = max(0.0_r8, target_struct_c - struct_c) + total_deficit_c = leaf_deficit_c + fnrt_deficit_c + sapw_deficit_c + & + struct_deficit_c + + ! Flush either the amount required from the memory, 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) * & + total_deficit_c / store_c, & + 1.0_r8 - carbon_store_buffer ) + + ! This call will request that storage carbon will be transferred to + ! each tissue. It is specified as a fraction of the available storage + ! MLO - Just to be safe, skip steps in the unlikely case total_deficit is zero, to avoid FPE errors. + if (total_deficit_c > nearzero) then + call PRTPhenologyFlush(currentCohort%prt, ipft, leaf_organ, & + store_c_transfer_frac*leaf_deficit_c/total_deficit_c) + call PRTPhenologyFlush(currentCohort%prt, ipft, fnrt_organ, & + store_c_transfer_frac*fnrt_deficit_c/total_deficit_c) + + ! MLO - stem_drop_fraction is a PFT parameter, do we really need this + ! check for woody/non-woody PFT? + if ( prt_params%woody(ipft) == ifalse ) then + call PRTPhenologyFlush(currentCohort%prt, ipft, sapw_organ, & + store_c_transfer_frac*sapw_deficit_c/total_deficit_c) + call PRTPhenologyFlush(currentCohort%prt, ipft, struct_organ, & + store_c_transfer_frac*struct_deficit_c/total_deficit_c) end if + end if + else + ! Not enough carbon to flush any living tissue. + store_c_transfer_frac = 0.0_r8 + end if transf_block + end if flush_block + + + + ! B. This is time to switch to (COLD or DROUGHT) LEAF OFF + shed_block: if (is_shedding_time) then + if ( currentCohort%efleaf_coh > 0.0_r8 ) then + ! Partial shedding + currentCohort%status_coh = leaves_shedding + else + ! Complete abscission + currentCohort%status_coh = leaves_off + 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. + ! Find the effective fraction to drop. This fraction must be calculated every time + ! because we must account for partial abscission. The simplest approach is to simply + ! use the ratio between the target and the original biomass of each pool. The + ! max(tissue_c,nearzero) is overly cautious, because leaf_c = 0 would imply that + ! leaves are already off, and this wouldn't be considered shedding time. + eff_leaf_drop_fraction = max( 0.0_r8, min( 1.0_r8,1.0_r8 - target_leaf_c / max( leaf_c , nearzero ) ) ) + eff_fnrt_drop_fraction = max( 0.0_r8, min( 1.0_r8,1.0_r8 - target_fnrt_c / max( fnrt_c , nearzero ) ) ) + eff_sapw_drop_fraction = max( 0.0_r8, min( 1.0_r8,1.0_r8 - target_sapw_c / max( sapw_c , nearzero ) ) ) + eff_struct_drop_fraction = max( 0.0_r8, min( 1.0_r8,1.0_r8 - target_struct_c / max( struct_c, nearzero ) ) ) + + ! Drop leaves + call PRTDeciduousTurnover(currentCohort%prt,ipft, leaf_organ, eff_leaf_drop_fraction) + + ! Drop fine roots + call PRTDeciduousTurnover(currentCohort%prt,ipft, fnrt_organ, eff_fnrt_drop_fraction) + + ! If plant is not woody, shed sapwood and heartwood (they may have a minimum amount of woody tissues for + ! running plant hydraulics, and it makes sense to shed them along with leaves when they should be off). + ! MLO - stem_drop_fraction is a PFT parameter, do we really need this check for woody/non-woody PFT? + if ( prt_params%woody(ipft) == ifalse ) then + ! Shed sapwood and heartwood. + call PRTDeciduousTurnover(currentCohort%prt,ipft,sapw_organ , eff_sapw_drop_fraction ) + call PRTDeciduousTurnover(currentCohort%prt,ipft,struct_organ, eff_struct_drop_fraction) + end if + end if shed_block if(debug) call currentCohort%prt%CheckMassConservation(ipft,1) currentCohort => currentCohort%shorter - enddo !currentCohort + end do cohort_loop currentPatch => currentPatch%younger - enddo !currentPatch + end do patch_loop end subroutine phenology_leafonoff @@ -1352,8 +1777,8 @@ subroutine satellite_phenology(currentSite, bc_in) class(prt_vartypes), pointer :: prt ! !LOCAL VARIABLES: - type(ed_patch_type) , pointer :: currentPatch - type(ed_cohort_type), pointer :: currentCohort + type(fates_patch_type) , pointer :: currentPatch + type(fates_cohort_type), pointer :: currentCohort real(r8) :: spread ! dummy value of canopy spread to estimate c_area real(r8) :: leaf_c ! leaf carbon estimated to generate target tlai @@ -1457,124 +1882,147 @@ subroutine satellite_phenology(currentSite, bc_in) end subroutine satellite_phenology - ! ===================================================================================== - - subroutine assign_cohort_SP_properties(currentCohort,htop,tlai,tsai,parea,init,leaf_c) - - ! -----------------------------------------------------------------------------------! - ! Takes the daily inputs of leaf area index, stem area index and canopy height and - ! translates them into a FATES structure with one patch and one cohort per PFT - ! The leaf area of the cohort is modified each day to match that asserted by the HLM - ! -----------------------------------------------------------------------------------! - use EDTypesMod , only : nclmax - - type(ed_cohort_type), intent(inout), target :: currentCohort - - real(r8), intent(in) :: tlai ! target leaf area index from SP inputs - real(r8), intent(in) :: tsai ! target stem area index from SP inputs - real(r8), intent(in) :: htop ! target tree height from SP inputs - real(r8), intent(in) :: parea ! patch area for this PFT - integer, intent(in) :: init ! are we in the initialization routine? if so do not set leaf_c - real(r8), intent(out) :: leaf_c ! leaf carbon estimated to generate target tlai - - real(r8) :: dummy_n ! set cohort n to a dummy value of 1.0 - integer :: fates_pft ! fates pft numer for weighting loop - real(r8) :: spread ! dummy value of canopy spread to estimate c_area - real(r8) :: check_treelai - real(r8) :: canopylai(1:nclmax) - real(r8) :: fracerr - real(r8) :: oldcarea - - ! Do some checks - if(associated(currentCohort%shorter))then - write(fates_log(),*) 'SP mode has >1 cohort' - write(fates_log(),*) "SP mode >1 cohort: PFT",currentCohort%pft, currentCohort%shorter%pft - write(fates_log(),*) "SP mode >1 cohort: CL",currentCohort%canopy_layer, currentCohort%shorter%canopy_layer - call endrun(msg=errMsg(sourcefile, __LINE__)) - end if - - !------------------------------------------ - ! Calculate dbh from input height, and c_area from dbh - !------------------------------------------ - currentCohort%hite = htop - - fates_pft = currentCohort%pft - call h2d_allom(currentCohort%hite,fates_pft,currentCohort%dbh) - - dummy_n = 1.0_r8 ! make n=1 to get area of one tree. - spread = 1.0_r8 ! fix this to 0 to remove dynamics of canopy closure, assuming a closed canopy. - ! n.b. the value of this will only affect 'n', which isn't/shouldn't be a diagnostic in - ! SP mode. - call carea_allom(currentCohort%dbh,dummy_n,spread,currentCohort%pft,currentCohort%c_area) + ! ====================================================================================== - !------------------------------------------ - ! Calculate canopy N assuming patch area is full - !------------------------------------------ - currentCohort%n = parea / currentCohort%c_area - - ! correct c_area for the new nplant - call carea_allom(currentCohort%dbh,currentCohort%n,spread,currentCohort%pft,currentCohort%c_area) + subroutine calculate_SP_properties(htop, tlai, tsai, parea, pft, crown_damage, & + canopy_layer, vcmax25top, leaf_c, dbh, cohort_n, c_area) + ! + ! DESCRIPTION: + ! Takes the daily inputs of leaf area index, stem area index and canopy height and + ! translates them into a FATES structure with one patch and one cohort per PFT. + ! The leaf area of the cohort is modified each day to match that asserted by the HLM + ! - ! ------------------------------------------ - ! Calculate leaf carbon from target treelai - ! ------------------------------------------ - currentCohort%treelai = tlai + ! ARGUMENTS: + real(r8), intent(in) :: tlai ! target leaf area index from SP inputs [m2 m-2] + real(r8), intent(in) :: tsai ! target stem area index from SP inputs [m2 m-2] + real(r8), intent(in) :: htop ! target tree height from SP inputs [m] + real(r8), intent(in) :: parea ! patch area for this PFT [m2] + real(r8), intent(in) :: vcmax25top ! maximum carboxylation at canopy top and 25degC [umol CO2/m2/s] + integer, intent(in) :: pft ! cohort PFT index + integer, intent(in) :: crown_damage ! cohort crown damage status + integer, intent(in) :: canopy_layer ! canopy status of cohort [1 = canopy, 2 = understorey, etc.] + real(r8), intent(out) :: leaf_c ! leaf carbon estimated to generate target tlai [kgC] + real(r8), intent(out) :: dbh ! cohort diameter at breast height [cm] + real(r8), intent(out) :: cohort_n ! cohort density [/m2] + real(r8), intent(out) :: c_area + + ! LOCAL VARIABLES: + real(r8) :: check_treelai ! check tree LAI against input tlai [m2/m2] + real(r8) :: canopylai(1:nclmax) ! canopy LAI [m2/m2] + real(r8) :: oldcarea ! save value of crown area [m2] + + ! calculate DBH from input height + call h2d_allom(htop, pft, dbh) + + ! calculate canopy area, assuming n = 1.0 and spread = 1.0_r8 + call carea_allom(dbh, 1.0_r8, 1.0_r8, pft, crown_damage, c_area) + + ! calculate canopy N assuming patch area is full + cohort_n = parea/c_area + + ! correct c_area for the new nplant, assuming spread = 1.0 + call carea_allom(dbh, cohort_n, 1.0_r8, pft, crown_damage, c_area) + + ! calculate leaf carbon from target treelai canopylai(:) = 0._r8 - if(init.eq.itrue)then - ! If we are initializing, the canopy layer has not been set yet, so just set to 1 - currentCohort%canopy_layer = 1 - ! We need to get the vcmax25top - currentCohort%vcmax25top = EDPftvarcon_inst%vcmax25top(currentCohort%pft,1) - endif - leaf_c = leafc_from_treelai( currentCohort%treelai, currentCohort%pft, currentCohort%c_area,& - currentCohort%n, currentCohort%canopy_layer, currentCohort%vcmax25top) + leaf_c = leafc_from_treelai(tlai, pft, c_area, cohort_n, canopy_layer, vcmax25top) - !check that the inverse calculation of leafc from treelai is the same as the + ! check that the inverse calculation of leafc from treelai is the same as the ! standard calculation of treelai from leafc. Maybe can delete eventually? + check_treelai = tree_lai(leaf_c, pft, c_area, cohort_n, canopy_layer, & + canopylai, vcmax25top) - check_treelai = tree_lai(leaf_c, currentCohort%pft, currentCohort%c_area, & - currentCohort%n, currentCohort%canopy_layer, & - canopylai,currentCohort%vcmax25top ) - - if( abs(currentCohort%treelai-check_treelai).gt.1.0e-12)then !this is not as precise as nearzero - write(fates_log(),*) 'error in validate treelai',currentCohort%treelai,check_treelai,currentCohort%treelai-check_treelai - write(fates_log(),*) 'tree_lai inputs: ', currentCohort%pft, currentCohort%c_area, currentCohort%n, & - currentCohort%canopy_layer, currentCohort%vcmax25top + if (abs(tlai - check_treelai) > area_error_2) then !this is not as precise as nearzero + write(fates_log(),*) 'error in validate treelai', tlai, check_treelai, tlai - check_treelai + write(fates_log(),*) 'tree_lai inputs: ', pft, c_area, cohort_n, & + canopy_layer, vcmax25top call endrun(msg=errMsg(sourcefile, __LINE__)) end if ! the carea_allom routine sometimes generates precision-tolerance level errors in the canopy area ! these mean that the canopy area does not exactly add up to the patch area, which causes chaos in ! the radiation routines. Correct both the area and the 'n' to remove error, and don't use - !! carea_allom in SP mode after this point. - - if(abs(currentCohort%c_area-parea).gt.nearzero)then ! there is an error - if(abs(currentCohort%c_area-parea).lt.10.e-9)then !correct this if it's a very small error - oldcarea = currentCohort%c_area - !generate new cohort area - currentCohort%c_area = currentCohort%c_area - (currentCohort%c_area- parea) - currentCohort%n = currentCohort%n * (currentCohort%c_area/oldcarea) - if(abs(currentCohort%c_area-parea).gt.nearzero)then - write(fates_log(),*) 'SPassign, c_area still broken',currentCohort%c_area-parea,currentCohort%c_area-oldcarea - call endrun(msg=errMsg(sourcefile, __LINE__)) + ! carea_allom in SP mode after this point. + + if (abs(c_area - parea) > nearzero) then ! there is an error + if (abs(c_area - parea) < area_error_3) then ! correct this if it's a very small error + oldcarea = c_area + ! generate new cohort area + c_area = c_area - (c_area - parea) + cohort_n = cohort_n*(c_area/oldcarea) + if (abs(c_area-parea) > nearzero) then + write(fates_log(),*) 'SPassign, c_area still broken', c_area - parea, c_area - oldcarea + call endrun(msg=errMsg(sourcefile, __LINE__)) end if else - write(fates_log(),*) 'SPassign, big error in c_area',currentCohort%c_area-parea,currentCohort%pft + write(fates_log(),*) 'SPassign, big error in c_area', c_area - parea, pft + call endrun(msg=errMsg(sourcefile, __LINE__)) end if ! still broken end if !small error - if(init.eq.ifalse)then - call SetState(currentCohort%prt, leaf_organ, carbon12_element, leaf_c, 1) + end subroutine calculate_SP_properties + + ! ====================================================================================== + + subroutine assign_cohort_SP_properties(currentCohort, htop, tlai, tsai, parea, init, & + leaf_c) + ! + ! DESCRIPTION: + ! Takes the daily inputs of leaf area index, stem area index and canopy height and + ! translates them into a FATES structure with one patch and one cohort per PFT. + ! The leaf area of the cohort is modified each day to match that asserted by the HLM + + + ! ARGUMENTS + type(fates_cohort_type), intent(inout), target :: currentCohort ! cohort object + real(r8), intent(in) :: tlai ! target leaf area index from SP inputs [m2/m2] + real(r8), intent(in) :: tsai ! target stem area index from SP inputs [m2/m2] + real(r8), intent(in) :: htop ! target tree height from SP inputs [m] + real(r8), intent(in) :: parea ! patch area for this PFT [m2] + integer, intent(in) :: init ! are we in the initialization routine? if so do not set leaf_c + real(r8), intent(out) :: leaf_c ! leaf carbon estimated to generate target tlai [kgC] + + ! LOCAL VARIABLES + real(r8) :: dbh ! cohort dbh [cm] + real(r8) :: cohort_n ! cohort density [/m2] + real(r8) :: c_area ! cohort canopy area [m2] + + if (associated(currentCohort%shorter)) then + write(fates_log(),*) 'SP mode has >1 cohort' + write(fates_log(),*) "SP mode >1 cohort: PFT", currentCohort%pft, currentCohort%shorter%pft + write(fates_log(),*) "SP mode >1 cohort: CL", currentCohort%canopy_layer, currentCohort%shorter%canopy_layer + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + + if (init .eq. itrue) then + ! If we are initializing, the canopy layer has not been set yet, so just set to 1 + currentCohort%canopy_layer = 1 + ! We need to get the vcmax25top + currentCohort%vcmax25top = EDPftvarcon_inst%vcmax25top(currentCohort%pft, 1) endif - ! assert sai + call calculate_SP_properties(htop, tlai, tsai, parea, currentCohort%pft, & + currentCohort%crowndamage, currentCohort%canopy_layer, currentCohort%vcmax25top, & + leaf_c, dbh, cohort_n, c_area) + + ! set allometric characteristics + currentCohort%height = htop + currentCohort%dbh = dbh + currentCohort%n = cohort_n + currentCohort%c_area = c_area + currentCohort%treelai = tlai currentCohort%treesai = tsai + if (init .eq. ifalse) then + call SetState(currentCohort%prt, leaf_organ, carbon12_element, leaf_c, 1) + endif + end subroutine assign_cohort_SP_properties ! ===================================================================================== - - subroutine SeedIn( currentSite, bc_in ) + + subroutine SeedUpdate( currentSite ) ! ----------------------------------------------------------------------------------- ! Flux from plants into the seed pool. @@ -1591,39 +2039,45 @@ subroutine SeedIn( currentSite, bc_in ) ! !USES: use EDTypesMod, only : area use EDTypesMod, only : homogenize_seed_pfts - !use FatesInterfaceTypesMod, only : hlm_use_fixed_biogeog ! For future reduced complexity? + use FatesInterfaceTypesMod, only : hlm_seeddisp_cadence + use FatesInterfaceTypesMod, only : fates_dispersal_cadence_none ! ! !ARGUMENTS type(ed_site_type), intent(inout), target :: currentSite - type(bc_in_type), intent(in) :: bc_in - type(ed_patch_type), pointer :: currentPatch + type(fates_patch_type), pointer :: currentPatch type(litter_type), pointer :: litt - type(ed_cohort_type), pointer :: currentCohort + type(fates_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) :: site_seed_rain(numpft) ! This is the sum of seed-rain for the site [kg/site/day] + real(r8) :: site_disp_frac(numpft) ! Fraction of seeds from prodeced in current grid cell to + ! disperse out to other gridcells 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) :: 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 integer :: element_id ! element id consistent with parteh/PRTGenericMod.F90 - !------------------------------------------------------------------------------------ - do el = 1, num_elements + ! If the dispersal kernel is not turned on, keep the dispersal fraction at zero + site_disp_frac(:) = 0._r8 + if (hlm_seeddisp_cadence .ne. fates_dispersal_cadence_none) then + site_disp_frac(:) = EDPftvarcon_inst%seed_dispersal_fraction(:) + end if - site_seed_rain(:) = 0._r8 + el_loop: 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)) + seed_rain_loop: do while (associated(currentPatch)) currentCohort => currentPatch%tallest do while (associated(currentCohort)) @@ -1644,7 +2098,7 @@ 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. - + call PRTReproRelease(currentCohort%prt,repro_organ,element_id, & 1.0_r8, seed_prod) @@ -1652,14 +2106,15 @@ subroutine SeedIn( currentSite, bc_in ) 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) ![kg/site/day, kg/ha/day] currentCohort => currentCohort%shorter enddo !cohort loop currentPatch => currentPatch%younger - enddo + enddo seed_rain_loop ! 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 @@ -1668,108 +2123,227 @@ subroutine SeedIn( currentSite, bc_in ) 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)) + seed_in_loop: 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 + ! Seed input from local sources (within site). Note that a fraction of the + ! internal seed rain is sent out to neighboring gridcells. + litt%seed_in_local(pft) = litt%seed_in_local(pft) + site_seed_rain(pft)*(1-site_disp_frac(pft))/area ![kg/m2/day] + + ! 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, usung the seed optimal stoichiometry - ! for non-carbon + ! 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 = prt_params%nitr_recr_stoich(pft) + seed_stoich = currentPatch%nitr_repro_stoich(pft) case(phosphorus_element) - seed_stoich = prt_params%phos_recr_stoich(pft) + 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 + ! Include both prescribed seed_suppl and seed_in dispersed from neighbouring gridcells + seed_in_external = seed_stoich*(currentSite%seed_in(pft)/area + EDPftvarcon_inst%seed_suppl(pft)*years_per_day) ![kg/m2/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 + end if !use this pft enddo - currentPatch => currentPatch%younger - enddo + enddo seed_in_loop - end do + ! Determine the total site-level seed output for the current element and update the seed_out mass + ! for each element loop since the site_seed_rain is resent and updated for each element loop iteration + do pft = 1,numpft + site_mass%seed_out = site_mass%seed_out + site_seed_rain(pft)*site_disp_frac(pft) ![kg/site/day] + currentSite%seed_out(pft) = currentSite%seed_out(pft) + site_seed_rain(pft)*site_disp_frac(pft) ![kg/site/day] + end do + + end do el_loop return - end subroutine SeedIn + end subroutine SeedUpdate ! ============================================================================ - subroutine SeedDecay( litt ) + 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. 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 + type(fates_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) :: 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 + !---------------------------------------------------------------------- + + ! 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 ! 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 + !===================================================================================== + do pft = 1,numpft + + ! 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 - litt%seed_germ_decay(pft) = litt%seed_germ(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 - enddo + 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 + + + ! If the TRS is switched on with seedling dynamics (regeneration_model = 2) + ! then calculate seedling mortality. + 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. + + 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 + + ! 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) + + 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 ! ============================================================================ - subroutine SeedGermination( litt, cold_stat, drought_stat ) + subroutine SeedGermination( litt, cold_stat, drought_stat, bc_in, 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, dimension(numpft), intent(in) :: drought_stat ! Is the site in drought leaf-off status? + type(bc_in_type), intent(in) :: bc_in + type(fates_patch_type), intent(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 + + !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 + !------------------------------------------------------------------------------------------------------------- - 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 @@ -1781,350 +2355,402 @@ subroutine SeedGermination( litt, cold_stat, drought_stat ) ! 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 - - ! ===================================================================================== - - - + ! If the TRS's seedling dynamics is switched off, then we use FATES's default approach + ! to germination + 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 - ! ===================================================================================== - - 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 + 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 - allocate(temp_cohort) ! create temporary cohort - call zero_cohort(temp_cohort) - - - do ft = 1,numpft - - ! The following if block is for the prescribed biogeography and/or nocomp modes. - ! Since currentSite%use_this_pft is a site-level quantity and thus only limits whether a given PFT - ! is permitted on a given gridcell or not, it applies to the prescribed biogeography case only. - ! If nocomp is enabled, then we must determine whether a given PFT is allowed on a given patch or not. - - if(currentSite%use_this_pft(ft).eq.itrue & - .and. ((hlm_use_nocomp .eq. ifalse) .or. (ft .eq. currentPatch%nocomp_pft_label)))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 + ! Step 1. Calculate how germination rate is modified by understory light + ! This applies to photoblastic germinators (e.g. many tropical pioneers) - ! 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 + ! 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 (Eq. 3 Hanbury-Brown et al., 2022) + photoblastic_germ_modifier = seedling_layer_par / & + (seedling_layer_par + EDPftvarcon_inst%par_crit_germ(pft)) - ! Cycle through available carbon and nutrients, find the limiting element - ! to dictate the total number of plants that can be generated + ! 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. - if ( (hlm_use_ed_prescribed_phys .eq. ifalse) .or. & - (EDPftvarcon_inst%prescribed_recruitment(ft) .lt. 0._r8) ) then + ! 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() - temp_cohort%n = 1.e20_r8 + ! 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) - do el = 1,num_elements + ! 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 - element_id = element_list(el) - select case(element_id) - case(carbon12_element) + ! 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 - mass_demand = c_struct+c_leaf+c_fnrt+c_sapw+c_store + seedling_emerg_rate = 0.0_r8 - case(nitrogen_element) + end if ! End soil-moisture based seedling emergence rate - 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) + ! Step 4. Calculate the amount of carbon germinating out of the seed bank + litt%seed_germ_in(pft) = litt%seed(pft) * seedling_emerg_rate - 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))) + end if if_tfs_or_def + + !set the germination only under the growing season...c.xu - case default - write(fates_log(),*) 'Undefined element type in recruitment' - call endrun(msg=errMsg(sourcefile, __LINE__)) - end select + if ((prt_params%season_decid(pft) == itrue ) .and. & + (any(cold_stat == [phen_cstat_nevercold,phen_cstat_iscold]))) then + ! no germination for all PFTs when cold + litt%seed_germ_in(pft) = 0.0_r8 + endif - mass_avail = currentPatch%area * currentPatch%litter(el)%seed_germ(ft) + ! Drought deciduous, halt germination when status is shedding, even leaves are not + ! completely abscissed. MLO + select case (prt_params%stress_decid(pft)) + case (ihard_stress_decid,isemi_stress_decid) + if (any(drought_stat(pft) == [phen_dstat_timeoff,phen_dstat_moistoff,phen_dstat_pshed])) then + litt%seed_germ_in(pft) = 0.0_r8 + end if + end select - ! ------------------------------------------------------------------------ - ! Update number density if this is the limiting mass - ! ------------------------------------------------------------------------ + end do - temp_cohort%n = min(temp_cohort%n, mass_avail/mass_demand) + end subroutine SeedGermination - end do + ! ===================================================================================== + subroutine recruitment(currentSite, currentPatch, bc_in) + ! + ! DESCRIPTION: + ! spawn new cohorts of juveniles of each PFT + ! + + ! ARGUMENTS: + type(ed_site_type), intent(inout) :: currentSite + type(fates_patch_type), intent(inout), pointer :: currentPatch + type(bc_in_type), intent(in) :: bc_in + + ! LOCAL VARIABLES: + class(prt_vartypes), pointer :: prt ! PARTEH object + type(litter_type), pointer :: litt ! litter object (carbon right now) + type(site_massbal_type), pointer :: site_mass ! for accounting total in-out mass fluxes + integer :: ft ! loop counter for PFTs + integer :: leaf_status ! cohort phenology status [leaves on/off] + 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 :: crowndamage ! crown damage class of the cohort [1 = undamaged, >1 = damaged] + real(r8) :: height ! new cohort height [m] + real(r8) :: dbh ! new cohort DBH [cm] + real(r8) :: cohort_n ! new cohort density + real(r8) :: l2fr ! leaf to fineroot biomass ratio [0-1] + 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) :: efleaf_coh + real(r8) :: effnrt_coh + real(r8) :: efstem_coh + real(r8) :: mass_avail ! 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 ! + real(r8) :: fnrt_drop_fraction ! + real(r8) :: sdlng2sap_par ! running mean of PAR at the seedling layer [MJ/m2/day] + real(r8) :: seedling_layer_smp ! soil matric potential at seedling rooting depth [mm H2O suction] + integer, parameter :: recruitstatus = 1 ! whether the newly created cohorts are recruited or initialized + integer :: ilayer_seedling_root ! the soil layer at seedling rooting depth + + !--------------------------------------------------------------------------- + + do ft = 1, numpft + + ! The following if block is for the prescribed biogeography and/or nocomp modes. + ! Since currentSite%use_this_pft is a site-level quantity and thus only limits whether a given PFT + ! is permitted on a given gridcell or not, it applies to the prescribed biogeography case only. + ! If nocomp is enabled, then we must determine whether a given PFT is allowed on a given patch or not. + + if (currentSite%use_this_pft(ft) .eq. itrue .and. & + ((hlm_use_nocomp .eq. ifalse) .or. & + (ft .eq. currentPatch%nocomp_pft_label))) then + + height = EDPftvarcon_inst%hgt_min(ft) + stem_drop_fraction = prt_params%phen_stem_drop_fraction(ft) + fnrt_drop_fraction = prt_params%phen_fnrt_drop_fraction(ft) + l2fr = currentSite%rec_l2fr(ft, currentPatch%NCL_p) + crowndamage = 1 ! new recruits are undamaged + + ! calculate DBH from initial height + call h2d_allom(height, ft, dbh) + + ! default assumption is that leaves are on + efleaf_coh = 1.0_r8 + effnrt_coh = 1.0_r8 + efstem_coh = 1.0_r8 + leaf_status = leaves_on + + ! 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 + efleaf_coh = 0.0_r8 + effnrt_coh = 1.0_r8 - fnrt_drop_fraction + efstem_coh = 1.0_r8 - stem_drop_fraction + leaf_status = leaves_off + end if + + ! Or.. if the plant is drought deciduous, make sure leaf status is consistent with the + ! leaf elongation factor. + ! For tissues other than leaves, the actual drop fraction is a combination of the + ! elongation factor (e) and the drop fraction (x), which will ensure that the remaining + ! tissue biomass will be exactly e when x=1, and exactly the original biomass when x = 0. + select case (prt_params%stress_decid(ft)) + case (ihard_stress_decid, isemi_stress_decid) + efleaf_coh = currentSite%elong_factor(ft) + effnrt_coh = 1.0_r8 - (1.0_r8 - efleaf_coh)*fnrt_drop_fraction + efstem_coh = 1.0_r8 - (1.0_r8 - efleaf_coh)*stem_drop_fraction + + ! For the initial state, we always assume that leaves are flushing (instead of partially abscissing) + ! whenever the elongation factor is non-zero. If the elongation factor is zero, then leaves are in + ! the "off" state. + if (efleaf_coh > 0.0_r8) then + leaf_status = leaves_on + else + leaf_status = leaves_off + end if + end select + + ! calculate live pools + call bleaf(dbh, ft, crowndamage, init_recruit_trim, efleaf_coh, & + c_leaf) + call bfineroot(dbh, ft, init_recruit_trim, l2fr, effnrt_coh, c_fnrt) + call bsap_allom(dbh, ft, crowndamage, init_recruit_trim, & + efstem_coh, a_sapw, c_sapw) + call bagw_allom(dbh, ft, crowndamage, efstem_coh, c_agw) + call bbgw_allom(dbh, ft, efstem_coh, c_bgw) + call bdead_allom(c_agw, c_bgw, c_sapw, ft, c_struct) + call bstore_allom(dbh, ft, crowndamage, init_recruit_trim, c_store) + + ! cycle through available carbon and nutrients, find the limiting element + ! to dictate the total number of plants that can be generated + if_not_prescribed: if ((hlm_use_ed_prescribed_phys .eq. ifalse) .or. & + (EDPftvarcon_inst%prescribed_recruitment(ft) .lt. 0._r8)) then + + cohort_n = 1.e20_r8 + + do_elem: 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_p1(ft, prt_params%organ_param_id(struct_organ)) + & + c_leaf*prt_params%nitr_stoich_p1(ft, prt_params%organ_param_id(leaf_organ)) + & + c_fnrt*prt_params%nitr_stoich_p1(ft, prt_params%organ_param_id(fnrt_organ)) + & + c_sapw*prt_params%nitr_stoich_p1(ft, prt_params%organ_param_id(sapw_organ)) + & + StorageNutrientTarget(ft, element_id, & + c_leaf*prt_params%nitr_stoich_p1(ft, prt_params%organ_param_id(leaf_organ)), & + c_fnrt*prt_params%nitr_stoich_p1(ft, prt_params%organ_param_id(fnrt_organ)), & + c_sapw*prt_params%nitr_stoich_p1(ft, prt_params%organ_param_id(sapw_organ)), & + c_struct*prt_params%nitr_stoich_p1(ft, prt_params%organ_param_id(struct_organ))) + case(phosphorus_element) + mass_demand = & + c_struct*prt_params%phos_stoich_p1(ft, prt_params%organ_param_id(struct_organ)) + & + c_leaf*prt_params%phos_stoich_p1(ft, prt_params%organ_param_id(leaf_organ)) + & + c_fnrt*prt_params%phos_stoich_p1(ft, prt_params%organ_param_id(fnrt_organ)) + & + c_sapw*prt_params%phos_stoich_p1(ft, prt_params%organ_param_id(sapw_organ)) + & + StorageNutrientTarget(ft, element_id, & + c_leaf*prt_params%phos_stoich_p1(ft, prt_params%organ_param_id(leaf_organ)), & + c_fnrt*prt_params%phos_stoich_p1(ft, prt_params%organ_param_id(fnrt_organ)), & + c_sapw*prt_params%phos_stoich_p1(ft, prt_params%organ_param_id(sapw_organ)), & + c_struct*prt_params%phos_stoich_p1(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 + + ! 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_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) + + ! 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 if ! End use TRS with seedling dynamics + + ! update number density if this is the limiting mass + cohort_n = min(cohort_n, mass_avail/mass_demand) + + end do do_elem - else - ! prescribed recruitment rates. number per sq. meter per year - temp_cohort%n = currentPatch%area * & - EDPftvarcon_inst%prescribed_recruitment(ft) * & + else + ! prescribed recruitment rates. number per sq. meter per year + 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,temp_cohort%c_area, & - 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 - - ! ============================================================================ + endif if_not_prescribed + + ! Only bother allocating a new cohort if there is a reasonable amount of it + any_recruits: if (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_p1(ft, prt_params%organ_param_id(struct_organ)) + m_leaf = c_leaf*prt_params%nitr_stoich_p1(ft, prt_params%organ_param_id(leaf_organ)) + m_fnrt = c_fnrt*prt_params%nitr_stoich_p1(ft, prt_params%organ_param_id(fnrt_organ)) + m_sapw = c_sapw*prt_params%nitr_stoich_p1(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_p1(ft, prt_params%organ_param_id(struct_organ)) + m_leaf = c_leaf*prt_params%phos_stoich_p1(ft, prt_params%organ_param_id(leaf_organ)) + m_fnrt = c_fnrt*prt_params%phos_stoich_p1(ft, prt_params%organ_param_id(fnrt_organ)) + m_sapw = c_sapw*prt_params%phos_stoich_p1(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 + & + 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) - cohort_n / currentPatch%area * & + (m_struct + m_leaf + m_fnrt + m_sapw + m_store + m_repro) + end if + end do + + ! cycle through the initial conditions, and makes sure that they are all initialized + call prt%CheckInitialConditions() + + call create_cohort(currentSite, currentPatch, ft, cohort_n, & + height, 0.0_r8, dbh, prt, efleaf_coh, effnrt_coh, efstem_coh, & + leaf_status, recruitstatus, init_recruit_trim, 0.0_r8, & + currentPatch%NCL_p, crowndamage, currentSite%spread, bc_in) + + ! Note that if hydraulics is on, the number of cohorts may have + ! 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) + cohort_n + + endif any_recruits + endif !use_this_pft + enddo !pft loop + end subroutine recruitment + + ! ====================================================================================== subroutine CWDInput( currentSite, currentPatch, litt, bc_in) @@ -2137,18 +2763,17 @@ subroutine CWDInput( currentSite, currentPatch, litt, bc_in) ! 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(fates_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(fates_cohort_type), pointer :: currentCohort type(site_fluxdiags_type), pointer :: flux_diags type(site_massbal_type), pointer :: site_mass integer :: c @@ -2183,6 +2808,8 @@ subroutine CWDInput( currentSite, currentPatch, litt, bc_in) integer :: pft integer :: dcmpy ! decomposability pool index integer :: numlevsoil ! Actual number of soil layers + + real(r8) :: SF_val_CWD_frac_adj(4) !SF_val_CWD_frac adjusted based on cohort dbh !---------------------------------------------------------------------- ! ----------------------------------------------------------------------------------- @@ -2201,25 +2828,43 @@ subroutine CWDInput( currentSite, currentPatch, litt, bc_in) currentCohort => currentPatch%shortest do while(associated(currentCohort)) - pft = currentCohort%pft - call set_root_fraction(currentSite%rootfrac_scr, pft, currentSite%zi_soil, & + 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) + if (prt_params%woody(currentCohort%pft) == itrue) then + ! Assumption: for woody plants fluxes from deadwood and sapwood go together in CWD pool + leaf_m_turnover = currentCohort%prt%GetTurnover(leaf_organ,element_id) + sapw_m_turnover = currentCohort%prt%GetTurnover(sapw_organ,element_id) + struct_m_turnover = currentCohort%prt%GetTurnover(struct_organ,element_id) + + leaf_m = currentCohort%prt%GetState(leaf_organ,element_id) + sapw_m = currentCohort%prt%GetState(sapw_organ,element_id) + struct_m = currentCohort%prt%GetState(struct_organ,element_id) + else + ! for non-woody plants all stem fluxes go into the same leaf litter pool + leaf_m_turnover = currentCohort%prt%GetTurnover(leaf_organ,element_id) + & + currentCohort%prt%GetTurnover(sapw_organ,element_id) + & + currentCohort%prt%GetTurnover(struct_organ,element_id) + sapw_m_turnover = 0._r8 + struct_m_turnover = 0._r8 + + leaf_m = currentCohort%prt%GetState(leaf_organ,element_id) + & + currentCohort%prt%GetState(sapw_organ,element_id) + & + currentCohort%prt%GetState(struct_organ,element_id) + sapw_m = 0._r8 + struct_m = 0._r8 + end if + plant_dens = currentCohort%n/currentPatch%area ! --------------------------------------------------------------------------------- @@ -2256,18 +2901,22 @@ subroutine CWDInput( currentSite, currentPatch, litt, bc_in) ! Assumption: turnover from deadwood and sapwood are lumped together in CWD pool + !update partitioning of stem wood (struct + sapw) to cwd based on cohort dbh + call adjust_SF_CWD_frac(currentCohort%dbh,ncwd,SF_val_CWD_frac,SF_val_CWD_frac_adj) + + 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 * & + SF_val_CWD_frac_adj(c) * plant_dens * & prt_params%allom_agb_frac(pft) flux_diags%cwd_ag_input(c) = flux_diags%cwd_ag_input(c) + & - (struct_m_turnover + sapw_m_turnover) * SF_val_CWD_frac(c) * & + (struct_m_turnover + sapw_m_turnover) * SF_val_CWD_frac_adj(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 * & + SF_val_CWD_frac_adj(c) * plant_dens * & (1.0_r8-prt_params%allom_agb_frac(pft)) do ilyr = 1, numlevsoil @@ -2348,7 +2997,7 @@ subroutine CWDInput( currentSite, currentPatch, litt, bc_in) ! Below-ground bg_cwd_tot = (struct_m + sapw_m) * & - SF_val_CWD_frac(c) * dead_n * & + SF_val_CWD_frac_adj(c) * dead_n * & (1.0_r8-prt_params%allom_agb_frac(pft)) do ilyr = 1, numlevsoil @@ -2367,7 +3016,7 @@ subroutine CWDInput( currentSite, currentPatch, litt, bc_in) trunk_wood = (struct_m + sapw_m) * & - SF_val_CWD_frac(c) * dead_n_dlogging * & + SF_val_CWD_frac_adj(c) * dead_n_dlogging * & prt_params%allom_agb_frac(pft) site_mass%wood_product = site_mass%wood_product + & @@ -2385,21 +3034,21 @@ subroutine CWDInput( currentSite, currentPatch, litt, bc_in) ! 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) * & + SF_val_CWD_frac_adj(c) * (dead_n_natural+dead_n_ilogging) * & prt_params%allom_agb_frac(pft) flux_diags%cwd_ag_input(c) = flux_diags%cwd_ag_input(c) + & - SF_val_CWD_frac(c) * (dead_n_natural+dead_n_ilogging) * & + SF_val_CWD_frac_adj(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 * & + SF_val_CWD_frac_adj(c) * dead_n * & prt_params%allom_agb_frac(pft) flux_diags%cwd_ag_input(c) = flux_diags%cwd_ag_input(c) + & - SF_val_CWD_frac(c) * dead_n * (struct_m + sapw_m) * & + SF_val_CWD_frac_adj(c) * dead_n * (struct_m + sapw_m) * & currentPatch%area * prt_params%allom_agb_frac(pft) end if @@ -2429,13 +3078,13 @@ subroutine CWDInput( currentSite, currentPatch, litt, bc_in) 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) * & + SF_val_CWD_frac_adj(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 + SF_val_CWD_frac_adj(c) * dead_n * currentPatch%area end do ! Update diagnostics that track resource management @@ -2463,13 +3112,11 @@ subroutine fragmentation_scaler( currentPatch, bc_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(fates_patch_type), intent(inout) :: currentPatch type(bc_in_type), intent(in) :: bc_in ! @@ -2487,7 +3134,7 @@ subroutine fragmentation_scaler( currentPatch, bc_in) catanf(t1) = 11.75_r8 +(29.7_r8 / pi) * atan( pi * 0.031_r8 * ( t1 - 15.4_r8 )) catanf_30 = catanf(30._r8) - if(currentPatch%nocomp_pft_label.ne.0)then + if(currentPatch%nocomp_pft_label.ne.nocomp_bareground)then ! Use the hlm temp and moisture decomp fractions by default if ( use_hlm_soil_scalar ) then @@ -2590,5 +3237,152 @@ subroutine CWDOut( litt, fragmentation_scaler, nlev_eff_decomp ) enddo end subroutine CWDOut + + subroutine UpdateRecruitL2FR(csite) + + + ! When CNP is active, the l2fr (target leaf to fine-root biomass multiplier) + ! is dynamic. We therefore update what the l2fr for recruits + ! are, taking an exponential moving average of all plants that + ! are within recruit size limitations (less than recruit size + delta) + ! and less than the max_count cohort. + + type(ed_site_type) :: csite + type(fates_patch_type), pointer :: cpatch + type(fates_cohort_type), pointer :: ccohort + + real(r8) :: rec_n(maxpft,nclmax) ! plant count + real(r8) :: rec_l2fr0(maxpft,nclmax) ! mean l2fr for this day + integer :: rec_count(maxpft,nclmax) ! sample count + integer :: ft ! functional type index + integer :: cl ! canopy layer index + real(r8) :: dbh_min ! the dbh of a recruit + real(r8), parameter :: max_delta = 5.0_r8 ! dbh tolerance, cm, consituting a recruit + real(r8), parameter :: smth_wgt = 1._r8/300.0_r8 + integer, parameter :: max_count = 3 + + ! Difference in dbh (cm) to consider a plant was recruited fairly recently + + if(hlm_parteh_mode .ne. prt_cnp_flex_allom_hyp) return + + rec_n(1:numpft,1:nclmax) = 0._r8 + rec_l2fr0(1:numpft,1:nclmax) = 0._r8 + + cpatch => csite%youngest_patch + do while(associated(cpatch)) + + rec_count(1:numpft,1:nclmax) = 0 + + ccohort => cpatch%shortest + cloop: do while(associated(ccohort)) + + ft = ccohort%pft + cl = ccohort%canopy_layer + call h2d_allom(EDPftvarcon_inst%hgt_min(ft),ft,dbh_min) + + if( .not.ccohort%isnew ) then + + if(rec_count(ft,cl) <= max_count .and. & + ccohort%dbh-dbh_min < max_delta ) then + rec_count(ft,cl) = rec_count(ft,cl) + 1 + rec_n(ft,cl) = rec_n(ft,cl) + ccohort%n + rec_l2fr0(ft,cl) = rec_l2fr0(ft,cl) + ccohort%n*ccohort%l2fr + end if + + end if + + ccohort => ccohort%taller + end do cloop + + cpatch => cpatch%older + end do + + ! Find the daily mean for each PFT weighted by number and add it to the running mean + do cl = 1,nclmax + do ft = 1,numpft + if(rec_n(ft,cl)>nearzero)then + rec_l2fr0(ft,cl) = rec_l2fr0(ft,cl) / rec_n(ft,cl) + csite%rec_l2fr(ft,cl) = & + (1._r8-smth_wgt)*csite%rec_l2fr(ft,cl) + smth_wgt*rec_l2fr0(ft,cl) + end if + end do + end do + + return + end subroutine UpdateRecruitL2FR + + ! ====================================================================== + + subroutine UpdateRecruitStoich(csite) + + type(ed_site_type) :: csite + type(fates_patch_type), pointer :: cpatch + type(fates_cohort_type), pointer :: ccohort + integer :: ft ! functional type index + integer :: cl ! canopy layer index + real(r8) :: rec_l2fr_pft ! Actual l2fr of a pft in it's patch + + ! Update the total plant stoichiometry of a new recruit, based on the updated + ! L2FR values + + if(hlm_parteh_mode .ne. prt_cnp_flex_allom_hyp) return + + cpatch => csite%youngest_patch + do while(associated(cpatch)) + cl = cpatch%ncl_p + + do ft = 1,numpft + rec_l2fr_pft = csite%rec_l2fr(ft,cl) + cpatch%nitr_repro_stoich(ft) = & + NewRecruitTotalStoichiometry(ft,rec_l2fr_pft,nitrogen_element) + cpatch%phos_repro_stoich(ft) = & + NewRecruitTotalStoichiometry(ft,rec_l2fr_pft,phosphorus_element) + end do + + ccohort => cpatch%shortest + cloop: do while(associated(ccohort)) + rec_l2fr_pft = csite%rec_l2fr(ccohort%pft,cl) + ccohort%nc_repro = NewRecruitTotalStoichiometry(ccohort%pft,rec_l2fr_pft,nitrogen_element) + ccohort%pc_repro = NewRecruitTotalStoichiometry(ccohort%pft,rec_l2fr_pft,phosphorus_element) + ccohort => ccohort%taller + end do cloop + + cpatch => cpatch%older + end do + + return + end subroutine UpdateRecruitStoich + + ! ====================================================================== + + subroutine SetRecruitL2FR(csite) + + + type(ed_site_type) :: csite + type(fates_patch_type), pointer :: cpatch + type(fates_cohort_type), pointer :: ccohort + integer :: ft,cl + + if(hlm_parteh_mode .ne. prt_cnp_flex_allom_hyp) return + + cpatch => csite%youngest_patch + do while(associated(cpatch)) + ccohort => cpatch%shortest + cloop: do while(associated(ccohort)) + + if( ccohort%isnew ) then + ft = ccohort%pft + cl = ccohort%canopy_layer + ccohort%l2fr = csite%rec_l2fr(ft,cl) + end if + + ccohort => ccohort%taller + end do cloop + + cpatch => cpatch%older + end do + + return + end subroutine SetRecruitL2FR end module EDPhysiologyMod diff --git a/biogeochem/FatesAllometryMod.F90 b/biogeochem/FatesAllometryMod.F90 index 42264ca776..431219cfda 100644 --- a/biogeochem/FatesAllometryMod.F90 +++ b/biogeochem/FatesAllometryMod.F90 @@ -95,9 +95,10 @@ module FatesAllometryMod use shr_log_mod , only : errMsg => shr_log_errMsg use FatesGlobals , only : fates_log use FatesGlobals , only : endrun => fates_endrun - use EDTypesMod , only : nlevleaf, dinc_vai - use EDTypesMod , only : nclmax - + use FatesGlobals , only : FatesWarn,N2S,A2S,I2S + use EDParamsMod , only : nlevleaf, dinc_vai + use EDParamsMod , only : nclmax + use DamageMainMod , only : GetCrownReduction implicit none @@ -130,6 +131,8 @@ module FatesAllometryMod logical, parameter :: debug = .false. + + character(len=1024) :: warn_msg ! for defining a warning message ! If testing b4b with older versions, do not remove sapwood ! Our old methods with saldarriaga did not remove sapwood from the @@ -157,8 +160,9 @@ module FatesAllometryMod ! ============================================================================ - subroutine CheckIntegratedAllometries(dbh,ipft,canopy_trim, & - bl,bfr,bsap,bstore,bdead, & + subroutine CheckIntegratedAllometries(dbh,ipft,crowndamage, & + canopy_trim, elongf_leaf, elongf_fnrt, elongf_stem, & + l2fr, bl,bfr,bsap,bstore,bdead, & grow_leaf, grow_fr, grow_sap, grow_store, grow_dead, & max_err, l_pass) @@ -172,7 +176,12 @@ subroutine CheckIntegratedAllometries(dbh,ipft,canopy_trim, & real(r8),intent(in) :: dbh ! diameter of plant [cm] integer,intent(in) :: ipft ! plant functional type index + integer,intent(in) :: crowndamage ! crowndamage [1: undamaged, >1 damaged] real(r8),intent(in) :: canopy_trim ! trimming function + real(r8),intent(in) :: elongf_leaf ! Leaf elongation factor + real(r8),intent(in) :: elongf_fnrt ! Fine-root elongation factor + real(r8),intent(in) :: elongf_stem ! Stem elongation factor + real(r8),intent(in) :: l2fr ! leaf to fine-root biomass multiplier (fr/leaf) real(r8),intent(in) :: bl ! integrated leaf biomass [kgC] real(r8),intent(in) :: bfr ! integrated fine root biomass [kgC] real(r8),intent(in) :: bsap ! integrated sapwood biomass [kgC] @@ -202,7 +211,7 @@ subroutine CheckIntegratedAllometries(dbh,ipft,canopy_trim, & l_pass = .true. ! Default assumption is that step passed if (grow_leaf) then - call bleaf(dbh,ipft,canopy_trim,bl_diag) + call bleaf(dbh,ipft,crowndamage, canopy_trim, elongf_leaf, bl_diag) if( abs(bl_diag-bl) > max_err ) then if(verbose_logging) then write(fates_log(),*) 'disparity in integrated/diagnosed leaf carbon' @@ -216,7 +225,7 @@ subroutine CheckIntegratedAllometries(dbh,ipft,canopy_trim, & end if if (grow_fr) then - call bfineroot(dbh,ipft,canopy_trim,bfr_diag) + call bfineroot(dbh,ipft,canopy_trim,l2fr, elongf_fnrt, bfr_diag) if( abs(bfr_diag-bfr) > max_err ) then if(verbose_logging) then write(fates_log(),*) 'disparity in integrated/diagnosed fineroot carbon' @@ -230,7 +239,7 @@ subroutine CheckIntegratedAllometries(dbh,ipft,canopy_trim, & end if if (grow_sap) then - call bsap_allom(dbh,ipft,canopy_trim,asap_diag,bsap_diag) + call bsap_allom(dbh,ipft,crowndamage, canopy_trim, elongf_stem, asap_diag,bsap_diag) if( abs(bsap_diag-bsap) > max_err ) then if(verbose_logging) then write(fates_log(),*) 'disparity in integrated/diagnosed sapwood carbon' @@ -244,7 +253,7 @@ subroutine CheckIntegratedAllometries(dbh,ipft,canopy_trim, & end if if (grow_store) then - call bstore_allom(dbh,ipft,canopy_trim,bstore_diag) + call bstore_allom(dbh,ipft,crowndamage, canopy_trim,bstore_diag) if( abs(bstore_diag-bstore) > max_err ) then if(verbose_logging) then write(fates_log(),*) 'disparity in integrated/diagnosed storage carbon' @@ -258,10 +267,11 @@ subroutine CheckIntegratedAllometries(dbh,ipft,canopy_trim, & end if if (grow_dead) then - call bsap_allom(dbh,ipft,canopy_trim,asap_diag,bsap_diag) - call bagw_allom(dbh,ipft,bagw_diag) - call bbgw_allom(dbh,ipft,bbgw_diag) - call bdead_allom( bagw_diag, bbgw_diag, bsap_diag, ipft, bdead_diag ) + call bsap_allom(dbh,ipft,crowndamage, canopy_trim, elongf_stem,asap_diag,bsap_diag) + call bagw_allom(dbh,ipft,crowndamage, elongf_stem, bagw_diag) + call bbgw_allom(dbh,ipft, elongf_stem,bbgw_diag) + call bdead_allom( bagw_diag, bbgw_diag, bsap_diag, ipft, bdead_diag ) + if( abs(bdead_diag-bdead) > max_err ) then if(verbose_logging) then write(fates_log(),*) 'disparity in integrated/diagnosed structural carbon' @@ -359,17 +369,23 @@ end subroutine h_allom ! Generic AGB interface ! ============================================================================ - subroutine bagw_allom(d,ipft,bagw,dbagwdd) - + subroutine bagw_allom(d,ipft,crowndamage, elongf_stem, bagw,dbagwdd) + use DamageMainMod, only : GetCrownReduction + use FatesParameterDerivedMod, only : param_derived + real(r8),intent(in) :: d ! plant diameter [cm] integer(i4),intent(in) :: ipft ! PFT index + integer(i4),intent(in) :: crowndamage ! crowndamage [1: undamaged, >1: damaged] + real(r8),intent(in) :: elongf_stem ! Stem elongation factor real(r8),intent(out) :: bagw ! biomass above ground woody tissues real(r8),intent(out),optional :: dbagwdd ! change in agbw per diameter [kgC/cm] real(r8) :: h ! height real(r8) :: dhdd ! change in height wrt d - + real(r8) :: crown_reduction ! crown reduction from damage + real(r8) :: branch_frac ! fraction of aboveground woody biomass in branches + associate( p1 => prt_params%allom_agb1(ipft), & p2 => prt_params%allom_agb2(ipft), & p3 => prt_params%allom_agb3(ipft), & @@ -378,6 +394,8 @@ subroutine bagw_allom(d,ipft,bagw,dbagwdd) c2b => prt_params%c2b(ipft), & agb_frac => prt_params%allom_agb_frac(ipft), & allom_amode => prt_params%allom_amode(ipft)) + + branch_frac = param_derived%branch_frac(ipft) select case(int(allom_amode)) case (1) !"salda") @@ -395,6 +413,22 @@ subroutine bagw_allom(d,ipft,bagw,dbagwdd) call endrun(msg=errMsg(sourcefile, __LINE__)) end select + ! Potentially reduce AGB based on crown damage (crown_reduction) and/or + ! phenology (elongf_stem). + if(crowndamage > 1) then + call GetCrownReduction(crowndamage, crown_reduction) + bagw = elongf_stem * ( bagw - (bagw * branch_frac * crown_reduction) ) + if(present(dbagwdd))then + dbagwdd = elongf_stem * ( dbagwdd - (dbagwdd * branch_frac * crown_reduction) ) + end if + else + bagw = elongf_stem * bagw + if (present(dbagwdd)) then + dbagwdd = elongf_stem * dbagwdd + end if + end if + + end associate return end subroutine bagw_allom @@ -439,12 +473,13 @@ end subroutine blmax_allom ! Generic crown area allometry wrapper ! ============================================================================ - subroutine carea_allom(dbh,nplant,site_spread,ipft,c_area,inverse) + subroutine carea_allom(dbh,nplant,site_spread,ipft,crowndamage,c_area,inverse) real(r8),intent(inout) :: dbh ! plant diameter at breast (reference) height [cm] real(r8),intent(in) :: site_spread ! site level spread factor (crowdedness) real(r8),intent(in) :: nplant ! number of plants [1/ha] integer(i4),intent(in) :: ipft ! PFT index + integer(i4),intent(in) :: crowndamage ! crown damage class [1: undamaged, >1: damaged] real(r8),intent(inout) :: c_area ! crown area per cohort (m2) logical,optional,intent(in) :: inverse ! if true, calculate dbh from crown area ! instead of crown area from dbh @@ -475,14 +510,17 @@ subroutine carea_allom(dbh,nplant,site_spread,ipft,c_area,inverse) select case(int(allom_lmode)) case(1) dbh_eff = min(dbh,dbh_maxh) - call carea_2pwr(dbh_eff,site_spread,d2bl_p2,d2bl_ediff,d2ca_min,d2ca_max,c_area,do_inverse) + call carea_2pwr(dbh_eff,site_spread,d2bl_p2,d2bl_ediff,d2ca_min,d2ca_max, & + crowndamage,c_area, do_inverse) capped_allom = .true. case(2) ! "2par_pwr") - call carea_2pwr(dbh,site_spread,d2bl_p2,d2bl_ediff,d2ca_min,d2ca_max,c_area,do_inverse) + call carea_2pwr(dbh,site_spread,d2bl_p2,d2bl_ediff,d2ca_min,d2ca_max, & + crowndamage, c_area, do_inverse) capped_allom = .false. case(3) dbh_eff = min(dbh,dbh_maxh) - call carea_2pwr(dbh_eff,site_spread,d2bl_p2,d2bl_ediff,d2ca_min,d2ca_max,c_area,do_inverse) + call carea_2pwr(dbh_eff,site_spread,d2bl_p2,d2bl_ediff,d2ca_min,d2ca_max, & + crowndamage, c_area, do_inverse) capped_allom = .true. case DEFAULT write(fates_log(),*) 'An undefined leaf allometry was specified: ', & @@ -513,7 +551,7 @@ end subroutine carea_allom ! ===================================================================================== - subroutine bleaf(d,ipft,canopy_trim,bl,dbldd) + subroutine bleaf(d,ipft,crowndamage,canopy_trim,elongf_leaf,bl,dbldd) ! ------------------------------------------------------------------------- ! This subroutine calculates the actual target bleaf @@ -521,15 +559,20 @@ subroutine bleaf(d,ipft,canopy_trim,bl,dbldd) ! is not allometry and rather an emergent property, ! this routine is not name-spaced with allom_ ! ------------------------------------------------------------------------- + + use DamageMainMod , only : GetCrownReduction real(r8),intent(in) :: d ! plant diameter [cm] integer(i4),intent(in) :: ipft ! PFT index + integer(i4),intent(in) :: crowndamage ! crown damage class [1: undamaged, >1: damaged] real(r8),intent(in) :: canopy_trim ! trimming function - real(r8),intent(out) :: bl ! plant leaf biomass [kg] + real(r8),intent(in) :: elongf_leaf ! Leaf elongation factor (phenology) + real(r8),intent(out) :: bl ! plant leaf biomass [kgC] real(r8),intent(out),optional :: dbldd ! change leaf bio per diameter [kgC/cm] real(r8) :: blmax real(r8) :: dblmaxdd + real(r8) :: crown_reduction call blmax_allom(d,ipft,blmax,dblmaxdd) @@ -541,11 +584,28 @@ subroutine bleaf(d,ipft,canopy_trim,bl,dbldd) ! ------------------------------------------------------------------------- bl = blmax * canopy_trim - + if(present(dbldd))then dbldd = dblmaxdd * canopy_trim end if - + + + ! Potentially reduce leaf biomass based on crown damage (crown_reduction) and/or + ! phenology (elongf_leaf). + if ( crowndamage > 1 ) then + + call GetCrownReduction(crowndamage, crown_reduction) + bl = elongf_leaf * bl * (1.0_r8 - crown_reduction) + if(present(dbldd))then + dbldd = elongf_leaf * dblmaxdd * canopy_trim * (1.0_r8 - crown_reduction) + end if + else + bl = elongf_leaf * bl + if (present(dbldd)) then + dbldd = elongf_leaf * dbldd + end if + end if + return end subroutine bleaf @@ -702,16 +762,18 @@ end function tree_lai ! ============================================================================ - real(r8) function tree_sai( pft, dbh, canopy_trim, c_area, nplant, cl, & - canopy_lai, treelai, vcmax25top, call_id ) + real(r8) function tree_sai(pft, dbh, crowndamage, canopy_trim, elongf_stem, c_area, nplant, & + cl, canopy_lai, treelai, vcmax25top, call_id ) ! ============================================================================ ! SAI of individual trees is a function of the LAI of individual trees ! ============================================================================ - integer, intent(in) :: pft - real(r8), intent(in) :: dbh + integer, intent(in) :: pft + real(r8), intent(in) :: dbh + integer, intent(in) :: crowndamage real(r8), intent(in) :: canopy_trim ! trimming function (0-1) + real(r8), intent(in) :: elongf_stem ! Elongation factor for stems. real(r8), intent(in) :: c_area ! crown area (m2) real(r8), intent(in) :: nplant ! number of plants integer, intent(in) :: cl ! canopy layer index @@ -722,14 +784,17 @@ real(r8) function tree_sai( pft, dbh, canopy_trim, c_area, nplant, cl, & integer,intent(in) :: call_id ! flag specifying where this is called ! from real(r8) :: h - real(r8) :: target_bleaf real(r8) :: target_lai + real(r8) :: target_bleaf - call bleaf(dbh,pft,canopy_trim,target_bleaf) + ! Assume fully flushed leaves, so stem area index is independent on leaf phenology. + ! SAI can be downscaled by stem phenology (typically applied to grasses only). + call bleaf(dbh, pft, crowndamage, canopy_trim, 1.0_r8, target_bleaf) - target_lai = tree_lai( target_bleaf, pft, c_area, nplant, cl, canopy_lai, vcmax25top) + target_lai = tree_lai(target_bleaf, pft, c_area, nplant, cl,& + canopy_lai, vcmax25top) - tree_sai = prt_params%allom_sai_scaler(pft) * target_lai + tree_sai = elongf_stem * prt_params%allom_sai_scaler(pft) * target_lai if( (treelai + tree_sai) > (sum(dinc_vai)) )then @@ -738,18 +803,18 @@ real(r8) function tree_sai( pft, dbh, canopy_trim, c_area, nplant, cl, & write(fates_log(),*) 'The leaf and stem are predicted for a cohort, maxed out the array size' write(fates_log(),*) 'lai: ',treelai write(fates_log(),*) 'sai: ',tree_sai - write(fates_log(),*) 'target_lai: ',target_lai write(fates_log(),*) 'lai+sai: ',treelai+tree_sai + write(fates_log(),*) 'target_bleaf: ', target_bleaf + write(fates_log(),*) 'area: ', c_area + write(fates_log(),*) 'target_lai: ',target_lai write(fates_log(),*) 'dinc_vai:',dinc_vai write(fates_log(),*) 'nlevleaf,sum(dinc_vai):',nlevleaf,sum(dinc_vai) write(fates_log(),*) 'pft: ',pft write(fates_log(),*) 'call id: ',call_id write(fates_log(),*) 'n: ',nplant - write(fates_log(),*) 'c_area: ',c_area write(fates_log(),*) 'dbh: ',dbh,' dbh_max: ',prt_params%allom_dbh_maxheight(pft) write(fates_log(),*) 'h: ',h write(fates_log(),*) 'canopy_trim: ',canopy_trim - write(fates_log(),*) 'target_bleaf: ',target_bleaf write(fates_log(),*) 'canopy layer: ',cl write(fates_log(),*) 'canopy_tlai: ',canopy_lai(:) write(fates_log(),*) 'vcmax25top: ',vcmax25top @@ -854,16 +919,21 @@ end function leafc_from_treelai ! Generic sapwood biomass interface ! ============================================================================ - subroutine bsap_allom(d,ipft,canopy_trim,sapw_area,bsap,dbsapdd) + subroutine bsap_allom(d,ipft,crowndamage,canopy_trim,elongf_stem, sapw_area,bsap,dbsapdd) + + use DamageMainMod , only : GetCrownReduction + use FatesParameterDerivedMod, only : param_derived real(r8),intent(in) :: d ! plant diameter [cm] integer(i4),intent(in) :: ipft ! PFT index + integer(i4),intent(in) :: crowndamage ! Crown damage class [1: undamaged, >1: damaged] real(r8),intent(in) :: canopy_trim + real(r8),intent(in) :: elongf_stem ! Elongation factor for stems (phenology) real(r8),intent(out) :: sapw_area ! cross section area of ! plant sapwood at reference [m2] - real(r8),intent(out) :: bsap ! plant leaf biomass [kgC] - real(r8),intent(out),optional :: dbsapdd ! change leaf biomass - ! per d [kgC/cm] + real(r8),intent(out) :: bsap ! sapwood biomass [kgC] + real(r8),intent(out),optional :: dbsapdd ! change in sapwood biomass + ! per d [kgC/cm] real(r8) :: h ! Plant height [m] real(r8) :: dhdd @@ -877,10 +947,18 @@ subroutine bsap_allom(d,ipft,canopy_trim,sapw_area,bsap,dbsapdd) ! than some specified proportion of woody biomass ! should not trip, and only in small plants + real(r8) :: crown_reduction ! amount that crown is damage by + real(r8) :: agb_frac ! aboveground biomass fraction + real(r8) :: branch_frac ! fraction of aboveground woody biomass in branches + ! Constrain sapwood so that its above ground portion be no larger than ! X% of total woody/fibrous (ie non leaf/fineroot) tissues real(r8),parameter :: max_frac = 0.95_r8 + agb_frac = prt_params%allom_agb_frac(ipft) + branch_frac = param_derived%branch_frac(ipft) + + select case(int(prt_params%allom_smode(ipft))) ! --------------------------------------------------------------------- ! Currently only one sapwood allometry model. the slope @@ -889,13 +967,33 @@ subroutine bsap_allom(d,ipft,canopy_trim,sapw_area,bsap,dbsapdd) case(1) ! linearly related to leaf area based on target leaf biomass ! and slatop (no provisions for slamax) + ! We assume fully flushed leaves, so sapwood biomass is independent of leaf phenology + ! (but could be modulated by stem phenology). call h_allom(d,ipft,h,dhdd) - call bleaf(d,ipft,canopy_trim,bl,dbldd) + call bleaf(d,ipft,1,canopy_trim,1.0_r8,bl,dbldd) call bsap_ltarg_slatop(d,h,dhdd,bl,dbldd,ipft,sapw_area,bsap,dbsapdd) + ! if trees are damaged reduce bsap by percent crown loss * + ! fraction of biomass that would be in branches (pft specific) + if(crowndamage > 1)then + + call GetCrownReduction(crowndamage, crown_reduction) + bsap = elongf_stem * ( bsap - (bsap * agb_frac * branch_frac * crown_reduction) ) + if(present(dbsapdd))then + dbsapdd = elongf_stem * & + ( dbsapdd - (dbsapdd * agb_frac * branch_frac * crown_reduction) ) + end if + else + bsap = elongf_stem * bsap + if (present(dbsapdd)) then + dbsapdd = elongf_stem * dbsapdd + end if + end if + + ! Perform a capping/check on total woody biomass - call bagw_allom(d,ipft,bagw,dbagwdd) - call bbgw_allom(d,ipft,bbgw,dbbgwdd) + call bagw_allom(d,ipft,crowndamage, elongf_stem, bagw,dbagwdd) + call bbgw_allom(d,ipft, elongf_stem,bbgw,dbbgwdd) ! Force sapwood to be less than a maximum fraction of total biomass ! We omit the sapwood area from this calculation @@ -924,19 +1022,24 @@ end subroutine bsap_allom ! non-fineroot biomass. ! ============================================================================ - subroutine bbgw_allom(d,ipft,bbgw,dbbgwdd) + subroutine bbgw_allom(d,ipft,elongf_stem,bbgw,dbbgwdd) - real(r8),intent(in) :: d ! plant diameter [cm] - integer(i4),intent(in) :: ipft ! PFT index - real(r8),intent(out) :: bbgw ! below ground woody biomass [kgC] - real(r8),intent(out),optional :: dbbgwdd ! change bbgw per diam [kgC/cm] + real(r8),intent(in) :: d ! plant diameter [cm] + integer(i4),intent(in) :: ipft ! PFT index + real(r8),intent(in) :: elongf_stem ! Elongation factor for stems (phenology) + real(r8),intent(out) :: bbgw ! below ground woody biomass [kgC] + real(r8),intent(out),optional :: dbbgwdd ! change bbgw per diam [kgC/cm] real(r8) :: bagw ! above ground biomass [kgC] real(r8) :: dbagwdd ! change in agb per diameter [kgC/cm] select case(int(prt_params%allom_cmode(ipft))) case(1) !"constant") - call bagw_allom(d,ipft,bagw,dbagwdd) + ! bbgw not affected by damage so use target allometry no damage. But note that bbgw + ! is affected by stem phenology (typically applied only to grasses). We do not need + ! to account for stem phenology in bbgw_const because bbgw will be proportional to + ! bagw, and bagw is downscaled due to stem phenology. + call bagw_allom(d,ipft,1, elongf_stem, bagw,dbagwdd) call bbgw_const(d,bagw,dbagwdd,ipft,bbgw,dbbgwdd) case DEFAULT write(fates_log(),*) 'An undefined coarse root allometry was specified: ', & @@ -951,18 +1054,23 @@ end subroutine bbgw_allom ! Fine root biomass allometry wrapper ! ============================================================================ - subroutine bfineroot(d,ipft,canopy_trim,bfr,dbfrdd) + subroutine bfineroot(d,ipft,canopy_trim,l2fr,elongf_fnrt,bfr,dbfrdd) ! ------------------------------------------------------------------------- ! This subroutine calculates the actual target fineroot biomass ! based on functions that may or may not have prognostic properties. ! ------------------------------------------------------------------------- - real(r8),intent(in) :: d ! plant diameter [cm] - integer(i4),intent(in) :: ipft ! PFT index - real(r8),intent(in) :: canopy_trim ! trimming function - real(r8),intent(out) :: bfr ! fine root biomass [kgC] - real(r8),intent(out),optional :: dbfrdd ! change leaf bio per diameter [kgC/cm] + real(r8),intent(in) :: d ! plant diameter [cm] + integer(i4),intent(in) :: ipft ! PFT index + real(r8),intent(in) :: canopy_trim ! trimming function + real(r8),intent(in) :: l2fr ! leaf to fineroot scaler + ! this is either a PFT parameter + ! constant (when no nutrient model) + ! or dynamic (with nutrient model) + real(r8),intent(in) :: elongf_fnrt ! Elongation factor for fine roots + real(r8),intent(out) :: bfr ! fine root biomass [kgC] + real(r8),intent(out),optional :: dbfrdd ! change leaf bio per diameter [kgC/cm] real(r8) :: blmax ! maximum leaf biomss per allometry real(r8) :: dblmaxdd @@ -974,18 +1082,20 @@ subroutine bfineroot(d,ipft,canopy_trim,bfr,dbfrdd) case(1) ! "constant proportionality with TRIMMED target bleaf" call blmax_allom(d,ipft,blmax,dblmaxdd) - call bfrmax_const(d,blmax,dblmaxdd,ipft,bfrmax,dbfrmaxdd) - bfr = bfrmax * canopy_trim + + bfr = blmax*l2fr*canopy_trim + if(present(dbfrdd))then - dbfrdd = dbfrmaxdd * canopy_trim + dbfrdd = dblmaxdd*l2fr * canopy_trim + end if case(2) ! "constant proportionality with UNTRIMMED target bleaf" call blmax_allom(d,ipft,blmax,dblmaxdd) - call bfrmax_const(d,blmax,dblmaxdd,ipft,bfrmax,dbfrmaxdd) - bfr = bfrmax + + bfr = blmax*l2fr if(present(dbfrdd))then - dbfrdd = dbfrmaxdd + dbfrdd = dblmaxdd*l2fr end if case DEFAULT @@ -994,7 +1104,15 @@ subroutine bfineroot(d,ipft,canopy_trim,bfr,dbfrdd) write(fates_log(),*) 'Aborting' call endrun(msg=errMsg(sourcefile, __LINE__)) end select - + + + ! Reduce fine-root biomass due to phenology. + bfr = elongf_fnrt * bfr + if (present(dbfrdd)) then + dbfrdd = elongf_fnrt * dbfrdd + end if + + return end subroutine bfineroot @@ -1003,30 +1121,35 @@ end subroutine bfineroot ! Storage biomass interface ! ============================================================================ - subroutine bstore_allom(d,ipft,canopy_trim,bstore,dbstoredd) + subroutine bstore_allom(d,ipft,crowndamage, canopy_trim,bstore,dbstoredd) real(r8),intent(in) :: d ! plant diameter [cm] integer(i4),intent(in) :: ipft ! PFT index + integer(i4),intent(in) :: crowndamage ! Crowndamage class [1: undamaged, >1: damaged] real(r8),intent(in) :: canopy_trim ! Crown trimming function [0-1] real(r8),intent(out) :: bstore ! allometric target storage [kgC] real(r8),intent(out),optional :: dbstoredd ! change storage per cm [kgC/cm] real(r8) :: bl ! Allometric target leaf biomass real(r8) :: dbldd ! Allometric target change in leaf biomass per cm + real(r8) :: blmax ! Allometric target leaf biomass (UNTRIMMED) + real(r8) :: dblmaxdd ! Allometric target change in leaf biomass per cm (UNTRIMMED) - ! TODO: allom_stmode needs to be added to the parameter file - associate( allom_stmode => prt_params%allom_stmode(ipft), & cushion => prt_params%cushion(ipft) ) select case(int(allom_stmode)) case(1) ! Storage is constant proportionality of trimmed maximum leaf - ! biomass (ie cushion * bleaf) - - call bleaf(d,ipft,canopy_trim,bl,dbldd) + ! biomass (ie cushion * bleaf), and thus leaf phenology is ignored. + call bleaf(d,ipft, crowndamage, canopy_trim, 1.0_r8, bl, dbldd) call bstore_blcushion(d,bl,dbldd,cushion,ipft,bstore,dbstoredd) - + + case(2) ! Storage is constant proportionality of untrimmed maximum leaf + ! biomass (ie cushion * bleaf_max) + call blmax_allom(d,ipft,blmax,dblmaxdd) + call bstore_blcushion(d,blmax,dblmaxdd,cushion,ipft,bstore,dbstoredd) + case DEFAULT write(fates_log(),*) 'An undefined fine storage allometry was specified: ', & allom_stmode @@ -1096,32 +1219,6 @@ subroutine bdead_allom(bagw,bbgw,bsap,ipft,bdead,dbagwdd,dbbgwdd,dbsapdd,dbdeadd return end subroutine bdead_allom - ! ============================================================================ - ! Specific bfrmax relationships - ! ============================================================================ - - subroutine bfrmax_const(d,blmax,dblmaxdd,ipft,bfrmax,dbfrmaxdd) - - - real(r8),intent(in) :: d ! plant diameter [cm] - real(r8),intent(in) :: blmax ! max leaf biomass [kgC] - real(r8),intent(in) :: dblmaxdd ! change in blmax per diam [kgC/cm] - integer(i4),intent(in) :: ipft ! PFT index - real(r8),intent(out) :: bfrmax ! max fine-root root biomass [kgC] - real(r8),intent(out),optional :: dbfrmaxdd ! change frmax bio per diam [kgC/cm] - - associate( l2fr => prt_params%allom_l2fr(ipft) ) - - bfrmax = blmax*l2fr - - ! dbfr/dd = dbfrmax/dblmax * dblmax/dd - if(present(dbfrmaxdd))then - dbfrmaxdd = dblmaxdd*l2fr - end if - - end associate - return - end subroutine bfrmax_const ! ============================================================================ ! Specific bbgw relationships @@ -1465,7 +1562,7 @@ subroutine d2h_poorter2006(d,p1,p2,p3,dbh_maxh,h,dhdd) ! "d2h_poorter2006" ! "d to height via Poorter et al. 2006, these routines use natively - ! asymtotic functions" + ! asymtotic functions (Weibull function)" ! ! Poorter et al calculated height diameter allometries over a variety of ! species in Bolivia, including those that could be classified in guilds @@ -1999,13 +2096,13 @@ subroutine CrownDepth(height,ft,crown_depth) ! Alternative Hypothesis: ! crown depth from Poorter, Bongers & Bongers - ! crown_depth = exp(-1.169_r8)*cCohort%hite**1.098_r8 + ! crown_depth = exp(-1.169_r8)*cCohort%height**1.098_r8 ! Alternative Hypothesis: ! Original FATES crown depth heigh used for hydraulics ! crown_depth = min(height,0.1_r8) - crown_depth = prt_params%crown(ft) * height + crown_depth = prt_params%crown_depth_frac(ft) * height return @@ -2018,7 +2115,8 @@ end subroutine CrownDepth ! ============================================================================= - subroutine carea_2pwr(dbh,spread,d2bl_p2,d2bl_ediff,d2ca_min,d2ca_max,c_area,inverse) + subroutine carea_2pwr(dbh,spread,d2bl_p2,d2bl_ediff,d2ca_min, & + d2ca_max,crowndamage,c_area,inverse) ! ============================================================================ ! Calculate area of ground covered by entire cohort. (m2) @@ -2031,11 +2129,13 @@ subroutine carea_2pwr(dbh,spread,d2bl_p2,d2bl_ediff,d2ca_min,d2ca_max,c_area,inv real(r8),intent(in) :: d2bl_ediff ! area difference factor in the diameter-bleaf allometry (exponent) real(r8),intent(in) :: d2ca_min ! minimum diameter to crown area scaling factor real(r8),intent(in) :: d2ca_max ! maximum diameter to crown area scaling factor + integer,intent(in) :: crowndamage ! crowndamage class [1: undamaged, >1: damaged] real(r8),intent(inout) :: c_area ! crown area for one plant [m2] logical,intent(in) :: inverse ! if true, calculate dbh from crown area rather than its reverse real(r8) :: crown_area_to_dbh_exponent real(r8) :: spreadterm ! Effective 2bh to crown area scaling factor + real(r8) :: crown_reduction ! default is to use the same exponent as the dbh to bleaf exponent so that per-plant ! canopy depth remains invariant during growth, but allowed to vary via the @@ -2058,7 +2158,17 @@ subroutine carea_2pwr(dbh,spread,d2bl_p2,d2bl_ediff,d2ca_min,d2ca_max,c_area,inv if ( .not. inverse) then c_area = spreadterm * dbh ** crown_area_to_dbh_exponent + + if(crowndamage > 1) then + call GetCrownReduction(crowndamage, crown_reduction) + c_area = c_area * (1.0_r8 - crown_reduction) + end if + else + if(crowndamage > 1) then + call GetCrownReduction(crowndamage, crown_reduction) + c_area = c_area/(1.0_r8 - crown_reduction) + end if dbh = (c_area / spreadterm) ** (1./crown_area_to_dbh_exponent) endif @@ -2326,30 +2436,30 @@ real(r8) function decay_coeff_kn(pft,vcmax25top) end function decay_coeff_kn ! ===================================================================================== - - - subroutine ForceDBH( ipft, canopy_trim, d, h, bdead, bl ) +subroutine ForceDBH( ipft, crowndamage, canopy_trim, elongf_leaf, elongf_stem, d, h, bdead, bl ) ! ========================================================================= ! This subroutine estimates the diameter based on either the structural biomass ! (if woody) or the leaf biomass using the allometric ! functions. Since allometry is specified with diameter - ! as the independant variable, we must do this through a search algorithm. + ! as the independent variable, we must do this through a search algorithm. ! Here, we keep searching until the difference between actual structure and ! the predicted structure based on the searched diameter is within a tolerance. ! ============================================================================ - - use FatesConstantsMod , only : calloc_abs_error + use FatesConstantsMod , only : calloc_abs_error ! Arguments integer(i4),intent(in) :: ipft ! PFT index + integer(i4),intent(in) :: crowndamage ! crowndamage [1: undamaged, >1: damaged] real(r8),intent(in) :: canopy_trim + real(r8),intent(in) :: elongf_leaf ! Elongation factor: leaves (phenology) + real(r8),intent(in) :: elongf_stem ! Elongation factor: stem (phenology) real(r8),intent(inout) :: d ! plant diameter [cm] real(r8),intent(out) :: h ! plant height real(r8),intent(in),optional :: bdead ! Structural biomass real(r8),intent(in),optional :: bl ! Leaf biomass - + ! Locals real(r8) :: bt_sap,dbt_sap_dd ! target sap wood at current d @@ -2368,18 +2478,20 @@ subroutine ForceDBH( ipft, canopy_trim, d, h, bdead, bl ) integer :: counter real(r8), parameter :: step_frac0 = 0.9_r8 integer, parameter :: max_counter = 200 + ! Do reduce "if" calls, we break this call into two parts - if ( int(prt_params%woody(ipft)) == itrue ) then + if ( prt_params%woody(ipft) == itrue ) then if(.not.present(bdead)) then write(fates_log(),*) 'woody plants must use structure for dbh reset' call endrun(msg=errMsg(sourcefile, __LINE__)) end if - call bsap_allom(d,ipft,canopy_trim,at_sap,bt_sap,dbt_sap_dd) - call bagw_allom(d,ipft,bt_agw,dbt_agw_dd) - call bbgw_allom(d,ipft,bt_bgw,dbt_bgw_dd) + call bsap_allom(d,ipft,crowndamage, canopy_trim, elongf_stem,at_sap,bt_sap,dbt_sap_dd) + call bagw_allom(d,ipft,crowndamage, elongf_stem, bt_agw,dbt_agw_dd) + call bbgw_allom(d,ipft, elongf_stem,bt_bgw,dbt_bgw_dd) + call bdead_allom(bt_agw,bt_bgw, bt_sap, ipft, bt_dead, dbt_agw_dd, & dbt_bgw_dd, dbt_sap_dd, dbt_dead_dd) @@ -2394,13 +2506,16 @@ subroutine ForceDBH( ipft, canopy_trim, d, h, bdead, bl ) dd = step_frac*(bdead-bt_dead)/dbt_dead_dd d_try = d + dd - call bsap_allom(d_try,ipft,canopy_trim,at_sap,bt_sap,dbt_sap_dd) - call bagw_allom(d_try,ipft,bt_agw,dbt_agw_dd) - call bbgw_allom(d_try,ipft,bt_bgw,dbt_bgw_dd) + call bsap_allom(d_try,ipft,crowndamage, canopy_trim, elongf_stem,at_sap, & + bt_sap,dbt_sap_dd) + call bagw_allom(d_try,ipft,crowndamage, elongf_stem, bt_agw,dbt_agw_dd) + call bbgw_allom(d_try,ipft, elongf_stem, bt_bgw,dbt_bgw_dd) + + call bdead_allom(bt_agw,bt_bgw, bt_sap, ipft, bt_dead_try, dbt_agw_dd, & dbt_bgw_dd, dbt_sap_dd, dbt_dead_dd_try) - ! Prevent overshooting + ! Prevent overshooting if(bt_dead_try > (bdead+calloc_abs_error)) then step_frac = step_frac*0.5_r8 else @@ -2424,7 +2539,7 @@ subroutine ForceDBH( ipft, canopy_trim, d, h, bdead, bl ) call endrun(msg=errMsg(sourcefile, __LINE__)) end if - call bleaf(d,ipft,canopy_trim,bt_leaf,dbt_leaf_dd) + call bleaf(d,ipft,crowndamage,canopy_trim,elongf_leaf,bt_leaf,dbt_leaf_dd) counter = 0 step_frac = step_frac0 @@ -2433,7 +2548,7 @@ subroutine ForceDBH( ipft, canopy_trim, d, h, bdead, bl ) dd = step_frac*(bl-bt_leaf)/dbt_leaf_dd d_try = d + dd - call bleaf(d_try,ipft,canopy_trim,bt_leaf_try,dbt_leaf_dd_try) + call bleaf(d_try,ipft,crowndamage,canopy_trim,elongf_stem,bt_leaf_try,dbt_leaf_dd_try) ! Prevent overshooting if(bt_leaf_try > (bl+calloc_abs_error)) then @@ -2454,9 +2569,16 @@ subroutine ForceDBH( ipft, canopy_trim, d, h, bdead, bl ) end if call h_allom(d,ipft,h) - if(counter>10)then + if(counter>20)then write(fates_log(),*) 'dbh counter: ',counter,' is woody: ',& - int(prt_params%woody(ipft))==itrue + (prt_params%woody(ipft) == itrue) + + if(prt_params%woody(ipft)==itrue)then + warn_msg = 'dbh counter: '//trim(I2S(counter))//' is woody' + else + warn_msg = 'dbh counter: '//trim(I2S(counter))//' is not woody' + end if + call FatesWarn(warn_msg,index=3) end if @@ -2504,4 +2626,6 @@ subroutine cspline(x1,x2,y1,y2,dydx1,dydx2,x,y,dydx) return end subroutine cspline + + end module FatesAllometryMod diff --git a/biogeochem/FatesCohortMod.F90 b/biogeochem/FatesCohortMod.F90 new file mode 100644 index 0000000000..7c1b586a71 --- /dev/null +++ b/biogeochem/FatesCohortMod.F90 @@ -0,0 +1,1090 @@ +module FatesCohortMod + + use FatesConstantsMod, only : r8 => fates_r8 + use FatesConstantsMod, only : fates_unset_int + use FatesConstantsMod, only : ifalse, itrue + use FatesConstantsMod, only : nearzero + use FatesConstantsMod, only : ican_upper, ican_ustory + use EDParamsMod, only : nlevleaf + use EDParamsMod, only : nclmax + use FatesGlobals, only : endrun => fates_endrun + use FatesGlobals, only : fates_log + use PRTGenericMod, only : max_nleafage + use PRTGenericMod, only : prt_vartypes + use PRTGenericMod, only : prt_carbon_allom_hyp + use PRTGenericMod, only : prt_cnp_flex_allom_hyp + use PRTGenericMod, only : leaf_organ, fnrt_organ, sapw_organ + use PRTGenericMod, only : repro_organ, store_organ, struct_organ + use PRTGenericMod, only : carbon12_element + use PRTParametersMod, only : prt_params + use FatesParameterDerivedMod, only : param_derived + use FatesHydraulicsMemMod, only : ed_cohort_hydr_type + use FatesInterfaceTypesMod, only : hlm_parteh_mode + use FatesInterfaceTypesMod, only : hlm_use_sp + use FatesInterfaceTypesMod, only : hlm_use_planthydro + use FatesInterfaceTypesMod, only : nleafage + use EDPftvarcon, only : EDPftvarcon_inst + use FatesSizeAgeTypeIndicesMod, only : sizetype_class_index + use FatesSizeAgeTypeIndicesMod, only : coagetype_class_index + use FatesAllometryMod, only : carea_allom, tree_lai, tree_sai + use PRTAllometricCarbonMod, only : ac_bc_inout_id_dbh, ac_bc_inout_id_netdc + use PRTAllometricCarbonMod, only : ac_bc_in_id_cdamage, ac_bc_in_id_pft + use PRTAllometricCarbonMod, only : ac_bc_in_id_ctrim, ac_bc_in_id_lstat + use PRTAllometricCarbonMod, only : ac_bc_in_id_efleaf + use PRTAllometricCarbonMod, only : ac_bc_in_id_effnrt + use PRTAllometricCarbonMod, only : ac_bc_in_id_efstem + use PRTAllometricCNPMod, only : acnp_bc_in_id_pft, acnp_bc_in_id_ctrim + use PRTAllometricCNPMod, only : acnp_bc_in_id_lstat, acnp_bc_in_id_netdc + use PRTAllometricCNPMod, only : acnp_bc_in_id_netdc, acnp_bc_in_id_nc_repro + use PRTAllometricCNPMod, only : acnp_bc_in_id_pc_repro, acnp_bc_in_id_cdamage + use PRTAllometricCNPMod, only : acnp_bc_inout_id_dbh, acnp_bc_inout_id_resp_excess + use PRTAllometricCNPMod, only : acnp_bc_inout_id_l2fr, acnp_bc_inout_id_cx_int + use PRTAllometricCNPMod, only : acnp_bc_inout_id_emadcxdt, acnp_bc_inout_id_cx0 + use PRTAllometricCNPMod, only : acnp_bc_inout_id_netdn, acnp_bc_inout_id_netdp + use PRTAllometricCNPMod, only : acnp_bc_out_id_cefflux, acnp_bc_out_id_nefflux + use PRTAllometricCNPMod, only : acnp_bc_out_id_pefflux, acnp_bc_out_id_limiter + use PRTAllometricCNPMod, only : acnp_bc_in_id_efleaf + use PRTAllometricCNPMod, only : acnp_bc_in_id_effnrt + use PRTAllometricCNPMod, only : acnp_bc_in_id_efstem + + use shr_infnan_mod, only : nan => shr_infnan_nan, assignment(=) + use shr_log_mod, only : errMsg => shr_log_errMsg + + implicit none + private + + ! PARAMETERS + character(len=*), parameter, private :: sourcefile = __FILE__ + + ! FATES COHORT TYPE + type, public :: fates_cohort_type + + ! POINTERS + type (fates_cohort_type), pointer :: taller => null() ! pointer to next tallest cohort + type (fates_cohort_type), pointer :: shorter => null() ! pointer to next shorter cohort + + !--------------------------------------------------------------------------- + + ! Multi-species, multi-organ Plant Reactive Transport (PRT) + ! Contains carbon and nutrient state variables for various plant organs + class(prt_vartypes), pointer :: prt + real(r8) :: l2fr ! leaf to fineroot biomass ratio [kg root / kg leaf] + ! (this is constant in carbon only simulationss, and + ! is set by the allom_l2fr parameter). + ! For nutrient enabled simulations, this is dynamic. + ! In cold-start simulations, the allom_l2fr + ! parameter sets the starter value. + + !--------------------------------------------------------------------------- + + ! VEGETATION STRUCTURE + + integer :: pft ! pft index + real(r8) :: n ! number of individuals in cohort per 'area' (10000m2 default) [/m2] + real(r8) :: dbh ! diameter at breast height [cm] + real(r8) :: coage ! age [years] + real(r8) :: height ! height [m] + integer :: indexnumber ! unique number for each cohort (within clump?) + integer :: canopy_layer ! canopy status of cohort [1 = canopy, 2 = understorey, etc.] + real(r8) :: canopy_layer_yesterday ! recent canopy status of cohort [1 = canopy, 2 = understorey, etc.] + ! real to be conservative during fusion + integer :: crowndamage ! crown damage class of the cohort [1 = undamaged, >1 = damaged] + real(r8) :: g_sb_laweight ! total conductance (stomata + boundary layer) of the cohort + ! weighted by its leaf area [m/s]*[m2] + real(r8) :: canopy_trim ! fraction of the maximum leaf biomass that we are targeting [0-1] + real(r8) :: leaf_cost ! how much does it cost to maintain leaves [kgC/m2/year] + real(r8) :: excl_weight ! how much of this cohort is demoted each year, as a proportion of all cohorts + real(r8) :: prom_weight ! how much of this cohort is promoted each year, as a proportion of all cohorts + integer :: nv ! number of leaf layers + integer :: status_coh ! growth status of plant [2 = leaves on , 1 = leaves off] + real(r8) :: efleaf_coh ! elongation factor for leaves [fraction] + real(r8) :: effnrt_coh ! elongation factor for fine roots [fraction] + real(r8) :: efstem_coh ! elongation factor for stem [fraction] + ! for all the elongation factors, 0 means fully abscissed, and + ! 1 means fully flushed. + real(r8) :: c_area ! areal extent of canopy [m2] + real(r8) :: treelai ! lai of an individual within cohort leaf area [m2 leaf area/m2 crown area] + real(r8) :: treesai ! stem area index of an individual within cohort [m2 stem area/m2 crown area] + logical :: isnew ! flag to signify a new cohort - new cohorts have not experienced + ! npp or mortality and should therefore not be fused or averaged + integer :: size_class ! index that indicates which diameter size bin the cohort currently resides in + ! this is used for history output. We maintain this in the main cohort memory + ! because we don't want to continually re-calculate the cohort's position when + ! performing size diagnostics at high-frequency calls + integer :: coage_class ! index that indicates which age bin the cohort currently resides in + ! (used for history output) + integer :: size_by_pft_class ! index that indicates the cohorts position of the joint size-class x functional + ! type classification. We also maintain this in the main cohort memory + ! because we don't want to continually re-calculate the cohort's position when + ! performing size diagnostics at high-frequency calls + integer :: coage_by_pft_class ! index that indicates the cohorts position of the join cohort age class x PFT + integer :: size_class_lasttimestep ! size class of the cohort at the last time step + + !--------------------------------------------------------------------------- + + ! CARBON AND NUTRIENT FLUXES + + ! -------------------------------------------------------------------------- + ! NPP, GPP and RESP: Instantaneous, accumulated and accumulated-hold types* + ! + ! _tstep: The instantaneous estimate that is calculated at each rapid plant biophysics + ! time-step (ie photosynthesis, sub-hourly) [kgC/indiv/timestep] + ! _acc: The accumulation of the _tstep variable from the beginning to ending of + ! the dynamics time-scale. This variable is zero'd during initialization and + ! after the dynamics call-sequence is completed. [kgC/indiv/day] + ! _acc_hold: While _acc is zero'd after the dynamics call sequence and then integrated, + ! _acc_hold "holds" the integrated value until the next time dynamics is + ! called. This is necessary for restarts. This variable also has units + ! converted to a useful rate [kgC/indiv/yr] + ! -------------------------------------------------------------------------- + + real(r8) :: gpp_tstep ! Gross Primary Production (see above *) + real(r8) :: gpp_acc + real(r8) :: gpp_acc_hold + + real(r8) :: npp_tstep ! Net Primary Production (see above *) + real(r8) :: npp_acc + real(r8) :: npp_acc_hold + + real(r8) :: resp_tstep ! Autotrophic respiration (see above *) + real(r8) :: resp_acc + real(r8) :: resp_acc_hold + + real(r8) :: c13disc_clm ! carbon 13 discrimination in new synthesized carbon at each indiv/timestep [ppm] + real(r8) :: c13disc_acc ! carbon 13 discrimination in new synthesized carbon at each indiv/day + ! at the end of a day [ppm] + + ! The following four biophysical rates are assumed to be at the canopy top, at reference temp 25degC, + ! and based on the leaf age weighted average of the PFT parameterized values. + ! The last condition is why it is dynamic and tied to the cohort + + real(r8) :: vcmax25top ! maximum carboxylation at canopy top and 25degC [umol CO2/m2/s] + real(r8) :: jmax25top ! maximum electron transport rate at canopy top and 25degC [umol electrons/m2/s] + real(r8) :: tpu25top ! triose phosphate utilization rate at canopy top and 25degC [umol CO2/m2/s] + real(r8) :: kp25top ! initial slope of CO2 response curve (C4 plants) at 25C + + real(r8) :: ts_net_uptake(nlevleaf) ! net uptake of leaf layers [kgC/m2/timestep] + real(r8) :: year_net_uptake(nlevleaf) ! net uptake of leaf layers [kgC/m2/year] + + ! used for CNP + integer :: cnp_limiter ! which element is limiting growth [0 = none, 1 = C, 2 = N, 3 = P] + real(r8) :: cx_int ! time integration of the log of the relative carbon storage over relative nutrient + real(r8) :: ema_dcxdt ! derivative of the log of the relative carbon storage over relative nutrient + real(r8) :: cx0 ! value on the previous time-step of log of the relative carbon storage over + ! relative nutrient + real(r8) :: nc_repro ! N:C ratio of a new recruit, used also for defining reproductive stoich + real(r8) :: pc_repro ! P:C ratio of a new recruit + + ! Nutrient Fluxes (if N, P, etc. are turned on) + real(r8) :: daily_nh4_uptake ! integrated daily uptake of mineralized ammonium through competitive acquisition + ! in soil [kgN/plant/day] + real(r8) :: daily_no3_uptake ! integrated daily uptake of mineralized nitrate through competitive acquisition + ! in soil [kgN/plant/day] + + real(r8) :: sym_nfix_daily ! accumulated symbiotic N fixation from the roots [kgN/indiv/day] + real(r8) :: sym_nfix_tstep ! symbiotic N fixation from the roots for the time-step [kgN/indiv/timestep] + + real(r8) :: daily_n_gain ! sum of fixation and uptake of mineralized NH4/NO3 in solution as well as + ! symbiotic fixation + real(r8) :: daily_p_gain ! integrated daily uptake of mineralized P through competitive acquisition + ! in soil [kgP/plant/day] + + real(r8) :: daily_c_efflux ! daily mean efflux of excess carbon from roots into labile pool [kgC/plant/day] + real(r8) :: daily_n_efflux ! daily mean efflux of excess nitrogen from roots into labile pool [kgN/plant/day] + real(r8) :: daily_p_efflux ! daily mean efflux of excess phophorus from roots into labile pool [kgP/plant/day] + + real(r8) :: daily_n_demand ! daily amount of N demanded by the plant [kgN/plant/day] + real(r8) :: daily_p_demand ! daily amount of P demanded by the plant [kgN/plant/day] + + real(r8) :: seed_prod ! diagnostic seed production rate [kgC/plant/day] + + !--------------------------------------------------------------------------- + + ! RESPIRATION COMPONENTS + real(r8) :: rdark ! dark respiration [kgC/indiv/s] + real(r8) :: resp_g_tstep ! growth respiration [kgC/indiv/timestep] + real(r8) :: resp_m ! maintenance respiration [kgC/indiv/timestep] + real(r8) :: resp_m_unreduced ! diagnostic-only unreduced maintenance respiration [kgC/indiv/timestep] + real(r8) :: resp_excess ! respiration of excess carbon [kgC/indiv/day] + real(r8) :: livestem_mr ! aboveground live stem maintenance respiration [kgC/indiv/s] + real(r8) :: livecroot_mr ! belowground live stem maintenance respiration [kgC/indiv/s] + real(r8) :: froot_mr ! live fine root maintenance respiration [kgC/indiv/s] + + !--------------------------------------------------------------------------- + + ! DAMAGE + real(r8) :: branch_frac ! fraction of aboveground woody biomass in branches [0-1] + + !--------------------------------------------------------------------------- + + ! MORTALITY + real(r8) :: dmort ! proportional mortality rate [/year] + + ! Mortality Rate Partitions + real(r8) :: bmort ! background mortality rate [indiv/year] + real(r8) :: cmort ! carbon starvation mortality rate [indiv/year] + real(r8) :: hmort ! hydraulic failure mortality rate [indiv/year] + real(r8) :: frmort ! freezing mortality rate [indiv/year] + real(r8) :: smort ! senesence mortality [indiv/year] + real(r8) :: asmort ! age senescence mortality [indiv/year] + real(r8) :: dgmort ! damage mortality [indiv/year] + + ! Logging Mortality Rate + ! Yi Xu & M. Huang + real(r8) :: lmort_direct ! directly logging rate [fraction/logging activity] + real(r8) :: lmort_collateral ! collaterally damaged rate [fraction/logging activity] + real(r8) :: lmort_infra ! mechanically damaged rate [fraction/logging activity] + real(r8) :: l_degrad ! rate of trees that are not killed but suffer from forest degradation + ! (i.e. they are moved to newly-anthro-disturbed secondary + ! forest patch) [fraction/logging activity] + + !--------------------------------------------------------------------------- + + ! NITROGEN POOLS + ! -------------------------------------------------------------------------- + ! Nitrogen pools are not prognostic in the current implementation. + ! They are diagnosed during photosynthesis using a simple C2N parameter. + ! Local values are used in that routine. + ! -------------------------------------------------------------------------- + + !--------------------------------------------------------------------------- + + ! GROWTH DERIVIATIVES + real(r8) :: dndt ! time derivative of cohort size [n/year] + real(r8) :: dhdt ! time derivative of height [m/year] + real(r8) :: ddbhdt ! time derivative of dbh [cm/year] + real(r8) :: dbdeaddt ! time derivative of dead biomass [kgC/year] + + !--------------------------------------------------------------------------- + + ! FIRE + real(r8) :: fraction_crown_burned ! proportion of crown affected by fire [0-1] + real(r8) :: cambial_mort ! probability that trees dies due to cambial charring [0-1] + ! (conditional on the tree being subjected to the fire) + real(r8) :: crownfire_mort ! probability of tree post-fire mortality from crown scorch [0-1] + ! (conditional on the tree being subjected to the fire) + real(r8) :: fire_mort ! post-fire mortality from cambial and crown damage assuming two are independent [0-1] + + !--------------------------------------------------------------------------- + + ! HYDRAULICS + type(ed_cohort_hydr_type), pointer :: co_hydr ! all cohort hydraulics data, see FatesHydraulicsMemMod.F90 + + contains + + procedure :: Init + procedure :: NanValues + procedure :: ZeroValues + procedure :: Create + procedure :: Copy + procedure :: FreeMemory + procedure :: CanUpperUnder + procedure :: InitPRTBoundaryConditions + procedure :: UpdateCohortBioPhysRates + procedure :: Dump + + end type fates_cohort_type + + contains + + !=========================================================================== + + subroutine Init(this, prt) + ! + ! DESCRIPTION: + ! Create new cohort and set default values for all variables + ! + + ! ARGUMENTS: + class(fates_cohort_type), intent(inout) :: this + class(prt_vartypes), intent(inout), pointer :: prt ! allocated PARTEH object + + call this%NanValues() ! make everything in the cohort not-a-number + call this%ZeroValues() ! zero things that need to be zeroed + + ! point to the PARTEH object + this%prt => prt + + ! The PARTEH cohort object should be allocated and already + ! initialized in this routine. + call this%prt%CheckInitialConditions() + + ! new cohorts do not have mortality rates, nor have they moved any + ! carbon when they are created. They will bias our statistics + ! until they have experienced a full day. We need a newly recruited flag. + ! This flag will be set to false after it has experienced + ! growth, disturbance and mortality. + this%isnew = .true. + + end subroutine Init + + !=========================================================================== + + subroutine NanValues(this) + ! + ! DESCRIPTION: + ! make all the cohort variables NaN or unset so they aren't used before defined + ! + + ! ARGUMENTS: + class(fates_cohort_type), intent(inout) :: this + + ! set pointers to null + this%taller => null() + this%shorter => null() + this%prt => null() + this%co_hydr => null() + nullify(this%taller) + nullify(this%shorter) + nullify(this%prt) + nullify(this%co_hydr) + + ! VEGETATION STRUCTURE + this%l2fr = nan + this%pft = fates_unset_int + this%n = nan + this%dbh = nan + this%coage = nan + this%height = nan + this%indexnumber = fates_unset_int + this%canopy_layer = fates_unset_int + this%canopy_layer_yesterday = nan + this%crowndamage = fates_unset_int + this%g_sb_laweight = nan + this%canopy_trim = nan + this%leaf_cost = nan + this%excl_weight = nan + this%prom_weight = nan + this%nv = fates_unset_int + this%status_coh = fates_unset_int + this%efleaf_coh = nan + this%effnrt_coh = nan + this%efstem_coh = nan + this%c_area = nan + this%treelai = nan + this%treesai = nan + this%isnew = .false. + this%size_class = fates_unset_int + this%coage_class = fates_unset_int + this%size_by_pft_class = fates_unset_int + this%coage_by_pft_class = fates_unset_int + this%size_class_lasttimestep = fates_unset_int + + ! CARBON AND NUTRIENT FLUXES + this%gpp_tstep = nan + this%gpp_acc = nan + this%gpp_acc_hold = nan + this%npp_tstep = nan + this%npp_acc = nan + this%npp_acc_hold = nan + this%resp_tstep = nan + this%resp_acc = nan + this%resp_acc_hold = nan + this%c13disc_clm = nan + this%c13disc_acc = nan + this%vcmax25top = nan + this%jmax25top = nan + this%tpu25top = nan + this%kp25top = nan + this%year_net_uptake(:) = nan + this%ts_net_uptake(:) = nan + this%cnp_limiter = fates_unset_int + this%cx_int = nan + this%ema_dcxdt = nan + this%cx0 = nan + this%nc_repro = nan + this%pc_repro = nan + this%daily_nh4_uptake = nan + this%daily_no3_uptake = nan + this%sym_nfix_daily = nan + this%sym_nfix_tstep = nan + this%daily_n_gain = nan + this%daily_p_gain = nan + this%daily_c_efflux = nan + this%daily_n_efflux = nan + this%daily_p_efflux = nan + this%daily_n_demand = nan + this%daily_p_demand = nan + this%seed_prod = nan + + ! RESPIRATION COMPONENTS + this%rdark = nan + this%resp_g_tstep = nan + this%resp_m = nan + this%resp_m_unreduced = nan + this%resp_excess = nan + this%livestem_mr = nan + this%livecroot_mr = nan + this%froot_mr = nan + + ! DAMAGE + this%branch_frac = nan + + ! MORTALITY + this%dmort = nan + this%bmort = nan + this%cmort = nan + this%frmort = nan + this%smort = nan + this%asmort = nan + this%dgmort = nan + this%lmort_direct = nan + this%lmort_collateral = nan + this%lmort_infra = nan + this%l_degrad = nan + + ! GROWTH DERIVATIVES + this%dndt = nan + this%dhdt = nan + this%ddbhdt = nan + this%dbdeaddt = nan + + ! FIRE + this%fraction_crown_burned = nan + this%cambial_mort = nan + this%crownfire_mort = nan + this%fire_mort = nan + + end subroutine NanValues + + !=========================================================================== + + subroutine ZeroValues(this) + ! + ! DESCRIPTION: + ! Zero variables that need to be accounted for if this cohort is altered + ! before they are defined. + ! + ! ARGUMENTS + class(fates_cohort_type), intent(inout) :: this + + this%g_sb_laweight = 0._r8 + + this%leaf_cost = 0._r8 + this%excl_weight = 0._r8 + this%prom_weight = 0._r8 + this%nv = 0 + this%status_coh = 0 + this%efleaf_coh = 0.0_r8 + this%effnrt_coh = 0.0_r8 + this%efstem_coh = 0.0_r8 + + this%treesai = 0._r8 + this%size_class = 1 + this%coage_class = 1 + + this%size_class_lasttimestep = 0 + this%gpp_tstep = 0._r8 + this%gpp_acc = 0._r8 + this%gpp_acc_hold = 0._r8 + this%npp_tstep = 0._r8 + this%npp_acc = 0._r8 + this%npp_acc_hold = 0._r8 + this%resp_tstep = 0._r8 + this%resp_acc = 0._r8 + this%resp_acc_hold = 0._r8 + this%c13disc_clm = 0._r8 + this%c13disc_acc = 0._r8 + + this%ts_net_uptake(:) = 0._r8 + this%year_net_uptake(:) = 999._r8 ! this needs to be 999, or trimming of new cohorts will break. + + this%daily_nh4_uptake = 0._r8 + this%daily_no3_uptake = 0._r8 + + ! fixation is also integrated over the course of the day and must be + ! zeroed upon creation and after plant resource allocation + this%sym_nfix_daily = 0._r8 + this%daily_n_gain = 0._r8 + this%daily_p_gain = 0._r8 + + ! daily nutrient fluxes are INTEGRATED over the course of the day. + ! These variables MUST be zerod upon creation AND after allocation. + ! These variables exist in carbon-only mode but are not used. + this%daily_c_efflux = 0._r8 + this%daily_n_efflux = 0._r8 + this%daily_p_efflux = 0._r8 + + ! initialize these as negative + this%daily_n_demand = -9._r8 + this%daily_p_demand = -9._r8 + this%seed_prod = 0._r8 + this%rdark = 0._r8 + this%resp_g_tstep = 0._r8 + this%resp_m = 0._r8 + this%resp_m_unreduced = 0._r8 + this%resp_excess = 0._r8 + this%livestem_mr = 0._r8 + this%livecroot_mr = 0._r8 + this%froot_mr = 0._r8 + + this%dmort = 0._r8 + this%lmort_direct = 0._r8 + this%lmort_collateral = 0._r8 + this%lmort_infra = 0._r8 + this%l_degrad = 0._r8 + this%fraction_crown_burned = 0._r8 + this%cambial_mort = 0._r8 + this%crownfire_mort = 0._r8 + this%fire_mort = 0._r8 + + end subroutine ZeroValues + + !=========================================================================== + + subroutine Create(this, prt, pft, nn, height, coage, dbh, status, & + ctrim, carea, clayer, crowndamage, spread, can_tlai, elongf_leaf, & + elongf_fnrt, elongf_stem) + ! + ! DESCRIPTION: + ! set up values for a newly created cohort + + ! ARGUMENTS + class(fates_cohort_type), intent(inout), target :: this ! cohort object + class(prt_vartypes), intent(inout), pointer :: prt ! The allocated PARTEH object + integer, intent(in) :: pft ! cohort Plant Functional Type + integer, intent(in) :: crowndamage ! cohort damage class + integer, intent(in) :: clayer ! canopy status of cohort [canopy/understory] + integer, intent(in) :: status ! growth status of cohort [leaves on/off] + real(r8), intent(in) :: nn ! number of individuals in cohort [/m2] + real(r8), intent(in) :: height ! cohort height [m] + real(r8), intent(in) :: coage ! cohort age [yr] + real(r8), intent(in) :: dbh ! cohort diameter at breat height [cm] + real(r8), intent(in) :: ctrim ! fraction of the maximum leaf biomass + real(r8), intent(in) :: spread ! how spread crowns are in horizontal space + real(r8), intent(in) :: carea ! area of cohort, for SP mode [m2] + real(r8), intent(in) :: can_tlai(nclmax) ! patch-level total LAI of each leaf layer + real(r8), intent(in) :: elongf_leaf ! leaf elongation factor [fraction] + real(r8), intent(in) :: elongf_fnrt ! fine-root "elongation factor" [fraction] + real(r8), intent(in) :: elongf_stem ! stem "elongation factor" [fraction] + + ! LOCAL VARIABLES: + integer :: iage ! loop counter for leaf age classes + real(r8) :: leaf_c ! total leaf carbon [kgC] + + ! initialize cohort + call this%Init(prt) + + ! set values + this%pft = pft + this%crowndamage = crowndamage + this%canopy_layer = clayer + this%canopy_layer_yesterday = real(clayer, r8) + this%status_coh = status + this%n = nn + this%height = height + this%dbh = dbh + this%coage = coage + this%canopy_trim = ctrim + this%efleaf_coh = elongf_leaf + this%effnrt_coh = elongf_fnrt + this%efstem_coh = elongf_stem + + ! This routine may be called during restarts, and at this point in the call sequence + ! the actual cohort data is unknown, as this is really only used for allocation + ! In these cases, testing if things like biomass are reasonable is premature + ! However, in this part of the code, we will pass in nominal values for size, number and type + if (this%dbh <= 0._r8 .or. this%n == 0._r8 .or. this%pft == 0) then + write(fates_log(),*) 'FATES: something is zero in cohort%Create', & + this%dbh, this%n, this%pft + call endrun(msg=errMsg(sourcefile, __LINE__)) + endif + + ! Initialize the leaf to fineroot biomass ratio. + ! For C-only, this will stay constant, for nutrient-enabled this will be + ! dynamic. In both cases, new cohorts are initialized with the minimum. + ! This works in the nutrient enabled case because cohorts are also + ! initialized with full stores, which match with minimum fineroot biomass + this%l2fr = prt_params%allom_l2fr(pft) + + if (hlm_parteh_mode .eq. prt_cnp_flex_allom_hyp) then + this%cx_int = 0._r8 ! Assume balanced N,P/C stores ie log(1) = 0 + this%cx0 = 0._r8 ! Assume balanced N,P/C stores ie log(1) = 0 + this%ema_dcxdt = 0._r8 ! Assume unchanged dCX/dt + this%cnp_limiter = 0 ! Assume limitations are unknown + end if + + ! This sets things like vcmax25top, that depend on the leaf age fractions + ! (which are defined by PARTEH) + call this%UpdateCohortBioPhysRates() + + ! calculate size classes + call sizetype_class_index(this%dbh, this%pft, this%size_class, & + this%size_by_pft_class) + + ! If cohort age tracking is off we call this here once, just so everything + ! is in the first bin. This makes it easier to copy and terminate cohorts + ! later. + ! We don't need to update this ever if cohort age tracking is off + call coagetype_class_index(this%coage, this%pft, this%coage_class, & + this%coage_by_pft_class) + + ! asssign or calculate canopy extent and depth + if (hlm_use_sp .eq. ifalse) then + call carea_allom(this%dbh, this%n, spread, this%pft, this%crowndamage, & + this%c_area) + else + ! set this from previously precision-controlled value in SP mode + this%c_area = carea + endif + + ! Query PARTEH for the leaf carbon [kg] + leaf_c = this%prt%GetState(leaf_organ, carbon12_element) + + ! calculate tree lai + this%treelai = tree_lai(leaf_c, this%pft, this%c_area, this%n, & + this%canopy_layer, can_tlai, this%vcmax25top) + + if (hlm_use_sp .eq. ifalse) then + this%treesai = tree_sai(this%pft, this%dbh, this%crowndamage, & + this%canopy_trim, this%efstem_coh, this%c_area, this%n, & + this%canopy_layer, can_tlai, this%treelai,this%vcmax25top, 2) + end if + + call this%InitPRTBoundaryConditions() + + end subroutine Create + + !=========================================================================== + + subroutine Copy(this, copyCohort) + ! + ! DESCRIPTION: + ! copies all the variables in one cohort into a new cohort + ! + + ! ARGUMENTS + class(fates_cohort_type), intent(in) :: this ! old cohort + class(fates_cohort_type), intent(inout) :: copyCohort ! new cohort + + copyCohort%indexnumber = fates_unset_int + + ! POINTERS + copyCohort%taller => NULL() + copyCohort%shorter => NULL() + + ! PRT + call copyCohort%prt%CopyPRTVartypes(this%prt) + copyCohort%l2fr = this%l2fr + + ! VEGETATION STRUCTURE + copyCohort%pft = this%pft + copyCohort%n = this%n + copyCohort%dbh = this%dbh + copyCohort%coage = this%coage + copyCohort%height = this%height + copyCohort%canopy_layer = this%canopy_layer + copyCohort%canopy_layer_yesterday = this%canopy_layer_yesterday + copyCohort%crowndamage = this%crowndamage + copyCohort%g_sb_laweight = this%g_sb_laweight + copyCohort%canopy_trim = this%canopy_trim + copyCohort%leaf_cost = this%leaf_cost + copyCohort%excl_weight = this%excl_weight + copyCohort%prom_weight = this%prom_weight + copyCohort%nv = this%nv + copyCohort%status_coh = this%status_coh + copyCohort%efleaf_coh = this%efleaf_coh + copyCohort%effnrt_coh = this%effnrt_coh + copyCohort%efstem_coh = this%efstem_coh + copyCohort%c_area = this%c_area + copyCohort%treelai = this%treelai + copyCohort%treesai = this%treesai + copyCohort%isnew = this%isnew + copyCohort%size_class = this%size_class + copyCohort%coage_class = this%coage_class + copyCohort%size_by_pft_class = this%size_by_pft_class + copyCohort%coage_by_pft_class = this%coage_by_pft_class + copyCohort%size_class_lasttimestep = this%size_class_lasttimestep + + ! CARBON AND NUTRIENT FLUXES + copyCohort%gpp_tstep = this%gpp_tstep + copyCohort%gpp_acc = this%gpp_acc + copyCohort%gpp_acc_hold = this%gpp_acc_hold + copyCohort%npp_tstep = this%npp_tstep + copyCohort%npp_acc = this%npp_acc + copyCohort%npp_acc_hold = this%npp_acc_hold + copyCohort%resp_tstep = this%resp_tstep + copyCohort%resp_acc = this%resp_acc + copyCohort%resp_acc_hold = this%resp_acc_hold + copyCohort%c13disc_clm = this%c13disc_clm + copyCohort%c13disc_acc = this%c13disc_acc + copyCohort%vcmax25top = this%vcmax25top + copyCohort%jmax25top = this%jmax25top + copyCohort%tpu25top = this%tpu25top + copyCohort%kp25top = this%kp25top + copyCohort%ts_net_uptake = this%ts_net_uptake + copyCohort%year_net_uptake = this%year_net_uptake + copyCohort%cnp_limiter = this%cnp_limiter + + if (hlm_parteh_mode .eq. prt_cnp_flex_allom_hyp) then + copyCohort%cx_int = this%cx_int + copyCohort%ema_dcxdt = this%ema_dcxdt + copyCohort%cx0 = this%cx0 + end if + + copyCohort%nc_repro = this%nc_repro + copyCohort%daily_nh4_uptake = this%daily_nh4_uptake + copyCohort%daily_no3_uptake = this%daily_no3_uptake + copyCohort%sym_nfix_daily = this%sym_nfix_daily + copyCohort%sym_nfix_tstep = this%sym_nfix_tstep + copyCohort%daily_n_gain = this%daily_n_gain + copyCohort%daily_p_gain = this%daily_p_gain + copyCohort%daily_c_efflux = this%daily_c_efflux + copyCohort%daily_n_efflux = this%daily_n_efflux + copyCohort%daily_p_efflux = this%daily_p_efflux + copyCohort%daily_n_demand = this%daily_n_demand + copyCohort%daily_p_demand = this%daily_p_demand + copyCohort%seed_prod = this%seed_prod + + ! RESPIRATION COMPONENTS + copyCohort%rdark = this%rdark + copyCohort%resp_g_tstep = this%resp_g_tstep + copyCohort%resp_m = this%resp_m + copyCohort%resp_m_unreduced = this%resp_m_unreduced + copyCohort%resp_excess = this%resp_excess + copyCohort%livestem_mr = this%livestem_mr + copyCohort%livecroot_mr = this%livecroot_mr + copyCohort%froot_mr = this%froot_mr + + ! DAMAGE + copyCohort%branch_frac = this%branch_frac + + ! MORTALITY + copyCohort%dmort = this%dmort + copyCohort%bmort = this%bmort + copyCohort%cmort = this%cmort + copyCohort%hmort = this%hmort + copyCohort%frmort = this%frmort + copyCohort%smort = this%smort + copyCohort%asmort = this%asmort + copyCohort%dgmort = this%dgmort + copyCohort%lmort_direct = this%lmort_direct + copyCohort%lmort_collateral = this%lmort_collateral + copyCohort%lmort_infra = this%lmort_infra + copyCohort%l_degrad = this%l_degrad + + ! GROWTH DERIVATIVES + copyCohort%dndt = this%dndt + copyCohort%dhdt = this%dhdt + copyCohort%ddbhdt = this%ddbhdt + copyCohort%dbdeaddt = this%dbdeaddt + + ! FIRE + copyCohort%fraction_crown_burned = this%fraction_crown_burned + copyCohort%cambial_mort = this%cambial_mort + copyCohort%crownfire_mort = this%crownfire_mort + copyCohort%fire_mort = this%fire_mort + + ! HYDRAULICS + if (hlm_use_planthydro .eq. itrue) then + call copyCohort%co_hydr%CopyCohortHydraulics(this%co_hydr) + endif + + end subroutine Copy + + !=========================================================================== + + subroutine FreeMemory(this) + ! + ! DESCRIPTION: + ! deallocates all dynamic memory and objects within the cohort structure + ! DOES NOT deallocate the cohort structure itself + ! + + ! ARGUMENTS + class(fates_cohort_type), intent(inout) :: this ! cohort object + + ! LOCALS: + integer :: istat ! return status code + character(len=255) :: smsg ! error message + + ! at this point, nothing should be pointing to current cohort + if (hlm_use_planthydro .eq. itrue) then + call this%co_hydr%DeAllocateHydrCohortArrays() + deallocate(this%co_hydr) + end if + + ! deallocate the cohort's PRT structures + call this%prt%DeallocatePRTVartypes() + + ! Deallocate the PRT object + deallocate(this%prt, stat=istat, errmsg=smsg) + if (istat /= 0) then + write(fates_log(),*) 'dealloc002: fail in deallocate(currentCohort%prt):'//trim(smsg) + call endrun(msg=errMsg(sourcefile, __LINE__)) + endif + + end subroutine FreeMemory + + !=========================================================================== + + subroutine InitPRTBoundaryConditions(this) + ! + ! DESCRIPTION: + ! Set the boundary conditions that flow in an out of the PARTEH + ! allocation hypotheses. Each of these calls to "RegsterBC" are simply + ! setting pointers. + ! For instance, if the hypothesis wants to know what + ! the DBH of the plant is, then we pass in the dbh as an argument (copyCohort%dbh), + ! and also tell it which boundary condition we are talking about (which is + ! defined by an integer index (ac_bc_inout_id_dbh) + ! + ! Again, elaborated Example: + ! "ac_bc_inout_id_dbh" is the unique integer that defines the object index + ! for the allometric carbon "ac" boundary condition "bc" for DBH "dbh" + ! that is classified as input and output "inout". + ! See PRTAllometricCarbonMod.F90 to track its usage. + ! bc_rval is used as the optional argument identifyer to specify a real + ! value boundary condition. + ! bc_ival is used as the optional argument identifyer to specify an integer + ! value boundary condition. + + ! ARGUMENTS: + class(fates_cohort_type), intent(inout), target :: this + + select case(hlm_parteh_mode) + case (prt_carbon_allom_hyp) + + ! Register boundary conditions for the Carbon Only Allometric Hypothesis + + call this%prt%RegisterBCInOut(ac_bc_inout_id_dbh, bc_rval=this%dbh) + call this%prt%RegisterBCInOut(ac_bc_inout_id_netdc, bc_rval=this%npp_acc) + call this%prt%RegisterBCIn(ac_bc_in_id_cdamage, bc_ival=this%crowndamage) + call this%prt%RegisterBCIn(ac_bc_in_id_pft, bc_ival=this%pft) + call this%prt%RegisterBCIn(ac_bc_in_id_ctrim, bc_rval=this%canopy_trim) + call this%prt%RegisterBCIn(ac_bc_in_id_lstat, bc_ival=this%status_coh) + call this%prt%RegisterBCIn(ac_bc_in_id_efleaf, bc_rval = this%efleaf_coh) + call this%prt%RegisterBCIn(ac_bc_in_id_effnrt, bc_rval = this%effnrt_coh) + call this%prt%RegisterBCIn(ac_bc_in_id_efstem, bc_rval = this%efstem_coh) + + case (prt_cnp_flex_allom_hyp) + + ! Register boundary conditions for the CNP Allometric Hypothesis + + call this%prt%RegisterBCIn(acnp_bc_in_id_pft, bc_ival=this%pft) + call this%prt%RegisterBCIn(acnp_bc_in_id_ctrim, bc_rval=this%canopy_trim) + call this%prt%RegisterBCIn(acnp_bc_in_id_lstat, bc_ival=this%status_coh) + call this%prt%RegisterBCIn(acnp_bc_in_id_efleaf, bc_rval = this%efleaf_coh) + call this%prt%RegisterBCIn(acnp_bc_in_id_effnrt, bc_rval = this%effnrt_coh) + call this%prt%RegisterBCIn(acnp_bc_in_id_efstem, bc_rval = this%efstem_coh) + call this%prt%RegisterBCIn(acnp_bc_in_id_netdc, bc_rval=this%npp_acc) + + call this%prt%RegisterBCIn(acnp_bc_in_id_nc_repro, bc_rval=this%nc_repro) + call this%prt%RegisterBCIn(acnp_bc_in_id_pc_repro, bc_rval=this%pc_repro) + call this%prt%RegisterBCIn(acnp_bc_in_id_cdamage, bc_ival=this%crowndamage) + + call this%prt%RegisterBCInOut(acnp_bc_inout_id_dbh, bc_rval=this%dbh) + call this%prt%RegisterBCInOut(acnp_bc_inout_id_resp_excess, bc_rval=this%resp_excess) + call this%prt%RegisterBCInOut(acnp_bc_inout_id_l2fr, bc_rval=this%l2fr) + call this%prt%RegisterBCInOut(acnp_bc_inout_id_cx_int, bc_rval=this%cx_int) + call this%prt%RegisterBCInOut(acnp_bc_inout_id_emadcxdt, bc_rval=this%ema_dcxdt) + call this%prt%RegisterBCInOut(acnp_bc_inout_id_cx0, bc_rval=this%cx0) + + call this%prt%RegisterBCInOut(acnp_bc_inout_id_netdn, bc_rval=this%daily_n_gain) + call this%prt%RegisterBCInOut(acnp_bc_inout_id_netdp, bc_rval=this%daily_p_gain) + + call this%prt%RegisterBCOut(acnp_bc_out_id_cefflux, bc_rval=this%daily_c_efflux) + call this%prt%RegisterBCOut(acnp_bc_out_id_nefflux, bc_rval=this%daily_n_efflux) + call this%prt%RegisterBCOut(acnp_bc_out_id_pefflux, bc_rval=this%daily_p_efflux) + call this%prt%RegisterBCOut(acnp_bc_out_id_limiter, bc_ival=this%cnp_limiter) + + case DEFAULT + + write(fates_log(),*) 'You specified an unknown PRT module' + write(fates_log(),*) 'Aborting' + call endrun(msg=errMsg(sourcefile, __LINE__)) + + end select + + end subroutine InitPRTBoundaryConditions + + !=========================================================================== + + subroutine UpdateCohortBioPhysRates(this) + ! + ! DESCRIPTION: + ! Update the four key biophysical rates of leaves based on the changes + ! in a cohort's leaf age proportions. + ! + ! This should be called after growth. Growth occurs + ! after turnover and damage states are applied to the tree. + ! Therefore, following growth, the leaf mass fractions + ! of different age classes are unchanged until the next day. + + ! ARGUMENTS + class(fates_cohort_type), intent(inout) :: this ! cohort object + + ! LOCAL VARIABLES + real(r8) :: frac_leaf_aclass(max_nleafage) ! fraction of leaves in each age-class + integer :: iage ! loop index for leaf ages + integer :: ipft ! plant functional type index + + ! First, calculate the fraction of leaves in each age class + ! It is assumed that each class has the same proportion across leaf layers + do iage = 1, nleafage + frac_leaf_aclass(iage) = this%prt%GetState(leaf_organ, & + carbon12_element, iage) + end do + + ! If there are leaves, then perform proportional weighting on the four rates + ! We assume that leaf age does not effect the specific leaf area, so the mass + ! fractions are applicable to these rates + + ipft = this%pft + + if (sum(frac_leaf_aclass(1:nleafage)) > nearzero .and. & + hlm_use_sp .eq. ifalse) then + + frac_leaf_aclass(1:nleafage) = frac_leaf_aclass(1:nleafage)/ & + sum(frac_leaf_aclass(1:nleafage)) + + this%vcmax25top = sum(EDPftvarcon_inst%vcmax25top(ipft, 1:nleafage)* & + frac_leaf_aclass(1:nleafage)) + + this%jmax25top = sum(param_derived%jmax25top(ipft, 1:nleafage)* & + frac_leaf_aclass(1:nleafage)) + + this%tpu25top = sum(param_derived%tpu25top(ipft, 1:nleafage)* & + frac_leaf_aclass(1:nleafage)) + + this%kp25top = sum(param_derived%kp25top(ipft, 1:nleafage)* & + frac_leaf_aclass(1:nleafage)) + + else if (hlm_use_sp .eq. itrue) then + + this%vcmax25top = EDPftvarcon_inst%vcmax25top(ipft, 1) + this%jmax25top = param_derived%jmax25top(ipft, 1) + this%tpu25top = param_derived%tpu25top(ipft, 1) + this%kp25top = param_derived%kp25top(ipft, 1) + + else + + this%vcmax25top = 0._r8 + this%jmax25top = 0._r8 + this%tpu25top = 0._r8 + this%kp25top = 0._r8 + + end if + + end subroutine UpdateCohortBioPhysRates + + !=========================================================================== + + function CanUpperUnder(this) result(can_position) + ! + ! DESCRIPTION: + ! This simple function is used to determine if a cohort's crown position + ! is in the upper portion (ie the canopy) or the understory. This + ! differentiation is only used for diagnostic purposes. Functionally, + ! the model uses the canopy layer position, which may have more than + ! two layers at any given time. Utlimately, every plant that is not in + ! the top layer (canopy), is considered understory. + ! + + ! ARGUMENTS: + class(fates_cohort_type) :: this ! current cohort of interest + integer :: can_position ! canopy position + + if (this%canopy_layer == 1)then + can_position = ican_upper + else + can_position = ican_ustory + end if + + end function CanUpperUnder + + !=========================================================================== + + subroutine Dump(this) + ! + ! DESCRIPTION: + ! Print out attributes of a cohort + ! + + ! ARGUMENTS: + class(fates_cohort_type), intent(in), target :: this + + write(fates_log(),*) '----------------------------------------' + write(fates_log(),*) ' Dumping Cohort Information ' + write(fates_log(),*) '----------------------------------------' + write(fates_log(),*) 'cohort%pft = ', this%pft + write(fates_log(),*) 'cohort%n = ', this%n + write(fates_log(),*) 'cohort%dbh = ', this%dbh + write(fates_log(),*) 'cohort%height = ', this%height + write(fates_log(),*) 'cohort%crowndamage = ', this%crowndamage + write(fates_log(),*) 'cohort%coage = ', this%coage + write(fates_log(),*) 'cohort%l2fr = ', this%l2fr + write(fates_log(),*) 'leaf carbon = ', this%prt%GetState(leaf_organ,carbon12_element) + write(fates_log(),*) 'fineroot carbon = ', this%prt%GetState(fnrt_organ,carbon12_element) + write(fates_log(),*) 'sapwood carbon = ', this%prt%GetState(sapw_organ,carbon12_element) + write(fates_log(),*) 'structural (dead) carbon = ', this%prt%GetState(struct_organ,carbon12_element) + write(fates_log(),*) 'storage carbon = ', this%prt%GetState(store_organ,carbon12_element) + write(fates_log(),*) 'reproductive carbon = ', this%prt%GetState(repro_organ,carbon12_element) + write(fates_log(),*) 'cohort%g_sb_laweight = ', this%g_sb_laweight + write(fates_log(),*) 'cohort%leaf_cost = ', this%leaf_cost + write(fates_log(),*) 'cohort%canopy_layer = ', this%canopy_layer + write(fates_log(),*) 'cohort%canopy_layer_yesterday = ', this%canopy_layer_yesterday + write(fates_log(),*) 'cohort%nv = ', this%nv + write(fates_log(),*) 'cohort%status_coh = ', this%status_coh + write(fates_log(),*) 'co%status_coh = ', this%status_coh + write(fates_log(),*) 'co%efleaf_coh = ', this%efleaf_coh + write(fates_log(),*) 'co%effnrt_coh = ', this%effnrt_coh + write(fates_log(),*) 'co%efstem_coh = ', this%efstem_coh + write(fates_log(),*) 'cohort%canopy_trim = ', this%canopy_trim + write(fates_log(),*) 'cohort%excl_weight = ', this%excl_weight + write(fates_log(),*) 'cohort%prom_weight = ', this%prom_weight + write(fates_log(),*) 'cohort%size_class = ', this%size_class + write(fates_log(),*) 'cohort%size_by_pft_class = ', this%size_by_pft_class + write(fates_log(),*) 'cohort%coage_class = ', this%coage_class + write(fates_log(),*) 'cohort%coage_by_pft_class = ', this%coage_by_pft_class + write(fates_log(),*) 'cohort%gpp_acc_hold = ', this%gpp_acc_hold + write(fates_log(),*) 'cohort%gpp_acc = ', this%gpp_acc + write(fates_log(),*) 'cohort%gpp_tstep = ', this%gpp_tstep + write(fates_log(),*) 'cohort%npp_acc_hold = ', this%npp_acc_hold + write(fates_log(),*) 'cohort%npp_tstep = ', this%npp_tstep + write(fates_log(),*) 'cohort%npp_acc = ', this%npp_acc + write(fates_log(),*) 'cohort%resp_tstep = ', this%resp_tstep + write(fates_log(),*) 'cohort%resp_acc = ', this%resp_acc + write(fates_log(),*) 'cohort%resp_acc_hold = ', this%resp_acc_hold + write(fates_log(),*) 'cohort%rdark = ', this%rdark + write(fates_log(),*) 'cohort%resp_m = ', this%resp_m + write(fates_log(),*) 'cohort%resp_g_tstep = ', this%resp_g_tstep + write(fates_log(),*) 'cohort%livestem_mr = ', this%livestem_mr + write(fates_log(),*) 'cohort%livecroot_mr = ', this%livecroot_mr + write(fates_log(),*) 'cohort%froot_mr = ', this%froot_mr + write(fates_log(),*) 'cohort%dgmort = ', this%dgmort + write(fates_log(),*) 'cohort%treelai = ', this%treelai + write(fates_log(),*) 'cohort%treesai = ', this%treesai + write(fates_log(),*) 'cohort%c_area = ', this%c_area + write(fates_log(),*) 'cohort%cmort = ', this%cmort + write(fates_log(),*) 'cohort%bmort = ', this%bmort + write(fates_log(),*) 'cohort%smort = ', this%smort + write(fates_log(),*) 'cohort%asmort = ', this%asmort + write(fates_log(),*) 'cohort%dgmort = ', this%dgmort + write(fates_log(),*) 'cohort%hmort = ', this%hmort + write(fates_log(),*) 'cohort%frmort = ', this%frmort + write(fates_log(),*) 'cohort%asmort = ', this%asmort + write(fates_log(),*) 'cohort%lmort_direct = ', this%lmort_direct + write(fates_log(),*) 'cohort%lmort_collateral = ', this%lmort_collateral + write(fates_log(),*) 'cohort%lmort_infra = ', this%lmort_infra + write(fates_log(),*) 'cohort%isnew = ', this%isnew + write(fates_log(),*) 'cohort%dndt = ', this%dndt + write(fates_log(),*) 'cohort%dhdt = ', this%dhdt + write(fates_log(),*) 'cohort%ddbhdt = ', this%ddbhdt + write(fates_log(),*) 'cohort%dbdeaddt = ', this%dbdeaddt + write(fates_log(),*) 'cohort%fraction_crown_burned = ', this%fraction_crown_burned + write(fates_log(),*) 'cohort%fire_mort = ', this%fire_mort + write(fates_log(),*) 'cohort%crownfire_mort = ', this%crownfire_mort + write(fates_log(),*) 'cohort%cambial_mort = ', this%cambial_mort + write(fates_log(),*) 'cohort%size_class = ', this%size_class + write(fates_log(),*) 'cohort%size_by_pft_class = ', this%size_by_pft_class + + if (associated(this%co_hydr)) call this%co_hydr%Dump() + + write(fates_log(),*) '----------------------------------------' + + end subroutine Dump + + !=========================================================================== + +end module FatesCohortMod diff --git a/biogeochem/FatesLitterMod.F90 b/biogeochem/FatesLitterMod.F90 index be5ec48aa9..e16cce69db 100644 --- a/biogeochem/FatesLitterMod.F90 +++ b/biogeochem/FatesLitterMod.F90 @@ -36,7 +36,6 @@ module FatesLitterMod use FatesConstantsMod, only : nearzero use FatesConstantsMod, only : calloc_abs_error use FatesConstantsMod, only : fates_unset_r8 - use FatesGlobals , only : endrun => fates_endrun use FatesGlobals , only : fates_log use shr_log_mod , only : errMsg => shr_log_errMsg @@ -44,6 +43,7 @@ module FatesLitterMod implicit none private + public :: adjust_SF_CWD_frac integer, public, parameter :: ncwd = 4 ! number of coarse woody debris pools ! (twig,s branch,l branch, trunk) @@ -55,9 +55,18 @@ module FatesLitterMod integer, public, parameter :: icellulose = 2 ! Array index for cellulose portion integer, public, parameter :: ilignin = 3 ! Array index for the lignin portion + ! SPITFIRE + + integer, parameter, public :: NFSC = NCWD+2 ! number fuel size classes (4 cwd size classes, leaf litter, and grass) + integer, parameter, public :: tw_sf = 1 ! array index of twig pool for spitfire + integer, parameter, public :: lb_sf = 3 ! array index of large branch pool for spitfire + integer, parameter, public :: tr_sf = 4 ! array index of dead trunk pool for spitfire + integer, parameter, public :: dl_sf = 5 ! array index of dead leaf pool for spitfire (dead grass and dead leaves) + integer, parameter, public :: lg_sf = 6 ! array index of live grass pool for spitfire + - type, public :: litter_type + type, public :: litter_type ! This object is allocated for each element (C, N, P, etc) that we wish to track. @@ -424,6 +433,73 @@ function GetTotalLitterMass(this) result(total_mass) return end function GetTotalLitterMass - + + ! ===================================================== + + subroutine adjust_SF_CWD_frac(dbh,ncwd,SF_val_CWD_frac,SF_val_CWD_frac_adj) + + !DESCRIPTION + !Adjust the partitioning of struct + sawp into cwd pools based on + !cohort dbh. This avoids struct and sapw from small cohorts going to + !fuel classes that are larger than their dbh. Here, struct + sapw are sent to the cwd + !class consistent with fuel class diameter thresholds (Fosberg et al., 1971; + !Rothermel, 1983) + + !ARGUMENTS + real(r8), intent(in) :: dbh !dbh of cohort [cm] + type(integer), intent(in) :: ncwd !number of cwd pools + real(r8), intent(in) :: SF_val_CWD_frac(:) !fates parameter specifying the + !fraction of struct + sapw going + !to each CWD class + real(r8), intent(out) :: SF_val_CWD_frac_adj(:) !Updated cwd paritions + ! + !LOCAL VARIABLES + !These diameter ranges are based on work by Fosberg et al., 1971 + + real(r8), parameter :: lb_max_diam = 7.6 !max diameter [cm] for large branch (100 hr fuel) + real(r8), parameter :: sb_max_diam = 2.5 !max diameter [cm] for small branch (10 hr fuel) + real(r8), parameter :: twig_max_diam = 0.6 !max diameter [cm] for twig (1 hr fuel) + !------------------------------------------------------------------------------------ + + + SF_val_CWD_frac_adj = SF_val_CWD_frac + + !If dbh is > 7.6 cm diameter then the main stem is 1,000 hr fuel and we don't change + !how biomass is partitioned among cwd classes. + if (dbh > lb_max_diam) then + return + + !When dbh is greater than the max size of a small branch (10 hr fuel) but less than or + !equal to the max size of a large branch (e.g. saplings where dbh > 2.5 cm and < 7.5 cm) + !we redistribute the biomass that would have gone to 1,000 hr fuel among the smaller cwd classes. + !This keeps the biomass proportions among the combustible classes the same as the scenario + !where a fraction of struct + sawp goes to 1,000 hr fuel. + else if (dbh > sb_max_diam .and. dbh .le. lb_max_diam) then + SF_val_CWD_frac_adj(ncwd) = 0.0 + SF_val_CWD_frac_adj(ncwd-1) = SF_val_CWD_frac(ncwd-1) / (1.0_r8 - SF_val_CWD_frac(ncwd) ) + SF_val_CWD_frac_adj(ncwd-2) = SF_val_CWD_frac(ncwd-2) / (1.0_r8 - SF_val_CWD_frac(ncwd) ) + SF_val_CWD_frac_adj(ncwd-3) = SF_val_CWD_frac(ncwd-3) / (1.0_r8 - SF_val_CWD_frac(ncwd) ) + + !When dbh is greater than the max size of a twig (1 hr fuel) but less than or + !equal to the max size of a small branch (10 hr fuel) we redistribute the biomass among the smaller + !pools. + else if (dbh > twig_max_diam .and. dbh .le. sb_max_diam) then + SF_val_CWD_frac_adj(ncwd) = 0.0 + SF_val_CWD_frac_adj(ncwd-1) = 0.0 + SF_val_CWD_frac_adj(ncwd-2) = SF_val_CWD_frac(ncwd-2) / (1.0_r8 - (SF_val_CWD_frac(ncwd) + & + SF_val_CWD_frac(ncwd-1))) + SF_val_CWD_frac_adj(ncwd-3) = SF_val_CWD_frac(ncwd-3) / (1.0_r8 - (SF_val_CWD_frac(ncwd) + & + SF_val_CWD_frac(ncwd-1))) + + !If dbh is less than or equal to the max size of a twig we send all + !biomass to twigs. + else if (dbh .le. twig_max_diam) then + SF_val_CWD_frac_adj(ncwd) = 0.0 + SF_val_CWD_frac_adj(ncwd-1) = 0.0 + SF_val_CWD_frac_adj(ncwd-2) = 0.0 + SF_val_CWD_frac_adj(ncwd-3) = sum(SF_val_CWD_frac) + + endif + end subroutine adjust_SF_CWD_frac end module FatesLitterMod diff --git a/biogeochem/FatesPatchMod.F90 b/biogeochem/FatesPatchMod.F90 new file mode 100644 index 0000000000..d8ee395f62 --- /dev/null +++ b/biogeochem/FatesPatchMod.F90 @@ -0,0 +1,816 @@ +module FatesPatchMod + + use FatesConstantsMod, only : r8 => fates_r8 + use FatesConstantsMod, only : fates_unset_r8 + use FatesConstantsMod, only : fates_unset_int + use FatesConstantsMod, only : primaryforest, secondaryforest + use FatesConstantsMod, only : TRS_regeneration + use FatesGlobals, only : fates_log + use FatesGlobals, only : endrun => fates_endrun + use FatesUtilsMod, only : check_hlm_list + use FatesUtilsMod, only : check_var_real + use FatesCohortMod, only : fates_cohort_type + use FatesRunningMeanMod, only : rmean_type, rmean_arr_type + use FatesLitterMod, only : nfsc + use FatesLitterMod, only : litter_type + use PRTGenericMod, only : num_elements + use PRTGenericMod, only : element_list + use EDParamsMod, only : maxSWb, nlevleaf, nclmax, maxpft + use FatesConstantsMod, only : n_dbh_bins, n_dist_types + use FatesConstantsMod, only : n_rad_stream_types + use FatesConstantsMod, only : t_water_freeze_k_1atm + use FatesRunningMeanMod, only : ema_24hr, fixed_24hr, ema_lpa, ema_longterm + use FatesRunningMeanMod, only : ema_sdlng_emerg_h2o, ema_sdlng_mort_par + use FatesRunningMeanMod, only : ema_sdlng2sap_par, ema_sdlng_mdd + + use shr_infnan_mod, only : nan => shr_infnan_nan, assignment(=) + use shr_log_mod, only : errMsg => shr_log_errMsg + + implicit none + private + + ! for error message writing + character(len=*), parameter :: sourcefile = __FILE__ + + type, public :: fates_patch_type + + ! POINTERS + type (fates_cohort_type), pointer :: tallest => null() ! pointer to patch's tallest cohort + type (fates_cohort_type), pointer :: shortest => null() ! pointer to patch's shortest cohort + type (fates_patch_type), pointer :: older => null() ! pointer to next older patch + type (fates_patch_type), pointer :: younger => null() ! pointer to next younger patch + + !--------------------------------------------------------------------------- + + ! INDICES + integer :: patchno ! unique number given to each new patch created for tracking + integer :: nocomp_pft_label ! when nocomp is active, use this label for patch ID + ! each patch ID corresponds to a pft number since each + ! patch has only one pft. Bareground patches are given + ! a zero integer as a label. If nocomp is not active this + ! is set to unset. This is set in patch%Create as an argument + ! to that procedure. + + !--------------------------------------------------------------------------- + + ! PATCH INFO + real(r8) :: age ! average patch age [years] + integer :: age_class ! age class of the patch for history binning purposes + real(r8) :: area ! patch area [m2] + integer :: countcohorts ! number of cohorts in patch + integer :: ncl_p ! number of occupied canopy layers + integer :: anthro_disturbance_label ! patch label for anthropogenic disturbance classification + real(r8) :: age_since_anthro_disturbance ! average age for secondary forest since last anthropogenic disturbance [years] + + !--------------------------------------------------------------------------- + + ! RUNNING MEANS + !class(rmean_type), pointer :: t2m ! place-holder for 2m air temperature (variable window-size) + class(rmean_type), pointer :: tveg24 ! 24-hour mean vegetation temperature [K] + class(rmean_type), pointer :: tveg_lpa ! running mean of vegetation temperature at the + ! leaf photosynthesis acclimation timescale [K] + class(rmean_type), pointer :: tveg_longterm ! long-term running mean of vegetation temperature at the + ! leaf photosynthesis acclimation timescale [K] (i.e T_home) + class(rmean_type), pointer :: seedling_layer_par24 ! 24-hour mean of photosynthetically active radiation at seedling layer [W/m2] + 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_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) + 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 aboveground biomass, for patch fusion [kgC/m2] + real(r8) :: canopy_layer_tlai(nclmax) ! total leaf area index of each canopy layer [m2 veg/m2 canopy area] + ! (patch without bare ground) + ! used to determine attenuation of parameters during photosynthesis + real(r8) :: total_canopy_area ! area that is covered by vegetation [m2] + real(r8) :: total_tree_area ! area that is covered by woody vegetation [m2] + real(r8) :: zstar ! height of smallest canopy tree, only meaningful in "strict PPA" mode [m] + real(r8) :: elai_profile(nclmax,maxpft,nlevleaf) ! exposed leaf area in each canopy layer, pft, and leaf layer [m2 leaf/m2 contributing crown area] + real(r8) :: esai_profile(nclmax,maxpft,nlevleaf) ! exposed stem area in each canopy layer, pft, and leaf layer [m2 leaf/m2 contributing crown area] + real(r8) :: tlai_profile(nclmax,maxpft,nlevleaf) + real(r8) :: tsai_profile(nclmax,maxpft,nlevleaf) + real(r8) :: canopy_area_profile(nclmax,maxpft,nlevleaf) ! fraction of crown area per canopy area in each layer + ! they will sum to 1.0 in the fully closed canopy layers + ! but only in leaf-layers that contain contributions + ! from all cohorts that donate to canopy_area + integer :: canopy_mask(nclmax,maxpft) ! is there any of this pft in this canopy layer? + integer :: nrad(nclmax,maxpft) ! number of exposed leaf layers for each canopy layer and pft + integer :: ncan(nclmax,maxpft) ! number of total leaf layers for each canopy layer and pft + real(r8) :: c_stomata ! mean stomatal conductance of all leaves in the patch [umol/m2/s] + real(r8) :: c_lblayer ! mean boundary layer conductance of all leaves in the patch [umol/m2/s] + + !TODO - can we delete these? + real(r8) :: layer_height_profile(nclmax,maxpft,nlevleaf) + real(r8) :: psn_z(nclmax,maxpft,nlevleaf) + real(r8) :: nrmlzd_parprof_pft_dir_z(n_rad_stream_types,nclmax,maxpft,nlevleaf) + real(r8) :: nrmlzd_parprof_pft_dif_z(n_rad_stream_types,nclmax,maxpft,nlevleaf) + real(r8) :: nrmlzd_parprof_dir_z(n_rad_stream_types,nclmax,nlevleaf) + real(r8) :: nrmlzd_parprof_dif_z(n_rad_stream_types,nclmax,nlevleaf) + + !--------------------------------------------------------------------------- + + ! RADIATION + real(r8) :: radiation_error ! radiation error [W/m2] + real(r8) :: fcansno ! fraction of canopy covered in snow [0-1] + logical :: solar_zenith_flag ! integer flag specifying daylight (based on zenith angle) + real(r8) :: solar_zenith_angle ! solar zenith angle [radians] + real(r8) :: gnd_alb_dif(maxSWb) ! ground albedo for diffuse rad, both bands [0-1] + real(r8) :: gnd_alb_dir(maxSWb) ! ground albedo for direct rad, both bands [0-1] + + ! organized by canopy layer, pft, and leaf layer + real(r8) :: fabd_sun_z(nclmax,maxpft,nlevleaf) ! sun fraction of direct light absorbed [0-1] + real(r8) :: fabd_sha_z(nclmax,maxpft,nlevleaf) ! shade fraction of direct light absorbed [0-1] + real(r8) :: fabi_sun_z(nclmax,maxpft,nlevleaf) ! sun fraction of indirect light absorbed [0-1] + real(r8) :: fabi_sha_z(nclmax,maxpft,nlevleaf) ! shade fraction of indirect light absorbed [0-1] + real(r8) :: ed_parsun_z(nclmax,maxpft,nlevleaf) ! PAR absorbed in the sun [W/m2] + real(r8) :: ed_parsha_z(nclmax,maxpft,nlevleaf) ! PAR absorbed in the shade [W/m2] + real(r8) :: ed_laisun_z(nclmax,maxpft,nlevleaf) + real(r8) :: ed_laisha_z(nclmax,maxpft,nlevleaf) + real(r8) :: f_sun(nclmax,maxpft,nlevleaf) ! fraction of leaves in the sun [0-1] + + ! radiation profiles for comparison against observations + real(r8) :: parprof_pft_dir_z(nclmax,maxpft,nlevleaf) ! direct-beam PAR profile through canopy, by canopy, PFT, leaf level [W/m2] + real(r8) :: parprof_pft_dif_z(nclmax,maxpft,nlevleaf) ! diffuse PAR profile through canopy, by canopy, PFT, leaf level [W/m2] + real(r8) :: parprof_dir_z(nclmax,nlevleaf) ! direct-beam PAR profile through canopy, by canopy, leaf level [W/m2] + real(r8) :: parprof_dif_z(nclmax,nlevleaf) ! diffuse PAR profile through canopy, by canopy, leaf level [W/m2] + + real(r8), allocatable :: tr_soil_dir(:) ! fraction of incoming direct radiation transmitted to the soil as direct, by numSWB [0-1] + real(r8), allocatable :: tr_soil_dif(:) ! fraction of incoming diffuse radiation that is transmitted to the soil as diffuse [0-1] + real(r8), allocatable :: tr_soil_dir_dif(:) ! fraction of incoming direct radiation that is transmitted to the soil as diffuse [0-1] + real(r8), allocatable :: fab(:) ! fraction of incoming total radiation that is absorbed by the canopy + real(r8), allocatable :: fabd(:) ! fraction of incoming direct radiation that is absorbed by the canopy + real(r8), allocatable :: fabi(:) ! fraction of incoming diffuse radiation that is absorbed by the canopy + real(r8), allocatable :: sabs_dir(:) ! fraction of incoming direct radiation that is absorbed by the canopy + real(r8), allocatable :: sabs_dif(:) ! fraction of incoming diffuse radiation that is absorbed by the canopy + + !--------------------------------------------------------------------------- + + ! ROOTS + real(r8) :: btran_ft(maxpft) ! btran calculated seperately for each PFT + real(r8) :: bstress_sal_ft(maxpft) ! bstress from salinity calculated seperately for each PFT + + !--------------------------------------------------------------------------- + + ! EXTERNAL SEED RAIN + real(r8) :: nitr_repro_stoich(maxpft) ! The NC ratio of a new recruit in this patch + real(r8) :: phos_repro_stoich(maxpft) ! The PC ratio of a new recruit in this patch + + !--------------------------------------------------------------------------- + + ! DISTURBANCE + real(r8) :: disturbance_rates(n_dist_types) ! disturbance rate [0-1/day] from 1) mortality + ! 2) fire + ! 3) logging mortatliy + real(r8) :: fract_ldist_not_harvested ! fraction of logged area that is canopy trees that weren't harvested [0-1] + + !--------------------------------------------------------------------------- + + ! LITTER AND COARSE WOODY DEBRIS + type(litter_type), pointer :: litter(:) ! litter (leaf,fnrt,CWD and seeds) for different elements + real(r8), allocatable :: fragmentation_scaler(:) ! scale rate of litter fragmentation based on soil layer [0-1] + + !--------------------------------------------------------------------------- + + ! FUELS AND FIRE + ! fuel characteristics + real(r8) :: sum_fuel ! total ground fuel related to ROS (omits 1000 hr fuels) [kgC/m2] + real(r8) :: fuel_frac(nfsc) ! fraction of each litter class in the ros_fuel [0-1] + real(r8) :: livegrass ! total aboveground grass biomass in patch [kgC/m2] + real(r8) :: fuel_bulkd ! average fuel bulk density of the ground fuel. [kg/m3] + ! (incl. live grasses, omits 1000hr fuels) + real(r8) :: fuel_sav ! average surface area to volume ratio of the ground fuel [cm-1] + ! (incl. live grasses, omits 1000hr fuels) + real(r8) :: fuel_mef ! average moisture of extinction factor + ! of the ground fuel (incl. live grasses, omits 1000hr fuels) + real(r8) :: fuel_eff_moist ! effective avearage fuel moisture content of the ground fuel + ! (incl. live grasses. omits 1000hr fuels) + real(r8) :: litter_moisture(nfsc) ! moisture of litter [m3/m3] + real(r8) :: canopy_bulk_density + + + ! fire spread + real(r8) :: ros_front ! rate of forward spread of fire [m/min] + real(r8) :: ros_back ! rate of backward spread of fire [m/min] + real(r8) :: effect_wspeed ! windspeed modified by fraction of relative grass and tree cover [m/min] + real(r8) :: tau_l ! duration of lethal heating [min] + real(r8) :: fi ! average fire intensity of flaming front [kJ/m/s] or [kW/m] + integer :: fire ! is there a fire? [1=yes; 0=no] + integer :: active_crown_fire_flg + real(r8) :: fd ! fire duration [min] + + ! fire effects + real(r8) :: scorch_ht(maxpft) ! scorch height [m] + real(r8) :: frac_burnt ! fraction burnt [0-1/day] + real(r8) :: tfc_ros ! total intensity-relevant fuel consumed - no trunks [kgC/m2 of burned ground/day] + real(r8) :: burnt_frac_litter(nfsc) ! fraction of each litter pool burned, conditional on it being burned [0-1] + + !--------------------------------------------------------------------------- + + ! 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 + + contains + + procedure :: Init + procedure :: NanValues + procedure :: ZeroValues + procedure :: InitRunningMeans + procedure :: InitLitter + procedure :: Create + procedure :: FreeMemory + procedure :: Dump + procedure :: CheckVars + + end type fates_patch_type + + contains + + !=========================================================================== + + subroutine Init(this, num_swb, num_levsoil) + ! + ! DESCRIPTION: + ! Initialize a new patch - allocate arrays and set values to nan and/or 0.0 + ! + + ! ARGUMENTS: + class(fates_patch_type), intent(inout) :: this ! patch object + integer, intent(in) :: num_swb ! number of shortwave broad-bands to track + integer, intent(in) :: num_levsoil ! number of soil layers + + ! allocate arrays + allocate(this%tr_soil_dir(num_swb)) + allocate(this%tr_soil_dif(num_swb)) + allocate(this%tr_soil_dir_dif(num_swb)) + allocate(this%fab(num_swb)) + allocate(this%fabd(num_swb)) + allocate(this%fabi(num_swb)) + allocate(this%sabs_dir(num_swb)) + allocate(this%sabs_dif(num_swb)) + allocate(this%fragmentation_scaler(num_levsoil)) + + ! initialize all values to nan + call this%NanValues() + + ! zero values that should be zeroed + call this%ZeroValues() + + end subroutine Init + + !=========================================================================== + + subroutine NanValues(this) + ! + ! DESCRIPTION: + ! Sets all values in patch to nan + ! + + ! ARGUMENTS: + class(fates_patch_type), intent(inout) :: this ! patch object + + ! set pointers to null + this%tallest => null() + this%shortest => null() + this%older => null() + this%younger => null() + nullify(this%tallest) + nullify(this%shortest) + nullify(this%older) + nullify(this%younger) + + ! INDICES + this%patchno = fates_unset_int + this%nocomp_pft_label = fates_unset_int + + ! PATCH INFO + this%age = nan + this%age_class = fates_unset_int + this%area = nan + this%countcohorts = fates_unset_int + this%ncl_p = fates_unset_int + this%anthro_disturbance_label = fates_unset_int + this%age_since_anthro_disturbance = nan + + ! LEAF ORGANIZATION + this%pft_agb_profile(:,:) = nan + this%canopy_layer_tlai(:) = nan + this%total_canopy_area = nan + this%total_tree_area = nan + this%zstar = nan + this%elai_profile(:,:,:) = nan + this%esai_profile(:,:,:) = nan + this%tlai_profile(:,:,:) = nan + this%tsai_profile(:,:,:) = nan + this%canopy_area_profile(:,:,:) = nan + this%canopy_mask(:,:) = fates_unset_int + this%nrad(:,:) = fates_unset_int + this%ncan(:,:) = fates_unset_int + this%c_stomata = nan + this%c_lblayer = nan + this%layer_height_profile(:,:,:) = nan + + this%psn_z(:,:,:) = nan + this%nrmlzd_parprof_pft_dir_z(:,:,:,:) = nan + this%nrmlzd_parprof_pft_dif_z(:,:,:,:) = nan + this%nrmlzd_parprof_dir_z(:,:,:) = nan + this%nrmlzd_parprof_dir_z(:,:,:) = nan + + ! RADIATION + this%radiation_error = nan + this%fcansno = nan + this%solar_zenith_flag = .false. + this%solar_zenith_angle = nan + this%gnd_alb_dif(:) = nan + this%gnd_alb_dir(:) = nan + this%fabd_sun_z(:,:,:) = nan + this%fabd_sha_z(:,:,:) = nan + this%fabi_sun_z(:,:,:) = nan + this%fabi_sha_z(:,:,:) = nan + this%ed_laisun_z(:,:,:) = nan + this%ed_laisha_z(:,:,:) = nan + this%ed_parsun_z(:,:,:) = nan + this%ed_parsha_z(:,:,:) = nan + this%f_sun(:,:,:) = nan + this%parprof_pft_dir_z(:,:,:) = nan + this%parprof_pft_dif_z(:,:,:) = nan + this%parprof_dir_z(:,:) = nan + this%parprof_dif_z(:,:) = nan + this%tr_soil_dir(:) = nan + this%tr_soil_dif(:) = nan + this%tr_soil_dir_dif(:) = nan + this%fab(:) = nan + this%fabd(:) = nan + this%fabi(:) = nan + this%sabs_dir(:) = nan + this%sabs_dif(:) = nan + + ! ROOTS + this%btran_ft(:) = nan + this%bstress_sal_ft(:) = nan + + ! EXTERNAL SEED RAIN + this%nitr_repro_stoich(:) = nan + this%phos_repro_stoich(:) = nan + + ! DISTURBANCE + this%disturbance_rates(:) = nan + this%fract_ldist_not_harvested = nan + + ! LITTER AND COARSE WOODY DEBRIS + this%fragmentation_scaler(:) = nan + + ! FUELS AND FIRE + this%sum_fuel = nan + this%fuel_frac(:) = nan + this%livegrass = nan + this%fuel_bulkd = nan + this%fuel_sav = nan + this%fuel_mef = nan + this%fuel_eff_moist = nan + this%litter_moisture(:) = nan + this%ros_front = nan + this%ros_back = nan + this%effect_wspeed = nan + this%tau_l = nan + this%fi = nan + this%fire = fates_unset_int + this%active_crown_fire_flg = fates_unset_int + this%fd = nan + this%scorch_ht(:) = nan + this%frac_burnt = nan + this%canopy_bulk_density = nan + this%tfc_ros = nan + this%burnt_frac_litter(:) = nan + + end subroutine NanValues + + !=========================================================================== + + subroutine ZeroValues(this) + ! + ! DESCRIPTION: + ! sets specific variables in patch to zero + ! these should only be values that are incremented, so that we can + ! catch all other uninitialized variables with nans + + ! ARGUMENTS: + class(fates_patch_type), intent(inout) :: this + + ! LEAF ORGANIZATION + this%canopy_layer_tlai(:) = 0.0_r8 + this%total_tree_area = 0.0_r8 + this%zstar = 0.0_r8 + this%elai_profile(:,:,:) = 0.0_r8 + this%c_stomata = 0.0_r8 + this%c_lblayer = 0.0_r8 + this%psn_z(:,:,:) = 0.0_r8 + this%nrmlzd_parprof_pft_dir_z(:,:,:,:) = 0.0_r8 + this%nrmlzd_parprof_pft_dif_z(:,:,:,:) = 0.0_r8 + this%nrmlzd_parprof_dir_z(:,:,:) = 0.0_r8 + this%nrmlzd_parprof_dif_z(:,:,:) = 0.0_r8 + + ! RADIATION + this%radiation_error = 0.0_r8 + this%fabd_sun_z(:,:,:) = 0.0_r8 + this%fabd_sha_z(:,:,:) = 0.0_r8 + this%fabi_sun_z(:,:,:) = 0.0_r8 + this%fabi_sha_z(:,:,:) = 0.0_r8 + this%ed_parsun_z(:,:,:) = 0.0_r8 + this%ed_parsha_z(:,:,:) = 0.0_r8 + this%ed_laisun_z(:,:,:) = 0.0_r8 + this%ed_laisha_z(:,:,:) = 0.0_r8 + this%f_sun = 0.0_r8 + this%tr_soil_dir_dif(:) = 0.0_r8 + this%fab(:) = 0.0_r8 + this%fabi(:) = 0.0_r8 + this%fabd(:) = 0.0_r8 + this%sabs_dir(:) = 0.0_r8 + this%sabs_dif(:) = 0.0_r8 + + ! ROOTS + this%btran_ft(:) = 0.0_r8 + + ! DISTURBANCE + this%disturbance_rates(:) = 0.0_r8 + this%fract_ldist_not_harvested = 0.0_r8 + + ! LITTER AND COARSE WOODY DEBRIS + this%fragmentation_scaler(:) = 0.0_r8 + + ! FIRE + this%sum_fuel = 0.0_r8 + this%fuel_frac(:) = 0.0_r8 + this%livegrass = 0.0_r8 + this%fuel_bulkd = 0.0_r8 + this%fuel_sav = 0.0_r8 + this%fuel_mef = 0.0_r8 + this%fuel_eff_moist = 0.0_r8 + this%litter_moisture(:) = 0.0_r8 + this%ros_front = 0.0_r8 + this%ros_back = 0.0_r8 + this%effect_wspeed = 0.0_r8 + this%tau_l = 0.0_r8 + this%fi = 0.0_r8 + this%fd = 0.0_r8 + this%scorch_ht(:) = 0.0_r8 + this%frac_burnt = 0.0_r8 + this%canopy_bulk_density = 0.0_r8 + this%tfc_ros = 0.0_r8 + this%burnt_frac_litter(:) = 0.0_r8 + + end subroutine ZeroValues + + !=========================================================================== + + subroutine InitRunningMeans(this, current_tod, regeneration_model, numpft) + ! + ! DESCRIPTION: + ! set initial values for patch running means + ! + + ! ARGUMENTS: + class(fates_patch_type), intent(inout) :: this ! patch object + integer, intent(in) :: current_tod ! time of day [seconds past 0Z] + integer, intent(in) :: regeneration_model ! regeneration model type + integer, intent(in) :: numpft ! number of pfts on patch + + ! PARAMETERS: + ! 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 ! arbitrary initialization for seedling layer [MJ m-2 d-1] + real(r8), parameter :: init_seedling_smp = -26652.0_r8 ! abitrary initialization of smp [mm] + integer :: pft ! pft looping index + + allocate(this%tveg24) + allocate(this%tveg_lpa) + allocate(this%tveg_longterm) + + ! set initial values for running means + call this%tveg24%InitRMean(fixed_24hr, init_value=temp_init_veg, & + init_offset=real(current_tod, r8)) + call this%tveg_lpa%InitRmean(ema_lpa, init_value=temp_init_veg) + call this%tveg_longterm%InitRmean(ema_longterm, init_value=temp_init_veg) + + if (regeneration_model == TRS_regeneration) then + allocate(this%seedling_layer_par24) + allocate(this%sdlng_mdd(numpft)) + allocate(this%sdlng_emerg_smp(numpft)) + allocate(this%sdlng_mort_par) + allocate(this%sdlng2sap_par) + + call this%seedling_layer_par24%InitRMean(fixed_24hr, & + init_value=init_seedling_par, init_offset=real(current_tod, r8)) + call this%sdlng_mort_par%InitRMean(ema_sdlng_mort_par, & + init_value=temp_init_veg) + call this%sdlng2sap_par%InitRMean(ema_sdlng2sap_par, & + init_value=init_seedling_par) + + do pft = 1,numpft + allocate(this%sdlng_mdd(pft)%p) + allocate(this%sdlng_emerg_smp(pft)%p) + + call this%sdlng_mdd(pft)%p%InitRMean(ema_sdlng_mdd, & + init_value=0.0_r8) + call this%sdlng_emerg_smp(pft)%p%InitRMean(ema_sdlng_emerg_h2o, & + init_value=init_seedling_smp) + end do + end if + + end subroutine InitRunningMeans + + !=========================================================================== + + subroutine InitLitter(this, num_pft, num_levsoil) + ! + ! DESCRIPTION: + ! set initial values for litter + ! + + ! ARGUMENTS: + class(fates_patch_type), intent(inout) :: this ! patch object + integer, intent(in) :: num_pft ! number of pfts to simulate + integer, intent(in) :: num_levsoil ! number of soil layers + + ! LOCALS: + integer :: el ! looping index + + allocate(this%litter(num_elements)) + + do el = 1, num_elements + call this%litter(el)%InitAllocate(num_pft, num_levsoil, element_list(el)) + call this%litter(el)%ZeroFlux() + call this%litter(el)%InitConditions(init_leaf_fines=fates_unset_r8, & + init_root_fines=fates_unset_r8, init_ag_cwd=fates_unset_r8, & + init_bg_cwd=fates_unset_r8, init_seed=fates_unset_r8, & + init_seed_germ=fates_unset_r8) + end do + + end subroutine InitLitter + + !=========================================================================== + + subroutine Create(this, age, area, label, nocomp_pft, num_swb, num_pft, & + num_levsoil, current_tod, regeneration_model) + ! + ! DESCRIPTION: + ! create a new patch with input and default values + ! + + ! ARGUMENTS: + class(fates_patch_type), intent(inout) :: this ! patch object + real(r8), intent(in) :: age ! notional age of this patch in years + real(r8), intent(in) :: area ! initial area of this patch in m2. + integer, intent(in) :: label ! anthropogenic disturbance label + integer, intent(in) :: nocomp_pft ! no-competition mode pft label + integer, intent(in) :: num_swb ! number of shortwave broad-bands to track + integer, intent(in) :: num_pft ! number of pfts to simulate + integer, intent(in) :: num_levsoil ! number of soil layers + integer, intent(in) :: current_tod ! time of day [seconds past 0Z] + integer, intent(in) :: regeneration_model ! regeneration model version + + ! initialize patch + ! sets all values to nan, then some values to zero + call this%Init(num_swb, num_levsoil) + + ! initialize running means for patch + call this%InitRunningMeans(current_tod, regeneration_model, num_pft) + + ! initialize litter + call this%InitLitter(num_pft, num_levsoil) + + ! assign known patch attributes + this%age = age + this%age_class = 1 + this%area = area + + ! assign anthropgenic disturbance category and label + this%anthro_disturbance_label = label + if (label .eq. secondaryforest) then + this%age_since_anthro_disturbance = age + else + this%age_since_anthro_disturbance = fates_unset_r8 + endif + this%nocomp_pft_label = nocomp_pft + + this%tr_soil_dir(:) = 1.0_r8 + this%tr_soil_dif(:) = 1.0_r8 + this%NCL_p = 1 + + end subroutine Create + + !=========================================================================== + + subroutine FreeMemory(this, regeneration_model, numpft) + ! + ! DESCRIPTION: + ! deallocate the allocatable memory associated with this patch + ! this DOES NOT deallocate the patch structure itself + ! + + ! ARGUMENTS: + class(fates_patch_type), intent(inout) :: this + integer, intent(in) :: regeneration_model + integer, intent(in) :: numpft + + ! LOCALS: + type(fates_cohort_type), pointer :: ccohort ! current cohort + type(fates_cohort_type), pointer :: ncohort ! next cohort + integer :: el ! loop counter for elements + integer :: pft ! loop counter for pfts + integer :: istat ! return status code + character(len=255) :: smsg ! message string for deallocation errors + + ! first deallocate the cohorts + ccohort => this%shortest + do while(associated(ccohort)) + ncohort => ccohort%taller + call ccohort%FreeMemory() + deallocate(ccohort, stat=istat, errmsg=smsg) + if (istat /= 0) then + write(fates_log(),*) 'dealloc007: fail on deallocate(cchort):'//trim(smsg) + call endrun(msg=errMsg(sourcefile, __LINE__)) + endif + ccohort => ncohort + end do + + ! deallocate all litter objects + do el=1,num_elements + call this%litter(el)%DeallocateLitt() + end do + deallocate(this%litter, stat=istat, errmsg=smsg) + if (istat/=0) then + write(fates_log(),*) 'dealloc008: fail on deallocate(this%litter):'//trim(smsg) + call endrun(msg=errMsg(sourcefile, __LINE__)) + endif + + ! deallocate the allocatable arrays + deallocate(this%tr_soil_dir, & + this%tr_soil_dif, & + this%tr_soil_dir_dif, & + this%fab, & + this%fabd, & + this%fabi, & + this%sabs_dir, & + this%sabs_dif, & + this%fragmentation_scaler, & + stat=istat, errmsg=smsg) + + if (istat/=0) then + write(fates_log(),*) 'dealloc009: fail on deallocate patch vectors:'//trim(smsg) + call endrun(msg=errMsg(sourcefile, __LINE__)) + endif + + ! deallocate running means + deallocate(this%tveg24, stat=istat, errmsg=smsg) + if (istat/=0) then + write(fates_log(),*) 'dealloc010: fail on deallocate(this%tveg24):'//trim(smsg) + call endrun(msg=errMsg(sourcefile, __LINE__)) + endif + deallocate(this%tveg_lpa, stat=istat, errmsg=smsg) + if (istat/=0) then + write(fates_log(),*) 'dealloc011: fail on deallocate(this%tveg_lpa):'//trim(smsg) + call endrun(msg=errMsg(sourcefile, __LINE__)) + endif + deallocate(this%tveg_longterm, stat=istat, errmsg=smsg) + if (istat/=0) then + write(fates_log(),*) 'dealloc012: fail on deallocate(this%tveg_longterm):'//trim(smsg) + call endrun(msg=errMsg(sourcefile, __LINE__)) + endif + + if (regeneration_model == TRS_regeneration) then + deallocate(this%seedling_layer_par24) + deallocate(this%sdlng_mort_par) + deallocate(this%sdlng2sap_par) + do pft = 1, numpft + deallocate(this%sdlng_mdd(pft)%p) + end do + deallocate(this%sdlng_mdd) + do pft = 1, numpft + deallocate(this%sdlng_emerg_smp(pft)%p) + end do + deallocate(this%sdlng_emerg_smp) + end if + + end subroutine FreeMemory + + !=========================================================================== + + subroutine Dump(this) + ! + ! DESCRIPTION: + ! print attributes of a patch + ! + + ! ARGUMENTS: + class(fates_patch_type), intent(in) :: this ! patch object + + ! LOCALS: + integer :: el ! element loop counting index + + write(fates_log(),*) '----------------------------------------' + write(fates_log(),*) ' Dumping Patch Information ' + write(fates_log(),*) ' (omitting arrays) ' + write(fates_log(),*) '----------------------------------------' + write(fates_log(),*) 'pa%patchno = ',this%patchno + write(fates_log(),*) 'pa%age = ',this%age + write(fates_log(),*) 'pa%age_class = ',this%age_class + write(fates_log(),*) 'pa%area = ',this%area + write(fates_log(),*) 'pa%countcohorts = ',this%countcohorts + write(fates_log(),*) 'pa%ncl_p = ',this%ncl_p + write(fates_log(),*) 'pa%total_canopy_area = ',this%total_canopy_area + write(fates_log(),*) 'pa%total_tree_area = ',this%total_tree_area + write(fates_log(),*) 'pa%zstar = ',this%zstar + write(fates_log(),*) 'pa%solar_zenith_flag = ',this%solar_zenith_flag + write(fates_log(),*) 'pa%solar_zenith_angle = ',this%solar_zenith_angle + write(fates_log(),*) 'pa%gnd_alb_dif = ',this%gnd_alb_dif(:) + write(fates_log(),*) 'pa%gnd_alb_dir = ',this%gnd_alb_dir(:) + write(fates_log(),*) 'pa%c_stomata = ',this%c_stomata + write(fates_log(),*) 'pa%c_lblayer = ',this%c_lblayer + write(fates_log(),*) 'pa%disturbance_rates = ',this%disturbance_rates(:) + write(fates_log(),*) 'pa%active_crown_fire_flg = ', this%active_crown_fire_flg + write(fates_log(),*) 'pa%anthro_disturbance_label = ',this%anthro_disturbance_label + write(fates_log(),*) '----------------------------------------' + + do el = 1, num_elements + write(fates_log(),*) 'element id: ',element_list(el) + write(fates_log(),*) 'seed mass: ',sum(this%litter(el)%seed) + write(fates_log(),*) 'seed germ mass: ',sum(this%litter(el)%seed_germ) + write(fates_log(),*) 'leaf fines(pft): ',sum(this%litter(el)%leaf_fines) + write(fates_log(),*) 'root fines(pft,sl): ',sum(this%litter(el)%root_fines) + write(fates_log(),*) 'ag_cwd(c): ',sum(this%litter(el)%ag_cwd) + write(fates_log(),*) 'bg_cwd(c,sl): ',sum(this%litter(el)%bg_cwd) + end do + + end subroutine Dump + + !=========================================================================== + + subroutine CheckVars(this, var_aliases, return_code) + ! + ! DESCRIPTION: + ! perform numerical checks on patch variables of interest + ! The input string is of the form: 'VAR1_NAME:VAR2_NAME:VAR3_NAME' + ! + + ! ARGUMENTS: + class(fates_patch_type), intent(in) :: this ! patch object + character(len=*), intent(in) :: var_aliases + integer, intent(out) :: return_code ! return 0 for all fine + ! return 1 if a nan detected + ! return 10+ if an overflow + ! return 100% if an underflow + ! LOCALS: + type(fates_cohort_type), pointer :: currentCohort + + ! Check through a registry of variables to check + + if (check_hlm_list(trim(var_aliases), 'co_n')) then + currentCohort => this%shortest + do while(associated(currentCohort)) + call check_var_real(currentCohort%n, 'cohort%n', return_code) + if (.not.(return_code .eq. 0)) then + call this%Dump() + call currentCohort%Dump() + return + end if + currentCohort => currentCohort%taller + end do + end if + + if (check_hlm_list(trim(var_aliases), 'co_dbh')) then + currentCohort => this%shortest + do while(associated(currentCohort)) + call check_var_real(currentCohort%dbh, 'cohort%dbh', return_code) + if (.not. (return_code .eq. 0)) then + call this%Dump() + call currentCohort%Dump() + return + end if + currentCohort => currentCohort%taller + end do + end if + + if (check_hlm_list(trim(var_aliases), 'pa_area')) then + call check_var_real(this%area, 'patch%area', return_code) + if (.not. (return_code .eq. 0)) then + call this%Dump() + return + end if + end if + + end subroutine CheckVars + + !=========================================================================== + +end module FatesPatchMod \ No newline at end of file diff --git a/biogeochem/FatesSoilBGCFluxMod.F90 b/biogeochem/FatesSoilBGCFluxMod.F90 index d14ce7b005..9d813c32b3 100644 --- a/biogeochem/FatesSoilBGCFluxMod.F90 +++ b/biogeochem/FatesSoilBGCFluxMod.F90 @@ -20,7 +20,6 @@ module FatesSoilBGCFluxMod 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 @@ -38,16 +37,15 @@ module FatesSoilBGCFluxMod 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 EDTypesMod , only : p_uptake_mode - use EDTypesMod , only : n_uptake_mode + use EDParamsMod , only : p_uptake_mode + use EDParamsMod , only : n_uptake_mode use EDTypesMod , only : ed_site_type - use EDTypesMod , only : ed_patch_type - use EDTypesMod , only : ed_cohort_type + use FatesPatchMod , only : fates_patch_type + use FatesCohortMod , only : fates_cohort_type use EDTypesMod , only : AREA,AREA_INV use FatesInterfaceTypesMod, only : bc_in_type use FatesInterfaceTypesMod, only : bc_out_type @@ -55,6 +53,7 @@ module FatesSoilBGCFluxMod use FatesInterfaceTypesMod, only : hlm_nu_com use FatesInterfaceTypesMod, only : hlm_parteh_mode use FatesInterfaceTypesMod, only : hlm_use_ch4 + use FatesInterfaceTypesMod, only : hlm_decomp use FatesConstantsMod , only : prescribed_p_uptake use FatesConstantsMod , only : prescribed_n_uptake use FatesConstantsMod , only : coupled_p_uptake @@ -63,8 +62,7 @@ module FatesSoilBGCFluxMod use FatesConstantsMod, only : g_per_kg use FatesConstantsMod, only : kg_per_g use FatesConstantsMod, only : fates_np_comp_scaling - use FatesConstantsMod, only : cohort_np_comp_scaling - use FatesConstantsMod, only : pft_np_comp_scaling + use FatesConstantsMod, only : coupled_np_comp_scaling use FatesConstantsMod, only : trivial_np_comp_scaling use FatesConstantsMod, only : rsnbl_math_prec use FatesConstantsMod, only : days_per_year @@ -88,7 +86,7 @@ module FatesSoilBGCFluxMod public :: PrepNutrientAquisitionBCs public :: UnPackNutrientAquisitionBCs public :: FluxIntoLitterPools - + public :: EffluxIntoLitterPools logical, parameter :: debug = .false. ! local debug flag character(len=*), parameter, private :: sourcefile = & @@ -97,72 +95,6 @@ module FatesSoilBGCFluxMod contains - ! ===================================================================================== - - function GetPlantDemand(ccohort,element_id) result(plant_demand) - - ! ----------------------------------------------------------------------------------- - ! This function calculates the plant's demand for a given nutrient - ! based upon the need to fill its NPP demand and/or the need to - ! get its tissues to their ideal stoichiometry ratios. - ! This routine is used for informing BGC competition schemes, and - ! for generating synthetic upake rates and also for calculating - ! diagnostics. - ! - ! THIS ROUTINE IS UNDERGOING MODIFICATIONS WILL CLEAN UP AFTER - ! A DECENT FIRST HYPOTHESIS MANIFESTS - ! ----------------------------------------------------------------------------------- - - - type(ed_cohort_type),intent(in) :: ccohort - integer,intent(in) :: element_id ! Should match nitrogen_element or - ! phosphorus_element - - real(r8) :: plant_demand ! Nutrient demand per plant [kg] - real(r8) :: plant_x ! Total mass for element of interest [kg] - real(r8) :: plant_max_x ! Maximum mass for element of interest [kg] - integer :: pft - real(r8) :: dbh - real(r8) :: leafm,fnrtm,sapwm,structm,storem - - real(r8), parameter :: smth_fac = 0.1_r8 ! Smoothing factor for updating - ! demand. - real(r8), parameter :: init_demand_frac = 0.1_r8 ! Newly recruited plants - ! will specify a demand - ! based on their total nutrient - ! because they have not history - ! of need yet - - - - pft = ccohort%pft - dbh = ccohort%dbh - - - ! If the cohort has not experienced a day of integration - ! (and thus any allocation yet), it has no deficit - ! in its storage to drive any need, so it thus has no demand - if(ccohort%isnew) then - plant_demand = 0._r8 - return - end if - - - ! If the plant is not a newly recruited plant - ! We use other methods of specifying nutrient demand - ! ----------------------------------------------------------------------------------- - - if(element_id.eq.nitrogen_element) then - - plant_demand = smth_fac*ccohort%daily_n_demand + (1._r8-smth_fac)*max(0._r8,ccohort%daily_n_need) - - elseif(element_id.eq.phosphorus_element) then - - plant_demand = smth_fac*ccohort%daily_p_demand + (1._r8-smth_fac)*max(0._r8,ccohort%daily_p_need) - - end if - - end function GetPlantDemand ! ===================================================================================== @@ -194,32 +126,15 @@ subroutine UnPackNutrientAquisitionBCs(sites, bc_in) integer :: icomp ! competitor index integer :: id ! decomp layer index integer :: pft ! pft index - type(ed_patch_type), pointer :: cpatch ! current patch pointer - type(ed_cohort_type), pointer :: ccohort ! current cohort pointer + type(fates_patch_type), pointer :: cpatch ! current patch pointer + type(fates_cohort_type), pointer :: ccohort ! current cohort pointer real(r8) :: fnrt_c ! fine-root carbon [kg] - real(r8) :: fnrt_c_pft(numpft) ! total mass of root for each PFT [kgC] nsites = size(sites,dim=1) - - ! Zero the uptake rates - do s = 1, nsites - cpatch => sites(s)%oldest_patch - do while (associated(cpatch)) - ccohort => cpatch%tallest - do while (associated(ccohort)) - ccohort%daily_nh4_uptake = 0._r8 - ccohort%daily_no3_uptake = 0._r8 - ccohort%daily_p_uptake = 0._r8 - ccohort => ccohort%shorter - end do - cpatch => cpatch%younger - end do - - end do - ! We can exit if this is a c-only simulation - if(hlm_parteh_mode.eq.prt_carbon_allom_hyp) then + select case (hlm_parteh_mode) + case (prt_carbon_allom_hyp) ! These can now be zero'd do s = 1, nsites bc_in(s)%plant_nh4_uptake_flux(:,:) = 0._r8 @@ -227,7 +142,7 @@ subroutine UnPackNutrientAquisitionBCs(sites, bc_in) bc_in(s)%plant_p_uptake_flux(:,:) = 0._r8 end do return - end if + end select do s = 1, nsites @@ -235,24 +150,45 @@ subroutine UnPackNutrientAquisitionBCs(sites, bc_in) ! then we are not coupling with the soil bgc model. ! In this case, the bc_in structure is meaningless. ! Instead, we give the plants a parameterized fraction - ! of their demand. Routine GetPlantDemand() returns - ! the plant demand. + ! of their demand. if (n_uptake_mode.eq.prescribed_n_uptake) then + cpatch => sites(s)%oldest_patch do while (associated(cpatch)) ccohort => cpatch%tallest do while (associated(ccohort)) pft = ccohort%pft + fnrt_c = ccohort%prt%GetState(fnrt_organ, carbon12_element) + ccohort%daily_n_demand = fnrt_c * & + (EDPftvarcon_inst%vmax_nh4(pft)+EDPftvarcon_inst%vmax_no3(pft)) * sec_per_day + ccohort%daily_nh4_uptake = fnrt_c*EDPftvarcon_inst%vmax_nh4(pft)*EDPftvarcon_inst%prescribed_nuptake(pft)* sec_per_day + ccohort%daily_no3_uptake = fnrt_c*EDPftvarcon_inst%vmax_no3(pft)*EDPftvarcon_inst%prescribed_nuptake(pft)* sec_per_day + ccohort => ccohort%shorter + end do + cpatch => cpatch%younger + end do - ccohort%daily_n_demand = GetPlantDemand(ccohort,nitrogen_element) - ccohort%daily_nh4_uptake = EDPftvarcon_inst%prescribed_nuptake(pft) * ccohort%daily_n_demand - ccohort%daily_no3_uptake = 0._r8 - + elseif(n_uptake_mode.eq.coupled_n_uptake) then + + icomp = 0 + cpatch => sites(s)%oldest_patch + do while (associated(cpatch)) + ccohort => cpatch%tallest + do while (associated(ccohort)) + icomp = icomp+1 + pft = ccohort%pft + fnrt_c = ccohort%prt%GetState(fnrt_organ, carbon12_element) + ccohort%daily_n_demand = fnrt_c * & + (EDPftvarcon_inst%vmax_nh4(pft)+EDPftvarcon_inst%vmax_no3(pft)) * sec_per_day + ! N Uptake: Convert g/m2/day -> kg/plant/day + ccohort%daily_nh4_uptake = bc_in(s)%plant_nh4_uptake_flux(icomp,1)*kg_per_g*AREA/ccohort%n + ccohort%daily_no3_uptake = bc_in(s)%plant_no3_uptake_flux(icomp,1)*kg_per_g*AREA/ccohort%n ccohort => ccohort%shorter end do cpatch => cpatch%younger end do + end if if (p_uptake_mode.eq.prescribed_p_uptake) then @@ -261,151 +197,34 @@ subroutine UnPackNutrientAquisitionBCs(sites, bc_in) ccohort => cpatch%tallest do while (associated(ccohort)) pft = ccohort%pft - - ccohort%daily_p_demand = GetPlantDemand(ccohort,phosphorus_element) - ccohort%daily_p_uptake = EDPftvarcon_inst%prescribed_puptake(pft) * ccohort%daily_p_demand - + fnrt_c = ccohort%prt%GetState(fnrt_organ, carbon12_element) + ccohort%daily_p_demand = fnrt_c * EDPftvarcon_inst%vmax_p(pft) * sec_per_day + ccohort%daily_p_gain = fnrt_c * EDPftvarcon_inst%vmax_p(pft) * sec_per_day * EDPftvarcon_inst%prescribed_nuptake(pft) ccohort => ccohort%shorter end do cpatch => cpatch%younger end do - end if - - - ! If nutrient competition is sent to the BGC model as PFTs - ! and not as individual cohorts, we need to unravel the input - ! boundary condition and send to cohort. We do this downscaling - ! by finding each cohort's fraction of total fine-root for the group - - n_or_p_coupled_if: if(n_uptake_mode.eq.coupled_n_uptake .or. p_uptake_mode.eq.coupled_p_uptake)then - - ! Note there are two scaling methods. Either competition for - ! N and/or P was performed by cohorts acting individually - ! (cohort_np_comp_scaling) , or as PFTs (pft_np_comp_scaling) - ! If we opt for the latter, then we assume that the nutrient - ! uptake share of the cohort, matches the fraction of root - ! mass it contributes to the group (PFT). - if(fates_np_comp_scaling.eq.pft_np_comp_scaling) then - - ! *Currently, all cohorts in a PFT have the same root - ! fraction, so all we have to to is find its total mass fraction. - - fnrt_c_pft(:) = 0._r8 - cpatch => sites(s)%oldest_patch - do while (associated(cpatch)) - ccohort => cpatch%tallest - do while (associated(ccohort)) - pft = ccohort%pft - fnrt_c_pft(pft) = fnrt_c_pft(pft) + & - ccohort%prt%GetState(fnrt_organ, all_carbon_elements)*ccohort%n - ccohort => ccohort%shorter - end do - cpatch => cpatch%younger + elseif(p_uptake_mode.eq.coupled_p_uptake) then + + icomp = 0 + cpatch => sites(s)%oldest_patch + do while (associated(cpatch)) + ccohort => cpatch%tallest + do while (associated(ccohort)) + icomp = icomp+1 + pft = ccohort%pft + fnrt_c = ccohort%prt%GetState(fnrt_organ, carbon12_element) + ccohort%daily_p_demand = fnrt_c * EDPftvarcon_inst%vmax_p(pft) * sec_per_day + ! P Uptake: Convert g/m2/day -> kg/plant/day + ccohort%daily_p_gain = bc_in(s)%plant_p_uptake_flux(icomp,1)*kg_per_g*AREA/ccohort%n + ccohort => ccohort%shorter end do - - end if ! end if(fates_np_comp_scaling.eq.pft_np_comp_scaling) then + cpatch => cpatch%younger + end do + + end if - ! -------------------------------------------------------------------------------- - ! Now that we have the arrays ready for downscaling (if needed) - ! loop through all cohorts and acquire nutrient - ! -------------------------------------------------------------------------------- - - if(n_uptake_mode.eq.coupled_n_uptake) then - - if(fates_np_comp_scaling.eq.cohort_np_comp_scaling) then - - icomp = 0 - cpatch => sites(s)%oldest_patch - do while (associated(cpatch)) - ccohort => cpatch%tallest - do while (associated(ccohort)) - icomp = icomp+1 - - ! N Uptake: Convert g/m2/day -> kg/plant/day - - ccohort%daily_nh4_uptake = sum(bc_in(s)%plant_nh4_uptake_flux(icomp,:))*kg_per_g*AREA/ccohort%n - ccohort%daily_no3_uptake = sum(bc_in(s)%plant_no3_uptake_flux(icomp,:))*kg_per_g*AREA/ccohort%n - - ccohort => ccohort%shorter - end do - cpatch => cpatch%younger - end do - - else - - cpatch => sites(s)%oldest_patch - do while (associated(cpatch)) - ccohort => cpatch%tallest - do while (associated(ccohort)) - pft = ccohort%pft - - ! Total fine-root carbon of the cohort [kgC/ha] - fnrt_c = ccohort%prt%GetState(fnrt_organ, all_carbon_elements)*ccohort%n - - ! Loop through soil layers, add up the uptake this cohort gets from each layer - do id = 1,bc_in(s)%nlevdecomp - ccohort%daily_nh4_uptake = ccohort%daily_nh4_uptake + & - bc_in(s)%plant_nh4_uptake_flux(pft,id) * & - (fnrt_c/fnrt_c_pft(pft))*kg_per_g*AREA/ccohort%n - ccohort%daily_no3_uptake = ccohort%daily_no3_uptake + & - bc_in(s)%plant_no3_uptake_flux(pft,id) * & - (fnrt_c/fnrt_c_pft(pft))*kg_per_g*AREA/ccohort%n - end do - - ccohort => ccohort%shorter - end do - cpatch => cpatch%younger - end do - - end if - - end if - - if(p_uptake_mode.eq.coupled_p_uptake) then - - if(fates_np_comp_scaling.eq.cohort_np_comp_scaling) then - - icomp = 0 - cpatch => sites(s)%oldest_patch - do while (associated(cpatch)) - ccohort => cpatch%tallest - do while (associated(ccohort)) - icomp = icomp+1 - ! P Uptake: Convert g/m2/day -> kg/plant/day - ccohort%daily_p_uptake = ccohort%daily_p_uptake + & - sum(bc_in(s)%plant_p_uptake_flux(icomp,:))*kg_per_g*AREA/ccohort%n - ccohort => ccohort%shorter - end do - cpatch => cpatch%younger - end do - - else - - cpatch => sites(s)%oldest_patch - do while (associated(cpatch)) - ccohort => cpatch%tallest - do while (associated(ccohort)) - pft = ccohort%pft - ! Total fine-root carbon of the cohort [kgC/ha] - fnrt_c = ccohort%prt%GetState(fnrt_organ, all_carbon_elements)*ccohort%n - ! Loop through soil layers, add up the uptake this cohort gets from each layer - do id = 1,bc_in(s)%nlevdecomp - ccohort%daily_p_uptake = ccohort%daily_p_uptake + & - bc_in(s)%plant_p_uptake_flux(pft,id) * & - (fnrt_c/fnrt_c_pft(pft))*kg_per_g*AREA/ccohort%n - end do - ccohort => ccohort%shorter - end do - cpatch => cpatch%younger - end do - - end if - - end if - - end if n_or_p_coupled_if - ! These can now be zero'd bc_in(s)%plant_nh4_uptake_flux(:,:) = 0._r8 bc_in(s)%plant_no3_uptake_flux(:,:) = 0._r8 @@ -430,8 +249,8 @@ subroutine PrepCH4BCs(csite,bc_in,bc_out) type(bc_out_type), intent(inout) :: bc_out type(bc_in_type), intent(in) :: bc_in - type(ed_patch_type), pointer :: cpatch ! current patch pointer - type(ed_cohort_type), pointer :: ccohort ! current cohort pointer + type(fates_patch_type), pointer :: cpatch ! current patch pointer + type(fates_cohort_type), pointer :: ccohort ! current cohort pointer integer :: pft ! plant functional type integer :: fp ! patch index of the site real(r8) :: agnpp ! Above ground daily npp @@ -446,8 +265,11 @@ subroutine PrepCH4BCs(csite,bc_in,bc_out) real(r8) :: struct_net_alloc real(r8) :: repro_net_alloc + real(r8), parameter :: ema_npp_tscale = 10._r8 ! 10 day + + ! Exit if we need not communicate with the hlm's ch4 module - if(.not.(hlm_use_ch4==itrue)) return + ! if(.not.(hlm_use_ch4==itrue) .and. .not.(hlm_parteh_mode==prt_cnp_flex_allom_hyp) ) return ! Initialize to zero bc_out%annavg_agnpp_pa(:) = 0._r8 @@ -457,11 +279,15 @@ subroutine PrepCH4BCs(csite,bc_in,bc_out) bc_out%frootc_pa(:) = 0._r8 bc_out%root_resp(:) = 0._r8 bc_out%woody_frac_aere_pa(:) = 0._r8 + bc_out%ema_npp = 0._r8 + + ! Process CH4 variables first + !if(.not.(hlm_use_ch4==itrue) .and. .not.(hlm_parteh_mode==prt_cnp_flex_allom_hyp) ) fp = 0 cpatch => csite%oldest_patch do while (associated(cpatch)) - + ! Patch ordering when passing boundary conditions ! always goes from oldest to youngest, following ! the convention of EDPatchDynamics::set_patchno() @@ -475,7 +301,7 @@ subroutine PrepCH4BCs(csite,bc_in,bc_out) ccohort => cpatch%tallest do while (associated(ccohort)) - + ! For consistency, only apply calculations to non-new ! cohorts. New cohorts will not have respiration rates ! at this point in the call sequence. @@ -483,23 +309,12 @@ subroutine PrepCH4BCs(csite,bc_in,bc_out) if(.not.ccohort%isnew) then pft = ccohort%pft - + call set_root_fraction(csite%rootfrac_scr, pft, csite%zi_soil, & bc_in%max_rooting_depth_index_col ) - + fnrt_c = ccohort%prt%GetState(fnrt_organ, carbon12_element) - - ! Fine root fraction over depth - - bc_out%rootfr_pa(fp,1:bc_in%nlevsoil) = & - bc_out%rootfr_pa(fp,1:bc_in%nlevsoil) + & - csite%rootfrac_scr(1:bc_in%nlevsoil) - - ! Fine root carbon, convert [kg/plant] -> [g/m2] - bc_out%frootc_pa(fp) = & - bc_out%frootc_pa(fp) + & - fnrt_c*ccohort%n/cpatch%area * g_per_kg - + ! [kgC/day] sapw_net_alloc = ccohort%prt%GetNetAlloc(sapw_organ, carbon12_element) * days_per_sec store_net_alloc = ccohort%prt%GetNetAlloc(store_organ, carbon12_element) * days_per_sec @@ -507,23 +322,37 @@ subroutine PrepCH4BCs(csite,bc_in,bc_out) fnrt_net_alloc = ccohort%prt%GetNetAlloc(fnrt_organ, carbon12_element) * days_per_sec struct_net_alloc = ccohort%prt%GetNetAlloc(struct_organ, carbon12_element) * days_per_sec repro_net_alloc = ccohort%prt%GetNetAlloc(repro_organ, carbon12_element) * days_per_sec - + ! [kgC/plant/day] -> [gC/m2/s] agnpp = agnpp + ccohort%n/cpatch%area * (leaf_net_alloc + repro_net_alloc + & prt_params%allom_agb_frac(pft)*(sapw_net_alloc+store_net_alloc+struct_net_alloc)) * g_per_kg - + ! [kgC/plant/day] -> [gC/m2/s] bgnpp = bgnpp + ccohort%n/cpatch%area * (fnrt_net_alloc + & (1._r8-prt_params%allom_agb_frac(pft))*(sapw_net_alloc+store_net_alloc+struct_net_alloc)) * g_per_kg - - ! (gC/m2/s) root respiration (fine root MR + total root GR) - ! RGK: We do not save root respiration and average over the day. Until we do - ! this is a best (bad) guess at fine root MR + total root GR - ! (kgC/indiv/yr) -> gC/m2/s - bc_out%root_resp(1:bc_in%nlevsoil) = bc_out%root_resp(1:bc_in%nlevsoil) + & - ccohort%resp_acc_hold*years_per_day*g_per_kg*days_per_sec* & - ccohort%n*area_inv*(1._r8-prt_params%allom_agb_frac(pft)) * csite%rootfrac_scr(1:bc_in%nlevsoil) - + + if(hlm_use_ch4==itrue)then + + ! Fine root fraction over depth + bc_out%rootfr_pa(fp,1:bc_in%nlevsoil) = & + bc_out%rootfr_pa(fp,1:bc_in%nlevsoil) + & + csite%rootfrac_scr(1:bc_in%nlevsoil) + + ! Fine root carbon, convert [kg/plant] -> [g/m2] + bc_out%frootc_pa(fp) = & + bc_out%frootc_pa(fp) + & + fnrt_c*ccohort%n/cpatch%area * g_per_kg + + ! (gC/m2/s) root respiration (fine root MR + total root GR) + ! RGK: We do not save root respiration and average over the day. Until we do + ! this is a best (bad) guess at fine root MR + total root GR + ! (kgC/indiv/yr) -> gC/m2/s + bc_out%root_resp(1:bc_in%nlevsoil) = bc_out%root_resp(1:bc_in%nlevsoil) + & + ccohort%resp_acc_hold*years_per_day*g_per_kg*days_per_sec* & + ccohort%n*area_inv*(1._r8-prt_params%allom_agb_frac(pft)) * csite%rootfrac_scr(1:bc_in%nlevsoil) + + end if + if( prt_params%woody(pft)==itrue ) then woody_area = woody_area + ccohort%c_area end if @@ -534,30 +363,35 @@ subroutine PrepCH4BCs(csite,bc_in,bc_out) ccohort => ccohort%shorter end do - - if( sum(bc_out%rootfr_pa(fp,1:bc_in%nlevsoil)) > nearzero) then - bc_out%rootfr_pa(fp,1:bc_in%nlevsoil) = & - bc_out%rootfr_pa(fp,1:bc_in%nlevsoil) / & - sum(bc_out%rootfr_pa(fp,1:bc_in%nlevsoil)) - end if - - ! RGK: These averages should switch to the new patch averaging methods - ! when available. Right now we are not doing any time averaging - ! because it would be mixing the memory of patches, which - ! would be arguably worse than just using the instantaneous value - ! gC/m2/s - bc_out%annavg_agnpp_pa(fp) = agnpp - bc_out%annavg_bgnpp_pa(fp) = bgnpp - ! gc/m2/yr - bc_out%annsum_npp_pa(fp) = (bgnpp+agnpp)*days_per_year*sec_per_day - - if(plant_area>nearzero) then - bc_out%woody_frac_aere_pa(fp) = woody_area/plant_area + if(hlm_use_ch4==itrue)then + if( sum(bc_out%rootfr_pa(fp,1:bc_in%nlevsoil)) > nearzero) then + bc_out%rootfr_pa(fp,1:bc_in%nlevsoil) = & + bc_out%rootfr_pa(fp,1:bc_in%nlevsoil) / & + sum(bc_out%rootfr_pa(fp,1:bc_in%nlevsoil)) + end if + + ! RGK: These averages should switch to the new patch averaging methods + ! when available. Right now we are not doing any time averaging + ! because it would be mixing the memory of patches, which + ! would be arguably worse than just using the instantaneous value + + ! gC/m2/s + bc_out%annavg_agnpp_pa(fp) = agnpp + bc_out%annavg_bgnpp_pa(fp) = bgnpp + ! gc/m2/yr + bc_out%annsum_npp_pa(fp) = (bgnpp+agnpp)*days_per_year*sec_per_day + + if(plant_area>nearzero) then + bc_out%woody_frac_aere_pa(fp) = woody_area/plant_area + end if + end if cpatch => cpatch%younger end do + + bc_out%ema_npp = csite%ema_npp return end subroutine PrepCH4BCs @@ -570,8 +404,7 @@ subroutine PrepNutrientAquisitionBCs(csite, bc_in, bc_out) ! This subroutine will generate the appropriate boundary condition output ! structures, depending on: ! 1) Which soil-bgc competition method is active in the HLM - ! 2) If nitrification/denitrification is turned on - ! 3) Which competitor scaling type is used + ! 2) Which competitor scaling type is used ! ----------------------------------------------------------------------------------- ! !ARGUMENTS @@ -580,307 +413,175 @@ subroutine PrepNutrientAquisitionBCs(csite, bc_in, bc_out) type(bc_out_type), intent(inout) :: bc_out ! Locals - integer :: icomp ! competitor index - integer :: j ! soil layer index - integer :: id ! decomp index (might == j) - integer :: pft ! plant functional type - type(ed_patch_type), pointer :: cpatch ! current patch pointer - type(ed_cohort_type), pointer :: ccohort ! current cohort pointer - real(r8) :: fnrt_c ! fine-root carbon [kg] - real(r8) :: veg_rootc ! fine root carbon in each layer [g/m3] - real(r8) :: dbh ! dbh (cm) - real(r8) :: npp_n_demand ! Nitrogen needed to keep up with NPP [kgN] - real(r8) :: npp_p_demand ! Phosphorus needed to keep up with NPP [kgP] - real(r8) :: deficit_n_demand ! Nitrogen needed to get stoich back to - ! optimal [kgN] - real(r8) :: deficit_p_demand ! Phosphorus needed to get stoich back to - ! optimal [kgP] - real(r8) :: comp_per_pft(numpft) ! Competitors per PFT, used for averaging - real(r8) :: decompmicc_layer ! Microbial dedcomposer biomass for current layer - integer :: comp_scaling ! Flag that defines the boundary condition scaling method (includes trivial) - - real(r8), parameter :: decompmicc_lambda = 2.5_r8 ! Depth attenuation exponent for decomposer biomass + integer :: icomp ! competitor index + integer :: j ! soil layer index + integer :: id ! decomp index (might == j) + integer :: pft ! plant functional type + type(fates_patch_type), pointer :: cpatch ! current patch pointer + type(fates_cohort_type), pointer :: ccohort ! current cohort pointer + real(r8) :: fnrt_c ! fine-root carbon [kg] + real(r8) :: veg_rootc ! fine root carbon in each layer [g/m3] + real(r8) :: decompmicc_layer ! Microbial dedcomposer biomass for current layer + + real(r8), parameter :: decompmicc_lambda = 2.5_r8 ! Depth attenuation exponent for decomposer biomass real(r8), parameter :: decompmicc_zmax = 7.0e-2_r8 ! Depth of maximum decomposer biomass - ! Determine the scaling approach - if((hlm_parteh_mode.eq.prt_cnp_flex_allom_hyp) .and. & - ((n_uptake_mode.eq.coupled_n_uptake) .or. & - (p_uptake_mode.eq.coupled_p_uptake))) then - comp_scaling = fates_np_comp_scaling - - else - - comp_scaling = trivial_np_comp_scaling - - ! Note: With ECA, we still need to update the - ! decomp microbe density even if we are not - ! fully coupled, so can't exit yet - - if(trim(hlm_nu_com).eq.'RD') then - bc_out%num_plant_comps = 1 - bc_out%n_demand(1) = 0._r8 - bc_out%p_demand(1) = 0._r8 - return + + ! Whether this is a trivial or coupled run, + ! the following variables get initialized in the same way + bc_out%veg_rootc(:,:) = 0._r8 + bc_out%ft_index(:) = -1 + if(trim(hlm_nu_com).eq.'ECA')then + bc_out%decompmicc(:) = 0._r8 + bc_out%cn_scalar(:) = 1._r8 + bc_out%cp_scalar(:) = 1._r8 + end if + + if(fates_np_comp_scaling == trivial_np_comp_scaling) then + if(trim(hlm_nu_com).eq.'RD')then + bc_out%num_plant_comps = 1 + bc_out%ft_index(1) = 1 + return end if - end if - - ! ECA Specific Parameters - ! -------------------------------------------------------------------------------- - if(trim(hlm_nu_com).eq.'ECA')then - - bc_out%veg_rootc(:,:) = 0._r8 ! Zero this, it will be incremented - bc_out%decompmicc(:) = 0._r8 - bc_out%cn_scalar(:) = 0._r8 - bc_out%cp_scalar(:) = 0._r8 - bc_out%ft_index(:) = -1 - - ! Loop over all patches and sum up the seed input for each PFT - icomp = 0 - comp_per_pft(:) = 0 ! This counts how many competitors per - ! pft, used for averaging - - cpatch => csite%oldest_patch - do while (associated(cpatch)) - - ccohort => cpatch%tallest - do while (associated(ccohort)) - - pft = ccohort%pft - ! If we are not coupling plant uptake - ! with ECA, then we send 1 token - ! competitor with plant root biomass, but no - ! uptake affinity + ! For both the trivial case with ECA, and the coupled case + ! we still need to calculate the root biomass and decompmicc + ! arrays (the former for the latter when trivial). So we + ! don't differentiate - if(comp_scaling.eq.cohort_np_comp_scaling) then - icomp = icomp+1 - bc_out%ft_index(icomp) = pft - else - icomp = pft - comp_per_pft(pft) = comp_per_pft(pft) + 1 - bc_out%ft_index(icomp) = pft - end if - - call set_root_fraction(csite%rootfrac_scr, pft, csite%zi_soil, & - bc_in%max_rooting_depth_index_col ) - - fnrt_c = ccohort%prt%GetState(fnrt_organ, carbon12_element) - - ! Map the soil layers to the decomposition layers - ! (which may be synonomous) - ! veg_rootc in units: [g/m3] = [kgC/plant] * [plant/ha] * [ha/ 10k m2] * [1000 g / kg] * [1/m] + icomp = 0 + cpatch => csite%oldest_patch + do while (associated(cpatch)) + ccohort => cpatch%tallest + do while (associated(ccohort)) - do j = 1, bc_in%nlevdecomp - id = bc_in%decomp_id(j) ! Map from soil layer to decomp layer - veg_rootc = fnrt_c * ccohort%n * csite%rootfrac_scr(j) * AREA_INV * g_per_kg / csite%dz_soil(j) - - bc_out%veg_rootc(icomp,id) = bc_out%veg_rootc(icomp,id) + veg_rootc + if(fates_np_comp_scaling .eq. coupled_np_comp_scaling) then + icomp = icomp+1 + else + icomp = 1 + end if + + pft = ccohort%pft + bc_out%ft_index(icomp) = pft + + call set_root_fraction(csite%rootfrac_scr, pft, csite%zi_soil, & + bc_in%max_rooting_depth_index_col ) + + fnrt_c = ccohort%prt%GetState(fnrt_organ, carbon12_element) + + ! Map the soil layers to the decomposition layers (which may be synonomous) + ! veg_rootc in units: [gC/m3] = [kgC/plant] * [plant/ha] * [ha/ 10k m2] * [1000 g / kg] * [1/m] + + do j = 1, bc_in%nlevdecomp + id = bc_in%decomp_id(j) ! Map from soil layer to decomp layer + veg_rootc = fnrt_c * ccohort%n * csite%rootfrac_scr(j) * AREA_INV * g_per_kg / csite%dz_soil(j) + + bc_out%veg_rootc(icomp,id) = bc_out%veg_rootc(icomp,id) + veg_rootc + + if(trim(hlm_nu_com).eq.'ECA')then - ! We use a 3 parameter exponential attenuation function to estimate decomposer biomass + ! We use a 2 parameter exponential attenuation function to estimate decomposer biomass ! The parameter EDPftvarcon_inst%decompmicc(pft) is the maximum amount found at depth ! decompmicc_zmax, and the profile attenuates with strength lambda - + decompmicc_layer = EDPftvarcon_inst%decompmicc(pft) * & exp(-decompmicc_lambda*abs(csite%z_soil(j)-decompmicc_zmax)) - + + bc_out%decompmicc(id) = bc_out%decompmicc(id) + decompmicc_layer * veg_rootc - end do - ccohort => ccohort%shorter + end if + end do - - cpatch => cpatch%younger + ccohort => ccohort%shorter end do - ! We calculate the decomposer microbial biomass by weighting with the - ! root biomass. This is just the normalization step + cpatch => cpatch%younger + end do + + ! We calculate the decomposer microbial biomass by weighting with the + ! root biomass. This is just the normalization step + if(trim(hlm_nu_com).eq.'ECA')then do id = 1,bc_in%nlevdecomp bc_out%decompmicc(id) = bc_out%decompmicc(id) / & max(nearzero,sum(bc_out%veg_rootc(:,id),dim=1)) end do + end if - if(comp_scaling.eq.cohort_np_comp_scaling) then - bc_out%num_plant_comps = icomp - elseif(comp_scaling.eq.pft_np_comp_scaling) then - bc_out%num_plant_comps = numpft - elseif(comp_scaling.eq.trivial_np_comp_scaling) then - bc_out%num_plant_comps = 1 - ! Now that the microbial density is calculated - ! we can exit the trivial case - return - end if - - coupled_n_if: if(n_uptake_mode.eq.coupled_n_uptake) then - icomp = 0 - cpatch => csite%oldest_patch - do while (associated(cpatch)) - ccohort => cpatch%tallest - do while (associated(ccohort)) + if(fates_np_comp_scaling == coupled_np_comp_scaling) then + bc_out%num_plant_comps = icomp + else + bc_out%num_plant_comps = 1 + end if + + return + end subroutine PrepNutrientAquisitionBCs - pft = ccohort%pft - if(fates_np_comp_scaling.eq.cohort_np_comp_scaling) then - icomp = icomp+1 - else - icomp = pft - end if + ! ===================================================================================== - bc_out%cn_scalar(icomp) = bc_out%cn_scalar(icomp) + & - ECACScalar(ccohort, nitrogen_element) - - ccohort => ccohort%shorter - end do - cpatch => cpatch%younger - end do + subroutine EffluxIntoLitterPools(csite, cpatch, ccohort, bc_in ) - ! Normalize the sum to a mean, if this is a PFT scale - ! boundary flux - if(fates_np_comp_scaling.eq.pft_np_comp_scaling) then - do icomp = 1, numpft - bc_out%cn_scalar(icomp) = bc_out%cn_scalar(icomp)/real(comp_per_pft(icomp),r8) - end do - end if + ! ----------------------------------------------------------------------------------- + ! This subroutine just handles the transfer of exudation/efflux from plants + ! to the HLM. We "root_fines_frag" array to save memory, and because it has + ! a labile component, soil discretization, and already has routines + ! in place for restarting and mass balancing through disturbance. + ! ----------------------------------------------------------------------------------- - else + ! Arguments + type(ed_site_type), intent(inout) :: csite + type(fates_patch_type), intent(inout) :: cpatch + type(fates_cohort_type), intent(inout),target :: ccohort + type(bc_in_type), intent(in) :: bc_in - ! If we are not coupling N, then make sure to set affinity of plants to 0 - ! (it is possible to be here if P is coupled but N is not) - bc_out%cn_scalar(:) = 0._r8 - - end if coupled_n_if + ! locals + integer :: el ! element loop index + integer :: j ! soil layer loop index + real(r8), pointer :: efflux_ptr ! pointer to cohort efflux + type(litter_type), pointer :: litt + + call set_root_fraction(csite%rootfrac_scr, & + ccohort%pft, csite%zi_soil, & + bc_in%max_rooting_depth_index_col ) + + ! Loop over the different elements. + do el = 1, num_elements - coupled_p_if: if(p_uptake_mode.eq.coupled_p_uptake) then - - icomp = 0 - cpatch => csite%oldest_patch - do while (associated(cpatch)) - ccohort => cpatch%tallest - do while (associated(ccohort)) + select case (element_list(el)) + case (carbon12_element) - pft = ccohort%pft - if(fates_np_comp_scaling.eq.cohort_np_comp_scaling) then - icomp = icomp+1 - else - icomp = pft - end if - - bc_out%cp_scalar(icomp) = bc_out%cp_scalar(icomp) + & - ECACScalar(ccohort, phosphorus_element) - - ccohort => ccohort%shorter - end do - cpatch => cpatch%younger - end do + efflux_ptr => ccohort%daily_c_efflux - if(fates_np_comp_scaling.eq.pft_np_comp_scaling) then - do icomp = 1, numpft - bc_out%cp_scalar(icomp) = bc_out%cp_scalar(icomp)/real(comp_per_pft(icomp),r8) - end do - end if - else + case (nitrogen_element) - ! If we are not coupling P, then make sure to set affinity of plants to 0 - ! (it is possible to be here if N is coupled but P is not) - bc_out%cp_scalar(:) = 0._r8 + efflux_ptr => ccohort%daily_n_efflux - end if coupled_p_if - - elseif(trim(hlm_nu_com).eq.'RD') then + case (phosphorus_element) - ! If we are using RD competition and coupling that into FATES, - ! we must update the plant's demand - ! (if this is un-coupled, the demand is handled completely in - ! the UnPack code) - ! ----------------------------------------------------------------------------------- - - if(n_uptake_mode .eq. coupled_n_uptake ) then - cpatch => csite%oldest_patch - do while (associated(cpatch)) - ccohort => cpatch%tallest - do while (associated(ccohort)) - ccohort%daily_n_demand = GetPlantDemand(ccohort,nitrogen_element) - ccohort => ccohort%shorter - end do - cpatch => cpatch%younger - end do + efflux_ptr => ccohort%daily_p_efflux - end if - - if(p_uptake_mode .eq. coupled_p_uptake ) then - cpatch => csite%oldest_patch - do while (associated(cpatch)) - ccohort => cpatch%tallest - do while (associated(ccohort)) - ccohort%daily_p_demand = GetPlantDemand(ccohort,phosphorus_element) - ccohort => ccohort%shorter - end do - cpatch => cpatch%younger - end do - end if - - ! -------------------------------------------------------------------------------- - ! Units on demand: - ! [gX/m2/s] convert [kgX/plant/day] * [plant/ha] * - ! [ha/10000 m2] * [1000 g/kg] * [1 day /86400 sec] - ! -------------------------------------------------------------------------------- - - bc_out%n_demand(:) = 0._r8 - bc_out%p_demand(:) = 0._r8 - - if(n_uptake_mode.eq.coupled_n_uptake) then - icomp = 0 - cpatch => csite%oldest_patch - do while (associated(cpatch)) - ccohort => cpatch%tallest - do while (associated(ccohort)) - pft = ccohort%pft - if(fates_np_comp_scaling.eq.cohort_np_comp_scaling) then - icomp = icomp+1 - else - icomp = pft - end if - bc_out%n_demand(icomp) = bc_out%n_demand(icomp) + & - ccohort%daily_n_demand*ccohort%n*AREA_INV*g_per_kg*days_per_sec - - ccohort => ccohort%shorter - end do - cpatch => cpatch%younger - end do - end if - - if(p_uptake_mode.eq.coupled_p_uptake) then - icomp = 0 - cpatch => csite%oldest_patch - do while (associated(cpatch)) - ccohort => cpatch%tallest - do while (associated(ccohort)) - pft = ccohort%pft - if(fates_np_comp_scaling.eq.cohort_np_comp_scaling) then - icomp = icomp+1 - else - icomp = pft - end if - bc_out%p_demand(icomp) = bc_out%p_demand(icomp) + & - ccohort%daily_p_demand*ccohort%n*AREA_INV*g_per_kg*days_per_sec - ccohort => ccohort%shorter - end do - cpatch => cpatch%younger - end do - end if + end select - if(comp_scaling.eq.cohort_np_comp_scaling) then - bc_out%num_plant_comps = icomp - elseif(comp_scaling.eq.pft_np_comp_scaling) then - bc_out%num_plant_comps = numpft - else - bc_out%num_plant_comps = 1 - end if + litt => cpatch%litter(el) - end if - - - return - end subroutine PrepNutrientAquisitionBCs + do j = 1,csite%nlevsoil + ! kg/m2/day + litt%root_fines_frag(ilabile,j) = litt%root_fines_frag(ilabile,j) + & + efflux_ptr * ccohort%n * AREA_INV * csite%rootfrac_scr(j) + + ! Note: we do not increment the site-level mass flux checking + ! variable site_mass%frag_out This will be incremented later + ! in the call sequence, and we don't want to double count. + + end do + + end do + + return + end subroutine EffluxIntoLitterPools + + ! ===================================================================================== subroutine FluxIntoLitterPools(csite, bc_in, bc_out) @@ -912,9 +613,7 @@ subroutine FluxIntoLitterPools(csite, bc_in, bc_out) ! ----------------------------------------------------------------------------------- - use FatesConstantsMod, only : sec_per_day use FatesInterfaceTypesMod, only : bc_in_type, bc_out_type - use FatesInterfaceTypesMod, only : hlm_use_vertsoilc use FatesConstantsMod, only : itrue use FatesGlobals, only : endrun => fates_endrun use EDParamsMod , only : ED_val_cwd_flig, ED_val_cwd_fcel @@ -929,13 +628,11 @@ subroutine FluxIntoLitterPools(csite, bc_in, bc_out) type(bc_out_type) , intent(inout),target :: bc_out ! !LOCAL VARIABLES: - type (ed_patch_type), pointer :: currentPatch - type (ed_cohort_type), pointer :: currentCohort + type (fates_patch_type), pointer :: currentPatch + type (fates_cohort_type), pointer :: ccohort real(r8), pointer :: flux_cel_si(:) real(r8), pointer :: flux_lab_si(:) real(r8), pointer :: flux_lig_si(:) - real(r8), pointer :: efflux_ptr ! Points to the current - ! element's root efflux type(litter_type), pointer :: litt real(r8) :: surface_prof(bc_in%nlevsoil) ! this array is used to distribute @@ -954,6 +651,21 @@ subroutine FluxIntoLitterPools(csite, bc_in, bc_out) integer :: ic ! CWD type index integer :: ipft ! PFT index + ! The following are used for the MIMICS ligC/N boundary condition + real(r8) :: leaf_c, sapw_c ! leaf and sapwood carbon, per plant [kg] + real(r8) :: fnrt_c, struct_c ! fineroot and struct carbon, per plant [kg] + real(r8) :: leaf_n, sapw_n ! leaf and sapwood N, per plant [kg] + real(r8) :: fnrt_n, struct_n ! fineroot and struct N, per plant [kg] + real(r8) :: sum_ligC ! Flux of lignin C [kg/m2/s] + real(r8) :: sum_N ! Flux of all N [kg/m2/s] + real(r8) :: tot_leaf_c ! total leaf C of all cohorts in patch [kg/m2] + real(r8) :: tot_leaf_n ! total leaf N of all cohorts in patch [kg/m2] + real(r8) :: tot_fnrt_c ! total fineroot C of all cohorts in patch [kg/m2] + real(r8) :: tot_fnrt_n ! total fineroot N of all cohorts in patch [kg/m2] + real(r8) :: tot_wood_c ! total wood C of all cohorts in patch [kg/m2] + real(r8) :: tot_wood_n ! total wood N of all cohorts in patch [kg/m2] + + ! NOTE(rgk, 201705) this parameter was brought over from SoilBiogeochemVerticalProfile ! how steep profile is for surface components (1/ e_folding depth) (1/m) real(r8), parameter :: surfprof_exp = 10. @@ -991,7 +703,7 @@ subroutine FluxIntoLitterPools(csite, bc_in, bc_out) do el = 1, num_elements ! Zero out the boundary flux arrays - ! Make a pointer to the cellulose, labile and lignan + ! Make a pointer to the cellulose, labile and lignin ! flux partitions. select case (element_list(el)) @@ -1002,15 +714,13 @@ subroutine FluxIntoLitterPools(csite, bc_in, bc_out) flux_cel_si => bc_out%litt_flux_cel_c_si(:) flux_lab_si => bc_out%litt_flux_lab_c_si(:) flux_lig_si => bc_out%litt_flux_lig_c_si(:) - - case (nitrogen_element) + case (nitrogen_element) bc_out%litt_flux_cel_n_si(:) = 0._r8 bc_out%litt_flux_lig_n_si(:) = 0._r8 bc_out%litt_flux_lab_n_si(:) = 0._r8 flux_cel_si => bc_out%litt_flux_cel_n_si(:) flux_lab_si => bc_out%litt_flux_lab_n_si(:) flux_lig_si => bc_out%litt_flux_lig_n_si(:) - case (phosphorus_element) bc_out%litt_flux_cel_p_si(:) = 0._r8 bc_out%litt_flux_lig_p_si(:) = 0._r8 @@ -1018,19 +728,8 @@ subroutine FluxIntoLitterPools(csite, bc_in, bc_out) flux_cel_si => bc_out%litt_flux_cel_p_si(:) flux_lab_si => bc_out%litt_flux_lab_p_si(:) flux_lig_si => bc_out%litt_flux_lig_p_si(:) - end select - - ! If there is any efflux (from stores overflowing) - ! than pass that to the labile litter pool - - do id = 1,nlev_eff_decomp - flux_lab_si(id) = flux_lab_si(id) + & - sum(csite%flux_diags(el)%nutrient_efflux_scpf(:)) * & - area_inv * surface_prof(id) - end do - currentPatch => csite%oldest_patch do while (associated(currentPatch)) @@ -1048,6 +747,7 @@ subroutine FluxIntoLitterPools(csite, bc_in, bc_out) flux_lig_si(id) = flux_lig_si(id) + & litt%ag_cwd_frag(ic) * ED_val_cwd_flig * area_frac * surface_prof(id) + end do do j = 1, nlev_eff_soil @@ -1063,6 +763,9 @@ subroutine FluxIntoLitterPools(csite, bc_in, bc_out) end do end do + + + ! leaf and fine root fragmentation fluxes do id = 1,nlev_eff_decomp @@ -1082,7 +785,6 @@ 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) @@ -1097,9 +799,7 @@ subroutine FluxIntoLitterPools(csite, bc_in, bc_out) end do end do - do j = 1, nlev_eff_soil - id = bc_in%decomp_id(j) flux_lab_si(id) = flux_lab_si(id) + & litt%root_fines_frag(ilabile,j) * area_frac @@ -1126,107 +826,104 @@ subroutine FluxIntoLitterPools(csite, bc_in, bc_out) end do ! do elements - return - end subroutine FluxIntoLitterPools - - ! ===================================================================================== - - function ECACScalar(ccohort, element_id) result(c_scalar) - - ! ----------------------------------------------------------------------------------- - ! This function returns the cn_scalar or cp_scalar term - ! described in: - ! Zhu, Q et al. Representing Nitrogen, Phosphorus and Carbon - ! interactions in the E3SM land model: Development and Global benchmarking. - ! Journal of Advances in Modeling Earth Systems, 11, 2238-2258, 2019. - ! https://doi.org/10.1029/2018MS001571 - ! - ! In the manuscript c_scalar is described as: "f(CN) and f(CP) account for the - ! regulation of plant nutritional level on nutrient carrier enzyme activity" - ! Also, see equations 4 and 5. - ! ----------------------------------------------------------------------------------- + ! If we are coupled with MIMICS, then we need some assessment of litter quality + ! ie ligC/totalN. If we are not tracking N in the litter flux (ie C-only model) + ! then we need to approximate this by estimating the mean C:N ratios of each + ! plant organ, and mulitplying that by the different C Fluxes to get a total + ! approximate N flux. Note, in C-only, we will not capture any re-absorption. - - ! Arguments (in) - type(ed_cohort_type), pointer :: ccohort ! current cohort pointer - integer :: element_id ! element id consistent with parteh/PRTGenericMod.F90 - - ! Arguments (out) - real(r8) :: c_scalar + if(trim(hlm_decomp).eq.'MIMICS') then - ! Locals - real(r8) :: store_frac ! Current nutrient storage relative to max - real(r8) :: store_max ! Maximum nutrient storable by plant - real(r8) :: store_c ! Current storage carbon - real(r8) :: store_c_max ! Current maximum storage carbon - integer :: icode ! real variable checking code - - integer, parameter :: downreg_linear = 1 - integer, parameter :: downreg_logi = 2 - integer, parameter :: downreg_CN_logi = 3 - - integer, parameter :: downreg_type = downreg_linear + ! If we track nitrogen (ie cnp or other) then + ! we diagnose the c-lig/n ratio directly from the pools + if(element_pos(nitrogen_element)>0) then - - real(r8), parameter :: logi_k = 25.0_r8 ! logistic function k - real(r8), parameter :: store_x0 = 1.0_r8 ! storage fraction inflection point - real(r8), parameter :: logi_min = 0.0_r8 ! minimum cn_scalar for logistic + ! Sum totalN fluxes over depth [g/m2] + sum_N = sum((bc_out%litt_flux_cel_n_si(1:nlev_eff_soil) + & + bc_out%litt_flux_lig_n_si(1:nlev_eff_soil) + & + bc_out%litt_flux_lab_n_si(1:nlev_eff_soil)) * & + bc_in%dz_sisl(1:nlev_eff_soil)) + + else + + ! In this case (Carbon Only), we use the stoichiometry parameters to estimate + ! the C:N of live vegetation and the seedbank, and use that + ! as a proxy for the C:N of the litter flux - ! This is the storage fraction where downregulation starts if using - ! a linear function - real(r8), parameter :: store_frac0 = 0.5_r8 + sum_N = 0._r8 + + currentPatch => csite%oldest_patch + do while (associated(currentPatch)) + + litt => currentPatch%litter(element_pos(carbon12_element)) + area_frac = currentPatch%area*area_inv - real(r8), parameter :: c_max = 1.0_r8 - real(r8), parameter :: c_min = 1.e-3_r8 - - - store_max = ccohort%prt%GetNutrientTarget(element_id,store_organ,stoich_max) - store_frac = min(2.0_r8,ccohort%prt%GetState(store_organ, element_id)/store_max) - - if(downreg_type == downreg_linear) then + tot_leaf_c = 0._r8 + tot_leaf_n = 0._r8 + tot_fnrt_c = 0._r8 + tot_fnrt_n = 0._r8 + tot_wood_c = 0._r8 + tot_wood_n = 0._r8 - c_scalar = min(c_max,max(c_min,1.0 - (store_frac - store_frac0)/(1.0_r8-store_frac0))) - - elseif(downreg_type == downreg_logi) then - - ! In this method, we define the c_scalar term - ! with a logistic function that goes to 1 (full need) - ! as the plant's nutrien storage hits a low threshold - ! and goes to 0, no demand, as the plant's nutrient - ! storage approaches it's maximum holding capacity + ccohort => currentPatch%tallest + do while (associated(ccohort)) + ipft = ccohort%pft + leaf_c = ccohort%n * area_inv * ccohort%prt%GetState(leaf_organ, carbon12_element) + sapw_c = ccohort%n * area_inv * ccohort%prt%GetState(sapw_organ, carbon12_element) + fnrt_c = ccohort%n * area_inv * ccohort%prt%GetState(fnrt_organ, carbon12_element) + struct_c = ccohort%n * area_inv * ccohort%prt%GetState(struct_organ, carbon12_element) + leaf_n = leaf_c * prt_params%nitr_stoich_p1(ipft,prt_params%organ_param_id(leaf_organ)) + sapw_n = sapw_c * prt_params%nitr_stoich_p1(ipft,prt_params%organ_param_id(sapw_organ)) + fnrt_n = fnrt_c * prt_params%nitr_stoich_p1(ipft,prt_params%organ_param_id(fnrt_organ)) + struct_n = struct_c * prt_params%nitr_stoich_p1(ipft,prt_params%organ_param_id(struct_organ)) + tot_leaf_c = tot_leaf_c + leaf_c + tot_leaf_n = tot_leaf_n + leaf_n + tot_fnrt_c = tot_fnrt_c + fnrt_c + tot_fnrt_n = tot_fnrt_n + fnrt_n + tot_wood_c = tot_wood_c + sapw_c + struct_c + tot_wood_n = tot_wood_n + sapw_n + struct_n + ccohort => ccohort%shorter + end do - - - c_scalar = max(c_min,min(c_max,logi_min + (1.0_r8-logi_min)/(1.0_r8 + exp(logi_k*(store_frac-store_x0))))) + if(tot_wood_c>nearzero) then + sum_N = sum_N + area_frac*sum(litt%ag_cwd_frag)*(tot_wood_n/tot_wood_c) + sum_N = sum_N + area_frac*sum(litt%bg_cwd_frag)*(tot_wood_n/tot_wood_c) + end if + if(tot_leaf_c>nearzero)then + sum_N = sum_N + area_frac*sum(litt%leaf_fines_frag)*(tot_leaf_n / tot_leaf_c) + end if + if(tot_fnrt_c>nearzero)then + sum_N = sum_N + area_frac*sum(litt%root_fines_frag)*(tot_fnrt_n / tot_fnrt_c) + end if + do ipft = 1,numpft + sum_N = sum_N + area_frac * currentPatch%nitr_repro_stoich(ipft) * & + (litt%seed_decay(ipft) + litt%seed_germ_decay(ipft)) + end do - call check_var_real(c_scalar,'c_scalar',icode) - if (icode .ne. 0) then - write(fates_log(),*) 'c_scalar is invalid, element: ',element_id - write(fates_log(),*) 'ending' - call endrun(msg=errMsg(sourcefile, __LINE__)) - endif + currentPatch => currentPatch%younger + end do + + ! Convert from kg/m2/day -> g/m2/s + sum_N = sum_N * days_per_sec * g_per_kg + + end if - else + ! Sum over layers and multiply by depth g/m3/s * m -> g/m2/s + sum_ligC = sum(bc_out%litt_flux_lig_c_si(1:nlev_eff_soil) * bc_in%dz_sisl(1:nlev_eff_soil)) + + if(sum_N>nearzero)then + bc_out%litt_flux_ligc_per_n = sum_ligC / sum_N + else + bc_out%litt_flux_ligc_per_n = 0._r8 + end if - store_c = ccohort%prt%GetState(store_organ, carbon12_element) - call bstore_allom(ccohort%dbh,ccohort%pft,ccohort%canopy_trim,store_c_max) + end if - ! Fraction of N per fraction of C - ! If this is greater than 1, then we have more N in storage than - ! we have C, so we downregulate. If this is less than 1, then - ! we have less N in storage than we have C, so up-regulate - - store_frac = store_frac / (store_c/store_c_max) - c_scalar = max(c_min,min(c_max,logi_min + (1.0_r8-logi_min)/(1.0_r8 + exp(logi_k*(store_frac-store_x0))))) - - - - end if - - end function ECACScalar + return + end subroutine FluxIntoLitterPools end module FatesSoilBGCFluxMod diff --git a/biogeophys/EDAccumulateFluxesMod.F90 b/biogeophys/EDAccumulateFluxesMod.F90 index a0fe4dd7df..f32a2f0e6e 100644 --- a/biogeophys/EDAccumulateFluxesMod.F90 +++ b/biogeophys/EDAccumulateFluxesMod.F90 @@ -9,10 +9,11 @@ module EDAccumulateFluxesMod ! Rosie Fisher. March 2014. ! ! !USES: - use FatesGlobals, only : fates_endrun + use FatesGlobals, only : endrun => fates_endrun use FatesGlobals, only : fates_log use shr_log_mod , only : errMsg => shr_log_errMsg use FatesConstantsMod , only : r8 => fates_r8 + use FatesConstantsMod , only : nocomp_bareground implicit none @@ -37,8 +38,9 @@ subroutine AccumulateFluxes_ED(nsites, sites, bc_in, bc_out, dt_time) ! ! !USES: - use EDTypesMod , only : ed_patch_type, ed_cohort_type, & - ed_site_type, AREA + use EDTypesMod , only : ed_site_type, AREA + use FatesPatchMod, only : fates_patch_type + use FatesCohortMod, only : fates_cohort_type use FatesInterfaceTypesMod , only : bc_in_type,bc_out_type ! @@ -50,8 +52,8 @@ subroutine AccumulateFluxes_ED(nsites, sites, bc_in, bc_out, dt_time) real(r8), intent(in) :: dt_time ! timestep interval ! ! !LOCAL VARIABLES: - type(ed_cohort_type), pointer :: ccohort ! current cohort - type(ed_patch_type) , pointer :: cpatch ! current patch + type(fates_cohort_type), pointer :: ccohort ! current cohort + type(fates_patch_type) , pointer :: cpatch ! current patch integer :: iv !leaf layer integer :: c ! clm/alm column integer :: s ! ed site @@ -64,7 +66,7 @@ subroutine AccumulateFluxes_ED(nsites, sites, bc_in, bc_out, dt_time) cpatch => sites(s)%oldest_patch do while (associated(cpatch)) - if(cpatch%nocomp_pft_label.ne.0)then + if(cpatch%nocomp_pft_label.ne.nocomp_bareground)then ifp = ifp+1 if( bc_in(s)%filter_photo_pa(ifp) == 3 ) then @@ -86,6 +88,8 @@ subroutine AccumulateFluxes_ED(nsites, sites, bc_in, bc_out, dt_time) ccohort%gpp_acc = ccohort%gpp_acc + ccohort%gpp_tstep ccohort%resp_acc = ccohort%resp_acc + ccohort%resp_tstep + ccohort%sym_nfix_daily = ccohort%sym_nfix_daily + ccohort%sym_nfix_tstep + ! weighted mean of D13C by gpp if((ccohort%gpp_acc + ccohort%gpp_tstep) .eq. 0.0_r8) then ccohort%c13disc_acc = 0.0_r8 diff --git a/biogeophys/EDBtranMod.F90 b/biogeophys/EDBtranMod.F90 index e36642447e..a785493d54 100644 --- a/biogeophys/EDBtranMod.F90 +++ b/biogeophys/EDBtranMod.F90 @@ -8,10 +8,11 @@ module EDBtranMod use EDPftvarcon , only : EDPftvarcon_inst use FatesConstantsMod , only : tfrz => t_water_freeze_k_1atm use FatesConstantsMod , only : itrue,ifalse,nearzero - use EDTypesMod , only : ed_site_type, & - ed_patch_type, & - ed_cohort_type, & - maxpft + use FatesConstantsMod , only : nocomp_bareground + use EDTypesMod , only : ed_site_type + use FatesPatchMod, only : fates_patch_type + use EDParamsMod, only : maxpft + use FatesCohortMod, only : fates_cohort_type use shr_kind_mod , only : r8 => shr_kind_r8 use FatesInterfaceTypesMod , only : bc_in_type, & bc_out_type, & @@ -19,11 +20,16 @@ module EDBtranMod use FatesInterfaceTypesMod , only : hlm_use_planthydro use FatesGlobals , only : fates_log use FatesAllometryMod , only : set_root_fraction + use shr_log_mod , only : errMsg => shr_log_errMsg + use FatesGlobals, only : endrun => fates_endrun ! implicit none private + + logical, parameter :: debug = .false. + public :: btran_ed public :: get_active_suction_layers public :: check_layer_water @@ -104,8 +110,8 @@ subroutine btran_ed( nsites, sites, bc_in, bc_out) ! ! !LOCAL VARIABLES: - type(ed_patch_type),pointer :: cpatch ! Current Patch Pointer - type(ed_cohort_type),pointer :: ccohort ! Current cohort pointer + type(fates_patch_type),pointer :: cpatch ! Current Patch Pointer + type(fates_cohort_type),pointer :: ccohort ! Current cohort pointer integer :: s ! site integer :: j ! soil layer integer :: ifp ! patch vector index for the site @@ -133,7 +139,7 @@ subroutine btran_ed( nsites, sites, bc_in, bc_out) ifp = 0 cpatch => sites(s)%oldest_patch do while (associated(cpatch)) - if(cpatch%nocomp_pft_label.ne.0)then ! only for veg patches + if(cpatch%nocomp_pft_label.ne.nocomp_bareground)then ! only for veg patches ifp=ifp+1 ! THIS SHOULD REALLY BE A COHORT LOOP ONCE WE HAVE rootfr_ft FOR COHORTS (RGK) @@ -231,10 +237,13 @@ subroutine btran_ed( nsites, sites, bc_in, bc_out) temprootr = sum(bc_out(s)%rootr_pasl(ifp,1:bc_in(s)%nlevsoil)) if(abs(1.0_r8-temprootr) > 1.0e-10_r8 .and. temprootr > 1.0e-10_r8)then - write(fates_log(),*) 'error with rootr in canopy fluxes',temprootr,sum_pftgs + + if(debug) write(fates_log(),*) 'error with rootr in canopy fluxes',temprootr,sum_pftgs + do j = 1,bc_in(s)%nlevsoil bc_out(s)%rootr_pasl(ifp,j) = bc_out(s)%rootr_pasl(ifp,j)/temprootr enddo + end if endif ! not bare ground cpatch => cpatch%younger diff --git a/biogeophys/EDSurfaceAlbedoMod.F90 b/biogeophys/EDSurfaceAlbedoMod.F90 index 7799ee4333..18c7e7866e 100644 --- a/biogeophys/EDSurfaceAlbedoMod.F90 +++ b/biogeophys/EDSurfaceAlbedoMod.F90 @@ -10,28 +10,30 @@ module EDSurfaceRadiationMod #include "shr_assert.h" - use EDTypesMod , only : ed_patch_type, ed_site_type - use EDTypesMod , only : maxPatchesPerSite - use EDTypesMod , only : maxpft + use EDTypesMod , only : ed_site_type + use FatesPatchMod, only : fates_patch_type + use EDParamsMod, only : maxpft use FatesConstantsMod , only : r8 => fates_r8 use FatesConstantsMod , only : itrue use FatesConstantsMod , only : pi_const + use FatesConstantsMod , only : nocomp_bareground use FatesInterfaceTypesMod , only : bc_in_type use FatesInterfaceTypesMod , only : bc_out_type use FatesInterfaceTypesMod , only : hlm_numSWb use FatesInterfaceTypesMod , only : numpft - use EDTypesMod , only : maxSWb - use EDTypesMod , only : nclmax - use EDTypesMod , only : nlevleaf + use EDParamsMod , only : maxSWb + use EDParamsMod , only : nclmax + use EDParamsMod , only : nlevleaf use EDTypesMod , only : n_rad_stream_types use EDTypesMod , only : idiffuse use EDTypesMod , only : idirect - use EDTypesMod , only : ivis - use EDTypesMod , only : inir - use EDTypesMod , only : ipar + use EDParamsMod , only : ivis + use EDParamsMod , only : inir + use EDParamsMod , only : ipar use EDCanopyStructureMod, only: calc_areaindex use FatesGlobals , only : fates_log use FatesGlobals, only : endrun => fates_endrun + use EDPftvarcon, only : EDPftvarcon_inst ! CIME globals use shr_log_mod , only : errMsg => shr_log_errMsg @@ -44,7 +46,8 @@ module EDSurfaceRadiationMod public :: ED_SunShadeFracs logical :: debug = .false. ! for debugging this module - + character(len=*), parameter, private :: sourcefile = & + __FILE__ ! real(r8), public :: albice(maxSWb) = & ! albedo land ice by waveband (1=vis, 2=nir) ! (/ 0.80_r8, 0.55_r8 /) @@ -64,14 +67,8 @@ module EDSurfaceRadiationMod subroutine ED_Norman_Radiation (nsites, sites, bc_in, bc_out ) ! - ! - ! !USES: - use EDPftvarcon , only : EDPftvarcon_inst - use EDtypesMod , only : ed_patch_type - use EDTypesMod , only : ed_site_type - - + ! !ARGUMENTS: integer, intent(in) :: nsites @@ -84,7 +81,7 @@ subroutine ED_Norman_Radiation (nsites, sites, bc_in, bc_out ) integer :: s ! site loop counter integer :: ifp ! patch loop counter integer :: ib ! radiation broad band counter - type(ed_patch_type), pointer :: currentPatch ! patch pointer + type(fates_patch_type), pointer :: currentPatch ! patch pointer !----------------------------------------------------------------------- ! ------------------------------------------------------------------------------- @@ -100,7 +97,7 @@ subroutine ED_Norman_Radiation (nsites, sites, bc_in, bc_out ) ifp = 0 currentpatch => sites(s)%oldest_patch do while (associated(currentpatch)) - if(currentpatch%nocomp_pft_label.ne.0)then + if(currentpatch%nocomp_pft_label.ne.nocomp_bareground)then ! do not do albedo calculations for bare ground patch in SP mode ! and (more impotantly) do not iterate ifp or it will mess up the indexing wherein ! ifp=1 is the first vegetated patch. @@ -193,16 +190,11 @@ subroutine PatchNormanRadiation (currentPatch, & ! ! ----------------------------------------------------------------------------------- - ! - ! !USES: - use EDPftvarcon , only : EDPftvarcon_inst - use EDtypesMod , only : ed_patch_type - ! ----------------------------------------------------------------------------------- ! !ARGUMENTS: ! ----------------------------------------------------------------------------------- - type(ed_patch_type), intent(inout), target :: currentPatch + type(fates_patch_type), intent(inout), target :: currentPatch real(r8), intent(inout) :: albd_parb_out(hlm_numSWb) real(r8), intent(inout) :: albi_parb_out(hlm_numSWb) real(r8), intent(inout) :: fabd_parb_out(hlm_numSWb) @@ -264,7 +256,6 @@ subroutine PatchNormanRadiation (currentPatch, & integer :: fp,iv,s ! array indices integer :: ib ! waveband number real(r8) :: cosz ! 0.001 <= coszen <= 1.000 - real(r8) :: chil real(r8) :: gdir @@ -362,11 +353,7 @@ subroutine PatchNormanRadiation (currentPatch, & cosz = max(0.001_r8, currentPatch%solar_zenith_angle ) !copied from previous radiation code... do ft = 1,numpft sb = (90._r8 - (acos(cosz)*180._r8/pi_const)) * (pi_const / 180._r8) - chil = xl(ft) !min(max(xl(ft), -0.4_r8), 0.6_r8 ) - if ( abs(chil) <= 0.01_r8) then - chil = 0.01_r8 - end if - phi1b(ft) = 0.5_r8 - 0.633_r8*chil - 0.330_r8*chil*chil + phi1b(ft) = 0.5_r8 - 0.633_r8*xl(ft) - 0.330_r8*xl(ft)*xl(ft) phi2b(ft) = 0.877_r8 * (1._r8 - 2._r8*phi1b(ft)) !0 = horiz leaves, 1 - vert leaves. gdir = phi1b(ft) + phi2b(ft) * sin(sb) !how much direct light penetrates a singleunit of lai? @@ -392,13 +379,16 @@ subroutine PatchNormanRadiation (currentPatch, & end do !iv end do !ft1 end do !L - if (sum(ftweight(1,:,1))<0.999_r8)then - write(fates_log(),*) 'canopy not full',ftweight(1,:,1) - endif - if (sum(ftweight(1,:,1))>1.0001_r8)then - write(fates_log(),*) 'canopy too full',ftweight(1,:,1) - endif + if(debug)then + if (sum(ftweight(1,:,1))<0.999_r8)then + write(fates_log(),*) 'canopy not full',ftweight(1,:,1) + endif + if (sum(ftweight(1,:,1))>1.0001_r8)then + write(fates_log(),*) 'canopy too full',ftweight(1,:,1) + endif + end if + do L = 1,currentPatch%NCL_p !start at the top canopy layer (1 is the top layer.) weighted_dir_tr(L) = 0.0_r8 @@ -450,11 +440,13 @@ subroutine PatchNormanRadiation (currentPatch, & !where there is a partly empty leaf layer, some fluxes go straight through. lai_change(L,ft,iv) = ftweight(L,ft,iv)-ftweight(L,ft,iv+1) endif - if (ftweight(L,ft,iv+1) - ftweight(L,ft,iv) > 1.e-10_r8)then - write(fates_log(),*) 'lower layer has more coverage. This is wrong' , & - ftweight(L,ft,iv),ftweight(L,ft,iv+1),ftweight(L,ft,iv+1)-ftweight(L,ft,iv) - endif - + if(debug)then + if (ftweight(L,ft,iv+1) - ftweight(L,ft,iv) > 1.e-10_r8)then + write(fates_log(),*) 'lower layer has more coverage. This is wrong' , & + ftweight(L,ft,iv),ftweight(L,ft,iv+1),ftweight(L,ft,iv+1)-ftweight(L,ft,iv) + endif + end if + !n.b. in theory lai_change could be calculated daily in the ED code. !This is light coming striaght through the canopy. if (L==1)then @@ -981,26 +973,30 @@ subroutine PatchNormanRadiation (currentPatch, & error = abs(currentPatch%sabs_dir(ib) - (currentPatch%tr_soil_dir(ib) * & (1.0_r8-currentPatch%gnd_alb_dir(ib) ) + & currentPatch%tr_soil_dir_dif(ib) * (1.0_r8-currentPatch%gnd_alb_dif(ib) ))) - if ( abs(error) > 0.0001)then - write(fates_log(),*)'dir ground absorption error',error,currentPatch%sabs_dir(ib), & - currentPatch%tr_soil_dir(ib)* & - (1.0_r8-currentPatch%gnd_alb_dir(ib) ),currentPatch%NCL_p,ib,sum(ftweight(1,1:numpft,1)) - write(fates_log(),*) 'albedos',currentPatch%sabs_dir(ib) ,currentPatch%tr_soil_dir(ib), & - (1.0_r8-currentPatch%gnd_alb_dir(ib) ) - - do ft =1,3 - iv = currentPatch%nrad(1,ft) + 1 - write(fates_log(),*) 'abs soil fluxes', Abs_dir_z(ft,iv),Abs_dif_z(ft,iv) - end do + if(debug)then + if ( abs(error) > 0.0001)then + write(fates_log(),*)'dir ground absorption error',error,currentPatch%sabs_dir(ib), & + currentPatch%tr_soil_dir(ib)* & + (1.0_r8-currentPatch%gnd_alb_dir(ib) ),currentPatch%NCL_p,ib,sum(ftweight(1,1:numpft,1)) + write(fates_log(),*) 'albedos',currentPatch%sabs_dir(ib) ,currentPatch%tr_soil_dir(ib), & + (1.0_r8-currentPatch%gnd_alb_dir(ib) ) + do ft =1,numpft + iv = currentPatch%nrad(1,ft) + 1 + write(fates_log(),*) 'abs soil fluxes', Abs_dir_z(ft,iv),Abs_dif_z(ft,iv) + end do + end if end if + else - if ( abs(currentPatch%sabs_dif(ib)-(currentPatch%tr_soil_dif(ib) * & - (1.0_r8-currentPatch%gnd_alb_dif(ib) ))) > 0.0001_r8)then - write(fates_log(),*)'dif ground absorption error',currentPatch%sabs_dif(ib) , & - (currentPatch%tr_soil_dif(ib)* & - (1.0_r8-currentPatch%gnd_alb_dif(ib) )),currentPatch%NCL_p,ib,sum(ftweight(1,1:numpft,1)) - endif + if (debug) then + if ( abs(currentPatch%sabs_dif(ib)-(currentPatch%tr_soil_dif(ib) * & + (1.0_r8-currentPatch%gnd_alb_dif(ib) ))) > 0.0001_r8)then + write(fates_log(),*)'dif ground absorption error',currentPatch%sabs_dif(ib) , & + (currentPatch%tr_soil_dif(ib)* & + (1.0_r8-currentPatch%gnd_alb_dif(ib) )),currentPatch%NCL_p,ib,sum(ftweight(1,1:numpft,1)) + endif + end if endif if (radtype == idirect)then @@ -1044,16 +1040,18 @@ subroutine PatchNormanRadiation (currentPatch, & ! to the complexity of this code, but where the system generates occasional errors, we ! will deal with them for now. end if + if (abs(error) > 0.15_r8)then - write(fates_log(),*) 'Large Dir Radn consvn error',error ,ib - write(fates_log(),*) 'diags', albd_parb_out(ib), ftdd_parb_out(ib), & - ftid_parb_out(ib), fabd_parb_out(ib) - write(fates_log(),*) 'elai',currentpatch%elai_profile(currentpatch%ncl_p,1:numpft,1:diag_nlevleaf) - write(fates_log(),*) 'esai',currentpatch%esai_profile(currentpatch%ncl_p,1:numpft,1:diag_nlevleaf) - write(fates_log(),*) 'ftweight',ftweight(1,1:numpft,1:diag_nlevleaf) - write(fates_log(),*) 'cp',currentPatch%area, currentPatch%patchno - write(fates_log(),*) 'ground albedo diffuse (ib)', currentPatch%gnd_alb_dir(ib) - + if(debug)then + write(fates_log(),*) 'Large Dir Radn consvn error',error ,ib + write(fates_log(),*) 'diags', albd_parb_out(ib), ftdd_parb_out(ib), & + ftid_parb_out(ib), fabd_parb_out(ib) + write(fates_log(),*) 'elai',currentpatch%elai_profile(currentpatch%ncl_p,1:numpft,1:diag_nlevleaf) + write(fates_log(),*) 'esai',currentpatch%esai_profile(currentpatch%ncl_p,1:numpft,1:diag_nlevleaf) + write(fates_log(),*) 'ftweight',ftweight(1,1:numpft,1:diag_nlevleaf) + write(fates_log(),*) 'cp',currentPatch%area, currentPatch%patchno + write(fates_log(),*) 'ground albedo diffuse (ib)', currentPatch%gnd_alb_dir(ib) + end if albd_parb_out(ib) = albd_parb_out(ib) + error end if else @@ -1063,20 +1061,21 @@ subroutine PatchNormanRadiation (currentPatch, & end if if (abs(error) > 0.15_r8)then - write(fates_log(),*) 'lg Dif Radn consvn error',error ,ib - write(fates_log(),*) 'diags', albi_parb_out(ib), ftii_parb_out(ib), & - fabi_parb_out(ib) - !write(fates_log(),*) 'lai_change',lai_change(currentpatch%ncl_p,1:numpft,1:diag_nlevleaf) - !write(fates_log(),*) 'elai',currentpatch%elai_profile(currentpatch%ncl_p,1:numpft,1:diag_nlevleaf) - !write(fates_log(),*) 'esai',currentpatch%esai_profile(currentpatch%ncl_p,1:numpft,1:diag_nlevleaf) - !write(fates_log(),*) 'ftweight',ftweight(currentpatch%ncl_p,1:numpft,1:diag_nlevleaf) - write(fates_log(),*) 'cp',currentPatch%area, currentPatch%patchno - write(fates_log(),*) 'ground albedo diffuse (ib)', currentPatch%gnd_alb_dir(ib) - !write(fates_log(),*) 'rhol',rhol(1:numpft,:) - !write(fates_log(),*) 'ftw',sum(ftweight(1,1:numpft,1)),ftweight(1,1:numpft,1) - !write(fates_log(),*) 'present',currentPatch%canopy_mask(1,1:numpft) - !write(fates_log(),*) 'CAP',currentPatch%canopy_area_profile(1,1:numpft,1) - + if(debug)then + write(fates_log(),*) 'lg Dif Radn consvn error',error ,ib + write(fates_log(),*) 'diags', albi_parb_out(ib), ftii_parb_out(ib), & + fabi_parb_out(ib) + !write(fates_log(),*) 'lai_change',lai_change(currentpatch%ncl_p,1:numpft,1:diag_nlevleaf) + !write(fates_log(),*) 'elai',currentpatch%elai_profile(currentpatch%ncl_p,1:numpft,1:diag_nlevleaf) + !write(fates_log(),*) 'esai',currentpatch%esai_profile(currentpatch%ncl_p,1:numpft,1:diag_nlevleaf) + !write(fates_log(),*) 'ftweight',ftweight(currentpatch%ncl_p,1:numpft,1:diag_nlevleaf) + write(fates_log(),*) 'cp',currentPatch%area, currentPatch%patchno + write(fates_log(),*) 'ground albedo diffuse (ib)', currentPatch%gnd_alb_dir(ib) + !write(fates_log(),*) 'rhol',rhol(1:numpft,:) + !write(fates_log(),*) 'ftw',sum(ftweight(1,1:numpft,1)),ftweight(1,1:numpft,1) + !write(fates_log(),*) 'present',currentPatch%canopy_mask(1,1:numpft) + !write(fates_log(),*) 'CAP',currentPatch%canopy_area_profile(1,1:numpft,1) + end if albi_parb_out(ib) = albi_parb_out(ib) + error end if @@ -1088,10 +1087,12 @@ subroutine PatchNormanRadiation (currentPatch, & (fabi_parb_out(ib) + albi_parb_out(ib) + currentPatch%sabs_dif(ib)) endif - if (abs(error) > 0.00000001_r8)then - write(fates_log(),*) 'there is still error after correction',error ,ib + if(debug) then + if (abs(error) > 0.00000001_r8)then + write(fates_log(),*) 'there is still error after correction',error ,ib + end if end if - + end if end do !hlm_numSWb @@ -1116,7 +1117,7 @@ subroutine ED_SunShadeFracs(nsites, sites,bc_in,bc_out) ! locals - type (ed_patch_type),pointer :: cpatch ! c"urrent" patch + type (fates_patch_type),pointer :: cpatch ! c"urrent" patch real(r8) :: sunlai real(r8) :: shalai real(r8) :: elai @@ -1133,7 +1134,7 @@ subroutine ED_SunShadeFracs(nsites, sites,bc_in,bc_out) cpatch => sites(s)%oldest_patch do while (associated(cpatch)) - if(cpatch%nocomp_pft_label.ne.0)then !only for veg patches + if(cpatch%nocomp_pft_label.ne.nocomp_bareground)then !only for veg patches ! do not do albedo calculations for bare ground patch in SP mode ! and (more impotantly) do not iterate ifp or it will mess up the indexing wherein ! ifp=1 is the first vegetated patch. @@ -1198,11 +1199,13 @@ subroutine ED_SunShadeFracs(nsites, sites,bc_in,bc_out) bc_out(s)%fsun_pa(ifp) = 0._r8 endif - if(bc_out(s)%fsun_pa(ifp) > 1._r8)then - write(fates_log(),*) 'too much leaf area in profile', bc_out(s)%fsun_pa(ifp), & - sunlai,shalai - endif - + if(debug)then + if(bc_out(s)%fsun_pa(ifp) > 1._r8)then + write(fates_log(),*) 'too much leaf area in profile', bc_out(s)%fsun_pa(ifp), & + sunlai,shalai + endif + end if + elai = calc_areaindex(cpatch,'elai') bc_out(s)%laisun_pa(ifp) = elai*bc_out(s)%fsun_pa(ifp) diff --git a/biogeophys/FatesBstressMod.F90 b/biogeophys/FatesBstressMod.F90 index c56b4930f5..f37ab8ccb1 100644 --- a/biogeophys/FatesBstressMod.F90 +++ b/biogeophys/FatesBstressMod.F90 @@ -7,10 +7,10 @@ module FatesBstressMod ! use FatesConstantsMod , only : tfrz => t_water_freeze_k_1atm use FatesConstantsMod , only : itrue,ifalse - use EDTypesMod , only : ed_site_type, & - ed_patch_type, & - ed_cohort_type, & - maxpft + use EDParamsMod, only : maxpft + use EDTypesMod , only : ed_site_type + use FatesPatchMod, only : fates_patch_type + use FatesCohortMod , only : fates_cohort_type use shr_kind_mod , only : r8 => shr_kind_r8 use FatesInterfaceTypesMod , only : bc_in_type, & bc_out_type, & @@ -48,8 +48,8 @@ subroutine btran_sal_stress_fates( nsites, sites, bc_in) ! ! !LOCAL VARIABLES: - type(ed_patch_type),pointer :: cpatch ! Current Patch Pointer - type(ed_cohort_type),pointer :: ccohort ! Current cohort pointer + type(fates_patch_type),pointer :: cpatch ! Current Patch Pointer + type(fates_cohort_type),pointer :: ccohort ! Current cohort pointer integer :: s ! site integer :: j ! soil layer integer :: ft ! plant functional type index diff --git a/biogeophys/FatesPlantHydraulicsMod.F90 b/biogeophys/FatesPlantHydraulicsMod.F90 index 5571adc089..e38e042252 100644 --- a/biogeophys/FatesPlantHydraulicsMod.F90 +++ b/biogeophys/FatesPlantHydraulicsMod.F90 @@ -42,20 +42,21 @@ module FatesPlantHydraulicsMod use FatesConstantsMod, only : cm3_per_m3 use FatesConstantsMod, only : kg_per_g use FatesConstantsMod, only : fates_unset_r8 + use FatesConstantsMod, only : nocomp_bareground use EDParamsMod , only : hydr_kmax_rsurf1 use EDParamsMod , only : hydr_kmax_rsurf2 use EDParamsMod , only : hydr_psi0 use EDParamsMod , only : hydr_psicap use EDParamsMod , only : hydr_htftype_node - use EDParamsMod , only : hydr_solver_type + use EDParamsMod , only : hydr_solver use EDTypesMod , only : ed_site_type - use EDTypesMod , only : ed_patch_type - use EDTypesMod , only : ed_cohort_type + use FatesPatchMod , only : fates_patch_type + use FatesCohortMod , only : fates_cohort_type use EDTypesMod , only : AREA_INV use EDTypesMod , only : AREA - use EDTypesMod , only : leaves_on + use FatesConstantsMod , only : leaves_on use FatesInterfaceTypesMod , only : bc_in_type use FatesInterfaceTypesMod , only : bc_out_type @@ -97,8 +98,6 @@ module FatesPlantHydraulicsMod use PRTGenericMod, only : num_elements use PRTGenericMod, only : element_list - use clm_time_manager , only : get_step_size, get_nstep - use EDPftvarcon, only : EDPftvarcon_inst use PRTParametersMod, only : prt_params @@ -253,7 +252,6 @@ module FatesPlantHydraulicsMod public :: InitHydrCohort public :: DeallocateHydrCohort public :: UpdateH2OVeg - public :: CopyCohortHydraulics public :: FuseCohortHydraulics public :: UpdateSizeDepPlantHydProps public :: UpdateSizeDepPlantHydStates @@ -337,8 +335,8 @@ subroutine RestartHydrStates(sites,nsites,bc_in,bc_out) ! locals ! ---------------------------------------------------------------------------------- ! LL pointers - type(ed_patch_type),pointer :: cpatch ! current patch - type(ed_cohort_type),pointer :: ccohort ! current cohort + type(fates_patch_type),pointer :: cpatch ! current patch + type(fates_cohort_type),pointer :: ccohort ! current cohort type(ed_cohort_hydr_type),pointer :: ccohort_hydr type(ed_site_hydr_type),pointer :: csite_hydr integer :: s ! site loop counter @@ -367,7 +365,7 @@ subroutine RestartHydrStates(sites,nsites,bc_in,bc_out) ccohort_hydr => ccohort%co_hydr ! This calculates node heights - call UpdatePlantHydrNodes(ccohort,ccohort%pft,ccohort%hite, & + call UpdatePlantHydrNodes(ccohort,ccohort%pft,ccohort%height, & sites(s)%si_hydr) ! This calculates volumes and lengths @@ -534,7 +532,7 @@ subroutine InitPlantHydStates(site, cohort) ! !ARGUMENTS: type(ed_site_type), intent(inout), target :: site ! current site pointer - type(ed_cohort_type), intent(inout), target :: cohort ! current cohort pointer + type(fates_cohort_type), intent(inout), target :: cohort ! current cohort pointer ! ! !LOCAL VARIABLES: type(ed_site_hydr_type), pointer :: csite_hydr @@ -683,7 +681,7 @@ subroutine UpdatePlantPsiFTCFromTheta(ccohort,csite_hydr) ! of total conductivity based on the relative water ! content ! Arguments - type(ed_cohort_type),intent(inout), target :: ccohort + type(fates_cohort_type),intent(inout), target :: ccohort type(ed_site_hydr_type),intent(in), target :: csite_hydr ! Locals @@ -743,7 +741,7 @@ subroutine UpdatePlantHydrNodes(ccohort,ft,plant_height,csite_hydr) ! -------------------------------------------------------------------------------- ! Arguments - type(ed_cohort_type), intent(inout) :: ccohort + type(fates_cohort_type), intent(inout) :: ccohort integer,intent(in) :: ft ! plant functional type index real(r8), intent(in) :: plant_height ! [m] type(ed_site_hydr_type), intent(in) :: csite_hydr @@ -846,7 +844,7 @@ subroutine UpdateSizeDepPlantHydProps(currentSite,ccohort,bc_in) ! ARGUMENTS: type(ed_site_type) , intent(in) :: currentSite ! Site stuff - type(ed_cohort_type) , intent(inout) :: ccohort ! current cohort pointer + type(fates_cohort_type) , intent(inout) :: ccohort ! current cohort pointer type(bc_in_type) , intent(in) :: bc_in ! Boundary Conditions ! Locals @@ -864,7 +862,7 @@ subroutine UpdateSizeDepPlantHydProps(currentSite,ccohort,bc_in) call SavePreviousCompartmentVolumes(ccohort_hydr) ! This updates all of the z_node positions - call UpdatePlantHydrNodes(ccohort,ft,ccohort%hite,currentSite%si_hydr) + call UpdatePlantHydrNodes(ccohort,ft,ccohort%height,currentSite%si_hydr) ! This updates plant compartment volumes, lengths and ! maximum conductances. Make sure for already @@ -895,7 +893,7 @@ subroutine UpdatePlantHydrLenVol(ccohort,csite_hydr) ! ----------------------------------------------------------------------------------- ! Arguments - type(ed_cohort_type),intent(inout) :: ccohort + type(fates_cohort_type),intent(inout) :: ccohort type(ed_site_hydr_type),intent(in) :: csite_hydr type(ed_cohort_hydr_type),pointer :: ccohort_hydr ! Plant hydraulics structure @@ -925,12 +923,15 @@ subroutine UpdatePlantHydrLenVol(ccohort,csite_hydr) integer :: nlevrhiz ! number of rhizosphere levels real(r8) :: dbh ! the dbh of current cohort [cm] real(r8) :: z_fr ! rooting depth of a cohort [cm] - + real(r8) :: v_leaf_donate(1:n_hypool_leaf) ! the volume that leaf will donate to xylem + ! We allow the transporting root to donate a fraction of its volume to the absorbing ! roots to help mitigate numerical issues due to very small volumes. This is the ! fraction the transporting roots donate to those layers real(r8), parameter :: t2aroot_vol_donate_frac = 0.65_r8 - + real(r8), parameter :: l2sap_vol_donate_frac = 0.5_r8 ! Junyan added + + real(r8), parameter :: min_leaf_frac = 0.1_r8 ! Fraction of maximum leaf carbon that ! we set as our lower cap on leaf volume real(r8), parameter :: min_trim = 0.1_r8 ! The lower cap on trimming function used @@ -979,7 +980,8 @@ subroutine UpdatePlantHydrLenVol(ccohort,csite_hydr) ! Get the target, or rather, maximum leaf carrying capacity of plant ! Lets also avoid super-low targets that have very low trimming functions - call bleaf(ccohort%dbh,ccohort%pft,max(ccohort%canopy_trim,min_trim),leaf_c_target) + call bleaf(ccohort%dbh,ccohort%pft,ccohort%crowndamage, & + max(ccohort%canopy_trim,min_trim),ccohort%efleaf_coh, leaf_c_target) if( (ccohort%status_coh == leaves_on) .or. ccohort_hydr%is_newly_recruited ) then ccohort_hydr%v_ag(1:n_hypool_leaf) = max(leaf_c,min_leaf_frac*leaf_c_target) * & @@ -994,21 +996,30 @@ subroutine UpdatePlantHydrLenVol(ccohort,csite_hydr) ! v_stem = c_stem_biom / (prt_params%wood_density(ft) * kg_per_g * cm3_per_m3 ) ! calculate the sapwood cross-sectional area - call bsap_allom(ccohort%dbh,ccohort%pft,ccohort%canopy_trim,a_sapwood_target,sapw_c_target) + call bsap_allom(ccohort%dbh,ccohort%pft,ccohort%crowndamage, & + ccohort%canopy_trim, ccohort%efstem_coh, a_sapwood_target,sapw_c_target) ! uncomment this if you want to use ! the actual sapwood, which may be lower than target due to branchfall. a_sapwood = a_sapwood_target ! * sapw_c / sapw_c_target ! alternative cross section calculation - ! a_sapwood = a_leaf_tot / ( 0.001_r8 + 0.025_r8 * ccohort%hite ) * 1.e-4_r8 + ! a_sapwood = a_leaf_tot / ( 0.001_r8 + 0.025_r8 * ccohort%height ) * 1.e-4_r8 - !call CrownDepth(ccohort%hite,ft,crown_depth) - crown_depth = min(ccohort%hite,0.1_r8) - z_stem = ccohort%hite - crown_depth + !call CrownDepth(ccohort%height,ft,crown_depth) + crown_depth = min(ccohort%height,0.1_r8) + z_stem = ccohort%height - crown_depth v_sapwood = a_sapwood * z_stem ! + 0.333_r8*a_sapwood*crown_depth - ccohort_hydr%v_ag(n_hypool_leaf+1:n_hypool_ag) = v_sapwood / n_hypool_stem + ! Junyan changed the following code to calculate the above ground node volume + ! foliage donate half of its water volume to xylem for grass + if (prt_params%woody(ft)==1) then + ccohort_hydr%v_ag(n_hypool_leaf+1:n_hypool_ag) = v_sapwood / n_hypool_stem ! original code + else + v_leaf_donate(1:n_hypool_leaf) = ccohort_hydr%v_ag(1:n_hypool_leaf) * l2sap_vol_donate_frac + ccohort_hydr%v_ag(1:n_hypool_leaf) = ccohort_hydr%v_ag(1:n_hypool_leaf) - v_leaf_donate(1:n_hypool_leaf) + ccohort_hydr%v_ag(n_hypool_leaf+1:n_hypool_ag) = (v_sapwood + sum(v_leaf_donate(1:n_hypool_leaf))) / n_hypool_stem + end if ! Determine belowground biomass as a function of total (sapwood, heartwood, ! leaf, fine root) biomass then subtract out the fine root biomass to get @@ -1084,7 +1095,7 @@ subroutine UpdateSizeDepPlantHydStates(currentSite,ccohort) ! !ARGUMENTS: type(ed_site_type) , intent(in) :: currentSite ! Site stuff - type(ed_cohort_type) , intent(inout) :: ccohort + type(fates_cohort_type) , intent(inout) :: ccohort ! ! !LOCAL VARIABLES: type(ed_cohort_hydr_type), pointer :: ccohort_hydr @@ -1094,7 +1105,6 @@ subroutine UpdateSizeDepPlantHydStates(currentSite,ccohort) real(r8) :: th_uncorr ! Uncorrected water content real(r8), parameter :: small_theta_num = 1.e-7_r8 ! avoids theta values equalling thr or ths [m3 m-3] - integer :: nstep !number of time steps !----------------------------------------------------------------------- ccohort_hydr => ccohort%co_hydr @@ -1184,79 +1194,11 @@ end function constrain_water_contents ! ===================================================================================== -subroutine CopyCohortHydraulics(newCohort, oldCohort) - - ! Arguments - type(ed_cohort_type), intent(inout), target :: newCohort - type(ed_cohort_type), intent(inout), target :: oldCohort - - ! Locals - type(ed_cohort_hydr_type), pointer :: ncohort_hydr - type(ed_cohort_hydr_type), pointer :: ocohort_hydr - - - ncohort_hydr => newCohort%co_hydr - ocohort_hydr => oldCohort%co_hydr - - ! Node heights - ncohort_hydr%z_node_ag = ocohort_hydr%z_node_ag - ncohort_hydr%z_upper_ag = ocohort_hydr%z_upper_ag - ncohort_hydr%z_lower_ag = ocohort_hydr%z_lower_ag - ncohort_hydr%z_node_troot = ocohort_hydr%z_node_troot - - ! Compartment kmax's - ncohort_hydr%kmax_petiole_to_leaf = ocohort_hydr%kmax_petiole_to_leaf - ncohort_hydr%kmax_stem_lower = ocohort_hydr%kmax_stem_lower - ncohort_hydr%kmax_stem_upper = ocohort_hydr%kmax_stem_upper - ncohort_hydr%kmax_troot_upper = ocohort_hydr%kmax_troot_upper - ncohort_hydr%kmax_troot_lower = ocohort_hydr%kmax_troot_lower - ncohort_hydr%kmax_aroot_upper = ocohort_hydr%kmax_aroot_upper - ncohort_hydr%kmax_aroot_lower = ocohort_hydr%kmax_aroot_lower - ncohort_hydr%kmax_aroot_radial_in = ocohort_hydr%kmax_aroot_radial_in - ncohort_hydr%kmax_aroot_radial_out = ocohort_hydr%kmax_aroot_radial_out - - ! Compartment volumes - ncohort_hydr%v_ag_init = ocohort_hydr%v_ag_init - ncohort_hydr%v_ag = ocohort_hydr%v_ag - ncohort_hydr%v_troot_init = ocohort_hydr%v_troot_init - ncohort_hydr%v_troot = ocohort_hydr%v_troot - ncohort_hydr%v_aroot_layer_init = ocohort_hydr%v_aroot_layer_init - ncohort_hydr%v_aroot_layer = ocohort_hydr%v_aroot_layer - ncohort_hydr%l_aroot_layer = ocohort_hydr%l_aroot_layer - - ! State Variables - ncohort_hydr%th_ag = ocohort_hydr%th_ag - ncohort_hydr%th_troot = ocohort_hydr%th_troot - ncohort_hydr%th_aroot = ocohort_hydr%th_aroot - ncohort_hydr%psi_ag = ocohort_hydr%psi_ag - ncohort_hydr%psi_troot = ocohort_hydr%psi_troot - ncohort_hydr%psi_aroot = ocohort_hydr%psi_aroot - ncohort_hydr%ftc_ag = ocohort_hydr%ftc_ag - ncohort_hydr%ftc_troot = ocohort_hydr%ftc_troot - ncohort_hydr%ftc_aroot = ocohort_hydr%ftc_aroot - - ! Other - ncohort_hydr%btran = ocohort_hydr%btran - ncohort_hydr%supsub_flag = ocohort_hydr%supsub_flag - ncohort_hydr%iterh1 = ocohort_hydr%iterh1 - ncohort_hydr%iterh2 = ocohort_hydr%iterh2 - ncohort_hydr%iterlayer = ocohort_hydr%iterlayer - ncohort_hydr%errh2o = ocohort_hydr%errh2o - - - ! BC PLANT HYDRAULICS - flux terms - ncohort_hydr%qtop = ocohort_hydr%qtop - - ncohort_hydr%is_newly_recruited = ocohort_hydr%is_newly_recruited - -end subroutine CopyCohortHydraulics - -! ===================================================================================== subroutine FuseCohortHydraulics(currentSite,currentCohort, nextCohort, bc_in, newn) - type(ed_cohort_type), intent(inout), target :: currentCohort ! current cohort - type(ed_cohort_type), intent(inout), target :: nextCohort ! next (donor) cohort + type(fates_cohort_type), intent(inout), target :: currentCohort ! current cohort + type(fates_cohort_type), intent(inout), target :: nextCohort ! next (donor) cohort type(ed_site_type), intent(inout), target :: currentSite ! current site type(bc_in_type), intent(in) :: bc_in @@ -1286,7 +1228,7 @@ subroutine FuseCohortHydraulics(currentSite,currentCohort, nextCohort, bc_in, ne call SavePreviousCompartmentVolumes(ccohort_hydr) ! This updates all of the z_node positions - call UpdatePlantHydrNodes(currentCohort,ft,currentCohort%hite,csite_hydr) + call UpdatePlantHydrNodes(currentCohort,ft,currentCohort%height,csite_hydr) ! This updates plant compartment volumes, lengths and ! maximum conductances. Make sure for already @@ -1361,7 +1303,7 @@ subroutine InitHydrCohort(currentSite,currentCohort) ! Arguments type(ed_site_type), target :: currentSite - type(ed_cohort_type), target :: currentCohort + type(fates_cohort_type), target :: currentCohort type(ed_cohort_hydr_type), pointer :: ccohort_hydr if ( hlm_use_planthydro.eq.ifalse ) return @@ -1377,7 +1319,7 @@ end subroutine InitHydrCohort subroutine DeallocateHydrCohort(currentCohort) ! Arguments - type(ed_cohort_type), target :: currentCohort + type(fates_cohort_type), target :: currentCohort type(ed_cohort_hydr_type), pointer :: ccohort_hydr if ( hlm_use_planthydro.eq.ifalse ) return @@ -1468,7 +1410,7 @@ subroutine InitHydrSites(sites,bc_in) case(rhizlayer_aggmeth_none) csite_hydr%nlevrhiz = bc_in(s)%nlevsoil - call sites(s)%si_hydr%InitHydrSite(numpft,nlevsclass,hydr_solver_type,bc_in(s)%nlevsoil) + call sites(s)%si_hydr%InitHydrSite(numpft,nlevsclass,hydr_solver,bc_in(s)%nlevsoil) do j=1,csite_hydr%nlevrhiz csite_hydr%map_r2s(j,1) = j @@ -1480,7 +1422,7 @@ subroutine InitHydrSites(sites,bc_in) case(rhizlayer_aggmeth_combine12) csite_hydr%nlevrhiz = max(1,bc_in(s)%nlevsoil-1) - call sites(s)%si_hydr%InitHydrSite(numpft,nlevsclass,hydr_solver_type,bc_in(s)%nlevsoil) + call sites(s)%si_hydr%InitHydrSite(numpft,nlevsclass,hydr_solver,bc_in(s)%nlevsoil) csite_hydr%map_r2s(1,1) = 1 j_bc = min(2,bc_in(s)%nlevsoil) ! this protects 1 soil layer @@ -1498,7 +1440,7 @@ subroutine InitHydrSites(sites,bc_in) case(rhizlayer_aggmeth_balN) csite_hydr%nlevrhiz = min(aggN,bc_in(s)%nlevsoil) - call sites(s)%si_hydr%InitHydrSite(numpft,nlevsclass,hydr_solver_type,bc_in(s)%nlevsoil) + call sites(s)%si_hydr%InitHydrSite(numpft,nlevsclass,hydr_solver,bc_in(s)%nlevsoil) ntoagg = int(ceiling(real(bc_in(s)%nlevsoil)/real(csite_hydr%nlevrhiz)-nearzero)) @@ -1765,18 +1707,14 @@ subroutine UpdateH2OVeg(csite,bc_out,prev_site_h2o,icall) ! Locals - type(ed_cohort_type), pointer :: currentCohort - type(ed_patch_type), pointer :: currentPatch + type(fates_cohort_type), pointer :: currentCohort + type(fates_patch_type), pointer :: currentPatch type(ed_cohort_hydr_type), pointer :: ccohort_hydr type(ed_site_hydr_type), pointer :: csite_hydr integer :: s real(r8) :: balive_patch - integer :: nstep !number of time steps - - !for debug only - nstep = get_nstep() - bc_out%plant_stored_h2o_si = 0.0_r8 + bc_out%plant_stored_h2o_si = 0.0_r8 if( hlm_use_planthydro.eq.ifalse ) return @@ -1852,12 +1790,11 @@ subroutine RecruitWUptake(nsites,sites,bc_in,dtime,recruitflag) logical, intent(out) :: recruitflag !flag to check if there is newly recruited cohorts ! Locals - type(ed_cohort_type), pointer :: currentCohort - type(ed_patch_type), pointer :: currentPatch + type(fates_cohort_type), pointer :: currentCohort + type(fates_patch_type), pointer :: currentPatch type(ed_cohort_hydr_type), pointer :: ccohort_hydr type(ed_site_hydr_type), pointer :: csite_hydr integer :: s, j, ft - integer :: nstep !number of time steps real(r8) :: rootfr !fraction of root in different soil layer real(r8) :: recruitw !water for newly recruited cohorts (kg water/m2/s) real(r8) :: recruitw_total ! total water for newly recruited cohorts (kg water/m2/s) @@ -1919,7 +1856,7 @@ end subroutine RecruitWUptake !===================================================================================== -subroutine ConstrainRecruitNumber(csite,ccohort, bc_in) +subroutine ConstrainRecruitNumber(csite,ccohort, cpatch, bc_in, mean_temp) ! --------------------------------------------------------------------------- ! This subroutine constrains the number of plants so that there is enought water @@ -1928,13 +1865,14 @@ subroutine ConstrainRecruitNumber(csite,ccohort, bc_in) ! Arguments type(ed_site_type), intent(inout), target :: csite - type(ed_cohort_type) , intent(inout), target :: ccohort + type(fates_cohort_type) , intent(inout), target :: ccohort + type(fates_patch_type), intent(inout), target :: cpatch type(bc_in_type) , intent(in) :: bc_in + real(r8), intent(in) :: mean_temp ! Locals type(ed_cohort_hydr_type), pointer :: ccohort_hydr type(ed_site_hydr_type), pointer :: csite_hydr - type(ed_patch_type), pointer :: cpatch real(r8) :: tmp1 real(r8) :: watres_local ! minum water content [m3/m3] real(r8) :: total_water ! total water in rhizosphere at a specific layer (m^3 ha-1) @@ -1950,7 +1888,6 @@ subroutine ConstrainRecruitNumber(csite,ccohort, bc_in) real(r8) :: leaf_m, store_m, sapw_m ! Element mass in organ tissues real(r8) :: fnrt_m, struct_m, repro_m ! Element mass in organ tissues - cpatch => ccohort%patchptr csite_hydr => csite%si_hydr ccohort_hydr =>ccohort%co_hydr recruitw = (sum(ccohort_hydr%th_ag(:)*ccohort_hydr%v_ag(:)) + & @@ -1984,7 +1921,7 @@ subroutine ConstrainRecruitNumber(csite,ccohort, bc_in) end do ! Prevent recruitment when temperatures are freezing or below - if (cpatch%tveg24%GetMean() <= 273.15_r8) then + if (mean_temp <= 273.15_r8) then nmin = 0._r8 end if @@ -2054,8 +1991,8 @@ subroutine UpdateSizeDepRhizVolLenCon(currentSite, bc_in) ! ! !LOCAL VARIABLES: type(ed_site_hydr_type), pointer :: csite_hydr - type(ed_patch_type) , pointer :: cPatch - type(ed_cohort_type) , pointer :: cCohort + type(fates_patch_type) , pointer :: cPatch + type(fates_cohort_type) , pointer :: cCohort type(ed_cohort_hydr_type), pointer :: ccohort_hydr real(r8) :: hksat_s ! hksat converted to units of 10^6sec ! which is equiv to [kg m-1 s-1 MPa-1] @@ -2191,8 +2128,8 @@ subroutine BTranForHLMDiagnosticsFromCohortHydr(nsites,sites,bc_out) integer :: s integer :: ifp real(r8) :: balive_patch - type(ed_patch_type),pointer :: cpatch - type(ed_cohort_type),pointer :: ccohort + type(fates_patch_type),pointer :: cpatch + type(fates_cohort_type),pointer :: ccohort do s = 1,nsites @@ -2421,8 +2358,8 @@ subroutine hydraulics_bc ( nsites, sites, bc_in, bc_out, dtime) !---------------------------------------------------------------------- - type (ed_patch_type), pointer :: cpatch ! current patch pointer - type (ed_cohort_type), pointer :: ccohort ! current cohort pointer + type (fates_patch_type), pointer :: cpatch ! current patch pointer + type (fates_cohort_type), pointer :: ccohort ! current cohort pointer type(ed_site_hydr_type), pointer :: csite_hydr ! site hydraulics pointer type(ed_cohort_hydr_type), pointer :: ccohort_hydr ! cohort hydraulics pointer @@ -2544,7 +2481,7 @@ subroutine hydraulics_bc ( nsites, sites, bc_in, bc_out, dtime) ifp = 0 cpatch => sites(s)%oldest_patch do while (associated(cpatch)) - if(cpatch%nocomp_pft_label.ne.0)then + if(cpatch%nocomp_pft_label.ne.nocomp_bareground)then ifp = ifp + 1 ! ---------------------------------------------------------------------------- @@ -2627,21 +2564,21 @@ subroutine hydraulics_bc ( nsites, sites, bc_in, bc_out, dtime) ! from leaf to the current soil layer. This does NOT ! update cohort%th_* - if(hydr_solver_type == hydr_solver_2DNewton) then + if(hydr_solver == hydr_solver_2DNewton) then call MatSolve2D(csite_hydr,ccohort,ccohort_hydr, & dtime,qflx_tran_veg_indiv, & sapflow,rootuptake(1:nlevrhiz),wb_err_plant,dwat_plant, & dth_layershell_col) - elseif(hydr_solver_type == hydr_solver_2DPicard) then + elseif(hydr_solver == hydr_solver_2DPicard) then call PicardSolve2D(csite_hydr,ccohort,ccohort_hydr, & dtime,qflx_tran_veg_indiv, & sapflow,rootuptake(1:nlevrhiz),wb_err_plant,dwat_plant, & dth_layershell_col,csite_hydr%num_nodes) - elseif(hydr_solver_type == hydr_solver_1DTaylor ) then + elseif(hydr_solver == hydr_solver_1DTaylor ) then ! --------------------------------------------------------------------------------- ! Approach: do nlevsoi_hyd sequential solutions to Richards' equation, @@ -2748,6 +2685,7 @@ subroutine hydraulics_bc ( nsites, sites, bc_in, bc_out, dtime) ccohort=>cpatch%tallest do while(associated(ccohort)) + ccohort_hydr => ccohort%co_hydr sum_l_aroot = sum(ccohort_hydr%l_aroot_layer(:)) ft = ccohort%pft @@ -2883,20 +2821,21 @@ subroutine hydraulics_bc ( nsites, sites, bc_in, bc_out, dtime) wb_check_site = delta_plant_storage+delta_soil_storage+site_runoff+transp_flux ! Now check on total error - if( abs(wb_check_site) > 1.e-4_r8 ) then - write(fates_log(),*) 'FATES hydro water balance does not add up [kg/m2]' - write(fates_log(),*) 'csite_hydr%errh2o_hyd: ',wb_check_site - write(fates_log(),*) 'delta_plant_storage: ',delta_plant_storage - write(fates_log(),*) 'delta_soil_storage: ',delta_soil_storage - write(fates_log(),*) 'site_runoff: ',site_runoff - write(fates_log(),*) 'transp_flux: ',transp_flux - end if - + if(debug)then + if( abs(wb_check_site) > 1.e-4_r8 ) then + write(fates_log(),*) 'FATES hydro water balance does not add up [kg/m2]' + write(fates_log(),*) 'csite_hydr%errh2o_hyd: ',wb_check_site + write(fates_log(),*) 'delta_plant_storage: ',delta_plant_storage + write(fates_log(),*) 'delta_soil_storage: ',delta_soil_storage + write(fates_log(),*) 'site_runoff: ',site_runoff + write(fates_log(),*) 'transp_flux: ',transp_flux + end if + end if + csite_hydr%h2oveg_hydro_err = csite_hydr%h2oveg_hydro_err + csite_hydr%errh2o_hyd - - call UpdateH2OVeg(sites(s),bc_out(s)) + call UpdateH2OVeg(sites(s),bc_out(s)) enddo !site @@ -2935,7 +2874,7 @@ subroutine UpdatePlantKmax(ccohort_hydr,ccohort,csite_hydr) ! Arguments type(ed_cohort_hydr_type),intent(inout),target :: ccohort_hydr - type(ed_cohort_type),intent(in),target :: ccohort + type(fates_cohort_type),intent(in),target :: ccohort type(ed_site_hydr_type),intent(in),target :: csite_hydr ! Locals @@ -2971,7 +2910,8 @@ subroutine UpdatePlantKmax(ccohort_hydr,ccohort,csite_hydr) pft = ccohort%pft ! Get the cross-section of the plant's sapwood area [m2] - call bsap_allom(ccohort%dbh,pft,ccohort%canopy_trim,a_sapwood,c_sap_dummy) + call bsap_allom(ccohort%dbh,pft,ccohort%crowndamage, & + ccohort%canopy_trim, ccohort%efstem_coh, a_sapwood,c_sap_dummy) ! Leaf Maximum Hydraulic Conductance ! The starting hypothesis is that there is no resistance inside the @@ -3144,7 +3084,7 @@ subroutine OrderLayersForSolve1D(csite_hydr,cohort,cohort_hydr,ordered, kbg_laye ! Arguments (IN) type(ed_site_hydr_type), intent(in),target :: csite_hydr - type(ed_cohort_type), intent(in),target :: cohort + type(fates_cohort_type), intent(in),target :: cohort type(ed_cohort_hydr_type),intent(in),target :: cohort_hydr @@ -3286,7 +3226,7 @@ subroutine ImTaylorSolve1D(slat, slon,recruitflag,csite_hydr,cohort,cohort_hydr, real(r8), intent(in) :: slat ! latitidue of the site real(r8), intent(in) :: slon ! longitidue of the site logical, intent(in) :: recruitflag - type(ed_cohort_type),intent(in),target :: cohort + type(fates_cohort_type),intent(in),target :: cohort type(ed_cohort_hydr_type),intent(inout),target :: cohort_hydr type(ed_site_hydr_type), intent(in),target :: csite_hydr real(r8), intent(in) :: dtime @@ -3979,7 +3919,7 @@ subroutine Report1DError(cohort, csite_hydr, ilayer, z_node, v_node, & ! like, and then quits. ! Arguments (IN) - type(ed_cohort_type),intent(in),target :: cohort + type(fates_cohort_type),intent(in),target :: cohort type(ed_site_hydr_type),intent(in), target :: csite_hydr integer, intent(in) :: ilayer ! soil layer index of interest real(r8), intent(in) :: z_node(:) ! elevation of nodes @@ -4292,7 +4232,7 @@ subroutine AccumulateMortalityWaterStorage(csite,ccohort,delta_n) ! Arguments type(ed_site_type), intent(inout), target :: csite - type(ed_cohort_type) , intent(inout), target :: ccohort + type(fates_cohort_type) , intent(inout), target :: ccohort real(r8), intent(in) :: delta_n ! Loss in number density ! for this cohort /ha/day @@ -4336,8 +4276,8 @@ subroutine RecruitWaterStorage(nsites,sites,bc_out) type(bc_out_type), intent(inout) :: bc_out(nsites) ! Locals - type(ed_cohort_type), pointer :: currentCohort - type(ed_patch_type), pointer :: currentPatch + type(fates_cohort_type), pointer :: currentCohort + type(fates_patch_type), pointer :: currentPatch type(ed_cohort_hydr_type), pointer :: ccohort_hydr type(ed_site_hydr_type), pointer :: csite_hydr integer :: s @@ -4605,56 +4545,63 @@ end subroutine shellGeom ! ===================================================================================== -function xylemtaper(p, dz) result(chi_tapnotap) +function xylemtaper(pexp, dz) result(chi_tapnotap) - ! !ARGUMENTS: - real(r8) , intent(in) :: p ! Savage et al. (2010) taper exponent - real(r8) , intent(in) :: dz ! hydraulic distance from petiole to node of interest [m] - ! - ! !LOCAL VARIABLES: - real(r8) :: atap,btap ! scaling exponents for total conductance ~ tree size (ratio of stem radius to terminal twig radius) - real(r8) :: anotap,bnotap ! same as atap, btap, but not acounting for xylem taper (Savage et al. (2010) p = 0) - ! NOTE: these scaling exponents were digitized from Fig 2a of Savage et al. (2010) - ! Savage VM, Bentley LP, Enquist BJ, Sperry JS, Smith DD, Reich PB, von Allmen EI. 2010. - ! Hydraulic trade-offs and space filling enable better predictions of vascular structure - ! and function in plants. Proceedings of the National Academy of Sciences 107(52): 22722-22727. - real(r8) :: lN=0.04_r8 ! petiole length [m] - real(r8) :: little_n=2._r8 ! number of daughter branches per parent branch, assumed constant throughout tree (self-similarity) [-] - real(r8) :: big_n ! number of branching levels (allowed here to take on non-integer values): increases with tree size [-] - real(r8) :: ktap ! hydraulic conductance along the pathway, accounting for xylem taper [kg s-1 MPa-1] - real(r8) :: knotap ! hydraulic conductance along the pathway, not accounting for xylem taper [kg s-1 MPa-1] - real(r8) :: num ! temporary - real(r8) :: den ! temporary - ! - ! !RESULT - real(r8) :: chi_tapnotap ! ratio of total tree conductance accounting for xylem taper to that without, over interval dz - ! - !------------------------------------------------------------------------ + use FatesConstantsMod, only : pi => pi_const - anotap = 7.19903e-13_r8 - bnotap = 1.326105578_r8 - if (p >= 1.0_r8) then - btap = 2.00586217_r8 - atap = 1.82513E-12_r8 - else if (p >= (1._r8/3._r8) .AND. p < 1._r8) then - btap = 1.854812819_r8 - atap = 6.66908E-13_r8 - else if (p >= (1._r8/6._r8) .AND. p < (1._r8/3._r8)) then - btap = 1.628179741_r8 - atap = 6.58345E-13_r8 - else - btap = bnotap - atap = anotap - end if + ! !DESCRIPTION: Following the theory presented i + ! Savage VM, Bentley LP, Enquist BJ, Sperry JS, Smith DD, Reich PB, von + ! Allmen EI. 2010. + ! Hydraulic trade-offs and space filling enable better predictions of + ! vascular structure + ! and function in plants. Proceedings of the National Academy of Sciences + ! 107(52): 22722-22727. - num = 3._r8*log(1._r8 - dz/lN * (1._r8-little_n**(1._r8/3._r8))) - den = log(little_n) - big_n = num/den - 1._r8 - ktap = atap * (little_n**(big_N* btap/2._r8)) - knotap = anotap * (little_n**(big_N*bnotap/2._r8)) - chi_tapnotap = ktap / knotap + ! Revised 2019-01-03 BOC: total conductance exponent (qexp) is now a + ! continuous function of the xylem taper exponent (pexp). + ! renamed btap to qexp, a[tap][notap] to kN, + ! little_n to n_ext, to match variable names + ! in Savage et al. - return + ! !ARGUMENTS: + real(r8) , intent(in) :: pexp ! Savage et al. (2010) taper exponent[-] + real(r8) , intent(in) :: dz ! hydraulic distance from petiole to node of interest[m] + ! + ! !LOCAL VARIABLES: + real(r8) :: qexp ! total conductance exponent (as in Fig. 2b of Savage et al. (2010) minus a0 term + real(r8) :: lN=0.005_r8 ! petiole length[m] + real(r8) :: n_ext=2._r8 ! number of daughter branches per parent branch, assumed constant throughout tree (self-similarity) [-] + real(r8) :: big_n ! number of branching levels (allowed here to take on non-integer values): increases with tree size [-] + real(r8) :: r0rN ! ratio of stem radius to terminal twig radius; r.ext0/r.extN (x-axis of Savage et al. (2010) Fig 2a)[-] + real(r8) :: num ! temporary + real(r8) :: den ! temporary + real(r8) :: a5,a4,a3,a2,a1,a0 ! coefficients of 5th-order polynomial fit to Savage et al. Fig. 2b (qexp vs. pexp) + ! NOTE: These were obtained by digitizing + ! Fig. 2b (dashed line) and fitting a + ! polynomial using nls() in R + ! + ! !RESULT + real(r8) :: chi_tapnotap ! ratio of total tree conductance accounting for xylem taper to that without, over interval dz + ! + !------------------------------------------------------------------------ + + a5 = -3.555547_r8 + a4 = 9.760275_r8 + a3 = -8.468005_r8 + a2 = 1.096488_r8 + a1 = 1.844792_r8 + a0 = 1.320732_r8 + + qexp = a5*pexp**5 + a4*pexp**4 + a3*pexp**3 + a2*pexp**2 + a1*pexp + + num = 3._r8*log(1._r8 - dz/lN * (1._r8-n_ext**(1._r8/3._r8))) + den = log(n_ext) + big_N = num/den - 1._r8 + r0rN = n_ext**(big_N/2._r8) + + chi_tapnotap = r0rN**qexp + + return end function xylemtaper @@ -4779,7 +4726,7 @@ subroutine MatSolve2D(csite_hydr,cohort,cohort_hydr, & ! ----------------------------------------------------------------------------------- type(ed_site_hydr_type), intent(inout),target :: csite_hydr ! ED csite_hydr structure type(ed_cohort_hydr_type), target :: cohort_hydr - type(ed_cohort_type) , intent(inout), target :: cohort + type(fates_cohort_type) , intent(inout), target :: cohort real(r8),intent(in) :: tmx ! time interval to integrate over [s] real(r8),intent(in) :: qtop real(r8),intent(out) :: sapflow ! time integrated mass flux between transp-root and stem [kg] @@ -4848,8 +4795,6 @@ subroutine MatSolve2D(csite_hydr,cohort,cohort_hydr, & integer :: kshell ! rhizosphere shell index, 1->nshell integer :: info - integer :: nstep !number of time steps - ! This is a convergence test. This is the maximum difference ! allowed between the flux balance and the change in storage @@ -4936,12 +4881,8 @@ subroutine MatSolve2D(csite_hydr,cohort,cohort_hydr, & ft => cohort%pft) - !for debug only - nstep = get_nstep() - - ! This NaN's the scratch arrays - call csite_hydr%FlushSiteScratch(hydr_solver_type) + call csite_hydr%FlushSiteScratch(hydr_solver) ! This is the maximum number of iterations needed for this cohort ! (each soil layer has a different number, this saves the max) @@ -5210,7 +5151,9 @@ subroutine MatSolve2D(csite_hydr,cohort,cohort_hydr, & enddo if ( nwtn_iter > max_newton_iter) then icnv = icnv_fail_round - write(fates_log(),*) 'Newton hydraulics solve failed',residual_amax,nsd,tm + if(debug)then + write(fates_log(),*) 'Newton hydraulics solve failed',residual_amax,nsd,tm + end if endif ! Three scenarios: @@ -5402,10 +5345,12 @@ subroutine MatSolve2D(csite_hydr,cohort,cohort_hydr, & end do outerloop - if(cohort_hydr%iterh1>1._r8) then - write(fates_log(),*) "hydro solve info: i1: ",cohort_hydr%iterh1,"i2: ",cohort_hydr%iterh2 + if(debug)then + if(cohort_hydr%iterh1>1._r8) then + write(fates_log(),*) "hydro solve info: i1: ",cohort_hydr%iterh1,"i2: ",cohort_hydr%iterh2 + end if end if - + ! Save flux diagnostics ! ------------------------------------------------------ @@ -5550,7 +5495,7 @@ subroutine PicardSolve2D(csite_hydr,cohort,cohort_hydr, & ! ----------------------------------------------------------------------------------- type(ed_site_hydr_type), intent(inout),target :: csite_hydr ! ED csite_hydr structure type(ed_cohort_hydr_type), target :: cohort_hydr - type(ed_cohort_type) , intent(inout), target :: cohort + type(fates_cohort_type) , intent(inout), target :: cohort real(r8),intent(in) :: tmx ! time interval to integrate over [s] real(r8),intent(in) :: qtop integer :: nnode !total number of nodes @@ -5620,8 +5565,6 @@ subroutine PicardSolve2D(csite_hydr,cohort,cohort_hydr, & integer :: kshell ! rhizosphere shell index, 1->nshell integer :: info - integer :: nstep !number of time steps - ! This is a convergence test. This is the maximum difference ! allowed between the flux balance and the change in storage @@ -5714,13 +5657,8 @@ subroutine PicardSolve2D(csite_hydr,cohort,cohort_hydr, & dftc_dpsi_node => csite_hydr%dftc_dpsi_node, & ft => cohort%pft) - - !for debug only - nstep = get_nstep() - - ! This NaN's the scratch arrays - call csite_hydr%FlushSiteScratch(hydr_solver_type) + call csite_hydr%FlushSiteScratch(hydr_solver) ! This is the maximum number of iterations needed for this cohort ! (each soil layer has a different number, this saves the max) diff --git a/biogeophys/FatesPlantRespPhotosynthMod.F90 b/biogeophys/FatesPlantRespPhotosynthMod.F90 index adffe67d85..50bb0464bf 100644 --- a/biogeophys/FatesPlantRespPhotosynthMod.F90 +++ b/biogeophys/FatesPlantRespPhotosynthMod.F90 @@ -22,6 +22,7 @@ module FATESPlantRespPhotosynthMod use FatesGlobals, only : endrun => fates_endrun use FatesGlobals, only : fates_log + use FatesGlobals, only : FatesWarn,N2S,A2S,I2S use FatesConstantsMod, only : r8 => fates_r8 use FatesConstantsMod, only : itrue use FatesConstantsMod, only : nearzero @@ -29,19 +30,28 @@ module FATESPlantRespPhotosynthMod use FatesConstantsMod, only : molar_mass_water use FatesConstantsMod, only : rgas_J_K_mol use FatesConstantsMod, only : fates_unset_r8 + use FatesConstantsMod, only : tfrz => t_water_freeze_k_1atm + use FatesConstantsMod, only : nocomp_bareground + use FatesConstantsMod, only : photosynth_acclim_model_none + use FatesConstantsMod, only : photosynth_acclim_model_kumarathunge_etal_2019 use FatesInterfaceTypesMod, only : hlm_use_planthydro use FatesInterfaceTypesMod, only : hlm_parteh_mode use FatesInterfaceTypesMod, only : numpft use FatesInterfaceTypesMod, only : nleafage - use EDTypesMod, only : maxpft - use EDTypesMod, only : nlevleaf - use EDTypesMod, only : nclmax + use EDParamsMod, only : maxpft + use EDParamsMod, only : nlevleaf + use EDParamsMod, only : nclmax use PRTGenericMod, only : max_nleafage use EDTypesMod, only : do_fates_salinity use EDParamsMod, only : q10_mr + use FatesPatchMod, only : fates_patch_type + use FatesCohortMod, only : fates_cohort_type + use EDParamsMod, only : maintresp_leaf_model + use FatesConstantsMod, only : lmrmodel_ryan_1991 + use FatesConstantsMod, only : lmrmodel_atkin_etal_2017 use PRTGenericMod, only : prt_carbon_allom_hyp use PRTGenericMod, only : prt_cnp_flex_allom_hyp - use PRTGenericMod, only : all_carbon_elements + use PRTGenericMod, only : carbon12_element use PRTGenericMod, only : nitrogen_element use PRTGenericMod, only : leaf_organ use PRTGenericMod, only : fnrt_organ @@ -49,10 +59,14 @@ module FATESPlantRespPhotosynthMod use PRTGenericMod, only : store_organ use PRTGenericMod, only : repro_organ use PRTGenericMod, only : struct_organ - use EDParamsMod, only : ED_val_base_mr_20, stomatal_model + use EDParamsMod, only : maintresp_nonleaf_baserate + use EDParamsMod, only : stomatal_model + use EDParamsMod, only : stomatal_assim_model + use EDParamsMod, only : photo_tempsens_model use PRTParametersMod, only : prt_params - use EDPftvarcon , only : EDPftvarcon_inst - + use EDPftvarcon , only : EDPftvarcon_inst + use TemperatureType, only : temperature_type + ! CIME Globals use shr_log_mod , only : errMsg => shr_log_errMsg @@ -63,6 +77,10 @@ module FATESPlantRespPhotosynthMod character(len=*), parameter, private :: sourcefile = & __FILE__ + + + character(len=1024) :: warn_msg ! for defining a warning message + !------------------------------------------------------------------------------------- ! maximum stomatal resistance [s/m] (used across several procedures) @@ -88,12 +106,9 @@ module FATESPlantRespPhotosynthMod ! Alternatively, Gross Assimilation can be used to estimate ! leaf co2 partial pressure and therefore conductance. The default - !is to use anet - logical, parameter :: use_agross = .false. - - - - + ! is to use anet + integer, parameter :: net_assim_model = 1 + integer, parameter :: gross_assim_model = 2 contains @@ -109,24 +124,16 @@ subroutine FatesPlantRespPhotosynthDrive (nsites, sites,bc_in,bc_out,dtime) ! a multi-layer canopy ! ----------------------------------------------------------------------------------- - ! !USES: - - use FatesSynchronizedParamsMod , only : FatesSynchronizedParamsInst - use EDTypesMod , only : ed_patch_type - use EDTypesMod , only : ed_cohort_type use EDTypesMod , only : ed_site_type - use EDTypesMod , only : maxpft - use EDTypesMod , only : dinc_vai - use EDTypesMod , only : dlower_vai + use EDParamsMod , only : dinc_vai + use EDParamsMod , only : dlower_vai use FatesInterfaceTypesMod , only : bc_in_type use FatesInterfaceTypesMod , only : bc_out_type use EDCanopyStructureMod, only : calc_areaindex use FatesConstantsMod, only : umolC_to_kgC - use FatesConstantsMod, only : g_per_kg use FatesConstantsMod, only : umol_per_mmol use FatesConstantsMod, only : rgas => rgas_J_K_kmol - use FatesConstantsMod, only : tfrz => t_water_freeze_k_1atm use FatesParameterDerivedMod, only : param_derived use FatesAllometryMod, only : bleaf, bstore_allom @@ -134,6 +141,10 @@ subroutine FatesPlantRespPhotosynthDrive (nsites, sites,bc_in,bc_out,dtime) use FatesAllometryMod, only : set_root_fraction use FatesAllometryMod, only : decay_coeff_kn + use DamageMainMod, only : GetCrownReduction + + use FatesInterfaceTypesMod, only : hlm_use_tree_damage + ! ARGUMENTS: ! ----------------------------------------------------------------------------------- integer,intent(in) :: nsites @@ -145,8 +156,8 @@ subroutine FatesPlantRespPhotosynthDrive (nsites, sites,bc_in,bc_out,dtime) ! LOCAL VARIABLES: ! ----------------------------------------------------------------------------------- - type (ed_patch_type) , pointer :: currentPatch - type (ed_cohort_type), pointer :: currentCohort + type (fates_patch_type) , pointer :: currentPatch + type (fates_cohort_type), pointer :: currentCohort ! ----------------------------------------------------------------------------------- ! These three arrays hold leaf-level biophysical rates that are calculated @@ -221,7 +232,7 @@ subroutine FatesPlantRespPhotosynthDrive (nsites, sites,bc_in,bc_out,dtime) real(r8) :: maintresp_reduction_factor ! factor by which to reduce maintenance - ! respiration when storage pools are low + ! respiration when storage pools are low real(r8) :: b_leaf ! leaf biomass kgC real(r8) :: frac ! storage pool as a fraction of target leaf biomass real(r8) :: check_elai ! This is a check on the effective LAI that is calculated @@ -237,8 +248,23 @@ subroutine FatesPlantRespPhotosynthDrive (nsites, sites,bc_in,bc_out,dtime) real(r8) :: lai_current ! the LAI in the current leaf layer real(r8) :: cumulative_lai ! the cumulative LAI, top down, to the leaf layer of interest real(r8) :: leaf_psi ! leaf xylem matric potential [MPa] (only meaningful/used w/ hydro) + real(r8) :: fnrt_mr_layer ! fine root maintenance respiation per layer [kgC/plant/s] + + real(r8) :: fnrt_mr_nfix_layer ! fineroot maintenance respiration specifically for symbiotic fixation [kgC/plant/layer/s] + real(r8) :: nfix_layer ! Nitrogen fixed in each layer this timestep [kgN/plant/layer/timestep] real(r8), allocatable :: rootfr_ft(:,:) ! Root fractions per depth and PFT + real(r8) :: agb_frac ! fraction of biomass aboveground + real(r8) :: branch_frac ! fraction of aboveground woody biomass in branches + real(r8) :: crown_reduction ! reduction in crown biomass from damage + real(r8) :: sapw_c_bgw ! belowground sapwood + real(r8) :: sapw_c_agw ! aboveground sapwood + real(r8) :: sapw_c_undamaged ! the target sapwood of an undamaged tree + real(r8) :: sapw_n ! sapwood nitrogen + real(r8) :: sapw_n_bgw ! nitrogen in belowground portion of sapwood + real(r8) :: sapw_n_agw ! nitrogen in aboveground portion of sapwood + real(r8) :: sapw_n_undamaged ! nitrogen in sapwood of undamaged tree + ! ----------------------------------------------------------------------------------- ! Keeping these two definitions in case they need to be added later ! @@ -252,21 +278,18 @@ subroutine FatesPlantRespPhotosynthDrive (nsites, sites,bc_in,bc_out,dtime) integer :: iage ! loop counter for leaf age classes ! Parameters - ! ----------------------------------------------------------------------- - ! Base maintenance respiration rate for plant tissues base_mr_20 - ! M. Ryan, 1991. Effects of climate change on plant respiration. - ! Ecological Applications, 1(2), 157-167. - ! Original expression is br = 0.0106 molC/(molN h) - ! Conversion by molecular weights of C and N gives 2.525e-6 gC/(gN s) ! ! Base rate is at 20C. Adjust to 25C using the CN Q10 = 1.5 ! (gC/gN/s) ! ------------------------------------------------------------------------ + ! ----------------------------------------------------------------------------------- ! Photosynthesis and stomatal conductance parameters, from: ! Bonan et al (2011) JGR, 116, doi:10.1029/2010JG001593 ! ----------------------------------------------------------------------------------- + + associate( & c3psn => EDPftvarcon_inst%c3psn , & @@ -300,7 +323,7 @@ subroutine FatesPlantRespPhotosynthDrive (nsites, sites,bc_in,bc_out,dtime) ifp = 0 currentpatch => sites(s)%oldest_patch do while (associated(currentpatch)) - if(currentpatch%nocomp_pft_label.ne.0)then + if(currentpatch%nocomp_pft_label.ne.nocomp_bareground)then ifp = ifp+1 NCL_p = currentPatch%NCL_p @@ -337,6 +360,7 @@ subroutine FatesPlantRespPhotosynthDrive (nsites, sites,bc_in,bc_out,dtime) ! CO2 compensation point (Pa) ! leaf boundary layer conductance of h20 ! constrained vapor pressure + call GetCanopyGasParameters(bc_in(s)%forc_pbot, & ! in bc_in(s)%oair_pa(ifp), & ! in bc_in(s)%t_veg_pa(ifp), & ! in @@ -385,21 +409,25 @@ subroutine FatesPlantRespPhotosynthDrive (nsites, sites,bc_in,bc_out,dtime) ft = currentCohort%pft cl = currentCohort%canopy_layer - call bleaf(currentCohort%dbh,currentCohort%pft,currentCohort%canopy_trim,store_c_target) + ! MLO. Assuming target to be related to leaf biomass when leaves are fully + ! flushed. But unsure whether this call is correct or not, shouldn't we get + ! the target value directly from the bstore_allom? + call bleaf(currentCohort%dbh,currentCohort%pft,& + currentCohort%crowndamage,currentCohort%canopy_trim,1.0_r8,store_c_target) ! call bstore_allom(currentCohort%dbh,currentCohort%pft, & ! currentCohort%canopy_trim,store_c_target) call storage_fraction_of_target(store_c_target, & - currentCohort%prt%GetState(store_organ, all_carbon_elements), & + currentCohort%prt%GetState(store_organ, carbon12_element), & frac) call lowstorage_maintresp_reduction(frac,currentCohort%pft, & maintresp_reduction_factor) ! are there any leaves of this pft in this layer? - if(currentPatch%canopy_mask(cl,ft) == 1)then + canopy_mask_if: if(currentPatch%canopy_mask(cl,ft) == 1)then ! Loop over leaf-layers - do iv = 1,currentCohort%nv + leaf_layer_loop : do iv = 1,currentCohort%nv ! ------------------------------------------------------------ ! If we are doing plant hydro-dynamics (or any run-type @@ -414,7 +442,7 @@ subroutine FatesPlantRespPhotosynthDrive (nsites, sites,bc_in,bc_out,dtime) ! age classes ! ------------------------------------------------------------ - if ( .not.rate_mask_z(iv,ft,cl) .or. & + rate_mask_if: if ( .not.rate_mask_z(iv,ft,cl) .or. & (hlm_use_planthydro.eq.itrue) .or. & (nleafage > 1) .or. & (hlm_parteh_mode .ne. prt_carbon_allom_hyp ) ) then @@ -486,7 +514,7 @@ subroutine FatesPlantRespPhotosynthDrive (nsites, sites,bc_in,bc_out,dtime) case (prt_cnp_flex_allom_hyp) - leaf_c = currentCohort%prt%GetState(leaf_organ, all_carbon_elements) + leaf_c = currentCohort%prt%GetState(leaf_organ, carbon12_element) if( (leaf_c*slatop(ft)) > nearzero) then leaf_n = currentCohort%prt%GetState(leaf_organ, nitrogen_element) lnc_top = leaf_n / (slatop(ft) * leaf_c ) @@ -500,16 +528,33 @@ subroutine FatesPlantRespPhotosynthDrive (nsites, sites,bc_in,bc_out,dtime) end select - lmr25top = 2.525e-6_r8 * (1.5_r8 ** ((25._r8 - 20._r8)/10._r8)) - lmr25top = lmr25top * lnc_top / (umolC_to_kgC * g_per_kg) + ! Part VII: Calculate dark respiration (leaf maintenance) for this layer + + select case (maintresp_leaf_model) + case (lmrmodel_ryan_1991) - ! Part VII: Calculate dark respiration (leaf maintenance) for this layer - call LeafLayerMaintenanceRespiration( lmr25top, & ! in - nscaler, & ! in - ft, & ! in - bc_in(s)%t_veg_pa(ifp), & ! in - lmr_z(iv,ft,cl)) ! out + call LeafLayerMaintenanceRespiration_Ryan_1991( lnc_top, & ! in + nscaler, & ! in + ft, & ! in + bc_in(s)%t_veg_pa(ifp), & ! in + lmr_z(iv,ft,cl)) ! out + + case (lmrmodel_atkin_etal_2017) + + call LeafLayerMaintenanceRespiration_Atkin_etal_2017(lnc_top, & ! in + nscaler, & ! in + ft, & ! in + bc_in(s)%t_veg_pa(ifp), & ! in + currentPatch%tveg_lpa%GetMean(), & ! in + lmr_z(iv,ft,cl)) ! out + + case default + + write (fates_log(),*)'error, incorrect leaf respiration model specified' + call endrun(msg=errMsg(sourcefile, __LINE__)) + + end select ! Part VII: Calculate (1) maximum rate of carboxylation (vcmax), ! (2) maximum electron transport rate, (3) triose phosphate @@ -530,6 +575,8 @@ subroutine FatesPlantRespPhotosynthDrive (nsites, sites,bc_in,bc_out,dtime) currentCohort%kp25top, & ! in nscaler, & ! in bc_in(s)%t_veg_pa(ifp), & ! in + currentPatch%tveg_lpa%GetMean(), & ! in + currentPatch%tveg_longterm%GetMean(),& ! in btran_eff, & ! in vcmax_z, & ! out jmax_z, & ! out @@ -570,8 +617,9 @@ subroutine FatesPlantRespPhotosynthDrive (nsites, sites,bc_in,bc_out,dtime) c13disc_z(cl,ft,iv)) ! out rate_mask_z(iv,ft,cl) = .true. - end if - end do + + end if rate_mask_if + end do leaf_layer_loop ! Zero cohort flux accumulators. currentCohort%npp_tstep = 0.0_r8 @@ -620,7 +668,7 @@ subroutine FatesPlantRespPhotosynthDrive (nsites, sites,bc_in,bc_out,dtime) currentCohort%g_sb_laweight = 0.0_r8 currentCohort%ts_net_uptake(:) = 0.0_r8 - end if ! if(currentPatch%canopy_mask(cl,ft) == 1)then + end if canopy_mask_if ! ------------------------------------------------------------------ @@ -635,19 +683,40 @@ subroutine FatesPlantRespPhotosynthDrive (nsites, sites,bc_in,bc_out,dtime) ! Units are in (kgN/plant) ! ------------------------------------------------------------------ - sapw_c = currentCohort%prt%GetState(sapw_organ, all_carbon_elements) - fnrt_c = currentCohort%prt%GetState(fnrt_organ, all_carbon_elements) + sapw_c = currentCohort%prt%GetState(sapw_organ, carbon12_element) + fnrt_c = currentCohort%prt%GetState(fnrt_organ, carbon12_element) + if (hlm_use_tree_damage .eq. itrue) then + + ! Crown damage currenly only reduces the aboveground portion of + ! sapwood. Therefore we calculate the aboveground and the belowground portion + ! sapwood for use in stem respiration. + call GetCrownReduction(currentCohort%crowndamage, crown_reduction) + + else + crown_reduction = 0.0_r8 + end if + + ! If crown reduction is zero, undamaged sapwood target will equal sapwood carbon + agb_frac = prt_params%allom_agb_frac(currentCohort%pft) + branch_frac = param_derived%branch_frac(currentCohort%pft) + sapw_c_undamaged = sapw_c / (1.0_r8 - (agb_frac * branch_frac * crown_reduction)) + + ! Undamaged below ground portion + sapw_c_bgw = sapw_c_undamaged * (1.0_r8 - agb_frac) + + ! Damaged aboveground portion + sapw_c_agw = sapw_c - sapw_c_bgw + + select case(hlm_parteh_mode) case (prt_carbon_allom_hyp) - live_stem_n = prt_params%allom_agb_frac(currentCohort%pft) * & - sapw_c * prt_params%nitr_stoich_p1(ft,prt_params%organ_param_id(sapw_organ)) + live_stem_n = sapw_c_agw * prt_params%nitr_stoich_p1(ft,prt_params%organ_param_id(sapw_organ)) - live_croot_n = (1.0_r8-prt_params%allom_agb_frac(currentCohort%pft)) * & - sapw_c * prt_params%nitr_stoich_p1(ft,prt_params%organ_param_id(sapw_organ)) + live_croot_n = sapw_c_bgw * prt_params%nitr_stoich_p1(ft,prt_params%organ_param_id(sapw_organ)) - fnrt_n = fnrt_c * prt_params%nitr_stoich_p1(ft,prt_params%organ_param_id(fnrt_organ)) + fnrt_n = fnrt_c * prt_params%nitr_stoich_p1(ft,prt_params%organ_param_id(fnrt_organ)) case(prt_cnp_flex_allom_hyp) @@ -657,16 +726,33 @@ subroutine FatesPlantRespPhotosynthDrive (nsites, sites,bc_in,bc_out,dtime) live_croot_n = (1.0_r8-prt_params%allom_agb_frac(currentCohort%pft)) * & currentCohort%prt%GetState(sapw_organ, nitrogen_element) + fnrt_n = currentCohort%prt%GetState(fnrt_organ, nitrogen_element) + if (hlm_use_tree_damage .eq. itrue) then + + sapw_n = currentCohort%prt%GetState(sapw_organ, nitrogen_element) + + sapw_n_undamaged = sapw_n / & + (1.0_r8 - (agb_frac * branch_frac * crown_reduction)) + + sapw_n_bgw = sapw_n_undamaged * (1.0_r8 - agb_frac) + sapw_n_agw = sapw_n - sapw_n_bgw + + live_croot_n = sapw_n_bgw + + live_stem_n = sapw_n_agw + + end if + ! If one wants to break coupling with dynamic N conentrations, ! use the stoichiometry parameter ! ! live_stem_n = prt_params%allom_agb_frac(currentCohort%pft) * & - ! sapw_c * prt_params%nitr_stoich_p1(ft,prt_params%organ_param_id(sapw_organ)) + ! sapw_c * prt_params%nitr_stoich_p1(ft,prt_params%organ_param_id(sapw_organ)) ! live_croot_n = (1.0_r8-prt_params%allom_agb_frac(currentCohort%pft)) * & - ! sapw_c * prt_params%nitr_stoich_p1(ft,prt_params%organ_param_id(sapw_organ)) - ! fnrt_n = fnrt_c * prt_params%nitr_stoich_p1(ft,prt_params%organ_param_id(fnrt_organ)) + ! sapw_c * prt_params%nitr_stoich_p1(ft,prt_params%organ_param_id(sapw_organ)) + ! fnrt_n = fnrt_c * prt_params%nitr_stoich_p1(ft,prt_params%organ_param_id(fnrt_organ)) case default @@ -688,19 +774,36 @@ subroutine FatesPlantRespPhotosynthDrive (nsites, sites,bc_in,bc_out,dtime) if ( int(woody(ft)) == itrue) then tcwood = q10_mr**((bc_in(s)%t_veg_pa(ifp)-tfrz - 20.0_r8)/10.0_r8) ! kgC/s = kgN * kgC/kgN/s - currentCohort%livestem_mr = live_stem_n * ED_val_base_mr_20 * tcwood * maintresp_reduction_factor + currentCohort%livestem_mr = live_stem_n * maintresp_nonleaf_baserate * tcwood * maintresp_reduction_factor else currentCohort%livestem_mr = 0._r8 end if ! Fine Root MR (kgC/plant/s) + ! and calculate the N fixation rate as a function of the fixation-specific root respiration + ! for now use dev_arbitrary_pft as scaling term between 0 and 1 as additional increment of root respiration used for N fixation ! ------------------------------------------------------------------ currentCohort%froot_mr = 0._r8 + currentCohort%sym_nfix_tstep = 0._r8 + + ! n_fixation is integrated over the course of the day + ! this variable is zeroed at the end of the FATES dynamics sequence + do j = 1,bc_in(s)%nlevsoil tcsoi = q10_mr**((bc_in(s)%t_soisno_sl(j)-tfrz - 20.0_r8)/10.0_r8) - currentCohort%froot_mr = currentCohort%froot_mr + & - fnrt_n * ED_val_base_mr_20 * tcsoi * rootfr_ft(ft,j) * maintresp_reduction_factor + + fnrt_mr_layer = fnrt_n * maintresp_nonleaf_baserate * tcsoi * rootfr_ft(ft,j) * maintresp_reduction_factor + + ! calculate the cost of carbon for N fixation in each soil layer and calculate N fixation rate based on that [kgC / kgN] + + call RootLayerNFixation(bc_in(s)%t_soisno_sl(j),ft,dtime,fnrt_mr_layer,fnrt_mr_nfix_layer,nfix_layer) + + currentCohort%froot_mr = currentCohort%froot_mr + fnrt_mr_nfix_layer + fnrt_mr_layer + + currentCohort%sym_nfix_tstep = currentCohort%sym_nfix_tstep + nfix_layer + + enddo ! Coarse Root MR (kgC/plant/s) (below ground sapwood) @@ -711,7 +814,7 @@ subroutine FatesPlantRespPhotosynthDrive (nsites, sites,bc_in,bc_out,dtime) ! Soil temperature used to adjust base rate of MR tcsoi = q10_mr**((bc_in(s)%t_soisno_sl(j)-tfrz - 20.0_r8)/10.0_r8) currentCohort%livecroot_mr = currentCohort%livecroot_mr + & - live_croot_n * ED_val_base_mr_20 * tcsoi * & + live_croot_n * maintresp_nonleaf_baserate * tcsoi * & rootfr_ft(ft,j) * maintresp_reduction_factor enddo else @@ -743,6 +846,9 @@ subroutine FatesPlantRespPhotosynthDrive (nsites, sites,bc_in,bc_out,dtime) currentCohort%resp_m = currentCohort%resp_m + currentCohort%rdark + ! save as a diagnostic the un-throttled maintenance respiration to be able to know how strong this is + currentCohort%resp_m_unreduced = currentCohort%resp_m / maintresp_reduction_factor + ! convert from kgC/indiv/s to kgC/indiv/timestep currentCohort%resp_m = currentCohort%resp_m * dtime currentCohort%gpp_tstep = currentCohort%gpp_tstep * dtime @@ -853,6 +959,64 @@ subroutine FatesPlantRespPhotosynthDrive (nsites, sites,bc_in,bc_out,dtime) end associate end subroutine FatesPlantRespPhotosynthDrive +! =========================================================================================== + + +subroutine RootLayerNFixation(t_soil,ft,dtime,fnrt_mr_layer,fnrt_mr_nfix_layer,nfix_layer) + + + ! ------------------------------------------------------------------------------- + ! Symbiotic N Fixation is handled via Houlton et al 2008 and Fisher et al. 2010 + ! + ! A unifying framework for dinitrogen fixation in the terrestrial biosphere + ! Benjamin Z. Houlton, Ying-Ping Wang, Peter M. Vitousek & Christopher B. Field + ! Nature volume 454, pages327–330 (2008) https://doi.org/10.1038/nature07028 + ! + ! Carbon cost of plant nitrogen acquisition: A mechanistic, globally applicable model + ! of plant nitrogen uptake, retranslocation, and fixation. J. B. Fisher,S. Sitch,Y. + ! Malhi,R. A. Fisher,C. Huntingford,S.-Y. Tan. Global Biogeochemical Cycles. March + ! 2010 https://doi.org/10.1029/2009GB003621 + ! + ! ------------------------------------------------------------------------------ + + + real(r8),intent(in) :: t_soil ! Temperature of the current soil layer [degC] + integer,intent(in) :: ft ! Functional type index + real(r8),intent(in) :: dtime ! Time step length [s] + real(r8),intent(in) :: fnrt_mr_layer ! Amount of maintenance respiration in the fine-roots + ! for all non-fixation related processes [kgC/s] + + real(r8),intent(out) :: fnrt_mr_nfix_layer ! The added maintenance respiration due to nfixation + ! to be added as a surcharge to non-fixation MR [kgC] + real(r8),intent(out) :: nfix_layer ! The amount of N fixed in this layer through + ! symbiotic activity [kgN] + + real(r8) :: c_cost_nfix ! carbon cost of N fixation [kgC/kgN] + real(r8) :: c_spent_nfix ! carbon spent on N fixation, per layer [kgC/plant/timestep] + + ! N fixation parameters from Houlton et al (2008) and Fisher et al (2010) + real(r8), parameter :: s_fix = -6.25_r8 ! s parameter from FUN model (fisher et al 2010) + real(r8), parameter :: a_fix = -3.62_r8 ! a parameter from Houlton et al. 2010 (a = -3.62 +/- 0.52) + real(r8), parameter :: b_fix = 0.27_r8 ! b parameter from Houlton et al. 2010 (b = 0.27 +/-0.04) + real(r8), parameter :: c_fix = 25.15_r8 ! c parameter from Houlton et al. 2010 (c = 25.15 +/- 0.66) + + ! Amount of C spent (as part of MR respiration) on symbiotic fixation [kgC/s] + fnrt_mr_nfix_layer = fnrt_mr_layer * prt_params%nfix_mresp_scfrac(ft) + + ! This is the unit carbon cost for nitrogen fixation. It is temperature dependant [kgC/kgN] + c_cost_nfix = s_fix * (exp(a_fix + b_fix * (t_soil-tfrz) & + * (1._r8 - 0.5_r8 * (t_soil-tfrz) / c_fix)) - 2._r8) + + ! Time integrated amount of carbon spent on fixation (in this layer) [kgC/plant/layer/tstep] + c_spent_nfix = fnrt_mr_nfix_layer * dtime + + ! Amount of nitrogen fixed in this layer [kgC/plant/layer/tstep]/[kgC/kgN] = [kgN/plant/layer/tstep] + nfix_layer = c_spent_nfix / c_cost_nfix + + return +end subroutine RootLayerNFixation + + ! ======================================================================================= subroutine LeafLayerPhotosynthesis(f_sun_lsl, & ! in @@ -1147,7 +1311,7 @@ subroutine LeafLayerPhotosynthesis(f_sun_lsl, & ! in ! using anet in calculating gs this is version B anet = agross - lmr - if (use_agross) then + if ( stomatal_assim_model == gross_assim_model ) then if ( stomatal_model == medlyn_model ) then write (fates_log(),*) 'Gross Assimilation conductance is incompatible with the Medlyn model' call endrun(msg=errMsg(sourcefile, __LINE__)) @@ -1262,8 +1426,8 @@ subroutine LeafLayerPhotosynthesis(f_sun_lsl, & ! in end if if (abs(gs_mol-gs_mol_err) > 1.e-01_r8) then - write (fates_log(),*) 'Stomatal model error check - stomatal conductance error:' - write (fates_log(),*) gs_mol, gs_mol_err + warn_msg = 'Stomatal conductance error check - weak convergence: '//trim(N2S(gs_mol))//' '//trim(N2S(gs_mol_err)) + call FatesWarn(warn_msg,index=1) end if enddo !sunsha loop @@ -1434,14 +1598,14 @@ subroutine ScaleLeafLayerFluxToCohort(nv, & ! in currentCohort%nv real(r8), intent(in) :: nplant ! indiv/m2 real(r8), intent(in) :: rb ! leaf boundary layer resistance (s/m) real(r8), intent(in) :: maintresp_reduction_factor ! factor by which to reduce maintenance respiration - real(r8), intent(out) :: g_sb_laweight ! Combined conductance (stomatal + boundary layer) for the cohort - ! weighted by leaf area [m/s]*[m2] - real(r8), intent(out) :: gpp ! GPP (kgC/indiv/s) - real(r8), intent(out) :: rdark ! Dark Leaf Respiration (kgC/indiv/s) - real(r8), intent(out) :: cohort_eleaf_area ! Effective leaf area of the cohort [m2] - real(r8), intent(out) :: c13disc_clm ! unpacked Cohort level c13 discrimination - real(r8) :: sum_weight ! sum of weight for unpacking d13c flux (c13disc_z) from - ! (canopy_layer, pft, leaf_layer) matrix to cohort (c13disc_clm) + real(r8), intent(out) :: g_sb_laweight ! Combined conductance (stomatal + boundary layer) for the cohort + ! weighted by leaf area [m/s]*[m2] + real(r8), intent(out) :: gpp ! GPP (kgC/indiv/s) + real(r8), intent(out) :: rdark ! Dark Leaf Respiration (kgC/indiv/s) + real(r8), intent(out) :: cohort_eleaf_area ! Effective leaf area of the cohort [m2] + real(r8), intent(out) :: c13disc_clm ! unpacked Cohort level c13 discrimination + real(r8) :: sum_weight ! sum of weight for unpacking d13c flux (c13disc_z) from + ! (canopy_layer, pft, leaf_layer) matrix to cohort (c13disc_clm) ! GPP IN THIS SUBROUTINE IS A RATE. THE CALLING ARGUMENT IS GPP_TSTEP. AFTER THIS ! CALL THE RATE WILL BE MULTIPLIED BY THE INTERVAL TO GIVE THE INTEGRATED QUANT. @@ -1539,7 +1703,7 @@ function ft1_f(tl, ha) result(ans) ! !!USES use FatesConstantsMod, only : rgas => rgas_J_K_kmol - use FatesConstantsMod, only : tfrz => t_water_freeze_k_1atm + ! ! !ARGUMENTS: real(r8), intent(in) :: tl ! leaf temperature in photosynthesis temperature function (K) @@ -1566,7 +1730,6 @@ function fth_f(tl,hd,se,scaleFactor) result(ans) ! 7/23/16: Copied over from CLM by Ryan Knox ! use FatesConstantsMod, only : rgas => rgas_J_K_kmol - use FatesConstantsMod, only : tfrz => t_water_freeze_k_1atm ! ! !ARGUMENTS: @@ -1598,7 +1761,6 @@ function fth25_f(hd,se)result(ans) !!USES use FatesConstantsMod, only : rgas => rgas_J_K_kmol - use FatesConstantsMod, only : tfrz => t_water_freeze_k_1atm ! ! !ARGUMENTS: @@ -1728,13 +1890,9 @@ subroutine UpdateCanopyNCanNRadPresent(currentPatch) ! profile). ! --------------------------------------------------------------------------------- - - use EDTypesMod , only : ed_patch_type - use EDTypesMod , only : ed_cohort_type - ! Arguments - type(ed_patch_type), target :: currentPatch - type(ed_cohort_type), pointer :: currentCohort + type(fates_patch_type), target :: currentPatch + type(fates_cohort_type), pointer :: currentCohort ! Locals integer :: cl ! Canopy Layer Index @@ -1906,26 +2064,37 @@ end subroutine GetCanopyGasParameters ! ==================================================================================== -subroutine LeafLayerMaintenanceRespiration(lmr25top_ft, & - nscaler, & - ft, & +subroutine LeafLayerMaintenanceRespiration_Ryan_1991(lnc_top, & + nscaler, & + ft, & veg_tempk, & lmr) use FatesConstantsMod, only : tfrz => t_water_freeze_k_1atm - + use FatesConstantsMod, only : umolC_to_kgC + use FatesConstantsMod, only : g_per_kg + use EDPftvarcon , only : EDPftvarcon_inst + + ! ----------------------------------------------------------------------- + ! Base maintenance respiration rate for plant tissues maintresp_leaf_ryan1991_baserate + ! M. Ryan, 1991. Effects of climate change on plant respiration. + ! Ecological Applications, 1(2), 157-167. + ! Original expression is br = 0.0106 molC/(molN h) + ! Conversion by molecular weights of C and N gives 2.525e-6 gC/(gN s) + ! Which is the default value of maintresp_nonleaf_baserate ! Arguments - real(r8), intent(in) :: lmr25top_ft ! canopy top leaf maint resp rate at 25C - ! for this pft (umol CO2/m**2/s) - integer, intent(in) :: ft ! (plant) Functional Type Index + real(r8), intent(in) :: lnc_top ! Leaf nitrogen content per unit area at canopy top [gN/m2] real(r8), intent(in) :: nscaler ! Scale for leaf nitrogen profile + integer, intent(in) :: ft ! (plant) Functional Type Index real(r8), intent(in) :: veg_tempk ! vegetation temperature real(r8), intent(out) :: lmr ! Leaf Maintenance Respiration (umol CO2/m**2/s) ! Locals real(r8) :: lmr25 ! leaf layer: leaf maintenance respiration rate at 25C (umol CO2/m**2/s) - + real(r8) :: lmr25top ! canopy top leaf maint resp rate at 25C for this pft (umol CO2/m**2/s) + integer :: c3c4_path_index ! Index for which photosynthetic pathway + ! Parameter real(r8), parameter :: lmrha = 46390._r8 ! activation energy for lmr (J/mol) real(r8), parameter :: lmrhd = 150650._r8 ! deactivation energy for lmr (J/mol) @@ -1933,26 +2102,89 @@ subroutine LeafLayerMaintenanceRespiration(lmr25top_ft, & real(r8), parameter :: lmrc = 1.15912391_r8 ! scaling factor for high ! temperature inhibition (25 C = 1.0) - - + lmr25top = EDPftvarcon_inst%maintresp_leaf_ryan1991_baserate(ft) * (1.5_r8 ** ((25._r8 - 20._r8)/10._r8)) + lmr25top = lmr25top * lnc_top / (umolC_to_kgC * g_per_kg) ! Part I: Leaf Maintenance respiration: umol CO2 / m**2 [leaf] / s ! ---------------------------------------------------------------------------------- - lmr25 = lmr25top_ft * nscaler + lmr25 = lmr25top * nscaler - if ( nint(EDpftvarcon_inst%c3psn(ft)) == 1)then + ! photosynthetic pathway: 0. = c4, 1. = c3 + c3c4_path_index = nint(EDPftvarcon_inst%c3psn(ft)) + + if (c3c4_path_index == c3_path_index) then + ! temperature sensitivity of C3 plants lmr = lmr25 * ft1_f(veg_tempk, lmrha) * & - fth_f(veg_tempk, lmrhd, lmrse, lmrc) + fth_f(veg_tempk, lmrhd, lmrse, lmrc) else + ! temperature sensitivity of C4 plants lmr = lmr25 * 2._r8**((veg_tempk-(tfrz+25._r8))/10._r8) lmr = lmr / (1._r8 + exp( 1.3_r8*(veg_tempk-(tfrz+55._r8)) )) - end if + endif ! Any hydrodynamic limitations could go here, currently none ! lmr = lmr * (nothing) -end subroutine LeafLayerMaintenanceRespiration +end subroutine LeafLayerMaintenanceRespiration_Ryan_1991 + +! ==================================================================================== + +subroutine LeafLayerMaintenanceRespiration_Atkin_etal_2017(lnc_top, & + nscaler, & + ft, & + veg_tempk, & + tgrowth, & + lmr) + + use FatesConstantsMod, only : tfrz => t_water_freeze_k_1atm + use FatesConstantsMod, only : umolC_to_kgC + use FatesConstantsMod, only : g_per_kg + use FatesConstantsMod, only : lmr_b + use FatesConstantsMod, only : lmr_c + use FatesConstantsMod, only : lmr_TrefC + use FatesConstantsMod, only : lmr_r_1 + use FatesConstantsMod, only : lmr_r_2 + use EDPftvarcon , only : EDPftvarcon_inst + + ! Arguments + real(r8), intent(in) :: lnc_top ! Leaf nitrogen content per unit area at canopy top [gN/m2] + integer, intent(in) :: ft ! (plant) Functional Type Index + real(r8), intent(in) :: nscaler ! Scale for leaf nitrogen profile + real(r8), intent(in) :: veg_tempk ! vegetation temperature (degrees K) + real(r8), intent(in) :: tgrowth ! lagged vegetation temperature averaged over acclimation timescale (degrees K) + real(r8), intent(out) :: lmr ! Leaf Maintenance Respiration (umol CO2/m**2/s) + + ! Locals + real(r8) :: lmr25 ! leaf layer: leaf maintenance respiration rate at 25C (umol CO2/m**2/s) + real(r8) :: r_0 ! base respiration rate, PFT-dependent (umol CO2/m**2/s) + real(r8) :: r_t_ref ! acclimated ref respiration rate (umol CO2/m**2/s) + real(r8) :: lmr25top ! canopy top leaf maint resp rate at 25C for this pft (umol CO2/m**2/s) + + ! parameter values of r_0 as listed in Atkin et al 2017: (umol CO2/m**2/s) + ! Broad-leaved trees 1.7560 + ! Needle-leaf trees 1.4995 + ! Shrubs 2.0749 + ! C3 herbs/grasses 2.1956 + ! In the absence of better information, we use the same value for C4 grasses as C3 grasses. + + ! note that this code uses the relationship between leaf N and respiration from Atkin et al + ! for the top of the canopy, but then assumes proportionality with N through the canopy. + + ! r_0 currently put into the EDPftvarcon_inst%dev_arbitrary_pft + ! all figs in Atkin et al 2017 stop at zero Celsius so we will assume acclimation is fixed below that + r_0 = EDPftvarcon_inst%maintresp_leaf_atkin2017_baserate(ft) + r_t_ref = max( 0._r8, nscaler * (r_0 + lmr_r_1 * lnc_top + lmr_r_2 * max(0._r8, (tgrowth - tfrz) )) ) + + if (r_t_ref .eq. 0._r8) then + warn_msg = 'Rdark is negative at this temperature and is capped at 0. tgrowth (C): '//trim(N2S(tgrowth-tfrz))//' pft: '//trim(I2S(ft)) + call FatesWarn(warn_msg,index=4) + end if + + lmr = r_t_ref * exp(lmr_b * (veg_tempk - tfrz - lmr_TrefC) + lmr_c * & + ((veg_tempk-tfrz)**2 - lmr_TrefC**2)) + +end subroutine LeafLayerMaintenanceRespiration_Atkin_etal_2017 ! ==================================================================================== @@ -1963,6 +2195,8 @@ subroutine LeafLayerBiophysicalRates( parsun_lsl, & co2_rcurve_islope25top_ft, & nscaler, & veg_tempk, & + t_growth, & + t_home, & btran, & vcmax, & jmax, & @@ -1982,7 +2216,6 @@ subroutine LeafLayerBiophysicalRates( parsun_lsl, & ! --------------------------------------------------------------------------------- use EDPftvarcon , only : EDPftvarcon_inst - use FatesConstantsMod, only : tfrz => t_water_freeze_k_1atm ! Arguments ! ------------------------------------------------------------------------------ @@ -1997,6 +2230,8 @@ subroutine LeafLayerBiophysicalRates( parsun_lsl, & real(r8), intent(in) :: co2_rcurve_islope25top_ft ! initial slope of CO2 response curve ! (C4 plants) at 25C, canopy top, this pft real(r8), intent(in) :: veg_tempk ! vegetation temperature + real(r8), intent(in) :: t_growth ! T_growth (short-term running mean temperature) (K) + real(r8), intent(in) :: t_home ! T_home (long-term running mean temperature) (K) real(r8), intent(in) :: btran ! transpiration wetness factor (0 to 1) real(r8), intent(out) :: vcmax ! maximum rate of carboxylation (umol co2/m**2/s) @@ -2012,7 +2247,7 @@ subroutine LeafLayerBiophysicalRates( parsun_lsl, & ! (umol electrons/m**2/s) real(r8) :: co2_rcurve_islope25 ! leaf layer: Initial slope of CO2 response curve ! (C4 plants) at 25C - + integer :: c3c4_path_index ! Index for which photosynthetic pathway ! Parameters ! --------------------------------------------------------------------------------- @@ -2022,17 +2257,34 @@ subroutine LeafLayerBiophysicalRates( parsun_lsl, & real(r8) :: jmaxhd ! deactivation energy for jmax (J/mol) real(r8) :: vcmaxse ! entropy term for vcmax (J/mol/K) real(r8) :: jmaxse ! entropy term for jmax (J/mol/K) + real(r8) :: t_growth_celsius ! average growing temperature + real(r8) :: t_home_celsius ! average home temperature + real(r8) :: jvr ! ratio of Jmax25 / Vcmax25 real(r8) :: vcmaxc ! scaling factor for high temperature inhibition (25 C = 1.0) real(r8) :: jmaxc ! scaling factor for high temperature inhibition (25 C = 1.0) - vcmaxha = EDPftvarcon_inst%vcmaxha(FT) - jmaxha = EDPftvarcon_inst%jmaxha(FT) - - vcmaxhd = EDPftvarcon_inst%vcmaxhd(FT) - jmaxhd = EDPftvarcon_inst%jmaxhd(FT) - - vcmaxse = EDPftvarcon_inst%vcmaxse(FT) - jmaxse = EDPftvarcon_inst%jmaxse(FT) + select case(photo_tempsens_model) + case (photosynth_acclim_model_none) !No temperature acclimation + vcmaxha = EDPftvarcon_inst%vcmaxha(FT) + jmaxha = EDPftvarcon_inst%jmaxha(FT) + vcmaxhd = EDPftvarcon_inst%vcmaxhd(FT) + jmaxhd = EDPftvarcon_inst%jmaxhd(FT) + vcmaxse = EDPftvarcon_inst%vcmaxse(FT) + jmaxse = EDPftvarcon_inst%jmaxse(FT) + case (photosynth_acclim_model_kumarathunge_etal_2019) !Kumarathunge et al. temperature acclimation, Thome=30-year running mean + t_growth_celsius = t_growth-tfrz + t_home_celsius = t_home-tfrz + vcmaxha = (42.6_r8 + (1.14_r8*t_growth_celsius))*1e3_r8 !J/mol + jmaxha = 40.71_r8*1e3_r8 !J/mol + vcmaxhd = 200._r8*1e3_r8 !J/mol + jmaxhd = 200._r8*1e3_r8 !J/mol + vcmaxse = (645.13_r8 - (0.38_r8*t_growth_celsius)) + jmaxse = 658.77_r8 - (0.84_r8*t_home_celsius) - 0.52_r8*(t_growth_celsius-t_home_celsius) + jvr = 2.56_r8 - (0.0375_r8*t_home_celsius)-(0.0202_r8*(t_growth_celsius-t_home_celsius)) + case default + write (fates_log(),*)'error, incorrect leaf photosynthesis temperature acclimation model specified' + call endrun(msg=errMsg(sourcefile, __LINE__)) + end select vcmaxc = fth25_f(vcmaxhd, vcmaxse) jmaxc = fth25_f(jmaxhd, jmaxse) @@ -2045,18 +2297,32 @@ subroutine LeafLayerBiophysicalRates( parsun_lsl, & ! Vcmax25top was already calculated to derive the nscaler function vcmax25 = vcmax25top_ft * nscaler - jmax25 = jmax25top_ft * nscaler + select case(photo_tempsens_model) + case (photosynth_acclim_model_none) + jmax25 = jmax25top_ft * nscaler + case (photosynth_acclim_model_kumarathunge_etal_2019) + jmax25 = vcmax25*jvr + case default + write (fates_log(),*)'error, incorrect leaf photosynthesis temperature acclimation model specified' + call endrun(msg=errMsg(sourcefile, __LINE__)) + end select + co2_rcurve_islope25 = co2_rcurve_islope25top_ft * nscaler ! Adjust for temperature - vcmax = vcmax25 * ft1_f(veg_tempk, vcmaxha) * fth_f(veg_tempk, vcmaxhd, vcmaxse, vcmaxc) - jmax = jmax25 * ft1_f(veg_tempk, jmaxha) * fth_f(veg_tempk, jmaxhd, jmaxse, jmaxc) + ! photosynthetic pathway: 0. = c4, 1. = c3 + c3c4_path_index = nint(EDPftvarcon_inst%c3psn(ft)) - if (nint(EDPftvarcon_inst%c3psn(ft)) /= 1) then + if (c3c4_path_index == c3_path_index) then + vcmax = vcmax25 * ft1_f(veg_tempk, vcmaxha) * fth_f(veg_tempk, vcmaxhd, vcmaxse, vcmaxc) + else vcmax = vcmax25 * 2._r8**((veg_tempk-(tfrz+25._r8))/10._r8) vcmax = vcmax / (1._r8 + exp( 0.2_r8*((tfrz+15._r8)-veg_tempk ) )) vcmax = vcmax / (1._r8 + exp( 0.3_r8*(veg_tempk-(tfrz+40._r8)) )) end if + + jmax = jmax25 * ft1_f(veg_tempk, jmaxha) * fth_f(veg_tempk, jmaxhd, jmaxse, jmaxc) + !q10 response of product limited psn. co2_rcurve_islope = co2_rcurve_islope25 * 2._r8**((veg_tempk-(tfrz+25._r8))/10._r8) end if @@ -2065,7 +2331,8 @@ subroutine LeafLayerBiophysicalRates( parsun_lsl, & vcmax = vcmax * btran return -end subroutine LeafLayerBiophysicalRates + + end subroutine LeafLayerBiophysicalRates subroutine lowstorage_maintresp_reduction(frac, pft, maintresp_reduction_factor) @@ -2098,7 +2365,7 @@ subroutine lowstorage_maintresp_reduction(frac, pft, maintresp_reduction_factor) ! --------------------------------------------------------------------------------- if( frac .lt. 1._r8 )then - if ( EDPftvarcon_inst%maintresp_reduction_curvature(pft) .ne. 1._r8 ) then + if ( abs(EDPftvarcon_inst%maintresp_reduction_curvature(pft)-1._r8) > nearzero ) then maintresp_reduction_factor = (1._r8 - EDPftvarcon_inst%maintresp_reduction_intercept(pft)) + & EDPftvarcon_inst%maintresp_reduction_intercept(pft) * & (1._r8 - EDPftvarcon_inst%maintresp_reduction_curvature(pft)**frac) & diff --git a/fire/SFMainMod.F90 b/fire/SFMainMod.F90 index 6b0197dfcc..b056fcc6b8 100644 --- a/fire/SFMainMod.F90 +++ b/fire/SFMainMod.F90 @@ -8,6 +8,7 @@ module SFMainMod use FatesConstantsMod , only : r8 => fates_r8 use FatesConstantsMod , only : itrue, ifalse use FatesConstantsMod , only : pi_const + use FatesConstantsMod , only : nocomp_bareground use FatesInterfaceTypesMod , only : hlm_masterproc ! 1= master process, 0=not master process use EDTypesMod , only : numWaterMem use FatesGlobals , only : fates_log @@ -23,21 +24,19 @@ module SFMainMod use PRTGenericMod , only : element_pos use EDtypesMod , only : ed_site_type - use EDtypesMod , only : ed_patch_type - use EDtypesMod , only : ed_cohort_type + use FatesPatchMod , only : fates_patch_type + use FatesCohortMod , only : fates_cohort_type use EDtypesMod , only : AREA - use EDtypesMod , only : DL_SF - use EDtypesMod , only : crown_fire_threshold ! TODO slevis: NOT used; if end up using, look at SF_val_fire_threshold as template - use EDTypesMod , only : TW_SF - use EDtypesMod , only : LB_SF - use EDtypesMod , only : LG_SF + use FatesLitterMod , only : DL_SF + use FatesLitterMod , only : TW_SF + use FatesLitterMod , only : LB_SF + use FatesLitterMod , only : LG_SF use FatesLitterMod , only : ncwd - use EDtypesMod , only : NFSC - use EDtypesMod , only : TR_SF + use FatesLitterMod , only : NFSC + use FatesLitterMod , only : TR_SF use FatesLitterMod , only : litter_type use PRTGenericMod, only : carbon12_element - use PRTGenericMod, only : all_carbon_elements use PRTGenericMod, only : leaf_organ use PRTGenericMod, only : fnrt_organ use PRTGenericMod, only : sapw_organ @@ -54,10 +53,12 @@ module SFMainMod public :: fire_model public :: fire_danger_index public :: characteristics_of_fuel + public :: characteristics_of_crown public :: rate_of_spread public :: ground_fuel_consumption public :: wind_effect public :: area_burnt_intensity + public :: active_crown_fire public :: crown_scorching public :: crown_damage public :: cambial_damage_kill @@ -66,8 +67,8 @@ module SFMainMod ! The following parameter represents one of the values of hlm_spitfire_mode ! and more of these appear in subroutine area_burnt_intensity below ! NB. The same parameters are set in /src/biogeochem/CNFireFactoryMod - integer :: write_SF = 0 ! for debugging - logical :: debug = .false. ! for debugging + integer :: write_SF = ifalse ! for debugging + logical :: debug = .false. ! for debugging ! ============================================================================ ! ============================================================================ @@ -85,42 +86,41 @@ subroutine fire_model( currentSite, bc_in) type(bc_in_type) , intent(in) :: bc_in - type (ed_patch_type), pointer :: currentPatch + type (fates_patch_type), pointer :: currentPatch + + real(r8) :: canopy_fuel_load ! available canopy fuel load in patch (kg biomass) + real(r8) :: passive_crown_FI ! fire intensity for ignition of passive canopy fuel (kW/m) + real(r8) :: ROS_torch ! ROS for crown torch initation (m/min) + real(r8) :: lb !length to breadth ratio of fire ellipse (unitless) + real(r8) :: heat_per_area ! heat release per unit area (kJ/m2) for surface fuel - real(r8) :: MEF(nfsc) ! Moisture extinction factor of fuels - real(r8) :: fuel_moisture(nfsc) ! Scaled moisture content of small litter fuels !zero fire things currentPatch => currentSite%youngest_patch do while(associated(currentPatch)) currentPatch%frac_burnt = 0.0_r8 + currentPatch%FI = 0.0_r8 + currentPatch%FD = 0.0_r8 currentPatch%fire = 0 currentPatch%active_crown_fire_flg = 0 currentPatch => currentPatch%older enddo - if(write_SF==1)then + if(write_SF==itrue)then write(fates_log(),*) 'spitfire_mode', hlm_spitfire_mode endif if( hlm_spitfire_mode > hlm_sf_nofire_def )then call fire_danger_index(currentSite, bc_in) call wind_effect(currentSite, bc_in) - call characteristics_of_fuel(currentSite, MEF, fuel_moisture) - call rate_of_spread(currentSite, MEF, fuel_moisture) + call characteristics_of_fuel(currentSite) + call characteristics_of_crown(currentSite, canopy_fuel_load, passive_crown_FI) + call rate_of_spread(currentSite, passive_crown_FI, ROS_torch, heat_per_area) call ground_fuel_consumption(currentSite) - call area_burnt_intensity(currentSite, bc_in) + call area_burnt_intensity(currentSite, bc_in, lb) + call active_crown_fire (currentSite,passive_crown_FI,canopy_fuel_load,ROS_torch,heat_per_area,lb) call crown_scorching(currentSite) call crown_damage(currentSite) - ! Begin: Repeat calls to calculate effects of active crown fire - ! TODO slevis: if (currentPatch%active_crown_fire_flg) > 0) - ! at any Patch at this Site, then execute the repeat calls. - ! NB. this subroutine runs at the Site level. -! call rate_of_spread(currentSite, MEF, fuel_moisture) -! call area_burnt_intensity(currentSite, bc_in) -! call crown_scorching(currentSite) -! call crown_damage(currentSite) - ! End: Repeat calls to calculate effects of active crown fire call cambial_damage_kill(currentSite) call post_fire_mortality(currentSite) end if @@ -140,6 +140,8 @@ subroutine fire_danger_index ( currentSite, bc_in) type(ed_site_type) , intent(inout), target :: currentSite type(bc_in_type) , intent(in) :: bc_in + type(fates_patch_type), pointer :: currentPatch + real(r8) :: temp_in_C ! daily averaged temperature in celcius real(r8) :: rainfall ! daily precip in mm/day real(r8) :: rh ! daily rh @@ -154,9 +156,17 @@ subroutine fire_danger_index ( currentSite, bc_in) ! is simply using the values associated with the first patch. ! which probably won't have much inpact, unless we decide to ever calculated the NI for each patch. - iofp = currentSite%oldest_patch%patchno + currentPatch => currentSite%oldest_patch + + ! If the oldest patch is a bareground patch (i.e. nocomp mode is on) use the first vegetated patch + ! for the iofp index (i.e. the next younger patch) + if(currentPatch%nocomp_pft_label .eq. nocomp_bareground)then + currentPatch => currentPatch%younger + endif + + iofp = currentPatch%patchno - temp_in_C = currentSite%oldest_patch%tveg24%GetMean() - tfrz + temp_in_C = currentPatch%tveg24%GetMean() - tfrz rainfall = bc_in%precip24_pa(iofp)*sec_per_day rh = bc_in%relhumid24_pa(iofp) @@ -166,97 +176,98 @@ subroutine fire_danger_index ( currentSite, bc_in) else yipsolon = (SF_val_fdi_a* temp_in_C)/(SF_val_fdi_b+ temp_in_C)+log(max(1.0_r8,rh)/100.0_r8) dewpoint = (SF_val_fdi_b*yipsolon)/(SF_val_fdi_a-yipsolon) !Standard met. formula - d_NI = ( temp_in_C-dewpoint)* temp_in_C !follows Nesterov 1968. Equation 5. Thonicke et al. 2010. + d_NI = ( temp_in_C-dewpoint)* temp_in_C !follows Nesterov 1968. Eq 5, Thonicke et al. 2010. if (d_NI < 0.0_r8) then !Change in NI cannot be negative. d_NI = 0.0_r8 !check endif endif - currentSite%acc_NI = currentSite%acc_NI + d_NI !Accumulate Nesterov index over the fire season. + currentSite%acc_NI = currentSite%acc_NI + d_NI !Accumulate Nesterov index over fire season. end subroutine fire_danger_index - !***************************************************************** - subroutine characteristics_of_fuel ( currentSite, MEF, fuel_moisture ) - !***************************************************************** + !***************************************************************** + subroutine characteristics_of_fuel ( currentSite) + !***************************************************************** - use SFParamsMod, only: SF_val_drying_ratio, SF_val_SAV, SF_val_FBD, & - SF_val_miner_total + use SFParamsMod, only: SF_val_drying_ratio, SF_val_SAV, SF_val_FBD, SF_val_miner_total type(ed_site_type), intent(in), target :: currentSite - type(ed_patch_type), pointer :: currentPatch - type(ed_cohort_type), pointer :: currentCohort + type(fates_patch_type), pointer :: currentPatch + type(fates_cohort_type), pointer :: currentCohort type(litter_type), pointer :: litt_c - ! ARGUMENTS - real(r8), intent(out) :: MEF(nfsc) ! Moisture extinction factor of fuels integer n - real(r8), intent(out) :: fuel_moisture(nfsc) ! Scaled moisture content of small litter fuels - - ! LOCAL VARIABLES real(r8) alpha_FMC(nfsc) ! Relative fuel moisture adjusted per drying ratio + real(r8) fuel_moisture(nfsc) ! Scaled moisture content of small litter fuels + real(r8) MEF(nfsc) ! Moisture extinction factor of fuels, integer n fuel_moisture(:) = 0.0_r8 + currentPatch => currentSite%oldest_patch; + do while (associated(currentPatch)) - currentPatch => currentSite%oldest_patch; - do while(associated(currentPatch)) + if (currentPatch%nocomp_pft_label .ne. nocomp_bareground) then - litt_c => currentPatch%litter(element_pos(carbon12_element)) - - ! How much live grass is there? - currentPatch%livegrass = 0.0_r8 - currentCohort => currentPatch%tallest - do while(associated(currentCohort)) - if( int(prt_params%woody(currentCohort%pft)) == ifalse)then - - currentPatch%livegrass = currentPatch%livegrass + & - currentCohort%prt%GetState(leaf_organ, all_carbon_elements) * & - currentCohort%n/currentPatch%area + litt_c => currentPatch%litter(element_pos(carbon12_element)) + + ! How much live grass is there? + currentPatch%livegrass = 0.0_r8 + currentCohort => currentPatch%tallest + do while(associated(currentCohort)) + ! for grasses sum all aboveground tissues + if( prt_params%woody(currentCohort%pft) == ifalse)then + + currentPatch%livegrass = currentPatch%livegrass + & + ( currentCohort%prt%GetState(leaf_organ, carbon12_element) + & + currentCohort%prt%GetState(sapw_organ, carbon12_element) + & + currentCohort%prt%GetState(struct_organ, carbon12_element) ) * & + currentCohort%n/currentPatch%area endif currentCohort => currentCohort%shorter - enddo - - ! There are SIX fuel classes - ! 1:4) four CWD_AG pools (twig, s branch, l branch, trunk), 5) dead leaves and 6) live grass - ! NCWD =4 NFSC = 6 - ! tw_sf = 1, lb_sf = 3, tr_sf = 4, dl_sf = 5, lg_sf = 6, - + enddo - if(write_sf == itrue)then + ! There are SIX fuel classes + ! 1:4) four CWD_AG pools (twig, s branch, l branch, trunk), 5) dead leaves and 6) live grass + ! NCWD =4 NFSC = 6 + ! tw_sf = 1, lb_sf = 3, tr_sf = 4, dl_sf = 5, lg_sf = 6, + + + if(write_sf == itrue)then if ( hlm_masterproc == itrue ) write(fates_log(),*) ' leaf_litter1 ',sum(litt_c%leaf_fines(:)) if ( hlm_masterproc == itrue ) write(fates_log(),*) ' leaf_litter2 ',sum(litt_c%ag_cwd(:)) if ( hlm_masterproc == itrue ) write(fates_log(),*) ' leaf_litter3 ',currentPatch%livegrass - endif + endif - currentPatch%sum_fuel = sum(litt_c%leaf_fines(:)) + & - sum(litt_c%ag_cwd(:)) + & - currentPatch%livegrass - if(write_SF == itrue)then + currentPatch%sum_fuel = sum(litt_c%leaf_fines(:)) + & + sum(litt_c%ag_cwd(:)) + & + currentPatch%livegrass + if (write_SF == itrue) then if ( hlm_masterproc == itrue ) write(fates_log(),*) 'sum fuel', currentPatch%sum_fuel,currentPatch%area - endif - ! =============================================== - ! Average moisture, bulk density, surface area-volume and moisture extinction of fuel - ! ================================================ - - if (currentPatch%sum_fuel > 0.0) then + endif + + ! =============================================== + ! Average moisture, bulk density, surface area-volume and moisture extinction of fuel + ! ================================================ + + if (currentPatch%sum_fuel > 0.0) then ! Fraction of fuel in litter classes currentPatch%fuel_frac(dl_sf) = sum(litt_c%leaf_fines(:))/ currentPatch%sum_fuel currentPatch%fuel_frac(tw_sf:tr_sf) = litt_c%ag_cwd(:) / currentPatch%sum_fuel - if(write_sf == itrue)then - if ( hlm_masterproc == itrue ) write(fates_log(),*) 'ff2a ', & - lg_sf,currentPatch%livegrass,currentPatch%sum_fuel + if (write_sf == itrue) then + if ( hlm_masterproc == itrue ) write(fates_log(),*) 'ff2a ', & + lg_sf,currentPatch%livegrass,currentPatch%sum_fuel endif currentPatch%fuel_frac(lg_sf) = currentPatch%livegrass / currentPatch%sum_fuel - + ! MEF (moisure of extinction) depends on compactness of fuel, depth, particle size, wind, slope - ! Eqn here is eqn 27 from Peterson and Ryan (1986) "Modeling Postfire Conifer Mortality for Long-Range Planning" + ! Eq here is Eq 27 from Peterson and Ryan (1986) "Modeling Postfire Conifer Mortality for Long-Range Planning" ! but lots of other approaches in use out there... - ! MEF: pine needles=0.30 (text near EQ 28 Rothermal 1972) + ! MEF: pine needles=0.30 (text near Eq 28 Rothermal 1972) ! Table II-1 NFFL mixed fuels models from Rothermal 1983 Gen. Tech. Rep. INT-143 ! MEF: short grass=0.12,tall grass=0.25,chaparral=0.20,closed timber litter=0.30,hardwood litter=0.25 ! Thonicke 2010 SAV values propagated thru P&R86 eqn below gives MEF:tw=0.355, sb=0.44, lb=0.525, tr=0.63, dg=0.248, lg=0.248 @@ -268,28 +279,28 @@ subroutine characteristics_of_fuel ( currentSite, MEF, fuel_moisture ) ! dead leaves and twigs included in 1hr pool per Thonicke (2010) ! Calculate fuel moisture for trunks to hold value for fuel consumption alpha_FMC(tw_sf:dl_sf) = SF_val_SAV(tw_sf:dl_sf)/SF_val_drying_ratio - + fuel_moisture(tw_sf:dl_sf) = exp(-1.0_r8 * alpha_FMC(tw_sf:dl_sf) * currentSite%acc_NI) - + if(write_SF == itrue)then - if ( hlm_masterproc == itrue ) write(fates_log(),*) 'ff3 ',currentPatch%fuel_frac - if ( hlm_masterproc == itrue ) write(fates_log(),*) 'fm ',fuel_moisture - if ( hlm_masterproc == itrue ) write(fates_log(),*) 'csa ',currentSite%acc_NI - if ( hlm_masterproc == itrue ) write(fates_log(),*) 'sfv ',alpha_FMC + if ( hlm_masterproc == itrue ) write(fates_log(),*) 'ff3 ',currentPatch%fuel_frac + if ( hlm_masterproc == itrue ) write(fates_log(),*) 'fm ',fuel_moisture + if ( hlm_masterproc == itrue ) write(fates_log(),*) 'csa ',currentSite%acc_NI + if ( hlm_masterproc == itrue ) write(fates_log(),*) 'sfv ',alpha_FMC endif - + ! live grass moisture is a function of SAV and changes via Nesterov Index ! along the same relationship as the 1 hour fuels (live grass has same SAV as dead grass, ! but retains more moisture with this calculation.) fuel_moisture(lg_sf) = exp(-1.0_r8 * ((SF_val_SAV(tw_sf)/SF_val_drying_ratio) * currentSite%acc_NI)) - + ! Average properties over the first three litter pools (twigs, s branches, l branches) currentPatch%fuel_bulkd = sum(currentPatch%fuel_frac(tw_sf:lb_sf) * SF_val_FBD(tw_sf:lb_sf)) currentPatch%fuel_sav = sum(currentPatch%fuel_frac(tw_sf:lb_sf) * SF_val_SAV(tw_sf:lb_sf)) currentPatch%fuel_mef = sum(currentPatch%fuel_frac(tw_sf:lb_sf) * MEF(tw_sf:lb_sf)) currentPatch%fuel_eff_moist = sum(currentPatch%fuel_frac(tw_sf:lb_sf) * fuel_moisture(tw_sf:lb_sf)) - if(write_sf == itrue)then - if ( hlm_masterproc == itrue ) write(fates_log(),*) 'ff4 ',currentPatch%fuel_eff_moist + if (write_sf == itrue) then + if ( hlm_masterproc == itrue ) write(fates_log(),*) 'ff4 ',currentPatch%fuel_eff_moist endif ! Add on properties of dead leaves and live grass pools (5 & 6) currentPatch%fuel_bulkd = currentPatch%fuel_bulkd + sum(currentPatch%fuel_frac(dl_sf:lg_sf) * SF_val_FBD(dl_sf:lg_sf)) @@ -303,25 +314,24 @@ subroutine characteristics_of_fuel ( currentSite, MEF, fuel_moisture ) currentPatch%fuel_sav = currentPatch%fuel_sav * (1.0_r8/(1.0_r8-currentPatch%fuel_frac(tr_sf))) currentPatch%fuel_mef = currentPatch%fuel_mef * (1.0_r8/(1.0_r8-currentPatch%fuel_frac(tr_sf))) currentPatch%fuel_eff_moist = currentPatch%fuel_eff_moist * (1.0_r8/(1.0_r8-currentPatch%fuel_frac(tr_sf))) - + ! Pass litter moisture into the fuel burning routine (all fuels: twigs,s branch,l branch,trunk,dead leaves,live grass) ! (wo/me term in Thonicke et al. 2010) currentPatch%litter_moisture(tw_sf:lb_sf) = fuel_moisture(tw_sf:lb_sf)/MEF(tw_sf:lb_sf) currentPatch%litter_moisture(tr_sf) = fuel_moisture(tr_sf)/MEF(tr_sf) currentPatch%litter_moisture(dl_sf) = fuel_moisture(dl_sf)/MEF(dl_sf) currentPatch%litter_moisture(lg_sf) = fuel_moisture(lg_sf)/MEF(lg_sf) - - else - - if(write_SF == itrue)then - - if ( hlm_masterproc == itrue ) write(fates_log(),*) 'no litter fuel at all',currentPatch%patchno, & - currentPatch%sum_fuel,sum(litt_c%ag_cwd(:)),sum(litt_c%leaf_fines(:)) + else + if (write_SF == itrue) then + if ( hlm_masterproc == itrue ) write(fates_log(),*) 'no litter fuel at all',currentPatch%patchno, & + currentPatch%sum_fuel,sum(litt_c%ag_cwd(:)),sum(litt_c%leaf_fines(:)) endif currentPatch%fuel_sav = sum(SF_val_SAV(1:nfsc))/(nfsc) ! make average sav to avoid crashing code. - if ( hlm_masterproc == itrue ) write(fates_log(),*) 'problem with spitfire fuel averaging' + if ( hlm_masterproc == itrue .and. write_SF == itrue) then + write(fates_log(),*) 'problem with spitfire fuel averaging' + end if ! FIX(SPM,032414) refactor...should not have 0 fuel unless everything is burnt ! off. @@ -331,25 +341,177 @@ subroutine characteristics_of_fuel ( currentSite, MEF, fuel_moisture ) currentPatch%fuel_mef = 0.0000000001_r8 currentPatch%sum_fuel = 0.0000000001_r8 - endif - ! check values. - ! FIX(SPM,032414) refactor... - if(write_SF == itrue.and.currentPatch%fuel_sav <= 0.0_r8.or.currentPatch%fuel_bulkd <= & - 0.0_r8.or.currentPatch%fuel_mef <= 0.0_r8.or.currentPatch%fuel_eff_moist <= 0.0_r8)then - if ( hlm_masterproc == itrue ) write(fates_log(),*) 'problem with spitfire fuel averaging' - endif - - ! remove mineral content from net fuel load per Thonicke 2010 - ! for ir calculation in subr. rate_of_spread - ! slevis moved here because rate_of_spread is now called twice/timestep - currentPatch%sum_fuel = currentPatch%sum_fuel * (1.0_r8 - SF_val_miner_total) !net of minerals + endif + ! check values. + ! FIX(SPM,032414) refactor... + if (write_SF == itrue.and.currentPatch%fuel_sav <= 0.0_r8.or.currentPatch%fuel_bulkd <= & + 0.0_r8.or.currentPatch%fuel_mef <= 0.0_r8.or.currentPatch%fuel_eff_moist <= 0.0_r8) then + if ( hlm_masterproc == itrue ) write(fates_log(),*) 'problem with spitfire fuel averaging' + endif - currentPatch => currentPatch%younger + ! remove mineral content from net fuel load per Thonicke 2010 + ! for ir calculation in subr. rate_of_spread + ! slevis moved here because rate_of_spread is now called twice/timestep + currentPatch%sum_fuel = currentPatch%sum_fuel * (1.0_r8 - SF_val_miner_total) !net of minerals + + currentPatch => currentPatch%younger + + end if enddo !end patch loop end subroutine characteristics_of_fuel + !**************************************************************** + subroutine characteristics_of_crown ( currentSite, canopy_fuel_load, passive_crown_FI) + !****************************************************************. + + !returns the live crown fuel characteristics within each patch. + ! passive_crown_FI is minimum fire intensity to ignite canopy crown fuel + + use SFParamsMod, only : SF_VAL_CWD_FRAC + + type(ed_site_type), intent(in), target :: currentSite + + type(fates_patch_type) , pointer :: currentPatch + type(fates_cohort_type), pointer :: currentCohort + + ! ARGUMENTS + real(r8), intent(out) :: canopy_fuel_load ! available canopy fuel load in patch (kg biomass) + real(r8), intent(out) :: passive_crown_FI ! min fire intensity to ignite canopy fuel (kW/m) + + ! LOCAL + real(r8) :: crown_depth ! depth of crown (m) + real(r8) :: height_cbb ! clear branch bole height or crown base height (m) + real(r8) :: max_height ! max cohort on patch (m) + real(r8) :: crown_ignite_energy ! heat yield for crown (kJ/kg) + real(r8) :: tree_sapw_struct_c ! above-ground tree struct and sap biomass in cohort (kgC) + real(r8) :: leaf_c ! leaf carbon (kgC) + real(r8) :: sapw_c ! sapwood carbon (kgC) + real(r8) :: struct_c ! structure carbon (kgC) + real(r8) :: twig_sapw_struct_c ! above-ground twig sap and struct in cohort (kgC) + real(r8) :: crown_fuel_c ! biomass of 1 hr fuels (leaves,twigs) in cohort (kg C) + real(r8) :: crown_fuel_biomass ! biomass of crown fuel in cohort (kg biomass) + real(r8) :: crown_fuel_per_m ! crown fuel per 1m section in cohort + real(r8) :: height_base_canopy ! lowest height of fuels in patch to carry fire in crown + + integer :: ih ! counter + + real, dimension(70):: biom_matrix ! matrix to track biomass from bottom to 70m + real(r8),parameter :: min_density_canopy_fuel = 0.011_r8 !min canopy fuel density (kg/m3) sufficient to + !propogate fire vertically through canopy + !Scott and Reinhardt 2001 RMRS-RP-29 + real(r8),parameter :: foliar_moist_content = 1.0_r8 !foliar moisture content default 100% Scott & Reinhardt 2001 + + + !returns the live crown fuel characteristics within each patch. + ! passive_crown_FI is the required minimum fire intensity to ignite canopy crown fuel + + currentPatch => currentSite%oldest_patch + + !! check to see if active_crown_fire is enabled? + + do while(associated(currentPatch)) + !zero Patch level variables + height_base_canopy = 0.0_r8 + canopy_fuel_load = 0.0_r8 + passive_crown_FI = 0.0_r8 + currentPatch%canopy_bulk_density = 0.0_r8 + +! if (currentPatch%active_crown_fire == 1) then + + currentCohort=>currentPatch%tallest + do while(associated(currentCohort)) + + !zero cohort level variables + tree_sapw_struct_c = 0.0_r8 + leaf_c = 0.0_r8 + sapw_c = 0.0_r8 + struct_c = 0.0_r8 + twig_sapw_struct_c = 0.0_r8 + crown_fuel_c = 0.0_r8 + crown_fuel_biomass = 0.0_r8 + crown_fuel_per_m = 0.0_r8 + + ! Calculate crown 1hr fuel biomass (leaf, twig sapwood, twig structural biomass) + if ( int(prt_params%woody(currentCohort%pft)) == itrue) then !trees + + call CrownDepth(currentCohort%height,currentCohort%pft,crown_depth) + height_cbb = currentCohort%height - crown_depth + + !find patch max height for stand canopy fuel + if (currentCohort%height > max_height) then + max_height = currentCohort%height + endif + + leaf_c = currentCohort%prt%GetState(leaf_organ, carbon12_element) + sapw_c = currentCohort%prt%GetState(sapw_organ, carbon12_element) + struct_c = currentCohort%prt%GetState(struct_organ, carbon12_element) + + tree_sapw_struct_c = currentCohort%n * & + (prt_params%allom_agb_frac(currentCohort%pft)*(sapw_c + struct_c)) + + twig_sapw_struct_c = tree_sapw_struct_c * SF_VAL_CWD_frac(1) !only 1hr fuel + + crown_fuel_c = (currentCohort%n * leaf_c) + twig_sapw_struct_c !crown fuel (kgC) + + crown_fuel_biomass = crown_fuel_c / 0.45_r8 ! crown fuel (kg biomass) + + crown_fuel_per_m = crown_fuel_biomass / crown_depth ! kg biomass per m + + !sort crown fuel into bins from bottom to top of crown + !accumulate across cohorts to find density within canopy 1m sections + do ih = int(height_cbb), int(currentCohort%height) + biom_matrix(ih) = biom_matrix(ih) + crown_fuel_per_m + end do + + !accumulate available canopy fuel for patch (kg biomass) + ! use this in CFB (crown fraction burn) calculation and FI final + canopy_fuel_load = canopy_fuel_load + crown_fuel_biomass !canopy fuel in patch + + endif !trees only + + currentCohort => currentCohort%shorter; + + enddo !end cohort loop + + biom_matrix(:) = biom_matrix(:) / currentPatch%area !kg biomass/m3 + + !loop from 1m to 70m to find bin with total density = 0.011 kg/m3 + !min canopy fuel density to propogate fire vertically in canopy across patch + do ih=1,70 + if (biom_matrix(ih) > min_density_canopy_fuel) then + height_base_canopy = float(ih) + exit + end if + end do + + !canopy_bulk_density (kg/m3) for Patch + currentPatch%canopy_bulk_density = sum(biom_matrix) / (max_height - height_base_canopy) + + ! Note: crown_ignition_energy to be calculated based on PFT foliar moisture content from FATES-Hydro + ! or create foliar moisture % based on BTRAN + ! Use foliar_moisture(currentCohort%pft) and compute weighted PFT average with Eq 3 Van Wagner 1977 + ! in place of foliar_moist_content parameter + + ! Eq 3 Van Wagner 1977, Eq 11 Scott & Reinhardt 2001 + ! h = 460.0 + 25.9*m + ! h = crown_ignite_energy (kJ/kg), m = foliar moisture content based on dry fuel (%) + crown_ignite_energy = 460.0 + 25.9 * foliar_moist_content + + ! Crown fuel ignition potential (kW/m), Eq 4 Van Wagner 1977, Eq 11 Scott & Reinhardt 2001 + ! FI = (Czh)**3/2 where z=canopy base height,h=heat of crown ignite energy, FI=fire intensity + ! 0.01 = C, empirical constant Van Wagner 1977 Eq 4 for 6m canopy base height, 100% FMC, FI 2500kW/m + ! passive_crown_FI = min fire intensity to ignite canopy fuel (kW/m or kJ/m/s) + passive_crown_FI = (0.01_r8 * height_base_canopy * crown_ignite_energy)**1.5_r8 + +! endif !active crown fire? + + currentPatch => currentPatch%younger; + + enddo !end patch loop + + end subroutine characteristics_of_crown !***************************************************************** subroutine wind_effect ( currentSite, bc_in) @@ -364,8 +526,8 @@ subroutine wind_effect ( currentSite, bc_in) type(ed_site_type) , intent(inout), target :: currentSite type(bc_in_type) , intent(in) :: bc_in - type(ed_patch_type) , pointer :: currentPatch - type(ed_cohort_type), pointer :: currentCohort + type(fates_patch_type) , pointer :: currentPatch + type(fates_cohort_type), pointer :: currentCohort real(r8) :: total_grass_area ! per patch,in m2 real(r8) :: tree_fraction ! site level. no units @@ -374,10 +536,17 @@ subroutine wind_effect ( currentSite, bc_in) integer :: iofp ! index of oldest fates patch + currentPatch => currentSite%oldest_patch + + ! If the oldest patch is a bareground patch (i.e. nocomp mode is on) use the first vegetated patch + ! for the iofp index (i.e. the next younger patch) + if(currentPatch%nocomp_pft_label .eq. nocomp_bareground)then + currentPatch => currentPatch%younger + endif + ! note - this is a patch level temperature, which probably won't have much inpact, ! unless we decide to ever calculated the NI for each patch. - - iofp = currentSite%oldest_patch%patchno + iofp = currentPatch%patchno currentSite%wind = bc_in%wind24_pa(iofp) * sec_per_min !Convert to m/min for SPITFIRE if(write_SF == itrue)then @@ -390,13 +559,16 @@ subroutine wind_effect ( currentSite, bc_in) grass_fraction = 0.0_r8 currentPatch=>currentSite%oldest_patch; do while(associated(currentPatch)) + + if(currentPatch%nocomp_pft_label .ne. nocomp_bareground)then + currentPatch%total_tree_area = 0.0_r8 total_grass_area = 0.0_r8 currentCohort => currentPatch%tallest do while(associated(currentCohort)) if (debug) write(fates_log(),*) 'SF currentCohort%c_area ',currentCohort%c_area - if( int(prt_params%woody(currentCohort%pft)) == itrue)then + if( prt_params%woody(currentCohort%pft) == itrue)then currentPatch%total_tree_area = currentPatch%total_tree_area + currentCohort%c_area else total_grass_area = total_grass_area + currentCohort%c_area @@ -412,6 +584,8 @@ subroutine wind_effect ( currentSite, bc_in) write(fates_log(),*) 'SF total_grass_area ',tree_fraction,grass_fraction write(fates_log(),*) 'SF AREA ',AREA endif + + endif !nocomp_pft_label check currentPatch => currentPatch%younger enddo !currentPatch loop @@ -427,45 +601,41 @@ subroutine wind_effect ( currentSite, bc_in) currentPatch=>currentSite%oldest_patch; do while(associated(currentPatch)) + if(currentPatch%nocomp_pft_label .ne. nocomp_bareground)then + currentPatch%total_tree_area = min(currentPatch%total_tree_area,currentPatch%area) ! effect_wspeed in units m/min currentPatch%effect_wspeed = currentSite%wind * (tree_fraction*0.4_r8+(grass_fraction+bare_fraction)*0.6_r8) + + endif ! nocomp_pft_label check currentPatch => currentPatch%younger enddo !end patch loop end subroutine wind_effect - !***************************************************************** - subroutine rate_of_spread ( currentSite, MEF, fuel_moisture ) + !******************************************************************* + subroutine rate_of_spread ( currentSite, ROS_torch, passive_crown_FI, heat_per_area) !*****************************************************************. !Routine called daily from within ED within a site loop. !Returns the updated currentPatch%ROS_front value for each patch. - use SFParamsMod, only : SF_val_SAV, & - SF_val_drying_ratio, & + use SFParamsMod, only : SF_val_miner_total, & SF_val_part_dens, & SF_val_miner_damp, & SF_val_fuel_energy - use FatesInterfaceTypesMod, only : hlm_current_day, hlm_current_month - type(ed_site_type), intent(in), target :: currentSite - type(ed_patch_type), pointer :: currentPatch - type(ed_cohort_type), pointer :: currentCohort - type(litter_type), pointer :: litt_c + type(fates_patch_type), pointer :: currentPatch ! ARGUMENTS - real(r8), intent(in) :: MEF(nfsc) ! Moisture extinction factor of fuels - real(r8), intent(in) :: fuel_moisture(nfsc) ! Scaled moisture content of small litter fuels + real(r8), intent(out) :: ROS_torch ! ROS for crown torch initation (m/min) + real(r8), intent(out) :: heat_per_area ! heat release per unit area (kJ/m2) for surface fuel + real(r8), intent(in) :: passive_crown_FI ! min fire intensity to ignite canopy fuel (kW/m or kJ/m/s) ! LOCAL VARIABLES - real(r8) :: sum_fuel ! value saved for comparison - real(r8) :: leaf_c ! leaf carbon [kg] - real(r8) :: alpha_live_fuel ! ratio of mass fine live fuel to mass total fine fuel (1-hour fuels Rothermal 1972) - real(r8) :: fuel_eff_moist_dead - real(r8) :: fuel_mef_fine + ! Rothermal fire spread model parameters. real(r8) beta,beta_op ! weighted average of packing ratio (unitless) real(r8) ir ! reaction intensity (kJ/m2/min) @@ -476,15 +646,17 @@ subroutine rate_of_spread ( currentSite, MEF, fuel_moisture ) real(r8) beta_ratio ! ratio of beta/beta_op real(r8) a_beta ! dummy variable for product of a* beta_ratio for react_v_opt equation real(r8) a,b,c,e ! function of fuel sav + real(r8) time_r ! residence time (min) - logical, parameter :: debug_windspeed = .false. !for debugging - real(r8),parameter :: q_dry = 581.0_r8 !heat of pre-ignition of dry fuels (kJ/kg) + real(r8),parameter :: q_dry = 581.0_r8 !heat of pre-ignition of dry fuels (kJ/kg) + real(r8),parameter :: wind_reduce = 0.2_r8 !wind reduction factor (%) currentPatch=>currentSite%oldest_patch; - litt_c => currentPatch%litter(element_pos(carbon12_element)) do while(associated(currentPatch)) + + if(currentPatch%nocomp_pft_label .ne. nocomp_bareground)then ! ---initialise parameters to zero.--- beta_ratio = 0.0_r8; q_ig = 0.0_r8; eps = 0.0_r8; a = 0.0_r8; b = 0.0_r8; c = 0.0_r8; e = 0.0_r8 @@ -492,36 +664,6 @@ subroutine rate_of_spread ( currentSite, MEF, fuel_moisture ) moist_damp = 0.0_r8; ir = 0.0_r8; a_beta = 0.0_r8; currentPatch%ROS_front = 0.0_r8 - ! --------------------------------------------------- -! ! Active crown fire effects: https://github.com/NGEET/fates/issues/573 -! ! Update some characteristics of fuel -! ! TODO Would it make sense to move this section of code to subr. -! ! characteristics_of_fuel? -! sum_fuel = currentPatch%sum_fuel ! save for comparison later -! if (currentPatch%fire == 1 .and. currentPatch%active_crown_fire_flg == 1) then -! currentCohort=>currentPatch%tallest -! do while(associated(currentCohort)) -! ! Add the leaf carbon from each cohort to currentPatch%sum_fuel -! leaf_c = currentCohort%prt%GetState(leaf_organ, all_carbon_elements) -! currentPatch%sum_fuel = currentPatch%sum_fuel + leaf_c -! currentCohort => currentCohort%shorter; -! enddo !end cohort loop - -! ! if sum_fuel was indeed updated for a case of active crown fire, go -! ! on to update currentPatch%fuel_mef and currentPatch%fuel_eff_moist -! if (currentPatch%sum_fuel > sum_fuel) then -! alpha_live_fuel = (currentPatch%livegrass + leaf_c) / & -! (currentPatch%livegrass + leaf_c + sum(litt_c%leaf_fines(:)) + litt_c%ag_cwd(tw_sf)) -! fuel_eff_moist_dead = sum(currentPatch%fuel_frac(tw_sf:dl_sf) * fuel_moisture(tw_sf:dl_sf)) -! fuel_mef_fine = currentPatch%fuel_frac(tw_sf) * MEF(tw_sf) + & -! currentPatch%fuel_frac(dl_sf) * MEF(dl_sf) + & -! currentPatch%fuel_frac(lg_sf) * MEF(lg_sf) -! currentPatch%fuel_mef = max((2.9_r8 * ((1.0_r8 - alpha_live_fuel) / alpha_live_fuel) * (1.0_r8 - fuel_eff_moist_dead) - 0.226_r8), fuel_mef_fine) -! currentPatch%fuel_eff_moist = exp(-1.0_r8 * currentSite%acc_NI * SF_val_SAV(lg_sf) / SF_val_drying_ratio) -! end if -! end if - ! --------------------------------------------------- - ! ----start spreading--- if ( hlm_masterproc == itrue .and.debug) write(fates_log(),*) & @@ -533,7 +675,7 @@ subroutine rate_of_spread ( currentSite, MEF, fuel_moisture ) ! fraction of fuel array volume occupied by fuel or compactness of fuel bed beta = currentPatch%fuel_bulkd / SF_val_part_dens - ! Equation A6 in Thonicke et al. 2010 + ! Eq A6 in Thonicke et al. 2010 ! packing ratio (unitless) beta_op = 0.200395_r8 *(currentPatch%fuel_sav**(-0.8189_r8)) @@ -546,20 +688,20 @@ subroutine rate_of_spread ( currentSite, MEF, fuel_moisture ) endif ! ---heat of pre-ignition--- - ! Equation A4 in Thonicke et al. 2010 - ! Rothermal EQ12= 250 Btu/lb + 1116 Btu/lb * fuel_eff_moist - ! conversion of Rothermal (1972) EQ12 in BTU/lb to current kJ/kg + ! Eq A4 in Thonicke et al. 2010, Eq 12 Rothermel 1972 + ! 50 Btu/lb + 1116 Btu/lb * fuel_eff_moist + ! conversion of Rothermel (1972) Eq 12 in BTU/lb to current kJ/kg ! q_ig in kJ/kg - q_ig = q_dry +2594.0_r8 * currentPatch%fuel_eff_moist + q_ig = q_dry + 2594.0_r8 * currentPatch%fuel_eff_moist ! ---effective heating number--- - ! Equation A3 in Thonicke et al. 2010. + ! Eq A3 in Thonicke et al. 2010. eps = exp(-4.528_r8 / currentPatch%fuel_sav) - ! Equation A7 in Thonicke et al. 2010 per eqn 49 from Rothermel 1972 + ! Eq A7 in Thonicke et al. 2010 per Eq 49 Rothermel 1972 b = 0.15988_r8 * (currentPatch%fuel_sav**0.54_r8) - ! Equation A8 in Thonicke et al. 2010 per eqn 48 from Rothermel 1972 + ! Eq A8 in Thonicke et al. 2010 per Eq 48 Rothermel 1972 c = 7.47_r8 * (exp(-0.8711_r8 * (currentPatch%fuel_sav**0.55_r8))) - ! Equation A9 in Thonicke et al. 2010. (appears to have typo, using coefficient eqn.50 Rothermel 1972) + ! Eq A9 in Thonicke et al. 2010. (has typo, using coefficient Eq 50 Rothermel 1972) e = 0.715_r8 * (exp(-0.01094_r8 * currentPatch%fuel_sav)) if (debug) then @@ -571,35 +713,35 @@ subroutine rate_of_spread ( currentSite, MEF, fuel_moisture ) if ( hlm_masterproc == itrue .and.debug) write(fates_log(),*) 'SF - e ',e endif - ! Equation A5 in Thonicke et al. 2010 + ! Eq A5 in Thonicke et al. 2010 ! phi_wind (unitless) ! convert current_wspeed (wind at elev relevant to fire) from m/min to ft/min for Rothermel ROS eqn phi_wind = c * ((3.281_r8*currentPatch%effect_wspeed)**b)*(beta_ratio**(-e)) ! ---propagating flux---- - ! Equation A2 in Thonicke et al.2010 and Eq. 42 Rothermal 1972 + ! Eq A2 in Thonicke et al.2010 and Eq 42 Rothermel 1972 ! xi (unitless) xi = (exp((0.792_r8 + 3.7597_r8 * (currentPatch%fuel_sav**0.5_r8)) * (beta+0.1_r8))) / & (192_r8+7.9095_r8 * currentPatch%fuel_sav) ! ---reaction intensity---- - ! Equation in table A1 Thonicke et al. 2010. + ! Eq in table A1 Thonicke et al. 2010. a = 8.9033_r8 * (currentPatch%fuel_sav**(-0.7913_r8)) a_beta = exp(a*(1.0_r8-beta_ratio)) !dummy variable for reaction_v_opt equation - ! Equation in table A1 Thonicke et al. 2010. + ! Eq in table A1 Thonicke et al. 2010. ! reaction_v_max and reaction_v_opt = reaction velocity in units of per min - ! reaction_v_max = Equation 36 in Rothermal 1972 and Fig 12 + ! reaction_v_max = Eq 36 in Rothermel 1972 and Fig 12 reaction_v_max = 1.0_r8 / (0.0591_r8 + 2.926_r8* (currentPatch%fuel_sav**(-1.5_r8))) - ! reaction_v_opt = Equation 38 in Rothermal 1972 and Fig 11 + ! reaction_v_opt = Eq 38 in Rothermel 1972 and Fig 11 reaction_v_opt = reaction_v_max*(beta_ratio**a)*a_beta ! mw_weight = relative fuel moisture/fuel moisture of extinction ! average values for litter pools (dead leaves, twigs, small and large branches) plus grass mw_weight = currentPatch%fuel_eff_moist/currentPatch%fuel_mef - ! Equation in table A1 Thonicke et al. 2010. + ! Eq in table A1 Thonicke et al. 2010. ! moist_damp is unitless moist_damp = max(0.0_r8,(1.0_r8 - (2.59_r8 * mw_weight) + (5.11_r8 * (mw_weight**2.0_r8)) - & (3.52_r8*(mw_weight**3.0_r8)))) @@ -610,19 +752,33 @@ subroutine rate_of_spread ( currentSite, MEF, fuel_moisture ) ! write(fates_log(),*) 'ir',gamma_aptr,moist_damp,SF_val_fuel_energy,SF_val_miner_damp + if (((currentPatch%fuel_bulkd) <= 0.0_r8).or.(eps <= 0.0_r8).or.(q_ig <= 0.0_r8)) then currentPatch%ROS_front = 0.0_r8 - else ! Equation 9. Thonicke et al. 2010. + ROS_torch = 0.0_r8 + else ! Eq 9. Thonicke et al. 2010. ! forward ROS in m/min currentPatch%ROS_front = (ir*xi*(1.0_r8+phi_wind)) / (currentPatch%fuel_bulkd*eps*q_ig) ! write(fates_log(),*) 'ROS',currentPatch%ROS_front,phi_wind,currentPatch%effect_wspeed ! write(fates_log(),*) 'ros calcs',currentPatch%fuel_bulkd,ir,xi,eps,q_ig + + ! calculate heat release per unit area (HPA)(kJ/m2), Eq 2 Scott & Reinhardt 2001 + ! and residence time (min), Eq 3 Scott & Reinhardt 2001 + time_r = 12.595 / currentPatch%fuel_sav + heat_per_area = ir * time_r + + ! calculate torching index based on wind speed and crown fuels + ! ROS for crown torch initation (m/min), Eq 18 Scott & Reinhardt 2001 + ROS_torch = (1.0 / 54.683 * wind_reduce)* & + ((((60.0*passive_crown_FI*currentPatch%fuel_bulkd*eps*q_ig)/heat_per_area*ir*xi)-1.0) & + / (c*beta_ratio)**(-1*e))**1/b endif - ! Equation 10 in Thonicke et al. 2010 + ! Eq 10 in Thonicke et al. 2010 ! backward ROS from Can FBP System (1992) in m/min ! backward ROS wind not changed by vegetation currentPatch%ROS_back = currentPatch%ROS_front*exp(-0.012_r8*currentSite%wind) + end if ! nocomp_pft_label check currentPatch => currentPatch%younger enddo !end patch loop @@ -639,7 +795,7 @@ subroutine ground_fuel_consumption ( currentSite ) SF_val_mid_moisture_Coeff, SF_val_mid_moisture_Slope type(ed_site_type) , intent(in), target :: currentSite - type(ed_patch_type), pointer :: currentPatch + type(fates_patch_type), pointer :: currentPatch type(litter_type), pointer :: litt_c ! carbon 12 litter pool real(r8) :: moist !effective fuel moisture @@ -651,9 +807,12 @@ subroutine ground_fuel_consumption ( currentSite ) currentPatch => currentSite%oldest_patch; do while(associated(currentPatch)) + + if(currentPatch%nocomp_pft_label .ne. nocomp_bareground)then + currentPatch%burnt_frac_litter(:) = 1.0_r8 ! Calculate fraction of litter is burnt for all classes. - ! Equation B1 in Thonicke et al. 2010--- + ! Eq B1 in Thonicke et al. 2010--- do c = 1, nfsc !work out the burnt fraction for all pools, even if those pools dont exist. moist = currentPatch%litter_moisture(c) ! 1. Very dry litter @@ -710,6 +869,8 @@ subroutine ground_fuel_consumption ( currentSite ) ! ignore 1000hr fuels. Just interested in fuels affecting ROS currentPatch%TFC_ROS = sum(FC_ground)-FC_ground(tr_sf) + end if ! nocomp_pft_label check + currentPatch=>currentPatch%younger; enddo !end patch loop @@ -717,7 +878,7 @@ end subroutine ground_fuel_consumption !***************************************************************** - subroutine area_burnt_intensity ( currentSite, bc_in ) + subroutine area_burnt_intensity ( currentSite, bc_in, lb) !***************************************************************** !returns the updated currentPatch%FI value for each patch. @@ -733,45 +894,57 @@ subroutine area_burnt_intensity ( currentSite, bc_in ) use EDParamsMod, only : cg_strikes ! fraction of cloud-to-ground ligtning strikes use FatesConstantsMod, only : years_per_day use SFParamsMod, only : SF_val_fdi_alpha,SF_val_fuel_energy, & - SF_val_max_durat, SF_val_durat_slope, SF_val_fire_threshold + SF_val_max_durat, SF_val_durat_slope, SF_val_fire_threshold type(ed_site_type), intent(inout), target :: currentSite - type(ed_patch_type), pointer :: currentPatch + type(fates_patch_type), pointer :: currentPatch type(bc_in_type), intent(in) :: bc_in - real(r8) ROS !m/s - real(r8) W !kgBiomass/m2 - real(r8) :: tree_fraction_patch ! patch level. no units - real(r8) lb !length to breadth ratio of fire ellipse (unitless) - real(r8) df !distance fire has travelled forward in m - real(r8) db !distance fire has travelled backward in m - real(r8) AB !daily area burnt in m2 per km2 - - real(r8) size_of_fire !in m2 - real(r8) cloud_to_ground_strikes ! [fraction] depends on hlm_spitfire_mode - real(r8) anthro_ign_count ! anthropogenic ignition count/km2/day - integer :: iofp ! index of oldest fates patch + ! ARGUMENTS + real(r8), intent(out) :: lb !length to breadth ratio of fire ellipse (unitless) + + ! LOCAL VARIABLES + real(r8) ROS !rate of spread (m/s) + real(r8) W !available fuel (kgBiomass/m2) + real(r8) :: tree_fraction_patch !patch level. no units + real(r8) df !distance fire has travelled forward (m) + real(r8) db !distance fire has travelled backward (m) + real(r8) AB !daily area burnt (m2 per km2) + real(r8) size_of_fire !in m2 + real(r8) cloud_to_ground_strikes ! [fraction] depends on hlm_spitfire_mode + real(r8) anthro_ign_count ! anthropogenic ignition count/km2/day + integer :: iofp ! index of oldest fates patch real(r8), parameter :: pot_hmn_ign_counts_alpha = 0.0035_r8 ! Potential human ignition counts (alpha in Li et al. 2012) (#/person/month) - real(r8), parameter :: km2_to_m2 = 1000000.0_r8 !area conversion for square km to square m + real(r8), parameter :: km2_to_m2 = 1000000.0_r8 ! area conversion for square km to square m real(r8), parameter :: m_per_min__to__km_per_hour = 0.06_r8 ! convert wind speed from m/min to km/hr - real(r8), parameter :: forest_grassland_lengthtobreadth_threshold = 0.55_r8 ! tree canopy cover below which to use grassland length-to-breadth eqn + real(r8), parameter :: forest_grassland_lengthtobreadth_threshold = 0.55_r8 ! tree canopy cover below which to use + ! grassland length-to-breadth eqn + ! 0.55 = benchmark forest cover, Staver 2010 ! ---initialize site parameters to zero--- currentSite%NF_successful = 0._r8 - ! Equation 7 from Venevsky et al GCB 2002 (modification of equation 8 in Thonicke et al. 2010) + ! Eq 7 from Venevsky et al GCB 2002 (modification of Eqn 8, Thonicke et al. 2010) ! FDI 0.1 = low, 0.3 moderate, 0.75 high, and 1 = extreme ignition potential for alpha 0.000337 if (hlm_spitfire_mode == hlm_sf_successful_ignitions_def) then - currentSite%FDI = 1.0_r8 ! READING "SUCCESSFUL IGNITION" DATA - ! force ignition potential to be extreme + currentSite%FDI = 1.0_r8 ! READING "SUCCESSFUL IGNITION" DATA + ! force ignition potential to be extreme cloud_to_ground_strikes = 1.0_r8 ! cloud_to_ground = 1 = use 100% incoming observed ignitions else ! USING LIGHTNING DATA currentSite%FDI = 1.0_r8 - exp(-SF_val_fdi_alpha*currentSite%acc_NI) cloud_to_ground_strikes = cg_strikes end if + currentPatch => currentSite%oldest_patch + + ! If the oldest patch is a bareground patch (i.e. nocomp mode is on) use the first vegetated patch + ! for the iofp index (i.e. the next younger patch) + if(currentPatch%nocomp_pft_label .eq. nocomp_bareground)then + currentPatch => currentPatch%younger + endif + !NF = number of lighting strikes per day per km2 scaled by cloud to ground strikes - iofp = currentSite%oldest_patch%patchno + iofp = currentPatch%patchno if (hlm_spitfire_mode == hlm_sf_scalar_lightning_def ) then currentSite%NF = ED_val_nignitions * years_per_day * cloud_to_ground_strikes else ! use external daily lightning ignition data @@ -794,6 +967,9 @@ subroutine area_burnt_intensity ( currentSite, bc_in ) currentPatch => currentSite%oldest_patch; do while(associated(currentPatch)) + + if(currentPatch%nocomp_pft_label .ne. nocomp_bareground)then + ! ---initialize patch parameters to zero--- currentPatch%FI = 0._r8 currentPatch%fire = 0 @@ -802,14 +978,14 @@ subroutine area_burnt_intensity ( currentSite, bc_in ) if (currentSite%NF > 0.0_r8) then - ! Equation 14 in Thonicke et al. 2010 + ! Eq 14 in Thonicke et al. 2010 ! fire duration in minutes currentPatch%FD = (SF_val_max_durat+1.0_r8) / (1.0_r8 + SF_val_max_durat * & exp(SF_val_durat_slope*currentSite%FDI)) if(write_SF == itrue)then if ( hlm_masterproc == itrue ) write(fates_log(),*) 'fire duration minutes',currentPatch%fd endif - !equation 15 in Arora and Boer CTEM model.Average fire is 1 day long. + !Eq 15 in Arora and Boer CTEM model.Average fire is 1 day long. !currentPatch%FD = 60.0_r8 * 24.0_r8 !no minutes in a day tree_fraction_patch = 0.0_r8 @@ -825,12 +1001,12 @@ subroutine area_burnt_intensity ( currentSite, bc_in ) if ((currentPatch%effect_wspeed*m_per_min__to__km_per_hour) < 1._r8) then !16.67m/min = 1km/hr lb = 1.0_r8 else - if (tree_fraction_patch > forest_grassland_lengthtobreadth_threshold) then !benchmark forest cover, Staver 2010 - ! EQ 79 forest fuels (Canadian Forest Fire Behavior Prediction System Ont.Inf.Rep. ST-X-3, 1992) + if (tree_fraction_patch > forest_grassland_lengthtobreadth_threshold) then + ! Eq 79 forest fuels (Canadian Forest Fire Behavior Prediction System Ont.Inf.Rep. ST-X-3, 1992) lb = (1.0_r8 + (8.729_r8 * & ((1.0_r8 -(exp(-0.03_r8 * m_per_min__to__km_per_hour * currentPatch%effect_wspeed)))**2.155_r8))) - else ! EQ 80 grass fuels (CFFBPS Ont.Inf.Rep. ST-X-3, 1992, but with a correction from an errata published within - ! Information Report GLC-X-10 by Bottom et al., 2009 because there is a typo in CFFBPS Ont.Inf.Rep. ST-X-3, 1992) + else ! Eq 80 grass fuels (CFFBPS Ont.Inf.Rep. ST-X-3, 1992, with correction from errata published in + ! Inf.Rep. GLC-X-10 (Bottom et al., 2009) because of typo in CFFBPS Ont.Inf.Rep. ST-X-3, 1992) lb = (1.1_r8*((m_per_min__to__km_per_hour * currentPatch%effect_wspeed)**0.464_r8)) endif endif @@ -845,12 +1021,12 @@ subroutine area_burnt_intensity ( currentSite, bc_in ) ! --- calculate area burnt--- if(lb > 0.0_r8) then - ! Equation 1 in Thonicke et al. 2010 + ! Eq 1 in Thonicke et al. 2010 ! To Do: Connect here with the Li & Levis GDP fire suppression algorithm. - ! Equation 16 in arora and boer model JGR 2005 + ! Eq 16 in arora and boer model JGR 2005 ! AB = AB *3.0_r8 - !size of fire = equation 14 Arora and Boer JGR 2005 (area of an ellipse) + !size of fire = Eq 14 Arora and Boer JGR 2005 (area of an ellipse) size_of_fire = ((pi_const/(4.0_r8*lb))*((df+db)**2.0_r8)) ! AB = daily area burnt = size fires in m2 * num ignitions per day per km2 * prob ignition starts fire @@ -873,12 +1049,12 @@ subroutine area_burnt_intensity ( currentSite, bc_in ) currentPatch%frac_burnt = 0._r8 endif ! lb - ROS = currentPatch%ROS_front / 60.0_r8 !m/min to m/sec - W = currentPatch%TFC_ROS / 0.45_r8 !kgC/m2 of burned area to kgbiomass/m2 of burned area + ROS = currentPatch%ROS_front / 60.0_r8 !m/min to m/sec for FI calculation + W = currentPatch%TFC_ROS / 0.45_r8 !kgC/m2 of burned area to kgbiomass/m2 of burned area - ! EQ 15 Thonicke et al 2010 - !units of fire intensity = (kJ/kg)*(kgBiomass/m2)*(m/min) - currentPatch%FI = SF_val_fuel_energy * W * ROS !kj/m/s, or kW/m + ! Eq 15 Thonicke et al 2010 + !units of fire intensity = (kJ/kg)*(kgBiomass/m2)*(m/sec) + currentPatch%FI = SF_val_fuel_energy * W * ROS !kj/m/s, or kW/m if(write_sf == itrue)then if( hlm_masterproc == itrue ) write(fates_log(),*) 'fire_intensity',currentPatch%fi,W,currentPatch%ROS_front @@ -897,7 +1073,8 @@ subroutine area_burnt_intensity ( currentSite, bc_in ) currentPatch%frac_burnt = 0.0_r8 endif - endif! NF ignitions check + endif ! NF ignitions check + endif ! nocomp_pft_label check currentPatch => currentPatch%younger @@ -905,6 +1082,282 @@ subroutine area_burnt_intensity ( currentSite, bc_in ) end subroutine area_burnt_intensity + !***************************************************************** + subroutine active_crown_fire ( currentSite, canopy_fuel_load, ROS_torch, & + lb, heat_per_area, passive_crown_FI) + !***************************************************************** + + !evaluates if there will be an active crown fire based on canopy fuel and rate of spread + !returns final rate of spread and fire intensity in patch with added fuel from active crown fire. + !currentCohort%fraction_crown_burned is the proportion of crown affected by fire + + use SFParamsMod, only : SF_val_miner_total, SF_val_part_dens, SF_val_miner_damp, & + SF_val_fuel_energy, SF_val_drying_ratio + + + type(ed_site_type), intent(in), target :: currentSite + + type(fates_patch_type) , pointer :: currentPatch + type(fates_cohort_type), pointer :: currentCohort + + ! ARGUMENTS + real(r8), intent(in) :: ROS_torch ! ROS for crown torch initation (m/min) + real(r8), intent(in) :: canopy_fuel_load ! available canopy fuel load in patch (kg biomass) + real(r8), intent(in) :: lb !length to breadth ratio of fire ellipse (unitless) + real(r8), intent(in) :: heat_per_area ! heat release per unit area (kJ/m2) for surface fuel + real(r8), intent(in) :: passive_crown_FI ! fire intensity for ignition of passive canopy fuel (kW/m) + + ! Active crown Rothermel fire spread model parameters using FM 10 + real(r8) beta,beta_op ! weighted average of packing ratio (unitless) + real(r8) ir ! reaction intensity (kJ/m2/min) + real(r8) xi,eps,phi_wind ! all are unitless + real(r8) q_ig ! heat of pre-ignition (kJ/kg) + real(r8) reaction_v_opt,reaction_v_max !reaction velocity (per min)!optimum and maximum + real(r8) moist_damp,mw_weight ! moisture dampening coefficient and ratio fuel moisture to extinction + real(r8) beta_ratio ! ratio of beta/beta_op + real(r8) a_beta ! dummy variable for product of a* beta_ratio for react_v_opt equation + real(r8) a,b,c,e ! function of fuel sav + real(r8) total_fuel ! total fuel (kg biomass/m2) + real(r8) net_fuel ! net fuel (kg biomass/m2) without minerals + real(r8) fuel_depth ! fuel depth (m) + real(r8) fuel_bd ! fuel bulk density (kg biomass/m3) + real(r8) fuel_sav ! fuels average sav + real(r8) fuel_eff_moist ! fuels effective moisture + real(r8) fuel_moist1hr ! moisture 1 hour fuels + real(r8) fuel_moist10hr ! moisture 10 hour fuels + real(r8) fuel_moist100hr ! moisture 100 hour fuels + real(r8) fuel_moistlive ! moisture live fuels + real(r8) fuel_1hr + real(r8) fuel_10hr + real(r8) fuel_100hr + real(r8) fuel_live + real(r8) SAV_1hr ! surface area to volume 1 hour fuels (twigs) + real(r8) SAV_10hr ! surface area to volume 10 hour fuels (small branches) + real(r8) SAV_100hr ! surface area to volume 100 hour fuels (large branches) + real(r8) SAV_live ! surface area to volume live fuels + real(r8) midflame_wind ! 40% of open wind speed, Scott & Reinhardt 2001 + real(r8) db ! distance fire has traveld backward (m) + real(r8) df ! distance fire has travelled forward (m) + real(r8) AB ! daily area burnt (m2 per km2) + real(r8) size_of_fire ! in m2 + real(r8) ROS_active ! actual rate of spread (m/min) using FM 10 fuels + real(r8) ROS_active_min ! minimum rate of spread to ignite active crown fire + real(r8) CI_temp ! temporary variable to calculate wind_active_min + real(r8) wind_active_min ! open windspeed to sustain active crown fire where ROS_SA = ROS_active_min + real(r8) ROS_SA ! rate of spread for surface fire with wind_active_min + real(r8) canopy_frac_burnt ! fraction of canopy fuels consumed (0, surface fire to 1,active crown fire) + real(r8) ROS_final ! final rate of spread for combined surface and canopy spread (m/min) + real(r8) FI_final ! final fireline intensity (kW/m or kJ/m/sec) with canopy consumption + + real(r8),parameter :: q_dry = 581.0_r8 !heat of pre-ignition of dry fuels (kJ/kg) + ! fuel loading, MEF, and depth from Anderson 1982 Aids to determining fuel models for fire behavior + ! SAV values from BEHAVE model Burgan & Rothermel (1984) + real(r8),parameter :: fuel_1hr_ton = 3.01_r8 ! FM 10 1-hr fuel loading (US tons/acre) + real(r8),parameter :: fuel_10hr_ton = 2.0_r8 ! FM 10 10-hr fuel loading (US tons/acre) + real(r8),parameter :: fuel_100hr_ton = 5.01_r8 ! FM 10 100-hr fuel loading (US tons/acre) + real(r8),parameter :: fuel_live_ton = 2.0_r8 ! FM 10 live fuel loading (US tons/acre) + real(r8),parameter :: fuel_mef = 0.25_r8 ! FM 10 moisture of extinction (volumetric) + real(r8),parameter :: fuel_depth_ft= 1.0_r8 ! FM 10 fuel depth (ft) + real(r8),parameter :: sav_1hr_ft = 2000.0_r8 ! FM 10 1-hr SAV (ft2/ft3) + real(r8),parameter :: sav_10hr_ft = 109.0_r8 ! FM 10 10-hr SAV (ft2/ft3) + real(r8),parameter :: sav_100hr_ft = 30.0_r8 ! FM 10 100-hr SAV (ft2/ft3) + real(r8),parameter :: sav_live_ft = 1650.0_r8 ! FM 10 live SAV (ft2/ft3) + real(r8),parameter :: tonnes_acre_to_kg_m2 = 0.2241701 ! convert tons/acre to kg/m2 + real(r8),parameter :: sqft_cubicft_to_sqm_cubicm = 0.03280844 !convert ft2/ft3 to m2/m3 + real(r8),parameter :: canopy_ignite_energy = 18000_r8 ! heat yield for canopy fuels (kJ/kg) + real(r8),parameter :: critical_mass_flow_rate = 0.05_r8 ! critical mass flow rate (kg/m2/sec)for crown fire + real(r8),parameter :: km2_to_m2 = 1000000.0_r8 ! area conversion for square km to square m + + integer :: passive_canopy_fuel_flg ! flag if canopy fuel true for vertical spread + + + currentPatch => currentSite%oldest_patch + + !! check to see if active_crown_fire is enabled + + do while(associated(currentPatch)) + + if (currentPatch%fire == 1) then + passive_canopy_fuel_flg = 0 !does patch have canopy fuels for vertical spread? + ROS_active = 0.0_r8 + + ! check initiation of passive crown fire + if (currentPatch%FI >= passive_crown_FI) then + passive_canopy_fuel_flg = 1 !enough passive canopy fuels for vertical spread + + ! Calculate rate of spread using FM 10 as in Rothermel 1977 + ! fuel characteristics + fuel_1hr = fuel_1hr_ton * tonnes_acre_to_kg_m2 + fuel_10hr = fuel_10hr_ton * tonnes_acre_to_kg_m2 + fuel_100hr = fuel_100hr_ton * tonnes_acre_to_kg_m2 + fuel_live = fuel_live_ton * tonnes_acre_to_kg_m2 + + total_fuel = (fuel_1hr + fuel_10hr + fuel_100hr + fuel_live) !total fuel (kg/m2) + + SAV_1hr = sav_1hr_ft * sqft_cubicft_to_sqm_cubicm + SAV_10hr = sav_10hr_ft * sqft_cubicft_to_sqm_cubicm + SAV_100hr = sav_100hr_ft * sqft_cubicft_to_sqm_cubicm + SAV_live = sav_live_ft * sqft_cubicft_to_sqm_cubicm + + fuel_moist1hr = exp(-1.0_r8 * ((SAV_1hr/SF_val_drying_ratio) * currentSite%acc_NI)) + fuel_moist10hr = exp(-1.0_r8 * ((SAV_10hr/SF_val_drying_ratio) * currentSite%acc_NI)) + fuel_moist100hr = exp(-1.0_r8 * ((SAV_100hr/SF_val_drying_ratio) * currentSite%acc_NI)) + fuel_moistlive = exp(-1.0_r8 * ((SAV_live/SF_val_drying_ratio) * currentSite%acc_NI)) + + fuel_depth = fuel_depth_ft *0.3048 !convert to meters + fuel_bd = total_fuel/fuel_depth !fuel bulk density (kg/m3) + + fuel_sav = SAV_1hr *(fuel_1hr/total_fuel) + SAV_10hr*(fuel_10hr/total_fuel) + & + SAV_100hr*(fuel_100hr/total_fuel) + SAV_live*(fuel_live/total_fuel) + + fuel_eff_moist = fuel_moist1hr *(fuel_1hr/total_fuel) + fuel_moist10hr*(fuel_10hr/total_fuel) + & + fuel_moist100hr*(fuel_100hr/total_fuel) + fuel_moistlive*(fuel_live/total_fuel) + + ! remove mineral content from net fuel load + net_fuel = total_fuel * (1.0_r8 - SF_val_miner_total) !net of minerals + + ! ---start spreading--- + !beta = packing ratio (unitless) + beta = fuel_bd / SF_val_part_dens + beta_op = 0.200395_r8 *(fuel_sav**(-0.8189_r8)) + beta_ratio = beta/beta_op + + ! -- heat of pre-ignition -- + q_ig = q_dry + 2594.0_r8 * fuel_eff_moist + + ! ---effective heating number--- + ! Eq A3 in Thonicke et al. 2010. + eps = exp(-4.528_r8 / fuel_sav) + ! Eq A7 in Thonicke et al. 2010 per Eq 49, Rothermel 1972 + b = 0.15988_r8 * (fuel_sav**0.54_r8) + ! Eq A8 in Thonicke et al. 2010 per Eq 48, Rothermel 1972 + c = 7.47_r8 * (exp(-0.8711_r8 * (fuel_sav**0.55_r8))) + ! Eq A9 in Thonicke et al. 2010. (typo in Eq A9, using coefficient Eq 50, Rothermel 1972) + e = 0.715_r8 * (exp(-0.01094_r8 * fuel_sav)) + + midflame_wind = currentSite%wind *0.40_r8 !Scott & Reinhardt 2001 40% open wind speed + + ! Eq A5 in Thonicke et al. 2010 + ! include convert wind from m/min to ft/min for Rothermel ROS eqn + phi_wind = c * ((3.281_r8*midflame_wind)**b)*(beta_ratio**(-e)) !unitless + + ! ---propagating flux = xi (unitless) + ! Eq A2 in Thonicke et al.2010 and Eq 42 Rothermel 1972 + xi = (exp((0.792_r8 + 3.7597_r8 * (fuel_sav**0.5_r8)) * (beta+0.1_r8))) / & + (192_r8+7.9095_r8 * fuel_sav) + + ! ---reaction intensity---- + ! Eq in table A1 Thonicke et al. 2010. + a = 8.9033_r8 * (fuel_sav**(-0.7913_r8)) + a_beta = exp(a*(1.0_r8-beta_ratio)) !dummy variable for reaction_v_opt equation + + ! Eq in table A1 Thonicke et al. 2010. + ! reaction_v_max and reaction_v_opt = reaction velocity in units of per min + ! reaction_v_max = Eq 36 in Rothermel 1972 and Fig 12 + reaction_v_max = 1.0_r8 / (0.0591_r8 + 2.926_r8* (fuel_sav**(-1.5_r8))) + ! reaction_v_opt = Eq 38 in Rothermel 1972 and Fig 11 + reaction_v_opt = reaction_v_max*(beta_ratio**a)*a_beta + + ! mw_weight = relative fuel moisture/fuel moisture of extinction + mw_weight = fuel_eff_moist/fuel_mef + + ! Eq in table A1 Thonicke et al. 2010. (unitless) + moist_damp = max(0.0_r8,(1.0_r8 - (2.59_r8 * mw_weight) + (5.11_r8 * (mw_weight**2.0_r8)) - & + (3.52_r8*(mw_weight**3.0_r8)))) + + ! ir = reaction intenisty in kJ/m2/min + ! sum_fuel as kgBiomass/m2 for ir calculation + ir = reaction_v_opt*(net_fuel)*SF_val_fuel_energy*moist_damp*SF_val_miner_damp + + ! actual ROS (m/min) for FM 10 fuels for open windspeed, Eq 8 Scott & Reinhardt 2001 + ROS_active = 3.34_r8*((ir*xi*(1.0_r8+phi_wind)) / (fuel_bd * eps * q_ig)) + + ! critical min rate of spread (m/min) for active crowning + ROS_active_min = (critical_mass_flow_rate / fuel_bd) * 60.0_r8 + + ! check threshold intensity and rate of spread + if (currentPatch%FI >= passive_crown_FI .and. ROS_active >= ROS_active_min) then + currentPatch%active_crown_fire_flg = 1 ! active crown fire ignited + + !ROS_final = ROS_surface+CFB(ROS_active - ROS_surface), Eq 21 Scott & Reinhardt 2001 + !with active crown fire CFB (canopy fraction burned) = 100% + canopy_frac_burnt = 1.0_r8 + ROS_final = currentPatch%ROS_front + canopy_frac_burnt*(ROS_active-currentPatch%ROS_front) + + else + currentPatch%active_crown_fire_flg = 0 ! only passive crown fire with partial crown burnt + + ! phi_slope is not used yet. consider adding with later development + ! calculate open wind speed critical to sustain active crown fire Eq 20 Scott & Reinhardt + CI_temp = ((164.8_r8 * eps * q_ig)/(ir * currentPatch%canopy_bulk_density)) - 1.0_r8 + + wind_active_min = 0.0457_r8*(CI_temp/0.001612_r8)**0.7_r8 + + ! use open wind speed "wind_active_min" for ROS surface fire where ROS_SA=ROS_active_min + ROS_SA = (ir * xi * (1.0_r8 + wind_active_min)) / (fuel_bd * eps * q_ig) + + ! canopy fraction burnt, Eq 28 Scott & Reinhardt Appendix A + canopy_frac_burnt = (min(1.0_r8, ((currentPatch%ROS_front - ROS_active_min) & + /(ROS_SA - ROS_active_min)))) + + !ROS_final = ROS_surface+CFB(ROS_active - ROS_surface), Eq 21 Scott & Reinhardt 2001 + ROS_final = currentPatch%ROS_front + canopy_frac_burnt*(ROS_active-currentPatch%ROS_front) + + endif !check intensity & ROS for active crown fire thresholds + + ! recalculate area burned with new ROS_front value from ROS_final + ! ---- re-calculate length of major axis for df using new ROS_front value from ROS final--- + db = currentPatch%ROS_back * currentPatch%FD !(m) + df = ROS_final * currentPatch%FD !(m) update with ROS final + + ! update ROS_front with ROS_final for output variable + currentPatch%ROS_front = ROS_final + + ! --- calculate updated area burnt using df from ROS final--- + if(lb > 0.0_r8) then + + ! Eq 1 in Thonicke et al. 2010 + ! To Do: Connect here with the Li & Levis GDP fire suppression algorithm. + ! Eq 16 in arora and boer model JGR 2005 + ! AB = AB *3.0_r8 + + !size of fire = Eq 14 Arora and Boer JGR 2005 (area of an ellipse) + size_of_fire = ((pi_const/(4.0_r8*lb))*((df+db)**2.0_r8)) + + ! AB = daily area burnt = size fires in m2 * num ignitions per day per km2 * prob ignition starts fire + ! AB = m2 per km2 per day + ! the denominator in the units of currentSite%NF is total gridcell area, but since we assume that ignitions + ! are equally probable across patches, currentSite%NF is equivalently per area of a given patch + ! thus AB has units of m2 burned area per km2 patch area per day + AB = size_of_fire * currentSite%NF * currentSite%FDI + + ! frac_burnt + ! just a unit conversion from AB, to become area burned per area patch per day, + ! or just the fraction of the patch burned on that day + currentPatch%frac_burnt = (min(0.99_r8, AB / km2_to_m2)) + + if(write_SF == itrue)then + if ( hlm_masterproc == itrue ) write(fates_log(),*) 'frac_burnt',currentPatch%frac_burnt + endif + + else + currentPatch%frac_burnt = 0.0_r8 + endif ! lb + + !final fireline intensity (kJ/m/sec or kW/m), Eq 22 Scott & Reinhardt 2001 + FI_final = ((heat_per_area + (canopy_fuel_load*canopy_ignite_energy*canopy_frac_burnt))& + *currentPatch%ROS_front)/60.0 + ! update patch FI to adjust according to potential canopy fuel consumed (passive and active) + currentPatch%FI = FI_final + + endif !check if passive crown fire? + endif !fire? + + currentPatch => currentPatch%younger; + + enddo !end patch loop + + end subroutine active_crown_fire !***************************************************************** @@ -916,8 +1369,8 @@ subroutine crown_scorching ( currentSite ) type(ed_site_type), intent(in), target :: currentSite - type(ed_patch_type), pointer :: currentPatch - type(ed_cohort_type), pointer :: currentCohort + type(fates_patch_type), pointer :: currentPatch + type(fates_cohort_type), pointer :: currentCohort real(r8) :: tree_ag_biomass ! total amount of above-ground tree biomass in patch. kgC/m2 real(r8) :: leaf_c ! leaf carbon [kg] @@ -929,16 +1382,18 @@ subroutine crown_scorching ( currentSite ) currentPatch => currentSite%oldest_patch; do while(associated(currentPatch)) + + if(currentPatch%nocomp_pft_label .ne. nocomp_bareground)then tree_ag_biomass = 0.0_r8 if (currentPatch%fire == 1) then currentCohort => currentPatch%tallest; do while(associated(currentCohort)) - if ( int(prt_params%woody(currentCohort%pft)) == itrue) then !trees only + if ( prt_params%woody(currentCohort%pft) == itrue) then !trees only - 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) + leaf_c = currentCohort%prt%GetState(leaf_organ, carbon12_element) + sapw_c = currentCohort%prt%GetState(sapw_organ, carbon12_element) + struct_c = currentCohort%prt%GetState(struct_organ, carbon12_element) tree_ag_biomass = tree_ag_biomass + & currentCohort%n * (leaf_c + & @@ -948,7 +1403,7 @@ subroutine crown_scorching ( currentSite ) enddo !end cohort loop do i_pft=1,numpft - if (tree_ag_biomass > 0.0_r8 .and. int(prt_params%woody(i_pft)) == itrue) then + if (tree_ag_biomass > 0.0_r8 .and. prt_params%woody(i_pft) == itrue) then !Equation 16 in Thonicke et al. 2010 !Van Wagner 1973 EQ8 !2/3 Byram (1959) currentPatch%Scorch_ht(i_pft) = EDPftvarcon_inst%fire_alpha_SH(i_pft) * (currentPatch%FI**0.667_r8) @@ -962,12 +1417,14 @@ subroutine crown_scorching ( currentSite ) end do endif !fire + endif !nocomp_pft_label currentPatch => currentPatch%younger; enddo !end patch loop end subroutine crown_scorching + !***************************************************************** subroutine crown_damage ( currentSite ) !***************************************************************** @@ -975,162 +1432,21 @@ subroutine crown_damage ( currentSite ) !returns the updated currentCohort%fraction_crown_burned for each tree cohort within each patch. !currentCohort%fraction_crown_burned is the proportion of crown affected by fire - use SFParamsMod, only : SF_VAL_CWD_FRAC - type(ed_site_type), intent(in), target :: currentSite - type(ed_patch_type) , pointer :: currentPatch - type(ed_cohort_type), pointer :: currentCohort + type(fates_patch_type) , pointer :: currentPatch + type(fates_cohort_type), pointer :: currentCohort - real(r8), parameter :: low_heat_of_combustion = 12700.0_r8 ! [kJ/kg] - real(r8), parameter :: critical_mass_flow_rate = 0.05_r8 ! [kg/m2/s] value for conifer forests; if available for other vegetation, move to the params file? - real(r8) :: active_crown_FI ! critical fire intensity for active crown fire ignition (kW/m) - real(r8) :: ignite_active_crown ! ratio for ignition of active crown fire,EQ 14b Bessie & Johnson 1995 real(r8) :: crown_depth ! depth of crown (m) - real(r8) :: height_cbb ! clear branch bole height or crown base height (m) - real(r8) :: max_height ! max cohort on patch (m) -! real(r8) :: passive_crown_FI ! fire intensity for ignition from passive canopy fuel (kW/m), EQ 8 -! real(r8) :: ignite_passive_crown ! ratio for ignition from passive canopy fuel,EQ 14 Bessie & Johnson 1995 - real(r8) :: tree_sapw_struct_c ! above-ground tree struct and sap biomass in cohort (kgC) - real(r8) :: leaf_c ! leaf carbon (kgC) - real(r8) :: sapw_c ! sapwood carbon (kgC) - real(r8) :: struct_c ! structure carbon (kgC) - real(r8) :: twig_sapw_struct_c ! above-ground twig sap and struct in cohort (kgC) - real(r8) :: crown_fuel_c ! biomass of 1 hr fuels (leaves,twigs) in cohort (kg C) - real(r8) :: crown_fuel_biomass ! biomass of crown fuel in cohort (kg biomass) - real(r8) :: crown_fuel_per_m ! crown fuel per 1m section in cohort - real(r8) :: canopy_bulk_density ! density of canopy fuel on patch - real(r8) :: height_base_canopy ! lowest height of fuels to carry fire in crown - integer :: ih ! counter - integer :: passive_canopy_fuel_flg ! flag if canopy fuel true for vertical spread - - real, dimension(70):: biom_matrix ! matrix to track biomass from bottom to 70m - real(r8),parameter :: min_density_canopy_fuel = 0.011_r8 !min canopy fuel density (kg/m3) sufficient to - !propogate fire vertically through canopy - !Scott and Reinhardt 2001 RMRS-RP-29 - real(r8),parameter :: crown_ignite_energy = 3060_r8 !crown ignition energy (kJ/kg) Van Wagner 1977 + real(r8) :: height_cbb ! clear branch bole height or crown base height (m) for cohort currentPatch => currentSite%oldest_patch do while(associated(currentPatch)) !zero Patch level variables -! passive_crown_FI = 0.0_r8 -! ignite_passive_crown = 0.0_r8 - biom_matrix = 0.0_r8 - canopy_bulk_density = 0.0_r8 - max_height = 0.0_r8 - height_base_canopy = 0.0_r8 - + if(currentPatch%nocomp_pft_label .ne. nocomp_bareground)then if (currentPatch%fire == 1) then - currentCohort=>currentPatch%tallest - do while(associated(currentCohort)) - - !zero cohort level variables - tree_sapw_struct_c = 0.0_r8 - leaf_c = 0.0_r8 - sapw_c = 0.0_r8 - struct_c = 0.0_r8 - twig_sapw_struct_c = 0.0_r8 - crown_fuel_c = 0.0_r8 - crown_fuel_biomass = 0.0_r8 - crown_fuel_per_m = 0.0_r8 - - ! Calculate crown 1hr fuel biomass (leaf, twig sapwood, twig structural biomass) - if ( int(prt_params%woody(currentCohort%pft)) == itrue) then !trees - - call CrownDepth(currentCohort%hite,currentCohort%pft,crown_depth) - height_cbb = currentCohort%hite - crown_depth - - !find patch max height for stand canopy fuel - if (currentCohort%hite > max_height) then - max_height = currentCohort%hite - endif - - 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) - - tree_sapw_struct_c = currentCohort%n * & - (prt_params%allom_agb_frac(currentCohort%pft)*(sapw_c + struct_c)) - - twig_sapw_struct_c = tree_sapw_struct_c * SF_VAL_CWD_frac(1) !only 1hr fuel - - crown_fuel_c = (currentCohort%n * leaf_c) + twig_sapw_struct_c !crown fuel (kgC) - - crown_fuel_biomass = crown_fuel_c / 0.45_r8 ! crown fuel (kg biomass) - - crown_fuel_per_m = crown_fuel_biomass / crown_depth ! kg biomass per m - - !sort crown fuel into bins from bottom to top of crown - !accumulate across cohorts to find density within canopy 1m sections - do ih = int(height_cbb), int(currentCohort%hite) - biom_matrix(ih) = biom_matrix(ih) + crown_fuel_per_m - end do - - endif !trees only - - currentCohort => currentCohort%shorter; - - enddo !end cohort loop - - biom_matrix(:) = biom_matrix(:) / currentPatch%area !kg biomass/m3 - - !loop from 1m to 70m to find bin with total density = 0.011 kg/m3 - !min canopy fuel density to propogate fire vertically in canopy across patch - do ih=1,70 - if (biom_matrix(ih) > min_density_canopy_fuel) then - height_base_canopy = float(ih) - exit - end if - end do - - !canopy_bulk_denisty (kg/m3) for Patch - canopy_bulk_density = sum(biom_matrix) / (max_height - height_base_canopy) - - ! Note: crown_ignition_energy to be calculated based on PFT foliar moisture content from FATES-Hydro - ! or create foliar_moisture based on BTRAN - ! Use foliar_moisture(currentCohort%pft) and compute weighted PFT average with EQ3 Van Wagner 1977 - ! in place of crown_ignite_energy parameter - - ! EQ 3 Van Wagner 1977 - ! h = crown_ignite_energy (kJ/kg), m = foliar moisture content based on dry fuel (%) - ! crown_ignite_energy = 460 + 26 * m - - ! Crown fuel ignition potential, EQ 8 Bessie and Johnson 1995, EQ 4 Van Wagner 1977 - ! FI = (Czh)**3/2 where z=canopy base height,h=heat of crown ignite energy, FI=fire intensity - ! 0.01 = C from Van Wagner 1977 EQ4 for canopy base height 6m, 100% FMC, and FI 2500kW/m -! passive_crown_FI = (0.01_r8 * height_base_canopy * crown_ignite_energy)**1.5_r8 - -! passive_canopy_fuel_flg = 0 !does patch have canopy fuels for vertical spread? - - ! Initiation of passive crown fire, EQ 14a Bessie and Johnson 1995 - ! Are the canopy fuels in the stand large enough to support vertical spread of fire? -! ignite_passive_crown = currentPatch%FI/passive_crown_FI - -! if (ignite_passive_crown >= 1.0_r8) then -! passive_canopy_fuel_flg = 1 !enough passive canopy fuels for vertical spread -! endif - - !evaluate active crown fire conditions - ! Critical intensity for active crowning (kW/m) - ! EQ 12 Bessie and Johnson 1995 - ! Fuels / 0.45 to get biomass. Also dividing - ! critical_mass_flow_rate by 3.34, an empirical - ! constant in Bessie & Johnson 1995 - active_crown_FI = critical_mass_flow_rate * & - low_heat_of_combustion * currentPatch%sum_fuel / & - (0.45_r8 * 3.34_r8 * canopy_bulk_density) - - ! Initiate active crown fire? - ! EQ 14b Bessie & Johnson 1995 - ignite_active_crown = currentPatch%FI / active_crown_FI - - if (ignite_active_crown >= 1.0_r8 .and. & - EDPftvarcon_inst%active_crown_fire(currentCohort%pft) > 0.0_r8) then - currentPatch%active_crown_fire_flg = 1 ! active crown fire ignited - end if - currentCohort=>currentPatch%tallest do while(associated(currentCohort)) @@ -1139,18 +1455,17 @@ subroutine crown_damage ( currentSite ) ! height_cbb = clear branch bole height at base of crown (m) ! inst%crown = crown_depth_frac (PFT) - call CrownDepth(currentCohort%hite,currentCohort%pft,crown_depth) - height_cbb = currentCohort%hite - crown_depth + call CrownDepth(currentCohort%height,currentCohort%pft,crown_depth) + height_cbb = currentCohort%height - crown_depth ! Equation 17 in Thonicke et al. 2010 ! flames over bottom of canopy, and potentially over top of ! canopy - if (currentCohort%hite > 0.0_r8 .and. & + if (currentCohort%height > 0.0_r8 .and. & currentPatch%Scorch_ht(currentCohort%pft) >= height_cbb) then if (currentPatch%active_crown_fire_flg == 0) then currentCohort%fraction_crown_burned = min(1.0_r8, & - ((currentPatch%Scorch_ht(currentCohort%pft) - & - height_cbb) / crown_depth)) + ((currentPatch%Scorch_ht(currentCohort%pft) - height_cbb) / crown_depth)) else ! active crown fire occurring currentCohort%fraction_crown_burned = 1.0_r8 end if @@ -1166,6 +1481,7 @@ subroutine crown_damage ( currentSite ) enddo !end cohort loop endif !fire? + endif !nocomp_pft_label check currentPatch => currentPatch%younger; @@ -1182,8 +1498,8 @@ subroutine cambial_damage_kill ( currentSite ) type(ed_site_type), intent(in), target :: currentSite - type(ed_patch_type) , pointer :: currentPatch - type(ed_cohort_type), pointer :: currentCohort + type(fates_patch_type) , pointer :: currentPatch + type(fates_cohort_type), pointer :: currentCohort real(r8) :: tau_c !critical time taken to kill cambium (minutes) real(r8) :: bt !bark thickness in cm. @@ -1192,6 +1508,8 @@ subroutine cambial_damage_kill ( currentSite ) do while(associated(currentPatch)) + if(currentPatch%nocomp_pft_label .ne. nocomp_bareground)then + if (currentPatch%fire == 1) then currentCohort => currentPatch%tallest; do while(associated(currentCohort)) @@ -1217,6 +1535,7 @@ subroutine cambial_damage_kill ( currentSite ) enddo !end cohort loop endif !fire? + endif !nocomp_pft_label check currentPatch=>currentPatch%younger; @@ -1236,19 +1555,21 @@ subroutine post_fire_mortality ( currentSite ) type(ed_site_type), intent(in), target :: currentSite - type(ed_patch_type), pointer :: currentPatch - type(ed_cohort_type), pointer :: currentCohort + type(fates_patch_type), pointer :: currentPatch + type(fates_cohort_type), pointer :: currentCohort currentPatch => currentSite%oldest_patch do while(associated(currentPatch)) + if(currentPatch%nocomp_pft_label .ne. nocomp_bareground)then + if (currentPatch%fire == 1) then currentCohort => currentPatch%tallest do while(associated(currentCohort)) currentCohort%fire_mort = 0.0_r8 currentCohort%crownfire_mort = 0.0_r8 - if ( int(prt_params%woody(currentCohort%pft)) == itrue) then + if ( prt_params%woody(currentCohort%pft) == itrue) then ! Equation 22 in Thonicke et al. 2010. currentCohort%crownfire_mort = EDPftvarcon_inst%crown_kill(currentCohort%pft)*currentCohort%fraction_crown_burned**3.0_r8 ! Equation 18 in Thonicke et al. 2010. @@ -1262,6 +1583,7 @@ subroutine post_fire_mortality ( currentSite ) enddo !end cohort loop endif !fire? + endif !nocomp_pft_label check currentPatch => currentPatch%younger diff --git a/fire/SFParamsMod.F90 b/fire/SFParamsMod.F90 index 02c0ce7756..306034a804 100644 --- a/fire/SFParamsMod.F90 +++ b/fire/SFParamsMod.F90 @@ -4,7 +4,7 @@ module SFParamsMod ! use FatesConstantsMod , only: r8 => fates_r8 use FatesConstantsMod , only: fates_check_param_set - use EDtypesMod , only: NFSC + use FatesLitterMod , only: NFSC use FatesLitterMod , only: ncwd use FatesParametersInterface, only : param_string_length use FatesGlobals, only : fates_log @@ -52,8 +52,8 @@ module SFParamsMod character(len=param_string_length),parameter :: SF_name_durat_slope = "fates_fire_durat_slope" character(len=param_string_length),parameter :: SF_name_drying_ratio = "fates_fire_drying_ratio" character(len=param_string_length),parameter :: SF_name_fire_threshold = "fates_fire_threshold" - character(len=param_string_length),parameter :: SF_name_CWD_frac = "fates_CWD_frac" - character(len=param_string_length),parameter :: SF_name_max_decomp = "fates_max_decomp" + character(len=param_string_length),parameter :: SF_name_CWD_frac = "fates_frag_cwd_frac" + character(len=param_string_length),parameter :: SF_name_max_decomp = "fates_frag_maxdecomp" character(len=param_string_length),parameter :: SF_name_SAV = "fates_fire_SAV" character(len=param_string_length),parameter :: SF_name_FBD = "fates_fire_FBD" character(len=param_string_length),parameter :: SF_name_min_moisture = "fates_fire_min_moisture" @@ -260,37 +260,37 @@ subroutine SpitFireReceiveScalars(fates_params) real(r8) :: tmp_real - call fates_params%RetreiveParameter(name=SF_name_fdi_a, & + call fates_params%RetrieveParameter(name=SF_name_fdi_a, & data=SF_val_fdi_a) - call fates_params%RetreiveParameter(name=SF_name_fdi_b, & + call fates_params%RetrieveParameter(name=SF_name_fdi_b, & data=SF_val_fdi_b) - call fates_params%RetreiveParameter(name=SF_name_fdi_alpha, & + call fates_params%RetrieveParameter(name=SF_name_fdi_alpha, & data=SF_val_fdi_alpha) - call fates_params%RetreiveParameter(name=SF_name_miner_total, & + call fates_params%RetrieveParameter(name=SF_name_miner_total, & data=SF_val_miner_total) - call fates_params%RetreiveParameter(name=SF_name_fuel_energy, & + call fates_params%RetrieveParameter(name=SF_name_fuel_energy, & data=SF_val_fuel_energy) - call fates_params%RetreiveParameter(name=SF_name_part_dens, & + call fates_params%RetrieveParameter(name=SF_name_part_dens, & data=SF_val_part_dens) - call fates_params%RetreiveParameter(name=SF_name_miner_damp, & + call fates_params%RetrieveParameter(name=SF_name_miner_damp, & data=SF_val_miner_damp) - call fates_params%RetreiveParameter(name=SF_name_max_durat, & + call fates_params%RetrieveParameter(name=SF_name_max_durat, & data=SF_val_max_durat) - call fates_params%RetreiveParameter(name=SF_name_durat_slope, & + call fates_params%RetrieveParameter(name=SF_name_durat_slope, & data=SF_val_durat_slope) - call fates_params%RetreiveParameter(name=SF_name_drying_ratio, & + call fates_params%RetrieveParameter(name=SF_name_drying_ratio, & data=SF_val_drying_ratio) - call fates_params%RetreiveParameter(name=SF_name_fire_threshold, & + call fates_params%RetrieveParameter(name=SF_name_fire_threshold, & data=SF_val_fire_threshold) @@ -323,7 +323,7 @@ subroutine SpitFireReceiveNCWD(fates_params) class(fates_parameters_type), intent(inout) :: fates_params - call fates_params%RetreiveParameter(name=SF_name_CWD_frac, & + call fates_params%RetrieveParameter(name=SF_name_CWD_frac, & data=SF_val_CWD_frac) @@ -380,31 +380,31 @@ subroutine SpitFireReceiveNFSC(fates_params) class(fates_parameters_type), intent(inout) :: fates_params - call fates_params%RetreiveParameter(name=SF_name_SAV, & + call fates_params%RetrieveParameter(name=SF_name_SAV, & data=SF_val_SAV) - call fates_params%RetreiveParameter(name=SF_name_FBD, & + call fates_params%RetrieveParameter(name=SF_name_FBD, & data=SF_val_FBD) - call fates_params%RetreiveParameter(name=SF_name_min_moisture, & + call fates_params%RetrieveParameter(name=SF_name_min_moisture, & data=SF_val_min_moisture) - call fates_params%RetreiveParameter(name=SF_name_mid_moisture, & + call fates_params%RetrieveParameter(name=SF_name_mid_moisture, & data=SF_val_mid_moisture) - call fates_params%RetreiveParameter(name=SF_name_low_moisture_Coeff, & + call fates_params%RetrieveParameter(name=SF_name_low_moisture_Coeff, & data=SF_val_low_moisture_Coeff) - call fates_params%RetreiveParameter(name=SF_name_low_moisture_Slope, & + call fates_params%RetrieveParameter(name=SF_name_low_moisture_Slope, & data=SF_val_low_moisture_Slope) - call fates_params%RetreiveParameter(name=SF_name_mid_moisture_Coeff, & + call fates_params%RetrieveParameter(name=SF_name_mid_moisture_Coeff, & data=SF_val_mid_moisture_Coeff) - call fates_params%RetreiveParameter(name=SF_name_mid_moisture_Slope, & + call fates_params%RetrieveParameter(name=SF_name_mid_moisture_Slope, & data=SF_val_mid_moisture_Slope) - call fates_params%RetreiveParameter(name=SF_name_max_decomp, & + call fates_params%RetrieveParameter(name=SF_name_max_decomp, & data=SF_val_max_decomp) end subroutine SpitFireReceiveNFSC diff --git a/functional_unit_testing/parteh/f90src/FatesCohortWrapMod.F90 b/functional_unit_testing/parteh/f90src/FatesCohortWrapMod.F90 index 75575d3df9..4d5efcf241 100644 --- a/functional_unit_testing/parteh/f90src/FatesCohortWrapMod.F90 +++ b/functional_unit_testing/parteh/f90src/FatesCohortWrapMod.F90 @@ -69,7 +69,7 @@ module FatesCohortWrapMod use FatesConstantsMod , only : nearzero - use EDTypesMod , only : nclmax + use EDParamsMod , only : nclmax use FatesGlobals , only : endrun => fates_endrun use FatesGlobals , only : fates_log @@ -78,7 +78,7 @@ module FatesCohortWrapMod implicit none private ! Modules are private by default - type, public :: ed_cohort_type + type, public :: fates_cohort_type integer :: pft ! pft number real(r8) :: dbh ! dbh: cm @@ -106,11 +106,11 @@ module FatesCohortWrapMod ! Multi-species, multi-pool Reactive Transport class(prt_vartypes), pointer :: prt - end type ed_cohort_type + end type fates_cohort_type ! Global Instances - type(ed_cohort_type), pointer, public :: cohort_array(:) + type(fates_cohort_type), pointer, public :: cohort_array(:) integer, public :: numcohort character(len=*), parameter, private :: sourcefile = __FILE__ @@ -132,7 +132,7 @@ subroutine CohortInitAlloc(numcohorts) ! Locals integer(i4) :: ico - type(ed_cohort_type), pointer :: ccohort + type(fates_cohort_type), pointer :: ccohort allocate(cohort_array(numcohorts)) @@ -189,7 +189,7 @@ subroutine CohortPySet(ipft,hgt_min,canopy_trim) ! Locals - type(ed_cohort_type), pointer :: ccohort ! Current cohort + type(fates_cohort_type), pointer :: ccohort ! Current cohort real(r8) :: leaf_c real(r8) :: fnrt_c real(r8) :: sapw_c @@ -230,7 +230,7 @@ subroutine CohortPySet(ipft,hgt_min,canopy_trim) ! Use allometry to compute initial values ! Leaf biomass (carbon) - call bleaf(ccohort%dbh, ipft, canopy_trim, leaf_c) + call bleaf(ccohort%dbh, ipft,canopy_trim, leaf_c) ! Fine-root biomass (carbon) call bfineroot(ccohort%dbh, ipft, canopy_trim, fnrt_c) @@ -376,7 +376,7 @@ subroutine WrapDailyPRT(ipft,daily_carbon_gain,canopy_trim,flush_c,drop_frac_c,l real(r8), intent(in), optional :: daily_phosphorus_gain real(r8), intent(in), optional :: daily_r_maint_demand - type(ed_cohort_type), pointer :: ccohort + type(fates_cohort_type), pointer :: ccohort logical, parameter :: is_drought = .false. ccohort => cohort_array(ipft) @@ -431,7 +431,7 @@ end subroutine WrapDailyPRT ! ===================================================================================== - subroutine WrapQueryVars(ipft,leaf_area,crown_area,agb,store_c,target_leaf_c) + subroutine WrapQueryVars(ipft,crowndamage, leaf_area,crown_area,agb,store_c,target_leaf_c) implicit none ! Arguments @@ -443,13 +443,14 @@ subroutine WrapQueryVars(ipft,leaf_area,crown_area,agb,store_c,target_leaf_c) real(r8),intent(out) :: target_leaf_c real(r8) :: leaf_c - type(ed_cohort_type), pointer :: ccohort - + type(fates_cohort_type), pointer :: ccohort + real(r8),parameter :: nplant = 1.0_r8 real(r8),parameter :: site_spread = 1.0_r8 real(r8), dimension(nclmax) :: canopy_lai integer, parameter :: cl1 = 1 + ccohort => cohort_array(ipft) @@ -466,18 +467,19 @@ subroutine WrapQueryVars(ipft,leaf_area,crown_area,agb,store_c,target_leaf_c) leaf_c = ccohort%prt%GetState(leaf_organ, carbon12_element ) store_c = ccohort%prt%GetState(store_organ, carbon12_element ) - call carea_allom(ccohort%dbh,nplant,site_spread,ipft,crown_area) + call carea_allom(ccohort%dbh,nplant,site_spread,ipft,ccohort%crowndamage,crown_area) leaf_area = crown_area*tree_lai(leaf_c, ipft, crown_area, nplant, cl1, canopy_lai,ccohort%vcmax25top) - call bagw_allom(ccohort%dbh,ipft,agb) + call bagw_allom(ccohort%dbh,ipft, agb) call bleaf(ccohort%dbh,ipft, ccohort%canopy_trim, target_leaf_c) return end subroutine WrapQueryVars - + + ! ========================================================================================== subroutine WrapQueryDiagnostics(ipft, dbh, & leaf_c, fnrt_c, sapw_c, store_c, struct_c, repro_c, & @@ -538,7 +540,7 @@ subroutine WrapQueryDiagnostics(ipft, dbh, & real(r8),intent(out) :: growth_resp real(r8),intent(out) :: crown_area - type(ed_cohort_type), pointer :: ccohort + type(fates_cohort_type), pointer :: ccohort real(r8),parameter :: nplant = 1.0_r8 real(r8),parameter :: site_spread = 1.0_r8 diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 4506d2c354..dfd5eaba2a 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -12,4 +12,3 @@ list(APPEND clm_sources ) sourcelist_to_parent(clm_sources) - diff --git a/main/ChecksBalancesMod.F90 b/main/ChecksBalancesMod.F90 index 9a17fbfc33..df671a52ac 100644 --- a/main/ChecksBalancesMod.F90 +++ b/main/ChecksBalancesMod.F90 @@ -3,8 +3,8 @@ module ChecksBalancesMod use shr_kind_mod, only : r8 => shr_kind_r8 use shr_const_mod, only : SHR_CONST_CDAY use EDtypesMod, only : ed_site_type - use EDTypesMod, only : ed_patch_type - use EDTypesMod, only : ed_cohort_type + use FatesPatchMod, only : fates_patch_type + use FatesCohortMod, only : fates_cohort_type use EDTypesMod, only : AREA use EDTypesMod, only : site_massbal_type use PRTGenericMod, only : num_elements @@ -15,7 +15,6 @@ module ChecksBalancesMod use FatesLitterMod, only : litter_type use FatesLitterMod, only : ncwd use FatesLitterMod, only : ndcmpy - use PRTGenericMod, only : all_carbon_elements use PRTGenericMod, only : carbon12_element use PRTGenericMod, only : leaf_organ use PRTGenericMod, only : fnrt_organ @@ -49,8 +48,8 @@ subroutine SiteMassStock(currentSite,el,total_stock,biomass_stock,litter_stock,s real(r8),intent(out) :: litter_stock ! kg real(r8),intent(out) :: biomass_stock ! kg real(r8),intent(out) :: seed_stock ! kg - type(ed_patch_type), pointer :: currentPatch - type(ed_cohort_type), pointer :: currentCohort + type(fates_patch_type), pointer :: currentPatch + type(fates_cohort_type), pointer :: currentCohort real(r8) :: patch_biomass ! kg real(r8) :: patch_seed ! kg real(r8) :: patch_litter ! kg @@ -82,14 +81,14 @@ subroutine PatchMassStock(currentPatch,el,live_stock,seed_stock,litter_stock) ! --------------------------------------------------------------------------------- ! Sum up the mass of the different stocks on a patch for each element ! --------------------------------------------------------------------------------- - type(ed_patch_type),intent(inout),target :: currentPatch + type(fates_patch_type),intent(inout),target :: currentPatch integer,intent(in) :: el real(r8),intent(out) :: live_stock real(r8),intent(out) :: seed_stock real(r8),intent(out) :: litter_stock type(litter_type), pointer :: litt ! litter object - type(ed_cohort_type), pointer :: currentCohort + type(fates_cohort_type), pointer :: currentCohort integer :: element_id litt => currentPatch%litter(el) @@ -106,6 +105,7 @@ subroutine PatchMassStock(currentPatch,el,live_stock,seed_stock,litter_stock) seed_stock = currentPatch%area * & (sum(litt%seed) + sum(litt%seed_germ)) + ! Total mass on living plants live_stock = 0._r8 currentCohort => currentPatch%tallest @@ -121,16 +121,6 @@ subroutine PatchMassStock(currentPatch,el,live_stock,seed_stock,litter_stock) currentCohort => currentCohort%shorter enddo !end cohort loop - - if(element_id.eq.carbon12_element) then - currentCohort => currentPatch%tallest - do while(associated(currentCohort)) - live_stock = live_stock - & - (currentCohort%resp_m_def*currentCohort%n) - currentCohort => currentCohort%shorter - enddo !end cohort loop - end if - return end subroutine PatchMassStock @@ -157,7 +147,7 @@ subroutine CheckLitterPools(currentSite,bc_in) type(bc_in_type), intent(in) :: bc_in ! Local variables - type(ed_patch_type), pointer :: currentPatch + type(fates_patch_type), pointer :: currentPatch type(litter_type), pointer :: litt ! Litter object integer :: el ! Litter element loop index integer :: element_id ! parteh consistent litter index diff --git a/main/EDInitMod.F90 b/main/EDInitMod.F90 index 06bcd1858a..41a846ac3e 100644 --- a/main/EDInitMod.F90 +++ b/main/EDInitMod.F90 @@ -8,29 +8,36 @@ 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 FatesConstantsMod , only : nearzero, area_error_4, area_error_3 use FatesGlobals , only : endrun => fates_endrun - use EDTypesMod , only : nclmax + use EDParamsMod , only : nclmax + use EDParamsMod , only : regeneration_model use FatesGlobals , only : fates_log - use FatesInterfaceTypesMod , only : hlm_is_restart + use FatesInterfaceTypesMod , only : hlm_is_restart + use FatesInterfaceTypesMod , only : hlm_current_tod + use FatesInterfaceTypesMod , only : hlm_numSWb use EDPftvarcon , only : EDPftvarcon_inst use PRTParametersMod , only : prt_params use EDCohortDynamicsMod , only : create_cohort, fuse_cohorts, sort_cohorts use EDCohortDynamicsMod , only : InitPRTObject - use EDPatchDynamicsMod , only : create_patch use EDPatchDynamicsMod , only : set_patchno - use EDPhysiologyMod , only : assign_cohort_sp_properties + use EDPhysiologyMod , only : calculate_sp_properties use ChecksBalancesMod , only : SiteMassStock - use EDTypesMod , only : ed_site_type, ed_patch_type, ed_cohort_type + use FatesInterfaceTypesMod , only : hlm_day_of_year + use EDTypesMod , only : ed_site_type + use FatesPatchMod , only : fates_patch_type + use FatesCohortMod , only : fates_cohort_type use EDTypesMod , only : numWaterMem use EDTypesMod , only : num_vegtemp_mem - use EDTypesMod , only : maxpft use EDTypesMod , only : AREA use EDTypesMod , only : init_spread_near_bare_ground use EDTypesMod , only : init_spread_inventory - use EDTypesMod , only : leaves_on - use EDTypesMod , only : leaves_off + use FatesConstantsMod , only : leaves_on + use FatesConstantsMod , only : leaves_off + use FatesConstantsMod , only : ihard_stress_decid + use FatesConstantsMod , only : isemi_stress_decid use PRTGenericMod , only : num_elements use PRTGenericMod , only : element_list use EDTypesMod , only : phen_cstat_nevercold @@ -43,15 +50,18 @@ module EDInitMod use FatesInterfaceTypesMod , only : hlm_use_planthydro use FatesInterfaceTypesMod , only : hlm_use_inventory_init use FatesInterfaceTypesMod , only : hlm_use_fixed_biogeog + use FatesInterfaceTypesMod , only : hlm_use_tree_damage use FatesInterfaceTypesMod , only : hlm_use_sp use FatesInterfaceTypesMod , only : numpft use FatesInterfaceTypesMod , only : nleafage use FatesInterfaceTypesMod , only : nlevsclass use FatesInterfaceTypesMod , only : nlevcoage + use FatesInterfaceTypesMod , only : nlevdamage use FatesInterfaceTypesMod , only : hlm_use_nocomp use FatesInterfaceTypesMod , only : nlevage use FatesAllometryMod , only : h2d_allom + use FatesAllometryMod , only : h_allom use FatesAllometryMod , only : bagw_allom use FatesAllometryMod , only : bbgw_allom use FatesAllometryMod , only : bleaf @@ -59,6 +69,7 @@ module EDInitMod use FatesAllometryMod , only : bsap_allom use FatesAllometryMod , only : bdead_allom use FatesAllometryMod , only : bstore_allom + use FatesAllometryMod , only : carea_allom use PRTGenericMod , only : StorageNutrientTarget use FatesInterfaceTypesMod, only : hlm_parteh_mode use PRTGenericMod, only : prt_carbon_allom_hyp @@ -75,7 +86,8 @@ module EDInitMod use PRTGenericMod, only : phosphorus_element use PRTGenericMod, only : SetState use FatesSizeAgeTypeIndicesMod,only : get_age_class_index - + use DamageMainMod, only : undamaged_class + ! CIME GLOBALS use shr_log_mod , only : errMsg => shr_log_errMsg @@ -84,6 +96,8 @@ module EDInitMod logical :: debug = .false. + integer :: istat ! return status code + character(len=255) :: smsg ! Message string for deallocation errors character(len=*), parameter, private :: sourcefile = & __FILE__ @@ -107,8 +121,8 @@ subroutine init_site_vars( site_in, bc_in, bc_out ) ! ! !ARGUMENTS type(ed_site_type), intent(inout) :: site_in - type(bc_in_type),intent(in),target :: bc_in - type(bc_out_type),intent(in),target :: bc_out + type(bc_in_type),intent(in) :: bc_in + type(bc_out_type),intent(in) :: bc_out ! ! !LOCAL VARIABLES: !---------------------------------------------------------------------- @@ -128,13 +142,47 @@ subroutine init_site_vars( site_in, bc_in, bc_out ) allocate(site_in%mass_balance(1:num_elements)) allocate(site_in%flux_diags(1:num_elements)) + if (hlm_use_tree_damage .eq. itrue) then + allocate(site_in%term_nindivs_canopy_damage(1:nlevdamage, 1:nlevsclass, 1:numpft)) + allocate(site_in%term_nindivs_ustory_damage(1:nlevdamage, 1:nlevsclass, 1:numpft)) + allocate(site_in%imort_rate_damage(1:nlevdamage, 1:nlevsclass, 1:numpft)) + allocate(site_in%imort_cflux_damage(1:nlevdamage, 1:nlevsclass)) + allocate(site_in%term_cflux_canopy_damage(1:nlevdamage, 1:nlevsclass)) + allocate(site_in%term_cflux_ustory_damage(1:nlevdamage, 1:nlevsclass)) + allocate(site_in%fmort_rate_canopy_damage(1:nlevdamage, 1:nlevsclass, 1:numpft)) + allocate(site_in%fmort_rate_ustory_damage(1:nlevdamage, 1:nlevsclass, 1:numpft)) + allocate(site_in%fmort_cflux_canopy_damage(1:nlevdamage, 1:nlevsclass)) + allocate(site_in%fmort_cflux_ustory_damage(1:nlevdamage, 1:nlevsclass)) + else + allocate(site_in%term_nindivs_canopy_damage(1,1,1)) + allocate(site_in%term_nindivs_ustory_damage(1,1,1)) + allocate(site_in%imort_rate_damage(1,1,1)) + allocate(site_in%imort_cflux_damage(1,1)) + allocate(site_in%term_cflux_canopy_damage(1,1)) + allocate(site_in%term_cflux_ustory_damage(1,1)) + allocate(site_in%fmort_rate_canopy_damage(1,1,1)) + allocate(site_in%fmort_rate_ustory_damage(1,1,1)) + allocate(site_in%fmort_cflux_canopy_damage(1,1)) + allocate(site_in%fmort_cflux_ustory_damage(1,1)) + end if + + allocate(site_in%term_carbonflux_canopy(1:numpft)) + allocate(site_in%term_carbonflux_ustory(1:numpft)) + allocate(site_in%imort_carbonflux(1:numpft)) + allocate(site_in%fmort_carbonflux_canopy(1:numpft)) + allocate(site_in%fmort_carbonflux_ustory(1:numpft)) + + allocate(site_in%term_abg_flux(1:nlevsclass,1:numpft)) + allocate(site_in%imort_abg_flux(1:nlevsclass,1:numpft)) + allocate(site_in%fmort_abg_flux(1:nlevsclass,1:numpft)) + site_in%nlevsoil = bc_in%nlevsoil allocate(site_in%rootfrac_scr(site_in%nlevsoil)) allocate(site_in%zi_soil(0:site_in%nlevsoil)) allocate(site_in%dz_soil(site_in%nlevsoil)) allocate(site_in%z_soil(site_in%nlevsoil)) - if (hlm_use_nocomp .eq. itrue) then + if (hlm_use_nocomp .eq. itrue .and. hlm_use_fixed_biogeog .eq. itrue) then allocate(site_in%area_pft(0:numpft)) else ! SP and nocomp require a bare-ground patch. allocate(site_in%area_pft(1:numpft)) @@ -143,7 +191,11 @@ subroutine init_site_vars( site_in, bc_in, bc_out ) allocate(site_in%use_this_pft(1:numpft)) allocate(site_in%area_by_age(1:nlevage)) - + ! for CNP dynamics, track the mean l2fr of recruits + ! for different pfts and canopy positions + allocate(site_in%rec_l2fr(1:numpft,nclmax)) + + ! SP mode allocate(site_in%sp_tlai(1:numpft)) allocate(site_in%sp_tsai(1:numpft)) @@ -152,19 +204,18 @@ subroutine init_site_vars( site_in, bc_in, bc_out ) do el=1,num_elements allocate(site_in%flux_diags(el)%leaf_litter_input(1:numpft)) allocate(site_in%flux_diags(el)%root_litter_input(1:numpft)) - allocate(site_in%flux_diags(el)%nutrient_efflux_scpf(nlevsclass*numpft)) - allocate(site_in%flux_diags(el)%nutrient_uptake_scpf(nlevsclass*numpft)) - allocate(site_in%flux_diags(el)%nutrient_need_scpf(nlevsclass*numpft)) end do ! Initialize the static soil ! arrays from the boundary (initial) condition - site_in%zi_soil(:) = bc_in%zi_sisl(:) site_in%dz_soil(:) = bc_in%dz_sisl(:) site_in%z_soil(:) = bc_in%z_sisl(:) - ! + ! Seed dispersal + allocate(site_in%seed_in(1:numpft)) + allocate(site_in%seed_out(1:numpft)) + end subroutine init_site_vars ! ============================================================================ @@ -189,21 +240,29 @@ subroutine zero_site( site_in ) ! PHENOLOGY site_in%cstatus = fates_unset_int ! are leaves in this pixel on or off? - site_in%dstatus = fates_unset_int + site_in%dstatus(:) = fates_unset_int site_in%grow_deg_days = nan ! growing degree days site_in%snow_depth = nan site_in%nchilldays = fates_unset_int site_in%ncolddays = fates_unset_int - site_in%cleafondate = fates_unset_int ! doy of leaf on - site_in%cleafoffdate = fates_unset_int ! doy of leaf off - site_in%dleafondate = fates_unset_int ! doy of leaf on drought - site_in%dleafoffdate = fates_unset_int ! doy of leaf on drought - site_in%water_memory(:) = nan + site_in%cleafondate = fates_unset_int ! doy of leaf on (cold) + site_in%cleafoffdate = fates_unset_int ! doy of leaf off (cold) + site_in%dleafondate(:) = fates_unset_int ! doy of leaf on (drought) + site_in%dleafoffdate(:) = fates_unset_int ! doy of leaf off (drought) + site_in%cndaysleafon = fates_unset_int ! days since leaf on (cold) + site_in%cndaysleafoff = fates_unset_int ! days since leaf off (cold) + site_in%dndaysleafon(:) = fates_unset_int ! days since leaf on (drought) + site_in%dndaysleafoff(:) = fates_unset_int ! days since leaf off (drought) + site_in%elong_factor(:) = nan ! Elongation factor (0 - full abscission; 1 - fully flushed) + + site_in%liqvol_memory(:,:) = nan + site_in%smp_memory(:,:) = nan site_in%vegtemp_memory(:) = nan ! record of last 10 days temperature for senescence model. + site_in%phen_model_date = fates_unset_int + ! Disturbance rates tracking site_in%primary_land_patchfusion_error = 0.0_r8 - site_in%harvest_carbon_flux = 0.0_r8 site_in%potential_disturbance_rates(:) = 0.0_r8 site_in%disturbance_rates_secondary_to_secondary(:) = 0.0_r8 site_in%disturbance_rates_primary_to_secondary(:) = 0.0_r8 @@ -222,21 +281,34 @@ subroutine zero_site( site_in ) call site_in%flux_diags(el)%ZeroFluxDiags() end do + ! This will be initialized in FatesSoilBGCFluxMod:PrepCH4BCs() + ! It checks to see if the value is below -9000. If it is, + ! it will assume the first value of the smoother is set + site_in%ema_npp = -9999.9_r8 ! termination and recruitment info site_in%term_nindivs_canopy(:,:) = 0._r8 site_in%term_nindivs_ustory(:,:) = 0._r8 - site_in%term_carbonflux_canopy = 0._r8 - site_in%term_carbonflux_ustory = 0._r8 + site_in%term_crownarea_canopy = 0._r8 + site_in%term_crownarea_ustory = 0._r8 + site_in%imort_crownarea = 0._r8 + site_in%fmort_crownarea_canopy = 0._r8 + site_in%fmort_crownarea_ustory = 0._r8 + site_in%term_carbonflux_canopy(:) = 0._r8 + site_in%term_carbonflux_ustory(:) = 0._r8 site_in%recruitment_rate(:) = 0._r8 site_in%imort_rate(:,:) = 0._r8 - site_in%imort_carbonflux = 0._r8 + site_in%imort_carbonflux(:) = 0._r8 site_in%fmort_rate_canopy(:,:) = 0._r8 site_in%fmort_rate_ustory(:,:) = 0._r8 - site_in%fmort_carbonflux_canopy = 0._r8 - site_in%fmort_carbonflux_ustory = 0._r8 + site_in%fmort_carbonflux_canopy(:) = 0._r8 + site_in%fmort_carbonflux_ustory(:) = 0._r8 site_in%fmort_rate_cambial(:,:) = 0._r8 site_in%fmort_rate_crown(:,:) = 0._r8 + site_in%term_abg_flux(:,:) = 0._r8 + site_in%imort_abg_flux(:,:) = 0._r8 + site_in%fmort_abg_flux(:,:) = 0._r8 + ! fusoin-induced growth flux of individuals site_in%growthflux_fusion(:,:) = 0._r8 @@ -247,16 +319,36 @@ subroutine zero_site( site_in ) site_in%promotion_rate(:) = 0._r8 site_in%promotion_carbonflux = 0._r8 + ! damage transition info + site_in%imort_rate_damage(:,:,:) = 0._r8 + site_in%term_nindivs_canopy_damage(:,:,:) = 0._r8 + site_in%term_nindivs_ustory_damage(:,:,:) = 0._r8 + site_in%imort_cflux_damage(:,:) = 0._r8 + site_in%term_cflux_canopy_damage(:,:) = 0._r8 + site_in%term_cflux_ustory_damage(:,:) = 0._r8 + site_in%crownarea_canopy_damage = 0._r8 + site_in%crownarea_ustory_damage = 0._r8 + site_in%fmort_rate_canopy_damage(:,:,:) = 0._r8 + site_in%fmort_rate_ustory_damage(:,:,:) = 0._r8 + site_in%fmort_cflux_canopy_damage(:,:) = 0._r8 + site_in%fmort_cflux_ustory_damage(:,:) = 0._r8 + ! Resources management (logging/harvesting, etc) + site_in%resources_management%harvest_debt = 0.0_r8 + site_in%resources_management%harvest_debt_sec = 0.0_r8 site_in%resources_management%trunk_product_site = 0.0_r8 ! canopy spread site_in%spread = 0._r8 + ! Seed dispersal + site_in%seed_in(:) = 0.0_r8 + site_in%seed_out(:) = 0.0_r8 + site_in%area_pft(:) = 0._r8 site_in%use_this_pft(:) = fates_unset_int site_in%area_by_age(:) = 0._r8 - + end subroutine zero_site ! ============================================================================ @@ -268,9 +360,9 @@ subroutine set_site_properties( nsites, sites,bc_in ) ! ! !ARGUMENTS - integer, intent(in) :: nsites - type(ed_site_type) , intent(inout), target :: sites(nsites) - type(bc_in_type), intent(in) :: bc_in(nsites) + integer, intent(in) :: nsites + type(ed_site_type) , intent(inout) :: sites(nsites) + type(bc_in_type), intent(in) :: bc_in(nsites) ! ! !LOCAL VARIABLES: integer :: s @@ -278,11 +370,17 @@ subroutine set_site_properties( nsites, sites,bc_in ) real(r8) :: GDD integer :: dstat ! drought status phenology flag real(r8) :: acc_NI - real(r8) :: watermem + real(r8) :: liqvolmem + real(r8) :: smpmem + real(r8) :: elong_factor ! Elongation factor (0 - fully off; 1 - fully on) integer :: cleafon ! DOY for cold-decid leaf-on, initial guess integer :: cleafoff ! DOY for cold-decid leaf-off, initial guess integer :: dleafoff ! DOY for drought-decid leaf-off, initial guess integer :: dleafon ! DOY for drought-decid leaf-on, initial guess + integer :: cndleafon ! days since leaf on (cold), initial guess + integer :: cndleafoff ! days since leaf off (cold), initial guess + integer :: dndleafon ! days since leaf on (drought), initial guess + integer :: dndleafoff ! days since leaf off (drought), initial guess integer :: ft ! PFT loop real(r8) :: sumarea ! area of PFTs in nocomp mode. integer :: hlm_pft ! used in fixed biogeog mode @@ -300,35 +398,56 @@ subroutine set_site_properties( nsites, sites,bc_in ) GDD = 30.0_r8 cleafon = 100 cleafoff = 300 + cndleafon = 0 + cndleafoff = 0 cstat = phen_cstat_notcold ! Leaves are on acc_NI = 0.0_r8 dstat = phen_dstat_moiston ! Leaves are on dleafoff = 300 dleafon = 100 - watermem = 0.5_r8 + dndleafon = 0 + dndleafoff = 0 + liqvolmem = 0.5_r8 + smpmem = 0._r8 + elong_factor = 1._r8 do s = 1,nsites sites(s)%nchilldays = 0 sites(s)%ncolddays = 0 ! recalculated in phenology - ! immediately, so yes this - ! is memory-less, but needed - ! for first value in history file - - sites(s)%cleafondate = cleafon - sites(s)%cleafoffdate = cleafoff - sites(s)%dleafoffdate = dleafoff - sites(s)%dleafondate = dleafon - sites(s)%grow_deg_days = GDD - - sites(s)%water_memory(1:numWaterMem) = watermem + ! immediately, so yes this + ! is memory-less, but needed + ! for first value in history file + sites(s)%phen_model_date = 0 + sites(s)%cleafondate = cleafon - hlm_day_of_year + sites(s)%cleafoffdate = cleafoff - hlm_day_of_year + sites(s)%cndaysleafon = cndleafon + sites(s)%cndaysleafoff = cndleafoff + sites(s)%dleafoffdate (1:numpft) = dleafoff - hlm_day_of_year + sites(s)%dleafondate (1:numpft) = dleafon - hlm_day_of_year + sites(s)%dndaysleafon (1:numpft) = dndleafon + sites(s)%dndaysleafoff(1:numpft) = dndleafoff + sites(s)%grow_deg_days = GDD + + sites(s)%liqvol_memory(1:numWaterMem,1:numpft) = liqvolmem + sites(s)%smp_memory(1:numWaterMem,1:numpft) = smpmem sites(s)%vegtemp_memory(1:num_vegtemp_mem) = 0._r8 sites(s)%cstatus = cstat - sites(s)%dstatus = dstat + sites(s)%dstatus(1:numpft) = dstat + sites(s)%elong_factor(1:numpft) = elong_factor sites(s)%acc_NI = acc_NI sites(s)%NF = 0.0_r8 sites(s)%NF_successful = 0.0_r8 + sites(s)%area_pft(:) = 0.0_r8 + + do ft = 1,numpft + sites(s)%rec_l2fr(ft,:) = prt_params%allom_l2fr(ft) + end do + + ! Its difficult to come up with a resonable starting smoothing value, so + ! we initialize on a cold-start to -1 + sites(s)%ema_npp = -9999._r8 if(hlm_use_fixed_biogeog.eq.itrue)then ! MAPPING OF FATES PFTs on to HLM_PFTs @@ -336,7 +455,6 @@ subroutine set_site_properties( nsites, sites,bc_in ) ! where pft_areafrac is the area of land in each HLM PFT and (from surface dataset) ! hlm_pft_map is the area of that land in each FATES PFT (from param file) - sites(s)%area_pft(1:numpft) = 0._r8 do hlm_pft = 1,size( EDPftvarcon_inst%hlm_pft_map,2) do fates_pft = 1,numpft ! loop round all fates pfts for all hlm pfts sites(s)%area_pft(fates_pft) = sites(s)%area_pft(fates_pft) + & @@ -346,7 +464,7 @@ subroutine set_site_properties( nsites, sites,bc_in ) do ft = 1,numpft if(sites(s)%area_pft(ft).lt.0.01_r8.and.sites(s)%area_pft(ft).gt.0.0_r8)then - write(fates_log(),*) 'removing small pft patches',s,ft,sites(s)%area_pft(ft) + if(debug) write(fates_log(),*) 'removing small pft patches',s,ft,sites(s)%area_pft(ft) sites(s)%area_pft(ft)=0.0_r8 ! remove tiny patches to prevent numerical errors in terminate patches endif @@ -378,25 +496,25 @@ subroutine set_site_properties( nsites, sites,bc_in ) else ! for sp and nocomp mode, assert a bare ground patch if needed sumarea = sum(sites(s)%area_pft(1:numpft)) - ! In all the other FATES modes, bareground is the area in which plants - ! do not grow of their own accord. In SP mode we assert that the canopy is full for - ! each PFT patch. Thus, we also need to assert a bare ground area in - ! order to not have all of the ground filled by leaves. + ! In all the other FATES modes, bareground is the area in which plants + ! do not grow of their own accord. In SP mode we assert that the canopy is full for + ! each PFT patch. Thus, we also need to assert a bare ground area in + ! order to not have all of the ground filled by leaves. - ! Further to that, one could calculate bare ground as the remaining area when - ! all fhe canopies are accounted for, but this means we don't pass balance checks - ! on canopy are inside FATES, and so in SP mode, we define the bare groud - ! patch as having a PFT identifier as zero. + ! Further to that, one could calculate bare ground as the remaining area when + ! all fhe canopies are accounted for, but this means we don't pass balance checks + ! on canopy are inside FATES, and so in SP mode, we define the bare groud + ! patch as having a PFT identifier as zero. if(sumarea.lt.area)then !make some bare ground sites(s)%area_pft(0) = area - sumarea - else - sites(s)%area_pft(0) = 0.0_r8 end if end if !sp mode end if !fixed biogeog do ft = 1,numpft + ! Setting this to true ensures that all pfts + ! are used for nocomp with no biogeog sites(s)%use_this_pft(ft) = itrue if(hlm_use_fixed_biogeog.eq.itrue)then if(sites(s)%area_pft(ft).gt.0.0_r8)then @@ -421,9 +539,6 @@ subroutine init_patches( nsites, sites, bc_in) ! This may be call a near bare ground initialization, or it may ! load patches from an inventory. - ! - - use FatesPlantHydraulicsMod, only : updateSizeDepRhizHydProps use FatesInventoryInitMod, only : initialize_sites_by_inventory @@ -438,7 +553,8 @@ subroutine init_patches( nsites, sites, bc_in) integer :: el real(r8) :: age !notional age of this patch integer :: ageclass - + real(r8) :: area_diff + ! dummy locals real(r8) :: biomass_stock real(r8) :: litter_stock @@ -448,13 +564,16 @@ subroutine init_patches( nsites, sites, bc_in) integer :: num_new_patches integer :: nocomp_pft real(r8) :: newparea - real(r8) :: tota !check on area + real(r8) :: total !check on area + real(r8) :: litt_init + real(r8) :: old_carea integer :: is_first_patch type(ed_site_type), pointer :: sitep - type(ed_patch_type), pointer :: newppft(:) - type(ed_patch_type), pointer :: newp - type(ed_patch_type), pointer :: currentPatch + type(fates_patch_type), pointer :: newppft(:) + type(fates_patch_type), pointer :: newp + type(fates_cohort_type), pointer :: cohort + type(fates_patch_type), pointer :: currentPatch ! List out some nominal patch values that are used for Near Bear Ground initializations ! as well as initializing inventory @@ -537,8 +656,9 @@ subroutine init_patches( nsites, sites, bc_in) if(newparea.gt.0._r8)then ! Stop patches being initilialized when PFT not present in nocomop mode allocate(newp) - - call create_patch(sites(s), newp, age, newparea, primaryforest, nocomp_pft) + call newp%Create(age, newparea, primaryforest, nocomp_pft, & + hlm_numSWb, numpft, sites(s)%nlevsoil, hlm_current_tod, & + regeneration_model) if(is_first_patch.eq.itrue)then !is this the first patch? ! set poointers for first patch (or only patch, if nocomp is false) @@ -561,13 +681,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) @@ -582,29 +707,47 @@ subroutine init_patches( nsites, sites, bc_in) end do !no new patches !check if the total area adds to the same as site area - tota = 0.0_r8 + total = 0.0_r8 newp => sites(s)%oldest_patch do while (associated(newp)) - tota=tota+newp%area - newp=>newp%younger + total = total + newp%area + newp => newp%younger end do - - if(abs(tota-area).gt.nearzero*area)then - if(abs(tota-area).lt.1.0e-10_r8)then ! this is a precision error - if(sites(s)%oldest_patch%area.gt.(tota-area+nearzero))then + + area_diff = total - area + if (abs(area_diff) > nearzero) then + if (abs(area_diff) < area_error_4) then ! this is a precision error + if (sites(s)%oldest_patch%area > area_diff + nearzero) then ! remove or add extra area ! if the oldest patch has enough area, use that - sites(s)%oldest_patch%area = sites(s)%oldest_patch%area - (tota-area) - write(*,*) 'fixing patch precision - oldest',s, tota-area + sites(s)%oldest_patch%area = sites(s)%oldest_patch%area - area_diff + if (debug) write(fates_log(),*) 'fixing patch precision - oldest', s, area_diff else ! or otherwise take the area from the youngest patch. - sites(s)%youngest_patch%area = sites(s)%oldest_patch%area - (tota-area) - write(*,*) 'fixing patch precision -youngest ',s, tota-area - endif + sites(s)%youngest_patch%area = sites(s)%youngest_patch%area - area_diff + if (debug) write(fates_log(),*) 'fixing patch precision -youngest ', s, area_diff + end if else !this is a big error not just a precision error. - write(*,*) 'issue with patch area in EDinit',tota-area,tota + write(fates_log(),*) 'issue with patch area in EDinit', area_diff, total call endrun(msg=errMsg(sourcefile, __LINE__)) - endif ! big error + end if ! big error end if ! too much patch area + + ! we might have messed up patch area now - need to correct if SP mode + if (hlm_use_sp .eq. itrue) then + newp => sites(s)%oldest_patch + do while (associated(newp)) + cohort => newp%tallest + do while (associated(cohort)) + if (abs(cohort%c_area - newp%area) < area_error_3) then ! correct if it's a very small error + old_carea = cohort%c_area + cohort%c_area = cohort%c_area - (cohort%c_area - newp%area) + cohort%n = cohort%n*(cohort%c_area/old_carea) + end if + cohort => cohort%shorter + end do + newp => newp%younger + end do + end if ! For carbon balance checks, we need to initialize the ! total carbon stock @@ -618,34 +761,34 @@ subroutine init_patches( nsites, sites, bc_in) enddo !s end if - ! zero all the patch fire variables for the first timestep + ! zero all the patch fire variables for the first timestep do s = 1, nsites - currentPatch => sites(s)%youngest_patch - do while(associated(currentPatch)) - - currentPatch%litter_moisture(:) = 0._r8 - currentPatch%fuel_eff_moist = 0._r8 - currentPatch%livegrass = 0._r8 - currentPatch%sum_fuel = 0._r8 - currentPatch%fuel_bulkd = 0._r8 - currentPatch%fuel_sav = 0._r8 - currentPatch%fuel_mef = 0._r8 - currentPatch%ros_front = 0._r8 - currentPatch%effect_wspeed = 0._r8 - currentPatch%tau_l = 0._r8 - currentPatch%fuel_frac(:) = 0._r8 - currentPatch%tfc_ros = 0._r8 - currentPatch%fi = 0._r8 - currentPatch%fire = 0 - currentPatch%fd = 0._r8 - currentPatch%ros_back = 0._r8 - currentPatch%scorch_ht(:) = 0._r8 - currentPatch%frac_burnt = 0._r8 - currentPatch%burnt_frac_litter(:) = 0._r8 - - currentPatch => currentPatch%older - enddo - enddo + currentPatch => sites(s)%youngest_patch + do while(associated(currentPatch)) + + currentPatch%litter_moisture(:) = 0._r8 + currentPatch%fuel_eff_moist = 0._r8 + currentPatch%livegrass = 0._r8 + currentPatch%sum_fuel = 0._r8 + currentPatch%fuel_bulkd = 0._r8 + currentPatch%fuel_sav = 0._r8 + currentPatch%fuel_mef = 0._r8 + currentPatch%ros_front = 0._r8 + currentPatch%effect_wspeed = 0._r8 + currentPatch%tau_l = 0._r8 + currentPatch%fuel_frac(:) = 0._r8 + currentPatch%tfc_ros = 0._r8 + currentPatch%fi = 0._r8 + currentPatch%fire = 0 + currentPatch%fd = 0._r8 + currentPatch%ros_back = 0._r8 + currentPatch%scorch_ht(:) = 0._r8 + currentPatch%frac_burnt = 0._r8 + currentPatch%burnt_frac_litter(:) = 0._r8 + + currentPatch => currentPatch%older + enddo + enddo ! This sets the rhizosphere shells based on the plant initialization ! The initialization of the plant-relevant hydraulics variables @@ -661,264 +804,305 @@ subroutine init_patches( nsites, sites, bc_in) end subroutine init_patches ! ============================================================================ - subroutine init_cohorts( site_in, patch_in, bc_in) - ! - ! !DESCRIPTION: - ! initialize new cohorts on bare ground - ! - ! !USES: - ! - ! !ARGUMENTS - type(ed_site_type), intent(inout), pointer :: site_in - type(ed_patch_type), intent(inout), pointer :: patch_in - type(bc_in_type), intent(in) :: bc_in - ! - ! !LOCAL VARIABLES: - type(ed_cohort_type),pointer :: temp_cohort - class(prt_vartypes),pointer :: prt_obj - integer :: cstatus - integer :: pft - integer :: iage ! index for leaf age loop - integer :: el ! index for element loop - integer :: element_id ! element index consistent with defs in PRTGeneric - integer :: use_pft_local(numpft) ! determine whether this PFT is used for this patch and site. - real(r8) :: c_agw ! biomass above ground (non-leaf) [kgC] - real(r8) :: c_bgw ! biomass below ground (non-fineroot) [kgC] - real(r8) :: c_leaf ! biomass in leaves [kgC] - real(r8) :: c_fnrt ! biomass in fine roots [kgC] - real(r8) :: c_sapw ! biomass in sapwood [kgC] - real(r8) :: c_struct ! biomass in structure (dead) [kgC] - real(r8) :: c_store ! biomass in storage [kgC] - real(r8) :: a_sapw ! area in sapwood (dummy) [m2] - real(r8) :: m_struct ! Generic (any element) mass for structure [kg] - real(r8) :: m_leaf ! Generic mass for leaf [kg] - real(r8) :: m_fnrt ! Generic mass for fine-root [kg] - real(r8) :: m_sapw ! Generic mass for sapwood [kg] - real(r8) :: m_store ! Generic mass for storage [kg] - real(r8) :: m_repro ! Generic mass for reproductive tissues [kg] - real(r8) :: stem_drop_fraction - - integer, parameter :: rstatus = 0 - integer init - !---------------------------------------------------------------------- - - patch_in%tallest => null() - patch_in%shortest => null() - - ! Manage interactions of fixed biogeog (site level filter) and - ! nocomp (patch level filter) - ! Need to cover all potential biogeog x nocomp combinations - ! 1. biogeog = false. nocomp = false: all PFTs on (DEFAULT) - ! 2. biogeog = true. nocomp = false: site level filter - ! 3. biogeog = false. nocomp = true : patch level filter - ! 4. biogeog = true. nocomp = true : patch and site level filter - ! in principle this could be a patch level variable. - do pft = 1,numpft - ! Turn every PFT ON, unless we are in a special case. - use_pft_local(pft) = itrue ! Case 1 - if(hlm_use_fixed_biogeog.eq.itrue)then !filter geographically - use_pft_local(pft) = site_in%use_this_pft(pft) ! Case 2 - if(hlm_use_nocomp.eq.itrue.and.pft.ne.patch_in%nocomp_pft_label)then - ! Having set the biogeog filter as on or off, turn off all PFTs - ! whose identiy does not correspond to this patch label. - use_pft_local(pft) = ifalse ! Case 3 - endif - else - if(hlm_use_nocomp.eq.itrue.and.pft.ne.patch_in%nocomp_pft_label)then - ! This case has all PFTs on their own patch everywhere. - use_pft_local(pft) = ifalse ! Case 4 - endif - endif - - end do - do pft = 1,numpft - if(use_pft_local(pft).eq.itrue)then - if(EDPftvarcon_inst%initd(pft)>nearzero) then - - allocate(temp_cohort) ! temporary cohort - - temp_cohort%pft = pft - temp_cohort%n = EDPftvarcon_inst%initd(pft) * patch_in%area - if(hlm_use_nocomp.eq.itrue)then !in nocomp mode we only have one PFT per patch - ! as opposed to numpft's. So we should up the initial density - ! to compensate (otherwise runs are very hard to compare) - ! this multiplies it by the number of PFTs there would have been in - ! the single shared patch in competition mode. - ! n.b. that this is the same as currentcohort%n = %initd(pft) &AREA - temp_cohort%n = temp_cohort%n * sum(site_in%use_this_pft) - endif - - temp_cohort%canopy_trim = 1.0_r8 - - ! h,dbh,leafc,n from SP values or from small initial size. - - if(hlm_use_sp.eq.itrue)then - init = itrue - ! At this point, we do not know the bc_in values of tlai tsai and htop, - ! so this is initializing to an arbitrary value for the very first timestep. - ! Not sure if there's a way around this or not. - call assign_cohort_SP_properties(temp_cohort, 0.5_r8,0.2_r8, 0.1_r8,patch_in%area,init,c_leaf) - - else - temp_cohort%hite = EDPftvarcon_inst%hgt_min(pft) - - ! Calculate the plant diameter from height - call h2d_allom(temp_cohort%hite,pft,temp_cohort%dbh) - - ! Calculate the leaf biomass from allometry - ! (calculates a maximum first, then applies canopy trim) - call bleaf(temp_cohort%dbh,pft,temp_cohort%canopy_trim,c_leaf) - end if ! sp mode - - ! Calculate total above-ground biomass from allometry - call bagw_allom(temp_cohort%dbh,pft,c_agw) - - ! Calculate coarse root biomass from allometry - call bbgw_allom(temp_cohort%dbh,pft,c_bgw) - - ! Calculate fine root biomass from allometry - ! (calculates a maximum and then trimming value) - call bfineroot(temp_cohort%dbh,pft,temp_cohort%canopy_trim,c_fnrt) - - ! Calculate sapwood biomass - call bsap_allom(temp_cohort%dbh,pft,temp_cohort%canopy_trim,a_sapw,c_sapw) - - call bdead_allom( c_agw, c_bgw, c_sapw, pft, c_struct ) - - call bstore_allom(temp_cohort%dbh, pft, temp_cohort%canopy_trim, c_store) - - temp_cohort%laimemory = 0._r8 - temp_cohort%sapwmemory = 0._r8 - temp_cohort%structmemory = 0._r8 - cstatus = leaves_on - - stem_drop_fraction = EDPftvarcon_inst%phen_stem_drop_fraction(temp_cohort%pft) - - if(hlm_use_sp.eq.ifalse)then ! do not override SP vales with phenology - - if( prt_params%season_decid(pft) == itrue .and. & - any(site_in%cstatus == [phen_cstat_nevercold,phen_cstat_iscold])) then - temp_cohort%laimemory = c_leaf - temp_cohort%sapwmemory = c_sapw * stem_drop_fraction - temp_cohort%structmemory = c_struct * stem_drop_fraction - c_leaf = 0._r8 - c_sapw = (1.0_r8-stem_drop_fraction) * c_sapw - c_struct = (1.0_r8-stem_drop_fraction) * c_struct - cstatus = leaves_off - endif - - if ( prt_params%stress_decid(pft) == itrue .and. & - any(site_in%dstatus == [phen_dstat_timeoff,phen_dstat_moistoff])) then - temp_cohort%laimemory = c_leaf - temp_cohort%sapwmemory = c_sapw * stem_drop_fraction - temp_cohort%structmemory = c_struct * stem_drop_fraction - c_leaf = 0._r8 - c_sapw = (1.0_r8-stem_drop_fraction) * c_sapw - c_struct = (1.0_r8-stem_drop_fraction) * c_struct - cstatus = leaves_off - endif - - end if ! SP mode - - if ( debug ) write(fates_log(),*) 'EDInitMod.F90 call create_cohort ' - - temp_cohort%coage = 0.0_r8 - - - ! -------------------------------------------------------------------------------- - ! Initialize the mass of every element in every organ of the organ - ! -------------------------------------------------------------------------------- - - prt_obj => null() - call InitPRTObject(prt_obj) - - 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(pft,prt_params%organ_param_id(struct_organ)) - m_leaf = c_leaf*prt_params%nitr_stoich_p2(pft,prt_params%organ_param_id(leaf_organ)) - m_fnrt = c_fnrt*prt_params%nitr_stoich_p2(pft,prt_params%organ_param_id(fnrt_organ)) - m_sapw = c_sapw*prt_params%nitr_stoich_p2(pft,prt_params%organ_param_id(sapw_organ)) - m_repro = 0._r8 - m_store = StorageNutrientTarget(pft,element_id,m_leaf,m_fnrt,m_sapw,m_struct) - - case(phosphorus_element) - - m_struct = c_struct*prt_params%phos_stoich_p2(pft,prt_params%organ_param_id(struct_organ)) - m_leaf = c_leaf*prt_params%phos_stoich_p2(pft,prt_params%organ_param_id(leaf_organ)) - m_fnrt = c_fnrt*prt_params%phos_stoich_p2(pft,prt_params%organ_param_id(fnrt_organ)) - m_sapw = c_sapw*prt_params%phos_stoich_p2(pft,prt_params%organ_param_id(sapw_organ)) - m_repro = 0._r8 - m_store = StorageNutrientTarget(pft,element_id,m_leaf,m_fnrt,m_sapw,m_struct) - - 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_obj,leaf_organ, element_id,m_leaf,1) - do iage = 2,nleafage - call SetState(prt_obj,leaf_organ, element_id,0._r8,iage) - end do - - call SetState(prt_obj,fnrt_organ, element_id, m_fnrt) - call SetState(prt_obj,sapw_organ, element_id, m_sapw) - call SetState(prt_obj,store_organ, element_id, m_store) - call SetState(prt_obj,struct_organ, element_id, m_struct) - call SetState(prt_obj,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 - - end do - - call prt_obj%CheckInitialConditions() - - call create_cohort(site_in, patch_in, pft, temp_cohort%n, temp_cohort%hite, & - temp_cohort%coage, temp_cohort%dbh, prt_obj, temp_cohort%laimemory, & - temp_cohort%sapwmemory, temp_cohort%structmemory, cstatus, rstatus, & - temp_cohort%canopy_trim, temp_cohort%c_area,1, site_in%spread, bc_in) - - - deallocate(temp_cohort) ! get rid of temporary cohort - - endif - endif !use_this_pft - enddo !numpft - - ! (Keeping as an example) - ! Pass patch level temperature to the new cohorts (this is a nominal 15C right now) - !temp_cohort => patch_in%tallest - !do while(associated(temp_cohort)) - !call temp_cohort%tveg_lpa%UpdateRmean(patch_in%tveg_lpa%GetMean()) - !temp_cohort => temp_cohort%shorter - !end do - - call fuse_cohorts(site_in, patch_in,bc_in) - call sort_cohorts(patch_in) - - - end subroutine init_cohorts - - ! =============================================================================================== - + + subroutine init_cohorts(site_in, patch_in, bc_in) + ! + ! DESCRIPTION: + ! initialize new cohorts on bare ground + ! + + ! ARGUMENTS + type(ed_site_type), intent(inout), pointer :: site_in + type(fates_patch_type), intent(inout), pointer :: patch_in + type(bc_in_type), intent(in) :: bc_in + + ! LOCAL VARIABLES: + class(prt_vartypes), pointer :: prt ! PARTEH object + integer :: leaf_status ! cohort phenology status [leaves on/off] + integer :: pft ! index for PFT + integer :: iage ! index for leaf age loop + integer :: el ! index for element loop + integer :: element_id ! element index consistent with defs in PRTGeneric + integer :: use_pft_local(numpft) ! determine whether this PFT is used for this patch and site + integer :: crown_damage ! crown damage class of the cohort [1 = undamaged, >1 = damaged] + real(r8) :: l2fr ! leaf to fineroot biomass ratio [kg kg-1] + real(r8) :: canopy_trim ! fraction of the maximum leaf biomass that we are targeting [0-1] + real(r8) :: cohort_n ! cohort density + real(r8) :: dbh ! cohort dbh [cm] + real(r8) :: height ! cohort height [m] + real(r8) :: c_area ! cohort crown area [m2] + real(r8) :: c_agw ! above ground (non-leaf) biomass [kgC] + real(r8) :: c_bgw ! below ground (non-fineroot) biomss [kgC] + real(r8) :: c_leaf ! leaf biomass [kgC] + real(r8) :: c_fnrt ! fine root biomss [kgC] + real(r8) :: c_sapw ! sapwood biomass [kgC] + real(r8) :: c_struct ! structural (dead) biomass [kgC] + real(r8) :: c_store ! storage biomass [kgC] + real(r8) :: a_sapw ! sapwood area [m2] + real(r8) :: m_struct ! generic (any element) mass for structure [kg] + real(r8) :: m_leaf ! generic mass for leaf [kg] + real(r8) :: m_fnrt ! generic mass for fine-root [kg] + real(r8) :: m_sapw ! generic mass for sapwood [kg] + real(r8) :: m_store ! generic mass for storage [kg] + real(r8) :: m_repro ! generic mass for reproductive tissues [kg] + ! of all the organs in the recruits. Used for both [kg per plant] and [kg per cohort] + real(r8) :: efleaf_coh + real(r8) :: effnrt_coh + real(r8) :: efstem_coh + real(r8) :: stem_drop_fraction ! fraction of stem to absciss when leaves absciss + real(r8) :: fnrt_drop_fraction ! fraction of fine roots to absciss when leaves absciss + integer, parameter :: recruitstatus = 0 ! whether the newly created cohorts are recruited or initialized + real(r8),parameter :: zero_co_age = 0._r8 ! The age of a newly recruited cohort is zero + !------------------------------------------------------------------------------------- + + patch_in%tallest => null() + patch_in%shortest => null() + + ! if any pfts are starting with large size then the whole site needs a spread of 0 + do pft = 1, numpft + if (EDPftvarcon_inst%initd(pft) < 0.0_r8) then + site_in%spread = init_spread_inventory + end if + end do + + + ! Manage interactions of fixed biogeog (site level filter) and nocomp (patch level filter) + ! Need to cover all potential biogeog x nocomp combinations + ! 1. biogeog = false. nocomp = false: all PFTs on (DEFAULT) + ! 2. biogeog = true. nocomp = false: site level filter + ! 3. biogeog = false. nocomp = true : patch level filter + ! 4. biogeog = true. nocomp = true : patch and site level filter + ! in principle this could be a patch level variable. + do pft = 1, numpft + ! first turn every PFT ON, unless we are in a special case + use_pft_local(pft) = itrue ! Case 1 + if (hlm_use_fixed_biogeog .eq. itrue) then !filter geographically + use_pft_local(pft) = site_in%use_this_pft(pft) ! Case 2 + if (hlm_use_nocomp .eq. itrue .and. pft .ne. patch_in%nocomp_pft_label) then + ! having set the biogeog filter as on or off, turn off all PFTs + ! whose identity does not correspond to this patch label + use_pft_local(pft) = ifalse ! Case 3 + endif + else + if (hlm_use_nocomp .eq. itrue .and. pft .ne. patch_in%nocomp_pft_label) then + ! This case has all PFTs on their own patch everywhere + use_pft_local(pft) = ifalse ! Case 4 + endif + endif + end do + + pft_loop: do pft = 1, numpft + if_use_this_pft: if (use_pft_local(pft) .eq. itrue) then + l2fr = prt_params%allom_l2fr(pft) + canopy_trim = 1.0_r8 + crown_damage = 1 ! Assume no damage to begin with + + ! retrieve drop fraction of non-leaf tissues for phenology initialization + fnrt_drop_fraction = prt_params%phen_fnrt_drop_fraction(pft) + stem_drop_fraction = prt_params%phen_stem_drop_fraction(pft) + + ! initialize phenology variables + if_spmode: if (hlm_use_sp == itrue) then + ! satellite phenology: do not override SP values with build-in phenology + efleaf_coh = 1.0_r8 + effnrt_coh = 1.0_r8 + efstem_coh = 1.0_r8 + leaf_status = leaves_on + else + ! use built-in phenology + if (prt_params%season_decid(pft) == itrue .and. & + any(site_in%cstatus == [phen_cstat_nevercold, phen_cstat_iscold])) then + ! Cold deciduous, off season, assume complete abscission + efleaf_coh = 0.0_r8 + effnrt_coh = 1.0_r8 - fnrt_drop_fraction + efstem_coh = 1.0_r8 - stem_drop_fraction + leaf_status = leaves_off + else if (any(prt_params%stress_decid(pft) == [ihard_stress_decid, isemi_stress_decid])) then + ! If the plant is drought deciduous, make sure leaf status is + ! always consistent with the leaf elongation factor. For tissues + ! other than leaves, the actual drop fraction is a combination of the + ! elongation factor (e) and the drop fraction (x), which will ensure + ! that the remaining tissue biomass will be exactly e when x=1, and + ! exactly the original biomass when x = 0. + efleaf_coh = site_in%elong_factor(pft) + effnrt_coh = 1.0_r8 - (1.0_r8 - efleaf_coh)*fnrt_drop_fraction + efstem_coh = 1.0_r8 - (1.0_r8 - efleaf_coh)*stem_drop_fraction + + if (efleaf_coh > 0.0_r8) then + leaf_status = leaves_on + else + leaf_status = leaves_off + end if + else + ! Evergreens, or deciduous during growing season + ! Assume leaves fully flushed + efleaf_coh = 1.0_r8 + effnrt_coh = 1.0_r8 + efstem_coh = 1.0_r8 + leaf_status = leaves_on + end if + end if if_spmode + + ! If positive EDPftvarcon_inst%initd is interpreted as initial recruit density. + ! If negative EDPftvarcon_inst%initd is interpreted as initial dbh. + ! Dbh-initialization can only be used in nocomp mode. + ! In the dbh-initialization case, we calculate crown area for a single tree and then calculate + ! the density of plants needed for a full canopy. + if_init_dens: if (EDPftvarcon_inst%initd(pft) > nearzero) then ! interpret as initial density and calculate diameter + + cohort_n = EDPftvarcon_inst%initd(pft)*patch_in%area + if (hlm_use_nocomp .eq. itrue) then !in nocomp mode we only have one PFT per patch + ! as opposed to numpft's. So we should up the initial density + ! to compensate (otherwise runs are very hard to compare) + ! this multiplies it by the number of PFTs there would have been in + ! the single shared patch in competition mode. + ! n.b. that this is the same as currentcohort%n = %initd(pft) &AREA + cohort_n = cohort_n*sum(site_in%use_this_pft) + endif + height = EDPftvarcon_inst%hgt_min(pft) + + ! h, dbh, leafc, n from SP values or from small initial size + if (hlm_use_sp .eq. itrue) then + ! At this point, we do not know the bc_in values of tlai tsai and htop, + ! so this is initializing to an arbitrary value for the very first timestep. + ! Not sure if there's a way around this or not. + height = 0.5_r8 + call calculate_SP_properties(height, 0.2_r8, 0.1_r8, & + patch_in%area, pft, crown_damage, 1, & + EDPftvarcon_inst%vcmax25top(pft, 1), c_leaf, dbh, & + cohort_n, c_area) + else + ! calculate the plant diameter from height + call h2d_allom(height, pft, dbh) + + ! Calculate the leaf biomass from allometry + ! (calculates a maximum first, then applies canopy trim) + call bleaf(dbh, pft, crown_damage, canopy_trim, efleaf_coh, c_leaf) + endif ! sp mode + + else ! interpret as initial diameter and calculate density + if (hlm_use_nocomp .eq. itrue) then + + dbh = abs(EDPftvarcon_inst%initd(pft)) + + ! calculate crown area of a single plant + call carea_allom(dbh, 1.0_r8, init_spread_inventory, pft, crown_damage, & + c_area) + + ! calculate initial density required to close canopy + cohort_n = patch_in%area/c_area + + ! Calculate the leaf biomass from allometry + ! (calculates a maximum first, then applies canopy trim) + call bleaf(dbh, pft, crown_damage, canopy_trim, efleaf_coh, & + c_leaf) + + ! calculate crown area of the cohort + call carea_allom(dbh, cohort_n, init_spread_inventory, pft, crown_damage, & + c_area) + + ! calculate height from diameter + call h_allom(dbh, pft, height) + + else + write(fates_log(),*) 'Negative fates_recruit_init_density can only be used in no comp mode' + call endrun(msg=errMsg(sourcefile, __LINE__)) + endif + endif if_init_dens + + ! calculate total above-ground biomass from allometry + call bagw_allom(dbh, pft, crown_damage, efstem_coh, c_agw) + + ! calculate coarse root biomass from allometry + call bbgw_allom(dbh, pft, efstem_coh, c_bgw) + + ! Calculate fine root biomass from allometry + ! (calculates a maximum and then trimming value) + call bfineroot(dbh, pft, canopy_trim, l2fr, effnrt_coh, c_fnrt) + + ! Calculate sapwood biomass + call bsap_allom(dbh, pft, crown_damage, canopy_trim, efstem_coh, & + a_sapw, c_sapw) + + call bdead_allom(c_agw, c_bgw, c_sapw, pft, c_struct) + call bstore_allom(dbh, pft, crown_damage, canopy_trim, c_store) + + if (debug) write(fates_log(),*) 'EDInitMod.F90 call create_cohort ' + + ! -------------------------------------------------------------------------------- + ! Initialize the mass of every element in every organ of the organ + ! -------------------------------------------------------------------------------- + + prt => null() + call InitPRTObject(prt) + + element_loop: 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_p1(pft, prt_params%organ_param_id(struct_organ)) + m_leaf = c_leaf*prt_params%nitr_stoich_p1(pft, prt_params%organ_param_id(leaf_organ)) + m_fnrt = c_fnrt*prt_params%nitr_stoich_p1(pft, prt_params%organ_param_id(fnrt_organ)) + m_sapw = c_sapw*prt_params%nitr_stoich_p1(pft, prt_params%organ_param_id(sapw_organ)) + m_repro = 0._r8 + m_store = StorageNutrientTarget(pft, element_id, m_leaf, m_fnrt, m_sapw, m_struct) + case(phosphorus_element) + + m_struct = c_struct*prt_params%phos_stoich_p1(pft, prt_params%organ_param_id(struct_organ)) + m_leaf = c_leaf*prt_params%phos_stoich_p1(pft, prt_params%organ_param_id(leaf_organ)) + m_fnrt = c_fnrt*prt_params%phos_stoich_p1(pft, prt_params%organ_param_id(fnrt_organ)) + m_sapw = c_sapw*prt_params%phos_stoich_p1(pft, prt_params%organ_param_id(sapw_organ)) + m_repro = 0._r8 + m_store = StorageNutrientTarget(pft, element_id, m_leaf, m_fnrt, m_sapw, m_struct) + 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 + + end do element_loop + + call prt%CheckInitialConditions() + + call create_cohort(site_in, patch_in, pft, cohort_n, & + height, zero_co_age, dbh, prt, efleaf_coh, & + effnrt_coh, efstem_coh, leaf_status, recruitstatus, & + canopy_trim, c_area, 1, crown_damage, site_in%spread, bc_in) + + endif if_use_this_pft + enddo pft_loop + + if (hlm_use_sp == ifalse) then + call fuse_cohorts(site_in, patch_in,bc_in) + call sort_cohorts(patch_in) + end if + + end subroutine init_cohorts + + ! ====================================================================================== end module EDInitMod diff --git a/main/EDMainMod.F90 b/main/EDMainMod.F90 index 152911b59c..2b29157512 100644 --- a/main/EDMainMod.F90 +++ b/main/EDMainMod.F90 @@ -19,6 +19,7 @@ module EDMainMod use FatesInterfaceTypesMod , only : hlm_use_cohort_age_tracking use FatesInterfaceTypesMod , only : hlm_reference_date use FatesInterfaceTypesMod , only : hlm_use_ed_prescribed_phys + use FatesInterfaceTypesMod , only : hlm_use_tree_damage use FatesInterfaceTypesMod , only : hlm_use_ed_st3 use FatesInterfaceTypesMod , only : hlm_use_sp use FatesInterfaceTypesMod , only : bc_in_type @@ -35,6 +36,7 @@ module EDMainMod use EDCohortDynamicsMod , only : sort_cohorts use EDCohortDynamicsMod , only : count_cohorts use EDCohortDynamicsMod , only : EvaluateAndCorrectDBH + use EDCohortDynamicsMod , only : DamageRecovery use EDPatchDynamicsMod , only : disturbance_rates use EDPatchDynamicsMod , only : fuse_patches use EDPatchDynamicsMod , only : spawn_patches @@ -43,13 +45,17 @@ module EDMainMod use EDPhysiologyMod , only : satellite_phenology use EDPhysiologyMod , only : recruitment use EDPhysiologyMod , only : trim_canopy - use EDPhysiologyMod , only : SeedIn + use EDPhysiologyMod , only : SeedUpdate use EDPhysiologyMod , only : ZeroAllocationRates use EDPhysiologyMod , only : ZeroLitterFluxes use EDPhysiologyMod , only : PreDisturbanceLitterFluxes use EDPhysiologyMod , only : PreDisturbanceIntegrateLitter + use EDPhysiologyMod , only : UpdateRecruitL2FR + use EDPhysiologyMod , only : UpdateRecruitStoich + use EDPhysiologyMod , only : SetRecruitL2FR + use EDPhysiologyMod , only : GenerateDamageAndLitterFluxes use FatesSoilBGCFluxMod , only : FluxIntoLitterPools - use EDCohortDynamicsMod , only : UpdateCohortBioPhysRates + use FatesSoilBGCFluxMod , only : EffluxIntoLitterPools use FatesSoilBGCFluxMod , only : PrepNutrientAquisitionBCs use FatesSoilBGCFluxMod , only : PrepCH4BCs use SFMainMod , only : fire_model @@ -58,8 +64,8 @@ module EDMainMod use FatesLitterMod , only : litter_type use FatesLitterMod , only : ncwd use EDtypesMod , only : ed_site_type - use EDtypesMod , only : ed_patch_type - use EDtypesMod , only : ed_cohort_type + use FatesPatchMod , only : fates_patch_type + use FatesCohortMod , only : fates_cohort_type use EDTypesMod , only : AREA use EDTypesMod , only : site_massbal_type use PRTGenericMod , only : num_elements @@ -80,13 +86,14 @@ module EDMainMod use FatesPlantHydraulicsMod , only : AccumulateMortalityWaterStorage use FatesAllometryMod , only : h_allom,tree_sai,tree_lai use EDLoggingMortalityMod , only : IsItLoggingTime + use EDLoggingMortalityMod , only : get_harvestable_carbon + use DamageMainMod , only : IsItDamageTime use EDPatchDynamicsMod , only : get_frac_site_primary use FatesGlobals , only : endrun => fates_endrun use ChecksBalancesMod , only : SiteMassStock use EDMortalityFunctionsMod , only : Mortality_Derivative use EDTypesMod , only : AREA_INV use PRTGenericMod, only : carbon12_element - use PRTGenericMod, only : all_carbon_elements use PRTGenericMod, only : leaf_organ use PRTGenericMod, only : fnrt_organ use PRTGenericMod, only : sapw_organ @@ -96,8 +103,6 @@ module EDMainMod use PRTLossFluxesMod, only : PRTMaintTurnover use PRTLossFluxesMod, only : PRTReproRelease use EDPftvarcon, only : EDPftvarcon_inst - 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 @@ -111,6 +116,7 @@ module EDMainMod ! !PUBLIC MEMBER FUNCTIONS: public :: ed_ecosystem_dynamics public :: ed_update_site + ! ! !PRIVATE MEMBER FUNCTIONS: @@ -143,13 +149,13 @@ subroutine ed_ecosystem_dynamics(currentSite, bc_in, bc_out) type(bc_out_type) , intent(inout) :: bc_out ! ! !LOCAL VARIABLES: - type(ed_patch_type), pointer :: currentPatch - integer :: el ! Loop counter for elements + type(fates_patch_type), pointer :: currentPatch + integer :: el ! Loop counter for variables integer :: do_patch_dynamics ! for some modes, we turn off patch dynamics !----------------------------------------------------------------------- - if ( hlm_masterproc==itrue ) write(fates_log(),'(A,I4,A,I2.2,A,I2.2)') 'FATES Dynamics: ',& + if (debug .and.( hlm_masterproc==itrue)) write(fates_log(),'(A,I4,A,I2.2,A,I2.2)') 'FATES Dynamics: ',& hlm_current_year,'-',hlm_current_month,'-',hlm_current_day ! Consider moving this towards the end, because some of these @@ -163,11 +169,16 @@ subroutine ed_ecosystem_dynamics(currentSite, bc_in, bc_out) ! zero dynamics (upfreq_in = 1) output history variables call fates_hist%zero_site_hvars(currentSite,upfreq_in=1) + ! zero nutrient fluxes (upfreq_in=5) output hist variables + call fates_hist%zero_site_hvars(currentSite,upfreq_in=5) ! Call a routine that simply identifies if logging should occur ! This is limited to a global event until more structured event handling is enabled call IsItLoggingTime(hlm_masterproc,currentSite) + ! Call a routine that identifies if damage should occur + call IsItDamageTime(hlm_masterproc) + !************************************************************************** ! Fire, growth, biogeochemistry. !************************************************************************** @@ -197,7 +208,15 @@ subroutine ed_ecosystem_dynamics(currentSite, bc_in, bc_out) if (hlm_use_ed_st3.eq.ifalse.and.hlm_use_sp.eq.ifalse) then ! Bypass if ST3 - call fire_model(currentSite, bc_in) + + ! Check that the site doesn't consist solely of a single bareground patch. + ! If so, skip the fire model. Since the bareground patch should be the + ! oldest patch per set_patchno, we check that the youngest patch isn't zero. + ! If there are multiple patches on the site, the bareground patch is avoided + ! at the level of the fire_model subroutines. + if (currentSite%youngest_patch%patchno .ne. 0) then + call fire_model(currentSite, bc_in) + end if ! Calculate disturbance and mortality based on previous timestep vegetation. ! disturbance_rates calls logging mortality and other mortalities, Yi Xu @@ -227,6 +246,8 @@ subroutine ed_ecosystem_dynamics(currentSite, bc_in, bc_out) ! adds small cohort of each PFT call recruitment(currentSite, currentPatch, bc_in) + !YL -------------- + ! call recruitment(currentSite, currentPatch, bc_in, bc_out) currentPatch => currentPatch%younger enddo @@ -292,7 +313,7 @@ subroutine ed_ecosystem_dynamics(currentSite, bc_in, bc_out) end if call TotalBalanceCheck(currentSite,5) - + end subroutine ed_ecosystem_dynamics !-------------------------------------------------------------------------------! @@ -303,8 +324,18 @@ subroutine ed_integrate_state_variables(currentSite, bc_in, bc_out ) ! FIX(SPM,032414) refactor so everything goes through interface ! ! !USES: + use FatesInterfaceTypesMod, only : hlm_num_lu_harvest_cats + use PRTGenericMod , only : leaf_organ + use PRTGenericMod , only : repro_organ + use PRTGenericMod , only : sapw_organ + use PRTGenericMod , only : struct_organ + use PRTGenericMod , only : store_organ + use PRTGenericMod , only : fnrt_organ use FatesInterfaceTypesMod, only : hlm_use_cohort_age_tracking use FatesConstantsMod, only : itrue + use FatesConstantsMod , only : nearzero + use EDCanopyStructureMod , only : canopy_structure + ! !ARGUMENTS: type(ed_site_type) , intent(inout) :: currentSite @@ -314,8 +345,14 @@ subroutine ed_integrate_state_variables(currentSite, bc_in, bc_out ) ! ! !LOCAL VARIABLES: type(site_massbal_type), pointer :: site_cmass - type(ed_patch_type) , pointer :: currentPatch - type(ed_cohort_type) , pointer :: currentCohort + type(fates_patch_type) , pointer :: currentPatch + type(fates_cohort_type) , pointer :: currentCohort + type(fates_cohort_type) , pointer :: nc + type(fates_cohort_type) , pointer :: storesmallcohort + type(fates_cohort_type) , pointer :: storebigcohort + + integer :: snull + integer :: tnull integer :: c ! Counter for litter size class integer :: ft ! Counter for PFT @@ -324,31 +361,81 @@ subroutine ed_integrate_state_variables(currentSite, bc_in, bc_out ) integer :: el ! Counter for element type (c,n,p,etc) real(r8) :: cohort_biomass_store ! remembers the biomass in the cohort for balance checking real(r8) :: dbh_old ! dbh of plant before daily PRT [cm] - real(r8) :: hite_old ! height of plant before daily PRT [m] + real(r8) :: height_old ! height of plant before daily PRT [m] logical :: is_drought ! logical for if the plant (site) is in a drought state real(r8) :: delta_dbh ! correction for dbh - real(r8) :: delta_hite ! correction for hite - - real(r8) :: current_npp ! place holder for calculating npp each year in prescribed physiology mode - !----------------------------------------------------------------------- + real(r8) :: delta_height ! correction for height + real(r8) :: mean_temp + + logical :: newly_recovered ! If the current loop is dealing with a newly created cohort, which + ! was created because it is a clone of the previous cohort in + ! a lowered damage state. This cohort should bypass several calculations + ! because it inherited them (such as daily carbon balance) + real(r8) :: target_leaf_c real(r8) :: frac_site_primary + real(r8) :: harvestable_forest_c(hlm_num_lu_harvest_cats) + integer :: harvest_tag(hlm_num_lu_harvest_cats) + + real(r8) :: n_old + real(r8) :: n_recover + real(r8) :: sapw_c + real(r8) :: leaf_c + real(r8) :: fnrt_c + real(r8) :: struct_c + real(r8) :: repro_c + real(r8) :: total_c + real(r8) :: store_c + + real(r8) :: cc_leaf_c + real(r8) :: cc_fnrt_c + real(r8) :: cc_struct_c + real(r8) :: cc_repro_c + real(r8) :: cc_store_c + real(r8) :: cc_sapw_c + + real(r8) :: sapw_c0 + real(r8) :: leaf_c0 + real(r8) :: fnrt_c0 + real(r8) :: struct_c0 + real(r8) :: repro_c0 + real(r8) :: store_c0 + real(r8) :: total_c0 + real(r8) :: nc_carbon + real(r8) :: cc_carbon + + integer,parameter :: leaf_c_id = 1 + + !----------------------------------------------------------------------- call get_frac_site_primary(currentSite, frac_site_primary) + ! Clear site GPP and AR passing to HLM + bc_out%gpp_site = 0._r8 + bc_out%ar_site = 0._r8 + + ! Patch level biomass are required for C-based harvest + call get_harvestable_carbon(currentSite, bc_in%site_area, bc_in%hlm_harvest_catnames, harvestable_forest_c) + ! Set a pointer to this sites carbon12 mass balance site_cmass => currentSite%mass_balance(element_pos(carbon12_element)) - currentPatch => currentSite%youngest_patch + ! This call updates the assessment of the total stoichiometry + ! for a new recruit, based on its PFT and the L2FR of + ! a new recruit. This is called here, because it is + ! prior to the growth sequence, where reproductive + ! tissues are allocated + call UpdateRecruitStoich(currentSite) + currentPatch => currentSite%oldest_patch do while(associated(currentPatch)) - currentPatch%age = currentPatch%age + hlm_freq_day ! FIX(SPM,032414) valgrind 'Conditional jump or move depends on uninitialised value' if( currentPatch%age < 0._r8 )then write(fates_log(),*) 'negative patch age?',currentPatch%age, & currentPatch%patchno,currentPatch%area + call endrun(msg=errMsg(sourcefile, __LINE__)) endif ! add age increment to secondary forest patches as well @@ -360,173 +447,190 @@ subroutine ed_integrate_state_variables(currentSite, bc_in, bc_out ) ! check to see if the patch has moved to the next age class currentPatch%age_class = get_age_class_index(currentPatch%age) - ! Update Canopy Biomass Pools + + ! Within this loop, we may be creating new cohorts, which + ! are copies of pre-existing cohorts with reduced damage classes. + ! If that is true, we want to bypass some of the things in + ! this loop (such as calculation of npp, etc) because they + ! are derived from the donor and have been modified accordingly + newly_recovered = .false. + currentCohort => currentPatch%shortest do while(associated(currentCohort)) - ft = currentCohort%pft + ! Some cohorts are created and inserted to the list while + ! the loop is going. These are pointed to the "taller" position + ! of current, and then inherit properties of their donor (current) + ! we don't need to repeat things before allocation for these + ! newly_recovered cohorts + + if_not_newlyrecovered: if(.not.newly_recovered) then + + + ! Calculate the mortality derivatives + mean_temp = currentPatch%tveg24%GetMean() + call Mortality_Derivative(currentSite, currentCohort, bc_in, & + currentPatch%btran_ft, mean_temp, & + currentPatch%anthro_disturbance_label, & + currentPatch%age_since_anthro_disturbance, frac_site_primary, & + harvestable_forest_c, harvest_tag) + + ! ----------------------------------------------------------------------------- + ! Apply Plant Allocation and Reactive Transport + ! ----------------------------------------------------------------------------- + ! ----------------------------------------------------------------------------- + ! Identify the net carbon gain for this dynamics interval + ! Set the available carbon pool, identify allocation portions, and + ! decrement the available carbon pool to zero. + ! ----------------------------------------------------------------------------- + + + if (hlm_use_ed_prescribed_phys .eq. itrue) then + if (currentCohort%canopy_layer .eq. 1) then + currentCohort%npp_acc = EDPftvarcon_inst%prescribed_npp_canopy(ft) & + * currentCohort%c_area / currentCohort%n / hlm_days_per_year + else + currentCohort%npp_acc = EDPftvarcon_inst%prescribed_npp_understory(ft) & + * currentCohort%c_area / currentCohort%n / hlm_days_per_year + endif + + ! We don't explicitly define a respiration rate for prescribe phys + ! but we do need to pass mass balance. So we say it is zero respiration + currentCohort%gpp_acc = currentCohort%npp_acc + currentCohort%resp_acc = 0._r8 - ! Calculate the mortality derivatives - call Mortality_Derivative( currentSite, currentCohort, bc_in, frac_site_primary ) - - ! ----------------------------------------------------------------------------- - ! Apply Plant Allocation and Reactive Transport - ! ----------------------------------------------------------------------------- - ! ----------------------------------------------------------------------------- - ! Identify the net carbon gain for this dynamics interval - ! Set the available carbon pool, identify allocation portions, and - ! decrement the available carbon pool to zero. - ! ----------------------------------------------------------------------------- - + end if - if (hlm_use_ed_prescribed_phys .eq. itrue) then - if (currentCohort%canopy_layer .eq. 1) then - currentCohort%npp_acc = EDPftvarcon_inst%prescribed_npp_canopy(ft) & - * currentCohort%c_area / currentCohort%n / hlm_days_per_year + ! ----------------------------------------------------------------------------- + ! Save NPP/GPP/R in these "hold" style variables. These variables + ! persist after this routine is complete, and used in I/O diagnostics. + ! Whereas the _acc style variables are zero'd because they are key + ! accumulation state variables. + ! + ! convert from kgC/indiv/day into kgC/indiv/year + ! _acc_hold is remembered until the next dynamics step (used for I/O) + ! _acc will be reset soon and will be accumulated on the next leaf + ! photosynthesis step + ! ----------------------------------------------------------------------------- + + currentCohort%npp_acc_hold = currentCohort%npp_acc * real(hlm_days_per_year,r8) + currentCohort%gpp_acc_hold = currentCohort%gpp_acc * real(hlm_days_per_year,r8) + currentCohort%resp_acc_hold = currentCohort%resp_acc * real(hlm_days_per_year,r8) + + ! Passing gpp_acc_hold to HLM + bc_out%gpp_site = bc_out%gpp_site + currentCohort%gpp_acc_hold * & + AREA_INV * currentCohort%n / hlm_days_per_year / sec_per_day + bc_out%ar_site = bc_out%ar_site + currentCohort%resp_acc_hold * & + AREA_INV * currentCohort%n / hlm_days_per_year / sec_per_day + + ! Conduct Maintenance Turnover (parteh) + if(debug) call currentCohort%prt%CheckMassConservation(ft,3) + if(any(currentSite%dstatus(ft) == [phen_dstat_moiston,phen_dstat_timeon])) then + is_drought = .false. else - currentCohort%npp_acc = EDPftvarcon_inst%prescribed_npp_understory(ft) & - * currentCohort%c_area / currentCohort%n / hlm_days_per_year - endif - - ! We don't explicitly define a respiration rate for prescribe phys - ! but we do need to pass mass balance. So we say it is zero respiration - currentCohort%gpp_acc = currentCohort%npp_acc - currentCohort%resp_acc = 0._r8 - - end if - - ! ----------------------------------------------------------------------------- - ! Save NPP/GPP/R in these "hold" style variables. These variables - ! persist after this routine is complete, and used in I/O diagnostics. - ! Whereas the _acc style variables are zero'd because they are key - ! accumulation state variables. - ! - ! convert from kgC/indiv/day into kgC/indiv/year - ! _acc_hold is remembered until the next dynamics step (used for I/O) - ! _acc will be reset soon and will be accumulated on the next leaf - ! photosynthesis step - ! ----------------------------------------------------------------------------- - - currentCohort%npp_acc_hold = currentCohort%npp_acc * real(hlm_days_per_year,r8) - currentCohort%gpp_acc_hold = currentCohort%gpp_acc * real(hlm_days_per_year,r8) - currentCohort%resp_acc_hold = currentCohort%resp_acc * real(hlm_days_per_year,r8) - + is_drought = .true. + end if - ! Conduct Maintenance Turnover (parteh) - if(debug) call currentCohort%prt%CheckMassConservation(ft,3) - if(any(currentSite%dstatus == [phen_dstat_moiston,phen_dstat_timeon])) then - is_drought = .false. - else - is_drought = .true. - end if - call PRTMaintTurnover(currentCohort%prt,ft,is_drought) + call PRTMaintTurnover(currentCohort%prt,ft,is_drought) + + ! ----------------------------------------------------------------------------------- + ! Call the routine that advances leaves in age. + ! This will move a portion of the leaf mass in each + ! age bin, to the next bin. This will not handle movement + ! of mass from the oldest bin into the litter pool, that is something else. + ! ----------------------------------------------------------------------------------- + call currentCohort%prt%AgeLeaves(ft,sec_per_day) + + ! Plants can acquire N from 3 sources (excluding re-absorption), + ! the source doesn't affect how its allocated (yet), so they + ! are combined into daily_n_gain, which is the value used in the following + ! allocation scheme + + currentCohort%daily_n_gain = currentCohort%daily_nh4_uptake + & + currentCohort%daily_no3_uptake + currentCohort%sym_nfix_daily + + currentCohort%resp_excess = 0._r8 + + end if if_not_newlyrecovered ! If the current diameter of a plant is somehow less than what is consistent ! with what is allometrically consistent with the stuctural biomass, then ! correct the dbh to match. - - call EvaluateAndCorrectDBH(currentCohort,delta_dbh,delta_hite) - - hite_old = currentCohort%hite + call EvaluateAndCorrectDBH(currentCohort,delta_dbh,delta_height) + + ! We want to save these values for the newly recovered cohort as well + height_old = currentCohort%height dbh_old = currentCohort%dbh ! ----------------------------------------------------------------------------- ! Growth and Allocation (PARTEH) ! ----------------------------------------------------------------------------- + + + ! We split the allocation into phases (currently for all hypotheses) + ! In phase 1, allocation, we address prioritized allocation that should + ! only happen once per day, this is only allocation that does not grow stature. + ! In phase 2, allocation , we address allocation that can be performed + ! as many times as necessary. This is allocation that does not contain stature + ! growth. This is separate from phase 1, because some recovering plants + ! will have new allocation targets that need to be updated after they change status. + ! In Phase 3, we assume that the plant has reached its targets, and any + ! left-over resources are used to grow the stature of the plant + + if(.not.newly_recovered)then + call currentCohort%prt%DailyPRT(phase=1) + end if - call currentCohort%prt%DailyPRT() + call currentCohort%prt%DailyPRT(phase=2) + + if((.not.newly_recovered) .and. (hlm_use_tree_damage .eq. itrue) ) then + ! The loop order is shortest to tallest + ! The recovered cohort (ie one with larger targets) + ! is newly created in DamageRecovery(), and + ! is inserted into the next position, following the + ! original and current (unrecovered) cohort. + ! we pass it back here in case the pointer is + ! needed for diagnostics + call DamageRecovery(currentSite,currentPatch,currentCohort,newly_recovered) + else + newly_recovered = .false. + end if + call currentCohort%prt%DailyPRT(phase=3) + ! Update the mass balance tracking for the daily nutrient uptake flux ! Then zero out the daily uptakes, they have been used - ! ----------------------------------------------------------------------------- - if(hlm_parteh_mode .eq. prt_cnp_flex_allom_hyp ) then + ! ----------------------------------------------------------------------------- + + call EffluxIntoLitterPools(currentSite, currentPatch, currentCohort, bc_in ) + if(element_pos(nitrogen_element)>0) then ! Mass balance for N uptake currentSite%mass_balance(element_pos(nitrogen_element))%net_root_uptake = & currentSite%mass_balance(element_pos(nitrogen_element))%net_root_uptake + & - (currentCohort%daily_nh4_uptake+currentCohort%daily_no3_uptake- & - currentCohort%daily_n_efflux)*currentCohort%n - + (currentCohort%daily_n_gain-currentCohort%daily_n_efflux)*currentCohort%n + end if + if(element_pos(phosphorus_element)>0) then ! Mass balance for P uptake currentSite%mass_balance(element_pos(phosphorus_element))%net_root_uptake = & currentSite%mass_balance(element_pos(phosphorus_element))%net_root_uptake + & - (currentCohort%daily_p_uptake-currentCohort%daily_p_efflux)*currentCohort%n - - ! mass balance for C efflux (if any) - currentSite%mass_balance(element_pos(carbon12_element))%net_root_uptake = & - currentSite%mass_balance(element_pos(carbon12_element))%net_root_uptake - & - currentCohort%daily_c_efflux*currentCohort%n - - ! size class index - iscpf = currentCohort%size_by_pft_class - - ! Diagnostics for uptake, by size and pft, [kgX/ha/day] - - io_si = currentSite%h_gid - - fates_hist%hvars(ih_nh4uptake_scpf)%r82d(io_si,iscpf) = & - fates_hist%hvars(ih_nh4uptake_scpf)%r82d(io_si,iscpf) + & - currentCohort%daily_nh4_uptake*currentCohort%n / & - m2_per_ha / sec_per_day - - fates_hist%hvars(ih_no3uptake_scpf)%r82d(io_si,iscpf) = & - fates_hist%hvars(ih_no3uptake_scpf)%r82d(io_si,iscpf) + & - currentCohort%daily_no3_uptake*currentCohort%n / & - m2_per_ha / sec_per_day - - fates_hist%hvars(ih_puptake_scpf)%r82d(io_si,iscpf) = & - fates_hist%hvars(ih_puptake_scpf)%r82d(io_si,iscpf) + & - currentCohort%daily_p_uptake*currentCohort%n / & - m2_per_ha / sec_per_day - - fates_hist%hvars(ih_nh4uptake_si)%r81d(io_si) = & - fates_hist%hvars(ih_nh4uptake_si)%r81d(io_si) + & - currentCohort%daily_nh4_uptake*currentCohort%n / & - m2_per_ha / sec_per_day - - fates_hist%hvars(ih_no3uptake_si)%r81d(io_si) = & - fates_hist%hvars(ih_no3uptake_si)%r81d(io_si) + & - currentCohort%daily_no3_uptake*currentCohort%n / & - m2_per_ha / sec_per_day - - fates_hist%hvars(ih_puptake_si)%r81d(io_si) = & - fates_hist%hvars(ih_puptake_si)%r81d(io_si) + & - currentCohort%daily_p_uptake*currentCohort%n / & - m2_per_ha / sec_per_day - - - ! Diagnostics on efflux, size and pft [kgX/ha/day] - currentSite%flux_diags(element_pos(nitrogen_element))%nutrient_efflux_scpf(iscpf) = & - currentSite%flux_diags(element_pos(nitrogen_element))%nutrient_efflux_scpf(iscpf) + & - currentCohort%daily_n_efflux*currentCohort%n - - currentSite%flux_diags(element_pos(phosphorus_element))%nutrient_efflux_scpf(iscpf) = & - currentSite%flux_diags(element_pos(phosphorus_element))%nutrient_efflux_scpf(iscpf) + & - currentCohort%daily_p_efflux*currentCohort%n - - currentSite%flux_diags(element_pos(carbon12_element))%nutrient_efflux_scpf(iscpf) = & - currentSite%flux_diags(element_pos(carbon12_element))%nutrient_efflux_scpf(iscpf) + & - currentCohort%daily_c_efflux*currentCohort%n - - ! Diagnostics on plant nutrient need - currentSite%flux_diags(element_pos(nitrogen_element))%nutrient_need_scpf(iscpf) = & - currentSite%flux_diags(element_pos(nitrogen_element))%nutrient_need_scpf(iscpf) + & - currentCohort%daily_n_need*currentCohort%n - - currentSite%flux_diags(element_pos(phosphorus_element))%nutrient_need_scpf(iscpf) = & - currentSite%flux_diags(element_pos(phosphorus_element))%nutrient_need_scpf(iscpf) + & - currentCohort%daily_p_need*currentCohort%n - + (currentCohort%daily_p_gain-currentCohort%daily_p_efflux)*currentCohort%n end if - + + ! mass balance for C efflux (if any) + currentSite%mass_balance(element_pos(carbon12_element))%net_root_uptake = & + currentSite%mass_balance(element_pos(carbon12_element))%net_root_uptake - & + currentCohort%daily_c_efflux*currentCohort%n + ! And simultaneously add the input fluxes to mass balance accounting site_cmass%gpp_acc = site_cmass%gpp_acc + & currentCohort%gpp_acc * currentCohort%n + site_cmass%aresp_acc = site_cmass%aresp_acc + & - currentCohort%resp_acc * currentCohort%n + (currentCohort%resp_acc+currentCohort%resp_excess) * currentCohort%n call currentCohort%prt%CheckMassConservation(ft,5) @@ -534,15 +638,15 @@ subroutine ed_integrate_state_variables(currentSite, bc_in, bc_out ) ! mass in the different leaf age classes. Following growth ! and turnover, these proportions won't change again. This ! routine is also called following fusion - call UpdateCohortBioPhysRates(currentCohort) + call currentCohort%UpdateCohortBioPhysRates() ! This cohort has grown, it is no longer "new" currentCohort%isnew = .false. ! Update the plant height (if it has grown) - call h_allom(currentCohort%dbh,ft,currentCohort%hite) + call h_allom(currentCohort%dbh,ft,currentCohort%height) - currentCohort%dhdt = (currentCohort%hite-hite_old)/hlm_freq_day + currentCohort%dhdt = (currentCohort%height-height_old)/hlm_freq_day currentCohort%ddbhdt = (currentCohort%dbh-dbh_old)/hlm_freq_day ! Carbon assimilate has been spent at this point @@ -566,23 +670,37 @@ subroutine ed_integrate_state_variables(currentSite, bc_in, bc_out ) currentCohort%coage = currentCohort%coage + hlm_freq_day if(currentCohort%coage < 0.0_r8)then write(fates_log(),*) 'negative cohort age?',currentCohort%coage + call endrun(msg=errMsg(sourcefile, __LINE__)) end if ! update cohort age class and age x pft class call coagetype_class_index(currentCohort%coage, currentCohort%pft, & currentCohort%coage_class,currentCohort%coage_by_pft_class) end if - - + currentCohort => currentCohort%taller - end do + end do - currentPatch => currentPatch%older + currentPatch => currentPatch%younger end do - - - ! When plants die, the water goes with them. This effects - ! the water balance. + + ! We keep a record of the L2FRs of plants + ! that are near the recruit size, for different + ! pfts and canopy layer. We use this mean to + ! set the L2FRs of newly recruited plants + + call UpdateRecruitL2FR(currentSite) + + ! Update history diagnostics related to Nutrients (if any) + ! ----------------------------------------------------------------------------- + select case(hlm_parteh_mode) + case (prt_cnp_flex_allom_hyp) + call fates_hist%update_history_nutrflux(currentSite) + end select + + ! When plants die, the water goes with them. This effects + + ! the water balance. if( hlm_use_planthydro == itrue ) then currentPatch => currentSite%youngest_patch @@ -601,27 +719,28 @@ subroutine ed_integrate_state_variables(currentSite, bc_in, bc_out ) ! With growth and mortality rates now calculated we can determine the seed rain ! fluxes. However, because this is potentially a cross-patch mixing model ! we will calculate this as a group - - call SeedIn(currentSite,bc_in) + + call SeedUpdate(currentSite) ! Calculate all other litter fluxes ! ----------------------------------------------------------------------------------- currentPatch => currentSite%youngest_patch do while(associated(currentPatch)) + + call GenerateDamageAndLitterFluxes( currentSite, currentPatch, bc_in) call PreDisturbanceLitterFluxes( currentSite, currentPatch, bc_in) - call PreDisturbanceIntegrateLitter(currentPatch ) currentPatch => currentPatch%older enddo - ! Before we start messing with the patch areas, and before we start removing - ! trees, this is a good time to pass fragmentation litter fluxes and - ! plant-to-soil fluxes (such as efflux and fixation fluxes) + ! RGK: This call is unecessary for CLM coupling. I believe we + ! can remove it completely if/when this call is added in ELM to + ! subroutine UpdateLitterFluxes(this,bounds_clump) in elmfates_interfaceMod.F90 call FluxIntoLitterPools(currentsite, bc_in, bc_out) @@ -635,6 +754,7 @@ subroutine ed_integrate_state_variables(currentSite, bc_in, bc_out ) currentCohort => currentPatch%shortest do while(associated(currentCohort)) currentCohort%n = max(0._r8,currentCohort%n + currentCohort%dndt * hlm_freq_day ) + currentCohort%sym_nfix_daily = 0._r8 currentCohort => currentCohort%taller enddo currentPatch => currentPatch%older @@ -663,7 +783,7 @@ subroutine ed_update_site( currentSite, bc_in, bc_out ) type(bc_out_type) , intent(inout) :: bc_out ! ! !LOCAL VARIABLES: - type (ed_patch_type) , pointer :: currentPatch + type (fates_patch_type) , pointer :: currentPatch !----------------------------------------------------------------------- if(hlm_use_sp.eq.ifalse)then call canopy_spread(currentSite) @@ -677,6 +797,9 @@ subroutine ed_update_site( currentSite, bc_in, bc_out ) call TotalBalanceCheck(currentSite,final_check_id) + ! Update recruit L2FRs based on new canopy position + call SetRecruitL2FR(currentSite) + currentSite%area_by_age(:) = 0._r8 currentPatch => currentSite%oldest_patch @@ -759,8 +882,8 @@ subroutine TotalBalanceCheck (currentSite, call_index ) ! Also, the carbon pools are per site/gridcell, so that ! we can account for the changing areas of patches. - type(ed_patch_type) , pointer :: currentPatch - type(ed_cohort_type) , pointer :: currentCohort + type(fates_patch_type) , pointer :: currentPatch + type(fates_cohort_type) , pointer :: currentCohort type(litter_type), pointer :: litt logical, parameter :: print_cohorts = .true. ! Set to true if you want ! to print cohort data @@ -845,7 +968,6 @@ subroutine TotalBalanceCheck (currentSite, call_index ) write(fates_log(),*) 'BG CWD (by layer): ', sum(litt%bg_cwd,dim=1) write(fates_log(),*) 'leaf litter:',sum(litt%leaf_fines) write(fates_log(),*) 'root litter (by layer): ',sum(litt%root_fines,dim=1) - write(fates_log(),*) 'dist mode: ',currentPatch%disturbance_mode write(fates_log(),*) 'anthro_disturbance_label: ',currentPatch%anthro_disturbance_label write(fates_log(),*) 'use_this_pft: ', currentSite%use_this_pft(:) if(print_cohorts)then @@ -863,14 +985,15 @@ subroutine TotalBalanceCheck (currentSite, call_index ) write(fates_log(),*) 'leaf: ',leaf_m,' structure: ',struct_m,' store: ',store_m write(fates_log(),*) 'fineroot: ',fnrt_m,' repro: ',repro_m,' sapwood: ',sapw_m write(fates_log(),*) 'num plant: ',currentCohort%n - write(fates_log(),*) 'resp m def: ',currentCohort%resp_m_def*currentCohort%n + write(fates_log(),*) 'resp excess: ',currentCohort%resp_excess*currentCohort%n if(element_list(el).eq.nitrogen_element) then write(fates_log(),*) 'NH4 uptake: ',currentCohort%daily_nh4_uptake*currentCohort%n write(fates_log(),*) 'NO3 uptake: ',currentCohort%daily_no3_uptake*currentCohort%n write(fates_log(),*) 'N efflux: ',currentCohort%daily_n_efflux*currentCohort%n + write(fates_log(),*) 'N fixation: ',currentCohort%sym_nfix_daily*currentCohort%n elseif(element_list(el).eq.phosphorus_element) then - write(fates_log(),*) 'P uptake: ',currentCohort%daily_p_uptake*currentCohort%n + write(fates_log(),*) 'P uptake: ',currentCohort%daily_p_gain*currentCohort%n write(fates_log(),*) 'P efflux: ',currentCohort%daily_p_efflux*currentCohort%n elseif(element_list(el).eq.carbon12_element) then write(fates_log(),*) 'C efflux: ',currentCohort%daily_c_efflux*currentCohort%n @@ -914,8 +1037,8 @@ subroutine bypass_dynamics(currentSite) type(ed_site_type) , intent(inout), target :: currentSite ! Locals - type(ed_patch_type), pointer :: currentPatch - type(ed_cohort_type), pointer :: currentCohort + type(fates_patch_type), pointer :: currentPatch + type(fates_cohort_type), pointer :: currentCohort currentPatch => currentSite%youngest_patch do while(associated(currentPatch)) @@ -943,6 +1066,7 @@ subroutine bypass_dynamics(currentSite) currentCohort%frmort = 0.0_r8 currentCohort%smort = 0.0_r8 currentCohort%asmort = 0.0_r8 + currentCohort%dgmort = 0.0_r8 currentCohort%dndt = 0.0_r8 currentCohort%dhdt = 0.0_r8 diff --git a/main/EDParamsMod.F90 b/main/EDParamsMod.F90 index 64dfab6c0f..413b2fadb7 100644 --- a/main/EDParamsMod.F90 +++ b/main/EDParamsMod.F90 @@ -9,6 +9,7 @@ module EDParamsMod use FatesParametersInterface, only : param_string_length use FatesGlobals , only : fates_log use FatesGlobals , only : endrun => fates_endrun + use FatesConstantsMod, only : fates_unset_r8 ! CIME Globals use shr_log_mod , only : errMsg => shr_log_errMsg @@ -23,51 +24,112 @@ module EDParamsMod real(r8),protected, public :: vai_top_bin_width ! width in VAI units of uppermost leaf+stem ! layer scattering element in each canopy layer [m2/m2] - ! (NOT YET IMPLEMENTED) real(r8),protected, public :: vai_width_increase_factor ! factor by which each leaf+stem scattering element ! increases in VAI width (1 = uniform spacing) - ! (NOT YET IMPLEMENTED) real(r8),protected, public :: photo_temp_acclim_timescale ! Length of the window for the exponential moving average (ema) - ! of vegetation temperature used in photosynthesis - ! temperature acclimation (NOT YET IMPLEMENTED) - - integer,protected, public :: maintresp_model ! switch for choosing between leaf maintenance - ! respiration model. 1=Ryan (1991) (NOT YET IMPLEMENTED) + ! of vegetation temperature used in photosynthesis and respiration + ! temperature acclimation [days] + real(r8),protected, public :: photo_temp_acclim_thome_time ! Length of the window for the long-term exponential moving average (ema) + ! of vegetation temperature used in photosynthesis + ! T_home term in Kumarathunge parameterization [years] + integer,protected, public :: maintresp_leaf_model ! switch for choosing between leaf maintenance + ! respiration model. 1=Ryan (1991), 2=Atkin et al (2017) + 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 :: photo_tempsens_model ! switch for choosing the model that defines the temperature ! sensitivity of photosynthetic parameters (vcmax, jmax). - ! 1=non-acclimating (NOT YET IMPLEMENTED) + ! 1=non-acclimating, 2=Kumarathunge et al., 2019 + + integer,protected, public :: radiation_model ! Switch betrween Norman (1) and Two-stream (2) radiation models real(r8),protected, public :: fates_mortality_disturbance_fraction ! the fraction of canopy mortality that results in disturbance - real(r8),protected, public :: ED_val_comp_excln - real(r8),protected, public :: ED_val_vai_top_bin_width - real(r8),protected, public :: ED_val_vai_width_increase_factor - real(r8),protected, public :: ED_val_init_litter - real(r8),protected, public :: ED_val_nignitions - real(r8),protected, public :: ED_val_understorey_death - real(r8),protected, public :: ED_val_cwd_fcel - real(r8),protected, public :: ED_val_cwd_flig - real(r8),protected, public :: ED_val_base_mr_20 - real(r8),protected, public :: ED_val_phen_drought_threshold - real(r8),protected, public :: ED_val_phen_doff_time - real(r8),protected, public :: ED_val_phen_a - real(r8),protected, public :: ED_val_phen_b - real(r8),protected, public :: ED_val_phen_c - real(r8),protected, public :: ED_val_phen_chiltemp - real(r8),protected, public :: ED_val_phen_mindayson - real(r8),protected, public :: ED_val_phen_ncolddayslim - real(r8),protected, public :: ED_val_phen_coldtemp - real(r8),protected, public :: ED_val_cohort_size_fusion_tol - real(r8),protected, public :: ED_val_cohort_age_fusion_tol - 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 + real(r8),protected, public :: ED_val_comp_excln ! weighting factor for canopy layer exclusion and promotion + real(r8),protected, public :: ED_val_vai_top_bin_width ! width in VAI units of uppermost leaf+stem layer scattering element + real(r8),protected, public :: ED_val_vai_width_increase_factor ! factor by which each leaf+stem scattering element increases in VAI width + real(r8),protected, public :: ED_val_nignitions ! number of annual ignitions per square km + real(r8),protected, public :: ED_val_understorey_death ! fraction of plants in understorey cohort impacted by overstorey tree-fall + real(r8),protected, public :: ED_val_cwd_fcel ! Cellulose fraction for CWD + real(r8),protected, public :: ED_val_cwd_flig ! Lignin fraction of coarse woody debris + real(r8),protected, public :: maintresp_nonleaf_baserate ! Base maintenance respiration rate for plant tissues + real(r8),protected, public :: ED_val_phen_a ! GDD accumulation function, intercept parameter: gdd_thesh = a + b exp(c*ncd) + real(r8),protected, public :: ED_val_phen_b ! GDD accumulation function, multiplier parameter: gdd_thesh = a + b exp(c*ncd) + real(r8),protected, public :: ED_val_phen_c ! GDD accumulation function, exponent parameter: gdd_thesh = a + b exp(c*ncd) + real(r8),protected, public :: ED_val_phen_chiltemp ! chilling day counting threshold for vegetation + real(r8),protected, public :: ED_val_phen_mindayson ! day threshold compared against days since leaves became on-allometry + real(r8),protected, public :: ED_val_phen_ncolddayslim ! day threshold exceedance for temperature leaf-drop + real(r8),protected, public :: ED_val_phen_coldtemp ! vegetation temperature exceedance that flags a cold-day for leaf-drop + real(r8),protected, public :: ED_val_cohort_size_fusion_tol ! minimum fraction in difference in dbh between cohorts + real(r8),protected, public :: ED_val_cohort_age_fusion_tol ! minimum fraction in differece in cohort age between cohorts + 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 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 + character(len=param_string_length),parameter :: fates_name_active_crown_fire = "fates_fire_active_crown_fire" real(r8), protected, public :: cg_strikes ! fraction of cloud to ground lightning strikes (0-1) character(len=param_string_length),parameter :: fates_name_cg_strikes="fates_fire_cg_strikes" ! empirical curvature parameters for ac, aj photosynthesis co-limitation, c3 and c4 plants respectively - real(r8),protected,public :: theta_cj_c3 - real(r8),protected,public :: theta_cj_c4 + real(r8),protected,public :: theta_cj_c3 ! Empirical curvature parameter for ac, aj photosynthesis co-limitation in c3 plants + real(r8),protected,public :: theta_cj_c4 ! Empirical curvature parameter for ac, aj photosynthesis co-limitation in c4 plants + + ! Global identifier of how nutrients interact with the host land model + ! either they are fully coupled, or they generate uptake rates synthetically + ! in prescribed mode. In the latter, there is both NO mass removed from the HLM's soil + ! BGC N and P pools, and there is also none removed. + + integer, public :: n_uptake_mode + integer, public :: p_uptake_mode + + integer, parameter, public :: nclmax = 2 ! Maximum number of canopy layers + + ! parameters that govern the VAI (LAI+SAI) bins used in radiative transfer code + integer, parameter, public :: nlevleaf = 30 ! number of leaf+stem layers in each canopy layer + + real(r8), public :: dinc_vai(nlevleaf) = fates_unset_r8 ! VAI bin widths array + real(r8), public :: dlower_vai(nlevleaf) = fates_unset_r8 ! lower edges of VAI bins + + ! TODO: we use this cp_maxSWb only because we have a static array q(size=2) of + ! land-ice abledo for vis and nir. This should be a parameter, which would + ! get us on track to start using multi-spectral or hyper-spectral (RGK 02-2017) + + integer, parameter, public :: maxSWb = 2 ! maximum number of broad-bands in the + ! shortwave spectrum cp_numSWb <= cp_maxSWb + ! this is just for scratch-array purposes + ! if cp_numSWb is larger than this value + ! simply bump this number up as needed + +integer, parameter, public :: ivis = 1 ! This is the array index for short-wave + ! radiation in the visible spectrum, as expected + ! in boundary condition files and parameter + ! files. This will be compared with + ! the HLM's expectation in FatesInterfaceMod +integer, parameter, public :: inir = 2 ! This is the array index for short-wave + ! radiation in the near-infrared spectrum, as expected + ! in boundary condition files and parameter + ! files. This will be compared with + ! the HLM's expectation in FatesInterfaceMod + +integer, parameter, public :: ipar = ivis ! The photosynthetically active band + ! can be approximated to be equal to the visible band + + + +integer, parameter, public :: maxpft = 16 ! maximum number of PFTs allowed real(r8),protected,public :: q10_mr ! Q10 for respiration rate (for soil fragmenation and plant respiration) (unitless) real(r8),protected,public :: q10_froz ! Q10 for frozen-soil respiration rates (for soil fragmentation) (unitless) @@ -75,7 +137,7 @@ module EDParamsMod ! Unassociated pft dimensioned free parameter that developers can use for testing arbitrary new hypotheses ! (THIS PARAMETER IS UNUSED, FEEL FREE TO USE IT FOR WHATEVER PURPOSE YOU LIKE. WE CAN ! HELP MIGRATE YOUR USAGE OF THE PARMETER TO A PERMANENT HOME LATER) - real(r8),protected,public :: dev_arbitrary + real(r8),protected,public :: dev_arbitrary ! Unassociated free parameter that developers can use for testing arbitrary new hypotheses character(len=param_string_length),parameter,public :: name_dev_arbitrary = "fates_dev_arbitrary" ! parameters whose size is defined in the parameter file @@ -83,43 +145,37 @@ module EDParamsMod real(r8),protected,allocatable,public :: ED_val_history_ageclass_bin_edges(:) real(r8),protected,allocatable,public :: ED_val_history_height_bin_edges(:) real(r8),protected,allocatable,public :: ED_val_history_coageclass_bin_edges(:) - + real(r8),protected,allocatable,public :: ED_val_history_damage_bin_edges(:) + ! Switch that defines the current pressure-volume and pressure-conductivity model ! to be used at each node (compartment/organ) ! 1 = Christofferson et al. 2016 (TFS), 2 = Van Genuchten 1980 - integer, protected,allocatable,public :: hydr_htftype_node(:) - - ! Switch that defines which hydraulic solver to use - ! 1 = Taylor solution that solves plant fluxes with 1 layer - ! sequentially placing solution on top of previous layer solves - ! 2 = Newton-Raphson solution that solves all fluxes in a plant and - ! the soil simultaneously, 2D: soil x (root + shell) - ! 3 = Picard solution that solves all fluxes in a plant and - ! the soil simultaneously, 2D: soil x (root + shell) - - integer, parameter, public :: hydr_solver_type = 1 ! 1 = hydr_solver_1DTaylor - 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 :: 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" + 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" + character(len=param_string_length),parameter,public :: name_photo_tempsens_model = "fates_leaf_photo_tempsens_model" + character(len=param_string_length),parameter,public :: name_maintresp_model = "fates_maintresp_leaf_model" + character(len=param_string_length),parameter,public :: name_radiation_model = "fates_rad_model" + character(len=param_string_length),parameter,public :: ED_name_hydr_htftype_node = "fates_hydro_htftype_node" character(len=param_string_length),parameter,public :: ED_name_mort_disturb_frac = "fates_mort_disturb_frac" character(len=param_string_length),parameter,public :: ED_name_comp_excln = "fates_comp_excln" 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_init_litter = "fates_init_litter" character(len=param_string_length),parameter,public :: ED_name_nignitions = "fates_fire_nignitions" character(len=param_string_length),parameter,public :: ED_name_understorey_death = "fates_mort_understorey_death" - character(len=param_string_length),parameter,public :: ED_name_cwd_fcel= "fates_cwd_fcel" - character(len=param_string_length),parameter,public :: ED_name_cwd_flig= "fates_cwd_flig" - character(len=param_string_length),parameter,public :: ED_name_base_mr_20= "fates_base_mr_20" - character(len=param_string_length),parameter,public :: ED_name_phen_drought_threshold= "fates_phen_drought_threshold" - character(len=param_string_length),parameter,public :: ED_name_phen_doff_time= "fates_phen_doff_time" - character(len=param_string_length),parameter,public :: ED_name_phen_a= "fates_phen_a" - character(len=param_string_length),parameter,public :: ED_name_phen_b= "fates_phen_b" - character(len=param_string_length),parameter,public :: ED_name_phen_c= "fates_phen_c" - character(len=param_string_length),parameter,public :: ED_name_phen_chiltemp= "fates_phen_chiltemp" - character(len=param_string_length),parameter,public :: ED_name_phen_mindayson= "fates_phen_mindayson" + character(len=param_string_length),parameter,public :: ED_name_cwd_fcel= "fates_frag_cwd_fcel" + character(len=param_string_length),parameter,public :: ED_name_cwd_flig= "fates_frag_cwd_flig" + character(len=param_string_length),parameter,public :: fates_name_maintresp_nonleaf_baserate= "fates_maintresp_nonleaf_baserate" + character(len=param_string_length),parameter,public :: ED_name_phen_a= "fates_phen_gddthresh_a" + character(len=param_string_length),parameter,public :: ED_name_phen_b= "fates_phen_gddthresh_b" + character(len=param_string_length),parameter,public :: ED_name_phen_c= "fates_phen_gddthresh_c" + character(len=param_string_length),parameter,public :: ED_name_phen_chiltemp= "fates_phen_chilltemp" + character(len=param_string_length),parameter,public :: ED_name_phen_mindayson= "fates_phen_mindayson" character(len=param_string_length),parameter,public :: ED_name_phen_ncolddayslim= "fates_phen_ncolddayslim" character(len=param_string_length),parameter,public :: ED_name_phen_coldtemp= "fates_phen_coldtemp" character(len=param_string_length),parameter,public :: ED_name_cohort_size_fusion_tol= "fates_cohort_size_fusion_tol" @@ -127,9 +183,10 @@ 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" + character(len=param_string_length),parameter,public :: name_theta_cj_c3 = "fates_leaf_theta_cj_c3" + character(len=param_string_length),parameter,public :: name_theta_cj_c4 = "fates_leaf_theta_cj_c4" character(len=param_string_length),parameter :: fates_name_q10_mr="fates_q10_mr" character(len=param_string_length),parameter :: fates_name_q10_froz="fates_q10_froz" @@ -139,67 +196,118 @@ module EDParamsMod character(len=param_string_length),parameter,public :: ED_name_history_ageclass_bin_edges= "fates_history_ageclass_bin_edges" character(len=param_string_length),parameter,public :: ED_name_history_height_bin_edges= "fates_history_height_bin_edges" character(len=param_string_length),parameter,public :: ED_name_history_coageclass_bin_edges = "fates_history_coageclass_bin_edges" + character(len=param_string_length),parameter,public :: ED_name_history_damage_bin_edges = "fates_history_damage_bin_edges" ! Hydraulics Control Parameters (ONLY RELEVANT WHEN USE_FATES_HYDR = TRUE) ! ---------------------------------------------------------------------------------------------- real(r8),protected,public :: hydr_kmax_rsurf1 ! maximum conducitivity for unit root surface ! soil to root direction (kg water/m2 root area/Mpa/s) - character(len=param_string_length),parameter,public :: hydr_name_kmax_rsurf1 = "fates_hydr_kmax_rsurf1" + character(len=param_string_length),parameter,public :: hydr_name_kmax_rsurf1 = "fates_hydro_kmax_rsurf1" real(r8),protected,public :: hydr_kmax_rsurf2 ! maximum conducitivity for unit root surface ! root to soil direciton (kg water/m2 root area/Mpa/s) - character(len=param_string_length),parameter,public :: hydr_name_kmax_rsurf2 = "fates_hydr_kmax_rsurf2" + character(len=param_string_length),parameter,public :: hydr_name_kmax_rsurf2 = "fates_hydro_kmax_rsurf2" real(r8),protected,public :: hydr_psi0 ! sapwood water potential at saturation (MPa) - character(len=param_string_length),parameter,public :: hydr_name_psi0 = "fates_hydr_psi0" + character(len=param_string_length),parameter,public :: hydr_name_psi0 = "fates_hydro_psi0" real(r8),protected,public :: hydr_psicap ! sapwood water potential at which capillary reserves exhausted (MPa) - character(len=param_string_length),parameter,public :: hydr_name_psicap = "fates_hydr_psicap" + character(len=param_string_length),parameter,public :: hydr_name_psicap = "fates_hydro_psicap" + + ! Switch that defines which hydraulic solver to use + ! 1 = Taylor solution that solves plant fluxes with 1 layer + ! sequentially placing solution on top of previous layer solves + ! 2 = Picard solution that solves all fluxes in a plant and + ! the soil simultaneously, 2D: soil x (root + shell) + ! 3 = Newton-Raphson (Deprecated) solution that solves all fluxes in a plant and + ! the soil simultaneously, 2D: soil x (root + shell) + + integer,protected,public :: hydr_solver ! switch designating hydraulics numerical solver + character(len=param_string_length),parameter,public :: hydr_name_solver = "fates_hydro_solver" + !Soil BGC parameters, mostly used for testing FATES when not coupled to the dynamics bgc hlm ! ---------------------------------------------------------------------------------------------- real(r8),protected,public :: bgc_soil_salinity ! site-level soil salinity for FATES when not coupled to dynamic soil BGC of salinity character(len=param_string_length),parameter,public :: bgc_name_soil_salinity= "fates_soil_salinity" + + ! Switch designating whether to use net or gross assimilation in the stomata model + integer, protected, public :: stomatal_assim_model + character(len=param_string_length), parameter, public :: stomatal_assim_name = "fates_leaf_stomatal_assim_model" + + ! Integer code that options how damage events are structured + integer, protected, public :: damage_event_code + character(len=param_string_length), parameter, public :: damage_name_event_code = "fates_damage_event_code" + + integer,protected,public :: damage_canopy_layer_code ! Code that changes whether damage affects canopy trees (1), understory trees (2) + character(len=param_string_length),parameter,public :: damage_name_canopy_layer_code = "fates_damage_canopy_layer_code" + + ! Maximum allowable primary and secondary patches + ! These values are USED FOR ALLOCATIONS IN BOTH FATES AND CLM/ELM!!!! + ! The number of patches specified in the parameter file may be over-written. + ! For instance, in SP mode, we want the same number of primary patches as the number of PFTs + ! in the fates parameter file, and zero secondary. + + integer, public :: maxpatch_primary + character(len=param_string_length), parameter, public :: maxpatch_primary_name = "fates_maxpatch_primary" + + integer, public :: maxpatch_secondary + character(len=param_string_length), parameter, public :: maxpatch_secondary_name = "fates_maxpatch_secondary" + + integer, public :: maxpatch_total + + ! Maximum allowable cohorts per patch + integer, protected, public :: max_cohort_per_patch + character(len=param_string_length), parameter, public :: maxcohort_name = "fates_maxcohort" + + ! Logging Control Parameters (ONLY RELEVANT WHEN USE_FATES_LOGGING = TRUE) ! ---------------------------------------------------------------------------------------------- real(r8),protected,public :: logging_dbhmin ! Minimum dbh at which logging is applied (cm) ! Typically associated with harvesting - character(len=param_string_length),parameter,public :: logging_name_dbhmin = "fates_logging_dbhmin" + character(len=param_string_length),parameter,public :: logging_name_dbhmin = "fates_landuse_logging_dbhmin" real(r8),protected,public :: logging_dbhmax ! Maximum dbh at which logging is applied (cm) ! Typically associated with fire suppression - character(len=param_string_length),parameter,public :: logging_name_dbhmax = "fates_logging_dbhmax" + character(len=param_string_length),parameter,public :: logging_name_dbhmax = "fates_landuse_logging_dbhmax" real(r8),protected,public :: logging_collateral_frac ! Ratio of collateral mortality to direct logging mortality - character(len=param_string_length),parameter,public :: logging_name_collateral_frac = "fates_logging_collateral_frac" + character(len=param_string_length),parameter,public :: logging_name_collateral_frac = "fates_landuse_logging_collateral_frac" real(r8),protected,public :: logging_coll_under_frac ! Fraction of understory plants that die when logging disturbance ! is generated - character(len=param_string_length),parameter,public :: logging_name_coll_under_frac = "fates_logging_coll_under_frac" + character(len=param_string_length),parameter,public :: logging_name_coll_under_frac = "fates_landuse_logging_coll_under_frac" real(r8),protected,public :: logging_direct_frac ! Fraction of stems logged per event - character(len=param_string_length),parameter,public :: logging_name_direct_frac = "fates_logging_direct_frac" + character(len=param_string_length),parameter,public :: logging_name_direct_frac = "fates_landuse_logging_direct_frac" real(r8),protected,public :: logging_mechanical_frac ! Fraction of stems logged per event - character(len=param_string_length),parameter,public :: logging_name_mechanical_frac = "fates_logging_mechanical_frac" + character(len=param_string_length),parameter,public :: logging_name_mechanical_frac = "fates_landuse_logging_mechanical_frac" real(r8),protected,public :: logging_event_code ! Code that options how logging events are structured - character(len=param_string_length),parameter,public :: logging_name_event_code = "fates_logging_event_code" + character(len=param_string_length),parameter,public :: logging_name_event_code = "fates_landuse_logging_event_code" real(r8),protected,public :: logging_dbhmax_infra ! "Tree diameter, above which infrastructure from logging does not impact damage or mortality. - character(len=param_string_length),parameter,public :: logging_name_dbhmax_infra = "fates_logging_dbhmax_infra" + character(len=param_string_length),parameter,public :: logging_name_dbhmax_infra = "fates_landuse_logging_dbhmax_infra" real(r8),protected,public :: logging_export_frac ! "fraction of trunk product being shipped offsite, the ! leftovers will be left onsite as large CWD - character(len=param_string_length),parameter,public :: logging_name_export_frac ="fates_logging_export_frac" + character(len=param_string_length),parameter,public :: logging_name_export_frac ="fates_landuse_logging_export_frac" + + real(r8),protected,public :: pprodharv10_forest_mean ! "mean harvest mortality proportion of deadstem to 10-yr + ! product pool (pprodharv10) of all woody PFT types + character(len=param_string_length),parameter,public :: logging_name_pprodharv10="fates_landuse_pprodharv10_forest_mean" real(r8),protected,public :: eca_plant_escalar ! scaling factor for plant fine root biomass to ! calculate nutrient carrier enzyme abundance (ECA) - character(len=param_string_length),parameter,public :: eca_name_plant_escalar = "fates_eca_plant_escalar" + + + + character(len=param_string_length),parameter,public :: eca_name_plant_escalar = "fates_cnp_eca_plant_escalar" public :: FatesParamsInit public :: FatesRegisterParams @@ -220,20 +328,23 @@ 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_temp_acclim_thome_time = nan photo_tempsens_model = -9 - maintresp_model = -9 + maintresp_leaf_model = -9 + radiation_model = -9 fates_mortality_disturbance_fraction = nan ED_val_comp_excln = nan ED_val_vai_top_bin_width = nan ED_val_vai_width_increase_factor = nan - ED_val_init_litter = nan ED_val_nignitions = nan ED_val_understorey_death = nan ED_val_cwd_fcel = nan ED_val_cwd_flig = nan - ED_val_base_mr_20 = nan - ED_val_phen_drought_threshold = nan - ED_val_phen_doff_time = nan + maintresp_nonleaf_baserate = nan ED_val_phen_a = nan ED_val_phen_b = nan ED_val_phen_c = nan @@ -246,10 +357,16 @@ subroutine FatesParamsInit() ED_val_patch_fusion_tol = nan ED_val_canopy_closure_thresh = nan stomatal_model = -9 + regeneration_model = -9 + stomatal_assim_model = -9 + maxpatch_primary = -9 + maxpatch_secondary = -9 + max_cohort_per_patch = -9 hydr_kmax_rsurf1 = nan hydr_kmax_rsurf2 = nan hydr_psi0 = nan hydr_psicap = nan + hydr_solver = -9 bgc_soil_salinity = nan logging_dbhmin = nan logging_dbhmax = nan @@ -259,12 +376,15 @@ subroutine FatesParamsInit() logging_event_code = nan logging_dbhmax_infra = nan logging_export_frac = nan + pprodharv10_forest_mean = nan eca_plant_escalar = nan q10_mr = nan q10_froz = nan theta_cj_c3 = nan theta_cj_c4 = nan dev_arbitrary = nan + damage_event_code = -9 + damage_canopy_layer_code = -9 end subroutine FatesParamsInit !----------------------------------------------------------------------- @@ -276,7 +396,7 @@ subroutine FatesRegisterParams(fates_params) use FatesParametersInterface, only : fates_parameters_type, dimension_name_scalar, dimension_shape_1d use FatesParametersInterface, only : dimension_name_history_size_bins, dimension_name_history_age_bins use FatesParametersInterface, only : dimension_name_history_height_bins, dimension_name_hydr_organs - use FatesParametersInterface, only : dimension_name_history_coage_bins + use FatesParametersInterface, only : dimension_name_history_coage_bins, dimension_name_history_damage_bins use FatesParametersInterface, only : dimension_shape_scalar @@ -290,15 +410,34 @@ subroutine FatesRegisterParams(fates_params) character(len=param_string_length), parameter :: dim_names_height(1) = (/dimension_name_history_height_bins/) character(len=param_string_length), parameter :: dim_names_coageclass(1) = (/dimension_name_history_coage_bins/) character(len=param_string_length), parameter :: dim_names_hydro_organs(1) = (/dimension_name_hydr_organs/) - + character(len=param_string_length), parameter :: dim_names_damageclass(1)= (/dimension_name_history_damage_bins/) + call FatesParamsInit() 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=ED_name_photo_temp_acclim_thome_time, 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) + call fates_params%RegisterParameter(name=name_radiation_model,dimension_shape=dimension_shape_scalar, & + dimension_names=dim_names_scalar) + call fates_params%RegisterParameter(name=name_maintresp_model,dimension_shape=dimension_shape_scalar, & dimension_names=dim_names_scalar) @@ -320,9 +459,6 @@ subroutine FatesRegisterParams(fates_params) call fates_params%RegisterParameter(name=ED_name_vai_width_increase_factor, dimension_shape=dimension_shape_scalar, & dimension_names=dim_names_scalar) - call fates_params%RegisterParameter(name=ED_name_init_litter, dimension_shape=dimension_shape_scalar, & - dimension_names=dim_names_scalar) - call fates_params%RegisterParameter(name=ED_name_nignitions, dimension_shape=dimension_shape_scalar, & dimension_names=dim_names_scalar) @@ -335,13 +471,7 @@ subroutine FatesRegisterParams(fates_params) call fates_params%RegisterParameter(name=ED_name_cwd_flig, dimension_shape=dimension_shape_scalar, & dimension_names=dim_names_scalar) - call fates_params%RegisterParameter(name=ED_name_base_mr_20, dimension_shape=dimension_shape_scalar, & - dimension_names=dim_names_scalar) - - call fates_params%RegisterParameter(name=ED_name_phen_drought_threshold, dimension_shape=dimension_shape_scalar, & - dimension_names=dim_names_scalar) - - call fates_params%RegisterParameter(name=ED_name_phen_doff_time, dimension_shape=dimension_shape_scalar, & + call fates_params%RegisterParameter(name=fates_name_maintresp_nonleaf_baserate, dimension_shape=dimension_shape_scalar, & dimension_names=dim_names_scalar) call fates_params%RegisterParameter(name=ED_name_phen_a, dimension_shape=dimension_shape_scalar, & @@ -380,6 +510,24 @@ 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=stomatal_assim_name, dimension_shape=dimension_shape_scalar, & + dimension_names=dim_names_scalar) + + call fates_params%RegisterParameter(name=maxpatch_primary_name, dimension_shape=dimension_shape_scalar, & + dimension_names=dim_names_scalar) + + call fates_params%RegisterParameter(name=maxpatch_secondary_name, dimension_shape=dimension_shape_scalar, & + dimension_names=dim_names_scalar) + + call fates_params%RegisterParameter(name=maxcohort_name, dimension_shape=dimension_shape_scalar, & + dimension_names=dim_names_scalar) + + call fates_params%RegisterParameter(name=hydr_name_solver, 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) @@ -422,6 +570,9 @@ subroutine FatesRegisterParams(fates_params) call fates_params%RegisterParameter(name=logging_name_export_frac, dimension_shape=dimension_shape_scalar, & dimension_names=dim_names_scalar) + call fates_params%RegisterParameter(name=logging_name_pprodharv10, dimension_shape=dimension_shape_scalar, & + dimension_names=dim_names_scalar) + call fates_params%RegisterParameter(name=eca_name_plant_escalar, dimension_shape=dimension_shape_scalar, & dimension_names=dim_names_scalar) @@ -433,6 +584,12 @@ subroutine FatesRegisterParams(fates_params) call fates_params%RegisterParameter(name=name_dev_arbitrary, dimension_shape=dimension_shape_scalar, & dimension_names=dim_names_scalar) + + call fates_params%RegisterParameter(name=damage_name_event_code, dimension_shape=dimension_shape_scalar, & + dimension_names=dim_names_scalar) + + call fates_params%RegisterParameter(name=damage_name_canopy_layer_code, dimension_shape=dimension_shape_scalar, & + dimension_names=dim_names_scalar) ! non-scalar parameters @@ -454,6 +611,8 @@ subroutine FatesRegisterParams(fates_params) call fates_params%RegisterParameter(name=ED_name_history_coageclass_bin_edges, dimension_shape=dimension_shape_1d, & dimension_names=dim_names_coageclass) + call fates_params%RegisterParameter(name=ED_name_history_damage_bin_edges, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names_damageclass) end subroutine FatesRegisterParams @@ -470,167 +629,217 @@ subroutine FatesReceiveParams(fates_params) real(r8) :: tmpreal ! local real variable for changing type on read real(r8), allocatable :: hydr_htftype_real(:) - call fates_params%RetreiveParameter(name=ED_name_photo_temp_acclim_timescale, & + call fates_params%RetrieveParameter(name=ED_name_photo_temp_acclim_timescale, & data=photo_temp_acclim_timescale) - call fates_params%RetreiveParameter(name=name_photo_tempsens_model, & + call fates_params%RetrieveParameter(name=ED_name_sdlng_emerg_h2o_timescale, & + data=sdlng_emerg_h2o_timescale) + + call fates_params%RetrieveParameter(name=ED_name_sdlng_mort_par_timescale, & + data=sdlng_mort_par_timescale) + + call fates_params%RetrieveParameter(name=ED_name_sdlng_mdd_timescale, & + data=sdlng_mdd_timescale) + + call fates_params%RetrieveParameter(name=ED_name_sdlng2sap_par_timescale, & + data=sdlng2sap_par_timescale) + + call fates_params%RetrieveParameter(name=ED_name_photo_temp_acclim_thome_time, & + data=photo_temp_acclim_thome_time) + + call fates_params%RetrieveParameter(name=name_photo_tempsens_model, & data=tmpreal) photo_tempsens_model = nint(tmpreal) - call fates_params%RetreiveParameter(name=name_maintresp_model, & + call fates_params%RetrieveParameter(name=name_radiation_model, & + data=tmpreal) + radiation_model = nint(tmpreal) + + call fates_params%RetrieveParameter(name=name_maintresp_model, & data=tmpreal) - maintresp_model = nint(tmpreal) + maintresp_leaf_model = nint(tmpreal) - call fates_params%RetreiveParameter(name=ED_name_mort_disturb_frac, & + call fates_params%RetrieveParameter(name=ED_name_mort_disturb_frac, & data=fates_mortality_disturbance_fraction) - call fates_params%RetreiveParameter(name=ED_name_comp_excln, & + call fates_params%RetrieveParameter(name=ED_name_comp_excln, & data=ED_val_comp_excln) - call fates_params%RetreiveParameter(name=ED_name_vai_top_bin_width, & + call fates_params%RetrieveParameter(name=ED_name_vai_top_bin_width, & data=ED_val_vai_top_bin_width) - call fates_params%RetreiveParameter(name=ED_name_vai_width_increase_factor, & + call fates_params%RetrieveParameter(name=ED_name_vai_width_increase_factor, & data=ED_val_vai_width_increase_factor) - call fates_params%RetreiveParameter(name=ED_name_init_litter, & - data=ED_val_init_litter) - - call fates_params%RetreiveParameter(name=ED_name_nignitions, & + call fates_params%RetrieveParameter(name=ED_name_nignitions, & data=ED_val_nignitions) - call fates_params%RetreiveParameter(name=ED_name_understorey_death, & + call fates_params%RetrieveParameter(name=ED_name_understorey_death, & data=ED_val_understorey_death) - call fates_params%RetreiveParameter(name=ED_name_cwd_fcel, & + call fates_params%RetrieveParameter(name=ED_name_cwd_fcel, & data=ED_val_cwd_fcel) - call fates_params%RetreiveParameter(name=ED_name_cwd_flig, & + call fates_params%RetrieveParameter(name=ED_name_cwd_flig, & data=ED_val_cwd_flig) - call fates_params%RetreiveParameter(name=ED_name_base_mr_20, & - data=ED_val_base_mr_20) - - call fates_params%RetreiveParameter(name=ED_name_phen_drought_threshold, & - data=ED_val_phen_drought_threshold) - - call fates_params%RetreiveParameter(name=ED_name_phen_doff_time, & - data=ED_val_phen_doff_time) + call fates_params%RetrieveParameter(name=fates_name_maintresp_nonleaf_baserate, & + data=maintresp_nonleaf_baserate) - call fates_params%RetreiveParameter(name=ED_name_phen_a, & + call fates_params%RetrieveParameter(name=ED_name_phen_a, & data=ED_val_phen_a) - call fates_params%RetreiveParameter(name=ED_name_phen_b, & + call fates_params%RetrieveParameter(name=ED_name_phen_b, & data=ED_val_phen_b) - call fates_params%RetreiveParameter(name=ED_name_phen_c, & + call fates_params%RetrieveParameter(name=ED_name_phen_c, & data=ED_val_phen_c) - call fates_params%RetreiveParameter(name=ED_name_phen_chiltemp, & + call fates_params%RetrieveParameter(name=ED_name_phen_chiltemp, & data=ED_val_phen_chiltemp) - call fates_params%RetreiveParameter(name=ED_name_phen_mindayson, & + call fates_params%RetrieveParameter(name=ED_name_phen_mindayson, & data=ED_val_phen_mindayson) - call fates_params%RetreiveParameter(name=ED_name_phen_ncolddayslim, & + call fates_params%RetrieveParameter(name=ED_name_phen_ncolddayslim, & data=ED_val_phen_ncolddayslim) - call fates_params%RetreiveParameter(name=ED_name_phen_coldtemp, & + call fates_params%RetrieveParameter(name=ED_name_phen_coldtemp, & data=ED_val_phen_coldtemp) - call fates_params%RetreiveParameter(name=ED_name_cohort_size_fusion_tol, & + call fates_params%RetrieveParameter(name=ED_name_cohort_size_fusion_tol, & data=ED_val_cohort_size_fusion_tol) - call fates_params%RetreiveParameter(name=ED_name_cohort_age_fusion_tol, & + call fates_params%RetrieveParameter(name=ED_name_cohort_age_fusion_tol, & data=ED_val_cohort_age_fusion_tol) - call fates_params%RetreiveParameter(name=ED_name_patch_fusion_tol, & + call fates_params%RetrieveParameter(name=ED_name_patch_fusion_tol, & data=ED_val_patch_fusion_tol) - call fates_params%RetreiveParameter(name=ED_name_canopy_closure_thresh, & + call fates_params%RetrieveParameter(name=ED_name_canopy_closure_thresh, & data=ED_val_canopy_closure_thresh) - call fates_params%RetreiveParameter(name=ED_name_stomatal_model, & + call fates_params%RetrieveParameter(name=ED_name_stomatal_model, & data=tmpreal) stomatal_model = nint(tmpreal) - call fates_params%RetreiveParameter(name=hydr_name_kmax_rsurf1, & + call fates_params%RetrieveParameter(name=ED_name_regeneration_model, & + data=tmpreal) + regeneration_model = nint(tmpreal) + + call fates_params%RetrieveParameter(name=stomatal_assim_name, & + data=tmpreal) + stomatal_assim_model = nint(tmpreal) + + call fates_params%RetrieveParameter(name=maxpatch_primary_name, & + data=tmpreal) + maxpatch_primary = nint(tmpreal) + + call fates_params%RetrieveParameter(name=maxpatch_secondary_name, & + data=tmpreal) + maxpatch_secondary = nint(tmpreal) + + maxpatch_total = maxpatch_primary+maxpatch_secondary + + call fates_params%RetrieveParameter(name=maxcohort_name, & + data=tmpreal) + max_cohort_per_patch = nint(tmpreal) + + call fates_params%RetrieveParameter(name=hydr_name_kmax_rsurf1, & data=hydr_kmax_rsurf1) - call fates_params%RetreiveParameter(name=hydr_name_kmax_rsurf2, & + call fates_params%RetrieveParameter(name=hydr_name_kmax_rsurf2, & data=hydr_kmax_rsurf2) - call fates_params%RetreiveParameter(name=hydr_name_psi0, & + call fates_params%RetrieveParameter(name=hydr_name_psi0, & data=hydr_psi0) - call fates_params%RetreiveParameter(name=hydr_name_psicap, & + call fates_params%RetrieveParameter(name=hydr_name_psicap, & data=hydr_psicap) - - call fates_params%RetreiveParameter(name=bgc_name_soil_salinity, & + + call fates_params%RetrieveParameter(name=hydr_name_solver, & + data=tmpreal) + hydr_solver = nint(tmpreal) + + call fates_params%RetrieveParameter(name=bgc_name_soil_salinity, & data=bgc_soil_salinity) - call fates_params%RetreiveParameter(name=logging_name_dbhmin, & + call fates_params%RetrieveParameter(name=logging_name_dbhmin, & data=logging_dbhmin) - call fates_params%RetreiveParameter(name=logging_name_dbhmax, & + call fates_params%RetrieveParameter(name=logging_name_dbhmax, & data=logging_dbhmax) - call fates_params%RetreiveParameter(name=logging_name_collateral_frac, & + call fates_params%RetrieveParameter(name=logging_name_collateral_frac, & data=logging_collateral_frac) - call fates_params%RetreiveParameter(name=logging_name_coll_under_frac, & + call fates_params%RetrieveParameter(name=logging_name_coll_under_frac, & data=logging_coll_under_frac) - call fates_params%RetreiveParameter(name=logging_name_direct_frac, & + call fates_params%RetrieveParameter(name=logging_name_direct_frac, & data=logging_direct_frac) - call fates_params%RetreiveParameter(name=logging_name_mechanical_frac, & + call fates_params%RetrieveParameter(name=logging_name_mechanical_frac, & data=logging_mechanical_frac) - call fates_params%RetreiveParameter(name=logging_name_event_code, & + call fates_params%RetrieveParameter(name=logging_name_event_code, & data=logging_event_code) - call fates_params%RetreiveParameter(name=logging_name_dbhmax_infra, & + call fates_params%RetrieveParameter(name=logging_name_dbhmax_infra, & data=logging_dbhmax_infra) - call fates_params%RetreiveParameter(name=logging_name_export_frac, & + call fates_params%RetrieveParameter(name=logging_name_export_frac, & data=logging_export_frac) - call fates_params%RetreiveParameter(name=eca_name_plant_escalar, & + call fates_params%RetrieveParameter(name=logging_name_pprodharv10, & + data=pprodharv10_forest_mean) + + call fates_params%RetrieveParameter(name=eca_name_plant_escalar, & data=eca_plant_escalar) - call fates_params%RetreiveParameter(name=name_theta_cj_c3, & + call fates_params%RetrieveParameter(name=name_theta_cj_c3, & data=theta_cj_c3) - call fates_params%RetreiveParameter(name=name_theta_cj_c4, & + call fates_params%RetrieveParameter(name=name_theta_cj_c4, & data=theta_cj_c4) - call fates_params%RetreiveParameter(name=fates_name_q10_mr, & + call fates_params%RetrieveParameter(name=fates_name_q10_mr, & data=q10_mr) - call fates_params%RetreiveParameter(name=fates_name_q10_froz, & + call fates_params%RetrieveParameter(name=fates_name_q10_froz, & data=q10_froz) - call fates_params%RetreiveParameter(name=name_dev_arbitrary, & + call fates_params%RetrieveParameter(name=name_dev_arbitrary, & data=dev_arbitrary) - call fates_params%RetreiveParameter(name=fates_name_cg_strikes, & + call fates_params%RetrieveParameter(name=fates_name_cg_strikes, & data=cg_strikes) + call fates_params%RetrieveParameter(name=damage_name_event_code, & + data=tmpreal) + damage_event_code = nint(tmpreal) + + call fates_params%RetrieveParameter(name=damage_name_canopy_layer_code, & + data=tmpreal) + damage_canopy_layer_code = nint(tmpreal) + ! parameters that are arrays of size defined within the params file and thus need allocating as well - call fates_params%RetreiveParameterAllocate(name=ED_name_history_sizeclass_bin_edges, & + call fates_params%RetrieveParameterAllocate(name=ED_name_history_sizeclass_bin_edges, & data=ED_val_history_sizeclass_bin_edges) - call fates_params%RetreiveParameterAllocate(name=ED_name_history_ageclass_bin_edges, & + call fates_params%RetrieveParameterAllocate(name=ED_name_history_ageclass_bin_edges, & data=ED_val_history_ageclass_bin_edges) - call fates_params%RetreiveParameterAllocate(name=ED_name_history_height_bin_edges, & + call fates_params%RetrieveParameterAllocate(name=ED_name_history_height_bin_edges, & data=ED_val_history_height_bin_edges) - call fates_params%RetreiveParameterAllocate(name=ED_name_history_coageclass_bin_edges, & + call fates_params%RetrieveParameterAllocate(name=ED_name_history_coageclass_bin_edges, & data=ED_val_history_coageclass_bin_edges) - call fates_params%RetreiveParameterAllocate(name=ED_name_hydr_htftype_node, & + call fates_params%RetrieveParameterAllocate(name=ED_name_history_damage_bin_edges, & + data=ED_val_history_damage_bin_edges) + + call fates_params%RetrieveParameterAllocate(name=ED_name_hydr_htftype_node, & data=hydr_htftype_real) allocate(hydr_htftype_node(size(hydr_htftype_real))) hydr_htftype_node(:) = nint(hydr_htftype_real(:)) @@ -654,19 +863,22 @@ 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(),fmt0) 'photo_temp_acclim_timescale (days) = ',photo_temp_acclim_timescale + write(fates_log(),fmt0) 'photo_temp_acclim_thome_time (years) = ',photo_temp_acclim_thome_time 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 write(fates_log(),fmt0) 'ED_val_vai_top_bin_width = ',ED_val_vai_top_bin_width write(fates_log(),fmt0) 'ED_val_vai_width_increase_factor = ',ED_val_vai_width_increase_factor - write(fates_log(),fmt0) 'ED_val_init_litter = ',ED_val_init_litter write(fates_log(),fmt0) 'ED_val_nignitions = ',ED_val_nignitions write(fates_log(),fmt0) 'ED_val_understorey_death = ',ED_val_understorey_death write(fates_log(),fmt0) 'ED_val_cwd_fcel = ',ED_val_cwd_fcel write(fates_log(),fmt0) 'ED_val_cwd_flig = ',ED_val_cwd_flig - write(fates_log(),fmt0) 'ED_val_base_mr_20 = ', ED_val_base_mr_20 - write(fates_log(),fmt0) 'ED_val_phen_drought_threshold = ',ED_val_phen_drought_threshold - write(fates_log(),fmt0) 'ED_val_phen_doff_time = ',ED_val_phen_doff_time + write(fates_log(),fmt0) 'fates_maintresp_nonleaf_baserate = ', maintresp_nonleaf_baserate write(fates_log(),fmt0) 'ED_val_phen_a = ',ED_val_phen_a write(fates_log(),fmt0) 'ED_val_phen_b = ',ED_val_phen_b write(fates_log(),fmt0) 'ED_val_phen_c = ',ED_val_phen_c @@ -678,11 +890,14 @@ subroutine FatesReportParams(is_master) write(fates_log(),fmt0) 'ED_val_cohort_age_fusion_tol = ',ED_val_cohort_age_fusion_tol 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) 'hydr_kmax_rsurf1 = ',hydr_kmax_rsurf1 - write(fates_log(),fmt0) 'hydr_kmax_rsurf2 = ',hydr_kmax_rsurf2 - write(fates_log(),fmt0) 'hydr_psi0 = ',hydr_psi0 - write(fates_log(),fmt0) 'hydr_psicap = ',hydr_psicap + write(fates_log(),fmt0) 'regeneration_model = ',regeneration_model + write(fates_log(),fmt0) 'stomatal_model = ',stomatal_model + write(fates_log(),fmt0) 'stomatal_assim_model = ',stomatal_assim_model + write(fates_log(),fmt0) 'hydro_kmax_rsurf1 = ',hydr_kmax_rsurf1 + write(fates_log(),fmt0) 'hydro_kmax_rsurf2 = ',hydr_kmax_rsurf2 + write(fates_log(),fmt0) 'hydro_psi0 = ',hydr_psi0 + write(fates_log(),fmt0) 'hydro_psicap = ',hydr_psicap + write(fates_log(),fmt0) 'hydro_solver = ',hydr_solver write(fates_log(),fmt0) 'bgc_soil_salinity = ', bgc_soil_salinity write(fates_log(),fmt0) 'logging_dbhmin = ',logging_dbhmin write(fates_log(),fmt0) 'logging_dbhmax = ',logging_dbhmax @@ -696,6 +911,9 @@ subroutine FatesReportParams(is_master) write(fates_log(),fmt0) 'q10_mr = ',q10_mr write(fates_log(),fmt0) 'q10_froz = ',q10_froz write(fates_log(),fmt0) 'cg_strikes = ',cg_strikes + write(fates_log(),'(a,L2)') 'active_crown_fire = ',active_crown_fire + write(fates_log(),fmt0) 'damage_event_code = ',damage_event_code + write(fates_log(),fmt0) 'damage_canopy_layer_code = ', damage_canopy_layer_code write(fates_log(),*) '------------------------------------------------------' end if diff --git a/main/EDPftvarcon.F90 b/main/EDPftvarcon.F90 index c9cb341423..f420894248 100644 --- a/main/EDPftvarcon.F90 +++ b/main/EDPftvarcon.F90 @@ -6,8 +6,7 @@ module EDPftvarcon ! read and initialize vegetation (PFT) constants. ! ! !USES: - use EDTypesMod , only : maxSWb, ivis, inir - use EDTypesMod , only : n_uptake_mode, p_uptake_mode + use EDParamsMod , only : maxSWb, ivis, inir use FatesConstantsMod, only : r8 => fates_r8 use FatesConstantsMod, only : nearzero use FatesConstantsMod, only : itrue, ifalse @@ -25,7 +24,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 @@ -59,7 +61,7 @@ module EDPftvarcon real(r8), allocatable :: lf_flab(:) ! Leaf litter labile fraction [-] real(r8), allocatable :: lf_fcel(:) ! Leaf litter cellulose fraction [-] - real(r8), allocatable :: lf_flig(:) ! Leaf litter lignan fraction [-] + real(r8), allocatable :: lf_flig(:) ! Leaf litter lignin fraction [-] real(r8), allocatable :: fr_flab(:) ! Fine-root litter labile fraction [-] real(r8), allocatable :: fr_fcel(:) ! Fine-root litter cellulose fraction [-] real(r8), allocatable :: fr_flig(:) ! Fine-root litter lignatn fraction [-] @@ -80,32 +82,63 @@ module EDPftvarcon ! 1=linear, 0=very curved real(r8), allocatable :: maintresp_reduction_intercept(:) ! intercept of MR reduction as f(carbon storage), ! 0=no throttling, 1=max throttling + real(r8), allocatable :: maintresp_reduction_upthresh (:) ! Upper threshold for storage biomass (relative + ! to leaf biomass) above which MR is not reduced + + real(r8), allocatable :: maintresp_leaf_atkin2017_baserate(:) ! leaf maintenance respiration base rate (r0) + ! per Atkin et al 2017 + + real(r8), allocatable :: maintresp_leaf_ryan1991_baserate(:) ! leaf maintenance respiration per Ryan et al 1991 + real(r8), allocatable :: bmort(:) - real(r8), allocatable :: mort_ip_size_senescence(:) ! inflection point of dbh dependent senescence - real(r8), allocatable :: mort_r_size_senescence(:) ! rate of change in mortality with dbh - real(r8), allocatable :: mort_ip_age_senescence(:) ! inflection point of age dependent senescence - real(r8), allocatable :: mort_r_age_senescence(:) ! rate of change in mortality with age - real(r8), allocatable :: mort_scalar_coldstress(:) - real(r8), allocatable :: mort_scalar_cstarvation(:) - real(r8), allocatable :: mort_scalar_hydrfailure(:) - real(r8), allocatable :: hf_sm_threshold(:) - real(r8), allocatable :: hf_flc_threshold(:) - real(r8), allocatable :: vcmaxha(:) - real(r8), allocatable :: jmaxha(:) - real(r8), allocatable :: vcmaxhd(:) - real(r8), allocatable :: jmaxhd(:) - real(r8), allocatable :: vcmaxse(:) - real(r8), allocatable :: jmaxse(:) + real(r8), allocatable :: mort_ip_size_senescence(:) ! inflection point of dbh dependent senescence + real(r8), allocatable :: mort_r_size_senescence(:) ! rate of change in mortality with dbh + real(r8), allocatable :: mort_ip_age_senescence(:) ! inflection point of age dependent senescence + real(r8), allocatable :: mort_r_age_senescence(:) ! rate of change in mortality with age + real(r8), allocatable :: mort_scalar_coldstress(:) ! maximum mortality rate from cold stress + real(r8), allocatable :: mort_scalar_cstarvation(:) ! maximum mortality rate from carbon starvation + real(r8), allocatable :: mort_scalar_hydrfailure(:) ! maximum mortality rate from hydraulic failure + real(r8), allocatable :: mort_upthresh_cstarvation(:) ! threshold for storage biomass (relative to target leaf biomass) above which carbon starvation is zero + real(r8), allocatable :: hf_sm_threshold(:) ! soil moisture (btran units) at which drought mortality begins for non-hydraulic model + real(r8), allocatable :: hf_flc_threshold(:) ! plant fractional loss of conductivity at which drought mortality begins for hydraulic model + real(r8), allocatable :: vcmaxha(:) ! activation energy for vcmax + real(r8), allocatable :: jmaxha(:) ! activation energy for jmax + real(r8), allocatable :: vcmaxhd(:) ! deactivation energy for vcmax + real(r8), allocatable :: jmaxhd(:) ! deactivation energy for jmax + real(r8), allocatable :: vcmaxse(:) ! entropy term for vcmax + real(r8), allocatable :: jmaxse(:) ! entropy term for jmax real(r8), allocatable :: germination_rate(:) ! Fraction of seed mass germinating per year (yr-1) real(r8), allocatable :: seed_decay_rate(:) ! Fraction of seed mass (both germinated and ! ungerminated), decaying per year (yr-1) + real(r8), allocatable :: seed_dispersal_pdf_scale(:) ! Seed dispersal scale parameter, Bullock et al. (2017) + real(r8), allocatable :: seed_dispersal_pdf_shape(:) ! Seed dispersal shape parameter, Bullock et al. (2017) + real(r8), allocatable :: seed_dispersal_max_dist(:) ! Maximum seed dispersal distance parameter (m) + real(r8), allocatable :: seed_dispersal_fraction(:) ! Fraction of seed rain to disperse, per pft + + 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) - real(r8), allocatable :: rhol(:, :) - real(r8), allocatable :: rhos(:, :) - real(r8), allocatable :: taul(:, :) - real(r8), allocatable :: taus(:, :) + real(r8), allocatable :: rhol(:, :) ! Leaf reflectance; second dim: 1 = vis, 2 = nir + real(r8), allocatable :: rhos(:, :) ! Stem reflectance; second dim: 1 = vis, 2 = nir + real(r8), allocatable :: taul(:, :) ! Leaf transmittance; second dim: 1 = vis, 2 = nir + real(r8), allocatable :: taus(:, :) ! Stem transmittance; second dim: 1 = vis, 2 = nir ! Fire Parameters (No PFT vector capabilities in their own routines) ! See fire/SFParamsMod.F90 for bulk of fire parameters @@ -131,10 +164,32 @@ module EDPftvarcon real(r8), allocatable :: prescribed_recruitment(:) ! this is only for the ! prescribed_physiology_mode + + ! Damage Parameters + + real(r8), allocatable :: damage_frac(:) ! Fraction of each cohort damaged per year + real(r8), allocatable :: damage_mort_p1(:) ! Inflection point for damage mortality function + real(r8), allocatable :: damage_mort_p2(:) ! Rate parameter for damage mortality function + real(r8), allocatable :: damage_recovery_scalar(:) ! what fraction of cohort gets to recover + ! Nutrient Aquisition (ECA & RD) + + real(r8), allocatable :: decompmicc(:) ! microbial decomposer biomass gC/m3 ! on root surface + real(r8), allocatable :: vmax_nh4(:) ! maximum production rate for plant NH4 uptake [gN/gC/s] + real(r8), allocatable :: vmax_no3(:) ! maximum production rate for plant NO3 uptake [gN/gC/s] + ! For ECA: these rates will be applied separately to + ! draw from mineralized nh4 and no3 pools independantly. + ! For RD: these rates will be added, to construct a total + ! N demand, which will be applied to NH4 and then NO3 + ! sequentially + real(r8), allocatable :: vmax_p(:) ! maximum production rate for plant p uptake [gP/gC/s] + + + + ! ECA Parameters: See Zhu et al. Multiple soil nutrient competition between plants, ! microbes, and mineral surfaces: model development, parameterization, ! and example applications in several tropical forests. Biogeosciences, @@ -142,13 +197,13 @@ module EDPftvarcon ! KM: Michaeles-Menten half-saturation constants for ECA (plant–enzyme affinity) ! VMAX: Product of the reaction-rate and enzyme abundance for each PFT in ECA ! Note*: units of [gC] is grams carbon of fine-root - + real(r8), allocatable :: eca_km_nh4(:) ! half-saturation constant for plant nh4 uptake [gN/m3] - real(r8), allocatable :: eca_vmax_nh4(:) ! maximum production rate for plant nh4 uptake [gN/gC/s] + real(r8), allocatable :: eca_km_no3(:) ! half-saturation constant for plant no3 uptake [gN/m3] - real(r8), allocatable :: eca_vmax_no3(:) ! maximum production rate for plant no3 uptake [gN/gC/s] + real(r8), allocatable :: eca_km_p(:) ! half-saturation constant for plant p uptake [gP/m3] - real(r8), allocatable :: eca_vmax_p(:) ! maximum production rate for plant p uptake [gP/gC/s] + real(r8), allocatable :: eca_km_ptase(:) ! half-saturation constant for biochemical P production [gP/m3] real(r8), allocatable :: eca_vmax_ptase(:) ! maximum production rate for biochemical P prod [gP/gC/s] real(r8), allocatable :: eca_alpha_ptase(:) ! Fraction of min P generated from ptase activity @@ -157,18 +212,12 @@ module EDPftvarcon ! biochemical production, fraction based how much ! more in need a plant is for P versus N [/] - !real(r8), allocatable :: nfix1(:) ! nitrogen fixation parameter 1 - !real(r8), allocatable :: nfix2(:) ! nitrogen fixation parameter 2 - - - ! Turnover related things + ! Phenology related things real(r8), allocatable :: phenflush_fraction(:) ! Maximum fraction of storage carbon used to flush leaves ! on bud-burst [kgC/kgC] real(r8), allocatable :: phen_cold_size_threshold(:) ! stem/leaf drop occurs on DBH size of decidious non-woody ! (coastal grass) plants larger than the threshold value - real(r8), allocatable :: phen_stem_drop_fraction(:) ! Fraction of stem dropped/senescened for decidious - ! non-woody (grass) plants ! Nutrient Aquisition parameters real(r8), allocatable :: prescribed_nuptake(:) ! If there is no soil BGC model active, @@ -178,7 +227,6 @@ module EDPftvarcon ! prescribe an uptake rate for phosphorus ! This is the fraction of plant demand - ! Unassociated pft dimensioned free parameter that ! developers can use for testing arbitrary new hypothese real(r8), allocatable :: dev_arbitrary_pft(:) @@ -325,7 +373,7 @@ 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_recruit_hgt_min' + name = 'fates_recruit_height_min' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) @@ -341,11 +389,11 @@ 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_recruit_initd' + name = 'fates_recruit_init_density' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_seed_suppl' + name = 'fates_recruit_seed_supplement' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) @@ -361,36 +409,35 @@ 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_lf_flab' + name = 'fates_frag_leaf_flab' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_lf_fcel' + name = 'fates_frag_leaf_fcel' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_lf_flig' + name = 'fates_frag_leaf_flig' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_fr_flab' + name = 'fates_frag_fnrt_flab' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_fr_fcel' + name = 'fates_frag_fnrt_fcel' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_fr_flig' + name = 'fates_frag_fnrt_flig' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_leaf_xl' + name = 'fates_rad_leaf_xl' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - - name = 'fates_leaf_clumping_index' + name = 'fates_rad_leaf_clumping_index' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) @@ -398,11 +445,11 @@ 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_smpso' + name = 'fates_nonhydro_smpso' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_smpsc' + name = 'fates_nonhydro_smpsc' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) @@ -414,6 +461,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_maintresp_reduction_upthresh' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + + name = 'fates_maintresp_leaf_atkin2017_baserate' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + + name = 'fates_maintresp_leaf_ryan1991_baserate' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + name = 'fates_prescribed_npp_canopy' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) @@ -422,15 +481,31 @@ 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_prescribed_mortality_canopy' + name = 'fates_mort_prescribed_canopy' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + + name = 'fates_mort_prescribed_understory' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + + name = 'fates_recruit_prescribed_rate' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + + name = 'fates_damage_frac' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + + name = 'fates_damage_mort_p1' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_prescribed_mortality_understory' + name = 'fates_damage_mort_p2' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_prescribed_recruitment' + name = 'fates_damage_recovery_scalar' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) @@ -442,31 +517,31 @@ 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_hydr_p_taper' + name = 'fates_hydro_p_taper' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_hydr_rs2' + name = 'fates_hydro_rs2' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_hydr_srl' + name = 'fates_hydro_srl' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_hydr_rfrac_stem' + name = 'fates_hydro_rfrac_stem' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_hydr_avuln_gs' + name = 'fates_hydro_avuln_gs' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_hydr_p50_gs' + name = 'fates_hydro_p50_gs' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_hydr_k_lwp' + name = 'fates_hydro_k_lwp' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) @@ -502,6 +577,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_mort_upthresh_cstarvation' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + name = 'fates_mort_hf_sm_threshold' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) @@ -534,14 +613,94 @@ 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_seed_germination_rate' + name = 'fates_recruit_seed_germination_rate' 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' + 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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_trs_seedling_background_mort' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + + name = 'fates_frag_seed_decay_rate' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + + name = 'fates_seed_dispersal_pdf_scale' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + + name = 'fates_seed_dispersal_pdf_shape' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + + name = 'fates_seed_dispersal_max_dist' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + + name = 'fates_seed_dispersal_fraction' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + name = 'fates_trim_limit' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) @@ -550,19 +709,19 @@ 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_leaf_diameter' + name = 'fates_turb_leaf_diameter' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_z0mr' + name = 'fates_turb_z0mr' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_displar' + name = 'fates_turb_displar' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_phenflush_fraction' + name = 'fates_phen_flush_fraction' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) @@ -570,62 +729,58 @@ 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_phen_stem_drop_fraction' - call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & - dimension_names=dim_names, lower_bounds=dim_lower_bound) ! Nutrient competition parameters - - name = 'fates_eca_decompmicc' + name = 'fates_cnp_eca_decompmicc' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_eca_km_nh4' + name = 'fates_cnp_eca_km_nh4' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_eca_vmax_nh4' + name = 'fates_cnp_vmax_nh4' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_eca_km_no3' + name = 'fates_cnp_eca_km_no3' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_eca_vmax_no3' + name = 'fates_cnp_vmax_no3' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_eca_km_p' + name = 'fates_cnp_eca_km_p' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_eca_vmax_p' + name = 'fates_cnp_vmax_p' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_eca_km_ptase' + name = 'fates_cnp_eca_km_ptase' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_eca_vmax_ptase' + name = 'fates_cnp_eca_vmax_ptase' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_eca_alpha_ptase' + name = 'fates_cnp_eca_alpha_ptase' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_eca_lambda_ptase' + name = 'fates_cnp_eca_lambda_ptase' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_prescribed_nuptake' + name = 'fates_cnp_prescribed_nuptake' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_prescribed_puptake' + name = 'fates_cnp_prescribed_puptake' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) @@ -656,333 +811,441 @@ subroutine Receive_PFT(this, fates_params) character(len=param_string_length) :: name !X! name = '' - !X! call fates_params%RetreiveParameter(name=name, & + !X! call fates_params%RetrieveParameter(name=name, & !X! data=this%) name = 'fates_mort_freezetol' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=this%freezetol) - name = 'fates_recruit_hgt_min' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_recruit_height_min' + call fates_params%RetrieveParameterAllocate(name=name, & data=this%hgt_min) name = 'fates_fire_bark_scaler' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=this%bark_scaler) name = 'fates_fire_crown_kill' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=this%crown_kill) name = 'fates_fire_active_crown_fire' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=this%active_crown_fire) - name = 'fates_recruit_initd' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_recruit_init_density' + call fates_params%RetrieveParameterAllocate(name=name, & data=this%initd) - name = 'fates_seed_suppl' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_recruit_seed_supplement' + call fates_params%RetrieveParameterAllocate(name=name, & data=this%seed_suppl) name = 'fates_leaf_stomatal_slope_ballberry' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=this%bb_slope) name = 'fates_leaf_stomatal_slope_medlyn' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=this%medlyn_slope) name = 'fates_leaf_stomatal_intercept' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=this%stomatal_intercept) - name = 'fates_lf_flab' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_frag_leaf_flab' + call fates_params%RetrieveParameterAllocate(name=name, & data=this%lf_flab) - name = 'fates_lf_fcel' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_frag_leaf_fcel' + call fates_params%RetrieveParameterAllocate(name=name, & data=this%lf_fcel) - name = 'fates_lf_flig' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_frag_leaf_flig' + call fates_params%RetrieveParameterAllocate(name=name, & data=this%lf_flig) - name = 'fates_fr_flab' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_frag_fnrt_flab' + call fates_params%RetrieveParameterAllocate(name=name, & data=this%fr_flab) - name = 'fates_fr_fcel' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_frag_fnrt_fcel' + call fates_params%RetrieveParameterAllocate(name=name, & data=this%fr_fcel) - name = 'fates_fr_flig' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_frag_fnrt_flig' + call fates_params%RetrieveParameterAllocate(name=name, & data=this%fr_flig) - name = 'fates_leaf_xl' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_rad_leaf_xl' + call fates_params%RetrieveParameterAllocate(name=name, & data=this%xl) - name = 'fates_leaf_clumping_index' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_rad_leaf_clumping_index' + call fates_params%RetrieveParameterAllocate(name=name, & data=this%clumping_index) name = 'fates_leaf_c3psn' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=this%c3psn) - name = 'fates_smpso' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_nonhydro_smpso' + call fates_params%RetrieveParameterAllocate(name=name, & data=this%smpso) - name = 'fates_smpsc' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_nonhydro_smpsc' + call fates_params%RetrieveParameterAllocate(name=name, & data=this%smpsc) name = 'fates_maintresp_reduction_curvature' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=this%maintresp_reduction_curvature) name = 'fates_maintresp_reduction_intercept' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=this%maintresp_reduction_intercept) + name = 'fates_maintresp_reduction_upthresh' + call fates_params%RetrieveParameterAllocate(name=name, & + data=this%maintresp_reduction_upthresh) + + name = 'fates_maintresp_leaf_atkin2017_baserate' + call fates_params%RetrieveParameterAllocate(name=name, & + data=this%maintresp_leaf_atkin2017_baserate) + + name = 'fates_maintresp_leaf_ryan1991_baserate' + call fates_params%RetrieveParameterAllocate(name=name, & + data=this%maintresp_leaf_ryan1991_baserate) + name = 'fates_prescribed_npp_canopy' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=this%prescribed_npp_canopy) name = 'fates_prescribed_npp_understory' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=this%prescribed_npp_understory) - name = 'fates_prescribed_mortality_canopy' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_mort_prescribed_canopy' + call fates_params%RetrieveParameterAllocate(name=name, & data=this%prescribed_mortality_canopy) - name = 'fates_prescribed_mortality_understory' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_mort_prescribed_understory' + call fates_params%RetrieveParameterAllocate(name=name, & data=this%prescribed_mortality_understory) - name = 'fates_prescribed_recruitment' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_recruit_prescribed_rate' + call fates_params%RetrieveParameterAllocate(name=name, & data=this%prescribed_recruitment) + name = 'fates_damage_frac' + call fates_params%RetrieveParameterAllocate(name=name, & + data=this%damage_frac) + + name = 'fates_damage_mort_p1' + call fates_params%RetrieveParameterAllocate(name=name, & + data=this%damage_mort_p1) + + name = 'fates_damage_mort_p2' + call fates_params%RetrieveParameterAllocate(name=name, & + data=this%damage_mort_p2) + + name = 'fates_damage_recovery_scalar' + call fates_params%RetrieveParameterAllocate(name=name, & + data=this%damage_recovery_scalar) + name = 'fates_fire_alpha_SH' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=this%fire_alpha_SH) name = 'fates_allom_frbstor_repro' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=this%allom_frbstor_repro) - name = 'fates_hydr_p_taper' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_hydro_p_taper' + call fates_params%RetrieveParameterAllocate(name=name, & data=this%hydr_p_taper) - name = 'fates_hydr_rs2' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_hydro_rs2' + call fates_params%RetrieveParameterAllocate(name=name, & data=this%hydr_rs2) - name = 'fates_hydr_srl' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_hydro_srl' + call fates_params%RetrieveParameterAllocate(name=name, & data=this%hydr_srl) - name = 'fates_hydr_rfrac_stem' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_hydro_rfrac_stem' + call fates_params%RetrieveParameterAllocate(name=name, & data=this%hydr_rfrac_stem) - name = 'fates_hydr_k_lwp' - call fates_params%RetreiveParameterAllocate(name=name, & - data=this%hydr_k_lwp) - - name = 'fates_hydr_avuln_gs' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_hydro_avuln_gs' + call fates_params%RetrieveParameterAllocate(name=name, & data=this%hydr_avuln_gs) - name = 'fates_hydr_p50_gs' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_hydro_p50_gs' + call fates_params%RetrieveParameterAllocate(name=name, & data=this%hydr_p50_gs) - name = 'fates_hydr_k_lwp' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_hydro_k_lwp' + call fates_params%RetrieveParameterAllocate(name=name, & data=this%hydr_k_lwp) name = 'fates_mort_bmort' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=this%bmort) name = 'fates_mort_scalar_coldstress' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=this%mort_scalar_coldstress) name = 'fates_mort_scalar_cstarvation' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=this%mort_scalar_cstarvation) name = 'fates_mort_scalar_hydrfailure' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=this%mort_scalar_hydrfailure) + name = 'fates_mort_upthresh_cstarvation' + call fates_params%RetrieveParameterAllocate(name=name, & + data=this%mort_upthresh_cstarvation) + name = 'fates_mort_ip_size_senescence' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=this%mort_ip_size_senescence) name = 'fates_mort_r_size_senescence' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=this%mort_r_size_senescence) name = 'fates_mort_ip_age_senescence' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=this%mort_ip_age_senescence) name = 'fates_mort_r_age_senescence' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=this%mort_r_age_senescence) name = 'fates_mort_scalar_coldstress' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=this%mort_scalar_coldstress) name = 'fates_mort_scalar_cstarvation' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=this%mort_scalar_cstarvation) + name = 'fates_mort_upthresh_cstarvation' + call fates_params%RetrieveParameterAllocate(name=name, & + data=this%mort_upthresh_cstarvation) + name = 'fates_mort_hf_sm_threshold' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=this%hf_sm_threshold) name = 'fates_mort_hf_flc_threshold' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=this%hf_flc_threshold) name = 'fates_leaf_vcmaxha' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=this%vcmaxha) name = 'fates_leaf_jmaxha' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=this%jmaxha) name = 'fates_leaf_vcmaxhd' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=this%vcmaxhd) name = 'fates_leaf_jmaxhd' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=this%jmaxhd) name = 'fates_leaf_vcmaxse' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=this%vcmaxse) name = 'fates_leaf_jmaxse' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=this%jmaxse) - name = 'fates_seed_germination_rate' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_recruit_seed_germination_rate' + call fates_params%RetrieveParameterAllocate(name=name, & data=this%germination_rate) - name = 'fates_seed_decay_rate' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_trs_repro_frac_seed' + call fates_params%RetrieveParameterAllocate(name=name, & + data=this%repro_frac_seed) + + name = 'fates_trs_seedling_a_emerg' + call fates_params%RetrieveParameterAllocate(name=name, & + data=this%a_emerg) + + name = 'fates_trs_seedling_b_emerg' + call fates_params%RetrieveParameterAllocate(name=name, & + data=this%b_emerg) + + name = 'fates_trs_seedling_par_crit_germ' + call fates_params%RetrieveParameterAllocate(name=name, & + data=this%par_crit_germ) + + name = 'fates_trs_seedling_psi_emerg' + call fates_params%RetrieveParameterAllocate(name=name, & + data=this%seedling_psi_emerg) + + name = 'fates_trs_seedling_psi_crit' + call fates_params%RetrieveParameterAllocate(name=name, & + data=this%seedling_psi_crit) + + name = 'fates_trs_seedling_light_rec_a' + call fates_params%RetrieveParameterAllocate(name=name, & + data=this%seedling_light_rec_a) + + name = 'fates_trs_seedling_light_rec_b' + call fates_params%RetrieveParameterAllocate(name=name, & + data=this%seedling_light_rec_b) + + name = 'fates_trs_seedling_mdd_crit' + call fates_params%RetrieveParameterAllocate(name=name, & + data=this%seedling_mdd_crit) + + name = 'fates_trs_seedling_h2o_mort_a' + call fates_params%RetrieveParameterAllocate(name=name, & + data=this%seedling_h2o_mort_a) + + name = 'fates_trs_seedling_h2o_mort_b' + call fates_params%RetrieveParameterAllocate(name=name, & + data=this%seedling_h2o_mort_b) + + name = 'fates_trs_seedling_h2o_mort_c' + call fates_params%RetrieveParameterAllocate(name=name, & + data=this%seedling_h2o_mort_c) + + name = 'fates_trs_seedling_root_depth' + call fates_params%RetrieveParameterAllocate(name=name, & + data=this%seedling_root_depth) + + name = 'fates_trs_seedling_light_mort_a' + call fates_params%RetrieveParameterAllocate(name=name, & + data=this%seedling_light_mort_a) + + name = 'fates_trs_seedling_light_mort_b' + call fates_params%RetrieveParameterAllocate(name=name, & + data=this%seedling_light_mort_b) + + name = 'fates_trs_seedling_background_mort' + call fates_params%RetrieveParameterAllocate(name=name, & + data=this%background_seedling_mort) + + name = 'fates_frag_seed_decay_rate' + call fates_params%RetrieveParameterAllocate(name=name, & data=this%seed_decay_rate) + name = 'fates_seed_dispersal_pdf_scale' + call fates_params%RetrieveParameterAllocate(name=name, & + data=this%seed_dispersal_pdf_scale) + + name = 'fates_seed_dispersal_pdf_shape' + call fates_params%RetrieveParameterAllocate(name=name, & + data=this%seed_dispersal_pdf_shape) + + name = 'fates_seed_dispersal_max_dist' + call fates_params%RetrieveParameterAllocate(name=name, & + data=this%seed_dispersal_max_dist) + + name = 'fates_seed_dispersal_fraction' + call fates_params%RetrieveParameterAllocate(name=name, & + data=this%seed_dispersal_fraction) + name = 'fates_trim_limit' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=this%trim_limit) name = 'fates_trim_inc' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=this%trim_inc) - name = 'fates_leaf_diameter' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_turb_leaf_diameter' + call fates_params%RetrieveParameterAllocate(name=name, & data=this%dleaf) - name = 'fates_z0mr' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_turb_z0mr' + call fates_params%RetrieveParameterAllocate(name=name, & data=this%z0mr) - name = 'fates_displar' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_turb_displar' + call fates_params%RetrieveParameterAllocate(name=name, & data=this%displar) - name = 'fates_phenflush_fraction' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_phen_flush_fraction' + call fates_params%RetrieveParameterAllocate(name=name, & data=this%phenflush_fraction) name = 'fates_phen_cold_size_threshold' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=this%phen_cold_size_threshold) - name = 'fates_phen_stem_drop_fraction' - call fates_params%RetreiveParameterAllocate(name=name, & - data=this%phen_stem_drop_fraction) - - name = 'fates_prescribed_nuptake' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_cnp_prescribed_nuptake' + call fates_params%RetrieveParameterAllocate(name=name, & data=this%prescribed_nuptake) - name = 'fates_prescribed_puptake' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_cnp_prescribed_puptake' + call fates_params%RetrieveParameterAllocate(name=name, & data=this%prescribed_puptake) name = 'fates_dev_arbitrary_pft' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=this%dev_arbitrary_pft) - name = 'fates_eca_decompmicc' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_cnp_eca_decompmicc' + call fates_params%RetrieveParameterAllocate(name=name, & data=this%decompmicc) - name = 'fates_eca_km_nh4' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_cnp_eca_km_nh4' + call fates_params%RetrieveParameterAllocate(name=name, & data=this%eca_km_nh4) + + name = 'fates_cnp_vmax_nh4' + call fates_params%RetrieveParameterAllocate(name=name, & + data=this%vmax_nh4) - name = 'fates_eca_vmax_nh4' - call fates_params%RetreiveParameterAllocate(name=name, & - data=this%eca_vmax_nh4) - - name = 'fates_eca_km_no3' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_cnp_eca_km_no3' + call fates_params%RetrieveParameterAllocate(name=name, & data=this%eca_km_no3) - name = 'fates_eca_vmax_no3' - call fates_params%RetreiveParameterAllocate(name=name, & - data=this%eca_vmax_no3) + name = 'fates_cnp_vmax_no3' + call fates_params%RetrieveParameterAllocate(name=name, & + data=this%vmax_no3) - name = 'fates_eca_km_p' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_cnp_eca_km_p' + call fates_params%RetrieveParameterAllocate(name=name, & data=this%eca_km_p) - name = 'fates_eca_vmax_p' - call fates_params%RetreiveParameterAllocate(name=name, & - data=this%eca_vmax_p) + name = 'fates_cnp_vmax_p' + call fates_params%RetrieveParameterAllocate(name=name, & + data=this%vmax_p) - name = 'fates_eca_km_ptase' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_cnp_eca_km_ptase' + call fates_params%RetrieveParameterAllocate(name=name, & data=this%eca_km_ptase) - name = 'fates_eca_vmax_ptase' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_cnp_eca_vmax_ptase' + call fates_params%RetrieveParameterAllocate(name=name, & data=this%eca_vmax_ptase) - name = 'fates_eca_alpha_ptase' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_cnp_eca_alpha_ptase' + call fates_params%RetrieveParameterAllocate(name=name, & data=this%eca_alpha_ptase) - name = 'fates_eca_lambda_ptase' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_cnp_eca_lambda_ptase' + call fates_params%RetrieveParameterAllocate(name=name, & data=this%eca_lambda_ptase) name = 'fates_hlm_pft_map' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=this%hlm_pft_map) end subroutine Receive_PFT @@ -1009,40 +1272,38 @@ subroutine Register_PFT_numrad(this, fates_params) !X! call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & !X! dimension_names=dim_names) - name = 'fates_rholvis' + name = 'fates_rad_leaf_rhovis' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names) - name = 'fates_rholnir' + name = 'fates_rad_leaf_rhonir' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names) - name = 'fates_rhosvis' + name = 'fates_rad_stem_rhovis' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names) - name = 'fates_rhosnir' + name = 'fates_rad_stem_rhonir' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names) - name = 'fates_taulvis' + name = 'fates_rad_leaf_tauvis' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names) - name = 'fates_taulnir' + name = 'fates_rad_leaf_taunir' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names) - name = 'fates_tausvis' + name = 'fates_rad_stem_tauvis' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names) - name = 'fates_tausnir' + name = 'fates_rad_stem_taunir' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names) - - end subroutine Register_PFT_numrad !----------------------------------------------------------------------- @@ -1050,7 +1311,7 @@ subroutine Receive_PFT_numrad(this, fates_params) ! NOTE(bja, 2017-02) these are 2-d parameters, but they are ! currently stored in the parameter file as separate 1-d arrays. ! We can't allocate slices of arrays separately, so we have to - ! manually allocate the memory here, retreive into a dummy array, + ! manually allocate the memory here, retrieve into a dummy array, ! and copy. All parameters in this subroutine are sized the same, ! so we can reused the dummy array. If someone wants to cleanup ! the input file, all this complexity can be removed. @@ -1065,7 +1326,7 @@ subroutine Receive_PFT_numrad(this, fates_params) character(len=param_string_length) :: name !X! name = '' - !X! call fates_params%RetreiveParameter(name=name, & + !X! call fates_params%RetrieveParameter(name=name, & !X! data=this%) integer :: index @@ -1079,7 +1340,7 @@ subroutine Receive_PFT_numrad(this, fates_params) ! Fetch metadata from a representative variable. All variables ! called by this subroutine must be dimensioned the same way! - name = 'fates_rholvis' + name = 'fates_rad_leaf_rhovis' index = fates_params%FindIndex(name) call fates_params%GetMetaData(index, name, dimension_shape, dimension_sizes, dimension_names, is_host_param) lower_bound_1 = lower_bound_pft @@ -1096,13 +1357,13 @@ subroutine Receive_PFT_numrad(this, fates_params) ! allocate(this%rhol(lower_bound_1:upper_bound_1, lower_bound_2:upper_bound_2)) - name = 'fates_rholvis' - call fates_params%RetreiveParameter(name=name, & + name = 'fates_rad_leaf_rhovis' + call fates_params%RetrieveParameter(name=name, & data=dummy_data) this%rhol(lower_bound_1:upper_bound_1, ivis) = dummy_data - name = 'fates_rholnir' - call fates_params%RetreiveParameter(name=name, & + name = 'fates_rad_leaf_rhonir' + call fates_params%RetrieveParameter(name=name, & data=dummy_data) this%rhol(lower_bound_1:upper_bound_1, inir) = dummy_data @@ -1111,13 +1372,13 @@ subroutine Receive_PFT_numrad(this, fates_params) ! allocate(this%rhos(lower_bound_1:upper_bound_1, lower_bound_2:upper_bound_2)) - name = 'fates_rhosvis' - call fates_params%RetreiveParameter(name=name, & + name = 'fates_rad_stem_rhovis' + call fates_params%RetrieveParameter(name=name, & data=dummy_data) this%rhos(lower_bound_1:upper_bound_1, ivis) = dummy_data - name = 'fates_rhosnir' - call fates_params%RetreiveParameter(name=name, & + name = 'fates_rad_stem_rhonir' + call fates_params%RetrieveParameter(name=name, & data=dummy_data) this%rhos(lower_bound_1:upper_bound_1, inir) = dummy_data @@ -1126,13 +1387,13 @@ subroutine Receive_PFT_numrad(this, fates_params) ! allocate(this%taul(lower_bound_1:upper_bound_1, lower_bound_2:upper_bound_2)) - name = 'fates_taulvis' - call fates_params%RetreiveParameter(name=name, & + name = 'fates_rad_leaf_tauvis' + call fates_params%RetrieveParameter(name=name, & data=dummy_data) this%taul(lower_bound_1:upper_bound_1, ivis) = dummy_data - name = 'fates_taulnir' - call fates_params%RetreiveParameter(name=name, & + name = 'fates_rad_leaf_taunir' + call fates_params%RetrieveParameter(name=name, & data=dummy_data) this%taul(lower_bound_1:upper_bound_1, inir) = dummy_data @@ -1141,13 +1402,13 @@ subroutine Receive_PFT_numrad(this, fates_params) ! allocate(this%taus(lower_bound_1:upper_bound_1, lower_bound_2:upper_bound_2)) - name = 'fates_tausvis' - call fates_params%RetreiveParameter(name=name, & + name = 'fates_rad_stem_tauvis' + call fates_params%RetrieveParameter(name=name, & data=dummy_data) this%taus(lower_bound_1:upper_bound_1, ivis) = dummy_data - name = 'fates_tausnir' - call fates_params%RetreiveParameter(name=name, & + name = 'fates_rad_stem_taunir' + call fates_params%RetrieveParameter(name=name, & data=dummy_data) this%taus(lower_bound_1:upper_bound_1, inir) = dummy_data @@ -1200,7 +1461,7 @@ subroutine Receive_PFT_leafage(this, fates_params) character(len=param_string_length) :: name name = 'fates_leaf_vcmax25top' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=this%vcmax25top) return @@ -1228,63 +1489,63 @@ subroutine Register_PFT_hydr_organs(this, fates_params) dim_names(1) = dimension_name_pft dim_names(2) = dimension_name_hydr_organs - name = 'fates_hydr_vg_alpha_node' + name = 'fates_hydro_vg_alpha_node' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_2d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_hydr_vg_m_node' + name = 'fates_hydro_vg_m_node' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_2d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_hydr_vg_n_node' + name = 'fates_hydro_vg_n_node' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_2d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_hydr_avuln_node' + name = 'fates_hydro_avuln_node' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_2d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_hydr_p50_node' + name = 'fates_hydro_p50_node' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_2d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_hydr_thetas_node' + name = 'fates_hydro_thetas_node' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_2d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_hydr_epsil_node' + name = 'fates_hydro_epsil_node' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_2d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_hydr_pitlp_node' + name = 'fates_hydro_pitlp_node' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_2d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_hydr_resid_node' + name = 'fates_hydro_resid_node' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_2d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_hydr_fcap_node' + name = 'fates_hydro_fcap_node' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_2d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_hydr_pinot_node' + name = 'fates_hydro_pinot_node' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_2d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_hydr_kmax_node' + name = 'fates_hydro_kmax_node' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_2d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_hydr_vg_alpha_node' + name = 'fates_hydro_vg_alpha_node' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_2d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_hydr_vg_m_node' + name = 'fates_hydro_vg_m_node' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_2d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_hydr_vg_n_node' + name = 'fates_hydro_vg_n_node' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_2d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) @@ -1305,64 +1566,64 @@ subroutine Receive_PFT_hydr_organs(this, fates_params) character(len=param_string_length) :: name - name = 'fates_hydr_vg_alpha_node' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_hydro_vg_alpha_node' + call fates_params%RetrieveParameterAllocate(name=name, & data=this%hydr_vg_alpha_node) - name = 'fates_hydr_vg_m_node' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_hydro_vg_m_node' + call fates_params%RetrieveParameterAllocate(name=name, & data=this%hydr_vg_m_node) - name = 'fates_hydr_vg_n_node' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_hydro_vg_n_node' + call fates_params%RetrieveParameterAllocate(name=name, & data=this%hydr_vg_n_node) - name = 'fates_hydr_avuln_node' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_hydro_avuln_node' + call fates_params%RetrieveParameterAllocate(name=name, & data=this%hydr_avuln_node) - name = 'fates_hydr_p50_node' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_hydro_p50_node' + call fates_params%RetrieveParameterAllocate(name=name, & data=this%hydr_p50_node) - name = 'fates_hydr_thetas_node' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_hydro_thetas_node' + call fates_params%RetrieveParameterAllocate(name=name, & data=this%hydr_thetas_node) - name = 'fates_hydr_epsil_node' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_hydro_epsil_node' + call fates_params%RetrieveParameterAllocate(name=name, & data=this%hydr_epsil_node) - name = 'fates_hydr_pitlp_node' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_hydro_pitlp_node' + call fates_params%RetrieveParameterAllocate(name=name, & data=this%hydr_pitlp_node) - name = 'fates_hydr_resid_node' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_hydro_resid_node' + call fates_params%RetrieveParameterAllocate(name=name, & data=this%hydr_resid_node) - name = 'fates_hydr_fcap_node' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_hydro_fcap_node' + call fates_params%RetrieveParameterAllocate(name=name, & data=this%hydr_fcap_node) - name = 'fates_hydr_pinot_node' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_hydro_pinot_node' + call fates_params%RetrieveParameterAllocate(name=name, & data=this%hydr_pinot_node) - name = 'fates_hydr_kmax_node' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_hydro_kmax_node' + call fates_params%RetrieveParameterAllocate(name=name, & data=this%hydr_kmax_node) - name = 'fates_hydr_vg_alpha_node' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_hydro_vg_alpha_node' + call fates_params%RetrieveParameterAllocate(name=name, & data=this%hydr_vg_alpha_node) - name = 'fates_hydr_vg_m_node' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_hydro_vg_m_node' + call fates_params%RetrieveParameterAllocate(name=name, & data=this%hydr_vg_m_node) - name = 'fates_hydr_vg_n_node' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_hydro_vg_n_node' + call fates_params%RetrieveParameterAllocate(name=name, & data=this%hydr_vg_n_node) end subroutine Receive_PFT_hydr_organs @@ -1424,6 +1685,7 @@ subroutine FatesReportPFTParams(is_master) write(fates_log(),fmt0) 'mort_scalar_coldstress = ',EDPftvarcon_inst%mort_scalar_coldstress write(fates_log(),fmt0) 'mort_scalar_cstarvation = ',EDPftvarcon_inst%mort_scalar_cstarvation write(fates_log(),fmt0) 'mort_scalar_hydrfailure = ',EDPftvarcon_inst%mort_scalar_hydrfailure + write(fates_log(),fmt0) 'mort_upthresh_cstarvation = ',EDPftvarcon_inst%mort_upthresh_cstarvation write(fates_log(),fmt0) 'hf_sm_threshold = ',EDPftvarcon_inst%hf_sm_threshold write(fates_log(),fmt0) 'hf_flc_threshold = ',EDPftvarcon_inst%hf_flc_threshold write(fates_log(),fmt0) 'vcmaxha = ',EDPftvarcon_inst%vcmaxha @@ -1434,38 +1696,54 @@ 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) 'seed_dispersal_pdf_scale = ',EDPftvarcon_inst%seed_dispersal_pdf_scale + write(fates_log(),fmt0) 'seed_dispersal_pdf_shape = ',EDPftvarcon_inst%seed_dispersal_pdf_shape + write(fates_log(),fmt0) 'seed_dispersal_max_dist = ',EDPftvarcon_inst%seed_dispersal_max_dist + write(fates_log(),fmt0) 'seed_dispersal_fraction = ',EDPftvarcon_inst%seed_dispersal_fraction + 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) '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 + 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 write(fates_log(),fmt0) 'rhos = ',EDPftvarcon_inst%rhos write(fates_log(),fmt0) 'taul = ',EDPftvarcon_inst%taul write(fates_log(),fmt0) 'taus = ',EDPftvarcon_inst%taus - write(fates_log(),fmt0) 'phenflush_fraction',EDpftvarcon_inst%phenflush_fraction + write(fates_log(),fmt0) 'phen_flush_fraction',EDpftvarcon_inst%phenflush_fraction write(fates_log(),fmt0) 'phen_cold_size_threshold = ',EDPftvarcon_inst%phen_cold_size_threshold - write(fates_log(),fmt0) 'phen_stem_drop_fraction',EDpftvarcon_inst%phen_stem_drop_fraction write(fates_log(),fmt0) 'fire_alpha_SH = ',EDPftvarcon_inst%fire_alpha_SH - write(fates_log(),fmt0) 'allom_frbstor_repro = ',EDPftvarcon_inst%allom_frbstor_repro - write(fates_log(),fmt0) 'hydr_p_taper = ',EDPftvarcon_inst%hydr_p_taper - write(fates_log(),fmt0) 'hydr_rs2 = ',EDPftvarcon_inst%hydr_rs2 - write(fates_log(),fmt0) 'hydr_srl = ',EDPftvarcon_inst%hydr_srl - write(fates_log(),fmt0) 'hydr_rfrac_stem = ',EDPftvarcon_inst%hydr_rfrac_stem - write(fates_log(),fmt0) 'hydr_avuln_gs = ',EDPftvarcon_inst%hydr_avuln_gs - write(fates_log(),fmt0) 'hydr_k_lwp = ',EDPftvarcon_inst%hydr_k_lwp - write(fates_log(),fmt0) 'hydr_p50_gs = ',EDPftvarcon_inst%hydr_p50_gs - write(fates_log(),fmt0) 'hydr_k_lwp = ',EDPftvarcon_inst%hydr_k_lwp - write(fates_log(),fmt0) 'hydr_avuln_node = ',EDPftvarcon_inst%hydr_avuln_node - write(fates_log(),fmt0) 'hydr_p50_node = ',EDPftvarcon_inst%hydr_p50_node - write(fates_log(),fmt0) 'hydr_thetas_node = ',EDPftvarcon_inst%hydr_thetas_node - write(fates_log(),fmt0) 'hydr_epsil_node = ',EDPftvarcon_inst%hydr_epsil_node - write(fates_log(),fmt0) 'hydr_pitlp_node = ',EDPftvarcon_inst%hydr_pitlp_node - write(fates_log(),fmt0) 'hydr_resid_node = ',EDPftvarcon_inst%hydr_resid_node - write(fates_log(),fmt0) 'hydr_fcap_node = ',EDPftvarcon_inst%hydr_fcap_node - write(fates_log(),fmt0) 'hydr_pinot_node = ',EDPftvarcon_inst%hydr_pinot_node - write(fates_log(),fmt0) 'hydr_kmax_node = ',EDPftvarcon_inst%hydr_kmax_node + write(fates_log(),fmt0) 'allom_frbstor_repro = ',EDPftvarcon_inst%allom_frbstor_repro + write(fates_log(),fmt0) 'hydro_p_taper = ',EDPftvarcon_inst%hydr_p_taper + write(fates_log(),fmt0) 'hydro_rs2 = ',EDPftvarcon_inst%hydr_rs2 + write(fates_log(),fmt0) 'hydro_srl = ',EDPftvarcon_inst%hydr_srl + write(fates_log(),fmt0) 'hydro_rfrac_stem = ',EDPftvarcon_inst%hydr_rfrac_stem + write(fates_log(),fmt0) 'hydro_avuln_gs = ',EDPftvarcon_inst%hydr_avuln_gs + write(fates_log(),fmt0) 'hydro_k_lwp = ',EDPftvarcon_inst%hydr_k_lwp + write(fates_log(),fmt0) 'hydro_p50_gs = ',EDPftvarcon_inst%hydr_p50_gs + write(fates_log(),fmt0) 'hydro_avuln_node = ',EDPftvarcon_inst%hydr_avuln_node + write(fates_log(),fmt0) 'hydro_p50_node = ',EDPftvarcon_inst%hydr_p50_node + write(fates_log(),fmt0) 'hydro_thetas_node = ',EDPftvarcon_inst%hydr_thetas_node + write(fates_log(),fmt0) 'hydro_epsil_node = ',EDPftvarcon_inst%hydr_epsil_node + write(fates_log(),fmt0) 'hydro_pitlp_node = ',EDPftvarcon_inst%hydr_pitlp_node + write(fates_log(),fmt0) 'hydro_resid_node = ',EDPftvarcon_inst%hydr_resid_node + write(fates_log(),fmt0) 'hydro_fcap_node = ',EDPftvarcon_inst%hydr_fcap_node + write(fates_log(),fmt0) 'hydro_pinot_node = ',EDPftvarcon_inst%hydr_pinot_node + write(fates_log(),fmt0) 'hydro_kmax_node = ',EDPftvarcon_inst%hydr_kmax_node write(fates_log(),fmt0) 'hlm_pft_map = ', EDPftvarcon_inst%hlm_pft_map - write(fates_log(),fmt0) 'hydr_vg_alpha_node = ',EDPftvarcon_inst%hydr_vg_alpha_node - write(fates_log(),fmt0) 'hydr_vg_m_node = ',EDPftvarcon_inst%hydr_vg_m_node - write(fates_log(),fmt0) 'hydr_vg_n_node = ',EDPftvarcon_inst%hydr_vg_n_node + write(fates_log(),fmt0) 'hydro_vg_alpha_node = ',EDPftvarcon_inst%hydr_vg_alpha_node + write(fates_log(),fmt0) 'hydro_vg_m_node = ',EDPftvarcon_inst%hydr_vg_m_node + write(fates_log(),fmt0) 'hydro_vg_n_node = ',EDPftvarcon_inst%hydr_vg_n_node write(fates_log(),*) '-------------------------------------------------' end if @@ -1488,9 +1766,15 @@ subroutine FatesCheckParams(is_master) ! ----------------------------------------------------------------------------------- use FatesConstantsMod , only : fates_check_param_set use FatesConstantsMod , only : itrue, ifalse - use EDParamsMod , only : logging_mechanical_frac, logging_collateral_frac, logging_direct_frac - use FatesInterfaceTypesMod , only : hlm_use_fixed_biogeog,hlm_use_sp - + use FatesConstantsMod, only : tfrz => t_water_freeze_k_1atm + use FatesConstantsMod, only : lmr_r_1 + use FatesConstantsMod, only : lmr_r_2 + use EDParamsMod , only : logging_mechanical_frac, logging_collateral_frac + use EDParamsMod , only : logging_direct_frac,logging_export_frac + use EDParamsMod , only : radiation_model + use FatesInterfaceTypesMod, only : hlm_use_fixed_biogeog,hlm_use_sp, hlm_name + use FatesInterfaceTypesMod, only : hlm_use_inventory_init + ! Argument logical, intent(in) :: is_master ! Only log if this is the master proc @@ -1505,13 +1789,37 @@ subroutine FatesCheckParams(is_master) integer :: fates_pft ! used in fixed biogeog mode real(r8) :: sumarea ! area of PFTs in nocomp mode. - + real(r8) :: neg_lmr_temp ! temperature at which lmr would got negative + real(r8) :: r_0 ! base respiartion rate, PFT-dependent + real(r8) :: lnc_top ! leaf nitrogen content at top of canopy + + npft = size(EDPftvarcon_inst%freezetol,1) if(.not.is_master) return + if(radiation_model.ne.1) then + write(fates_log(),*) 'The only available canopy radiation model' + write(fates_log(),*) 'is the Norman scheme: fates_rad_model = 1' + write(fates_log(),*) 'The two-stream scheme is not available yet' + write(fates_log(),*) 'You specified fates_rad_model = ',radiation_model + write(fates_log(),*) 'Aborting' + 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 - if (hlm_parteh_mode .eq. prt_cnp_flex_allom_hyp) then + + select case (hlm_parteh_mode) + case (prt_cnp_flex_allom_hyp) ! Check to see if either RD/ECA/MIC is turned on @@ -1523,6 +1831,7 @@ subroutine FatesCheckParams(is_master) call endrun(msg=errMsg(sourcefile, __LINE__)) end if + ! If nitrogen is turned on, check to make sure there are valid ammonium ! parameters if(hlm_nitrogen_spec>0)then @@ -1546,41 +1855,43 @@ subroutine FatesCheckParams(is_master) end if end if + + ! If any PFTs are specified as either prescribed N or P uptake + ! then they all must be ! + + if (any(EDPftvarcon_inst%prescribed_nuptake(:) < -nearzero ) .or. & + any(EDPftvarcon_inst%prescribed_nuptake(:) > 10._r8 ) ) then + write(fates_log(),*) 'Negative values for EDPftvarcon_inst%prescribed_nuptake(:)' + write(fates_log(),*) 'are not allowed. Reasonable ranges for this parameter are zero' + write(fates_log(),*) 'to something slightly larger than 1, so we set a cap at 10.' + write(fates_log(),*) 'Set to zero to turn off and use coupled nutrients.' + write(fates_log(),*) ' Aborting' + call endrun(msg=errMsg(sourcefile, __LINE__)) + elseif (any(abs(EDPftvarcon_inst%prescribed_nuptake(:)) > nearzero )) then + if(.not.all(abs(EDPftvarcon_inst%prescribed_nuptake(:)) > nearzero )) then + write(fates_log(),*) 'If any PFTs are specified as having prescribed N' + write(fates_log(),*) 'uptake, then they must all. Note, prescribed' + write(fates_log(),*) 'rates are associated with any value abs(x)>nearzero' + write(fates_log(),*) 'EDPftvarcon_inst%prescribed_nuptake(:):', & + EDPftvarcon_inst%prescribed_nuptake(:) + write(fates_log(),*) ' Aborting' + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + end if + + + case (prt_carbon_allom_hyp) + ! No additional checks needed for now. + continue - elseif (hlm_parteh_mode .ne. prt_carbon_allom_hyp) then + case default write(fates_log(),*) 'FATES Plant Allocation and Reactive Transport has' write(fates_log(),*) 'only 2 modules supported, allometric carbon and CNP.' write(fates_log(),*) 'fates_parteh_mode must be set to 1 or 2 in the namelist' write(fates_log(),*) 'Aborting' call endrun(msg=errMsg(sourcefile, __LINE__)) - end if - - ! If any PFTs are specified as either prescribed N or P uptake - ! then they all must be ! - - if (any(EDPftvarcon_inst%prescribed_nuptake(:) < -nearzero ) .or. & - any(EDPftvarcon_inst%prescribed_nuptake(:) > 10._r8 ) ) then - write(fates_log(),*) 'Negative values for EDPftvarcon_inst%prescribed_nuptake(:)' - write(fates_log(),*) 'are not allowed. Reasonable ranges for this parameter are zero' - write(fates_log(),*) 'to something slightly larger than 1, so we set a cap at 10.' - write(fates_log(),*) 'Set to zero to turn off and use coupled nutrients.' - write(fates_log(),*) ' Aborting' - call endrun(msg=errMsg(sourcefile, __LINE__)) - elseif (any(abs(EDPftvarcon_inst%prescribed_nuptake(:)) > nearzero )) then - if(.not.all(abs(EDPftvarcon_inst%prescribed_nuptake(:)) > nearzero )) then - write(fates_log(),*) 'If any PFTs are specified as having prescribed N' - write(fates_log(),*) 'uptake, then they must all. Note, prescribed' - write(fates_log(),*) 'rates are associated with any value abs(x)>nearzero' - write(fates_log(),*) 'EDPftvarcon_inst%prescribed_nuptake(:):', & - EDPftvarcon_inst%prescribed_nuptake(:) - write(fates_log(),*) ' Aborting' - call endrun(msg=errMsg(sourcefile, __LINE__)) - end if - n_uptake_mode = prescribed_n_uptake - else - n_uptake_mode = coupled_n_uptake - end if + end select ! logging parameters, make sure they make sense if ( (logging_mechanical_frac + logging_collateral_frac + logging_direct_frac) .gt. 1._r8) then @@ -1609,16 +1920,80 @@ subroutine FatesCheckParams(is_master) write(fates_log(),*) ' Aborting' call endrun(msg=errMsg(sourcefile, __LINE__)) end if - p_uptake_mode = prescribed_p_uptake - else - p_uptake_mode = coupled_p_uptake end if + do ipft = 1,npft + ! xl must be between -0.4 and 0.6 according to Bonan (2019) doi:10.1017/9781107339217 pg. 238 + !----------------------------------------------------------------------------------- + if (EDPftvarcon_inst%xl(ipft) < -0.4 .or. EDPftvarcon_inst%xl(ipft) > 0.6) then + write(fates_log(),*) 'fates_rad_leaf_xl for pft ', ipft, ' is outside the allowed range of -0.4 to 0.6' + write(fates_log(),*) 'Aborting' + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if - do ipft = 1,npft + ! Check that the seed dispersal parameters are all set if one of them is set + !----------------------------------------------------------------------------------- + if (( EDPftvarcon_inst%seed_dispersal_pdf_scale(ipft) < fates_check_param_set ) .and. & + (( EDPftvarcon_inst%seed_dispersal_max_dist(ipft) > fates_check_param_set ) .or. & + ( EDPftvarcon_inst%seed_dispersal_pdf_shape(ipft) > fates_check_param_set ) .or. & + ( EDPftvarcon_inst%seed_dispersal_fraction(ipft) > fates_check_param_set ))) then + + write(fates_log(),*) 'Seed dispersal is on per fates_seed_dispersal_pdf_scale being set' + write(fates_log(),*) 'Please provide values for all other seed_dispersal parameters' + write(fates_log(),*) 'See Bullock et al. (2017) for reasonable values' + write(fates_log(),*) 'Aborting' + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + if (( EDPftvarcon_inst%seed_dispersal_pdf_shape(ipft) < fates_check_param_set ) .and. & + (( EDPftvarcon_inst%seed_dispersal_max_dist(ipft) > fates_check_param_set ) .or. & + ( EDPftvarcon_inst%seed_dispersal_pdf_scale(ipft) > fates_check_param_set ) .or. & + ( EDPftvarcon_inst%seed_dispersal_fraction(ipft) > fates_check_param_set ))) then + + write(fates_log(),*) 'Seed dispersal is on per fates_seed_dispersal_pdf_shape being set' + write(fates_log(),*) 'Please provide values for all other seed_dispersal parameters' + write(fates_log(),*) 'See Bullock et al. (2017) for reasonable values' + write(fates_log(),*) 'Aborting' + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + + if (( EDPftvarcon_inst%seed_dispersal_max_dist(ipft) < fates_check_param_set ) .and. & + (( EDPftvarcon_inst%seed_dispersal_pdf_shape(ipft) > fates_check_param_set ) .or. & + ( EDPftvarcon_inst%seed_dispersal_pdf_scale(ipft) > fates_check_param_set ) .or. & + ( EDPftvarcon_inst%seed_dispersal_fraction(ipft) > fates_check_param_set ))) then + + write(fates_log(),*) 'Seed dispersal is on per seed_dispersal_max_dist being set' + write(fates_log(),*) 'Please provide values for all other seed_dispersal parameters' + write(fates_log(),*) 'See Bullock et al. (2017) for reasonable values' + write(fates_log(),*) 'Aborting' + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + + if (( EDPftvarcon_inst%seed_dispersal_fraction(ipft) < fates_check_param_set ) .and. & + (( EDPftvarcon_inst%seed_dispersal_pdf_shape(ipft) > fates_check_param_set ) .or. & + ( EDPftvarcon_inst%seed_dispersal_pdf_scale(ipft) > fates_check_param_set ) .or. & + ( EDPftvarcon_inst%seed_dispersal_max_dist(ipft) > fates_check_param_set ))) then + + write(fates_log(),*) 'Seed dispersal is on per seed_dispersal_fraction being set' + write(fates_log(),*) 'Please provide values for all other seed_dispersal parameters' + write(fates_log(),*) 'See Bullock et al. (2017) for reasonable values' + write(fates_log(),*) 'Aborting' + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + + ! Check that parameter ranges for the seed dispersal fraction make sense + !----------------------------------------------------------------------------------- + if (( EDPftvarcon_inst%seed_dispersal_fraction(ipft) < fates_check_param_set ) .and. & + (( EDPftvarcon_inst%seed_dispersal_fraction(ipft) > 1.0_r8 ) .or. & + ( EDPftvarcon_inst%seed_dispersal_fraction(ipft) < 0.0_r8 ))) then + write(fates_log(),*) 'Seed dispersal is on per seed_dispersal_fraction being set' + write(fates_log(),*) 'Please make sure the fraction value is between 0 and 1' + write(fates_log(),*) 'Aborting' + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + ! Check that parameter ranges for age-dependent mortality make sense !----------------------------------------------------------------------------------- if ( ( EDPftvarcon_inst%mort_ip_age_senescence(ipft) < fates_check_param_set ) .and. & @@ -1672,8 +2047,7 @@ subroutine FatesCheckParams(is_master) ! Check if the fraction of storage used for flushing deciduous trees ! is greater than zero, and less than or equal to 1. - - if ( int(prt_params%evergreen(ipft)) .ne. 1 ) then + if (prt_params%evergreen(ipft) == ifalse) then if ( ( EDPftvarcon_inst%phenflush_fraction(ipft) < nearzero ) .or. & ( EDPFtvarcon_inst%phenflush_fraction(ipft) > 1 ) ) then @@ -1681,24 +2055,13 @@ subroutine FatesCheckParams(is_master) write(fates_log(),*) ' on bud-burst. If phenflush_fraction is not greater than 0' write(fates_log(),*) ' it will not be able to put out any leaves. Plants need leaves.' write(fates_log(),*) ' PFT#: ',ipft - write(fates_log(),*) ' evergreen flag: (shold be 0):',int(prt_params%evergreen(ipft)) + write(fates_log(),*) ' evergreen flag: (should be 0):',int(prt_params%evergreen(ipft)) write(fates_log(),*) ' phenflush_fraction: ', EDPFtvarcon_inst%phenflush_fraction(ipft) write(fates_log(),*) ' Aborting' call endrun(msg=errMsg(sourcefile, __LINE__)) end if - if ( ( EDPftvarcon_inst%phen_stem_drop_fraction(ipft) < 0.0_r8 ) .or. & - ( EDPFtvarcon_inst%phen_stem_drop_fraction(ipft) > 1 ) ) then - write(fates_log(),*) ' Deciduous non-wood plants must keep 0-100% of their stems' - write(fates_log(),*) ' during the deciduous period.' - write(fates_log(),*) ' PFT#: ',ipft - write(fates_log(),*) ' evergreen flag: (shold be 0):',int(prt_params%evergreen(ipft)) - write(fates_log(),*) ' phen_stem_drop_fraction: ', EDPFtvarcon_inst%phen_stem_drop_fraction(ipft) - write(fates_log(),*) ' Aborting' - call endrun(msg=errMsg(sourcefile, __LINE__)) - end if end if - ! Check if freezing tolerance is within reasonable bounds ! ---------------------------------------------------------------------------------- @@ -1716,7 +2079,22 @@ subroutine FatesCheckParams(is_master) end if - + ! Check that in initial density is not equal to zero in a cold-start run + !----------------------------------------------------------------------------------- + + if ( hlm_use_inventory_init == ifalse .and. & + abs( EDPftvarcon_inst%initd(ipft) ) < nearzero ) then + + write(fates_log(),*) ' In a cold start run initial density cannot be zero.' + write(fates_log(),*) ' For a bare ground run set to initial recruit density.' + write(fates_log(),*) ' If no-comp is on it is possible to initialize with larger ' + write(fates_log(),*) ' plants by setting fates_recruit_init_density to a negative number' + write(fates_log(),*) ' which will be interpreted as (absolute) initial dbh. ' + write(fates_log(),*) ' Aborting' + call endrun(msg=errMsg(sourcefile, __LINE__)) + + end if + ! Check if fraction of storage to reproduction is between 0-1 @@ -1771,6 +2149,32 @@ subroutine FatesCheckParams(is_master) end do !ipft + ! Check the temperature at which Rdark would become negative for each PFT - + ! given their parameters + !------------------------------------------------------------------------------------ + do ipft = 1,npft + + r_0 = EDPftvarcon_inst%maintresp_leaf_atkin2017_baserate(ipft) + + lnc_top = prt_params%nitr_stoich_p1(ipft, prt_params%organ_param_id(leaf_organ)) + + ! From LeafLayerMaintenanceRespiration_Atkin_etal_2017 + ! r_t_ref = nscaler * (r_0 + r_1 * lnc_top + r_2 * max(0._r8, (tgrowth - tfrz) )) + + ! find temperature at which whole term is negative + neg_lmr_temp = ( -1._r8 * ( r_0 + lmr_r_1 * lnc_top ) ) / lmr_r_2 + + write(fates_log(),*) 'PFT ', ipft + write(fates_log(),*) 'will have negative Rdark at ', neg_lmr_temp, 'degrees C' + write(fates_log(),*) 'with these values of slatop, nitrogen stoichiometry and' + write(fates_log(),*) 'maintresp_leaf_atkin2017_baserate.' + write(fates_log(),*) 'See LeafLayerMaintenanceRespiration_Atkin_etal_2017 in ' + write(fates_log(),*) 'FatesPlantRespPhotosynthMod' + + end do ! ipft + + + !! ! Checks for HYDRO !! if( hlm_use_planthydro == itrue ) then !! @@ -1792,7 +2196,6 @@ subroutine FatesCheckParams(is_master) !! end if !! end do - return end subroutine FatesCheckParams diff --git a/main/EDTypesMod.F90 b/main/EDTypesMod.F90 index 15360eaf43..3ceaa49396 100644 --- a/main/EDTypesMod.F90 +++ b/main/EDTypesMod.F90 @@ -1,6 +1,7 @@ module EDTypesMod use FatesConstantsMod, only : r8 => fates_r8 + use FatesGlobals, only : endrun => fates_endrun use FatesConstantsMod, only : ifalse use FatesConstantsMod, only : itrue use FatesGlobals, only : fates_log @@ -9,42 +10,32 @@ module EDTypesMod use PRTGenericMod, only : prt_vartypes use PRTGenericMod, only : leaf_organ, fnrt_organ, sapw_organ use PRTGenericMod, only : repro_organ, store_organ, struct_organ - use PRTGenericMod, only : all_carbon_elements + use PRTGenericMod, only : prt_carbon_allom_hyp + use PRTGenericMod, only : prt_cnp_flex_allom_hyp use PRTGenericMod, only : num_organ_types use PRTGenericMod, only : num_elements use PRTGenericMod, only : element_list use PRTGenericMod, only : num_element_types + use PRTGenericMod, only : carbon12_element use FatesLitterMod, only : litter_type - use FatesLitterMod, only : ncwd + use FatesLitterMod, only : ncwd, NFSC use FatesConstantsMod, only : n_anthro_disturbance_categories use FatesConstantsMod, only : days_per_year + use FatesRunningMeanMod, only : rmean_type,rmean_arr_type use FatesConstantsMod, only : fates_unset_r8 - use FatesRunningMeanMod, only : rmean_type use FatesInterfaceTypesMod,only : bc_in_type use FatesInterfaceTypesMod,only : bc_out_type + use FatesInterfaceTypesMod,only : hlm_parteh_mode + use FatesCohortMod, only : fates_cohort_type + use FatesPatchMod, only : fates_patch_type + use EDParamsMod, only : maxSWb, nclmax, nlevleaf, maxpft + use FatesConstantsMod, only : n_dbh_bins, n_dist_types + use shr_log_mod, only : errMsg => shr_log_errMsg - implicit none private ! By default everything is private save - - integer, parameter, public :: maxPatchesPerSite = 14 ! maximum number of patches to live on a site - integer, parameter, public :: maxPatchesPerSite_by_disttype(n_anthro_disturbance_categories) = & - (/ 10, 4 /) !!! MUST SUM TO maxPatchesPerSite !!! - integer, public :: maxCohortsPerPatch = 100 ! maximum number of cohorts per patch - - integer, parameter, public :: nclmax = 2 ! Maximum number of canopy layers - integer, parameter, public :: ican_upper = 1 ! Nominal index for the upper canopy - integer, parameter, public :: ican_ustory = 2 ! Nominal index for diagnostics that refer - ! to understory layers (all layers that - ! are not the top canopy layer) - - integer, parameter, public :: maxpft = 16 ! maximum number of PFTs allowed - ! the parameter file may determine that fewer - ! are used, but this helps allocate scratch - ! space and output arrays. - - + real(r8), parameter, public :: init_recruit_trim = 0.8_r8 ! This is the initial trimming value that ! new recruits start with @@ -54,49 +45,13 @@ module EDTypesMod ! this is ok for now. (RGK 04-2018) ! ------------------------------------------------------------------------------------- - integer, parameter, public :: n_rad_stream_types = 2 ! The number of radiation streams used (direct/diffuse) integer, parameter, public :: idirect = 1 ! This is the array index for direct radiation integer, parameter, public :: idiffuse = 2 ! This is the array index for diffuse radiation - ! parameters that govern the VAI (LAI+SAI) bins used in radiative transfer code - integer, parameter, public :: nlevleaf = 30 ! number of leaf+stem layers in canopy layer - real(r8), public :: dinc_vai(nlevleaf) = fates_unset_r8 ! VAI bin widths array - real(r8), public :: dlower_vai(nlevleaf) = fates_unset_r8 ! lower edges of VAI bins - - ! TODO: we use this cp_maxSWb only because we have a static array q(size=2) of - ! land-ice abledo for vis and nir. This should be a parameter, which would - ! get us on track to start using multi-spectral or hyper-spectral (RGK 02-2017) - - integer, parameter, public :: maxSWb = 2 ! maximum number of broad-bands in the - ! shortwave spectrum cp_numSWb <= cp_maxSWb - ! this is just for scratch-array purposes - ! if cp_numSWb is larger than this value - ! simply bump this number up as needed - - integer, parameter, public :: ivis = 1 ! This is the array index for short-wave - ! radiation in the visible spectrum, as expected - ! in boundary condition files and parameter - ! files. This will be compared with - ! the HLM's expectation in FatesInterfaceMod - integer, parameter, public :: inir = 2 ! This is the array index for short-wave - ! radiation in the near-infrared spectrum, as expected - ! in boundary condition files and parameter - ! files. This will be compared with - ! the HLM's expectation in FatesInterfaceMod - - integer, parameter, public :: ipar = ivis ! The photosynthetically active band - ! can be approximated to be equal to the visible band - - - integer, parameter, public :: leaves_on = 2 ! Flag specifying that a deciduous plant has leaves - ! and should be allocating to them as well - integer, parameter, public :: leaves_off = 1 ! Flag specifying that a deciduous plant has dropped - ! its leaves and should not be trying to allocate - ! towards any growth. - - ! Flag to turn on/off salinity effects on the effective "btran" + + ! Flag to turn on/off salinity effects on the effective "btran" ! btran stress function. logical, parameter, public :: do_fates_salinity = .false. @@ -127,12 +82,11 @@ module EDTypesMod ! The actual number of soil layers should not exceed this + + ! BIOLOGY/BIOGEOCHEMISTRY integer , parameter, public :: num_vegtemp_mem = 10 ! Window of time over which we track temp for cold sensecence (days) - integer , parameter, public :: N_DIST_TYPES = 3 ! Disturbance Modes 1) tree-fall, 2) fire, 3) logging - integer , parameter, public :: dtype_ifall = 1 ! index for naturally occuring tree-fall generated event - integer , parameter, public :: dtype_ifire = 2 ! index for fire generated disturbance event - integer , parameter, public :: dtype_ilog = 3 ! index for logging generated disturbance event + ! Phenology status flag definitions (cold type is cstat, dry type is dstat) @@ -145,31 +99,19 @@ module EDTypesMod integer, parameter, public :: phen_dstat_moistoff = 1 ! Leaves off due to moisture avail (drought phenology) integer, parameter, public :: phen_dstat_moiston = 2 ! Leaves on due to moisture avail (drought phenology) integer, parameter, public :: phen_dstat_timeon = 3 ! Leaves on due to time exceedance (drought phenology) - - - ! SPITFIRE - - integer, parameter, public :: NFSC = NCWD+2 ! number fuel size classes (4 cwd size classes, leaf litter, and grass) - integer, parameter, public :: tw_sf = 1 ! array index of twig pool for spitfire - integer, parameter, public :: lb_sf = 3 ! array index of large branch pool for spitfire - integer, parameter, public :: tr_sf = 4 ! array index of dead trunk pool for spitfire - integer, parameter, public :: dl_sf = 5 ! array index of dead leaf pool for spitfire (dead grass and dead leaves) - integer, parameter, public :: lg_sf = 6 ! array index of live grass pool for spitfire + integer, parameter, public :: phen_dstat_pshed = 4 ! Leaves partially abscissing (drought phenology) real(r8), parameter, public :: crown_fire_threshold = 200.0_r8 ! threshold for passive crown fire ignition. KWm-2 (Bessie & Johnson 1995) TODO slevis: see corresponding todo in SFMainMod.F90 ! PATCH FUSION real(r8), parameter, public :: force_patchfuse_min_biomass = 0.005_r8 ! min biomass (kg / m2 patch area) below which to force-fuse patches - integer , parameter, public :: N_DBH_BINS = 6 ! no. of dbh bins used when comparing patches - real(r8), parameter, public :: patchfusion_dbhbin_loweredges(N_DBH_BINS) = & - (/0._r8, 5._r8, 20._r8, 50._r8, 100._r8, 150._r8/) ! array of bin lower edges for comparing patches real(r8), parameter, public :: patch_fusion_tolerance_relaxation_increment = 1.1_r8 ! amount by which to increment patch fusion threshold real(r8), parameter, public :: max_age_of_second_oldest_patch = 200._r8 ! age in years above which to combine all patches ! COHORT FUSION - real(r8), parameter, public :: HITEMAX = 30.0_r8 ! max dbh value used in hgt profile comparison - integer , parameter, public :: N_HITE_BINS = 60 ! no. of hite bins used to distribute LAI + real(r8), parameter, public :: HEIGHTMAX = 30.0_r8 ! max dbh value used in hgt profile comparison + integer , parameter, public :: N_HEIGHT_BINS = 60 ! no. of height bins used to distribute LAI ! COHORT TERMINATION @@ -184,412 +126,10 @@ module EDTypesMod real(r8), parameter, public :: min_n_safemath = 1.0E-12_r8 ! in some cases, we want to immediately remove super small ! number densities of cohorts to prevent FPEs - character*4 yearchar - ! special mode to cause PFTs to create seed mass of all currently-existing PFTs logical, parameter, public :: homogenize_seed_pfts = .false. - - - ! Global identifier of how nutrients interact with the host land model - ! either they are fully coupled, or they generate uptake rates synthetically - ! in prescribed mode. In the latter, there is both NO mass removed from the HLM's soil - ! BGC N and P pools, and there is also none removed. - - integer, public :: n_uptake_mode - integer, public :: p_uptake_mode + character(len=*), parameter, private :: sourcefile = __FILE__ - !************************************ - !** COHORT type structure ** - !************************************ - type, public :: ed_cohort_type - - ! POINTERS - type (ed_cohort_type) , pointer :: taller => null() ! pointer to next tallest cohort - type (ed_cohort_type) , pointer :: shorter => null() ! pointer to next shorter cohort - type (ed_patch_type) , pointer :: patchptr => null() ! pointer to patch that cohort is in - - - - ! Multi-species, multi-organ Plant Reactive Transport (PRT) - ! Contains carbon and nutrient state variables for various plant organs - - class(prt_vartypes), pointer :: prt - - ! VEGETATION STRUCTURE - integer :: pft ! pft number - real(r8) :: n ! number of individuals in cohort per 'area' (10000m2 default) - real(r8) :: dbh ! dbh: cm - real(r8) :: coage ! cohort age in years - real(r8) :: hite ! height: meters - integer :: indexnumber ! unique number for each cohort. (within clump?) - real(r8) :: laimemory ! target leaf biomass- set from previous year: kGC per indiv - real(r8) :: sapwmemory ! target sapwood biomass- set from previous year: kGC per indiv - real(r8) :: structmemory ! target structural biomass- set from previous year: kGC per indiv - integer :: canopy_layer ! canopy status of cohort (1 = canopy, 2 = understorey, etc.) - real(r8) :: canopy_layer_yesterday ! recent canopy status of cohort - ! (1 = canopy, 2 = understorey, etc.) - ! real to be conservative during fusion - - real(r8) :: lai ! leaf area index of cohort: m2 leaf area of entire cohort per m2 of canopy area of a patch - real(r8) :: sai ! stem area index of cohort: m2 leaf area of entire cohort per m2 of canopy area of a patch - real(r8) :: g_sb_laweight ! Total conductance (stomata+boundary layer) of the cohort, weighted by its leaf area [m/s]*[m2] - real(r8) :: canopy_trim ! What is the fraction of the maximum leaf biomass that we are targeting? :- - real(r8) :: leaf_cost ! How much does it cost to maintain leaves: kgC/m2/year-1 - real(r8) :: excl_weight ! How much of this cohort is demoted each year, as a proportion of all cohorts:- - real(r8) :: prom_weight ! How much of this cohort is promoted each year, as a proportion of all cohorts:- - integer :: nv ! Number of leaf layers: - - integer :: status_coh ! growth status of plant (2 = leaves on , 1 = leaves off) - real(r8) :: c_area ! areal extent of canopy (m2) - real(r8) :: treelai ! lai of an individual within cohort leaf area (m2) / crown area (m2) - real(r8) :: treesai ! stem area index of an indiv. within cohort: stem area (m2) / crown area (m2) - logical :: isnew ! flag to signify a new cohort, new cohorts have not experienced - ! npp or mortality and should therefore not be fused or averaged - integer :: size_class ! An index that indicates which diameter size bin the cohort currently resides in - ! this is used for history output. We maintain this in the main cohort memory - ! because we don't want to continually re-calculate the cohort's position when - ! performing size diagnostics at high-frequency calls - integer :: coage_class ! An index that indicates which age bin the cohort currently resides in - ! used for history output. - integer :: size_by_pft_class ! An index that indicates the cohorts position of the joint size-class x functional - ! type classification. We also maintain this in the main cohort memory - ! because we don't want to continually re-calculate the cohort's position when - ! performing size diagnostics at high-frequency calls - integer :: coage_by_pft_class ! An index that indicates the cohorts position of the join cohort age class x PFT - integer :: size_class_lasttimestep ! size class of the cohort at the last time step - - ! CARBON FLUXES - - ! ---------------------------------------------------------------------------------- - ! NPP, GPP and RESP: Instantaneous, accumulated and accumulated-hold types.* - ! - ! _tstep: The instantaneous estimate that is calculated at each rapid plant biophysics - ! time-step (ie photosynthesis, sub-hourly). (kgC/indiv/timestep) - ! _acc: The accumulation of the _tstep variable from the beginning to ending of - ! the dynamics time-scale. This variable is zero'd during initialization and - ! after the dynamics call-sequence is completed. (kgC/indiv/day) - ! _acc_hold: While _acc is zero'd after the dynamics call sequence and then integrated, - ! _acc_hold "holds" the integrated value until the next time dynamics is - ! called. This is necessary for restarts. This variable also has units - ! converted to a useful rate (kgC/indiv/yr) - ! ---------------------------------------------------------------------------------- - - real(r8) :: gpp_tstep ! Gross Primary Production (see above *) - real(r8) :: gpp_acc - real(r8) :: gpp_acc_hold - - real(r8) :: npp_tstep ! Net Primary Production (see above *) - real(r8) :: npp_acc - real(r8) :: npp_acc_hold - - real(r8) :: resp_tstep ! Autotrophic respiration (see above *) - real(r8) :: resp_acc - real(r8) :: resp_acc_hold - - ! carbon 13c discrimination - real(r8) :: c13disc_clm ! carbon 13 discrimination in new synthesized carbon: part-per-mil, at each indiv/timestep - real(r8) :: c13disc_acc ! carbon 13 discrimination in new synthesized carbon: part-per-mil, at each indiv/day, at the end of a day - - ! Nutrient Fluxes (if N, P, etc. are turned on) - - real(r8) :: daily_nh4_uptake ! integrated daily uptake of mineralized ammonium through competitive acquisition in soil [kg N / plant/ day] - real(r8) :: daily_no3_uptake ! integrated daily uptake of mineralized nitrate through competitive acquisition in soil [kg N / plant/ day] - real(r8) :: daily_p_uptake ! integrated daily uptake of mineralized P through competitive acquisition in soil [kg P / plant/ day] - - real(r8) :: daily_c_efflux ! daily mean efflux of excess carbon from roots into labile pool [kg C/plant/day] - real(r8) :: daily_n_efflux ! daily mean efflux of excess nitrogen from roots into labile pool [kg N/plant/day] - real(r8) :: daily_p_efflux ! daily mean efflux of excess phophorus from roots into labile pool [kg P/plant/day] - - real(r8) :: daily_n_need ! Generic Nitrogen need of the plant, (hypothesis dependent) [kgN/plant/day] - real(r8) :: daily_p_need ! Generic Phosphorus need of the plant, (hypothesis dependent) [kgN/plant/day] - - - ! These two variables may use the previous "need" variables, by applying a smoothing function. - ! These variables are used in two scenarios. 1) They work with the prescribed uptake fraction - ! in un-coupled mode, and 2) They are the plant's demand subbmitted to the Relative-Demand - ! type soil BGC scheme. - - real(r8) :: daily_n_demand ! The daily amount of N demanded by the plant [kgN] - real(r8) :: daily_p_demand ! The daily amount of P demanded by the plant [kgN] - - - ! The following four biophysical rates are assumed to be - ! at the canopy top, at reference temp 25C, and based on the - ! leaf age weighted average of the PFT parameterized values. The last - ! condition is why it is dynamic and tied to the cohort - - real(r8) :: vcmax25top ! Maximum carboxylation at the cohort's top - ! at reference temperature (25C). - real(r8) :: jmax25top ! canopy top: maximum electron transport - ! rate at 25C (umol electrons/m**2/s) - real(r8) :: tpu25top ! canopy top: triose phosphate utilization - ! rate at 25C (umol CO2/m**2/s) - real(r8) :: kp25top ! canopy top: initial slope of CO2 response - ! curve (C4 plants) at 25C - - - - real(r8) :: ts_net_uptake(nlevleaf) ! Net uptake of leaf layers: kgC/m2/timestep - real(r8) :: year_net_uptake(nlevleaf) ! Net uptake of leaf layers: kgC/m2/year - - ! RESPIRATION COMPONENTS - real(r8) :: rdark ! Dark respiration: kgC/indiv/s - - real(r8) :: resp_g_tstep ! Growth respiration: kgC/indiv/timestep - real(r8) :: resp_m ! Maintenance respiration: kgC/indiv/timestep - real(r8) :: resp_m_def ! Optional: (NOT IMPLEMENTED YET) - ! It may be possible to not respire at desired rate - ! because of low carbon stores, and thus build - ! up a deficit. This tracks that deficit. kgC/indiv - real(r8) :: livestem_mr ! Live stem maintenance respiration: kgC/indiv/s - ! (Above ground) - real(r8) :: livecroot_mr ! Live stem maintenance respiration: kgC/indiv/s - ! (below ground) - real(r8) :: froot_mr ! Live fine root maintenance respiration: kgC/indiv/s - - !MORTALITY - real(r8) :: dmort ! proportional mortality rate. (year-1) - - ! Mortality Rate Partitions - real(r8) :: bmort ! background mortality rate n/year - real(r8) :: cmort ! carbon starvation mortality rate n/year - real(r8) :: hmort ! hydraulic failure mortality rate n/year - real(r8) :: frmort ! freezing mortality n/year - real(r8) :: smort ! senesence mortality n/year - real(r8) :: asmort ! age senescence mortality n/year - - ! Logging Mortality Rate - ! Yi Xu & M. Huang - real(r8) :: lmort_direct ! directly logging rate fraction /per logging activity - real(r8) :: lmort_collateral ! collaterally damaged rate fraction /per logging activity - real(r8) :: lmort_infra ! mechanically damaged rate fraction /per logging activity - real(r8) :: l_degrad ! rate of trees that are not killed but suffer from forest degradation - ! (i.e. they are moved to newly-anthro-disturbed secondary - ! forest patch). fraction /per logging activity - - real(r8) :: seed_prod ! diagnostic seed production rate [kgC/plant/day] - - ! NITROGEN POOLS - ! ---------------------------------------------------------------------------------- - ! Nitrogen pools are not prognostic in the current implementation. - ! They are diagnosed during photosynthesis using a simple C2N parameter. Local values - ! used in that routine. - ! ---------------------------------------------------------------------------------- - - ! GROWTH DERIVIATIVES - real(r8) :: dndt ! time derivative of cohort size : n/year - real(r8) :: dhdt ! time derivative of height : m/year - real(r8) :: ddbhdt ! time derivative of dbh : cm/year - real(r8) :: dbdeaddt ! time derivative of dead biomass : KgC/year - - ! FIRE - real(r8) :: fraction_crown_burned ! proportion of crown affected by fire:- - real(r8) :: cambial_mort ! probability that trees dies due to cambial char - ! (conditional on the tree being subjected to the fire) - real(r8) :: crownfire_mort ! probability of tree post-fire mortality - ! due to crown scorch (conditional on the tree being subjected to the fire) - real(r8) :: fire_mort ! post-fire mortality from cambial and crown damage assuming two are independent:- - - ! Hydraulics - type(ed_cohort_hydr_type), pointer :: co_hydr ! All cohort hydraulics data, see FatesHydraulicsMemMod.F90 - - - ! Running means - - ! (keeping this in-code as an example) - !class(rmean_type), pointer :: tveg_lpa ! exponential moving average of leaf temperature at the - ! leaf photosynthetic acclimation time-scale [K] - - - end type ed_cohort_type - - !************************************ - !** Patch type structure ** - !************************************ - - type, public :: ed_patch_type - - ! POINTERS - type (ed_cohort_type), pointer :: tallest => null() ! pointer to patch's tallest cohort - type (ed_cohort_type), pointer :: shortest => null() ! pointer to patch's shortest cohort - type (ed_patch_type), pointer :: older => null() ! pointer to next older patch - type (ed_patch_type), pointer :: younger => null() ! pointer to next younger patch - - !INDICES - integer :: patchno ! unique number given to each new patch created for tracking - - ! PATCH INFO - real(r8) :: age ! average patch age: years - integer :: age_class ! age class of the patch for history binning purposes - real(r8) :: area ! patch area: m2 - integer :: countcohorts ! Number of cohorts in patch - integer :: ncl_p ! Number of occupied canopy layers - integer :: anthro_disturbance_label ! patch label for anthropogenic disturbance classification - real(r8) :: age_since_anthro_disturbance ! average age for secondary forest since last anthropogenic disturbance - - - ! Running means - !class(rmean_type), pointer :: t2m ! Place-holder for 2m air temperature (variable window-size) - class(rmean_type), pointer :: tveg24 ! 24-hour mean vegetation temperature (K) - class(rmean_type), pointer :: tveg_lpa ! Running mean of vegetation temperature at the - ! leaf photosynthesis acclimation timescale [K] - 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 - ! used to determine attenuation of parameters during - ! photosynthesis m2 veg / m2 of canopy area (patch without bare ground) - real(r8) :: total_canopy_area ! area that is covered by vegetation : m2 - real(r8) :: total_tree_area ! area that is covered by woody vegetation : m2 - real(r8) :: zstar ! height of smallest canopy tree -- only meaningful in "strict PPA" mode - - real(r8) :: c_stomata ! Mean stomatal conductance of all leaves in the patch [umol/m2/s] - real(r8) :: c_lblayer ! Mean boundary layer conductance of all leaves in the patch [umol/m2/s] - - ! UNITS for the ai profiles - ! [ m2 leaf / m2 contributing crown footprints] - real(r8) :: tlai_profile(nclmax,maxpft,nlevleaf) ! total leaf area in each canopy layer, pft, and leaf layer. - real(r8) :: elai_profile(nclmax,maxpft,nlevleaf) ! exposed leaf area in each canopy layer, pft, and leaf layer - real(r8) :: tsai_profile(nclmax,maxpft,nlevleaf) ! total stem area in each canopy layer, pft, and leaf layer - real(r8) :: esai_profile(nclmax,maxpft,nlevleaf) ! exposed stem area in each canopy layer, pft, and leaf layer - real(r8) :: radiation_error ! radiation error (w/m2) - real(r8) :: layer_height_profile(nclmax,maxpft,nlevleaf) - real(r8) :: canopy_area_profile(nclmax,maxpft,nlevleaf) ! fraction of crown area per canopy area in each layer - ! they will sum to 1.0 in the fully closed canopy layers - ! but only in leaf-layers that contain contributions - ! from all cohorts that donate to canopy_area - - - ! layer, pft, and leaf layer:- - integer :: canopy_mask(nclmax,maxpft) ! is there any of this pft in this canopy layer? - integer :: nrad(nclmax,maxpft) ! number of exposed leaf layers for each canopy layer and pft - integer :: ncan(nclmax,maxpft) ! number of total leaf layers for each canopy layer and pft - - !RADIATION FLUXES - real(r8) :: fcansno ! Fraction of canopy covered in snow - - logical :: solar_zenith_flag ! integer flag specifying daylight (based on zenith angle) - real(r8) :: solar_zenith_angle ! solar zenith angle (radians) - - real(r8) :: gnd_alb_dif(maxSWb) ! ground albedo for diffuse rad, both bands (fraction) - real(r8) :: gnd_alb_dir(maxSWb) ! ground albedo for direct rad, both bands (fraction) - - real(r8) :: fabd_sun_z(nclmax,maxpft,nlevleaf) ! sun fraction of direct light absorbed by each canopy - ! layer, pft, and leaf layer:- - real(r8) :: fabd_sha_z(nclmax,maxpft,nlevleaf) ! shade fraction of direct light absorbed by each canopy - ! layer, pft, and leaf layer:- - real(r8) :: fabi_sun_z(nclmax,maxpft,nlevleaf) ! sun fraction of indirect light absorbed by each canopy - ! layer, pft, and leaf layer:- - real(r8) :: fabi_sha_z(nclmax,maxpft,nlevleaf) ! shade fraction of indirect light absorbed by each canopy - ! layer, pft, and leaf layer:- - - real(r8) :: ed_laisun_z(nclmax,maxpft,nlevleaf) ! amount of LAI in the sun in each canopy layer, - ! pft, and leaf layer. m2/m2 - real(r8) :: ed_laisha_z(nclmax,maxpft,nlevleaf) ! amount of LAI in the shade in each canopy layer, - real(r8) :: ed_parsun_z(nclmax,maxpft,nlevleaf) ! PAR absorbed in the sun in each canopy layer, - real(r8) :: ed_parsha_z(nclmax,maxpft,nlevleaf) ! PAR absorbed in the shade in each canopy layer, - real(r8) :: f_sun(nclmax,maxpft,nlevleaf) ! fraction of leaves in the sun in each canopy layer, pft, - - ! radiation profiles for comparison against observations - - ! normalized direct photosynthetically active radiation profiles by - ! incident type (direct/diffuse at top of canopy),leaf,pft,leaf (unitless) - real(r8) :: nrmlzd_parprof_pft_dir_z(n_rad_stream_types,nclmax,maxpft,nlevleaf) - - ! normalized diffuse photosynthetically active radiation profiles by - ! incident type (direct/diffuse at top of canopy),leaf,pft,leaf (unitless) - real(r8) :: nrmlzd_parprof_pft_dif_z(n_rad_stream_types,nclmax,maxpft,nlevleaf) - - ! normalized direct photosynthetically active radiation profiles by - ! incident type (direct/diffuse at top of canopy),leaf,leaf (unitless) - real(r8) :: nrmlzd_parprof_dir_z(n_rad_stream_types,nclmax,nlevleaf) - - ! normalized diffuse photosynthetically active radiation profiles by - ! incident type (direct/diffuse at top of canopy),leaf,leaf (unitless) - real(r8) :: nrmlzd_parprof_dif_z(n_rad_stream_types,nclmax,nlevleaf) - - real(r8) :: parprof_pft_dir_z(nclmax,maxpft,nlevleaf) ! direct-beam PAR profile through canopy, by canopy,PFT,leaf level (w/m2) - real(r8) :: parprof_pft_dif_z(nclmax,maxpft,nlevleaf) ! diffuse PAR profile through canopy, by canopy,PFT,leaf level (w/m2) - real(r8) :: parprof_dir_z(nclmax,nlevleaf) ! direct-beam PAR profile through canopy, by canopy,leaf level (w/m2) - real(r8) :: parprof_dif_z(nclmax,nlevleaf) ! diffuse PAR profile through canopy, by canopy,leaf level (w/m2) - - ! and leaf layer. m2/m2 - real(r8),allocatable :: tr_soil_dir(:) ! fraction of incoming direct radiation that (cm_numSWb) - ! is transmitted to the soil as direct - real(r8),allocatable :: tr_soil_dif(:) ! fraction of incoming diffuse radiation that - ! is transmitted to the soil as diffuse - real(r8),allocatable :: tr_soil_dir_dif(:) ! fraction of incoming direct radiation that - ! is transmitted to the soil as diffuse - real(r8),allocatable :: fab(:) ! fraction of incoming total radiation that is absorbed by the canopy - real(r8),allocatable :: fabd(:) ! fraction of incoming direct radiation that is absorbed by the canopy - real(r8),allocatable :: fabi(:) ! fraction of incoming diffuse radiation that is absorbed by the canopy - real(r8),allocatable :: sabs_dir(:) ! fraction of incoming direct radiation that is absorbed by the canopy - real(r8),allocatable :: sabs_dif(:) ! fraction of incoming diffuse radiation that is absorbed by the canopy - - - ! PHOTOSYNTHESIS - - real(r8) :: psn_z(nclmax,maxpft,nlevleaf) ! carbon assimilation in each canopy layer, pft, and leaf layer. umolC/m2/s - - ! ROOTS - real(r8) :: btran_ft(maxpft) ! btran calculated seperately for each PFT:- - real(r8) :: bstress_sal_ft(maxpft) ! bstress from salinity calculated seperately for each PFT:- - - - ! DISTURBANCE - real(r8) :: disturbance_rates(n_dist_types) ! disturbance rate from 1) mortality - ! 2) fire: fraction/day - ! 3) logging mortatliy - real(r8) :: disturbance_rate ! larger effective disturbance rate: fraction/day - integer :: disturbance_mode ! index identifying which disturbance was applied - ! can be one of: dtype_ifall, dtype_ilog or dtype_ifire - real(r8) :: fract_ldist_not_harvested ! fraction of logged area that is canopy trees that weren't harvested - - - ! Litter and Coarse Woody Debris - - type(litter_type), pointer :: litter(:) ! Litter (leaf,fnrt,CWD and seeds) for different elements - - real(r8),allocatable :: fragmentation_scaler(:) ! Scale rate of litter fragmentation based on soil layer. 0 to 1. - - !FUEL CHARECTERISTICS - real(r8) :: sum_fuel ! total ground fuel related to ros (omits 1000hr fuels): KgC/m2 - real(r8) :: fuel_frac(nfsc) ! fraction of each litter class in the ros_fuel:-. - real(r8) :: livegrass ! total aboveground grass biomass in patch. KgC/m2 - real(r8) :: fuel_bulkd ! average fuel bulk density of the ground fuel. kgBiomass/m3 - ! (incl. live grasses. omits 1000hr fuels). KgC/m3 - real(r8) :: fuel_sav ! average surface area to volume ratio of the ground fuel. cm-1 - ! (incl. live grasses. omits 1000hr fuels). - real(r8) :: fuel_mef ! average moisture of extinction factor - ! of the ground fuel (incl. live grasses. omits 1000hr fuels). - real(r8) :: fuel_eff_moist ! effective avearage fuel moisture content of the ground fuel - ! (incl. live grasses. omits 1000hr fuels) - real(r8) :: litter_moisture(nfsc) - - ! FIRE SPREAD - real(r8) :: ros_front ! rate of forward spread of fire: m/min - real(r8) :: ros_back ! rate of backward spread of fire: m/min - real(r8) :: effect_wspeed ! windspeed modified by fraction of relative grass and tree cover: m/min - real(r8) :: tau_l ! Duration of lethal heating: mins - real(r8) :: fi ! average fire intensity of flaming front: kj/m/s or kw/m - integer :: fire ! Is there a fire? 1=yes 0=no - real(r8) :: fd ! fire duration: mins - - ! FIRE EFFECTS - real(r8) :: scorch_ht(maxpft) ! scorch height: m - real(r8) :: frac_burnt ! fraction burnt: frac patch/day - real(r8) :: tfc_ros ! total intensity-relevant fuel consumed - no trunks. KgC/m2 of burned ground/day - real(r8) :: burnt_frac_litter(nfsc) ! fraction of each litter pool burned, conditional on it being burned - integer :: active_crown_fire_flg ! flag for active crown fire ignition - - - ! 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 - - !************************************ !** Resources management type ** ! YX @@ -597,6 +137,9 @@ module EDTypesMod type, public :: ed_resources_management_type real(r8) :: trunk_product_site ! Actual trunk product at site level KgC/site + real(r8) :: harvest_debt ! the amount of kgC per site that did not successfully harvested + real(r8) :: harvest_debt_sec ! the amount of kgC per site from secondary patches that did + ! not successfully harvested !debug variables real(r8) :: delta_litter_stock ! kgC/site = kgC/ha @@ -622,10 +165,6 @@ module EDTypesMod real(r8) :: cwd_bg_input(1:ncwd) real(r8),allocatable :: leaf_litter_input(:) real(r8),allocatable :: root_litter_input(:) - - real(r8),allocatable :: nutrient_uptake_scpf(:) - real(r8),allocatable :: nutrient_efflux_scpf(:) - real(r8),allocatable :: nutrient_need_scpf(:) contains @@ -658,7 +197,8 @@ module EDTypesMod real(r8) :: aresp_acc ! Accumulated autotrophic respiration [kg/site/day] real(r8) :: net_root_uptake ! Net uptake of carbon or nutrients through the roots [kg/site/day] - ! (if carbon most likely exudation, if even active) + ! could include exudation, and for N this also includes symbiotic + ! fixation real(r8) :: seed_in ! Total mass of external seed rain into fates site [kg/site/day] ! This is from external grid-cells or from user parameterization @@ -694,8 +234,8 @@ module EDTypesMod type, public :: ed_site_type ! POINTERS - type (ed_patch_type), pointer :: oldest_patch => null() ! pointer to oldest patch at the site - type (ed_patch_type), pointer :: youngest_patch => null() ! pointer to yngest patch at the site + type (fates_patch_type), pointer :: oldest_patch => null() ! pointer to oldest patch at the site + type (fates_patch_type), pointer :: youngest_patch => null() ! pointer to yngest patch at the site ! Resource management type (ed_resources_management_type) :: resources_management ! resources_management at the site @@ -719,6 +259,16 @@ module EDTypesMod ! Total area of patches in each age bin [m2] real(r8), allocatable :: area_by_age(:) + ! Nutrient relevant + real(r8), allocatable :: rec_l2fr(:,:) ! A running mean of the l2fr's for the newly + ! recruited, pft x canopy_layer + real(r8) :: ema_npp ! An exponential moving average of NPP [gC/m2/year] + ! The lengthscale is hard-coded "ema_npp_tcale" + ! in FatesSoilBGCFluxMod. Used solely to inform bc_out%ema_npp + ! which is used for fixation + + + ! SP mode target PFT level variables real(r8), allocatable :: sp_tlai(:) ! target TLAI per FATES pft real(r8), allocatable :: sp_tsai(:) ! target TSAI per FATES pft @@ -741,20 +291,32 @@ module EDTypesMod ! 400 days, leaves are dropped and flagged as non-cold region ! 1 = this site is in a cold-state where leaves should have fallen ! 2 = this site is in a warm-state where leaves are allowed to flush - integer :: dstatus ! are leaves in this pixel on or off for drought decid + integer :: dstatus(maxpft) ! are leaves in this pixel on or off for drought decid ! 0 = leaves off due to time exceedance ! 1 = leaves off due to moisture avail ! 2 = leaves on due to moisture avail ! 3 = leaves on due to time exceedance + ! 4 = leaves partially on (ED2-like phenology) integer :: nchilldays ! num chilling days: (for botta gdd trheshold calculation) integer :: ncolddays ! num cold days: (must exceed threshold to drop leaves) real(r8) :: vegtemp_memory(num_vegtemp_mem) ! record of last 10 days temperature for senescence model. deg C integer :: cleafondate ! model date (day integer) of leaf on (cold):- integer :: cleafoffdate ! model date (day integer) of leaf off (cold):- - integer :: dleafondate ! model date (day integer) of leaf on drought:- - integer :: dleafoffdate ! model date (day integer) of leaf off drought:- - - real(r8) :: water_memory(numWaterMem) ! last 10 days of soil moisture memory... + integer :: cndaysleafon ! number of days since leaf on period started (cold) + integer :: cndaysleafoff ! number of days since leaf off period started (cold) + integer :: dleafondate(maxpft) ! model date (day integer) of leaf on drought:- + integer :: dleafoffdate(maxpft) ! model date (day integer) of leaf off drought:- + integer :: dndaysleafon(maxpft) ! number of days since leaf on period started (drought) + integer :: dndaysleafoff(maxpft) ! number of days since leaf off period started (drought) + real(r8) :: elong_factor(maxpft) ! Elongation factor (ED2-like phenology). This is zero when leaves are + ! completely off, and one when they are completely flushed. + integer :: phen_model_date ! current model date (day integer) + ! this date stays continuous when + ! in runs that are restarted, regardless of + ! the conditions of restart + + real(r8) :: liqvol_memory(numWaterMem,maxpft) ! last 10 days of soil liquid water volume (drought phenology) + real(r8) :: smp_memory(numWaterMem,maxpft) ! last 10 days of soil matric potential (drought phenology) ! FIRE @@ -796,66 +358,90 @@ module EDTypesMod ! TERMINATION, RECRUITMENT, DEMOTION, and DISTURBANCE + real(r8) :: term_crownarea_canopy ! crownarea from termination mortality, per canopy level + real(r8) :: term_crownarea_ustory ! crownarea from termination mortality, per canopy level + + real(r8) :: imort_crownarea ! crownarea of individuals killed due to impact mortality per year. [m2 day] + + real(r8) :: fmort_crownarea_canopy ! crownarea of canopy indivs killed due to fire per year. [m2/sec] + real(r8) :: fmort_crownarea_ustory ! crownarea of understory indivs killed due to fire per year [m2/sec] + real(r8), allocatable :: term_nindivs_canopy(:,:) ! number of canopy individuals that were in cohorts which ! were terminated this timestep, on size x pft real(r8), allocatable :: term_nindivs_ustory(:,:) ! number of understory individuals that were in cohorts which ! were terminated this timestep, on size x pft - - real(r8) :: term_carbonflux_canopy ! carbon flux from live to dead pools associated - ! with termination mortality, per canopy level - real(r8) :: term_carbonflux_ustory ! carbon flux from live to dead pools associated - ! with termination mortality, per canopy level - real(r8) :: demotion_carbonflux ! biomass of demoted individuals from canopy to understory [kgC/ha/day] - real(r8) :: promotion_carbonflux ! biomass of promoted individuals from understory to canopy [kgC/ha/day] - real(r8) :: imort_carbonflux ! biomass of individuals killed due to impact mortality per year. [kgC/ha/day] - real(r8) :: fmort_carbonflux_canopy ! biomass of canopy indivs killed due to fire per year. [gC/m2/sec] - real(r8) :: fmort_carbonflux_ustory ! biomass of understory indivs killed due to fire per year [gC/m2/sec] - - real(r8) :: recruitment_rate(1:maxpft) ! number of individuals that were recruited into new cohorts - real(r8), allocatable :: demotion_rate(:) ! rate of individuals demoted from canopy to understory per FATES timestep - - real(r8), allocatable :: promotion_rate(:) ! rate of individuals promoted from understory to canopy per FATES timestep - - real(r8), allocatable :: imort_rate(:,:) ! rate of individuals killed due to impact mortality per year. on size x pft array + + real(r8), allocatable :: term_carbonflux_canopy(:) ! carbon flux from live to dead pools associated + ! with termination mortality, per canopy level. [kgC/ha/day] + real(r8), allocatable :: term_carbonflux_ustory(:) ! carbon flux from live to dead pools associated + ! with termination mortality, per canopy level. [kgC/ha/day] + real(r8), allocatable :: imort_carbonflux(:) ! biomass of individuals killed due to impact mortality per year. [kgC/m2/sec] + real(r8), allocatable :: fmort_carbonflux_canopy(:) ! biomass of canopy indivs killed due to fire per year. [gC/m2/sec] + real(r8), allocatable :: fmort_carbonflux_ustory(:) ! biomass of understory indivs killed due to fire per year [gC/m2/sec] + + real(r8), allocatable :: term_abg_flux(:,:) ! aboveground biomass lost due to termination mortality x size x pft + real(r8), allocatable :: imort_abg_flux(:,:) ! aboveground biomass lost due to impact mortality x size x pft [kgC/m2/sec] + real(r8), allocatable :: fmort_abg_flux(:,:) ! aboveground biomass lost due to fire mortality x size x pft + + + real(r8) :: demotion_carbonflux ! biomass of demoted individuals from canopy to understory [kgC/ha/day] + real(r8) :: promotion_carbonflux ! biomass of promoted individuals from understory to canopy [kgC/ha/day] + real(r8) :: recruitment_rate(1:maxpft) ! number of individuals that were recruited into new cohorts + real(r8), allocatable :: demotion_rate(:) ! rate of individuals demoted from canopy to understory per FATES timestep + real(r8), allocatable :: promotion_rate(:) ! rate of individuals promoted from understory to canopy per FATES timestep + real(r8), allocatable :: imort_rate(:,:) ! rate of individuals killed due to impact mortality per year. on size x pft array - real(r8), allocatable :: fmort_rate_canopy(:,:) ! rate of canopy individuals killed due to fire mortality per year. - ! on size x pft array (1:nlevsclass,1:numpft) - real(r8), allocatable :: fmort_rate_ustory(:,:) ! rate of understory individuals killed due to fire mortality per year. - ! on size x pft array (1:nlevsclass,1:numpft) + real(r8), allocatable :: fmort_rate_canopy(:,:) ! rate of canopy individuals killed due to fire mortality per year. + ! on size x pft array (1:nlevsclass,1:numpft) + real(r8), allocatable :: fmort_rate_ustory(:,:) ! rate of understory individuals killed due to fire mortality per year. + ! on size x pft array (1:nlevsclass,1:numpft) - real(r8), allocatable :: fmort_rate_cambial(:,:) ! rate of individuals killed due to fire mortality - ! from cambial damage per year. on size x pft array - real(r8), allocatable :: fmort_rate_crown(:,:) ! rate of individuals killed due to fire mortality - ! from crown damage per year. on size x pft array - - real(r8), allocatable :: growthflux_fusion(:,:) ! rate of individuals moving into a given size class bin - ! due to fusion in a given day. on size x pft array - - - + real(r8), allocatable :: fmort_rate_cambial(:,:) ! rate of individuals killed due to fire mortality + ! from cambial damage per year. on size x pft array + real(r8), allocatable :: fmort_rate_crown(:,:) ! rate of individuals killed due to fire mortality + ! from crown damage per year. on size x pft array + + real(r8), allocatable :: imort_rate_damage(:,:,:) ! number of individuals per damage class that die from impact mortality + real(r8), allocatable :: term_nindivs_canopy_damage(:,:,:) ! number of individuals per damage class that die from termination mortality - canopy + real(r8), allocatable :: term_nindivs_ustory_damage(:,:,:) ! number of individuals per damage class that die from termination mortality - canopy + real(r8), allocatable :: fmort_rate_canopy_damage(:,:,:) ! number of individuals per damage class that die from fire - canopy + real(r8), allocatable :: fmort_rate_ustory_damage(:,:,:) ! number of individuals per damage class that die from fire - ustory + real(r8), allocatable :: fmort_cflux_canopy_damage(:,:) ! cflux per damage class that die from fire - canopy + real(r8), allocatable :: fmort_cflux_ustory_damage(:,:) ! cflux per damage class that die from fire - ustory + real(r8), allocatable :: imort_cflux_damage(:,:) ! carbon flux from impact mortality by damage class [kgC/m2/sec] + real(r8), allocatable :: term_cflux_canopy_damage(:,:) ! carbon flux from termination mortality by damage class + real(r8), allocatable :: term_cflux_ustory_damage(:,:) ! carbon flux from termination mortality by damage class + + real(r8), allocatable :: growthflux_fusion(:,:) ! rate of individuals moving into a given size class bin + ! due to fusion in a given day. on size x pft array + + + real(r8) :: crownarea_canopy_damage ! crown area of canopy that is damaged annually + real(r8) :: crownarea_ustory_damage ! crown area of understory that is damaged annually + ! Canopy Spread real(r8) :: spread ! dynamic canopy allometric term [unitless] + ! Seed dispersal + real(r8), allocatable :: seed_out(:) ! amount of seed leaving the site [kg/site/day] + real(r8), allocatable :: seed_in(:) ! amount of seed dispersed into the site from neighbouring cells [kg/site/day] + ! site-level variables to keep track of the disturbance rates, both actual and "potential" real(r8) :: disturbance_rates_primary_to_primary(N_DIST_TYPES) ! actual disturbance rates from primary patches to primary patches [m2/m2/day] real(r8) :: disturbance_rates_primary_to_secondary(N_DIST_TYPES) ! actual disturbance rates from primary patches to secondary patches [m2/m2/day] real(r8) :: disturbance_rates_secondary_to_secondary(N_DIST_TYPES) ! actual disturbance rates from secondary patches to secondary patches [m2/m2/day] real(r8) :: potential_disturbance_rates(N_DIST_TYPES) ! "potential" disturb rates (i.e. prior to the "which is most" logic) [m2/m2/day] real(r8) :: primary_land_patchfusion_error ! error term in total area of primary patches associated with patch fusion [m2/m2/day] - real(r8) :: harvest_carbon_flux ! diagnostic site level flux of carbon as harvested plants [kg C / m2 / day] end type ed_site_type ! Make public necessary subroutines and functions - public :: val_check_ed_vars public :: dump_site - public :: dump_patch - public :: dump_cohort - public :: dump_cohort_hydr contains - + + ! ===================================================================================== subroutine ZeroFluxDiags(this) @@ -865,9 +451,6 @@ subroutine ZeroFluxDiags(this) this%cwd_bg_input(:) = 0._r8 this%leaf_litter_input(:) = 0._r8 this%root_litter_input(:) = 0._r8 - this%nutrient_uptake_scpf(:) = 0._r8 - this%nutrient_efflux_scpf(:) = 0._r8 - this%nutrient_need_scpf(:) = 0._r8 return end subroutine ZeroFluxDiags @@ -902,245 +485,25 @@ subroutine ZeroMassBalFlux(this) return end subroutine ZeroMassBalFlux - - ! ===================================================================================== - - subroutine val_check_ed_vars(currentPatch,var_aliases,return_code) - - ! ---------------------------------------------------------------------------------- - ! Perform numerical checks on variables of interest. - ! The input string is of the form: 'VAR1_NAME:VAR2_NAME:VAR3_NAME' - ! ---------------------------------------------------------------------------------- - - - use FatesUtilsMod,only : check_hlm_list - use FatesUtilsMod,only : check_var_real - - ! Arguments - type(ed_patch_type),intent(in), target :: currentPatch - character(len=*),intent(in) :: var_aliases - integer,intent(out) :: return_code ! return 0 for all fine - ! return 1 if a nan detected - ! return 10+ if an overflow - ! return 100% if an underflow - ! Locals - type(ed_cohort_type), pointer :: currentCohort - - - ! Check through a registry of variables to check - - if ( check_hlm_list(trim(var_aliases),'co_n') ) then - - currentCohort => currentPatch%shortest - do while(associated(currentCohort)) - call check_var_real(currentCohort%n,'cohort%n',return_code) - if(.not.(return_code.eq.0)) then - call dump_patch(currentPatch) - call dump_cohort(currentCohort) - return - end if - currentCohort => currentCohort%taller - end do - end if - - if ( check_hlm_list(trim(var_aliases),'co_dbh') ) then - - currentCohort => currentPatch%shortest - do while(associated(currentCohort)) - call check_var_real(currentCohort%dbh,'cohort%dbh',return_code) - if(.not.(return_code.eq.0)) then - call dump_patch(currentPatch) - call dump_cohort(currentCohort) - return - end if - currentCohort => currentCohort%taller - end do - end if - - if ( check_hlm_list(trim(var_aliases),'pa_area') ) then - - call check_var_real(currentPatch%area,'patch%area',return_code) - if(.not.(return_code.eq.0)) then - call dump_patch(currentPatch) - return - end if - end if - - - - return - end subroutine val_check_ed_vars - ! ===================================================================================== subroutine dump_site(csite) - type(ed_site_type),intent(in),target :: csite - + type(ed_site_type),intent(in),target :: csite - ! EDTypes is - write(fates_log(),*) '----------------------------------------' - write(fates_log(),*) ' Site Coordinates ' - write(fates_log(),*) '----------------------------------------' - write(fates_log(),*) 'latitude = ', csite%lat - write(fates_log(),*) 'longitude = ', csite%lon - write(fates_log(),*) '----------------------------------------' - return + ! EDTypes is - end subroutine dump_site + write(fates_log(),*) '----------------------------------------' + write(fates_log(),*) ' Site Coordinates ' + write(fates_log(),*) '----------------------------------------' + write(fates_log(),*) 'latitude = ', csite%lat + write(fates_log(),*) 'longitude = ', csite%lon + write(fates_log(),*) '----------------------------------------' + return - ! ===================================================================================== - - - subroutine dump_patch(cpatch) - - type(ed_patch_type),intent(in),target :: cpatch - - ! locals - integer :: el ! element loop counting index - - write(fates_log(),*) '----------------------------------------' - write(fates_log(),*) ' Dumping Patch Information ' - write(fates_log(),*) ' (omitting arrays) ' - write(fates_log(),*) '----------------------------------------' - write(fates_log(),*) 'pa%patchno = ',cpatch%patchno - write(fates_log(),*) 'pa%age = ',cpatch%age - write(fates_log(),*) 'pa%age_class = ',cpatch%age_class - write(fates_log(),*) 'pa%area = ',cpatch%area - write(fates_log(),*) 'pa%countcohorts = ',cpatch%countcohorts - write(fates_log(),*) 'pa%ncl_p = ',cpatch%ncl_p - write(fates_log(),*) 'pa%total_canopy_area = ',cpatch%total_canopy_area - write(fates_log(),*) 'pa%total_tree_area = ',cpatch%total_tree_area - write(fates_log(),*) 'pa%zstar = ',cpatch%zstar - write(fates_log(),*) 'pa%solar_zenith_flag = ',cpatch%solar_zenith_flag - write(fates_log(),*) 'pa%solar_zenith_angle = ',cpatch%solar_zenith_angle - write(fates_log(),*) 'pa%gnd_alb_dif = ',cpatch%gnd_alb_dif(:) - write(fates_log(),*) 'pa%gnd_alb_dir = ',cpatch%gnd_alb_dir(:) - write(fates_log(),*) 'pa%c_stomata = ',cpatch%c_stomata - write(fates_log(),*) 'pa%c_lblayer = ',cpatch%c_lblayer - write(fates_log(),*) 'pa%disturbance_rate = ',cpatch%disturbance_rate - write(fates_log(),*) 'pa%disturbance_rates = ',cpatch%disturbance_rates(:) - write(fates_log(),*) 'pa%anthro_disturbance_label = ', cpatch%anthro_disturbance_label - write(fates_log(),*) 'pa%active_crown_fire_flg = ', cpatch%active_crown_fire_flg - write(fates_log(),*) '----------------------------------------' - do el = 1,num_elements - write(fates_log(),*) 'element id: ',element_list(el) - write(fates_log(),*) 'seed mass: ',sum(cpatch%litter(el)%seed) - write(fates_log(),*) 'seed germ mass: ',sum(cpatch%litter(el)%seed_germ) - write(fates_log(),*) 'leaf fines(pft): ',sum(cpatch%litter(el)%leaf_fines) - write(fates_log(),*) 'root fines(pft,sl): ',sum(cpatch%litter(el)%root_fines) - write(fates_log(),*) 'ag_cwd(c): ',sum(cpatch%litter(el)%ag_cwd) - write(fates_log(),*) 'bg_cwd(c,sl): ',sum(cpatch%litter(el)%bg_cwd) - end do - - return - - end subroutine dump_patch - - ! ===================================================================================== +end subroutine dump_site - subroutine dump_cohort(ccohort) - - - type(ed_cohort_type),intent(in),target :: ccohort - - write(fates_log(),*) '----------------------------------------' - write(fates_log(),*) ' Dumping Cohort Information ' - write(fates_log(),*) '----------------------------------------' - write(fates_log(),*) 'co%pft = ', ccohort%pft - write(fates_log(),*) 'co%n = ', ccohort%n - write(fates_log(),*) 'co%dbh = ', ccohort%dbh - write(fates_log(),*) 'co%hite = ', ccohort%hite - write(fates_log(),*) 'co%coage = ', ccohort%coage - write(fates_log(),*) 'co%laimemory = ', ccohort%laimemory - write(fates_log(),*) 'co%sapwmemory = ', ccohort%sapwmemory - write(fates_log(),*) 'co%structmemory = ', ccohort%structmemory - - write(fates_log(),*) 'leaf carbon = ', ccohort%prt%GetState(leaf_organ,all_carbon_elements) - write(fates_log(),*) 'fineroot carbon = ', ccohort%prt%GetState(fnrt_organ,all_carbon_elements) - write(fates_log(),*) 'sapwood carbon = ', ccohort%prt%GetState(sapw_organ,all_carbon_elements) - write(fates_log(),*) 'structural (dead) carbon = ', ccohort%prt%GetState(struct_organ,all_carbon_elements) - write(fates_log(),*) 'storage carbon = ', ccohort%prt%GetState(store_organ,all_carbon_elements) - write(fates_log(),*) 'reproductive carbon = ', ccohort%prt%GetState(repro_organ,all_carbon_elements) - - write(fates_log(),*) 'co%lai = ', ccohort%lai - write(fates_log(),*) 'co%sai = ', ccohort%sai - write(fates_log(),*) 'co%g_sb_laweight = ', ccohort%g_sb_laweight - write(fates_log(),*) 'co%leaf_cost = ', ccohort%leaf_cost - write(fates_log(),*) 'co%canopy_layer = ', ccohort%canopy_layer - write(fates_log(),*) 'co%canopy_layer_yesterday = ', ccohort%canopy_layer_yesterday - write(fates_log(),*) 'co%nv = ', ccohort%nv - write(fates_log(),*) 'co%status_coh = ', ccohort%status_coh - write(fates_log(),*) 'co%canopy_trim = ', ccohort%canopy_trim - write(fates_log(),*) 'co%excl_weight = ', ccohort%excl_weight - write(fates_log(),*) 'co%prom_weight = ', ccohort%prom_weight - write(fates_log(),*) 'co%size_class = ', ccohort%size_class - write(fates_log(),*) 'co%size_by_pft_class = ', ccohort%size_by_pft_class - write(fates_log(),*) 'co%coage_class = ', ccohort%coage_class - write(fates_log(),*) 'co%coage_by_pft_class = ', ccohort%coage_by_pft_class - write(fates_log(),*) 'co%gpp_acc_hold = ', ccohort%gpp_acc_hold - write(fates_log(),*) 'co%gpp_acc = ', ccohort%gpp_acc - write(fates_log(),*) 'co%gpp_tstep = ', ccohort%gpp_tstep - write(fates_log(),*) 'co%npp_acc_hold = ', ccohort%npp_acc_hold - write(fates_log(),*) 'co%npp_tstep = ', ccohort%npp_tstep - write(fates_log(),*) 'co%npp_acc = ', ccohort%npp_acc - write(fates_log(),*) 'co%resp_tstep = ', ccohort%resp_tstep - write(fates_log(),*) 'co%resp_acc = ', ccohort%resp_acc - write(fates_log(),*) 'co%resp_acc_hold = ', ccohort%resp_acc_hold - write(fates_log(),*) 'co%rdark = ', ccohort%rdark - write(fates_log(),*) 'co%resp_m = ', ccohort%resp_m - write(fates_log(),*) 'co%resp_m_def = ', ccohort%resp_m_def - write(fates_log(),*) 'co%resp_g_tstep = ', ccohort%resp_g_tstep - write(fates_log(),*) 'co%livestem_mr = ', ccohort%livestem_mr - write(fates_log(),*) 'co%livecroot_mr = ', ccohort%livecroot_mr - write(fates_log(),*) 'co%froot_mr = ', ccohort%froot_mr - write(fates_log(),*) 'co%dmort = ', ccohort%dmort - write(fates_log(),*) 'co%treelai = ', ccohort%treelai - write(fates_log(),*) 'co%treesai = ', ccohort%treesai - write(fates_log(),*) 'co%c_area = ', ccohort%c_area - write(fates_log(),*) 'co%cmort = ', ccohort%cmort - write(fates_log(),*) 'co%bmort = ', ccohort%bmort - write(fates_log(),*) 'co%smort = ', ccohort%smort - write(fates_log(),*) 'co%asmort = ', ccohort%asmort - write(fates_log(),*) 'co%hmort = ', ccohort%hmort - write(fates_log(),*) 'co%frmort = ', ccohort%frmort - write(fates_log(),*) 'co%asmort = ', ccohort%asmort - write(fates_log(),*) 'co%isnew = ', ccohort%isnew - write(fates_log(),*) 'co%dndt = ', ccohort%dndt - write(fates_log(),*) 'co%dhdt = ', ccohort%dhdt - write(fates_log(),*) 'co%ddbhdt = ', ccohort%ddbhdt - write(fates_log(),*) 'co%dbdeaddt = ', ccohort%dbdeaddt - write(fates_log(),*) 'co%fraction_crown_burned = ', ccohort%fraction_crown_burned - write(fates_log(),*) 'co%fire_mort = ', ccohort%fire_mort - write(fates_log(),*) 'co%crownfire_mort = ', ccohort%crownfire_mort - write(fates_log(),*) 'co%cambial_mort = ', ccohort%cambial_mort - write(fates_log(),*) 'co%size_class = ', ccohort%size_class - write(fates_log(),*) 'co%size_by_pft_class = ', ccohort%size_by_pft_class - if (associated(ccohort%co_hydr) ) then - call dump_cohort_hydr(ccohort) - endif - write(fates_log(),*) '----------------------------------------' - return - end subroutine dump_cohort - - ! ===================================================================================== - subroutine dump_cohort_hydr(ccohort) - - - type(ed_cohort_type),intent(in),target :: ccohort - type(ed_cohort_hydr_type), pointer :: ccohort_hydr - ccohort_hydr => ccohort%co_hydr - - write(fates_log(),*) '--------------------------------------------' - write(fates_log(),*) ' Dumping Cohort Plant Hydraulic Information ' - write(fates_log(),*) 'ccohort_hydr%th_aroot(:) = ', ccohort_hydr%th_aroot(:) - write(fates_log(),*) 'ccohort_hydr%v_aroot_layer_init(:) = ', ccohort_hydr%v_aroot_layer_init(:) - write(fates_log(),*) 'ccohort_hydr%v_aroot_layer(:) = ', ccohort_hydr%v_aroot_layer(:) - write(fates_log(),*) '--------------------------------------------' - return - end subroutine dump_cohort_hydr - end module EDTypesMod diff --git a/main/FatesConstantsMod.F90 b/main/FatesConstantsMod.F90 index 726100a37b..fbc4e96c29 100644 --- a/main/FatesConstantsMod.F90 +++ b/main/FatesConstantsMod.F90 @@ -30,12 +30,60 @@ module FatesConstantsMod ! Integer equivalent of false (in case come compilers dont auto convert) integer, parameter, public :: ifalse = 0 + ! the parameter file may determine that fewer + ! are used, but this helps allocate scratch + ! space and output arrays. + + integer, parameter, public :: n_rad_stream_types = 2 ! The number of radiation streams used (direct/diffuse) + + integer , parameter, public :: N_DBH_BINS = 6 ! no. of dbh bins used when comparing patches + real(fates_r8), parameter, public :: patchfusion_dbhbin_loweredges(N_DBH_BINS) = & + (/0._fates_r8, 5._fates_r8, 20._fates_r8, 50._fates_r8, 100._fates_r8, 150._fates_r8/) ! array of bin lower edges for comparing patches + + + integer , parameter, public :: N_DIST_TYPES = 3 ! Disturbance Modes 1) tree-fall, 2) fire, 3) logging + integer , parameter, public :: dtype_ifall = 1 ! index for naturally occuring tree-fall generated event + integer , parameter, public :: dtype_ifire = 2 ! index for fire generated disturbance event + integer , parameter, public :: dtype_ilog = 3 ! index for logging generated disturbance event + ! Labels for patch disturbance history integer, parameter, public :: n_anthro_disturbance_categories = 2 integer, parameter, public :: primaryforest = 1 integer, parameter, public :: secondaryforest = 2 + integer, parameter, public :: leaves_on = 2 ! Flag specifying that a deciduous plant has leaves + ! and should be allocating to them as well + integer, parameter, public :: leaves_off = 1 ! Flag specifying that a deciduous plant has dropped + ! its leaves and should not be trying to allocate + ! towards any growth. + integer, parameter, public :: leaves_shedding = 3 ! Flag specifying that a deciduous plant has leaves + ! but is shedding them (partial shedding). This plant + ! should not allocate carbon towards growth or + ! reproduction. +integer, parameter, public :: ihard_stress_decid = 1 ! If the PFT is stress (drought) deciduous, + ! this flag is used to tell that the PFT + ! is a "hard" deciduous (i.e., the plant + ! has only two statuses, the plant either + ! sheds all leaves when it's time, or seeks + ! to flush the leaves back to allometry + ! when conditions improve. +integer, parameter, public :: isemi_stress_decid = 2 ! If the PFT is stress (drought) deciduous, + ! this flag is used to tell that the PFT + ! is a semi-deciduous (i.e., the plant + ! can downregulate the amount of leaves + ! relative to the allometry based on + ! soil moisture conditions. It can still + ! shed all leaves if conditions are very + ! dry. + + integer, parameter, public :: ican_upper = 1 ! nominal index for the upper canopy + integer, parameter, public :: ican_ustory = 2 ! nominal index for diagnostics that refer to understory layers + ! (all layers that are not the top canopy layer) + + ! Bareground label for no competition mode + integer, parameter, public :: nocomp_bareground = 0 + ! Flags specifying how phosphorous uptake and turnover interacts ! with the host model. integer, public, parameter :: prescribed_p_uptake = 1 @@ -45,17 +93,26 @@ module FatesConstantsMod ! with the host model. integer, public, parameter :: prescribed_n_uptake = 1 integer, public, parameter :: coupled_n_uptake = 2 - - - integer, public, parameter :: cohort_np_comp_scaling = 1 ! This flag definition indicates that EVERY cohort on - ! the column should compete independently in the soil - ! BGC nitrogen and phosphorus acquisition scheme. - - integer, public, parameter :: pft_np_comp_scaling = 2 ! This flag definition indicates that cohorts should - ! be grouped into PFTs, and each PFT will be represented - ! as the competitor, in the BGC N and P acquisition scheme - - integer, public, parameter :: trivial_np_comp_scaling = 3 ! This flag definition indicates that either + 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. 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_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. + 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 ! plants are not coupled with below ground chemistry. In ! this situation, we send token boundary condition information. @@ -63,17 +120,24 @@ module FatesConstantsMod ! This flag specifies the scaling of how we present ! nutrient competitors to the HLM's soil BGC model - - integer, public, parameter :: fates_np_comp_scaling = cohort_np_comp_scaling + + integer, public :: fates_np_comp_scaling = fates_unset_int real(fates_r8), parameter, public :: secondary_age_threshold = 94._fates_r8 ! less than this value is young secondary land ! based on average age of global ! secondary 1900s land in hurtt-2011 + ! integer labels for specifying harvest units + integer, parameter, public :: photosynth_acclim_model_none = 1 + integer, parameter, public :: photosynth_acclim_model_kumarathunge_etal_2019 = 2 + ! integer labels for specifying harvest units integer, parameter, public :: hlm_harvest_area_fraction = 1 ! Code for harvesting by area integer, parameter, public :: hlm_harvest_carbon = 2 ! Code for harvesting based on carbon extracted. + ! integer labels for specifying leaf maintenance respiration models + integer, parameter, public :: lmrmodel_ryan_1991 = 1 + integer, parameter, public :: lmrmodel_atkin_etal_2017 = 2 ! Error Tolerances @@ -82,6 +146,12 @@ module FatesConstantsMod ! error tolerance of 1 microgram. real(fates_r8), parameter, public :: calloc_abs_error = 1.0e-9_fates_r8 + ! area tolerance checks + real(fates_r8), parameter, public :: area_error_1 = 1.0e-16_fates_r8 ! error tolerance for area checks (canopy, patch) + real(fates_r8), parameter, public :: area_error_2 = 1.0e-12_fates_r8 ! error tolerance for tree lai checks + real(fates_r8), parameter, public :: area_error_3 = 10.e-9_fates_r8 ! error tolerance for area checks (canopy, patch) + real(fates_r8), parameter, public :: area_error_4 = 1.0e-10_fates_r8 ! error tolerance for area checks + ! Rounding errors seem to hover around 1e-15 for the gnu compiler ! when not applying compiler directives for safe math. An example ! of this is taking a vector of numbers, dividing through by their sum, @@ -132,6 +202,9 @@ module FatesConstantsMod ! Conversion factor: micromoles per mole real(fates_r8), parameter, public :: umol_per_mol = 1.0E6_fates_r8 + ! Conversion factor: moles per micromole + real(fates_r8), parameter, public :: mol_per_umol = 1.0E-6_fates_r8 + ! Conversion factor: umols per kilomole real(fates_r8), parameter, public :: umol_per_kmol = 1.0E9_fates_r8 @@ -141,6 +214,9 @@ module FatesConstantsMod ! Conversion factor: milimeters per meter real(fates_r8), parameter, public :: mm_per_m = 1.0E3_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: meters per centimeter real(fates_r8), parameter, public :: m_per_cm = 1.0E-2_fates_r8 @@ -170,6 +246,10 @@ 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 @@ -177,6 +257,9 @@ module FatesConstantsMod ! If we need to link to 365.25-day-calendared HLM, rewire to pass through interface real(fates_r8), parameter, public :: days_per_year = 365.00_fates_r8 + ! Integer version of days per year. + integer, parameter, public :: ndays_per_year = nint(days_per_year) + ! Conversion: years per day. assume HLM uses 365 day calendar. ! If we need to link to 365.25-day-calendared HLM, rewire to pass through interface real(fates_r8), parameter, public :: years_per_day = 1.0_fates_r8/365.00_fates_r8 @@ -219,14 +302,37 @@ 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) real(fates_r8), parameter, public :: fates_tiny = tiny(g_per_kg) + + ! Geodesy constants (WGS 84) + real(fates_r8), parameter, public :: earth_radius_eq = 6378137.0_fates_r8 ! equitorial radius, earth [m] + real(fates_r8), parameter, public :: earth_flattening = 1.0_fates_r8 / 298.257223563_fates_r8 ! flattening [non-dimensional] + ! Geometric Constants ! PI real(fates_r8), parameter, public :: pi_const = 3.14159265359_fates_r8 + real(fates_r8), parameter, public :: rad_per_deg = pi_const/180.0_fates_r8 + + ! Rdark constants from Atkin et al., 2017 https://doi.org/10.1007/978-3-319-68703-2_6 + ! and Heskel et al., 2016 https://doi.org/10.1073/pnas.1520282113 + real(fates_r8), parameter, public :: lmr_b = 0.1012_fates_r8 ! (degrees C**-1) + + real(fates_r8), parameter, public :: lmr_c = -0.0005_fates_r8 ! (degrees C**-2) + + real(fates_r8), parameter, public :: lmr_TrefC = 25._fates_r8 ! (degrees C) + real(fates_r8), parameter, public :: lmr_r_1 = 0.2061_fates_r8 ! (umol CO2/m**2/s / (gN/(m2 leaf))) + + real(fates_r8), parameter, public :: lmr_r_2 = -0.0402_fates_r8 ! (umol CO2/m**2/s/degree C) + + end module FatesConstantsMod diff --git a/main/FatesDispersalMod.F90 b/main/FatesDispersalMod.F90 new file mode 100644 index 0000000000..f030983a99 --- /dev/null +++ b/main/FatesDispersalMod.F90 @@ -0,0 +1,274 @@ +module FatesDispersalMod + + use shr_log_mod , only : errMsg => shr_log_errMsg + use FatesGlobals , only : endrun => fates_endrun + use FatesGlobals , only : fates_log + use FatesConstantsMod , only : r8 => fates_r8 + use FatesConstantsMod , only : pi_const + use FatesInterfaceTypesMod, only : numpft + + implicit none + + ! Neighbor node + type, public :: neighbor_type + + ! Grid cell neighbor + type(neighbor_type), pointer :: next_neighbor => null() + + integer :: gindex ! grid cell index + real(r8) :: gc_dist ! distance between source and neighbor + real(r8), allocatable :: density_prob(:) ! probability density from source per pft + + end type neighbor_type + + ! Neighborhood linked list + type, public :: neighborhood_type + + ! Linked list of neighbors for a given source grid cell + type(neighbor_type), pointer :: first_neighbor => null() + type(neighbor_type), pointer :: last_neighbor => null() + + integer :: neighbor_count ! total neighbors near source + integer, allocatable :: neighbor_indices(:) ! list of gridcell indices + + end type neighborhood_type + + ! Dispersal type + type, public :: dispersal_type + + real(r8), allocatable :: outgoing_local(:,:) ! local buffer array of outgoing seeds, local gridcell x pft + real(r8), allocatable :: outgoing_global(:,:) ! global accumulation buffer array of outgoing seeds, global gridcell x pft + real(r8), allocatable :: incoming_global(:,:) ! local buffer array used to calculate incoming seeds based on nearest neighbors + integer, allocatable :: ncells_array(:) ! local array with the number of gridcells per process for each rank index + integer, allocatable :: begg_array(:) ! local array with the starting index of each gridcell for each rank index + + contains + + procedure :: init + + end type dispersal_type + + type(neighborhood_type), public, pointer :: lneighbors(:) + + public :: ProbabilityDensity + public :: IsItDispersalTime + + integer :: dispersal_date = 0 ! Last candence date in which there was a dispersal + logical :: dispersal_flag = .false. ! Have seeds been disperesed globally + + character(len=*), parameter, private :: sourcefile = __FILE__ + +contains + + ! ==================================================================================== + + subroutine init(this, numprocs, numgc_global, numgc_local, numpft) + + ! Use + use EDPftvarcon , only : EDPftvarcon_inst + use FatesConstantsMod , only : fates_check_param_set, fates_unset_int + + ! Arguments + class(dispersal_type), intent(inout) :: this + + integer, intent(in) :: numprocs ! number of processors (across all nodes) + integer, intent(in) :: numgc_global ! number of gridcells across all processors + integer, intent(in) :: numgc_local ! number of gridcells on this processor + integer, intent(in) :: numpft ! number of FATES pfts + + allocate(this%outgoing_local(numpft,numgc_local)) + allocate(this%outgoing_global(numpft,numgc_global)) + allocate(this%incoming_global(numpft,numgc_global)) + allocate(this%begg_array(numprocs)) + allocate(this%ncells_array(numprocs)) + + this%outgoing_local(:,:) = 0._r8 + this%outgoing_global(:,:) = 0._r8 + this%incoming_global(:,:) = 0._r8 + this%ncells_array(:) = fates_unset_int + this%begg_array(:) = fates_unset_int + + ! Set the dispersal date to the current date. Dispersal will start at the end of + ! current initial date + dispersal_date = GetCadenceDate() + + end subroutine init + + ! ==================================================================================== + + subroutine ProbabilityDensity(pd, ipft, dist) + + ! Main subroutine that calls difference routines based on case select mode + + ! Use + use FatesInterfaceTypesMod, only : fates_dispersal_kernel_exponential, & + fates_dispersal_kernel_exppower, & + fates_dispersal_kernel_logsech, & + fates_dispersal_kernel_mode + + ! Arguments + real(r8), intent(out) :: pd ! Probability density + integer, intent(in) :: ipft ! pft index + real(r8), intent(in) :: dist ! distance + + ! Select the function to use based on the kernel mode + ! Note that hlm_seeddisp_cadence is checked prior to this call being made + select case(fates_dispersal_kernel_mode) + + case (fates_dispersal_kernel_exponential) + pd = PD_exponential(dist,ipft) + case (fates_dispersal_kernel_exppower) + pd = PD_exppower(dist,ipft) + case (fates_dispersal_kernel_logsech) + pd = PD_logsech(dist,ipft) + case default + write(fates_log(),*) 'ERROR: An undefined dispersal kernel was specified: ', fates_dispersal_kernel_mode + call endrun(msg=errMsg(sourcefile, __LINE__)) + end select + + end subroutine ProbabilityDensity + + ! ==================================================================================== + + real(r8) function PD_exponential(dist, ipft) + + use EDPftvarcon , only : EDPftvarcon_inst + + ! Arguments + real(r8), intent(in) :: dist + integer, intent(in) :: ipft + + ! Assuming simple exponential decay. In the future perhaps this could be an interface + ! for different weight calculations (and could be held only in fates) + + PD_exponential = exp(-EDPftvarcon_inst%seed_dispersal_pdf_scale(ipft)*dist) + + end function PD_exponential + + ! ==================================================================================== + + real(r8) function PD_exppower(dist, ipft) + + use EDPftvarcon , only : EDPftvarcon_inst + + ! Arguments + real(r8), intent(in) :: dist + integer, intent(in) :: ipft + + associate(& + param_a => EDPftvarcon_inst%seed_dispersal_pdf_scale(ipft), & + param_b => EDPftvarcon_inst%seed_dispersal_pdf_shape(ipft)) + + PD_exppower = (param_b / (2*pi_const*gamma(2/param_b))) * & + exp(-(dist**param_b)/(param_a**param_b)) + + end associate + + end function PD_exppower + + ! ==================================================================================== + + real(r8) function PD_logsech(dist, ipft) + + use EDPftvarcon , only : EDPftvarcon_inst + + ! Arguments + real(r8), intent(in) :: dist + integer, intent(in) :: ipft + + associate(& + param_a => EDPftvarcon_inst%seed_dispersal_pdf_scale(ipft), & + param_b => EDPftvarcon_inst%seed_dispersal_pdf_shape(ipft)) + + PD_logsech = (1/(pi_const**2 * param_b * dist**2)) / & + ((dist/param_a)**(1/param_b) + & + (dist/param_a)**(-1/param_b)) + + end associate + + end function PD_logsech + + ! ==================================================================================== + + logical function IsItDispersalTime(setdispersedflag) + + ! Determine if seeds should be dispersed across gridcells. This eventually could be + ! driven by plant reproduction dynamics. For now this is based strictly on a calendar. + ! This function attempts to wrap up all the logic for the dispersal code, which is + ! takes place at multiple points in the code, into a single function. + ! The logic for the function is as follows: + ! - If new date and seeds not globally dispersed, pass local seed to global bufffer + ! (see wrap_update_hlmfates_dyn) + ! - If new date and seeds not globally dispersed, globally disperse seeds (call WrapSeedGlobal) and + ! set dispersed flag to true. Note that since this must happen outside of threaded region, + ! this comes after fates dynamic_driv procedure. + ! - If new date or not and seeds have been globally dispersed, call wrap_seed_disperse + ! to pass dispersed seeds to fates. Set dispersed flag to false. Given that this must + ! happen after WrapSeedGlobal, but can be threaded this takes place at the top of the + ! dynamics_driv call. + + ! Arguments + logical, optional :: setdispersedflag ! Has the global dispersal been completed? + + ! Local + logical :: setflag + + ! The default return value is false + IsItDispersalTime = .false. + + ! Check if set dispersal flag is provided. This should be provided during a check + ! when the flag should be set to true after the global dispersal + setflag = .false. + if (present(setdispersedflag)) then + setflag = setdispersedflag + end if + + ! If dispersal flag is true, regardless of the date, pass dispersed seeds to fates and reset flag + ! If dispersal flag is false, check if it is time to disperse + ! If it's time to disperse, check to see if the dispersal flag should be set true and last + ! dispersal date updated + if (dispersal_flag) then + IsItDispersalTime = .true. + dispersal_flag = .false. + else + if (GetCadenceDate() .ne. dispersal_date) then + IsItDispersalTime = .true. + if (setflag) then + dispersal_flag = .true. + dispersal_date = GetCadenceDate() + end if + end if + end if + + end function IsItDispersalTime + + ! ==================================================================================== + + integer function GetCadenceDate() + + use FatesInterfaceTypesMod, only : hlm_current_day, & + hlm_current_month, & + hlm_current_year, & + hlm_current_date, & + hlm_seeddisp_cadence, & + fates_dispersal_cadence_daily, & + fates_dispersal_cadence_monthly, & + fates_dispersal_cadence_yearly + + ! Select the date type to check against based on the dispersal candence + select case(hlm_seeddisp_cadence) + case (fates_dispersal_cadence_daily) + GetCadenceDate = hlm_current_day + case (fates_dispersal_cadence_monthly) + GetCadenceDate = hlm_current_month + case (fates_dispersal_cadence_yearly) + GetCadenceDate = hlm_current_year + case default + write(fates_log(),*) 'ERROR: An undefined dispersal cadence was specified: ', hlm_seeddisp_cadence + call endrun(msg=errMsg(sourcefile, __LINE__)) + end select + + end function GetCadenceDate + + +end module FatesDispersalMod diff --git a/main/FatesGlobals.F90 b/main/FatesGlobals.F90 index d37ffe3b2a..ebc0f326ff 100644 --- a/main/FatesGlobals.F90 +++ b/main/FatesGlobals.F90 @@ -17,7 +17,36 @@ module FatesGlobals public :: fates_log public :: fates_global_verbose public :: fates_endrun - + public :: FatesWarn + public :: A2S + public :: N2S + public :: I2S + public :: FatesReportTotalWarnings + + ! ------------------------------------------------------------------------------------- + ! Warning handling + ! The objective here is to stop writing the same warning over and over again. After + ! we've seen the same machine print out the same warning over and over again, we get + ! the point and don't have to continue seeing the message. + ! We also allow warnings to have their own unique or group identifier, which will + ! make is to you only turn off warnings that are particularly chatty, and continue + ! to allow warnings elsewhere that have not tripped as often. + ! ------------------------------------------------------------------------------------- + + integer, parameter :: max_ids = 200 ! Maximum number of unique warning ids + ! expand as necessary + integer :: warn_counts(0:max_ids) = 0 ! Total number of times each id has warned + integer, parameter :: max_warnings = 100 ! The maximum number of warnings before we + ! stop writing the warning + logical :: warn_active(0:max_ids) = .true. ! The current status of the warning. + logical, parameter :: warning_override = .false. ! If you really don't want any warnings + ! you can set this to true to avoid + ! printing any of these warnings to the log + ! It should also bypass the logicals bound inside + ! at the compiler level (?) and be faster + + + contains @@ -66,7 +95,95 @@ subroutine fates_endrun(msg) end subroutine fates_endrun + ! ===================================================================================== + + subroutine FatesWarn(msg,index) + + character(len=*), intent(in) :: msg ! string to be printed + integer,optional,intent(in) :: index ! warning index + + integer :: ind + + if(warning_override) return ! Exit early if we are turning off warnings + + if(present(index))then + ind = index + else + ind = 0 + end if + + ! Don't check if the index is within bounds, this routine could already + ! be too expensive if this is in cohort loops + warn_counts(ind) = warn_counts(ind) + 1 + + if(warn_active(ind))then + write(fates_log(),*) 'FATESWARN: '//trim(ADJUSTL(I2S(ind)))//' m: '//trim(msg) + if(warn_counts(ind)> max_warnings) then + warn_active(ind) = .false. + write(fates_log(),*) 'FATESWARN: '//trim(ADJUSTL(I2S(ind)))//' has saturated messaging, no longer reporting' + end if + end if + return + end subroutine FatesWarn + + ! ===================================================================================== + + + subroutine FatesReportTotalWarnings() + + integer :: ind + + do ind = 0,max_ids + + if(warn_counts(ind)>0)then + + write(fates_log(),*) 'FATESWARN: '//trim(ADJUSTL(I2S(ind)))//' was triggered ',trim(ADJUSTL(I2S(warn_counts(ind))))//' times' + + end if + + end do + + + end subroutine FatesReportTotalWarnings + + + ! ===================================================================================== + + function N2S(real_in) result(str) + + real(r8) :: real_in + character(len=16) :: str + + !write(str,*) real_in + write(str,'(E12.6)') real_in + + end function N2S + ! ===================================================================================== + function I2S(int_in) result(str) + integer :: int_in + character(len=16) :: str + + !write(str,*) real_in + write(str,'(I15)') int_in + + end function I2S + + ! ===================================================================================== + + function A2S(reals_in) result(str) + + real(r8) :: reals_in(:) + character(len=1024) :: str + integer :: i, nreal + + str = ', ' + do i = 1,ubound(reals_in,1) + str = trim(str)//', '//N2S(reals_in(i)) + end do + + end function A2S + end module FatesGlobals diff --git a/main/FatesHistoryInterfaceMod.F90 b/main/FatesHistoryInterfaceMod.F90 index 0c3137127d..ba34b6dcb4 100644 --- a/main/FatesHistoryInterfaceMod.F90 +++ b/main/FatesHistoryInterfaceMod.F90 @@ -12,24 +12,25 @@ module FatesHistoryInterfaceMod use FatesConstantsMod , only : t_water_freeze_k_1atm use FatesGlobals , only : fates_log use FatesGlobals , only : endrun => fates_endrun - use EDTypesMod , only : nclmax - use EDTypesMod , only : ican_upper + use EDParamsMod , only : nclmax, maxpft + use FatesConstantsMod , only : ican_upper use PRTGenericMod , only : element_pos use PRTGenericMod , only : num_elements + use PRTGenericMod , only : prt_cnp_flex_allom_hyp use EDTypesMod , only : site_fluxdiags_type use EDtypesMod , only : ed_site_type - use EDtypesMod , only : ed_cohort_type - use EDtypesMod , only : ed_patch_type + use FatesCohortMod , only : fates_cohort_type + use FatesPatchMod , only : fates_patch_type use EDtypesMod , only : AREA use EDtypesMod , only : AREA_INV use EDTypesMod , only : numWaterMem use EDTypesMod , only : num_vegtemp_mem use EDTypesMod , only : site_massbal_type use PRTGenericMod , only : element_list - use EDTypesMod , only : N_DIST_TYPES - use EDTypesMod , only : dtype_ifall - use EDTypesMod , only : dtype_ifire - use EDTypesMod , only : dtype_ilog + use FatesConstantsMod , only : N_DIST_TYPES + use FatesConstantsMod , only : dtype_ifall + use FatesConstantsMod , only : dtype_ifire + use FatesConstantsMod , only : dtype_ilog use FatesIODimensionsMod , only : fates_io_dimension_type use FatesIOVariableKindMod , only : fates_io_variable_kind_type use FatesIOVariableKindMod , only : site_int @@ -38,6 +39,8 @@ module FatesHistoryInterfaceMod use FatesInterfaceTypesMod , only : hlm_use_planthydro use FatesInterfaceTypesMod , only : hlm_use_ed_st3 use FatesInterfaceTypesMod , only : hlm_use_cohort_age_tracking + use FatesInterfaceTypesMod , only : hlm_use_tree_damage + use FatesInterfaceTypesMod , only : nlevdamage use FatesInterfaceTypesMod , only : numpft use FatesInterfaceTypesMod , only : hlm_freq_day use FatesInterfaceTypesMod , only : hlm_parteh_mode @@ -46,11 +49,15 @@ module FatesHistoryInterfaceMod use FatesInterfaceTypesMod , only : nlevsclass, nlevage use FatesInterfaceTypesMod , only : nlevheight use FatesInterfaceTypesMod , only : bc_in_type + use FatesInterfaceTypesMod , only : bc_out_type use FatesInterfaceTypesMod , only : hlm_model_day use FatesInterfaceTypesMod , only : nlevcoage use FatesInterfaceTypesMod , only : hlm_use_nocomp + use FatesInterfaceTypesMod , only : hlm_use_fixed_biogeog use FatesAllometryMod , only : CrownDepth - + use FatesAllometryMod , only : bstore_allom + use FatesAllometryMod , only : set_root_fraction + use EDPftvarcon , only : EDPftvarcon_inst use PRTParametersMod , only : prt_params @@ -58,28 +65,35 @@ module FatesHistoryInterfaceMod use shr_log_mod , only : errMsg => shr_log_errMsg use shr_infnan_mod , only : isnan => shr_infnan_isnan use FatesConstantsMod , only : g_per_kg + use FatesConstantsMod , only : kg_per_g use FatesConstantsMod , only : ha_per_m2 use FatesConstantsMod , only : days_per_sec use FatesConstantsMod , only : sec_per_day + use FatesConstantsMod , only : days_per_sec use FatesConstantsMod , only : days_per_year use FatesConstantsMod , only : years_per_day use FatesConstantsMod , only : m2_per_km2 use FatesConstantsMod , only : J_per_kJ use FatesConstantsMod , only : m2_per_ha + use FatesConstantsMod , only : ha_per_m2 use FatesConstantsMod , only : m_per_cm + use FatesConstantsMod , only : m_per_mm use FatesConstantsMod , only : sec_per_min - use FatesConstantsMod , only : umol_per_mol + use FatesConstantsMod , only : umol_per_mol,mol_per_umol use FatesConstantsMod , only : pa_per_mpa + use FatesConstantsMod , only : dens_fresh_liquid_water + use FatesConstantsMod , only : grav_earth use FatesLitterMod , only : litter_type use FatesConstantsMod , only : secondaryforest use PRTGenericMod , only : leaf_organ, fnrt_organ, sapw_organ use PRTGenericMod , only : struct_organ, store_organ, repro_organ - use PRTGenericMod , only : all_carbon_elements use PRTGenericMod , only : carbon12_element use PRTGenericMod , only : nitrogen_element, phosphorus_element use PRTGenericMod , only : prt_carbon_allom_hyp - + use PRTAllometricCNPMod , only : stoich_max,stoich_growth_min + use FatesSizeAgeTypeIndicesMod, only : get_layersizetype_class_index + implicit none private ! By default everything is private @@ -158,51 +172,90 @@ module FatesHistoryInterfaceMod ! Indices to 1D Patch variables integer :: ih_storec_si + integer :: ih_storectfrac_si + integer :: ih_storectfrac_canopy_scpf + integer :: ih_storectfrac_ustory_scpf integer :: ih_leafc_si integer :: ih_sapwc_si integer :: ih_fnrtc_si + integer :: ih_fnrtc_sl integer :: ih_reproc_si integer :: ih_totvegc_si + ! Nutrient relevant diagnostics (CNP) + ! --------------------------------------------------------------- + ! These are active if if(any(element_list(:)==nitrogen_element)) integer :: ih_storen_si - integer :: ih_storentfrac_si integer :: ih_leafn_si integer :: ih_sapwn_si integer :: ih_fnrtn_si integer :: ih_repron_si integer :: ih_totvegn_si - + integer :: ih_storentfrac_si + integer :: ih_totvegn_scpf + integer :: ih_leafn_scpf + integer :: ih_fnrtn_scpf + integer :: ih_storen_scpf + integer :: ih_sapwn_scpf + integer :: ih_repron_scpf + integer :: ih_storentfrac_canopy_scpf + integer :: ih_storentfrac_understory_scpf + + ! These are active if if(any(element_list(:)==phosphorus_element)) integer :: ih_storep_si - integer :: ih_storeptfrac_si integer :: ih_leafp_si integer :: ih_sapwp_si integer :: ih_fnrtp_si integer :: ih_reprop_si integer :: ih_totvegp_si + integer :: ih_storeptfrac_si + integer :: ih_totvegp_scpf + integer :: ih_leafp_scpf + integer :: ih_fnrtp_scpf + integer :: ih_reprop_scpf + integer :: ih_storep_scpf + integer :: ih_sapwp_scpf + integer :: ih_storeptfrac_canopy_scpf + integer :: ih_storeptfrac_understory_scpf - integer,public :: ih_nh4uptake_si - integer,public :: ih_no3uptake_si - integer,public :: ih_puptake_si - integer :: ih_cefflux_si + ! These are active if hlm_parteh_mode = prt_cnp_flex_allom_hyp + integer :: ih_l2fr_si + integer :: ih_l2fr_clscpf + integer :: ih_recl2fr_canopy_pf + integer :: ih_recl2fr_ustory_pf + integer :: ih_nh4uptake_scpf + integer :: ih_no3uptake_scpf + integer :: ih_puptake_scpf + integer :: ih_nh4uptake_si + integer :: ih_no3uptake_si + integer :: ih_puptake_si integer :: ih_nefflux_si integer :: ih_pefflux_si - integer :: ih_nneed_si - integer :: ih_pneed_si - + integer :: ih_nefflux_scpf + integer :: ih_pefflux_scpf + integer :: ih_ndemand_si + integer :: ih_ndemand_scpf + integer :: ih_pdemand_si + integer :: ih_pdemand_scpf + integer :: ih_nfix_si + integer :: ih_nfix_scpf + integer :: ih_trimming_si integer :: ih_area_plant_si integer :: ih_area_trees_si - - 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_elem integer :: ih_litter_out_elem integer :: ih_seed_bank_elem + integer :: ih_fates_fraction_si + 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_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 integer :: ih_seeds_in_extern_elem integer :: ih_seed_decay_elem @@ -212,6 +265,7 @@ module FatesHistoryInterfaceMod integer :: ih_fines_bg_elem integer :: ih_cwd_ag_elem integer :: ih_cwd_bg_elem + integer :: ih_cwd_elcwd integer :: ih_burn_flux_elem ! Size-class x PFT mass states @@ -220,21 +274,9 @@ module FatesHistoryInterfaceMod integer :: ih_bstor_understory_si_scpf integer :: ih_bleaf_canopy_si_scpf integer :: ih_bleaf_understory_si_scpf - - - - integer :: ih_totvegn_scpf - integer :: ih_leafn_scpf - integer :: ih_fnrtn_scpf - integer :: ih_storen_scpf - integer :: ih_storentfrac_canopy_scpf - integer :: ih_storentfrac_understory_scpf - integer :: ih_sapwn_scpf - integer :: ih_repron_scpf - integer,public :: ih_nh4uptake_scpf - integer,public :: ih_no3uptake_scpf - integer :: ih_nefflux_scpf - integer :: ih_nneed_scpf + ! Size-class x PFT LAI states + integer :: ih_lai_canopy_si_scpf + integer :: ih_lai_understory_si_scpf integer :: ih_totvegc_scpf integer :: ih_leafc_scpf @@ -242,20 +284,6 @@ module FatesHistoryInterfaceMod integer :: ih_storec_scpf integer :: ih_sapwc_scpf integer :: ih_reproc_scpf - integer :: ih_cefflux_scpf - - integer :: ih_totvegp_scpf - integer :: ih_leafp_scpf - integer :: ih_fnrtp_scpf - integer :: ih_reprop_scpf - integer :: ih_storep_scpf - integer :: ih_storeptfrac_canopy_scpf - integer :: ih_storeptfrac_understory_scpf - integer :: ih_sapwp_scpf - integer,public :: ih_puptake_scpf - integer :: ih_pefflux_scpf - integer :: ih_pneed_scpf - integer :: ih_bdead_si integer :: ih_balive_si integer :: ih_agb_si @@ -264,12 +292,20 @@ module FatesHistoryInterfaceMod integer :: ih_aresp_si integer :: ih_maint_resp_si integer :: ih_growth_resp_si + integer :: ih_excess_resp_si integer :: ih_ar_canopy_si integer :: ih_gpp_canopy_si integer :: ih_ar_understory_si integer :: ih_gpp_understory_si integer :: ih_canopy_biomass_si integer :: ih_understory_biomass_si + integer :: ih_maint_resp_unreduced_si + + integer :: ih_npp_secondary_si + integer :: ih_gpp_secondary_si + integer :: ih_aresp_secondary_si + integer :: ih_maint_resp_secondary_si + integer :: ih_growth_resp_secondary_si integer :: ih_primaryland_fusion_error_si integer :: ih_disturbance_rate_p2p_si @@ -280,6 +316,8 @@ module FatesHistoryInterfaceMod integer :: ih_fall_disturbance_rate_si integer :: ih_potential_disturbance_rate_si integer :: ih_harvest_carbonflux_si + integer :: ih_harvest_debt_si + integer :: ih_harvest_debt_sec_si ! Indices to site by size-class by age variables integer :: ih_nplant_si_scag @@ -300,6 +338,8 @@ module FatesHistoryInterfaceMod ! Indices to (site) variables integer :: ih_tveg24_si + integer :: ih_tlongterm_si + integer :: ih_tgrowth_si integer :: ih_tveg_si integer :: ih_nep_si integer :: ih_hr_si @@ -315,11 +355,15 @@ module FatesHistoryInterfaceMod integer :: ih_err_fates_si integer :: ih_npatches_si + integer :: ih_npatches_sec_si integer :: ih_ncohorts_si + integer :: ih_ncohorts_sec_si integer :: ih_demotion_carbonflux_si integer :: ih_promotion_carbonflux_si integer :: ih_canopy_mortality_carbonflux_si integer :: ih_understory_mortality_carbonflux_si + integer :: ih_canopy_mortality_crownarea_si + integer :: ih_understory_mortality_crownarea_si integer :: ih_canopy_spread_si integer :: ih_npp_leaf_si integer :: ih_npp_seed_si @@ -339,17 +383,14 @@ module FatesHistoryInterfaceMod integer :: ih_h2oveg_recruit_si integer :: ih_h2oveg_growturn_err_si integer :: ih_h2oveg_hydro_err_si - + integer :: ih_lai_si + integer :: ih_site_cstatus_si - integer :: ih_site_dstatus_si integer :: ih_gdd_si integer :: ih_site_nchilldays_si integer :: ih_site_ncolddays_si integer :: ih_cleafoff_si integer :: ih_cleafon_si - integer :: ih_dleafoff_si - integer :: ih_dleafon_si - integer :: ih_meanliqvol_si integer :: ih_nesterov_fire_danger_si integer :: ih_fire_nignitions_si @@ -379,9 +420,10 @@ module FatesHistoryInterfaceMod integer :: ih_npp_agdw_si_scpf integer :: ih_npp_stor_si_scpf - integer :: ih_mortality_canopy_si_scpf integer :: ih_mortality_understory_si_scpf + integer :: ih_m3_mortality_canopy_si_scpf + integer :: ih_m3_mortality_understory_si_scpf integer :: ih_nplant_canopy_si_scpf integer :: ih_nplant_understory_si_scpf integer :: ih_ddbh_canopy_si_scpf @@ -406,9 +448,14 @@ module FatesHistoryInterfaceMod integer :: ih_m8_si_scpf integer :: ih_m9_si_scpf integer :: ih_m10_si_scpf + integer :: ih_m11_si_scpf + integer :: ih_crownfiremort_si_scpf integer :: ih_cambialfiremort_si_scpf + integer :: ih_abg_mortality_cflux_si_scpf + integer :: ih_abg_productivity_cflux_si_scpf + integer :: ih_m10_si_capf integer :: ih_nplant_si_capf @@ -433,6 +480,9 @@ module FatesHistoryInterfaceMod integer :: ih_sai_understory_si_scls integer :: ih_mortality_canopy_si_scls integer :: ih_mortality_understory_si_scls + integer :: ih_m3_mortality_canopy_si_scls + integer :: ih_m3_mortality_understory_si_scls + integer :: ih_demotion_rate_si_scls integer :: ih_promotion_rate_si_scls integer :: ih_trimming_canopy_si_scls @@ -443,6 +493,7 @@ module FatesHistoryInterfaceMod integer :: ih_ddbh_understory_si_scls integer :: ih_agb_si_scls integer :: ih_biomass_si_scls + integer :: ih_mortality_canopy_secondary_si_scls ! mortality vars integer :: ih_m1_si_scls @@ -456,6 +507,14 @@ module FatesHistoryInterfaceMod integer :: ih_m9_si_scls integer :: ih_m10_si_scls + integer :: ih_m1_sec_si_scls + integer :: ih_m2_sec_si_scls + integer :: ih_m3_sec_si_scls + integer :: ih_m7_sec_si_scls + integer :: ih_m8_sec_si_scls + integer :: ih_m9_sec_si_scls + integer :: ih_m10_sec_si_scls + integer :: ih_m10_si_cacls integer :: ih_nplant_si_cacls @@ -505,18 +564,34 @@ module FatesHistoryInterfaceMod ! indices to (site x pft) variables integer :: ih_biomass_si_pft + integer :: ih_biomass_sec_si_pft integer :: ih_leafbiomass_si_pft integer :: ih_storebiomass_si_pft integer :: ih_nindivs_si_pft + integer :: ih_nindivs_sec_si_pft integer :: ih_recruitment_si_pft integer :: ih_mortality_si_pft + integer :: ih_mortality_carbonflux_si_pft + integer :: ih_hydraulicmortality_carbonflux_si_pft + integer :: ih_cstarvmortality_carbonflux_si_pft + integer :: ih_firemortality_carbonflux_si_pft integer :: ih_crownarea_si_pft integer :: ih_canopycrownarea_si_pft integer :: ih_gpp_si_pft + integer :: ih_gpp_sec_si_pft integer :: ih_npp_si_pft + integer :: ih_npp_sec_si_pft + integer :: ih_site_dstatus_si_pft + integer :: ih_dleafoff_si_pft + integer :: ih_dleafon_si_pft + integer :: ih_meanliqvol_si_pft + integer :: ih_meansmp_si_pft + integer :: ih_elong_factor_si_pft integer :: ih_nocomp_pftpatchfraction_si_pft integer :: ih_nocomp_pftnpatches_si_pft integer :: ih_nocomp_pftburnedarea_si_pft + integer :: ih_seeds_out_gc_si_pft + integer :: ih_seeds_in_gc_si_pft ! indices to (site x patch-age) variables integer :: ih_area_si_age @@ -537,6 +612,8 @@ module FatesHistoryInterfaceMod integer :: ih_fire_intensity_si_age integer :: ih_fire_sum_fuel_si_age + integer :: ih_lai_secondary_si + ! indices to (site x height) variables integer :: ih_canopy_height_dist_si_height integer :: ih_leaf_height_dist_si_height @@ -624,6 +701,29 @@ module FatesHistoryInterfaceMod integer :: ih_parprof_dir_si_cnlfpft integer :: ih_parprof_dif_si_cnlfpft + ! indices to site x crown damage variables + ! site x crown damage x pft x sizeclass + ! site x crown damage x size class + integer :: ih_nplant_si_cdpf + integer :: ih_nplant_canopy_si_cdpf + integer :: ih_nplant_understory_si_cdpf + integer :: ih_mortality_si_cdpf + integer :: ih_mortality_canopy_si_cdpf + integer :: ih_mortality_understory_si_cdpf + integer :: ih_m3_si_cdpf + integer :: ih_m11_si_cdpf + integer :: ih_m3_mortality_canopy_si_cdpf + integer :: ih_m3_mortality_understory_si_cdpf + integer :: ih_m11_mortality_canopy_si_cdpf + integer :: ih_m11_mortality_understory_si_cdpf + integer :: ih_ddbh_si_cdpf + integer :: ih_ddbh_canopy_si_cdpf + integer :: ih_ddbh_understory_si_cdpf + + ! crownarea damaged + integer :: ih_crownarea_canopy_damage_si + integer :: ih_crownarea_ustory_damage_si + ! indices to (site x canopy layer) variables integer :: ih_parsun_top_si_can integer :: ih_parsha_top_si_can @@ -664,12 +764,13 @@ module FatesHistoryInterfaceMod integer, private :: levscls_index_, levpft_index_, levage_index_ integer, private :: levfuel_index_, levcwdsc_index_, levscag_index_ integer, private :: levcan_index_, levcnlf_index_, levcnlfpft_index_ + integer, private :: levcdpf_index_, levcdsc_index_, levcdam_index_ integer, private :: levscagpft_index_, levagepft_index_ integer, private :: levheight_index_, levagefuel_index_ integer, private :: levelem_index_, levelpft_index_ integer, private :: levelcwd_index_, levelage_index_ integer, private :: levcacls_index_, levcapf_index_ - + integer, private :: levclscpf_index_ contains @@ -681,7 +782,8 @@ module FatesHistoryInterfaceMod procedure :: update_history_dyn procedure :: update_history_hifrq procedure :: update_history_hydraulics - + procedure :: update_history_nutrflux + ! 'get' methods used by external callers to access private read only data procedure :: num_history_vars @@ -698,6 +800,9 @@ module FatesHistoryInterfaceMod procedure :: levcan_index procedure :: levcnlf_index procedure :: levcnlfpft_index + procedure :: levcdpf_index + procedure :: levcdsc_index + procedure :: levcdam_index procedure :: levscag_index procedure :: levscagpft_index procedure :: levagepft_index @@ -707,7 +812,8 @@ module FatesHistoryInterfaceMod procedure :: levelcwd_index procedure :: levelage_index procedure :: levagefuel_index - + procedure :: levclscpf_index + ! private work functions procedure, private :: define_history_vars procedure, private :: set_history_var @@ -726,12 +832,16 @@ module FatesHistoryInterfaceMod procedure, private :: set_levcan_index procedure, private :: set_levcnlf_index procedure, private :: set_levcnlfpft_index + procedure, private :: set_levcdpf_index + procedure, private :: set_levcdsc_index + procedure, private :: set_levcdam_index procedure, private :: set_levscag_index procedure, private :: set_levscagpft_index procedure, private :: set_levagepft_index procedure, private :: set_levheight_index procedure, private :: set_levagefuel_index - + procedure, private :: set_levclscpf_index + procedure, private :: set_levelem_index procedure, private :: set_levelpft_index procedure, private :: set_levelcwd_index @@ -739,6 +849,7 @@ module FatesHistoryInterfaceMod procedure, public :: flush_hvars procedure, public :: zero_site_hvars + end type fates_history_interface_type @@ -766,7 +877,8 @@ subroutine Init(this, num_threads, fates_bounds) use FatesIODimensionsMod, only : fates_bounds_type use FatesIODimensionsMod, only : levheight, levagefuel use FatesIODimensionsMod, only : levelem, levelpft - use FatesIODimensionsMod, only : levelcwd, levelage + use FatesIODimensionsMod, only : levelcwd, levelage, levclscpf + use FatesIODimensionsMod, only : levcdpf, levcdsc, levcdam implicit none @@ -841,6 +953,21 @@ subroutine Init(this, num_threads, fates_bounds) call this%dim_bounds(dim_count)%Init(levcnlfpft, num_threads, & fates_bounds%cnlfpft_begin, fates_bounds%cnlfpft_end) + dim_count = dim_count + 1 + call this%set_levcdpf_index(dim_count) + call this%dim_bounds(dim_count)%Init(levcdpf, num_threads, & + fates_bounds%cdpf_begin, fates_bounds%cdpf_end) + + dim_count = dim_count + 1 + call this%set_levcdsc_index(dim_count) + call this%dim_bounds(dim_count)%Init(levcdsc, num_threads, & + fates_bounds%cdsc_begin, fates_bounds%cdsc_end) + + dim_count = dim_count + 1 + call this%set_levcdam_index(dim_count) + call this%dim_bounds(dim_count)%Init(levcdam, num_threads, & + fates_bounds%cdam_begin, fates_bounds%cdam_end) + dim_count = dim_count + 1 call this%set_levscag_index(dim_count) call this%dim_bounds(dim_count)%Init(levscag, num_threads, & @@ -886,6 +1013,11 @@ subroutine Init(this, num_threads, fates_bounds) call this%dim_bounds(dim_count)%Init(levagefuel, num_threads, & fates_bounds%agefuel_begin, fates_bounds%agefuel_end) + dim_count = dim_count + 1 + call this%set_levclscpf_index(dim_count) + call this%dim_bounds(dim_count)%Init(levclscpf, num_threads, & + fates_bounds%clscpf_begin, fates_bounds%clscpf_end) + end subroutine Init ! ====================================================================== @@ -954,6 +1086,18 @@ subroutine SetThreadBoundsEach(this, thread_index, thread_bounds) call this%dim_bounds(index)%SetThreadBounds(thread_index, & thread_bounds%cnlfpft_begin, thread_bounds%cnlfpft_end) + index = this%levcdpf_index() + call this%dim_bounds(index)%SetThreadBounds(thread_index, & + thread_bounds%cdpf_begin, thread_bounds%cdpf_end) + + index = this%levcdsc_index() + call this%dim_bounds(index)%SetThreadBounds(thread_index, & + thread_bounds%cdsc_begin, thread_bounds%cdsc_end) + + index = this%levcdam_index() + call this%dim_bounds(index)%SetThreadBounds(thread_index, & + thread_bounds%cdam_begin, thread_bounds%cdam_end) + index = this%levscag_index() call this%dim_bounds(index)%SetThreadBounds(thread_index, & thread_bounds%sizeage_class_begin, thread_bounds%sizeage_class_end) @@ -990,9 +1134,9 @@ subroutine SetThreadBoundsEach(this, thread_index, thread_bounds) call this%dim_bounds(index)%SetThreadBounds(thread_index, & thread_bounds%agefuel_begin, thread_bounds%agefuel_end) - - - + index = this%levclscpf_index() + call this%dim_bounds(index)%SetThreadBounds(thread_index, & + thread_bounds%clscpf_begin, thread_bounds%clscpf_end) end subroutine SetThreadBoundsEach @@ -1007,8 +1151,9 @@ subroutine assemble_history_output_types(this) use FatesIOVariableKindMod, only : site_can_r8, site_cnlf_r8, site_cnlfpft_r8 use FatesIOVariableKindMod, only : site_height_r8, site_agefuel_r8 use FatesIOVariableKindMod, only : site_elem_r8, site_elpft_r8 - use FatesIOVariableKindMod, only : site_elcwd_r8, site_elage_r8 - + use FatesIOVariableKindMod, only : site_elcwd_r8, site_elage_r8, site_clscpf_r8 + use FatesIOVariableKindMod, only : site_cdpf_r8, site_cdsc_r8, site_cdam_r8 + implicit none class(fates_history_interface_type), intent(inout) :: this @@ -1053,6 +1198,15 @@ subroutine assemble_history_output_types(this) call this%set_dim_indices(site_cnlfpft_r8, 1, this%column_index()) call this%set_dim_indices(site_cnlfpft_r8, 2, this%levcnlfpft_index()) + call this%set_dim_indices(site_cdpf_r8, 1, this%column_index()) + call this%set_dim_indices(site_cdpf_r8, 2, this%levcdpf_index()) + + call this%set_dim_indices(site_cdsc_r8, 1, this%column_index()) + call this%set_dim_indices(site_cdsc_r8, 2, this%levcdsc_index()) + + call this%set_dim_indices(site_cdam_r8, 1, this%column_index()) + call this%set_dim_indices(site_cdam_r8, 2, this%levcdam_index()) + call this%set_dim_indices(site_scag_r8, 1, this%column_index()) call this%set_dim_indices(site_scag_r8, 2, this%levscag_index()) @@ -1080,7 +1234,9 @@ subroutine assemble_history_output_types(this) call this%set_dim_indices(site_agefuel_r8, 1, this%column_index()) call this%set_dim_indices(site_agefuel_r8, 2, this%levagefuel_index()) - + call this%set_dim_indices(site_clscpf_r8, 1, this%column_index()) + call this%set_dim_indices(site_clscpf_r8, 2, this%levclscpf_index()) + end subroutine assemble_history_output_types ! =================================================================================== @@ -1108,8 +1264,7 @@ subroutine set_dim_indices(this, dk_name, idim, dim_index) write(fates_log(), *) 'Trying to define dimension size to a dim-type structure' write(fates_log(), *) 'but the dimension index does not exist' write(fates_log(), *) 'type: ',dk_name,' ndims: ',this%dim_kinds(ityp)%ndims,' input dim:',idim - stop - !end_run + call endrun(msg=errMsg(sourcefile, __LINE__)) end if if (idim == 1) then @@ -1306,6 +1461,48 @@ integer function levcnlfpft_index(this) levcnlfpft_index = this%levcnlfpft_index_ end function levcnlfpft_index + ! ======================================================================= + subroutine set_levcdpf_index(this, index) + implicit none + class(fates_history_interface_type), intent(inout) :: this + integer, intent(in) :: index + this%levcdpf_index_ = index + end subroutine set_levcdpf_index + + integer function levcdpf_index(this) + implicit none + class(fates_history_interface_type), intent(in) :: this + levcdpf_index = this%levcdpf_index_ + end function levcdpf_index + + ! ======================================================================= + subroutine set_levcdsc_index(this, index) + implicit none + class(fates_history_interface_type), intent(inout) :: this + integer, intent(in) :: index + this%levcdsc_index_ = index + end subroutine set_levcdsc_index + + integer function levcdsc_index(this) + implicit none + class(fates_history_interface_type), intent(in) :: this + levcdsc_index = this%levcdsc_index_ + end function levcdsc_index + + ! ======================================================================= + subroutine set_levcdam_index(this, index) + implicit none + class(fates_history_interface_type), intent(inout) :: this + integer, intent(in) :: index + this%levcdam_index_ = index + end subroutine set_levcdam_index + + integer function levcdam_index(this) + implicit none + class(fates_history_interface_type), intent(in) :: this + levcdam_index = this%levcdam_index_ + end function levcdam_index + ! ====================================================================================== subroutine set_levscag_index(this, index) implicit none @@ -1436,6 +1633,20 @@ integer function levagefuel_index(this) class(fates_history_interface_type), intent(in) :: this levagefuel_index = this%levagefuel_index_ end function levagefuel_index + ! ====================================================================================== + + subroutine set_levclscpf_index(this, index) + implicit none + class(fates_history_interface_type), intent(inout) :: this + integer, intent(in) :: index + this%levclscpf_index_ = index + end subroutine set_levclscpf_index + + integer function levclscpf_index(this) + implicit none + class(fates_history_interface_type), intent(in) :: this + levclscpf_index = this%levclscpf_index_ + end function levclscpf_index ! ====================================================================================== @@ -1454,7 +1665,7 @@ subroutine zero_site_hvars(this, currentSite, upfreq_in) integer :: ndims ! number of dimensions do ivar=1,ubound(this%hvars,1) - if (this%hvars(ivar)%upfreq == upfreq_in) then ! Only flush variables with update on dynamics step + if (this%hvars(ivar)%upfreq == upfreq_in) then ndims = this%dim_kinds(this%hvars(ivar)%dim_kinds_index)%ndims @@ -1498,7 +1709,7 @@ end subroutine flush_hvars ! ===================================================================================== subroutine set_history_var(this, vname, units, long, use_default, avgflag, vtype, & - hlms, upfreq, ivar, initialize, index) + hlms, upfreq, ivar, initialize, index, flush_to_zero) use FatesUtilsMod, only : check_hlm_list use FatesInterfaceTypesMod, only : hlm_name @@ -1522,6 +1733,7 @@ subroutine set_history_var(this, vname, units, long, use_default, avgflag, vtype ! explict name (for fast reference during update) ! A zero is passed back when the variable is ! not used + logical, intent(in), optional :: flush_to_zero ! locals integer :: ub1, lb1, ub2, lb2 ! Bounds for allocating the var @@ -1533,8 +1745,15 @@ subroutine set_history_var(this, vname, units, long, use_default, avgflag, vtype ! Flushing to the ignore val coerces all FATES diagnostics to be ! relevant only on FATES sites. This way we do not average zero's ! at locations not on FATES columns + ! We make one exception to this rule, for the fates_fraction variable. That way + ! we can always know what fraction of the gridcell FATES is occupying. flushval = hlm_hio_ignore_val + if (present(flush_to_zero)) then + if (flush_to_zero) then + flushval = 0.0_r8 + endif + endif write_var = check_hlm_list(trim(hlms), trim(hlm_name)) if( write_var ) then @@ -1575,8 +1794,9 @@ subroutine init_dim_kinds_maps(this) use FatesIOVariableKindMod, only : site_can_r8, site_cnlf_r8, site_cnlfpft_r8 use FatesIOVariableKindMod, only : site_height_r8, site_agefuel_r8 use FatesIOVariableKindMod, only : site_elem_r8, site_elpft_r8 - use FatesIOVariableKindMod, only : site_elcwd_r8, site_elage_r8 - + use FatesIOVariableKindMod, only : site_elcwd_r8, site_elage_r8, site_clscpf_r8 + use FatesIOVariableKindMod, only : site_cdpf_r8, site_cdsc_r8, site_cdam_r8 + implicit none ! Arguments @@ -1637,6 +1857,18 @@ subroutine init_dim_kinds_maps(this) index = index + 1 call this%dim_kinds(index)%Init(site_cnlfpft_r8, 2) + ! site x crown damage x pft x size class + index = index + 1 + call this%dim_kinds(index)%Init(site_cdpf_r8, 2) + + ! site x crown damage x size class + index = index + 1 + call this%dim_kinds(index)%Init(site_cdsc_r8, 2) + + ! site x crown damage + index = index + 1 + call this%dim_kinds(index)%Init(site_cdam_r8, 2) + ! site x size-class x age class index = index + 1 call this%dim_kinds(index)%Init(site_scag_r8, 2) @@ -1673,17 +1905,207 @@ subroutine init_dim_kinds_maps(this) index = index + 1 call this%dim_kinds(index)%Init(site_agefuel_r8, 2) + ! site x age x fuel size class + index = index + 1 + call this%dim_kinds(index)%Init(site_clscpf_r8, 2) ! FIXME(bja, 2016-10) assert(index == fates_history_num_dim_kinds) end subroutine init_dim_kinds_maps - ! ======================================================================= + ! ======================================================================= + + subroutine update_history_nutrflux(this,csite) + + ! Update history diagnostics for nutrient dynamics variables. + ! This is a separate routine because we like to handle these + ! things before patches are reshuffled during disturbance, and + ! thus this is called immediately after PARTEH allocation + ! These diagnostics must be zero'd at the beginning + ! of the dynamics call (not here, because this is a + ! being called at the cohort level) + + ! Arguments + class(fates_history_interface_type) :: this + type(ed_site_type), intent(in) :: csite + + type(fates_patch_type), pointer :: cpatch + type(fates_cohort_type), pointer :: ccohort + integer :: iclscpf ! layer x size x pft class index + integer :: iscpf ! Size x pft class index + integer :: io_si ! site's global index in the history vector + integer :: el ! element loop index + integer :: ft + real(r8):: uconv ! combined unit conversion factor + + ! We use gpp and fineroot C for weighted averages + real(r8) :: gpp_si + real(r8) :: fnrtc_si + real(r8) :: fnrt_c + + associate( & + !hio_l2fr_clscpf => this%hvars(ih_l2fr_clscpf)%r82d, & + hio_l2fr_si => this%hvars(ih_l2fr_si)%r81d, & + hio_recl2fr_canopy_pf => this%hvars(ih_recl2fr_canopy_pf)%r82d, & + hio_recl2fr_ustory_pf => this%hvars(ih_recl2fr_ustory_pf)%r82d ) + + gpp_si = 0._r8 + fnrtc_si = 0._r8 + + ! history site index + io_si = csite%h_gid + + cpatch => csite%youngest_patch + do while(associated(cpatch)) + + ccohort => cpatch%shortest + do while(associated(ccohort)) + + ! If this is a new cohort, do not make diagnostics + if(ccohort%isnew) then + ccohort => ccohort%taller + cycle + end if + + ! size class index + iscpf = ccohort%size_by_pft_class + + ! layer by size by pft index + iclscpf = get_layersizetype_class_index(ccohort%canopy_layer,ccohort%dbh,ccohort%pft) + + ! unit conversion factor to get x/plant/day -> x/m2/sec + uconv = ccohort%n * ha_per_m2 * days_per_sec + + + fnrt_c = ccohort%prt%GetState(fnrt_organ, carbon12_element) + !hio_l2fr_clscpf(io_si,iclscpf) = & + ! hio_l2fr_clscpf(io_si,iclscpf) + ccohort%n*fnrt_c*ccohort%l2fr + + hio_l2fr_si(io_si) = hio_l2fr_si(io_si) + ccohort%n*fnrt_c*ccohort%l2fr + + ! These are used for normalizing weighted averages + gpp_si = gpp_si + ccohort%n*ccohort%gpp_acc_hold + fnrtc_si = fnrtc_si + ccohort%n*fnrt_c + + ! Loop over the different elements. + do el = 1, num_elements + + select case (element_list(el)) + case (carbon12_element) + + ! Excess carbon respired + this%hvars(ih_excess_resp_si)%r81d(io_si) = & + this%hvars(ih_excess_resp_si)%r81d(io_si) + & + ccohort%resp_excess*uconv + + case (nitrogen_element) + + ! Mineralized uptake of NH4, NO3 + fates_hist%hvars(ih_nh4uptake_scpf)%r82d(io_si,iscpf) = & + fates_hist%hvars(ih_nh4uptake_scpf)%r82d(io_si,iscpf) + & + ccohort%daily_nh4_uptake*uconv + + fates_hist%hvars(ih_no3uptake_scpf)%r82d(io_si,iscpf) = & + fates_hist%hvars(ih_no3uptake_scpf)%r82d(io_si,iscpf) + & + ccohort%daily_no3_uptake*uconv + fates_hist%hvars(ih_nh4uptake_si)%r81d(io_si) = & + fates_hist%hvars(ih_nh4uptake_si)%r81d(io_si) + & + ccohort%daily_nh4_uptake*uconv + fates_hist%hvars(ih_no3uptake_si)%r81d(io_si) = & + fates_hist%hvars(ih_no3uptake_si)%r81d(io_si) + & + ccohort%daily_no3_uptake*uconv + + ! Symbiotic Fixation + fates_hist%hvars(ih_nfix_si)%r81d(io_si) = & + fates_hist%hvars(ih_nfix_si)%r81d(io_si) + & + ccohort%sym_nfix_daily*uconv + + fates_hist%hvars(ih_nfix_scpf)%r82d(io_si,iscpf) = & + fates_hist%hvars(ih_nfix_scpf)%r82d(io_si,iscpf) + & + ccohort%sym_nfix_daily*uconv + + ! Efflux/exudation + this%hvars(ih_nefflux_scpf)%r82d(io_si,iscpf) = & + this%hvars(ih_nefflux_scpf)%r82d(io_si,iscpf) + & + ccohort%daily_n_efflux*uconv + + this%hvars(ih_nefflux_si)%r81d(io_si) = & + this%hvars(ih_nefflux_si)%r81d(io_si) + & + ccohort%daily_n_efflux*uconv + + ! Demand + this%hvars(ih_ndemand_scpf)%r82d(io_si,iscpf) = & + this%hvars(ih_ndemand_scpf)%r82d(io_si,iscpf) + & + ccohort%daily_n_demand*uconv + + this%hvars(ih_ndemand_si)%r81d(io_si) = & + this%hvars(ih_ndemand_si)%r81d(io_si) + & + ccohort%daily_n_demand*uconv + + case (phosphorus_element) + + fates_hist%hvars(ih_puptake_scpf)%r82d(io_si,iscpf) = & + fates_hist%hvars(ih_puptake_scpf)%r82d(io_si,iscpf) + & + ccohort%daily_p_gain*uconv + + fates_hist%hvars(ih_puptake_si)%r81d(io_si) = & + fates_hist%hvars(ih_puptake_si)%r81d(io_si) + & + ccohort%daily_p_gain*uconv + + this%hvars(ih_pefflux_scpf)%r82d(io_si,iscpf) = & + this%hvars(ih_pefflux_scpf)%r82d(io_si,iscpf) + & + ccohort%daily_p_efflux*uconv + + this%hvars(ih_pefflux_si)%r81d(io_si) = & + this%hvars(ih_pefflux_si)%r81d(io_si) + & + ccohort%daily_p_efflux*uconv + + this%hvars(ih_pdemand_scpf)%r82d(io_si,iscpf) = & + this%hvars(ih_pdemand_scpf)%r82d(io_si,iscpf) + & + ccohort%daily_p_demand*uconv + + this%hvars(ih_pdemand_si)%r81d(io_si) = & + ccohort%daily_p_demand*uconv + end select + end do + + ccohort => ccohort%taller + end do + + cpatch => cpatch%older + end do + + ! Normalize the layer x size x pft arrays + !do iclscpf = 1,nclmax*numpft*nlevsclass + !if(fnrtc_clscpf(iclscpf)>nearzero) then + ! hio_l2fr_clscpf(io_si,iclscpf) = hio_l2fr_clscpf(io_si,iclscpf) / fnrtc_clscpf(iclscpf) + !else + ! hio_l2fr_clscpf(io_si,iclscpf) = hlm_hio_ignore_val + !end if + !end do + + do ft = 1,numpft + hio_recl2fr_canopy_pf(io_si,ft) = csite%rec_l2fr(ft,1) + hio_recl2fr_ustory_pf(io_si,ft) = csite%rec_l2fr(ft,2) + end do + + if(fnrtc_si>nearzero)then + hio_l2fr_si(io_si) = hio_l2fr_si(io_si)/fnrtc_si + else + hio_l2fr_si(io_si) = hlm_hio_ignore_val + end if + + + + end associate + + return + end subroutine update_history_nutrflux ! ==================================================================================== - subroutine update_history_dyn(this,nc,nsites,sites) + subroutine update_history_dyn(this,nc,nsites,sites,bc_in) ! --------------------------------------------------------------------------------- ! This is the call to update the history IO arrays that are expected to only change @@ -1691,10 +2113,10 @@ subroutine update_history_dyn(this,nc,nsites,sites) ! --------------------------------------------------------------------------------- - use EDtypesMod , only : nfsc + use FatesLitterMod , only : nfsc use FatesLitterMod , only : ncwd - use EDtypesMod , only : ican_upper - use EDtypesMod , only : ican_ustory + use FatesConstantsMod , only : ican_upper + use FatesConstantsMod , only : ican_ustory use FatesSizeAgeTypeIndicesMod, only : get_sizeage_class_index use FatesSizeAgeTypeIndicesMod, only : get_sizeagepft_class_index use FatesSizeAgeTypeIndicesMod, only : get_agepft_class_index @@ -1702,16 +2124,20 @@ subroutine update_history_dyn(this,nc,nsites,sites) use FatesSizeAgeTypeIndicesMod, only : get_age_class_index use FatesSizeAgeTypeIndicesMod, only : get_height_index use FatesSizeAgeTypeIndicesMod, only : sizetype_class_index + use FatesSizeAgeTypeIndicesMod, only : get_cdamagesize_class_index + use FatesSizeAgeTypeIndicesMod, only : get_cdamagesizepft_class_index use FatesSizeAgeTypeIndicesMod, only : coagetype_class_index - use EDTypesMod , only : nlevleaf + + use EDParamsMod , only : nlevleaf use EDParamsMod , only : ED_val_history_height_bin_edges - + use FatesInterfaceTypesMod , only : nlevdamage + ! Arguments class(fates_history_interface_type) :: this integer , intent(in) :: nc ! clump index integer , intent(in) :: nsites type(ed_site_type) , intent(inout), target :: sites(nsites) - + type(bc_in_type) , intent(in) :: bc_in(nsites) ! Locals type(litter_type), pointer :: litt_c ! Pointer to the carbon12 litter pool type(litter_type), pointer :: litt ! Generic pointer to any litter pool @@ -1736,10 +2162,11 @@ subroutine update_history_dyn(this,nc,nsites,sites) integer :: iagepft ! age x pft index integer :: i_agefuel ! age x fuel size class index integer :: ican, ileaf, cnlf_indx ! iterators for leaf and canopy level + integer :: icdpf, icdsc, icdam, cdpf, cdsc ! iterators for the crown damage level integer :: height_bin_max, height_bin_min ! which height bin a given cohort's canopy is in integer :: i_heightbin ! iterator for height bins integer :: el ! Loop index for elements - integer :: model_day_int ! integer model day from reference + integer :: model_day_int ! Integer model day since simulation start integer :: ageclass_since_anthrodist ! what is the equivalent age class for ! time-since-anthropogenic-disturbance of secondary forest @@ -1777,30 +2204,53 @@ subroutine update_history_dyn(this,nc,nsites,sites) real(r8) :: area_frac real(r8) :: crown_depth - type(ed_patch_type),pointer :: cpatch - type(ed_cohort_type),pointer :: ccohort + real(r8) :: storen_canopy_scpf(numpft*nlevsclass) + real(r8) :: storen_understory_scpf(numpft*nlevsclass) + real(r8) :: storep_canopy_scpf(numpft*nlevsclass) + real(r8) :: storep_understory_scpf(numpft*nlevsclass) + real(r8) :: storec_canopy_scpf(numpft*nlevsclass) + real(r8) :: storec_understory_scpf(numpft*nlevsclass) + + integer :: return_code + + type(fates_patch_type),pointer :: cpatch + type(fates_cohort_type),pointer :: ccohort - real(r8), parameter :: tiny = 1.e-5_r8 ! some small number real(r8), parameter :: reallytalltrees = 1000. ! some large number (m) integer :: tmp associate( hio_npatches_si => this%hvars(ih_npatches_si)%r81d, & + hio_npatches_sec_si => this%hvars(ih_npatches_sec_si)%r81d, & hio_ncohorts_si => this%hvars(ih_ncohorts_si)%r81d, & + hio_ncohorts_sec_si => this%hvars(ih_ncohorts_sec_si)%r81d, & hio_trimming_si => this%hvars(ih_trimming_si)%r81d, & hio_area_plant_si => this%hvars(ih_area_plant_si)%r81d, & hio_area_trees_si => this%hvars(ih_area_trees_si)%r81d, & + hio_fates_fraction_si => this%hvars(ih_fates_fraction_si)%r81d, & + hio_ba_weighted_height_si => this%hvars(ih_ba_weighted_height_si)%r81d, & + hio_ca_weighted_height_si => this%hvars(ih_ca_weighted_height_si)%r81d, & hio_canopy_spread_si => this%hvars(ih_canopy_spread_si)%r81d, & hio_biomass_si_pft => this%hvars(ih_biomass_si_pft)%r82d, & + hio_biomass_sec_si_pft => this%hvars(ih_biomass_sec_si_pft)%r82d, & hio_leafbiomass_si_pft => this%hvars(ih_leafbiomass_si_pft)%r82d, & hio_storebiomass_si_pft => this%hvars(ih_storebiomass_si_pft)%r82d, & hio_nindivs_si_pft => this%hvars(ih_nindivs_si_pft)%r82d, & + hio_nindivs_sec_si_pft => this%hvars(ih_nindivs_sec_si_pft)%r82d, & hio_recruitment_si_pft => this%hvars(ih_recruitment_si_pft)%r82d, & + hio_seeds_out_gc_si_pft => this%hvars(ih_seeds_out_gc_si_pft)%r82d, & + hio_seeds_in_gc_si_pft => this%hvars(ih_seeds_in_gc_si_pft)%r82d, & hio_mortality_si_pft => this%hvars(ih_mortality_si_pft)%r82d, & + hio_mortality_carbonflux_si_pft => this%hvars(ih_mortality_carbonflux_si_pft)%r82d, & + hio_cstarvmortality_carbonflux_si_pft => this%hvars(ih_cstarvmortality_carbonflux_si_pft)%r82d, & + hio_hydraulicmortality_carbonflux_si_pft => this%hvars(ih_hydraulicmortality_carbonflux_si_pft)%r82d, & + hio_firemortality_carbonflux_si_pft => this%hvars(ih_firemortality_carbonflux_si_pft)%r82d, & hio_crownarea_si_pft => this%hvars(ih_crownarea_si_pft)%r82d, & hio_canopycrownarea_si_pft => this%hvars(ih_canopycrownarea_si_pft)%r82d, & hio_gpp_si_pft => this%hvars(ih_gpp_si_pft)%r82d, & + hio_gpp_sec_si_pft => this%hvars(ih_gpp_sec_si_pft)%r82d, & hio_npp_si_pft => this%hvars(ih_npp_si_pft)%r82d, & + hio_npp_sec_si_pft => this%hvars(ih_npp_sec_si_pft)%r82d, & hio_nesterov_fire_danger_si => this%hvars(ih_nesterov_fire_danger_si)%r81d, & hio_fire_nignitions_si => this%hvars(ih_fire_nignitions_si)%r81d, & hio_fire_fdi_si => this%hvars(ih_fire_fdi_si)%r81d, & @@ -1819,7 +2269,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_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_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, & @@ -1841,6 +2294,8 @@ subroutine update_history_dyn(this,nc,nsites,sites) hio_fall_disturbance_rate_si => this%hvars(ih_fall_disturbance_rate_si)%r81d, & hio_potential_disturbance_rate_si => this%hvars(ih_potential_disturbance_rate_si)%r81d, & hio_harvest_carbonflux_si => this%hvars(ih_harvest_carbonflux_si)%r81d, & + hio_harvest_debt_si => this%hvars(ih_harvest_debt_si)%r81d, & + hio_harvest_debt_sec_si => this%hvars(ih_harvest_debt_sec_si)%r81d, & hio_gpp_si_scpf => this%hvars(ih_gpp_si_scpf)%r82d, & hio_npp_totl_si_scpf => this%hvars(ih_npp_totl_si_scpf)%r82d, & hio_npp_leaf_si_scpf => this%hvars(ih_npp_leaf_si_scpf)%r82d, & @@ -1861,8 +2316,17 @@ subroutine update_history_dyn(this,nc,nsites,sites) hio_bstor_understory_si_scpf => this%hvars(ih_bstor_understory_si_scpf)%r82d, & hio_bleaf_canopy_si_scpf => this%hvars(ih_bleaf_canopy_si_scpf)%r82d, & hio_bleaf_understory_si_scpf => this%hvars(ih_bleaf_understory_si_scpf)%r82d, & + hio_lai_canopy_si_scpf => this%hvars(ih_lai_canopy_si_scpf)%r82d, & + hio_lai_understory_si_scpf => this%hvars(ih_lai_understory_si_scpf)%r82d, & hio_mortality_canopy_si_scpf => this%hvars(ih_mortality_canopy_si_scpf)%r82d, & + hio_mortality_canopy_secondary_si_scls => this%hvars(ih_mortality_canopy_secondary_si_scls)%r82d, & hio_mortality_understory_si_scpf => this%hvars(ih_mortality_understory_si_scpf)%r82d, & + hio_m3_mortality_canopy_si_scpf => this%hvars(ih_m3_mortality_canopy_si_scpf)%r82d, & + hio_m3_mortality_understory_si_scpf => this%hvars(ih_m3_mortality_understory_si_scpf)%r82d, & + hio_m3_mortality_canopy_si_scls => this%hvars(ih_m3_mortality_canopy_si_scls)%r82d, & + hio_m3_mortality_understory_si_scls => this%hvars(ih_m3_mortality_understory_si_scls)%r82d, & + hio_canopy_mortality_crownarea_si => this%hvars(ih_canopy_mortality_crownarea_si)%r81d, & + hio_understory_mortality_crownarea_si => this%hvars(ih_understory_mortality_crownarea_si)%r81d, & hio_nplant_canopy_si_scpf => this%hvars(ih_nplant_canopy_si_scpf)%r82d, & hio_nplant_understory_si_scpf => this%hvars(ih_nplant_understory_si_scpf)%r82d, & hio_ddbh_canopy_si_scpf => this%hvars(ih_ddbh_canopy_si_scpf)%r82d, & @@ -1896,6 +2360,9 @@ subroutine update_history_dyn(this,nc,nsites,sites) hio_crownfiremort_si_scpf => this%hvars(ih_crownfiremort_si_scpf)%r82d, & hio_cambialfiremort_si_scpf => this%hvars(ih_cambialfiremort_si_scpf)%r82d, & + hio_abg_mortality_cflux_si_scpf => this%hvars(ih_abg_mortality_cflux_si_scpf)%r82d, & + hio_abg_productivity_cflux_si_scpf => this%hvars(ih_abg_productivity_cflux_si_scpf)%r82d, & + hio_fire_c_to_atm_si => this%hvars(ih_fire_c_to_atm_si)%r81d, & hio_burn_flux_elem => this%hvars(ih_burn_flux_elem)%r82d, & @@ -1911,6 +2378,14 @@ subroutine update_history_dyn(this,nc,nsites,sites) hio_m10_si_scls => this%hvars(ih_m10_si_scls)%r82d, & hio_m10_si_cacls => this%hvars(ih_m10_si_cacls)%r82d, & + hio_m1_sec_si_scls => this%hvars(ih_m1_sec_si_scls)%r82d, & + hio_m2_sec_si_scls => this%hvars(ih_m2_sec_si_scls)%r82d, & + hio_m3_sec_si_scls => this%hvars(ih_m3_sec_si_scls)%r82d, & + hio_m7_sec_si_scls => this%hvars(ih_m7_sec_si_scls)%r82d, & + hio_m8_sec_si_scls => this%hvars(ih_m8_sec_si_scls)%r82d, & + hio_m9_sec_si_scls => this%hvars(ih_m9_sec_si_scls)%r82d, & + hio_m10_sec_si_scls => this%hvars(ih_m10_sec_si_scls)%r82d, & + hio_c13disc_si_scpf => this%hvars(ih_c13disc_si_scpf)%r82d, & hio_cwd_elcwd => this%hvars(ih_cwd_elcwd)%r82d, & @@ -1975,6 +2450,7 @@ subroutine update_history_dyn(this,nc,nsites,sites) hio_yesterdaycanopylevel_understory_si_scls => this%hvars(ih_yesterdaycanopylevel_understory_si_scls)%r82d, & hio_area_si_age => this%hvars(ih_area_si_age)%r82d, & hio_lai_si_age => this%hvars(ih_lai_si_age)%r82d, & + hio_lai_secondary_si => this%hvars(ih_lai_secondary_si)%r81d, & hio_canopy_area_si_age => this%hvars(ih_canopy_area_si_age)%r82d, & hio_ncl_si_age => this%hvars(ih_ncl_si_age)%r82d, & hio_npatches_si_age => this%hvars(ih_npatches_si_age)%r82d, & @@ -2003,32 +2479,42 @@ subroutine update_history_dyn(this,nc,nsites,sites) hio_cwd_bg_out_si_cwdsc => this%hvars(ih_cwd_bg_out_si_cwdsc)%r82d, & hio_crownarea_si_cnlf => this%hvars(ih_crownarea_si_cnlf)%r82d, & hio_crownarea_si_can => this%hvars(ih_crownarea_si_can)%r82d, & - hio_nplant_si_scag => this%hvars(ih_nplant_si_scag)%r82d, & - hio_nplant_canopy_si_scag => this%hvars(ih_nplant_canopy_si_scag)%r82d, & - hio_nplant_understory_si_scag => this%hvars(ih_nplant_understory_si_scag)%r82d, & hio_ddbh_canopy_si_scag => this%hvars(ih_ddbh_canopy_si_scag)%r82d, & hio_ddbh_understory_si_scag => this%hvars(ih_ddbh_understory_si_scag)%r82d, & hio_mortality_canopy_si_scag => this%hvars(ih_mortality_canopy_si_scag)%r82d, & - hio_mortality_understory_si_scag => this%hvars(ih_mortality_understory_si_scag)%r82d, & - hio_site_cstatus_si => this%hvars(ih_site_cstatus_si)%r81d, & - hio_site_dstatus_si => this%hvars(ih_site_dstatus_si)%r81d, & - hio_gdd_si => this%hvars(ih_gdd_si)%r81d, & + hio_mortality_understory_si_scag => this%hvars(ih_mortality_understory_si_scag)%r82d ) + + ! Split up the associate statement as the nag compiler has a limit on line continuation + associate( hio_gdd_si => this%hvars(ih_gdd_si)%r81d, & hio_site_ncolddays_si => this%hvars(ih_site_ncolddays_si)%r81d, & hio_site_nchilldays_si => this%hvars(ih_site_nchilldays_si)%r81d, & + hio_site_cstatus_si => this%hvars(ih_site_cstatus_si)%r81d, & hio_cleafoff_si => this%hvars(ih_cleafoff_si)%r81d, & hio_cleafon_si => this%hvars(ih_cleafon_si)%r81d, & - hio_dleafoff_si => this%hvars(ih_dleafoff_si)%r81d, & - hio_dleafon_si => this%hvars(ih_dleafoff_si)%r81d, & + hio_site_dstatus_si_pft => this%hvars(ih_site_dstatus_si_pft)%r82d, & + hio_dleafoff_si_pft => this%hvars(ih_dleafoff_si_pft)%r82d, & + hio_dleafon_si_pft => this%hvars(ih_dleafon_si_pft)%r82d, & + hio_meanliqvol_si_pft => this%hvars(ih_meanliqvol_si_pft)%r82d, & + hio_meansmp_si_pft => this%hvars(ih_meansmp_si_pft)%r82d, & + hio_elong_factor_si_pft => this%hvars(ih_elong_factor_si_pft)%r82d, & hio_tveg24 => this%hvars(ih_tveg24_si)%r81d, & - hio_meanliqvol_si => this%hvars(ih_meanliqvol_si)%r81d, & + hio_tlongterm => this%hvars(ih_tlongterm_si)%r81d, & + hio_tgrowth => this%hvars(ih_tgrowth_si)%r81d, & hio_cbal_err_fates_si => this%hvars(ih_cbal_err_fates_si)%r81d, & - hio_err_fates_si => this%hvars(ih_err_fates_si)%r82d ) + hio_err_fates_si => this%hvars(ih_err_fates_si)%r82d, & + hio_nplant_si_scag => this%hvars(ih_nplant_si_scag)%r82d, & + hio_nplant_canopy_si_scag => this%hvars(ih_nplant_canopy_si_scag)%r82d, & + hio_nplant_understory_si_scag => this%hvars(ih_nplant_understory_si_scag)%r82d, & + hio_lai_si => this%hvars(ih_lai_si)%r81d ) ! If we don't have dynamics turned on, we just abort these diagnostics if (hlm_use_ed_st3.eq.itrue) return model_day_int = nint(hlm_model_day) + + + ! --------------------------------------------------------------------------------- ! Loop through the FATES scale hierarchy and fill the history IO arrays ! --------------------------------------------------------------------------------- @@ -2037,6 +2523,20 @@ subroutine update_history_dyn(this,nc,nsites,sites) io_si = sites(s)%h_gid + ! These are weighting factors + storen_canopy_scpf(:) = 0._r8 + storen_understory_scpf(:) = 0._r8 + storep_canopy_scpf(:) = 0._r8 + storep_understory_scpf(:) = 0._r8 + storec_canopy_scpf(:) = 0._r8 + storec_understory_scpf(:) = 0._r8 + + flux_diags_c => sites(s)%flux_diags(element_pos(carbon12_element)) + + ! set the fates fraction to one, since it is zero on non-fates columns, & + ! the average is the total gridcell fates fraction + hio_fates_fraction_si(io_si) = 1._r8 + ! Total carbon model error [kgC/day -> kgC/s] hio_cbal_err_fates_si(io_si) = & sites(s)%mass_balance(element_pos(carbon12_element))%err_fates / sec_per_day @@ -2058,13 +2558,25 @@ subroutine update_history_dyn(this,nc,nsites,sites) end do + ! damage variables - site level - this needs to be OUT of the patch loop + if(hlm_use_tree_damage .eq. itrue) then + + this%hvars(ih_crownarea_canopy_damage_si)%r81d(io_si) = & + this%hvars(ih_crownarea_canopy_damage_si)%r81d(io_si) + & + sites(s)%crownarea_canopy_damage * days_per_year * 1 / m2_per_ha + + this%hvars(ih_crownarea_ustory_damage_si)%r81d(io_si) = & + this%hvars(ih_crownarea_ustory_damage_si)%r81d(io_si) + & + sites(s)%crownarea_ustory_damage * days_per_year * 1 / m2_per_ha + + end if + + ! Canopy spread index (0-1) hio_canopy_spread_si(io_si) = sites(s)%spread - ! Site statuses (stati?) for cold deciduous and drought - ! deciduous - hio_site_cstatus_si(io_si) = real(sites(s)%cstatus,r8) - hio_site_dstatus_si(io_si) = real(sites(s)%dstatus,r8) + ! Update the site status for cold deciduous (drought deciduous is now PFT dependent) + hio_site_cstatus_si(io_si) = real(sites(s)%cstatus,r8) ! Number of chill days and cold days hio_site_nchilldays_si(io_si) = real(sites(s)%nchilldays,r8) @@ -2073,17 +2585,34 @@ subroutine update_history_dyn(this,nc,nsites,sites) ! Growing degree-days hio_gdd_si(io_si) = sites(s)%grow_deg_days - ! Model days elapsed since leaf on/off for cold- and drought-deciduous - hio_cleafoff_si(io_si) = real(model_day_int - sites(s)%cleafoffdate,r8) - hio_cleafon_si(io_si) = real(model_day_int - sites(s)%cleafondate,r8) - hio_dleafoff_si(io_si) = real(model_day_int - sites(s)%dleafoffdate,r8) - hio_dleafon_si(io_si) = real(model_day_int - sites(s)%dleafondate,r8) + ! Model days elapsed since leaf on/off for cold-deciduous + hio_cleafoff_si(io_si) = real(sites(s)%phen_model_date - sites(s)%cleafoffdate,r8) + hio_cleafon_si(io_si) = real(sites(s)%phen_model_date - sites(s)%cleafondate,r8) - ! Mean liquid water content (m3/m3) used for drought phenology - if(model_day_int>numWaterMem)then - hio_meanliqvol_si(io_si) = & - sum(sites(s)%water_memory(1:numWaterMem))/real(numWaterMem,r8) - end if + + ! Update drought deciduous information (now separated by PFT). + do i_pft = 1,numpft + ! Update the site-PFT status for drought deciduous + hio_site_dstatus_si_pft(io_si,i_pft) = real(sites(s)%dstatus(i_pft),r8) + + ! Model days elapsed since leaf off/on for drought deciduous + hio_dleafoff_si_pft(io_si,i_pft) = real(sites(s)%dndaysleafon (i_pft),r8) + hio_dleafon_si_pft(io_si,i_pft) = real(sites(s)%dndaysleafoff(i_pft),r8) + + ! Leaf elongation factor (0 means fully abscissed, 1 means fully flushed). + hio_elong_factor_si_pft(io_si,i_pft) = sites(s)%elong_factor(i_pft) + + if(model_day_int>numWaterMem)then + ! Mean liquid water content (m3/m3) used for drought phenology + hio_meanliqvol_si_pft(io_si,i_pft) = & + sum(sites(s)%liqvol_memory(1:numWaterMem,i_pft))/real(numWaterMem,r8) + + ! Mean soil matric potential (Pa) used for drought phenology + hio_meansmp_si_pft(io_si,i_pft) = & + sum(sites(s)%smp_memory(1:numWaterMem,i_pft))/real(numWaterMem,r8) & + * dens_fresh_liquid_water * grav_earth * m_per_mm + end if + end do ! track total wood product accumulation at the site level hio_woodproduct_si(io_si) = sites(s)%resources_management%trunk_product_site & @@ -2108,6 +2637,8 @@ subroutine update_history_dyn(this,nc,nsites,sites) this%hvars(ih_h2oveg_recruit_si)%r81d(io_si) = sites(s)%si_hydr%h2oveg_recruit this%hvars(ih_h2oveg_growturn_err_si)%r81d(io_si) = sites(s)%si_hydr%h2oveg_growturn_err end if + hio_harvest_debt_si(io_si) = sites(s)%resources_management%harvest_debt + hio_harvest_debt_sec_si(io_si) = sites(s)%resources_management%harvest_debt_sec ! error in primary lands from patch fusion [m2 m-2 day-1] -> [m2 m-2 yr-1] hio_primaryland_fusion_error_si(io_si) = sites(s)%primary_land_patchfusion_error * days_per_year @@ -2134,10 +2665,8 @@ subroutine update_history_dyn(this,nc,nsites,sites) hio_potential_disturbance_rate_si(io_si) = sum(sites(s)%potential_disturbance_rates(1:N_DIST_TYPES)) * days_per_year - ! harvest carbon flux in [kgC/m2/d] -> [kgC/m2/yr] - hio_harvest_carbonflux_si(io_si) = sites(s)%harvest_carbon_flux * & - days_per_year - + hio_harvest_carbonflux_si(io_si) = sites(s)%mass_balance(element_pos(carbon12_element))%wood_product * AREA_INV + ! Loop through patches to sum up diagonistics ipa = 0 cpatch => sites(s)%oldest_patch @@ -2145,6 +2674,9 @@ subroutine update_history_dyn(this,nc,nsites,sites) ! Increment the number of patches per site hio_npatches_si(io_si) = hio_npatches_si(io_si) + 1._r8 + if ( cpatch%anthro_disturbance_label .eq. secondaryforest ) then + hio_npatches_sec_si(io_si) = hio_npatches_sec_si(io_si) + 1._r8 + end if cpatch%age_class = get_age_class_index(cpatch%age) @@ -2155,15 +2687,26 @@ subroutine update_history_dyn(this,nc,nsites,sites) ! 24hr veg temperature hio_tveg24(io_si) = hio_tveg24(io_si) + & (cpatch%tveg24%GetMean()- t_water_freeze_k_1atm)*cpatch%area*AREA_INV - - ! Increment some patch-age-resolved diagnostics + ! long-term veg temperature + hio_tlongterm(io_si) = hio_tlongterm(io_si) + & + (cpatch%tveg_longterm%GetMean()- t_water_freeze_k_1atm)*cpatch%area*AREA_INV + + ! long-term running mean veg temperature (tgrowth) + hio_tgrowth(io_si) = hio_tgrowth(io_si) + & + (cpatch%tveg_lpa%GetMean()- t_water_freeze_k_1atm)*cpatch%area*AREA_INV + + ! Increment some patch-age-resolved diagnostics hio_lai_si_age(io_si,cpatch%age_class) = hio_lai_si_age(io_si,cpatch%age_class) & + sum(cpatch%tlai_profile(:,:,:)) * cpatch%area + hio_ncl_si_age(io_si,cpatch%age_class) = hio_ncl_si_age(io_si,cpatch%age_class) & + cpatch%ncl_p * cpatch%area hio_npatches_si_age(io_si,cpatch%age_class) = hio_npatches_si_age(io_si,cpatch%age_class) + 1._r8 + hio_lai_si(io_si) = hio_lai_si(io_si) + sum( cpatch%canopy_area_profile(:,:,:) * cpatch%elai_profile(:,:,:) ) * & + cpatch%total_canopy_area * AREA_INV + if ( ED_val_comp_excln .lt. 0._r8 ) then ! only valid when "strict ppa" enabled hio_zstar_si_age(io_si,cpatch%age_class) = hio_zstar_si_age(io_si,cpatch%age_class) & + cpatch%zstar * cpatch%area * AREA_INV @@ -2185,6 +2728,12 @@ subroutine update_history_dyn(this,nc,nsites,sites) + cpatch%area * AREA_INV endif + ! Secondary forest mean LAI + if ( cpatch%anthro_disturbance_label .eq. secondaryforest ) then + hio_lai_secondary_si(io_si) = hio_lai_secondary_si(io_si) & + + sum(cpatch%tlai_profile(:,:,:)) * cpatch%total_canopy_area + end if + ! patch-age-resolved fire variables do i_pft = 1,numpft ! for scorch height, weight the value by patch area within any @@ -2250,15 +2799,19 @@ subroutine update_history_dyn(this,nc,nsites,sites) ! Increment the number of cohorts per site hio_ncohorts_si(io_si) = hio_ncohorts_si(io_si) + 1._r8 + if ( cpatch%anthro_disturbance_label .eq. secondaryforest ) then + hio_ncohorts_sec_si(io_si) = hio_ncohorts_sec_si(io_si) + 1._r8 + end if + n_perm2 = ccohort%n * AREA_INV hio_canopy_area_si_age(io_si,cpatch%age_class) = hio_canopy_area_si_age(io_si,cpatch%age_class) & + ccohort%c_area * AREA_INV ! calculate leaf height distribution, assuming leaf area is evenly distributed thru crown depth - call CrownDepth(ccohort%hite,ft,crown_depth) - height_bin_max = get_height_index(ccohort%hite) - height_bin_min = get_height_index(ccohort%hite - crown_depth) + call CrownDepth(ccohort%height,ft,crown_depth) + height_bin_max = get_height_index(ccohort%height) + height_bin_min = get_height_index(ccohort%height - crown_depth) do i_heightbin = height_bin_min, height_bin_max binbottom = ED_val_history_height_bin_edges(i_heightbin) if (i_heightbin .eq. nlevheight) then @@ -2267,8 +2820,8 @@ subroutine update_history_dyn(this,nc,nsites,sites) bintop = ED_val_history_height_bin_edges(i_heightbin+1) endif ! what fraction of a cohort's crown is in this height bin? - frac_canopy_in_bin = (min(bintop,ccohort%hite) - & - max(binbottom,ccohort%hite-crown_depth)) / & + frac_canopy_in_bin = (min(bintop,ccohort%height) - & + max(binbottom,ccohort%height-crown_depth)) / & (crown_depth) hio_leaf_height_dist_si_height(io_si,i_heightbin) = & @@ -2287,6 +2840,9 @@ subroutine update_history_dyn(this,nc,nsites,sites) hio_canopy_height_dist_si_height(io_si,height_bin_max) + ccohort%c_area * AREA_INV endif + call set_root_fraction(sites(s)%rootfrac_scr, ccohort%pft, sites(s)%zi_soil, & + bc_in(s)%max_rooting_depth_index_col ) + ! Update biomass components ! Mass pools [kg] elloop: do el = 1, num_elements @@ -2301,10 +2857,13 @@ subroutine update_history_dyn(this,nc,nsites,sites) alive_m = leaf_m + fnrt_m + sapw_m total_m = alive_m + store_m + struct_m + i_scpf = ccohort%size_by_pft_class + + ! Plant multi-element states and fluxes ! Zero states, and set the fluxes if( element_list(el).eq.carbon12_element )then - + ! mass in different tissues [kg/ha] -> [kg/m2] this%hvars(ih_storec_si)%r81d(io_si) = & this%hvars(ih_storec_si)%r81d(io_si) + ccohort%n * & @@ -2325,6 +2884,20 @@ subroutine update_history_dyn(this,nc,nsites,sites) this%hvars(ih_totvegc_si)%r81d(io_si)+ ccohort%n * & total_m / m2_per_ha + + call bstore_allom(ccohort%dbh,ccohort%pft,ccohort%crowndamage,ccohort%canopy_trim, store_max) + this%hvars(ih_storectfrac_si)%r81d(io_si) = & + this%hvars(ih_storectfrac_si)%r81d(io_si) + ccohort%n * store_max/m2_per_ha + + ! Determine the root carbon biomass in kg/m3 + ! [kg/m3] = [kg/plant] * [plant/ha] / [m3/ha] * [fraction] / [m] + + + do ilyr = 1,sites(s)%nlevsoil + this%hvars(ih_fnrtc_sl)%r82d(io_si,ilyr) = this%hvars(ih_fnrtc_sl)%r82d(io_si,ilyr) + & + fnrt_m * ccohort%n / area * sites(s)%rootfrac_scr(ilyr) / sites(s)%dz_soil(ilyr) + end do + hio_bdead_si(io_si) = hio_bdead_si(io_si) + n_perm2 * struct_m hio_balive_si(io_si) = hio_balive_si(io_si) + n_perm2 * alive_m @@ -2342,9 +2915,19 @@ subroutine update_history_dyn(this,nc,nsites,sites) hio_nindivs_si_pft(io_si,ft) = hio_nindivs_si_pft(io_si,ft) + & ccohort%n * AREA_INV + if ( cpatch%anthro_disturbance_label .eq. secondaryforest ) then + hio_nindivs_sec_si_pft(io_si,ft) = hio_nindivs_sec_si_pft(io_si,ft) + & + ccohort%n * AREA_INV + end if + hio_biomass_si_pft(io_si, ft) = hio_biomass_si_pft(io_si, ft) + & (ccohort%n * AREA_INV) * total_m + if ( cpatch%anthro_disturbance_label .eq. secondaryforest ) then + hio_biomass_sec_si_pft(io_si, ft) = hio_biomass_sec_si_pft(io_si, ft) + & + (ccohort%n * AREA_INV) * total_m + end if + ! update total biomass per age bin hio_biomass_si_age(io_si,cpatch%age_class) = hio_biomass_si_age(io_si,cpatch%age_class) & + total_m * ccohort%n * AREA_INV @@ -2355,9 +2938,24 @@ subroutine update_history_dyn(this,nc,nsites,sites) total_m * ccohort%n * AREA_INV endif - elseif(element_list(el).eq.nitrogen_element)then + if (ccohort%canopy_layer .eq. 1) then + storec_canopy_scpf(i_scpf) = & + storec_canopy_scpf(i_scpf) + ccohort%n * store_m + this%hvars(ih_storectfrac_canopy_scpf)%r82d(io_si,i_scpf) = & + this%hvars(ih_storectfrac_canopy_scpf)%r82d(io_si,i_scpf) + & + ccohort%n * store_max + else + storec_understory_scpf(i_scpf) = & + storec_understory_scpf(i_scpf) + ccohort%n * store_m + this%hvars(ih_storectfrac_ustory_scpf)%r82d(io_si,i_scpf) = & + this%hvars(ih_storectfrac_ustory_scpf)%r82d(io_si,i_scpf) + & + ccohort%n * store_max + end if + + + elseif(element_list(el).eq.nitrogen_element)then - store_max = ccohort%prt%GetNutrientTarget(element_list(el),store_organ) + store_max = ccohort%prt%GetNutrientTarget(element_list(el),store_organ,stoich_growth_min) this%hvars(ih_storen_si)%r81d(io_si) = & this%hvars(ih_storen_si)%r81d(io_si) + ccohort%n * & @@ -2381,9 +2979,23 @@ subroutine update_history_dyn(this,nc,nsites,sites) this%hvars(ih_totvegn_si)%r81d(io_si) + ccohort%n * & total_m / m2_per_ha + if (ccohort%canopy_layer .eq. 1) then + storen_canopy_scpf(i_scpf) = & + storen_canopy_scpf(i_scpf) + ccohort%n * store_m + this%hvars(ih_storentfrac_canopy_scpf)%r82d(io_si,i_scpf) = & + this%hvars(ih_storentfrac_canopy_scpf)%r82d(io_si,i_scpf) + & + ccohort%n * store_max + else + storen_understory_scpf(i_scpf) = & + storen_understory_scpf(i_scpf) + ccohort%n * store_m + this%hvars(ih_storentfrac_understory_scpf)%r82d(io_si,i_scpf) = & + this%hvars(ih_storentfrac_understory_scpf)%r82d(io_si,i_scpf) + & + ccohort%n * store_max + end if + elseif(element_list(el).eq.phosphorus_element) then - store_max = ccohort%prt%GetNutrientTarget(element_list(el),store_organ) + store_max = ccohort%prt%GetNutrientTarget(element_list(el),store_organ,stoich_growth_min) this%hvars(ih_storep_si)%r81d(io_si) = & this%hvars(ih_storep_si)%r81d(io_si) + ccohort%n * & @@ -2407,6 +3019,21 @@ subroutine update_history_dyn(this,nc,nsites,sites) this%hvars(ih_totvegp_si)%r81d(io_si)+ ccohort%n * & total_m / m2_per_ha + if (ccohort%canopy_layer .eq. 1) then + storep_canopy_scpf(i_scpf) = & + storep_canopy_scpf(i_scpf) + ccohort%n * store_m + this%hvars(ih_storeptfrac_canopy_scpf)%r82d(io_si,i_scpf) = & + this%hvars(ih_storeptfrac_canopy_scpf)%r82d(io_si,i_scpf) + & + ccohort%n * store_max + else + storep_understory_scpf(i_scpf) = & + storep_understory_scpf(i_scpf) + ccohort%n * store_m + this%hvars(ih_storeptfrac_understory_scpf)%r82d(io_si,i_scpf) = & + this%hvars(ih_storeptfrac_understory_scpf)%r82d(io_si,i_scpf) + & + ccohort%n * store_max + end if + + end if end do elloop @@ -2427,6 +3054,13 @@ subroutine update_history_dyn(this,nc,nsites,sites) hio_npp_si_pft(io_si, ft) = hio_npp_si_pft(io_si, ft) + & ccohort%npp_acc_hold * n_perm2 / days_per_year / sec_per_day + if ( cpatch%anthro_disturbance_label .eq. secondaryforest ) then + hio_gpp_sec_si_pft(io_si, ft) = hio_gpp_sec_si_pft(io_si, ft) + & + ccohort%gpp_acc_hold * n_perm2 / days_per_year / sec_per_day + hio_npp_sec_si_pft(io_si, ft) = hio_npp_sec_si_pft(io_si, ft) + & + ccohort%npp_acc_hold * n_perm2 / days_per_year / sec_per_day + end if + ! Site by Size-Class x PFT (SCPF) ! ------------------------------------------------------------------------ @@ -2473,7 +3107,8 @@ subroutine update_history_dyn(this,nc,nsites,sites) associate( scpf => ccohort%size_by_pft_class, & scls => ccohort%size_class, & cacls => ccohort%coage_class, & - capf => ccohort%coage_by_pft_class) + capf => ccohort%coage_by_pft_class, & + cdam => ccohort%crowndamage) gpp_cached = (hio_gpp_si_scpf(io_si,scpf)) * & days_per_year * sec_per_day @@ -2505,22 +3140,27 @@ subroutine update_history_dyn(this,nc,nsites,sites) hio_npp_stor_si_scpf(io_si,scpf) = hio_npp_stor_si_scpf(io_si,scpf) + & store_m_net_alloc*n_perm2 / days_per_year / sec_per_day + ! Woody State Variables (basal area growth increment) - if ( int(prt_params%woody(ft)) == itrue) then + if ( prt_params%woody(ft) == itrue) then ! basal area [m2/m2] hio_ba_si_scpf(io_si,scpf) = hio_ba_si_scpf(io_si,scpf) + & - 0.25_r8*3.14159_r8*((dbh/100.0_r8)**2.0_r8)*ccohort%n / m2_per_ha + 0.25_r8*pi_const*((dbh/100.0_r8)**2.0_r8)*ccohort%n / m2_per_ha ! also by size class only hio_ba_si_scls(io_si,scls) = hio_ba_si_scls(io_si,scls) + & - 0.25_r8*3.14159_r8*((dbh/100.0_r8)**2.0_r8)* & + 0.25_r8*pi_const*((dbh/100.0_r8)**2.0_r8)* & ccohort%n / m2_per_ha ! growth increment hio_ddbh_si_scpf(io_si,scpf) = hio_ddbh_si_scpf(io_si,scpf) + & ccohort%ddbhdt*ccohort%n / m2_per_ha * m_per_cm + hio_ba_weighted_height_si(io_si) = hio_ba_weighted_height_si(io_si) + & + ccohort%height * & + 0.25_r8*pi_const*((dbh/100.0_r8)**2.0_r8)*ccohort%n / m2_per_ha + end if ! mortality sums [#/m2] @@ -2551,6 +3191,9 @@ subroutine update_history_dyn(this,nc,nsites,sites) ccohort%asmort*ccohort%n / m2_per_ha end if + + + hio_m1_si_scls(io_si,scls) = hio_m1_si_scls(io_si,scls) + ccohort%bmort*ccohort%n / m2_per_ha hio_m2_si_scls(io_si,scls) = hio_m2_si_scls(io_si,scls) + ccohort%hmort*ccohort%n / m2_per_ha hio_m3_si_scls(io_si,scls) = hio_m3_si_scls(io_si,scls) + ccohort%cmort*ccohort%n / m2_per_ha @@ -2560,6 +3203,24 @@ subroutine update_history_dyn(this,nc,nsites,sites) ccohort%frmort*ccohort%n / m2_per_ha hio_m9_si_scls(io_si,scls) = hio_m9_si_scls(io_si,scls) + ccohort%smort*ccohort%n / m2_per_ha + ! Examine secondary forest mortality and mortality rates + if(cpatch%anthro_disturbance_label .eq. secondaryforest) then + + if (hlm_use_cohort_age_tracking .eq.itrue) then + hio_m10_sec_si_scls(io_si,scls) = hio_m10_sec_si_scls(io_si,scls) + & + ccohort%asmort*ccohort%n / m2_per_ha + end if + + hio_m1_sec_si_scls(io_si,scls) = hio_m1_sec_si_scls(io_si,scls) + ccohort%bmort*ccohort%n / m2_per_ha + hio_m2_sec_si_scls(io_si,scls) = hio_m2_sec_si_scls(io_si,scls) + ccohort%hmort*ccohort%n / m2_per_ha + hio_m3_sec_si_scls(io_si,scls) = hio_m3_sec_si_scls(io_si,scls) + ccohort%cmort*ccohort%n / m2_per_ha + hio_m7_sec_si_scls(io_si,scls) = hio_m7_sec_si_scls(io_si,scls) + & + (ccohort%lmort_direct+ccohort%lmort_collateral+ccohort%lmort_infra) * ccohort%n / m2_per_ha + hio_m8_sec_si_scls(io_si,scls) = hio_m8_sec_si_scls(io_si,scls) + & + ccohort%frmort*ccohort%n / m2_per_ha + hio_m9_sec_si_scls(io_si,scls) = hio_m9_sec_si_scls(io_si,scls) + ccohort%smort*ccohort%n / m2_per_ha + end if + !C13 discrimination if(gpp_cached + ccohort%gpp_acc_hold > 0.0_r8)then hio_c13disc_si_scpf(io_si,scpf) = ((hio_c13disc_si_scpf(io_si,scpf) * gpp_cached) + & @@ -2577,6 +3238,39 @@ subroutine update_history_dyn(this,nc,nsites,sites) hio_nplant_si_cacls(io_si,cacls) = hio_nplant_si_cacls(io_si,cacls)+ccohort%n / m2_per_ha end if + ! damage variables - cohort level + if(hlm_use_tree_damage .eq. itrue) then + + cdpf = get_cdamagesizepft_class_index(ccohort%dbh, ccohort%crowndamage, ccohort%pft) + + this%hvars(ih_mortality_si_cdpf)%r82d(io_si,cdpf) = & + this%hvars(ih_mortality_si_cdpf)%r82d(io_si,cdpf) + & + (ccohort%bmort + ccohort%hmort + ccohort%cmort + ccohort%frmort + & + ccohort%smort + ccohort%asmort + ccohort%dgmort) * ccohort%n / m2_per_ha + & + (ccohort%lmort_direct + ccohort%lmort_collateral + ccohort%lmort_infra) * & + ccohort%n * sec_per_day * days_per_year / m2_per_ha + + ! crown damage by size by pft + this%hvars(ih_nplant_si_cdpf)%r82d(io_si, cdpf) = & + this%hvars(ih_nplant_si_cdpf)%r82d(io_si, cdpf) + ccohort%n / m2_per_ha + this%hvars(ih_m3_si_cdpf)%r82d(io_si, cdpf) = & + this%hvars(ih_m3_si_cdpf)%r82d(io_si, cdpf) + & + ccohort%cmort * ccohort%n / m2_per_ha + + ! mortality + this%hvars(ih_m11_si_scpf)%r82d(io_si,scpf) = & + this%hvars(ih_m11_si_scpf)%r82d(io_si,scpf) + & + ccohort%dgmort*ccohort%n / m2_per_ha + this%hvars(ih_m11_si_cdpf)%r82d(io_si,cdpf) = & + this%hvars(ih_m11_si_cdpf)%r82d(io_si,cdpf) + & + ccohort%dgmort*ccohort%n / m2_per_ha + + this%hvars(ih_ddbh_si_cdpf)%r82d(io_si,cdpf) = & + this%hvars(ih_ddbh_si_cdpf)%r82d(io_si,cdpf) + & + ccohort%ddbhdt*ccohort%n / m2_per_ha * m_per_cm + + end if + ! Carbon only metrics sapw_m = ccohort%prt%GetState(sapw_organ, carbon12_element) struct_m = ccohort%prt%GetState(struct_organ, carbon12_element) @@ -2587,7 +3281,37 @@ subroutine update_history_dyn(this,nc,nsites,sites) alive_m = leaf_m + fnrt_m + sapw_m total_m = alive_m + store_m + struct_m + hio_mortality_carbonflux_si_pft(io_si,ccohort%pft) = hio_mortality_carbonflux_si_pft(io_si,ccohort%pft) + & + (ccohort%bmort + ccohort%hmort + ccohort%cmort + & + ccohort%frmort + ccohort%smort + ccohort%asmort + ccohort%dgmort) * & + total_m * ccohort%n * days_per_sec * years_per_day * ha_per_m2 + & + (ccohort%lmort_direct + ccohort%lmort_collateral + ccohort%lmort_infra) * total_m * & + ccohort%n * ha_per_m2 + + + hio_hydraulicmortality_carbonflux_si_pft(io_si,ccohort%pft) = hio_hydraulicmortality_carbonflux_si_pft(io_si,ccohort%pft) + & + ccohort%hmort * total_m * ccohort%n * days_per_sec * years_per_day * ha_per_m2 + + hio_cstarvmortality_carbonflux_si_pft(io_si,ccohort%pft) = hio_cstarvmortality_carbonflux_si_pft(io_si,ccohort%pft) + & + ccohort%cmort * total_m * ccohort%n * days_per_sec * years_per_day * ha_per_m2 + + ! Aboveground mortality + hio_abg_mortality_cflux_si_scpf(io_si,scpf) = hio_abg_mortality_cflux_si_scpf(io_si,scpf) + & + (ccohort%bmort + ccohort%hmort + ccohort%cmort + & + ccohort%frmort + ccohort%smort + ccohort%asmort) * & + ( (sapw_m + struct_m + store_m ) * prt_params%allom_agb_frac(ccohort%pft) + & + leaf_m ) * ccohort%n * days_per_sec * years_per_day * ha_per_m2 + & + (ccohort%lmort_direct + ccohort%lmort_collateral + ccohort%lmort_infra) * & + ( (sapw_m + struct_m + store_m ) * prt_params%allom_agb_frac(ccohort%pft) + & + leaf_m ) * ccohort%n * ha_per_m2 + + ! Aboveground woody productivity + hio_abg_productivity_cflux_si_scpf(io_si,scpf) = hio_abg_productivity_cflux_si_scpf(io_si,scpf) + & + ( (sapw_m_net_alloc + struct_m_net_alloc + store_m_net_alloc) * prt_params%allom_agb_frac(ccohort%pft) + & + leaf_m_net_alloc ) * n_perm2 / & + days_per_year / sec_per_day + ! number density by size and biomass hio_agb_si_scls(io_si,scls) = hio_agb_si_scls(io_si,scls) + & total_m * ccohort%n * prt_params%allom_agb_frac(ccohort%pft) * AREA_INV @@ -2626,13 +3350,15 @@ subroutine update_history_dyn(this,nc,nsites,sites) hio_nplant_canopy_si_scag(io_si,iscag) = hio_nplant_canopy_si_scag(io_si,iscag) + ccohort%n / m2_per_ha hio_mortality_canopy_si_scag(io_si,iscag) = hio_mortality_canopy_si_scag(io_si,iscag) + & (ccohort%bmort + ccohort%hmort + ccohort%cmort + & - ccohort%frmort + ccohort%smort + ccohort%asmort) * ccohort%n / m2_per_ha + ccohort%frmort + ccohort%smort + ccohort%asmort + ccohort%dgmort) * ccohort%n / m2_per_ha hio_ddbh_canopy_si_scag(io_si,iscag) = hio_ddbh_canopy_si_scag(io_si,iscag) + & ccohort%ddbhdt*ccohort%n * m_per_cm / m2_per_ha hio_bstor_canopy_si_scpf(io_si,scpf) = hio_bstor_canopy_si_scpf(io_si,scpf) + & store_m * ccohort%n / m2_per_ha hio_bleaf_canopy_si_scpf(io_si,scpf) = hio_bleaf_canopy_si_scpf(io_si,scpf) + & leaf_m * ccohort%n / m2_per_ha + hio_lai_canopy_si_scpf(io_si,scpf) = hio_lai_canopy_si_scpf(io_si,scpf) + & + ccohort%treelai*ccohort%c_area * AREA_INV hio_canopy_biomass_si(io_si) = hio_canopy_biomass_si(io_si) + n_perm2 * total_m @@ -2642,10 +3368,13 @@ subroutine update_history_dyn(this,nc,nsites,sites) hio_mortality_canopy_si_scpf(io_si,scpf) = hio_mortality_canopy_si_scpf(io_si,scpf)+ & (ccohort%bmort + ccohort%hmort + ccohort%cmort + ccohort%frmort + & - ccohort%smort + ccohort%asmort) * ccohort%n / m2_per_ha + & + ccohort%smort + ccohort%asmort + ccohort%dgmort) * ccohort%n / m2_per_ha + & (ccohort%lmort_direct + ccohort%lmort_collateral + ccohort%lmort_infra) * & ccohort%n * sec_per_day * days_per_year / m2_per_ha + hio_m3_mortality_canopy_si_scpf(io_si,scpf) = hio_m3_mortality_canopy_si_scpf(io_si,scpf) + & + ccohort%cmort * ccohort%n / m2_per_ha + hio_nplant_canopy_si_scpf(io_si,scpf) = hio_nplant_canopy_si_scpf(io_si,scpf) + ccohort%n / m2_per_ha hio_nplant_canopy_si_scls(io_si,scls) = hio_nplant_canopy_si_scls(io_si,scls) + ccohort%n / m2_per_ha hio_lai_canopy_si_scls(io_si,scls) = hio_lai_canopy_si_scls(io_si,scls) + & @@ -2669,21 +3398,63 @@ subroutine update_history_dyn(this,nc,nsites,sites) ! sum of all mortality hio_mortality_canopy_si_scls(io_si,scls) = hio_mortality_canopy_si_scls(io_si,scls) + & (ccohort%bmort + ccohort%hmort + ccohort%cmort + & - ccohort%frmort + ccohort%smort + ccohort%asmort) * ccohort%n / m2_per_ha + & + ccohort%frmort + ccohort%smort + ccohort%asmort + ccohort%dgmort) * ccohort%n / m2_per_ha + & (ccohort%lmort_direct + ccohort%lmort_collateral + ccohort%lmort_infra) * & ccohort%n * sec_per_day * days_per_year / m2_per_ha + hio_m3_mortality_canopy_si_scls(io_si,scls) = hio_m3_mortality_canopy_si_scls(io_si,scls) + & + ccohort%cmort * ccohort%n / m2_per_ha + hio_canopy_mortality_carbonflux_si(io_si) = hio_canopy_mortality_carbonflux_si(io_si) + & (ccohort%bmort + ccohort%hmort + ccohort%cmort + & - ccohort%frmort + ccohort%smort + ccohort%asmort) * & + ccohort%frmort + ccohort%smort + ccohort%asmort + ccohort%dgmort) * & total_m * ccohort%n * days_per_sec * years_per_day * ha_per_m2 + & (ccohort%lmort_direct + ccohort%lmort_collateral + ccohort%lmort_infra) * total_m * & ccohort%n * ha_per_m2 + hio_canopy_mortality_crownarea_si(io_si) = hio_canopy_mortality_crownarea_si(io_si) + & + (ccohort%bmort + ccohort%hmort + ccohort%cmort + & + ccohort%frmort + ccohort%smort + ccohort%asmort + ccohort%dgmort) * & + ccohort%c_area + & + (ccohort%lmort_direct + ccohort%lmort_collateral + ccohort%lmort_infra) * & + ccohort%c_area * sec_per_day * days_per_year hio_carbon_balance_canopy_si_scls(io_si,scls) = hio_carbon_balance_canopy_si_scls(io_si,scls) + & - ccohort%n * ccohort%npp_acc_hold / m2_per_ha / days_per_year / sec_per_day - + ccohort%n * ccohort%npp_acc_hold / m2_per_ha / days_per_year / sec_per_day + + ! damage variables - canopy + if(hlm_use_tree_damage .eq. itrue) then + + ! carbon starvation mortality in the canopy by size x damage x pft + this%hvars(ih_m3_mortality_canopy_si_cdpf)%r82d(io_si,cdpf) = & + this%hvars(ih_m3_mortality_canopy_si_cdpf)%r82d(io_si,cdpf)+& + ccohort%cmort * ccohort%n / m2_per_ha + + ! damage mortality in the canopy by size x damage x pft + this%hvars(ih_m11_mortality_canopy_si_cdpf)%r82d(io_si,cdpf) = & + this%hvars(ih_m11_mortality_canopy_si_cdpf)%r82d(io_si,cdpf)+& + ccohort%dgmort * ccohort%n / m2_per_ha + + this%hvars(ih_mortality_canopy_si_cdpf)%r82d(io_si,cdpf) = & + this%hvars(ih_mortality_canopy_si_cdpf)%r82d(io_si,cdpf)+ & + (ccohort%bmort + ccohort%hmort + ccohort%cmort + ccohort%frmort + ccohort%smort + & + ccohort%asmort + ccohort%dgmort) * ccohort%n / m2_per_ha + & + (ccohort%lmort_direct + ccohort%lmort_collateral + ccohort%lmort_infra) * & + ccohort%n * sec_per_day * days_per_year / m2_per_ha + + ! nplants by damage + this%hvars(ih_nplant_canopy_si_cdpf)%r82d(io_si,cdpf) = & + this%hvars(ih_nplant_canopy_si_cdpf)%r82d(io_si,cdpf) + & + ccohort%n / m2_per_ha + + ! growth rate by damage x size x pft in the canopy + this%hvars(ih_ddbh_canopy_si_cdpf)%r82d(io_si,cdpf) = & + this%hvars(ih_ddbh_canopy_si_cdpf)%r82d(io_si,cdpf) + & + ccohort%ddbhdt*ccohort%n / m2_per_ha * m_per_cm + + end if ! end if damage + + hio_leaf_md_canopy_si_scls(io_si,scls) = hio_leaf_md_canopy_si_scls(io_si,scls) + & leaf_m_turnover * ccohort%n / m2_per_ha / days_per_year / sec_per_day hio_root_md_canopy_si_scls(io_si,scls) = hio_root_md_canopy_si_scls(io_si,scls) + & @@ -2713,11 +3484,14 @@ subroutine update_history_dyn(this,nc,nsites,sites) hio_yesterdaycanopylevel_canopy_si_scls(io_si,scls) = & hio_yesterdaycanopylevel_canopy_si_scls(io_si,scls) + & ccohort%canopy_layer_yesterday * ccohort%n / m2_per_ha + + hio_ca_weighted_height_si(io_si) = hio_ca_weighted_height_si(io_si) + & + ccohort%height * ccohort%c_area / m2_per_ha else canlayer hio_nplant_understory_si_scag(io_si,iscag) = hio_nplant_understory_si_scag(io_si,iscag) + ccohort%n / m2_per_ha hio_mortality_understory_si_scag(io_si,iscag) = hio_mortality_understory_si_scag(io_si,iscag) + & (ccohort%bmort + ccohort%hmort + ccohort%cmort + & - ccohort%frmort + ccohort%smort + ccohort%asmort) * ccohort%n / m2_per_ha + ccohort%frmort + ccohort%smort + ccohort%asmort + ccohort%dgmort) * ccohort%n / m2_per_ha hio_ddbh_understory_si_scag(io_si,iscag) = hio_ddbh_understory_si_scag(io_si,iscag) + & ccohort%ddbhdt*ccohort%n * m_per_cm / m2_per_ha hio_bstor_understory_si_scpf(io_si,scpf) = hio_bstor_understory_si_scpf(io_si,scpf) + & @@ -2726,6 +3500,8 @@ subroutine update_history_dyn(this,nc,nsites,sites) leaf_m * ccohort%n / m2_per_ha hio_understory_biomass_si(io_si) = hio_understory_biomass_si(io_si) + & n_perm2 * total_m + hio_lai_understory_si_scpf(io_si,scpf) = hio_lai_understory_si_scpf(io_si,scpf) + & + ccohort%treelai*ccohort%c_area * AREA_INV !hio_mortality_understory_si_scpf(io_si,scpf) = hio_mortality_understory_si_scpf(io_si,scpf)+ & ! (ccohort%bmort + ccohort%hmort + ccohort%cmort + @@ -2733,10 +3509,21 @@ subroutine update_history_dyn(this,nc,nsites,sites) hio_mortality_understory_si_scpf(io_si,scpf) = hio_mortality_understory_si_scpf(io_si,scpf)+ & (ccohort%bmort + ccohort%hmort + ccohort%cmort + & - ccohort%frmort + ccohort%smort + ccohort%asmort) * ccohort%n / m2_per_ha + & + ccohort%frmort + ccohort%smort + ccohort%asmort + ccohort%dgmort) * ccohort%n / m2_per_ha + & (ccohort%lmort_direct + ccohort%lmort_collateral + ccohort%lmort_infra) * & ccohort%n * sec_per_day * days_per_year / m2_per_ha + hio_m3_mortality_understory_si_scpf(io_si,scpf) = hio_m3_mortality_understory_si_scpf(io_si,scpf) + & + ccohort%cmort * ccohort%n / m2_per_ha + + if ( cpatch%anthro_disturbance_label .eq. secondaryforest ) then + hio_mortality_canopy_secondary_si_scls(io_si,scls) = hio_mortality_canopy_secondary_si_scls(io_si,scls) + & + (ccohort%bmort + ccohort%hmort + ccohort%cmort + & + ccohort%frmort + ccohort%smort + ccohort%asmort) * ccohort%n / m2_per_ha + & + (ccohort%lmort_direct + ccohort%lmort_collateral + ccohort%lmort_infra) * & + ccohort%n * sec_per_day * days_per_year / m2_per_ha + end if + hio_nplant_understory_si_scpf(io_si,scpf) = hio_nplant_understory_si_scpf(io_si,scpf) + ccohort%n / m2_per_ha hio_nplant_understory_si_scls(io_si,scls) = hio_nplant_understory_si_scls(io_si,scls) + ccohort%n / m2_per_ha hio_lai_understory_si_scls(io_si,scls) = hio_lai_understory_si_scls(io_si,scls) + & @@ -2761,19 +3548,61 @@ subroutine update_history_dyn(this,nc,nsites,sites) ! sum of all mortality hio_mortality_understory_si_scls(io_si,scls) = hio_mortality_understory_si_scls(io_si,scls) + & (ccohort%bmort + ccohort%hmort + ccohort%cmort + & - ccohort%frmort + ccohort%smort + ccohort%asmort) * ccohort%n / m2_per_ha + & + ccohort%frmort + ccohort%smort + ccohort%asmort + ccohort%dgmort) * ccohort%n / m2_per_ha + & (ccohort%lmort_direct + ccohort%lmort_collateral + ccohort%lmort_infra) * & ccohort%n * sec_per_day * days_per_year / m2_per_ha + hio_m3_mortality_understory_si_scls(io_si,scls) = hio_m3_mortality_understory_si_scls(io_si,scls) + & + ccohort%cmort * ccohort%n / m2_per_ha + hio_understory_mortality_carbonflux_si(io_si) = hio_understory_mortality_carbonflux_si(io_si) + & (ccohort%bmort + ccohort%hmort + ccohort%cmort + & - ccohort%frmort + ccohort%smort + ccohort%asmort) * & - total_m * ccohort%n * days_per_sec * years_per_day * ha_per_m2 + & + ccohort%frmort + ccohort%smort + ccohort%asmort + ccohort%dgmort) * & + total_m * ccohort%n * days_per_sec * years_per_day * ha_per_m2 + & (ccohort%lmort_direct + ccohort%lmort_collateral + ccohort%lmort_infra) * total_m * & ccohort%n * ha_per_m2 + hio_understory_mortality_crownarea_si(io_si) = hio_understory_mortality_crownarea_si(io_si) + & + (ccohort%bmort + ccohort%hmort + ccohort%cmort + & + ccohort%frmort + ccohort%smort + ccohort%asmort + ccohort%dgmort) * & + ccohort%c_area + & + (ccohort%lmort_direct + ccohort%lmort_collateral + ccohort%lmort_infra) * & + ccohort%c_area * sec_per_day * days_per_year + hio_carbon_balance_understory_si_scls(io_si,scls) = hio_carbon_balance_understory_si_scls(io_si,scls) + & - ccohort%npp_acc_hold * ccohort%n / m2_per_ha / days_per_year / sec_per_day + ccohort%npp_acc_hold * ccohort%n / m2_per_ha / days_per_year / sec_per_day + + ! damage variables - understory + if(hlm_use_tree_damage .eq. itrue) then + + ! carbon mortality in the understory by damage x size x pft + this%hvars(ih_m3_mortality_understory_si_cdpf)%r82d(io_si,cdpf) = & + this%hvars(ih_m3_mortality_understory_si_cdpf)%r82d(io_si,cdpf) + & + ccohort%cmort * ccohort%n / m2_per_ha + + ! damage in the understory by damage x size x pft + this%hvars(ih_m11_mortality_understory_si_cdpf)%r82d(io_si,cdpf) = & + this%hvars(ih_m11_mortality_understory_si_cdpf)%r82d(io_si,cdpf) + & + ccohort%dgmort * ccohort%n / m2_per_ha + + ! total mortality of understory cohorts by damage x size x pft + this%hvars(ih_mortality_understory_si_cdpf)%r82d(io_si,cdpf) = & + this%hvars(ih_mortality_understory_si_cdpf)%r82d(io_si,cdpf) + & + (ccohort%bmort + ccohort%hmort + ccohort%cmort + ccohort%frmort + & + ccohort%smort + ccohort%asmort + ccohort%dgmort) * ccohort%n / m2_per_ha + & + (ccohort%lmort_direct + ccohort%lmort_collateral + ccohort%lmort_infra) * & + ccohort%n * sec_per_day * days_per_year / m2_per_ha + + this%hvars(ih_nplant_understory_si_cdpf)%r82d(io_si,cdpf) = & + this%hvars(ih_nplant_understory_si_cdpf)%r82d(io_si,cdpf) + & + ccohort%n / m2_per_ha + + ! growth rate by size x damage x pft - understory + this%hvars(ih_ddbh_understory_si_cdpf)%r82d(io_si,cdpf) = & + this%hvars(ih_ddbh_understory_si_cdpf)%r82d(io_si,cdpf) + & + ccohort%ddbhdt*ccohort%n / m2_per_ha * m_per_cm + + end if ! end if damage hio_leaf_md_understory_si_scls(io_si,scls) = hio_leaf_md_understory_si_scls(io_si,scls) + & leaf_m_turnover * ccohort%n / m2_per_ha / days_per_year / sec_per_day @@ -2889,7 +3718,7 @@ subroutine update_history_dyn(this,nc,nsites,sites) ! Update Litter Flux Variables litt_c => cpatch%litter(element_pos(carbon12_element)) - flux_diags_c => sites(s)%flux_diags(element_pos(carbon12_element)) + do i_cwd = 1, ncwd @@ -2912,9 +3741,18 @@ subroutine update_history_dyn(this,nc,nsites,sites) cpatch => cpatch%younger end do patchloop !patch loop - ! divide so-far-just-summed but to-be-averaged patch-age-class variables by patch-age-class area to get mean values + + ! divide basal-area-weighted height by basal area to get mean + if ( sum(hio_ba_si_scpf(io_si,:)) .gt. nearzero ) then + hio_ba_weighted_height_si(io_si) = hio_ba_weighted_height_si(io_si) / sum(hio_ba_si_scpf(io_si,:)) + else + hio_ba_weighted_height_si(io_si) = 0._r8 + endif + + ! divide so-far-just-summed but to-be-averaged patch-age-class + ! variables by patch-age-class area to get mean values do ipa2 = 1, nlevage - if (hio_area_si_age(io_si, ipa2) .gt. tiny) then + if (hio_area_si_age(io_si, ipa2) .gt. nearzero) then hio_lai_si_age(io_si, ipa2) = hio_lai_si_age(io_si, ipa2) / (hio_area_si_age(io_si, ipa2)*AREA) hio_ncl_si_age(io_si, ipa2) = hio_ncl_si_age(io_si, ipa2) / (hio_area_si_age(io_si, ipa2)*AREA) do i_pft = 1, numpft @@ -2928,6 +3766,13 @@ subroutine update_history_dyn(this,nc,nsites,sites) endif end do + ! divide secondary plant leaf area by secondary forest area to get the secondary forest LAI + if (hio_fraction_secondary_forest_si(io_si) .gt. nearzero) then + hio_lai_secondary_si(io_si) = hio_lai_secondary_si(io_si) / (hio_fraction_secondary_forest_si(io_si)*AREA) + else + hio_lai_secondary_si(io_si) = 0._r8 + end if + ! pass the cohort termination mortality as a flux to the history, and then reset the termination mortality buffer ! note there are various ways of reporting the total mortality, so pass to these as well do i_pft = 1, numpft @@ -2990,6 +3835,12 @@ subroutine update_history_dyn(this,nc,nsites,sites) hio_mortality_canopy_si_scls(io_si,i_scls) = hio_mortality_canopy_si_scls(io_si,i_scls) + & sites(s)%fmort_rate_canopy(i_scls, i_pft) / m2_per_ha + ! Shijie: Think about how to add later? + !if ( cpatch%anthro_disturbance_label .eq. secondaryforest ) then + ! hio_mortality_canopy_secondary_si_scls(io_si,i_scls) = hio_mortality_canopy_secondary_si_scls(io_si,i_scls) + & + ! sites(s)%term_nindivs_canopy(i_scls,i_pft) * days_per_year / m2_per_ha + !end if + ! the fire mortality rates for each layer are total dead, since the usable ! output will then normalize by the counts, we are allowed to sum over layers hio_mortality_understory_si_scpf(io_si,i_scpf) = hio_mortality_understory_si_scpf(io_si,i_scpf) + & @@ -2998,14 +3849,6 @@ subroutine update_history_dyn(this,nc,nsites,sites) hio_mortality_understory_si_scls(io_si,i_scls) = hio_mortality_understory_si_scls(io_si,i_scls) + & sites(s)%fmort_rate_ustory(i_scls, i_pft) / m2_per_ha - ! - ! carbon flux associated with mortality of trees dying by fire - hio_canopy_mortality_carbonflux_si(io_si) = hio_canopy_mortality_carbonflux_si(io_si) + & - sites(s)%fmort_carbonflux_canopy / g_per_kg - - hio_understory_mortality_carbonflux_si(io_si) = hio_understory_mortality_carbonflux_si(io_si) + & - sites(s)%fmort_carbonflux_ustory / g_per_kg - ! ! for scag variables, also treat as happening in the newly-disurbed patch @@ -3021,25 +3864,111 @@ subroutine update_history_dyn(this,nc,nsites,sites) end do end do + ! + ! carbon flux associated with mortality of trees dying by fire + hio_canopy_mortality_carbonflux_si(io_si) = hio_canopy_mortality_carbonflux_si(io_si) + & + sum(sites(s)%fmort_carbonflux_canopy(:)) / g_per_kg + + hio_understory_mortality_carbonflux_si(io_si) = hio_understory_mortality_carbonflux_si(io_si) + & + sum(sites(s)%fmort_carbonflux_ustory(:)) / g_per_kg + ! treat carbon flux from imort the same way hio_understory_mortality_carbonflux_si(io_si) = hio_understory_mortality_carbonflux_si(io_si) + & - sites(s)%imort_carbonflux / g_per_kg - ! + sum(sites(s)%imort_carbonflux(:)) + + do i_pft = 1, numpft + hio_mortality_carbonflux_si_pft(io_si,i_pft) = hio_mortality_carbonflux_si_pft(io_si,i_pft) + & + (sites(s)%fmort_carbonflux_canopy(i_pft) + & + sites(s)%fmort_carbonflux_ustory(i_pft) ) / g_per_kg + & + sites(s)%imort_carbonflux(i_pft) + & + sites(s)%term_carbonflux_ustory(i_pft) * days_per_sec * ha_per_m2 + & + sites(s)%term_carbonflux_canopy(i_pft) * days_per_sec * ha_per_m2 + + hio_firemortality_carbonflux_si_pft(io_si,i_pft) = sites(s)%fmort_carbonflux_canopy(i_pft) / g_per_kg + end do + + ! add imort and fmort to aboveground woody mortality + do i_pft = 1, numpft + do i_scls = 1,nlevsclass + i_scpf = (i_pft-1)*nlevsclass + i_scls + hio_abg_mortality_cflux_si_scpf(io_si,i_scpf) = hio_abg_mortality_cflux_si_scpf(io_si,i_scpf) + & + (sites(s)%fmort_abg_flux(i_scls,i_pft) / g_per_kg ) + & + sites(s)%imort_abg_flux(i_scls,i_pft) + & + (sites(s)%term_abg_flux(i_scls,i_pft) * days_per_sec * ha_per_m2 ) + end do + end do + + + if(hlm_use_tree_damage .eq. itrue) then + + do i_pft = 1, numpft + do icdam = 1, nlevdamage + do i_scls = 1,nlevsclass + + icdsc = (icdam-1)*nlevsclass + i_scls + icdpf = (icdam-1)*nlevsclass + i_scls + & + (i_pft-1) * nlevsclass * nlevdamage + + this%hvars(ih_mortality_si_cdpf)%r82d(io_si, icdpf) = & + this%hvars(ih_mortality_si_cdpf)%r82d(io_si, icdpf) + & + ( (sites(s)%term_nindivs_canopy_damage(icdam, i_scls, i_pft) * days_per_year) + & + (sites(s)%term_nindivs_ustory_damage(icdam, i_scls, i_pft) * days_per_year) + & + sites(s)%imort_rate_damage(icdam, i_scls, i_pft) + & + sites(s)%fmort_rate_canopy_damage(icdam, i_scls, i_pft) + & + sites(s)%fmort_rate_ustory_damage(icdam, i_scls, i_pft) ) / m2_per_ha + + this%hvars(ih_mortality_canopy_si_cdpf)%r82d(io_si,icdpf) = & + this%hvars(ih_mortality_canopy_si_cdpf)%r82d(io_si,icdpf) + & + ( sites(s)%term_nindivs_canopy_damage(icdam,i_scls,i_pft) * days_per_year + & + sites(s)%fmort_rate_canopy_damage(icdam, i_scls, i_pft) )/ m2_per_ha + + this%hvars(ih_mortality_understory_si_cdpf)%r82d(io_si,icdpf) = & + this%hvars(ih_mortality_understory_si_cdpf)%r82d(io_si,icdpf) + & + ( sites(s)%term_nindivs_ustory_damage(icdam, i_scls,i_pft) * days_per_year + & + sites(s)%imort_rate_damage(icdam, i_scls, i_pft) + & + sites(s)%fmort_rate_ustory_damage(icdam, i_scls, i_pft) )/ m2_per_ha + + end do + end do + end do + end if + sites(s)%term_nindivs_canopy(:,:) = 0._r8 sites(s)%term_nindivs_ustory(:,:) = 0._r8 - sites(s)%imort_carbonflux = 0._r8 + sites(s)%imort_carbonflux(:) = 0._r8 sites(s)%imort_rate(:,:) = 0._r8 sites(s)%fmort_rate_canopy(:,:) = 0._r8 sites(s)%fmort_rate_ustory(:,:) = 0._r8 - sites(s)%fmort_carbonflux_canopy = 0._r8 - sites(s)%fmort_carbonflux_ustory = 0._r8 + sites(s)%fmort_carbonflux_canopy(:) = 0._r8 + sites(s)%fmort_carbonflux_ustory(:) = 0._r8 sites(s)%fmort_rate_cambial(:,:) = 0._r8 sites(s)%fmort_rate_crown(:,:) = 0._r8 sites(s)%growthflux_fusion(:,:) = 0._r8 - + sites(s)%fmort_abg_flux(:,:) = 0._r8 + sites(s)%imort_abg_flux(:,:) = 0._r8 + sites(s)%term_abg_flux(:,:) = 0._r8 + + sites(s)%imort_rate_damage(:,:,:) = 0.0_r8 + sites(s)%term_nindivs_canopy_damage(:,:,:) = 0.0_r8 + sites(s)%term_nindivs_ustory_damage(:,:,:) = 0.0_r8 + sites(s)%imort_cflux_damage(:,:) = 0._r8 + sites(s)%term_cflux_canopy_damage(:,:) = 0._r8 + sites(s)%term_cflux_ustory_damage(:,:) = 0._r8 + sites(s)%fmort_rate_canopy_damage(:,:,:) = 0._r8 + sites(s)%fmort_rate_ustory_damage(:,:,:) = 0._r8 + sites(s)%fmort_cflux_canopy_damage(:,:) = 0._r8 + sites(s)%fmort_cflux_ustory_damage(:,:) = 0._r8 + sites(s)%crownarea_canopy_damage = 0._r8 + sites(s)%crownarea_ustory_damage = 0._r8 + ! pass the recruitment rate as a flux to the history, and then reset the recruitment buffer do i_pft = 1, numpft + ! pass the recruitment rate as a flux to the history, and then reset the recruitment buffer hio_recruitment_si_pft(io_si,i_pft) = sites(s)%recruitment_rate(i_pft) * days_per_year / m2_per_ha + + ! Gridcell output and inputs + hio_seeds_out_gc_si_pft(io_si,i_pft) = sites(s)%seed_out(i_pft) + hio_seeds_in_gc_si_pft(io_si,i_pft) = sites(s)%seed_in(i_pft) end do sites(s)%recruitment_rate(:) = 0._r8 @@ -3059,7 +3988,12 @@ subroutine update_history_dyn(this,nc,nsites,sites) hio_m8_si_scpf(io_si,i_scpf) + & hio_m9_si_scpf(io_si,i_scpf) + & hio_m10_si_scpf(io_si,i_scpf) - + + if(hlm_use_tree_damage .eq. itrue) then + hio_mortality_si_pft(io_si, i_pft) = hio_mortality_si_pft(io_si,i_pft) + & + this%hvars(ih_m11_si_scpf)%r82d(io_si,i_scpf) + end if + end do end do @@ -3067,17 +4001,18 @@ subroutine update_history_dyn(this,nc,nsites,sites) ! Some carbon only litter diagnostics (legacy) ! ------------------------------------------------------------------------------ - flux_diags => sites(s)%flux_diags(element_pos(carbon12_element)) - - hio_litter_in_si(io_si) = (sum(flux_diags%cwd_ag_input(:)) + & - sum(flux_diags%cwd_bg_input(:)) + & - sum(flux_diags%leaf_litter_input(:)) + & - sum(flux_diags%root_litter_input(:))) * & + hio_litter_in_si(io_si) = (sum(flux_diags_c%cwd_ag_input(:)) + & + sum(flux_diags_c%cwd_bg_input(:)) + & + sum(flux_diags_c%leaf_litter_input(:)) + & + sum(flux_diags_c%root_litter_input(:))) * & AREA_INV * days_per_sec hio_litter_out_si(io_si) = 0._r8 hio_seed_bank_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 cpatch => sites(s)%oldest_patch do while(associated(cpatch)) @@ -3086,23 +4021,39 @@ subroutine update_history_dyn(this,nc,nsites,sites) area_frac = cpatch%area * AREA_INV - ! Sum up all output fluxes (fragmentation) kgC/m2/day -> gC/m2/s + ! Sum up all output fluxes (fragmentation) kgC/m2/day -> kgC/m2/s hio_litter_out_si(io_si) = hio_litter_out_si(io_si) + & (sum(litt%leaf_fines_frag(:)) + & sum(litt%root_fines_frag(:,:)) + & sum(litt%ag_cwd_frag(:)) + & - sum(litt%bg_cwd_frag(:,:))) * & + sum(litt%bg_cwd_frag(:,:)) + & + sum(litt%seed_decay(:)) + & + sum(litt%seed_germ_decay(:))) * & area_frac * days_per_sec ! 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_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_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) 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_local_si(io_si) = hio_seeds_in_local_si(io_si) + & + sum(litt%seed_in_local(:)) * & + area_frac * days_per_sec + + cpatch => cpatch%younger end do @@ -3144,14 +4095,6 @@ subroutine update_history_dyn(this,nc,nsites,sites) this%hvars(ih_storec_scpf)%r82d(io_si,:) = 0._r8 this%hvars(ih_reproc_scpf)%r82d(io_si,:) = 0._r8 - this%hvars(ih_cefflux_scpf)%r82d(io_si,:) = & - sites(s)%flux_diags(el)%nutrient_efflux_scpf(:) / & - m2_per_ha / sec_per_day - - this%hvars(ih_cefflux_si)%r81d(io_si) = & - sum(sites(s)%flux_diags(el)%nutrient_efflux_scpf(:),dim=1) / & - m2_per_ha / sec_per_day - elseif(element_list(el).eq.nitrogen_element)then this%hvars(ih_totvegn_scpf)%r82d(io_si,:) = 0._r8 @@ -3159,52 +4102,17 @@ subroutine update_history_dyn(this,nc,nsites,sites) this%hvars(ih_fnrtn_scpf)%r82d(io_si,:) = 0._r8 this%hvars(ih_sapwn_scpf)%r82d(io_si,:) = 0._r8 this%hvars(ih_storen_scpf)%r82d(io_si,:) = 0._r8 - this%hvars(ih_storentfrac_canopy_scpf)%r82d(io_si,:) = 0._r8 - this%hvars(ih_storentfrac_understory_scpf)%r82d(io_si,:) = 0._r8 this%hvars(ih_repron_scpf)%r82d(io_si,:) = 0._r8 - - this%hvars(ih_nefflux_scpf)%r82d(io_si,:) = & - sites(s)%flux_diags(el)%nutrient_efflux_scpf(:) / & - m2_per_ha / sec_per_day - - this%hvars(ih_nneed_scpf)%r82d(io_si,:) = & - sites(s)%flux_diags(el)%nutrient_need_scpf(:) / & - m2_per_ha / sec_per_day - - this%hvars(ih_nneed_si)%r81d(io_si) = & - sum(sites(s)%flux_diags(el)%nutrient_need_scpf(:),dim=1) / & - m2_per_ha / sec_per_day - - this%hvars(ih_nefflux_si)%r81d(io_si) = & - sum(sites(s)%flux_diags(el)%nutrient_efflux_scpf(:),dim=1) / & - m2_per_ha / sec_per_day - - + elseif(element_list(el).eq.phosphorus_element)then this%hvars(ih_totvegp_scpf)%r82d(io_si,:) = 0._r8 this%hvars(ih_leafp_scpf)%r82d(io_si,:) = 0._r8 this%hvars(ih_fnrtp_scpf)%r82d(io_si,:) = 0._r8 this%hvars(ih_sapwp_scpf)%r82d(io_si,:) = 0._r8 this%hvars(ih_storep_scpf)%r82d(io_si,:) = 0._r8 - this%hvars(ih_storeptfrac_canopy_scpf)%r82d(io_si,:) = 0._r8 - this%hvars(ih_storeptfrac_understory_scpf)%r82d(io_si,:) = 0._r8 this%hvars(ih_reprop_scpf)%r82d(io_si,:) = 0._r8 - this%hvars(ih_pefflux_scpf)%r82d(io_si,:) = & - sites(s)%flux_diags(el)%nutrient_efflux_scpf(:) / & - m2_per_ha / sec_per_day - - this%hvars(ih_pneed_scpf)%r82d(io_si,:) = & - sites(s)%flux_diags(el)%nutrient_need_scpf(:) / & - m2_per_ha / sec_per_day - - this%hvars(ih_pneed_si)%r81d(io_si) = & - sum(sites(s)%flux_diags(el)%nutrient_need_scpf(:),dim=1) / & - m2_per_ha / sec_per_day - - this%hvars(ih_pefflux_si)%r81d(io_si) = & - sum(sites(s)%flux_diags(el)%nutrient_efflux_scpf(:),dim=1) / & - m2_per_ha / sec_per_day + end if @@ -3228,7 +4136,7 @@ subroutine update_history_dyn(this,nc,nsites,sites) sum(litt%seed(:)) * cpatch%area / m2_per_ha hio_seed_germ_elem(io_si,el) = hio_seed_germ_elem(io_si,el) + & - sum(litt%seed_germ(:)) * cpatch%area / m2_per_ha / sec_per_day + sum(litt%seed_germ(:)) * cpatch%area / m2_per_ha hio_seed_decay_elem(io_si,el) = hio_seed_decay_elem(io_si,el) + & sum(litt%seed_decay(:) + litt%seed_germ_decay(:) ) * & @@ -3297,7 +4205,7 @@ subroutine update_history_dyn(this,nc,nsites,sites) repro_m * ccohort%n / m2_per_ha elseif(element_list(el).eq.nitrogen_element)then - store_max = ccohort%prt%GetNutrientTarget(element_list(el),store_organ) + store_max = ccohort%prt%GetNutrientTarget(element_list(el),store_organ,stoich_growth_min) this%hvars(ih_totvegn_scpf)%r82d(io_si,i_scpf) = & this%hvars(ih_totvegn_scpf)%r82d(io_si,i_scpf) + & @@ -3318,17 +4226,9 @@ subroutine update_history_dyn(this,nc,nsites,sites) this%hvars(ih_repron_scpf)%r82d(io_si,i_scpf) + & repro_m * ccohort%n / m2_per_ha - if (ccohort%canopy_layer .eq. 1) then - this%hvars(ih_storentfrac_canopy_scpf)%r82d(io_si,i_scpf) = & - this%hvars(ih_storentfrac_canopy_scpf)%r82d(io_si,i_scpf) + store_m/store_max * ccohort%n - else - this%hvars(ih_storentfrac_understory_scpf)%r82d(io_si,i_scpf) = & - this%hvars(ih_storentfrac_understory_scpf)%r82d(io_si,i_scpf) + store_m/store_max * ccohort%n - end if - elseif(element_list(el).eq.phosphorus_element)then - store_max = ccohort%prt%GetNutrientTarget(element_list(el),store_organ) + store_max = ccohort%prt%GetNutrientTarget(element_list(el),store_organ,stoich_growth_min) this%hvars(ih_totvegp_scpf)%r82d(io_si,i_scpf) = & this%hvars(ih_totvegp_scpf)%r82d(io_si,i_scpf) + & @@ -3349,14 +4249,6 @@ subroutine update_history_dyn(this,nc,nsites,sites) this%hvars(ih_reprop_scpf)%r82d(io_si,i_scpf) + & repro_m * ccohort%n / m2_per_ha - if (ccohort%canopy_layer .eq. 1) then - this%hvars(ih_storeptfrac_canopy_scpf)%r82d(io_si,i_scpf) = & - this%hvars(ih_storeptfrac_canopy_scpf)%r82d(io_si,i_scpf) + store_m/store_max * ccohort%n - else - this%hvars(ih_storeptfrac_understory_scpf)%r82d(io_si,i_scpf) = & - this%hvars(ih_storeptfrac_understory_scpf)%r82d(io_si,i_scpf) + store_m/store_max * ccohort%n - end if - end if ccohort => ccohort%shorter @@ -3367,9 +4259,34 @@ subroutine update_history_dyn(this,nc,nsites,sites) end do ! end element loop - ! Normalize nutrient storage fractions + + ! Normalize storage fractions and L2FR + + if( this%hvars(ih_storectfrac_si)%r81d(io_si)>nearzero ) then + this%hvars(ih_storectfrac_si)%r81d(io_si) = this%hvars(ih_storec_si)%r81d(io_si) / & + this%hvars(ih_storectfrac_si)%r81d(io_si) + end if + + do i_pft = 1, numpft + do i_scls = 1,nlevsclass + i_scpf = (i_pft-1)*nlevsclass + i_scls + + if( this%hvars(ih_storectfrac_canopy_scpf)%r82d(io_si,i_scpf)>nearzero ) then + this%hvars(ih_storectfrac_canopy_scpf)%r82d(io_si,i_scpf) = & + storec_canopy_scpf(i_scpf) / & + this%hvars(ih_storectfrac_canopy_scpf)%r82d(io_si,i_scpf) + end if + if( this%hvars(ih_storectfrac_ustory_scpf)%r82d(io_si,i_scpf)>nearzero ) then + this%hvars(ih_storectfrac_ustory_scpf)%r82d(io_si,i_scpf) = & + storec_understory_scpf(i_scpf) / & + this%hvars(ih_storectfrac_ustory_scpf)%r82d(io_si,i_scpf) + end if + + end do + end do do el = 1, num_elements + if(element_list(el).eq.nitrogen_element)then if( this%hvars(ih_storentfrac_si)%r81d(io_si)>nearzero ) then this%hvars(ih_storentfrac_si)%r81d(io_si) = this%hvars(ih_storen_si)%r81d(io_si) / & @@ -3379,16 +4296,15 @@ subroutine update_history_dyn(this,nc,nsites,sites) do i_scls = 1,nlevsclass i_scpf = (i_pft-1)*nlevsclass + i_scls - if( hio_nplant_canopy_si_scpf(io_si,i_scpf)>nearzero ) then + if( this%hvars(ih_storentfrac_canopy_scpf)%r82d(io_si,i_scpf)>nearzero ) then this%hvars(ih_storentfrac_canopy_scpf)%r82d(io_si,i_scpf) = & - this%hvars(ih_storentfrac_canopy_scpf)%r82d(io_si,i_scpf) / & - (hio_nplant_canopy_si_scpf(io_si,i_scpf)*m2_per_ha) + storen_canopy_scpf(i_scpf) / & + this%hvars(ih_storentfrac_canopy_scpf)%r82d(io_si,i_scpf) end if - - if( hio_nplant_understory_si_scpf(io_si,i_scpf)>nearzero ) then + if( this%hvars(ih_storentfrac_understory_scpf)%r82d(io_si,i_scpf)>nearzero ) then this%hvars(ih_storentfrac_understory_scpf)%r82d(io_si,i_scpf) = & - this%hvars(ih_storentfrac_understory_scpf)%r82d(io_si,i_scpf) / & - (hio_nplant_understory_si_scpf(io_si,i_scpf)*m2_per_ha) + storen_understory_scpf(i_scpf) / & + this%hvars(ih_storentfrac_understory_scpf)%r82d(io_si,i_scpf) end if end do @@ -3402,16 +4318,15 @@ subroutine update_history_dyn(this,nc,nsites,sites) do i_scls = 1,nlevsclass i_scpf = (i_pft-1)*nlevsclass + i_scls - if( hio_nplant_canopy_si_scpf(io_si,i_scpf)>nearzero ) then + if( this%hvars(ih_storeptfrac_canopy_scpf)%r82d(io_si,i_scpf)>nearzero ) then this%hvars(ih_storeptfrac_canopy_scpf)%r82d(io_si,i_scpf) = & - this%hvars(ih_storeptfrac_canopy_scpf)%r82d(io_si,i_scpf) /& - (hio_nplant_canopy_si_scpf(io_si,i_scpf)*m2_per_ha) - + storep_canopy_scpf(i_scpf) / & + this%hvars(ih_storeptfrac_canopy_scpf)%r82d(io_si,i_scpf) end if - if( hio_nplant_understory_si_scpf(io_si,i_scpf)>nearzero ) then + if( this%hvars(ih_storeptfrac_understory_scpf)%r82d(io_si,i_scpf)>nearzero ) then this%hvars(ih_storeptfrac_understory_scpf)%r82d(io_si,i_scpf) = & - this%hvars(ih_storeptfrac_understory_scpf)%r82d(io_si,i_scpf) /& - (hio_nplant_understory_si_scpf(io_si,i_scpf)*m2_per_ha) + storep_understory_scpf(i_scpf) / & + this%hvars(ih_storeptfrac_understory_scpf)%r82d(io_si,i_scpf) end if end do @@ -3432,14 +4347,24 @@ subroutine update_history_dyn(this,nc,nsites,sites) ! mortality-associated carbon fluxes hio_canopy_mortality_carbonflux_si(io_si) = hio_canopy_mortality_carbonflux_si(io_si) + & - sites(s)%term_carbonflux_canopy * days_per_sec * ha_per_m2 + sum(sites(s)%term_carbonflux_canopy(:)) * days_per_sec * ha_per_m2 hio_understory_mortality_carbonflux_si(io_si) = hio_understory_mortality_carbonflux_si(io_si) + & - sites(s)%term_carbonflux_ustory * days_per_sec * ha_per_m2 + sum(sites(s)%term_carbonflux_ustory(:)) * days_per_sec * ha_per_m2 + ! add site level mortality counting to crownarea diagnostic + hio_canopy_mortality_crownarea_si(io_si) = hio_canopy_mortality_crownarea_si(io_si) + & + sites(s)%fmort_crownarea_canopy + & + sites(s)%term_crownarea_canopy * days_per_year + + hio_understory_mortality_crownarea_si(io_si) = hio_understory_mortality_crownarea_si(io_si) + & + sites(s)%fmort_crownarea_ustory + & + sites(s)%term_crownarea_ustory * days_per_year + & + sites(s)%imort_crownarea + ! and zero the site-level termination carbon flux variable - sites(s)%term_carbonflux_canopy = 0._r8 - sites(s)%term_carbonflux_ustory = 0._r8 + sites(s)%term_carbonflux_canopy(:) = 0._r8 + sites(s)%term_carbonflux_ustory(:) = 0._r8 ! ! add the site-level disturbance-associated cwd and litter input fluxes to thir respective flux fields @@ -3455,6 +4380,7 @@ subroutine update_history_dyn(this,nc,nsites,sites) enddo siteloop ! site loop + end associate end associate return @@ -3467,7 +4393,7 @@ subroutine update_history_hifrq(this,nc,nsites,sites,bc_in,dt_tstep) ! after rapid timescale productivity calculations (gpp and respiration). ! --------------------------------------------------------------------------------- - use EDTypesMod , only : nclmax, nlevleaf + use EDParamsMod , only : nclmax, nlevleaf ! ! Arguments class(fates_history_interface_type) :: this @@ -3489,20 +4415,25 @@ subroutine update_history_hifrq(this,nc,nsites,sites,bc_in,dt_tstep) real(r8) :: npp ! npp for this time-step (adjusted for g resp) [kgC/indiv/step] real(r8) :: aresp ! autotrophic respiration (adjusted for g resp) [kgC/indiv/step] real(r8) :: n_perm2 ! individuals per m2 for the whole column - real(r8) :: patch_area_by_age(nlevage) ! patch area in each bin for normalizing purposes + real(r8) :: patch_area_by_age(nlevage) ! patch area in each bin for normalizing purposes real(r8) :: canopy_area_by_age(nlevage) ! canopy area in each bin for normalizing purposes - real(r8), parameter :: tiny = 1.e-5_r8 ! some small number + real(r8) :: site_area_veg ! area of the site that is not bare-ground integer :: ipa2 ! patch incrementer integer :: cnlfpft_indx, cnlf_indx, ipft, ican, ileaf ! more iterators and indices - type(ed_patch_type),pointer :: cpatch - type(ed_cohort_type),pointer :: ccohort + type(fates_patch_type),pointer :: cpatch + type(fates_cohort_type),pointer :: ccohort real(r8) :: per_dt_tstep ! Time step in frequency units (/s) associate( hio_gpp_si => this%hvars(ih_gpp_si)%r81d, & + hio_gpp_secondary_si => this%hvars(ih_gpp_secondary_si)%r81d, & hio_npp_si => this%hvars(ih_npp_si)%r81d, & + hio_npp_secondary_si => this%hvars(ih_npp_secondary_si)%r81d, & hio_aresp_si => this%hvars(ih_aresp_si)%r81d, & + hio_aresp_secondary_si => this%hvars(ih_aresp_secondary_si)%r81d, & hio_maint_resp_si => this%hvars(ih_maint_resp_si)%r81d, & + hio_maint_resp_secondary_si => this%hvars(ih_maint_resp_secondary_si)%r81d, & hio_growth_resp_si => this%hvars(ih_growth_resp_si)%r81d, & + hio_growth_resp_secondary_si => this%hvars(ih_growth_resp_secondary_si)%r81d, & hio_c_stomata_si => this%hvars(ih_c_stomata_si)%r81d, & hio_c_lblayer_si => this%hvars(ih_c_lblayer_si)%r81d, & hio_rad_error_si => this%hvars(ih_rad_error_si)%r81d, & @@ -3568,8 +4499,9 @@ subroutine update_history_hifrq(this,nc,nsites,sites,bc_in,dt_tstep) hio_fabi_sha_top_si_can => this%hvars(ih_fabi_sha_top_si_can)%r82d, & hio_parsun_top_si_can => this%hvars(ih_parsun_top_si_can)%r82d, & hio_parsha_top_si_can => this%hvars(ih_parsha_top_si_can)%r82d, & + hio_maint_resp_unreduced_si => this%hvars(ih_maint_resp_unreduced_si)%r81d, & hio_tveg => this%hvars(ih_tveg_si)%r81d) - + ! Flush the relevant history variables call this%flush_hvars(nc,upfreq_in=2) @@ -3581,15 +4513,21 @@ subroutine update_history_hifrq(this,nc,nsites,sites,bc_in,dt_tstep) io_si = sites(s)%h_gid - hio_nep_si(io_si) = -bc_in(s)%tot_het_resp / g_per_kg ! (kgC/m2/s) - hio_hr_si(io_si) = bc_in(s)%tot_het_resp / g_per_kg + hio_nep_si(io_si) = -bc_in(s)%tot_het_resp * kg_per_g + hio_hr_si(io_si) = bc_in(s)%tot_het_resp * kg_per_g ipa = 0 - cpatch => sites(s)%oldest_patch - + patch_area_by_age(1:nlevage) = 0._r8 canopy_area_by_age(1:nlevage) = 0._r8 + + ! Calculate the site-level total vegetated area (i.e. non-bareground) + site_area_veg = area + if (hlm_use_nocomp .eq. itrue .and. hlm_use_fixed_biogeog .eq. itrue) then + site_area_veg = area - sites(s)%area_pft(0) + end if + cpatch => sites(s)%oldest_patch do while(associated(cpatch)) patch_area_by_age(cpatch%age_class) = & @@ -3601,24 +4539,28 @@ subroutine update_history_hifrq(this,nc,nsites,sites,bc_in,dt_tstep) ! Canopy resitance terms hio_c_stomata_si_age(io_si,cpatch%age_class) = & hio_c_stomata_si_age(io_si,cpatch%age_class) + & - cpatch%c_stomata * cpatch%total_canopy_area / umol_per_mol + cpatch%c_stomata * cpatch%total_canopy_area * mol_per_umol hio_c_lblayer_si_age(io_si,cpatch%age_class) = & hio_c_lblayer_si_age(io_si,cpatch%age_class) + & - cpatch%c_lblayer * cpatch%total_canopy_area / umol_per_mol + cpatch%c_lblayer * cpatch%total_canopy_area * mol_per_umol hio_c_stomata_si(io_si) = hio_c_stomata_si(io_si) + & - cpatch%c_stomata * cpatch%total_canopy_area / umol_per_mol + cpatch%c_stomata * cpatch%total_canopy_area * mol_per_umol hio_c_lblayer_si(io_si) = hio_c_lblayer_si(io_si) + & - cpatch%c_lblayer * cpatch%total_canopy_area / umol_per_mol + cpatch%c_lblayer * cpatch%total_canopy_area * mol_per_umol hio_rad_error_si(io_si) = hio_rad_error_si(io_si) + & cpatch%radiation_error * cpatch%area * AREA_INV + + ! Only accumulate the instantaneous vegetation temperature for vegetated patches + if (cpatch%patchno .ne. 0) then + hio_tveg(io_si) = hio_tveg(io_si) + & + (bc_in(s)%t_veg_pa(cpatch%patchno) - t_water_freeze_k_1atm) * & + cpatch%area / site_area_veg + end if - hio_tveg(io_si) = hio_tveg(io_si) + & - (bc_in(s)%t_veg_pa(cpatch%patchno) - t_water_freeze_k_1atm)*cpatch%area*area_inv - ccohort => cpatch%shortest do while(associated(ccohort)) @@ -3640,6 +4582,7 @@ subroutine update_history_hifrq(this,nc,nsites,sites,bc_in,dt_tstep) hio_gpp_si(io_si) = hio_gpp_si(io_si) + & ccohort%gpp_tstep * n_perm2 * per_dt_tstep + hio_aresp_si(io_si) = hio_aresp_si(io_si) + & aresp * n_perm2 * per_dt_tstep hio_growth_resp_si(io_si) = hio_growth_resp_si(io_si) + & @@ -3647,6 +4590,23 @@ subroutine update_history_hifrq(this,nc,nsites,sites,bc_in,dt_tstep) hio_maint_resp_si(io_si) = hio_maint_resp_si(io_si) + & ccohort%resp_m * n_perm2 * per_dt_tstep + hio_maint_resp_unreduced_si(io_si) = hio_maint_resp_unreduced_si(io_si) + & + ccohort%resp_m_unreduced * n_perm2 * per_dt_tstep + + ! Secondary forest only + if ( cpatch%anthro_disturbance_label .eq. secondaryforest ) then + hio_npp_secondary_si(io_si) = hio_npp_secondary_si(io_si) + & + npp * n_perm2 * per_dt_tstep + hio_gpp_secondary_si(io_si) = hio_gpp_secondary_si(io_si) + & + ccohort%gpp_tstep * n_perm2 * per_dt_tstep + hio_aresp_secondary_si(io_si) = hio_aresp_secondary_si(io_si) + & + aresp * n_perm2 * per_dt_tstep + hio_growth_resp_secondary_si(io_si) = hio_growth_resp_secondary_si(io_si) + & + resp_g * n_perm2 * per_dt_tstep + hio_maint_resp_secondary_si(io_si) = hio_maint_resp_secondary_si(io_si) + & + ccohort%resp_m * n_perm2 * per_dt_tstep + end if + ! Add up the total Net Ecosystem Production ! for this timestep. [kgC/m2/s] hio_nep_si(io_si) = hio_nep_si(io_si) + & @@ -3664,15 +4624,15 @@ subroutine update_history_hifrq(this,nc,nsites,sites,bc_in,dt_tstep) ! Total AR (kgC/m2/s) = (kgC/plant/step) / (s/step) * (plant/m2) hio_ar_si_scpf(io_si,scpf) = hio_ar_si_scpf(io_si,scpf) + & - (ccohort%resp_tstep/dt_tstep) * n_perm2 + (ccohort%resp_tstep*per_dt_tstep) * n_perm2 ! Growth AR (kgC/m2/s) hio_ar_grow_si_scpf(io_si,scpf) = hio_ar_grow_si_scpf(io_si,scpf) + & - (resp_g/dt_tstep) * n_perm2 + (resp_g*per_dt_tstep) * n_perm2 ! Maint AR (kgC/m2/s) hio_ar_maint_si_scpf(io_si,scpf) = hio_ar_maint_si_scpf(io_si,scpf) + & - (ccohort%resp_m/dt_tstep) * n_perm2 + (ccohort%resp_m*per_dt_tstep) * n_perm2 ! Maintenance AR partition variables are stored as rates (kgC/plant/s) ! (kgC/m2/s) = (kgC/plant/s) * (plant/m2) @@ -3704,46 +4664,49 @@ subroutine update_history_hifrq(this,nc,nsites,sites,bc_in,dt_tstep) ! bulk fluxes are in gC / m2 / s hio_gpp_canopy_si(io_si) = hio_gpp_canopy_si(io_si) + & ccohort%gpp_tstep * n_perm2 * per_dt_tstep + hio_ar_canopy_si(io_si) = hio_ar_canopy_si(io_si) + & aresp * n_perm2 * per_dt_tstep ! ! size-resolved respiration fluxes are in kg C / m2 / s hio_rdark_canopy_si_scls(io_si,scls) = hio_rdark_canopy_si_scls(io_si,scls) + & - ccohort%rdark * ccohort%n / m2_per_ha + ccohort%rdark * ccohort%n * ha_per_m2 hio_livestem_mr_canopy_si_scls(io_si,scls) = hio_livestem_mr_canopy_si_scls(io_si,scls) + & - ccohort%livestem_mr * ccohort%n / m2_per_ha + ccohort%livestem_mr * ccohort%n * ha_per_m2 hio_livecroot_mr_canopy_si_scls(io_si,scls) = hio_livecroot_mr_canopy_si_scls(io_si,scls) + & - ccohort%livecroot_mr * ccohort%n / m2_per_ha + ccohort%livecroot_mr * ccohort%n * ha_per_m2 hio_froot_mr_canopy_si_scls(io_si,scls) = hio_froot_mr_canopy_si_scls(io_si,scls) + & - ccohort%froot_mr * ccohort%n / m2_per_ha + ccohort%froot_mr * ccohort%n * ha_per_m2 hio_resp_g_canopy_si_scls(io_si,scls) = hio_resp_g_canopy_si_scls(io_si,scls) + & - resp_g * ccohort%n * per_dt_tstep / m2_per_ha + resp_g * ccohort%n * per_dt_tstep * ha_per_m2 hio_resp_m_canopy_si_scls(io_si,scls) = hio_resp_m_canopy_si_scls(io_si,scls) + & - ccohort%resp_m * ccohort%n * per_dt_tstep / m2_per_ha + ccohort%resp_m * ccohort%n * per_dt_tstep * ha_per_m2 else ! ! bulk fluxes are in gC / m2 / s hio_gpp_understory_si(io_si) = hio_gpp_understory_si(io_si) + & ccohort%gpp_tstep * n_perm2 * per_dt_tstep + + hio_ar_understory_si(io_si) = hio_ar_understory_si(io_si) + & aresp * n_perm2 * per_dt_tstep ! ! size-resolved respiration fluxes are in kg C / m2 / s hio_rdark_understory_si_scls(io_si,scls) = hio_rdark_understory_si_scls(io_si,scls) + & - ccohort%rdark * ccohort%n / m2_per_ha + ccohort%rdark * ccohort%n * ha_per_m2 hio_livestem_mr_understory_si_scls(io_si,scls) = hio_livestem_mr_understory_si_scls(io_si,scls) + & - ccohort%livestem_mr * ccohort%n / m2_per_ha + ccohort%livestem_mr * ccohort%n * ha_per_m2 hio_livecroot_mr_understory_si_scls(io_si,scls) = hio_livecroot_mr_understory_si_scls(io_si,scls) + & - ccohort%livecroot_mr * ccohort%n / m2_per_ha + ccohort%livecroot_mr * ccohort%n * ha_per_m2 hio_froot_mr_understory_si_scls(io_si,scls) = hio_froot_mr_understory_si_scls(io_si,scls) + & - ccohort%froot_mr * ccohort%n / m2_per_ha + ccohort%froot_mr * ccohort%n * ha_per_m2 hio_resp_g_understory_si_scls(io_si,scls) = hio_resp_g_understory_si_scls(io_si,scls) + & - resp_g * ccohort%n * per_dt_tstep / m2_per_ha + resp_g * ccohort%n * per_dt_tstep * ha_per_m2 hio_resp_m_understory_si_scls(io_si,scls) = hio_resp_m_understory_si_scls(io_si,scls) + & - ccohort%resp_m * ccohort%n * per_dt_tstep / m2_per_ha + ccohort%resp_m * ccohort%n * per_dt_tstep * ha_per_m2 endif end associate endif @@ -3753,7 +4716,7 @@ subroutine update_history_hifrq(this,nc,nsites,sites,bc_in,dt_tstep) do ileaf=1,ccohort%nv cnlf_indx = ileaf + (ican-1) * nlevleaf hio_ts_net_uptake_si_cnlf(io_si, cnlf_indx) = hio_ts_net_uptake_si_cnlf(io_si, cnlf_indx) + & - ccohort%ts_net_uptake(ileaf) * per_dt_tstep * ccohort%c_area / AREA + ccohort%ts_net_uptake(ileaf) * per_dt_tstep * ccohort%c_area * area_inv end do ccohort => ccohort%taller @@ -3856,7 +4819,7 @@ subroutine update_history_hifrq(this,nc,nsites,sites,bc_in,dt_tstep) end do !patch loop do ipa2 = 1, nlevage - if (patch_area_by_age(ipa2) .gt. tiny) then + if (patch_area_by_age(ipa2) .gt. nearzero) then hio_gpp_si_age(io_si, ipa2) = hio_gpp_si_age(io_si, ipa2) / (patch_area_by_age(ipa2)) hio_npp_si_age(io_si, ipa2) = hio_npp_si_age(io_si, ipa2) / (patch_area_by_age(ipa2)) else @@ -3865,7 +4828,7 @@ subroutine update_history_hifrq(this,nc,nsites,sites,bc_in,dt_tstep) endif ! Normalize resistance diagnostics - if (canopy_area_by_age(ipa2) .gt. tiny) then + if (canopy_area_by_age(ipa2) .gt. nearzero) then hio_c_stomata_si_age(io_si,ipa2) = & hio_c_stomata_si_age(io_si,ipa2) / canopy_area_by_age(ipa2) @@ -3879,7 +4842,7 @@ subroutine update_history_hifrq(this,nc,nsites,sites,bc_in,dt_tstep) end do ! Normalize resistance diagnostics - if ( sum(canopy_area_by_age(1:nlevage)) .gt. tiny) then + if ( sum(canopy_area_by_age(1:nlevage)) .gt. nearzero) then hio_c_stomata_si(io_si) = hio_c_stomata_si(io_si) / sum(canopy_area_by_age(1:nlevage)) hio_c_lblayer_si(io_si) = hio_c_lblayer_si(io_si) / sum(canopy_area_by_age(1:nlevage)) else @@ -3904,8 +4867,6 @@ subroutine update_history_hydraulics(this,nc,nsites,sites,bc_in,dt_tstep) use FatesHydraulicsMemMod, only : ed_cohort_hydr_type, nshell use FatesHydraulicsMemMod, only : ed_site_hydr_type - use EDTypesMod , only : maxpft - ! Arguments class(fates_history_interface_type) :: this @@ -3921,7 +4882,6 @@ subroutine update_history_hydraulics(this,nc,nsites,sites,bc_in,dt_tstep) integer :: ipa ! The local "I"ndex of "PA"tches integer :: ft ! functional type index ! integer :: io_shsl ! The combined "SH"ell "S"oil "L"ayer index in the IO array - real(r8), parameter :: tiny = 1.e-5_r8 ! some small number real(r8) :: ncohort_scpf(nlevsclass*maxpft) ! Bins to count up cohorts counts used in weighting ! should be "hio_nplant_si_scpf" real(r8) :: nplant_scpf(nlevsclass*maxpft) ! Bins to count up cohorts counts used in weighting @@ -3950,11 +4910,11 @@ subroutine update_history_hydraulics(this,nc,nsites,sites,bc_in,dt_tstep) real(r8) :: psi ! matric potential of soil layer real(r8) :: depth_frac ! fraction of rhizosphere layer depth occupied by current soil layer character(2) :: fmt_char - type(ed_patch_type),pointer :: cpatch - type(ed_cohort_type),pointer :: ccohort + type(fates_patch_type),pointer :: cpatch + type(fates_cohort_type),pointer :: ccohort type(ed_cohort_hydr_type), pointer :: ccohort_hydr type(ed_site_hydr_type), pointer :: site_hydr - + real(r8) :: per_dt_tstep ! Time step in frequency units (/s) real(r8), parameter :: daysecs = 86400.0_r8 ! What modeler doesn't recognize 86400? real(r8), parameter :: yeardays = 365.0_r8 ! Should this be 365.25? @@ -4007,6 +4967,8 @@ subroutine update_history_hydraulics(this,nc,nsites,sites,bc_in,dt_tstep) ! Flush the relevant history variables call this%flush_hvars(nc,upfreq_in=4) + per_dt_tstep = 1._r8 / dt_tstep + if(print_iterations) then do iscpf = 1,iterh2_nhist iterh2_histx(iscpf) = iterh2_dx*real(iscpf-1,r8) @@ -4044,7 +5006,7 @@ subroutine update_history_hydraulics(this,nc,nsites,sites,bc_in,dt_tstep) do j_bc = j_t,j_b vwc = bc_in(s)%h2o_liqvol_sl(j_bc) - psi = site_hydr%wrf_soil(j)%p%psi_from_th(vwc) + psi = site_hydr%wrf_soil(j)%p%psi_from_th(vwc) ! MLO: Any reason for not using smp_sl? ! cap capillary pressure ! psi = max(-1e5_r8,psi) Removing cap as that is inconstistent ! with model internals and physics. Should @@ -4118,11 +5080,11 @@ subroutine update_history_hydraulics(this,nc,nsites,sites,bc_in,dt_tstep) do ipft = 1, numpft do iscls = 1,nlevsclass iscpf = (ipft-1)*nlevsclass + iscls - hio_sapflow_scpf(io_si,iscpf) = site_hydr%sapflow_scpf(iscls, ipft) / m2_per_ha - hio_rootuptake0_scpf(io_si,iscpf) = site_hydr%rootuptake0_scpf(iscls,ipft) / m2_per_ha - hio_rootuptake10_scpf(io_si,iscpf) = site_hydr%rootuptake10_scpf(iscls,ipft) / m2_per_ha - hio_rootuptake50_scpf(io_si,iscpf) = site_hydr%rootuptake50_scpf(iscls,ipft) / m2_per_ha - hio_rootuptake100_scpf(io_si,iscpf) = site_hydr%rootuptake100_scpf(iscls,ipft) / m2_per_ha + hio_sapflow_scpf(io_si,iscpf) = site_hydr%sapflow_scpf(iscls, ipft) * ha_per_m2 + hio_rootuptake0_scpf(io_si,iscpf) = site_hydr%rootuptake0_scpf(iscls,ipft) * ha_per_m2 + hio_rootuptake10_scpf(io_si,iscpf) = site_hydr%rootuptake10_scpf(iscls,ipft) * ha_per_m2 + hio_rootuptake50_scpf(io_si,iscpf) = site_hydr%rootuptake50_scpf(iscls,ipft) * ha_per_m2 + hio_rootuptake100_scpf(io_si,iscpf) = site_hydr%rootuptake100_scpf(iscls,ipft) * ha_per_m2 hio_iterh1_scpf(io_si,iscpf) = 0._r8 hio_iterh2_scpf(io_si,iscpf) = 0._r8 end do @@ -4143,7 +5105,7 @@ subroutine update_history_hydraulics(this,nc,nsites,sites,bc_in,dt_tstep) iscpf = ccohort%size_by_pft_class ! scale up cohort fluxes to their sites - number_fraction_rate = (ccohort%n / nplant_scpf(iscpf))/dt_tstep + number_fraction_rate = (ccohort%n / nplant_scpf(iscpf)) * per_dt_tstep ! scale cohorts to mean quantity number_fraction = (ccohort%n / nplant_scpf(iscpf)) @@ -4217,7 +5179,7 @@ subroutine update_history_hydraulics(this,nc,nsites,sites,bc_in,dt_tstep) if(hlm_use_ed_st3.eq.ifalse) then do iscpf=1,nlevsclass*numpft - if ((abs(hio_nplant_si_scpf(io_si, iscpf)-(nplant_scpf(iscpf)/m2_per_ha)) > 1.0E-8_r8) .and. & + if ((abs(hio_nplant_si_scpf(io_si, iscpf)-(nplant_scpf(iscpf)*ha_per_m2)) > 1.0E-8_r8) .and. & (hio_nplant_si_scpf(io_si, iscpf) .ne. hlm_hio_ignore_val)) then write(fates_log(),*) 'numpft:',numpft write(fates_log(),*) 'nlevsclass:',nlevsclass @@ -4232,11 +5194,8 @@ subroutine update_history_hydraulics(this,nc,nsites,sites,bc_in,dt_tstep) end if if(print_iterations) then -! print*,' Mean solves: ',sum(hio_iterh2_scpf(io_si,:))/real(count(ncohort_scpf(:)>0._r8),r8), & -! ' Mean failures: ',sum(hio_iterh1_scpf(io_si,:))/real(count(ncohort_scpf(:)>0._r8),r8) - write(fmt_char,'(I2)') iterh2_nhist - write(fates_log(),fmt='(A,'//fmt_char//'I5)') 'Solves: ',int(iterh2_histy(:)) - !write(*,*) 'Histogram: ',int(iterh2_histy(:)) + write(fmt_char,'(I2)') iterh2_nhist + write(fates_log(),fmt='(A,'//fmt_char//'I5)') 'Solves: ',int(iterh2_histy(:)) end if @@ -4317,8 +5276,9 @@ subroutine define_history_vars(this, initialize_variables) use FatesIOVariableKindMod, only : site_fuel_r8, site_cwdsc_r8, site_scag_r8 use FatesIOVariableKindMod, only : site_can_r8, site_cnlf_r8, site_cnlfpft_r8 + use FatesIOVariableKindMod, only : site_cdsc_r8, site_cdpf_r8, site_cdam_r8 use FatesIOVariableKindMod, only : site_scagpft_r8, site_agepft_r8 - use FatesIOVariableKindMod, only : site_elem_r8, site_elpft_r8 + use FatesIOVariableKindMod, only : site_elem_r8, site_elpft_r8, site_clscpf_r8 use FatesIOVariableKindMod, only : site_elcwd_r8, site_elage_r8 @@ -4346,7 +5306,8 @@ subroutine define_history_vars(this, initialize_variables) ! plant functional type (site_pft_r8) : PF ! soil layer (site_soil_r8) : SL ! cohort size (site_size_r8) : SZ - + ! cohort crown damage (site_cd_r8) : CD + ! Multiple dimensions should have multiple two-code suffixes: ! cohort age x pft (site_cooage_r8) : ACPF ! patch age x fuel class (site_agefuel_r8) : APFC @@ -4357,8 +5318,9 @@ subroutine define_history_vars(this, initialize_variables) ! cohort size x patch age (site_scag_r8) : SZAP ! cohort size x patch age x pft (site_scagpft_r8) : SZAPPF ! cohort size x pft (site_size_pft_r8) : SZPF - - + ! canopy layer x size x pft (site_clscpf_r8) : CLSZPF (NOT ACTIVE) + ! cohort size x crown damage (site_cdsc_r8) : SZCD + ! cohort size x crown damage x pft (site_cdpf_r8) : CDPF ! Site level counting variables call this%set_history_var(vname='FATES_NPATCHES', units='', & @@ -4373,6 +5335,18 @@ subroutine define_history_vars(this, initialize_variables) upfreq=1, ivar=ivar, initialize=initialize_variables, & index=ih_ncohorts_si) + call this%set_history_var(vname='FATES_NPATCHES_SECONDARY', units='', & + long='total number of patches per site', use_default='active', & + avgflag='A', vtype=site_r8, hlms='CLM:ALM', & + upfreq=1, ivar=ivar, initialize=initialize_variables, & + index=ih_npatches_sec_si) + + call this%set_history_var(vname='FATES_NCOHORTS_SECONDARY', units='', & + long='total number of cohorts per site', use_default='active', & + avgflag='A', vtype=site_r8, hlms='CLM:ALM', & + upfreq=1, ivar=ivar, initialize=initialize_variables, & + index=ih_ncohorts_sec_si) + ! Patch variables call this%set_history_var(vname='FATES_TRIMMING', units='1', & long='degree to which canopy expansion is limited by leaf economics (0-1)', & @@ -4380,6 +5354,10 @@ subroutine define_history_vars(this, initialize_variables) upfreq=1, ivar=ivar, initialize=initialize_variables, & index=ih_trimming_si) + + + + call this%set_history_var(vname='FATES_AREA_PLANTS', units='m2 m-2', & long='area occupied by all plants per m2 land area', use_default='active', & avgflag='A', vtype=site_r8, hlms='CLM:ALM', upfreq=1, ivar=ivar, & @@ -4391,19 +5369,30 @@ subroutine define_history_vars(this, initialize_variables) upfreq=1, ivar=ivar, initialize=initialize_variables, & index=ih_area_trees_si) + call this%set_history_var(vname='FATES_FRACTION', units='m2 m-2', & + long='total gridcell fraction which FATES is running over', use_default='active', & + avgflag='A', vtype=site_r8, hlms='CLM:ALM', & + upfreq=1, ivar=ivar, initialize=initialize_variables, & + index=ih_fates_fraction_si, flush_to_zero=.true.) + + call this%set_history_var(vname='FATES_BA_WEIGHTED_HEIGHT', units='m', & + long='basal area-weighted mean height of woody plants', use_default='active', & + avgflag='A', vtype=site_r8, hlms='CLM:ALM', & + upfreq=1, ivar=ivar, initialize=initialize_variables, & + index=ih_ba_weighted_height_si) + + call this%set_history_var(vname='FATES_CA_WEIGHTED_HEIGHT', units='m', & + long='crown area-weighted mean height of canopy plants', use_default='active', & + avgflag='A', vtype=site_r8, hlms='CLM:ALM', & + upfreq=1, ivar=ivar, initialize=initialize_variables, & + index=ih_ca_weighted_height_si) + call this%set_history_var(vname='FATES_COLD_STATUS', units='', & long='site-level cold status, 0=not cold-dec, 1=too cold for leaves, 2=not too cold', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=1, ivar=ivar, initialize=initialize_variables, & index=ih_site_cstatus_si) - call this%set_history_var(vname='FATES_DROUGHT_STATUS', & - units='', & - long='site-level drought status, <2 too dry for leaves, >=2 not too dry', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index=ih_site_dstatus_si) - call this%set_history_var(vname='FATES_GDD', units='degree_Celsius', & long='site-level growing degree days', use_default='active', & avgflag='A', vtype=site_r8, hlms='CLM:ALM', & @@ -4433,38 +5422,30 @@ subroutine define_history_vars(this, initialize_variables) upfreq=1, ivar=ivar, initialize=initialize_variables, & index=ih_cleafon_si) - call this%set_history_var(vname='FATES_DAYSINCE_DROUGHTLEAFOFF', & - units='days', long='site level days elapsed since drought leaf drop', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index=ih_dleafoff_si) - - call this%set_history_var(vname='FATES_DAYSINCE_DROUGHTLEAFON', & - units='days', & - long='site-level days elapsed since drought leaf flush', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index=ih_dleafon_si) - - call this%set_history_var(vname='FATES_MEANLIQVOL_DROUGHTPHEN', & - units='m3 m-3', & - long='site-level mean liquid water volume for drought phenolgy', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index=ih_meanliqvol_si) - call this%set_history_var(vname='FATES_CANOPY_SPREAD', units='', & long='scaling factor (0-1) between tree basal area and canopy area', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=1, ivar=ivar, initialize=initialize_variables, & index=ih_canopy_spread_si) + call this%set_history_var(vname='FATES_LAI', units='m2 m-2', & + long='leaf area index per m2 land area', & + use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & + upfreq=1, ivar=ivar, initialize=initialize_variables, & + index=ih_lai_si) + call this%set_history_var(vname='FATES_VEGC_PF', units='kg m-2', & long='total PFT-level biomass in kg of carbon per land area', & use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & upfreq=1, ivar=ivar, initialize=initialize_variables, & index=ih_biomass_si_pft) + call this%set_history_var(vname='FATES_VEGC_SE_PF', units='kg m-2', & + long='total PFT-level biomass in kg of carbon per land area, secondary patches', & + use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & + upfreq=1, ivar=ivar, initialize=initialize_variables, & + index=ih_biomass_sec_si_pft) + call this%set_history_var(vname='FATES_LEAFC_PF', units='kg m-2', & long='total PFT-level leaf biomass in kg carbon per m2 land area', & use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & @@ -4495,31 +5476,105 @@ 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, & index=ih_npp_si_pft) + call this%set_history_var(vname='FATES_GPP_SE_PF', units='kg m-2 s-1', & + long='total PFT-level GPP in kg carbon per m2 land area per second, secondary patches', & + use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & + upfreq=1, ivar=ivar, initialize=initialize_variables, & + index=ih_gpp_sec_si_pft) + + call this%set_history_var(vname='FATES_NPP_SE_PF', units='kg m-2 s-1', & + long='total PFT-level NPP in kg carbon per m2 land area per second, secondary patches', & + use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & + upfreq=1, ivar=ivar, initialize=initialize_variables, & + index=ih_npp_sec_si_pft) + call this%set_history_var(vname='FATES_NPLANT_PF', units='m-2', & long='total PFT-level number of individuals per m2 land area', & use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & upfreq=1, ivar=ivar, initialize=initialize_variables, & index=ih_nindivs_si_pft) + call this%set_history_var(vname='FATES_NPLANT_SEC_PF', units='m-2', & + long='total PFT-level number of individuals per m2 land area, secondary patches', & + use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & + upfreq=1, ivar=ivar, initialize=initialize_variables, & + index=ih_nindivs_sec_si_pft) + call this%set_history_var(vname='FATES_RECRUITMENT_PF', & units='m-2 yr-1', & long='PFT-level recruitment rate in number of individuals per m2 land area per year', & use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & upfreq=1, ivar=ivar, initialize=initialize_variables, & index=ih_recruitment_si_pft) + + call this%set_history_var(vname='FATES_SEEDS_IN_GRIDCELL_PF', & + units='kg', & + long='Site-level seed mass input from neighboring gridcells per pft', & + use_default='inactive', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & + upfreq=1, ivar=ivar, initialize=initialize_variables, & + index=ih_seeds_in_gc_si_pft) + call this%set_history_var(vname='FATES_SEEDS_OUT_GRIDCELL_PF', & + units='kg', & + long='Site-level seed mass output to neighboring gridcells per pft', & + use_default='inactive', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & + upfreq=1, ivar=ivar, initialize=initialize_variables, & + index=ih_seeds_out_gc_si_pft) + call this%set_history_var(vname='FATES_MORTALITY_PF', units='m-2 yr-1', & long='PFT-level mortality rate in number of individuals per m2 land area per year', & use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & upfreq=1, ivar=ivar, initialize=initialize_variables, & index=ih_mortality_si_pft) + !MLO - Drought-deciduous phenology variables are now defined for each PFT. + call this%set_history_var(vname='FATES_DROUGHT_STATUS_PF', & + units='', & + long='PFT-level drought status, <2 too dry for leaves, >=2 not too dry', & + use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & + upfreq=1, ivar=ivar, initialize=initialize_variables, & + index=ih_site_dstatus_si_pft) + + call this%set_history_var(vname='FATES_DAYSINCE_DROUGHTLEAFOFF_PF', & + units='days', long='PFT-level days elapsed since drought leaf drop', & + use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & + upfreq=1, ivar=ivar, initialize=initialize_variables, & + index=ih_dleafoff_si_pft) + + call this%set_history_var(vname='FATES_DAYSINCE_DROUGHTLEAFON_PF', & + units='days', & + long='PFT-level days elapsed since drought leaf flush', & + use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & + upfreq=1, ivar=ivar, initialize=initialize_variables, & + index=ih_dleafon_si_pft) + + call this%set_history_var(vname='FATES_MEANLIQVOL_DROUGHTPHEN_PF', & + units='m3 m-3', & + long='PFT-level mean liquid water volume for drought phenolgy', & + use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & + upfreq=1, ivar=ivar, initialize=initialize_variables, & + index=ih_meanliqvol_si_pft) + + call this%set_history_var(vname='FATES_MEANSMP_DROUGHTPHEN_PF', & + units='Pa', & + long='PFT-level mean soil matric potential for drought phenology', & + use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & + upfreq=1, ivar=ivar, initialize=initialize_variables, & + index=ih_meansmp_si_pft) + + call this%set_history_var(vname='FATES_ELONG_FACTOR_PF', & + units='1', & + long='PFT-level mean elongation factor (partial flushing/abscission)', & + use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & + upfreq=1, ivar=ivar, initialize=initialize_variables, & + index=ih_elong_factor_si_pft) + nocomp_if: if (hlm_use_nocomp .eq. itrue) then call this%set_history_var(vname='FATES_NOCOMP_NPATCHES_PF', units='', & long='number of patches per PFT (nocomp-mode-only)', & @@ -4552,6 +5607,12 @@ subroutine define_history_vars(this, initialize_variables) upfreq=1, ivar=ivar, initialize=initialize_variables, & index=ih_lai_si_age) + call this%set_history_var(vname='FATES_LAI_SECONDARY', units='m2 m-2', & + long='leaf area index per m2 land area, secondary patches', & + use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & + upfreq=1, ivar=ivar, initialize=initialize_variables, & + index=ih_lai_secondary_si) + call this%set_history_var(vname='FATES_CANOPYAREA_AP', units='m2 m-2', & long='canopy area by age bin per m2 land area', use_default='active', & avgflag='A', vtype=site_age_r8, hlms='CLM:ALM', upfreq=1, ivar=ivar, & @@ -4603,20 +5664,20 @@ subroutine define_history_vars(this, initialize_variables) call this%set_history_var(vname='FATES_SECONDARY_FOREST_FRACTION', & units='m2 m-2', long='secondary forest fraction', & - use_default='inactive', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & + use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=1, ivar=ivar, initialize=initialize_variables, & index=ih_fraction_secondary_forest_si) call this%set_history_var(vname='FATES_WOOD_PRODUCT', units='kg m-2', & long='total wood product from logging in kg carbon per m2 land area', & - use_default='inactive', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & + use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=1, ivar=ivar, initialize=initialize_variables, & index=ih_woodproduct_si) call this%set_history_var(vname='FATES_SECONDARY_FOREST_VEGC', & units='kg m-2', & long='biomass on secondary lands in kg carbon per m2 land area (mult by FATES_SECONDARY_FOREST_FRACTION to get per secondary forest area)', & - use_default='inactive', avgflag='A', vtype=site_r8, & + use_default='active', avgflag='A', vtype=site_r8, & hlms='CLM:ALM', upfreq=1, ivar=ivar, initialize=initialize_variables, & index=ih_biomass_secondary_forest_si) @@ -4710,7 +5771,7 @@ subroutine define_history_vars(this, initialize_variables) avgflag='A', vtype=site_r8, hlms='CLM:ALM', upfreq=1, ivar=ivar, & initialize=initialize_variables, index = ih_fire_fuel_eff_moist_si) - call this%set_history_var(vname='FATES_FUEL_SAV', units='per m', & + call this%set_history_var(vname='FATES_FUEL_SAV', units='m-1', & long='spitfire fuel surface area to volume ratio', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=1, ivar=ivar, initialize=initialize_variables, & @@ -4780,7 +5841,7 @@ subroutine define_history_vars(this, initialize_variables) index = ih_litter_in_si) call this%set_history_var(vname='FATES_LITTER_OUT', units='kg m-2 s-1', & - long='litter flux out in kg carbon per m2 per second', & + long='litter flux out in kg carbon (exudation, fragmentation, seed decay)', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=1, ivar=ivar, initialize=initialize_variables, & index = ih_litter_out_si) @@ -4790,6 +5851,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_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_ungerm_seed_bank_si) + + 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_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', & @@ -4797,6 +5870,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, & @@ -4804,7 +5883,7 @@ subroutine define_history_vars(this, initialize_variables) index = ih_litter_in_elem) call this%set_history_var(vname='FATES_LITTER_OUT_EL', units='kg m-2 s-1', & - long='litter flux out (fragmentation only) in kg element per m2 per second', & + long='litter flux out (exudation, fragmentation and seed decay) in kg element', & use_default='active', avgflag='A', vtype=site_elem_r8, & hlms='CLM:ALM', upfreq=1, ivar=ivar, initialize=initialize_variables, & index = ih_litter_out_elem) @@ -4828,8 +5907,8 @@ subroutine define_history_vars(this, initialize_variables) hlms='CLM:ALM', upfreq=1, ivar=ivar, initialize=initialize_variables, & index = ih_seeds_in_extern_elem) - call this%set_history_var(vname='FATES_SEED_GERM_EL', units='kg m-2 s-1', & - long='seed mass converted into new cohorts in kg element per m2 per s', & + call this%set_history_var(vname='FATES_SEED_GERM_EL', units='kg m-2', & + long='element-level total germinated seed mass of all PFTs in kg element per m2', & use_default='active', avgflag='A', vtype=site_elem_r8, & hlms='CLM:ALM', upfreq=1, ivar=ivar, initialize=initialize_variables, & index = ih_seed_germ_elem) @@ -4848,6 +5927,24 @@ subroutine define_history_vars(this, initialize_variables) upfreq=1, ivar=ivar, initialize=initialize_variables, & index = ih_storec_si) + call this%set_history_var(vname='FATES_STOREC_TF', units='kg kg-1', & + long='Storage C fraction of target', use_default='active', & + avgflag='A', vtype=site_r8, hlms='CLM:ALM', upfreq=1, & + ivar=ivar, initialize=initialize_variables, index = ih_storectfrac_si ) + + call this%set_history_var(vname='FATES_STOREC_TF_USTORY_SZPF', units='kg kg-1', & + long='Storage C fraction of target by size x pft, in the understory', use_default='inactive', & + avgflag='A', vtype=site_size_pft_r8, hlms='CLM:ALM', upfreq=1, & + ivar=ivar, initialize=initialize_variables, index = ih_storectfrac_ustory_scpf ) + + + call this%set_history_var(vname='FATES_STOREC_TF_CANOPY_SZPF', units='kg kg-1', & + long='Storage C fraction of target by size x pft, in the canopy', use_default='inactive', & + avgflag='A', vtype=site_size_pft_r8, hlms='CLM:ALM', upfreq=1, & + ivar=ivar, initialize=initialize_variables, index = ih_storectfrac_canopy_scpf ) + + + call this%set_history_var(vname='FATES_VEGC', units='kg m-2', & long='total biomass in live plants in kg carbon per m2 land area', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & @@ -4872,32 +5969,124 @@ subroutine define_history_vars(this, initialize_variables) upfreq=1, ivar=ivar, initialize=initialize_variables, & index = ih_fnrtc_si) + call this%set_history_var(vname='FATES_FROOTC_SL', units='kg m-3', & + long='Total carbon in live plant fine-roots over depth', use_default='active', & + avgflag='A', vtype=site_soil_r8, hlms='CLM:ALM', upfreq=1, & + ivar=ivar, initialize=initialize_variables, index = ih_fnrtc_sl ) + call this%set_history_var(vname='FATES_REPROC', units='kg m-2', & long='total biomass in live plant reproductive tissues in kg carbon per m2', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=1, ivar=ivar, initialize=initialize_variables, & index = ih_reproc_si) - call this%set_history_var(vname='FATES_CEFFLUX', units='kg m-2 s-1', & - long='carbon efflux, root to soil, in kg carbon per m2 per second', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index = ih_cefflux_si) + ! Output specific to the chemical species dynamics used (parteh) + select case(hlm_parteh_mode) + case (prt_cnp_flex_allom_hyp) + + call this%set_history_var(vname='FATES_L2FR', units='kg kg-1', & + long='The leaf to fineroot biomass multiplier for target allometry', & + use_default='active', & + avgflag='A', vtype=site_r8, hlms='CLM:ALM', upfreq=1, & + ivar=ivar, initialize=initialize_variables, index = ih_l2fr_si) + + call this%set_history_var(vname='FATES_L2FR_CANOPY_REC_PF', units='kg kg-1', & + long='The leaf to fineroot biomass multiplier for recruits (canopy)', & + use_default='active', & + avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', upfreq=1, & + ivar=ivar, initialize=initialize_variables, index = ih_recl2fr_canopy_pf) + + call this%set_history_var(vname='FATES_L2FR_USTORY_REC_PF', units='kg kg-1', & + long='The leaf to fineroot biomass multiplier for recruits (understory)', & + use_default='active', & + avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', upfreq=1, & + ivar=ivar, initialize=initialize_variables, index = ih_recl2fr_ustory_pf) + + !call this%set_history_var(vname='FATES_L2FR_CLSZPF', units='kg kg-1', & + ! long='The leaf to fineroot biomass multiplier for target allometry', & + ! use_default='inactive', & + ! avgflag='A', vtype=site_clscpf_r8, hlms='CLM:ALM', upfreq=1, & + ! ivar=ivar, initialize=initialize_variables, index = ih_l2fr_clscpf) - nitrogen_active_if: if(any(element_list(:)==nitrogen_element)) then - call this%set_history_var(vname='FATES_STOREN', units='kg m-2', & - long='total nitrogen in live plant storage', use_default='active', & - avgflag='A', vtype=site_r8, hlms='CLM:ALM', upfreq=1, & - ivar=ivar, initialize=initialize_variables, index = ih_storen_si) + call this%set_history_var(vname='FATES_NH4UPTAKE_SZPF', & + units='kg m-2 s-1', & + long='ammonium uptake rate by plants by size-class x pft in kg NH4 per m2 per second', & + use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & + hlms='CLM:ALM', upfreq=5, ivar=ivar, & + initialize=initialize_variables, index = ih_nh4uptake_scpf) - call this%set_history_var(vname='FATES_STOREN_TF', units='1', & - long='storage N fraction of target', use_default='active', & - avgflag='A', vtype=site_r8, hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_storentfrac_si) + call this%set_history_var(vname='FATES_NO3UPTAKE_SZPF', & + units='kg m-2 s-1', & + long='nitrate uptake rate by plants by size-class x pft in kg NO3 per m2 per second', & + use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & + hlms='CLM:ALM', upfreq=5, ivar=ivar, & + initialize=initialize_variables, index = ih_no3uptake_scpf) - call this%set_history_var(vname='FATES_VEGN', units='kg m-2', & - long='total nitrogen in live plants', use_default='active', & + call this%set_history_var(vname='FATES_NEFFLUX_SZPF', units='kg m-2 s-1', & + long='nitrogen efflux, root to soil, by size-class x pft in kg N per m2 per second', & + use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & + hlms='CLM:ALM', upfreq=5, ivar=ivar, & + initialize=initialize_variables, index = ih_nefflux_scpf) + + call this%set_history_var(vname='FATES_NDEMAND_SZPF', units='kg m-2 s-1', & + long='plant N need (algorithm dependent), by size-class x pft in kg N per m2 per second', & + use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & + hlms='CLM:ALM', upfreq=5, ivar=ivar, & + initialize=initialize_variables, index = ih_ndemand_scpf) + + call this%set_history_var(vname='FATES_NFIX_SYM_SZPF', units='kg m-2 s-1', & + long='symbiotic dinitrogen fixation, by size-class x pft in kg N per m2 per second', & + use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & + hlms='CLM:ALM', upfreq=5, ivar=ivar, & + initialize=initialize_variables, index = ih_nfix_scpf) + + + call this%set_history_var(vname='FATES_NH4UPTAKE', units='kg m-2 s-1', & + long='ammonium uptake rate by plants in kg NH4 per m2 per second', & + use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & + upfreq=5, ivar=ivar, initialize=initialize_variables, & + index = ih_nh4uptake_si) + + call this%set_history_var(vname='FATES_NO3UPTAKE', units='kg m-2 s-1', & + long='nitrate uptake rate by plants in kg NO3 per m2 per second', & + use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & + upfreq=5, ivar=ivar, initialize=initialize_variables, & + index = ih_no3uptake_si) + + call this%set_history_var(vname='FATES_NEFFLUX', units='kg m-2 s-1', & + long='nitrogen effluxed from plant in kg N per m2 per second (unused)', & + use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & + upfreq=5, ivar=ivar, initialize=initialize_variables, & + index = ih_nefflux_si) + + call this%set_history_var(vname='FATES_NDEMAND', units='kg m-2 s-1', & + long='plant nitrogen need (algorithm dependent) in kg N per m2 per second', & + use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & + upfreq=5, ivar=ivar, initialize=initialize_variables, & + index = ih_ndemand_si) + + call this%set_history_var(vname='FATES_NFIX_SYM', units='kg m-2 s-1', & + long='symbiotic dinitrogen fixation in kg N per m2 per second', & + use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & + upfreq=5, ivar=ivar, initialize=initialize_variables, & + index = ih_nfix_si) + + end select + + nitrogen_active_if: if(any(element_list(:)==nitrogen_element)) then + call this%set_history_var(vname='FATES_STOREN', units='kg m-2', & + long='total nitrogen in live plant storage', use_default='active', & + avgflag='A', vtype=site_r8, hlms='CLM:ALM', upfreq=1, & + ivar=ivar, initialize=initialize_variables, index = ih_storen_si) + + call this%set_history_var(vname='FATES_STOREN_TF', units='1', & + long='storage N fraction of target', use_default='active', & + avgflag='A', vtype=site_r8, hlms='CLM:ALM', upfreq=1, ivar=ivar, & + initialize=initialize_variables, index = ih_storentfrac_si) + + call this%set_history_var(vname='FATES_VEGN', units='kg m-2', & + long='total nitrogen in live plants', use_default='active', & avgflag='A', vtype=site_r8, hlms='CLM:ALM', upfreq=1, ivar=ivar, & initialize=initialize_variables, index = ih_totvegn_si) @@ -4923,29 +6112,56 @@ subroutine define_history_vars(this, initialize_variables) upfreq=1, ivar=ivar, initialize=initialize_variables, & index = ih_repron_si) - call this%set_history_var(vname='FATES_NH4UPTAKE', units='kg m-2 s-1', & - long='ammonium uptake rate by plants in kg NH4 per m2 per second', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index = ih_nh4uptake_si) + call this%set_history_var(vname='FATES_VEGN_SZPF', units='kg m-2', & + long='total (live) vegetation nitrogen mass by size-class x pft in kg N per m2', & + use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & + hlms='CLM:ALM', upfreq=1, ivar=ivar, & + initialize=initialize_variables, index = ih_totvegn_scpf) - call this%set_history_var(vname='FATES_NO3UPTAKE', units='kg m-2 s-1', & - long='nitrate uptake rate by plants in kg NO3 per m2 per second', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index = ih_no3uptake_si) + call this%set_history_var(vname='FATES_LEAFN_SZPF', units='kg m-2', & + long='leaf nitrogen mass by size-class x pft in kg N per m2', & + use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & + hlms='CLM:ALM', upfreq=1, ivar=ivar, & + initialize=initialize_variables, index = ih_leafn_scpf) - call this%set_history_var(vname='FATES_NEFFLUX', units='kg m-2 s-1', & - long='nitrogen effluxed from plant in kg N per m2 per second (unused)', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index = ih_nefflux_si) + call this%set_history_var(vname='FATES_FROOTN_SZPF', units='kg m-2', & + long='fine-root nitrogen mass by size-class x pft in kg N per m2', & + use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & + hlms='CLM:ALM', upfreq=1, ivar=ivar, & + initialize=initialize_variables, index = ih_fnrtn_scpf) - call this%set_history_var(vname='FATES_NNEED', units='kg m-2 s-1', & - long='plant nitrogen need (algorithm dependent) in kg N per m2 per second', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index = ih_nneed_si) + call this%set_history_var(vname='FATES_SAPWOODN_SZPF', units='kg m-2', & + long='sapwood nitrogen mass by size-class x pft in kg N per m2', & + use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & + hlms='CLM:ALM', upfreq=1, ivar=ivar, & + initialize=initialize_variables, index = ih_sapwn_scpf) + + call this%set_history_var(vname='FATES_STOREN_SZPF', units='kg m-2', & + long='storage nitrogen mass by size-class x pft in kg N per m2', & + use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & + hlms='CLM:ALM', upfreq=1, ivar=ivar, & + initialize=initialize_variables, index = ih_storen_scpf) + + call this%set_history_var(vname='FATES_STOREN_TF_CANOPY_SZPF', & + units='1', & + long='storage nitrogen fraction (0-1) of target, in canopy, by size-class x pft', & + use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & + hlms='CLM:ALM', upfreq=1, ivar=ivar, & + initialize=initialize_variables, index = ih_storentfrac_canopy_scpf) + + call this%set_history_var(vname='FATES_STOREN_TF_USTORY_SZPF', & + units='1', & + long='storage nitrogen fraction (0-1) of target, in understory, by size-class x pft', & + use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & + hlms='CLM:ALM', upfreq=1, ivar=ivar, & + initialize=initialize_variables, & + index = ih_storentfrac_understory_scpf) + + call this%set_history_var(vname='FATES_REPRON_SZPF', units='kg m-2', & + long='reproductive nitrogen mass (on plant) by size-class x pft in kg N per m2', & + use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & + hlms='CLM:ALM', upfreq=1, ivar=ivar, & + initialize=initialize_variables, index = ih_repron_scpf) end if nitrogen_active_if @@ -4994,20 +6210,90 @@ subroutine define_history_vars(this, initialize_variables) call this%set_history_var(vname='FATES_PUPTAKE', units='kg m-2 s-1', & long='mineralized phosphorus uptake rate of plants in kg P per m2 per second', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & + upfreq=5, ivar=ivar, initialize=initialize_variables, & index = ih_puptake_si) call this%set_history_var(vname='FATES_PEFFLUX', units='kg m-2 s-1', & long='phosphorus effluxed from plant in kg P per m2 per second (unused)', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & + upfreq=5, ivar=ivar, initialize=initialize_variables, & index = ih_pefflux_si) - call this%set_history_var(vname='FATES_PNEED', units='kg m-2 s-1', & + call this%set_history_var(vname='FATES_PDEMAND', units='kg m-2 s-1', & long='plant phosphorus need (algorithm dependent) in kg P per m2 per second', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index = ih_pneed_si) + upfreq=5, ivar=ivar, initialize=initialize_variables, & + index = ih_pdemand_si) + + call this%set_history_var(vname='FATES_VEGP_SZPF', units='kg m-2', & + long='total (live) vegetation phosphorus mass by size-class x pft in kg P per m2', & + use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & + hlms='CLM:ALM', upfreq=1, ivar=ivar, & + initialize=initialize_variables, index = ih_totvegp_scpf) + + call this%set_history_var(vname='FATES_LEAFP_SZPF', units='kg m-2', & + long='leaf phosphorus mass by size-class x pft', use_default='inactive', & + avgflag='A', vtype=site_size_pft_r8, hlms='CLM:ALM', & + upfreq=1, ivar=ivar, initialize=initialize_variables, index = ih_leafp_scpf ) + + call this%set_history_var(vname='FATES_FROOTP_SZPF', units='kg m-2', & + long='fine-root phosphorus mass by size-class x pft in kg P per m2', & + use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & + hlms='CLM:ALM', upfreq=1, ivar=ivar, & + initialize=initialize_variables, index = ih_fnrtp_scpf) + + call this%set_history_var(vname='FATES_SAPWOODP_SZPF', units='kg m-2', & + long='sapwood phosphorus mass by size-class x pft in kg P per m2', & + use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & + hlms='CLM:ALM', upfreq=1, ivar=ivar, & + initialize=initialize_variables, index = ih_sapwp_scpf) + + call this%set_history_var(vname='FATES_STOREP_SZPF', units='kg m-2', & + long='storage phosphorus mass by size-class x pft in kg P per m2', & + use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & + hlms='CLM:ALM', upfreq=1, ivar=ivar, & + initialize=initialize_variables, index = ih_storep_scpf) + + call this%set_history_var(vname='FATES_STOREP_TF_CANOPY_SZPF', & + units='1', & + long='storage phosphorus fraction (0-1) of target, in canopy, by size-class x pft', & + use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & + hlms='CLM:ALM', upfreq=1, ivar=ivar, & + initialize=initialize_variables, index = ih_storeptfrac_canopy_scpf) + + call this%set_history_var(vname='FATES_STOREP_TF_USTORY_SZPF', & + units='1', & + long='storage phosphorus fraction (0-1) of target, in understory, by size-class x pft', & + use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & + hlms='CLM:ALM', upfreq=1, ivar=ivar, & + initialize=initialize_variables, & + index = ih_storeptfrac_understory_scpf) + + call this%set_history_var(vname='FATES_REPROP_SZPF', units='kg m-2', & + long='reproductive phosphorus mass (on plant) by size-class x pft in kg P per m2', & + use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & + hlms='CLM:ALM', upfreq=1, ivar=ivar, & + initialize=initialize_variables, index = ih_reprop_scpf) + + call this%set_history_var(vname='FATES_PUPTAKE_SZPF', & + units='kg m-2 s-1', & + long='phosphorus uptake rate by plants, by size-class x pft in kg P per m2 per second', & + use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & + hlms='CLM:ALM', upfreq=5, ivar=ivar, & + initialize=initialize_variables, index = ih_puptake_scpf) + + call this%set_history_var(vname='FATES_PEFFLUX_SZPF', & + units='kg m-2 s-1', & + long='phosphorus efflux, root to soil, by size-class x pft in kg P per m2 per second', & + use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & + hlms='CLM:ALM', upfreq=5, ivar=ivar, & + initialize=initialize_variables, index = ih_pefflux_scpf) + + call this%set_history_var(vname='FATES_PDEMAND_SZPF', units='kg m-2 s-1', & + long='plant P need (algorithm dependent), by size-class x pft in kg P per m2 per second', & + use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & + hlms='CLM:ALM', upfreq=5, ivar=ivar, & + initialize=initialize_variables, index = ih_pdemand_scpf) end if phosphorus_active_if @@ -5117,26 +6403,53 @@ subroutine define_history_vars(this, initialize_variables) ivar=ivar, initialize=initialize_variables, index = ih_c_lblayer_si) ! Temperature - + call this%set_history_var(vname='FATES_TVEG24', units='degree_Celsius', & long='fates 24-hr running mean vegetation temperature by site', & use_default='active', & avgflag='A', vtype=site_r8, hlms='CLM:ALM', upfreq=1, & ivar=ivar, initialize=initialize_variables, index = ih_tveg24_si ) - + + call this%set_history_var(vname='FATES_TLONGTERM', units='degree_Celsius', & + long='fates 30-year running mean vegetation temperature by site', & + use_default='inactive', & + avgflag='A', vtype=site_r8, hlms='CLM:ALM', upfreq=1, & + ivar=ivar, initialize=initialize_variables, index = ih_tlongterm_si ) + + call this%set_history_var(vname='FATES_TGROWTH', units='degree_Celsius', & + long='fates long-term running mean vegetation temperature by site', & + use_default='inactive', & + avgflag='A', vtype=site_r8, hlms='CLM:ALM', upfreq=1, & + ivar=ivar, initialize=initialize_variables, index = ih_tgrowth_si ) + call this%set_history_var(vname='FATES_TVEG', units='degree_Celsius', & long='fates instantaneous mean vegetation temperature by site', & use_default='active', & avgflag='A', vtype=site_r8, hlms='CLM:ALM', upfreq=2, & ivar=ivar, initialize=initialize_variables, index = ih_tveg_si ) - - ! radiation error - call this%set_history_var(vname='FATES_RAD_ERROR', units='W m-2 ', & + ! radiation error + call this%set_history_var(vname='FATES_RAD_ERROR', units='W m-2 ', & long='radiation error in FATES RTM', use_default='active', & avgflag='A', vtype=site_r8, hlms='CLM:ALM', upfreq=2, & ivar=ivar, initialize=initialize_variables, index = ih_rad_error_si) + call this%set_history_var(vname='FATES_AR', units='gC/m^2/s', & + long='autotrophic respiration', use_default='active', & + avgflag='A', vtype=site_r8, hlms='CLM:ALM', upfreq=2, & + ivar=ivar, initialize=initialize_variables, index = ih_aresp_si ) + + call this%set_history_var(vname='FATES_HARVEST_DEBT', units='kg C', & + long='Accumulated carbon failed to be harvested', use_default='active', & + avgflag='A', vtype=site_r8, hlms='CLM:ALM', upfreq=1, & + ivar=ivar, initialize=initialize_variables, index = ih_harvest_debt_si ) + + call this%set_history_var(vname='FATES_HARVEST_DEBT_SEC', units='kg C', & + long='Accumulated carbon failed to be harvested from secondary patches', use_default='active', & + avgflag='A', vtype=site_r8, hlms='CLM:ALM', upfreq=1, & + ivar=ivar, initialize=initialize_variables, index = ih_harvest_debt_sec_si ) + + ! Ecosystem Carbon Fluxes (updated rapidly, upfreq=2) @@ -5145,36 +6458,79 @@ subroutine define_history_vars(this, initialize_variables) use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=2, ivar=ivar, initialize=initialize_variables, index = ih_npp_si) + call this%set_history_var(vname='FATES_NPP_SECONDARY', units='kg m-2 s-1', & + long='net primary production in kg carbon per m2 per second, secondary patches', & + use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & + upfreq=2, ivar=ivar, initialize=initialize_variables, index = ih_npp_secondary_si) + call this%set_history_var(vname='FATES_GPP', units='kg m-2 s-1', & long='gross primary production in kg carbon per m2 per second', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=2, ivar=ivar, initialize=initialize_variables, index = ih_gpp_si) + call this%set_history_var(vname='FATES_GPP_SECONDARY', units='kg m-2 s-1', & + long='gross primary production in kg carbon per m2 per second, secondary patches', & + use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & + upfreq=2, ivar=ivar, initialize=initialize_variables, index = ih_gpp_secondary_si) + call this%set_history_var(vname='FATES_AUTORESP', units='kg m-2 s-1', & long='autotrophic respiration in kg carbon per m2 per second', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=2, ivar=ivar, initialize=initialize_variables, index = ih_aresp_si) + call this%set_history_var(vname='FATES_AUTORESP_SECONDARY', units='kg m-2 s-1', & + long='autotrophic respiration in kg carbon per m2 per second, secondary patches', & + use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & + upfreq=2, ivar=ivar, initialize=initialize_variables, index = ih_aresp_secondary_si) + call this%set_history_var(vname='FATES_GROWTH_RESP', units='kg m-2 s-1', & long='growth respiration in kg carbon per m2 per second', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=2, ivar=ivar, initialize=initialize_variables, & index = ih_growth_resp_si) + call this%set_history_var(vname='FATES_GROWTH_RESP_SECONDARY', units='kg m-2 s-1', & + long='growth respiration in kg carbon per m2 per second, secondary patches', & + use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & + upfreq=2, ivar=ivar, initialize=initialize_variables, & + index = ih_growth_resp_secondary_si) + call this%set_history_var(vname='FATES_MAINT_RESP', units='kg m-2 s-1', & long='maintenance respiration in kg carbon per m2 land area per second', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=2, ivar=ivar, initialize=initialize_variables, & index = ih_maint_resp_si) - ! Canopy resistance + call this%set_history_var(vname='FATES_MAINT_RESP_UNREDUCED', units='kg m-2 s-1', & + long='diagnostic maintenance respiration if the low-carbon-storage reduction is ignored', & + use_default='inactive', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & + upfreq=2, ivar=ivar, initialize=initialize_variables, & + index = ih_maint_resp_unreduced_si) + call this%set_history_var(vname='FATES_MAINT_RESP_SECONDARY', units='kg m-2 s-1', & + long='maintenance respiration in kg carbon per m2 land area per second, secondary patches', & + use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & + upfreq=2, ivar=ivar, initialize=initialize_variables, & + index = ih_maint_resp_secondary_si) + + call this%set_history_var(vname='FATES_EXCESS_RESP', units='kg m-2 s-1', & + long='respiration of un-allocatable carbon gain', & + use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & + upfreq=5, ivar=ivar, initialize=initialize_variables, & + index = ih_excess_resp_si) + + ! Canopy resistance call this%set_history_var(vname='FATES_STOMATAL_COND_AP', & units='mol m-2 s-1', long='mean stomatal conductance - by patch age', & use_default='inactive', avgflag='A', vtype=site_age_r8, & hlms='CLM:ALM', upfreq=2, ivar=ivar, initialize=initialize_variables, & index = ih_c_stomata_si_age) + call this%set_history_var(vname='FATES_AR_CANOPY', units='gC/m^2/s', & + long='autotrophic respiration of canopy plants', use_default='active', & + avgflag='A', vtype=site_r8, hlms='CLM:ALM', upfreq=2, & + ivar=ivar, initialize=initialize_variables, index = ih_ar_canopy_si ) + call this%set_history_var(vname='FATES_LBLAYER_COND_AP', & units='mol m-2 s-1', & long='mean leaf boundary layer conductance - by patch age', & @@ -5195,6 +6551,11 @@ subroutine define_history_vars(this, initialize_variables) hlms='CLM:ALM', upfreq=2, ivar=ivar, initialize=initialize_variables, & index = ih_gpp_si_age) + call this%set_history_var(vname='FATES_AR_UNDERSTORY', units='gC/m^2/s', & + long='autotrophic respiration of understory plants', use_default='active', & + avgflag='A', vtype=site_r8, hlms='CLM:ALM', upfreq=2, & + ivar=ivar, initialize=initialize_variables, index = ih_ar_understory_si ) + ! fast fluxes separated canopy/understory call this%set_history_var(vname='FATES_GPP_CANOPY', units='kg m-2 s-1', & long='gross primary production of canopy plants in kg carbon per m2 per second', & @@ -5209,14 +6570,14 @@ subroutine define_history_vars(this, initialize_variables) upfreq=2, ivar=ivar, initialize=initialize_variables, & index = ih_ar_canopy_si) - call this%set_history_var(vname='FATES_GPP_UNDERSTORY', & + call this%set_history_var(vname='FATES_GPP_USTORY', & units='kg m-2 s-1', & long='gross primary production of understory plants in kg carbon per m2 per second', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=2, ivar=ivar, initialize=initialize_variables, & index = ih_gpp_understory_si) - call this%set_history_var(vname='FATES_AUTORESP_UNDERSTORY', & + call this%set_history_var(vname='FATES_AUTORESP_USTORY', & units='kg m-2 s-1', & long='autotrophic respiration of understory plants in kg carbon per m2 per second', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & @@ -5436,13 +6797,63 @@ subroutine define_history_vars(this, initialize_variables) upfreq=1, ivar=ivar, initialize=initialize_variables, & index = ih_canopy_mortality_carbonflux_si) - call this%set_history_var(vname='FATES_MORTALITY_CFLUX_UNDERSTORY', & + call this%set_history_var(vname='FATES_MORTALITY_CFLUX_USTORY', & units = 'kg m-2 s-1', & long='flux of biomass carbon from live to dead pools from mortality of understory plants in kg carbon per m2 per second', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=1, ivar=ivar, initialize=initialize_variables, & index = ih_understory_mortality_carbonflux_si) + call this%set_history_var(vname='FATES_MORTALITY_CFLUX_PF', units='kg m-2 s-1', & + long='PFT-level flux of biomass carbon from live to dead pool from mortality', & + use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & + upfreq=1, ivar=ivar, initialize=initialize_variables, & + index=ih_mortality_carbonflux_si_pft) + + call this%set_history_var(vname='FATES_MORTALITY_FIRE_CFLUX_PF', units='kg m-2 s-1', & + long='PFT-level flux of biomass carbon from live to dead pool from fire mortality', & + use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & + upfreq=1, ivar=ivar, initialize=initialize_variables, & + index=ih_firemortality_carbonflux_si_pft) + + call this%set_history_var(vname='FATES_MORTALITY_HYDRO_CFLUX_PF', units='kg m-2 s-1', & + long='PFT-level flux of biomass carbon from live to dead pool from hydraulic failure mortality', & + use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & + upfreq=1, ivar=ivar, initialize=initialize_variables, & + index=ih_hydraulicmortality_carbonflux_si_pft) + + call this%set_history_var(vname='FATES_MORTALITY_CSTARV_CFLUX_PF', units='kg m-2 s-1', & + long='PFT-level flux of biomass carbon from live to dead pool from carbon starvation mortality', & + use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & + upfreq=1, ivar=ivar, initialize=initialize_variables, & + index=ih_cstarvmortality_carbonflux_si_pft) + + call this%set_history_var(vname='FATES_ABOVEGROUND_MORT_SZPF', units='kg m-2 s-1', & + long='Aboveground flux of carbon from AGB to necromass due to mortality', & + use_default='inactive', avgflag='A', vtype=site_size_pft_r8, hlms='CLM:ALM', & + upfreq=1, ivar=ivar, initialize=initialize_variables, & + index=ih_abg_mortality_cflux_si_scpf) + + call this%set_history_var(vname='FATES_ABOVEGROUND_PROD_SZPF', units='kg m-2 s-1', & + long='Aboveground carbon productivity', & + use_default='inactive', avgflag='A', vtype=site_size_pft_r8, hlms='CLM:ALM', & + upfreq=1, ivar=ivar, initialize=initialize_variables, & + index=ih_abg_productivity_cflux_si_scpf) + + call this%set_history_var(vname='MORTALITY_CROWNAREA_CANOPY', & + units = 'm2/ha/year', & + long='Crown area of canopy trees that died', & + use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & + upfreq=1, ivar=ivar, initialize=initialize_variables, & + index = ih_canopy_mortality_crownarea_si ) + + call this%set_history_var(vname='MORTALITY_CROWNAREA_UNDERSTORY', & + units = 'm2/ha/year', & + long='Crown aera of understory trees that died', & + use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & + upfreq=1, ivar=ivar, initialize=initialize_variables, & + index = ih_understory_mortality_crownarea_si ) + ! size class by age dimensioned variables call this%set_history_var(vname='FATES_NPLANT_SZAP', units = 'm-2', & @@ -5733,7 +7144,7 @@ subroutine define_history_vars(this, initialize_variables) call this%set_history_var(vname='FATES_MORTALITY_LOGGING_SZPF', & units = 'm-2 yr-1', & - long='logging mortality by pft/size in number of plants per m2 per ', & + long='logging mortality by pft/size in number of plants per m2 per year', & use_default='inactive', & avgflag='A', vtype=site_size_pft_r8, hlms='CLM:ALM', upfreq=1, & ivar=ivar, initialize=initialize_variables, index = ih_m7_si_scpf) @@ -5773,6 +7184,21 @@ subroutine define_history_vars(this, initialize_variables) hlms='CLM:ALM', upfreq=1, ivar=ivar, & initialize=initialize_variables, index = ih_mortality_canopy_si_scpf) + call this%set_history_var(vname='FATES_M3_MORTALITY_CANOPY_SZPF', & + units = 'N/ha/yr', & + long='C starvation mortality of canopy plants by pft/size', & + use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & + hlms='CLM:ALM', upfreq=1, ivar=ivar, & + initialize=initialize_variables, index = ih_m3_mortality_canopy_si_scpf ) + + call this%set_history_var(vname='FATES_M3_MORTALITY_USTORY_SZPF', & + units = 'N/ha/yr', & + long='C starvation mortality of understory plants by pft/size', & + use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & + hlms='CLM:ALM', upfreq=1, ivar=ivar, & + initialize=initialize_variables, index = ih_m3_mortality_understory_si_scpf ) + + call this%set_history_var(vname='FATES_C13DISC_SZPF', units = 'per mil', & long='C13 discrimination by pft/size',use_default='inactive', & avgflag='A', vtype=site_size_pft_r8, hlms='CLM:ALM', & @@ -5793,6 +7219,14 @@ subroutine define_history_vars(this, initialize_variables) ivar=ivar, initialize=initialize_variables, & index = ih_bleaf_canopy_si_scpf) + call this%set_history_var(vname='FATES_LAI_CANOPY_SZPF', & + units = 'm2 m-2', & + long='Leaf area index (LAI) of canopy plants by pft/size', & + use_default='inactive', & + avgflag='A', vtype=site_size_pft_r8, hlms='CLM:ALM', upfreq=1, & + ivar=ivar, initialize=initialize_variables, & + index = ih_lai_canopy_si_scpf ) + call this%set_history_var(vname='FATES_NPLANT_CANOPY_SZPF', units = 'm-2', & long='number of canopy plants by size/pft per m2', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & @@ -5821,6 +7255,13 @@ subroutine define_history_vars(this, initialize_variables) hlms='CLM:ALM', upfreq=1, ivar=ivar, & initialize=initialize_variables, index = ih_bleaf_understory_si_scpf) + call this%set_history_var(vname='FATES_LAI_USTORY_SZPF', & + units = 'm2 m-2', & + long='Leaf area index (LAI) of understory plants by pft/size', & + use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & + hlms='CLM:ALM', upfreq=1, ivar=ivar, & + initialize=initialize_variables, index = ih_lai_understory_si_scpf ) + call this%set_history_var(vname='FATES_NPLANT_USTORY_SZPF', & units = 'm-2', & long='density of understory plants by pft/size in number of plants per m2', & @@ -6007,6 +7448,13 @@ subroutine define_history_vars(this, initialize_variables) hlms='CLM:ALM', upfreq=1, ivar=ivar, & initialize=initialize_variables, index = ih_mortality_canopy_si_scls) + call this%set_history_var(vname='FATES_MORTALITY_CANOPY_SE_SZ', & + units = 'm-2 yr-1', & + long='total mortality of canopy trees by size class in number of plants per m2, secondary patches', & + use_default='active', avgflag='A', vtype=site_size_r8, & + hlms='CLM:ALM', upfreq=1, ivar=ivar, & + initialize=initialize_variables, index = ih_mortality_canopy_secondary_si_scls) + call this%set_history_var(vname='FATES_NPLANT_USTORY_SZ', & units = 'm-2', & long='number of understory plants per m2 by size class', & @@ -6014,6 +7462,20 @@ subroutine define_history_vars(this, initialize_variables) hlms='CLM:ALM', upfreq=1, ivar=ivar, & initialize=initialize_variables, index = ih_nplant_understory_si_scls) + call this%set_history_var(vname='FATES_M3_MORTALITY_CANOPY_SZ', & + units = 'N/ha/yr', & + long='C starvation mortality of canopy plants by size', & + use_default='inactive', avgflag='A', vtype=site_size_r8, & + hlms='CLM:ALM', upfreq=1, ivar=ivar, & + initialize=initialize_variables, index = ih_m3_mortality_canopy_si_scls ) + + call this%set_history_var(vname='FATES_M3_MORTALITY_USTORY_SZ', & + units = 'N/ha/yr', & + long='C starvation mortality of understory plants by size', & + use_default='inactive', avgflag='A', vtype=site_size_r8, & + hlms='CLM:ALM', upfreq=1, ivar=ivar, & + initialize=initialize_variables, index = ih_m3_mortality_understory_si_scls ) + call this%set_history_var(vname='FATES_LAI_USTORY_SZ', & units = 'm2 m-2', & long='leaf area index (LAI) of understory plants by size class', & @@ -6060,6 +7522,27 @@ subroutine define_history_vars(this, initialize_variables) hlms='CLM:ALM', upfreq=1, ivar=ivar, & initialize=initialize_variables, index = ih_m3_si_scls) + call this%set_history_var(vname='FATES_MORTALITY_BACKGROUND_SE_SZ', & + units = 'm-2 yr-1', & + long='background mortality by size in number of plants per m2 per year, secondary patches', & + use_default='active', avgflag='A', vtype=site_size_r8, & + hlms='CLM:ALM', upfreq=1, ivar=ivar, & + initialize=initialize_variables, index = ih_m1_sec_si_scls) + + call this%set_history_var(vname='FATES_MORTALITY_HYDRAULIC_SE_SZ', & + units = 'm-2 yr-1', & + long='hydraulic mortality by size in number of plants per m2 per year, secondary patches', & + use_default='active', avgflag='A', vtype=site_size_r8, & + hlms='CLM:ALM', upfreq=1, ivar=ivar, & + initialize=initialize_variables, index = ih_m2_sec_si_scls) + + call this%set_history_var(vname='FATES_MORTALITY_CSTARV_SE_SZ', & + units = 'm-2 yr-1', & + long='carbon starvation mortality by size in number of plants per m2 per year, secondary patches', & + use_default='active', avgflag='A', vtype=site_size_r8, & + hlms='CLM:ALM', upfreq=1, ivar=ivar, & + initialize=initialize_variables, index = ih_m3_sec_si_scls) + call this%set_history_var(vname='FATES_MORTALITY_IMPACT_SZ', & units = 'm-2 yr-1', & long='impact mortality by size in number of plants per m2 per year', & @@ -6083,21 +7566,21 @@ subroutine define_history_vars(this, initialize_variables) call this%set_history_var(vname='FATES_MORTALITY_LOGGING_SZ', & units = 'm-2 yr-1', & - long='logging mortality by size in number of plants per m2 per event', & + long='logging mortality by size in number of plants per m2 per year', & use_default='active', avgflag='A', vtype=site_size_r8, & hlms='CLM:ALM', upfreq=1, ivar=ivar, & initialize=initialize_variables, index = ih_m7_si_scls) call this%set_history_var(vname='FATES_MORTALITY_FREEZING_SZ', & - units = 'm-2 event-1', & - long='freezing mortality by size in number of plants per m2 per event', & + units = 'm-2 yr-1', & + long='freezing mortality by size in number of plants per m2 per year', & use_default='active', avgflag='A', vtype=site_size_r8, & hlms='CLM:ALM', upfreq=1, ivar=ivar, & initialize=initialize_variables, index = ih_m8_si_scls) call this%set_history_var(vname='FATES_MORTALITY_SENESCENCE_SZ', & units = 'm-2 yr-1', & - long='senescence mortality by size in number of plants per m2 per event', & + long='senescence mortality by size in number of plants per m2 per year', & use_default='active', avgflag='A', vtype=site_size_r8, & hlms='CLM:ALM', upfreq=1, ivar=ivar, & initialize=initialize_variables, index = ih_m9_si_scls) @@ -6116,6 +7599,34 @@ subroutine define_history_vars(this, initialize_variables) hlms='CLM:ALM', upfreq=1, ivar=ivar, & initialize=initialize_variables, index = ih_m10_si_cacls) + call this%set_history_var(vname='FATES_MORTALITY_LOGGING_SE_SZ', & + units = 'm-2 yr-1', & + long='logging mortality by size in number of plants per m2 per event, secondary patches', & + use_default='active', avgflag='A', vtype=site_size_r8, & + hlms='CLM:ALM', upfreq=1, ivar=ivar, & + initialize=initialize_variables, index = ih_m7_sec_si_scls) + + call this%set_history_var(vname='FATES_MORTALITY_FREEZING_SE_SZ', & + units = 'm-2 event-1', & + long='freezing mortality by size in number of plants per m2 per event, secondary patches', & + use_default='active', avgflag='A', vtype=site_size_r8, & + hlms='CLM:ALM', upfreq=1, ivar=ivar, & + initialize=initialize_variables, index = ih_m8_sec_si_scls) + + call this%set_history_var(vname='FATES_MORTALITY_SENESCENCE_SE_SZ', & + units = 'm-2 yr-1', & + long='senescence mortality by size in number of plants per m2 per event, secondary patches', & + use_default='active', avgflag='A', vtype=site_size_r8, & + hlms='CLM:ALM', upfreq=1, ivar=ivar, & + initialize=initialize_variables, index = ih_m9_sec_si_scls) + + call this%set_history_var(vname='FATES_MORTALITY_AGESCEN_SE_SZ', & + units = 'm-2 yr-1', & + long='age senescence mortality by size in number of plants per m2 per year, secondary patches', & + use_default='active', avgflag='A', vtype=site_size_r8, & + hlms='CLM:ALM', upfreq=1, ivar=ivar, & + initialize=initialize_variables, index = ih_m10_sec_si_scls) + call this%set_history_var(vname='FATES_NPP_CANOPY_SZ', units = 'kg m-2 s-1', & long='NPP of canopy plants by size class in kg carbon per m2 per second', & use_default='inactive', avgflag='A', vtype=site_size_r8, & @@ -6456,6 +7967,101 @@ subroutine define_history_vars(this, initialize_variables) index = ih_resp_m_understory_si_scls) + ! CROWN DAMAGE VARIABLES + if_crowndamage: if(hlm_use_tree_damage .eq. itrue) then + + call this%set_history_var(vname='FATES_CROWNAREA_CANOPY_CD', units = 'm2 m-2 yr-1', & + long='crownarea lost to damage each year', use_default='inactive', & + avgflag='A', vtype=site_r8, hlms='CLM:ALM', & + upfreq=1, ivar=ivar, initialize=initialize_variables, index = ih_crownarea_canopy_damage_si ) + + call this%set_history_var(vname='FATES_CROWNAREA_USTORY_CD', units = 'm2 m-2 yr-1', & + long='crownarea lost to damage each year', use_default='inactive', & + avgflag='A', vtype=site_r8, hlms='CLM:ALM', & + upfreq=1, ivar=ivar, initialize=initialize_variables, index = ih_crownarea_ustory_damage_si ) + + call this%set_history_var(vname='FATES_NPLANT_CDPF', units = 'm-2', & + long='N. plants per damage x size x pft class', use_default='inactive', & + avgflag='A', vtype=site_cdpf_r8, hlms='CLM:ALM', & + upfreq=1, ivar=ivar, initialize=initialize_variables, index = ih_nplant_si_cdpf ) + + call this%set_history_var(vname='FATES_NPLANT_CANOPY_CDPF', units = 'm-2', & + long='N. plants per damage x size x pft class', use_default='inactive', & + avgflag='A', vtype=site_cdpf_r8, hlms='CLM:ALM', & + upfreq=1, ivar=ivar, initialize=initialize_variables, index = ih_nplant_canopy_si_cdpf ) + + call this%set_history_var(vname='FATES_NPLANT_USTORY_CDPF', units = 'm-2', & + long='N. plants in the understory per damage x size x pft class', use_default='inactive', & + avgflag='A', vtype=site_cdpf_r8, hlms='CLM:ALM', & + upfreq=1, ivar=ivar, initialize=initialize_variables, index = ih_nplant_understory_si_cdpf ) + + call this%set_history_var(vname='FATES_M3_CDPF', units = 'm-2 yr-1', & + long='carbon starvation mortality by damaage/pft/size', use_default='inactive', & + avgflag='A', vtype=site_cdpf_r8, hlms='CLM:ALM', & + upfreq=1, ivar=ivar, initialize=initialize_variables, index = ih_m3_si_cdpf ) + + call this%set_history_var(vname='FATES_M11_SZPF', units = 'm-2 yr-1', & + long='damage mortality by pft/size',use_default='inactive', & + avgflag='A', vtype =site_size_pft_r8, hlms='CLM:ALM', & + upfreq=1, ivar=ivar, initialize=initialize_variables, index = ih_m11_si_scpf ) + + call this%set_history_var(vname='FATES_M11_CDPF', units = 'm-2 yr-1', & + long='damage mortality by damaage/pft/size', use_default='inactive', & + avgflag='A', vtype=site_cdpf_r8, hlms='CLM:ALM', & + upfreq=1, ivar=ivar, initialize=initialize_variables, index = ih_m11_si_cdpf ) + + call this%set_history_var(vname='FATES_MORTALITY_CDPF', units = 'm-2 yr-1', & + long='mortality by damage class by size by pft', use_default='inactive', & + avgflag='A', vtype=site_cdpf_r8, hlms='CLM:ALM', & + upfreq=1, ivar=ivar, initialize=initialize_variables, index = ih_mortality_si_cdpf ) + + call this%set_history_var(vname='FATES_M3_MORTALITY_CANOPY_CDPF', units = 'm-2 yr-1', & + long='C starvation mortality of canopy plants by damage/pft/size', use_default='inactive', & + avgflag='A', vtype=site_cdpf_r8, hlms='CLM:ALM', & + upfreq=1, ivar=ivar, initialize=initialize_variables, index = ih_m3_mortality_canopy_si_cdpf ) + + call this%set_history_var(vname='FATES_M3_MORTALITY_USTORY_CDPF', units = 'm-2 yr-1', & + long='C starvation mortality of understory plants by pft/size', use_default='inactive', & + avgflag='A', vtype=site_cdpf_r8, hlms='CLM:ALM', & + upfreq=1, ivar=ivar, initialize=initialize_variables, index = ih_m3_mortality_understory_si_cdpf ) + + call this%set_history_var(vname='FATES_M11_MORTALITY_CANOPY_CDPF', units = 'm-2 yr-1', & + long='damage mortality of canopy plants by damage/pft/size', use_default='inactive', & + avgflag='A', vtype=site_cdpf_r8, hlms='CLM:ALM', & + upfreq=1, ivar=ivar, initialize=initialize_variables, index = ih_m11_mortality_canopy_si_cdpf ) + + call this%set_history_var(vname='FATES_M11_MORTALITY_USTORY_CDPF', units = 'm-2 yr-1', & + long='damage mortality of understory plants by pft/size', use_default='inactive', & + avgflag='A', vtype=site_cdpf_r8, hlms='CLM:ALM', & + upfreq=1, ivar=ivar, initialize=initialize_variables, index = ih_m11_mortality_understory_si_cdpf ) + + call this%set_history_var(vname='FATES_MORTALITY_CANOPY_CDPF', units = 'm-2 yr-1', & + long='mortality of canopy plants by damage/pft/size', use_default='inactive', & + avgflag='A', vtype=site_cdpf_r8, hlms='CLM:ALM', & + upfreq=1, ivar=ivar, initialize=initialize_variables, index = ih_mortality_canopy_si_cdpf ) + + call this%set_history_var(vname='FATES_MORTALITY_USTORY_CDPF', units = 'm-2 yr-1', & + long='mortality of understory plants by pft/size', use_default='inactive', & + avgflag='A', vtype=site_cdpf_r8, hlms='CLM:ALM', & + upfreq=1, ivar=ivar, initialize=initialize_variables, index = ih_mortality_understory_si_cdpf ) + + call this%set_history_var(vname='FATES_DDBH_CDPF', units = 'm m-2 yr-1', & + long='ddbh annual increment growth by damage x size pft', use_default='inactive', & + avgflag='A', vtype=site_cdpf_r8, hlms='CLM:ALM', & + upfreq=1, ivar=ivar, initialize=initialize_variables, index = ih_ddbh_si_cdpf ) + + call this%set_history_var(vname='FATES_DDBH_CANOPY_CDPF', units = 'm m-2 yr-1', & + long='ddbh annual canopy increment growth by damage x size pft', use_default='inactive', & + avgflag='A', vtype=site_cdpf_r8, hlms='CLM:ALM', & + upfreq=1, ivar=ivar, initialize=initialize_variables, index = ih_ddbh_canopy_si_cdpf ) + + call this%set_history_var(vname='FATES_DDBH_USTORY_CDPF', units = 'm m-2 yr-1', & + long='ddbh annual understory increment growth by damage x size pft', use_default='inactive', & + avgflag='A', vtype=site_cdpf_r8, hlms='CLM:ALM', & + upfreq=1, ivar=ivar, initialize=initialize_variables, index = ih_ddbh_understory_si_cdpf ) + + end if if_crowndamage + ! CARBON BALANCE VARIABLES THAT DEPEND ON HLM BGC INPUTS call this%set_history_var(vname='FATES_NEP', units='kg m-2 s-1', & @@ -6562,171 +8168,6 @@ subroutine define_history_vars(this, initialize_variables) hlms='CLM:ALM', upfreq=1, ivar=ivar, initialize=initialize_variables, & index = ih_reproc_scpf) - call this%set_history_var(vname='FATES_CEFFLUX_SZPF', units='kg m-2 s-1', & - long='carbon efflux, root to soil, by size-class x pft in kg carbon per m2 per second', & - use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, initialize=initialize_variables, & - index = ih_cefflux_scpf) - - ! NITROGEN - - nitrogen_active_if2: if(any(element_list(:)==nitrogen_element)) then - - call this%set_history_var(vname='FATES_VEGN_SZPF', units='kg m-2', & - long='total (live) vegetation nitrogen mass by size-class x pft in kg N per m2', & - use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_totvegn_scpf) - - call this%set_history_var(vname='FATES_LEAFN_SZPF', units='kg m-2', & - long='leaf nitrogen mass by size-class x pft in kg N per m2', & - use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_leafn_scpf) - - call this%set_history_var(vname='FATES_FROOTN_SZPF', units='kg m-2', & - long='fine-root nitrogen mass by size-class x pft in kg N per m2', & - use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_fnrtn_scpf) - - call this%set_history_var(vname='FATES_SAPWOODN_SZPF', units='kg m-2', & - long='sapwood nitrogen mass by size-class x pft in kg N per m2', & - use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_sapwn_scpf) - - call this%set_history_var(vname='FATES_STOREN_SZPF', units='kg m-2', & - long='storage nitrogen mass by size-class x pft in kg N per m2', & - use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_storen_scpf) - - call this%set_history_var(vname='FATES_STOREN_TF_CANOPY_SZPF', & - units='1', & - long='storage nitrogen fraction (0-1) of target, in canopy, by size-class x pft', & - use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_storentfrac_canopy_scpf) - - call this%set_history_var(vname='FATES_STOREN_TF_USTORY_SZPF', & - units='1', & - long='storage nitrogen fraction (0-1) of target, in understory, by size-class x pft', & - use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, & - index = ih_storentfrac_understory_scpf) - - call this%set_history_var(vname='FATES_REPRON_SZPF', units='kg m-2', & - long='reproductive nitrogen mass (on plant) by size-class x pft in kg N per m2', & - use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_repron_scpf) - - call this%set_history_var(vname='FATES_NH4UPTAKE_SZPF', & - units='kg m-2 s-1', & - long='ammonium uptake rate by plants by size-class x pft in kg NH4 per m2 per second', & - use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_nh4uptake_scpf) - - call this%set_history_var(vname='FATES_NO3UPTAKE_SZPF', & - units='kg m-2 s-1', & - long='nitrate uptake rate by plants by size-class x pft in kg NO3 per m2 per second', & - use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_no3uptake_scpf) - - call this%set_history_var(vname='FATES_NEFFLUX_SZPF', units='kg m-2 s-1', & - long='nitrogen efflux, root to soil, by size-class x pft in kg N per m2 per second', & - use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_nefflux_scpf) - - call this%set_history_var(vname='FATES_NNEED_SZPF', units='kg m-2 s-1', & - long='plant N need (algorithm dependent), by size-class x pft in kg N per m2 per second', & - use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_nneed_scpf) - - end if nitrogen_active_if2 - - ! PHOSPHORUS - - phosphorus_active_if2: if(any(element_list(:)==phosphorus_element))then - - call this%set_history_var(vname='FATES_VEGP_SZPF', units='kg m-2', & - long='total (live) vegetation phosphorus mass by size-class x pft in kg P per m2', & - use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_totvegp_scpf) - - call this%set_history_var(vname='FATES_LEAFP_SZPF', units='kg m-2', & - long='leaf phosphorus mass by size-class x pft', use_default='inactive', & - avgflag='A', vtype=site_size_pft_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, index = ih_leafp_scpf ) - - call this%set_history_var(vname='FATES_FROOTP_SZPF', units='kg m-2', & - long='fine-root phosphorus mass by size-class x pft in kg P per m2', & - use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_fnrtp_scpf) - - call this%set_history_var(vname='FATES_SAPWOODP_SZPF', units='kg m-2', & - long='sapwood phosphorus mass by size-class x pft in kg P per m2', & - use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_sapwp_scpf) - - call this%set_history_var(vname='FATES_STOREP_SZPF', units='kg m-2', & - long='storage phosphorus mass by size-class x pft in kg P per m2', & - use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_storep_scpf) - - call this%set_history_var(vname='FATES_STOREP_TF_CANOPY_SZPF', & - units='1', & - long='storage phosphorus fraction (0-1) of target, in canopy, by size-class x pft', & - use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_storeptfrac_canopy_scpf) - - call this%set_history_var(vname='FATES_STOREP_TF_USTORY_SZPF', & - units='1', & - long='storage phosphorus fraction (0-1) of target, in understory, by size-class x pft', & - use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, & - index = ih_storeptfrac_understory_scpf) - - call this%set_history_var(vname='FATES_REPROP_SZPF', units='kg m-2', & - long='reproductive phosphorus mass (on plant) by size-class x pft in kg P per m2', & - use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_reprop_scpf) - - call this%set_history_var(vname='FATES_PUPTAKE_SZPF', & - units='kg m-2 s-1', & - long='phosphorus uptake rate by plants, by size-class x pft in kg P per m2 per second', & - use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_puptake_scpf) - - call this%set_history_var(vname='FATES_PEFFLUX_SZPF', & - units='kg m-2 s-1', & - long='phosphorus efflux, root to soil, by size-class x pft in kg P per m2 per second', & - use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_pefflux_scpf) - - call this%set_history_var(vname='FATES_PNEED_SZPF', units='kg m-2 s-1', & - long='plant P need (algorithm dependent), by size-class x pft in kg P per m2 per second', & - use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_pneed_scpf) - - end if phosphorus_active_if2 - ! organ-partitioned NPP / allocation fluxes call this%set_history_var(vname='FATES_LEAF_ALLOC', units='kg m-2 s-1', & diff --git a/main/FatesHistoryVariableType.F90 b/main/FatesHistoryVariableType.F90 index c56d1db984..5902496a2c 100644 --- a/main/FatesHistoryVariableType.F90 +++ b/main/FatesHistoryVariableType.F90 @@ -1,7 +1,8 @@ module FatesHistoryVariableType use FatesConstantsMod, only : r8 => fates_r8 - use FatesGlobals, only : fates_log + use FatesGlobals, only : fates_log + use FatesGlobals , only : endrun => fates_endrun use FatesIODimensionsMod, only : fates_io_dimension_type use FatesIOVariableKindMod, only : fates_io_variable_kind_type use FatesIOVariableKindMod, only : site_r8, site_soil_r8, site_size_pft_r8 @@ -11,15 +12,21 @@ module FatesHistoryVariableType use FatesIOVariableKindMod, only : site_fuel_r8, site_cwdsc_r8, site_scag_r8 use FatesIOVariableKindMod, only : site_scagpft_r8, site_agepft_r8 use FatesIOVariableKindMod, only : site_can_r8, site_cnlf_r8, site_cnlfpft_r8 + use FatesIOVariableKindMod, only : site_cdsc_r8, site_cdpf_r8 use FatesIOVariableKindMod, only : site_elem_r8, site_elpft_r8 use FatesIOVariableKindMod, only : site_elcwd_r8, site_elage_r8 - use FatesIOVariableKindMod, only : iotype_index, site_agefuel_r8 + use FatesIOVariableKindMod, only : iotype_index, site_agefuel_r8, site_clscpf_r8 + use shr_log_mod , only : errMsg => shr_log_errMsg + implicit none private ! By default everything is private ! Make public necessary subroutines and functions + + character(len=*), parameter, private :: sourcefile = & + __FILE__ ! This type is instanteated in the HLM-FATES interface (clmfates_interfaceMod.F90) @@ -161,6 +168,14 @@ subroutine Init(this, vname, units, long, use_default, & allocate(this%r82d(lb1:ub1, lb2:ub2)) this%r82d(:,:) = flushval + case(site_cdsc_r8) + allocate(this%r82d(lb1:ub1, lb2:ub2)) + this%r82d(:,:) = flushval + + case(site_cdpf_r8) + allocate(this%r82d(lb1:ub1, lb2:ub2)) + this%r82d(:,:) = flushval + case(site_scag_r8) allocate(this%r82d(lb1:ub1, lb2:ub2)) this%r82d(:,:) = flushval @@ -193,11 +208,14 @@ subroutine Init(this, vname, units, long, use_default, & allocate(this%r82d(lb1:ub1, lb2:ub2)) this%r82d(:,:) = flushval + case(site_clscpf_r8) + allocate(this%r82d(lb1:ub1, lb2:ub2)) + this%r82d(:,:) = flushval + case default write(fates_log(),*) 'Incompatible vtype passed to set_history_var' write(fates_log(),*) 'vtype = ',trim(vtype),' ?' - stop - ! end_run + call endrun(msg=errMsg(sourcefile, __LINE__)) end select end subroutine Init @@ -298,6 +316,10 @@ subroutine Flush(this, thread, dim_bounds, dim_kinds) this%r82d(lb1:ub1, lb2:ub2) = this%flushval case(site_cnlfpft_r8) this%r82d(lb1:ub1, lb2:ub2) = this%flushval + case(site_cdsc_r8) + this%r82d(lb1:ub1, lb2:ub2) = this%flushval + case(site_cdpf_r8) + this%r82d(lb1:ub1, lb2:ub2) = this%flushval case(site_scag_r8) this%r82d(lb1:ub1, lb2:ub2) = this%flushval case(site_scagpft_r8) @@ -314,10 +336,11 @@ subroutine Flush(this, thread, dim_bounds, dim_kinds) this%r82d(lb1:ub1, lb2:ub2) = this%flushval case(site_agefuel_r8) this%r82d(lb1:ub1, lb2:ub2) = this%flushval + case(site_clscpf_r8) + this%r82d(lb1:ub1, lb2:ub2) = this%flushval case default write(fates_log(),*) 'fates history variable type undefined while flushing history variables' - stop - !end_run + call endrun(msg=errMsg(sourcefile, __LINE__)) end select end subroutine Flush diff --git a/main/FatesHydraulicsMemMod.F90 b/main/FatesHydraulicsMemMod.F90 index 65163e1c8c..61e97173c7 100644 --- a/main/FatesHydraulicsMemMod.F90 +++ b/main/FatesHydraulicsMemMod.F90 @@ -2,6 +2,7 @@ module FatesHydraulicsMemMod use FatesConstantsMod, only : r8 => fates_r8 use FatesConstantsMod, only : fates_unset_r8 + use FatesGlobals, only : fates_log use shr_infnan_mod, only : nan => shr_infnan_nan, assignment(=) use FatesConstantsMod, only : itrue,ifalse use FatesHydroWTFMod, only : wrf_arr_type @@ -14,8 +15,8 @@ module FatesHydraulicsMemMod ! Define the various different solver options for hydraulics integer, parameter, public :: hydr_solver_1DTaylor = 1 - integer, parameter, public :: hydr_solver_2DNewton = 2 - integer, parameter, public :: hydr_solver_2DPicard = 3 + integer, parameter, public :: hydr_solver_2DNewton = 3 + integer, parameter, public :: hydr_solver_2DPicard = 2 ! Number of soil layers for indexing cohort fine root quanitities ! NOTE: The hydraulics code does have some capacity to run a single soil @@ -33,7 +34,7 @@ module FatesHydraulicsMemMod integer, parameter, public :: n_hypool_stem = 1 integer, parameter, public :: n_hypool_troot = 1 ! CANNOT BE CHANGED integer, parameter, public :: n_hypool_aroot = 1 ! THIS IS "PER-SOIL-LAYER" - integer, parameter, public :: nshell = 5 + integer, parameter, public :: nshell = 1 ! number of aboveground plant water storage nodes @@ -314,11 +315,74 @@ module FatesHydraulicsMemMod procedure :: AllocateHydrCohortArrays procedure :: DeallocateHydrCohortArrays + procedure :: CopyCohortHydraulics + procedure :: Dump end type ed_cohort_hydr_type contains - + + subroutine CopyCohortHydraulics(ncohort_hydr, ocohort_hydr) + + ! Arguments + class(ed_cohort_hydr_type), intent(inout) :: ncohort_hydr + class(ed_cohort_hydr_type), intent(inout) :: ocohort_hydr + + ! Node heights + ncohort_hydr%z_node_ag = ocohort_hydr%z_node_ag + ncohort_hydr%z_upper_ag = ocohort_hydr%z_upper_ag + ncohort_hydr%z_lower_ag = ocohort_hydr%z_lower_ag + ncohort_hydr%z_node_troot = ocohort_hydr%z_node_troot + + ! Compartment kmax's + ncohort_hydr%kmax_petiole_to_leaf = ocohort_hydr%kmax_petiole_to_leaf + ncohort_hydr%kmax_stem_lower = ocohort_hydr%kmax_stem_lower + ncohort_hydr%kmax_stem_upper = ocohort_hydr%kmax_stem_upper + ncohort_hydr%kmax_troot_upper = ocohort_hydr%kmax_troot_upper + ncohort_hydr%kmax_troot_lower = ocohort_hydr%kmax_troot_lower + ncohort_hydr%kmax_aroot_upper = ocohort_hydr%kmax_aroot_upper + ncohort_hydr%kmax_aroot_lower = ocohort_hydr%kmax_aroot_lower + ncohort_hydr%kmax_aroot_radial_in = ocohort_hydr%kmax_aroot_radial_in + ncohort_hydr%kmax_aroot_radial_out = ocohort_hydr%kmax_aroot_radial_out + + ! Compartment volumes + ncohort_hydr%v_ag_init = ocohort_hydr%v_ag_init + ncohort_hydr%v_ag = ocohort_hydr%v_ag + ncohort_hydr%v_troot_init = ocohort_hydr%v_troot_init + ncohort_hydr%v_troot = ocohort_hydr%v_troot + ncohort_hydr%v_aroot_layer_init = ocohort_hydr%v_aroot_layer_init + ncohort_hydr%v_aroot_layer = ocohort_hydr%v_aroot_layer + ncohort_hydr%l_aroot_layer = ocohort_hydr%l_aroot_layer + + ! State Variables + ncohort_hydr%th_ag = ocohort_hydr%th_ag + ncohort_hydr%th_troot = ocohort_hydr%th_troot + ncohort_hydr%th_aroot = ocohort_hydr%th_aroot + ncohort_hydr%psi_ag = ocohort_hydr%psi_ag + ncohort_hydr%psi_troot = ocohort_hydr%psi_troot + ncohort_hydr%psi_aroot = ocohort_hydr%psi_aroot + ncohort_hydr%ftc_ag = ocohort_hydr%ftc_ag + ncohort_hydr%ftc_troot = ocohort_hydr%ftc_troot + ncohort_hydr%ftc_aroot = ocohort_hydr%ftc_aroot + + ! Other + ncohort_hydr%btran = ocohort_hydr%btran + ncohort_hydr%supsub_flag = ocohort_hydr%supsub_flag + ncohort_hydr%iterh1 = ocohort_hydr%iterh1 + ncohort_hydr%iterh2 = ocohort_hydr%iterh2 + ncohort_hydr%iterlayer = ocohort_hydr%iterlayer + ncohort_hydr%errh2o = ocohort_hydr%errh2o + + + ! BC PLANT HYDRAULICS - flux terms + ncohort_hydr%qtop = ocohort_hydr%qtop + + ncohort_hydr%is_newly_recruited = ocohort_hydr%is_newly_recruited + + end subroutine CopyCohortHydraulics + + ! ========================================================================== + subroutine AllocateHydrCohortArrays(this,nlevrhiz) ! Arguments @@ -361,7 +425,24 @@ subroutine DeallocateHydrCohortArrays(this) return end subroutine DeallocateHydrCohortArrays - ! =================================================================================== + ! ========================================================================== + + subroutine Dump(this) + + class(ed_cohort_hydr_type), intent(in) :: this + + write(fates_log(),*) '--------------------------------------------' + write(fates_log(),*) ' Dumping Cohort Plant Hydraulic Information ' + write(fates_log(),*) 'ccohort_hydr%th_aroot(:) = ', this%th_aroot(:) + write(fates_log(),*) 'ccohort_hydr%v_aroot_layer_init(:) = ', this%v_aroot_layer_init(:) + write(fates_log(),*) 'ccohort_hydr%v_aroot_layer(:) = ', this%v_aroot_layer(:) + write(fates_log(),*) '--------------------------------------------' + + return + + end subroutine Dump + + ! ========================================================================== subroutine InitHydrSite(this,numpft,numlevsclass,hydr_solver_type,nlevsoil) diff --git a/main/FatesIODimensionsMod.F90 b/main/FatesIODimensionsMod.F90 index 6760bf0dbe..92488d00a9 100644 --- a/main/FatesIODimensionsMod.F90 +++ b/main/FatesIODimensionsMod.F90 @@ -26,8 +26,11 @@ module FatesIODimensionsMod character(*), parameter, public :: levcan = 'fates_levcan' ! matches histFileMod character(*), parameter, public :: levcnlf = 'fates_levcnlf' ! matches histFileMod character(*), parameter, public :: levcnlfpft = 'fates_levcnlfpf' ! matches histFileMod + character(*), parameter, public :: levclscpf = 'fates_levclscpf' + character(*), parameter, public :: levcdsc = 'fates_levcdsc' ! matches histFileMod + character(*), parameter, public :: levcdpf = 'fates_levcdpf' ! matches histFileMod + character(*), parameter, public :: levcdam = 'fates_levcdam' ! matches histFileMod character(*), parameter, public :: levagefuel = 'fates_levagefuel' ! matches histFileMod - character(*), parameter, public :: levelem = 'fates_levelem' character(*), parameter, public :: levelpft = 'fates_levelpft' character(*), parameter, public :: levelcwd = 'fates_levelcwd' @@ -76,6 +79,15 @@ module FatesIODimensionsMod ! levcnlfpft = This is a structure that records the boundaries for the ! number of canopy layer x leaf layer x pft dimension + ! levcdsc = This is a structure that records the boundaries for the + ! number of crown damage x size classes dimension + + ! levcdpf = This is a structure that records the boundaries for the + ! number of crown damage x size classes x pft dimension + + ! levcdam = This is the structure that records the boundaries for the + ! number of crown damage classes dimension + ! levscag = This is a strcture that records the boundaries for the ! number of size-classes x patch age @@ -88,12 +100,22 @@ module FatesIODimensionsMod ! levagefuel = This is a strcture that records the boundaries for the ! number of patch age x fuel size class + ! levclscpf = '' number of canopy layers x pft x size class + ! levelem = This records the boundaries for the number of elements ! levelpft = This records the boundaries for elements x pft ! levelcwd = This records the boundaries for element x cwd ! levelage = This records the boundaries for element x age + ! levcdsc = This is a structure that records the boundaries for the + ! number of crown damage x size classes dimension + + ! levcdpf = This is a structure that records the boundaries for the + ! number of crown damage x size classes x pft dimension + ! levcdam = This is the structure that records the boundaries for the + ! number of crown damage classes dimension + type, public :: fates_bounds_type integer :: cohort_begin integer :: cohort_end @@ -131,6 +153,12 @@ module FatesIODimensionsMod integer :: cnlf_end integer :: cnlfpft_begin integer :: cnlfpft_end + integer :: cdsc_begin + integer :: cdsc_end + integer :: cdpf_begin + integer :: cdpf_end + integer :: cdam_begin + integer :: cdam_end integer :: elem_begin integer :: elem_end integer :: elpft_begin @@ -141,6 +169,8 @@ module FatesIODimensionsMod integer :: elage_end integer :: agefuel_begin integer :: agefuel_end + integer :: clscpf_begin + integer :: clscpf_end end type fates_bounds_type diff --git a/main/FatesIOVariableKindMod.F90 b/main/FatesIOVariableKindMod.F90 index daba4f3c20..84dd8e692f 100644 --- a/main/FatesIOVariableKindMod.F90 +++ b/main/FatesIOVariableKindMod.F90 @@ -3,10 +3,16 @@ module FatesIOVariableKindMod use FatesConstantsMod, only : fates_long_string_length use FatesGlobals, only : fates_log use FatesIODimensionsMod, only : fates_io_dimension_type + use FatesGlobals , only : endrun => fates_endrun + use shr_log_mod , only : errMsg => shr_log_errMsg + implicit none private + character(len=*), parameter, private :: sourcefile = & + __FILE__ + ! FIXME(bja, 2016-10) do these need to be strings, or can they be integer enumerations? ! FIXME(rgk, 2016-11) these should probably be moved to varkindmod? @@ -26,12 +32,16 @@ module FatesIOVariableKindMod character(*), parameter, public :: site_cwdsc_r8 = 'SI_CWDSC_R8' character(*), parameter, public :: site_can_r8 = 'SI_CAN_R8' character(*), parameter, public :: site_cnlf_r8 = 'SI_CNLF_R8' + character(*), parameter, public :: site_cdpf_r8 = 'SI_CDPF_R8' + character(*), parameter, public :: site_cdsc_r8 = 'SI_CDSC_R8' + character(*), parameter, public :: site_cdam_r8 = 'SI_CDAM_R8' character(*), parameter, public :: site_cnlfpft_r8 = 'SI_CNLFPFT_R8' character(*), parameter, public :: site_scag_r8 = 'SI_SCAG_R8' character(*), parameter, public :: site_scagpft_r8 = 'SI_SCAGPFT_R8' character(*), parameter, public :: site_agepft_r8 = 'SI_AGEPFT_R8' character(*), parameter, public :: site_agefuel_r8 = 'SI_AGEFUEL_R8' - + character(*), parameter, public :: site_clscpf_r8 = 'SI_CLSCPF_R8' + ! Element, and multiplexed element dimensions character(*), parameter, public :: site_elem_r8 = 'SI_ELEM_R8' character(*), parameter, public :: site_elpft_r8 = 'SI_ELEMPFT_R8' @@ -118,7 +128,7 @@ function iotype_index(iotype_name, num_dim_kinds, dim_kinds) result(dk_index) end if end do write(fates_log(),*) 'An IOTYPE THAT DOESNT EXIST WAS SPECIFIED' - !end_run + call endrun(msg=errMsg(sourcefile, __LINE__)) end function iotype_index diff --git a/main/FatesInterfaceMod.F90 b/main/FatesInterfaceMod.F90 index 3ce7589f48..6ea4d21bf8 100644 --- a/main/FatesInterfaceMod.F90 +++ b/main/FatesInterfaceMod.F90 @@ -10,32 +10,41 @@ module FatesInterfaceMod ! ------------------------------------------------------------------------------------ use EDTypesMod , only : ed_site_type - use EDTypesMod , only : maxPatchesPerSite - use EDTypesMod , only : maxCohortsPerPatch - use EDTypesMod , only : dinc_vai - use EDTypesMod , only : dlower_vai + use EDParamsMod , only : dinc_vai + use EDParamsMod , only : dlower_vai use EDParamsMod , only : ED_val_vai_top_bin_width use EDParamsMod , only : ED_val_vai_width_increase_factor - use EDTypesMod , only : maxSWb - use EDTypesMod , only : ivis - use EDTypesMod , only : inir - use EDTypesMod , only : nclmax - use EDTypesMod , only : nlevleaf - use EDTypesMod , only : maxpft + use EDParamsMod , only : ED_val_history_damage_bin_edges + use EDParamsMod , only : maxpatch_total + use EDParamsMod , only : maxpatch_primary + use EDParamsMod , only : maxpatch_secondary + use EDParamsMod , only : max_cohort_per_patch + use EDParamsMod , only : regeneration_model + use EDParamsMod , only : maxSWb + use EDParamsMod , only : ivis + use EDParamsMod , only : inir + use EDParamsMod , only : nclmax + use EDParamsMod , only : nlevleaf + use EDParamsMod , only : maxpft use EDTypesMod , only : do_fates_salinity use EDTypesMod , only : numWaterMem use EDTypesMod , only : numlevsoil_max use EDTypesMod , only : ed_site_type - use EDTypesMod , only : ed_patch_type - use EDTypesMod , only : ed_cohort_type + use FatesPatchMod , only : fates_patch_type + use FatesCohortMod , only : fates_cohort_type use EDTypesMod , only : area_inv + use EDTypesMod , only : num_vegtemp_mem use FatesConstantsMod , only : r8 => fates_r8 use FatesConstantsMod , only : itrue,ifalse use FatesConstantsMod , only : nearzero use FatesConstantsMod , only : sec_per_day + use FatesConstantsMod , only : days_per_year + use FatesConstantsMod , only : TRS_regeneration + use FatesConstantsMod , only : g_per_kg use FatesGlobals , only : fates_global_verbose use FatesGlobals , only : fates_log use FatesGlobals , only : endrun => fates_endrun + use FatesConstantsMod , only : fates_unset_r8 use FatesLitterMod , only : ncwd use FatesLitterMod , only : ndcmpy use EDPftvarcon , only : FatesReportPFTParams @@ -46,21 +55,26 @@ module FatesInterfaceMod use EDParamsMod , only : bgc_soil_salinity use FatesPlantHydraulicsMod , only : InitHydroGlobals use EDParamsMod , only : photo_temp_acclim_timescale + use EDParamsMod , only : photo_temp_acclim_thome_time + 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 use EDParamsMod , only : ED_val_history_coageclass_bin_edges use CLMFatesParamInterfaceMod , only : FatesReadParameters - use EDTypesMod , only : p_uptake_mode - use EDTypesMod , only : n_uptake_mode + use EDParamsMod , only : p_uptake_mode + use EDParamsMod , only : n_uptake_mode use EDTypesMod , only : ed_site_type use FatesConstantsMod , only : prescribed_p_uptake use FatesConstantsMod , only : prescribed_n_uptake use FatesConstantsMod , only : coupled_p_uptake use FatesConstantsMod , only : coupled_n_uptake use FatesConstantsMod , only : fates_np_comp_scaling - use FatesConstantsMod , only : cohort_np_comp_scaling - use FatesConstantsMod , only : pft_np_comp_scaling + use FatesConstantsMod , only : coupled_np_comp_scaling + use FatesConstantsMod , only : trivial_np_comp_scaling use PRTGenericMod , only : num_elements use PRTGenericMod , only : element_list use PRTGenericMod , only : element_pos @@ -78,16 +92,22 @@ 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 : ema_longterm + use FatesRunningMeanMod , only : ema_60day use FatesRunningMeanMod , only : moving_ema_window use FatesRunningMeanMod , only : fixed_window use FatesHistoryInterfaceMod , only : fates_hist - + use FatesHydraulicsMemMod , only : nshell + use FatesHydraulicsMemMod , only : nlevsoi_hyd_max ! CIME Globals use shr_log_mod , only : errMsg => shr_log_errMsg use shr_infnan_mod , only : nan => shr_infnan_nan, assignment(=) + use shr_kind_mod , only : SHR_KIND_CL ! Just use everything from FatesInterfaceTypesMod, this is ! its sister code @@ -133,8 +153,6 @@ module FatesInterfaceMod end type fates_interface_type - - character(len=*), parameter :: sourcefile = & __FILE__ @@ -142,7 +160,8 @@ module FatesInterfaceMod public :: FatesInterfaceInit public :: set_fates_ctrlparms public :: SetFatesTime - public :: SetFatesGlobalElements + public :: SetFatesGlobalElements1 + public :: SetFatesGlobalElements2 public :: FatesReportParameters public :: allocate_bcin public :: allocate_bcout @@ -152,6 +171,9 @@ module FatesInterfaceMod public :: set_bcs public :: UpdateFatesRMeansTStep public :: InitTimeAveragingGlobals + public :: DetermineGridCellNeighbors + + logical :: debug = .false. ! for debugging this module contains @@ -197,13 +219,13 @@ subroutine allocate_bcpconst(bc_pconst,nlevdecomp) type(bc_pconst_type), intent(inout) :: bc_pconst integer , intent(in) :: nlevdecomp - + + allocate(bc_pconst%vmax_nh4(numpft)) + allocate(bc_pconst%vmax_no3(numpft)) + allocate(bc_pconst%vmax_p(numpft)) allocate(bc_pconst%eca_km_nh4(numpft)) - allocate(bc_pconst%eca_vmax_nh4(numpft)) allocate(bc_pconst%eca_km_no3(numpft)) - allocate(bc_pconst%eca_vmax_no3(numpft)) allocate(bc_pconst%eca_km_p(numpft)) - allocate(bc_pconst%eca_vmax_p(numpft)) allocate(bc_pconst%eca_km_ptase(numpft)) allocate(bc_pconst%eca_vmax_ptase(numpft)) allocate(bc_pconst%eca_alpha_ptase(numpft)) @@ -221,24 +243,18 @@ subroutine set_bcpconst(bc_pconst,nlevdecomp) integer , intent(in) :: nlevdecomp integer :: j + bc_pconst%vmax_nh4(1:numpft) = EDPftvarcon_inst%vmax_nh4(1:numpft) + bc_pconst%vmax_no3(1:numpft) = EDPftvarcon_inst%vmax_no3(1:numpft) + bc_pconst%vmax_p(1:numpft) = EDPftvarcon_inst%vmax_p(1:numpft) + bc_pconst%eca_km_nh4(1:numpft) = EDPftvarcon_inst%eca_km_nh4(1:numpft) - bc_pconst%eca_vmax_nh4(1:numpft) = EDPftvarcon_inst%eca_vmax_nh4(1:numpft) bc_pconst%eca_km_no3(1:numpft) = EDPftvarcon_inst%eca_km_no3(1:numpft) - bc_pconst%eca_vmax_no3(1:numpft) = EDPftvarcon_inst%eca_vmax_no3(1:numpft) bc_pconst%eca_km_p(1:numpft) = EDPftvarcon_inst%eca_km_p(1:numpft) - bc_pconst%eca_vmax_p(1:numpft) = EDPftvarcon_inst%eca_vmax_p(1:numpft) bc_pconst%eca_km_ptase(1:numpft) = EDPftvarcon_inst%eca_km_ptase(1:numpft) bc_pconst%eca_vmax_ptase(1:numpft) = EDPftvarcon_inst%eca_vmax_ptase(1:numpft) bc_pconst%eca_alpha_ptase(1:numpft) = EDPftvarcon_inst%eca_alpha_ptase(1:numpft) bc_pconst%eca_lambda_ptase(1:numpft) = EDPftvarcon_inst%eca_lambda_ptase(1:numpft) bc_pconst%eca_plant_escalar = eca_plant_escalar - if(fates_np_comp_scaling.eq.cohort_np_comp_scaling) then - bc_pconst%j_uptake(1:nlevdecomp) = 1 - else - do j=1,nlevdecomp - bc_pconst%j_uptake(j) = j - end do - end if return end subroutine set_bcpconst @@ -304,12 +320,22 @@ subroutine zero_bcs(fates,s) fates%bc_out(s)%rootr_pasl(:,:) = 0.0_r8 fates%bc_out(s)%btran_pa(:) = 0.0_r8 + ! MIMIC litter quality, always initialize to unset + fates%bc_out(s)%litt_flux_ligc_per_n = fates_unset_r8 + + ! Fates -> BGC fragmentation mass fluxes select case(hlm_parteh_mode) case(prt_carbon_allom_hyp) fates%bc_out(s)%litt_flux_cel_c_si(:) = 0._r8 fates%bc_out(s)%litt_flux_lig_c_si(:) = 0._r8 fates%bc_out(s)%litt_flux_lab_c_si(:) = 0._r8 + ! Yes, zero out N flux arrays for c-only runs. + ! This is because we want these on (and zero) + ! with CLM. + fates%bc_out(s)%litt_flux_cel_n_si(:) = 0._r8 + fates%bc_out(s)%litt_flux_lig_n_si(:) = 0._r8 + fates%bc_out(s)%litt_flux_lab_n_si(:) = 0._r8 case(prt_cnp_flex_allom_hyp) fates%bc_in(s)%plant_nh4_uptake_flux(:,:) = 0._r8 @@ -365,12 +391,18 @@ subroutine zero_bcs(fates,s) end if fates%bc_out(s)%plant_stored_h2o_si = 0.0_r8 + ! Land Use realated + fates%bc_out(s)%gpp_site = 0.0_r8 + fates%bc_out(s)%ar_site = 0.0_r8 + fates%bc_out(s)%hrv_deadstemc_to_prod10c = 0.0_r8 + fates%bc_out(s)%hrv_deadstemc_to_prod100c = 0.0_r8 + return end subroutine zero_bcs ! =========================================================================== - subroutine allocate_bcin(bc_in, nlevsoil_in, nlevdecomp_in, num_lu_harvest_cats) + subroutine allocate_bcin(bc_in, nlevsoil_in, nlevdecomp_in, num_lu_harvest_cats,natpft_lb,natpft_ub) ! --------------------------------------------------------------------------------- ! Allocate and Initialze the FATES boundary condition vectors @@ -381,6 +413,7 @@ subroutine allocate_bcin(bc_in, nlevsoil_in, nlevdecomp_in, num_lu_harvest_cats) integer,intent(in) :: nlevsoil_in integer,intent(in) :: nlevdecomp_in integer,intent(in) :: num_lu_harvest_cats + integer,intent(in) :: natpft_lb,natpft_ub ! dimension bounds of the array holding surface file pft data ! Allocate input boundaries @@ -394,24 +427,8 @@ subroutine allocate_bcin(bc_in, nlevsoil_in, nlevdecomp_in, num_lu_harvest_cats) call endrun(msg=errMsg(sourcefile, __LINE__)) end if - if( (nlevsoil_in*ndcmpy) > fates_maxElementsPerPatch .or. & - (nlevsoil_in*ncwd) > fates_maxElementsPerPatch) then - write(fates_log(), *) 'The restart files require that space is allocated' - write(fates_log(), *) 'to accomodate the multi-dimensional patch arrays' - write(fates_log(), *) 'that are nlevsoil*numpft and nlevsoil*ncwd' - write(fates_log(), *) 'fates_maxElementsPerPatch = ',fates_maxElementsPerPatch - write(fates_log(), *) 'nlevsoil = ',nlevsoil_in - write(fates_log(), *) 'dcmpy = ',ndcmpy - write(fates_log(), *) 'ncwd = ',ncwd - write(fates_log(), *) 'numpft*nlevsoil = ',nlevsoil_in*numpft - write(fates_log(), *) 'ncwd*nlevsoil = ',ncwd * nlevsoil_in - write(fates_log(), *) 'To increase max_elements, change numlevsoil_max' - call endrun(msg=errMsg(sourcefile, __LINE__)) - end if - bc_in%nlevdecomp = nlevdecomp_in - if (hlm_use_vertsoilc == itrue) then if(bc_in%nlevdecomp .ne. bc_in%nlevsoil) then write(fates_log(), *) 'The host has signaled a vertically resolved' @@ -440,22 +457,15 @@ subroutine allocate_bcin(bc_in, nlevsoil_in, nlevdecomp_in, num_lu_harvest_cats) ! Allocating differently could save a lot of memory and time if (hlm_parteh_mode .eq. prt_cnp_flex_allom_hyp) then - if(fates_np_comp_scaling.eq.cohort_np_comp_scaling) then - allocate(bc_in%plant_nh4_uptake_flux(max_comp_per_site,1)) - allocate(bc_in%plant_no3_uptake_flux(max_comp_per_site,1)) - allocate(bc_in%plant_p_uptake_flux(max_comp_per_site,1)) - else - allocate(bc_in%plant_nh4_uptake_flux(max_comp_per_site,bc_in%nlevdecomp)) - allocate(bc_in%plant_no3_uptake_flux(max_comp_per_site,bc_in%nlevdecomp)) - allocate(bc_in%plant_p_uptake_flux(max_comp_per_site,bc_in%nlevdecomp)) - end if + allocate(bc_in%plant_nh4_uptake_flux(max_comp_per_site,1)) + allocate(bc_in%plant_no3_uptake_flux(max_comp_per_site,1)) + allocate(bc_in%plant_p_uptake_flux(max_comp_per_site,1)) else allocate(bc_in%plant_nh4_uptake_flux(1,1)) allocate(bc_in%plant_no3_uptake_flux(1,1)) allocate(bc_in%plant_p_uptake_flux(1,1)) end if - allocate(bc_in%zi_sisl(0:nlevsoil_in)) allocate(bc_in%dz_sisl(nlevsoil_in)) allocate(bc_in%z_sisl(nlevsoil_in)) @@ -466,15 +476,15 @@ subroutine allocate_bcin(bc_in, nlevsoil_in, nlevdecomp_in, num_lu_harvest_cats) ! Lightning (or successful ignitions) and population density ! Fire related variables - allocate(bc_in%lightning24(maxPatchesPerSite)) - allocate(bc_in%pop_density(maxPatchesPerSite)) - allocate(bc_in%wind24_pa(maxPatchesPerSite)) - allocate(bc_in%relhumid24_pa(maxPatchesPerSite)) - allocate(bc_in%precip24_pa(maxPatchesPerSite)) + allocate(bc_in%lightning24(maxpatch_total)) + allocate(bc_in%pop_density(maxpatch_total)) + allocate(bc_in%wind24_pa(maxpatch_total)) + allocate(bc_in%relhumid24_pa(maxpatch_total)) + allocate(bc_in%precip24_pa(maxpatch_total)) ! Radiation - allocate(bc_in%solad_parb(maxPatchesPerSite,hlm_numSWb)) - allocate(bc_in%solai_parb(maxPatchesPerSite,hlm_numSWb)) + allocate(bc_in%solad_parb(maxpatch_total,hlm_numSWb)) + allocate(bc_in%solai_parb(maxpatch_total,hlm_numSWb)) ! Hydrology allocate(bc_in%smp_sl(nlevsoil_in)) @@ -491,30 +501,30 @@ subroutine allocate_bcin(bc_in, nlevsoil_in, nlevdecomp_in, num_lu_harvest_cats) ! Photosynthesis - allocate(bc_in%filter_photo_pa(maxPatchesPerSite)) - allocate(bc_in%dayl_factor_pa(maxPatchesPerSite)) - allocate(bc_in%esat_tv_pa(maxPatchesPerSite)) - allocate(bc_in%eair_pa(maxPatchesPerSite)) - allocate(bc_in%oair_pa(maxPatchesPerSite)) - allocate(bc_in%cair_pa(maxPatchesPerSite)) - allocate(bc_in%rb_pa(maxPatchesPerSite)) - allocate(bc_in%t_veg_pa(maxPatchesPerSite)) - allocate(bc_in%tgcm_pa(maxPatchesPerSite)) + allocate(bc_in%filter_photo_pa(maxpatch_total)) + allocate(bc_in%dayl_factor_pa(maxpatch_total)) + allocate(bc_in%esat_tv_pa(maxpatch_total)) + allocate(bc_in%eair_pa(maxpatch_total)) + allocate(bc_in%oair_pa(maxpatch_total)) + allocate(bc_in%cair_pa(maxpatch_total)) + allocate(bc_in%rb_pa(maxpatch_total)) + allocate(bc_in%t_veg_pa(maxpatch_total)) + allocate(bc_in%tgcm_pa(maxpatch_total)) allocate(bc_in%t_soisno_sl(nlevsoil_in)) ! Canopy Radiation - allocate(bc_in%filter_vegzen_pa(maxPatchesPerSite)) - allocate(bc_in%coszen_pa(maxPatchesPerSite)) - allocate(bc_in%fcansno_pa(maxPatchesPerSite)) + allocate(bc_in%filter_vegzen_pa(maxpatch_total)) + allocate(bc_in%coszen_pa(maxpatch_total)) + allocate(bc_in%fcansno_pa(maxpatch_total)) allocate(bc_in%albgr_dir_rb(hlm_numSWb)) allocate(bc_in%albgr_dif_rb(hlm_numSWb)) ! Plant-Hydro BC's if (hlm_use_planthydro.eq.itrue) then - allocate(bc_in%qflx_transp_pa(maxPatchesPerSite)) - allocate(bc_in%swrad_net_pa(maxPatchesPerSite)) - allocate(bc_in%lwrad_net_pa(maxPatchesPerSite)) + allocate(bc_in%qflx_transp_pa(maxpatch_total)) + allocate(bc_in%swrad_net_pa(maxpatch_total)) + allocate(bc_in%lwrad_net_pa(maxpatch_total)) allocate(bc_in%watsat_sisl(nlevsoil_in)) allocate(bc_in%watres_sisl(nlevsoil_in)) @@ -536,13 +546,13 @@ subroutine allocate_bcin(bc_in, nlevsoil_in, nlevdecomp_in, num_lu_harvest_cats) allocate(bc_in%hlm_harvest_catnames(0)) end if - allocate(bc_in%pft_areafrac(0:maxpft)) + allocate(bc_in%pft_areafrac(natpft_lb:natpft_ub)) ! Variables for SP mode. if(hlm_use_sp.eq.itrue) then - allocate(bc_in%hlm_sp_tlai(0:maxpft)) - allocate(bc_in%hlm_sp_tsai(0:maxpft)) - allocate(bc_in%hlm_sp_htop(0:maxpft)) + allocate(bc_in%hlm_sp_tlai(natpft_lb:natpft_ub)) + allocate(bc_in%hlm_sp_tsai(natpft_lb:natpft_ub)) + allocate(bc_in%hlm_sp_htop(natpft_lb:natpft_ub)) end if return end subroutine allocate_bcin @@ -561,28 +571,28 @@ subroutine allocate_bcout(bc_out, nlevsoil_in, nlevdecomp_in) integer,intent(in) :: nlevdecomp_in ! Radiation - allocate(bc_out%fsun_pa(maxPatchesPerSite)) - allocate(bc_out%laisun_pa(maxPatchesPerSite)) - allocate(bc_out%laisha_pa(maxPatchesPerSite)) + allocate(bc_out%fsun_pa(maxpatch_total)) + allocate(bc_out%laisun_pa(maxpatch_total)) + allocate(bc_out%laisha_pa(maxpatch_total)) ! Hydrology allocate(bc_out%active_suction_sl(nlevsoil_in)) - allocate(bc_out%rootr_pasl(maxPatchesPerSite,nlevsoil_in)) - allocate(bc_out%btran_pa(maxPatchesPerSite)) + allocate(bc_out%rootr_pasl(maxpatch_total,nlevsoil_in)) + allocate(bc_out%btran_pa(maxpatch_total)) ! Photosynthesis - allocate(bc_out%rssun_pa(maxPatchesPerSite)) - allocate(bc_out%rssha_pa(maxPatchesPerSite)) + allocate(bc_out%rssun_pa(maxpatch_total)) + allocate(bc_out%rssha_pa(maxpatch_total)) ! Canopy Radiation - allocate(bc_out%albd_parb(maxPatchesPerSite,hlm_numSWb)) - allocate(bc_out%albi_parb(maxPatchesPerSite,hlm_numSWb)) - allocate(bc_out%fabd_parb(maxPatchesPerSite,hlm_numSWb)) - allocate(bc_out%fabi_parb(maxPatchesPerSite,hlm_numSWb)) - allocate(bc_out%ftdd_parb(maxPatchesPerSite,hlm_numSWb)) - allocate(bc_out%ftid_parb(maxPatchesPerSite,hlm_numSWb)) - allocate(bc_out%ftii_parb(maxPatchesPerSite,hlm_numSWb)) + allocate(bc_out%albd_parb(maxpatch_total,hlm_numSWb)) + allocate(bc_out%albi_parb(maxpatch_total,hlm_numSWb)) + allocate(bc_out%fabd_parb(maxpatch_total,hlm_numSWb)) + allocate(bc_out%fabi_parb(maxpatch_total,hlm_numSWb)) + allocate(bc_out%ftdd_parb(maxpatch_total,hlm_numSWb)) + allocate(bc_out%ftid_parb(maxpatch_total,hlm_numSWb)) + allocate(bc_out%ftii_parb(maxpatch_total,hlm_numSWb)) ! We allocate the boundary conditions to the BGC @@ -595,44 +605,52 @@ subroutine allocate_bcout(bc_out, nlevsoil_in, nlevdecomp_in) ! When FATES does not have nutrients enabled, these ! arrays are indexed by 1. - if(trim(hlm_nu_com).eq.'RD') then - allocate(bc_out%n_demand(max_comp_per_site)) - allocate(bc_out%p_demand(max_comp_per_site)) - end if - + !if(trim(hlm_nu_com).eq.'RD') then + ! allocate(bc_out%n_demand(max_comp_per_site)) + ! allocate(bc_out%p_demand(max_comp_per_site)) + !end if + + ! Used in both + allocate(bc_out%veg_rootc(max_comp_per_site,nlevdecomp_in)) + allocate(bc_out%ft_index(max_comp_per_site)) + if(trim(hlm_nu_com).eq.'ECA') then - allocate(bc_out%veg_rootc(max_comp_per_site,nlevdecomp_in)) allocate(bc_out%decompmicc(nlevdecomp_in)) - allocate(bc_out%ft_index(max_comp_per_site)) allocate(bc_out%cn_scalar(max_comp_per_site)) allocate(bc_out%cp_scalar(max_comp_per_site)) end if ! Include the bare-ground patch for these patch-level boundary conditions ! (it will always be zero for all of these) - if(hlm_use_ch4.eq.itrue) then - allocate(bc_out%annavg_agnpp_pa(0:maxPatchesPerSite));bc_out%annavg_agnpp_pa(:)=nan - allocate(bc_out%annavg_bgnpp_pa(0:maxPatchesPerSite));bc_out%annavg_bgnpp_pa(:)=nan - allocate(bc_out%annsum_npp_pa(0:maxPatchesPerSite));bc_out%annsum_npp_pa(:)=nan - allocate(bc_out%frootc_pa(0:maxPatchesPerSite));bc_out%frootc_pa(:)=nan + !if(hlm_use_ch4.eq.itrue) then + allocate(bc_out%annavg_agnpp_pa(0:maxpatch_total));bc_out%annavg_agnpp_pa(:)=nan + allocate(bc_out%annavg_bgnpp_pa(0:maxpatch_total));bc_out%annavg_bgnpp_pa(:)=nan + allocate(bc_out%annsum_npp_pa(0:maxpatch_total));bc_out%annsum_npp_pa(:)=nan + allocate(bc_out%frootc_pa(0:maxpatch_total));bc_out%frootc_pa(:)=nan allocate(bc_out%root_resp(nlevsoil_in));bc_out%root_resp(:)=nan - allocate(bc_out%woody_frac_aere_pa(0:maxPatchesPerSite));bc_out%woody_frac_aere_pa(:)=nan - allocate(bc_out%rootfr_pa(0:maxPatchesPerSite,nlevsoil_in)) + allocate(bc_out%woody_frac_aere_pa(0:maxpatch_total));bc_out%woody_frac_aere_pa(:)=nan + allocate(bc_out%rootfr_pa(0:maxpatch_total,nlevsoil_in)) bc_out%rootfr_pa(:,:)=nan ! Give the bare-ground root fractions a nominal fraction of unity over depth bc_out%rootfr_pa(0,1:nlevsoil_in)=1._r8/real(nlevsoil_in,r8) - end if + !end if - + bc_out%ema_npp = nan + ! Fates -> BGC fragmentation mass fluxes select case(hlm_parteh_mode) case(prt_carbon_allom_hyp) allocate(bc_out%litt_flux_cel_c_si(nlevdecomp_in)) allocate(bc_out%litt_flux_lig_c_si(nlevdecomp_in)) allocate(bc_out%litt_flux_lab_c_si(nlevdecomp_in)) + ! Yes, allocate N flux arrays for c-only runs. + ! This is because we want these on (and zero) + ! with CLM. + allocate(bc_out%litt_flux_cel_n_si(nlevdecomp_in)) + allocate(bc_out%litt_flux_lig_n_si(nlevdecomp_in)) + allocate(bc_out%litt_flux_lab_n_si(nlevdecomp_in)) case(prt_cnp_flex_allom_hyp) - allocate(bc_out%litt_flux_cel_c_si(nlevdecomp_in)) allocate(bc_out%litt_flux_lig_c_si(nlevdecomp_in)) allocate(bc_out%litt_flux_lab_c_si(nlevdecomp_in)) @@ -642,10 +660,8 @@ subroutine allocate_bcout(bc_out, nlevsoil_in, nlevdecomp_in) allocate(bc_out%litt_flux_cel_p_si(nlevdecomp_in)) allocate(bc_out%litt_flux_lig_p_si(nlevdecomp_in)) allocate(bc_out%litt_flux_lab_p_si(nlevdecomp_in)) - allocate(bc_out%source_nh4(nlevdecomp_in)) allocate(bc_out%source_p(nlevdecomp_in)) - case default write(fates_log(), *) 'An unknown parteh hypothesis was passed' write(fates_log(), *) 'to the site level output boundary conditions' @@ -655,21 +671,21 @@ subroutine allocate_bcout(bc_out, nlevsoil_in, nlevdecomp_in) ! Canopy Structure - allocate(bc_out%elai_pa(maxPatchesPerSite)) - allocate(bc_out%esai_pa(maxPatchesPerSite)) - allocate(bc_out%tlai_pa(maxPatchesPerSite)) - allocate(bc_out%tsai_pa(maxPatchesPerSite)) - allocate(bc_out%htop_pa(maxPatchesPerSite)) - allocate(bc_out%hbot_pa(maxPatchesPerSite)) - allocate(bc_out%dleaf_pa(maxPatchesPerSite)) + allocate(bc_out%elai_pa(maxpatch_total)) + allocate(bc_out%esai_pa(maxpatch_total)) + allocate(bc_out%tlai_pa(maxpatch_total)) + allocate(bc_out%tsai_pa(maxpatch_total)) + allocate(bc_out%htop_pa(maxpatch_total)) + allocate(bc_out%hbot_pa(maxpatch_total)) + allocate(bc_out%dleaf_pa(maxpatch_total)) - allocate(bc_out%displa_pa(maxPatchesPerSite)) - allocate(bc_out%z0m_pa(maxPatchesPerSite)) + allocate(bc_out%displa_pa(maxpatch_total)) + allocate(bc_out%z0m_pa(maxpatch_total)) - allocate(bc_out%canopy_fraction_pa(maxPatchesPerSite)) - allocate(bc_out%frac_veg_nosno_alb_pa(maxPatchesPerSite)) + allocate(bc_out%canopy_fraction_pa(maxpatch_total)) + allocate(bc_out%frac_veg_nosno_alb_pa(maxpatch_total)) - allocate(bc_out%nocomp_pft_label_pa(maxPatchesPerSite)) + allocate(bc_out%nocomp_pft_label_pa(maxpatch_total)) ! Plant-Hydro BC's if (hlm_use_planthydro.eq.itrue) then @@ -711,37 +727,90 @@ end subroutine set_bcs ! =================================================================================== - subroutine SetFatesGlobalElements(use_fates) + subroutine SetFatesGlobalElements1(use_fates,surf_numpft,surf_numcft) ! -------------------------------------------------------------------------------- ! ! This is the first FATES routine that is called. ! - ! This subroutine MUST BE CALLED AFTER the FATES PFT parameter file has been read in, - ! and the EDPftvarcon_inst structure has been made. - ! This subroutine MUST BE CALLED AFTER NL VARIABLES ARE READ (ie hlm_parteh_mode,etc) - ! This subroutine must ALSO BE CALLED BEFORE the history file dimensions - ! are set. - ! - ! This routine requires no information from the HLM. This routine is responsible - ! for generating the globals that are required by the HLM that are entirely - ! FATES derived. - ! + ! spmode,biogeog and nocomp mode flags have been passed prior to this call ! -------------------------------------------------------------------------------- - - + implicit none - logical,intent(in) :: use_fates ! Is fates turned on? - integer :: i + logical, intent(in) :: use_fates ! Is fates turned on? + integer, intent(in) :: surf_numpft ! Number of PFTs in surface dataset + integer, intent(in) :: surf_numcft ! Number of CFTs in surface dataset + + integer :: fates_numpft ! Number of PFTs tracked in FATES if (use_fates) then ! Self explanatory, read the fates parameter file call FatesReadParameters() - ! Identify the number of PFTs by evaluating a pft array - ! Using wood density as that is not expected to be deprecated any time soon + fates_numpft = size(prt_params%wood_density,dim=1) + + if(hlm_use_sp==itrue)then + + ! For an SP run we also just use the primary patches + ! to hold all PFTs. So create the same number of + ! patches as the number of PFTs + + maxpatch_primary = fates_numpft + maxpatch_secondary = 0 + maxpatch_total = fates_numpft + + ! If this is an SP run, we actually need enough patches on the + ! CLM/ELM side of the code to hold the LAI data. This + ! number may be larger than what fates requires. Of course + ! we may have multiple PFTs in the surface datafile mapping + ! to FATES. The surf_numpft includes the bare ground. + ! maxpatch_total does not include the bare ground (so add 1) + + fates_maxPatchesPerSite = max(surf_numpft+surf_numcft,maxpatch_total+1) + + else + + ! If we are using fixed biogeography or no-comp then we + ! can also apply those constraints to maxpatch_primary and secondary + ! and that value will match fates_maxPatchesPerSite + + if(hlm_use_nocomp==itrue) then + + maxpatch_primary = max(maxpatch_primary,fates_numpft) + maxpatch_total = maxpatch_primary + maxpatch_secondary + !if(maxpatch_primary nearzero )) then + n_uptake_mode = prescribed_n_uptake + else + n_uptake_mode = coupled_n_uptake + end if + + if (any(abs(EDPftvarcon_inst%prescribed_puptake(:)) > nearzero )) then + p_uptake_mode = prescribed_p_uptake + else + p_uptake_mode = coupled_p_uptake + end if + if (hlm_parteh_mode .eq. prt_cnp_flex_allom_hyp ) then - if(fates_np_comp_scaling.eq.cohort_np_comp_scaling) then + + if((p_uptake_mode==coupled_p_uptake) .or. (n_uptake_mode==coupled_n_uptake))then max_comp_per_site = fates_maxElementsPerSite - elseif(fates_np_comp_scaling.eq.pft_np_comp_scaling) then - max_comp_per_site = numpft + fates_np_comp_scaling = coupled_np_comp_scaling else - write(fates_log(), *) 'An unknown nutrient competitor scaling method was chosen?' - call endrun(msg=errMsg(sourcefile, __LINE__)) + max_comp_per_site = 1 + fates_np_comp_scaling = trivial_np_comp_scaling end if + else max_comp_per_site = 1 + fates_np_comp_scaling = trivial_np_comp_scaling end if ! calculate the bin edges for radiative transfer calculations @@ -826,11 +904,11 @@ subroutine SetFatesGlobalElements(use_fates) ! Identify number of size and age class bins for history output ! assume these arrays are 1-indexed - nlevsclass = size(ED_val_history_sizeclass_bin_edges,dim=1) nlevage = size(ED_val_history_ageclass_bin_edges,dim=1) nlevheight = size(ED_val_history_height_bin_edges,dim=1) nlevcoage = size(ED_val_history_coageclass_bin_edges,dim=1) - + nlevdamage = size(ED_val_history_damage_bin_edges, dim=1) + ! do some checks on the size, age, and height bin arrays to make sure they make sense: ! make sure that all start at zero, and that both are monotonically increasing if ( ED_val_history_sizeclass_bin_edges(1) .ne. 0._r8 ) then @@ -869,8 +947,18 @@ subroutine SetFatesGlobalElements(use_fates) call endrun(msg=errMsg(sourcefile, __LINE__)) end if end do - - ! Initialize Hydro globals + + ! Set the fates dispersal kernel mode if there are any seed dispersal parameters set. + ! The validation of the parameter values is check in FatesCheckParams prior to this check. + ! This is currently hard coded, but could be added as a fates parameter file option, + ! particularly one that is pft dependent. + if(any(EDPftvarcon_inst%seed_dispersal_pdf_scale .lt. fates_check_param_set)) then + fates_dispersal_kernel_mode = fates_dispersal_kernel_exponential + ! fates_dispersal_kernel_mode = fates_dispersal_kernel_exppower + ! fates_dispersal_kernel_mode = fates_dispersal_kernel_logsech + end if + + ! Initialize Hydro globals ! (like water retention functions) ! this needs to know the number of PFTs, which is ! determined in that call @@ -889,6 +977,9 @@ subroutine SetFatesGlobalElements(use_fates) ! These will not be used if use_ed or use_fates is false call fates_history_maps() + + + else @@ -902,9 +993,7 @@ subroutine SetFatesGlobalElements(use_fates) end if - - - end subroutine SetFatesGlobalElements + end subroutine SetFatesGlobalElements2 ! ====================================================================== @@ -919,10 +1008,31 @@ subroutine InitTimeAveragingGlobals() 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) + allocate(ema_lpa) ! note that this parameter has units of days 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) + allocate(ema_longterm) ! note that this parameter has units of years + call ema_longterm%define(photo_temp_acclim_thome_time*days_per_year*sec_per_day, & + hlm_stepsize,moving_ema_window) + + !allocate(ema_60day) + !call ema_60day%define(prt_params%fnrt_adapt_tscl*sec_per_day,sec_per_day,moving_ema_window) + !class(rmean_arr_type), pointer :: ema_fnrt_tscale(:) + !rmean_arr_type + + return end subroutine InitTimeAveragingGlobals @@ -978,9 +1088,9 @@ end subroutine InitPARTEHGlobals subroutine fates_history_maps - use EDTypesMod, only : NFSC - use EDTypesMod, only : nclmax - use EDTypesMod, only : nlevleaf + use FatesLitterMod, only : NFSC + use EDParamsMod, only : nclmax + use EDParamsMod, only : nlevleaf 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 @@ -1000,6 +1110,7 @@ subroutine fates_history_maps integer :: icwd integer :: ifuel integer :: ican + integer :: icdam integer :: ileaf integer :: iage integer :: iheight @@ -1043,14 +1154,21 @@ subroutine fates_history_maps allocate( fates_hdim_cwdmap_levelcwd(num_elements*ncwd)) allocate( fates_hdim_agemap_levelage(num_elements*nlevage)) - + allocate( fates_hdim_levdamage(1:nlevdamage )) + allocate( fates_hdim_scmap_levcdsc(nlevsclass*nlevdamage)) + allocate( fates_hdim_cdmap_levcdsc(nlevsclass*nlevdamage)) + allocate( fates_hdim_scmap_levcdpf(nlevsclass*nlevdamage * numpft)) + allocate( fates_hdim_cdmap_levcdpf(nlevsclass*nlevdamage * numpft)) + allocate( fates_hdim_pftmap_levcdpf(nlevsclass*nlevdamage * numpft)) + ! Fill the IO array of plant size classes fates_hdim_levsclass(:) = ED_val_history_sizeclass_bin_edges(:) fates_hdim_levage(:) = ED_val_history_ageclass_bin_edges(:) fates_hdim_levheight(:) = ED_val_history_height_bin_edges(:) fates_hdim_levcoage(:) = ED_val_history_coageclass_bin_edges(:) fates_hdim_levleaf(:) = dlower_vai(:) - + fates_hdim_levdamage(:) = ED_val_history_damage_bin_edges(:) + ! make pft array do ipft=1,numpft fates_hdim_levpft(ipft) = ipft @@ -1141,6 +1259,27 @@ subroutine fates_history_maps end do end do + i=0 + do icdam=1,nlevdamage + do isc=1,nlevsclass + i=i+1 + fates_hdim_scmap_levcdsc(i) = isc + fates_hdim_cdmap_levcdsc(i) = icdam + end do + end do + + i=0 + do ipft=1,numpft + do icdam=1,nlevdamage + do isc=1,nlevsclass + i=i+1 + fates_hdim_scmap_levcdpf(i) = isc + fates_hdim_cdmap_levcdpf(i) = icdam + fates_hdim_pftmap_levcdpf(i) = ipft + end do + end do + end do + i=0 do ipft=1,numpft do ican=1,nclmax @@ -1275,13 +1414,15 @@ subroutine set_fates_ctrlparms(tag,ival,rval,cval) hlm_masterproc = unset_int hlm_ipedof = unset_int hlm_nu_com = 'unset' + hlm_decomp = 'unset' hlm_nitrogen_spec = unset_int + hlm_use_tree_damage = unset_int hlm_phosphorus_spec = unset_int - hlm_max_patch_per_site = unset_int hlm_use_ch4 = unset_int hlm_use_vertsoilc = unset_int hlm_parteh_mode = unset_int hlm_spitfire_mode = unset_int + hlm_seeddisp_cadence = unset_int hlm_sf_nofire_def = unset_int hlm_sf_scalar_lightning_def = unset_int hlm_sf_successful_ignitions_def = unset_int @@ -1302,36 +1443,28 @@ subroutine set_fates_ctrlparms(tag,ival,rval,cval) case('check_allset') if(hlm_numSWb .eq. unset_int) then - if (fates_global_verbose()) then - write(fates_log(), *) 'FATES dimension/parameter unset: num_sw_rad_bbands' - end if + write(fates_log(), *) 'FATES dimension/parameter unset: num_sw_rad_bbands' call endrun(msg=errMsg(sourcefile, __LINE__)) end if if(hlm_masterproc .eq. unset_int) then - if (fates_global_verbose()) then - write(fates_log(), *) 'FATES parameter unset: hlm_masterproc' - end if + write(fates_log(), *) 'FATES parameter unset: hlm_masterproc' call endrun(msg=errMsg(sourcefile, __LINE__)) end if if(hlm_numSWb > maxSWb) then - if (fates_global_verbose()) then - write(fates_log(), *) 'FATES sets a maximum number of shortwave bands' - write(fates_log(), *) 'for some scratch-space, maxSWb' - write(fates_log(), *) 'it defaults to 2, but can be increased as needed' - write(fates_log(), *) 'your driver or host model is intending to drive' - write(fates_log(), *) 'FATES with:',hlm_numSWb,' bands.' - write(fates_log(), *) 'please increase maxSWb in EDTypes to match' - write(fates_log(), *) 'or exceed this value' - end if + write(fates_log(), *) 'FATES sets a maximum number of shortwave bands' + write(fates_log(), *) 'for some scratch-space, maxSWb' + write(fates_log(), *) 'it defaults to 2, but can be increased as needed' + write(fates_log(), *) 'your driver or host model is intending to drive' + write(fates_log(), *) 'FATES with:',hlm_numSWb,' bands.' + write(fates_log(), *) 'please increase maxSWb in EDTypes to match' + write(fates_log(), *) 'or exceed this value' call endrun(msg=errMsg(sourcefile, __LINE__)) end if if ( .not.((hlm_use_planthydro.eq.1).or.(hlm_use_planthydro.eq.0)) ) then - if (fates_global_verbose()) then - write(fates_log(), *) 'The FATES namelist planthydro flag must be 0 or 1, exiting' - end if + write(fates_log(), *) 'The FATES namelist planthydro flag must be 0 or 1, exiting' call endrun(msg=errMsg(sourcefile, __LINE__)) elseif (hlm_use_planthydro.eq.1 ) then write(fates_log(), *) '!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!' @@ -1344,105 +1477,77 @@ subroutine set_fates_ctrlparms(tag,ival,rval,cval) end if if ( (hlm_use_lu_harvest .lt. 0).or.(hlm_use_lu_harvest .gt. 1) ) then - if (fates_global_verbose()) then - write(fates_log(), *) 'The FATES lu_harvest flag must be 0 or 1, exiting' - end if + write(fates_log(), *) 'The FATES lu_harvest flag must be 0 or 1, exiting' call endrun(msg=errMsg(sourcefile, __LINE__)) end if if ( (hlm_num_lu_harvest_cats .lt. 0) ) then - if (fates_global_verbose()) then - write(fates_log(), *) 'The FATES number of hlm harvest cats must be >= 0, exiting' - end if + write(fates_log(), *) 'The FATES number of hlm harvest cats must be >= 0, exiting' call endrun(msg=errMsg(sourcefile, __LINE__)) end if if ( .not.((hlm_use_logging .eq.1).or.(hlm_use_logging.eq.0)) ) then - if (fates_global_verbose()) then - write(fates_log(), *) 'The FATES namelist use_logging flag must be 0 or 1, exiting' - end if + write(fates_log(), *) 'The FATES namelist use_logging flag must be 0 or 1, exiting' call endrun(msg=errMsg(sourcefile, __LINE__)) end if if ( ( ANY(EDPftvarcon_inst%mort_ip_age_senescence < fates_check_param_set )) .and. & (hlm_use_cohort_age_tracking .eq.0 ) ) then - write(fates_log(),*) 'Age dependent mortality cannot be on if' write(fates_log(),*) 'cohort age tracking is off.' - write(fates_log(),*) 'Set hlm_use_cohort_age_tracking = .true.' + write(fates_log(),*) 'Set use_fates_cohort_age_tracking = .true.' write(fates_log(),*) 'in FATES namelist options' write(fates_log(),*) 'Aborting' call endrun(msg=errMsg(sourcefile, __LINE__)) end if - if ( .not.((hlm_use_ed_st3.eq.1).or.(hlm_use_ed_st3.eq.0)) ) then - if (fates_global_verbose()) then - write(fates_log(), *) 'The FATES namelist stand structure flag must be 0 or 1, exiting' - end if + write(fates_log(), *) 'The FATES namelist stand structure flag must be 0 or 1, exiting' call endrun(msg=errMsg(sourcefile, __LINE__)) end if if ( .not.((hlm_use_ed_prescribed_phys.eq.1).or.(hlm_use_ed_prescribed_phys.eq.0)) ) then - if (fates_global_verbose()) then - write(fates_log(), *) 'The FATES namelist prescribed physiology flag must be 0 or 1, exiting' - end if + write(fates_log(), *) 'The FATES namelist prescribed physiology flag must be 0 or 1, exiting' call endrun(msg=errMsg(sourcefile, __LINE__)) end if if ( hlm_use_ed_prescribed_phys.eq.1 .and. hlm_use_ed_st3.eq.1 ) then - if (fates_global_verbose()) then - write(fates_log(), *) 'FATES ST3 and prescribed physiology cannot both be turned on.' - write(fates_log(), *) 'Review the namelist entries, exiting' - end if + write(fates_log(), *) 'FATES ST3 and prescribed physiology cannot both be turned on.' + write(fates_log(), *) 'Review the namelist entries, exiting' call endrun(msg=errMsg(sourcefile, __LINE__)) end if if ( hlm_use_inventory_init.eq.1 .and. hlm_use_cohort_age_tracking .eq.1) then - if (fates_global_verbose()) then - write(fates_log(), *) 'Fates inventory init cannot be used with age dependent mortality' - write(fates_log(), *) 'Set hlm_use_cohort_age_tracking to 0 or turn off inventory init' - end if + write(fates_log(), *) 'Fates inventory init cannot be used with age dependent mortality' + write(fates_log(), *) 'Set use_fates_cohort_age_tracking to 0 or turn off inventory init' call endrun(msg=errMsg(sourcefile, __LINE__)) end if - - if ( .not.((hlm_use_inventory_init.eq.1).or.(hlm_use_inventory_init.eq.0)) ) then - if (fates_global_verbose()) then - write(fates_log(), *) 'The FATES NL inventory flag must be 0 or 1, exiting' - end if + write(fates_log(), *) 'The FATES NL inventory flag must be 0 or 1, exiting' call endrun(msg=errMsg(sourcefile, __LINE__)) end if if(trim(hlm_inventory_ctrl_file) .eq. 'unset') then - if (fates_global_verbose()) then - write(fates_log(),*) 'namelist entry for fates inventory control file is unset, exiting' - end if + write(fates_log(),*) 'namelist entry for fates inventory control file is unset, exiting' call endrun(msg=errMsg(sourcefile, __LINE__)) end if if(hlm_ivis .ne. ivis) then - if (fates_global_verbose()) then - write(fates_log(), *) 'FATES assumption about the index of visible shortwave' - write(fates_log(), *) 'radiation is different from the HLM, exiting' - end if + write(fates_log(), *) 'FATES assumption about the index of visible shortwave' + write(fates_log(), *) 'radiation is different from the HLM, exiting' call endrun(msg=errMsg(sourcefile, __LINE__)) end if if(hlm_inir .ne. inir) then - if (fates_global_verbose()) then - write(fates_log(), *) 'FATES assumption about the index of NIR shortwave' - write(fates_log(), *) 'radiation is different from the HLM, exiting' - end if + write(fates_log(), *) 'FATES assumption about the index of NIR shortwave' + write(fates_log(), *) 'radiation is different from the HLM, exiting' call endrun(msg=errMsg(sourcefile, __LINE__)) end if if(hlm_is_restart .eq. unset_int) then - if (fates_global_verbose()) then - write(fates_log(), *) 'FATES parameter unset: hlm_is_restart, exiting' - end if + write(fates_log(), *) 'FATES parameter unset: hlm_is_restart, exiting' call endrun(msg=errMsg(sourcefile, __LINE__)) end if @@ -1454,112 +1559,105 @@ subroutine set_fates_ctrlparms(tag,ival,rval,cval) end if if(trim(hlm_name) .eq. 'unset') then - if (fates_global_verbose()) then - write(fates_log(),*) 'FATES dimension/parameter unset: hlm_name, exiting' - end if + write(fates_log(),*) 'FATES dimension/parameter unset: hlm_name, exiting' call endrun(msg=errMsg(sourcefile, __LINE__)) end if - if(trim(hlm_nu_com) .eq. 'unset') then + if(trim(hlm_decomp) .eq. 'unset') then if (fates_global_verbose()) then - write(fates_log(),*) 'FATES dimension/parameter unset: hlm_nu_com, exiting' + write(fates_log(),*) 'FATES dimension/parameter unset: hlm_decomp, exiting' + write(fates_log(),*) 'valid: MIMICS, CENTURY, CTC' end if call endrun(msg=errMsg(sourcefile, __LINE__)) end if - - if(hlm_nitrogen_spec .eq. unset_int) then + if( .not. ((trim(hlm_decomp) .eq. 'MIMICS') .or. & + (trim(hlm_decomp) .eq. 'CENTURY') .or. & + (trim(hlm_decomp) .eq. 'CTC') .or. & + (trim(hlm_decomp) .eq. 'NONE')) ) then if (fates_global_verbose()) then - write(fates_log(),*) 'FATES parameters unset: hlm_nitrogen_spec, exiting' + write(fates_log(),*) 'FATES dimension/parameter unset: hlm_decomp, exiting' + write(fates_log(),*) 'valid: NONE, MIMICS, CENTURY, CTC, yours: ',trim(hlm_decomp) end if call endrun(msg=errMsg(sourcefile, __LINE__)) end if - if(hlm_phosphorus_spec .eq. unset_int) then - if (fates_global_verbose()) then - write(fates_log(),*) 'FATES parameters unset: hlm_phosphorus_spec, exiting' - end if + if(trim(hlm_nu_com) .eq. 'unset') then + write(fates_log(),*) 'FATES dimension/parameter unset: hlm_nu_com, exiting' call endrun(msg=errMsg(sourcefile, __LINE__)) end if - if( abs(hlm_hio_ignore_val-unset_double)<1e-10 ) then - if (fates_global_verbose()) then - write(fates_log(),*) 'FATES dimension/parameter unset: hio_ignore' - end if + if(hlm_use_tree_damage .eq. unset_int) then + write(fates_log(),*) 'FATES dimension/parameter unset: hlm_use_tree_damage, exiting' call endrun(msg=errMsg(sourcefile, __LINE__)) + else + if((hlm_use_tree_damage .eq. itrue) .and. & + (hlm_parteh_mode .eq. prt_cnp_flex_allom_hyp))then + write(fates_log(),*) 'FATES tree damage (use_fates_tree_damage = .true.) is not' + write(fates_log(),*) '(yet) compatible with CNP allocation (fates_parteh_mode = 2)' + call endrun(msg=errMsg(sourcefile, __LINE__)) end if - if(hlm_ipedof .eq. unset_int) then - if (fates_global_verbose()) then - write(fates_log(), *) 'index for the HLMs pedotransfer function unset: hlm_ipedof, exiting' - end if + + end if + + if(hlm_nitrogen_spec .eq. unset_int) then + write(fates_log(),*) 'FATES parameters unset: hlm_nitrogen_spec, exiting' call endrun(msg=errMsg(sourcefile, __LINE__)) end if + if(hlm_phosphorus_spec .eq. unset_int) then + write(fates_log(),*) 'FATES parameters unset: hlm_phosphorus_spec, exiting' + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if - if(hlm_max_patch_per_site .eq. unset_int ) then - if (fates_global_verbose()) then - write(fates_log(), *) 'the number of patch-space per site unset: hlm_max_patch_per_site, exiting' - end if + if( abs(hlm_hio_ignore_val-unset_double)<1e-10 ) then + write(fates_log(),*) 'FATES dimension/parameter unset: hio_ignore' call endrun(msg=errMsg(sourcefile, __LINE__)) - elseif(hlm_max_patch_per_site < maxPatchesPerSite ) then - if (fates_global_verbose()) then - write(fates_log(), *) 'FATES is trying to allocate space for more patches per site, than the HLM has space for.' - write(fates_log(), *) 'hlm_max_patch_per_site (HLM side): ', hlm_max_patch_per_site - write(fates_log(), *) 'maxPatchesPerSite (FATES side): ', maxPatchesPerSite - write(fates_log(), *) - end if + end if + + if(hlm_ipedof .eq. unset_int) then + write(fates_log(), *) 'index for the HLMs pedotransfer function unset: hlm_ipedof, exiting' call endrun(msg=errMsg(sourcefile, __LINE__)) end if if(hlm_parteh_mode .eq. unset_int) then - if (fates_global_verbose()) then - write(fates_log(), *) 'switch deciding which plant reactive transport model to use is unset, hlm_parteh_mode, exiting' - end if + write(fates_log(), *) 'switch deciding which plant reactive transport model to use is unset, hlm_parteh_mode, exiting' + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + + if(hlm_seeddisp_cadence .eq. unset_int) then + write(fates_log(), *) 'switch defining seed dispersal cadence is unset, hlm_seeddisp_cadence, exiting' call endrun(msg=errMsg(sourcefile, __LINE__)) end if if(hlm_use_ch4 .eq. unset_int) then - if (fates_global_verbose()) then - write(fates_log(), *) 'switch for the HLMs CH4 module unset: hlm_use_ch4, exiting' - end if + write(fates_log(), *) 'switch for the HLMs CH4 module unset: hlm_use_ch4, exiting' call endrun(msg=errMsg(sourcefile, __LINE__)) end if - + if(hlm_use_vertsoilc .eq. unset_int) then - if (fates_global_verbose()) then - write(fates_log(), *) 'switch for the HLMs soil carbon discretization unset: hlm_use_vertsoilc, exiting' - end if + write(fates_log(), *) 'switch for the HLMs soil carbon discretization unset: hlm_use_vertsoilc, exiting' call endrun(msg=errMsg(sourcefile, __LINE__)) end if if(hlm_spitfire_mode .eq. unset_int) then - if (fates_global_verbose()) then - write(fates_log(), *) 'switch for SPITFIRE unset: hlm_spitfire_mode, exiting' - end if + write(fates_log(), *) 'switch for SPITFIRE unset: hlm_spitfire_mode, exiting' call endrun(msg=errMsg(sourcefile, __LINE__)) end if if(hlm_sf_nofire_def .eq. unset_int) then - if (fates_global_verbose()) then - write(fates_log(), *) 'definition of no-fire mode unset: hlm_sf_nofire_def, exiting' - end if + write(fates_log(), *) 'definition of no-fire mode unset: hlm_sf_nofire_def, exiting' call endrun(msg=errMsg(sourcefile, __LINE__)) end if if(hlm_sf_scalar_lightning_def .eq. unset_int) then - if (fates_global_verbose()) then - write(fates_log(), *) 'definition of scalar lightning mode unset: hlm_sf_scalltng_def, exiting' - end if + write(fates_log(), *) 'definition of scalar lightning mode unset: hlm_sf_scalltng_def, exiting' call endrun(msg=errMsg(sourcefile, __LINE__)) end if if(hlm_sf_successful_ignitions_def .eq. unset_int) then - if (fates_global_verbose()) then - write(fates_log(), *) 'definition of successful ignition mode unset: hlm_sf_successful, exiting' - end if + write(fates_log(), *) 'definition of successful ignition mode unset: hlm_sf_successful, exiting' call endrun(msg=errMsg(sourcefile, __LINE__)) end if if(hlm_sf_anthro_ignitions_def .eq. unset_int) then - if (fates_global_verbose()) then - write(fates_log(), *) 'definition of anthro-ignition mode unset: hlm_sf_anthig_def, exiting' - end if + write(fates_log(), *) 'definition of anthro-ignition mode unset: hlm_sf_anthig_def, exiting' call endrun(msg=errMsg(sourcefile, __LINE__)) end if @@ -1573,32 +1671,25 @@ subroutine set_fates_ctrlparms(tag,ival,rval,cval) end if end if - if(hlm_use_fixed_biogeog.eq.unset_int) then if(fates_global_verbose()) then - write(fates_log(), *) 'switch for fixed biogeog unset: him_use_fixed_biogeog, exiting' + write(fates_log(), *) 'switch for fixed biogeog unset: hlm_use_fixed_biogeog, exiting' end if call endrun(msg=errMsg(sourcefile, __LINE__)) end if if(hlm_use_nocomp.eq.unset_int) then - if(fates_global_verbose()) then - write(fates_log(), *) 'switch for no competition mode. ' - end if - call endrun(msg=errMsg(sourcefile, __LINE__)) + write(fates_log(), *) 'switch for no competition mode. ' + call endrun(msg=errMsg(sourcefile, __LINE__)) end if if(hlm_use_sp.eq.unset_int) then - if(fates_global_verbose()) then - write(fates_log(), *) 'switch for SP mode. ' - end if - call endrun(msg=errMsg(sourcefile, __LINE__)) + write(fates_log(), *) 'switch for SP mode. ' + call endrun(msg=errMsg(sourcefile, __LINE__)) end if if(hlm_use_cohort_age_tracking .eq. unset_int) then - if (fates_global_verbose()) then - write(fates_log(), *) 'switch for cohort_age_tracking unset: hlm_use_cohort_age_tracking, exiting' - end if + write(fates_log(), *) 'switch for cohort_age_tracking unset: hlm_use_cohort_age_tracking, exiting' call endrun(msg=errMsg(sourcefile, __LINE__)) end if @@ -1607,7 +1698,6 @@ subroutine set_fates_ctrlparms(tag,ival,rval,cval) call endrun(msg=errMsg(sourcefile, __LINE__)) end if - if(hlm_use_sp.eq.itrue.and.hlm_use_fixed_biogeog.eq.ifalse)then write(fates_log(), *) 'SP cannot be on if fixed biogeog mode is off. Exiting. ' call endrun(msg=errMsg(sourcefile, __LINE__)) @@ -1616,7 +1706,6 @@ subroutine set_fates_ctrlparms(tag,ival,rval,cval) if (fates_global_verbose()) then write(fates_log(), *) 'Checked. All control parameters sent to FATES.' end if - case default @@ -1665,6 +1754,12 @@ subroutine set_fates_ctrlparms(tag,ival,rval,cval) write(fates_log(),*) 'Transfering hlm_ipedof = ',ival,' to FATES' end if + case('use_tree_damage') + hlm_use_tree_damage = ival + if (fates_global_verbose()) then + write(fates_log(),*) 'Transfering hlm_use_tree_damage = ',ival,' to FATES' + end if + case('nitrogen_spec') hlm_nitrogen_spec = ival if (fates_global_verbose()) then @@ -1677,13 +1772,6 @@ subroutine set_fates_ctrlparms(tag,ival,rval,cval) write(fates_log(),*) 'Transfering hlm_phosphorus_spec = ',ival,' to FATES' end if - - case('max_patch_per_site') - hlm_max_patch_per_site = ival - if (fates_global_verbose()) then - write(fates_log(),*) 'Transfering hlm_max_patch_per_site = ',ival,' to FATES' - end if - case('use_ch4') hlm_use_ch4 = ival if (fates_global_verbose()) then @@ -1702,6 +1790,12 @@ subroutine set_fates_ctrlparms(tag,ival,rval,cval) write(fates_log(),*) 'Transfering hlm_parteh_mode= ',ival,' to FATES' end if + case('seeddisp_cadence') + hlm_seeddisp_cadence = ival + if (fates_global_verbose()) then + write(fates_log(),*) 'Transfering hlm_seeddisp_cadence= ',ival,' to FATES' + end if + case('spitfire_mode') hlm_spitfire_mode = ival if (fates_global_verbose()) then @@ -1746,10 +1840,10 @@ subroutine set_fates_ctrlparms(tag,ival,rval,cval) end if case('use_sp') - hlm_use_sp = ival - if (fates_global_verbose()) then - write(fates_log(),*) 'Transfering hlm_use_sp= ',ival,' to FATES' - end if + hlm_use_sp = ival + if (fates_global_verbose()) then + write(fates_log(),*) 'Transfering hlm_use_sp= ',ival,' to FATES' + end if case('use_planthydro') hlm_use_planthydro = ival @@ -1800,11 +1894,8 @@ subroutine set_fates_ctrlparms(tag,ival,rval,cval) end if case default - if (fates_global_verbose()) then - write(fates_log(), *) 'tag not recognized:',trim(tag) - call endrun(msg=errMsg(sourcefile, __LINE__)) - end if - ! end_run + write(fates_log(), *) 'fates NL tag not recognized:',trim(tag) + !! call endrun(msg=errMsg(sourcefile, __LINE__)) end select end if @@ -1817,10 +1908,8 @@ subroutine set_fates_ctrlparms(tag,ival,rval,cval) write(fates_log(),*) 'Transfering hio_ignore_val = ',rval,' to FATES' end if case default - if (fates_global_verbose()) then - write(fates_log(),*) 'tag not recognized:',trim(tag) - end if - ! end_run + write(fates_log(),*) 'fates NL tag not recognized:',trim(tag) + !! call endrun(msg=errMsg(sourcefile, __LINE__)) end select end if @@ -1839,6 +1928,12 @@ subroutine set_fates_ctrlparms(tag,ival,rval,cval) write(fates_log(),*) 'Transfering the nutrient competition name = ',trim(cval) end if + case('decomp_method') + hlm_decomp = trim(cval) + if (fates_global_verbose()) then + write(fates_log(),*) 'Transfering the decomp method name = ',trim(cval) + end if + case('inventory_ctrl_file') hlm_inventory_ctrl_file = trim(cval) if (fates_global_verbose()) then @@ -1846,10 +1941,8 @@ subroutine set_fates_ctrlparms(tag,ival,rval,cval) end if case default - if (fates_global_verbose()) then - write(fates_log(),*) 'tag not recognized:',trim(tag) - end if - ! end_run + write(fates_log(),*) 'fates NL tag not recognized:',trim(tag) + !! call endrun(msg=errMsg(sourcefile, __LINE__)) end select end if @@ -1871,8 +1964,8 @@ subroutine FatesReportParameters(masterproc) call FatesReportPFTParams(masterproc) call FatesReportParams(masterproc) - call FatesCheckParams(masterproc) ! Check general fates parameters call PRTDerivedParams() ! Update PARTEH derived constants + call FatesCheckParams(masterproc) ! Check general fates parameters call PRTCheckParams(masterproc) ! Check PARTEH parameters call SpitFireCheckParams(masterproc) @@ -1892,31 +1985,397 @@ subroutine UpdateFatesRMeansTStep(sites,bc_in) type(ed_site_type), intent(inout) :: sites(:) type(bc_in_type), intent(in) :: bc_in(:) - type(ed_patch_type), pointer :: cpatch - type(ed_cohort_type), pointer :: ccohort - integer :: s, ifp, io_si + type(fates_patch_type), pointer :: cpatch + type(fates_cohort_type), pointer :: ccohort + integer :: s, ifp, io_si, pft + real(r8) :: site_npp ! Site level NPP gC/m2/year + 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) + real(r8), parameter :: ema_npp_tscale = 480._r8 ! 10 day (10*48 steps) do s = 1,size(sites,dim=1) ifp=0 + site_npp = 0._r8 cpatch => sites(s)%oldest_patch do while(associated(cpatch)) + if (cpatch%patchno .ne. 0) then 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)) + call cpatch%tveg_longterm%UpdateRMean(bc_in(s)%t_veg_pa(ifp)) + + ! Update the seedling layer par running means + if ( regeneration_model == TRS_regeneration ) then - ! (Keeping as an example) - !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 + ! 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 + + ccohort => cpatch%tallest + do while (associated(ccohort)) + ! call ccohort%tveg_lpa%UpdateRMean(bc_in(s)%t_veg_pa(ifp)) + + ! [kgC/plant/yr] -> [gC/m2/s] + site_npp = site_npp + ccohort%npp_acc_hold * ccohort%n*area_inv * & + g_per_kg * hlm_days_per_year / sec_per_day + + ccohort => ccohort%shorter + end do + + end if + + cpatch => cpatch%younger + enddo + + ! Smoothed [gc/m2/yr] + if(sites(s)%ema_npp<-9000._r8)then + sites(s)%ema_npp = site_npp + else + sites(s)%ema_npp = (1._r8-1._r8/ema_npp_tscale)*sites(s)%ema_npp + (1._r8/ema_npp_tscale)*site_npp + end if + + 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(fates_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) :: 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 + + ! 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 + 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 in the current canopy layer + if (iv .ne. 0) then + 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)) + cl_area = cl_area + cpatch%canopy_area_profile(cl,ipft,1) + end if end do - return - end subroutine UpdateFatesRMeansTStep + ! 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 + 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 + ! 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-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 = cl_par + end if + + end do + + return + +end subroutine SeedlingParPatch + +! ====================================================================================== + +subroutine DetermineGridCellNeighbors(neighbors,seeds,numg) + + ! This subroutine utilizes information from the decomposition and domain types to determine + ! the set of grid cell neighbors within some maximum distance. It records the distance for each + ! neighbor for later use. This should be called after decompInit_lnd and surf_get_grid + ! as it relies on ldecomp and ldomain information. + + use decompMod , only : procinfo + use domainMod , only : ldomain + use spmdMod , only : MPI_REAL8, MPI_INTEGER, mpicom, npes, masterproc, iam + use perf_mod , only : t_startf, t_stopf + use FatesDispersalMod , only : neighborhood_type, neighbor_type, ProbabilityDensity, dispersal_type + use FatesUtilsMod , only : GetNeighborDistance + use FatesConstantsMod , only : fates_unset_int + use EDPftvarcon , only : EDPftvarcon_inst + + ! Arguments + type(neighborhood_type), intent(inout), pointer :: neighbors(:) ! land gridcell neighbor data structure + type(dispersal_type), intent(inout) :: seeds ! land gridcell neighbor data structure + integer , intent(in) :: numg ! number of land gridcells + + ! Local variables + type (neighbor_type), pointer :: current_neighbor + type (neighbor_type), pointer :: another_neighbor + + integer :: i, gi, gj, ni ! indices + integer :: ier, mpierr ! error status + integer :: ipft ! pft index + + integer, allocatable :: ncells_array(:), begg_array(:) ! number of cells and starting global grid cell index per process + real(r8), allocatable :: gclat(:), gclon(:) ! local array holding gridcell lat and lon + + real(r8) :: g2g_dist ! grid cell distance (m) + real(r8) :: pdf ! probability density function output + + if(debug .and. hlm_is_restart .eq. itrue) write(fates_log(),*) 'gridcell initialization during restart' + + if(debug) write(fates_log(),*)'DGCN: npes, numg: ', npes, numg + + ! Allocate and initialize array neighbor type + allocate(neighbors(numg), stat=ier) + neighbors(:)%neighbor_count = 0 + + ! Allocate and initialize local lat and lon arrays + allocate(gclat(numg), stat=ier) + if(debug) write(fates_log(),*)'DGCN: gclat alloc: ', ier + + allocate(gclon(numg), stat=ier) + if(debug) write(fates_log(),*)'DGCN: gclon alloc: ', ier + + gclon(:) = nan + gclat(:) = nan + + ! Allocate and initialize MPI count and displacement values + allocate(ncells_array(0:npes-1), stat=ier) + if(debug) write(fates_log(),*)'DGCN: ncells alloc: ', ier + + allocate(begg_array(0:npes-1), stat=ier) + if(debug) write(fates_log(),*)'DGCN: begg alloc: ', ier + + ncells_array(:) = fates_unset_int + begg_array(:) = fates_unset_int + + call t_startf('fates-seed-init-allgather') + + if(debug) write(fates_log(),*)'DGCN: procinfo%begg: ', procinfo%begg + if(debug) write(fates_log(),*)'DGCN: procinfo%ncells: ', procinfo%ncells + + ! Gather the sizes of the ldomain that each mpi rank is passing + call MPI_Allgather(procinfo%ncells,1,MPI_INTEGER,ncells_array,1,MPI_INTEGER,mpicom,mpierr) + if(debug) write(fates_log(),*)'DGCN: ncells mpierr: ', mpierr + + ! Gather the starting gridcell index for each ldomain + call MPI_Allgather(procinfo%begg,1,MPI_INTEGER,begg_array,1,MPI_INTEGER,mpicom,mpierr) + if(debug) write(fates_log(),*)'DGCN: begg mpierr: ', mpierr + + ! reduce the begg_array displacements by one as MPI collectives expect zero indexed arrays + begg_array = begg_array - 1 + + if(debug) write(fates_log(),*)'DGCN: ncells_array: ' , ncells_array + if(debug) write(fates_log(),*)'DGCN: begg_array: ' , begg_array + + ! Gather the domain information together into the neighbor type + ! Note that MPI_Allgatherv is only gathering a subset of ldomain + if(debug) write(fates_log(),*)'DGCN: gathering latc' + call MPI_Allgatherv(ldomain%latc,procinfo%ncells,MPI_REAL8,gclat,ncells_array,begg_array,MPI_REAL8,mpicom,mpierr) + + if(debug) write(fates_log(),*)'DGCN: gathering lonc' + call MPI_Allgatherv(ldomain%lonc,procinfo%ncells,MPI_REAL8,gclon,ncells_array,begg_array,MPI_REAL8,mpicom,mpierr) + + if (debug .and. iam .eq. 0) then + write(fates_log(),*)'DGCN: sum(gclat):, sum(gclon): ', sum(gclat), sum(gclon) + end if + + ! Save number of cells and begging index arrays to dispersal type + if(debug) write(fates_log(),*)'DGCN: save to seeds type' + if(debug) write(fates_log(),*)'DGCN: seeds ncells alloc: ', allocated(seeds%ncells_array) + if(debug) write(fates_log(),*)'DGCN: seeds begg alloc: ', allocated(seeds%begg_array) + seeds%ncells_array = ncells_array + seeds%begg_array = begg_array + + if (debug .and. iam .eq. 0) then + write(fates_log(),*)'DGCN: seeds%ncells_array: ', seeds%ncells_array + write(fates_log(),*)'DGCN: seeds%begg_array: ', seeds%begg_array + end if + + call t_stopf('fates-seed-init-allgather') + + call t_startf('fates-seed-init-decomp') + + if(debug) write(fates_log(), *) 'DGCN: maxdist: ', EDPftvarcon_inst%seed_dispersal_max_dist + + ! Iterate through the grid cell indices and determine if any neighboring cells are in range + gc_loop: do gi = 1,numg-1 + + ! Seach forward through all indices for neighbors to current grid cell index + neighbor_search: do gj = gi+1,numg + + ! Determine distance to old grid cells to the current one + g2g_dist = GetNeighborDistance(gi,gj,gclat,gclon) + + if(debug) write(fates_log(), *) 'DGCN: gi,gj,g2g_dist: ', gi,gj,g2g_dist + + ! + dist_check: if (any(EDPftvarcon_inst%seed_dispersal_max_dist .gt. g2g_dist)) then + + ! Add neighbor index to current grid cell index list + allocate(current_neighbor) + current_neighbor%next_neighbor => null() + + current_neighbor%gindex = gj + + current_neighbor%gc_dist = g2g_dist + + allocate(current_neighbor%density_prob(numpft)) + + do ipft = 1, numpft + call ProbabilityDensity(pdf, ipft, g2g_dist) + current_neighbor%density_prob(ipft) = pdf + end do + + if (associated(neighbors(gi)%first_neighbor)) then + neighbors(gi)%last_neighbor%next_neighbor => current_neighbor + neighbors(gi)%last_neighbor => current_neighbor + else + neighbors(gi)%first_neighbor => current_neighbor + neighbors(gi)%last_neighbor => current_neighbor + end if + + neighbors(gi)%neighbor_count = neighbors(gi)%neighbor_count + 1 + + ! Add current grid cell index to the neighbor's list as well + allocate(another_neighbor) + another_neighbor%next_neighbor => null() + + another_neighbor%gindex = gi + + another_neighbor%gc_dist = current_neighbor%gc_dist + allocate(another_neighbor%density_prob(numpft)) + do ipft = 1, numpft + another_neighbor%density_prob(ipft) = current_neighbor%density_prob(ipft) + end do + + if (associated(neighbors(gj)%first_neighbor)) then + neighbors(gj)%last_neighbor%next_neighbor => another_neighbor + neighbors(gj)%last_neighbor => another_neighbor + else + neighbors(gj)%first_neighbor => another_neighbor + neighbors(gj)%last_neighbor => another_neighbor + end if + + neighbors(gj)%neighbor_count = neighbors(gj)%neighbor_count + 1 + + end if dist_check + end do neighbor_search + end do gc_loop + + ! Loop through the list and populate the grid cell index array for each gridcell + do gi = 1,numg + + ! Start at the first neighbor of each neighborhood list + current_neighbor => neighbors(gi)%first_neighbor + + ! Allocate an array to hold the gridcell indices in each neighborhood + allocate(neighbors(gi)%neighbor_indices(neighbors(gi)%neighbor_count)) + + ! Walk through the neighborhood linked list and populate the array + ni = 1 + do while (associated(current_neighbor)) + neighbors(gi)%neighbor_indices(ni) = current_neighbor%gindex + ni = ni + 1 + current_neighbor => current_neighbor%next_neighbor + end do + + if (debug .and. iam .eq. 0) then + write(fates_log(), *) 'DGCN: g, lat, lon: ', gi, gclat(gi), gclon(gi) + write(fates_log(), *) 'DGCN: g, ncount: ', gi, neighbors(gi)%neighbor_count + do i = 1,neighbors(gi)%neighbor_count + write(fates_log(), *) 'DGCN: g, gilist: ', gi, neighbors(gi)%neighbor_indices(i) + end do + end if + + end do + + + call t_stopf('fates-seed-init-decomp') + +end subroutine DetermineGridCellNeighbors end module FatesInterfaceMod diff --git a/main/FatesInterfaceTypesMod.F90 b/main/FatesInterfaceTypesMod.F90 index ee18396d70..29a4ec2ba0 100644 --- a/main/FatesInterfaceTypesMod.F90 +++ b/main/FatesInterfaceTypesMod.F90 @@ -46,7 +46,11 @@ module FatesInterfaceTypesMod ! specficially packaged for them. ! This string sets which filter is enacted. - + character(len=16), public :: hlm_decomp ! This string defines which soil decomposition + ! scheme is active + ! expected values are one of CENTURY,MIMICS,CTC + + character(len=16), public :: hlm_nu_com ! This string defines which soil ! nutrient competition scheme is in use. ! current options with @@ -87,18 +91,12 @@ module FatesInterfaceTypesMod ! and how it moves and stores water in its ! rhizosphere shells - integer, public :: hlm_max_patch_per_site ! The HLM needs to exchange some patch - ! level quantities with FATES - ! FATES does not dictate those allocations - ! since it happens pretty early in - ! the model initialization sequence. - ! So we want to at least query it, - ! compare it to our maxpatchpersite, - ! and gracefully halt if we are over-allocating - integer, public :: hlm_parteh_mode ! This flag signals which Plant Allocation and Reactive ! Transport (exensible) Hypothesis (PARTEH) to use + integer, public :: hlm_seeddisp_cadence ! This flag signals at what cadence to disperse seeds across gridcells + ! 0 => no seed dispersal + ! 1, 2, 3 => daily, monthly, yearly dispersal integer, public :: hlm_use_ch4 ! This flag signals whether the methane model in ELM/CLM is ! active, and therefore whether or not boundary conditions @@ -148,17 +146,21 @@ module FatesInterfaceTypesMod ! THIS IS CURRENTLY NOT SUPPORTED integer, public :: hlm_use_cohort_age_tracking ! This flag signals whether or not to use - ! cohort age tracking. 1 = TRUE, 0 = FALSE - - integer, public :: hlm_use_ed_st3 ! This flag signals whether or not to use - ! (ST)atic (ST)and (ST)ructure mode (ST3) - ! Essentially, this gives us the ability - ! to turn off "dynamics", ie growth, disturbance - ! recruitment and mortality. - ! (EXPERIMENTAL!!!!! - RGK 07-2017) - ! 1 = TRUE, 0 = FALSE - ! default should be FALSE (dynamics on) - ! cannot be true with prescribed_phys + ! cohort age tracking. 1 = TRUE, 0 = FALSE + + + integer, public :: hlm_use_tree_damage ! This flag signals whether or not to turn on the + ! tree damage module + + integer, public :: hlm_use_ed_st3 ! This flag signals whether or not to use + ! (ST)atic (ST)and (ST)ructure mode (ST3) + ! Essentially, this gives us the ability + ! to turn off "dynamics", ie growth, disturbance + ! recruitment and mortality. + ! (EXPERIMENTAL!!!!! - RGK 07-2017) + ! 1 = TRUE, 0 = FALSE + ! default should be FALSE (dynamics on) + ! cannot be true with prescribed_phys integer, public :: hlm_use_ed_prescribed_phys ! This flag signals whether or not to use ! prescribed physiology, somewhat the opposite @@ -191,6 +193,7 @@ module FatesInterfaceTypesMod integer, public :: hlm_use_sp ! Flag to use FATES satellite phenology (LAI) mode ! 1 = TRUE, 0 = FALSE + ! ------------------------------------------------------------------------------------- ! Parameters that are dictated by FATES and known to be required knowledge ! needed by the HLMs @@ -212,10 +215,31 @@ module FatesInterfaceTypesMod ! data as some fields are arrays where each array is ! associated with one cohort - + ! The number of patches that FATES wants the HLM to allocate + ! for non sp/no-comp, this is the same number of patches that + ! fates tracks, plus 1 for the bare-ground. For sp/nocomp, it is the + ! maximum between the number fates tracks, and the numper of PFTs+CFTs + ! in the surface file. + ! for an SP simulation, if there are more PFTs and CFTs in the surface + ! dataset than the number of PFTs in FATES, we have to allocate with + ! the prior so that we can hold the LAI data + integer, public :: fates_maxPatchesPerSite + integer, public :: max_comp_per_site ! This is the maximum number of nutrient aquisition ! competitors that will be generated on each site + + integer, public :: fates_dispersal_kernel_mode ! Flag to signal the type of kernel used for grid cell seed dispersal + + integer, parameter, public :: fates_dispersal_kernel_exponential = 1 ! exponential dispersal kernel + integer, parameter, public :: fates_dispersal_kernel_exppower = 2 ! exponential power (ExP) dispersal kernel + integer, parameter, public :: fates_dispersal_kernel_logsech = 3 ! logistic-sech (LogS) dispersal kernel + + integer, parameter, public :: fates_dispersal_cadence_none = 0 ! no dispersal (use seed rain only) + integer, parameter, public :: fates_dispersal_cadence_daily = 1 ! Disperse seeds daily + integer, parameter, public :: fates_dispersal_cadence_monthly = 2 ! Disperse seeds monthly + integer, parameter, public :: fates_dispersal_cadence_yearly = 3 ! Disperse seeds yearly + ! ------------------------------------------------------------------------------------- ! These vectors are used for history output mapping ! CLM/ALM have limited support for multi-dimensional history output arrays. @@ -260,7 +284,14 @@ module FatesInterfaceTypesMod integer , public, allocatable :: fates_hdim_pftmap_levelpft(:) ! map of pfts in the element x pft dimension integer , public, allocatable :: fates_hdim_cwdmap_levelcwd(:) ! map of cwds in the element x cwd dimension integer , public, allocatable :: fates_hdim_agemap_levelage(:) ! map of ages in the element x age dimension - + + integer , public, allocatable :: fates_hdim_pftmap_levcdpf(:) ! map of pfts into size x crowndamage x pft dimension + integer , public, allocatable :: fates_hdim_cdmap_levcdpf(:) ! map of crowndamage into size x crowndamage x pft + integer , public, allocatable :: fates_hdim_scmap_levcdpf(:) ! map of size into size x crowndamage x pft + integer , public, allocatable :: fates_hdim_cdmap_levcdsc(:) ! map of crowndamage into size x crowndamage + integer , public, allocatable :: fates_hdim_scmap_levcdsc(:) ! map of size into size x crowndamage + integer , public, allocatable :: fates_hdim_levdamage(:) ! plant damage class lower bound dimension + ! ------------------------------------------------------------------------------------ ! DYNAMIC BOUNDARY CONDITIONS ! ------------------------------------------------------------------------------------ @@ -297,7 +328,8 @@ module FatesInterfaceTypesMod integer, public :: nlevheight ! The total number of height bins output to history integer, public :: nlevcoage ! The total number of cohort age bins output to history integer, public :: nleafage ! The total number of leaf age classes - + integer, public :: nlevdamage ! The total number of damage classes + ! ------------------------------------------------------------------------------------- ! Structured Boundary Conditions (SITE/PATCH SCALE) ! For floating point arrays, it is sometimes the convention to define the arrays as @@ -507,7 +539,7 @@ module FatesInterfaceTypesMod real(r8),allocatable :: hksat_sisl(:) ! hydraulic conductivity at saturation (mm H2O /s) real(r8),allocatable :: h2o_liq_sisl(:) ! Liquid water mass in each layer (kg/m2) real(r8) :: smpmin_si ! restriction for min of soil potential (mm) - + ! Land use ! --------------------------------------------------------------------------------- real(r8),allocatable :: hlm_harvest_rates(:) ! annual harvest rate per cat from hlm for a site @@ -515,6 +547,8 @@ module FatesInterfaceTypesMod character(len=64), allocatable :: hlm_harvest_catnames(:) ! names of hlm_harvest d1 integer :: hlm_harvest_units ! what units are the harvest rates specified in? [area vs carbon] + + real(r8) :: site_area ! Actual area of current site [m2], only used in carbon-based harvest ! Fixed biogeography mode real(r8), allocatable :: pft_areafrac(:) ! Fractional area of the FATES column occupied by each PFT @@ -593,15 +627,21 @@ module FatesInterfaceTypesMod ! Mass fluxes to BGC from fragmentation of litter into decomposing pools real(r8), allocatable :: litt_flux_cel_c_si(:) ! cellulose carbon litter, fates->BGC g/m3/s - real(r8), allocatable :: litt_flux_lig_c_si(:) ! lignan carbon litter, fates->BGC g/m3/s + real(r8), allocatable :: litt_flux_lig_c_si(:) ! lignin carbon litter, fates->BGC g/m3/s real(r8), allocatable :: litt_flux_lab_c_si(:) ! labile carbon litter, fates->BGC g/m3/s real(r8), allocatable :: litt_flux_cel_n_si(:) ! cellulose nitrogen litter, fates->BGC g/m3/s - real(r8), allocatable :: litt_flux_lig_n_si(:) ! lignan nitrogen litter, fates->BGC g/m3/s + real(r8), allocatable :: litt_flux_lig_n_si(:) ! lignin nitrogen litter, fates->BGC g/m3/s real(r8), allocatable :: litt_flux_lab_n_si(:) ! labile nitrogen litter, fates->BGC g/m3/s real(r8), allocatable :: litt_flux_cel_p_si(:) ! cellulose phosphorus litter, fates->BGC g/m3/s - real(r8), allocatable :: litt_flux_lig_p_si(:) ! lignan phosphorus litter, fates->BGC g/m3/s + real(r8), allocatable :: litt_flux_lig_p_si(:) ! lignin phosphorus litter, fates->BGC g/m3/s real(r8), allocatable :: litt_flux_lab_p_si(:) ! labile phosphorus litter, fates->BGC g/m3/s + + ! MIMICS Boundary Conditions + ! ----------------------------------------------------------------------------------- + real(r8) :: litt_flux_ligc_per_n ! lignin carbon per total nitrogen + ! in the fragmentation flux, per square meter [g/g] + ! Nutrient competition boundary conditions ! (These are all pointer allocations, this is because the host models @@ -635,12 +675,15 @@ module FatesInterfaceTypesMod ! RD Nutrient Boundary Conditions ! --------------------------------------------------------------------------------- - real(r8), pointer :: n_demand(:) ! Nitrogen demand from each competitor - ! for use in ELMs CTC/RD [g/m2/s] - real(r8), pointer :: p_demand(:) ! Phosophorus demand from each competitor - ! for use in ELMs CTC/RD [g/m2/s] + !real(r8), pointer :: n_demand(:) ! Nitrogen demand from each competitor + ! ! for use in ELMs CTC/RD [g/m2/s] + !real(r8), pointer :: p_demand(:) ! Phosophorus demand from each competitor + ! ! for use in ELMs CTC/RD [g/m2/s] + + + ! CH4 Boundary Conditions ! ----------------------------------------------------------------------------------- real(r8), pointer :: annavg_agnpp_pa(:) ! annual average patch npp above ground (gC/m2/s) @@ -652,6 +695,8 @@ module FatesInterfaceTypesMod real(r8), pointer :: woody_frac_aere_pa(:) ! Woody plant fraction (by crown area) of all plants ! used for calculating patch-level aerenchyma porosity + real(r8) :: ema_npp ! site-level NPP smoothed over time, see PrepCH4BCs() + ! used for N fixation in ELM/CLM right now ! Canopy Structure real(r8), allocatable :: elai_pa(:) ! exposed leaf area index @@ -697,6 +742,11 @@ module FatesInterfaceTypesMod ! small fluxes for various reasons ! [mm H2O/s] + ! FATES LULCC + real(r8) :: hrv_deadstemc_to_prod10c ! Harvested C flux to 10-yr wood product pool [Site-Level, gC m-2 s-1] + real(r8) :: hrv_deadstemc_to_prod100c ! Harvested C flux to 100-yr wood product pool [Site-Level, gC m-2 s-1] + real(r8) :: gpp_site ! Site level GPP, for NBP diagnosis in HLM [Site-Level, gC m-2 s-1] + real(r8) :: ar_site ! Site level Autotrophic Resp, for NBP diagnosis in HLM [Site-Level, gC m-2 s-1] end type bc_out_type @@ -713,12 +763,15 @@ module FatesInterfaceTypesMod ! each column is inefficient. Each of these are dimensioned by PFT. integer :: max_plant_comps + + real(r8), pointer :: vmax_nh4(:) + real(r8), pointer :: vmax_no3(:) + real(r8), pointer :: vmax_p(:) + real(r8), pointer :: eca_km_nh4(:) - real(r8), pointer :: eca_vmax_nh4(:) real(r8), pointer :: eca_km_no3(:) - real(r8), pointer :: eca_vmax_no3(:) - real(r8), pointer :: eca_km_p(:) - real(r8), pointer :: eca_vmax_p(:) + real(r8), pointer :: eca_km_p(:) + real(r8), pointer :: eca_km_ptase(:) real(r8), pointer :: eca_vmax_ptase(:) real(r8), pointer :: eca_alpha_ptase(:) @@ -732,12 +785,9 @@ module FatesInterfaceTypesMod end type bc_pconst_type - - contains - - ! ==================================================================================== - - - + + ! ====================================================================================== + + end module FatesInterfaceTypesMod diff --git a/main/FatesInventoryInitMod.F90 b/main/FatesInventoryInitMod.F90 index 507f01dbee..ec099860f1 100644 --- a/main/FatesInventoryInitMod.F90 +++ b/main/FatesInventoryInitMod.F90 @@ -28,16 +28,22 @@ module FatesInventoryInitMod use FatesConstantsMod, only : itrue use FatesGlobals , only : endrun => fates_endrun use FatesGlobals , only : fates_log + use EDParamsMod , only : regeneration_model use FatesInterfaceTypesMod, only : bc_in_type use FatesInterfaceTypesMod, only : hlm_inventory_ctrl_file use FatesInterfaceTypesMod, only : nleafage + use FatesInterfaceTypesMod, only : hlm_current_tod + use FatesInterfaceTypesMod, only : hlm_numSWb + use FatesInterfaceTypesMod, only : numpft use FatesLitterMod , only : litter_type use EDTypesMod , only : ed_site_type - use EDTypesMod , only : ed_patch_type - use EDTypesMod , only : ed_cohort_type + use FatesPatchMod , only : fates_patch_type + use FatesCohortMod , only : fates_cohort_type use EDTypesMod , only : area - use EDTypesMod , only : leaves_on - use EDTypesMod , only : leaves_off + use FatesConstantsMod, only : leaves_on + use FatesConstantsMod, only : leaves_off + use FatesConstantsMod, only : ihard_stress_decid + use FatesConstantsMod, only : isemi_stress_decid use PRTGenericMod , only : num_elements use PRTGenericMod , only : element_list use EDTypesMod , only : phen_cstat_nevercold @@ -65,6 +71,7 @@ module FatesInventoryInitMod use FatesRunningMeanMod, only : ema_lpa use PRTGenericMod, only : StorageNutrientTarget use FatesConstantsMod, only : fates_unset_int + use EDCanopyStructureMod, only : canopy_summarization, canopy_structure implicit none private @@ -75,7 +82,7 @@ module FatesInventoryInitMod ! with a patch. BY having a vector of patch pointers that lines up with the string ! identifier array, this can be done quickly. type pp_array - type(ed_patch_type), pointer :: cpatch + type(fates_patch_type), pointer :: cpatch end type pp_array character(len=*), parameter, private :: sourcefile = __FILE__ @@ -109,7 +116,6 @@ subroutine initialize_sites_by_inventory(nsites,sites,bc_in) use shr_file_mod, only : shr_file_getUnit use shr_file_mod, only : shr_file_freeUnit use FatesConstantsMod, only : nearzero - use EDPatchDynamicsMod, only : create_patch use EDPatchDynamicsMod, only : fuse_patches use EDCohortDynamicsMod, only : fuse_cohorts use EDCohortDynamicsMod, only : sort_cohorts @@ -123,12 +129,12 @@ subroutine initialize_sites_by_inventory(nsites,sites,bc_in) ! Locals type(ed_site_type), pointer :: currentSite - type(ed_patch_type), pointer :: currentpatch - type(ed_cohort_type), pointer :: currentcohort - type(ed_patch_type), pointer :: newpatch - type(ed_patch_type), pointer :: olderpatch - type(ed_patch_type), pointer :: head_of_unsorted_patch_list - type(ed_patch_type), pointer :: next_in_unsorted_patch_list + type(fates_patch_type), pointer :: currentpatch + type(fates_cohort_type), pointer :: currentcohort + type(fates_patch_type), pointer :: newpatch + type(fates_patch_type), pointer :: olderpatch + type(fates_patch_type), pointer :: head_of_unsorted_patch_list + type(fates_patch_type), pointer :: next_in_unsorted_patch_list integer :: sitelist_file_unit ! fortran file unit for site list integer :: pss_file_unit ! fortran file unit for the pss file integer :: css_file_unit ! fortran file unit for the css file @@ -141,6 +147,7 @@ subroutine initialize_sites_by_inventory(nsites,sites,bc_in) real(r8) :: area_init ! dummy value for creating a patch integer :: s ! site index integer :: ipa ! patch index + integer :: iv, ft, ic integer :: total_cohorts ! cohort counter for error checking integer, allocatable :: inv_format_list(:) ! list of format specs character(len=path_strlen), allocatable :: inv_css_list(:) ! list of css file names @@ -265,12 +272,6 @@ subroutine initialize_sites_by_inventory(nsites,sites,bc_in) do ipa=1,npatches - allocate(newpatch) - - newpatch%patchno = ipa - newpatch%younger => null() - newpatch%older => null() - ! This call doesn't do much asside from initializing the patch with ! nominal values, NaNs, zero's and allocating some vectors. We should ! be able to get the following values from the patch files. But on @@ -278,8 +279,14 @@ subroutine initialize_sites_by_inventory(nsites,sites,bc_in) age_init = 0.0_r8 area_init = 0.0_r8 + allocate(newpatch) + call newpatch%Create(age_init, area_init, primaryforest, & + fates_unset_int, hlm_numSWb, numpft, sites(s)%nlevsoil, & + hlm_current_tod, regeneration_model) - call create_patch(sites(s), newpatch, age_init, area_init, primaryforest, fates_unset_int ) + newpatch%patchno = ipa + newpatch%younger => null() + newpatch%older => null() if( inv_format_list(invsite) == 1 ) then @@ -485,7 +492,7 @@ subroutine initialize_sites_by_inventory(nsites,sites,bc_in) write(fates_log(),*) 'Lat: ',sites(s)%lat,' Lon: ',sites(s)%lon write(fates_log(),*) basal_area_pref,' [m2/ha]' write(fates_log(),*) '-------------------------------------------------------' - + ! Update the patch index numbers and fuse the cohorts in the patches ! ---------------------------------------------------------------------------------------- ipa=1 @@ -518,6 +525,7 @@ subroutine initialize_sites_by_inventory(nsites,sites,bc_in) ! Report Basal Area (as a check on if things were read in) ! ---------------------------------------------------------------------------------------- + !call canopy_structure(sites(s),bc_in(s)) basal_area_postf = 0.0_r8 currentpatch => sites(s)%youngest_patch do while(associated(currentpatch)) @@ -527,9 +535,12 @@ subroutine initialize_sites_by_inventory(nsites,sites,bc_in) currentcohort%n*0.25*((currentcohort%dbh/100.0_r8)**2.0_r8)*pi_const currentcohort => currentcohort%shorter end do + currentPatch => currentpatch%older enddo + + write(fates_log(),*) '-------------------------------------------------------' write(fates_log(),*) 'Basal Area from inventory, AFTER fusion' write(fates_log(),*) 'Lat: ',sites(s)%lat,' Lon: ',sites(s)%lon @@ -538,11 +549,13 @@ subroutine initialize_sites_by_inventory(nsites,sites,bc_in) ! If this is flagged as true, the post-fusion inventory will be written to file ! in the run directory. + if(do_inventory_out)then call write_inventory_type1(sites(s)) end if end do + deallocate(inv_format_list, inv_pss_list, inv_css_list, inv_lat_list, inv_lon_list) return @@ -734,7 +747,7 @@ subroutine set_inventory_edpatch_type1(newpatch,pss_file_unit,ipa,ios,patch_name ! water (NA) Water content of soil (NOT USED) ! fsc (kg/m2) Fast Soil Carbon ! stsc (kg/m2) Structural Soil Carbon - ! stsl (kg/m2) Structural Soil Lignan + ! stsl (kg/m2) Structural Soil Lignin ! ssc (kg/m2) Slow Soil Carbon ! psc (NA) Passive Soil Carbon (NOT USED) ! msn (kg/m2) Mineralized Soil Nitrogen @@ -743,10 +756,9 @@ subroutine set_inventory_edpatch_type1(newpatch,pss_file_unit,ipa,ios,patch_name use FatesSizeAgeTypeIndicesMod, only: get_age_class_index use EDtypesMod, only: AREA - use SFParamsMod , only : SF_val_CWD_frac ! Arguments - type(ed_patch_type),intent(inout), target :: newpatch ! Patch structure + type(fates_patch_type),intent(inout), target :: newpatch ! Patch structure integer,intent(in) :: pss_file_unit ! Self explanatory integer,intent(in) :: ipa ! Patch index (line number) integer,intent(out) :: ios ! Return flag @@ -763,7 +775,7 @@ subroutine set_inventory_edpatch_type1(newpatch,pss_file_unit,ipa,ios,patch_name real(r8) :: p_water ! Patch water (unused) real(r8) :: p_fsc ! Patch fast soil carbon real(r8) :: p_stsc ! Patch structural soil carbon - real(r8) :: p_stsl ! Patch structural soil lignans + real(r8) :: p_stsl ! Patch structural soil lignins real(r8) :: p_ssc ! Patch slow soil carbon real(r8) :: p_psc ! Patch P soil carbon real(r8) :: p_msn ! Patch mean soil nitrogen @@ -847,7 +859,7 @@ subroutine set_inventory_edcohort_type1(csite,bc_in,css_file_unit,npatches, & ! patch (string) patch id string associated with this cohort ! index (integer) cohort index ! dbh (cm) diameter at breast height - ! height (m) height of the tree + ! height (m) height of the tree ! pft (integer) the plant functional type index (must be consistent with param file) ! n (/m2) The plant number density ! bdead (kgC/plant)The dead biomass per indiv of this cohort (NOT USED) @@ -891,11 +903,10 @@ subroutine set_inventory_edcohort_type1(csite,bc_in,css_file_unit,npatches, & real(r8) :: c_avgRG ! avg radial growth (NOT USED) real(r8) :: site_spread ! initial guess of site spread ! should be quickly re-calculated - integer :: cstatus ! cohort status integer,parameter :: rstatus = 0 ! recruit status - type(ed_patch_type), pointer :: cpatch ! current patch pointer - type(ed_cohort_type), pointer :: temp_cohort ! temporary patch (needed for allom funcs) + type(fates_patch_type), pointer :: cpatch ! current patch pointer + type(fates_cohort_type), pointer :: temp_cohort ! temporary patch (needed for allom funcs) integer :: ipa ! patch idex integer :: iage integer :: el @@ -915,9 +926,10 @@ subroutine set_inventory_edcohort_type1(csite,bc_in,css_file_unit,npatches, & real(r8) :: m_sapw ! Generic mass for sapwood [kg] real(r8) :: m_store ! Generic mass for storage [kg] real(r8) :: m_repro ! Generic mass for reproductive tissues [kg] - real(r8) :: stem_drop_fraction + real(r8) :: fnrt_drop_fraction ! Fine-root abscission fraction + real(r8) :: stem_drop_fraction ! Stem abscission fraction integer :: i_pft, ncohorts_to_create - + character(len=128),parameter :: wr_fmt = & '(F7.1,2X,A20,2X,A20,2X,F5.2,2X,F5.2,2X,I4,2X,F5.2,2X,F5.2,2X,F5.2,2X,F5.2)' @@ -925,6 +937,7 @@ subroutine set_inventory_edcohort_type1(csite,bc_in,css_file_unit,npatches, & real(r8), parameter :: abnormal_large_dbh = 500.0_r8 ! I've never heard of a tree > 3m integer, parameter :: recruitstatus = 0 + read(css_file_unit,fmt=*,iostat=ios) c_time, p_name, c_name, c_dbh, c_height, & c_pft, c_nplant, c_bdead, c_balive, c_avgRG @@ -995,9 +1008,11 @@ subroutine set_inventory_edcohort_type1(csite,bc_in,css_file_unit,npatches, & end if if (c_pft .eq. 0 ) then - write(fates_log(), *) 'inventory pft: ',c_pft - write(fates_log(), *) 'SPECIAL CASE TRIGGERED: PFT == 0 and therefore this subroutine' - write(fates_log(), *) 'will assign a cohort with n = n_orig/numpft to every cohort in range 1 to numpft' + if(debug_inv)then + write(fates_log(), *) 'inventory pft: ',c_pft + write(fates_log(), *) 'SPECIAL CASE TRIGGERED: PFT == 0 and therefore this subroutine' + write(fates_log(), *) 'will assign a cohort with n = n_orig/numpft to every cohort in range 1 to numpft' + end if ncohorts_to_create = numpft else ncohorts_to_create = 1 @@ -1016,57 +1031,78 @@ subroutine set_inventory_edcohort_type1(csite,bc_in,css_file_unit,npatches, & temp_cohort%n = c_nplant * cpatch%area / real(ncohorts_to_create,r8) temp_cohort%dbh = c_dbh + temp_cohort%crowndamage = 1 ! assume undamaged - call h_allom(c_dbh,temp_cohort%pft,temp_cohort%hite) + call h_allom(c_dbh,temp_cohort%pft,temp_cohort%height) temp_cohort%canopy_trim = 1.0_r8 + ! Determine the phenology status and the elongation factors. + fnrt_drop_fraction = prt_params%phen_fnrt_drop_fraction(temp_cohort%pft) + stem_drop_fraction = prt_params%phen_stem_drop_fraction(temp_cohort%pft) + + if( prt_params%season_decid(temp_cohort%pft) == itrue .and. & + any(csite%cstatus == [phen_cstat_nevercold,phen_cstat_iscold])) then + ! Cold deciduous and season is for leaves off. Set leaf status and + ! elongation factors accordingly + temp_cohort%efleaf_coh = 0.0_r8 + temp_cohort%effnrt_coh = 1._r8 - fnrt_drop_fraction + temp_cohort%efstem_coh = 1._r8 - stem_drop_fraction + + temp_cohort%status_coh = leaves_off + + elseif ( any(prt_params%stress_decid(temp_cohort%pft) == [ihard_stress_decid,isemi_stress_decid])) then + ! Drought deciduous. For the default approach, elongation factor is either + ! zero (full abscission) or one (fully flushed), but this can also be a + ! fraction in other approaches. Here we assume that leaves are "on" (i.e. + ! either fully flushed or growing) if elongation factor is not 0 for the + ! initial conditions. + ! + ! For tissues other than leaves, the actual drop fraction is a combination + ! of the elongation factor (e) and the drop fraction (x), which will ensure + ! that the remaining tissue biomass will be exactly e when x=1, and exactly + ! the original biomass when x = 0. + temp_cohort%efleaf_coh = csite%elong_factor(temp_cohort%pft) + temp_cohort%effnrt_coh = 1.0_r8 - (1.0_r8 - temp_cohort%efleaf_coh ) * fnrt_drop_fraction + temp_cohort%efstem_coh = 1.0_r8 - (1.0_r8 - temp_cohort%efleaf_coh ) * stem_drop_fraction + + if (temp_cohort%efleaf_coh > 0.0_r8) then + ! Assume leaves are growing even if they are not fully flushed. + temp_cohort%status_coh = leaves_on + else + ! Leaves are off (abscissing). + temp_cohort%status_coh = leaves_off + end if + else + ! Evergreen, or deciduous PFT during the growing season. Assume tissues are fully flushed. + temp_cohort%efleaf_coh = 1.0_r8 + temp_cohort%effnrt_coh = 1.0_r8 + temp_cohort%efstem_coh = 1.0_r8 + + temp_cohort%status_coh = leaves_on + end if - call bagw_allom(temp_cohort%dbh,temp_cohort%pft,c_agw) + call bagw_allom(temp_cohort%dbh,temp_cohort%pft, & + temp_cohort%crowndamage, temp_cohort%efstem_coh, c_agw) ! Calculate coarse root biomass from allometry - call bbgw_allom(temp_cohort%dbh,temp_cohort%pft,c_bgw) + call bbgw_allom(temp_cohort%dbh,temp_cohort%pft, temp_cohort%efstem_coh, c_bgw) ! Calculate the leaf biomass (calculates a maximum first, then applies canopy trim ! and sla scaling factors) - call bleaf(temp_cohort%dbh,temp_cohort%pft,temp_cohort%canopy_trim,c_leaf) - + call bleaf(temp_cohort%dbh,temp_cohort%pft,temp_cohort%crowndamage,& + temp_cohort%canopy_trim, temp_cohort%efleaf_coh, c_leaf) + ! Calculate fine root biomass - call bfineroot(temp_cohort%dbh,temp_cohort%pft,temp_cohort%canopy_trim,c_fnrt) - ! Calculate sapwood biomass - call bsap_allom(temp_cohort%dbh,temp_cohort%pft,temp_cohort%canopy_trim, a_sapw, c_sapw) + temp_cohort%l2fr = prt_params%allom_l2fr(temp_cohort%pft) + call bfineroot(temp_cohort%dbh,temp_cohort%pft,temp_cohort%canopy_trim,temp_cohort%l2fr, & + temp_cohort%effnrt_coh, c_fnrt) + ! Calculate sapwood biomass + call bsap_allom(temp_cohort%dbh,temp_cohort%pft,temp_cohort%crowndamage, & + temp_cohort%canopy_trim, temp_cohort%efstem_coh, a_sapw, c_sapw) + call bdead_allom( c_agw, c_bgw, c_sapw, temp_cohort%pft, c_struct ) - - call bstore_allom(temp_cohort%dbh, temp_cohort%pft, temp_cohort%canopy_trim, c_store) - - temp_cohort%laimemory = 0._r8 - temp_cohort%sapwmemory = 0._r8 - temp_cohort%structmemory = 0._r8 - cstatus = leaves_on - - stem_drop_fraction = EDPftvarcon_inst%phen_stem_drop_fraction(temp_cohort%pft) - - if( prt_params%season_decid(temp_cohort%pft) == itrue .and. & - any(csite%cstatus == [phen_cstat_nevercold,phen_cstat_iscold])) then - temp_cohort%laimemory = c_leaf - temp_cohort%sapwmemory = c_sapw * stem_drop_fraction - temp_cohort%structmemory = c_struct * stem_drop_fraction - c_leaf = 0._r8 - c_sapw = (1._r8 - stem_drop_fraction) * c_sapw - c_struct = (1._r8 - stem_drop_fraction) * c_struct - cstatus = leaves_off - endif - - if ( prt_params%stress_decid(temp_cohort%pft) == itrue .and. & - any(csite%dstatus == [phen_dstat_timeoff,phen_dstat_moistoff])) then - temp_cohort%laimemory = c_leaf - temp_cohort%sapwmemory = c_sapw * stem_drop_fraction - temp_cohort%structmemory = c_struct * stem_drop_fraction - c_leaf = 0._r8 - c_sapw = (1._r8 - stem_drop_fraction) * c_sapw - c_struct = (1._r8 - stem_drop_fraction) * c_struct - cstatus = leaves_off - endif + call bstore_allom(temp_cohort%dbh, temp_cohort%pft, temp_cohort%crowndamage,temp_cohort%canopy_trim, c_store) prt_obj => null() call InitPRTObject(prt_obj) @@ -1095,21 +1131,17 @@ subroutine set_inventory_edcohort_type1(csite,bc_in,css_file_unit,npatches, & case(nitrogen_element) ! For inventory runs, initialize nutrient contents half way between max and min stoichiometries - m_struct = c_struct * 0.5_r8 * & - (prt_params%nitr_stoich_p1(temp_cohort%pft,prt_params%organ_param_id(struct_organ)) + & - prt_params%nitr_stoich_p2(temp_cohort%pft,prt_params%organ_param_id(struct_organ))) + m_struct = c_struct * & + prt_params%nitr_stoich_p1(temp_cohort%pft,prt_params%organ_param_id(struct_organ)) - m_leaf = c_leaf * 0.5_r8 * & - (prt_params%nitr_stoich_p1(temp_cohort%pft,prt_params%organ_param_id(leaf_organ)) + & - prt_params%nitr_stoich_p2(temp_cohort%pft,prt_params%organ_param_id(leaf_organ))) + m_leaf = c_leaf * & + prt_params%nitr_stoich_p1(temp_cohort%pft,prt_params%organ_param_id(leaf_organ)) - m_fnrt = c_fnrt * 0.5_r8 * & - (prt_params%nitr_stoich_p1(temp_cohort%pft,prt_params%organ_param_id(fnrt_organ)) + & - prt_params%nitr_stoich_p2(temp_cohort%pft,prt_params%organ_param_id(fnrt_organ))) + m_fnrt = c_fnrt * & + prt_params%nitr_stoich_p1(temp_cohort%pft,prt_params%organ_param_id(fnrt_organ)) - m_sapw = c_sapw * 0.5_r8 * & - (prt_params%nitr_stoich_p1(temp_cohort%pft,prt_params%organ_param_id(sapw_organ)) + & - prt_params%nitr_stoich_p2(temp_cohort%pft,prt_params%organ_param_id(sapw_organ))) + m_sapw = c_sapw * & + prt_params%nitr_stoich_p1(temp_cohort%pft,prt_params%organ_param_id(sapw_organ)) m_repro = 0._r8 @@ -1117,21 +1149,17 @@ subroutine set_inventory_edcohort_type1(csite,bc_in,css_file_unit,npatches, & case(phosphorus_element) - m_struct = c_struct * 0.5_r8 * & - (prt_params%phos_stoich_p1(temp_cohort%pft,prt_params%organ_param_id(struct_organ)) + & - prt_params%phos_stoich_p2(temp_cohort%pft,prt_params%organ_param_id(struct_organ))) - - m_leaf = c_leaf * 0.5_r8 * & - (prt_params%phos_stoich_p1(temp_cohort%pft,prt_params%organ_param_id(leaf_organ)) + & - prt_params%phos_stoich_p2(temp_cohort%pft,prt_params%organ_param_id(leaf_organ))) + m_struct = c_struct * & + prt_params%phos_stoich_p1(temp_cohort%pft,prt_params%organ_param_id(struct_organ)) - m_fnrt = c_fnrt * 0.5_r8 * & - (prt_params%phos_stoich_p1(temp_cohort%pft,prt_params%organ_param_id(fnrt_organ)) + & - prt_params%phos_stoich_p2(temp_cohort%pft,prt_params%organ_param_id(fnrt_organ))) + m_leaf = c_leaf * & + prt_params%phos_stoich_p1(temp_cohort%pft,prt_params%organ_param_id(leaf_organ)) - m_sapw = c_sapw * 0.5_r8 * & - (prt_params%phos_stoich_p1(temp_cohort%pft,prt_params%organ_param_id(sapw_organ)) + & - prt_params%phos_stoich_p2(temp_cohort%pft,prt_params%organ_param_id(sapw_organ))) + m_fnrt = c_fnrt * & + prt_params%phos_stoich_p1(temp_cohort%pft,prt_params%organ_param_id(fnrt_organ)) + + m_sapw = c_sapw * & + prt_params%phos_stoich_p1(temp_cohort%pft,prt_params%organ_param_id(sapw_organ)) m_repro = 0._r8 @@ -1162,14 +1190,12 @@ subroutine set_inventory_edcohort_type1(csite,bc_in,css_file_unit,npatches, & call prt_obj%CheckInitialConditions() - - ! Since spread is a canopy level calculation, we need to provide an initial guess here. - - call create_cohort(csite, cpatch, temp_cohort%pft, temp_cohort%n, temp_cohort%hite, & + call create_cohort(csite, cpatch, temp_cohort%pft, temp_cohort%n, temp_cohort%height, & temp_cohort%coage, temp_cohort%dbh, & - prt_obj, temp_cohort%laimemory,temp_cohort%sapwmemory, temp_cohort%structmemory, & - cstatus, rstatus, temp_cohort%canopy_trim,temp_cohort%c_area, & - 1, csite%spread, bc_in) + prt_obj, temp_cohort%efleaf_coh, temp_cohort%effnrt_coh, & + temp_cohort%efstem_coh, temp_cohort%status_coh, rstatus, & + temp_cohort%canopy_trim,temp_cohort%c_area, & + 1, temp_cohort%crowndamage, csite%spread, bc_in) deallocate(temp_cohort) ! get rid of temporary cohort @@ -1198,8 +1224,8 @@ subroutine write_inventory_type1(currentSite) type(ed_site_type), target :: currentSite ! Locals - type(ed_patch_type), pointer :: currentpatch - type(ed_cohort_type), pointer :: currentcohort + type(fates_patch_type), pointer :: currentpatch + type(fates_cohort_type), pointer :: currentcohort character(len=128) :: pss_name_out ! output file string character(len=128) :: css_name_out ! output file string @@ -1242,7 +1268,7 @@ subroutine write_inventory_type1(currentSite) open(unit=css_file_out,file=trim(css_name_out), status='UNKNOWN',action='WRITE',form='FORMATTED') write(pss_file_out,*) 'time patch trk age area water fsc stsc stsl ssc psc msn fsn' - write(css_file_out,*) 'time patch cohort dbh hite pft nplant bdead alive Avgrg' + write(css_file_out,*) 'time patch cohort dbh height pft nplant bdead alive Avgrg' ipatch=0 currentpatch => currentSite%youngest_patch diff --git a/main/FatesParameterDerivedMod.F90 b/main/FatesParameterDerivedMod.F90 index 66445c1906..aa1584feb0 100644 --- a/main/FatesParameterDerivedMod.F90 +++ b/main/FatesParameterDerivedMod.F90 @@ -13,7 +13,10 @@ module FatesParameterDerivedMod use FatesConstantsMod, only : umolC_to_kgC use FatesConstantsMod, only : g_per_kg use FatesInterfaceTypesMod, only : nleafage - + use FatesInterfaceTypesMod, only : nlevdamage + use FatesGlobals , only : fates_log + use EDParamsMod , only : ED_val_history_damage_bin_edges + implicit none private @@ -25,17 +28,29 @@ module FatesParameterDerivedMod ! rate at 25C (umol CO2/m**2/s) real(r8), allocatable :: kp25top(:,:) ! canopy top: initial slope of CO2 response ! curve (C4 plants) at 25C + + real(r8), allocatable :: branch_frac(:) ! fraction of aboveground woody biomass in branches (as + ! oppose to stems) - for use in damage allometries + + real(r8), allocatable :: damage_transitions(:,:,:) ! matrix of transition probabilities between + ! damage classes - one per PFT + contains procedure :: Init + procedure :: InitDamageTransitions procedure :: InitAllocate + procedure :: InitAllocateDamageTransitions end type param_derived_type type(param_derived_type), public :: param_derived -contains + logical :: debug = .false. ! for module level debugging +contains + + ! =================================================================================== subroutine InitAllocate(this,numpft) class(param_derived_type), intent(inout) :: this @@ -44,26 +59,46 @@ subroutine InitAllocate(this,numpft) allocate(this%jmax25top(numpft,nleafage)) allocate(this%tpu25top(numpft,nleafage)) allocate(this%kp25top(numpft,nleafage)) + + allocate(this%branch_frac(numpft)) + return end subroutine InitAllocate ! ===================================================================================== - + + ! =================================================================================== + subroutine InitAllocateDamageTransitions(this,numpft) + + class(param_derived_type), intent(inout) :: this + integer, intent(in) :: numpft + + allocate(this%damage_transitions(nlevdamage,nlevdamage, numpft)) + + return + end subroutine InitAllocateDamageTransitions + + ! ===================================================================================== + subroutine Init(this,numpft) use EDPftvarcon, only: EDPftvarcon_inst - + use SFParamsMod, only: SF_val_CWD_frac + use FatesLitterMod, only : ncwd + class(param_derived_type), intent(inout) :: this integer, intent(in) :: numpft ! local variables integer :: ft ! pft index integer :: iage ! leaf age class index - + integer :: c ! cwd index + associate( vcmax25top => EDPftvarcon_inst%vcmax25top ) call this%InitAllocate(numpft) + call this%InitDamageTransitions(numpft) do ft = 1,numpft @@ -85,11 +120,78 @@ subroutine Init(this,numpft) this%kp25top(ft,iage) = 20000._r8 * vcmax25top(ft,iage) end do + + ! Allocate fraction of aboveground woody biomass in branches + this%branch_frac(ft) = sum(SF_val_CWD_frac(1:3)) - end do !ft + end do !ft end associate return end subroutine Init +!========================================================================= + + subroutine InitDamageTransitions(this, numpft) + + use EDPftvarcon, only: EDPftvarcon_inst + + + class(param_derived_type), intent(inout) :: this + integer, intent(in) :: numpft + + ! local variables + integer :: ft ! pft index + integer :: i ! crowndamage index + integer :: j ! damage bin index + real(r8) :: damage_frac ! damage fraction + real(r8), allocatable :: damage_bin_edges_ex(:) ! including the upper bound of 100 + real(r8), allocatable :: class_widths(:) ! widths of each damage class + + call this%InitAllocateDamageTransitions(numpft) + + allocate(class_widths(1:nlevdamage)) + allocate(damage_bin_edges_ex(1:(nlevdamage+1))) + + ! class widths + ! append 100 to ED_val_history_damage_bin_edges + do j = 1,nlevdamage + damage_bin_edges_ex(j) = ED_val_history_damage_bin_edges(j) + end do + damage_bin_edges_ex(j) = 100.0_r8 + + ! gets class widths (something like below) + class_widths = damage_bin_edges_ex(2:(nlevdamage+1)) - & + damage_bin_edges_ex(1:nlevdamage) + + do ft = 1, numpft + + damage_frac = EDPftvarcon_inst%damage_frac(ft) + + do i = 1, nlevdamage + + ! zero the column + this%damage_transitions(i,:,ft) = 0._r8 + ! damage rate stays the same + this%damage_transitions(i,i,ft) = 1.0_r8 - damage_frac + + + if(i < nlevdamage) then + ! fraction damaged get split according to class width + this%damage_transitions(i,i+1:nlevdamage,ft) = damage_frac * & + class_widths(i+1:nlevdamage)/ SUM(class_widths(i+1:nlevdamage)) + end if + ! Make sure it sums to one - they have to go somewhere + this%damage_transitions(i, :, ft) = this%damage_transitions(i, :, ft)/SUM(this%damage_transitions(i, :, ft)) + end do + + if (debug) write(fates_log(),'(a/,5(F12.6,1x))') 'annual transition matrix : ', this%damage_transitions(:,:,ft) + end do + + + + + return + end subroutine InitDamageTransitions + end module FatesParameterDerivedMod diff --git a/main/FatesParametersInterface.F90 b/main/FatesParametersInterface.F90 index f69d4ef5bf..b19817a091 100644 --- a/main/FatesParametersInterface.F90 +++ b/main/FatesParametersInterface.F90 @@ -4,7 +4,7 @@ module FatesParametersInterface ! depend on any host modules. use FatesConstantsMod, only : r8 => fates_r8 - use FatesGlobals, only : fates_log + use FatesGlobals, only : fates_log, fates_endrun implicit none private ! Modules are private by default @@ -29,13 +29,15 @@ module FatesParametersInterface character(len=*), parameter, public :: dimension_name_allpfts = 'fates_allpfts' character(len=*), parameter, public :: dimension_name_variants = 'fates_variants' character(len=*), parameter, public :: dimension_name_hydr_organs = 'fates_hydr_organs' - character(len=*), parameter, public :: dimension_name_prt_organs = 'fates_prt_organs' + character(len=*), parameter, public :: dimension_name_prt_organs = 'fates_plant_organs' character(len=*), parameter, public :: dimension_name_leaf_age = 'fates_leafage_class' character(len=*), parameter, public :: dimension_name_history_size_bins = 'fates_history_size_bins' character(len=*), parameter, public :: dimension_name_history_age_bins = 'fates_history_age_bins' character(len=*), parameter, public :: dimension_name_history_height_bins = 'fates_history_height_bins' character(len=*), parameter, public :: dimension_name_history_coage_bins = 'fates_history_coage_bins' character(len=*), parameter, public :: dimension_name_hlm_pftno = 'fates_hlm_pftno' + character(len=*), parameter, public :: dimension_name_history_damage_bins = 'fates_history_damage_bins' + character(len=*), parameter, public :: dimension_name_damage = 'fates_damage_class' ! Dimensions in the host namespace: character(len=*), parameter, public :: dimension_name_host_allpfts = 'allpfts' @@ -59,8 +61,8 @@ module FatesParametersInterface procedure :: Init procedure :: Destroy procedure :: RegisterParameter - generic :: RetreiveParameter => RetreiveParameterScalar, RetreiveParameter1D, RetreiveParameter2D - generic :: RetreiveParameterAllocate => RetreiveParameter1DAllocate, RetreiveParameter2DAllocate + generic :: RetrieveParameter => RetrieveParameterScalar, RetrieveParameter1D, RetrieveParameter2D + generic :: RetrieveParameterAllocate => RetrieveParameter1DAllocate, RetrieveParameter2DAllocate generic :: SetData => SetDataScalar, SetData1D, SetData2D procedure :: GetUsedDimensions procedure :: SetDimensionSizes @@ -70,11 +72,11 @@ module FatesParametersInterface procedure :: FindIndex ! Private functions - procedure, private :: RetreiveParameterScalar - procedure, private :: RetreiveParameter1D - procedure, private :: RetreiveParameter2D - procedure, private :: RetreiveParameter1DAllocate - procedure, private :: RetreiveParameter2DAllocate + procedure, private :: RetrieveParameterScalar + procedure, private :: RetrieveParameter1D + procedure, private :: RetrieveParameter2D + procedure, private :: RetrieveParameter1DAllocate + procedure, private :: RetrieveParameter2DAllocate procedure, private :: SetDataScalar procedure, private :: SetData1D procedure, private :: SetData2D @@ -151,7 +153,7 @@ subroutine RegisterParameter(this, name, dimension_shape, dimension_names, & end subroutine RegisterParameter !----------------------------------------------------------------------- - subroutine RetreiveParameterScalar(this, name, data) + subroutine RetrieveParameterScalar(this, name, data) implicit none @@ -165,12 +167,10 @@ subroutine RetreiveParameterScalar(this, name, data) ! assert(size(data) == size(this%parameters(i)%data)) data = this%parameters(i)%data(1, 1) - end subroutine RetreiveParameterScalar + end subroutine RetrieveParameterScalar !----------------------------------------------------------------------- - subroutine RetreiveParameter1D(this, name, data) - - use abortutils, only : endrun + subroutine RetrieveParameter1D(this, name, data) implicit none @@ -182,7 +182,7 @@ subroutine RetreiveParameter1D(this, name, data) i = this%FindIndex(name) if (size(data) /= size(this%parameters(i)%data(:, 1))) then - write(fates_log(), *) 'ERROR : retreiveparameter1d : ', name, ' size inconsistent.' + write(fates_log(), *) 'ERROR : RetrieveParameter1d : ', name, ' size inconsistent.' write(fates_log(), *) 'ERROR : expected size = ', size(data) write(fates_log(), *) 'ERROR : data size received from file = ', size(this%parameters(i)%data(:, 1)) write(fates_log(), *) 'ERROR : dimesions received from file' @@ -190,16 +190,14 @@ subroutine RetreiveParameter1D(this, name, data) do d = 1, max_dimensions write(fates_log(), *) this%parameters(i)%dimension_names(d), ', ', this%parameters(i)%dimension_sizes(d) end do - call endrun(msg='size error retreiving 1d parameter.') + call fates_endrun(msg='size error retreiving 1d parameter.') end if data = this%parameters(i)%data(:, 1) - end subroutine RetreiveParameter1D + end subroutine RetrieveParameter1D !----------------------------------------------------------------------- - subroutine RetreiveParameter2D(this, name, data) - - use abortutils, only : endrun + subroutine RetrieveParameter2D(this, name, data) implicit none @@ -212,7 +210,7 @@ subroutine RetreiveParameter2D(this, name, data) i = this%FindIndex(name) if (size(data, 1) /= size(this%parameters(i)%data, 1) .and. & size(data, 2) /= size(this%parameters(i)%data, 2)) then - write(fates_log(), *) 'ERROR : retreiveparameter2d : ', name, ' size inconsistent.' + write(fates_log(), *) 'ERROR : RetrieveParameter2d : ', name, ' size inconsistent.' write(fates_log(), *) 'ERROR : expected shape = ', shape(data) write(fates_log(), *) 'ERROR : dim 1 expected size = ', size(data, 1) write(fates_log(), *) 'ERROR : dim 2 expected size = ', size(data, 2) @@ -223,16 +221,14 @@ subroutine RetreiveParameter2D(this, name, data) do d = 1, max_dimensions write(fates_log(), *) this%parameters(i)%dimension_names(d), ', ', this%parameters(i)%dimension_sizes(d) end do - call endrun(msg='size error retreiving 2d parameter.') + call fates_endrun(msg='size error retreiving 2d parameter.') end if data = this%parameters(i)%data - end subroutine RetreiveParameter2D + end subroutine RetrieveParameter2D !----------------------------------------------------------------------- - subroutine RetreiveParameter1DAllocate(this, name, data) - - use abortutils, only : endrun + subroutine RetrieveParameter1DAllocate(this, name, data) implicit none @@ -248,12 +244,10 @@ subroutine RetreiveParameter1DAllocate(this, name, data) allocate(data(lower_bound:upper_bound)) data(lower_bound:upper_bound) = this%parameters(i)%data(:, 1) - end subroutine RetreiveParameter1DAllocate + end subroutine RetrieveParameter1DAllocate !----------------------------------------------------------------------- - subroutine RetreiveParameter2DAllocate(this, name, data) - - use abortutils, only : endrun + subroutine RetrieveParameter2DAllocate(this, name, data) implicit none @@ -271,7 +265,7 @@ subroutine RetreiveParameter2DAllocate(this, name, data) allocate(data(lb_1:ub_1, lb_2:ub_2)) data(lb_1:ub_1, lb_2:ub_2) = this%parameters(i)%data - end subroutine RetreiveParameter2DAllocate + end subroutine RetrieveParameter2DAllocate !----------------------------------------------------------------------- function FindIndex(this, name) result(i) @@ -370,7 +364,6 @@ subroutine SetDimensionSizes(this, is_host_file, num_used_dimensions, dimension_ ! non-empty dimension name, set the size do i = 1, num_used_dimensions if (trim(dimension_names(i)) == trim(dim_name)) then - !write(*, *) '--> ', trim(this%parameters(p)%name), ' setting ', trim(dim_name), ' d = ', d, 'size = ', dimension_sizes(i) this%parameters(p)%dimension_sizes(d) = dimension_sizes(i) exit end if @@ -438,9 +431,7 @@ end subroutine SetDataScalar !----------------------------------------------------------------------- subroutine SetData1D(this, index, data) - - use abortutils, only : endrun - + implicit none class(fates_parameters_type), intent(inout) :: this @@ -459,7 +450,7 @@ subroutine SetData1D(this, index, data) do d = 1, max_dimensions write(fates_log(), *) this%parameters(index)%dimension_names(d), ', ', this%parameters(index)%dimension_sizes(d) end do - call endrun(msg='size error setting 1d parameter.') + call fates_endrun(msg='size error setting 1d parameter.') end if allocate(this%parameters(index)%data(size_dim_1, 1)) diff --git a/main/FatesRestartInterfaceMod.F90 b/main/FatesRestartInterfaceMod.F90 index 0605767cd6..c59e2ef17c 100644 --- a/main/FatesRestartInterfaceMod.F90 +++ b/main/FatesRestartInterfaceMod.F90 @@ -1,14 +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 : 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 @@ -18,30 +21,33 @@ module FatesRestartInterfaceMod use FatesInterfaceTypesMod, only : bc_in_type use FatesInterfaceTypesMod, only : bc_out_type use FatesInterfaceTypesMod, only : hlm_use_planthydro + use FatesInterfaceTypesMod, only : hlm_parteh_mode use FatesInterfaceTypesMod, only : hlm_use_sp + use FatesInterfaceTypesMod, only : hlm_use_nocomp, hlm_use_fixed_biogeog use FatesInterfaceTypesMod, only : fates_maxElementsPerSite - use EDCohortDynamicsMod, only : UpdateCohortBioPhysRates + use FatesInterfaceTypesMod, only : hlm_use_tree_damage use FatesHydraulicsMemMod, only : nshell use FatesHydraulicsMemMod, only : n_hypool_ag use FatesHydraulicsMemMod, only : n_hypool_troot use FatesHydraulicsMemMod, only : nlevsoi_hyd_max use FatesPlantHydraulicsMod, only : UpdatePlantPsiFTCFromTheta use PRTGenericMod, only : prt_global - use EDCohortDynamicsMod, only : nan_cohort - use EDCohortDynamicsMod, only : zero_cohort + use PRTGenericMod, only : prt_cnp_flex_allom_hyp use EDCohortDynamicsMod, only : InitPRTObject - use EDCohortDynamicsMod, only : InitPRTBoundaryConditions use FatesPlantHydraulicsMod, only : InitHydrCohort use FatesInterfaceTypesMod, only : nlevsclass + use FatesInterfaceTypesMod, only : nlevdamage use FatesLitterMod, only : litter_type - use FatesLitterMod, only : ncwd + use FatesLitterMod, only : ncwd, nfsc use FatesLitterMod, only : ndcmpy - use EDTypesMod, only : nfsc + use EDTypesMod, only : area + use EDParamsMod, only : nlevleaf use PRTGenericMod, only : prt_global 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 @@ -80,13 +86,13 @@ module FatesRestartInterfaceMod integer :: ir_npatch_si integer :: ir_cd_status_si - integer :: ir_dd_status_si integer :: ir_nchill_days_si integer :: ir_ncold_days_si - integer :: ir_leafondate_si - integer :: ir_leafoffdate_si - integer :: ir_dleafondate_si - integer :: ir_dleafoffdate_si + integer :: ir_cleafondate_si + integer :: ir_cleafoffdate_si + integer :: ir_cndaysleafon_si + integer :: ir_cndaysleafoff_si + integer :: ir_phenmodeldate_si integer :: ir_acc_ni_si integer :: ir_gdd_si integer :: ir_snow_depth_si @@ -94,15 +100,26 @@ module FatesRestartInterfaceMod integer :: ir_ncohort_pa integer :: ir_canopy_layer_co integer :: ir_canopy_layer_yesterday_co + integer :: ir_crowndamage_co integer :: ir_canopy_trim_co + integer :: ir_l2fr_co + + integer :: ir_cx_int_co + integer :: ir_emadcxdt_co + integer :: ir_cx0_co + integer :: ir_cnplimiter_co + integer :: ir_daily_nh4_uptake_co + integer :: ir_daily_no3_uptake_co + integer :: ir_daily_n_fixation_co + integer :: ir_daily_p_uptake_co + integer :: ir_daily_n_demand_co + integer :: ir_daily_p_demand_co + integer :: ir_size_class_lasttimestep_co integer :: ir_dbh_co integer :: ir_coage_co integer :: ir_g_sb_laweight_co integer :: ir_height_co - integer :: ir_laimemory_co - integer :: ir_sapwmemory_co - integer :: ir_structmemory_co integer :: ir_nplant_co integer :: ir_gpp_acc_co integer :: ir_npp_acc_co @@ -110,28 +127,20 @@ module FatesRestartInterfaceMod integer :: ir_gpp_acc_hold_co integer :: ir_npp_acc_hold_co integer :: ir_resp_acc_hold_co - integer :: ir_resp_m_def_co + integer :: ir_resp_excess_co integer :: ir_bmort_co integer :: ir_hmort_co integer :: ir_cmort_co integer :: ir_frmort_co integer :: ir_smort_co integer :: ir_asmort_co + integer :: ir_dgmort_co integer :: ir_c_area_co integer :: ir_treelai_co integer :: ir_treesai_co integer :: ir_canopy_layer_tlai_pa - integer :: ir_daily_nh4_uptake_co - integer :: ir_daily_no3_uptake_co - integer :: ir_daily_p_uptake_co - integer :: ir_daily_c_efflux_co - integer :: ir_daily_n_efflux_co - integer :: ir_daily_p_efflux_co - integer :: ir_daily_n_demand_co - integer :: ir_daily_p_demand_co - integer :: ir_daily_n_need_co - integer :: ir_daily_p_need_co + !Logging integer :: ir_lmort_direct_co @@ -148,14 +157,25 @@ module FatesRestartInterfaceMod ! Running Means integer :: ir_tveg24_pa integer :: ir_tveglpa_pa + 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 + + integer :: ir_ddbhdt_co integer :: ir_resp_tstep_co integer :: ir_pft_co integer :: ir_status_co + integer :: ir_efleaf_co + integer :: ir_effnrt_co + integer :: ir_efstem_co integer :: ir_isnew_co ! Litter @@ -187,7 +207,15 @@ module FatesRestartInterfaceMod integer :: ir_litter_moisture_pa_nfsc ! Site level - integer :: ir_watermem_siwm + integer :: ir_dd_status_sift + integer :: ir_dleafondate_sift + integer :: ir_dleafoffdate_sift + integer :: ir_dndaysleafon_sift + integer :: ir_dndaysleafoff_sift + integer :: ir_elong_factor_sift + integer :: ir_liqvolmem_siwmft + integer :: ir_smpmem_siwmft + integer :: ir_recl2fr_sipfcl integer :: ir_vegtempmem_sitm integer :: ir_seed_bank_sift integer :: ir_spread_si @@ -204,23 +232,52 @@ module FatesRestartInterfaceMod integer :: ir_growflx_fusion_siscpf integer :: ir_demorate_sisc integer :: ir_promrate_sisc - integer :: ir_termcflux_cano_si - integer :: ir_termcflux_usto_si + integer :: ir_termcarea_cano_si + integer :: ir_termcarea_usto_si + + integer :: ir_imortcarea_si + integer :: ir_fmortcarea_cano_si + integer :: ir_fmortcarea_usto_si + integer :: ir_termcflux_cano_sipft + integer :: ir_termcflux_usto_sipft integer :: ir_democflux_si integer :: ir_promcflux_si - integer :: ir_imortcflux_si - integer :: ir_fmortcflux_cano_si - integer :: ir_fmortcflux_usto_si + integer :: ir_imortcflux_sipft + integer :: ir_fmortcflux_cano_sipft + integer :: ir_fmortcflux_usto_sipft + integer :: ir_abg_term_flux_siscpf + integer :: ir_abg_imort_flux_siscpf + integer :: ir_abg_fmort_flux_siscpf + integer :: ir_cwdagin_flxdg integer :: ir_cwdbgin_flxdg integer :: ir_leaflittin_flxdg integer :: ir_rootlittin_flxdg - integer :: ir_efflux_flxdg - integer :: ir_uptake_flxdg integer :: ir_oldstock_mbal integer :: ir_errfates_mbal + integer :: ir_woodprod_mbal integer :: ir_prt_base ! Base index for all PRT variables + ! site-level input seed from dispersal + integer :: ir_seed_in_sift + integer :: ir_seed_out_sift + + ! Damage x damage or damage x size + integer :: ir_imortrate_sicdpf + integer :: ir_termnindiv_cano_sicdpf + integer :: ir_termnindiv_usto_sicdpf + integer :: ir_fmortrate_cano_sicdpf + integer :: ir_fmortrate_usto_sicdpf + integer :: ir_imortcflux_sicdsc + integer :: ir_termcflux_cano_sicdsc + integer :: ir_termcflux_usto_sicdsc + integer :: ir_fmortcflux_cano_sicdsc + integer :: ir_fmortcflux_usto_sicdsc + integer :: ir_crownarea_cano_si + integer :: ir_crownarea_usto_si + integer :: ir_emanpp_si + + ! Hydraulic indices integer :: ir_hydro_th_ag_covec integer :: ir_hydro_th_troot @@ -420,8 +477,7 @@ subroutine set_dim_indices(this, dk_name, idim, dim_index) write(fates_log(), *) 'Trying to define dimension size to a dim-type structure' write(fates_log(), *) 'but the dimension index does not exist' write(fates_log(), *) 'type: ',dk_name,' ndims: ',this%dim_kinds(ityp)%ndims,' input dim:',idim - stop - !end_run + call endrun(msg=errMsg(sourcefile, __LINE__)) end if if (idim == 1) then @@ -606,10 +662,6 @@ subroutine define_restart_vars(this, initialize_variables) long_name='status flag for cold deciduous plants', units='unitless', flushval = flushinvalid, & hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_cd_status_si ) - call this%set_restart_var(vname='fates_drought_dec_status', vtype=site_int, & - long_name='status flag for drought deciduous plants', units='unitless', flushval = flushinvalid, & - hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_dd_status_si ) - call this%set_restart_var(vname='fates_chilling_days', vtype=site_int, & long_name='chilling day counter', units='unitless', flushval = flushinvalid, & hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_nchill_days_si ) @@ -618,21 +670,25 @@ subroutine define_restart_vars(this, initialize_variables) long_name='cold day counter', units='unitless', flushval = flushinvalid, & hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_ncold_days_si ) - call this%set_restart_var(vname='fates_leafondate', vtype=site_int, & - long_name='the day of year for leaf on', units='day of year', flushval = flushinvalid, & - hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_leafondate_si ) + call this%set_restart_var(vname='fates_cold_leafondate', vtype=site_int, & + long_name='the model day of last cold leaf on', units='absolute integer day', flushval = flushinvalid, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_cleafondate_si ) - call this%set_restart_var(vname='fates_leafoffdate', vtype=site_int, & - long_name='the day of year for leaf off', units='day of year', flushval = flushinvalid, & - hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_leafoffdate_si ) + call this%set_restart_var(vname='fates_cold_leafoffdate', vtype=site_int, & + long_name='the model day last cold leaf off', units='absolute integer day', flushval = flushinvalid, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_cleafoffdate_si ) - call this%set_restart_var(vname='fates_drought_leafondate', vtype=site_int, & - long_name='the day of year for drought based leaf-on', units='day of year', flushval = flushinvalid, & - hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_dleafondate_si ) + call this%set_restart_var(vname='fates_cold_ndaysleafon', vtype=site_int, & + long_name='number of days since leaf on (cold deciduous)', units='days', flushval = flushinvalid, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_cndaysleafon_si ) - call this%set_restart_var(vname='fates_drought_leafoffdate', vtype=site_int, & - long_name='the day of year for drought based leaf-off', units='day of year', flushval = flushinvalid, & - hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_dleafoffdate_si ) + call this%set_restart_var(vname='fates_cold_ndaysleafoff', vtype=site_int, & + long_name='number of days since leaf off (cold deciduous)', units='days', flushval = flushinvalid, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_cndaysleafoff_si ) + + call this%set_restart_var(vname='fates_phen_model_date', vtype=site_int, & + long_name='integer model day used for phen timing', units='absolute integer day', flushval = flushinvalid, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_phenmodeldate_si ) call this%set_restart_var(vname='fates_acc_nesterov_id', vtype=site_r8, & long_name='a nesterov index accumulator', units='unitless', flushval = flushzero, & @@ -651,7 +707,6 @@ subroutine define_restart_vars(this, initialize_variables) units='kgC/m2', flushval = flushzero, & hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_trunk_product_si ) - ! ----------------------------------------------------------------------------------- ! Variables stored within cohort vectors ! Note: Some of these are multi-dimensional variables in the patch/site dimension @@ -685,7 +740,6 @@ subroutine define_restart_vars(this, initialize_variables) long_name='fates cohort - seed production', units='kgC/plant', flushval = flushinvalid, & hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_seed_prod_co ) - call this%set_restart_var(vname='fates_canopy_layer', vtype=cohort_int, & long_name='ed cohort - canopy_layer', units='unitless', flushval = flushinvalid, & hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_canopy_layer_co ) @@ -694,10 +748,68 @@ subroutine define_restart_vars(this, initialize_variables) long_name='ed cohort - canopy_layer_yesterday', units='unitless', flushval = flushzero, & hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_canopy_layer_yesterday_co ) + call this%set_restart_var(vname='fates_crowndamage', vtype=cohort_int, & + long_name='ed cohort - crowndamage class', units='unitless', flushval = flushinvalid, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_crowndamage_co ) + call this%set_restart_var(vname='fates_canopy_trim', vtype=cohort_r8, & long_name='ed cohort - canopy_trim', units='fraction', flushval = flushzero, & hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_canopy_trim_co ) + call this%set_restart_var(vname='fates_l2fr', vtype=cohort_r8, & + long_name='ed cohort - l2fr', units='fraction', flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_l2fr_co ) + + if(hlm_parteh_mode .eq. prt_cnp_flex_allom_hyp) then + + call this%set_restart_var(vname='fates_cx_int', vtype=cohort_r8, & + long_name='ed cohort - emacx', units='fraction', flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_cx_int_co ) + + call this%set_restart_var(vname='fates_emadcxdt', vtype=cohort_r8, & + long_name='ed cohort - emadcxdt', units='fraction', flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_emadcxdt_co ) + + call this%set_restart_var(vname='fates_cx0', vtype=cohort_r8, & + long_name='ed cohort - cx0', units='fraction', flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_cx0_co ) + + call this%set_restart_var(vname='fates_cnplimiter', vtype=cohort_r8, & + long_name='ed cohort - cnp limiter index', units='index', flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_cnplimiter_co ) + + call this%set_restart_var(vname='fates_daily_nh4_uptake', vtype=cohort_r8, & + long_name='fates cohort- daily ammonium [NH4] uptake', & + units='kg/plant/day', flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_daily_nh4_uptake_co ) + + call this%set_restart_var(vname='fates_daily_no3_uptake', vtype=cohort_r8, & + long_name='fates cohort- daily ammonium [NO3] uptake', & + units='kg/plant/day', flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_daily_no3_uptake_co ) + + call this%set_restart_var(vname='fates_daily_n_fixation', vtype=cohort_r8, & + long_name='fates cohort- daily N symbiotic fixation', & + units='kg/plant/day', flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_daily_n_fixation_co ) + + call this%set_restart_var(vname='fates_daily_p_uptake', vtype=cohort_r8, & + long_name='fates cohort- daily phosphorus uptake', & + units='kg/plant/day', flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_daily_p_uptake_co ) + + call this%set_restart_var(vname='fates_daily_p_demand', vtype=cohort_r8, & + long_name='fates cohort- daily phosphorus demand', & + units='kgP/plant/day', flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_daily_p_demand_co ) + + call this%set_restart_var(vname='fates_daily_n_demand', vtype=cohort_r8, & + long_name='fates cohort- daily nitrogen demand', & + units='kgN/plant/day', flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_daily_n_demand_co ) + + end if + call this%set_restart_var(vname='fates_size_class_lasttimestep', vtype=cohort_int, & long_name='ed cohort - size-class last timestep', units='index', flushval = flushzero, & hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_size_class_lasttimestep_co ) @@ -714,21 +826,6 @@ subroutine define_restart_vars(this, initialize_variables) long_name='ed cohort - plant height', units='m', flushval = flushzero, & hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_height_co ) - call this%set_restart_var(vname='fates_laimemory', vtype=cohort_r8, & - long_name='ed cohort - target leaf biomass set from prev year', & - units='kgC/indiv', flushval = flushzero, & - hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_laimemory_co ) - - call this%set_restart_var(vname='fates_sapwmemory', vtype=cohort_r8, & - long_name='ed cohort - target sapwood biomass set from prev year', & - units='kgC/indiv', flushval = flushzero, & - hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_sapwmemory_co ) - - call this%set_restart_var(vname='fates_structmemory', vtype=cohort_r8, & - long_name='ed cohort - target structural biomass set from prev year', & - units='kgC/indiv', flushval = flushzero, & - hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_structmemory_co ) - call this%set_restart_var(vname='fates_nplant', vtype=cohort_r8, & long_name='ed cohort - number of plants in the cohort', & units='/patch', flushval = flushzero, & @@ -764,10 +861,10 @@ subroutine define_restart_vars(this, initialize_variables) units='kgC/indiv/year', flushval = flushzero, & hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_resp_acc_hold_co ) - call this%set_restart_var(vname='fates_resp_m_def', vtype=cohort_r8, & + call this%set_restart_var(vname='fates_resp_excess', vtype=cohort_r8, & long_name='ed cohort - maintenance respiration deficit', & units='kgC/indiv', flushval = flushzero, & - hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_resp_m_def_co ) + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_resp_excess_co ) call this%set_restart_var(vname='fates_bmort', vtype=cohort_r8, & long_name='ed cohort - background mortality rate', & @@ -784,55 +881,7 @@ subroutine define_restart_vars(this, initialize_variables) units='/year', flushval = flushzero, & hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_cmort_co ) - call this%set_restart_var(vname='fates_daily_nh4_uptake', vtype=cohort_r8, & - long_name='fates cohort- daily ammonium [NH4] uptake', & - units='kg/plant/day', flushval = flushzero, & - hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_daily_nh4_uptake_co ) - - call this%set_restart_var(vname='fates_daily_no3_uptake', vtype=cohort_r8, & - long_name='fates cohort- daily ammonium [NO3] uptake', & - units='kg/plant/day', flushval = flushzero, & - hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_daily_no3_uptake_co ) - - call this%set_restart_var(vname='fates_daily_p_uptake', vtype=cohort_r8, & - long_name='fates cohort- daily phosphorus uptake', & - units='kg/plant/day', flushval = flushzero, & - hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_daily_p_uptake_co ) - - call this%set_restart_var(vname='fates_daily_c_efflux', vtype=cohort_r8, & - long_name='fates cohort- daily carbon efflux', & - units='kg/plant/day', flushval = flushzero, & - hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_daily_c_efflux_co ) - - call this%set_restart_var(vname='fates_daily_n_efflux', vtype=cohort_r8, & - long_name='fates cohort- daily nitrogen efflux', & - units='kg/plant/day', flushval = flushzero, & - hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_daily_n_efflux_co ) - - call this%set_restart_var(vname='fates_daily_p_efflux', vtype=cohort_r8, & - long_name='fates cohort- daily phosphorus efflux', & - units='kg/plant/day', flushval = flushzero, & - hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_daily_p_efflux_co ) - - call this%set_restart_var(vname='fates_daily_p_demand', vtype=cohort_r8, & - long_name='fates cohort- daily phosphorus demand', & - units='kgP/plant/day', flushval = flushzero, & - hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_daily_p_demand_co ) - - call this%set_restart_var(vname='fates_daily_n_demand', vtype=cohort_r8, & - long_name='fates cohort- daily nitrogen demand', & - units='kgN/plant/day', flushval = flushzero, & - hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_daily_n_demand_co ) - - call this%set_restart_var(vname='fates_daily_p_need', vtype=cohort_r8, & - long_name='fates cohort- daily phosphorus need', & - units='kgP/plant/day', flushval = flushzero, & - hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_daily_p_need_co ) - - call this%set_restart_var(vname='fates_daily_n_need', vtype=cohort_r8, & - long_name='fates cohort- daily nitrogen need', & - units='kgN/plant/day', flushval = flushzero, & - hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_daily_n_need_co ) + call this%set_restart_var(vname='fates_frmort', vtype=cohort_r8, & long_name='ed cohort - freezing mortality rate', & @@ -849,6 +898,11 @@ subroutine define_restart_vars(this, initialize_variables) units = '/year', flushval = flushzero, & hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_asmort_co ) + call this%set_restart_var(vname='fates_dgmort', vtype=cohort_r8, & + long_name='ed cohort - damage mortality rate', & + units = '/year', flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_dgmort_co ) + call this%set_restart_var(vname='fates_lmort_direct', vtype=cohort_r8, & long_name='ed cohort - directly logging mortality rate', & units='%/event', flushval = flushzero, & @@ -882,6 +936,18 @@ subroutine define_restart_vars(this, initialize_variables) long_name='ed cohort - plant phenology status', units='unitless', flushval = flushzero, & hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_status_co ) + call this%set_restart_var(vname='fates_efleaf_coh', vtype=cohort_r8, & + long_name='ed cohort - leaf elongation factor', units='unitless', flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_efleaf_co ) + + call this%set_restart_var(vname='fates_effnrt_coh', vtype=cohort_r8, & + long_name='ed cohort - fine-root elongation factor', units='unitless', flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_effnrt_co ) + + call this%set_restart_var(vname='fates_efstem_coh', vtype=cohort_r8, & + long_name='ed cohort - stem elongation factor', units='unitless', flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_efstem_co ) + call this%set_restart_var(vname='fates_isnew', vtype=cohort_int, & long_name='ed cohort - binary flag specifying if a plant has experienced a full day cycle', & units='0/1', flushval = flushone, & @@ -937,127 +1003,124 @@ subroutine define_restart_vars(this, initialize_variables) long_name='are of the ED patch', units='m2', flushval = flushzero, & hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_area_pa ) - call this%set_restart_var(vname='fates_scorch_ht_pa_pft', vtype=cohort_r8, & - long_name='scorch height', units='m', flushval = flushzero, & - hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_scorch_ht_pa_pft) - - call this%set_restart_var(vname='fates_litter_moisture_pa_nfsc', vtype=cohort_r8, & - long_name='scorch height', units='m', flushval = flushzero, & - hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_litter_moisture_pa_nfsc) - + if(hlm_use_sp.eq.ifalse)then + call this%set_restart_var(vname='fates_scorch_ht_pa_pft', vtype=cohort_r8, & + long_name='scorch height', units='m', flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_scorch_ht_pa_pft) + + call this%set_restart_var(vname='fates_litter_moisture_pa_nfsc', vtype=cohort_r8, & + long_name='scorch height', units='m', flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_litter_moisture_pa_nfsc) + end if + ! Site Level Diagnostics over multiple nutrients ! Patch Level Litter Pools are potentially multi-element - - call this%RegisterCohortVector(symbol_base='fates_ag_cwd', vtype=cohort_r8, & + if(hlm_use_sp.eq.ifalse)then + call this%RegisterCohortVector(symbol_base='fates_ag_cwd', vtype=cohort_r8, & long_name_base='above ground CWD', & units='kg/m2', veclength=num_elements, flushval = flushzero, & hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_agcwd_litt) - call this%RegisterCohortVector(symbol_base='fates_bg_cwd', vtype=cohort_r8, & + call this%RegisterCohortVector(symbol_base='fates_bg_cwd', vtype=cohort_r8, & long_name_base='below ground CWD', & units='kg/m2', veclength=num_elements, flushval = flushzero, & hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_bgcwd_litt) - call this%RegisterCohortVector(symbol_base='fates_leaf_fines', vtype=cohort_r8, & + call this%RegisterCohortVector(symbol_base='fates_leaf_fines', vtype=cohort_r8, & long_name_base='above ground leaf litter', & units='kg/m2', veclength=num_elements, flushval = flushzero, & hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_leaf_litt) - call this%RegisterCohortVector(symbol_base='fates_fnrt_fines', vtype=cohort_r8, & + call this%RegisterCohortVector(symbol_base='fates_fnrt_fines', vtype=cohort_r8, & long_name_base='fine root litter', & units='kg/m2', veclength=num_elements, flushval = flushzero, & hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_fnrt_litt) - call this%RegisterCohortVector(symbol_base='fates_seed', vtype=cohort_r8, & + call this%RegisterCohortVector(symbol_base='fates_seed', vtype=cohort_r8, & long_name_base='seed bank (non-germinated)', & units='kg/m2', veclength=num_elements, flushval = flushzero, & hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_seed_litt) - call this%RegisterCohortVector(symbol_base='fates_seedgerm', vtype=cohort_r8, & - long_name_base='seed bank (germinated)', & - units='kg/m2', veclength=num_elements, flushval = flushzero, & - hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_seedgerm_litt) + call this%RegisterCohortVector(symbol_base='fates_seedgerm', vtype=cohort_r8, & + long_name_base='seed bank (germinated)', & + units='kg/m2', veclength=num_elements, flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_seedgerm_litt) - call this%RegisterCohortVector(symbol_base='fates_seed_frag', vtype=cohort_r8, & + call this%RegisterCohortVector(symbol_base='fates_seed_frag', vtype=cohort_r8, & long_name_base='seed bank fragmentation flux (non-germinated)', & units='kg/m2', veclength=num_elements, flushval = flushzero, & hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_seed_decay_litt) - call this%RegisterCohortVector(symbol_base='fates_seedgerm_frag', vtype=cohort_r8, & - long_name_base='seed bank fragmentation flux (germinated)', & - units='kg/m2', veclength=num_elements, flushval = flushzero, & - hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_seedgerm_decay_litt) + call this%RegisterCohortVector(symbol_base='fates_seedgerm_frag', vtype=cohort_r8, & + long_name_base='seed bank fragmentation flux (germinated)', & + units='kg/m2', veclength=num_elements, flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_seedgerm_decay_litt) - call this%RegisterCohortVector(symbol_base='fates_ag_cwd_frag', vtype=cohort_r8, & + call this%RegisterCohortVector(symbol_base='fates_ag_cwd_frag', vtype=cohort_r8, & long_name_base='above ground CWD frag flux', & units='kg/m2/day', veclength=num_elements, flushval = flushzero, & hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_agcwd_frag_litt) - call this%RegisterCohortVector(symbol_base='fates_bg_cwd_frag', vtype=cohort_r8, & + call this%RegisterCohortVector(symbol_base='fates_bg_cwd_frag', vtype=cohort_r8, & long_name_base='below ground CWD frag flux', & units='kg/m2/day', veclength=num_elements, flushval = flushzero, & hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_bgcwd_frag_litt) - call this%RegisterCohortVector(symbol_base='fates_lfines_frag', vtype=cohort_r8, & + call this%RegisterCohortVector(symbol_base='fates_lfines_frag', vtype=cohort_r8, & long_name_base='frag flux from leaf fines', & units='kg/m2/day', veclength=num_elements, flushval = flushzero, & hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_lfines_frag_litt) - call this%RegisterCohortVector(symbol_base='fates_rfines_frag', vtype=cohort_r8, & + call this%RegisterCohortVector(symbol_base='fates_rfines_frag', vtype=cohort_r8, & long_name_base='frag flux from froot fines', & units='kg/m2/day', veclength=num_elements, flushval = flushzero, & hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_rfines_frag_litt) - - + end if + ! Site level flux diagnostics for each element - - call this%RegisterCohortVector(symbol_base='fates_cwdagin', vtype=cohort_r8, & + if(hlm_use_sp.eq.ifalse)then + call this%RegisterCohortVector(symbol_base='fates_cwdagin', vtype=cohort_r8, & long_name_base='Input flux of AG CWD', & units='kg/ha', veclength=num_elements, flushval = flushzero, & hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_cwdagin_flxdg) - call this%RegisterCohortVector(symbol_base='fates_cwdbgin', vtype=cohort_r8, & + call this%RegisterCohortVector(symbol_base='fates_cwdbgin', vtype=cohort_r8, & long_name_base='Input flux of BG CWD', & units='kg/ha', veclength=num_elements, flushval = flushzero, & hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_cwdbgin_flxdg) - call this%RegisterCohortVector(symbol_base='fates_leaflittin', vtype=cohort_r8, & + call this%RegisterCohortVector(symbol_base='fates_leaflittin', vtype=cohort_r8, & long_name_base='Input flux of leaf litter', & units='kg/ha', veclength=num_elements, flushval = flushzero, & hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_leaflittin_flxdg) - call this%RegisterCohortVector(symbol_base='fates_rootlittin', vtype=cohort_r8, & - long_name_base='Input flux of root litter', & - units='kg/ha', veclength=num_elements, flushval = flushzero, & - hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_rootlittin_flxdg) - - call this%RegisterCohortVector(symbol_base='fates_efflux_scpf', vtype=cohort_r8, & - long_name_base='Efflux from plants to soil through roots', & - units='kg/day/ha', veclength=num_elements, flushval = flushzero, & - hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_efflux_flxdg) - - call this%RegisterCohortVector(symbol_base='fates_uptake_scpf', vtype=cohort_r8, & - long_name_base='Daily uptake for plants through roots', & - units='kg/day/ha', veclength=num_elements, flushval = flushzero, & - hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_uptake_flxdg) - - - ! Site level Mass Balance State Accounting + call this%RegisterCohortVector(symbol_base='fates_rootlittin', vtype=cohort_r8, & + long_name_base='Input flux of root litter', & + units='kg/ha', veclength=num_elements, flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_rootlittin_flxdg) - call this%RegisterCohortVector(symbol_base='fates_oldstock', vtype=site_r8, & - long_name_base='Previous total mass of all fates state variables', & - units='kg/ha', veclength=num_elements, flushval = flushzero, & - hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_oldstock_mbal) + ! Site level Mass Balance State Accounting - call this%RegisterCohortVector(symbol_base='fates_errfates', vtype=site_r8, & - long_name_base='Previous total mass of error fates state variables', & - units='kg/ha', veclength=num_elements, flushval = flushzero, & - hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_errfates_mbal) + call this%RegisterCohortVector(symbol_base='fates_oldstock', vtype=site_r8, & + long_name_base='Previous total mass of all fates state variables', & + units='kg/ha', veclength=num_elements, flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_oldstock_mbal) + call this%RegisterCohortVector(symbol_base='fates_errfates', vtype=site_r8, & + long_name_base='Previous total mass of error fates state variables', & + units='kg/ha', veclength=num_elements, flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_errfates_mbal) + end if + + call this%RegisterCohortVector(symbol_base='fates_woodproduct', vtype=site_r8, & + long_name_base='Current wood product flux', & + units='kg/m2/day', veclength=num_elements, flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_woodprod_mbal) + ! Only register satellite phenology related restart variables if it is turned on! if(hlm_use_sp .eq. itrue) then @@ -1154,10 +1217,44 @@ subroutine define_restart_vars(this, initialize_variables) ! site x time level vars ! - call this%set_restart_var(vname='fates_water_memory', vtype=cohort_r8, & + call this%set_restart_var(vname='fates_drought_dec_status', vtype=cohort_int, & + long_name='status flag for drought deciduous plants', units='unitless', flushval = flushinvalid, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_dd_status_sift ) + + call this%set_restart_var(vname='fates_drought_leafondate', vtype=cohort_int, & + long_name='the day of year for drought based leaf-on', units='day of year', flushval = flushinvalid, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_dleafondate_sift ) + + call this%set_restart_var(vname='fates_drought_leafoffdate', vtype=cohort_int, & + long_name='the day of year for drought based leaf-off', units='day of year', flushval = flushinvalid, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_dleafoffdate_sift ) + + call this%set_restart_var(vname='fates_drought_ndaysleafon', vtype=cohort_int, & + long_name='number of days since leaf on (drought deciduous)', units='days', flushval = flushinvalid, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_dndaysleafon_sift ) + + call this%set_restart_var(vname='fates_drought_ndaysleafoff', vtype=cohort_int, & + long_name='number of days since leaf off (drought deciduous)', units='days', flushval = flushinvalid, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_dndaysleafoff_sift ) + + call this%set_restart_var(vname='fates_elong_factor', vtype=cohort_r8, & + long_name='leaf elongation factor (0 - completely abscissed; 1 - completely flushed)', units='unitless', flushval = flushinvalid, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_elong_factor_sift ) + + call this%set_restart_var(vname='fates_recruit_l2fr', vtype=cohort_r8, & + long_name='site-level mean recruit l2frs, by pft x canopy layer', & + units='-', flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_recl2fr_sipfcl) + + call this%set_restart_var(vname='fates_liqvol_memory', vtype=cohort_r8, & long_name='last 10 days of volumetric soil water, by site x day-index', & units='m3/m3', flushval = flushzero, & - hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_watermem_siwm ) + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_liqvolmem_siwmft ) + + call this%set_restart_var(vname='fates_smp_memory', vtype=cohort_r8, & + long_name='last 10 days of soil matric potential, by site x day-index', & + units='mm', flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_smpmem_siwmft ) call this%set_restart_var(vname='fates_vegtemp_memory', vtype=cohort_r8, & long_name='last 10 days of 24-hour vegetation temperature, by site x day-index', & @@ -1179,6 +1276,15 @@ subroutine define_restart_vars(this, initialize_variables) units='0/1', flushval = flushzero, & hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_area_pft_sift) + call this%set_restart_var(vname='fates_seed_in_site', vtype=cohort_r8, & + long_name='Site-level seed mass input from neighboring gridcells per pft', & + units='kg', flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_seed_in_sift ) + + call this%set_restart_var(vname='fates_seed_out_site', vtype=cohort_r8, & + long_name='Site-level seed mass output to neighboring gridcells per pft', & + units='kg', flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_seed_out_sift ) call this%set_restart_var(vname='fates_fmortrate_canopy', vtype=cohort_r8, & long_name='fates diagnostics on fire mortality canopy', & @@ -1194,7 +1300,7 @@ subroutine define_restart_vars(this, initialize_variables) long_name='fates diagnostics on impact mortality', & units='indiv/ha/year', flushval = flushzero, & hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_imortrate_siscpf) - + call this%set_restart_var(vname='fates_fmortrate_crown', vtype=cohort_r8, & long_name='fates diagnostics on crown fire mortality', & units='indiv/ha/year', flushval = flushzero, & @@ -1230,30 +1336,50 @@ subroutine define_restart_vars(this, initialize_variables) units='indiv/ha/da', flushval = flushzero, & hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_promrate_sisc) - call this%set_restart_var(vname='fates_imortcflux', vtype=site_r8, & + call this%set_restart_var(vname='fates_imortcflux', vtype=cohort_r8, & long_name='biomass of indivs killed due to impact mort', & units='kgC/ha/day', flushval = flushzero, & - hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_imortcflux_si) + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_imortcflux_sipft) - call this%set_restart_var(vname='fates_fmortcflux_canopy', vtype=site_r8, & + call this%set_restart_var(vname='fates_imortcarea', vtype=site_r8, & + long_name='crownarea of indivs killed due to impact mort', & + units='m2/ha/day', flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_imortcarea_si) + + call this%set_restart_var(vname='fates_fmortcflux_canopy', vtype=cohort_r8, & long_name='fates diagnostic biomass of canopy fire', & units='gC/m2/sec', flushval = flushzero, & - hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_fmortcflux_cano_si) + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_fmortcflux_cano_sipft) - call this%set_restart_var(vname='fates_fmortcflux_ustory', vtype=site_r8, & + call this%set_restart_var(vname='fates_fmortcflux_ustory', vtype=cohort_r8, & long_name='fates diagnostic biomass of understory fire', & units='gC/m2/sec', flushval = flushzero, & - hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_fmortcflux_usto_si) + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_fmortcflux_usto_sipft) - call this%set_restart_var(vname='fates_termcflux_canopy', vtype=site_r8, & + call this%set_restart_var(vname='fates_termcflux_canopy', vtype=cohort_r8, & long_name='fates diagnostic term carbon flux canopy', & units='', flushval = flushzero, & - hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_termcflux_cano_si ) + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_termcflux_cano_sipft ) - call this%set_restart_var(vname='fates_termcflux_ustory', vtype=site_r8, & + call this%set_restart_var(vname='fates_termcflux_ustory', vtype=cohort_r8, & long_name='fates diagnostic term carbon flux understory', & units='', flushval = flushzero, & - hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_termcflux_usto_si ) + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_termcflux_usto_sipft ) + + call this%set_restart_var(vname='fates_abg_term_flux', vtype=cohort_r8, & + long_name='fates aboveground biomass loss from termination mortality', & + units='', flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_abg_term_flux_siscpf ) + + call this%set_restart_var(vname='fates_abg_imort_flux', vtype=cohort_r8, & + long_name='fates aboveground biomass loss from impact mortality', & + units='', flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_abg_imort_flux_siscpf ) + + call this%set_restart_var(vname='fates_abg_fmort_flux', vtype=cohort_r8, & + long_name='fates aboveground biomass loss from fire mortality', & + units='', flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_abg_fmort_flux_siscpf ) call this%set_restart_var(vname='fates_democflux', vtype=site_r8, & long_name='fates diagnostic demotion carbon flux', & @@ -1265,15 +1391,128 @@ subroutine define_restart_vars(this, initialize_variables) units='', flushval = flushzero, & hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_promcflux_si ) + call this%set_restart_var(vname='fates_fmortcarea_canopy', vtype=site_r8, & + long_name='fates diagnostic crownarea of canopy fire', & + units='m2/sec', flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_fmortcarea_cano_si) + + call this%set_restart_var(vname='fates_fmortcarea_ustory', vtype=site_r8, & + long_name='fates diagnostic crownarea of understory fire', & + units='m2/sec', flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_fmortcarea_usto_si) + + call this%set_restart_var(vname='fates_termcarea_canopy', vtype=site_r8, & + long_name='fates diagnostic term crownarea canopy', & + units='', flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_termcarea_cano_si ) + + call this%set_restart_var(vname='fates_termcarea_ustory', vtype=site_r8, & + long_name='fates diagnostic term crownarea understory', & + units='', flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_termcarea_usto_si ) + + ! Damage variables + call this%set_restart_var(vname='fates_imortrate_dam', vtype=cohort_r8, & + long_name='fates diagnostics on impact mortality by damage class', & + units='indiv/ha/year', flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_imortrate_sicdpf) + + call this%set_restart_var(vname='fates_termn_cano_dam', vtype=cohort_r8, & + long_name='fates diagnostics on termination mortality by damage class -canopy', & + units='indiv/ha/year', flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_termnindiv_cano_sicdpf) + + call this%set_restart_var(vname='fates_termn_usto_dam', vtype=cohort_r8, & + long_name='fates diagnostics on termination mortality by damage class -understory', & + units='indiv/ha/year', flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_termnindiv_usto_sicdpf) + + call this%set_restart_var(vname='fates_fmortrate_cano_dam', vtype=cohort_r8, & + long_name='fates diagnostics on fire mortality by damage class', & + units='indiv/ha/year', flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_fmortrate_cano_sicdpf) + + call this%set_restart_var(vname='fates_fmortrate_usto_dam', vtype=cohort_r8, & + long_name='fates diagnostics on fire mortality by damage class', & + units='indiv/ha/year', flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_fmortrate_usto_sicdpf) + + call this%set_restart_var(vname='fates_imortcflux_dam', vtype=cohort_r8, & + long_name='biomass of indivs killed due to impact mort by damage class', & + units='kgC/ha/day', flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_imortcflux_sicdsc) + + call this%set_restart_var(vname='fates_termcflux_cano_dam', vtype=cohort_r8, & + long_name='biomass of indivs killed due to termination mort by damage class', & + units='kgC/ha/day', flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_termcflux_cano_sicdsc) + call this%set_restart_var(vname='fates_termcflux_usto_dam', vtype=cohort_r8, & + long_name='biomass of indivs killed due to termination mort by damage class', & + units='kgC/ha/day', flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_termcflux_usto_sicdsc) + + call this%set_restart_var(vname='fates_fmortcflux_cano_dam', vtype=cohort_r8, & + long_name='biomass of indivs killed due to fire mort by damage class', & + units='kgC/ha/day', flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_fmortcflux_cano_sicdsc) + + call this%set_restart_var(vname='fates_fmortcflux_usto_dam', vtype=cohort_r8, & + long_name='biomass of indivs killed due to fire mort by damage class', & + units='kgC/ha/day', flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_fmortcflux_usto_sicdsc) + + call this%set_restart_var(vname='fates_crownarea_canopy_damage', vtype=site_r8, & + 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_cano_si) + + call this%set_restart_var(vname='fates_crownarea_understory_damage', vtype=site_r8, & + 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) + + call this%set_restart_var(vname='fates_emanpp', vtype=site_r8, & + long_name='smoothed NPP (exp. moving avg) at the site level (for fixation)', & + units='kg/m2/yr', flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_emanpp_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) + 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) + call this%DefineRMeanRestartVar(vname='fates_tveglongtermpatch',vtype=cohort_r8, & + long_name='long-term (T_home) running average (EMA) of patch veg temp for photo acclim', & + units='K', initialize=initialize_variables,ivar=ivar, index = ir_tveglongterm_pa) + ! (Keeping as an example) !call this%DefineRMeanRestartVar(vname='fates_tveglpacohort',vtype=cohort_r8, & ! long_name='running average (EMA) of cohort veg temp for photo acclim', & @@ -1674,12 +1913,13 @@ subroutine set_restart_vectors(this,nc,nsites,sites) use FatesInterfaceTypesMod, only : fates_maxElementsPerPatch use FatesInterfaceTypesMod, only : numpft use EDTypesMod, only : ed_site_type - use EDTypesMod, only : ed_cohort_type - use EDTypesMod, only : ed_patch_type - use EDTypesMod, only : maxSWb - use EDTypesMod, only : nclmax + use FatesCohortMod, only : fates_cohort_type + use FatesPatchMod, only : fates_patch_type + use EDParamsMod, only : maxSWb + use EDParamsMod, only : nclmax use EDTypesMod, only : numWaterMem use EDTypesMod, only : num_vegtemp_mem + use FatesInterfaceTypesMod, only : nlevdamage ! Arguments class(fates_restart_interface_type) :: this @@ -1709,11 +1949,14 @@ subroutine set_restart_vectors(this,nc,nsites,sites) integer :: io_idx_pa_dc ! each decomposability index integer :: io_idx_pa_ib ! each SW band (vis/ir) per patch (pa_ib) integer :: io_idx_si_wmem ! each water memory class within each site + integer :: io_idx_si_pfcl ! each pft x canopy layer within each site integer :: io_idx_si_lyr_shell ! site - layer x shell index integer :: io_idx_si_scpf ! each size-class x pft index within site integer :: io_idx_si_sc ! each size-class index within site integer :: io_idx_si_capf ! each cohort age-class x pft index within site integer :: io_idx_si_cacls ! each cohort age class index within site + integer :: io_idx_si_cdsc ! each damage-class x size class within site + integer :: io_idx_si_cdpf ! each damage-class x size x pft within site integer :: io_idx_si_cwd ! each site-cwd index integer :: io_idx_si_pft ! each site-pft index integer :: io_idx_si_vtmem ! indices for veg-temp memory at site @@ -1737,21 +1980,24 @@ subroutine set_restart_vectors(this,nc,nsites,sites) integer :: i_cacls ! loop counter for cohort age class integer :: i_cwd ! loop counter for cwd integer :: i_pft ! loop counter for pft - + integer :: i_cdam ! loop counter for damage + integer :: icdi ! loop counter for damage + integer :: icdj ! loop counter for damage + type(fates_restart_variable_type) :: rvar - type(ed_patch_type),pointer :: cpatch - type(ed_cohort_type),pointer :: ccohort + type(fates_patch_type),pointer :: cpatch + type(fates_cohort_type),pointer :: ccohort associate( rio_npatch_si => this%rvars(ir_npatch_si)%int1d, & rio_cd_status_si => this%rvars(ir_cd_status_si)%int1d, & - rio_dd_status_si => this%rvars(ir_dd_status_si)%int1d, & rio_nchill_days_si => this%rvars(ir_nchill_days_si)%int1d, & rio_ncold_days_si => this%rvars(ir_ncold_days_si)%int1d, & - rio_leafondate_si => this%rvars(ir_leafondate_si)%int1d, & - rio_leafoffdate_si => this%rvars(ir_leafoffdate_si)%int1d, & - rio_dleafondate_si => this%rvars(ir_dleafondate_si)%int1d, & - rio_dleafoffdate_si => this%rvars(ir_dleafoffdate_si)%int1d, & + rio_cleafondate_si => this%rvars(ir_cleafondate_si)%int1d, & + rio_cleafoffdate_si => this%rvars(ir_cleafoffdate_si)%int1d, & + rio_cndaysleafon_si => this%rvars(ir_cndaysleafon_si)%int1d, & + rio_cndaysleafoff_si => this%rvars(ir_cndaysleafoff_si)%int1d, & + rio_phenmodeldate_si => this%rvars(ir_phenmodeldate_si)%int1d, & rio_acc_ni_si => this%rvars(ir_acc_ni_si)%r81d, & rio_gdd_si => this%rvars(ir_gdd_si)%r81d, & rio_snow_depth_si => this%rvars(ir_snow_depth_si)%r81d, & @@ -1762,16 +2008,15 @@ subroutine set_restart_vectors(this,nc,nsites,sites) rio_solar_zenith_angle_pa => this%rvars(ir_solar_zenith_angle_pa)%r81d, & rio_canopy_layer_co => this%rvars(ir_canopy_layer_co)%int1d, & rio_canopy_layer_yesterday_co => this%rvars(ir_canopy_layer_yesterday_co)%r81d, & + rio_crowndamage_co => this%rvars(ir_crowndamage_co)%int1d, & rio_canopy_trim_co => this%rvars(ir_canopy_trim_co)%r81d, & + rio_l2fr_co => this%rvars(ir_l2fr_co)%r81d, & rio_seed_prod_co => this%rvars(ir_seed_prod_co)%r81d, & rio_size_class_lasttimestep => this%rvars(ir_size_class_lasttimestep_co)%int1d, & rio_dbh_co => this%rvars(ir_dbh_co)%r81d, & rio_coage_co => this%rvars(ir_coage_co)%r81d, & rio_g_sb_laweight_co => this%rvars(ir_g_sb_laweight_co)%r81d, & rio_height_co => this%rvars(ir_height_co)%r81d, & - rio_laimemory_co => this%rvars(ir_laimemory_co)%r81d, & - rio_sapwmemory_co => this%rvars(ir_sapwmemory_co)%r81d, & - rio_structmemory_co => this%rvars(ir_structmemory_co)%r81d, & rio_nplant_co => this%rvars(ir_nplant_co)%r81d, & rio_gpp_acc_co => this%rvars(ir_gpp_acc_co)%r81d, & rio_npp_acc_co => this%rvars(ir_npp_acc_co)%r81d, & @@ -1779,22 +2024,13 @@ subroutine set_restart_vectors(this,nc,nsites,sites) rio_gpp_acc_hold_co => this%rvars(ir_gpp_acc_hold_co)%r81d, & rio_resp_acc_hold_co => this%rvars(ir_resp_acc_hold_co)%r81d, & rio_npp_acc_hold_co => this%rvars(ir_npp_acc_hold_co)%r81d, & - rio_resp_m_def_co => this%rvars(ir_resp_m_def_co)%r81d, & + rio_resp_excess_co => this%rvars(ir_resp_excess_co)%r81d, & rio_bmort_co => this%rvars(ir_bmort_co)%r81d, & rio_hmort_co => this%rvars(ir_hmort_co)%r81d, & rio_cmort_co => this%rvars(ir_cmort_co)%r81d, & - rio_daily_nh4_uptake_co => this%rvars(ir_daily_nh4_uptake_co)%r81d, & - rio_daily_no3_uptake_co => this%rvars(ir_daily_no3_uptake_co)%r81d, & - rio_daily_p_uptake_co => this%rvars(ir_daily_p_uptake_co)%r81d, & - rio_daily_c_efflux_co => this%rvars(ir_daily_c_efflux_co)%r81d, & - rio_daily_n_efflux_co => this%rvars(ir_daily_n_efflux_co)%r81d, & - rio_daily_p_efflux_co => this%rvars(ir_daily_p_efflux_co)%r81d, & - rio_daily_n_demand_co => this%rvars(ir_daily_n_demand_co)%r81d, & - rio_daily_p_demand_co => this%rvars(ir_daily_p_demand_co)%r81d, & - rio_daily_n_need_co => this%rvars(ir_daily_n_need_co)%r81d, & - rio_daily_p_need_co => this%rvars(ir_daily_p_need_co)%r81d, & rio_smort_co => this%rvars(ir_smort_co)%r81d, & rio_asmort_co => this%rvars(ir_asmort_co)%r81d, & + rio_dgmort_co => this%rvars(ir_dgmort_co)%r81d, & rio_frmort_co => this%rvars(ir_frmort_co)%r81d, & rio_lmort_direct_co => this%rvars(ir_lmort_direct_co)%r81d, & rio_lmort_collateral_co => this%rvars(ir_lmort_collateral_co)%r81d, & @@ -1803,6 +2039,9 @@ subroutine set_restart_vectors(this,nc,nsites,sites) rio_resp_tstep_co => this%rvars(ir_resp_tstep_co)%r81d, & rio_pft_co => this%rvars(ir_pft_co)%int1d, & rio_status_co => this%rvars(ir_status_co)%int1d, & + rio_efleaf_co => this%rvars(ir_efleaf_co)%r81d, & + rio_effnrt_co => this%rvars(ir_effnrt_co)%r81d, & + rio_efstem_co => this%rvars(ir_efstem_co)%r81d, & rio_isnew_co => this%rvars(ir_isnew_co)%int1d, & rio_gnd_alb_dif_pasb => this%rvars(ir_gnd_alb_dif_pasb)%r81d, & rio_gnd_alb_dir_pasb => this%rvars(ir_gnd_alb_dir_pasb)%r81d, & @@ -1813,11 +2052,21 @@ subroutine set_restart_vectors(this,nc,nsites,sites) rio_agesinceanthrodist_pa => this%rvars(ir_agesinceanthrodist_pa)%r81d, & rio_nocomp_pft_label_pa => this%rvars(ir_nocomp_pft_label_pa)%int1d, & rio_area_pa => this%rvars(ir_area_pa)%r81d, & - rio_watermem_siwm => this%rvars(ir_watermem_siwm)%r81d, & + rio_dd_status_sift => this%rvars(ir_dd_status_sift)%int1d, & + rio_dleafondate_sift => this%rvars(ir_dleafondate_sift)%int1d, & + rio_dleafoffdate_sift => this%rvars(ir_dleafoffdate_sift)%int1d, & + rio_dndaysleafon_sift => this%rvars(ir_dndaysleafon_sift)%int1d, & + rio_dndaysleafoff_sift => this%rvars(ir_dndaysleafoff_sift)%int1d, & + rio_elong_factor_sift => this%rvars(ir_elong_factor_sift)%r81d, & + rio_liqvolmem_siwmft => this%rvars(ir_liqvolmem_siwmft)%r81d, & + rio_smpmem_siwmft => this%rvars(ir_smpmem_siwmft)%r81d, & + rio_recl2fr_sipfcl => this%rvars(ir_recl2fr_sipfcl)%r81d, & rio_vegtempmem_sitm => this%rvars(ir_vegtempmem_sitm)%r81d, & rio_recrate_sift => this%rvars(ir_recrate_sift)%r81d, & rio_use_this_pft_sift => this%rvars(ir_use_this_pft_sift)%int1d, & rio_area_pft_sift => this%rvars(ir_area_pft_sift)%r81d, & + rio_seed_in_sift => this%rvars(ir_seed_in_sift)%r81d, & + rio_seed_out_sift => this%rvars(ir_seed_out_sift)%r81d, & rio_fmortrate_cano_siscpf => this%rvars(ir_fmortrate_cano_siscpf)%r81d, & rio_fmortrate_usto_siscpf => this%rvars(ir_fmortrate_usto_siscpf)%r81d, & rio_imortrate_siscpf => this%rvars(ir_imortrate_siscpf)%r81d, & @@ -1828,15 +2077,37 @@ subroutine set_restart_vectors(this,nc,nsites,sites) rio_growflx_fusion_siscpf => this%rvars(ir_growflx_fusion_siscpf)%r81d, & rio_demorate_sisc => this%rvars(ir_demorate_sisc)%r81d, & rio_promrate_sisc => this%rvars(ir_promrate_sisc)%r81d, & - rio_termcflux_cano_si => this%rvars(ir_termcflux_cano_si)%r81d, & - rio_termcflux_usto_si => this%rvars(ir_termcflux_usto_si)%r81d, & + rio_termcarea_cano_si => this%rvars(ir_termcarea_cano_si)%r81d, & + rio_termcarea_usto_si => this%rvars(ir_termcarea_usto_si)%r81d, & + + rio_imortcarea_si => this%rvars(ir_imortcarea_si)%r81d, & + rio_fmortcarea_cano_si => this%rvars(ir_fmortcarea_cano_si)%r81d, & + rio_fmortcarea_usto_si => this%rvars(ir_fmortcarea_usto_si)%r81d, & + rio_termcflux_cano_sipft => this%rvars(ir_termcflux_cano_sipft)%r81d, & + rio_termcflux_usto_sipft => this%rvars(ir_termcflux_usto_sipft)%r81d, & rio_democflux_si => this%rvars(ir_democflux_si)%r81d, & rio_promcflux_si => this%rvars(ir_promcflux_si)%r81d, & - rio_imortcflux_si => this%rvars(ir_imortcflux_si)%r81d, & - rio_fmortcflux_cano_si => this%rvars(ir_fmortcflux_cano_si)%r81d, & - rio_fmortcflux_usto_si => this%rvars(ir_fmortcflux_usto_si)%r81d) - - + rio_imortcflux_sipft => this%rvars(ir_imortcflux_sipft)%r81d, & + rio_fmortcflux_cano_sipft => this%rvars(ir_fmortcflux_cano_sipft)%r81d, & + rio_fmortcflux_usto_sipft => this%rvars(ir_fmortcflux_usto_sipft)%r81d, & + rio_abg_imort_flux_siscpf => this%rvars(ir_abg_imort_flux_siscpf)%r81d, & + rio_abg_fmort_flux_siscpf => this%rvars(ir_abg_fmort_flux_siscpf)%r81d, & + rio_abg_term_flux_siscpf => this%rvars(ir_abg_term_flux_siscpf)%r81d, & + + rio_imortrate_sicdpf => this%rvars(ir_imortrate_sicdpf)%r81d, & + rio_imortcflux_sicdsc => this%rvars(ir_imortcflux_sicdsc)%r81d, & + rio_termcflux_cano_sicdsc => this%rvars(ir_termcflux_cano_sicdsc)%r81d, & + rio_termnindiv_cano_sicdpf => this%rvars(ir_termnindiv_cano_sicdpf)%r81d, & + rio_termcflux_usto_sicdsc => this%rvars(ir_termcflux_usto_sicdsc)%r81d, & + rio_termnindiv_usto_sicdpf => this%rvars(ir_termnindiv_usto_sicdpf)%r81d, & + rio_fmortrate_cano_sicdpf => this%rvars(ir_fmortrate_cano_sicdpf)%r81d, & + rio_fmortrate_usto_sicdpf => this%rvars(ir_fmortrate_usto_sicdpf)%r81d, & + rio_fmortcflux_cano_sicdsc => this%rvars(ir_fmortcflux_cano_sicdsc)%r81d, & + rio_fmortcflux_usto_sicdsc => this%rvars(ir_fmortcflux_usto_sicdsc)%r81d, & + rio_crownarea_cano_damage_si=> this%rvars(ir_crownarea_cano_si)%r81d, & + rio_crownarea_usto_damage_si=> this%rvars(ir_crownarea_usto_si)%r81d, & + rio_emanpp_si => this%rvars(ir_emanpp_si)%r81d) + totalCohorts = 0 ! --------------------------------------------------------------------------------- @@ -1858,6 +2129,7 @@ subroutine set_restart_vectors(this,nc,nsites,sites) io_idx_co = io_idx_co_1st io_idx_pa_ib = io_idx_co_1st io_idx_si_wmem = io_idx_co_1st + io_idx_si_pfcl = io_idx_co_1st io_idx_si_vtmem = io_idx_co_1st io_idx_pa_ncl = io_idx_co_1st @@ -1866,6 +2138,10 @@ subroutine set_restart_vectors(this,nc,nsites,sites) io_idx_si_sc = io_idx_co_1st io_idx_si_capf = io_idx_co_1st io_idx_si_cacls= io_idx_co_1st + io_idx_si_cdsc = io_idx_co_1st + io_idx_si_cdpf = io_idx_co_1st + io_idx_si_scpf = io_idx_co_1st + io_idx_si_pft = io_idx_co_1st ! recruitment rate do i_pft = 1,numpft @@ -1880,39 +2156,66 @@ subroutine set_restart_vectors(this,nc,nsites,sites) rio_area_pft_sift(io_idx_co_1st+i_pft-1) = sites(s)%area_pft(i_pft) end do - do el = 1, num_elements + do i_scls = 1, nlevsclass + do i_pft = 1, numpft + rio_fmortrate_cano_siscpf(io_idx_si_scpf) = sites(s)%fmort_rate_canopy(i_scls, i_pft) + rio_fmortrate_usto_siscpf(io_idx_si_scpf) = sites(s)%fmort_rate_ustory(i_scls, i_pft) + rio_imortrate_siscpf(io_idx_si_scpf) = sites(s)%imort_rate(i_scls, i_pft) + rio_fmortrate_crown_siscpf(io_idx_si_scpf) = sites(s)%fmort_rate_crown(i_scls, i_pft) + rio_fmortrate_cambi_siscpf(io_idx_si_scpf) = sites(s)%fmort_rate_cambial(i_scls, i_pft) + rio_termnindiv_cano_siscpf(io_idx_si_scpf) = sites(s)%term_nindivs_canopy(i_scls,i_pft) + rio_termnindiv_usto_siscpf(io_idx_si_scpf) = sites(s)%term_nindivs_ustory(i_scls,i_pft) + rio_growflx_fusion_siscpf(io_idx_si_scpf) = sites(s)%growthflux_fusion(i_scls, i_pft) + rio_abg_term_flux_siscpf(io_idx_si_scpf) = sites(s)%term_abg_flux(i_scls, i_pft) + rio_abg_imort_flux_siscpf(io_idx_si_scpf) = sites(s)%imort_abg_flux(i_scls, i_pft) + rio_abg_fmort_flux_siscpf(io_idx_si_scpf) = sites(s)%fmort_abg_flux(i_scls, i_pft) + io_idx_si_scpf = io_idx_si_scpf + 1 + end do + end do - io_idx_si_cwd = io_idx_co_1st - io_idx_si_pft = io_idx_co_1st - io_idx_si_scpf = io_idx_co_1st + do i_pft = 1, numpft + rio_termcflux_cano_sipft(io_idx_si_pft) = sites(s)%term_carbonflux_canopy(i_pft) + rio_termcflux_usto_sipft(io_idx_si_pft) = sites(s)%term_carbonflux_ustory(i_pft) + rio_fmortcflux_cano_sipft(io_idx_si_pft) = sites(s)%fmort_carbonflux_canopy(i_pft) + rio_fmortcflux_usto_sipft(io_idx_si_pft) = sites(s)%fmort_carbonflux_ustory(i_pft) + rio_imortcflux_sipft(io_idx_si_pft) = sites(s)%imort_carbonflux(i_pft) + rio_dd_status_sift(io_idx_si_pft) = sites(s)%dstatus(i_pft) + rio_dleafondate_sift(io_idx_si_pft) = sites(s)%dleafondate(i_pft) + rio_dleafoffdate_sift(io_idx_si_pft) = sites(s)%dleafoffdate(i_pft) + rio_dndaysleafon_sift(io_idx_si_pft) = sites(s)%dndaysleafon(i_pft) + rio_dndaysleafoff_sift(io_idx_si_pft) = sites(s)%dndaysleafoff(i_pft) + rio_elong_factor_sift(io_idx_si_pft) = sites(s)%elong_factor(i_pft) + rio_seed_in_sift(io_idx_si_pft) = sites(s)%seed_in(i_pft) + rio_seed_out_sift(io_idx_si_pft) = sites(s)%seed_out(i_pft) + io_idx_si_pft = io_idx_si_pft + 1 + end do - do i_cwd=1,ncwd - this%rvars(ir_cwdagin_flxdg+el-1)%r81d(io_idx_si_cwd) = sites(s)%flux_diags(el)%cwd_ag_input(i_cwd) - this%rvars(ir_cwdbgin_flxdg+el-1)%r81d(io_idx_si_cwd) = sites(s)%flux_diags(el)%cwd_bg_input(i_cwd) - io_idx_si_cwd = io_idx_si_cwd + 1 - end do + if(hlm_use_sp.eq.ifalse)then + do el = 1, num_elements - do i_pft=1,numpft - this%rvars(ir_leaflittin_flxdg+el-1)%r81d(io_idx_si_pft) = sites(s)%flux_diags(el)%leaf_litter_input(i_pft) - this%rvars(ir_rootlittin_flxdg+el-1)%r81d(io_idx_si_pft) = sites(s)%flux_diags(el)%root_litter_input(i_pft) - io_idx_si_pft = io_idx_si_pft + 1 - end do + io_idx_si_cwd = io_idx_co_1st + io_idx_si_pft = io_idx_co_1st + io_idx_si_scpf = io_idx_co_1st - iscpf = 1 - do i_scls = 1, nlevsclass - do i_pft = 1, numpft - this%rvars(ir_efflux_flxdg+el-1)%r81d(io_idx_si_scpf) = sites(s)%flux_diags(el)%nutrient_efflux_scpf(iscpf) - this%rvars(ir_uptake_flxdg+el-1)%r81d(io_idx_si_scpf) = sites(s)%flux_diags(el)%nutrient_uptake_scpf(iscpf) - iscpf = iscpf + 1 - io_idx_si_scpf = io_idx_si_scpf + 1 + do i_cwd=1,ncwd + this%rvars(ir_cwdagin_flxdg+el-1)%r81d(io_idx_si_cwd) = sites(s)%flux_diags(el)%cwd_ag_input(i_cwd) + this%rvars(ir_cwdbgin_flxdg+el-1)%r81d(io_idx_si_cwd) = sites(s)%flux_diags(el)%cwd_bg_input(i_cwd) + io_idx_si_cwd = io_idx_si_cwd + 1 end do - end do + do i_pft=1,numpft + this%rvars(ir_leaflittin_flxdg+el-1)%r81d(io_idx_si_pft) = sites(s)%flux_diags(el)%leaf_litter_input(i_pft) + this%rvars(ir_rootlittin_flxdg+el-1)%r81d(io_idx_si_pft) = sites(s)%flux_diags(el)%root_litter_input(i_pft) + io_idx_si_pft = io_idx_si_pft + 1 + end do - this%rvars(ir_oldstock_mbal+el-1)%r81d(io_idx_si) = sites(s)%mass_balance(el)%old_stock - this%rvars(ir_errfates_mbal+el-1)%r81d(io_idx_si) = sites(s)%mass_balance(el)%err_fates + this%rvars(ir_oldstock_mbal+el-1)%r81d(io_idx_si) = sites(s)%mass_balance(el)%old_stock + this%rvars(ir_errfates_mbal+el-1)%r81d(io_idx_si) = sites(s)%mass_balance(el)%err_fates + this%rvars(ir_woodprod_mbal+el-1)%r81d(io_idx_si) = sites(s)%mass_balance(el)%wood_product + + end do + end if - end do ! canopy spread term @@ -1923,7 +2226,7 @@ subroutine set_restart_vectors(this,nc,nsites,sites) ! new column, reset num patches patchespersite = 0 - do while(associated(cpatch)) + do_patch: do while(associated(cpatch)) ! found patch, increment patchespersite = patchespersite + 1 @@ -1974,6 +2277,20 @@ subroutine set_restart_vectors(this,nc,nsites,sites) end do end do + rio_l2fr_co(io_idx_co) = ccohort%l2fr + + if(hlm_parteh_mode .eq. prt_cnp_flex_allom_hyp) then + this%rvars(ir_cx_int_co)%r81d(io_idx_co) = ccohort%cx_int + this%rvars(ir_emadcxdt_co)%r81d(io_idx_co) = ccohort%ema_dcxdt + this%rvars(ir_cx0_co)%r81d(io_idx_co) = ccohort%cx0 + this%rvars(ir_cnplimiter_co)%r81d(io_idx_co) = real(ccohort%cnp_limiter,r8) + this%rvars(ir_daily_no3_uptake_co)%r81d(io_idx_co) = ccohort%daily_no3_uptake + this%rvars(ir_daily_nh4_uptake_co)%r81d(io_idx_co) = ccohort%daily_nh4_uptake + this%rvars(ir_daily_p_uptake_co)%r81d(io_idx_co) = ccohort%daily_p_gain + this%rvars(ir_daily_n_fixation_co)%r81d(io_idx_co) = ccohort%sym_nfix_daily + this%rvars(ir_daily_n_demand_co)%r81d(io_idx_co) = ccohort%daily_n_demand + this%rvars(ir_daily_p_demand_co)%r81d(io_idx_co) = ccohort%daily_p_demand + end if if(hlm_use_planthydro==itrue)then @@ -1991,17 +2308,15 @@ subroutine set_restart_vectors(this,nc,nsites,sites) rio_canopy_layer_co(io_idx_co) = ccohort%canopy_layer rio_canopy_layer_yesterday_co(io_idx_co) = ccohort%canopy_layer_yesterday + rio_crowndamage_co(io_idx_co) = ccohort%crowndamage rio_canopy_trim_co(io_idx_co) = ccohort%canopy_trim + rio_seed_prod_co(io_idx_co) = ccohort%seed_prod rio_size_class_lasttimestep(io_idx_co) = ccohort%size_class_lasttimestep rio_dbh_co(io_idx_co) = ccohort%dbh rio_coage_co(io_idx_co) = ccohort%coage - rio_height_co(io_idx_co) = ccohort%hite - rio_laimemory_co(io_idx_co) = ccohort%laimemory - rio_sapwmemory_co(io_idx_co) = ccohort%sapwmemory - rio_structmemory_co(io_idx_co) = ccohort%structmemory + rio_height_co(io_idx_co) = ccohort%height rio_g_sb_laweight_co(io_idx_co)= ccohort%g_sb_laweight - rio_nplant_co(io_idx_co) = ccohort%n rio_gpp_acc_co(io_idx_co) = ccohort%gpp_acc rio_npp_acc_co(io_idx_co) = ccohort%npp_acc @@ -2010,28 +2325,16 @@ subroutine set_restart_vectors(this,nc,nsites,sites) rio_resp_acc_hold_co(io_idx_co) = ccohort%resp_acc_hold rio_npp_acc_hold_co(io_idx_co) = ccohort%npp_acc_hold - rio_resp_m_def_co(io_idx_co) = ccohort%resp_m_def + rio_resp_excess_co(io_idx_co) = ccohort%resp_excess rio_bmort_co(io_idx_co) = ccohort%bmort rio_hmort_co(io_idx_co) = ccohort%hmort rio_cmort_co(io_idx_co) = ccohort%cmort rio_smort_co(io_idx_co) = ccohort%smort rio_asmort_co(io_idx_co) = ccohort%asmort - rio_frmort_co(io_idx_co) = ccohort%frmort - - ! Nutrient uptake/efflux - rio_daily_no3_uptake_co(io_idx_co) = ccohort%daily_no3_uptake - rio_daily_nh4_uptake_co(io_idx_co) = ccohort%daily_nh4_uptake - rio_daily_p_uptake_co(io_idx_co) = ccohort%daily_p_uptake + rio_dgmort_co(io_idx_co) = ccohort%dgmort + rio_frmort_co(io_idx_co) = ccohort%frmort - rio_daily_c_efflux_co(io_idx_co) = ccohort%daily_c_efflux - rio_daily_n_efflux_co(io_idx_co) = ccohort%daily_n_efflux - rio_daily_p_efflux_co(io_idx_co) = ccohort%daily_p_efflux - - rio_daily_n_demand_co(io_idx_co) = ccohort%daily_n_demand - rio_daily_p_demand_co(io_idx_co) = ccohort%daily_p_demand - rio_daily_n_need_co(io_idx_co) = ccohort%daily_n_need - rio_daily_p_need_co(io_idx_co) = ccohort%daily_p_need !Logging rio_lmort_direct_co(io_idx_co) = ccohort%lmort_direct @@ -2042,6 +2345,9 @@ subroutine set_restart_vectors(this,nc,nsites,sites) rio_resp_tstep_co(io_idx_co) = ccohort%resp_tstep rio_pft_co(io_idx_co) = ccohort%pft rio_status_co(io_idx_co) = ccohort%status_coh + rio_efleaf_co(io_idx_co) = ccohort%efleaf_coh + rio_effnrt_co(io_idx_co) = ccohort%effnrt_coh + rio_efstem_co(io_idx_co) = ccohort%efstem_coh if ( ccohort%isnew ) then rio_isnew_co(io_idx_co) = new_cohort else @@ -2081,7 +2387,20 @@ 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%tveg_longterm, ir_tveglongterm_pa, io_idx_co_1st) + + 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 @@ -2100,67 +2419,70 @@ subroutine set_restart_vectors(this,nc,nsites,sites) ,io_idx_co,cohortsperpatch endif - io_idx_pa_pft = io_idx_co_1st - do i = 1,numpft - this%rvars(ir_scorch_ht_pa_pft)%r81d(io_idx_pa_pft) = cpatch%scorch_ht(i) - io_idx_pa_pft = io_idx_pa_pft + 1 - end do - io_idx_pa_cwd = io_idx_co_1st - do i = 1,nfsc - this%rvars(ir_litter_moisture_pa_nfsc)%r81d(io_idx_pa_cwd) = cpatch%litter_moisture(i) - io_idx_pa_cwd = io_idx_pa_cwd + 1 - end do + if(hlm_use_sp.eq.ifalse)then - ! -------------------------------------------------------------------------- - ! Send litter to the restart arrays - ! Each element has its own variable, so we have to make sure - ! we keep re-setting this - ! -------------------------------------------------------------------------- + io_idx_pa_pft = io_idx_co_1st + do i = 1,numpft + this%rvars(ir_scorch_ht_pa_pft)%r81d(io_idx_pa_pft) = cpatch%scorch_ht(i) + io_idx_pa_pft = io_idx_pa_pft + 1 + end do - do el = 0, num_elements-1 + io_idx_pa_cwd = io_idx_co_1st + do i = 1,nfsc + this%rvars(ir_litter_moisture_pa_nfsc)%r81d(io_idx_pa_cwd) = cpatch%litter_moisture(i) + io_idx_pa_cwd = io_idx_pa_cwd + 1 + end do - io_idx_pa_pft = io_idx_co_1st - io_idx_pa_cwd = io_idx_co_1st - io_idx_pa_cwsl = io_idx_co_1st - io_idx_pa_dcsl = io_idx_co_1st - io_idx_pa_dc = io_idx_co_1st + ! -------------------------------------------------------------------------- + ! Send litter to the restart arrays + ! Each element has its own variable, so we have to make sure + ! we keep re-setting this + ! -------------------------------------------------------------------------- - litt => cpatch%litter(el+1) + do el = 0, num_elements-1 - do i = 1,numpft - this%rvars(ir_seed_litt+el)%r81d(io_idx_pa_pft) = litt%seed(i) - this%rvars(ir_seedgerm_litt+el)%r81d(io_idx_pa_pft) = litt%seed_germ(i) - this%rvars(ir_seed_decay_litt+el)%r81d(io_idx_pa_pft) = litt%seed_decay(i) - this%rvars(ir_seedgerm_decay_litt+el)%r81d(io_idx_pa_pft) = litt%seed_germ_decay(i) - io_idx_pa_pft = io_idx_pa_pft + 1 - end do + io_idx_pa_pft = io_idx_co_1st + io_idx_pa_cwd = io_idx_co_1st + io_idx_pa_cwsl = io_idx_co_1st + io_idx_pa_dcsl = io_idx_co_1st + io_idx_pa_dc = io_idx_co_1st + litt => cpatch%litter(el+1) + + do i = 1,numpft + this%rvars(ir_seed_litt+el)%r81d(io_idx_pa_pft) = litt%seed(i) + this%rvars(ir_seedgerm_litt+el)%r81d(io_idx_pa_pft) = litt%seed_germ(i) + this%rvars(ir_seed_decay_litt+el)%r81d(io_idx_pa_pft) = litt%seed_decay(i) + this%rvars(ir_seedgerm_decay_litt+el)%r81d(io_idx_pa_pft) = litt%seed_germ_decay(i) + io_idx_pa_pft = io_idx_pa_pft + 1 + end do - do i = 1,ndcmpy - this%rvars(ir_leaf_litt+el)%r81d(io_idx_pa_dc) = litt%leaf_fines(i) - this%rvars(ir_lfines_frag_litt+el)%r81d(io_idx_pa_dc) = litt%leaf_fines_frag(i) - io_idx_pa_dc = io_idx_pa_dc + 1 - do ilyr=1,sites(s)%nlevsoil + + do i = 1,ndcmpy + this%rvars(ir_leaf_litt+el)%r81d(io_idx_pa_dc) = litt%leaf_fines(i) + this%rvars(ir_lfines_frag_litt+el)%r81d(io_idx_pa_dc) = litt%leaf_fines_frag(i) + io_idx_pa_dc = io_idx_pa_dc + 1 + do ilyr=1,sites(s)%nlevsoil this%rvars(ir_fnrt_litt+el)%r81d(io_idx_pa_dcsl) = litt%root_fines(i,ilyr) this%rvars(ir_rfines_frag_litt+el)%r81d(io_idx_pa_dcsl) = litt%root_fines_frag(i,ilyr) io_idx_pa_dcsl = io_idx_pa_dcsl + 1 - end do - end do - - do i = 1,ncwd - this%rvars(ir_agcwd_litt+el)%r81d(io_idx_pa_cwd) = litt%ag_cwd(i) - this%rvars(ir_agcwd_frag_litt+el)%r81d(io_idx_pa_cwd) = litt%ag_cwd_frag(i) - io_idx_pa_cwd = io_idx_pa_cwd + 1 - do ilyr=1,sites(s)%nlevsoil + end do + end do + + do i = 1,ncwd + this%rvars(ir_agcwd_litt+el)%r81d(io_idx_pa_cwd) = litt%ag_cwd(i) + this%rvars(ir_agcwd_frag_litt+el)%r81d(io_idx_pa_cwd) = litt%ag_cwd_frag(i) + io_idx_pa_cwd = io_idx_pa_cwd + 1 + do ilyr=1,sites(s)%nlevsoil this%rvars(ir_bgcwd_litt+el)%r81d(io_idx_pa_cwsl) = litt%bg_cwd(i,ilyr) this%rvars(ir_bgcwd_frag_litt+el)%r81d(io_idx_pa_cwsl) = litt%bg_cwd_frag(i,ilyr) io_idx_pa_cwsl = io_idx_pa_cwsl + 1 - end do - end do - - end do + end do + end do + end do + end if do i = 1,maxSWb rio_gnd_alb_dif_pasb(io_idx_pa_ib) = cpatch%gnd_alb_dif(i) @@ -2194,51 +2516,71 @@ subroutine set_restart_vectors(this,nc,nsites,sites) cpatch => cpatch%younger - enddo ! cpatch do while - - io_idx_si_scpf = io_idx_co_1st + enddo do_patch ! cpatch do while ! Fill the site level diagnostics arrays do i_scls = 1, nlevsclass - do i_pft = 1, numpft - - rio_fmortrate_cano_siscpf(io_idx_si_scpf) = sites(s)%fmort_rate_canopy(i_scls, i_pft) - rio_fmortrate_usto_siscpf(io_idx_si_scpf) = sites(s)%fmort_rate_ustory(i_scls, i_pft) - rio_imortrate_siscpf(io_idx_si_scpf) = sites(s)%imort_rate(i_scls, i_pft) - rio_fmortrate_crown_siscpf(io_idx_si_scpf) = sites(s)%fmort_rate_crown(i_scls, i_pft) - rio_fmortrate_cambi_siscpf(io_idx_si_scpf) = sites(s)%fmort_rate_cambial(i_scls, i_pft) - rio_termnindiv_cano_siscpf(io_idx_si_scpf) = sites(s)%term_nindivs_canopy(i_scls,i_pft) - rio_termnindiv_usto_siscpf(io_idx_si_scpf) = sites(s)%term_nindivs_ustory(i_scls,i_pft) - rio_growflx_fusion_siscpf(io_idx_si_scpf) = sites(s)%growthflux_fusion(i_scls, i_pft) - - io_idx_si_scpf = io_idx_si_scpf + 1 - end do rio_demorate_sisc(io_idx_si_sc) = sites(s)%demotion_rate(i_scls) rio_promrate_sisc(io_idx_si_sc) = sites(s)%promotion_rate(i_scls) io_idx_si_sc = io_idx_si_sc + 1 end do + + rio_termcarea_cano_si(io_idx_si) = sites(s)%term_crownarea_canopy + rio_termcarea_usto_si(io_idx_si) = sites(s)%term_crownarea_ustory + rio_emanpp_si(io_idx_si) = sites(s)%ema_npp + + ! this only copies live portions of transitions - but that's ok because the mortality + ! bit only needs to be added for history outputs + if(hlm_use_tree_damage .eq. itrue) then + + do i_scls = 1, nlevsclass + do i_cdam = 1, nlevdamage + do i_pft = 1, numpft + rio_imortrate_sicdpf(io_idx_si_cdpf) = sites(s)%imort_rate_damage(i_cdam, i_scls, i_pft) + rio_termnindiv_cano_sicdpf(io_idx_si_cdpf) = sites(s)%term_nindivs_canopy_damage(i_cdam,i_scls,i_pft) + rio_termnindiv_usto_sicdpf(io_idx_si_cdpf) = sites(s)%term_nindivs_ustory_damage(i_cdam,i_scls,i_pft) + rio_imortcflux_sicdsc(io_idx_si_cdsc) = sites(s)%imort_cflux_damage(i_cdam, i_scls) + rio_termcflux_cano_sicdsc(io_idx_si_cdsc) = sites(s)%term_cflux_canopy_damage(i_cdam, i_scls) + rio_termcflux_usto_sicdsc(io_idx_si_cdsc) = sites(s)%term_cflux_ustory_damage(i_cdam, i_scls) + rio_fmortrate_cano_sicdpf(io_idx_si_cdpf) = sites(s)%fmort_rate_canopy_damage(i_cdam, i_scls, i_pft) + rio_fmortrate_usto_sicdpf(io_idx_si_cdpf) = sites(s)%fmort_rate_ustory_damage(i_cdam, i_scls, i_pft) + rio_fmortcflux_cano_sicdsc(io_idx_si_cdsc) = sites(s)%fmort_cflux_canopy_damage(i_cdam, i_scls) + rio_fmortcflux_usto_sicdsc(io_idx_si_cdsc) = sites(s)%fmort_cflux_ustory_damage(i_cdam, i_scls) + io_idx_si_cdsc = io_idx_si_cdsc + 1 + io_idx_si_cdpf = io_idx_si_cdpf + 1 + end do + end do + end do - rio_termcflux_cano_si(io_idx_si) = sites(s)%term_carbonflux_canopy - rio_termcflux_usto_si(io_idx_si) = sites(s)%term_carbonflux_ustory + rio_crownarea_cano_damage_si(io_idx_si) = sites(s)%crownarea_canopy_damage + rio_crownarea_usto_damage_si(io_idx_si) = sites(s)%crownarea_ustory_damage + + end if + + rio_democflux_si(io_idx_si) = sites(s)%demotion_carbonflux rio_promcflux_si(io_idx_si) = sites(s)%promotion_carbonflux - rio_imortcflux_si(io_idx_si) = sites(s)%imort_carbonflux - rio_fmortcflux_cano_si(io_idx_si) = sites(s)%fmort_carbonflux_canopy - rio_fmortcflux_usto_si(io_idx_si) = sites(s)%fmort_carbonflux_ustory - - rio_cd_status_si(io_idx_si) = sites(s)%cstatus - rio_dd_status_si(io_idx_si) = sites(s)%dstatus - rio_nchill_days_si(io_idx_si) = sites(s)%nchilldays - rio_ncold_days_si(io_idx_si) = sites(s)%ncolddays - rio_leafondate_si(io_idx_si) = sites(s)%cleafondate - rio_leafoffdate_si(io_idx_si) = sites(s)%cleafoffdate - - rio_dleafondate_si(io_idx_si) = sites(s)%dleafondate - rio_dleafoffdate_si(io_idx_si) = sites(s)%dleafoffdate + + rio_imortcarea_si(io_idx_si) = sites(s)%imort_crownarea + rio_fmortcarea_cano_si(io_idx_si) = sites(s)%fmort_crownarea_canopy + rio_fmortcarea_usto_si(io_idx_si) = sites(s)%fmort_crownarea_ustory + + rio_cd_status_si(io_idx_si) = sites(s)%cstatus + rio_nchill_days_si(io_idx_si) = sites(s)%nchilldays + rio_ncold_days_si(io_idx_si) = sites(s)%ncolddays + rio_cleafondate_si(io_idx_si) = sites(s)%cleafondate + rio_cleafoffdate_si(io_idx_si) = sites(s)%cleafoffdate + rio_cndaysleafon_si(io_idx_si) = sites(s)%cndaysleafon + rio_cndaysleafoff_si(io_idx_si) = sites(s)%cndaysleafoff + rio_gdd_si(io_idx_si) = sites(s)%grow_deg_days + rio_phenmodeldate_si(io_idx_si) = sites(s)%phen_model_date + + + + rio_acc_ni_si(io_idx_si) = sites(s)%acc_NI - rio_gdd_si(io_idx_si) = sites(s)%grow_deg_days rio_snow_depth_si(io_idx_si) = sites(s)%snow_depth ! Accumulated trunk product @@ -2247,9 +2589,19 @@ subroutine set_restart_vectors(this,nc,nsites,sites) rio_npatch_si(io_idx_si) = patchespersite + do i = 1,nclmax + do i_pft = 1, numpft + rio_recl2fr_sipfcl(io_idx_si_pfcl ) = sites(s)%rec_l2fr(i_pft,i) + io_idx_si_pfcl = io_idx_si_pfcl + 1 + end do + end do + do i = 1,numWaterMem ! numWaterMem currently 10 - rio_watermem_siwm( io_idx_si_wmem ) = sites(s)%water_memory(i) - io_idx_si_wmem = io_idx_si_wmem + 1 + do i_pft=1,numpft + rio_liqvolmem_siwmft( io_idx_si_wmem ) = sites(s)%liqvol_memory(i,i_pft) + rio_smpmem_siwmft( io_idx_si_wmem ) = sites(s)%smp_memory(i,i_pft) + io_idx_si_wmem = io_idx_si_wmem + 1 + end do end do do i = 1, num_vegtemp_mem @@ -2304,18 +2656,15 @@ subroutine create_patchcohort_structure(this, nc, nsites, sites, bc_in, bc_out) ! --------------------------------------------------------------------------------- use EDTypesMod, only : ed_site_type - use EDTypesMod, only : ed_cohort_type - use EDTypesMod, only : ed_patch_type - use EDTypesMod, only : maxSWb + use FatesCohortMod, only : fates_cohort_type + use FatesPatchMod, only : fates_patch_type + use EDParamsMod, only : maxSWb, regeneration_model use FatesInterfaceTypesMod, only : fates_maxElementsPerPatch + use FatesInterfaceTypesMod, only : hlm_current_tod, hlm_numSWb, numpft - use EDTypesMod, only : maxpft use EDTypesMod, only : area - use EDPatchDynamicsMod, only : zero_patch use EDInitMod, only : zero_site use EDInitMod, only : init_site_vars - use EDPatchDynamicsMod, only : create_patch - use EDPftvarcon, only : EDPftvarcon_inst use FatesAllometryMod, only : h2d_allom @@ -2329,9 +2678,9 @@ subroutine create_patchcohort_structure(this, nc, nsites, sites, bc_in, bc_out) ! local variables - type(ed_patch_type) , pointer :: newp - type(ed_cohort_type), pointer :: new_cohort - type(ed_cohort_type), pointer :: prev_cohort + type(fates_patch_type) , pointer :: newp + type(fates_cohort_type), pointer :: new_cohort + type(fates_cohort_type), pointer :: prev_cohort integer :: cohortstatus integer :: s ! site index integer :: idx_pa ! local patch index @@ -2382,7 +2731,9 @@ subroutine create_patchcohort_structure(this, nc, nsites, sites, bc_in, bc_out) nocomp_pft = fates_unset_int ! the nocomp_pft label is set after patch creation has occured in 'get_restart_vectors' ! make new patch - call create_patch(sites(s), newp, fates_unset_r8, fates_unset_r8, primaryforest, nocomp_pft ) + call newp%Create(fates_unset_r8, fates_unset_r8, primaryforest, & + nocomp_pft, hlm_numSWb, numpft, sites(s)%nlevsoil, & + hlm_current_tod, regeneration_model) ! Initialize the litter pools to zero, these ! pools will be populated by looping over the existing patches @@ -2412,9 +2763,8 @@ subroutine create_patchcohort_structure(this, nc, nsites, sites, bc_in, bc_out) do fto = 1, rio_ncohort_pa( io_idx_co_1st ) allocate(new_cohort) - call nan_cohort(new_cohort) - call zero_cohort(new_cohort) - new_cohort%patchptr => newp + call new_cohort%NanValues() + call new_cohort%ZeroValues() ! If this is the first in the list, it is tallest if (.not.associated(newp%tallest)) then @@ -2435,7 +2785,7 @@ subroutine create_patchcohort_structure(this, nc, nsites, sites, bc_in, bc_out) ! correct boundary condition fields new_cohort%prt => null() call InitPRTObject(new_cohort%prt) - call InitPRTBoundaryConditions(new_cohort) + ! Allocate hydraulics arrays @@ -2504,16 +2854,16 @@ end subroutine create_patchcohort_structure subroutine get_restart_vectors(this, nc, nsites, sites) use EDTypesMod, only : ed_site_type - use EDTypesMod, only : ed_cohort_type - use EDTypesMod, only : ed_patch_type - use EDTypesMod, only : maxSWb - use EDTypesMod, only : nclmax + use FatesCohortMod, only : fates_cohort_type + use FatesPatchMod, only : fates_patch_type + use EDParamsMod, only : maxSWb + use EDParamsMod, only : nclmax use FatesInterfaceTypesMod, only : numpft use FatesInterfaceTypesMod, only : fates_maxElementsPerPatch use EDTypesMod, only : numWaterMem use EDTypesMod, only : num_vegtemp_mem use FatesSizeAgeTypeIndicesMod, only : get_age_class_index - + ! !ARGUMENTS: class(fates_restart_interface_type) , intent(inout) :: this integer , intent(in) :: nc @@ -2524,11 +2874,11 @@ subroutine get_restart_vectors(this, nc, nsites, sites) ! locals ! ---------------------------------------------------------------------------------- ! LL pointers - type(ed_patch_type),pointer :: cpatch ! current patch - type(ed_cohort_type),pointer :: ccohort ! current cohort + type(fates_patch_type),pointer :: cpatch ! current patch + type(fates_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) @@ -2548,6 +2898,7 @@ subroutine get_restart_vectors(this, nc, nsites, sites) integer :: io_idx_pa_dc ! each decomposability index integer :: io_idx_pa_ib ! each SW radiation band per patch (pa_ib) integer :: io_idx_si_wmem ! each water memory class within each site + integer :: io_idx_si_pfcl ! each pft x canopy layer class within each site integer :: io_idx_si_vtmem ! counter for vegetation temp memory integer :: io_idx_si_lyr_shell ! site - layer x shell index integer :: io_idx_si_scpf ! each size-class x pft index within site @@ -2556,6 +2907,9 @@ subroutine get_restart_vectors(this, nc, nsites, sites) integer :: io_idx_si_capf ! each cohort age class x pft index within site integer :: io_idx_si_cwd integer :: io_idx_si_pft + integer :: io_idx_si_cdsc ! each damage x size class within site + integer :: io_idx_si_cdpf ! damage x size x pft within site + integer :: io_idx_pa_ncl ! each canopy layer within each patch ! Some counters (for checking mostly) @@ -2573,16 +2927,19 @@ subroutine get_restart_vectors(this, nc, nsites, sites) integer :: i_pft ! loop counter for pft integer :: i_scls ! loop counter for size-clas integer :: i_cacls ! loop counter for cohort age class + integer :: i_cdam ! loop counter for damage class + integer :: icdj ! loop counter for damage class + integer :: icdi ! loop counter for damage class associate( rio_npatch_si => this%rvars(ir_npatch_si)%int1d, & rio_cd_status_si => this%rvars(ir_cd_status_si)%int1d, & - rio_dd_status_si => this%rvars(ir_dd_status_si)%int1d, & rio_nchill_days_si => this%rvars(ir_nchill_days_si)%int1d, & rio_ncold_days_si => this%rvars(ir_ncold_days_si)%int1d, & - rio_leafondate_si => this%rvars(ir_leafondate_si)%int1d, & - rio_leafoffdate_si => this%rvars(ir_leafoffdate_si)%int1d, & - rio_dleafondate_si => this%rvars(ir_dleafondate_si)%int1d, & - rio_dleafoffdate_si => this%rvars(ir_dleafoffdate_si)%int1d, & + rio_cleafondate_si => this%rvars(ir_cleafondate_si)%int1d, & + rio_cleafoffdate_si => this%rvars(ir_cleafoffdate_si)%int1d, & + rio_cndaysleafon_si => this%rvars(ir_cndaysleafon_si)%int1d, & + rio_cndaysleafoff_si => this%rvars(ir_cndaysleafoff_si)%int1d, & + rio_phenmodeldate_si => this%rvars(ir_phenmodeldate_si)%int1d, & rio_acc_ni_si => this%rvars(ir_acc_ni_si)%r81d, & rio_gdd_si => this%rvars(ir_gdd_si)%r81d, & rio_snow_depth_si => this%rvars(ir_snow_depth_si)%r81d, & @@ -2593,16 +2950,15 @@ subroutine get_restart_vectors(this, nc, nsites, sites) rio_solar_zenith_angle_pa => this%rvars(ir_solar_zenith_angle_pa)%r81d, & rio_canopy_layer_co => this%rvars(ir_canopy_layer_co)%int1d, & rio_canopy_layer_yesterday_co => this%rvars(ir_canopy_layer_yesterday_co)%r81d, & + rio_crowndamage_co => this%rvars(ir_crowndamage_co)%int1d, & rio_canopy_trim_co => this%rvars(ir_canopy_trim_co)%r81d, & + rio_l2fr_co => this%rvars(ir_l2fr_co)%r81d, & rio_seed_prod_co => this%rvars(ir_seed_prod_co)%r81d, & rio_size_class_lasttimestep => this%rvars(ir_size_class_lasttimestep_co)%int1d, & rio_dbh_co => this%rvars(ir_dbh_co)%r81d, & rio_coage_co => this%rvars(ir_coage_co)%r81d, & rio_g_sb_laweight_co => this%rvars(ir_g_sb_laweight_co)%r81d, & rio_height_co => this%rvars(ir_height_co)%r81d, & - rio_laimemory_co => this%rvars(ir_laimemory_co)%r81d, & - rio_sapwmemory_co => this%rvars(ir_sapwmemory_co)%r81d, & - rio_structmemory_co => this%rvars(ir_structmemory_co)%r81d, & rio_nplant_co => this%rvars(ir_nplant_co)%r81d, & rio_gpp_acc_co => this%rvars(ir_gpp_acc_co)%r81d, & rio_npp_acc_co => this%rvars(ir_npp_acc_co)%r81d, & @@ -2610,22 +2966,13 @@ subroutine get_restart_vectors(this, nc, nsites, sites) rio_gpp_acc_hold_co => this%rvars(ir_gpp_acc_hold_co)%r81d, & rio_resp_acc_hold_co => this%rvars(ir_resp_acc_hold_co)%r81d, & rio_npp_acc_hold_co => this%rvars(ir_npp_acc_hold_co)%r81d, & - rio_resp_m_def_co => this%rvars(ir_resp_m_def_co)%r81d, & + rio_resp_excess_co => this%rvars(ir_resp_excess_co)%r81d, & rio_bmort_co => this%rvars(ir_bmort_co)%r81d, & rio_hmort_co => this%rvars(ir_hmort_co)%r81d, & rio_cmort_co => this%rvars(ir_cmort_co)%r81d, & - rio_daily_nh4_uptake_co => this%rvars(ir_daily_nh4_uptake_co)%r81d, & - rio_daily_no3_uptake_co => this%rvars(ir_daily_no3_uptake_co)%r81d, & - rio_daily_p_uptake_co => this%rvars(ir_daily_p_uptake_co)%r81d, & - rio_daily_c_efflux_co => this%rvars(ir_daily_c_efflux_co)%r81d, & - rio_daily_n_efflux_co => this%rvars(ir_daily_n_efflux_co)%r81d, & - rio_daily_p_efflux_co => this%rvars(ir_daily_p_efflux_co)%r81d, & - rio_daily_n_demand_co => this%rvars(ir_daily_n_demand_co)%r81d, & - rio_daily_p_demand_co => this%rvars(ir_daily_p_demand_co)%r81d, & - rio_daily_n_need_co => this%rvars(ir_daily_n_need_co)%r81d, & - rio_daily_p_need_co => this%rvars(ir_daily_p_need_co)%r81d, & rio_smort_co => this%rvars(ir_smort_co)%r81d, & rio_asmort_co => this%rvars(ir_asmort_co)%r81d, & + rio_dgmort_co => this%rvars(ir_dgmort_co)%r81d, & rio_frmort_co => this%rvars(ir_frmort_co)%r81d, & rio_lmort_direct_co => this%rvars(ir_lmort_direct_co)%r81d, & rio_lmort_collateral_co => this%rvars(ir_lmort_collateral_co)%r81d, & @@ -2634,6 +2981,9 @@ subroutine get_restart_vectors(this, nc, nsites, sites) rio_resp_tstep_co => this%rvars(ir_resp_tstep_co)%r81d, & rio_pft_co => this%rvars(ir_pft_co)%int1d, & rio_status_co => this%rvars(ir_status_co)%int1d, & + rio_efleaf_co => this%rvars(ir_efleaf_co)%r81d, & + rio_effnrt_co => this%rvars(ir_effnrt_co)%r81d, & + rio_efstem_co => this%rvars(ir_efstem_co)%r81d, & rio_isnew_co => this%rvars(ir_isnew_co)%int1d, & rio_gnd_alb_dif_pasb => this%rvars(ir_gnd_alb_dif_pasb)%r81d, & rio_gnd_alb_dir_pasb => this%rvars(ir_gnd_alb_dir_pasb)%r81d, & @@ -2644,11 +2994,21 @@ subroutine get_restart_vectors(this, nc, nsites, sites) rio_agesinceanthrodist_pa => this%rvars(ir_agesinceanthrodist_pa)%r81d, & rio_nocomp_pft_label_pa => this%rvars(ir_nocomp_pft_label_pa)%int1d, & rio_area_pa => this%rvars(ir_area_pa)%r81d, & - rio_watermem_siwm => this%rvars(ir_watermem_siwm)%r81d, & + rio_dd_status_sift => this%rvars(ir_dd_status_sift)%int1d, & + rio_dleafondate_sift => this%rvars(ir_dleafondate_sift)%int1d, & + rio_dleafoffdate_sift => this%rvars(ir_dleafoffdate_sift)%int1d, & + rio_dndaysleafon_sift => this%rvars(ir_dndaysleafon_sift)%int1d, & + rio_dndaysleafoff_sift => this%rvars(ir_dndaysleafoff_sift)%int1d, & + rio_elong_factor_sift => this%rvars(ir_elong_factor_sift)%r81d, & + rio_liqvolmem_siwmft => this%rvars(ir_liqvolmem_siwmft)%r81d, & + rio_smpmem_siwmft => this%rvars(ir_smpmem_siwmft)%r81d, & + rio_recl2fr_sipfcl => this%rvars(ir_recl2fr_sipfcl)%r81d, & rio_vegtempmem_sitm => this%rvars(ir_vegtempmem_sitm)%r81d, & rio_recrate_sift => this%rvars(ir_recrate_sift)%r81d, & rio_use_this_pft_sift => this%rvars(ir_use_this_pft_sift)%int1d, & rio_area_pft_sift => this%rvars(ir_area_pft_sift)%r81d,& + rio_seed_in_sift => this%rvars(ir_seed_in_sift)%r81d, & + rio_seed_out_sift => this%rvars(ir_seed_out_sift)%r81d, & rio_fmortrate_cano_siscpf => this%rvars(ir_fmortrate_cano_siscpf)%r81d, & rio_fmortrate_usto_siscpf => this%rvars(ir_fmortrate_usto_siscpf)%r81d, & rio_imortrate_siscpf => this%rvars(ir_imortrate_siscpf)%r81d, & @@ -2659,13 +3019,34 @@ subroutine get_restart_vectors(this, nc, nsites, sites) rio_growflx_fusion_siscpf => this%rvars(ir_growflx_fusion_siscpf)%r81d, & rio_demorate_sisc => this%rvars(ir_demorate_sisc)%r81d, & rio_promrate_sisc => this%rvars(ir_promrate_sisc)%r81d, & - rio_termcflux_cano_si => this%rvars(ir_termcflux_cano_si)%r81d, & - rio_termcflux_usto_si => this%rvars(ir_termcflux_usto_si)%r81d, & + rio_termcflux_cano_sipft => this%rvars(ir_termcflux_cano_sipft)%r81d, & + rio_termcflux_usto_sipft => this%rvars(ir_termcflux_usto_sipft)%r81d, & rio_democflux_si => this%rvars(ir_democflux_si)%r81d, & rio_promcflux_si => this%rvars(ir_promcflux_si)%r81d, & - rio_imortcflux_si => this%rvars(ir_imortcflux_si)%r81d, & - rio_fmortcflux_cano_si => this%rvars(ir_fmortcflux_cano_si)%r81d, & - rio_fmortcflux_usto_si => this%rvars(ir_fmortcflux_usto_si)%r81d) + rio_termcarea_cano_si => this%rvars(ir_termcarea_cano_si)%r81d, & + rio_termcarea_usto_si => this%rvars(ir_termcarea_usto_si)%r81d, & + rio_imortcarea_si => this%rvars(ir_imortcarea_si)%r81d, & + rio_fmortcarea_cano_si => this%rvars(ir_fmortcarea_cano_si)%r81d, & + rio_fmortcarea_usto_si => this%rvars(ir_fmortcarea_usto_si)%r81d, & + rio_imortrate_sicdpf => this%rvars(ir_imortrate_sicdpf)%r81d, & + rio_termnindiv_cano_sicdpf => this%rvars(ir_termnindiv_cano_sicdpf)%r81d, & + rio_termnindiv_usto_sicdpf => this%rvars(ir_termnindiv_usto_sicdpf)%r81d, & + rio_imortcflux_sicdsc => this%rvars(ir_imortcflux_sicdsc)%r81d, & + rio_termcflux_cano_sicdsc => this%rvars(ir_termcflux_cano_sicdsc)%r81d, & + rio_termcflux_usto_sicdsc => this%rvars(ir_termcflux_usto_sicdsc)%r81d, & + rio_fmortrate_cano_sicdpf => this%rvars(ir_fmortrate_cano_sicdpf)%r81d, & + rio_fmortrate_usto_sicdpf => this%rvars(ir_fmortrate_usto_sicdpf)%r81d, & + rio_fmortcflux_cano_sicdsc => this%rvars(ir_fmortcflux_cano_sicdsc)%r81d, & + rio_fmortcflux_usto_sicdsc => this%rvars(ir_fmortcflux_usto_sicdsc)%r81d, & + rio_crownarea_cano_damage_si=> this%rvars(ir_crownarea_cano_si)%r81d, & + rio_crownarea_usto_damage_si=> this%rvars(ir_crownarea_usto_si)%r81d, & + rio_emanpp_si => this%rvars(ir_emanpp_si)%r81d, & + rio_imortcflux_sipft => this%rvars(ir_imortcflux_sipft)%r81d, & + rio_fmortcflux_cano_sipft => this%rvars(ir_fmortcflux_cano_sipft)%r81d, & + rio_fmortcflux_usto_sipft => this%rvars(ir_fmortcflux_usto_sipft)%r81d, & + rio_abg_term_flux_siscpf => this%rvars(ir_abg_term_flux_siscpf)%r81d, & + rio_abg_imort_flux_siscpf => this%rvars(ir_abg_imort_flux_siscpf)%r81d, & + rio_abg_fmort_flux_siscpf => this%rvars(ir_abg_fmort_flux_siscpf)%r81d ) totalcohorts = 0 @@ -2678,6 +3059,7 @@ subroutine get_restart_vectors(this, nc, nsites, sites) io_idx_co = io_idx_co_1st io_idx_pa_ib = io_idx_co_1st io_idx_si_wmem = io_idx_co_1st + io_idx_si_pfcl = io_idx_co_1st io_idx_si_vtmem = io_idx_co_1st io_idx_pa_ncl = io_idx_co_1st @@ -2688,60 +3070,98 @@ subroutine get_restart_vectors(this, nc, nsites, sites) io_idx_si_sc = io_idx_co_1st io_idx_si_capf = io_idx_co_1st io_idx_si_cacls= io_idx_co_1st - + io_idx_si_cdsc = io_idx_co_1st + io_idx_si_cdpf = io_idx_co_1st + io_idx_si_scpf = io_idx_co_1st + io_idx_si_pft = io_idx_co_1st + ! read seed_bank info(site-level, but PFT-resolved) do i_pft = 1,numpft sites(s)%recruitment_rate(i_pft) = rio_recrate_sift(io_idx_co_1st+i_pft-1) enddo - !variables for fixed biogeography mode. These are currently used in restart even when this is off. + ! variables for fixed biogeography mode. These are currently used in restart even when this is off. do i_pft = 1,numpft sites(s)%use_this_pft(i_pft) = rio_use_this_pft_sift(io_idx_co_1st+i_pft-1) sites(s)%area_pft(i_pft) = rio_area_pft_sift(io_idx_co_1st+i_pft-1) enddo - ! Mass balance and diagnostics across elements at the site level - do el = 1, num_elements - - io_idx_si_cwd = io_idx_co_1st - io_idx_si_pft = io_idx_co_1st - io_idx_si_scpf = io_idx_co_1st + ! calculate the bareground area for the pft in no competition + fixed biogeo modes + if (hlm_use_nocomp .eq. itrue .and. hlm_use_fixed_biogeog .eq. itrue) then + if (area-sum(sites(s)%area_pft(1:numpft)) .gt. nearzero) then + sites(s)%area_pft(0) = area - sum(sites(s)%area_pft(1:numpft)) + else + sites(s)%area_pft(0) = 0.0_r8 + endif + endif - do i_cwd=1,ncwd - sites(s)%flux_diags(el)%cwd_ag_input(i_cwd) = this%rvars(ir_cwdagin_flxdg+el-1)%r81d(io_idx_si_cwd) - sites(s)%flux_diags(el)%cwd_bg_input(i_cwd) = this%rvars(ir_cwdbgin_flxdg+el-1)%r81d(io_idx_si_cwd) - io_idx_si_cwd = io_idx_si_cwd + 1 + do i_scls = 1,nlevsclass + do i_pft = 1, numpft + sites(s)%fmort_rate_canopy(i_scls, i_pft) = rio_fmortrate_cano_siscpf(io_idx_si_scpf) + sites(s)%fmort_rate_ustory(i_scls, i_pft) = rio_fmortrate_usto_siscpf(io_idx_si_scpf) + sites(s)%imort_rate(i_scls, i_pft) = rio_imortrate_siscpf(io_idx_si_scpf) + sites(s)%fmort_rate_crown(i_scls, i_pft) = rio_fmortrate_crown_siscpf(io_idx_si_scpf) + sites(s)%fmort_rate_cambial(i_scls, i_pft) = rio_fmortrate_cambi_siscpf(io_idx_si_scpf) + sites(s)%term_nindivs_canopy(i_scls,i_pft) = rio_termnindiv_cano_siscpf(io_idx_si_scpf) + sites(s)%term_nindivs_ustory(i_scls,i_pft) = rio_termnindiv_usto_siscpf(io_idx_si_scpf) + sites(s)%growthflux_fusion(i_scls, i_pft) = rio_growflx_fusion_siscpf(io_idx_si_scpf) + sites(s)%term_abg_flux(i_scls,i_pft) = rio_abg_term_flux_siscpf(io_idx_si_scpf) + sites(s)%imort_abg_flux(i_scls,i_pft) = rio_abg_imort_flux_siscpf(io_idx_si_scpf) + sites(s)%fmort_abg_flux(i_scls,i_pft) = rio_abg_fmort_flux_siscpf(io_idx_si_scpf) + io_idx_si_scpf = io_idx_si_scpf + 1 end do + end do - do i_pft=1,numpft - sites(s)%flux_diags(el)%leaf_litter_input(i_pft) = this%rvars(ir_leaflittin_flxdg+el-1)%r81d(io_idx_si_pft) - sites(s)%flux_diags(el)%root_litter_input(i_pft) = this%rvars(ir_rootlittin_flxdg+el-1)%r81d(io_idx_si_pft) - io_idx_si_pft = io_idx_si_pft + 1 - end do + do i_pft = 1, numpft + sites(s)%term_carbonflux_canopy(i_pft) = rio_termcflux_cano_sipft(io_idx_si_pft) + sites(s)%term_carbonflux_ustory(i_pft) = rio_termcflux_usto_sipft(io_idx_si_pft) + sites(s)%fmort_carbonflux_canopy(i_pft) = rio_fmortcflux_cano_sipft(io_idx_si_pft) + sites(s)%fmort_carbonflux_ustory(i_pft) = rio_fmortcflux_usto_sipft(io_idx_si_pft) + sites(s)%imort_carbonflux(i_pft) = rio_imortcflux_sipft(io_idx_si_pft) + sites(s)%dstatus(i_pft) = rio_dd_status_sift(io_idx_si_pft) + sites(s)%dleafondate(i_pft) = rio_dleafondate_sift(io_idx_si_pft) + sites(s)%dleafoffdate(i_pft) = rio_dleafoffdate_sift(io_idx_si_pft) + sites(s)%dndaysleafon(i_pft) = rio_dndaysleafon_sift(io_idx_si_pft) + sites(s)%dndaysleafoff(i_pft) = rio_dndaysleafoff_sift(io_idx_si_pft) + sites(s)%elong_factor(i_pft) = rio_elong_factor_sift(io_idx_si_pft) + sites(s)%seed_in(i_pft) = rio_seed_in_sift(io_idx_si_pft) + sites(s)%seed_out(i_pft) = rio_seed_out_sift(io_idx_si_pft) + io_idx_si_pft = io_idx_si_pft + 1 + end do - iscpf = 1 - do i_scls = 1, nlevsclass - do i_pft = 1, numpft - sites(s)%flux_diags(el)%nutrient_efflux_scpf(iscpf) = this%rvars(ir_efflux_flxdg+el-1)%r81d(io_idx_si_scpf) - sites(s)%flux_diags(el)%nutrient_uptake_scpf(iscpf) = this%rvars(ir_uptake_flxdg+el-1)%r81d(io_idx_si_scpf) - iscpf = iscpf + 1 - io_idx_si_scpf = io_idx_si_scpf + 1 - end do - end do + ! Mass balance and diagnostics across elements at the site level + if(hlm_use_sp.eq.ifalse)then + do el = 1, num_elements + io_idx_si_cwd = io_idx_co_1st + io_idx_si_pft = io_idx_co_1st + io_idx_si_scpf = io_idx_co_1st - sites(s)%mass_balance(el)%old_stock = this%rvars(ir_oldstock_mbal+el-1)%r81d(io_idx_si) - sites(s)%mass_balance(el)%err_fates = this%rvars(ir_errfates_mbal+el-1)%r81d(io_idx_si) + do i_cwd=1,ncwd + sites(s)%flux_diags(el)%cwd_ag_input(i_cwd) = this%rvars(ir_cwdagin_flxdg+el-1)%r81d(io_idx_si_cwd) + sites(s)%flux_diags(el)%cwd_bg_input(i_cwd) = this%rvars(ir_cwdbgin_flxdg+el-1)%r81d(io_idx_si_cwd) + io_idx_si_cwd = io_idx_si_cwd + 1 + end do - end do + do i_pft=1,numpft + sites(s)%flux_diags(el)%leaf_litter_input(i_pft) = this%rvars(ir_leaflittin_flxdg+el-1)%r81d(io_idx_si_pft) + sites(s)%flux_diags(el)%root_litter_input(i_pft) = this%rvars(ir_rootlittin_flxdg+el-1)%r81d(io_idx_si_pft) + io_idx_si_pft = io_idx_si_pft + 1 + end do + sites(s)%mass_balance(el)%old_stock = this%rvars(ir_oldstock_mbal+el-1)%r81d(io_idx_si) + sites(s)%mass_balance(el)%err_fates = this%rvars(ir_errfates_mbal+el-1)%r81d(io_idx_si) + sites(s)%mass_balance(el)%wood_product = this%rvars(ir_woodprod_mbal+el-1)%r81d(io_idx_si) + end do + end if + sites(s)%spread = rio_spread_si(io_idx_si) ! Perform a check on the number of patches per site patchespersite = 0 cpatch => sites(s)%oldest_patch - do while(associated(cpatch)) + do_patch: do while(associated(cpatch)) patchespersite = patchespersite + 1 @@ -2787,24 +3207,31 @@ subroutine get_restart_vectors(this, nc, nsites, sites) end do end do - !ccohort%vcmax25top - !ccohort%jmax25top - !ccohort%tpu25top - !ccohort%kp25top - - ccohort%canopy_layer = rio_canopy_layer_co(io_idx_co) ccohort%canopy_layer_yesterday = rio_canopy_layer_yesterday_co(io_idx_co) + ccohort%crowndamage = rio_crowndamage_co(io_idx_co) ccohort%canopy_trim = rio_canopy_trim_co(io_idx_co) + ccohort%l2fr = rio_l2fr_co(io_idx_co) + + if(hlm_parteh_mode .eq. prt_cnp_flex_allom_hyp) then + ccohort%cx_int = this%rvars(ir_cx_int_co)%r81d(io_idx_co) + ccohort%ema_dcxdt = this%rvars(ir_emadcxdt_co)%r81d(io_idx_co) + ccohort%cx0 = this%rvars(ir_cx0_co)%r81d(io_idx_co) + ccohort%cnp_limiter = int(this%rvars(ir_cnplimiter_co)%r81d(io_idx_co)) + ccohort%daily_nh4_uptake = this%rvars(ir_daily_nh4_uptake_co)%r81d(io_idx_co) + ccohort%daily_no3_uptake = this%rvars(ir_daily_no3_uptake_co)%r81d(io_idx_co) + ccohort%sym_nfix_daily = this%rvars(ir_daily_n_fixation_co)%r81d(io_idx_co) + ccohort%daily_p_gain = this%rvars(ir_daily_p_uptake_co)%r81d(io_idx_co) + ccohort%daily_n_demand = this%rvars(ir_daily_n_demand_co)%r81d(io_idx_co) + ccohort%daily_p_demand = this%rvars(ir_daily_p_demand_co)%r81d(io_idx_co) + end if + ccohort%seed_prod = rio_seed_prod_co(io_idx_co) ccohort%size_class_lasttimestep = rio_size_class_lasttimestep(io_idx_co) ccohort%dbh = rio_dbh_co(io_idx_co) ccohort%coage = rio_coage_co(io_idx_co) ccohort%g_sb_laweight= rio_g_sb_laweight_co(io_idx_co) - ccohort%hite = rio_height_co(io_idx_co) - ccohort%laimemory = rio_laimemory_co(io_idx_co) - ccohort%sapwmemory = rio_sapwmemory_co(io_idx_co) - ccohort%structmemory= rio_structmemory_co(io_idx_co) + ccohort%height = rio_height_co(io_idx_co) ccohort%n = rio_nplant_co(io_idx_co) ccohort%gpp_acc = rio_gpp_acc_co(io_idx_co) ccohort%npp_acc = rio_npp_acc_co(io_idx_co) @@ -2812,27 +3239,17 @@ subroutine get_restart_vectors(this, nc, nsites, sites) ccohort%gpp_acc_hold = rio_gpp_acc_hold_co(io_idx_co) ccohort%resp_acc_hold = rio_resp_acc_hold_co(io_idx_co) ccohort%npp_acc_hold = rio_npp_acc_hold_co(io_idx_co) - ccohort%resp_m_def = rio_resp_m_def_co(io_idx_co) + ccohort%resp_excess = rio_resp_excess_co(io_idx_co) ccohort%bmort = rio_bmort_co(io_idx_co) ccohort%hmort = rio_hmort_co(io_idx_co) ccohort%cmort = rio_cmort_co(io_idx_co) ccohort%smort = rio_smort_co(io_idx_co) ccohort%asmort = rio_asmort_co(io_idx_co) + ccohort%dgmort = rio_dgmort_co(io_idx_co) ccohort%frmort = rio_frmort_co(io_idx_co) - ! Nutrient uptake / efflux - ccohort%daily_nh4_uptake = rio_daily_nh4_uptake_co(io_idx_co) - ccohort%daily_no3_uptake = rio_daily_no3_uptake_co(io_idx_co) - ccohort%daily_p_uptake = rio_daily_p_uptake_co(io_idx_co) - ccohort%daily_c_efflux = rio_daily_c_efflux_co(io_idx_co) - ccohort%daily_n_efflux = rio_daily_n_efflux_co(io_idx_co) - ccohort%daily_p_efflux = rio_daily_p_efflux_co(io_idx_co) - - ccohort%daily_n_demand = rio_daily_n_demand_co(io_idx_co) - ccohort%daily_p_demand = rio_daily_p_demand_co(io_idx_co) - ccohort%daily_n_need = rio_daily_n_need_co(io_idx_co) - ccohort%daily_p_need = rio_daily_p_need_co(io_idx_co) + !Logging ccohort%lmort_direct = rio_lmort_direct_co(io_idx_co) @@ -2843,10 +3260,13 @@ subroutine get_restart_vectors(this, nc, nsites, sites) ccohort%resp_tstep = rio_resp_tstep_co(io_idx_co) ccohort%pft = rio_pft_co(io_idx_co) ccohort%status_coh = rio_status_co(io_idx_co) + ccohort%efleaf_coh = rio_efleaf_co(io_idx_co) + ccohort%effnrt_coh = rio_effnrt_co(io_idx_co) + ccohort%efstem_coh = rio_efstem_co(io_idx_co) ccohort%isnew = ( rio_isnew_co(io_idx_co) .eq. new_cohort ) - call UpdateCohortBioPhysRates(ccohort) - + call ccohort%InitPRTBoundaryConditions() + call ccohort%UpdateCohortBioPhysRates() ! Initialize Plant Hydraulics @@ -2905,7 +3325,20 @@ 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) + + 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 if ( debug ) then @@ -2913,69 +3346,73 @@ subroutine get_restart_vectors(this, nc, nsites, sites) ,io_idx_co,cohortsperpatch endif - io_idx_pa_pft = io_idx_co_1st - do i = 1,numpft - cpatch%scorch_ht(i) = this%rvars(ir_scorch_ht_pa_pft)%r81d(io_idx_pa_pft) - io_idx_pa_pft = io_idx_pa_pft + 1 - end do + if(hlm_use_sp.eq.ifalse)then - io_idx_pa_cwd = io_idx_co_1st - do i = 1,nfsc - cpatch%litter_moisture(i) = this%rvars(ir_litter_moisture_pa_nfsc)%r81d(io_idx_pa_cwd) - io_idx_pa_cwd = io_idx_pa_cwd + 1 - end do + io_idx_pa_pft = io_idx_co_1st + do i = 1,numpft + cpatch%scorch_ht(i) = this%rvars(ir_scorch_ht_pa_pft)%r81d(io_idx_pa_pft) + io_idx_pa_pft = io_idx_pa_pft + 1 + end do + + io_idx_pa_cwd = io_idx_co_1st + do i = 1,nfsc + cpatch%litter_moisture(i) = this%rvars(ir_litter_moisture_pa_nfsc)%r81d(io_idx_pa_cwd) + io_idx_pa_cwd = io_idx_pa_cwd + 1 + end do + + ! -------------------------------------------------------------------------- + ! Pull litter from the restart arrays + ! Each element has its own variable, so we have to make sure + ! we keep re-setting this + ! -------------------------------------------------------------------------- + + do el = 0, num_elements-1 + + io_idx_pa_pft = io_idx_co_1st + io_idx_pa_cwd = io_idx_co_1st + io_idx_pa_cwsl = io_idx_co_1st + io_idx_pa_dcsl = io_idx_co_1st + io_idx_pa_dc = io_idx_co_1st + + litt => cpatch%litter(el+1) + nlevsoil = size(litt%bg_cwd,dim=2) + + do i = 1,numpft + litt%seed(i) = this%rvars(ir_seed_litt+el)%r81d(io_idx_pa_pft) + litt%seed_germ(i) = this%rvars(ir_seedgerm_litt+el)%r81d(io_idx_pa_pft) + litt%seed_decay(i) = this%rvars(ir_seed_decay_litt+el)%r81d(io_idx_pa_pft) + litt%seed_germ_decay(i) = this%rvars(ir_seedgerm_decay_litt+el)%r81d(io_idx_pa_pft) + io_idx_pa_pft = io_idx_pa_pft + 1 + end do - ! -------------------------------------------------------------------------- - ! Pull litter from the restart arrays - ! Each element has its own variable, so we have to make sure - ! we keep re-setting this - ! -------------------------------------------------------------------------- - - do el = 0, num_elements-1 - - io_idx_pa_pft = io_idx_co_1st - io_idx_pa_cwd = io_idx_co_1st - io_idx_pa_cwsl = io_idx_co_1st - io_idx_pa_dcsl = io_idx_co_1st - io_idx_pa_dc = io_idx_co_1st - - litt => cpatch%litter(el+1) - nlevsoil = size(litt%bg_cwd,dim=2) - - do i = 1,numpft - litt%seed(i) = this%rvars(ir_seed_litt+el)%r81d(io_idx_pa_pft) - litt%seed_germ(i) = this%rvars(ir_seedgerm_litt+el)%r81d(io_idx_pa_pft) - litt%seed_decay(i) = this%rvars(ir_seed_decay_litt+el)%r81d(io_idx_pa_pft) - litt%seed_germ_decay(i) = this%rvars(ir_seedgerm_decay_litt+el)%r81d(io_idx_pa_pft) - io_idx_pa_pft = io_idx_pa_pft + 1 - end do - - do i = 1,ndcmpy - litt%leaf_fines(i) = this%rvars(ir_leaf_litt+el)%r81d(io_idx_pa_dc) - litt%leaf_fines_frag(i) = this%rvars(ir_lfines_frag_litt+el)%r81d(io_idx_pa_dc) - io_idx_pa_dc = io_idx_pa_dc + 1 - do ilyr=1,nlevsoil + do i = 1,ndcmpy + litt%leaf_fines(i) = this%rvars(ir_leaf_litt+el)%r81d(io_idx_pa_dc) + litt%leaf_fines_frag(i) = this%rvars(ir_lfines_frag_litt+el)%r81d(io_idx_pa_dc) + io_idx_pa_dc = io_idx_pa_dc + 1 + do ilyr=1,nlevsoil litt%root_fines(i,ilyr) = this%rvars(ir_fnrt_litt+el)%r81d(io_idx_pa_dcsl) litt%root_fines_frag(i,ilyr) = this%rvars(ir_rfines_frag_litt+el)%r81d(io_idx_pa_dcsl) io_idx_pa_dcsl = io_idx_pa_dcsl + 1 - end do - end do + end do + end do - do i = 1,ncwd + do i = 1,ncwd - litt%ag_cwd(i) = this%rvars(ir_agcwd_litt+el)%r81d(io_idx_pa_cwd) - litt%ag_cwd_frag(i) = this%rvars(ir_agcwd_frag_litt+el)%r81d(io_idx_pa_cwd) - io_idx_pa_cwd = io_idx_pa_cwd + 1 + litt%ag_cwd(i) = this%rvars(ir_agcwd_litt+el)%r81d(io_idx_pa_cwd) + litt%ag_cwd_frag(i) = this%rvars(ir_agcwd_frag_litt+el)%r81d(io_idx_pa_cwd) + io_idx_pa_cwd = io_idx_pa_cwd + 1 - do ilyr=1,nlevsoil + do ilyr=1,nlevsoil litt%bg_cwd(i,ilyr) = this%rvars(ir_bgcwd_litt+el)%r81d(io_idx_pa_cwsl) litt%bg_cwd_frag(i,ilyr) = this%rvars(ir_bgcwd_frag_litt+el)%r81d(io_idx_pa_cwsl) io_idx_pa_cwsl = io_idx_pa_cwsl + 1 - end do - end do + end do + end do - end do + end do + end if + do i = 1,maxSWb cpatch%gnd_alb_dif(i) = rio_gnd_alb_dif_pasb(io_idx_pa_ib) cpatch%gnd_alb_dir(i) = rio_gnd_alb_dir_pasb(io_idx_pa_ib) @@ -3008,17 +3445,26 @@ subroutine get_restart_vectors(this, nc, nsites, sites) end if cpatch => cpatch%younger - - enddo ! patch do while + enddo do_patch if(patchespersite .ne. rio_npatch_si(io_idx_si)) then write(fates_log(),*) 'Number of patches per site during retrieval does not match allocation' call endrun(msg=errMsg(sourcefile, __LINE__)) end if + do i = 1,nclmax + do i_pft = 1, numpft + sites(s)%rec_l2fr(i_pft,i) = rio_recl2fr_sipfcl(io_idx_si_pfcl) + io_idx_si_pfcl = io_idx_si_pfcl + 1 + end do + end do + do i = 1,numWaterMem - sites(s)%water_memory(i) = rio_watermem_siwm( io_idx_si_wmem ) - io_idx_si_wmem = io_idx_si_wmem + 1 + do i_pft=1,numpft + sites(s)%liqvol_memory(i,i_pft) = rio_liqvolmem_siwmft( io_idx_si_wmem ) + sites(s)%smp_memory(i,i_pft) = rio_smpmem_siwmft( io_idx_si_wmem ) + io_idx_si_wmem = io_idx_si_wmem + 1 + end do end do do i = 1, num_vegtemp_mem @@ -3056,51 +3502,65 @@ subroutine get_restart_vectors(this, nc, nsites, sites) ! Fill the site level diagnostics arrays ! ----------------------------------------------------------------------------- - - io_idx_si_scpf = io_idx_co_1st - do i_scls = 1,nlevsclass - do i_pft = 1, numpft - sites(s)%fmort_rate_canopy(i_scls, i_pft) = rio_fmortrate_cano_siscpf(io_idx_si_scpf) - sites(s)%fmort_rate_ustory(i_scls, i_pft) = rio_fmortrate_usto_siscpf(io_idx_si_scpf) - sites(s)%imort_rate(i_scls, i_pft) = rio_imortrate_siscpf(io_idx_si_scpf) - sites(s)%fmort_rate_crown(i_scls, i_pft) = rio_fmortrate_crown_siscpf(io_idx_si_scpf) - sites(s)%fmort_rate_cambial(i_scls, i_pft) = rio_fmortrate_cambi_siscpf(io_idx_si_scpf) - sites(s)%term_nindivs_canopy(i_scls,i_pft) = rio_termnindiv_cano_siscpf(io_idx_si_scpf) - sites(s)%term_nindivs_ustory(i_scls,i_pft) = rio_termnindiv_usto_siscpf(io_idx_si_scpf) - sites(s)%growthflux_fusion(i_scls, i_pft) = rio_growflx_fusion_siscpf(io_idx_si_scpf) - io_idx_si_scpf = io_idx_si_scpf + 1 - end do sites(s)%demotion_rate(i_scls) = rio_demorate_sisc(io_idx_si_sc) sites(s)%promotion_rate(i_scls) = rio_promrate_sisc(io_idx_si_sc) - + io_idx_si_sc = io_idx_si_sc + 1 end do + + if (hlm_use_tree_damage .eq. itrue) then + do i_cdam = 1, nlevdamage + do i_pft = 1, numpft + do i_scls = 1, nlevsclass + sites(s)%imort_rate_damage(i_cdam, i_scls, i_pft) = rio_imortrate_sicdpf(io_idx_si_cdpf) + sites(s)%term_nindivs_canopy_damage(i_cdam,i_scls,i_pft) = rio_termnindiv_cano_sicdpf(io_idx_si_cdpf) + sites(s)%term_nindivs_ustory_damage(i_cdam,i_scls,i_pft) = rio_termnindiv_usto_sicdpf(io_idx_si_cdpf) + sites(s)%imort_cflux_damage(i_cdam, i_scls) = rio_imortcflux_sicdsc(io_idx_si_cdsc) + sites(s)%term_cflux_canopy_damage(i_cdam, i_scls) = rio_termcflux_cano_sicdsc(io_idx_si_cdsc) + sites(s)%term_cflux_ustory_damage(i_cdam, i_scls) = rio_termcflux_usto_sicdsc(io_idx_si_cdsc) + sites(s)%fmort_rate_canopy_damage(i_cdam, i_scls, i_pft) = rio_fmortrate_cano_sicdpf(io_idx_si_cdpf) + sites(s)%fmort_rate_ustory_damage(i_cdam, i_scls, i_pft) = rio_fmortrate_usto_sicdpf(io_idx_si_cdpf) + sites(s)%fmort_cflux_canopy_damage(i_cdam, i_scls) = rio_fmortcflux_cano_sicdsc(io_idx_si_cdsc) + sites(s)%fmort_cflux_ustory_damage(i_cdam, i_scls) = rio_fmortcflux_usto_sicdsc(io_idx_si_cdsc) + io_idx_si_cdsc = io_idx_si_cdsc + 1 + io_idx_si_cdpf = io_idx_si_cdpf + 1 + end do + end do + end do + + sites(s)%crownarea_canopy_damage = rio_crownarea_cano_damage_si(io_idx_si) + sites(s)%crownarea_ustory_damage = rio_crownarea_usto_damage_si(io_idx_si) + + + end if - sites(s)%term_carbonflux_canopy = rio_termcflux_cano_si(io_idx_si) - sites(s)%term_carbonflux_ustory = rio_termcflux_usto_si(io_idx_si) + sites(s)%ema_npp = rio_emanpp_si(io_idx_si) + sites(s)%term_crownarea_canopy = rio_termcarea_cano_si(io_idx_si) + sites(s)%term_crownarea_ustory = rio_termcarea_usto_si(io_idx_si) + sites(s)%imort_crownarea = rio_imortcarea_si(io_idx_si) + sites(s)%fmort_crownarea_canopy = rio_fmortcarea_cano_si(io_idx_si) + sites(s)%fmort_crownarea_ustory = rio_fmortcarea_usto_si(io_idx_si) sites(s)%demotion_carbonflux = rio_democflux_si(io_idx_si) sites(s)%promotion_carbonflux = rio_promcflux_si(io_idx_si) - sites(s)%imort_carbonflux = rio_imortcflux_si(io_idx_si) - sites(s)%fmort_carbonflux_canopy = rio_fmortcflux_cano_si(io_idx_si) - sites(s)%fmort_carbonflux_ustory = rio_fmortcflux_usto_si(io_idx_si) - ! Site level phenology status flags sites(s)%cstatus = rio_cd_status_si(io_idx_si) - sites(s)%dstatus = rio_dd_status_si(io_idx_si) sites(s)%nchilldays = rio_nchill_days_si(io_idx_si) sites(s)%ncolddays = rio_ncold_days_si(io_idx_si) - sites(s)%cleafondate = rio_leafondate_si(io_idx_si) - sites(s)%cleafoffdate = rio_leafoffdate_si(io_idx_si) - sites(s)%dleafondate = rio_dleafondate_si(io_idx_si) - sites(s)%dleafoffdate = rio_dleafoffdate_si(io_idx_si) - sites(s)%acc_NI = rio_acc_ni_si(io_idx_si) + sites(s)%cleafondate = rio_cleafondate_si(io_idx_si) + sites(s)%cleafoffdate = rio_cleafoffdate_si(io_idx_si) + sites(s)%cndaysleafon = rio_cndaysleafon_si(io_idx_si) + sites(s)%cndaysleafoff = rio_cndaysleafoff_si(io_idx_si) sites(s)%grow_deg_days = rio_gdd_si(io_idx_si) - sites(s)%snow_depth = rio_snow_depth_si(io_idx_si) + sites(s)%phen_model_date= rio_phenmodeldate_si(io_idx_si) + + + sites(s)%acc_NI = rio_acc_ni_si(io_idx_si) + sites(s)%snow_depth = rio_snow_depth_si(io_idx_si) sites(s)%resources_management%trunk_product_site = rio_trunk_product_si(io_idx_si) end do @@ -3122,7 +3582,7 @@ subroutine update_3dpatch_radiation(this, nsites, sites, bc_out) ! ------------------------------------------------------------------------- use EDTypesMod, only : ed_site_type - use EDTypesMod, only : ed_patch_type + use FatesPatchMod, only : fates_patch_type use EDSurfaceRadiationMod, only : PatchNormanRadiation use FatesInterfaceTypesMod, only : hlm_numSWb @@ -3134,7 +3594,7 @@ subroutine update_3dpatch_radiation(this, nsites, sites, bc_out) ! locals ! ---------------------------------------------------------------------------------- - type(ed_patch_type),pointer :: currentPatch ! current patch + type(fates_patch_type),pointer :: currentPatch ! current patch integer :: s ! site counter integer :: ib ! radiation band counter integer :: ifp ! patch counter @@ -3185,10 +3645,8 @@ subroutine update_3dpatch_radiation(this, nsites, sites, bc_out) bc_out(s)%fabi_parb(ifp,:) = 0.0_r8 do ib = 1,hlm_numSWb - ! REQUIRES A FIX HERE albd vs albi - bc_out(s)%albd_parb(ifp,ib) = currentPatch%gnd_alb_dir(ib) - bc_out(s)%albd_parb(ifp,ib) = currentPatch%gnd_alb_dif(ib) + bc_out(s)%albi_parb(ifp,ib) = currentPatch%gnd_alb_dif(ib) bc_out(s)%ftdd_parb(ifp,ib)= 1.0_r8 bc_out(s)%ftid_parb(ifp,ib)= 1.0_r8 bc_out(s)%ftii_parb(ifp,ib)= 1.0_r8 diff --git a/main/FatesRestartVariableType.F90 b/main/FatesRestartVariableType.F90 index 4cec99c349..ac35412adb 100644 --- a/main/FatesRestartVariableType.F90 +++ b/main/FatesRestartVariableType.F90 @@ -3,10 +3,16 @@ module FatesRestartVariableMod use FatesConstantsMod, only : r8 => fates_r8 use FatesGlobals, only : fates_log use FatesIOVariableKindMod, only : fates_io_variable_kind_type - + use FatesGlobals , only : endrun => fates_endrun + use shr_log_mod , only : errMsg => shr_log_errMsg + implicit none private ! Modules are private by default + + character(len=*), parameter, private :: sourcefile = & + __FILE__ + ! This type is instanteated in the HLM-FATES interface (clmfates_interfaceMod.F90) type, public :: fates_restart_variable_type @@ -100,8 +106,7 @@ subroutine Init(this, vname, units, long, vtype, flushval, num_dim_kinds, dim_ki case default write(fates_log(),*) 'Incompatible vtype passed to set_restart_var' write(fates_log(),*) 'vtype = ',trim(vtype),' ?' - stop - ! end_run + call endrun(msg=errMsg(sourcefile, __LINE__)) end select end subroutine Init @@ -188,8 +193,7 @@ subroutine flush(this, thread, dim_bounds, dim_kinds) case default write(fates_log(),*) 'fates history variable type undefined while flushing history variables' - stop - !end_run + call endrun(msg=errMsg(sourcefile, __LINE__)) end select end subroutine Flush diff --git a/main/FatesRunningMeanMod.F90 b/main/FatesRunningMeanMod.F90 index 7fa3bfd7cc..7ef7866d62 100644 --- a/main/FatesRunningMeanMod.F90 +++ b/main/FatesRunningMeanMod.F90 @@ -79,7 +79,6 @@ module FatesRunningMeanMod end type rmean_type - logical, parameter :: debug = .true. character(len=*), parameter, private :: sourcefile = & @@ -91,7 +90,24 @@ 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_longterm ! Exponential moving average - long-term leaf photo acclimation + 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_mort_par ! EMA for seedling mort from light stress + 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_type), pointer :: p + end type rmean_arr_type + contains @@ -197,7 +213,11 @@ subroutine InitRMean(this,rmean_def,init_value,init_offset) if(present(init_value))then this%c_mean = init_value this%l_mean = init_value - this%c_index = 1 + if(present(init_offset))then + this%c_index = min(nint(init_offset/rmean_def%up_period),rmean_def%n_mem) + else + this%c_index = 1 + end if else this%c_mean = nan this%l_mean = nan @@ -296,12 +316,13 @@ subroutine FuseRMean(this,donor,recip_wgt) class(rmean_type) :: this class(rmean_type), pointer :: donor real(r8),intent(in) :: recip_wgt ! Weighting factor for recipient (0-1) - - if(this%def_type%n_mem .ne. donor%def_type%n_mem) then - write(fates_log(), *) 'memory size is somehow different during fusion' - write(fates_log(), *) 'of two running mean variables: '!,this%name,donor%name - call endrun(msg=errMsg(sourcefile, __LINE__)) - end if + + ! Unecessary + !if(this%def_type%n_mem .ne. donor%def_type%n_mem) then + ! write(fates_log(), *) 'memory size is somehow different during fusion' + ! write(fates_log(), *) 'of two running mean variables: '!,this%name,donor%name + ! call endrun(msg=errMsg(sourcefile, __LINE__)) + !end if if(this%def_type%method .eq. fixed_window ) then if (this%c_index .ne. donor%c_index) then diff --git a/main/FatesSizeAgeTypeIndicesMod.F90 b/main/FatesSizeAgeTypeIndicesMod.F90 index d624db1e24..7945bef035 100644 --- a/main/FatesSizeAgeTypeIndicesMod.F90 +++ b/main/FatesSizeAgeTypeIndicesMod.F90 @@ -1,15 +1,19 @@ module FatesSizeAgeTypeIndicesMod use FatesConstantsMod, only : r8 => fates_r8 + use FatesInterfaceTypesMod, only : nlevsclass use FatesInterfaceTypesMod, only : nlevage use FatesInterfaceTypesMod, only : nlevheight use FatesInterfaceTypesMod, only : nlevcoage + use EDParamsMod, only : nclmax + use FatesInterfaceTypesMod, only : nlevdamage 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 use EDParamsMod, only : ED_val_history_coageclass_bin_edges - + use EDParamsMod, only : ED_val_history_damage_bin_edges + implicit none private ! Modules are private by default @@ -21,10 +25,13 @@ module FatesSizeAgeTypeIndicesMod public :: get_height_index public :: get_sizeagepft_class_index public :: get_agepft_class_index + public :: get_cdamagesize_class_index + public :: get_cdamagesizepft_class_index public :: coagetype_class_index public :: get_coage_class_index public :: get_agefuel_class_index - + public :: get_layersizetype_class_index + contains ! ===================================================================================== @@ -39,6 +46,33 @@ function get_age_class_index(age) result( patch_age_class ) end function get_age_class_index + ! ===================================================================================== + + + function get_layersizetype_class_index(layer,dbh,pft) result(iclscpf) + + ! Get the 1D index for a canopy layer x size x pft triplet + + ! Arguments + integer,intent(in) :: layer + real(r8),intent(in) :: dbh + integer,intent(in) :: pft + + integer :: size_class + integer :: iclscpf + + size_class = get_size_class_index(dbh) + + iclscpf = (pft-1)*nlevsclass*nclmax + (size_class-1)*nclmax + layer + + ! FOR ANALYSIS CODE, REVERSE: (assuming indices starting at 1): + + ! pft = ceiling(real(index,r8)/real(nlevsclass*nclmax,r8)) + ! size_class = ceiling(real(index-(pft-1)*nlevsclass*nclmax,r8)/real(nclmax,r8)) + ! layer = index - ((pft-1)*nlevsclass*nclmax + (size_class-1)*nclmax) + + end function get_layersizetype_class_index + ! ===================================================================================== function get_sizeage_class_index(dbh,age) result(size_by_age_class) @@ -59,6 +93,25 @@ function get_sizeage_class_index(dbh,age) result(size_by_age_class) end function get_sizeage_class_index + !====================================================================================== + + + function get_cdamagesize_class_index(dbh,cdamage) result(cdamage_by_size_class) + + ! Arguments + real(r8),intent(in) :: dbh + integer,intent(in) :: cdamage + + integer :: size_class + integer :: cdamage_by_size_class + + size_class = get_size_class_index(dbh) + + cdamage_by_size_class = (cdamage-1)*nlevsclass + size_class + + end function get_cdamagesize_class_index + + ! ===================================================================================== subroutine sizetype_class_index(dbh,pft,size_class,size_by_pft_class) @@ -153,6 +206,25 @@ function get_sizeagepft_class_index(dbh,age,pft) result(size_by_age_by_pft_class end function get_sizeagepft_class_index + ! ===================================================================================== + + function get_cdamagesizepft_class_index(dbh,cdamage,pft) result(cdamage_by_size_by_pft_class) + + ! Arguments + real(r8),intent(in) :: dbh + integer,intent(in) :: cdamage + integer,intent(in) :: pft + + integer :: size_class + integer :: cdamage_by_size_by_pft_class + + size_class = get_size_class_index(dbh) + + cdamage_by_size_by_pft_class = (cdamage-1)*nlevsclass + size_class + & + (pft-1) * nlevsclass * nlevdamage + + end function get_cdamagesizepft_class_index + ! ===================================================================================== function get_agepft_class_index(age,pft) result(age_by_pft_class) diff --git a/main/FatesSynchronizedParamsMod.F90 b/main/FatesSynchronizedParamsMod.F90 index 7f35b8eeec..8cbda3fdb1 100644 --- a/main/FatesSynchronizedParamsMod.F90 +++ b/main/FatesSynchronizedParamsMod.F90 @@ -126,11 +126,11 @@ subroutine ReceiveParamsScalar(this, fates_params) character(len=param_string_length) :: name ! name = 'q10_mr' -! call fates_params%RetreiveParameter(name=name, & +! call fates_params%RetrieveParameter(name=name, & ! data=this%Q10) ! name = 'froz_q10' -! call fates_params%RetreiveParameter(name=name, & +! call fates_params%RetrieveParameter(name=name, & ! data=this%froz_q10) end subroutine ReceiveParamsScalar diff --git a/main/FatesUtilsMod.F90 b/main/FatesUtilsMod.F90 index 20416e16d6..3310b5d6a4 100644 --- a/main/FatesUtilsMod.F90 +++ b/main/FatesUtilsMod.F90 @@ -12,6 +12,7 @@ module FatesUtilsMod ! Make public necessary subroutines and functions public :: check_hlm_list public :: check_var_real + public :: GetNeighborDistance contains @@ -74,6 +75,74 @@ subroutine check_var_real(r8_var, var_name, return_code) end subroutine check_var_real - + + !==========================================================================================! + ! Function to compute the great circle distance between two points: the s suffix denotes ! + ! source point, and f denotes the destination - "forepoint"). The results are given in ! + ! metres. The formula is intended to be accurate for both small and large distances and ! + ! uses double precision to avoid ill-conditioned behaviour of sin and cos for numbers ! + ! close to the n*pi/2. ! + !------------------------------------------------------------------------------------------! + real(r8) function GreatCircleDist(slons,slonf,slats,slatf) + + use FatesConstantsMod, only : earth_radius_eq & + , rad_per_deg + implicit none + + !----- Local variables. ----------------------------------------------------------------! + real(r8), intent(in) :: slons + real(r8), intent(in) :: slonf + real(r8), intent(in) :: slats + real(r8), intent(in) :: slatf + + !----- Local variables. ----------------------------------------------------------------! + real(r8) :: lons + real(r8) :: lonf + real(r8) :: lats + real(r8) :: latf + real(r8) :: dlon + real(r8) :: dlat + real(r8) :: x + real(r8) :: y + !---------------------------------------------------------------------------------------! + + !----- Convert the co-ordinates to double precision and to radians. --------------------! + lons = slons * rad_per_deg + lonf = slonf * rad_per_deg + lats = slats * rad_per_deg + latf = slatf * rad_per_deg + dlon = lonf - lons + dlat = latf - lats + + !----- Find the arcs. ------------------------------------------------------------------! + x = dsin(lats) * dsin(latf) + dcos(lats) * dcos(latf) * dcos(dlon) + y = dsqrt( (dcos(latf)*dsin(dlon)) * (dcos(latf)*dsin(dlon)) & + + (dcos(lats)*dsin(latf)-dsin(lats)*dcos(latf)*dcos(dlon)) & + * (dcos(lats)*dsin(latf)-dsin(lats)*dcos(latf)*dcos(dlon)) ) + + !----- Convert the arcs to actual distance. --------------------------------------------! + GreatCircleDist = earth_radius_eq*datan2(y,x) + + return + + end function GreatCircleDist + + + ! ====================================================================================== + + function GetNeighborDistance(gi,gj,latc,lonc) result(gcd) + + integer, intent(in) :: gi,gj ! indices of gridcells + real(r8), intent(in) :: latc(:),lonc(:) ! lat/lon of gridcells + real(r8) :: gcd + + ! write(fates_log(),*)'neighborhood: size ldomain latc/lonc: ', size(ldomain%latc), size(ldomain%lonc) + + gcd = GreatCircleDist(lonc(gi),lonc(gj), & + latc(gi),latc(gj)) + + end function GetNeighborDistance + + ! ====================================================================================== end module FatesUtilsMod diff --git a/parameter_files/archive/api24.1.0_101722_fates_params_default.cdl b/parameter_files/archive/api24.1.0_101722_fates_params_default.cdl new file mode 100644 index 0000000000..569e6a1ab6 --- /dev/null +++ b/parameter_files/archive/api24.1.0_101722_fates_params_default.cdl @@ -0,0 +1,1538 @@ +netcdf fates_params_default_api24 { +dimensions: + fates_NCWD = 4 ; + fates_history_age_bins = 7 ; + fates_history_coage_bins = 2 ; + fates_history_damage_bins = 2 ; + fates_history_height_bins = 6 ; + fates_history_size_bins = 13 ; + fates_hlm_pftno = 14 ; + fates_hydr_organs = 4 ; + fates_leafage_class = 1 ; + fates_litterclass = 6 ; + fates_pft = 12 ; + fates_plant_organs = 4 ; + fates_string_length = 60 ; +variables: + double fates_history_ageclass_bin_edges(fates_history_age_bins) ; + fates_history_ageclass_bin_edges:units = "yr" ; + fates_history_ageclass_bin_edges:long_name = "Lower edges for age class bins used in age-resolved patch history output" ; + double fates_history_coageclass_bin_edges(fates_history_coage_bins) ; + fates_history_coageclass_bin_edges:units = "years" ; + fates_history_coageclass_bin_edges:long_name = "Lower edges for cohort age class bins used in cohort age resolved history output" ; + double fates_history_height_bin_edges(fates_history_height_bins) ; + fates_history_height_bin_edges:units = "m" ; + fates_history_height_bin_edges:long_name = "Lower edges for height bins used in height-resolved history output" ; + double fates_history_damage_bin_edges(fates_history_damage_bins) ; + fates_history_damage_bin_edges:units = "% crown loss" ; + fates_history_damage_bin_edges:long_name = "Lower edges for damage class bins used in cohort history output" ; + double fates_history_sizeclass_bin_edges(fates_history_size_bins) ; + fates_history_sizeclass_bin_edges:units = "cm" ; + fates_history_sizeclass_bin_edges:long_name = "Lower edges for DBH size class bins used in size-resolved cohort history output" ; + double fates_alloc_organ_id(fates_plant_organs) ; + fates_alloc_organ_id:units = "unitless" ; + fates_alloc_organ_id:long_name = "This is the global index that the organ in this file is associated with, values match those in parteh/PRTGenericMod.F90" ; + double fates_hydro_htftype_node(fates_hydr_organs) ; + fates_hydro_htftype_node:units = "unitless" ; + fates_hydro_htftype_node:long_name = "Switch that defines the hydraulic transfer functions for each organ." ; + char fates_pftname(fates_pft, fates_string_length) ; + fates_pftname:units = "unitless - string" ; + fates_pftname:long_name = "Description of plant type" ; + char fates_hydro_organ_name(fates_hydr_organs, fates_string_length) ; + fates_hydro_organ_name:units = "unitless - string" ; + fates_hydro_organ_name:long_name = "Name of plant hydraulics organs (DONT CHANGE, order matches media list in FatesHydraulicsMemMod.F90)" ; + char fates_alloc_organ_name(fates_plant_organs, fates_string_length) ; + fates_alloc_organ_name:units = "unitless - string" ; + fates_alloc_organ_name:long_name = "Name of plant organs (with alloc_organ_id, must match PRTGenericMod.F90)" ; + char fates_litterclass_name(fates_litterclass, fates_string_length) ; + fates_litterclass_name:units = "unitless - string" ; + fates_litterclass_name:long_name = "Name of the litter classes, for variables associated with dimension fates_litterclass" ; + double fates_alloc_organ_priority(fates_plant_organs, fates_pft) ; + fates_alloc_organ_priority:units = "index" ; + fates_alloc_organ_priority:long_name = "Priority level for allocation, 1: replaces turnover from storage, 2: same priority as storage use/replacement, 3: ascending in order of least importance" ; + double fates_alloc_storage_cushion(fates_pft) ; + fates_alloc_storage_cushion:units = "fraction" ; + fates_alloc_storage_cushion:long_name = "maximum size of storage C pool, relative to maximum size of leaf C pool" ; + double fates_alloc_store_priority_frac(fates_pft) ; + fates_alloc_store_priority_frac:units = "unitless" ; + fates_alloc_store_priority_frac:long_name = "for high-priority organs, the fraction of their turnover demand that is gauranteed to be replaced, and if need-be by storage" ; + double fates_allom_agb1(fates_pft) ; + fates_allom_agb1:units = "variable" ; + fates_allom_agb1:long_name = "Parameter 1 for agb allometry" ; + double fates_allom_agb2(fates_pft) ; + fates_allom_agb2:units = "variable" ; + fates_allom_agb2:long_name = "Parameter 2 for agb allometry" ; + double fates_allom_agb3(fates_pft) ; + fates_allom_agb3:units = "variable" ; + fates_allom_agb3:long_name = "Parameter 3 for agb allometry" ; + double fates_allom_agb4(fates_pft) ; + fates_allom_agb4:units = "variable" ; + fates_allom_agb4:long_name = "Parameter 4 for agb allometry" ; + double fates_allom_agb_frac(fates_pft) ; + fates_allom_agb_frac:units = "fraction" ; + fates_allom_agb_frac:long_name = "Fraction of woody biomass that is above ground" ; + double fates_allom_amode(fates_pft) ; + fates_allom_amode:units = "index" ; + fates_allom_amode:long_name = "AGB allometry function index." ; + double fates_allom_blca_expnt_diff(fates_pft) ; + fates_allom_blca_expnt_diff:units = "unitless" ; + fates_allom_blca_expnt_diff:long_name = "difference between allometric DBH:bleaf and DBH:crown area exponents" ; + double fates_allom_cmode(fates_pft) ; + fates_allom_cmode:units = "index" ; + fates_allom_cmode:long_name = "coarse root biomass allometry function index." ; + double fates_allom_crown_depth_frac(fates_pft) ; + fates_allom_crown_depth_frac:units = "fraction" ; + fates_allom_crown_depth_frac:long_name = "the depth of a cohort crown as a fraction of its height" ; + double fates_allom_d2bl1(fates_pft) ; + fates_allom_d2bl1:units = "variable" ; + fates_allom_d2bl1:long_name = "Parameter 1 for d2bl allometry" ; + double fates_allom_d2bl2(fates_pft) ; + fates_allom_d2bl2:units = "variable" ; + fates_allom_d2bl2:long_name = "Parameter 2 for d2bl allometry" ; + double fates_allom_d2bl3(fates_pft) ; + fates_allom_d2bl3:units = "unitless" ; + fates_allom_d2bl3:long_name = "Parameter 3 for d2bl allometry" ; + double fates_allom_d2ca_coefficient_max(fates_pft) ; + fates_allom_d2ca_coefficient_max:units = "m2 cm^(-1/beta)" ; + fates_allom_d2ca_coefficient_max:long_name = "max (savanna) dbh to area multiplier factor where: area = n*d2ca_coeff*dbh^beta" ; + double fates_allom_d2ca_coefficient_min(fates_pft) ; + fates_allom_d2ca_coefficient_min:units = "m2 cm^(-1/beta)" ; + fates_allom_d2ca_coefficient_min:long_name = "min (forest) dbh to area multiplier factor where: area = n*d2ca_coeff*dbh^beta" ; + double fates_allom_d2h1(fates_pft) ; + fates_allom_d2h1:units = "variable" ; + fates_allom_d2h1:long_name = "Parameter 1 for d2h allometry (intercept, or c)" ; + double fates_allom_d2h2(fates_pft) ; + fates_allom_d2h2:units = "variable" ; + fates_allom_d2h2:long_name = "Parameter 2 for d2h allometry (slope, or m)" ; + double fates_allom_d2h3(fates_pft) ; + fates_allom_d2h3:units = "variable" ; + fates_allom_d2h3:long_name = "Parameter 3 for d2h allometry (optional)" ; + double fates_allom_dbh_maxheight(fates_pft) ; + fates_allom_dbh_maxheight:units = "cm" ; + fates_allom_dbh_maxheight:long_name = "the diameter (if any) corresponding to maximum height, diameters may increase beyond this" ; + double fates_allom_fmode(fates_pft) ; + fates_allom_fmode:units = "index" ; + fates_allom_fmode:long_name = "fine root biomass allometry function index." ; + double fates_allom_fnrt_prof_a(fates_pft) ; + fates_allom_fnrt_prof_a:units = "unitless" ; + fates_allom_fnrt_prof_a:long_name = "Fine root profile function, parameter a" ; + double fates_allom_fnrt_prof_b(fates_pft) ; + fates_allom_fnrt_prof_b:units = "unitless" ; + fates_allom_fnrt_prof_b:long_name = "Fine root profile function, parameter b" ; + double fates_allom_fnrt_prof_mode(fates_pft) ; + fates_allom_fnrt_prof_mode:units = "index" ; + fates_allom_fnrt_prof_mode:long_name = "Index to select fine root profile function: 1) Jackson Beta, 2) 1-param exponential 3) 2-param exponential" ; + double fates_allom_frbstor_repro(fates_pft) ; + fates_allom_frbstor_repro:units = "fraction" ; + fates_allom_frbstor_repro:long_name = "fraction of bstore goes to reproduction after plant dies" ; + double fates_allom_hmode(fates_pft) ; + fates_allom_hmode:units = "index" ; + fates_allom_hmode:long_name = "height allometry function index." ; + double fates_allom_l2fr(fates_pft) ; + fates_allom_l2fr:units = "gC/gC" ; + fates_allom_l2fr:long_name = "Allocation parameter: fine root C per leaf C" ; + double fates_allom_la_per_sa_int(fates_pft) ; + fates_allom_la_per_sa_int:units = "m2/cm2" ; + fates_allom_la_per_sa_int:long_name = "Leaf area per sapwood area, intercept" ; + double fates_allom_la_per_sa_slp(fates_pft) ; + fates_allom_la_per_sa_slp:units = "m2/cm2/m" ; + fates_allom_la_per_sa_slp:long_name = "Leaf area per sapwood area rate of change with height, slope (optional)" ; + double fates_allom_lmode(fates_pft) ; + fates_allom_lmode:units = "index" ; + fates_allom_lmode:long_name = "leaf biomass allometry function index." ; + double fates_allom_sai_scaler(fates_pft) ; + fates_allom_sai_scaler:units = "m2/m2" ; + fates_allom_sai_scaler:long_name = "allometric ratio of SAI per LAI" ; + double fates_allom_smode(fates_pft) ; + fates_allom_smode:units = "index" ; + fates_allom_smode:long_name = "sapwood allometry function index." ; + double fates_allom_stmode(fates_pft) ; + fates_allom_stmode:units = "index" ; + fates_allom_stmode:long_name = "storage allometry function index." ; + double fates_allom_zroot_k(fates_pft) ; + fates_allom_zroot_k:units = "unitless" ; + fates_allom_zroot_k:long_name = "scale coefficient of logistic rooting depth model" ; + double fates_allom_zroot_max_dbh(fates_pft) ; + fates_allom_zroot_max_dbh:units = "cm" ; + fates_allom_zroot_max_dbh:long_name = "dbh at which a plant reaches the maximum value for its maximum rooting depth" ; + double fates_allom_zroot_max_z(fates_pft) ; + fates_allom_zroot_max_z:units = "m" ; + fates_allom_zroot_max_z:long_name = "the maximum rooting depth defined at dbh = fates_allom_zroot_max_dbh. note: max_z=min_z=large, sets rooting depth to soil depth" ; + double fates_allom_zroot_min_dbh(fates_pft) ; + fates_allom_zroot_min_dbh:units = "cm" ; + fates_allom_zroot_min_dbh:long_name = "dbh at which the maximum rooting depth for a recruit is defined" ; + double fates_allom_zroot_min_z(fates_pft) ; + fates_allom_zroot_min_z:units = "m" ; + fates_allom_zroot_min_z:long_name = "the maximum rooting depth defined at dbh = fates_allom_zroot_min_dbh. note: max_z=min_z=large, sets rooting depth to soil depth" ; + double fates_c2b(fates_pft) ; + fates_c2b:units = "ratio" ; + fates_c2b:long_name = "Carbon to biomass multiplier of bulk structural tissues" ; + double fates_cnp_eca_alpha_ptase(fates_pft) ; + fates_cnp_eca_alpha_ptase:units = "g/m3" ; + fates_cnp_eca_alpha_ptase:long_name = "fraction of P from ptase activity sent directly to plant (ECA)" ; + double fates_cnp_eca_decompmicc(fates_pft) ; + fates_cnp_eca_decompmicc:units = "gC/m3" ; + fates_cnp_eca_decompmicc:long_name = "maximum soil microbial decomposer biomass found over depth (will be applied at a reference depth w/ exponential attenuation) (ECA)" ; + double fates_cnp_eca_km_nh4(fates_pft) ; + fates_cnp_eca_km_nh4:units = "gN/m3" ; + fates_cnp_eca_km_nh4:long_name = "half-saturation constant for plant nh4 uptake (ECA)" ; + double fates_cnp_eca_km_no3(fates_pft) ; + fates_cnp_eca_km_no3:units = "gN/m3" ; + fates_cnp_eca_km_no3:long_name = "half-saturation constant for plant no3 uptake (ECA)" ; + double fates_cnp_eca_km_p(fates_pft) ; + fates_cnp_eca_km_p:units = "gP/m3" ; + fates_cnp_eca_km_p:long_name = "half-saturation constant for plant p uptake (ECA)" ; + double fates_cnp_eca_km_ptase(fates_pft) ; + fates_cnp_eca_km_ptase:units = "gP/m3" ; + fates_cnp_eca_km_ptase:long_name = "half-saturation constant for biochemical P (ECA)" ; + double fates_cnp_eca_lambda_ptase(fates_pft) ; + fates_cnp_eca_lambda_ptase:units = "g/m3" ; + fates_cnp_eca_lambda_ptase:long_name = "critical value for biochemical production (ECA)" ; + double fates_cnp_eca_vmax_nh4(fates_pft) ; + fates_cnp_eca_vmax_nh4:units = "gN/gC/s" ; + fates_cnp_eca_vmax_nh4:long_name = "maximum production rate for plant nh4 uptake (ECA)" ; + double fates_cnp_eca_vmax_no3(fates_pft) ; + fates_cnp_eca_vmax_no3:units = "gN/gC/s" ; + fates_cnp_eca_vmax_no3:long_name = "maximum production rate for plant no3 uptake (ECA)" ; + double fates_cnp_eca_vmax_ptase(fates_pft) ; + fates_cnp_eca_vmax_ptase:units = "gP/m2/s" ; + fates_cnp_eca_vmax_ptase:long_name = "maximum production rate for biochemical P (per m2) (ECA)" ; + double fates_cnp_fnrt_adapt_tscale(fates_pft) ; + fates_cnp_fnrt_adapt_tscale:units = "days" ; + fates_cnp_fnrt_adapt_tscale:long_name = "Number of days that is shortest possible doubling period for fine-root adaptation to C/N/P balance" ; + double fates_cnp_nfix1(fates_pft) ; + fates_cnp_nfix1:units = "NA" ; + fates_cnp_nfix1:long_name = "place-holder for future n-fixation parameter (NOT IMPLEMENTED)" ; + double fates_cnp_nitr_store_ratio(fates_pft) ; + fates_cnp_nitr_store_ratio:units = "(gN/gN)" ; + fates_cnp_nitr_store_ratio:long_name = "storeable (labile) N, as a ratio compared to the N bound in cell structures of other organs (see code)" ; + double fates_cnp_phos_store_ratio(fates_pft) ; + fates_cnp_phos_store_ratio:units = "(gP/gP)" ; + fates_cnp_phos_store_ratio:long_name = "storeable (labile) P, as a ratio compared to the P bound in cell structures of other organs (see code)" ; + double fates_cnp_prescribed_nuptake(fates_pft) ; + fates_cnp_prescribed_nuptake:units = "fraction" ; + fates_cnp_prescribed_nuptake:long_name = "Prescribed N uptake flux. 0=fully coupled simulation >0=prescribed (experimental)" ; + double fates_cnp_prescribed_puptake(fates_pft) ; + fates_cnp_prescribed_puptake:units = "fraction" ; + fates_cnp_prescribed_puptake:long_name = "Prescribed P uptake flux. 0=fully coupled simulation, >0=prescribed (experimental)" ; + double fates_cnp_rd_vmax_n(fates_pft) ; + fates_cnp_rd_vmax_n:units = "gN/gC/s" ; + fates_cnp_rd_vmax_n:long_name = "maximum production rate for compbined (NH4+NO3) uptake (RD)" ; + double fates_cnp_store_ovrflw_frac(fates_pft) ; + fates_cnp_store_ovrflw_frac:units = "fraction" ; + fates_cnp_store_ovrflw_frac:long_name = "size of overflow storage (for excess C,N or P) as a fraction of storage target" ; + fates_cnp_store_ovrflw_frac:use_case = "None" ; + double fates_cnp_turnover_nitr_retrans(fates_plant_organs, fates_pft) ; + fates_cnp_turnover_nitr_retrans:units = "fraction" ; + fates_cnp_turnover_nitr_retrans:long_name = "retranslocation (reabsorbtion) fraction of nitrogen in turnover of scenescing tissues" ; + double fates_cnp_turnover_phos_retrans(fates_plant_organs, fates_pft) ; + fates_cnp_turnover_phos_retrans:units = "fraction" ; + fates_cnp_turnover_phos_retrans:long_name = "retranslocation (reabsorbtion) fraction of phosphorus in turnover of scenescing tissues" ; + double fates_cnp_vmax_p(fates_pft) ; + fates_cnp_vmax_p:units = "gP/gC/s" ; + fates_cnp_vmax_p:long_name = "maximum production rate for phosphorus (ECA and RD)" ; + double fates_damage_frac(fates_pft) ; + fates_damage_frac:units = "fraction" ; + fates_damage_frac:long_name = "fraction of cohort damaged in each damage event (event frequency specified in the is_it_damage_time subroutine)" ; + double fates_damage_mort_p1(fates_pft) ; + fates_damage_mort_p1:units = "fraction" ; + fates_damage_mort_p1:long_name = "inflection point of damage mortality function, a value of 0.8 means 50% mortality with 80% loss of crown, turn off with a large number" ; + double fates_damage_mort_p2(fates_pft) ; + fates_damage_mort_p2:units = "unitless" ; + fates_damage_mort_p2:long_name = "rate of mortality increase with damage" ; + double fates_damage_recovery_scalar(fates_pft) ; + fates_damage_recovery_scalar:units = "unitless" ; + fates_damage_recovery_scalar:long_name = "fraction of the cohort that recovers from damage" ; + double fates_dev_arbitrary_pft(fates_pft) ; + fates_dev_arbitrary_pft:units = "unknown" ; + fates_dev_arbitrary_pft:long_name = "Unassociated pft dimensioned free parameter that developers can use for testing arbitrary new hypotheses" ; + double fates_fire_alpha_SH(fates_pft) ; + fates_fire_alpha_SH:units = "m / (kw/m)**(2/3)" ; + fates_fire_alpha_SH:long_name = "spitfire parameter, alpha scorch height, Equation 16 Thonicke et al 2010" ; + double fates_fire_bark_scaler(fates_pft) ; + fates_fire_bark_scaler:units = "fraction" ; + fates_fire_bark_scaler:long_name = "the thickness of a cohorts bark as a fraction of its dbh" ; + double fates_fire_crown_kill(fates_pft) ; + fates_fire_crown_kill:units = "NA" ; + fates_fire_crown_kill:long_name = "fire parameter, see equation 22 in Thonicke et al 2010" ; + double fates_frag_fnrt_fcel(fates_pft) ; + fates_frag_fnrt_fcel:units = "fraction" ; + fates_frag_fnrt_fcel:long_name = "Fine root litter cellulose fraction" ; + double fates_frag_fnrt_flab(fates_pft) ; + fates_frag_fnrt_flab:units = "fraction" ; + fates_frag_fnrt_flab:long_name = "Fine root litter labile fraction" ; + double fates_frag_fnrt_flig(fates_pft) ; + fates_frag_fnrt_flig:units = "fraction" ; + fates_frag_fnrt_flig:long_name = "Fine root litter lignin fraction" ; + double fates_frag_leaf_fcel(fates_pft) ; + fates_frag_leaf_fcel:units = "fraction" ; + fates_frag_leaf_fcel:long_name = "Leaf litter cellulose fraction" ; + double fates_frag_leaf_flab(fates_pft) ; + fates_frag_leaf_flab:units = "fraction" ; + fates_frag_leaf_flab:long_name = "Leaf litter labile fraction" ; + double fates_frag_leaf_flig(fates_pft) ; + fates_frag_leaf_flig:units = "fraction" ; + fates_frag_leaf_flig:long_name = "Leaf litter lignin fraction" ; + double fates_frag_seed_decay_rate(fates_pft) ; + fates_frag_seed_decay_rate:units = "yr-1" ; + fates_frag_seed_decay_rate:long_name = "fraction of seeds that decay per year" ; + double fates_grperc(fates_pft) ; + fates_grperc:units = "unitless" ; + fates_grperc:long_name = "Growth respiration factor" ; + double fates_hydro_avuln_gs(fates_pft) ; + fates_hydro_avuln_gs:units = "unitless" ; + fates_hydro_avuln_gs:long_name = "shape parameter for stomatal control of water vapor exiting leaf" ; + double fates_hydro_avuln_node(fates_hydr_organs, fates_pft) ; + fates_hydro_avuln_node:units = "unitless" ; + fates_hydro_avuln_node:long_name = "xylem vulnerability curve shape parameter" ; + double fates_hydro_epsil_node(fates_hydr_organs, fates_pft) ; + fates_hydro_epsil_node:units = "MPa" ; + fates_hydro_epsil_node:long_name = "bulk elastic modulus" ; + double fates_hydro_fcap_node(fates_hydr_organs, fates_pft) ; + fates_hydro_fcap_node:units = "unitless" ; + fates_hydro_fcap_node:long_name = "fraction of non-residual water that is capillary in source" ; + double fates_hydro_k_lwp(fates_pft) ; + fates_hydro_k_lwp:units = "unitless" ; + fates_hydro_k_lwp:long_name = "inner leaf humidity scaling coefficient" ; + double fates_hydro_kmax_node(fates_hydr_organs, fates_pft) ; + fates_hydro_kmax_node:units = "kg/MPa/m/s" ; + fates_hydro_kmax_node:long_name = "maximum xylem conductivity per unit conducting xylem area" ; + double fates_hydro_p50_gs(fates_pft) ; + fates_hydro_p50_gs:units = "MPa" ; + fates_hydro_p50_gs:long_name = "water potential at 50% loss of stomatal conductance" ; + double fates_hydro_p50_node(fates_hydr_organs, fates_pft) ; + fates_hydro_p50_node:units = "MPa" ; + fates_hydro_p50_node:long_name = "xylem water potential at 50% loss of conductivity" ; + double fates_hydro_p_taper(fates_pft) ; + fates_hydro_p_taper:units = "unitless" ; + fates_hydro_p_taper:long_name = "xylem taper exponent" ; + double fates_hydro_pinot_node(fates_hydr_organs, fates_pft) ; + fates_hydro_pinot_node:units = "MPa" ; + fates_hydro_pinot_node:long_name = "osmotic potential at full turgor" ; + double fates_hydro_pitlp_node(fates_hydr_organs, fates_pft) ; + fates_hydro_pitlp_node:units = "MPa" ; + fates_hydro_pitlp_node:long_name = "turgor loss point" ; + double fates_hydro_resid_node(fates_hydr_organs, fates_pft) ; + fates_hydro_resid_node:units = "cm3/cm3" ; + fates_hydro_resid_node:long_name = "residual water conent" ; + double fates_hydro_rfrac_stem(fates_pft) ; + fates_hydro_rfrac_stem:units = "fraction" ; + fates_hydro_rfrac_stem:long_name = "fraction of total tree resistance from troot to canopy" ; + double fates_hydro_rs2(fates_pft) ; + fates_hydro_rs2:units = "m" ; + fates_hydro_rs2:long_name = "absorbing root radius" ; + double fates_hydro_srl(fates_pft) ; + fates_hydro_srl:units = "m g-1" ; + fates_hydro_srl:long_name = "specific root length" ; + double fates_hydro_thetas_node(fates_hydr_organs, fates_pft) ; + fates_hydro_thetas_node:units = "cm3/cm3" ; + fates_hydro_thetas_node:long_name = "saturated water content" ; + double fates_hydro_vg_alpha_node(fates_hydr_organs, fates_pft) ; + fates_hydro_vg_alpha_node:units = "MPa-1" ; + fates_hydro_vg_alpha_node:long_name = "(used if hydr_htftype_node = 2), capillary length parameter in van Genuchten model" ; + double fates_hydro_vg_m_node(fates_hydr_organs, fates_pft) ; + fates_hydro_vg_m_node:units = "unitless" ; + fates_hydro_vg_m_node:long_name = "(used if hydr_htftype_node = 2),m in van Genuchten 1980 model, 2nd pore size distribution parameter" ; + double fates_hydro_vg_n_node(fates_hydr_organs, fates_pft) ; + fates_hydro_vg_n_node:units = "unitless" ; + fates_hydro_vg_n_node:long_name = "(used if hydr_htftype_node = 2),n in van Genuchten 1980 model, pore size distribution parameter" ; + double fates_leaf_c3psn(fates_pft) ; + fates_leaf_c3psn:units = "flag" ; + fates_leaf_c3psn:long_name = "Photosynthetic pathway (1=c3, 0=c4)" ; + double fates_leaf_jmaxha(fates_pft) ; + fates_leaf_jmaxha:units = "J/mol" ; + fates_leaf_jmaxha:long_name = "activation energy for jmax" ; + double fates_leaf_jmaxhd(fates_pft) ; + fates_leaf_jmaxhd:units = "J/mol" ; + fates_leaf_jmaxhd:long_name = "deactivation energy for jmax" ; + double fates_leaf_jmaxse(fates_pft) ; + fates_leaf_jmaxse:units = "J/mol/K" ; + fates_leaf_jmaxse:long_name = "entropy term for jmax" ; + double fates_leaf_slamax(fates_pft) ; + fates_leaf_slamax:units = "m^2/gC" ; + fates_leaf_slamax:long_name = "Maximum Specific Leaf Area (SLA), even if under a dense canopy" ; + double fates_leaf_slatop(fates_pft) ; + fates_leaf_slatop:units = "m^2/gC" ; + fates_leaf_slatop:long_name = "Specific Leaf Area (SLA) at top of canopy, projected area basis" ; + double fates_leaf_stomatal_intercept(fates_pft) ; + fates_leaf_stomatal_intercept:units = "umol H2O/m**2/s" ; + fates_leaf_stomatal_intercept:long_name = "Minimum unstressed stomatal conductance for Ball-Berry model and Medlyn model" ; + double fates_leaf_stomatal_slope_ballberry(fates_pft) ; + fates_leaf_stomatal_slope_ballberry:units = "unitless" ; + fates_leaf_stomatal_slope_ballberry:long_name = "stomatal slope parameter, as per Ball-Berry" ; + double fates_leaf_stomatal_slope_medlyn(fates_pft) ; + fates_leaf_stomatal_slope_medlyn:units = "KPa**0.5" ; + fates_leaf_stomatal_slope_medlyn:long_name = "stomatal slope parameter, as per Medlyn" ; + double fates_leaf_vcmax25top(fates_leafage_class, fates_pft) ; + fates_leaf_vcmax25top:units = "umol CO2/m^2/s" ; + fates_leaf_vcmax25top:long_name = "maximum carboxylation rate of Rub. at 25C, canopy top" ; + double fates_leaf_vcmaxha(fates_pft) ; + fates_leaf_vcmaxha:units = "J/mol" ; + fates_leaf_vcmaxha:long_name = "activation energy for vcmax" ; + double fates_leaf_vcmaxhd(fates_pft) ; + fates_leaf_vcmaxhd:units = "J/mol" ; + fates_leaf_vcmaxhd:long_name = "deactivation energy for vcmax" ; + double fates_leaf_vcmaxse(fates_pft) ; + fates_leaf_vcmaxse:units = "J/mol/K" ; + fates_leaf_vcmaxse:long_name = "entropy term for vcmax" ; + double fates_maintresp_reduction_curvature(fates_pft) ; + fates_maintresp_reduction_curvature:units = "unitless (0-1)" ; + fates_maintresp_reduction_curvature:long_name = "curvature of MR reduction as f(carbon storage), 1=linear, 0=very curved" ; + double fates_maintresp_reduction_intercept(fates_pft) ; + fates_maintresp_reduction_intercept:units = "unitless (0-1)" ; + fates_maintresp_reduction_intercept:long_name = "intercept of MR reduction as f(carbon storage), 0=no throttling, 1=max throttling" ; + double fates_mort_bmort(fates_pft) ; + fates_mort_bmort:units = "1/yr" ; + fates_mort_bmort:long_name = "background mortality rate" ; + double fates_mort_freezetol(fates_pft) ; + fates_mort_freezetol:units = "degrees C" ; + fates_mort_freezetol:long_name = "minimum temperature tolerance" ; + double fates_mort_hf_flc_threshold(fates_pft) ; + fates_mort_hf_flc_threshold:units = "fraction" ; + fates_mort_hf_flc_threshold:long_name = "plant fractional loss of conductivity at which drought mortality begins for hydraulic model" ; + double fates_mort_hf_sm_threshold(fates_pft) ; + fates_mort_hf_sm_threshold:units = "unitless" ; + fates_mort_hf_sm_threshold:long_name = "soil moisture (btran units) at which drought mortality begins for non-hydraulic model" ; + double fates_mort_ip_age_senescence(fates_pft) ; + fates_mort_ip_age_senescence:units = "years" ; + fates_mort_ip_age_senescence:long_name = "Mortality cohort age senescence inflection point. If _ this mortality term is off. Setting this value turns on age dependent mortality. " ; + double fates_mort_ip_size_senescence(fates_pft) ; + fates_mort_ip_size_senescence:units = "dbh cm" ; + fates_mort_ip_size_senescence:long_name = "Mortality dbh senescence inflection point. If _ this mortality term is off. Setting this value turns on size dependent mortality" ; + double fates_mort_prescribed_canopy(fates_pft) ; + fates_mort_prescribed_canopy:units = "1/yr" ; + fates_mort_prescribed_canopy:long_name = "mortality rate of canopy trees for prescribed physiology mode" ; + double fates_mort_prescribed_understory(fates_pft) ; + fates_mort_prescribed_understory:units = "1/yr" ; + fates_mort_prescribed_understory:long_name = "mortality rate of understory trees for prescribed physiology mode" ; + double fates_mort_r_age_senescence(fates_pft) ; + fates_mort_r_age_senescence:units = "mortality rate year^-1" ; + fates_mort_r_age_senescence:long_name = "Mortality age senescence rate of change. Sensible range is around 0.03-0.06. Larger values givesteeper mortality curves." ; + double fates_mort_r_size_senescence(fates_pft) ; + fates_mort_r_size_senescence:units = "mortality rate dbh^-1" ; + fates_mort_r_size_senescence:long_name = "Mortality dbh senescence rate of change. Sensible range is around 0.03-0.06. Larger values give steeper mortality curves." ; + double fates_mort_scalar_coldstress(fates_pft) ; + fates_mort_scalar_coldstress:units = "1/yr" ; + fates_mort_scalar_coldstress:long_name = "maximum mortality rate from cold stress" ; + double fates_mort_scalar_cstarvation(fates_pft) ; + fates_mort_scalar_cstarvation:units = "1/yr" ; + fates_mort_scalar_cstarvation:long_name = "maximum mortality rate from carbon starvation" ; + double fates_mort_scalar_hydrfailure(fates_pft) ; + fates_mort_scalar_hydrfailure:units = "1/yr" ; + fates_mort_scalar_hydrfailure:long_name = "maximum mortality rate from hydraulic failure" ; + double fates_nonhydro_smpsc(fates_pft) ; + fates_nonhydro_smpsc:units = "mm" ; + fates_nonhydro_smpsc:long_name = "Soil water potential at full stomatal closure" ; + double fates_nonhydro_smpso(fates_pft) ; + fates_nonhydro_smpso:units = "mm" ; + fates_nonhydro_smpso:long_name = "Soil water potential at full stomatal opening" ; + double fates_phen_cold_size_threshold(fates_pft) ; + fates_phen_cold_size_threshold:units = "cm" ; + fates_phen_cold_size_threshold:long_name = "the dbh size above which will lead to phenology-related stem and leaf drop" ; + double fates_phen_evergreen(fates_pft) ; + fates_phen_evergreen:units = "logical flag" ; + fates_phen_evergreen:long_name = "Binary flag for evergreen leaf habit" ; + double fates_phen_flush_fraction(fates_pft) ; + fates_phen_flush_fraction:units = "fraction" ; + fates_phen_flush_fraction:long_name = "Upon bud-burst, the maximum fraction of storage carbon used for flushing leaves" ; + double fates_phen_fnrt_drop_frac(fates_pft) ; + fates_phen_fnrt_drop_frac:units = "fraction" ; + fates_phen_fnrt_drop_frac:long_name = "fraction of fine roots to drop during drought or cold" ; + double fates_phen_season_decid(fates_pft) ; + fates_phen_season_decid:units = "logical flag" ; + fates_phen_season_decid:long_name = "Binary flag for seasonal-deciduous leaf habit" ; + double fates_phen_stem_drop_fraction(fates_pft) ; + fates_phen_stem_drop_fraction:units = "fraction" ; + fates_phen_stem_drop_fraction:long_name = "fraction of stems to drop for non-woody species during drought/cold" ; + double fates_phen_stress_decid(fates_pft) ; + fates_phen_stress_decid:units = "logical flag" ; + fates_phen_stress_decid:long_name = "Binary flag for stress-deciduous leaf habit" ; + double fates_prescribed_npp_canopy(fates_pft) ; + fates_prescribed_npp_canopy:units = "kgC / m^2 / yr" ; + fates_prescribed_npp_canopy:long_name = "NPP per unit crown area of canopy trees for prescribed physiology mode" ; + double fates_prescribed_npp_understory(fates_pft) ; + fates_prescribed_npp_understory:units = "kgC / m^2 / yr" ; + fates_prescribed_npp_understory:long_name = "NPP per unit crown area of understory trees for prescribed physiology mode" ; + double fates_rad_leaf_clumping_index(fates_pft) ; + fates_rad_leaf_clumping_index:units = "fraction (0-1)" ; + fates_rad_leaf_clumping_index:long_name = "factor describing how much self-occlusion of leaf scattering elements decreases light interception" ; + double fates_rad_leaf_rhonir(fates_pft) ; + fates_rad_leaf_rhonir:units = "fraction" ; + fates_rad_leaf_rhonir:long_name = "Leaf reflectance: near-IR" ; + double fates_rad_leaf_rhovis(fates_pft) ; + fates_rad_leaf_rhovis:units = "fraction" ; + fates_rad_leaf_rhovis:long_name = "Leaf reflectance: visible" ; + double fates_rad_leaf_taunir(fates_pft) ; + fates_rad_leaf_taunir:units = "fraction" ; + fates_rad_leaf_taunir:long_name = "Leaf transmittance: near-IR" ; + double fates_rad_leaf_tauvis(fates_pft) ; + fates_rad_leaf_tauvis:units = "fraction" ; + fates_rad_leaf_tauvis:long_name = "Leaf transmittance: visible" ; + double fates_rad_leaf_xl(fates_pft) ; + fates_rad_leaf_xl:units = "unitless" ; + fates_rad_leaf_xl:long_name = "Leaf/stem orientation index" ; + double fates_rad_stem_rhonir(fates_pft) ; + fates_rad_stem_rhonir:units = "fraction" ; + fates_rad_stem_rhonir:long_name = "Stem reflectance: near-IR" ; + double fates_rad_stem_rhovis(fates_pft) ; + fates_rad_stem_rhovis:units = "fraction" ; + fates_rad_stem_rhovis:long_name = "Stem reflectance: visible" ; + double fates_rad_stem_taunir(fates_pft) ; + fates_rad_stem_taunir:units = "fraction" ; + fates_rad_stem_taunir:long_name = "Stem transmittance: near-IR" ; + double fates_rad_stem_tauvis(fates_pft) ; + fates_rad_stem_tauvis:units = "fraction" ; + fates_rad_stem_tauvis:long_name = "Stem transmittance: visible" ; + double fates_recruit_height_min(fates_pft) ; + fates_recruit_height_min:units = "m" ; + fates_recruit_height_min:long_name = "the minimum height (ie starting height) of a newly recruited plant" ; + double fates_recruit_init_density(fates_pft) ; + fates_recruit_init_density:units = "stems/m2" ; + fates_recruit_init_density:long_name = "initial seedling density for a cold-start near-bare-ground simulation" ; + double fates_recruit_prescribed_rate(fates_pft) ; + fates_recruit_prescribed_rate:units = "n/yr" ; + fates_recruit_prescribed_rate:long_name = "recruitment rate for prescribed physiology mode" ; + double fates_recruit_seed_alloc(fates_pft) ; + fates_recruit_seed_alloc:units = "fraction" ; + fates_recruit_seed_alloc:long_name = "fraction of available carbon balance allocated to seeds" ; + double fates_recruit_seed_alloc_mature(fates_pft) ; + fates_recruit_seed_alloc_mature:units = "fraction" ; + fates_recruit_seed_alloc_mature:long_name = "fraction of available carbon balance allocated to seeds in mature plants (adds to fates_seed_alloc)" ; + double fates_recruit_seed_dbh_repro_threshold(fates_pft) ; + fates_recruit_seed_dbh_repro_threshold:units = "cm" ; + fates_recruit_seed_dbh_repro_threshold:long_name = "the diameter (if any) where the plant will start extra clonal allocation to the seed pool" ; + double fates_recruit_seed_germination_rate(fates_pft) ; + fates_recruit_seed_germination_rate:units = "yr-1" ; + fates_recruit_seed_germination_rate:long_name = "fraction of seeds that germinate per year" ; + double fates_recruit_seed_supplement(fates_pft) ; + fates_recruit_seed_supplement:units = "KgC/m2/yr" ; + fates_recruit_seed_supplement:long_name = "Supplemental external seed rain source term (non-mass conserving)" ; + double fates_stoich_nitr(fates_plant_organs, fates_pft) ; + fates_stoich_nitr:units = "gN/gC" ; + fates_stoich_nitr:long_name = "target nitrogen concentration (ratio with carbon) of organs" ; + double fates_stoich_phos(fates_plant_organs, fates_pft) ; + fates_stoich_phos:units = "gP/gC" ; + fates_stoich_phos:long_name = "target phosphorus concentration (ratio with carbon) of organs" ; + double fates_trim_inc(fates_pft) ; + fates_trim_inc:units = "m2/m2" ; + fates_trim_inc:long_name = "Arbitrary incremental change in trimming function." ; + double fates_trim_limit(fates_pft) ; + fates_trim_limit:units = "m2/m2" ; + fates_trim_limit:long_name = "Arbitrary limit to reductions in leaf area with stress" ; + double fates_turb_displar(fates_pft) ; + fates_turb_displar:units = "unitless" ; + fates_turb_displar:long_name = "Ratio of displacement height to canopy top height" ; + double fates_turb_leaf_diameter(fates_pft) ; + fates_turb_leaf_diameter:units = "m" ; + fates_turb_leaf_diameter:long_name = "Characteristic leaf dimension" ; + double fates_turb_z0mr(fates_pft) ; + fates_turb_z0mr:units = "unitless" ; + fates_turb_z0mr:long_name = "Ratio of momentum roughness length to canopy top height" ; + double fates_turnover_branch(fates_pft) ; + fates_turnover_branch:units = "yr" ; + fates_turnover_branch:long_name = "turnover time of branches" ; + double fates_turnover_fnrt(fates_pft) ; + fates_turnover_fnrt:units = "yr" ; + fates_turnover_fnrt:long_name = "root longevity (alternatively, turnover time)" ; + double fates_turnover_leaf(fates_leafage_class, fates_pft) ; + fates_turnover_leaf:units = "yr" ; + fates_turnover_leaf:long_name = "Leaf longevity (ie turnover timescale)" ; + double fates_turnover_senleaf_fdrought(fates_pft) ; + fates_turnover_senleaf_fdrought:units = "unitless[0-1]" ; + fates_turnover_senleaf_fdrought:long_name = "multiplication factor for leaf longevity of senescent leaves during drought" ; + double fates_wood_density(fates_pft) ; + fates_wood_density:units = "g/cm3" ; + fates_wood_density:long_name = "mean density of woody tissue in plant" ; + double fates_woody(fates_pft) ; + fates_woody:units = "logical flag" ; + fates_woody:long_name = "Binary woody lifeform flag" ; + double fates_hlm_pft_map(fates_hlm_pftno, fates_pft) ; + fates_hlm_pft_map:units = "area fraction" ; + fates_hlm_pft_map:long_name = "In fixed biogeog mode, fraction of HLM area associated with each FATES PFT" ; + double fates_fire_FBD(fates_litterclass) ; + fates_fire_FBD:units = "kg Biomass/m3" ; + fates_fire_FBD:long_name = "fuel bulk density" ; + double fates_fire_low_moisture_Coeff(fates_litterclass) ; + fates_fire_low_moisture_Coeff:units = "NA" ; + fates_fire_low_moisture_Coeff:long_name = "spitfire parameter, equation B1 Thonicke et al 2010" ; + double fates_fire_low_moisture_Slope(fates_litterclass) ; + fates_fire_low_moisture_Slope:units = "NA" ; + fates_fire_low_moisture_Slope:long_name = "spitfire parameter, equation B1 Thonicke et al 2010" ; + double fates_fire_mid_moisture(fates_litterclass) ; + fates_fire_mid_moisture:units = "NA" ; + fates_fire_mid_moisture:long_name = "spitfire litter moisture threshold to be considered medium dry" ; + double fates_fire_mid_moisture_Coeff(fates_litterclass) ; + fates_fire_mid_moisture_Coeff:units = "NA" ; + fates_fire_mid_moisture_Coeff:long_name = "spitfire parameter, equation B1 Thonicke et al 2010" ; + double fates_fire_mid_moisture_Slope(fates_litterclass) ; + fates_fire_mid_moisture_Slope:units = "NA" ; + fates_fire_mid_moisture_Slope:long_name = "spitfire parameter, equation B1 Thonicke et al 2010" ; + double fates_fire_min_moisture(fates_litterclass) ; + fates_fire_min_moisture:units = "NA" ; + fates_fire_min_moisture:long_name = "spitfire litter moisture threshold to be considered very dry" ; + double fates_fire_SAV(fates_litterclass) ; + fates_fire_SAV:units = "cm-1" ; + fates_fire_SAV:long_name = "fuel surface area to volume ratio" ; + double fates_frag_maxdecomp(fates_litterclass) ; + fates_frag_maxdecomp:units = "yr-1" ; + fates_frag_maxdecomp:long_name = "maximum rate of litter & CWD transfer from non-decomposing class into decomposing class" ; + double fates_frag_cwd_frac(fates_NCWD) ; + fates_frag_cwd_frac:units = "fraction" ; + fates_frag_cwd_frac:long_name = "fraction of woody (bdead+bsw) biomass destined for CWD pool" ; + double fates_base_mr_20 ; + fates_base_mr_20:units = "gC/gN/s" ; + fates_base_mr_20:long_name = "Base maintenance respiration rate for plant tissues, using Ryan 1991" ; + double fates_canopy_closure_thresh ; + fates_canopy_closure_thresh:units = "unitless" ; + fates_canopy_closure_thresh:long_name = "tree canopy coverage at which crown area allometry changes from savanna to forest value" ; + double fates_cnp_eca_plant_escalar ; + fates_cnp_eca_plant_escalar:units = "" ; + fates_cnp_eca_plant_escalar:long_name = "scaling factor for plant fine root biomass to calculate nutrient carrier enzyme abundance (ECA)" ; + double fates_cohort_age_fusion_tol ; + fates_cohort_age_fusion_tol:units = "unitless" ; + fates_cohort_age_fusion_tol:long_name = "minimum fraction in differece in cohort age between cohorts." ; + double fates_cohort_size_fusion_tol ; + fates_cohort_size_fusion_tol:units = "unitless" ; + fates_cohort_size_fusion_tol:long_name = "minimum fraction in difference in dbh between cohorts" ; + double fates_comp_excln ; + fates_comp_excln:units = "none" ; + fates_comp_excln:long_name = "IF POSITIVE: weighting factor (exponent on dbh) for canopy layer exclusion and promotion, IF NEGATIVE: switch to use deterministic height sorting" ; + double fates_damage_canopy_layer_code ; + fates_damage_canopy_layer_code:units = "unitless" ; + fates_damage_canopy_layer_code:long_name = "Integer code that decides whether damage affects canopy trees (1), understory trees (2)" ; + double fates_damage_event_code ; + fates_damage_event_code:units = "unitless" ; + fates_damage_event_code:long_name = "Integer code that options how damage events are structured" ; + double fates_dev_arbitrary ; + fates_dev_arbitrary:units = "unknown" ; + fates_dev_arbitrary:long_name = "Unassociated free parameter that developers can use for testing arbitrary new hypotheses" ; + double fates_fire_active_crown_fire ; + fates_fire_active_crown_fire:units = "0 or 1" ; + fates_fire_active_crown_fire:long_name = "flag, 1=active crown fire 0=no active crown fire" ; + double fates_fire_cg_strikes ; + fates_fire_cg_strikes:units = "fraction (0-1)" ; + fates_fire_cg_strikes:long_name = "fraction of cloud to ground lightning strikes" ; + double fates_fire_drying_ratio ; + fates_fire_drying_ratio:units = "NA" ; + fates_fire_drying_ratio:long_name = "spitfire parameter, fire drying ratio for fuel moisture, alpha_FMC EQ 6 Thonicke et al 2010" ; + double fates_fire_durat_slope ; + fates_fire_durat_slope:units = "NA" ; + fates_fire_durat_slope:long_name = "spitfire parameter, fire max duration slope, Equation 14 Thonicke et al 2010" ; + double fates_fire_fdi_a ; + fates_fire_fdi_a:units = "NA" ; + fates_fire_fdi_a:long_name = "spitfire parameter, fire danger index, EQ 5 Thonicke et al 2010" ; + double fates_fire_fdi_alpha ; + fates_fire_fdi_alpha:units = "NA" ; + fates_fire_fdi_alpha:long_name = "spitfire parameter, EQ 7 Venevsky et al. GCB 2002,(modified EQ 8 Thonicke et al. 2010) " ; + double fates_fire_fdi_b ; + fates_fire_fdi_b:units = "NA" ; + fates_fire_fdi_b:long_name = "spitfire parameter, fire danger index, EQ 5 Thonicke et al 2010 " ; + double fates_fire_fuel_energy ; + fates_fire_fuel_energy:units = "kJ/kg" ; + fates_fire_fuel_energy:long_name = "spitfire parameter, heat content of fuel" ; + double fates_fire_max_durat ; + fates_fire_max_durat:units = "minutes" ; + fates_fire_max_durat:long_name = "spitfire parameter, fire maximum duration, Equation 14 Thonicke et al 2010" ; + double fates_fire_miner_damp ; + fates_fire_miner_damp:units = "NA" ; + fates_fire_miner_damp:long_name = "spitfire parameter, mineral-dampening coefficient EQ A1 Thonicke et al 2010 " ; + double fates_fire_miner_total ; + fates_fire_miner_total:units = "fraction" ; + fates_fire_miner_total:long_name = "spitfire parameter, total mineral content, Table A1 Thonicke et al 2010" ; + double fates_fire_nignitions ; + fates_fire_nignitions:units = "ignitions per year per km2" ; + fates_fire_nignitions:long_name = "number of annual ignitions per square km" ; + double fates_fire_part_dens ; + fates_fire_part_dens:units = "kg/m2" ; + fates_fire_part_dens:long_name = "spitfire parameter, oven dry particle density, Table A1 Thonicke et al 2010" ; + double fates_fire_threshold ; + fates_fire_threshold:units = "kW/m" ; + fates_fire_threshold:long_name = "spitfire parameter, fire intensity threshold for tracking fires that spread" ; + double fates_frag_cwd_fcel ; + fates_frag_cwd_fcel:units = "unitless" ; + fates_frag_cwd_fcel:long_name = "Cellulose fraction for CWD" ; + double fates_frag_cwd_flig ; + fates_frag_cwd_flig:units = "unitless" ; + fates_frag_cwd_flig:long_name = "Lignin fraction of coarse woody debris" ; + double fates_hydro_kmax_rsurf1 ; + fates_hydro_kmax_rsurf1:units = "kg water/m2 root area/Mpa/s" ; + fates_hydro_kmax_rsurf1:long_name = "maximum conducitivity for unit root surface (into root)" ; + double fates_hydro_kmax_rsurf2 ; + fates_hydro_kmax_rsurf2:units = "kg water/m2 root area/Mpa/s" ; + fates_hydro_kmax_rsurf2:long_name = "maximum conducitivity for unit root surface (out of root)" ; + double fates_hydro_psi0 ; + fates_hydro_psi0:units = "MPa" ; + fates_hydro_psi0:long_name = "sapwood water potential at saturation" ; + double fates_hydro_psicap ; + fates_hydro_psicap:units = "MPa" ; + fates_hydro_psicap:long_name = "sapwood water potential at which capillary reserves exhausted" ; + double fates_hydro_solver ; + fates_hydro_solver:units = "unitless" ; + fates_hydro_solver:long_name = "switch designating which numerical solver for plant hydraulics, 1 = 1D taylor, 2 = 2D Picard, 3 = 2D Newton (deprecated)" ; + double fates_landuse_logging_coll_under_frac ; + fates_landuse_logging_coll_under_frac:units = "fraction" ; + fates_landuse_logging_coll_under_frac:long_name = "Fraction of stems killed in the understory when logging generates disturbance" ; + double fates_landuse_logging_collateral_frac ; + fates_landuse_logging_collateral_frac:units = "fraction" ; + fates_landuse_logging_collateral_frac:long_name = "Fraction of large stems in upperstory that die from logging collateral damage" ; + double fates_landuse_logging_dbhmax ; + fates_landuse_logging_dbhmax:units = "cm" ; + fates_landuse_logging_dbhmax:long_name = "Maximum dbh below which logging is applied (unset values flag this to be unused)" ; + double fates_landuse_logging_dbhmax_infra ; + fates_landuse_logging_dbhmax_infra:units = "cm" ; + fates_landuse_logging_dbhmax_infra:long_name = "Tree diameter, above which infrastructure from logging does not impact damage or mortality." ; + double fates_landuse_logging_dbhmin ; + fates_landuse_logging_dbhmin:units = "cm" ; + fates_landuse_logging_dbhmin:long_name = "Minimum dbh at which logging is applied" ; + double fates_landuse_logging_direct_frac ; + fates_landuse_logging_direct_frac:units = "fraction" ; + fates_landuse_logging_direct_frac:long_name = "Fraction of stems logged directly per event" ; + double fates_landuse_logging_event_code ; + fates_landuse_logging_event_code:units = "unitless" ; + fates_landuse_logging_event_code:long_name = "Integer code that options how logging events are structured" ; + double fates_landuse_logging_export_frac ; + fates_landuse_logging_export_frac:units = "fraction" ; + fates_landuse_logging_export_frac:long_name = "fraction of trunk product being shipped offsite, the leftovers will be left onsite as large CWD" ; + double fates_landuse_logging_mechanical_frac ; + fates_landuse_logging_mechanical_frac:units = "fraction" ; + fates_landuse_logging_mechanical_frac:long_name = "Fraction of stems killed due infrastructure an other mechanical means" ; + double fates_landuse_pprodharv10_forest_mean ; + fates_landuse_pprodharv10_forest_mean:units = "fraction" ; + fates_landuse_pprodharv10_forest_mean:long_name = "mean harvest mortality proportion of deadstem to 10-yr product (pprodharv10) of all woody PFT types" ; + double fates_leaf_photo_temp_acclim_timescale ; + fates_leaf_photo_temp_acclim_timescale:units = "days" ; + fates_leaf_photo_temp_acclim_timescale:long_name = "Length of the window for the exponential moving average (ema) of vegetation temperature used in photosynthesis temperature acclimation (NOT USED)" ; + double fates_leaf_photo_tempsens_model ; + fates_leaf_photo_tempsens_model:units = "unitless" ; + fates_leaf_photo_tempsens_model:long_name = "switch for choosing the model that defines the temperature sensitivity of photosynthetic parameters (vcmax, jmax). 1=non-acclimating (NOT USED)" ; + double fates_leaf_stomatal_assim_model ; + fates_leaf_stomatal_assim_model:units = "unitless" ; + fates_leaf_stomatal_assim_model:long_name = "a switch designating whether to use net (1) or gross (2) assimilation in the stomatal model" ; + double fates_leaf_stomatal_model ; + fates_leaf_stomatal_model:units = "unitless" ; + fates_leaf_stomatal_model:long_name = "switch for choosing between Ball-Berry (1) stomatal conductance model and Medlyn (2) model" ; + double fates_leaf_theta_cj_c3 ; + fates_leaf_theta_cj_c3:units = "unitless" ; + fates_leaf_theta_cj_c3:long_name = "Empirical curvature parameter for ac, aj photosynthesis co-limitation in c3 plants" ; + double fates_leaf_theta_cj_c4 ; + fates_leaf_theta_cj_c4:units = "unitless" ; + fates_leaf_theta_cj_c4:long_name = "Empirical curvature parameter for ac, aj photosynthesis co-limitation in c4 plants" ; + double fates_maintresp_model ; + fates_maintresp_model:units = "unitless" ; + fates_maintresp_model:long_name = "switch for choosing between maintenance respiration models. 1=Ryan (1991) (NOT USED)" ; + double fates_maxcohort ; + fates_maxcohort:units = "count" ; + fates_maxcohort:long_name = "maximum number of cohorts per patch. Actual number of cohorts also depend on cohort fusion tolerances" ; + double fates_maxpatch_primary ; + fates_maxpatch_primary:units = "count" ; + fates_maxpatch_primary:long_name = "maximum number of primary vegetation patches per site" ; + double fates_maxpatch_secondary ; + fates_maxpatch_secondary:units = "count" ; + fates_maxpatch_secondary:long_name = "maximum number of secondary vegetation patches per site" ; + double fates_mort_disturb_frac ; + fates_mort_disturb_frac:units = "fraction" ; + fates_mort_disturb_frac:long_name = "fraction of canopy mortality that results in disturbance (i.e. transfer of area from new to old patch)" ; + double fates_mort_understorey_death ; + fates_mort_understorey_death:units = "fraction" ; + fates_mort_understorey_death:long_name = "fraction of plants in understorey cohort impacted by overstorey tree-fall" ; + double fates_patch_fusion_tol ; + fates_patch_fusion_tol:units = "unitless" ; + fates_patch_fusion_tol:long_name = "minimum fraction in difference in profiles between patches" ; + double fates_phen_chilltemp ; + fates_phen_chilltemp:units = "degrees C" ; + fates_phen_chilltemp:long_name = "chilling day counting threshold for vegetation" ; + double fates_phen_coldtemp ; + fates_phen_coldtemp:units = "degrees C" ; + fates_phen_coldtemp:long_name = "vegetation temperature exceedance that flags a cold-day for leaf-drop" ; + double fates_phen_drought_model ; + fates_phen_drought_model:units = "unitless" ; + fates_phen_drought_model:long_name = "which method to use for drought phenology: 0 - FATES default; 1 - Semi-deciduous (ED2-like)" ; + double fates_phen_drought_threshold ; + fates_phen_drought_threshold:units = "m3/m3 or mm" ; + fates_phen_drought_threshold:long_name = "threshold for drought phenology (or lower threshold when fates_phen_drought_model = 1); the quantity depends on the sign: if positive, the threshold is volumetric soil moisture (m3/m3). If negative, the threshold is soil matric potentical (mm)" ; + double fates_phen_gddthresh_a ; + fates_phen_gddthresh_a:units = "none" ; + fates_phen_gddthresh_a:long_name = "GDD accumulation function, intercept parameter: gdd_thesh = a + b exp(c*ncd)" ; + double fates_phen_gddthresh_b ; + fates_phen_gddthresh_b:units = "none" ; + fates_phen_gddthresh_b:long_name = "GDD accumulation function, multiplier parameter: gdd_thesh = a + b exp(c*ncd)" ; + double fates_phen_gddthresh_c ; + fates_phen_gddthresh_c:units = "none" ; + fates_phen_gddthresh_c:long_name = "GDD accumulation function, exponent parameter: gdd_thesh = a + b exp(c*ncd)" ; + double fates_phen_mindaysoff ; + fates_phen_mindaysoff:units = "days" ; + fates_phen_mindaysoff:long_name = "day threshold compared against days since leaves became off-allometry" ; + double fates_phen_mindayson ; + fates_phen_mindayson:units = "days" ; + fates_phen_mindayson:long_name = "day threshold compared against days since leaves became on-allometry" ; + double fates_phen_moist_threshold ; + fates_phen_moist_threshold:units = "m3/m3 or mm" ; + fates_phen_moist_threshold:long_name = "upper threshold for drought phenology (only for fates_phen_drought_model=1); the quantity depends on the sign: if positive, the threshold is volumetric soil moisture (m3/m3). If negative, the threshold is soil matric potentical (mm)" ; + double fates_phen_ncolddayslim ; + fates_phen_ncolddayslim:units = "days" ; + fates_phen_ncolddayslim:long_name = "day threshold exceedance for temperature leaf-drop" ; + double fates_q10_froz ; + fates_q10_froz:units = "unitless" ; + fates_q10_froz:long_name = "Q10 for frozen-soil respiration rates" ; + double fates_q10_mr ; + fates_q10_mr:units = "unitless" ; + fates_q10_mr:long_name = "Q10 for maintenance respiration" ; + double fates_soil_salinity ; + fates_soil_salinity:units = "ppt" ; + fates_soil_salinity:long_name = "soil salinity used for model when not coupled to dynamic soil salinity" ; + double fates_vai_top_bin_width ; + fates_vai_top_bin_width:units = "m2/m2" ; + fates_vai_top_bin_width:long_name = "width in VAI units of uppermost leaf+stem layer scattering element in each canopy layer" ; + double fates_vai_width_increase_factor ; + fates_vai_width_increase_factor:units = "unitless" ; + fates_vai_width_increase_factor:long_name = "factor by which each leaf+stem scattering element increases in VAI width (1 = uniform spacing)" ; + +// global attributes: + :history = "This parameter file is maintained in version control\nSee https://github.com/NGEET/fates/blob/master/parameter_files/fates_params_default.cdl \nFor changes, use git blame \n" ; +data: + + fates_history_ageclass_bin_edges = 0, 1, 2, 5, 10, 20, 50 ; + + fates_history_coageclass_bin_edges = 0, 5 ; + + fates_history_height_bin_edges = 0, 0.1, 0.3, 1, 3, 10 ; + + fates_history_damage_bin_edges = 0, 80 ; + + fates_history_sizeclass_bin_edges = 0, 5, 10, 15, 20, 30, 40, 50, 60, 70, + 80, 90, 100 ; + + fates_alloc_organ_id = 1, 2, 3, 6 ; + + fates_hydro_htftype_node = 1, 1, 1, 1 ; + + fates_pftname = + "broadleaf_evergreen_tropical_tree ", + "needleleaf_evergreen_extratrop_tree ", + "needleleaf_colddecid_extratrop_tree ", + "broadleaf_evergreen_extratrop_tree ", + "broadleaf_hydrodecid_tropical_tree ", + "broadleaf_colddecid_extratrop_tree ", + "broadleaf_evergreen_extratrop_shrub ", + "broadleaf_hydrodecid_extratrop_shrub ", + "broadleaf_colddecid_extratrop_shrub ", + "arctic_c3_grass ", + "cool_c3_grass ", + "c4_grass " ; + + fates_hydro_organ_name = + "leaf ", + "stem ", + "transporting root ", + "absorbing root " ; + + fates_alloc_organ_name = + "leaf", + "fine root", + "sapwood", + "structure" ; + + fates_litterclass_name = + "twig ", + "small branch ", + "large branch ", + "trunk ", + "dead leaves ", + "live grass " ; + + fates_alloc_organ_priority = + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 ; + + fates_alloc_storage_cushion = 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, + 1.2, 1.2, 1.2 ; + + fates_alloc_store_priority_frac = 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, + 0.8, 0.8, 0.8, 0.8 ; + + fates_allom_agb1 = 0.06896, 0.06896, 0.06896, 0.06896, 0.06896, 0.06896, + 0.06896, 0.06896, 0.06896, 0.01, 0.01, 0.01 ; + + fates_allom_agb2 = 0.572, 0.572, 0.572, 0.572, 0.572, 0.572, 0.572, 0.572, + 0.572, 0.572, 0.572, 0.572 ; + + fates_allom_agb3 = 1.94, 1.94, 1.94, 1.94, 1.94, 1.94, 1.94, 1.94, 1.94, + 1.94, 1.94, 1.94 ; + + fates_allom_agb4 = 0.931, 0.931, 0.931, 0.931, 0.931, 0.931, 0.931, 0.931, + 0.931, 0.931, 0.931, 0.931 ; + + fates_allom_agb_frac = 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, + 0.6, 0.6 ; + + fates_allom_amode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_blca_expnt_diff = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_allom_cmode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_crown_depth_frac = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.95, 0.95, + 0.95, 1, 1, 1 ; + + fates_allom_d2bl1 = 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, + 0.07, 0.07, 0.07 ; + + fates_allom_d2bl2 = 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, + 1.3 ; + + fates_allom_d2bl3 = 0.55, 0.55, 0.55, 0.55, 0.55, 0.55, 0.55, 0.55, 0.55, + 0.55, 0.55, 0.55 ; + + fates_allom_d2ca_coefficient_max = 0.6568464, 0.6568464, 0.6568464, + 0.6568464, 0.6568464, 0.6568464, 0.6568464, 0.6568464, 0.6568464, + 0.6568464, 0.6568464, 0.6568464 ; + + fates_allom_d2ca_coefficient_min = 0.3381119, 0.3381119, 0.3381119, + 0.3381119, 0.3381119, 0.3381119, 0.3381119, 0.3381119, 0.3381119, + 0.3381119, 0.3381119, 0.3381119 ; + + fates_allom_d2h1 = 0.64, 0.64, 0.64, 0.64, 0.64, 0.64, 0.64, 0.64, 0.64, + 0.64, 0.64, 0.64 ; + + fates_allom_d2h2 = 0.37, 0.37, 0.37, 0.37, 0.37, 0.37, 0.37, 0.37, 0.37, + 0.37, 0.37, 0.37 ; + + fates_allom_d2h3 = -999.9, -999.9, -999.9, -999.9, -999.9, -999.9, -999.9, + -999.9, -999.9, -999.9, -999.9, -999.9 ; + + fates_allom_dbh_maxheight = 90, 90, 90, 90, 90, 90, 3, 3, 2, 0.35, 0.35, 0.35 ; + + fates_allom_fmode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_fnrt_prof_a = 7, 7, 7, 7, 6, 6, 7, 7, 7, 11, 11, 11 ; + + fates_allom_fnrt_prof_b = 1, 2, 2, 1, 2, 2, 1.5, 1.5, 1.5, 2, 2, 2 ; + + fates_allom_fnrt_prof_mode = 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 ; + + fates_allom_frbstor_repro = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_allom_hmode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_l2fr = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_la_per_sa_int = 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, + 0.8, 0.8, 0.8 ; + + fates_allom_la_per_sa_slp = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_allom_lmode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_sai_scaler = 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, + 0.1, 0.1 ; + + fates_allom_smode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_stmode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_zroot_k = 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10 ; + + fates_allom_zroot_max_dbh = 100, 100, 100, 100, 100, 100, 2, 2, 2, 2, 2, 2 ; + + fates_allom_zroot_max_z = 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, + 100, 100 ; + + fates_allom_zroot_min_dbh = 1, 1, 1, 2.5, 2.5, 2.5, 0.1, 0.1, 0.1, 0.1, 0.1, + 0.1 ; + + fates_allom_zroot_min_z = 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, + 100, 100 ; + + fates_c2b = 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ; + + fates_cnp_eca_alpha_ptase = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5 ; + + fates_cnp_eca_decompmicc = 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280 ; + + fates_cnp_eca_km_nh4 = 0.14, 0.14, 0.14, 0.14, 0.14, 0.14, 0.14, 0.14, 0.14, + 0.14, 0.14, 0.14 ; + + fates_cnp_eca_km_no3 = 0.27, 0.27, 0.27, 0.27, 0.27, 0.27, 0.27, 0.27, 0.27, + 0.27, 0.27, 0.27 ; + + fates_cnp_eca_km_p = 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, + 0.1 ; + + fates_cnp_eca_km_ptase = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_cnp_eca_lambda_ptase = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_cnp_eca_vmax_nh4 = 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, + 5e-09, 5e-09, 5e-09, 5e-09, 5e-09 ; + + fates_cnp_eca_vmax_no3 = 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, + 5e-09, 5e-09, 5e-09, 5e-09, 5e-09 ; + + fates_cnp_eca_vmax_ptase = 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, + 5e-09, 5e-09, 5e-09, 5e-09, 5e-09 ; + + fates_cnp_fnrt_adapt_tscale = 100, 100, 100, 100, 100, 100, 100, 100, 100, + 100, 100, 100 ; + + fates_cnp_nfix1 = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_cnp_nitr_store_ratio = 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, + 1.5, 1.5, 1.5 ; + + fates_cnp_phos_store_ratio = 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, + 1.5, 1.5, 1.5 ; + + fates_cnp_prescribed_nuptake = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_cnp_prescribed_puptake = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_cnp_rd_vmax_n = 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, + 5e-09, 5e-09, 5e-09, 5e-09, 5e-09 ; + + fates_cnp_store_ovrflw_frac = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_cnp_turnover_nitr_retrans = + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_cnp_turnover_phos_retrans = + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_cnp_vmax_p = 5e-10, 5e-10, 5e-10, 5e-10, 5e-10, 5e-10, 5e-10, 5e-10, + 5e-10, 5e-10, 5e-10, 5e-10 ; + + fates_damage_frac = 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, + 0.01, 0.01, 0.01 ; + + fates_damage_mort_p1 = 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 ; + + fates_damage_mort_p2 = 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, + 5.5, 5.5 ; + + fates_damage_recovery_scalar = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_dev_arbitrary_pft = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_fire_alpha_SH = 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, + 0.2 ; + + fates_fire_bark_scaler = 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, + 0.07, 0.07, 0.07, 0.07 ; + + fates_fire_crown_kill = 0.775, 0.775, 0.775, 0.775, 0.775, 0.775, 0.775, + 0.775, 0.775, 0.775, 0.775, 0.775 ; + + fates_frag_fnrt_fcel = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5 ; + + fates_frag_fnrt_flab = 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25 ; + + fates_frag_fnrt_flig = 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25 ; + + fates_frag_leaf_fcel = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5 ; + + fates_frag_leaf_flab = 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25 ; + + fates_frag_leaf_flig = 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25 ; + + fates_frag_seed_decay_rate = 0.51, 0.51, 0.51, 0.51, 0.51, 0.51, 0.51, 0.51, + 0.51, 0.51, 0.51, 0.51 ; + + fates_grperc = 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, + 0.11, 0.11 ; + + fates_hydro_avuln_gs = 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, + 2.5, 2.5 ; + + fates_hydro_avuln_node = + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ; + + fates_hydro_epsil_node = + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 ; + + fates_hydro_fcap_node = + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, + 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_hydro_k_lwp = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_hydro_kmax_node = + -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999 ; + + fates_hydro_p50_gs = -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, + -1.5, -1.5, -1.5 ; + + fates_hydro_p50_node = + -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, + -2.25, -2.25, + -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, + -2.25, -2.25, + -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, + -2.25, -2.25, + -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, + -2.25, -2.25 ; + + fates_hydro_p_taper = 0.333, 0.333, 0.333, 0.333, 0.333, 0.333, 0.333, + 0.333, 0.333, 0.333, 0.333, 0.333 ; + + fates_hydro_pinot_node = + -1.465984, -1.465984, -1.465984, -1.465984, -1.465984, -1.465984, + -1.465984, -1.465984, -1.465984, -1.465984, -1.465984, -1.465984, + -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, + -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, + -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, + -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, + -1.043478, -1.043478, -1.043478, -1.043478, -1.043478, -1.043478, + -1.043478, -1.043478, -1.043478, -1.043478, -1.043478, -1.043478 ; + + fates_hydro_pitlp_node = + -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, + -1.67, -1.67, + -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, + -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, + -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2 ; + + fates_hydro_resid_node = + 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, + 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, + 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, + 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11 ; + + fates_hydro_rfrac_stem = 0.625, 0.625, 0.625, 0.625, 0.625, 0.625, 0.625, + 0.625, 0.625, 0.625, 0.625, 0.625 ; + + fates_hydro_rs2 = 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, + 0.0001, 0.0001, 0.0001, 0.0001, 0.0001 ; + + fates_hydro_srl = 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25 ; + + fates_hydro_thetas_node = + 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, + 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, + 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, + 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75 ; + + fates_hydro_vg_alpha_node = + 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.005, 0.005, 0.005, 0.005, 0.005, + 0.005, 0.005, + 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.005, 0.005, 0.005, 0.005, 0.005, + 0.005, 0.005, + 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.005, 0.005, 0.005, 0.005, 0.005, + 0.005, 0.005, + 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.005, 0.005, 0.005, 0.005, 0.005, + 0.005, 0.005 ; + + fates_hydro_vg_m_node = + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5 ; + + fates_hydro_vg_n_node = + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ; + + fates_leaf_c3psn = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 ; + + fates_leaf_jmaxha = 43540, 43540, 43540, 43540, 43540, 43540, 43540, 43540, + 43540, 43540, 43540, 43540 ; + + fates_leaf_jmaxhd = 152040, 152040, 152040, 152040, 152040, 152040, 152040, + 152040, 152040, 152040, 152040, 152040 ; + + fates_leaf_jmaxse = 495, 495, 495, 495, 495, 495, 495, 495, 495, 495, 495, + 495 ; + + fates_leaf_slamax = 0.0954, 0.0954, 0.0954, 0.0954, 0.0954, 0.0954, 0.012, + 0.03, 0.03, 0.03, 0.03, 0.03 ; + + fates_leaf_slatop = 0.012, 0.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, + 10000, 10000, 10000, 10000, 10000, 40000 ; + + fates_leaf_stomatal_slope_ballberry = 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 ; + + fates_leaf_stomatal_slope_medlyn = 4.1, 2.3, 2.3, 4.1, 4.4, 4.4, 4.7, 4.7, + 4.7, 2.2, 5.3, 1.6 ; + + fates_leaf_vcmax25top = + 50, 65, 39, 62, 41, 58, 62, 54, 54, 78, 78, 78 ; + + fates_leaf_vcmaxha = 65330, 65330, 65330, 65330, 65330, 65330, 65330, 65330, + 65330, 65330, 65330, 65330 ; + + fates_leaf_vcmaxhd = 149250, 149250, 149250, 149250, 149250, 149250, 149250, + 149250, 149250, 149250, 149250, 149250 ; + + fates_leaf_vcmaxse = 485, 485, 485, 485, 485, 485, 485, 485, 485, 485, 485, + 485 ; + + fates_maintresp_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, + 0.014, 0.014, 0.014, 0.014 ; + + 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, + 0.5, 0.5, 0.5 ; + + fates_mort_hf_sm_threshold = 1e-06, 1e-06, 1e-06, 1e-06, 1e-06, 1e-06, + 1e-06, 1e-06, 1e-06, 1e-06, 1e-06, 1e-06 ; + + fates_mort_ip_age_senescence = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_mort_ip_size_senescence = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_mort_prescribed_canopy = 0.0194, 0.0194, 0.0194, 0.0194, 0.0194, + 0.0194, 0.0194, 0.0194, 0.0194, 0.0194, 0.0194, 0.0194 ; + + fates_mort_prescribed_understory = 0.025, 0.025, 0.025, 0.025, 0.025, 0.025, + 0.025, 0.025, 0.025, 0.025, 0.025, 0.025 ; + + fates_mort_r_age_senescence = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_mort_r_size_senescence = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_mort_scalar_coldstress = 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 ; + + fates_mort_scalar_cstarvation = 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, + 0.6, 0.6, 0.6 ; + + fates_mort_scalar_hydrfailure = 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, + 0.6, 0.6, 0.6 ; + + fates_nonhydro_smpsc = -255000, -255000, -255000, -255000, -255000, -255000, + -255000, -255000, -255000, -255000, -255000, -255000 ; + + fates_nonhydro_smpso = -66000, -66000, -66000, -66000, -66000, -66000, + -66000, -66000, -66000, -66000, -66000, -66000 ; + + fates_phen_cold_size_threshold = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_phen_evergreen = 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 ; + + fates_phen_flush_fraction = _, _, 0.5, _, 0.5, 0.5, _, 0.5, 0.5, 0.5, 0.5, + 0.5 ; + + fates_phen_fnrt_drop_frac = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_phen_season_decid = 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0 ; + + fates_phen_stem_drop_fraction = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_phen_stress_decid = 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1 ; + + fates_prescribed_npp_canopy = 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, + 0.4, 0.4, 0.4 ; + + fates_prescribed_npp_understory = 0.03125, 0.03125, 0.03125, 0.03125, + 0.03125, 0.03125, 0.03125, 0.03125, 0.03125, 0.03125, 0.03125, 0.03125 ; + + fates_rad_leaf_clumping_index = 0.85, 0.85, 0.8, 0.85, 0.85, 0.9, 0.85, 0.9, + 0.9, 0.75, 0.75, 0.75 ; + + fates_rad_leaf_rhonir = 0.46, 0.41, 0.39, 0.46, 0.41, 0.41, 0.46, 0.41, + 0.41, 0.28, 0.28, 0.28 ; + + fates_rad_leaf_rhovis = 0.11, 0.09, 0.08, 0.11, 0.08, 0.08, 0.11, 0.08, + 0.08, 0.05, 0.05, 0.05 ; + + fates_rad_leaf_taunir = 0.33, 0.32, 0.42, 0.33, 0.43, 0.43, 0.33, 0.43, + 0.43, 0.4, 0.4, 0.4 ; + + fates_rad_leaf_tauvis = 0.06, 0.04, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, + 0.06, 0.05, 0.05, 0.05 ; + + fates_rad_leaf_xl = 0.32, 0.01, 0.01, 0.32, 0.2, 0.59, 0.32, 0.59, 0.59, + -0.23, -0.23, -0.23 ; + + fates_rad_stem_rhonir = 0.49, 0.36, 0.36, 0.49, 0.49, 0.49, 0.49, 0.49, + 0.49, 0.53, 0.53, 0.53 ; + + fates_rad_stem_rhovis = 0.21, 0.12, 0.12, 0.21, 0.21, 0.21, 0.21, 0.21, + 0.21, 0.31, 0.31, 0.31 ; + + fates_rad_stem_taunir = 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, + 0.001, 0.001, 0.25, 0.25, 0.25 ; + + fates_rad_stem_tauvis = 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, + 0.001, 0.001, 0.12, 0.12, 0.12 ; + + fates_recruit_height_min = 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 0.75, 0.75, 0.75, + 0.125, 0.125, 0.125 ; + + fates_recruit_init_density = 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, + 0.2, 0.2, 0.2 ; + + fates_recruit_prescribed_rate = 0.02, 0.02, 0.02, 0.02, 0.02, 0.02, 0.02, + 0.02, 0.02, 0.02, 0.02, 0.02 ; + + fates_recruit_seed_alloc = 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, + 0.1, 0.1 ; + + fates_recruit_seed_alloc_mature = 0, 0, 0, 0, 0, 0, 0.9, 0.9, 0.9, 0.9, 0.9, + 0.9 ; + + fates_recruit_seed_dbh_repro_threshold = 150, 90, 90, 90, 90, 90, 3, 3, 2, + 1.47, 1.47, 1.47 ; + + fates_recruit_seed_germination_rate = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5 ; + + fates_recruit_seed_supplement = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_stoich_nitr = + 0.033, 0.029, 0.04, 0.033, 0.04, 0.04, 0.033, 0.04, 0.04, 0.04, 0.04, 0.04, + 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, + 0.024, 0.024, + 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, + 1e-08, 1e-08, + 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, + 0.0047, 0.0047, 0.0047 ; + + fates_stoich_phos = + 0.0033, 0.0029, 0.004, 0.0033, 0.004, 0.004, 0.0033, 0.004, 0.004, 0.004, + 0.004, 0.004, + 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, + 0.0024, 0.0024, 0.0024, + 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, + 1e-09, 1e-09, + 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, + 0.00047, 0.00047, 0.00047, 0.00047 ; + + fates_trim_inc = 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, + 0.03, 0.03 ; + + fates_trim_limit = 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3 ; + + fates_turb_displar = 0.67, 0.67, 0.67, 0.67, 0.67, 0.67, 0.67, 0.67, 0.67, + 0.67, 0.67, 0.67 ; + + fates_turb_leaf_diameter = 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, + 0.04, 0.04, 0.04, 0.04 ; + + fates_turb_z0mr = 0.055, 0.055, 0.055, 0.055, 0.055, 0.055, 0.055, 0.055, + 0.055, 0.055, 0.055, 0.055 ; + + fates_turnover_branch = 150, 150, 150, 150, 150, 150, 150, 150, 150, 0, 0, 0 ; + + fates_turnover_fnrt = 1, 2, 1, 1.5, 1, 1, 1.5, 1, 1, 1, 1, 1 ; + + fates_turnover_leaf = + 1.5, 4, 1, 1.5, 1, 1, 1.5, 1, 1, 1, 1, 1 ; + + fates_turnover_senleaf_fdrought = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_wood_density = 0.7, 0.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_hlm_pft_map = + 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 ; + + fates_fire_FBD = 15.4, 16.8, 19.6, 999, 4, 4 ; + + fates_fire_low_moisture_Coeff = 1.12, 1.09, 0.98, 0.8, 1.15, 1.15 ; + + fates_fire_low_moisture_Slope = 0.62, 0.72, 0.85, 0.8, 0.62, 0.62 ; + + fates_fire_mid_moisture = 0.72, 0.51, 0.38, 1, 0.8, 0.8 ; + + fates_fire_mid_moisture_Coeff = 2.35, 1.47, 1.06, 0.8, 3.2, 3.2 ; + + fates_fire_mid_moisture_Slope = 2.35, 1.47, 1.06, 0.8, 3.2, 3.2 ; + + fates_fire_min_moisture = 0.18, 0.12, 0, 0, 0.24, 0.24 ; + + fates_fire_SAV = 13, 3.58, 0.98, 0.2, 66, 66 ; + + fates_frag_maxdecomp = 0.52, 0.383, 0.383, 0.19, 1, 999 ; + + fates_frag_cwd_frac = 0.045, 0.075, 0.21, 0.67 ; + + fates_base_mr_20 = 2.52e-06 ; + + fates_canopy_closure_thresh = 0.8 ; + + fates_cnp_eca_plant_escalar = 1.25e-05 ; + + fates_cohort_age_fusion_tol = 0.08 ; + + fates_cohort_size_fusion_tol = 0.08 ; + + fates_comp_excln = 3 ; + + fates_damage_canopy_layer_code = 1 ; + + fates_damage_event_code = 1 ; + + fates_dev_arbitrary = _ ; + + fates_fire_active_crown_fire = 0 ; + + fates_fire_cg_strikes = 0.2 ; + + fates_fire_drying_ratio = 66000 ; + + fates_fire_durat_slope = -11.06 ; + + fates_fire_fdi_a = 17.62 ; + + fates_fire_fdi_alpha = 0.00037 ; + + fates_fire_fdi_b = 243.12 ; + + fates_fire_fuel_energy = 18000 ; + + fates_fire_max_durat = 240 ; + + fates_fire_miner_damp = 0.41739 ; + + fates_fire_miner_total = 0.055 ; + + fates_fire_nignitions = 15 ; + + fates_fire_part_dens = 513 ; + + fates_fire_threshold = 50 ; + + fates_frag_cwd_fcel = 0.76 ; + + fates_frag_cwd_flig = 0.24 ; + + fates_hydro_kmax_rsurf1 = 20 ; + + fates_hydro_kmax_rsurf2 = 0.0001 ; + + fates_hydro_psi0 = 0 ; + + fates_hydro_psicap = -0.6 ; + + fates_hydro_solver = 1 ; + + fates_landuse_logging_coll_under_frac = 0.55983 ; + + fates_landuse_logging_collateral_frac = 0.05 ; + + fates_landuse_logging_dbhmax = _ ; + + fates_landuse_logging_dbhmax_infra = 35 ; + + fates_landuse_logging_dbhmin = 50 ; + + fates_landuse_logging_direct_frac = 0.15 ; + + fates_landuse_logging_event_code = -30 ; + + fates_landuse_logging_export_frac = 0.8 ; + + fates_landuse_logging_mechanical_frac = 0.05 ; + + fates_landuse_pprodharv10_forest_mean = 0.8125 ; + + fates_leaf_photo_temp_acclim_timescale = 30 ; + + fates_leaf_photo_tempsens_model = 1 ; + + fates_leaf_stomatal_assim_model = 1 ; + + fates_leaf_stomatal_model = 1 ; + + fates_leaf_theta_cj_c3 = 0.999 ; + + fates_leaf_theta_cj_c4 = 0.999 ; + + fates_maintresp_model = 1 ; + + fates_maxcohort = 100 ; + + fates_maxpatch_primary = 10 ; + + fates_maxpatch_secondary = 4 ; + + fates_mort_disturb_frac = 1 ; + + fates_mort_understorey_death = 0.55983 ; + + fates_patch_fusion_tol = 0.05 ; + + fates_phen_chilltemp = 5 ; + + fates_phen_coldtemp = 7.5 ; + + fates_phen_drought_model = 0 ; + + fates_phen_drought_threshold = 0.15 ; + + fates_phen_gddthresh_a = -68 ; + + fates_phen_gddthresh_b = 638 ; + + fates_phen_gddthresh_c = -0.01 ; + + fates_phen_mindaysoff = 100 ; + + fates_phen_mindayson = 90 ; + + fates_phen_moist_threshold = 0.18 ; + + fates_phen_ncolddayslim = 5 ; + + fates_q10_froz = 1.5 ; + + fates_q10_mr = 1.5 ; + + fates_soil_salinity = 0.4 ; + + fates_vai_top_bin_width = 1 ; + + fates_vai_width_increase_factor = 1 ; +} diff --git a/parameter_files/archive/api24.1.0_101722_patch_params.xml b/parameter_files/archive/api24.1.0_101722_patch_params.xml new file mode 100644 index 0000000000..c985072be0 --- /dev/null +++ b/parameter_files/archive/api24.1.0_101722_patch_params.xml @@ -0,0 +1,51 @@ + + + These parameter modifications are only applicable to the fates parameter file fates/parameter_files/fates_params_default.cdl, and only for the following API's: 24.0, 24.1. These calibrations were assembled by Jennifer Holm (jaholm@lbl.gov). These are available for public use, however please coordinate with Jennifer if these parameters are used in publication. Provenance: leaf parameters were derived from TRY (Kattge et al. 2020), wood density derived from the global wood density database (Chave et al.2009, Zanne et al. 2009) height parameters are manual calibrations and personal observation. The cold mortality threshold change is simply a correction to a previous omission. The reduction in the dbh threshold for extra seed allocation is based on a logical argument, that plants will start directing resources towards reproductive allocation at or before they hit their maximum height. Plants that were set higher than dbh at maximum height were reduced to max dbh at maximum height. + archive/api24.1.0_101722_fates_params_default.cdl + fates_params_default.cdl + 1,2,3,4,5,6,7,8,9,10,11,12 + + + + + + + + + + + + + + + + + + + + + + + + 0.005, 0.009 + 62, 61 + 0.4, 0.53 + + + 80, 80, 80, 80 + 80, 80, 80, 80 + + + + 0.2, 0.2, 0.2 + + + -80 + + + 90, 0.35, 0.35, 0.35 + + + + + diff --git a/parameter_files/archive/api24.2.0_112822_fates_params_default.cdl b/parameter_files/archive/api24.2.0_112822_fates_params_default.cdl new file mode 100644 index 0000000000..0c89520e40 --- /dev/null +++ b/parameter_files/archive/api24.2.0_112822_fates_params_default.cdl @@ -0,0 +1,1537 @@ +netcdf fates_params_default { +dimensions: + fates_NCWD = 4 ; + fates_history_age_bins = 7 ; + fates_history_coage_bins = 2 ; + fates_history_damage_bins = 2 ; + fates_history_height_bins = 6 ; + fates_history_size_bins = 13 ; + fates_hlm_pftno = 14 ; + fates_hydr_organs = 4 ; + fates_leafage_class = 1 ; + fates_litterclass = 6 ; + fates_pft = 12 ; + fates_plant_organs = 4 ; + fates_string_length = 60 ; +variables: + double fates_history_ageclass_bin_edges(fates_history_age_bins) ; + fates_history_ageclass_bin_edges:units = "yr" ; + fates_history_ageclass_bin_edges:long_name = "Lower edges for age class bins used in age-resolved patch history output" ; + double fates_history_coageclass_bin_edges(fates_history_coage_bins) ; + fates_history_coageclass_bin_edges:units = "years" ; + fates_history_coageclass_bin_edges:long_name = "Lower edges for cohort age class bins used in cohort age resolved history output" ; + double fates_history_height_bin_edges(fates_history_height_bins) ; + fates_history_height_bin_edges:units = "m" ; + fates_history_height_bin_edges:long_name = "Lower edges for height bins used in height-resolved history output" ; + double fates_history_damage_bin_edges(fates_history_damage_bins) ; + fates_history_damage_bin_edges:units = "% crown loss" ; + fates_history_damage_bin_edges:long_name = "Lower edges for damage class bins used in cohort history output" ; + double fates_history_sizeclass_bin_edges(fates_history_size_bins) ; + fates_history_sizeclass_bin_edges:units = "cm" ; + fates_history_sizeclass_bin_edges:long_name = "Lower edges for DBH size class bins used in size-resolved cohort history output" ; + double fates_alloc_organ_id(fates_plant_organs) ; + fates_alloc_organ_id:units = "unitless" ; + fates_alloc_organ_id:long_name = "This is the global index that the organ in this file is associated with, values match those in parteh/PRTGenericMod.F90" ; + double fates_hydro_htftype_node(fates_hydr_organs) ; + fates_hydro_htftype_node:units = "unitless" ; + fates_hydro_htftype_node:long_name = "Switch that defines the hydraulic transfer functions for each organ." ; + char fates_pftname(fates_pft, fates_string_length) ; + fates_pftname:units = "unitless - string" ; + fates_pftname:long_name = "Description of plant type" ; + char fates_hydro_organ_name(fates_hydr_organs, fates_string_length) ; + fates_hydro_organ_name:units = "unitless - string" ; + fates_hydro_organ_name:long_name = "Name of plant hydraulics organs (DONT CHANGE, order matches media list in FatesHydraulicsMemMod.F90)" ; + char fates_alloc_organ_name(fates_plant_organs, fates_string_length) ; + fates_alloc_organ_name:units = "unitless - string" ; + fates_alloc_organ_name:long_name = "Name of plant organs (with alloc_organ_id, must match PRTGenericMod.F90)" ; + char fates_litterclass_name(fates_litterclass, fates_string_length) ; + fates_litterclass_name:units = "unitless - string" ; + fates_litterclass_name:long_name = "Name of the litter classes, for variables associated with dimension fates_litterclass" ; + double fates_alloc_organ_priority(fates_plant_organs, fates_pft) ; + fates_alloc_organ_priority:units = "index" ; + fates_alloc_organ_priority:long_name = "Priority level for allocation, 1: replaces turnover from storage, 2: same priority as storage use/replacement, 3: ascending in order of least importance" ; + double fates_alloc_storage_cushion(fates_pft) ; + fates_alloc_storage_cushion:units = "fraction" ; + fates_alloc_storage_cushion:long_name = "maximum size of storage C pool, relative to maximum size of leaf C pool" ; + double fates_alloc_store_priority_frac(fates_pft) ; + fates_alloc_store_priority_frac:units = "unitless" ; + fates_alloc_store_priority_frac:long_name = "for high-priority organs, the fraction of their turnover demand that is gauranteed to be replaced, and if need-be by storage" ; + double fates_allom_agb1(fates_pft) ; + fates_allom_agb1:units = "variable" ; + fates_allom_agb1:long_name = "Parameter 1 for agb allometry" ; + double fates_allom_agb2(fates_pft) ; + fates_allom_agb2:units = "variable" ; + fates_allom_agb2:long_name = "Parameter 2 for agb allometry" ; + double fates_allom_agb3(fates_pft) ; + fates_allom_agb3:units = "variable" ; + fates_allom_agb3:long_name = "Parameter 3 for agb allometry" ; + double fates_allom_agb4(fates_pft) ; + fates_allom_agb4:units = "variable" ; + fates_allom_agb4:long_name = "Parameter 4 for agb allometry" ; + double fates_allom_agb_frac(fates_pft) ; + fates_allom_agb_frac:units = "fraction" ; + fates_allom_agb_frac:long_name = "Fraction of woody biomass that is above ground" ; + double fates_allom_amode(fates_pft) ; + fates_allom_amode:units = "index" ; + fates_allom_amode:long_name = "AGB allometry function index." ; + double fates_allom_blca_expnt_diff(fates_pft) ; + fates_allom_blca_expnt_diff:units = "unitless" ; + fates_allom_blca_expnt_diff:long_name = "difference between allometric DBH:bleaf and DBH:crown area exponents" ; + double fates_allom_cmode(fates_pft) ; + fates_allom_cmode:units = "index" ; + fates_allom_cmode:long_name = "coarse root biomass allometry function index." ; + double fates_allom_crown_depth_frac(fates_pft) ; + fates_allom_crown_depth_frac:units = "fraction" ; + fates_allom_crown_depth_frac:long_name = "the depth of a cohort crown as a fraction of its height" ; + double fates_allom_d2bl1(fates_pft) ; + fates_allom_d2bl1:units = "variable" ; + fates_allom_d2bl1:long_name = "Parameter 1 for d2bl allometry" ; + double fates_allom_d2bl2(fates_pft) ; + fates_allom_d2bl2:units = "variable" ; + fates_allom_d2bl2:long_name = "Parameter 2 for d2bl allometry" ; + double fates_allom_d2bl3(fates_pft) ; + fates_allom_d2bl3:units = "unitless" ; + fates_allom_d2bl3:long_name = "Parameter 3 for d2bl allometry" ; + double fates_allom_d2ca_coefficient_max(fates_pft) ; + fates_allom_d2ca_coefficient_max:units = "m2 cm^(-1/beta)" ; + fates_allom_d2ca_coefficient_max:long_name = "max (savanna) dbh to area multiplier factor where: area = n*d2ca_coeff*dbh^beta" ; + double fates_allom_d2ca_coefficient_min(fates_pft) ; + fates_allom_d2ca_coefficient_min:units = "m2 cm^(-1/beta)" ; + fates_allom_d2ca_coefficient_min:long_name = "min (forest) dbh to area multiplier factor where: area = n*d2ca_coeff*dbh^beta" ; + double fates_allom_d2h1(fates_pft) ; + fates_allom_d2h1:units = "variable" ; + fates_allom_d2h1:long_name = "Parameter 1 for d2h allometry (intercept, or c)" ; + double fates_allom_d2h2(fates_pft) ; + fates_allom_d2h2:units = "variable" ; + fates_allom_d2h2:long_name = "Parameter 2 for d2h allometry (slope, or m)" ; + double fates_allom_d2h3(fates_pft) ; + fates_allom_d2h3:units = "variable" ; + fates_allom_d2h3:long_name = "Parameter 3 for d2h allometry (optional)" ; + double fates_allom_dbh_maxheight(fates_pft) ; + fates_allom_dbh_maxheight:units = "cm" ; + fates_allom_dbh_maxheight:long_name = "the diameter (if any) corresponding to maximum height, diameters may increase beyond this" ; + double fates_allom_fmode(fates_pft) ; + fates_allom_fmode:units = "index" ; + fates_allom_fmode:long_name = "fine root biomass allometry function index." ; + double fates_allom_fnrt_prof_a(fates_pft) ; + fates_allom_fnrt_prof_a:units = "unitless" ; + fates_allom_fnrt_prof_a:long_name = "Fine root profile function, parameter a" ; + double fates_allom_fnrt_prof_b(fates_pft) ; + fates_allom_fnrt_prof_b:units = "unitless" ; + fates_allom_fnrt_prof_b:long_name = "Fine root profile function, parameter b" ; + double fates_allom_fnrt_prof_mode(fates_pft) ; + fates_allom_fnrt_prof_mode:units = "index" ; + fates_allom_fnrt_prof_mode:long_name = "Index to select fine root profile function: 1) Jackson Beta, 2) 1-param exponential 3) 2-param exponential" ; + double fates_allom_frbstor_repro(fates_pft) ; + fates_allom_frbstor_repro:units = "fraction" ; + fates_allom_frbstor_repro:long_name = "fraction of bstore goes to reproduction after plant dies" ; + double fates_allom_hmode(fates_pft) ; + fates_allom_hmode:units = "index" ; + fates_allom_hmode:long_name = "height allometry function index." ; + double fates_allom_l2fr(fates_pft) ; + fates_allom_l2fr:units = "gC/gC" ; + fates_allom_l2fr:long_name = "Allocation parameter: fine root C per leaf C" ; + double fates_allom_la_per_sa_int(fates_pft) ; + fates_allom_la_per_sa_int:units = "m2/cm2" ; + fates_allom_la_per_sa_int:long_name = "Leaf area per sapwood area, intercept" ; + double fates_allom_la_per_sa_slp(fates_pft) ; + fates_allom_la_per_sa_slp:units = "m2/cm2/m" ; + fates_allom_la_per_sa_slp:long_name = "Leaf area per sapwood area rate of change with height, slope (optional)" ; + double fates_allom_lmode(fates_pft) ; + fates_allom_lmode:units = "index" ; + fates_allom_lmode:long_name = "leaf biomass allometry function index." ; + double fates_allom_sai_scaler(fates_pft) ; + fates_allom_sai_scaler:units = "m2/m2" ; + fates_allom_sai_scaler:long_name = "allometric ratio of SAI per LAI" ; + double fates_allom_smode(fates_pft) ; + fates_allom_smode:units = "index" ; + fates_allom_smode:long_name = "sapwood allometry function index." ; + double fates_allom_stmode(fates_pft) ; + fates_allom_stmode:units = "index" ; + fates_allom_stmode:long_name = "storage allometry function index." ; + double fates_allom_zroot_k(fates_pft) ; + fates_allom_zroot_k:units = "unitless" ; + fates_allom_zroot_k:long_name = "scale coefficient of logistic rooting depth model" ; + double fates_allom_zroot_max_dbh(fates_pft) ; + fates_allom_zroot_max_dbh:units = "cm" ; + fates_allom_zroot_max_dbh:long_name = "dbh at which a plant reaches the maximum value for its maximum rooting depth" ; + double fates_allom_zroot_max_z(fates_pft) ; + fates_allom_zroot_max_z:units = "m" ; + fates_allom_zroot_max_z:long_name = "the maximum rooting depth defined at dbh = fates_allom_zroot_max_dbh. note: max_z=min_z=large, sets rooting depth to soil depth" ; + double fates_allom_zroot_min_dbh(fates_pft) ; + fates_allom_zroot_min_dbh:units = "cm" ; + fates_allom_zroot_min_dbh:long_name = "dbh at which the maximum rooting depth for a recruit is defined" ; + double fates_allom_zroot_min_z(fates_pft) ; + fates_allom_zroot_min_z:units = "m" ; + fates_allom_zroot_min_z:long_name = "the maximum rooting depth defined at dbh = fates_allom_zroot_min_dbh. note: max_z=min_z=large, sets rooting depth to soil depth" ; + double fates_c2b(fates_pft) ; + fates_c2b:units = "ratio" ; + fates_c2b:long_name = "Carbon to biomass multiplier of bulk structural tissues" ; + double fates_cnp_eca_alpha_ptase(fates_pft) ; + fates_cnp_eca_alpha_ptase:units = "g/m3" ; + fates_cnp_eca_alpha_ptase:long_name = "fraction of P from ptase activity sent directly to plant (ECA)" ; + double fates_cnp_eca_decompmicc(fates_pft) ; + fates_cnp_eca_decompmicc:units = "gC/m3" ; + fates_cnp_eca_decompmicc:long_name = "maximum soil microbial decomposer biomass found over depth (will be applied at a reference depth w/ exponential attenuation) (ECA)" ; + double fates_cnp_eca_km_nh4(fates_pft) ; + fates_cnp_eca_km_nh4:units = "gN/m3" ; + fates_cnp_eca_km_nh4:long_name = "half-saturation constant for plant nh4 uptake (ECA)" ; + double fates_cnp_eca_km_no3(fates_pft) ; + fates_cnp_eca_km_no3:units = "gN/m3" ; + fates_cnp_eca_km_no3:long_name = "half-saturation constant for plant no3 uptake (ECA)" ; + double fates_cnp_eca_km_p(fates_pft) ; + fates_cnp_eca_km_p:units = "gP/m3" ; + fates_cnp_eca_km_p:long_name = "half-saturation constant for plant p uptake (ECA)" ; + double fates_cnp_eca_km_ptase(fates_pft) ; + fates_cnp_eca_km_ptase:units = "gP/m3" ; + fates_cnp_eca_km_ptase:long_name = "half-saturation constant for biochemical P (ECA)" ; + double fates_cnp_eca_lambda_ptase(fates_pft) ; + fates_cnp_eca_lambda_ptase:units = "g/m3" ; + fates_cnp_eca_lambda_ptase:long_name = "critical value for biochemical production (ECA)" ; + double fates_cnp_eca_vmax_nh4(fates_pft) ; + fates_cnp_eca_vmax_nh4:units = "gN/gC/s" ; + fates_cnp_eca_vmax_nh4:long_name = "maximum production rate for plant nh4 uptake (ECA)" ; + double fates_cnp_eca_vmax_no3(fates_pft) ; + fates_cnp_eca_vmax_no3:units = "gN/gC/s" ; + fates_cnp_eca_vmax_no3:long_name = "maximum production rate for plant no3 uptake (ECA)" ; + double fates_cnp_eca_vmax_ptase(fates_pft) ; + fates_cnp_eca_vmax_ptase:units = "gP/m2/s" ; + fates_cnp_eca_vmax_ptase:long_name = "maximum production rate for biochemical P (per m2) (ECA)" ; + double fates_cnp_fnrt_adapt_tscale(fates_pft) ; + fates_cnp_fnrt_adapt_tscale:units = "days" ; + fates_cnp_fnrt_adapt_tscale:long_name = "Number of days that is shortest possible doubling period for fine-root adaptation to C/N/P balance" ; + double fates_cnp_nfix1(fates_pft) ; + fates_cnp_nfix1:units = "NA" ; + fates_cnp_nfix1:long_name = "place-holder for future n-fixation parameter (NOT IMPLEMENTED)" ; + double fates_cnp_nitr_store_ratio(fates_pft) ; + fates_cnp_nitr_store_ratio:units = "(gN/gN)" ; + fates_cnp_nitr_store_ratio:long_name = "storeable (labile) N, as a ratio compared to the N bound in cell structures of other organs (see code)" ; + double fates_cnp_phos_store_ratio(fates_pft) ; + fates_cnp_phos_store_ratio:units = "(gP/gP)" ; + fates_cnp_phos_store_ratio:long_name = "storeable (labile) P, as a ratio compared to the P bound in cell structures of other organs (see code)" ; + double fates_cnp_prescribed_nuptake(fates_pft) ; + fates_cnp_prescribed_nuptake:units = "fraction" ; + fates_cnp_prescribed_nuptake:long_name = "Prescribed N uptake flux. 0=fully coupled simulation >0=prescribed (experimental)" ; + double fates_cnp_prescribed_puptake(fates_pft) ; + fates_cnp_prescribed_puptake:units = "fraction" ; + fates_cnp_prescribed_puptake:long_name = "Prescribed P uptake flux. 0=fully coupled simulation, >0=prescribed (experimental)" ; + double fates_cnp_rd_vmax_n(fates_pft) ; + fates_cnp_rd_vmax_n:units = "gN/gC/s" ; + fates_cnp_rd_vmax_n:long_name = "maximum production rate for compbined (NH4+NO3) uptake (RD)" ; + double fates_cnp_store_ovrflw_frac(fates_pft) ; + fates_cnp_store_ovrflw_frac:units = "fraction" ; + fates_cnp_store_ovrflw_frac:long_name = "size of overflow storage (for excess C,N or P) as a fraction of storage target" ; + double fates_cnp_turnover_nitr_retrans(fates_plant_organs, fates_pft) ; + fates_cnp_turnover_nitr_retrans:units = "fraction" ; + fates_cnp_turnover_nitr_retrans:long_name = "retranslocation (reabsorbtion) fraction of nitrogen in turnover of scenescing tissues" ; + double fates_cnp_turnover_phos_retrans(fates_plant_organs, fates_pft) ; + fates_cnp_turnover_phos_retrans:units = "fraction" ; + fates_cnp_turnover_phos_retrans:long_name = "retranslocation (reabsorbtion) fraction of phosphorus in turnover of scenescing tissues" ; + double fates_cnp_vmax_p(fates_pft) ; + fates_cnp_vmax_p:units = "gP/gC/s" ; + fates_cnp_vmax_p:long_name = "maximum production rate for phosphorus (ECA and RD)" ; + double fates_damage_frac(fates_pft) ; + fates_damage_frac:units = "fraction" ; + fates_damage_frac:long_name = "fraction of cohort damaged in each damage event (event frequency specified in the is_it_damage_time subroutine)" ; + double fates_damage_mort_p1(fates_pft) ; + fates_damage_mort_p1:units = "fraction" ; + fates_damage_mort_p1:long_name = "inflection point of damage mortality function, a value of 0.8 means 50% mortality with 80% loss of crown, turn off with a large number" ; + double fates_damage_mort_p2(fates_pft) ; + fates_damage_mort_p2:units = "unitless" ; + fates_damage_mort_p2:long_name = "rate of mortality increase with damage" ; + double fates_damage_recovery_scalar(fates_pft) ; + fates_damage_recovery_scalar:units = "unitless" ; + fates_damage_recovery_scalar:long_name = "fraction of the cohort that recovers from damage" ; + double fates_dev_arbitrary_pft(fates_pft) ; + fates_dev_arbitrary_pft:units = "unknown" ; + fates_dev_arbitrary_pft:long_name = "Unassociated pft dimensioned free parameter that developers can use for testing arbitrary new hypotheses" ; + double fates_fire_alpha_SH(fates_pft) ; + fates_fire_alpha_SH:units = "m / (kw/m)**(2/3)" ; + fates_fire_alpha_SH:long_name = "spitfire parameter, alpha scorch height, Equation 16 Thonicke et al 2010" ; + double fates_fire_bark_scaler(fates_pft) ; + fates_fire_bark_scaler:units = "fraction" ; + fates_fire_bark_scaler:long_name = "the thickness of a cohorts bark as a fraction of its dbh" ; + double fates_fire_crown_kill(fates_pft) ; + fates_fire_crown_kill:units = "NA" ; + fates_fire_crown_kill:long_name = "fire parameter, see equation 22 in Thonicke et al 2010" ; + double fates_frag_fnrt_fcel(fates_pft) ; + fates_frag_fnrt_fcel:units = "fraction" ; + fates_frag_fnrt_fcel:long_name = "Fine root litter cellulose fraction" ; + double fates_frag_fnrt_flab(fates_pft) ; + fates_frag_fnrt_flab:units = "fraction" ; + fates_frag_fnrt_flab:long_name = "Fine root litter labile fraction" ; + double fates_frag_fnrt_flig(fates_pft) ; + fates_frag_fnrt_flig:units = "fraction" ; + fates_frag_fnrt_flig:long_name = "Fine root litter lignin fraction" ; + double fates_frag_leaf_fcel(fates_pft) ; + fates_frag_leaf_fcel:units = "fraction" ; + fates_frag_leaf_fcel:long_name = "Leaf litter cellulose fraction" ; + double fates_frag_leaf_flab(fates_pft) ; + fates_frag_leaf_flab:units = "fraction" ; + fates_frag_leaf_flab:long_name = "Leaf litter labile fraction" ; + double fates_frag_leaf_flig(fates_pft) ; + fates_frag_leaf_flig:units = "fraction" ; + fates_frag_leaf_flig:long_name = "Leaf litter lignin fraction" ; + double fates_frag_seed_decay_rate(fates_pft) ; + fates_frag_seed_decay_rate:units = "yr-1" ; + fates_frag_seed_decay_rate:long_name = "fraction of seeds that decay per year" ; + double fates_grperc(fates_pft) ; + fates_grperc:units = "unitless" ; + fates_grperc:long_name = "Growth respiration factor" ; + double fates_hydro_avuln_gs(fates_pft) ; + fates_hydro_avuln_gs:units = "unitless" ; + fates_hydro_avuln_gs:long_name = "shape parameter for stomatal control of water vapor exiting leaf" ; + double fates_hydro_avuln_node(fates_hydr_organs, fates_pft) ; + fates_hydro_avuln_node:units = "unitless" ; + fates_hydro_avuln_node:long_name = "xylem vulnerability curve shape parameter" ; + double fates_hydro_epsil_node(fates_hydr_organs, fates_pft) ; + fates_hydro_epsil_node:units = "MPa" ; + fates_hydro_epsil_node:long_name = "bulk elastic modulus" ; + double fates_hydro_fcap_node(fates_hydr_organs, fates_pft) ; + fates_hydro_fcap_node:units = "unitless" ; + fates_hydro_fcap_node:long_name = "fraction of non-residual water that is capillary in source" ; + double fates_hydro_k_lwp(fates_pft) ; + fates_hydro_k_lwp:units = "unitless" ; + fates_hydro_k_lwp:long_name = "inner leaf humidity scaling coefficient" ; + double fates_hydro_kmax_node(fates_hydr_organs, fates_pft) ; + fates_hydro_kmax_node:units = "kg/MPa/m/s" ; + fates_hydro_kmax_node:long_name = "maximum xylem conductivity per unit conducting xylem area" ; + double fates_hydro_p50_gs(fates_pft) ; + fates_hydro_p50_gs:units = "MPa" ; + fates_hydro_p50_gs:long_name = "water potential at 50% loss of stomatal conductance" ; + double fates_hydro_p50_node(fates_hydr_organs, fates_pft) ; + fates_hydro_p50_node:units = "MPa" ; + fates_hydro_p50_node:long_name = "xylem water potential at 50% loss of conductivity" ; + double fates_hydro_p_taper(fates_pft) ; + fates_hydro_p_taper:units = "unitless" ; + fates_hydro_p_taper:long_name = "xylem taper exponent" ; + double fates_hydro_pinot_node(fates_hydr_organs, fates_pft) ; + fates_hydro_pinot_node:units = "MPa" ; + fates_hydro_pinot_node:long_name = "osmotic potential at full turgor" ; + double fates_hydro_pitlp_node(fates_hydr_organs, fates_pft) ; + fates_hydro_pitlp_node:units = "MPa" ; + fates_hydro_pitlp_node:long_name = "turgor loss point" ; + double fates_hydro_resid_node(fates_hydr_organs, fates_pft) ; + fates_hydro_resid_node:units = "cm3/cm3" ; + fates_hydro_resid_node:long_name = "residual water conent" ; + double fates_hydro_rfrac_stem(fates_pft) ; + fates_hydro_rfrac_stem:units = "fraction" ; + fates_hydro_rfrac_stem:long_name = "fraction of total tree resistance from troot to canopy" ; + double fates_hydro_rs2(fates_pft) ; + fates_hydro_rs2:units = "m" ; + fates_hydro_rs2:long_name = "absorbing root radius" ; + double fates_hydro_srl(fates_pft) ; + fates_hydro_srl:units = "m g-1" ; + fates_hydro_srl:long_name = "specific root length" ; + double fates_hydro_thetas_node(fates_hydr_organs, fates_pft) ; + fates_hydro_thetas_node:units = "cm3/cm3" ; + fates_hydro_thetas_node:long_name = "saturated water content" ; + double fates_hydro_vg_alpha_node(fates_hydr_organs, fates_pft) ; + fates_hydro_vg_alpha_node:units = "MPa-1" ; + fates_hydro_vg_alpha_node:long_name = "(used if hydr_htftype_node = 2), capillary length parameter in van Genuchten model" ; + double fates_hydro_vg_m_node(fates_hydr_organs, fates_pft) ; + fates_hydro_vg_m_node:units = "unitless" ; + fates_hydro_vg_m_node:long_name = "(used if hydr_htftype_node = 2),m in van Genuchten 1980 model, 2nd pore size distribution parameter" ; + double fates_hydro_vg_n_node(fates_hydr_organs, fates_pft) ; + fates_hydro_vg_n_node:units = "unitless" ; + fates_hydro_vg_n_node:long_name = "(used if hydr_htftype_node = 2),n in van Genuchten 1980 model, pore size distribution parameter" ; + double fates_leaf_c3psn(fates_pft) ; + fates_leaf_c3psn:units = "flag" ; + fates_leaf_c3psn:long_name = "Photosynthetic pathway (1=c3, 0=c4)" ; + double fates_leaf_jmaxha(fates_pft) ; + fates_leaf_jmaxha:units = "J/mol" ; + fates_leaf_jmaxha:long_name = "activation energy for jmax" ; + double fates_leaf_jmaxhd(fates_pft) ; + fates_leaf_jmaxhd:units = "J/mol" ; + fates_leaf_jmaxhd:long_name = "deactivation energy for jmax" ; + double fates_leaf_jmaxse(fates_pft) ; + fates_leaf_jmaxse:units = "J/mol/K" ; + fates_leaf_jmaxse:long_name = "entropy term for jmax" ; + double fates_leaf_slamax(fates_pft) ; + fates_leaf_slamax:units = "m^2/gC" ; + fates_leaf_slamax:long_name = "Maximum Specific Leaf Area (SLA), even if under a dense canopy" ; + double fates_leaf_slatop(fates_pft) ; + fates_leaf_slatop:units = "m^2/gC" ; + fates_leaf_slatop:long_name = "Specific Leaf Area (SLA) at top of canopy, projected area basis" ; + double fates_leaf_stomatal_intercept(fates_pft) ; + fates_leaf_stomatal_intercept:units = "umol H2O/m**2/s" ; + fates_leaf_stomatal_intercept:long_name = "Minimum unstressed stomatal conductance for Ball-Berry model and Medlyn model" ; + double fates_leaf_stomatal_slope_ballberry(fates_pft) ; + fates_leaf_stomatal_slope_ballberry:units = "unitless" ; + fates_leaf_stomatal_slope_ballberry:long_name = "stomatal slope parameter, as per Ball-Berry" ; + double fates_leaf_stomatal_slope_medlyn(fates_pft) ; + fates_leaf_stomatal_slope_medlyn:units = "KPa**0.5" ; + fates_leaf_stomatal_slope_medlyn:long_name = "stomatal slope parameter, as per Medlyn" ; + double fates_leaf_vcmax25top(fates_leafage_class, fates_pft) ; + fates_leaf_vcmax25top:units = "umol CO2/m^2/s" ; + fates_leaf_vcmax25top:long_name = "maximum carboxylation rate of Rub. at 25C, canopy top" ; + double fates_leaf_vcmaxha(fates_pft) ; + fates_leaf_vcmaxha:units = "J/mol" ; + fates_leaf_vcmaxha:long_name = "activation energy for vcmax" ; + double fates_leaf_vcmaxhd(fates_pft) ; + fates_leaf_vcmaxhd:units = "J/mol" ; + fates_leaf_vcmaxhd:long_name = "deactivation energy for vcmax" ; + double fates_leaf_vcmaxse(fates_pft) ; + fates_leaf_vcmaxse:units = "J/mol/K" ; + fates_leaf_vcmaxse:long_name = "entropy term for vcmax" ; + double fates_maintresp_reduction_curvature(fates_pft) ; + fates_maintresp_reduction_curvature:units = "unitless (0-1)" ; + fates_maintresp_reduction_curvature:long_name = "curvature of MR reduction as f(carbon storage), 1=linear, 0=very curved" ; + double fates_maintresp_reduction_intercept(fates_pft) ; + fates_maintresp_reduction_intercept:units = "unitless (0-1)" ; + fates_maintresp_reduction_intercept:long_name = "intercept of MR reduction as f(carbon storage), 0=no throttling, 1=max throttling" ; + double fates_mort_bmort(fates_pft) ; + fates_mort_bmort:units = "1/yr" ; + fates_mort_bmort:long_name = "background mortality rate" ; + double fates_mort_freezetol(fates_pft) ; + fates_mort_freezetol:units = "degrees C" ; + fates_mort_freezetol:long_name = "minimum temperature tolerance" ; + double fates_mort_hf_flc_threshold(fates_pft) ; + fates_mort_hf_flc_threshold:units = "fraction" ; + fates_mort_hf_flc_threshold:long_name = "plant fractional loss of conductivity at which drought mortality begins for hydraulic model" ; + double fates_mort_hf_sm_threshold(fates_pft) ; + fates_mort_hf_sm_threshold:units = "unitless" ; + fates_mort_hf_sm_threshold:long_name = "soil moisture (btran units) at which drought mortality begins for non-hydraulic model" ; + double fates_mort_ip_age_senescence(fates_pft) ; + fates_mort_ip_age_senescence:units = "years" ; + fates_mort_ip_age_senescence:long_name = "Mortality cohort age senescence inflection point. If _ this mortality term is off. Setting this value turns on age dependent mortality. " ; + double fates_mort_ip_size_senescence(fates_pft) ; + fates_mort_ip_size_senescence:units = "dbh cm" ; + fates_mort_ip_size_senescence:long_name = "Mortality dbh senescence inflection point. If _ this mortality term is off. Setting this value turns on size dependent mortality" ; + double fates_mort_prescribed_canopy(fates_pft) ; + fates_mort_prescribed_canopy:units = "1/yr" ; + fates_mort_prescribed_canopy:long_name = "mortality rate of canopy trees for prescribed physiology mode" ; + double fates_mort_prescribed_understory(fates_pft) ; + fates_mort_prescribed_understory:units = "1/yr" ; + fates_mort_prescribed_understory:long_name = "mortality rate of understory trees for prescribed physiology mode" ; + double fates_mort_r_age_senescence(fates_pft) ; + fates_mort_r_age_senescence:units = "mortality rate year^-1" ; + fates_mort_r_age_senescence:long_name = "Mortality age senescence rate of change. Sensible range is around 0.03-0.06. Larger values givesteeper mortality curves." ; + double fates_mort_r_size_senescence(fates_pft) ; + fates_mort_r_size_senescence:units = "mortality rate dbh^-1" ; + fates_mort_r_size_senescence:long_name = "Mortality dbh senescence rate of change. Sensible range is around 0.03-0.06. Larger values give steeper mortality curves." ; + double fates_mort_scalar_coldstress(fates_pft) ; + fates_mort_scalar_coldstress:units = "1/yr" ; + fates_mort_scalar_coldstress:long_name = "maximum mortality rate from cold stress" ; + double fates_mort_scalar_cstarvation(fates_pft) ; + fates_mort_scalar_cstarvation:units = "1/yr" ; + fates_mort_scalar_cstarvation:long_name = "maximum mortality rate from carbon starvation" ; + double fates_mort_scalar_hydrfailure(fates_pft) ; + fates_mort_scalar_hydrfailure:units = "1/yr" ; + fates_mort_scalar_hydrfailure:long_name = "maximum mortality rate from hydraulic failure" ; + double fates_nonhydro_smpsc(fates_pft) ; + fates_nonhydro_smpsc:units = "mm" ; + fates_nonhydro_smpsc:long_name = "Soil water potential at full stomatal closure" ; + double fates_nonhydro_smpso(fates_pft) ; + fates_nonhydro_smpso:units = "mm" ; + fates_nonhydro_smpso:long_name = "Soil water potential at full stomatal opening" ; + double fates_phen_cold_size_threshold(fates_pft) ; + fates_phen_cold_size_threshold:units = "cm" ; + fates_phen_cold_size_threshold:long_name = "the dbh size above which will lead to phenology-related stem and leaf drop" ; + double fates_phen_evergreen(fates_pft) ; + fates_phen_evergreen:units = "logical flag" ; + fates_phen_evergreen:long_name = "Binary flag for evergreen leaf habit" ; + double fates_phen_flush_fraction(fates_pft) ; + fates_phen_flush_fraction:units = "fraction" ; + fates_phen_flush_fraction:long_name = "Upon bud-burst, the maximum fraction of storage carbon used for flushing leaves" ; + double fates_phen_fnrt_drop_frac(fates_pft) ; + fates_phen_fnrt_drop_frac:units = "fraction" ; + fates_phen_fnrt_drop_frac:long_name = "fraction of fine roots to drop during drought or cold" ; + double fates_phen_season_decid(fates_pft) ; + fates_phen_season_decid:units = "logical flag" ; + fates_phen_season_decid:long_name = "Binary flag for seasonal-deciduous leaf habit" ; + double fates_phen_stem_drop_fraction(fates_pft) ; + fates_phen_stem_drop_fraction:units = "fraction" ; + fates_phen_stem_drop_fraction:long_name = "fraction of stems to drop for non-woody species during drought/cold" ; + double fates_phen_stress_decid(fates_pft) ; + fates_phen_stress_decid:units = "logical flag" ; + fates_phen_stress_decid:long_name = "Binary flag for stress-deciduous leaf habit" ; + double fates_prescribed_npp_canopy(fates_pft) ; + fates_prescribed_npp_canopy:units = "kgC / m^2 / yr" ; + fates_prescribed_npp_canopy:long_name = "NPP per unit crown area of canopy trees for prescribed physiology mode" ; + double fates_prescribed_npp_understory(fates_pft) ; + fates_prescribed_npp_understory:units = "kgC / m^2 / yr" ; + fates_prescribed_npp_understory:long_name = "NPP per unit crown area of understory trees for prescribed physiology mode" ; + double fates_rad_leaf_clumping_index(fates_pft) ; + fates_rad_leaf_clumping_index:units = "fraction (0-1)" ; + fates_rad_leaf_clumping_index:long_name = "factor describing how much self-occlusion of leaf scattering elements decreases light interception" ; + double fates_rad_leaf_rhonir(fates_pft) ; + fates_rad_leaf_rhonir:units = "fraction" ; + fates_rad_leaf_rhonir:long_name = "Leaf reflectance: near-IR" ; + double fates_rad_leaf_rhovis(fates_pft) ; + fates_rad_leaf_rhovis:units = "fraction" ; + fates_rad_leaf_rhovis:long_name = "Leaf reflectance: visible" ; + double fates_rad_leaf_taunir(fates_pft) ; + fates_rad_leaf_taunir:units = "fraction" ; + fates_rad_leaf_taunir:long_name = "Leaf transmittance: near-IR" ; + double fates_rad_leaf_tauvis(fates_pft) ; + fates_rad_leaf_tauvis:units = "fraction" ; + fates_rad_leaf_tauvis:long_name = "Leaf transmittance: visible" ; + double fates_rad_leaf_xl(fates_pft) ; + fates_rad_leaf_xl:units = "unitless" ; + fates_rad_leaf_xl:long_name = "Leaf/stem orientation index" ; + double fates_rad_stem_rhonir(fates_pft) ; + fates_rad_stem_rhonir:units = "fraction" ; + fates_rad_stem_rhonir:long_name = "Stem reflectance: near-IR" ; + double fates_rad_stem_rhovis(fates_pft) ; + fates_rad_stem_rhovis:units = "fraction" ; + fates_rad_stem_rhovis:long_name = "Stem reflectance: visible" ; + double fates_rad_stem_taunir(fates_pft) ; + fates_rad_stem_taunir:units = "fraction" ; + fates_rad_stem_taunir:long_name = "Stem transmittance: near-IR" ; + double fates_rad_stem_tauvis(fates_pft) ; + fates_rad_stem_tauvis:units = "fraction" ; + fates_rad_stem_tauvis:long_name = "Stem transmittance: visible" ; + double fates_recruit_height_min(fates_pft) ; + fates_recruit_height_min:units = "m" ; + fates_recruit_height_min:long_name = "the minimum height (ie starting height) of a newly recruited plant" ; + double fates_recruit_init_density(fates_pft) ; + fates_recruit_init_density:units = "stems/m2" ; + fates_recruit_init_density:long_name = "initial seedling density for a cold-start near-bare-ground simulation" ; + double fates_recruit_prescribed_rate(fates_pft) ; + fates_recruit_prescribed_rate:units = "n/yr" ; + fates_recruit_prescribed_rate:long_name = "recruitment rate for prescribed physiology mode" ; + double fates_recruit_seed_alloc(fates_pft) ; + fates_recruit_seed_alloc:units = "fraction" ; + fates_recruit_seed_alloc:long_name = "fraction of available carbon balance allocated to seeds" ; + double fates_recruit_seed_alloc_mature(fates_pft) ; + fates_recruit_seed_alloc_mature:units = "fraction" ; + fates_recruit_seed_alloc_mature:long_name = "fraction of available carbon balance allocated to seeds in mature plants (adds to fates_seed_alloc)" ; + double fates_recruit_seed_dbh_repro_threshold(fates_pft) ; + fates_recruit_seed_dbh_repro_threshold:units = "cm" ; + fates_recruit_seed_dbh_repro_threshold:long_name = "the diameter where the plant will increase allocation to the seed pool by fraction: fates_recruit_seed_alloc_mature" ; + double fates_recruit_seed_germination_rate(fates_pft) ; + fates_recruit_seed_germination_rate:units = "yr-1" ; + fates_recruit_seed_germination_rate:long_name = "fraction of seeds that germinate per year" ; + double fates_recruit_seed_supplement(fates_pft) ; + fates_recruit_seed_supplement:units = "KgC/m2/yr" ; + fates_recruit_seed_supplement:long_name = "Supplemental external seed rain source term (non-mass conserving)" ; + double fates_stoich_nitr(fates_plant_organs, fates_pft) ; + fates_stoich_nitr:units = "gN/gC" ; + fates_stoich_nitr:long_name = "target nitrogen concentration (ratio with carbon) of organs" ; + double fates_stoich_phos(fates_plant_organs, fates_pft) ; + fates_stoich_phos:units = "gP/gC" ; + fates_stoich_phos:long_name = "target phosphorus concentration (ratio with carbon) of organs" ; + double fates_trim_inc(fates_pft) ; + fates_trim_inc:units = "m2/m2" ; + fates_trim_inc:long_name = "Arbitrary incremental change in trimming function." ; + double fates_trim_limit(fates_pft) ; + fates_trim_limit:units = "m2/m2" ; + fates_trim_limit:long_name = "Arbitrary limit to reductions in leaf area with stress" ; + double fates_turb_displar(fates_pft) ; + fates_turb_displar:units = "unitless" ; + fates_turb_displar:long_name = "Ratio of displacement height to canopy top height" ; + double fates_turb_leaf_diameter(fates_pft) ; + fates_turb_leaf_diameter:units = "m" ; + fates_turb_leaf_diameter:long_name = "Characteristic leaf dimension" ; + double fates_turb_z0mr(fates_pft) ; + fates_turb_z0mr:units = "unitless" ; + fates_turb_z0mr:long_name = "Ratio of momentum roughness length to canopy top height" ; + double fates_turnover_branch(fates_pft) ; + fates_turnover_branch:units = "yr" ; + fates_turnover_branch:long_name = "turnover time of branches" ; + double fates_turnover_fnrt(fates_pft) ; + fates_turnover_fnrt:units = "yr" ; + fates_turnover_fnrt:long_name = "root longevity (alternatively, turnover time)" ; + double fates_turnover_leaf(fates_leafage_class, fates_pft) ; + fates_turnover_leaf:units = "yr" ; + fates_turnover_leaf:long_name = "Leaf longevity (ie turnover timescale)" ; + double fates_turnover_senleaf_fdrought(fates_pft) ; + fates_turnover_senleaf_fdrought:units = "unitless[0-1]" ; + fates_turnover_senleaf_fdrought:long_name = "multiplication factor for leaf longevity of senescent leaves during drought" ; + double fates_wood_density(fates_pft) ; + fates_wood_density:units = "g/cm3" ; + fates_wood_density:long_name = "mean density of woody tissue in plant" ; + double fates_woody(fates_pft) ; + fates_woody:units = "logical flag" ; + fates_woody:long_name = "Binary woody lifeform flag" ; + double fates_hlm_pft_map(fates_hlm_pftno, fates_pft) ; + fates_hlm_pft_map:units = "area fraction" ; + fates_hlm_pft_map:long_name = "In fixed biogeog mode, fraction of HLM area associated with each FATES PFT" ; + double fates_fire_FBD(fates_litterclass) ; + fates_fire_FBD:units = "kg Biomass/m3" ; + fates_fire_FBD:long_name = "fuel bulk density" ; + double fates_fire_low_moisture_Coeff(fates_litterclass) ; + fates_fire_low_moisture_Coeff:units = "NA" ; + fates_fire_low_moisture_Coeff:long_name = "spitfire parameter, equation B1 Thonicke et al 2010" ; + double fates_fire_low_moisture_Slope(fates_litterclass) ; + fates_fire_low_moisture_Slope:units = "NA" ; + fates_fire_low_moisture_Slope:long_name = "spitfire parameter, equation B1 Thonicke et al 2010" ; + double fates_fire_mid_moisture(fates_litterclass) ; + fates_fire_mid_moisture:units = "NA" ; + fates_fire_mid_moisture:long_name = "spitfire litter moisture threshold to be considered medium dry" ; + double fates_fire_mid_moisture_Coeff(fates_litterclass) ; + fates_fire_mid_moisture_Coeff:units = "NA" ; + fates_fire_mid_moisture_Coeff:long_name = "spitfire parameter, equation B1 Thonicke et al 2010" ; + double fates_fire_mid_moisture_Slope(fates_litterclass) ; + fates_fire_mid_moisture_Slope:units = "NA" ; + fates_fire_mid_moisture_Slope:long_name = "spitfire parameter, equation B1 Thonicke et al 2010" ; + double fates_fire_min_moisture(fates_litterclass) ; + fates_fire_min_moisture:units = "NA" ; + fates_fire_min_moisture:long_name = "spitfire litter moisture threshold to be considered very dry" ; + double fates_fire_SAV(fates_litterclass) ; + fates_fire_SAV:units = "cm-1" ; + fates_fire_SAV:long_name = "fuel surface area to volume ratio" ; + double fates_frag_maxdecomp(fates_litterclass) ; + fates_frag_maxdecomp:units = "yr-1" ; + fates_frag_maxdecomp:long_name = "maximum rate of litter & CWD transfer from non-decomposing class into decomposing class" ; + double fates_frag_cwd_frac(fates_NCWD) ; + fates_frag_cwd_frac:units = "fraction" ; + fates_frag_cwd_frac:long_name = "fraction of woody (bdead+bsw) biomass destined for CWD pool" ; + double fates_base_mr_20 ; + fates_base_mr_20:units = "gC/gN/s" ; + fates_base_mr_20:long_name = "Base maintenance respiration rate for plant tissues, using Ryan 1991" ; + double fates_canopy_closure_thresh ; + fates_canopy_closure_thresh:units = "unitless" ; + fates_canopy_closure_thresh:long_name = "tree canopy coverage at which crown area allometry changes from savanna to forest value" ; + double fates_cnp_eca_plant_escalar ; + fates_cnp_eca_plant_escalar:units = "" ; + fates_cnp_eca_plant_escalar:long_name = "scaling factor for plant fine root biomass to calculate nutrient carrier enzyme abundance (ECA)" ; + double fates_cohort_age_fusion_tol ; + fates_cohort_age_fusion_tol:units = "unitless" ; + fates_cohort_age_fusion_tol:long_name = "minimum fraction in differece in cohort age between cohorts." ; + double fates_cohort_size_fusion_tol ; + fates_cohort_size_fusion_tol:units = "unitless" ; + fates_cohort_size_fusion_tol:long_name = "minimum fraction in difference in dbh between cohorts" ; + double fates_comp_excln ; + fates_comp_excln:units = "none" ; + fates_comp_excln:long_name = "IF POSITIVE: weighting factor (exponent on dbh) for canopy layer exclusion and promotion, IF NEGATIVE: switch to use deterministic height sorting" ; + double fates_damage_canopy_layer_code ; + fates_damage_canopy_layer_code:units = "unitless" ; + fates_damage_canopy_layer_code:long_name = "Integer code that decides whether damage affects canopy trees (1), understory trees (2)" ; + double fates_damage_event_code ; + fates_damage_event_code:units = "unitless" ; + fates_damage_event_code:long_name = "Integer code that options how damage events are structured" ; + double fates_dev_arbitrary ; + fates_dev_arbitrary:units = "unknown" ; + fates_dev_arbitrary:long_name = "Unassociated free parameter that developers can use for testing arbitrary new hypotheses" ; + double fates_fire_active_crown_fire ; + fates_fire_active_crown_fire:units = "0 or 1" ; + fates_fire_active_crown_fire:long_name = "flag, 1=active crown fire 0=no active crown fire" ; + double fates_fire_cg_strikes ; + fates_fire_cg_strikes:units = "fraction (0-1)" ; + fates_fire_cg_strikes:long_name = "fraction of cloud to ground lightning strikes" ; + double fates_fire_drying_ratio ; + fates_fire_drying_ratio:units = "NA" ; + fates_fire_drying_ratio:long_name = "spitfire parameter, fire drying ratio for fuel moisture, alpha_FMC EQ 6 Thonicke et al 2010" ; + double fates_fire_durat_slope ; + fates_fire_durat_slope:units = "NA" ; + fates_fire_durat_slope:long_name = "spitfire parameter, fire max duration slope, Equation 14 Thonicke et al 2010" ; + double fates_fire_fdi_a ; + fates_fire_fdi_a:units = "NA" ; + fates_fire_fdi_a:long_name = "spitfire parameter, fire danger index, EQ 5 Thonicke et al 2010" ; + double fates_fire_fdi_alpha ; + fates_fire_fdi_alpha:units = "NA" ; + fates_fire_fdi_alpha:long_name = "spitfire parameter, EQ 7 Venevsky et al. GCB 2002,(modified EQ 8 Thonicke et al. 2010) " ; + double fates_fire_fdi_b ; + fates_fire_fdi_b:units = "NA" ; + fates_fire_fdi_b:long_name = "spitfire parameter, fire danger index, EQ 5 Thonicke et al 2010 " ; + double fates_fire_fuel_energy ; + fates_fire_fuel_energy:units = "kJ/kg" ; + fates_fire_fuel_energy:long_name = "spitfire parameter, heat content of fuel" ; + double fates_fire_max_durat ; + fates_fire_max_durat:units = "minutes" ; + fates_fire_max_durat:long_name = "spitfire parameter, fire maximum duration, Equation 14 Thonicke et al 2010" ; + double fates_fire_miner_damp ; + fates_fire_miner_damp:units = "NA" ; + fates_fire_miner_damp:long_name = "spitfire parameter, mineral-dampening coefficient EQ A1 Thonicke et al 2010 " ; + double fates_fire_miner_total ; + fates_fire_miner_total:units = "fraction" ; + fates_fire_miner_total:long_name = "spitfire parameter, total mineral content, Table A1 Thonicke et al 2010" ; + double fates_fire_nignitions ; + fates_fire_nignitions:units = "ignitions per year per km2" ; + fates_fire_nignitions:long_name = "number of annual ignitions per square km" ; + double fates_fire_part_dens ; + fates_fire_part_dens:units = "kg/m2" ; + fates_fire_part_dens:long_name = "spitfire parameter, oven dry particle density, Table A1 Thonicke et al 2010" ; + double fates_fire_threshold ; + fates_fire_threshold:units = "kW/m" ; + fates_fire_threshold:long_name = "spitfire parameter, fire intensity threshold for tracking fires that spread" ; + double fates_frag_cwd_fcel ; + fates_frag_cwd_fcel:units = "unitless" ; + fates_frag_cwd_fcel:long_name = "Cellulose fraction for CWD" ; + double fates_frag_cwd_flig ; + fates_frag_cwd_flig:units = "unitless" ; + fates_frag_cwd_flig:long_name = "Lignin fraction of coarse woody debris" ; + double fates_hydro_kmax_rsurf1 ; + fates_hydro_kmax_rsurf1:units = "kg water/m2 root area/Mpa/s" ; + fates_hydro_kmax_rsurf1:long_name = "maximum conducitivity for unit root surface (into root)" ; + double fates_hydro_kmax_rsurf2 ; + fates_hydro_kmax_rsurf2:units = "kg water/m2 root area/Mpa/s" ; + fates_hydro_kmax_rsurf2:long_name = "maximum conducitivity for unit root surface (out of root)" ; + double fates_hydro_psi0 ; + fates_hydro_psi0:units = "MPa" ; + fates_hydro_psi0:long_name = "sapwood water potential at saturation" ; + double fates_hydro_psicap ; + fates_hydro_psicap:units = "MPa" ; + fates_hydro_psicap:long_name = "sapwood water potential at which capillary reserves exhausted" ; + double fates_hydro_solver ; + fates_hydro_solver:units = "unitless" ; + fates_hydro_solver:long_name = "switch designating which numerical solver for plant hydraulics, 1 = 1D taylor, 2 = 2D Picard, 3 = 2D Newton (deprecated)" ; + double fates_landuse_logging_coll_under_frac ; + fates_landuse_logging_coll_under_frac:units = "fraction" ; + fates_landuse_logging_coll_under_frac:long_name = "Fraction of stems killed in the understory when logging generates disturbance" ; + double fates_landuse_logging_collateral_frac ; + fates_landuse_logging_collateral_frac:units = "fraction" ; + fates_landuse_logging_collateral_frac:long_name = "Fraction of large stems in upperstory that die from logging collateral damage" ; + double fates_landuse_logging_dbhmax ; + fates_landuse_logging_dbhmax:units = "cm" ; + fates_landuse_logging_dbhmax:long_name = "Maximum dbh below which logging is applied (unset values flag this to be unused)" ; + double fates_landuse_logging_dbhmax_infra ; + fates_landuse_logging_dbhmax_infra:units = "cm" ; + fates_landuse_logging_dbhmax_infra:long_name = "Tree diameter, above which infrastructure from logging does not impact damage or mortality." ; + double fates_landuse_logging_dbhmin ; + fates_landuse_logging_dbhmin:units = "cm" ; + fates_landuse_logging_dbhmin:long_name = "Minimum dbh at which logging is applied" ; + double fates_landuse_logging_direct_frac ; + fates_landuse_logging_direct_frac:units = "fraction" ; + fates_landuse_logging_direct_frac:long_name = "Fraction of stems logged directly per event" ; + double fates_landuse_logging_event_code ; + fates_landuse_logging_event_code:units = "unitless" ; + fates_landuse_logging_event_code:long_name = "Integer code that options how logging events are structured" ; + double fates_landuse_logging_export_frac ; + fates_landuse_logging_export_frac:units = "fraction" ; + fates_landuse_logging_export_frac:long_name = "fraction of trunk product being shipped offsite, the leftovers will be left onsite as large CWD" ; + double fates_landuse_logging_mechanical_frac ; + fates_landuse_logging_mechanical_frac:units = "fraction" ; + fates_landuse_logging_mechanical_frac:long_name = "Fraction of stems killed due infrastructure an other mechanical means" ; + double fates_landuse_pprodharv10_forest_mean ; + fates_landuse_pprodharv10_forest_mean:units = "fraction" ; + fates_landuse_pprodharv10_forest_mean:long_name = "mean harvest mortality proportion of deadstem to 10-yr product (pprodharv10) of all woody PFT types" ; + double fates_leaf_photo_temp_acclim_timescale ; + fates_leaf_photo_temp_acclim_timescale:units = "days" ; + fates_leaf_photo_temp_acclim_timescale:long_name = "Length of the window for the exponential moving average (ema) of vegetation temperature used in photosynthesis temperature acclimation (NOT USED)" ; + double fates_leaf_photo_tempsens_model ; + fates_leaf_photo_tempsens_model:units = "unitless" ; + fates_leaf_photo_tempsens_model:long_name = "switch for choosing the model that defines the temperature sensitivity of photosynthetic parameters (vcmax, jmax). 1=non-acclimating (NOT USED)" ; + double fates_leaf_stomatal_assim_model ; + fates_leaf_stomatal_assim_model:units = "unitless" ; + fates_leaf_stomatal_assim_model:long_name = "a switch designating whether to use net (1) or gross (2) assimilation in the stomatal model" ; + double fates_leaf_stomatal_model ; + fates_leaf_stomatal_model:units = "unitless" ; + fates_leaf_stomatal_model:long_name = "switch for choosing between Ball-Berry (1) stomatal conductance model and Medlyn (2) model" ; + double fates_leaf_theta_cj_c3 ; + fates_leaf_theta_cj_c3:units = "unitless" ; + fates_leaf_theta_cj_c3:long_name = "Empirical curvature parameter for ac, aj photosynthesis co-limitation in c3 plants" ; + double fates_leaf_theta_cj_c4 ; + fates_leaf_theta_cj_c4:units = "unitless" ; + fates_leaf_theta_cj_c4:long_name = "Empirical curvature parameter for ac, aj photosynthesis co-limitation in c4 plants" ; + double fates_maintresp_model ; + fates_maintresp_model:units = "unitless" ; + fates_maintresp_model:long_name = "switch for choosing between maintenance respiration models. 1=Ryan (1991) (NOT USED)" ; + double fates_maxcohort ; + fates_maxcohort:units = "count" ; + fates_maxcohort:long_name = "maximum number of cohorts per patch. Actual number of cohorts also depend on cohort fusion tolerances" ; + double fates_maxpatch_primary ; + fates_maxpatch_primary:units = "count" ; + fates_maxpatch_primary:long_name = "maximum number of primary vegetation patches per site" ; + double fates_maxpatch_secondary ; + fates_maxpatch_secondary:units = "count" ; + fates_maxpatch_secondary:long_name = "maximum number of secondary vegetation patches per site" ; + double fates_mort_disturb_frac ; + fates_mort_disturb_frac:units = "fraction" ; + fates_mort_disturb_frac:long_name = "fraction of canopy mortality that results in disturbance (i.e. transfer of area from new to old patch)" ; + double fates_mort_understorey_death ; + fates_mort_understorey_death:units = "fraction" ; + fates_mort_understorey_death:long_name = "fraction of plants in understorey cohort impacted by overstorey tree-fall" ; + double fates_patch_fusion_tol ; + fates_patch_fusion_tol:units = "unitless" ; + fates_patch_fusion_tol:long_name = "minimum fraction in difference in profiles between patches" ; + double fates_phen_chilltemp ; + fates_phen_chilltemp:units = "degrees C" ; + fates_phen_chilltemp:long_name = "chilling day counting threshold for vegetation" ; + double fates_phen_coldtemp ; + fates_phen_coldtemp:units = "degrees C" ; + fates_phen_coldtemp:long_name = "vegetation temperature exceedance that flags a cold-day for leaf-drop" ; + double fates_phen_drought_model ; + fates_phen_drought_model:units = "unitless" ; + fates_phen_drought_model:long_name = "which method to use for drought phenology: 0 - FATES default; 1 - Semi-deciduous (ED2-like)" ; + double fates_phen_drought_threshold ; + fates_phen_drought_threshold:units = "m3/m3 or mm" ; + fates_phen_drought_threshold:long_name = "threshold for drought phenology (or lower threshold when fates_phen_drought_model = 1); the quantity depends on the sign: if positive, the threshold is volumetric soil moisture (m3/m3). If negative, the threshold is soil matric potentical (mm)" ; + double fates_phen_gddthresh_a ; + fates_phen_gddthresh_a:units = "none" ; + fates_phen_gddthresh_a:long_name = "GDD accumulation function, intercept parameter: gdd_thesh = a + b exp(c*ncd)" ; + double fates_phen_gddthresh_b ; + fates_phen_gddthresh_b:units = "none" ; + fates_phen_gddthresh_b:long_name = "GDD accumulation function, multiplier parameter: gdd_thesh = a + b exp(c*ncd)" ; + double fates_phen_gddthresh_c ; + fates_phen_gddthresh_c:units = "none" ; + fates_phen_gddthresh_c:long_name = "GDD accumulation function, exponent parameter: gdd_thesh = a + b exp(c*ncd)" ; + double fates_phen_mindaysoff ; + fates_phen_mindaysoff:units = "days" ; + fates_phen_mindaysoff:long_name = "day threshold compared against days since leaves became off-allometry" ; + double fates_phen_mindayson ; + fates_phen_mindayson:units = "days" ; + fates_phen_mindayson:long_name = "day threshold compared against days since leaves became on-allometry" ; + double fates_phen_moist_threshold ; + fates_phen_moist_threshold:units = "m3/m3 or mm" ; + fates_phen_moist_threshold:long_name = "upper threshold for drought phenology (only for fates_phen_drought_model=1); the quantity depends on the sign: if positive, the threshold is volumetric soil moisture (m3/m3). If negative, the threshold is soil matric potentical (mm)" ; + double fates_phen_ncolddayslim ; + fates_phen_ncolddayslim:units = "days" ; + fates_phen_ncolddayslim:long_name = "day threshold exceedance for temperature leaf-drop" ; + double fates_q10_froz ; + fates_q10_froz:units = "unitless" ; + fates_q10_froz:long_name = "Q10 for frozen-soil respiration rates" ; + double fates_q10_mr ; + fates_q10_mr:units = "unitless" ; + fates_q10_mr:long_name = "Q10 for maintenance respiration" ; + double fates_soil_salinity ; + fates_soil_salinity:units = "ppt" ; + fates_soil_salinity:long_name = "soil salinity used for model when not coupled to dynamic soil salinity" ; + double fates_vai_top_bin_width ; + fates_vai_top_bin_width:units = "m2/m2" ; + fates_vai_top_bin_width:long_name = "width in VAI units of uppermost leaf+stem layer scattering element in each canopy layer" ; + double fates_vai_width_increase_factor ; + fates_vai_width_increase_factor:units = "unitless" ; + fates_vai_width_increase_factor:long_name = "factor by which each leaf+stem scattering element increases in VAI width (1 = uniform spacing)" ; + +// global attributes: + :history = "This file was generated by BatchPatchParams.py:\nCDL Base File = archive/api24.1.0_101722_fates_params_default.cdl\nXML patch file = archive/api24.1.0_101722_patch_params.xml" ; +data: + + fates_history_ageclass_bin_edges = 0, 1, 2, 5, 10, 20, 50 ; + + fates_history_coageclass_bin_edges = 0, 5 ; + + fates_history_height_bin_edges = 0, 0.1, 0.3, 1, 3, 10 ; + + fates_history_damage_bin_edges = 0, 80 ; + + fates_history_sizeclass_bin_edges = 0, 5, 10, 15, 20, 30, 40, 50, 60, 70, + 80, 90, 100 ; + + fates_alloc_organ_id = 1, 2, 3, 6 ; + + fates_hydro_htftype_node = 1, 1, 1, 1 ; + + fates_pftname = + "broadleaf_evergreen_tropical_tree ", + "needleleaf_evergreen_extratrop_tree ", + "needleleaf_colddecid_extratrop_tree ", + "broadleaf_evergreen_extratrop_tree ", + "broadleaf_hydrodecid_tropical_tree ", + "broadleaf_colddecid_extratrop_tree ", + "broadleaf_evergreen_extratrop_shrub ", + "broadleaf_hydrodecid_extratrop_shrub ", + "broadleaf_colddecid_extratrop_shrub ", + "arctic_c3_grass ", + "cool_c3_grass ", + "c4_grass " ; + + fates_hydro_organ_name = + "leaf ", + "stem ", + "transporting root ", + "absorbing root " ; + + fates_alloc_organ_name = + "leaf", + "fine root", + "sapwood", + "structure" ; + + fates_litterclass_name = + "twig ", + "small branch ", + "large branch ", + "trunk ", + "dead leaves ", + "live grass " ; + + fates_alloc_organ_priority = + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 ; + + fates_alloc_storage_cushion = 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, + 1.2, 1.2, 1.2 ; + + fates_alloc_store_priority_frac = 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, + 0.8, 0.8, 0.8, 0.8 ; + + fates_allom_agb1 = 0.06896, 0.06896, 0.06896, 0.06896, 0.06896, 0.06896, + 0.06896, 0.06896, 0.06896, 0.01, 0.01, 0.01 ; + + fates_allom_agb2 = 0.572, 0.572, 0.572, 0.572, 0.572, 0.572, 0.572, 0.572, + 0.572, 0.572, 0.572, 0.572 ; + + fates_allom_agb3 = 1.94, 1.94, 1.94, 1.94, 1.94, 1.94, 1.94, 1.94, 1.94, + 1.94, 1.94, 1.94 ; + + fates_allom_agb4 = 0.931, 0.931, 0.931, 0.931, 0.931, 0.931, 0.931, 0.931, + 0.931, 0.931, 0.931, 0.931 ; + + fates_allom_agb_frac = 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, + 0.6, 0.6 ; + + fates_allom_amode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_blca_expnt_diff = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_allom_cmode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_crown_depth_frac = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.95, 0.95, + 0.95, 1, 1, 1 ; + + fates_allom_d2bl1 = 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, + 0.07, 0.07, 0.07 ; + + fates_allom_d2bl2 = 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, + 1.3 ; + + fates_allom_d2bl3 = 0.55, 0.55, 0.55, 0.55, 0.55, 0.55, 0.55, 0.55, 0.55, + 0.55, 0.55, 0.55 ; + + fates_allom_d2ca_coefficient_max = 0.6568464, 0.6568464, 0.6568464, + 0.6568464, 0.6568464, 0.6568464, 0.6568464, 0.6568464, 0.6568464, + 0.6568464, 0.6568464, 0.6568464 ; + + fates_allom_d2ca_coefficient_min = 0.3381119, 0.3381119, 0.3381119, + 0.3381119, 0.3381119, 0.3381119, 0.3381119, 0.3381119, 0.3381119, + 0.3381119, 0.3381119, 0.3381119 ; + + fates_allom_d2h1 = 0.64, 0.64, 0.64, 0.64, 0.64, 0.64, 0.64, 0.64, 0.64, + 0.64, 0.64, 0.64 ; + + fates_allom_d2h2 = 0.37, 0.37, 0.37, 0.37, 0.37, 0.37, 0.37, 0.37, 0.37, + 0.37, 0.37, 0.37 ; + + fates_allom_d2h3 = -999.9, -999.9, -999.9, -999.9, -999.9, -999.9, -999.9, + -999.9, -999.9, -999.9, -999.9, -999.9 ; + + fates_allom_dbh_maxheight = 90, 80, 80, 80, 90, 80, 3, 3, 2, 0.35, 0.35, 0.35 ; + + fates_allom_fmode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_fnrt_prof_a = 7, 7, 7, 7, 6, 6, 7, 7, 7, 11, 11, 11 ; + + fates_allom_fnrt_prof_b = 1, 2, 2, 1, 2, 2, 1.5, 1.5, 1.5, 2, 2, 2 ; + + fates_allom_fnrt_prof_mode = 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 ; + + fates_allom_frbstor_repro = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_allom_hmode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_l2fr = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_la_per_sa_int = 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, + 0.8, 0.8, 0.8 ; + + fates_allom_la_per_sa_slp = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_allom_lmode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_sai_scaler = 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, + 0.1, 0.1 ; + + fates_allom_smode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_stmode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_zroot_k = 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10 ; + + fates_allom_zroot_max_dbh = 100, 100, 100, 100, 100, 100, 2, 2, 2, 2, 2, 2 ; + + fates_allom_zroot_max_z = 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, + 100, 100 ; + + fates_allom_zroot_min_dbh = 1, 1, 1, 2.5, 2.5, 2.5, 0.1, 0.1, 0.1, 0.1, 0.1, + 0.1 ; + + fates_allom_zroot_min_z = 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, + 100, 100 ; + + fates_c2b = 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ; + + fates_cnp_eca_alpha_ptase = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5 ; + + fates_cnp_eca_decompmicc = 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280 ; + + fates_cnp_eca_km_nh4 = 0.14, 0.14, 0.14, 0.14, 0.14, 0.14, 0.14, 0.14, 0.14, + 0.14, 0.14, 0.14 ; + + fates_cnp_eca_km_no3 = 0.27, 0.27, 0.27, 0.27, 0.27, 0.27, 0.27, 0.27, 0.27, + 0.27, 0.27, 0.27 ; + + fates_cnp_eca_km_p = 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, + 0.1 ; + + fates_cnp_eca_km_ptase = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_cnp_eca_lambda_ptase = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_cnp_eca_vmax_nh4 = 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, + 5e-09, 5e-09, 5e-09, 5e-09, 5e-09 ; + + fates_cnp_eca_vmax_no3 = 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, + 5e-09, 5e-09, 5e-09, 5e-09, 5e-09 ; + + fates_cnp_eca_vmax_ptase = 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, + 5e-09, 5e-09, 5e-09, 5e-09, 5e-09 ; + + fates_cnp_fnrt_adapt_tscale = 100, 100, 100, 100, 100, 100, 100, 100, 100, + 100, 100, 100 ; + + fates_cnp_nfix1 = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_cnp_nitr_store_ratio = 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, + 1.5, 1.5, 1.5 ; + + fates_cnp_phos_store_ratio = 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, + 1.5, 1.5, 1.5 ; + + fates_cnp_prescribed_nuptake = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_cnp_prescribed_puptake = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_cnp_rd_vmax_n = 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, + 5e-09, 5e-09, 5e-09, 5e-09, 5e-09 ; + + fates_cnp_store_ovrflw_frac = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_cnp_turnover_nitr_retrans = + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_cnp_turnover_phos_retrans = + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_cnp_vmax_p = 5e-10, 5e-10, 5e-10, 5e-10, 5e-10, 5e-10, 5e-10, 5e-10, + 5e-10, 5e-10, 5e-10, 5e-10 ; + + fates_damage_frac = 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, + 0.01, 0.01, 0.01 ; + + fates_damage_mort_p1 = 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 ; + + fates_damage_mort_p2 = 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, + 5.5, 5.5 ; + + fates_damage_recovery_scalar = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_dev_arbitrary_pft = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_fire_alpha_SH = 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, + 0.2 ; + + fates_fire_bark_scaler = 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, + 0.07, 0.07, 0.07, 0.07 ; + + fates_fire_crown_kill = 0.775, 0.775, 0.775, 0.775, 0.775, 0.775, 0.775, + 0.775, 0.775, 0.775, 0.775, 0.775 ; + + fates_frag_fnrt_fcel = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5 ; + + fates_frag_fnrt_flab = 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25 ; + + fates_frag_fnrt_flig = 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25 ; + + fates_frag_leaf_fcel = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5 ; + + fates_frag_leaf_flab = 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25 ; + + fates_frag_leaf_flig = 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25 ; + + fates_frag_seed_decay_rate = 0.51, 0.51, 0.51, 0.51, 0.51, 0.51, 0.51, 0.51, + 0.51, 0.51, 0.51, 0.51 ; + + fates_grperc = 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, + 0.11, 0.11 ; + + fates_hydro_avuln_gs = 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, + 2.5, 2.5 ; + + fates_hydro_avuln_node = + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ; + + fates_hydro_epsil_node = + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 ; + + fates_hydro_fcap_node = + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, + 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_hydro_k_lwp = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_hydro_kmax_node = + -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999 ; + + fates_hydro_p50_gs = -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, + -1.5, -1.5, -1.5 ; + + fates_hydro_p50_node = + -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, + -2.25, -2.25, + -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, + -2.25, -2.25, + -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, + -2.25, -2.25, + -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, + -2.25, -2.25 ; + + fates_hydro_p_taper = 0.333, 0.333, 0.333, 0.333, 0.333, 0.333, 0.333, + 0.333, 0.333, 0.333, 0.333, 0.333 ; + + fates_hydro_pinot_node = + -1.465984, -1.465984, -1.465984, -1.465984, -1.465984, -1.465984, + -1.465984, -1.465984, -1.465984, -1.465984, -1.465984, -1.465984, + -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, + -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, + -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, + -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, + -1.043478, -1.043478, -1.043478, -1.043478, -1.043478, -1.043478, + -1.043478, -1.043478, -1.043478, -1.043478, -1.043478, -1.043478 ; + + fates_hydro_pitlp_node = + -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, + -1.67, -1.67, + -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, + -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, + -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2 ; + + fates_hydro_resid_node = + 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, + 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, + 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, + 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11 ; + + fates_hydro_rfrac_stem = 0.625, 0.625, 0.625, 0.625, 0.625, 0.625, 0.625, + 0.625, 0.625, 0.625, 0.625, 0.625 ; + + fates_hydro_rs2 = 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, + 0.0001, 0.0001, 0.0001, 0.0001, 0.0001 ; + + fates_hydro_srl = 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25 ; + + fates_hydro_thetas_node = + 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, + 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, + 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, + 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75 ; + + fates_hydro_vg_alpha_node = + 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.005, 0.005, 0.005, 0.005, 0.005, + 0.005, 0.005, + 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.005, 0.005, 0.005, 0.005, 0.005, + 0.005, 0.005, + 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.005, 0.005, 0.005, 0.005, 0.005, + 0.005, 0.005, + 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.005, 0.005, 0.005, 0.005, 0.005, + 0.005, 0.005 ; + + fates_hydro_vg_m_node = + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5 ; + + fates_hydro_vg_n_node = + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ; + + fates_leaf_c3psn = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 ; + + fates_leaf_jmaxha = 43540, 43540, 43540, 43540, 43540, 43540, 43540, 43540, + 43540, 43540, 43540, 43540 ; + + fates_leaf_jmaxhd = 152040, 152040, 152040, 152040, 152040, 152040, 152040, + 152040, 152040, 152040, 152040, 152040 ; + + fates_leaf_jmaxse = 495, 495, 495, 495, 495, 495, 495, 495, 495, 495, 495, + 495 ; + + fates_leaf_slamax = 0.0954, 0.0954, 0.0954, 0.0954, 0.0954, 0.0954, 0.012, + 0.03, 0.03, 0.03, 0.03, 0.03 ; + + fates_leaf_slatop = 0.012, 0.005, 0.024, 0.009, 0.03, 0.03, 0.012, 0.03, + 0.03, 0.03, 0.03, 0.03 ; + + fates_leaf_stomatal_intercept = 10000, 10000, 10000, 10000, 10000, 10000, + 10000, 10000, 10000, 10000, 10000, 40000 ; + + fates_leaf_stomatal_slope_ballberry = 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 ; + + fates_leaf_stomatal_slope_medlyn = 4.1, 2.3, 2.3, 4.1, 4.4, 4.4, 4.7, 4.7, + 4.7, 2.2, 5.3, 1.6 ; + + fates_leaf_vcmax25top = + 50, 62, 39, 61, 41, 58, 62, 54, 54, 78, 78, 78 ; + + fates_leaf_vcmaxha = 65330, 65330, 65330, 65330, 65330, 65330, 65330, 65330, + 65330, 65330, 65330, 65330 ; + + fates_leaf_vcmaxhd = 149250, 149250, 149250, 149250, 149250, 149250, 149250, + 149250, 149250, 149250, 149250, 149250 ; + + fates_leaf_vcmaxse = 485, 485, 485, 485, 485, 485, 485, 485, 485, 485, 485, + 485 ; + + fates_maintresp_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, + 0.014, 0.014, 0.014, 0.014 ; + + fates_mort_freezetol = 2.5, -55, -80, -30, 2.5, -80, -60, -10, -80, -80, + -20, 2.5 ; + + fates_mort_hf_flc_threshold = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5 ; + + fates_mort_hf_sm_threshold = 1e-06, 1e-06, 1e-06, 1e-06, 1e-06, 1e-06, + 1e-06, 1e-06, 1e-06, 1e-06, 1e-06, 1e-06 ; + + fates_mort_ip_age_senescence = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_mort_ip_size_senescence = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_mort_prescribed_canopy = 0.0194, 0.0194, 0.0194, 0.0194, 0.0194, + 0.0194, 0.0194, 0.0194, 0.0194, 0.0194, 0.0194, 0.0194 ; + + fates_mort_prescribed_understory = 0.025, 0.025, 0.025, 0.025, 0.025, 0.025, + 0.025, 0.025, 0.025, 0.025, 0.025, 0.025 ; + + fates_mort_r_age_senescence = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_mort_r_size_senescence = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_mort_scalar_coldstress = 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 ; + + fates_mort_scalar_cstarvation = 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, + 0.6, 0.6, 0.6 ; + + fates_mort_scalar_hydrfailure = 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, + 0.6, 0.6, 0.6 ; + + fates_nonhydro_smpsc = -255000, -255000, -255000, -255000, -255000, -255000, + -255000, -255000, -255000, -255000, -255000, -255000 ; + + fates_nonhydro_smpso = -66000, -66000, -66000, -66000, -66000, -66000, + -66000, -66000, -66000, -66000, -66000, -66000 ; + + fates_phen_cold_size_threshold = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_phen_evergreen = 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 ; + + fates_phen_flush_fraction = _, _, 0.5, _, 0.5, 0.5, _, 0.5, 0.5, 0.5, 0.5, + 0.5 ; + + fates_phen_fnrt_drop_frac = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_phen_season_decid = 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0 ; + + fates_phen_stem_drop_fraction = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_phen_stress_decid = 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1 ; + + fates_prescribed_npp_canopy = 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, + 0.4, 0.4, 0.4 ; + + fates_prescribed_npp_understory = 0.03125, 0.03125, 0.03125, 0.03125, + 0.03125, 0.03125, 0.03125, 0.03125, 0.03125, 0.03125, 0.03125, 0.03125 ; + + fates_rad_leaf_clumping_index = 0.85, 0.85, 0.8, 0.85, 0.85, 0.9, 0.85, 0.9, + 0.9, 0.75, 0.75, 0.75 ; + + fates_rad_leaf_rhonir = 0.46, 0.41, 0.39, 0.46, 0.41, 0.41, 0.46, 0.41, + 0.41, 0.28, 0.28, 0.28 ; + + fates_rad_leaf_rhovis = 0.11, 0.09, 0.08, 0.11, 0.08, 0.08, 0.11, 0.08, + 0.08, 0.05, 0.05, 0.05 ; + + fates_rad_leaf_taunir = 0.33, 0.32, 0.42, 0.33, 0.43, 0.43, 0.33, 0.43, + 0.43, 0.4, 0.4, 0.4 ; + + fates_rad_leaf_tauvis = 0.06, 0.04, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, + 0.06, 0.05, 0.05, 0.05 ; + + fates_rad_leaf_xl = 0.32, 0.01, 0.01, 0.32, 0.2, 0.59, 0.32, 0.59, 0.59, + -0.23, -0.23, -0.23 ; + + fates_rad_stem_rhonir = 0.49, 0.36, 0.36, 0.49, 0.49, 0.49, 0.49, 0.49, + 0.49, 0.53, 0.53, 0.53 ; + + fates_rad_stem_rhovis = 0.21, 0.12, 0.12, 0.21, 0.21, 0.21, 0.21, 0.21, + 0.21, 0.31, 0.31, 0.31 ; + + fates_rad_stem_taunir = 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, + 0.001, 0.001, 0.25, 0.25, 0.25 ; + + fates_rad_stem_tauvis = 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, + 0.001, 0.001, 0.12, 0.12, 0.12 ; + + fates_recruit_height_min = 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 0.2, 0.2, 0.2, + 0.125, 0.125, 0.125 ; + + fates_recruit_init_density = 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, + 0.2, 0.2, 0.2 ; + + fates_recruit_prescribed_rate = 0.02, 0.02, 0.02, 0.02, 0.02, 0.02, 0.02, + 0.02, 0.02, 0.02, 0.02, 0.02 ; + + fates_recruit_seed_alloc = 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, + 0.1, 0.1 ; + + fates_recruit_seed_alloc_mature = 0, 0, 0, 0, 0, 0, 0.9, 0.9, 0.9, 0.9, 0.9, + 0.9 ; + + fates_recruit_seed_dbh_repro_threshold = 90, 80, 80, 80, 90, 80, 3, 3, 2, + 0.35, 0.35, 0.35 ; + + fates_recruit_seed_germination_rate = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5 ; + + fates_recruit_seed_supplement = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_stoich_nitr = + 0.033, 0.029, 0.04, 0.033, 0.04, 0.04, 0.033, 0.04, 0.04, 0.04, 0.04, 0.04, + 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, + 0.024, 0.024, + 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, + 1e-08, 1e-08, + 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, + 0.0047, 0.0047, 0.0047 ; + + fates_stoich_phos = + 0.0033, 0.0029, 0.004, 0.0033, 0.004, 0.004, 0.0033, 0.004, 0.004, 0.004, + 0.004, 0.004, + 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, + 0.0024, 0.0024, 0.0024, + 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, + 1e-09, 1e-09, + 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, + 0.00047, 0.00047, 0.00047, 0.00047 ; + + fates_trim_inc = 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, + 0.03, 0.03 ; + + fates_trim_limit = 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3 ; + + fates_turb_displar = 0.67, 0.67, 0.67, 0.67, 0.67, 0.67, 0.67, 0.67, 0.67, + 0.67, 0.67, 0.67 ; + + fates_turb_leaf_diameter = 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, + 0.04, 0.04, 0.04, 0.04 ; + + fates_turb_z0mr = 0.055, 0.055, 0.055, 0.055, 0.055, 0.055, 0.055, 0.055, + 0.055, 0.055, 0.055, 0.055 ; + + fates_turnover_branch = 150, 150, 150, 150, 150, 150, 150, 150, 150, 0, 0, 0 ; + + fates_turnover_fnrt = 1, 2, 1, 1.5, 1, 1, 1.5, 1, 1, 1, 1, 1 ; + + fates_turnover_leaf = + 1.5, 4, 1, 1.5, 1, 1, 1.5, 1, 1, 1, 1, 1 ; + + fates_turnover_senleaf_fdrought = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_wood_density = 0.7, 0.4, 0.7, 0.53, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, + 0.7 ; + + fates_woody = 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 ; + + fates_hlm_pft_map = + 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 ; + + fates_fire_FBD = 15.4, 16.8, 19.6, 999, 4, 4 ; + + fates_fire_low_moisture_Coeff = 1.12, 1.09, 0.98, 0.8, 1.15, 1.15 ; + + fates_fire_low_moisture_Slope = 0.62, 0.72, 0.85, 0.8, 0.62, 0.62 ; + + fates_fire_mid_moisture = 0.72, 0.51, 0.38, 1, 0.8, 0.8 ; + + fates_fire_mid_moisture_Coeff = 2.35, 1.47, 1.06, 0.8, 3.2, 3.2 ; + + fates_fire_mid_moisture_Slope = 2.35, 1.47, 1.06, 0.8, 3.2, 3.2 ; + + fates_fire_min_moisture = 0.18, 0.12, 0, 0, 0.24, 0.24 ; + + fates_fire_SAV = 13, 3.58, 0.98, 0.2, 66, 66 ; + + fates_frag_maxdecomp = 0.52, 0.383, 0.383, 0.19, 1, 999 ; + + fates_frag_cwd_frac = 0.045, 0.075, 0.21, 0.67 ; + + fates_base_mr_20 = 2.52e-06 ; + + fates_canopy_closure_thresh = 0.8 ; + + fates_cnp_eca_plant_escalar = 1.25e-05 ; + + fates_cohort_age_fusion_tol = 0.08 ; + + fates_cohort_size_fusion_tol = 0.08 ; + + fates_comp_excln = 3 ; + + fates_damage_canopy_layer_code = 1 ; + + fates_damage_event_code = 1 ; + + fates_dev_arbitrary = _ ; + + fates_fire_active_crown_fire = 0 ; + + fates_fire_cg_strikes = 0.2 ; + + fates_fire_drying_ratio = 66000 ; + + fates_fire_durat_slope = -11.06 ; + + fates_fire_fdi_a = 17.62 ; + + fates_fire_fdi_alpha = 0.00037 ; + + fates_fire_fdi_b = 243.12 ; + + fates_fire_fuel_energy = 18000 ; + + fates_fire_max_durat = 240 ; + + fates_fire_miner_damp = 0.41739 ; + + fates_fire_miner_total = 0.055 ; + + fates_fire_nignitions = 15 ; + + fates_fire_part_dens = 513 ; + + fates_fire_threshold = 50 ; + + fates_frag_cwd_fcel = 0.76 ; + + fates_frag_cwd_flig = 0.24 ; + + fates_hydro_kmax_rsurf1 = 20 ; + + fates_hydro_kmax_rsurf2 = 0.0001 ; + + fates_hydro_psi0 = 0 ; + + fates_hydro_psicap = -0.6 ; + + fates_hydro_solver = 1 ; + + fates_landuse_logging_coll_under_frac = 0.55983 ; + + fates_landuse_logging_collateral_frac = 0.05 ; + + fates_landuse_logging_dbhmax = _ ; + + fates_landuse_logging_dbhmax_infra = 35 ; + + fates_landuse_logging_dbhmin = 50 ; + + fates_landuse_logging_direct_frac = 0.15 ; + + fates_landuse_logging_event_code = -30 ; + + fates_landuse_logging_export_frac = 0.8 ; + + fates_landuse_logging_mechanical_frac = 0.05 ; + + fates_landuse_pprodharv10_forest_mean = 0.8125 ; + + fates_leaf_photo_temp_acclim_timescale = 30 ; + + fates_leaf_photo_tempsens_model = 1 ; + + fates_leaf_stomatal_assim_model = 1 ; + + fates_leaf_stomatal_model = 1 ; + + fates_leaf_theta_cj_c3 = 0.999 ; + + fates_leaf_theta_cj_c4 = 0.999 ; + + fates_maintresp_model = 1 ; + + fates_maxcohort = 100 ; + + fates_maxpatch_primary = 10 ; + + fates_maxpatch_secondary = 4 ; + + fates_mort_disturb_frac = 1 ; + + fates_mort_understorey_death = 0.55983 ; + + fates_patch_fusion_tol = 0.05 ; + + fates_phen_chilltemp = 5 ; + + fates_phen_coldtemp = 7.5 ; + + fates_phen_drought_model = 0 ; + + fates_phen_drought_threshold = 0.15 ; + + fates_phen_gddthresh_a = -68 ; + + fates_phen_gddthresh_b = 638 ; + + fates_phen_gddthresh_c = -0.01 ; + + fates_phen_mindaysoff = 100 ; + + fates_phen_mindayson = 90 ; + + fates_phen_moist_threshold = 0.18 ; + + fates_phen_ncolddayslim = 5 ; + + fates_q10_froz = 1.5 ; + + fates_q10_mr = 1.5 ; + + fates_soil_salinity = 0.4 ; + + fates_vai_top_bin_width = 1 ; + + fates_vai_width_increase_factor = 1 ; +} diff --git a/parameter_files/archive/api25.1.0_021623_fates_params_default.cdl b/parameter_files/archive/api25.1.0_021623_fates_params_default.cdl new file mode 100644 index 0000000000..c5ddba36c6 --- /dev/null +++ b/parameter_files/archive/api25.1.0_021623_fates_params_default.cdl @@ -0,0 +1,1541 @@ +netcdf fates_params_default { +dimensions: + fates_NCWD = 4 ; + fates_history_age_bins = 7 ; + fates_history_coage_bins = 2 ; + fates_history_damage_bins = 2 ; + fates_history_height_bins = 6 ; + fates_history_size_bins = 13 ; + fates_hlm_pftno = 14 ; + fates_hydr_organs = 4 ; + fates_leafage_class = 1 ; + fates_litterclass = 6 ; + fates_pft = 12 ; + fates_plant_organs = 4 ; + fates_string_length = 60 ; +variables: + double fates_history_ageclass_bin_edges(fates_history_age_bins) ; + fates_history_ageclass_bin_edges:units = "yr" ; + fates_history_ageclass_bin_edges:long_name = "Lower edges for age class bins used in age-resolved patch history output" ; + double fates_history_coageclass_bin_edges(fates_history_coage_bins) ; + fates_history_coageclass_bin_edges:units = "years" ; + fates_history_coageclass_bin_edges:long_name = "Lower edges for cohort age class bins used in cohort age resolved history output" ; + double fates_history_height_bin_edges(fates_history_height_bins) ; + fates_history_height_bin_edges:units = "m" ; + fates_history_height_bin_edges:long_name = "Lower edges for height bins used in height-resolved history output" ; + double fates_history_damage_bin_edges(fates_history_damage_bins) ; + fates_history_damage_bin_edges:units = "% crown loss" ; + fates_history_damage_bin_edges:long_name = "Lower edges for damage class bins used in cohort history output" ; + double fates_history_sizeclass_bin_edges(fates_history_size_bins) ; + fates_history_sizeclass_bin_edges:units = "cm" ; + fates_history_sizeclass_bin_edges:long_name = "Lower edges for DBH size class bins used in size-resolved cohort history output" ; + double fates_alloc_organ_id(fates_plant_organs) ; + fates_alloc_organ_id:units = "unitless" ; + fates_alloc_organ_id:long_name = "This is the global index that the organ in this file is associated with, values match those in parteh/PRTGenericMod.F90" ; + double fates_hydro_htftype_node(fates_hydr_organs) ; + fates_hydro_htftype_node:units = "unitless" ; + fates_hydro_htftype_node:long_name = "Switch that defines the hydraulic transfer functions for each organ." ; + char fates_pftname(fates_pft, fates_string_length) ; + fates_pftname:units = "unitless - string" ; + fates_pftname:long_name = "Description of plant type" ; + char fates_hydro_organ_name(fates_hydr_organs, fates_string_length) ; + fates_hydro_organ_name:units = "unitless - string" ; + fates_hydro_organ_name:long_name = "Name of plant hydraulics organs (DONT CHANGE, order matches media list in FatesHydraulicsMemMod.F90)" ; + char fates_alloc_organ_name(fates_plant_organs, fates_string_length) ; + fates_alloc_organ_name:units = "unitless - string" ; + fates_alloc_organ_name:long_name = "Name of plant organs (with alloc_organ_id, must match PRTGenericMod.F90)" ; + char fates_litterclass_name(fates_litterclass, fates_string_length) ; + fates_litterclass_name:units = "unitless - string" ; + fates_litterclass_name:long_name = "Name of the litter classes, for variables associated with dimension fates_litterclass" ; + double fates_alloc_organ_priority(fates_plant_organs, fates_pft) ; + fates_alloc_organ_priority:units = "index" ; + fates_alloc_organ_priority:long_name = "Priority level for allocation, 1: replaces turnover from storage, 2: same priority as storage use/replacement, 3: ascending in order of least importance" ; + double fates_alloc_storage_cushion(fates_pft) ; + fates_alloc_storage_cushion:units = "fraction" ; + fates_alloc_storage_cushion:long_name = "maximum size of storage C pool, relative to maximum size of leaf C pool" ; + double fates_alloc_store_priority_frac(fates_pft) ; + fates_alloc_store_priority_frac:units = "unitless" ; + fates_alloc_store_priority_frac:long_name = "for high-priority organs, the fraction of their turnover demand that is gauranteed to be replaced, and if need-be by storage" ; + double fates_allom_agb1(fates_pft) ; + fates_allom_agb1:units = "variable" ; + fates_allom_agb1:long_name = "Parameter 1 for agb allometry" ; + double fates_allom_agb2(fates_pft) ; + fates_allom_agb2:units = "variable" ; + fates_allom_agb2:long_name = "Parameter 2 for agb allometry" ; + double fates_allom_agb3(fates_pft) ; + fates_allom_agb3:units = "variable" ; + fates_allom_agb3:long_name = "Parameter 3 for agb allometry" ; + double fates_allom_agb4(fates_pft) ; + fates_allom_agb4:units = "variable" ; + fates_allom_agb4:long_name = "Parameter 4 for agb allometry" ; + double fates_allom_agb_frac(fates_pft) ; + fates_allom_agb_frac:units = "fraction" ; + fates_allom_agb_frac:long_name = "Fraction of woody biomass that is above ground" ; + double fates_allom_amode(fates_pft) ; + fates_allom_amode:units = "index" ; + fates_allom_amode:long_name = "AGB allometry function index." ; + double fates_allom_blca_expnt_diff(fates_pft) ; + fates_allom_blca_expnt_diff:units = "unitless" ; + fates_allom_blca_expnt_diff:long_name = "difference between allometric DBH:bleaf and DBH:crown area exponents" ; + double fates_allom_cmode(fates_pft) ; + fates_allom_cmode:units = "index" ; + fates_allom_cmode:long_name = "coarse root biomass allometry function index." ; + double fates_allom_crown_depth_frac(fates_pft) ; + fates_allom_crown_depth_frac:units = "fraction" ; + fates_allom_crown_depth_frac:long_name = "the depth of a cohort crown as a fraction of its height" ; + double fates_allom_d2bl1(fates_pft) ; + fates_allom_d2bl1:units = "variable" ; + fates_allom_d2bl1:long_name = "Parameter 1 for d2bl allometry" ; + double fates_allom_d2bl2(fates_pft) ; + fates_allom_d2bl2:units = "variable" ; + fates_allom_d2bl2:long_name = "Parameter 2 for d2bl allometry" ; + double fates_allom_d2bl3(fates_pft) ; + fates_allom_d2bl3:units = "unitless" ; + fates_allom_d2bl3:long_name = "Parameter 3 for d2bl allometry" ; + double fates_allom_d2ca_coefficient_max(fates_pft) ; + fates_allom_d2ca_coefficient_max:units = "m2 cm^(-1/beta)" ; + fates_allom_d2ca_coefficient_max:long_name = "max (savanna) dbh to area multiplier factor where: area = n*d2ca_coeff*dbh^beta" ; + double fates_allom_d2ca_coefficient_min(fates_pft) ; + fates_allom_d2ca_coefficient_min:units = "m2 cm^(-1/beta)" ; + fates_allom_d2ca_coefficient_min:long_name = "min (forest) dbh to area multiplier factor where: area = n*d2ca_coeff*dbh^beta" ; + double fates_allom_d2h1(fates_pft) ; + fates_allom_d2h1:units = "variable" ; + fates_allom_d2h1:long_name = "Parameter 1 for d2h allometry (intercept, or c)" ; + double fates_allom_d2h2(fates_pft) ; + fates_allom_d2h2:units = "variable" ; + fates_allom_d2h2:long_name = "Parameter 2 for d2h allometry (slope, or m)" ; + double fates_allom_d2h3(fates_pft) ; + fates_allom_d2h3:units = "variable" ; + fates_allom_d2h3:long_name = "Parameter 3 for d2h allometry (optional)" ; + double fates_allom_dbh_maxheight(fates_pft) ; + fates_allom_dbh_maxheight:units = "cm" ; + fates_allom_dbh_maxheight:long_name = "the diameter (if any) corresponding to maximum height, diameters may increase beyond this" ; + double fates_allom_fmode(fates_pft) ; + fates_allom_fmode:units = "index" ; + fates_allom_fmode:long_name = "fine root biomass allometry function index." ; + double fates_allom_fnrt_prof_a(fates_pft) ; + fates_allom_fnrt_prof_a:units = "unitless" ; + fates_allom_fnrt_prof_a:long_name = "Fine root profile function, parameter a" ; + double fates_allom_fnrt_prof_b(fates_pft) ; + fates_allom_fnrt_prof_b:units = "unitless" ; + fates_allom_fnrt_prof_b:long_name = "Fine root profile function, parameter b" ; + double fates_allom_fnrt_prof_mode(fates_pft) ; + fates_allom_fnrt_prof_mode:units = "index" ; + fates_allom_fnrt_prof_mode:long_name = "Index to select fine root profile function: 1) Jackson Beta, 2) 1-param exponential 3) 2-param exponential" ; + double fates_allom_frbstor_repro(fates_pft) ; + fates_allom_frbstor_repro:units = "fraction" ; + fates_allom_frbstor_repro:long_name = "fraction of bstore goes to reproduction after plant dies" ; + double fates_allom_hmode(fates_pft) ; + fates_allom_hmode:units = "index" ; + fates_allom_hmode:long_name = "height allometry function index." ; + double fates_allom_l2fr(fates_pft) ; + fates_allom_l2fr:units = "gC/gC" ; + fates_allom_l2fr:long_name = "Allocation parameter: fine root C per leaf C" ; + double fates_allom_la_per_sa_int(fates_pft) ; + fates_allom_la_per_sa_int:units = "m2/cm2" ; + fates_allom_la_per_sa_int:long_name = "Leaf area per sapwood area, intercept" ; + double fates_allom_la_per_sa_slp(fates_pft) ; + fates_allom_la_per_sa_slp:units = "m2/cm2/m" ; + fates_allom_la_per_sa_slp:long_name = "Leaf area per sapwood area rate of change with height, slope (optional)" ; + double fates_allom_lmode(fates_pft) ; + fates_allom_lmode:units = "index" ; + fates_allom_lmode:long_name = "leaf biomass allometry function index." ; + double fates_allom_sai_scaler(fates_pft) ; + fates_allom_sai_scaler:units = "m2/m2" ; + fates_allom_sai_scaler:long_name = "allometric ratio of SAI per LAI" ; + double fates_allom_smode(fates_pft) ; + fates_allom_smode:units = "index" ; + fates_allom_smode:long_name = "sapwood allometry function index." ; + double fates_allom_stmode(fates_pft) ; + fates_allom_stmode:units = "index" ; + fates_allom_stmode:long_name = "storage allometry function index: 1) Storage proportional to leaf biomass (with trimming), 2) Storage proportional to maximum leaf biomass (not trimmed)" ; + double fates_allom_zroot_k(fates_pft) ; + fates_allom_zroot_k:units = "unitless" ; + fates_allom_zroot_k:long_name = "scale coefficient of logistic rooting depth model" ; + double fates_allom_zroot_max_dbh(fates_pft) ; + fates_allom_zroot_max_dbh:units = "cm" ; + fates_allom_zroot_max_dbh:long_name = "dbh at which a plant reaches the maximum value for its maximum rooting depth" ; + double fates_allom_zroot_max_z(fates_pft) ; + fates_allom_zroot_max_z:units = "m" ; + fates_allom_zroot_max_z:long_name = "the maximum rooting depth defined at dbh = fates_allom_zroot_max_dbh. note: max_z=min_z=large, sets rooting depth to soil depth" ; + double fates_allom_zroot_min_dbh(fates_pft) ; + fates_allom_zroot_min_dbh:units = "cm" ; + fates_allom_zroot_min_dbh:long_name = "dbh at which the maximum rooting depth for a recruit is defined" ; + double fates_allom_zroot_min_z(fates_pft) ; + fates_allom_zroot_min_z:units = "m" ; + fates_allom_zroot_min_z:long_name = "the maximum rooting depth defined at dbh = fates_allom_zroot_min_dbh. note: max_z=min_z=large, sets rooting depth to soil depth" ; + double fates_c2b(fates_pft) ; + fates_c2b:units = "ratio" ; + fates_c2b:long_name = "Carbon to biomass multiplier of bulk structural tissues" ; + double fates_cnp_eca_alpha_ptase(fates_pft) ; + fates_cnp_eca_alpha_ptase:units = "g/m3" ; + fates_cnp_eca_alpha_ptase:long_name = "fraction of P from ptase activity sent directly to plant (ECA)" ; + double fates_cnp_eca_decompmicc(fates_pft) ; + fates_cnp_eca_decompmicc:units = "gC/m3" ; + fates_cnp_eca_decompmicc:long_name = "maximum soil microbial decomposer biomass found over depth (will be applied at a reference depth w/ exponential attenuation) (ECA)" ; + double fates_cnp_eca_km_nh4(fates_pft) ; + fates_cnp_eca_km_nh4:units = "gN/m3" ; + fates_cnp_eca_km_nh4:long_name = "half-saturation constant for plant nh4 uptake (ECA)" ; + double fates_cnp_eca_km_no3(fates_pft) ; + fates_cnp_eca_km_no3:units = "gN/m3" ; + fates_cnp_eca_km_no3:long_name = "half-saturation constant for plant no3 uptake (ECA)" ; + double fates_cnp_eca_km_p(fates_pft) ; + fates_cnp_eca_km_p:units = "gP/m3" ; + fates_cnp_eca_km_p:long_name = "half-saturation constant for plant p uptake (ECA)" ; + double fates_cnp_eca_km_ptase(fates_pft) ; + fates_cnp_eca_km_ptase:units = "gP/m3" ; + fates_cnp_eca_km_ptase:long_name = "half-saturation constant for biochemical P (ECA)" ; + double fates_cnp_eca_lambda_ptase(fates_pft) ; + fates_cnp_eca_lambda_ptase:units = "g/m3" ; + fates_cnp_eca_lambda_ptase:long_name = "critical value for biochemical production (ECA)" ; + double fates_cnp_eca_vmax_ptase(fates_pft) ; + fates_cnp_eca_vmax_ptase:units = "gP/m2/s" ; + fates_cnp_eca_vmax_ptase:long_name = "maximum production rate for biochemical P (per m2) (ECA)" ; + double fates_cnp_nfix1(fates_pft) ; + fates_cnp_nfix1:units = "fraction" ; + fates_cnp_nfix1:long_name = "fractional surcharge added to maintenance respiration that drives symbiotic fixation" ; + double fates_cnp_nitr_store_ratio(fates_pft) ; + fates_cnp_nitr_store_ratio:units = "(gN/gN)" ; + fates_cnp_nitr_store_ratio:long_name = "storeable (labile) N, as a ratio compared to the N bound in cell structures of other organs (see code)" ; + double fates_cnp_phos_store_ratio(fates_pft) ; + fates_cnp_phos_store_ratio:units = "(gP/gP)" ; + fates_cnp_phos_store_ratio:long_name = "storeable (labile) P, as a ratio compared to the P bound in cell structures of other organs (see code)" ; + double fates_cnp_pid_kd(fates_pft) ; + fates_cnp_pid_kd:units = "unknown" ; + fates_cnp_pid_kd:long_name = "derivative constant of the PID controller on adaptive fine-root biomass" ; + double fates_cnp_pid_ki(fates_pft) ; + fates_cnp_pid_ki:units = "unknown" ; + fates_cnp_pid_ki:long_name = "integral constant of the PID controller on adaptive fine-root biomass" ; + double fates_cnp_pid_kp(fates_pft) ; + fates_cnp_pid_kp:units = "unknown" ; + fates_cnp_pid_kp:long_name = "proportional constant of the PID controller on adaptive fine-root biomass" ; + double fates_cnp_prescribed_nuptake(fates_pft) ; + fates_cnp_prescribed_nuptake:units = "fraction" ; + fates_cnp_prescribed_nuptake:long_name = "Prescribed N uptake flux. 0=fully coupled simulation >0=prescribed (experimental)" ; + double fates_cnp_prescribed_puptake(fates_pft) ; + fates_cnp_prescribed_puptake:units = "fraction" ; + fates_cnp_prescribed_puptake:long_name = "Prescribed P uptake flux. 0=fully coupled simulation, >0=prescribed (experimental)" ; + double fates_cnp_store_ovrflw_frac(fates_pft) ; + fates_cnp_store_ovrflw_frac:units = "fraction" ; + fates_cnp_store_ovrflw_frac:long_name = "size of overflow storage (for excess C,N or P) as a fraction of storage target" ; + double fates_cnp_turnover_nitr_retrans(fates_plant_organs, fates_pft) ; + fates_cnp_turnover_nitr_retrans:units = "fraction" ; + fates_cnp_turnover_nitr_retrans:long_name = "retranslocation (reabsorbtion) fraction of nitrogen in turnover of scenescing tissues" ; + double fates_cnp_turnover_phos_retrans(fates_plant_organs, fates_pft) ; + fates_cnp_turnover_phos_retrans:units = "fraction" ; + fates_cnp_turnover_phos_retrans:long_name = "retranslocation (reabsorbtion) fraction of phosphorus in turnover of scenescing tissues" ; + double fates_cnp_vmax_nh4(fates_pft) ; + fates_cnp_vmax_nh4:units = "gN/gC/s" ; + fates_cnp_vmax_nh4:long_name = "maximum (potential) uptake rate of NH4 per gC of fineroot biomass (see main/EDPftvarcon.F90 vmax_nh4 for usage)" ; + double fates_cnp_vmax_no3(fates_pft) ; + fates_cnp_vmax_no3:units = "gN/gC/s" ; + fates_cnp_vmax_no3:long_name = "maximum (potential) uptake rate of NO3 per gC of fineroot biomass (see main/EDPftvarcon.F90 vmax_no3 for usage)" ; + double fates_cnp_vmax_p(fates_pft) ; + fates_cnp_vmax_p:units = "gP/gC/s" ; + fates_cnp_vmax_p:long_name = "maximum production rate for phosphorus (ECA and RD)" ; + double fates_damage_frac(fates_pft) ; + fates_damage_frac:units = "fraction" ; + fates_damage_frac:long_name = "fraction of cohort damaged in each damage event (event frequency specified in the is_it_damage_time subroutine)" ; + double fates_damage_mort_p1(fates_pft) ; + fates_damage_mort_p1:units = "fraction" ; + fates_damage_mort_p1:long_name = "inflection point of damage mortality function, a value of 0.8 means 50% mortality with 80% loss of crown, turn off with a large number" ; + double fates_damage_mort_p2(fates_pft) ; + fates_damage_mort_p2:units = "unitless" ; + fates_damage_mort_p2:long_name = "rate of mortality increase with damage" ; + double fates_damage_recovery_scalar(fates_pft) ; + fates_damage_recovery_scalar:units = "unitless" ; + fates_damage_recovery_scalar:long_name = "fraction of the cohort that recovers from damage" ; + double fates_dev_arbitrary_pft(fates_pft) ; + fates_dev_arbitrary_pft:units = "unknown" ; + fates_dev_arbitrary_pft:long_name = "Unassociated pft dimensioned free parameter that developers can use for testing arbitrary new hypotheses" ; + double fates_fire_alpha_SH(fates_pft) ; + fates_fire_alpha_SH:units = "m / (kw/m)**(2/3)" ; + fates_fire_alpha_SH:long_name = "spitfire parameter, alpha scorch height, Equation 16 Thonicke et al 2010" ; + double fates_fire_bark_scaler(fates_pft) ; + fates_fire_bark_scaler:units = "fraction" ; + fates_fire_bark_scaler:long_name = "the thickness of a cohorts bark as a fraction of its dbh" ; + double fates_fire_crown_kill(fates_pft) ; + fates_fire_crown_kill:units = "NA" ; + fates_fire_crown_kill:long_name = "fire parameter, see equation 22 in Thonicke et al 2010" ; + double fates_frag_fnrt_fcel(fates_pft) ; + fates_frag_fnrt_fcel:units = "fraction" ; + fates_frag_fnrt_fcel:long_name = "Fine root litter cellulose fraction" ; + double fates_frag_fnrt_flab(fates_pft) ; + fates_frag_fnrt_flab:units = "fraction" ; + fates_frag_fnrt_flab:long_name = "Fine root litter labile fraction" ; + double fates_frag_fnrt_flig(fates_pft) ; + fates_frag_fnrt_flig:units = "fraction" ; + fates_frag_fnrt_flig:long_name = "Fine root litter lignin fraction" ; + double fates_frag_leaf_fcel(fates_pft) ; + fates_frag_leaf_fcel:units = "fraction" ; + fates_frag_leaf_fcel:long_name = "Leaf litter cellulose fraction" ; + double fates_frag_leaf_flab(fates_pft) ; + fates_frag_leaf_flab:units = "fraction" ; + fates_frag_leaf_flab:long_name = "Leaf litter labile fraction" ; + double fates_frag_leaf_flig(fates_pft) ; + fates_frag_leaf_flig:units = "fraction" ; + fates_frag_leaf_flig:long_name = "Leaf litter lignin fraction" ; + double fates_frag_seed_decay_rate(fates_pft) ; + fates_frag_seed_decay_rate:units = "yr-1" ; + fates_frag_seed_decay_rate:long_name = "fraction of seeds that decay per year" ; + double fates_grperc(fates_pft) ; + fates_grperc:units = "unitless" ; + fates_grperc:long_name = "Growth respiration factor" ; + double fates_hydro_avuln_gs(fates_pft) ; + fates_hydro_avuln_gs:units = "unitless" ; + fates_hydro_avuln_gs:long_name = "shape parameter for stomatal control of water vapor exiting leaf" ; + double fates_hydro_avuln_node(fates_hydr_organs, fates_pft) ; + fates_hydro_avuln_node:units = "unitless" ; + fates_hydro_avuln_node:long_name = "xylem vulnerability curve shape parameter" ; + double fates_hydro_epsil_node(fates_hydr_organs, fates_pft) ; + fates_hydro_epsil_node:units = "MPa" ; + fates_hydro_epsil_node:long_name = "bulk elastic modulus" ; + double fates_hydro_fcap_node(fates_hydr_organs, fates_pft) ; + fates_hydro_fcap_node:units = "unitless" ; + fates_hydro_fcap_node:long_name = "fraction of non-residual water that is capillary in source" ; + double fates_hydro_k_lwp(fates_pft) ; + fates_hydro_k_lwp:units = "unitless" ; + fates_hydro_k_lwp:long_name = "inner leaf humidity scaling coefficient" ; + double fates_hydro_kmax_node(fates_hydr_organs, fates_pft) ; + fates_hydro_kmax_node:units = "kg/MPa/m/s" ; + fates_hydro_kmax_node:long_name = "maximum xylem conductivity per unit conducting xylem area" ; + double fates_hydro_p50_gs(fates_pft) ; + fates_hydro_p50_gs:units = "MPa" ; + fates_hydro_p50_gs:long_name = "water potential at 50% loss of stomatal conductance" ; + double fates_hydro_p50_node(fates_hydr_organs, fates_pft) ; + fates_hydro_p50_node:units = "MPa" ; + fates_hydro_p50_node:long_name = "xylem water potential at 50% loss of conductivity" ; + double fates_hydro_p_taper(fates_pft) ; + fates_hydro_p_taper:units = "unitless" ; + fates_hydro_p_taper:long_name = "xylem taper exponent" ; + double fates_hydro_pinot_node(fates_hydr_organs, fates_pft) ; + fates_hydro_pinot_node:units = "MPa" ; + fates_hydro_pinot_node:long_name = "osmotic potential at full turgor" ; + double fates_hydro_pitlp_node(fates_hydr_organs, fates_pft) ; + fates_hydro_pitlp_node:units = "MPa" ; + fates_hydro_pitlp_node:long_name = "turgor loss point" ; + double fates_hydro_resid_node(fates_hydr_organs, fates_pft) ; + fates_hydro_resid_node:units = "cm3/cm3" ; + fates_hydro_resid_node:long_name = "residual water conent" ; + double fates_hydro_rfrac_stem(fates_pft) ; + fates_hydro_rfrac_stem:units = "fraction" ; + fates_hydro_rfrac_stem:long_name = "fraction of total tree resistance from troot to canopy" ; + double fates_hydro_rs2(fates_pft) ; + fates_hydro_rs2:units = "m" ; + fates_hydro_rs2:long_name = "absorbing root radius" ; + double fates_hydro_srl(fates_pft) ; + fates_hydro_srl:units = "m g-1" ; + fates_hydro_srl:long_name = "specific root length" ; + double fates_hydro_thetas_node(fates_hydr_organs, fates_pft) ; + fates_hydro_thetas_node:units = "cm3/cm3" ; + fates_hydro_thetas_node:long_name = "saturated water content" ; + double fates_hydro_vg_alpha_node(fates_hydr_organs, fates_pft) ; + fates_hydro_vg_alpha_node:units = "MPa-1" ; + fates_hydro_vg_alpha_node:long_name = "(used if hydr_htftype_node = 2), capillary length parameter in van Genuchten model" ; + double fates_hydro_vg_m_node(fates_hydr_organs, fates_pft) ; + fates_hydro_vg_m_node:units = "unitless" ; + fates_hydro_vg_m_node:long_name = "(used if hydr_htftype_node = 2),m in van Genuchten 1980 model, 2nd pore size distribution parameter" ; + double fates_hydro_vg_n_node(fates_hydr_organs, fates_pft) ; + fates_hydro_vg_n_node:units = "unitless" ; + fates_hydro_vg_n_node:long_name = "(used if hydr_htftype_node = 2),n in van Genuchten 1980 model, pore size distribution parameter" ; + double fates_leaf_c3psn(fates_pft) ; + fates_leaf_c3psn:units = "flag" ; + fates_leaf_c3psn:long_name = "Photosynthetic pathway (1=c3, 0=c4)" ; + double fates_leaf_jmaxha(fates_pft) ; + fates_leaf_jmaxha:units = "J/mol" ; + fates_leaf_jmaxha:long_name = "activation energy for jmax" ; + double fates_leaf_jmaxhd(fates_pft) ; + fates_leaf_jmaxhd:units = "J/mol" ; + fates_leaf_jmaxhd:long_name = "deactivation energy for jmax" ; + double fates_leaf_jmaxse(fates_pft) ; + fates_leaf_jmaxse:units = "J/mol/K" ; + fates_leaf_jmaxse:long_name = "entropy term for jmax" ; + double fates_leaf_slamax(fates_pft) ; + fates_leaf_slamax:units = "m^2/gC" ; + fates_leaf_slamax:long_name = "Maximum Specific Leaf Area (SLA), even if under a dense canopy" ; + double fates_leaf_slatop(fates_pft) ; + fates_leaf_slatop:units = "m^2/gC" ; + fates_leaf_slatop:long_name = "Specific Leaf Area (SLA) at top of canopy, projected area basis" ; + double fates_leaf_stomatal_intercept(fates_pft) ; + fates_leaf_stomatal_intercept:units = "umol H2O/m**2/s" ; + fates_leaf_stomatal_intercept:long_name = "Minimum unstressed stomatal conductance for Ball-Berry model and Medlyn model" ; + double fates_leaf_stomatal_slope_ballberry(fates_pft) ; + fates_leaf_stomatal_slope_ballberry:units = "unitless" ; + fates_leaf_stomatal_slope_ballberry:long_name = "stomatal slope parameter, as per Ball-Berry" ; + double fates_leaf_stomatal_slope_medlyn(fates_pft) ; + fates_leaf_stomatal_slope_medlyn:units = "KPa**0.5" ; + fates_leaf_stomatal_slope_medlyn:long_name = "stomatal slope parameter, as per Medlyn" ; + double fates_leaf_vcmax25top(fates_leafage_class, fates_pft) ; + fates_leaf_vcmax25top:units = "umol CO2/m^2/s" ; + fates_leaf_vcmax25top:long_name = "maximum carboxylation rate of Rub. at 25C, canopy top" ; + double fates_leaf_vcmaxha(fates_pft) ; + fates_leaf_vcmaxha:units = "J/mol" ; + fates_leaf_vcmaxha:long_name = "activation energy for vcmax" ; + double fates_leaf_vcmaxhd(fates_pft) ; + fates_leaf_vcmaxhd:units = "J/mol" ; + fates_leaf_vcmaxhd:long_name = "deactivation energy for vcmax" ; + double fates_leaf_vcmaxse(fates_pft) ; + fates_leaf_vcmaxse:units = "J/mol/K" ; + fates_leaf_vcmaxse:long_name = "entropy term for vcmax" ; + double fates_maintresp_reduction_curvature(fates_pft) ; + fates_maintresp_reduction_curvature:units = "unitless (0-1)" ; + fates_maintresp_reduction_curvature:long_name = "curvature of MR reduction as f(carbon storage), 1=linear, 0=very curved" ; + double fates_maintresp_reduction_intercept(fates_pft) ; + fates_maintresp_reduction_intercept:units = "unitless (0-1)" ; + fates_maintresp_reduction_intercept:long_name = "intercept of MR reduction as f(carbon storage), 0=no throttling, 1=max throttling" ; + double fates_mort_bmort(fates_pft) ; + fates_mort_bmort:units = "1/yr" ; + fates_mort_bmort:long_name = "background mortality rate" ; + double fates_mort_freezetol(fates_pft) ; + fates_mort_freezetol:units = "degrees C" ; + fates_mort_freezetol:long_name = "minimum temperature tolerance" ; + double fates_mort_hf_flc_threshold(fates_pft) ; + fates_mort_hf_flc_threshold:units = "fraction" ; + fates_mort_hf_flc_threshold:long_name = "plant fractional loss of conductivity at which drought mortality begins for hydraulic model" ; + double fates_mort_hf_sm_threshold(fates_pft) ; + fates_mort_hf_sm_threshold:units = "unitless" ; + fates_mort_hf_sm_threshold:long_name = "soil moisture (btran units) at which drought mortality begins for non-hydraulic model" ; + double fates_mort_ip_age_senescence(fates_pft) ; + fates_mort_ip_age_senescence:units = "years" ; + fates_mort_ip_age_senescence:long_name = "Mortality cohort age senescence inflection point. If _ this mortality term is off. Setting this value turns on age dependent mortality. " ; + double fates_mort_ip_size_senescence(fates_pft) ; + fates_mort_ip_size_senescence:units = "dbh cm" ; + fates_mort_ip_size_senescence:long_name = "Mortality dbh senescence inflection point. If _ this mortality term is off. Setting this value turns on size dependent mortality" ; + double fates_mort_prescribed_canopy(fates_pft) ; + fates_mort_prescribed_canopy:units = "1/yr" ; + fates_mort_prescribed_canopy:long_name = "mortality rate of canopy trees for prescribed physiology mode" ; + double fates_mort_prescribed_understory(fates_pft) ; + fates_mort_prescribed_understory:units = "1/yr" ; + fates_mort_prescribed_understory:long_name = "mortality rate of understory trees for prescribed physiology mode" ; + double fates_mort_r_age_senescence(fates_pft) ; + fates_mort_r_age_senescence:units = "mortality rate year^-1" ; + fates_mort_r_age_senescence:long_name = "Mortality age senescence rate of change. Sensible range is around 0.03-0.06. Larger values givesteeper mortality curves." ; + double fates_mort_r_size_senescence(fates_pft) ; + fates_mort_r_size_senescence:units = "mortality rate dbh^-1" ; + fates_mort_r_size_senescence:long_name = "Mortality dbh senescence rate of change. Sensible range is around 0.03-0.06. Larger values give steeper mortality curves." ; + double fates_mort_scalar_coldstress(fates_pft) ; + fates_mort_scalar_coldstress:units = "1/yr" ; + fates_mort_scalar_coldstress:long_name = "maximum mortality rate from cold stress" ; + double fates_mort_scalar_cstarvation(fates_pft) ; + fates_mort_scalar_cstarvation:units = "1/yr" ; + fates_mort_scalar_cstarvation:long_name = "maximum mortality rate from carbon starvation" ; + double fates_mort_scalar_hydrfailure(fates_pft) ; + fates_mort_scalar_hydrfailure:units = "1/yr" ; + fates_mort_scalar_hydrfailure:long_name = "maximum mortality rate from hydraulic failure" ; + double fates_nonhydro_smpsc(fates_pft) ; + fates_nonhydro_smpsc:units = "mm" ; + fates_nonhydro_smpsc:long_name = "Soil water potential at full stomatal closure" ; + double fates_nonhydro_smpso(fates_pft) ; + fates_nonhydro_smpso:units = "mm" ; + fates_nonhydro_smpso:long_name = "Soil water potential at full stomatal opening" ; + double fates_phen_cold_size_threshold(fates_pft) ; + fates_phen_cold_size_threshold:units = "cm" ; + fates_phen_cold_size_threshold:long_name = "the dbh size above which will lead to phenology-related stem and leaf drop" ; + double fates_phen_evergreen(fates_pft) ; + fates_phen_evergreen:units = "logical flag" ; + fates_phen_evergreen:long_name = "Binary flag for evergreen leaf habit" ; + double fates_phen_flush_fraction(fates_pft) ; + fates_phen_flush_fraction:units = "fraction" ; + fates_phen_flush_fraction:long_name = "Upon bud-burst, the maximum fraction of storage carbon used for flushing leaves" ; + double fates_phen_fnrt_drop_frac(fates_pft) ; + fates_phen_fnrt_drop_frac:units = "fraction" ; + fates_phen_fnrt_drop_frac:long_name = "fraction of fine roots to drop during drought or cold" ; + double fates_phen_season_decid(fates_pft) ; + fates_phen_season_decid:units = "logical flag" ; + fates_phen_season_decid:long_name = "Binary flag for seasonal-deciduous leaf habit" ; + double fates_phen_stem_drop_fraction(fates_pft) ; + fates_phen_stem_drop_fraction:units = "fraction" ; + fates_phen_stem_drop_fraction:long_name = "fraction of stems to drop for non-woody species during drought/cold" ; + double fates_phen_stress_decid(fates_pft) ; + fates_phen_stress_decid:units = "logical flag" ; + fates_phen_stress_decid:long_name = "Binary flag for stress-deciduous leaf habit" ; + double fates_prescribed_npp_canopy(fates_pft) ; + fates_prescribed_npp_canopy:units = "kgC / m^2 / yr" ; + fates_prescribed_npp_canopy:long_name = "NPP per unit crown area of canopy trees for prescribed physiology mode" ; + double fates_prescribed_npp_understory(fates_pft) ; + fates_prescribed_npp_understory:units = "kgC / m^2 / yr" ; + fates_prescribed_npp_understory:long_name = "NPP per unit crown area of understory trees for prescribed physiology mode" ; + double fates_rad_leaf_clumping_index(fates_pft) ; + fates_rad_leaf_clumping_index:units = "fraction (0-1)" ; + fates_rad_leaf_clumping_index:long_name = "factor describing how much self-occlusion of leaf scattering elements decreases light interception" ; + double fates_rad_leaf_rhonir(fates_pft) ; + fates_rad_leaf_rhonir:units = "fraction" ; + fates_rad_leaf_rhonir:long_name = "Leaf reflectance: near-IR" ; + double fates_rad_leaf_rhovis(fates_pft) ; + fates_rad_leaf_rhovis:units = "fraction" ; + fates_rad_leaf_rhovis:long_name = "Leaf reflectance: visible" ; + double fates_rad_leaf_taunir(fates_pft) ; + fates_rad_leaf_taunir:units = "fraction" ; + fates_rad_leaf_taunir:long_name = "Leaf transmittance: near-IR" ; + double fates_rad_leaf_tauvis(fates_pft) ; + fates_rad_leaf_tauvis:units = "fraction" ; + fates_rad_leaf_tauvis:long_name = "Leaf transmittance: visible" ; + double fates_rad_leaf_xl(fates_pft) ; + fates_rad_leaf_xl:units = "unitless" ; + fates_rad_leaf_xl:long_name = "Leaf/stem orientation index" ; + double fates_rad_stem_rhonir(fates_pft) ; + fates_rad_stem_rhonir:units = "fraction" ; + fates_rad_stem_rhonir:long_name = "Stem reflectance: near-IR" ; + double fates_rad_stem_rhovis(fates_pft) ; + fates_rad_stem_rhovis:units = "fraction" ; + fates_rad_stem_rhovis:long_name = "Stem reflectance: visible" ; + double fates_rad_stem_taunir(fates_pft) ; + fates_rad_stem_taunir:units = "fraction" ; + fates_rad_stem_taunir:long_name = "Stem transmittance: near-IR" ; + double fates_rad_stem_tauvis(fates_pft) ; + fates_rad_stem_tauvis:units = "fraction" ; + fates_rad_stem_tauvis:long_name = "Stem transmittance: visible" ; + double fates_recruit_height_min(fates_pft) ; + fates_recruit_height_min:units = "m" ; + fates_recruit_height_min:long_name = "the minimum height (ie starting height) of a newly recruited plant" ; + double fates_recruit_init_density(fates_pft) ; + fates_recruit_init_density:units = "stems/m2" ; + fates_recruit_init_density:long_name = "initial seedling density for a cold-start near-bare-ground simulation" ; + double fates_recruit_prescribed_rate(fates_pft) ; + fates_recruit_prescribed_rate:units = "n/yr" ; + fates_recruit_prescribed_rate:long_name = "recruitment rate for prescribed physiology mode" ; + double fates_recruit_seed_alloc(fates_pft) ; + fates_recruit_seed_alloc:units = "fraction" ; + fates_recruit_seed_alloc:long_name = "fraction of available carbon balance allocated to seeds" ; + double fates_recruit_seed_alloc_mature(fates_pft) ; + fates_recruit_seed_alloc_mature:units = "fraction" ; + fates_recruit_seed_alloc_mature:long_name = "fraction of available carbon balance allocated to seeds in mature plants (adds to fates_seed_alloc)" ; + double fates_recruit_seed_dbh_repro_threshold(fates_pft) ; + fates_recruit_seed_dbh_repro_threshold:units = "cm" ; + fates_recruit_seed_dbh_repro_threshold:long_name = "the diameter where the plant will increase allocation to the seed pool by fraction: fates_recruit_seed_alloc_mature" ; + double fates_recruit_seed_germination_rate(fates_pft) ; + fates_recruit_seed_germination_rate:units = "yr-1" ; + fates_recruit_seed_germination_rate:long_name = "fraction of seeds that germinate per year" ; + double fates_recruit_seed_supplement(fates_pft) ; + fates_recruit_seed_supplement:units = "KgC/m2/yr" ; + fates_recruit_seed_supplement:long_name = "Supplemental external seed rain source term (non-mass conserving)" ; + double fates_stoich_nitr(fates_plant_organs, fates_pft) ; + fates_stoich_nitr:units = "gN/gC" ; + fates_stoich_nitr:long_name = "target nitrogen concentration (ratio with carbon) of organs" ; + double fates_stoich_phos(fates_plant_organs, fates_pft) ; + fates_stoich_phos:units = "gP/gC" ; + fates_stoich_phos:long_name = "target phosphorus concentration (ratio with carbon) of organs" ; + double fates_trim_inc(fates_pft) ; + fates_trim_inc:units = "m2/m2" ; + fates_trim_inc:long_name = "Arbitrary incremental change in trimming function." ; + double fates_trim_limit(fates_pft) ; + fates_trim_limit:units = "m2/m2" ; + fates_trim_limit:long_name = "Arbitrary limit to reductions in leaf area with stress" ; + double fates_turb_displar(fates_pft) ; + fates_turb_displar:units = "unitless" ; + fates_turb_displar:long_name = "Ratio of displacement height to canopy top height" ; + double fates_turb_leaf_diameter(fates_pft) ; + fates_turb_leaf_diameter:units = "m" ; + fates_turb_leaf_diameter:long_name = "Characteristic leaf dimension" ; + double fates_turb_z0mr(fates_pft) ; + fates_turb_z0mr:units = "unitless" ; + fates_turb_z0mr:long_name = "Ratio of momentum roughness length to canopy top height" ; + double fates_turnover_branch(fates_pft) ; + fates_turnover_branch:units = "yr" ; + fates_turnover_branch:long_name = "turnover time of branches" ; + double fates_turnover_fnrt(fates_pft) ; + fates_turnover_fnrt:units = "yr" ; + fates_turnover_fnrt:long_name = "root longevity (alternatively, turnover time)" ; + double fates_turnover_leaf(fates_leafage_class, fates_pft) ; + fates_turnover_leaf:units = "yr" ; + fates_turnover_leaf:long_name = "Leaf longevity (ie turnover timescale)" ; + double fates_turnover_senleaf_fdrought(fates_pft) ; + fates_turnover_senleaf_fdrought:units = "unitless[0-1]" ; + fates_turnover_senleaf_fdrought:long_name = "multiplication factor for leaf longevity of senescent leaves during drought" ; + double fates_wood_density(fates_pft) ; + fates_wood_density:units = "g/cm3" ; + fates_wood_density:long_name = "mean density of woody tissue in plant" ; + double fates_woody(fates_pft) ; + fates_woody:units = "logical flag" ; + fates_woody:long_name = "Binary woody lifeform flag" ; + double fates_hlm_pft_map(fates_hlm_pftno, fates_pft) ; + fates_hlm_pft_map:units = "area fraction" ; + fates_hlm_pft_map:long_name = "In fixed biogeog mode, fraction of HLM area associated with each FATES PFT" ; + double fates_fire_FBD(fates_litterclass) ; + fates_fire_FBD:units = "kg Biomass/m3" ; + fates_fire_FBD:long_name = "fuel bulk density" ; + double fates_fire_low_moisture_Coeff(fates_litterclass) ; + fates_fire_low_moisture_Coeff:units = "NA" ; + fates_fire_low_moisture_Coeff:long_name = "spitfire parameter, equation B1 Thonicke et al 2010" ; + double fates_fire_low_moisture_Slope(fates_litterclass) ; + fates_fire_low_moisture_Slope:units = "NA" ; + fates_fire_low_moisture_Slope:long_name = "spitfire parameter, equation B1 Thonicke et al 2010" ; + double fates_fire_mid_moisture(fates_litterclass) ; + fates_fire_mid_moisture:units = "NA" ; + fates_fire_mid_moisture:long_name = "spitfire litter moisture threshold to be considered medium dry" ; + double fates_fire_mid_moisture_Coeff(fates_litterclass) ; + fates_fire_mid_moisture_Coeff:units = "NA" ; + fates_fire_mid_moisture_Coeff:long_name = "spitfire parameter, equation B1 Thonicke et al 2010" ; + double fates_fire_mid_moisture_Slope(fates_litterclass) ; + fates_fire_mid_moisture_Slope:units = "NA" ; + fates_fire_mid_moisture_Slope:long_name = "spitfire parameter, equation B1 Thonicke et al 2010" ; + double fates_fire_min_moisture(fates_litterclass) ; + fates_fire_min_moisture:units = "NA" ; + fates_fire_min_moisture:long_name = "spitfire litter moisture threshold to be considered very dry" ; + double fates_fire_SAV(fates_litterclass) ; + fates_fire_SAV:units = "cm-1" ; + fates_fire_SAV:long_name = "fuel surface area to volume ratio" ; + double fates_frag_maxdecomp(fates_litterclass) ; + fates_frag_maxdecomp:units = "yr-1" ; + fates_frag_maxdecomp:long_name = "maximum rate of litter & CWD transfer from non-decomposing class into decomposing class" ; + double fates_frag_cwd_frac(fates_NCWD) ; + fates_frag_cwd_frac:units = "fraction" ; + fates_frag_cwd_frac:long_name = "fraction of woody (bdead+bsw) biomass destined for CWD pool" ; + double fates_base_mr_20 ; + fates_base_mr_20:units = "gC/gN/s" ; + fates_base_mr_20:long_name = "Base maintenance respiration rate for plant tissues, using Ryan 1991" ; + double fates_canopy_closure_thresh ; + fates_canopy_closure_thresh:units = "unitless" ; + fates_canopy_closure_thresh:long_name = "tree canopy coverage at which crown area allometry changes from savanna to forest value" ; + double fates_cnp_eca_plant_escalar ; + fates_cnp_eca_plant_escalar:units = "" ; + fates_cnp_eca_plant_escalar:long_name = "scaling factor for plant fine root biomass to calculate nutrient carrier enzyme abundance (ECA)" ; + double fates_cohort_age_fusion_tol ; + fates_cohort_age_fusion_tol:units = "unitless" ; + fates_cohort_age_fusion_tol:long_name = "minimum fraction in differece in cohort age between cohorts." ; + double fates_cohort_size_fusion_tol ; + fates_cohort_size_fusion_tol:units = "unitless" ; + fates_cohort_size_fusion_tol:long_name = "minimum fraction in difference in dbh between cohorts" ; + double fates_comp_excln ; + fates_comp_excln:units = "none" ; + fates_comp_excln:long_name = "IF POSITIVE: weighting factor (exponent on dbh) for canopy layer exclusion and promotion, IF NEGATIVE: switch to use deterministic height sorting" ; + double fates_damage_canopy_layer_code ; + fates_damage_canopy_layer_code:units = "unitless" ; + fates_damage_canopy_layer_code:long_name = "Integer code that decides whether damage affects canopy trees (1), understory trees (2)" ; + double fates_damage_event_code ; + fates_damage_event_code:units = "unitless" ; + fates_damage_event_code:long_name = "Integer code that options how damage events are structured" ; + double fates_dev_arbitrary ; + fates_dev_arbitrary:units = "unknown" ; + fates_dev_arbitrary:long_name = "Unassociated free parameter that developers can use for testing arbitrary new hypotheses" ; + double fates_fire_active_crown_fire ; + fates_fire_active_crown_fire:units = "0 or 1" ; + fates_fire_active_crown_fire:long_name = "flag, 1=active crown fire 0=no active crown fire" ; + double fates_fire_cg_strikes ; + fates_fire_cg_strikes:units = "fraction (0-1)" ; + fates_fire_cg_strikes:long_name = "fraction of cloud to ground lightning strikes" ; + double fates_fire_drying_ratio ; + fates_fire_drying_ratio:units = "NA" ; + fates_fire_drying_ratio:long_name = "spitfire parameter, fire drying ratio for fuel moisture, alpha_FMC EQ 6 Thonicke et al 2010" ; + double fates_fire_durat_slope ; + fates_fire_durat_slope:units = "NA" ; + fates_fire_durat_slope:long_name = "spitfire parameter, fire max duration slope, Equation 14 Thonicke et al 2010" ; + double fates_fire_fdi_a ; + fates_fire_fdi_a:units = "NA" ; + fates_fire_fdi_a:long_name = "spitfire parameter, fire danger index, EQ 5 Thonicke et al 2010" ; + double fates_fire_fdi_alpha ; + fates_fire_fdi_alpha:units = "NA" ; + fates_fire_fdi_alpha:long_name = "spitfire parameter, EQ 7 Venevsky et al. GCB 2002,(modified EQ 8 Thonicke et al. 2010) " ; + double fates_fire_fdi_b ; + fates_fire_fdi_b:units = "NA" ; + fates_fire_fdi_b:long_name = "spitfire parameter, fire danger index, EQ 5 Thonicke et al 2010 " ; + double fates_fire_fuel_energy ; + fates_fire_fuel_energy:units = "kJ/kg" ; + fates_fire_fuel_energy:long_name = "spitfire parameter, heat content of fuel" ; + double fates_fire_max_durat ; + fates_fire_max_durat:units = "minutes" ; + fates_fire_max_durat:long_name = "spitfire parameter, fire maximum duration, Equation 14 Thonicke et al 2010" ; + double fates_fire_miner_damp ; + fates_fire_miner_damp:units = "NA" ; + fates_fire_miner_damp:long_name = "spitfire parameter, mineral-dampening coefficient EQ A1 Thonicke et al 2010 " ; + double fates_fire_miner_total ; + fates_fire_miner_total:units = "fraction" ; + fates_fire_miner_total:long_name = "spitfire parameter, total mineral content, Table A1 Thonicke et al 2010" ; + double fates_fire_nignitions ; + fates_fire_nignitions:units = "ignitions per year per km2" ; + fates_fire_nignitions:long_name = "number of annual ignitions per square km" ; + double fates_fire_part_dens ; + fates_fire_part_dens:units = "kg/m2" ; + fates_fire_part_dens:long_name = "spitfire parameter, oven dry particle density, Table A1 Thonicke et al 2010" ; + double fates_fire_threshold ; + fates_fire_threshold:units = "kW/m" ; + fates_fire_threshold:long_name = "spitfire parameter, fire intensity threshold for tracking fires that spread" ; + double fates_frag_cwd_fcel ; + fates_frag_cwd_fcel:units = "unitless" ; + fates_frag_cwd_fcel:long_name = "Cellulose fraction for CWD" ; + double fates_frag_cwd_flig ; + fates_frag_cwd_flig:units = "unitless" ; + fates_frag_cwd_flig:long_name = "Lignin fraction of coarse woody debris" ; + double fates_hydro_kmax_rsurf1 ; + fates_hydro_kmax_rsurf1:units = "kg water/m2 root area/Mpa/s" ; + fates_hydro_kmax_rsurf1:long_name = "maximum conducitivity for unit root surface (into root)" ; + double fates_hydro_kmax_rsurf2 ; + fates_hydro_kmax_rsurf2:units = "kg water/m2 root area/Mpa/s" ; + fates_hydro_kmax_rsurf2:long_name = "maximum conducitivity for unit root surface (out of root)" ; + double fates_hydro_psi0 ; + fates_hydro_psi0:units = "MPa" ; + fates_hydro_psi0:long_name = "sapwood water potential at saturation" ; + double fates_hydro_psicap ; + fates_hydro_psicap:units = "MPa" ; + fates_hydro_psicap:long_name = "sapwood water potential at which capillary reserves exhausted" ; + double fates_hydro_solver ; + fates_hydro_solver:units = "unitless" ; + fates_hydro_solver:long_name = "switch designating which numerical solver for plant hydraulics, 1 = 1D taylor, 2 = 2D Picard, 3 = 2D Newton (deprecated)" ; + double fates_landuse_logging_coll_under_frac ; + fates_landuse_logging_coll_under_frac:units = "fraction" ; + fates_landuse_logging_coll_under_frac:long_name = "Fraction of stems killed in the understory when logging generates disturbance" ; + double fates_landuse_logging_collateral_frac ; + fates_landuse_logging_collateral_frac:units = "fraction" ; + fates_landuse_logging_collateral_frac:long_name = "Fraction of large stems in upperstory that die from logging collateral damage" ; + double fates_landuse_logging_dbhmax ; + fates_landuse_logging_dbhmax:units = "cm" ; + fates_landuse_logging_dbhmax:long_name = "Maximum dbh below which logging is applied (unset values flag this to be unused)" ; + double fates_landuse_logging_dbhmax_infra ; + fates_landuse_logging_dbhmax_infra:units = "cm" ; + fates_landuse_logging_dbhmax_infra:long_name = "Tree diameter, above which infrastructure from logging does not impact damage or mortality." ; + double fates_landuse_logging_dbhmin ; + fates_landuse_logging_dbhmin:units = "cm" ; + fates_landuse_logging_dbhmin:long_name = "Minimum dbh at which logging is applied" ; + double fates_landuse_logging_direct_frac ; + fates_landuse_logging_direct_frac:units = "fraction" ; + fates_landuse_logging_direct_frac:long_name = "Fraction of stems logged directly per event" ; + double fates_landuse_logging_event_code ; + fates_landuse_logging_event_code:units = "unitless" ; + fates_landuse_logging_event_code:long_name = "Integer code that options how logging events are structured" ; + double fates_landuse_logging_export_frac ; + fates_landuse_logging_export_frac:units = "fraction" ; + fates_landuse_logging_export_frac:long_name = "fraction of trunk product being shipped offsite, the leftovers will be left onsite as large CWD" ; + double fates_landuse_logging_mechanical_frac ; + fates_landuse_logging_mechanical_frac:units = "fraction" ; + fates_landuse_logging_mechanical_frac:long_name = "Fraction of stems killed due infrastructure an other mechanical means" ; + double fates_landuse_pprodharv10_forest_mean ; + fates_landuse_pprodharv10_forest_mean:units = "fraction" ; + fates_landuse_pprodharv10_forest_mean:long_name = "mean harvest mortality proportion of deadstem to 10-yr product (pprodharv10) of all woody PFT types" ; + double fates_leaf_photo_temp_acclim_timescale ; + fates_leaf_photo_temp_acclim_timescale:units = "days" ; + fates_leaf_photo_temp_acclim_timescale:long_name = "Length of the window for the exponential moving average (ema) of vegetation temperature used in photosynthesis temperature acclimation (NOT USED)" ; + double fates_leaf_photo_tempsens_model ; + fates_leaf_photo_tempsens_model:units = "unitless" ; + fates_leaf_photo_tempsens_model:long_name = "switch for choosing the model that defines the temperature sensitivity of photosynthetic parameters (vcmax, jmax). 1=non-acclimating (NOT USED)" ; + double fates_leaf_stomatal_assim_model ; + fates_leaf_stomatal_assim_model:units = "unitless" ; + fates_leaf_stomatal_assim_model:long_name = "a switch designating whether to use net (1) or gross (2) assimilation in the stomatal model" ; + double fates_leaf_stomatal_model ; + fates_leaf_stomatal_model:units = "unitless" ; + fates_leaf_stomatal_model:long_name = "switch for choosing between Ball-Berry (1) stomatal conductance model and Medlyn (2) model" ; + double fates_leaf_theta_cj_c3 ; + fates_leaf_theta_cj_c3:units = "unitless" ; + fates_leaf_theta_cj_c3:long_name = "Empirical curvature parameter for ac, aj photosynthesis co-limitation in c3 plants" ; + double fates_leaf_theta_cj_c4 ; + fates_leaf_theta_cj_c4:units = "unitless" ; + fates_leaf_theta_cj_c4:long_name = "Empirical curvature parameter for ac, aj photosynthesis co-limitation in c4 plants" ; + double fates_maintresp_model ; + fates_maintresp_model:units = "unitless" ; + fates_maintresp_model:long_name = "switch for choosing between maintenance respiration models. 1=Ryan (1991) (NOT USED)" ; + double fates_maxcohort ; + fates_maxcohort:units = "count" ; + fates_maxcohort:long_name = "maximum number of cohorts per patch. Actual number of cohorts also depend on cohort fusion tolerances" ; + double fates_maxpatch_primary ; + fates_maxpatch_primary:units = "count" ; + fates_maxpatch_primary:long_name = "maximum number of primary vegetation patches per site" ; + double fates_maxpatch_secondary ; + fates_maxpatch_secondary:units = "count" ; + fates_maxpatch_secondary:long_name = "maximum number of secondary vegetation patches per site" ; + double fates_mort_disturb_frac ; + fates_mort_disturb_frac:units = "fraction" ; + fates_mort_disturb_frac:long_name = "fraction of canopy mortality that results in disturbance (i.e. transfer of area from new to old patch)" ; + double fates_mort_understorey_death ; + fates_mort_understorey_death:units = "fraction" ; + fates_mort_understorey_death:long_name = "fraction of plants in understorey cohort impacted by overstorey tree-fall" ; + double fates_patch_fusion_tol ; + fates_patch_fusion_tol:units = "unitless" ; + fates_patch_fusion_tol:long_name = "minimum fraction in difference in profiles between patches" ; + double fates_phen_chilltemp ; + fates_phen_chilltemp:units = "degrees C" ; + fates_phen_chilltemp:long_name = "chilling day counting threshold for vegetation" ; + double fates_phen_coldtemp ; + fates_phen_coldtemp:units = "degrees C" ; + fates_phen_coldtemp:long_name = "vegetation temperature exceedance that flags a cold-day for leaf-drop" ; + double fates_phen_drought_model ; + fates_phen_drought_model:units = "unitless" ; + fates_phen_drought_model:long_name = "which method to use for drought phenology: 0 - FATES default; 1 - Semi-deciduous (ED2-like)" ; + double fates_phen_drought_threshold ; + fates_phen_drought_threshold:units = "m3/m3 or mm" ; + fates_phen_drought_threshold:long_name = "threshold for drought phenology (or lower threshold when fates_phen_drought_model = 1); the quantity depends on the sign: if positive, the threshold is volumetric soil moisture (m3/m3). If negative, the threshold is soil matric potentical (mm)" ; + double fates_phen_gddthresh_a ; + fates_phen_gddthresh_a:units = "none" ; + fates_phen_gddthresh_a:long_name = "GDD accumulation function, intercept parameter: gdd_thesh = a + b exp(c*ncd)" ; + double fates_phen_gddthresh_b ; + fates_phen_gddthresh_b:units = "none" ; + fates_phen_gddthresh_b:long_name = "GDD accumulation function, multiplier parameter: gdd_thesh = a + b exp(c*ncd)" ; + double fates_phen_gddthresh_c ; + fates_phen_gddthresh_c:units = "none" ; + fates_phen_gddthresh_c:long_name = "GDD accumulation function, exponent parameter: gdd_thesh = a + b exp(c*ncd)" ; + double fates_phen_mindaysoff ; + fates_phen_mindaysoff:units = "days" ; + fates_phen_mindaysoff:long_name = "day threshold compared against days since leaves became off-allometry" ; + double fates_phen_mindayson ; + fates_phen_mindayson:units = "days" ; + fates_phen_mindayson:long_name = "day threshold compared against days since leaves became on-allometry" ; + double fates_phen_moist_threshold ; + fates_phen_moist_threshold:units = "m3/m3 or mm" ; + fates_phen_moist_threshold:long_name = "upper threshold for drought phenology (only for fates_phen_drought_model=1); the quantity depends on the sign: if positive, the threshold is volumetric soil moisture (m3/m3). If negative, the threshold is soil matric potentical (mm)" ; + double fates_phen_ncolddayslim ; + fates_phen_ncolddayslim:units = "days" ; + fates_phen_ncolddayslim:long_name = "day threshold exceedance for temperature leaf-drop" ; + double fates_q10_froz ; + fates_q10_froz:units = "unitless" ; + fates_q10_froz:long_name = "Q10 for frozen-soil respiration rates" ; + double fates_q10_mr ; + fates_q10_mr:units = "unitless" ; + fates_q10_mr:long_name = "Q10 for maintenance respiration" ; + double fates_soil_salinity ; + fates_soil_salinity:units = "ppt" ; + fates_soil_salinity:long_name = "soil salinity used for model when not coupled to dynamic soil salinity" ; + double fates_vai_top_bin_width ; + fates_vai_top_bin_width:units = "m2/m2" ; + fates_vai_top_bin_width:long_name = "width in VAI units of uppermost leaf+stem layer scattering element in each canopy layer" ; + double fates_vai_width_increase_factor ; + fates_vai_width_increase_factor:units = "unitless" ; + fates_vai_width_increase_factor:long_name = "factor by which each leaf+stem scattering element increases in VAI width (1 = uniform spacing)" ; + +// global attributes: + :history = "This file was generated by BatchPatchParams.py:\nCDL Base File = archive/api24.1.0_101722_fates_params_default.cdl\nXML patch file = archive/api24.1.0_101722_patch_params.xml" ; +data: + + fates_history_ageclass_bin_edges = 0, 1, 2, 5, 10, 20, 50 ; + + fates_history_coageclass_bin_edges = 0, 5 ; + + fates_history_height_bin_edges = 0, 0.1, 0.3, 1, 3, 10 ; + + fates_history_damage_bin_edges = 0, 80 ; + + fates_history_sizeclass_bin_edges = 0, 5, 10, 15, 20, 30, 40, 50, 60, 70, + 80, 90, 100 ; + + fates_alloc_organ_id = 1, 2, 3, 6 ; + + fates_hydro_htftype_node = 1, 1, 1, 1 ; + + fates_pftname = + "broadleaf_evergreen_tropical_tree ", + "needleleaf_evergreen_extratrop_tree ", + "needleleaf_colddecid_extratrop_tree ", + "broadleaf_evergreen_extratrop_tree ", + "broadleaf_hydrodecid_tropical_tree ", + "broadleaf_colddecid_extratrop_tree ", + "broadleaf_evergreen_extratrop_shrub ", + "broadleaf_hydrodecid_extratrop_shrub ", + "broadleaf_colddecid_extratrop_shrub ", + "arctic_c3_grass ", + "cool_c3_grass ", + "c4_grass " ; + + fates_hydro_organ_name = + "leaf ", + "stem ", + "transporting root ", + "absorbing root " ; + + fates_alloc_organ_name = + "leaf", + "fine root", + "sapwood", + "structure" ; + + fates_litterclass_name = + "twig ", + "small branch ", + "large branch ", + "trunk ", + "dead leaves ", + "live grass " ; + + fates_alloc_organ_priority = + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 ; + + fates_alloc_storage_cushion = 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, + 1.2, 1.2, 1.2 ; + + fates_alloc_store_priority_frac = 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, + 0.8, 0.8, 0.8, 0.8 ; + + fates_allom_agb1 = 0.06896, 0.06896, 0.06896, 0.06896, 0.06896, 0.06896, + 0.06896, 0.06896, 0.06896, 0.01, 0.01, 0.01 ; + + fates_allom_agb2 = 0.572, 0.572, 0.572, 0.572, 0.572, 0.572, 0.572, 0.572, + 0.572, 0.572, 0.572, 0.572 ; + + fates_allom_agb3 = 1.94, 1.94, 1.94, 1.94, 1.94, 1.94, 1.94, 1.94, 1.94, + 1.94, 1.94, 1.94 ; + + fates_allom_agb4 = 0.931, 0.931, 0.931, 0.931, 0.931, 0.931, 0.931, 0.931, + 0.931, 0.931, 0.931, 0.931 ; + + fates_allom_agb_frac = 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, + 0.6, 0.6 ; + + fates_allom_amode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_blca_expnt_diff = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_allom_cmode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_crown_depth_frac = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.95, 0.95, + 0.95, 1, 1, 1 ; + + fates_allom_d2bl1 = 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, + 0.07, 0.07, 0.07 ; + + fates_allom_d2bl2 = 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, + 1.3 ; + + fates_allom_d2bl3 = 0.55, 0.55, 0.55, 0.55, 0.55, 0.55, 0.55, 0.55, 0.55, + 0.55, 0.55, 0.55 ; + + fates_allom_d2ca_coefficient_max = 0.6568464, 0.6568464, 0.6568464, + 0.6568464, 0.6568464, 0.6568464, 0.6568464, 0.6568464, 0.6568464, + 0.6568464, 0.6568464, 0.6568464 ; + + fates_allom_d2ca_coefficient_min = 0.3381119, 0.3381119, 0.3381119, + 0.3381119, 0.3381119, 0.3381119, 0.3381119, 0.3381119, 0.3381119, + 0.3381119, 0.3381119, 0.3381119 ; + + fates_allom_d2h1 = 0.64, 0.64, 0.64, 0.64, 0.64, 0.64, 0.64, 0.64, 0.64, + 0.64, 0.64, 0.64 ; + + fates_allom_d2h2 = 0.37, 0.37, 0.37, 0.37, 0.37, 0.37, 0.37, 0.37, 0.37, + 0.37, 0.37, 0.37 ; + + fates_allom_d2h3 = -999.9, -999.9, -999.9, -999.9, -999.9, -999.9, -999.9, + -999.9, -999.9, -999.9, -999.9, -999.9 ; + + fates_allom_dbh_maxheight = 90, 80, 80, 80, 90, 80, 3, 3, 2, 0.35, 0.35, 0.35 ; + + fates_allom_fmode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_fnrt_prof_a = 7, 7, 7, 7, 6, 6, 7, 7, 7, 11, 11, 11 ; + + fates_allom_fnrt_prof_b = 1, 2, 2, 1, 2, 2, 1.5, 1.5, 1.5, 2, 2, 2 ; + + fates_allom_fnrt_prof_mode = 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 ; + + fates_allom_frbstor_repro = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_allom_hmode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_l2fr = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_la_per_sa_int = 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, + 0.8, 0.8, 0.8 ; + + fates_allom_la_per_sa_slp = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_allom_lmode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_sai_scaler = 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, + 0.1, 0.1 ; + + fates_allom_smode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_stmode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_zroot_k = 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10 ; + + fates_allom_zroot_max_dbh = 100, 100, 100, 100, 100, 100, 2, 2, 2, 2, 2, 2 ; + + fates_allom_zroot_max_z = 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, + 100, 100 ; + + fates_allom_zroot_min_dbh = 1, 1, 1, 2.5, 2.5, 2.5, 0.1, 0.1, 0.1, 0.1, 0.1, + 0.1 ; + + fates_allom_zroot_min_z = 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, + 100, 100 ; + + fates_c2b = 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ; + + fates_cnp_eca_alpha_ptase = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5 ; + + fates_cnp_eca_decompmicc = 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280 ; + + fates_cnp_eca_km_nh4 = 0.14, 0.14, 0.14, 0.14, 0.14, 0.14, 0.14, 0.14, 0.14, + 0.14, 0.14, 0.14 ; + + fates_cnp_eca_km_no3 = 0.27, 0.27, 0.27, 0.27, 0.27, 0.27, 0.27, 0.27, 0.27, + 0.27, 0.27, 0.27 ; + + fates_cnp_eca_km_p = 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, + 0.1 ; + + fates_cnp_eca_km_ptase = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_cnp_eca_lambda_ptase = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_cnp_eca_vmax_ptase = 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, + 5e-09, 5e-09, 5e-09, 5e-09, 5e-09 ; + + fates_cnp_nfix1 = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_cnp_nitr_store_ratio = 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, + 1.5, 1.5, 1.5 ; + + fates_cnp_phos_store_ratio = 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, + 1.5, 1.5, 1.5 ; + + fates_cnp_pid_kd = 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1 ; + + fates_cnp_pid_ki = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_cnp_pid_kp = 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, + 0.0005, 0.0005, 0.0005, 0.0005, 0.0005 ; + + fates_cnp_prescribed_nuptake = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_cnp_prescribed_puptake = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_cnp_store_ovrflw_frac = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_cnp_turnover_nitr_retrans = + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_cnp_turnover_phos_retrans = + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_cnp_vmax_nh4 = 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, + 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09 ; + + fates_cnp_vmax_no3 = 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, + 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09 ; + + fates_cnp_vmax_p = 5e-10, 5e-10, 5e-10, 5e-10, 5e-10, 5e-10, 5e-10, 5e-10, + 5e-10, 5e-10, 5e-10, 5e-10 ; + + fates_damage_frac = 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, + 0.01, 0.01, 0.01 ; + + fates_damage_mort_p1 = 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 ; + + fates_damage_mort_p2 = 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, + 5.5, 5.5 ; + + fates_damage_recovery_scalar = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_dev_arbitrary_pft = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_fire_alpha_SH = 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, + 0.2 ; + + fates_fire_bark_scaler = 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, + 0.07, 0.07, 0.07, 0.07 ; + + fates_fire_crown_kill = 0.775, 0.775, 0.775, 0.775, 0.775, 0.775, 0.775, + 0.775, 0.775, 0.775, 0.775, 0.775 ; + + fates_frag_fnrt_fcel = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5 ; + + fates_frag_fnrt_flab = 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25 ; + + fates_frag_fnrt_flig = 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25 ; + + fates_frag_leaf_fcel = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5 ; + + fates_frag_leaf_flab = 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25 ; + + fates_frag_leaf_flig = 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25 ; + + fates_frag_seed_decay_rate = 0.51, 0.51, 0.51, 0.51, 0.51, 0.51, 0.51, 0.51, + 0.51, 0.51, 0.51, 0.51 ; + + fates_grperc = 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, + 0.11, 0.11 ; + + fates_hydro_avuln_gs = 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, + 2.5, 2.5 ; + + fates_hydro_avuln_node = + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ; + + fates_hydro_epsil_node = + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 ; + + fates_hydro_fcap_node = + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, + 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_hydro_k_lwp = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_hydro_kmax_node = + -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999 ; + + fates_hydro_p50_gs = -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, + -1.5, -1.5, -1.5 ; + + fates_hydro_p50_node = + -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, + -2.25, -2.25, + -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, + -2.25, -2.25, + -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, + -2.25, -2.25, + -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, + -2.25, -2.25 ; + + fates_hydro_p_taper = 0.333, 0.333, 0.333, 0.333, 0.333, 0.333, 0.333, + 0.333, 0.333, 0.333, 0.333, 0.333 ; + + fates_hydro_pinot_node = + -1.465984, -1.465984, -1.465984, -1.465984, -1.465984, -1.465984, + -1.465984, -1.465984, -1.465984, -1.465984, -1.465984, -1.465984, + -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, + -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, + -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, + -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, + -1.043478, -1.043478, -1.043478, -1.043478, -1.043478, -1.043478, + -1.043478, -1.043478, -1.043478, -1.043478, -1.043478, -1.043478 ; + + fates_hydro_pitlp_node = + -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, + -1.67, -1.67, + -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, + -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, + -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2 ; + + fates_hydro_resid_node = + 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, + 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, + 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, + 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11 ; + + fates_hydro_rfrac_stem = 0.625, 0.625, 0.625, 0.625, 0.625, 0.625, 0.625, + 0.625, 0.625, 0.625, 0.625, 0.625 ; + + fates_hydro_rs2 = 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, + 0.0001, 0.0001, 0.0001, 0.0001, 0.0001 ; + + fates_hydro_srl = 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25 ; + + fates_hydro_thetas_node = + 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, + 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, + 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, + 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75 ; + + fates_hydro_vg_alpha_node = + 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.005, 0.005, 0.005, 0.005, 0.005, + 0.005, 0.005, + 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.005, 0.005, 0.005, 0.005, 0.005, + 0.005, 0.005, + 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.005, 0.005, 0.005, 0.005, 0.005, + 0.005, 0.005, + 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.005, 0.005, 0.005, 0.005, 0.005, + 0.005, 0.005 ; + + fates_hydro_vg_m_node = + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5 ; + + fates_hydro_vg_n_node = + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ; + + fates_leaf_c3psn = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 ; + + fates_leaf_jmaxha = 43540, 43540, 43540, 43540, 43540, 43540, 43540, 43540, + 43540, 43540, 43540, 43540 ; + + fates_leaf_jmaxhd = 152040, 152040, 152040, 152040, 152040, 152040, 152040, + 152040, 152040, 152040, 152040, 152040 ; + + fates_leaf_jmaxse = 495, 495, 495, 495, 495, 495, 495, 495, 495, 495, 495, + 495 ; + + fates_leaf_slamax = 0.0954, 0.0954, 0.0954, 0.0954, 0.0954, 0.0954, 0.012, + 0.03, 0.03, 0.03, 0.03, 0.03 ; + + fates_leaf_slatop = 0.012, 0.005, 0.024, 0.009, 0.03, 0.03, 0.012, 0.03, + 0.03, 0.03, 0.03, 0.03 ; + + fates_leaf_stomatal_intercept = 10000, 10000, 10000, 10000, 10000, 10000, + 10000, 10000, 10000, 10000, 10000, 40000 ; + + fates_leaf_stomatal_slope_ballberry = 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 ; + + fates_leaf_stomatal_slope_medlyn = 4.1, 2.3, 2.3, 4.1, 4.4, 4.4, 4.7, 4.7, + 4.7, 2.2, 5.3, 1.6 ; + + fates_leaf_vcmax25top = + 50, 62, 39, 61, 41, 58, 62, 54, 54, 78, 78, 78 ; + + fates_leaf_vcmaxha = 65330, 65330, 65330, 65330, 65330, 65330, 65330, 65330, + 65330, 65330, 65330, 65330 ; + + fates_leaf_vcmaxhd = 149250, 149250, 149250, 149250, 149250, 149250, 149250, + 149250, 149250, 149250, 149250, 149250 ; + + fates_leaf_vcmaxse = 485, 485, 485, 485, 485, 485, 485, 485, 485, 485, 485, + 485 ; + + fates_maintresp_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, + 0.014, 0.014, 0.014, 0.014 ; + + fates_mort_freezetol = 2.5, -55, -80, -30, 2.5, -80, -60, -10, -80, -80, + -20, 2.5 ; + + fates_mort_hf_flc_threshold = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5 ; + + fates_mort_hf_sm_threshold = 1e-06, 1e-06, 1e-06, 1e-06, 1e-06, 1e-06, + 1e-06, 1e-06, 1e-06, 1e-06, 1e-06, 1e-06 ; + + fates_mort_ip_age_senescence = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_mort_ip_size_senescence = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_mort_prescribed_canopy = 0.0194, 0.0194, 0.0194, 0.0194, 0.0194, + 0.0194, 0.0194, 0.0194, 0.0194, 0.0194, 0.0194, 0.0194 ; + + fates_mort_prescribed_understory = 0.025, 0.025, 0.025, 0.025, 0.025, 0.025, + 0.025, 0.025, 0.025, 0.025, 0.025, 0.025 ; + + fates_mort_r_age_senescence = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_mort_r_size_senescence = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_mort_scalar_coldstress = 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 ; + + fates_mort_scalar_cstarvation = 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, + 0.6, 0.6, 0.6 ; + + fates_mort_scalar_hydrfailure = 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, + 0.6, 0.6, 0.6 ; + + fates_nonhydro_smpsc = -255000, -255000, -255000, -255000, -255000, -255000, + -255000, -255000, -255000, -255000, -255000, -255000 ; + + fates_nonhydro_smpso = -66000, -66000, -66000, -66000, -66000, -66000, + -66000, -66000, -66000, -66000, -66000, -66000 ; + + fates_phen_cold_size_threshold = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_phen_evergreen = 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 ; + + fates_phen_flush_fraction = _, _, 0.5, _, 0.5, 0.5, _, 0.5, 0.5, 0.5, 0.5, + 0.5 ; + + fates_phen_fnrt_drop_frac = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_phen_season_decid = 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0 ; + + fates_phen_stem_drop_fraction = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_phen_stress_decid = 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1 ; + + fates_prescribed_npp_canopy = 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, + 0.4, 0.4, 0.4 ; + + fates_prescribed_npp_understory = 0.03125, 0.03125, 0.03125, 0.03125, + 0.03125, 0.03125, 0.03125, 0.03125, 0.03125, 0.03125, 0.03125, 0.03125 ; + + fates_rad_leaf_clumping_index = 0.85, 0.85, 0.8, 0.85, 0.85, 0.9, 0.85, 0.9, + 0.9, 0.75, 0.75, 0.75 ; + + fates_rad_leaf_rhonir = 0.46, 0.41, 0.39, 0.46, 0.41, 0.41, 0.46, 0.41, + 0.41, 0.28, 0.28, 0.28 ; + + fates_rad_leaf_rhovis = 0.11, 0.09, 0.08, 0.11, 0.08, 0.08, 0.11, 0.08, + 0.08, 0.05, 0.05, 0.05 ; + + fates_rad_leaf_taunir = 0.33, 0.32, 0.42, 0.33, 0.43, 0.43, 0.33, 0.43, + 0.43, 0.4, 0.4, 0.4 ; + + fates_rad_leaf_tauvis = 0.06, 0.04, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, + 0.06, 0.05, 0.05, 0.05 ; + + fates_rad_leaf_xl = 0.32, 0.01, 0.01, 0.32, 0.2, 0.59, 0.32, 0.59, 0.59, + -0.23, -0.23, -0.23 ; + + fates_rad_stem_rhonir = 0.49, 0.36, 0.36, 0.49, 0.49, 0.49, 0.49, 0.49, + 0.49, 0.53, 0.53, 0.53 ; + + fates_rad_stem_rhovis = 0.21, 0.12, 0.12, 0.21, 0.21, 0.21, 0.21, 0.21, + 0.21, 0.31, 0.31, 0.31 ; + + fates_rad_stem_taunir = 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, + 0.001, 0.001, 0.25, 0.25, 0.25 ; + + fates_rad_stem_tauvis = 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, + 0.001, 0.001, 0.12, 0.12, 0.12 ; + + fates_recruit_height_min = 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 0.2, 0.2, 0.2, + 0.125, 0.125, 0.125 ; + + fates_recruit_init_density = 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, + 0.2, 0.2, 0.2 ; + + fates_recruit_prescribed_rate = 0.02, 0.02, 0.02, 0.02, 0.02, 0.02, 0.02, + 0.02, 0.02, 0.02, 0.02, 0.02 ; + + fates_recruit_seed_alloc = 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, + 0.1, 0.1 ; + + fates_recruit_seed_alloc_mature = 0, 0, 0, 0, 0, 0, 0.9, 0.9, 0.9, 0.9, 0.9, + 0.9 ; + + fates_recruit_seed_dbh_repro_threshold = 90, 80, 80, 80, 90, 80, 3, 3, 2, + 0.35, 0.35, 0.35 ; + + fates_recruit_seed_germination_rate = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5 ; + + fates_recruit_seed_supplement = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_stoich_nitr = + 0.033, 0.029, 0.04, 0.033, 0.04, 0.04, 0.033, 0.04, 0.04, 0.04, 0.04, 0.04, + 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, + 0.024, 0.024, + 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, + 1e-08, 1e-08, + 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, + 0.0047, 0.0047, 0.0047 ; + + fates_stoich_phos = + 0.0033, 0.0029, 0.004, 0.0033, 0.004, 0.004, 0.0033, 0.004, 0.004, 0.004, + 0.004, 0.004, + 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, + 0.0024, 0.0024, 0.0024, + 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, + 1e-09, 1e-09, + 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, + 0.00047, 0.00047, 0.00047, 0.00047 ; + + fates_trim_inc = 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, + 0.03, 0.03 ; + + fates_trim_limit = 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3 ; + + fates_turb_displar = 0.67, 0.67, 0.67, 0.67, 0.67, 0.67, 0.67, 0.67, 0.67, + 0.67, 0.67, 0.67 ; + + fates_turb_leaf_diameter = 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, + 0.04, 0.04, 0.04, 0.04 ; + + fates_turb_z0mr = 0.055, 0.055, 0.055, 0.055, 0.055, 0.055, 0.055, 0.055, + 0.055, 0.055, 0.055, 0.055 ; + + fates_turnover_branch = 150, 150, 150, 150, 150, 150, 150, 150, 150, 0, 0, 0 ; + + fates_turnover_fnrt = 1, 2, 1, 1.5, 1, 1, 1.5, 1, 1, 1, 1, 1 ; + + fates_turnover_leaf = + 1.5, 4, 1, 1.5, 1, 1, 1.5, 1, 1, 1, 1, 1 ; + + fates_turnover_senleaf_fdrought = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_wood_density = 0.7, 0.4, 0.7, 0.53, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, + 0.7 ; + + fates_woody = 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 ; + + fates_hlm_pft_map = + 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 ; + + fates_fire_FBD = 15.4, 16.8, 19.6, 999, 4, 4 ; + + fates_fire_low_moisture_Coeff = 1.12, 1.09, 0.98, 0.8, 1.15, 1.15 ; + + fates_fire_low_moisture_Slope = 0.62, 0.72, 0.85, 0.8, 0.62, 0.62 ; + + fates_fire_mid_moisture = 0.72, 0.51, 0.38, 1, 0.8, 0.8 ; + + fates_fire_mid_moisture_Coeff = 2.35, 1.47, 1.06, 0.8, 3.2, 3.2 ; + + fates_fire_mid_moisture_Slope = 2.35, 1.47, 1.06, 0.8, 3.2, 3.2 ; + + fates_fire_min_moisture = 0.18, 0.12, 0, 0, 0.24, 0.24 ; + + fates_fire_SAV = 13, 3.58, 0.98, 0.2, 66, 66 ; + + fates_frag_maxdecomp = 0.52, 0.383, 0.383, 0.19, 1, 999 ; + + fates_frag_cwd_frac = 0.045, 0.075, 0.21, 0.67 ; + + fates_base_mr_20 = 2.52e-06 ; + + fates_canopy_closure_thresh = 0.8 ; + + fates_cnp_eca_plant_escalar = 1.25e-05 ; + + fates_cohort_age_fusion_tol = 0.08 ; + + fates_cohort_size_fusion_tol = 0.08 ; + + fates_comp_excln = 3 ; + + fates_damage_canopy_layer_code = 1 ; + + fates_damage_event_code = 1 ; + + fates_dev_arbitrary = _ ; + + fates_fire_active_crown_fire = 0 ; + + fates_fire_cg_strikes = 0.2 ; + + fates_fire_drying_ratio = 66000 ; + + fates_fire_durat_slope = -11.06 ; + + fates_fire_fdi_a = 17.62 ; + + fates_fire_fdi_alpha = 0.00037 ; + + fates_fire_fdi_b = 243.12 ; + + fates_fire_fuel_energy = 18000 ; + + fates_fire_max_durat = 240 ; + + fates_fire_miner_damp = 0.41739 ; + + fates_fire_miner_total = 0.055 ; + + fates_fire_nignitions = 15 ; + + fates_fire_part_dens = 513 ; + + fates_fire_threshold = 50 ; + + fates_frag_cwd_fcel = 0.76 ; + + fates_frag_cwd_flig = 0.24 ; + + fates_hydro_kmax_rsurf1 = 20 ; + + fates_hydro_kmax_rsurf2 = 0.0001 ; + + fates_hydro_psi0 = 0 ; + + fates_hydro_psicap = -0.6 ; + + fates_hydro_solver = 1 ; + + fates_landuse_logging_coll_under_frac = 0.55983 ; + + fates_landuse_logging_collateral_frac = 0.05 ; + + fates_landuse_logging_dbhmax = _ ; + + fates_landuse_logging_dbhmax_infra = 35 ; + + fates_landuse_logging_dbhmin = 50 ; + + fates_landuse_logging_direct_frac = 0.15 ; + + fates_landuse_logging_event_code = -30 ; + + fates_landuse_logging_export_frac = 0.8 ; + + fates_landuse_logging_mechanical_frac = 0.05 ; + + fates_landuse_pprodharv10_forest_mean = 0.8125 ; + + fates_leaf_photo_temp_acclim_timescale = 30 ; + + fates_leaf_photo_tempsens_model = 1 ; + + fates_leaf_stomatal_assim_model = 1 ; + + fates_leaf_stomatal_model = 1 ; + + fates_leaf_theta_cj_c3 = 0.999 ; + + fates_leaf_theta_cj_c4 = 0.999 ; + + fates_maintresp_model = 1 ; + + fates_maxcohort = 100 ; + + fates_maxpatch_primary = 10 ; + + fates_maxpatch_secondary = 4 ; + + fates_mort_disturb_frac = 1 ; + + fates_mort_understorey_death = 0.55983 ; + + fates_patch_fusion_tol = 0.05 ; + + fates_phen_chilltemp = 5 ; + + fates_phen_coldtemp = 7.5 ; + + fates_phen_drought_model = 0 ; + + fates_phen_drought_threshold = 0.15 ; + + fates_phen_gddthresh_a = -68 ; + + fates_phen_gddthresh_b = 638 ; + + fates_phen_gddthresh_c = -0.01 ; + + fates_phen_mindaysoff = 100 ; + + fates_phen_mindayson = 90 ; + + fates_phen_moist_threshold = 0.18 ; + + fates_phen_ncolddayslim = 5 ; + + fates_q10_froz = 1.5 ; + + fates_q10_mr = 1.5 ; + + fates_soil_salinity = 0.4 ; + + fates_vai_top_bin_width = 1 ; + + fates_vai_width_increase_factor = 1 ; +} diff --git a/parameter_files/archive/api25.1.0_021623_pr931.xml b/parameter_files/archive/api25.1.0_021623_pr931.xml new file mode 100644 index 0000000000..df4598fd14 --- /dev/null +++ b/parameter_files/archive/api25.1.0_021623_pr931.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + archive/api25.1.0_021623_fates_params_default.cdl + fates_params_default.cdl + 1,2,3,4,5,6,7,8,9,10,11,12 + + + fates_maintresp_leaf_atkin2017_baserate + fates_pft + umol CO2/m^2/s + Leaf maintenance respiration base rate parameter (r0) per Atkin et al 2017 + 1.7560, 1.4995, 1.4995, 1.7560, 1.7560, 1.7560, 2.0749, 2.0749, 2.0749, 2.1956, 2.1956, 2.1956 + + + fates_maintresp_leaf_ryan1991_baserate + fates_pft + gC/gN/s + Leaf maintenance respiration base rate per Ryan et al 1991 + 2.525e-06, 2.525e-06, 2.525e-06, 2.525e-06, 2.525e-06, 2.525e-06, 2.525e-06, 2.525e-06, 2.525e-06, 2.525e-06, 2.525e-06, 2.525e-06 + + + fates_maintresp_nonleaf_baserate + 2.525e-06 + + + fates_maintresp_leaf_model + + + diff --git a/parameter_files/archive/api25.2.0_031723_fates_params_default.cdl b/parameter_files/archive/api25.2.0_031723_fates_params_default.cdl new file mode 100644 index 0000000000..7cf0fe3135 --- /dev/null +++ b/parameter_files/archive/api25.2.0_031723_fates_params_default.cdl @@ -0,0 +1,1554 @@ +netcdf fates_params_default { +dimensions: + fates_NCWD = 4 ; + fates_history_age_bins = 7 ; + fates_history_coage_bins = 2 ; + fates_history_damage_bins = 2 ; + fates_history_height_bins = 6 ; + fates_history_size_bins = 13 ; + fates_hlm_pftno = 14 ; + fates_hydr_organs = 4 ; + fates_leafage_class = 1 ; + fates_litterclass = 6 ; + fates_pft = 12 ; + fates_plant_organs = 4 ; + fates_string_length = 60 ; +variables: + double fates_history_ageclass_bin_edges(fates_history_age_bins) ; + fates_history_ageclass_bin_edges:units = "yr" ; + fates_history_ageclass_bin_edges:long_name = "Lower edges for age class bins used in age-resolved patch history output" ; + double fates_history_coageclass_bin_edges(fates_history_coage_bins) ; + fates_history_coageclass_bin_edges:units = "years" ; + fates_history_coageclass_bin_edges:long_name = "Lower edges for cohort age class bins used in cohort age resolved history output" ; + double fates_history_height_bin_edges(fates_history_height_bins) ; + fates_history_height_bin_edges:units = "m" ; + fates_history_height_bin_edges:long_name = "Lower edges for height bins used in height-resolved history output" ; + double fates_history_damage_bin_edges(fates_history_damage_bins) ; + fates_history_damage_bin_edges:units = "% crown loss" ; + fates_history_damage_bin_edges:long_name = "Lower edges for damage class bins used in cohort history output" ; + double fates_history_sizeclass_bin_edges(fates_history_size_bins) ; + fates_history_sizeclass_bin_edges:units = "cm" ; + fates_history_sizeclass_bin_edges:long_name = "Lower edges for DBH size class bins used in size-resolved cohort history output" ; + double fates_alloc_organ_id(fates_plant_organs) ; + fates_alloc_organ_id:units = "unitless" ; + fates_alloc_organ_id:long_name = "This is the global index that the organ in this file is associated with, values match those in parteh/PRTGenericMod.F90" ; + double fates_hydro_htftype_node(fates_hydr_organs) ; + fates_hydro_htftype_node:units = "unitless" ; + fates_hydro_htftype_node:long_name = "Switch that defines the hydraulic transfer functions for each organ." ; + char fates_pftname(fates_pft, fates_string_length) ; + fates_pftname:units = "unitless - string" ; + fates_pftname:long_name = "Description of plant type" ; + char fates_hydro_organ_name(fates_hydr_organs, fates_string_length) ; + fates_hydro_organ_name:units = "unitless - string" ; + fates_hydro_organ_name:long_name = "Name of plant hydraulics organs (DONT CHANGE, order matches media list in FatesHydraulicsMemMod.F90)" ; + char fates_alloc_organ_name(fates_plant_organs, fates_string_length) ; + fates_alloc_organ_name:units = "unitless - string" ; + fates_alloc_organ_name:long_name = "Name of plant organs (with alloc_organ_id, must match PRTGenericMod.F90)" ; + char fates_litterclass_name(fates_litterclass, fates_string_length) ; + fates_litterclass_name:units = "unitless - string" ; + fates_litterclass_name:long_name = "Name of the litter classes, for variables associated with dimension fates_litterclass" ; + double fates_alloc_organ_priority(fates_plant_organs, fates_pft) ; + fates_alloc_organ_priority:units = "index" ; + fates_alloc_organ_priority:long_name = "Priority level for allocation, 1: replaces turnover from storage, 2: same priority as storage use/replacement, 3: ascending in order of least importance" ; + double fates_alloc_storage_cushion(fates_pft) ; + fates_alloc_storage_cushion:units = "fraction" ; + fates_alloc_storage_cushion:long_name = "maximum size of storage C pool, relative to maximum size of leaf C pool" ; + double fates_alloc_store_priority_frac(fates_pft) ; + fates_alloc_store_priority_frac:units = "unitless" ; + fates_alloc_store_priority_frac:long_name = "for high-priority organs, the fraction of their turnover demand that is gauranteed to be replaced, and if need-be by storage" ; + double fates_allom_agb1(fates_pft) ; + fates_allom_agb1:units = "variable" ; + fates_allom_agb1:long_name = "Parameter 1 for agb allometry" ; + double fates_allom_agb2(fates_pft) ; + fates_allom_agb2:units = "variable" ; + fates_allom_agb2:long_name = "Parameter 2 for agb allometry" ; + double fates_allom_agb3(fates_pft) ; + fates_allom_agb3:units = "variable" ; + fates_allom_agb3:long_name = "Parameter 3 for agb allometry" ; + double fates_allom_agb4(fates_pft) ; + fates_allom_agb4:units = "variable" ; + fates_allom_agb4:long_name = "Parameter 4 for agb allometry" ; + double fates_allom_agb_frac(fates_pft) ; + fates_allom_agb_frac:units = "fraction" ; + fates_allom_agb_frac:long_name = "Fraction of woody biomass that is above ground" ; + double fates_allom_amode(fates_pft) ; + fates_allom_amode:units = "index" ; + fates_allom_amode:long_name = "AGB allometry function index." ; + double fates_allom_blca_expnt_diff(fates_pft) ; + fates_allom_blca_expnt_diff:units = "unitless" ; + fates_allom_blca_expnt_diff:long_name = "difference between allometric DBH:bleaf and DBH:crown area exponents" ; + double fates_allom_cmode(fates_pft) ; + fates_allom_cmode:units = "index" ; + fates_allom_cmode:long_name = "coarse root biomass allometry function index." ; + double fates_allom_crown_depth_frac(fates_pft) ; + fates_allom_crown_depth_frac:units = "fraction" ; + fates_allom_crown_depth_frac:long_name = "the depth of a cohort crown as a fraction of its height" ; + double fates_allom_d2bl1(fates_pft) ; + fates_allom_d2bl1:units = "variable" ; + fates_allom_d2bl1:long_name = "Parameter 1 for d2bl allometry" ; + double fates_allom_d2bl2(fates_pft) ; + fates_allom_d2bl2:units = "variable" ; + fates_allom_d2bl2:long_name = "Parameter 2 for d2bl allometry" ; + double fates_allom_d2bl3(fates_pft) ; + fates_allom_d2bl3:units = "unitless" ; + fates_allom_d2bl3:long_name = "Parameter 3 for d2bl allometry" ; + double fates_allom_d2ca_coefficient_max(fates_pft) ; + fates_allom_d2ca_coefficient_max:units = "m2 cm^(-1/beta)" ; + fates_allom_d2ca_coefficient_max:long_name = "max (savanna) dbh to area multiplier factor where: area = n*d2ca_coeff*dbh^beta" ; + double fates_allom_d2ca_coefficient_min(fates_pft) ; + fates_allom_d2ca_coefficient_min:units = "m2 cm^(-1/beta)" ; + fates_allom_d2ca_coefficient_min:long_name = "min (forest) dbh to area multiplier factor where: area = n*d2ca_coeff*dbh^beta" ; + double fates_allom_d2h1(fates_pft) ; + fates_allom_d2h1:units = "variable" ; + fates_allom_d2h1:long_name = "Parameter 1 for d2h allometry (intercept, or c)" ; + double fates_allom_d2h2(fates_pft) ; + fates_allom_d2h2:units = "variable" ; + fates_allom_d2h2:long_name = "Parameter 2 for d2h allometry (slope, or m)" ; + double fates_allom_d2h3(fates_pft) ; + fates_allom_d2h3:units = "variable" ; + fates_allom_d2h3:long_name = "Parameter 3 for d2h allometry (optional)" ; + double fates_allom_dbh_maxheight(fates_pft) ; + fates_allom_dbh_maxheight:units = "cm" ; + fates_allom_dbh_maxheight:long_name = "the diameter (if any) corresponding to maximum height, diameters may increase beyond this" ; + double fates_allom_fmode(fates_pft) ; + fates_allom_fmode:units = "index" ; + fates_allom_fmode:long_name = "fine root biomass allometry function index." ; + double fates_allom_fnrt_prof_a(fates_pft) ; + fates_allom_fnrt_prof_a:units = "unitless" ; + fates_allom_fnrt_prof_a:long_name = "Fine root profile function, parameter a" ; + double fates_allom_fnrt_prof_b(fates_pft) ; + fates_allom_fnrt_prof_b:units = "unitless" ; + fates_allom_fnrt_prof_b:long_name = "Fine root profile function, parameter b" ; + double fates_allom_fnrt_prof_mode(fates_pft) ; + fates_allom_fnrt_prof_mode:units = "index" ; + fates_allom_fnrt_prof_mode:long_name = "Index to select fine root profile function: 1) Jackson Beta, 2) 1-param exponential 3) 2-param exponential" ; + double fates_allom_frbstor_repro(fates_pft) ; + fates_allom_frbstor_repro:units = "fraction" ; + fates_allom_frbstor_repro:long_name = "fraction of bstore goes to reproduction after plant dies" ; + double fates_allom_hmode(fates_pft) ; + fates_allom_hmode:units = "index" ; + fates_allom_hmode:long_name = "height allometry function index." ; + double fates_allom_l2fr(fates_pft) ; + fates_allom_l2fr:units = "gC/gC" ; + fates_allom_l2fr:long_name = "Allocation parameter: fine root C per leaf C" ; + double fates_allom_la_per_sa_int(fates_pft) ; + fates_allom_la_per_sa_int:units = "m2/cm2" ; + fates_allom_la_per_sa_int:long_name = "Leaf area per sapwood area, intercept" ; + double fates_allom_la_per_sa_slp(fates_pft) ; + fates_allom_la_per_sa_slp:units = "m2/cm2/m" ; + fates_allom_la_per_sa_slp:long_name = "Leaf area per sapwood area rate of change with height, slope (optional)" ; + double fates_allom_lmode(fates_pft) ; + fates_allom_lmode:units = "index" ; + fates_allom_lmode:long_name = "leaf biomass allometry function index." ; + double fates_allom_sai_scaler(fates_pft) ; + fates_allom_sai_scaler:units = "m2/m2" ; + fates_allom_sai_scaler:long_name = "allometric ratio of SAI per LAI" ; + double fates_allom_smode(fates_pft) ; + fates_allom_smode:units = "index" ; + fates_allom_smode:long_name = "sapwood allometry function index." ; + double fates_allom_stmode(fates_pft) ; + fates_allom_stmode:units = "index" ; + fates_allom_stmode:long_name = "storage allometry function index: 1) Storage proportional to leaf biomass (with trimming), 2) Storage proportional to maximum leaf biomass (not trimmed)" ; + double fates_allom_zroot_k(fates_pft) ; + fates_allom_zroot_k:units = "unitless" ; + fates_allom_zroot_k:long_name = "scale coefficient of logistic rooting depth model" ; + double fates_allom_zroot_max_dbh(fates_pft) ; + fates_allom_zroot_max_dbh:units = "cm" ; + fates_allom_zroot_max_dbh:long_name = "dbh at which a plant reaches the maximum value for its maximum rooting depth" ; + double fates_allom_zroot_max_z(fates_pft) ; + fates_allom_zroot_max_z:units = "m" ; + fates_allom_zroot_max_z:long_name = "the maximum rooting depth defined at dbh = fates_allom_zroot_max_dbh. note: max_z=min_z=large, sets rooting depth to soil depth" ; + double fates_allom_zroot_min_dbh(fates_pft) ; + fates_allom_zroot_min_dbh:units = "cm" ; + fates_allom_zroot_min_dbh:long_name = "dbh at which the maximum rooting depth for a recruit is defined" ; + double fates_allom_zroot_min_z(fates_pft) ; + fates_allom_zroot_min_z:units = "m" ; + fates_allom_zroot_min_z:long_name = "the maximum rooting depth defined at dbh = fates_allom_zroot_min_dbh. note: max_z=min_z=large, sets rooting depth to soil depth" ; + double fates_c2b(fates_pft) ; + fates_c2b:units = "ratio" ; + fates_c2b:long_name = "Carbon to biomass multiplier of bulk structural tissues" ; + double fates_cnp_eca_alpha_ptase(fates_pft) ; + fates_cnp_eca_alpha_ptase:units = "g/m3" ; + fates_cnp_eca_alpha_ptase:long_name = "fraction of P from ptase activity sent directly to plant (ECA)" ; + double fates_cnp_eca_decompmicc(fates_pft) ; + fates_cnp_eca_decompmicc:units = "gC/m3" ; + fates_cnp_eca_decompmicc:long_name = "maximum soil microbial decomposer biomass found over depth (will be applied at a reference depth w/ exponential attenuation) (ECA)" ; + double fates_cnp_eca_km_nh4(fates_pft) ; + fates_cnp_eca_km_nh4:units = "gN/m3" ; + fates_cnp_eca_km_nh4:long_name = "half-saturation constant for plant nh4 uptake (ECA)" ; + double fates_cnp_eca_km_no3(fates_pft) ; + fates_cnp_eca_km_no3:units = "gN/m3" ; + fates_cnp_eca_km_no3:long_name = "half-saturation constant for plant no3 uptake (ECA)" ; + double fates_cnp_eca_km_p(fates_pft) ; + fates_cnp_eca_km_p:units = "gP/m3" ; + fates_cnp_eca_km_p:long_name = "half-saturation constant for plant p uptake (ECA)" ; + double fates_cnp_eca_km_ptase(fates_pft) ; + fates_cnp_eca_km_ptase:units = "gP/m3" ; + fates_cnp_eca_km_ptase:long_name = "half-saturation constant for biochemical P (ECA)" ; + double fates_cnp_eca_lambda_ptase(fates_pft) ; + fates_cnp_eca_lambda_ptase:units = "g/m3" ; + fates_cnp_eca_lambda_ptase:long_name = "critical value for biochemical production (ECA)" ; + double fates_cnp_eca_vmax_ptase(fates_pft) ; + fates_cnp_eca_vmax_ptase:units = "gP/m2/s" ; + fates_cnp_eca_vmax_ptase:long_name = "maximum production rate for biochemical P (per m2) (ECA)" ; + double fates_cnp_nfix1(fates_pft) ; + fates_cnp_nfix1:units = "fraction" ; + fates_cnp_nfix1:long_name = "fractional surcharge added to maintenance respiration that drives symbiotic fixation" ; + double fates_cnp_nitr_store_ratio(fates_pft) ; + fates_cnp_nitr_store_ratio:units = "(gN/gN)" ; + fates_cnp_nitr_store_ratio:long_name = "storeable (labile) N, as a ratio compared to the N bound in cell structures of other organs (see code)" ; + double fates_cnp_phos_store_ratio(fates_pft) ; + fates_cnp_phos_store_ratio:units = "(gP/gP)" ; + fates_cnp_phos_store_ratio:long_name = "storeable (labile) P, as a ratio compared to the P bound in cell structures of other organs (see code)" ; + double fates_cnp_pid_kd(fates_pft) ; + fates_cnp_pid_kd:units = "unknown" ; + fates_cnp_pid_kd:long_name = "derivative constant of the PID controller on adaptive fine-root biomass" ; + double fates_cnp_pid_ki(fates_pft) ; + fates_cnp_pid_ki:units = "unknown" ; + fates_cnp_pid_ki:long_name = "integral constant of the PID controller on adaptive fine-root biomass" ; + double fates_cnp_pid_kp(fates_pft) ; + fates_cnp_pid_kp:units = "unknown" ; + fates_cnp_pid_kp:long_name = "proportional constant of the PID controller on adaptive fine-root biomass" ; + double fates_cnp_prescribed_nuptake(fates_pft) ; + fates_cnp_prescribed_nuptake:units = "fraction" ; + fates_cnp_prescribed_nuptake:long_name = "Prescribed N uptake flux. 0=fully coupled simulation >0=prescribed (experimental)" ; + double fates_cnp_prescribed_puptake(fates_pft) ; + fates_cnp_prescribed_puptake:units = "fraction" ; + fates_cnp_prescribed_puptake:long_name = "Prescribed P uptake flux. 0=fully coupled simulation, >0=prescribed (experimental)" ; + double fates_cnp_store_ovrflw_frac(fates_pft) ; + fates_cnp_store_ovrflw_frac:units = "fraction" ; + fates_cnp_store_ovrflw_frac:long_name = "size of overflow storage (for excess C,N or P) as a fraction of storage target" ; + double fates_cnp_turnover_nitr_retrans(fates_plant_organs, fates_pft) ; + fates_cnp_turnover_nitr_retrans:units = "fraction" ; + fates_cnp_turnover_nitr_retrans:long_name = "retranslocation (reabsorbtion) fraction of nitrogen in turnover of scenescing tissues" ; + double fates_cnp_turnover_phos_retrans(fates_plant_organs, fates_pft) ; + fates_cnp_turnover_phos_retrans:units = "fraction" ; + fates_cnp_turnover_phos_retrans:long_name = "retranslocation (reabsorbtion) fraction of phosphorus in turnover of scenescing tissues" ; + double fates_cnp_vmax_nh4(fates_pft) ; + fates_cnp_vmax_nh4:units = "gN/gC/s" ; + fates_cnp_vmax_nh4:long_name = "maximum (potential) uptake rate of NH4 per gC of fineroot biomass (see main/EDPftvarcon.F90 vmax_nh4 for usage)" ; + double fates_cnp_vmax_no3(fates_pft) ; + fates_cnp_vmax_no3:units = "gN/gC/s" ; + fates_cnp_vmax_no3:long_name = "maximum (potential) uptake rate of NO3 per gC of fineroot biomass (see main/EDPftvarcon.F90 vmax_no3 for usage)" ; + double fates_cnp_vmax_p(fates_pft) ; + fates_cnp_vmax_p:units = "gP/gC/s" ; + fates_cnp_vmax_p:long_name = "maximum production rate for phosphorus (ECA and RD)" ; + double fates_damage_frac(fates_pft) ; + fates_damage_frac:units = "fraction" ; + fates_damage_frac:long_name = "fraction of cohort damaged in each damage event (event frequency specified in the is_it_damage_time subroutine)" ; + double fates_damage_mort_p1(fates_pft) ; + fates_damage_mort_p1:units = "fraction" ; + fates_damage_mort_p1:long_name = "inflection point of damage mortality function, a value of 0.8 means 50% mortality with 80% loss of crown, turn off with a large number" ; + double fates_damage_mort_p2(fates_pft) ; + fates_damage_mort_p2:units = "unitless" ; + fates_damage_mort_p2:long_name = "rate of mortality increase with damage" ; + double fates_damage_recovery_scalar(fates_pft) ; + fates_damage_recovery_scalar:units = "unitless" ; + fates_damage_recovery_scalar:long_name = "fraction of the cohort that recovers from damage" ; + double fates_dev_arbitrary_pft(fates_pft) ; + fates_dev_arbitrary_pft:units = "unknown" ; + fates_dev_arbitrary_pft:long_name = "Unassociated pft dimensioned free parameter that developers can use for testing arbitrary new hypotheses" ; + double fates_fire_alpha_SH(fates_pft) ; + fates_fire_alpha_SH:units = "m / (kw/m)**(2/3)" ; + fates_fire_alpha_SH:long_name = "spitfire parameter, alpha scorch height, Equation 16 Thonicke et al 2010" ; + double fates_fire_bark_scaler(fates_pft) ; + fates_fire_bark_scaler:units = "fraction" ; + fates_fire_bark_scaler:long_name = "the thickness of a cohorts bark as a fraction of its dbh" ; + double fates_fire_crown_kill(fates_pft) ; + fates_fire_crown_kill:units = "NA" ; + fates_fire_crown_kill:long_name = "fire parameter, see equation 22 in Thonicke et al 2010" ; + double fates_frag_fnrt_fcel(fates_pft) ; + fates_frag_fnrt_fcel:units = "fraction" ; + fates_frag_fnrt_fcel:long_name = "Fine root litter cellulose fraction" ; + double fates_frag_fnrt_flab(fates_pft) ; + fates_frag_fnrt_flab:units = "fraction" ; + fates_frag_fnrt_flab:long_name = "Fine root litter labile fraction" ; + double fates_frag_fnrt_flig(fates_pft) ; + fates_frag_fnrt_flig:units = "fraction" ; + fates_frag_fnrt_flig:long_name = "Fine root litter lignin fraction" ; + double fates_frag_leaf_fcel(fates_pft) ; + fates_frag_leaf_fcel:units = "fraction" ; + fates_frag_leaf_fcel:long_name = "Leaf litter cellulose fraction" ; + double fates_frag_leaf_flab(fates_pft) ; + fates_frag_leaf_flab:units = "fraction" ; + fates_frag_leaf_flab:long_name = "Leaf litter labile fraction" ; + double fates_frag_leaf_flig(fates_pft) ; + fates_frag_leaf_flig:units = "fraction" ; + fates_frag_leaf_flig:long_name = "Leaf litter lignin fraction" ; + double fates_frag_seed_decay_rate(fates_pft) ; + fates_frag_seed_decay_rate:units = "yr-1" ; + fates_frag_seed_decay_rate:long_name = "fraction of seeds that decay per year" ; + double fates_grperc(fates_pft) ; + fates_grperc:units = "unitless" ; + fates_grperc:long_name = "Growth respiration factor" ; + double fates_hydro_avuln_gs(fates_pft) ; + fates_hydro_avuln_gs:units = "unitless" ; + fates_hydro_avuln_gs:long_name = "shape parameter for stomatal control of water vapor exiting leaf" ; + double fates_hydro_avuln_node(fates_hydr_organs, fates_pft) ; + fates_hydro_avuln_node:units = "unitless" ; + fates_hydro_avuln_node:long_name = "xylem vulnerability curve shape parameter" ; + double fates_hydro_epsil_node(fates_hydr_organs, fates_pft) ; + fates_hydro_epsil_node:units = "MPa" ; + fates_hydro_epsil_node:long_name = "bulk elastic modulus" ; + double fates_hydro_fcap_node(fates_hydr_organs, fates_pft) ; + fates_hydro_fcap_node:units = "unitless" ; + fates_hydro_fcap_node:long_name = "fraction of non-residual water that is capillary in source" ; + double fates_hydro_k_lwp(fates_pft) ; + fates_hydro_k_lwp:units = "unitless" ; + fates_hydro_k_lwp:long_name = "inner leaf humidity scaling coefficient" ; + double fates_hydro_kmax_node(fates_hydr_organs, fates_pft) ; + fates_hydro_kmax_node:units = "kg/MPa/m/s" ; + fates_hydro_kmax_node:long_name = "maximum xylem conductivity per unit conducting xylem area" ; + double fates_hydro_p50_gs(fates_pft) ; + fates_hydro_p50_gs:units = "MPa" ; + fates_hydro_p50_gs:long_name = "water potential at 50% loss of stomatal conductance" ; + double fates_hydro_p50_node(fates_hydr_organs, fates_pft) ; + fates_hydro_p50_node:units = "MPa" ; + fates_hydro_p50_node:long_name = "xylem water potential at 50% loss of conductivity" ; + double fates_hydro_p_taper(fates_pft) ; + fates_hydro_p_taper:units = "unitless" ; + fates_hydro_p_taper:long_name = "xylem taper exponent" ; + double fates_hydro_pinot_node(fates_hydr_organs, fates_pft) ; + fates_hydro_pinot_node:units = "MPa" ; + fates_hydro_pinot_node:long_name = "osmotic potential at full turgor" ; + double fates_hydro_pitlp_node(fates_hydr_organs, fates_pft) ; + fates_hydro_pitlp_node:units = "MPa" ; + fates_hydro_pitlp_node:long_name = "turgor loss point" ; + double fates_hydro_resid_node(fates_hydr_organs, fates_pft) ; + fates_hydro_resid_node:units = "cm3/cm3" ; + fates_hydro_resid_node:long_name = "residual water conent" ; + double fates_hydro_rfrac_stem(fates_pft) ; + fates_hydro_rfrac_stem:units = "fraction" ; + fates_hydro_rfrac_stem:long_name = "fraction of total tree resistance from troot to canopy" ; + double fates_hydro_rs2(fates_pft) ; + fates_hydro_rs2:units = "m" ; + fates_hydro_rs2:long_name = "absorbing root radius" ; + double fates_hydro_srl(fates_pft) ; + fates_hydro_srl:units = "m g-1" ; + fates_hydro_srl:long_name = "specific root length" ; + double fates_hydro_thetas_node(fates_hydr_organs, fates_pft) ; + fates_hydro_thetas_node:units = "cm3/cm3" ; + fates_hydro_thetas_node:long_name = "saturated water content" ; + double fates_hydro_vg_alpha_node(fates_hydr_organs, fates_pft) ; + fates_hydro_vg_alpha_node:units = "MPa-1" ; + fates_hydro_vg_alpha_node:long_name = "(used if hydr_htftype_node = 2), capillary length parameter in van Genuchten model" ; + double fates_hydro_vg_m_node(fates_hydr_organs, fates_pft) ; + fates_hydro_vg_m_node:units = "unitless" ; + fates_hydro_vg_m_node:long_name = "(used if hydr_htftype_node = 2),m in van Genuchten 1980 model, 2nd pore size distribution parameter" ; + double fates_hydro_vg_n_node(fates_hydr_organs, fates_pft) ; + fates_hydro_vg_n_node:units = "unitless" ; + fates_hydro_vg_n_node:long_name = "(used if hydr_htftype_node = 2),n in van Genuchten 1980 model, pore size distribution parameter" ; + double fates_leaf_c3psn(fates_pft) ; + fates_leaf_c3psn:units = "flag" ; + fates_leaf_c3psn:long_name = "Photosynthetic pathway (1=c3, 0=c4)" ; + double fates_leaf_jmaxha(fates_pft) ; + fates_leaf_jmaxha:units = "J/mol" ; + fates_leaf_jmaxha:long_name = "activation energy for jmax" ; + double fates_leaf_jmaxhd(fates_pft) ; + fates_leaf_jmaxhd:units = "J/mol" ; + fates_leaf_jmaxhd:long_name = "deactivation energy for jmax" ; + double fates_leaf_jmaxse(fates_pft) ; + fates_leaf_jmaxse:units = "J/mol/K" ; + fates_leaf_jmaxse:long_name = "entropy term for jmax" ; + double fates_leaf_slamax(fates_pft) ; + fates_leaf_slamax:units = "m^2/gC" ; + fates_leaf_slamax:long_name = "Maximum Specific Leaf Area (SLA), even if under a dense canopy" ; + double fates_leaf_slatop(fates_pft) ; + fates_leaf_slatop:units = "m^2/gC" ; + fates_leaf_slatop:long_name = "Specific Leaf Area (SLA) at top of canopy, projected area basis" ; + double fates_leaf_stomatal_intercept(fates_pft) ; + fates_leaf_stomatal_intercept:units = "umol H2O/m**2/s" ; + fates_leaf_stomatal_intercept:long_name = "Minimum unstressed stomatal conductance for Ball-Berry model and Medlyn model" ; + double fates_leaf_stomatal_slope_ballberry(fates_pft) ; + fates_leaf_stomatal_slope_ballberry:units = "unitless" ; + fates_leaf_stomatal_slope_ballberry:long_name = "stomatal slope parameter, as per Ball-Berry" ; + double fates_leaf_stomatal_slope_medlyn(fates_pft) ; + fates_leaf_stomatal_slope_medlyn:units = "KPa**0.5" ; + fates_leaf_stomatal_slope_medlyn:long_name = "stomatal slope parameter, as per Medlyn" ; + double fates_leaf_vcmax25top(fates_leafage_class, fates_pft) ; + fates_leaf_vcmax25top:units = "umol CO2/m^2/s" ; + fates_leaf_vcmax25top:long_name = "maximum carboxylation rate of Rub. at 25C, canopy top" ; + double fates_leaf_vcmaxha(fates_pft) ; + fates_leaf_vcmaxha:units = "J/mol" ; + fates_leaf_vcmaxha:long_name = "activation energy for vcmax" ; + double fates_leaf_vcmaxhd(fates_pft) ; + fates_leaf_vcmaxhd:units = "J/mol" ; + fates_leaf_vcmaxhd:long_name = "deactivation energy for vcmax" ; + double fates_leaf_vcmaxse(fates_pft) ; + fates_leaf_vcmaxse:units = "J/mol/K" ; + fates_leaf_vcmaxse:long_name = "entropy term for vcmax" ; + double fates_maintresp_leaf_atkin2017_baserate(fates_pft) ; + fates_maintresp_leaf_atkin2017_baserate:units = "umol CO2/m^2/s" ; + fates_maintresp_leaf_atkin2017_baserate:long_name = "Leaf maintenance respiration base rate parameter (r0) per Atkin et al 2017" ; + double fates_maintresp_leaf_ryan1991_baserate(fates_pft) ; + fates_maintresp_leaf_ryan1991_baserate:units = "gC/gN/s" ; + fates_maintresp_leaf_ryan1991_baserate:long_name = "Leaf maintenance respiration base rate per Ryan et al 1991" ; + double fates_maintresp_reduction_curvature(fates_pft) ; + fates_maintresp_reduction_curvature:units = "unitless (0-1)" ; + fates_maintresp_reduction_curvature:long_name = "curvature of MR reduction as f(carbon storage), 1=linear, 0=very curved" ; + double fates_maintresp_reduction_intercept(fates_pft) ; + fates_maintresp_reduction_intercept:units = "unitless (0-1)" ; + fates_maintresp_reduction_intercept:long_name = "intercept of MR reduction as f(carbon storage), 0=no throttling, 1=max throttling" ; + double fates_mort_bmort(fates_pft) ; + fates_mort_bmort:units = "1/yr" ; + fates_mort_bmort:long_name = "background mortality rate" ; + double fates_mort_freezetol(fates_pft) ; + fates_mort_freezetol:units = "degrees C" ; + fates_mort_freezetol:long_name = "minimum temperature tolerance" ; + double fates_mort_hf_flc_threshold(fates_pft) ; + fates_mort_hf_flc_threshold:units = "fraction" ; + fates_mort_hf_flc_threshold:long_name = "plant fractional loss of conductivity at which drought mortality begins for hydraulic model" ; + double fates_mort_hf_sm_threshold(fates_pft) ; + fates_mort_hf_sm_threshold:units = "unitless" ; + fates_mort_hf_sm_threshold:long_name = "soil moisture (btran units) at which drought mortality begins for non-hydraulic model" ; + double fates_mort_ip_age_senescence(fates_pft) ; + fates_mort_ip_age_senescence:units = "years" ; + fates_mort_ip_age_senescence:long_name = "Mortality cohort age senescence inflection point. If _ this mortality term is off. Setting this value turns on age dependent mortality. " ; + double fates_mort_ip_size_senescence(fates_pft) ; + fates_mort_ip_size_senescence:units = "dbh cm" ; + fates_mort_ip_size_senescence:long_name = "Mortality dbh senescence inflection point. If _ this mortality term is off. Setting this value turns on size dependent mortality" ; + double fates_mort_prescribed_canopy(fates_pft) ; + fates_mort_prescribed_canopy:units = "1/yr" ; + fates_mort_prescribed_canopy:long_name = "mortality rate of canopy trees for prescribed physiology mode" ; + double fates_mort_prescribed_understory(fates_pft) ; + fates_mort_prescribed_understory:units = "1/yr" ; + fates_mort_prescribed_understory:long_name = "mortality rate of understory trees for prescribed physiology mode" ; + double fates_mort_r_age_senescence(fates_pft) ; + fates_mort_r_age_senescence:units = "mortality rate year^-1" ; + fates_mort_r_age_senescence:long_name = "Mortality age senescence rate of change. Sensible range is around 0.03-0.06. Larger values givesteeper mortality curves." ; + double fates_mort_r_size_senescence(fates_pft) ; + fates_mort_r_size_senescence:units = "mortality rate dbh^-1" ; + fates_mort_r_size_senescence:long_name = "Mortality dbh senescence rate of change. Sensible range is around 0.03-0.06. Larger values give steeper mortality curves." ; + double fates_mort_scalar_coldstress(fates_pft) ; + fates_mort_scalar_coldstress:units = "1/yr" ; + fates_mort_scalar_coldstress:long_name = "maximum mortality rate from cold stress" ; + double fates_mort_scalar_cstarvation(fates_pft) ; + fates_mort_scalar_cstarvation:units = "1/yr" ; + fates_mort_scalar_cstarvation:long_name = "maximum mortality rate from carbon starvation" ; + double fates_mort_scalar_hydrfailure(fates_pft) ; + fates_mort_scalar_hydrfailure:units = "1/yr" ; + fates_mort_scalar_hydrfailure:long_name = "maximum mortality rate from hydraulic failure" ; + double fates_nonhydro_smpsc(fates_pft) ; + fates_nonhydro_smpsc:units = "mm" ; + fates_nonhydro_smpsc:long_name = "Soil water potential at full stomatal closure" ; + double fates_nonhydro_smpso(fates_pft) ; + fates_nonhydro_smpso:units = "mm" ; + fates_nonhydro_smpso:long_name = "Soil water potential at full stomatal opening" ; + double fates_phen_cold_size_threshold(fates_pft) ; + fates_phen_cold_size_threshold:units = "cm" ; + fates_phen_cold_size_threshold:long_name = "the dbh size above which will lead to phenology-related stem and leaf drop" ; + double fates_phen_evergreen(fates_pft) ; + fates_phen_evergreen:units = "logical flag" ; + fates_phen_evergreen:long_name = "Binary flag for evergreen leaf habit" ; + double fates_phen_flush_fraction(fates_pft) ; + fates_phen_flush_fraction:units = "fraction" ; + fates_phen_flush_fraction:long_name = "Upon bud-burst, the maximum fraction of storage carbon used for flushing leaves" ; + double fates_phen_fnrt_drop_frac(fates_pft) ; + fates_phen_fnrt_drop_frac:units = "fraction" ; + fates_phen_fnrt_drop_frac:long_name = "fraction of fine roots to drop during drought or cold" ; + double fates_phen_season_decid(fates_pft) ; + fates_phen_season_decid:units = "logical flag" ; + fates_phen_season_decid:long_name = "Binary flag for seasonal-deciduous leaf habit" ; + double fates_phen_stem_drop_fraction(fates_pft) ; + fates_phen_stem_drop_fraction:units = "fraction" ; + fates_phen_stem_drop_fraction:long_name = "fraction of stems to drop for non-woody species during drought/cold" ; + double fates_phen_stress_decid(fates_pft) ; + fates_phen_stress_decid:units = "logical flag" ; + fates_phen_stress_decid:long_name = "Binary flag for stress-deciduous leaf habit" ; + double fates_prescribed_npp_canopy(fates_pft) ; + fates_prescribed_npp_canopy:units = "kgC / m^2 / yr" ; + fates_prescribed_npp_canopy:long_name = "NPP per unit crown area of canopy trees for prescribed physiology mode" ; + double fates_prescribed_npp_understory(fates_pft) ; + fates_prescribed_npp_understory:units = "kgC / m^2 / yr" ; + fates_prescribed_npp_understory:long_name = "NPP per unit crown area of understory trees for prescribed physiology mode" ; + double fates_rad_leaf_clumping_index(fates_pft) ; + fates_rad_leaf_clumping_index:units = "fraction (0-1)" ; + fates_rad_leaf_clumping_index:long_name = "factor describing how much self-occlusion of leaf scattering elements decreases light interception" ; + double fates_rad_leaf_rhonir(fates_pft) ; + fates_rad_leaf_rhonir:units = "fraction" ; + fates_rad_leaf_rhonir:long_name = "Leaf reflectance: near-IR" ; + double fates_rad_leaf_rhovis(fates_pft) ; + fates_rad_leaf_rhovis:units = "fraction" ; + fates_rad_leaf_rhovis:long_name = "Leaf reflectance: visible" ; + double fates_rad_leaf_taunir(fates_pft) ; + fates_rad_leaf_taunir:units = "fraction" ; + fates_rad_leaf_taunir:long_name = "Leaf transmittance: near-IR" ; + double fates_rad_leaf_tauvis(fates_pft) ; + fates_rad_leaf_tauvis:units = "fraction" ; + fates_rad_leaf_tauvis:long_name = "Leaf transmittance: visible" ; + double fates_rad_leaf_xl(fates_pft) ; + fates_rad_leaf_xl:units = "unitless" ; + fates_rad_leaf_xl:long_name = "Leaf/stem orientation index" ; + double fates_rad_stem_rhonir(fates_pft) ; + fates_rad_stem_rhonir:units = "fraction" ; + fates_rad_stem_rhonir:long_name = "Stem reflectance: near-IR" ; + double fates_rad_stem_rhovis(fates_pft) ; + fates_rad_stem_rhovis:units = "fraction" ; + fates_rad_stem_rhovis:long_name = "Stem reflectance: visible" ; + double fates_rad_stem_taunir(fates_pft) ; + fates_rad_stem_taunir:units = "fraction" ; + fates_rad_stem_taunir:long_name = "Stem transmittance: near-IR" ; + double fates_rad_stem_tauvis(fates_pft) ; + fates_rad_stem_tauvis:units = "fraction" ; + fates_rad_stem_tauvis:long_name = "Stem transmittance: visible" ; + double fates_recruit_height_min(fates_pft) ; + fates_recruit_height_min:units = "m" ; + fates_recruit_height_min:long_name = "the minimum height (ie starting height) of a newly recruited plant" ; + double fates_recruit_init_density(fates_pft) ; + fates_recruit_init_density:units = "stems/m2" ; + fates_recruit_init_density:long_name = "initial seedling density for a cold-start near-bare-ground simulation" ; + double fates_recruit_prescribed_rate(fates_pft) ; + fates_recruit_prescribed_rate:units = "n/yr" ; + fates_recruit_prescribed_rate:long_name = "recruitment rate for prescribed physiology mode" ; + double fates_recruit_seed_alloc(fates_pft) ; + fates_recruit_seed_alloc:units = "fraction" ; + fates_recruit_seed_alloc:long_name = "fraction of available carbon balance allocated to seeds" ; + double fates_recruit_seed_alloc_mature(fates_pft) ; + fates_recruit_seed_alloc_mature:units = "fraction" ; + fates_recruit_seed_alloc_mature:long_name = "fraction of available carbon balance allocated to seeds in mature plants (adds to fates_seed_alloc)" ; + double fates_recruit_seed_dbh_repro_threshold(fates_pft) ; + fates_recruit_seed_dbh_repro_threshold:units = "cm" ; + fates_recruit_seed_dbh_repro_threshold:long_name = "the diameter where the plant will increase allocation to the seed pool by fraction: fates_recruit_seed_alloc_mature" ; + double fates_recruit_seed_germination_rate(fates_pft) ; + fates_recruit_seed_germination_rate:units = "yr-1" ; + fates_recruit_seed_germination_rate:long_name = "fraction of seeds that germinate per year" ; + double fates_recruit_seed_supplement(fates_pft) ; + fates_recruit_seed_supplement:units = "KgC/m2/yr" ; + fates_recruit_seed_supplement:long_name = "Supplemental external seed rain source term (non-mass conserving)" ; + double fates_stoich_nitr(fates_plant_organs, fates_pft) ; + fates_stoich_nitr:units = "gN/gC" ; + fates_stoich_nitr:long_name = "target nitrogen concentration (ratio with carbon) of organs" ; + double fates_stoich_phos(fates_plant_organs, fates_pft) ; + fates_stoich_phos:units = "gP/gC" ; + fates_stoich_phos:long_name = "target phosphorus concentration (ratio with carbon) of organs" ; + double fates_trim_inc(fates_pft) ; + fates_trim_inc:units = "m2/m2" ; + fates_trim_inc:long_name = "Arbitrary incremental change in trimming function." ; + double fates_trim_limit(fates_pft) ; + fates_trim_limit:units = "m2/m2" ; + fates_trim_limit:long_name = "Arbitrary limit to reductions in leaf area with stress" ; + double fates_turb_displar(fates_pft) ; + fates_turb_displar:units = "unitless" ; + fates_turb_displar:long_name = "Ratio of displacement height to canopy top height" ; + double fates_turb_leaf_diameter(fates_pft) ; + fates_turb_leaf_diameter:units = "m" ; + fates_turb_leaf_diameter:long_name = "Characteristic leaf dimension" ; + double fates_turb_z0mr(fates_pft) ; + fates_turb_z0mr:units = "unitless" ; + fates_turb_z0mr:long_name = "Ratio of momentum roughness length to canopy top height" ; + double fates_turnover_branch(fates_pft) ; + fates_turnover_branch:units = "yr" ; + fates_turnover_branch:long_name = "turnover time of branches" ; + double fates_turnover_fnrt(fates_pft) ; + fates_turnover_fnrt:units = "yr" ; + fates_turnover_fnrt:long_name = "root longevity (alternatively, turnover time)" ; + double fates_turnover_leaf(fates_leafage_class, fates_pft) ; + fates_turnover_leaf:units = "yr" ; + fates_turnover_leaf:long_name = "Leaf longevity (ie turnover timescale)" ; + double fates_turnover_senleaf_fdrought(fates_pft) ; + fates_turnover_senleaf_fdrought:units = "unitless[0-1]" ; + fates_turnover_senleaf_fdrought:long_name = "multiplication factor for leaf longevity of senescent leaves during drought" ; + double fates_wood_density(fates_pft) ; + fates_wood_density:units = "g/cm3" ; + fates_wood_density:long_name = "mean density of woody tissue in plant" ; + double fates_woody(fates_pft) ; + fates_woody:units = "logical flag" ; + fates_woody:long_name = "Binary woody lifeform flag" ; + double fates_hlm_pft_map(fates_hlm_pftno, fates_pft) ; + fates_hlm_pft_map:units = "area fraction" ; + fates_hlm_pft_map:long_name = "In fixed biogeog mode, fraction of HLM area associated with each FATES PFT" ; + double fates_fire_FBD(fates_litterclass) ; + fates_fire_FBD:units = "kg Biomass/m3" ; + fates_fire_FBD:long_name = "fuel bulk density" ; + double fates_fire_low_moisture_Coeff(fates_litterclass) ; + fates_fire_low_moisture_Coeff:units = "NA" ; + fates_fire_low_moisture_Coeff:long_name = "spitfire parameter, equation B1 Thonicke et al 2010" ; + double fates_fire_low_moisture_Slope(fates_litterclass) ; + fates_fire_low_moisture_Slope:units = "NA" ; + fates_fire_low_moisture_Slope:long_name = "spitfire parameter, equation B1 Thonicke et al 2010" ; + double fates_fire_mid_moisture(fates_litterclass) ; + fates_fire_mid_moisture:units = "NA" ; + fates_fire_mid_moisture:long_name = "spitfire litter moisture threshold to be considered medium dry" ; + double fates_fire_mid_moisture_Coeff(fates_litterclass) ; + fates_fire_mid_moisture_Coeff:units = "NA" ; + fates_fire_mid_moisture_Coeff:long_name = "spitfire parameter, equation B1 Thonicke et al 2010" ; + double fates_fire_mid_moisture_Slope(fates_litterclass) ; + fates_fire_mid_moisture_Slope:units = "NA" ; + fates_fire_mid_moisture_Slope:long_name = "spitfire parameter, equation B1 Thonicke et al 2010" ; + double fates_fire_min_moisture(fates_litterclass) ; + fates_fire_min_moisture:units = "NA" ; + fates_fire_min_moisture:long_name = "spitfire litter moisture threshold to be considered very dry" ; + double fates_fire_SAV(fates_litterclass) ; + fates_fire_SAV:units = "cm-1" ; + fates_fire_SAV:long_name = "fuel surface area to volume ratio" ; + double fates_frag_maxdecomp(fates_litterclass) ; + fates_frag_maxdecomp:units = "yr-1" ; + fates_frag_maxdecomp:long_name = "maximum rate of litter & CWD transfer from non-decomposing class into decomposing class" ; + double fates_frag_cwd_frac(fates_NCWD) ; + fates_frag_cwd_frac:units = "fraction" ; + fates_frag_cwd_frac:long_name = "fraction of woody (bdead+bsw) biomass destined for CWD pool" ; + double fates_canopy_closure_thresh ; + fates_canopy_closure_thresh:units = "unitless" ; + fates_canopy_closure_thresh:long_name = "tree canopy coverage at which crown area allometry changes from savanna to forest value" ; + double fates_cnp_eca_plant_escalar ; + fates_cnp_eca_plant_escalar:units = "" ; + fates_cnp_eca_plant_escalar:long_name = "scaling factor for plant fine root biomass to calculate nutrient carrier enzyme abundance (ECA)" ; + double fates_cohort_age_fusion_tol ; + fates_cohort_age_fusion_tol:units = "unitless" ; + fates_cohort_age_fusion_tol:long_name = "minimum fraction in differece in cohort age between cohorts." ; + double fates_cohort_size_fusion_tol ; + fates_cohort_size_fusion_tol:units = "unitless" ; + fates_cohort_size_fusion_tol:long_name = "minimum fraction in difference in dbh between cohorts" ; + double fates_comp_excln ; + fates_comp_excln:units = "none" ; + fates_comp_excln:long_name = "IF POSITIVE: weighting factor (exponent on dbh) for canopy layer exclusion and promotion, IF NEGATIVE: switch to use deterministic height sorting" ; + double fates_damage_canopy_layer_code ; + fates_damage_canopy_layer_code:units = "unitless" ; + fates_damage_canopy_layer_code:long_name = "Integer code that decides whether damage affects canopy trees (1), understory trees (2)" ; + double fates_damage_event_code ; + fates_damage_event_code:units = "unitless" ; + fates_damage_event_code:long_name = "Integer code that options how damage events are structured" ; + double fates_dev_arbitrary ; + fates_dev_arbitrary:units = "unknown" ; + fates_dev_arbitrary:long_name = "Unassociated free parameter that developers can use for testing arbitrary new hypotheses" ; + double fates_fire_active_crown_fire ; + fates_fire_active_crown_fire:units = "0 or 1" ; + fates_fire_active_crown_fire:long_name = "flag, 1=active crown fire 0=no active crown fire" ; + double fates_fire_cg_strikes ; + fates_fire_cg_strikes:units = "fraction (0-1)" ; + fates_fire_cg_strikes:long_name = "fraction of cloud to ground lightning strikes" ; + double fates_fire_drying_ratio ; + fates_fire_drying_ratio:units = "NA" ; + fates_fire_drying_ratio:long_name = "spitfire parameter, fire drying ratio for fuel moisture, alpha_FMC EQ 6 Thonicke et al 2010" ; + double fates_fire_durat_slope ; + fates_fire_durat_slope:units = "NA" ; + fates_fire_durat_slope:long_name = "spitfire parameter, fire max duration slope, Equation 14 Thonicke et al 2010" ; + double fates_fire_fdi_a ; + fates_fire_fdi_a:units = "NA" ; + fates_fire_fdi_a:long_name = "spitfire parameter, fire danger index, EQ 5 Thonicke et al 2010" ; + double fates_fire_fdi_alpha ; + fates_fire_fdi_alpha:units = "NA" ; + fates_fire_fdi_alpha:long_name = "spitfire parameter, EQ 7 Venevsky et al. GCB 2002,(modified EQ 8 Thonicke et al. 2010) " ; + double fates_fire_fdi_b ; + fates_fire_fdi_b:units = "NA" ; + fates_fire_fdi_b:long_name = "spitfire parameter, fire danger index, EQ 5 Thonicke et al 2010 " ; + double fates_fire_fuel_energy ; + fates_fire_fuel_energy:units = "kJ/kg" ; + fates_fire_fuel_energy:long_name = "spitfire parameter, heat content of fuel" ; + double fates_fire_max_durat ; + fates_fire_max_durat:units = "minutes" ; + fates_fire_max_durat:long_name = "spitfire parameter, fire maximum duration, Equation 14 Thonicke et al 2010" ; + double fates_fire_miner_damp ; + fates_fire_miner_damp:units = "NA" ; + fates_fire_miner_damp:long_name = "spitfire parameter, mineral-dampening coefficient EQ A1 Thonicke et al 2010 " ; + double fates_fire_miner_total ; + fates_fire_miner_total:units = "fraction" ; + fates_fire_miner_total:long_name = "spitfire parameter, total mineral content, Table A1 Thonicke et al 2010" ; + double fates_fire_nignitions ; + fates_fire_nignitions:units = "ignitions per year per km2" ; + fates_fire_nignitions:long_name = "number of annual ignitions per square km" ; + double fates_fire_part_dens ; + fates_fire_part_dens:units = "kg/m2" ; + fates_fire_part_dens:long_name = "spitfire parameter, oven dry particle density, Table A1 Thonicke et al 2010" ; + double fates_fire_threshold ; + fates_fire_threshold:units = "kW/m" ; + fates_fire_threshold:long_name = "spitfire parameter, fire intensity threshold for tracking fires that spread" ; + double fates_frag_cwd_fcel ; + fates_frag_cwd_fcel:units = "unitless" ; + fates_frag_cwd_fcel:long_name = "Cellulose fraction for CWD" ; + double fates_frag_cwd_flig ; + fates_frag_cwd_flig:units = "unitless" ; + fates_frag_cwd_flig:long_name = "Lignin fraction of coarse woody debris" ; + double fates_hydro_kmax_rsurf1 ; + fates_hydro_kmax_rsurf1:units = "kg water/m2 root area/Mpa/s" ; + fates_hydro_kmax_rsurf1:long_name = "maximum conducitivity for unit root surface (into root)" ; + double fates_hydro_kmax_rsurf2 ; + fates_hydro_kmax_rsurf2:units = "kg water/m2 root area/Mpa/s" ; + fates_hydro_kmax_rsurf2:long_name = "maximum conducitivity for unit root surface (out of root)" ; + double fates_hydro_psi0 ; + fates_hydro_psi0:units = "MPa" ; + fates_hydro_psi0:long_name = "sapwood water potential at saturation" ; + double fates_hydro_psicap ; + fates_hydro_psicap:units = "MPa" ; + fates_hydro_psicap:long_name = "sapwood water potential at which capillary reserves exhausted" ; + double fates_hydro_solver ; + fates_hydro_solver:units = "unitless" ; + fates_hydro_solver:long_name = "switch designating which numerical solver for plant hydraulics, 1 = 1D taylor, 2 = 2D Picard, 3 = 2D Newton (deprecated)" ; + double fates_landuse_logging_coll_under_frac ; + fates_landuse_logging_coll_under_frac:units = "fraction" ; + fates_landuse_logging_coll_under_frac:long_name = "Fraction of stems killed in the understory when logging generates disturbance" ; + double fates_landuse_logging_collateral_frac ; + fates_landuse_logging_collateral_frac:units = "fraction" ; + fates_landuse_logging_collateral_frac:long_name = "Fraction of large stems in upperstory that die from logging collateral damage" ; + double fates_landuse_logging_dbhmax ; + fates_landuse_logging_dbhmax:units = "cm" ; + fates_landuse_logging_dbhmax:long_name = "Maximum dbh below which logging is applied (unset values flag this to be unused)" ; + double fates_landuse_logging_dbhmax_infra ; + fates_landuse_logging_dbhmax_infra:units = "cm" ; + fates_landuse_logging_dbhmax_infra:long_name = "Tree diameter, above which infrastructure from logging does not impact damage or mortality." ; + double fates_landuse_logging_dbhmin ; + fates_landuse_logging_dbhmin:units = "cm" ; + fates_landuse_logging_dbhmin:long_name = "Minimum dbh at which logging is applied" ; + double fates_landuse_logging_direct_frac ; + fates_landuse_logging_direct_frac:units = "fraction" ; + fates_landuse_logging_direct_frac:long_name = "Fraction of stems logged directly per event" ; + double fates_landuse_logging_event_code ; + fates_landuse_logging_event_code:units = "unitless" ; + fates_landuse_logging_event_code:long_name = "Integer code that options how logging events are structured" ; + double fates_landuse_logging_export_frac ; + fates_landuse_logging_export_frac:units = "fraction" ; + fates_landuse_logging_export_frac:long_name = "fraction of trunk product being shipped offsite, the leftovers will be left onsite as large CWD" ; + double fates_landuse_logging_mechanical_frac ; + fates_landuse_logging_mechanical_frac:units = "fraction" ; + fates_landuse_logging_mechanical_frac:long_name = "Fraction of stems killed due infrastructure an other mechanical means" ; + double fates_landuse_pprodharv10_forest_mean ; + fates_landuse_pprodharv10_forest_mean:units = "fraction" ; + fates_landuse_pprodharv10_forest_mean:long_name = "mean harvest mortality proportion of deadstem to 10-yr product (pprodharv10) of all woody PFT types" ; + double fates_leaf_photo_temp_acclim_timescale ; + fates_leaf_photo_temp_acclim_timescale:units = "days" ; + fates_leaf_photo_temp_acclim_timescale:long_name = "Length of the window for the exponential moving average (ema) of vegetation temperature used in photosynthesis temperature acclimation (NOT USED)" ; + double fates_leaf_photo_tempsens_model ; + fates_leaf_photo_tempsens_model:units = "unitless" ; + fates_leaf_photo_tempsens_model:long_name = "switch for choosing the model that defines the temperature sensitivity of photosynthetic parameters (vcmax, jmax). 1=non-acclimating (NOT USED)" ; + double fates_leaf_stomatal_assim_model ; + fates_leaf_stomatal_assim_model:units = "unitless" ; + fates_leaf_stomatal_assim_model:long_name = "a switch designating whether to use net (1) or gross (2) assimilation in the stomatal model" ; + double fates_leaf_stomatal_model ; + fates_leaf_stomatal_model:units = "unitless" ; + fates_leaf_stomatal_model:long_name = "switch for choosing between Ball-Berry (1) stomatal conductance model and Medlyn (2) model" ; + double fates_leaf_theta_cj_c3 ; + fates_leaf_theta_cj_c3:units = "unitless" ; + fates_leaf_theta_cj_c3:long_name = "Empirical curvature parameter for ac, aj photosynthesis co-limitation in c3 plants" ; + double fates_leaf_theta_cj_c4 ; + fates_leaf_theta_cj_c4:units = "unitless" ; + fates_leaf_theta_cj_c4:long_name = "Empirical curvature parameter for ac, aj photosynthesis co-limitation in c4 plants" ; + double fates_maintresp_leaf_model ; + fates_maintresp_leaf_model:units = "unitless" ; + fates_maintresp_leaf_model:long_name = "switch for choosing between maintenance respiration models. 1=Ryan (1991) (NOT USED)" ; + double fates_maintresp_nonleaf_baserate ; + fates_maintresp_nonleaf_baserate:units = "gC/gN/s" ; + fates_maintresp_nonleaf_baserate:long_name = "Base maintenance respiration rate for plant tissues, using Ryan 1991" ; + double fates_maxcohort ; + fates_maxcohort:units = "count" ; + fates_maxcohort:long_name = "maximum number of cohorts per patch. Actual number of cohorts also depend on cohort fusion tolerances" ; + double fates_maxpatch_primary ; + fates_maxpatch_primary:units = "count" ; + fates_maxpatch_primary:long_name = "maximum number of primary vegetation patches per site" ; + double fates_maxpatch_secondary ; + fates_maxpatch_secondary:units = "count" ; + fates_maxpatch_secondary:long_name = "maximum number of secondary vegetation patches per site" ; + double fates_mort_disturb_frac ; + fates_mort_disturb_frac:units = "fraction" ; + fates_mort_disturb_frac:long_name = "fraction of canopy mortality that results in disturbance (i.e. transfer of area from new to old patch)" ; + double fates_mort_understorey_death ; + fates_mort_understorey_death:units = "fraction" ; + fates_mort_understorey_death:long_name = "fraction of plants in understorey cohort impacted by overstorey tree-fall" ; + double fates_patch_fusion_tol ; + fates_patch_fusion_tol:units = "unitless" ; + fates_patch_fusion_tol:long_name = "minimum fraction in difference in profiles between patches" ; + double fates_phen_chilltemp ; + fates_phen_chilltemp:units = "degrees C" ; + fates_phen_chilltemp:long_name = "chilling day counting threshold for vegetation" ; + double fates_phen_coldtemp ; + fates_phen_coldtemp:units = "degrees C" ; + fates_phen_coldtemp:long_name = "vegetation temperature exceedance that flags a cold-day for leaf-drop" ; + double fates_phen_drought_model ; + fates_phen_drought_model:units = "unitless" ; + fates_phen_drought_model:long_name = "which method to use for drought phenology: 0 - FATES default; 1 - Semi-deciduous (ED2-like)" ; + double fates_phen_drought_threshold ; + fates_phen_drought_threshold:units = "m3/m3 or mm" ; + fates_phen_drought_threshold:long_name = "threshold for drought phenology (or lower threshold when fates_phen_drought_model = 1); the quantity depends on the sign: if positive, the threshold is volumetric soil moisture (m3/m3). If negative, the threshold is soil matric potentical (mm)" ; + double fates_phen_gddthresh_a ; + fates_phen_gddthresh_a:units = "none" ; + fates_phen_gddthresh_a:long_name = "GDD accumulation function, intercept parameter: gdd_thesh = a + b exp(c*ncd)" ; + double fates_phen_gddthresh_b ; + fates_phen_gddthresh_b:units = "none" ; + fates_phen_gddthresh_b:long_name = "GDD accumulation function, multiplier parameter: gdd_thesh = a + b exp(c*ncd)" ; + double fates_phen_gddthresh_c ; + fates_phen_gddthresh_c:units = "none" ; + fates_phen_gddthresh_c:long_name = "GDD accumulation function, exponent parameter: gdd_thesh = a + b exp(c*ncd)" ; + double fates_phen_mindaysoff ; + fates_phen_mindaysoff:units = "days" ; + fates_phen_mindaysoff:long_name = "day threshold compared against days since leaves became off-allometry" ; + double fates_phen_mindayson ; + fates_phen_mindayson:units = "days" ; + fates_phen_mindayson:long_name = "day threshold compared against days since leaves became on-allometry" ; + double fates_phen_moist_threshold ; + fates_phen_moist_threshold:units = "m3/m3 or mm" ; + fates_phen_moist_threshold:long_name = "upper threshold for drought phenology (only for fates_phen_drought_model=1); the quantity depends on the sign: if positive, the threshold is volumetric soil moisture (m3/m3). If negative, the threshold is soil matric potentical (mm)" ; + double fates_phen_ncolddayslim ; + fates_phen_ncolddayslim:units = "days" ; + fates_phen_ncolddayslim:long_name = "day threshold exceedance for temperature leaf-drop" ; + double fates_q10_froz ; + fates_q10_froz:units = "unitless" ; + fates_q10_froz:long_name = "Q10 for frozen-soil respiration rates" ; + double fates_q10_mr ; + fates_q10_mr:units = "unitless" ; + fates_q10_mr:long_name = "Q10 for maintenance respiration" ; + double fates_soil_salinity ; + fates_soil_salinity:units = "ppt" ; + fates_soil_salinity:long_name = "soil salinity used for model when not coupled to dynamic soil salinity" ; + double fates_vai_top_bin_width ; + fates_vai_top_bin_width:units = "m2/m2" ; + fates_vai_top_bin_width:long_name = "width in VAI units of uppermost leaf+stem layer scattering element in each canopy layer" ; + double fates_vai_width_increase_factor ; + fates_vai_width_increase_factor:units = "unitless" ; + fates_vai_width_increase_factor:long_name = "factor by which each leaf+stem scattering element increases in VAI width (1 = uniform spacing)" ; + +// global attributes: + :history = "This file was generated by BatchPatchParams.py:\nCDL Base File = archive/api24.1.0_101722_fates_params_default.cdl\nXML patch file = archive/api24.1.0_101722_patch_params.xml" ; +data: + + fates_history_ageclass_bin_edges = 0, 1, 2, 5, 10, 20, 50 ; + + fates_history_coageclass_bin_edges = 0, 5 ; + + fates_history_height_bin_edges = 0, 0.1, 0.3, 1, 3, 10 ; + + fates_history_damage_bin_edges = 0, 80 ; + + fates_history_sizeclass_bin_edges = 0, 5, 10, 15, 20, 30, 40, 50, 60, 70, + 80, 90, 100 ; + + fates_alloc_organ_id = 1, 2, 3, 6 ; + + fates_hydro_htftype_node = 1, 1, 1, 1 ; + + fates_pftname = + "broadleaf_evergreen_tropical_tree ", + "needleleaf_evergreen_extratrop_tree ", + "needleleaf_colddecid_extratrop_tree ", + "broadleaf_evergreen_extratrop_tree ", + "broadleaf_hydrodecid_tropical_tree ", + "broadleaf_colddecid_extratrop_tree ", + "broadleaf_evergreen_extratrop_shrub ", + "broadleaf_hydrodecid_extratrop_shrub ", + "broadleaf_colddecid_extratrop_shrub ", + "arctic_c3_grass ", + "cool_c3_grass ", + "c4_grass " ; + + fates_hydro_organ_name = + "leaf ", + "stem ", + "transporting root ", + "absorbing root " ; + + fates_alloc_organ_name = + "leaf", + "fine root", + "sapwood", + "structure" ; + + fates_litterclass_name = + "twig ", + "small branch ", + "large branch ", + "trunk ", + "dead leaves ", + "live grass " ; + + fates_alloc_organ_priority = + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 ; + + fates_alloc_storage_cushion = 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, + 1.2, 1.2, 1.2 ; + + fates_alloc_store_priority_frac = 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, + 0.8, 0.8, 0.8, 0.8 ; + + fates_allom_agb1 = 0.06896, 0.06896, 0.06896, 0.06896, 0.06896, 0.06896, + 0.06896, 0.06896, 0.06896, 0.01, 0.01, 0.01 ; + + fates_allom_agb2 = 0.572, 0.572, 0.572, 0.572, 0.572, 0.572, 0.572, 0.572, + 0.572, 0.572, 0.572, 0.572 ; + + fates_allom_agb3 = 1.94, 1.94, 1.94, 1.94, 1.94, 1.94, 1.94, 1.94, 1.94, + 1.94, 1.94, 1.94 ; + + fates_allom_agb4 = 0.931, 0.931, 0.931, 0.931, 0.931, 0.931, 0.931, 0.931, + 0.931, 0.931, 0.931, 0.931 ; + + fates_allom_agb_frac = 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, + 0.6, 0.6 ; + + fates_allom_amode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_blca_expnt_diff = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_allom_cmode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_crown_depth_frac = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.95, 0.95, + 0.95, 1, 1, 1 ; + + fates_allom_d2bl1 = 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, + 0.07, 0.07, 0.07 ; + + fates_allom_d2bl2 = 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, + 1.3 ; + + fates_allom_d2bl3 = 0.55, 0.55, 0.55, 0.55, 0.55, 0.55, 0.55, 0.55, 0.55, + 0.55, 0.55, 0.55 ; + + fates_allom_d2ca_coefficient_max = 0.6568464, 0.6568464, 0.6568464, + 0.6568464, 0.6568464, 0.6568464, 0.6568464, 0.6568464, 0.6568464, + 0.6568464, 0.6568464, 0.6568464 ; + + fates_allom_d2ca_coefficient_min = 0.3381119, 0.3381119, 0.3381119, + 0.3381119, 0.3381119, 0.3381119, 0.3381119, 0.3381119, 0.3381119, + 0.3381119, 0.3381119, 0.3381119 ; + + fates_allom_d2h1 = 0.64, 0.64, 0.64, 0.64, 0.64, 0.64, 0.64, 0.64, 0.64, + 0.64, 0.64, 0.64 ; + + fates_allom_d2h2 = 0.37, 0.37, 0.37, 0.37, 0.37, 0.37, 0.37, 0.37, 0.37, + 0.37, 0.37, 0.37 ; + + fates_allom_d2h3 = -999.9, -999.9, -999.9, -999.9, -999.9, -999.9, -999.9, + -999.9, -999.9, -999.9, -999.9, -999.9 ; + + fates_allom_dbh_maxheight = 90, 80, 80, 80, 90, 80, 3, 3, 2, 0.35, 0.35, 0.35 ; + + fates_allom_fmode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_fnrt_prof_a = 7, 7, 7, 7, 6, 6, 7, 7, 7, 11, 11, 11 ; + + fates_allom_fnrt_prof_b = 1, 2, 2, 1, 2, 2, 1.5, 1.5, 1.5, 2, 2, 2 ; + + fates_allom_fnrt_prof_mode = 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 ; + + fates_allom_frbstor_repro = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_allom_hmode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_l2fr = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_la_per_sa_int = 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, + 0.8, 0.8, 0.8 ; + + fates_allom_la_per_sa_slp = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_allom_lmode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_sai_scaler = 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, + 0.1, 0.1 ; + + fates_allom_smode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_stmode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_zroot_k = 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10 ; + + fates_allom_zroot_max_dbh = 100, 100, 100, 100, 100, 100, 2, 2, 2, 2, 2, 2 ; + + fates_allom_zroot_max_z = 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, + 100, 100 ; + + fates_allom_zroot_min_dbh = 1, 1, 1, 2.5, 2.5, 2.5, 0.1, 0.1, 0.1, 0.1, 0.1, + 0.1 ; + + fates_allom_zroot_min_z = 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, + 100, 100 ; + + fates_c2b = 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ; + + fates_cnp_eca_alpha_ptase = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5 ; + + fates_cnp_eca_decompmicc = 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280 ; + + fates_cnp_eca_km_nh4 = 0.14, 0.14, 0.14, 0.14, 0.14, 0.14, 0.14, 0.14, 0.14, + 0.14, 0.14, 0.14 ; + + fates_cnp_eca_km_no3 = 0.27, 0.27, 0.27, 0.27, 0.27, 0.27, 0.27, 0.27, 0.27, + 0.27, 0.27, 0.27 ; + + fates_cnp_eca_km_p = 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, + 0.1 ; + + fates_cnp_eca_km_ptase = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_cnp_eca_lambda_ptase = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_cnp_eca_vmax_ptase = 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, + 5e-09, 5e-09, 5e-09, 5e-09, 5e-09 ; + + fates_cnp_nfix1 = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_cnp_nitr_store_ratio = 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, + 1.5, 1.5, 1.5 ; + + fates_cnp_phos_store_ratio = 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, + 1.5, 1.5, 1.5 ; + + fates_cnp_pid_kd = 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1 ; + + fates_cnp_pid_ki = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_cnp_pid_kp = 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, + 0.0005, 0.0005, 0.0005, 0.0005, 0.0005 ; + + fates_cnp_prescribed_nuptake = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_cnp_prescribed_puptake = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_cnp_store_ovrflw_frac = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_cnp_turnover_nitr_retrans = + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_cnp_turnover_phos_retrans = + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_cnp_vmax_nh4 = 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, + 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09 ; + + fates_cnp_vmax_no3 = 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, + 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09 ; + + fates_cnp_vmax_p = 5e-10, 5e-10, 5e-10, 5e-10, 5e-10, 5e-10, 5e-10, 5e-10, + 5e-10, 5e-10, 5e-10, 5e-10 ; + + fates_damage_frac = 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, + 0.01, 0.01, 0.01 ; + + fates_damage_mort_p1 = 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 ; + + fates_damage_mort_p2 = 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, + 5.5, 5.5 ; + + fates_damage_recovery_scalar = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_dev_arbitrary_pft = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_fire_alpha_SH = 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, + 0.2 ; + + fates_fire_bark_scaler = 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, + 0.07, 0.07, 0.07, 0.07 ; + + fates_fire_crown_kill = 0.775, 0.775, 0.775, 0.775, 0.775, 0.775, 0.775, + 0.775, 0.775, 0.775, 0.775, 0.775 ; + + fates_frag_fnrt_fcel = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5 ; + + fates_frag_fnrt_flab = 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25 ; + + fates_frag_fnrt_flig = 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25 ; + + fates_frag_leaf_fcel = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5 ; + + fates_frag_leaf_flab = 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25 ; + + fates_frag_leaf_flig = 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25 ; + + fates_frag_seed_decay_rate = 0.51, 0.51, 0.51, 0.51, 0.51, 0.51, 0.51, 0.51, + 0.51, 0.51, 0.51, 0.51 ; + + fates_grperc = 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, + 0.11, 0.11 ; + + fates_hydro_avuln_gs = 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, + 2.5, 2.5 ; + + fates_hydro_avuln_node = + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ; + + fates_hydro_epsil_node = + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 ; + + fates_hydro_fcap_node = + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, + 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_hydro_k_lwp = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_hydro_kmax_node = + -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999 ; + + fates_hydro_p50_gs = -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, + -1.5, -1.5, -1.5 ; + + fates_hydro_p50_node = + -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, + -2.25, -2.25, + -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, + -2.25, -2.25, + -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, + -2.25, -2.25, + -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, + -2.25, -2.25 ; + + fates_hydro_p_taper = 0.333, 0.333, 0.333, 0.333, 0.333, 0.333, 0.333, + 0.333, 0.333, 0.333, 0.333, 0.333 ; + + fates_hydro_pinot_node = + -1.465984, -1.465984, -1.465984, -1.465984, -1.465984, -1.465984, + -1.465984, -1.465984, -1.465984, -1.465984, -1.465984, -1.465984, + -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, + -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, + -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, + -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, + -1.043478, -1.043478, -1.043478, -1.043478, -1.043478, -1.043478, + -1.043478, -1.043478, -1.043478, -1.043478, -1.043478, -1.043478 ; + + fates_hydro_pitlp_node = + -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, + -1.67, -1.67, + -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, + -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, + -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2 ; + + fates_hydro_resid_node = + 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, + 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, + 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, + 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11 ; + + fates_hydro_rfrac_stem = 0.625, 0.625, 0.625, 0.625, 0.625, 0.625, 0.625, + 0.625, 0.625, 0.625, 0.625, 0.625 ; + + fates_hydro_rs2 = 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, + 0.0001, 0.0001, 0.0001, 0.0001, 0.0001 ; + + fates_hydro_srl = 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25 ; + + fates_hydro_thetas_node = + 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, + 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, + 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, + 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75 ; + + fates_hydro_vg_alpha_node = + 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.005, 0.005, 0.005, 0.005, 0.005, + 0.005, 0.005, + 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.005, 0.005, 0.005, 0.005, 0.005, + 0.005, 0.005, + 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.005, 0.005, 0.005, 0.005, 0.005, + 0.005, 0.005, + 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.005, 0.005, 0.005, 0.005, 0.005, + 0.005, 0.005 ; + + fates_hydro_vg_m_node = + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5 ; + + fates_hydro_vg_n_node = + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ; + + fates_leaf_c3psn = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 ; + + fates_leaf_jmaxha = 43540, 43540, 43540, 43540, 43540, 43540, 43540, 43540, + 43540, 43540, 43540, 43540 ; + + fates_leaf_jmaxhd = 152040, 152040, 152040, 152040, 152040, 152040, 152040, + 152040, 152040, 152040, 152040, 152040 ; + + fates_leaf_jmaxse = 495, 495, 495, 495, 495, 495, 495, 495, 495, 495, 495, + 495 ; + + fates_leaf_slamax = 0.0954, 0.0954, 0.0954, 0.0954, 0.0954, 0.0954, 0.012, + 0.03, 0.03, 0.03, 0.03, 0.03 ; + + fates_leaf_slatop = 0.012, 0.005, 0.024, 0.009, 0.03, 0.03, 0.012, 0.03, + 0.03, 0.03, 0.03, 0.03 ; + + fates_leaf_stomatal_intercept = 10000, 10000, 10000, 10000, 10000, 10000, + 10000, 10000, 10000, 10000, 10000, 40000 ; + + fates_leaf_stomatal_slope_ballberry = 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 ; + + fates_leaf_stomatal_slope_medlyn = 4.1, 2.3, 2.3, 4.1, 4.4, 4.4, 4.7, 4.7, + 4.7, 2.2, 5.3, 1.6 ; + + fates_leaf_vcmax25top = + 50, 62, 39, 61, 41, 58, 62, 54, 54, 78, 78, 78 ; + + fates_leaf_vcmaxha = 65330, 65330, 65330, 65330, 65330, 65330, 65330, 65330, + 65330, 65330, 65330, 65330 ; + + fates_leaf_vcmaxhd = 149250, 149250, 149250, 149250, 149250, 149250, 149250, + 149250, 149250, 149250, 149250, 149250 ; + + fates_leaf_vcmaxse = 485, 485, 485, 485, 485, 485, 485, 485, 485, 485, 485, + 485 ; + + fates_maintresp_leaf_atkin2017_baserate = 1.756, 1.4995, 1.4995, 1.756, + 1.756, 1.756, 2.0749, 2.0749, 2.0749, 2.1956, 2.1956, 2.1956 ; + + fates_maintresp_leaf_ryan1991_baserate = 2.525e-06, 2.525e-06, 2.525e-06, + 2.525e-06, 2.525e-06, 2.525e-06, 2.525e-06, 2.525e-06, 2.525e-06, + 2.525e-06, 2.525e-06, 2.525e-06 ; + + fates_maintresp_reduction_curvature = 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, + 0.01, 0.01, 0.01, 0.01, 0.01, 0.01 ; + + fates_maintresp_reduction_intercept = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_mort_bmort = 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, + 0.014, 0.014, 0.014, 0.014 ; + + fates_mort_freezetol = 2.5, -55, -80, -30, 2.5, -80, -60, -10, -80, -80, + -20, 2.5 ; + + fates_mort_hf_flc_threshold = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5 ; + + fates_mort_hf_sm_threshold = 1e-06, 1e-06, 1e-06, 1e-06, 1e-06, 1e-06, + 1e-06, 1e-06, 1e-06, 1e-06, 1e-06, 1e-06 ; + + fates_mort_ip_age_senescence = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_mort_ip_size_senescence = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_mort_prescribed_canopy = 0.0194, 0.0194, 0.0194, 0.0194, 0.0194, + 0.0194, 0.0194, 0.0194, 0.0194, 0.0194, 0.0194, 0.0194 ; + + fates_mort_prescribed_understory = 0.025, 0.025, 0.025, 0.025, 0.025, 0.025, + 0.025, 0.025, 0.025, 0.025, 0.025, 0.025 ; + + fates_mort_r_age_senescence = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_mort_r_size_senescence = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_mort_scalar_coldstress = 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 ; + + fates_mort_scalar_cstarvation = 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, + 0.6, 0.6, 0.6 ; + + fates_mort_scalar_hydrfailure = 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, + 0.6, 0.6, 0.6 ; + + fates_nonhydro_smpsc = -255000, -255000, -255000, -255000, -255000, -255000, + -255000, -255000, -255000, -255000, -255000, -255000 ; + + fates_nonhydro_smpso = -66000, -66000, -66000, -66000, -66000, -66000, + -66000, -66000, -66000, -66000, -66000, -66000 ; + + fates_phen_cold_size_threshold = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_phen_evergreen = 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 ; + + fates_phen_flush_fraction = _, _, 0.5, _, 0.5, 0.5, _, 0.5, 0.5, 0.5, 0.5, + 0.5 ; + + fates_phen_fnrt_drop_frac = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_phen_season_decid = 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0 ; + + fates_phen_stem_drop_fraction = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_phen_stress_decid = 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1 ; + + fates_prescribed_npp_canopy = 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, + 0.4, 0.4, 0.4 ; + + fates_prescribed_npp_understory = 0.03125, 0.03125, 0.03125, 0.03125, + 0.03125, 0.03125, 0.03125, 0.03125, 0.03125, 0.03125, 0.03125, 0.03125 ; + + fates_rad_leaf_clumping_index = 0.85, 0.85, 0.8, 0.85, 0.85, 0.9, 0.85, 0.9, + 0.9, 0.75, 0.75, 0.75 ; + + fates_rad_leaf_rhonir = 0.46, 0.41, 0.39, 0.46, 0.41, 0.41, 0.46, 0.41, + 0.41, 0.28, 0.28, 0.28 ; + + fates_rad_leaf_rhovis = 0.11, 0.09, 0.08, 0.11, 0.08, 0.08, 0.11, 0.08, + 0.08, 0.05, 0.05, 0.05 ; + + fates_rad_leaf_taunir = 0.33, 0.32, 0.42, 0.33, 0.43, 0.43, 0.33, 0.43, + 0.43, 0.4, 0.4, 0.4 ; + + fates_rad_leaf_tauvis = 0.06, 0.04, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, + 0.06, 0.05, 0.05, 0.05 ; + + fates_rad_leaf_xl = 0.32, 0.01, 0.01, 0.32, 0.2, 0.59, 0.32, 0.59, 0.59, + -0.23, -0.23, -0.23 ; + + fates_rad_stem_rhonir = 0.49, 0.36, 0.36, 0.49, 0.49, 0.49, 0.49, 0.49, + 0.49, 0.53, 0.53, 0.53 ; + + fates_rad_stem_rhovis = 0.21, 0.12, 0.12, 0.21, 0.21, 0.21, 0.21, 0.21, + 0.21, 0.31, 0.31, 0.31 ; + + fates_rad_stem_taunir = 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, + 0.001, 0.001, 0.25, 0.25, 0.25 ; + + fates_rad_stem_tauvis = 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, + 0.001, 0.001, 0.12, 0.12, 0.12 ; + + fates_recruit_height_min = 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 0.2, 0.2, 0.2, + 0.125, 0.125, 0.125 ; + + fates_recruit_init_density = 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, + 0.2, 0.2, 0.2 ; + + fates_recruit_prescribed_rate = 0.02, 0.02, 0.02, 0.02, 0.02, 0.02, 0.02, + 0.02, 0.02, 0.02, 0.02, 0.02 ; + + fates_recruit_seed_alloc = 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, + 0.1, 0.1 ; + + fates_recruit_seed_alloc_mature = 0, 0, 0, 0, 0, 0, 0.9, 0.9, 0.9, 0.9, 0.9, + 0.9 ; + + fates_recruit_seed_dbh_repro_threshold = 90, 80, 80, 80, 90, 80, 3, 3, 2, + 0.35, 0.35, 0.35 ; + + fates_recruit_seed_germination_rate = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5 ; + + fates_recruit_seed_supplement = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_stoich_nitr = + 0.033, 0.029, 0.04, 0.033, 0.04, 0.04, 0.033, 0.04, 0.04, 0.04, 0.04, 0.04, + 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, + 0.024, 0.024, + 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, + 1e-08, 1e-08, + 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, + 0.0047, 0.0047, 0.0047 ; + + fates_stoich_phos = + 0.0033, 0.0029, 0.004, 0.0033, 0.004, 0.004, 0.0033, 0.004, 0.004, 0.004, + 0.004, 0.004, + 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, + 0.0024, 0.0024, 0.0024, + 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, + 1e-09, 1e-09, + 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, + 0.00047, 0.00047, 0.00047, 0.00047 ; + + fates_trim_inc = 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, + 0.03, 0.03 ; + + fates_trim_limit = 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3 ; + + fates_turb_displar = 0.67, 0.67, 0.67, 0.67, 0.67, 0.67, 0.67, 0.67, 0.67, + 0.67, 0.67, 0.67 ; + + fates_turb_leaf_diameter = 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, + 0.04, 0.04, 0.04, 0.04 ; + + fates_turb_z0mr = 0.055, 0.055, 0.055, 0.055, 0.055, 0.055, 0.055, 0.055, + 0.055, 0.055, 0.055, 0.055 ; + + fates_turnover_branch = 150, 150, 150, 150, 150, 150, 150, 150, 150, 0, 0, 0 ; + + fates_turnover_fnrt = 1, 2, 1, 1.5, 1, 1, 1.5, 1, 1, 1, 1, 1 ; + + fates_turnover_leaf = + 1.5, 4, 1, 1.5, 1, 1, 1.5, 1, 1, 1, 1, 1 ; + + fates_turnover_senleaf_fdrought = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_wood_density = 0.7, 0.4, 0.7, 0.53, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, + 0.7 ; + + fates_woody = 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 ; + + fates_hlm_pft_map = + 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 ; + + fates_fire_FBD = 15.4, 16.8, 19.6, 999, 4, 4 ; + + fates_fire_low_moisture_Coeff = 1.12, 1.09, 0.98, 0.8, 1.15, 1.15 ; + + fates_fire_low_moisture_Slope = 0.62, 0.72, 0.85, 0.8, 0.62, 0.62 ; + + fates_fire_mid_moisture = 0.72, 0.51, 0.38, 1, 0.8, 0.8 ; + + fates_fire_mid_moisture_Coeff = 2.35, 1.47, 1.06, 0.8, 3.2, 3.2 ; + + fates_fire_mid_moisture_Slope = 2.35, 1.47, 1.06, 0.8, 3.2, 3.2 ; + + fates_fire_min_moisture = 0.18, 0.12, 0, 0, 0.24, 0.24 ; + + fates_fire_SAV = 13, 3.58, 0.98, 0.2, 66, 66 ; + + fates_frag_maxdecomp = 0.52, 0.383, 0.383, 0.19, 1, 999 ; + + fates_frag_cwd_frac = 0.045, 0.075, 0.21, 0.67 ; + + fates_canopy_closure_thresh = 0.8 ; + + fates_cnp_eca_plant_escalar = 1.25e-05 ; + + fates_cohort_age_fusion_tol = 0.08 ; + + fates_cohort_size_fusion_tol = 0.08 ; + + fates_comp_excln = 3 ; + + fates_damage_canopy_layer_code = 1 ; + + fates_damage_event_code = 1 ; + + fates_dev_arbitrary = _ ; + + fates_fire_active_crown_fire = 0 ; + + fates_fire_cg_strikes = 0.2 ; + + fates_fire_drying_ratio = 66000 ; + + fates_fire_durat_slope = -11.06 ; + + fates_fire_fdi_a = 17.62 ; + + fates_fire_fdi_alpha = 0.00037 ; + + fates_fire_fdi_b = 243.12 ; + + fates_fire_fuel_energy = 18000 ; + + fates_fire_max_durat = 240 ; + + fates_fire_miner_damp = 0.41739 ; + + fates_fire_miner_total = 0.055 ; + + fates_fire_nignitions = 15 ; + + fates_fire_part_dens = 513 ; + + fates_fire_threshold = 50 ; + + fates_frag_cwd_fcel = 0.76 ; + + fates_frag_cwd_flig = 0.24 ; + + fates_hydro_kmax_rsurf1 = 20 ; + + fates_hydro_kmax_rsurf2 = 0.0001 ; + + fates_hydro_psi0 = 0 ; + + fates_hydro_psicap = -0.6 ; + + fates_hydro_solver = 1 ; + + fates_landuse_logging_coll_under_frac = 0.55983 ; + + fates_landuse_logging_collateral_frac = 0.05 ; + + fates_landuse_logging_dbhmax = _ ; + + fates_landuse_logging_dbhmax_infra = 35 ; + + fates_landuse_logging_dbhmin = 50 ; + + fates_landuse_logging_direct_frac = 0.15 ; + + fates_landuse_logging_event_code = -30 ; + + fates_landuse_logging_export_frac = 0.8 ; + + fates_landuse_logging_mechanical_frac = 0.05 ; + + fates_landuse_pprodharv10_forest_mean = 0.8125 ; + + fates_leaf_photo_temp_acclim_timescale = 30 ; + + fates_leaf_photo_tempsens_model = 1 ; + + fates_leaf_stomatal_assim_model = 1 ; + + fates_leaf_stomatal_model = 1 ; + + fates_leaf_theta_cj_c3 = 0.999 ; + + fates_leaf_theta_cj_c4 = 0.999 ; + + fates_maintresp_leaf_model = 1 ; + + fates_maintresp_nonleaf_baserate = 2.525e-06 ; + + fates_maxcohort = 100 ; + + fates_maxpatch_primary = 10 ; + + fates_maxpatch_secondary = 4 ; + + fates_mort_disturb_frac = 1 ; + + fates_mort_understorey_death = 0.55983 ; + + fates_patch_fusion_tol = 0.05 ; + + fates_phen_chilltemp = 5 ; + + fates_phen_coldtemp = 7.5 ; + + fates_phen_drought_model = 0 ; + + fates_phen_drought_threshold = 0.15 ; + + fates_phen_gddthresh_a = -68 ; + + fates_phen_gddthresh_b = 638 ; + + fates_phen_gddthresh_c = -0.01 ; + + fates_phen_mindaysoff = 100 ; + + fates_phen_mindayson = 90 ; + + fates_phen_moist_threshold = 0.18 ; + + fates_phen_ncolddayslim = 5 ; + + fates_q10_froz = 1.5 ; + + fates_q10_mr = 1.5 ; + + fates_soil_salinity = 0.4 ; + + fates_vai_top_bin_width = 1 ; + + fates_vai_width_increase_factor = 1 ; +} diff --git a/parameter_files/archive/api25.2.0_031723_pr984.xml b/parameter_files/archive/api25.2.0_031723_pr984.xml new file mode 100644 index 0000000000..fb1f975f65 --- /dev/null +++ b/parameter_files/archive/api25.2.0_031723_pr984.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + archive/api25.2.0_031723_fates_params_default.cdl + fates_params_default.cdl + 1,2,3,4,5,6,7,8,9,10,11,12 + + + fates_leaf_photo_temp_acclim_thome_time + scalar + years + Length of the window for the long-term (i.e. T_home in Kumarathunge et al 2019) exponential moving average (ema) of vegetation temperature used in photosynthesis temperature acclimation (used if fates_leaf_photo_tempsens_model = 2) + 30 + + + activation energy for jmax. NOTE: if fates_leaf_photo_tempsens_model=2 then these values are NOT USED + + + deactivation energy for jmax. NOTE: if fates_leaf_photo_tempsens_model=2 then these values are NOT USED + + + entropy term for jmax. NOTE: if fates_leaf_photo_tempsens_model=2 then these values are NOT USED + + + activation energy for vcmax. NOTE: if fates_leaf_photo_tempsens_model=2 then these values are NOT USED + + + deactivation energy for vcmax. NOTE: if fates_leaf_photo_tempsens_model=2 then these values are NOT USED + + + entropy term for vcmax. NOTE: if fates_leaf_photo_tempsens_model=2 then these values are NOT USED + + + Length of the window for the exponential moving average (ema) of vegetation temperature used in photosynthesis temperature acclimation (used if fates_maintresp_leaf_model=2 or fates_leaf_photo_tempsens_model = 2) + + + switch for choosing the model that defines the temperature sensitivity of photosynthetic parameters (vcmax, jmax). 1=non-acclimating; 2=Kumarathunge et al 2019 + + + switch for choosing between maintenance respiration models. 1=Ryan (1991), 2=Atkin et al., (2017) + + + diff --git a/parameter_files/archive/api25.3.0_032223_fates_params_default.cdl b/parameter_files/archive/api25.3.0_032223_fates_params_default.cdl new file mode 100644 index 0000000000..fd5f0d6dd3 --- /dev/null +++ b/parameter_files/archive/api25.3.0_032223_fates_params_default.cdl @@ -0,0 +1,1559 @@ +netcdf fates_params_default { +dimensions: + fates_NCWD = 4 ; + fates_history_age_bins = 7 ; + fates_history_coage_bins = 2 ; + fates_history_damage_bins = 2 ; + fates_history_height_bins = 6 ; + fates_history_size_bins = 13 ; + fates_hlm_pftno = 14 ; + fates_hydr_organs = 4 ; + fates_leafage_class = 1 ; + fates_litterclass = 6 ; + fates_pft = 12 ; + fates_plant_organs = 4 ; + fates_string_length = 60 ; +variables: + double fates_history_ageclass_bin_edges(fates_history_age_bins) ; + fates_history_ageclass_bin_edges:units = "yr" ; + fates_history_ageclass_bin_edges:long_name = "Lower edges for age class bins used in age-resolved patch history output" ; + double fates_history_coageclass_bin_edges(fates_history_coage_bins) ; + fates_history_coageclass_bin_edges:units = "years" ; + fates_history_coageclass_bin_edges:long_name = "Lower edges for cohort age class bins used in cohort age resolved history output" ; + double fates_history_height_bin_edges(fates_history_height_bins) ; + fates_history_height_bin_edges:units = "m" ; + fates_history_height_bin_edges:long_name = "Lower edges for height bins used in height-resolved history output" ; + double fates_history_damage_bin_edges(fates_history_damage_bins) ; + fates_history_damage_bin_edges:units = "% crown loss" ; + fates_history_damage_bin_edges:long_name = "Lower edges for damage class bins used in cohort history output" ; + double fates_history_sizeclass_bin_edges(fates_history_size_bins) ; + fates_history_sizeclass_bin_edges:units = "cm" ; + fates_history_sizeclass_bin_edges:long_name = "Lower edges for DBH size class bins used in size-resolved cohort history output" ; + double fates_alloc_organ_id(fates_plant_organs) ; + fates_alloc_organ_id:units = "unitless" ; + fates_alloc_organ_id:long_name = "This is the global index that the organ in this file is associated with, values match those in parteh/PRTGenericMod.F90" ; + double fates_hydro_htftype_node(fates_hydr_organs) ; + fates_hydro_htftype_node:units = "unitless" ; + fates_hydro_htftype_node:long_name = "Switch that defines the hydraulic transfer functions for each organ." ; + char fates_pftname(fates_pft, fates_string_length) ; + fates_pftname:units = "unitless - string" ; + fates_pftname:long_name = "Description of plant type" ; + char fates_hydro_organ_name(fates_hydr_organs, fates_string_length) ; + fates_hydro_organ_name:units = "unitless - string" ; + fates_hydro_organ_name:long_name = "Name of plant hydraulics organs (DONT CHANGE, order matches media list in FatesHydraulicsMemMod.F90)" ; + char fates_alloc_organ_name(fates_plant_organs, fates_string_length) ; + fates_alloc_organ_name:units = "unitless - string" ; + fates_alloc_organ_name:long_name = "Name of plant organs (with alloc_organ_id, must match PRTGenericMod.F90)" ; + char fates_litterclass_name(fates_litterclass, fates_string_length) ; + fates_litterclass_name:units = "unitless - string" ; + fates_litterclass_name:long_name = "Name of the litter classes, for variables associated with dimension fates_litterclass" ; + double fates_alloc_organ_priority(fates_plant_organs, fates_pft) ; + fates_alloc_organ_priority:units = "index" ; + fates_alloc_organ_priority:long_name = "Priority level for allocation, 1: replaces turnover from storage, 2: same priority as storage use/replacement, 3: ascending in order of least importance" ; + double fates_alloc_storage_cushion(fates_pft) ; + fates_alloc_storage_cushion:units = "fraction" ; + fates_alloc_storage_cushion:long_name = "maximum size of storage C pool, relative to maximum size of leaf C pool" ; + double fates_alloc_store_priority_frac(fates_pft) ; + fates_alloc_store_priority_frac:units = "unitless" ; + fates_alloc_store_priority_frac:long_name = "for high-priority organs, the fraction of their turnover demand that is gauranteed to be replaced, and if need-be by storage" ; + double fates_allom_agb1(fates_pft) ; + fates_allom_agb1:units = "variable" ; + fates_allom_agb1:long_name = "Parameter 1 for agb allometry" ; + double fates_allom_agb2(fates_pft) ; + fates_allom_agb2:units = "variable" ; + fates_allom_agb2:long_name = "Parameter 2 for agb allometry" ; + double fates_allom_agb3(fates_pft) ; + fates_allom_agb3:units = "variable" ; + fates_allom_agb3:long_name = "Parameter 3 for agb allometry" ; + double fates_allom_agb4(fates_pft) ; + fates_allom_agb4:units = "variable" ; + fates_allom_agb4:long_name = "Parameter 4 for agb allometry" ; + double fates_allom_agb_frac(fates_pft) ; + fates_allom_agb_frac:units = "fraction" ; + fates_allom_agb_frac:long_name = "Fraction of woody biomass that is above ground" ; + double fates_allom_amode(fates_pft) ; + fates_allom_amode:units = "index" ; + fates_allom_amode:long_name = "AGB allometry function index." ; + double fates_allom_blca_expnt_diff(fates_pft) ; + fates_allom_blca_expnt_diff:units = "unitless" ; + fates_allom_blca_expnt_diff:long_name = "difference between allometric DBH:bleaf and DBH:crown area exponents" ; + double fates_allom_cmode(fates_pft) ; + fates_allom_cmode:units = "index" ; + fates_allom_cmode:long_name = "coarse root biomass allometry function index." ; + double fates_allom_crown_depth_frac(fates_pft) ; + fates_allom_crown_depth_frac:units = "fraction" ; + fates_allom_crown_depth_frac:long_name = "the depth of a cohort crown as a fraction of its height" ; + double fates_allom_d2bl1(fates_pft) ; + fates_allom_d2bl1:units = "variable" ; + fates_allom_d2bl1:long_name = "Parameter 1 for d2bl allometry" ; + double fates_allom_d2bl2(fates_pft) ; + fates_allom_d2bl2:units = "variable" ; + fates_allom_d2bl2:long_name = "Parameter 2 for d2bl allometry" ; + double fates_allom_d2bl3(fates_pft) ; + fates_allom_d2bl3:units = "unitless" ; + fates_allom_d2bl3:long_name = "Parameter 3 for d2bl allometry" ; + double fates_allom_d2ca_coefficient_max(fates_pft) ; + fates_allom_d2ca_coefficient_max:units = "m2 cm^(-1/beta)" ; + fates_allom_d2ca_coefficient_max:long_name = "max (savanna) dbh to area multiplier factor where: area = n*d2ca_coeff*dbh^beta" ; + double fates_allom_d2ca_coefficient_min(fates_pft) ; + fates_allom_d2ca_coefficient_min:units = "m2 cm^(-1/beta)" ; + fates_allom_d2ca_coefficient_min:long_name = "min (forest) dbh to area multiplier factor where: area = n*d2ca_coeff*dbh^beta" ; + double fates_allom_d2h1(fates_pft) ; + fates_allom_d2h1:units = "variable" ; + fates_allom_d2h1:long_name = "Parameter 1 for d2h allometry (intercept, or c)" ; + double fates_allom_d2h2(fates_pft) ; + fates_allom_d2h2:units = "variable" ; + fates_allom_d2h2:long_name = "Parameter 2 for d2h allometry (slope, or m)" ; + double fates_allom_d2h3(fates_pft) ; + fates_allom_d2h3:units = "variable" ; + fates_allom_d2h3:long_name = "Parameter 3 for d2h allometry (optional)" ; + double fates_allom_dbh_maxheight(fates_pft) ; + fates_allom_dbh_maxheight:units = "cm" ; + fates_allom_dbh_maxheight:long_name = "the diameter (if any) corresponding to maximum height, diameters may increase beyond this" ; + double fates_allom_fmode(fates_pft) ; + fates_allom_fmode:units = "index" ; + fates_allom_fmode:long_name = "fine root biomass allometry function index." ; + double fates_allom_fnrt_prof_a(fates_pft) ; + fates_allom_fnrt_prof_a:units = "unitless" ; + fates_allom_fnrt_prof_a:long_name = "Fine root profile function, parameter a" ; + double fates_allom_fnrt_prof_b(fates_pft) ; + fates_allom_fnrt_prof_b:units = "unitless" ; + fates_allom_fnrt_prof_b:long_name = "Fine root profile function, parameter b" ; + double fates_allom_fnrt_prof_mode(fates_pft) ; + fates_allom_fnrt_prof_mode:units = "index" ; + fates_allom_fnrt_prof_mode:long_name = "Index to select fine root profile function: 1) Jackson Beta, 2) 1-param exponential 3) 2-param exponential" ; + double fates_allom_frbstor_repro(fates_pft) ; + fates_allom_frbstor_repro:units = "fraction" ; + fates_allom_frbstor_repro:long_name = "fraction of bstore goes to reproduction after plant dies" ; + double fates_allom_hmode(fates_pft) ; + fates_allom_hmode:units = "index" ; + fates_allom_hmode:long_name = "height allometry function index." ; + double fates_allom_l2fr(fates_pft) ; + fates_allom_l2fr:units = "gC/gC" ; + fates_allom_l2fr:long_name = "Allocation parameter: fine root C per leaf C" ; + double fates_allom_la_per_sa_int(fates_pft) ; + fates_allom_la_per_sa_int:units = "m2/cm2" ; + fates_allom_la_per_sa_int:long_name = "Leaf area per sapwood area, intercept" ; + double fates_allom_la_per_sa_slp(fates_pft) ; + fates_allom_la_per_sa_slp:units = "m2/cm2/m" ; + fates_allom_la_per_sa_slp:long_name = "Leaf area per sapwood area rate of change with height, slope (optional)" ; + double fates_allom_lmode(fates_pft) ; + fates_allom_lmode:units = "index" ; + fates_allom_lmode:long_name = "leaf biomass allometry function index." ; + double fates_allom_sai_scaler(fates_pft) ; + fates_allom_sai_scaler:units = "m2/m2" ; + fates_allom_sai_scaler:long_name = "allometric ratio of SAI per LAI" ; + double fates_allom_smode(fates_pft) ; + fates_allom_smode:units = "index" ; + fates_allom_smode:long_name = "sapwood allometry function index." ; + double fates_allom_stmode(fates_pft) ; + fates_allom_stmode:units = "index" ; + fates_allom_stmode:long_name = "storage allometry function index: 1) Storage proportional to leaf biomass (with trimming), 2) Storage proportional to maximum leaf biomass (not trimmed)" ; + double fates_allom_zroot_k(fates_pft) ; + fates_allom_zroot_k:units = "unitless" ; + fates_allom_zroot_k:long_name = "scale coefficient of logistic rooting depth model" ; + double fates_allom_zroot_max_dbh(fates_pft) ; + fates_allom_zroot_max_dbh:units = "cm" ; + fates_allom_zroot_max_dbh:long_name = "dbh at which a plant reaches the maximum value for its maximum rooting depth" ; + double fates_allom_zroot_max_z(fates_pft) ; + fates_allom_zroot_max_z:units = "m" ; + fates_allom_zroot_max_z:long_name = "the maximum rooting depth defined at dbh = fates_allom_zroot_max_dbh. note: max_z=min_z=large, sets rooting depth to soil depth" ; + double fates_allom_zroot_min_dbh(fates_pft) ; + fates_allom_zroot_min_dbh:units = "cm" ; + fates_allom_zroot_min_dbh:long_name = "dbh at which the maximum rooting depth for a recruit is defined" ; + double fates_allom_zroot_min_z(fates_pft) ; + fates_allom_zroot_min_z:units = "m" ; + fates_allom_zroot_min_z:long_name = "the maximum rooting depth defined at dbh = fates_allom_zroot_min_dbh. note: max_z=min_z=large, sets rooting depth to soil depth" ; + double fates_c2b(fates_pft) ; + fates_c2b:units = "ratio" ; + fates_c2b:long_name = "Carbon to biomass multiplier of bulk structural tissues" ; + double fates_cnp_eca_alpha_ptase(fates_pft) ; + fates_cnp_eca_alpha_ptase:units = "g/m3" ; + fates_cnp_eca_alpha_ptase:long_name = "fraction of P from ptase activity sent directly to plant (ECA)" ; + double fates_cnp_eca_decompmicc(fates_pft) ; + fates_cnp_eca_decompmicc:units = "gC/m3" ; + fates_cnp_eca_decompmicc:long_name = "maximum soil microbial decomposer biomass found over depth (will be applied at a reference depth w/ exponential attenuation) (ECA)" ; + double fates_cnp_eca_km_nh4(fates_pft) ; + fates_cnp_eca_km_nh4:units = "gN/m3" ; + fates_cnp_eca_km_nh4:long_name = "half-saturation constant for plant nh4 uptake (ECA)" ; + double fates_cnp_eca_km_no3(fates_pft) ; + fates_cnp_eca_km_no3:units = "gN/m3" ; + fates_cnp_eca_km_no3:long_name = "half-saturation constant for plant no3 uptake (ECA)" ; + double fates_cnp_eca_km_p(fates_pft) ; + fates_cnp_eca_km_p:units = "gP/m3" ; + fates_cnp_eca_km_p:long_name = "half-saturation constant for plant p uptake (ECA)" ; + double fates_cnp_eca_km_ptase(fates_pft) ; + fates_cnp_eca_km_ptase:units = "gP/m3" ; + fates_cnp_eca_km_ptase:long_name = "half-saturation constant for biochemical P (ECA)" ; + double fates_cnp_eca_lambda_ptase(fates_pft) ; + fates_cnp_eca_lambda_ptase:units = "g/m3" ; + fates_cnp_eca_lambda_ptase:long_name = "critical value for biochemical production (ECA)" ; + double fates_cnp_eca_vmax_ptase(fates_pft) ; + fates_cnp_eca_vmax_ptase:units = "gP/m2/s" ; + fates_cnp_eca_vmax_ptase:long_name = "maximum production rate for biochemical P (per m2) (ECA)" ; + double fates_cnp_nfix1(fates_pft) ; + fates_cnp_nfix1:units = "fraction" ; + fates_cnp_nfix1:long_name = "fractional surcharge added to maintenance respiration that drives symbiotic fixation" ; + double fates_cnp_nitr_store_ratio(fates_pft) ; + fates_cnp_nitr_store_ratio:units = "(gN/gN)" ; + fates_cnp_nitr_store_ratio:long_name = "storeable (labile) N, as a ratio compared to the N bound in cell structures of other organs (see code)" ; + double fates_cnp_phos_store_ratio(fates_pft) ; + fates_cnp_phos_store_ratio:units = "(gP/gP)" ; + fates_cnp_phos_store_ratio:long_name = "storeable (labile) P, as a ratio compared to the P bound in cell structures of other organs (see code)" ; + double fates_cnp_pid_kd(fates_pft) ; + fates_cnp_pid_kd:units = "unknown" ; + fates_cnp_pid_kd:long_name = "derivative constant of the PID controller on adaptive fine-root biomass" ; + double fates_cnp_pid_ki(fates_pft) ; + fates_cnp_pid_ki:units = "unknown" ; + fates_cnp_pid_ki:long_name = "integral constant of the PID controller on adaptive fine-root biomass" ; + double fates_cnp_pid_kp(fates_pft) ; + fates_cnp_pid_kp:units = "unknown" ; + fates_cnp_pid_kp:long_name = "proportional constant of the PID controller on adaptive fine-root biomass" ; + double fates_cnp_prescribed_nuptake(fates_pft) ; + fates_cnp_prescribed_nuptake:units = "fraction" ; + fates_cnp_prescribed_nuptake:long_name = "Prescribed N uptake flux. 0=fully coupled simulation >0=prescribed (experimental)" ; + double fates_cnp_prescribed_puptake(fates_pft) ; + fates_cnp_prescribed_puptake:units = "fraction" ; + fates_cnp_prescribed_puptake:long_name = "Prescribed P uptake flux. 0=fully coupled simulation, >0=prescribed (experimental)" ; + double fates_cnp_store_ovrflw_frac(fates_pft) ; + fates_cnp_store_ovrflw_frac:units = "fraction" ; + fates_cnp_store_ovrflw_frac:long_name = "size of overflow storage (for excess C,N or P) as a fraction of storage target" ; + double fates_cnp_turnover_nitr_retrans(fates_plant_organs, fates_pft) ; + fates_cnp_turnover_nitr_retrans:units = "fraction" ; + fates_cnp_turnover_nitr_retrans:long_name = "retranslocation (reabsorbtion) fraction of nitrogen in turnover of scenescing tissues" ; + double fates_cnp_turnover_phos_retrans(fates_plant_organs, fates_pft) ; + fates_cnp_turnover_phos_retrans:units = "fraction" ; + fates_cnp_turnover_phos_retrans:long_name = "retranslocation (reabsorbtion) fraction of phosphorus in turnover of scenescing tissues" ; + double fates_cnp_vmax_nh4(fates_pft) ; + fates_cnp_vmax_nh4:units = "gN/gC/s" ; + fates_cnp_vmax_nh4:long_name = "maximum (potential) uptake rate of NH4 per gC of fineroot biomass (see main/EDPftvarcon.F90 vmax_nh4 for usage)" ; + double fates_cnp_vmax_no3(fates_pft) ; + fates_cnp_vmax_no3:units = "gN/gC/s" ; + fates_cnp_vmax_no3:long_name = "maximum (potential) uptake rate of NO3 per gC of fineroot biomass (see main/EDPftvarcon.F90 vmax_no3 for usage)" ; + double fates_cnp_vmax_p(fates_pft) ; + fates_cnp_vmax_p:units = "gP/gC/s" ; + fates_cnp_vmax_p:long_name = "maximum production rate for phosphorus (ECA and RD)" ; + double fates_damage_frac(fates_pft) ; + fates_damage_frac:units = "fraction" ; + fates_damage_frac:long_name = "fraction of cohort damaged in each damage event (event frequency specified in the is_it_damage_time subroutine)" ; + double fates_damage_mort_p1(fates_pft) ; + fates_damage_mort_p1:units = "fraction" ; + fates_damage_mort_p1:long_name = "inflection point of damage mortality function, a value of 0.8 means 50% mortality with 80% loss of crown, turn off with a large number" ; + double fates_damage_mort_p2(fates_pft) ; + fates_damage_mort_p2:units = "unitless" ; + fates_damage_mort_p2:long_name = "rate of mortality increase with damage" ; + double fates_damage_recovery_scalar(fates_pft) ; + fates_damage_recovery_scalar:units = "unitless" ; + fates_damage_recovery_scalar:long_name = "fraction of the cohort that recovers from damage" ; + double fates_dev_arbitrary_pft(fates_pft) ; + fates_dev_arbitrary_pft:units = "unknown" ; + fates_dev_arbitrary_pft:long_name = "Unassociated pft dimensioned free parameter that developers can use for testing arbitrary new hypotheses" ; + double fates_fire_alpha_SH(fates_pft) ; + fates_fire_alpha_SH:units = "m / (kw/m)**(2/3)" ; + fates_fire_alpha_SH:long_name = "spitfire parameter, alpha scorch height, Equation 16 Thonicke et al 2010" ; + double fates_fire_bark_scaler(fates_pft) ; + fates_fire_bark_scaler:units = "fraction" ; + fates_fire_bark_scaler:long_name = "the thickness of a cohorts bark as a fraction of its dbh" ; + double fates_fire_crown_kill(fates_pft) ; + fates_fire_crown_kill:units = "NA" ; + fates_fire_crown_kill:long_name = "fire parameter, see equation 22 in Thonicke et al 2010" ; + double fates_frag_fnrt_fcel(fates_pft) ; + fates_frag_fnrt_fcel:units = "fraction" ; + fates_frag_fnrt_fcel:long_name = "Fine root litter cellulose fraction" ; + double fates_frag_fnrt_flab(fates_pft) ; + fates_frag_fnrt_flab:units = "fraction" ; + fates_frag_fnrt_flab:long_name = "Fine root litter labile fraction" ; + double fates_frag_fnrt_flig(fates_pft) ; + fates_frag_fnrt_flig:units = "fraction" ; + fates_frag_fnrt_flig:long_name = "Fine root litter lignin fraction" ; + double fates_frag_leaf_fcel(fates_pft) ; + fates_frag_leaf_fcel:units = "fraction" ; + fates_frag_leaf_fcel:long_name = "Leaf litter cellulose fraction" ; + double fates_frag_leaf_flab(fates_pft) ; + fates_frag_leaf_flab:units = "fraction" ; + fates_frag_leaf_flab:long_name = "Leaf litter labile fraction" ; + double fates_frag_leaf_flig(fates_pft) ; + fates_frag_leaf_flig:units = "fraction" ; + fates_frag_leaf_flig:long_name = "Leaf litter lignin fraction" ; + double fates_frag_seed_decay_rate(fates_pft) ; + fates_frag_seed_decay_rate:units = "yr-1" ; + fates_frag_seed_decay_rate:long_name = "fraction of seeds that decay per year" ; + double fates_grperc(fates_pft) ; + fates_grperc:units = "unitless" ; + fates_grperc:long_name = "Growth respiration factor" ; + double fates_hydro_avuln_gs(fates_pft) ; + fates_hydro_avuln_gs:units = "unitless" ; + fates_hydro_avuln_gs:long_name = "shape parameter for stomatal control of water vapor exiting leaf" ; + double fates_hydro_avuln_node(fates_hydr_organs, fates_pft) ; + fates_hydro_avuln_node:units = "unitless" ; + fates_hydro_avuln_node:long_name = "xylem vulnerability curve shape parameter" ; + double fates_hydro_epsil_node(fates_hydr_organs, fates_pft) ; + fates_hydro_epsil_node:units = "MPa" ; + fates_hydro_epsil_node:long_name = "bulk elastic modulus" ; + double fates_hydro_fcap_node(fates_hydr_organs, fates_pft) ; + fates_hydro_fcap_node:units = "unitless" ; + fates_hydro_fcap_node:long_name = "fraction of non-residual water that is capillary in source" ; + double fates_hydro_k_lwp(fates_pft) ; + fates_hydro_k_lwp:units = "unitless" ; + fates_hydro_k_lwp:long_name = "inner leaf humidity scaling coefficient" ; + double fates_hydro_kmax_node(fates_hydr_organs, fates_pft) ; + fates_hydro_kmax_node:units = "kg/MPa/m/s" ; + fates_hydro_kmax_node:long_name = "maximum xylem conductivity per unit conducting xylem area" ; + double fates_hydro_p50_gs(fates_pft) ; + fates_hydro_p50_gs:units = "MPa" ; + fates_hydro_p50_gs:long_name = "water potential at 50% loss of stomatal conductance" ; + double fates_hydro_p50_node(fates_hydr_organs, fates_pft) ; + fates_hydro_p50_node:units = "MPa" ; + fates_hydro_p50_node:long_name = "xylem water potential at 50% loss of conductivity" ; + double fates_hydro_p_taper(fates_pft) ; + fates_hydro_p_taper:units = "unitless" ; + fates_hydro_p_taper:long_name = "xylem taper exponent" ; + double fates_hydro_pinot_node(fates_hydr_organs, fates_pft) ; + fates_hydro_pinot_node:units = "MPa" ; + fates_hydro_pinot_node:long_name = "osmotic potential at full turgor" ; + double fates_hydro_pitlp_node(fates_hydr_organs, fates_pft) ; + fates_hydro_pitlp_node:units = "MPa" ; + fates_hydro_pitlp_node:long_name = "turgor loss point" ; + double fates_hydro_resid_node(fates_hydr_organs, fates_pft) ; + fates_hydro_resid_node:units = "cm3/cm3" ; + fates_hydro_resid_node:long_name = "residual water conent" ; + double fates_hydro_rfrac_stem(fates_pft) ; + fates_hydro_rfrac_stem:units = "fraction" ; + fates_hydro_rfrac_stem:long_name = "fraction of total tree resistance from troot to canopy" ; + double fates_hydro_rs2(fates_pft) ; + fates_hydro_rs2:units = "m" ; + fates_hydro_rs2:long_name = "absorbing root radius" ; + double fates_hydro_srl(fates_pft) ; + fates_hydro_srl:units = "m g-1" ; + fates_hydro_srl:long_name = "specific root length" ; + double fates_hydro_thetas_node(fates_hydr_organs, fates_pft) ; + fates_hydro_thetas_node:units = "cm3/cm3" ; + fates_hydro_thetas_node:long_name = "saturated water content" ; + double fates_hydro_vg_alpha_node(fates_hydr_organs, fates_pft) ; + fates_hydro_vg_alpha_node:units = "MPa-1" ; + fates_hydro_vg_alpha_node:long_name = "(used if hydr_htftype_node = 2), capillary length parameter in van Genuchten model" ; + double fates_hydro_vg_m_node(fates_hydr_organs, fates_pft) ; + fates_hydro_vg_m_node:units = "unitless" ; + fates_hydro_vg_m_node:long_name = "(used if hydr_htftype_node = 2),m in van Genuchten 1980 model, 2nd pore size distribution parameter" ; + double fates_hydro_vg_n_node(fates_hydr_organs, fates_pft) ; + fates_hydro_vg_n_node:units = "unitless" ; + fates_hydro_vg_n_node:long_name = "(used if hydr_htftype_node = 2),n in van Genuchten 1980 model, pore size distribution parameter" ; + double fates_leaf_c3psn(fates_pft) ; + fates_leaf_c3psn:units = "flag" ; + fates_leaf_c3psn:long_name = "Photosynthetic pathway (1=c3, 0=c4)" ; + double fates_leaf_jmaxha(fates_pft) ; + fates_leaf_jmaxha:units = "J/mol" ; + fates_leaf_jmaxha:long_name = "activation energy for jmax. NOTE: if fates_leaf_photo_tempsens_model=2 then these values are NOT USED" ; + double fates_leaf_jmaxhd(fates_pft) ; + fates_leaf_jmaxhd:units = "J/mol" ; + fates_leaf_jmaxhd:long_name = "deactivation energy for jmax. NOTE: if fates_leaf_photo_tempsens_model=2 then these values are NOT USED" ; + double fates_leaf_jmaxse(fates_pft) ; + fates_leaf_jmaxse:units = "J/mol/K" ; + fates_leaf_jmaxse:long_name = "entropy term for jmax. NOTE: if fates_leaf_photo_tempsens_model=2 then these values are NOT USED" ; + double fates_leaf_slamax(fates_pft) ; + fates_leaf_slamax:units = "m^2/gC" ; + fates_leaf_slamax:long_name = "Maximum Specific Leaf Area (SLA), even if under a dense canopy" ; + double fates_leaf_slatop(fates_pft) ; + fates_leaf_slatop:units = "m^2/gC" ; + fates_leaf_slatop:long_name = "Specific Leaf Area (SLA) at top of canopy, projected area basis" ; + double fates_leaf_stomatal_intercept(fates_pft) ; + fates_leaf_stomatal_intercept:units = "umol H2O/m**2/s" ; + fates_leaf_stomatal_intercept:long_name = "Minimum unstressed stomatal conductance for Ball-Berry model and Medlyn model" ; + double fates_leaf_stomatal_slope_ballberry(fates_pft) ; + fates_leaf_stomatal_slope_ballberry:units = "unitless" ; + fates_leaf_stomatal_slope_ballberry:long_name = "stomatal slope parameter, as per Ball-Berry" ; + double fates_leaf_stomatal_slope_medlyn(fates_pft) ; + fates_leaf_stomatal_slope_medlyn:units = "KPa**0.5" ; + fates_leaf_stomatal_slope_medlyn:long_name = "stomatal slope parameter, as per Medlyn" ; + double fates_leaf_vcmax25top(fates_leafage_class, fates_pft) ; + fates_leaf_vcmax25top:units = "umol CO2/m^2/s" ; + fates_leaf_vcmax25top:long_name = "maximum carboxylation rate of Rub. at 25C, canopy top" ; + double fates_leaf_vcmaxha(fates_pft) ; + fates_leaf_vcmaxha:units = "J/mol" ; + fates_leaf_vcmaxha:long_name = "activation energy for vcmax. NOTE: if fates_leaf_photo_tempsens_model=2 then these values are NOT USED" ; + double fates_leaf_vcmaxhd(fates_pft) ; + fates_leaf_vcmaxhd:units = "J/mol" ; + fates_leaf_vcmaxhd:long_name = "deactivation energy for vcmax. NOTE: if fates_leaf_photo_tempsens_model=2 then these values are NOT USED" ; + double fates_leaf_vcmaxse(fates_pft) ; + fates_leaf_vcmaxse:units = "J/mol/K" ; + fates_leaf_vcmaxse:long_name = "entropy term for vcmax. NOTE: if fates_leaf_photo_tempsens_model=2 then these values are NOT USED" ; + double fates_maintresp_leaf_atkin2017_baserate(fates_pft) ; + fates_maintresp_leaf_atkin2017_baserate:units = "umol CO2/m^2/s" ; + fates_maintresp_leaf_atkin2017_baserate:long_name = "Leaf maintenance respiration base rate parameter (r0) per Atkin et al 2017" ; + double fates_maintresp_leaf_ryan1991_baserate(fates_pft) ; + fates_maintresp_leaf_ryan1991_baserate:units = "gC/gN/s" ; + fates_maintresp_leaf_ryan1991_baserate:long_name = "Leaf maintenance respiration base rate per Ryan et al 1991" ; + double fates_maintresp_reduction_curvature(fates_pft) ; + fates_maintresp_reduction_curvature:units = "unitless (0-1)" ; + fates_maintresp_reduction_curvature:long_name = "curvature of MR reduction as f(carbon storage), 1=linear, 0=very curved" ; + double fates_maintresp_reduction_intercept(fates_pft) ; + fates_maintresp_reduction_intercept:units = "unitless (0-1)" ; + fates_maintresp_reduction_intercept:long_name = "intercept of MR reduction as f(carbon storage), 0=no throttling, 1=max throttling" ; + double fates_mort_bmort(fates_pft) ; + fates_mort_bmort:units = "1/yr" ; + fates_mort_bmort:long_name = "background mortality rate" ; + double fates_mort_freezetol(fates_pft) ; + fates_mort_freezetol:units = "degrees C" ; + fates_mort_freezetol:long_name = "minimum temperature tolerance" ; + double fates_mort_hf_flc_threshold(fates_pft) ; + fates_mort_hf_flc_threshold:units = "fraction" ; + fates_mort_hf_flc_threshold:long_name = "plant fractional loss of conductivity at which drought mortality begins for hydraulic model" ; + double fates_mort_hf_sm_threshold(fates_pft) ; + fates_mort_hf_sm_threshold:units = "unitless" ; + fates_mort_hf_sm_threshold:long_name = "soil moisture (btran units) at which drought mortality begins for non-hydraulic model" ; + double fates_mort_ip_age_senescence(fates_pft) ; + fates_mort_ip_age_senescence:units = "years" ; + fates_mort_ip_age_senescence:long_name = "Mortality cohort age senescence inflection point. If _ this mortality term is off. Setting this value turns on age dependent mortality. " ; + double fates_mort_ip_size_senescence(fates_pft) ; + fates_mort_ip_size_senescence:units = "dbh cm" ; + fates_mort_ip_size_senescence:long_name = "Mortality dbh senescence inflection point. If _ this mortality term is off. Setting this value turns on size dependent mortality" ; + double fates_mort_prescribed_canopy(fates_pft) ; + fates_mort_prescribed_canopy:units = "1/yr" ; + fates_mort_prescribed_canopy:long_name = "mortality rate of canopy trees for prescribed physiology mode" ; + double fates_mort_prescribed_understory(fates_pft) ; + fates_mort_prescribed_understory:units = "1/yr" ; + fates_mort_prescribed_understory:long_name = "mortality rate of understory trees for prescribed physiology mode" ; + double fates_mort_r_age_senescence(fates_pft) ; + fates_mort_r_age_senescence:units = "mortality rate year^-1" ; + fates_mort_r_age_senescence:long_name = "Mortality age senescence rate of change. Sensible range is around 0.03-0.06. Larger values givesteeper mortality curves." ; + double fates_mort_r_size_senescence(fates_pft) ; + fates_mort_r_size_senescence:units = "mortality rate dbh^-1" ; + fates_mort_r_size_senescence:long_name = "Mortality dbh senescence rate of change. Sensible range is around 0.03-0.06. Larger values give steeper mortality curves." ; + double fates_mort_scalar_coldstress(fates_pft) ; + fates_mort_scalar_coldstress:units = "1/yr" ; + fates_mort_scalar_coldstress:long_name = "maximum mortality rate from cold stress" ; + double fates_mort_scalar_cstarvation(fates_pft) ; + fates_mort_scalar_cstarvation:units = "1/yr" ; + fates_mort_scalar_cstarvation:long_name = "maximum mortality rate from carbon starvation" ; + double fates_mort_scalar_hydrfailure(fates_pft) ; + fates_mort_scalar_hydrfailure:units = "1/yr" ; + fates_mort_scalar_hydrfailure:long_name = "maximum mortality rate from hydraulic failure" ; + double fates_nonhydro_smpsc(fates_pft) ; + fates_nonhydro_smpsc:units = "mm" ; + fates_nonhydro_smpsc:long_name = "Soil water potential at full stomatal closure" ; + double fates_nonhydro_smpso(fates_pft) ; + fates_nonhydro_smpso:units = "mm" ; + fates_nonhydro_smpso:long_name = "Soil water potential at full stomatal opening" ; + double fates_phen_cold_size_threshold(fates_pft) ; + fates_phen_cold_size_threshold:units = "cm" ; + fates_phen_cold_size_threshold:long_name = "the dbh size above which will lead to phenology-related stem and leaf drop" ; + double fates_phen_evergreen(fates_pft) ; + fates_phen_evergreen:units = "logical flag" ; + fates_phen_evergreen:long_name = "Binary flag for evergreen leaf habit" ; + double fates_phen_flush_fraction(fates_pft) ; + fates_phen_flush_fraction:units = "fraction" ; + fates_phen_flush_fraction:long_name = "Upon bud-burst, the maximum fraction of storage carbon used for flushing leaves" ; + double fates_phen_fnrt_drop_frac(fates_pft) ; + fates_phen_fnrt_drop_frac:units = "fraction" ; + fates_phen_fnrt_drop_frac:long_name = "fraction of fine roots to drop during drought or cold" ; + double fates_phen_season_decid(fates_pft) ; + fates_phen_season_decid:units = "logical flag" ; + fates_phen_season_decid:long_name = "Binary flag for seasonal-deciduous leaf habit" ; + double fates_phen_stem_drop_fraction(fates_pft) ; + fates_phen_stem_drop_fraction:units = "fraction" ; + fates_phen_stem_drop_fraction:long_name = "fraction of stems to drop for non-woody species during drought/cold" ; + double fates_phen_stress_decid(fates_pft) ; + fates_phen_stress_decid:units = "logical flag" ; + fates_phen_stress_decid:long_name = "Binary flag for stress-deciduous leaf habit" ; + double fates_prescribed_npp_canopy(fates_pft) ; + fates_prescribed_npp_canopy:units = "kgC / m^2 / yr" ; + fates_prescribed_npp_canopy:long_name = "NPP per unit crown area of canopy trees for prescribed physiology mode" ; + double fates_prescribed_npp_understory(fates_pft) ; + fates_prescribed_npp_understory:units = "kgC / m^2 / yr" ; + fates_prescribed_npp_understory:long_name = "NPP per unit crown area of understory trees for prescribed physiology mode" ; + double fates_rad_leaf_clumping_index(fates_pft) ; + fates_rad_leaf_clumping_index:units = "fraction (0-1)" ; + fates_rad_leaf_clumping_index:long_name = "factor describing how much self-occlusion of leaf scattering elements decreases light interception" ; + double fates_rad_leaf_rhonir(fates_pft) ; + fates_rad_leaf_rhonir:units = "fraction" ; + fates_rad_leaf_rhonir:long_name = "Leaf reflectance: near-IR" ; + double fates_rad_leaf_rhovis(fates_pft) ; + fates_rad_leaf_rhovis:units = "fraction" ; + fates_rad_leaf_rhovis:long_name = "Leaf reflectance: visible" ; + double fates_rad_leaf_taunir(fates_pft) ; + fates_rad_leaf_taunir:units = "fraction" ; + fates_rad_leaf_taunir:long_name = "Leaf transmittance: near-IR" ; + double fates_rad_leaf_tauvis(fates_pft) ; + fates_rad_leaf_tauvis:units = "fraction" ; + fates_rad_leaf_tauvis:long_name = "Leaf transmittance: visible" ; + double fates_rad_leaf_xl(fates_pft) ; + fates_rad_leaf_xl:units = "unitless" ; + fates_rad_leaf_xl:long_name = "Leaf/stem orientation index" ; + double fates_rad_stem_rhonir(fates_pft) ; + fates_rad_stem_rhonir:units = "fraction" ; + fates_rad_stem_rhonir:long_name = "Stem reflectance: near-IR" ; + double fates_rad_stem_rhovis(fates_pft) ; + fates_rad_stem_rhovis:units = "fraction" ; + fates_rad_stem_rhovis:long_name = "Stem reflectance: visible" ; + double fates_rad_stem_taunir(fates_pft) ; + fates_rad_stem_taunir:units = "fraction" ; + fates_rad_stem_taunir:long_name = "Stem transmittance: near-IR" ; + double fates_rad_stem_tauvis(fates_pft) ; + fates_rad_stem_tauvis:units = "fraction" ; + fates_rad_stem_tauvis:long_name = "Stem transmittance: visible" ; + double fates_recruit_height_min(fates_pft) ; + fates_recruit_height_min:units = "m" ; + fates_recruit_height_min:long_name = "the minimum height (ie starting height) of a newly recruited plant" ; + double fates_recruit_init_density(fates_pft) ; + fates_recruit_init_density:units = "stems/m2" ; + fates_recruit_init_density:long_name = "initial seedling density for a cold-start near-bare-ground simulation. If negative sets initial tree dbh - only to be used in nocomp mode" ; + double fates_recruit_prescribed_rate(fates_pft) ; + fates_recruit_prescribed_rate:units = "n/yr" ; + fates_recruit_prescribed_rate:long_name = "recruitment rate for prescribed physiology mode" ; + double fates_recruit_seed_alloc(fates_pft) ; + fates_recruit_seed_alloc:units = "fraction" ; + fates_recruit_seed_alloc:long_name = "fraction of available carbon balance allocated to seeds" ; + double fates_recruit_seed_alloc_mature(fates_pft) ; + fates_recruit_seed_alloc_mature:units = "fraction" ; + fates_recruit_seed_alloc_mature:long_name = "fraction of available carbon balance allocated to seeds in mature plants (adds to fates_seed_alloc)" ; + double fates_recruit_seed_dbh_repro_threshold(fates_pft) ; + fates_recruit_seed_dbh_repro_threshold:units = "cm" ; + fates_recruit_seed_dbh_repro_threshold:long_name = "the diameter where the plant will increase allocation to the seed pool by fraction: fates_recruit_seed_alloc_mature" ; + double fates_recruit_seed_germination_rate(fates_pft) ; + fates_recruit_seed_germination_rate:units = "yr-1" ; + fates_recruit_seed_germination_rate:long_name = "fraction of seeds that germinate per year" ; + double fates_recruit_seed_supplement(fates_pft) ; + fates_recruit_seed_supplement:units = "KgC/m2/yr" ; + fates_recruit_seed_supplement:long_name = "Supplemental external seed rain source term (non-mass conserving)" ; + double fates_stoich_nitr(fates_plant_organs, fates_pft) ; + fates_stoich_nitr:units = "gN/gC" ; + fates_stoich_nitr:long_name = "target nitrogen concentration (ratio with carbon) of organs" ; + double fates_stoich_phos(fates_plant_organs, fates_pft) ; + fates_stoich_phos:units = "gP/gC" ; + fates_stoich_phos:long_name = "target phosphorus concentration (ratio with carbon) of organs" ; + double fates_trim_inc(fates_pft) ; + fates_trim_inc:units = "m2/m2" ; + fates_trim_inc:long_name = "Arbitrary incremental change in trimming function." ; + double fates_trim_limit(fates_pft) ; + fates_trim_limit:units = "m2/m2" ; + fates_trim_limit:long_name = "Arbitrary limit to reductions in leaf area with stress" ; + double fates_turb_displar(fates_pft) ; + fates_turb_displar:units = "unitless" ; + fates_turb_displar:long_name = "Ratio of displacement height to canopy top height" ; + double fates_turb_leaf_diameter(fates_pft) ; + fates_turb_leaf_diameter:units = "m" ; + fates_turb_leaf_diameter:long_name = "Characteristic leaf dimension" ; + double fates_turb_z0mr(fates_pft) ; + fates_turb_z0mr:units = "unitless" ; + fates_turb_z0mr:long_name = "Ratio of momentum roughness length to canopy top height" ; + double fates_turnover_branch(fates_pft) ; + fates_turnover_branch:units = "yr" ; + fates_turnover_branch:long_name = "turnover time of branches" ; + double fates_turnover_fnrt(fates_pft) ; + fates_turnover_fnrt:units = "yr" ; + fates_turnover_fnrt:long_name = "root longevity (alternatively, turnover time)" ; + double fates_turnover_leaf(fates_leafage_class, fates_pft) ; + fates_turnover_leaf:units = "yr" ; + fates_turnover_leaf:long_name = "Leaf longevity (ie turnover timescale)" ; + double fates_turnover_senleaf_fdrought(fates_pft) ; + fates_turnover_senleaf_fdrought:units = "unitless[0-1]" ; + fates_turnover_senleaf_fdrought:long_name = "multiplication factor for leaf longevity of senescent leaves during drought" ; + double fates_wood_density(fates_pft) ; + fates_wood_density:units = "g/cm3" ; + fates_wood_density:long_name = "mean density of woody tissue in plant" ; + double fates_woody(fates_pft) ; + fates_woody:units = "logical flag" ; + fates_woody:long_name = "Binary woody lifeform flag" ; + double fates_hlm_pft_map(fates_hlm_pftno, fates_pft) ; + fates_hlm_pft_map:units = "area fraction" ; + fates_hlm_pft_map:long_name = "In fixed biogeog mode, fraction of HLM area associated with each FATES PFT" ; + double fates_fire_FBD(fates_litterclass) ; + fates_fire_FBD:units = "kg Biomass/m3" ; + fates_fire_FBD:long_name = "fuel bulk density" ; + double fates_fire_low_moisture_Coeff(fates_litterclass) ; + fates_fire_low_moisture_Coeff:units = "NA" ; + fates_fire_low_moisture_Coeff:long_name = "spitfire parameter, equation B1 Thonicke et al 2010" ; + double fates_fire_low_moisture_Slope(fates_litterclass) ; + fates_fire_low_moisture_Slope:units = "NA" ; + fates_fire_low_moisture_Slope:long_name = "spitfire parameter, equation B1 Thonicke et al 2010" ; + double fates_fire_mid_moisture(fates_litterclass) ; + fates_fire_mid_moisture:units = "NA" ; + fates_fire_mid_moisture:long_name = "spitfire litter moisture threshold to be considered medium dry" ; + double fates_fire_mid_moisture_Coeff(fates_litterclass) ; + fates_fire_mid_moisture_Coeff:units = "NA" ; + fates_fire_mid_moisture_Coeff:long_name = "spitfire parameter, equation B1 Thonicke et al 2010" ; + double fates_fire_mid_moisture_Slope(fates_litterclass) ; + fates_fire_mid_moisture_Slope:units = "NA" ; + fates_fire_mid_moisture_Slope:long_name = "spitfire parameter, equation B1 Thonicke et al 2010" ; + double fates_fire_min_moisture(fates_litterclass) ; + fates_fire_min_moisture:units = "NA" ; + fates_fire_min_moisture:long_name = "spitfire litter moisture threshold to be considered very dry" ; + double fates_fire_SAV(fates_litterclass) ; + fates_fire_SAV:units = "cm-1" ; + fates_fire_SAV:long_name = "fuel surface area to volume ratio" ; + double fates_frag_maxdecomp(fates_litterclass) ; + fates_frag_maxdecomp:units = "yr-1" ; + fates_frag_maxdecomp:long_name = "maximum rate of litter & CWD transfer from non-decomposing class into decomposing class" ; + double fates_frag_cwd_frac(fates_NCWD) ; + fates_frag_cwd_frac:units = "fraction" ; + fates_frag_cwd_frac:long_name = "fraction of woody (bdead+bsw) biomass destined for CWD pool" ; + double fates_canopy_closure_thresh ; + fates_canopy_closure_thresh:units = "unitless" ; + fates_canopy_closure_thresh:long_name = "tree canopy coverage at which crown area allometry changes from savanna to forest value" ; + double fates_cnp_eca_plant_escalar ; + fates_cnp_eca_plant_escalar:units = "" ; + fates_cnp_eca_plant_escalar:long_name = "scaling factor for plant fine root biomass to calculate nutrient carrier enzyme abundance (ECA)" ; + double fates_cohort_age_fusion_tol ; + fates_cohort_age_fusion_tol:units = "unitless" ; + fates_cohort_age_fusion_tol:long_name = "minimum fraction in differece in cohort age between cohorts." ; + double fates_cohort_size_fusion_tol ; + fates_cohort_size_fusion_tol:units = "unitless" ; + fates_cohort_size_fusion_tol:long_name = "minimum fraction in difference in dbh between cohorts" ; + double fates_comp_excln ; + fates_comp_excln:units = "none" ; + fates_comp_excln:long_name = "IF POSITIVE: weighting factor (exponent on dbh) for canopy layer exclusion and promotion, IF NEGATIVE: switch to use deterministic height sorting" ; + double fates_damage_canopy_layer_code ; + fates_damage_canopy_layer_code:units = "unitless" ; + fates_damage_canopy_layer_code:long_name = "Integer code that decides whether damage affects canopy trees (1), understory trees (2)" ; + double fates_damage_event_code ; + fates_damage_event_code:units = "unitless" ; + fates_damage_event_code:long_name = "Integer code that options how damage events are structured" ; + double fates_dev_arbitrary ; + fates_dev_arbitrary:units = "unknown" ; + fates_dev_arbitrary:long_name = "Unassociated free parameter that developers can use for testing arbitrary new hypotheses" ; + double fates_fire_active_crown_fire ; + fates_fire_active_crown_fire:units = "0 or 1" ; + fates_fire_active_crown_fire:long_name = "flag, 1=active crown fire 0=no active crown fire" ; + double fates_fire_cg_strikes ; + fates_fire_cg_strikes:units = "fraction (0-1)" ; + fates_fire_cg_strikes:long_name = "fraction of cloud to ground lightning strikes" ; + double fates_fire_drying_ratio ; + fates_fire_drying_ratio:units = "NA" ; + fates_fire_drying_ratio:long_name = "spitfire parameter, fire drying ratio for fuel moisture, alpha_FMC EQ 6 Thonicke et al 2010" ; + double fates_fire_durat_slope ; + fates_fire_durat_slope:units = "NA" ; + fates_fire_durat_slope:long_name = "spitfire parameter, fire max duration slope, Equation 14 Thonicke et al 2010" ; + double fates_fire_fdi_a ; + fates_fire_fdi_a:units = "NA" ; + fates_fire_fdi_a:long_name = "spitfire parameter, fire danger index, EQ 5 Thonicke et al 2010" ; + double fates_fire_fdi_alpha ; + fates_fire_fdi_alpha:units = "NA" ; + fates_fire_fdi_alpha:long_name = "spitfire parameter, EQ 7 Venevsky et al. GCB 2002,(modified EQ 8 Thonicke et al. 2010) " ; + double fates_fire_fdi_b ; + fates_fire_fdi_b:units = "NA" ; + fates_fire_fdi_b:long_name = "spitfire parameter, fire danger index, EQ 5 Thonicke et al 2010 " ; + double fates_fire_fuel_energy ; + fates_fire_fuel_energy:units = "kJ/kg" ; + fates_fire_fuel_energy:long_name = "spitfire parameter, heat content of fuel" ; + double fates_fire_max_durat ; + fates_fire_max_durat:units = "minutes" ; + fates_fire_max_durat:long_name = "spitfire parameter, fire maximum duration, Equation 14 Thonicke et al 2010" ; + double fates_fire_miner_damp ; + fates_fire_miner_damp:units = "NA" ; + fates_fire_miner_damp:long_name = "spitfire parameter, mineral-dampening coefficient EQ A1 Thonicke et al 2010 " ; + double fates_fire_miner_total ; + fates_fire_miner_total:units = "fraction" ; + fates_fire_miner_total:long_name = "spitfire parameter, total mineral content, Table A1 Thonicke et al 2010" ; + double fates_fire_nignitions ; + fates_fire_nignitions:units = "ignitions per year per km2" ; + fates_fire_nignitions:long_name = "number of annual ignitions per square km" ; + double fates_fire_part_dens ; + fates_fire_part_dens:units = "kg/m2" ; + fates_fire_part_dens:long_name = "spitfire parameter, oven dry particle density, Table A1 Thonicke et al 2010" ; + double fates_fire_threshold ; + fates_fire_threshold:units = "kW/m" ; + fates_fire_threshold:long_name = "spitfire parameter, fire intensity threshold for tracking fires that spread" ; + double fates_frag_cwd_fcel ; + fates_frag_cwd_fcel:units = "unitless" ; + fates_frag_cwd_fcel:long_name = "Cellulose fraction for CWD" ; + double fates_frag_cwd_flig ; + fates_frag_cwd_flig:units = "unitless" ; + fates_frag_cwd_flig:long_name = "Lignin fraction of coarse woody debris" ; + double fates_hydro_kmax_rsurf1 ; + fates_hydro_kmax_rsurf1:units = "kg water/m2 root area/Mpa/s" ; + fates_hydro_kmax_rsurf1:long_name = "maximum conducitivity for unit root surface (into root)" ; + double fates_hydro_kmax_rsurf2 ; + fates_hydro_kmax_rsurf2:units = "kg water/m2 root area/Mpa/s" ; + fates_hydro_kmax_rsurf2:long_name = "maximum conducitivity for unit root surface (out of root)" ; + double fates_hydro_psi0 ; + fates_hydro_psi0:units = "MPa" ; + fates_hydro_psi0:long_name = "sapwood water potential at saturation" ; + double fates_hydro_psicap ; + fates_hydro_psicap:units = "MPa" ; + fates_hydro_psicap:long_name = "sapwood water potential at which capillary reserves exhausted" ; + double fates_hydro_solver ; + fates_hydro_solver:units = "unitless" ; + fates_hydro_solver:long_name = "switch designating which numerical solver for plant hydraulics, 1 = 1D taylor, 2 = 2D Picard, 3 = 2D Newton (deprecated)" ; + double fates_landuse_logging_coll_under_frac ; + fates_landuse_logging_coll_under_frac:units = "fraction" ; + fates_landuse_logging_coll_under_frac:long_name = "Fraction of stems killed in the understory when logging generates disturbance" ; + double fates_landuse_logging_collateral_frac ; + fates_landuse_logging_collateral_frac:units = "fraction" ; + fates_landuse_logging_collateral_frac:long_name = "Fraction of large stems in upperstory that die from logging collateral damage" ; + double fates_landuse_logging_dbhmax ; + fates_landuse_logging_dbhmax:units = "cm" ; + fates_landuse_logging_dbhmax:long_name = "Maximum dbh below which logging is applied (unset values flag this to be unused)" ; + double fates_landuse_logging_dbhmax_infra ; + fates_landuse_logging_dbhmax_infra:units = "cm" ; + fates_landuse_logging_dbhmax_infra:long_name = "Tree diameter, above which infrastructure from logging does not impact damage or mortality." ; + double fates_landuse_logging_dbhmin ; + fates_landuse_logging_dbhmin:units = "cm" ; + fates_landuse_logging_dbhmin:long_name = "Minimum dbh at which logging is applied" ; + double fates_landuse_logging_direct_frac ; + fates_landuse_logging_direct_frac:units = "fraction" ; + fates_landuse_logging_direct_frac:long_name = "Fraction of stems logged directly per event" ; + double fates_landuse_logging_event_code ; + fates_landuse_logging_event_code:units = "unitless" ; + fates_landuse_logging_event_code:long_name = "Integer code that options how logging events are structured" ; + double fates_landuse_logging_export_frac ; + fates_landuse_logging_export_frac:units = "fraction" ; + fates_landuse_logging_export_frac:long_name = "fraction of trunk product being shipped offsite, the leftovers will be left onsite as large CWD" ; + double fates_landuse_logging_mechanical_frac ; + fates_landuse_logging_mechanical_frac:units = "fraction" ; + fates_landuse_logging_mechanical_frac:long_name = "Fraction of stems killed due infrastructure an other mechanical means" ; + double fates_landuse_pprodharv10_forest_mean ; + fates_landuse_pprodharv10_forest_mean:units = "fraction" ; + fates_landuse_pprodharv10_forest_mean:long_name = "mean harvest mortality proportion of deadstem to 10-yr product (pprodharv10) of all woody PFT types" ; + double fates_leaf_photo_temp_acclim_thome_time ; + fates_leaf_photo_temp_acclim_thome_time:units = "years" ; + fates_leaf_photo_temp_acclim_thome_time:long_name = "Length of the window for the long-term (i.e. T_home in Kumarathunge et al 2019) exponential moving average (ema) of vegetation temperature used in photosynthesis temperature acclimation (used if fates_leaf_photo_tempsens_model = 2)" ; + double fates_leaf_photo_temp_acclim_timescale ; + fates_leaf_photo_temp_acclim_timescale:units = "days" ; + fates_leaf_photo_temp_acclim_timescale:long_name = "Length of the window for the exponential moving average (ema) of vegetation temperature used in photosynthesis temperature acclimation (used if fates_maintresp_leaf_model=2 or fates_leaf_photo_tempsens_model = 2)" ; + double fates_leaf_photo_tempsens_model ; + fates_leaf_photo_tempsens_model:units = "unitless" ; + fates_leaf_photo_tempsens_model:long_name = "switch for choosing the model that defines the temperature sensitivity of photosynthetic parameters (vcmax, jmax). 1=non-acclimating; 2=Kumarathunge et al 2019" ; + double fates_leaf_stomatal_assim_model ; + fates_leaf_stomatal_assim_model:units = "unitless" ; + fates_leaf_stomatal_assim_model:long_name = "a switch designating whether to use net (1) or gross (2) assimilation in the stomatal model" ; + double fates_leaf_stomatal_model ; + fates_leaf_stomatal_model:units = "unitless" ; + fates_leaf_stomatal_model:long_name = "switch for choosing between Ball-Berry (1) stomatal conductance model and Medlyn (2) model" ; + double fates_leaf_theta_cj_c3 ; + fates_leaf_theta_cj_c3:units = "unitless" ; + fates_leaf_theta_cj_c3:long_name = "Empirical curvature parameter for ac, aj photosynthesis co-limitation in c3 plants" ; + double fates_leaf_theta_cj_c4 ; + fates_leaf_theta_cj_c4:units = "unitless" ; + fates_leaf_theta_cj_c4:long_name = "Empirical curvature parameter for ac, aj photosynthesis co-limitation in c4 plants" ; + double fates_maintresp_leaf_model ; + fates_maintresp_leaf_model:units = "unitless" ; + fates_maintresp_leaf_model:long_name = "switch for choosing between maintenance respiration models. 1=Ryan (1991), 2=Atkin et al., (2017)" ; + double fates_maintresp_nonleaf_baserate ; + fates_maintresp_nonleaf_baserate:units = "gC/gN/s" ; + fates_maintresp_nonleaf_baserate:long_name = "Base maintenance respiration rate for plant tissues, using Ryan 1991" ; + double fates_maxcohort ; + fates_maxcohort:units = "count" ; + fates_maxcohort:long_name = "maximum number of cohorts per patch. Actual number of cohorts also depend on cohort fusion tolerances" ; + double fates_maxpatch_primary ; + fates_maxpatch_primary:units = "count" ; + fates_maxpatch_primary:long_name = "maximum number of primary vegetation patches per site" ; + double fates_maxpatch_secondary ; + fates_maxpatch_secondary:units = "count" ; + fates_maxpatch_secondary:long_name = "maximum number of secondary vegetation patches per site" ; + double fates_mort_disturb_frac ; + fates_mort_disturb_frac:units = "fraction" ; + fates_mort_disturb_frac:long_name = "fraction of canopy mortality that results in disturbance (i.e. transfer of area from new to old patch)" ; + double fates_mort_understorey_death ; + fates_mort_understorey_death:units = "fraction" ; + fates_mort_understorey_death:long_name = "fraction of plants in understorey cohort impacted by overstorey tree-fall" ; + double fates_patch_fusion_tol ; + fates_patch_fusion_tol:units = "unitless" ; + fates_patch_fusion_tol:long_name = "minimum fraction in difference in profiles between patches" ; + double fates_phen_chilltemp ; + fates_phen_chilltemp:units = "degrees C" ; + fates_phen_chilltemp:long_name = "chilling day counting threshold for vegetation" ; + double fates_phen_coldtemp ; + fates_phen_coldtemp:units = "degrees C" ; + fates_phen_coldtemp:long_name = "vegetation temperature exceedance that flags a cold-day for leaf-drop" ; + double fates_phen_drought_model ; + fates_phen_drought_model:units = "unitless" ; + fates_phen_drought_model:long_name = "which method to use for drought phenology: 0 - FATES default; 1 - Semi-deciduous (ED2-like)" ; + double fates_phen_drought_threshold ; + fates_phen_drought_threshold:units = "m3/m3 or mm" ; + fates_phen_drought_threshold:long_name = "threshold for drought phenology (or lower threshold when fates_phen_drought_model = 1); the quantity depends on the sign: if positive, the threshold is volumetric soil moisture (m3/m3). If negative, the threshold is soil matric potentical (mm)" ; + double fates_phen_gddthresh_a ; + fates_phen_gddthresh_a:units = "none" ; + fates_phen_gddthresh_a:long_name = "GDD accumulation function, intercept parameter: gdd_thesh = a + b exp(c*ncd)" ; + double fates_phen_gddthresh_b ; + fates_phen_gddthresh_b:units = "none" ; + fates_phen_gddthresh_b:long_name = "GDD accumulation function, multiplier parameter: gdd_thesh = a + b exp(c*ncd)" ; + double fates_phen_gddthresh_c ; + fates_phen_gddthresh_c:units = "none" ; + fates_phen_gddthresh_c:long_name = "GDD accumulation function, exponent parameter: gdd_thesh = a + b exp(c*ncd)" ; + double fates_phen_mindaysoff ; + fates_phen_mindaysoff:units = "days" ; + fates_phen_mindaysoff:long_name = "day threshold compared against days since leaves became off-allometry" ; + double fates_phen_mindayson ; + fates_phen_mindayson:units = "days" ; + fates_phen_mindayson:long_name = "day threshold compared against days since leaves became on-allometry" ; + double fates_phen_moist_threshold ; + fates_phen_moist_threshold:units = "m3/m3 or mm" ; + fates_phen_moist_threshold:long_name = "upper threshold for drought phenology (only for fates_phen_drought_model=1); the quantity depends on the sign: if positive, the threshold is volumetric soil moisture (m3/m3). If negative, the threshold is soil matric potentical (mm)" ; + double fates_phen_ncolddayslim ; + fates_phen_ncolddayslim:units = "days" ; + fates_phen_ncolddayslim:long_name = "day threshold exceedance for temperature leaf-drop" ; + double fates_q10_froz ; + fates_q10_froz:units = "unitless" ; + fates_q10_froz:long_name = "Q10 for frozen-soil respiration rates" ; + double fates_q10_mr ; + fates_q10_mr:units = "unitless" ; + fates_q10_mr:long_name = "Q10 for maintenance respiration" ; + double fates_soil_salinity ; + fates_soil_salinity:units = "ppt" ; + fates_soil_salinity:long_name = "soil salinity used for model when not coupled to dynamic soil salinity" ; + double fates_vai_top_bin_width ; + fates_vai_top_bin_width:units = "m2/m2" ; + fates_vai_top_bin_width:long_name = "width in VAI units of uppermost leaf+stem layer scattering element in each canopy layer" ; + double fates_vai_width_increase_factor ; + fates_vai_width_increase_factor:units = "unitless" ; + fates_vai_width_increase_factor:long_name = "factor by which each leaf+stem scattering element increases in VAI width (1 = uniform spacing)" ; + +// global attributes: + :history = "This file was generated by BatchPatchParams.py:\nCDL Base File = archive/api24.1.0_101722_fates_params_default.cdl\nXML patch file = archive/api24.1.0_101722_patch_params.xml" ; +data: + + fates_history_ageclass_bin_edges = 0, 1, 2, 5, 10, 20, 50 ; + + fates_history_coageclass_bin_edges = 0, 5 ; + + fates_history_height_bin_edges = 0, 0.1, 0.3, 1, 3, 10 ; + + fates_history_damage_bin_edges = 0, 80 ; + + fates_history_sizeclass_bin_edges = 0, 5, 10, 15, 20, 30, 40, 50, 60, 70, + 80, 90, 100 ; + + fates_alloc_organ_id = 1, 2, 3, 6 ; + + fates_hydro_htftype_node = 1, 1, 1, 1 ; + + fates_pftname = + "broadleaf_evergreen_tropical_tree ", + "needleleaf_evergreen_extratrop_tree ", + "needleleaf_colddecid_extratrop_tree ", + "broadleaf_evergreen_extratrop_tree ", + "broadleaf_hydrodecid_tropical_tree ", + "broadleaf_colddecid_extratrop_tree ", + "broadleaf_evergreen_extratrop_shrub ", + "broadleaf_hydrodecid_extratrop_shrub ", + "broadleaf_colddecid_extratrop_shrub ", + "arctic_c3_grass ", + "cool_c3_grass ", + "c4_grass " ; + + fates_hydro_organ_name = + "leaf ", + "stem ", + "transporting root ", + "absorbing root " ; + + fates_alloc_organ_name = + "leaf", + "fine root", + "sapwood", + "structure" ; + + fates_litterclass_name = + "twig ", + "small branch ", + "large branch ", + "trunk ", + "dead leaves ", + "live grass " ; + + fates_alloc_organ_priority = + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 ; + + fates_alloc_storage_cushion = 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, + 1.2, 1.2, 1.2 ; + + fates_alloc_store_priority_frac = 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, + 0.8, 0.8, 0.8, 0.8 ; + + fates_allom_agb1 = 0.06896, 0.06896, 0.06896, 0.06896, 0.06896, 0.06896, + 0.06896, 0.06896, 0.06896, 0.01, 0.01, 0.01 ; + + fates_allom_agb2 = 0.572, 0.572, 0.572, 0.572, 0.572, 0.572, 0.572, 0.572, + 0.572, 0.572, 0.572, 0.572 ; + + fates_allom_agb3 = 1.94, 1.94, 1.94, 1.94, 1.94, 1.94, 1.94, 1.94, 1.94, + 1.94, 1.94, 1.94 ; + + fates_allom_agb4 = 0.931, 0.931, 0.931, 0.931, 0.931, 0.931, 0.931, 0.931, + 0.931, 0.931, 0.931, 0.931 ; + + fates_allom_agb_frac = 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, + 0.6, 0.6 ; + + fates_allom_amode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_blca_expnt_diff = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_allom_cmode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_crown_depth_frac = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.95, 0.95, + 0.95, 1, 1, 1 ; + + fates_allom_d2bl1 = 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, + 0.07, 0.07, 0.07 ; + + fates_allom_d2bl2 = 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, + 1.3 ; + + fates_allom_d2bl3 = 0.55, 0.55, 0.55, 0.55, 0.55, 0.55, 0.55, 0.55, 0.55, + 0.55, 0.55, 0.55 ; + + fates_allom_d2ca_coefficient_max = 0.6568464, 0.6568464, 0.6568464, + 0.6568464, 0.6568464, 0.6568464, 0.6568464, 0.6568464, 0.6568464, + 0.6568464, 0.6568464, 0.6568464 ; + + fates_allom_d2ca_coefficient_min = 0.3381119, 0.3381119, 0.3381119, + 0.3381119, 0.3381119, 0.3381119, 0.3381119, 0.3381119, 0.3381119, + 0.3381119, 0.3381119, 0.3381119 ; + + fates_allom_d2h1 = 0.64, 0.64, 0.64, 0.64, 0.64, 0.64, 0.64, 0.64, 0.64, + 0.64, 0.64, 0.64 ; + + fates_allom_d2h2 = 0.37, 0.37, 0.37, 0.37, 0.37, 0.37, 0.37, 0.37, 0.37, + 0.37, 0.37, 0.37 ; + + fates_allom_d2h3 = -999.9, -999.9, -999.9, -999.9, -999.9, -999.9, -999.9, + -999.9, -999.9, -999.9, -999.9, -999.9 ; + + fates_allom_dbh_maxheight = 90, 80, 80, 80, 90, 80, 3, 3, 2, 0.35, 0.35, 0.35 ; + + fates_allom_fmode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_fnrt_prof_a = 7, 7, 7, 7, 6, 6, 7, 7, 7, 11, 11, 11 ; + + fates_allom_fnrt_prof_b = 1, 2, 2, 1, 2, 2, 1.5, 1.5, 1.5, 2, 2, 2 ; + + fates_allom_fnrt_prof_mode = 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 ; + + fates_allom_frbstor_repro = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_allom_hmode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_l2fr = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_la_per_sa_int = 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, + 0.8, 0.8, 0.8 ; + + fates_allom_la_per_sa_slp = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_allom_lmode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_sai_scaler = 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, + 0.1, 0.1 ; + + fates_allom_smode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_stmode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_zroot_k = 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10 ; + + fates_allom_zroot_max_dbh = 100, 100, 100, 100, 100, 100, 2, 2, 2, 2, 2, 2 ; + + fates_allom_zroot_max_z = 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, + 100, 100 ; + + fates_allom_zroot_min_dbh = 1, 1, 1, 2.5, 2.5, 2.5, 0.1, 0.1, 0.1, 0.1, 0.1, + 0.1 ; + + fates_allom_zroot_min_z = 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, + 100, 100 ; + + fates_c2b = 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ; + + fates_cnp_eca_alpha_ptase = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5 ; + + fates_cnp_eca_decompmicc = 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280 ; + + fates_cnp_eca_km_nh4 = 0.14, 0.14, 0.14, 0.14, 0.14, 0.14, 0.14, 0.14, 0.14, + 0.14, 0.14, 0.14 ; + + fates_cnp_eca_km_no3 = 0.27, 0.27, 0.27, 0.27, 0.27, 0.27, 0.27, 0.27, 0.27, + 0.27, 0.27, 0.27 ; + + fates_cnp_eca_km_p = 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, + 0.1 ; + + fates_cnp_eca_km_ptase = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_cnp_eca_lambda_ptase = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_cnp_eca_vmax_ptase = 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, + 5e-09, 5e-09, 5e-09, 5e-09, 5e-09 ; + + fates_cnp_nfix1 = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_cnp_nitr_store_ratio = 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, + 1.5, 1.5, 1.5 ; + + fates_cnp_phos_store_ratio = 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, + 1.5, 1.5, 1.5 ; + + fates_cnp_pid_kd = 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1 ; + + fates_cnp_pid_ki = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_cnp_pid_kp = 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, + 0.0005, 0.0005, 0.0005, 0.0005, 0.0005 ; + + fates_cnp_prescribed_nuptake = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_cnp_prescribed_puptake = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_cnp_store_ovrflw_frac = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_cnp_turnover_nitr_retrans = + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_cnp_turnover_phos_retrans = + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_cnp_vmax_nh4 = 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, + 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09 ; + + fates_cnp_vmax_no3 = 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, + 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09 ; + + fates_cnp_vmax_p = 5e-10, 5e-10, 5e-10, 5e-10, 5e-10, 5e-10, 5e-10, 5e-10, + 5e-10, 5e-10, 5e-10, 5e-10 ; + + fates_damage_frac = 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, + 0.01, 0.01, 0.01 ; + + fates_damage_mort_p1 = 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 ; + + fates_damage_mort_p2 = 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, + 5.5, 5.5 ; + + fates_damage_recovery_scalar = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_dev_arbitrary_pft = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_fire_alpha_SH = 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, + 0.2 ; + + fates_fire_bark_scaler = 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, + 0.07, 0.07, 0.07, 0.07 ; + + fates_fire_crown_kill = 0.775, 0.775, 0.775, 0.775, 0.775, 0.775, 0.775, + 0.775, 0.775, 0.775, 0.775, 0.775 ; + + fates_frag_fnrt_fcel = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5 ; + + fates_frag_fnrt_flab = 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25 ; + + fates_frag_fnrt_flig = 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25 ; + + fates_frag_leaf_fcel = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5 ; + + fates_frag_leaf_flab = 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25 ; + + fates_frag_leaf_flig = 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25 ; + + fates_frag_seed_decay_rate = 0.51, 0.51, 0.51, 0.51, 0.51, 0.51, 0.51, 0.51, + 0.51, 0.51, 0.51, 0.51 ; + + fates_grperc = 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, + 0.11, 0.11 ; + + fates_hydro_avuln_gs = 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, + 2.5, 2.5 ; + + fates_hydro_avuln_node = + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ; + + fates_hydro_epsil_node = + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 ; + + fates_hydro_fcap_node = + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, + 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_hydro_k_lwp = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_hydro_kmax_node = + -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999 ; + + fates_hydro_p50_gs = -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, + -1.5, -1.5, -1.5 ; + + fates_hydro_p50_node = + -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, + -2.25, -2.25, + -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, + -2.25, -2.25, + -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, + -2.25, -2.25, + -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, + -2.25, -2.25 ; + + fates_hydro_p_taper = 0.333, 0.333, 0.333, 0.333, 0.333, 0.333, 0.333, + 0.333, 0.333, 0.333, 0.333, 0.333 ; + + fates_hydro_pinot_node = + -1.465984, -1.465984, -1.465984, -1.465984, -1.465984, -1.465984, + -1.465984, -1.465984, -1.465984, -1.465984, -1.465984, -1.465984, + -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, + -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, + -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, + -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, + -1.043478, -1.043478, -1.043478, -1.043478, -1.043478, -1.043478, + -1.043478, -1.043478, -1.043478, -1.043478, -1.043478, -1.043478 ; + + fates_hydro_pitlp_node = + -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, + -1.67, -1.67, + -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, + -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, + -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2 ; + + fates_hydro_resid_node = + 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, + 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, + 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, + 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11 ; + + fates_hydro_rfrac_stem = 0.625, 0.625, 0.625, 0.625, 0.625, 0.625, 0.625, + 0.625, 0.625, 0.625, 0.625, 0.625 ; + + fates_hydro_rs2 = 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, + 0.0001, 0.0001, 0.0001, 0.0001, 0.0001 ; + + fates_hydro_srl = 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25 ; + + fates_hydro_thetas_node = + 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, + 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, + 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, + 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75 ; + + fates_hydro_vg_alpha_node = + 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.005, 0.005, 0.005, 0.005, 0.005, + 0.005, 0.005, + 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.005, 0.005, 0.005, 0.005, 0.005, + 0.005, 0.005, + 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.005, 0.005, 0.005, 0.005, 0.005, + 0.005, 0.005, + 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.005, 0.005, 0.005, 0.005, 0.005, + 0.005, 0.005 ; + + fates_hydro_vg_m_node = + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5 ; + + fates_hydro_vg_n_node = + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ; + + fates_leaf_c3psn = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 ; + + fates_leaf_jmaxha = 43540, 43540, 43540, 43540, 43540, 43540, 43540, 43540, + 43540, 43540, 43540, 43540 ; + + fates_leaf_jmaxhd = 152040, 152040, 152040, 152040, 152040, 152040, 152040, + 152040, 152040, 152040, 152040, 152040 ; + + fates_leaf_jmaxse = 495, 495, 495, 495, 495, 495, 495, 495, 495, 495, 495, + 495 ; + + fates_leaf_slamax = 0.0954, 0.0954, 0.0954, 0.0954, 0.0954, 0.0954, 0.012, + 0.03, 0.03, 0.03, 0.03, 0.03 ; + + fates_leaf_slatop = 0.012, 0.005, 0.024, 0.009, 0.03, 0.03, 0.012, 0.03, + 0.03, 0.03, 0.03, 0.03 ; + + fates_leaf_stomatal_intercept = 10000, 10000, 10000, 10000, 10000, 10000, + 10000, 10000, 10000, 10000, 10000, 40000 ; + + fates_leaf_stomatal_slope_ballberry = 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 ; + + fates_leaf_stomatal_slope_medlyn = 4.1, 2.3, 2.3, 4.1, 4.4, 4.4, 4.7, 4.7, + 4.7, 2.2, 5.3, 1.6 ; + + fates_leaf_vcmax25top = + 50, 62, 39, 61, 41, 58, 62, 54, 54, 78, 78, 78 ; + + fates_leaf_vcmaxha = 65330, 65330, 65330, 65330, 65330, 65330, 65330, 65330, + 65330, 65330, 65330, 65330 ; + + fates_leaf_vcmaxhd = 149250, 149250, 149250, 149250, 149250, 149250, 149250, + 149250, 149250, 149250, 149250, 149250 ; + + fates_leaf_vcmaxse = 485, 485, 485, 485, 485, 485, 485, 485, 485, 485, 485, + 485 ; + + fates_maintresp_leaf_atkin2017_baserate = 1.756, 1.4995, 1.4995, 1.756, + 1.756, 1.756, 2.0749, 2.0749, 2.0749, 2.1956, 2.1956, 2.1956 ; + + fates_maintresp_leaf_ryan1991_baserate = 2.525e-06, 2.525e-06, 2.525e-06, + 2.525e-06, 2.525e-06, 2.525e-06, 2.525e-06, 2.525e-06, 2.525e-06, + 2.525e-06, 2.525e-06, 2.525e-06 ; + + fates_maintresp_reduction_curvature = 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, + 0.01, 0.01, 0.01, 0.01, 0.01, 0.01 ; + + fates_maintresp_reduction_intercept = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_mort_bmort = 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, + 0.014, 0.014, 0.014, 0.014 ; + + fates_mort_freezetol = 2.5, -55, -80, -30, 2.5, -80, -60, -10, -80, -80, + -20, 2.5 ; + + fates_mort_hf_flc_threshold = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5 ; + + fates_mort_hf_sm_threshold = 1e-06, 1e-06, 1e-06, 1e-06, 1e-06, 1e-06, + 1e-06, 1e-06, 1e-06, 1e-06, 1e-06, 1e-06 ; + + fates_mort_ip_age_senescence = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_mort_ip_size_senescence = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_mort_prescribed_canopy = 0.0194, 0.0194, 0.0194, 0.0194, 0.0194, + 0.0194, 0.0194, 0.0194, 0.0194, 0.0194, 0.0194, 0.0194 ; + + fates_mort_prescribed_understory = 0.025, 0.025, 0.025, 0.025, 0.025, 0.025, + 0.025, 0.025, 0.025, 0.025, 0.025, 0.025 ; + + fates_mort_r_age_senescence = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_mort_r_size_senescence = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_mort_scalar_coldstress = 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 ; + + fates_mort_scalar_cstarvation = 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, + 0.6, 0.6, 0.6 ; + + fates_mort_scalar_hydrfailure = 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, + 0.6, 0.6, 0.6 ; + + fates_nonhydro_smpsc = -255000, -255000, -255000, -255000, -255000, -255000, + -255000, -255000, -255000, -255000, -255000, -255000 ; + + fates_nonhydro_smpso = -66000, -66000, -66000, -66000, -66000, -66000, + -66000, -66000, -66000, -66000, -66000, -66000 ; + + fates_phen_cold_size_threshold = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_phen_evergreen = 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 ; + + fates_phen_flush_fraction = _, _, 0.5, _, 0.5, 0.5, _, 0.5, 0.5, 0.5, 0.5, + 0.5 ; + + fates_phen_fnrt_drop_frac = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_phen_season_decid = 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0 ; + + fates_phen_stem_drop_fraction = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_phen_stress_decid = 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1 ; + + fates_prescribed_npp_canopy = 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, + 0.4, 0.4, 0.4 ; + + fates_prescribed_npp_understory = 0.03125, 0.03125, 0.03125, 0.03125, + 0.03125, 0.03125, 0.03125, 0.03125, 0.03125, 0.03125, 0.03125, 0.03125 ; + + fates_rad_leaf_clumping_index = 0.85, 0.85, 0.8, 0.85, 0.85, 0.9, 0.85, 0.9, + 0.9, 0.75, 0.75, 0.75 ; + + fates_rad_leaf_rhonir = 0.46, 0.41, 0.39, 0.46, 0.41, 0.41, 0.46, 0.41, + 0.41, 0.28, 0.28, 0.28 ; + + fates_rad_leaf_rhovis = 0.11, 0.09, 0.08, 0.11, 0.08, 0.08, 0.11, 0.08, + 0.08, 0.05, 0.05, 0.05 ; + + fates_rad_leaf_taunir = 0.33, 0.32, 0.42, 0.33, 0.43, 0.43, 0.33, 0.43, + 0.43, 0.4, 0.4, 0.4 ; + + fates_rad_leaf_tauvis = 0.06, 0.04, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, + 0.06, 0.05, 0.05, 0.05 ; + + fates_rad_leaf_xl = 0.32, 0.01, 0.01, 0.32, 0.2, 0.59, 0.32, 0.59, 0.59, + -0.23, -0.23, -0.23 ; + + fates_rad_stem_rhonir = 0.49, 0.36, 0.36, 0.49, 0.49, 0.49, 0.49, 0.49, + 0.49, 0.53, 0.53, 0.53 ; + + fates_rad_stem_rhovis = 0.21, 0.12, 0.12, 0.21, 0.21, 0.21, 0.21, 0.21, + 0.21, 0.31, 0.31, 0.31 ; + + fates_rad_stem_taunir = 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, + 0.001, 0.001, 0.25, 0.25, 0.25 ; + + fates_rad_stem_tauvis = 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, + 0.001, 0.001, 0.12, 0.12, 0.12 ; + + fates_recruit_height_min = 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 0.2, 0.2, 0.2, + 0.125, 0.125, 0.125 ; + + fates_recruit_init_density = 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, + 0.2, 0.2, 0.2 ; + + fates_recruit_prescribed_rate = 0.02, 0.02, 0.02, 0.02, 0.02, 0.02, 0.02, + 0.02, 0.02, 0.02, 0.02, 0.02 ; + + fates_recruit_seed_alloc = 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, + 0.1, 0.1 ; + + fates_recruit_seed_alloc_mature = 0, 0, 0, 0, 0, 0, 0.9, 0.9, 0.9, 0.9, 0.9, + 0.9 ; + + fates_recruit_seed_dbh_repro_threshold = 90, 80, 80, 80, 90, 80, 3, 3, 2, + 0.35, 0.35, 0.35 ; + + fates_recruit_seed_germination_rate = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5 ; + + fates_recruit_seed_supplement = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_stoich_nitr = + 0.033, 0.029, 0.04, 0.033, 0.04, 0.04, 0.033, 0.04, 0.04, 0.04, 0.04, 0.04, + 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, + 0.024, 0.024, + 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, + 1e-08, 1e-08, + 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, + 0.0047, 0.0047, 0.0047 ; + + fates_stoich_phos = + 0.0033, 0.0029, 0.004, 0.0033, 0.004, 0.004, 0.0033, 0.004, 0.004, 0.004, + 0.004, 0.004, + 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, + 0.0024, 0.0024, 0.0024, + 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, + 1e-09, 1e-09, + 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, + 0.00047, 0.00047, 0.00047, 0.00047 ; + + fates_trim_inc = 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, + 0.03, 0.03 ; + + fates_trim_limit = 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3 ; + + fates_turb_displar = 0.67, 0.67, 0.67, 0.67, 0.67, 0.67, 0.67, 0.67, 0.67, + 0.67, 0.67, 0.67 ; + + fates_turb_leaf_diameter = 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, + 0.04, 0.04, 0.04, 0.04 ; + + fates_turb_z0mr = 0.055, 0.055, 0.055, 0.055, 0.055, 0.055, 0.055, 0.055, + 0.055, 0.055, 0.055, 0.055 ; + + fates_turnover_branch = 150, 150, 150, 150, 150, 150, 150, 150, 150, 0, 0, 0 ; + + fates_turnover_fnrt = 1, 2, 1, 1.5, 1, 1, 1.5, 1, 1, 1, 1, 1 ; + + fates_turnover_leaf = + 1.5, 4, 1, 1.5, 1, 1, 1.5, 1, 1, 1, 1, 1 ; + + fates_turnover_senleaf_fdrought = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_wood_density = 0.7, 0.4, 0.7, 0.53, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, + 0.7 ; + + fates_woody = 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 ; + + fates_hlm_pft_map = + 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 ; + + fates_fire_FBD = 15.4, 16.8, 19.6, 999, 4, 4 ; + + fates_fire_low_moisture_Coeff = 1.12, 1.09, 0.98, 0.8, 1.15, 1.15 ; + + fates_fire_low_moisture_Slope = 0.62, 0.72, 0.85, 0.8, 0.62, 0.62 ; + + fates_fire_mid_moisture = 0.72, 0.51, 0.38, 1, 0.8, 0.8 ; + + fates_fire_mid_moisture_Coeff = 2.35, 1.47, 1.06, 0.8, 3.2, 3.2 ; + + fates_fire_mid_moisture_Slope = 2.35, 1.47, 1.06, 0.8, 3.2, 3.2 ; + + fates_fire_min_moisture = 0.18, 0.12, 0, 0, 0.24, 0.24 ; + + fates_fire_SAV = 13, 3.58, 0.98, 0.2, 66, 66 ; + + fates_frag_maxdecomp = 0.52, 0.383, 0.383, 0.19, 1, 999 ; + + fates_frag_cwd_frac = 0.045, 0.075, 0.21, 0.67 ; + + fates_canopy_closure_thresh = 0.8 ; + + fates_cnp_eca_plant_escalar = 1.25e-05 ; + + fates_cohort_age_fusion_tol = 0.08 ; + + fates_cohort_size_fusion_tol = 0.08 ; + + fates_comp_excln = 3 ; + + fates_damage_canopy_layer_code = 1 ; + + fates_damage_event_code = 1 ; + + fates_dev_arbitrary = _ ; + + fates_fire_active_crown_fire = 0 ; + + fates_fire_cg_strikes = 0.2 ; + + fates_fire_drying_ratio = 66000 ; + + fates_fire_durat_slope = -11.06 ; + + fates_fire_fdi_a = 17.62 ; + + fates_fire_fdi_alpha = 0.00037 ; + + fates_fire_fdi_b = 243.12 ; + + fates_fire_fuel_energy = 18000 ; + + fates_fire_max_durat = 240 ; + + fates_fire_miner_damp = 0.41739 ; + + fates_fire_miner_total = 0.055 ; + + fates_fire_nignitions = 15 ; + + fates_fire_part_dens = 513 ; + + fates_fire_threshold = 50 ; + + fates_frag_cwd_fcel = 0.76 ; + + fates_frag_cwd_flig = 0.24 ; + + fates_hydro_kmax_rsurf1 = 20 ; + + fates_hydro_kmax_rsurf2 = 0.0001 ; + + fates_hydro_psi0 = 0 ; + + fates_hydro_psicap = -0.6 ; + + fates_hydro_solver = 1 ; + + fates_landuse_logging_coll_under_frac = 0.55983 ; + + fates_landuse_logging_collateral_frac = 0.05 ; + + fates_landuse_logging_dbhmax = _ ; + + fates_landuse_logging_dbhmax_infra = 35 ; + + fates_landuse_logging_dbhmin = 50 ; + + fates_landuse_logging_direct_frac = 0.15 ; + + fates_landuse_logging_event_code = -30 ; + + fates_landuse_logging_export_frac = 0.8 ; + + fates_landuse_logging_mechanical_frac = 0.05 ; + + fates_landuse_pprodharv10_forest_mean = 0.8125 ; + + fates_leaf_photo_temp_acclim_thome_time = 30 ; + + fates_leaf_photo_temp_acclim_timescale = 30 ; + + fates_leaf_photo_tempsens_model = 1 ; + + fates_leaf_stomatal_assim_model = 1 ; + + fates_leaf_stomatal_model = 1 ; + + fates_leaf_theta_cj_c3 = 0.999 ; + + fates_leaf_theta_cj_c4 = 0.999 ; + + fates_maintresp_leaf_model = 1 ; + + fates_maintresp_nonleaf_baserate = 2.525e-06 ; + + fates_maxcohort = 100 ; + + fates_maxpatch_primary = 10 ; + + fates_maxpatch_secondary = 4 ; + + fates_mort_disturb_frac = 1 ; + + fates_mort_understorey_death = 0.55983 ; + + fates_patch_fusion_tol = 0.05 ; + + fates_phen_chilltemp = 5 ; + + fates_phen_coldtemp = 7.5 ; + + fates_phen_drought_model = 0 ; + + fates_phen_drought_threshold = 0.15 ; + + fates_phen_gddthresh_a = -68 ; + + fates_phen_gddthresh_b = 638 ; + + fates_phen_gddthresh_c = -0.01 ; + + fates_phen_mindaysoff = 100 ; + + fates_phen_mindayson = 90 ; + + fates_phen_moist_threshold = 0.18 ; + + fates_phen_ncolddayslim = 5 ; + + fates_q10_froz = 1.5 ; + + fates_q10_mr = 1.5 ; + + fates_soil_salinity = 0.4 ; + + fates_vai_top_bin_width = 1 ; + + fates_vai_width_increase_factor = 1 ; +} diff --git a/parameter_files/archive/api25.3.0_032223_pr995.xml b/parameter_files/archive/api25.3.0_032223_pr995.xml new file mode 100644 index 0000000000..e68fb782cc --- /dev/null +++ b/parameter_files/archive/api25.3.0_032223_pr995.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + archive/api25.3.0_032223_fates_params_default.cdl + fates_params_default.cdl + 1,2,3,4,5,6,7,8,9,10,11,12 + + + initial seedling density for a cold-start near-bare-ground simulation. If negative sets initial tree dbh - only to be used in nocomp mode + + + diff --git a/parameter_files/archive/api25.4.0_041023_fates_params_default.cdl b/parameter_files/archive/api25.4.0_041023_fates_params_default.cdl new file mode 100644 index 0000000000..d461cb6fbb --- /dev/null +++ b/parameter_files/archive/api25.4.0_041023_fates_params_default.cdl @@ -0,0 +1,1559 @@ +netcdf fates_params_default { +dimensions: + fates_NCWD = 4 ; + fates_history_age_bins = 7 ; + fates_history_coage_bins = 2 ; + fates_history_damage_bins = 2 ; + fates_history_height_bins = 6 ; + fates_history_size_bins = 13 ; + fates_hlm_pftno = 14 ; + fates_hydr_organs = 4 ; + fates_leafage_class = 1 ; + fates_litterclass = 6 ; + fates_pft = 12 ; + fates_plant_organs = 4 ; + fates_string_length = 60 ; +variables: + double fates_history_ageclass_bin_edges(fates_history_age_bins) ; + fates_history_ageclass_bin_edges:units = "yr" ; + fates_history_ageclass_bin_edges:long_name = "Lower edges for age class bins used in age-resolved patch history output" ; + double fates_history_coageclass_bin_edges(fates_history_coage_bins) ; + fates_history_coageclass_bin_edges:units = "years" ; + fates_history_coageclass_bin_edges:long_name = "Lower edges for cohort age class bins used in cohort age resolved history output" ; + double fates_history_height_bin_edges(fates_history_height_bins) ; + fates_history_height_bin_edges:units = "m" ; + fates_history_height_bin_edges:long_name = "Lower edges for height bins used in height-resolved history output" ; + double fates_history_damage_bin_edges(fates_history_damage_bins) ; + fates_history_damage_bin_edges:units = "% crown loss" ; + fates_history_damage_bin_edges:long_name = "Lower edges for damage class bins used in cohort history output" ; + double fates_history_sizeclass_bin_edges(fates_history_size_bins) ; + fates_history_sizeclass_bin_edges:units = "cm" ; + fates_history_sizeclass_bin_edges:long_name = "Lower edges for DBH size class bins used in size-resolved cohort history output" ; + double fates_alloc_organ_id(fates_plant_organs) ; + fates_alloc_organ_id:units = "unitless" ; + fates_alloc_organ_id:long_name = "This is the global index that the organ in this file is associated with, values match those in parteh/PRTGenericMod.F90" ; + double fates_hydro_htftype_node(fates_hydr_organs) ; + fates_hydro_htftype_node:units = "unitless" ; + fates_hydro_htftype_node:long_name = "Switch that defines the hydraulic transfer functions for each organ." ; + char fates_pftname(fates_pft, fates_string_length) ; + fates_pftname:units = "unitless - string" ; + fates_pftname:long_name = "Description of plant type" ; + char fates_hydro_organ_name(fates_hydr_organs, fates_string_length) ; + fates_hydro_organ_name:units = "unitless - string" ; + fates_hydro_organ_name:long_name = "Name of plant hydraulics organs (DONT CHANGE, order matches media list in FatesHydraulicsMemMod.F90)" ; + char fates_alloc_organ_name(fates_plant_organs, fates_string_length) ; + fates_alloc_organ_name:units = "unitless - string" ; + fates_alloc_organ_name:long_name = "Name of plant organs (with alloc_organ_id, must match PRTGenericMod.F90)" ; + char fates_litterclass_name(fates_litterclass, fates_string_length) ; + fates_litterclass_name:units = "unitless - string" ; + fates_litterclass_name:long_name = "Name of the litter classes, for variables associated with dimension fates_litterclass" ; + double fates_alloc_organ_priority(fates_plant_organs, fates_pft) ; + fates_alloc_organ_priority:units = "index" ; + fates_alloc_organ_priority:long_name = "Priority level for allocation, 1: replaces turnover from storage, 2: same priority as storage use/replacement, 3: ascending in order of least importance" ; + double fates_alloc_storage_cushion(fates_pft) ; + fates_alloc_storage_cushion:units = "fraction" ; + fates_alloc_storage_cushion:long_name = "maximum size of storage C pool, relative to maximum size of leaf C pool" ; + double fates_alloc_store_priority_frac(fates_pft) ; + fates_alloc_store_priority_frac:units = "unitless" ; + fates_alloc_store_priority_frac:long_name = "for high-priority organs, the fraction of their turnover demand that is gauranteed to be replaced, and if need-be by storage" ; + double fates_allom_agb1(fates_pft) ; + fates_allom_agb1:units = "variable" ; + fates_allom_agb1:long_name = "Parameter 1 for agb allometry" ; + double fates_allom_agb2(fates_pft) ; + fates_allom_agb2:units = "variable" ; + fates_allom_agb2:long_name = "Parameter 2 for agb allometry" ; + double fates_allom_agb3(fates_pft) ; + fates_allom_agb3:units = "variable" ; + fates_allom_agb3:long_name = "Parameter 3 for agb allometry" ; + double fates_allom_agb4(fates_pft) ; + fates_allom_agb4:units = "variable" ; + fates_allom_agb4:long_name = "Parameter 4 for agb allometry" ; + double fates_allom_agb_frac(fates_pft) ; + fates_allom_agb_frac:units = "fraction" ; + fates_allom_agb_frac:long_name = "Fraction of woody biomass that is above ground" ; + double fates_allom_amode(fates_pft) ; + fates_allom_amode:units = "index" ; + fates_allom_amode:long_name = "AGB allometry function index." ; + double fates_allom_blca_expnt_diff(fates_pft) ; + fates_allom_blca_expnt_diff:units = "unitless" ; + fates_allom_blca_expnt_diff:long_name = "difference between allometric DBH:bleaf and DBH:crown area exponents" ; + double fates_allom_cmode(fates_pft) ; + fates_allom_cmode:units = "index" ; + fates_allom_cmode:long_name = "coarse root biomass allometry function index." ; + double fates_allom_crown_depth_frac(fates_pft) ; + fates_allom_crown_depth_frac:units = "fraction" ; + fates_allom_crown_depth_frac:long_name = "the depth of a cohort crown as a fraction of its height" ; + double fates_allom_d2bl1(fates_pft) ; + fates_allom_d2bl1:units = "variable" ; + fates_allom_d2bl1:long_name = "Parameter 1 for d2bl allometry" ; + double fates_allom_d2bl2(fates_pft) ; + fates_allom_d2bl2:units = "variable" ; + fates_allom_d2bl2:long_name = "Parameter 2 for d2bl allometry" ; + double fates_allom_d2bl3(fates_pft) ; + fates_allom_d2bl3:units = "unitless" ; + fates_allom_d2bl3:long_name = "Parameter 3 for d2bl allometry" ; + double fates_allom_d2ca_coefficient_max(fates_pft) ; + fates_allom_d2ca_coefficient_max:units = "m2 cm^(-1/beta)" ; + fates_allom_d2ca_coefficient_max:long_name = "max (savanna) dbh to area multiplier factor where: area = n*d2ca_coeff*dbh^beta" ; + double fates_allom_d2ca_coefficient_min(fates_pft) ; + fates_allom_d2ca_coefficient_min:units = "m2 cm^(-1/beta)" ; + fates_allom_d2ca_coefficient_min:long_name = "min (forest) dbh to area multiplier factor where: area = n*d2ca_coeff*dbh^beta" ; + double fates_allom_d2h1(fates_pft) ; + fates_allom_d2h1:units = "variable" ; + fates_allom_d2h1:long_name = "Parameter 1 for d2h allometry (intercept, or c)" ; + double fates_allom_d2h2(fates_pft) ; + fates_allom_d2h2:units = "variable" ; + fates_allom_d2h2:long_name = "Parameter 2 for d2h allometry (slope, or m)" ; + double fates_allom_d2h3(fates_pft) ; + fates_allom_d2h3:units = "variable" ; + fates_allom_d2h3:long_name = "Parameter 3 for d2h allometry (optional)" ; + double fates_allom_dbh_maxheight(fates_pft) ; + fates_allom_dbh_maxheight:units = "cm" ; + fates_allom_dbh_maxheight:long_name = "the diameter (if any) corresponding to maximum height, diameters may increase beyond this" ; + double fates_allom_fmode(fates_pft) ; + fates_allom_fmode:units = "index" ; + fates_allom_fmode:long_name = "fine root biomass allometry function index." ; + double fates_allom_fnrt_prof_a(fates_pft) ; + fates_allom_fnrt_prof_a:units = "unitless" ; + fates_allom_fnrt_prof_a:long_name = "Fine root profile function, parameter a" ; + double fates_allom_fnrt_prof_b(fates_pft) ; + fates_allom_fnrt_prof_b:units = "unitless" ; + fates_allom_fnrt_prof_b:long_name = "Fine root profile function, parameter b" ; + double fates_allom_fnrt_prof_mode(fates_pft) ; + fates_allom_fnrt_prof_mode:units = "index" ; + fates_allom_fnrt_prof_mode:long_name = "Index to select fine root profile function: 1) Jackson Beta, 2) 1-param exponential 3) 2-param exponential" ; + double fates_allom_frbstor_repro(fates_pft) ; + fates_allom_frbstor_repro:units = "fraction" ; + fates_allom_frbstor_repro:long_name = "fraction of bstore goes to reproduction after plant dies" ; + double fates_allom_hmode(fates_pft) ; + fates_allom_hmode:units = "index" ; + fates_allom_hmode:long_name = "height allometry function index." ; + double fates_allom_l2fr(fates_pft) ; + fates_allom_l2fr:units = "gC/gC" ; + fates_allom_l2fr:long_name = "Allocation parameter: fine root C per leaf C" ; + double fates_allom_la_per_sa_int(fates_pft) ; + fates_allom_la_per_sa_int:units = "m2/cm2" ; + fates_allom_la_per_sa_int:long_name = "Leaf area per sapwood area, intercept" ; + double fates_allom_la_per_sa_slp(fates_pft) ; + fates_allom_la_per_sa_slp:units = "m2/cm2/m" ; + fates_allom_la_per_sa_slp:long_name = "Leaf area per sapwood area rate of change with height, slope (optional)" ; + double fates_allom_lmode(fates_pft) ; + fates_allom_lmode:units = "index" ; + fates_allom_lmode:long_name = "leaf biomass allometry function index." ; + double fates_allom_sai_scaler(fates_pft) ; + fates_allom_sai_scaler:units = "m2/m2" ; + fates_allom_sai_scaler:long_name = "allometric ratio of SAI per LAI" ; + double fates_allom_smode(fates_pft) ; + fates_allom_smode:units = "index" ; + fates_allom_smode:long_name = "sapwood allometry function index." ; + double fates_allom_stmode(fates_pft) ; + fates_allom_stmode:units = "index" ; + fates_allom_stmode:long_name = "storage allometry function index: 1) Storage proportional to leaf biomass (with trimming), 2) Storage proportional to maximum leaf biomass (not trimmed)" ; + double fates_allom_zroot_k(fates_pft) ; + fates_allom_zroot_k:units = "unitless" ; + fates_allom_zroot_k:long_name = "scale coefficient of logistic rooting depth model" ; + double fates_allom_zroot_max_dbh(fates_pft) ; + fates_allom_zroot_max_dbh:units = "cm" ; + fates_allom_zroot_max_dbh:long_name = "dbh at which a plant reaches the maximum value for its maximum rooting depth" ; + double fates_allom_zroot_max_z(fates_pft) ; + fates_allom_zroot_max_z:units = "m" ; + fates_allom_zroot_max_z:long_name = "the maximum rooting depth defined at dbh = fates_allom_zroot_max_dbh. note: max_z=min_z=large, sets rooting depth to soil depth" ; + double fates_allom_zroot_min_dbh(fates_pft) ; + fates_allom_zroot_min_dbh:units = "cm" ; + fates_allom_zroot_min_dbh:long_name = "dbh at which the maximum rooting depth for a recruit is defined" ; + double fates_allom_zroot_min_z(fates_pft) ; + fates_allom_zroot_min_z:units = "m" ; + fates_allom_zroot_min_z:long_name = "the maximum rooting depth defined at dbh = fates_allom_zroot_min_dbh. note: max_z=min_z=large, sets rooting depth to soil depth" ; + double fates_c2b(fates_pft) ; + fates_c2b:units = "ratio" ; + fates_c2b:long_name = "Carbon to biomass multiplier of bulk structural tissues" ; + double fates_cnp_eca_alpha_ptase(fates_pft) ; + fates_cnp_eca_alpha_ptase:units = "g/m3" ; + fates_cnp_eca_alpha_ptase:long_name = "fraction of P from ptase activity sent directly to plant (ECA)" ; + double fates_cnp_eca_decompmicc(fates_pft) ; + fates_cnp_eca_decompmicc:units = "gC/m3" ; + fates_cnp_eca_decompmicc:long_name = "maximum soil microbial decomposer biomass found over depth (will be applied at a reference depth w/ exponential attenuation) (ECA)" ; + double fates_cnp_eca_km_nh4(fates_pft) ; + fates_cnp_eca_km_nh4:units = "gN/m3" ; + fates_cnp_eca_km_nh4:long_name = "half-saturation constant for plant nh4 uptake (ECA)" ; + double fates_cnp_eca_km_no3(fates_pft) ; + fates_cnp_eca_km_no3:units = "gN/m3" ; + fates_cnp_eca_km_no3:long_name = "half-saturation constant for plant no3 uptake (ECA)" ; + double fates_cnp_eca_km_p(fates_pft) ; + fates_cnp_eca_km_p:units = "gP/m3" ; + fates_cnp_eca_km_p:long_name = "half-saturation constant for plant p uptake (ECA)" ; + double fates_cnp_eca_km_ptase(fates_pft) ; + fates_cnp_eca_km_ptase:units = "gP/m3" ; + fates_cnp_eca_km_ptase:long_name = "half-saturation constant for biochemical P (ECA)" ; + double fates_cnp_eca_lambda_ptase(fates_pft) ; + fates_cnp_eca_lambda_ptase:units = "g/m3" ; + fates_cnp_eca_lambda_ptase:long_name = "critical value for biochemical production (ECA)" ; + double fates_cnp_eca_vmax_ptase(fates_pft) ; + fates_cnp_eca_vmax_ptase:units = "gP/m2/s" ; + fates_cnp_eca_vmax_ptase:long_name = "maximum production rate for biochemical P (per m2) (ECA)" ; + double fates_cnp_nfix1(fates_pft) ; + fates_cnp_nfix1:units = "fraction" ; + fates_cnp_nfix1:long_name = "fractional surcharge added to maintenance respiration that drives symbiotic fixation" ; + double fates_cnp_nitr_store_ratio(fates_pft) ; + fates_cnp_nitr_store_ratio:units = "(gN/gN)" ; + fates_cnp_nitr_store_ratio:long_name = "storeable (labile) N, as a ratio compared to the N bound in cell structures of other organs (see code)" ; + double fates_cnp_phos_store_ratio(fates_pft) ; + fates_cnp_phos_store_ratio:units = "(gP/gP)" ; + fates_cnp_phos_store_ratio:long_name = "storeable (labile) P, as a ratio compared to the P bound in cell structures of other organs (see code)" ; + double fates_cnp_pid_kd(fates_pft) ; + fates_cnp_pid_kd:units = "unknown" ; + fates_cnp_pid_kd:long_name = "derivative constant of the PID controller on adaptive fine-root biomass" ; + double fates_cnp_pid_ki(fates_pft) ; + fates_cnp_pid_ki:units = "unknown" ; + fates_cnp_pid_ki:long_name = "integral constant of the PID controller on adaptive fine-root biomass" ; + double fates_cnp_pid_kp(fates_pft) ; + fates_cnp_pid_kp:units = "unknown" ; + fates_cnp_pid_kp:long_name = "proportional constant of the PID controller on adaptive fine-root biomass" ; + double fates_cnp_prescribed_nuptake(fates_pft) ; + fates_cnp_prescribed_nuptake:units = "fraction" ; + fates_cnp_prescribed_nuptake:long_name = "Prescribed N uptake flux. 0=fully coupled simulation >0=prescribed (experimental)" ; + double fates_cnp_prescribed_puptake(fates_pft) ; + fates_cnp_prescribed_puptake:units = "fraction" ; + fates_cnp_prescribed_puptake:long_name = "Prescribed P uptake flux. 0=fully coupled simulation, >0=prescribed (experimental)" ; + double fates_cnp_store_ovrflw_frac(fates_pft) ; + fates_cnp_store_ovrflw_frac:units = "fraction" ; + fates_cnp_store_ovrflw_frac:long_name = "size of overflow storage (for excess C,N or P) as a fraction of storage target" ; + double fates_cnp_turnover_nitr_retrans(fates_plant_organs, fates_pft) ; + fates_cnp_turnover_nitr_retrans:units = "fraction" ; + fates_cnp_turnover_nitr_retrans:long_name = "retranslocation (reabsorbtion) fraction of nitrogen in turnover of scenescing tissues" ; + double fates_cnp_turnover_phos_retrans(fates_plant_organs, fates_pft) ; + fates_cnp_turnover_phos_retrans:units = "fraction" ; + fates_cnp_turnover_phos_retrans:long_name = "retranslocation (reabsorbtion) fraction of phosphorus in turnover of scenescing tissues" ; + double fates_cnp_vmax_nh4(fates_pft) ; + fates_cnp_vmax_nh4:units = "gN/gC/s" ; + fates_cnp_vmax_nh4:long_name = "maximum (potential) uptake rate of NH4 per gC of fineroot biomass (see main/EDPftvarcon.F90 vmax_nh4 for usage)" ; + double fates_cnp_vmax_no3(fates_pft) ; + fates_cnp_vmax_no3:units = "gN/gC/s" ; + fates_cnp_vmax_no3:long_name = "maximum (potential) uptake rate of NO3 per gC of fineroot biomass (see main/EDPftvarcon.F90 vmax_no3 for usage)" ; + double fates_cnp_vmax_p(fates_pft) ; + fates_cnp_vmax_p:units = "gP/gC/s" ; + fates_cnp_vmax_p:long_name = "maximum production rate for phosphorus (ECA and RD)" ; + double fates_damage_frac(fates_pft) ; + fates_damage_frac:units = "fraction" ; + fates_damage_frac:long_name = "fraction of cohort damaged in each damage event (event frequency specified in the is_it_damage_time subroutine)" ; + double fates_damage_mort_p1(fates_pft) ; + fates_damage_mort_p1:units = "fraction" ; + fates_damage_mort_p1:long_name = "inflection point of damage mortality function, a value of 0.8 means 50% mortality with 80% loss of crown, turn off with a large number" ; + double fates_damage_mort_p2(fates_pft) ; + fates_damage_mort_p2:units = "unitless" ; + fates_damage_mort_p2:long_name = "rate of mortality increase with damage" ; + double fates_damage_recovery_scalar(fates_pft) ; + fates_damage_recovery_scalar:units = "unitless" ; + fates_damage_recovery_scalar:long_name = "fraction of the cohort that recovers from damage" ; + double fates_dev_arbitrary_pft(fates_pft) ; + fates_dev_arbitrary_pft:units = "unknown" ; + fates_dev_arbitrary_pft:long_name = "Unassociated pft dimensioned free parameter that developers can use for testing arbitrary new hypotheses" ; + double fates_fire_alpha_SH(fates_pft) ; + fates_fire_alpha_SH:units = "m / (kw/m)**(2/3)" ; + fates_fire_alpha_SH:long_name = "spitfire parameter, alpha scorch height, Equation 16 Thonicke et al 2010" ; + double fates_fire_bark_scaler(fates_pft) ; + fates_fire_bark_scaler:units = "fraction" ; + fates_fire_bark_scaler:long_name = "the thickness of a cohorts bark as a fraction of its dbh" ; + double fates_fire_crown_kill(fates_pft) ; + fates_fire_crown_kill:units = "NA" ; + fates_fire_crown_kill:long_name = "fire parameter, see equation 22 in Thonicke et al 2010" ; + double fates_frag_fnrt_fcel(fates_pft) ; + fates_frag_fnrt_fcel:units = "fraction" ; + fates_frag_fnrt_fcel:long_name = "Fine root litter cellulose fraction" ; + double fates_frag_fnrt_flab(fates_pft) ; + fates_frag_fnrt_flab:units = "fraction" ; + fates_frag_fnrt_flab:long_name = "Fine root litter labile fraction" ; + double fates_frag_fnrt_flig(fates_pft) ; + fates_frag_fnrt_flig:units = "fraction" ; + fates_frag_fnrt_flig:long_name = "Fine root litter lignin fraction" ; + double fates_frag_leaf_fcel(fates_pft) ; + fates_frag_leaf_fcel:units = "fraction" ; + fates_frag_leaf_fcel:long_name = "Leaf litter cellulose fraction" ; + double fates_frag_leaf_flab(fates_pft) ; + fates_frag_leaf_flab:units = "fraction" ; + fates_frag_leaf_flab:long_name = "Leaf litter labile fraction" ; + double fates_frag_leaf_flig(fates_pft) ; + fates_frag_leaf_flig:units = "fraction" ; + fates_frag_leaf_flig:long_name = "Leaf litter lignin fraction" ; + double fates_frag_seed_decay_rate(fates_pft) ; + fates_frag_seed_decay_rate:units = "yr-1" ; + fates_frag_seed_decay_rate:long_name = "fraction of seeds that decay per year" ; + double fates_grperc(fates_pft) ; + fates_grperc:units = "unitless" ; + fates_grperc:long_name = "Growth respiration factor" ; + double fates_hydro_avuln_gs(fates_pft) ; + fates_hydro_avuln_gs:units = "unitless" ; + fates_hydro_avuln_gs:long_name = "shape parameter for stomatal control of water vapor exiting leaf" ; + double fates_hydro_avuln_node(fates_hydr_organs, fates_pft) ; + fates_hydro_avuln_node:units = "unitless" ; + fates_hydro_avuln_node:long_name = "xylem vulnerability curve shape parameter" ; + double fates_hydro_epsil_node(fates_hydr_organs, fates_pft) ; + fates_hydro_epsil_node:units = "MPa" ; + fates_hydro_epsil_node:long_name = "bulk elastic modulus" ; + double fates_hydro_fcap_node(fates_hydr_organs, fates_pft) ; + fates_hydro_fcap_node:units = "unitless" ; + fates_hydro_fcap_node:long_name = "fraction of non-residual water that is capillary in source" ; + double fates_hydro_k_lwp(fates_pft) ; + fates_hydro_k_lwp:units = "unitless" ; + fates_hydro_k_lwp:long_name = "inner leaf humidity scaling coefficient" ; + double fates_hydro_kmax_node(fates_hydr_organs, fates_pft) ; + fates_hydro_kmax_node:units = "kg/MPa/m/s" ; + fates_hydro_kmax_node:long_name = "maximum xylem conductivity per unit conducting xylem area" ; + double fates_hydro_p50_gs(fates_pft) ; + fates_hydro_p50_gs:units = "MPa" ; + fates_hydro_p50_gs:long_name = "water potential at 50% loss of stomatal conductance" ; + double fates_hydro_p50_node(fates_hydr_organs, fates_pft) ; + fates_hydro_p50_node:units = "MPa" ; + fates_hydro_p50_node:long_name = "xylem water potential at 50% loss of conductivity" ; + double fates_hydro_p_taper(fates_pft) ; + fates_hydro_p_taper:units = "unitless" ; + fates_hydro_p_taper:long_name = "xylem taper exponent" ; + double fates_hydro_pinot_node(fates_hydr_organs, fates_pft) ; + fates_hydro_pinot_node:units = "MPa" ; + fates_hydro_pinot_node:long_name = "osmotic potential at full turgor" ; + double fates_hydro_pitlp_node(fates_hydr_organs, fates_pft) ; + fates_hydro_pitlp_node:units = "MPa" ; + fates_hydro_pitlp_node:long_name = "turgor loss point" ; + double fates_hydro_resid_node(fates_hydr_organs, fates_pft) ; + fates_hydro_resid_node:units = "cm3/cm3" ; + fates_hydro_resid_node:long_name = "residual water conent" ; + double fates_hydro_rfrac_stem(fates_pft) ; + fates_hydro_rfrac_stem:units = "fraction" ; + fates_hydro_rfrac_stem:long_name = "fraction of total tree resistance from troot to canopy" ; + double fates_hydro_rs2(fates_pft) ; + fates_hydro_rs2:units = "m" ; + fates_hydro_rs2:long_name = "absorbing root radius" ; + double fates_hydro_srl(fates_pft) ; + fates_hydro_srl:units = "m g-1" ; + fates_hydro_srl:long_name = "specific root length" ; + double fates_hydro_thetas_node(fates_hydr_organs, fates_pft) ; + fates_hydro_thetas_node:units = "cm3/cm3" ; + fates_hydro_thetas_node:long_name = "saturated water content" ; + double fates_hydro_vg_alpha_node(fates_hydr_organs, fates_pft) ; + fates_hydro_vg_alpha_node:units = "MPa-1" ; + fates_hydro_vg_alpha_node:long_name = "(used if hydr_htftype_node = 2), capillary length parameter in van Genuchten model" ; + double fates_hydro_vg_m_node(fates_hydr_organs, fates_pft) ; + fates_hydro_vg_m_node:units = "unitless" ; + fates_hydro_vg_m_node:long_name = "(used if hydr_htftype_node = 2),m in van Genuchten 1980 model, 2nd pore size distribution parameter" ; + double fates_hydro_vg_n_node(fates_hydr_organs, fates_pft) ; + fates_hydro_vg_n_node:units = "unitless" ; + fates_hydro_vg_n_node:long_name = "(used if hydr_htftype_node = 2),n in van Genuchten 1980 model, pore size distribution parameter" ; + double fates_leaf_c3psn(fates_pft) ; + fates_leaf_c3psn:units = "flag" ; + fates_leaf_c3psn:long_name = "Photosynthetic pathway (1=c3, 0=c4)" ; + double fates_leaf_jmaxha(fates_pft) ; + fates_leaf_jmaxha:units = "J/mol" ; + fates_leaf_jmaxha:long_name = "activation energy for jmax. NOTE: if fates_leaf_photo_tempsens_model=2 then these values are NOT USED" ; + double fates_leaf_jmaxhd(fates_pft) ; + fates_leaf_jmaxhd:units = "J/mol" ; + fates_leaf_jmaxhd:long_name = "deactivation energy for jmax. NOTE: if fates_leaf_photo_tempsens_model=2 then these values are NOT USED" ; + double fates_leaf_jmaxse(fates_pft) ; + fates_leaf_jmaxse:units = "J/mol/K" ; + fates_leaf_jmaxse:long_name = "entropy term for jmax. NOTE: if fates_leaf_photo_tempsens_model=2 then these values are NOT USED" ; + double fates_leaf_slamax(fates_pft) ; + fates_leaf_slamax:units = "m^2/gC" ; + fates_leaf_slamax:long_name = "Maximum Specific Leaf Area (SLA), even if under a dense canopy" ; + double fates_leaf_slatop(fates_pft) ; + fates_leaf_slatop:units = "m^2/gC" ; + fates_leaf_slatop:long_name = "Specific Leaf Area (SLA) at top of canopy, projected area basis" ; + double fates_leaf_stomatal_intercept(fates_pft) ; + fates_leaf_stomatal_intercept:units = "umol H2O/m**2/s" ; + fates_leaf_stomatal_intercept:long_name = "Minimum unstressed stomatal conductance for Ball-Berry model and Medlyn model" ; + double fates_leaf_stomatal_slope_ballberry(fates_pft) ; + fates_leaf_stomatal_slope_ballberry:units = "unitless" ; + fates_leaf_stomatal_slope_ballberry:long_name = "stomatal slope parameter, as per Ball-Berry" ; + double fates_leaf_stomatal_slope_medlyn(fates_pft) ; + fates_leaf_stomatal_slope_medlyn:units = "KPa**0.5" ; + fates_leaf_stomatal_slope_medlyn:long_name = "stomatal slope parameter, as per Medlyn" ; + double fates_leaf_vcmax25top(fates_leafage_class, fates_pft) ; + fates_leaf_vcmax25top:units = "umol CO2/m^2/s" ; + fates_leaf_vcmax25top:long_name = "maximum carboxylation rate of Rub. at 25C, canopy top" ; + double fates_leaf_vcmaxha(fates_pft) ; + fates_leaf_vcmaxha:units = "J/mol" ; + fates_leaf_vcmaxha:long_name = "activation energy for vcmax. NOTE: if fates_leaf_photo_tempsens_model=2 then these values are NOT USED" ; + double fates_leaf_vcmaxhd(fates_pft) ; + fates_leaf_vcmaxhd:units = "J/mol" ; + fates_leaf_vcmaxhd:long_name = "deactivation energy for vcmax. NOTE: if fates_leaf_photo_tempsens_model=2 then these values are NOT USED" ; + double fates_leaf_vcmaxse(fates_pft) ; + fates_leaf_vcmaxse:units = "J/mol/K" ; + fates_leaf_vcmaxse:long_name = "entropy term for vcmax. NOTE: if fates_leaf_photo_tempsens_model=2 then these values are NOT USED" ; + double fates_maintresp_leaf_atkin2017_baserate(fates_pft) ; + fates_maintresp_leaf_atkin2017_baserate:units = "umol CO2/m^2/s" ; + fates_maintresp_leaf_atkin2017_baserate:long_name = "Leaf maintenance respiration base rate parameter (r0) per Atkin et al 2017" ; + double fates_maintresp_leaf_ryan1991_baserate(fates_pft) ; + fates_maintresp_leaf_ryan1991_baserate:units = "gC/gN/s" ; + fates_maintresp_leaf_ryan1991_baserate:long_name = "Leaf maintenance respiration base rate per Ryan et al 1991" ; + double fates_maintresp_reduction_curvature(fates_pft) ; + fates_maintresp_reduction_curvature:units = "unitless (0-1)" ; + fates_maintresp_reduction_curvature:long_name = "curvature of MR reduction as f(carbon storage), 1=linear, 0=very curved" ; + double fates_maintresp_reduction_intercept(fates_pft) ; + fates_maintresp_reduction_intercept:units = "unitless (0-1)" ; + fates_maintresp_reduction_intercept:long_name = "intercept of MR reduction as f(carbon storage), 0=no throttling, 1=max throttling" ; + double fates_mort_bmort(fates_pft) ; + fates_mort_bmort:units = "1/yr" ; + fates_mort_bmort:long_name = "background mortality rate" ; + double fates_mort_freezetol(fates_pft) ; + fates_mort_freezetol:units = "degrees C" ; + fates_mort_freezetol:long_name = "minimum temperature tolerance" ; + double fates_mort_hf_flc_threshold(fates_pft) ; + fates_mort_hf_flc_threshold:units = "fraction" ; + fates_mort_hf_flc_threshold:long_name = "plant fractional loss of conductivity at which drought mortality begins for hydraulic model" ; + double fates_mort_hf_sm_threshold(fates_pft) ; + fates_mort_hf_sm_threshold:units = "unitless" ; + fates_mort_hf_sm_threshold:long_name = "soil moisture (btran units) at which drought mortality begins for non-hydraulic model" ; + double fates_mort_ip_age_senescence(fates_pft) ; + fates_mort_ip_age_senescence:units = "years" ; + fates_mort_ip_age_senescence:long_name = "Mortality cohort age senescence inflection point. If _ this mortality term is off. Setting this value turns on age dependent mortality. " ; + double fates_mort_ip_size_senescence(fates_pft) ; + fates_mort_ip_size_senescence:units = "dbh cm" ; + fates_mort_ip_size_senescence:long_name = "Mortality dbh senescence inflection point. If _ this mortality term is off. Setting this value turns on size dependent mortality" ; + double fates_mort_prescribed_canopy(fates_pft) ; + fates_mort_prescribed_canopy:units = "1/yr" ; + fates_mort_prescribed_canopy:long_name = "mortality rate of canopy trees for prescribed physiology mode" ; + double fates_mort_prescribed_understory(fates_pft) ; + fates_mort_prescribed_understory:units = "1/yr" ; + fates_mort_prescribed_understory:long_name = "mortality rate of understory trees for prescribed physiology mode" ; + double fates_mort_r_age_senescence(fates_pft) ; + fates_mort_r_age_senescence:units = "mortality rate year^-1" ; + fates_mort_r_age_senescence:long_name = "Mortality age senescence rate of change. Sensible range is around 0.03-0.06. Larger values givesteeper mortality curves." ; + double fates_mort_r_size_senescence(fates_pft) ; + fates_mort_r_size_senescence:units = "mortality rate dbh^-1" ; + fates_mort_r_size_senescence:long_name = "Mortality dbh senescence rate of change. Sensible range is around 0.03-0.06. Larger values give steeper mortality curves." ; + double fates_mort_scalar_coldstress(fates_pft) ; + fates_mort_scalar_coldstress:units = "1/yr" ; + fates_mort_scalar_coldstress:long_name = "maximum mortality rate from cold stress" ; + double fates_mort_scalar_cstarvation(fates_pft) ; + fates_mort_scalar_cstarvation:units = "1/yr" ; + fates_mort_scalar_cstarvation:long_name = "maximum mortality rate from carbon starvation" ; + double fates_mort_scalar_hydrfailure(fates_pft) ; + fates_mort_scalar_hydrfailure:units = "1/yr" ; + fates_mort_scalar_hydrfailure:long_name = "maximum mortality rate from hydraulic failure" ; + double fates_nonhydro_smpsc(fates_pft) ; + fates_nonhydro_smpsc:units = "mm" ; + fates_nonhydro_smpsc:long_name = "Soil water potential at full stomatal closure" ; + double fates_nonhydro_smpso(fates_pft) ; + fates_nonhydro_smpso:units = "mm" ; + fates_nonhydro_smpso:long_name = "Soil water potential at full stomatal opening" ; + double fates_phen_cold_size_threshold(fates_pft) ; + fates_phen_cold_size_threshold:units = "cm" ; + fates_phen_cold_size_threshold:long_name = "the dbh size above which will lead to phenology-related stem and leaf drop" ; + double fates_phen_evergreen(fates_pft) ; + fates_phen_evergreen:units = "logical flag" ; + fates_phen_evergreen:long_name = "Binary flag for evergreen leaf habit" ; + double fates_phen_flush_fraction(fates_pft) ; + fates_phen_flush_fraction:units = "fraction" ; + fates_phen_flush_fraction:long_name = "Upon bud-burst, the maximum fraction of storage carbon used for flushing leaves" ; + double fates_phen_fnrt_drop_frac(fates_pft) ; + fates_phen_fnrt_drop_frac:units = "fraction" ; + fates_phen_fnrt_drop_frac:long_name = "fraction of fine roots to drop during drought or cold" ; + double fates_phen_season_decid(fates_pft) ; + fates_phen_season_decid:units = "logical flag" ; + fates_phen_season_decid:long_name = "Binary flag for seasonal-deciduous leaf habit" ; + double fates_phen_stem_drop_fraction(fates_pft) ; + fates_phen_stem_drop_fraction:units = "fraction" ; + fates_phen_stem_drop_fraction:long_name = "fraction of stems to drop for non-woody species during drought/cold" ; + double fates_phen_stress_decid(fates_pft) ; + fates_phen_stress_decid:units = "logical flag" ; + fates_phen_stress_decid:long_name = "Binary flag for stress-deciduous leaf habit" ; + double fates_prescribed_npp_canopy(fates_pft) ; + fates_prescribed_npp_canopy:units = "kgC / m^2 / yr" ; + fates_prescribed_npp_canopy:long_name = "NPP per unit crown area of canopy trees for prescribed physiology mode" ; + double fates_prescribed_npp_understory(fates_pft) ; + fates_prescribed_npp_understory:units = "kgC / m^2 / yr" ; + fates_prescribed_npp_understory:long_name = "NPP per unit crown area of understory trees for prescribed physiology mode" ; + double fates_rad_leaf_clumping_index(fates_pft) ; + fates_rad_leaf_clumping_index:units = "fraction (0-1)" ; + fates_rad_leaf_clumping_index:long_name = "factor describing how much self-occlusion of leaf scattering elements decreases light interception" ; + double fates_rad_leaf_rhonir(fates_pft) ; + fates_rad_leaf_rhonir:units = "fraction" ; + fates_rad_leaf_rhonir:long_name = "Leaf reflectance: near-IR" ; + double fates_rad_leaf_rhovis(fates_pft) ; + fates_rad_leaf_rhovis:units = "fraction" ; + fates_rad_leaf_rhovis:long_name = "Leaf reflectance: visible" ; + double fates_rad_leaf_taunir(fates_pft) ; + fates_rad_leaf_taunir:units = "fraction" ; + fates_rad_leaf_taunir:long_name = "Leaf transmittance: near-IR" ; + double fates_rad_leaf_tauvis(fates_pft) ; + fates_rad_leaf_tauvis:units = "fraction" ; + fates_rad_leaf_tauvis:long_name = "Leaf transmittance: visible" ; + double fates_rad_leaf_xl(fates_pft) ; + fates_rad_leaf_xl:units = "unitless" ; + fates_rad_leaf_xl:long_name = "Leaf/stem orientation index" ; + double fates_rad_stem_rhonir(fates_pft) ; + fates_rad_stem_rhonir:units = "fraction" ; + fates_rad_stem_rhonir:long_name = "Stem reflectance: near-IR" ; + double fates_rad_stem_rhovis(fates_pft) ; + fates_rad_stem_rhovis:units = "fraction" ; + fates_rad_stem_rhovis:long_name = "Stem reflectance: visible" ; + double fates_rad_stem_taunir(fates_pft) ; + fates_rad_stem_taunir:units = "fraction" ; + fates_rad_stem_taunir:long_name = "Stem transmittance: near-IR" ; + double fates_rad_stem_tauvis(fates_pft) ; + fates_rad_stem_tauvis:units = "fraction" ; + fates_rad_stem_tauvis:long_name = "Stem transmittance: visible" ; + double fates_recruit_height_min(fates_pft) ; + fates_recruit_height_min:units = "m" ; + fates_recruit_height_min:long_name = "the minimum height (ie starting height) of a newly recruited plant" ; + double fates_recruit_init_density(fates_pft) ; + fates_recruit_init_density:units = "stems/m2" ; + fates_recruit_init_density:long_name = "initial seedling density for a cold-start near-bare-ground simulation. If negative sets initial tree dbh - only to be used in nocomp mode" ; + double fates_recruit_prescribed_rate(fates_pft) ; + fates_recruit_prescribed_rate:units = "n/yr" ; + fates_recruit_prescribed_rate:long_name = "recruitment rate for prescribed physiology mode" ; + double fates_recruit_seed_alloc(fates_pft) ; + fates_recruit_seed_alloc:units = "fraction" ; + fates_recruit_seed_alloc:long_name = "fraction of available carbon balance allocated to seeds" ; + double fates_recruit_seed_alloc_mature(fates_pft) ; + fates_recruit_seed_alloc_mature:units = "fraction" ; + fates_recruit_seed_alloc_mature:long_name = "fraction of available carbon balance allocated to seeds in mature plants (adds to fates_seed_alloc)" ; + double fates_recruit_seed_dbh_repro_threshold(fates_pft) ; + fates_recruit_seed_dbh_repro_threshold:units = "cm" ; + fates_recruit_seed_dbh_repro_threshold:long_name = "the diameter where the plant will increase allocation to the seed pool by fraction: fates_recruit_seed_alloc_mature" ; + double fates_recruit_seed_germination_rate(fates_pft) ; + fates_recruit_seed_germination_rate:units = "yr-1" ; + fates_recruit_seed_germination_rate:long_name = "fraction of seeds that germinate per year" ; + double fates_recruit_seed_supplement(fates_pft) ; + fates_recruit_seed_supplement:units = "KgC/m2/yr" ; + fates_recruit_seed_supplement:long_name = "Supplemental external seed rain source term (non-mass conserving)" ; + double fates_stoich_nitr(fates_plant_organs, fates_pft) ; + fates_stoich_nitr:units = "gN/gC" ; + fates_stoich_nitr:long_name = "target nitrogen concentration (ratio with carbon) of organs" ; + double fates_stoich_phos(fates_plant_organs, fates_pft) ; + fates_stoich_phos:units = "gP/gC" ; + fates_stoich_phos:long_name = "target phosphorus concentration (ratio with carbon) of organs" ; + double fates_trim_inc(fates_pft) ; + fates_trim_inc:units = "m2/m2" ; + fates_trim_inc:long_name = "Arbitrary incremental change in trimming function." ; + double fates_trim_limit(fates_pft) ; + fates_trim_limit:units = "m2/m2" ; + fates_trim_limit:long_name = "Arbitrary limit to reductions in leaf area with stress" ; + double fates_turb_displar(fates_pft) ; + fates_turb_displar:units = "unitless" ; + fates_turb_displar:long_name = "Ratio of displacement height to canopy top height" ; + double fates_turb_leaf_diameter(fates_pft) ; + fates_turb_leaf_diameter:units = "m" ; + fates_turb_leaf_diameter:long_name = "Characteristic leaf dimension" ; + double fates_turb_z0mr(fates_pft) ; + fates_turb_z0mr:units = "unitless" ; + fates_turb_z0mr:long_name = "Ratio of momentum roughness length to canopy top height" ; + double fates_turnover_branch(fates_pft) ; + fates_turnover_branch:units = "yr" ; + fates_turnover_branch:long_name = "turnover time of branches" ; + double fates_turnover_fnrt(fates_pft) ; + fates_turnover_fnrt:units = "yr" ; + fates_turnover_fnrt:long_name = "root longevity (alternatively, turnover time)" ; + double fates_turnover_leaf(fates_leafage_class, fates_pft) ; + fates_turnover_leaf:units = "yr" ; + fates_turnover_leaf:long_name = "Leaf longevity (ie turnover timescale)" ; + double fates_turnover_senleaf_fdrought(fates_pft) ; + fates_turnover_senleaf_fdrought:units = "unitless[0-1]" ; + fates_turnover_senleaf_fdrought:long_name = "multiplication factor for leaf longevity of senescent leaves during drought" ; + double fates_wood_density(fates_pft) ; + fates_wood_density:units = "g/cm3" ; + fates_wood_density:long_name = "mean density of woody tissue in plant" ; + double fates_woody(fates_pft) ; + fates_woody:units = "logical flag" ; + fates_woody:long_name = "Binary woody lifeform flag" ; + double fates_hlm_pft_map(fates_hlm_pftno, fates_pft) ; + fates_hlm_pft_map:units = "area fraction" ; + fates_hlm_pft_map:long_name = "In fixed biogeog mode, fraction of HLM area associated with each FATES PFT" ; + double fates_fire_FBD(fates_litterclass) ; + fates_fire_FBD:units = "kg Biomass/m3" ; + fates_fire_FBD:long_name = "fuel bulk density" ; + double fates_fire_low_moisture_Coeff(fates_litterclass) ; + fates_fire_low_moisture_Coeff:units = "NA" ; + fates_fire_low_moisture_Coeff:long_name = "spitfire parameter, equation B1 Thonicke et al 2010" ; + double fates_fire_low_moisture_Slope(fates_litterclass) ; + fates_fire_low_moisture_Slope:units = "NA" ; + fates_fire_low_moisture_Slope:long_name = "spitfire parameter, equation B1 Thonicke et al 2010" ; + double fates_fire_mid_moisture(fates_litterclass) ; + fates_fire_mid_moisture:units = "NA" ; + fates_fire_mid_moisture:long_name = "spitfire litter moisture threshold to be considered medium dry" ; + double fates_fire_mid_moisture_Coeff(fates_litterclass) ; + fates_fire_mid_moisture_Coeff:units = "NA" ; + fates_fire_mid_moisture_Coeff:long_name = "spitfire parameter, equation B1 Thonicke et al 2010" ; + double fates_fire_mid_moisture_Slope(fates_litterclass) ; + fates_fire_mid_moisture_Slope:units = "NA" ; + fates_fire_mid_moisture_Slope:long_name = "spitfire parameter, equation B1 Thonicke et al 2010" ; + double fates_fire_min_moisture(fates_litterclass) ; + fates_fire_min_moisture:units = "NA" ; + fates_fire_min_moisture:long_name = "spitfire litter moisture threshold to be considered very dry" ; + double fates_fire_SAV(fates_litterclass) ; + fates_fire_SAV:units = "cm-1" ; + fates_fire_SAV:long_name = "fuel surface area to volume ratio" ; + double fates_frag_maxdecomp(fates_litterclass) ; + fates_frag_maxdecomp:units = "yr-1" ; + fates_frag_maxdecomp:long_name = "maximum rate of litter & CWD transfer from non-decomposing class into decomposing class" ; + double fates_frag_cwd_frac(fates_NCWD) ; + fates_frag_cwd_frac:units = "fraction" ; + fates_frag_cwd_frac:long_name = "fraction of woody (bdead+bsw) biomass destined for CWD pool" ; + double fates_canopy_closure_thresh ; + fates_canopy_closure_thresh:units = "unitless" ; + fates_canopy_closure_thresh:long_name = "tree canopy coverage at which crown area allometry changes from savanna to forest value" ; + double fates_cnp_eca_plant_escalar ; + fates_cnp_eca_plant_escalar:units = "" ; + fates_cnp_eca_plant_escalar:long_name = "scaling factor for plant fine root biomass to calculate nutrient carrier enzyme abundance (ECA)" ; + double fates_cohort_age_fusion_tol ; + fates_cohort_age_fusion_tol:units = "unitless" ; + fates_cohort_age_fusion_tol:long_name = "minimum fraction in differece in cohort age between cohorts." ; + double fates_cohort_size_fusion_tol ; + fates_cohort_size_fusion_tol:units = "unitless" ; + fates_cohort_size_fusion_tol:long_name = "minimum fraction in difference in dbh between cohorts" ; + double fates_comp_excln ; + fates_comp_excln:units = "none" ; + fates_comp_excln:long_name = "IF POSITIVE: weighting factor (exponent on dbh) for canopy layer exclusion and promotion, IF NEGATIVE: switch to use deterministic height sorting" ; + double fates_damage_canopy_layer_code ; + fates_damage_canopy_layer_code:units = "unitless" ; + fates_damage_canopy_layer_code:long_name = "Integer code that decides whether damage affects canopy trees (1), understory trees (2)" ; + double fates_damage_event_code ; + fates_damage_event_code:units = "unitless" ; + fates_damage_event_code:long_name = "Integer code that options how damage events are structured" ; + double fates_dev_arbitrary ; + fates_dev_arbitrary:units = "unknown" ; + fates_dev_arbitrary:long_name = "Unassociated free parameter that developers can use for testing arbitrary new hypotheses" ; + double fates_fire_active_crown_fire ; + fates_fire_active_crown_fire:units = "0 or 1" ; + fates_fire_active_crown_fire:long_name = "flag, 1=active crown fire 0=no active crown fire" ; + double fates_fire_cg_strikes ; + fates_fire_cg_strikes:units = "fraction (0-1)" ; + fates_fire_cg_strikes:long_name = "fraction of cloud to ground lightning strikes" ; + double fates_fire_drying_ratio ; + fates_fire_drying_ratio:units = "NA" ; + fates_fire_drying_ratio:long_name = "spitfire parameter, fire drying ratio for fuel moisture, alpha_FMC EQ 6 Thonicke et al 2010" ; + double fates_fire_durat_slope ; + fates_fire_durat_slope:units = "NA" ; + fates_fire_durat_slope:long_name = "spitfire parameter, fire max duration slope, Equation 14 Thonicke et al 2010" ; + double fates_fire_fdi_a ; + fates_fire_fdi_a:units = "NA" ; + fates_fire_fdi_a:long_name = "spitfire parameter, fire danger index, EQ 5 Thonicke et al 2010" ; + double fates_fire_fdi_alpha ; + fates_fire_fdi_alpha:units = "NA" ; + fates_fire_fdi_alpha:long_name = "spitfire parameter, EQ 7 Venevsky et al. GCB 2002,(modified EQ 8 Thonicke et al. 2010) " ; + double fates_fire_fdi_b ; + fates_fire_fdi_b:units = "NA" ; + fates_fire_fdi_b:long_name = "spitfire parameter, fire danger index, EQ 5 Thonicke et al 2010 " ; + double fates_fire_fuel_energy ; + fates_fire_fuel_energy:units = "kJ/kg" ; + fates_fire_fuel_energy:long_name = "spitfire parameter, heat content of fuel" ; + double fates_fire_max_durat ; + fates_fire_max_durat:units = "minutes" ; + fates_fire_max_durat:long_name = "spitfire parameter, fire maximum duration, Equation 14 Thonicke et al 2010" ; + double fates_fire_miner_damp ; + fates_fire_miner_damp:units = "NA" ; + fates_fire_miner_damp:long_name = "spitfire parameter, mineral-dampening coefficient EQ A1 Thonicke et al 2010 " ; + double fates_fire_miner_total ; + fates_fire_miner_total:units = "fraction" ; + fates_fire_miner_total:long_name = "spitfire parameter, total mineral content, Table A1 Thonicke et al 2010" ; + double fates_fire_nignitions ; + fates_fire_nignitions:units = "ignitions per year per km2" ; + fates_fire_nignitions:long_name = "number of annual ignitions per square km" ; + double fates_fire_part_dens ; + fates_fire_part_dens:units = "kg/m2" ; + fates_fire_part_dens:long_name = "spitfire parameter, oven dry particle density, Table A1 Thonicke et al 2010" ; + double fates_fire_threshold ; + fates_fire_threshold:units = "kW/m" ; + fates_fire_threshold:long_name = "spitfire parameter, fire intensity threshold for tracking fires that spread" ; + double fates_frag_cwd_fcel ; + fates_frag_cwd_fcel:units = "unitless" ; + fates_frag_cwd_fcel:long_name = "Cellulose fraction for CWD" ; + double fates_frag_cwd_flig ; + fates_frag_cwd_flig:units = "unitless" ; + fates_frag_cwd_flig:long_name = "Lignin fraction of coarse woody debris" ; + double fates_hydro_kmax_rsurf1 ; + fates_hydro_kmax_rsurf1:units = "kg water/m2 root area/Mpa/s" ; + fates_hydro_kmax_rsurf1:long_name = "maximum conducitivity for unit root surface (into root)" ; + double fates_hydro_kmax_rsurf2 ; + fates_hydro_kmax_rsurf2:units = "kg water/m2 root area/Mpa/s" ; + fates_hydro_kmax_rsurf2:long_name = "maximum conducitivity for unit root surface (out of root)" ; + double fates_hydro_psi0 ; + fates_hydro_psi0:units = "MPa" ; + fates_hydro_psi0:long_name = "sapwood water potential at saturation" ; + double fates_hydro_psicap ; + fates_hydro_psicap:units = "MPa" ; + fates_hydro_psicap:long_name = "sapwood water potential at which capillary reserves exhausted" ; + double fates_hydro_solver ; + fates_hydro_solver:units = "unitless" ; + fates_hydro_solver:long_name = "switch designating which numerical solver for plant hydraulics, 1 = 1D taylor, 2 = 2D Picard, 3 = 2D Newton (deprecated)" ; + double fates_landuse_logging_coll_under_frac ; + fates_landuse_logging_coll_under_frac:units = "fraction" ; + fates_landuse_logging_coll_under_frac:long_name = "Fraction of stems killed in the understory when logging generates disturbance" ; + double fates_landuse_logging_collateral_frac ; + fates_landuse_logging_collateral_frac:units = "fraction" ; + fates_landuse_logging_collateral_frac:long_name = "Fraction of large stems in upperstory that die from logging collateral damage" ; + double fates_landuse_logging_dbhmax ; + fates_landuse_logging_dbhmax:units = "cm" ; + fates_landuse_logging_dbhmax:long_name = "Maximum dbh below which logging is applied (unset values flag this to be unused)" ; + double fates_landuse_logging_dbhmax_infra ; + fates_landuse_logging_dbhmax_infra:units = "cm" ; + fates_landuse_logging_dbhmax_infra:long_name = "Tree diameter, above which infrastructure from logging does not impact damage or mortality." ; + double fates_landuse_logging_dbhmin ; + fates_landuse_logging_dbhmin:units = "cm" ; + fates_landuse_logging_dbhmin:long_name = "Minimum dbh at which logging is applied" ; + double fates_landuse_logging_direct_frac ; + fates_landuse_logging_direct_frac:units = "fraction" ; + fates_landuse_logging_direct_frac:long_name = "Fraction of stems logged directly per event" ; + double fates_landuse_logging_event_code ; + fates_landuse_logging_event_code:units = "unitless" ; + fates_landuse_logging_event_code:long_name = "Integer code that options how logging events are structured" ; + double fates_landuse_logging_export_frac ; + fates_landuse_logging_export_frac:units = "fraction" ; + fates_landuse_logging_export_frac:long_name = "fraction of trunk product being shipped offsite, the leftovers will be left onsite as large CWD" ; + double fates_landuse_logging_mechanical_frac ; + fates_landuse_logging_mechanical_frac:units = "fraction" ; + fates_landuse_logging_mechanical_frac:long_name = "Fraction of stems killed due infrastructure an other mechanical means" ; + double fates_landuse_pprodharv10_forest_mean ; + fates_landuse_pprodharv10_forest_mean:units = "fraction" ; + fates_landuse_pprodharv10_forest_mean:long_name = "mean harvest mortality proportion of deadstem to 10-yr product (pprodharv10) of all woody PFT types" ; + double fates_leaf_photo_temp_acclim_thome_time ; + fates_leaf_photo_temp_acclim_thome_time:units = "years" ; + fates_leaf_photo_temp_acclim_thome_time:long_name = "Length of the window for the long-term (i.e. T_home in Kumarathunge et al 2019) exponential moving average (ema) of vegetation temperature used in photosynthesis temperature acclimation (used if fates_leaf_photo_tempsens_model = 2)" ; + double fates_leaf_photo_temp_acclim_timescale ; + fates_leaf_photo_temp_acclim_timescale:units = "days" ; + fates_leaf_photo_temp_acclim_timescale:long_name = "Length of the window for the exponential moving average (ema) of vegetation temperature used in photosynthesis temperature acclimation (used if fates_maintresp_leaf_model=2 or fates_leaf_photo_tempsens_model = 2)" ; + double fates_leaf_photo_tempsens_model ; + fates_leaf_photo_tempsens_model:units = "unitless" ; + fates_leaf_photo_tempsens_model:long_name = "switch for choosing the model that defines the temperature sensitivity of photosynthetic parameters (vcmax, jmax). 1=non-acclimating; 2=Kumarathunge et al 2019" ; + double fates_leaf_stomatal_assim_model ; + fates_leaf_stomatal_assim_model:units = "unitless" ; + fates_leaf_stomatal_assim_model:long_name = "a switch designating whether to use net (1) or gross (2) assimilation in the stomatal model" ; + double fates_leaf_stomatal_model ; + fates_leaf_stomatal_model:units = "unitless" ; + fates_leaf_stomatal_model:long_name = "switch for choosing between Ball-Berry (1) stomatal conductance model and Medlyn (2) model" ; + double fates_leaf_theta_cj_c3 ; + fates_leaf_theta_cj_c3:units = "unitless" ; + fates_leaf_theta_cj_c3:long_name = "Empirical curvature parameter for ac, aj photosynthesis co-limitation in c3 plants" ; + double fates_leaf_theta_cj_c4 ; + fates_leaf_theta_cj_c4:units = "unitless" ; + fates_leaf_theta_cj_c4:long_name = "Empirical curvature parameter for ac, aj photosynthesis co-limitation in c4 plants" ; + double fates_maintresp_leaf_model ; + fates_maintresp_leaf_model:units = "unitless" ; + fates_maintresp_leaf_model:long_name = "switch for choosing between maintenance respiration models. 1=Ryan (1991), 2=Atkin et al., (2017)" ; + double fates_maintresp_nonleaf_baserate ; + fates_maintresp_nonleaf_baserate:units = "gC/gN/s" ; + fates_maintresp_nonleaf_baserate:long_name = "Base maintenance respiration rate for plant tissues, using Ryan 1991" ; + double fates_maxcohort ; + fates_maxcohort:units = "count" ; + fates_maxcohort:long_name = "maximum number of cohorts per patch. Actual number of cohorts also depend on cohort fusion tolerances" ; + double fates_maxpatch_primary ; + fates_maxpatch_primary:units = "count" ; + fates_maxpatch_primary:long_name = "maximum number of primary vegetation patches per site" ; + double fates_maxpatch_secondary ; + fates_maxpatch_secondary:units = "count" ; + fates_maxpatch_secondary:long_name = "maximum number of secondary vegetation patches per site" ; + double fates_mort_disturb_frac ; + fates_mort_disturb_frac:units = "fraction" ; + fates_mort_disturb_frac:long_name = "fraction of canopy mortality that results in disturbance (i.e. transfer of area from new to old patch)" ; + double fates_mort_understorey_death ; + fates_mort_understorey_death:units = "fraction" ; + fates_mort_understorey_death:long_name = "fraction of plants in understorey cohort impacted by overstorey tree-fall" ; + double fates_patch_fusion_tol ; + fates_patch_fusion_tol:units = "unitless" ; + fates_patch_fusion_tol:long_name = "minimum fraction in difference in profiles between patches" ; + double fates_phen_chilltemp ; + fates_phen_chilltemp:units = "degrees C" ; + fates_phen_chilltemp:long_name = "chilling day counting threshold for vegetation" ; + double fates_phen_coldtemp ; + fates_phen_coldtemp:units = "degrees C" ; + fates_phen_coldtemp:long_name = "vegetation temperature exceedance that flags a cold-day for leaf-drop" ; + double fates_phen_drought_model ; + fates_phen_drought_model:units = "unitless" ; + fates_phen_drought_model:long_name = "which method to use for drought phenology: 0 - FATES default; 1 - Semi-deciduous (ED2-like)" ; + double fates_phen_drought_threshold ; + fates_phen_drought_threshold:units = "m3/m3 or mm" ; + fates_phen_drought_threshold:long_name = "threshold for drought phenology (or lower threshold when fates_phen_drought_model = 1); the quantity depends on the sign: if positive, the threshold is volumetric soil moisture (m3/m3). If negative, the threshold is soil matric potentical (mm)" ; + double fates_phen_gddthresh_a ; + fates_phen_gddthresh_a:units = "none" ; + fates_phen_gddthresh_a:long_name = "GDD accumulation function, intercept parameter: gdd_thesh = a + b exp(c*ncd)" ; + double fates_phen_gddthresh_b ; + fates_phen_gddthresh_b:units = "none" ; + fates_phen_gddthresh_b:long_name = "GDD accumulation function, multiplier parameter: gdd_thesh = a + b exp(c*ncd)" ; + double fates_phen_gddthresh_c ; + fates_phen_gddthresh_c:units = "none" ; + fates_phen_gddthresh_c:long_name = "GDD accumulation function, exponent parameter: gdd_thesh = a + b exp(c*ncd)" ; + double fates_phen_mindaysoff ; + fates_phen_mindaysoff:units = "days" ; + fates_phen_mindaysoff:long_name = "day threshold compared against days since leaves became off-allometry" ; + double fates_phen_mindayson ; + fates_phen_mindayson:units = "days" ; + fates_phen_mindayson:long_name = "day threshold compared against days since leaves became on-allometry" ; + double fates_phen_moist_threshold ; + fates_phen_moist_threshold:units = "m3/m3 or mm" ; + fates_phen_moist_threshold:long_name = "upper threshold for drought phenology (only for fates_phen_drought_model=1); the quantity depends on the sign: if positive, the threshold is volumetric soil moisture (m3/m3). If negative, the threshold is soil matric potentical (mm)" ; + double fates_phen_ncolddayslim ; + fates_phen_ncolddayslim:units = "days" ; + fates_phen_ncolddayslim:long_name = "day threshold exceedance for temperature leaf-drop" ; + double fates_q10_froz ; + fates_q10_froz:units = "unitless" ; + fates_q10_froz:long_name = "Q10 for frozen-soil respiration rates" ; + double fates_q10_mr ; + fates_q10_mr:units = "unitless" ; + fates_q10_mr:long_name = "Q10 for maintenance respiration" ; + double fates_soil_salinity ; + fates_soil_salinity:units = "ppt" ; + fates_soil_salinity:long_name = "soil salinity used for model when not coupled to dynamic soil salinity" ; + double fates_vai_top_bin_width ; + fates_vai_top_bin_width:units = "m2/m2" ; + fates_vai_top_bin_width:long_name = "width in VAI units of uppermost leaf+stem layer scattering element in each canopy layer" ; + double fates_vai_width_increase_factor ; + fates_vai_width_increase_factor:units = "unitless" ; + fates_vai_width_increase_factor:long_name = "factor by which each leaf+stem scattering element increases in VAI width (1 = uniform spacing)" ; + +// global attributes: + :history = "This file was generated by BatchPatchParams.py:\nCDL Base File = archive/api24.1.0_101722_fates_params_default.cdl\nXML patch file = archive/api24.1.0_101722_patch_params.xml" ; +data: + + fates_history_ageclass_bin_edges = 0, 1, 2, 5, 10, 20, 50 ; + + fates_history_coageclass_bin_edges = 0, 5 ; + + fates_history_height_bin_edges = 0, 0.1, 0.3, 1, 3, 10 ; + + fates_history_damage_bin_edges = 0, 80 ; + + fates_history_sizeclass_bin_edges = 0, 5, 10, 15, 20, 30, 40, 50, 60, 70, + 80, 90, 100 ; + + fates_alloc_organ_id = 1, 2, 3, 6 ; + + fates_hydro_htftype_node = 1, 1, 1, 1 ; + + fates_pftname = + "broadleaf_evergreen_tropical_tree ", + "needleleaf_evergreen_extratrop_tree ", + "needleleaf_colddecid_extratrop_tree ", + "broadleaf_evergreen_extratrop_tree ", + "broadleaf_hydrodecid_tropical_tree ", + "broadleaf_colddecid_extratrop_tree ", + "broadleaf_evergreen_extratrop_shrub ", + "broadleaf_hydrodecid_extratrop_shrub ", + "broadleaf_colddecid_extratrop_shrub ", + "arctic_c3_grass ", + "cool_c3_grass ", + "c4_grass " ; + + fates_hydro_organ_name = + "leaf ", + "stem ", + "transporting root ", + "absorbing root " ; + + fates_alloc_organ_name = + "leaf", + "fine root", + "sapwood", + "structure" ; + + fates_litterclass_name = + "twig ", + "small branch ", + "large branch ", + "trunk ", + "dead leaves ", + "live grass " ; + + fates_alloc_organ_priority = + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 ; + + fates_alloc_storage_cushion = 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, + 1.2, 1.2, 1.2 ; + + fates_alloc_store_priority_frac = 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, + 0.8, 0.8, 0.8, 0.8 ; + + fates_allom_agb1 = 0.06896, 0.06896, 0.06896, 0.06896, 0.06896, 0.06896, + 0.06896, 0.06896, 0.06896, 0.01, 0.01, 0.01 ; + + fates_allom_agb2 = 0.572, 0.572, 0.572, 0.572, 0.572, 0.572, 0.572, 0.572, + 0.572, 0.572, 0.572, 0.572 ; + + fates_allom_agb3 = 1.94, 1.94, 1.94, 1.94, 1.94, 1.94, 1.94, 1.94, 1.94, + 1.94, 1.94, 1.94 ; + + fates_allom_agb4 = 0.931, 0.931, 0.931, 0.931, 0.931, 0.931, 0.931, 0.931, + 0.931, 0.931, 0.931, 0.931 ; + + fates_allom_agb_frac = 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, + 0.6, 0.6 ; + + fates_allom_amode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_blca_expnt_diff = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_allom_cmode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_crown_depth_frac = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.95, 0.95, + 0.95, 1, 1, 1 ; + + fates_allom_d2bl1 = 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, + 0.07, 0.07, 0.07 ; + + fates_allom_d2bl2 = 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, + 1.3 ; + + fates_allom_d2bl3 = 0.55, 0.55, 0.55, 0.55, 0.55, 0.55, 0.55, 0.55, 0.55, + 0.55, 0.55, 0.55 ; + + fates_allom_d2ca_coefficient_max = 0.6568464, 0.6568464, 0.6568464, + 0.6568464, 0.6568464, 0.6568464, 0.6568464, 0.6568464, 0.6568464, + 0.6568464, 0.6568464, 0.6568464 ; + + fates_allom_d2ca_coefficient_min = 0.3381119, 0.3381119, 0.3381119, + 0.3381119, 0.3381119, 0.3381119, 0.3381119, 0.3381119, 0.3381119, + 0.3381119, 0.3381119, 0.3381119 ; + + fates_allom_d2h1 = 0.64, 0.64, 0.64, 0.64, 0.64, 0.64, 0.64, 0.64, 0.64, + 0.64, 0.64, 0.64 ; + + fates_allom_d2h2 = 0.37, 0.37, 0.37, 0.37, 0.37, 0.37, 0.37, 0.37, 0.37, + 0.37, 0.37, 0.37 ; + + fates_allom_d2h3 = -999.9, -999.9, -999.9, -999.9, -999.9, -999.9, -999.9, + -999.9, -999.9, -999.9, -999.9, -999.9 ; + + fates_allom_dbh_maxheight = 90, 80, 80, 80, 90, 80, 3, 3, 2, 0.35, 0.35, 0.35 ; + + fates_allom_fmode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_fnrt_prof_a = 7, 7, 7, 7, 6, 6, 7, 7, 7, 11, 11, 11 ; + + fates_allom_fnrt_prof_b = 1, 2, 2, 1, 2, 2, 1.5, 1.5, 1.5, 2, 2, 2 ; + + fates_allom_fnrt_prof_mode = 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 ; + + fates_allom_frbstor_repro = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_allom_hmode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_l2fr = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_la_per_sa_int = 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, + 0.8, 0.8, 0.8 ; + + fates_allom_la_per_sa_slp = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_allom_lmode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_sai_scaler = 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, + 0.1, 0.1 ; + + fates_allom_smode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_stmode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_zroot_k = 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10 ; + + fates_allom_zroot_max_dbh = 100, 100, 100, 100, 100, 100, 2, 2, 2, 2, 2, 2 ; + + fates_allom_zroot_max_z = 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, + 100, 100 ; + + fates_allom_zroot_min_dbh = 1, 1, 1, 2.5, 2.5, 2.5, 0.1, 0.1, 0.1, 0.1, 0.1, + 0.1 ; + + fates_allom_zroot_min_z = 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, + 100, 100 ; + + fates_c2b = 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ; + + fates_cnp_eca_alpha_ptase = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5 ; + + fates_cnp_eca_decompmicc = 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280 ; + + fates_cnp_eca_km_nh4 = 0.14, 0.14, 0.14, 0.14, 0.14, 0.14, 0.14, 0.14, 0.14, + 0.14, 0.14, 0.14 ; + + fates_cnp_eca_km_no3 = 0.27, 0.27, 0.27, 0.27, 0.27, 0.27, 0.27, 0.27, 0.27, + 0.27, 0.27, 0.27 ; + + fates_cnp_eca_km_p = 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, + 0.1 ; + + fates_cnp_eca_km_ptase = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_cnp_eca_lambda_ptase = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_cnp_eca_vmax_ptase = 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, + 5e-09, 5e-09, 5e-09, 5e-09, 5e-09 ; + + fates_cnp_nfix1 = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_cnp_nitr_store_ratio = 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, + 1.5, 1.5, 1.5 ; + + fates_cnp_phos_store_ratio = 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, + 1.5, 1.5, 1.5 ; + + fates_cnp_pid_kd = 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1 ; + + fates_cnp_pid_ki = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_cnp_pid_kp = 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, + 0.0005, 0.0005, 0.0005, 0.0005, 0.0005 ; + + fates_cnp_prescribed_nuptake = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_cnp_prescribed_puptake = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_cnp_store_ovrflw_frac = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_cnp_turnover_nitr_retrans = + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_cnp_turnover_phos_retrans = + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_cnp_vmax_nh4 = 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, + 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09 ; + + fates_cnp_vmax_no3 = 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, + 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09 ; + + fates_cnp_vmax_p = 5e-10, 5e-10, 5e-10, 5e-10, 5e-10, 5e-10, 5e-10, 5e-10, + 5e-10, 5e-10, 5e-10, 5e-10 ; + + fates_damage_frac = 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, + 0.01, 0.01, 0.01 ; + + fates_damage_mort_p1 = 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 ; + + fates_damage_mort_p2 = 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, + 5.5, 5.5 ; + + fates_damage_recovery_scalar = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_dev_arbitrary_pft = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_fire_alpha_SH = 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, + 0.2 ; + + fates_fire_bark_scaler = 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, + 0.07, 0.07, 0.07, 0.07 ; + + fates_fire_crown_kill = 0.775, 0.775, 0.775, 0.775, 0.775, 0.775, 0.775, + 0.775, 0.775, 0.775, 0.775, 0.775 ; + + fates_frag_fnrt_fcel = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5 ; + + fates_frag_fnrt_flab = 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25 ; + + fates_frag_fnrt_flig = 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25 ; + + fates_frag_leaf_fcel = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5 ; + + fates_frag_leaf_flab = 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25 ; + + fates_frag_leaf_flig = 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25 ; + + fates_frag_seed_decay_rate = 0.51, 0.51, 0.51, 0.51, 0.51, 0.51, 0.51, 0.51, + 0.51, 0.51, 0.51, 0.51 ; + + fates_grperc = 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, + 0.11, 0.11 ; + + fates_hydro_avuln_gs = 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, + 2.5, 2.5 ; + + fates_hydro_avuln_node = + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ; + + fates_hydro_epsil_node = + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 ; + + fates_hydro_fcap_node = + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, + 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_hydro_k_lwp = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_hydro_kmax_node = + -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999 ; + + fates_hydro_p50_gs = -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, + -1.5, -1.5, -1.5 ; + + fates_hydro_p50_node = + -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, + -2.25, -2.25, + -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, + -2.25, -2.25, + -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, + -2.25, -2.25, + -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, + -2.25, -2.25 ; + + fates_hydro_p_taper = 0.333, 0.333, 0.333, 0.333, 0.333, 0.333, 0.333, + 0.333, 0.333, 0.333, 0.333, 0.333 ; + + fates_hydro_pinot_node = + -1.465984, -1.465984, -1.465984, -1.465984, -1.465984, -1.465984, + -1.465984, -1.465984, -1.465984, -1.465984, -1.465984, -1.465984, + -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, + -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, + -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, + -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, + -1.043478, -1.043478, -1.043478, -1.043478, -1.043478, -1.043478, + -1.043478, -1.043478, -1.043478, -1.043478, -1.043478, -1.043478 ; + + fates_hydro_pitlp_node = + -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, + -1.67, -1.67, + -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, + -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, + -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2 ; + + fates_hydro_resid_node = + 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, + 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, + 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, + 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11 ; + + fates_hydro_rfrac_stem = 0.625, 0.625, 0.625, 0.625, 0.625, 0.625, 0.625, + 0.625, 0.625, 0.625, 0.625, 0.625 ; + + fates_hydro_rs2 = 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, + 0.0001, 0.0001, 0.0001, 0.0001, 0.0001 ; + + fates_hydro_srl = 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25 ; + + fates_hydro_thetas_node = + 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, + 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, + 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, + 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75 ; + + fates_hydro_vg_alpha_node = + 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.005, 0.005, 0.005, 0.005, 0.005, + 0.005, 0.005, + 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.005, 0.005, 0.005, 0.005, 0.005, + 0.005, 0.005, + 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.005, 0.005, 0.005, 0.005, 0.005, + 0.005, 0.005, + 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.005, 0.005, 0.005, 0.005, 0.005, + 0.005, 0.005 ; + + fates_hydro_vg_m_node = + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5 ; + + fates_hydro_vg_n_node = + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ; + + fates_leaf_c3psn = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 ; + + fates_leaf_jmaxha = 43540, 43540, 43540, 43540, 43540, 43540, 43540, 43540, + 43540, 43540, 43540, 43540 ; + + fates_leaf_jmaxhd = 152040, 152040, 152040, 152040, 152040, 152040, 152040, + 152040, 152040, 152040, 152040, 152040 ; + + fates_leaf_jmaxse = 495, 495, 495, 495, 495, 495, 495, 495, 495, 495, 495, + 495 ; + + fates_leaf_slamax = 0.0954, 0.0954, 0.0954, 0.0954, 0.0954, 0.0954, 0.012, + 0.03, 0.03, 0.03, 0.03, 0.03 ; + + fates_leaf_slatop = 0.012, 0.005, 0.024, 0.009, 0.03, 0.03, 0.012, 0.03, + 0.03, 0.03, 0.03, 0.03 ; + + fates_leaf_stomatal_intercept = 10000, 10000, 10000, 10000, 10000, 10000, + 10000, 10000, 10000, 10000, 10000, 40000 ; + + fates_leaf_stomatal_slope_ballberry = 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 ; + + fates_leaf_stomatal_slope_medlyn = 4.1, 2.3, 2.3, 4.1, 4.4, 4.4, 4.7, 4.7, + 4.7, 2.2, 5.3, 1.6 ; + + fates_leaf_vcmax25top = + 50, 62, 39, 61, 41, 58, 62, 54, 54, 78, 78, 78 ; + + fates_leaf_vcmaxha = 65330, 65330, 65330, 65330, 65330, 65330, 65330, 65330, + 65330, 65330, 65330, 65330 ; + + fates_leaf_vcmaxhd = 149250, 149250, 149250, 149250, 149250, 149250, 149250, + 149250, 149250, 149250, 149250, 149250 ; + + fates_leaf_vcmaxse = 485, 485, 485, 485, 485, 485, 485, 485, 485, 485, 485, + 485 ; + + fates_maintresp_leaf_atkin2017_baserate = 1.756, 1.4995, 1.4995, 1.756, + 1.756, 1.756, 2.0749, 2.0749, 2.0749, 2.1956, 2.1956, 2.1956 ; + + fates_maintresp_leaf_ryan1991_baserate = 2.525e-06, 2.525e-06, 2.525e-06, + 2.525e-06, 2.525e-06, 2.525e-06, 2.525e-06, 2.525e-06, 2.525e-06, + 2.525e-06, 2.525e-06, 2.525e-06 ; + + fates_maintresp_reduction_curvature = 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, + 0.01, 0.01, 0.01, 0.01, 0.01, 0.01 ; + + fates_maintresp_reduction_intercept = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_mort_bmort = 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, + 0.014, 0.014, 0.014, 0.014 ; + + fates_mort_freezetol = 2.5, -55, -80, -30, 2.5, -80, -60, -10, -80, -80, + -20, 2.5 ; + + fates_mort_hf_flc_threshold = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5 ; + + fates_mort_hf_sm_threshold = 1e-06, 1e-06, 1e-06, 1e-06, 1e-06, 1e-06, + 1e-06, 1e-06, 1e-06, 1e-06, 1e-06, 1e-06 ; + + fates_mort_ip_age_senescence = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_mort_ip_size_senescence = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_mort_prescribed_canopy = 0.0194, 0.0194, 0.0194, 0.0194, 0.0194, + 0.0194, 0.0194, 0.0194, 0.0194, 0.0194, 0.0194, 0.0194 ; + + fates_mort_prescribed_understory = 0.025, 0.025, 0.025, 0.025, 0.025, 0.025, + 0.025, 0.025, 0.025, 0.025, 0.025, 0.025 ; + + fates_mort_r_age_senescence = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_mort_r_size_senescence = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_mort_scalar_coldstress = 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 ; + + fates_mort_scalar_cstarvation = 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, + 0.6, 0.6, 0.6 ; + + fates_mort_scalar_hydrfailure = 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, + 0.6, 0.6, 0.6 ; + + fates_nonhydro_smpsc = -255000, -255000, -255000, -255000, -255000, -255000, + -255000, -255000, -255000, -255000, -255000, -255000 ; + + fates_nonhydro_smpso = -66000, -66000, -66000, -66000, -66000, -66000, + -66000, -66000, -66000, -66000, -66000, -66000 ; + + fates_phen_cold_size_threshold = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_phen_evergreen = 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 ; + + fates_phen_flush_fraction = _, _, 0.5, _, 0.5, 0.5, _, 0.5, 0.5, 0.5, 0.5, + 0.5 ; + + fates_phen_fnrt_drop_frac = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_phen_season_decid = 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0 ; + + fates_phen_stem_drop_fraction = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_phen_stress_decid = 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1 ; + + fates_prescribed_npp_canopy = 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, + 0.4, 0.4, 0.4 ; + + fates_prescribed_npp_understory = 0.03125, 0.03125, 0.03125, 0.03125, + 0.03125, 0.03125, 0.03125, 0.03125, 0.03125, 0.03125, 0.03125, 0.03125 ; + + fates_rad_leaf_clumping_index = 0.85, 0.85, 0.8, 0.85, 0.85, 0.9, 0.85, 0.9, + 0.9, 0.75, 0.75, 0.75 ; + + fates_rad_leaf_rhonir = 0.46, 0.41, 0.39, 0.46, 0.41, 0.41, 0.46, 0.41, + 0.41, 0.28, 0.28, 0.28 ; + + fates_rad_leaf_rhovis = 0.11, 0.09, 0.08, 0.11, 0.08, 0.08, 0.11, 0.08, + 0.08, 0.05, 0.05, 0.05 ; + + fates_rad_leaf_taunir = 0.33, 0.32, 0.42, 0.33, 0.43, 0.43, 0.33, 0.43, + 0.43, 0.4, 0.4, 0.4 ; + + fates_rad_leaf_tauvis = 0.06, 0.04, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, + 0.06, 0.05, 0.05, 0.05 ; + + fates_rad_leaf_xl = 0.32, 0.01, 0.01, 0.32, 0.2, 0.59, 0.32, 0.59, 0.59, + -0.23, -0.23, -0.23 ; + + fates_rad_stem_rhonir = 0.49, 0.36, 0.36, 0.49, 0.49, 0.49, 0.49, 0.49, + 0.49, 0.53, 0.53, 0.53 ; + + fates_rad_stem_rhovis = 0.21, 0.12, 0.12, 0.21, 0.21, 0.21, 0.21, 0.21, + 0.21, 0.31, 0.31, 0.31 ; + + fates_rad_stem_taunir = 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, + 0.001, 0.001, 0.25, 0.25, 0.25 ; + + fates_rad_stem_tauvis = 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, + 0.001, 0.001, 0.12, 0.12, 0.12 ; + + fates_recruit_height_min = 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 0.2, 0.2, 0.2, + 0.125, 0.125, 0.125 ; + + fates_recruit_init_density = 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, + 0.2, 0.2, 0.2 ; + + fates_recruit_prescribed_rate = 0.02, 0.02, 0.02, 0.02, 0.02, 0.02, 0.02, + 0.02, 0.02, 0.02, 0.02, 0.02 ; + + fates_recruit_seed_alloc = 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, + 0.1, 0.1 ; + + fates_recruit_seed_alloc_mature = 0, 0, 0, 0, 0, 0, 0.9, 0.9, 0.9, 0.9, 0.9, + 0.9 ; + + fates_recruit_seed_dbh_repro_threshold = 90, 80, 80, 80, 90, 80, 3, 3, 2, + 0.35, 0.35, 0.35 ; + + fates_recruit_seed_germination_rate = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5 ; + + fates_recruit_seed_supplement = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_stoich_nitr = + 0.033, 0.029, 0.04, 0.033, 0.04, 0.04, 0.033, 0.04, 0.04, 0.04, 0.04, 0.04, + 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, + 0.024, 0.024, + 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, + 1e-08, 1e-08, + 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, + 0.0047, 0.0047, 0.0047 ; + + fates_stoich_phos = + 0.0033, 0.0029, 0.004, 0.0033, 0.004, 0.004, 0.0033, 0.004, 0.004, 0.004, + 0.004, 0.004, + 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, + 0.0024, 0.0024, 0.0024, + 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, + 1e-09, 1e-09, + 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, + 0.00047, 0.00047, 0.00047, 0.00047 ; + + fates_trim_inc = 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, + 0.03, 0.03 ; + + fates_trim_limit = 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3 ; + + fates_turb_displar = 0.67, 0.67, 0.67, 0.67, 0.67, 0.67, 0.67, 0.67, 0.67, + 0.67, 0.67, 0.67 ; + + fates_turb_leaf_diameter = 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, + 0.04, 0.04, 0.04, 0.04 ; + + fates_turb_z0mr = 0.055, 0.055, 0.055, 0.055, 0.055, 0.055, 0.055, 0.055, + 0.055, 0.055, 0.055, 0.055 ; + + fates_turnover_branch = 150, 150, 150, 150, 150, 150, 150, 150, 150, 0, 0, 0 ; + + fates_turnover_fnrt = 1, 2, 1, 1.5, 1, 1, 1.5, 1, 1, 1, 1, 1 ; + + fates_turnover_leaf = + 1.5, 4, 1, 1.5, 1, 1, 1.5, 1, 1, 1, 1, 1 ; + + fates_turnover_senleaf_fdrought = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_wood_density = 0.7, 0.4, 0.7, 0.53, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, + 0.7 ; + + fates_woody = 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 ; + + fates_hlm_pft_map = + 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 ; + + fates_fire_FBD = 15.4, 16.8, 19.6, 999, 4, 4 ; + + fates_fire_low_moisture_Coeff = 1.12, 1.09, 0.98, 0.8, 1.15, 1.15 ; + + fates_fire_low_moisture_Slope = 0.62, 0.72, 0.85, 0.8, 0.62, 0.62 ; + + fates_fire_mid_moisture = 0.72, 0.51, 0.38, 1, 0.8, 0.8 ; + + fates_fire_mid_moisture_Coeff = 2.35, 1.47, 1.06, 0.8, 3.2, 3.2 ; + + fates_fire_mid_moisture_Slope = 2.35, 1.47, 1.06, 0.8, 3.2, 3.2 ; + + fates_fire_min_moisture = 0.18, 0.12, 0, 0, 0.24, 0.24 ; + + fates_fire_SAV = 13, 3.58, 0.98, 0.2, 66, 66 ; + + fates_frag_maxdecomp = 0.52, 0.383, 0.383, 0.19, 1, 999 ; + + fates_frag_cwd_frac = 0.045, 0.075, 0.21, 0.67 ; + + fates_canopy_closure_thresh = 0.8 ; + + fates_cnp_eca_plant_escalar = 1.25e-05 ; + + fates_cohort_age_fusion_tol = 0.08 ; + + fates_cohort_size_fusion_tol = 0.08 ; + + fates_comp_excln = 3 ; + + fates_damage_canopy_layer_code = 1 ; + + fates_damage_event_code = 1 ; + + fates_dev_arbitrary = _ ; + + fates_fire_active_crown_fire = 0 ; + + fates_fire_cg_strikes = 0.2 ; + + fates_fire_drying_ratio = 66000 ; + + fates_fire_durat_slope = -11.06 ; + + fates_fire_fdi_a = 17.62 ; + + fates_fire_fdi_alpha = 0.00037 ; + + fates_fire_fdi_b = 243.12 ; + + fates_fire_fuel_energy = 18000 ; + + fates_fire_max_durat = 240 ; + + fates_fire_miner_damp = 0.41739 ; + + fates_fire_miner_total = 0.055 ; + + fates_fire_nignitions = 15 ; + + fates_fire_part_dens = 513 ; + + fates_fire_threshold = 50 ; + + fates_frag_cwd_fcel = 0.76 ; + + fates_frag_cwd_flig = 0.24 ; + + fates_hydro_kmax_rsurf1 = 20 ; + + fates_hydro_kmax_rsurf2 = 0.0001 ; + + fates_hydro_psi0 = 0 ; + + fates_hydro_psicap = -0.6 ; + + fates_hydro_solver = 1 ; + + fates_landuse_logging_coll_under_frac = 0.55983 ; + + fates_landuse_logging_collateral_frac = 0.05 ; + + fates_landuse_logging_dbhmax = _ ; + + fates_landuse_logging_dbhmax_infra = 35 ; + + fates_landuse_logging_dbhmin = 50 ; + + fates_landuse_logging_direct_frac = 0.15 ; + + fates_landuse_logging_event_code = -30 ; + + fates_landuse_logging_export_frac = 0.8 ; + + fates_landuse_logging_mechanical_frac = 0.05 ; + + fates_landuse_pprodharv10_forest_mean = 0.8125 ; + + fates_leaf_photo_temp_acclim_thome_time = 30 ; + + fates_leaf_photo_temp_acclim_timescale = 30 ; + + fates_leaf_photo_tempsens_model = 1 ; + + fates_leaf_stomatal_assim_model = 1 ; + + fates_leaf_stomatal_model = 1 ; + + fates_leaf_theta_cj_c3 = 0.999 ; + + fates_leaf_theta_cj_c4 = 0.999 ; + + fates_maintresp_leaf_model = 1 ; + + fates_maintresp_nonleaf_baserate = 2.525e-06 ; + + fates_maxcohort = 100 ; + + fates_maxpatch_primary = 10 ; + + fates_maxpatch_secondary = 4 ; + + fates_mort_disturb_frac = 1 ; + + fates_mort_understorey_death = 0.55983 ; + + fates_patch_fusion_tol = 0.05 ; + + fates_phen_chilltemp = 5 ; + + fates_phen_coldtemp = 7.5 ; + + fates_phen_drought_model = 0 ; + + fates_phen_drought_threshold = 0.15 ; + + fates_phen_gddthresh_a = -68 ; + + fates_phen_gddthresh_b = 638 ; + + fates_phen_gddthresh_c = -0.01 ; + + fates_phen_mindaysoff = 100 ; + + fates_phen_mindayson = 90 ; + + fates_phen_moist_threshold = 0.18 ; + + fates_phen_ncolddayslim = 5 ; + + fates_q10_froz = 1.5 ; + + fates_q10_mr = 1.5 ; + + fates_soil_salinity = 0.4 ; + + fates_vai_top_bin_width = 1 ; + + fates_vai_width_increase_factor = 1 ; +} diff --git a/parameter_files/archive/api25.4.0_041023_pr958.xml b/parameter_files/archive/api25.4.0_041023_pr958.xml new file mode 100644 index 0000000000..7d30f52f71 --- /dev/null +++ b/parameter_files/archive/api25.4.0_041023_pr958.xml @@ -0,0 +1,303 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + archive/api25.4.0_041023_fates_params_default.cdl + fates_params_default.cdl + 1,2,3,4,5,6,7,8,9,10,11,12 + + + fates_maintresp_reduction_upthresh + fates_pft + unitless (0-1) + upper threshold for storage biomass (relative to leaf biomass) above which MR is not reduced + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 + + + fates_mort_upthresh_cstarvation + fates_pft + unitless + threshold for storage biomass (relative to target leaf biomass) above which carbon starvation is zero + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 + + + fates_phen_fnrt_drop_fraction + fraction of fine roots to drop during drought/cold + + + Leaf longevity (ie turnover timescale). For drought-deciduous PFTs, this also indicates the maximum length of the growing (i.e., leaves on) season. + + + fates_pft + 1.2, 1.2, 1.2, 1.2, 2.4, 1.2, 1.2, 2.4, 1.2, 1.2, 1.2, 1.2 + + + fates_pft + -152957.4, -152957.4, -152957.4, -152957.4, -152957.4, -152957.4, -152957.4, -152957.4, -152957.4, -152957.4, -152957.4, -152957.4 + threshold for drought phenology (or lower threshold for semi-deciduous PFTs); the quantity depends on the sign: if positive, the threshold is volumetric soil moisture (m3/m3). If negative, the threshold is soil matric potentical (mm) + + + fates_pft + -122365.9, -122365.9, -122365.9, -122365.9, -122365.9, -122365.9, -122365.9, -122365.9, -122365.9, -122365.9, -122365.9, -122365.9 + upper threshold for drought phenology (only for drought semi-deciduous PFTs); the quantity depends on the sign: if positive, the threshold is volumetric soil moisture (m3/m3). If negative, the threshold is soil matric potentical (mm) + + + fates_pft + 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100 + day threshold compared against days since leaves abscised (shed) + + + 50, 62, 39, 61, 58, 58, 62, 54, 54, 78, 78, 78 + + + fates_phen_drought_model + + + fates_rad_model + scalar + unitless + switch designating the model for canopy radiation, 1 = Norman, 2 = Two-stream (experimental) + 1 + + + fates_trs_repro_alloc_a + fates_pft + fraction + shape parameter for sigmoidal function relating dbh to reproductive allocation + 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 + fates_pft + fraction + intercept parameter for sigmoidal function relating dbh to reproductive allocation + -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 + fates_pft + fraction + fraction of reproductive mass that is 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 + fates_pft + day -1 + mean fraction of seed bank emerging + 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 + fates_pft + day -1 + seedling emergence sensitivity to soil moisture + 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 + fates_pft + MJ m-2 day-1 + critical light level for germination + 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_root_depth + fates_pft + m + rooting depth of seedlings + 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_psi_emerg + fates_pft + mm h20 suction + critical soil moisture for seedling emergence + -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 + fates_pft + mm H2O + critical soil moisture (suction) for seedling stress + -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 + fates_pft + mm H2O day + critical moisture deficit (suction) day accumulation for seedling moisture-based seedling mortality to begin + 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 + fates_pft + - + coefficient in moisture-based seedling mortality + 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 + fates_pft + - + coefficient in moisture-based seedling mortality + -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 + fates_pft + - + coefficient in moisture-based seedling mortality + 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 + fates_pft + - + light-based seedling mortality coefficient + -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 + fates_pft + - + light-based seedling mortality coefficient + -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 + fates_pft + yr-1 + background seedling mortality rate + 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_light_rec_a + fates_pft + - + coefficient in light-based seedling to sapling transition + 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 + fates_pft + - + coefficient in light-based seedling to sapling transition + 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_regeneration_model + scalar + - + switch for choosing between FATES's: 1) default regeneration scheme , 2) the Tree Recruitment Scheme (Hanbury-Brown et al., 2022), or (3) the Tree Recruitment Scheme without seedling dynamics + 1 + + + fates_trs_seedling_emerg_h2o_timescale + scalar + days + Length of the window for the exponential moving average of smp used to calculate seedling emergence + 7 + + + fates_trs_seedling_mort_par_timescale + scalar + days + Length of the window for the exponential moving average of par at the seedling layer used to calculate seedling mortality + 32 + + + fates_trs_seedling_mdd_timescale + scalar + days + Length of the window for the exponential moving average of moisture deficit days used to calculate seedling mortality + 126 + + + fates_trs_seedling2sap_par_timescale + scalar + days + Length of the window for the exponential moving average of par at the seedling layer used to calculate seedling to sapling transition rates + 32 + + + fates_seed_dispersal_max_dist + fates_pft + m + maximum seed dispersal distance for a given pft + + + + fates_seed_dispersal_fraction + fates_pft + fraction + fraction of seed rain to be dispersed to other grid cells + + + + fates_seed_dispersal_pdf_scale + fates_pft + unitless + seed dispersal probability density function scale parameter, A, Table 1 Bullock et al 2016 + + + + fates_seed_dispersal_pdf_shape + fates_pft + unitless + seed dispersal probability density function shape parameter, B, Table 1 Bullock et al 2016 + + + + fates_maintresp_reduction_upthresh + fates_pft + unitless (0-1) + upper threshold for storage biomass (relative to leaf biomass) above which MR is not reduced + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 + + + fates_mort_upthresh_cstarvation + fates_pft + unitless + threshold for storage biomass (relative to target leaf biomass) above which carbon starvation is zero + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 + + + diff --git a/parameter_files/archive/apichange_23to24.xml b/parameter_files/archive/apichange_23to24.xml new file mode 100644 index 0000000000..0bddd6940d --- /dev/null +++ b/parameter_files/archive/apichange_23to24.xml @@ -0,0 +1,568 @@ + + + + + + + + + + fates_params_default.cdl + fates_params_default_api24.cdl + 1,2,3,4,5,6,7,8,9,10,11,12 + + + fates_history_damage_bins + 2 + + + fates_allom_crown_depth_frac + the depth of a cohort crown as a fraction of its height + + + fates_phen_fnrt_drop_frac + fates_pft + fraction + fraction of fine roots to drop during drought or cold + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + + + fates_hydro_solver + scalar + unitless + switch designating which numerical solver for plant hydraulics, 1 = 1D taylor, 2 = 2D Picard, 3 = 2D Newton (deprecated) + 1 + + + fates_history_damage_bin_edges + fates_history_damage_bins + % crown loss + Lower edges for damage class bins used in cohort history output + 0, 80 + + + fates_damage_frac + fates_pft + fraction + fraction of cohort damaged in each damage event (event frequency specified in the is_it_damage_time subroutine) + 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01 + + + fates_damage_mort_p1 + fates_pft + fraction + inflection point of damage mortality function, a value of 0.8 means 50% mortality with 80% loss of crown, turn off with a large number + 9.0, 9.0, 9.0, 9.0, 9.0, 9.0, 9.0, 9.0, 9.0, 9.0, 9.0, 9.0 + + + fates_damage_mort_p2 + fates_pft + unitless + rate of mortality increase with damage + 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5 + + + fates_damage_recovery_scalar + fates_pft + unitless + fraction of the cohort that recovers from damage + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 + + + fates_maxpatch_primary + scalar + count + maximum number of primary vegetation patches per site + 10 + + + fates_maxpatch_secondary + scalar + count + maximum number of secondary vegetation patches per site + 4 + + + + fates_maxcohort + scalar + count + maximum number of cohorts per patch. Actual number of cohorts also depend on cohort fusion tolerances + 100 + + + + fates_phen_drought_model + scalar + unitless + which method to use for drought phenology: 0 - FATES default; 1 - Semi-deciduous (ED2-like) + 0 + + + fates_phen_drought_threshold + scalar + m3/m3 or mm + threshold for drought phenology (or lower threshold when fates_phen_drought_model = 1); the quantity depends on the sign: if positive, the threshold is volumetric soil moisture (m3/m3). If negative, the threshold is soil matric potentical (mm) + 0.15 + + + fates_phen_moist_threshold + scalar + m3/m3 or mm + upper threshold for drought phenology (only for fates_phen_drought_model=1); the quantity depends on the sign: if positive, the threshold is volumetric soil moisture (m3/m3). If negative, the threshold is soil matric potentical (mm) + 0.18 + + + fates_landuse_pprodharv10_forest_mean + scalar + fraction + mean harvest mortality proportion of deadstem to 10-yr product (pprodharv10) of all woody PFT types + 0.8125 + + + fates_leaf_stomatal_assim_model + scalar + unitless + a switch designating whether to use net (1) or gross (2) assimilation in the stomatal model + 1 + + + width in VAI units of uppermost leaf+stem layer scattering element in each canopy layer + + + factor by which each leaf+stem scattering element increases in VAI width (1 = uniform spacing) + + + factor by which each leaf+stem scattering element increases in VAI width (1 = uniform spacing) + + + fates_prt_organs + + + fates_plant_organs + 4 + + + fates_alloc_organ_priority + fates_plant_organs, fates_pft + index + Priority level for allocation, 1: replaces turnover from storage, 2: same priority as storage use/replacement, 3: ascending in order of least importance + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 + + + fates_alloc_organ_name + fates_plant_organs, fates_string_length + unitless - string + Name of plant organs (with alloc_organ_id, must match PRTGenericMod.F90) + leaf, fine root, sapwood,structure + + + fates_stoich_nitr + fates_plant_organs, fates_pft + gN/gC + target nitrogen concentration (ratio with carbon) of organs + 0.033, 0.029, 0.04, 0.033, 0.04, 0.04, 0.033, 0.04, 0.04, 0.04, 0.04, 0.04, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047 + + + fates_alloc_organ_id + fates_plant_organs + unitless + This is the global index that the organ in this file is associated with, values match those in parteh/PRTGenericMod.F90 + 1, 2, 3, 6 + + + fates_stoich_phos + fates_plant_organs, fates_pft + gP/gC + target phosphorus concentration (ratio with carbon) of organs + 0.0033, 0.0029, 0.004, 0.0033, 0.004, 0.004, 0.0033, 0.004, 0.004, 0.004, 0.004, 0.004, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, 0.00047 + + + fates_cnp_turnover_nitr_retrans + fates_plant_organs, fates_pft + fraction + retranslocation (reabsorbtion) fraction of nitrogen in turnover of scenescing tissues + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + + + fates_cnp_turnover_phos_retrans + fates_plant_organs, fates_pft + fraction + retranslocation (reabsorbtion) fraction of phosphorus in turnover of scenescing tissues + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + + + fates_hydro_organ_name + + + fates_init_litter + + + fates_mort_prescribed_canopy + + + fates_mort_prescribed_understory + + + fates_phen_flush_fraction + + + fates_phen_mindaysoff + + + fates_turb_leaf_diameter + + + fates_turb_displar + + + fates_turb_z0mr + + + fates_landuse_logging_coll_under_frac + + + fates_landuse_logging_collateral_frac + + + fates_landuse_logging_dbhmax + + + fates_landuse_logging_dbhmax_infra + + + fates_landuse_logging_dbhmin + + + fates_landuse_logging_direct_frac + + + fates_landuse_logging_event_code + + + fates_landuse_logging_export_frac + + + fates_landuse_logging_mechanical_frac + + + fates_leaf_photo_temp_acclim_timescale + + + fates_leaf_theta_cj_c3 + + + fates_leaf_theta_cj_c4 + + + fates_leaf_photo_tempsens_model + + + fates_nonhydro_smpsc + + + fates_nonhydro_smpso + + + fates_hydro_htftype_node + + + fates_hydro_kmax_rsurf1 + + + fates_hydro_kmax_rsurf2 + + + fates_hydro_psi0 + + + fates_hydro_psicap + + + fates_hydro_avuln_gs + + + fates_hydro_avuln_node + + + fates_hydro_epsil_node + + + fates_hydro_fcap_node + + + fates_hydro_k_lwp + + + fates_hydro_kmax_node + + + fates_hydro_p50_gs + + + fates_hydro_p50_node + + + fates_hydro_p_taper + + + fates_hydro_pinot_node + + + fates_hydro_pitlp_node + + + fates_hydro_resid_node + + + fates_hydro_rfrac_stem + + + fates_hydro_rs2 + + + fates_hydro_srl + + + fates_hydro_thetas_node + + + fates_hydro_vg_alpha_node + + + fates_hydro_vg_m_node + + + fates_hydro_vg_n_node + + + fates_cnp_eca_alpha_ptase + + + fates_cnp_eca_decompmicc + + + fates_cnp_eca_km_nh4 + + + fates_cnp_eca_km_no3 + + + fates_cnp_eca_km_p + + + fates_cnp_eca_km_ptase + + + fates_cnp_eca_lambda_ptase + + + fates_cnp_eca_vmax_ptase + + + fates_cnp_fnrt_adapt_tscale + fates_pft + days + Number of days that is shortest possible doubling period for fine-root adaptation to C/N/P balance + 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100 + + + fates_cnp_nfix1 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + + + fates_nfix2 + + + fates_cnp_nitr_store_ratio + storeable (labile) N, as a ratio compared to the N bound in cell structures of other organs (see code) + + + fates_cnp_phos_store_ratio + storeable (labile) P, as a ratio compared to the P bound in cell structures of other organs (see code) + + + fates_cnp_prescribed_nuptake + + + fates_cnp_prescribed_puptake + + + fates_cnp_eca_vmax_nh4 + 5.e-9, 5.e-9, 5.e-9, 5.e-9, 5.e-9, 5.e-9, 5.e-9, 5.e-9, 5.e-9, 5.e-9, 5.e-9, 5.e-9 + + + fates_cnp_eca_vmax_no3 + 5.e-9, 5.e-9, 5.e-9, 5.e-9, 5.e-9, 5.e-9, 5.e-9, 5.e-9, 5.e-9, 5.e-9, 5.e-9, 5.e-9 + + + fates_cnp_rd_vmax_n + fates_pft + gN/gC/s + maximum production rate for compbined (NH4+NO3) uptake (RD) + 5.e-9, 5.e-9, 5.e-9, 5.e-9, 5.e-9, 5.e-9, 5.e-9, 5.e-9, 5.e-9, 5.e-9, 5.e-9, 5.e-9 + + + fates_cnp_vmax_p + maximum production rate for phosphorus (ECA and RD) + 5.e-10, 5.e-10, 5.e-10, 5.e-10, 5.e-10, 5.e-10, 5.e-10, 5.e-10, 5.e-10, 5.e-10, 5.e-10, 5.e-10 + + + fates_turnover_retrans_mode + + + fates_cnp_eca_plant_escalar + + + fates_alloc_store_priority_frac + for high-priority organs, the fraction of their turnover demand that is gauranteed to be replaced, and if need-be by storage + + + fates_turnover_leaf + + + fates_turnover_fnrt + + + fates_turnover_senleaf_fdrought + + + fates_turnover_branch + + + fates_allom_fnrt_prof_a + + + fates_allom_fnrt_prof_b + + + fates_allom_fnrt_prof_mode + + + fates_frag_maxdecomp + + + fates_frag_cwd_frac + + + fates_frag_fnrt_fcel + + + fates_frag_fnrt_flab + + + fates_frag_fnrt_flig + + + fates_frag_leaf_fcel + + + fates_frag_leaf_flab + + + fates_frag_leaf_flig + + + fates_frag_seed_decay_rate + + + fates_frag_cwd_fcel + + + fates_frag_cwd_flig + + + fates_recruit_seed_alloc + + + fates_recruit_seed_alloc_mature + + + fates_recruit_seed_dbh_repro_threshold + + + fates_recruit_seed_germination_rate + + + fates_recruit_seed_supplement + + + fates_recruit_prescribed_rate + + + fates_recruit_height_min + + + fates_recruit_init_density + + + fates_rad_leaf_clumping_index + + + fates_rad_leaf_xl + + + fates_rad_leaf_rhonir + + + fates_rad_leaf_rhovis + + + fates_rad_stem_rhonir + + + fates_rad_stem_rhovis + + + fates_rad_leaf_taunir + + + fates_rad_leaf_tauvis + + + fates_rad_stem_taunir + + + fates_rad_stem_tauvis + + + fates_damage_event_code + scalar + unitless + Integer code that options how damage events are structured + 1 + + + fates_damage_canopy_layer_code + scalar + unitless + Integer code that decides whether damage affects canopy trees (1), understory trees (2) + 1 + + + fates_phen_gddthresh_a + + + fates_phen_gddthresh_b + + + fates_phen_gddthresh_c + + + fates_phen_chilltemp + + + fates_cnp_store_ovrflw_frac + fates_pft + fraction + size of overflow storage (for excess C,N or P) as a fraction of storage target + 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 + + + diff --git a/parameter_files/archive/apichange_24.2to25.xml b/parameter_files/archive/apichange_24.2to25.xml new file mode 100644 index 0000000000..41d3ea711b --- /dev/null +++ b/parameter_files/archive/apichange_24.2to25.xml @@ -0,0 +1,72 @@ + + + + + + + + + + archive/api24.2.0_112822_fates_params_default.cdl + fates_params_default_api25_v2.cdl + 1,2,3,4,5,6,7,8,9,10,11,12 + + + fates_cnp_fnrt_adapt_tscale + + + fates_cnp_eca_vmax_nh4 + + + fates_cnp_rd_vmax_n + + + fates_cnp_eca_vmax_no3 + + + fates_cnp_vmax_nh4 + fates_pft + gN/gC/s + maximum (potential) uptake rate of NH4 per gC of fineroot biomass (see main/EDPftvarcon.F90 vmax_nh4 for usage) + 2.5e-9, 2.5e-9, 2.5e-9, 2.5e-9, 2.5e-9, 2.5e-9, 2.5e-9, 2.5e-9, 2.5e-9, 2.5e-9, 2.5e-9, 2.5e-9 + + + fates_cnp_vmax_no3 + fates_pft + gN/gC/s + maximum (potential) uptake rate of NO3 per gC of fineroot biomass (see main/EDPftvarcon.F90 vmax_no3 for usage) + 2.5e-9, 2.5e-9, 2.5e-9, 2.5e-9, 2.5e-9, 2.5e-9, 2.5e-9, 2.5e-9, 2.5e-9, 2.5e-9, 2.5e-9, 2.5e-9 + + + fates_cnp_pid_kd + fates_pft + unknown + derivative constant of the PID controller on adaptive fine-root biomass + 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1 + + + fates_cnp_pid_ki + fates_pft + unknown + integral constant of the PID controller on adaptive fine-root biomass + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 + + + fates_cnp_pid_kp + fates_pft + unknown + proportional constant of the PID controller on adaptive fine-root biomass + 5e-4, 5e-4, 5e-4, 5e-4, 5e-4, 5e-4, 5e-4, 5e-4, 5e-4, 5e-4, 5e-4, 5e-4 + + + fractional surcharge added to maintenance respiration that drives symbiotic fixation + fraction + + + diff --git a/parameter_files/fates_params_default.cdl b/parameter_files/fates_params_default.cdl index caeaeb2464..f170fe2275 100644 --- a/parameter_files/fates_params_default.cdl +++ b/parameter_files/fates_params_default.cdl @@ -1,17 +1,18 @@ -netcdf fates_params_default.c210629_sorted { +netcdf fates_params_default { dimensions: fates_NCWD = 4 ; fates_history_age_bins = 7 ; + fates_history_coage_bins = 2 ; + fates_history_damage_bins = 2 ; fates_history_height_bins = 6 ; fates_history_size_bins = 13 ; - fates_history_coage_bins = 2 ; + fates_hlm_pftno = 14 ; fates_hydr_organs = 4 ; fates_leafage_class = 1 ; fates_litterclass = 6 ; fates_pft = 12 ; - fates_prt_organs = 4 ; + fates_plant_organs = 4 ; fates_string_length = 60 ; - fates_hlm_pftno = 14 ; variables: double fates_history_ageclass_bin_edges(fates_history_age_bins) ; fates_history_ageclass_bin_edges:units = "yr" ; @@ -22,31 +23,39 @@ variables: double fates_history_height_bin_edges(fates_history_height_bins) ; fates_history_height_bin_edges:units = "m" ; fates_history_height_bin_edges:long_name = "Lower edges for height bins used in height-resolved history output" ; + double fates_history_damage_bin_edges(fates_history_damage_bins) ; + fates_history_damage_bin_edges:units = "% crown loss" ; + fates_history_damage_bin_edges:long_name = "Lower edges for damage class bins used in cohort history output" ; double fates_history_sizeclass_bin_edges(fates_history_size_bins) ; fates_history_sizeclass_bin_edges:units = "cm" ; fates_history_sizeclass_bin_edges:long_name = "Lower edges for DBH size class bins used in size-resolved cohort history output" ; - double fates_hydr_htftype_node(fates_hydr_organs) ; - fates_hydr_htftype_node:units = "unitless" ; - fates_hydr_htftype_node:long_name = "Switch that defines the hydraulic transfer functions for each organ." ; - fates_hydr_htftype_node:possible_values = "1: Christofferson et al. 2016 (TFS); 2: Van Genuchten 1980" ; - double fates_prt_organ_id(fates_prt_organs) ; - fates_prt_organ_id:units = "index, unitless" ; - fates_prt_organ_id:long_name = "This is the global index the organ in this file is associated with in PRTGenericMod.F90" ; + double fates_alloc_organ_id(fates_plant_organs) ; + fates_alloc_organ_id:units = "unitless" ; + fates_alloc_organ_id:long_name = "This is the global index that the organ in this file is associated with, values match those in parteh/PRTGenericMod.F90" ; + double fates_hydro_htftype_node(fates_hydr_organs) ; + fates_hydro_htftype_node:units = "unitless" ; + fates_hydro_htftype_node:long_name = "Switch that defines the hydraulic transfer functions for each organ." ; char fates_pftname(fates_pft, fates_string_length) ; fates_pftname:units = "unitless - string" ; fates_pftname:long_name = "Description of plant type" ; - char fates_hydr_organname_node(fates_hydr_organs, fates_string_length) ; - fates_hydr_organname_node:units = "unitless - string" ; - fates_hydr_organname_node:long_name = "Name of plant hydraulics organs (DONT CHANGE, order matches media list in FatesHydraulicsMemMod.F90)" ; + char fates_hydro_organ_name(fates_hydr_organs, fates_string_length) ; + fates_hydro_organ_name:units = "unitless - string" ; + fates_hydro_organ_name:long_name = "Name of plant hydraulics organs (DONT CHANGE, order matches media list in FatesHydraulicsMemMod.F90)" ; + char fates_alloc_organ_name(fates_plant_organs, fates_string_length) ; + fates_alloc_organ_name:units = "unitless - string" ; + fates_alloc_organ_name:long_name = "Name of plant organs (with alloc_organ_id, must match PRTGenericMod.F90)" ; char fates_litterclass_name(fates_litterclass, fates_string_length) ; fates_litterclass_name:units = "unitless - string" ; fates_litterclass_name:long_name = "Name of the litter classes, for variables associated with dimension fates_litterclass" ; - char fates_prt_organ_name(fates_prt_organs, fates_string_length) ; - fates_prt_organ_name:units = "unitless - string" ; - fates_prt_organ_name:long_name = "Name of plant organs (order must match PRTGenericMod.F90)" ; + double fates_alloc_organ_priority(fates_plant_organs, fates_pft) ; + fates_alloc_organ_priority:units = "index" ; + fates_alloc_organ_priority:long_name = "Priority level for allocation, 1: replaces turnover from storage, 2: same priority as storage use/replacement, 3: ascending in order of least importance" ; double fates_alloc_storage_cushion(fates_pft) ; fates_alloc_storage_cushion:units = "fraction" ; fates_alloc_storage_cushion:long_name = "maximum size of storage C pool, relative to maximum size of leaf C pool" ; + double fates_alloc_store_priority_frac(fates_pft) ; + fates_alloc_store_priority_frac:units = "unitless" ; + fates_alloc_store_priority_frac:long_name = "for high-priority organs, the fraction of their turnover demand that is gauranteed to be replaced, and if need-be by storage" ; double fates_allom_agb1(fates_pft) ; fates_allom_agb1:units = "variable" ; fates_allom_agb1:long_name = "Parameter 1 for agb allometry" ; @@ -65,14 +74,15 @@ variables: double fates_allom_amode(fates_pft) ; fates_allom_amode:units = "index" ; fates_allom_amode:long_name = "AGB allometry function index." ; - fates_allom_amode:possible_values = "1: Saldarriaga 1998; 2: 2 parameter power law; 3: Chave 2014" ; double fates_allom_blca_expnt_diff(fates_pft) ; fates_allom_blca_expnt_diff:units = "unitless" ; fates_allom_blca_expnt_diff:long_name = "difference between allometric DBH:bleaf and DBH:crown area exponents" ; double fates_allom_cmode(fates_pft) ; fates_allom_cmode:units = "index" ; fates_allom_cmode:long_name = "coarse root biomass allometry function index." ; - fates_allom_cmode:possible_values = "1: Constant fraction on AGB" ; + double fates_allom_crown_depth_frac(fates_pft) ; + fates_allom_crown_depth_frac:units = "fraction" ; + fates_allom_crown_depth_frac:long_name = "the depth of a cohort crown as a fraction of its height" ; double fates_allom_d2bl1(fates_pft) ; fates_allom_d2bl1:units = "variable" ; fates_allom_d2bl1:long_name = "Parameter 1 for d2bl allometry" ; @@ -103,14 +113,21 @@ variables: double fates_allom_fmode(fates_pft) ; fates_allom_fmode:units = "index" ; fates_allom_fmode:long_name = "fine root biomass allometry function index." ; - fates_allom_fmode:possible_values = "1: constant fraction of trimmed bleaf; 2: constant fraction of untrimmed bleaf." ; + double fates_allom_fnrt_prof_a(fates_pft) ; + fates_allom_fnrt_prof_a:units = "unitless" ; + fates_allom_fnrt_prof_a:long_name = "Fine root profile function, parameter a" ; + double fates_allom_fnrt_prof_b(fates_pft) ; + fates_allom_fnrt_prof_b:units = "unitless" ; + fates_allom_fnrt_prof_b:long_name = "Fine root profile function, parameter b" ; + double fates_allom_fnrt_prof_mode(fates_pft) ; + fates_allom_fnrt_prof_mode:units = "index" ; + fates_allom_fnrt_prof_mode:long_name = "Index to select fine root profile function: 1) Jackson Beta, 2) 1-param exponential 3) 2-param exponential" ; double fates_allom_frbstor_repro(fates_pft) ; fates_allom_frbstor_repro:units = "fraction" ; fates_allom_frbstor_repro:long_name = "fraction of bstore goes to reproduction after plant dies" ; double fates_allom_hmode(fates_pft) ; fates_allom_hmode:units = "index" ; fates_allom_hmode:long_name = "height allometry function index." ; - fates_allom_hmode:possible_values = "1: OBrien 1995; 2: Poorter 2006; 3: 2 parameter power law; 4: Chave 2014; 5: Martinez-Cano 2019." ; double fates_allom_l2fr(fates_pft) ; fates_allom_l2fr:units = "gC/gC" ; fates_allom_l2fr:long_name = "Allocation parameter: fine root C per leaf C" ; @@ -123,18 +140,15 @@ variables: double fates_allom_lmode(fates_pft) ; fates_allom_lmode:units = "index" ; fates_allom_lmode:long_name = "leaf biomass allometry function index." ; - fates_allom_lmode:possible_values = "1: Saldarriaga 1998 (capped-dbh power law); 2: generic power law; 3: generic capped-dbh power law." ; double fates_allom_sai_scaler(fates_pft) ; fates_allom_sai_scaler:units = "m2/m2" ; fates_allom_sai_scaler:long_name = "allometric ratio of SAI per LAI" ; double fates_allom_smode(fates_pft) ; fates_allom_smode:units = "index" ; fates_allom_smode:long_name = "sapwood allometry function index." ; - fates_allom_smode:possible_values = "1: sapwood area proportional to leaf area based on target leaf biomass" ; double fates_allom_stmode(fates_pft) ; fates_allom_stmode:units = "index" ; - fates_allom_stmode:long_name = "storage allometry function index." ; - fates_allom_stmode:possible_values = "1: target storage proportional to trimmed maximum leaf biomass." ; + 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" ; @@ -150,166 +164,192 @@ variables: double fates_allom_zroot_min_z(fates_pft) ; fates_allom_zroot_min_z:units = "m" ; fates_allom_zroot_min_z:long_name = "the maximum rooting depth defined at dbh = fates_allom_zroot_min_dbh. note: max_z=min_z=large, sets rooting depth to soil depth" ; - double fates_branch_turnover(fates_pft) ; - fates_branch_turnover:units = "yr" ; - fates_branch_turnover:long_name = "turnover time of branches" ; double fates_c2b(fates_pft) ; fates_c2b:units = "ratio" ; fates_c2b:long_name = "Carbon to biomass multiplier of bulk structural tissues" ; + double fates_cnp_eca_alpha_ptase(fates_pft) ; + fates_cnp_eca_alpha_ptase:units = "g/m3" ; + fates_cnp_eca_alpha_ptase:long_name = "fraction of P from ptase activity sent directly to plant (ECA)" ; + double fates_cnp_eca_decompmicc(fates_pft) ; + fates_cnp_eca_decompmicc:units = "gC/m3" ; + fates_cnp_eca_decompmicc:long_name = "maximum soil microbial decomposer biomass found over depth (will be applied at a reference depth w/ exponential attenuation) (ECA)" ; + double fates_cnp_eca_km_nh4(fates_pft) ; + fates_cnp_eca_km_nh4:units = "gN/m3" ; + fates_cnp_eca_km_nh4:long_name = "half-saturation constant for plant nh4 uptake (ECA)" ; + double fates_cnp_eca_km_no3(fates_pft) ; + fates_cnp_eca_km_no3:units = "gN/m3" ; + fates_cnp_eca_km_no3:long_name = "half-saturation constant for plant no3 uptake (ECA)" ; + double fates_cnp_eca_km_p(fates_pft) ; + fates_cnp_eca_km_p:units = "gP/m3" ; + fates_cnp_eca_km_p:long_name = "half-saturation constant for plant p uptake (ECA)" ; + double fates_cnp_eca_km_ptase(fates_pft) ; + fates_cnp_eca_km_ptase:units = "gP/m3" ; + fates_cnp_eca_km_ptase:long_name = "half-saturation constant for biochemical P (ECA)" ; + double fates_cnp_eca_lambda_ptase(fates_pft) ; + fates_cnp_eca_lambda_ptase:units = "g/m3" ; + fates_cnp_eca_lambda_ptase:long_name = "critical value for biochemical production (ECA)" ; + double fates_cnp_eca_vmax_ptase(fates_pft) ; + fates_cnp_eca_vmax_ptase:units = "gP/m2/s" ; + fates_cnp_eca_vmax_ptase:long_name = "maximum production rate for biochemical P (per m2) (ECA)" ; + double fates_cnp_nfix1(fates_pft) ; + fates_cnp_nfix1:units = "fraction" ; + fates_cnp_nfix1:long_name = "fractional surcharge added to maintenance respiration that drives symbiotic fixation" ; + double fates_cnp_nitr_store_ratio(fates_pft) ; + fates_cnp_nitr_store_ratio:units = "(gN/gN)" ; + fates_cnp_nitr_store_ratio:long_name = "storeable (labile) N, as a ratio compared to the N bound in cell structures of other organs (see code)" ; + double fates_cnp_phos_store_ratio(fates_pft) ; + fates_cnp_phos_store_ratio:units = "(gP/gP)" ; + fates_cnp_phos_store_ratio:long_name = "storeable (labile) P, as a ratio compared to the P bound in cell structures of other organs (see code)" ; + double fates_cnp_pid_kd(fates_pft) ; + fates_cnp_pid_kd:units = "unknown" ; + fates_cnp_pid_kd:long_name = "derivative constant of the PID controller on adaptive fine-root biomass" ; + double fates_cnp_pid_ki(fates_pft) ; + fates_cnp_pid_ki:units = "unknown" ; + fates_cnp_pid_ki:long_name = "integral constant of the PID controller on adaptive fine-root biomass" ; + double fates_cnp_pid_kp(fates_pft) ; + fates_cnp_pid_kp:units = "unknown" ; + fates_cnp_pid_kp:long_name = "proportional constant of the PID controller on adaptive fine-root biomass" ; + double fates_cnp_prescribed_nuptake(fates_pft) ; + fates_cnp_prescribed_nuptake:units = "fraction" ; + fates_cnp_prescribed_nuptake:long_name = "Prescribed N uptake flux. 0=fully coupled simulation >0=prescribed (experimental)" ; + double fates_cnp_prescribed_puptake(fates_pft) ; + fates_cnp_prescribed_puptake:units = "fraction" ; + fates_cnp_prescribed_puptake:long_name = "Prescribed P uptake flux. 0=fully coupled simulation, >0=prescribed (experimental)" ; + double fates_cnp_store_ovrflw_frac(fates_pft) ; + fates_cnp_store_ovrflw_frac:units = "fraction" ; + fates_cnp_store_ovrflw_frac:long_name = "size of overflow storage (for excess C,N or P) as a fraction of storage target" ; + double fates_cnp_turnover_nitr_retrans(fates_plant_organs, fates_pft) ; + fates_cnp_turnover_nitr_retrans:units = "fraction" ; + fates_cnp_turnover_nitr_retrans:long_name = "retranslocation (reabsorbtion) fraction of nitrogen in turnover of scenescing tissues" ; + double fates_cnp_turnover_phos_retrans(fates_plant_organs, fates_pft) ; + fates_cnp_turnover_phos_retrans:units = "fraction" ; + fates_cnp_turnover_phos_retrans:long_name = "retranslocation (reabsorbtion) fraction of phosphorus in turnover of scenescing tissues" ; + double fates_cnp_vmax_nh4(fates_pft) ; + fates_cnp_vmax_nh4:units = "gN/gC/s" ; + fates_cnp_vmax_nh4:long_name = "maximum (potential) uptake rate of NH4 per gC of fineroot biomass (see main/EDPftvarcon.F90 vmax_nh4 for usage)" ; + double fates_cnp_vmax_no3(fates_pft) ; + fates_cnp_vmax_no3:units = "gN/gC/s" ; + fates_cnp_vmax_no3:long_name = "maximum (potential) uptake rate of NO3 per gC of fineroot biomass (see main/EDPftvarcon.F90 vmax_no3 for usage)" ; + double fates_cnp_vmax_p(fates_pft) ; + fates_cnp_vmax_p:units = "gP/gC/s" ; + fates_cnp_vmax_p:long_name = "maximum production rate for phosphorus (ECA and RD)" ; + double fates_damage_frac(fates_pft) ; + fates_damage_frac:units = "fraction" ; + fates_damage_frac:long_name = "fraction of cohort damaged in each damage event (event frequency specified in the is_it_damage_time subroutine)" ; + double fates_damage_mort_p1(fates_pft) ; + fates_damage_mort_p1:units = "fraction" ; + fates_damage_mort_p1:long_name = "inflection point of damage mortality function, a value of 0.8 means 50% mortality with 80% loss of crown, turn off with a large number" ; + double fates_damage_mort_p2(fates_pft) ; + fates_damage_mort_p2:units = "unitless" ; + fates_damage_mort_p2:long_name = "rate of mortality increase with damage" ; + double fates_damage_recovery_scalar(fates_pft) ; + fates_damage_recovery_scalar:units = "unitless" ; + fates_damage_recovery_scalar:long_name = "fraction of the cohort that recovers from damage" ; double fates_dev_arbitrary_pft(fates_pft) ; fates_dev_arbitrary_pft:units = "unknown" ; fates_dev_arbitrary_pft:long_name = "Unassociated pft dimensioned free parameter that developers can use for testing arbitrary new hypotheses" ; - double fates_displar(fates_pft) ; - fates_displar:units = "unitless" ; - fates_displar:long_name = "Ratio of displacement height to canopy top height" ; - double fates_eca_alpha_ptase(fates_pft) ; - fates_eca_alpha_ptase:units = "g/m3" ; - fates_eca_alpha_ptase:long_name = "fraction of P from ptase activity sent directly to plant (ECA)" ; - double fates_eca_decompmicc(fates_pft) ; - fates_eca_decompmicc:units = "gC/m3" ; - fates_eca_decompmicc:long_name = "mean soil microbial decomposer biomass (ECA)" ; - double fates_eca_km_nh4(fates_pft) ; - fates_eca_km_nh4:units = "gN/m3" ; - fates_eca_km_nh4:long_name = "half-saturation constant for plant nh4 uptake (ECA)" ; - double fates_eca_km_no3(fates_pft) ; - fates_eca_km_no3:units = "gN/m3" ; - fates_eca_km_no3:long_name = "half-saturation constant for plant no3 uptake (ECA)" ; - double fates_eca_km_p(fates_pft) ; - fates_eca_km_p:units = "gP/m3" ; - fates_eca_km_p:long_name = "half-saturation constant for plant p uptake (ECA)" ; - double fates_eca_km_ptase(fates_pft) ; - fates_eca_km_ptase:units = "gP/m3" ; - fates_eca_km_ptase:long_name = "half-saturation constant for biochemical P (ECA)" ; - double fates_eca_lambda_ptase(fates_pft) ; - fates_eca_lambda_ptase:units = "g/m3" ; - fates_eca_lambda_ptase:long_name = "critical value for biochemical production (ECA)" ; - double fates_eca_vmax_nh4(fates_pft) ; - fates_eca_vmax_nh4:units = "gN/gC/s" ; - fates_eca_vmax_nh4:long_name = "maximum production rate for plant nh4 uptake (ECA)" ; - double fates_eca_vmax_no3(fates_pft) ; - fates_eca_vmax_no3:units = "gN/gC/s" ; - fates_eca_vmax_no3:long_name = "maximum production rate for plant no3 uptake (ECA)" ; - double fates_eca_vmax_p(fates_pft) ; - fates_eca_vmax_p:units = "gP/gC/s" ; - fates_eca_vmax_p:long_name = "maximum production rate for plant p uptake (ECA)" ; - double fates_eca_vmax_ptase(fates_pft) ; - fates_eca_vmax_ptase:units = "gP/m2/s" ; - fates_eca_vmax_ptase:long_name = "maximum production rate for biochemical P (per m2) (ECA)" ; double fates_fire_alpha_SH(fates_pft) ; fates_fire_alpha_SH:units = "m / (kw/m)**(2/3)" ; fates_fire_alpha_SH:long_name = "spitfire parameter, alpha scorch height, Equation 16 Thonicke et al 2010" ; double fates_fire_bark_scaler(fates_pft) ; fates_fire_bark_scaler:units = "fraction" ; fates_fire_bark_scaler:long_name = "the thickness of a cohorts bark as a fraction of its dbh" ; - double fates_fire_crown_depth_frac(fates_pft) ; - fates_fire_crown_depth_frac:units = "fraction" ; - fates_fire_crown_depth_frac:long_name = "the depth of a cohorts crown as a fraction of its height" ; double fates_fire_crown_kill(fates_pft) ; fates_fire_crown_kill:units = "NA" ; - fates_fire_crown_kill:long_name = "crown resistance to fire (1 = none), EQ 22 in Thonicke et al 2010" ; - double fates_fire_active_crown_fire(fates_pft) ; - fates_fire_active_crown_fire:units = "fraction" ; - fates_fire_active_crown_fire:long_name = "resistance to active crown fire (1=none)"; - double fates_fnrt_prof_a(fates_pft) ; - fates_fnrt_prof_a:units = "unitless" ; - fates_fnrt_prof_a:long_name = "Fine root profile function, parameter a" ; - double fates_fnrt_prof_b(fates_pft) ; - fates_fnrt_prof_b:units = "unitless" ; - fates_fnrt_prof_b:long_name = "Fine root profile function, parameter b" ; - double fates_fnrt_prof_mode(fates_pft) ; - fates_fnrt_prof_mode:units = "index" ; - fates_fnrt_prof_mode:long_name = "Index to select fine root profile function: 1) Jackson Beta, 2) 1-param exponential 3) 2-param exponential" ; - double fates_fr_fcel(fates_pft) ; - fates_fr_fcel:units = "fraction" ; - fates_fr_fcel:long_name = "Fine root litter cellulose fraction" ; - double fates_fr_flab(fates_pft) ; - fates_fr_flab:units = "fraction" ; - fates_fr_flab:long_name = "Fine root litter labile fraction" ; - double fates_fr_flig(fates_pft) ; - fates_fr_flig:units = "fraction" ; - fates_fr_flig:long_name = "Fine root litter lignin fraction" ; + fates_fire_crown_kill:long_name = "fire parameter, see equation 22 in Thonicke et al 2010" ; + double fates_frag_fnrt_fcel(fates_pft) ; + fates_frag_fnrt_fcel:units = "fraction" ; + fates_frag_fnrt_fcel:long_name = "Fine root litter cellulose fraction" ; + double fates_frag_fnrt_flab(fates_pft) ; + fates_frag_fnrt_flab:units = "fraction" ; + fates_frag_fnrt_flab:long_name = "Fine root litter labile fraction" ; + double fates_frag_fnrt_flig(fates_pft) ; + fates_frag_fnrt_flig:units = "fraction" ; + fates_frag_fnrt_flig:long_name = "Fine root litter lignin fraction" ; + double fates_frag_leaf_fcel(fates_pft) ; + fates_frag_leaf_fcel:units = "fraction" ; + fates_frag_leaf_fcel:long_name = "Leaf litter cellulose fraction" ; + double fates_frag_leaf_flab(fates_pft) ; + fates_frag_leaf_flab:units = "fraction" ; + fates_frag_leaf_flab:long_name = "Leaf litter labile fraction" ; + double fates_frag_leaf_flig(fates_pft) ; + fates_frag_leaf_flig:units = "fraction" ; + fates_frag_leaf_flig:long_name = "Leaf litter lignin fraction" ; + double fates_frag_seed_decay_rate(fates_pft) ; + fates_frag_seed_decay_rate:units = "yr-1" ; + fates_frag_seed_decay_rate:long_name = "fraction of seeds that decay per year" ; double fates_grperc(fates_pft) ; fates_grperc:units = "unitless" ; fates_grperc:long_name = "Growth respiration factor" ; - double fates_hydr_avuln_gs(fates_pft) ; - fates_hydr_avuln_gs:units = "unitless" ; - fates_hydr_avuln_gs:long_name = "shape parameter for stomatal control of water vapor exiting leaf" ; - double fates_hydr_avuln_node(fates_hydr_organs, fates_pft) ; - fates_hydr_avuln_node:units = "unitless" ; - fates_hydr_avuln_node:long_name = "xylem vulnerability curve shape parameter" ; - double fates_hydr_epsil_node(fates_hydr_organs, fates_pft) ; - fates_hydr_epsil_node:units = "MPa" ; - fates_hydr_epsil_node:long_name = "bulk elastic modulus" ; - double fates_hydr_fcap_node(fates_hydr_organs, fates_pft) ; - fates_hydr_fcap_node:units = "unitless" ; - fates_hydr_fcap_node:long_name = "fraction of non-residual water that is capillary in source" ; - double fates_hydr_k_lwp(fates_pft) ; - fates_hydr_k_lwp:units = "unitless" ; - fates_hydr_k_lwp:long_name = "inner leaf humidity scaling coefficient" ; - fates_hydr_k_lwp:possible_values = "0: turns off leaf humidity effects on conductance. 1-10 activates humidity effects" ; - double fates_hydr_kmax_node(fates_hydr_organs, fates_pft) ; - fates_hydr_kmax_node:units = "kg/MPa/m/s" ; - fates_hydr_kmax_node:long_name = "maximum xylem conductivity per unit conducting xylem area" ; - double fates_hydr_p50_gs(fates_pft) ; - fates_hydr_p50_gs:units = "MPa" ; - fates_hydr_p50_gs:long_name = "water potential at 50% loss of stomatal conductance" ; - double fates_hydr_p50_node(fates_hydr_organs, fates_pft) ; - fates_hydr_p50_node:units = "MPa" ; - fates_hydr_p50_node:long_name = "xylem water potential at 50% loss of conductivity" ; - double fates_hydr_p_taper(fates_pft) ; - fates_hydr_p_taper:units = "unitless" ; - fates_hydr_p_taper:long_name = "xylem taper exponent" ; - double fates_hydr_pinot_node(fates_hydr_organs, fates_pft) ; - fates_hydr_pinot_node:units = "MPa" ; - fates_hydr_pinot_node:long_name = "osmotic potential at full turgor" ; - double fates_hydr_pitlp_node(fates_hydr_organs, fates_pft) ; - fates_hydr_pitlp_node:units = "MPa" ; - fates_hydr_pitlp_node:long_name = "turgor loss point" ; - double fates_hydr_resid_node(fates_hydr_organs, fates_pft) ; - fates_hydr_resid_node:units = "cm3/cm3" ; - fates_hydr_resid_node:long_name = "residual water conent" ; - double fates_hydr_rfrac_stem(fates_pft) ; - fates_hydr_rfrac_stem:units = "fraction" ; - fates_hydr_rfrac_stem:long_name = "fraction of total tree resistance from troot to canopy" ; - double fates_hydr_rs2(fates_pft) ; - fates_hydr_rs2:units = "m" ; - fates_hydr_rs2:long_name = "absorbing root radius" ; - double fates_hydr_srl(fates_pft) ; - fates_hydr_srl:units = "m g-1" ; - fates_hydr_srl:long_name = "specific root length" ; - double fates_hydr_thetas_node(fates_hydr_organs, fates_pft) ; - fates_hydr_thetas_node:units = "cm3/cm3" ; - fates_hydr_thetas_node:long_name = "saturated water content" ; - double fates_hydr_vg_alpha_node(fates_hydr_organs, fates_pft) ; - fates_hydr_vg_alpha_node:units = "MPa-1" ; - fates_hydr_vg_alpha_node:long_name = "(used if hydr_htftype_node = 2), capillary length parameter in van Genuchten model" ; - double fates_hydr_vg_m_node(fates_hydr_organs, fates_pft) ; - fates_hydr_vg_m_node:units = "unitless" ; - fates_hydr_vg_m_node:long_name = "(used if hydr_htftype_node = 2),m in van Genuchten 1980 model, 2nd pore size distribution parameter" ; - double fates_hydr_vg_n_node(fates_hydr_organs, fates_pft) ; - fates_hydr_vg_n_node:units = "unitless" ; - fates_hydr_vg_n_node:long_name = "(used if hydr_htftype_node = 2),n in van Genuchten 1980 model, pore size distribution parameter" ; + double fates_hydro_avuln_gs(fates_pft) ; + fates_hydro_avuln_gs:units = "unitless" ; + fates_hydro_avuln_gs:long_name = "shape parameter for stomatal control of water vapor exiting leaf" ; + double fates_hydro_avuln_node(fates_hydr_organs, fates_pft) ; + fates_hydro_avuln_node:units = "unitless" ; + fates_hydro_avuln_node:long_name = "xylem vulnerability curve shape parameter" ; + double fates_hydro_epsil_node(fates_hydr_organs, fates_pft) ; + fates_hydro_epsil_node:units = "MPa" ; + fates_hydro_epsil_node:long_name = "bulk elastic modulus" ; + double fates_hydro_fcap_node(fates_hydr_organs, fates_pft) ; + fates_hydro_fcap_node:units = "unitless" ; + fates_hydro_fcap_node:long_name = "fraction of non-residual water that is capillary in source" ; + double fates_hydro_k_lwp(fates_pft) ; + fates_hydro_k_lwp:units = "unitless" ; + fates_hydro_k_lwp:long_name = "inner leaf humidity scaling coefficient" ; + double fates_hydro_kmax_node(fates_hydr_organs, fates_pft) ; + fates_hydro_kmax_node:units = "kg/MPa/m/s" ; + fates_hydro_kmax_node:long_name = "maximum xylem conductivity per unit conducting xylem area" ; + double fates_hydro_p50_gs(fates_pft) ; + fates_hydro_p50_gs:units = "MPa" ; + fates_hydro_p50_gs:long_name = "water potential at 50% loss of stomatal conductance" ; + double fates_hydro_p50_node(fates_hydr_organs, fates_pft) ; + fates_hydro_p50_node:units = "MPa" ; + fates_hydro_p50_node:long_name = "xylem water potential at 50% loss of conductivity" ; + double fates_hydro_p_taper(fates_pft) ; + fates_hydro_p_taper:units = "unitless" ; + fates_hydro_p_taper:long_name = "xylem taper exponent" ; + double fates_hydro_pinot_node(fates_hydr_organs, fates_pft) ; + fates_hydro_pinot_node:units = "MPa" ; + fates_hydro_pinot_node:long_name = "osmotic potential at full turgor" ; + double fates_hydro_pitlp_node(fates_hydr_organs, fates_pft) ; + fates_hydro_pitlp_node:units = "MPa" ; + fates_hydro_pitlp_node:long_name = "turgor loss point" ; + double fates_hydro_resid_node(fates_hydr_organs, fates_pft) ; + fates_hydro_resid_node:units = "cm3/cm3" ; + fates_hydro_resid_node:long_name = "residual water conent" ; + double fates_hydro_rfrac_stem(fates_pft) ; + fates_hydro_rfrac_stem:units = "fraction" ; + fates_hydro_rfrac_stem:long_name = "fraction of total tree resistance from troot to canopy" ; + double fates_hydro_rs2(fates_pft) ; + fates_hydro_rs2:units = "m" ; + fates_hydro_rs2:long_name = "absorbing root radius" ; + double fates_hydro_srl(fates_pft) ; + fates_hydro_srl:units = "m g-1" ; + fates_hydro_srl:long_name = "specific root length" ; + double fates_hydro_thetas_node(fates_hydr_organs, fates_pft) ; + fates_hydro_thetas_node:units = "cm3/cm3" ; + fates_hydro_thetas_node:long_name = "saturated water content" ; + double fates_hydro_vg_alpha_node(fates_hydr_organs, fates_pft) ; + fates_hydro_vg_alpha_node:units = "MPa-1" ; + fates_hydro_vg_alpha_node:long_name = "(used if hydr_htftype_node = 2), capillary length parameter in van Genuchten model" ; + double fates_hydro_vg_m_node(fates_hydr_organs, fates_pft) ; + fates_hydro_vg_m_node:units = "unitless" ; + fates_hydro_vg_m_node:long_name = "(used if hydr_htftype_node = 2),m in van Genuchten 1980 model, 2nd pore size distribution parameter" ; + double fates_hydro_vg_n_node(fates_hydr_organs, fates_pft) ; + fates_hydro_vg_n_node:units = "unitless" ; + fates_hydro_vg_n_node:long_name = "(used if hydr_htftype_node = 2),n in van Genuchten 1980 model, pore size distribution parameter" ; double fates_leaf_c3psn(fates_pft) ; fates_leaf_c3psn:units = "flag" ; fates_leaf_c3psn:long_name = "Photosynthetic pathway (1=c3, 0=c4)" ; - double fates_leaf_clumping_index(fates_pft) ; - fates_leaf_clumping_index:units = "fraction (0-1)" ; - fates_leaf_clumping_index:long_name = "factor describing how much self-occlusion of leaf scattering elements decreases light interception" ; - double fates_leaf_diameter(fates_pft) ; - fates_leaf_diameter:units = "m" ; - fates_leaf_diameter:long_name = "Characteristic leaf dimension" ; double fates_leaf_jmaxha(fates_pft) ; fates_leaf_jmaxha:units = "J/mol" ; - fates_leaf_jmaxha:long_name = "activation energy for jmax" ; + fates_leaf_jmaxha:long_name = "activation energy for jmax. NOTE: if fates_leaf_photo_tempsens_model=2 then these values are NOT USED" ; double fates_leaf_jmaxhd(fates_pft) ; fates_leaf_jmaxhd:units = "J/mol" ; - fates_leaf_jmaxhd:long_name = "deactivation energy for jmax" ; + fates_leaf_jmaxhd:long_name = "deactivation energy for jmax. NOTE: if fates_leaf_photo_tempsens_model=2 then these values are NOT USED" ; double fates_leaf_jmaxse(fates_pft) ; fates_leaf_jmaxse:units = "J/mol/K" ; - fates_leaf_jmaxse:long_name = "entropy term for jmax" ; - double fates_leaf_long(fates_leafage_class, fates_pft) ; - fates_leaf_long:units = "yr" ; - fates_leaf_long:long_name = "Leaf longevity (ie turnover timescale)" ; + fates_leaf_jmaxse:long_name = "entropy term for jmax. NOTE: if fates_leaf_photo_tempsens_model=2 then these values are NOT USED" ; double fates_leaf_slamax(fates_pft) ; fates_leaf_slamax:units = "m^2/gC" ; fates_leaf_slamax:long_name = "Maximum Specific Leaf Area (SLA), even if under a dense canopy" ; @@ -325,39 +365,33 @@ variables: double fates_leaf_stomatal_slope_medlyn(fates_pft) ; fates_leaf_stomatal_slope_medlyn:units = "KPa**0.5" ; fates_leaf_stomatal_slope_medlyn:long_name = "stomatal slope parameter, as per Medlyn" ; - double fates_leaf_stor_priority(fates_pft) ; - fates_leaf_stor_priority:units = "unitless" ; - fates_leaf_stor_priority:long_name = "factor governing priority of replacing storage with NPP" ; double fates_leaf_vcmax25top(fates_leafage_class, fates_pft) ; fates_leaf_vcmax25top:units = "umol CO2/m^2/s" ; fates_leaf_vcmax25top:long_name = "maximum carboxylation rate of Rub. at 25C, canopy top" ; double fates_leaf_vcmaxha(fates_pft) ; fates_leaf_vcmaxha:units = "J/mol" ; - fates_leaf_vcmaxha:long_name = "activation energy for vcmax" ; + fates_leaf_vcmaxha:long_name = "activation energy for vcmax. NOTE: if fates_leaf_photo_tempsens_model=2 then these values are NOT USED" ; double fates_leaf_vcmaxhd(fates_pft) ; fates_leaf_vcmaxhd:units = "J/mol" ; - fates_leaf_vcmaxhd:long_name = "deactivation energy for vcmax" ; + fates_leaf_vcmaxhd:long_name = "deactivation energy for vcmax. NOTE: if fates_leaf_photo_tempsens_model=2 then these values are NOT USED" ; double fates_leaf_vcmaxse(fates_pft) ; fates_leaf_vcmaxse:units = "J/mol/K" ; - fates_leaf_vcmaxse:long_name = "entropy term for vcmax" ; - double fates_leaf_xl(fates_pft) ; - fates_leaf_xl:units = "unitless" ; - fates_leaf_xl:long_name = "Leaf/stem orientation index" ; - double fates_lf_fcel(fates_pft) ; - fates_lf_fcel:units = "fraction" ; - fates_lf_fcel:long_name = "Leaf litter cellulose fraction" ; - double fates_lf_flab(fates_pft) ; - fates_lf_flab:units = "fraction" ; - fates_lf_flab:long_name = "Leaf litter labile fraction" ; - double fates_lf_flig(fates_pft) ; - fates_lf_flig:units = "fraction" ; - fates_lf_flig:long_name = "Leaf litter lignin fraction" ; + fates_leaf_vcmaxse:long_name = "entropy term for vcmax. NOTE: if fates_leaf_photo_tempsens_model=2 then these values are NOT USED" ; + double fates_maintresp_leaf_atkin2017_baserate(fates_pft) ; + fates_maintresp_leaf_atkin2017_baserate:units = "umol CO2/m^2/s" ; + fates_maintresp_leaf_atkin2017_baserate:long_name = "Leaf maintenance respiration base rate parameter (r0) per Atkin et al 2017" ; + double fates_maintresp_leaf_ryan1991_baserate(fates_pft) ; + fates_maintresp_leaf_ryan1991_baserate:units = "gC/gN/s" ; + fates_maintresp_leaf_ryan1991_baserate:long_name = "Leaf maintenance respiration base rate per Ryan et al 1991" ; double fates_maintresp_reduction_curvature(fates_pft) ; fates_maintresp_reduction_curvature:units = "unitless (0-1)" ; fates_maintresp_reduction_curvature:long_name = "curvature of MR reduction as f(carbon storage), 1=linear, 0=very curved" ; double fates_maintresp_reduction_intercept(fates_pft) ; fates_maintresp_reduction_intercept:units = "unitless (0-1)" ; fates_maintresp_reduction_intercept:long_name = "intercept of MR reduction as f(carbon storage), 0=no throttling, 1=max throttling" ; + double fates_maintresp_reduction_upthresh(fates_pft) ; + fates_maintresp_reduction_upthresh:units = "unitless (0-1)" ; + fates_maintresp_reduction_upthresh:long_name = "upper threshold for storage biomass (relative to leaf biomass) above which MR is not reduced" ; double fates_mort_bmort(fates_pft) ; fates_mort_bmort:units = "1/yr" ; fates_mort_bmort:long_name = "background mortality rate" ; @@ -376,6 +410,12 @@ variables: double fates_mort_ip_size_senescence(fates_pft) ; fates_mort_ip_size_senescence:units = "dbh cm" ; fates_mort_ip_size_senescence:long_name = "Mortality dbh senescence inflection point. If _ this mortality term is off. Setting this value turns on size dependent mortality" ; + double fates_mort_prescribed_canopy(fates_pft) ; + fates_mort_prescribed_canopy:units = "1/yr" ; + fates_mort_prescribed_canopy:long_name = "mortality rate of canopy trees for prescribed physiology mode" ; + double fates_mort_prescribed_understory(fates_pft) ; + fates_mort_prescribed_understory:units = "1/yr" ; + fates_mort_prescribed_understory:long_name = "mortality rate of understory trees for prescribed physiology mode" ; double fates_mort_r_age_senescence(fates_pft) ; fates_mort_r_age_senescence:units = "mortality rate year^-1" ; fates_mort_r_age_senescence:long_name = "Mortality age senescence rate of change. Sensible range is around 0.03-0.06. Larger values givesteeper mortality curves." ; @@ -391,21 +431,36 @@ variables: double fates_mort_scalar_hydrfailure(fates_pft) ; fates_mort_scalar_hydrfailure:units = "1/yr" ; fates_mort_scalar_hydrfailure:long_name = "maximum mortality rate from hydraulic failure" ; - double fates_nfix1(fates_pft) ; - fates_nfix1:units = "NA" ; - fates_nfix1:long_name = "place-holder for future n-fixation parameter (NOT IMPLEMENTED)" ; - double fates_nfix2(fates_pft) ; - fates_nfix2:units = "NA" ; - fates_nfix2:long_name = "place-holder for future n-fixation parameter (NOT IMPLEMENTED)" ; - double fates_nitr_store_ratio(fates_pft) ; - fates_nitr_store_ratio:units = "(gN/gN)" ; - fates_nitr_store_ratio:long_name = "ratio of storeable N, to functional N bound in cell structures of leaf,root,sap" ; + double fates_mort_upthresh_cstarvation(fates_pft) ; + fates_mort_upthresh_cstarvation:units = "unitless" ; + fates_mort_upthresh_cstarvation:long_name = "threshold for storage biomass (relative to target leaf biomass) above which carbon starvation is zero" ; + double fates_nonhydro_smpsc(fates_pft) ; + fates_nonhydro_smpsc:units = "mm" ; + fates_nonhydro_smpsc:long_name = "Soil water potential at full stomatal closure" ; + double fates_nonhydro_smpso(fates_pft) ; + fates_nonhydro_smpso:units = "mm" ; + fates_nonhydro_smpso:long_name = "Soil water potential at full stomatal opening" ; double fates_phen_cold_size_threshold(fates_pft) ; fates_phen_cold_size_threshold:units = "cm" ; fates_phen_cold_size_threshold:long_name = "the dbh size above which will lead to phenology-related stem and leaf drop" ; + double fates_phen_drought_threshold(fates_pft) ; + fates_phen_drought_threshold:units = "m3/m3 or mm" ; + fates_phen_drought_threshold:long_name = "threshold for drought phenology (or lower threshold for semi-deciduous PFTs); the quantity depends on the sign: if positive, the threshold is volumetric soil moisture (m3/m3). If negative, the threshold is soil matric potentical (mm)" ; double fates_phen_evergreen(fates_pft) ; fates_phen_evergreen:units = "logical flag" ; fates_phen_evergreen:long_name = "Binary flag for evergreen leaf habit" ; + double fates_phen_flush_fraction(fates_pft) ; + fates_phen_flush_fraction:units = "fraction" ; + fates_phen_flush_fraction:long_name = "Upon bud-burst, the maximum fraction of storage carbon used for flushing leaves" ; + double fates_phen_fnrt_drop_fraction(fates_pft) ; + fates_phen_fnrt_drop_fraction:units = "fraction" ; + fates_phen_fnrt_drop_fraction:long_name = "fraction of fine roots to drop during drought/cold" ; + double fates_phen_mindaysoff(fates_pft) ; + fates_phen_mindaysoff:units = "days" ; + fates_phen_mindaysoff:long_name = "day threshold compared against days since leaves abscised (shed)" ; + double fates_phen_moist_threshold(fates_pft) ; + fates_phen_moist_threshold:units = "m3/m3 or mm" ; + fates_phen_moist_threshold:long_name = "upper threshold for drought phenology (only for drought semi-deciduous PFTs); the quantity depends on the sign: if positive, the threshold is volumetric soil moisture (m3/m3). If negative, the threshold is soil matric potentical (mm)" ; double fates_phen_season_decid(fates_pft) ; fates_phen_season_decid:units = "logical flag" ; fates_phen_season_decid:long_name = "Binary flag for seasonal-deciduous leaf habit" ; @@ -415,139 +470,174 @@ variables: double fates_phen_stress_decid(fates_pft) ; fates_phen_stress_decid:units = "logical flag" ; fates_phen_stress_decid:long_name = "Binary flag for stress-deciduous leaf habit" ; - double fates_phenflush_fraction(fates_pft) ; - fates_phenflush_fraction:units = "fraction" ; - fates_phenflush_fraction:long_name = "Upon bud-burst, the maximum fraction of storage carbon used for flushing leaves" ; - double fates_phos_store_ratio(fates_pft) ; - fates_phos_store_ratio:units = "(gP/gP)" ; - fates_phos_store_ratio:long_name = "ratio of storeable P, to functional P bound in cell structures of leaf,root,sap" ; - double fates_prescribed_mortality_canopy(fates_pft) ; - fates_prescribed_mortality_canopy:units = "1/yr" ; - fates_prescribed_mortality_canopy:long_name = "mortality rate of canopy trees for prescribed physiology mode" ; - double fates_prescribed_mortality_understory(fates_pft) ; - fates_prescribed_mortality_understory:units = "1/yr" ; - fates_prescribed_mortality_understory:long_name = "mortality rate of understory trees for prescribed physiology mode" ; double fates_prescribed_npp_canopy(fates_pft) ; fates_prescribed_npp_canopy:units = "kgC / m^2 / yr" ; fates_prescribed_npp_canopy:long_name = "NPP per unit crown area of canopy trees for prescribed physiology mode" ; double fates_prescribed_npp_understory(fates_pft) ; fates_prescribed_npp_understory:units = "kgC / m^2 / yr" ; fates_prescribed_npp_understory:long_name = "NPP per unit crown area of understory trees for prescribed physiology mode" ; - double fates_prescribed_nuptake(fates_pft) ; - 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: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" ; - fates_prescribed_recruitment:long_name = "recruitment rate for prescribed physiology mode" ; - double fates_prt_alloc_priority(fates_prt_organs, fates_pft) ; - fates_prt_alloc_priority:units = "index (0-fates_prt_organs)" ; - fates_prt_alloc_priority:long_name = "Priority order for allocation (C storage=2)" ; - double fates_prt_nitr_stoich_p1(fates_prt_organs, fates_pft) ; - fates_prt_nitr_stoich_p1:units = "(gN/gC)" ; - fates_prt_nitr_stoich_p1:long_name = "nitrogen stoichiometry, parameter 1" ; - double fates_prt_nitr_stoich_p2(fates_prt_organs, fates_pft) ; - fates_prt_nitr_stoich_p2:units = "(gN/gC)" ; - fates_prt_nitr_stoich_p2:long_name = "nitrogen stoichiometry, parameter 2" ; - double fates_prt_phos_stoich_p1(fates_prt_organs, fates_pft) ; - fates_prt_phos_stoich_p1:units = "(gP/gC)" ; - fates_prt_phos_stoich_p1:long_name = "phosphorous stoichiometry, parameter 1" ; - double fates_prt_phos_stoich_p2(fates_prt_organs, fates_pft) ; - fates_prt_phos_stoich_p2:units = "(gP/gC)" ; - fates_prt_phos_stoich_p2:long_name = "phosphorous stoichiometry, parameter 2" ; - double fates_recruit_hgt_min(fates_pft) ; - fates_recruit_hgt_min:units = "m" ; - fates_recruit_hgt_min:long_name = "the minimum height (ie starting height) of a newly recruited plant" ; - double fates_recruit_initd(fates_pft) ; - fates_recruit_initd:units = "stems/m2" ; - fates_recruit_initd:long_name = "initial seedling density for a cold-start near-bare-ground simulation" ; - double fates_rholnir(fates_pft) ; - fates_rholnir:units = "fraction" ; - fates_rholnir:long_name = "Leaf reflectance: near-IR" ; - double fates_rholvis(fates_pft) ; - fates_rholvis:units = "fraction" ; - fates_rholvis:long_name = "Leaf reflectance: visible" ; - double fates_rhosnir(fates_pft) ; - fates_rhosnir:units = "fraction" ; - fates_rhosnir:long_name = "Stem reflectance: near-IR" ; - double fates_rhosvis(fates_pft) ; - fates_rhosvis:units = "fraction" ; - fates_rhosvis:long_name = "Stem reflectance: visible" ; - double fates_root_long(fates_pft) ; - fates_root_long:units = "yr" ; - fates_root_long:long_name = "root longevity (alternatively, turnover time)" ; - 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) ; - 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) ; - fates_seed_dbh_repro_threshold:units = "cm" ; - fates_seed_dbh_repro_threshold:long_name = "the diameter (if any) where the plant will start extra clonal allocation to the seed pool" ; - double fates_seed_decay_rate(fates_pft) ; - fates_seed_decay_rate:units = "yr-1" ; - fates_seed_decay_rate:long_name = "fraction of seeds that decay per year" ; - double fates_seed_germination_rate(fates_pft) ; - fates_seed_germination_rate:units = "yr-1" ; - fates_seed_germination_rate:long_name = "fraction of seeds that germinate per year" ; - double fates_seed_suppl(fates_pft) ; - fates_seed_suppl:units = "KgC/m2/yr" ; - fates_seed_suppl:long_name = "Supplemental external seed rain source term (non-mass conserving)" ; - double fates_senleaf_long_fdrought(fates_pft) ; - fates_senleaf_long_fdrought:units = "unitless[0-1]" ; - fates_senleaf_long_fdrought:long_name = "multiplication factor for leaf longevity of senescent leaves during drought" ; - double fates_smpsc(fates_pft) ; - fates_smpsc:units = "mm" ; - fates_smpsc:long_name = "Soil water potential at full stomatal closure" ; - double fates_smpso(fates_pft) ; - fates_smpso:units = "mm" ; - fates_smpso:long_name = "Soil water potential at full stomatal opening" ; - double fates_taulnir(fates_pft) ; - fates_taulnir:units = "fraction" ; - fates_taulnir:long_name = "Leaf transmittance: near-IR" ; - double fates_taulvis(fates_pft) ; - fates_taulvis:units = "fraction" ; - fates_taulvis:long_name = "Leaf transmittance: visible" ; - double fates_tausnir(fates_pft) ; - fates_tausnir:units = "fraction" ; - fates_tausnir:long_name = "Stem transmittance: near-IR" ; - double fates_tausvis(fates_pft) ; - fates_tausvis:units = "fraction" ; - fates_tausvis:long_name = "Stem transmittance: visible" ; + double fates_rad_leaf_clumping_index(fates_pft) ; + fates_rad_leaf_clumping_index:units = "fraction (0-1)" ; + fates_rad_leaf_clumping_index:long_name = "factor describing how much self-occlusion of leaf scattering elements decreases light interception" ; + double fates_rad_leaf_rhonir(fates_pft) ; + fates_rad_leaf_rhonir:units = "fraction" ; + fates_rad_leaf_rhonir:long_name = "Leaf reflectance: near-IR" ; + double fates_rad_leaf_rhovis(fates_pft) ; + fates_rad_leaf_rhovis:units = "fraction" ; + fates_rad_leaf_rhovis:long_name = "Leaf reflectance: visible" ; + double fates_rad_leaf_taunir(fates_pft) ; + fates_rad_leaf_taunir:units = "fraction" ; + fates_rad_leaf_taunir:long_name = "Leaf transmittance: near-IR" ; + double fates_rad_leaf_tauvis(fates_pft) ; + fates_rad_leaf_tauvis:units = "fraction" ; + fates_rad_leaf_tauvis:long_name = "Leaf transmittance: visible" ; + double fates_rad_leaf_xl(fates_pft) ; + fates_rad_leaf_xl:units = "unitless" ; + fates_rad_leaf_xl:long_name = "Leaf/stem orientation index" ; + double fates_rad_stem_rhonir(fates_pft) ; + fates_rad_stem_rhonir:units = "fraction" ; + fates_rad_stem_rhonir:long_name = "Stem reflectance: near-IR" ; + double fates_rad_stem_rhovis(fates_pft) ; + fates_rad_stem_rhovis:units = "fraction" ; + fates_rad_stem_rhovis:long_name = "Stem reflectance: visible" ; + double fates_rad_stem_taunir(fates_pft) ; + fates_rad_stem_taunir:units = "fraction" ; + fates_rad_stem_taunir:long_name = "Stem transmittance: near-IR" ; + double fates_rad_stem_tauvis(fates_pft) ; + fates_rad_stem_tauvis:units = "fraction" ; + fates_rad_stem_tauvis:long_name = "Stem transmittance: visible" ; + double fates_recruit_height_min(fates_pft) ; + fates_recruit_height_min:units = "m" ; + fates_recruit_height_min:long_name = "the minimum height (ie starting height) of a newly recruited plant" ; + double fates_recruit_init_density(fates_pft) ; + fates_recruit_init_density:units = "stems/m2" ; + fates_recruit_init_density:long_name = "initial seedling density for a cold-start near-bare-ground simulation. If negative sets initial tree dbh - only to be used in nocomp mode" ; + double fates_recruit_prescribed_rate(fates_pft) ; + fates_recruit_prescribed_rate:units = "n/yr" ; + fates_recruit_prescribed_rate:long_name = "recruitment rate for prescribed physiology mode" ; + double fates_recruit_seed_alloc(fates_pft) ; + fates_recruit_seed_alloc:units = "fraction" ; + fates_recruit_seed_alloc:long_name = "fraction of available carbon balance allocated to seeds" ; + double fates_recruit_seed_alloc_mature(fates_pft) ; + fates_recruit_seed_alloc_mature:units = "fraction" ; + fates_recruit_seed_alloc_mature:long_name = "fraction of available carbon balance allocated to seeds in mature plants (adds to fates_seed_alloc)" ; + double fates_recruit_seed_dbh_repro_threshold(fates_pft) ; + fates_recruit_seed_dbh_repro_threshold:units = "cm" ; + fates_recruit_seed_dbh_repro_threshold:long_name = "the diameter where the plant will increase allocation to the seed pool by fraction: fates_recruit_seed_alloc_mature" ; + double fates_recruit_seed_germination_rate(fates_pft) ; + fates_recruit_seed_germination_rate:units = "yr-1" ; + fates_recruit_seed_germination_rate:long_name = "fraction of seeds that germinate per year" ; + double fates_recruit_seed_supplement(fates_pft) ; + fates_recruit_seed_supplement:units = "KgC/m2/yr" ; + fates_recruit_seed_supplement:long_name = "Supplemental external seed rain source term (non-mass conserving)" ; + double fates_seed_dispersal_fraction(fates_pft) ; + fates_seed_dispersal_fraction:units = "fraction" ; + fates_seed_dispersal_fraction:long_name = "fraction of seed rain to be dispersed to other grid cells" ; + double fates_seed_dispersal_max_dist(fates_pft) ; + fates_seed_dispersal_max_dist:units = "m" ; + fates_seed_dispersal_max_dist:long_name = "maximum seed dispersal distance for a given pft" ; + double fates_seed_dispersal_pdf_scale(fates_pft) ; + fates_seed_dispersal_pdf_scale:units = "unitless" ; + fates_seed_dispersal_pdf_scale:long_name = "seed dispersal probability density function scale parameter, A, Table 1 Bullock et al 2016" ; + double fates_seed_dispersal_pdf_shape(fates_pft) ; + fates_seed_dispersal_pdf_shape:units = "unitless" ; + fates_seed_dispersal_pdf_shape:long_name = "seed dispersal probability density function shape parameter, B, Table 1 Bullock et al 2016" ; + double fates_stoich_nitr(fates_plant_organs, fates_pft) ; + fates_stoich_nitr:units = "gN/gC" ; + fates_stoich_nitr:long_name = "target nitrogen concentration (ratio with carbon) of organs" ; + double fates_stoich_phos(fates_plant_organs, fates_pft) ; + fates_stoich_phos:units = "gP/gC" ; + fates_stoich_phos:long_name = "target phosphorus concentration (ratio with carbon) of organs" ; double fates_trim_inc(fates_pft) ; fates_trim_inc:units = "m2/m2" ; fates_trim_inc:long_name = "Arbitrary incremental change in trimming function." ; double fates_trim_limit(fates_pft) ; fates_trim_limit:units = "m2/m2" ; fates_trim_limit:long_name = "Arbitrary limit to reductions in leaf area with stress" ; - double fates_turnover_carb_retrans(fates_prt_organs, fates_pft) ; - fates_turnover_carb_retrans:units = "-" ; - fates_turnover_carb_retrans:long_name = "retranslocation fraction of carbon in turnover" ; - double fates_turnover_nitr_retrans(fates_prt_organs, fates_pft) ; - fates_turnover_nitr_retrans:units = "-" ; - fates_turnover_nitr_retrans:long_name = "retranslocation fraction of nitrogen in turnover" ; - double fates_turnover_phos_retrans(fates_prt_organs, fates_pft) ; - fates_turnover_phos_retrans:units = "-" ; - fates_turnover_phos_retrans:long_name = "retranslocation fraction of phosphorous in turnover, parameter 1" ; - double fates_turnover_retrans_mode(fates_pft) ; - fates_turnover_retrans_mode:units = "index" ; - fates_turnover_retrans_mode:long_name = "retranslocation method for leaf/fineroot turnover." ; - fates_turnover_retrans_mode:possible_values = "1: constant fraction." ; + double fates_trs_repro_alloc_a(fates_pft) ; + fates_trs_repro_alloc_a:units = "fraction" ; + fates_trs_repro_alloc_a:long_name = "shape parameter for sigmoidal function relating dbh to reproductive allocation" ; + double fates_trs_repro_alloc_b(fates_pft) ; + fates_trs_repro_alloc_b:units = "fraction" ; + fates_trs_repro_alloc_b:long_name = "intercept parameter for sigmoidal function relating dbh to reproductive allocation" ; + double fates_trs_repro_frac_seed(fates_pft) ; + fates_trs_repro_frac_seed:units = "fraction" ; + fates_trs_repro_frac_seed:long_name = "fraction of reproductive mass that is seed" ; + double fates_trs_seedling_a_emerg(fates_pft) ; + fates_trs_seedling_a_emerg:units = "day -1" ; + fates_trs_seedling_a_emerg:long_name = "mean fraction of seed bank emerging" ; + double fates_trs_seedling_b_emerg(fates_pft) ; + fates_trs_seedling_b_emerg:units = "day -1" ; + fates_trs_seedling_b_emerg:long_name = "seedling emergence sensitivity to soil moisture" ; + double fates_trs_seedling_background_mort(fates_pft) ; + fates_trs_seedling_background_mort:units = "yr-1" ; + fates_trs_seedling_background_mort:long_name = "background seedling mortality rate" ; + double fates_trs_seedling_h2o_mort_a(fates_pft) ; + fates_trs_seedling_h2o_mort_a:units = "-" ; + fates_trs_seedling_h2o_mort_a:long_name = "coefficient in moisture-based seedling mortality" ; + double fates_trs_seedling_h2o_mort_b(fates_pft) ; + fates_trs_seedling_h2o_mort_b:units = "-" ; + fates_trs_seedling_h2o_mort_b:long_name = "coefficient in moisture-based seedling mortality" ; + double fates_trs_seedling_h2o_mort_c(fates_pft) ; + fates_trs_seedling_h2o_mort_c:units = "-" ; + fates_trs_seedling_h2o_mort_c:long_name = "coefficient in moisture-based seedling mortality" ; + double fates_trs_seedling_light_mort_a(fates_pft) ; + fates_trs_seedling_light_mort_a:units = "-" ; + fates_trs_seedling_light_mort_a:long_name = "light-based seedling mortality coefficient" ; + double fates_trs_seedling_light_mort_b(fates_pft) ; + fates_trs_seedling_light_mort_b:units = "-" ; + fates_trs_seedling_light_mort_b:long_name = "light-based seedling mortality coefficient" ; + double fates_trs_seedling_light_rec_a(fates_pft) ; + fates_trs_seedling_light_rec_a:units = "-" ; + fates_trs_seedling_light_rec_a:long_name = "coefficient in light-based seedling to sapling transition" ; + double fates_trs_seedling_light_rec_b(fates_pft) ; + fates_trs_seedling_light_rec_b:units = "-" ; + fates_trs_seedling_light_rec_b:long_name = "coefficient in light-based seedling to sapling transition" ; + double fates_trs_seedling_mdd_crit(fates_pft) ; + fates_trs_seedling_mdd_crit:units = "mm H2O day" ; + fates_trs_seedling_mdd_crit:long_name = "critical moisture deficit (suction) day accumulation for seedling moisture-based seedling mortality to begin" ; + double fates_trs_seedling_par_crit_germ(fates_pft) ; + fates_trs_seedling_par_crit_germ:units = "MJ m-2 day-1" ; + fates_trs_seedling_par_crit_germ:long_name = "critical light level for germination" ; + double fates_trs_seedling_psi_crit(fates_pft) ; + fates_trs_seedling_psi_crit:units = "mm H2O" ; + fates_trs_seedling_psi_crit:long_name = "critical soil moisture (suction) for seedling stress" ; + double fates_trs_seedling_psi_emerg(fates_pft) ; + fates_trs_seedling_psi_emerg:units = "mm h20 suction" ; + fates_trs_seedling_psi_emerg:long_name = "critical soil moisture for seedling emergence" ; + double fates_trs_seedling_root_depth(fates_pft) ; + fates_trs_seedling_root_depth:units = "m" ; + fates_trs_seedling_root_depth:long_name = "rooting depth of seedlings" ; + double fates_turb_displar(fates_pft) ; + fates_turb_displar:units = "unitless" ; + fates_turb_displar:long_name = "Ratio of displacement height to canopy top height" ; + double fates_turb_leaf_diameter(fates_pft) ; + fates_turb_leaf_diameter:units = "m" ; + fates_turb_leaf_diameter:long_name = "Characteristic leaf dimension" ; + double fates_turb_z0mr(fates_pft) ; + fates_turb_z0mr:units = "unitless" ; + fates_turb_z0mr:long_name = "Ratio of momentum roughness length to canopy top height" ; + double fates_turnover_branch(fates_pft) ; + fates_turnover_branch:units = "yr" ; + fates_turnover_branch:long_name = "turnover time of branches" ; + double fates_turnover_fnrt(fates_pft) ; + fates_turnover_fnrt:units = "yr" ; + fates_turnover_fnrt:long_name = "root longevity (alternatively, turnover time)" ; + double fates_turnover_leaf(fates_leafage_class, fates_pft) ; + fates_turnover_leaf:units = "yr" ; + fates_turnover_leaf:long_name = "Leaf longevity (ie turnover timescale). For drought-deciduous PFTs, this also indicates the maximum length of the growing (i.e., leaves on) season." ; + double fates_turnover_senleaf_fdrought(fates_pft) ; + fates_turnover_senleaf_fdrought:units = "unitless[0-1]" ; + fates_turnover_senleaf_fdrought:long_name = "multiplication factor for leaf longevity of senescent leaves during drought" ; double fates_wood_density(fates_pft) ; fates_wood_density:units = "g/cm3" ; fates_wood_density:long_name = "mean density of woody tissue in plant" ; double fates_woody(fates_pft) ; fates_woody:units = "logical flag" ; fates_woody:long_name = "Binary woody lifeform flag" ; - double fates_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" ; @@ -572,18 +662,18 @@ variables: double fates_fire_SAV(fates_litterclass) ; fates_fire_SAV:units = "cm-1" ; fates_fire_SAV:long_name = "fuel surface area to volume ratio" ; - double fates_max_decomp(fates_litterclass) ; - fates_max_decomp:units = "yr-1" ; - fates_max_decomp:long_name = "maximum rate of litter & CWD transfer from non-decomposing class into decomposing class" ; - double fates_CWD_frac(fates_NCWD) ; - fates_CWD_frac:units = "fraction" ; - fates_CWD_frac:long_name = "fraction of woody (bdead+bsw) biomass destined for CWD pool" ; - double fates_base_mr_20 ; - fates_base_mr_20:units = "gC/gN/s" ; - fates_base_mr_20:long_name = "Base maintenance respiration rate for plant tissues, using Ryan 1991" ; + double fates_frag_maxdecomp(fates_litterclass) ; + fates_frag_maxdecomp:units = "yr-1" ; + fates_frag_maxdecomp:long_name = "maximum rate of litter & CWD transfer from non-decomposing class into decomposing class" ; + double fates_frag_cwd_frac(fates_NCWD) ; + fates_frag_cwd_frac:units = "fraction" ; + fates_frag_cwd_frac:long_name = "fraction of woody (bdead+bsw) biomass destined for CWD pool" ; double fates_canopy_closure_thresh ; fates_canopy_closure_thresh:units = "unitless" ; fates_canopy_closure_thresh:long_name = "tree canopy coverage at which crown area allometry changes from savanna to forest value" ; + double fates_cnp_eca_plant_escalar ; + fates_cnp_eca_plant_escalar:units = "" ; + fates_cnp_eca_plant_escalar:long_name = "scaling factor for plant fine root biomass to calculate nutrient carrier enzyme abundance (ECA)" ; double fates_cohort_age_fusion_tol ; fates_cohort_age_fusion_tol:units = "unitless" ; fates_cohort_age_fusion_tol:long_name = "minimum fraction in differece in cohort age between cohorts." ; @@ -593,18 +683,18 @@ variables: double fates_comp_excln ; fates_comp_excln:units = "none" ; fates_comp_excln:long_name = "IF POSITIVE: weighting factor (exponent on dbh) for canopy layer exclusion and promotion, IF NEGATIVE: switch to use deterministic height sorting" ; - double fates_cwd_fcel ; - fates_cwd_fcel:units = "unitless" ; - fates_cwd_fcel:long_name = "Cellulose fraction for CWD" ; - double fates_cwd_flig ; - fates_cwd_flig:units = "unitless" ; - fates_cwd_flig:long_name = "Lignin fraction of coarse woody debris" ; + double fates_damage_canopy_layer_code ; + fates_damage_canopy_layer_code:units = "unitless" ; + fates_damage_canopy_layer_code:long_name = "Integer code that decides whether damage affects canopy trees (1), understory trees (2)" ; + double fates_damage_event_code ; + fates_damage_event_code:units = "unitless" ; + fates_damage_event_code:long_name = "Integer code that options how damage events are structured" ; double fates_dev_arbitrary ; fates_dev_arbitrary:units = "unknown" ; fates_dev_arbitrary:long_name = "Unassociated free parameter that developers can use for testing arbitrary new hypotheses" ; - double fates_eca_plant_escalar ; - fates_eca_plant_escalar:units = "" ; - fates_eca_plant_escalar:long_name = "scaling factor for plant fine root biomass to calculate nutrient carrier enzyme abundance (ECA)" ; + double fates_fire_active_crown_fire ; + fates_fire_active_crown_fire:units = "0 or 1" ; + fates_fire_active_crown_fire:long_name = "flag, 1=active crown fire 0=no active crown fire" ; double fates_fire_cg_strikes ; fates_fire_cg_strikes:units = "fraction (0-1)" ; fates_fire_cg_strikes:long_name = "fraction of cloud to ground lightning strikes" ; @@ -644,54 +734,93 @@ variables: double fates_fire_threshold ; fates_fire_threshold:units = "kW/m" ; fates_fire_threshold:long_name = "spitfire parameter, fire intensity threshold for tracking fires that spread" ; - double fates_hydr_kmax_rsurf1 ; - fates_hydr_kmax_rsurf1:units = "kg water/m2 root area/Mpa/s" ; - fates_hydr_kmax_rsurf1:long_name = "maximum conducitivity for unit root surface (into root)" ; - double fates_hydr_kmax_rsurf2 ; - fates_hydr_kmax_rsurf2:units = "kg water/m2 root area/Mpa/s" ; - fates_hydr_kmax_rsurf2:long_name = "maximum conducitivity for unit root surface (out of root)" ; - double fates_hydr_psi0 ; - fates_hydr_psi0:units = "MPa" ; - fates_hydr_psi0:long_name = "sapwood water potential at saturation" ; - double fates_hydr_psicap ; - fates_hydr_psicap:units = "MPa" ; - fates_hydr_psicap:long_name = "sapwood water potential at which capillary reserves exhausted" ; - double fates_init_litter ; - fates_init_litter:units = "NA" ; - fates_init_litter:long_name = "Initialization value for litter pool in cold-start (NOT USED)" ; + double fates_frag_cwd_fcel ; + fates_frag_cwd_fcel:units = "unitless" ; + fates_frag_cwd_fcel:long_name = "Cellulose fraction for CWD" ; + double fates_frag_cwd_flig ; + fates_frag_cwd_flig:units = "unitless" ; + fates_frag_cwd_flig:long_name = "Lignin fraction of coarse woody debris" ; + double fates_hydro_kmax_rsurf1 ; + fates_hydro_kmax_rsurf1:units = "kg water/m2 root area/Mpa/s" ; + fates_hydro_kmax_rsurf1:long_name = "maximum conducitivity for unit root surface (into root)" ; + double fates_hydro_kmax_rsurf2 ; + fates_hydro_kmax_rsurf2:units = "kg water/m2 root area/Mpa/s" ; + fates_hydro_kmax_rsurf2:long_name = "maximum conducitivity for unit root surface (out of root)" ; + double fates_hydro_psi0 ; + fates_hydro_psi0:units = "MPa" ; + fates_hydro_psi0:long_name = "sapwood water potential at saturation" ; + double fates_hydro_psicap ; + fates_hydro_psicap:units = "MPa" ; + fates_hydro_psicap:long_name = "sapwood water potential at which capillary reserves exhausted" ; + double fates_hydro_solver ; + fates_hydro_solver:units = "unitless" ; + fates_hydro_solver:long_name = "switch designating which numerical solver for plant hydraulics, 1 = 1D taylor, 2 = 2D Picard, 3 = 2D Newton (deprecated)" ; + double fates_landuse_logging_coll_under_frac ; + fates_landuse_logging_coll_under_frac:units = "fraction" ; + fates_landuse_logging_coll_under_frac:long_name = "Fraction of stems killed in the understory when logging generates disturbance" ; + double fates_landuse_logging_collateral_frac ; + fates_landuse_logging_collateral_frac:units = "fraction" ; + fates_landuse_logging_collateral_frac:long_name = "Fraction of large stems in upperstory that die from logging collateral damage" ; + double fates_landuse_logging_dbhmax ; + fates_landuse_logging_dbhmax:units = "cm" ; + fates_landuse_logging_dbhmax:long_name = "Maximum dbh below which logging is applied (unset values flag this to be unused)" ; + double fates_landuse_logging_dbhmax_infra ; + fates_landuse_logging_dbhmax_infra:units = "cm" ; + fates_landuse_logging_dbhmax_infra:long_name = "Tree diameter, above which infrastructure from logging does not impact damage or mortality." ; + double fates_landuse_logging_dbhmin ; + fates_landuse_logging_dbhmin:units = "cm" ; + fates_landuse_logging_dbhmin:long_name = "Minimum dbh at which logging is applied" ; + double fates_landuse_logging_direct_frac ; + fates_landuse_logging_direct_frac:units = "fraction" ; + fates_landuse_logging_direct_frac:long_name = "Fraction of stems logged directly per event" ; + double fates_landuse_logging_event_code ; + fates_landuse_logging_event_code:units = "unitless" ; + fates_landuse_logging_event_code:long_name = "Integer code that options how logging events are structured" ; + double fates_landuse_logging_export_frac ; + fates_landuse_logging_export_frac:units = "fraction" ; + fates_landuse_logging_export_frac:long_name = "fraction of trunk product being shipped offsite, the leftovers will be left onsite as large CWD" ; + double fates_landuse_logging_mechanical_frac ; + fates_landuse_logging_mechanical_frac:units = "fraction" ; + fates_landuse_logging_mechanical_frac:long_name = "Fraction of stems killed due infrastructure an other mechanical means" ; + double fates_landuse_pprodharv10_forest_mean ; + fates_landuse_pprodharv10_forest_mean:units = "fraction" ; + fates_landuse_pprodharv10_forest_mean:long_name = "mean harvest mortality proportion of deadstem to 10-yr product (pprodharv10) of all woody PFT types" ; + double fates_leaf_photo_temp_acclim_thome_time ; + fates_leaf_photo_temp_acclim_thome_time:units = "years" ; + fates_leaf_photo_temp_acclim_thome_time:long_name = "Length of the window for the long-term (i.e. T_home in Kumarathunge et al 2019) exponential moving average (ema) of vegetation temperature used in photosynthesis temperature acclimation (used if fates_leaf_photo_tempsens_model = 2)" ; + double fates_leaf_photo_temp_acclim_timescale ; + fates_leaf_photo_temp_acclim_timescale:units = "days" ; + fates_leaf_photo_temp_acclim_timescale:long_name = "Length of the window for the exponential moving average (ema) of vegetation temperature used in photosynthesis temperature acclimation (used if fates_maintresp_leaf_model=2 or fates_leaf_photo_tempsens_model = 2)" ; + double fates_leaf_photo_tempsens_model ; + fates_leaf_photo_tempsens_model:units = "unitless" ; + fates_leaf_photo_tempsens_model:long_name = "switch for choosing the model that defines the temperature sensitivity of photosynthetic parameters (vcmax, jmax). 1=non-acclimating; 2=Kumarathunge et al 2019" ; + double fates_leaf_stomatal_assim_model ; + fates_leaf_stomatal_assim_model:units = "unitless" ; + fates_leaf_stomatal_assim_model:long_name = "a switch designating whether to use net (1) or gross (2) assimilation in the stomatal model" ; double fates_leaf_stomatal_model ; fates_leaf_stomatal_model:units = "unitless" ; fates_leaf_stomatal_model:long_name = "switch for choosing between Ball-Berry (1) stomatal conductance model and Medlyn (2) model" ; - double fates_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 ; - fates_logging_collateral_frac:units = "fraction" ; - fates_logging_collateral_frac:long_name = "Fraction of large stems in upperstory that die from logging collateral damage" ; - double fates_logging_dbhmax ; - fates_logging_dbhmax:units = "cm" ; - fates_logging_dbhmax:long_name = "Maximum dbh below which logging is applied (unset values flag this to be unused)" ; - double fates_logging_dbhmax_infra ; - fates_logging_dbhmax_infra:units = "cm" ; - fates_logging_dbhmax_infra:long_name = "Tree diameter, above which infrastructure from logging does not impact damage or mortality." ; - double fates_logging_dbhmin ; - fates_logging_dbhmin:units = "cm" ; - fates_logging_dbhmin:long_name = "Minimum dbh at which logging is applied" ; - double fates_logging_direct_frac ; - fates_logging_direct_frac:units = "fraction" ; - fates_logging_direct_frac:long_name = "Fraction of stems logged directly per event" ; - double fates_logging_event_code ; - fates_logging_event_code:units = "unitless" ; - fates_logging_event_code:long_name = "Integer code that options how logging events are structured" ; - double fates_logging_export_frac ; - fates_logging_export_frac:units = "fraction" ; - fates_logging_export_frac:long_name = "fraction of trunk product being shipped offsite, the leftovers will be left onsite as large CWD" ; - double fates_logging_mechanical_frac ; - fates_logging_mechanical_frac:units = "fraction" ; - fates_logging_mechanical_frac:long_name = "Fraction of stems killed due infrastructure an other mechanical means" ; - double fates_maintresp_model ; - fates_maintresp_model:units = "unitless" ; - fates_maintresp_model:long_name = "switch for choosing between maintenance respiration models. 1=Ryan (1991) (NOT USED)" ; + double fates_leaf_theta_cj_c3 ; + fates_leaf_theta_cj_c3:units = "unitless" ; + fates_leaf_theta_cj_c3:long_name = "Empirical curvature parameter for ac, aj photosynthesis co-limitation in c3 plants" ; + double fates_leaf_theta_cj_c4 ; + fates_leaf_theta_cj_c4:units = "unitless" ; + fates_leaf_theta_cj_c4:long_name = "Empirical curvature parameter for ac, aj photosynthesis co-limitation in c4 plants" ; + double fates_maintresp_leaf_model ; + fates_maintresp_leaf_model:units = "unitless" ; + fates_maintresp_leaf_model:long_name = "switch for choosing between maintenance respiration models. 1=Ryan (1991), 2=Atkin et al., (2017)" ; + double fates_maintresp_nonleaf_baserate ; + fates_maintresp_nonleaf_baserate:units = "gC/gN/s" ; + fates_maintresp_nonleaf_baserate:long_name = "Base maintenance respiration rate for plant tissues, using Ryan 1991" ; + double fates_maxcohort ; + fates_maxcohort:units = "count" ; + fates_maxcohort:long_name = "maximum number of cohorts per patch. Actual number of cohorts also depend on cohort fusion tolerances" ; + double fates_maxpatch_primary ; + fates_maxpatch_primary:units = "count" ; + fates_maxpatch_primary:long_name = "maximum number of primary vegetation patches per site" ; + double fates_maxpatch_secondary ; + fates_maxpatch_secondary:units = "count" ; + fates_maxpatch_secondary:long_name = "maximum number of secondary vegetation patches per site" ; double fates_mort_disturb_frac ; fates_mort_disturb_frac:units = "fraction" ; fates_mort_disturb_frac:long_name = "fraction of canopy mortality that results in disturbance (i.e. transfer of area from new to old patch)" ; @@ -701,63 +830,63 @@ variables: double fates_patch_fusion_tol ; fates_patch_fusion_tol:units = "unitless" ; fates_patch_fusion_tol:long_name = "minimum fraction in difference in profiles between patches" ; - double fates_phen_a ; - fates_phen_a:units = "none" ; - fates_phen_a:long_name = "GDD accumulation function, intercept parameter: gdd_thesh = a + b exp(c*ncd)" ; - double fates_phen_b ; - fates_phen_b:units = "none" ; - fates_phen_b:long_name = "GDD accumulation function, multiplier parameter: gdd_thesh = a + b exp(c*ncd)" ; - double fates_phen_c ; - fates_phen_c:units = "none" ; - fates_phen_c:long_name = "GDD accumulation function, exponent parameter: gdd_thesh = a + b exp(c*ncd)" ; - double fates_phen_chiltemp ; - fates_phen_chiltemp:units = "degrees C" ; - fates_phen_chiltemp:long_name = "chilling day counting threshold for vegetation" ; + double fates_phen_chilltemp ; + fates_phen_chilltemp:units = "degrees C" ; + fates_phen_chilltemp:long_name = "chilling day counting threshold for vegetation" ; double fates_phen_coldtemp ; fates_phen_coldtemp:units = "degrees C" ; fates_phen_coldtemp:long_name = "vegetation temperature exceedance that flags a cold-day for leaf-drop" ; - double fates_phen_doff_time ; - fates_phen_doff_time:units = "days" ; - fates_phen_doff_time:long_name = "day threshold compared against days since leaves became off-allometry" ; - double fates_phen_drought_threshold ; - fates_phen_drought_threshold:units = "m3/m3" ; - fates_phen_drought_threshold:long_name = "liquid volume in soil layer, threashold for drought phenology" ; + double fates_phen_gddthresh_a ; + fates_phen_gddthresh_a:units = "none" ; + fates_phen_gddthresh_a:long_name = "GDD accumulation function, intercept parameter: gdd_thesh = a + b exp(c*ncd)" ; + double fates_phen_gddthresh_b ; + fates_phen_gddthresh_b:units = "none" ; + fates_phen_gddthresh_b:long_name = "GDD accumulation function, multiplier parameter: gdd_thesh = a + b exp(c*ncd)" ; + double fates_phen_gddthresh_c ; + fates_phen_gddthresh_c:units = "none" ; + fates_phen_gddthresh_c:long_name = "GDD accumulation function, exponent parameter: gdd_thesh = a + b exp(c*ncd)" ; double fates_phen_mindayson ; fates_phen_mindayson:units = "days" ; fates_phen_mindayson:long_name = "day threshold compared against days since leaves became on-allometry" ; double fates_phen_ncolddayslim ; fates_phen_ncolddayslim:units = "days" ; fates_phen_ncolddayslim:long_name = "day threshold exceedance for temperature leaf-drop" ; - double fates_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_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)" ; double fates_q10_froz ; fates_q10_froz:units = "unitless" ; fates_q10_froz:long_name = "Q10 for frozen-soil respiration rates" ; double fates_q10_mr ; fates_q10_mr:units = "unitless" ; fates_q10_mr:long_name = "Q10 for maintenance respiration" ; + double fates_rad_model ; + fates_rad_model:units = "unitless" ; + fates_rad_model:long_name = "switch designating the model for canopy radiation, 1 = Norman, 2 = Two-stream (experimental)" ; + double fates_regeneration_model ; + fates_regeneration_model:units = "-" ; + fates_regeneration_model:long_name = "switch for choosing between FATES\'s: 1) default regeneration scheme , 2) the Tree Recruitment Scheme (Hanbury-Brown et al., 2022), or (3) the Tree Recruitment Scheme without seedling dynamics" ; double fates_soil_salinity ; fates_soil_salinity:units = "ppt" ; fates_soil_salinity:long_name = "soil salinity used for model when not coupled to dynamic soil salinity" ; - double fates_theta_cj_c3 ; - fates_theta_cj_c3:units = "unitless" ; - fates_theta_cj_c3:long_name = "Empirical curvature parameter for ac, aj photosynthesis co-limitation in c3 plants" ; - double fates_theta_cj_c4 ; - fates_theta_cj_c4:units = "unitless" ; - fates_theta_cj_c4:long_name = "Empirical curvature parameter for ac, aj photosynthesis co-limitation in c4 plants" ; + double fates_trs_seedling2sap_par_timescale ; + fates_trs_seedling2sap_par_timescale:units = "days" ; + fates_trs_seedling2sap_par_timescale:long_name = "Length of the window for the exponential moving average of par at the seedling layer used to calculate seedling to sapling transition rates" ; + double fates_trs_seedling_emerg_h2o_timescale ; + fates_trs_seedling_emerg_h2o_timescale:units = "days" ; + fates_trs_seedling_emerg_h2o_timescale:long_name = "Length of the window for the exponential moving average of smp used to calculate seedling emergence" ; + double fates_trs_seedling_mdd_timescale ; + fates_trs_seedling_mdd_timescale:units = "days" ; + fates_trs_seedling_mdd_timescale:long_name = "Length of the window for the exponential moving average of moisture deficit days used to calculate seedling mortality" ; + double fates_trs_seedling_mort_par_timescale ; + fates_trs_seedling_mort_par_timescale:units = "days" ; + fates_trs_seedling_mort_par_timescale:long_name = "Length of the window for the exponential moving average of par at the seedling layer used to calculate seedling mortality" ; double fates_vai_top_bin_width ; fates_vai_top_bin_width:units = "m2/m2" ; - fates_vai_top_bin_width:long_name = "width in VAI units of uppermost leaf+stem layer scattering element in each canopy layer (NOT USED)" ; + fates_vai_top_bin_width:long_name = "width in VAI units of uppermost leaf+stem layer scattering element in each canopy layer" ; double fates_vai_width_increase_factor ; fates_vai_width_increase_factor:units = "unitless" ; - fates_vai_width_increase_factor:long_name = "factor by which each leaf+stem scattering element increases in VAI width (1 = uniform spacing) (NOT USED)" ; + fates_vai_width_increase_factor:long_name = "factor by which each leaf+stem scattering element increases in VAI width (1 = uniform spacing)" ; // global attributes: - :history = "This parameter file is maintained in version control\nSee https://github.com/NGEET/fates/blob/master/parameter_files/fates_params_default.cdl \nFor changes, use git blame \n" ; + :history = "This file was generated by BatchPatchParams.py:\nCDL Base File = archive/api24.1.0_101722_fates_params_default.cdl\nXML patch file = archive/api24.1.0_101722_patch_params.xml" ; data: fates_history_ageclass_bin_edges = 0, 1, 2, 5, 10, 20, 50 ; @@ -766,12 +895,14 @@ 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_damage_bin_edges = 0, 80 ; + + 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 ; + fates_alloc_organ_id = 1, 2, 3, 6 ; - fates_prt_organ_id = 1, 2, 3, 6 ; + fates_hydro_htftype_node = 1, 1, 1, 1 ; fates_pftname = "broadleaf_evergreen_tropical_tree ", @@ -787,12 +918,18 @@ data: "cool_c3_grass ", "c4_grass " ; - fates_hydr_organname_node = + fates_hydro_organ_name = "leaf ", "stem ", "transporting root ", "absorbing root " ; + fates_alloc_organ_name = + "leaf", + "fine root", + "sapwood", + "structure" ; + fates_litterclass_name = "twig ", "small branch ", @@ -801,28 +938,31 @@ data: "dead leaves ", "live grass " ; - fates_prt_organ_name = - "leaf ", - "fine root ", - "sapwood ", - "structure " ; + fates_alloc_organ_priority = + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 ; - fates_alloc_storage_cushion = 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, + fates_alloc_storage_cushion = 1.2, 1.2, 1.2, 1.2, 2.4, 1.2, 1.2, 2.4, 1.2, 1.2, 1.2, 1.2 ; - fates_allom_agb1 = 0.06896, 0.06896, 0.06896, 0.06896, 0.06896, 0.06896, + fates_alloc_store_priority_frac = 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, + 0.8, 0.8, 0.8, 0.8 ; + + fates_allom_agb1 = 0.06896, 0.06896, 0.06896, 0.06896, 0.06896, 0.06896, 0.06896, 0.06896, 0.06896, 0.01, 0.01, 0.01 ; - fates_allom_agb2 = 0.572, 0.572, 0.572, 0.572, 0.572, 0.572, 0.572, 0.572, + 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,50 +971,59 @@ 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_crown_depth_frac = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.95, 0.95, + 0.95, 1, 1, 1 ; + + fates_allom_d2bl1 = 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07 ; - fates_allom_d2bl2 = 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, + 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 ; + fates_allom_dbh_maxheight = 90, 80, 80, 80, 90, 80, 3, 3, 2, 0.35, 0.35, 0.35 ; fates_allom_fmode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + fates_allom_fnrt_prof_a = 7, 7, 7, 7, 6, 6, 7, 7, 7, 11, 11, 11 ; + + fates_allom_fnrt_prof_b = 1, 2, 2, 1, 2, 2, 1.5, 1.5, 1.5, 2, 2, 2 ; + + fates_allom_fnrt_prof_mode = 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 ; + fates_allom_frbstor_repro = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; fates_allom_hmode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; fates_allom_l2fr = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; - fates_allom_la_per_sa_int = 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, + 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,184 +1034,225 @@ 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 ; - fates_c2b = 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ; - 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, - 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, - 0.5, 0.5 ; + fates_cnp_eca_alpha_ptase = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5 ; - fates_eca_decompmicc = 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + fates_cnp_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_cnp_eca_km_nh4 = 0.14, 0.14, 0.14, 0.14, 0.14, 0.14, 0.14, 0.14, 0.14, 0.14, 0.14, 0.14 ; - fates_eca_km_no3 = 0.27, 0.27, 0.27, 0.27, 0.27, 0.27, 0.27, 0.27, 0.27, + fates_cnp_eca_km_no3 = 0.27, 0.27, 0.27, 0.27, 0.27, 0.27, 0.27, 0.27, 0.27, 0.27, 0.27, 0.27 ; - fates_eca_km_p = 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1 ; + fates_cnp_eca_km_p = 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, + 0.1 ; + + fates_cnp_eca_km_ptase = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; - fates_eca_km_ptase = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + fates_cnp_eca_lambda_ptase = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; - fates_eca_lambda_ptase = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + fates_cnp_eca_vmax_ptase = 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, + 5e-09, 5e-09, 5e-09, 5e-09, 5e-09 ; - fates_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_cnp_nfix1 = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; - 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_cnp_nitr_store_ratio = 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, + 1.5, 1.5, 1.5 ; - fates_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_cnp_phos_store_ratio = 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, + 1.5, 1.5, 1.5 ; - fates_eca_vmax_ptase = 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, - 5e-09, 5e-09, 5e-09, 5e-09, 5e-09 ; + fates_cnp_pid_kd = 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1 ; + + fates_cnp_pid_ki = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_cnp_pid_kp = 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, + 0.0005, 0.0005, 0.0005, 0.0005, 0.0005 ; + + fates_cnp_prescribed_nuptake = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; - fates_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_cnp_prescribed_puptake = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_cnp_store_ovrflw_frac = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_cnp_turnover_nitr_retrans = + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_cnp_turnover_phos_retrans = + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_cnp_vmax_nh4 = 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, + 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09 ; + + fates_cnp_vmax_no3 = 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, + 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09 ; + + fates_cnp_vmax_p = 5e-10, 5e-10, 5e-10, 5e-10, 5e-10, 5e-10, 5e-10, 5e-10, + 5e-10, 5e-10, 5e-10, 5e-10 ; + + fates_damage_frac = 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, + 0.01, 0.01, 0.01 ; + + fates_damage_mort_p1 = 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 ; + + fates_damage_mort_p2 = 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, + 5.5, 5.5 ; + + fates_damage_recovery_scalar = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_dev_arbitrary_pft = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_fire_alpha_SH = 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2 ; - fates_fire_bark_scaler = 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, + 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, - 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_fire_active_crown_fire = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + fates_frag_fnrt_fcel = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5 ; - fates_fnrt_prof_a = 7, 7, 7, 7, 6, 6, 7, 7, 7, 11, 11, 11 ; + fates_frag_fnrt_flab = 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25 ; - fates_fnrt_prof_b = 1, 2, 2, 1, 2, 2, 1.5, 1.5, 1.5, 2, 2, 2 ; + fates_frag_fnrt_flig = 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25 ; - fates_fnrt_prof_mode = 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 ; + fates_frag_leaf_fcel = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5 ; - fates_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_frag_leaf_flab = 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25 ; - fates_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_frag_leaf_flig = 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25 ; - fates_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_frag_seed_decay_rate = 0.51, 0.51, 0.51, 0.51, 0.51, 0.51, 0.51, 0.51, + 0.51, 0.51, 0.51, 0.51 ; - fates_grperc = 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, + 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, - 2.5 ; + fates_hydro_avuln_gs = 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, + 2.5, 2.5 ; - fates_hydr_avuln_node = + fates_hydro_avuln_node = 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ; - fates_hydr_epsil_node = + fates_hydro_epsil_node = 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 ; - fates_hydr_fcap_node = + fates_hydro_fcap_node = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; - fates_hydr_k_lwp = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + fates_hydro_k_lwp = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; - fates_hydr_kmax_node = + fates_hydro_kmax_node = -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999 ; - fates_hydr_p50_gs = -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, + fates_hydro_p50_gs = -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5 ; - fates_hydr_p50_node = - -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, + fates_hydro_p50_node = + -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, - -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, + -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, - -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, + -2.25, -2.25, -2.25, -2.25, -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, - 0.333, 0.333, 0.333, 0.333 ; + fates_hydro_p_taper = 0.333, 0.333, 0.333, 0.333, 0.333, 0.333, 0.333, + 0.333, 0.333, 0.333, 0.333, 0.333 ; - fates_hydr_pinot_node = - -1.465984, -1.465984, -1.465984, -1.465984, -1.465984, -1.465984, + fates_hydro_pinot_node = + -1.465984, -1.465984, -1.465984, -1.465984, -1.465984, -1.465984, -1.465984, -1.465984, -1.465984, -1.465984, -1.465984, -1.465984, - -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, + -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, - -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, -1.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, + fates_hydro_pitlp_node = + -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2 ; - fates_hydr_resid_node = + fates_hydro_resid_node = 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11 ; - fates_hydr_rfrac_stem = 0.625, 0.625, 0.625, 0.625, 0.625, 0.625, 0.625, + fates_hydro_rfrac_stem = 0.625, 0.625, 0.625, 0.625, 0.625, 0.625, 0.625, 0.625, 0.625, 0.625, 0.625, 0.625 ; - fates_hydr_rs2 = 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, + fates_hydro_rs2 = 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001 ; - fates_hydr_srl = 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25 ; + fates_hydro_srl = 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25 ; - fates_hydr_thetas_node = + fates_hydro_thetas_node = 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75 ; - fates_hydr_vg_alpha_node = - 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.005, 0.005, 0.005, 0.005, 0.005, + fates_hydro_vg_alpha_node = + 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.005, 0.005, 0.005, 0.005, 0.005, 0.005, 0.005, - 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.005, 0.005, 0.005, 0.005, 0.005, + 0.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 = + fates_hydro_vg_m_node = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5 ; - fates_hydr_vg_n_node = + fates_hydro_vg_n_node = 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -1070,284 +1260,314 @@ 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, - 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, - 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.005, 0.024, 0.009, 0.03, 0.03, 0.012, 0.03, 0.03, 0.03, 0.03, 0.03 ; - fates_leaf_stomatal_intercept = 10000, 10000, 10000, 10000, 10000, 10000, + 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, - 0.8, 0.8 ; - fates_leaf_vcmax25top = - 50, 65, 39, 62, 41, 58, 62, 54, 54, 78, 78, 78 ; + 50, 62, 39, 61, 58, 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.32, 0.01, 0.01, 0.32, 0.2, 0.59, 0.32, 0.59, 0.59, -0.23, - -0.23, -0.23 ; - - 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_maintresp_leaf_atkin2017_baserate = 1.756, 1.4995, 1.4995, 1.756, + 1.756, 1.756, 2.0749, 2.0749, 2.0749, 2.1956, 2.1956, 2.1956 ; - fates_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_maintresp_leaf_ryan1991_baserate = 2.525e-06, 2.525e-06, 2.525e-06, + 2.525e-06, 2.525e-06, 2.525e-06, 2.525e-06, 2.525e-06, 2.525e-06, + 2.525e-06, 2.525e-06, 2.525e-06 ; - fates_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_maintresp_reduction_upthresh = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_mort_bmort = 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014 ; - fates_mort_freezetol = 2.5, -55, -80, -30, 2.5, -30, -60, -10, -80, -80, + fates_mort_freezetol = 2.5, -55, -80, -30, 2.5, -80, -60, -10, -80, -80, -20, 2.5 ; - fates_mort_hf_flc_threshold = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 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 = _, _, _, _, _, _, _, _, _, _, _, _ ; fates_mort_ip_size_senescence = _, _, _, _, _, _, _, _, _, _, _, _ ; + fates_mort_prescribed_canopy = 0.0194, 0.0194, 0.0194, 0.0194, 0.0194, + 0.0194, 0.0194, 0.0194, 0.0194, 0.0194, 0.0194, 0.0194 ; + + fates_mort_prescribed_understory = 0.025, 0.025, 0.025, 0.025, 0.025, 0.025, + 0.025, 0.025, 0.025, 0.025, 0.025, 0.025 ; + fates_mort_r_age_senescence = _, _, _, _, _, _, _, _, _, _, _, _ ; fates_mort_r_size_senescence = _, _, _, _, _, _, _, _, _, _, _, _ ; fates_mort_scalar_coldstress = 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 ; - fates_mort_scalar_cstarvation = 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, + 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_mort_upthresh_cstarvation = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; - fates_nfix2 = _, _, _, _, _, _, _, _, _, _, _, _ ; + fates_nonhydro_smpsc = -255000, -255000, -255000, -255000, -255000, -255000, + -255000, -255000, -255000, -255000, -255000, -255000 ; - 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_nonhydro_smpso = -66000, -66000, -66000, -66000, -66000, -66000, + -66000, -66000, -66000, -66000, -66000, -66000 ; fates_phen_cold_size_threshold = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + fates_phen_drought_threshold = -152957.4, -152957.4, -152957.4, -152957.4, + -152957.4, -152957.4, -152957.4, -152957.4, -152957.4, -152957.4, + -152957.4, -152957.4 ; + fates_phen_evergreen = 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 ; + fates_phen_flush_fraction = _, _, 0.5, _, 0.5, 0.5, _, 0.5, 0.5, 0.5, 0.5, + 0.5 ; + + fates_phen_fnrt_drop_fraction = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_phen_mindaysoff = 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, + 100, 100 ; + + fates_phen_moist_threshold = -122365.9, -122365.9, -122365.9, -122365.9, + -122365.9, -122365.9, -122365.9, -122365.9, -122365.9, -122365.9, + -122365.9, -122365.9 ; + fates_phen_season_decid = 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0 ; fates_phen_stem_drop_fraction = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; fates_phen_stress_decid = 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1 ; - fates_phenflush_fraction = _, _, 0.5, _, 0.5, 0.5, _, 0.5, 0.5, 0.5, 0.5, 0.5 ; + 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_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_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_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_rad_leaf_clumping_index = 0.85, 0.85, 0.8, 0.85, 0.85, 0.9, 0.85, 0.9, + 0.9, 0.75, 0.75, 0.75 ; - fates_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_rad_leaf_rhonir = 0.46, 0.41, 0.39, 0.46, 0.41, 0.41, 0.46, 0.41, + 0.41, 0.28, 0.28, 0.28 ; - fates_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_rad_leaf_rhovis = 0.11, 0.09, 0.08, 0.11, 0.08, 0.08, 0.11, 0.08, + 0.08, 0.05, 0.05, 0.05 ; - fates_prescribed_npp_understory = 0.03125, 0.03125, 0.03125, 0.03125, - 0.03125, 0.03125, 0.03125, 0.03125, 0.03125, 0.03125, 0.03125, 0.03125 ; + fates_rad_leaf_taunir = 0.33, 0.32, 0.42, 0.33, 0.43, 0.43, 0.33, 0.43, + 0.43, 0.4, 0.4, 0.4 ; + + fates_rad_leaf_tauvis = 0.06, 0.04, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, + 0.06, 0.05, 0.05, 0.05 ; + + fates_rad_leaf_xl = 0.32, 0.01, 0.01, 0.32, 0.2, 0.59, 0.32, 0.59, 0.59, + -0.23, -0.23, -0.23 ; + + fates_rad_stem_rhonir = 0.49, 0.36, 0.36, 0.49, 0.49, 0.49, 0.49, 0.49, + 0.49, 0.53, 0.53, 0.53 ; + + fates_rad_stem_rhovis = 0.21, 0.12, 0.12, 0.21, 0.21, 0.21, 0.21, 0.21, + 0.21, 0.31, 0.31, 0.31 ; - fates_prescribed_nuptake = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + fates_rad_stem_taunir = 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, + 0.001, 0.001, 0.25, 0.25, 0.25 ; - fates_prescribed_puptake = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + fates_rad_stem_tauvis = 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, + 0.001, 0.001, 0.12, 0.12, 0.12 ; - fates_prescribed_recruitment = 0.02, 0.02, 0.02, 0.02, 0.02, 0.02, 0.02, + fates_recruit_height_min = 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 0.2, 0.2, 0.2, + 0.125, 0.125, 0.125 ; + + fates_recruit_init_density = 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, + 0.2, 0.2, 0.2 ; + + fates_recruit_prescribed_rate = 0.02, 0.02, 0.02, 0.02, 0.02, 0.02, 0.02, 0.02, 0.02, 0.02, 0.02, 0.02 ; - fates_prt_alloc_priority = - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 ; + fates_recruit_seed_alloc = 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, + 0.1, 0.1 ; - fates_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, - 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, - 1e-08, 1e-08, - 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, - 0.0047, 0.0047, 0.0047 ; + fates_recruit_seed_alloc_mature = 0, 0, 0, 0, 0, 0, 0.9, 0.9, 0.9, 0.9, 0.9, + 0.9 ; + + fates_recruit_seed_dbh_repro_threshold = 90, 80, 80, 80, 90, 80, 3, 3, 2, + 0.35, 0.35, 0.35 ; + + fates_recruit_seed_germination_rate = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5 ; + + fates_recruit_seed_supplement = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; - fates_prt_nitr_stoich_p2 = + fates_seed_dispersal_fraction = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_seed_dispersal_max_dist = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_seed_dispersal_pdf_scale = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_seed_dispersal_pdf_shape = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_stoich_nitr = 0.033, 0.029, 0.04, 0.033, 0.04, 0.04, 0.033, 0.04, 0.04, 0.04, 0.04, 0.04, - 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, + 0.024, 0.024, 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, + fates_stoich_phos = + 0.0033, 0.0029, 0.004, 0.0033, 0.004, 0.004, 0.0033, 0.004, 0.004, 0.004, 0.004, 0.004, - 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, + 0.0024, 0.0024, 0.0024, 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.004, 0.004, - 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, - 0.0024, 0.0024, 0.0024, - 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, - 1e-09, 1e-09, - 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, - 0.00047, 0.00047, 0.00047, 0.00047 ; + fates_trim_inc = 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, + 0.03, 0.03 ; - fates_recruit_hgt_min = 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 0.75, 0.75, 0.75, - 0.125, 0.125, 0.125 ; + fates_trim_limit = 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3 ; - fates_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_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_rholnir = 0.46, 0.41, 0.39, 0.46, 0.41, 0.41, 0.46, 0.41, 0.41, 0.28, - 0.28, 0.28 ; + fates_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_rholvis = 0.11, 0.09, 0.08, 0.11, 0.08, 0.08, 0.11, 0.08, 0.08, 0.05, 0.05, 0.05 ; + fates_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_rhosnir = 0.49, 0.36, 0.36, 0.49, 0.49, 0.49, 0.49, 0.49, 0.49, 0.53, - 0.53, 0.53 ; + fates_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_rhosvis = 0.21, 0.12, 0.12, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.31, - 0.31, 0.31 ; + fates_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_root_long = 1, 2, 1, 1.5, 1, 1, 1.5, 1, 1, 1, 1, 1 ; + 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_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_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_seed_alloc_mature = 0, 0, 0, 0, 0, 0, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9 ; + 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_seed_dbh_repro_threshold = 150, 90, 90, 90, 90, 90, 3, 3, 2, 1.47, - 1.47, 1.47 ; + 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_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_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_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_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_seed_suppl = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + 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_senleaf_long_fdrought = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + 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_smpsc = -255000, -255000, -255000, -255000, -255000, -255000, -255000, - -255000, -255000, -255000, -255000, -255000 ; + fates_trs_seedling_mdd_crit = 1400000, 1400000, 1400000, 1400000, 1400000, + 1400000, 1400000, 1400000, 1400000, 1400000, 1400000, 1400000 ; - fates_smpso = -66000, -66000, -66000, -66000, -66000, -66000, -66000, - -66000, -66000, -66000, -66000, -66000 ; + 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_taulnir = 0.33, 0.32, 0.42, 0.33, 0.43, 0.43, 0.33, 0.43, 0.43, 0.4, - 0.4, 0.4 ; + fates_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_taulvis = 0.06, 0.04, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.05, - 0.05, 0.05 ; + fates_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_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_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_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_turb_displar = 0.67, 0.67, 0.67, 0.67, 0.67, 0.67, 0.67, 0.67, 0.67, + 0.67, 0.67, 0.67 ; - fates_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_turb_leaf_diameter = 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, + 0.04, 0.04, 0.04, 0.04 ; - fates_trim_limit = 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3 ; + fates_turb_z0mr = 0.055, 0.055, 0.055, 0.055, 0.055, 0.055, 0.055, 0.055, + 0.055, 0.055, 0.055, 0.055 ; - fates_turnover_carb_retrans = - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + fates_turnover_branch = 150, 150, 150, 150, 150, 150, 150, 150, 150, 0, 0, 0 ; - fates_turnover_nitr_retrans = - 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, - 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + fates_turnover_fnrt = 1, 2, 1, 1.5, 1, 1, 1.5, 1, 1, 1, 1, 1 ; - fates_turnover_phos_retrans = - 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, - 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + fates_turnover_leaf = + 1.5, 4, 1, 1.5, 1, 1, 1.5, 1, 1, 1, 1, 1 ; - fates_turnover_retrans_mode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + fates_turnover_senleaf_fdrought = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; - fates_wood_density = 0.7, 0.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.4, 0.7, 0.53, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7 ; fates_woody = 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 ; - fates_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 ; @@ -1365,27 +1585,27 @@ data: fates_fire_SAV = 13, 3.58, 0.98, 0.2, 66, 66 ; - fates_max_decomp = 0.52, 0.383, 0.383, 0.19, 1, 999 ; - - fates_CWD_frac = 0.045, 0.075, 0.21, 0.67 ; + fates_frag_maxdecomp = 0.52, 0.383, 0.383, 0.19, 1, 999 ; - fates_base_mr_20 = 2.52e-06 ; + fates_frag_cwd_frac = 0.045, 0.075, 0.21, 0.67 ; fates_canopy_closure_thresh = 0.8 ; + fates_cnp_eca_plant_escalar = 1.25e-05 ; + fates_cohort_age_fusion_tol = 0.08 ; fates_cohort_size_fusion_tol = 0.08 ; fates_comp_excln = 3 ; - fates_cwd_fcel = 0.76 ; + fates_damage_canopy_layer_code = 1 ; - fates_cwd_flig = 0.24 ; + fates_damage_event_code = 1 ; fates_dev_arbitrary = _ ; - fates_eca_plant_escalar = 1.25e-05 ; + fates_fire_active_crown_fire = 0 ; fates_fire_cg_strikes = 0.2 ; @@ -1413,75 +1633,101 @@ data: fates_fire_threshold = 50 ; - fates_hydr_kmax_rsurf1 = 20 ; + fates_frag_cwd_fcel = 0.76 ; - fates_hydr_kmax_rsurf2 = 0.0001 ; + fates_frag_cwd_flig = 0.24 ; - fates_hydr_psi0 = 0 ; + fates_hydro_kmax_rsurf1 = 20 ; - fates_hydr_psicap = -0.6 ; + fates_hydro_kmax_rsurf2 = 0.0001 ; - fates_init_litter = 0.05 ; + fates_hydro_psi0 = 0 ; - fates_leaf_stomatal_model = 1 ; + fates_hydro_psicap = -0.6 ; - fates_logging_coll_under_frac = 0.55983 ; + fates_hydro_solver = 1 ; - fates_logging_collateral_frac = 0.05 ; + fates_landuse_logging_coll_under_frac = 0.55983 ; - fates_logging_dbhmax = _ ; + fates_landuse_logging_collateral_frac = 0.05 ; - fates_logging_dbhmax_infra = 35 ; + fates_landuse_logging_dbhmax = _ ; - fates_logging_dbhmin = 50 ; + fates_landuse_logging_dbhmax_infra = 35 ; - fates_logging_direct_frac = 0.15 ; + fates_landuse_logging_dbhmin = 50 ; - fates_logging_event_code = -30 ; + fates_landuse_logging_direct_frac = 0.15 ; - fates_logging_export_frac = 0.8 ; + fates_landuse_logging_event_code = -30 ; - fates_logging_mechanical_frac = 0.05 ; + fates_landuse_logging_export_frac = 0.8 ; - fates_maintresp_model = 1 ; + fates_landuse_logging_mechanical_frac = 0.05 ; - fates_mort_disturb_frac = 1 ; + fates_landuse_pprodharv10_forest_mean = 0.8125 ; - fates_mort_understorey_death = 0.55983 ; + fates_leaf_photo_temp_acclim_thome_time = 30 ; - fates_patch_fusion_tol = 0.05 ; + fates_leaf_photo_temp_acclim_timescale = 30 ; - fates_phen_a = -68 ; + fates_leaf_photo_tempsens_model = 1 ; - fates_phen_b = 638 ; + fates_leaf_stomatal_assim_model = 1 ; + + fates_leaf_stomatal_model = 1 ; - fates_phen_c = -0.01 ; + fates_leaf_theta_cj_c3 = 0.999 ; - fates_phen_chiltemp = 5 ; + fates_leaf_theta_cj_c4 = 0.999 ; + + fates_maintresp_leaf_model = 1 ; + + fates_maintresp_nonleaf_baserate = 2.525e-06 ; + + fates_maxcohort = 100 ; + + fates_maxpatch_primary = 10 ; + + fates_maxpatch_secondary = 4 ; + + fates_mort_disturb_frac = 1 ; + + fates_mort_understorey_death = 0.55983 ; + + fates_patch_fusion_tol = 0.05 ; + + fates_phen_chilltemp = 5 ; fates_phen_coldtemp = 7.5 ; - fates_phen_doff_time = 100 ; + fates_phen_gddthresh_a = -68 ; + + fates_phen_gddthresh_b = 638 ; - fates_phen_drought_threshold = 0.15 ; + fates_phen_gddthresh_c = -0.01 ; fates_phen_mindayson = 90 ; fates_phen_ncolddayslim = 5 ; - fates_photo_temp_acclim_timescale = 30 ; - - fates_photo_tempsens_model = 1 ; - fates_q10_froz = 1.5 ; fates_q10_mr = 1.5 ; + fates_rad_model = 1 ; + + fates_regeneration_model = 1 ; + fates_soil_salinity = 0.4 ; - fates_theta_cj_c3 = 0.999 ; + fates_trs_seedling2sap_par_timescale = 32 ; + + fates_trs_seedling_emerg_h2o_timescale = 7 ; + + fates_trs_seedling_mdd_timescale = 126 ; - fates_theta_cj_c4 = 0.999 ; + fates_trs_seedling_mort_par_timescale = 32 ; fates_vai_top_bin_width = 1 ; diff --git a/parameter_files/patch_default_bciopt224.xml b/parameter_files/patch_default_bciopt224.xml index bfcc288efa..8ab504ed31 100644 --- a/parameter_files/patch_default_bciopt224.xml +++ b/parameter_files/patch_default_bciopt224.xml @@ -2,17 +2,21 @@ This parameter dataset was created by Ryan Knox rgknox@lbl.gov. Please contact if using in published work. The calibration uses the following datasets: [1] Ely et al. 2019. Leaf mass area, Panama. NGEE-Tropics data collection.http://dx.doi.org/10.15486/ngt/1411973 and [2] Condit et al. 2019. Complete data from the Barro Colorado 50-ha plot. https://doi.org/10.15146/5xcp-0d46. [3] Koven et al. 2019. Benchmarking and parameter sensitivity of physiological and vegetation dynamics using the functionally assembled terrestrial ecosystem simulator. Biogeosciences. The ECA nutrient aquisition parmeters are unconstrained, the file output naming convention vmn6phi is shorthand for vmax for nitrogen uptake is order e-6 and for phosphorus is excessively high. These parameters were calibrated with the special fates modification in main/EDTypesMod.F90: nclmax = 3 fates_params_default.cdl - fates_params_opt224_vmn6phi_080621.cdl - 1 + fates_params_opt224_040822_api25.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 + + + + + + 0 + 0 + 0.03347526,0.024,1e-08,0.0047 + 0.002675,0.0005,0.00015,0.00015 + 0.45,0.25,0,0 + 0.65,0.25,0,0 + 0.8012471 30.94711 0.0673 0.976 @@ -31,22 +35,28 @@ 2 5 0.4863088 + 0.0 + 1 3 - 3e-06 - 3e-06 - 3e-07 - 3e-08 + 5e-09 + 0 + 5e-10 + 3e-08 0.03991654 0.01995827 0.01303514 0.02955703 - 3 - 3 - 0.04680188 - 0.001 + 3 + 3 + 0.04680188 + 0.001 0.8374751 - -1 - 0.5 - 1 + + + 1,1,3,4 + -1 + 0.5 + 1 + diff --git a/parameter_files/patch_default_e3smtest.xml b/parameter_files/patch_default_e3smtest.xml index 01111c2200..56dbb9b844 100644 --- a/parameter_files/patch_default_e3smtest.xml +++ b/parameter_files/patch_default_e3smtest.xml @@ -4,7 +4,7 @@ fates_params_e3smtest.cdl 1,2,3,4,5,6,7,8,9,10,11,12 - 0,0,0,0,0,0,0,0,0,0,0,0 - 0,0,0,0,0,0,0,0,0,0,0,0 + 0,0,0,0,0,0,0,0,0,0,0,0 + 0,0,0,0,0,0,0,0,0,0,0,0 diff --git a/parteh/PRTAllometricCNPMod.F90 b/parteh/PRTAllometricCNPMod.F90 index 5617d71e5d..ec29fff40a 100644 --- a/parteh/PRTAllometricCNPMod.F90 +++ b/parteh/PRTAllometricCNPMod.F90 @@ -18,14 +18,14 @@ module PRTAllometricCNPMod use PRTGenericMod , only : nitrogen_element use PRTGenericMod , only : phosphorus_element use PRTGenericMod , only : max_nleafage - + use PRTGenericMod , only : l2fr_min 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 : all_organs + use PRTGenericMod , only : num_organ_types use PRTGenericMod , only : prt_cnp_flex_allom_hyp use PRTGenericMod , only : StorageNutrientTarget @@ -46,6 +46,8 @@ module PRTAllometricCNPMod use FatesConstantsMod , only : i4 => fates_int 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 @@ -54,8 +56,21 @@ 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 FatesConstantsMod , only : leaves_on,leaves_off + use FatesConstantsMod , only : leaves_shedding + use EDParamsMod , only : p_uptake_mode + use EDParamsMod , only : n_uptake_mode + 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 @@ -67,8 +82,6 @@ module PRTAllometricCNPMod ! ! ------------------------------------------------------------------------------------- - - integer, parameter :: leaf_c_id = 1 ! leaf carbon index integer, parameter :: fnrt_c_id = 2 ! fine-root carbon index integer, parameter :: sapw_c_id = 3 ! sapwood carbon index @@ -92,14 +105,15 @@ module PRTAllometricCNPMod ! Total number of state variables integer, parameter :: num_vars = 18 - - + + ! Global identifiers for the two stoichiometry values integer,public, parameter :: stoich_growth_min = 1 ! Flag for stoichiometry associated with - ! minimum needed for growth + ! minimum needed for growth + + ! This is deprecated until a reasonable hypothesis is in place (RGK) integer,public, parameter :: stoich_max = 2 ! Flag for stoichiometry associated with - ! maximum for that organ - + ! maximum for that organ ! This is the ordered list of organs used in this module ! ------------------------------------------------------------------------------------- @@ -107,9 +121,11 @@ module PRTAllometricCNPMod integer, parameter :: num_organs = 6 ! Converting from local to global organ id - integer, parameter,dimension(num_organs) :: organ_list = & + integer, parameter,dimension(num_organs) :: l2g_organ_list = & [leaf_organ, fnrt_organ, sapw_organ, store_organ, repro_organ, struct_organ] + + ! These are local indices associated with organs and quantities ! that can be integrated (namely, growth respiration during stature growth ! and dbh) @@ -125,6 +141,7 @@ module PRTAllometricCNPMod integer, parameter :: num_intgr_vars = 7 + ! ------------------------------------------------------------------------------------- ! Input/Output Boundary Indices (These are public, and therefore ! each boundary condition across all modules must @@ -135,24 +152,31 @@ module PRTAllometricCNPMod integer, public, parameter :: acnp_bc_inout_id_dbh = 1 ! Plant DBH - integer, public, parameter :: acnp_bc_inout_id_rmaint_def = 2 ! Index for any accumulated - ! maintenance respiration deficit - integer, public, parameter :: num_bc_inout = 2 + integer, public, parameter :: acnp_bc_inout_id_resp_excess = 2 ! Respiration of excess storage + integer, public, parameter :: acnp_bc_inout_id_l2fr = 3 ! leaf 2 fineroot scalar, this + ! is dynamic with CNP + integer, public, parameter :: acnp_bc_inout_id_netdn = 4 ! Index for the net daily NH4 input BC + integer, public, parameter :: acnp_bc_inout_id_netdp = 5 ! Index for the net daily P input BC + integer, public, parameter :: acnp_bc_inout_id_cx_int = 6 ! Index for the EMA log storage ratio max(N,P)/C + integer, public, parameter :: acnp_bc_inout_id_cx0 = 7 ! Index for the previous step's log storage ratio max(N,P)/C + integer, public, parameter :: acnp_bc_inout_id_emadcxdt = 8 ! Index for the EMA log storage ratio derivative d max(NP)/C dt + integer, public, parameter :: num_bc_inout = 8 ! ------------------------------------------------------------------------------------- ! Input only Boundary Indices (These are public) ! ------------------------------------------------------------------------------------- - integer, public, parameter :: acnp_bc_in_id_pft = 1 ! Index for the PFT input BC - integer, public, parameter :: acnp_bc_in_id_ctrim = 2 ! Index for the canopy trim function - integer, public, parameter :: acnp_bc_in_id_lstat = 3 ! phenology status logical - integer, public, parameter :: acnp_bc_in_id_netdc = 4 ! Index for the net daily C input BC - integer, public, parameter :: acnp_bc_in_id_netdnh4 = 5 ! Index for the net daily NH4 input BC - integer, public, parameter :: acnp_bc_in_id_netdno3 = 6 ! Index for the net daily NO3 input BC - integer, public, parameter :: acnp_bc_in_id_netdp = 7 ! Index for the net daily P input BC - - ! 0=leaf off, 1=leaf on - integer, parameter :: num_bc_in = 7 + integer, public, parameter :: acnp_bc_in_id_pft = 1 ! Index for the PFT input BC + integer, public, parameter :: acnp_bc_in_id_ctrim = 2 ! Index for the canopy trim function + integer, public, parameter :: acnp_bc_in_id_lstat = 3 ! phenology status logical + integer, public, parameter :: acnp_bc_in_id_netdc = 4 ! Index for the net daily C input BC + integer, public, parameter :: acnp_bc_in_id_nc_repro = 5 + integer, public, parameter :: acnp_bc_in_id_pc_repro = 6 + integer, public, parameter :: acnp_bc_in_id_cdamage = 7 ! Index for the crowndamage input BC + integer, public, parameter :: acnp_bc_in_id_efleaf = 8 ! Leaf elongation factor + integer, public, parameter :: acnp_bc_in_id_effnrt = 9 ! Fine-root "elongation factor" + integer, public, parameter :: acnp_bc_in_id_efstem = 10 ! Stem "elongation factor" + integer, parameter :: num_bc_in = 10 ! ------------------------------------------------------------------------------------- ! Output Boundary Indices (These are public) @@ -161,48 +185,67 @@ module PRTAllometricCNPMod integer, public, parameter :: acnp_bc_out_id_cefflux = 1 ! Daily exudation of C [kg] integer, public, parameter :: acnp_bc_out_id_nefflux = 2 ! Daily exudation of N [kg] integer, public, parameter :: acnp_bc_out_id_pefflux = 3 ! Daily exudation of P [kg] - integer, public, parameter :: acnp_bc_out_id_nneed = 4 ! N need [kgN] - integer, public, parameter :: acnp_bc_out_id_pneed = 5 ! P need [kgP] + integer, public, parameter :: acnp_bc_out_id_limiter = 4 ! The minimum of the Nutrient ratio over c ratio - integer, parameter :: num_bc_out = 5 ! Total number of - - - + integer, parameter :: num_bc_out = 4 ! Total number of + + + ! Indices for parameters passed to the integrator + integer,private, parameter :: intgr_parm_ctrim = 1 + integer,private, parameter :: intgr_parm_pft = 2 + integer,private, parameter :: intgr_parm_l2fr = 3 + integer,private, parameter :: intgr_parm_cdamage = 4 + integer,private, parameter :: intgr_parm_efleaf = 5 + integer,private, parameter :: intgr_parm_effnrt = 6 + integer,private, parameter :: intgr_parm_efstem = 7 + integer,private, parameter :: num_intgr_parm = 7 ! ------------------------------------------------------------------------------------- ! Define the size of the coorindate vector. For this hypothesis, there is only ! one pool per each species x organ combination, except for leaves (WHICH HAVE AGE) + ! icd refers to the first index in the leaf array, which is the youngest. Growth + ! and allocation only happens in the youngest bin by definition ! ------------------------------------------------------------------------------------- integer, parameter :: icd = 1 - - real(r8), parameter :: store_overflow_frac = 0.15 ! The fraction above target allowed in storage - - - ! User may want to attempt matching results with the - ! C-only allocation module. If so, then set reproduce_conly - ! and make sure both fnrt and leaf are set to the highest - ! priority order, sapwood and storage are set to the - ! second highest, and then structure is last. When this is - ! flagged as true, it changes the logic in the first allocation - ! phase, to give first dibs to leaves, even though they are - ! in the same priority group as fineroots. - - logical, parameter :: reproduce_conly = .false. + ! These constants define different methods of dealing with excess carbon at + ! the end of the allocation process, assuming that N or P is limiting growth. + ! You can either exude (send to soil), retain (grow storage without limit), + ! or burn (as respiration to the atm). + integer, parameter :: exude_c_store_overflow = 1 + integer, parameter :: retain_c_store_overflow = 2 + integer, parameter :: burn_c_store_overflow = 3 + integer, parameter :: store_c_overflow = burn_c_store_overflow + + ! These constants define if/how growth is limited by + ! one of the 3 chemical species, 0 indicates there is some + ! degree of co limitation + integer, parameter :: cnp_limited = 0 + integer, parameter :: c_limited = 1 + integer, parameter :: n_limited = 2 + integer, parameter :: p_limited = 3 + + ! Flags to select using the equivalent carbon method of co-limitation, + ! or to just grow with available carbon and let it fix itself on the + ! next step - - ! Array of pointers are difficult in F90 - ! This structure is a necessary intermediate - type :: parray_type - real(r8), pointer :: ptr - end type parray_type + integer, parameter :: grow_lim_conly = 1 ! Just use C to decide stature on this step + integer, parameter :: grow_lim_estNP = 2 ! Estimate equivalent C from N and P + integer, parameter :: grow_lim_type = grow_lim_estNP + + ! Following growth, if desired, you can prioritize that + ! reproductive tissues get balanced CNP + logical, parameter :: prioritize_repro_nutr_growth = .true. + + ! If this parameter is true, then the fine-root l2fr optimization + ! scheme will remove biomass from roots without restriction if the + ! l2fr is getting smaller. + logical, parameter :: use_unrestricted_contraction = .true. ! ------------------------------------------------------------------------------------- ! This is the core type that holds this specific ! plant reactive transport (PRT) module ! ------------------------------------------------------------------------------------- - - type, public, extends(prt_vartypes) :: cnp_allom_prt_vartypes contains @@ -214,10 +257,11 @@ module PRTAllometricCNPMod ! Extended functions specific to Allometric CNP procedure :: CNPPrioritizedReplacement procedure :: CNPStatureGrowth + procedure :: EstimateGrowthNC + procedure :: CNPAdjustFRootTargets procedure :: CNPAllocateRemainder procedure :: GetDeficit - procedure :: GrowEquivC - procedure :: NAndPToMatchC + procedure :: TrimFineRoot end type cnp_allom_prt_vartypes @@ -255,10 +299,14 @@ subroutine InitPRTGlobalAllometricCNP() ! ----------------------------------------------------------------------------------- integer :: nleafage + integer :: istat + character(len=255) :: smsg - allocate(prt_global_acnp) - allocate(prt_global_acnp%state_descriptor(num_vars)) - + allocate(prt_global_acnp, stat=istat, errmsg=smsg) + if (istat/=0) call endrun(msg='allocate stat/=0:'//trim(smsg)//errMsg(sourcefile, __LINE__)) + allocate(prt_global_acnp%state_descriptor(num_vars), stat=istat, errmsg=smsg) + if (istat/=0) call endrun(msg='allocate stat/=0:'//trim(smsg)//errMsg(sourcefile, __LINE__)) + prt_global_acnp%hyp_name = 'Allometric Flexible C+N+P' prt_global_acnp%hyp_id = prt_cnp_flex_allom_hyp @@ -280,8 +328,6 @@ subroutine InitPRTGlobalAllometricCNP() call endrun(msg=errMsg(sourcefile, __LINE__)) end if - - call prt_global_acnp%RegisterVarInGlobal(leaf_c_id,'Leaf Carbon','leaf_c',leaf_organ,carbon12_element,nleafage) call prt_global_acnp%RegisterVarInGlobal(fnrt_c_id,'Fine Root Carbon','fnrt_c',fnrt_organ,carbon12_element,icd) call prt_global_acnp%RegisterVarInGlobal(sapw_c_id,'Sapwood Carbon','sapw_c',sapw_organ,carbon12_element,icd) @@ -320,51 +366,49 @@ end subroutine InitPRTGlobalAllometricCNP ! ===================================================================================== - subroutine DailyPRTAllometricCNP(this) + subroutine DailyPRTAllometricCNP(this,phase) class(cnp_allom_prt_vartypes) :: this + integer,intent(in) :: phase ! the phase splits the routine into parts + ! note that phasing is used primarily to + ! accomodate the damage module. Damage + ! and nutrient cycling are not yet compatable though + ! hence, we simply return from any phase but phase 1 + ! Pointers to in-out bcs real(r8),pointer :: dbh ! Diameter at breast height [cm] - real(r8),pointer :: maint_r_def ! Current maintenance respiration deficit [kgC] + real(r8),pointer :: resp_excess ! Respiration of any un-allocatable C + real(r8),pointer :: l2fr ! Leaf to fineroot ratio of target biomass ! Input only bcs - integer :: ipft ! Plant Functional Type index - real(r8) :: c_gain ! Daily carbon balance for this cohort [kgC] - real(r8) :: n_gain ! Daily nitrogen uptake through fine-roots [kgN] - real(r8) :: p_gain ! Daily phosphorus uptake through fine-roots [kgN] - real(r8) :: canopy_trim ! The canopy trimming function [0-1] - + integer :: ipft ! Plant Functional Type index + real(r8) :: c_gain ! Daily carbon balance for this cohort [kgC] + real(r8),pointer :: n_gain ! Daily nitrogen uptake through fine-roots [kgN] + real(r8),pointer :: p_gain ! Daily phosphorus uptake through fine-roots [kgN] + real(r8) :: canopy_trim ! The canopy trimming function [0-1] + integer :: crown_damage ! which crown damage clas + real(r8) :: elongf_leaf ! Leaf elongation factor [0-1] + real(r8) :: elongf_fnrt ! Fine-root "elongation factor" [0-1] + real(r8) :: elongf_stem ! Stem "elongation factor" [0-1] + ! Pointers to output bcs real(r8),pointer :: c_efflux ! Total plant efflux of carbon (kgC) real(r8),pointer :: n_efflux ! Total plant efflux of nitrogen (kgN) real(r8),pointer :: p_efflux ! Total plant efflux of phosphorus (kgP) - real(r8),pointer :: n_need ! N need (algorithm dependant) (kgN) - real(r8),pointer :: p_need ! P need (algorithm dependant) (kgP) - real(r8),pointer :: growth_r ! Total plant growth respiration this step (kgC) - - ! These are pointers to the state variables, rearranged in organ dimensioned - ! arrays. This is useful because we loop through organs so often - type(parray_type),pointer :: state_c(:) ! State array for carbon, by organ [kg] - type(parray_type),pointer :: state_n(:) ! State array for N, by organ [kg] - type(parray_type),pointer :: state_p(:) ! State array for P, by organ [kg] - integer :: i_org ! organ index - integer :: i_var ! variable index - - ! Agruments for allometry functions, that are not in the target_c array + ! Allometry targets (kg/plant) and (kg/cm/plant) + real(r8), dimension(num_organ_types) :: target_c, target_dcdd + ! Initial states (for accounting) (kg/plant) + real(r8), dimension(num_organ_types) :: state_c0, state_n0, state_p0 + ! Allometry partial targets real(r8) :: agw_c_target,agw_dcdd_target real(r8) :: bgw_c_target,bgw_dcdd_target real(r8) :: sapw_area - integer :: cnp_limiter - real(r8) :: max_store_n - ! These arrays hold various support variables dimensioned by organ - ! Zero suffix indicates the initial state values at the beginning of the routine - ! _unl suffix indicates values used for tracking nutrient need (ie unlimited) - ! target is the target masses associated with the plant stature, and - ! also the derivative of c wrt diameter at current diameter - real(r8), dimension(num_organs) :: target_c, target_dcdd - real(r8), dimension(num_organs) :: state_c0, state_n0, state_p0 + real(r8) :: store_flux + integer :: i ! generic organ loop index + integer :: i_org ! organ index + integer :: i_var ! variable index ! These are daily mass gains, frozen in time, not drawn from, and thus ! these are only used for evaluating mass balancing at the end @@ -372,16 +416,38 @@ subroutine DailyPRTAllometricCNP(this) real(r8) :: c_gain0 real(r8) :: n_gain0 real(r8) :: p_gain0 - real(r8) :: maint_r_def0 + real(r8) :: resp_excess0 ! Used for mass checking, total mass allocated based ! on change in the states, should match gain0's real(r8) :: allocated_c real(r8) :: allocated_n real(r8) :: allocated_p - real(r8) :: target_n,target_p real(r8) :: sum_c ! error checking sum + + ! Phasing is only used to accomodate the + ! damage module. Since this is incompatible with CNP + ! Ignore all subsequent calls after the first + if (phase.ne.1) return + + + ! In/out boundary conditions + resp_excess => this%bc_inout(acnp_bc_inout_id_resp_excess)%rval + dbh => this%bc_inout(acnp_bc_inout_id_dbh)%rval + dbh0 = dbh + l2fr => this%bc_inout(acnp_bc_inout_id_l2fr)%rval + n_gain => this%bc_inout(acnp_bc_inout_id_netdn)%rval + p_gain => this%bc_inout(acnp_bc_inout_id_netdp)%rval + + + ! Assume that there is no other source of excess respiration + ! so it is safe to zero it. In the third stage we will + ! decide if this should be updated + resp_excess = 0._r8 + resp_excess0 = resp_excess + + ! integrator variables ! Copy the input only boundary conditions into readable local variables @@ -389,136 +455,137 @@ subroutine DailyPRTAllometricCNP(this) ! Also, we save the initial values of many of these BC's ! for checking and resetting if needed ! ----------------------------------------------------------------------------------- - c_gain = this%bc_in(acnp_bc_in_id_netdc)%rval; c_gain0 = c_gain - n_gain = this%bc_in(acnp_bc_in_id_netdnh4)%rval + & - this%bc_in(acnp_bc_in_id_netdno3)%rval - n_gain0 = n_gain - p_gain = this%bc_in(acnp_bc_in_id_netdp)%rval; p_gain0 = p_gain + c_gain = this%bc_in(acnp_bc_in_id_netdc)%rval canopy_trim = this%bc_in(acnp_bc_in_id_ctrim)%rval ipft = this%bc_in(acnp_bc_in_id_pft)%ival + crown_damage = this%bc_in(acnp_bc_in_id_cdamage)%ival + elongf_leaf = this%bc_in(acnp_bc_in_id_efleaf)%rval + elongf_fnrt = this%bc_in(acnp_bc_in_id_effnrt)%rval + elongf_stem = this%bc_in(acnp_bc_in_id_efstem)%rval + + ! If either n or p uptake is in prescribed mode + ! set the gains to something massive. 1 kilo of pure + ! nutrient should be wayyy more than enough + if(n_uptake_mode.eq.prescribed_n_uptake) then + n_gain = 1.e3_r8 + end if + if(p_uptake_mode.eq.prescribed_p_uptake) then + p_gain = 1.e3_r8 + end if + + n_gain0 = n_gain + p_gain0 = p_gain + c_gain0 = c_gain - ! Output only boundary conditions - c_efflux => this%bc_out(acnp_bc_out_id_cefflux)%rval; c_efflux = 0._r8 - n_efflux => this%bc_out(acnp_bc_out_id_nefflux)%rval; n_efflux = 0._r8 - p_efflux => this%bc_out(acnp_bc_out_id_pefflux)%rval; p_efflux = 0._r8 - n_need => this%bc_out(acnp_bc_out_id_nneed)%rval; n_need = fates_unset_r8 - p_need => this%bc_out(acnp_bc_out_id_pneed)%rval; p_need = fates_unset_r8 - - ! In/out boundary conditions - maint_r_def => this%bc_inout(acnp_bc_inout_id_rmaint_def)%rval; maint_r_def0 = maint_r_def - dbh => this%bc_inout(acnp_bc_inout_id_dbh)%rval; dbh0 = dbh - - - - ! If more than 1 leaf age bin is present, this - ! call advances leaves in their age, but does - ! not actually remove any biomass from the plant - - call this%AgeLeaves(ipft,sec_per_day) + ! Calculate Carbon allocation targets + ! ----------------------------------------------------------------------------------- - - ! Set all of the per-organ pointer arrays - ! Note: Since growth only happens in the 1st leaf bin, we only - ! point to that bin. However, we need to account for all bins - ! when we calculate the deficit - - allocate(state_c(num_organs)) - allocate(state_n(num_organs)) - allocate(state_p(num_organs)) - ! Set carbon targets based on the plant's current stature target_c(:) = fates_unset_r8 target_dcdd(:) = fates_unset_r8 - call bsap_allom(dbh,ipft,canopy_trim,sapw_area,target_c(sapw_id),target_dcdd(sapw_id) ) - call bagw_allom(dbh,ipft,agw_c_target,agw_dcdd_target) - call bbgw_allom(dbh,ipft,bgw_c_target,bgw_dcdd_target) - call bdead_allom(agw_c_target,bgw_c_target, target_c(sapw_id), ipft, target_c(struct_id), & - agw_dcdd_target, bgw_dcdd_target, target_dcdd(sapw_id), target_dcdd(struct_id)) - call bleaf(dbh,ipft,canopy_trim, target_c(leaf_id), target_dcdd(leaf_id)) - call bfineroot(dbh,ipft,canopy_trim, target_c(fnrt_id), target_dcdd(fnrt_id)) - call bstore_allom(dbh,ipft,canopy_trim, target_c(store_id), target_dcdd(store_id)) - target_c(repro_id) = 0._r8 - target_dcdd(repro_id) = 0._r8 - - ! Initialize the the state, and keep a record of this state - ! as we may actuall run the allocation process twice, and - ! will need this state to both reset, and measure total - ! mass fluxes - do i_org = 1,num_organs - - i_var = prt_global%sp_organ_map(organ_list(i_org),carbon12_element) - state_c(i_org)%ptr => this%variables(i_var)%val(1) - state_c0(i_org) = this%variables(i_var)%val(1) + call bsap_allom(dbh,ipft,crown_damage,canopy_trim,elongf_stem,sapw_area,target_c(sapw_organ),target_dcdd(sapw_organ)) + call bagw_allom(dbh,ipft,crown_damage,elongf_stem,agw_c_target,agw_dcdd_target) + call bbgw_allom(dbh,ipft,elongf_stem,bgw_c_target,bgw_dcdd_target) + call bdead_allom(agw_c_target,bgw_c_target,target_c(sapw_organ),ipft,target_c(struct_organ), & + agw_dcdd_target,bgw_dcdd_target,target_dcdd(sapw_organ),target_dcdd(struct_organ)) + call bleaf(dbh,ipft,crown_damage,canopy_trim, elongf_leaf, target_c(leaf_organ), target_dcdd(leaf_organ)) + call bfineroot(dbh,ipft,canopy_trim, l2fr, elongf_fnrt, target_c(fnrt_organ), target_dcdd(fnrt_organ)) + call bstore_allom(dbh,ipft,crown_damage, canopy_trim, target_c(store_organ), target_dcdd(store_organ)) + target_c(repro_organ) = 0._r8 + target_dcdd(repro_organ) = 0._r8 - i_var = prt_global%sp_organ_map(organ_list(i_org),nitrogen_element) - state_n(i_org)%ptr => this%variables(i_var)%val(1) - state_n0(i_org) = this%variables(i_var)%val(1) + ! =================================================================================== + ! Step 1: Evaluate nutrient storage in the plant. Depending on how low + ! these stores are, we will move proportionally more or less of the daily carbon + ! gain to increase the target fine-root biomass, fill up to target + ! and then attempt to get them up to stoichiometry targets. + ! =================================================================================== - i_var = prt_global%sp_organ_map(organ_list(i_org),phosphorus_element) - state_p(i_org)%ptr => this%variables(i_var)%val(1) + + + ! Remember the original C,N,P states to help with final + ! evaluation of how much was allocated + ! ----------------------------------------------------------------------------------- + + do i = 1,num_organs + i_org = l2g_organ_list(i) ! global index from PRTGeneric + i_var = prt_global%sp_organ_map(i_org,carbon12_element) + state_c0(i_org) = this%variables(i_var)%val(1) + i_var = prt_global%sp_organ_map(i_org,nitrogen_element) + state_n0(i_org) = this%variables(i_var)%val(1) + i_var = prt_global%sp_organ_map(i_org,phosphorus_element) state_p0(i_org) = this%variables(i_var)%val(1) - end do + + + ! Output only boundary conditions + c_efflux => this%bc_out(acnp_bc_out_id_cefflux)%rval; c_efflux = 0._r8 + n_efflux => this%bc_out(acnp_bc_out_id_nefflux)%rval; n_efflux = 0._r8 + p_efflux => this%bc_out(acnp_bc_out_id_pefflux)%rval; p_efflux = 0._r8 ! =================================================================================== - ! Step 0. Transfer all stored nutrient into the daily uptake pool. - ! Storage in nutrients does not need to have a buffer like - ! carbon does, so we simply use it when we want it, and then - ! anything left at the end is added back (CNPAllocateRemainder()) + ! Step 0. Transfer all stored nutrient into the daily uptake pool. Also + ! transfer C storage that is above the target (ie transfer overflow) ! =================================================================================== - i_var = prt_global%sp_organ_map(store_organ,nitrogen_element) - n_gain = n_gain + sum(this%variables(i_var)%val(:)) - this%variables(i_var)%val(:) = 0._r8 + ! Put overflow storage into the net daily pool + store_flux = max(0._r8, this%variables(store_c_id)%val(1) - target_c(store_organ)) + c_gain = c_gain + store_flux + this%variables(store_c_id)%val(1) = this%variables(store_c_id)%val(1) - store_flux + + n_gain = n_gain + sum(this%variables(store_n_id)%val(:)) + this%variables(store_n_id)%val(:) = 0._r8 - i_var = prt_global%sp_organ_map(store_organ,phosphorus_element) - p_gain = p_gain + sum(this%variables(i_var)%val(:)) - this%variables(i_var)%val(:) = 0._r8 + p_gain = p_gain + sum(this%variables(store_p_id)%val(:)) + this%variables(store_p_id)%val(:) = 0._r8 + ! =================================================================================== - ! Step 1. Prioritized allocation to replace tissues from turnover, and/or pay + ! Step 2. Prioritized allocation to replace tissues from turnover, and/or pay ! any un-paid maintenance respiration from storage. ! =================================================================================== - call this%CNPPrioritizedReplacement(maint_r_def, c_gain, n_gain, p_gain, & - state_c, state_n, state_p, target_c) - + call this%CNPPrioritizedReplacement(c_gain, n_gain, p_gain, target_c) + sum_c = 0._r8 - do i_org = 1,num_organs - sum_c = sum_c+state_c(i_org)%ptr + do i = 1,num_organs + i_org = l2g_organ_list(i) + i_var = prt_global%sp_organ_map(i_org,carbon12_element) + sum_c = sum_c+this%variables(i_var)%val(1) end do if( abs((c_gain0-c_gain) - & - (sum_c-sum(state_c0(:),dim=1)+(maint_r_def0-maint_r_def))) >calloc_abs_error ) then + (sum_c-sum(state_c0(:),dim=1))) >calloc_abs_error ) then write(fates_log(),*) 'Carbon not balancing I' - do i_org = 1,num_organs - write(fates_log(),*) 'state_c: ',state_c(i_org)%ptr,state_c0(i_org) + do i = 1,num_organs + i_org = l2g_organ_list(i) + write(fates_log(),*) 'c: ',this%variables(prt_global%sp_organ_map(i_org,carbon12_element))%val(1) end do - write(fates_log(),*) maint_r_def0-maint_r_def call endrun(msg=errMsg(sourcefile, __LINE__)) end if ! =================================================================================== - ! Step 2. Grow out the stature of the plant by allocating to tissues beyond + ! Step 3. Grow out the stature of the plant by allocating to tissues beyond ! current targets. ! Attempts have been made to get all pools and species closest to allometric ! targets based on prioritized relative demand and allometry functions. ! =================================================================================== - - call this%CNPStatureGrowth(c_gain, n_gain, p_gain, & - state_c, state_n, state_p, target_c, target_dcdd, cnp_limiter) - + + call this%CNPStatureGrowth(c_gain, n_gain, p_gain, target_c, target_dcdd) + sum_c = 0._r8 - do i_org = 1,num_organs - sum_c = sum_c+state_c(i_org)%ptr + do i = 1,num_organs + i_org = l2g_organ_list(i) + i_var = prt_global%sp_organ_map(i_org,carbon12_element) + sum_c = sum_c+this%variables(i_var)%val(1) end do if( abs((c_gain0-c_gain) - & - (sum_c-sum(state_c0(:),dim=1)+(maint_r_def0-maint_r_def))) >calloc_abs_error ) then - write(fates_log(),*) 'Carbon not balanceing II' - do i_org = 1,num_organs - write(fates_log(),*) 'state_c: ',state_c(i_org)%ptr,state_c0(i_org) + (sum_c-sum(state_c0(:),dim=1))) >calloc_abs_error ) then + write(fates_log(),*) 'Carbon not balancing II' + do i = 1,num_organs + i_org = l2g_organ_list(i) + write(fates_log(),*) 'c: ',this%variables(prt_global%sp_organ_map(i_org,carbon12_element))%val(1) end do - write(fates_log(),*) maint_r_def0-maint_r_def call endrun(msg=errMsg(sourcefile, __LINE__)) end if @@ -527,52 +594,66 @@ subroutine DailyPRTAllometricCNP(this) ! At this point, at least 1 of the 3 resources have been used up. ! Allocate the remaining resources, or as a last resort, efflux them. ! =================================================================================== - - call this%CNPAllocateRemainder(c_gain, n_gain, p_gain, & - state_c, state_n, state_p, c_efflux, n_efflux, p_efflux) - ! Error Check: Make sure that the mass gains are completely used up - if( abs(c_gain) > calloc_abs_error .or. & - abs(n_gain) > 0.1_r8*calloc_abs_error .or. & - abs(p_gain) > 0.02_r8*calloc_abs_error ) then + call this%CNPAllocateRemainder(c_gain, n_gain, p_gain, & + c_efflux, n_efflux, p_efflux,target_c,target_dcdd) + + + if(n_uptake_mode.ne.prescribed_n_uptake) then + if( abs(n_gain) > 0.1_r8*calloc_abs_error) then + write(fates_log(),*) 'Allocation scheme should had used up all mass gain pools' + write(fates_log(),*) 'Any mass that cannot be allocated should be effluxed' + write(fates_log(),*) 'n_gain: ',n_gain + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + end if + + if(p_uptake_mode.ne.prescribed_p_uptake) then + if( abs(p_gain) > 0.01_r8*calloc_abs_error) then + write(fates_log(),*) 'Allocation scheme should had used up all mass gain pools' + write(fates_log(),*) 'Any mass that cannot be allocated should be effluxed' + write(fates_log(),*) 'p_gain: ',p_gain + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + end if + + if( abs(c_gain) > calloc_abs_error) then write(fates_log(),*) 'Allocation scheme should had used up all mass gain pools' write(fates_log(),*) 'Any mass that cannot be allocated should be effluxed' write(fates_log(),*) 'c_gain: ',c_gain - write(fates_log(),*) 'n_gain: ',n_gain - write(fates_log(),*) 'p_gain: ',p_gain call endrun(msg=errMsg(sourcefile, __LINE__)) end if - ! Perform a final tally on what was used (allocated) ! Since this is also a check against what was available - ! we include maintenance pay-back and efflux to the "allocated" - ! pool to make sure everything balances. + ! we include what is lost through respiration of excess storage - allocated_c = (maint_r_def0-maint_r_def) + c_efflux + allocated_c = (resp_excess-resp_excess0) + c_efflux allocated_n = n_efflux allocated_p = p_efflux ! Update the allocation flux diagnostic arrays for each 3 elements - do i_org = 1,num_organs - - i_var = prt_global%sp_organ_map(organ_list(i_org),carbon12_element) + do i = 1,num_organs + + i_org = l2g_organ_list(i) + + i_var = prt_global%sp_organ_map(i_org,carbon12_element) this%variables(i_var)%net_alloc(1) = & - this%variables(i_var)%net_alloc(1) + (state_c(i_org)%ptr - state_c0(i_org)) + this%variables(i_var)%net_alloc(1) + (this%variables(i_var)%val(1) - state_c0(i_org)) - allocated_c = allocated_c + (state_c(i_org)%ptr - state_c0(i_org)) + allocated_c = allocated_c + (this%variables(i_var)%val(1) - state_c0(i_org)) - i_var = prt_global%sp_organ_map(organ_list(i_org),nitrogen_element) + i_var = prt_global%sp_organ_map(i_org,nitrogen_element) this%variables(i_var)%net_alloc(1) = & - this%variables(i_var)%net_alloc(1) + (state_n(i_org)%ptr - state_n0(i_org)) + this%variables(i_var)%net_alloc(1) + (this%variables(i_var)%val(1) - state_n0(i_org)) - allocated_n = allocated_n + (state_n(i_org)%ptr - state_n0(i_org)) + allocated_n = allocated_n + (this%variables(i_var)%val(1) - state_n0(i_org)) - i_var = prt_global%sp_organ_map(organ_list(i_org),phosphorus_element) + i_var = prt_global%sp_organ_map(i_org,phosphorus_element) this%variables(i_var)%net_alloc(1) = & - this%variables(i_var)%net_alloc(1) + (state_p(i_org)%ptr - state_p0(i_org)) + this%variables(i_var)%net_alloc(1) + (this%variables(i_var)%val(1) - state_p0(i_org)) - allocated_p = allocated_p + (state_p(i_org)%ptr - state_p0(i_org)) + allocated_p = allocated_p + (this%variables(i_var)%val(1) - state_p0(i_org)) end do @@ -581,41 +662,285 @@ subroutine DailyPRTAllometricCNP(this) ! Error Check: Do a final balance between how much mass ! we had to work with, and how much was allocated - if ( abs(allocated_c - c_gain0) > calloc_abs_error .or. & - abs(allocated_n - n_gain0) > calloc_abs_error .or. & - abs(allocated_p - p_gain0) > calloc_abs_error ) then + if ( abs(allocated_c - (c_gain0-c_gain)) > calloc_abs_error .or. & + abs(allocated_n - (n_gain0-n_gain)) > calloc_abs_error .or. & + abs(allocated_p - (p_gain0-p_gain)) > calloc_abs_error ) then write(fates_log(),*) 'CNP allocation scheme did not balance mass.' - write(fates_log(),*) 'c_gain0: ',c_gain0,' allocated_c: ',allocated_c + write(fates_log(),*) 'c_gain0: ',c_gain0,' allocated_c: ',allocated_c,resp_excess,resp_excess0,c_efflux write(fates_log(),*) 'n_gain0: ',n_gain0,' allocated_n: ',allocated_n write(fates_log(),*) 'p_gain0: ',p_gain0,' allocated_p: ',allocated_p - do i_org = 1,num_organs - write(fates_log(),*) i_org, state_c(i_org)%ptr-state_c0(i_org) + do i = 1,num_organs + i_org = l2g_organ_list(i) + i_var = prt_global%sp_organ_map(i_org,carbon12_element) + write(fates_log(),*) i_org, this%variables(i_var)%val(1)-state_c0(i_org) end do - write(fates_log(),*) (maint_r_def0-maint_r_def), c_efflux call endrun(msg=errMsg(sourcefile, __LINE__)) end if end if - target_n = this%GetNutrientTarget(nitrogen_element,store_organ) - target_p = this%GetNutrientTarget(phosphorus_element,store_organ) - - n_need = target_n - state_n(store_id)%ptr - p_need = target_p - state_p(store_id)%ptr - - deallocate(state_c) - deallocate(state_n) - deallocate(state_p) + ! IF this was prescribed, then we dictate the uptake + ! and pass that back as an output, otherwise + ! we set the gains to what we started with so that + ! it can be used again for mass balance checking and diagnostics + if(n_uptake_mode.eq.prescribed_n_uptake) then + n_gain = n_gain0-n_gain + else + n_gain = n_gain0 + end if + if(p_uptake_mode.eq.prescribed_p_uptake) then + p_gain = p_gain0-p_gain + else + p_gain = p_gain0 + end if + + + + ! If fine-roots are allocated above their + ! target (perhaps with some buffer, but perhaps not) + ! then + call this%TrimFineRoot() + return end subroutine DailyPRTAllometricCNP + + function SafeLog(val) result(logval) + + ! The log functions used to transform storage ratios + ! need not be large. Even a ratio of 10 is sending a strong signal to the + ! root adaptation algorithm to change course pretty strongly. We set + ! bounds of e3 here to prevent numerical overflows and underflows + + real(r8) :: val + real(r8) :: logval + real(r8), parameter :: safelog_min = 0.001_r8 !Don't pass anything smaller to a log + real(r8), parameter :: safelog_max = 1000._r8 + + logval = log(max(safelog_min,min(safelog_max,val))) + + end function SafeLog + + ! ===================================================================================== - subroutine CNPPrioritizedReplacement(this, & - maint_r_deficit, c_gain, n_gain, p_gain, & - state_c, state_n, state_p, target_c) + subroutine CNPAdjustFRootTargets(this, target_c, target_dcdd) + + class(cnp_allom_prt_vartypes) :: this + real(r8) :: target_c(:) + real(r8) :: target_dcdd(:) + + real(r8), pointer :: l2fr ! leaf to fineroot target biomass scaler + integer :: ipft ! PFT index + real(r8), pointer :: dbh + real(r8) :: canopy_trim + integer :: leaf_status + integer, pointer :: limiter + real(r8) :: elongf_fnrt + real(r8) :: store_c_max, store_c_act + real(r8) :: store_nut_max, store_nut_act + real(r8) :: l2fr_delta + real(r8) :: cn_ratio, cp_ratio ! ratio of relative C storage over relative N or P storage + real(r8) :: dcxdt_ratio ! log change (derivative) of the maximum of the N/C and P/C storage ratio + real(r8) :: cx_logratio ! log Maximum of the C/N and C/P storage ratio + real(r8), pointer :: cx_int ! Integration of the cx_logratio + real(r8), pointer :: cx0 ! The log of the cx ratio from previous time-step + real(r8), pointer :: ema_dcxdt ! the EMA of the change in log storage ratio + + real(r8), parameter :: pid_drv_wgt = 1._r8/20._r8 ! n-day smoothing of the derivative + ! of the process function in the PID controller + + leaf_status = this%bc_in(acnp_bc_in_id_lstat)%ival + ipft = this%bc_in(acnp_bc_in_id_pft)%ival + elongf_fnrt = this%bc_in(acnp_bc_in_id_effnrt)%rval + l2fr => this%bc_inout(acnp_bc_inout_id_l2fr)%rval + dbh => this%bc_inout(acnp_bc_inout_id_dbh)%rval + canopy_trim = this%bc_in(acnp_bc_in_id_ctrim)%rval + cx_int => this%bc_inout(acnp_bc_inout_id_cx_int)%rval + cx0 => this%bc_inout(acnp_bc_inout_id_cx0)%rval + ema_dcxdt => this%bc_inout(acnp_bc_inout_id_emadcxdt)%rval + limiter => this%bc_out(acnp_bc_out_id_limiter)%ival + ! Abort if leaves are off + if(leaf_status.eq.leaves_off) return + + + ! Step 1: Determine the process function for the controller. Generally, this is + ! some indicator about the relative health of the plant in terms of carbon versus + ! nutrient. There are a few ways to cast this function, but right now we are using + ! the relative amount of Carbon storage (actual/maximum) divided by the relative amount + ! of nutrient (actual/maximum). We take the natural log of this ratio. And then we take + ! maximum of the two quotients that use nitrogen and phosphorus. + ! ----------------------------------------------------------------------------------- + + store_c_max = target_c(store_organ) + + store_c_act = max(0.001_r8*store_c_max,this%GetState(store_organ, carbon12_element) + & + this%bc_in(acnp_bc_in_id_netdc)%rval) + + if(n_uptake_mode.eq.prescribed_n_uptake)then + cn_ratio = -1._r8 + else + + ! Calculate the relative nitrogen storage fraction, + ! over the relative carbon storage fraction. + + store_nut_max = this%GetNutrientTarget(nitrogen_element,store_organ,stoich_growth_min) + + store_nut_act = max(0.001_r8*store_nut_max, & + this%GetState(store_organ, nitrogen_element) + & + this%bc_inout(acnp_bc_inout_id_netdn)%rval) + + cn_ratio = (store_c_act/store_c_max)/(store_nut_act/store_nut_max) + + end if + + if(p_uptake_mode.eq.prescribed_p_uptake)then + cp_ratio = -1._r8 + else + + ! Calculate the relative phosphorus storage fraction, + ! over the relative carbon storage fraction. + + store_nut_max = this%GetNutrientTarget(phosphorus_element,store_organ,stoich_growth_min) + + store_nut_act = max(0.001_r8*store_nut_max, & + this%GetState(store_organ, phosphorus_element) + & + this%bc_inout(acnp_bc_inout_id_netdp)%rval) + + cp_ratio = (store_c_act/store_c_max)/(store_nut_act/store_nut_max) + + end if + + ! Use the limiting nutrient species + if( (n_uptake_mode.eq.prescribed_n_uptake) .and. & + (p_uptake_mode.eq.prescribed_p_uptake) )then + cx_int = 0._r8 + ema_dcxdt = 0._r8 + cx0 = 0.0_r8 + return + else + if (n_uptake_mode.eq.prescribed_n_uptake) then + cx_logratio = SafeLog(cp_ratio) + elseif (p_uptake_mode.eq.prescribed_p_uptake) then + cx_logratio = SafeLog(cn_ratio) + else + cx_logratio = SafeLog(max(cp_ratio,cn_ratio)) + end if + + ! If cx_logratio has just crossed zero, then + ! reset the integrator. This will be true if + ! the sign of the current ratio is different than + ! the sign of the previous + + cx_int = cx_int + cx_logratio + + ! Reset the integrator if its sign changes + if( abs(cx_logratio)>nearzero .and. abs(cx0)>nearzero) then + if( abs(cx_logratio/abs(cx_logratio) - cx0/abs(cx0)) > nearzero ) then + cx_int = cx_logratio + end if + end if + + dcxdt_ratio = cx_logratio-cx0 + + ema_dcxdt = pid_drv_wgt*dcxdt_ratio + (1._r8-pid_drv_wgt)*ema_dcxdt + + cx0 = cx_logratio + + + end if + + l2fr_delta = prt_params%pid_kp(ipft)*cx_logratio + & + prt_params%pid_ki(ipft)*cx_int + & + prt_params%pid_kd(ipft)*ema_dcxdt + + ! Apply the delta, also, avoid generating incredibly small l2fr's, + ! super small l2frs will occur in plants that perpetually get almost + ! now carbon gain, such as newly recruited plants in a dark understory + + l2fr = max(l2fr_min, l2fr + l2fr_delta) + + ! Find the updated target fineroot biomass + call bfineroot(dbh,ipft,canopy_trim, l2fr, elongf_fnrt, target_c(fnrt_organ),target_dcdd(fnrt_organ)) + + return + end subroutine CNPAdjustFRootTargets + + ! ===================================================================================== + + subroutine TrimFineRoot(this) + + ! The following section allows forceful turnover of fine-roots if a new L2FR is generated + ! that is lower than the previous l2fr. The maintenance turnover (background) rate + ! will automatically accomodate a lower l2fr, but if the change is large it will + ! not keep pace. Note 1: however, that the algorithm for calculating l2fr will prevent + ! large drops in l2fr (unless that safegaurd is removed). Note 2: this section may also + ! generate mass check errors in the main CNPAllocation routine, this is because the "val" is + ! changing but the net_allocated is not reciprocating, which is expected. + + ! Keep a buffer above the L2FR in the hopes that natural turnover will catch + ! up. + class(cnp_allom_prt_vartypes) :: this + + real(r8) :: fnrt_flux_c + real(r8) :: turn_flux_c + real(r8) :: store_flux_c + real(r8) :: nc_fnrt + real(r8) :: pc_fnrt + real(r8) :: target_fnrt_c + real(r8),parameter :: nday_buffer = 0._r8 + real(r8),parameter :: fnrt_opt_eff = 0._r8 ! If we want to transfer resources to storage + + if(.not.use_unrestricted_contraction)return + + associate( ipft => this%bc_in(acnp_bc_in_id_pft)%ival, & + l2fr => this%bc_inout(acnp_bc_inout_id_l2fr)%rval, & + dbh => this%bc_inout(acnp_bc_inout_id_dbh)%rval, & + elongf_fnrt => this%bc_in(acnp_bc_in_id_effnrt)%rval, & + canopy_trim => this%bc_in(acnp_bc_in_id_ctrim)%rval) + + ! Find the updated target fineroot biomass + call bfineroot(dbh,ipft,canopy_trim, l2fr, elongf_fnrt, target_fnrt_c) + + fnrt_flux_c = max(0._r8,this%variables(fnrt_c_id)%val(1)*(1._r8-nday_buffer*(years_per_day / prt_params%root_long(ipft))) - target_fnrt_c ) + + if(fnrt_flux_c>nearzero) then + + turn_flux_c = (1._r8 - fnrt_opt_eff)*fnrt_flux_c + store_flux_c = fnrt_opt_eff*fnrt_flux_c + + nc_fnrt = this%variables(fnrt_n_id)%val(1)/this%variables(fnrt_c_id)%val(1) + pc_fnrt = this%variables(fnrt_p_id)%val(1)/this%variables(fnrt_c_id)%val(1) + + this%variables(fnrt_c_id)%val(1) = this%variables(fnrt_c_id)%val(1) - fnrt_flux_c + this%variables(fnrt_c_id)%turnover(1) = this%variables(fnrt_c_id)%turnover(1) + turn_flux_c + this%variables(fnrt_c_id)%net_alloc(1) = this%variables(fnrt_c_id)%net_alloc(1) - store_flux_c + this%variables(store_c_id)%val(1) = this%variables(store_c_id)%val(1) + store_flux_c + this%variables(store_c_id)%net_alloc(1) = this%variables(store_c_id)%net_alloc(1) + store_flux_c + + this%variables(fnrt_n_id)%val(1) = this%variables(fnrt_n_id)%val(1) - fnrt_flux_c * nc_fnrt + this%variables(fnrt_n_id)%turnover(1) = this%variables(fnrt_n_id)%turnover(1) + turn_flux_c * nc_fnrt + this%variables(fnrt_n_id)%net_alloc(1) = this%variables(fnrt_n_id)%net_alloc(1) - store_flux_c * nc_fnrt + this%variables(store_n_id)%val(1) = this%variables(store_n_id)%val(1) + store_flux_c * nc_fnrt + this%variables(store_n_id)%net_alloc(1) = this%variables(store_n_id)%net_alloc(1) + store_flux_c * nc_fnrt + + this%variables(fnrt_p_id)%val(1) = this%variables(fnrt_p_id)%val(1) - fnrt_flux_c * pc_fnrt + this%variables(fnrt_p_id)%turnover(1) = this%variables(fnrt_p_id)%turnover(1) + turn_flux_c * pc_fnrt + this%variables(fnrt_p_id)%net_alloc(1) = this%variables(fnrt_p_id)%net_alloc(1) - store_flux_c * pc_fnrt + this%variables(store_p_id)%val(1) = this%variables(store_p_id)%val(1) + store_flux_c * pc_fnrt + this%variables(store_p_id)%net_alloc(1) = this%variables(store_p_id)%net_alloc(1) + store_flux_c * pc_fnrt + + end if + end associate + return + end subroutine TrimFineRoot + + ! ===================================================================================== + + subroutine CNPPrioritizedReplacement(this,c_gain, n_gain, p_gain, target_c) + ! ----------------------------------------------------------------------------------- ! Alternative allocation hypothesis for the prioritized replacement phase. @@ -626,56 +951,74 @@ subroutine CNPPrioritizedReplacement(this, & real(r8), intent(inout) :: c_gain real(r8), intent(inout) :: n_gain real(r8), intent(inout) :: p_gain - real(r8), intent(inout) :: maint_r_deficit - type(parray_type) :: state_c(:) ! State array for carbon, by organ [kg] - type(parray_type) :: state_n(:) ! State array for N, by organ [kg] - type(parray_type) :: state_p(:) ! State array for P, by organ [kg] - real(r8), intent(in) :: target_c(:) - + real(r8), intent(in) :: target_c(:) ! Indexed by global organ (from PRTGenericMod) + integer :: n_curpri_org - integer, dimension(num_organs) :: curpri_org ! C variable ID's of the current priority level + + integer, dimension(num_organs) :: curpri_org ! organ ID's of the current priority level real(r8), dimension(num_organs) :: deficit_c ! Deficit to get to target from current [kg] real(r8), dimension(num_organs) :: deficit_n ! Deficit to get to target from current [kg] real(r8), dimension(num_organs) :: deficit_p ! Deficit to get to target from current [kg] + integer :: i, ii, i_org ! Loop indices (mostly for organs) - integer :: i_cvar ! variable index + integer :: i_var ! variable index integer :: i_pri ! loop index for priority integer :: ipft ! Plant functional type index of this plant integer :: leaf_status ! Is this plant in a leaf on or off status? - real(r8) :: dbh ! DBH [cm] real(r8) :: canopy_trim ! trim factor for maximum leaf biomass real(r8) :: target_n ! Target mass of N for a given organ [kg] real(r8) :: target_p ! Target mass of P for a given organ [kg] - real(r8) :: c_gain0 + real(r8) :: elongf_leaf ! Leaf elongation factor + real(r8) :: elongf_fnrt ! Fine-root "elongation factor" + real(r8) :: elongf_stem ! Stem "elongation factor" integer :: priority_code ! Index for priority level of each organ - real(r8) :: sum_c_demand ! Carbon demanded to bring tissues up to allometry (kg) - real(r8) :: sum_n_deficit ! The nitrogen deficit of all pools for given priority level (kg) - real(r8) :: sum_p_deficit ! The phosphorus deficit of all pools for given priority level (kg) - real(r8) :: store_below_target - real(r8) :: store_target_fraction - real(r8) :: store_demand - real(r8) :: store_c_flux + real(r8) :: sum_c_demand ! Carbon demanded to bring tissues up to allometry (kg) + real(r8) :: store_below_target ! The amount of storage that is less than the target (kg) + real(r8) :: store_target_fraction ! The fraction of actual storage carbon over the target (kg) + real(r8) :: store_demand ! Based on the target fraction, an exponential function defining + ! how much carbon we should try to put back into storage + real(r8) :: store_c_flux ! The amount of C we draw from gains to give back to storage (kg) real(r8) :: sum_c_flux ! The flux to bring tissues up to allometry (kg) - real(r8) :: sum_n_flux ! The flux of nitrogen "" (kg) - real(r8) :: sum_p_flux ! The flux of phosphorus "" (Kg) real(r8) :: c_flux ! carbon flux into an arbitrary pool (kg) - real(r8) :: gr_flux ! carbon flux to fulfill growth respiration of an arbitrary pool (kg) - real(r8) :: n_flux ! nitrogen flux into an arbitrary pool (kg) - real(r8) :: p_flux ! phosphorus flux into an arbitrary pool (kg) - real(r8) :: maint_r_def_flux ! Flux into maintenance respiration during priority 1 allocation - real(r8) :: c_gain_flux ! Flux used to pay back negative carbon gain (from storage) (kgC) - real(r8) :: sapw_area - integer, parameter :: n_max_priority = num_organs + 1 ! Maximum possible number of priority levels is - ! the total number organs plus 1, which allows - ! each organ to have its own level, and ignore - ! the specialized priority 1 - - - c_gain0 = c_gain + integer :: n_max_priority ! Maximum possible number of priority levels is + ! the total number organs plus 1, which allows + ! each organ to have its own level, and ignore + ! the specialized priority 1 + leaf_status = this%bc_in(acnp_bc_in_id_lstat)%ival + elongf_leaf = this%bc_in(acnp_bc_in_id_efleaf)%rval + elongf_fnrt = this%bc_in(acnp_bc_in_id_effnrt)%rval + elongf_stem = this%bc_in(acnp_bc_in_id_efstem)%rval ipft = this%bc_in(acnp_bc_in_id_pft)%ival canopy_trim = this%bc_in(acnp_bc_in_id_ctrim)%rval + + + n_max_priority = maxval(prt_params%organ_param_id(:)) + if(n_max_priority>10 .or. n_max_priority<0)then + write(fates_log(),*) 'was unable to interpret prt_params%organ_param_id' + write(fates_log(),*) 'for cnp allocation, there should be non-zero values <10' + write(fates_log(),*) 'your values: ',prt_params%organ_param_id(:) + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + + ! ----------------------------------------------------------------------------------- + ! Notes on indexes: + ! + ! i_org: this is the index that matches the global organ indices found in PRTGenericMod + ! + ! prt_params%alloc_priority is a parameter array that only holds a subset of the + ! organs. For instance it does not include reproductive and storage, because those + ! organs are special. We can find out the global organ index (ie i_org) from the + ! parameter array prt_params%organ_id + ! + ! i and ii are just local indices used to iterate through sub-groups of organs. + ! for instance, i will generally iterate through the curpri_org, which is an + ! array of the global organ indices (i_org) for the current subset of organs that + ! should be allocated at the current priority level + ! + ! ----------------------------------------------------------------------------------- + ! ----------------------------------------------------------------------------------- ! Preferential transfer of available carbon and nutrients into the highest @@ -684,30 +1027,31 @@ subroutine CNPPrioritizedReplacement(this, & ! If it is, then we track the variable ids associated with that pool for each CNP ! species. It "should" work fine if there are NO priority=1 pools... ! ----------------------------------------------------------------------------------- - + curpri_org(:) = fates_unset_int ! reset "current-priority" organ ids i = 0 - do ii = 1, num_organs - - deficit_c(ii) = max(0._r8,this%GetDeficit(carbon12_element,organ_list(ii),target_c(ii))) + do ii = 1, size(prt_params%organ_id,1) - ! The following logic bars any organs that were not given allocation priority - if( prt_params%organ_param_id(organ_list(ii)) < 1 ) cycle + ! universal organ index from PRTGenericMod + i_org = prt_params%organ_id(ii) - ! The priority code associated with this organ - priority_code = int(prt_params%alloc_priority(ipft, prt_params%organ_param_id(organ_list(ii)))) - ! Don't allow allocation to leaves if they are in an "off" status. ! Also, dont allocate to replace turnover if this is not evergreen ! (this prevents accidental re-flushing on the day they drop) - if( ((leaf_status.eq.leaves_off) .or. (prt_params%evergreen(ipft) .ne. itrue)) & - .and. (organ_list(ii).eq.leaf_organ)) cycle - + if( ( any(leaf_status == [leaves_off,leaves_shedding]) .or. & + (prt_params%evergreen(ipft) /= itrue) ) & + .and. (i_org == leaf_organ)) cycle + + ! The priority code associated with this organ + priority_code = int(prt_params%alloc_priority(ipft, ii)) + ! 1 is the highest priority code possible if( priority_code == 1 ) then i = i + 1 - curpri_org(i) = ii + curpri_org(i) = i_org + deficit_c(i) = max(0._r8,this%GetDeficit(carbon12_element,i_org,target_c(i_org))) end if + end do @@ -723,39 +1067,30 @@ subroutine CNPPrioritizedReplacement(this, & ! ----------------------------------------------------------------------------------- sum_c_demand = 0._r8 - do ii = 1,n_curpri_org - i = curpri_org(ii) - - i_cvar = prt_global%sp_organ_map(organ_list(i),carbon12_element) + do i = 1,n_curpri_org + i_org = curpri_org(i) + i_var = prt_global%sp_organ_map(i_org,carbon12_element) sum_c_demand = sum_c_demand + prt_params%leaf_stor_priority(ipft) * & - sum(this%variables(i_cvar)%turnover(:)) - + sum(this%variables(i_var)%turnover(:)) end do - - sum_c_flux = max(0._r8,min(sum_c_demand,state_c(store_id)%ptr+c_gain)) + sum_c_flux = max(0._r8,min(sum_c_demand,this%variables(store_c_id)%val(1)+c_gain)) if (sum_c_flux> nearzero ) then ! We pay this even if we don't have the carbon ! Just don't pay so much carbon that storage+carbon_balance can't pay for it - do ii = 1,n_curpri_org - i = curpri_org(ii) - - i_cvar = prt_global%sp_organ_map(organ_list(i),carbon12_element) + do i = 1,n_curpri_org - if(reproduce_conly) then - c_flux = min(prt_params%leaf_stor_priority(ipft)*sum(this%variables(i_cvar)%turnover(:)), & - max(0.0_r8, (state_c(store_id)%ptr+c_gain)* & - (prt_params%leaf_stor_priority(ipft)*sum(this%variables(i_cvar)%turnover(:))/sum_c_demand) )) - else - c_flux = sum_c_flux*(prt_params%leaf_stor_priority(ipft) * & - sum(this%variables(i_cvar)%turnover(:))/sum_c_demand) - end if + i_org = curpri_org(i) + i_var = prt_global%sp_organ_map(i_org,carbon12_element) + c_flux = sum_c_flux*(prt_params%leaf_stor_priority(ipft) * & + sum(this%variables(i_var)%turnover(:))/sum_c_demand) + ! Add carbon to the pool - state_c(i)%ptr = state_c(i)%ptr + c_flux + this%variables(i_var)%val(1) = this%variables(i_var)%val(1) + c_flux ! Remove from daily carbon gain c_gain = c_gain - c_flux @@ -763,41 +1098,33 @@ subroutine CNPPrioritizedReplacement(this, & end do end if - ! Determine nutrient demand and make tansfers (ignore replacing storage) + ! Determine nutrient demand and make tansfers do i = 1, n_curpri_org i_org = curpri_org(i) ! Update the nitrogen deficits - ! Note that the nitrogen target is tied to the stoichiometry of thegrowing pool only + ! Note that the nitrogen target is tied to the stoichiometry of the growing pool only (pos = 1) - if(organ_list(i_org).ne.store_organ)then - - target_n = this%GetNutrientTarget(nitrogen_element,organ_list(i_org),stoich_growth_min) - deficit_n(i_org) = max(0.0_r8, target_n - state_n(i_org)%ptr ) - - ! Update the phosphorus deficits (which are based off of carbon actual..) - ! Note that the phsophorus target is tied to the stoichiometry of thegrowing pool only (also) - target_p = this%GetNutrientTarget(phosphorus_element,organ_list(i_org),stoich_growth_min) - deficit_p(i_org) = max(0.0_r8, target_p - state_p(i_org)%ptr ) - else - deficit_n(i_org) = 0._r8 - deficit_p(i_org) = 0._r8 - end if + target_n = this%GetNutrientTarget(nitrogen_element,i_org,stoich_growth_min) + deficit_n(i) = max(0.0_r8, target_n - this%GetState(i_org, nitrogen_element,1)) + + ! Update the phosphorus deficits (which are based off of carbon actual..) + ! Note that the phsophorus target is tied to the stoichiometry of thegrowing pool only (also) + target_p = this%GetNutrientTarget(phosphorus_element,i_org,stoich_growth_min) + deficit_p(i) = max(0.0_r8, target_p - this%GetState(i_org, phosphorus_element,1)) end do ! Allocate nutrients at this priority level ! Nitrogen - call ProportionalNutrAllocation(state_n, deficit_n, & + call ProportionalNutrAllocation(this,deficit_n(1:n_curpri_org), & n_gain, nitrogen_element, curpri_org(1:n_curpri_org)) ! Phosphorus - call ProportionalNutrAllocation(state_p, deficit_p, & + call ProportionalNutrAllocation(this,deficit_p(1:n_curpri_org), & p_gain, phosphorus_element, curpri_org(1:n_curpri_org)) - - ! ----------------------------------------------------------------------------------- ! IV. if carbon balance is negative, re-coup the losses from storage ! if it is positive, give some love to storage carbon @@ -807,27 +1134,25 @@ subroutine CNPPrioritizedReplacement(this, & ! Storage will have to pay for any negative gains store_c_flux = -c_gain - c_gain = c_gain + store_c_flux - state_c(store_id)%ptr = state_c(store_id)%ptr - store_c_flux + c_gain = c_gain + store_c_flux + + this%variables(store_c_id)%val(1) = this%variables(store_c_id)%val(1) - store_c_flux else ! This is just a cap, don't fill up more than is needed (shouldn't even apply) - store_below_target = max(target_c(store_id) - state_c(store_id)%ptr,0._r8) + store_below_target = max(target_c(store_organ) - this%variables(store_c_id)%val(1),0._r8) ! This is the desired need for carbon - store_target_fraction = max(state_c(store_id)%ptr/target_c(store_id),0._r8) - + store_target_fraction = max(this%variables(store_c_id)%val(1)/target_c(store_organ),0._r8) store_demand = max(c_gain*(exp(-1.*store_target_fraction**4._r8) - exp( -1.0_r8 )),0._r8) - - ! The flux is the (positive) minimum of all three store_c_flux = min(store_below_target,store_demand) c_gain = c_gain - store_c_flux - state_c(store_id)%ptr = state_c(store_id)%ptr + store_c_flux - + + this%variables(store_c_id)%val(1) = this%variables(store_c_id)%val(1) + store_c_flux end if @@ -839,6 +1164,7 @@ subroutine CNPPrioritizedReplacement(this, & ! ----------------------------------------------------------------------------------- ! Bring all pools, in priority order, up to allometric targets if possible + ! Repeat priority order 1 as well. ! ----------------------------------------------------------------------------------- priority_loop: do i_pri = 1, n_max_priority @@ -846,49 +1172,49 @@ subroutine CNPPrioritizedReplacement(this, & curpri_org(:) = fates_unset_int ! "current-priority" organ indices i = 0 - do ii = 1, num_organs + + ! Storage has a special hard-coded priority level of 2 + if( i_pri == 2 ) then + curpri_org(1) = store_organ + i=1 + end if - ! The priority code associated with this organ - ! Storage has a special hard-coded priority level of 2 - ! Note that it is also implicitly part of step 1 + ! Loop over all organs in the CNP routine, which + do ii = 1, size(prt_params%organ_id,1) - if( organ_list(ii).eq.store_organ ) then - priority_code = 2 - else - if( prt_params%organ_param_id(organ_list(ii)) <1 ) then - priority_code = -1 - else - priority_code = int(prt_params%alloc_priority(ipft,prt_params%organ_param_id(organ_list(ii)))) - end if - end if - + ! universal organ index from PRTGenericMod + i_org = prt_params%organ_id(ii) + + ! The priority code associated with this organ + + priority_code = int(prt_params%alloc_priority(ipft,ii)) ! Don't allow allocation to leaves if they are in an "off" status. ! (this prevents accidental re-flushing on the day they drop) - if((leaf_status.eq.leaves_off) .and. (organ_list(ii).eq.leaf_organ)) cycle - - ! 1 is the highest priority code possible + if( any(leaf_status == [leaves_off,leaves_shedding]) .and. & + (i_org == leaf_organ) ) cycle + if( priority_code == i_pri ) then - deficit_c(ii) = max(0._r8,this%GetDeficit(carbon12_element,organ_list(ii),target_c(ii))) i = i + 1 - curpri_org(i) = ii + curpri_org(i) = i_org end if end do + n_curpri_org = i + + do i = 1,n_curpri_org + i_org = curpri_org(i) + deficit_c(i) = max(0._r8,this%GetDeficit(carbon12_element,i_org,target_c(i_org))) + end do + ! Bring carbon up to target first, this order is required ! because we need to know the resulting carbon concentrations ! before we set the allometric targets for the nutrients - n_curpri_org = i - - ! The total amount of carbon needed to be replaced - ! is the deficit and the growth respiration needed - ! accomany replacing that deficit - sum_c_demand = 0._r8 do i=1,n_curpri_org i_org = curpri_org(i) - sum_c_demand = sum_c_demand + deficit_c(i_org) + sum_c_demand = sum_c_demand + deficit_c(i) end do sum_c_flux = min(c_gain, sum_c_demand) @@ -899,89 +1225,51 @@ subroutine CNPPrioritizedReplacement(this, & i_org = curpri_org(i) - if(reproduce_conly) then - c_flux = min(deficit_c(i_org), & - c_gain*(deficit_c(i_org)/sum_c_demand)) - else - c_flux = sum_c_flux*deficit_c(i_org)/sum_c_demand - end if - - ! Update the carbon pool - state_c(i_org)%ptr = state_c(i_org)%ptr + c_flux - - ! Update carbon pools deficit - deficit_c(i_org) = max(0._r8,deficit_c(i_org) - c_flux) - - ! Reduce the carbon gain - c_gain = c_gain - c_flux - - end do - end if - - - sum_c_demand = 0._r8 - do i=1,n_curpri_org - i_org = curpri_org(i) - deficit_c(i_org) = max(0._r8,this%GetDeficit(carbon12_element,organ_list(i_org),target_c(i_org))) - sum_c_demand = sum_c_demand + deficit_c(i_org) - end do - - sum_c_flux = min(c_gain, sum_c_demand) - - ! Transfer carbon into pools if there is any (second round to match C-only) - if (sum_c_flux>nearzero) then - do i = 1, n_curpri_org - - i_org = curpri_org(i) - - c_flux = sum_c_flux*deficit_c(i_org)/sum_c_demand + c_flux = sum_c_flux*deficit_c(i)/sum_c_demand ! Update the carbon pool - state_c(i_org)%ptr = state_c(i_org)%ptr + c_flux + i_var = prt_global%sp_organ_map(i_org,carbon12_element) + this%variables(i_var)%val(1) = this%variables(i_var)%val(1) + c_flux ! Update carbon pools deficit - deficit_c(i_org) = max(0._r8,deficit_c(i_org) - c_flux) + deficit_c(i) = max(0._r8,deficit_c(i) - c_flux) ! Reduce the carbon gain c_gain = c_gain - c_flux end do end if - - - ! Determine nutrient demand and make tansfers do i = 1, n_curpri_org i_org = curpri_org(i) - if(organ_list(i_org).ne.store_organ)then - ! Update the nitrogen deficits - ! Note that the nitrogen target is tied to the stoichiometry of thegrowing pool only - target_n = this%GetNutrientTarget(nitrogen_element,organ_list(i_org),stoich_growth_min) - deficit_n(i_org) = max(0.0_r8, target_n - state_n(i_org)%ptr ) + + ! Update the nitrogen deficits + ! Note that the nitrogen target is tied to the stoichiometry of thegrowing pool only + target_n = this%GetNutrientTarget(nitrogen_element,i_org,stoich_growth_min) + deficit_n(i) = max(0.0_r8, target_n - this%GetState(i_org, nitrogen_element,1) ) - ! Update the phosphorus deficits (which are based off of carbon actual..) - ! Note that the phsophorus target is tied to the stoichiometry of thegrowing pool only (also) - target_p = this%GetNutrientTarget(phosphorus_element,organ_list(i_org),stoich_growth_min) - deficit_p(i_org) = max(0.0_r8, target_p - state_p(i_org)%ptr ) - else - deficit_n(i_org) = 0._r8 - deficit_p(i_org) = 0._r8 - end if + ! Update the phosphorus deficits (which are based off of carbon actual..) + ! Note that the phsophorus target is tied to the stoichiometry of thegrowing pool only (also) + target_p = this%GetNutrientTarget(phosphorus_element,i_org,stoich_growth_min) + deficit_p(i) = max(0.0_r8, target_p - this%GetState(i_org, phosphorus_element,1) ) + end do - ! Allocate nutrients at this priority level - ! Nitrogen - call ProportionalNutrAllocation(state_n, deficit_n, & + ! Allocate nutrients at this priority level Nitrogen + call ProportionalNutrAllocation(this,deficit_n(1:n_curpri_org), & n_gain, nitrogen_element, curpri_org(1:n_curpri_org)) ! Phosphorus - call ProportionalNutrAllocation(state_p, deficit_p, & + call ProportionalNutrAllocation(this,deficit_p(1:n_curpri_org), & p_gain, phosphorus_element, curpri_org(1:n_curpri_org)) end do priority_loop + + + return end subroutine CNPPrioritizedReplacement @@ -989,33 +1277,32 @@ end subroutine CNPPrioritizedReplacement ! ===================================================================================== - subroutine CNPStatureGrowth(this,c_gain, n_gain, p_gain, & - state_c, state_n, state_p, & - target_c, target_dcdd, cnp_limiter) + subroutine CNPStatureGrowth(this,c_gain, n_gain, p_gain, & + target_c, target_dcdd) class(cnp_allom_prt_vartypes) :: this - real(r8), intent(inout) :: c_gain - real(r8), intent(inout) :: n_gain - real(r8), intent(inout) :: p_gain - real(r8), pointer :: maint_r_deficit - type(parray_type) :: state_c(:) ! State array for carbon, by organ [kg] - type(parray_type) :: state_n(:) ! State array for N, by organ [kg] - type(parray_type) :: state_p(:) ! State array for P, by organ [kg] - real(r8), intent(in) :: target_c(:) - real(r8), intent(in) :: target_dcdd(:) - integer, intent(out) :: cnp_limiter - + real(r8), intent(inout) :: c_gain ! Total daily C gain that remains to be used + real(r8), intent(inout) :: n_gain ! Total N available for allocation + ! (new uptake + storage) + real(r8), intent(inout) :: p_gain ! Total P available for allocation + ! (new uptake + storage) + real(r8), intent(in) :: target_c(:) ! target carbon mass for each organ (before growth) + real(r8), intent(in) :: target_dcdd(:) ! target carbon mass derivative (wrt dbh) before growth) + + real(r8), pointer :: dbh integer :: ipft - real(r8) :: canopy_trim - real(r8) :: leaf_status - + integer, pointer :: limiter ! Integer flagging which (C,N,P) is limiting + real(r8) :: canopy_trim ! fraction of crown trimmed + integer :: crown_damage ! Damage status level + real(r8) :: elongf_leaf ! Elongation factor (leaves) + real(r8) :: elongf_fnrt ! Elongation factor (fine roots) + real(r8) :: elongf_stem ! Elongation factor (woods) + real(r8) :: leaf_status ! leaves on or off? + real(r8) :: l2fr ! leaf to fineroot allometry multiplier integer :: i, ii ! organ index loops (masked and unmasked) - integer :: istep ! outer step iteration loop - real(r8) :: grow_c_from_c ! carbon transferred into tissues - real(r8) :: grow_c_from_n ! carbon needed to match N transfers to tissues - real(r8) :: grow_c_from_p ! carbon needed to match P transfers to tissues + integer :: i_org ! global organ index real(r8) :: total_dcostdd ! Total carbon transferred to all pools for unit growth logical :: step_pass ! flag stating if the integration sub-steps passed checks real(r8) :: totalC ! total carbon sent to integrator (kg) @@ -1023,28 +1310,26 @@ subroutine CNPStatureGrowth(this,c_gain, n_gain, p_gain, & real(r8) :: cdeficit ! carbon deficit from target integer :: ierr ! error flag for allometric growth step integer :: nsteps ! number of sub-steps + real(r8) :: avg_nc,avg_pc ! Estimated average N/C and P/C ratios of + ! allocated carbon during stature growth real(r8) :: repro_c_frac ! Fraction of C allocated to reproduction ! at current stature (dbh) [/] real(r8) :: sum_c_flux ! Sum of the carbon allocated, as reported ! by the ODE solver. [kg] - real(r8) :: np_limit - real(r8) :: n_match - real(r8) :: p_match real(r8) :: c_flux_adj ! Adjustment to total carbon flux during stature growth ! intended to correct integration error (kg/kg) real(r8) :: c_flux ! Carbon flux from the gain pool to an organ (kgC) - real(r8) :: gr_flux ! Growth respiration flux for the current transaction (kgC) + real(r8) :: n_flux,p_flux real(r8) :: c_gstature ! Carbon reserved for stature growth (kg) real(r8) :: target_n ! Target mass of N for a given organ [kg] real(r8) :: target_p ! Target mass of P for a given organ [kg] real(r8) :: sum_n_demand ! Total N deficit to overcome after C stature growth [kg] real(r8) :: sum_p_demand ! Total P deficit to overcome after C stature growth [kg] - real(r8), dimension(num_organs) :: frac_c ! Fraction of C going towards each pool - ! (only used when calculating which species limits) real(r8), dimension(num_organs) :: deficit_n ! Deficit to get to target from current [kg] real(r8), dimension(num_organs) :: deficit_p ! Deficit to get to target from current [kg] integer,dimension(num_organs) :: mask_organs ! This works with "state_mask", the list - ! of organs in the mask + ! of organs (local ids) in the mask + integer,dimension(num_organs) :: mask_gorgans ! List of organ global indices in the mask integer :: n_mask_organs ! Integrator error checking @@ -1075,24 +1360,37 @@ subroutine CNPStatureGrowth(this,c_gain, n_gain, p_gain, & integer , parameter :: max_substeps = 300 ! Maximum allowable iterations real(r8), parameter :: max_trunc_error = 1.0_r8 ! Maximum allowable truncation error integer, parameter :: ODESolve = 2 ! 1=RKF45, 2=Euler - real(r8) :: intgr_params(num_bc_in) - integer, parameter :: grow_lim_type = 3 ! Dev flag for growth limitation algorithm - ! 1 = tries to calculate equivalent carbon - ! 2 = modification of 1 - ! 3 = don't limit, and assume nutrient limitations will prevent calling - ! of this step on the next cycle if they exist + real(r8) :: intgr_params(num_intgr_parm) + + + real(r8) :: neq_cgain, peq_cgain ! N and P equivalent c_gain spent on growth + real(r8) :: cnp_gain ! used as a check to see efficiency of limited growth + - integer, parameter :: c_limited = 1 - integer, parameter :: n_limited = 2 - integer, parameter :: p_limited = 3 leaf_status = this%bc_in(acnp_bc_in_id_lstat)%ival + elongf_leaf = this%bc_in(acnp_bc_in_id_efleaf)%rval + elongf_fnrt = this%bc_in(acnp_bc_in_id_effnrt)%rval + elongf_stem = this%bc_in(acnp_bc_in_id_efstem)%rval dbh => this%bc_inout(acnp_bc_inout_id_dbh)%rval ipft = this%bc_in(acnp_bc_in_id_pft)%ival + crown_damage = this%bc_in(acnp_bc_in_id_cdamage)%ival + limiter => this%bc_out(acnp_bc_out_id_limiter)%ival canopy_trim = this%bc_in(acnp_bc_in_id_ctrim)%rval + l2fr = this%bc_inout(acnp_bc_inout_id_l2fr)%rval ! This variable is not updated in this + ! routine, and is therefore not a pointer + + if( c_gain <= calloc_abs_error ) then + limiter = c_limited + if((n_gain <= 0.1_r8*calloc_abs_error) .or. & + (p_gain <= 0.02_r8*calloc_abs_error)) limiter = cnp_limited + else + if(n_gain <= 0.1_r8*calloc_abs_error) limiter = n_limited + if(p_gain <= 0.02_r8*calloc_abs_error) limiter = p_limited + end if - cnp_limiter = 0 + limiter = 0 ! If any of these resources is essentially tapped out, ! then there is no point in performing growth @@ -1101,22 +1399,25 @@ subroutine CNPStatureGrowth(this,c_gain, n_gain, p_gain, & ! a plant had a productive last day before the phenology scheme ! signaled a drop. If this is the case, we can't grow stature ! cause that would force the leaves back on, so just leave. - + if( c_gain <= calloc_abs_error .or. & n_gain <= 0.1_r8*calloc_abs_error .or. & p_gain <= 0.02_r8*calloc_abs_error .or. & - leaf_status.eq.leaves_off ) then + any(leaf_status == [leaves_off,leaves_shedding]) ) then return end if - - intgr_params(:) = fates_unset_r8 - intgr_params(acnp_bc_in_id_ctrim) = this%bc_in(acnp_bc_in_id_ctrim)%rval - intgr_params(acnp_bc_in_id_pft) = real(this%bc_in(acnp_bc_in_id_pft)%ival) - - + intgr_params(:) = fates_unset_r8 + intgr_params(intgr_parm_ctrim) = this%bc_in(acnp_bc_in_id_ctrim)%rval + intgr_params(intgr_parm_pft) = real(this%bc_in(acnp_bc_in_id_pft)%ival,r8) + intgr_params(intgr_parm_l2fr) = this%bc_inout(acnp_bc_inout_id_l2fr)%rval + intgr_params(intgr_parm_cdamage) = real(this%bc_in(acnp_bc_in_id_cdamage)%ival,r8) + intgr_params(intgr_parm_efleaf) = this%bc_in(acnp_bc_in_id_efleaf)%rval + intgr_params(intgr_parm_effnrt) = this%bc_in(acnp_bc_in_id_effnrt)%rval + intgr_params(intgr_parm_efstem) = this%bc_in(acnp_bc_in_id_efstem)%rval state_mask(:) = .false. mask_organs(:) = fates_unset_int + mask_gorgans(:) = fates_unset_int ! Go through and flag the integrating variables as either pools that ! are growing in this iteration, or not. At this point, if carbon for growth @@ -1128,7 +1429,9 @@ subroutine CNPStatureGrowth(this,c_gain, n_gain, p_gain, & ii = 0 do i = 1, num_organs - cdeficit = this%GetDeficit(carbon12_element,organ_list(i),target_c(i)) + i_org = l2g_organ_list(i) + + cdeficit = this%GetDeficit(carbon12_element,i_org,target_c(i_org)) if ( cdeficit > calloc_abs_error ) then ! In this case, we somehow still have carbon to play with, @@ -1136,10 +1439,10 @@ subroutine CNPStatureGrowth(this,c_gain, n_gain, p_gain, & ! gracefully fail write(fates_log(),*) 'A carbon pool has reached the stature growth step' write(fates_log(),*) 'yet its deficit is too large to integrate ' - write(fates_log(),*) 'organ: ',i + write(fates_log(),*) 'organ: ',i_org write(fates_log(),*) 'carbon gain: ',c_gain write(fates_log(),*) 'leaves status:', leaf_status - write(fates_log(),*) cdeficit, target_c(i), state_c(i)%ptr + write(fates_log(),*) cdeficit, target_c(i_org) call endrun(msg=errMsg(sourcefile, __LINE__)) elseif( (-cdeficit) > calloc_abs_error ) then ! In this case, we are above our target (ie negative deficit (fusion?)) @@ -1153,9 +1456,10 @@ subroutine CNPStatureGrowth(this,c_gain, n_gain, p_gain, & ! Reproduction is a special case, don't add it to the ! list of organs... yet - if (organ_list(i).ne.repro_organ) then + if (i_org.ne.repro_organ) then ii=ii+1 mask_organs(ii) = i + mask_gorgans(ii) = i_org end if end if @@ -1172,8 +1476,7 @@ subroutine CNPStatureGrowth(this,c_gain, n_gain, p_gain, & write(fates_log(),*) 'plants, and roots in grasses are not allowed above target.' write(fates_log(),*) 'pft: ',ipft write(fates_log(),*) 'dbh: ',dbh - write(fates_log(),*) 'c state1 : ',state_c(1)%ptr - write(fates_log(),*) 'c targets: ',target_c(1:num_organs) + write(fates_log(),*) 'c targets: ',target_c(:) call endrun(msg=errMsg(sourcefile, __LINE__)) end if end if @@ -1182,18 +1485,45 @@ 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, 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 + + 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) + ! 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))) + else - repro_c_frac = prt_params%seed_alloc(ipft) + prt_params%seed_alloc_mature(ipft) - end if - + + 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 + + if(repro_c_frac>nearzero)then state_mask(repro_id) = .true. - ii = ii + 1 - n_mask_organs = ii - mask_organs(ii) = repro_id + n_mask_organs = n_mask_organs + 1 + mask_organs(n_mask_organs) = repro_id + mask_gorgans(n_mask_organs) = repro_organ else state_mask(repro_id) = .false. end if @@ -1210,102 +1540,55 @@ subroutine CNPStatureGrowth(this,c_gain, n_gain, p_gain, & total_dcostdd = 0._r8 - do ii = 1, n_mask_organs - i = mask_organs(ii) - total_dcostdd = total_dcostdd + target_dcdd(i) - end do - - frac_c(:) = 0._r8 - do ii = 1, n_mask_organs - i = mask_organs(ii) - frac_c(i) = target_dcdd(i)/total_dcostdd * (1.0_r8 - repro_c_frac) + do i = 1, n_mask_organs + i_org = mask_gorgans(ii) + total_dcostdd = total_dcostdd + target_dcdd(i_org) end do - frac_c(repro_id) = repro_c_frac - - if(debug) then - if ( abs(sum(frac_c,dim=1)-1._r8)>rsnbl_math_prec ) then - write(fates_log(),*) 'predicted carbon allocation fractions dont sum to 1?' - write(fates_log(),*) 'frac_c(:):',frac_c - call endrun(msg=errMsg(sourcefile, __LINE__)) - end if - end if + + ! We can either proceed with stature growth by using all of the carbon + ! available, or we can try to estimate the limitations of N and P + ! and thereby reduce the amount of C we are willing to use to try + ! and match what is available in n_gain and p_gain. Note that the + ! c-only option does allow limitations to eventually occur, because + ! it is assumed that in the dynamics call that follows this one, there may + ! or not be enough N or P to reach the stature growth step at all. + if(grow_lim_type == grow_lim_conly) then + c_gstature = c_gain + limiter = 0 + elseif (grow_lim_type == grow_lim_estNP) then - select case(grow_lim_type) - case(1) + call EstimateGrowthNC(this,target_c,target_dcdd,state_mask,avg_nc,avg_pc) - - ! Calculate an approximation of the total amount of carbon that would be needed - ! to match the amount of each nutrient used. We also add in the amount of nutrient - ! that may or may-not exist above each pool's minimum stoichiometry... - ! -------------------------------------------------------------------------------- - - grow_c_from_c = 0._r8 - grow_c_from_n = 0._r8 - grow_c_from_p = 0._r8 + neq_cgain = n_gain/avg_nc + peq_cgain = p_gain/avg_pc - do ii = 1, n_mask_organs - i = mask_organs(ii) - if(organ_list(i).ne.store_organ)then - call this%GrowEquivC(c_gain,n_gain,p_gain, & - frac_c(i),ipft,organ_list(i), & - grow_c_from_c,grow_c_from_n,grow_c_from_p) - end if - end do - - ! -------------------------------------------------------------------------------- - ! We limit growth to align with the species would motivate the least flux of - ! carbon into growing tissues to match. This is only an approximation of how much - ! growth we get out of each, and they don't have to be perfect. As long as we - ! don't use more carbon than we have (we wont) and if we use the actual numerical - ! integrator in the trasfer step, the nutrients will be transferred linearly in - ! the next step. if they dip slightly above or below their target allometries, - ! its no big deal. - ! -------------------------------------------------------------------------------- - - if(grow_c_from_c > nearzero) then - c_gstature = c_gain * min(grow_c_from_c, grow_c_from_n, grow_c_from_p)/grow_c_from_c - else - write(fates_log(),*) 'Somehow grow_c_from_c is near zero',grow_c_from_c - call endrun(msg=errMsg(sourcefile, __LINE__)) - end if - case(2) - - n_match = 0._r8 - p_match = 0._r8 - do ii = 1, n_mask_organs - i = mask_organs(ii) - if(organ_list(i).ne.store_organ)then - call this%NAndPToMatchC(c_gain*frac_c(i),target_dcdd(i), & - ipft,organ_list(i),n_match,p_match) - end if - end do - - np_limit = min(min(1._r8, n_gain/n_match), min(1._r8, p_gain/p_match)) + if(c_gain1._r8 .and. (p_gain/p_match)>1._r8 ) then - cnp_limiter = c_limited + if(c_gain < peq_cgain) then + limiter = c_limited + c_gstature = c_gain + cnp_gain = c_gain + else + limiter = p_limited + c_gstature = peq_cgain + cnp_gain = p_gain + end if + else - if( n_gain/n_match < p_gain/p_match ) then - cnp_limiter = n_limited + if(neq_cgain < peq_cgain) then + limiter = n_limited + c_gstature = neq_cgain + cnp_gain = n_gain else - cnp_limiter = p_limited + limiter = p_limited + c_gstature = peq_cgain + cnp_gain = p_gain end if + end if - c_gstature = c_gain * np_limit - - case(3) - - ! No mathematical co-limitation of growth - ! This assumes that limitations will prevent - ! organs from allowing the growth step to even occur - ! and thus from an algorithmic level limit growth - - c_gstature = c_gain - - - end select + end if if_stature_growth: if(c_gstature > nearzero) then @@ -1325,13 +1608,13 @@ subroutine CNPStatureGrowth(this,c_gain, n_gain, p_gain, & ! Fill the state array with element masses for each organ do i = 1, num_organs - state_array(i) = state_c(i)%ptr + i_org = l2g_organ_list(i) + i_var = prt_global%sp_organ_map(i_org,carbon12_element) + state_array(i) = this%variables(i_var)%val(1) end do state_mask(dbh_id) = .true. state_array(dbh_id) = dbh - - totalC = c_gstature do_solve_check: do while( ierr .ne. 0 ) @@ -1356,8 +1639,9 @@ subroutine CNPStatureGrowth(this,c_gain, n_gain, p_gain, & do i = 2,nbins leafc_tp1 = leafc_tp1 + this%variables(i_var)%val(i) end do - - call CheckIntegratedAllometries(state_array_out(dbh_id),ipft,canopy_trim, & + + call CheckIntegratedAllometries(state_array_out(dbh_id),ipft,crown_damage,canopy_trim, & + elongf_leaf, elongf_fnrt, elongf_stem, l2fr, & leafc_tp1, state_array_out(fnrt_id), state_array_out(sapw_id), & state_array_out(store_id), state_array_out(struct_id), & state_mask(leaf_id), state_mask(fnrt_id), state_mask(sapw_id), & @@ -1396,8 +1680,10 @@ subroutine CNPStatureGrowth(this,c_gain, n_gain, p_gain, & sum_c_flux = 0.0_r8 do ii = 1, n_mask_organs - i = mask_organs(ii) - sum_c_flux = sum_c_flux + (state_array(i) - state_c(i)%ptr) + i = mask_organs(ii) + i_org = mask_gorgans(ii) + i_var = prt_global%sp_organ_map(i_org,carbon12_element) + sum_c_flux = sum_c_flux + (state_array(i) - this%variables(i_var)%val(1)) end do ! This is a correction factor that forces @@ -1406,13 +1692,15 @@ subroutine CNPStatureGrowth(this,c_gain, n_gain, p_gain, & do ii = 1, n_mask_organs - i = mask_organs(ii) + i = mask_organs(ii) + i_org = mask_gorgans(ii) + i_var = prt_global%sp_organ_map(i_org,carbon12_element) ! Calculate adjusted flux - c_flux = (state_array(i) - state_c(i)%ptr)*c_flux_adj + c_flux = (state_array(i) - this%variables(i_var)%val(1))*c_flux_adj ! update the carbon pool (in all pools flux goes into the first pool) - state_c(i)%ptr = state_c(i)%ptr + c_flux + this%variables(i_var)%val(1) = this%variables(i_var)%val(1) + c_flux ! Remove carbon from the daily gain c_gain = c_gain - c_flux @@ -1431,14 +1719,19 @@ subroutine CNPStatureGrowth(this,c_gain, n_gain, p_gain, & write(fates_log(),*) 'Aborting' write(fates_log(),*) 'mask: ',state_mask write(fates_log(),*) 'smallest deltaC',this%ode_opt_step - write(fates_log(),*) 'totalC',totalC + write(fates_log(),*) 'totalC',totalC,c_gain,neq_cgain,peq_cgain write(fates_log(),*) 'pft: ',ipft + write(fates_log(),*) 'trim: ',canopy_trim + write(fates_log(),*) 'l2fr: ',l2fr write(fates_log(),*) 'dbh: ',dbh - write(fates_log(),*) 'dCleaf_dd: ',target_dcdd(leaf_id) - write(fates_log(),*) 'dCfnrt_dd: ',target_dcdd(fnrt_id) - write(fates_log(),*) 'dCstore_dd: ',target_dcdd(store_id) - write(fates_log(),*) 'dCsapw_dd: ',target_dcdd(sapw_id) - write(fates_log(),*) 'dCstruct_dd: ',target_dcdd(struct_id) + write(fates_log(),*) 'elongf_leaf: ',elongf_leaf + write(fates_log(),*) 'elongf_fnrt: ',elongf_fnrt + write(fates_log(),*) 'elongf_stem: ',elongf_stem + write(fates_log(),*) 'dCleaf_dd: ',target_dcdd(leaf_organ) + write(fates_log(),*) 'dCfnrt_dd: ',target_dcdd(fnrt_organ) + write(fates_log(),*) 'dCstore_dd: ',target_dcdd(store_organ) + write(fates_log(),*) 'dCsapw_dd: ',target_dcdd(sapw_organ) + write(fates_log(),*) 'dCstruct_dd: ',target_dcdd(struct_organ) write(fates_log(),*) 'repro c frac: ',repro_c_frac dbh_tp1 = state_array_out(dbh_id) leafc_tp1 = state_array_out(leaf_id) @@ -1447,21 +1740,19 @@ subroutine CNPStatureGrowth(this,c_gain, n_gain, p_gain, & storec_tp1 = state_array_out(store_id) structc_tp1 = state_array_out(struct_id) - call bleaf(dbh_tp1,ipft,canopy_trim,leaf_c_target_tp1) - call bfineroot(dbh_tp1,ipft,canopy_trim,fnrt_c_target_tp1) - call bsap_allom(dbh_tp1,ipft,canopy_trim,sapw_area,sapw_c_target_tp1) - call bagw_allom(dbh_tp1,ipft,agw_c_target_tp1) - call bbgw_allom(dbh_tp1,ipft,bgw_c_target_tp1) + call bleaf(dbh_tp1,ipft,crown_damage,canopy_trim, elongf_leaf, leaf_c_target_tp1) + call bfineroot(dbh_tp1,ipft,canopy_trim,l2fr, elongf_fnrt, fnrt_c_target_tp1) + call bsap_allom(dbh_tp1,ipft,crown_damage,canopy_trim, elongf_stem, sapw_area,sapw_c_target_tp1) + call bagw_allom(dbh_tp1,ipft,crown_damage, elongf_stem, agw_c_target_tp1) + call bbgw_allom(dbh_tp1,ipft, elongf_stem, bgw_c_target_tp1) call bdead_allom(agw_c_target_tp1,bgw_c_target_tp1, sapw_c_target_tp1, ipft, struct_c_target_tp1) - call bstore_allom(dbh_tp1,ipft,canopy_trim,store_c_target_tp1) - + call bstore_allom(dbh_tp1,ipft,crown_damage,canopy_trim,store_c_target_tp1) + write(fates_log(),*) 'leaf_c: ',leafc_tp1, leaf_c_target_tp1,leafc_tp1-leaf_c_target_tp1 write(fates_log(),*) 'fnrt_c: ',fnrtc_tp1, fnrt_c_target_tp1,fnrtc_tp1- fnrt_c_target_tp1 write(fates_log(),*) 'sapw_c: ',sapwc_tp1, sapw_c_target_tp1 ,sapwc_tp1- sapw_c_target_tp1 write(fates_log(),*) 'store_c: ',storec_tp1, store_c_target_tp1,storec_tp1- store_c_target_tp1 write(fates_log(),*) 'struct_c: ',structc_tp1, struct_c_target_tp1,structc_tp1- struct_c_target_tp1 - write(fates_log(),*) 'sapw_c_t0: ',state_c(sapw_id)%ptr, target_c(sapw_id) - call endrun(msg=errMsg(sourcefile, __LINE__)) end if if_step_exceedance @@ -1477,18 +1768,23 @@ subroutine CNPStatureGrowth(this,c_gain, n_gain, p_gain, & ! have their maximum stoichiometry in each organ. The total stoichiometry ! of the recruits should match the stoichiometry of the seeds - !!target_n = this%GetNutrientTarget(nitrogen_element,repro_organ,stoich_growth_min) - !!deficit_n(repro_id) = this%GetDeficit(nitrogen_element,repro_organ,target_n) + if(prioritize_repro_nutr_growth)then - !!target_p = this%GetNutrientTarget(phosphorus_element,repro_organ,stoich_growth_min) - !!deficit_p(repro_id) = this%GetDeficit(phosphorus_element,repro_organ,target_p) - - ! Nitrogen for - !!call ProportionalNutrAllocation(state_n, deficit_n, n_gain, nitrogen_element,[repro_id]) - - ! Phosphorus - !!call ProportionalNutrAllocation(state_p, deficit_p, p_gain, phosphorus_element,[repro_id]) + target_n = this%GetNutrientTarget(nitrogen_element,repro_organ,stoich_growth_min) + deficit_n(1) = this%GetDeficit(nitrogen_element,repro_organ,target_n) + n_flux = max(0._r8,min(n_gain,deficit_n(1))) + + target_p = this%GetNutrientTarget(phosphorus_element,repro_organ,stoich_growth_min) + deficit_p(1) = this%GetDeficit(phosphorus_element,repro_organ,target_p) + p_flux = max(0._r8,min(p_gain,deficit_p(1))) + + this%variables(repro_n_id)%val(1) = this%variables(repro_n_id)%val(1) + n_flux + this%variables(repro_p_id)%val(1) = this%variables(repro_p_id)%val(1) + p_flux + n_gain = n_gain - n_flux + p_gain = p_gain - p_flux + + end if ! ----------------------------------------------------------------------------------- ! Nutrient Fluxes proportionally to each pool (these should be fully actualized) @@ -1498,56 +1794,52 @@ subroutine CNPStatureGrowth(this,c_gain, n_gain, p_gain, & sum_n_demand = 0._r8 ! For error checking sum_p_demand = 0._r8 ! For error checking do ii = 1, n_mask_organs - i = mask_organs(ii) - if(organ_list(i).ne.store_organ)then - ! Update the nitrogen deficits (which are based off of carbon actual..) - ! Note that the nitrogen target is tied to the stoichiometry of thegrowing pool only - target_n = this%GetNutrientTarget(nitrogen_element,organ_list(i),stoich_growth_min) - deficit_n(i) = this%GetDeficit(nitrogen_element,organ_list(i),target_n) - sum_n_demand = sum_n_demand+max(0._r8,deficit_n(i)) - - ! Update the nitrogen deficits (which are based off of carbon actual..) - ! Note that the nitrogen target is tied to the stoichiometry of thegrowing pool only - target_p = this%GetNutrientTarget(phosphorus_element,organ_list(i),stoich_growth_min) - deficit_p(i) = this%GetDeficit(phosphorus_element,organ_list(i),target_p) - sum_p_demand = sum_p_demand+max(0._r8,deficit_p(i)) - else - deficit_n(i) = 0._r8 - deficit_p(i) = 0._r8 - end if + + i = mask_organs(ii) + i_org = mask_gorgans(ii) + + target_n = this%GetNutrientTarget(nitrogen_element,i_org,stoich_growth_min) + target_p = this%GetNutrientTarget(phosphorus_element,i_org,stoich_growth_min) + + deficit_n(ii) = this%GetDeficit(nitrogen_element,i_org,target_n) + sum_n_demand = sum_n_demand+max(0._r8,deficit_n(ii)) + + deficit_p(ii) = this%GetDeficit(phosphorus_element,i_org,target_p) + sum_p_demand = sum_p_demand+max(0._r8,deficit_p(ii)) end do - - ! Nitrogen - call ProportionalNutrAllocation(state_n,deficit_n, & - n_gain, nitrogen_element,mask_organs(1:n_mask_organs)) - - ! Phosphorus - call ProportionalNutrAllocation(state_p, deficit_p, & - p_gain, phosphorus_element,mask_organs(1:n_mask_organs)) - - + + ! TODO: mask_organs should be a vector of global organs + + ! Nitrogen + call ProportionalNutrAllocation(this,deficit_n(1:n_mask_organs), & + n_gain, nitrogen_element,mask_gorgans(1:n_mask_organs)) + + ! Phosphorus + call ProportionalNutrAllocation(this,deficit_p(1:n_mask_organs), & + p_gain, phosphorus_element,mask_gorgans(1:n_mask_organs)) + end if if_stature_growth - + return end subroutine CNPStatureGrowth ! ===================================================================================== - subroutine CNPAllocateRemainder(this,c_gain, n_gain, p_gain, & - state_c, state_n, state_p, c_efflux, n_efflux, p_efflux) + subroutine CNPAllocateRemainder(this, c_gain,n_gain,p_gain, & + c_efflux, n_efflux, p_efflux, & + target_c,target_dcdd) class(cnp_allom_prt_vartypes) :: this real(r8), intent(inout) :: c_gain real(r8), intent(inout) :: n_gain - real(r8), intent(inout) :: p_gain - type(parray_type) :: state_c(:) ! State array for carbon, by organ [kg] - type(parray_type) :: state_n(:) ! State array for N, by organ [kg] - type(parray_type) :: state_p(:) ! State array for P, by organ [kg] + real(r8), intent(inout) :: p_gain real(r8), intent(inout) :: c_efflux real(r8), intent(inout) :: n_efflux real(r8), intent(inout) :: p_efflux - + real(r8) :: target_c(:) + real(r8) :: target_dcdd(:) + integer :: i real(r8), dimension(num_organs) :: deficit_n real(r8), dimension(num_organs) :: deficit_p @@ -1555,17 +1847,19 @@ subroutine CNPAllocateRemainder(this,c_gain, n_gain, p_gain, & real(r8) :: target_p real(r8) :: store_c_target ! Target amount of C in storage including "overflow" [kgC] real(r8) :: total_c_flux ! Total C flux from gains into storage and growth R [kgC] - real(r8) :: growth_r_flux ! Growth respiration for filling storage [kgC] - real(r8) :: store_c_flux ! Flux into storage [kgC] - integer, dimension(num_organs),parameter :: all_organs = [1,2,3,4,5,6] real(r8), pointer :: dbh + real(r8), pointer :: resp_excess integer :: ipft + integer, pointer :: limiter real(r8) :: canopy_trim + integer :: crown_damage - dbh => this%bc_inout(acnp_bc_inout_id_dbh)%rval canopy_trim = this%bc_in(acnp_bc_in_id_ctrim)%rval ipft = this%bc_in(acnp_bc_in_id_pft)%ival + resp_excess => this%bc_inout(acnp_bc_inout_id_resp_excess)%rval + limiter => this%bc_out(acnp_bc_out_id_limiter)%ival + crown_damage = this%bc_in(acnp_bc_in_id_cdamage)%ival ! ----------------------------------------------------------------------------------- ! If nutrients are still available, then we can bump up the values in the pools @@ -1575,39 +1869,37 @@ subroutine CNPAllocateRemainder(this,c_gain, n_gain, p_gain, & do i = 1, num_organs ! Update the nitrogen and phosphorus deficits - target_n = this%GetNutrientTarget(nitrogen_element,organ_list(i),stoich_max) - deficit_n(i) = max(0._r8,this%GetDeficit(nitrogen_element,organ_list(i),target_n)) - - target_p = this%GetNutrientTarget(phosphorus_element,organ_list(i),stoich_max) - deficit_p(i) = max(0._r8,this%GetDeficit(phosphorus_element,organ_list(i),target_p)) + target_n = this%GetNutrientTarget(nitrogen_element,l2g_organ_list(i),stoich_growth_min) + target_p = this%GetNutrientTarget(phosphorus_element,l2g_organ_list(i),stoich_growth_min) + + if(l2g_organ_list(i)==store_organ)then + target_n = target_n * (1._r8 + prt_params%store_ovrflw_frac(ipft)) + target_p = target_p * (1._r8 + prt_params%store_ovrflw_frac(ipft)) + end if + + deficit_n(i) = max(0._r8,this%GetDeficit(nitrogen_element,l2g_organ_list(i),target_n)) + deficit_p(i) = max(0._r8,this%GetDeficit(phosphorus_element,l2g_organ_list(i),target_p)) end do - + ! ----------------------------------------------------------------------------------- ! Nutrient Fluxes proportionally to each pool (these should be fully actualized) ! (this also removes from the gain pools) ! ----------------------------------------------------------------------------------- ! Nitrogen - call ProportionalNutrAllocation(state_n(1:num_organs), & - deficit_n(1:num_organs), & - n_gain, nitrogen_element, all_organs) + call ProportionalNutrAllocation(this,deficit_n(1:num_organs), & + n_gain, nitrogen_element, l2g_organ_list(1:num_organs)) ! Phosphorus - call ProportionalNutrAllocation(state_p(1:num_organs), & - deficit_p(1:num_organs), & - p_gain, phosphorus_element, all_organs) - + call ProportionalNutrAllocation(this,deficit_p(1:num_organs), & + p_gain, phosphorus_element, l2g_organ_list(1:num_organs)) - ! If any N or P is still hanging around, put it in storage - state_n(store_id)%ptr = state_n(store_id)%ptr + n_gain - state_p(store_id)%ptr = state_p(store_id)%ptr + p_gain - - n_gain = 0._r8 - p_gain = 0._r8 - - + ! This routine updates the l2fr (leaf 2 fine-root multiplier) variable + ! It will also update the target + call this%CNPAdjustFRootTargets(target_c,target_dcdd) + ! ----------------------------------------------------------------------------------- ! If carbon is still available, lets cram some into storage overflow ! We will do this last, because we wanted the non-overflow storage @@ -1616,35 +1908,94 @@ subroutine CNPAllocateRemainder(this,c_gain, n_gain, p_gain, & if(c_gain>calloc_abs_error) then - ! Update carbon based allometric targets - call bstore_allom(dbh,ipft,canopy_trim, store_c_target) - - ! Estimate the overflow - store_c_target = store_c_target * (1.0_r8 + store_overflow_frac) - - total_c_flux = min(c_gain,max(0.0, (store_c_target - state_c(store_id)%ptr))) - - ! Transfer excess carbon into storage overflow - state_c(store_id)%ptr = state_c(store_id)%ptr + total_c_flux - c_gain = c_gain - total_c_flux + if(store_c_overflow == retain_c_store_overflow)then + + total_c_flux = c_gain + ! Transfer excess carbon into storage overflow + this%variables(store_c_id)%val(1) = this%variables(store_c_id)%val(1) + total_c_flux + c_gain = c_gain - total_c_flux + + elseif(store_c_overflow == burn_c_store_overflow) then + ! Update carbon based allometric targets + call bstore_allom(dbh,ipft,crown_damage,canopy_trim, store_c_target) + + ! Allow some overflow + store_c_target = store_c_target * (1._r8 + prt_params%store_ovrflw_frac(ipft)) + + total_c_flux = max(0._r8,min(c_gain, store_c_target - this%variables(store_c_id)%val(1) )) + + ! Transfer excess carbon INTO storage overflow + this%variables(store_c_id)%val(1) = this%variables(store_c_id)%val(1) + total_c_flux + c_gain = c_gain - total_c_flux + + resp_excess = resp_excess + c_gain + c_gain = 0._r8 + + elseif(store_c_overflow == exude_c_store_overflow)then + + ! Update carbon based allometric targets + call bstore_allom(dbh,ipft,crown_damage,canopy_trim, store_c_target) + + ! Estimate the overflow + store_c_target = store_c_target * (1._r8 + prt_params%store_ovrflw_frac(ipft)) + + total_c_flux = max(0.0, min(c_gain, store_c_target - this%variables(store_c_id)%val(1))) + ! Transfer excess carbon into storage overflow + this%variables(store_c_id)%val(1) = this%variables(store_c_id)%val(1) + total_c_flux + c_gain = c_gain - total_c_flux + + end if end if + ! If we had some poor numerical precision resulting + ! in negative gains, use storage to get them back to zero + ! they should be very very small + if(c_gain<-nearzero) then + this%variables(store_c_id)%val(1) = this%variables(store_c_id)%val(1) + c_gain + c_gain = 0 + end if + if(n_gain<-nearzero) then + this%variables(store_n_id)%val(1) = this%variables(store_n_id)%val(1) + n_gain + n_gain = 0 + end if + if(p_gain<-nearzero) then + this%variables(store_p_id)%val(1) = this%variables(store_p_id)%val(1) + p_gain + p_gain = 0 + end if + ! Figure out what to do with excess carbon and nutrients ! 1) excude through roots cap at 0 to flush out imprecisions ! ----------------------------------------------------------------------------------- - c_efflux = max(0.0_r8,c_gain) -! n_efflux = max(0.0_r8,n_gain) -! p_efflux = max(0.0_r8,p_gain) + ! If either n or p uptake is in prescribed mode + ! don't efflux anything, we will use the remainder + ! n_gain and p_gain to specify the demand as what was used + ! and what was uptaken + + if(n_uptake_mode.eq.prescribed_n_uptake) then + n_efflux = 0._r8 + else + n_efflux = n_gain + n_gain = 0._r8 + end if + + if(p_uptake_mode.eq.prescribed_p_uptake) then + p_efflux = 0._r8 + else + p_efflux = p_gain + p_gain = 0._r8 + end if + c_efflux = c_gain + c_gain = 0.0_r8 + + - c_gain = 0.0_r8 -! n_gain = 0.0_r8 -! p_gain = 0.0_r8 + nullify(dbh) return end subroutine CNPAllocateRemainder @@ -1689,7 +2040,6 @@ function GetDeficit(this,element_id,organ_id,target_m) result(deficit_m) return end function GetDeficit - ! ===================================================================================== @@ -1704,20 +2054,31 @@ function GetNutrientTargetCNP(this,element_id,organ_id,stoich_mode) result(targe real(r8) :: target_c real(r8),pointer :: dbh real(r8) :: canopy_trim + real(r8) :: l2fr integer :: ipft integer :: i_cvar + integer :: crown_damage real(r8) :: sapw_area real(r8) :: leaf_c_target,fnrt_c_target real(r8) :: sapw_c_target,agw_c_target real(r8) :: bgw_c_target,struct_c_target + real(r8) :: elongf_leaf + real(r8) :: elongf_fnrt + real(r8) :: elongf_stem + real(r8) :: nc_repro,pc_repro + - - - dbh => this%bc_inout(acnp_bc_inout_id_dbh)%rval canopy_trim = this%bc_in(acnp_bc_in_id_ctrim)%rval ipft = this%bc_in(acnp_bc_in_id_pft)%ival + elongf_leaf = this%bc_in(acnp_bc_in_id_efleaf)%rval + elongf_fnrt = this%bc_in(acnp_bc_in_id_effnrt)%rval + elongf_stem = this%bc_in(acnp_bc_in_id_efstem)%rval i_cvar = prt_global%sp_organ_map(organ_id,carbon12_element) + l2fr = this%bc_inout(acnp_bc_inout_id_l2fr)%rval + nc_repro = this%bc_in(acnp_bc_in_id_nc_repro)%rval + pc_repro = this%bc_in(acnp_bc_in_id_pc_repro)%rval + crown_damage = this%bc_in(acnp_bc_in_id_cdamage)%ival ! Storage of nutrients are assumed to have different compartments than ! for carbon, and thus their targets are not associated with a tissue @@ -1726,11 +2087,11 @@ function GetNutrientTargetCNP(this,element_id,organ_id,stoich_mode) result(targe if(organ_id == store_organ) then - call bleaf(dbh,ipft,canopy_trim,leaf_c_target) - call bfineroot(dbh,ipft,canopy_trim,fnrt_c_target) - call bsap_allom(dbh,ipft,canopy_trim,sapw_area,sapw_c_target) - call bagw_allom(dbh,ipft,agw_c_target) - call bbgw_allom(dbh,ipft,bgw_c_target) + call bleaf(dbh,ipft,crown_damage,canopy_trim, elongf_leaf, leaf_c_target) + call bfineroot(dbh,ipft,canopy_trim,l2fr, elongf_fnrt, fnrt_c_target) + call bsap_allom(dbh,ipft,crown_damage,canopy_trim, elongf_stem, sapw_area,sapw_c_target) + call bagw_allom(dbh,ipft,crown_damage, elongf_stem, agw_c_target) + call bbgw_allom(dbh,ipft, elongf_stem, bgw_c_target) call bdead_allom(agw_c_target,bgw_c_target, sapw_c_target, ipft, struct_c_target) ! Target for storage is a fraction of the sum target of all @@ -1739,27 +2100,33 @@ function GetNutrientTargetCNP(this,element_id,organ_id,stoich_mode) result(targe if( element_id == nitrogen_element) then target_m = StorageNutrientTarget(ipft, element_id, & - leaf_c_target*prt_params%nitr_stoich_p2(ipft,prt_params%organ_param_id(leaf_organ)), & - fnrt_c_target*prt_params%nitr_stoich_p2(ipft,prt_params%organ_param_id(fnrt_organ)), & - sapw_c_target*prt_params%nitr_stoich_p2(ipft,prt_params%organ_param_id(sapw_organ)), & - struct_c_target*prt_params%nitr_stoich_p2(ipft,prt_params%organ_param_id(struct_organ))) + leaf_c_target*prt_params%nitr_stoich_p1(ipft,prt_params%organ_param_id(leaf_organ)), & + fnrt_c_target*prt_params%nitr_stoich_p1(ipft,prt_params%organ_param_id(fnrt_organ)), & + sapw_c_target*prt_params%nitr_stoich_p1(ipft,prt_params%organ_param_id(sapw_organ)), & + struct_c_target*prt_params%nitr_stoich_p1(ipft,prt_params%organ_param_id(struct_organ))) else - + target_m = StorageNutrientTarget(ipft, element_id, & - leaf_c_target*prt_params%phos_stoich_p2(ipft,prt_params%organ_param_id(leaf_organ)), & - fnrt_c_target*prt_params%phos_stoich_p2(ipft,prt_params%organ_param_id(fnrt_organ)), & - sapw_c_target*prt_params%phos_stoich_p2(ipft,prt_params%organ_param_id(sapw_organ)), & - struct_c_target*prt_params%phos_stoich_p2(ipft,prt_params%organ_param_id(struct_organ))) - + leaf_c_target*prt_params%phos_stoich_p1(ipft,prt_params%organ_param_id(leaf_organ)), & + fnrt_c_target*prt_params%phos_stoich_p1(ipft,prt_params%organ_param_id(fnrt_organ)), & + sapw_c_target*prt_params%phos_stoich_p1(ipft,prt_params%organ_param_id(sapw_organ)), & + struct_c_target*prt_params%phos_stoich_p1(ipft,prt_params%organ_param_id(struct_organ))) + end if + ! This is only called during phase 3, remainder and allows + ! us to have some overflow to avoid exudation/efflux if possible + if( stoich_mode == stoich_max ) then + target_m = target_m*(1._r8 + prt_params%store_ovrflw_frac(ipft)) + end if + elseif(organ_id == repro_organ) then target_c = this%variables(i_cvar)%val(1) if( element_id == nitrogen_element) then - target_m = target_c * prt_params%nitr_recr_stoich(ipft) + target_m = target_c * nc_repro else - target_m = target_c * prt_params%phos_recr_stoich(ipft) + target_m = target_c * pc_repro end if else @@ -1783,11 +2150,15 @@ function GetNutrientTargetCNP(this,element_id,organ_id,stoich_mode) result(targe target_m = target_c * prt_params%phos_stoich_p1(ipft,prt_params%organ_param_id(organ_id)) end if elseif( stoich_mode == stoich_max ) then - if( element_id == nitrogen_element) then - target_m = target_c * prt_params%nitr_stoich_p2(ipft,prt_params%organ_param_id(organ_id)) - else - target_m = target_c * prt_params%phos_stoich_p2(ipft,prt_params%organ_param_id(organ_id)) - end if + !if( element_id == nitrogen_element) then + ! target_m = target_c * prt_params%nitr_stoich_p2(ipft,prt_params%organ_param_id(organ_id)) + !else + ! target_m = target_c * prt_params%phos_stoich_p2(ipft,prt_params%organ_param_id(organ_id)) + !end if + write(fates_log(),*) 'invalid stoichiometry mode specified while getting' + write(fates_log(),*) 'nutrient targets' + write(fates_log(),*) 'stoich_mode: ',stoich_mode + call endrun(msg=errMsg(sourcefile, __LINE__)) else write(fates_log(),*) 'invalid stoichiometry mode specified while getting' write(fates_log(),*) 'nutrient targets' @@ -1795,7 +2166,9 @@ function GetNutrientTargetCNP(this,element_id,organ_id,stoich_mode) result(targe call endrun(msg=errMsg(sourcefile, __LINE__)) end if end if - + + nullify(dbh) + return end function GetNutrientTargetCNP @@ -1803,7 +2176,7 @@ end function GetNutrientTargetCNP ! ===================================================================================== - subroutine ProportionalNutrAllocation(state_m, deficit_m, gain_m, element_id, list) + subroutine ProportionalNutrAllocation(this,deficit_m, gain_m, element_id, list) ! ----------------------------------------------------------------------------------- ! This routine allocates nutrients to a set of organs based on proportional @@ -1812,19 +2185,18 @@ subroutine ProportionalNutrAllocation(state_m, deficit_m, gain_m, element_id, li ! Note: this may or may not be called inside some preferential organ filter. ! ----------------------------------------------------------------------------------- - type(parray_type) :: state_m(:) ! Current mass of nutrient - ! of arbitrary species - ! over some arbitrary set of organs + class(cnp_allom_prt_vartypes) :: this real(r8),intent(inout) :: deficit_m(:) ! Nutrient mass deficit of species ! over set of organs - integer, intent(in) :: list(:) ! List of indices if sparse + integer, intent(in) :: list(:) ! List of organ indices from PRTGenericMod real(r8),intent(inout) :: gain_m ! Total nutrient mass gain to ! work with - integer,intent(in) :: element_id ! Element global index (for debugging) + integer,intent(in) :: element_id ! Element global index ! locals integer :: num_organs - integer :: i,ii + integer :: i,i_org + integer :: i_var real(r8) :: flux real(r8) :: sum_deficit real(r8) :: sum_flux @@ -1832,8 +2204,8 @@ subroutine ProportionalNutrAllocation(state_m, deficit_m, gain_m, element_id, li num_organs = size(list,dim=1) sum_deficit = 0._r8 - do ii = 1, num_organs - i = list(ii) + do i = 1, num_organs + i_org = list(i) sum_deficit = sum_deficit + max(0._r8,deficit_m(i)) end do @@ -1841,11 +2213,14 @@ subroutine ProportionalNutrAllocation(state_m, deficit_m, gain_m, element_id, li sum_flux = min(gain_m, sum_deficit) - do ii = 1, num_organs - i = list(ii) + do i = 1, num_organs + i_org = list(i) + + flux = sum_flux * max(0._r8,deficit_m(i))/sum_deficit + + i_var = prt_global%sp_organ_map(i_org,element_id) + this%variables(i_var)%val(1) = this%variables(i_var)%val(1) + flux - flux = sum_flux * max(0._r8,deficit_m(i))/sum_deficit - state_m(i)%ptr = state_m(i)%ptr + flux deficit_m(i) = deficit_m(i) - flux gain_m = gain_m - flux @@ -1865,192 +2240,6 @@ subroutine ProportionalNutrAllocation(state_m, deficit_m, gain_m, element_id, li return end subroutine ProportionalNutrAllocation - ! ===================================================================================== - - - subroutine NAndPToMatchC(this,c_gain_org,dc_dd,ipft,organ_id,n_match,p_match) - - class(cnp_allom_prt_vartypes) :: this ! - real(r8),intent(in) :: c_gain_org ! Fraction of C sent to this organ - ! (does not include resp tax) - real(r8),intent(in) :: dc_dd ! derivative of the target value - integer, intent(in) :: ipft ! pft index - integer, intent(in) :: organ_id ! global organ index - real(r8), intent(inout) :: n_match ! N needed to match C growth - real(r8), intent(inout) :: p_match ! P needed to match C growth - - integer :: c_var_id ! Data array index of the carbon state variable - integer :: np_var_id ! Data array index of the N and P states - real(r8) :: grow_c ! Amount of C that would go into the organs tissue - real(r8) :: c0,d0 ! Variables to save the original C and dbh states - real(r8) :: np_target ! The target amount of N or P at the future C/DBH - - - ! All states are drawn from index 1, which is the growing index - ! for leaves, and the only index of non-leaves. Remember, if - ! this routine is being called, the initial amount of carbon - ! is the on-allometry value. - - c_var_id = prt_global%sp_organ_map(organ_id,carbon12_element) - - ! Save the current carbon and dbh state (we need dbh also - ! because nutient targets may not queue off of current mass, - ! but off of stature) - - c0 = this%variables(c_var_id)%val(1) - d0 = this%bc_inout(acnp_bc_inout_id_dbh)%rval - - ! Given the desired growth, imagine what the future C and dbh states are - this%variables(c_var_id)%val(1) = this%variables(c_var_id)%val(1)+c_gain_org - - ! Reproductive tissues may not have an allometry curve, their - ! target will be based off of actual C anyway - if(dc_dd>nearzero) then - this%bc_inout(acnp_bc_inout_id_dbh)%rval = & - this%bc_inout(acnp_bc_inout_id_dbh)%rval + c_gain_org/dc_dd - end if - - ! Calculate the nitrogen target at this future - np_var_id = prt_global%sp_organ_map(organ_id,nitrogen_element) - np_target = this%GetNutrientTarget(nitrogen_element,organ_id,stoich_growth_min) - - - ! Determine N needed to get match predicted C - n_match = n_match + max(0._r8, np_target - this%variables(np_var_id)%val(1)) - - - - ! Calculate the phosphorus target at this future - np_var_id = prt_global%sp_organ_map(organ_id,phosphorus_element) - np_target = this%GetNutrientTarget(phosphorus_element,organ_id,stoich_growth_min) - - - ! Determine P needed to get match predicted C - p_match = p_match + max(0._r8, np_target - this%variables(np_var_id)%val(1)) - - - ! Return out predictions back to their initial states - ! Save the current carbon and dbh state - this%variables(c_var_id)%val(1) = c0 - this%bc_inout(acnp_bc_inout_id_dbh)%rval = d0 - - - return - end subroutine NAndPToMatchC - - - - - ! ===================================================================================== - - subroutine GrowEquivC(this,carbon_gain,nitrogen_gain,phosphorus_gain, & - alloc_frac,ipft,organ_id,& - grow_c_from_c,grow_c_from_n,grow_c_from_p) - - ! ----------------------------------------------------------------------------------- - ! This subroutine calculates how much growth to expect in the specified organ - ! in terms of equivalent carbon, for each of C, N and P. - ! Total carbon allocated is roughly a function of how much carbon is available, - ! and the growth respiration tax. - ! Equivalent carbon allocated for each nutrient, is roughly the amount of - ! nutrient available, divided through by its stoichiometry, and also incremented - ! by any extra nutrient that may be in the tissues because of flexible stoich. - ! ----------------------------------------------------------------------------------- - - ! Arguments - class(cnp_allom_prt_vartypes) :: this ! - real(r8),intent(in) :: carbon_gain ! Total carbon available for allocation - real(r8),intent(in) :: nitrogen_gain ! Total N available for allocation - real(r8),intent(in) :: phosphorus_gain ! Total P available for allocation - real(r8),intent(in) :: alloc_frac ! - - integer,intent(in) :: ipft - integer,intent(in) :: organ_id - real(r8),intent(inout) :: grow_c_from_c - real(r8),intent(inout) :: grow_c_from_n - real(r8),intent(inout) :: grow_c_from_p - - ! Locals - real(r8) :: grow_c - real(r8) :: c_from_n_headstart - real(r8) :: c_from_n_gain - real(r8) :: c_from_p_headstart - real(r8) :: c_from_p_gain - integer :: c_var_id - integer :: n_var_id - integer :: p_var_id - real(r8) :: c_state - real(r8) :: n_target - real(r8) :: p_target - - ! Calculate gains from carbon - ! ----------------------------------------------------------------------------------- - grow_c = carbon_gain*alloc_frac - - grow_c_from_c = grow_c_from_c + grow_c - - c_var_id = prt_global%sp_organ_map(organ_id,carbon12_element) - - ! Calculate gains from Nitrogen - ! ----------------------------------------------------------------------------------- - - if(prt_params%nitr_stoich_p1(ipft,prt_params%organ_param_id(organ_id))>nearzero)then - - ! The amount of C we could match with N in the aquisition pool - c_from_n_gain = nitrogen_gain * alloc_frac / prt_params%nitr_stoich_p1(ipft,prt_params%organ_param_id(organ_id)) - - ! It is possible that the nutrient pool of interest is already above the minimum - ! requirement. In this case, we add that into the amount that the equivalent - ! carbon for that nutrient can get. Its like giving it a head start. - - n_var_id = prt_global%sp_organ_map(organ_id,nitrogen_element) - n_target = this%GetNutrientTarget(nitrogen_element,organ_id,stoich_growth_min) - - c_from_n_headstart = max(0.0_r8, sum(this%variables(n_var_id)%val(:),dim=1) - n_target ) / & - prt_params%nitr_stoich_p1(ipft,prt_params%organ_param_id(organ_id)) - - - ! Increment the amount of C that we could match with N, as the minimum - ! of what C could do itself, and what N could do. We need this minimum - ! because some pools may have excess, but those excesses cannot travel between - ! pools and contribute to the total allocation - grow_c_from_n = grow_c_from_n + min(grow_c,c_from_n_gain+c_from_n_headstart) - - - - end if - - ! Calculate gains from phosphorus - ! ----------------------------------------------------------------------------------- - - if(prt_params%phos_stoich_p1(ipft,prt_params%organ_param_id(organ_id))>nearzero) then - - - c_from_p_gain = phosphorus_gain * alloc_frac / prt_params%phos_stoich_p1(ipft,prt_params%organ_param_id(organ_id)) - - ! It is possible that the nutrient pool of interest is already above the minimum - ! requirement. In this case, we add that into the amount that the equivalent - ! carbon for that nutrient can get. Its like giving it a head start. - - p_var_id = prt_global%sp_organ_map(organ_id,phosphorus_element) - p_target = this%GetNutrientTarget(phosphorus_element,organ_id,stoich_growth_min) - - c_from_p_headstart = max(0.0_r8,sum(this%variables(p_var_id)%val(:),dim=1) - p_target ) / & - prt_params%phos_stoich_p1(ipft,prt_params%organ_param_id(organ_id)) - - ! Increment the amount of C that we could match with P, as the minimum - ! of what C could do itself, and what P could do. We need this minimum - ! because some pools may have excess, but those excesses cannot travel between - ! pools and contribute to the total allocation - grow_c_from_p = grow_c_from_p + min(grow_c,c_from_p_gain+c_from_p_headstart) - - - end if - - return - end subroutine GrowEquivC - - ! ===================================================================================== function AllomCNPGrowthDeriv(l_state_array,l_state_mask,cbalance,intgr_params) result(dCdx) @@ -2084,6 +2273,8 @@ function AllomCNPGrowthDeriv(l_state_array,l_state_mask,cbalance,intgr_params) r ! locals integer :: ipft ! PFT index real(r8) :: canopy_trim ! Canopy trimming function (boundary condition [0-1] + integer :: crown_damage ! Damage class + real(r8) :: l2fr ! leaf to fineroot biomass multiplier real(r8) :: leaf_c_target ! target leaf biomass, dummy var (kgC) real(r8) :: fnrt_c_target ! target fine-root biomass, dummy var (kgC) real(r8) :: sapw_c_target ! target sapwood biomass, dummy var (kgC) @@ -2099,10 +2290,12 @@ function AllomCNPGrowthDeriv(l_state_array,l_state_mask,cbalance,intgr_params) r real(r8) :: bgw_dcdd_target ! target BG wood biomass derivative wrt d, (kgC/cm) real(r8) :: store_dcdd_target ! target storage biomass derivative wrt d, (kgC/cm) real(r8) :: struct_dcdd_target ! target structural biomass derivative wrt d, (kgC/cm) - real(r8) :: total_dcdd_target ! target total (not reproductive) biomass derivative wrt d, (kgC/cm) real(r8) :: repro_fraction ! fraction of carbon balance directed towards reproduction (kgC/kgC) real(r8) :: total_dcostdd ! carbon cost for non-reproductive pools per unit increment of dbh - + real(r8) :: elongf_leaf ! Leaf elongation factor (0-1) + real(r8) :: elongf_fnrt ! Fine-root "elongation factor" (0-1) + real(r8) :: elongf_stem ! Stem "elongation factor" (0-1) + associate( dbh => l_state_array(dbh_id), & leaf_c => l_state_array(leaf_id), & @@ -2119,29 +2312,53 @@ function AllomCNPGrowthDeriv(l_state_array,l_state_mask,cbalance,intgr_params) r mask_struct => l_state_mask(struct_id), & mask_repro => l_state_mask(repro_id) ) - - canopy_trim = intgr_params(acnp_bc_in_id_ctrim) - ipft = int(intgr_params(acnp_bc_in_id_pft)) - - call bleaf(dbh,ipft,canopy_trim,leaf_c_target,leaf_dcdd_target) - call bfineroot(dbh,ipft,canopy_trim,fnrt_c_target,fnrt_dcdd_target) - call bsap_allom(dbh,ipft,canopy_trim,sapw_area,sapw_c_target,sapw_dcdd_target) - call bagw_allom(dbh,ipft,agw_c_target,agw_dcdd_target) - call bbgw_allom(dbh,ipft,bgw_c_target,bgw_dcdd_target) + canopy_trim = intgr_params(intgr_parm_ctrim) + ipft = int(intgr_params(intgr_parm_pft)) + l2fr = intgr_params(intgr_parm_l2fr) + crown_damage = int(intgr_params(intgr_parm_cdamage)) + elongf_leaf = intgr_params(intgr_parm_efleaf) + elongf_fnrt = intgr_params(intgr_parm_effnrt) + elongf_stem = intgr_params(intgr_parm_efstem) + + call bleaf(dbh,ipft,crown_damage,canopy_trim, elongf_leaf, leaf_c_target,leaf_dcdd_target) + call bfineroot(dbh,ipft,canopy_trim,l2fr, elongf_fnrt, fnrt_c_target,fnrt_dcdd_target) + call bsap_allom(dbh,ipft,crown_damage,canopy_trim, elongf_stem, sapw_area,sapw_c_target,sapw_dcdd_target) + call bagw_allom(dbh,ipft,crown_damage, elongf_stem,agw_c_target,agw_dcdd_target) + call bbgw_allom(dbh,ipft, elongf_stem,bgw_c_target,bgw_dcdd_target) call bdead_allom(agw_c_target,bgw_c_target, sapw_c_target, ipft, struct_c_target, & agw_dcdd_target, bgw_dcdd_target, sapw_dcdd_target, struct_dcdd_target) - call bstore_allom(dbh,ipft,canopy_trim,store_c_target,store_dcdd_target) + 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) + + ! 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))) else - repro_fraction = prt_params%seed_alloc(ipft) + prt_params%seed_alloc_mature(ipft) - end if - 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 repro_fraction = 0._r8 - end if + end if !mask repro total_dcostdd = 0._r8 if (mask_struct) then @@ -2220,78 +2437,122 @@ function AllomCNPGrowthDeriv(l_state_array,l_state_mask,cbalance,intgr_params) r return end function AllomCNPGrowthDeriv - ! ==================================================================================== - - subroutine TargetAllometryCheck(bleaf,bfroot,bsap,bstore,bdead, & - bt_leaf,bt_froot,bt_sap,bt_store,bt_dead, & - grow_leaf,grow_froot,grow_sapw,grow_store) - - ! Arguments - real(r8),intent(in) :: bleaf !actual - real(r8),intent(in) :: bfroot - real(r8),intent(in) :: bsap - real(r8),intent(in) :: bstore - real(r8),intent(in) :: bdead - real(r8),intent(in) :: bt_leaf !target - real(r8),intent(in) :: bt_froot - real(r8),intent(in) :: bt_sap - real(r8),intent(in) :: bt_store - real(r8),intent(in) :: bt_dead - logical,intent(out) :: grow_leaf !growth flag - logical,intent(out) :: grow_froot - logical,intent(out) :: grow_sapw - logical,intent(out) :: grow_store - - if( (bt_leaf - bleaf)>calloc_abs_error) then - write(fates_log(),*) 'leaves are not on-allometry at the growth step' - write(fates_log(),*) 'exiting',bleaf,bt_leaf - call endrun(msg=errMsg(sourcefile, __LINE__)) - elseif( (bleaf - bt_leaf)>calloc_abs_error) then - ! leaf is above allometry, ignore - grow_leaf = .false. - else - grow_leaf = .true. + ! ===================================================================================== + + + subroutine EstimateGrowthNC(this,target_c,target_dcdd,state_mask,avg_nc,avg_pc) + + ! This routine predicts the effective nutrient/carbon allocation ratio + ! for the forthcoming growth step. This helps the growth step predict + ! which element will be limiting, and reduce the amount of carbon + ! used to make the step. + + class(cnp_allom_prt_vartypes) :: this + real(r8) :: target_c(:) + real(r8) :: target_dcdd(:) + logical :: state_mask(:) + real(r8) :: avg_nc ! Average N:C ratio + real(r8) :: avg_pc ! Average P:C ratio + + real(r8) :: repro_c_frac + real(r8) :: total_w ! Weight (dC/dd) for the ratios + real(r8) :: store_nc + real(r8) :: store_pc + real(r8) :: repro_w,leaf_w,fnrt_w,sapw_w,struct_w,store_w + + associate(dbh => this%bc_inout(acnp_bc_inout_id_dbh)%rval, & + ipft => this%bc_in(acnp_bc_in_id_pft)%ival, & + nc_repro => this%bc_in(acnp_bc_in_id_nc_repro)%rval, & + pc_repro => this%bc_in(acnp_bc_in_id_pc_repro)%rval) + + if(state_mask(repro_id)) then + + ! 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))) + 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 + repro_c_frac = 0._r8 + end if ! state mask + + ! Estimate the total weight + total_w = 0._r8 + avg_nc = 0._r8 + avg_pc = 0._r8 + + if(state_mask(leaf_id)) then + leaf_w = target_dcdd(leaf_organ) * (1._r8 - repro_c_frac) + total_w = total_w + leaf_w + avg_nc = avg_nc + leaf_w * prt_params%nitr_stoich_p1(ipft,prt_params%organ_param_id(leaf_organ)) + avg_pc = avg_pc + leaf_w * prt_params%phos_stoich_p1(ipft,prt_params%organ_param_id(leaf_organ)) end if - - if( (bt_froot - bfroot)>calloc_abs_error) then - write(fates_log(),*) 'fineroots are not on-allometry at the growth step' - write(fates_log(),*) 'exiting',bfroot, bt_froot - call endrun(msg=errMsg(sourcefile, __LINE__)) - elseif( ( bfroot-bt_froot)>calloc_abs_error ) then - grow_froot = .false. - else - grow_froot = .true. + if(state_mask(fnrt_id)) then + fnrt_w = target_dcdd(fnrt_organ) * (1._r8 - repro_c_frac) + total_w = total_w + fnrt_w + avg_nc = avg_nc + fnrt_w * prt_params%nitr_stoich_p1(ipft,prt_params%organ_param_id(fnrt_organ)) + avg_pc = avg_pc + fnrt_w * prt_params%phos_stoich_p1(ipft,prt_params%organ_param_id(fnrt_organ)) end if - - if( (bt_sap - bsap)>calloc_abs_error) then - write(fates_log(),*) 'sapwood is not on-allometry at the growth step' - write(fates_log(),*) 'exiting',bsap, bt_sap - call endrun(msg=errMsg(sourcefile, __LINE__)) - elseif( ( bsap-bt_sap)>calloc_abs_error ) then - grow_sapw = .false. - else - grow_sapw = .true. + if(state_mask(sapw_id)) then + sapw_w = target_dcdd(sapw_organ) * (1._r8 - repro_c_frac) + total_w = total_w + sapw_w + avg_nc = avg_nc + sapw_w * prt_params%nitr_stoich_p1(ipft,prt_params%organ_param_id(sapw_organ)) + avg_pc = avg_pc + sapw_w * prt_params%phos_stoich_p1(ipft,prt_params%organ_param_id(sapw_organ)) end if - - if( (bt_store - bstore)>calloc_abs_error) then - write(fates_log(),*) 'storage is not on-allometry at the growth step' - write(fates_log(),*) 'exiting',bstore,bt_store - call endrun(msg=errMsg(sourcefile, __LINE__)) - elseif( ( bstore-bt_store)>calloc_abs_error ) then - grow_store = .false. - else - grow_store = .true. + if(state_mask(struct_id)) then + struct_w = target_dcdd(struct_organ) * (1._r8 - repro_c_frac) + total_w = total_w + struct_w + avg_nc = avg_nc + struct_w * prt_params%nitr_stoich_p1(ipft,prt_params%organ_param_id(struct_organ)) + avg_pc = avg_pc + struct_w * prt_params%phos_stoich_p1(ipft,prt_params%organ_param_id(struct_organ)) + end if + if(state_mask(store_id)) then + store_w = target_dcdd(store_organ) * (1._r8 - repro_c_frac) + total_w = total_w + store_w + store_nc = this%GetNutrientTarget(nitrogen_element,store_organ,stoich_growth_min) / target_c(store_organ) + store_pc = this%GetNutrientTarget(phosphorus_element,store_organ,stoich_growth_min) / target_c(store_organ) + avg_nc = avg_nc + store_w * store_nc + avg_pc = avg_pc + store_w * store_pc end if - if( (bt_dead - bdead)>calloc_abs_error) then - write(fates_log(),*) 'structure not on-allometry at the growth step' - write(fates_log(),*) 'exiting',bdead,bt_dead - call endrun(msg=errMsg(sourcefile, __LINE__)) + if(state_mask(repro_id)) then + + ! repro_w = total*repro_c_frac + ! repro_w = (total_w + repro_w)*repro_c_frac = total_w*repro_c_frac + repro_w*repro_c_frac + ! repro_w * (1 - repro_c_frac) = total_w*repro_c_frac + ! repro_w = total_w * repro_c_frac/(1-repro_c_frac) + + repro_w = total_w * repro_c_frac/(1._r8 - repro_c_frac) + total_w = total_w + repro_w + avg_nc = avg_nc + repro_w * nc_repro + avg_pc = avg_pc + repro_w * pc_repro end if - end subroutine TargetAllometryCheck - + avg_nc = avg_nc / total_w + avg_pc = avg_pc / total_w + + end associate + + return + end subroutine EstimateGrowthNC - - end module PRTAllometricCNPMod diff --git a/parteh/PRTAllometricCarbonMod.F90 b/parteh/PRTAllometricCarbonMod.F90 index 5bdf624502..8a732b24c7 100644 --- a/parteh/PRTAllometricCarbonMod.F90 +++ b/parteh/PRTAllometricCarbonMod.F90 @@ -34,7 +34,6 @@ module PRTAllometricCarbonMod use FatesAllometryMod , only : bagw_allom use FatesAllometryMod , only : h_allom use FatesAllometryMod , only : CheckIntegratedAllometries - use FatesAllometryMod , only : ForceDBH use FatesGlobals , only : endrun => fates_endrun use FatesGlobals , only : fates_log @@ -42,14 +41,28 @@ 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 + 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 use FatesConstantsMod , only : calloc_abs_error 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 + + use FatesConstantsMod , only : leaves_on + use FatesConstantsMod , only : leaves_off + use FatesConstantsMod , only : leaves_shedding + use FatesConstantsMod , only : ihard_stress_decid + use FatesConstantsMod , only : isemi_stress_decid implicit none private @@ -87,14 +100,20 @@ module PRTAllometricCarbonMod integer, public, parameter :: ac_bc_inout_id_dbh = 1 ! Plant DBH integer, public, parameter :: ac_bc_inout_id_netdc = 2 ! Index for the net daily C input BC + integer, parameter :: num_bc_inout = 2 ! Number of in & output boundary conditions - integer, public, parameter :: ac_bc_in_id_pft = 1 ! Index for the PFT input BC - integer, public, parameter :: ac_bc_in_id_ctrim = 2 ! Index for the canopy trim function - integer, public, parameter :: ac_bc_in_id_lstat = 3 ! Leaf status (on or off) - integer, parameter :: num_bc_in = 3 ! Number of input boundary conditions + integer, public, parameter :: ac_bc_in_id_pft = 1 ! Index for the PFT input BC + integer, public, parameter :: ac_bc_in_id_ctrim = 2 ! Index for the canopy trim function + integer, public, parameter :: ac_bc_in_id_lstat = 3 ! Leaf status (on, off, partial abscission) + integer, public, parameter :: ac_bc_in_id_cdamage = 4 ! Index for the crowndamage input BC + integer, public, parameter :: ac_bc_in_id_efleaf = 5 ! Elongation factor (leaves) + integer, public, parameter :: ac_bc_in_id_effnrt = 6 ! "Elongation factor" (fine roots) + integer, public, parameter :: ac_bc_in_id_efstem = 7 ! "Elongation factor" (stem) + integer, parameter :: num_bc_in = 7 ! Number of input boundary conditions + ! THere are no purely output boundary conditions integer, parameter :: num_bc_out = 0 ! Number of purely output boundary condtions @@ -114,7 +133,7 @@ module PRTAllometricCarbonMod ! ------------------------------------------------------------------------------------- - type, public, extends(prt_vartypes) :: callom_prt_vartypes + type, public, extends(prt_vartypes) :: callom_prt_vartypes contains @@ -144,7 +163,7 @@ module PRTAllometricCarbonMod public :: InitPRTGlobalAllometricCarbon -contains + contains subroutine InitPRTGlobalAllometricCarbon() @@ -238,7 +257,7 @@ end subroutine InitPRTGlobalAllometricCarbon ! ===================================================================================== - subroutine DailyPRTAllometricCarbon(this) + subroutine DailyPRTAllometricCarbon(this,phase) ! ----------------------------------------------------------------------------------- ! @@ -280,22 +299,25 @@ subroutine DailyPRTAllometricCarbon(this) ! ! ---------------------------------------------------------------------------------- - - ! The class is the only argument + class(callom_prt_vartypes) :: this ! this class + integer,intent(in) :: phase ! the phase splits the routine into parts + ! ----------------------------------------------------------------------------------- ! These are local copies of the in/out boundary condition structure ! ----------------------------------------------------------------------------------- real(r8),pointer :: dbh ! Diameter at breast height [cm] - ! this local will point to both in and out bc's + ! this local will point to both in and out bc's real(r8),pointer :: carbon_balance ! Daily carbon balance for this cohort [kgC] + integer :: crowndamage ! which crown damage class + + real(r8) :: canopy_trim ! The canopy trimming function [0-1] integer :: ipft ! Plant Functional Type index - real(r8) :: target_leaf_c ! target leaf carbon [kgC] real(r8) :: target_fnrt_c ! target fine-root carbon [kgC] real(r8) :: target_sapw_c ! target sapwood carbon [kgC] @@ -313,6 +335,9 @@ subroutine DailyPRTAllometricCarbon(this) real(r8) :: struct_below_target ! dead (structural) biomass below target amount [kgC] real(r8) :: total_below_target ! total biomass below the allometric target [kgC] + real(r8) :: allocation_factor ! allocation factor (relative to demand) to + ! reconstruct tissues + real(r8) :: flux_adj ! adjustment made to growth flux term to minimize error [kgC] real(r8) :: store_target_fraction ! ratio between storage and leaf biomass when on allometry [kgC] @@ -331,26 +356,29 @@ subroutine DailyPRTAllometricCarbon(this) real(r8),dimension(max_nleafage) :: leaf_c0 - ! Initial value of carbon used to determine net flux + ! Initial value of carbon used to determine net flux real(r8) :: fnrt_c0 ! during this routine real(r8) :: sapw_c0 ! "" real(r8) :: store_c0 ! "" real(r8) :: repro_c0 ! "" real(r8) :: struct_c0 ! "" + logical :: is_hydecid_dormant ! Flag to signal that the cohort is drought deciduous and dormant + logical :: is_deciduous ! Flag to signal this is a deciduous PFT + logical :: grow_struct logical :: grow_leaf ! Are leaves at allometric target and should be grown? logical :: grow_fnrt ! Are fine-roots at allometric target and should be grown? logical :: grow_sapw ! Is sapwood at allometric target and should be grown? logical :: grow_store ! Is storage at allometric target and should be grown? - ! integrator variables + ! integrator variables real(r8) :: deltaC ! trial value for substep integer :: ierr ! error flag for allometric growth step integer :: nsteps ! number of sub-steps integer :: istep ! current substep index real(r8) :: totalC ! total carbon allocated over alometric growth step - real(r8) :: hite_out ! dummy height variable + real(r8) :: height_out ! dummy height variable integer :: i_var ! index for iterating state variables integer :: i_age ! index for iterating leaf ages @@ -358,6 +386,9 @@ subroutine DailyPRTAllometricCarbon(this) integer :: leaf_status ! are leaves on (2) or off (1) real(r8) :: leaf_age_flux ! carbon mass flux between leaf age classification pools + real(r8) :: elongf_leaf ! Leaf elongation factor + real(r8) :: elongf_fnrt ! Fine-root "elongation factor" + real(r8) :: elongf_stem ! Stem "elongation factor" ! Integegrator variables c_pool is "mostly" carbon variables, it also includes ! dbh... @@ -374,491 +405,575 @@ subroutine DailyPRTAllometricCarbon(this) integer, parameter :: ODESolve = 2 ! 1=RKF45, 2=Euler integer, parameter :: iexp_leaf = 1 ! index 1 is the expanding (i.e. youngest) - ! leaf age class, and therefore - ! all new allocation goes into that pool - - real(r8) :: intgr_params(num_bc_in) ! The boundary conditions to this routine, - ! are pressed into an array that is also - ! passed to the integrators - - associate( & - leaf_c => this%variables(leaf_c_id)%val, & - fnrt_c => this%variables(fnrt_c_id)%val(icd), & - sapw_c => this%variables(sapw_c_id)%val(icd), & - store_c => this%variables(store_c_id)%val(icd), & - repro_c => this%variables(repro_c_id)%val(icd), & - struct_c => this%variables(struct_c_id)%val(icd)) + ! leaf age class, and therefore + ! all new allocation goes into that pool + character(len= 9), parameter :: fmti = '(a,1x,i5)' + character(len=13), parameter :: fmt0 = '(a,1x,es12.5)' + character(len=19), parameter :: fmth = '(a,1x,a5,3(1x,a12))' + character(len=22), parameter :: fmtg = '(a,5x,l1,3(1x,es12.5))' + + ! The boundary conditions to this routine, + ! are pressed into an array that is also + ! passed to the integrators + ! add one because we pass crown damage also + ! which is not a bc_in + + real(r8) :: intgr_params(num_bc_in) ! ----------------------------------------------------------------------------------- ! 0. ! Copy the boundary conditions into readable local variables. - ! We don't use pointers for bc's that ar "in" only, only "in-out" and "out" + ! We don't use pointers for bc's that are "in" only, only "in-out" and "out" ! ----------------------------------------------------------------------------------- - - dbh => this%bc_inout(ac_bc_inout_id_dbh)%rval - carbon_balance => this%bc_inout(ac_bc_inout_id_netdc)%rval - - canopy_trim = this%bc_in(ac_bc_in_id_ctrim)%rval - ipft = this%bc_in(ac_bc_in_id_pft)%ival - leaf_status = this%bc_in(ac_bc_in_id_lstat)%ival - - intgr_params(:) = un_initialized - intgr_params(ac_bc_in_id_ctrim) = this%bc_in(ac_bc_in_id_ctrim)%rval - intgr_params(ac_bc_in_id_pft) = real(this%bc_in(ac_bc_in_id_pft)%ival) - - + ipft = this%bc_in(ac_bc_in_id_pft)%ival + canopy_trim = this%bc_in(ac_bc_in_id_ctrim)%rval + leaf_status = this%bc_in(ac_bc_in_id_lstat)%ival + crowndamage = this%bc_in(ac_bc_in_id_cdamage)%ival + elongf_leaf = this%bc_in(ac_bc_in_id_efleaf)%rval + elongf_fnrt = this%bc_in(ac_bc_in_id_effnrt)%rval + elongf_stem = this%bc_in(ac_bc_in_id_efstem)%rval + !--- Set some logical flags to simplify "if" blocks + is_hydecid_dormant = any(prt_params%stress_decid(ipft) == [ihard_stress_decid,isemi_stress_decid] ) & + .and. any(leaf_status == [leaves_off,leaves_shedding] ) + is_deciduous = any(prt_params%stress_decid(ipft) == [ihard_stress_decid,isemi_stress_decid] ) & + .or. ( prt_params%season_decid(ipft) == itrue ) nleafage = prt_global%state_descriptor(leaf_c_id)%num_pos ! Number of leaf age class - ! ----------------------------------------------------------------------------------- - ! Call the routine that advances leaves in age. - ! This will move a portion of the leaf mass in each - ! age bin, to the next bin. This will not handle movement - ! of mass from the oldest bin into the litter pool, that is something else. - ! ----------------------------------------------------------------------------------- - - call this%AgeLeaves(ipft,sec_per_day) - - ! ----------------------------------------------------------------------------------- - ! I. Remember the values for the state variables at the beginning of this - ! routines. We will then use that to determine their net allocation and reactive - ! transport flux "%net_alloc" at the end. - ! ----------------------------------------------------------------------------------- - - leaf_c0(1:nleafage) = leaf_c(1:nleafage) ! Set initial leaf carbon - fnrt_c0 = fnrt_c ! Set initial fine-root carbon - sapw_c0 = sapw_c ! Set initial sapwood carbon - store_c0 = store_c ! Set initial storage carbon - repro_c0 = repro_c ! Set initial reproductive carbon - struct_c0 = struct_c ! Set initial structural carbon - - - ! ----------------------------------------------------------------------------------- - ! II. Calculate target size of the biomass compartment for a given dbh. - ! ----------------------------------------------------------------------------------- - - ! Target sapwood biomass according to allometry and trimming [kgC] - call bsap_allom(dbh,ipft,canopy_trim,sapw_area,target_sapw_c) - - ! Target total above ground biomass in woody/fibrous tissues [kgC] - call bagw_allom(dbh,ipft,target_agw_c) - - ! Target total below ground biomass in woody/fibrous tissues [kgC] - call bbgw_allom(dbh,ipft,target_bgw_c) - - ! Target total dead (structrual) biomass [kgC] - call bdead_allom( target_agw_c, target_bgw_c, target_sapw_c, ipft, target_struct_c) - - ! Target leaf biomass according to allometry and trimming - if(leaf_status==2) then - call bleaf(dbh,ipft,canopy_trim,target_leaf_c) - else - target_leaf_c = 0._r8 - end if - - ! Target fine-root biomass and deriv. according to allometry and trimming [kgC, kgC/cm] - call bfineroot(dbh,ipft,canopy_trim,target_fnrt_c) - - ! Target storage carbon [kgC,kgC/cm] - call bstore_allom(dbh,ipft,canopy_trim,target_store_c) - - - ! ----------------------------------------------------------------------------------- - ! III. Prioritize some amount of carbon to replace leaf/root turnover - ! Make sure it isnt a negative payment, and either pay what is available - ! or forcefully pay from storage. - ! ----------------------------------------------------------------------------------- - - if( prt_params%evergreen(ipft) ==1 ) then - leaf_c_demand = max(0.0_r8, & - prt_params%leaf_stor_priority(ipft)*sum(this%variables(leaf_c_id)%turnover(:))) - else - leaf_c_demand = 0.0_r8 - end if - - fnrt_c_demand = max(0.0_r8, & - prt_params%leaf_stor_priority(ipft)*this%variables(fnrt_c_id)%turnover(icd)) - - total_c_demand = leaf_c_demand + fnrt_c_demand - - if (total_c_demand> nearzero ) then - - ! We pay this even if we don't have the carbon - ! Just don't pay so much carbon that storage+carbon_balance can't pay for it - - leaf_c_flux = min(leaf_c_demand, & - max(0.0_r8,(store_c+carbon_balance)* & - (leaf_c_demand/total_c_demand))) - - ! Add carbon to the youngest age pool (i.e iexp_leaf = index 1) - carbon_balance = carbon_balance - leaf_c_flux - leaf_c(iexp_leaf) = leaf_c(iexp_leaf) + leaf_c_flux - - ! If we are testing b4b, then we pay this even if we don't have the carbon - fnrt_c_flux = min(fnrt_c_demand, & - max(0.0_r8, (store_c+carbon_balance)* & - (fnrt_c_demand/total_c_demand))) - - carbon_balance = carbon_balance - fnrt_c_flux - fnrt_c = fnrt_c + fnrt_c_flux - - end if ! ----------------------------------------------------------------------------------- - ! IV. if carbon balance is negative, re-coup the losses from storage - ! if it is positive, give some love to storage carbon + ! 1/2. Use pointers and associations to create simpler names inside the sub-routine. + ! MLO. Any reason to use associate for some variables and pointers for others? ! ----------------------------------------------------------------------------------- + associate( & + leaf_c => this%variables(leaf_c_id)%val, & + fnrt_c => this%variables(fnrt_c_id)%val(icd), & + sapw_c => this%variables(sapw_c_id)%val(icd), & + store_c => this%variables(store_c_id)%val(icd), & + repro_c => this%variables(repro_c_id)%val(icd), & + struct_c => this%variables(struct_c_id)%val(icd), & + l2fr => prt_params%allom_l2fr(ipft) ) + + dbh => this%bc_inout(ac_bc_inout_id_dbh)%rval + carbon_balance => this%bc_inout(ac_bc_inout_id_netdc)%rval + + + + + ! ----------------------------------------------------------------------------------- + ! I. Remember the values for the state variables at the beginning of this + ! routines. We will then use that to determine their net allocation and reactive + ! transport flux "%net_alloc" at the end. + ! ----------------------------------------------------------------------------------- + + leaf_c0(1:nleafage) = leaf_c(1:nleafage) ! Set initial leaf carbon + fnrt_c0 = fnrt_c ! Set initial fine-root carbon + sapw_c0 = sapw_c ! Set initial sapwood carbon + store_c0 = store_c ! Set initial storage carbon + repro_c0 = repro_c ! Set initial reproductive carbon + struct_c0 = struct_c ! Set initial structural carbon + + ! ----------------------------------------------------------------------------------- + ! II. Calculate target size of the biomass compartment for a given dbh. + ! ----------------------------------------------------------------------------------- + + ! Target sapwood biomass according to allometry and trimming [kgC] + call bsap_allom(dbh,ipft, crowndamage, canopy_trim, elongf_stem, sapw_area,target_sapw_c) + + ! Target total above ground biomass in woody/fibrous tissues [kgC] + call bagw_allom(dbh,ipft, crowndamage, elongf_stem, target_agw_c) + + ! Target total below ground biomass in woody/fibrous tissues [kgC] + call bbgw_allom(dbh,ipft, elongf_stem, target_bgw_c) + + ! Target total dead (structrual) biomass [kgC] + call bdead_allom( target_agw_c, target_bgw_c, target_sapw_c, ipft, target_struct_c) + + ! Target leaf biomass according to allometry and trimming + call bleaf(dbh,ipft,crowndamage,canopy_trim, elongf_leaf, target_leaf_c) + + ! Target fine-root biomass and deriv. according to allometry and trimming [kgC, kgC/cm] + call bfineroot(dbh,ipft,canopy_trim,l2fr, elongf_fnrt, target_fnrt_c) + + ! Target storage carbon [kgC,kgC/cm] + call bstore_allom(dbh,ipft,crowndamage,canopy_trim,target_store_c) + + + ! ----------------------------------------------------------------------------------- + ! II 1/2. Update target biomass based on the leaf elongation factor and the abscission + ! fraction for each non-leaf tissue. Elongation factor is binary for + ! cold-deciduous and original drought-deciduous, and always one for + ! evergreens. In case the plant is shedding leaves, we impose that any + ! positive carbon balance necessarily goes to storage, even if this causes + ! storage to go above allometry. + ! ----------------------------------------------------------------------------------- + if (is_hydecid_dormant) then + target_leaf_c = 0.0_r8 + target_fnrt_c = 0.0_r8 + target_sapw_c = 0.0_r8 + target_struct_c = 0.0_r8 + target_store_c = target_store_c + max(0.0_r8,carbon_balance) + end if + + + + ! ----------------------------------------------------------------------------------- + ! The following blocks will allocate carbon + ! ----------------------------------------------------------------------------------- + select_phase: select case (phase) + case(1) + ! ----------------------------------------------------------------------------------- + ! Phase 1: Replace losses, push pools towards targets + ! ----------------------------------------------------------------------------------- + + + ! ----------------------------------------------------------------------------------- + ! III. Prioritize some amount of carbon to replace leaf/root turnover + ! Make sure it isn't a negative payment, and either pay what is available + ! or forcefully pay from storage. + ! MLO. Added a few conditions to decide what to do in case plants are deciduous. + ! Specifically, drought deciduous with leaves off should not replace fine + ! roots. They will be in negative carbon balance, and unlike cold deciduous, + ! the turnover rates will be high during the dry season (turnover is + ! temperature-dependent, but not moisture-dependent). Allocating carbon + ! to high-maintanence tissues will drain the storage with little benefit for + ! these plants. + ! ----------------------------------------------------------------------------------- + if ( is_hydecid_dormant ) then + ! Drought deciduous, dormant state. Set demands to both leaves and roots to zero. + leaf_c_demand = 0.0_r8 + fnrt_c_demand = 0.0_r8 + elseif ( is_deciduous ) then + ! Either cold deciduous plant, or drought deciduous with leaves on. Maintain roots. + leaf_c_demand = 0.0_r8 + fnrt_c_demand = max(0.0_r8, & + prt_params%leaf_stor_priority(ipft)*this%variables(fnrt_c_id)%turnover(icd)) + else + ! Evergreen PFT. Try to meet demands for both leaves and fine roots. + ! If this is not evergreen, this PFT isn't expected by FATES, and we assume + ! evergreen. + leaf_c_demand = max(0.0_r8, & + prt_params%leaf_stor_priority(ipft)*sum(this%variables(leaf_c_id)%turnover(:))) + fnrt_c_demand = max(0.0_r8, & + prt_params%leaf_stor_priority(ipft)*this%variables(fnrt_c_id)%turnover(icd)) + end if + + total_c_demand = leaf_c_demand + fnrt_c_demand + + if (total_c_demand > nearzero) then + + ! We pay this even if we don't have the carbon + ! Just don't pay so much carbon that storage+carbon_balance can't pay for it + allocation_factor = max(0.0_r8,min(1.0_r8,(store_c+carbon_balance)/total_c_demand)) + + ! MLO. Edited the code to switch the order of operations. The previous code would + ! subtract leaf flux from carbon balance before estimating the fine root flux, + ! potentially allowing less fluxes to fine roots than possible. + leaf_c_flux = leaf_c_demand * allocation_factor + fnrt_c_flux = fnrt_c_demand * allocation_factor + + ! Add carbon to the youngest age pool (i.e iexp_leaf = index 1) and fine roots + leaf_c(iexp_leaf) = leaf_c(iexp_leaf) + leaf_c_flux + fnrt_c = fnrt_c + fnrt_c_flux + + ! Remove fluxes from carbon balance. In case we may have drawn carbon from storage, + ! carbon_balance will become negative, in which case we will deplete carbon from + ! storage in the next step. + carbon_balance = carbon_balance - ( leaf_c_flux + fnrt_c_flux ) + end if + + ! ----------------------------------------------------------------------------------- + ! IV. if carbon balance is negative, re-coup the losses from storage + ! if it is positive, give some love to storage carbon + ! ----------------------------------------------------------------------------------- + + if( carbon_balance < 0.0_r8 ) then + + ! Store_c_flux will be negative, so store_c will be depleted + store_c_flux = carbon_balance + carbon_balance = carbon_balance - store_c_flux + store_c = store_c + store_c_flux + + else + + ! Accumulate some carbon in storage. If storage is completely depleted, aim to + ! increase storage, but not to replenish completely so we can still use some + ! carbon for growth. + store_below_target = max(0.0_r8,target_store_c - store_c) + store_target_fraction = max(0.0_r8, store_c/target_store_c ) + + store_c_flux = min(store_below_target,carbon_balance * & + max(exp(-1.*store_target_fraction**4._r8) - exp( -1.0_r8 ),0.0_r8)) + + ! Move carbon from carbon balance to storage + carbon_balance = carbon_balance - store_c_flux + store_c = store_c + store_c_flux + + end if + + case (2) + + ! ----------------------------------------------------------------------------------- + ! V. If carbon is still available, prioritize some allocation to replace + ! the rest of the leaf/fineroot deficit + ! carbon balance is guaranteed to be >=0 beyond this point + ! MLO. Renamed demand with below target to make it consistent with the + ! definitions at the variable declaration part. + ! ----------------------------------------------------------------------------------- + + leaf_below_target = max(0.0_r8,target_leaf_c - sum(leaf_c(1:nleafage))) + fnrt_below_target = max(0.0_r8,target_fnrt_c - fnrt_c) + + total_below_target = leaf_below_target + fnrt_below_target + + if ( (carbon_balance > nearzero) .and. (total_below_target > nearzero) ) then + ! Find fraction of carbon to be allocated to leaves and fine roots + allocation_factor = min(1.0_r8, carbon_balance / total_below_target) + + ! MLO. Edited the code to switch the order of operations. The previous code would + ! subtract leaf flux from carbon balance before estimating the fine root flux, + ! potentially allowing less fluxes to fine roots than possible. + leaf_c_flux = leaf_below_target * allocation_factor + fnrt_c_flux = fnrt_below_target * allocation_factor + + leaf_c(iexp_leaf) = leaf_c(iexp_leaf) + leaf_c_flux + fnrt_c = fnrt_c + fnrt_c_flux + + carbon_balance = carbon_balance - ( leaf_c_flux + fnrt_c_flux ) + + end if + + ! ----------------------------------------------------------------------------------- + ! VI. If carbon is still available, we try to push all live + ! pools back towards allometry. But only upwards, if fusion happened + ! to generate some pools above allometric target, don't reduce the pool, + ! just ignore it until the rest of the plant grows to meet it. + ! ----------------------------------------------------------------------------------- + if( carbon_balance > nearzero ) then - if( carbon_balance < 0.0_r8 ) then - - store_c_flux = carbon_balance - carbon_balance = carbon_balance - store_c_flux - store_c = store_c + store_c_flux + leaf_below_target = max(target_leaf_c - sum(leaf_c(1:nleafage)),0.0_r8) + fnrt_below_target = max(target_fnrt_c - fnrt_c,0.0_r8) + sapw_below_target = max(target_sapw_c - sapw_c,0.0_r8) + store_below_target = max(target_store_c - store_c,0.0_r8) - else + total_below_target = leaf_below_target + fnrt_below_target + & + sapw_below_target + store_below_target - store_below_target = max(target_store_c - store_c,0.0_r8) - store_target_fraction = max(0.0_r8, store_c/target_store_c ) + if ( total_below_target > nearzero ) then + ! Find allocation factor based on available carbon and total demand to meet target. + allocation_factor = min(1.0_r8, carbon_balance / total_below_target) - store_c_flux = min(store_below_target,carbon_balance * & - max(exp(-1.*store_target_fraction**4._r8) - exp( -1.0_r8 ),0.0_r8)) + ! Find fluxes to individual pools + leaf_c_flux = leaf_below_target * allocation_factor + fnrt_c_flux = fnrt_below_target * allocation_factor + sapw_c_flux = sapw_below_target * allocation_factor + store_c_flux = store_below_target * allocation_factor - carbon_balance = carbon_balance - store_c_flux - store_c = store_c + store_c_flux + leaf_c(iexp_leaf) = leaf_c(iexp_leaf) + leaf_c_flux + fnrt_c = fnrt_c + fnrt_c_flux + sapw_c = sapw_c + sapw_c_flux + store_c = store_c + store_c_flux - end if + carbon_balance = carbon_balance - & + ( leaf_c_flux + fnrt_c_flux + sapw_c_flux + store_c_flux ) + end if + end if - ! ----------------------------------------------------------------------------------- - ! V. If carbon is still available, prioritize some allocation to replace - ! the rest of the leaf/fineroot deficit - ! carbon balance is guaranteed to be >=0 beyond this point - ! ----------------------------------------------------------------------------------- - - leaf_c_demand = max(0.0_r8,(target_leaf_c - sum(leaf_c(1:nleafage)))) - fnrt_c_demand = max(0.0_r8,(target_fnrt_c - fnrt_c)) + ! ----------------------------------------------------------------------------------- + ! VII. If carbon is still available, replenish the structural pool to get + ! back on allometry + ! ----------------------------------------------------------------------------------- - total_c_demand = leaf_c_demand + fnrt_c_demand - - if( (carbon_balance > nearzero ) .and. (total_c_demand>nearzero)) then + if( carbon_balance > nearzero ) then - leaf_c_flux = min(leaf_c_demand, & - carbon_balance*(leaf_c_demand/total_c_demand)) - carbon_balance = carbon_balance - leaf_c_flux - leaf_c(iexp_leaf) = leaf_c(iexp_leaf) + leaf_c_flux - - fnrt_c_flux = min(fnrt_c_demand, & - carbon_balance*(fnrt_c_demand/total_c_demand)) - carbon_balance = carbon_balance - fnrt_c_flux - fnrt_c = fnrt_c + fnrt_c_flux + struct_below_target = max(target_struct_c - struct_c ,0.0_r8) - end if + if ( struct_below_target > 0.0_r8) then - ! ----------------------------------------------------------------------------------- - ! VI. If carbon is still available, we try to push all live - ! pools back towards allometry. But only upwards, if fusion happened - ! to generate some pools above allometric target, don't reduce the pool, - ! just ignore it until the rest of the plant grows to meet it. - ! ----------------------------------------------------------------------------------- - if( carbon_balance > nearzero ) then - - leaf_below_target = max(target_leaf_c - sum(leaf_c(1:nleafage)),0.0_r8) - fnrt_below_target = max(target_fnrt_c - fnrt_c,0.0_r8) - sapw_below_target = max(target_sapw_c - sapw_c,0.0_r8) - store_below_target = max(target_store_c - store_c,0.0_r8) - - total_below_target = leaf_below_target + fnrt_below_target + & - sapw_below_target + store_below_target - - if ( total_below_target > nearzero ) then - - if( total_below_target > carbon_balance) then - leaf_c_flux = carbon_balance * leaf_below_target/total_below_target - fnrt_c_flux = carbon_balance * fnrt_below_target/total_below_target - sapw_c_flux = carbon_balance * sapw_below_target/total_below_target - store_c_flux = carbon_balance * store_below_target/total_below_target - else - leaf_c_flux = leaf_below_target - fnrt_c_flux = fnrt_below_target - sapw_c_flux = sapw_below_target - store_c_flux = store_below_target - end if - - carbon_balance = carbon_balance - leaf_c_flux - leaf_c(iexp_leaf) = leaf_c(iexp_leaf) + leaf_c_flux - - carbon_balance = carbon_balance - fnrt_c_flux - fnrt_c = fnrt_c + fnrt_c_flux - - carbon_balance = carbon_balance - sapw_c_flux - sapw_c = sapw_c + sapw_c_flux - - carbon_balance = carbon_balance - store_c_flux - store_c = store_c + store_c_flux - - end if - end if - - ! ----------------------------------------------------------------------------------- - ! VII. If carbon is still available, replenish the structural pool to get - ! back on allometry - ! ----------------------------------------------------------------------------------- + struct_c_flux = min(carbon_balance,struct_below_target) + carbon_balance = carbon_balance - struct_c_flux + struct_c = struct_c + struct_c_flux - if( carbon_balance > nearzero ) then - - struct_below_target = max(target_struct_c - struct_c ,0.0_r8) - - if ( struct_below_target > 0.0_r8) then - - struct_c_flux = min(carbon_balance,struct_below_target) - carbon_balance = carbon_balance - struct_c_flux - struct_c = struct_c + struct_c_flux - - end if - - end if - - ! ----------------------------------------------------------------------------------- - ! VIII. If carbon is yet still available ... - ! Our pools are now either on allometry or above (from fusion). - ! We we can increment those pools at or below, - ! including structure and reproduction according to their rates - ! Use an adaptive euler integration. If the error is not nominal, - ! the carbon balance sub-step (deltaC) will be halved and tried again - ! - ! Note that we compare against calloc_abs_error here because it is possible - ! that all the carbon was effectively used up, but a miniscule amount - ! remains due to numerical precision (ie -20 or so), so even though - ! the plant has not been brought to be "on allometry", it thinks it has carbon - ! left to allocate, and thus it must be on allometry when its not. - ! ----------------------------------------------------------------------------------- - - if_stature_growth: if( carbon_balance > calloc_abs_error ) then - - ! This routine checks that actual carbon is not below that targets. It does - ! allow actual pools to be above the target, and in these cases, it sends - ! a false on the "grow_<>" flag, allowing the plant to grow into these pools. - ! It also checks to make sure that structural biomass is not above the target. - - if( (target_store_c - store_c)>calloc_abs_error) then - write(fates_log(),*) 'storage is not on-allometry at the growth step' - write(fates_log(),*) 'exiting' - write(fates_log(),*) 'cbal: ',carbon_balance - write(fates_log(),*) 'near-zero',nearzero - write(fates_log(),*) 'store_c: ',store_c - write(fates_log(),*) 'target c: ',target_store_c - write(fates_log(),*) 'store_c0:', store_c0 - call endrun(msg=errMsg(sourcefile, __LINE__)) - end if - - - call TargetAllometryCheck(sum(leaf_c(1:nleafage)), fnrt_c, sapw_c, & - store_c, struct_c, & - target_leaf_c, target_fnrt_c, & - target_sapw_c, target_store_c, target_struct_c, & - grow_struct, grow_leaf, grow_fnrt, grow_sapw, grow_store) - - ! -------------------------------------------------------------------------------- - ! The numerical integration of growth requires that the instantaneous state - ! variables are passed in as an array. We call it "c_pool". - ! - ! Initialize the adaptive integrator arrays and flags - ! -------------------------------------------------------------------------------- - - ierr = 1 - totalC = carbon_balance - nsteps = 0 - - c_pool(:) = 0.0_r8 ! Zero state variable array - c_mask(:) = .false. ! This mask tells the integrator - ! which indices are active. Its possible - ! that due to fusion, or previous numerical - ! truncation errors, that one of these pools - ! may be larger than its target! We check - ! this, and if true, then we flag that - ! pool to be ignored. c_mask(i) = .false. - ! For grasses, since they don't grow very - ! large and thus won't accumulate such large - ! errors, we always mask as true. - - c_pool(leaf_c_id) = sum(leaf_c(1:nleafage)) - c_pool(fnrt_c_id) = fnrt_c - c_pool(sapw_c_id) = sapw_c - c_pool(store_c_id) = store_c - c_pool(struct_c_id) = struct_c - c_pool(repro_c_id) = repro_c - c_pool(dbh_id) = dbh - - ! Only grow leaves if we are in a "leaf-on" status - if(leaf_status==2) then - c_mask(leaf_c_id) = grow_leaf - else - c_mask(leaf_c_id) = .false. - end if - c_mask(fnrt_c_id) = grow_fnrt - c_mask(sapw_c_id) = grow_sapw - c_mask(store_c_id) = grow_store - c_mask(struct_c_id) = grow_struct - c_mask(repro_c_id) = .true. ! Always calculate reproduction on growth - c_mask(dbh_id) = .true. ! Always increment dbh on growth step - - - ! When using the Euler method, we keep things simple. We always try - ! to make the first integration step to span the entirety of the integration - ! window for the independent variable (available carbon) - - if(ODESolve == 2) then - this%ode_opt_step = totalC - end if - - do_solve_check: do while( ierr .ne. 0 ) - - deltaC = min(totalC,this%ode_opt_step) - if(ODESolve == 1) then - call RKF45(AllomCGrowthDeriv,c_pool,c_mask,deltaC,totalC, & - max_trunc_error,intgr_params,c_pool_out,this%ode_opt_step,step_pass) - - elseif(ODESolve == 2) then - call Euler(AllomCGrowthDeriv,c_pool,c_mask,deltaC,totalC,intgr_params,c_pool_out) - ! step_pass = .true. - - ! When integrating along the allometric curve, we have the luxury of perfect - ! hindsite. Ie, after we have made our step, we can see if the amount - ! of each carbon we have matches the target associated with the new dbh. - ! The following call evaluates how close we are to the allometically defined - ! targets. If we are too far (governed by max_trunc_error), then we - ! pass back the pass/fail flag (step_pass) as false. If false, then - ! we halve the step-size, and then retry. If that step was fine, then - ! we remember the current step size as a good next guess. - - call CheckIntegratedAllometries(c_pool_out(dbh_id),ipft,canopy_trim, & - c_pool_out(leaf_c_id), c_pool_out(fnrt_c_id), c_pool_out(sapw_c_id), & - c_pool_out(store_c_id), c_pool_out(struct_c_id), & - c_mask(leaf_c_id), c_mask(fnrt_c_id), c_mask(sapw_c_id), & - c_mask(store_c_id),c_mask(struct_c_id), max_trunc_error, step_pass) - if(step_pass) then - this%ode_opt_step = deltaC - else - this%ode_opt_step = 0.5*deltaC - end if - else - write(fates_log(),*) 'An integrator was chosen that does not exist' - write(fates_log(),*) 'ODESolve = ',ODESolve - call endrun(msg=errMsg(sourcefile, __LINE__)) - end if - - nsteps = nsteps + 1 - - if (step_pass) then ! If true, then step is accepted - totalC = totalC - deltaC - c_pool(:) = c_pool_out(:) - end if - - if(nsteps > max_substeps ) then - write(fates_log(),*) 'Plant Growth Integrator could not find' - write(fates_log(),*) 'a solution in less than ',max_substeps,' tries' - write(fates_log(),*) 'Aborting' - write(fates_log(),*) 'carbon_balance',carbon_balance - write(fates_log(),*) 'deltaC',deltaC - write(fates_log(),*) 'totalC',totalC - write(fates_log(),*) 'leaf:',grow_leaf,target_leaf_c,target_leaf_c - sum(leaf_c(:)) - write(fates_log(),*) 'fnrt:',grow_fnrt,target_fnrt_c,target_fnrt_c - fnrt_c - write(fates_log(),*) 'sap:',grow_sapw,target_sapw_c, target_sapw_c - sapw_c - write(fates_log(),*) 'store:',grow_store,target_store_c,target_store_c - store_c - write(fates_log(),*) 'dead:',target_struct_c,target_struct_c - struct_c - call endrun(msg=errMsg(sourcefile, __LINE__)) - end if - - ! - ! TotalC should eventually be whittled down to near zero. - ! The solvers are not perfect, so we can't expect it to be perfectly zero. - ! Note that calloc_abs_error is 1e-9, which is really small (1 microgram of carbon) - ! yet also six orders of magnitude greater than typical rounding errors (~1e-15). - - ! At that point, update the actual states - ! -------------------------------------------------------------------------------- - if_step_pass: if( (totalC < calloc_abs_error) .and. (step_pass) )then - - ierr = 0 - leaf_c_flux = c_pool(leaf_c_id) - sum(leaf_c(1:nleafage)) - fnrt_c_flux = c_pool(fnrt_c_id) - fnrt_c - sapw_c_flux = c_pool(sapw_c_id) - sapw_c - store_c_flux = c_pool(store_c_id) - store_c - struct_c_flux = c_pool(struct_c_id) - struct_c - repro_c_flux = c_pool(repro_c_id) - repro_c - - ! Make an adjustment to flux partitions to make it match remaining c balance - flux_adj = carbon_balance/(leaf_c_flux+fnrt_c_flux+sapw_c_flux + & - store_c_flux+struct_c_flux+repro_c_flux) - - - leaf_c_flux = leaf_c_flux*flux_adj - fnrt_c_flux = fnrt_c_flux*flux_adj - sapw_c_flux = sapw_c_flux*flux_adj - store_c_flux = store_c_flux*flux_adj - struct_c_flux = struct_c_flux*flux_adj - repro_c_flux = repro_c_flux*flux_adj - - carbon_balance = carbon_balance - leaf_c_flux - leaf_c(iexp_leaf) = leaf_c(iexp_leaf) + leaf_c_flux - - carbon_balance = carbon_balance - fnrt_c_flux - fnrt_c = fnrt_c + fnrt_c_flux - - carbon_balance = carbon_balance - sapw_c_flux - sapw_c = sapw_c + sapw_c_flux - - carbon_balance = carbon_balance - store_c_flux - store_c = store_c + store_c_flux - - carbon_balance = carbon_balance - struct_c_flux - struct_c = struct_c + struct_c_flux - - carbon_balance = carbon_balance - repro_c_flux - repro_c = repro_c + repro_c_flux - - dbh = c_pool(dbh_id) - - if( abs(carbon_balance)>calloc_abs_error ) then - write(fates_log(),*) 'carbon conservation error while integrating pools' - write(fates_log(),*) 'along alometric curve' - write(fates_log(),*) 'carbon_balance = ',carbon_balance,totalC - write(fates_log(),*) 'exiting' - call endrun(msg=errMsg(sourcefile, __LINE__)) - end if - - end if if_step_pass - - end do do_solve_check - - end if if_stature_growth - - ! Track the net allocations and transport from this routine - ! (the AgeLeaves() routine handled tracking allocation through aging) - - this%variables(leaf_c_id)%net_alloc(icd) = & - this%variables(leaf_c_id)%net_alloc(icd) + (leaf_c(icd) - leaf_c0(icd)) - - this%variables(fnrt_c_id)%net_alloc(icd) = & - this%variables(fnrt_c_id)%net_alloc(icd) + (fnrt_c - fnrt_c0) - - this%variables(sapw_c_id)%net_alloc(icd) = & - this%variables(sapw_c_id)%net_alloc(icd) + (sapw_c - sapw_c0) - - this%variables(store_c_id)%net_alloc(icd) = & - this%variables(store_c_id)%net_alloc(icd) + (store_c - store_c0) - - this%variables(repro_c_id)%net_alloc(icd) = & - this%variables(repro_c_id)%net_alloc(icd) + (repro_c - repro_c0) - - this%variables(struct_c_id)%net_alloc(icd) = & - this%variables(struct_c_id)%net_alloc(icd) + (struct_c - struct_c0) + end if + end if + + case (3) + ! ----------------------------------------------------------------------------------- + ! VII 1/2: If plant is semi-deciduous, there will be cases in which plant's carbon + ! balance is positive but plant is losing leaves, in which case the plant + ! should not invest in growth. + ! ----------------------------------------------------------------------------------- + select_stash_grow: select case (leaf_status) + case (leaves_off,leaves_shedding) + ! There is carbon balance, but plant is shedding leaves. We stash the carbon + ! to storage even if it makes their storage too large. + store_c_flux = carbon_balance + carbon_balance = carbon_balance - store_c_flux + store_c = store_c + store_c_flux + end select select_stash_grow + + + if_carbon_increment: if(carbon_balance > calloc_abs_error ) then + + + ! ----------------------------------------------------------------------------------- + ! VIII. If carbon is yet still available ... + ! Our pools are now either on allometry or above (from fusion). + ! We we can increment those pools at or below, + ! including structure and reproduction according to their rates + ! Use an adaptive euler integration. If the error is not nominal, + ! the carbon balance sub-step (deltaC) will be halved and tried again + ! + ! Note that we compare against calloc_abs_error here because it is possible + ! that all the carbon was effectively used up, but a miniscule amount + ! remains due to numerical precision (ie -20 or so), so even though + ! the plant has not been brought to be "on allometry", it thinks it has carbon + ! left to allocate, and thus it must be on allometry when its not. + ! ----------------------------------------------------------------------------------- + + intgr_params(:) = un_initialized + intgr_params(ac_bc_in_id_ctrim) = this%bc_in(ac_bc_in_id_ctrim)%rval + intgr_params(ac_bc_in_id_pft) = real(this%bc_in(ac_bc_in_id_pft)%ival,r8) + intgr_params(ac_bc_in_id_cdamage) = real(this%bc_in(ac_bc_in_id_cdamage)%ival,r8) + intgr_params(ac_bc_in_id_lstat) = real(this%bc_in(ac_bc_in_id_lstat)%ival,r8) + intgr_params(ac_bc_in_id_efleaf) = this%bc_in(ac_bc_in_id_efleaf)%rval + intgr_params(ac_bc_in_id_effnrt) = this%bc_in(ac_bc_in_id_effnrt)%rval + intgr_params(ac_bc_in_id_efstem) = this%bc_in(ac_bc_in_id_efstem)%rval + + + + ! This routine checks that actual carbon is not below that targets. It does + ! allow actual pools to be above the target, and in these cases, it sends + ! a false on the "grow_<>" flag, allowing the plant to grow into these pools. + ! It also checks to make sure that structural biomass is not above the target. + ! ( MLO. Removed the check for storage because the same test is done inside + ! sub-routine TargetAllometryCheck.) + + call TargetAllometryCheck(sum(leaf_c0(1:nleafage)),fnrt_c0,sapw_c0,store_c0,struct_c0, & + sum(leaf_c(1:nleafage)), fnrt_c, sapw_c,store_c, struct_c, & + target_leaf_c, target_fnrt_c, target_sapw_c, & + target_store_c, target_struct_c, & + carbon_balance,elongf_leaf,elongf_fnrt,elongf_stem,ipft,leaf_status, & + grow_leaf, grow_fnrt, grow_sapw, grow_store, grow_struct) + + ! -------------------------------------------------------------------------------- + ! The numerical integration of growth requires that the instantaneous state + ! variables are passed in as an array. We call it "c_pool". + ! + ! Initialize the adaptive integrator arrays and flags + ! -------------------------------------------------------------------------------- + + ierr = 1 + totalC = carbon_balance + nsteps = 0 + + c_pool(:) = 0.0_r8 ! Zero state variable array + c_mask(:) = .false. ! This mask tells the integrator + ! which indices are active. Its possible + ! that due to fusion, or previous numerical + ! truncation errors, that one of these pools + ! may be larger than its target! We check + ! this, and if true, then we flag that + ! pool to be ignored. c_mask(i) = .false. + ! For grasses, since they don't grow very + ! large and thus won't accumulate such large + ! errors, we always mask as true. + + c_pool(leaf_c_id) = sum(leaf_c(1:nleafage)) + c_pool(fnrt_c_id) = fnrt_c + c_pool(sapw_c_id) = sapw_c + c_pool(store_c_id) = store_c + c_pool(struct_c_id) = struct_c + c_pool(repro_c_id) = repro_c + c_pool(dbh_id) = dbh + + ! Only grow leaves if we are in a "leaf-on" status. For drought-deciduous, we + ! interrupt growth for all tissues when in dormant mode. + if (is_hydecid_dormant) then + c_mask(leaf_c_id) = .false. + c_mask(fnrt_c_id) = .false. + c_mask(sapw_c_id) = .false. + c_mask(struct_c_id) = .false. + + else + select case (leaf_status) + case (leaves_on) + c_mask(leaf_c_id) = grow_leaf + case default + c_mask(leaf_c_id) = .false. + end select + c_mask(fnrt_c_id) = grow_fnrt + c_mask(sapw_c_id) = grow_sapw + c_mask(struct_c_id) = grow_struct + + end if + c_mask(store_c_id) = grow_store + c_mask(repro_c_id) = .true. ! Always calculate reproduction on growth + c_mask(dbh_id) = .true. ! Always increment dbh on growth step + + + ! When using the Euler method, we keep things simple. We always try + ! to make the first integration step to span the entirety of the integration + ! window for the independent variable (available carbon) + + select case (ODESolve) + case (2) + this%ode_opt_step = totalC + end select + + do_solve_check: do while( ierr .ne. 0 ) + + deltaC = min(totalC,this%ode_opt_step) + select_ODESolve: select case (ODESolve) + case (1) + call RKF45(AllomCGrowthDeriv,c_pool,c_mask,deltaC,totalC, & + max_trunc_error,intgr_params,c_pool_out,this%ode_opt_step,step_pass) + + case (2) + call Euler(AllomCGrowthDeriv,c_pool,c_mask,deltaC,totalC,intgr_params,c_pool_out) + ! step_pass = .true. + + ! When integrating along the allometric curve, we have the luxury of perfect + ! hindsite. Ie, after we have made our step, we can see if the amount + ! of each carbon we have matches the target associated with the new dbh. + ! The following call evaluates how close we are to the allometically defined + ! targets. If we are too far (governed by max_trunc_error), then we + ! pass back the pass/fail flag (step_pass) as false. If false, then + ! we halve the step-size, and then retry. If that step was fine, then + ! we remember the current step size as a good next guess. + + call CheckIntegratedAllometries(c_pool_out(dbh_id),ipft,& + crowndamage, canopy_trim, elongf_leaf, elongf_fnrt, elongf_stem, l2fr, & + c_pool_out(leaf_c_id), c_pool_out(fnrt_c_id), c_pool_out(sapw_c_id), & + c_pool_out(store_c_id), c_pool_out(struct_c_id), & + c_mask(leaf_c_id), c_mask(fnrt_c_id), c_mask(sapw_c_id), & + c_mask(store_c_id), c_mask(struct_c_id), max_trunc_error, step_pass) + if(step_pass) then + this%ode_opt_step = deltaC + else + this%ode_opt_step = 0.5*deltaC + end if + case default + write(fates_log(),*) 'An integrator was chosen that does not exist' + write(fates_log(),*) 'ODESolve = ',ODESolve + call endrun(msg=errMsg(sourcefile, __LINE__)) + end select select_ODESolve + + nsteps = nsteps + 1 + + if (step_pass) then ! If true, then step is accepted + totalC = totalC - deltaC + c_pool(:) = c_pool_out(:) + end if + + if(nsteps > max_substeps ) then + write(fates_log(),fmt=*) '---~---' + write(fates_log(),fmt=*) 'Plant Growth Integrator could not find' + write(fates_log(),fmt=*) 'a solution in less than ',max_substeps,' tries.' + write(fates_log(),fmt=*) 'Aborting!' + write(fates_log(),fmt=*) '---~---' + write(fates_log(),fmt=fmti) 'Leaf status =',leaf_status + write(fates_log(),fmt=fmt0) 'Carbon_balance =',carbon_balance + write(fates_log(),fmt=fmt0) 'deltaC =',deltaC + write(fates_log(),fmt=fmt0) 'totalC =',totalC + write(fates_log(),fmt=*) 'crowndamage : ', crowndamage + write(fates_log(),fmt=fmth) ' Tissue |', ' Grow',' Current',' Target' ,' Deficit' + write(fates_log(),fmt=fmtg) ' Leaf |', grow_leaf , sum(leaf_c(:)),target_leaf_c , target_leaf_c - sum(leaf_c(:)) + write(fates_log(),fmt=fmtg) ' Fine root |', grow_fnrt , fnrt_c,target_fnrt_c , target_fnrt_c - fnrt_c + write(fates_log(),fmt=fmtg) ' Sapwood |', grow_sapw , sapw_c,target_sapw_c , target_sapw_c - sapw_c + write(fates_log(),fmt=fmtg) ' Storage |', grow_store , store_c,target_store_c , target_store_c - store_c + write(fates_log(),fmt=fmtg) ' Structural |', grow_struct , struct_c,target_struct_c, target_struct_c - struct_c + write(fates_log(),fmt=*) '---~---' + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + + ! + ! TotalC should eventually be whittled down to near zero. + ! The solvers are not perfect, so we can't expect it to be perfectly zero. + ! Note that calloc_abs_error is 1e-9, which is really small (1 microgram of carbon) + ! yet also six orders of magnitude greater than typical rounding errors (~1e-15). + + ! At that point, update the actual states + ! -------------------------------------------------------------------------------- + if_step_pass: if( (totalC < calloc_abs_error) .and. (step_pass) )then + + ierr = 0 + leaf_c_flux = c_pool(leaf_c_id) - sum(leaf_c(1:nleafage)) + fnrt_c_flux = c_pool(fnrt_c_id) - fnrt_c + sapw_c_flux = c_pool(sapw_c_id) - sapw_c + store_c_flux = c_pool(store_c_id) - store_c + struct_c_flux = c_pool(struct_c_id) - struct_c + repro_c_flux = c_pool(repro_c_id) - repro_c + + ! Make an adjustment to flux partitions to make it match remaining c balance + flux_adj = carbon_balance/(leaf_c_flux+fnrt_c_flux+sapw_c_flux + & + store_c_flux+struct_c_flux+repro_c_flux) + + + leaf_c_flux = leaf_c_flux*flux_adj + fnrt_c_flux = fnrt_c_flux*flux_adj + sapw_c_flux = sapw_c_flux*flux_adj + store_c_flux = store_c_flux*flux_adj + struct_c_flux = struct_c_flux*flux_adj + repro_c_flux = repro_c_flux*flux_adj + + leaf_c(iexp_leaf) = leaf_c(iexp_leaf) + leaf_c_flux + fnrt_c = fnrt_c + fnrt_c_flux + sapw_c = sapw_c + sapw_c_flux + store_c = store_c + store_c_flux + struct_c = struct_c + struct_c_flux + repro_c = repro_c + repro_c_flux + + carbon_balance = carbon_balance - & + ( leaf_c_flux + fnrt_c_flux + sapw_c_flux + & + store_c_flux + struct_c_flux + repro_c_flux ) + + dbh = c_pool(dbh_id) + + if( abs(carbon_balance)>calloc_abs_error ) then + write(fates_log(),*) 'carbon conservation error while integrating pools' + write(fates_log(),*) 'along alometric curve' + write(fates_log(),*) 'carbon_balance = ',carbon_balance,totalC + write(fates_log(),*) 'exiting' + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + + end if if_step_pass + + end do do_solve_check + + end if if_carbon_increment + + end select select_phase + + ! Track the net allocations and transport from this routine + ! (the AgeLeaves() routine handled tracking allocation through aging) + + this%variables(leaf_c_id)%net_alloc(icd) = & + this%variables(leaf_c_id)%net_alloc(icd) + (leaf_c(icd) - leaf_c0(icd)) + + this%variables(fnrt_c_id)%net_alloc(icd) = & + this%variables(fnrt_c_id)%net_alloc(icd) + (fnrt_c - fnrt_c0) + + this%variables(sapw_c_id)%net_alloc(icd) = & + this%variables(sapw_c_id)%net_alloc(icd) + (sapw_c - sapw_c0) + this%variables(store_c_id)%net_alloc(icd) = & + this%variables(store_c_id)%net_alloc(icd) + (store_c - store_c0) + + this%variables(repro_c_id)%net_alloc(icd) = & + this%variables(repro_c_id)%net_alloc(icd) + (repro_c - repro_c0) + + this%variables(struct_c_id)%net_alloc(icd) = & + this%variables(struct_c_id)%net_alloc(icd) + (struct_c - struct_c0) + + + + end associate - end associate - - return + return end subroutine DailyPRTAllometricCarbon ! ===================================================================================== @@ -889,15 +1004,20 @@ function AllomCGrowthDeriv(c_pools,c_mask,cbalance,intgr_params) result(dCdx) real(r8),dimension(lbound(c_pools,dim=1):ubound(c_pools,dim=1)) :: dCdx ! locals - integer :: ipft ! PFT index + integer :: ipft ! PFT index + integer :: crowndamage ! Damage class real(r8) :: canopy_trim ! Canopy trimming function (boundary condition [0-1] - real(r8) :: ct_leaf ! target leaf biomass, dummy var (kgC) - real(r8) :: ct_fnrt ! target fine-root biomass, dummy var (kgC) - real(r8) :: ct_sap ! target sapwood biomass, dummy var (kgC) - real(r8) :: ct_agw ! target aboveground wood, dummy var (kgC) - real(r8) :: ct_bgw ! target belowground wood, dummy var (kgC) - real(r8) :: ct_store ! target storage, dummy var (kgC) - real(r8) :: ct_dead ! target structural biomas, dummy var (kgC) + real(r8) :: elongf_leaf ! Leaf elongation factor (boundary condition) [0-1] + real(r8) :: elongf_fnrt ! Fine-root "elongation factor" (boundary condition) [0-1] + real(r8) :: elongf_stem ! Stem "elongation factor" (boundary condition) [0-1] + real(r8) :: l2fr ! Leaf to fine-root multiplier + real(r8) :: ct_leaf ! target leaf biomass, dummy var (kgC) + real(r8) :: ct_fnrt ! target fine-root biomass, dummy var (kgC) + real(r8) :: ct_sap ! target sapwood biomass, dummy var (kgC) + real(r8) :: ct_agw ! target aboveground wood, dummy var (kgC) + real(r8) :: ct_bgw ! target belowground wood, dummy var (kgC) + real(r8) :: ct_store ! target storage, dummy var (kgC) + real(r8) :: ct_dead ! target structural biomas, dummy var (kgC) real(r8) :: sapw_area ! dummy sapwood area real(r8) :: ct_dleafdd ! target leaf biomass derivative wrt diameter, (kgC/cm) real(r8) :: ct_dfnrtdd ! target fine-root biomass derivative wrt diameter, (kgC/cm) @@ -909,7 +1029,6 @@ function AllomCGrowthDeriv(c_pools,c_mask,cbalance,intgr_params) result(dCdx) 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) - associate( dbh => c_pools(dbh_id), & cleaf => c_pools(leaf_c_id), & cfnrt => c_pools(fnrt_c_id), & @@ -927,24 +1046,51 @@ function AllomCGrowthDeriv(c_pools,c_mask,cbalance,intgr_params) result(dCdx) canopy_trim = intgr_params(ac_bc_in_id_ctrim) ipft = int(intgr_params(ac_bc_in_id_pft)) - - - call bleaf(dbh,ipft,canopy_trim,ct_leaf,ct_dleafdd) - call bfineroot(dbh,ipft,canopy_trim,ct_fnrt,ct_dfnrtdd) - call bsap_allom(dbh,ipft,canopy_trim,sapw_area,ct_sap,ct_dsapdd) - - call bagw_allom(dbh,ipft,ct_agw,ct_dagwdd) - call bbgw_allom(dbh,ipft,ct_bgw,ct_dbgwdd) + elongf_leaf = intgr_params(ac_bc_in_id_efleaf) + elongf_fnrt = intgr_params(ac_bc_in_id_effnrt) + elongf_stem = intgr_params(ac_bc_in_id_efstem) + crowndamage = int(intgr_params(ac_bc_in_id_cdamage)) + l2fr = prt_params%allom_l2fr(ipft) + + call bleaf(dbh,ipft,crowndamage,canopy_trim, elongf_leaf, ct_leaf, dbldd=ct_dleafdd) + call bfineroot(dbh,ipft,canopy_trim,l2fr, elongf_fnrt, ct_fnrt,ct_dfnrtdd) + call bsap_allom(dbh,ipft, crowndamage, canopy_trim, elongf_stem, sapw_area,ct_sap,ct_dsapdd) + call bagw_allom(dbh,ipft,crowndamage, elongf_stem, ct_agw,ct_dagwdd) + call bbgw_allom(dbh,ipft, elongf_stem, 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) + + ! 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 - ! 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) + if ( regeneration_model == default_regeneration .or. & + prt_params%allom_dbh_maxheight(ipft) < min_max_dbh_for_trees ) then + + ! 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 - repro_fraction = prt_params%seed_alloc(ipft) + prt_params%seed_alloc_mature(ipft) - end if + 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 @@ -1008,80 +1154,101 @@ end function AllomCGrowthDeriv ! ==================================================================================== - subroutine TargetAllometryCheck(bleaf,bfroot,bsap,bstore,bdead, & - bt_leaf,bt_froot,bt_sap,bt_store,bt_dead, & - grow_dead,grow_leaf,grow_froot,grow_sapw,grow_store) - - ! Arguments - real(r8),intent(in) :: bleaf !actual - real(r8),intent(in) :: bfroot - real(r8),intent(in) :: bsap - real(r8),intent(in) :: bstore - real(r8),intent(in) :: bdead - real(r8),intent(in) :: bt_leaf !target - real(r8),intent(in) :: bt_froot - real(r8),intent(in) :: bt_sap - real(r8),intent(in) :: bt_store - real(r8),intent(in) :: bt_dead - logical,intent(out) :: grow_leaf !growth flag - logical,intent(out) :: grow_froot - logical,intent(out) :: grow_sapw - logical,intent(out) :: grow_store - logical,intent(out) :: grow_dead - - if( (bt_leaf - bleaf)>calloc_abs_error) then - write(fates_log(),*) 'leaves are not on-allometry at the growth step' - write(fates_log(),*) 'exiting',bleaf,bt_leaf - call endrun(msg=errMsg(sourcefile, __LINE__)) - elseif( (bleaf - bt_leaf)>calloc_abs_error) then - ! leaf is above allometry, ignore - grow_leaf = .false. - else - grow_leaf = .true. - end if - - if( (bt_froot - bfroot)>calloc_abs_error) then - write(fates_log(),*) 'fineroots are not on-allometry at the growth step' - write(fates_log(),*) 'exiting',bfroot, bt_froot - call endrun(msg=errMsg(sourcefile, __LINE__)) - elseif( ( bfroot-bt_froot)>calloc_abs_error ) then - grow_froot = .false. - else - grow_froot = .true. - end if - - if( (bt_sap - bsap)>calloc_abs_error) then - write(fates_log(),*) 'sapwood is not on-allometry at the growth step' - write(fates_log(),*) 'exiting',bsap, bt_sap - call endrun(msg=errMsg(sourcefile, __LINE__)) - elseif( ( bsap-bt_sap)>calloc_abs_error ) then - grow_sapw = .false. - else - grow_sapw = .true. - end if - - if( (bt_store - bstore)>calloc_abs_error) then - write(fates_log(),*) 'storage is not on-allometry at the growth step' - write(fates_log(),*) 'exiting',bstore,bt_store - call endrun(msg=errMsg(sourcefile, __LINE__)) - elseif( ( bstore-bt_store)>calloc_abs_error ) then - grow_store = .false. - else - grow_store = .true. - end if - - if( (bt_dead - bdead)>calloc_abs_error) then - write(fates_log(),*) 'structure not on-allometry at the growth step' - write(fates_log(),*) 'exiting',bdead,bt_dead - call endrun(msg=errMsg(sourcefile, __LINE__)) - elseif( (bdead-bt_dead)> calloc_abs_error) then - grow_dead = .false. - else - grow_dead = .true. - end if - + subroutine TargetAllometryCheck(b0_leaf,b0_fnrt,b0_sapw,b0_store,b0_struct, & + ba_leaf,ba_fnrt,ba_sapw,ba_store,ba_struct, & + bt_leaf,bt_fnrt,bt_sapw,bt_store,bt_struct, & + carbon_balance,elongf_leaf,elongf_fnrt,elongf_stem, & + ipft,leaf_status, & + grow_leaf,grow_fnrt,grow_sapw,grow_store,grow_struct) - return + ! Arguments + real(r8),intent(in) :: b0_leaf !initial + real(r8),intent(in) :: b0_fnrt + real(r8),intent(in) :: b0_sapw + real(r8),intent(in) :: b0_store + real(r8),intent(in) :: b0_struct + real(r8),intent(in) :: ba_leaf !actual + real(r8),intent(in) :: ba_fnrt + real(r8),intent(in) :: ba_sapw + real(r8),intent(in) :: ba_store + real(r8),intent(in) :: ba_struct + real(r8),intent(in) :: bt_leaf !target + real(r8),intent(in) :: bt_fnrt + real(r8),intent(in) :: bt_sapw + real(r8),intent(in) :: bt_store + real(r8),intent(in) :: bt_struct + real(r8),intent(in) :: carbon_balance !remaining carbon balance + real(r8),intent(in) :: elongf_leaf !elongation factors + real(r8),intent(in) :: elongf_fnrt + real(r8),intent(in) :: elongf_stem + integer,intent(in) :: ipft !Plant functional type + integer,intent(in) :: leaf_status !Phenology status + logical,intent(out) :: grow_leaf !growth flag + logical,intent(out) :: grow_fnrt + logical,intent(out) :: grow_sapw + logical,intent(out) :: grow_store + logical,intent(out) :: grow_struct + ! Local variables + logical :: fine_leaf + logical :: fine_fnrt + logical :: fine_sapw + logical :: fine_store + logical :: fine_struct + logical :: all_fine + ! Local constants + character(len= 3), parameter :: fmth = '(a)' + character(len=27), parameter :: fmtb = '(a,3(1x,es12.5,1x,a),1x,l1)' + character(len=13), parameter :: fmte = '(a,1x,es12.5)' + character(len=10), parameter :: fmti = '(a,1x,i12)' + + + ! First test whether or not each pool looks reasonable. + fine_leaf = (bt_leaf - ba_leaf ) <= calloc_abs_error + fine_fnrt = (bt_fnrt - ba_fnrt ) <= calloc_abs_error + fine_sapw = (bt_sapw - ba_sapw ) <= calloc_abs_error + fine_store = (bt_store - ba_store ) <= calloc_abs_error + fine_struct = (bt_struct - ba_struct) <= calloc_abs_error + all_fine = fine_leaf .and. fine_fnrt .and. fine_sapw .and. & + fine_store .and. fine_struct + + ! Decide whether or not to grow tissues (but only if all tissues look fine). + ! We grow only when biomass is less than target biomass (with tolerance). + if (all_fine) then + grow_leaf = ( ba_leaf - bt_leaf ) <= calloc_abs_error + grow_fnrt = ( ba_fnrt - bt_fnrt ) <= calloc_abs_error + grow_sapw = ( ba_sapw - bt_sapw ) <= calloc_abs_error + grow_store = ( ba_store - bt_store ) <= calloc_abs_error + grow_struct = ( ba_struct - bt_struct ) <= calloc_abs_error + else + ! If anything looks not fine, write a detailed report + write(fates_log(),fmt=fmth) '======' + write(fates_log(),fmt=fmth) ' At least one tissue is not on-allometry at the growth step' + write(fates_log(),fmt=fmth) '======' + write(fates_log(),fmt=fmth) '' + write(fates_log(),fmt=fmth) ' Biomass and on-allometry test (''F'' means problem)' + write(fates_log(),fmt=fmth) '------' + write(fates_log(),fmt=fmth) ' Tissue | Initial | Current | Target | On-allometry' + write(fates_log(),fmt=fmtb) ' Leaf |',b0_leaf ,'|',ba_leaf ,'|',bt_leaf ,'|',fine_leaf + write(fates_log(),fmt=fmtb) ' Fine root |',b0_fnrt ,'|',ba_fnrt ,'|',bt_fnrt ,'|',fine_fnrt + write(fates_log(),fmt=fmtb) ' Sap wood |',b0_sapw ,'|',ba_sapw ,'|',bt_sapw ,'|',fine_sapw + write(fates_log(),fmt=fmtb) ' Storage |',b0_store ,'|',ba_store ,'|',bt_store ,'|',fine_store + write(fates_log(),fmt=fmtb) ' Structural |',b0_struct ,'|',ba_struct ,'|',bt_struct ,'|',fine_struct + write(fates_log(),fmt=fmth) '' + write(fates_log(),fmt=fmth) ' Ancillary information' + write(fates_log(),fmt=fmth) '------' + write(fates_log(),fmt=fmti) ' PFT = ',ipft + write(fates_log(),fmt=fmti) ' leaf_status = ',leaf_status + write(fates_log(),fmt=fmte) ' elongf_leaf = ',elongf_leaf + write(fates_log(),fmt=fmte) ' elongf_fnrt = ',elongf_fnrt + write(fates_log(),fmt=fmte) ' elongf_stem = ',elongf_stem + write(fates_log(),fmt=fmte) ' carbon_balance = ',carbon_balance + write(fates_log(),fmt=fmte) ' calloc_abs_error = ',calloc_abs_error + write(fates_log(),fmt=fmth) '' + write(fates_log(),fmt=fmth) '======' + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + + return end subroutine TargetAllometryCheck ! ===================================================================================== @@ -1097,7 +1264,7 @@ subroutine FastPRTAllometricCarbon(this) return - end subroutine FastPRTAllometricCarbon + end subroutine FastPRTAllometricCarbon end module PRTAllometricCarbonMod diff --git a/parteh/PRTGenericMod.F90 b/parteh/PRTGenericMod.F90 index 3dab9563a3..81d29d7429 100644 --- a/parteh/PRTGenericMod.F90 +++ b/parteh/PRTGenericMod.F90 @@ -67,8 +67,7 @@ module PRTGenericMod ! ------------------------------------------------------------------------------------- integer, parameter, public :: prt_carbon_allom_hyp = 1 - integer, parameter, public :: prt_cnp_flex_allom_hyp = 2 ! Still under development - + integer, parameter, public :: prt_cnp_flex_allom_hyp = 2 ! ------------------------------------------------------------------------------------- ! Organ types @@ -100,7 +99,6 @@ module PRTGenericMod ! element. At the time of writing this, we are very far away from ! creating allocation schemes that even use potassium. - integer, parameter, public :: all_carbon_elements = 0 integer, parameter, public :: carbon12_element = 1 integer, parameter, public :: carbon13_element = 2 integer, parameter, public :: carbon14_element = 3 @@ -136,7 +134,7 @@ module PRTGenericMod ! List of all carbon elements, the special index "all_carbon_elements" - ! implies the following list of carbon organs + ! implies the following list of carbon organs (NOT USED) integer, parameter, dimension(3), public :: carbon_elements_list = & [carbon12_element, carbon13_element, carbon14_element] @@ -147,6 +145,11 @@ module PRTGenericMod ! (used for allocating scratch space) integer, parameter, public :: max_nleafage = 4 + + ! This is the minimum allowable L2FR, this is needed so that plants + ! in the understory don't shrink their roots down so far that + ! they dissappear and cause numerical issues + real(r8), parameter, public :: l2fr_min = 0.01_r8 ! ------------------------------------------------------------------------------------- ! @@ -185,8 +188,9 @@ module PRTGenericMod ! over the control period real(r8),allocatable :: burned(:) ! Losses due to burn [kg] + real(r8),allocatable :: damaged(:) ! Losses due to damage [kg] -! real(r8),allocatable :: herbiv(:) ! Losses due to herbivory [kg] + ! real(r8),allocatable :: herbiv(:) ! Losses due to herbivory [kg] ! Placeholder ! To save on memory, keep this commented out, or simply @@ -241,6 +245,7 @@ module PRTGenericMod procedure :: DailyPRT => DailyPRTBase procedure :: FastPRT => FastPRTBase + procedure :: DamageRecovery => DamageRecoveryBase procedure :: GetNutrientTarget => GetNutrientTargetBase ! These are generic functions that should work on all hypotheses @@ -262,7 +267,8 @@ module PRTGenericMod procedure, non_overridable :: DeallocatePRTVartypes procedure, non_overridable :: WeightedFusePRTVartypes procedure, non_overridable :: CopyPRTVartypes - + + procedure :: AgeLeaves ! This routine may be used generically ! but also leaving the door open for over-rides @@ -279,7 +285,7 @@ module PRTGenericMod ! examples are carbon12_element ! nitrogen_element, etc. - integer, public :: element_pos(num_organ_types) ! This is the reverse lookup + integer, public :: element_pos(num_element_types) ! This is the reverse lookup ! for element types. Pick an element ! global index, and it gives you ! the position in the element_list @@ -542,7 +548,8 @@ subroutine InitAllocate(this) allocate(this%variables(i_var)%turnover(num_pos)) allocate(this%variables(i_var)%net_alloc(num_pos)) allocate(this%variables(i_var)%burned(num_pos)) - + allocate(this%variables(i_var)%damaged(num_pos)) + end do @@ -567,6 +574,7 @@ subroutine InitializeInitialConditions(this) this%variables(i_var)%val0(:) = un_initialized this%variables(i_var)%turnover(:) = un_initialized this%variables(i_var)%burned(:) = un_initialized + this%variables(i_var)%damaged(:) = un_initialized this%variables(i_var)%net_alloc(:) = un_initialized end do @@ -787,6 +795,7 @@ subroutine CopyPRTVartypes(this, donor_prt_obj) this%variables(i_var)%net_alloc(:) = donor_prt_obj%variables(i_var)%net_alloc(:) this%variables(i_var)%turnover(:) = donor_prt_obj%variables(i_var)%turnover(:) this%variables(i_var)%burned(:) = donor_prt_obj%variables(i_var)%burned(:) + this%variables(i_var)%damaged(:) = donor_prt_obj%variables(i_var)%damaged(:) end do this%ode_opt_step = donor_prt_obj%ode_opt_step @@ -834,6 +843,9 @@ subroutine WeightedFusePRTVartypes(this,donor_prt_obj, recipient_fuse_weight) this%variables(i_var)%burned(pos_id) = recipient_fuse_weight * this%variables(i_var)%burned(pos_id) + & (1.0_r8-recipient_fuse_weight) * donor_prt_obj%variables(i_var)%burned(pos_id) + this%variables(i_var)%damaged(pos_id) = recipient_fuse_weight * this%variables(i_var)%damaged(pos_id) + & + (1.0_r8-recipient_fuse_weight) * donor_prt_obj%variables(i_var)%damaged(pos_id) + end do end do @@ -861,31 +873,41 @@ subroutine DeallocatePRTVartypes(this) ! --------------------------------------------------------------------------------- class(prt_vartypes) :: this - integer :: i_var + integer :: i_var, istat + character(len=255) :: smsg ! Check to see if there is any value in these pools? ! SHould not deallocate if there is any carbon left - do i_var = 1, prt_global%num_vars - deallocate(this%variables(i_var)%val) - deallocate(this%variables(i_var)%val0) - deallocate(this%variables(i_var)%net_alloc) - deallocate(this%variables(i_var)%turnover) - deallocate(this%variables(i_var)%burned) - end do - - deallocate(this%variables) + if(allocated(this%variables)) then + do i_var = 1, prt_global%num_vars + deallocate( & + this%variables(i_var)%val, & + this%variables(i_var)%val0, & + this%variables(i_var)%net_alloc, & + this%variables(i_var)%turnover, & + this%variables(i_var)%burned, & + stat=istat, errmsg=smsg ) + if (istat/=0) call endrun(msg='DeallocatePRTVartypes 1 stat/=0:'//trim(smsg)//errMsg(sourcefile, __LINE__)) + end do + + deallocate(this%variables, stat=istat, errmsg=smsg) + if (istat/=0) call endrun(msg='DeallocatePRTVartypes 2 stat/=0:'//trim(smsg)//errMsg(sourcefile, __LINE__)) + end if if(allocated(this%bc_in))then - deallocate(this%bc_in) + deallocate(this%bc_in, stat=istat, errmsg=smsg) + if (istat/=0) call endrun(msg='DeallocatePRTVartypes bc_in stat/=0:'//trim(smsg)//errMsg(sourcefile, __LINE__)) end if if(allocated(this%bc_out))then - deallocate(this%bc_out) + deallocate(this%bc_out, stat=istat, errmsg=smsg) + if (istat/=0) call endrun(msg='DeallocatePRTVartypes bc_out stat/=0:'//trim(smsg)//errMsg(sourcefile, __LINE__)) end if if(allocated(this%bc_inout))then - deallocate(this%bc_inout) + deallocate(this%bc_inout, stat=istat, errmsg=smsg) + if (istat/=0) call endrun(msg='DeallocatePRTVartypes bc_inout stat/=0:'//trim(smsg)//errMsg(sourcefile, __LINE__)) end if return @@ -914,6 +936,7 @@ subroutine ZeroRates(this) this%variables(i_var)%net_alloc(:) = 0.0_r8 this%variables(i_var)%turnover(:) = 0.0_r8 this%variables(i_var)%burned(:) = 0.0_r8 + this%variables(i_var)%damaged(:) = 0.0_r8 end do end subroutine ZeroRates @@ -949,14 +972,16 @@ subroutine CheckMassConservation(this,ipft,position_id) err = abs((this%variables(i_var)%val(i_pos) - this%variables(i_var)%val0(i_pos)) - & (this%variables(i_var)%net_alloc(i_pos) & -this%variables(i_var)%turnover(i_pos) & - -this%variables(i_var)%burned(i_pos) )) - + -this%variables(i_var)%burned(i_pos) & + -this%variables(i_var)%damaged(i_pos))) + if(this%variables(i_var)%val(i_pos) > nearzero ) then rel_err = err / this%variables(i_var)%val(i_pos) else rel_err = 0.0_r8 end if + if( abs(err) > calloc_abs_error ) then write(fates_log(),*) 'PARTEH mass conservation check failed' write(fates_log(),*) ' Change in mass over control period should' @@ -973,7 +998,8 @@ subroutine CheckMassConservation(this,ipft,position_id) this%variables(i_var)%val0(i_pos), & this%variables(i_var)%net_alloc(i_pos), & this%variables(i_var)%turnover(i_pos), & - this%variables(i_var)%burned(i_pos) + this%variables(i_var)%burned(i_pos), & + this%variables(i_var)%damaged(i_pos) write(fates_log(),*) ' Exiting.' call endrun(msg=errMsg(sourcefile, __LINE__)) end if @@ -999,44 +1025,23 @@ function GetState(this, organ_id, element_id, position_id) result(state_val) integer,intent(in) :: element_id ! Element type querried integer,intent(in),optional :: position_id ! Position querried real(r8) :: state_val ! Mass (value) of state variable [kg] - integer :: i_pos ! position loop counter - integer :: i_element ! element loop counter - integer :: num_element ! total number of elements - integer,dimension(max_spec_per_group) :: element_ids ! element ids (if element list) integer :: i_var ! variable id - - state_val = 0.0_r8 - - if(element_id == all_carbon_elements) then - element_ids(1:3) = carbon_elements_list(1:3) - num_element = 3 - else - num_element = 1 - element_ids(1) = element_id - end if if(present(position_id)) then - i_pos = position_id - - do i_element = 1,num_element - i_var = prt_global%sp_organ_map(organ_id,element_ids(i_element)) - if (i_var>0) state_val = state_val + this%variables(i_var)%val(i_pos) - end do + i_pos = position_id + i_var = prt_global%sp_organ_map(organ_id,element_id) + state_val = this%variables(i_var)%val(i_pos) + else - do i_element = 1,num_element - - i_var = prt_global%sp_organ_map(organ_id,element_ids(i_element)) - if(i_var>0)then - do i_pos = 1, prt_global%state_descriptor(i_var)%num_pos - state_val = state_val + this%variables(i_var)%val(i_pos) - end do - end if - + state_val = 0._r8 + i_var = prt_global%sp_organ_map(organ_id,element_id) + do i_pos = 1, prt_global%state_descriptor(i_var)%num_pos + state_val = state_val + this%variables(i_var)%val(i_pos) end do - + end if return @@ -1060,43 +1065,23 @@ function GetTurnover(this, organ_id, element_id, position_id) result(turnover_va integer,intent(in) :: element_id ! Element type querried integer,intent(in),optional :: position_id ! Position querried real(r8) :: turnover_val ! Amount (value) of turnover [kg] - integer :: i_pos ! position loop counter - integer :: i_element ! element loop counter - integer :: num_element ! total number of elements - integer,dimension(max_spec_per_group) :: element_ids ! element ids (if element list) integer :: i_var ! variable id - turnover_val = 0.0_r8 - - if(element_id == all_carbon_elements) then - element_ids(1:3) = carbon_elements_list(1:3) - num_element = 3 - else - num_element = 1 - element_ids(1) = element_id - end if - if(present(position_id)) then + i_pos = position_id - - do i_element = 1,num_element - i_var = prt_global%sp_organ_map(organ_id,element_ids(i_element)) - if(i_var>0) turnover_val = turnover_val + & - this%variables(i_var)%turnover(i_pos) - end do + i_var = prt_global%sp_organ_map(organ_id,element_id) + turnover_val = this%variables(i_var)%turnover(i_pos) else - do i_element = 1,num_element - i_var = prt_global%sp_organ_map(organ_id,element_ids(i_element)) - if(i_var>0) then - do i_pos = 1, prt_global%state_descriptor(i_var)%num_pos - turnover_val = turnover_val + this%variables(i_var)%turnover(i_pos) - end do - end if - + turnover_val = 0.0_r8 + i_var = prt_global%sp_organ_map(organ_id,element_id) + do i_pos = 1, prt_global%state_descriptor(i_var)%num_pos + turnover_val = turnover_val + this%variables(i_var)%turnover(i_pos) end do + end if @@ -1117,43 +1102,21 @@ function GetBurned(this, organ_id, element_id, position_id) result(burned_val) integer,intent(in) :: element_id ! Element type querried integer,intent(in),optional :: position_id ! Position querried real(r8) :: burned_val ! Amount (value) of burned [kg] - integer :: i_pos ! position loop counter - integer :: i_element ! element loop counter - integer :: num_element ! total number of elements - integer,dimension(max_spec_per_group) :: element_ids ! element ids (if element list) integer :: i_var ! variable id - - burned_val = 0.0_r8 - - if(element_id == all_carbon_elements) then - element_ids(1:3) = carbon_elements_list(1:3) - num_element = 3 - else - num_element = 1 - element_ids(1) = element_id - end if - if(present(position_id)) then + i_pos = position_id - - do i_element = 1,num_element - i_var = prt_global%sp_organ_map(organ_id,element_ids(i_element)) - if(i_var>0) burned_val = burned_val + & - this%variables(i_var)%burned(i_pos) - end do + i_var = prt_global%sp_organ_map(organ_id,element_id) + burned_val = this%variables(i_var)%burned(i_pos) else - do i_element = 1,num_element - i_var = prt_global%sp_organ_map(organ_id,element_ids(i_element)) - if(i_var>0) then - do i_pos = 1, prt_global%state_descriptor(i_var)%num_pos - burned_val = burned_val + this%variables(i_var)%burned(i_pos) - end do - end if - + burned_val = 0.0_r8 + i_var = prt_global%sp_organ_map(organ_id,element_id) + do i_pos = 1, prt_global%state_descriptor(i_var)%num_pos + burned_val = burned_val + this%variables(i_var)%burned(i_pos) end do end if @@ -1176,42 +1139,21 @@ function GetNetAlloc(this, organ_id, element_id, position_id) result(val_netallo integer,intent(in) :: element_id ! Element type querried integer,intent(in),optional :: position_id ! Position querried real(r8) :: val_netalloc ! Amount (value) of allocation [kg] - integer :: i_pos ! position loop counter - integer :: i_element ! element loop counter - integer :: num_element ! total number of elements - integer,dimension(max_spec_per_group) :: element_ids ! element ids (if element list) integer :: i_var ! variable id - - val_netalloc = 0.0_r8 - if(element_id == all_carbon_elements) then - element_ids(1:3) = carbon_elements_list(1:3) - num_element = 3 - else - num_element = 1 - element_ids(1) = element_id - end if - if(present(position_id)) then - i_pos = position_id - - do i_element = 1,num_element - i_var = prt_global%sp_organ_map(organ_id,element_ids(i_element)) - if(i_var>0) val_netalloc = val_netalloc + & - this%variables(i_var)%net_alloc(i_pos) - end do - else + i_pos = position_id + i_var = prt_global%sp_organ_map(organ_id,element_id) + val_netalloc = this%variables(i_var)%net_alloc(i_pos) - do i_element = 1,num_element - i_var = prt_global%sp_organ_map(organ_id,element_ids(i_element)) - if(i_var>0) then - do i_pos = 1, prt_global%state_descriptor(i_var)%num_pos - val_netalloc = val_netalloc + this%variables(i_var)%net_alloc(i_pos) - end do - end if - + else + + val_netalloc = 0.0_r8 + i_var = prt_global%sp_organ_map(organ_id,element_id) + do i_pos = 1, prt_global%state_descriptor(i_var)%num_pos + val_netalloc = val_netalloc + this%variables(i_var)%net_alloc(i_pos) end do end if @@ -1240,28 +1182,40 @@ end function GetCoordVal ! ==================================================================================== - subroutine DailyPRTBase(this) + subroutine DailyPRTBase(this,phase) - class(prt_vartypes) :: this - - write(fates_log(),*)'Daily PRT Allocation must be extended' - call endrun(msg=errMsg(sourcefile, __LINE__)) + class(prt_vartypes) :: this + integer,intent(in) :: phase ! We allow this and its children to be broken into phases + + write(fates_log(),*)'Daily PRT Allocation must be extended' + call endrun(msg=errMsg(sourcefile, __LINE__)) end subroutine DailyPRTBase ! ==================================================================================== - subroutine FastPRTBase(this) + subroutine DamageRecoveryBase(this) class(prt_vartypes) :: this - write(fates_log(),*)'FastReactiveTransport must be extended by a child class.' + write(fates_log(),*)'?' call endrun(msg=errMsg(sourcefile, __LINE__)) - end subroutine FastPRTBase + end subroutine DamageRecoveryBase ! ==================================================================================== + ! ==================================================================================== + + subroutine FastPRTBase(this) + + class(prt_vartypes) :: this + + write(fates_log(),*)'FastReactiveTransport must be extended by a child class' + call endrun(msg=errMsg(sourcefile, __LINE__)) + end subroutine FastPRTBase + + !==================================================================================== subroutine SetState(prt,organ_id, element_id, state_val, position_id) ! This routine should only be called for initalizing the state value @@ -1280,12 +1234,6 @@ subroutine SetState(prt,organ_id, element_id, state_val, position_id) integer :: i_var ! variable loop counter integer :: i_pos ! position loop counter - if(element_id == all_carbon_elements) then - write(fates_log(),*) 'You cannot set the state of all isotopes simultaneously.' - write(fates_log(),*) 'You can only set 1. Exiting.' - call endrun(msg=errMsg(sourcefile, __LINE__)) - end if - if( present(position_id) ) then i_pos = position_id else @@ -1425,10 +1373,12 @@ function StorageNutrientTarget(pft, element_id, leaf_target, fnrt_target, sapw_t ! total nitrogen content of 1 or more sets of organs ! ------------------------------------------------------------------------------------- - integer, parameter :: lfs_store_prop = 1 ! leaf-fnrt-sapw proportional storage - integer, parameter :: lfss_store_prop = 2 ! leaf-fnrt-sapw-struct proportional storage - integer, parameter :: fnrt_store_prop = 3 ! fineroot proportional storage - integer, parameter :: store_prop = fnrt_store_prop + integer, parameter :: lfs_store_prop = 1 ! leaf-sapwood proportional storage + integer, parameter :: lfss_store_prop = 2 ! leaf-fnrt-sapw-struct proportional storage + integer, parameter :: fnrt_store_prop = 3 ! fineroot proportional storage + integer, parameter :: cstore_store_prop = 4 ! As a proportion to carbon storage times mean CN + integer, parameter :: lf_store_prop = 5 ! leaf proportional storage + integer, parameter :: store_prop = lf_store_prop select case(element_id) @@ -1441,8 +1391,12 @@ function StorageNutrientTarget(pft, element_id, leaf_target, fnrt_target, sapw_t if (store_prop == lfs_store_prop) then - store_target = prt_params%nitr_store_ratio(pft) * (leaf_target + fnrt_target + sapw_target) + store_target = prt_params%nitr_store_ratio(pft) * (leaf_target + sapw_target) + elseif (store_prop == lf_store_prop) then + + store_target = prt_params%nitr_store_ratio(pft) * leaf_target + elseif(store_prop==lfss_store_prop) then store_target = prt_params%nitr_store_ratio(pft) * (leaf_target + fnrt_target + sapw_target + struct_target) @@ -1451,6 +1405,30 @@ function StorageNutrientTarget(pft, element_id, leaf_target, fnrt_target, sapw_t store_target = prt_params%nitr_store_ratio(pft) * fnrt_target + elseif(store_prop==cstore_store_prop) then + + !call bsap_allom(dbh,ipft,canopy_trim,elongf_stem,sapw_area,target_sapw_c) + !call bagw_allom(dbh,ipft,elongf_stem,agw_c_target) + !call bbgw_allom(dbh,ipft,elongf_stem,bgw_c_target) + !call bdead_allom(agw_c_target,bgw_c_target,target_sapw_c,ipft,target_struct_c) + !call bleaf(dbh,ipft,canopy_trim, elongf_leaf, target_leaf_c) + !call bfineroot(dbh,ipft,canopy_trim, l2fr, elongf_fnrt, target_fnrt_c) + !call bstore_allom(dbh,ipft,canopy_trim, target_store_c) + + ! Strategy, store as much nutrient as needed to match carbon's growth potential + ! ie, nutrient storage is proportional to carbon storage times plant NC ratio + + ! N_so = a * C_so * NC_p + ! NC_p = ( (N_so + N_lf + N_fr + N_sa + N_de)/C_tot ) + ! N_so = a * C_so * ( N_so/C_tot) + a * C_so * (N_lf + N_fr + N_sa + N_de)/C_tot ) + ! N_so = (a * C_so * (N_lf + N_fr + N_sa + N_de)/C_tot ) / ( 1 - a * C_so/C_tot) + + !store_target = (target_store_c * prt_params%nitr_store_ratio(pft) * & + ! (leaf_target + fnrt_target + sapw_target + struct_target)/total_c_target) / & + ! ( 1._r8 - target_store_c * prt_params%nitr_store_ratio(pft) / total_c_target ) + write(fates_log(),*)'cstore_store_prop method of calculating target nutrient stores not available' + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if @@ -1460,15 +1438,19 @@ function StorageNutrientTarget(pft, element_id, leaf_target, fnrt_target, sapw_t store_target = prt_params%phos_store_ratio(pft) * (leaf_target + fnrt_target + sapw_target) + elseif (store_prop == lf_store_prop) then + + store_target = prt_params%phos_store_ratio(pft) * leaf_target + elseif(store_prop==lfss_store_prop) then - store_target = prt_params%nitr_store_ratio(pft) * (leaf_target + fnrt_target + sapw_target + struct_target) + store_target = prt_params%phos_store_ratio(pft) * (leaf_target + fnrt_target + sapw_target + struct_target) elseif(store_prop==fnrt_store_prop) then store_target = prt_params%phos_store_ratio(pft) * fnrt_target - - end if + + end if end select diff --git a/parteh/PRTLossFluxesMod.F90 b/parteh/PRTLossFluxesMod.F90 index 13b09b2e37..833bbc7a40 100644 --- a/parteh/PRTLossFluxesMod.F90 +++ b/parteh/PRTLossFluxesMod.F90 @@ -1,3 +1,4 @@ + module PRTLossFluxesMod @@ -8,7 +9,6 @@ module PRTLossFluxesMod use PRTGenericMod, only : store_organ use PRTGenericMod, only : repro_organ use PRTGenericMod, only : struct_organ - use PRTGenericMod, only : carbon_elements_list use PRTGenericMod, only : carbon12_element use PRTGenericMod, only : carbon13_element use PRTGenericMod, only : carbon14_element @@ -64,7 +64,9 @@ module PRTLossFluxesMod public :: PRTBurnLosses public :: PRTPhenologyFlush public :: PRTReproRelease - + public :: PRTDamageLosses + public :: PRTDamageRecoveryFluxes + contains @@ -104,15 +106,22 @@ subroutine PRTPhenologyFlush(prt, ipft, organ_id, c_store_transfer_frac) real(r8) :: sp_demand ! nutrient demand for element - ! We currently only allow the flushing and drop of leaves. - ! If other organs should be desired (like seasonality of fine-roots) - ! those parameters and clauses need to be added + ! We currently allow the flushing and drop of leaves and fine roots (always) and + ! sapwood and heartwood (non-woody PFTs only). + ! If other organs should be desired, those parameters and clauses need to be added - !if(organ_id .ne. leaf_organ) then - if(organ_id .ne. leaf_organ .AND. prt_params%woody(ipft) == itrue) then - write(fates_log(),*) 'Deciduous drop and re-flushing only allowed in leaves' + if( (.not. any(organ_id == [leaf_organ,fnrt_organ])) .and. & + prt_params%woody(ipft) == itrue ) then + write(fates_log(),*) ' When PFT is woody, deciduous drop and re-flushing are' + write(fates_log(),*) ' only allowed in leaves and fine roots:' + write(fates_log(),*) '' + write(fates_log(),*) ' PFT: ',ipft + write(fates_log(),*) ' Woody PFT: ',prt_params%woody(ipft) == itrue + write(fates_log(),*) '' + write(fates_log(),*) '' write(fates_log(),*) ' leaf_organ: ',leaf_organ - write(fates_log(),*) ' organ: ',organ_id + write(fates_log(),*) ' fnrt_organ: ',fnrt_organ + write(fates_log(),*) ' Attempted organ: ',organ_id write(fates_log(),*) 'Exiting' call endrun(msg=errMsg(__FILE__, __LINE__)) end if @@ -158,23 +167,11 @@ subroutine PRTPhenologyFlush(prt, ipft, organ_id, c_store_transfer_frac) element_id = prt_global%state_descriptor(i_var)%element_id ! This will filter IN all carbon related variables - if( any(element_id == carbon_elements_list) ) then + if( element_id == carbon12_element ) then - ! No hypotheses exist for how to flush carbon isotopes - ! yet. Please fill this in. - if( (element_id == carbon13_element) .or. & - (element_id == carbon14_element) )then - write(fates_log(),*) ' Phenology flushing routine does not know' - write(fates_log(),*) ' how to handle carbon isotopes. Please' - write(fates_log(),*) ' evaluate the code referenced in this message' - write(fates_log(),*) ' and provide a hypothesis.' - call endrun(msg=errMsg(__FILE__, __LINE__)) - end if - ! Get the variable id of the storage pool for this element (carbon12) i_store = prt_global%sp_organ_map(store_organ,element_id) - do i_pos = 1,i_leaf_pos ! Calculate the mass transferred out of storage into the pool of interest @@ -222,7 +219,7 @@ subroutine PRTPhenologyFlush(prt, ipft, organ_id, c_store_transfer_frac) element_id = prt_global%state_descriptor(i_var)%element_id ! This will filter OUT all carbon related elements - if ( .not. any(element_id == carbon_elements_list) ) then + if ( .not. (element_id == carbon12_element) ) then ! Get the variable id of the storage pool for this element i_store = prt_global%sp_organ_map(store_organ,element_id) @@ -335,7 +332,62 @@ subroutine PRTBurnLosses(prt, organ_id, mass_fraction) end associate end subroutine PRTBurnLosses + ! ===================================================================================== + + subroutine PRTDamageLosses(prt, organ_id, mass_fraction) + + ! ---------------------------------------------------------------------------------- + ! This subroutine assumes that there is no re-translocation associated + ! with damage. There is only one destiny for damaged mass within + ! the organ, and that is outside the plant. + ! It is also assumed that non PARTEH parts of the code (ie the damage-model) + ! will decide what to do with the damaged mass (i.e. sent it to the litter + ! pool, or.. other?) + ! ---------------------------------------------------------------------------------- + + class(prt_vartypes) :: prt + integer,intent(in) :: organ_id + real(r8),intent(in) :: mass_fraction + integer :: i_pos ! position index + integer :: i_var ! index for the variable of interest + integer :: i_var_of_organ ! loop counter for all element in this organ + integer :: element_id ! Element id of the turnover pool + real(r8) :: damaged_mass ! Lost mass of each element, in each + ! position, in the organ of interest + + associate(organ_map => prt_global%organ_map) + + ! This is the total number of state variables associated + ! with this particular organ + + do i_var_of_organ = 1, organ_map(organ_id)%num_vars + + i_var = organ_map(organ_id)%var_id(i_var_of_organ) + + element_id = prt_global%state_descriptor(i_var)%element_id + + ! Loop over all of the coordinate ids + do i_pos = 1,prt_global%state_descriptor(i_var)%num_pos + + ! The mass that is leaving the plant + damaged_mass = mass_fraction * prt%variables(i_var)%val(i_pos) + + ! Track the amount of mass being lost (+ is amount lost) + prt%variables(i_var)%damaged(i_pos) = prt%variables(i_var)%damaged(i_pos) & + + damaged_mass + + ! Update the state of the pool to reflect the mass lost + prt%variables(i_var)%val(i_pos) = prt%variables(i_var)%val(i_pos) & + - damaged_mass + + end do + + end do + + end associate + end subroutine PRTDamageLosses + ! ===================================================================================== @@ -419,30 +471,29 @@ subroutine PRTDeciduousTurnover(prt,ipft,organ_id,mass_fraction) real(r8),intent(in) :: mass_fraction ! The fraction of mass in this organ that should ! leave the indicated organ. - ! We currently only allow the flushing and drop of leaves. - ! If other organs should be desired (like seasonality of fine-roots) - ! those parameters and clauses need to be added - - !if(organ_id .ne. leaf_organ) then - if(organ_id .ne. leaf_organ .AND. prt_params%woody(ipft) == itrue) then - write(fates_log(),*) 'Deciduous drop and re-flushing only allowed in leaves' + ! We currently allow the flushing and drop of leaves and fine roots (always) and + ! sapwood and heartwood (non-woody PFTs only). + ! If other organs should be desired, those parameters and clauses need to be added + + if( (.not. any(organ_id == [leaf_organ,fnrt_organ])) .and. & + prt_params%woody(ipft) == itrue ) then + write(fates_log(),*) ' When PFT is woody, deciduous drop and re-flushing are' + write(fates_log(),*) ' only allowed in leaves and fine roots:' + write(fates_log(),*) '' + write(fates_log(),*) ' PFT: ',ipft + write(fates_log(),*) ' Woody PFT: ',prt_params%woody(ipft) == itrue + write(fates_log(),*) '' + write(fates_log(),*) '' write(fates_log(),*) ' leaf_organ: ',leaf_organ - write(fates_log(),*) ' organ: ',organ_id + write(fates_log(),*) ' fnrt_organ: ',fnrt_organ + write(fates_log(),*) ' Attempted organ: ',organ_id write(fates_log(),*) 'Exiting' call endrun(msg=errMsg(__FILE__, __LINE__)) end if - if ( int(prt_params%turnover_retrans_mode(ipft)) == 1 ) then - call DeciduousTurnoverSimpleRetranslocation(prt,ipft,organ_id,mass_fraction) - else - write(fates_log(),*) 'A retranslocation mode was specified for deciduous drop' - write(fates_log(),*) 'that is unknown.' - write(fates_log(),*) 'turnover_retrans_mode= ',prt_params%turnover_retrans_mode(ipft) - write(fates_log(),*) 'pft = ',ipft - call endrun(msg=errMsg(__FILE__, __LINE__)) - end if - + call DeciduousTurnoverSimpleRetranslocation(prt,ipft,organ_id,mass_fraction) + return end subroutine PRTDeciduousTurnover @@ -517,8 +568,8 @@ subroutine DeciduousTurnoverSimpleRetranslocation(prt,ipft,organ_id,mass_fractio if( prt_params%organ_param_id(organ_id) < 1 ) then retrans = 0._r8 else - if ( any(element_id == carbon_elements_list) ) then - retrans = prt_params%turnover_carb_retrans(ipft,prt_params%organ_param_id(organ_id)) + if ( element_id == carbon12_element ) then + retrans = 0._r8 else if( element_id == nitrogen_element ) then retrans = prt_params%turnover_nitr_retrans(ipft,prt_params%organ_param_id(organ_id)) else if( element_id == phosphorus_element ) then @@ -538,7 +589,7 @@ subroutine DeciduousTurnoverSimpleRetranslocation(prt,ipft,organ_id,mass_fractio ! Loop over all of the coordinate ids do i_pos = 1, prt_global%state_descriptor(i_var)%num_pos - ! The mass that is leaving the plant + ! The mass that is leaving the plant turnover_mass = (1.0_r8 - retrans) * mass_fraction * prt%variables(i_var)%val(i_pos) ! The mass that is going towards storage @@ -587,15 +638,8 @@ subroutine PRTMaintTurnover(prt,ipft,is_drought) logical,intent(in) :: is_drought ! Is this plant/cohort operating in a drought ! stress context? - if ( int(prt_params%turnover_retrans_mode(ipft)) == 1 ) then - call MaintTurnoverSimpleRetranslocation(prt,ipft,is_drought) - else - write(fates_log(),*) 'A maintenance/retranslocation mode was specified' - write(fates_log(),*) 'that is unknown.' - write(fates_log(),*) 'turnover_retrans_mode= ',prt_params%turnover_retrans_mode(ipft) - write(fates_log(),*) 'pft = ',ipft - call endrun(msg=errMsg(__FILE__, __LINE__)) - end if + call MaintTurnoverSimpleRetranslocation(prt,ipft,is_drought) + return end subroutine PRTMaintTurnover @@ -728,8 +772,8 @@ subroutine MaintTurnoverSimpleRetranslocation(prt,ipft,is_drought) if( prt_params%organ_param_id(organ_id) < 1 ) then retrans_frac = 0._r8 else - if ( any(element_id == carbon_elements_list) ) then - retrans_frac = prt_params%turnover_carb_retrans(ipft,prt_params%organ_param_id(organ_id)) + if ( element_id == carbon12_element ) then + retrans_frac = 0._r8 else if( element_id == nitrogen_element ) then retrans_frac = prt_params%turnover_nitr_retrans(ipft,prt_params%organ_param_id(organ_id)) else if( element_id == phosphorus_element ) then @@ -811,6 +855,30 @@ subroutine MaintTurnoverSimpleRetranslocation(prt,ipft,is_drought) return end subroutine MaintTurnoverSimpleRetranslocation + !---------------------------------------------------------------------------------------------- + + subroutine PRTDamageRecoveryFluxes(prt, organ_id, mass_0, mass, cc_mass) + + class(prt_vartypes) :: prt + integer,intent(in) :: organ_id + real(r8),intent(in) :: mass_0 + real(r8),intent(in) :: mass + real(r8),intent(in) :: cc_mass + + integer, parameter :: icd = 1 + + ! Remove the amount that was copied from old cohort + prt%variables(organ_id)%net_alloc(icd) = prt%variables(organ_id)%net_alloc(icd) & + - (cc_mass - mass_0) + + + ! Track the amount of mass being lost (+ is amount lost) + prt%variables(organ_id)%net_alloc(icd) = prt%variables(organ_id)%net_alloc(icd) & + + (mass - mass_0) + + end subroutine PRTDamageRecoveryFluxes + + ! ===================================================================================== diff --git a/parteh/PRTParametersMod.F90 b/parteh/PRTParametersMod.F90 index 04a0f5dda0..f2419c3334 100644 --- a/parteh/PRTParametersMod.F90 +++ b/parteh/PRTParametersMod.F90 @@ -8,26 +8,55 @@ module PRTParametersMod ! that data, for that is model dependent (ie FATES may have a different ! way than another TBM) ! This code does perform checks on parameters. - + type,public :: prt_param_type ! The following three PFT classes ! are mutually exclusive - integer, allocatable :: stress_decid(:) ! Is the plant stress deciduous? (1=yes, 0=no) + ! MLO: perhaps we should replace these three parameters with a single + ! parameter (phenology(:)) that is assigned different indices? + integer, allocatable :: stress_decid(:) ! Is the plant stress deciduous? + ! 0 - No + ! 1 - Drought "hard" deciduous (i.e., PFT + ! sheds leaves all at once when stressed) + ! 2 - Drought semi-deciduous (i.e., PFT + ! sheds leaves gradually as drought + ! conditions deteriorate) integer, allocatable :: season_decid(:) ! Is the plant seasonally deciduous (1=yes, 0=no) integer, allocatable :: evergreen(:) ! Is the plant an evergreen (1=yes, 0=no) - + ! Drop fraction for tissues other than leaves (PFT-dependent) + real(r8), allocatable :: phen_fnrt_drop_fraction(:) ! Abscission fraction of fine roots + real(r8), allocatable :: phen_stem_drop_fraction(:) ! Abscission fraction of stems + real(r8), allocatable :: phen_drought_threshold(:) ! For obligate (hard) drought deciduous, this is the threshold + ! below which plants will abscise leaves, and + ! above which plants will flush leaves. For semi-deciduous + ! plants, this is the threshold below which abscission will + ! be complete. This depends on the sign. If positive, these + ! are soil volumetric water content [m3/m3]. If + ! negative, the values are soil matric potential [mm]. + ! Ignored for non-deciduous plants. + real(r8), allocatable :: phen_moist_threshold(:) ! For semi-deciduous, this is the threshold above which flushing + ! will be complete. This depends on the sign. If positive, these + ! are soil volumetric water content [m3/m3]. If + ! negative, the values are soil matric potential [mm]. + ! Ignored for non-deciduous plants. + real(r8), allocatable :: phen_doff_time(:) ! Minimum number of days that plants must remain leafless before + ! flushing leaves again. + + ! Growth and Turnover Parameters real(r8), allocatable :: senleaf_long_fdrought(:) ! Multiplication factor for leaf longevity of senescent ! leaves during drought( 1.0 indicates no change) real(r8), allocatable :: leaf_long(:,:) ! Leaf turnover time (longevity) (pft x age-class) ! If there is >1 class, it is the longevity from ! one class to the next [yr] + ! For drought-deciduous PFTs, the sum of leaf + ! longevity across all leaf age classes is also + ! the maximum length of the growing (i.e., leaves on) + ! season. real(r8), allocatable :: root_long(:) ! root turnover time (longevity) (pft) [yr] real(r8), allocatable :: branch_long(:) ! Turnover time for branchfall on live trees (pft) [yr] - real(r8), allocatable :: turnover_retrans_mode(:) ! Retranslocation method (pft) - real(r8), allocatable :: turnover_carb_retrans(:,:) ! carbon re-translocation fraction (pft x organ) real(r8), allocatable :: turnover_nitr_retrans(:,:) ! nitrogen re-translocation fraction (pft x organ) real(r8), allocatable :: turnover_phos_retrans(:,:) ! phosphorus re-translocation fraction (pft x organ) ! Parameters dimensioned by PFT and leaf age @@ -46,9 +75,7 @@ module PRTParametersMod ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! real(r8), allocatable :: nitr_stoich_p1(:,:) ! Parameter 1 for nitrogen stoichiometry (pft x organ) - real(r8), allocatable :: nitr_stoich_p2(:,:) ! Parameter 2 for nitrogen stoichiometry (pft x organ) real(r8), allocatable :: phos_stoich_p1(:,:) ! Parameter 1 for phosphorus stoichiometry (pft x organ) - real(r8), allocatable :: phos_stoich_p2(:,:) ! Parameter 2 for phosphorus stoichiometry (pft x organ) real(r8), allocatable :: nitr_store_ratio(:) ! This is the ratio of the target nitrogen stored per ! target nitrogen that is bound into the tissues @@ -61,10 +88,6 @@ module PRTParametersMod integer, allocatable :: organ_id(:) ! Mapping of the organ index in the parameter file, to the ! global list of organs found in PRTGenericMod.F90 - - - - real(r8), allocatable :: alloc_priority(:,:) ! Allocation priority for each organ (pft x organ) [integer 0-6] real(r8), allocatable :: cushion(:) ! labile carbon storage target as multiple of leaf pool. real(r8), allocatable :: leaf_stor_priority(:) ! leaf turnover vs labile carbon use prioritisation @@ -73,7 +96,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 @@ -81,27 +105,20 @@ module PRTParametersMod ! by all the possible organs in parteh, and each index ! may point to the index in the parameter file, or will be -1 - real(r8), allocatable :: nitr_recr_stoich(:) ! This is the N:C ratio of newly recruited plants that are - ! on allometry at their recruitment diameter - - real(r8), allocatable :: phos_recr_stoich(:) ! This is the P:C ratio of newly recruited plants that are - ! on allometry at their recruitment diameter - - ! Allometry Parameters ! -------------------------------------------------------------------------------------------- ! Root profile parameters. Note we have separate parameters for those that govern ! hydraulics, and those that govern biomass (for decomposition and respiration) - real(r8), allocatable :: fnrt_prof_mode(:) ! Fine root profile functional form - real(r8), allocatable :: fnrt_prof_a(:) ! Fine root profile scaling parameter A - real(r8), allocatable :: fnrt_prof_b(:) ! Fine root profile scaling parameter B + real(r8), allocatable :: fnrt_prof_mode(:) ! Fine root profile functional form + real(r8), allocatable :: fnrt_prof_a(:) ! Fine root profile scaling parameter A + real(r8), allocatable :: fnrt_prof_b(:) ! Fine root profile scaling parameter B real(r8), allocatable :: c2b(:) ! Carbon to biomass multiplier [kg/kgC] real(r8), allocatable :: wood_density(:) ! wood density g cm^-3 ... - real(r8), allocatable :: woody(:) ! Does the plant have wood? (1=yes, 0=no) - real(r8), allocatable :: crown(:) ! fraction of the height of the plant + real(r8), allocatable :: crown_depth_frac(:) ! fraction of the height of the plant + integer , allocatable :: woody(:) ! Does the plant have wood? (1=yes, 0=no) ! that is occupied by crown real(r8), allocatable :: slamax(:) ! Maximum specific leaf area of plant (at bottom) [m2/gC] real(r8), allocatable :: slatop(:) ! Specific leaf area at canopy top [m2/gC] @@ -113,13 +130,19 @@ module PRTParametersMod real(r8), allocatable :: allom_amode(:) ! AGB allometry function type real(r8), allocatable :: allom_cmode(:) ! Coarse root allometry function type real(r8), allocatable :: allom_smode(:) ! sapwood allometry function type - real(r8), allocatable :: allom_stmode(:) ! storage allometry functional type + real(r8), allocatable :: allom_stmode(:) ! storage allometry functional type + ! 0 - storage is proportional to maximum leaf biomass + ! (considering trimmed) + ! 1 - storage is proportional to maximum leaf biomass + ! (untrimmed) ! (HARD-CODED FOR TIME BEING, RGK 11-2017) real(r8), allocatable :: allom_la_per_sa_int(:) ! Leaf area to sap area conversion, intercept ! (sapwood area / leaf area) [cm2/m2] real(r8), allocatable :: allom_la_per_sa_slp(:) ! Leaf area to sap area conversion, slope ! (sapwood area / leaf area / diameter) [cm2/m2/cm] real(r8), allocatable :: allom_l2fr(:) ! Fine root biomass per leaf biomass ratio [kgC/kgC] + ! FOR C-ONLY: this is the static, unchanging ratio + ! FOR CNP: this is the initial value a cohort starts with real(r8), allocatable :: allom_agb_frac(:) ! Fraction of stem above ground [-] real(r8), allocatable :: allom_d2h1(:) ! Parameter 1 for d2h allometry (intercept, or "c") real(r8), allocatable :: allom_d2h2(:) ! Parameter 2 for d2h allometry (slope, or "m") @@ -144,6 +167,21 @@ module PRTParametersMod real(r8), allocatable :: allom_zroot_min_z(:) ! the maximum rooting depth defined at dbh = fates_allom_zroot_min_dbh [m] real(r8), allocatable :: allom_zroot_k(:) ! scale coefficient of logistic rooting depth model + + ! PID controller parameters + real(r8), allocatable :: pid_kp(:) ! proportion constant in the PID controller for fine-root biomass + real(r8), allocatable :: pid_ki(:) ! integral constant in the PID controller for fine-root biomass + real(r8), allocatable :: pid_kd(:) ! derivative constant in the PID controller for fine-root biomass + + real(r8), allocatable :: store_ovrflw_frac(:) ! For a coupled nutrient enabled simulation with dynamic fine-root biomass, + ! there will be an excess of at least two of the three species C, N or P. + ! This specifies how much excess (overflow) is allowed to be retained in storage + ! beyond the target level before it is either burned (C) or exuded (N or P). The + ! maximum value is the target * (1+store_ovrflw_frac) + + + real(r8), allocatable :: nfix_mresp_scfrac(:) ! Surcharge (as a fraction) to add to maintentance respiration + ! that is used to pay for N-Fixation end type prt_param_type diff --git a/parteh/PRTParamsFATESMod.F90 b/parteh/PRTParamsFATESMod.F90 index 208ff848fb..098b1e3738 100644 --- a/parteh/PRTParamsFATESMod.F90 +++ b/parteh/PRTParamsFATESMod.F90 @@ -32,6 +32,7 @@ module PRTInitParamsFatesMod use FatesAllometryMod, only : set_root_fraction use PRTGenericMod, only : StorageNutrientTarget use EDTypesMod, only : init_recruit_trim + use FatesConstantsMod, only : ihard_stress_decid, isemi_stress_decid ! ! !PUBLIC TYPES: @@ -50,6 +51,7 @@ module PRTInitParamsFatesMod public :: PRTReceiveParams public :: PRTCheckParams public :: PRTDerivedParams + public :: NewRecruitTotalStoichiometry !----------------------------------------------------------------------- contains @@ -104,7 +106,7 @@ subroutine PRTRegisterOrgan(fates_params) integer, parameter :: dim_lower_bound(1) = (/ lower_bound_general /) character(len=param_string_length) :: name - name = 'fates_prt_organ_id' + name = 'fates_alloc_organ_id' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) @@ -126,8 +128,8 @@ subroutine PRTReceiveOrgan(fates_params) real(r8), allocatable :: tmpreal(:) ! Temporary variable to hold floats - name = 'fates_prt_organ_id' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_alloc_organ_id' + call fates_params%RetrieveParameterAllocate(name=name, & data=tmpreal) allocate(prt_params%organ_id(size(tmpreal,dim=1))) call ArrayNint(tmpreal,prt_params%organ_id) @@ -163,15 +165,35 @@ subroutine PRTRegisterPFT(fates_params) call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_fnrt_prof_a' + name = 'fates_phen_stem_drop_fraction' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + + name = 'fates_phen_fnrt_drop_fraction' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + + name = 'fates_phen_mindaysoff' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + + name = 'fates_phen_drought_threshold' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + + name = 'fates_phen_moist_threshold' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + + name = 'fates_allom_fnrt_prof_a' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_fnrt_prof_b' + name = 'fates_allom_fnrt_prof_b' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_fnrt_prof_mode' + name = 'fates_allom_fnrt_prof_mode' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) @@ -179,7 +201,7 @@ subroutine PRTRegisterPFT(fates_params) call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_fire_crown_depth_frac' + name = 'fates_allom_crown_depth_frac' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) @@ -199,7 +221,7 @@ subroutine PRTRegisterPFT(fates_params) call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_seed_dbh_repro_threshold' + name = 'fates_recruit_seed_dbh_repro_threshold' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) @@ -207,26 +229,34 @@ subroutine PRTRegisterPFT(fates_params) call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_leaf_stor_priority' + name = 'fates_alloc_store_priority_frac' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_senleaf_long_fdrought' + name = 'fates_turnover_senleaf_fdrought' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_root_long' + name = 'fates_turnover_fnrt' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_seed_alloc_mature' + name = 'fates_recruit_seed_alloc_mature' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_seed_alloc' + name = 'fates_recruit_seed_alloc' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) + 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_trs_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) @@ -235,6 +265,26 @@ subroutine PRTRegisterPFT(fates_params) call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) + name = 'fates_cnp_pid_kd' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + + name = 'fates_cnp_pid_ki' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + + name = 'fates_cnp_pid_kp' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + + name = 'fates_cnp_store_ovrflw_frac' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + + name = 'fates_cnp_nfix1' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + name = 'fates_grperc' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) @@ -355,21 +405,17 @@ subroutine PRTRegisterPFT(fates_params) call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_turnover_retrans_mode' - call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & - dimension_names=dim_names, lower_bounds=dim_lower_bound) - - name = 'fates_branch_turnover' + name = 'fates_turnover_branch' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_nitr_store_ratio' + name = 'fates_cnp_nitr_store_ratio' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_phos_store_ratio' + name = 'fates_cnp_phos_store_ratio' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) @@ -391,234 +437,281 @@ subroutine PRTReceivePFT(fates_params) ! that are converted to ints name = 'fates_phen_stress_decid' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=tmpreal) allocate(prt_params%stress_decid(size(tmpreal,dim=1))) call ArrayNint(tmpreal,prt_params%stress_decid) deallocate(tmpreal) name = 'fates_phen_season_decid' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=tmpreal) allocate(prt_params%season_decid(size(tmpreal,dim=1))) call ArrayNint(tmpreal,prt_params%season_decid) deallocate(tmpreal) name = 'fates_phen_evergreen' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=tmpreal) allocate(prt_params%evergreen(size(tmpreal,dim=1))) call ArrayNint(tmpreal,prt_params%evergreen) deallocate(tmpreal) + name = 'fates_phen_stem_drop_fraction' + call fates_params%RetrieveParameterAllocate(name=name, & + data=prt_params%phen_stem_drop_fraction) + + name = 'fates_phen_fnrt_drop_fraction' + call fates_params%RetrieveParameterAllocate(name=name, & + data=prt_params%phen_fnrt_drop_fraction) + + name = 'fates_phen_mindaysoff' + call fates_params%RetrieveParameterAllocate(name=name, & + data=prt_params%phen_doff_time) + + name = 'fates_phen_drought_threshold' + call fates_params%RetrieveParameterAllocate(name=name, & + data=prt_params%phen_drought_threshold) + + name = 'fates_phen_moist_threshold' + call fates_params%RetrieveParameterAllocate(name=name, & + data=prt_params%phen_moist_threshold) + name = 'fates_leaf_slamax' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%slamax) name = 'fates_leaf_slatop' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%slatop) name = 'fates_allom_sai_scaler' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%allom_sai_scaler) - name = 'fates_fnrt_prof_a' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_allom_fnrt_prof_a' + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%fnrt_prof_a) - name = 'fates_fnrt_prof_b' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_allom_fnrt_prof_b' + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%fnrt_prof_b) - name = 'fates_fnrt_prof_mode' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_allom_fnrt_prof_mode' + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%fnrt_prof_mode) - name = 'fates_fire_crown_depth_frac' - call fates_params%RetreiveParameterAllocate(name=name, & - data=prt_params%crown) + name = 'fates_allom_crown_depth_frac' + call fates_params%RetrieveParameterAllocate(name=name, & + data=prt_params%crown_depth_frac) name = 'fates_woody' - call fates_params%RetreiveParameterAllocate(name=name, & - data=prt_params%woody) + call fates_params%RetrieveParameterAllocate(name=name, & + data=tmpreal) + allocate(prt_params%woody(size(tmpreal,dim=1))) + call ArrayNint(tmpreal,prt_params%woody) + deallocate(tmpreal) name = 'fates_wood_density' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%wood_density) - name = 'fates_seed_dbh_repro_threshold' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_recruit_seed_dbh_repro_threshold' + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%dbh_repro_threshold) name = 'fates_alloc_storage_cushion' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%cushion) - name = 'fates_leaf_stor_priority' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_alloc_store_priority_frac' + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%leaf_stor_priority) - name = 'fates_senleaf_long_fdrought' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_turnover_senleaf_fdrought' + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%senleaf_long_fdrought) - name = 'fates_root_long' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_turnover_fnrt' + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%root_long) - name = 'fates_seed_alloc_mature' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_recruit_seed_alloc_mature' + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%seed_alloc_mature) - - name = 'fates_seed_alloc' - call fates_params%RetreiveParameterAllocate(name=name, & + + name = 'fates_recruit_seed_alloc' + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%seed_alloc) + name = 'fates_trs_repro_alloc_a' + call fates_params%RetrieveParameterAllocate(name=name, & + data=prt_params%repro_alloc_a) + + name = 'fates_trs_repro_alloc_b' + call fates_params%RetrieveParameterAllocate(name=name, & + data=prt_params%repro_alloc_b) + name = 'fates_c2b' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%c2b) name = 'fates_grperc' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%grperc) name = 'fates_allom_dbh_maxheight' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%allom_dbh_maxheight) name = 'fates_allom_hmode' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%allom_hmode) name = 'fates_allom_lmode' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%allom_lmode) name = 'fates_allom_fmode' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%allom_fmode) name = 'fates_allom_amode' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%allom_amode) name = 'fates_allom_stmode' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%allom_stmode) name = 'fates_allom_cmode' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%allom_cmode) name = 'fates_allom_smode' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%allom_smode) name = 'fates_allom_la_per_sa_int' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%allom_la_per_sa_int) name = 'fates_allom_la_per_sa_slp' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%allom_la_per_sa_slp) name = 'fates_allom_l2fr' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%allom_l2fr) + name = 'fates_cnp_pid_kp' + call fates_params%RetrieveParameterAllocate(name=name, & + data=prt_params%pid_kp) + + name = 'fates_cnp_pid_ki' + call fates_params%RetrieveParameterAllocate(name=name, & + data=prt_params%pid_ki) + + name = 'fates_cnp_pid_kd' + call fates_params%RetrieveParameterAllocate(name=name, & + data=prt_params%pid_kd) + + name = 'fates_cnp_store_ovrflw_frac' + call fates_params%RetrieveParameterAllocate(name=name, & + data=prt_params%store_ovrflw_frac) + + name = 'fates_cnp_nfix1' + call fates_params%RetrieveParameterAllocate(name=name, & + data=prt_params%nfix_mresp_scfrac) + name = 'fates_allom_agb_frac' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%allom_agb_frac) name = 'fates_allom_d2h1' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%allom_d2h1) name = 'fates_allom_d2h2' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%allom_d2h2) name = 'fates_allom_d2h3' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%allom_d2h3) name = 'fates_allom_d2bl1' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%allom_d2bl1) name = 'fates_allom_d2bl2' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%allom_d2bl2) name = 'fates_allom_d2bl3' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%allom_d2bl3) name = 'fates_allom_blca_expnt_diff' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%allom_blca_expnt_diff) name = 'fates_allom_d2ca_coefficient_max' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%allom_d2ca_coefficient_max) name = 'fates_allom_d2ca_coefficient_min' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%allom_d2ca_coefficient_min) name = 'fates_allom_agb1' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%allom_agb1) name = 'fates_allom_agb2' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%allom_agb2) name = 'fates_allom_agb3' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%allom_agb3) name = 'fates_allom_agb4' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%allom_agb4) name = 'fates_allom_zroot_max_dbh' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%allom_zroot_max_dbh) name = 'fates_allom_zroot_max_z' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%allom_zroot_max_z) name = 'fates_allom_zroot_min_dbh' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%allom_zroot_min_dbh) name = 'fates_allom_zroot_min_z' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%allom_zroot_min_z) name = 'fates_allom_zroot_k' - call fates_params%RetreiveParameterAllocate(name=name, & + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%allom_zroot_k) - name = 'fates_branch_turnover' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_turnover_branch' + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%branch_long) - name = 'fates_turnover_retrans_mode' - call fates_params%RetreiveParameterAllocate(name=name, & - data=prt_params%turnover_retrans_mode) - - name = 'fates_nitr_store_ratio' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_cnp_nitr_store_ratio' + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%nitr_store_ratio) - name = 'fates_phos_store_ratio' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_cnp_phos_store_ratio' + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%phos_store_ratio) - + end subroutine PRTReceivePFT @@ -641,7 +734,7 @@ subroutine PRTRegisterPFTLeafAge(fates_params) dim_names(1) = dimension_name_pft dim_names(2) = dimension_name_leaf_age - name = 'fates_leaf_long' + name = 'fates_turnover_leaf' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_2d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) @@ -703,7 +796,7 @@ subroutine Receive_PFT_nvariants(fates_params) character(len=param_string_length) :: name !X! name = '' - !X! call fates_params%RetreiveParameter(name=name, & + !X! call fates_params%RetrieveParameter(name=name, & !X! data=this%) end subroutine Receive_PFT_nvariants @@ -721,8 +814,8 @@ subroutine PRTReceivePFTLeafAge(fates_params) character(len=param_string_length) :: name - name = 'fates_leaf_long' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_turnover_leaf' + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%leaf_long) return @@ -750,35 +843,23 @@ subroutine PRTRegisterPFTOrgans(fates_params) dim_names(1) = dimension_name_pft dim_names(2) = dimension_name_prt_organs - name = 'fates_prt_nitr_stoich_p1' - call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_2d, & - dimension_names=dim_names, lower_bounds=dim_lower_bound) - - name = 'fates_prt_nitr_stoich_p2' - call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_2d, & - dimension_names=dim_names, lower_bounds=dim_lower_bound) - - name = 'fates_prt_phos_stoich_p1' + name = 'fates_stoich_nitr' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_2d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_prt_phos_stoich_p2' + name = 'fates_stoich_phos' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_2d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_prt_alloc_priority' + name = 'fates_alloc_organ_priority' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_2d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_turnover_carb_retrans' - call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_2d, & - dimension_names=dim_names, lower_bounds=dim_lower_bound) - - name = 'fates_turnover_nitr_retrans' + name = 'fates_cnp_turnover_nitr_retrans' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_2d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_turnover_phos_retrans' + name = 'fates_cnp_turnover_phos_retrans' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_2d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) @@ -798,36 +879,24 @@ subroutine PRTReceivePFTOrgans(fates_params) character(len=param_string_length) :: name - name = 'fates_prt_nitr_stoich_p1' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_stoich_nitr' + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%nitr_stoich_p1) - name = 'fates_prt_nitr_stoich_p2' - call fates_params%RetreiveParameterAllocate(name=name, & - data=prt_params%nitr_stoich_p2) - - name = 'fates_prt_phos_stoich_p1' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_stoich_phos' + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%phos_stoich_p1) - name = 'fates_prt_phos_stoich_p2' - call fates_params%RetreiveParameterAllocate(name=name, & - data=prt_params%phos_stoich_p2) - - name = 'fates_prt_alloc_priority' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_alloc_organ_priority' + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%alloc_priority) - name = 'fates_turnover_carb_retrans' - call fates_params%RetreiveParameterAllocate(name=name, & - data=prt_params%turnover_carb_retrans) - - name = 'fates_turnover_nitr_retrans' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_cnp_turnover_nitr_retrans' + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%turnover_nitr_retrans) - name = 'fates_turnover_phos_retrans' - call fates_params%RetreiveParameterAllocate(name=name, & + name = 'fates_cnp_turnover_phos_retrans' + call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%turnover_phos_retrans) end subroutine PRTReceivePFTOrgans @@ -840,6 +909,7 @@ subroutine FatesReportPFTParams(is_master) logical, intent(in) :: is_master ! Only log if this is the master proc logical, parameter :: debug_report = .false. + character(len=15),parameter :: fmti = '(a,100(I12,1X))' character(len=32),parameter :: fmt0 = '(a,100(F12.4,1X))' integer :: npft,ipft @@ -856,9 +926,14 @@ subroutine FatesReportPFTParams(is_master) end if write(fates_log(),*) '----------- FATES PARTEH Parameters -----------------' - write(fates_log(),fmt0) 'stress_decid = ',prt_params%stress_decid - write(fates_log(),fmt0) 'season_decid = ',prt_params%season_decid - write(fates_log(),fmt0) 'evergreen = ',prt_params%evergreen + write(fates_log(),fmti) 'stress_decid = ',prt_params%stress_decid + write(fates_log(),fmti) 'season_decid = ',prt_params%season_decid + write(fates_log(),fmti) 'evergreen = ',prt_params%evergreen + write(fates_log(),fmt0) 'phen_fnrt_drop_fraction = ',prt_params%phen_fnrt_drop_fraction + write(fates_log(),fmt0) 'phen_stem_drop_fraction = ',prt_params%phen_stem_drop_fraction + write(fates_log(),fmt0) 'phen_doff_time = ',prt_params%phen_doff_time + write(fates_log(),fmt0) 'phen_drought_threshold = ',prt_params%phen_drought_threshold + write(fates_log(),fmt0) 'phen_moist_threshold = ',prt_params%phen_moist_threshold write(fates_log(),fmt0) 'wood_density = ',prt_params%wood_density write(fates_log(),fmt0) 'dbh max height = ',prt_params%allom_dbh_maxheight write(fates_log(),fmt0) 'dbh mature = ',prt_params%dbh_repro_threshold @@ -868,6 +943,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 + write(fates_log(),fmt0) 'repro_alloc_b = ',prt_params%repro_alloc_b 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 @@ -884,6 +961,10 @@ subroutine FatesReportPFTParams(is_master) write(fates_log(),fmt0) 'allom_la_per_sa_int = ',prt_params%allom_la_per_sa_int write(fates_log(),fmt0) 'allom_la_per_sa_slp = ',prt_params%allom_la_per_sa_slp write(fates_log(),fmt0) 'allom_l2fr = ',prt_params%allom_l2fr + write(fates_log(),fmt0) 'pid_kp = ',prt_params%pid_kp + write(fates_log(),fmt0) 'pid_ki = ',prt_params%pid_ki + write(fates_log(),fmt0) 'pid_kd = ',prt_params%pid_kd + write(fates_log(),fmt0) 'store_ovrflw_frac = ',prt_params%store_ovrflw_frac write(fates_log(),fmt0) 'allom_agb_frac = ',prt_params%allom_agb_frac write(fates_log(),fmt0) 'allom_d2h1 = ',prt_params%allom_d2h1 write(fates_log(),fmt0) 'allom_d2h2 = ',prt_params%allom_d2h2 @@ -905,20 +986,17 @@ subroutine FatesReportPFTParams(is_master) write(fates_log(),fmt0) 'allom_zroot_min_z = ',prt_params%allom_zroot_min_z write(fates_log(),fmt0) 'allom_zroot_k = ',prt_params%allom_zroot_k - write(fates_log(),fmt0) 'prt_nitr_stoich_p1 = ',prt_params%nitr_stoich_p1 - write(fates_log(),fmt0) 'prt_nitr_stoich_p2 = ',prt_params%nitr_stoich_p2 - write(fates_log(),fmt0) 'prt_phos_stoich_p1 = ',prt_params%phos_stoich_p1 - write(fates_log(),fmt0) 'prt_phos_stoich_p2 = ',prt_params%phos_stoich_p2 - write(fates_log(),fmt0) 'prt_alloc_priority = ',prt_params%alloc_priority + write(fates_log(),fmt0) 'stoich_nitr = ',prt_params%nitr_stoich_p1 + write(fates_log(),fmt0) 'stoich_phos = ',prt_params%phos_stoich_p1 + write(fates_log(),fmt0) 'alloc_organ_priority = ',prt_params%alloc_priority write(fates_log(),fmt0) 'woody = ',prt_params%woody - write(fates_log(),fmt0) 'crown = ',prt_params%crown + write(fates_log(),fmt0) 'crown_depth_frac = ',prt_params%crown_depth_frac write(fates_log(),fmt0) 'roota_par = ',prt_params%fnrt_prof_a write(fates_log(),fmt0) 'rootb_par = ',prt_params%fnrt_prof_b write(fates_log(),fmt0) 'fnrt_prof_mode = ',prt_params%fnrt_prof_mode - write(fates_log(),fmt0) 'turnover_carb_retrans = ',prt_params%turnover_carb_retrans write(fates_log(),fmt0) 'turnover_nitr_retrans = ',prt_params%turnover_nitr_retrans write(fates_log(),fmt0) 'turnover_phos_retrans = ',prt_params%turnover_phos_retrans - write(fates_log(),fmt0) 'organ_id = ',prt_params%organ_id + write(fates_log(),fmti) 'organ_id = ',prt_params%organ_id write(fates_log(),fmt0) 'nitr_store_ratio = ',prt_params%nitr_store_ratio write(fates_log(),fmt0) 'phos_store_ratio = ',prt_params%phos_store_ratio write(fates_log(),*) '-------------------------------------------------' @@ -941,8 +1019,6 @@ subroutine PRTDerivedParams() ! Set the reverse lookup map for organs to the parameter file index allocate(prt_params%organ_param_id(num_organ_types)) - allocate(prt_params%nitr_recr_stoich(npft)) - allocate(prt_params%phos_recr_stoich(npft)) ! Initialize them as invalid prt_params%organ_param_id(:) = -1 @@ -951,18 +1027,6 @@ subroutine PRTDerivedParams() prt_params%organ_param_id(prt_params%organ_id(i)) = i end do - - ! Calculate the stoichiometry of a new recruit, and use this for defining - ! seed stoichiometry and - - do ft = 1,npft - - prt_params%nitr_recr_stoich(ft) = NewRecruitTotalStoichiometry(ft,nitrogen_element) - prt_params%phos_recr_stoich(ft) = NewRecruitTotalStoichiometry(ft,phosphorus_element) - - end do - - return end subroutine PRTDerivedParams @@ -986,12 +1050,16 @@ subroutine PRTCheckParams(is_master) character(len=32),parameter :: fmt0 = '(a,100(F12.4,1X))' - integer :: npft ! number of PFTs - integer :: ipft ! pft index - integer :: nleafage ! size of the leaf age class array - integer :: iage ! leaf age class index - integer :: norgans ! size of the plant organ dimension - integer :: i, io ! generic loop index and organ loop index + integer :: npft ! number of PFTs + integer :: ipft ! pft index + integer :: nleafage ! size of the leaf age class array + integer :: iage ! leaf age class index + integer :: norgans ! size of the plant organ dimension + integer :: i, io ! generic loop index and organ loop index + logical :: is_evergreen ! Is the PFT evergreen + logical :: is_season_decid ! Is the PFT cold-deciduous? + logical :: is_stress_decid ! Is the PFT drought-deciduous? + logical :: is_semi_decid ! Is the PFT drought semi-deciduous? npft = size(prt_params%evergreen,1) @@ -1014,50 +1082,148 @@ subroutine PRTCheckParams(is_master) ! Check to make sure the organ ids are valid if this is the ! cnp_flex_allom_hypothesis - if ((hlm_parteh_mode .eq. prt_cnp_flex_allom_hyp) .or. & - (hlm_parteh_mode .eq. prt_carbon_allom_hyp) ) then + select case (hlm_parteh_mode) + case (prt_carbon_allom_hyp,prt_cnp_flex_allom_hyp) do io = 1,norgans if(prt_params%organ_id(io) == repro_organ) then - write(fates_log(),*) 'with flexible cnp or c-only alloc hypothesese' + write(fates_log(),*) 'with flexible cnp or c-only alloc hypotheses' write(fates_log(),*) 'reproductive tissues are a special case' write(fates_log(),*) 'and therefore should not be included in' write(fates_log(),*) 'the parameter file organ list' write(fates_log(),*) 'fates_prt_organ_id: ',prt_params%organ_id(:) write(fates_log(),*) 'Aborting' + call endrun(msg=errMsg(sourcefile, __LINE__)) end if if(prt_params%organ_id(io) == store_organ) then - write(fates_log(),*) 'with flexible cnp or c-only alloc hypothesese' + write(fates_log(),*) 'with flexible cnp or c-only alloc hypotheses' write(fates_log(),*) 'storage is a special case' write(fates_log(),*) 'and therefore should not be included in' write(fates_log(),*) 'the parameter file organ list' write(fates_log(),*) 'fates_prt_organ_id: ',prt_params%organ_id(:) write(fates_log(),*) 'Aborting' + call endrun(msg=errMsg(sourcefile, __LINE__)) end if - + end do + end select + + ! Make sure that the N fixation respiration surcharge fraction is + ! between 0 and 1 + if (hlm_parteh_mode .eq. prt_cnp_flex_allom_hyp) then + if(any(prt_params%nfix_mresp_scfrac(:)<0._r8) .or. any(prt_params%nfix_mresp_scfrac(:)>1.0_r8)) then + write(fates_log(),*) 'The N fixation surcharge nfix_mresp_sfrac (fates_nfix1) must be between 0-1.' + write(fates_log(),*) 'here are the values: ',prt_params%nfix_mresp_scfrac(:) + write(fates_log(),*) 'Aborting' + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if end if + pftloop: do ipft = 1,npft ! Check to see if evergreen, deciduous flags are mutually exclusive + ! By the way, if these are mutually exclusive, shouldn't we define a + ! single prt_params%leaf_phenology and a list of codes for the different + ! types (i.e., ievergreen, iseason_decid, istress_hard, istress_semi, etc.)? ! ---------------------------------------------------------------------------------- + is_evergreen = prt_params%evergreen(ipft) == itrue + is_season_decid = prt_params%season_decid(ipft) == itrue + is_stress_decid = any(prt_params%stress_decid(ipft) == [ihard_stress_decid,isemi_stress_decid]) + is_semi_decid = prt_params%stress_decid(ipft) == isemi_stress_decid + + if ( ( is_evergreen .and. is_season_decid ) .or. & + ( is_evergreen .and. is_stress_decid ) .or. & + ( is_season_decid .and. is_stress_decid ) ) then - if ( int(prt_params%evergreen(ipft) + & - prt_params%season_decid(ipft) + & - prt_params%stress_decid(ipft)) .ne. 1 ) then - write(fates_log(),*) 'PFT # ',ipft,' must be defined as having one of three' - write(fates_log(),*) 'phenology habits, ie == 1' + write(fates_log(),*) 'phenology habits, ie, only one of the flags below should' + write(fates_log(),*) 'be different than ',ifalse write(fates_log(),*) 'stress_decid: ',prt_params%stress_decid(ipft) write(fates_log(),*) 'season_decid: ',prt_params%season_decid(ipft) write(fates_log(),*) 'evergreen: ',prt_params%evergreen(ipft) write(fates_log(),*) 'Aborting' call endrun(msg=errMsg(sourcefile, __LINE__)) - end if + ! When using the the drought semi-deciduous phenology, we must ensure that the lower + ! and upper thresholds are consistent (i.e., that both are based on either soil + ! water content or soil matric potential). + if (is_semi_decid) then + if ( prt_params%phen_drought_threshold(ipft)*prt_params%phen_moist_threshold(ipft) < 0._r8 ) then + ! In case the product of the lower and upper thresholds is negative, the + ! thresholds are inconsistent as both should be defined using the same + ! quantity. + write(fates_log(),*) ' When using drought semi-deciduous phenology,' + write(fates_log(),*) ' the moist threshold must have the same sign as' + write(fates_log(),*) ' the dry threshold. Positive = soil water content [m3/m3],' + write(fates_log(),*) ' Negative = soil matric potential [mm].' + write(fates_log(),*) ' PFT = ',ipft + write(fates_log(),*) ' Stress_decid = ',prt_params%stress_decid(ipft) + write(fates_log(),*) ' fates_phen_drought_threshold = ',prt_params%phen_drought_threshold(ipft) + write(fates_log(),*) ' fates_phen_moist_threshold = ',prt_params%phen_moist_threshold (ipft) + write(fates_log(),*) ' Aborting' + call endrun(msg=errMsg(sourcefile, __LINE__)) + + elseif ( prt_params%phen_drought_threshold(ipft) >= prt_params%phen_moist_threshold(ipft) ) then + write(fates_log(),*) ' When using drought semi-deciduous phenology,' + write(fates_log(),*) ' the moist threshold must be greater than the dry threshold.' + write(fates_log(),*) ' By greater we mean more positive or less negative, and' + write(fates_log(),*) ' they cannot be the identical.' + write(fates_log(),*) ' PFT = ',ipft + write(fates_log(),*) ' Stress_decid = ',prt_params%stress_decid(ipft) + write(fates_log(),*) ' fates_phen_drought_threshold = ',prt_params%phen_drought_threshold(ipft) + write(fates_log(),*) ' fates_phen_moist_threshold = ',prt_params%phen_moist_threshold (ipft) + write(fates_log(),*) ' Aborting' + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + end if + + ! For all deciduous PFTs, check that abscission fractions are all bounded. + if (prt_params%evergreen(ipft) == ifalse) then + ! Check if the fraction of fine roots to be actively abscised relative to leaf abscission + ! is bounded between 0 and 1 (exactly 0 and 1 are acceptable). + if ( ( prt_params%phen_fnrt_drop_fraction(ipft) < 0.0_r8 ) .or. & + ( prt_params%phen_fnrt_drop_fraction(ipft) > 1.0_r8 ) ) then + write(fates_log(),*) ' Abscission rate for fine roots must be between 0 and 1 for ' + write(fates_log(),*) ' deciduous PFTs.' + write(fates_log(),*) ' PFT#: ',ipft + write(fates_log(),*) ' evergreen flag: (should be 0):',prt_params%evergreen(ipft) + write(fates_log(),*) ' phen_fnrt_drop_fraction: ', prt_params%phen_fnrt_drop_fraction(ipft) + write(fates_log(),*) ' Aborting' + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + + + ! Check if the fraction of stems to be actively abscised relative to leaf abscission + ! is bounded between 0 and 1 (exactly 0 and 1 are acceptable) when PFTs are non-woody, and + ! that the fraction is zero for woody PFTs. Stem abscission is a solution to avoid hydraulic + ! problems when plant hydraulics is enabled. + if ( ( prt_params%woody(ipft) == itrue ) .and. & + ( ( prt_params%phen_stem_drop_fraction(ipft) < 0.0_r8 ) .or. & + ( prt_params%phen_stem_drop_fraction(ipft) > nearzero ) ) ) then + write(fates_log(),*) ' Non-zero stem-drop fractions are not allowed for woody plants' + write(fates_log(),*) ' PFT#: ',ipft + write(fates_log(),*) ' part_params%woody:',prt_params%woody(ipft) + write(fates_log(),*) ' phen_stem_drop_fraction: ', prt_params%phen_stem_drop_fraction(ipft) + write(fates_log(),*) ' Aborting' + call endrun(msg=errMsg(sourcefile, __LINE__)) + elseif ( ( prt_params%phen_stem_drop_fraction(ipft) < 0.0_r8 ) .or. & + ( prt_params%phen_stem_drop_fraction(ipft) > 1.0_r8 ) ) then + write(fates_log(),*) ' Deciduous non-wood plants must keep 0-100% of their stems' + write(fates_log(),*) ' during the deciduous period.' + write(fates_log(),*) ' PFT#: ',ipft + write(fates_log(),*) ' evergreen flag: (should be 0):',prt_params%evergreen(ipft) + write(fates_log(),*) ' phen_stem_drop_fraction: ', prt_params%phen_stem_drop_fraction(ipft) + write(fates_log(),*) ' Aborting' + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + end if + + + + ! Check to see if mature and base seed allocation is greater than 1 ! ---------------------------------------------------------------------------------- if ( ( prt_params%seed_alloc(ipft) + & @@ -1076,13 +1242,13 @@ subroutine PRTCheckParams(is_master) ! Check if woody plants have a structural biomass (agb) intercept ! ---------------------------------------------------------------------------------- if ( ( prt_params%allom_agb1(ipft) <= tiny(prt_params%allom_agb1(ipft)) ) .and. & - ( int(prt_params%woody(ipft)) .eq. 1 ) ) then + ( prt_params%woody(ipft) .eq. 1 ) ) then write(fates_log(),*) 'Woody plants are expected to have a non-zero intercept' write(fates_log(),*) ' in the diameter to AGB allometry equations' write(fates_log(),*) ' PFT#: ',ipft write(fates_log(),*) ' allom_agb1: ',prt_params%allom_agb1(ipft) - write(fates_log(),*) ' woody: ',int(prt_params%woody(ipft)) + write(fates_log(),*) ' woody: ',prt_params%woody(ipft) write(fates_log(),*) ' Aborting' call endrun(msg=errMsg(sourcefile, __LINE__)) @@ -1091,7 +1257,7 @@ subroutine PRTCheckParams(is_master) ! Check if non-woody plants have structural biomass (agb) intercept ! ---------------------------------------------------------------------------------- ! if ( ( prt_params%allom_agb1(ipft) > tiny(prt_params%allom_agb1(ipft)) ) .and. & -! ( int(prt_params%woody(ipft)) .ne. 1 ) ) then +! ( iprt_params%woody(ipft) .ne. 1 ) ) then ! ! write(fates_log(),*) 'Non-woody plants are expected to have a zero intercept' ! write(fates_log(),*) ' in the diameter to AGB allometry equations' @@ -1100,7 +1266,7 @@ subroutine PRTCheckParams(is_master) ! write(fates_log(),*) ' woody tissues (sap and structural dead wood).' ! write(fates_log(),*) ' PFT#: ',ipft ! write(fates_log(),*) ' allom_agb1: ',prt_params%allom_agb1(ipft) -! write(fates_log(),*) ' woody: ',int(prt_params%woody(ipft)) +! write(fates_log(),*) ' woody: ',prt_params%woody(ipft) ! write(fates_log(),*) ' Aborting' ! call endrun(msg=errMsg(sourcefile, __LINE__)) ! @@ -1122,53 +1288,9 @@ subroutine PRTCheckParams(is_master) end if + select case (hlm_parteh_mode) + case (prt_cnp_flex_allom_hyp) - ! Check re-translocations - ! Seems reasonable to assume that sapwood, structure and reproduction - ! should not be re-translocating mass upon turnover. - ! Note to advanced users. Feel free to remove these checks... - ! ------------------------------------------------------------------- - - if ((hlm_parteh_mode .eq. prt_cnp_flex_allom_hyp) .or. & - (hlm_parteh_mode .eq. prt_carbon_allom_hyp) ) then - - do i = 1,norgans - io = prt_params%organ_id(i) - - if(io == sapw_organ) then - if ((prt_params%turnover_carb_retrans(ipft,i) > nearzero)) then - write(fates_log(),*) ' Retranslocation of sapwood tissues should be zero.' - write(fates_log(),*) ' PFT#: ',ipft - write(fates_log(),*) ' carbon retrans: ',prt_params%turnover_carb_retrans(ipft,i) - write(fates_log(),*) ' Aborting' - call endrun(msg=errMsg(sourcefile, __LINE__)) - end if - elseif(io == struct_organ) then - if ((prt_params%turnover_carb_retrans(ipft,i) > nearzero)) then - write(fates_log(),*) ' Retranslocation of structural tissues should be zero.' - write(fates_log(),*) ' PFT#: ',ipft - write(fates_log(),*) ' carbon retrans: ',prt_params%turnover_carb_retrans(ipft,i) - write(fates_log(),*) ' Aborting' - call endrun(msg=errMsg(sourcefile, __LINE__)) - end if - end if - - ! Otherwise, all other retranslocations should be between 0 and 1 - if ( (prt_params%turnover_carb_retrans(ipft,i) > 1.0_r8) .or. & - (prt_params%turnover_carb_retrans(ipft,i) < 0.0_r8) ) then - write(fates_log(),*) ' Retranslocation rates should be between 0 and 1.' - write(fates_log(),*) ' PFT#: ',ipft - write(fates_log(),*) ' parameter file index: ',i,' global index: ',io - write(fates_log(),*) ' retranslocation rate: ',prt_params%turnover_carb_retrans(ipft,i) - write(fates_log(),*) ' Aborting' - call endrun(msg=errMsg(sourcefile, __LINE__)) - end if - - end do - end if - - if (hlm_parteh_mode .eq. prt_cnp_flex_allom_hyp) then - ! Make sure nutrient storage fractions are positive if( prt_params%nitr_store_ratio(ipft) < 0._r8 ) then write(fates_log(),*) 'With parteh allometric CNP hypothesis' @@ -1235,9 +1357,9 @@ subroutine PRTCheckParams(is_master) end if end do - - end if - + + end select + ! Growth respiration ! if (parteh_mode .eq. prt_carbon_allom_hyp) then @@ -1258,8 +1380,8 @@ subroutine PRTCheckParams(is_master) ! end if ! end if - if ((hlm_parteh_mode .eq. prt_cnp_flex_allom_hyp) .or. & - (hlm_parteh_mode .eq. prt_carbon_allom_hyp) ) then + select case (hlm_parteh_mode) + case (prt_carbon_allom_hyp,prt_cnp_flex_allom_hyp) ! The first nitrogen stoichiometry is used in all cases if ( (any(prt_params%nitr_stoich_p1(ipft,:) < 0.0_r8)) .or. & (any(prt_params%nitr_stoich_p1(ipft,:) >= 1.0_r8))) then @@ -1269,32 +1391,25 @@ subroutine PRTCheckParams(is_master) write(fates_log(),*) ' Aborting' call endrun(msg=errMsg(sourcefile, __LINE__)) end if - end if + end select - if(hlm_parteh_mode .eq. prt_cnp_flex_allom_hyp) then + select case (hlm_parteh_mode) + case (prt_cnp_flex_allom_hyp) do i = 1,norgans if ( (prt_params%nitr_stoich_p1(ipft,i) < 0._r8) .or. & - (prt_params%nitr_stoich_p2(ipft,i) < 0._r8) .or. & (prt_params%phos_stoich_p1(ipft,i) < 0._r8) .or. & - (prt_params%phos_stoich_p2(ipft,i) < 0._r8) .or. & (prt_params%nitr_stoich_p1(ipft,i) > 1._r8) .or. & - (prt_params%nitr_stoich_p2(ipft,i) > 1._r8) .or. & - (prt_params%phos_stoich_p1(ipft,i) > 1._r8) .or. & - (prt_params%phos_stoich_p2(ipft,i) > 1._r8) ) then + (prt_params%phos_stoich_p1(ipft,i) > 1._r8) ) then write(fates_log(),*) 'When the C,N,P allocation hypothesis with flexible' write(fates_log(),*) 'stoichiometry is turned on (prt_cnp_flex_allom_hyp),' write(fates_log(),*) 'all stoichiometries must be greater than or equal to zero,' write(fates_log(),*) 'and less than 1 (probably way less than 1).' - write(fates_log(),*) 'Setting both p1 and p2 parameters to zero will turn' - write(fates_log(),*) 'off nutrient dynamics for the given species.' write(fates_log(),*) 'You specified an organ/pft less than zero.' write(fates_log(),*) 'PFT: ',ipft write(fates_log(),*) 'organ index (see head of PRTGenericMod): ',io - write(fates_log(),*) 'nitr_stoich_p1: ',prt_params%nitr_stoich_p1(ipft,i) - write(fates_log(),*) 'nitr_stoich_p2: ',prt_params%phos_stoich_p1(ipft,i) - write(fates_log(),*) 'phos_stoich_p1: ',prt_params%nitr_stoich_p2(ipft,i) - write(fates_log(),*) 'phos_stoich_p2: ',prt_params%phos_stoich_p2(ipft,i) + write(fates_log(),*) 'nitr_stoich: ',prt_params%nitr_stoich_p1(ipft,i) + write(fates_log(),*) 'phos_stoich: ',prt_params%phos_stoich_p1(ipft,i) write(fates_log(),*) 'Aborting' call endrun(msg=errMsg(sourcefile, __LINE__)) end if @@ -1309,7 +1424,7 @@ subroutine PRTCheckParams(is_master) call endrun(msg=errMsg(sourcefile, __LINE__)) end if - end if + end select ! Check turnover time-scales @@ -1428,7 +1543,7 @@ end subroutine PRTCheckParams ! ==================================================================================== - function NewRecruitTotalStoichiometry(ft,element_id) result(recruit_stoich) + function NewRecruitTotalStoichiometry(ft,l2fr,element_id) result(recruit_stoich) ! ---------------------------------------------------------------------------------- ! This function calculates the total N:C or P:C ratio for a newly recruited plant @@ -1442,10 +1557,10 @@ function NewRecruitTotalStoichiometry(ft,element_id) result(recruit_stoich) ! into new recruits. ! ---------------------------------------------------------------------------------- - - integer,intent(in) :: ft - integer,intent(in) :: element_id - real(r8) :: recruit_stoich ! nutrient to carbon ratio of recruit + integer,intent(in) :: ft + integer,intent(in) :: element_id + real(r8),intent(in) :: l2fr + real(r8) :: recruit_stoich ! nutrient to carbon ratio of recruit real(r8) :: dbh ! dbh of the new recruit [cm] real(r8) :: c_leaf ! target leaf biomass [kgC] @@ -1459,14 +1574,17 @@ function NewRecruitTotalStoichiometry(ft,element_id) result(recruit_stoich) real(r8) :: c_total ! total target carbon real(r8) :: nutr_total ! total target nutrient + integer, parameter :: not_damaged = 1 ! this is also in MainDamageMod, here for dependency purposes + + ! For all tissues, assume tissues of new recruits will be fully flushed. call h2d_allom(EDPftvarcon_inst%hgt_min(ft),ft,dbh) - call bleaf(dbh,ft,init_recruit_trim,c_leaf) - call bfineroot(dbh,ft,init_recruit_trim,c_fnrt) - call bsap_allom(dbh,ft,init_recruit_trim,a_sapw, c_sapw) - call bagw_allom(dbh,ft,c_agw) - call bbgw_allom(dbh,ft,c_bgw) + call bleaf(dbh,ft,not_damaged,init_recruit_trim, 1.0_r8, c_leaf) + call bfineroot(dbh,ft,init_recruit_trim,l2fr, 1.0_r8,c_fnrt) + call bsap_allom(dbh,ft,not_damaged,init_recruit_trim, 1.0_r8,a_sapw, c_sapw) + call bagw_allom(dbh,ft,not_damaged, 1.0_r8,c_agw) + call bbgw_allom(dbh,ft, 1.0_r8,c_bgw) call bdead_allom(c_agw,c_bgw,c_sapw,ft,c_struct) - call bstore_allom(dbh,ft,init_recruit_trim,c_store) + call bstore_allom(dbh,ft,not_damaged,init_recruit_trim,c_store) ! Total carbon in a newly recruited plant c_total = c_leaf + c_fnrt + c_sapw + c_struct + c_store @@ -1476,28 +1594,28 @@ function NewRecruitTotalStoichiometry(ft,element_id) result(recruit_stoich) case(nitrogen_element) nutr_total = & - 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)) + & + c_struct*prt_params%nitr_stoich_p1(ft,prt_params%organ_param_id(struct_organ)) + & + c_leaf*prt_params%nitr_stoich_p1(ft,prt_params%organ_param_id(leaf_organ)) + & + c_fnrt*prt_params%nitr_stoich_p1(ft,prt_params%organ_param_id(fnrt_organ)) + & + c_sapw*prt_params%nitr_stoich_p1(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))) + c_leaf*prt_params%nitr_stoich_p1(ft,prt_params%organ_param_id(leaf_organ)), & + c_fnrt*prt_params%nitr_stoich_p1(ft,prt_params%organ_param_id(fnrt_organ)), & + c_sapw*prt_params%nitr_stoich_p1(ft,prt_params%organ_param_id(sapw_organ)), & + c_struct*prt_params%nitr_stoich_p1(ft,prt_params%organ_param_id(struct_organ))) case(phosphorus_element) nutr_total = & - 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)) + & + c_struct*prt_params%phos_stoich_p1(ft,prt_params%organ_param_id(struct_organ)) + & + c_leaf*prt_params%phos_stoich_p1(ft,prt_params%organ_param_id(leaf_organ)) + & + c_fnrt*prt_params%phos_stoich_p1(ft,prt_params%organ_param_id(fnrt_organ)) + & + c_sapw*prt_params%phos_stoich_p1(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))) + c_leaf*prt_params%phos_stoich_p1(ft,prt_params%organ_param_id(leaf_organ)), & + c_fnrt*prt_params%phos_stoich_p1(ft,prt_params%organ_param_id(fnrt_organ)), & + c_sapw*prt_params%phos_stoich_p1(ft,prt_params%organ_param_id(sapw_organ)), & + c_struct*prt_params%phos_stoich_p1(ft,prt_params%organ_param_id(struct_organ))) end select diff --git a/tools/BatchPatchParams.py b/tools/BatchPatchParams.py index ee78ebcbd0..99a6f6bd76 100755 --- a/tools/BatchPatchParams.py +++ b/tools/BatchPatchParams.py @@ -8,7 +8,9 @@ import argparse import code # For development: code.interact(local=dict(globals(), **locals())) from scipy.io import netcdf +import xml.etree.ElementTree as et +debug = True # --------------------------------------------------------------------------------------- @@ -22,7 +24,7 @@ def __init__(self,name,values_text): def load_xml(xmlfile): - import xml.etree.ElementTree as et + xmlroot = et.parse(xmlfile).getroot() print("\nOpenend: "+xmlfile) @@ -30,16 +32,31 @@ def load_xml(xmlfile): base_cdl = xmlroot.find('base_file').text new_cdl = xmlroot.find('new_file').text - pftparams = xmlroot.find('pft_list').text.replace(" ","") + pftparams = xmlroot.find('pft_trim_list').text.replace(" ","") paramroot = xmlroot.find('parameters') - paramlist = [] - for param in paramroot: - print("parsing "+param.tag) - paramlist.append(param_type(param.tag,param.text)) + + grouplist = [] + for group in paramroot: + + if(not('ids' in group.attrib.keys())): + print("pft_mod_group must have an ids attribute with comma delimited pft indices") + print("exiting") + exit(2) + + pft_str = group.attrib['ids'].strip() + pft_strvec = pft_str.split(',') + pft_ids = [int(s) for s in pft_strvec] + print("Processing PFT group: "+group.tag+" ids: "+pft_str) + + #paramlist = [] + #for param in paramroot: + # print("parsing "+param.tag) + # paramlist.append(param_type(param.tag,param.text)) - + + code.interact(local=dict(globals(), **locals())) return(base_cdl,new_cdl,pftparams,paramlist) @@ -47,14 +64,20 @@ def load_xml(xmlfile): # Little function for assembling the call to the system to make the modification # ---------------------------------------------------------------------------------------- -def parse_syscall_str(fnamein,fnameout,param_name,param_val): +def parse_syscall_str(fnamein,fnameout,pft_index,param_name,param_val): - sys_call_str = "../tools/modify_fates_paramfile.py"+" --fin " + fnamein + \ - " --fout " + fnameout + " --var " + param_name + " --silent " +\ - " --val " + "\" "+param_val+"\"" + " --overwrite --all" + if(pft_index==0): + sys_call_str = "../tools/modify_fates_paramfile.py"+" --fin " + fnamein + \ + " --fout " + fnameout + " --var " + param_name + " --silent " +\ + " --val " + "\" "+param_val+"\"" + " --nohist --overwrite --all" + else: + pft_str_index="{}".format(pft_index) + sys_call_str = "../tools/modify_fates_paramfile.py"+" --fin " + fnamein + \ + " --fout " + fnameout + " --var " + param_name + " --silent " +\ + " --val " + "\" "+param_val+"\"" + " --nohist --overwrite --pft "+pft_str_index - - print(sys_call_str) + if(debug): + print(sys_call_str) return(sys_call_str) @@ -70,8 +93,13 @@ def main(): # Load the xml file, which contains the base cdl, the output cdl, # and the parameters to be modified - [base_cdl,new_cdl,pftlist,paramlist] = load_xml(args.xmlfile) + #[base_cdl,new_cdl,pftlist,paramlist] = load_xml(args.xmlfile) + + xmlroot = et.parse(args.xmlfile).getroot() + print("\nOpened: "+args.xmlfile) + base_cdl = xmlroot.find('base_file').text + new_cdl = xmlroot.find('new_file').text # Convert the base cdl file into a temp nc binary base_nc = os.popen('mktemp').read().rstrip('\n') @@ -81,32 +109,87 @@ def main(): # Generate a temp output file name new_nc = os.popen('mktemp').read().rstrip('\n') - # Use FatesPFTIndexSwapper.py to prune out unwanted PFTs - swapcmd="../tools/FatesPFTIndexSwapper.py --pft-indices="+pftlist+" --fin="+base_nc+" --fout="+new_nc #+" 1>/dev/null" + pft_trim_list = xmlroot.find('pft_trim_list').text.replace(" ","") + swapcmd="../tools/FatesPFTIndexSwapper.py --pft-indices="+pft_trim_list+" --fin="+base_nc+" --fout="+new_nc+" --nohist" #+" 1>/dev/null" os.system(swapcmd) - # We open the new parameter file. We only use this - # to do some dimension checking. - fp_nc = netcdf.netcdf_file(base_nc, 'r') - # On subsequent parameters, overwrite the file - for param in paramlist: - change_str = parse_syscall_str(new_nc,new_nc,param.name,param.values) - os.system(change_str) + paramroot = xmlroot.find('parameters') + + grouplist = [] + for group in paramroot: + + if(group.tag.strip() == 'non_pft_group'): + + print("Processing non_pft_group") + + for param in group: + print("parsing "+param.tag) + + change_str = parse_syscall_str(new_nc,new_nc,0,param.tag,param.text.replace(" ","")) + os.system(change_str) + + elif(group.tag.strip() == 'pft_group'): + + if(not('ids' in group.attrib.keys())): + print("pft_mod_group must have an ids attribute with comma delimited pft indices") + print("exiting") + exit(2) + + pft_str = group.attrib['ids'].strip() + pft_strvec = pft_str.split(',') + pft_ids = [int(s) for s in pft_strvec] + + print("Processing PFT group: "+group.tag+" ids: "+pft_str) + + for param in group: + print("parsing "+param.tag) + + param_vec = [str_val for str_val in param.text.replace(" ", "").split(',')] + + # The number of parameters does not need to equal to the number of PFTs + # but it does need to be equally divisible by it + v_per_p = float(len(param_vec))/float(len(pft_ids)) + + if( int(100.0*v_per_p) != 100*int(v_per_p) ): + print("inconsistent number of parameter values and number of pfts specified") + print("exiting") + exit(2) + + for j,pft_id in enumerate(pft_ids): + j0 = j*int(v_per_p) + j1 = (j+1)*int(v_per_p) + #code.interact(local=dict(globals(), **locals())) + param_str = ",".join(param_vec[j0:j1]) + change_str = parse_syscall_str(new_nc,new_nc,pft_id,param.tag,param_str) + os.system(change_str) + + else: + print("Unidentified group, should be: non_pft_group or pft_group") + print("exiting") + exit(2) + + + # Append history + fp_nc = netcdf.netcdf_file(new_nc, 'a') + fp_nc.history = "This file was generated by BatchPatchParams.py:\n"\ + "CDL Base File = {}\n"\ + "XML patch file = {}"\ + .format(base_cdl,args.xmlfile) + fp_nc.close() # Sort the new file newer_nc = os.popen('mktemp').read().rstrip('\n') os.system("../tools/ncvarsort.py --fin "+new_nc+" --fout "+newer_nc+" --overwrite") + # Dump the new file to the cdl os.system("ncdump "+newer_nc+" > "+new_cdl) - fp_nc.close() - print("\nBatch parameter transfer complete\n") - + print("\nGenerated: {}\n".format(new_cdl)) # This is the actual call to main diff --git a/tools/FatesPFTIndexSwapper.py b/tools/FatesPFTIndexSwapper.py index 7e39056fa8..99e258bdc6 100755 --- a/tools/FatesPFTIndexSwapper.py +++ b/tools/FatesPFTIndexSwapper.py @@ -24,7 +24,7 @@ # ======================================================================================= pft_dim_name = 'fates_pft' -prt_dim_name = 'fates_prt_organs' +prt_dim_name = 'fates_plant_organs' hydro_dim_name = 'fates_hydr_organs' litt_dim_name = 'fates_litterclass' string_dim_name = 'fates_string_length' @@ -85,9 +85,10 @@ def interp_args(argv): input_fname = "none" output_fname = "none" donor_pft_indices = -9 - donot_pft_indices_str = '' + donor_pft_indices_str = '' + histflag = True try: - opts, args = getopt.getopt(argv, 'h',["fin=","fout=","pft-indices="]) + opts, args = getopt.getopt(argv, 'h',["fin=","fout=","pft-indices=","nohist"]) except getopt.GetoptError as err: print('Argument error, see usage') usage() @@ -103,6 +104,8 @@ def interp_args(argv): output_fname = a elif o in ("--pft-indices"): donor_pft_indices_str = a.strip() + elif o in ("--nohist"): + histflag = False else: assert False, "unhandled option" @@ -127,7 +130,7 @@ def interp_args(argv): donor_pft_indices.append(int(strpft)) - return (input_fname,output_fname,donor_pft_indices) + return (input_fname,output_fname,donor_pft_indices,histflag) # ======================================================================================== @@ -139,7 +142,7 @@ def interp_args(argv): def main(argv): # Interpret the arguments to the script - [input_fname,output_fname,donor_pft_indices] = interp_args(argv) + [input_fname,output_fname,donor_pft_indices,histflag] = interp_args(argv) num_pft_out = len(donor_pft_indices) @@ -252,8 +255,9 @@ def main(argv): out_var.units = in_var.units out_var.long_name = in_var.long_name - fp_out.history = "This file was made from FatesPFTIndexSwapper.py \n Input File = {} \n Indices = {}"\ - .format(input_fname,donor_pft_indices) + if(histflag): + fp_out.history = "This file was made from FatesPFTIndexSwapper.py \n Input File = {} \n Indices = {}"\ + .format(input_fname,donor_pft_indices) #var_out.mode = var.mode #fp.flush() diff --git a/tools/UpdateParamAPI.py b/tools/UpdateParamAPI.py new file mode 100755 index 0000000000..f23ef5d24c --- /dev/null +++ b/tools/UpdateParamAPI.py @@ -0,0 +1,497 @@ +#!/usr/bin/env python + +# ======================================================================================= +# This script modifies any FATES parameter file to update it to a new API spec. +# It can change variable names +# It can add new variables +# It can add attributes +# It can update attributes +# It can add new dimensions +# ======================================================================================= + +import os +import argparse +import code # For development: code.interact(local=dict(globals(), **locals())) +from scipy.io import netcdf +import xml.etree.ElementTree as et +import numpy as np + +# ======================================================================================= + +def load_xml(xmlfile): + + # This routine parses the XML tree + + xmlroot = et.parse(xmlfile).getroot() + print("\nOpened: {}\n".format(xmlfile)) + + base_cdl = xmlroot.find('base_file').text + new_cdl = xmlroot.find('new_file').text + + pft_list = xmlroot.find('pft_list').text.replace(" ","") + + modroot = xmlroot.find('mods') + + return(base_cdl,new_cdl,pft_list,modroot) + +# ======================================================================================= + +def str2fvec(numstr): + + # Convert a list of strings into floating point numbers + + numvec = [float(i) for i in numstr.split(',')] + return(numvec) + +# ======================================================================================= + +def str2ivec(numstr): + + # Convert a list of strings into integer numbers + + intvec = [int(i) for i in numstr.split(',')] + return(intvec) + +# ======================================================================================= + +def createvar(ncfile,paramname,dimnames,units,longname,dcode,sel_values): + + # Create a new netcdf variable inside an existing netcdf dataset (append) + ncvar = ncfile.createVariable(paramname,dcode,dimnames) + ncvar.units = units + ncvar.long_name = longname + if( not dimnames): + ncvar.assignValue(sel_values) + else: + ncvar[:] = sel_values + ncfile.flush() + + return(ncfile,ncvar) + +# ======================================================================================= + +def selectvalues(ncfile,dimnames,ipft_list,values,dtype): + + # Reduce a list of values so that onlythe chosen pft values are left. This + # only works on float arrays currently. We need to pass in a file + # so that we can get the dimension sizes associated with the dimension names. + + if(len(ipft_list) != ncfile.dimensions['fates_pft']): + print('you list of pfts in the xml file must be') + print('the same size as the fates_pft dimension') + print('in your destination file. exiting') + print('len(ipft_list) = {}'.format(len(ipft_list))) + print('fates_pft dim = {}'.format(ncfile.dimensions['fates_pft'])) + exit(2) + + # shift the pft list to a base of 0 instead of 1 + + pft_dim = -1 + dim_size = [0 for i in range(0,len(dimnames))] + + for idim, name in enumerate(dimnames): + dim_size[idim] = ncfile.dimensions[name] + if(name=='fates_pft'): + pft_dim = idim + pft_dim_size = ncfile.dimensions['fates_pft'] + + if(len(dimnames) == 1): + + if(pft_dim==0): + dim1_list = ipft_list + else: + dim1_list = range(0,dim_size[0]) + + sel_values = np.zeros([len(dim1_list)]) + for i,ipft in enumerate(dim1_list): + sel_values[i] = values[ipft] + + elif(len(dimnames) == 2 ): + + if(dtype=="c"): + + if(pft_dim>0): + print("problem with pft_dim: {},{}".format(dimnames[0],dimnames[1]));exit(2) + + if(pft_dim==0): + dim1_list = ipft_list + else: + dim1_list = range(0,dim_size[0]) + + sel_values = np.chararray([len(dim1_list),dim_size[1]]) + sel_values[:] = "" + for i,ipft in enumerate(dim1_list): + for j,cc in enumerate(values[ipft]): + sel_values[i][j] = cc + + + elif(dtype=="d"): + + if(pft_dim==0): + print("problem with pft_dim: {},{}".format(dimnames[0],dimnames[1]));exit(2) + + if(pft_dim==1): + dim1_list = ipft_list + else: + dim1_list = range(0,dim_size[1]) + + sel_values = np.zeros([dim_size[0],len(dim1_list)]) + for i,ipft in enumerate(dim1_list): + for i2 in range(0,dim_size[0]): + id = i2*len(dim1_list)+ipft + sel_values[i2,i] = values[id] + + else: + + # Scalar + #code.interact(local=dict(globals(), **locals())) + sel_values = float(values[0]) + + return(sel_values) + +# ======================================================================================= + +def removevar(base_nc,varname): + + # Remove a variable from a dataset. This is actually the hardest thing to do! + # The trick here, is to copy the whole file, minus the variable of interest + # into a temp file. Then completely remove the old file, and + + fp_base = netcdf.netcdf_file(base_nc, 'r',mmap=False) + + new_nc = os.popen('mktemp').read().rstrip('\n') + fp_new = netcdf.netcdf_file(new_nc, 'w',mmap=False) + + found = False + for key, value in sorted(fp_base.dimensions.items()): + if( key == varname ): + found = True + else: + fp_new.createDimension(key,int(value)) + + for key, value in fp_base.variables.items(): + + if(key == varname): + found = True + else: + datatype = value.typecode() + new_var = fp_new.createVariable(key,datatype,value.dimensions) + if(value.data.size == 1): + new_var.assignValue(float(value.data)) + else: + new_var[:] = value[:].copy() + + new_var.units = value.units + new_var.long_name = value.long_name + #try: + # new_var.use_case = value.use_case + #except: + # new_var.use_case = "undefined" + + fp_new.history = fp_base.history + + if(not found): + print("was not able to find variable: ()".format(varname)) + exit(2) + + fp_new.flush() + fp_base.close() + fp_new.close() + + mvcmd = "(rm -f "+base_nc+";mv "+new_nc+" "+base_nc+")" + os.system(mvcmd) + + +# ======================================================================================= + +def main(): + + # Parse arguments + parser = argparse.ArgumentParser(description='Parse command line arguments to this script.') + parser.add_argument('--f', dest='xmlfile', type=str, help="XML control file Required.", required=True) + args = parser.parse_args() + + + # Load the xml file, which contains the base cdl, the output cdl, + # and the parameters to be modified + [base_cdl,new_cdl,pft_list,modroot] = load_xml(args.xmlfile) + + ipft_list = str2ivec(pft_list) + + for i,ipft in enumerate(ipft_list): + ipft_list[i] = ipft_list[i]-1 + + # Convert the base cdl file into a temp nc binary + base_nc = os.popen('mktemp').read().rstrip('\n') + gencmd = "ncgen -o "+base_nc+" "+base_cdl + os.system(gencmd) + modlist = [] + for mod in modroot: + if(not('type' in mod.attrib.keys())): + print("mod tag must have attribute type") + print("exiting") + exit(2) + + if(mod.attrib['type'].strip() == 'dimension_add'): + + try: + dimname = mod.find('di').text.strip() + except: + print("{}, no dimension (di), exiting".format(mod.attrib['type']));exit(2) + + try: + values = str2ivec(mod.find('val').text.strip()) + except: + print("no values (val), exiting");exit(2) + + if(len(values)>1): + print("The dimension size should be a scalar") + exit(2) + + ncfile = netcdf.netcdf_file(base_nc,"a",mmap=False) + ncfile.createDimension(dimname, values[0]) + ncfile.flush() + ncfile.close() + + print("dimension: {}, size: {}, added".format(dimname,values[0])) + + elif(mod.attrib['type'].strip() == 'dimension_del'): + + try: + dimname = mod.find('di').text.strip() + except: + print('define the dimension name to delete using a tag') + exit(2) + + # Find which parameters use this dimension + ncfile = netcdf.netcdf_file(base_nc,"r",mmap=False) + found = False + for key, value in sorted(ncfile.dimensions.items()): + if(key==dimname): + found=True + + if(not found): + print("could not find {} for deletion".format(dimname));exit(2) + + for key, value in sorted(ncfile.variables.items()): + hasdim = any([dim == dimname for dim in list(value.dimensions) ]) + + if (hasdim): + print("parameter: {}, removed (to accomodate dimension removal)".format(key)) + removevar(base_nc,key) + + ncfile.close() + + removevar(base_nc,dimname) + print("dimension: {}, removed".format(dimname)) + + elif(mod.attrib['type'].strip() == 'variable_add'): + + try: + paramname = mod.find('na').text.strip() + except: + print("no name (na), exiting");exit(2) + + #try: + # dtype = mod.find('dt').text.strip() + #except: + # print("no data type (dt), exiting");exit(2) + + try: + dimnames = tuple(mod.find('di').text.replace(" ","").split(',')) + except: + print("no data type (di), exiting");exit(2) + + try: + units = mod.find('un').text.strip() + except: + print("no units (un), exiting");exit(2) + + try: + longname = mod.find('ln').text.strip() + except: + print("no long-name (ln), exiting");exit(2) + + ncfile = netcdf.netcdf_file(base_nc,"a",mmap=False) + + try: + values = str2fvec(mod.find('val').text.strip()) + except: + # try: + if(isinstance(mod.find('val').text,type(None))): + # values = mod.find('val').text.strip() + # except: + print("Warning: no values (val). Setting undefined (i.e. '_'): {}\n".format(paramname)) + sel_values = ncfile.variables['fates_dev_arbitrary_pft'].data + dcode = "d" + else: + print("unknown values (val), exiting");exit(2) + + #print("no values (val), exiting");exit(2) + else: + #code.interact(local=dict(globals(), **locals())) + + if(dimnames[0]=='scalar' or dimnames[0]=='none' or dimnames[0]==''): + dimnames = () + + if(isinstance(values[0],str)): + dcode = "c" + values = values.split(',') + for i,val in enumerate(values): + values[i] = val.strip() + elif(isinstance(values[0],float)): + dcode = "d" + else: + print("Unknown value type: {} {}".format(type(values[0]),paramname));exit(2) + + sel_values = selectvalues(ncfile,list(dimnames),ipft_list,values,dcode) + + [ncfile,ncvar] = createvar(ncfile,paramname,dimnames,units,longname,dcode,sel_values) + ncfile.flush() + ncfile.close() + + print("parameter: {}, added".format(paramname)) + + + elif(mod.attrib['type'] == 'variable_del'): + try: + paramname = mod.find('na').text.strip() + except: + print('must define the parameter name to delete, using name attribute') + exit(2) + removevar(base_nc,paramname) + print("parameter: {}, removed".format(paramname)) + + + elif(mod.attrib['type'] == 'variable_change'): + + try: + paramname_o = mod.attrib['name'].strip() + except: + print("to change a parameter, the field must have a name attribute") + exit(2) + + ncfile = netcdf.netcdf_file(base_nc,"a",mmap=False) + ncvar_o = ncfile.variables[paramname_o] + # dims_o = ncvar_o.dimensions + dtype_o = ncvar_o.typecode() + units_o = ncvar_o.units.decode("utf-8") + longname_o = ncvar_o.long_name.decode("utf-8") + + # Check for a parameter name change + try: + newparamname = mod.find('na').text.strip() + except: + newparamname = None + + # Check for a dimensionality change + try: + dimnames = tuple(mod.find('di').text.replace(" ","").split(',')) + except: + dimnames = None + + # Change the parameter's name and/or the dimensionality + if(not isinstance(newparamname,type(None)) or not isinstance(dimnames,type(None))): + + # Initialize the parameter name to pass to the create variable function + # If this is None, a dimension update is happening and this will be updated + # below + paramname = newparamname + + # If no dimension change, use the previous dimensions + if not dimnames: + dims_o = ncvar_o.dimensions + else: + # If dimension to change to is scalar, set dims_o to an empty list + if(dimnames[0]=='scalar' or dimnames[0]=='none' or dimnames[0]==''): + dims_o = () + else: + dims_o = dimnames + + # If there is no dimension change grab the original data + if (isinstance(dimnames,type(None))): + if not dims_o: + ncvardata = float(ncvar_o.data) + # [ncfile,ncvar] = createvar(ncfile,paramname,dims_o,units_o,longname_o,dtype_o,float(ncvar_o.data)) + else: + ncvardata = ncvar_o[:].copy() + # [ncfile,ncvar] = createvar(ncfile,paramname,dims_o,units_o,longname_o,dtype_o,ncvar_o[:].copy()) + # If there is a dimension change create zero filled data + else: + # If there isn't a parameter name change, grab the old name + if (isinstance(paramname,type(None))): + paramname = paramname_o + + # If changing to scalar + if not dims_o: + ncvardata = 0. + # read the dimensions and create a + else: + dimsize = [] + for idim,name in enumerate(dimnames): + dimsize.append(ncfile.dimensions[name]) + ncvardata = np.zeros(dimsize) + + # Create the new variable + [ncfile,ncvar] = createvar(ncfile,paramname,dims_o,units_o,longname_o,dtype_o,ncvardata) + + else: + ncvar = ncvar_o + + # Change the metadata: + try: + units = mod.find('un').text.strip() + except: + units = None + if(not isinstance(units,type(None))): + ncvar.units = units + + try: + longname = mod.find('ln').text.strip() + except: + longname = None + if(not isinstance(longname,type(None))): + ncvar.long_name = longname + + try: + values = str2fvec(mod.find('val').text.strip()) + except: + values = None + + if(not isinstance(values,type(None))): + sel_values = selectvalues(ncfile,list(dims_o),ipft_list,values,dtype_o) + + # Scalars have their own thing + if(ncvar.data.size == 1): + ncvar.assignValue(sel_values) + else: + ncvar[:] = sel_values[:] + + + ncfile.flush() + ncfile.close() + + # Finally, if we did perform a re-name, and + # created a new variable. We need to delete the old one + # This is not necessary for a dimension only change + if(not isinstance(newparamname,type(None))): + removevar(base_nc,paramname_o) + paramname = paramname_o + + print("parameter: {}, modified".format(paramname_o)) + + + # Sort the new file + new_nc = os.popen('mktemp').read().rstrip('\n') + os.system("../tools/ncvarsort.py --silent --fin "+base_nc+" --fout "+new_nc+" --overwrite") + + # Dump the new file to the cdl + os.system("ncdump "+new_nc+" > "+new_cdl) + + print("\nAPI update complete, see file: {}\n".format(new_cdl)) + + +# This is the actual call to main + +if __name__ == "__main__": + main() diff --git a/tools/luh2/README.md b/tools/luh2/README.md new file mode 100644 index 0000000000..60305c7ad1 --- /dev/null +++ b/tools/luh2/README.md @@ -0,0 +1,55 @@ +# FATES LUH2 data tool README + +## Purpose + +This tool takes the raw Land Use Harmonization (https://luh.umd.edu/), or LUH2, data files as +input and prepares them for use with FATES. The tool concatenates the various raw data sets into +a single file and provides the ability to regrid the source data resolution to a target +resolution that the user designates. The output data is then usable by FATES, mediated through +a host land model (currently either CTSM or E3SM). + +For more information on how FATES utilizes this information see https://github.com/NGEET/fates/pull/1040. + +## Installation + +This tool requires the usage of conda with python3. See https://docs.conda.io/en/latest/miniconda.html#installing +for information on installing conda on your system. To install the conda environment necessary to run the tool +execute the following commands: + +conda env create -f conda-luh2.yml + +This will create a conda environment named "luh2". To activate this environment run: + +conda activate luh2 + +For more information on creating conda environments see +https://conda.io/projects/conda/en/latest/user-guide/tasks/manage-environments.html#creating-an-environment-from-an-environment-yml-file + +Note that it is planned that a subset of host land model (hlm) and hlm supported machines will incoporate this tool into the surface dataset workflow. +As such, if you are working on one of these machines, the output from this tool may be precomputed and available for the grid resolution of interest. + +## Usage + +After activating the "luh2" environment the tool can be run from the command line with the following minimum required inputs: + +python luh2.py -l -s -r -w -o + +The description of the minimum required input arguments is as follows: +- raw-luh2-datafile: this is one of three raw luh2 datafiles, either states, transitions, or management. This is the data to be regridded and used by FATES. +- luh2-static-datafile: supplementary 0.25 deg resolution static data used in the construction of the raw luh2 datafiles. This is utilized to help set the gridcell mask for the output file. +- regrid-targetfile: host land model surface data file intended to be used in conjunction with the fates run at a specific grid resolution. This is used as the regridder target resolution. +- regridder-output: the path and filename to write out the regridding weights file or to use an existing regridding weights file. +- outputfile: the path and filename to which the output is written + +The tool is intended to be run three times, sequentially, to concatenate the raw states, transitions, and management data into a single file. After the first run of +the tool, a merge option should also be included in the argument list pointing to the most recent output file. This will ensure that the previous regridding run +will be merged into the current run as well as reusing the previously output regridding weights file (to help reduce duplicate computation). +The luh2.sh file in this directory provides an example shell script in using the python tool in this sequential manner. The python tool itself provides additional +help by passing the `--help` option argument to the command line call. + +## Description of directory contents + +- luh2.py: main luh2 python script +- luh2mod.py: python module source file for the functions called in luh2.py +- luh2.sh: example bash shell script file demonstrating how to call luh2.py +- conda-luh2.yml: conda enviroment yaml file which defines the minimum set of package dependencies for luh2.py diff --git a/tools/luh2/conda-luh2.yml b/tools/luh2/conda-luh2.yml new file mode 100644 index 0000000000..12d4a35c65 --- /dev/null +++ b/tools/luh2/conda-luh2.yml @@ -0,0 +1,11 @@ +# This yaml file is intended for users who wish to utilize the luh2.py tool on their own machines. +# The file is not yet tested regularly to determine if the latest versions of the dependencies will +# always work. This regular testing is expected to be implemented in the future. +name: luh2 +channels: + - conda-forge + - defaults +dependencies: + - xesmf + # xarray which is autodownloaded as xesmf dependency, uses scipy, which needs netcdf4 to open datasets + - netcdf4 diff --git a/tools/luh2/luh2.py b/tools/luh2/luh2.py new file mode 100644 index 0000000000..d0cd91afec --- /dev/null +++ b/tools/luh2/luh2.py @@ -0,0 +1,138 @@ +#!/usr/bin/env python3 + +# LUH2 python script +# Usage: python luh2.py -l -s \ +# -r -w -o + +import argparse, os, sys +from luh2mod import ImportData, SetMaskLUH2, SetMaskSurfData +from luh2mod import RegridConservative, RegridLoop, CorrectStateSum + +# Add version checking here in case environment.yml not used +def main(): + + # Add argument parser - subfunction? Seperate common module? + # input_files and range should be the only arguments + # Allow variable input files (state and/or transitions and/or management) + args = CommandLineArgs() + + # Import and prep the LUH2 datasets and regrid target + ds_luh2 = ImportData(args.luh2_file,args.begin,args.end) + ds_regrid_target = ImportData(args.regridder_target_file,args.begin,args.end) + + # Import the LUH2 static data to use for masking + ds_luh2_static = ImportData(args.luh2_static_file) + + # Create new variable where the ice water fraction is inverted w + ds_luh2_static["landfrac"] = 1 - ds_luh2_static.icwtr + + # Mask all LUH2 input data using the ice/water fraction for the LUH2 static data + ds_luh2 = SetMaskLUH2(ds_luh2, ds_luh2_static) + ds_luh2_static = SetMaskLUH2(ds_luh2_static, ds_luh2_static) + + # Mask the regrid target + ds_regrid_target = SetMaskSurfData(ds_regrid_target) + + # Determine if we are saving a new regridder or using an old one + # TO DO: add check to handle if the user enters the full path + # TO DO: check if its possible to enter nothing with the argument + regrid_reuse = False + # If we are merging files together, we assume that the weights file + # being supplied exists on file + if (not isinstance(args.luh2_merge_file,type(None))): + regrid_reuse = True + + # Regrid the luh2 data to the target grid + # TO DO: provide a check for the save argument based on the input arguments + regrid_luh2,regridder_luh2 = RegridConservative(ds_luh2, ds_regrid_target, + args.regridder_weights, regrid_reuse) + + # Regrid the inverted ice/water fraction data to the target grid + regrid_land_fraction = regridder_luh2(ds_luh2_static) + + # Adjust the luh2 data by the land fraction + # TO DO: determine if this is necessary for the transitions and management data + regrid_luh2 = regrid_luh2 / regrid_land_fraction.landfrac + + # Correct the state sum (checks if argument passed is state file in the function) + regrid_luh2 = CorrectStateSum(regrid_luh2) + + # Add additional required variables for the host land model + # Add 'YEAR' as a variable. + # This is an old requirement of the HLM and should simply be a copy of the `time` dimension + # If we are merging, we might not need to do this, so check to see if its there already + if (not "YEAR" in list(regrid_luh2.variables)): + regrid_luh2["YEAR"] = regrid_luh2.time + regrid_luh2["LONGXY"] = ds_regrid_target["LONGXY"] # TO DO: double check if this is strictly necessary + regrid_luh2["LATIXY"] = ds_regrid_target["LATIXY"] # TO DO: double check if this is strictly necessary + + # Rename the dimensions for the output. This needs to happen after the "LONGXY/LATIXY" assignment + if (not 'lsmlat' in list(regrid_luh2.dims)): + regrid_luh2 = regrid_luh2.rename_dims({'lat':'lsmlat','lon':'lsmlon'}) + + # Merge existing regrided luh2 file with merge input target + # TO DO: check that the grid resolution + # We could do this with an append during the write phase instead of the merge + if (not(isinstance(args.luh2_merge_file,type(None)))): + ds_luh2_merge = ImportData(args.luh2_merge_file,args.begin,args.end,merge_flag=True) + #ds_luh2_merge = ds_luh2_merge.merge(regrid_luh2) + regrid_luh2 = regrid_luh2.merge(ds_luh2_merge) + + # Write the files + # TO DO: add check to handle if the user enters the full path + output_file = os.path.join(os.getcwd(),args.output) + print("generating output: {}".format(output_file)) + regrid_luh2.to_netcdf(output_file) + +def CommandLineArgs(): + + parser = argparse.ArgumentParser(description="placeholder desc") + + # Required input luh2 datafile + # TO DO: using the checking function to report back if invalid file input + parser.add_argument("-l","--luh2_file", + required=True, + help = "luh2 raw states, transitions, or management data file") + + # Required static luh2 data to get the ice/water fraction for masking + parser.add_argument("-s", "--luh2_static_file", + required=True, + help = "luh2 static data file") + + # File to use as regridder target (e.g. a surface dataset) + parser.add_argument("-r","--regridder_target_file", + required=True, + help = "target file with desired resolution to regrid luh2 data to") + + # Filename to use or save for the regridder weights + parser.add_argument("-w", "--regridder_weights", + default = 'regridder.nc', + help = "filename of regridder weights to write to or reuse (if -m option used)") + + # Optional input to subset the time range of the data + # TODO: add support for parsing the input and checking against the allowable date range + parser.add_argument("-b","--begin", + type = int, + default = None, + help = "beginning of date range of interest") + parser.add_argument("-e","--end", + type = int, + default = None, + help = "ending of date range to slice") + + # Optional output argument + parser.add_argument("-o","--output", + default = 'LUH2_timeseries.nc', + help = "output filename") + + # Optional merge argument to enable merging of other files + parser.add_argument("-m", "--luh2_merge_file", + default = None, + help = "previous luh2 output filename to merge into current run output") + + args = parser.parse_args() + + return(args) + +if __name__ == "__main__": + main() diff --git a/tools/luh2/luh2.sh b/tools/luh2/luh2.sh new file mode 100755 index 0000000000..3aa246907d --- /dev/null +++ b/tools/luh2/luh2.sh @@ -0,0 +1,57 @@ +#!/bin/bash +# WARNING: This script generates intermediate copies of the LUH2 +# data which at its peak takes up approximately 42G of space. +# +# Note that this script must be run with the luh2 conda environment +# It requires a single argument that points to the full path location +# of the luh2 data and the dataset to regrid against + +# LUH2 data names +DATA_LOC=$1 +STATIC_LOC=$2 +TARGET_LOC=$3 +OUTPUT_LOC=$4 +STATES_FILE=states.nc +TRANSITIONS_FILE=transitions.nc +MANAGE_FILE=management.nc +STATIC_FILE=staticData_quarterdeg.nc +REGRID_TARGET_FILE=surfdata_4x5_16pfts_Irrig_CMIP6_simyr2000_c170824.nc + +START=1850 +END=2015 + +# Save files +REGRID_SAVE=regridder.nc +OUTPUT_FILE=LUH2_historical_0850_2015_4x5.nc + +# Combine strings +STATES=${DATA_LOC}/${STATES_FILE} +TRANSITIONS=${DATA_LOC}/${TRANSITIONS_FILE} +MANAGE=${DATA_LOC}/${MANAGE_FILE} +STATIC=${STATIC_LOC}/${STATIC_FILE} +REGRID_TARGET=${TARGET_LOC}/${REGRID_TARGET_FILE} +REGRIDDER=${OUTPUT_LOC}/${REGRID_SAVE} + +# Comment this out if the user already has the modified datasets available + +# Regrid the luh2 data against a target surface data set and then remove the states_modified file +echo "starting storage" +du -h ${OUTPUT_LOC} +python luh2.py -b ${START} -e ${END} -l ${STATES} -s ${STATIC} -r ${REGRID_TARGET} -w ${REGRIDDER} -o ${OUTPUT_LOC}/states_regrid.nc +echo -e"storage status:\n" +du -h ${OUTPUT_LOC} + +# Regrid the luh2 transitions data using the saved regridder weights file and merge into previous regrid output +python luh2.py -b ${START} -e ${END} -l ${TRANSITIONS} -s ${STATIC} -r ${REGRID_TARGET} -w ${REGRIDDER} \ + -m ${OUTPUT_LOC}/states_regrid.nc -o ${OUTPUT_LOC}/states_trans_regrid.nc +echo -e"storage status:\n" +du -h ${OUTPUT_LOC} +rm ${DATA_LOC}/states_regrid.nc + +# Regrid the luh2 management data using the saved regridder file and merge into previous regrid output +python luh2.py -b ${START} -e ${END} -l ${MANAGE} -s ${STATIC} -r ${REGRID_TARGET} -w ${REGRIDDER} \ + -m ${OUTPUT_LOC}/states_trans_regrid.nc -o ${OUTPUT_LOC}/${OUTPUT_FILE} +echo -e"storage status:\n" +du -h ${OUTPUT_LOC} +rm ${OUTPUT_LOC}/states_trans_regrid.nc +rm ${REGRIDDER} diff --git a/tools/luh2/luh2mod.py b/tools/luh2/luh2mod.py new file mode 100644 index 0000000000..c8534d42a9 --- /dev/null +++ b/tools/luh2/luh2mod.py @@ -0,0 +1,248 @@ +#!/usr/bin/env python3 + +import re, sys +import numpy as np +import xarray as xr +import xesmf as xe + +# Import luh2 or surface data sets +def ImportData(input_file,start=None,stop=None,merge_flag=False): + + # Open files + # Set decode_times to false as the luh2 raw data is outside the range + # of the standard NetCDF datetime format. + datasetout = xr.open_dataset(input_file, cache=False, decode_times=False) + print("Input file dataset opened: {}".format(input_file)) + + # Prep the input data for use + datasetout = PrepDataset(datasetout,start,stop,merge_flag) + + return(datasetout) + +# Prepare the input_file to be used for regridding +def PrepDataset(input_dataset,start=None,stop=None,merge_flag=False): + + # Check that the input dataset is a valid type + dsflag, dstype = CheckDataset(input_dataset) + + # Use the maximum span if start and stop are not present + # This assumes that the luh2 raw data will always use a + # 'years since' style format. + if(not(dstype in ('static','regrid'))): + + if (dstype == 'LUH2'): + # Get the units to determine the file time + # It is expected that the units of time is 'years since ...' + time_since_array = input_dataset.time.units.split() + if (time_since_array[0] != 'years'): + sys.exit("FileTimeUnitsError: input file units of time is not 'years since ...'") + + # Note that datetime package is not used as the date range might + # be beyond the bounds of the packages applicable bounds + time_since = int(time_since_array[2].split('-')[0]) + + # Get the time bounds of the input file + start_bound = input_dataset.time.values[0] + stop_bound = input_dataset.time.values[-1] + + # If no input provided, simply get the bounds of the time + if (isinstance(start,type(None))): + start = start_bound + time_since + + if (isinstance(stop,type(None))): + stop = stop_bound + time_since + + # Convert the input dates to years since 0850 + years_since_start = start - time_since + years_since_stop = stop - time_since + + # Abort if the times provided are outside the applicable range + if (years_since_start < start_bound or years_since_stop < start_bound or + years_since_start > stop_bound or years_since_stop > stop_bound): + sys.exit("StartStopBoundError: the input start or stop date is outside the applicable range of {} to {}".format(time_since+start_bound,time_since+stop_bound)) + + # Truncate the data to the user defined range + # This might need some more error handling for when + # the start/stop is out of range + input_dataset = input_dataset.sel(time=slice(years_since_start,years_since_stop)) + + # Correct the necessary variables for both datasets + # We don't need to Prep the incoming dataset if it's being opened to merge + if(not merge_flag): + input_dataset = PrepDataset_ESMF(input_dataset,dsflag,dstype) + + return(input_dataset) + +# Updating datasets to work with xESMF +def PrepDataset_ESMF(input_dataset,dsflag,dstype): + + if (dsflag): + if(dstype == "LUH2"): + print("PrepDataset: LUH2") + input_dataset = BoundsVariableFixLUH2(input_dataset) + elif(dstype == "surface"): + print("PrepDataset: SurfData") + input_dataset = DimensionFixSurfData(input_dataset) + print("data set updated for xESMF\n") + + return(input_dataset) + +# Create the necessary variable "lat_b" and "lon_b" for xESMF conservative regridding +# Each lat/lon boundary array is a 2D array corresponding to the bounds of each +# coordinate position (e.g. lat_boundary would be 90.0 and 89.75 for lat coordinate +# of 89.875). +def BoundsVariableFixLUH2(input_dataset): + + # Create lat and lon bounds as a single dimension array out of the LUH2 two dimensional_bounds array. + # Future todo: is it possible to have xESMF recognize and use the original 2D array? + input_dataset["lat_b"] = np.insert(input_dataset.lat_bounds[:,1].data,0,input_dataset.lat_bounds[0,0].data) + input_dataset["lon_b"] = np.insert(input_dataset.lon_bounds[:,1].data,0,input_dataset.lon_bounds[0,0].data) + + # Drop the old boundary names to avoid confusion + input_dataset = input_dataset.drop(labels=['lat_bounds','lon_bounds']) + + print("LUH2 dataset lat/lon boundary variables formatted and added as new variable for xESMF") + + return(input_dataset) + +# The user will need to use a surface data set to regrid from, but the surface datasets +# need to have their dimensions renamed to something recognizable by xESMF +def DimensionFixSurfData(input_dataset): + + # Rename the surface dataset dimensions to something recognizable by xESMF. + input_dataset = input_dataset.rename_dims(dims_dict={'lsmlat':'lat','lsmlon':'lon'}) + + # Populate the new surface dataset with the actual lat/lon values + input_dataset['lon'] = input_dataset.LONGXY.isel(lat=0) + input_dataset['lat'] = input_dataset.LATIXY.isel(lon=0) + + print("Surface dataset dimensions renamed for xESMF") + + return(input_dataset) + +# LUH2 specific masking sub-function +def SetMaskLUH2(input_dataset,static_data_set): + + # Mask the luh2 data where the ice/water fraction is unity (i.e. fully ice covered gridcell) + input_dataset["mask"] = (static_data_set.icwtr != 1) + return(input_dataset) + +# Surface dataset specific masking sub-function +def SetMaskSurfData(input_dataset): + # Instead of passing the label_to_mask, loop through this for all labels? + input_dataset["mask"] = input_dataset["PCT_NATVEG"] > 0 + return(input_dataset) + +# Check which dataset we're working with +def CheckDataset(input_dataset): + + dsflag = False + dsvars = list(input_dataset.variables) + if('primf' in dsvars or + 'primf_to_secdn' in dsvars or + any('irrig' in subname for subname in dsvars)): + dstype = 'LUH2' + dsflag = True + print("LUH2") + elif('natpft' in dsvars): + dstype = 'surface' + dsflag = True + print("Surface") + elif('icwtr' in dsvars): + dstype = 'static' + dsflag = True + elif('col' in dsvars): + dstype = 'regrid' + dsflag = True + else: + dstype = 'Unknown' + sys.exit("CheckDataSetError: Unrecognize data set") + + return(dsflag,dstype) + +def RegridConservative(ds_to_regrid, ds_regrid_target, regridder_weights, regrid_reuse): + + # define the regridder transformation + regridder = GenerateRegridder(ds_to_regrid, ds_regrid_target, regridder_weights, regrid_reuse) + + # Loop through the variables to regrid + ds_regrid = RegridLoop(ds_to_regrid, regridder) + + return (ds_regrid, regridder) + +def GenerateRegridder(ds_to_regrid, ds_regrid_target, regridder_weights_file, regrid_reuse): + + regrid_method = "conservative" + print("\nDefining regridder, method: ", regrid_method) + + if (regrid_reuse): + regridder = xe.Regridder(ds_to_regrid, ds_regrid_target, + regrid_method, weights=regridder_weights_file) + else: + regridder = xe.Regridder(ds_to_regrid, ds_regrid_target, regrid_method) + + # If we are not reusing the regridder weights file, then save the regridder + filename = regridder.to_netcdf(regridder_weights_file) + print("regridder saved to file: ", filename) + + return(regridder) + +def RegridLoop(ds_to_regrid, regridder): + + # To Do: implement this with dask + print("\nRegridding") + + # Loop through the variables one at a time to conserve memory + ds_varnames = list(ds_to_regrid.variables.keys()) + varlen = len(ds_to_regrid.variables) + first_var = False + for i in range(varlen-1): + + # Skip time variable + if (ds_varnames[i] != "time"): + + # Only regrid variables that match the lat/lon shape. + if (ds_to_regrid[ds_varnames[i]][0].shape == (ds_to_regrid.lat.shape[0], ds_to_regrid.lon.shape[0])): + print("regridding variable {}/{}: {}".format(i+1, varlen, ds_varnames[i])) + + # For the first non-coordinate variable, copy and regrid the dataset as a whole. + # This makes sure to correctly include the lat/lon in the regridding. + if (not(first_var)): + ds_regrid = ds_to_regrid[ds_varnames[i]].to_dataset() # convert data array to dataset + ds_regrid = regridder(ds_regrid) + first_var = True + + # Once the first variable has been included, then we can regrid by variable + else: + ds_regrid[ds_varnames[i]] = regridder(ds_to_regrid[ds_varnames[i]]) + else: + print("skipping variable {}/{}: {}".format(i+1, varlen, ds_varnames[i])) + else: + print("skipping variable {}/{}: {}".format(i+1, varlen, ds_varnames[i])) + + print("\n") + return(ds_regrid) + +# Temporary: Add minor correction factor to assure states sum to one +def CorrectStateSum(input_dataset): + + # Only calculate the state sum to unity correction for the appropiate dataset + # TO DO: Update this to use the check function + if (not(any('irrig' in var for var in input_dataset) or + any('_to_' in var for var in input_dataset))): + + # Drop the secma and secmb variables temporarily + temp_dataset = input_dataset.drop({'secma','secmb'}) + + # Sum the remaining state variables and normalize + state_sum = temp_dataset.to_array().sum(dim='variable') + state_sum = state_sum.where(state_sum != 0) + temp_dataset = temp_dataset / state_sum + + # Update dataset with new scaled values + input_dataset.update(temp_dataset) + + # Save the correction value + input_dataset["stscf"] = 1.0 / state_sum + + return(input_dataset) diff --git a/tools/modify_fates_paramfile.py b/tools/modify_fates_paramfile.py index 5ab1116500..adacb2457b 100755 --- a/tools/modify_fates_paramfile.py +++ b/tools/modify_fates_paramfile.py @@ -138,8 +138,10 @@ def main(): otherdimpresent = False elif var.dimensions[i] in ['fates_history_age_bins','fates_history_size_bins', \ 'fates_history_coage_bins','fates_history_height_bins', \ + 'fates_history_damage_bins', 'fates_NCWD','fates_litterclass','fates_leafage_class', \ - 'fates_prt_organs','fates_hydr_organs','fates_hlm_pftno']: + 'fates_plant_organs','fates_hydr_organs','fates_hlm_pftno', \ + 'fates_leafage_class']: otherdimpresent = True otherdimname = var.dimensions[i] otherdimlength = var.shape[i] diff --git a/tools/ncvarsort.py b/tools/ncvarsort.py index e9cdc422b4..327dd84a96 100755 --- a/tools/ncvarsort.py +++ b/tools/ncvarsort.py @@ -20,6 +20,7 @@ def main(): parser.add_argument('--fout','--output', dest='fnameout', type=str, help="Output filename. Required.", required=True) parser.add_argument('--O','--overwrite', dest='overwrite', help="If present, automatically overwrite the output file.", action="store_true") parser.add_argument('--debug', dest='debug', help="If present, output more diagnostics", action="store_true") + parser.add_argument('--silent', dest='silent', help="If present, prevents printing messages", action="store_true") # args = parser.parse_args() # @@ -38,16 +39,20 @@ def main(): (u'fates_history_coage_bins',):1, (u'fates_history_height_bins',):2, (u'fates_history_size_bins',):3, + (u'fates_history_damage_bins',):3, (u'fates_hydr_organs',):4, (u'fates_prt_organs',):4, + (u'fates_plant_organs',):4, (u'fates_pft', u'fates_string_length'):5, (u'fates_hydr_organs', u'fates_string_length'):6, (u'fates_prt_organs', u'fates_string_length'):7, + (u'fates_plant_organs', u'fates_string_length'):7, (u'fates_litterclass', u'fates_string_length'):7, (u'fates_pft',):8, (u'fates_hydr_organs', u'fates_pft'):8, (u'fates_leafage_class', u'fates_pft'):8, (u'fates_prt_organs', u'fates_pft'):8, + (u'fates_plant_organs', u'fates_pft'):8, (u'fates_hlm_pftno', u'fates_pft'):9, (u'fates_litterclass',):10, (u'fates_NCWD',):11, @@ -64,17 +69,28 @@ def main(): for i in range(len(varnames_list)): varnames_list[i] = sorted(varnames_list[i], key=lambda L: (L.lower(), L)) varnames_list_sorted.extend(varnames_list[i]) - # + + if args.silent: + verbose = False + else: + verbose = True + # write list of variables in ourput order if args.debug: - print(varnames_list_sorted) - # + if (not verbose): + print("cant run debug and silent in ncvarsort") + exit(2) + else: + print(varnames_list_sorted) + + + # open the output filename, deleting it if it exists already. if os.path.isfile(args.fnameout): if args.fnameout == args.fnamein: raise ValueError('Error: output file name is the same as the input file name.') elif args.overwrite: - print('replacing file: '+args.fnameout) + if (verbose): print('replacing file: '+args.fnameout) os.remove(args.fnameout) else: raise ValueError('Output file already exists and overwrite flag not specified for filename: '+args.fnameout) @@ -84,15 +100,15 @@ def main(): #Copy dimensions for dname, the_dim in dsin.dimensions.items(): if args.debug: - print(dname, the_dim.size) + if (verbose): print(dname, the_dim.size) dsout.createDimension(dname, the_dim.size ) # - print() + if (verbose): print() # try: dsout.history = dsin.history except: - print('no history!') + if (verbose): print('no history!') # # # go through each variable in the order of the sorted master list, and copy the variable @@ -102,7 +118,7 @@ def main(): varin = dsin.variables[v_name] outVar = dsout.createVariable(v_name, varin.datatype, varin.dimensions) if args.debug: - print(v_name) + if (verbose): print(v_name) # outVar.setncatts({k: varin.getncattr(k) for k in varin.ncattrs()}) outVar[:] = varin[:]