Skip to content

Commit 4ae2e78

Browse files
authored
Merge pull request #440 from xuchongang/xuchongang/fates_hydro_improve_ready_to_merge
Improve the plant hydro codes to accomodate dynamic forest
2 parents fb4086b + 911b539 commit 4ae2e78

15 files changed

+2986
-497
lines changed

biogeochem/EDCanopyStructureMod.F90

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ module EDCanopyStructureMod
2525
use FatesInterfaceMod , only : hlm_days_per_year
2626
use FatesInterfaceMod , only : hlm_use_planthydro
2727
use FatesInterfaceMod , only : numpft
28-
use FatesPlantHydraulicsMod, only : UpdateH2OVeg,InitHydrCohort
28+
use FatesPlantHydraulicsMod, only : UpdateH2OVeg,InitHydrCohort, RecruitWaterStorage
2929

3030
use PRTGenericMod, only : leaf_organ
3131
use PRTGenericMod, only : all_carbon_elements
@@ -503,6 +503,7 @@ subroutine DemoteFromLayer(currentSite,currentPatch,i_lyr)
503503
! demoted to the understory
504504

505505
allocate(copyc)
506+
506507
call InitPRTCohort(copyc)
507508
if( hlm_use_planthydro.eq.itrue ) then
508509
call InitHydrCohort(currentSite,copyc)
@@ -850,6 +851,7 @@ subroutine PromoteIntoLayer(currentSite,currentPatch,i_lyr)
850851
elseif ( cc_gain > nearzero .and. cc_gain < currentCohort%c_area) then
851852

852853
allocate(copyc)
854+
853855
call InitPRTCohort(copyc)
854856
if( hlm_use_planthydro.eq.itrue ) then
855857
call InitHydrCohort(CurrentSite,copyc)
@@ -1759,6 +1761,7 @@ subroutine update_hlm_dynamics(nsites,sites,fcolumn,bc_out)
17591761

17601762
! If hydraulics is turned on, update the amount of water bound in vegetation
17611763
if (hlm_use_planthydro.eq.itrue) then
1764+
call RecruitWaterStorage(nsites,sites,bc_out)
17621765
call UpdateH2OVeg(nsites,sites,bc_out)
17631766
end if
17641767

biogeochem/EDCohortDynamicsMod.F90

Lines changed: 56 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ module EDCohortDynamicsMod
88
use FatesGlobals , only : fates_log
99
use FatesInterfaceMod , only : hlm_freq_day
1010
use FatesInterfaceMod , only : bc_in_type
11+
use FatesInterfaceMod , only : hlm_use_planthydro
1112
use FatesConstantsMod , only : r8 => fates_r8
1213
use FatesConstantsMod , only : fates_unset_int
1314
use FatesConstantsMod , only : itrue,ifalse
@@ -31,6 +32,9 @@ module EDCohortDynamicsMod
3132
use FatesPlantHydraulicsMod, only : InitHydrCohort
3233
use FatesPlantHydraulicsMod, only : DeallocateHydrCohort
3334
use FatesPlantHydraulicsMod, only : AccumulateMortalityWaterStorage
35+
use FatesPlantHydraulicsMod, only : UpdateTreeHydrNodes
36+
use FatesPlantHydraulicsMod, only : UpdateTreeHydrLenVolCond
37+
use FatesPlantHydraulicsMod, only : SavePreviousCompartmentVolumes
3438
use FatesSizeAgeTypeIndicesMod, only : sizetype_class_index
3539
use FatesAllometryMod , only : bleaf
3640
use FatesAllometryMod , only : bfineroot
@@ -98,6 +102,13 @@ subroutine create_cohort(currentSite, patchptr, pft, nn, hite, dbh, bleaf, bfine
98102
!
99103
! !DESCRIPTION:
100104
! create new cohort
105+
! There are 4 places this is called
106+
! 1) Initializing new cohorts at the beginning of a cold-start simulation
107+
! 2) Initializing new recruits during dynamics
108+
! 3) Initializing new cohorts at the beginning of a inventory read
109+
! 4) Initializing new cohorts during restart
110+
!
111+
! It is assumed that in the first 3, this is called with a reasonable amount of starter information.
101112
!
102113
! !USES:
103114
!
@@ -125,7 +136,8 @@ subroutine create_cohort(currentSite, patchptr, pft, nn, hite, dbh, bleaf, bfine
125136
! !LOCAL VARIABLES:
126137
type(ed_cohort_type), pointer :: new_cohort ! Pointer to New Cohort structure.
127138
type(ed_cohort_type), pointer :: storesmallcohort
128-
type(ed_cohort_type), pointer :: storebigcohort
139+
type(ed_cohort_type), pointer :: storebigcohort
140+
integer :: nlevsoi_hyd ! number of hydraulically active soil layers
129141
integer :: tnull,snull ! are the tallest and shortest cohorts allocate
130142
!----------------------------------------------------------------------
131143

@@ -242,12 +254,31 @@ subroutine create_cohort(currentSite, patchptr, pft, nn, hite, dbh, bleaf, bfine
242254
new_cohort%isnew = .true.
243255

244256
if( hlm_use_planthydro.eq.itrue ) then
245-
call InitHydrCohort(CurrentSite,new_cohort)
246-
call updateSizeDepTreeHydProps(CurrentSite,new_cohort, bc_in)
247-
call initTreeHydStates(CurrentSite,new_cohort, bc_in)
257+
258+
nlevsoi_hyd = currentSite%si_hydr%nlevsoi_hyd
259+
260+
! This allocates array spaces
261+
call InitHydrCohort(currentSite,new_cohort)
262+
263+
! This calculates node heights
264+
call UpdateTreeHydrNodes(new_cohort%co_hydr,new_cohort%pft, &
265+
new_cohort%hite,nlevsoi_hyd,bc_in)
266+
267+
! This calculates volumes, lengths and max conductances
268+
call UpdateTreeHydrLenVolCond(new_cohort,nlevsoi_hyd,bc_in)
269+
270+
! Since this is a newly initialized plant, we set the previous compartment-size
271+
! equal to the ones we just calculated.
272+
call SavePreviousCompartmentVolumes(new_cohort%co_hydr)
273+
274+
! This comes up with starter suctions and then water contents
275+
! based on the soil values
276+
call initTreeHydStates(currentSite,new_cohort, bc_in)
277+
248278
if(recruitstatus==1)then
249-
new_cohort%co_hydr%is_newly_recuited = .true.
279+
new_cohort%co_hydr%is_newly_recruited = .true.
250280
endif
281+
251282
endif
252283

253284
call insert_cohort(new_cohort, patchptr%tallest, patchptr%shortest, tnull, snull, &
@@ -607,6 +638,9 @@ subroutine terminate_cohorts( currentSite, currentPatch, level )
607638
! preserve a record of the to-be-terminated cohort for mortality accounting
608639
levcan = currentCohort%canopy_layer
609640

641+
if( hlm_use_planthydro == itrue ) &
642+
call AccumulateMortalityWaterStorage(currentSite,currentCohort,currentCohort%n)
643+
610644
if(levcan==ican_upper) then
611645
currentSite%term_nindivs_canopy(currentCohort%size_class,currentCohort%pft) = &
612646
currentSite%term_nindivs_canopy(currentCohort%size_class,currentCohort%pft) + currentCohort%n
@@ -734,6 +768,7 @@ subroutine fuse_cohorts(currentSite, currentPatch, bc_in)
734768
real(r8) :: newn
735769
real(r8) :: diff
736770
real(r8) :: dynamic_fusion_tolerance
771+
real(r8) :: leaf_c ! leaf carbon [kg]
737772

738773
integer :: largersc, smallersc, sc_i ! indices for tracking the growth flux caused by fusion
739774
real(r8) :: larger_n, smaller_n
@@ -850,8 +885,11 @@ subroutine fuse_cohorts(currentSite, currentPatch, bc_in)
850885

851886
call sizetype_class_index(currentCohort%dbh,currentCohort%pft, &
852887
currentCohort%size_class,currentCohort%size_by_pft_class)
888+
853889

854-
if(hlm_use_planthydro.eq.itrue) call FuseCohortHydraulics(currentSite,currentCohort,nextc,bc_in,newn)
890+
if(hlm_use_planthydro.eq.itrue) then
891+
call FuseCohortHydraulics(currentSite,currentCohort,nextc,bc_in,newn)
892+
endif
855893

856894
! recent canopy history
857895
currentCohort%canopy_layer_yesterday = (currentCohort%n*currentCohort%canopy_layer_yesterday + &
@@ -980,7 +1018,18 @@ subroutine fuse_cohorts(currentSite, currentPatch, bc_in)
9801018
endif
9811019

9821020
! At this point, nothing should be pointing to current Cohort
983-
if (hlm_use_planthydro.eq.itrue) call DeallocateHydrCohort(nextc)
1021+
! update hydraulics quantities that are functions of hite & biomasses
1022+
! deallocate the hydro structure of nextc
1023+
if (hlm_use_planthydro.eq.itrue) then
1024+
call carea_allom(currentCohort%dbh,currentCohort%n,currentSite%spread, &
1025+
currentCohort%pft,currentCohort%c_area)
1026+
leaf_c = currentCohort%prt%GetState(leaf_organ, all_carbon_elements)
1027+
currentCohort%treelai = tree_lai(leaf_c, &
1028+
currentCohort%pft, currentCohort%c_area, currentCohort%n, &
1029+
currentCohort%canopy_layer, currentPatch%canopy_layer_tlai )
1030+
call updateSizeDepTreeHydProps(currentSite,currentCohort, bc_in)
1031+
call DeallocateHydrCohort(nextc)
1032+
endif
9841033

9851034
! Deallocate the cohort's PRT structure
9861035
call nextc%prt%DeallocatePRTVartypes()

biogeochem/EDMortalityFunctionsMod.F90

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ module EDMortalityFunctionsMod
1616
use FatesInterfaceMod , only : bc_in_type
1717
use FatesInterfaceMod , only : hlm_use_ed_prescribed_phys
1818
use FatesInterfaceMod , only : hlm_freq_day
19+
use FatesInterfaceMod , only : hlm_use_planthydro
1920
use EDLoggingMortalityMod , only : LoggingMortality_frac
2021
use EDParamsMod , only : fates_mortality_disturbance_fraction
2122
use FatesInterfaceMod , only : bc_in_type
@@ -62,8 +63,14 @@ subroutine mortality_rates( cohort_in,bc_in,cmort,hmort,bmort,frmort )
6263
real(r8) :: leaf_c_target ! target leaf biomass kgC
6364
real(r8) :: store_c
6465
real(r8) :: hf_sm_threshold ! hydraulic failure soil moisture threshold
66+
real(r8) :: hf_flc_threshold ! hydraulic failure fractional loss of conductivity threshold
6567
real(r8) :: temp_dep_fraction ! Temp. function (freezing mortality)
6668
real(r8) :: temp_in_C ! Daily averaged temperature in Celcius
69+
real(r8) :: min_fmc_ag ! minimum fraction of maximum conductivity for aboveground
70+
real(r8) :: min_fmc_tr ! minimum fraction of maximum conductivity for transporting root
71+
real(r8) :: min_fmc_ar ! minimum fraction of maximum conductivity for absorbing root
72+
real(r8) :: min_fmc ! minimum fraction of maximum conductivity for whole plant
73+
real(r8) :: flc ! fractional loss of conductivity
6774
real(r8), parameter :: frost_mort_buffer = 5.0_r8 ! 5deg buffer for freezing mortality
6875
logical, parameter :: test_zero_mortality = .false. ! Developer test which
6976
! may help to debug carbon imbalances
@@ -77,12 +84,28 @@ subroutine mortality_rates( cohort_in,bc_in,cmort,hmort,bmort,frmort )
7784

7885
! Proxy for hydraulic failure induced mortality.
7986
hf_sm_threshold = EDPftvarcon_inst%hf_sm_threshold(cohort_in%pft)
80-
81-
if(cohort_in%patchptr%btran_ft(cohort_in%pft) <= hf_sm_threshold)then
87+
hf_flc_threshold = EDPftvarcon_inst%hf_flc_threshold(cohort_in%pft)
88+
if(hlm_use_planthydro.eq.itrue)then
89+
!note the flc is set as the fraction of max conductivity in hydro
90+
min_fmc_ag = minval(cohort_in%co_hydr%flc_ag(:))
91+
min_fmc_tr = minval(cohort_in%co_hydr%flc_troot(:))
92+
min_fmc_ar = minval(cohort_in%co_hydr%flc_aroot(:))
93+
min_fmc = min(min_fmc_ag, min_fmc_tr)
94+
min_fmc = min(min_fmc, min_fmc_ar)
95+
flc = 1.0_r8-min_fmc
96+
if(flc >= hf_flc_threshold .and. hf_flc_threshold < 1.0_r8 )then
97+
hmort = (flc-hf_flc_threshold)/(1.0_r8-hf_flc_threshold) * &
98+
EDPftvarcon_inst%mort_scalar_hydrfailure(cohort_in%pft)
99+
else
100+
hmort = 0.0_r8
101+
endif
102+
else
103+
if(cohort_in%patchptr%btran_ft(cohort_in%pft) <= hf_sm_threshold)then
82104
hmort = EDPftvarcon_inst%mort_scalar_hydrfailure(cohort_in%pft)
83105
else
84106
hmort = 0.0_r8
85-
endif
107+
endif
108+
endif
86109

87110
! Carbon Starvation induced mortality.
88111
if ( cohort_in%dbh > 0._r8 ) then

biogeochem/EDPhysiologyMod.F90

Lines changed: 66 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,13 @@ module EDPhysiologyMod
1313
use FatesInterfaceMod, only : hlm_day_of_year
1414
use FatesInterfaceMod, only : numpft
1515
use FatesInterfaceMod, only : hlm_use_planthydro
16+
use FatesInterfaceMod, only : hlm_parteh_mode
1617
use FatesConstantsMod, only : r8 => fates_r8
1718
use FatesConstantsMod, only : nearzero
1819
use EDPftvarcon , only : EDPftvarcon_inst
1920
use FatesInterfaceMod, only : bc_in_type
2021
use EDCohortDynamicsMod , only : zero_cohort
21-
use EDCohortDynamicsMod , only : create_cohort, sort_cohorts
22+
use EDCohortDynamicsMod , only : create_cohort, sort_cohorts,InitPRTCohort
2223
use FatesAllometryMod , only : tree_lai
2324
use FatesAllometryMod , only : tree_sai
2425
use FatesAllometryMod , only : decay_coeff_kn
@@ -39,6 +40,12 @@ module EDPhysiologyMod
3940
use EDParamsMod , only : fates_mortality_disturbance_fraction
4041

4142
use FatesPlantHydraulicsMod , only : AccumulateMortalityWaterStorage
43+
use FatesPlantHydraulicsMod , only : updateSizeDepTreeHydProps
44+
use FatesPlantHydraulicsMod , only : initTreeHydStates
45+
use FatesPlantHydraulicsMod , only : InitHydrCohort
46+
use FatesPlantHydraulicsMod , only : ConstrainRecruitNumber
47+
use FatesPlantHydraulicsMod , only : DeallocateHydrCohort
48+
4249
use FatesConstantsMod , only : itrue,ifalse
4350
use FatesConstantsMod , only : calloc_abs_error
4451

@@ -54,7 +61,8 @@ module EDPhysiologyMod
5461
use FatesAllometryMod , only : carea_allom
5562
use FatesAllometryMod , only : CheckIntegratedAllometries
5663
use FatesAllometryMod , only : StructureResetOfDH
57-
64+
65+
use PRTGenericMod, only : prt_carbon_allom_hyp
5866
use PRTGenericMod, only : leaf_organ
5967
use PRTGenericMod, only : all_carbon_elements
6068
use PRTGenericMod, only : carbon12_element
@@ -971,6 +979,10 @@ subroutine recruitment( currentSite, currentPatch, bc_in )
971979

972980
allocate(temp_cohort) ! create temporary cohort
973981
call zero_cohort(temp_cohort)
982+
if( hlm_use_planthydro.eq.itrue ) then
983+
call InitHydrCohort(CurrentSite,temp_cohort)
984+
endif
985+
call InitPRTCohort(temp_cohort)
974986

975987
do ft = 1,numpft
976988

@@ -1014,28 +1026,64 @@ subroutine recruitment( currentSite, currentPatch, bc_in )
10141026
else
10151027
! prescribed recruitment rates. number per sq. meter per year
10161028
temp_cohort%n = currentPatch%area * EDPftvarcon_inst%prescribed_recruitment(ft) * hlm_freq_day
1017-
! modify the carbon balance accumulators to take into account the different way of defining recruitment
1018-
! add prescribed rates as an input C flux, and the recruitment that would have otherwise occured as an output flux
1019-
! (since the carbon associated with them effectively vanishes)
1020-
currentSite%flux_in = currentSite%flux_in + temp_cohort%n * &
1021-
(b_store + b_leaf + b_fineroot + b_sapwood + b_dead)
1022-
currentSite%flux_out = currentSite%flux_out + currentPatch%area * currentPatch%seed_germination(ft)*hlm_freq_day
10231029
endif
10241030

10251031
if (temp_cohort%n > 0.0_r8 )then
1026-
if ( debug ) write(fates_log(),*) 'EDPhysiologyMod.F90 call create_cohort '
1027-
call create_cohort(currentSite,currentPatch, temp_cohort%pft, temp_cohort%n, temp_cohort%hite, temp_cohort%dbh, &
1032+
if ( DEBUG ) write(fates_log(),*) 'EDPhysiologyMod.F90 call create_cohort '
1033+
!constrain the number of individual based on rhyzosphere water availability
1034+
if( hlm_use_planthydro.eq.itrue ) then
1035+
call carea_allom(temp_cohort%dbh,temp_cohort%n,currentSite%spread, &
1036+
ft,temp_cohort%c_area)
1037+
if(associated(currentPatch%shortest)) then
1038+
temp_cohort%canopy_layer = currentPatch%shortest%canopy_layer
1039+
else
1040+
temp_cohort%canopy_layer = 1
1041+
endif
1042+
temp_cohort%pft = ft
1043+
select case(hlm_parteh_mode)
1044+
case (prt_carbon_allom_hyp)
1045+
1046+
call SetState(temp_cohort%prt,leaf_organ, carbon12_element, b_leaf)
1047+
call SetState(temp_cohort%prt,fnrt_organ, carbon12_element, b_fineroot)
1048+
call SetState(temp_cohort%prt,sapw_organ, carbon12_element, b_sapwood)
1049+
call SetState(temp_cohort%prt,store_organ, carbon12_element, b_store)
1050+
call SetState(temp_cohort%prt,struct_organ, carbon12_element, b_dead)
1051+
call SetState(temp_cohort%prt,repro_organ , carbon12_element, 0.0_r8)
1052+
1053+
end select
1054+
temp_cohort%treelai = tree_lai(b_leaf, ft,&
1055+
temp_cohort%c_area,temp_cohort%n, &
1056+
temp_cohort%canopy_layer,currentPatch%canopy_layer_tlai)
1057+
call updateSizeDepTreeHydProps(CurrentSite,temp_cohort, bc_in)
1058+
call initTreeHydStates(CurrentSite,temp_cohort, bc_in)
1059+
call ConstrainRecruitNumber(currentSite,temp_cohort, bc_in)
1060+
endif
1061+
if(temp_cohort%n > 0.0_r8) then
1062+
call create_cohort(currentSite,currentPatch, temp_cohort%pft, temp_cohort%n, temp_cohort%hite, temp_cohort%dbh, &
10281063
b_leaf, b_fineroot, b_sapwood, b_dead, b_store, &
10291064
temp_cohort%laimemory, cohortstatus,recruitstatus, temp_cohort%canopy_trim, currentPatch%NCL_p, &
10301065
currentSite%spread, bc_in)
1031-
1032-
1033-
! keep track of how many individuals were recruited for passing to history
1034-
currentSite%recruitment_rate(ft) = currentSite%recruitment_rate(ft) + temp_cohort%n
1066+
! keep track of how many individuals were recruited for passing to history
1067+
currentSite%recruitment_rate(ft) = currentSite%recruitment_rate(ft) + temp_cohort%n
1068+
! modify the carbon balance accumulators to take into account the different way of defining recruitment
1069+
! add prescribed rates as an input C flux, and the recruitment that would have otherwise occured as an output flux
1070+
! (since the carbon associated with them effectively vanishes)
1071+
! check the water for hydraulics
1072+
if (hlm_use_ed_prescribed_phys .ne. ifalse .and. EDPftvarcon_inst%prescribed_recruitment(ft) .ge. 0. ) then
1073+
currentSite%flux_in = currentSite%flux_in + temp_cohort%n * &
1074+
(b_store + b_leaf + b_fineroot + b_sapwood + b_dead)
1075+
currentSite%flux_out = currentSite%flux_out + currentPatch%area * currentPatch%seed_germination(ft)*hlm_freq_day
1076+
endif
1077+
1078+
endif
10351079

10361080
endif
10371081
enddo !pft loop
1038-
1082+
!deallocate the temporatory cohort
1083+
if (hlm_use_planthydro.eq.itrue) call DeallocateHydrCohort(temp_cohort)
1084+
!Deallocate the cohort's PRT structure
1085+
call temp_cohort%prt%DeallocatePRTVartypes()
1086+
deallocate(temp_cohort%prt)
10391087
deallocate(temp_cohort) ! delete temporary cohort
10401088

10411089
end subroutine recruitment
@@ -1173,7 +1221,9 @@ subroutine CWD_Input( currentSite, currentPatch)
11731221
hlm_freq_day * currentPatch%area
11741222

11751223
if( hlm_use_planthydro == itrue ) then
1176-
call AccumulateMortalityWaterStorage(currentSite,currentCohort,dead_n)
1224+
!call AccumulateMortalityWaterStorage(currentSite,currentCohort,dead_n)
1225+
call AccumulateMortalityWaterStorage(currentSite,currentCohort,&
1226+
-1.0_r8 * currentCohort%dndt * hlm_freq_day)
11771227
end if
11781228

11791229

biogeochem/FatesAllometryMod.F90

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ module FatesAllometryMod
117117
public :: decay_coeff_kn
118118
public :: StructureResetOfDH ! Method to set DBH to sync with structure biomass
119119
public :: CheckIntegratedAllometries
120+
public :: CrownDepth
120121
public :: set_root_fraction ! Generic wrapper to calculate normalized
121122
! root profiles
122123

@@ -1843,6 +1844,33 @@ subroutine h2d_martcano(h,p1,p2,p3,d,dddh)
18431844
return
18441845
end subroutine h2d_martcano
18451846

1847+
! =====================================================================================
1848+
1849+
1850+
subroutine CrownDepth(height,crown_depth)
1851+
1852+
! -----------------------------------------------------------------------------------
1853+
! This routine returns the depth of a plant's crown. Which is the length
1854+
! from the bottom of the crown to the top in the vertical dimension.
1855+
!
1856+
! This code may be used as a wrapper if different hypotheses are wished to be
1857+
! optioned.
1858+
! -----------------------------------------------------------------------------------
1859+
1860+
real(r8),intent(in) :: height ! The height of the plant [m]
1861+
real(r8),intent(out) :: crown_depth ! The depth of the crown [m]
1862+
1863+
! Alternative Hypothesis:
1864+
! crown depth from Poorter, Bongers & Bongers
1865+
! crown_depth = exp(-1.169_r8)*cCohort%hite**1.098_r8
1866+
1867+
crown_depth = min(height,0.1_r8)
1868+
1869+
return
1870+
end subroutine CrownDepth
1871+
1872+
1873+
18461874
! =============================================================================
18471875
! Specific diameter to crown area allometries
18481876
! =============================================================================

0 commit comments

Comments
 (0)