From ee4509b9b4d8541d1b05fd0f5d33d91bf60d31a8 Mon Sep 17 00:00:00 2001 From: Xiulin Gao Date: Sun, 19 Oct 2025 14:25:12 -0700 Subject: [PATCH 01/23] correct Rothermel ROS fire model --- fire/FatesFuelClassesMod.F90 | 118 ++-- fire/FatesFuelMod.F90 | 833 ++++++++++++++-------- fire/SFEquationsMod.F90 | 867 ++++++++++++----------- fire/SFMainMod.F90 | 1282 +++++++++++++++++----------------- 4 files changed, 1712 insertions(+), 1388 deletions(-) diff --git a/fire/FatesFuelClassesMod.F90 b/fire/FatesFuelClassesMod.F90 index 257c822a9f..e676fe9b45 100644 --- a/fire/FatesFuelClassesMod.F90 +++ b/fire/FatesFuelClassesMod.F90 @@ -1,63 +1,63 @@ module FatesFuelClassesMod - use FatesLitterMod, only : ncwd - - implicit none - private - - integer, parameter, public :: num_fuel_classes = 6 ! number of total fuel classes - - type :: fuel_classes_type - ! There are six fuel classes: - ! 1) twigs, 2) small branches, 3) large branches 4) trunks - ! 5) dead leaves, 6) live grass - integer, private :: twigs_i = 1 ! array index for twigs pool - integer, private :: small_branches_i = 2 ! array index for small branches pool - integer, private :: large_branches_i = 3 ! array index for large branches pool - integer, private :: dead_leaves_i = 5 ! array index for dead leaves pool - integer, private :: live_grass_i = 6 ! array index for live grass pool - integer, private :: trunks_i = 4 ! array index for trunks pool - - contains - - procedure :: twigs, small_branches, large_branches, trunks - procedure :: dead_leaves, live_grass - - end type fuel_classes_type - - ! actual type we can pass around - type(fuel_classes_type), public :: fuel_classes - - contains - - integer function twigs(this) - class(fuel_classes_type), intent(in) :: this - twigs = this%twigs_i - end function twigs - - integer function small_branches(this) - class(fuel_classes_type), intent(in) :: this - small_branches = this%small_branches_i - end function small_branches - - integer function large_branches(this) - class(fuel_classes_type), intent(in) :: this - large_branches = this%large_branches_i - end function large_branches - - integer function trunks(this) - class(fuel_classes_type), intent(in) :: this - trunks = this%trunks_i - end function trunks - - integer function dead_leaves(this) - class(fuel_classes_type), intent(in) :: this - dead_leaves = this%dead_leaves_i - end function dead_leaves - - integer function live_grass(this) - class(fuel_classes_type), intent(in) :: this - live_grass = this%live_grass_i - end function live_grass + use FatesLitterMod, only : ncwd + + implicit none + private + + integer, parameter, public :: num_fuel_classes = 6 ! number of total fuel classes + + type :: fuel_classes_type + ! There are six fuel classes: + ! 1) twigs, 2) small branches, 3) large branches 4) trunks + ! 5) dead leaves, 6) live grass + integer, private :: twigs_i = 1 ! array index for twigs pool + integer, private :: small_branches_i = 2 ! array index for small branches pool + integer, private :: large_branches_i = 3 ! array index for large branches pool + integer, private :: dead_leaves_i = 5 ! array index for dead leaves pool + integer, private :: live_grass_i = 6 ! array index for live grass pool + integer, private :: trunks_i = 4 ! array index for trunks pool + + contains + + procedure :: twigs, small_branches, large_branches, trunks + procedure :: dead_leaves, live_grass + + end type fuel_classes_type + + ! actual type we can pass around + type(fuel_classes_type), public :: fuel_classes + +contains + + integer function twigs(this) + class(fuel_classes_type), intent(in) :: this + twigs = this%twigs_i + end function twigs + + integer function small_branches(this) + class(fuel_classes_type), intent(in) :: this + small_branches = this%small_branches_i + end function small_branches + + integer function large_branches(this) + class(fuel_classes_type), intent(in) :: this + large_branches = this%large_branches_i + end function large_branches + + integer function trunks(this) + class(fuel_classes_type), intent(in) :: this + trunks = this%trunks_i + end function trunks + + integer function dead_leaves(this) + class(fuel_classes_type), intent(in) :: this + dead_leaves = this%dead_leaves_i + end function dead_leaves + + integer function live_grass(this) + class(fuel_classes_type), intent(in) :: this + live_grass = this%live_grass_i + end function live_grass end module FatesFuelClassesMod diff --git a/fire/FatesFuelMod.F90 b/fire/FatesFuelMod.F90 index b05702fc1a..5cc713c80d 100644 --- a/fire/FatesFuelMod.F90 +++ b/fire/FatesFuelMod.F90 @@ -1,69 +1,91 @@ module FatesFuelMod - use FatesFuelClassesMod, only : num_fuel_classes, fuel_classes - use FatesConstantsMod, only : r8 => fates_r8 - use FatesConstantsMod, only : nearzero - use SFNesterovMod, only : nesterov_index - use SFFireWeatherMod, only : fire_weather - use FatesGlobals, only : fates_log - use FatesGlobals, only : endrun => fates_endrun - use shr_log_mod, only : errMsg => shr_log_errMsg - - implicit none - private - - type, public :: fuel_type - - real(r8) :: loading(num_fuel_classes) ! fuel loading of each fuel class [kgC/m2] - real(r8) :: effective_moisture(num_fuel_classes) ! fuel effective moisture all fuel class (moisture/MEF) [m3/m3] - real(r8) :: frac_loading(num_fuel_classes) ! fractional loading of all fuel classes [0-1] - real(r8) :: frac_burnt(num_fuel_classes) ! fraction of litter burnt by fire [0-1] - real(r8) :: non_trunk_loading ! total fuel loading excluding trunks [kgC/m2] - real(r8) :: average_moisture_notrunks ! weighted average of fuel moisture across non-trunk fuel classes [m3/m3] - real(r8) :: bulk_density_notrunks ! weighted average of bulk density across non-trunk fuel classes [kg/m3] - real(r8) :: SAV_notrunks ! weighted average of surface area to volume ratio across non-trunk fuel classes [/cm] - real(r8) :: MEF_notrunks ! weighted average of moisture of extinction across non-trunk fuel classes [m3/m3] - - contains - + use FatesFuelClassesMod, only : num_fuel_classes, fuel_classes + use FatesConstantsMod, only : r8 => fates_r8 + use FatesConstantsMod, only : nearzero + use SFNesterovMod, only : nesterov_index + use SFFireWeatherMod, only : fire_weather + use FatesGlobals, only : fates_log + use FatesGlobals, only : endrun => fates_endrun + use shr_log_mod, only : errMsg => shr_log_errMsg + + implicit none + private + + type, public :: fuel_type + + real(r8) :: loading(num_fuel_classes) ! fuel loading of each fuel class [kgC/m2] + real(r8) :: mean_total_SA(num_fuel_classes) ! mean total surface area per unit fuel cell of each fuel class [m2] + real(r8) :: weighting_factor(num_fuel_classes) ! weighting factor for calculating average fuel characteristics [unitless] + real(r8) :: fuel_weight(num_fuel_classes) ! weighting factor for calculating average fuel load [unitless] + real(r8) :: moisture(num_fuel_classes) ! fuel moisture by fuel class [m3 m-3] + real(r8) :: effective_moisture(num_fuel_classes) ! fuel effective moisture all fuel class (moisture/MEF) [m3/m3] + real(r8) :: frac_loading(num_fuel_classes) ! fractional loading of all fuel classes [0-1] + real(r8) :: frac_burnt(num_fuel_classes) ! fraction of litter burnt by fire [0-1] + real(r8) :: non_trunk_loading ! total fuel loading excluding trunks [kgC/m2] + real(r8) :: weighted_loading_dead ! this is dead fuel load weighted by weighting_factor given SA:V [kgC/m2] + real(r8) :: weighted_loading_live ! this is live fuel load weighted by weighting factor given SA:V [kgC/m2] + real(r8) :: wf_lead ! weighting factor for dead fuel category [unitless] + real(r8) :: wf_live ! weighting factor for live fuel category [unitless] + real(r8) :: average_moisture_dead ! weighted average of fuel moisture across all fuel classes for dead fuels [m3/m3] + real(r8) :: average_moisture_live ! weighted average of fuel moisture across all fuel classes for live fuels [m3/m3] + real(r8) :: bulk_density_weighted ! weighted average of bulk density across all fuel classes [kg/m3] + real(r8) :: SAV_weighted ! weighted average of surface area to volume ratio across non-trunk fuel classes [/cm] + real(r8) :: MEF_dead ! weighted average of moisture of extinction across all dead fuel classes [m3/m3] + real(r8) :: MEF_live ! moisture of extinction for live fuels [m3/m3] + + contains + procedure :: Init procedure :: Fuse procedure :: UpdateLoading + procedure :: CalculateWeightingFactor procedure :: SumLoading procedure :: CalculateFractionalLoading procedure :: UpdateFuelMoisture - procedure :: AverageBulkDensity_NoTrunks - procedure :: AverageSAV_NoTrunks + procedure :: AverageBulkDensity + procedure :: AverageSAV procedure :: CalculateFuelBurnt procedure :: CalculateResidenceTime + procedure :: FuelLoadWeight - end type fuel_type - - contains + end type fuel_type - subroutine Init(this) +contains + + subroutine Init(this) ! DESCRIPTION: ! Initialize fuel class ! ARGUMENTS: class(fuel_type), intent(inout) :: this ! fuel class - + ! just zero everything this%loading(1:num_fuel_classes) = 0.0_r8 + this%mean_total_SA(1:num_fuel_classes) = 0.0_r8 + this%weighting_factor(1:num_fuel_classes) = 0.0_r8 + this%fuel_weight(1:num_fuel_classes) = 0.0_r8 this%frac_loading(1:num_fuel_classes) = 0.0_r8 - this%frac_burnt(1:num_fuel_classes) = 0.0_r8 + this%frac_burnt(1:num_fuel_classes) = 0.0_r8 + this%moisture(1:num_fuel_classes) = 0.0_r8 this%effective_moisture(1:num_fuel_classes) = 0.0_r8 this%non_trunk_loading = 0.0_r8 - this%average_moisture_notrunks = 0.0_r8 - this%bulk_density_notrunks = 0.0_r8 - this%SAV_notrunks = 0.0_r8 - this%MEF_notrunks = 0.0_r8 - - end subroutine Init - - !------------------------------------------------------------------------------------- - - subroutine Fuse(this, self_area, donor_area, donor_fuel) + this%weighted_loading_dead = 0.0_r8 + this%weighted_loading_live = 0.0_r8 + this%wf_dead = 0.0_r8 + this%wf_live = 0.0_r8 + this%average_moisture_dead = 0.0_r8 + this%average_moisture_live = 0.0_r8 + this%bulk_density_weighted = 0.0_r8 + this%SAV_weighted = 0.0_r8 + this%MEF_dead = 0.0_r8 + this%MEF_live = 0.0_r8 + + end subroutine Init + + !------------------------------------------------------------------------------------- + + subroutine Fuse(this, self_area, donor_area, donor_fuel) ! DESCRIPTION: ! Fuse attributes of this object with another @@ -72,41 +94,58 @@ subroutine Fuse(this, self_area, donor_area, donor_fuel) real(r8), intent(in) :: self_area ! area of this fuel class's patch [m2] real(r8), intent(in) :: donor_area ! area of donor fuel class's patch [m2] type(fuel_type), intent(in) :: donor_fuel ! donor fuel class - + ! LOCALS: integer :: i ! looping index real(r8) :: self_weight ! weighting of the receiving fuel class real(r8) :: donor_weight ! weighting of the donor fuel class - + self_weight = self_area/(donor_area + self_area) donor_weight = 1.0_r8 - self_weight - - do i = 1, num_fuel_classes - this%loading(i) = this%loading(i)*self_weight + & - donor_fuel%loading(i)*donor_weight - this%frac_loading(i) = this%frac_loading(i)*self_weight + & - donor_fuel%frac_loading(i)*donor_weight - this%frac_burnt(i) = this%frac_burnt(i)*self_weight + & - donor_fuel%frac_burnt(i)*donor_weight - this%effective_moisture(i) = this%effective_moisture(i)*self_weight + & - donor_fuel%effective_moisture(i)*donor_weight - end do - + + do i = 1, num_fuel_classes + this%loading(i) = this%loading(i)*self_weight + & + donor_fuel%loading(i)*donor_weight + this%mean_total_SA(i) = this%mean_total_SA(i)*self_weight + & + donor_fuel%mean_total_SA(i)*donor_weight + this%weighting_factor(i) = this%weighting_factor(i)*self_weight + & + donor_fuel%weighting_factor(i)*donor_weight + this%fuel_weight(i) = this%fuel_weight(i)*self_weight + & + donor_fuel%fuel_weight(i)*donor_weight + this%frac_loading(i) = this%frac_loading(i)*self_weight + & + donor_fuel%frac_loading(i)*donor_weight + this%frac_burnt(i) = this%frac_burnt(i)*self_weight + & + donor_fuel%frac_burnt(i)*donor_weight + this%moisture(i) = this%moisture(i)*self_weight + & + donor_fuel%moisture(i)*donor_weight + this%effective_moisture(i) = this%effective_moisture(i)*self_weight + & + donor_fuel%effective_moisture(i)*donor_weight + end do + this%non_trunk_loading = this%non_trunk_loading*self_weight + & - donor_fuel%non_trunk_loading*donor_weight - this%average_moisture_notrunks = this%average_moisture_notrunks*self_weight + & - donor_fuel%average_moisture_notrunks*donor_weight - this%bulk_density_notrunks = this%bulk_density_notrunks*self_weight + & - donor_fuel%bulk_density_notrunks*donor_weight - this%SAV_notrunks = this%SAV_notrunks*self_weight + donor_fuel%SAV_notrunks*donor_weight - this%MEF_notrunks = this%MEF_notrunks*self_weight + donor_fuel%MEF_notrunks*donor_weight - - end subroutine Fuse - - !------------------------------------------------------------------------------------- - - subroutine UpdateLoading(this, leaf_litter, twig_litter, small_branch_litter, & - large_branch_litter, trunk_litter, live_grass) + donor_fuel%non_trunk_loading*donor_weight + this%weighted_loading_dead = this%weighted_loading_dead*self_weight + & + donor_fuel%weighted_loading_dead*donor_weight + this%weighted_loading_live = this%weighted_loading_live*self_weight + & + donor_fuel%weighted_loading_live*donor_weight + this%wf_dead = this%wf_dead*self_weight + donor_fuel%wf_dead*donor_weight + this%wf_live = this%wf_live*self_weight + donor_fuel%wf_live*donor_weight + this%average_moisture_dead = this%average_moisture_dead*self_weight + & + donor_fuel%average_moisture_dead*donor_weight + this%average_moisture_live = this%average_moisture_live*self_weight + & + donor_fuel%average_moisture_live*donor_weight + this%bulk_density_weighted = this%bulk_density_weighted*self_weight + & + donor_fuel%bulk_density_weighted*donor_weight + this%SAV_weighted = this%SAV_weighted*self_weight + donor_fuel%SAV_weighted*donor_weight + this%MEF_dead = this%MEF_dead*self_weight + donor_fuel%MEF_dead*donor_weight + this%MEF_live = this%MEF_live*self_weight + donor_fuel%live_dead*donor_weight + + end subroutine Fuse + + !------------------------------------------------------------------------------------- + + subroutine UpdateLoading(this, leaf_litter, twig_litter, small_branch_litter, & + large_branch_litter, trunk_litter, live_grass) ! DESCRIPTION: ! Updates loading for each fuel type @@ -126,156 +165,260 @@ subroutine UpdateLoading(this, leaf_litter, twig_litter, small_branch_litter, this%loading(fuel_classes%live_grass()) = live_grass this%loading(fuel_classes%trunks()) = trunk_litter - end subroutine UpdateLoading + end subroutine UpdateLoading + + !------------------------------------------------------------------------------------- + + subroutine CalculateWeightingFactor(this, sav_fuel, part_dens) + ! DESCRIPTION: + ! Calculate total area per fuel cell of each fuel class + ! and the derived weighting factors + + ! ARGUMENTS: + class(fuel_type), intent(inout) :: this ! fuel class + real(r8), intent(in) :: sav_fuel(num_fuel_classes) ! surface area to volume ratio of all fuel types [/cm] + real(r8), intent(in) :: part_dens ! oven-dry particle density [kg m-2] + + ! LOCALS: + integer :: i ! looping index + real(r8) :: A_dead ! total surface area of dead fuels + real(r8) :: A_live ! total surface area of live fuels + + ! initialize values + A_dead = 0.0_r8 + A_live = 0.0_r8 + ! calculate mean total area per unit fuel cell of each size EQ 53 in Rothermel 1972 + do i = 1, num_fuel_classes + this%mean_total_SA(i) = sav_fuel(i)*this%loading(i)/part_dens + if (i /= fuel_classes%live_grass()) then + A_dead = A_dead + this%mean_total_SA(i) + else + A_live = A_live + this%mean_total_SA(i) + end if + end do + ! calculate weighting factor, EQ. 56 in Rothermel 1972 + do i = 1, num_fuel_classes + if(i /= fuel_classes%live_grass()) then + this%weighting_factor(i) = this%mean_total_SA(i)/A_dead + else + this%weighting_factor(i) = this%mean_total_SA(i)/A_live + end if + end do + + this%wf_dead = A_dead/(A_dead + A_live) + this%wf_live = A_live/(A_dead + A_live) + + end subroutine CalculateWeightingFactor - !------------------------------------------------------------------------------------- + !------------------------------------------------------------------------------------- - subroutine SumLoading(this) + subroutine SumLoading(this) ! DESCRIPTION: - ! Sums up the loading - excludes trunks + ! Sums up the loading - excludes trunks ! - ! Only the 1-h, 10-h and 100-h fuel classes influence fire spread - ! Rothermel, 1972 (USDA FS GTR INT-115) - ! Wilson, 1982 (UTINT-289) - ! Pyne et al., 1996 (Introduction to wildland fire) + ! Only the 1-h, 10-h and 100-h fuel classes influence fire spread + ! Rothermel, 1972 (USDA FS GTR INT-115) + ! Wilson, 1982 (UTINT-289) + ! Pyne et al., 1996 (Introduction to wildland fire) + ! XLG 2025-10-16 + ! fuel load is summed using the calculated weighting factors in + ! a way that if two fuel classes belong to the same group given SAV (see below) + ! then the two fuel classes share one weighting factor, which is the sum of the weighting_factor + ! across the two fuel classes, and weight is 0 if SAV < 0.52 cm-1 + ! + ! the six fuel subgroups are: + ! SAV >= 1200 ft-1 (39.36 cm-1) + ! 192 ft-1 (6.3 cm-1) <= SAV < 1200 ft-1 (39.36 cm-1) + ! 96 ft-1 (3.14 cm-1) <= SAV < 192 ft-1 (6.3 cm-1) + ! 48 ft-1 (1.57 cm-1) <= SAV < 96 ft-1 (3.14 cm-1) + ! 16 ft-1 (0.52 cm-1) <= SAV < 48 ft-1 (1.57 cm-1) + ! SAV < 16 ft-1 (0.52 cm-1) + ! P 14-15 in Albini 1976a , which is refined version for EQs 59-60 in Rothermel 1972 ! ARGUMENTS: class(fuel_type), intent(inout) :: this ! fuel class - + ! LOCALS: - integer :: i ! looping index - + integer :: i ! looping index + + ! ensure weighting factor is updated + call this%CalculateWeightingFactor() + + ! get fuel load weighting factor given SAV + call this%FuelLoadWeight() this%non_trunk_loading = 0.0_r8 + this%weighted_loading_dead = 0.0_r8 + this%weighted_loading_live = 0.0_r8 do i = 1, num_fuel_classes - if (i /= fuel_classes%trunks()) then - this%non_trunk_loading = this%non_trunk_loading + this%loading(i) - end if + if (i /= fuel_classes%trunks()) then + this%non_trunk_loading = this%non_trunk_loading + & + this%loading(i) + end if + + if(i /= fuel_classes%live_grass())then + this%weighted_loading_dead = this%weighted_loading_dead + & + this%fuel_weight*this%loading(i) + else + this%weighted_loading_live = this%weighted_loading_live + & + this%fuel_weight*this%loading(i) + end if + end do - end subroutine SumLoading + end subroutine SumLoading - !------------------------------------------------------------------------------------- - - subroutine CalculateFractionalLoading(this) + !------------------------------------------------------------------------------------- + + subroutine CalculateFractionalLoading(this) ! DESCRIPTION: ! Calculates fractional loading for fuel ! ARGUMENTS: class(fuel_type), intent(inout) :: this ! fuel class - + ! LOCALS: integer :: i ! looping index ! sum up loading just in case call this%SumLoading() - + if (this%non_trunk_loading > nearzero) then - do i = 1, num_fuel_classes - if (i /= fuel_classes%trunks()) then - this%frac_loading(i) = this%loading(i)/this%non_trunk_loading - else - this%frac_loading(i) = 0.0_r8 - end if - end do - else - this%frac_loading(1:num_fuel_classes) = 0.0_r8 - this%non_trunk_loading = 0.0_r8 - end if - - end subroutine CalculateFractionalLoading - - !------------------------------------------------------------------------------------- - - subroutine UpdateFuelMoisture(this, sav_fuel, drying_ratio, fireWeatherClass) + do i = 1, num_fuel_classes + if (i /= fuel_classes%trunks()) then + this%frac_loading(i) = this%loading(i)/this%non_trunk_loading + else + this%frac_loading(i) = 0.0_r8 + end if + end do + else + this%frac_loading(1:num_fuel_classes) = 0.0_r8 + this%non_trunk_loading = 0.0_r8 + end if + + end subroutine CalculateFractionalLoading + + !------------------------------------------------------------------------------------- + + subroutine UpdateFuelMoisture(this, sav_fuel, drying_ratio, fireWeatherClass) ! DESCRIPTION: ! Updates fuel moisture depending on what fire weather class is in use - + ! ARGUMENTS: class(fuel_type), intent(inout) :: this ! fuel class real(r8), intent(in) :: sav_fuel(num_fuel_classes) ! surface area to volume ratio of all fuel types [/cm] real(r8), intent(in) :: drying_ratio ! drying ratio class(fire_weather), intent(in) :: fireWeatherClass ! fireWeatherClass - - real(r8) :: moisture(num_fuel_classes) ! fuel moisture [m3/m3] + real(r8) :: moisture_of_extinction(num_fuel_classes) ! fuel moisture of extinction [m3/m3] + real(r8) :: mef_live ! live fuel moisture of extinction [m3/m3] integer :: i ! looping index - - if (this%non_trunk_loading + this%loading(fuel_classes%trunks()) > nearzero) then - ! calculate fuel moisture [m3/m3] for each fuel class depending on what - ! fire weather class is in use - select type (fireWeatherClass) + + if (this%non_trunk_loading + this%loading(fuel_classes%trunks()) > nearzero) then + ! calculate fuel moisture [m3/m3] for each fuel class depending on what + ! fire weather class is in use + select type (fireWeatherClass) class is (nesterov_index) call CalculateFuelMoistureNesterov(sav_fuel, drying_ratio, & - fireWeatherClass%fire_weather_index, moisture) - class default + fireWeatherClass%fire_weather_index) + class default write(fates_log(), *) 'Unknown fire weather class selected.' write(fates_log(), *) 'Choose a different fire weather class or upate this subroutine.' call endrun(msg=errMsg( __FILE__, __LINE__)) - end select - - this%average_moisture_notrunks = 0.0_r8 - this%MEF_notrunks = 0.0_r8 - do i = 1, num_fuel_classes - ! calculate moisture of extinction and fuel effective moisture - moisture_of_extinction(i) = MoistureOfExtinction(sav_fuel(i)) - this%effective_moisture(i) = moisture(i)/moisture_of_extinction(i) - - ! average fuel moisture and MEF across all fuel types except trunks [m3/m3] - if (i /= fuel_classes%trunks()) then - this%average_moisture_notrunks = this%average_moisture_notrunks + this%frac_loading(i)*moisture(i) - this%MEF_notrunks = this%MEF_notrunks + this%frac_loading(i)*moisture_of_extinction(i) - end if - end do - - else - this%effective_moisture(1:num_fuel_classes) = 0.0_r8 - this%average_moisture_notrunks = 0.0_r8 - this%MEF_notrunks = 0.0_r8 + end select + + this%average_moisture_dead = 0.0_r8 + this%average_moisture_live = 0.0_r8 + this%MEF_dead = 0.0_r8 + this%MEF_live = 0.0_r8 + do i = 1, num_fuel_classes + ! effective_moisture is used for determining fractional fuel burnt per fuel class later + ! to derive this by fuel category (live vs dead) and by fuel sizes + ! let's still keep this calculation for both dead and live fuels + moisture_of_extinction(i) = MoistureOfExtinction(sav_fuel(i)) + this%effective_moisture(i) = moisture(i)/moisture_of_extinction(i) + if(i /= fuel_classes%live_grass())then + ! average fuel moisture and MEF for dead fuels [m3/m3] EQ. 66 in Rothermel 1972 + ! trunk is not excluded, but it's getting a small weight + ! MEF_dead is an input parameter in Rothermel 1972. Since we are calculating it for + ! each fuel size class given SA:V, I am calculating averaged MEF_dead using the + ! weighting factor 2025-10-16 XLG + this%average_moisture_dead = this%average_moisture_dead + & + this%weighting_factor(i)*moisture(i) + this%MEF_dead = this%MEF_dead + this%weighting_factor(i)*moisture_of_extinction(i) + end if + end do + + ! calculate average moisture and MEF for live fuels. We currently only have live grass fuel + ! The definition of surface fuel bed, however, includes live woody fuel from 1h to 100h + ! consider including live fine woody fuels later 2025-10-16 XLG + + this%average_moisture_live = this%average_moisture_live + & + this%weighting_factor(fuel_classes%live_grass())*moisture(fuel_classes%live_grass()) + + ! this is the Rothermel way of calculating averaged live fuel MEF across all fuel + ! classes for live fuels, which is then used to calculate live fuel mositure damping coeff + ! The difference between the SPITFIRE version and original Rothermel model + ! is that live and dead fuels are always treated separately in the original model + call LiveFuelMoistureOfExtinction(this%fuel_loading, sav_fuel, moisture, & + this%MEF_dead, mef_live) + this%MEF_live = mef_live + else + this%effective_moisture(1:num_fuel_classes) = 0.0_r8 + this%average_moisture_dead = 0.0_r8 + this%average_moisture_live = 0.0_r8 + this%MEF_dead = 0.0_r8 + this%MEF_live = 0.0_r8 end if - - end subroutine UpdateFuelMoisture - - !------------------------------------------------------------------------------------- - - subroutine CalculateFuelMoistureNesterov(sav_fuel, drying_ratio, NI, moisture) + + end subroutine UpdateFuelMoisture + + !------------------------------------------------------------------------------------- + + subroutine CalculateFuelMoistureNesterov(this, sav_fuel, drying_ratio, NI) ! ! DESCRIPTION: ! Updates fuel moisture ! ARGUMENTS: - real(r8), intent(in) :: sav_fuel(num_fuel_classes) ! surface area to volume ratio of all fuel types [/cm] - real(r8), intent(in) :: drying_ratio ! drying ratio - real(r8), intent(in) :: NI ! Nesterov Index - real(r8), intent(out) :: moisture(num_fuel_classes) ! moisture of litter [m3/m3] - + class(fuel_type), intent(inout) :: this ! fuel class + real(r8), intent(in) :: sav_fuel(num_fuel_classes) ! surface area to volume ratio of all fuel types [/cm] + real(r8), intent(in) :: drying_ratio ! drying ratio + real(r8), intent(in) :: NI ! Nesterov Index + ! LOCALS integer :: i ! looping index real(r8) :: alpha_FMC ! intermediate variable for calculating fuel moisture - + do i = 1, num_fuel_classes - if (i == fuel_classes%live_grass()) then - ! 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 - alpha_FMC = sav_fuel(fuel_classes%twigs())/drying_ratio - else - alpha_FMC = sav_fuel(i)/drying_ratio - end if - moisture(i) = exp(-1.0_r8*alpha_FMC*NI) + if (i == fuel_classes%live_grass()) then + ! 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 + alpha_FMC = sav_fuel(fuel_classes%twigs())/drying_ratio + else + alpha_FMC = sav_fuel(i)/drying_ratio + end if + this%moisture(i) = exp(-1.0_r8*alpha_FMC*NI) end do - - end subroutine CalculateFuelMoistureNesterov - - !------------------------------------------------------------------------------------- - - real(r8) function MoistureOfExtinction(sav) + + end subroutine CalculateFuelMoistureNesterov + + !------------------------------------------------------------------------------------- + + real(r8) function MoistureOfExtinction(sav) ! ! DESCRIPTION: ! Calculates moisture of extinction based on input surface area to volume ratio - - ! MEF (moisure of extinction) depends on compactness of fuel, depth, particle size, + ! In Albini 1976a and Rothermel 1972 MEF_dead is an input parameter + ! MEF_live is then calculated using P16 in Albini 1976a, which is a function of + ! MEF_dead, dead-to-live load ratio and dead fuel moisture + ! We'll keep this function for calculating MEF dead for each fuel class and then + ! calculate the weighted mean MEF_dead given weighting_factor + ! XLG 2025-10-16 + + ! MEF (moisure of extinction) depends on compactness of fuel, depth, particle size, ! wind, and slope - ! Equation here is Eq. 27 from Peterson and Ryan (1986) "Modeling Postfire Conifer + ! Equation here is Eq. 27 from Peterson and Ryan (1986) "Modeling Postfire Conifer ! Mortality for Long-Range Planning" ! ! Example MEFs: @@ -291,98 +434,155 @@ real(r8) function MoistureOfExtinction(sav) ! tropical deciduous trees = 0.3 (Lasslop 2014; Table 1) ! extratropical trees = 0.3 (Lasslop 2014; Table 1) ! - ! SAV values from Thonicke 2010 give: + ! SAV values from Thonicke 2010 give: ! twigs = 0.355, small branches = 0.44, large branches = 0.525, trunks = 0.63 ! dead leaves = 0.248, live grass = 0.248 ! - + ! ARGUMENTS: real(r8), intent(in) :: sav ! fuel surface area to volume ratio [/cm] - + ! CONSTANTS: real(r8), parameter :: MEF_a = 0.524_r8 real(r8), parameter :: MEF_b = 0.066_r8 - + if (sav <= 0.0_r8) then - write(fates_log(), *) 'SAV cannot be negative - SAV' - call endrun(msg=errMsg(__FILE__, __LINE__)) + write(fates_log(), *) 'SAV cannot be negative - SAV' + call endrun(msg=errMsg(__FILE__, __LINE__)) else - MoistureOfExtinction = MEF_a - MEF_b*log(sav) + MoistureOfExtinction = MEF_a - MEF_b*log(sav) end if - - end function MoistureOfExtinction - - !------------------------------------------------------------------------------------- - - subroutine AverageBulkDensity_NoTrunks(this, bulk_density) + + end function MoistureOfExtinction + + !------------------------------------------------------------------------------------- + subroutine LiveFuelMoistureOfExtinction(fuel_load, sav_val, fmc, mef_dead, mef_live) + ! + ! DESCRIPTION + ! Calculate average MEF for live fuels using P. 16 in Albini 1976a, whiched replaced EQ. 88 + ! in Rothermel 1972; a unit conversion for sav has been applied to convert [cm-1 ----> ft-1 ] + ! + use FatesLitterMod + ! ARGUMENTS + real(r8), intent(in) :: fuel_load(num_fuel_classes) ! fuel load [kgC m-2] + real(r8), intent(in) :: sav_val(num_fuel_classes) ! fuel surface area to volume ratio [cm-1] + real(r8), intent(in) :: fmc(num_fuel_classes) ! fuel moisture content by size class [m3/m3] + real(r8), intent(in) :: mef_dead ! weighted mean of moisture of extinction for dead fuel + real(r8), intent(out) :: mef_live ! live fuel moisture of extinction + ! LOCALS + real(r8) :: W ! dead-to-live load ratio + real(r8) :: moist_dead ! dead fuel moisture + real(r8) :: w_n, md_n ! nominator for calculating W and moist_dead + real(r8) :: w_d, md_d ! denominator for calculating W and moist_dead + + integer :: i ! looping index + + w_n = 0.0_r8 + md_n = 0.0_r8 + w_d = 0.0_r8 + md_d = 0.0_r8 + do i = 1, num_fuel_classes + if(i /= fuel_classes%live_grass())then + w_n = w_n + fuel_load(i)*exp(-4.5276_r8/sav_val(i)) + md_n = md_n + fmc(i)*fuel_load(i)*exp(-4.5276_r8/sav_val(i)) + md_d = md_d + fuel_load(i)*exp(-4.5264_r8/sav_val(i)) + else + w_d = w_d + fuel_load(i)*exp(-16.4042_r8/sav_val(i)) + end if + + end do + W = w_n/w_d + moist_dead = md_n/md_d + mef_live = 2.9_r8 * W * (1.0_r8 - moist_dead/mef_dead) - 0.226_r8 + + end subroutine LiveFuelMoistureOfExtinction + + !------------------------------------------------------------------------------------- + + subroutine AverageBulkDensity(this, bulk_density) ! DESCRIPTION: - ! Calculates average bulk density (not including trunks) + ! Calculates average bulk density, which is weighted toward fine fuels (1-100-h fuels) ! - ! Only the 1-h, 10-h and 100-h fuel classes influence fire spread - ! Rothermel, 1972 (USDA FS GTR INT-115) + ! Only the 1-h, 10-h and 100-h fuel classes influence fire spread + ! Rothermel, 1972 (USDA FS GTR INT-115) ! Wilson, 1982 (UTINT-289) ! Pyne et al., 1996 (Introduction to wildland fire) ! ARGUMENTS: class(fuel_type), intent(inout) :: this ! fuel class real(r8), intent(in) :: bulk_density(num_fuel_classes) ! bulk density of all fuel types [kg/m3] - + ! LOCALS: - integer :: i ! looping index - + integer :: i ! looping index + real(r8) :: fbd_dead ! mean fuel bulk density for dead fuels [kg/m3] + real(r8) :: fbd_live ! mean fuel bulk density for live fuels [kg/m3] + if (this%non_trunk_loading > nearzero) then - this%bulk_density_notrunks = 0.0_r8 - do i = 1, num_fuel_classes - ! average bulk density across all fuel types except trunks - if (i /= fuel_classes%trunks()) then - this%bulk_density_notrunks = this%bulk_density_notrunks + this%frac_loading(i)*bulk_density(i) - end if - end do - else - this%bulk_density_notrunks = sum(bulk_density(1:num_fuel_classes))/num_fuel_classes + fbd_dead = 0.0_r8 + fbd_live = 0.0_r8 + do i = 1, num_fuel_classes + if(i /= fuel_classes%live_grass())then + fbd_dead = fbd_dead + this%weighting_factor(i)*bulk_density(i) + else + fbd_live = fbd_live + this%weighting_factor(i)*bulk_density(i) + end if + + end do + ! average bulk density between dead and live fuels using wf_dead and wf_live + ! same as how SAV is calculated for the entire fuel bed + this%bulk_density_weighted = this%wf_dead*fbd_dead + this%wf_live*fbd_live + else + this%bulk_density_weighted = sum(bulk_density(1:num_fuel_classes))/num_fuel_classes end if - - end subroutine AverageBulkDensity_NoTrunks - - !------------------------------------------------------------------------------------- - - subroutine AverageSAV_NoTrunks(this, sav_fuel) + + end subroutine AverageBulkDensity + + !------------------------------------------------------------------------------------- + + subroutine AverageSAV(this, sav_fuel) ! DESCRIPTION: - ! Calculates average surface area to volume ratio (not including trunks) + ! Calculates average surface area to volume ratio, weighted toward fine fuels (1-100-h fuels) ! - ! Only the 1-h, 10-h and 100-h fuel classes influence fire spread - ! Rothermel, 1972 (USDA FS GTR INT-115) + ! Only the 1-h, 10-h and 100-h fuel classes influence fire spread + ! Rothermel, 1972 (USDA FS GTR INT-115) ! Wilson, 1982 (UTINT-289) ! Pyne et al., 1996 (Introduction to wildland fire) ! ARGUMENTS: class(fuel_type), intent(inout) :: this ! fuel class real(r8), intent(in) :: sav_fuel(num_fuel_classes) ! surface area to volume ratio of all fuel types [/cm] - + ! LOCALS: - integer :: i ! looping index - + integer :: i ! looping index + real(r8) :: sav_dead ! average SA:V of dead fuels + real(r8) :: sav_live ! average SA:V of live fuels + if (this%non_trunk_loading > nearzero) then - this%SAV_notrunks = 0.0_r8 - do i = 1, num_fuel_classes - ! average bulk density across all fuel types except trunks - if (i /= fuel_classes%trunks()) then - this%SAV_notrunks = this%SAV_notrunks + this%frac_loading(i)*sav_fuel(i) - end if - end do - else - this%SAV_notrunks = sum(sav_fuel(1:num_fuel_classes))/num_fuel_classes + sav_dead = 0.0_r8 + sav_live = 0.0_r8 + do i = 1, num_fuel_classes + ! average bulk density across all fuel types, EQ. 72 in Rothermel 1972 + if (i /= fuel_classes%live_grass()) then + sav_dead = sav_dead + this%weighting_factor(i)*sav_fuel(i) + else + sav_live = sav_live + this%weighting_factor(i)*sav_fuel(i) + end if + end do + ! averaged SA:V between dead and live fuels, EQ 71 in Rothermel 1972 + this%SAV_weighted = this%wf_dead*sav_dead + this%wf_live*sav_live + else + this%SAV_weighted = sum(sav_fuel(1:num_fuel_classes))/num_fuel_classes end if - - end subroutine AverageSAV_NoTrunks - - !--------------------------------------------------------------------------------------- - - subroutine CalculateFuelBurnt(this, fuel_consumed) + + end subroutine AverageSAV + + !--------------------------------------------------------------------------------------- + + subroutine CalculateFuelBurnt(this, fuel_consumed) ! DESCRIPTION: ! Calculates the fraction and total amount of fuel burnt ! - + use SFParamsMod, only : SF_val_mid_moisture, SF_val_mid_moisture_Coeff use SFParamsMod, only : SF_val_mid_moisture_Slope, SF_val_min_moisture use SFParamsMod, only : SF_val_low_moisture_Coeff, SF_val_low_moisture_Slope @@ -391,55 +591,62 @@ subroutine CalculateFuelBurnt(this, fuel_consumed) ! ARGUMENTS: class(fuel_type), intent(inout) :: this ! fuel class real(r8), intent(out) :: fuel_consumed(num_fuel_classes) ! fuel consumed [kgC/m2] - + ! LOCALS: - real(r8) :: rel_moisture ! relative moisture of fuel (moist/moisture of extinction) [unitless] - integer :: i ! looping index - + real(r8) :: rel_moisture ! relative moisture of fuel (moist/moisture of extinction) [unitless] + integer :: i ! looping index + ! CONSTANTS: real(r8), parameter :: max_grass_frac = 0.8_r8 ! maximum fraction burnt for live grass fuels - + this%frac_burnt(:) = 1.0_r8 - - ! Calculate fraction of litter is burnt for all classes. + ! get all the weighting factor + call this%CalculateWeightingFactor() + call this%FuelLoadWeight() + + ! Calculate fraction of litter is burnt for all classes. ! Equation B1 in Thonicke et al. 2010 - do i = 1, num_fuel_classes - - rel_moisture = this%effective_moisture(i) - - if (rel_moisture <= SF_val_min_moisture(i)) then - ! very dry litter - this%frac_burnt(i) = 1.0_r8 - else if (rel_moisture > SF_val_min_moisture(i) .and. rel_moisture <= SF_val_mid_moisture(i)) then - ! low to medium moisture - this%frac_burnt(i) = max(0.0_r8, min(1.0_r8, SF_val_low_moisture_Coeff(i) - & - SF_val_low_moisture_Slope(i)*rel_moisture)) - else if (rel_moisture > SF_val_mid_moisture(i) .and. rel_moisture <= 1.0_r8) then - ! medium to high moisture - this%frac_burnt(i) = max(0.0_r8, min(1.0_r8, SF_val_mid_moisture_Coeff(i) - & - SF_val_mid_moisture_Slope(i)*rel_moisture)) - else - ! very wet litter - this%frac_burnt(i) = 0.0_r8 - endif - - ! we can't ever kill all of the grass - if (i == fuel_classes%live_grass()) then - this%frac_burnt(i) = min(max_grass_frac, this%frac_burnt(i)) - end if - - ! reduce fraction burnt based on mineral content - this%frac_burnt(i) = this%frac_burnt(i)*(1.0_r8 - SF_val_miner_total) - - ! calculate fuel consumed - fuel_consumed(i) = this%frac_burnt(i)*this%loading(i) + do i = 1, num_fuel_classes + + rel_moisture = this%effective_moisture(i) + + if (rel_moisture <= SF_val_min_moisture(i)) then + ! very dry litter + this%frac_burnt(i) = 1.0_r8 + else if (rel_moisture > SF_val_min_moisture(i) .and. rel_moisture <= SF_val_mid_moisture(i)) then + ! low to medium moisture + this%frac_burnt(i) = max(0.0_r8, min(1.0_r8, SF_val_low_moisture_Coeff(i) - & + SF_val_low_moisture_Slope(i)*rel_moisture)) + else if (rel_moisture > SF_val_mid_moisture(i) .and. rel_moisture <= 1.0_r8) then + ! medium to high moisture + this%frac_burnt(i) = max(0.0_r8, min(1.0_r8, SF_val_mid_moisture_Coeff(i) - & + SF_val_mid_moisture_Slope(i)*rel_moisture)) + else + ! very wet litter + this%frac_burnt(i) = 0.0_r8 + endif + + ! we can't ever kill all of the grass + if (i == fuel_classes%live_grass()) then + this%frac_burnt(i) = min(max_grass_frac, this%frac_burnt(i)) + end if + + ! reduce fraction burnt based on mineral content + this%frac_burnt(i) = this%frac_burnt(i)*(1.0_r8 - SF_val_miner_total) + + ! calculate fuel consumed + ! we don't use the raw loading (which assum a weight of 1 for each fuel class) + ! switch to using the weighted fuel load per size class 2025-10-16 XLG + ! see p15, p17 in Albini 1976a for the calculation of reaction intensity based on + ! weighted fuel load. so we also use the weighted fuel load here just to be consistent + fuel_consumed(i) = this%frac_burnt(i)*this%loading(i)*this%fuel_weight(i) end do - end subroutine CalculateFuelBurnt - - !------------------------------------------------------------------------------------- - - subroutine CalculateResidenceTime(this, tau_l) + end subroutine CalculateFuelBurnt + + !------------------------------------------------------------------------------------- + + subroutine CalculateResidenceTime(this, tau_l) ! ! DESCRIPTION: ! Calculates fire residence time, duration of lethal bole heating [min] @@ -447,27 +654,91 @@ subroutine CalculateResidenceTime(this, tau_l) ! ! From Peterson & Ryan (1986) ! - + ! ARGUMENTS: class(fuel_type), intent(in) :: this ! fuel class real(r8), intent(out) :: tau_l ! duration of lethal bole heating [min] - + ! LOCALS: integer :: i ! looping index - - tau_l = 0.0_r8 + + tau_l = 0.0_r8 do i = 1, num_fuel_classes - if (i /= fuel_classes%trunks()) then - ! don't include 1000-hr fuels - ! convert loading from kgC/m2 to g/cm2 - tau_l = tau_l + 39.4_r8*(this%frac_loading(i)*this%non_trunk_loading/0.45_r8/10.0_r8)* & - (1.0_r8 - ((1.0_r8 - this%frac_burnt(i))**0.5_r8)) - end if + if (i /= fuel_classes%trunks()) then + ! don't include 1000-hr fuels + ! convert loading from kgC/m2 to g/cm2 + tau_l = tau_l + 39.4_r8*(this%frac_loading(i)*this%non_trunk_loading/0.45_r8/10.0_r8)* & + (1.0_r8 - ((1.0_r8 - this%frac_burnt(i))**0.5_r8)) + end if end do - + ! cap the residence time to 8mins, as suggested by literature survey by P&R (1986) - tau_l = min(8.0_r8, tau_l) + tau_l = min(8.0_r8, tau_l) + + end subroutine CalculateResidenceTime + + + !------------------------------------------------------------------------------------- + subroutine FuelLoadWeight(this) + ! + ! DESCRIPTION + ! Assign each fuel class to one fuel group given user-defined SA:V + ! calculate weighting factor for each fuel class, which will be used + ! to calculate sum fuel load; we only do this for dead fuel since + ! dead and live fuels are treated separately and we currently only have + ! one live fuel, weight should always be 1 + ! + use SFParamsMod, only : SF_val_SAV + ! ARGUMENTS: + class(fuel_type), intent(inout) :: this ! fuel class + ! LOCALS: + integer :: ng ! sizes + integer :: i, g ! looping indices + integer :: group_idx(num_fuel_classes) ! fuel group assigned + real(r8), allocatable :: group_sum(:) ! summed weight across fuel sizes that are within the same subgroup + real(r8), parameter, dimension(5) :: sav_edg=(/0.53_r8, 1.58_r8, 3.15_r8, 6.30_r8, 39.37_r8/) + + ng = size(sav_edg) + ! initialize fuel group with group 1 (sav < 0.53) + group_idx(:) = 1 + ! assign fuel class to one of the fuel groups + ! for each sav edge value, if sav > sav_edg, increment by 1 + ! at the corresponding location for group_idx + do g = 1, ng + where (SF_val_SAV >= sav_edg(g)) group_idx = group_idx + 1 + end do + + allocate(group_sum(ng+1)) + group_sum(:) = 0.0_r8 + + ! sum weighting factor across the same subgroup + ! only using dead fuels now + ! as this is calculated for dead and live category separately + ! but dead and live fuels should have same SA:V (which should only be + ! influenced by size class not dead/live category). + ! We only have one live grass fuel, which share one SAV value with 1h dead + do i = 1, num_fuel_classes + if(i /= fuel_classes%live_grass())then + group_sum(group_idx(i)) = group_sum(group_idx(i)) + this%weighting_factor(i) + end if + end do + ! map the fuel load weighting factor to each fuel class + ! if group is 1 (sav < 0.5) then fuel_weight = 0 + ! also live grass fuel has a weight of 1 since we now only have one + ! fuel size in live fuel category + do i = 1, num_fuel_classes + if(group_idx(i) == 1) then + this%fuel_weight(i) = group_sum(group_idx(i))*0.0_r8 + else if(i == fuel_classes%live_grass())then + this%fuel_weight(i) = 1.0_r8 + else + this%fuel_weight(i) = group_sum(group_idx(i)) + end if + end do + + deallocate(group_sum) + + end subroutine FuelLoadWeight + - end subroutine CalculateResidenceTime - end module FatesFuelMod diff --git a/fire/SFEquationsMod.F90 b/fire/SFEquationsMod.F90 index ab8fcc16c3..9d66157cbe 100644 --- a/fire/SFEquationsMod.F90 +++ b/fire/SFEquationsMod.F90 @@ -1,225 +1,227 @@ module SFEquationsMod - ! ============================================================================ - ! Helper methods for the FATES SPITFIRE model - ! Most equations come from: - ! Thonicke et al. 2010, Biogeosciences 7:1991-2011 - ! Rothermel et al. 1972, Research Paper INT 115 - ! Albini et al. 1976, Research Report INT 30 - ! ============================================================================ - - use FatesConstantsMod, only : r8 => fates_r8 - use FatesConstantsMod, only : nearzero - use FatesGlobals, only : endrun => fates_endrun - use shr_log_mod, only : errMsg => shr_log_errMsg - - implicit none - private - - public :: MaximumReactionVelocity - public :: OptimumReactionVelocity - public :: OptimumPackingRatio - public :: MoistureCoefficient - public :: ReactionIntensity - public :: HeatofPreignition - public :: EffectiveHeatingNumber - public :: WindFactor - public :: PropagatingFlux - public :: ForwardRateOfSpread - public :: BackwardRateOfSpread - public :: FireDuration - public :: LengthToBreadth - public :: FireSize - public :: AreaBurnt - public :: FireIntensity - public :: ScorchHeight - public :: CrownFractionBurnt - public :: BarkThickness - public :: CambialMortality - public :: TotalFireMortality - public :: CrownFireMortality - public :: CriticalResidenceTime - public :: cambial_mort - - ! for error message writing - character(len=*), parameter :: sourcefile = __FILE__ - - contains - - real(r8) function OptimumPackingRatio(SAV) - ! - ! DESCRIPTION: - ! Calculates optimum packing ratio [unitless] - ! Equation A6 in Thonicke et al. 2010 - ! Rothermel 1972 Eq. 37 - ! - - ! ARGUMENTS: - real(r8), intent(in) :: SAV ! surface area to volume ratio of fuel [/cm] - - ! CONSTANTS: - real(r8), parameter :: a = 0.200395_r8 - real(r8), parameter :: b = -0.8189_r8 - - if (SAV < nearzero) then - OptimumPackingRatio = 0.0_r8 - else - OptimumPackingRatio = a*(SAV**b) - end if - - end function OptimumPackingRatio - - !------------------------------------------------------------------------------------- - - real(r8) function MaximumReactionVelocity(SAV) + ! ============================================================================ + ! Helper methods for the FATES SPITFIRE model + ! Most equations come from: + ! Thonicke et al. 2010, Biogeosciences 7:1991-2011 + ! Rothermel et al. 1972, Research Paper INT 115 + ! Albini et al. 1976, Research Report INT 30 + ! ============================================================================ + + use FatesFuelClassesMod, only : num_fuel_classes, fuel_classes + use FatesConstantsMod, only : r8 => fates_r8 + use FatesConstantsMod, only : nearzero + use FatesGlobals, only : endrun => fates_endrun + use shr_log_mod, only : errMsg => shr_log_errMsg + + implicit none + private + + public :: MaximumReactionVelocity + public :: OptimumReactionVelocity + public :: OptimumPackingRatio + public :: MoistureCoefficient + public :: ReactionIntensity + public :: HeatofPreignition + public :: EffectiveHeatingNumber + public :: HeatSink + public :: WindFactor + public :: PropagatingFlux + public :: ForwardRateOfSpread + public :: BackwardRateOfSpread + public :: FireDuration + public :: LengthToBreadth + public :: FireSize + public :: AreaBurnt + public :: FireIntensity + public :: ScorchHeight + public :: CrownFractionBurnt + public :: BarkThickness + public :: CambialMortality + public :: TotalFireMortality + public :: CrownFireMortality + public :: CriticalResidenceTime + public :: cambial_mort + + ! for error message writing + character(len=*), parameter :: sourcefile = __FILE__ + +contains + + real(r8) function OptimumPackingRatio(SAV) + ! + ! DESCRIPTION: + ! Calculates optimum packing ratio [unitless] + ! Equation A6 in Thonicke et al. 2010 + ! Rothermel 1972 Eq. 37 + ! + + ! ARGUMENTS: + real(r8), intent(in) :: SAV ! surface area to volume ratio of fuel [/cm] + + ! CONSTANTS: + real(r8), parameter :: a = 0.20395_r8 + real(r8), parameter :: b = -0.8189_r8 + + if (SAV < nearzero) then + OptimumPackingRatio = 0.0_r8 + else + OptimumPackingRatio = a*(SAV**b) + end if + + end function OptimumPackingRatio + + !------------------------------------------------------------------------------------- + + real(r8) function MaximumReactionVelocity(SAV) ! ! DESCRIPTION: ! Calculates maximum reaction velocity in /min ! ! From Equation 36 in Rothermel 1972; Fig. 12 ! - + ! ARGUMENTS: real(r8), intent(in) :: SAV ! fuel surface area to volume ratio [/cm] - - if (SAV < nearzero) then - MaximumReactionVelocity = 0.0_r8 - else - MaximumReactionVelocity = 1.0_r8/(0.0591_r8 + 2.926_r8*(SAV**(-1.5_r8))) + + if (SAV < nearzero) then + MaximumReactionVelocity = 0.0_r8 + else + MaximumReactionVelocity = 1.0_r8/(0.0591_r8 + 2.942_r8*(SAV**(-1.5_r8))) end if - - end function MaximumReactionVelocity - - !------------------------------------------------------------------------------------- - - real(r8) function OptimumReactionVelocity(max_reaction_vel, SAV, beta_ratio) + + end function MaximumReactionVelocity + + !------------------------------------------------------------------------------------- + + real(r8) function OptimumReactionVelocity(max_reaction_vel, SAV, beta_ratio) ! ! DESCRIPTION: ! Calculates optimum reaction velocity in /min ! - ! Reaction velocity (i.e. rate of fuel consumption) that would exist if the - ! fuel were free of moisture and contained minerals at the same reaction + ! Reaction velocity (i.e. rate of fuel consumption) that would exist if the + ! fuel were free of moisture and contained minerals at the same reaction ! concentration as alpha cellulose ! ! From Equation 38 in Rothermel 1972; Fig. 11 ! - + ! ARGUMENTS: real(r8), intent(in) :: max_reaction_vel ! maximum reaction velocity [/min] real(r8), intent(in) :: SAV ! fuel surface area to volume ratio [/cm] real(r8), intent(in) :: beta_ratio ! ratio of packing ratio to optimum packing ratio [0-1] - + ! LOCALS: real (r8) :: a, a_beta ! intermediate variables - + ! Equations in Table A1 Thonicke et al. 2010 a = 8.9033_r8*(SAV**(-0.7913_r8)) - a_beta = exp(a*(1.0_r8 - beta_ratio)) - + a_beta = exp(a*(1.0_r8 - beta_ratio)) + OptimumReactionVelocity = max_reaction_vel*(beta_ratio**a)*a_beta - - end function OptimumReactionVelocity - - !------------------------------------------------------------------------------------- - - real(r8) function MoistureCoefficient(moisture, MEF) + + end function OptimumReactionVelocity + + !------------------------------------------------------------------------------------- + + real(r8) function MoistureCoefficient(moisture, MEF) ! ! DESCRIPTION: ! Calculates the moisture dampening coefficient for reaction intensity - ! Based on Equation in table A1 Thonicke et al. 2010. + ! Based on Equation in table A1 Thonicke et al. 2010. ! - + ! ARGUMENTS: real(r8), intent(in) :: moisture ! fuel moisture [m3/m3] real(r8), intent(in) :: MEF ! fuel moisture of extinction [m3/m3] - + ! LOCALS: real(r8) :: mw_weight ! relative fuel moisture/fuel moisture of extinction - - if (MEF < nearzero) then - ! this really should never happen - essentially this means fuel can never burn - ! but we are putting this here to avoid divide by zeros - MoistureCoefficient = 0.0_r8 - return - end if - + + if (MEF < nearzero) then + ! this really should never happen - essentially this means fuel can never burn + ! but we are putting this here to avoid divide by zeros + MoistureCoefficient = 0.0_r8 + return + end if + ! average values for litter pools (dead leaves, twigs, small and large branches), plus grass mw_weight = moisture/MEF - + ! MoistureCoefficient is unitless MoistureCoefficient = 1.0_r8 - (2.59_r8*mw_weight) + (5.11_r8*(mw_weight**2.0_r8)) - & - (3.52_r8*(mw_weight**3.0_r8)) - - if (MoistureCoefficient < nearzero) MoistureCoefficient = 0.0_r8 - - end function MoistureCoefficient - - !------------------------------------------------------------------------------------- + (3.52_r8*(mw_weight**3.0_r8)) + + if (MoistureCoefficient < nearzero) MoistureCoefficient = 0.0_r8 + + end function MoistureCoefficient + + !------------------------------------------------------------------------------------- - real(r8) function ReactionIntensity(fuel_loading, SAV, beta_ratio, moisture, MEF) + real(r8) function ReactionIntensity(fuel_loading, SAV, beta_ratio, moisture, MEF) ! ! DESCRIPTION: ! Calculates reaction intensity in kJ/m2/min - ! + ! ! Rate of energy release per unit area within the flaming front ! - + ! USES use SFParamsMod, only : SF_val_fuel_energy, SF_val_miner_damp - + ! ARGUMENTS: real(r8), intent(in) :: fuel_loading ! net fuel loading [kg/m2] real(r8), intent(in) :: SAV ! fuel surface area to volume ratio [/cm] real(r8), intent(in) :: beta_ratio ! ratio of packing ratio to optimum packing ratio [0-1] real(r8), intent(in) :: moisture ! fuel moisture [m3/m3] real(r8), intent(in) :: MEF ! fuel moisture of extinction [m3/m3] - + ! LOCALS: real(r8) :: max_reaction_vel ! maximum reaction velocity real(r8) :: opt_reaction_vel ! optimum reaction velocity real(r8) :: moist_coeff ! moisture dampening coefficient [0-1] - + ! calculate maximum reaction velocity [/min] max_reaction_vel = MaximumReactionVelocity(SAV) - + ! calculate optimum reacion velocity [/min] opt_reaction_vel = OptimumReactionVelocity(max_reaction_vel, SAV, beta_ratio) - + ! calculate moisture dampening coefficient [0-1] moist_coeff = MoistureCoefficient(moisture, MEF) - + ReactionIntensity = opt_reaction_vel*fuel_loading*SF_val_fuel_energy* & - moist_coeff*SF_val_miner_damp + moist_coeff*SF_val_miner_damp + + end function ReactionIntensity - end function ReactionIntensity - - !------------------------------------------------------------------------------------- - - real(r8) function HeatofPreignition(fuel_moisture) + !------------------------------------------------------------------------------------- + + real(r8) function HeatofPreignition(fuel_moisture) ! ! DESCRIPTION: ! Calculates heat of pre-ignition in kJ/kg ! - ! Heat of pre-ignition is the heat required to bring a unit weight of fuel to + ! Heat of pre-ignition is the heat required to bring a unit weight of fuel to ! ignition ! ! Equation A4 in Thonicke et al. 2010 ! Rothermel EQ12 = 250 Btu/lb + 1116 Btu/lb * average_moisture - ! conversion of Rothermel (1972) EQ12 in BTU/lb to current kJ/kg + ! conversion of Rothermel (1972) EQ12 in BTU/lb to current kJ/kg ! - + ! ARGUMENTS: real(r8), intent(in) :: fuel_moisture ! fuel moisture [m3/m3] - + ! CONTANTS: real(r8), parameter :: q_dry = 581.0_r8 ! heat of pre-ignition of dry fuels [kJ/kg] - + HeatofPreignition = q_dry + 2594.0_r8*fuel_moisture - end function HeatofPreignition + end function HeatofPreignition + + !------------------------------------------------------------------------------------- - !------------------------------------------------------------------------------------- - - real(r8) function EffectiveHeatingNumber(SAV) + real(r8) function EffectiveHeatingNumber(SAV) ! ! DESCRIPTION: ! Calculates effective heating number [unitless] @@ -232,22 +234,57 @@ real(r8) function EffectiveHeatingNumber(SAV) ! ARGUMENTS: real(r8), intent(in) :: SAV ! fuel surface area to volume ratio [/cm] - - if (SAV < nearzero) then - EffectiveHeatingNumber = 0.0_r8 + + if (SAV < nearzero) then + EffectiveHeatingNumber = 0.0_r8 else - EffectiveHeatingNumber = exp(-4.528_r8/SAV) + EffectiveHeatingNumber = exp(-4.528_r8/SAV) end if - - end function EffectiveHeatingNumber - !------------------------------------------------------------------------------------- - - real(r8) function WindFactor(wind_speed, beta_ratio, SAV) + end function EffectiveHeatingNumber + + !------------------------------------------------------------------------------------- + real(r8) function HeatSink(q_ig, eps, wf, mean_FBD, wf_dead, wf_live) + ! + ! DESCRIPTION + ! Calculate the total heat sink that are required to pre-heat the fuel bed + ! and ignite the fuels per unit volume [kJ m-3] + ! EQ 78 Rothermel 1972 + ! + ! ARGUMENTS + real(r8), intent(in) :: q_ig(num_fuel_classes) ! heat of pre-ignition per fuel class [kJ kg-1] + real(r8), intent(in) :: eps(num_fuel_classes) ! effective heating number per fue class [unitless] + real(r8), intent(in) :: wf(num_fuel_classes) ! weighting factor for each fuel class given SA:V [unitess] + real(r8), intent(in) :: mean_FBD ! weighted fuel bed bulk density [kg m-3] + real(r8), intent(in) :: wf_dead ! fractional total surface area contributed by dead fuels [unitless] + real(r8), intent(in) :: wf_live ! fractional total surface area contributed by live fuels [unitless] + ! + ! LOCALS + real(r8) :: sum_dead ! sum of the product of wf, q_ig, and effective heating number across dead fuel classes + real(r8) :: sum_live ! sum of the product of wf, q_ig, and effective heating number across live fuel classes + integer :: i ! looping index + sum_dead = 0.0_r8 + sum_live = 0.0_r8 + do i = 1, num_fuel_classes + if(i /= fuel_classes%live_grass())then + sum_dead = sum_dead + wf(i)*eps(i)*q_ig(i) + else + sum_live = sum_live + wf(i)*eps(i),q_ig(i) + end if + end do + HeatSink = mean_FBD * (wf_dead*sum_dead + wf_live*sum_live) + + + end function HeatSink + + + !------------------------------------------------------------------------------------- + + real(r8) function WindFactor(wind_speed, beta_ratio, SAV) ! ! DESCRIPTION: ! Calculates wind factor for the rate of spread equation [unitless] - ! + ! ! Accounts for effect of wind speed increasing ROS ! @@ -255,16 +292,16 @@ real(r8) function WindFactor(wind_speed, beta_ratio, SAV) real(r8), intent(in) :: wind_speed ! wind speed [m/min] real(r8), intent(in) :: beta_ratio ! relative packing ratio [unitless] real(r8), intent(in) :: SAV ! fuel surface area to volume ratio [/cm] - + ! LOCALS: real(r8) :: b, c, e ! temporary variables - + ! Equation A7 in Thonicke et al. 2010 per eqn 49 from Rothermel 1972 b = 0.15988_r8*(SAV**0.54_r8) - - ! Equation A8 in Thonicke et al. 2010 per eqn 48 from Rothermel 1972 + + ! Equation A8 in Thonicke et al. 2010 per eqn 48 from Rothermel 1972 c = 7.47_r8*(exp(-0.8711_r8*(SAV**0.55_r8))) - + ! Equation A9 in Thonicke et al. 2010 (appears to have typo, using coefficient Eq. 50 Rothermel 1972) e = 0.715_r8*(exp(-0.01094_r8*SAV)) @@ -272,67 +309,65 @@ real(r8) function WindFactor(wind_speed, beta_ratio, SAV) ! convert wind_speed (wind at elev relevant to fire) from m/min to ft/min for Rothermel ROS Eq. WindFactor = c*((3.281_r8*wind_speed)**b)*(beta_ratio**(-e)) - end function WindFactor - - !------------------------------------------------------------------------------------- - - real(r8) function PropagatingFlux(beta, SAV) + end function WindFactor + + !------------------------------------------------------------------------------------- + + real(r8) function PropagatingFlux(beta, SAV) ! ! DESCRIPTION: ! Calculates propagating flux ratio [unitless] - ! + ! ! Proportion of reaction intensity that heats adjacent fuel particles to ignition - ! + ! ! Equation A2 in Thonicke et al. 2010 and Eq. 42 Rothermel 1972 ! ! ARGUMENTS: real(r8), intent(in) :: beta ! packing ratio [unitless] real(r8), intent(in) :: SAV ! fuel surface area to volume ratio [/cm] - + PropagatingFlux = (exp((0.792_r8 + 3.7597_r8*(SAV**0.5_r8))*(beta + 0.1_r8)))/ & - (192.0_r8 + 7.9095_r8*SAV) + (192.0_r8 + 7.9095_r8*SAV) - end function PropagatingFlux - - !------------------------------------------------------------------------------------- - - real(r8) function ForwardRateOfSpread(bulk_density, eps, q_ig, i_r, xi, phi_wind) + end function PropagatingFlux + + !------------------------------------------------------------------------------------- + + real(r8) function ForwardRateOfSpread(heat_sink, i_r, xi, phi_wind) ! ! DESCRIPTION: ! Calculates forward rate of spread [m/min] - ! + ! ! Flaming front of a surface fire ! ! Equation 9. Thonicke et al. 2010 ! ! ARGUMENTS: - real(r8), intent(in) :: bulk_density ! fulk bulk density [kg/m3] - real(r8), intent(in) :: eps ! effective heating number [unitless] - real(r8), intent(in) :: q_ig ! heat of preignition [kJ/kg] + real(r8), intent(in) :: heat_sink ! total heat required to ignite fuel bed [kJ m-3] real(r8), intent(in) :: i_r ! reaction intensity [kJ/m2/min] - real(r8), intent(in) :: xi ! propagating flux [unitless] + real(r8), intent(in) :: xi ! propagating flux [unitless] real(r8), intent(in) :: phi_wind ! wind factor [unitless] - - if ((bulk_density <= nearzero) .or. (eps <= nearzero) .or. (q_ig <= nearzero)) then - ForwardRateOfSpread = 0.0_r8 + + if (heat_sink <= nearzero) then + ForwardRateOfSpread = 0.0_r8 else - ForwardRateOfSpread = (i_r*xi*(1.0_r8 + phi_wind))/(bulk_density*eps*q_ig) + ForwardRateOfSpread = (i_r*xi*(1.0_r8 + phi_wind))/heat_sink endif - end function ForwardRateOfSpread - - !------------------------------------------------------------------------------------- - - real(r8) function BackwardRateOfSpread(ros_front, wind_speed) + end function ForwardRateOfSpread + + !------------------------------------------------------------------------------------- + + real(r8) function BackwardRateOfSpread(ros_front, wind_speed) ! ! DESCRIPTION: ! Calculates backwards rate of spread [m/min] ! ! Equation 10 in Thonicke et al. 2010 ! backward ROS from Can FBP System (1992) - ! backward ROS wind not changed by vegetation + ! backward ROS wind not changed by vegetation ! ! ARGUMENTS: @@ -340,12 +375,12 @@ real(r8) function BackwardRateOfSpread(ros_front, wind_speed) real(r8), intent(in) :: wind_speed ! wind speed [m/min] BackwardRateOfSpread = ros_front*exp(-0.012_r8*wind_speed) - - end function BackwardRateOfSpread - !------------------------------------------------------------------------------------- - - real(r8) function FireDuration(FDI) + end function BackwardRateOfSpread + + !------------------------------------------------------------------------------------- + + real(r8) function FireDuration(FDI) ! ! DESCRIPTION: ! Calculates fire duration [min] @@ -358,16 +393,16 @@ real(r8) function FireDuration(FDI) real(r8), intent(in) :: FDI ! fire danger index [0-1] FireDuration = (SF_val_max_durat + 1.0_r8)/(1.0_r8 + SF_val_max_durat* & - exp(SF_val_durat_slope*FDI)) + exp(SF_val_durat_slope*FDI)) + + end function FireDuration - end function FireDuration + !------------------------------------------------------------------------------------- - !------------------------------------------------------------------------------------- - - real(r8) function LengthToBreadth(effective_windspeed, tree_fraction) + real(r8) function LengthToBreadth(effective_windspeed, tree_fraction) ! ! DESCRIPTION: - ! Calculates length to breadth ratio of fire ellipse [unitless], used for calculating area burnt + ! Calculates length to breadth ratio of fire ellipse [unitless], used for calculating area burnt ! ! Canadian Forest Fire Behavior Prediction System Ont.Int.Rep. ST-X-3, 1992 ! Information Report GLC-X-10, Wotten et al. 2009 @@ -377,30 +412,30 @@ real(r8) function LengthToBreadth(effective_windspeed, tree_fraction) ! ARGUMENTS: real(r8), intent(in) :: effective_windspeed ! effective windspeed [m/min] real(r8), intent(in) :: tree_fraction ! tree fraction [0-1] - + ! LOCALS: real(r8) :: windspeed_km_hr ! effective windspeed, converted to correct units [km/hr] - + ! CONSTANTS: real(r8), parameter :: lb_threshold = 0.55_r8 ! tree canopy fraction below which to use grassland length-to-breadth eqn windspeed_km_hr = effective_windspeed/m_per_km*min_per_hr - if (windspeed_km_hr < 1.0_r8) then - LengthToBreadth = 1.0_r8 + if (windspeed_km_hr < 1.0_r8) then + LengthToBreadth = 1.0_r8 else - if (tree_fraction > lb_threshold) then - LengthToBreadth = 1.0_r8 + 8.729_r8*((1.0_r8 - exp(-0.03_r8*windspeed_km_hr))**2.155_r8) - else - LengthToBreadth = 1.1_r8*(windspeed_km_hr**0.464_r8) - endif + if (tree_fraction > lb_threshold) then + LengthToBreadth = 1.0_r8 + 8.729_r8*((1.0_r8 - exp(-0.03_r8*windspeed_km_hr))**2.155_r8) + else + LengthToBreadth = 1.1_r8*(windspeed_km_hr**0.464_r8) + endif endif - end function LengthToBreadth + end function LengthToBreadth + + !------------------------------------------------------------------------------------- - !------------------------------------------------------------------------------------- - - real(r8) function FireSize(length_to_breadth, ros_back, ros_forward, fire_duration) + real(r8) function FireSize(length_to_breadth, ros_back, ros_forward, fire_duration) ! ! DESCRIPTION: ! Calculates fire size [m2] @@ -414,27 +449,27 @@ real(r8) function FireSize(length_to_breadth, ros_back, ros_forward, fire_durati real(r8), intent(in) :: ros_back ! backwards rate of spread [m/min] real(r8), intent(in) :: ros_forward ! forward rate of spread [m/min] real(r8), intent(in) :: fire_duration ! fire duration [min] - + ! LOCALS: real(r8) :: dist_back ! distance fire has travelled backwards [m] real(r8) :: dist_forward ! distance fire has travelled forward [m] real(r8) :: fire_size ! area of fire [m2] - + dist_back = ros_back*fire_duration dist_forward = ros_forward*fire_duration - + ! Eq 14 Arora and Boer JGR 2005 (area of an ellipse) - if (length_to_breadth < nearzero) then - FireSize = 0.0_r8 - else - FireSize = (pi_const/(4.0_r8*length_to_breadth))*((dist_forward + dist_back)**2.0_r8) + if (length_to_breadth < nearzero) then + FireSize = 0.0_r8 + else + FireSize = (pi_const/(4.0_r8*length_to_breadth))*((dist_forward + dist_back)**2.0_r8) end if - - end function FireSize - - !------------------------------------------------------------------------------------- - - real(r8) function AreaBurnt(fire_size, num_ignitions, FDI) + + end function FireSize + + !------------------------------------------------------------------------------------- + + real(r8) function AreaBurnt(fire_size, num_ignitions, FDI) ! ! DESCRIPTION: ! Calculates area burnt [m2/km2/day] @@ -442,11 +477,11 @@ real(r8) function AreaBurnt(fire_size, num_ignitions, FDI) ! daily area burnt = size fires in m2 * num ignitions per day per km2 * prob ignition starts fire ! Thonicke 2010 Eq. 1 ! - ! the denominator in the units of currentSite%NF is total gridcell area, but since we assume that ignitions + ! 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 AreaBurnt has units of m2 burned area per km2 patch area per day ! - ! TO DO: Connect here with the Li & Levis GDP fire suppression algorithm. + ! TO DO: Connect here with the Li & Levis GDP fire suppression algorithm. ! Equation 16 in arora and boer model JGR 2005 ! @@ -454,14 +489,14 @@ real(r8) function AreaBurnt(fire_size, num_ignitions, FDI) real(r8), intent(in) :: fire_size ! fire size [m2] real(r8), intent(in) :: num_ignitions ! number of ignitions [/km2/day] real(r8), intent(in) :: FDI ! fire danger index [0-1] - + AreaBurnt = fire_size*num_ignitions*FDI - end function AreaBurnt - - !------------------------------------------------------------------------------------- - - real(r8) function FireIntensity(fuel_consumed, ros) + end function AreaBurnt + + !------------------------------------------------------------------------------------- + + real(r8) function FireIntensity(fuel_consumed, ros) ! ! DESCRIPTION: ! Calculates fire intensity [kW/m] @@ -472,193 +507,193 @@ real(r8) function FireIntensity(fuel_consumed, ros) ! ARGUMENTS: real(r8), intent(in) :: fuel_consumed ! fuel consumed [kg/m2] real(r8), intent(in) :: ros ! rate of spread [m/s] - + FireIntensity = SF_val_fuel_energy*fuel_consumed*ros - end function FireIntensity - - !--------------------------------------------------------------------------------------- - - real(r8) function ScorchHeight(alpha_SH, FI) - ! - ! DESCRIPTION: - ! Calculates scorch height [m] - ! - ! Equation 16 in Thonicke et al. 2010 - ! Van Wagner 1973 Eq. 8; Byram (1959) - ! - - ! ARGUMENTS: - real(r8), intent(in) :: alpha_SH ! alpha parameter for scorch height equation - real(r8), intent(in) :: FI ! fire intensity [kW/m] - - if (FI < nearzero) then - ScorchHeight = 0.0_r8 - else - ScorchHeight = alpha_SH*(FI**0.667_r8) - end if - - end function ScorchHeight - - !--------------------------------------------------------------------------------------- - - real(r8) function CrownFractionBurnt(SH, height, crown_depth) - ! - ! DESCRIPTION: - ! Calculates fraction of the crown burnt of woody plants - ! Equation 17 in Thonicke et al. 2010 - ! - - ! ARGUMENTS: - real(r8), intent(in) :: SH ! scorch height [m] - real(r8), intent(in) :: height ! plant height [m] - real(r8), intent(in) :: crown_depth ! crown depth [m] - - if (crown_depth < nearzero) then - CrownFractionBurnt = 0.0_r8 - else - CrownFractionBurnt = (SH - height + crown_depth)/crown_depth - CrownFractionBurnt = min(1.0_r8, max(0.0_r8, CrownFractionBurnt)) - end if - - end function CrownFractionBurnt - - !--------------------------------------------------------------------------------------- - - real(r8) function BarkThickness(bark_scalar, dbh) - ! - ! DESCRIPTION: - ! Calculates bark thickness [cm] - ! Equation 21 in Thonicke et al 2010 - ! - - ! ARGUMENTS: - real(r8), intent(in) :: bark_scalar ! bark per dbh [cm/cm] - real(r8), intent(in) :: dbh ! diameter at breast height [cm] - - BarkThickness = bark_scalar*dbh - - if (BarkThickness < nearzero) then - call endrun(msg="bark thickness is negative", & - additional_msg=errMsg(sourcefile, __LINE__)) - end if - - end function BarkThickness - - !--------------------------------------------------------------------------------------- - - real(r8) function CriticalResidenceTime(bark_thickness) - ! - ! DESCRIPTION: - ! Calculates critical fire residence time for cambial damage [min] - ! Equation 19 in Thonicke et al. 2010 - ! - - ! ARGUMENTS: - real(r8), intent(in) :: bark_thickness ! bark thickness [cm] - - CriticalResidenceTime = 2.9_r8*bark_thickness**2.0_r8 - - end function CriticalResidenceTime - - !--------------------------------------------------------------------------------------- - - real(r8) function CambialMortality(bark_scalar, dbh, tau_l) - ! - ! DESCRIPTION: - ! Calculates rate of cambial damage mortality [0-1] - ! Equation 19 in Thonicke et al. 2010 - ! - - ! ARGUMENTS: - real(r8), intent(in) :: bark_scalar ! cm bark per cm dbh [cm/cm] - real(r8), intent(in) :: dbh ! diameter at breast height [cm] - real(r8), intent(in) :: tau_l ! residence time of fire [min] - - ! LOCALS: - real(r8) :: bark_thickness ! bark thickness [cm] - real(r8) :: tau_c ! critical fire residence time for cambial damage [min] - real(r8) :: tau_r ! relative fire residence time (actual / critical) - - ! calculate bark thickness based of bark scalar parameter and DBH - bark_thickness = BarkThickness(bark_scalar, dbh) - - ! calculate critical residence time for cambial damage [min] - tau_c = CriticalResidenceTime(bark_thickness) - - ! relative residence time - tau_r = tau_l/tau_c - - CambialMortality = cambial_mort(tau_r) - - end function CambialMortality - - !--------------------------------------------------------------------------------------- - - real(r8) function cambial_mort(tau_r) - ! - ! DESCRIPTION: - ! Helper function for CambialMortality - ! Calculates rate of cambial damage mortality [0-1] - ! Equation 19 in Thonicke et al. 2010 - ! - - ! ARGUMENTS: - real(r8), intent(in) :: tau_r ! relative residence time of fire - - if (tau_r >= 2.0_r8) then - cambial_mort = 1.0_r8 - else if (tau_r < 2.0_r8 .and. tau_r > 0.22_r8) then - cambial_mort = 0.563_r8*tau_r - 0.125_r8 - else - cambial_mort = 0.0_r8 - end if - - end function cambial_mort - - !--------------------------------------------------------------------------------------- - - real(r8) function CrownFireMortality(crown_kill, fraction_crown_burned) - ! - ! DESCRIPTION: - ! Calculates rate of mortality from crown scorching [0-1] - ! Equation 19 in Thonicke et al. 2010 - ! - - ! ARGUMENTS: - real(r8), intent(in) :: crown_kill ! parameter for crown kill cm bark per cm dbh [cm/cm] - real(r8), intent(in) :: fraction_crown_burned ! fraction of the crown burned [0-1] - - CrownFireMortality = crown_kill*fraction_crown_burned**3.0_r8 - if (CrownFireMortality > 1.0_r8) CrownFireMortality = 1.0_r8 - if (CrownFireMortality < nearzero) CrownFireMortality = 0.0_r8 - - end function CrownFireMortality - - !--------------------------------------------------------------------------------------- - - real(r8) function TotalFireMortality(crownfire_mort, cambial_damage_mort) - ! - ! DESCRIPTION: - ! Calculates rate of mortality from wildfire [0-1] - ! Equation 18 in Thonicke et al. 2010 - ! - - ! ARGUMENTS: - real(r8), intent(in) :: crownfire_mort ! mortality rate from crown scorching [0-1] - real(r8), intent(in) :: cambial_damage_mort ! mortality rate from cambial damage [0-1] - - if (crownfire_mort > 1.0_r8 .or. cambial_damage_mort > 1.0_r8) then - TotalFireMortality = 1.0_r8 - else - TotalFireMortality = crownfire_mort + cambial_damage_mort - (crownfire_mort*cambial_damage_mort) - end if - - if (TotalFireMortality > 1.0_r8) TotalFireMortality = 1.0_r8 - if (TotalFireMortality < nearzero) TotalFireMortality = 0.0_r8 - - end function TotalFireMortality - - !--------------------------------------------------------------------------------------- - + end function FireIntensity + + !--------------------------------------------------------------------------------------- + + real(r8) function ScorchHeight(alpha_SH, FI) + ! + ! DESCRIPTION: + ! Calculates scorch height [m] + ! + ! Equation 16 in Thonicke et al. 2010 + ! Van Wagner 1973 Eq. 8; Byram (1959) + ! + + ! ARGUMENTS: + real(r8), intent(in) :: alpha_SH ! alpha parameter for scorch height equation + real(r8), intent(in) :: FI ! fire intensity [kW/m] + + if (FI < nearzero) then + ScorchHeight = 0.0_r8 + else + ScorchHeight = alpha_SH*(FI**0.667_r8) + end if + + end function ScorchHeight + + !--------------------------------------------------------------------------------------- + + real(r8) function CrownFractionBurnt(SH, height, crown_depth) + ! + ! DESCRIPTION: + ! Calculates fraction of the crown burnt of woody plants + ! Equation 17 in Thonicke et al. 2010 + ! + + ! ARGUMENTS: + real(r8), intent(in) :: SH ! scorch height [m] + real(r8), intent(in) :: height ! plant height [m] + real(r8), intent(in) :: crown_depth ! crown depth [m] + + if (crown_depth < nearzero) then + CrownFractionBurnt = 0.0_r8 + else + CrownFractionBurnt = (SH - height + crown_depth)/crown_depth + CrownFractionBurnt = min(1.0_r8, max(0.0_r8, CrownFractionBurnt)) + end if + + end function CrownFractionBurnt + + !--------------------------------------------------------------------------------------- + + real(r8) function BarkThickness(bark_scalar, dbh) + ! + ! DESCRIPTION: + ! Calculates bark thickness [cm] + ! Equation 21 in Thonicke et al 2010 + ! + + ! ARGUMENTS: + real(r8), intent(in) :: bark_scalar ! bark per dbh [cm/cm] + real(r8), intent(in) :: dbh ! diameter at breast height [cm] + + BarkThickness = bark_scalar*dbh + + if (BarkThickness < nearzero) then + call endrun(msg="bark thickness is negative", & + additional_msg=errMsg(sourcefile, __LINE__)) + end if + + end function BarkThickness + + !--------------------------------------------------------------------------------------- + + real(r8) function CriticalResidenceTime(bark_thickness) + ! + ! DESCRIPTION: + ! Calculates critical fire residence time for cambial damage [min] + ! Equation 19 in Thonicke et al. 2010 + ! + + ! ARGUMENTS: + real(r8), intent(in) :: bark_thickness ! bark thickness [cm] + + CriticalResidenceTime = 2.9_r8*bark_thickness**2.0_r8 + + end function CriticalResidenceTime + + !--------------------------------------------------------------------------------------- + + real(r8) function CambialMortality(bark_scalar, dbh, tau_l) + ! + ! DESCRIPTION: + ! Calculates rate of cambial damage mortality [0-1] + ! Equation 19 in Thonicke et al. 2010 + ! + + ! ARGUMENTS: + real(r8), intent(in) :: bark_scalar ! cm bark per cm dbh [cm/cm] + real(r8), intent(in) :: dbh ! diameter at breast height [cm] + real(r8), intent(in) :: tau_l ! residence time of fire [min] + + ! LOCALS: + real(r8) :: bark_thickness ! bark thickness [cm] + real(r8) :: tau_c ! critical fire residence time for cambial damage [min] + real(r8) :: tau_r ! relative fire residence time (actual / critical) + + ! calculate bark thickness based of bark scalar parameter and DBH + bark_thickness = BarkThickness(bark_scalar, dbh) + + ! calculate critical residence time for cambial damage [min] + tau_c = CriticalResidenceTime(bark_thickness) + + ! relative residence time + tau_r = tau_l/tau_c + + CambialMortality = cambial_mort(tau_r) + + end function CambialMortality + + !--------------------------------------------------------------------------------------- + + real(r8) function cambial_mort(tau_r) + ! + ! DESCRIPTION: + ! Helper function for CambialMortality + ! Calculates rate of cambial damage mortality [0-1] + ! Equation 19 in Thonicke et al. 2010 + ! + + ! ARGUMENTS: + real(r8), intent(in) :: tau_r ! relative residence time of fire + + if (tau_r >= 2.0_r8) then + cambial_mort = 1.0_r8 + else if (tau_r < 2.0_r8 .and. tau_r > 0.22_r8) then + cambial_mort = 0.563_r8*tau_r - 0.125_r8 + else + cambial_mort = 0.0_r8 + end if + + end function cambial_mort + + !--------------------------------------------------------------------------------------- + + real(r8) function CrownFireMortality(crown_kill, fraction_crown_burned) + ! + ! DESCRIPTION: + ! Calculates rate of mortality from crown scorching [0-1] + ! Equation 19 in Thonicke et al. 2010 + ! + + ! ARGUMENTS: + real(r8), intent(in) :: crown_kill ! parameter for crown kill cm bark per cm dbh [cm/cm] + real(r8), intent(in) :: fraction_crown_burned ! fraction of the crown burned [0-1] + + CrownFireMortality = crown_kill*fraction_crown_burned**3.0_r8 + if (CrownFireMortality > 1.0_r8) CrownFireMortality = 1.0_r8 + if (CrownFireMortality < nearzero) CrownFireMortality = 0.0_r8 + + end function CrownFireMortality + + !--------------------------------------------------------------------------------------- + + real(r8) function TotalFireMortality(crownfire_mort, cambial_damage_mort) + ! + ! DESCRIPTION: + ! Calculates rate of mortality from wildfire [0-1] + ! Equation 18 in Thonicke et al. 2010 + ! + + ! ARGUMENTS: + real(r8), intent(in) :: crownfire_mort ! mortality rate from crown scorching [0-1] + real(r8), intent(in) :: cambial_damage_mort ! mortality rate from cambial damage [0-1] + + if (crownfire_mort > 1.0_r8 .or. cambial_damage_mort > 1.0_r8) then + TotalFireMortality = 1.0_r8 + else + TotalFireMortality = crownfire_mort + cambial_damage_mort - (crownfire_mort*cambial_damage_mort) + end if + + if (TotalFireMortality > 1.0_r8) TotalFireMortality = 1.0_r8 + if (TotalFireMortality < nearzero) TotalFireMortality = 0.0_r8 + + end function TotalFireMortality + + !--------------------------------------------------------------------------------------- + end module SFEquationsMod diff --git a/fire/SFMainMod.F90 b/fire/SFMainMod.F90 index 7e6de3323b..eda9bc528d 100644 --- a/fire/SFMainMod.F90 +++ b/fire/SFMainMod.F90 @@ -1,643 +1,661 @@ module SFMainMod - ! ============================================================================ - ! All subroutines related to the SPITFIRE fire routine. - ! Code originally developed by Allan Spessa & Rosie Fisher as part of the NERC-QUEST project. - ! ============================================================================ - - use FatesConstantsMod, only : r8 => fates_r8 - use FatesConstantsMod, only : itrue, ifalse - use FatesConstantsMod, only : pi_const - use FatesConstantsMod, only : nocomp_bareground, nearzero - use FatesGlobals, only : fates_log - use FatesGlobals , only : endrun => fates_endrun - use shr_log_mod , only : errMsg => shr_log_errMsg - use FatesInterfaceTypesMod, only : hlm_masterproc - use FatesInterfaceTypesMod, only : hlm_spitfire_mode - use FatesInterfaceTypesMod, only : hlm_sf_nofire_def - use FatesInterfaceTypesMod, only : hlm_sf_scalar_lightning_def - use FatesInterfaceTypesMod, only : hlm_sf_successful_ignitions_def - use FatesInterfaceTypesMod, only : hlm_sf_anthro_ignitions_def - use FatesInterfaceTypesMod, only : bc_in_type - use EDPftvarcon, only : EDPftvarcon_inst - use PRTParametersMod, only : prt_params - use PRTGenericMod, only : element_pos - use EDtypesMod, only : ed_site_type - use FatesPatchMod, only : fates_patch_type - use FatesCohortMod, only : fates_cohort_type - use EDtypesMod, only : AREA - use FatesLitterMod, only : litter_type - use FatesFuelClassesMod, only : num_fuel_classes - use PRTGenericMod, only : carbon12_element - use FatesInterfaceTypesMod, only : numpft - use FatesAllometryMod, only : CrownDepth - use FatesFuelClassesMod, only : fuel_classes - - implicit none - private - - public :: DailyFireModel - public :: UpdateFuelCharacteristics - - ! ====================================================================================== + ! ============================================================================ + ! All subroutines related to the SPITFIRE fire routine. + ! Code originally developed by Allan Spessa & Rosie Fisher as part of the NERC-QUEST project. + ! ============================================================================ + + use FatesConstantsMod, only : r8 => fates_r8 + use FatesConstantsMod, only : itrue, ifalse + use FatesConstantsMod, only : pi_const + use FatesConstantsMod, only : nocomp_bareground, nearzero + use FatesGlobals, only : fates_log + use FatesGlobals , only : endrun => fates_endrun + use shr_log_mod , only : errMsg => shr_log_errMsg + use FatesInterfaceTypesMod, only : hlm_masterproc + use FatesInterfaceTypesMod, only : hlm_spitfire_mode + use FatesInterfaceTypesMod, only : hlm_sf_nofire_def + use FatesInterfaceTypesMod, only : hlm_sf_scalar_lightning_def + use FatesInterfaceTypesMod, only : hlm_sf_successful_ignitions_def + use FatesInterfaceTypesMod, only : hlm_sf_anthro_ignitions_def + use FatesInterfaceTypesMod, only : bc_in_type + use EDPftvarcon, only : EDPftvarcon_inst + use PRTParametersMod, only : prt_params + use PRTGenericMod, only : element_pos + use EDtypesMod, only : ed_site_type + use FatesPatchMod, only : fates_patch_type + use FatesCohortMod, only : fates_cohort_type + use EDtypesMod, only : AREA + use FatesLitterMod, only : litter_type + use FatesFuelClassesMod, only : num_fuel_classes + use PRTGenericMod, only : carbon12_element + use FatesInterfaceTypesMod, only : numpft + use FatesAllometryMod, only : CrownDepth + use FatesFuelClassesMod, only : fuel_classes + + implicit none + private + + public :: DailyFireModel + public :: UpdateFuelCharacteristics + + ! ====================================================================================== contains - subroutine DailyFireModel(currentSite, bc_in) - ! - ! DESCRIPTION: - ! Runs the daily fire model - - ! ARGUMENTS: - type(ed_site_type), intent(inout), target :: currentSite ! site object - type(bc_in_type), intent(in) :: bc_in ! BC in object - - ! LOCALS: - type (fates_patch_type), pointer :: currentPatch ! patch object - - if (hlm_spitfire_mode > hlm_sf_nofire_def) then - call UpdateFireWeather(currentSite, bc_in) - call UpdateFuelCharacteristics(currentSite) - call CalculateIgnitionsandFDI(currentSite, bc_in) - call CalculateSurfaceRateOfSpread(currentSite) - call CalculateSurfaceFireIntensity(currentSite) - call CalculateAreaBurnt(currentSite) - call CalculateRxFireAreaBurnt(currentSite) - call CalculatePostFireMortality(currentSite) - end if - - end subroutine DailyFireModel - - !--------------------------------------------------------------------------------------- - - subroutine UpdateFireWeather(currentSite, bc_in) - ! - ! DESCRIPTION: - ! Updates the site's fire weather index, burn window for prescribed fire, and calculates effective windspeed based on - ! vegetation characteristics - ! - ! Currently we use tree and grass fraction averaged over whole grid (site) to - ! prevent extreme divergence - - use FatesConstantsMod, only : tfrz => t_water_freeze_k_1atm - use FatesConstantsMod, only : sec_per_day, sec_per_min - use EDTypesMod, only : CalculateTreeGrassAreaSite - use FatesInterfaceTypesMod, only : hlm_use_managed_fire - use SFParamsMod, only : SF_val_rxfire_tpup, SF_val_rxfire_tplw, SF_val_rxfire_rhup, & - SF_val_rxfire_rhlw, SF_val_rxfire_wdup, SF_val_rxfire_wdlw - - ! ARGUMENTS: - type(ed_site_type), intent(inout), target :: currentSite - type(bc_in_type), intent(in) :: bc_in - - ! LOCALS: - type(fates_patch_type), pointer :: currentPatch ! patch object - real(r8) :: temp_C ! daily averaged temperature [deg C] - real(r8) :: precip ! daily precip [mm/day] - real(r8) :: rh ! daily relative humidity [%] - real(r8) :: wind ! wind speed [m/s] - real(r8) :: tree_fraction ! site-level tree fraction [0-1] - real(r8) :: grass_fraction ! site-level grass fraction [0-1] - real(r8) :: bare_fraction ! site-level bare ground fraction [0-1] - integer :: iofp ! index of oldest the fates patch - - ! NOTE that the boundary conditions of temperature, precipitation and relative humidity - ! are available at the patch level. We are currently using a simplification where the whole site - ! is simply using the values associated with the first patch. - ! which probably won't have much impact, unless we decide to ever calculated fire weather for each 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 == nocomp_bareground) then - currentPatch => currentPatch%younger - endif - - iofp = currentPatch%patchno - temp_C = currentPatch%tveg24%GetMean() - tfrz - precip = bc_in%precip24_pa(iofp)*sec_per_day - rh = bc_in%relhumid24_pa(iofp) - wind = bc_in%wind24_pa(iofp) - - ! convert to m/min - currentSite%wind = wind*sec_per_min - - ! update fire weather index - call currentSite%fireWeather%UpdateIndex(temp_C, precip, rh, wind) - - ! update prescribed fire burn window - call currentSite%fireWeather%UpdateRxfireBurnWindow(hlm_use_managed_fire, temp_C, rh, wind, & - SF_val_rxfire_tpup, SF_val_rxfire_tplw, SF_val_rxfire_rhup, SF_val_rxfire_rhlw, & - SF_val_rxfire_wdup, SF_val_rxfire_wdlw) - - ! calculate site-level tree, grass, and bare fraction - call CalculateTreeGrassAreaSite(currentSite, tree_fraction, grass_fraction, bare_fraction) - - ! update effective wind speed - call currentSite%fireWeather%UpdateEffectiveWindSpeed(wind*sec_per_min, tree_fraction, & - grass_fraction, bare_fraction) - - end subroutine UpdateFireWeather - - !--------------------------------------------------------------------------------------- - - subroutine UpdateFuelCharacteristics(currentSite) - ! - ! DESCRIPTION: - ! Updates fuel characteristics on each patch of the site - ! - - use SFParamsMod, only : SF_val_drying_ratio, SF_val_SAV, SF_val_FBD - - ! ARGUMENTS: - type(ed_site_type), intent(in), target :: currentSite ! site object - - ! LOCALS: - type(fates_patch_type), pointer :: currentPatch ! FATES patch - type(litter_type), pointer :: litter ! pointer to patch litter class - real(r8) :: MEF_trunks, fuel_moisture_trunks - - currentPatch => currentSite%oldest_patch - do while(associated(currentPatch)) - - if (currentPatch%nocomp_pft_label /= nocomp_bareground) then - - ! calculate live grass [kgC/m2] - call currentPatch%UpdateLiveGrass() - - ! update fuel loading [kgC/m2] - litter => currentPatch%litter(element_pos(carbon12_element)) - call currentPatch%fuel%UpdateLoading(sum(litter%leaf_fines(:)), & - litter%ag_cwd(1), litter%ag_cwd(2), litter%ag_cwd(3), litter%ag_cwd(4), & - currentPatch%livegrass) - - ! sum up fuel classes and calculate fractional loading for each - call currentPatch%fuel%SumLoading() - call currentPatch%fuel%CalculateFractionalLoading() - - ! calculate fuel moisture [m3/m3] - call currentPatch%fuel%UpdateFuelMoisture(SF_val_SAV, SF_val_drying_ratio, & - currentSite%fireWeather) - - ! calculate geometric properties - call currentPatch%fuel%AverageBulkDensity_NoTrunks(SF_val_FBD) - call currentPatch%fuel%AverageSAV_NoTrunks(SF_val_SAV) - - end if - currentPatch => currentPatch%younger - end do - - end subroutine UpdateFuelCharacteristics - - !--------------------------------------------------------------------------------------- - - subroutine CalculateIgnitionsandFDI(currentSite, bc_in) - ! - ! DESCRIPTION: - ! Calculates ignitions and fire danger index (FDI) for a site - ! - - use FatesInterfaceTypesMod, only : hlm_spitfire_mode - use EDParamsMod, only : cg_strikes - use EDParamsMod, only : ED_val_nignitions - use SFParamsMod, only : SF_val_fdi_alpha - use FatesConstantsMod, only : years_per_day - - ! ARGUMENTS: - type(ed_site_type), intent(inout), target :: currentSite ! site object - type(bc_in_type), intent(in) :: bc_in ! BC in object - - ! LOCALS: - type(fates_patch_type), pointer :: currentPatch ! patch object - real(r8) :: cloud_to_ground_strikes ! fraction of cloud-to-ground strikes [0-1] - real(r8) :: anthro_ignitions ! anthropogenic ignitions [count/km2/day] - integer :: iofp ! patch index - - ! CONSTANTS: - real(r8), parameter :: igns_per_person_month = 0.0035_r8 ! potential human ignition counts (alpha in Li et al. 2012) (#/person/month) - real(r8), parameter :: approx_days_per_month = 30.0_r8 ! approximate days per month [days] - - ! initialize site parameters to zero - currentSite%NF_successful = 0.0_r8 - - ! Equation 7 from Venevsky et al GCB 2002 (modification of equation 8 in 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 - ! READING "SUCCESSFUL IGNITION" DATA - ! force ignition potential to be extreme - ! cloud_to_ground_strikes = 1 means using 100% of incoming observed ignitions - currentSite%FDI = 1.0_r8 - cloud_to_ground_strikes = 1.0_r8 - else - ! USING LIGHTNING STRIKE DATA - currentSite%FDI = 1.0_r8 - exp(-SF_val_fdi_alpha*currentSite%fireWeather%fire_weather_index) - cloud_to_ground_strikes = cg_strikes - end if - - ! 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) - currentPatch => currentSite%oldest_patch - if (currentPatch%nocomp_pft_label == nocomp_bareground)then - currentPatch => currentPatch%younger - endif - iofp = currentPatch%patchno - - ! NF = number of lighting strikes per day per km2 scaled by cloud to ground strikes - 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 - currentSite%NF = bc_in%lightning24(iofp)*cloud_to_ground_strikes - end if - - ! calculate anthropogenic ignitions according to Li et al. (2012) - ! add to ignitions by lightning - if (hlm_spitfire_mode == hlm_sf_anthro_ignitions_def) then - ! anthropogenic ignitions (count/km2/day) - ! = (ignitions/person/month)*6.8*population_density**0.43/approximate days per month - anthro_ignitions = igns_per_person_month*6.8_r8*bc_in%pop_density(iofp)**0.43_r8/approx_days_per_month - currentSite%NF = currentSite%NF + anthro_ignitions - end if - - end subroutine CalculateIgnitionsandFDI - - !--------------------------------------------------------------------------------------- - - subroutine CalculateSurfaceRateOfSpread(currentSite) - ! - ! DESCRIPTION: - ! Calculates potential rate of spread based on fuel characteristics for - ! each patch of a site - ! - - use SFParamsMod, only : SF_val_miner_total, SF_val_part_dens - use SFEquationsMod, only : OptimumPackingRatio, ReactionIntensity - use SFEquationsMod, only : HeatofPreignition, EffectiveHeatingNumber - use SFEquationsMod, only : WindFactor, PropagatingFlux - use SFEquationsMod, only : ForwardRateOfSpread, BackwardRateOfSpread - - ! ARGUMENTS: - type(ed_site_type), intent(in), target :: currentSite ! site object - - ! LOCALS: - type(fates_patch_type), pointer :: currentPatch ! patch object - real(r8) :: beta ! packing ratio [unitless] - real(r8) :: beta_op ! optimum packing ratio [unitless] - real(r8) :: beta_ratio ! relative packing ratio [unitless] - real(r8) :: i_r ! reaction intensity [kJ/m2/min] - real(r8) :: xi ! propagating flux ratio [unitless] - real(r8) :: eps ! effective heating number [unitless] - real(r8) :: phi_wind ! wind factor [unitless] - real(r8) :: q_ig ! heat of pre-ignition [kJ/kg] - - currentPatch => currentSite%oldest_patch - do while(associated(currentPatch)) - if (currentPatch%nocomp_pft_label /= nocomp_bareground .and. & - currentPatch%fuel%non_trunk_loading > nearzero) then - - ! fraction of fuel array volume occupied by fuel, i.e. compactness of fuel bed [unitless] - ! Rothermel 1972 Eq. 31 - beta = currentPatch%fuel%bulk_density_notrunks/SF_val_part_dens - - ! optimum packing ratio [unitless] - beta_op = OptimumPackingRatio(currentPatch%fuel%SAV_notrunks) - - ! relative packing ratio [unitless] - if (beta_op < nearzero) then - beta_ratio = 0.0_r8 - else - beta_ratio = beta/beta_op - end if - - ! remove mineral content from fuel load per Thonicke 2010 - currentPatch%fuel%non_trunk_loading = currentPatch%fuel%non_trunk_loading*(1.0_r8 - SF_val_miner_total) - - ! reaction intensity [kJ/m2/min] - i_r = ReactionIntensity(currentPatch%fuel%non_trunk_loading/0.45_r8, & - currentPatch%fuel%SAV_notrunks, beta_ratio, & - currentPatch%fuel%average_moisture_notrunks, currentPatch%fuel%MEF_notrunks) - - ! heat of preignition [kJ/kg] - q_ig = HeatofPreignition(currentPatch%fuel%average_moisture_notrunks) - - ! effective heating number [unitless] - eps = EffectiveHeatingNumber(currentPatch%fuel%SAV_notrunks) - - ! wind factor [unitless] - phi_wind = WindFactor(currentSite%fireWeather%effective_windspeed, beta_ratio, & - currentPatch%fuel%SAV_notrunks) - - ! propagating flux [unitless] - xi = PropagatingFlux(beta, currentPatch%fuel%SAV_notrunks) - - ! forward rate of spread [m/min] - currentPatch%ROS_front = ForwardRateOfSpread(currentPatch%fuel%bulk_density_notrunks, & - eps, q_ig, i_r, xi, phi_wind) - - ! backwards rate of spread [m/min] - ! backward ROS wind not changed by vegetation - so use wind, not effective_windspeed - currentPatch%ROS_back = BackwardRateOfSpread(currentPatch%ROS_front, & - currentSite%wind) - - end if - currentPatch => currentPatch%younger - end do - - end subroutine CalculateSurfaceRateOfSpread - - !--------------------------------------------------------------------------------------- - - subroutine CalculateSurfaceFireIntensity(currentSite) - ! - ! DESCRIPTION: - ! Calculates surface fireline intensity for each patch of a site - ! Use calculated fire intensity to determine if prescribed fire or - ! wildfire happens - ! - - use SFEquationsMod, only : FireIntensity - use SFParamsMod, only : SF_val_fire_threshold - use SFParamsMod, only : SF_val_rxfire_max_threshold, SF_val_rxfire_min_threshold - use SFParamsMod, only : SF_val_rxfire_fuel_max, SF_val_rxfire_fuel_min - use FatesRxFireMod, only : is_prescribed_burn - - ! ARGUMENTS: - type(ed_site_type), intent(inout), target :: currentSite - - ! LOCALS: - type(fates_patch_type), pointer :: currentPatch ! patch object - real(r8) :: fuel_consumed(num_fuel_classes) ! fuel consumed [kgC/m2] - logical :: is_rxfire ! is it a prescribed fire? - logical :: rxfire_fuel_check ! is fuel within thresholds for prescribed burn - logical :: fi_check ! is (potential) fire intensity high enough for fire to actually happen? - logical :: has_ignition ! is ignition greater than zero? - - currentPatch => currentSite%oldest_patch - do while (associated(currentPatch)) - - currentPatch%fuel%frac_burnt(:) = 0.0_r8 - - if (currentPatch%nocomp_pft_label /= nocomp_bareground) then - - call currentPatch%fuel%CalculateFuelBurnt(fuel_consumed) - call currentPatch%fuel%CalculateResidenceTime(currentPatch%tau_l) - - ! calculate overall fuel consumed by spreading fire - ! ignore 1000-hr fuels (i.e. trunks) - currentPatch%TFC_ROS = sum(fuel_consumed) - fuel_consumed(fuel_classes%trunks()) - - ! initialize patch parameters to zero - currentPatch%FI = 0.0_r8 ! either nonrx or rx FI - currentPatch%nonrx_fire = 0 ! only wildfire - currentPatch%rx_fire = 0 ! only rx fire - currentPatch%rx_FI = 0.0_r8 - currentPatch%nonrx_FI = 0.0_r8 - - has_ignition = currentSite%NF > 0.0_r8 - - if (has_ignition .or. currentSite%fireWeather%rx_flag == itrue) then - - ! fire intensity [kW/m] - currentPatch%FI = FireIntensity(currentPatch%TFC_ROS/0.45_r8, currentPatch%ROS_front/60.0_r8) - fi_check = currentPatch%FI > SF_val_fire_threshold - - ! check if prescribed fire can occur based on fuel load - rxfire_fuel_check = currentPatch%fuel%non_trunk_loading > SF_val_rxfire_fuel_min .and. & - currentPatch%fuel%non_trunk_loading < SF_val_rxfire_fuel_max - - if (currentSite%fireWeather%rx_flag == itrue .and. rxfire_fuel_check) then - - ! record burnable area after fuel load check - currentSite%rxfire_area_fuel = currentSite%rxfire_area_fuel + currentPatch%area - - ! determine fire type - ! prescribed fire and wildfire cannot happen on the same patch - is_rxfire = is_prescribed_burn(currentPatch%FI, currentSite%NF, & - SF_val_rxfire_min_threshold, SF_val_rxfire_max_threshold, SF_val_fire_threshold) - - if (is_rxfire) then - currentSite%rxfire_area_fi = currentSite%rxfire_area_fi + currentPatch%area ! record burnable area after FI check - currentPatch%rx_fire = 1 - - else if (has_ignition .and. fi_check) then ! (potential) intensity is greater than kW/m energy threshold - currentPatch%nonrx_fire = 1 - end if - - else if (has_ignition .and. fi_check) then ! not a patch suitable for conducting prescribed fire or rxfire is not even turned on, but (potential) intensity is greater than kW/m energy threshold - currentPatch%nonrx_fire = 1 - end if - - ! assign fire intensities and ignitions based on fire type - if (currentPatch%nonrx_fire == itrue) then - currentSite%NF_successful = currentSite%NF_successful + & - currentSite%NF*currentSite%FDI*currentPatch%area/area - currentPatch%nonrx_FI = currentPatch%FI - else if (currentPatch%rx_fire == itrue) then - currentPatch%rx_FI = currentPatch%FI - end if - end if + subroutine DailyFireModel(currentSite, bc_in) + ! + ! DESCRIPTION: + ! Runs the daily fire model + + ! ARGUMENTS: + type(ed_site_type), intent(inout), target :: currentSite ! site object + type(bc_in_type), intent(in) :: bc_in ! BC in object + + ! LOCALS: + type (fates_patch_type), pointer :: currentPatch ! patch object + + if (hlm_spitfire_mode > hlm_sf_nofire_def) then + call UpdateFireWeather(currentSite, bc_in) + call UpdateFuelCharacteristics(currentSite) + call CalculateIgnitionsandFDI(currentSite, bc_in) + call CalculateSurfaceRateOfSpread(currentSite) + call CalculateSurfaceFireIntensity(currentSite) + call CalculateAreaBurnt(currentSite) + call CalculateRxFireAreaBurnt(currentSite) + call CalculatePostFireMortality(currentSite) + end if + + end subroutine DailyFireModel + + !--------------------------------------------------------------------------------------- + + subroutine UpdateFireWeather(currentSite, bc_in) + ! + ! DESCRIPTION: + ! Updates the site's fire weather index, burn window for prescribed fire, and calculates effective windspeed based on + ! vegetation characteristics + ! + ! Currently we use tree and grass fraction averaged over whole grid (site) to + ! prevent extreme divergence + + use FatesConstantsMod, only : tfrz => t_water_freeze_k_1atm + use FatesConstantsMod, only : sec_per_day, sec_per_min + use EDTypesMod, only : CalculateTreeGrassAreaSite + use FatesInterfaceTypesMod, only : hlm_use_managed_fire + use SFParamsMod, only : SF_val_rxfire_tpup, SF_val_rxfire_tplw, SF_val_rxfire_rhup, & + SF_val_rxfire_rhlw, SF_val_rxfire_wdup, SF_val_rxfire_wdlw + + ! ARGUMENTS: + type(ed_site_type), intent(inout), target :: currentSite + type(bc_in_type), intent(in) :: bc_in + + ! LOCALS: + type(fates_patch_type), pointer :: currentPatch ! patch object + real(r8) :: temp_C ! daily averaged temperature [deg C] + real(r8) :: precip ! daily precip [mm/day] + real(r8) :: rh ! daily relative humidity [%] + real(r8) :: wind ! wind speed [m/s] + real(r8) :: tree_fraction ! site-level tree fraction [0-1] + real(r8) :: grass_fraction ! site-level grass fraction [0-1] + real(r8) :: bare_fraction ! site-level bare ground fraction [0-1] + integer :: iofp ! index of oldest the fates patch + + ! NOTE that the boundary conditions of temperature, precipitation and relative humidity + ! are available at the patch level. We are currently using a simplification where the whole site + ! is simply using the values associated with the first patch. + ! which probably won't have much impact, unless we decide to ever calculated fire weather for each 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 == nocomp_bareground) then + currentPatch => currentPatch%younger + endif + + iofp = currentPatch%patchno + temp_C = currentPatch%tveg24%GetMean() - tfrz + precip = bc_in%precip24_pa(iofp)*sec_per_day + rh = bc_in%relhumid24_pa(iofp) + wind = bc_in%wind24_pa(iofp) + + ! convert to m/min + currentSite%wind = wind*sec_per_min + + ! update fire weather index + call currentSite%fireWeather%UpdateIndex(temp_C, precip, rh, wind) + + ! update prescribed fire burn window + call currentSite%fireWeather%UpdateRxfireBurnWindow(hlm_use_managed_fire, temp_C, rh, wind, & + SF_val_rxfire_tpup, SF_val_rxfire_tplw, SF_val_rxfire_rhup, SF_val_rxfire_rhlw, & + SF_val_rxfire_wdup, SF_val_rxfire_wdlw) + + ! calculate site-level tree, grass, and bare fraction + call CalculateTreeGrassAreaSite(currentSite, tree_fraction, grass_fraction, bare_fraction) + + ! update effective wind speed + call currentSite%fireWeather%UpdateEffectiveWindSpeed(wind*sec_per_min, tree_fraction, & + grass_fraction, bare_fraction) + + end subroutine UpdateFireWeather + + !--------------------------------------------------------------------------------------- + + subroutine UpdateFuelCharacteristics(currentSite) + ! + ! DESCRIPTION: + ! Updates fuel characteristics on each patch of the site + ! + + use SFParamsMod, only : SF_val_drying_ratio, SF_val_SAV, SF_val_FBD + + ! ARGUMENTS: + type(ed_site_type), intent(in), target :: currentSite ! site object + + ! LOCALS: + type(fates_patch_type), pointer :: currentPatch ! FATES patch + type(litter_type), pointer :: litter ! pointer to patch litter class + real(r8) :: MEF_trunks, fuel_moisture_trunks + + currentPatch => currentSite%oldest_patch + do while(associated(currentPatch)) + + if (currentPatch%nocomp_pft_label /= nocomp_bareground) then + + ! calculate live grass [kgC/m2] + call currentPatch%UpdateLiveGrass() + + ! update fuel loading [kgC/m2] + litter => currentPatch%litter(element_pos(carbon12_element)) + call currentPatch%fuel%UpdateLoading(sum(litter%leaf_fines(:)), & + litter%ag_cwd(1), litter%ag_cwd(2), litter%ag_cwd(3), litter%ag_cwd(4), & + currentPatch%livegrass) + ! update weighting factors + call currentPatch%fuel%CalculateWeightingFactor(SF_val_SAV, SF_val_part_dens) + + ! sum up fuel classes and calculate fractional loading for each + call currentPatch%fuel%SumLoading() + call currentPatch%fuel%CalculateFractionalLoading() + + ! calculate fuel moisture [m3/m3] + call currentPatch%fuel%UpdateFuelMoisture(SF_val_SAV, SF_val_drying_ratio, & + currentSite%fireWeather) + + ! calculate geometric properties + call currentPatch%fuel%AverageBulkDensity(SF_val_FBD) + call currentPatch%fuel%AverageSAV(SF_val_SAV) + + end if + currentPatch => currentPatch%younger + end do + + end subroutine UpdateFuelCharacteristics + + !--------------------------------------------------------------------------------------- + + subroutine CalculateIgnitionsandFDI(currentSite, bc_in) + ! + ! DESCRIPTION: + ! Calculates ignitions and fire danger index (FDI) for a site + ! + + use FatesInterfaceTypesMod, only : hlm_spitfire_mode + use EDParamsMod, only : cg_strikes + use EDParamsMod, only : ED_val_nignitions + use SFParamsMod, only : SF_val_fdi_alpha + use FatesConstantsMod, only : years_per_day + + ! ARGUMENTS: + type(ed_site_type), intent(inout), target :: currentSite ! site object + type(bc_in_type), intent(in) :: bc_in ! BC in object + + ! LOCALS: + type(fates_patch_type), pointer :: currentPatch ! patch object + real(r8) :: cloud_to_ground_strikes ! fraction of cloud-to-ground strikes [0-1] + real(r8) :: anthro_ignitions ! anthropogenic ignitions [count/km2/day] + integer :: iofp ! patch index + + ! CONSTANTS: + real(r8), parameter :: igns_per_person_month = 0.0035_r8 ! potential human ignition counts (alpha in Li et al. 2012) (#/person/month) + real(r8), parameter :: approx_days_per_month = 30.0_r8 ! approximate days per month [days] + + ! initialize site parameters to zero + currentSite%NF_successful = 0.0_r8 + + ! Equation 7 from Venevsky et al GCB 2002 (modification of equation 8 in 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 + ! READING "SUCCESSFUL IGNITION" DATA + ! force ignition potential to be extreme + ! cloud_to_ground_strikes = 1 means using 100% of incoming observed ignitions + currentSite%FDI = 1.0_r8 + cloud_to_ground_strikes = 1.0_r8 + else + ! USING LIGHTNING STRIKE DATA + currentSite%FDI = 1.0_r8 - exp(-SF_val_fdi_alpha*currentSite%fireWeather%fire_weather_index) + cloud_to_ground_strikes = cg_strikes end if - currentPatch => currentPatch%younger - end do - - end subroutine CalculateSurfaceFireIntensity - - !--------------------------------------------------------------------------------------- - - subroutine CalculateAreaBurnt(currentSite) - ! - ! DESCRIPTION: - ! Calculates area burnt for each patch of a site - ! - use FatesConstantsMod, only : m2_per_km2 - use SFEquationsMod, only : FireDuration, LengthToBreadth - use SFEquationsMod, only : AreaBurnt, FireSize - - ! ARGUMENTS: - type(ed_site_type), intent(inout), target :: currentSite - - ! LOCALS: - type(fates_patch_type), pointer :: currentPatch ! patch object - real(r8) :: tree_fraction_patch ! treed fraction on patch [0-1] - real(r8) :: length_to_breadth ! length to breadth ratio of fire ellipse (unitless) - real(r8) :: fire_size ! size of fire [m2] - real(r8) :: area_burnt ! area burnt [m2/km2] - - ! CONSTANTS: - real(r8), parameter :: max_frac_burnt = 0.99_r8 ! maximum fraction burnt on patch - - currentPatch => currentSite%oldest_patch - do while (associated(currentPatch)) - - if (currentPatch%nocomp_pft_label /= nocomp_bareground) then - - ! initialize patch parameters to zero - currentPatch%FD = 0.0_r8 - currentPatch%nonrx_frac_burnt = 0.0_r8 - - if (currentPatch%nonrx_fire == 1) then - - ! fire duration [min] - currentPatch%FD = FireDuration(currentSite%FDI) - - ! length-to-breadth ratio of fire ellipse [unitless] - tree_fraction_patch = currentPatch%total_tree_area/currentPatch%area - length_to_breadth = LengthToBreadth(currentSite%fireWeather%effective_windspeed, tree_fraction_patch) - - ! fire size [m2] - fire_size = FireSize(length_to_breadth, currentPatch%ROS_back, & - currentPatch%ROS_front, currentPatch%FD) - - ! area burnt [m2/km2] - area_burnt = AreaBurnt(fire_size, currentSite%NF, currentSite%FDI) - - ! convert to area burned per area patch per day - ! i.e., fraction of the patch burned on that day - currentPatch%nonrx_frac_burnt = min(max_frac_burnt, area_burnt/m2_per_km2) - - end if + + ! 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) + currentPatch => currentSite%oldest_patch + if (currentPatch%nocomp_pft_label == nocomp_bareground)then + currentPatch => currentPatch%younger + endif + iofp = currentPatch%patchno + + ! NF = number of lighting strikes per day per km2 scaled by cloud to ground strikes + 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 + currentSite%NF = bc_in%lightning24(iofp)*cloud_to_ground_strikes end if - currentPatch => currentPatch%younger - end do - - end subroutine CalculateAreaBurnt - - !--------------------------------------------------------------------------------------- - - subroutine CalculateRxFireAreaBurnt (currentSite) - ! - ! DESCRIPTION: - ! Returns burned fraction for prescribed fire per patch by first checking - ! if total burnable fraction at site level is greater than user defined fraction of site area - ! if yes, calculate burned fraction as (user defined frac / total burnable frac) - ! - use SFParamsMod, only : SF_val_rxfire_AB ! user defined prescribed fire area in fraction per day to reflect burning capacity - use SFParamsMod, only : SF_val_rxfire_min_frac ! minimum fraction of land needs to be burnable for conducting prescribed fire - - ! ARGUMENTS - type(ed_site_type), intent(inout), target :: currentSite - - ! LOCALS - type(fates_patch_type), pointer :: currentPatch - real(r8) :: total_burnable_frac ! total fractional land area that can apply prescribed fire after condition checks at site level - - ! initialize site variables - currentSite%rxfire_area_final = 0.0_r8 - total_burnable_frac = 0.0_r8 - - ! update total burnable fraction - total_burnable_frac = currentSite%rxfire_area_fi/AREA - - currentPatch => currentSite%oldest_patch - - do while (associated(currentPatch)) - if (currentPatch%nocomp_pft_label /= nocomp_bareground) then - currentPatch%fire = 0 ! fire, either rx or non-rx - currentPatch%frac_burnt = 0.0_r8 ! rx_frac_burnt + nonrx_frac_burnt - currentPatch%rx_frac_burnt = 0.0_r8 - if (currentPatch%rx_fire == itrue .and. & - total_burnable_frac >= SF_val_rxfire_min_frac ) then - currentSite%rxfire_area_final = currentSite%rxfire_area_final + currentPatch%area ! the final burned total land area - currentPatch%rx_frac_burnt = min(0.99_r8, SF_val_rxfire_AB/total_burnable_frac) - else - currentPatch%rx_fire = 0 ! update rxfire occurence at patch - currentPatch%rx_FI = 0.0_r8 - end if - - ! update patch level fire occurence and total frac burnt - currentPatch%fire = currentPatch%nonrx_fire + currentPatch%rx_fire - currentPatch%frac_burnt = currentPatch%nonrx_frac_burnt + currentPatch%rx_frac_burnt - - ! currentPatch%fire cannot be >1, which indicates both rx and wildfire are happening - ! we currently do not allow this to happen on the same patch yet - if (currentPatch%fire > 1) then - write(fates_log(),*) 'Both wildfire and management fire are happening at same patch' - write(fates_log(),*) 'rxfire =', currentPatch%rx_fire - write(fates_log(),*) 'wildfire =', currentPatch%nonrx_fire - call endrun(msg=errMsg(__FILE__, __LINE__)) - end if + + ! calculate anthropogenic ignitions according to Li et al. (2012) + ! add to ignitions by lightning + if (hlm_spitfire_mode == hlm_sf_anthro_ignitions_def) then + ! anthropogenic ignitions (count/km2/day) + ! = (ignitions/person/month)*6.8*population_density**0.43/approximate days per month + anthro_ignitions = igns_per_person_month*6.8_r8*bc_in%pop_density(iofp)**0.43_r8/approx_days_per_month + currentSite%NF = currentSite%NF + anthro_ignitions end if - currentPatch => currentPatch%younger - end do - - end subroutine CalculateRxFireAreaBurnt - - !--------------------------------------------------------------------------------------- - - subroutine CalculatePostFireMortality(currentSite) - ! - ! DESCRIPTION: - ! Calculates mortality (for woody PFTs) due to fire from crown scorching and cambial damage - ! - use SFEquationsMod, only : ScorchHeight, CrownFireMortality, CrownFractionBurnt - use SFEquationsMod, only : CambialMortality, TotalFireMortality - - ! ARGUMENTS: - type(ed_site_type), intent(in), target :: currentSite ! site object - - ! LOCALS: - type(fates_patch_type), pointer :: currentPatch ! patch object - type(fates_cohort_type), pointer :: currentCohort ! cohort object - real(r8) :: crown_depth ! crown depth [m] - integer :: i_pft ! looping index - - currentPatch => currentSite%oldest_patch - do while (associated(currentPatch)) - if (currentPatch%nocomp_pft_label /= nocomp_bareground) then - if (currentPatch%fire == 1) then - - ! calculate scorch height [m] - do i_pft = 1, numpft - if (prt_params%woody(i_pft) == itrue) then - currentPatch%Scorch_ht(i_pft) = ScorchHeight(EDPftvarcon_inst%fire_alpha_SH(i_pft), & - currentPatch%FI) + + end subroutine CalculateIgnitionsandFDI + + !--------------------------------------------------------------------------------------- + + subroutine CalculateSurfaceRateOfSpread(currentSite) + ! + ! DESCRIPTION: + ! Calculates potential rate of spread based on fuel characteristics for + ! each patch of a site + ! + + use SFParamsMod, only : SF_val_miner_total, SF_val_part_dens, SF_val_SAV + use SFEquationsMod, only : OptimumPackingRatio, ReactionIntensity + use SFEquationsMod, only : HeatofPreignition, EffectiveHeatingNumber + use SFEquationsMod, only : WindFactor, HeatSink, PropagatingFlux + use SFEquationsMod, only : ForwardRateOfSpread, BackwardRateOfSpread + + ! ARGUMENTS: + type(ed_site_type), intent(in), target :: currentSite ! site object + + ! LOCALS: + type(fates_patch_type), pointer :: currentPatch ! patch object + real(r8) :: beta ! packing ratio [unitless] + real(r8) :: beta_op ! optimum packing ratio [unitless] + real(r8) :: beta_ratio ! relative packing ratio [unitless] + real(r8) :: IR_dead ! reaction intensity of dead fuels [kJ m-2 min-1] + real(r8) :: IR_live ! reaction intensity of live fuels [kJ m-2 min-1] + real(r8) :: i_r ! summed reaction intensity of dead and live fuels [kJ/m2/min] + real(r8) :: xi ! propagating flux ratio [unitless] + real(r8) :: heat_sink ! total heat required to ignite per unit volume fuel bed [kJ m-3] + real(r8) :: eps(num_fuel_classes) ! effective heating number by fuel class [unitless] + real(r8) :: phi_wind ! wind factor [unitless] + real(r8) :: q_ig(num_fuel_classes) ! heat of pre-ignition by fuel class [kJ/kg] + integer :: i ! looping index + + currentPatch => currentSite%oldest_patch + do while(associated(currentPatch)) + if (currentPatch%nocomp_pft_label /= nocomp_bareground .and. & + currentPatch%fuel%non_trunk_loading > nearzero) then + + ! fraction of fuel array volume occupied by fuel, i.e. compactness of fuel bed [unitless] + ! Rothermel 1972 Eq. 31 + beta = currentPatch%fuel%bulk_density_weighted/SF_val_part_dens + + ! optimum packing ratio [unitless] + beta_op = OptimumPackingRatio(currentPatch%fuel%SAV_weighted) + + ! relative packing ratio [unitless] + if (beta_op < nearzero) then + beta_ratio = 0.0_r8 else - currentPatch%Scorch_ht(i_pft) = 0.0_r8 + beta_ratio = beta/beta_op + end if + + ! remove mineral content from fuel load per Thonicke 2010 + currentPatch%fuel%non_trunk_loading = currentPatch%fuel%non_trunk_loading*(1.0_r8 - SF_val_miner_total) + currentPatch%fuel%weighted_loading_dead = currentPatch%fuel%weighted_loading_dead*(1.0_r8 - SF_val_miner_total) + currentPatch%fuel%weighted_loading_live = currentPatch%fuel%weighted_loading_live*(1.0_r8 - SF_val_miner_total) + + ! reaction intensity [kJ/m2/min] + IR_dead = ReactionIntensity(currentPatch%fuel%weighted_loading_dead/0.45_r8, & + currentPatch%fuel%SAV_weighted, beta_ratio, & + currentPatch%fuel%average_moisture_dead, currentPatch%fuel%MEF_dead) + + IR_live = ReactionIntensity(currentPatch%fuel%weighted_loading_live/0.45_r8, & + currentPatch%fuel%SAV_weighted, beta_ratio, & + currentPatch%fuel%average_moisture_live, currentPatch%fuel%MEF_live) + i_r = IR_dead + IR_live + + do i = 1, num_fuel_classes + ! heat of preignition per fuel class [kJ/kg] + q_ig(i) = HeatofPreignition(currentPatch%fuel%moisture(i)) + + ! effective heating number per fuel class [unitless] + eps(i) = EffectiveHeatingNumber(SF_val_SAV(i)) + end do + ! total heat required to ignite per unit fuel bed + heat_sink = HeatSink(q_ig, eps, currentPatch%fuel%weighting_factor, & + currentPatch%fuel%bulk_density_weighted, currentPatch%fuel%wf_dead, & + currentPatch%fuel%wf_live) + + ! wind factor [unitless] + phi_wind = WindFactor(currentSite%fireWeather%effective_windspeed, beta_ratio, & + currentPatch%fuel%SAV_weighted) + + ! propagating flux [unitless] + xi = PropagatingFlux(beta, currentPatch%fuel%SAV_weighted) + + ! forward rate of spread [m/min] + currentPatch%ROS_front = ForwardRateOfSpread(heat_sink, i_r, xi, phi_wind) + + ! backwards rate of spread [m/min] + ! backward ROS wind not changed by vegetation - so use wind, not effective_windspeed + currentPatch%ROS_back = BackwardRateOfSpread(currentPatch%ROS_front, & + currentSite%wind) + + end if + currentPatch => currentPatch%younger + end do + + end subroutine CalculateSurfaceRateOfSpread + + !--------------------------------------------------------------------------------------- + + subroutine CalculateSurfaceFireIntensity(currentSite) + ! + ! DESCRIPTION: + ! Calculates surface fireline intensity for each patch of a site + ! Use calculated fire intensity to determine if prescribed fire or + ! wildfire happens + ! + + use SFEquationsMod, only : FireIntensity + use SFParamsMod, only : SF_val_fire_threshold + use SFParamsMod, only : SF_val_rxfire_max_threshold, SF_val_rxfire_min_threshold + use SFParamsMod, only : SF_val_rxfire_fuel_max, SF_val_rxfire_fuel_min + use FatesRxFireMod, only : is_prescribed_burn + + ! ARGUMENTS: + type(ed_site_type), intent(inout), target :: currentSite + + ! LOCALS: + type(fates_patch_type), pointer :: currentPatch ! patch object + real(r8) :: fuel_consumed(num_fuel_classes) ! fuel consumed [kgC/m2] + logical :: is_rxfire ! is it a prescribed fire? + logical :: rxfire_fuel_check ! is fuel within thresholds for prescribed burn + logical :: fi_check ! is (potential) fire intensity high enough for fire to actually happen? + logical :: has_ignition ! is ignition greater than zero? + + currentPatch => currentSite%oldest_patch + do while (associated(currentPatch)) + + currentPatch%fuel%frac_burnt(:) = 0.0_r8 + + if (currentPatch%nocomp_pft_label /= nocomp_bareground) then + + call currentPatch%fuel%CalculateFuelBurnt(fuel_consumed) + call currentPatch%fuel%CalculateResidenceTime(currentPatch%tau_l) + + ! calculate overall fuel consumed by spreading fire + ! ignore 1000-hr fuels (i.e. trunks) + currentPatch%TFC_ROS = sum(fuel_consumed) - fuel_consumed(fuel_classes%trunks()) + + ! initialize patch parameters to zero + currentPatch%FI = 0.0_r8 ! either nonrx or rx FI + currentPatch%nonrx_fire = 0 ! only wildfire + currentPatch%rx_fire = 0 ! only rx fire + currentPatch%rx_FI = 0.0_r8 + currentPatch%nonrx_FI = 0.0_r8 + + has_ignition = currentSite%NF > 0.0_r8 + + if (has_ignition .or. currentSite%fireWeather%rx_flag == itrue) then + + ! fire intensity [kW/m] + currentPatch%FI = FireIntensity(currentPatch%TFC_ROS/0.45_r8, currentPatch%ROS_front/60.0_r8) + fi_check = currentPatch%FI > SF_val_fire_threshold + + ! check if prescribed fire can occur based on fuel load + rxfire_fuel_check = currentPatch%fuel%non_trunk_loading > SF_val_rxfire_fuel_min .and. & + currentPatch%fuel%non_trunk_loading < SF_val_rxfire_fuel_max + + if (currentSite%fireWeather%rx_flag == itrue .and. rxfire_fuel_check) then + + ! record burnable area after fuel load check + currentSite%rxfire_area_fuel = currentSite%rxfire_area_fuel + currentPatch%area + + ! determine fire type + ! prescribed fire and wildfire cannot happen on the same patch + is_rxfire = is_prescribed_burn(currentPatch%FI, currentSite%NF, & + SF_val_rxfire_min_threshold, SF_val_rxfire_max_threshold, SF_val_fire_threshold) + + if (is_rxfire) then + currentSite%rxfire_area_fi = currentSite%rxfire_area_fi + currentPatch%area ! record burnable area after FI check + currentPatch%rx_fire = 1 + + else if (has_ignition .and. fi_check) then ! (potential) intensity is greater than kW/m energy threshold + currentPatch%nonrx_fire = 1 + end if + + else if (has_ignition .and. fi_check) then ! not a patch suitable for conducting prescribed fire or rxfire is not even turned on, but (potential) intensity is greater than kW/m energy threshold + currentPatch%nonrx_fire = 1 + end if + + ! assign fire intensities and ignitions based on fire type + if (currentPatch%nonrx_fire == itrue) then + currentSite%NF_successful = currentSite%NF_successful + & + currentSite%NF*currentSite%FDI*currentPatch%area/area + currentPatch%nonrx_FI = currentPatch%FI + else if (currentPatch%rx_fire == itrue) then + currentPatch%rx_FI = currentPatch%FI + end if end if - end do - - ! calculate fire-related mortality - currentCohort => currentPatch%tallest - do while (associated(currentCohort)) - - currentCohort%fraction_crown_burned = 0.0_r8 - currentCohort%fire_mort = 0.0_r8 - currentCohort%crownfire_mort = 0.0_r8 - currentCohort%cambial_mort = 0.0_r8 - - if (prt_params%woody(currentCohort%pft) == itrue) then - - ! calculate crown fraction burned [0-1] - call CrownDepth(currentCohort%height, currentCohort%pft, crown_depth) - currentCohort%fraction_crown_burned = CrownFractionBurnt(currentPatch%Scorch_ht(currentCohort%pft), & - currentCohort%height, crown_depth) - - ! shrink canopy to account for burnt section - ! currentCohort%canopy_trim = min(currentCohort%canopy_trim, 1.0_r8 - currentCohort%fraction_crown_burned) - - ! calculate cambial mortality rate [0-1] - currentCohort%cambial_mort = CambialMortality(EDPftvarcon_inst%bark_scaler(currentCohort%pft), & - currentCohort%dbh, currentPatch%tau_l) - - ! calculate crown fire mortality [0-1] - currentCohort%crownfire_mort = CrownFireMortality(EDPftvarcon_inst%crown_kill(currentCohort%pft), & - currentCohort%fraction_crown_burned) - - ! total fire mortality [0-1] - currentCohort%fire_mort = TotalFireMortality(currentCohort%crownfire_mort, & - currentCohort%cambial_mort) - - end if - currentCohort => currentCohort%shorter - end do - end if - end if - currentPatch => currentPatch%younger - end do - - end subroutine CalculatePostFireMortality - - !--------------------------------------------------------------------------------------- - + end if + currentPatch => currentPatch%younger + end do + + end subroutine CalculateSurfaceFireIntensity + + !--------------------------------------------------------------------------------------- + + subroutine CalculateAreaBurnt(currentSite) + ! + ! DESCRIPTION: + ! Calculates area burnt for each patch of a site + ! + use FatesConstantsMod, only : m2_per_km2 + use SFEquationsMod, only : FireDuration, LengthToBreadth + use SFEquationsMod, only : AreaBurnt, FireSize + + ! ARGUMENTS: + type(ed_site_type), intent(inout), target :: currentSite + + ! LOCALS: + type(fates_patch_type), pointer :: currentPatch ! patch object + real(r8) :: tree_fraction_patch ! treed fraction on patch [0-1] + real(r8) :: length_to_breadth ! length to breadth ratio of fire ellipse (unitless) + real(r8) :: fire_size ! size of fire [m2] + real(r8) :: area_burnt ! area burnt [m2/km2] + + ! CONSTANTS: + real(r8), parameter :: max_frac_burnt = 0.99_r8 ! maximum fraction burnt on patch + + currentPatch => currentSite%oldest_patch + do while (associated(currentPatch)) + + if (currentPatch%nocomp_pft_label /= nocomp_bareground) then + + ! initialize patch parameters to zero + currentPatch%FD = 0.0_r8 + currentPatch%nonrx_frac_burnt = 0.0_r8 + + if (currentPatch%nonrx_fire == 1) then + + ! fire duration [min] + currentPatch%FD = FireDuration(currentSite%FDI) + + ! length-to-breadth ratio of fire ellipse [unitless] + tree_fraction_patch = currentPatch%total_tree_area/currentPatch%area + length_to_breadth = LengthToBreadth(currentSite%fireWeather%effective_windspeed, tree_fraction_patch) + + ! fire size [m2] + fire_size = FireSize(length_to_breadth, currentPatch%ROS_back, & + currentPatch%ROS_front, currentPatch%FD) + + ! area burnt [m2/km2] + area_burnt = AreaBurnt(fire_size, currentSite%NF, currentSite%FDI) + + ! convert to area burned per area patch per day + ! i.e., fraction of the patch burned on that day + currentPatch%nonrx_frac_burnt = min(max_frac_burnt, area_burnt/m2_per_km2) + + end if + end if + currentPatch => currentPatch%younger + end do + + end subroutine CalculateAreaBurnt + + !--------------------------------------------------------------------------------------- + + subroutine CalculateRxFireAreaBurnt (currentSite) + ! + ! DESCRIPTION: + ! Returns burned fraction for prescribed fire per patch by first checking + ! if total burnable fraction at site level is greater than user defined fraction of site area + ! if yes, calculate burned fraction as (user defined frac / total burnable frac) + ! + use SFParamsMod, only : SF_val_rxfire_AB ! user defined prescribed fire area in fraction per day to reflect burning capacity + use SFParamsMod, only : SF_val_rxfire_min_frac ! minimum fraction of land needs to be burnable for conducting prescribed fire + + ! ARGUMENTS + type(ed_site_type), intent(inout), target :: currentSite + + ! LOCALS + type(fates_patch_type), pointer :: currentPatch + real(r8) :: total_burnable_frac ! total fractional land area that can apply prescribed fire after condition checks at site level + + ! initialize site variables + currentSite%rxfire_area_final = 0.0_r8 + total_burnable_frac = 0.0_r8 + + ! update total burnable fraction + total_burnable_frac = currentSite%rxfire_area_fi/AREA + + currentPatch => currentSite%oldest_patch + + do while (associated(currentPatch)) + if (currentPatch%nocomp_pft_label /= nocomp_bareground) then + currentPatch%fire = 0 ! fire, either rx or non-rx + currentPatch%frac_burnt = 0.0_r8 ! rx_frac_burnt + nonrx_frac_burnt + currentPatch%rx_frac_burnt = 0.0_r8 + if (currentPatch%rx_fire == itrue .and. & + total_burnable_frac >= SF_val_rxfire_min_frac ) then + currentSite%rxfire_area_final = currentSite%rxfire_area_final + currentPatch%area ! the final burned total land area + currentPatch%rx_frac_burnt = min(0.99_r8, SF_val_rxfire_AB/total_burnable_frac) + else + currentPatch%rx_fire = 0 ! update rxfire occurence at patch + currentPatch%rx_FI = 0.0_r8 + end if + + ! update patch level fire occurence and total frac burnt + currentPatch%fire = currentPatch%nonrx_fire + currentPatch%rx_fire + currentPatch%frac_burnt = currentPatch%nonrx_frac_burnt + currentPatch%rx_frac_burnt + + ! currentPatch%fire cannot be >1, which indicates both rx and wildfire are happening + ! we currently do not allow this to happen on the same patch yet + if (currentPatch%fire > 1) then + write(fates_log(),*) 'Both wildfire and management fire are happening at same patch' + write(fates_log(),*) 'rxfire =', currentPatch%rx_fire + write(fates_log(),*) 'wildfire =', currentPatch%nonrx_fire + call endrun(msg=errMsg(__FILE__, __LINE__)) + end if + end if + currentPatch => currentPatch%younger + end do + + end subroutine CalculateRxFireAreaBurnt + + !--------------------------------------------------------------------------------------- + + subroutine CalculatePostFireMortality(currentSite) + ! + ! DESCRIPTION: + ! Calculates mortality (for woody PFTs) due to fire from crown scorching and cambial damage + ! + use SFEquationsMod, only : ScorchHeight, CrownFireMortality, CrownFractionBurnt + use SFEquationsMod, only : CambialMortality, TotalFireMortality + + ! ARGUMENTS: + type(ed_site_type), intent(in), target :: currentSite ! site object + + ! LOCALS: + type(fates_patch_type), pointer :: currentPatch ! patch object + type(fates_cohort_type), pointer :: currentCohort ! cohort object + real(r8) :: crown_depth ! crown depth [m] + integer :: i_pft ! looping index + + currentPatch => currentSite%oldest_patch + do while (associated(currentPatch)) + if (currentPatch%nocomp_pft_label /= nocomp_bareground) then + if (currentPatch%fire == 1) then + + ! calculate scorch height [m] + do i_pft = 1, numpft + if (prt_params%woody(i_pft) == itrue) then + currentPatch%Scorch_ht(i_pft) = ScorchHeight(EDPftvarcon_inst%fire_alpha_SH(i_pft), & + currentPatch%FI) + else + currentPatch%Scorch_ht(i_pft) = 0.0_r8 + end if + end do + + ! calculate fire-related mortality + currentCohort => currentPatch%tallest + do while (associated(currentCohort)) + + currentCohort%fraction_crown_burned = 0.0_r8 + currentCohort%fire_mort = 0.0_r8 + currentCohort%crownfire_mort = 0.0_r8 + currentCohort%cambial_mort = 0.0_r8 + + if (prt_params%woody(currentCohort%pft) == itrue) then + + ! calculate crown fraction burned [0-1] + call CrownDepth(currentCohort%height, currentCohort%pft, crown_depth) + currentCohort%fraction_crown_burned = CrownFractionBurnt(currentPatch%Scorch_ht(currentCohort%pft), & + currentCohort%height, crown_depth) + + ! shrink canopy to account for burnt section + ! currentCohort%canopy_trim = min(currentCohort%canopy_trim, 1.0_r8 - currentCohort%fraction_crown_burned) + + ! calculate cambial mortality rate [0-1] + currentCohort%cambial_mort = CambialMortality(EDPftvarcon_inst%bark_scaler(currentCohort%pft), & + currentCohort%dbh, currentPatch%tau_l) + + ! calculate crown fire mortality [0-1] + currentCohort%crownfire_mort = CrownFireMortality(EDPftvarcon_inst%crown_kill(currentCohort%pft), & + currentCohort%fraction_crown_burned) + + ! total fire mortality [0-1] + currentCohort%fire_mort = TotalFireMortality(currentCohort%crownfire_mort, & + currentCohort%cambial_mort) + + end if + currentCohort => currentCohort%shorter + end do + end if + end if + currentPatch => currentPatch%younger + end do + + end subroutine CalculatePostFireMortality + + !--------------------------------------------------------------------------------------- + end module SFMainMod From 694c8782d67323dbcb3ffdd065b0bfffcf88a08e Mon Sep 17 00:00:00 2001 From: Xiulin Gao Date: Sun, 19 Oct 2025 15:20:22 -0700 Subject: [PATCH 02/23] correct corresponding SPITFIRE hist vars after ROS model correction --- main/FatesHistoryInterfaceMod.F90 | 12391 ++++++++++++++-------------- 1 file changed, 6209 insertions(+), 6182 deletions(-) diff --git a/main/FatesHistoryInterfaceMod.F90 b/main/FatesHistoryInterfaceMod.F90 index ee8cc1ed3c..a8362e28f1 100644 --- a/main/FatesHistoryInterfaceMod.F90 +++ b/main/FatesHistoryInterfaceMod.F90 @@ -1,2166 +1,2169 @@ module FatesHistoryInterfaceMod - 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,ifalse - use FatesConstantsMod , only : calloc_abs_error - use FatesConstantsMod , only : mg_per_kg - use FatesConstantsMod , only : pi_const - use FatesConstantsMod , only : nearzero - use FatesConstantsMod , only : t_water_freeze_k_1atm - use FatesConstantsMod , only : n_term_mort_types - use FatesConstantsMod , only : i_term_mort_type_cstarv - use FatesConstantsMod , only : i_term_mort_type_canlev - use FatesConstantsMod , only : i_term_mort_type_numdens - use FatesConstantsMod , only : nocomp_bareground_land - use FatesConstantsMod , only : nocomp_bareground - use FatesGlobals , only : fates_log - use FatesGlobals , only : endrun => fates_endrun - 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 : elem_diag_type - use EDtypesMod , only : ed_site_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 PRTGenericMod , only : element_list - use FatesIOVariableKindMod , only : group_dyna_simple, group_dyna_complx - use FatesIOVariableKindMod , only : group_hifr_simple, group_hifr_complx - use FatesIOVariableKindMod , only : group_hydr_simple, group_hydr_complx - use FatesIOVariableKindMod , only : group_nflx_simple, group_nflx_complx - 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 - use FatesHistoryVariableType , only : fates_history_variable_type - use FatesInterfaceTypesMod , only : hlm_hio_ignore_val - 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 - use FatesInterfaceTypesMod , only : hlm_use_sp - use EDParamsMod , only : comp_excln_exp - use EDParamsMod , only : ED_val_phen_coldtemp - use EDParamsMod , only : nlevleaf - use EDParamsMod , only : ED_val_history_height_bin_edges - use EDParamsMod , only : ED_val_history_ageclass_bin_edges - 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 FatesRadiationMemMod , only : ivis,inir,ipar - use FatesInterfaceTypesMod , only : hlm_hist_level_hifrq,hlm_hist_level_dynam - use FatesIOVariableKindMod, only : site_r8, site_soil_r8, site_size_pft_r8 - use FatesIOVariableKindMod, only : site_size_r8, site_pft_r8, site_age_r8 - use FatesIOVariableKindMod, only : site_coage_r8, site_coage_pft_r8 - 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_height_r8, site_agefuel_r8 - use FatesIOVariableKindMod, only : site_elem_r8, site_elpft_r8 - use FatesIOVariableKindMod, only : site_elcwd_r8, site_elage_r8, site_clscpf_r8 - use FatesIOVariableKindMod, only : site_cdpf_r8, site_cdsc_r8, site_cdam_r8 - use FatesIOVariableKindMod, only : site_landuse_r8, site_lulu_r8, site_lupft_r8 - use FatesConstantsMod , only : n_landuse_cats - use FatesAllometryMod , only : CrownDepth - use FatesAllometryMod , only : bstore_allom, bsap_allom - use FatesAllometryMod , only : set_root_fraction - - use EDPftvarcon , only : EDPftvarcon_inst - use PRTParametersMod , only : prt_params - - ! CIME Globals - 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,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 : secondaryland - use FatesConstantsMod , only : primaryland - - use PRTGenericMod , only : leaf_organ, fnrt_organ, sapw_organ - use PRTGenericMod , only : struct_organ, store_organ, repro_organ - 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 - use FatesSizeAgeTypeIndicesMod, only : get_age_class_index - - use FatesFuelClassesMod , only : num_fuel_classes - use FatesLitterMod , only : ncwd - 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 - use FatesSizeAgeTypeIndicesMod, only : get_agefuel_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 - - implicit none - private ! By default everything is private - - ! These variables hold the index of the history output structure so we don't - ! have to constantly do name lookup when we want to populate the dataset - ! These indices are set during "define_history_vars()" call to "set_history_var()" - ! during the initialize phase. Definitions are not provided, for an explanation of - ! the variable go to its registry. (IH_ signifies "index history") - ! - ! Because of the complex sub-gridscale structure of FATES, in which multiple patches and cohorts - ! exist within a gridcell, along with vertical gradients within and between canopy layers, as well - ! as distinct classes such as PFTs or fuel size bins, there are multiple different dimensions in - ! which it is possible to output history variables to better understand what's going on. - ! - ! a key point is that, while the number of patches or cohorts can in principle be large, and - ! the age and size indices of a given patch or cohort can be finely resolved, we collapse these - ! continuously varying indices into bins of time-invariant width for the purposes of history - ! outputting. This is because a given patch or cohort may not persist across a given interval - ! of history averaging, so it is better to output all patches of cohorts whose index is within - ! a given interval along the size or age bin. - ! - ! Another particularity of the issue of FATES shifting its subgrid structure frequently - ! and possibly having multiple (or zero) patches or cohorts within a given bin is that, if you - ! want to output an average quantities across some dimension, such as a mean carbon flux across - ! patch area of a given age, in general it is better to output both the numerator and denominator - ! of the averaging calculation separately, rather than the average itself, and then calculate - ! the average in post-processing. So, e.g. this means outputting both the patch area and the - ! product of the flux within each patch and the patch area as separate variables. Doing this - ! allows conservation even when the weights are changing rapidly and simplifies the logic when - ! the number of patches or cohorts may be anywhere from zero to a large number. - ! - ! So what this means is that anything that is disaggregated at the patch area requires - ! outputting the patch age distribution (in units of patch area / site area) as the denominator - ! of the average and then calculating the numerator of the average as XXX times the patch - ! area so (so in units of XXX * patch area / site area). For cohort-level quantities, - ! this requires outputting the number density (in units of individuals per site area), etc. - ! - ! For reference, some standardized abbreviations of the FATES dimensions are listed here: - ! scls = size-class dimension - ! cacls = cohort age-class dimension - ! pft = the pft dimension - ! age = the age bin dimension - ! height = the height bin dimension - ! cwdsc = the coarse woody debris size class dimension - ! - ! Since the netcdf interface can only handle variables with a certain number of dimensions, - ! we have create some "multiplexed" dimensions that combine two or more dimensions into a - ! single dimension. Examples of these are the following: - ! scpf = size class x PFT - ! cacpf = cohort age class x PFT - ! cnlf = canopy layer x leaf layer - ! cnlfpft = canopy layer x leaf layer x PFT - ! scag = size class bin x age bin - ! scagpft = size class bin x age bin x PFT - ! agepft = age bin x PFT - ! agefuel = age bin x fuel size class - - - ! A recipe for adding a new history variable to this module: - ! (1) decide what time frequency it makes sense to update the variable at, and what dimension(s) - ! you want to output the variable on - ! (2) add the ih_ integer variable in the immediately following section of the module. - ! use the suffix as outlined above for the dimension you are using. - ! (3) define a corresponding hio_ variable by associating it to the ih_ variable - ! in the associate section of the subroutine that corresponds to the time-updating - ! frequency that you've chosen - ! (i.e. if half-hourly, then work in subroutine update_history_prod; if daily, - ! then work in subroutine update_history_dyn) - ! (4) within that subroutine, add the logic that passes the information from the - ! fates-native variable (possibly on a patch or cohort structure) to the history - ! hio_ variable that you've associated to. - ! (5) add the variable name, metadata, units, dimension, updating frequency, the ih_ variable - ! index, etc via a call to the set_history_var method in the subroutine define_history_vars. - ! - - ! --STEPS-- TO CONVERT TO HISTORY LEVELS: - ! SPLIT INTO HIFRQ AND DYNAMICS - ! GO UP IN ORDER - - - ! 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_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_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 :: 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_nefflux_scpf - integer :: ih_pefflux_scpf - integer :: ih_nfix_si - integer :: ih_nfix_scpf - integer :: ih_ndemand_si - integer :: ih_ndemand_scpf - integer :: ih_pdemand_si - integer :: ih_pdemand_scpf - - integer :: ih_trimming_si - integer :: ih_fracarea_plant_si - integer :: ih_fracarea_trees_si - 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 - integer :: ih_seed_germ_elem - - integer :: ih_fines_ag_elem - 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 - - integer :: ih_bstor_canopy_si_scpf - integer :: ih_bstor_understory_si_scpf - integer :: ih_bleaf_canopy_si_scpf - integer :: ih_bleaf_understory_si_scpf - ! Size-class x PFT LAI states - integer :: ih_lai_canopy_si_scpf - integer :: ih_lai_understory_si_scpf - ! Size-class x PFT LAI states - integer :: ih_crownarea_canopy_si_scpf - integer :: ih_crownarea_understory_si_scpf - - integer :: ih_totvegc_scpf - integer :: ih_leafc_scpf - integer :: ih_fnrtc_scpf - integer :: ih_storec_scpf - integer :: ih_sapwc_scpf - integer :: ih_reproc_scpf - integer :: ih_bdead_si - integer :: ih_balive_si - integer :: ih_agb_si - integer :: ih_npp_si - integer :: ih_gpp_si - 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_primaryland_fusion_error_si - - ! land-use-resolved variables - integer :: ih_fracarea_si_landuse - integer :: ih_biomass_si_landuse - integer :: ih_burnedarea_si_landuse - integer :: ih_gpp_si_landuse - integer :: ih_npp_si_landuse - - ! land use by land use variables - integer :: ih_disturbance_rate_si_lulu - integer :: ih_transition_matrix_si_lulu - - integer :: ih_fire_disturbance_rate_si - integer :: ih_logging_disturbance_rate_si - integer :: ih_fall_disturbance_rate_si - integer :: ih_harvest_debt_si - integer :: ih_harvest_debt_sec_si - integer :: ih_harvest_woodprod_carbonflux_si - integer :: ih_luchange_woodprod_carbonflux_si - - ! Indices to site by size-class by age variables - integer :: ih_nplant_si_scag - integer :: ih_nplant_canopy_si_scag - integer :: ih_nplant_understory_si_scag - integer :: ih_ddbh_canopy_si_scag - integer :: ih_ddbh_understory_si_scag - integer :: ih_mortality_canopy_si_scag - integer :: ih_mortality_understory_si_scag - - ! Indices to site by size-class by age by pft variables - integer :: ih_nplant_si_scagpft - - ! Indices to site by patch age by pft variables - integer :: ih_biomass_si_agepft - integer :: ih_npp_si_agepft - integer :: ih_scorch_height_si_pft - integer :: ih_scorch_height_si_agepft - - ! 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 - - integer :: ih_c_stomata_si - integer :: ih_c_lblayer_si - integer :: ih_vis_rad_err_si - integer :: ih_nir_rad_err_si - integer :: ih_fire_c_to_atm_si - integer :: ih_interr_liveveg_elem - integer :: ih_interr_litter_elem - integer :: ih_cbal_err_fates_si - integer :: ih_err_fates_elem - - integer :: ih_npatches_si - integer :: ih_ncohorts_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 - integer :: ih_npp_stem_si - integer :: ih_npp_froot_si - integer :: ih_npp_croot_si - integer :: ih_npp_stor_si - integer :: ih_leaf_mr_si - integer :: ih_froot_mr_si - integer :: ih_livestem_mr_si - integer :: ih_livecroot_mr_si - integer :: ih_h2oveg_si - integer :: ih_h2oveg_dead_si - integer :: ih_h2oveg_recruit_si - integer :: ih_h2oveg_growturn_err_si - integer :: ih_h2oveg_hydro_err_si - integer :: ih_lai_si - integer :: ih_elai_si - - integer :: ih_site_cstatus_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_nesterov_fire_danger_si - integer :: ih_fire_nignitions_si - integer :: ih_fire_fdi_si - integer :: ih_fire_intensity_fracarea_product_si - integer :: ih_nonrx_intensity_fracarea_product_si - integer :: ih_rx_intensity_fracarea_product_si - integer :: ih_spitfire_ros_si - integer :: ih_effect_wspeed_si - integer :: ih_tfc_ros_si - integer :: ih_fire_intensity_si - integer :: ih_nonrx_intensity_si - integer :: ih_fire_fracarea_si - integer :: ih_nonrx_fracarea_si - integer :: ih_fire_fuel_bulkd_si - integer :: ih_fire_fuel_eff_moist_si - integer :: ih_fire_fuel_sav_si - integer :: ih_fire_fuel_mef_si - integer :: ih_sum_fuel_si - integer :: ih_rx_burn_window_si - integer :: ih_rx_intensity_si - integer :: ih_rx_fracarea_si - integer :: ih_rx_fracarea_fuel_si - integer :: ih_rx_fracarea_fi_si - integer :: ih_rx_fracarea_final_si - integer :: ih_fragmentation_scaler_sl - - integer :: ih_nplant_si_scpf - integer :: ih_gpp_si_scpf - integer :: ih_npp_totl_si_scpf - integer :: ih_npp_leaf_si_scpf - integer :: ih_npp_seed_si_scpf - integer :: ih_npp_fnrt_si_scpf - integer :: ih_npp_bgsw_si_scpf - integer :: ih_npp_bgdw_si_scpf - integer :: ih_npp_agsw_si_scpf - integer :: ih_npp_agdw_si_scpf - integer :: ih_npp_stor_si_scpf - integer :: ih_grazing_si - - 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 - integer :: ih_ddbh_understory_si_scpf - integer :: ih_gpp_canopy_si_scpf - integer :: ih_gpp_understory_si_scpf - integer :: ih_ar_canopy_si_scpf - integer :: ih_ar_understory_si_scpf - - integer :: ih_ddbh_si_scpf - integer :: ih_growthflux_si_scpf - integer :: ih_growthflux_fusion_si_scpf - integer :: ih_ba_si_scpf - integer :: ih_agb_si_scpf - integer :: ih_m1_si_scpf - integer :: ih_m2_si_scpf - integer :: ih_m3_si_scpf - integer :: ih_m4_si_scpf - integer :: ih_m5_si_scpf - integer :: ih_m6_si_scpf - integer :: ih_m7_si_scpf - integer :: ih_m8_si_scpf - integer :: ih_m9_si_scpf - integer :: ih_m10_si_scpf - integer :: ih_m11_si_scpf - integer :: ih_m12_si_scpf - - integer :: ih_nonrx_crown_mort_si_scpf - integer :: ih_nonrx_cambial_mort_si_scpf - integer :: ih_rx_crown_mort_si_scpf - integer :: ih_rx_cambial_mort_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 - - integer :: ih_ar_si_scpf - integer :: ih_ar_grow_si_scpf - integer :: ih_ar_maint_si_scpf - integer :: ih_ar_darkm_si_scpf - integer :: ih_ar_agsapm_si_scpf - integer :: ih_ar_crootm_si_scpf - integer :: ih_ar_frootm_si_scpf - - integer :: ih_c13disc_si_scpf - - ! indices to (site x scls [size class bins]) variables - integer :: ih_ba_si_scls - integer :: ih_nplant_si_scls - integer :: ih_nplant_canopy_si_scls - integer :: ih_nplant_understory_si_scls - integer :: ih_lai_canopy_si_scls - integer :: ih_lai_understory_si_scls - integer :: ih_sai_canopy_si_scls - 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 - integer :: ih_trimming_understory_si_scls - integer :: ih_crown_fracarea_canopy_si_scls - integer :: ih_crown_fracarea_understory_si_scls - integer :: ih_ddbh_canopy_si_scls - 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 - integer :: ih_m2_si_scls - integer :: ih_m3_si_scls - integer :: ih_m4_si_scls - integer :: ih_m5_si_scls - integer :: ih_m6_si_scls - integer :: ih_m7_si_scls - integer :: ih_m8_si_scls - integer :: ih_m9_si_scls - integer :: ih_m10_si_scls - integer :: ih_m12_si_scls - - integer :: ih_m10_si_cacls - integer :: ih_nplant_si_cacls - - ! lots of non-default diagnostics for understanding canopy versus understory carbon balances - integer :: ih_rdark_canopy_si_scls - integer :: ih_livestem_mr_canopy_si_scls - integer :: ih_livecroot_mr_canopy_si_scls - integer :: ih_froot_mr_canopy_si_scls - integer :: ih_resp_g_canopy_si_scls - integer :: ih_resp_m_canopy_si_scls - integer :: ih_leaf_md_canopy_si_scls - integer :: ih_root_md_canopy_si_scls - integer :: ih_carbon_balance_canopy_si_scls - integer :: ih_bstore_md_canopy_si_scls - integer :: ih_bdead_md_canopy_si_scls - integer :: ih_bsw_md_canopy_si_scls - integer :: ih_seed_prod_canopy_si_scls - integer :: ih_npp_leaf_canopy_si_scls - integer :: ih_npp_fnrt_canopy_si_scls - integer :: ih_npp_sapw_canopy_si_scls - integer :: ih_npp_dead_canopy_si_scls - integer :: ih_npp_seed_canopy_si_scls - integer :: ih_npp_stor_canopy_si_scls - - integer :: ih_rdark_understory_si_scls - integer :: ih_livestem_mr_understory_si_scls - integer :: ih_livecroot_mr_understory_si_scls - integer :: ih_froot_mr_understory_si_scls - integer :: ih_resp_g_understory_si_scls - integer :: ih_resp_m_understory_si_scls - integer :: ih_leaf_md_understory_si_scls - integer :: ih_root_md_understory_si_scls - integer :: ih_carbon_balance_understory_si_scls - integer :: ih_bsw_md_understory_si_scls - integer :: ih_bdead_md_understory_si_scls - integer :: ih_bstore_md_understory_si_scls - integer :: ih_seed_prod_understory_si_scls - integer :: ih_npp_leaf_understory_si_scls - integer :: ih_npp_fnrt_understory_si_scls - integer :: ih_npp_sapw_understory_si_scls - integer :: ih_npp_dead_understory_si_scls - integer :: ih_npp_seed_understory_si_scls - integer :: ih_npp_stor_understory_si_scls - - integer :: ih_yesterdaycanopylevel_canopy_si_scls - integer :: ih_yesterdaycanopylevel_understory_si_scls - - ! indices to (site x pft) variables - integer :: ih_biomass_si_pft - integer :: ih_leafbiomass_si_pft - integer :: ih_storebiomass_si_pft - integer :: ih_nindivs_si_pft - integer :: ih_recruitment_si_pft - integer :: ih_recruitment_cflux_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_cstarvmortality_continuous_carbonflux_si_pft - integer :: ih_crownarea_si_pft - integer :: ih_canopycrownarea_si_pft - integer :: ih_crownarea_si_cnlf - integer :: ih_gpp_si_pft - integer :: ih_npp_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 - integer :: ih_seed_bank_si_pft ! carbon only - integer :: ih_seeds_in_si_pft ! carbon only - integer :: ih_seeds_in_local_si_pft ! carbon only - integer :: ih_ungerm_seed_bank_si_pft ! carbon only - integer :: ih_seedling_pool_si_pft ! carbon only - - ! Non-per-ageclass equivalents of per-ageclass variables - integer :: ih_canopy_fracarea_si - integer :: ih_ncl_si - integer :: ih_fracarea_si - - ! indices to (site x patch-age) variables - integer :: ih_fracarea_si_age - integer :: ih_lai_si_age - integer :: ih_canopy_fracarea_si_age - integer :: ih_gpp_si_age - integer :: ih_npp_si_age - integer :: ih_ncl_si_age - integer :: ih_npatches_si_age - integer :: ih_zstar_si - integer :: ih_zstar_si_age - integer :: ih_biomass_si_age - integer :: ih_c_stomata_si_age - integer :: ih_c_lblayer_si_age - integer :: ih_agesince_anthrodist_si - integer :: ih_agesince_anthrodist_si_age - integer :: ih_secondarylands_area_si_age - integer :: ih_primarylands_area_si_age - integer :: ih_area_burnt_si_age - integer :: ih_primarylands_fracarea_si - integer :: ih_secondarylands_fracarea_si - integer :: ih_secondarylands_fracarea_si_age - integer :: ih_primarylands_fracarea_si_age - integer :: ih_fracarea_burnt_si_age - integer :: ih_rx_fracarea_burnt_si_age - integer :: ih_nonrx_fracarea_burnt_si_age - ! integer :: ih_fire_rate_of_spread_front_si_age - integer :: ih_fire_intensity_si_age - integer :: ih_fire_sum_fuel_si_age - integer :: ih_rx_intensity_si_age - integer :: ih_nonrx_intensity_si_age - - ! indices to (site x height) variables - integer :: ih_canopy_height_dist_si_height - integer :: ih_leaf_height_dist_si_height - - ! Indices to hydraulics variables - - integer :: ih_errh2o_scpf - integer :: ih_tran_scpf - - ! integer :: ih_h2osoi_si_scagpft ! hijacking the scagpft dimension instead of creating a new shsl dimension - integer :: ih_sapflow_scpf - integer :: ih_sapwood_area_scpf - integer :: ih_sapflow_si - integer :: ih_iterh1_scpf - integer :: ih_iterh2_scpf - integer :: ih_supsub_scpf - integer :: ih_ath_scpf - integer :: ih_tth_scpf - integer :: ih_sth_scpf - integer :: ih_lth_scpf - integer :: ih_awp_scpf - integer :: ih_twp_scpf - integer :: ih_swp_scpf - integer :: ih_lwp_scpf - integer :: ih_aflc_scpf - integer :: ih_tflc_scpf - integer :: ih_sflc_scpf - integer :: ih_lflc_scpf - integer :: ih_btran_scpf - - ! Hydro: Soil water states - integer :: ih_rootwgt_soilvwc_si - integer :: ih_rootwgt_soilvwcsat_si - integer :: ih_rootwgt_soilmatpot_si - - ! Hydro: Soil water state by layer - integer :: ih_soilmatpot_sl - integer :: ih_soilvwc_sl - integer :: ih_soilvwcsat_sl - - ! Hydro: Root water Uptake rates - integer :: ih_rootuptake_si - integer :: ih_rootuptake_sl - integer :: ih_rootuptake0_scpf - integer :: ih_rootuptake10_scpf - integer :: ih_rootuptake50_scpf - integer :: ih_rootuptake100_scpf - - - ! indices to (site x fuel class) variables - integer :: ih_litter_moisture_si_fuel - integer :: ih_burnt_frac_litter_si_fuel - integer :: ih_fuel_amount_si_fuel - - ! indices to (site x cwd size class) variables - integer :: ih_cwd_ag_si_cwdsc - integer :: ih_cwd_bg_si_cwdsc - integer :: ih_cwd_ag_in_si_cwdsc - integer :: ih_cwd_bg_in_si_cwdsc - integer :: ih_cwd_ag_out_si_cwdsc - integer :: ih_cwd_bg_out_si_cwdsc - - ! indices to (site x [canopy layer x leaf layer]) variables - integer :: ih_parsun_z_si_cnlf - integer :: ih_parsha_z_si_cnlf - integer :: ih_laisun_z_si_cnlf - integer :: ih_laisha_z_si_cnlf - integer :: ih_ts_net_uptake_si_cnlf - integer :: ih_crownarea_clll - integer :: ih_parprof_dir_si_cnlf - integer :: ih_parprof_dif_si_cnlf - - ! indices to (site x [canopy layer x leaf layer x pft]) variables - integer :: ih_parsun_z_si_cnlfpft - integer :: ih_parsha_z_si_cnlfpft - integer :: ih_laisun_clllpf - integer :: ih_laisha_clllpf - integer :: ih_parprof_dir_si_cnlfpft - integer :: ih_parprof_dif_si_cnlfpft - integer :: ih_crownfrac_clllpf - - ! 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_si_can - integer :: ih_parsha_si_can - integer :: ih_laisun_si_can - integer :: ih_laisha_si_can - integer :: ih_crownarea_cl - - ! indices to (patch age x fuel size class) variables - integer :: ih_fuel_amount_si_agfc - - ! The number of variable dim/kind types we have defined (static) - - integer, parameter, public :: fates_history_num_dimensions = 50 - integer, parameter, public :: fates_history_num_dim_kinds = 50 - - type, public :: fates_history_interface_type - - ! Instance of the list of history output varialbes - type(fates_history_variable_type), allocatable :: hvars(:) - integer, private :: num_history_vars_ - - ! Instanteat one registry of the different dimension/kinds (dk) - ! All output variables will have a pointer to one of these dk's - type(fates_io_variable_kind_type) :: dim_kinds(fates_history_num_dim_kinds) - - ! This is a structure that explains where FATES patch boundaries - ! on each thread point to in the host IO array, this structure is - ! allocated by number of threads. This could be dynamically - ! allocated, but is unlikely to change...? - type(fates_io_dimension_type) :: dim_bounds(fates_history_num_dimensions) - - !! THESE WERE EXPLICITLY PRIVATE WHEN TYPE WAS PUBLIC - integer, private :: column_index_, levsoil_index_, levscpf_index_ - 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_ - integer, private :: levlanduse_index_, levlulu_index_, levlupft_index_ + 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,ifalse + use FatesConstantsMod , only : calloc_abs_error + use FatesConstantsMod , only : mg_per_kg + use FatesConstantsMod , only : pi_const + use FatesConstantsMod , only : nearzero + use FatesConstantsMod , only : t_water_freeze_k_1atm + use FatesConstantsMod , only : n_term_mort_types + use FatesConstantsMod , only : i_term_mort_type_cstarv + use FatesConstantsMod , only : i_term_mort_type_canlev + use FatesConstantsMod , only : i_term_mort_type_numdens + use FatesConstantsMod , only : nocomp_bareground_land + use FatesConstantsMod , only : nocomp_bareground + use FatesGlobals , only : fates_log + use FatesGlobals , only : endrun => fates_endrun + 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 : elem_diag_type + use EDtypesMod , only : ed_site_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 PRTGenericMod , only : element_list + use FatesIOVariableKindMod , only : group_dyna_simple, group_dyna_complx + use FatesIOVariableKindMod , only : group_hifr_simple, group_hifr_complx + use FatesIOVariableKindMod , only : group_hydr_simple, group_hydr_complx + use FatesIOVariableKindMod , only : group_nflx_simple, group_nflx_complx + 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 + use FatesHistoryVariableType , only : fates_history_variable_type + use FatesInterfaceTypesMod , only : hlm_hio_ignore_val + 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 + use FatesInterfaceTypesMod , only : hlm_use_sp + use EDParamsMod , only : comp_excln_exp + use EDParamsMod , only : ED_val_phen_coldtemp + use EDParamsMod , only : nlevleaf + use EDParamsMod , only : ED_val_history_height_bin_edges + use EDParamsMod , only : ED_val_history_ageclass_bin_edges + 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 FatesRadiationMemMod , only : ivis,inir,ipar + use FatesInterfaceTypesMod , only : hlm_hist_level_hifrq,hlm_hist_level_dynam + use FatesIOVariableKindMod, only : site_r8, site_soil_r8, site_size_pft_r8 + use FatesIOVariableKindMod, only : site_size_r8, site_pft_r8, site_age_r8 + use FatesIOVariableKindMod, only : site_coage_r8, site_coage_pft_r8 + 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_height_r8, site_agefuel_r8 + use FatesIOVariableKindMod, only : site_elem_r8, site_elpft_r8 + use FatesIOVariableKindMod, only : site_elcwd_r8, site_elage_r8, site_clscpf_r8 + use FatesIOVariableKindMod, only : site_cdpf_r8, site_cdsc_r8, site_cdam_r8 + use FatesIOVariableKindMod, only : site_landuse_r8, site_lulu_r8, site_lupft_r8 + use FatesConstantsMod , only : n_landuse_cats + use FatesAllometryMod , only : CrownDepth + use FatesAllometryMod , only : bstore_allom, bsap_allom + use FatesAllometryMod , only : set_root_fraction + + use EDPftvarcon , only : EDPftvarcon_inst + use PRTParametersMod , only : prt_params + + ! CIME Globals + 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,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 : secondaryland + use FatesConstantsMod , only : primaryland + + use PRTGenericMod , only : leaf_organ, fnrt_organ, sapw_organ + use PRTGenericMod , only : struct_organ, store_organ, repro_organ + 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 + use FatesSizeAgeTypeIndicesMod, only : get_age_class_index + + use FatesFuelClassesMod , only : num_fuel_classes + use FatesLitterMod , only : ncwd + 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 + use FatesSizeAgeTypeIndicesMod, only : get_agefuel_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 + + implicit none + private ! By default everything is private + + ! These variables hold the index of the history output structure so we don't + ! have to constantly do name lookup when we want to populate the dataset + ! These indices are set during "define_history_vars()" call to "set_history_var()" + ! during the initialize phase. Definitions are not provided, for an explanation of + ! the variable go to its registry. (IH_ signifies "index history") + ! + ! Because of the complex sub-gridscale structure of FATES, in which multiple patches and cohorts + ! exist within a gridcell, along with vertical gradients within and between canopy layers, as well + ! as distinct classes such as PFTs or fuel size bins, there are multiple different dimensions in + ! which it is possible to output history variables to better understand what's going on. + ! + ! a key point is that, while the number of patches or cohorts can in principle be large, and + ! the age and size indices of a given patch or cohort can be finely resolved, we collapse these + ! continuously varying indices into bins of time-invariant width for the purposes of history + ! outputting. This is because a given patch or cohort may not persist across a given interval + ! of history averaging, so it is better to output all patches of cohorts whose index is within + ! a given interval along the size or age bin. + ! + ! Another particularity of the issue of FATES shifting its subgrid structure frequently + ! and possibly having multiple (or zero) patches or cohorts within a given bin is that, if you + ! want to output an average quantities across some dimension, such as a mean carbon flux across + ! patch area of a given age, in general it is better to output both the numerator and denominator + ! of the averaging calculation separately, rather than the average itself, and then calculate + ! the average in post-processing. So, e.g. this means outputting both the patch area and the + ! product of the flux within each patch and the patch area as separate variables. Doing this + ! allows conservation even when the weights are changing rapidly and simplifies the logic when + ! the number of patches or cohorts may be anywhere from zero to a large number. + ! + ! So what this means is that anything that is disaggregated at the patch area requires + ! outputting the patch age distribution (in units of patch area / site area) as the denominator + ! of the average and then calculating the numerator of the average as XXX times the patch + ! area so (so in units of XXX * patch area / site area). For cohort-level quantities, + ! this requires outputting the number density (in units of individuals per site area), etc. + ! + ! For reference, some standardized abbreviations of the FATES dimensions are listed here: + ! scls = size-class dimension + ! cacls = cohort age-class dimension + ! pft = the pft dimension + ! age = the age bin dimension + ! height = the height bin dimension + ! cwdsc = the coarse woody debris size class dimension + ! + ! Since the netcdf interface can only handle variables with a certain number of dimensions, + ! we have create some "multiplexed" dimensions that combine two or more dimensions into a + ! single dimension. Examples of these are the following: + ! scpf = size class x PFT + ! cacpf = cohort age class x PFT + ! cnlf = canopy layer x leaf layer + ! cnlfpft = canopy layer x leaf layer x PFT + ! scag = size class bin x age bin + ! scagpft = size class bin x age bin x PFT + ! agepft = age bin x PFT + ! agefuel = age bin x fuel size class + + + ! A recipe for adding a new history variable to this module: + ! (1) decide what time frequency it makes sense to update the variable at, and what dimension(s) + ! you want to output the variable on + ! (2) add the ih_ integer variable in the immediately following section of the module. + ! use the suffix as outlined above for the dimension you are using. + ! (3) define a corresponding hio_ variable by associating it to the ih_ variable + ! in the associate section of the subroutine that corresponds to the time-updating + ! frequency that you've chosen + ! (i.e. if half-hourly, then work in subroutine update_history_prod; if daily, + ! then work in subroutine update_history_dyn) + ! (4) within that subroutine, add the logic that passes the information from the + ! fates-native variable (possibly on a patch or cohort structure) to the history + ! hio_ variable that you've associated to. + ! (5) add the variable name, metadata, units, dimension, updating frequency, the ih_ variable + ! index, etc via a call to the set_history_var method in the subroutine define_history_vars. + ! + + ! --STEPS-- TO CONVERT TO HISTORY LEVELS: + ! SPLIT INTO HIFRQ AND DYNAMICS + ! GO UP IN ORDER + + + ! 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_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_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 :: 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_nefflux_scpf + integer :: ih_pefflux_scpf + integer :: ih_nfix_si + integer :: ih_nfix_scpf + integer :: ih_ndemand_si + integer :: ih_ndemand_scpf + integer :: ih_pdemand_si + integer :: ih_pdemand_scpf + + integer :: ih_trimming_si + integer :: ih_fracarea_plant_si + integer :: ih_fracarea_trees_si + 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 + integer :: ih_seed_germ_elem + + integer :: ih_fines_ag_elem + 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 + + integer :: ih_bstor_canopy_si_scpf + integer :: ih_bstor_understory_si_scpf + integer :: ih_bleaf_canopy_si_scpf + integer :: ih_bleaf_understory_si_scpf + ! Size-class x PFT LAI states + integer :: ih_lai_canopy_si_scpf + integer :: ih_lai_understory_si_scpf + ! Size-class x PFT LAI states + integer :: ih_crownarea_canopy_si_scpf + integer :: ih_crownarea_understory_si_scpf + + integer :: ih_totvegc_scpf + integer :: ih_leafc_scpf + integer :: ih_fnrtc_scpf + integer :: ih_storec_scpf + integer :: ih_sapwc_scpf + integer :: ih_reproc_scpf + integer :: ih_bdead_si + integer :: ih_balive_si + integer :: ih_agb_si + integer :: ih_npp_si + integer :: ih_gpp_si + 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_primaryland_fusion_error_si + + ! land-use-resolved variables + integer :: ih_fracarea_si_landuse + integer :: ih_biomass_si_landuse + integer :: ih_burnedarea_si_landuse + integer :: ih_gpp_si_landuse + integer :: ih_npp_si_landuse + + ! land use by land use variables + integer :: ih_disturbance_rate_si_lulu + integer :: ih_transition_matrix_si_lulu + + integer :: ih_fire_disturbance_rate_si + integer :: ih_logging_disturbance_rate_si + integer :: ih_fall_disturbance_rate_si + integer :: ih_harvest_debt_si + integer :: ih_harvest_debt_sec_si + integer :: ih_harvest_woodprod_carbonflux_si + integer :: ih_luchange_woodprod_carbonflux_si + + ! Indices to site by size-class by age variables + integer :: ih_nplant_si_scag + integer :: ih_nplant_canopy_si_scag + integer :: ih_nplant_understory_si_scag + integer :: ih_ddbh_canopy_si_scag + integer :: ih_ddbh_understory_si_scag + integer :: ih_mortality_canopy_si_scag + integer :: ih_mortality_understory_si_scag + + ! Indices to site by size-class by age by pft variables + integer :: ih_nplant_si_scagpft + + ! Indices to site by patch age by pft variables + integer :: ih_biomass_si_agepft + integer :: ih_npp_si_agepft + integer :: ih_scorch_height_si_pft + integer :: ih_scorch_height_si_agepft + + ! 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 + + integer :: ih_c_stomata_si + integer :: ih_c_lblayer_si + integer :: ih_vis_rad_err_si + integer :: ih_nir_rad_err_si + integer :: ih_fire_c_to_atm_si + integer :: ih_interr_liveveg_elem + integer :: ih_interr_litter_elem + integer :: ih_cbal_err_fates_si + integer :: ih_err_fates_elem + + integer :: ih_npatches_si + integer :: ih_ncohorts_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 + integer :: ih_npp_stem_si + integer :: ih_npp_froot_si + integer :: ih_npp_croot_si + integer :: ih_npp_stor_si + integer :: ih_leaf_mr_si + integer :: ih_froot_mr_si + integer :: ih_livestem_mr_si + integer :: ih_livecroot_mr_si + integer :: ih_h2oveg_si + integer :: ih_h2oveg_dead_si + integer :: ih_h2oveg_recruit_si + integer :: ih_h2oveg_growturn_err_si + integer :: ih_h2oveg_hydro_err_si + integer :: ih_lai_si + integer :: ih_elai_si + + integer :: ih_site_cstatus_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_nesterov_fire_danger_si + integer :: ih_fire_nignitions_si + integer :: ih_fire_fdi_si + integer :: ih_fire_intensity_fracarea_product_si + integer :: ih_nonrx_intensity_fracarea_product_si + integer :: ih_rx_intensity_fracarea_product_si + integer :: ih_spitfire_ros_si + integer :: ih_effect_wspeed_si + integer :: ih_tfc_ros_si + integer :: ih_fire_intensity_si + integer :: ih_nonrx_intensity_si + integer :: ih_fire_fracarea_si + integer :: ih_nonrx_fracarea_si + integer :: ih_fire_fuel_bulkd_si + integer :: ih_fire_fuel_moist_dead_si + integer :: ih_fire_fuel_moist_live_si + integer :: ih_fire_fuel_sav_si + integer :: ih_fire_fuel_mef_dead_si + integer :: ih_fire_fuel_mef_live_si + integer :: ih_sum_fuel_si + integer :: ih_weighted_sum_fuel_si + integer :: ih_rx_burn_window_si + integer :: ih_rx_intensity_si + integer :: ih_rx_fracarea_si + integer :: ih_rx_fracarea_fuel_si + integer :: ih_rx_fracarea_fi_si + integer :: ih_rx_fracarea_final_si + integer :: ih_fragmentation_scaler_sl + + integer :: ih_nplant_si_scpf + integer :: ih_gpp_si_scpf + integer :: ih_npp_totl_si_scpf + integer :: ih_npp_leaf_si_scpf + integer :: ih_npp_seed_si_scpf + integer :: ih_npp_fnrt_si_scpf + integer :: ih_npp_bgsw_si_scpf + integer :: ih_npp_bgdw_si_scpf + integer :: ih_npp_agsw_si_scpf + integer :: ih_npp_agdw_si_scpf + integer :: ih_npp_stor_si_scpf + integer :: ih_grazing_si + + 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 + integer :: ih_ddbh_understory_si_scpf + integer :: ih_gpp_canopy_si_scpf + integer :: ih_gpp_understory_si_scpf + integer :: ih_ar_canopy_si_scpf + integer :: ih_ar_understory_si_scpf + + integer :: ih_ddbh_si_scpf + integer :: ih_growthflux_si_scpf + integer :: ih_growthflux_fusion_si_scpf + integer :: ih_ba_si_scpf + integer :: ih_agb_si_scpf + integer :: ih_m1_si_scpf + integer :: ih_m2_si_scpf + integer :: ih_m3_si_scpf + integer :: ih_m4_si_scpf + integer :: ih_m5_si_scpf + integer :: ih_m6_si_scpf + integer :: ih_m7_si_scpf + integer :: ih_m8_si_scpf + integer :: ih_m9_si_scpf + integer :: ih_m10_si_scpf + integer :: ih_m11_si_scpf + integer :: ih_m12_si_scpf + + integer :: ih_nonrx_crown_mort_si_scpf + integer :: ih_nonrx_cambial_mort_si_scpf + integer :: ih_rx_crown_mort_si_scpf + integer :: ih_rx_cambial_mort_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 + + integer :: ih_ar_si_scpf + integer :: ih_ar_grow_si_scpf + integer :: ih_ar_maint_si_scpf + integer :: ih_ar_darkm_si_scpf + integer :: ih_ar_agsapm_si_scpf + integer :: ih_ar_crootm_si_scpf + integer :: ih_ar_frootm_si_scpf + + integer :: ih_c13disc_si_scpf + + ! indices to (site x scls [size class bins]) variables + integer :: ih_ba_si_scls + integer :: ih_nplant_si_scls + integer :: ih_nplant_canopy_si_scls + integer :: ih_nplant_understory_si_scls + integer :: ih_lai_canopy_si_scls + integer :: ih_lai_understory_si_scls + integer :: ih_sai_canopy_si_scls + 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 + integer :: ih_trimming_understory_si_scls + integer :: ih_crown_fracarea_canopy_si_scls + integer :: ih_crown_fracarea_understory_si_scls + integer :: ih_ddbh_canopy_si_scls + 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 + integer :: ih_m2_si_scls + integer :: ih_m3_si_scls + integer :: ih_m4_si_scls + integer :: ih_m5_si_scls + integer :: ih_m6_si_scls + integer :: ih_m7_si_scls + integer :: ih_m8_si_scls + integer :: ih_m9_si_scls + integer :: ih_m10_si_scls + integer :: ih_m12_si_scls + + integer :: ih_m10_si_cacls + integer :: ih_nplant_si_cacls + + ! lots of non-default diagnostics for understanding canopy versus understory carbon balances + integer :: ih_rdark_canopy_si_scls + integer :: ih_livestem_mr_canopy_si_scls + integer :: ih_livecroot_mr_canopy_si_scls + integer :: ih_froot_mr_canopy_si_scls + integer :: ih_resp_g_canopy_si_scls + integer :: ih_resp_m_canopy_si_scls + integer :: ih_leaf_md_canopy_si_scls + integer :: ih_root_md_canopy_si_scls + integer :: ih_carbon_balance_canopy_si_scls + integer :: ih_bstore_md_canopy_si_scls + integer :: ih_bdead_md_canopy_si_scls + integer :: ih_bsw_md_canopy_si_scls + integer :: ih_seed_prod_canopy_si_scls + integer :: ih_npp_leaf_canopy_si_scls + integer :: ih_npp_fnrt_canopy_si_scls + integer :: ih_npp_sapw_canopy_si_scls + integer :: ih_npp_dead_canopy_si_scls + integer :: ih_npp_seed_canopy_si_scls + integer :: ih_npp_stor_canopy_si_scls + + integer :: ih_rdark_understory_si_scls + integer :: ih_livestem_mr_understory_si_scls + integer :: ih_livecroot_mr_understory_si_scls + integer :: ih_froot_mr_understory_si_scls + integer :: ih_resp_g_understory_si_scls + integer :: ih_resp_m_understory_si_scls + integer :: ih_leaf_md_understory_si_scls + integer :: ih_root_md_understory_si_scls + integer :: ih_carbon_balance_understory_si_scls + integer :: ih_bsw_md_understory_si_scls + integer :: ih_bdead_md_understory_si_scls + integer :: ih_bstore_md_understory_si_scls + integer :: ih_seed_prod_understory_si_scls + integer :: ih_npp_leaf_understory_si_scls + integer :: ih_npp_fnrt_understory_si_scls + integer :: ih_npp_sapw_understory_si_scls + integer :: ih_npp_dead_understory_si_scls + integer :: ih_npp_seed_understory_si_scls + integer :: ih_npp_stor_understory_si_scls + + integer :: ih_yesterdaycanopylevel_canopy_si_scls + integer :: ih_yesterdaycanopylevel_understory_si_scls + + ! indices to (site x pft) variables + integer :: ih_biomass_si_pft + integer :: ih_leafbiomass_si_pft + integer :: ih_storebiomass_si_pft + integer :: ih_nindivs_si_pft + integer :: ih_recruitment_si_pft + integer :: ih_recruitment_cflux_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_cstarvmortality_continuous_carbonflux_si_pft + integer :: ih_crownarea_si_pft + integer :: ih_canopycrownarea_si_pft + integer :: ih_crownarea_si_cnlf + integer :: ih_gpp_si_pft + integer :: ih_npp_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 + integer :: ih_seed_bank_si_pft ! carbon only + integer :: ih_seeds_in_si_pft ! carbon only + integer :: ih_seeds_in_local_si_pft ! carbon only + integer :: ih_ungerm_seed_bank_si_pft ! carbon only + integer :: ih_seedling_pool_si_pft ! carbon only + + ! Non-per-ageclass equivalents of per-ageclass variables + integer :: ih_canopy_fracarea_si + integer :: ih_ncl_si + integer :: ih_fracarea_si + + ! indices to (site x patch-age) variables + integer :: ih_fracarea_si_age + integer :: ih_lai_si_age + integer :: ih_canopy_fracarea_si_age + integer :: ih_gpp_si_age + integer :: ih_npp_si_age + integer :: ih_ncl_si_age + integer :: ih_npatches_si_age + integer :: ih_zstar_si + integer :: ih_zstar_si_age + integer :: ih_biomass_si_age + integer :: ih_c_stomata_si_age + integer :: ih_c_lblayer_si_age + integer :: ih_agesince_anthrodist_si + integer :: ih_agesince_anthrodist_si_age + integer :: ih_secondarylands_area_si_age + integer :: ih_primarylands_area_si_age + integer :: ih_area_burnt_si_age + integer :: ih_primarylands_fracarea_si + integer :: ih_secondarylands_fracarea_si + integer :: ih_secondarylands_fracarea_si_age + integer :: ih_primarylands_fracarea_si_age + integer :: ih_fracarea_burnt_si_age + integer :: ih_rx_fracarea_burnt_si_age + integer :: ih_nonrx_fracarea_burnt_si_age + ! integer :: ih_fire_rate_of_spread_front_si_age + integer :: ih_fire_intensity_si_age + integer :: ih_fire_sum_fuel_si_age + integer :: ih_rx_intensity_si_age + integer :: ih_nonrx_intensity_si_age + + ! indices to (site x height) variables + integer :: ih_canopy_height_dist_si_height + integer :: ih_leaf_height_dist_si_height + + ! Indices to hydraulics variables + + integer :: ih_errh2o_scpf + integer :: ih_tran_scpf + + ! integer :: ih_h2osoi_si_scagpft ! hijacking the scagpft dimension instead of creating a new shsl dimension + integer :: ih_sapflow_scpf + integer :: ih_sapwood_area_scpf + integer :: ih_sapflow_si + integer :: ih_iterh1_scpf + integer :: ih_iterh2_scpf + integer :: ih_supsub_scpf + integer :: ih_ath_scpf + integer :: ih_tth_scpf + integer :: ih_sth_scpf + integer :: ih_lth_scpf + integer :: ih_awp_scpf + integer :: ih_twp_scpf + integer :: ih_swp_scpf + integer :: ih_lwp_scpf + integer :: ih_aflc_scpf + integer :: ih_tflc_scpf + integer :: ih_sflc_scpf + integer :: ih_lflc_scpf + integer :: ih_btran_scpf + + ! Hydro: Soil water states + integer :: ih_rootwgt_soilvwc_si + integer :: ih_rootwgt_soilvwcsat_si + integer :: ih_rootwgt_soilmatpot_si + + ! Hydro: Soil water state by layer + integer :: ih_soilmatpot_sl + integer :: ih_soilvwc_sl + integer :: ih_soilvwcsat_sl + + ! Hydro: Root water Uptake rates + integer :: ih_rootuptake_si + integer :: ih_rootuptake_sl + integer :: ih_rootuptake0_scpf + integer :: ih_rootuptake10_scpf + integer :: ih_rootuptake50_scpf + integer :: ih_rootuptake100_scpf + + + ! indices to (site x fuel class) variables + integer :: ih_litter_moisture_si_fuel + integer :: ih_burnt_frac_litter_si_fuel + integer :: ih_fuel_amount_si_fuel + + ! indices to (site x cwd size class) variables + integer :: ih_cwd_ag_si_cwdsc + integer :: ih_cwd_bg_si_cwdsc + integer :: ih_cwd_ag_in_si_cwdsc + integer :: ih_cwd_bg_in_si_cwdsc + integer :: ih_cwd_ag_out_si_cwdsc + integer :: ih_cwd_bg_out_si_cwdsc + + ! indices to (site x [canopy layer x leaf layer]) variables + integer :: ih_parsun_z_si_cnlf + integer :: ih_parsha_z_si_cnlf + integer :: ih_laisun_z_si_cnlf + integer :: ih_laisha_z_si_cnlf + integer :: ih_ts_net_uptake_si_cnlf + integer :: ih_crownarea_clll + integer :: ih_parprof_dir_si_cnlf + integer :: ih_parprof_dif_si_cnlf + + ! indices to (site x [canopy layer x leaf layer x pft]) variables + integer :: ih_parsun_z_si_cnlfpft + integer :: ih_parsha_z_si_cnlfpft + integer :: ih_laisun_clllpf + integer :: ih_laisha_clllpf + integer :: ih_parprof_dir_si_cnlfpft + integer :: ih_parprof_dif_si_cnlfpft + integer :: ih_crownfrac_clllpf + + ! 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_si_can + integer :: ih_parsha_si_can + integer :: ih_laisun_si_can + integer :: ih_laisha_si_can + integer :: ih_crownarea_cl + + ! indices to (patch age x fuel size class) variables + integer :: ih_fuel_amount_si_agfc + + ! The number of variable dim/kind types we have defined (static) + + integer, parameter, public :: fates_history_num_dimensions = 50 + integer, parameter, public :: fates_history_num_dim_kinds = 50 + + type, public :: fates_history_interface_type + + ! Instance of the list of history output varialbes + type(fates_history_variable_type), allocatable :: hvars(:) + integer, private :: num_history_vars_ + + ! Instanteat one registry of the different dimension/kinds (dk) + ! All output variables will have a pointer to one of these dk's + type(fates_io_variable_kind_type) :: dim_kinds(fates_history_num_dim_kinds) + + ! This is a structure that explains where FATES patch boundaries + ! on each thread point to in the host IO array, this structure is + ! allocated by number of threads. This could be dynamically + ! allocated, but is unlikely to change...? + type(fates_io_dimension_type) :: dim_bounds(fates_history_num_dimensions) + + !! THESE WERE EXPLICITLY PRIVATE WHEN TYPE WAS PUBLIC + integer, private :: column_index_, levsoil_index_, levscpf_index_ + 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_ + integer, private :: levlanduse_index_, levlulu_index_, levlupft_index_ contains - procedure :: Init - procedure :: SetThreadBoundsEach - procedure :: initialize_history_vars - procedure :: assemble_history_output_types - - procedure :: update_history_dyn - procedure :: update_history_dyn_sitelevel - procedure :: update_history_dyn_subsite - procedure :: update_history_dyn_subsite_ageclass - procedure :: reset_history_dyn_subsite - procedure :: update_history_hifrq - procedure :: update_history_hifrq_sitelevel - procedure :: update_history_hifrq_subsite - procedure :: update_history_hifrq_subsite_ageclass - procedure :: update_history_hydraulics - procedure :: update_history_nutrflux - - ! 'get' methods used by external callers to access private read only data - - procedure :: num_history_vars - procedure :: column_index - procedure :: levsoil_index - procedure :: levscpf_index - procedure :: levscls_index - procedure :: levcapf_index - procedure :: levcacls_index - procedure :: levpft_index - procedure :: levage_index - procedure :: levfuel_index - procedure :: levcwdsc_index - 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 - procedure :: levheight_index - procedure :: levelem_index - procedure :: levelpft_index - procedure :: levelcwd_index - procedure :: levelage_index - procedure :: levagefuel_index - procedure :: levclscpf_index - procedure :: levlanduse_index - procedure :: levlulu_index - procedure :: levlupft_index - - ! private work functions - procedure, private :: define_history_vars - procedure, private :: per_ageclass_norm_info - procedure, private :: set_history_var - procedure, private :: init_dim_kinds_maps - procedure, private :: set_dim_indices - procedure, private :: set_column_index - procedure, private :: set_levsoil_index - procedure, private :: set_levscpf_index - procedure, private :: set_levcacls_index - procedure, private :: set_levcapf_index - procedure, private :: set_levscls_index - procedure, private :: set_levpft_index - procedure, private :: set_levage_index - procedure, private :: set_levfuel_index - procedure, private :: set_levcwdsc_index - 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_levlanduse_index - procedure, private :: set_levlulu_index - procedure, private :: set_levlupft_index - procedure, private :: set_levelem_index - procedure, private :: set_levelpft_index - procedure, private :: set_levelcwd_index - procedure, private :: set_levelage_index - - procedure, public :: flush_hvars - procedure, public :: zero_site_hvars - procedure, public :: flush_all_hvars - - end type fates_history_interface_type - - character(len=*), parameter :: sourcefile = & - __FILE__ - - - ! The instance of the type - - type(fates_history_interface_type), public :: fates_hist + procedure :: Init + procedure :: SetThreadBoundsEach + procedure :: initialize_history_vars + procedure :: assemble_history_output_types + + procedure :: update_history_dyn + procedure :: update_history_dyn_sitelevel + procedure :: update_history_dyn_subsite + procedure :: update_history_dyn_subsite_ageclass + procedure :: reset_history_dyn_subsite + procedure :: update_history_hifrq + procedure :: update_history_hifrq_sitelevel + procedure :: update_history_hifrq_subsite + procedure :: update_history_hifrq_subsite_ageclass + procedure :: update_history_hydraulics + procedure :: update_history_nutrflux + + ! 'get' methods used by external callers to access private read only data + + procedure :: num_history_vars + procedure :: column_index + procedure :: levsoil_index + procedure :: levscpf_index + procedure :: levscls_index + procedure :: levcapf_index + procedure :: levcacls_index + procedure :: levpft_index + procedure :: levage_index + procedure :: levfuel_index + procedure :: levcwdsc_index + 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 + procedure :: levheight_index + procedure :: levelem_index + procedure :: levelpft_index + procedure :: levelcwd_index + procedure :: levelage_index + procedure :: levagefuel_index + procedure :: levclscpf_index + procedure :: levlanduse_index + procedure :: levlulu_index + procedure :: levlupft_index + + ! private work functions + procedure, private :: define_history_vars + procedure, private :: per_ageclass_norm_info + procedure, private :: set_history_var + procedure, private :: init_dim_kinds_maps + procedure, private :: set_dim_indices + procedure, private :: set_column_index + procedure, private :: set_levsoil_index + procedure, private :: set_levscpf_index + procedure, private :: set_levcacls_index + procedure, private :: set_levcapf_index + procedure, private :: set_levscls_index + procedure, private :: set_levpft_index + procedure, private :: set_levage_index + procedure, private :: set_levfuel_index + procedure, private :: set_levcwdsc_index + 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_levlanduse_index + procedure, private :: set_levlulu_index + procedure, private :: set_levlupft_index + procedure, private :: set_levelem_index + procedure, private :: set_levelpft_index + procedure, private :: set_levelcwd_index + procedure, private :: set_levelage_index + + procedure, public :: flush_hvars + procedure, public :: zero_site_hvars + procedure, public :: flush_all_hvars + + end type fates_history_interface_type + + character(len=*), parameter :: sourcefile = & + __FILE__ + + + ! The instance of the type + + type(fates_history_interface_type), public :: fates_hist contains - ! ====================================================================== + ! ====================================================================== - subroutine Init(this, num_threads, fates_bounds) + subroutine Init(this, num_threads, fates_bounds) - use FatesIODimensionsMod, only : column, levsoil, levscpf - use FatesIODimensionsMod, only : levscls, levpft, levage - use FatesIODimensionsMod, only : levcacls, levcapf - use FatesIODimensionsMod, only : levfuel, levcwdsc, levscag - use FatesIODimensionsMod, only : levscagpft, levagepft - use FatesIODimensionsMod, only : levcan, levcnlf, levcnlfpft - use FatesIODimensionsMod, only : fates_bounds_type - use FatesIODimensionsMod, only : levheight, levagefuel - use FatesIODimensionsMod, only : levelem, levelpft - use FatesIODimensionsMod, only : levelcwd, levelage, levclscpf - use FatesIODimensionsMod, only : levcdpf, levcdsc, levcdam - use FatesIODimensionsMod, only : levlanduse, levlulu, levlupft + use FatesIODimensionsMod, only : column, levsoil, levscpf + use FatesIODimensionsMod, only : levscls, levpft, levage + use FatesIODimensionsMod, only : levcacls, levcapf + use FatesIODimensionsMod, only : levfuel, levcwdsc, levscag + use FatesIODimensionsMod, only : levscagpft, levagepft + use FatesIODimensionsMod, only : levcan, levcnlf, levcnlfpft + use FatesIODimensionsMod, only : fates_bounds_type + use FatesIODimensionsMod, only : levheight, levagefuel + use FatesIODimensionsMod, only : levelem, levelpft + use FatesIODimensionsMod, only : levelcwd, levelage, levclscpf + use FatesIODimensionsMod, only : levcdpf, levcdsc, levcdam + use FatesIODimensionsMod, only : levlanduse, levlulu, levlupft - implicit none + implicit none - class(fates_history_interface_type), intent(inout) :: this - integer, intent(in) :: num_threads - type(fates_bounds_type), intent(in) :: fates_bounds + class(fates_history_interface_type), intent(inout) :: this + integer, intent(in) :: num_threads + type(fates_bounds_type), intent(in) :: fates_bounds - integer :: dim_count = 0 + integer :: dim_count = 0 - dim_count = dim_count + 1 - call this%set_column_index(dim_count) - call this%dim_bounds(dim_count)%Init(column, num_threads, & + dim_count = dim_count + 1 + call this%set_column_index(dim_count) + call this%dim_bounds(dim_count)%Init(column, num_threads, & fates_bounds%column_begin, fates_bounds%column_end) - dim_count = dim_count + 1 - call this%set_levsoil_index(dim_count) - call this%dim_bounds(dim_count)%Init(levsoil, num_threads, & + dim_count = dim_count + 1 + call this%set_levsoil_index(dim_count) + call this%dim_bounds(dim_count)%Init(levsoil, num_threads, & fates_bounds%soil_begin, fates_bounds%soil_end) - dim_count = dim_count + 1 - call this%set_levscpf_index(dim_count) - call this%dim_bounds(dim_count)%Init(levscpf, num_threads, & + dim_count = dim_count + 1 + call this%set_levscpf_index(dim_count) + call this%dim_bounds(dim_count)%Init(levscpf, num_threads, & fates_bounds%sizepft_class_begin, fates_bounds%sizepft_class_end) - dim_count = dim_count + 1 - call this%set_levscls_index(dim_count) - call this%dim_bounds(dim_count)%Init(levscls, num_threads, & + dim_count = dim_count + 1 + call this%set_levscls_index(dim_count) + call this%dim_bounds(dim_count)%Init(levscls, num_threads, & fates_bounds%size_class_begin, fates_bounds%size_class_end) - dim_count = dim_count + 1 - call this%set_levcacls_index(dim_count) - call this%dim_bounds(dim_count)%Init(levcacls, num_threads, & + dim_count = dim_count + 1 + call this%set_levcacls_index(dim_count) + call this%dim_bounds(dim_count)%Init(levcacls, num_threads, & fates_bounds%coage_class_begin, fates_bounds%coage_class_end) - dim_count = dim_count + 1 - call this%set_levcapf_index(dim_count) - call this%dim_bounds(dim_count)%Init(levcapf, num_threads, & + dim_count = dim_count + 1 + call this%set_levcapf_index(dim_count) + call this%dim_bounds(dim_count)%Init(levcapf, num_threads, & fates_bounds%coagepf_class_begin, fates_bounds%coagepf_class_end) - dim_count = dim_count + 1 - call this%set_levpft_index(dim_count) - call this%dim_bounds(dim_count)%Init(levpft, num_threads, & + dim_count = dim_count + 1 + call this%set_levpft_index(dim_count) + call this%dim_bounds(dim_count)%Init(levpft, num_threads, & fates_bounds%pft_class_begin, fates_bounds%pft_class_end) - dim_count = dim_count + 1 - call this%set_levage_index(dim_count) - call this%dim_bounds(dim_count)%Init(levage, num_threads, & + dim_count = dim_count + 1 + call this%set_levage_index(dim_count) + call this%dim_bounds(dim_count)%Init(levage, num_threads, & fates_bounds%age_class_begin, fates_bounds%age_class_end) - dim_count = dim_count + 1 - call this%set_levfuel_index(dim_count) - call this%dim_bounds(dim_count)%Init(levfuel, num_threads, & + dim_count = dim_count + 1 + call this%set_levfuel_index(dim_count) + call this%dim_bounds(dim_count)%Init(levfuel, num_threads, & fates_bounds%fuel_begin, fates_bounds%fuel_end) - dim_count = dim_count + 1 - call this%set_levcwdsc_index(dim_count) - call this%dim_bounds(dim_count)%Init(levcwdsc, num_threads, & + dim_count = dim_count + 1 + call this%set_levcwdsc_index(dim_count) + call this%dim_bounds(dim_count)%Init(levcwdsc, num_threads, & fates_bounds%cwdsc_begin, fates_bounds%cwdsc_end) - dim_count = dim_count + 1 - call this%set_levcan_index(dim_count) - call this%dim_bounds(dim_count)%Init(levcan, num_threads, & + dim_count = dim_count + 1 + call this%set_levcan_index(dim_count) + call this%dim_bounds(dim_count)%Init(levcan, num_threads, & fates_bounds%can_begin, fates_bounds%can_end) - dim_count = dim_count + 1 - call this%set_levcnlf_index(dim_count) - call this%dim_bounds(dim_count)%Init(levcnlf, num_threads, & + dim_count = dim_count + 1 + call this%set_levcnlf_index(dim_count) + call this%dim_bounds(dim_count)%Init(levcnlf, num_threads, & fates_bounds%cnlf_begin, fates_bounds%cnlf_end) - dim_count = dim_count + 1 - call this%set_levcnlfpft_index(dim_count) - call this%dim_bounds(dim_count)%Init(levcnlfpft, num_threads, & + dim_count = dim_count + 1 + call this%set_levcnlfpft_index(dim_count) + 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, & + 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, & + 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, & + 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, & + dim_count = dim_count + 1 + call this%set_levscag_index(dim_count) + call this%dim_bounds(dim_count)%Init(levscag, num_threads, & fates_bounds%sizeage_class_begin, fates_bounds%sizeage_class_end) - dim_count = dim_count + 1 - call this%set_levscagpft_index(dim_count) - call this%dim_bounds(dim_count)%Init(levscagpft, num_threads, & + dim_count = dim_count + 1 + call this%set_levscagpft_index(dim_count) + call this%dim_bounds(dim_count)%Init(levscagpft, num_threads, & fates_bounds%sizeagepft_class_begin, fates_bounds%sizeagepft_class_end) - dim_count = dim_count + 1 - call this%set_levagepft_index(dim_count) - call this%dim_bounds(dim_count)%Init(levagepft, num_threads, & + dim_count = dim_count + 1 + call this%set_levagepft_index(dim_count) + call this%dim_bounds(dim_count)%Init(levagepft, num_threads, & fates_bounds%agepft_class_begin, fates_bounds%agepft_class_end) - dim_count = dim_count + 1 - call this%set_levheight_index(dim_count) - call this%dim_bounds(dim_count)%Init(levheight, num_threads, & + dim_count = dim_count + 1 + call this%set_levheight_index(dim_count) + call this%dim_bounds(dim_count)%Init(levheight, num_threads, & fates_bounds%height_begin, fates_bounds%height_end) - dim_count = dim_count + 1 - call this%set_levelem_index(dim_count) - call this%dim_bounds(dim_count)%Init(levelem, num_threads, & + dim_count = dim_count + 1 + call this%set_levelem_index(dim_count) + call this%dim_bounds(dim_count)%Init(levelem, num_threads, & fates_bounds%elem_begin, fates_bounds%elem_end) - dim_count = dim_count + 1 - call this%set_levelpft_index(dim_count) - call this%dim_bounds(dim_count)%Init(levelpft, num_threads, & + dim_count = dim_count + 1 + call this%set_levelpft_index(dim_count) + call this%dim_bounds(dim_count)%Init(levelpft, num_threads, & fates_bounds%elpft_begin, fates_bounds%elpft_end) - dim_count = dim_count + 1 - call this%set_levelcwd_index(dim_count) - call this%dim_bounds(dim_count)%Init(levelcwd, num_threads, & + dim_count = dim_count + 1 + call this%set_levelcwd_index(dim_count) + call this%dim_bounds(dim_count)%Init(levelcwd, num_threads, & fates_bounds%elcwd_begin, fates_bounds%elcwd_end) - dim_count = dim_count + 1 - call this%set_levelage_index(dim_count) - call this%dim_bounds(dim_count)%Init(levelage, num_threads, & + dim_count = dim_count + 1 + call this%set_levelage_index(dim_count) + call this%dim_bounds(dim_count)%Init(levelage, num_threads, & fates_bounds%elage_begin, fates_bounds%elage_end) - dim_count = dim_count + 1 - call this%set_levagefuel_index(dim_count) - call this%dim_bounds(dim_count)%Init(levagefuel, num_threads, & + dim_count = dim_count + 1 + call this%set_levagefuel_index(dim_count) + 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, & + 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) - dim_count = dim_count + 1 - call this%set_levlanduse_index(dim_count) - call this%dim_bounds(dim_count)%Init(levlanduse, num_threads, & + dim_count = dim_count + 1 + call this%set_levlanduse_index(dim_count) + call this%dim_bounds(dim_count)%Init(levlanduse, num_threads, & fates_bounds%landuse_begin, fates_bounds%landuse_end) - dim_count = dim_count + 1 - call this%set_levlulu_index(dim_count) - call this%dim_bounds(dim_count)%Init(levlulu, num_threads, & + dim_count = dim_count + 1 + call this%set_levlulu_index(dim_count) + call this%dim_bounds(dim_count)%Init(levlulu, num_threads, & fates_bounds%lulu_begin, fates_bounds%lulu_end) - dim_count = dim_count + 1 - call this%set_levlupft_index(dim_count) - call this%dim_bounds(dim_count)%Init(levlupft, num_threads, & + dim_count = dim_count + 1 + call this%set_levlupft_index(dim_count) + call this%dim_bounds(dim_count)%Init(levlupft, num_threads, & fates_bounds%lupft_begin, fates_bounds%lupft_end) - end subroutine Init + end subroutine Init - ! ====================================================================== - subroutine SetThreadBoundsEach(this, thread_index, thread_bounds) + ! ====================================================================== + subroutine SetThreadBoundsEach(this, thread_index, thread_bounds) - use FatesIODimensionsMod, only : fates_bounds_type + use FatesIODimensionsMod, only : fates_bounds_type - implicit none + implicit none - class(fates_history_interface_type), intent(inout) :: this + class(fates_history_interface_type), intent(inout) :: this - integer, intent(in) :: thread_index - type(fates_bounds_type), intent(in) :: thread_bounds + integer, intent(in) :: thread_index + type(fates_bounds_type), intent(in) :: thread_bounds - integer :: index + integer :: index - index = this%column_index() - call this%dim_bounds(index)%SetThreadBounds(thread_index, & + index = this%column_index() + call this%dim_bounds(index)%SetThreadBounds(thread_index, & thread_bounds%column_begin, thread_bounds%column_end) - index = this%levsoil_index() - call this%dim_bounds(index)%SetThreadBounds(thread_index, & + index = this%levsoil_index() + call this%dim_bounds(index)%SetThreadBounds(thread_index, & thread_bounds%soil_begin, thread_bounds%soil_end) - index = this%levscpf_index() - call this%dim_bounds(index)%SetThreadBounds(thread_index, & + index = this%levscpf_index() + call this%dim_bounds(index)%SetThreadBounds(thread_index, & thread_bounds%sizepft_class_begin, thread_bounds%sizepft_class_end) - index = this%levscls_index() - call this%dim_bounds(index)%SetThreadBounds(thread_index, & + index = this%levscls_index() + call this%dim_bounds(index)%SetThreadBounds(thread_index, & thread_bounds%size_class_begin, thread_bounds%size_class_end) - index = this%levcacls_index() - call this%dim_bounds(index)%SetThreadBounds(thread_index, & + index = this%levcacls_index() + call this%dim_bounds(index)%SetThreadBounds(thread_index, & thread_bounds%coage_class_begin, thread_bounds%coage_class_end) - index = this%levcapf_index() - call this%dim_bounds(index)%SetThreadBounds(thread_index, & + index = this%levcapf_index() + call this%dim_bounds(index)%SetThreadBounds(thread_index, & thread_bounds%coagepf_class_begin, thread_bounds%coagepf_class_end) - index = this%levpft_index() - call this%dim_bounds(index)%SetThreadBounds(thread_index, & + index = this%levpft_index() + call this%dim_bounds(index)%SetThreadBounds(thread_index, & thread_bounds%pft_class_begin, thread_bounds%pft_class_end) - index = this%levage_index() - call this%dim_bounds(index)%SetThreadBounds(thread_index, & + index = this%levage_index() + call this%dim_bounds(index)%SetThreadBounds(thread_index, & thread_bounds%age_class_begin, thread_bounds%age_class_end) - index = this%levfuel_index() - call this%dim_bounds(index)%SetThreadBounds(thread_index, & + index = this%levfuel_index() + call this%dim_bounds(index)%SetThreadBounds(thread_index, & thread_bounds%fuel_begin, thread_bounds%fuel_end) - index = this%levcwdsc_index() - call this%dim_bounds(index)%SetThreadBounds(thread_index, & + index = this%levcwdsc_index() + call this%dim_bounds(index)%SetThreadBounds(thread_index, & thread_bounds%cwdsc_begin, thread_bounds%cwdsc_end) - index = this%levcan_index() - call this%dim_bounds(index)%SetThreadBounds(thread_index, & + index = this%levcan_index() + call this%dim_bounds(index)%SetThreadBounds(thread_index, & thread_bounds%can_begin, thread_bounds%can_end) - index = this%levcnlf_index() - call this%dim_bounds(index)%SetThreadBounds(thread_index, & + index = this%levcnlf_index() + call this%dim_bounds(index)%SetThreadBounds(thread_index, & thread_bounds%cnlf_begin, thread_bounds%cnlf_end) - index = this%levcnlfpft_index() - call this%dim_bounds(index)%SetThreadBounds(thread_index, & + index = this%levcnlfpft_index() + 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, & + 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, & + 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, & + 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, & + index = this%levscag_index() + call this%dim_bounds(index)%SetThreadBounds(thread_index, & thread_bounds%sizeage_class_begin, thread_bounds%sizeage_class_end) - index = this%levscagpft_index() - call this%dim_bounds(index)%SetThreadBounds(thread_index, & + index = this%levscagpft_index() + call this%dim_bounds(index)%SetThreadBounds(thread_index, & thread_bounds%sizeagepft_class_begin, thread_bounds%sizeagepft_class_end) - index = this%levagepft_index() - call this%dim_bounds(index)%SetThreadBounds(thread_index, & + index = this%levagepft_index() + call this%dim_bounds(index)%SetThreadBounds(thread_index, & thread_bounds%agepft_class_begin, thread_bounds%agepft_class_end) - index = this%levheight_index() - call this%dim_bounds(index)%SetThreadBounds(thread_index, & + index = this%levheight_index() + call this%dim_bounds(index)%SetThreadBounds(thread_index, & thread_bounds%height_begin, thread_bounds%height_end) - index = this%levelem_index() - call this%dim_bounds(index)%SetThreadBounds(thread_index, & + index = this%levelem_index() + call this%dim_bounds(index)%SetThreadBounds(thread_index, & thread_bounds%elem_begin, thread_bounds%elem_end) - index = this%levelpft_index() - call this%dim_bounds(index)%SetThreadBounds(thread_index, & + index = this%levelpft_index() + call this%dim_bounds(index)%SetThreadBounds(thread_index, & thread_bounds%elpft_begin, thread_bounds%elpft_end) - index = this%levelcwd_index() - call this%dim_bounds(index)%SetThreadBounds(thread_index, & + index = this%levelcwd_index() + call this%dim_bounds(index)%SetThreadBounds(thread_index, & thread_bounds%elcwd_begin, thread_bounds%elcwd_end) - index = this%levelage_index() - call this%dim_bounds(index)%SetThreadBounds(thread_index, & + index = this%levelage_index() + call this%dim_bounds(index)%SetThreadBounds(thread_index, & thread_bounds%elage_begin, thread_bounds%elage_end) - index = this%levagefuel_index() - call this%dim_bounds(index)%SetThreadBounds(thread_index, & + index = this%levagefuel_index() + 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, & + index = this%levclscpf_index() + call this%dim_bounds(index)%SetThreadBounds(thread_index, & thread_bounds%clscpf_begin, thread_bounds%clscpf_end) - index = this%levlanduse_index() - call this%dim_bounds(index)%SetThreadBounds(thread_index, & + index = this%levlanduse_index() + call this%dim_bounds(index)%SetThreadBounds(thread_index, & thread_bounds%landuse_begin, thread_bounds%landuse_end) - index = this%levlulu_index() - call this%dim_bounds(index)%SetThreadBounds(thread_index, & + index = this%levlulu_index() + call this%dim_bounds(index)%SetThreadBounds(thread_index, & thread_bounds%lulu_begin, thread_bounds%lulu_end) - index = this%levlupft_index() - call this%dim_bounds(index)%SetThreadBounds(thread_index, & + index = this%levlupft_index() + call this%dim_bounds(index)%SetThreadBounds(thread_index, & thread_bounds%lupft_begin, thread_bounds%lupft_end) - end subroutine SetThreadBoundsEach + end subroutine SetThreadBoundsEach - ! =================================================================================== - subroutine assemble_history_output_types(this) + ! =================================================================================== + subroutine assemble_history_output_types(this) - implicit none + implicit none - class(fates_history_interface_type), intent(inout) :: this + class(fates_history_interface_type), intent(inout) :: this - call this%init_dim_kinds_maps() + call this%init_dim_kinds_maps() - call this%set_dim_indices(site_r8, 1, this%column_index()) + call this%set_dim_indices(site_r8, 1, this%column_index()) - call this%set_dim_indices(site_soil_r8, 1, this%column_index()) - call this%set_dim_indices(site_soil_r8, 2, this%levsoil_index()) + call this%set_dim_indices(site_soil_r8, 1, this%column_index()) + call this%set_dim_indices(site_soil_r8, 2, this%levsoil_index()) - call this%set_dim_indices(site_size_pft_r8, 1, this%column_index()) - call this%set_dim_indices(site_size_pft_r8, 2, this%levscpf_index()) + call this%set_dim_indices(site_size_pft_r8, 1, this%column_index()) + call this%set_dim_indices(site_size_pft_r8, 2, this%levscpf_index()) - call this%set_dim_indices(site_size_r8, 1, this%column_index()) - call this%set_dim_indices(site_size_r8, 2, this%levscls_index()) + call this%set_dim_indices(site_size_r8, 1, this%column_index()) + call this%set_dim_indices(site_size_r8, 2, this%levscls_index()) - call this%set_dim_indices(site_coage_r8, 1, this%column_index()) - call this%set_dim_indices(site_coage_r8, 2, this%levcacls_index()) + call this%set_dim_indices(site_coage_r8, 1, this%column_index()) + call this%set_dim_indices(site_coage_r8, 2, this%levcacls_index()) - call this%set_dim_indices(site_coage_pft_r8, 1, this%column_index()) - call this%set_dim_indices(site_coage_pft_r8, 2, this%levcapf_index()) + call this%set_dim_indices(site_coage_pft_r8, 1, this%column_index()) + call this%set_dim_indices(site_coage_pft_r8, 2, this%levcapf_index()) - call this%set_dim_indices(site_pft_r8, 1, this%column_index()) - call this%set_dim_indices(site_pft_r8, 2, this%levpft_index()) + call this%set_dim_indices(site_pft_r8, 1, this%column_index()) + call this%set_dim_indices(site_pft_r8, 2, this%levpft_index()) - call this%set_dim_indices(site_age_r8, 1, this%column_index()) - call this%set_dim_indices(site_age_r8, 2, this%levage_index()) + call this%set_dim_indices(site_age_r8, 1, this%column_index()) + call this%set_dim_indices(site_age_r8, 2, this%levage_index()) - call this%set_dim_indices(site_fuel_r8, 1, this%column_index()) - call this%set_dim_indices(site_fuel_r8, 2, this%levfuel_index()) + call this%set_dim_indices(site_fuel_r8, 1, this%column_index()) + call this%set_dim_indices(site_fuel_r8, 2, this%levfuel_index()) - call this%set_dim_indices(site_cwdsc_r8, 1, this%column_index()) - call this%set_dim_indices(site_cwdsc_r8, 2, this%levcwdsc_index()) + call this%set_dim_indices(site_cwdsc_r8, 1, this%column_index()) + call this%set_dim_indices(site_cwdsc_r8, 2, this%levcwdsc_index()) - call this%set_dim_indices(site_can_r8, 1, this%column_index()) - call this%set_dim_indices(site_can_r8, 2, this%levcan_index()) + call this%set_dim_indices(site_can_r8, 1, this%column_index()) + call this%set_dim_indices(site_can_r8, 2, this%levcan_index()) - call this%set_dim_indices(site_cnlf_r8, 1, this%column_index()) - call this%set_dim_indices(site_cnlf_r8, 2, this%levcnlf_index()) + call this%set_dim_indices(site_cnlf_r8, 1, this%column_index()) + call this%set_dim_indices(site_cnlf_r8, 2, this%levcnlf_index()) - 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_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_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_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_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()) + call this%set_dim_indices(site_scag_r8, 1, this%column_index()) + call this%set_dim_indices(site_scag_r8, 2, this%levscag_index()) - call this%set_dim_indices(site_scagpft_r8, 1, this%column_index()) - call this%set_dim_indices(site_scagpft_r8, 2, this%levscagpft_index()) + call this%set_dim_indices(site_scagpft_r8, 1, this%column_index()) + call this%set_dim_indices(site_scagpft_r8, 2, this%levscagpft_index()) - call this%set_dim_indices(site_agepft_r8, 1, this%column_index()) - call this%set_dim_indices(site_agepft_r8, 2, this%levagepft_index()) + call this%set_dim_indices(site_agepft_r8, 1, this%column_index()) + call this%set_dim_indices(site_agepft_r8, 2, this%levagepft_index()) - call this%set_dim_indices(site_height_r8, 1, this%column_index()) - call this%set_dim_indices(site_height_r8, 2, this%levheight_index()) + call this%set_dim_indices(site_height_r8, 1, this%column_index()) + call this%set_dim_indices(site_height_r8, 2, this%levheight_index()) - call this%set_dim_indices(site_elem_r8, 1, this%column_index()) - call this%set_dim_indices(site_elem_r8, 2, this%levelem_index()) + call this%set_dim_indices(site_elem_r8, 1, this%column_index()) + call this%set_dim_indices(site_elem_r8, 2, this%levelem_index()) - call this%set_dim_indices(site_elpft_r8, 1, this%column_index()) - call this%set_dim_indices(site_elpft_r8, 2, this%levelpft_index()) + call this%set_dim_indices(site_elpft_r8, 1, this%column_index()) + call this%set_dim_indices(site_elpft_r8, 2, this%levelpft_index()) - call this%set_dim_indices(site_elcwd_r8, 1, this%column_index()) - call this%set_dim_indices(site_elcwd_r8, 2, this%levelcwd_index()) + call this%set_dim_indices(site_elcwd_r8, 1, this%column_index()) + call this%set_dim_indices(site_elcwd_r8, 2, this%levelcwd_index()) - call this%set_dim_indices(site_elage_r8, 1, this%column_index()) - call this%set_dim_indices(site_elage_r8, 2, this%levelage_index()) + call this%set_dim_indices(site_elage_r8, 1, this%column_index()) + call this%set_dim_indices(site_elage_r8, 2, this%levelage_index()) - 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_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()) + call this%set_dim_indices(site_clscpf_r8, 1, this%column_index()) + call this%set_dim_indices(site_clscpf_r8, 2, this%levclscpf_index()) - call this%set_dim_indices(site_landuse_r8, 1, this%column_index()) - call this%set_dim_indices(site_landuse_r8, 2, this%levlanduse_index()) + call this%set_dim_indices(site_landuse_r8, 1, this%column_index()) + call this%set_dim_indices(site_landuse_r8, 2, this%levlanduse_index()) - call this%set_dim_indices(site_lulu_r8, 1, this%column_index()) - call this%set_dim_indices(site_lulu_r8, 2, this%levlulu_index()) + call this%set_dim_indices(site_lulu_r8, 1, this%column_index()) + call this%set_dim_indices(site_lulu_r8, 2, this%levlulu_index()) - call this%set_dim_indices(site_lupft_r8, 1, this%column_index()) - call this%set_dim_indices(site_lupft_r8, 2, this%levlupft_index()) + call this%set_dim_indices(site_lupft_r8, 1, this%column_index()) + call this%set_dim_indices(site_lupft_r8, 2, this%levlupft_index()) - end subroutine assemble_history_output_types + end subroutine assemble_history_output_types - ! =================================================================================== + ! =================================================================================== - subroutine set_dim_indices(this, dk_name, idim, dim_index) + subroutine set_dim_indices(this, dk_name, idim, dim_index) - use FatesIOVariableKindMod , only : iotype_index + use FatesIOVariableKindMod , only : iotype_index - implicit none + implicit none - ! arguments - class(fates_history_interface_type), intent(inout) :: this - character(len=*), intent(in) :: dk_name - integer, intent(in) :: idim ! dimension index - integer, intent(in) :: dim_index + ! arguments + class(fates_history_interface_type), intent(inout) :: this + character(len=*), intent(in) :: dk_name + integer, intent(in) :: idim ! dimension index + integer, intent(in) :: dim_index - ! local - integer :: ityp + ! local + integer :: ityp - ityp = iotype_index(trim(dk_name), fates_history_num_dim_kinds, this%dim_kinds) + ityp = iotype_index(trim(dk_name), fates_history_num_dim_kinds, this%dim_kinds) - ! First check to see if the dimension is allocated - if (this%dim_kinds(ityp)%ndims < idim) then - 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 - call endrun(msg=errMsg(sourcefile, __LINE__)) - end if + ! First check to see if the dimension is allocated + if (this%dim_kinds(ityp)%ndims < idim) then + 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 + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if - if (idim == 1) then - this%dim_kinds(ityp)%dim1_index = dim_index - else if (idim == 2) then - this%dim_kinds(ityp)%dim2_index = dim_index - end if + if (idim == 1) then + this%dim_kinds(ityp)%dim1_index = dim_index + else if (idim == 2) then + this%dim_kinds(ityp)%dim2_index = dim_index + end if - ! With the map, we can set the dimension size - this%dim_kinds(ityp)%dimsize(idim) = this%dim_bounds(dim_index)%upper_bound - & + ! With the map, we can set the dimension size + this%dim_kinds(ityp)%dimsize(idim) = this%dim_bounds(dim_index)%upper_bound - & this%dim_bounds(dim_index)%lower_bound + 1 - end subroutine set_dim_indices - - ! ======================================================================= - subroutine set_column_index(this, index) - implicit none - class(fates_history_interface_type), intent(inout) :: this - integer, intent(in) :: index - this%column_index_ = index - end subroutine set_column_index - - integer function column_index(this) - implicit none - class(fates_history_interface_type), intent(in) :: this - column_index = this%column_index_ - end function column_index - - ! ======================================================================= - subroutine set_levsoil_index(this, index) - implicit none - class(fates_history_interface_type), intent(inout) :: this - integer, intent(in) :: index - this%levsoil_index_ = index - end subroutine set_levsoil_index - - integer function levsoil_index(this) - implicit none - class(fates_history_interface_type), intent(in) :: this - levsoil_index = this%levsoil_index_ - end function levsoil_index - - ! ======================================================================= - subroutine set_levscpf_index(this, index) - implicit none - class(fates_history_interface_type), intent(inout) :: this - integer, intent(in) :: index - this%levscpf_index_ = index - end subroutine set_levscpf_index - - integer function levscpf_index(this) - implicit none - class(fates_history_interface_type), intent(in) :: this - levscpf_index = this%levscpf_index_ - end function levscpf_index - - ! ======================================================================= - subroutine set_levscls_index(this, index) - implicit none - class(fates_history_interface_type), intent(inout) :: this - integer, intent(in) :: index - this%levscls_index_ = index - end subroutine set_levscls_index - - integer function levscls_index(this) - implicit none - class(fates_history_interface_type), intent(in) :: this - levscls_index = this%levscls_index_ - end function levscls_index - - !========================================================================= - subroutine set_levcacls_index(this, index) - implicit none - class(fates_history_interface_type), intent(inout) :: this - integer, intent(in) :: index - this%levcacls_index_ = index - end subroutine set_levcacls_index - - integer function levcacls_index(this) - implicit none - class(fates_history_interface_type), intent(in) :: this - levcacls_index = this%levcacls_index_ - end function levcacls_index - - !========================================================================= - subroutine set_levcapf_index(this, index) - implicit none - class(fates_history_interface_type), intent(inout) :: this - integer, intent(in) :: index - this%levcapf_index_ = index - end subroutine set_levcapf_index - - integer function levcapf_index(this) - implicit none - class(fates_history_interface_type), intent(in) :: this - levcapf_index = this%levcapf_index_ - end function levcapf_index - - ! ======================================================================= - subroutine set_levpft_index(this, index) - implicit none - class(fates_history_interface_type), intent(inout) :: this - integer, intent(in) :: index - this%levpft_index_ = index - end subroutine set_levpft_index - - integer function levpft_index(this) - implicit none - class(fates_history_interface_type), intent(in) :: this - levpft_index = this%levpft_index_ - end function levpft_index - - ! ======================================================================= - subroutine set_levage_index(this, index) - implicit none - class(fates_history_interface_type), intent(inout) :: this - integer, intent(in) :: index - this%levage_index_ = index - end subroutine set_levage_index - - integer function levage_index(this) - implicit none - class(fates_history_interface_type), intent(in) :: this - levage_index = this%levage_index_ - end function levage_index - - ! ======================================================================= - subroutine set_levfuel_index(this, index) - implicit none - class(fates_history_interface_type), intent(inout) :: this - integer, intent(in) :: index - this%levfuel_index_ = index - end subroutine set_levfuel_index - - integer function levfuel_index(this) - implicit none - class(fates_history_interface_type), intent(in) :: this - levfuel_index = this%levfuel_index_ - end function levfuel_index - - ! ======================================================================= - subroutine set_levcwdsc_index(this, index) - implicit none - class(fates_history_interface_type), intent(inout) :: this - integer, intent(in) :: index - this%levcwdsc_index_ = index - end subroutine set_levcwdsc_index - - integer function levcwdsc_index(this) - implicit none - class(fates_history_interface_type), intent(in) :: this - levcwdsc_index = this%levcwdsc_index_ - end function levcwdsc_index - - ! ======================================================================= - subroutine set_levcan_index(this, index) - implicit none - class(fates_history_interface_type), intent(inout) :: this - integer, intent(in) :: index - this%levcan_index_ = index - end subroutine set_levcan_index - - integer function levcan_index(this) - implicit none - class(fates_history_interface_type), intent(in) :: this - levcan_index = this%levcan_index_ - end function levcan_index - - ! ======================================================================= - subroutine set_levcnlf_index(this, index) - implicit none - class(fates_history_interface_type), intent(inout) :: this - integer, intent(in) :: index - this%levcnlf_index_ = index - end subroutine set_levcnlf_index - - integer function levcnlf_index(this) - implicit none - class(fates_history_interface_type), intent(in) :: this - levcnlf_index = this%levcnlf_index_ - end function levcnlf_index - - ! ======================================================================= - subroutine set_levcnlfpft_index(this, index) - implicit none - class(fates_history_interface_type), intent(inout) :: this - integer, intent(in) :: index - this%levcnlfpft_index_ = index - end subroutine set_levcnlfpft_index - - integer function levcnlfpft_index(this) - implicit none - class(fates_history_interface_type), intent(in) :: 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 - class(fates_history_interface_type), intent(inout) :: this - integer, intent(in) :: index - this%levscag_index_ = index - end subroutine set_levscag_index - - integer function levscag_index(this) - implicit none - class(fates_history_interface_type), intent(in) :: this - levscag_index = this%levscag_index_ - end function levscag_index - - ! ====================================================================================== - subroutine set_levscagpft_index(this, index) - implicit none - class(fates_history_interface_type), intent(inout) :: this - integer, intent(in) :: index - this%levscagpft_index_ = index - end subroutine set_levscagpft_index - - integer function levscagpft_index(this) - implicit none - class(fates_history_interface_type), intent(in) :: this - levscagpft_index = this%levscagpft_index_ - end function levscagpft_index - - ! ====================================================================================== - subroutine set_levagepft_index(this, index) - implicit none - class(fates_history_interface_type), intent(inout) :: this - integer, intent(in) :: index - this%levagepft_index_ = index - end subroutine set_levagepft_index - - integer function levagepft_index(this) - implicit none - class(fates_history_interface_type), intent(in) :: this - levagepft_index = this%levagepft_index_ - end function levagepft_index - - ! ====================================================================================== - subroutine set_levheight_index(this, index) - implicit none - class(fates_history_interface_type), intent(inout) :: this - integer, intent(in) :: index - this%levheight_index_ = index - end subroutine set_levheight_index - - integer function levheight_index(this) - implicit none - class(fates_history_interface_type), intent(in) :: this - levheight_index = this%levheight_index_ - end function levheight_index - - ! ====================================================================================== - - subroutine set_levelem_index(this, index) - implicit none - class(fates_history_interface_type), intent(inout) :: this - integer, intent(in) :: index - this%levelem_index_ = index - end subroutine set_levelem_index - - integer function levelem_index(this) - implicit none - class(fates_history_interface_type), intent(in) :: this - levelem_index = this%levelem_index_ - end function levelem_index - - ! ====================================================================================== - - subroutine set_levelpft_index(this, index) - implicit none - class(fates_history_interface_type), intent(inout) :: this - integer, intent(in) :: index - this%levelpft_index_ = index - end subroutine set_levelpft_index - - integer function levelpft_index(this) - implicit none - class(fates_history_interface_type), intent(in) :: this - levelpft_index = this%levelpft_index_ - end function levelpft_index - - ! ====================================================================================== - - subroutine set_levelcwd_index(this, index) - implicit none - class(fates_history_interface_type), intent(inout) :: this - integer, intent(in) :: index - this%levelcwd_index_ = index - end subroutine set_levelcwd_index - - integer function levelcwd_index(this) - implicit none - class(fates_history_interface_type), intent(in) :: this - levelcwd_index = this%levelcwd_index_ - end function levelcwd_index - - ! ====================================================================================== - - subroutine set_levelage_index(this, index) - implicit none - class(fates_history_interface_type), intent(inout) :: this - integer, intent(in) :: index - this%levelage_index_ = index - end subroutine set_levelage_index - - integer function levelage_index(this) - implicit none - class(fates_history_interface_type), intent(in) :: this - levelage_index = this%levelage_index_ - end function levelage_index - - ! ====================================================================================== - - subroutine set_levagefuel_index(this, index) - implicit none - class(fates_history_interface_type), intent(inout) :: this - integer, intent(in) :: index - this%levagefuel_index_ = index - end subroutine set_levagefuel_index - - integer function levagefuel_index(this) - implicit none - 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 - - ! ====================================================================================== - - subroutine set_levlanduse_index(this, index) - implicit none - class(fates_history_interface_type), intent(inout) :: this - integer, intent(in) :: index - this%levlanduse_index_ = index - end subroutine set_levlanduse_index - - integer function levlanduse_index(this) - implicit none - class(fates_history_interface_type), intent(in) :: this - levlanduse_index = this%levlanduse_index_ - end function levlanduse_index - - ! ====================================================================================== - - subroutine set_levlulu_index(this, index) - implicit none - class(fates_history_interface_type), intent(inout) :: this - integer, intent(in) :: index - this%levlulu_index_ = index - end subroutine set_levlulu_index - - integer function levlulu_index(this) - implicit none - class(fates_history_interface_type), intent(in) :: this - levlulu_index = this%levlulu_index_ - end function levlulu_index - - ! ====================================================================================== - - subroutine set_levlupft_index(this, index) - implicit none - class(fates_history_interface_type), intent(inout) :: this - integer, intent(in) :: index - this%levlupft_index_ = index - end subroutine set_levlupft_index - - integer function levlupft_index(this) - implicit none - class(fates_history_interface_type), intent(in) :: this - levlupft_index = this%levlupft_index_ - end function levlupft_index - - ! ===================================================================================== - - subroutine zero_site_hvars(this, currentSite, upfreq_in) - - ! This routine zero's a history diagnostic variable - ! but only zero's on fates sites - ! This should be called prior to filling the variable - ! and after they have been flushed to the ignore value - - class(fates_history_interface_type) :: this ! hvars_interface instance - integer, intent(in) :: upfreq_in ! - type(ed_site_type), intent(in), target :: currentSite ! site instance - - integer :: ivar ! history variable index - integer :: ndims ! number of dimensions - - do ivar=1,ubound(this%hvars,1) - if (this%hvars(ivar)%upfreq == upfreq_in) then - - ndims = this%dim_kinds(this%hvars(ivar)%dim_kinds_index)%ndims - - if(trim(this%dim_kinds(this%hvars(ivar)%dim_kinds_index)%name) == site_int)then - write(fates_log(),*)'add in zeroing provision for SI_INT' - call endrun(msg=errMsg(sourcefile, __LINE__)) - end if - - if(ndims==1) then - this%hvars(ivar)%r81d(currentSite%h_gid) = 0._r8 - elseif(ndims==2) then - this%hvars(ivar)%r82d(currentSite%h_gid,:) = 0._r8 - elseif(ndims==3) then - this%hvars(ivar)%r83d(currentSite%h_gid,:,:) = 0._r8 - end if - end if - end do - - return - end subroutine zero_site_hvars - - - ! ====================================================================================== - - subroutine flush_all_hvars(this,nc) - - ! A wrapper to flush all active history - ! groups to their flush value - - class(fates_history_interface_type) :: this - integer,intent(in) :: nc - - if(hlm_hist_level_hifrq>0) then - call this%flush_hvars(nc,upfreq_in=group_hifr_simple) - if (hlm_use_planthydro.eq.itrue) call this%flush_hvars(nc,upfreq_in=group_hydr_simple) - if(hlm_hist_level_hifrq>1) then - call this%flush_hvars(nc,upfreq_in=group_hifr_complx) - if (hlm_use_planthydro.eq.itrue) call this%flush_hvars(nc,upfreq_in=group_hydr_complx) - end if - end if - - if(hlm_hist_level_dynam>0) then - call this%flush_hvars(nc,upfreq_in=group_dyna_simple) - call this%flush_hvars(nc,upfreq_in=group_nflx_simple) - if(hlm_hist_level_dynam>1) then - call this%flush_hvars(nc,upfreq_in=group_dyna_complx) - call this%flush_hvars(nc,upfreq_in=group_nflx_complx) - end if - end if - - return - end subroutine flush_all_hvars - - ! ====================================================================================== - - subroutine flush_hvars(this,nc,upfreq_in) - - class(fates_history_interface_type) :: this - integer,intent(in) :: nc - integer,intent(in) :: upfreq_in - integer :: ivar - integer :: lb1,ub1,lb2,ub2 - - do ivar=1,ubound(this%hvars,1) - if (this%hvars(ivar)%upfreq == upfreq_in) then ! Only flush variables with update on dynamics step - call this%hvars(ivar)%HFlush(nc, this%dim_bounds, this%dim_kinds) - end if - end do - - end subroutine flush_hvars - - - ! ===================================================================================== - - subroutine set_history_var(this, vname, units, long, use_default, avgflag, vtype, & - hlms, upfreq, ivar, initialize, index, flush_to_zero) - - use FatesUtilsMod, only : check_hlm_list - use FatesInterfaceTypesMod, only : hlm_name - - implicit none - - ! arguments - class(fates_history_interface_type), intent(inout) :: this - character(len=*), intent(in) :: vname - character(len=*), intent(in) :: units - character(len=*), intent(in) :: long - character(len=*), intent(in) :: use_default - character(len=*), intent(in) :: avgflag - character(len=*), intent(in) :: vtype - character(len=*), intent(in) :: hlms - integer, intent(in) :: upfreq - logical, intent(in) :: initialize - integer, intent(inout) :: ivar - integer, intent(inout) :: index ! This is the index for the variable of - ! interest that is associated with an - ! 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 - integer :: ityp - real(r8) :: flushval - logical :: write_var - - - ! 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 - ivar = ivar+1 - index = ivar - - if (initialize) then - call this%hvars(ivar)%Init(vname, units, long, use_default, & + end subroutine set_dim_indices + + ! ======================================================================= + subroutine set_column_index(this, index) + implicit none + class(fates_history_interface_type), intent(inout) :: this + integer, intent(in) :: index + this%column_index_ = index + end subroutine set_column_index + + integer function column_index(this) + implicit none + class(fates_history_interface_type), intent(in) :: this + column_index = this%column_index_ + end function column_index + + ! ======================================================================= + subroutine set_levsoil_index(this, index) + implicit none + class(fates_history_interface_type), intent(inout) :: this + integer, intent(in) :: index + this%levsoil_index_ = index + end subroutine set_levsoil_index + + integer function levsoil_index(this) + implicit none + class(fates_history_interface_type), intent(in) :: this + levsoil_index = this%levsoil_index_ + end function levsoil_index + + ! ======================================================================= + subroutine set_levscpf_index(this, index) + implicit none + class(fates_history_interface_type), intent(inout) :: this + integer, intent(in) :: index + this%levscpf_index_ = index + end subroutine set_levscpf_index + + integer function levscpf_index(this) + implicit none + class(fates_history_interface_type), intent(in) :: this + levscpf_index = this%levscpf_index_ + end function levscpf_index + + ! ======================================================================= + subroutine set_levscls_index(this, index) + implicit none + class(fates_history_interface_type), intent(inout) :: this + integer, intent(in) :: index + this%levscls_index_ = index + end subroutine set_levscls_index + + integer function levscls_index(this) + implicit none + class(fates_history_interface_type), intent(in) :: this + levscls_index = this%levscls_index_ + end function levscls_index + + !========================================================================= + subroutine set_levcacls_index(this, index) + implicit none + class(fates_history_interface_type), intent(inout) :: this + integer, intent(in) :: index + this%levcacls_index_ = index + end subroutine set_levcacls_index + + integer function levcacls_index(this) + implicit none + class(fates_history_interface_type), intent(in) :: this + levcacls_index = this%levcacls_index_ + end function levcacls_index + + !========================================================================= + subroutine set_levcapf_index(this, index) + implicit none + class(fates_history_interface_type), intent(inout) :: this + integer, intent(in) :: index + this%levcapf_index_ = index + end subroutine set_levcapf_index + + integer function levcapf_index(this) + implicit none + class(fates_history_interface_type), intent(in) :: this + levcapf_index = this%levcapf_index_ + end function levcapf_index + + ! ======================================================================= + subroutine set_levpft_index(this, index) + implicit none + class(fates_history_interface_type), intent(inout) :: this + integer, intent(in) :: index + this%levpft_index_ = index + end subroutine set_levpft_index + + integer function levpft_index(this) + implicit none + class(fates_history_interface_type), intent(in) :: this + levpft_index = this%levpft_index_ + end function levpft_index + + ! ======================================================================= + subroutine set_levage_index(this, index) + implicit none + class(fates_history_interface_type), intent(inout) :: this + integer, intent(in) :: index + this%levage_index_ = index + end subroutine set_levage_index + + integer function levage_index(this) + implicit none + class(fates_history_interface_type), intent(in) :: this + levage_index = this%levage_index_ + end function levage_index + + ! ======================================================================= + subroutine set_levfuel_index(this, index) + implicit none + class(fates_history_interface_type), intent(inout) :: this + integer, intent(in) :: index + this%levfuel_index_ = index + end subroutine set_levfuel_index + + integer function levfuel_index(this) + implicit none + class(fates_history_interface_type), intent(in) :: this + levfuel_index = this%levfuel_index_ + end function levfuel_index + + ! ======================================================================= + subroutine set_levcwdsc_index(this, index) + implicit none + class(fates_history_interface_type), intent(inout) :: this + integer, intent(in) :: index + this%levcwdsc_index_ = index + end subroutine set_levcwdsc_index + + integer function levcwdsc_index(this) + implicit none + class(fates_history_interface_type), intent(in) :: this + levcwdsc_index = this%levcwdsc_index_ + end function levcwdsc_index + + ! ======================================================================= + subroutine set_levcan_index(this, index) + implicit none + class(fates_history_interface_type), intent(inout) :: this + integer, intent(in) :: index + this%levcan_index_ = index + end subroutine set_levcan_index + + integer function levcan_index(this) + implicit none + class(fates_history_interface_type), intent(in) :: this + levcan_index = this%levcan_index_ + end function levcan_index + + ! ======================================================================= + subroutine set_levcnlf_index(this, index) + implicit none + class(fates_history_interface_type), intent(inout) :: this + integer, intent(in) :: index + this%levcnlf_index_ = index + end subroutine set_levcnlf_index + + integer function levcnlf_index(this) + implicit none + class(fates_history_interface_type), intent(in) :: this + levcnlf_index = this%levcnlf_index_ + end function levcnlf_index + + ! ======================================================================= + subroutine set_levcnlfpft_index(this, index) + implicit none + class(fates_history_interface_type), intent(inout) :: this + integer, intent(in) :: index + this%levcnlfpft_index_ = index + end subroutine set_levcnlfpft_index + + integer function levcnlfpft_index(this) + implicit none + class(fates_history_interface_type), intent(in) :: 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 + class(fates_history_interface_type), intent(inout) :: this + integer, intent(in) :: index + this%levscag_index_ = index + end subroutine set_levscag_index + + integer function levscag_index(this) + implicit none + class(fates_history_interface_type), intent(in) :: this + levscag_index = this%levscag_index_ + end function levscag_index + + ! ====================================================================================== + subroutine set_levscagpft_index(this, index) + implicit none + class(fates_history_interface_type), intent(inout) :: this + integer, intent(in) :: index + this%levscagpft_index_ = index + end subroutine set_levscagpft_index + + integer function levscagpft_index(this) + implicit none + class(fates_history_interface_type), intent(in) :: this + levscagpft_index = this%levscagpft_index_ + end function levscagpft_index + + ! ====================================================================================== + subroutine set_levagepft_index(this, index) + implicit none + class(fates_history_interface_type), intent(inout) :: this + integer, intent(in) :: index + this%levagepft_index_ = index + end subroutine set_levagepft_index + + integer function levagepft_index(this) + implicit none + class(fates_history_interface_type), intent(in) :: this + levagepft_index = this%levagepft_index_ + end function levagepft_index + + ! ====================================================================================== + subroutine set_levheight_index(this, index) + implicit none + class(fates_history_interface_type), intent(inout) :: this + integer, intent(in) :: index + this%levheight_index_ = index + end subroutine set_levheight_index + + integer function levheight_index(this) + implicit none + class(fates_history_interface_type), intent(in) :: this + levheight_index = this%levheight_index_ + end function levheight_index + + ! ====================================================================================== + + subroutine set_levelem_index(this, index) + implicit none + class(fates_history_interface_type), intent(inout) :: this + integer, intent(in) :: index + this%levelem_index_ = index + end subroutine set_levelem_index + + integer function levelem_index(this) + implicit none + class(fates_history_interface_type), intent(in) :: this + levelem_index = this%levelem_index_ + end function levelem_index + + ! ====================================================================================== + + subroutine set_levelpft_index(this, index) + implicit none + class(fates_history_interface_type), intent(inout) :: this + integer, intent(in) :: index + this%levelpft_index_ = index + end subroutine set_levelpft_index + + integer function levelpft_index(this) + implicit none + class(fates_history_interface_type), intent(in) :: this + levelpft_index = this%levelpft_index_ + end function levelpft_index + + ! ====================================================================================== + + subroutine set_levelcwd_index(this, index) + implicit none + class(fates_history_interface_type), intent(inout) :: this + integer, intent(in) :: index + this%levelcwd_index_ = index + end subroutine set_levelcwd_index + + integer function levelcwd_index(this) + implicit none + class(fates_history_interface_type), intent(in) :: this + levelcwd_index = this%levelcwd_index_ + end function levelcwd_index + + ! ====================================================================================== + + subroutine set_levelage_index(this, index) + implicit none + class(fates_history_interface_type), intent(inout) :: this + integer, intent(in) :: index + this%levelage_index_ = index + end subroutine set_levelage_index + + integer function levelage_index(this) + implicit none + class(fates_history_interface_type), intent(in) :: this + levelage_index = this%levelage_index_ + end function levelage_index + + ! ====================================================================================== + + subroutine set_levagefuel_index(this, index) + implicit none + class(fates_history_interface_type), intent(inout) :: this + integer, intent(in) :: index + this%levagefuel_index_ = index + end subroutine set_levagefuel_index + + integer function levagefuel_index(this) + implicit none + 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 + + ! ====================================================================================== + + subroutine set_levlanduse_index(this, index) + implicit none + class(fates_history_interface_type), intent(inout) :: this + integer, intent(in) :: index + this%levlanduse_index_ = index + end subroutine set_levlanduse_index + + integer function levlanduse_index(this) + implicit none + class(fates_history_interface_type), intent(in) :: this + levlanduse_index = this%levlanduse_index_ + end function levlanduse_index + + ! ====================================================================================== + + subroutine set_levlulu_index(this, index) + implicit none + class(fates_history_interface_type), intent(inout) :: this + integer, intent(in) :: index + this%levlulu_index_ = index + end subroutine set_levlulu_index + + integer function levlulu_index(this) + implicit none + class(fates_history_interface_type), intent(in) :: this + levlulu_index = this%levlulu_index_ + end function levlulu_index + + ! ====================================================================================== + + subroutine set_levlupft_index(this, index) + implicit none + class(fates_history_interface_type), intent(inout) :: this + integer, intent(in) :: index + this%levlupft_index_ = index + end subroutine set_levlupft_index + + integer function levlupft_index(this) + implicit none + class(fates_history_interface_type), intent(in) :: this + levlupft_index = this%levlupft_index_ + end function levlupft_index + + ! ===================================================================================== + + subroutine zero_site_hvars(this, currentSite, upfreq_in) + + ! This routine zero's a history diagnostic variable + ! but only zero's on fates sites + ! This should be called prior to filling the variable + ! and after they have been flushed to the ignore value + + class(fates_history_interface_type) :: this ! hvars_interface instance + integer, intent(in) :: upfreq_in ! + type(ed_site_type), intent(in), target :: currentSite ! site instance + + integer :: ivar ! history variable index + integer :: ndims ! number of dimensions + + do ivar=1,ubound(this%hvars,1) + if (this%hvars(ivar)%upfreq == upfreq_in) then + + ndims = this%dim_kinds(this%hvars(ivar)%dim_kinds_index)%ndims + + if(trim(this%dim_kinds(this%hvars(ivar)%dim_kinds_index)%name) == site_int)then + write(fates_log(),*)'add in zeroing provision for SI_INT' + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + + if(ndims==1) then + this%hvars(ivar)%r81d(currentSite%h_gid) = 0._r8 + elseif(ndims==2) then + this%hvars(ivar)%r82d(currentSite%h_gid,:) = 0._r8 + elseif(ndims==3) then + this%hvars(ivar)%r83d(currentSite%h_gid,:,:) = 0._r8 + end if + end if + end do + + return + end subroutine zero_site_hvars + + + ! ====================================================================================== + + subroutine flush_all_hvars(this,nc) + + ! A wrapper to flush all active history + ! groups to their flush value + + class(fates_history_interface_type) :: this + integer,intent(in) :: nc + + if(hlm_hist_level_hifrq>0) then + call this%flush_hvars(nc,upfreq_in=group_hifr_simple) + if (hlm_use_planthydro.eq.itrue) call this%flush_hvars(nc,upfreq_in=group_hydr_simple) + if(hlm_hist_level_hifrq>1) then + call this%flush_hvars(nc,upfreq_in=group_hifr_complx) + if (hlm_use_planthydro.eq.itrue) call this%flush_hvars(nc,upfreq_in=group_hydr_complx) + end if + end if + + if(hlm_hist_level_dynam>0) then + call this%flush_hvars(nc,upfreq_in=group_dyna_simple) + call this%flush_hvars(nc,upfreq_in=group_nflx_simple) + if(hlm_hist_level_dynam>1) then + call this%flush_hvars(nc,upfreq_in=group_dyna_complx) + call this%flush_hvars(nc,upfreq_in=group_nflx_complx) + end if + end if + + return + end subroutine flush_all_hvars + + ! ====================================================================================== + + subroutine flush_hvars(this,nc,upfreq_in) + + class(fates_history_interface_type) :: this + integer,intent(in) :: nc + integer,intent(in) :: upfreq_in + integer :: ivar + integer :: lb1,ub1,lb2,ub2 + + do ivar=1,ubound(this%hvars,1) + if (this%hvars(ivar)%upfreq == upfreq_in) then ! Only flush variables with update on dynamics step + call this%hvars(ivar)%HFlush(nc, this%dim_bounds, this%dim_kinds) + end if + end do + + end subroutine flush_hvars + + + ! ===================================================================================== + + subroutine set_history_var(this, vname, units, long, use_default, avgflag, vtype, & + hlms, upfreq, ivar, initialize, index, flush_to_zero) + + use FatesUtilsMod, only : check_hlm_list + use FatesInterfaceTypesMod, only : hlm_name + + implicit none + + ! arguments + class(fates_history_interface_type), intent(inout) :: this + character(len=*), intent(in) :: vname + character(len=*), intent(in) :: units + character(len=*), intent(in) :: long + character(len=*), intent(in) :: use_default + character(len=*), intent(in) :: avgflag + character(len=*), intent(in) :: vtype + character(len=*), intent(in) :: hlms + integer, intent(in) :: upfreq + logical, intent(in) :: initialize + integer, intent(inout) :: ivar + integer, intent(inout) :: index ! This is the index for the variable of + ! interest that is associated with an + ! 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 + integer :: ityp + real(r8) :: flushval + logical :: write_var + + + ! 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 + ivar = ivar+1 + index = ivar + + if (initialize) then + call this%hvars(ivar)%Init(vname, units, long, use_default, & vtype, avgflag, flushval, upfreq, fates_history_num_dim_kinds, & this%dim_kinds, this%dim_bounds) - end if - else - index = 0 - end if - - return - end subroutine set_history_var - - ! ==================================================================================== - - subroutine init_dim_kinds_maps(this) - - ! ---------------------------------------------------------------------------------- - ! This subroutine simply initializes the structures that define the different - ! array and type formats for different IO variables - ! - ! SI_R8 : 1D site scale 8-byte reals - ! - ! The allocation on the structures is not dynamic and should only add up to the - ! number of entries listed here. - ! - ! ---------------------------------------------------------------------------------- - use FatesIOVariableKindMod, only : site_r8, site_soil_r8, site_size_pft_r8 - use FatesIOVariableKindMod, only : site_size_r8, site_pft_r8, site_age_r8 - use FatesIOVariableKindMod, only : site_coage_r8, site_coage_pft_r8 - 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_height_r8, site_agefuel_r8 - use FatesIOVariableKindMod, only : site_elem_r8, site_elpft_r8 - use FatesIOVariableKindMod, only : site_elcwd_r8, site_elage_r8, site_clscpf_r8 - use FatesIOVariableKindMod, only : site_cdpf_r8, site_cdsc_r8, site_cdam_r8 - - implicit none - - ! Arguments - class(fates_history_interface_type), intent(inout) :: this - - - integer :: index - - index = 1 - ! 1d Site - call this%dim_kinds(index)%Init(site_r8, 1) - - ! site x soil - index = index + 1 - call this%dim_kinds(index)%Init(site_soil_r8, 2) - - ! site x size-class/pft - index = index + 1 - call this%dim_kinds(index)%Init(site_size_pft_r8, 2) - - ! site x size-class - index = index + 1 - call this%dim_kinds(index)%Init(site_size_r8, 2) - - ! site x cohort age-class/pft - index = index + 1 - call this%dim_kinds(index)%Init(site_coage_pft_r8, 2) - - ! site x cohort age-class - index = index + 1 - call this%dim_kinds(index)%Init(site_coage_r8, 2) + end if + else + index = 0 + end if + + return + end subroutine set_history_var + + ! ==================================================================================== + + subroutine init_dim_kinds_maps(this) + + ! ---------------------------------------------------------------------------------- + ! This subroutine simply initializes the structures that define the different + ! array and type formats for different IO variables + ! + ! SI_R8 : 1D site scale 8-byte reals + ! + ! The allocation on the structures is not dynamic and should only add up to the + ! number of entries listed here. + ! + ! ---------------------------------------------------------------------------------- + use FatesIOVariableKindMod, only : site_r8, site_soil_r8, site_size_pft_r8 + use FatesIOVariableKindMod, only : site_size_r8, site_pft_r8, site_age_r8 + use FatesIOVariableKindMod, only : site_coage_r8, site_coage_pft_r8 + 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_height_r8, site_agefuel_r8 + use FatesIOVariableKindMod, only : site_elem_r8, site_elpft_r8 + use FatesIOVariableKindMod, only : site_elcwd_r8, site_elage_r8, site_clscpf_r8 + use FatesIOVariableKindMod, only : site_cdpf_r8, site_cdsc_r8, site_cdam_r8 + + implicit none + + ! Arguments + class(fates_history_interface_type), intent(inout) :: this + + + integer :: index + + index = 1 + ! 1d Site + call this%dim_kinds(index)%Init(site_r8, 1) + + ! site x soil + index = index + 1 + call this%dim_kinds(index)%Init(site_soil_r8, 2) + + ! site x size-class/pft + index = index + 1 + call this%dim_kinds(index)%Init(site_size_pft_r8, 2) + + ! site x size-class + index = index + 1 + call this%dim_kinds(index)%Init(site_size_r8, 2) + + ! site x cohort age-class/pft + index = index + 1 + call this%dim_kinds(index)%Init(site_coage_pft_r8, 2) + + ! site x cohort age-class + index = index + 1 + call this%dim_kinds(index)%Init(site_coage_r8, 2) - ! site x pft - index = index + 1 - call this%dim_kinds(index)%Init(site_pft_r8, 2) - - ! site x patch-age class - index = index + 1 - call this%dim_kinds(index)%Init(site_age_r8, 2) - - ! site x fuel size class - index = index + 1 - call this%dim_kinds(index)%Init(site_fuel_r8, 2) - - ! site x cwd size class - index = index + 1 - call this%dim_kinds(index)%Init(site_cwdsc_r8, 2) - - ! site x can class - index = index + 1 - call this%dim_kinds(index)%Init(site_can_r8, 2) - - ! site x cnlf class - index = index + 1 - call this%dim_kinds(index)%Init(site_cnlf_r8, 2) - - ! site x cnlfpft class - 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) - - ! site x size-class x age class x pft - index = index + 1 - call this%dim_kinds(index)%Init(site_scagpft_r8, 2) - - ! site x age class x pft - index = index + 1 - call this%dim_kinds(index)%Init(site_agepft_r8, 2) - - ! site x height - index = index + 1 - call this%dim_kinds(index)%Init(site_height_r8, 2) - - ! site x elemenet - index = index + 1 - call this%dim_kinds(index)%Init(site_elem_r8, 2) - - ! site x element x pft - index = index + 1 - call this%dim_kinds(index)%Init(site_elpft_r8, 2) - - ! site x element x cwd - index = index + 1 - call this%dim_kinds(index)%Init(site_elcwd_r8, 2) + ! site x pft + index = index + 1 + call this%dim_kinds(index)%Init(site_pft_r8, 2) + + ! site x patch-age class + index = index + 1 + call this%dim_kinds(index)%Init(site_age_r8, 2) + + ! site x fuel size class + index = index + 1 + call this%dim_kinds(index)%Init(site_fuel_r8, 2) + + ! site x cwd size class + index = index + 1 + call this%dim_kinds(index)%Init(site_cwdsc_r8, 2) + + ! site x can class + index = index + 1 + call this%dim_kinds(index)%Init(site_can_r8, 2) + + ! site x cnlf class + index = index + 1 + call this%dim_kinds(index)%Init(site_cnlf_r8, 2) + + ! site x cnlfpft class + 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) + + ! site x size-class x age class x pft + index = index + 1 + call this%dim_kinds(index)%Init(site_scagpft_r8, 2) + + ! site x age class x pft + index = index + 1 + call this%dim_kinds(index)%Init(site_agepft_r8, 2) + + ! site x height + index = index + 1 + call this%dim_kinds(index)%Init(site_height_r8, 2) + + ! site x elemenet + index = index + 1 + call this%dim_kinds(index)%Init(site_elem_r8, 2) + + ! site x element x pft + index = index + 1 + call this%dim_kinds(index)%Init(site_elpft_r8, 2) + + ! site x element x cwd + index = index + 1 + call this%dim_kinds(index)%Init(site_elcwd_r8, 2) + + ! site x element x age + index = index + 1 + call this%dim_kinds(index)%Init(site_elage_r8, 2) + + ! site x age x fuel size class + 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) + + ! site x land use class + index = index + 1 + call this%dim_kinds(index)%Init(site_landuse_r8, 2) + + ! site x land use x land use class + index = index + 1 + call this%dim_kinds(index)%Init(site_lulu_r8, 2) + + ! site x land use x pft + index = index + 1 + call this%dim_kinds(index)%Init(site_lupft_r8, 2) + + ! FIXME(bja, 2016-10) assert(index == fates_history_num_dim_kinds) + end subroutine init_dim_kinds_maps + + ! ======================================================================= + + subroutine update_history_nutrflux(this,csite) + + ! TODO IN FUTURE PR: + ! CHANGE THIS NAME FROM NUTRFLUX TO + ! DYNAM_FLUX AND THE EXISISTING DYNAMICS + ! TO DYNAM_STATE. MOVE FLUX DIAGNOSTIC + ! TO THIS ROUTINE, AND USE THIS ROUTINE + ! TO TRACK ALL DYNAMICS FLUX DIAGNOSTICS + ! AND CALL THIS AFTER DISTURBANCE RATES + ! HAVE BEEN CALLED, BUT BEFORE PATCHES + ! HAVE BEEN SPLIT AND SPAWNED + + + ! 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 ! pft loop index + real(r8):: uconv ! combined unit conversion factor + real(r8) :: fnrt_c ! cohort fine-root c + + ! Process variables with time-space dimensions only + ! --------------------------------------------------------------------------------------------- + + if_dynam1: if(hlm_hist_level_dynam>0) then - ! site x element x age - index = index + 1 - call this%dim_kinds(index)%Init(site_elage_r8, 2) - - ! site x age x fuel size class - 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) - - ! site x land use class - index = index + 1 - call this%dim_kinds(index)%Init(site_landuse_r8, 2) - - ! site x land use x land use class - index = index + 1 - call this%dim_kinds(index)%Init(site_lulu_r8, 2) - - ! site x land use x pft - index = index + 1 - call this%dim_kinds(index)%Init(site_lupft_r8, 2) - - ! FIXME(bja, 2016-10) assert(index == fates_history_num_dim_kinds) - end subroutine init_dim_kinds_maps - - ! ======================================================================= - - subroutine update_history_nutrflux(this,csite) - - ! TODO IN FUTURE PR: - ! CHANGE THIS NAME FROM NUTRFLUX TO - ! DYNAM_FLUX AND THE EXISISTING DYNAMICS - ! TO DYNAM_STATE. MOVE FLUX DIAGNOSTIC - ! TO THIS ROUTINE, AND USE THIS ROUTINE - ! TO TRACK ALL DYNAMICS FLUX DIAGNOSTICS - ! AND CALL THIS AFTER DISTURBANCE RATES - ! HAVE BEEN CALLED, BUT BEFORE PATCHES - ! HAVE BEEN SPLIT AND SPAWNED - - - ! 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 ! pft loop index - real(r8):: uconv ! combined unit conversion factor - real(r8) :: fnrt_c ! cohort fine-root c - - ! Process variables with time-space dimensions only - ! --------------------------------------------------------------------------------------------- - - if_dynam1: if(hlm_hist_level_dynam>0) then - ! history site index io_si = csite%h_gid ! zero nutrient fluxes call this%zero_site_hvars(csite,upfreq_in=group_nflx_simple) - + cpatch => csite%youngest_patch do while(associated(cpatch)) @@ -2178,60 +2181,60 @@ subroutine update_history_nutrflux(this,csite) fnrt_c = ccohort%prt%GetState(fnrt_organ, carbon12_element) - ! Loop over the different elements. + ! Loop over the different elements. do el = 1, num_elements select case (element_list(el)) - case (carbon12_element) + 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_hold*uconv + this%hvars(ih_excess_resp_si)%r81d(io_si) + & + ccohort%resp_excess_hold*uconv - case (nitrogen_element) + case (nitrogen_element) ! Mineralized uptake of NH4, NO3 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_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 + 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_si)%r81d(io_si) + & + ccohort%sym_nfix_daily*uconv ! Efflux/exudation this%hvars(ih_nefflux_si)%r81d(io_si) = & - this%hvars(ih_nefflux_si)%r81d(io_si) + & - ccohort%daily_n_efflux*uconv + this%hvars(ih_nefflux_si)%r81d(io_si) + & + ccohort%daily_n_efflux*uconv ! Demand this%hvars(ih_ndemand_si)%r81d(io_si) = & - this%hvars(ih_ndemand_si)%r81d(io_si) + & - ccohort%daily_n_demand*uconv - - case (phosphorus_element) + this%hvars(ih_ndemand_si)%r81d(io_si) + & + ccohort%daily_n_demand*uconv + + case (phosphorus_element) ! Mineralized uptake of PO4 fates_hist%hvars(ih_puptake_si)%r81d(io_si) = & - fates_hist%hvars(ih_puptake_si)%r81d(io_si) + & - ccohort%daily_p_gain*uconv + fates_hist%hvars(ih_puptake_si)%r81d(io_si) + & + ccohort%daily_p_gain*uconv ! Efflux this%hvars(ih_pefflux_si)%r81d(io_si) = & - this%hvars(ih_pefflux_si)%r81d(io_si) + & - ccohort%daily_p_efflux*uconv + this%hvars(ih_pefflux_si)%r81d(io_si) + & + ccohort%daily_p_efflux*uconv ! Demand this%hvars(ih_pdemand_si)%r81d(io_si) = & - this%hvars(ih_pdemand_si)%r81d(io_si) + & - ccohort%daily_p_demand*uconv - + this%hvars(ih_pdemand_si)%r81d(io_si) + & + ccohort%daily_p_demand*uconv + end select end do @@ -2241,18 +2244,18 @@ subroutine update_history_nutrflux(this,csite) cpatch => cpatch%older end do - end if if_dynam1 + end if if_dynam1 + + ! Process multiplexed variables + ! --------------------------------------------------------------------------------------------- - ! Process multiplexed variables - ! --------------------------------------------------------------------------------------------- - - if_dynam2: if(hlm_hist_level_dynam>1) then + if_dynam2: if(hlm_hist_level_dynam>1) then ! history site index io_si = csite%h_gid call this%zero_site_hvars(csite,upfreq_in=group_nflx_complx) - + cpatch => csite%youngest_patch do while(associated(cpatch)) @@ -2274,54 +2277,54 @@ subroutine update_history_nutrflux(this,csite) ! unit conversion factor to get x/plant/day -> x/m2/sec uconv = ccohort%n * ha_per_m2 * days_per_sec - ! Loop over the different elements. + ! Loop over the different elements. do el = 1, num_elements select case (element_list(el)) - case (nitrogen_element) + 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_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_no3uptake_scpf)%r82d(io_si,iscpf) + & + ccohort%daily_no3_uptake*uconv ! Fixation 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 + 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_scpf)%r82d(io_si,iscpf) + & + 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 - - case (phosphorus_element) + this%hvars(ih_ndemand_scpf)%r82d(io_si,iscpf) + & + ccohort%daily_n_demand*uconv + + case (phosphorus_element) ! Mineralized uptake of PO4 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_scpf)%r82d(io_si,iscpf) + & + ccohort%daily_p_gain*uconv ! Efflux 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_scpf)%r82d(io_si,iscpf) + & + ccohort%daily_p_efflux*uconv + ! Demand this%hvars(ih_pdemand_scpf)%r82d(io_si,iscpf) = & - this%hvars(ih_pdemand_scpf)%r82d(io_si,iscpf) + & - ccohort%daily_p_demand*uconv - + this%hvars(ih_pdemand_scpf)%r82d(io_si,iscpf) + & + ccohort%daily_p_demand*uconv + end select end do @@ -2331,106 +2334,106 @@ subroutine update_history_nutrflux(this,csite) cpatch => cpatch%older end do - end if if_dynam2 - - return - end subroutine update_history_nutrflux - - ! ==================================================================================== - - 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 - ! after Ecosystem Dynamics have been processed. - ! This is the general routine that will call the single or multi-dimensional - ! routines if they are called for by the user - ! --------------------------------------------------------------------------------- - - ! 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 - - ! If we don't have dynamics turned on, we just abort these diagnostics - - ! There is future work slated to split dynamics diagnostics into those - ! related to states, and those related to fluxes. States should be fine - ! to report in ST3 mode. - - if (hlm_use_ed_st3.eq.itrue) return - - if(hlm_hist_level_dynam>0) then - call update_history_dyn_sitelevel(this,nc,nsites,sites) - if(hlm_hist_level_dynam>1) then - call update_history_dyn_subsite(this,nc,nsites,sites,bc_in) - call update_history_dyn_subsite_ageclass(this,nc,nsites,sites) - call reset_history_dyn_subsite(this, nsites, sites) - end if - end if - - - - return - end subroutine update_history_dyn - - ! ========================================================================= - - subroutine update_history_dyn_sitelevel(this,nc,nsites,sites) - - ! --------------------------------------------------------------------------------- - ! This subroutine is intended to update all history variables with upfreq == - ! group_dyna_simple that are saved at the site level. So, eg., FATES_VEGC is - ! updated here, but not FATES_VEGC_PF. - ! --------------------------------------------------------------------------------- - - - ! 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(fates_cohort_type), pointer :: ccohort - type(fates_patch_type), pointer :: cpatch - type(elem_diag_type), pointer :: elflux_diags_c ! Pointer to site level carbon fluxes - type(litter_type), pointer :: litt ! Generic pointer to any litter pool - - integer :: s ! site counter - integer :: io_si ! site's index in the history output array space - integer :: el ! element index - integer :: ft ! pft index - real(r8) :: site_ba ! Site basal area used for weighting - real(r8) :: cohort_ba ! Cohort basal area - real(r8) :: site_ca ! Site crown area used for weighting - real(r8) :: store_max ! Maximum storage capacity for carbon and nutrients - real(r8) :: sapw_m ! Sapwood mass (elemental, c,n or p) [kg/plant] - real(r8) :: struct_m ! Structural mass "" - real(r8) :: leaf_m ! Leaf mass "" - real(r8) :: fnrt_m ! Fineroot mass "" - real(r8) :: store_m ! Storage mass "" - real(r8) :: alive_m ! Alive biomass (sap+leaf+fineroot+repro+storage) "" - real(r8) :: total_m ! Total vegetation mass - real(r8) :: repro_m ! Total reproductive mass (on plant) "" - real(r8) :: sapw_m_turnover ! sapwood turnover rate [kg/yr] - real(r8) :: store_m_turnover ! storage turnover rate [kg/yr] - real(r8) :: leaf_m_turnover ! leaf turnover rate [kg/yr] - real(r8) :: fnrt_m_turnover ! fine-root turnover rate [kg/yr] - real(r8) :: struct_m_turnover ! structural turnover rate [kg/yr] - real(r8) :: sapw_m_net_alloc ! mass allocated to sapwood [kg/yr] - real(r8) :: store_m_net_alloc ! mass allocated to storage [kg/yr] - real(r8) :: leaf_m_net_alloc ! mass allocated to leaf [kg/yr] - real(r8) :: fnrt_m_net_alloc ! mass allocated to fine-root [kg/yr] - real(r8) :: struct_m_net_alloc ! mass allocated to structure [kg/yr] - real(r8) :: repro_m_net_alloc ! mass allocated to reproduction [kg/yr] - real(r8) :: leaf_herbivory ! mass of leaves eaten by herbivores [kg/yr] - real(r8) :: n_perm2 ! abundance per m2 - real(r8) :: patch_fracarea ! Fraction of area for this patch - - associate( hio_npatches_si => this%hvars(ih_npatches_si)%r81d, & + end if if_dynam2 + + return + end subroutine update_history_nutrflux + + ! ==================================================================================== + + 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 + ! after Ecosystem Dynamics have been processed. + ! This is the general routine that will call the single or multi-dimensional + ! routines if they are called for by the user + ! --------------------------------------------------------------------------------- + + ! 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 + + ! If we don't have dynamics turned on, we just abort these diagnostics + + ! There is future work slated to split dynamics diagnostics into those + ! related to states, and those related to fluxes. States should be fine + ! to report in ST3 mode. + + if (hlm_use_ed_st3.eq.itrue) return + + if(hlm_hist_level_dynam>0) then + call update_history_dyn_sitelevel(this,nc,nsites,sites) + if(hlm_hist_level_dynam>1) then + call update_history_dyn_subsite(this,nc,nsites,sites,bc_in) + call update_history_dyn_subsite_ageclass(this,nc,nsites,sites) + call reset_history_dyn_subsite(this, nsites, sites) + end if + end if + + + + return + end subroutine update_history_dyn + + ! ========================================================================= + + subroutine update_history_dyn_sitelevel(this,nc,nsites,sites) + + ! --------------------------------------------------------------------------------- + ! This subroutine is intended to update all history variables with upfreq == + ! group_dyna_simple that are saved at the site level. So, eg., FATES_VEGC is + ! updated here, but not FATES_VEGC_PF. + ! --------------------------------------------------------------------------------- + + + ! 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(fates_cohort_type), pointer :: ccohort + type(fates_patch_type), pointer :: cpatch + type(elem_diag_type), pointer :: elflux_diags_c ! Pointer to site level carbon fluxes + type(litter_type), pointer :: litt ! Generic pointer to any litter pool + + integer :: s ! site counter + integer :: io_si ! site's index in the history output array space + integer :: el ! element index + integer :: ft ! pft index + real(r8) :: site_ba ! Site basal area used for weighting + real(r8) :: cohort_ba ! Cohort basal area + real(r8) :: site_ca ! Site crown area used for weighting + real(r8) :: store_max ! Maximum storage capacity for carbon and nutrients + real(r8) :: sapw_m ! Sapwood mass (elemental, c,n or p) [kg/plant] + real(r8) :: struct_m ! Structural mass "" + real(r8) :: leaf_m ! Leaf mass "" + real(r8) :: fnrt_m ! Fineroot mass "" + real(r8) :: store_m ! Storage mass "" + real(r8) :: alive_m ! Alive biomass (sap+leaf+fineroot+repro+storage) "" + real(r8) :: total_m ! Total vegetation mass + real(r8) :: repro_m ! Total reproductive mass (on plant) "" + real(r8) :: sapw_m_turnover ! sapwood turnover rate [kg/yr] + real(r8) :: store_m_turnover ! storage turnover rate [kg/yr] + real(r8) :: leaf_m_turnover ! leaf turnover rate [kg/yr] + real(r8) :: fnrt_m_turnover ! fine-root turnover rate [kg/yr] + real(r8) :: struct_m_turnover ! structural turnover rate [kg/yr] + real(r8) :: sapw_m_net_alloc ! mass allocated to sapwood [kg/yr] + real(r8) :: store_m_net_alloc ! mass allocated to storage [kg/yr] + real(r8) :: leaf_m_net_alloc ! mass allocated to leaf [kg/yr] + real(r8) :: fnrt_m_net_alloc ! mass allocated to fine-root [kg/yr] + real(r8) :: struct_m_net_alloc ! mass allocated to structure [kg/yr] + real(r8) :: repro_m_net_alloc ! mass allocated to reproduction [kg/yr] + real(r8) :: leaf_herbivory ! mass of leaves eaten by herbivores [kg/yr] + real(r8) :: n_perm2 ! abundance per m2 + real(r8) :: patch_fracarea ! Fraction of area for this patch + + associate( hio_npatches_si => this%hvars(ih_npatches_si)%r81d, & hio_ncohorts_si => this%hvars(ih_ncohorts_si)%r81d, & hio_ncl_si => this%hvars(ih_ncl_si)%r81d, & hio_zstar_si => this%hvars(ih_zstar_si)%r81d, & @@ -2452,10 +2455,13 @@ subroutine update_history_dyn_sitelevel(this,nc,nsites,sites) hio_fire_intensity_fracarea_product_si => this%hvars(ih_fire_intensity_fracarea_product_si)%r81d, & hio_fire_fracarea_si => this%hvars(ih_fire_fracarea_si)%r81d, & hio_fire_fuel_bulkd_si => this%hvars(ih_fire_fuel_bulkd_si)%r81d, & - hio_fire_fuel_eff_moist_si => this%hvars(ih_fire_fuel_eff_moist_si)%r81d, & + hio_fire_fuel_moist_dead_si => this%hvars(ih_fire_fuel_moist_dead_si)%r81d, & + hio_fire_fuel_moist_live_si => this%hvars(ih_fire_fuel_moist_live_si)%r81d, & hio_fire_fuel_sav_si => this%hvars(ih_fire_fuel_sav_si)%r81d, & - hio_fire_fuel_mef_si => this%hvars(ih_fire_fuel_mef_si)%r81d, & + hio_fire_fuel_mef_dead_si => this%hvars(ih_fire_fuel_mef_dead_si)%r81d, & + hio_fire_fuel_mef_live_si => this%hvars(ih_fire_fuel_mef_live_si)%r81d, & hio_sum_fuel_si => this%hvars(ih_sum_fuel_si)%r81d, & + hio_weighted_sum_fuel_si => this%hvars(ih_weighted_sum_fuel_si)%r81d, & hio_nonrx_intensity_si => this%hvars(ih_nonrx_intensity_si)%r81d, & hio_nonrx_intensity_fracarea_product_si => this%hvars(ih_nonrx_intensity_fracarea_product_si)%r81d, & hio_nonrx_fracarea_si => this%hvars(ih_nonrx_fracarea_si)%r81d, & @@ -2515,637 +2521,641 @@ subroutine update_history_dyn_sitelevel(this,nc,nsites,sites) hio_harvest_woodprod_carbonflux_si => this%hvars(ih_harvest_woodprod_carbonflux_si)%r81d, & hio_luchange_woodprod_carbonflux_si => this%hvars(ih_luchange_woodprod_carbonflux_si)%r81d) - ! --------------------------------------------------------------------------------- - ! Loop through the FATES scale hierarchy and fill the history IO arrays - ! --------------------------------------------------------------------------------- + ! --------------------------------------------------------------------------------- + ! Loop through the FATES scale hierarchy and fill the history IO arrays + ! --------------------------------------------------------------------------------- - siteloop: do s = 1,nsites + siteloop: do s = 1,nsites - io_si = sites(s)%h_gid + io_si = sites(s)%h_gid - site_ba = 0._r8 - site_ca = 0._r8 + site_ba = 0._r8 + site_ca = 0._r8 - call this%zero_site_hvars(sites(s),upfreq_in=group_dyna_simple) - - ! 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 + call this%zero_site_hvars(sites(s),upfreq_in=group_dyna_simple) - ! 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 + ! 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 lost to atmosphere from burning (kgC/site/day -> kgC/m2/s) - hio_fire_c_to_atm_si(io_si) = & - sites(s)%mass_balance(element_pos(carbon12_element))%burn_flux_to_atm * & - ha_per_m2 * days_per_sec + ! 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 - ! 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 + ! Total carbon lost to atmosphere from burning (kgC/site/day -> kgC/m2/s) + hio_fire_c_to_atm_si(io_si) = & + sites(s)%mass_balance(element_pos(carbon12_element))%burn_flux_to_atm * & + ha_per_m2 * days_per_sec - end if + ! damage variables - site level - this needs to be OUT of the patch loop + if(hlm_use_tree_damage .eq. itrue) then - ! Canopy spread index (0-1) - hio_canopy_spread_si(io_si) = sites(s)%spread + 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 - ! Update the site status for cold deciduous (drought deciduous is now PFT dependent) - hio_site_cstatus_si(io_si) = real(sites(s)%cstatus,r8) + 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 - ! Number of chill days and cold days - hio_site_nchilldays_si(io_si) = real(sites(s)%nchilldays,r8) - hio_site_ncolddays_si(io_si) = real(sites(s)%ncolddays,r8) + end if - ! Growing degree-days - hio_gdd_si(io_si) = sites(s)%grow_deg_days + ! Canopy spread index (0-1) + hio_canopy_spread_si(io_si) = sites(s)%spread - ! 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) + ! Update the site status for cold deciduous (drought deciduous is now PFT dependent) + hio_site_cstatus_si(io_si) = real(sites(s)%cstatus,r8) - ! site-level fire variables: + ! Number of chill days and cold days + hio_site_nchilldays_si(io_si) = real(sites(s)%nchilldays,r8) + hio_site_ncolddays_si(io_si) = real(sites(s)%ncolddays,r8) - ! Nesterov index (unitless) - hio_nesterov_fire_danger_si(io_si) = sites(s)%fireWeather%fire_weather_index - - hio_effect_wspeed_si(io_si) = sites(s)%fireWeather%effective_windspeed/sec_per_min + ! Growing degree-days + hio_gdd_si(io_si) = sites(s)%grow_deg_days - ! Prescribed fire burn window - hio_rx_burn_window_si(io_si) = hio_rx_burn_window_si(io_si) + sites(s)%fireWeather%rx_flag + ! 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) - ! number of ignitions [#/km2/day -> #/m2/s] - hio_fire_nignitions_si(io_si) = sites(s)%NF_successful / m2_per_km2 / & - sec_per_day + ! site-level fire variables: - ! Fire danger index (FDI) (0-1) - hio_fire_fdi_si(io_si) = sites(s)%FDI + ! Nesterov index (unitless) + hio_nesterov_fire_danger_si(io_si) = sites(s)%fireWeather%fire_weather_index - ! total rx burnable fraction when fuel condition met - hio_rx_fracarea_fuel_si(io_si) = sites(s)%rxfire_area_fuel * AREA_INV + hio_effect_wspeed_si(io_si) = sites(s)%fireWeather%effective_windspeed/sec_per_min - ! total rx burnable fraction when fuel and FI conditions met - hio_rx_fracarea_fi_si(io_si) = sites(s)%rxfire_area_fi * AREA_INV + ! Prescribed fire burn window + hio_rx_burn_window_si(io_si) = hio_rx_burn_window_si(io_si) + sites(s)%fireWeather%rx_flag - ! total rx burnable fraction when all conditions met - hio_rx_fracarea_final_si(io_si) = sites(s)%rxfire_area_final * AREA_INV + ! number of ignitions [#/km2/day -> #/m2/s] + hio_fire_nignitions_si(io_si) = sites(s)%NF_successful / m2_per_km2 / & + sec_per_day - ! If hydraulics are turned on, track the error terms associated with - ! dynamics [kg/m2] - if(hlm_use_planthydro.eq.itrue)then - this%hvars(ih_h2oveg_dead_si)%r81d(io_si) = sites(s)%si_hydr%h2oveg_dead - 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 + ! Fire danger index (FDI) (0-1) + hio_fire_fdi_si(io_si) = sites(s)%FDI - 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 + ! total rx burnable fraction when fuel condition met + hio_rx_fracarea_fuel_si(io_si) = sites(s)%rxfire_area_fuel * AREA_INV - ! 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 + ! total rx burnable fraction when fuel and FI conditions met + hio_rx_fracarea_fi_si(io_si) = sites(s)%rxfire_area_fi * AREA_INV - ! output site-level disturbance rates [m2 m-2 day-1] -> [m2 m-2 yr-1] - TO DO rework this + ! total rx burnable fraction when all conditions met + hio_rx_fracarea_final_si(io_si) = sites(s)%rxfire_area_final * AREA_INV - hio_fire_disturbance_rate_si(io_si) = & - sum(sites(s)%disturbance_rates(dtype_ifire,1:n_landuse_cats,1:n_landuse_cats)) * & - days_per_year + ! If hydraulics are turned on, track the error terms associated with + ! dynamics [kg/m2] + if(hlm_use_planthydro.eq.itrue)then + this%hvars(ih_h2oveg_dead_si)%r81d(io_si) = sites(s)%si_hydr%h2oveg_dead + 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_logging_disturbance_rate_si(io_si) = & - sum(sites(s)%disturbance_rates(dtype_ilog,1:n_landuse_cats,1:n_landuse_cats)) * & - days_per_year + hio_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 - hio_fall_disturbance_rate_si(io_si) = & - sum(sites(s)%disturbance_rates(dtype_ifall,1:n_landuse_cats,1:n_landuse_cats)) * & - days_per_year + ! 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 - hio_harvest_woodprod_carbonflux_si(io_si) = AREA_INV * & - sum(sites(s)%mass_balance(element_pos(carbon12_element))%wood_product_harvest(1:numpft)) + ! output site-level disturbance rates [m2 m-2 day-1] -> [m2 m-2 yr-1] - TO DO rework this - hio_luchange_woodprod_carbonflux_si(io_si) = AREA_INV * & - sum(sites(s)%mass_balance(element_pos(carbon12_element))%wood_product_landusechange(1:numpft)) - + hio_fire_disturbance_rate_si(io_si) = & + sum(sites(s)%disturbance_rates(dtype_ifire,1:n_landuse_cats,1:n_landuse_cats)) * & + days_per_year - ! 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_logging_disturbance_rate_si(io_si) = & + sum(sites(s)%disturbance_rates(dtype_ilog,1:n_landuse_cats,1:n_landuse_cats)) * & + days_per_year - - hio_ustory_mortality_carbonflux_si(io_si) = hio_ustory_mortality_carbonflux_si(io_si) + & - sum(sites(s)%fmort_carbonflux_ustory(:)) / g_per_kg + hio_fall_disturbance_rate_si(io_si) = & + sum(sites(s)%disturbance_rates(dtype_ifall,1:n_landuse_cats,1:n_landuse_cats)) * & + days_per_year - ! treat carbon flux from imort the same way - hio_ustory_mortality_carbonflux_si(io_si) = hio_ustory_mortality_carbonflux_si(io_si) + & - sum(sites(s)%imort_carbonflux(:)) + hio_harvest_woodprod_carbonflux_si(io_si) = AREA_INV * & + sum(sites(s)%mass_balance(element_pos(carbon12_element))%wood_product_harvest(1:numpft)) - ! convert kg C / ha / day to kgc / m2 / sec - hio_demotion_carbonflux_si(io_si) = sites(s)%demotion_carbonflux * ha_per_m2 * days_per_sec - hio_promotion_carbonflux_si(io_si) = sites(s)%promotion_carbonflux * ha_per_m2 * days_per_sec - ! - ! mortality-associated carbon fluxes + hio_luchange_woodprod_carbonflux_si(io_si) = AREA_INV * & + sum(sites(s)%mass_balance(element_pos(carbon12_element))%wood_product_landusechange(1:numpft)) - hio_canopy_mortality_carbonflux_si(io_si) = hio_canopy_mortality_carbonflux_si(io_si) + & - sum(sites(s)%term_carbonflux_canopy(:,:)) * days_per_sec * ha_per_m2 - - hio_ustory_mortality_carbonflux_si(io_si) = hio_ustory_mortality_carbonflux_si(io_si) + & - 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 + ! 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_ustory_mortality_crownarea_si(io_si) = hio_ustory_mortality_crownarea_si(io_si) + & - sites(s)%fmort_crownarea_ustory + & - sites(s)%term_crownarea_ustory * days_per_year + & - sites(s)%imort_crownarea + hio_ustory_mortality_carbonflux_si(io_si) = hio_ustory_mortality_carbonflux_si(io_si) + & + sum(sites(s)%fmort_carbonflux_ustory(:)) / g_per_kg - elflux_diags_c => sites(s)%flux_diags%elem(element_pos(carbon12_element)) + ! treat carbon flux from imort the same way + hio_ustory_mortality_carbonflux_si(io_si) = hio_ustory_mortality_carbonflux_si(io_si) + & + sum(sites(s)%imort_carbonflux(:)) - hio_litter_in_si(io_si) = (sum(elflux_diags_c%cwd_ag_input(:)) + & - sum(elflux_diags_c%cwd_bg_input(:)) + & - sum(elflux_diags_c%surf_fine_litter_input(:)) + & - sum(elflux_diags_c%root_litter_input(:))) * & - AREA_INV * days_per_sec + ! convert kg C / ha / day to kgc / m2 / sec + hio_demotion_carbonflux_si(io_si) = sites(s)%demotion_carbonflux * ha_per_m2 * days_per_sec + hio_promotion_carbonflux_si(io_si) = sites(s)%promotion_carbonflux * ha_per_m2 * days_per_sec + ! + ! mortality-associated carbon fluxes - ! Loop through patches to sum up diagonistics - cpatch => sites(s)%oldest_patch - patchloop: do while(associated(cpatch)) + hio_canopy_mortality_carbonflux_si(io_si) = hio_canopy_mortality_carbonflux_si(io_si) + & + sum(sites(s)%term_carbonflux_canopy(:,:)) * days_per_sec * ha_per_m2 - ! Increment the number of patches per site - hio_npatches_si(io_si) = hio_npatches_si(io_si) + 1._r8 + hio_ustory_mortality_carbonflux_si(io_si) = hio_ustory_mortality_carbonflux_si(io_si) + & + sum(sites(s)%term_carbonflux_ustory(:,:)) * days_per_sec * ha_per_m2 - hio_lai_si(io_si) = hio_lai_si(io_si) + sum( cpatch%canopy_area_profile(:,:,:) * cpatch%tlai_profile(:,:,:) ) * & - cpatch%total_canopy_area * AREA_INV - - hio_elai_si(io_si) = hio_elai_si(io_si) + sum( cpatch%canopy_area_profile(:,:,:) * cpatch%elai_profile(:,:,:) ) * & - cpatch%total_canopy_area * AREA_INV - - hio_ncl_si(io_si) = hio_ncl_si(io_si) + cpatch%ncl_p * cpatch%area * AREA_INV + ! 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 - ! only valid when "strict ppa" enabled - if ( comp_excln_exp .lt. 0._r8 ) then - hio_zstar_si(io_si) = hio_zstar_si(io_si) & - + cpatch%zstar * cpatch%area * AREA_INV - end if + hio_ustory_mortality_crownarea_si(io_si) = hio_ustory_mortality_crownarea_si(io_si) + & + sites(s)%fmort_crownarea_ustory + & + sites(s)%term_crownarea_ustory * days_per_year + & + sites(s)%imort_crownarea - ! 24hr veg temperature - hio_tveg24(io_si) = hio_tveg24(io_si) + & - (cpatch%tveg24%GetMean()- t_water_freeze_k_1atm)*cpatch%area*AREA_INV - ! 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 + elflux_diags_c => sites(s)%flux_diags%elem(element_pos(carbon12_element)) - ! 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 + hio_litter_in_si(io_si) = (sum(elflux_diags_c%cwd_ag_input(:)) + & + sum(elflux_diags_c%cwd_bg_input(:)) + & + sum(elflux_diags_c%surf_fine_litter_input(:)) + & + sum(elflux_diags_c%root_litter_input(:))) * & + AREA_INV * days_per_sec - ! Canopy trimming - degree to which canopy expansion is limited by leaf economics (0-1) - if(associated(cpatch%tallest))then - hio_trimming_si(io_si) = hio_trimming_si(io_si) + cpatch%tallest%canopy_trim * cpatch%area * AREA_INV - endif + ! Loop through patches to sum up diagonistics + cpatch => sites(s)%oldest_patch + patchloop: do while(associated(cpatch)) - ! fractional area occupied by plants and trees [m2/m2] - hio_fracarea_plant_si(io_si) = hio_fracarea_plant_si(io_si) + min(cpatch%total_canopy_area,cpatch%area) * AREA_INV - hio_fracarea_trees_si(io_si) = hio_fracarea_trees_si(io_si) + min(cpatch%total_tree_area,cpatch%area) * AREA_INV - - ! Patch specific variables that are already calculated - ! These things are all duplicated. Should they all be converted to LL or array structures RF? - ! define scalar to counteract the patch albedo scaling logic for conserved quantities - - ! Update Fire Variables - hio_spitfire_ros_si(io_si) = hio_spitfire_ros_si(io_si) + cpatch%ROS_front * cpatch%area * AREA_INV / sec_per_min - hio_tfc_ros_si(io_si) = hio_tfc_ros_si(io_si) + cpatch%TFC_ROS * cpatch%area * AREA_INV - hio_fire_intensity_si(io_si) = hio_fire_intensity_si(io_si) + cpatch%FI * cpatch%area * AREA_INV * J_per_kJ - hio_fire_fracarea_si(io_si) = hio_fire_fracarea_si(io_si) + cpatch%frac_burnt * cpatch%area * AREA_INV / sec_per_day - hio_nonrx_intensity_si(io_si) = hio_nonrx_intensity_si(io_si) + cpatch%nonrx_FI * cpatch%area * AREA_INV * J_per_kJ - hio_nonrx_fracarea_si(io_si) = hio_nonrx_fracarea_si(io_si) + cpatch%nonrx_frac_burnt * cpatch%area * AREA_INV / sec_per_day - hio_rx_intensity_si(io_si) = hio_rx_intensity_si(io_si) + cpatch%rx_FI * cpatch%area * AREA_INV * J_per_kJ - hio_rx_fracarea_si(io_si) = hio_rx_fracarea_si(io_si) + cpatch%rx_frac_burnt * cpatch%area * AREA_INV / sec_per_day - hio_fire_fuel_bulkd_si(io_si) = hio_fire_fuel_bulkd_si(io_si) + cpatch%fuel%bulk_density_notrunks * cpatch%area * AREA_INV - hio_fire_fuel_eff_moist_si(io_si) = hio_fire_fuel_eff_moist_si(io_si) + cpatch%fuel%average_moisture_notrunks * cpatch%area * AREA_INV - hio_fire_fuel_sav_si(io_si) = hio_fire_fuel_sav_si(io_si) + cpatch%fuel%SAV_notrunks * cpatch%area * AREA_INV / m_per_cm - hio_fire_fuel_mef_si(io_si) = hio_fire_fuel_mef_si(io_si) + cpatch%fuel%MEF_notrunks * cpatch%area * AREA_INV - hio_sum_fuel_si(io_si) = hio_sum_fuel_si(io_si) + cpatch%fuel%non_trunk_loading * cpatch%area * AREA_INV - - hio_nonrx_intensity_fracarea_product_si(io_si) = hio_nonrx_intensity_fracarea_product_si(io_si) + & - cpatch%nonrx_FI * cpatch%nonrx_frac_burnt * cpatch%area * AREA_INV * J_per_kJ - - hio_rx_intensity_fracarea_product_si(io_si) = hio_rx_intensity_fracarea_product_si(io_si) + & - cpatch%rx_FI * cpatch%rx_frac_burnt * cpatch%area * AREA_INV * J_per_kJ - - hio_fire_intensity_fracarea_product_si(io_si) = hio_fire_intensity_fracarea_product_si(io_si) + & - cpatch%FI * cpatch%frac_burnt * cpatch%area * AREA_INV * J_per_kJ - - litt => cpatch%litter(element_pos(carbon12_element)) - - patch_fracarea = cpatch%area * AREA_INV - - ! 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%seed_decay(:)) + & - sum(litt%seed_germ_decay(:))) * & - patch_fracarea * 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(:))) * & - patch_fracarea - - ! Sum up total seed bank (just ungerminated) - hio_ungerm_seed_bank_si(io_si) = hio_ungerm_seed_bank_si(io_si) + & - sum(litt%seed(:)) * patch_fracarea - - ! Sum up total seedling pool - hio_seedling_pool_si(io_si) = hio_seedling_pool_si(io_si) + & - sum(litt%seed_germ(:)) * patch_fracarea - - ! 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(:))) * & - patch_fracarea * days_per_sec - - hio_seeds_in_local_si(io_si) = hio_seeds_in_local_si(io_si) + & - sum(litt%seed_in_local(:)) * & - patch_fracarea * days_per_sec - - ! loop through cohorts on patch - ccohort => cpatch%shortest - cohortloop: do while(associated(ccohort)) - - ft = ccohort%pft - n_perm2 = ccohort%n * AREA_INV - - ! Increment the number of cohorts per site - hio_ncohorts_si(io_si) = hio_ncohorts_si(io_si) + 1._r8 - - ! Update biomass components - ! Mass pools [kg] - elloop: do el = 1, num_elements - - call ccohort%prt%GetBiomass(element_list(el), & - sapw_m, struct_m, leaf_m, fnrt_m, store_m, repro_m, alive_m, total_m) - - ! 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 * & - store_m / m2_per_ha - this%hvars(ih_leafc_si)%r81d(io_si) = & - this%hvars(ih_leafc_si)%r81d(io_si) + ccohort%n * & - leaf_m / m2_per_ha - this%hvars(ih_fnrtc_si)%r81d(io_si) = & - this%hvars(ih_fnrtc_si)%r81d(io_si) + ccohort%n * & - fnrt_m / m2_per_ha - this%hvars(ih_reproc_si)%r81d(io_si) = & - this%hvars(ih_reproc_si)%r81d(io_si)+ ccohort%n * & - repro_m / m2_per_ha - this%hvars(ih_sapwc_si)%r81d(io_si) = & - this%hvars(ih_sapwc_si)%r81d(io_si) + ccohort%n * & - sapw_m / m2_per_ha - this%hvars(ih_totvegc_si)%r81d(io_si) = & - 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 - - 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 - - hio_agb_si(io_si) = hio_agb_si(io_si) + n_perm2 * & - ( leaf_m + (sapw_m + struct_m + store_m) * prt_params%allom_agb_frac(ccohort%pft) ) - - if( hlm_parteh_mode == prt_cnp_flex_allom_hyp) then - this%hvars(ih_l2fr_si)%r81d(io_si) = & - this%hvars(ih_l2fr_si)%r81d(io_si) + & - ccohort%l2fr *ccohort%n * fnrt_m / m2_per_ha - else - this%hvars(ih_l2fr_si)%r81d(io_si) = & - this%hvars(ih_l2fr_si)%r81d(io_si) + & - prt_params%allom_l2fr(ft) *ccohort%n * fnrt_m / m2_per_ha + ! Increment the number of patches per site + hio_npatches_si(io_si) = hio_npatches_si(io_si) + 1._r8 + + hio_lai_si(io_si) = hio_lai_si(io_si) + sum( cpatch%canopy_area_profile(:,:,:) * cpatch%tlai_profile(:,:,:) ) * & + cpatch%total_canopy_area * AREA_INV + + hio_elai_si(io_si) = hio_elai_si(io_si) + sum( cpatch%canopy_area_profile(:,:,:) * cpatch%elai_profile(:,:,:) ) * & + cpatch%total_canopy_area * AREA_INV + + hio_ncl_si(io_si) = hio_ncl_si(io_si) + cpatch%ncl_p * cpatch%area * AREA_INV + + ! only valid when "strict ppa" enabled + if ( comp_excln_exp .lt. 0._r8 ) then + hio_zstar_si(io_si) = hio_zstar_si(io_si) & + + cpatch%zstar * cpatch%area * AREA_INV + end if + + ! 24hr veg temperature + hio_tveg24(io_si) = hio_tveg24(io_si) + & + (cpatch%tveg24%GetMean()- t_water_freeze_k_1atm)*cpatch%area*AREA_INV + + ! 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 + + ! Canopy trimming - degree to which canopy expansion is limited by leaf economics (0-1) + if(associated(cpatch%tallest))then + hio_trimming_si(io_si) = hio_trimming_si(io_si) + cpatch%tallest%canopy_trim * cpatch%area * AREA_INV + endif + + ! fractional area occupied by plants and trees [m2/m2] + hio_fracarea_plant_si(io_si) = hio_fracarea_plant_si(io_si) + min(cpatch%total_canopy_area,cpatch%area) * AREA_INV + hio_fracarea_trees_si(io_si) = hio_fracarea_trees_si(io_si) + min(cpatch%total_tree_area,cpatch%area) * AREA_INV + + ! Patch specific variables that are already calculated + ! These things are all duplicated. Should they all be converted to LL or array structures RF? + ! define scalar to counteract the patch albedo scaling logic for conserved quantities + + ! Update Fire Variables + hio_spitfire_ros_si(io_si) = hio_spitfire_ros_si(io_si) + cpatch%ROS_front * cpatch%area * AREA_INV / sec_per_min + hio_tfc_ros_si(io_si) = hio_tfc_ros_si(io_si) + cpatch%TFC_ROS * cpatch%area * AREA_INV + hio_fire_intensity_si(io_si) = hio_fire_intensity_si(io_si) + cpatch%FI * cpatch%area * AREA_INV * J_per_kJ + hio_fire_fracarea_si(io_si) = hio_fire_fracarea_si(io_si) + cpatch%frac_burnt * cpatch%area * AREA_INV / sec_per_day + hio_nonrx_intensity_si(io_si) = hio_nonrx_intensity_si(io_si) + cpatch%nonrx_FI * cpatch%area * AREA_INV * J_per_kJ + hio_nonrx_fracarea_si(io_si) = hio_nonrx_fracarea_si(io_si) + cpatch%nonrx_frac_burnt * cpatch%area * AREA_INV / sec_per_day + hio_rx_intensity_si(io_si) = hio_rx_intensity_si(io_si) + cpatch%rx_FI * cpatch%area * AREA_INV * J_per_kJ + hio_rx_fracarea_si(io_si) = hio_rx_fracarea_si(io_si) + cpatch%rx_frac_burnt * cpatch%area * AREA_INV / sec_per_day + hio_fire_fuel_bulkd_si(io_si) = hio_fire_fuel_bulkd_si(io_si) + cpatch%fuel%bulk_density_weighted * cpatch%area * AREA_INV + hio_fire_fuel_moist_dead_si(io_si) = hio_fire_fuel_moist_dead_si(io_si) + cpatch%fuel%average_moisture_dead * cpatch%area * AREA_INV + hio_fire_fuel_moist_live_si(io_si) = hio_fire_fuel_moist_live_si(io_si) + cpatch%fuel%average_moisture_live * cpatch%area * AREA_INV + hio_fire_fuel_sav_si(io_si) = hio_fire_fuel_sav_si(io_si) + cpatch%fuel%SAV_weighted * cpatch%area * AREA_INV / m_per_cm + hio_fire_fuel_mef_dead_si(io_si) = hio_fire_fuel_mef_dead_si(io_si) + cpatch%fuel%MEF_dead * cpatch%area * AREA_INV + hio_fire_fuel_mef_live_si(io_si) = hio_fire_fuel_mef_live_si(io_si) + cpatch%fuel%MEF_live * cpatch%area * AREA_INV + hio_sum_fuel_si(io_si) = hio_sum_fuel_si(io_si) + cpatch%fuel%non_trunk_loading * cpatch%area * AREA_INV + hio_weighted_sum_fuel_si(io_si) = hio_weighted_sum_fuel_si(io_si) + (cpatch%fuel%weighted_loading_dead + & + cpatch%fuel%weighted_loading_live) * cpatch%area * AREA_INV + + hio_nonrx_intensity_fracarea_product_si(io_si) = hio_nonrx_intensity_fracarea_product_si(io_si) + & + cpatch%nonrx_FI * cpatch%nonrx_frac_burnt * cpatch%area * AREA_INV * J_per_kJ + + hio_rx_intensity_fracarea_product_si(io_si) = hio_rx_intensity_fracarea_product_si(io_si) + & + cpatch%rx_FI * cpatch%rx_frac_burnt * cpatch%area * AREA_INV * J_per_kJ + + hio_fire_intensity_fracarea_product_si(io_si) = hio_fire_intensity_fracarea_product_si(io_si) + & + cpatch%FI * cpatch%frac_burnt * cpatch%area * AREA_INV * J_per_kJ + + litt => cpatch%litter(element_pos(carbon12_element)) + + patch_fracarea = cpatch%area * AREA_INV + + ! 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%seed_decay(:)) + & + sum(litt%seed_germ_decay(:))) * & + patch_fracarea * 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(:))) * & + patch_fracarea + + ! Sum up total seed bank (just ungerminated) + hio_ungerm_seed_bank_si(io_si) = hio_ungerm_seed_bank_si(io_si) + & + sum(litt%seed(:)) * patch_fracarea + + ! Sum up total seedling pool + hio_seedling_pool_si(io_si) = hio_seedling_pool_si(io_si) + & + sum(litt%seed_germ(:)) * patch_fracarea + + ! 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(:))) * & + patch_fracarea * days_per_sec + + hio_seeds_in_local_si(io_si) = hio_seeds_in_local_si(io_si) + & + sum(litt%seed_in_local(:)) * & + patch_fracarea * days_per_sec + + ! loop through cohorts on patch + ccohort => cpatch%shortest + cohortloop: do while(associated(ccohort)) + + ft = ccohort%pft + n_perm2 = ccohort%n * AREA_INV + + ! Increment the number of cohorts per site + hio_ncohorts_si(io_si) = hio_ncohorts_si(io_si) + 1._r8 + + ! Update biomass components + ! Mass pools [kg] + elloop: do el = 1, num_elements + + call ccohort%prt%GetBiomass(element_list(el), & + sapw_m, struct_m, leaf_m, fnrt_m, store_m, repro_m, alive_m, total_m) + + ! 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 * & + store_m / m2_per_ha + this%hvars(ih_leafc_si)%r81d(io_si) = & + this%hvars(ih_leafc_si)%r81d(io_si) + ccohort%n * & + leaf_m / m2_per_ha + this%hvars(ih_fnrtc_si)%r81d(io_si) = & + this%hvars(ih_fnrtc_si)%r81d(io_si) + ccohort%n * & + fnrt_m / m2_per_ha + this%hvars(ih_reproc_si)%r81d(io_si) = & + this%hvars(ih_reproc_si)%r81d(io_si)+ ccohort%n * & + repro_m / m2_per_ha + this%hvars(ih_sapwc_si)%r81d(io_si) = & + this%hvars(ih_sapwc_si)%r81d(io_si) + ccohort%n * & + sapw_m / m2_per_ha + this%hvars(ih_totvegc_si)%r81d(io_si) = & + 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 + + 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 + + hio_agb_si(io_si) = hio_agb_si(io_si) + n_perm2 * & + ( leaf_m + (sapw_m + struct_m + store_m) * prt_params%allom_agb_frac(ccohort%pft) ) + + if( hlm_parteh_mode == prt_cnp_flex_allom_hyp) then + this%hvars(ih_l2fr_si)%r81d(io_si) = & + this%hvars(ih_l2fr_si)%r81d(io_si) + & + ccohort%l2fr *ccohort%n * fnrt_m / m2_per_ha + else + this%hvars(ih_l2fr_si)%r81d(io_si) = & + this%hvars(ih_l2fr_si)%r81d(io_si) + & + prt_params%allom_l2fr(ft) *ccohort%n * fnrt_m / m2_per_ha + end if + + elseif(element_list(el).eq.nitrogen_element)then + + 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 * & + store_m / m2_per_ha + this%hvars(ih_storentfrac_si)%r81d(io_si) = & + this%hvars(ih_storentfrac_si)%r81d(io_si) + ccohort%n * & + store_max / m2_per_ha + this%hvars(ih_leafn_si)%r81d(io_si) = & + this%hvars(ih_leafn_si)%r81d(io_si) + ccohort%n * & + leaf_m / m2_per_ha + this%hvars(ih_fnrtn_si)%r81d(io_si) = & + this%hvars(ih_fnrtn_si)%r81d(io_si) + ccohort%n * & + fnrt_m / m2_per_ha + this%hvars(ih_repron_si)%r81d(io_si) = & + this%hvars(ih_repron_si)%r81d(io_si) + ccohort%n * & + repro_m / m2_per_ha + this%hvars(ih_sapwn_si)%r81d(io_si) = & + this%hvars(ih_sapwn_si)%r81d(io_si) + ccohort%n * & + sapw_m / m2_per_ha + this%hvars(ih_totvegn_si)%r81d(io_si) = & + this%hvars(ih_totvegn_si)%r81d(io_si) + ccohort%n * & + total_m / m2_per_ha + + elseif(element_list(el).eq.phosphorus_element) then + + 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 * & + store_m / m2_per_ha + this%hvars(ih_storeptfrac_si)%r81d(io_si) = & + this%hvars(ih_storeptfrac_si)%r81d(io_si) + ccohort%n * & + store_max / m2_per_ha + this%hvars(ih_leafp_si)%r81d(io_si) = & + this%hvars(ih_leafp_si)%r81d(io_si) + ccohort%n * & + leaf_m / m2_per_ha + this%hvars(ih_fnrtp_si)%r81d(io_si) = & + this%hvars(ih_fnrtp_si)%r81d(io_si) + ccohort%n * & + fnrt_m / m2_per_ha + this%hvars(ih_reprop_si)%r81d(io_si) = & + this%hvars(ih_reprop_si)%r81d(io_si) + ccohort%n * & + repro_m / m2_per_ha + this%hvars(ih_sapwp_si)%r81d(io_si) = & + this%hvars(ih_sapwp_si)%r81d(io_si) + ccohort%n * & + sapw_m / m2_per_ha + this%hvars(ih_totvegp_si)%r81d(io_si) = & + this%hvars(ih_totvegp_si)%r81d(io_si)+ ccohort%n * & + total_m / m2_per_ha end if + end do elloop + + ! Carbon FLUXES --- + ! Flux Variables (cohorts must had experienced a day before any of these values + ! have any meaning, otherwise they are just inialization values + + call ccohort%prt%GetBiomass(carbon12_element , & + sapw_m, struct_m, leaf_m, fnrt_m, store_m, repro_m, alive_m, total_m) + + notnew: if( .not.(ccohort%isnew) ) then + + hio_npp_si(io_si) = hio_npp_si(io_si) + & + ccohort%npp_acc_hold * n_perm2 / days_per_year / sec_per_day + + hio_growth_resp_si(io_si) = hio_growth_resp_si(io_si) + & + ccohort%resp_g_acc_hold * n_perm2 / days_per_year / sec_per_day + + hio_aresp_si(io_si) = hio_aresp_si(io_si) + & + (ccohort%resp_g_acc_hold + ccohort%resp_m_acc_hold) * n_perm2 / days_per_year / sec_per_day + & + ccohort%resp_excess_hold * n_perm2 / sec_per_day + + ! Turnover pools [kgC/day] * [day/yr] = [kgC/yr] + sapw_m_turnover = ccohort%prt%GetTurnover(sapw_organ, carbon12_element) * days_per_year + store_m_turnover = ccohort%prt%GetTurnover(store_organ, carbon12_element) * days_per_year + leaf_m_turnover = ccohort%prt%GetTurnover(leaf_organ, carbon12_element) * days_per_year + fnrt_m_turnover = ccohort%prt%GetTurnover(fnrt_organ, carbon12_element) * days_per_year + struct_m_turnover = ccohort%prt%GetTurnover(struct_organ, carbon12_element) * days_per_year + + ! Net change from allocation and transport [kgC/day] * [day/yr] = [kgC/yr] + sapw_m_net_alloc = ccohort%prt%GetNetAlloc(sapw_organ, carbon12_element) * days_per_year + store_m_net_alloc = ccohort%prt%GetNetAlloc(store_organ, carbon12_element) * days_per_year + leaf_m_net_alloc = ccohort%prt%GetNetAlloc(leaf_organ, carbon12_element) * days_per_year + fnrt_m_net_alloc = ccohort%prt%GetNetAlloc(fnrt_organ, carbon12_element) * days_per_year + struct_m_net_alloc = ccohort%prt%GetNetAlloc(struct_organ, carbon12_element) * days_per_year + repro_m_net_alloc = ccohort%prt%GetNetAlloc(repro_organ, carbon12_element) * days_per_year + + ! ecosystem-level, organ-partitioned NPP/allocation fluxes + ! [kgC/yr] -> [kgC/sec] + hio_npp_leaf_si(io_si) = hio_npp_leaf_si(io_si) + & + leaf_m_net_alloc * n_perm2 / days_per_year / sec_per_day + hio_npp_seed_si(io_si) = hio_npp_seed_si(io_si) + & + repro_m_net_alloc * n_perm2 / days_per_year / sec_per_day + hio_npp_stem_si(io_si) = hio_npp_stem_si(io_si) + & + (sapw_m_net_alloc + struct_m_net_alloc) * n_perm2 * & + (prt_params%allom_agb_frac(ccohort%pft)) / & + days_per_year / sec_per_day + hio_npp_froot_si(io_si) = hio_npp_froot_si(io_si) + & + fnrt_m_net_alloc * n_perm2 / days_per_year / sec_per_day + hio_npp_croot_si(io_si) = hio_npp_croot_si(io_si) + & + (sapw_m_net_alloc + struct_m_net_alloc) * n_perm2 * & + (1._r8-prt_params%allom_agb_frac(ccohort%pft)) / & + days_per_year / sec_per_day + hio_npp_stor_si(io_si) = hio_npp_stor_si(io_si) + & + store_m_net_alloc * n_perm2 / days_per_year / sec_per_day - elseif(element_list(el).eq.nitrogen_element)then - - 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 * & - store_m / m2_per_ha - this%hvars(ih_storentfrac_si)%r81d(io_si) = & - this%hvars(ih_storentfrac_si)%r81d(io_si) + ccohort%n * & - store_max / m2_per_ha - this%hvars(ih_leafn_si)%r81d(io_si) = & - this%hvars(ih_leafn_si)%r81d(io_si) + ccohort%n * & - leaf_m / m2_per_ha - this%hvars(ih_fnrtn_si)%r81d(io_si) = & - this%hvars(ih_fnrtn_si)%r81d(io_si) + ccohort%n * & - fnrt_m / m2_per_ha - this%hvars(ih_repron_si)%r81d(io_si) = & - this%hvars(ih_repron_si)%r81d(io_si) + ccohort%n * & - repro_m / m2_per_ha - this%hvars(ih_sapwn_si)%r81d(io_si) = & - this%hvars(ih_sapwn_si)%r81d(io_si) + ccohort%n * & - sapw_m / m2_per_ha - this%hvars(ih_totvegn_si)%r81d(io_si) = & - this%hvars(ih_totvegn_si)%r81d(io_si) + ccohort%n * & - total_m / m2_per_ha - - elseif(element_list(el).eq.phosphorus_element) then - - 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 * & - store_m / m2_per_ha - this%hvars(ih_storeptfrac_si)%r81d(io_si) = & - this%hvars(ih_storeptfrac_si)%r81d(io_si) + ccohort%n * & - store_max / m2_per_ha - this%hvars(ih_leafp_si)%r81d(io_si) = & - this%hvars(ih_leafp_si)%r81d(io_si) + ccohort%n * & - leaf_m / m2_per_ha - this%hvars(ih_fnrtp_si)%r81d(io_si) = & - this%hvars(ih_fnrtp_si)%r81d(io_si) + ccohort%n * & - fnrt_m / m2_per_ha - this%hvars(ih_reprop_si)%r81d(io_si) = & - this%hvars(ih_reprop_si)%r81d(io_si) + ccohort%n * & - repro_m / m2_per_ha - this%hvars(ih_sapwp_si)%r81d(io_si) = & - this%hvars(ih_sapwp_si)%r81d(io_si) + ccohort%n * & - sapw_m / m2_per_ha - this%hvars(ih_totvegp_si)%r81d(io_si) = & - this%hvars(ih_totvegp_si)%r81d(io_si)+ ccohort%n * & - total_m / m2_per_ha - end if - end do elloop - - ! Carbon FLUXES --- - ! Flux Variables (cohorts must had experienced a day before any of these values - ! have any meaning, otherwise they are just inialization values - - call ccohort%prt%GetBiomass(carbon12_element , & - sapw_m, struct_m, leaf_m, fnrt_m, store_m, repro_m, alive_m, total_m) - - notnew: if( .not.(ccohort%isnew) ) then - - hio_npp_si(io_si) = hio_npp_si(io_si) + & - ccohort%npp_acc_hold * n_perm2 / days_per_year / sec_per_day - - hio_growth_resp_si(io_si) = hio_growth_resp_si(io_si) + & - ccohort%resp_g_acc_hold * n_perm2 / days_per_year / sec_per_day - - hio_aresp_si(io_si) = hio_aresp_si(io_si) + & - (ccohort%resp_g_acc_hold + ccohort%resp_m_acc_hold) * n_perm2 / days_per_year / sec_per_day + & - ccohort%resp_excess_hold * n_perm2 / sec_per_day - - ! Turnover pools [kgC/day] * [day/yr] = [kgC/yr] - sapw_m_turnover = ccohort%prt%GetTurnover(sapw_organ, carbon12_element) * days_per_year - store_m_turnover = ccohort%prt%GetTurnover(store_organ, carbon12_element) * days_per_year - leaf_m_turnover = ccohort%prt%GetTurnover(leaf_organ, carbon12_element) * days_per_year - fnrt_m_turnover = ccohort%prt%GetTurnover(fnrt_organ, carbon12_element) * days_per_year - struct_m_turnover = ccohort%prt%GetTurnover(struct_organ, carbon12_element) * days_per_year - - ! Net change from allocation and transport [kgC/day] * [day/yr] = [kgC/yr] - sapw_m_net_alloc = ccohort%prt%GetNetAlloc(sapw_organ, carbon12_element) * days_per_year - store_m_net_alloc = ccohort%prt%GetNetAlloc(store_organ, carbon12_element) * days_per_year - leaf_m_net_alloc = ccohort%prt%GetNetAlloc(leaf_organ, carbon12_element) * days_per_year - fnrt_m_net_alloc = ccohort%prt%GetNetAlloc(fnrt_organ, carbon12_element) * days_per_year - struct_m_net_alloc = ccohort%prt%GetNetAlloc(struct_organ, carbon12_element) * days_per_year - repro_m_net_alloc = ccohort%prt%GetNetAlloc(repro_organ, carbon12_element) * days_per_year - - ! ecosystem-level, organ-partitioned NPP/allocation fluxes - ! [kgC/yr] -> [kgC/sec] - hio_npp_leaf_si(io_si) = hio_npp_leaf_si(io_si) + & - leaf_m_net_alloc * n_perm2 / days_per_year / sec_per_day - hio_npp_seed_si(io_si) = hio_npp_seed_si(io_si) + & - repro_m_net_alloc * n_perm2 / days_per_year / sec_per_day - hio_npp_stem_si(io_si) = hio_npp_stem_si(io_si) + & - (sapw_m_net_alloc + struct_m_net_alloc) * n_perm2 * & - (prt_params%allom_agb_frac(ccohort%pft)) / & - days_per_year / sec_per_day - hio_npp_froot_si(io_si) = hio_npp_froot_si(io_si) + & - fnrt_m_net_alloc * n_perm2 / days_per_year / sec_per_day - hio_npp_croot_si(io_si) = hio_npp_croot_si(io_si) + & - (sapw_m_net_alloc + struct_m_net_alloc) * n_perm2 * & - (1._r8-prt_params%allom_agb_frac(ccohort%pft)) / & - days_per_year / sec_per_day - hio_npp_stor_si(io_si) = hio_npp_stor_si(io_si) + & - store_m_net_alloc * n_perm2 / days_per_year / sec_per_day - - leaf_herbivory = ccohort%prt%GetHerbivory(leaf_organ, carbon12_element) * days_per_year !cdkcdk - hio_grazing_si(io_si) = hio_grazing_si(io_si) + leaf_herbivory * n_perm2 / days_per_year / sec_per_day - - ! Woody State Variables (basal area growth increment) - if ( prt_params%woody(ft) == itrue) then - - cohort_ba = 0.25_r8*pi_const*((ccohort%dbh/100.0_r8)**2.0_r8)*ccohort%n - - hio_ba_weighted_height_si(io_si) = hio_ba_weighted_height_si(io_si) + & - ccohort%height * cohort_ba - - site_ba = site_ba + cohort_ba + leaf_herbivory = ccohort%prt%GetHerbivory(leaf_organ, carbon12_element) * days_per_year !cdkcdk + hio_grazing_si(io_si) = hio_grazing_si(io_si) + leaf_herbivory * n_perm2 / days_per_year / sec_per_day - end if + ! Woody State Variables (basal area growth increment) + if ( prt_params%woody(ft) == itrue) then - ! THIS NEEDS TO BE NORMALIZED - hio_ca_weighted_height_si(io_si) = hio_ca_weighted_height_si(io_si) + & - ccohort%height * ccohort%c_area / m2_per_ha + cohort_ba = 0.25_r8*pi_const*((ccohort%dbh/100.0_r8)**2.0_r8)*ccohort%n - site_ca = site_ca + ccohort%c_area / m2_per_ha + hio_ba_weighted_height_si(io_si) = hio_ba_weighted_height_si(io_si) + & + ccohort%height * cohort_ba - - ! Mortality Carbon Flux by layer - ! ---------------------------------------------------------------------------------- - if (ccohort%canopy_layer .eq. 1) then + site_ba = site_ba + cohort_ba + + end if - hio_canopy_mortality_carbonflux_si(io_si) = hio_canopy_mortality_carbonflux_si(io_si) + & - ccohort%SumMortForHistory(per_year = .false.) * total_m * ccohort%n * ha_per_m2 + ! THIS NEEDS TO BE NORMALIZED + hio_ca_weighted_height_si(io_si) = hio_ca_weighted_height_si(io_si) + & + ccohort%height * ccohort%c_area / m2_per_ha - hio_canopy_mortality_crownarea_si(io_si) = hio_canopy_mortality_crownarea_si(io_si) + & - ccohort%SumMortForHistory(per_year = .true.) * ccohort%c_area + site_ca = site_ca + ccohort%c_area / m2_per_ha - else - hio_ustory_mortality_carbonflux_si(io_si) = hio_ustory_mortality_carbonflux_si(io_si) + & - ccohort%SumMortForHistory(per_year = .false.) * total_m * ccohort%n * ha_per_m2 + ! Mortality Carbon Flux by layer + ! ---------------------------------------------------------------------------------- + if (ccohort%canopy_layer .eq. 1) then + + hio_canopy_mortality_carbonflux_si(io_si) = hio_canopy_mortality_carbonflux_si(io_si) + & + ccohort%SumMortForHistory(per_year = .false.) * total_m * ccohort%n * ha_per_m2 + + hio_canopy_mortality_crownarea_si(io_si) = hio_canopy_mortality_crownarea_si(io_si) + & + ccohort%SumMortForHistory(per_year = .true.) * ccohort%c_area + + else + + hio_ustory_mortality_carbonflux_si(io_si) = hio_ustory_mortality_carbonflux_si(io_si) + & + ccohort%SumMortForHistory(per_year = .false.) * total_m * ccohort%n * ha_per_m2 + + hio_ustory_mortality_crownarea_si(io_si) = hio_ustory_mortality_crownarea_si(io_si) + & + ccohort%SumMortForHistory(per_year = .true.) * ccohort%c_area + + end if - hio_ustory_mortality_crownarea_si(io_si) = hio_ustory_mortality_crownarea_si(io_si) + & - ccohort%SumMortForHistory(per_year = .true.) * ccohort%c_area + end if notnew + if (ccohort%canopy_layer .eq. 1) then + hio_canopy_biomass_si(io_si) = hio_canopy_biomass_si(io_si) + n_perm2 * total_m + else + hio_ustory_biomass_si(io_si) = hio_ustory_biomass_si(io_si) + n_perm2 * total_m end if - - end if notnew - if (ccohort%canopy_layer .eq. 1) then - hio_canopy_biomass_si(io_si) = hio_canopy_biomass_si(io_si) + n_perm2 * total_m - else - hio_ustory_biomass_si(io_si) = hio_ustory_biomass_si(io_si) + n_perm2 * total_m - end if - - ccohort => ccohort%taller - enddo cohortloop ! cohort loop + ccohort => ccohort%taller + enddo cohortloop ! cohort loop - cpatch => cpatch%younger - end do patchloop !patch loop + cpatch => cpatch%younger + end do patchloop !patch loop - ! Perform any necessary normalizations - ! ---------------------------------------------------------------------------------------- + ! Perform any necessary normalizations + ! ---------------------------------------------------------------------------------------- - ! Normalize crown-area weighted height - if(site_ca>nearzero)then - hio_ca_weighted_height_si(io_si) = hio_ca_weighted_height_si(io_si)/site_ca - end if + ! Normalize crown-area weighted height + if(site_ca>nearzero)then + hio_ca_weighted_height_si(io_si) = hio_ca_weighted_height_si(io_si)/site_ca + end if - ! divide basal-area-weighted height by basal area to get mean - if ( site_ba .gt. nearzero ) then - hio_ba_weighted_height_si(io_si) = hio_ba_weighted_height_si(io_si)/site_ba - endif - - elloop2: do el = 1, num_elements - if( element_list(el).eq.carbon12_element )then - 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 - elseif( 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) / & - this%hvars(ih_storentfrac_si)%r81d(io_si) - end if - elseif( element_list(el).eq.phosphorus_element )then - if( this%hvars(ih_storeptfrac_si)%r81d(io_si)>nearzero ) then - this%hvars(ih_storeptfrac_si)%r81d(io_si) = this%hvars(ih_storep_si)%r81d(io_si) / & - this%hvars(ih_storeptfrac_si)%r81d(io_si) + ! divide basal-area-weighted height by basal area to get mean + if ( site_ba .gt. nearzero ) then + hio_ba_weighted_height_si(io_si) = hio_ba_weighted_height_si(io_si)/site_ba + endif + + elloop2: do el = 1, num_elements + if( element_list(el).eq.carbon12_element )then + 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 + elseif( 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) / & + this%hvars(ih_storentfrac_si)%r81d(io_si) + end if + elseif( element_list(el).eq.phosphorus_element )then + if( this%hvars(ih_storeptfrac_si)%r81d(io_si)>nearzero ) then + this%hvars(ih_storeptfrac_si)%r81d(io_si) = this%hvars(ih_storep_si)%r81d(io_si) / & + this%hvars(ih_storeptfrac_si)%r81d(io_si) + end if end if + end do elloop2 + + + if(this%hvars(ih_fnrtc_si)%r81d(io_si)>nearzero)then + this%hvars(ih_l2fr_si)%r81d(io_si) = this%hvars(ih_l2fr_si)%r81d(io_si) / & + this%hvars(ih_fnrtc_si)%r81d(io_si) + else + this%hvars(ih_l2fr_si)%r81d(io_si) = hlm_hio_ignore_val end if - end do elloop2 + ! zero the site-level termination carbon flux variable + sites(s)%term_carbonflux_canopy(:,:) = 0._r8 + sites(s)%term_carbonflux_ustory(:,:) = 0._r8 + sites(s)%crownarea_canopy_damage = 0._r8 + sites(s)%crownarea_ustory_damage = 0._r8 - if(this%hvars(ih_fnrtc_si)%r81d(io_si)>nearzero)then - this%hvars(ih_l2fr_si)%r81d(io_si) = this%hvars(ih_l2fr_si)%r81d(io_si) / & - this%hvars(ih_fnrtc_si)%r81d(io_si) - else - this%hvars(ih_l2fr_si)%r81d(io_si) = hlm_hio_ignore_val - end if - - ! zero the site-level termination carbon flux variable - sites(s)%term_carbonflux_canopy(:,:) = 0._r8 - sites(s)%term_carbonflux_ustory(:,:) = 0._r8 - sites(s)%crownarea_canopy_damage = 0._r8 - sites(s)%crownarea_ustory_damage = 0._r8 + end do siteloop - end do siteloop + end associate + return + end subroutine update_history_dyn_sitelevel + + ! ========================================================================================= + + subroutine update_history_dyn_subsite(this,nc,nsites,sites,bc_in) + + ! --------------------------------------------------------------------------------- + ! This subroutine is intended to update all history variables with upfreq == + ! group_dyna_complx (i.e., that have a dimension in addition to that for the site + ! level) that do NOT include age class. So, eg., FATES_VEGC_PF is updated here, + ! but not FATES_VEGC or FATES_VEGC_APPF. + ! --------------------------------------------------------------------------------- - end associate - return - end subroutine update_history_dyn_sitelevel - - ! ========================================================================================= - - subroutine update_history_dyn_subsite(this,nc,nsites,sites,bc_in) - - ! --------------------------------------------------------------------------------- - ! This subroutine is intended to update all history variables with upfreq == - ! group_dyna_complx (i.e., that have a dimension in addition to that for the site - ! level) that do NOT include age class. So, eg., FATES_VEGC_PF is updated here, - ! but not FATES_VEGC or FATES_VEGC_APPF. - ! --------------------------------------------------------------------------------- - - ! 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) - - type(fates_cohort_type), pointer :: ccohort - type(fates_patch_type), pointer :: cpatch - type(litter_type), pointer :: litt_c ! Pointer to the carbon12 litter pool - type(litter_type), pointer :: litt ! Generic pointer to any litter pool - integer :: s ! site counter - integer :: ipa2 ! patch index matching host model array space - integer :: io_si ! site's index in the history output array space - integer :: el ! element index - integer :: ft ! pft index - real(r8) :: site_ba ! Site basal area used for weighting - integer :: model_day_int ! Integer model day since simulation start - real(r8) :: store_max ! Maximum storage capacity for carbon and nutrients - real(r8) :: sapw_m ! Sapwood mass (elemental, c,n or p) [kg/plant] - real(r8) :: struct_m ! Structural mass "" - real(r8) :: leaf_m ! Leaf mass "" - real(r8) :: fnrt_m ! Fineroot mass "" - real(r8) :: store_m ! Storage mass "" - real(r8) :: alive_m ! Alive biomass (sap+leaf+fineroot+repro+storage) "" - real(r8) :: total_m ! Total vegetation mass - real(r8) :: repro_m ! Total reproductive mass (on plant) "" - real(r8) :: sapw_m_turnover ! sapwood turnover rate [kg/yr] - real(r8) :: store_m_turnover ! storage turnover rate [kg/yr] - real(r8) :: leaf_m_turnover ! leaf turnover rate [kg/yr] - real(r8) :: fnrt_m_turnover ! fine-root turnover rate [kg/yr] - real(r8) :: struct_m_turnover ! structural turnover rate [kg/yr] - real(r8) :: sapw_m_net_alloc ! mass allocated to sapwood [kg/yr] - real(r8) :: store_m_net_alloc ! mass allocated to storage [kg/yr] - real(r8) :: leaf_m_net_alloc ! mass allocated to leaf [kg/yr] - real(r8) :: fnrt_m_net_alloc ! mass allocated to fine-root [kg/yr] - real(r8) :: struct_m_net_alloc ! mass allocated to structure [kg/yr] - real(r8) :: repro_m_net_alloc ! mass allocated to reproduction [kg/yr] - real(r8) :: n_perm2 ! abundance per m2 - integer :: iscag_anthrodist ! what is the equivalent age class for - ! time-since-anthropogenic-disturbance of secondary forest - real(r8) :: patch_fracarea ! Fraction of area for this patch - real(r8) :: frac_canopy_in_bin ! fraction of a leaf's canopy that is within a given height bin - real(r8) :: binbottom,bintop ! edges of height bins - integer :: height_bin_max, height_bin_min ! which height bin a given cohort's canopy is in - integer :: ican, ileaf, cnlf_indx ! iterators for leaf and canopy level - integer :: elcwd, i_cwd ! combined index of element and pft or cwd - integer :: i_scpf,i_pft,i_scls ! iterators for scpf, pft, and scls dims - integer :: i_cacls, i_capf ! iterators for cohort age and cohort age x pft - integer :: i_fuel ! iterators for fuel dims - integer :: i_heightbin ! iterator for height bins - integer :: ilyr ! Soil index for nlevsoil - integer :: icdpf, icdsc, icdam ! iterators for the crown damage level - real(r8) :: gpp_cached ! gpp from previous timestep, for c13 discrimination - real(r8) :: crown_depth ! Depth of the crown [m] - real(r8) :: gpp_cached_scpf(numpft*nlevsclass) ! variable used to cache gpp value in previous time step; for C13 discrimination - 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) - real(r8) :: a_sapw ! sapwood area [m^2] - real(r8) :: c_sapw ! sapwood biomass [kgC] - - integer :: i_dist, j_dist - - type(elem_diag_type), pointer :: elflux_diags - type(elem_diag_type), pointer :: elflux_diags_c - - - real(r8), parameter :: reallytalltrees = 1000. ! some large number (m) - - associate( hio_biomass_si_pft => this%hvars(ih_biomass_si_pft)%r82d, & + ! 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) + + type(fates_cohort_type), pointer :: ccohort + type(fates_patch_type), pointer :: cpatch + type(litter_type), pointer :: litt_c ! Pointer to the carbon12 litter pool + type(litter_type), pointer :: litt ! Generic pointer to any litter pool + integer :: s ! site counter + integer :: ipa2 ! patch index matching host model array space + integer :: io_si ! site's index in the history output array space + integer :: el ! element index + integer :: ft ! pft index + real(r8) :: site_ba ! Site basal area used for weighting + integer :: model_day_int ! Integer model day since simulation start + real(r8) :: store_max ! Maximum storage capacity for carbon and nutrients + real(r8) :: sapw_m ! Sapwood mass (elemental, c,n or p) [kg/plant] + real(r8) :: struct_m ! Structural mass "" + real(r8) :: leaf_m ! Leaf mass "" + real(r8) :: fnrt_m ! Fineroot mass "" + real(r8) :: store_m ! Storage mass "" + real(r8) :: alive_m ! Alive biomass (sap+leaf+fineroot+repro+storage) "" + real(r8) :: total_m ! Total vegetation mass + real(r8) :: repro_m ! Total reproductive mass (on plant) "" + real(r8) :: sapw_m_turnover ! sapwood turnover rate [kg/yr] + real(r8) :: store_m_turnover ! storage turnover rate [kg/yr] + real(r8) :: leaf_m_turnover ! leaf turnover rate [kg/yr] + real(r8) :: fnrt_m_turnover ! fine-root turnover rate [kg/yr] + real(r8) :: struct_m_turnover ! structural turnover rate [kg/yr] + real(r8) :: sapw_m_net_alloc ! mass allocated to sapwood [kg/yr] + real(r8) :: store_m_net_alloc ! mass allocated to storage [kg/yr] + real(r8) :: leaf_m_net_alloc ! mass allocated to leaf [kg/yr] + real(r8) :: fnrt_m_net_alloc ! mass allocated to fine-root [kg/yr] + real(r8) :: struct_m_net_alloc ! mass allocated to structure [kg/yr] + real(r8) :: repro_m_net_alloc ! mass allocated to reproduction [kg/yr] + real(r8) :: n_perm2 ! abundance per m2 + integer :: iscag_anthrodist ! what is the equivalent age class for + ! time-since-anthropogenic-disturbance of secondary forest + real(r8) :: patch_fracarea ! Fraction of area for this patch + real(r8) :: frac_canopy_in_bin ! fraction of a leaf's canopy that is within a given height bin + real(r8) :: binbottom,bintop ! edges of height bins + integer :: height_bin_max, height_bin_min ! which height bin a given cohort's canopy is in + integer :: ican, ileaf, cnlf_indx ! iterators for leaf and canopy level + integer :: elcwd, i_cwd ! combined index of element and pft or cwd + integer :: i_scpf,i_pft,i_scls ! iterators for scpf, pft, and scls dims + integer :: i_cacls, i_capf ! iterators for cohort age and cohort age x pft + integer :: i_fuel ! iterators for fuel dims + integer :: i_heightbin ! iterator for height bins + integer :: ilyr ! Soil index for nlevsoil + integer :: icdpf, icdsc, icdam ! iterators for the crown damage level + real(r8) :: gpp_cached ! gpp from previous timestep, for c13 discrimination + real(r8) :: crown_depth ! Depth of the crown [m] + real(r8) :: gpp_cached_scpf(numpft*nlevsclass) ! variable used to cache gpp value in previous time step; for C13 discrimination + 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) + real(r8) :: a_sapw ! sapwood area [m^2] + real(r8) :: c_sapw ! sapwood biomass [kgC] + + integer :: i_dist, j_dist + + type(elem_diag_type), pointer :: elflux_diags + type(elem_diag_type), pointer :: elflux_diags_c + + + real(r8), parameter :: reallytalltrees = 1000. ! some large number (m) + + associate( hio_biomass_si_pft => this%hvars(ih_biomass_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, & @@ -3244,1543 +3254,1543 @@ subroutine update_history_dyn_subsite(this,nc,nsites,sites,bc_in) hio_m10_si_cacls => this%hvars(ih_m10_si_cacls)%r82d, & hio_m12_si_scls => this%hvars(ih_m12_si_scls)%r82d) - ! Break up associates for NAG compilers - associate(hio_c13disc_si_scpf => this%hvars(ih_c13disc_si_scpf)%r82d, & - hio_cwd_elcwd => this%hvars(ih_cwd_elcwd)%r82d, & - hio_cwd_ag_elem => this%hvars(ih_cwd_ag_elem)%r82d, & - hio_cwd_bg_elem => this%hvars(ih_cwd_bg_elem)%r82d, & - hio_fines_ag_elem => this%hvars(ih_fines_ag_elem)%r82d, & - hio_fines_bg_elem => this%hvars(ih_fines_bg_elem)%r82d, & - hio_ba_si_scls => this%hvars(ih_ba_si_scls)%r82d, & - hio_agb_si_scls => this%hvars(ih_agb_si_scls)%r82d, & - hio_biomass_si_scls => this%hvars(ih_biomass_si_scls)%r82d, & - hio_nplant_si_scls => this%hvars(ih_nplant_si_scls)%r82d, & - hio_nplant_si_cacls => this%hvars(ih_nplant_si_cacls)%r82d, & - hio_nplant_canopy_si_scls => this%hvars(ih_nplant_canopy_si_scls)%r82d, & - hio_nplant_understory_si_scls => this%hvars(ih_nplant_understory_si_scls)%r82d, & - hio_lai_canopy_si_scls => this%hvars(ih_lai_canopy_si_scls)%r82d, & - hio_lai_understory_si_scls => this%hvars(ih_lai_understory_si_scls)%r82d, & - hio_sai_canopy_si_scls => this%hvars(ih_sai_canopy_si_scls)%r82d, & - hio_sai_understory_si_scls => this%hvars(ih_sai_understory_si_scls)%r82d, & - hio_mortality_canopy_si_scls => this%hvars(ih_mortality_canopy_si_scls)%r82d, & - hio_mortality_understory_si_scls => this%hvars(ih_mortality_understory_si_scls)%r82d, & - hio_demotion_rate_si_scls => this%hvars(ih_demotion_rate_si_scls)%r82d, & - hio_promotion_rate_si_scls => this%hvars(ih_promotion_rate_si_scls)%r82d, & - hio_trimming_canopy_si_scls => this%hvars(ih_trimming_canopy_si_scls)%r82d, & - hio_trimming_understory_si_scls => this%hvars(ih_trimming_understory_si_scls)%r82d, & - hio_crown_fracarea_canopy_si_scls => this%hvars(ih_crown_fracarea_canopy_si_scls)%r82d, & - hio_crown_fracarea_understory_si_scls => this%hvars(ih_crown_fracarea_understory_si_scls)%r82d, & - hio_leaf_md_canopy_si_scls => this%hvars(ih_leaf_md_canopy_si_scls)%r82d, & - hio_root_md_canopy_si_scls => this%hvars(ih_root_md_canopy_si_scls)%r82d, & - hio_carbon_balance_canopy_si_scls => this%hvars(ih_carbon_balance_canopy_si_scls)%r82d, & - hio_bsw_md_canopy_si_scls => this%hvars(ih_bsw_md_canopy_si_scls)%r82d, & - hio_bdead_md_canopy_si_scls => this%hvars(ih_bdead_md_canopy_si_scls)%r82d, & - hio_bstore_md_canopy_si_scls => this%hvars(ih_bstore_md_canopy_si_scls)%r82d, & - hio_seed_prod_canopy_si_scls => this%hvars(ih_seed_prod_canopy_si_scls)%r82d, & - hio_npp_leaf_canopy_si_scls => this%hvars(ih_npp_leaf_canopy_si_scls)%r82d, & - hio_npp_fnrt_canopy_si_scls => this%hvars(ih_npp_fnrt_canopy_si_scls)%r82d, & - hio_npp_sapw_canopy_si_scls => this%hvars(ih_npp_sapw_canopy_si_scls)%r82d, & - hio_npp_dead_canopy_si_scls => this%hvars(ih_npp_dead_canopy_si_scls)%r82d, & - hio_npp_seed_canopy_si_scls => this%hvars(ih_npp_seed_canopy_si_scls)%r82d, & - hio_npp_stor_canopy_si_scls => this%hvars(ih_npp_stor_canopy_si_scls)%r82d, & - hio_leaf_md_understory_si_scls => this%hvars(ih_leaf_md_understory_si_scls)%r82d, & - hio_root_md_understory_si_scls => this%hvars(ih_root_md_understory_si_scls)%r82d, & - hio_carbon_balance_understory_si_scls=> this%hvars(ih_carbon_balance_understory_si_scls)%r82d, & - hio_bstore_md_understory_si_scls => this%hvars(ih_bstore_md_understory_si_scls)%r82d, & - hio_bsw_md_understory_si_scls => this%hvars(ih_bsw_md_understory_si_scls)%r82d, & - hio_bdead_md_understory_si_scls => this%hvars(ih_bdead_md_understory_si_scls)%r82d, & - hio_seed_prod_understory_si_scls => this%hvars(ih_seed_prod_understory_si_scls)%r82d, & - hio_npp_leaf_understory_si_scls => this%hvars(ih_npp_leaf_understory_si_scls)%r82d, & - hio_npp_fnrt_understory_si_scls => this%hvars(ih_npp_fnrt_understory_si_scls)%r82d, & - hio_npp_sapw_understory_si_scls => this%hvars(ih_npp_sapw_understory_si_scls)%r82d, & - hio_npp_dead_understory_si_scls => this%hvars(ih_npp_dead_understory_si_scls)%r82d, & - hio_npp_seed_understory_si_scls => this%hvars(ih_npp_seed_understory_si_scls)%r82d, & - hio_npp_stor_understory_si_scls => this%hvars(ih_npp_stor_understory_si_scls)%r82d, & - hio_yesterdaycanopylevel_canopy_si_scls => this%hvars(ih_yesterdaycanopylevel_canopy_si_scls)%r82d, & - hio_yesterdaycanopylevel_understory_si_scls => this%hvars(ih_yesterdaycanopylevel_understory_si_scls)%r82d, & - hio_fracarea_si => this%hvars(ih_fracarea_si)%r81d, & - hio_canopy_fracarea_si => this%hvars(ih_canopy_fracarea_si)%r81d, & - hio_agesince_anthrodist_si => this%hvars(ih_agesince_anthrodist_si)%r81d, & - hio_primarylands_fracarea_si => this%hvars(ih_primarylands_fracarea_si)%r81d, & - hio_secondarylands_fracarea_si => this%hvars(ih_secondarylands_fracarea_si)%r81d, & - hio_fracarea_si_landuse => this%hvars(ih_fracarea_si_landuse)%r82d, & - hio_npp_si_landuse => this%hvars(ih_npp_si_landuse)%r82d, & - hio_biomass_si_landuse => this%hvars(ih_biomass_si_landuse)%r82d, & - hio_burnedarea_si_landuse => this%hvars(ih_burnedarea_si_landuse)%r82d, & - hio_burnt_frac_litter_si_fuel => this%hvars(ih_burnt_frac_litter_si_fuel)%r82d, & - hio_fuel_amount_si_fuel => this%hvars(ih_fuel_amount_si_fuel)%r82d, & - hio_canopy_height_dist_si_height => this%hvars(ih_canopy_height_dist_si_height)%r82d, & - hio_leaf_height_dist_si_height => this%hvars(ih_leaf_height_dist_si_height)%r82d, & - hio_litter_moisture_si_fuel => this%hvars(ih_litter_moisture_si_fuel)%r82d, & - hio_cwd_ag_si_cwdsc => this%hvars(ih_cwd_ag_si_cwdsc)%r82d, & - hio_cwd_bg_si_cwdsc => this%hvars(ih_cwd_bg_si_cwdsc)%r82d, & - hio_cwd_ag_in_si_cwdsc => this%hvars(ih_cwd_ag_in_si_cwdsc)%r82d, & - hio_cwd_bg_in_si_cwdsc => this%hvars(ih_cwd_bg_in_si_cwdsc)%r82d, & - hio_cwd_ag_out_si_cwdsc => this%hvars(ih_cwd_ag_out_si_cwdsc)%r82d, & - 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_cl => this%hvars(ih_crownarea_cl)%r82d) - - ! Break up associates for NAG compilers - associate( 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_seed_bank_si_pft => this%hvars(ih_seed_bank_si_pft)%r82d, & - hio_ungerm_seed_bank_si_pft => this%hvars(ih_ungerm_seed_bank_si_pft)%r82d, & - hio_seedling_pool_si_pft => this%hvars(ih_seedling_pool_si_pft)%r82d, & - hio_seeds_in_si_pft => this%hvars(ih_seeds_in_si_pft)%r82d, & - hio_seeds_in_local_si_pft => this%hvars(ih_seeds_in_local_si_pft)%r82d, & - hio_disturbance_rate_si_lulu => this%hvars(ih_disturbance_rate_si_lulu)%r82d, & - hio_cstarvmortality_continuous_carbonflux_si_pft => this%hvars(ih_cstarvmortality_continuous_carbonflux_si_pft)%r82d, & - hio_transition_matrix_si_lulu => this%hvars(ih_transition_matrix_si_lulu)%r82d, & - hio_scorch_height_si_pft => this%hvars(ih_scorch_height_si_pft)%r82d, & - hio_sapwood_area_scpf => this%hvars(ih_sapwood_area_scpf)%r82d) - - model_day_int = nint(hlm_model_day) - - ! --------------------------------------------------------------------------------- - ! Loop through the FATES scale hierarchy and fill the history IO arrays - ! --------------------------------------------------------------------------------- - - - siteloop: do s = 1,nsites - - io_si = sites(s)%h_gid - - ! C13 will not get b4b restarts on the first day because - ! there is no mechanism to remember the previous day's values - ! through a restart. This should be added with the next refactor - gpp_cached_scpf(:) = hio_gpp_si_scpf(io_si,:) - - call this%zero_site_hvars(sites(s),upfreq_in=group_dyna_complx) - - ! 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 - - do i_dist = 1, n_landuse_cats - do j_dist = 1, n_landuse_cats - - ! roll up disturbance rates in land-use x land-use array into a single dimension - hio_disturbance_rate_si_lulu(io_si, i_dist+n_landuse_cats*(j_dist-1)) = & - sum(sites(s)%disturbance_rates(1:n_dist_types,i_dist, j_dist)) * & - days_per_year - - ! get the land use transition matrix and output that to history. - ! (mainly a sanity check, can maybe remove before integration) - hio_transition_matrix_si_lulu(io_si, i_dist+n_landuse_cats*(j_dist-1)) = & - sites(s)%landuse_transition_matrix(i_dist, j_dist) - end do - end do - - do el = 1, num_elements - - if((hlm_use_ed_st3 .eq. ifalse) .and. (hlm_use_sp .eq. ifalse)) then - - ! Total model error [kg/day -> kg/s] (all elements) - this%hvars(ih_err_fates_elem)%r82d(io_si,el) = sites(s)%mass_balance(el)%err_fates / sec_per_day - - this%hvars(ih_interr_liveveg_elem)%r82d(io_si,el) = sites(s)%flux_diags%elem(el)%err_liveveg - - this%hvars(ih_interr_litter_elem)%r82d(io_si,el) = sites(s)%flux_diags%elem(el)%err_litter - - end if - - ! Total element lost to atmosphere from burning (kg/site/day -> kg/m2/s) - hio_burn_flux_elem(io_si,el) = & - sites(s)%mass_balance(el)%burn_flux_to_atm * ha_per_m2 * & - days_per_sec - - end do - - - ! Update drought deciduous information (now separated by PFT). - do ft = 1,numpft - ! Update the site-PFT status for drought deciduous - hio_site_dstatus_si_pft(io_si,ft) = real(sites(s)%dstatus(ft),r8) - - ! Model days elapsed since leaf off/on for drought deciduous - hio_dleafoff_si_pft(io_si,ft) = real(sites(s)%dndaysleafon (ft),r8) - hio_dleafon_si_pft(io_si,ft) = real(sites(s)%dndaysleafoff(ft),r8) - - ! Leaf elongation factor (0 means fully abscissed, 1 means fully flushed). - hio_elong_factor_si_pft(io_si,ft) = sites(s)%elong_factor(ft) - - if(model_day_int>numWaterMem)then - ! Mean liquid water content (m3/m3) used for drought phenology - hio_meanliqvol_si_pft(io_si,ft) = & - sum(sites(s)%liqvol_memory(1:numWaterMem,ft))/real(numWaterMem,r8) - - ! Mean soil matric potential (Pa) used for drought phenology - hio_meansmp_si_pft(io_si,ft) = & - sum(sites(s)%smp_memory(1:numWaterMem,ft))/real(numWaterMem,r8) & - * dens_fresh_liquid_water * grav_earth * m_per_mm - end if - end do - - ! Loop through patches to sum up diagonistics - cpatch => sites(s)%oldest_patch - patchloop: do while(associated(cpatch)) - - hio_fracarea_si(io_si) = hio_fracarea_si(io_si) & - + cpatch%area * AREA_INV - - ! ignore land use info on nocomp bareground (where landuse label = 0) - if (cpatch%land_use_label .gt. nocomp_bareground_land) then - hio_fracarea_si_landuse(io_si, cpatch%land_use_label) = & - hio_fracarea_si_landuse(io_si, cpatch%land_use_label) & - + cpatch%area * AREA_INV + ! Break up associates for NAG compilers + associate(hio_c13disc_si_scpf => this%hvars(ih_c13disc_si_scpf)%r82d, & + hio_cwd_elcwd => this%hvars(ih_cwd_elcwd)%r82d, & + hio_cwd_ag_elem => this%hvars(ih_cwd_ag_elem)%r82d, & + hio_cwd_bg_elem => this%hvars(ih_cwd_bg_elem)%r82d, & + hio_fines_ag_elem => this%hvars(ih_fines_ag_elem)%r82d, & + hio_fines_bg_elem => this%hvars(ih_fines_bg_elem)%r82d, & + hio_ba_si_scls => this%hvars(ih_ba_si_scls)%r82d, & + hio_agb_si_scls => this%hvars(ih_agb_si_scls)%r82d, & + hio_biomass_si_scls => this%hvars(ih_biomass_si_scls)%r82d, & + hio_nplant_si_scls => this%hvars(ih_nplant_si_scls)%r82d, & + hio_nplant_si_cacls => this%hvars(ih_nplant_si_cacls)%r82d, & + hio_nplant_canopy_si_scls => this%hvars(ih_nplant_canopy_si_scls)%r82d, & + hio_nplant_understory_si_scls => this%hvars(ih_nplant_understory_si_scls)%r82d, & + hio_lai_canopy_si_scls => this%hvars(ih_lai_canopy_si_scls)%r82d, & + hio_lai_understory_si_scls => this%hvars(ih_lai_understory_si_scls)%r82d, & + hio_sai_canopy_si_scls => this%hvars(ih_sai_canopy_si_scls)%r82d, & + hio_sai_understory_si_scls => this%hvars(ih_sai_understory_si_scls)%r82d, & + hio_mortality_canopy_si_scls => this%hvars(ih_mortality_canopy_si_scls)%r82d, & + hio_mortality_understory_si_scls => this%hvars(ih_mortality_understory_si_scls)%r82d, & + hio_demotion_rate_si_scls => this%hvars(ih_demotion_rate_si_scls)%r82d, & + hio_promotion_rate_si_scls => this%hvars(ih_promotion_rate_si_scls)%r82d, & + hio_trimming_canopy_si_scls => this%hvars(ih_trimming_canopy_si_scls)%r82d, & + hio_trimming_understory_si_scls => this%hvars(ih_trimming_understory_si_scls)%r82d, & + hio_crown_fracarea_canopy_si_scls => this%hvars(ih_crown_fracarea_canopy_si_scls)%r82d, & + hio_crown_fracarea_understory_si_scls => this%hvars(ih_crown_fracarea_understory_si_scls)%r82d, & + hio_leaf_md_canopy_si_scls => this%hvars(ih_leaf_md_canopy_si_scls)%r82d, & + hio_root_md_canopy_si_scls => this%hvars(ih_root_md_canopy_si_scls)%r82d, & + hio_carbon_balance_canopy_si_scls => this%hvars(ih_carbon_balance_canopy_si_scls)%r82d, & + hio_bsw_md_canopy_si_scls => this%hvars(ih_bsw_md_canopy_si_scls)%r82d, & + hio_bdead_md_canopy_si_scls => this%hvars(ih_bdead_md_canopy_si_scls)%r82d, & + hio_bstore_md_canopy_si_scls => this%hvars(ih_bstore_md_canopy_si_scls)%r82d, & + hio_seed_prod_canopy_si_scls => this%hvars(ih_seed_prod_canopy_si_scls)%r82d, & + hio_npp_leaf_canopy_si_scls => this%hvars(ih_npp_leaf_canopy_si_scls)%r82d, & + hio_npp_fnrt_canopy_si_scls => this%hvars(ih_npp_fnrt_canopy_si_scls)%r82d, & + hio_npp_sapw_canopy_si_scls => this%hvars(ih_npp_sapw_canopy_si_scls)%r82d, & + hio_npp_dead_canopy_si_scls => this%hvars(ih_npp_dead_canopy_si_scls)%r82d, & + hio_npp_seed_canopy_si_scls => this%hvars(ih_npp_seed_canopy_si_scls)%r82d, & + hio_npp_stor_canopy_si_scls => this%hvars(ih_npp_stor_canopy_si_scls)%r82d, & + hio_leaf_md_understory_si_scls => this%hvars(ih_leaf_md_understory_si_scls)%r82d, & + hio_root_md_understory_si_scls => this%hvars(ih_root_md_understory_si_scls)%r82d, & + hio_carbon_balance_understory_si_scls=> this%hvars(ih_carbon_balance_understory_si_scls)%r82d, & + hio_bstore_md_understory_si_scls => this%hvars(ih_bstore_md_understory_si_scls)%r82d, & + hio_bsw_md_understory_si_scls => this%hvars(ih_bsw_md_understory_si_scls)%r82d, & + hio_bdead_md_understory_si_scls => this%hvars(ih_bdead_md_understory_si_scls)%r82d, & + hio_seed_prod_understory_si_scls => this%hvars(ih_seed_prod_understory_si_scls)%r82d, & + hio_npp_leaf_understory_si_scls => this%hvars(ih_npp_leaf_understory_si_scls)%r82d, & + hio_npp_fnrt_understory_si_scls => this%hvars(ih_npp_fnrt_understory_si_scls)%r82d, & + hio_npp_sapw_understory_si_scls => this%hvars(ih_npp_sapw_understory_si_scls)%r82d, & + hio_npp_dead_understory_si_scls => this%hvars(ih_npp_dead_understory_si_scls)%r82d, & + hio_npp_seed_understory_si_scls => this%hvars(ih_npp_seed_understory_si_scls)%r82d, & + hio_npp_stor_understory_si_scls => this%hvars(ih_npp_stor_understory_si_scls)%r82d, & + hio_yesterdaycanopylevel_canopy_si_scls => this%hvars(ih_yesterdaycanopylevel_canopy_si_scls)%r82d, & + hio_yesterdaycanopylevel_understory_si_scls => this%hvars(ih_yesterdaycanopylevel_understory_si_scls)%r82d, & + hio_fracarea_si => this%hvars(ih_fracarea_si)%r81d, & + hio_canopy_fracarea_si => this%hvars(ih_canopy_fracarea_si)%r81d, & + hio_agesince_anthrodist_si => this%hvars(ih_agesince_anthrodist_si)%r81d, & + hio_primarylands_fracarea_si => this%hvars(ih_primarylands_fracarea_si)%r81d, & + hio_secondarylands_fracarea_si => this%hvars(ih_secondarylands_fracarea_si)%r81d, & + hio_fracarea_si_landuse => this%hvars(ih_fracarea_si_landuse)%r82d, & + hio_npp_si_landuse => this%hvars(ih_npp_si_landuse)%r82d, & + hio_biomass_si_landuse => this%hvars(ih_biomass_si_landuse)%r82d, & + hio_burnedarea_si_landuse => this%hvars(ih_burnedarea_si_landuse)%r82d, & + hio_burnt_frac_litter_si_fuel => this%hvars(ih_burnt_frac_litter_si_fuel)%r82d, & + hio_fuel_amount_si_fuel => this%hvars(ih_fuel_amount_si_fuel)%r82d, & + hio_canopy_height_dist_si_height => this%hvars(ih_canopy_height_dist_si_height)%r82d, & + hio_leaf_height_dist_si_height => this%hvars(ih_leaf_height_dist_si_height)%r82d, & + hio_litter_moisture_si_fuel => this%hvars(ih_litter_moisture_si_fuel)%r82d, & + hio_cwd_ag_si_cwdsc => this%hvars(ih_cwd_ag_si_cwdsc)%r82d, & + hio_cwd_bg_si_cwdsc => this%hvars(ih_cwd_bg_si_cwdsc)%r82d, & + hio_cwd_ag_in_si_cwdsc => this%hvars(ih_cwd_ag_in_si_cwdsc)%r82d, & + hio_cwd_bg_in_si_cwdsc => this%hvars(ih_cwd_bg_in_si_cwdsc)%r82d, & + hio_cwd_ag_out_si_cwdsc => this%hvars(ih_cwd_ag_out_si_cwdsc)%r82d, & + 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_cl => this%hvars(ih_crownarea_cl)%r82d) + + ! Break up associates for NAG compilers + associate( 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_seed_bank_si_pft => this%hvars(ih_seed_bank_si_pft)%r82d, & + hio_ungerm_seed_bank_si_pft => this%hvars(ih_ungerm_seed_bank_si_pft)%r82d, & + hio_seedling_pool_si_pft => this%hvars(ih_seedling_pool_si_pft)%r82d, & + hio_seeds_in_si_pft => this%hvars(ih_seeds_in_si_pft)%r82d, & + hio_seeds_in_local_si_pft => this%hvars(ih_seeds_in_local_si_pft)%r82d, & + hio_disturbance_rate_si_lulu => this%hvars(ih_disturbance_rate_si_lulu)%r82d, & + hio_cstarvmortality_continuous_carbonflux_si_pft => this%hvars(ih_cstarvmortality_continuous_carbonflux_si_pft)%r82d, & + hio_transition_matrix_si_lulu => this%hvars(ih_transition_matrix_si_lulu)%r82d, & + hio_scorch_height_si_pft => this%hvars(ih_scorch_height_si_pft)%r82d, & + hio_sapwood_area_scpf => this%hvars(ih_sapwood_area_scpf)%r82d) + + model_day_int = nint(hlm_model_day) + + ! --------------------------------------------------------------------------------- + ! Loop through the FATES scale hierarchy and fill the history IO arrays + ! --------------------------------------------------------------------------------- + + + siteloop: do s = 1,nsites + + io_si = sites(s)%h_gid + + ! C13 will not get b4b restarts on the first day because + ! there is no mechanism to remember the previous day's values + ! through a restart. This should be added with the next refactor + gpp_cached_scpf(:) = hio_gpp_si_scpf(io_si,:) + + call this%zero_site_hvars(sites(s),upfreq_in=group_dyna_complx) + + ! 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 + + do i_dist = 1, n_landuse_cats + do j_dist = 1, n_landuse_cats + + ! roll up disturbance rates in land-use x land-use array into a single dimension + hio_disturbance_rate_si_lulu(io_si, i_dist+n_landuse_cats*(j_dist-1)) = & + sum(sites(s)%disturbance_rates(1:n_dist_types,i_dist, j_dist)) * & + days_per_year + + ! get the land use transition matrix and output that to history. + ! (mainly a sanity check, can maybe remove before integration) + hio_transition_matrix_si_lulu(io_si, i_dist+n_landuse_cats*(j_dist-1)) = & + sites(s)%landuse_transition_matrix(i_dist, j_dist) + end do + end do + + do el = 1, num_elements + + if((hlm_use_ed_st3 .eq. ifalse) .and. (hlm_use_sp .eq. ifalse)) then + + ! Total model error [kg/day -> kg/s] (all elements) + this%hvars(ih_err_fates_elem)%r82d(io_si,el) = sites(s)%mass_balance(el)%err_fates / sec_per_day + + this%hvars(ih_interr_liveveg_elem)%r82d(io_si,el) = sites(s)%flux_diags%elem(el)%err_liveveg + + this%hvars(ih_interr_litter_elem)%r82d(io_si,el) = sites(s)%flux_diags%elem(el)%err_litter - hio_burnedarea_si_landuse(io_si, cpatch%land_use_label) = & - hio_burnedarea_si_landuse(io_si, cpatch%land_use_label) + & - cpatch%frac_burnt * cpatch%area * AREA_INV / sec_per_day - end if + end if - ! some diagnostics on secondary forest area and its age distribution - if ( cpatch%land_use_label .eq. secondaryland ) then + ! Total element lost to atmosphere from burning (kg/site/day -> kg/m2/s) + hio_burn_flux_elem(io_si,el) = & + sites(s)%mass_balance(el)%burn_flux_to_atm * ha_per_m2 * & + days_per_sec - hio_agesince_anthrodist_si(io_si) = & - hio_agesince_anthrodist_si(io_si) & - + cpatch%area * AREA_INV + end do - hio_secondarylands_fracarea_si(io_si) = & - hio_secondarylands_fracarea_si(io_si) & - + cpatch%area * AREA_INV - else if ( cpatch%land_use_label .eq. primaryland ) then + ! Update drought deciduous information (now separated by PFT). + do ft = 1,numpft + ! Update the site-PFT status for drought deciduous + hio_site_dstatus_si_pft(io_si,ft) = real(sites(s)%dstatus(ft),r8) + + ! Model days elapsed since leaf off/on for drought deciduous + hio_dleafoff_si_pft(io_si,ft) = real(sites(s)%dndaysleafon (ft),r8) + hio_dleafon_si_pft(io_si,ft) = real(sites(s)%dndaysleafoff(ft),r8) - hio_primarylands_fracarea_si(io_si) = & - hio_primarylands_fracarea_si(io_si) & - + cpatch%area * AREA_INV + ! Leaf elongation factor (0 means fully abscissed, 1 means fully flushed). + hio_elong_factor_si_pft(io_si,ft) = sites(s)%elong_factor(ft) - endif + if(model_day_int>numWaterMem)then + ! Mean liquid water content (m3/m3) used for drought phenology + hio_meanliqvol_si_pft(io_si,ft) = & + sum(sites(s)%liqvol_memory(1:numWaterMem,ft))/real(numWaterMem,r8) - do ft = 1,numpft - hio_scorch_height_si_pft(io_si,ft) = hio_scorch_height_si_pft(io_si,ft) + & - cpatch%Scorch_ht(ft) * cpatch%area * AREA_INV + ! Mean soil matric potential (Pa) used for drought phenology + hio_meansmp_si_pft(io_si,ft) = & + sum(sites(s)%smp_memory(1:numWaterMem,ft))/real(numWaterMem,r8) & + * dens_fresh_liquid_water * grav_earth * m_per_mm + end if + end do + + ! Loop through patches to sum up diagonistics + cpatch => sites(s)%oldest_patch + patchloop: do while(associated(cpatch)) - ! weight the value by patch area within any given age class - in the event that - ! there is more than one patch per age class - - ! and also pft-labeled patch areas in the event that we are in nocomp mode - if ( hlm_use_nocomp .eq. itrue .and. cpatch%nocomp_pft_label .eq. ft) then - this%hvars(ih_nocomp_pftpatchfraction_si_pft)%r82d(io_si,ft) = & - this%hvars(ih_nocomp_pftpatchfraction_si_pft)%r82d(io_si,ft) + cpatch%area * AREA_INV + hio_fracarea_si(io_si) = hio_fracarea_si(io_si) & + + cpatch%area * AREA_INV - this%hvars(ih_nocomp_pftnpatches_si_pft)%r82d(io_si,ft) = & - this%hvars(ih_nocomp_pftnpatches_si_pft)%r82d(io_si,ft) + 1._r8 + ! ignore land use info on nocomp bareground (where landuse label = 0) + if (cpatch%land_use_label .gt. nocomp_bareground_land) then + hio_fracarea_si_landuse(io_si, cpatch%land_use_label) = & + hio_fracarea_si_landuse(io_si, cpatch%land_use_label) & + + cpatch%area * AREA_INV - this%hvars(ih_nocomp_pftburnedarea_si_pft)%r82d(io_si,ft) = & - this%hvars(ih_nocomp_pftburnedarea_si_pft)%r82d(io_si,ft) + & + hio_burnedarea_si_landuse(io_si, cpatch%land_use_label) = & + hio_burnedarea_si_landuse(io_si, cpatch%land_use_label) + & cpatch%frac_burnt * cpatch%area * AREA_INV / sec_per_day - endif - - end do - - ! loop through cohorts on patch - ccohort => cpatch%shortest - cohortloop: do while(associated(ccohort)) - - ft = ccohort%pft - - ! get indices for size class x pft and cohort age x pft - ! size class is the fastest changing dimension - call sizetype_class_index(ccohort%dbh, ccohort%pft, & - ccohort%size_class, ccohort%size_by_pft_class) - ! cohort age is the fastest changing dimension - call coagetype_class_index(ccohort%coage, ccohort%pft, & - ccohort%coage_class, ccohort%coage_by_pft_class) - - n_perm2 = ccohort%n * AREA_INV - - hio_canopy_fracarea_si(io_si) = hio_canopy_fracarea_si(io_si) + ccohort%c_area * AREA_INV - - ! calculate leaf height distribution, assuming leaf area is evenly distributed thru 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 - bintop = reallytalltrees - else - 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%height) - & - max(binbottom,ccohort%height-crown_depth)) / & - (crown_depth) - - hio_leaf_height_dist_si_height(io_si,i_heightbin) = & - hio_leaf_height_dist_si_height(io_si,i_heightbin) + & - ccohort%c_area * AREA_INV * ccohort%treelai * frac_canopy_in_bin - - ! if ( ( ccohort%c_area * AREA_INV * ccohort%treelai * frac_canopy_in_bin) .lt. 0._r8) then - ! write(fates_log(),*) ' negative hio_leaf_height_dist_si_height:' - ! write(fates_log(),*) ' c_area, treelai, frac_canopy_in_bin:', ccohort%c_area, ccohort%treelai, frac_canopy_in_bin - ! endif - end do - - if (ccohort%canopy_layer .eq. 1) then - ! calculate the area of canopy that is within each height bin - hio_canopy_height_dist_si_height(io_si,height_bin_max) = & - 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 - - call ccohort%prt%GetBiomass(element_list(el), & - sapw_m, struct_m, leaf_m, fnrt_m, store_m, repro_m, alive_m, total_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 - - call bstore_allom(ccohort%dbh,ccohort%pft,ccohort%crowndamage,ccohort%canopy_trim, store_max) - - ! 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 - - ! Update PFT partitioned biomass components - hio_leafbiomass_si_pft(io_si,ft) = hio_leafbiomass_si_pft(io_si,ft) + & - (ccohort%n * AREA_INV) * leaf_m - - hio_storebiomass_si_pft(io_si,ft) = hio_storebiomass_si_pft(io_si,ft) + & - (ccohort%n * AREA_INV) * store_m - - hio_nindivs_si_pft(io_si,ft) = hio_nindivs_si_pft(io_si,ft) + & - ccohort%n * AREA_INV - - if(ccohort%isnew) then - hio_recruitment_cflux_si_pft(io_si, ft) = hio_recruitment_cflux_si_pft(io_si, ft) + & - (ccohort%n * AREA_INV) * total_m * days_per_year - end if - - hio_biomass_si_pft(io_si, ft) = hio_biomass_si_pft(io_si, ft) + & - (ccohort%n * AREA_INV) * total_m - - ! biomass by land use type - hio_biomass_si_landuse(io_si, cpatch%land_use_label) = & - hio_biomass_si_landuse(io_si, cpatch%land_use_label) & - + total_m * ccohort%n * AREA_INV - - 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,stoich_growth_min) - - 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,stoich_growth_min) - - 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 - - ! Update PFT crown area - hio_crownarea_si_pft(io_si, ft) = hio_crownarea_si_pft(io_si, ft) + & - ccohort%c_area * AREA_INV - - if (ccohort%canopy_layer .eq. 1) then - ! Update PFT canopy crown area - hio_canopycrownarea_si_pft(io_si, ft) = hio_canopycrownarea_si_pft(io_si, ft) + & - ccohort%c_area * AREA_INV - end if - - ! Site by Size-Class x PFT (SCPF) - ! ------------------------------------------------------------------------ - - ! Flux Variables (cohorts must had experienced a day before any of these values - ! have any meaning, otherwise they are just inialization values - notnew: if( .not.(ccohort%isnew) ) then - - ! update pft-resolved NPP and GPP fluxes - hio_gpp_si_pft(io_si, ft) = hio_gpp_si_pft(io_si, ft) + & - ccohort%gpp_acc_hold * n_perm2 / (days_per_year* sec_per_day) - - 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%land_use_label .gt. nocomp_bareground_land) then - hio_npp_si_landuse(io_si,cpatch%land_use_label) = hio_npp_si_landuse(io_si,cpatch%land_use_label) & - + ccohort%npp_acc_hold * n_perm2 / (days_per_year*sec_per_day) - end if - - ! Turnover pools [kgC/day] * [day/yr] = [kgC/yr] - sapw_m_turnover = ccohort%prt%GetTurnover(sapw_organ, carbon12_element) * days_per_year - store_m_turnover = ccohort%prt%GetTurnover(store_organ, carbon12_element) * days_per_year - leaf_m_turnover = ccohort%prt%GetTurnover(leaf_organ, carbon12_element) * days_per_year - fnrt_m_turnover = ccohort%prt%GetTurnover(fnrt_organ, carbon12_element) * days_per_year - struct_m_turnover = ccohort%prt%GetTurnover(struct_organ, carbon12_element) * days_per_year - - ! Net change from allocation and transport [kgC/day] * [day/yr] = [kgC/yr] - sapw_m_net_alloc = ccohort%prt%GetNetAlloc(sapw_organ, carbon12_element) * days_per_year - store_m_net_alloc = ccohort%prt%GetNetAlloc(store_organ, carbon12_element) * days_per_year - leaf_m_net_alloc = ccohort%prt%GetNetAlloc(leaf_organ, carbon12_element) * days_per_year - fnrt_m_net_alloc = ccohort%prt%GetNetAlloc(fnrt_organ, carbon12_element) * days_per_year - struct_m_net_alloc = ccohort%prt%GetNetAlloc(struct_organ, carbon12_element) * days_per_year - repro_m_net_alloc = ccohort%prt%GetNetAlloc(repro_organ, carbon12_element) * days_per_year - - - - associate( scpf => ccohort%size_by_pft_class, & - scls => ccohort%size_class, & - cacls => ccohort%coage_class, & - capf => ccohort%coage_by_pft_class, & - cdam => ccohort%crowndamage) - - ! convert [kgC/plant/year] -> [kgC/m2/s] - hio_gpp_si_scpf(io_si,scpf) = hio_gpp_si_scpf(io_si,scpf) + & - n_perm2*ccohort%gpp_acc_hold / (days_per_year*sec_per_day) - - hio_npp_totl_si_scpf(io_si,scpf) = hio_npp_totl_si_scpf(io_si,scpf) + & - ccohort%npp_acc_hold * n_perm2 / (days_per_year*sec_per_day) - - hio_npp_leaf_si_scpf(io_si,scpf) = hio_npp_leaf_si_scpf(io_si,scpf) + & - leaf_m_net_alloc*n_perm2 / (days_per_year*sec_per_day) - - hio_npp_fnrt_si_scpf(io_si,scpf) = hio_npp_fnrt_si_scpf(io_si,scpf) + & - fnrt_m_net_alloc*n_perm2 / (days_per_year*sec_per_day) - - hio_npp_bgsw_si_scpf(io_si,scpf) = hio_npp_bgsw_si_scpf(io_si,scpf) + & - sapw_m_net_alloc*n_perm2*(1._r8-prt_params%allom_agb_frac(ccohort%pft)) / & - (days_per_year*sec_per_day) - - hio_npp_agsw_si_scpf(io_si,scpf) = hio_npp_agsw_si_scpf(io_si,scpf) + & - sapw_m_net_alloc*n_perm2*prt_params%allom_agb_frac(ccohort%pft) / & - (days_per_year*sec_per_day) - - hio_npp_bgdw_si_scpf(io_si,scpf) = hio_npp_bgdw_si_scpf(io_si,scpf) + & - struct_m_net_alloc*n_perm2*(1._r8-prt_params%allom_agb_frac(ccohort%pft)) / & - (days_per_year*sec_per_day) - - hio_npp_agdw_si_scpf(io_si,scpf) = hio_npp_agdw_si_scpf(io_si,scpf) + & - struct_m_net_alloc*n_perm2*prt_params%allom_agb_frac(ccohort%pft) / & - (days_per_year*sec_per_day) - - hio_npp_seed_si_scpf(io_si,scpf) = hio_npp_seed_si_scpf(io_si,scpf) + & - repro_m_net_alloc*n_perm2 / (days_per_year*sec_per_day) - - 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 ( 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*pi_const*((ccohort%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*pi_const*((ccohort%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 - - call bsap_allom(ccohort%dbh,ccohort%pft,ccohort%crowndamage,& - ccohort%canopy_trim, ccohort%efstem_coh, a_sapw, c_sapw) - - ! sapwood area [m2/m2] - hio_sapwood_area_scpf(io_si,scpf) = hio_sapwood_area_scpf(io_si,scpf)+ & - a_sapw*ccohort%n / m2_per_ha + end if - end if + ! some diagnostics on secondary forest area and its age distribution + if ( cpatch%land_use_label .eq. secondaryland ) then - ! mortality sums [#/m2] - hio_m1_si_scpf(io_si,scpf) = hio_m1_si_scpf(io_si,scpf) + & - ccohort%bmort*ccohort%n / m2_per_ha - hio_m2_si_scpf(io_si,scpf) = hio_m2_si_scpf(io_si,scpf) + & - ccohort%hmort*ccohort%n / m2_per_ha - hio_m3_si_scpf(io_si,scpf) = hio_m3_si_scpf(io_si,scpf) + & - ccohort%cmort*ccohort%n / m2_per_ha - - hio_m7_si_scpf(io_si,scpf) = hio_m7_si_scpf(io_si,scpf) + & - (ccohort%lmort_direct + ccohort%lmort_collateral + & - ccohort%lmort_infra) * ccohort%n / m2_per_ha - - hio_m8_si_scpf(io_si,scpf) = hio_m8_si_scpf(io_si,scpf) + & - ccohort%frmort*ccohort%n / m2_per_ha - hio_m9_si_scpf(io_si,scpf) = hio_m9_si_scpf(io_si,scpf) + & - ccohort%smort*ccohort%n / m2_per_ha - - if (hlm_use_cohort_age_tracking .eq.itrue) then - hio_m10_si_scpf(io_si,scpf) = hio_m10_si_scpf(io_si,scpf) + & - ccohort%asmort*ccohort%n / m2_per_ha - hio_m10_si_capf(io_si,capf) = hio_m10_si_capf(io_si,capf) + & - ccohort%asmort*ccohort%n / m2_per_ha - hio_m10_si_scls(io_si,scls) = hio_m10_si_scls(io_si,scls) + & - ccohort%asmort*ccohort%n / m2_per_ha - hio_m10_si_cacls(io_si,cacls) = hio_m10_si_cacls(io_si,cacls)+ & - ccohort%asmort*ccohort%n / m2_per_ha - end if + hio_agesince_anthrodist_si(io_si) = & + hio_agesince_anthrodist_si(io_si) & + + cpatch%area * AREA_INV + hio_secondarylands_fracarea_si(io_si) = & + hio_secondarylands_fracarea_si(io_si) & + + cpatch%area * AREA_INV + else if ( cpatch%land_use_label .eq. primaryland ) then + hio_primarylands_fracarea_si(io_si) = & + hio_primarylands_fracarea_si(io_si) & + + cpatch%area * AREA_INV - 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 - hio_m7_si_scls(io_si,scls) = hio_m7_si_scls(io_si,scls) + & - (ccohort%lmort_direct+ccohort%lmort_collateral+ccohort%lmort_infra) * ccohort%n / m2_per_ha - hio_m8_si_scls(io_si,scls) = hio_m8_si_scls(io_si,scls) + & - 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 + endif - !C13 discrimination - if(abs(gpp_cached_scpf(scpf)-hlm_hio_ignore_val)>nearzero .and. & - (gpp_cached_scpf(scpf) + ccohort%gpp_acc_hold) > 0.0_r8) then - - gpp_cached = gpp_cached_scpf(scpf)*days_per_year*sec_per_day - - hio_c13disc_si_scpf(io_si,scpf) = ((hio_c13disc_si_scpf(io_si,scpf) * gpp_cached) + & - (ccohort%c13disc_acc * ccohort%gpp_acc_hold)) / (gpp_cached + ccohort%gpp_acc_hold) - else - hio_c13disc_si_scpf(io_si,scpf) = 0.0_r8 - end if + do ft = 1,numpft + hio_scorch_height_si_pft(io_si,ft) = hio_scorch_height_si_pft(io_si,ft) + & + cpatch%Scorch_ht(ft) * cpatch%area * AREA_INV - ! number density [/m2] - hio_nplant_si_scpf(io_si,scpf) = hio_nplant_si_scpf(io_si,scpf) + ccohort%n / m2_per_ha + ! weight the value by patch area within any given age class - in the event that + ! there is more than one patch per age class - + ! and also pft-labeled patch areas in the event that we are in nocomp mode + if ( hlm_use_nocomp .eq. itrue .and. cpatch%nocomp_pft_label .eq. ft) then + this%hvars(ih_nocomp_pftpatchfraction_si_pft)%r82d(io_si,ft) = & + this%hvars(ih_nocomp_pftpatchfraction_si_pft)%r82d(io_si,ft) + cpatch%area * AREA_INV - ! number density along the cohort age dimension - if (hlm_use_cohort_age_tracking .eq.itrue) then - hio_nplant_si_capf(io_si,capf) = hio_nplant_si_capf(io_si,capf) + ccohort%n / m2_per_ha - hio_nplant_si_cacls(io_si,cacls) = hio_nplant_si_cacls(io_si,cacls)+ccohort%n / m2_per_ha - end if + this%hvars(ih_nocomp_pftnpatches_si_pft)%r82d(io_si,ft) = & + this%hvars(ih_nocomp_pftnpatches_si_pft)%r82d(io_si,ft) + 1._r8 - ! damage variables - cohort level - if(hlm_use_tree_damage .eq. itrue) then + this%hvars(ih_nocomp_pftburnedarea_si_pft)%r82d(io_si,ft) = & + this%hvars(ih_nocomp_pftburnedarea_si_pft)%r82d(io_si,ft) + & + cpatch%frac_burnt * cpatch%area * AREA_INV / sec_per_day + endif - icdpf = get_cdamagesizepft_class_index(ccohort%dbh, ccohort%crowndamage, ccohort%pft) + end do - this%hvars(ih_mortality_si_cdpf)%r82d(io_si,icdpf) = & - this%hvars(ih_mortality_si_cdpf)%r82d(io_si,icdpf) + & - ccohort%SumMortForHistory(per_year = .true.) * & - ccohort%n / m2_per_ha + ! loop through cohorts on patch + ccohort => cpatch%shortest + cohortloop: do while(associated(ccohort)) - ! crown damage by size by pft - this%hvars(ih_nplant_si_cdpf)%r82d(io_si, icdpf) = & - this%hvars(ih_nplant_si_cdpf)%r82d(io_si, icdpf) + ccohort%n / m2_per_ha - this%hvars(ih_m3_si_cdpf)%r82d(io_si, icdpf) = & - this%hvars(ih_m3_si_cdpf)%r82d(io_si, icdpf) + & - ccohort%cmort * ccohort%n / m2_per_ha + ft = ccohort%pft - ! 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,icdpf) = & - this%hvars(ih_m11_si_cdpf)%r82d(io_si,icdpf) + & - ccohort%dgmort*ccohort%n / m2_per_ha + ! get indices for size class x pft and cohort age x pft + ! size class is the fastest changing dimension + call sizetype_class_index(ccohort%dbh, ccohort%pft, & + ccohort%size_class, ccohort%size_by_pft_class) + ! cohort age is the fastest changing dimension + call coagetype_class_index(ccohort%coage, ccohort%pft, & + ccohort%coage_class, ccohort%coage_by_pft_class) + + n_perm2 = ccohort%n * AREA_INV + + hio_canopy_fracarea_si(io_si) = hio_canopy_fracarea_si(io_si) + ccohort%c_area * AREA_INV - this%hvars(ih_ddbh_si_cdpf)%r82d(io_si,icdpf) = & - this%hvars(ih_ddbh_si_cdpf)%r82d(io_si,icdpf) + & - ccohort%ddbhdt*ccohort%n / m2_per_ha * m_per_cm + ! calculate leaf height distribution, assuming leaf area is evenly distributed thru 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 + bintop = reallytalltrees + else + 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%height) - & + max(binbottom,ccohort%height-crown_depth)) / & + (crown_depth) + + hio_leaf_height_dist_si_height(io_si,i_heightbin) = & + hio_leaf_height_dist_si_height(io_si,i_heightbin) + & + ccohort%c_area * AREA_INV * ccohort%treelai * frac_canopy_in_bin + + ! if ( ( ccohort%c_area * AREA_INV * ccohort%treelai * frac_canopy_in_bin) .lt. 0._r8) then + ! write(fates_log(),*) ' negative hio_leaf_height_dist_si_height:' + ! write(fates_log(),*) ' c_area, treelai, frac_canopy_in_bin:', ccohort%c_area, ccohort%treelai, frac_canopy_in_bin + ! endif + end do + + if (ccohort%canopy_layer .eq. 1) then + ! calculate the area of canopy that is within each height bin + hio_canopy_height_dist_si_height(io_si,height_bin_max) = & + 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 + + call ccohort%prt%GetBiomass(element_list(el), & + sapw_m, struct_m, leaf_m, fnrt_m, store_m, repro_m, alive_m, total_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 + + call bstore_allom(ccohort%dbh,ccohort%pft,ccohort%crowndamage,ccohort%canopy_trim, store_max) + + ! 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 + + ! Update PFT partitioned biomass components + hio_leafbiomass_si_pft(io_si,ft) = hio_leafbiomass_si_pft(io_si,ft) + & + (ccohort%n * AREA_INV) * leaf_m + + hio_storebiomass_si_pft(io_si,ft) = hio_storebiomass_si_pft(io_si,ft) + & + (ccohort%n * AREA_INV) * store_m + + hio_nindivs_si_pft(io_si,ft) = hio_nindivs_si_pft(io_si,ft) + & + ccohort%n * AREA_INV + + if(ccohort%isnew) then + hio_recruitment_cflux_si_pft(io_si, ft) = hio_recruitment_cflux_si_pft(io_si, ft) + & + (ccohort%n * AREA_INV) * total_m * days_per_year + end if + + hio_biomass_si_pft(io_si, ft) = hio_biomass_si_pft(io_si, ft) + & + (ccohort%n * AREA_INV) * total_m + + ! biomass by land use type + hio_biomass_si_landuse(io_si, cpatch%land_use_label) = & + hio_biomass_si_landuse(io_si, cpatch%land_use_label) & + + total_m * ccohort%n * AREA_INV + + 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,stoich_growth_min) + + 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,stoich_growth_min) + + 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 + + ! Update PFT crown area + hio_crownarea_si_pft(io_si, ft) = hio_crownarea_si_pft(io_si, ft) + & + ccohort%c_area * AREA_INV + + if (ccohort%canopy_layer .eq. 1) then + ! Update PFT canopy crown area + hio_canopycrownarea_si_pft(io_si, ft) = hio_canopycrownarea_si_pft(io_si, ft) + & + ccohort%c_area * AREA_INV end if - ! Carbon only metrics - call ccohort%prt%GetBiomass(carbon12_element, & - sapw_m, struct_m, leaf_m, fnrt_m, store_m, repro_m, alive_m, total_m) - - hio_mortality_carbonflux_si_pft(io_si,ccohort%pft) = hio_mortality_carbonflux_si_pft(io_si,ccohort%pft) + & - ccohort%SumMortForHistory(per_year = .false.) * 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 - - hio_cstarvmortality_continuous_carbonflux_si_pft(io_si,ccohort%pft) = & - hio_cstarvmortality_continuous_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 - - hio_agb_si_scpf(io_si,scpf) = hio_agb_si_scpf(io_si,scpf) + & - total_m * ccohort%n * prt_params%allom_agb_frac(ccohort%pft) * AREA_INV - - hio_biomass_si_scls(io_si,scls) = hio_biomass_si_scls(io_si,scls) + & - total_m * ccohort%n * AREA_INV - - ! update size-class quantities - - hio_nplant_si_scls(io_si,scls) = hio_nplant_si_scls(io_si,scls) + ccohort%n / m2_per_ha - - ! update SCPF/SCLS- and canopy/subcanopy- partitioned quantities - canlayer: if (ccohort%canopy_layer .eq. 1) then - 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_crownarea_canopy_si_scpf(io_si,scpf) = hio_crownarea_canopy_si_scpf(io_si,scpf) + & - ccohort%c_area * AREA_INV - !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 - - hio_mortality_canopy_si_scpf(io_si,scpf) = hio_mortality_canopy_si_scpf(io_si,scpf)+ & - ccohort%SumMortForHistory(per_year = .true.) * ccohort%n / 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) + & - ccohort%treelai*ccohort%c_area * AREA_INV - hio_sai_canopy_si_scls(io_si,scls) = hio_sai_canopy_si_scls(io_si,scls) + & - ccohort%treesai*ccohort%c_area * AREA_INV - hio_trimming_canopy_si_scls(io_si,scls) = hio_trimming_canopy_si_scls(io_si,scls) + & - ccohort%n * ccohort%canopy_trim / m2_per_ha - hio_crown_fracarea_canopy_si_scls(io_si,scls) = hio_crown_fracarea_canopy_si_scls(io_si,scls) + & - ccohort%c_area * AREA_INV - hio_gpp_canopy_si_scpf(io_si,scpf) = hio_gpp_canopy_si_scpf(io_si,scpf) + & - n_perm2*ccohort%gpp_acc_hold / days_per_year / sec_per_day - hio_ar_canopy_si_scpf(io_si,scpf) = hio_ar_canopy_si_scpf(io_si,scpf) + & - n_perm2*(ccohort%resp_m_acc_hold + ccohort%resp_g_acc_hold + & - ccohort%resp_excess_hold) / days_per_year / sec_per_day - ! growth increment - hio_ddbh_canopy_si_scpf(io_si,scpf) = hio_ddbh_canopy_si_scpf(io_si,scpf) + & - ccohort%ddbhdt*ccohort%n * m_per_cm / m2_per_ha - hio_ddbh_canopy_si_scls(io_si,scls) = hio_ddbh_canopy_si_scls(io_si,scls) + & - ccohort%ddbhdt*ccohort%n * m_per_cm / m2_per_ha - - ! sum of all mortality - hio_mortality_canopy_si_scls(io_si,scls) = hio_mortality_canopy_si_scls(io_si,scls) + & - ccohort%SumMortForHistory(per_year = .true.) * ccohort%n / 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_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 - - ! 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,icdpf) = & - this%hvars(ih_m3_mortality_canopy_si_cdpf)%r82d(io_si,icdpf)+& - 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,icdpf) = & - this%hvars(ih_m11_mortality_canopy_si_cdpf)%r82d(io_si,icdpf)+& - ccohort%dgmort * ccohort%n / m2_per_ha + ! Site by Size-Class x PFT (SCPF) + ! ------------------------------------------------------------------------ - this%hvars(ih_mortality_canopy_si_cdpf)%r82d(io_si,icdpf) = & - this%hvars(ih_mortality_canopy_si_cdpf)%r82d(io_si,icdpf)+ & - ccohort%SumMortForHistory(per_year = .true.) * ccohort%n / m2_per_ha - - ! nplants by damage - this%hvars(ih_nplant_canopy_si_cdpf)%r82d(io_si,icdpf) = & - this%hvars(ih_nplant_canopy_si_cdpf)%r82d(io_si,icdpf) + & - 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,icdpf) = & - this%hvars(ih_ddbh_canopy_si_cdpf)%r82d(io_si,icdpf) + & - 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) + & - fnrt_m_turnover * ccohort%n / m2_per_ha / days_per_year / sec_per_day - hio_bsw_md_canopy_si_scls(io_si,scls) = hio_bsw_md_canopy_si_scls(io_si,scls) + & - sapw_m_turnover * ccohort%n / m2_per_ha / days_per_year / sec_per_day - hio_bstore_md_canopy_si_scls(io_si,scls) = hio_bstore_md_canopy_si_scls(io_si,scls) + & - store_m_turnover * ccohort%n / m2_per_ha / days_per_year / sec_per_day - hio_bdead_md_canopy_si_scls(io_si,scls) = hio_bdead_md_canopy_si_scls(io_si,scls) + & - struct_m_turnover * ccohort%n / m2_per_ha / days_per_year / sec_per_day - hio_seed_prod_canopy_si_scls(io_si,scls) = hio_seed_prod_canopy_si_scls(io_si,scls) + & - ccohort%seed_prod * ccohort%n / m2_per_ha / sec_per_day - - hio_npp_leaf_canopy_si_scls(io_si,scls) = hio_npp_leaf_canopy_si_scls(io_si,scls) + & - leaf_m_net_alloc * ccohort%n / m2_per_ha / days_per_year / sec_per_day - hio_npp_fnrt_canopy_si_scls(io_si,scls) = hio_npp_fnrt_canopy_si_scls(io_si,scls) + & - fnrt_m_net_alloc * ccohort%n / m2_per_ha / days_per_year / sec_per_day - hio_npp_sapw_canopy_si_scls(io_si,scls) = hio_npp_sapw_canopy_si_scls(io_si,scls) + & - sapw_m_net_alloc * ccohort%n / m2_per_ha / days_per_year / sec_per_day - hio_npp_dead_canopy_si_scls(io_si,scls) = hio_npp_dead_canopy_si_scls(io_si,scls) + & - struct_m_net_alloc * ccohort%n / m2_per_ha / days_per_year / sec_per_day - hio_npp_seed_canopy_si_scls(io_si,scls) = hio_npp_seed_canopy_si_scls(io_si,scls) + & - repro_m_net_alloc * ccohort%n / m2_per_ha / days_per_year / sec_per_day - hio_npp_stor_canopy_si_scls(io_si,scls) = hio_npp_stor_canopy_si_scls(io_si,scls) + & - store_m_net_alloc * ccohort%n / m2_per_ha / days_per_year / sec_per_day - - 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 - - - else canlayer - hio_bstor_understory_si_scpf(io_si,scpf) = hio_bstor_understory_si_scpf(io_si,scpf) + & - store_m * ccohort%n / m2_per_ha - hio_bleaf_understory_si_scpf(io_si,scpf) = hio_bleaf_understory_si_scpf(io_si,scpf) + & - leaf_m * ccohort%n / m2_per_ha - - hio_lai_understory_si_scpf(io_si,scpf) = hio_lai_understory_si_scpf(io_si,scpf) + & - ccohort%treelai*ccohort%c_area * AREA_INV - hio_crownarea_understory_si_scpf(io_si,scpf) = hio_crownarea_understory_si_scpf(io_si,scpf) + & - 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 + - ! ccohort%frmort + ccohort%smort + ccohort%asmort) * ccohort%n - - hio_mortality_understory_si_scpf(io_si,scpf) = hio_mortality_understory_si_scpf(io_si,scpf)+ & - ccohort%SumMortForHistory(per_year = .true.) * ccohort%n / 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%land_use_label .eq. secondaryland) then - hio_mortality_canopy_secondary_si_scls(io_si,scls) = hio_mortality_canopy_secondary_si_scls(io_si,scls) + & - (ccohort%bmort + ccohort%hmort + ccohort%cmort + & - ccohort%frmort + ccohort%smort + ccohort%asmort) * ccohort%n / m2_per_ha + & - (ccohort%lmort_direct + ccohort%lmort_collateral + ccohort%lmort_infra) * & - ccohort%n * sec_per_day * days_per_year / m2_per_ha + ! Flux Variables (cohorts must had experienced a day before any of these values + ! have any meaning, otherwise they are just inialization values + notnew: if( .not.(ccohort%isnew) ) then + + ! update pft-resolved NPP and GPP fluxes + hio_gpp_si_pft(io_si, ft) = hio_gpp_si_pft(io_si, ft) + & + ccohort%gpp_acc_hold * n_perm2 / (days_per_year* sec_per_day) + + 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%land_use_label .gt. nocomp_bareground_land) then + hio_npp_si_landuse(io_si,cpatch%land_use_label) = hio_npp_si_landuse(io_si,cpatch%land_use_label) & + + ccohort%npp_acc_hold * n_perm2 / (days_per_year*sec_per_day) 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) + & - ccohort%treelai*ccohort%c_area * AREA_INV - hio_sai_understory_si_scls(io_si,scls) = hio_sai_understory_si_scls(io_si,scls) + & - ccohort%treelai*ccohort%c_area * AREA_INV - hio_trimming_understory_si_scls(io_si,scls) = hio_trimming_understory_si_scls(io_si,scls) + & - ccohort%n * ccohort%canopy_trim / m2_per_ha - hio_crown_fracarea_understory_si_scls(io_si,scls) = hio_crown_fracarea_understory_si_scls(io_si,scls) + & - ccohort%c_area * AREA_INV - hio_gpp_understory_si_scpf(io_si,scpf) = hio_gpp_understory_si_scpf(io_si,scpf) + & - n_perm2*ccohort%gpp_acc_hold / days_per_year / sec_per_day - hio_ar_understory_si_scpf(io_si,scpf) = hio_ar_understory_si_scpf(io_si,scpf) + & - n_perm2*(ccohort%resp_m_acc_hold + ccohort%resp_g_acc_hold + & - ccohort%resp_excess_hold) / days_per_year / sec_per_day - - ! growth increment - hio_ddbh_understory_si_scpf(io_si,scpf) = hio_ddbh_understory_si_scpf(io_si,scpf) + & - ccohort%ddbhdt*ccohort%n * m_per_cm / m2_per_ha - hio_ddbh_understory_si_scls(io_si,scls) = hio_ddbh_understory_si_scls(io_si,scls) + & - ccohort%ddbhdt*ccohort%n * m_per_cm / m2_per_ha - - ! sum of all mortality - hio_mortality_understory_si_scls(io_si,scls) = hio_mortality_understory_si_scls(io_si,scls) + & - ccohort%SumMortForHistory(per_year = .true.) * ccohort%n / 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_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 - - ! 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,icdpf) = & - this%hvars(ih_m3_mortality_understory_si_cdpf)%r82d(io_si,icdpf) + & - 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,icdpf) = & - this%hvars(ih_m11_mortality_understory_si_cdpf)%r82d(io_si,icdpf) + & - 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,icdpf) = & - this%hvars(ih_mortality_understory_si_cdpf)%r82d(io_si,icdpf) + & - ccohort%SumMortForHistory(per_year = .true.) * ccohort%n / m2_per_ha - - this%hvars(ih_nplant_understory_si_cdpf)%r82d(io_si,icdpf) = & - this%hvars(ih_nplant_understory_si_cdpf)%r82d(io_si,icdpf) + & - ccohort%n / m2_per_ha - - ! growth rate by size x damage x pft - understory - this%hvars(ih_ddbh_understory_si_cdpf)%r82d(io_si,icdpf) = & - this%hvars(ih_ddbh_understory_si_cdpf)%r82d(io_si,icdpf) + & - 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 - hio_root_md_understory_si_scls(io_si,scls) = hio_root_md_understory_si_scls(io_si,scls) + & - fnrt_m_turnover * ccohort%n / m2_per_ha / days_per_year / sec_per_day - hio_bsw_md_understory_si_scls(io_si,scls) = hio_bsw_md_understory_si_scls(io_si,scls) + & - sapw_m_turnover * ccohort%n / m2_per_ha / days_per_year / sec_per_day - hio_bstore_md_understory_si_scls(io_si,scls) = hio_bstore_md_understory_si_scls(io_si,scls) + & - store_m_turnover * ccohort%n / m2_per_ha / days_per_year / sec_per_day - hio_bdead_md_understory_si_scls(io_si,scls) = hio_bdead_md_understory_si_scls(io_si,scls) + & - struct_m_turnover * ccohort%n / m2_per_ha / days_per_year / sec_per_day - hio_seed_prod_understory_si_scls(io_si,scls) = hio_seed_prod_understory_si_scls(io_si,scls) + & - ccohort%seed_prod * ccohort%n / m2_per_ha / sec_per_day - - hio_npp_leaf_understory_si_scls(io_si,scls) = hio_npp_leaf_understory_si_scls(io_si,scls) + & - leaf_m_net_alloc * ccohort%n / m2_per_ha / days_per_year / sec_per_day - hio_npp_fnrt_understory_si_scls(io_si,scls) = hio_npp_fnrt_understory_si_scls(io_si,scls) + & - fnrt_m_net_alloc * ccohort%n / m2_per_ha / days_per_year / sec_per_day - hio_npp_sapw_understory_si_scls(io_si,scls) = hio_npp_sapw_understory_si_scls(io_si,scls) + & - sapw_m_net_alloc * ccohort%n / m2_per_ha / days_per_year / sec_per_day - hio_npp_dead_understory_si_scls(io_si,scls) = hio_npp_dead_understory_si_scls(io_si,scls) + & - struct_m_net_alloc * ccohort%n / m2_per_ha / days_per_year / sec_per_day - hio_npp_seed_understory_si_scls(io_si,scls) = hio_npp_seed_understory_si_scls(io_si,scls) + & - repro_m_net_alloc * ccohort%n / m2_per_ha / days_per_year / sec_per_day - hio_npp_stor_understory_si_scls(io_si,scls) = hio_npp_stor_understory_si_scls(io_si,scls) + & - store_m_net_alloc * ccohort%n / m2_per_ha / days_per_year / sec_per_day - - hio_yesterdaycanopylevel_understory_si_scls(io_si,scls) = & - hio_yesterdaycanopylevel_understory_si_scls(io_si,scls) + & - ccohort%canopy_layer_yesterday * ccohort%n / m2_per_ha - endif canlayer + ! Turnover pools [kgC/day] * [day/yr] = [kgC/yr] + sapw_m_turnover = ccohort%prt%GetTurnover(sapw_organ, carbon12_element) * days_per_year + store_m_turnover = ccohort%prt%GetTurnover(store_organ, carbon12_element) * days_per_year + leaf_m_turnover = ccohort%prt%GetTurnover(leaf_organ, carbon12_element) * days_per_year + fnrt_m_turnover = ccohort%prt%GetTurnover(fnrt_organ, carbon12_element) * days_per_year + struct_m_turnover = ccohort%prt%GetTurnover(struct_organ, carbon12_element) * days_per_year + + ! Net change from allocation and transport [kgC/day] * [day/yr] = [kgC/yr] + sapw_m_net_alloc = ccohort%prt%GetNetAlloc(sapw_organ, carbon12_element) * days_per_year + store_m_net_alloc = ccohort%prt%GetNetAlloc(store_organ, carbon12_element) * days_per_year + leaf_m_net_alloc = ccohort%prt%GetNetAlloc(leaf_organ, carbon12_element) * days_per_year + fnrt_m_net_alloc = ccohort%prt%GetNetAlloc(fnrt_organ, carbon12_element) * days_per_year + struct_m_net_alloc = ccohort%prt%GetNetAlloc(struct_organ, carbon12_element) * days_per_year + repro_m_net_alloc = ccohort%prt%GetNetAlloc(repro_organ, carbon12_element) * days_per_year + + + + associate( scpf => ccohort%size_by_pft_class, & + scls => ccohort%size_class, & + cacls => ccohort%coage_class, & + capf => ccohort%coage_by_pft_class, & + cdam => ccohort%crowndamage) + + ! convert [kgC/plant/year] -> [kgC/m2/s] + hio_gpp_si_scpf(io_si,scpf) = hio_gpp_si_scpf(io_si,scpf) + & + n_perm2*ccohort%gpp_acc_hold / (days_per_year*sec_per_day) + + hio_npp_totl_si_scpf(io_si,scpf) = hio_npp_totl_si_scpf(io_si,scpf) + & + ccohort%npp_acc_hold * n_perm2 / (days_per_year*sec_per_day) + + hio_npp_leaf_si_scpf(io_si,scpf) = hio_npp_leaf_si_scpf(io_si,scpf) + & + leaf_m_net_alloc*n_perm2 / (days_per_year*sec_per_day) + + hio_npp_fnrt_si_scpf(io_si,scpf) = hio_npp_fnrt_si_scpf(io_si,scpf) + & + fnrt_m_net_alloc*n_perm2 / (days_per_year*sec_per_day) + + hio_npp_bgsw_si_scpf(io_si,scpf) = hio_npp_bgsw_si_scpf(io_si,scpf) + & + sapw_m_net_alloc*n_perm2*(1._r8-prt_params%allom_agb_frac(ccohort%pft)) / & + (days_per_year*sec_per_day) + + hio_npp_agsw_si_scpf(io_si,scpf) = hio_npp_agsw_si_scpf(io_si,scpf) + & + sapw_m_net_alloc*n_perm2*prt_params%allom_agb_frac(ccohort%pft) / & + (days_per_year*sec_per_day) + + hio_npp_bgdw_si_scpf(io_si,scpf) = hio_npp_bgdw_si_scpf(io_si,scpf) + & + struct_m_net_alloc*n_perm2*(1._r8-prt_params%allom_agb_frac(ccohort%pft)) / & + (days_per_year*sec_per_day) + + hio_npp_agdw_si_scpf(io_si,scpf) = hio_npp_agdw_si_scpf(io_si,scpf) + & + struct_m_net_alloc*n_perm2*prt_params%allom_agb_frac(ccohort%pft) / & + (days_per_year*sec_per_day) + + hio_npp_seed_si_scpf(io_si,scpf) = hio_npp_seed_si_scpf(io_si,scpf) + & + repro_m_net_alloc*n_perm2 / (days_per_year*sec_per_day) + + 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 ( 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*pi_const*((ccohort%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*pi_const*((ccohort%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 + + call bsap_allom(ccohort%dbh,ccohort%pft,ccohort%crowndamage,& + ccohort%canopy_trim, ccohort%efstem_coh, a_sapw, c_sapw) + + ! sapwood area [m2/m2] + hio_sapwood_area_scpf(io_si,scpf) = hio_sapwood_area_scpf(io_si,scpf)+ & + a_sapw*ccohort%n / m2_per_ha + + end if + + ! mortality sums [#/m2] + hio_m1_si_scpf(io_si,scpf) = hio_m1_si_scpf(io_si,scpf) + & + ccohort%bmort*ccohort%n / m2_per_ha + hio_m2_si_scpf(io_si,scpf) = hio_m2_si_scpf(io_si,scpf) + & + ccohort%hmort*ccohort%n / m2_per_ha + hio_m3_si_scpf(io_si,scpf) = hio_m3_si_scpf(io_si,scpf) + & + ccohort%cmort*ccohort%n / m2_per_ha + + hio_m7_si_scpf(io_si,scpf) = hio_m7_si_scpf(io_si,scpf) + & + (ccohort%lmort_direct + ccohort%lmort_collateral + & + ccohort%lmort_infra) * ccohort%n / m2_per_ha + + hio_m8_si_scpf(io_si,scpf) = hio_m8_si_scpf(io_si,scpf) + & + ccohort%frmort*ccohort%n / m2_per_ha + hio_m9_si_scpf(io_si,scpf) = hio_m9_si_scpf(io_si,scpf) + & + ccohort%smort*ccohort%n / m2_per_ha + + if (hlm_use_cohort_age_tracking .eq.itrue) then + hio_m10_si_scpf(io_si,scpf) = hio_m10_si_scpf(io_si,scpf) + & + ccohort%asmort*ccohort%n / m2_per_ha + hio_m10_si_capf(io_si,capf) = hio_m10_si_capf(io_si,capf) + & + ccohort%asmort*ccohort%n / m2_per_ha + hio_m10_si_scls(io_si,scls) = hio_m10_si_scls(io_si,scls) + & + ccohort%asmort*ccohort%n / m2_per_ha + hio_m10_si_cacls(io_si,cacls) = hio_m10_si_cacls(io_si,cacls)+ & + 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 + hio_m7_si_scls(io_si,scls) = hio_m7_si_scls(io_si,scls) + & + (ccohort%lmort_direct+ccohort%lmort_collateral+ccohort%lmort_infra) * ccohort%n / m2_per_ha + hio_m8_si_scls(io_si,scls) = hio_m8_si_scls(io_si,scls) + & + 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 + + !C13 discrimination + if(abs(gpp_cached_scpf(scpf)-hlm_hio_ignore_val)>nearzero .and. & + (gpp_cached_scpf(scpf) + ccohort%gpp_acc_hold) > 0.0_r8) then + + gpp_cached = gpp_cached_scpf(scpf)*days_per_year*sec_per_day + + hio_c13disc_si_scpf(io_si,scpf) = ((hio_c13disc_si_scpf(io_si,scpf) * gpp_cached) + & + (ccohort%c13disc_acc * ccohort%gpp_acc_hold)) / (gpp_cached + ccohort%gpp_acc_hold) + else + hio_c13disc_si_scpf(io_si,scpf) = 0.0_r8 + end if + + ! number density [/m2] + hio_nplant_si_scpf(io_si,scpf) = hio_nplant_si_scpf(io_si,scpf) + ccohort%n / m2_per_ha + + ! number density along the cohort age dimension + if (hlm_use_cohort_age_tracking .eq.itrue) then + hio_nplant_si_capf(io_si,capf) = hio_nplant_si_capf(io_si,capf) + ccohort%n / m2_per_ha + 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 + + icdpf = get_cdamagesizepft_class_index(ccohort%dbh, ccohort%crowndamage, ccohort%pft) + + this%hvars(ih_mortality_si_cdpf)%r82d(io_si,icdpf) = & + this%hvars(ih_mortality_si_cdpf)%r82d(io_si,icdpf) + & + ccohort%SumMortForHistory(per_year = .true.) * & + ccohort%n / m2_per_ha + + ! crown damage by size by pft + this%hvars(ih_nplant_si_cdpf)%r82d(io_si, icdpf) = & + this%hvars(ih_nplant_si_cdpf)%r82d(io_si, icdpf) + ccohort%n / m2_per_ha + this%hvars(ih_m3_si_cdpf)%r82d(io_si, icdpf) = & + this%hvars(ih_m3_si_cdpf)%r82d(io_si, icdpf) + & + 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,icdpf) = & + this%hvars(ih_m11_si_cdpf)%r82d(io_si,icdpf) + & + ccohort%dgmort*ccohort%n / m2_per_ha + + this%hvars(ih_ddbh_si_cdpf)%r82d(io_si,icdpf) = & + this%hvars(ih_ddbh_si_cdpf)%r82d(io_si,icdpf) + & + ccohort%ddbhdt*ccohort%n / m2_per_ha * m_per_cm + + end if + + ! Carbon only metrics + call ccohort%prt%GetBiomass(carbon12_element, & + sapw_m, struct_m, leaf_m, fnrt_m, store_m, repro_m, alive_m, total_m) + + hio_mortality_carbonflux_si_pft(io_si,ccohort%pft) = hio_mortality_carbonflux_si_pft(io_si,ccohort%pft) + & + ccohort%SumMortForHistory(per_year = .false.) * 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 + + hio_cstarvmortality_continuous_carbonflux_si_pft(io_si,ccohort%pft) = & + hio_cstarvmortality_continuous_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 + + hio_agb_si_scpf(io_si,scpf) = hio_agb_si_scpf(io_si,scpf) + & + total_m * ccohort%n * prt_params%allom_agb_frac(ccohort%pft) * AREA_INV + + hio_biomass_si_scls(io_si,scls) = hio_biomass_si_scls(io_si,scls) + & + total_m * ccohort%n * AREA_INV + + ! update size-class quantities + + hio_nplant_si_scls(io_si,scls) = hio_nplant_si_scls(io_si,scls) + ccohort%n / m2_per_ha + + ! update SCPF/SCLS- and canopy/subcanopy- partitioned quantities + canlayer: if (ccohort%canopy_layer .eq. 1) then + 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_crownarea_canopy_si_scpf(io_si,scpf) = hio_crownarea_canopy_si_scpf(io_si,scpf) + & + ccohort%c_area * AREA_INV + !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 + + hio_mortality_canopy_si_scpf(io_si,scpf) = hio_mortality_canopy_si_scpf(io_si,scpf)+ & + ccohort%SumMortForHistory(per_year = .true.) * ccohort%n / 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) + & + ccohort%treelai*ccohort%c_area * AREA_INV + hio_sai_canopy_si_scls(io_si,scls) = hio_sai_canopy_si_scls(io_si,scls) + & + ccohort%treesai*ccohort%c_area * AREA_INV + hio_trimming_canopy_si_scls(io_si,scls) = hio_trimming_canopy_si_scls(io_si,scls) + & + ccohort%n * ccohort%canopy_trim / m2_per_ha + hio_crown_fracarea_canopy_si_scls(io_si,scls) = hio_crown_fracarea_canopy_si_scls(io_si,scls) + & + ccohort%c_area * AREA_INV + hio_gpp_canopy_si_scpf(io_si,scpf) = hio_gpp_canopy_si_scpf(io_si,scpf) + & + n_perm2*ccohort%gpp_acc_hold / days_per_year / sec_per_day + hio_ar_canopy_si_scpf(io_si,scpf) = hio_ar_canopy_si_scpf(io_si,scpf) + & + n_perm2*(ccohort%resp_m_acc_hold + ccohort%resp_g_acc_hold + & + ccohort%resp_excess_hold) / days_per_year / sec_per_day + ! growth increment + hio_ddbh_canopy_si_scpf(io_si,scpf) = hio_ddbh_canopy_si_scpf(io_si,scpf) + & + ccohort%ddbhdt*ccohort%n * m_per_cm / m2_per_ha + hio_ddbh_canopy_si_scls(io_si,scls) = hio_ddbh_canopy_si_scls(io_si,scls) + & + ccohort%ddbhdt*ccohort%n * m_per_cm / m2_per_ha + + ! sum of all mortality + hio_mortality_canopy_si_scls(io_si,scls) = hio_mortality_canopy_si_scls(io_si,scls) + & + ccohort%SumMortForHistory(per_year = .true.) * ccohort%n / 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_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 + + ! 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,icdpf) = & + this%hvars(ih_m3_mortality_canopy_si_cdpf)%r82d(io_si,icdpf)+& + 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,icdpf) = & + this%hvars(ih_m11_mortality_canopy_si_cdpf)%r82d(io_si,icdpf)+& + ccohort%dgmort * ccohort%n / 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)+ & + ccohort%SumMortForHistory(per_year = .true.) * ccohort%n / m2_per_ha + + ! nplants by damage + this%hvars(ih_nplant_canopy_si_cdpf)%r82d(io_si,icdpf) = & + this%hvars(ih_nplant_canopy_si_cdpf)%r82d(io_si,icdpf) + & + 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,icdpf) = & + this%hvars(ih_ddbh_canopy_si_cdpf)%r82d(io_si,icdpf) + & + 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) + & + fnrt_m_turnover * ccohort%n / m2_per_ha / days_per_year / sec_per_day + hio_bsw_md_canopy_si_scls(io_si,scls) = hio_bsw_md_canopy_si_scls(io_si,scls) + & + sapw_m_turnover * ccohort%n / m2_per_ha / days_per_year / sec_per_day + hio_bstore_md_canopy_si_scls(io_si,scls) = hio_bstore_md_canopy_si_scls(io_si,scls) + & + store_m_turnover * ccohort%n / m2_per_ha / days_per_year / sec_per_day + hio_bdead_md_canopy_si_scls(io_si,scls) = hio_bdead_md_canopy_si_scls(io_si,scls) + & + struct_m_turnover * ccohort%n / m2_per_ha / days_per_year / sec_per_day + hio_seed_prod_canopy_si_scls(io_si,scls) = hio_seed_prod_canopy_si_scls(io_si,scls) + & + ccohort%seed_prod * ccohort%n / m2_per_ha / sec_per_day + + hio_npp_leaf_canopy_si_scls(io_si,scls) = hio_npp_leaf_canopy_si_scls(io_si,scls) + & + leaf_m_net_alloc * ccohort%n / m2_per_ha / days_per_year / sec_per_day + hio_npp_fnrt_canopy_si_scls(io_si,scls) = hio_npp_fnrt_canopy_si_scls(io_si,scls) + & + fnrt_m_net_alloc * ccohort%n / m2_per_ha / days_per_year / sec_per_day + hio_npp_sapw_canopy_si_scls(io_si,scls) = hio_npp_sapw_canopy_si_scls(io_si,scls) + & + sapw_m_net_alloc * ccohort%n / m2_per_ha / days_per_year / sec_per_day + hio_npp_dead_canopy_si_scls(io_si,scls) = hio_npp_dead_canopy_si_scls(io_si,scls) + & + struct_m_net_alloc * ccohort%n / m2_per_ha / days_per_year / sec_per_day + hio_npp_seed_canopy_si_scls(io_si,scls) = hio_npp_seed_canopy_si_scls(io_si,scls) + & + repro_m_net_alloc * ccohort%n / m2_per_ha / days_per_year / sec_per_day + hio_npp_stor_canopy_si_scls(io_si,scls) = hio_npp_stor_canopy_si_scls(io_si,scls) + & + store_m_net_alloc * ccohort%n / m2_per_ha / days_per_year / sec_per_day + + 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 + + + else canlayer + hio_bstor_understory_si_scpf(io_si,scpf) = hio_bstor_understory_si_scpf(io_si,scpf) + & + store_m * ccohort%n / m2_per_ha + hio_bleaf_understory_si_scpf(io_si,scpf) = hio_bleaf_understory_si_scpf(io_si,scpf) + & + leaf_m * ccohort%n / m2_per_ha + + hio_lai_understory_si_scpf(io_si,scpf) = hio_lai_understory_si_scpf(io_si,scpf) + & + ccohort%treelai*ccohort%c_area * AREA_INV + hio_crownarea_understory_si_scpf(io_si,scpf) = hio_crownarea_understory_si_scpf(io_si,scpf) + & + 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 + + ! ccohort%frmort + ccohort%smort + ccohort%asmort) * ccohort%n + + hio_mortality_understory_si_scpf(io_si,scpf) = hio_mortality_understory_si_scpf(io_si,scpf)+ & + ccohort%SumMortForHistory(per_year = .true.) * ccohort%n / 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%land_use_label .eq. secondaryland) then + hio_mortality_canopy_secondary_si_scls(io_si,scls) = hio_mortality_canopy_secondary_si_scls(io_si,scls) + & + (ccohort%bmort + ccohort%hmort + ccohort%cmort + & + ccohort%frmort + ccohort%smort + ccohort%asmort) * ccohort%n / m2_per_ha + & + (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) + & + ccohort%treelai*ccohort%c_area * AREA_INV + hio_sai_understory_si_scls(io_si,scls) = hio_sai_understory_si_scls(io_si,scls) + & + ccohort%treelai*ccohort%c_area * AREA_INV + hio_trimming_understory_si_scls(io_si,scls) = hio_trimming_understory_si_scls(io_si,scls) + & + ccohort%n * ccohort%canopy_trim / m2_per_ha + hio_crown_fracarea_understory_si_scls(io_si,scls) = hio_crown_fracarea_understory_si_scls(io_si,scls) + & + ccohort%c_area * AREA_INV + hio_gpp_understory_si_scpf(io_si,scpf) = hio_gpp_understory_si_scpf(io_si,scpf) + & + n_perm2*ccohort%gpp_acc_hold / days_per_year / sec_per_day + hio_ar_understory_si_scpf(io_si,scpf) = hio_ar_understory_si_scpf(io_si,scpf) + & + n_perm2*(ccohort%resp_m_acc_hold + ccohort%resp_g_acc_hold + & + ccohort%resp_excess_hold) / days_per_year / sec_per_day + + ! growth increment + hio_ddbh_understory_si_scpf(io_si,scpf) = hio_ddbh_understory_si_scpf(io_si,scpf) + & + ccohort%ddbhdt*ccohort%n * m_per_cm / m2_per_ha + hio_ddbh_understory_si_scls(io_si,scls) = hio_ddbh_understory_si_scls(io_si,scls) + & + ccohort%ddbhdt*ccohort%n * m_per_cm / m2_per_ha + + ! sum of all mortality + hio_mortality_understory_si_scls(io_si,scls) = hio_mortality_understory_si_scls(io_si,scls) + & + ccohort%SumMortForHistory(per_year = .true.) * ccohort%n / 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_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 + + ! 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,icdpf) = & + this%hvars(ih_m3_mortality_understory_si_cdpf)%r82d(io_si,icdpf) + & + 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,icdpf) = & + this%hvars(ih_m11_mortality_understory_si_cdpf)%r82d(io_si,icdpf) + & + 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,icdpf) = & + this%hvars(ih_mortality_understory_si_cdpf)%r82d(io_si,icdpf) + & + ccohort%SumMortForHistory(per_year = .true.) * ccohort%n / m2_per_ha + + this%hvars(ih_nplant_understory_si_cdpf)%r82d(io_si,icdpf) = & + this%hvars(ih_nplant_understory_si_cdpf)%r82d(io_si,icdpf) + & + ccohort%n / m2_per_ha + + ! growth rate by size x damage x pft - understory + this%hvars(ih_ddbh_understory_si_cdpf)%r82d(io_si,icdpf) = & + this%hvars(ih_ddbh_understory_si_cdpf)%r82d(io_si,icdpf) + & + 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 + hio_root_md_understory_si_scls(io_si,scls) = hio_root_md_understory_si_scls(io_si,scls) + & + fnrt_m_turnover * ccohort%n / m2_per_ha / days_per_year / sec_per_day + hio_bsw_md_understory_si_scls(io_si,scls) = hio_bsw_md_understory_si_scls(io_si,scls) + & + sapw_m_turnover * ccohort%n / m2_per_ha / days_per_year / sec_per_day + hio_bstore_md_understory_si_scls(io_si,scls) = hio_bstore_md_understory_si_scls(io_si,scls) + & + store_m_turnover * ccohort%n / m2_per_ha / days_per_year / sec_per_day + hio_bdead_md_understory_si_scls(io_si,scls) = hio_bdead_md_understory_si_scls(io_si,scls) + & + struct_m_turnover * ccohort%n / m2_per_ha / days_per_year / sec_per_day + hio_seed_prod_understory_si_scls(io_si,scls) = hio_seed_prod_understory_si_scls(io_si,scls) + & + ccohort%seed_prod * ccohort%n / m2_per_ha / sec_per_day + + hio_npp_leaf_understory_si_scls(io_si,scls) = hio_npp_leaf_understory_si_scls(io_si,scls) + & + leaf_m_net_alloc * ccohort%n / m2_per_ha / days_per_year / sec_per_day + hio_npp_fnrt_understory_si_scls(io_si,scls) = hio_npp_fnrt_understory_si_scls(io_si,scls) + & + fnrt_m_net_alloc * ccohort%n / m2_per_ha / days_per_year / sec_per_day + hio_npp_sapw_understory_si_scls(io_si,scls) = hio_npp_sapw_understory_si_scls(io_si,scls) + & + sapw_m_net_alloc * ccohort%n / m2_per_ha / days_per_year / sec_per_day + hio_npp_dead_understory_si_scls(io_si,scls) = hio_npp_dead_understory_si_scls(io_si,scls) + & + struct_m_net_alloc * ccohort%n / m2_per_ha / days_per_year / sec_per_day + hio_npp_seed_understory_si_scls(io_si,scls) = hio_npp_seed_understory_si_scls(io_si,scls) + & + repro_m_net_alloc * ccohort%n / m2_per_ha / days_per_year / sec_per_day + hio_npp_stor_understory_si_scls(io_si,scls) = hio_npp_stor_understory_si_scls(io_si,scls) + & + store_m_net_alloc * ccohort%n / m2_per_ha / days_per_year / sec_per_day + + hio_yesterdaycanopylevel_understory_si_scls(io_si,scls) = & + hio_yesterdaycanopylevel_understory_si_scls(io_si,scls) + & + ccohort%canopy_layer_yesterday * ccohort%n / m2_per_ha + endif canlayer + ! + ! + ccohort%canopy_layer_yesterday = real(ccohort%canopy_layer, r8) + ! + ! growth flux of individuals into a given bin + ! track the actual growth here, the virtual growth from fusion lower down + if ( (scls - ccohort%size_class_lasttimestep ) .gt. 0) then + do i_scls = ccohort%size_class_lasttimestep + 1, scls + i_scpf = (ccohort%pft-1)*nlevsclass+i_scls + hio_growthflux_si_scpf(io_si,i_scpf) = hio_growthflux_si_scpf(io_si,i_scpf) + & + ccohort%n * days_per_year / m2_per_ha + end do + end if + ccohort%size_class_lasttimestep = scls + + end associate + else notnew ! i.e. cohort%isnew + ! + ! if cohort is new, track its growth flux into the first size bin + i_scpf = (ccohort%pft-1)*nlevsclass+1 + hio_growthflux_si_scpf(io_si,i_scpf) = & + hio_growthflux_si_scpf(io_si,i_scpf) + ccohort%n * & + days_per_year / m2_per_ha + ccohort%size_class_lasttimestep = 1 + + end if notnew + + ! resolve some canopy area profiles, both total and of occupied leaves + ican = ccohort%canopy_layer + ! + hio_crownarea_cl(io_si, ican) = hio_crownarea_cl(io_si, ican) + ccohort%c_area / AREA + ! + do ileaf=1,ccohort%nv + cnlf_indx = ileaf + (ican-1) * nlevleaf + hio_crownarea_si_cnlf(io_si, cnlf_indx) = hio_crownarea_si_cnlf(io_si, cnlf_indx) + & + ccohort%c_area / AREA + end do + + ccohort => ccohort%taller + enddo cohortloop ! cohort loop + + + + do ilyr = 1,sites(s)%nlevsoil + hio_fragmentation_scaler_sl(io_si,ilyr) = hio_fragmentation_scaler_sl(io_si,ilyr) + cpatch%fragmentation_scaler(ilyr) * cpatch%area * AREA_INV + end do + + do i_fuel = 1, num_fuel_classes + + hio_litter_moisture_si_fuel(io_si, i_fuel) = hio_litter_moisture_si_fuel(io_si, i_fuel) + & + cpatch%fuel%effective_moisture(i_fuel) * cpatch%area * AREA_INV + + hio_fuel_amount_si_fuel(io_si, i_fuel) = hio_fuel_amount_si_fuel(io_si, i_fuel) + & + cpatch%fuel%frac_loading(i_fuel) * cpatch%fuel%non_trunk_loading * cpatch%area * AREA_INV + + hio_burnt_frac_litter_si_fuel(io_si, i_fuel) = hio_burnt_frac_litter_si_fuel(io_si, i_fuel) + & + cpatch%fuel%frac_burnt(i_fuel) * cpatch%frac_burnt * cpatch%area * AREA_INV + end do + + + + + ! Update Litter Flux Variables + + litt_c => cpatch%litter(element_pos(carbon12_element)) + + do i_pft = 1, numpft + ! Sum up total seed bank (germinated and ungerminated) + hio_seed_bank_si_pft(io_si,i_pft) = hio_seed_bank_si_pft(io_si,i_pft) + & + (litt_c%seed(i_pft)+litt_c%seed_germ(i_pft)) * cpatch%area * AREA_INV + + ! Sum up total seed bank (just ungerminated) + hio_ungerm_seed_bank_si_pft(io_si,i_pft) = hio_ungerm_seed_bank_si_pft(io_si,i_pft) + & + litt_c%seed(i_pft) * cpatch%area * AREA_INV + + ! Sum up total seedling pool + hio_seedling_pool_si_pft(io_si,i_pft) = hio_seedling_pool_si_pft(io_si,i_pft) + & + litt_c%seed_germ(i_pft) * cpatch%area * AREA_INV + + ! Sum up the input flux into the seed bank (local and external) + hio_seeds_in_si_pft(io_si,i_pft) = hio_seeds_in_si_pft(io_si,i_pft) + & + (litt_c%seed_in_local(i_pft) + litt_c%seed_in_extern(i_pft)) * & + cpatch%area * AREA_INV * days_per_sec + + hio_seeds_in_local_si_pft(io_si,i_pft) = hio_seeds_in_local_si_pft(io_si,i_pft) + & + litt_c%seed_in_local(i_pft) * & + cpatch%area * AREA_INV * days_per_sec + + end do + + do i_cwd = 1, ncwd + + hio_cwd_ag_si_cwdsc(io_si, i_cwd) = hio_cwd_ag_si_cwdsc(io_si, i_cwd) + & + litt_c%ag_cwd(i_cwd)*cpatch%area * AREA_INV + hio_cwd_bg_si_cwdsc(io_si, i_cwd) = hio_cwd_bg_si_cwdsc(io_si, i_cwd) + & + sum(litt_c%bg_cwd(i_cwd,:)) * cpatch%area * AREA_INV + + hio_cwd_ag_out_si_cwdsc(io_si, i_cwd) = hio_cwd_ag_out_si_cwdsc(io_si, i_cwd) + & + litt_c%ag_cwd_frag(i_cwd)*cpatch%area * AREA_INV / & + days_per_year / sec_per_day + + hio_cwd_bg_out_si_cwdsc(io_si, i_cwd) = hio_cwd_bg_out_si_cwdsc(io_si, i_cwd) + & + sum(litt_c%bg_cwd_frag(i_cwd,:)) * cpatch%area * AREA_INV / & + days_per_year / sec_per_day + + end do + + cpatch => cpatch%younger + end do patchloop !patch loop + + ! 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 + hio_cstarvmortality_carbonflux_si_pft(io_si,i_pft) = & + hio_cstarvmortality_carbonflux_si_pft(io_si,i_pft) + & + (sites(s)%term_carbonflux_ustory(i_term_mort_type_cstarv,i_pft) + & + sites(s)%term_carbonflux_canopy(i_term_mort_type_cstarv,i_pft)) * days_per_sec * ha_per_m2 + end do + do ft = 1, numpft + do i_scls = 1,nlevsclass + i_scpf = (ft-1)*nlevsclass + i_scls + ! + ! termination mortality. sum of canopy and understory indices + + ! move carbon starvation-related termination mortality to the carbon starvation mortality type and only consider + ! the other two types of termination mortality here. + + hio_m6_si_scpf(io_si,i_scpf) = & + (sum(sites(s)%term_nindivs_canopy(i_term_mort_type_canlev:n_term_mort_types,i_scls,ft)) + & + sum(sites(s)%term_nindivs_ustory(i_term_mort_type_canlev:n_term_mort_types,i_scls,ft))) * & + days_per_year / m2_per_ha + + hio_m6_si_scls(io_si,i_scls) = hio_m6_si_scls(io_si,i_scls) + & + (sum(sites(s)%term_nindivs_canopy(i_term_mort_type_canlev:n_term_mort_types,i_scls,ft)) + & + sum(sites(s)%term_nindivs_ustory(i_term_mort_type_canlev:n_term_mort_types,i_scls,ft))) * & + days_per_year / m2_per_ha + ! + ! add the carbon starvation-related termination mortality to the carbon starvation diagnostics + hio_m3_si_scpf(io_si,i_scpf) = hio_m3_si_scpf(io_si,i_scpf) + & + (sites(s)%term_nindivs_canopy(i_term_mort_type_cstarv,i_scls,ft) + & + sites(s)%term_nindivs_ustory(i_term_mort_type_cstarv,i_scls,ft)) * & + days_per_year / m2_per_ha + + hio_m3_si_scls(io_si,i_scls) = hio_m3_si_scls(io_si,i_scls) + & + (sites(s)%term_nindivs_canopy(i_term_mort_type_cstarv,i_scls,ft) + & + sites(s)%term_nindivs_ustory(i_term_mort_type_cstarv,i_scls,ft)) * & + days_per_year / m2_per_ha + + ! add c-starve termination mortality to canopy and understory M3 mortality (N/m^2/yr) + hio_m3_mortality_canopy_si_scpf(io_si,i_scpf) = & + hio_m3_mortality_canopy_si_scpf(io_si,i_scpf) + & + sites(s)%term_nindivs_canopy(i_term_mort_type_cstarv,i_scls,ft) * & + days_per_year / m2_per_ha + + hio_m3_mortality_understory_si_scpf(io_si,i_scpf) = & + hio_m3_mortality_understory_si_scpf(io_si,i_scpf) + & + sites(s)%term_nindivs_ustory(i_term_mort_type_cstarv,i_scls,ft) * & + days_per_year / m2_per_ha + + hio_m3_mortality_canopy_si_scls(io_si,i_scls) = & + hio_m3_mortality_canopy_si_scls(io_si,i_scls) + & + sites(s)%term_nindivs_canopy(i_term_mort_type_cstarv,i_scls,ft) * & + days_per_year / m2_per_ha + + hio_m3_mortality_understory_si_scls(io_si,i_scls) = & + hio_m3_mortality_understory_si_scls(io_si,i_scls) + & + sites(s)%term_nindivs_ustory(i_term_mort_type_cstarv,i_scls,ft) * & + days_per_year / m2_per_ha + ! + ! add termination mortality to canopy and understory mortality + hio_mortality_canopy_si_scls(io_si,i_scls) = hio_mortality_canopy_si_scls(io_si,i_scls) + & + sum(sites(s)%term_nindivs_canopy(:,i_scls,ft)) * days_per_year / m2_per_ha + + hio_mortality_understory_si_scls(io_si,i_scls) = hio_mortality_understory_si_scls(io_si,i_scls) + & + sum(sites(s)%term_nindivs_ustory(:,i_scls,ft)) * days_per_year / m2_per_ha + + hio_mortality_canopy_si_scpf(io_si,i_scpf) = hio_mortality_canopy_si_scpf(io_si,i_scpf) + & + sum(sites(s)%term_nindivs_canopy(:,i_scls,ft)) * days_per_year / m2_per_ha + + hio_mortality_understory_si_scpf(io_si,i_scpf) = hio_mortality_understory_si_scpf(io_si,i_scpf) + & + sum(sites(s)%term_nindivs_ustory(:,i_scls,ft)) * days_per_year / m2_per_ha + + + ! + ! imort on its own + hio_m4_si_scpf(io_si,i_scpf) = sites(s)%imort_rate(i_scls, ft) / m2_per_ha + hio_m4_si_scls(io_si,i_scls) = hio_m4_si_scls(io_si,i_scls) + sites(s)%imort_rate(i_scls, ft) / m2_per_ha ! - ccohort%canopy_layer_yesterday = real(ccohort%canopy_layer, r8) + ! add imort to other mortality terms. consider imort as understory mortality even if it happens in + ! cohorts that may have been promoted as part of the patch creation, and use the pre-calculated site-level + ! values to avoid biasing the results by the dramatically-reduced number densities in cohorts that are subject to imort + hio_mortality_understory_si_scpf(io_si,i_scpf) = hio_mortality_understory_si_scpf(io_si,i_scpf) + & + sites(s)%imort_rate(i_scls, ft) / m2_per_ha + hio_mortality_understory_si_scls(io_si,i_scls) = hio_mortality_understory_si_scls(io_si,i_scls) + & + sites(s)%imort_rate(i_scls, ft) / m2_per_ha ! - ! growth flux of individuals into a given bin - ! track the actual growth here, the virtual growth from fusion lower down - if ( (scls - ccohort%size_class_lasttimestep ) .gt. 0) then - do i_scls = ccohort%size_class_lasttimestep + 1, scls - i_scpf = (ccohort%pft-1)*nlevsclass+i_scls - hio_growthflux_si_scpf(io_si,i_scpf) = hio_growthflux_si_scpf(io_si,i_scpf) + & - ccohort%n * days_per_year / m2_per_ha + + ! wildfire mortality from the site-level diagnostic rates + hio_m5_si_scpf(io_si,i_scpf) = (sites(s)%nonrx_fmort_rate_canopy(i_scls, ft) + & + sites(s)%nonrx_fmort_rate_ustory(i_scls, ft)) / m2_per_ha + hio_m5_si_scls(io_si,i_scls) = hio_m5_si_scls(io_si,i_scls) + & + (sites(s)%nonrx_fmort_rate_canopy(i_scls, ft) + & + sites(s)%nonrx_fmort_rate_ustory(i_scls, ft)) / m2_per_ha + ! prescribed fire mortality + hio_m12_si_scpf(io_si,i_scpf) = (sites(s)%rx_fmort_rate_canopy(i_scls,ft) + & + sites(s)%rx_fmort_rate_ustory(i_scls, ft)) / m2_per_ha + hio_m12_si_scls(io_si,i_scls) = hio_m12_si_scls(io_si,i_scls) + & + (sites(s)%rx_fmort_rate_canopy(i_scls, ft) + & + sites(s)%rx_fmort_rate_ustory(i_scls, ft)) / m2_per_ha + ! wildfire crown and cambial mort + hio_nonrx_crown_mort_si_scpf(io_si,i_scpf) = sites(s)%nonrx_fmort_rate_crown(i_scls, ft) / m2_per_ha + hio_nonrx_cambial_mort_si_scpf(io_si,i_scpf) = sites(s)%nonrx_fmort_rate_cambial(i_scls, ft) / m2_per_ha + ! prescribed fire crown and cambial mort + hio_rx_crown_mort_si_scpf(io_si,i_scpf) = sites(s)%rx_fmort_rate_crown(i_scls, ft) / m2_per_ha + hio_rx_cambial_mort_si_scpf(io_si,i_scpf) = sites(s)%rx_fmort_rate_cambial(i_scls, ft) / m2_per_ha + ! + ! fire components of overall canopy and understory mortality + hio_mortality_canopy_si_scpf(io_si,i_scpf) = hio_mortality_canopy_si_scpf(io_si,i_scpf) + & + sites(s)%fmort_rate_canopy(i_scls, ft) / m2_per_ha + 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, ft) / m2_per_ha + + ! 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) + & + sites(s)%fmort_rate_ustory(i_scls, ft) / m2_per_ha + + 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, ft) / m2_per_ha + + ! while in this loop, pass the fusion-induced growth rate flux to history + hio_growthflux_fusion_si_scpf(io_si,i_scpf) = hio_growthflux_fusion_si_scpf(io_si,i_scpf) + & + sites(s)%growthflux_fusion(i_scls, ft) * days_per_year / m2_per_ha + + end do + end do + + + + do ft = 1, numpft + hio_mortality_carbonflux_si_pft(io_si,ft) = hio_mortality_carbonflux_si_pft(io_si,ft) + & + (sites(s)%fmort_carbonflux_canopy(ft) + & + sites(s)%fmort_carbonflux_ustory(ft)) / g_per_kg + & + sites(s)%imort_carbonflux(ft) + & + sum(sites(s)%term_carbonflux_ustory(:,ft)) * days_per_sec * ha_per_m2 + & + sum(sites(s)%term_carbonflux_canopy(:,ft)) * days_per_sec * ha_per_m2 + + hio_firemortality_carbonflux_si_pft(io_si,ft) = (sites(s)%fmort_carbonflux_canopy(ft) + & + sites(s)%fmort_carbonflux_ustory(ft)) / g_per_kg + end do + + ! add imort and fmort to aboveground woody mortality + do ft = 1, numpft + do i_scls = 1,nlevsclass + i_scpf = (ft-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,ft) / g_per_kg ) + & + sites(s)%imort_abg_flux(i_scls,ft) + & + (sites(s)%term_abg_flux(i_scls,ft) * days_per_sec * ha_per_m2 ) + end do + end do + + + if(hlm_use_tree_damage .eq. itrue) then + + do ft = 1, numpft + do icdam = 1, nlevdamage + do i_scls = 1,nlevsclass + + icdsc = (icdam-1)*nlevsclass + i_scls + icdpf = (icdam-1)*nlevsclass + i_scls + & + (ft-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, ft) * days_per_year) + & + (sites(s)%term_nindivs_ustory_damage(icdam, i_scls, ft) * days_per_year) + & + sites(s)%imort_rate_damage(icdam, i_scls, ft) + & + sites(s)%fmort_rate_canopy_damage(icdam, i_scls, ft) + & + sites(s)%fmort_rate_ustory_damage(icdam, i_scls, ft)) / 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,ft) * days_per_year + & + sites(s)%fmort_rate_canopy_damage(icdam, i_scls, ft))/ 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,ft) * days_per_year + & + sites(s)%imort_rate_damage(icdam, i_scls, ft) + & + sites(s)%fmort_rate_ustory_damage(icdam, i_scls, ft))/ m2_per_ha + end do + end do + end do + end if + + ! pass the recruitment rate as a flux to the history, and then reset the recruitment buffer + do ft = 1, numpft + ! pass the recruitment rate as a flux to the history, and then reset the recruitment buffer + hio_recruitment_si_pft(io_si,ft) = sites(s)%recruitment_rate(ft) * days_per_year / m2_per_ha + + ! Gridcell output and inputs + hio_seeds_out_gc_si_pft(io_si,ft) = sites(s)%seed_out(ft) + hio_seeds_in_gc_si_pft(io_si,ft) = sites(s)%seed_in(ft) + end do + sites(s)%recruitment_rate(:) = 0._r8 + + ! summarize all of the mortality fluxes by PFT + do ft = 1, numpft + do i_scls = 1,nlevsclass + i_scpf = (ft-1)*nlevsclass + i_scls + + hio_mortality_si_pft(io_si,ft) = hio_mortality_si_pft(io_si,ft) + & + hio_m1_si_scpf(io_si,i_scpf) + & + hio_m2_si_scpf(io_si,i_scpf) + & + hio_m3_si_scpf(io_si,i_scpf) + & + hio_m4_si_scpf(io_si,i_scpf) + & + hio_m5_si_scpf(io_si,i_scpf) + & + hio_m6_si_scpf(io_si,i_scpf) + & + hio_m7_si_scpf(io_si,i_scpf) + & + hio_m8_si_scpf(io_si,i_scpf) + & + hio_m9_si_scpf(io_si,i_scpf) + & + hio_m10_si_scpf(io_si,i_scpf) + & + hio_m12_si_scpf(io_si,i_scpf) + + if(hlm_use_tree_damage .eq. itrue) then + hio_mortality_si_pft(io_si, ft) = hio_mortality_si_pft(io_si,ft) + & + this%hvars(ih_m11_si_scpf)%r82d(io_si,i_scpf) end if - ccohort%size_class_lasttimestep = scls - - end associate - else notnew ! i.e. cohort%isnew - ! - ! if cohort is new, track its growth flux into the first size bin - i_scpf = (ccohort%pft-1)*nlevsclass+1 - hio_growthflux_si_scpf(io_si,i_scpf) = & - hio_growthflux_si_scpf(io_si,i_scpf) + ccohort%n * & - days_per_year / m2_per_ha - ccohort%size_class_lasttimestep = 1 - end if notnew + end do + end do + + ! ------------------------------------------------------------------------------ + ! Some carbon only litter diagnostics (legacy) + ! ------------------------------------------------------------------------------ + + elflux_diags_c => sites(s)%flux_diags%elem(element_pos(carbon12_element)) + + ! ------------------------------------------------------------------------------ + ! Diagnostics discretized by element type + ! ------------------------------------------------------------------------------ + + do el = 1, num_elements - ! resolve some canopy area profiles, both total and of occupied leaves - ican = ccohort%canopy_layer - ! - hio_crownarea_cl(io_si, ican) = hio_crownarea_cl(io_si, ican) + ccohort%c_area / AREA - ! - do ileaf=1,ccohort%nv - cnlf_indx = ileaf + (ican-1) * nlevleaf - hio_crownarea_si_cnlf(io_si, cnlf_indx) = hio_crownarea_si_cnlf(io_si, cnlf_indx) + & - ccohort%c_area / AREA - end do + elflux_diags => sites(s)%flux_diags%elem(el) - ccohort => ccohort%taller - enddo cohortloop ! cohort loop + ! Sum up all input litter fluxes (above below, fines, cwd) [kg/ha/day] + hio_litter_in_elem(io_si, el) = (sum(elflux_diags%cwd_ag_input(:)) + & + sum(elflux_diags%cwd_bg_input(:)) + sum(elflux_diags%surf_fine_litter_input(:)) + & + sum(elflux_diags%root_litter_input(:))) / m2_per_ha / sec_per_day + ! Plant multi-element states and fluxes + ! Zero states, and set the fluxes + if(element_list(el).eq.carbon12_element)then + this%hvars(ih_totvegc_scpf)%r82d(io_si,:) = 0._r8 + this%hvars(ih_leafc_scpf)%r82d(io_si,:) = 0._r8 + this%hvars(ih_fnrtc_scpf)%r82d(io_si,:) = 0._r8 + this%hvars(ih_sapwc_scpf)%r82d(io_si,:) = 0._r8 + this%hvars(ih_storec_scpf)%r82d(io_si,:) = 0._r8 + this%hvars(ih_reproc_scpf)%r82d(io_si,:) = 0._r8 - do ilyr = 1,sites(s)%nlevsoil - hio_fragmentation_scaler_sl(io_si,ilyr) = hio_fragmentation_scaler_sl(io_si,ilyr) + cpatch%fragmentation_scaler(ilyr) * cpatch%area * AREA_INV - end do + elseif(element_list(el).eq.nitrogen_element)then - do i_fuel = 1, num_fuel_classes + this%hvars(ih_totvegn_scpf)%r82d(io_si,:) = 0._r8 + this%hvars(ih_leafn_scpf)%r82d(io_si,:) = 0._r8 + 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_repron_scpf)%r82d(io_si,:) = 0._r8 - hio_litter_moisture_si_fuel(io_si, i_fuel) = hio_litter_moisture_si_fuel(io_si, i_fuel) + & - cpatch%fuel%effective_moisture(i_fuel) * cpatch%area * AREA_INV + 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_reprop_scpf)%r82d(io_si,:) = 0._r8 - hio_fuel_amount_si_fuel(io_si, i_fuel) = hio_fuel_amount_si_fuel(io_si, i_fuel) + & - cpatch%fuel%frac_loading(i_fuel) * cpatch%fuel%non_trunk_loading * cpatch%area * AREA_INV - hio_burnt_frac_litter_si_fuel(io_si, i_fuel) = hio_burnt_frac_litter_si_fuel(io_si, i_fuel) + & - cpatch%fuel%frac_burnt(i_fuel) * cpatch%frac_burnt * cpatch%area * AREA_INV - end do + end if + cpatch => sites(s)%oldest_patch + do while(associated(cpatch)) + + litt => cpatch%litter(el) + + patch_fracarea = cpatch%area * AREA_INV + + ! Sum up all output fluxes (fragmentation) + hio_litter_out_elem(io_si,el) = hio_litter_out_elem(io_si,el) + & + (sum(litt%leaf_fines_frag(:)) + & + sum(litt%root_fines_frag(:,:)) + & + sum(litt%ag_cwd_frag(:)) + & + sum(litt%bg_cwd_frag(:,:)) + & + sum(litt%seed_decay(:)) + & + sum(litt%seed_germ_decay(:))) * cpatch%area / m2_per_ha / sec_per_day + + hio_seed_bank_elem(io_si,el) = hio_seed_bank_elem(io_si,el) + & + 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 + + hio_seed_decay_elem(io_si,el) = hio_seed_decay_elem(io_si,el) + & + sum(litt%seed_decay(:) + litt%seed_germ_decay(:) ) * & + cpatch%area / m2_per_ha / sec_per_day + + hio_seeds_in_local_elem(io_si,el) = hio_seeds_in_local_elem(io_si,el) + & + sum(litt%seed_in_local(:)) * cpatch%area / m2_per_ha / sec_per_day + + hio_seed_in_extern_elem(io_si,el) = hio_seed_in_extern_elem(io_si,el) + & + sum(litt%seed_in_extern(:)) * cpatch%area / m2_per_ha / sec_per_day + + ! Litter State Variables + hio_cwd_ag_elem(io_si,el) = hio_cwd_ag_elem(io_si,el) + & + sum(litt%ag_cwd(:)) * cpatch%area / m2_per_ha + + hio_cwd_bg_elem(io_si,el) = hio_cwd_bg_elem(io_si,el) + & + sum(litt%bg_cwd(:,:)) * cpatch%area / m2_per_ha + + hio_fines_ag_elem(io_si,el) = hio_fines_ag_elem(io_si,el) + & + sum(litt%leaf_fines(:)) * cpatch%area / m2_per_ha + + hio_fines_bg_elem(io_si,el) = hio_fines_bg_elem(io_si,el) + & + sum(litt%root_fines(:,:)) * cpatch%area / m2_per_ha + + do i_cwd=1,ncwd + elcwd = (el-1)*ncwd+i_cwd + hio_cwd_elcwd(io_si,elcwd) = hio_cwd_elcwd(io_si,elcwd) + & + (litt%ag_cwd(i_cwd) + sum(litt%bg_cwd(i_cwd,:))) * & + cpatch%area / m2_per_ha + + end do + + ! Load Mass States + ccohort => cpatch%tallest + do while(associated(ccohort)) + + call ccohort%prt%GetBiomass(element_list(el), & + sapw_m, struct_m, leaf_m, fnrt_m, store_m, repro_m, alive_m, total_m) + + + i_scpf = ccohort%size_by_pft_class + + if(element_list(el).eq.carbon12_element)then + this%hvars(ih_totvegc_scpf)%r82d(io_si,i_scpf) = & + this%hvars(ih_totvegc_scpf)%r82d(io_si,i_scpf) + & + total_m * ccohort%n / m2_per_ha + this%hvars(ih_leafc_scpf)%r82d(io_si,i_scpf) = & + this%hvars(ih_leafc_scpf)%r82d(io_si,i_scpf) + & + leaf_m * ccohort%n / m2_per_ha + this%hvars(ih_fnrtc_scpf)%r82d(io_si,i_scpf) = & + this%hvars(ih_fnrtc_scpf)%r82d(io_si,i_scpf) + & + fnrt_m * ccohort%n / m2_per_ha + this%hvars(ih_sapwc_scpf)%r82d(io_si,i_scpf) = & + this%hvars(ih_sapwc_scpf)%r82d(io_si,i_scpf) + & + sapw_m * ccohort%n / m2_per_ha + this%hvars(ih_storec_scpf)%r82d(io_si,i_scpf) = & + this%hvars(ih_storec_scpf)%r82d(io_si,i_scpf) + & + store_m * ccohort%n / m2_per_ha + this%hvars(ih_reproc_scpf)%r82d(io_si,i_scpf) = & + this%hvars(ih_reproc_scpf)%r82d(io_si,i_scpf) + & + 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,stoich_growth_min) + + this%hvars(ih_totvegn_scpf)%r82d(io_si,i_scpf) = & + this%hvars(ih_totvegn_scpf)%r82d(io_si,i_scpf) + & + total_m * ccohort%n / m2_per_ha + this%hvars(ih_leafn_scpf)%r82d(io_si,i_scpf) = & + this%hvars(ih_leafn_scpf)%r82d(io_si,i_scpf) + & + leaf_m * ccohort%n / m2_per_ha + this%hvars(ih_fnrtn_scpf)%r82d(io_si,i_scpf) = & + this%hvars(ih_fnrtn_scpf)%r82d(io_si,i_scpf) + & + fnrt_m * ccohort%n / m2_per_ha + this%hvars(ih_sapwn_scpf)%r82d(io_si,i_scpf) = & + this%hvars(ih_sapwn_scpf)%r82d(io_si,i_scpf) + & + sapw_m * ccohort%n / m2_per_ha + this%hvars(ih_storen_scpf)%r82d(io_si,i_scpf) = & + this%hvars(ih_storen_scpf)%r82d(io_si,i_scpf) + & + store_m * ccohort%n / m2_per_ha + this%hvars(ih_repron_scpf)%r82d(io_si,i_scpf) = & + this%hvars(ih_repron_scpf)%r82d(io_si,i_scpf) + & + repro_m * ccohort%n / m2_per_ha + + elseif(element_list(el).eq.phosphorus_element)then + + 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) + & + total_m * ccohort%n / m2_per_ha + this%hvars(ih_leafp_scpf)%r82d(io_si,i_scpf) = & + this%hvars(ih_leafp_scpf)%r82d(io_si,i_scpf) + & + leaf_m * ccohort%n / m2_per_ha + this%hvars(ih_fnrtp_scpf)%r82d(io_si,i_scpf) = & + this%hvars(ih_fnrtp_scpf)%r82d(io_si,i_scpf) + & + fnrt_m * ccohort%n / m2_per_ha + this%hvars(ih_sapwp_scpf)%r82d(io_si,i_scpf) = & + this%hvars(ih_sapwp_scpf)%r82d(io_si,i_scpf) + & + sapw_m * ccohort%n / m2_per_ha + this%hvars(ih_storep_scpf)%r82d(io_si,i_scpf) = & + this%hvars(ih_storep_scpf)%r82d(io_si,i_scpf) + & + store_m * ccohort%n / m2_per_ha + this%hvars(ih_reprop_scpf)%r82d(io_si,i_scpf) = & + this%hvars(ih_reprop_scpf)%r82d(io_si,i_scpf) + & + repro_m * ccohort%n / m2_per_ha + end if - ! Update Litter Flux Variables + ccohort => ccohort%shorter + end do ! end cohort loop - litt_c => cpatch%litter(element_pos(carbon12_element)) + cpatch => cpatch%younger + end do ! end patch loop - do i_pft = 1, numpft - ! Sum up total seed bank (germinated and ungerminated) - hio_seed_bank_si_pft(io_si,i_pft) = hio_seed_bank_si_pft(io_si,i_pft) + & - (litt_c%seed(i_pft)+litt_c%seed_germ(i_pft)) * cpatch%area * AREA_INV + end do ! end element loop - ! Sum up total seed bank (just ungerminated) - hio_ungerm_seed_bank_si_pft(io_si,i_pft) = hio_ungerm_seed_bank_si_pft(io_si,i_pft) + & - litt_c%seed(i_pft) * cpatch%area * AREA_INV + do ft = 1, numpft + do i_scls = 1,nlevsclass + i_scpf = (ft-1)*nlevsclass + i_scls - ! Sum up total seedling pool - hio_seedling_pool_si_pft(io_si,i_pft) = hio_seedling_pool_si_pft(io_si,i_pft) + & - litt_c%seed_germ(i_pft) * cpatch%area * AREA_INV + 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 - ! Sum up the input flux into the seed bank (local and external) - hio_seeds_in_si_pft(io_si,i_pft) = hio_seeds_in_si_pft(io_si,i_pft) + & - (litt_c%seed_in_local(i_pft) + litt_c%seed_in_extern(i_pft)) * & - cpatch%area * AREA_INV * days_per_sec + end do + end do - hio_seeds_in_local_si_pft(io_si,i_pft) = hio_seeds_in_local_si_pft(io_si,i_pft) + & - litt_c%seed_in_local(i_pft) * & - cpatch%area * AREA_INV * days_per_sec + do el = 1, num_elements - end do + if(element_list(el).eq.nitrogen_element)then - do i_cwd = 1, ncwd + do ft = 1, numpft + do i_scls = 1,nlevsclass + i_scpf = (ft-1)*nlevsclass + i_scls - hio_cwd_ag_si_cwdsc(io_si, i_cwd) = hio_cwd_ag_si_cwdsc(io_si, i_cwd) + & - litt_c%ag_cwd(i_cwd)*cpatch%area * AREA_INV - hio_cwd_bg_si_cwdsc(io_si, i_cwd) = hio_cwd_bg_si_cwdsc(io_si, i_cwd) + & - sum(litt_c%bg_cwd(i_cwd,:)) * cpatch%area * AREA_INV + 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) = & + storen_canopy_scpf(i_scpf) / & + this%hvars(ih_storentfrac_canopy_scpf)%r82d(io_si,i_scpf) + end if + 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) = & + storen_understory_scpf(i_scpf) / & + this%hvars(ih_storentfrac_understory_scpf)%r82d(io_si,i_scpf) + end if - hio_cwd_ag_out_si_cwdsc(io_si, i_cwd) = hio_cwd_ag_out_si_cwdsc(io_si, i_cwd) + & - litt_c%ag_cwd_frag(i_cwd)*cpatch%area * AREA_INV / & - days_per_year / sec_per_day + end do + end do + elseif(element_list(el).eq.phosphorus_element)then + + do ft = 1, numpft + do i_scls = 1,nlevsclass + i_scpf = (ft-1)*nlevsclass + i_scls + + 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) = & + storep_canopy_scpf(i_scpf) / & + this%hvars(ih_storeptfrac_canopy_scpf)%r82d(io_si,i_scpf) + end if + 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) = & + storep_understory_scpf(i_scpf) / & + this%hvars(ih_storeptfrac_understory_scpf)%r82d(io_si,i_scpf) + end if - hio_cwd_bg_out_si_cwdsc(io_si, i_cwd) = hio_cwd_bg_out_si_cwdsc(io_si, i_cwd) + & - sum(litt_c%bg_cwd_frag(i_cwd,:)) * cpatch%area * AREA_INV / & - days_per_year / sec_per_day + end do + end do + end if + end do + + ! pass demotion rates and associated carbon fluxes to history + do i_scls = 1,nlevsclass + hio_demotion_rate_si_scls(io_si,i_scls) = sites(s)%demotion_rate(i_scls) * days_per_year / m2_per_ha + hio_promotion_rate_si_scls(io_si,i_scls) = sites(s)%promotion_rate(i_scls) * days_per_year / m2_per_ha + end do + + ! add the site-level disturbance-associated cwd and litter input fluxes to thir respective flux fields - end do - - cpatch => cpatch%younger - end do patchloop !patch loop - - ! 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 - hio_cstarvmortality_carbonflux_si_pft(io_si,i_pft) = & - hio_cstarvmortality_carbonflux_si_pft(io_si,i_pft) + & - (sites(s)%term_carbonflux_ustory(i_term_mort_type_cstarv,i_pft) + & - sites(s)%term_carbonflux_canopy(i_term_mort_type_cstarv,i_pft)) * days_per_sec * ha_per_m2 - end do - do ft = 1, numpft - do i_scls = 1,nlevsclass - i_scpf = (ft-1)*nlevsclass + i_scls - ! - ! termination mortality. sum of canopy and understory indices - - ! move carbon starvation-related termination mortality to the carbon starvation mortality type and only consider - ! the other two types of termination mortality here. - - hio_m6_si_scpf(io_si,i_scpf) = & - (sum(sites(s)%term_nindivs_canopy(i_term_mort_type_canlev:n_term_mort_types,i_scls,ft)) + & - sum(sites(s)%term_nindivs_ustory(i_term_mort_type_canlev:n_term_mort_types,i_scls,ft))) * & - days_per_year / m2_per_ha - - hio_m6_si_scls(io_si,i_scls) = hio_m6_si_scls(io_si,i_scls) + & - (sum(sites(s)%term_nindivs_canopy(i_term_mort_type_canlev:n_term_mort_types,i_scls,ft)) + & - sum(sites(s)%term_nindivs_ustory(i_term_mort_type_canlev:n_term_mort_types,i_scls,ft))) * & - days_per_year / m2_per_ha - ! - ! add the carbon starvation-related termination mortality to the carbon starvation diagnostics - hio_m3_si_scpf(io_si,i_scpf) = hio_m3_si_scpf(io_si,i_scpf) + & - (sites(s)%term_nindivs_canopy(i_term_mort_type_cstarv,i_scls,ft) + & - sites(s)%term_nindivs_ustory(i_term_mort_type_cstarv,i_scls,ft)) * & - days_per_year / m2_per_ha - - hio_m3_si_scls(io_si,i_scls) = hio_m3_si_scls(io_si,i_scls) + & - (sites(s)%term_nindivs_canopy(i_term_mort_type_cstarv,i_scls,ft) + & - sites(s)%term_nindivs_ustory(i_term_mort_type_cstarv,i_scls,ft)) * & - days_per_year / m2_per_ha - - ! add c-starve termination mortality to canopy and understory M3 mortality (N/m^2/yr) - hio_m3_mortality_canopy_si_scpf(io_si,i_scpf) = & - hio_m3_mortality_canopy_si_scpf(io_si,i_scpf) + & - sites(s)%term_nindivs_canopy(i_term_mort_type_cstarv,i_scls,ft) * & - days_per_year / m2_per_ha - - hio_m3_mortality_understory_si_scpf(io_si,i_scpf) = & - hio_m3_mortality_understory_si_scpf(io_si,i_scpf) + & - sites(s)%term_nindivs_ustory(i_term_mort_type_cstarv,i_scls,ft) * & - days_per_year / m2_per_ha - - hio_m3_mortality_canopy_si_scls(io_si,i_scls) = & - hio_m3_mortality_canopy_si_scls(io_si,i_scls) + & - sites(s)%term_nindivs_canopy(i_term_mort_type_cstarv,i_scls,ft) * & - days_per_year / m2_per_ha - - hio_m3_mortality_understory_si_scls(io_si,i_scls) = & - hio_m3_mortality_understory_si_scls(io_si,i_scls) + & - sites(s)%term_nindivs_ustory(i_term_mort_type_cstarv,i_scls,ft) * & - days_per_year / m2_per_ha - - ! - ! add termination mortality to canopy and understory mortality - hio_mortality_canopy_si_scls(io_si,i_scls) = hio_mortality_canopy_si_scls(io_si,i_scls) + & - sum(sites(s)%term_nindivs_canopy(:,i_scls,ft)) * days_per_year / m2_per_ha - - hio_mortality_understory_si_scls(io_si,i_scls) = hio_mortality_understory_si_scls(io_si,i_scls) + & - sum(sites(s)%term_nindivs_ustory(:,i_scls,ft)) * days_per_year / m2_per_ha - - hio_mortality_canopy_si_scpf(io_si,i_scpf) = hio_mortality_canopy_si_scpf(io_si,i_scpf) + & - sum(sites(s)%term_nindivs_canopy(:,i_scls,ft)) * days_per_year / m2_per_ha - - hio_mortality_understory_si_scpf(io_si,i_scpf) = hio_mortality_understory_si_scpf(io_si,i_scpf) + & - sum(sites(s)%term_nindivs_ustory(:,i_scls,ft)) * days_per_year / m2_per_ha - - - ! - ! imort on its own - hio_m4_si_scpf(io_si,i_scpf) = sites(s)%imort_rate(i_scls, ft) / m2_per_ha - hio_m4_si_scls(io_si,i_scls) = hio_m4_si_scls(io_si,i_scls) + sites(s)%imort_rate(i_scls, ft) / m2_per_ha - ! - ! add imort to other mortality terms. consider imort as understory mortality even if it happens in - ! cohorts that may have been promoted as part of the patch creation, and use the pre-calculated site-level - ! values to avoid biasing the results by the dramatically-reduced number densities in cohorts that are subject to imort - hio_mortality_understory_si_scpf(io_si,i_scpf) = hio_mortality_understory_si_scpf(io_si,i_scpf) + & - sites(s)%imort_rate(i_scls, ft) / m2_per_ha - hio_mortality_understory_si_scls(io_si,i_scls) = hio_mortality_understory_si_scls(io_si,i_scls) + & - sites(s)%imort_rate(i_scls, ft) / m2_per_ha - ! - - ! wildfire mortality from the site-level diagnostic rates - hio_m5_si_scpf(io_si,i_scpf) = (sites(s)%nonrx_fmort_rate_canopy(i_scls, ft) + & - sites(s)%nonrx_fmort_rate_ustory(i_scls, ft)) / m2_per_ha - hio_m5_si_scls(io_si,i_scls) = hio_m5_si_scls(io_si,i_scls) + & - (sites(s)%nonrx_fmort_rate_canopy(i_scls, ft) + & - sites(s)%nonrx_fmort_rate_ustory(i_scls, ft)) / m2_per_ha - ! prescribed fire mortality - hio_m12_si_scpf(io_si,i_scpf) = (sites(s)%rx_fmort_rate_canopy(i_scls,ft) + & - sites(s)%rx_fmort_rate_ustory(i_scls, ft)) / m2_per_ha - hio_m12_si_scls(io_si,i_scls) = hio_m12_si_scls(io_si,i_scls) + & - (sites(s)%rx_fmort_rate_canopy(i_scls, ft) + & - sites(s)%rx_fmort_rate_ustory(i_scls, ft)) / m2_per_ha - ! wildfire crown and cambial mort - hio_nonrx_crown_mort_si_scpf(io_si,i_scpf) = sites(s)%nonrx_fmort_rate_crown(i_scls, ft) / m2_per_ha - hio_nonrx_cambial_mort_si_scpf(io_si,i_scpf) = sites(s)%nonrx_fmort_rate_cambial(i_scls, ft) / m2_per_ha - ! prescribed fire crown and cambial mort - hio_rx_crown_mort_si_scpf(io_si,i_scpf) = sites(s)%rx_fmort_rate_crown(i_scls, ft) / m2_per_ha - hio_rx_cambial_mort_si_scpf(io_si,i_scpf) = sites(s)%rx_fmort_rate_cambial(i_scls, ft) / m2_per_ha - ! - ! fire components of overall canopy and understory mortality - hio_mortality_canopy_si_scpf(io_si,i_scpf) = hio_mortality_canopy_si_scpf(io_si,i_scpf) + & - sites(s)%fmort_rate_canopy(i_scls, ft) / m2_per_ha - 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, ft) / m2_per_ha - - ! 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) + & - sites(s)%fmort_rate_ustory(i_scls, ft) / m2_per_ha - - 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, ft) / m2_per_ha - - ! while in this loop, pass the fusion-induced growth rate flux to history - hio_growthflux_fusion_si_scpf(io_si,i_scpf) = hio_growthflux_fusion_si_scpf(io_si,i_scpf) + & - sites(s)%growthflux_fusion(i_scls, ft) * days_per_year / m2_per_ha - - end do - end do - - - - do ft = 1, numpft - hio_mortality_carbonflux_si_pft(io_si,ft) = hio_mortality_carbonflux_si_pft(io_si,ft) + & - (sites(s)%fmort_carbonflux_canopy(ft) + & - sites(s)%fmort_carbonflux_ustory(ft)) / g_per_kg + & - sites(s)%imort_carbonflux(ft) + & - sum(sites(s)%term_carbonflux_ustory(:,ft)) * days_per_sec * ha_per_m2 + & - sum(sites(s)%term_carbonflux_canopy(:,ft)) * days_per_sec * ha_per_m2 - - hio_firemortality_carbonflux_si_pft(io_si,ft) = (sites(s)%fmort_carbonflux_canopy(ft) + & - sites(s)%fmort_carbonflux_ustory(ft)) / g_per_kg - end do - - ! add imort and fmort to aboveground woody mortality - do ft = 1, numpft - do i_scls = 1,nlevsclass - i_scpf = (ft-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,ft) / g_per_kg ) + & - sites(s)%imort_abg_flux(i_scls,ft) + & - (sites(s)%term_abg_flux(i_scls,ft) * days_per_sec * ha_per_m2 ) - end do - end do - - - if(hlm_use_tree_damage .eq. itrue) then - - do ft = 1, numpft - do icdam = 1, nlevdamage - do i_scls = 1,nlevsclass - - icdsc = (icdam-1)*nlevsclass + i_scls - icdpf = (icdam-1)*nlevsclass + i_scls + & - (ft-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, ft) * days_per_year) + & - (sites(s)%term_nindivs_ustory_damage(icdam, i_scls, ft) * days_per_year) + & - sites(s)%imort_rate_damage(icdam, i_scls, ft) + & - sites(s)%fmort_rate_canopy_damage(icdam, i_scls, ft) + & - sites(s)%fmort_rate_ustory_damage(icdam, i_scls, ft)) / 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,ft) * days_per_year + & - sites(s)%fmort_rate_canopy_damage(icdam, i_scls, ft))/ 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,ft) * days_per_year + & - sites(s)%imort_rate_damage(icdam, i_scls, ft) + & - sites(s)%fmort_rate_ustory_damage(icdam, i_scls, ft))/ m2_per_ha - - end do - end do - end do - end if - - ! pass the recruitment rate as a flux to the history, and then reset the recruitment buffer - do ft = 1, numpft - ! pass the recruitment rate as a flux to the history, and then reset the recruitment buffer - hio_recruitment_si_pft(io_si,ft) = sites(s)%recruitment_rate(ft) * days_per_year / m2_per_ha - - ! Gridcell output and inputs - hio_seeds_out_gc_si_pft(io_si,ft) = sites(s)%seed_out(ft) - hio_seeds_in_gc_si_pft(io_si,ft) = sites(s)%seed_in(ft) - end do - sites(s)%recruitment_rate(:) = 0._r8 - - ! summarize all of the mortality fluxes by PFT - do ft = 1, numpft - do i_scls = 1,nlevsclass - i_scpf = (ft-1)*nlevsclass + i_scls - - hio_mortality_si_pft(io_si,ft) = hio_mortality_si_pft(io_si,ft) + & - hio_m1_si_scpf(io_si,i_scpf) + & - hio_m2_si_scpf(io_si,i_scpf) + & - hio_m3_si_scpf(io_si,i_scpf) + & - hio_m4_si_scpf(io_si,i_scpf) + & - hio_m5_si_scpf(io_si,i_scpf) + & - hio_m6_si_scpf(io_si,i_scpf) + & - hio_m7_si_scpf(io_si,i_scpf) + & - hio_m8_si_scpf(io_si,i_scpf) + & - hio_m9_si_scpf(io_si,i_scpf) + & - hio_m10_si_scpf(io_si,i_scpf) + & - hio_m12_si_scpf(io_si,i_scpf) - - if(hlm_use_tree_damage .eq. itrue) then - hio_mortality_si_pft(io_si, ft) = hio_mortality_si_pft(io_si,ft) + & - this%hvars(ih_m11_si_scpf)%r82d(io_si,i_scpf) - end if - - end do - end do - - ! ------------------------------------------------------------------------------ - ! Some carbon only litter diagnostics (legacy) - ! ------------------------------------------------------------------------------ - - elflux_diags_c => sites(s)%flux_diags%elem(element_pos(carbon12_element)) - - ! ------------------------------------------------------------------------------ - ! Diagnostics discretized by element type - ! ------------------------------------------------------------------------------ - - do el = 1, num_elements - - elflux_diags => sites(s)%flux_diags%elem(el) - - ! Sum up all input litter fluxes (above below, fines, cwd) [kg/ha/day] - hio_litter_in_elem(io_si, el) = (sum(elflux_diags%cwd_ag_input(:)) + & - sum(elflux_diags%cwd_bg_input(:)) + sum(elflux_diags%surf_fine_litter_input(:)) + & - sum(elflux_diags%root_litter_input(:))) / m2_per_ha / sec_per_day - - - ! Plant multi-element states and fluxes - ! Zero states, and set the fluxes - if(element_list(el).eq.carbon12_element)then - this%hvars(ih_totvegc_scpf)%r82d(io_si,:) = 0._r8 - this%hvars(ih_leafc_scpf)%r82d(io_si,:) = 0._r8 - this%hvars(ih_fnrtc_scpf)%r82d(io_si,:) = 0._r8 - this%hvars(ih_sapwc_scpf)%r82d(io_si,:) = 0._r8 - this%hvars(ih_storec_scpf)%r82d(io_si,:) = 0._r8 - this%hvars(ih_reproc_scpf)%r82d(io_si,:) = 0._r8 - - elseif(element_list(el).eq.nitrogen_element)then - - this%hvars(ih_totvegn_scpf)%r82d(io_si,:) = 0._r8 - this%hvars(ih_leafn_scpf)%r82d(io_si,:) = 0._r8 - 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_repron_scpf)%r82d(io_si,:) = 0._r8 - - 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_reprop_scpf)%r82d(io_si,:) = 0._r8 - - - - end if - - cpatch => sites(s)%oldest_patch - do while(associated(cpatch)) - - litt => cpatch%litter(el) - - patch_fracarea = cpatch%area * AREA_INV - - ! Sum up all output fluxes (fragmentation) - hio_litter_out_elem(io_si,el) = hio_litter_out_elem(io_si,el) + & - (sum(litt%leaf_fines_frag(:)) + & - sum(litt%root_fines_frag(:,:)) + & - sum(litt%ag_cwd_frag(:)) + & - sum(litt%bg_cwd_frag(:,:)) + & - sum(litt%seed_decay(:)) + & - sum(litt%seed_germ_decay(:))) * cpatch%area / m2_per_ha / sec_per_day - - hio_seed_bank_elem(io_si,el) = hio_seed_bank_elem(io_si,el) + & - 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 - - hio_seed_decay_elem(io_si,el) = hio_seed_decay_elem(io_si,el) + & - sum(litt%seed_decay(:) + litt%seed_germ_decay(:) ) * & - cpatch%area / m2_per_ha / sec_per_day - - hio_seeds_in_local_elem(io_si,el) = hio_seeds_in_local_elem(io_si,el) + & - sum(litt%seed_in_local(:)) * cpatch%area / m2_per_ha / sec_per_day - - hio_seed_in_extern_elem(io_si,el) = hio_seed_in_extern_elem(io_si,el) + & - sum(litt%seed_in_extern(:)) * cpatch%area / m2_per_ha / sec_per_day - - ! Litter State Variables - hio_cwd_ag_elem(io_si,el) = hio_cwd_ag_elem(io_si,el) + & - sum(litt%ag_cwd(:)) * cpatch%area / m2_per_ha - - hio_cwd_bg_elem(io_si,el) = hio_cwd_bg_elem(io_si,el) + & - sum(litt%bg_cwd(:,:)) * cpatch%area / m2_per_ha - - hio_fines_ag_elem(io_si,el) = hio_fines_ag_elem(io_si,el) + & - sum(litt%leaf_fines(:)) * cpatch%area / m2_per_ha - - hio_fines_bg_elem(io_si,el) = hio_fines_bg_elem(io_si,el) + & - sum(litt%root_fines(:,:)) * cpatch%area / m2_per_ha - - do i_cwd=1,ncwd - elcwd = (el-1)*ncwd+i_cwd - hio_cwd_elcwd(io_si,elcwd) = hio_cwd_elcwd(io_si,elcwd) + & - (litt%ag_cwd(i_cwd) + sum(litt%bg_cwd(i_cwd,:))) * & - cpatch%area / m2_per_ha - - end do - - ! Load Mass States - ccohort => cpatch%tallest - do while(associated(ccohort)) - - call ccohort%prt%GetBiomass(element_list(el), & - sapw_m, struct_m, leaf_m, fnrt_m, store_m, repro_m, alive_m, total_m) - - - i_scpf = ccohort%size_by_pft_class - - if(element_list(el).eq.carbon12_element)then - this%hvars(ih_totvegc_scpf)%r82d(io_si,i_scpf) = & - this%hvars(ih_totvegc_scpf)%r82d(io_si,i_scpf) + & - total_m * ccohort%n / m2_per_ha - this%hvars(ih_leafc_scpf)%r82d(io_si,i_scpf) = & - this%hvars(ih_leafc_scpf)%r82d(io_si,i_scpf) + & - leaf_m * ccohort%n / m2_per_ha - this%hvars(ih_fnrtc_scpf)%r82d(io_si,i_scpf) = & - this%hvars(ih_fnrtc_scpf)%r82d(io_si,i_scpf) + & - fnrt_m * ccohort%n / m2_per_ha - this%hvars(ih_sapwc_scpf)%r82d(io_si,i_scpf) = & - this%hvars(ih_sapwc_scpf)%r82d(io_si,i_scpf) + & - sapw_m * ccohort%n / m2_per_ha - this%hvars(ih_storec_scpf)%r82d(io_si,i_scpf) = & - this%hvars(ih_storec_scpf)%r82d(io_si,i_scpf) + & - store_m * ccohort%n / m2_per_ha - this%hvars(ih_reproc_scpf)%r82d(io_si,i_scpf) = & - this%hvars(ih_reproc_scpf)%r82d(io_si,i_scpf) + & - 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,stoich_growth_min) - - this%hvars(ih_totvegn_scpf)%r82d(io_si,i_scpf) = & - this%hvars(ih_totvegn_scpf)%r82d(io_si,i_scpf) + & - total_m * ccohort%n / m2_per_ha - this%hvars(ih_leafn_scpf)%r82d(io_si,i_scpf) = & - this%hvars(ih_leafn_scpf)%r82d(io_si,i_scpf) + & - leaf_m * ccohort%n / m2_per_ha - this%hvars(ih_fnrtn_scpf)%r82d(io_si,i_scpf) = & - this%hvars(ih_fnrtn_scpf)%r82d(io_si,i_scpf) + & - fnrt_m * ccohort%n / m2_per_ha - this%hvars(ih_sapwn_scpf)%r82d(io_si,i_scpf) = & - this%hvars(ih_sapwn_scpf)%r82d(io_si,i_scpf) + & - sapw_m * ccohort%n / m2_per_ha - this%hvars(ih_storen_scpf)%r82d(io_si,i_scpf) = & - this%hvars(ih_storen_scpf)%r82d(io_si,i_scpf) + & - store_m * ccohort%n / m2_per_ha - this%hvars(ih_repron_scpf)%r82d(io_si,i_scpf) = & - this%hvars(ih_repron_scpf)%r82d(io_si,i_scpf) + & - repro_m * ccohort%n / m2_per_ha - - elseif(element_list(el).eq.phosphorus_element)then - - 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) + & - total_m * ccohort%n / m2_per_ha - this%hvars(ih_leafp_scpf)%r82d(io_si,i_scpf) = & - this%hvars(ih_leafp_scpf)%r82d(io_si,i_scpf) + & - leaf_m * ccohort%n / m2_per_ha - this%hvars(ih_fnrtp_scpf)%r82d(io_si,i_scpf) = & - this%hvars(ih_fnrtp_scpf)%r82d(io_si,i_scpf) + & - fnrt_m * ccohort%n / m2_per_ha - this%hvars(ih_sapwp_scpf)%r82d(io_si,i_scpf) = & - this%hvars(ih_sapwp_scpf)%r82d(io_si,i_scpf) + & - sapw_m * ccohort%n / m2_per_ha - this%hvars(ih_storep_scpf)%r82d(io_si,i_scpf) = & - this%hvars(ih_storep_scpf)%r82d(io_si,i_scpf) + & - store_m * ccohort%n / m2_per_ha - this%hvars(ih_reprop_scpf)%r82d(io_si,i_scpf) = & - this%hvars(ih_reprop_scpf)%r82d(io_si,i_scpf) + & - repro_m * ccohort%n / m2_per_ha - - end if - - ccohort => ccohort%shorter - end do ! end cohort loop - - cpatch => cpatch%younger - end do ! end patch loop - - end do ! end element loop - - do ft = 1, numpft - do i_scls = 1,nlevsclass - i_scpf = (ft-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 - - do ft = 1, numpft - do i_scls = 1,nlevsclass - i_scpf = (ft-1)*nlevsclass + i_scls - - 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) = & - storen_canopy_scpf(i_scpf) / & - this%hvars(ih_storentfrac_canopy_scpf)%r82d(io_si,i_scpf) - end if - 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) = & - storen_understory_scpf(i_scpf) / & - this%hvars(ih_storentfrac_understory_scpf)%r82d(io_si,i_scpf) - end if - - end do - end do - elseif(element_list(el).eq.phosphorus_element)then - - do ft = 1, numpft - do i_scls = 1,nlevsclass - i_scpf = (ft-1)*nlevsclass + i_scls - - 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) = & - storep_canopy_scpf(i_scpf) / & - this%hvars(ih_storeptfrac_canopy_scpf)%r82d(io_si,i_scpf) - end if - 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) = & - storep_understory_scpf(i_scpf) / & - this%hvars(ih_storeptfrac_understory_scpf)%r82d(io_si,i_scpf) - end if - - end do - end do - end if - end do - - ! pass demotion rates and associated carbon fluxes to history - do i_scls = 1,nlevsclass - hio_demotion_rate_si_scls(io_si,i_scls) = sites(s)%demotion_rate(i_scls) * days_per_year / m2_per_ha - hio_promotion_rate_si_scls(io_si,i_scls) = sites(s)%promotion_rate(i_scls) * days_per_year / m2_per_ha - end do - - ! add the site-level disturbance-associated cwd and litter input fluxes to thir respective flux fields - - do i_cwd = 1, ncwd - hio_cwd_ag_in_si_cwdsc(io_si, i_cwd) = hio_cwd_ag_in_si_cwdsc(io_si, i_cwd) + & - elflux_diags_c%cwd_ag_input(i_cwd) / days_per_year / sec_per_day - - hio_cwd_bg_in_si_cwdsc(io_si, i_cwd) = hio_cwd_bg_in_si_cwdsc(io_si, i_cwd) + & - elflux_diags_c%cwd_bg_input(i_cwd) / days_per_year / sec_per_day - - end do - - do ft = 1,numpft - this%hvars(ih_recl2fr_canopy_pf)%r82d(io_si,ft) = sites(s)%rec_l2fr(ft,1) - this%hvars(ih_recl2fr_ustory_pf)%r82d(io_si,ft) = sites(s)%rec_l2fr(ft,2) - end do - - enddo siteloop ! site loop - - end associate + do i_cwd = 1, ncwd + hio_cwd_ag_in_si_cwdsc(io_si, i_cwd) = hio_cwd_ag_in_si_cwdsc(io_si, i_cwd) + & + elflux_diags_c%cwd_ag_input(i_cwd) / days_per_year / sec_per_day + + hio_cwd_bg_in_si_cwdsc(io_si, i_cwd) = hio_cwd_bg_in_si_cwdsc(io_si, i_cwd) + & + elflux_diags_c%cwd_bg_input(i_cwd) / days_per_year / sec_per_day + + end do + + do ft = 1,numpft + this%hvars(ih_recl2fr_canopy_pf)%r82d(io_si,ft) = sites(s)%rec_l2fr(ft,1) + this%hvars(ih_recl2fr_ustory_pf)%r82d(io_si,ft) = sites(s)%rec_l2fr(ft,2) + end do + + enddo siteloop ! site loop + + end associate + end associate end associate - end associate - - return - end subroutine update_history_dyn_subsite - - ! ========================================================================================= - - subroutine update_history_dyn_subsite_ageclass(this,nc,nsites,sites) - - ! --------------------------------------------------------------------------------- - ! This subroutine is intended to update all history variables with upfreq == - ! group_dyna_complx that have a dimension in addition to that for the site level - ! which DO include age class. So, eg., FATES_VEGC_APPF is updated here, - ! but not FATES_VEGC or FATES_VEGC_PF. - ! --------------------------------------------------------------------------------- - - ! 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(fates_cohort_type), pointer :: ccohort - type(fates_patch_type), pointer :: cpatch - integer :: s, ft, iagepft, i_agefuel, iscag, iscagpft, i_fuel, i_scls, io_si - integer :: iscag_anthrodist ! what is the equivalent age class for - ! time-since-anthropogenic-disturbance of secondary forest - real(r8) :: mort - real(r8) :: sapw_m ! Sapwood mass (elemental, c,n or p) [kg/plant] - real(r8) :: struct_m ! Structural mass "" - real(r8) :: leaf_m ! Leaf mass "" - real(r8) :: fnrt_m ! Fineroot mass "" - real(r8) :: store_m ! Storage mass "" - real(r8) :: alive_m ! Alive biomass (sap+leaf+fineroot+repro+storage) "" - real(r8) :: total_m ! Total vegetation mass - real(r8) :: repro_m ! Total reproductive mass (on plant) "" - real(r8) :: patch_area_div_site_area ! Weighting based on patch area relative to site area - real(r8) :: patch_canarea_div_site_area ! Weighting based on patch canopy area relative to site area - real(r8) :: cohort_n_div_site_area ! Weighting based on cohort density relative to site area - - associate( & + + return + end subroutine update_history_dyn_subsite + + ! ========================================================================================= + + subroutine update_history_dyn_subsite_ageclass(this,nc,nsites,sites) + + ! --------------------------------------------------------------------------------- + ! This subroutine is intended to update all history variables with upfreq == + ! group_dyna_complx that have a dimension in addition to that for the site level + ! which DO include age class. So, eg., FATES_VEGC_APPF is updated here, + ! but not FATES_VEGC or FATES_VEGC_PF. + ! --------------------------------------------------------------------------------- + + ! 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(fates_cohort_type), pointer :: ccohort + type(fates_patch_type), pointer :: cpatch + integer :: s, ft, iagepft, i_agefuel, iscag, iscagpft, i_fuel, i_scls, io_si + integer :: iscag_anthrodist ! what is the equivalent age class for + ! time-since-anthropogenic-disturbance of secondary forest + real(r8) :: mort + real(r8) :: sapw_m ! Sapwood mass (elemental, c,n or p) [kg/plant] + real(r8) :: struct_m ! Structural mass "" + real(r8) :: leaf_m ! Leaf mass "" + real(r8) :: fnrt_m ! Fineroot mass "" + real(r8) :: store_m ! Storage mass "" + real(r8) :: alive_m ! Alive biomass (sap+leaf+fineroot+repro+storage) "" + real(r8) :: total_m ! Total vegetation mass + real(r8) :: repro_m ! Total reproductive mass (on plant) "" + real(r8) :: patch_area_div_site_area ! Weighting based on patch area relative to site area + real(r8) :: patch_canarea_div_site_area ! Weighting based on patch canopy area relative to site area + real(r8) :: cohort_n_div_site_area ! Weighting based on cohort density relative to site area + + associate( & hio_lai_si_age => this%hvars(ih_lai_si_age)%r82d, & hio_ncl_si_age => this%hvars(ih_ncl_si_age)%r82d, & hio_scorch_height_si_agepft => this%hvars(ih_scorch_height_si_agepft)%r82d, & @@ -4813,359 +4823,359 @@ subroutine update_history_dyn_subsite_ageclass(this,nc,nsites,sites) hio_secondarylands_fracarea_si_age => this%hvars(ih_secondarylands_fracarea_si_age)%r82d, & hio_ddbh_understory_si_scag => this%hvars(ih_ddbh_understory_si_scag)%r82d) - siteloop: do s = 1,nsites - io_si = sites(s)%h_gid - - ! Loop through patches to sum up diagnostics - cpatch => sites(s)%oldest_patch - patchloop: do while(associated(cpatch)) - cpatch%age_class = get_age_class_index(cpatch%age) - patch_area_div_site_area = cpatch%area * AREA_INV - patch_canarea_div_site_area = cpatch%total_canopy_area * AREA_INV - - !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !!! Weighting by (or using) patch area relative to total site area !!! - !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - ! Increment the fractional area in each age class bin - hio_fracarea_si_age(io_si,cpatch%age_class) = hio_fracarea_si_age(io_si,cpatch%age_class) & - + cpatch%area * AREA_INV - - do ft = 1,numpft - iagepft = get_agepft_class_index(cpatch%age,ft) - hio_scorch_height_si_agepft(io_si,iagepft) = hio_scorch_height_si_agepft(io_si,iagepft) + & - cpatch%Scorch_ht(ft) * patch_area_div_site_area - end do - - hio_ncl_si_age(io_si,cpatch%age_class) = hio_ncl_si_age(io_si,cpatch%age_class) & - + cpatch%ncl_p * patch_area_div_site_area - - hio_fracarea_burnt_si_age(io_si,cpatch%age_class) = hio_fracarea_burnt_si_age(io_si,cpatch%age_class) + & - cpatch%frac_burnt / sec_per_day & ! [frac/day] -> [frac/sec] - * patch_area_div_site_area - - hio_rx_fracarea_burnt_si_age(io_si,cpatch%age_class) = hio_rx_fracarea_burnt_si_age(io_si,cpatch%age_class) + & - cpatch%rx_frac_burnt / sec_per_day & ! [frac/day] -> [frac/sec] - * patch_area_div_site_area - - hio_nonrx_fracarea_burnt_si_age(io_si,cpatch%age_class) = hio_nonrx_fracarea_burnt_si_age(io_si,cpatch%age_class) + & - cpatch%nonrx_frac_burnt / sec_per_day & ! [frac/day] -> [frac/sec] - * patch_area_div_site_area - - hio_fire_sum_fuel_si_age(io_si, cpatch%age_class) = hio_fire_sum_fuel_si_age(io_si, cpatch%age_class) + & - cpatch%fuel%non_trunk_loading * patch_area_div_site_area - do i_fuel = 1,num_fuel_classes - i_agefuel = get_agefuel_class_index(cpatch%age,i_fuel) - hio_fuel_amount_si_agfc(io_si,i_agefuel) = hio_fuel_amount_si_agfc(io_si,i_agefuel) + & - cpatch%fuel%frac_loading(i_fuel) * cpatch%fuel%non_trunk_loading * patch_area_div_site_area - end do - - ! only valid when "strict ppa" enabled - if ( comp_excln_exp .lt. 0._r8 ) then - hio_zstar_si_age(io_si,cpatch%age_class) = hio_zstar_si_age(io_si,cpatch%age_class) & - + cpatch%zstar * patch_area_div_site_area - end if - - ! some diagnostics on secondary forest area and its age distribution - if ( cpatch%land_use_label .eq. secondaryland ) then - - iscag_anthrodist = get_age_class_index(cpatch%age_since_anthro_disturbance) - - hio_agesince_anthrodist_si_age(io_si,iscag_anthrodist) = & - hio_agesince_anthrodist_si_age(io_si,iscag_anthrodist) & - + patch_area_div_site_area - - hio_secondarylands_fracarea_si_age(io_si,cpatch%age_class) = & - hio_secondarylands_fracarea_si_age(io_si,cpatch%age_class) & - + patch_area_div_site_area - else if ( cpatch%land_use_label .eq. primaryland) then - hio_primarylands_fracarea_si_age(io_si,cpatch%age_class) = & - hio_primarylands_fracarea_si_age(io_si,cpatch%age_class) & - + patch_area_div_site_area - endif - - !!!!!!!!!!!!!!!!!!!!!!! - !!! Other weighting !!! - !!!!!!!!!!!!!!!!!!!!!!! - - ! LAI is weighted by patch canopy area relative to total site area---NOT site CANOPY - ! area---because bare ground is included in LAI calculation. - hio_lai_si_age(io_si,cpatch%age_class) = hio_lai_si_age(io_si,cpatch%age_class) & - + sum(cpatch%tlai_profile(:,:,:) * cpatch%canopy_area_profile(:,:,:) ) & - * patch_canarea_div_site_area - - ! These fire variables are intended to be weighted by fire area. However, for precision - ! reasons, we don't divide by site-wide burned area here. Instead, in the long_name of - ! the history file variable, we tell the users to do that division themselves. - hio_fire_intensity_si_age(io_si, cpatch%age_class) = hio_fire_intensity_si_age(io_si,cpatch%age_class) + & - cpatch%FI * J_per_kJ & ! [kJ/m/s] -> [J/m/s] - * cpatch%frac_burnt * patch_area_div_site_area - ! hio_fire_rate_of_spread_front_si_age(io_si, cpatch%age_class) = hio_fire_rate_of_spread_si_age(io_si, cpatch%age_class) + & - ! cpatch%ros_front * cpatch*frac_burnt * patch_area_div_site_area - - hio_rx_intensity_si_age(io_si, cpatch%age_class) = hio_rx_intensity_si_age(io_si, cpatch%age_class) + & - cpatch%rx_FI * J_per_kJ & ! [kJ/m/s] -> [J/m/s] - * cpatch%rx_frac_burnt * patch_area_div_site_area - - hio_nonrx_intensity_si_age(io_si, cpatch%age_class) = hio_nonrx_intensity_si_age(io_si, cpatch%age_class) + & - cpatch%nonrx_FI * J_per_kJ & ! [kJ/m/s] -> [J/m/s] - * cpatch%nonrx_frac_burnt * patch_area_div_site_area - - ! Weighted by cohort canopy area relative to site area - ccohort => cpatch%shortest - cohortloop: do while(associated(ccohort)) - cohort_n_div_site_area = ccohort%n * AREA_INV - - hio_canopy_fracarea_si_age(io_si,cpatch%age_class) = hio_canopy_fracarea_si_age(io_si,cpatch%age_class) & - + ccohort%c_area * AREA_INV - - notnew: if( .not.(ccohort%isnew) ) then - hio_npp_si_age(io_si,cpatch%age_class) = hio_npp_si_age(io_si,cpatch%age_class) & - + ccohort%npp_acc_hold / days_per_year / sec_per_day & - * cohort_n_div_site_area - end if notnew - - ccohort => ccohort%taller - end do cohortloop - - ! Not weighted - hio_npatches_si_age(io_si,cpatch%age_class) = hio_npatches_si_age(io_si,cpatch%age_class) + 1._r8 - - cpatch => cpatch%younger - end do patchloop - - !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !!! Weighting by cohort stem density relative to total site area !!! - !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - ! Loop through patches to sum up diagnostics - cpatch => sites(s)%oldest_patch - patchloop2: do while(associated(cpatch)) - cpatch%age_class = get_age_class_index(cpatch%age) - - ! Loop through cohorts on patch - ccohort => cpatch%shortest - cohortloop2: do while(associated(ccohort)) - - ! If you SUM across all age classes, you should get the mean site value. - cohort_n_div_site_area = ccohort%n * AREA_INV - - iscag = get_sizeage_class_index(ccohort%dbh, cpatch%age) - iagepft = get_agepft_class_index(cpatch%age,ccohort%pft) - iscagpft = get_sizeagepft_class_index(ccohort%dbh,cpatch%age,ccohort%pft) - - ! Biomass - call ccohort%prt%GetBiomass(carbon12_element, & - sapw_m, struct_m, leaf_m, fnrt_m, store_m, repro_m, alive_m, total_m) - hio_biomass_si_age(io_si,cpatch%age_class) = hio_biomass_si_age(io_si,cpatch%age_class) & - + total_m * cohort_n_div_site_area - hio_biomass_si_agepft(io_si,iagepft) = hio_biomass_si_agepft(io_si,iagepft) & - + total_m * cohort_n_div_site_area - - if (.not. (ccohort%isnew)) then - hio_npp_si_agepft(io_si,iagepft) = hio_npp_si_agepft(io_si,iagepft) + & - ccohort%npp_acc_hold / days_per_year / sec_per_day & ! [kgC/indiv/yr] -> [kgC/s] - * cohort_n_div_site_area - hio_nplant_si_scag(io_si,iscag) = hio_nplant_si_scag(io_si,iscag) + cohort_n_div_site_area - hio_nplant_si_scagpft(io_si,iscagpft) = hio_nplant_si_scagpft(io_si,iscagpft) + cohort_n_div_site_area - - ! Canopy vs. understory variables - mort = ccohort%SumMortForHistory(per_year = .true.) - if (ccohort%canopy_layer .eq. 1) then - hio_mortality_canopy_si_scag(io_si,iscag) = hio_mortality_canopy_si_scag(io_si,iscag) + & - mort * cohort_n_div_site_area - hio_ddbh_canopy_si_scag(io_si,iscag) = hio_ddbh_canopy_si_scag(io_si,iscag) + & - ccohort%ddbhdt * m_per_cm & ! [m] -> [cm] + siteloop: do s = 1,nsites + io_si = sites(s)%h_gid + + ! Loop through patches to sum up diagnostics + cpatch => sites(s)%oldest_patch + patchloop: do while(associated(cpatch)) + cpatch%age_class = get_age_class_index(cpatch%age) + patch_area_div_site_area = cpatch%area * AREA_INV + patch_canarea_div_site_area = cpatch%total_canopy_area * AREA_INV + + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !!! Weighting by (or using) patch area relative to total site area !!! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + ! Increment the fractional area in each age class bin + hio_fracarea_si_age(io_si,cpatch%age_class) = hio_fracarea_si_age(io_si,cpatch%age_class) & + + cpatch%area * AREA_INV + + do ft = 1,numpft + iagepft = get_agepft_class_index(cpatch%age,ft) + hio_scorch_height_si_agepft(io_si,iagepft) = hio_scorch_height_si_agepft(io_si,iagepft) + & + cpatch%Scorch_ht(ft) * patch_area_div_site_area + end do + + hio_ncl_si_age(io_si,cpatch%age_class) = hio_ncl_si_age(io_si,cpatch%age_class) & + + cpatch%ncl_p * patch_area_div_site_area + + hio_fracarea_burnt_si_age(io_si,cpatch%age_class) = hio_fracarea_burnt_si_age(io_si,cpatch%age_class) + & + cpatch%frac_burnt / sec_per_day & ! [frac/day] -> [frac/sec] + * patch_area_div_site_area + + hio_rx_fracarea_burnt_si_age(io_si,cpatch%age_class) = hio_rx_fracarea_burnt_si_age(io_si,cpatch%age_class) + & + cpatch%rx_frac_burnt / sec_per_day & ! [frac/day] -> [frac/sec] + * patch_area_div_site_area + + hio_nonrx_fracarea_burnt_si_age(io_si,cpatch%age_class) = hio_nonrx_fracarea_burnt_si_age(io_si,cpatch%age_class) + & + cpatch%nonrx_frac_burnt / sec_per_day & ! [frac/day] -> [frac/sec] + * patch_area_div_site_area + + hio_fire_sum_fuel_si_age(io_si, cpatch%age_class) = hio_fire_sum_fuel_si_age(io_si, cpatch%age_class) + & + cpatch%fuel%non_trunk_loading * patch_area_div_site_area + do i_fuel = 1,num_fuel_classes + i_agefuel = get_agefuel_class_index(cpatch%age,i_fuel) + hio_fuel_amount_si_agfc(io_si,i_agefuel) = hio_fuel_amount_si_agfc(io_si,i_agefuel) + & + cpatch%fuel%frac_loading(i_fuel) * cpatch%fuel%non_trunk_loading * patch_area_div_site_area + end do + + ! only valid when "strict ppa" enabled + if ( comp_excln_exp .lt. 0._r8 ) then + hio_zstar_si_age(io_si,cpatch%age_class) = hio_zstar_si_age(io_si,cpatch%age_class) & + + cpatch%zstar * patch_area_div_site_area + end if + + ! some diagnostics on secondary forest area and its age distribution + if ( cpatch%land_use_label .eq. secondaryland ) then + + iscag_anthrodist = get_age_class_index(cpatch%age_since_anthro_disturbance) + + hio_agesince_anthrodist_si_age(io_si,iscag_anthrodist) = & + hio_agesince_anthrodist_si_age(io_si,iscag_anthrodist) & + + patch_area_div_site_area + + hio_secondarylands_fracarea_si_age(io_si,cpatch%age_class) = & + hio_secondarylands_fracarea_si_age(io_si,cpatch%age_class) & + + patch_area_div_site_area + else if ( cpatch%land_use_label .eq. primaryland) then + hio_primarylands_fracarea_si_age(io_si,cpatch%age_class) = & + hio_primarylands_fracarea_si_age(io_si,cpatch%age_class) & + + patch_area_div_site_area + endif + + !!!!!!!!!!!!!!!!!!!!!!! + !!! Other weighting !!! + !!!!!!!!!!!!!!!!!!!!!!! + + ! LAI is weighted by patch canopy area relative to total site area---NOT site CANOPY + ! area---because bare ground is included in LAI calculation. + hio_lai_si_age(io_si,cpatch%age_class) = hio_lai_si_age(io_si,cpatch%age_class) & + + sum(cpatch%tlai_profile(:,:,:) * cpatch%canopy_area_profile(:,:,:) ) & + * patch_canarea_div_site_area + + ! These fire variables are intended to be weighted by fire area. However, for precision + ! reasons, we don't divide by site-wide burned area here. Instead, in the long_name of + ! the history file variable, we tell the users to do that division themselves. + hio_fire_intensity_si_age(io_si, cpatch%age_class) = hio_fire_intensity_si_age(io_si,cpatch%age_class) + & + cpatch%FI * J_per_kJ & ! [kJ/m/s] -> [J/m/s] + * cpatch%frac_burnt * patch_area_div_site_area + ! hio_fire_rate_of_spread_front_si_age(io_si, cpatch%age_class) = hio_fire_rate_of_spread_si_age(io_si, cpatch%age_class) + & + ! cpatch%ros_front * cpatch*frac_burnt * patch_area_div_site_area + + hio_rx_intensity_si_age(io_si, cpatch%age_class) = hio_rx_intensity_si_age(io_si, cpatch%age_class) + & + cpatch%rx_FI * J_per_kJ & ! [kJ/m/s] -> [J/m/s] + * cpatch%rx_frac_burnt * patch_area_div_site_area + + hio_nonrx_intensity_si_age(io_si, cpatch%age_class) = hio_nonrx_intensity_si_age(io_si, cpatch%age_class) + & + cpatch%nonrx_FI * J_per_kJ & ! [kJ/m/s] -> [J/m/s] + * cpatch%nonrx_frac_burnt * patch_area_div_site_area + + ! Weighted by cohort canopy area relative to site area + ccohort => cpatch%shortest + cohortloop: do while(associated(ccohort)) + cohort_n_div_site_area = ccohort%n * AREA_INV + + hio_canopy_fracarea_si_age(io_si,cpatch%age_class) = hio_canopy_fracarea_si_age(io_si,cpatch%age_class) & + + ccohort%c_area * AREA_INV + + notnew: if( .not.(ccohort%isnew) ) then + hio_npp_si_age(io_si,cpatch%age_class) = hio_npp_si_age(io_si,cpatch%age_class) & + + ccohort%npp_acc_hold / days_per_year / sec_per_day & * cohort_n_div_site_area - hio_nplant_canopy_si_scag(io_si,iscag) = hio_nplant_canopy_si_scag(io_si,iscag) + cohort_n_div_site_area - else - hio_mortality_understory_si_scag(io_si,iscag) = hio_mortality_understory_si_scag(io_si, iscag) + & - mort * cohort_n_div_site_area - hio_ddbh_understory_si_scag(io_si,iscag) = hio_ddbh_understory_si_scag(io_si,iscag) + & - ccohort%ddbhdt * m_per_cm & ! [m] -> [cm] + end if notnew + + ccohort => ccohort%taller + end do cohortloop + + ! Not weighted + hio_npatches_si_age(io_si,cpatch%age_class) = hio_npatches_si_age(io_si,cpatch%age_class) + 1._r8 + + cpatch => cpatch%younger + end do patchloop + + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !!! Weighting by cohort stem density relative to total site area !!! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + ! Loop through patches to sum up diagnostics + cpatch => sites(s)%oldest_patch + patchloop2: do while(associated(cpatch)) + cpatch%age_class = get_age_class_index(cpatch%age) + + ! Loop through cohorts on patch + ccohort => cpatch%shortest + cohortloop2: do while(associated(ccohort)) + + ! If you SUM across all age classes, you should get the mean site value. + cohort_n_div_site_area = ccohort%n * AREA_INV + + iscag = get_sizeage_class_index(ccohort%dbh, cpatch%age) + iagepft = get_agepft_class_index(cpatch%age,ccohort%pft) + iscagpft = get_sizeagepft_class_index(ccohort%dbh,cpatch%age,ccohort%pft) + + ! Biomass + call ccohort%prt%GetBiomass(carbon12_element, & + sapw_m, struct_m, leaf_m, fnrt_m, store_m, repro_m, alive_m, total_m) + hio_biomass_si_age(io_si,cpatch%age_class) = hio_biomass_si_age(io_si,cpatch%age_class) & + + total_m * cohort_n_div_site_area + hio_biomass_si_agepft(io_si,iagepft) = hio_biomass_si_agepft(io_si,iagepft) & + + total_m * cohort_n_div_site_area + + if (.not. (ccohort%isnew)) then + hio_npp_si_agepft(io_si,iagepft) = hio_npp_si_agepft(io_si,iagepft) + & + ccohort%npp_acc_hold / days_per_year / sec_per_day & ! [kgC/indiv/yr] -> [kgC/s] * cohort_n_div_site_area - hio_nplant_understory_si_scag(io_si,iscag) = hio_nplant_understory_si_scag(io_si,iscag) + cohort_n_div_site_area - end if ! canopy layer? - end if ! cohort is new? - - ccohort => ccohort%taller - end do cohortloop2 - - cpatch => cpatch%younger - end do patchloop2 - - ! The mortality components in this loop already include cohort density (cohort%n), so they - ! don't use cohort_n_div_site_area. - do ft = 1, numpft - do i_scls = 1,nlevsclass - - ! since imort and fmort by definition something only happens in newly disturbed patches, - ! treat as such - iscag = i_scls - - ! add imort to other mortality terms. consider imort as understory mortality even if it happens in - ! cohorts that may have been promoted as part of the patch creation, and use the pre-calculated site-level - ! values to avoid biasing the results by the dramatically-reduced number densities in cohorts that are subject to imort - hio_mortality_understory_si_scag(io_si,iscag) = hio_mortality_understory_si_scag(io_si,iscag) + & - sites(s)%imort_rate(i_scls, ft) * AREA_INV - - ! add fire mortality to other mortality terms - hio_mortality_canopy_si_scag(io_si,iscag) = hio_mortality_canopy_si_scag(io_si,iscag) + & - sites(s)%fmort_rate_canopy(i_scls, ft) * AREA_INV - hio_mortality_understory_si_scag(io_si,iscag) = hio_mortality_understory_si_scag(io_si,iscag) + & - sites(s)%fmort_rate_ustory(i_scls, ft) * AREA_INV - - ! add termination mortality to other mortality terms - hio_mortality_canopy_si_scag(io_si,iscag) = hio_mortality_canopy_si_scag(io_si,iscag) + & - sum(sites(s)%term_nindivs_canopy(:,i_scls,ft)) * days_per_year * AREA_INV - hio_mortality_understory_si_scag(io_si,iscag) = hio_mortality_understory_si_scag(io_si,iscag) + & - sum(sites(s)%term_nindivs_ustory(:,i_scls,ft)) * days_per_year * AREA_INV - - end do ! size class loop - end do ! pft loop - end do siteloop - - end associate - end subroutine update_history_dyn_subsite_ageclass - - ! =============================================================================================== - - subroutine reset_history_dyn_subsite(this, nsites, sites) - - ! ------------------------------------------------------------------------------------ - ! This resets some variables that need to be zeroed out after dyn2 history subroutines - ! ------------------------------------------------------------------------------------ - ! - ! Arguments - class(fates_history_interface_type) :: this - integer , intent(in) :: nsites - type(ed_site_type), intent(inout), target :: sites(nsites) - ! - ! Local variables - integer :: s - - siteloop: do s = 1,nsites - - sites(s)%term_nindivs_canopy(:,:,:) = 0._r8 - sites(s)%term_nindivs_ustory(:,:,:) = 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_rate_cambial(:,:) = 0._r8 - sites(s)%fmort_rate_crown(:,:) = 0._r8 - - sites(s)%nonrx_fmort_rate_canopy(:,:) = 0._r8 - sites(s)%nonrx_fmort_rate_ustory(:,:) = 0._r8 - sites(s)%nonrx_fmort_carbonflux_canopy(:) = 0._r8 - sites(s)%nonrx_fmort_carbonflux_ustory(:) = 0._r8 - sites(s)%nonrx_fmort_rate_cambial(:,:) = 0._r8 - sites(s)%nonrx_fmort_rate_crown(:,:) = 0._r8 - sites(s)%nonrx_fmort_abg_flux(:,:) = 0._r8 - sites(s)%rx_fmort_rate_canopy(:,:) = 0._r8 - sites(s)%rx_fmort_rate_ustory(:,:) = 0._r8 - sites(s)%rx_fmort_carbonflux_canopy(:) = 0._r8 - sites(s)%rx_fmort_carbonflux_ustory(:) = 0._r8 - sites(s)%rx_fmort_rate_cambial(:,:) = 0._r8 - sites(s)%rx_fmort_rate_crown(:,:) = 0._r8 - sites(s)%rx_fmort_abg_flux(:,:) = 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)%nonrx_fmort_rate_canopy_damage(:,:,:) = 0._r8 - sites(s)%nonrx_fmort_rate_ustory_damage(:,:,:) = 0._r8 - sites(s)%nonrx_fmort_cflux_canopy_damage(:,:) = 0._r8 - sites(s)%nonrx_fmort_cflux_ustory_damage(:,:) = 0._r8 - sites(s)%rx_fmort_rate_canopy_damage(:,:,:) = 0._r8 - sites(s)%rx_fmort_rate_ustory_damage(:,:,:) = 0._r8 - sites(s)%rx_fmort_cflux_canopy_damage(:,:) = 0._r8 - sites(s)%rx_fmort_cflux_ustory_damage(:,:) = 0._r8 - - end do siteloop - end subroutine reset_history_dyn_subsite - - ! =============================================================================================== - - subroutine update_history_hifrq(this,nc,nsites,sites,bc_in,bc_out,dt_tstep) - - ! --------------------------------------------------------------------------------- - ! This is the call to update the history IO arrays that are expected to only change - ! at the model time-step frequency. - ! This is the general routine that will call the single or multi-dimensional - ! routines if they are called for by the user - ! --------------------------------------------------------------------------------- - ! - ! 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) - type(bc_out_type) , intent(in) :: bc_out(nsites) - real(r8) , intent(in) :: dt_tstep - - if(hlm_hist_level_hifrq>0) then - call update_history_hifrq_sitelevel(this,nc,nsites,sites,bc_in,dt_tstep) - if(hlm_hist_level_hifrq>1) then - call update_history_hifrq_subsite(this,nc,nsites,sites,bc_in,dt_tstep) - call update_history_hifrq_subsite_ageclass(this,nsites,sites,dt_tstep) - end if - end if - - - return - end subroutine update_history_hifrq - - subroutine update_history_hifrq_sitelevel(this,nc,nsites,sites,bc_in,dt_tstep) - - ! --------------------------------------------------------------------------------- - ! This subroutine is intended to update all history variables with upfreq == - ! group_hifrq_simple: i.e., those that are saved at the site level. So, eg., - ! FATES_GPP is updated here, but not FATES_GPP_AP. - ! --------------------------------------------------------------------------------- - - ! - ! 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) - real(r8) , intent(in) :: dt_tstep - - ! Locals - integer :: s ! The local site index - integer :: io_si ! The site index of the IO array - integer :: age_class ! class age index - real(r8) :: site_area_veg_inv ! inverse canopy area of the site (1/m2) - real(r8) :: site_area_rad_inv ! inverse canopy area of site for only - ! patches that called the solver - real(r8) :: dt_tstep_inv ! inverse timestep (1/sec) - real(r8) :: n_perm2 ! number of plants per square meter - real(r8) :: sum_area_rad ! sum of patch canopy areas - real(r8),allocatable :: age_area_rad(:) - - type(fates_patch_type),pointer :: cpatch - type(fates_cohort_type),pointer :: ccohort - - - associate( hio_gpp_si => this%hvars(ih_gpp_si)%r81d, & + hio_nplant_si_scag(io_si,iscag) = hio_nplant_si_scag(io_si,iscag) + cohort_n_div_site_area + hio_nplant_si_scagpft(io_si,iscagpft) = hio_nplant_si_scagpft(io_si,iscagpft) + cohort_n_div_site_area + + ! Canopy vs. understory variables + mort = ccohort%SumMortForHistory(per_year = .true.) + if (ccohort%canopy_layer .eq. 1) then + hio_mortality_canopy_si_scag(io_si,iscag) = hio_mortality_canopy_si_scag(io_si,iscag) + & + mort * cohort_n_div_site_area + hio_ddbh_canopy_si_scag(io_si,iscag) = hio_ddbh_canopy_si_scag(io_si,iscag) + & + ccohort%ddbhdt * m_per_cm & ! [m] -> [cm] + * cohort_n_div_site_area + hio_nplant_canopy_si_scag(io_si,iscag) = hio_nplant_canopy_si_scag(io_si,iscag) + cohort_n_div_site_area + else + hio_mortality_understory_si_scag(io_si,iscag) = hio_mortality_understory_si_scag(io_si, iscag) + & + mort * cohort_n_div_site_area + hio_ddbh_understory_si_scag(io_si,iscag) = hio_ddbh_understory_si_scag(io_si,iscag) + & + ccohort%ddbhdt * m_per_cm & ! [m] -> [cm] + * cohort_n_div_site_area + hio_nplant_understory_si_scag(io_si,iscag) = hio_nplant_understory_si_scag(io_si,iscag) + cohort_n_div_site_area + end if ! canopy layer? + end if ! cohort is new? + + ccohort => ccohort%taller + end do cohortloop2 + + cpatch => cpatch%younger + end do patchloop2 + + ! The mortality components in this loop already include cohort density (cohort%n), so they + ! don't use cohort_n_div_site_area. + do ft = 1, numpft + do i_scls = 1,nlevsclass + + ! since imort and fmort by definition something only happens in newly disturbed patches, + ! treat as such + iscag = i_scls + + ! add imort to other mortality terms. consider imort as understory mortality even if it happens in + ! cohorts that may have been promoted as part of the patch creation, and use the pre-calculated site-level + ! values to avoid biasing the results by the dramatically-reduced number densities in cohorts that are subject to imort + hio_mortality_understory_si_scag(io_si,iscag) = hio_mortality_understory_si_scag(io_si,iscag) + & + sites(s)%imort_rate(i_scls, ft) * AREA_INV + + ! add fire mortality to other mortality terms + hio_mortality_canopy_si_scag(io_si,iscag) = hio_mortality_canopy_si_scag(io_si,iscag) + & + sites(s)%fmort_rate_canopy(i_scls, ft) * AREA_INV + hio_mortality_understory_si_scag(io_si,iscag) = hio_mortality_understory_si_scag(io_si,iscag) + & + sites(s)%fmort_rate_ustory(i_scls, ft) * AREA_INV + + ! add termination mortality to other mortality terms + hio_mortality_canopy_si_scag(io_si,iscag) = hio_mortality_canopy_si_scag(io_si,iscag) + & + sum(sites(s)%term_nindivs_canopy(:,i_scls,ft)) * days_per_year * AREA_INV + hio_mortality_understory_si_scag(io_si,iscag) = hio_mortality_understory_si_scag(io_si,iscag) + & + sum(sites(s)%term_nindivs_ustory(:,i_scls,ft)) * days_per_year * AREA_INV + + end do ! size class loop + end do ! pft loop + end do siteloop + + end associate + end subroutine update_history_dyn_subsite_ageclass + + ! =============================================================================================== + + subroutine reset_history_dyn_subsite(this, nsites, sites) + + ! ------------------------------------------------------------------------------------ + ! This resets some variables that need to be zeroed out after dyn2 history subroutines + ! ------------------------------------------------------------------------------------ + ! + ! Arguments + class(fates_history_interface_type) :: this + integer , intent(in) :: nsites + type(ed_site_type), intent(inout), target :: sites(nsites) + ! + ! Local variables + integer :: s + + siteloop: do s = 1,nsites + + sites(s)%term_nindivs_canopy(:,:,:) = 0._r8 + sites(s)%term_nindivs_ustory(:,:,:) = 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_rate_cambial(:,:) = 0._r8 + sites(s)%fmort_rate_crown(:,:) = 0._r8 + + sites(s)%nonrx_fmort_rate_canopy(:,:) = 0._r8 + sites(s)%nonrx_fmort_rate_ustory(:,:) = 0._r8 + sites(s)%nonrx_fmort_carbonflux_canopy(:) = 0._r8 + sites(s)%nonrx_fmort_carbonflux_ustory(:) = 0._r8 + sites(s)%nonrx_fmort_rate_cambial(:,:) = 0._r8 + sites(s)%nonrx_fmort_rate_crown(:,:) = 0._r8 + sites(s)%nonrx_fmort_abg_flux(:,:) = 0._r8 + sites(s)%rx_fmort_rate_canopy(:,:) = 0._r8 + sites(s)%rx_fmort_rate_ustory(:,:) = 0._r8 + sites(s)%rx_fmort_carbonflux_canopy(:) = 0._r8 + sites(s)%rx_fmort_carbonflux_ustory(:) = 0._r8 + sites(s)%rx_fmort_rate_cambial(:,:) = 0._r8 + sites(s)%rx_fmort_rate_crown(:,:) = 0._r8 + sites(s)%rx_fmort_abg_flux(:,:) = 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)%nonrx_fmort_rate_canopy_damage(:,:,:) = 0._r8 + sites(s)%nonrx_fmort_rate_ustory_damage(:,:,:) = 0._r8 + sites(s)%nonrx_fmort_cflux_canopy_damage(:,:) = 0._r8 + sites(s)%nonrx_fmort_cflux_ustory_damage(:,:) = 0._r8 + sites(s)%rx_fmort_rate_canopy_damage(:,:,:) = 0._r8 + sites(s)%rx_fmort_rate_ustory_damage(:,:,:) = 0._r8 + sites(s)%rx_fmort_cflux_canopy_damage(:,:) = 0._r8 + sites(s)%rx_fmort_cflux_ustory_damage(:,:) = 0._r8 + + end do siteloop + end subroutine reset_history_dyn_subsite + + ! =============================================================================================== + + subroutine update_history_hifrq(this,nc,nsites,sites,bc_in,bc_out,dt_tstep) + + ! --------------------------------------------------------------------------------- + ! This is the call to update the history IO arrays that are expected to only change + ! at the model time-step frequency. + ! This is the general routine that will call the single or multi-dimensional + ! routines if they are called for by the user + ! --------------------------------------------------------------------------------- + ! + ! 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) + type(bc_out_type) , intent(in) :: bc_out(nsites) + real(r8) , intent(in) :: dt_tstep + + if(hlm_hist_level_hifrq>0) then + call update_history_hifrq_sitelevel(this,nc,nsites,sites,bc_in,dt_tstep) + if(hlm_hist_level_hifrq>1) then + call update_history_hifrq_subsite(this,nc,nsites,sites,bc_in,dt_tstep) + call update_history_hifrq_subsite_ageclass(this,nsites,sites,dt_tstep) + end if + end if + + + return + end subroutine update_history_hifrq + + subroutine update_history_hifrq_sitelevel(this,nc,nsites,sites,bc_in,dt_tstep) + + ! --------------------------------------------------------------------------------- + ! This subroutine is intended to update all history variables with upfreq == + ! group_hifrq_simple: i.e., those that are saved at the site level. So, eg., + ! FATES_GPP is updated here, but not FATES_GPP_AP. + ! --------------------------------------------------------------------------------- + + ! + ! 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) + real(r8) , intent(in) :: dt_tstep + + ! Locals + integer :: s ! The local site index + integer :: io_si ! The site index of the IO array + integer :: age_class ! class age index + real(r8) :: site_area_veg_inv ! inverse canopy area of the site (1/m2) + real(r8) :: site_area_rad_inv ! inverse canopy area of site for only + ! patches that called the solver + real(r8) :: dt_tstep_inv ! inverse timestep (1/sec) + real(r8) :: n_perm2 ! number of plants per square meter + real(r8) :: sum_area_rad ! sum of patch canopy areas + real(r8),allocatable :: age_area_rad(:) + + type(fates_patch_type),pointer :: cpatch + type(fates_cohort_type),pointer :: ccohort + + + associate( hio_gpp_si => this%hvars(ih_gpp_si)%r81d, & hio_npp_si => this%hvars(ih_npp_si)%r81d, & hio_aresp_si => this%hvars(ih_aresp_si)%r81d, & hio_maint_resp_si => this%hvars(ih_maint_resp_si)%r81d, & @@ -5188,216 +5198,216 @@ subroutine update_history_hifrq_sitelevel(this,nc,nsites,sites,bc_in,dt_tstep) hio_tveg => this%hvars(ih_tveg_si)%r81d) - ! THIS CAN BE REMOVED WHEN BOTH CTSM AND E3SM CALL FLUSH_ALL_HVARS - ! THIS IS NOT A LIABILITY, IT IS JUST REDUNDANT - call this%flush_hvars(nc,upfreq_in=group_hifr_simple) - - dt_tstep_inv = 1.0_r8/dt_tstep + ! THIS CAN BE REMOVED WHEN BOTH CTSM AND E3SM CALL FLUSH_ALL_HVARS + ! THIS IS NOT A LIABILITY, IT IS JUST REDUNDANT + call this%flush_hvars(nc,upfreq_in=group_hifr_simple) - allocate(age_area_rad(size(ED_val_history_ageclass_bin_edges,1)+1)) + dt_tstep_inv = 1.0_r8/dt_tstep - do_sites: do s = 1,nsites + allocate(age_area_rad(size(ED_val_history_ageclass_bin_edges,1)+1)) - call this%zero_site_hvars(sites(s), upfreq_in=group_hifr_simple) + do_sites: do s = 1,nsites - io_si = sites(s)%h_gid + call this%zero_site_hvars(sites(s), upfreq_in=group_hifr_simple) - 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 + io_si = sites(s)%h_gid - ! Diagnostics that are only incremented if we called the radiation solver - ! We do not call the radiation solver if - ! a) there is no vegetation - ! b) there is no light! (ie cos(zenith) ~= 0) - ! c) the "do albedo" flag is true...but, this - ! may be false in coupled runs on alternate time-steps - ! and it is ok to carry over the previous errors - ! and diagnostics between these steps - - age_area_rad(:) = 0._r8 - cpatch => sites(s)%oldest_patch - do while(associated(cpatch)) - ! We initialize the solver error to the ignore value - ! in the radiation driver. It is only modified if the - ! solver was called. The solver will be called for NIR - ! if VIS is called, and likewise the same for conservation - ! error. So the check on VIS solve error will catch all. - if( abs(cpatch%rad_error(ivis)-hlm_hio_ignore_val)>nearzero ) then - age_class = get_age_class_index(cpatch%age) - age_area_rad(age_class) = age_area_rad(age_class) + cpatch%total_canopy_area - end if - cpatch => cpatch%younger - end do + 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 - sum_area_rad = sum(age_area_rad(:)) + ! Diagnostics that are only incremented if we called the radiation solver + ! We do not call the radiation solver if + ! a) there is no vegetation + ! b) there is no light! (ie cos(zenith) ~= 0) + ! c) the "do albedo" flag is true...but, this + ! may be false in coupled runs on alternate time-steps + ! and it is ok to carry over the previous errors + ! and diagnostics between these steps - if_anyrad: if(sum_area_rad < nearzero .or. & - sites(s)%coszen < nearzero ) then - hio_vis_rad_err_si(io_si) = hlm_hio_ignore_val - hio_nir_rad_err_si(io_si) = hlm_hio_ignore_val - else - hio_vis_rad_err_si(io_si) = 0._r8 - hio_nir_rad_err_si(io_si) = 0._r8 + age_area_rad(:) = 0._r8 cpatch => sites(s)%oldest_patch do while(associated(cpatch)) + ! We initialize the solver error to the ignore value + ! in the radiation driver. It is only modified if the + ! solver was called. The solver will be called for NIR + ! if VIS is called, and likewise the same for conservation + ! error. So the check on VIS solve error will catch all. if( abs(cpatch%rad_error(ivis)-hlm_hio_ignore_val)>nearzero ) then - - hio_vis_rad_err_si(io_si) = hio_vis_rad_err_si(io_si) + & - cpatch%rad_error(ivis)*cpatch%total_canopy_area/sum_area_rad - hio_nir_rad_err_si(io_si) = hio_nir_rad_err_si(io_si) + & - cpatch%rad_error(inir)*cpatch%total_canopy_area/sum_area_rad - + age_class = get_age_class_index(cpatch%age) + age_area_rad(age_class) = age_area_rad(age_class) + cpatch%total_canopy_area end if cpatch => cpatch%younger end do - end if if_anyrad - ! Diagnostics that are only relevant if there is vegetation present on this site - ! ie, non-zero canopy area + sum_area_rad = sum(age_area_rad(:)) + + if_anyrad: if(sum_area_rad < nearzero .or. & + sites(s)%coszen < nearzero ) then + hio_vis_rad_err_si(io_si) = hlm_hio_ignore_val + hio_nir_rad_err_si(io_si) = hlm_hio_ignore_val + else + hio_vis_rad_err_si(io_si) = 0._r8 + hio_nir_rad_err_si(io_si) = 0._r8 + cpatch => sites(s)%oldest_patch + do while(associated(cpatch)) + if( abs(cpatch%rad_error(ivis)-hlm_hio_ignore_val)>nearzero ) then + + hio_vis_rad_err_si(io_si) = hio_vis_rad_err_si(io_si) + & + cpatch%rad_error(ivis)*cpatch%total_canopy_area/sum_area_rad + hio_nir_rad_err_si(io_si) = hio_nir_rad_err_si(io_si) + & + cpatch%rad_error(inir)*cpatch%total_canopy_area/sum_area_rad + + end if + cpatch => cpatch%younger + end do + end if if_anyrad + + ! Diagnostics that are only relevant if there is vegetation present on this site + ! ie, non-zero canopy area + + if (hlm_use_nocomp .eq. itrue .and. hlm_use_fixed_biogeog .eq. itrue) then + site_area_veg_inv = area - sites(s)%area_bareground * area + else + site_area_veg_inv = 0._r8 + cpatch => sites(s)%oldest_patch + do while(associated(cpatch)) + site_area_veg_inv = site_area_veg_inv + cpatch%total_canopy_area + cpatch => cpatch%younger + end do !patch loop + end if + + if_veg_area: if(site_area_veg_inv < nearzero) then - if (hlm_use_nocomp .eq. itrue .and. hlm_use_fixed_biogeog .eq. itrue) then - site_area_veg_inv = area - sites(s)%area_bareground * area - else - site_area_veg_inv = 0._r8 - cpatch => sites(s)%oldest_patch - do while(associated(cpatch)) - site_area_veg_inv = site_area_veg_inv + cpatch%total_canopy_area - cpatch => cpatch%younger - end do !patch loop - end if - - if_veg_area: if(site_area_veg_inv < nearzero) then + hio_c_stomata_si(io_si) = hlm_hio_ignore_val + hio_c_lblayer_si(io_si) = hlm_hio_ignore_val + hio_tveg(io_si) = hlm_hio_ignore_val - hio_c_stomata_si(io_si) = hlm_hio_ignore_val - hio_c_lblayer_si(io_si) = hlm_hio_ignore_val - hio_tveg(io_si) = hlm_hio_ignore_val + exit if_veg_area - exit if_veg_area + else - else + site_area_veg_inv = 1._r8/site_area_veg_inv - site_area_veg_inv = 1._r8/site_area_veg_inv + cpatch => sites(s)%oldest_patch + do while(associated(cpatch)) - cpatch => sites(s)%oldest_patch - do while(associated(cpatch)) + hio_c_stomata_si(io_si) = hio_c_stomata_si(io_si) + & + cpatch%c_stomata * cpatch%total_canopy_area * mol_per_umol * site_area_veg_inv - hio_c_stomata_si(io_si) = hio_c_stomata_si(io_si) + & - cpatch%c_stomata * cpatch%total_canopy_area * mol_per_umol * site_area_veg_inv + hio_c_lblayer_si(io_si) = hio_c_lblayer_si(io_si) + & + cpatch%c_lblayer * cpatch%total_canopy_area * mol_per_umol * site_area_veg_inv - hio_c_lblayer_si(io_si) = hio_c_lblayer_si(io_si) + & - cpatch%c_lblayer * cpatch%total_canopy_area * mol_per_umol * site_area_veg_inv + ! Only accumulate the instantaneous vegetation temperature for vegetated patches + if (cpatch%nocomp_pft_label.ne.nocomp_bareground)then + hio_tveg(io_si) = hio_tveg(io_si) + & + (bc_in(s)%t_veg_pa(cpatch%patchno) - t_water_freeze_k_1atm) * & + cpatch%total_canopy_area * site_area_veg_inv + end if - ! Only accumulate the instantaneous vegetation temperature for vegetated patches - if (cpatch%nocomp_pft_label.ne.nocomp_bareground)then - hio_tveg(io_si) = hio_tveg(io_si) + & - (bc_in(s)%t_veg_pa(cpatch%patchno) - t_water_freeze_k_1atm) * & - cpatch%total_canopy_area * site_area_veg_inv - end if + ccohort => cpatch%shortest + do while(associated(ccohort)) - ccohort => cpatch%shortest - do while(associated(ccohort)) + n_perm2 = ccohort%n * AREA_INV - n_perm2 = ccohort%n * AREA_INV + if_notnew: if ( .not. ccohort%isnew ) then - if_notnew: if ( .not. ccohort%isnew ) then + ! scale up cohort fluxes to the site level + ! these fluxes have conversions of [kg/plant/timestep] -> [kg/m2/s] - ! scale up cohort fluxes to the site level - ! these fluxes have conversions of [kg/plant/timestep] -> [kg/m2/s] - - ! Net Ecosystem Production [kgC/m2/s]. Use yesterday's growth respiration - hio_nep_si(io_si) = hio_nep_si(io_si) + & - (ccohort%gpp_tstep-ccohort%resp_m_tstep) * n_perm2 * dt_tstep_inv - & - (ccohort%resp_g_acc_hold+ccohort%resp_excess_hold) * n_perm2 / days_per_year / sec_per_day + ! Net Ecosystem Production [kgC/m2/s]. Use yesterday's growth respiration + hio_nep_si(io_si) = hio_nep_si(io_si) + & + (ccohort%gpp_tstep-ccohort%resp_m_tstep) * n_perm2 * dt_tstep_inv - & + (ccohort%resp_g_acc_hold+ccohort%resp_excess_hold) * n_perm2 / days_per_year / sec_per_day - hio_gpp_si(io_si) = hio_gpp_si(io_si) + & - ccohort%gpp_tstep * n_perm2 * dt_tstep_inv + hio_gpp_si(io_si) = hio_gpp_si(io_si) + & + ccohort%gpp_tstep * n_perm2 * dt_tstep_inv - hio_maint_resp_si(io_si) = hio_maint_resp_si(io_si) + & - ccohort%resp_m_tstep * n_perm2 * dt_tstep_inv + hio_maint_resp_si(io_si) = hio_maint_resp_si(io_si) + & + ccohort%resp_m_tstep * n_perm2 * dt_tstep_inv - hio_maint_resp_unreduced_si(io_si) = hio_maint_resp_unreduced_si(io_si) + & - ccohort%resp_m_unreduced * n_perm2 * dt_tstep_inv + hio_maint_resp_unreduced_si(io_si) = hio_maint_resp_unreduced_si(io_si) + & + ccohort%resp_m_unreduced * n_perm2 * dt_tstep_inv - ! Maintenance respiration of different organs - hio_leaf_mr_si(io_si) = hio_leaf_mr_si(io_si) + ccohort%rdark & - * n_perm2 - hio_froot_mr_si(io_si) = hio_froot_mr_si(io_si) + ccohort%froot_mr & - * n_perm2 - hio_livecroot_mr_si(io_si) = hio_livecroot_mr_si(io_si) + ccohort%livecroot_mr & - * n_perm2 - hio_livestem_mr_si(io_si) = hio_livestem_mr_si(io_si) + ccohort%livestem_mr & - * n_perm2 + ! Maintenance respiration of different organs + hio_leaf_mr_si(io_si) = hio_leaf_mr_si(io_si) + ccohort%rdark & + * n_perm2 + hio_froot_mr_si(io_si) = hio_froot_mr_si(io_si) + ccohort%froot_mr & + * n_perm2 + hio_livecroot_mr_si(io_si) = hio_livecroot_mr_si(io_si) + ccohort%livecroot_mr & + * n_perm2 + hio_livestem_mr_si(io_si) = hio_livestem_mr_si(io_si) + ccohort%livestem_mr & + * n_perm2 - ! accumulate fluxes on canopy- and understory- separated fluxes - ! these fluxes have conversions of [kg/plant/timestep] -> [kg/m2/s] - if (ccohort%canopy_layer .eq. 1) then + ! accumulate fluxes on canopy- and understory- separated fluxes + ! these fluxes have conversions of [kg/plant/timestep] -> [kg/m2/s] + if (ccohort%canopy_layer .eq. 1) then - hio_gpp_canopy_si(io_si) = hio_gpp_canopy_si(io_si) + & - ccohort%gpp_tstep * n_perm2 * dt_tstep_inv + hio_gpp_canopy_si(io_si) = hio_gpp_canopy_si(io_si) + & + ccohort%gpp_tstep * n_perm2 * dt_tstep_inv - else + else - hio_gpp_understory_si(io_si) = hio_gpp_understory_si(io_si) + & - ccohort%gpp_tstep * n_perm2 * dt_tstep_inv + hio_gpp_understory_si(io_si) = hio_gpp_understory_si(io_si) + & + ccohort%gpp_tstep * n_perm2 * dt_tstep_inv - end if + end if - end if if_notnew - ccohort => ccohort%taller + end if if_notnew + ccohort => ccohort%taller + end do + cpatch => cpatch%younger end do - cpatch => cpatch%younger - end do - end if if_veg_area - end do do_sites - - deallocate(age_area_rad) - - end associate - return - end subroutine update_history_hifrq_sitelevel - - ! =============================================================================================== - - subroutine update_history_hifrq_subsite(this,nc,nsites,sites,bc_in,dt_tstep) - - ! --------------------------------------------------------------------------------- - ! This subroutine is intended to update all history variables with upfreq == - ! group_hifrq_complex (i.e., that have a dimension in addition to that for the site - ! level) that do NOT include age class. So, e.g., FATES_GPP_PF would be updated - ! here, but not FATES_GPP or FATES_GPP_AP. This is an expensive call; the model - ! will probably run much faster if the user is not using any of these diagnostics. - ! --------------------------------------------------------------------------------- - - ! - ! Arguments - class(fates_history_interface_type) :: this - integer , intent(in) :: nc ! clump index - integer , intent(in) :: nsites - type(ed_site_type) , intent(inout) :: sites(nsites) - type(bc_in_type) , intent(in) :: bc_in(nsites) - real(r8) , intent(in) :: dt_tstep - - ! Locals - integer :: s ! The local site index - integer :: io_si ! The site index of the IO array - integer :: lb1,ub1,lb2,ub2 ! IO array bounds for the calling thread - integer :: ivar ! index of IO variable object vector - integer :: ft ! functional type index - real(r8) :: n_density ! individual of cohort per m2. - real(r8) :: n_perm2 ! individuals per m2 for the whole column - real(r8) :: site_area_veg_inv ! 1/area of the site that is not bare-ground - integer :: ipa2 ! patch incrementer - integer :: clllpf_indx, cnlf_indx, ipft, ican, ileaf ! more iterators and indices - real(r8) :: clllpf_area ! area footprint (m2) for the current cl x ll x pft bin - real(r8) :: clll_area ! area footprint (m2) for the cl x ll bin (ie adds up pfts in parallel) - real(r8) :: cl_area ! total weight of all ll x pft bins in the canopy layer - real(r8) :: parprof_pft_dir_z,parprof_pft_dif_z ! PAR intensity for dir/diff for pft/canopy/leaf layer (w/m2) - - type(fates_patch_type),pointer :: cpatch - type(fates_cohort_type),pointer :: ccohort - real(r8) :: dt_tstep_inv ! Time step in frequency units (/s) - - associate( hio_ar_si_scpf => this%hvars(ih_ar_si_scpf)%r82d, & + end if if_veg_area + end do do_sites + + deallocate(age_area_rad) + + end associate + return + end subroutine update_history_hifrq_sitelevel + + ! =============================================================================================== + + subroutine update_history_hifrq_subsite(this,nc,nsites,sites,bc_in,dt_tstep) + + ! --------------------------------------------------------------------------------- + ! This subroutine is intended to update all history variables with upfreq == + ! group_hifrq_complex (i.e., that have a dimension in addition to that for the site + ! level) that do NOT include age class. So, e.g., FATES_GPP_PF would be updated + ! here, but not FATES_GPP or FATES_GPP_AP. This is an expensive call; the model + ! will probably run much faster if the user is not using any of these diagnostics. + ! --------------------------------------------------------------------------------- + + ! + ! Arguments + class(fates_history_interface_type) :: this + integer , intent(in) :: nc ! clump index + integer , intent(in) :: nsites + type(ed_site_type) , intent(inout) :: sites(nsites) + type(bc_in_type) , intent(in) :: bc_in(nsites) + real(r8) , intent(in) :: dt_tstep + + ! Locals + integer :: s ! The local site index + integer :: io_si ! The site index of the IO array + integer :: lb1,ub1,lb2,ub2 ! IO array bounds for the calling thread + integer :: ivar ! index of IO variable object vector + integer :: ft ! functional type index + real(r8) :: n_density ! individual of cohort per m2. + real(r8) :: n_perm2 ! individuals per m2 for the whole column + real(r8) :: site_area_veg_inv ! 1/area of the site that is not bare-ground + integer :: ipa2 ! patch incrementer + integer :: clllpf_indx, cnlf_indx, ipft, ican, ileaf ! more iterators and indices + real(r8) :: clllpf_area ! area footprint (m2) for the current cl x ll x pft bin + real(r8) :: clll_area ! area footprint (m2) for the cl x ll bin (ie adds up pfts in parallel) + real(r8) :: cl_area ! total weight of all ll x pft bins in the canopy layer + real(r8) :: parprof_pft_dir_z,parprof_pft_dif_z ! PAR intensity for dir/diff for pft/canopy/leaf layer (w/m2) + + type(fates_patch_type),pointer :: cpatch + type(fates_cohort_type),pointer :: ccohort + real(r8) :: dt_tstep_inv ! Time step in frequency units (/s) + + associate( hio_ar_si_scpf => this%hvars(ih_ar_si_scpf)%r82d, & hio_ar_grow_si_scpf => this%hvars(ih_ar_grow_si_scpf)%r82d, & hio_ar_maint_si_scpf => this%hvars(ih_ar_maint_si_scpf)%r82d, & hio_ar_agsapm_si_scpf => this%hvars(ih_ar_agsapm_si_scpf)%r82d, & @@ -5437,486 +5447,486 @@ subroutine update_history_hifrq_subsite(this,nc,nsites,sites,bc_in,dt_tstep) hio_laisha_si_can => this%hvars(ih_laisha_si_can)%r82d ) - ! THIS CAN BE REMOVED WHEN BOTH CTSM AND E3SM CALL FLUSH_ALL_HVARS - ! THIS IS NOT A LIABILITY, IT IS JUST REDUNDANT - call this%flush_hvars(nc,upfreq_in=group_hifr_complx) - - dt_tstep_inv = 1.0_r8/dt_tstep + ! THIS CAN BE REMOVED WHEN BOTH CTSM AND E3SM CALL FLUSH_ALL_HVARS + ! THIS IS NOT A LIABILITY, IT IS JUST REDUNDANT + call this%flush_hvars(nc,upfreq_in=group_hifr_complx) - do_sites: do s = 1,nsites + dt_tstep_inv = 1.0_r8/dt_tstep - call this%zero_site_hvars(sites(s), upfreq_in=group_hifr_complx) - - site_area_veg_inv = 0._r8 - cpatch => sites(s)%oldest_patch - do while(associated(cpatch)) - site_area_veg_inv = site_area_veg_inv + cpatch%total_canopy_area - cpatch => cpatch%younger - end do !patch loop + do_sites: do s = 1,nsites - ! If there is no vegetation, go to the next site - if(site_area_veg_inv < nearzero) cycle do_sites + call this%zero_site_hvars(sites(s), upfreq_in=group_hifr_complx) - site_area_veg_inv = 1._r8/site_area_veg_inv + site_area_veg_inv = 0._r8 + cpatch => sites(s)%oldest_patch + do while(associated(cpatch)) + site_area_veg_inv = site_area_veg_inv + cpatch%total_canopy_area + cpatch => cpatch%younger + end do !patch loop - io_si = sites(s)%h_gid + ! If there is no vegetation, go to the next site + if(site_area_veg_inv < nearzero) cycle do_sites - cpatch => sites(s)%oldest_patch - patch_loop1: do while(associated(cpatch)) - - nocomp_bare: if(cpatch%nocomp_pft_label.ne.nocomp_bareground)then - - ccohort => cpatch%shortest - do while(associated(ccohort)) + site_area_veg_inv = 1._r8/site_area_veg_inv - n_perm2 = ccohort%n * AREA_INV - - if ( .not. ccohort%isnew ) then - - ! Calculate index for the scpf class - associate( scpf => ccohort%size_by_pft_class, & - scls => ccohort%size_class ) - - ! 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_m_tstep*dt_tstep_inv) * n_perm2 + & - (ccohort%resp_g_acc_hold + ccohort%resp_excess_hold)* n_perm2 / days_per_year / sec_per_day - - ! Growth AR (kgC/m2/s) ! CDK: this should be daily - hio_ar_grow_si_scpf(io_si,scpf) = hio_ar_grow_si_scpf(io_si,scpf) + & - ccohort%resp_g_acc_hold * n_perm2 / days_per_year / sec_per_day - - ! Maint AR (kgC/m2/s) - hio_ar_maint_si_scpf(io_si,scpf) = hio_ar_maint_si_scpf(io_si,scpf) + & - (ccohort%resp_m_tstep*dt_tstep_inv) * n_perm2 - - ! Maintenance AR partition variables are stored as rates (kgC/plant/s) - ! (kgC/m2/s) = (kgC/plant/s) * (plant/m2) - hio_ar_agsapm_si_scpf(io_si,scpf) = hio_ar_agsapm_si_scpf(io_si,scpf) + & - ccohort%livestem_mr * n_perm2 - - ! (kgC/m2/s) = (kgC/plant/s) * (plant/m2) - hio_ar_darkm_si_scpf(io_si,scpf) = hio_ar_darkm_si_scpf(io_si,scpf) + & - ccohort%rdark * n_perm2 - - ! (kgC/m2/s) = (kgC/plant/s) * (plant/m2) - hio_ar_crootm_si_scpf(io_si,scpf) = hio_ar_crootm_si_scpf(io_si,scpf) + & - ccohort%livecroot_mr * n_perm2 - - ! (kgC/m2/s) = (kgC/plant/s) * (plant/m2) - hio_ar_frootm_si_scpf(io_si,scpf) = hio_ar_frootm_si_scpf(io_si,scpf) + & - ccohort%froot_mr * n_perm2 - - if (cpatch%land_use_label .gt. nocomp_bareground_land) then - hio_gpp_si_landuse(io_si,cpatch%land_use_label) = hio_gpp_si_landuse(io_si,cpatch%land_use_label) & - + ccohort%gpp_tstep * ccohort%n * dt_tstep_inv - end if - - ! accumulate fluxes on canopy- and understory- separated fluxes - if (ccohort%canopy_layer .eq. 1) then - - ! 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 * 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 * 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 * 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 * ha_per_m2 - hio_resp_g_canopy_si_scls(io_si,scls) = hio_resp_g_canopy_si_scls(io_si,scls) + & - ccohort%resp_g_acc_hold * n_perm2 / days_per_year / sec_per_day - hio_resp_m_canopy_si_scls(io_si,scls) = hio_resp_m_canopy_si_scls(io_si,scls) + & - ccohort%resp_m_tstep * ccohort%n * dt_tstep_inv * ha_per_m2 - else - - ! 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 * 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 * 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 * 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 * ha_per_m2 - hio_resp_g_understory_si_scls(io_si,scls) = hio_resp_g_understory_si_scls(io_si,scls) + & - ccohort%resp_g_acc_hold * n_perm2 / days_per_year / sec_per_day - hio_resp_m_understory_si_scls(io_si,scls) = hio_resp_m_understory_si_scls(io_si,scls) + & - ccohort%resp_m_tstep * ccohort%n * dt_tstep_inv * ha_per_m2 - endif - end associate - endif - ! canopy leaf carbon balance + io_si = sites(s)%h_gid - ican = ccohort%canopy_layer - 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) * dt_tstep_inv * ccohort%c_area * area_inv - end do + cpatch => sites(s)%oldest_patch + patch_loop1: do while(associated(cpatch)) - ccohort => ccohort%taller - enddo ! cohort loop + nocomp_bare: if(cpatch%nocomp_pft_label.ne.nocomp_bareground)then + ccohort => cpatch%shortest + do while(associated(ccohort)) - ! Radiation diagnostics - ! Only process diagnostics if the sun is out - if_zenith1: if( sites(s)%coszen>0._r8 ) then + n_perm2 = ccohort%n * AREA_INV - do_pft1: do ipft=1,numpft - do_canlev1: do ican=1,cpatch%ncl_p - do_leaflev1: do ileaf=1,cpatch%nrad(ican,ipft) + if ( .not. ccohort%isnew ) then - ! calculate where we are on multiplexed dimensions - clllpf_indx = ileaf + (ican-1) * nlevleaf + (ipft-1) * nlevleaf * nclmax + ! Calculate index for the scpf class + associate( scpf => ccohort%size_by_pft_class, & + scls => ccohort%size_class ) + + ! 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_m_tstep*dt_tstep_inv) * n_perm2 + & + (ccohort%resp_g_acc_hold + ccohort%resp_excess_hold)* n_perm2 / days_per_year / sec_per_day + + ! Growth AR (kgC/m2/s) ! CDK: this should be daily + hio_ar_grow_si_scpf(io_si,scpf) = hio_ar_grow_si_scpf(io_si,scpf) + & + ccohort%resp_g_acc_hold * n_perm2 / days_per_year / sec_per_day + + ! Maint AR (kgC/m2/s) + hio_ar_maint_si_scpf(io_si,scpf) = hio_ar_maint_si_scpf(io_si,scpf) + & + (ccohort%resp_m_tstep*dt_tstep_inv) * n_perm2 + + ! Maintenance AR partition variables are stored as rates (kgC/plant/s) + ! (kgC/m2/s) = (kgC/plant/s) * (plant/m2) + hio_ar_agsapm_si_scpf(io_si,scpf) = hio_ar_agsapm_si_scpf(io_si,scpf) + & + ccohort%livestem_mr * n_perm2 + + ! (kgC/m2/s) = (kgC/plant/s) * (plant/m2) + hio_ar_darkm_si_scpf(io_si,scpf) = hio_ar_darkm_si_scpf(io_si,scpf) + & + ccohort%rdark * n_perm2 + + ! (kgC/m2/s) = (kgC/plant/s) * (plant/m2) + hio_ar_crootm_si_scpf(io_si,scpf) = hio_ar_crootm_si_scpf(io_si,scpf) + & + ccohort%livecroot_mr * n_perm2 + + ! (kgC/m2/s) = (kgC/plant/s) * (plant/m2) + hio_ar_frootm_si_scpf(io_si,scpf) = hio_ar_frootm_si_scpf(io_si,scpf) + & + ccohort%froot_mr * n_perm2 + + if (cpatch%land_use_label .gt. nocomp_bareground_land) then + hio_gpp_si_landuse(io_si,cpatch%land_use_label) = hio_gpp_si_landuse(io_si,cpatch%land_use_label) & + + ccohort%gpp_tstep * ccohort%n * dt_tstep_inv + end if + + ! accumulate fluxes on canopy- and understory- separated fluxes + if (ccohort%canopy_layer .eq. 1) then + + ! 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 * 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 * 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 * 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 * ha_per_m2 + hio_resp_g_canopy_si_scls(io_si,scls) = hio_resp_g_canopy_si_scls(io_si,scls) + & + ccohort%resp_g_acc_hold * n_perm2 / days_per_year / sec_per_day + hio_resp_m_canopy_si_scls(io_si,scls) = hio_resp_m_canopy_si_scls(io_si,scls) + & + ccohort%resp_m_tstep * ccohort%n * dt_tstep_inv * ha_per_m2 + else + + ! 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 * 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 * 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 * 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 * ha_per_m2 + hio_resp_g_understory_si_scls(io_si,scls) = hio_resp_g_understory_si_scls(io_si,scls) + & + ccohort%resp_g_acc_hold * n_perm2 / days_per_year / sec_per_day + hio_resp_m_understory_si_scls(io_si,scls) = hio_resp_m_understory_si_scls(io_si,scls) + & + ccohort%resp_m_tstep * ccohort%n * dt_tstep_inv * ha_per_m2 + endif + end associate + endif + ! canopy leaf carbon balance + + ican = ccohort%canopy_layer + 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) * dt_tstep_inv * ccohort%c_area * area_inv + end do + + ccohort => ccohort%taller + enddo ! cohort loop + + + ! Radiation diagnostics + ! Only process diagnostics if the sun is out + if_zenith1: if( sites(s)%coszen>0._r8 ) then - ! canopy_area_profile is the fraction of the total canopy area that - ! is occupied by this bin. If you add up the top leaf layer bins in the - ! top canopy layers, for all pfts, that should equal to 1 - - clllpf_area = cpatch%canopy_area_profile(ican,ipft,ileaf)*cpatch%total_canopy_area - - ! Canopy by leaf by pft level diagnostics - ! ------------------------------------------------------------------- - hio_parsun_z_si_cnlfpft(io_si,clllpf_indx) = hio_parsun_z_si_cnlfpft(io_si,clllpf_indx) + & - cpatch%ed_parsun_z(ican,ipft,ileaf) * clllpf_area - - hio_parsha_z_si_cnlfpft(io_si,clllpf_indx) = hio_parsha_z_si_cnlfpft(io_si,clllpf_indx) + & - cpatch%ed_parsha_z(ican,ipft,ileaf) * clllpf_area - - ! elai_profile is the m2 of leaf inside the m2 of bin. - - hio_laisun_clllpf(io_si, clllpf_indx) = hio_laisun_clllpf(io_si, clllpf_indx) + & - cpatch%elai_profile(ican,ipft,ileaf)*cpatch%f_sun(ican,ipft,ileaf)*clllpf_area - - hio_laisha_clllpf(io_si,clllpf_indx) = hio_laisha_clllpf(io_si,clllpf_indx) + & - cpatch%elai_profile(ican,ipft,ileaf)*(1._r8-cpatch%f_sun(ican,ipft,ileaf))*clllpf_area - - parprof_pft_dir_z = bc_in(s)%solad_parb(cpatch%patchno,ipar) * & - cpatch%nrmlzd_parprof_pft_dir_z(ican,ipft,ileaf) - - parprof_pft_dif_z = bc_in(s)%solai_parb(cpatch%patchno,ipar) * & - cpatch%nrmlzd_parprof_pft_dif_z(ican,ipft,ileaf) - - hio_parprof_dir_si_cnlfpft(io_si,clllpf_indx) = hio_parprof_dir_si_cnlfpft(io_si,clllpf_indx) + & - parprof_pft_dir_z * clllpf_area - - hio_parprof_dif_si_cnlfpft(io_si,clllpf_indx) = hio_parprof_dif_si_cnlfpft(io_si,clllpf_indx) + & - parprof_pft_dif_z * clllpf_area - - ! The fractional area of Canopy layer and PFTs can be used - ! do upscale the CLLLPF properties - hio_crownfrac_clllpf(io_si,clllpf_indx) = hio_crownfrac_clllpf(io_si,clllpf_indx) + & - clllpf_area - - - ! Canopy by leaf layer (mean across pfts) level diagnostics - ! ---------------------------------------------------------------------------- - hio_parprof_dir_si_cnlf(io_si,cnlf_indx) = hio_parprof_dir_si_cnlf(io_si,cnlf_indx) + & - parprof_pft_dir_z * clllpf_area - - hio_parprof_dif_si_cnlf(io_si,cnlf_indx) = hio_parprof_dif_si_cnlf(io_si,cnlf_indx) + & - parprof_pft_dif_z * clllpf_area - - hio_parsun_z_si_cnlf(io_si,cnlf_indx) = hio_parsun_z_si_cnlf(io_si,cnlf_indx) + & - cpatch%ed_parsun_z(ican,ipft,ileaf) * clllpf_area - - hio_parsha_z_si_cnlf(io_si,cnlf_indx) = hio_parsha_z_si_cnlf(io_si,cnlf_indx) + & - cpatch%ed_parsha_z(ican,ipft,ileaf) * clllpf_area - - hio_laisun_z_si_cnlf(io_si,cnlf_indx) = hio_laisun_z_si_cnlf(io_si,cnlf_indx) + & - cpatch%f_sun(ican,ipft,ileaf)*clllpf_area - - hio_laisha_z_si_cnlf(io_si,cnlf_indx) = hio_laisha_z_si_cnlf(io_si,cnlf_indx) + & - (1._r8-cpatch%f_sun(ican,ipft,ileaf))*clllpf_area - - ! Canopy mean diagnostics - ! -------------------------------------------------------------- - - hio_parsun_si_can(io_si,ican) = hio_parsun_si_can(io_si,ican) + & - cpatch%ed_parsun_z(ican,ipft,ileaf) * clllpf_area - hio_parsha_si_can(io_si,ican) = hio_parsha_si_can(io_si,ican) + & - cpatch%ed_parsha_z(ican,ipft,ileaf) * clllpf_area - - hio_laisun_si_can(io_si,ican) = hio_laisun_si_can(io_si,ican) + & - cpatch%f_sun(ican,ipft,ileaf)*cpatch%elai_profile(ican,ipft,ileaf) * clllpf_area - hio_laisha_si_can(io_si,ican) = hio_laisha_si_can(io_si,ican) + & - (1._r8-cpatch%f_sun(ican,ipft,ileaf))*cpatch%elai_profile(ican,ipft,ileaf) * clllpf_area - - - end do do_leaflev1 - end do do_canlev1 - end do do_pft1 - end if if_zenith1 - end if nocomp_bare - cpatch => cpatch%younger - end do patch_loop1 !patch loop - - ! Normalize the radiation multiplexed diagnostics - ! Set values that dont have canopy elements to ignore - ! ---------------------------------------------------------------------------- - - if_zenith2: if( sites(s)%coszen>0._r8 ) then - do_ican2: do ican = 1,nclmax - - cl_area = 0._r8 - do_ileaf2: do ileaf = 1,nlevleaf - - clll_area = 0._r8 - do_ipft2: do ipft = 1,numpft - - clllpf_indx = ileaf + (ican-1) * nlevleaf + (ipft-1) * nlevleaf * nclmax - if( hio_crownfrac_clllpf(io_si,clllpf_indx) cpatch%younger + end do patch_loop1 !patch loop + + ! Normalize the radiation multiplexed diagnostics + ! Set values that dont have canopy elements to ignore + ! ---------------------------------------------------------------------------- + + if_zenith2: if( sites(s)%coszen>0._r8 ) then + do_ican2: do ican = 1,nclmax + + cl_area = 0._r8 + do_ileaf2: do ileaf = 1,nlevleaf + + clll_area = 0._r8 + do_ipft2: do ipft = 1,numpft + + clllpf_indx = ileaf + (ican-1) * nlevleaf + (ipft-1) * nlevleaf * nclmax + if( hio_crownfrac_clllpf(io_si,clllpf_indx) this%hvars(ih_c_lblayer_si_age)%r82d, & + hio_c_stomata_si_age => this%hvars(ih_c_stomata_si_age)%r82d, & + hio_gpp_si_age => this%hvars(ih_gpp_si_age)%r82d & + ) + + dt_tstep_inv = 1.0_r8 / dt_tstep + + do_sites: do s = 1,nsites + + ! Get site-wide canopy area + site_canopy_area = 0._r8 + cpatch => sites(s)%oldest_patch + do while(associated(cpatch)) + site_canopy_area = site_canopy_area + cpatch%total_canopy_area + cpatch => cpatch%younger + end do + + io_si = sites(s)%h_gid + + ! Get ageclass-stratified variables + cpatch => sites(s)%oldest_patch + do while(associated(cpatch)) + cpatch%age_class = get_age_class_index(cpatch%age) + + ! Canopy resistance terms + if (site_canopy_area .gt. nearzero) then + patch_canarea_div_site_canarea = cpatch%total_canopy_area / site_canopy_area + hio_c_stomata_si_age(io_si,cpatch%age_class) = & + hio_c_stomata_si_age(io_si,cpatch%age_class) + & + cpatch%c_stomata * mol_per_umol & + * patch_canarea_div_site_canarea + + hio_c_lblayer_si_age(io_si,cpatch%age_class) = & + hio_c_lblayer_si_age(io_si,cpatch%age_class) + & + cpatch%c_lblayer * mol_per_umol & + * patch_canarea_div_site_canarea else - ! Since these are integrated metrics, ie absorbed over depth - ! and total leaf over depth, we just want to normalize by the - ! the area of the footprint. The weightings they had - ! recieved were always in m2 (ie the footprint of the bin) - hio_parsun_si_can(io_si,ican) = hio_parsun_si_can(io_si,ican) * site_area_veg_inv - hio_parsha_si_can(io_si,ican) = hio_parsha_si_can(io_si,ican) * site_area_veg_inv - hio_laisun_si_can(io_si,ican) = hio_laisun_si_can(io_si,ican) * site_area_veg_inv - hio_laisha_si_can(io_si,ican) = hio_laisha_si_can(io_si,ican) * site_area_veg_inv + hio_c_stomata_si_age(io_si,cpatch%age_class) = 0._r8 + hio_c_lblayer_si_age(io_si,cpatch%age_class) = 0._r8 end if - end do do_ican2 - end if if_zenith2 - enddo do_sites ! site loop - - end associate - - end subroutine update_history_hifrq_subsite - - ! =============================================================================================== - - subroutine update_history_hifrq_subsite_ageclass(this,nsites,sites,dt_tstep) - - ! --------------------------------------------------------------------------------- - ! This subroutine is intended to update all history variables with upfreq == - ! group_hifrq_complex (i.e., that have a dimension in addition to that for the site - ! level) that DO include age class. So, e.g., FATES_GPP_AP is updated here, but not - ! FATES_GPP or FATES_GPP_PF. This is an expensive call; the model will probably run - ! much faster if the user is not using any of these diagnostics. - ! --------------------------------------------------------------------------------- - - ! - ! Arguments - class(fates_history_interface_type) :: this - integer , intent(in) :: nsites - type(ed_site_type) , intent(inout), target :: sites(nsites) - real(r8) , intent(in) :: dt_tstep - - type(fates_cohort_type), pointer :: ccohort - type(fates_patch_type), pointer :: cpatch - integer :: s, io_si - real(r8) :: site_canopy_area - real(r8) :: dt_tstep_inv ! Time step in frequency units (/s) - real(r8) :: patch_canarea_div_site_canarea ! Weighting based on patch canopy area relative to site canopy area - real(r8) :: cohort_n_div_site_area ! Weighting based on cohort density relative to site area - - associate( & - hio_c_lblayer_si_age => this%hvars(ih_c_lblayer_si_age)%r82d, & - hio_c_stomata_si_age => this%hvars(ih_c_stomata_si_age)%r82d, & - hio_gpp_si_age => this%hvars(ih_gpp_si_age)%r82d & - ) - - dt_tstep_inv = 1.0_r8 / dt_tstep - - do_sites: do s = 1,nsites - - ! Get site-wide canopy area - site_canopy_area = 0._r8 - cpatch => sites(s)%oldest_patch - do while(associated(cpatch)) - site_canopy_area = site_canopy_area + cpatch%total_canopy_area - cpatch => cpatch%younger - end do - - io_si = sites(s)%h_gid - - ! Get ageclass-stratified variables - cpatch => sites(s)%oldest_patch - do while(associated(cpatch)) - cpatch%age_class = get_age_class_index(cpatch%age) - - ! Canopy resistance terms - if (site_canopy_area .gt. nearzero) then - patch_canarea_div_site_canarea = cpatch%total_canopy_area / site_canopy_area - hio_c_stomata_si_age(io_si,cpatch%age_class) = & - hio_c_stomata_si_age(io_si,cpatch%age_class) + & - cpatch%c_stomata * mol_per_umol & - * patch_canarea_div_site_canarea - - hio_c_lblayer_si_age(io_si,cpatch%age_class) = & - hio_c_lblayer_si_age(io_si,cpatch%age_class) + & - cpatch%c_lblayer * mol_per_umol & - * patch_canarea_div_site_canarea - else - hio_c_stomata_si_age(io_si,cpatch%age_class) = 0._r8 - hio_c_lblayer_si_age(io_si,cpatch%age_class) = 0._r8 - end if - - ccohort => cpatch%shortest - do while(associated(ccohort)) - if (ccohort%isnew) then - ccohort => ccohort%taller - cycle - end if - cohort_n_div_site_area = ccohort%n * AREA_INV - - hio_gpp_si_age(io_si,cpatch%age_class) = hio_gpp_si_age(io_si,cpatch%age_class) & - + ccohort%gpp_tstep * dt_tstep_inv & - * cohort_n_div_site_area - - ccohort => ccohort%taller - end do ! cohort loop - - cpatch => cpatch%younger - end do ! patch loop - end do do_sites - - end associate - - end subroutine update_history_hifrq_subsite_ageclass - - ! ===================================================================================== - - subroutine update_history_hydraulics(this,nc,nsites,sites,bc_in,dt_tstep) - - ! --------------------------------------------------------------------------------- - ! This is the call to update the history IO arrays that are expected to only change - ! after rapid timescale productivity calculations (gpp and respiration). - ! --------------------------------------------------------------------------------- - - use FatesHydraulicsMemMod, only : ed_cohort_hydr_type, nshell - use FatesHydraulicsMemMod, only : ed_site_hydr_type - - ! 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) - real(r8) , intent(in) :: dt_tstep - - ! Locals - integer :: s ! The local site index - integer :: io_si ! The site index of the IO array - integer :: ft ! functional type index - ! integer :: io_shsl ! The combined "SH"ell "S"oil "L"ayer index in the IO array - 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 - ! should be "hio_nplant_si_scpf" - real(r8) :: number_fraction - real(r8) :: number_fraction_rate - real(r8) :: mean_aroot - integer :: ipa2 ! patch incrementer - integer :: ix ! histogram x (count) bin index - integer :: iscpf ! index of the scpf group - integer :: ipft ! index of the pft loop - integer :: iscls ! index of the size-class loop - integer :: k ! rhizosphere shell index - integer :: j ! rhizosphere (ie root) layer index - integer :: j_bc ! Soil layer index (ie boundary condition grid index) - integer :: j_t,j_b ! top and bottom soil layer matching current rhiz layer - integer :: nlevrhiz ! number of rhizosphere layers - integer :: nlevsoil ! number of soil layers - real(r8) :: mean_soil_vwc ! mean soil volumetric water content [m3/m3] - real(r8) :: mean_soil_vwcsat ! mean soil saturated volumetric water content [m3/m3] - real(r8) :: mean_soil_matpot ! mean soil water potential [MPa] - real(r8) :: layer_areaweight ! root area weighting factor for each soil layer - real(r8) :: areaweight ! root area weighting factor for column - real(r8) :: vwc ! volumetric water content of layer [m3/m3] = theta - real(r8) :: vwc_sat ! saturated water content of layer [m3/m3] - 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(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? - - if(hlm_use_planthydro.eq.ifalse) return - - per_dt_tstep = 1._r8 / dt_tstep - - if_hifrq0: if(hlm_hist_level_hifrq>0) then - - ! THIS CAN BE REMOVED WHEN BOTH CTSM AND E3SM CALL FLUSH_ALL_HVARS - ! THIS IS NOT A LIABILITY, IT IS JUST REDUNDANT - call this%flush_hvars(nc,upfreq_in=group_hydr_simple) - - associate( hio_h2oveg_hydro_err_si => this%hvars(ih_h2oveg_hydro_err_si)%r81d, & + + ccohort => cpatch%shortest + do while(associated(ccohort)) + if (ccohort%isnew) then + ccohort => ccohort%taller + cycle + end if + cohort_n_div_site_area = ccohort%n * AREA_INV + + hio_gpp_si_age(io_si,cpatch%age_class) = hio_gpp_si_age(io_si,cpatch%age_class) & + + ccohort%gpp_tstep * dt_tstep_inv & + * cohort_n_div_site_area + + ccohort => ccohort%taller + end do ! cohort loop + + cpatch => cpatch%younger + end do ! patch loop + end do do_sites + + end associate + + end subroutine update_history_hifrq_subsite_ageclass + + ! ===================================================================================== + + subroutine update_history_hydraulics(this,nc,nsites,sites,bc_in,dt_tstep) + + ! --------------------------------------------------------------------------------- + ! This is the call to update the history IO arrays that are expected to only change + ! after rapid timescale productivity calculations (gpp and respiration). + ! --------------------------------------------------------------------------------- + + use FatesHydraulicsMemMod, only : ed_cohort_hydr_type, nshell + use FatesHydraulicsMemMod, only : ed_site_hydr_type + + ! 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) + real(r8) , intent(in) :: dt_tstep + + ! Locals + integer :: s ! The local site index + integer :: io_si ! The site index of the IO array + integer :: ft ! functional type index + ! integer :: io_shsl ! The combined "SH"ell "S"oil "L"ayer index in the IO array + 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 + ! should be "hio_nplant_si_scpf" + real(r8) :: number_fraction + real(r8) :: number_fraction_rate + real(r8) :: mean_aroot + integer :: ipa2 ! patch incrementer + integer :: ix ! histogram x (count) bin index + integer :: iscpf ! index of the scpf group + integer :: ipft ! index of the pft loop + integer :: iscls ! index of the size-class loop + integer :: k ! rhizosphere shell index + integer :: j ! rhizosphere (ie root) layer index + integer :: j_bc ! Soil layer index (ie boundary condition grid index) + integer :: j_t,j_b ! top and bottom soil layer matching current rhiz layer + integer :: nlevrhiz ! number of rhizosphere layers + integer :: nlevsoil ! number of soil layers + real(r8) :: mean_soil_vwc ! mean soil volumetric water content [m3/m3] + real(r8) :: mean_soil_vwcsat ! mean soil saturated volumetric water content [m3/m3] + real(r8) :: mean_soil_matpot ! mean soil water potential [MPa] + real(r8) :: layer_areaweight ! root area weighting factor for each soil layer + real(r8) :: areaweight ! root area weighting factor for column + real(r8) :: vwc ! volumetric water content of layer [m3/m3] = theta + real(r8) :: vwc_sat ! saturated water content of layer [m3/m3] + 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(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? + + if(hlm_use_planthydro.eq.ifalse) return + + per_dt_tstep = 1._r8 / dt_tstep + + if_hifrq0: if(hlm_hist_level_hifrq>0) then + + ! THIS CAN BE REMOVED WHEN BOTH CTSM AND E3SM CALL FLUSH_ALL_HVARS + ! THIS IS NOT A LIABILITY, IT IS JUST REDUNDANT + call this%flush_hvars(nc,upfreq_in=group_hydr_simple) + + associate( hio_h2oveg_hydro_err_si => this%hvars(ih_h2oveg_hydro_err_si)%r81d, & hio_rootwgt_soilvwc_si => this%hvars(ih_rootwgt_soilvwc_si)%r81d, & hio_rootwgt_soilvwcsat_si => this%hvars(ih_rootwgt_soilvwcsat_si)%r81d, & hio_rootwgt_soilmatpot_si => this%hvars(ih_rootwgt_soilmatpot_si)%r81d, & @@ -5924,82 +5934,82 @@ subroutine update_history_hydraulics(this,nc,nsites,sites,bc_in,dt_tstep) hio_rootuptake_si => this%hvars(ih_rootuptake_si)%r81d, & hio_h2oveg_si => this%hvars(ih_h2oveg_si)%r81d ) - do s = 1,nsites + do s = 1,nsites - call this%zero_site_hvars(sites(s),upfreq_in=group_hydr_simple) + call this%zero_site_hvars(sites(s),upfreq_in=group_hydr_simple) - site_hydr => sites(s)%si_hydr - nlevrhiz = site_hydr%nlevrhiz - nlevsoil = bc_in(s)%nlevsoil - io_si = sites(s)%h_gid + site_hydr => sites(s)%si_hydr + nlevrhiz = site_hydr%nlevrhiz + nlevsoil = bc_in(s)%nlevsoil + io_si = sites(s)%h_gid - hio_h2oveg_si(io_si) = site_hydr%h2oveg - hio_h2oveg_hydro_err_si(io_si) = site_hydr%h2oveg_hydro_err - hio_rootuptake_si(io_si) = sum(site_hydr%rootuptake_sl,dim=1) + hio_h2oveg_si(io_si) = site_hydr%h2oveg + hio_h2oveg_hydro_err_si(io_si) = site_hydr%h2oveg_hydro_err + hio_rootuptake_si(io_si) = sum(site_hydr%rootuptake_sl,dim=1) - ! Get column means of some soil diagnostics, these are weighted - ! by the amount of fine-root surface area in each layer - ! -------------------------------------------------------------------- + ! Get column means of some soil diagnostics, these are weighted + ! by the amount of fine-root surface area in each layer + ! -------------------------------------------------------------------- - mean_soil_vwc = 0._r8 - mean_soil_matpot = 0._r8 - mean_soil_vwcsat = 0._r8 - areaweight = 0._r8 + mean_soil_vwc = 0._r8 + mean_soil_matpot = 0._r8 + mean_soil_vwcsat = 0._r8 + areaweight = 0._r8 - do j=1,nlevrhiz + do j=1,nlevrhiz - j_t = site_hydr%map_r2s(j,1) ! top soil layer matching rhiz layer - j_b = site_hydr%map_r2s(j,2) ! bottom soil layer matching rhiz layer + j_t = site_hydr%map_r2s(j,1) ! top soil layer matching rhiz layer + j_b = site_hydr%map_r2s(j,2) ! bottom soil layer matching rhiz layer - do j_bc = j_t,j_b + 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) ! 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 - ! implement caps inside the functions - ! if desired. (RGK 12-2021) - vwc_sat = bc_in(s)%watsat_sl(j_bc) - depth_frac = bc_in(s)%dz_sisl(j_bc)/site_hydr%dz_rhiz(j) + vwc = bc_in(s)%h2o_liqvol_sl(j_bc) + 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 + ! implement caps inside the functions + ! if desired. (RGK 12-2021) + vwc_sat = bc_in(s)%watsat_sl(j_bc) + depth_frac = bc_in(s)%dz_sisl(j_bc)/site_hydr%dz_rhiz(j) - ! If there are any roots, we use root weighting - if(sum(site_hydr%l_aroot_layer(:),dim=1) > nearzero) then - layer_areaweight = site_hydr%l_aroot_layer(j)*depth_frac*pi_const*site_hydr%rs1(j)**2.0 + ! If there are any roots, we use root weighting + if(sum(site_hydr%l_aroot_layer(:),dim=1) > nearzero) then + layer_areaweight = site_hydr%l_aroot_layer(j)*depth_frac*pi_const*site_hydr%rs1(j)**2.0 - ! If there are no roots, we use depth weighting - else - layer_areaweight = bc_in(s)%dz_sisl(j_bc) - endif + ! If there are no roots, we use depth weighting + else + layer_areaweight = bc_in(s)%dz_sisl(j_bc) + endif - areaweight = areaweight + layer_areaweight - mean_soil_vwc = mean_soil_vwc + vwc*layer_areaweight - mean_soil_vwcsat = mean_soil_vwcsat + vwc_sat*layer_areaweight - mean_soil_matpot = mean_soil_matpot + psi*layer_areaweight + areaweight = areaweight + layer_areaweight + mean_soil_vwc = mean_soil_vwc + vwc*layer_areaweight + mean_soil_vwcsat = mean_soil_vwcsat + vwc_sat*layer_areaweight + mean_soil_matpot = mean_soil_matpot + psi*layer_areaweight + end do end do - end do - hio_rootwgt_soilvwc_si(io_si) = mean_soil_vwc/areaweight - hio_rootwgt_soilvwcsat_si(io_si) = mean_soil_vwcsat/areaweight - hio_rootwgt_soilmatpot_si(io_si) = mean_soil_matpot/areaweight * pa_per_mpa + hio_rootwgt_soilvwc_si(io_si) = mean_soil_vwc/areaweight + hio_rootwgt_soilvwcsat_si(io_si) = mean_soil_vwcsat/areaweight + hio_rootwgt_soilmatpot_si(io_si) = mean_soil_matpot/areaweight * pa_per_mpa - ! calculate site sapflow - do ipft = 1, numpft - do iscls = 1,nlevsclass - hio_sapflow_si(io_si) = hio_sapflow_si(io_si) + & - site_hydr%sapflow_scpf(iscls, ipft) * ha_per_m2 + ! calculate site sapflow + do ipft = 1, numpft + do iscls = 1,nlevsclass + hio_sapflow_si(io_si) = hio_sapflow_si(io_si) + & + site_hydr%sapflow_scpf(iscls, ipft) * ha_per_m2 + end do end do + + end do - - - end do - end associate - end if if_hifrq0 + end associate + end if if_hifrq0 - if_hifrq1: if(hlm_hist_level_hifrq>1) then + if_hifrq1: if(hlm_hist_level_hifrq>1) then - associate( hio_errh2o_scpf => this%hvars(ih_errh2o_scpf)%r82d, & + associate( hio_errh2o_scpf => this%hvars(ih_errh2o_scpf)%r82d, & hio_tran_scpf => this%hvars(ih_tran_scpf)%r82d, & hio_sapflow_scpf => this%hvars(ih_sapflow_scpf)%r82d, & hio_iterh1_scpf => this%hvars(ih_iterh1_scpf)%r82d, & @@ -6017,7 +6027,7 @@ subroutine update_history_hydraulics(this,nc,nsites,sites,bc_in,dt_tstep) hio_sflc_scpf => this%hvars(ih_sflc_scpf)%r82d, & hio_lflc_scpf => this%hvars(ih_lflc_scpf)%r82d, & hio_btran_scpf => this%hvars(ih_btran_scpf)%r82d, & - + hio_nplant_si_scpf => this%hvars(ih_nplant_si_scpf)%r82d, & hio_nplant_si_capf => this%hvars(ih_nplant_si_capf)%r82d, & hio_soilmatpot_sl => this%hvars(ih_soilmatpot_sl)%r82d, & @@ -6029,998 +6039,1015 @@ subroutine update_history_hydraulics(this,nc,nsites,sites,bc_in,dt_tstep) hio_rootuptake50_scpf => this%hvars(ih_rootuptake50_scpf)%r82d, & hio_rootuptake100_scpf => this%hvars(ih_rootuptake100_scpf)%r82d ) - ! THIS CAN BE REMOVED WHEN BOTH CTSM AND E3SM CALL FLUSH_ALL_HVARS - ! THIS IS NOT A LIABILITY, IT IS JUST REDUNDANT - call this%flush_hvars(nc,upfreq_in=group_hydr_complx) - - do s = 1,nsites - - site_hydr => sites(s)%si_hydr - nlevrhiz = site_hydr%nlevrhiz - nlevsoil = bc_in(s)%nlevsoil - io_si = sites(s)%h_gid + ! THIS CAN BE REMOVED WHEN BOTH CTSM AND E3SM CALL FLUSH_ALL_HVARS + ! THIS IS NOT A LIABILITY, IT IS JUST REDUNDANT + call this%flush_hvars(nc,upfreq_in=group_hydr_complx) - call this%zero_site_hvars(sites(s),upfreq_in=group_hydr_complx) - - hio_rootuptake_sl(io_si,1:nlevsoil) = site_hydr%rootuptake_sl(1:nlevsoil) + do s = 1,nsites - ! Get column means of some soil diagnostics, these are weighted - ! by the amount of fine-root surface area in each layer - ! -------------------------------------------------------------------- + site_hydr => sites(s)%si_hydr + nlevrhiz = site_hydr%nlevrhiz + nlevsoil = bc_in(s)%nlevsoil + io_si = sites(s)%h_gid - mean_soil_vwc = 0._r8 - mean_soil_matpot = 0._r8 - mean_soil_vwcsat = 0._r8 - areaweight = 0._r8 + call this%zero_site_hvars(sites(s),upfreq_in=group_hydr_complx) - do j=1,nlevrhiz + hio_rootuptake_sl(io_si,1:nlevsoil) = site_hydr%rootuptake_sl(1:nlevsoil) - j_t = site_hydr%map_r2s(j,1) ! top soil layer matching rhiz layer - j_b = site_hydr%map_r2s(j,2) ! bottom soil layer matching rhiz layer + ! Get column means of some soil diagnostics, these are weighted + ! by the amount of fine-root surface area in each layer + ! -------------------------------------------------------------------- - do j_bc = j_t,j_b + mean_soil_vwc = 0._r8 + mean_soil_matpot = 0._r8 + mean_soil_vwcsat = 0._r8 + areaweight = 0._r8 - vwc = bc_in(s)%h2o_liqvol_sl(j_bc) - 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 - ! implement caps inside the functions - ! if desired. (RGK 12-2021) - vwc_sat = bc_in(s)%watsat_sl(j_bc) - depth_frac = bc_in(s)%dz_sisl(j_bc)/site_hydr%dz_rhiz(j) + do j=1,nlevrhiz - ! If there are any roots, we use root weighting - if(sum(site_hydr%l_aroot_layer(:),dim=1) > nearzero) then - layer_areaweight = site_hydr%l_aroot_layer(j)*depth_frac*pi_const*site_hydr%rs1(j)**2.0 + j_t = site_hydr%map_r2s(j,1) ! top soil layer matching rhiz layer + j_b = site_hydr%map_r2s(j,2) ! bottom soil layer matching rhiz layer - ! If there are no roots, we use depth weighting - else - layer_areaweight = bc_in(s)%dz_sisl(j_bc) - endif + do j_bc = j_t,j_b - areaweight = areaweight + layer_areaweight - mean_soil_vwc = mean_soil_vwc + vwc*layer_areaweight - mean_soil_vwcsat = mean_soil_vwcsat + vwc_sat*layer_areaweight - mean_soil_matpot = mean_soil_matpot + psi*layer_areaweight + vwc = bc_in(s)%h2o_liqvol_sl(j_bc) + 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 + ! implement caps inside the functions + ! if desired. (RGK 12-2021) + vwc_sat = bc_in(s)%watsat_sl(j_bc) + depth_frac = bc_in(s)%dz_sisl(j_bc)/site_hydr%dz_rhiz(j) - hio_soilmatpot_sl(io_si,j_bc) = psi * pa_per_mpa - hio_soilvwc_sl(io_si,j_bc) = vwc - hio_soilvwcsat_sl(io_si,j_bc) = vwc_sat + ! If there are any roots, we use root weighting + if(sum(site_hydr%l_aroot_layer(:),dim=1) > nearzero) then + layer_areaweight = site_hydr%l_aroot_layer(j)*depth_frac*pi_const*site_hydr%rs1(j)**2.0 - end do - end do + ! If there are no roots, we use depth weighting + else + layer_areaweight = bc_in(s)%dz_sisl(j_bc) + endif - ! Normalization counters - nplant_scpf(:) = 0._r8 - ncohort_scpf(:) = 0._r8 - cpatch => sites(s)%oldest_patch - do while(associated(cpatch)) - ccohort => cpatch%shortest - do while(associated(ccohort)) - if ( .not. ccohort%isnew ) then - ! Calculate index for the scpf class - iscpf = ccohort%size_by_pft_class - nplant_scpf(iscpf) = nplant_scpf(iscpf) + ccohort%n - ncohort_scpf(iscpf) = ncohort_scpf(iscpf) + 1._r8 - end if - ccohort => ccohort%taller - enddo ! cohort loop - cpatch => cpatch%younger - end do !patch loop + areaweight = areaweight + layer_areaweight + mean_soil_vwc = mean_soil_vwc + vwc*layer_areaweight + mean_soil_vwcsat = mean_soil_vwcsat + vwc_sat*layer_areaweight + mean_soil_matpot = mean_soil_matpot + psi*layer_areaweight + + hio_soilmatpot_sl(io_si,j_bc) = psi * pa_per_mpa + hio_soilvwc_sl(io_si,j_bc) = vwc + hio_soilvwcsat_sl(io_si,j_bc) = vwc_sat - 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) * 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 + end do end do - end do - cpatch => sites(s)%oldest_patch - do while(associated(cpatch)) + ! Normalization counters + nplant_scpf(:) = 0._r8 + ncohort_scpf(:) = 0._r8 + cpatch => sites(s)%oldest_patch + do while(associated(cpatch)) + ccohort => cpatch%shortest + do while(associated(ccohort)) + if ( .not. ccohort%isnew ) then + ! Calculate index for the scpf class + iscpf = ccohort%size_by_pft_class + nplant_scpf(iscpf) = nplant_scpf(iscpf) + ccohort%n + ncohort_scpf(iscpf) = ncohort_scpf(iscpf) + 1._r8 + end if + ccohort => ccohort%taller + enddo ! cohort loop + cpatch => cpatch%younger + end do !patch loop + + 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) * 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 + end do + end do - ccohort => cpatch%shortest - do while(associated(ccohort)) + cpatch => sites(s)%oldest_patch + do while(associated(cpatch)) - ccohort_hydr => ccohort%co_hydr + ccohort => cpatch%shortest + do while(associated(ccohort)) - if ( .not. ccohort%isnew ) then + ccohort_hydr => ccohort%co_hydr - ! Calculate index for the scpf class - iscpf = ccohort%size_by_pft_class + if ( .not. ccohort%isnew ) then - ! scale up cohort fluxes to their sites - number_fraction_rate = (ccohort%n / nplant_scpf(iscpf)) * per_dt_tstep + ! Calculate index for the scpf class + iscpf = ccohort%size_by_pft_class - ! scale cohorts to mean quantity - number_fraction = (ccohort%n / nplant_scpf(iscpf)) + ! scale up cohort fluxes to their sites + number_fraction_rate = (ccohort%n / nplant_scpf(iscpf)) * per_dt_tstep - hio_errh2o_scpf(io_si,iscpf) = hio_errh2o_scpf(io_si,iscpf) + & - ccohort_hydr%errh2o * number_fraction_rate ! [kg/indiv/s] + ! scale cohorts to mean quantity + number_fraction = (ccohort%n / nplant_scpf(iscpf)) - hio_tran_scpf(io_si,iscpf) = hio_tran_scpf(io_si,iscpf) + & - (ccohort_hydr%qtop) * number_fraction_rate ! [kg/indiv/s] + hio_errh2o_scpf(io_si,iscpf) = hio_errh2o_scpf(io_si,iscpf) + & + ccohort_hydr%errh2o * number_fraction_rate ! [kg/indiv/s] - hio_iterh1_scpf(io_si,iscpf) = hio_iterh1_scpf(io_si,iscpf) + & - ccohort_hydr%iterh1/ncohort_scpf(iscpf) + hio_tran_scpf(io_si,iscpf) = hio_tran_scpf(io_si,iscpf) + & + (ccohort_hydr%qtop) * number_fraction_rate ! [kg/indiv/s] - hio_iterh2_scpf(io_si,iscpf) = hio_iterh2_scpf(io_si,iscpf) + & - ccohort_hydr%iterh2/ncohort_scpf(iscpf) + hio_iterh1_scpf(io_si,iscpf) = hio_iterh1_scpf(io_si,iscpf) + & + ccohort_hydr%iterh1/ncohort_scpf(iscpf) - mean_aroot = sum(ccohort_hydr%th_aroot(:)*ccohort_hydr%v_aroot_layer(:)) / & - sum(ccohort_hydr%v_aroot_layer(:)) + hio_iterh2_scpf(io_si,iscpf) = hio_iterh2_scpf(io_si,iscpf) + & + ccohort_hydr%iterh2/ncohort_scpf(iscpf) - hio_ath_scpf(io_si,iscpf) = hio_ath_scpf(io_si,iscpf) + & - mean_aroot * number_fraction ! [m3 m-3] + mean_aroot = sum(ccohort_hydr%th_aroot(:)*ccohort_hydr%v_aroot_layer(:)) / & + sum(ccohort_hydr%v_aroot_layer(:)) - hio_tth_scpf(io_si,iscpf) = hio_tth_scpf(io_si,iscpf) + & - ccohort_hydr%th_troot * number_fraction ! [m3 m-3] + hio_ath_scpf(io_si,iscpf) = hio_ath_scpf(io_si,iscpf) + & + mean_aroot * number_fraction ! [m3 m-3] - hio_sth_scpf(io_si,iscpf) = hio_sth_scpf(io_si,iscpf) + & - ccohort_hydr%th_ag(2) * number_fraction ! [m3 m-3] + hio_tth_scpf(io_si,iscpf) = hio_tth_scpf(io_si,iscpf) + & + ccohort_hydr%th_troot * number_fraction ! [m3 m-3] - hio_lth_scpf(io_si,iscpf) = hio_lth_scpf(io_si,iscpf) + & - ccohort_hydr%th_ag(1) * number_fraction ! [m3 m-3] + hio_sth_scpf(io_si,iscpf) = hio_sth_scpf(io_si,iscpf) + & + ccohort_hydr%th_ag(2) * number_fraction ! [m3 m-3] - mean_aroot = sum(ccohort_hydr%psi_aroot(:)*ccohort_hydr%v_aroot_layer(:)) / & - sum(ccohort_hydr%v_aroot_layer(:)) + hio_lth_scpf(io_si,iscpf) = hio_lth_scpf(io_si,iscpf) + & + ccohort_hydr%th_ag(1) * number_fraction ! [m3 m-3] - hio_awp_scpf(io_si,iscpf) = hio_awp_scpf(io_si,iscpf) + & - mean_aroot * number_fraction * pa_per_mpa ! [Pa] + mean_aroot = sum(ccohort_hydr%psi_aroot(:)*ccohort_hydr%v_aroot_layer(:)) / & + sum(ccohort_hydr%v_aroot_layer(:)) - hio_twp_scpf(io_si,iscpf) = hio_twp_scpf(io_si,iscpf) + & - ccohort_hydr%psi_troot * number_fraction * pa_per_mpa ! [Pa] + hio_awp_scpf(io_si,iscpf) = hio_awp_scpf(io_si,iscpf) + & + mean_aroot * number_fraction * pa_per_mpa ! [Pa] - hio_swp_scpf(io_si,iscpf) = hio_swp_scpf(io_si,iscpf) + & - ccohort_hydr%psi_ag(2) * number_fraction * pa_per_mpa ! [Pa] + hio_twp_scpf(io_si,iscpf) = hio_twp_scpf(io_si,iscpf) + & + ccohort_hydr%psi_troot * number_fraction * pa_per_mpa ! [Pa] - hio_lwp_scpf(io_si,iscpf) = hio_lwp_scpf(io_si,iscpf) + & - ccohort_hydr%psi_ag(1) * number_fraction * pa_per_mpa ! [Pa] + hio_swp_scpf(io_si,iscpf) = hio_swp_scpf(io_si,iscpf) + & + ccohort_hydr%psi_ag(2) * number_fraction * pa_per_mpa ! [Pa] - mean_aroot = sum(ccohort_hydr%ftc_aroot(:)*ccohort_hydr%v_aroot_layer(:)) / & - sum(ccohort_hydr%v_aroot_layer(:)) - hio_aflc_scpf(io_si,iscpf) = hio_aflc_scpf(io_si,iscpf) + & - mean_aroot * number_fraction + hio_lwp_scpf(io_si,iscpf) = hio_lwp_scpf(io_si,iscpf) + & + ccohort_hydr%psi_ag(1) * number_fraction * pa_per_mpa ! [Pa] - hio_tflc_scpf(io_si,iscpf) = hio_tflc_scpf(io_si,iscpf) + & - ccohort_hydr%ftc_troot * number_fraction + mean_aroot = sum(ccohort_hydr%ftc_aroot(:)*ccohort_hydr%v_aroot_layer(:)) / & + sum(ccohort_hydr%v_aroot_layer(:)) + hio_aflc_scpf(io_si,iscpf) = hio_aflc_scpf(io_si,iscpf) + & + mean_aroot * number_fraction - hio_sflc_scpf(io_si,iscpf) = hio_sflc_scpf(io_si,iscpf) + & - ccohort_hydr%ftc_ag(2) * number_fraction + hio_tflc_scpf(io_si,iscpf) = hio_tflc_scpf(io_si,iscpf) + & + ccohort_hydr%ftc_troot * number_fraction - hio_lflc_scpf(io_si,iscpf) = hio_lflc_scpf(io_si,iscpf) + & - ccohort_hydr%ftc_ag(1) * number_fraction + hio_sflc_scpf(io_si,iscpf) = hio_sflc_scpf(io_si,iscpf) + & + ccohort_hydr%ftc_ag(2) * number_fraction - hio_btran_scpf(io_si,iscpf) = hio_btran_scpf(io_si,iscpf) + & - ccohort_hydr%btran * number_fraction ! [-] + hio_lflc_scpf(io_si,iscpf) = hio_lflc_scpf(io_si,iscpf) + & + ccohort_hydr%ftc_ag(1) * number_fraction - endif + hio_btran_scpf(io_si,iscpf) = hio_btran_scpf(io_si,iscpf) + & + ccohort_hydr%btran * number_fraction ! [-] - ccohort => ccohort%taller - enddo ! cohort loop + endif - cpatch => cpatch%younger - end do !patch loop + ccohort => ccohort%taller + enddo ! cohort loop - 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)*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 - write(fates_log(),*) 'scpf:',iscpf - write(fates_log(),*) 'io_si:',io_si - write(fates_log(),*) 'hio_nplant_si_scpf:',hio_nplant_si_scpf(io_si, iscpf) - write(fates_log(),*) 'nplant_scpf:',nplant_scpf(iscpf) - write(fates_log(),*) 'nplant check on hio_nplant_si_scpf fails during hydraulics history updates' - call endrun(msg=errMsg(sourcefile, __LINE__)) - end if - end do - end if + cpatch => cpatch%younger + end do !patch loop - end do - end associate + 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)*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 + write(fates_log(),*) 'scpf:',iscpf + write(fates_log(),*) 'io_si:',io_si + write(fates_log(),*) 'hio_nplant_si_scpf:',hio_nplant_si_scpf(io_si, iscpf) + write(fates_log(),*) 'nplant_scpf:',nplant_scpf(iscpf) + write(fates_log(),*) 'nplant check on hio_nplant_si_scpf fails during hydraulics history updates' + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + end do + end if + + end do + end associate - end if if_hifrq1 + end if if_hifrq1 - end subroutine update_history_hydraulics + end subroutine update_history_hydraulics - ! ==================================================================================== - integer function num_history_vars(this) + ! ==================================================================================== + integer function num_history_vars(this) - implicit none + implicit none - class(fates_history_interface_type), intent(in) :: this + class(fates_history_interface_type), intent(in) :: this - num_history_vars = this%num_history_vars_ + num_history_vars = this%num_history_vars_ - end function num_history_vars + end function num_history_vars - ! ==================================================================================== + ! ==================================================================================== - subroutine initialize_history_vars(this) + subroutine initialize_history_vars(this) - implicit none + implicit none - class(fates_history_interface_type), intent(inout) :: this + class(fates_history_interface_type), intent(inout) :: this - ! Determine how many of the history IO variables registered in FATES - ! are going to be allocated - call this%define_history_vars(initialize_variables=.false.) + ! Determine how many of the history IO variables registered in FATES + ! are going to be allocated + call this%define_history_vars(initialize_variables=.false.) - ! Allocate the list of history output variable objects - allocate(this%hvars(this%num_history_vars())) + ! Allocate the list of history output variable objects + allocate(this%hvars(this%num_history_vars())) - ! construct the object that defines all of the IO variables - call this%define_history_vars(initialize_variables=.true.) - - end subroutine initialize_history_vars - - ! ==================================================================================== - - function per_ageclass_norm_info(this, norm_var) - - ! --------------------------------------------------------------------------------- - ! Produces a bit of text to include in long_name of variables with age-class axes, - ! explaining how to get real per-ageclass values if needed. - ! --------------------------------------------------------------------------------- - ! - ! Arguments - class(fates_history_interface_type) :: this ! Not used, but needed for a function in this type - character(len=*), intent(in) :: norm_var ! The variable(s) that this one should be multiplied by to get actual values - ! - ! Result - character(len=fates_long_string_length) :: per_ageclass_norm_info - - per_ageclass_norm_info = "; for real per-age values, mult by " // norm_var - - end function per_ageclass_norm_info - - ! ==================================================================================== - - subroutine define_history_vars(this, initialize_variables) - - ! --------------------------------------------------------------------------------- - ! - ! REGISTRY OF HISTORY OUTPUT VARIABLES - ! - ! This subroutine is called in two contexts, either in count mode or initialize mode - ! In count mode, we just walk through the list of registerred variables, compare - ! if the variable of interest list the current host model and add it to the count - ! if true. This count is used just to allocate the variable space. After this - ! has been done, we go through the list a second time populating a memory structure. - ! This phase is the "initialize" phase. These two phases are differntiated by the - ! string "callstep", which should be either "count" or "initialize". - ! - ! Note 1 there are different ways you can flush or initialize the output fields. - ! If you flush to a native type, (such as zero), the entire slab which covers - ! indices which may not be relevant to FATES, are flushed to this value. So - ! in that case, lakes and crops that are not controlled by FATES will zero'd - ! and when values are scaled up to the land-grid, the zero's for non FATES will - ! be included. This is good and correct if nothing is there. - ! - ! But, what if crops exist in the host model and occupy a fraction of the land-surface - ! shared with natural vegetation? In that case, you want to flush your arrays - ! with a value that the HLM treats as "do not average" - ! - ! If your HLM makes use of, and you want, INTEGER OUTPUT, pass the flushval as - ! a real. The applied flush value will use the NINT() intrinsic function - ! --------------------------------------------------------------------------------- - - use FatesIOVariableKindMod, only : site_r8, site_soil_r8, site_size_pft_r8 - use FatesIOVariableKindMod, only : site_size_r8, site_pft_r8, site_age_r8 - use FatesIOVariableKindMod, only : site_coage_pft_r8, site_coage_r8 - use FatesIOVariableKindMod, only : site_height_r8, site_agefuel_r8 - use FatesInterfaceTypesMod, only : hlm_use_planthydro - - 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, site_clscpf_r8 - use FatesIOVariableKindMod, only : site_elcwd_r8, site_elage_r8 + ! construct the object that defines all of the IO variables + call this%define_history_vars(initialize_variables=.true.) - - implicit none - - class(fates_history_interface_type), intent(inout) :: this - logical, intent(in) :: initialize_variables ! are we 'count'ing or 'initializ'ing? - - integer :: ivar - character(len=10) :: tempstring - - ivar=0 - - ! Variable names should start with the 'FATES_' prefix and end with a suffix - ! depending on how it is indexed (i.e. the dimension): - ! site (site_r8) : no suffix - ! cohort age (site_coage_r8) : AC - ! patch age (site_age_r8) : AP - ! canopy layer (site_can_r8) : CL - ! coarse woody debris size (site_cwdsc_r8) : DC - ! element (site_elem_r8) : EL - ! leaf layer : LL - ! fuel class (site_fuel_r8) : FC - ! height (site_height_r8) : HT - ! 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 - ! patch age x pft (site_agepft_r8) : APPF - ! canopy layer x leaf layer (site_cnlf_r8) : CLLL - ! canopy layer x leaf layer x pft (site_cnlfpft_r8) : CLLLPF - ! element x cwd size (site_elcwd_r8) : ELDC - ! 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 - - - if_dyn0: if(hlm_hist_level_dynam>0) then - - ! Site level counting variables - call this%set_history_var(vname='FATES_NPATCHES', units='', & + end subroutine initialize_history_vars + + ! ==================================================================================== + + function per_ageclass_norm_info(this, norm_var) + + ! --------------------------------------------------------------------------------- + ! Produces a bit of text to include in long_name of variables with age-class axes, + ! explaining how to get real per-ageclass values if needed. + ! --------------------------------------------------------------------------------- + ! + ! Arguments + class(fates_history_interface_type) :: this ! Not used, but needed for a function in this type + character(len=*), intent(in) :: norm_var ! The variable(s) that this one should be multiplied by to get actual values + ! + ! Result + character(len=fates_long_string_length) :: per_ageclass_norm_info + + per_ageclass_norm_info = "; for real per-age values, mult by " // norm_var + + end function per_ageclass_norm_info + + ! ==================================================================================== + + subroutine define_history_vars(this, initialize_variables) + + ! --------------------------------------------------------------------------------- + ! + ! REGISTRY OF HISTORY OUTPUT VARIABLES + ! + ! This subroutine is called in two contexts, either in count mode or initialize mode + ! In count mode, we just walk through the list of registerred variables, compare + ! if the variable of interest list the current host model and add it to the count + ! if true. This count is used just to allocate the variable space. After this + ! has been done, we go through the list a second time populating a memory structure. + ! This phase is the "initialize" phase. These two phases are differntiated by the + ! string "callstep", which should be either "count" or "initialize". + ! + ! Note 1 there are different ways you can flush or initialize the output fields. + ! If you flush to a native type, (such as zero), the entire slab which covers + ! indices which may not be relevant to FATES, are flushed to this value. So + ! in that case, lakes and crops that are not controlled by FATES will zero'd + ! and when values are scaled up to the land-grid, the zero's for non FATES will + ! be included. This is good and correct if nothing is there. + ! + ! But, what if crops exist in the host model and occupy a fraction of the land-surface + ! shared with natural vegetation? In that case, you want to flush your arrays + ! with a value that the HLM treats as "do not average" + ! + ! If your HLM makes use of, and you want, INTEGER OUTPUT, pass the flushval as + ! a real. The applied flush value will use the NINT() intrinsic function + ! --------------------------------------------------------------------------------- + + use FatesIOVariableKindMod, only : site_r8, site_soil_r8, site_size_pft_r8 + use FatesIOVariableKindMod, only : site_size_r8, site_pft_r8, site_age_r8 + use FatesIOVariableKindMod, only : site_coage_pft_r8, site_coage_r8 + use FatesIOVariableKindMod, only : site_height_r8, site_agefuel_r8 + use FatesInterfaceTypesMod, only : hlm_use_planthydro + + 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, site_clscpf_r8 + use FatesIOVariableKindMod, only : site_elcwd_r8, site_elage_r8 + + + implicit none + + class(fates_history_interface_type), intent(inout) :: this + logical, intent(in) :: initialize_variables ! are we 'count'ing or 'initializ'ing? + + integer :: ivar + character(len=10) :: tempstring + + ivar=0 + + ! Variable names should start with the 'FATES_' prefix and end with a suffix + ! depending on how it is indexed (i.e. the dimension): + ! site (site_r8) : no suffix + ! cohort age (site_coage_r8) : AC + ! patch age (site_age_r8) : AP + ! canopy layer (site_can_r8) : CL + ! coarse woody debris size (site_cwdsc_r8) : DC + ! element (site_elem_r8) : EL + ! leaf layer : LL + ! fuel class (site_fuel_r8) : FC + ! height (site_height_r8) : HT + ! 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 + ! patch age x pft (site_agepft_r8) : APPF + ! canopy layer x leaf layer (site_cnlf_r8) : CLLL + ! canopy layer x leaf layer x pft (site_cnlfpft_r8) : CLLLPF + ! element x cwd size (site_elcwd_r8) : ELDC + ! 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 + + + if_dyn0: if(hlm_hist_level_dynam>0) then + + ! Site level counting variables + call this%set_history_var(vname='FATES_NPATCHES', units='', & long='total number of patches per site', use_default='active', & avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index=ih_npatches_si) - call this%set_history_var(vname='FATES_NCOHORTS', units='', & + call this%set_history_var(vname='FATES_NCOHORTS', units='', & long='total number of cohorts per site', use_default='active', & avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index=ih_ncohorts_si) - ! Patch variables - call this%set_history_var(vname='FATES_TRIMMING', units='1', & + ! 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)', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index=ih_trimming_si) - call this%set_history_var(vname='FATES_AREA_PLANTS', units='m2 m-2', & + 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=group_dyna_simple, ivar=ivar, & initialize=initialize_variables, index=ih_fracarea_plant_si) - call this%set_history_var(vname='FATES_AREA_TREES', units='m2 m-2', & + call this%set_history_var(vname='FATES_AREA_TREES', units='m2 m-2', & long='area occupied by woody plants per m2 land area', use_default='active', & avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index=ih_fracarea_trees_si) - call this%set_history_var(vname='FATES_FRACTION', units='m2 m-2', & + 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=group_dyna_simple, 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', & + 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=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index=ih_ba_weighted_height_si) - call this%set_history_var(vname='FATES_CA_WEIGHTED_HEIGHT', units='m', & + 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=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index=ih_ca_weighted_height_si) - call this%set_history_var(vname='FATES_COLD_STATUS', units='', & + 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=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index=ih_site_cstatus_si) - call this%set_history_var(vname='FATES_GDD', units='degree_Celsius', & + 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', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, index=ih_gdd_si) - call this%set_history_var(vname='FATES_NCHILLDAYS', units = 'days', & + call this%set_history_var(vname='FATES_NCHILLDAYS', units = 'days', & long='site-level number of chill days', use_default='active', & avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index=ih_site_nchilldays_si) - call this%set_history_var(vname='FATES_NCOLDDAYS', units = 'days', & + call this%set_history_var(vname='FATES_NCOLDDAYS', units = 'days', & long='site-level number of cold days', use_default='active', & avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index=ih_site_ncolddays_si) - call this%set_history_var(vname='FATES_DAYSINCE_COLDLEAFOFF', & + call this%set_history_var(vname='FATES_DAYSINCE_COLDLEAFOFF', & units='days', long='site-level days elapsed since cold leaf drop', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index=ih_cleafoff_si) - call this%set_history_var(vname='FATES_DAYSINCE_COLDLEAFON', & + call this%set_history_var(vname='FATES_DAYSINCE_COLDLEAFON', & units='days', long='site-level days elapsed since cold leaf flush', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index=ih_cleafon_si) - call this%set_history_var(vname='FATES_CANOPY_SPREAD', units='', & + 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=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index=ih_canopy_spread_si) - call this%set_history_var(vname='FATES_LAI', units='m2 m-2', & + call this%set_history_var(vname='FATES_LAI', units='m2 m-2', & long='total leaf area index per m2 land area', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index=ih_lai_si) - - call this%set_history_var(vname='FATES_ELAI', units='m2 m-2', & + + call this%set_history_var(vname='FATES_ELAI', units='m2 m-2', & long='exposed (non snow-occluded) leaf area index per m2 land area', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index=ih_elai_si) - - ! Fire Variables - call this%set_history_var(vname='FATES_NESTEROV_INDEX', units='', & + ! Fire Variables + + call this%set_history_var(vname='FATES_NESTEROV_INDEX', units='', & long='nesterov fire danger index', use_default='active', & avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index=ih_nesterov_fire_danger_si) - - call this%set_history_var(vname='FATES_RX_BURN_WINDOW', units='', & + + call this%set_history_var(vname='FATES_RX_BURN_WINDOW', units='', & long='fraction of time when prescribed fire burn window presents', & use_default='active',avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=1, ivar=ivar, initialize=initialize_variables, & index=ih_rx_burn_window_si) - call this%set_history_var(vname='FATES_IGNITIONS', & + call this%set_history_var(vname='FATES_IGNITIONS', & units='m-2 s-1', & long='number of successful fire ignitions per m2 land area per second', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index=ih_fire_nignitions_si) - call this%set_history_var(vname='FATES_FDI', units='1', & + call this%set_history_var(vname='FATES_FDI', units='1', & long='Fire Danger Index (probability that an ignition will lead to a fire)', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index=ih_fire_fdi_si) - call this%set_history_var(vname='FATES_ROS', units='m s-1', & + call this%set_history_var(vname='FATES_ROS', units='m s-1', & long='fire rate of spread in meters per second', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index=ih_spitfire_ros_si) - call this%set_history_var(vname='FATES_EFFECT_WSPEED', units='m s-1', & + call this%set_history_var(vname='FATES_EFFECT_WSPEED', units='m s-1', & long ='effective wind speed for fire spread in meters per second', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index=ih_effect_wspeed_si) - call this%set_history_var(vname='FATES_FUELCONSUMED', units='kg m-2', & + call this%set_history_var(vname='FATES_FUELCONSUMED', units='kg m-2', & long ='total fuel consumed in kg carbon per m2 land area', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index=ih_tfc_ros_si) - call this%set_history_var(vname='FATES_FIRE_INTENSITY', & + call this%set_history_var(vname='FATES_FIRE_INTENSITY', & units='J m-1 s-1', & long='spitfire surface fireline intensity in J per m per second, sum of rx and wildfire', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index=ih_fire_intensity_si) - call this%set_history_var(vname='FATES_FIRE_INTENSITY_BURNFRAC', & + call this%set_history_var(vname='FATES_FIRE_INTENSITY_BURNFRAC', & units='J m-1 s-1', & long='product of surface fire intensity and burned area fraction, sum of rx and wildfire-- divide by FATES_BURNFRAC to get area-weighted mean intensity', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index=ih_fire_intensity_fracarea_product_si) - call this%set_history_var(vname='FATES_WILDFIRE_INTENSITY', & + call this%set_history_var(vname='FATES_WILDFIRE_INTENSITY', & units='J m-1 s-1', & long='spitfire surface fireline intensity of wildfire in J per m per second', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index=ih_nonrx_intensity_si) - call this%set_history_var(vname='FATES_WILDFIRE_INTENSITY_BURNFRAC', & + call this%set_history_var(vname='FATES_WILDFIRE_INTENSITY_BURNFRAC', & units='J m-1 s-1', & long='product of wildfire intensity and burned fraction -- divide by FATES_WILDFIRE_BURNFRAC to get area-weighted mean intensity', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index=ih_nonrx_intensity_fracarea_product_si) - - call this%set_history_var(vname='FATES_RXFIRE_INTENSITY', & + + call this%set_history_var(vname='FATES_RXFIRE_INTENSITY', & units='J m-1 s-1', & long='spitfire surface fireline intensity of prescribed fire in J per m per second', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=1, ivar=ivar, initialize=initialize_variables, & index=ih_rx_intensity_si) - - call this%set_history_var(vname='FATES_RXFIRE_INTENSITY_BURNFRAC', & + + call this%set_history_var(vname='FATES_RXFIRE_INTENSITY_BURNFRAC', & units='J m-1 s-1', & long='product of prescribed fire intensity and burned fraction -- to be devided by FATES_RXFIRE_BURNFRAC to get area-weighted mean intensity', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=1, ivar=ivar, initialize=initialize_variables, & index=ih_rx_intensity_fracarea_product_si) - call this%set_history_var(vname='FATES_BURNFRAC', units='s-1', & + call this%set_history_var(vname='FATES_BURNFRAC', units='s-1', & long='totaL burned area fraction per second -- sum of rxfire and wildfire burnt frac', use_default='active', & avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index=ih_fire_fracarea_si) - call this%set_history_var(vname='FATES_WILDFIRE_BURNFRAC', units='s-1', & + call this%set_history_var(vname='FATES_WILDFIRE_BURNFRAC', units='s-1', & long='burned area fraction per second by wildfire', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=1, ivar=ivar, initialize=initialize_variables, & index=ih_nonrx_fracarea_si) - - call this%set_history_var(vname='FATES_RXFIRE_BURNFRAC', units='s-1', & + + call this%set_history_var(vname='FATES_RXFIRE_BURNFRAC', units='s-1', & long='burned area fraction per second by prescribed fire', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=1, ivar=ivar, initialize=initialize_variables, & index=ih_rx_fracarea_si) - - call this%set_history_var(vname='FATES_RXFIRE_BURNABLE_FUEL', units='', & + + call this%set_history_var(vname='FATES_RXFIRE_BURNABLE_FUEL', units='', & long='burnable area fraction by Rx fire when fuel cond. met', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=1, ivar=ivar, initialize=initialize_variables, & index=ih_rx_fracarea_fuel_si) - - call this%set_history_var(vname='FATES_RXFIRE_BURNABLE_FI', units='', & + + call this%set_history_var(vname='FATES_RXFIRE_BURNABLE_FI', units='', & long='burnable area fraction by Rx fire when fuel and FI cond. met', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=1, ivar=ivar, initialize=initialize_variables, & index=ih_rx_fracarea_fi_si) - - call this%set_history_var(vname='FATES_RXFIRE_BURNABLE_FINAL', units='', & + + call this%set_history_var(vname='FATES_RXFIRE_BURNABLE_FINAL', units='', & long='burnable area fraction by Rx fire when all cond. met', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=1, ivar=ivar, initialize=initialize_variables, & index=ih_rx_fracarea_final_si) - call this%set_history_var(vname='FATES_FUEL_MEF', units='m3 m-3', & - long='fuel moisture of extinction (volumetric)', & + call this%set_history_var(vname='FATES_FUEL_MEF_DEAD', units='m3 m-3', & + long='dead fuel moisture of extinction (volumetric)', & + use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & + upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & + index=ih_fire_fuel_mef_dead_si) + + call this%set_history_var(vname='FATES_FUEL_MEF_LIVE', units='m3 m-3', & + long='live fuel moisture of extinction (volumetric)', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & - index=ih_fire_fuel_mef_si) + index=ih_fire_fuel_mef_live_si) - call this%set_history_var(vname='FATES_FUEL_BULKD', & + call this%set_history_var(vname='FATES_FUEL_BULKD', & units='kg m-3', long='fuel bulk density in kg per m3', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index = ih_fire_fuel_bulkd_si ) - call this%set_history_var(vname='FATES_FUEL_EFF_MOIST', units='m3 m-3', & - long='spitfire fuel moisture (volumetric)', use_default='active', & + call this%set_history_var(vname='FATES_FUEL_EFF_MOIST_DEAD', units='m3 m-3', & + long='spitfire dead fuel moisture (volumetric)', use_default='active', & + avgflag='A', vtype=site_r8, hlms='CLM:ALM', upfreq=group_dyna_simple, ivar=ivar, & + initialize=initialize_variables, index = ih_fire_fuel_moist_dead_si) + + call this%set_history_var(vname='FATES_FUEL_EFF_MOIST_LIVE', units='m3 m-3', & + long='spitfire live fuel moisture (volumetric)', use_default='active', & avgflag='A', vtype=site_r8, hlms='CLM:ALM', upfreq=group_dyna_simple, ivar=ivar, & - initialize=initialize_variables, index = ih_fire_fuel_eff_moist_si) + initialize=initialize_variables, index = ih_fire_fuel_moist_live_si) - call this%set_history_var(vname='FATES_FUEL_SAV', units='m-1', & + 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=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index = ih_fire_fuel_sav_si) - call this%set_history_var(vname='FATES_FUEL_AMOUNT', units='kg m-2', & - long='total ground fuel related to FATES_ROS (omits 1000hr fuels) in kg C per m2 land area', & + call this%set_history_var(vname='FATES_FUEL_AMOUNT', units='kg m-2', & + long='total ground fuel not weighted by fuel SAV in kg C per m2 land area', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index = ih_sum_fuel_si) - ! Litter Variables - call this%set_history_var(vname='FATES_LITTER_IN', units='kg m-2 s-1', & + call this%set_history_var(vname='FATES_FUEL_AMOUNT_WEIGHTED', units='kg m-2', & + long='total ground fuel weighted by fuel SAV and is related to FATES_ROS (omits 1000hr fuels) in kg C per m2 land area', & + use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & + upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & + index = ih_weighted_sum_fuel_si) + ! Litter Variables + + call this%set_history_var(vname='FATES_LITTER_IN', units='kg m-2 s-1', & long='litter flux in kg carbon per m2 per second', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index = ih_litter_in_si) - call this%set_history_var(vname='FATES_LITTER_OUT', units='kg m-2 s-1', & + call this%set_history_var(vname='FATES_LITTER_OUT', units='kg m-2 s-1', & long='litter flux out in kg carbon (exudation, fragmentation, seed decay)', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index = ih_litter_out_si) - call this%set_history_var(vname='FATES_SEED_BANK', units='kg m-2', & + call this%set_history_var(vname='FATES_SEED_BANK', units='kg m-2', & long='total seed mass of all PFTs in kg carbon per m2 land area', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index = ih_seed_bank_si) - call this%set_history_var(vname='FATES_UNGERM_SEED_BANK', units='kg m-2', & + 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=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index = ih_ungerm_seed_bank_si) - call this%set_history_var(vname='FATES_SEEDLING_POOL', units='kg m-2', & + 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=group_dyna_simple, 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', & + 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', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, 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', & + 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=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index = ih_seeds_in_local_si) - call this%set_history_var(vname='FATES_STOREC', units='kg m-2', & + call this%set_history_var(vname='FATES_STOREC', units='kg m-2', & long='total biomass in live plant storage in kg carbon per m2 land area', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index = ih_storec_si) - call this%set_history_var(vname='FATES_STOREC_TF', units='kg kg-1', & + 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=group_dyna_simple, & ivar=ivar, initialize=initialize_variables, index = ih_storectfrac_si ) - call this%set_history_var(vname='FATES_VEGC', units='kg m-2', & + 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', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index = ih_totvegc_si) - call this%set_history_var(vname='FATES_SAPWOODC', units='kg m-2', & + call this%set_history_var(vname='FATES_SAPWOODC', units='kg m-2', & long='total biomass in live plant sapwood in kg carbon per m2', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index = ih_sapwc_si) - call this%set_history_var(vname='FATES_LEAFC', units='kg m-2', & + call this%set_history_var(vname='FATES_LEAFC', units='kg m-2', & long='total biomass in live plant leaves in kg carbon per m2', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index = ih_leafc_si) - call this%set_history_var(vname='FATES_FROOTC', units='kg m-2', & + call this%set_history_var(vname='FATES_FROOTC', units='kg m-2', & long='total biomass in live plant fine roots in kg carbon per m2', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index = ih_fnrtc_si) - call this%set_history_var(vname='FATES_REPROC', units='kg m-2', & + 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=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index = ih_reproc_si) - call this%set_history_var(vname='FATES_NPP', units='kg m-2 s-1', & + call this%set_history_var(vname='FATES_NPP', units='kg m-2 s-1', & long='net primary production in kg carbon per m2 per second', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, index = ih_npp_si) - call this%set_history_var(vname='FATES_AUTORESP', units='kg m-2 s-1', & + 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=group_dyna_simple, ivar=ivar, initialize=initialize_variables, index = ih_aresp_si) - call this%set_history_var(vname='FATES_GROWTH_RESP', units='kg m-2 s-1', & + 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=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index = ih_growth_resp_si) - ! Output specific to the chemical species dynamics used (parteh) - call this%set_history_var(vname='FATES_L2FR', units='kg kg-1', & - long='The leaf to fineroot biomass multiplier for target allometry', & + ! Output specific to the chemical species dynamics used (parteh) + 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=group_dyna_simple, & ivar=ivar, initialize=initialize_variables, index = ih_l2fr_si) - nitrogen_active_if0: if(any(element_list(:)==nitrogen_element)) then + nitrogen_active_if0: if(any(element_list(:)==nitrogen_element)) then - call this%set_history_var(vname='FATES_NH4UPTAKE', units='kg m-2 s-1', & + 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=group_nflx_simple, ivar=ivar, initialize=initialize_variables, & index = ih_nh4uptake_si) - call this%set_history_var(vname='FATES_NO3UPTAKE', units='kg m-2 s-1', & + 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=group_nflx_simple, ivar=ivar, initialize=initialize_variables, & index = ih_no3uptake_si) - call this%set_history_var(vname='FATES_NEFFLUX', units='kg m-2 s-1', & + 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=group_nflx_simple, ivar=ivar, initialize=initialize_variables, & index = ih_nefflux_si) - call this%set_history_var(vname='FATES_NDEMAND', units='kg m-2 s-1', & + 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=group_nflx_simple, ivar=ivar, initialize=initialize_variables, & index = ih_ndemand_si) - - call this%set_history_var(vname='FATES_NFIX_SYM', units='kg m-2 s-1', & + + 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=group_nflx_simple, ivar=ivar, initialize=initialize_variables, & index = ih_nfix_si) - - call this%set_history_var(vname='FATES_STOREN', units='kg m-2', & + + 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=group_dyna_simple, & ivar=ivar, initialize=initialize_variables, index = ih_storen_si) - call this%set_history_var(vname='FATES_STOREN_TF', units='1', & + 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=group_dyna_simple, ivar=ivar, & initialize=initialize_variables, index = ih_storentfrac_si) - call this%set_history_var(vname='FATES_VEGN', units='kg m-2', & + 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=group_dyna_simple, ivar=ivar, & initialize=initialize_variables, index = ih_totvegn_si) - call this%set_history_var(vname='FATES_SAPWOODN', units='kg m-2', & + call this%set_history_var(vname='FATES_SAPWOODN', units='kg m-2', & long='total nitrogen in live plant sapwood', use_default='active', & avgflag='A', vtype=site_r8, hlms='CLM:ALM', upfreq=group_dyna_simple, & ivar=ivar, initialize=initialize_variables, index = ih_sapwn_si) - call this%set_history_var(vname='FATES_LEAFN', units='kg m-2', & + call this%set_history_var(vname='FATES_LEAFN', units='kg m-2', & long='total nitrogen in live plant leaves', use_default='active', & avgflag='A', vtype=site_r8, hlms='CLM:ALM', upfreq=group_dyna_simple, ivar=ivar, & initialize=initialize_variables, index = ih_leafn_si) - call this%set_history_var(vname='FATES_FROOTN', units='kg m-2', & + call this%set_history_var(vname='FATES_FROOTN', units='kg m-2', & long='total nitrogen in live plant fine-roots', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index = ih_fnrtn_si) - call this%set_history_var(vname='FATES_REPRON', units='kg m-2', & + call this%set_history_var(vname='FATES_REPRON', units='kg m-2', & long='total nitrogen in live plant reproductive tissues', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index = ih_repron_si) - end if nitrogen_active_if0 + end if nitrogen_active_if0 - phosphorus_active_if0: if(any(element_list(:)==phosphorus_element)) then - call this%set_history_var(vname='FATES_STOREP', units='kg m-2', & + phosphorus_active_if0: if(any(element_list(:)==phosphorus_element)) then + call this%set_history_var(vname='FATES_STOREP', units='kg m-2', & long='total phosphorus in live plant storage', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index = ih_storep_si) - call this%set_history_var(vname='FATES_STOREP_TF', units='1', & + call this%set_history_var(vname='FATES_STOREP_TF', units='1', & long='storage P fraction of target', use_default='active', & avgflag='A', vtype=site_r8, hlms='CLM:ALM', upfreq=group_dyna_simple, & ivar=ivar, initialize=initialize_variables, & index = ih_storeptfrac_si) - call this%set_history_var(vname='FATES_VEGP', units='kg m-2', & + call this%set_history_var(vname='FATES_VEGP', units='kg m-2', & long='total phosphorus in live plants', use_default='active', & avgflag='A', vtype=site_r8, hlms='CLM:ALM', upfreq=group_dyna_simple, & ivar=ivar, initialize=initialize_variables, index = ih_totvegp_si) - call this%set_history_var(vname='FATES_SAPWOODP', units='kg m-2', & + call this%set_history_var(vname='FATES_SAPWOODP', units='kg m-2', & long='Total phosphorus in live plant sapwood', use_default='active', & avgflag='A', vtype=site_r8, hlms='CLM:ALM', upfreq=group_dyna_simple, ivar=ivar, & initialize=initialize_variables, index = ih_sapwp_si) - call this%set_history_var(vname='FATES_LEAFP', units='kg m-2', & + call this%set_history_var(vname='FATES_LEAFP', units='kg m-2', & long='total phosphorus in live plant leaves', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index = ih_leafp_si) - call this%set_history_var(vname='FATES_FROOTP', units='kg m-2', & + call this%set_history_var(vname='FATES_FROOTP', units='kg m-2', & long='total phosphorus in live plant fine roots', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index = ih_fnrtp_si) - call this%set_history_var(vname='FATES_REPROP', units='kg m-2', & + call this%set_history_var(vname='FATES_REPROP', units='kg m-2', & long='total phosphorus in live plant reproductive tissues', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index = ih_reprop_si) - call this%set_history_var(vname='FATES_PUPTAKE', units='kg m-2 s-1', & + 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=group_nflx_simple, ivar=ivar, initialize=initialize_variables, & index = ih_puptake_si) - call this%set_history_var(vname='FATES_PEFFLUX', units='kg m-2 s-1', & + 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=group_nflx_simple, ivar=ivar, initialize=initialize_variables, & index = ih_pefflux_si) - call this%set_history_var(vname='FATES_PDEMAND', 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=group_nflx_simple, ivar=ivar, initialize=initialize_variables, & index = ih_pdemand_si) - - end if phosphorus_active_if0 - call this%set_history_var(vname='FATES_STRUCTC', units='kg m-2', & + end if phosphorus_active_if0 + + call this%set_history_var(vname='FATES_STRUCTC', units='kg m-2', & long='structural biomass in kg carbon per m2 land area', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index = ih_bdead_si) - call this%set_history_var(vname='FATES_NONSTRUCTC', units='kg m-2', & + call this%set_history_var(vname='FATES_NONSTRUCTC', units='kg m-2', & long='non-structural biomass (sapwood + leaf + fineroot) in kg carbon per m2', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index = ih_balive_si) - call this%set_history_var(vname='FATES_VEGC_ABOVEGROUND', units='kg m-2', & + call this%set_history_var(vname='FATES_VEGC_ABOVEGROUND', units='kg m-2', & long='aboveground biomass in kg carbon per m2 land area', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index = ih_agb_si) - call this%set_history_var(vname='FATES_CANOPY_VEGC', units='kg m-2', & + call this%set_history_var(vname='FATES_CANOPY_VEGC', units='kg m-2', & long='biomass of canopy plants in kg carbon per m2 land area', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index = ih_canopy_biomass_si) - call this%set_history_var(vname='FATES_USTORY_VEGC', units='kg m-2', & + call this%set_history_var(vname='FATES_USTORY_VEGC', units='kg m-2', & long='biomass of understory plants in kg carbon per m2 land area', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index = ih_understory_biomass_si) - ! disturbance rates + ! disturbance rates - call this%set_history_var(vname='FATES_PRIMARY_PATCHFUSION_ERR', & + call this%set_history_var(vname='FATES_PRIMARY_PATCHFUSION_ERR', & units='m2 m-2 yr-1', & long='error in total primary lands associated with patch fusion', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index = ih_primaryland_fusion_error_si) - call this%set_history_var(vname='FATES_DISTURBANCE_RATE_FIRE', & + call this%set_history_var(vname='FATES_DISTURBANCE_RATE_FIRE', & units='m2 m-2 yr-1', long='disturbance rate from fire', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index = ih_fire_disturbance_rate_si) - call this%set_history_var(vname='FATES_DISTURBANCE_RATE_LOGGING', & + call this%set_history_var(vname='FATES_DISTURBANCE_RATE_LOGGING', & units='m2 m-2 yr-1', long='disturbance rate from logging', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index = ih_logging_disturbance_rate_si) - call this%set_history_var(vname='FATES_DISTURBANCE_RATE_TREEFALL', & + call this%set_history_var(vname='FATES_DISTURBANCE_RATE_TREEFALL', & units='m2 m-2 yr-1', long='disturbance rate from treefall', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index = ih_fall_disturbance_rate_si) - - call this%set_history_var(vname='FATES_HARVEST_WOODPROD_C_FLUX', & + + call this%set_history_var(vname='FATES_HARVEST_WOODPROD_C_FLUX', & units='kg m-2 yr-1', & long='harvest-associated wood product carbon flux in kg C per m2 per year', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index = ih_harvest_woodprod_carbonflux_si) - - call this%set_history_var(vname='FATES_LUCHANGE_WOODPROD_C_FLUX', & + + call this%set_history_var(vname='FATES_LUCHANGE_WOODPROD_C_FLUX', & units='kg m-2 yr-1', & long='land-use-change-associated wood product carbon flux in kg C per m2 per year', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index = ih_luchange_woodprod_carbonflux_si) - - call this%set_history_var(vname='FATES_TVEG24', units='degree_Celsius', & + + 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=group_dyna_simple, & ivar=ivar, initialize=initialize_variables, index = ih_tveg24_si ) - call this%set_history_var(vname='FATES_TLONGTERM', units='degree_Celsius', & + 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=group_dyna_simple, & ivar=ivar, initialize=initialize_variables, index = ih_tlongterm_si ) - call this%set_history_var(vname='FATES_TGROWTH', units='degree_Celsius', & + 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=group_dyna_simple, & ivar=ivar, initialize=initialize_variables, index = ih_tgrowth_si ) - call this%set_history_var(vname='FATES_HARVEST_DEBT', units='kg C', & + 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=group_dyna_simple, & ivar=ivar, initialize=initialize_variables, index = ih_harvest_debt_si ) - call this%set_history_var(vname='FATES_HARVEST_DEBT_SEC', units='kg C', & + 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=group_dyna_simple, & ivar=ivar, initialize=initialize_variables, index = ih_harvest_debt_sec_si ) - ! Nutrient flux variables (dynamics call frequency) - ! ---------------------------------------------------- - call this%set_history_var(vname='FATES_EXCESS_RESP', units='kg m-2 s-1', & + ! Nutrient flux variables (dynamics call frequency) + ! ---------------------------------------------------- + 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=group_nflx_simple, ivar=ivar, initialize=initialize_variables, & index = ih_excess_resp_si) - - ! slow carbon fluxes associated with mortality from or transfer betweeen canopy and understory - call this%set_history_var(vname='FATES_DEMOTION_CARBONFLUX', & + ! slow carbon fluxes associated with mortality from or transfer betweeen canopy and understory + + call this%set_history_var(vname='FATES_DEMOTION_CARBONFLUX', & units = 'kg m-2 s-1', & long='demotion-associated biomass carbon flux from canopy to understory in kg carbon per m2 per second', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index = ih_demotion_carbonflux_si) - call this%set_history_var(vname='FATES_PROMOTION_CARBONFLUX', & + call this%set_history_var(vname='FATES_PROMOTION_CARBONFLUX', & units = 'kg m-2 s-1', & long='promotion-associated biomass carbon flux from understory to canopy in kg carbon per m2 per second', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index = ih_promotion_carbonflux_si) - call this%set_history_var(vname='FATES_MORTALITY_CFLUX_CANOPY', & + call this%set_history_var(vname='FATES_MORTALITY_CFLUX_CANOPY', & units = 'kg m-2 s-1', & long='flux of biomass carbon from live to dead pools from mortality of canopy plants in kg carbon per m2 per second', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index = ih_canopy_mortality_carbonflux_si) - call this%set_history_var(vname='FATES_MORTALITY_CFLUX_USTORY', & + 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=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index = ih_understory_mortality_carbonflux_si) - call this%set_history_var(vname='MORTALITY_CROWNAREA_CANOPY', & + 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=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index = ih_canopy_mortality_crownarea_si ) - call this%set_history_var(vname='MORTALITY_CROWNAREA_UNDERSTORY', & + 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=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index = ih_understory_mortality_crownarea_si ) - call this%set_history_var(vname='FATES_FIRE_CLOSS', units='kg m-2 s-1', & + call this%set_history_var(vname='FATES_FIRE_CLOSS', units='kg m-2 s-1', & long='carbon loss to atmosphere from fire in kg carbon per m2 per second', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index = ih_fire_c_to_atm_si) - call this%set_history_var(vname='FATES_CBALANCE_ERROR', & + call this%set_history_var(vname='FATES_CBALANCE_ERROR', & units='kg s-1', & long='total carbon error in kg carbon per second', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & @@ -7028,653 +7055,653 @@ subroutine define_history_vars(this, initialize_variables) index = ih_cbal_err_fates_si) - - call this%set_history_var(vname='FATES_LEAF_ALLOC', units='kg m-2 s-1', & + + call this%set_history_var(vname='FATES_LEAF_ALLOC', units='kg m-2 s-1', & long='allocation to leaves in kg carbon per m2 per second', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index = ih_npp_leaf_si) - call this%set_history_var(vname='FATES_SEED_ALLOC', units='kg m-2 s-1', & + call this%set_history_var(vname='FATES_SEED_ALLOC', units='kg m-2 s-1', & long='allocation to seeds in kg carbon per m2 per second', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index = ih_npp_seed_si) - call this%set_history_var(vname='FATES_STEM_ALLOC', units='kg m-2 s-1', & + call this%set_history_var(vname='FATES_STEM_ALLOC', units='kg m-2 s-1', & long='allocation to stem in kg carbon per m2 per second', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index = ih_npp_stem_si) - call this%set_history_var(vname='FATES_FROOT_ALLOC', units='kg m-2 s-1', & + call this%set_history_var(vname='FATES_FROOT_ALLOC', units='kg m-2 s-1', & long='allocation to fine roots in kg carbon per m2 per second', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index = ih_npp_froot_si) - call this%set_history_var(vname='FATES_CROOT_ALLOC', units='kg m-2 s-1', & + call this%set_history_var(vname='FATES_CROOT_ALLOC', units='kg m-2 s-1', & long='allocation to coarse roots in kg carbon per m2 per second', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index = ih_npp_croot_si) - call this%set_history_var(vname='FATES_STORE_ALLOC', units='kg m-2 s-1', & + call this%set_history_var(vname='FATES_STORE_ALLOC', units='kg m-2 s-1', & long='allocation to storage tissues in kg carbon per m2 per second', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index = ih_npp_stor_si) - call this%set_history_var(vname='FATES_GRAZING', units='kg m-2 s-1', & + call this%set_history_var(vname='FATES_GRAZING', units='kg m-2 s-1', & long='grazing by herbivores of leaves in kg carbon per m2 per second', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index = ih_grazing_si) - hydro_active_if: if(hlm_use_planthydro.eq.itrue) then - call this%set_history_var(vname='FATES_VEGH2O_DEAD', units = 'kg m-2', & + hydro_active_if: if(hlm_use_planthydro.eq.itrue) then + call this%set_history_var(vname='FATES_VEGH2O_DEAD', units = 'kg m-2', & long='cumulative water stored in dead biomass due to mortality', & use_default='inactive', avgflag='A', vtype=site_r8, & hlms='CLM:ALM', upfreq=group_dyna_simple, ivar=ivar, & initialize=initialize_variables, index = ih_h2oveg_dead_si) - call this%set_history_var(vname='FATES_VEGH2O_RECRUIT', & + call this%set_history_var(vname='FATES_VEGH2O_RECRUIT', & units = 'kg m-2', long='amount of water in new recruits', & use_default='inactive', avgflag='A', vtype=site_r8, & hlms='CLM:ALM', upfreq=group_dyna_simple, ivar=ivar, & initialize=initialize_variables, index = ih_h2oveg_recruit_si) - call this%set_history_var(vname='FATES_VEGH2O_GROWTURN_ERR', & + call this%set_history_var(vname='FATES_VEGH2O_GROWTURN_ERR', & units = 'kg m-2', & long='cumulative net borrowed (+) or lost (-) from water storage due to combined growth & turnover', & use_default='inactive', avgflag='A', vtype=site_r8, & hlms='CLM:ALM', upfreq=group_dyna_simple, ivar=ivar, & initialize=initialize_variables, index = ih_h2oveg_growturn_err_si) - end if hydro_active_if + end if hydro_active_if - if_crowndamage1: if(hlm_use_tree_damage .eq. itrue) then + if_crowndamage1: if(hlm_use_tree_damage .eq. itrue) then - call this%set_history_var(vname='FATES_CROWNAREA_CANOPY_CD', units = 'm2 m-2 yr-1', & + 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=group_dyna_simple, 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', & + + 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=group_dyna_simple, ivar=ivar, initialize=initialize_variables, index = ih_crownarea_ustory_damage_si ) - end if if_crowndamage1 + end if if_crowndamage1 - call this%set_history_var(vname='FATES_NCL', units='', & + call this%set_history_var(vname='FATES_NCL', units='', & long='number of canopy levels', & use_default='inactive', avgflag='A', vtype=site_r8, & hlms='CLM:ALM', upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index=ih_ncl_si) - if ( comp_excln_exp .lt. 0._r8 ) then ! only valid when "strict ppa" enabled - tempstring = 'active' - else - tempstring = 'inactive' - endif - - call this%set_history_var(vname='FATES_ZSTAR', units='m', & + if ( comp_excln_exp .lt. 0._r8 ) then ! only valid when "strict ppa" enabled + tempstring = 'active' + else + tempstring = 'inactive' + endif + + call this%set_history_var(vname='FATES_ZSTAR', units='m', & long='product of zstar and patch area', & use_default=tempstring, avgflag='A', vtype=site_r8, & hlms='CLM:ALM', upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & index=ih_zstar_si) - - if_dyn1: if(hlm_hist_level_dynam>1) then - call this%set_history_var(vname='FATES_NPP_LU', units='kg m-2 s-1', & + if_dyn1: if(hlm_hist_level_dynam>1) then + + call this%set_history_var(vname='FATES_NPP_LU', units='kg m-2 s-1', & long='net primary productivity by land use type in kg carbon per m2 per second', & use_default='inactive', avgflag='A', vtype=site_landuse_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_npp_si_landuse) - call this%set_history_var(vname='FATES_PATCHAREA_LU', units='m2 m-2', & + call this%set_history_var(vname='FATES_PATCHAREA_LU', units='m2 m-2', & long='patch area by land use type', use_default='active', & avgflag='A', vtype=site_landuse_r8, hlms='CLM:ALM', upfreq=group_dyna_complx, & ivar=ivar, initialize=initialize_variables, index=ih_fracarea_si_landuse) - call this%set_history_var(vname='FATES_VEGC_LU', units='kg m-2', & + call this%set_history_var(vname='FATES_VEGC_LU', units='kg m-2', & long='Vegetation Carbon by land use type', use_default='active', & avgflag='A', vtype=site_landuse_r8, hlms='CLM:ALM', upfreq=group_dyna_complx, & ivar=ivar, initialize=initialize_variables, index=ih_biomass_si_landuse) - call this%set_history_var(vname='FATES_BURNEDAREA_LU', units='s-1', & + call this%set_history_var(vname='FATES_BURNEDAREA_LU', units='s-1', & long='burned area by land use type', use_default='active', & avgflag='A', vtype=site_landuse_r8, hlms='CLM:ALM', upfreq=group_dyna_complx, & ivar=ivar, initialize=initialize_variables, index=ih_burnedarea_si_landuse) - call this%set_history_var(vname='FATES_TRANSITION_MATRIX_LULU', units='m2 m-2 yr-1', & + call this%set_history_var(vname='FATES_TRANSITION_MATRIX_LULU', units='m2 m-2 yr-1', & long='land use transition matrix', use_default='active', & avgflag='A', vtype=site_lulu_r8, hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index=ih_transition_matrix_si_lulu) - - call this%set_history_var(vname='FATES_DISTURBANCE_RATE_MATRIX_LULU', units='m2 m-2 yr-1', & + + call this%set_history_var(vname='FATES_DISTURBANCE_RATE_MATRIX_LULU', units='m2 m-2 yr-1', & long='disturbance rates by land use type x land use type matrix', use_default='active', & avgflag='A', vtype=site_lulu_r8, hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index=ih_disturbance_rate_si_lulu) - - call this%set_history_var(vname='FATES_VEGC_PF', units='kg m-2', & + + 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=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index=ih_biomass_si_pft) - call this%set_history_var(vname='FATES_RECRUITMENT_CFLUX_PF', units='kg m-2 yr-1', & + call this%set_history_var(vname='FATES_RECRUITMENT_CFLUX_PF', units='kg m-2 yr-1', & long='total PFT-level biomass of new recruits in kg of carbon per land area', & use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index=ih_recruitment_cflux_si_pft) - call this%set_history_var(vname='FATES_LEAFC_PF', units='kg m-2', & + 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', & upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index=ih_leafbiomass_si_pft) - call this%set_history_var(vname='FATES_STOREC_PF', units='kg m-2', & + call this%set_history_var(vname='FATES_STOREC_PF', units='kg m-2', & long='total PFT-level stored biomass in kg carbon per m2 land area', & use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index=ih_storebiomass_si_pft) - call this%set_history_var(vname='FATES_CROWNAREA_PF', units='m2 m-2', & + call this%set_history_var(vname='FATES_CROWNAREA_PF', units='m2 m-2', & long='total PFT-level crown area per m2 land area', & use_default='active', avgflag='A', vtype=site_pft_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index=ih_crownarea_si_pft) - call this%set_history_var(vname='FATES_CANOPYCROWNAREA_PF', & + call this%set_history_var(vname='FATES_CANOPYCROWNAREA_PF', & units='m2 m-2', long='total PFT-level canopy-layer crown area per m2 land area', & use_default='active', avgflag='A', vtype=site_pft_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index=ih_canopycrownarea_si_pft) - call this%set_history_var(vname='FATES_GPP_PF', units='kg m-2 s-1', & + call this%set_history_var(vname='FATES_GPP_PF', units='kg m-2 s-1', & long='total PFT-level GPP in kg carbon per m2 land area per second', & use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index=ih_gpp_si_pft) - call this%set_history_var(vname='FATES_NPP_PF', units='kg m-2 s-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=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index=ih_npp_si_pft) - call this%set_history_var(vname='FATES_NPLANT_PF', units='m-2', & + 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=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index=ih_nindivs_si_pft) - call this%set_history_var(vname='FATES_RECRUITMENT_PF', & + 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=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index=ih_recruitment_si_pft) - call this%set_history_var(vname='FATES_SEEDS_IN_GRIDCELL_PF', & + 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=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index=ih_seeds_in_gc_si_pft) - call this%set_history_var(vname='FATES_SEEDS_OUT_GRIDCELL_PF', & + 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=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index=ih_seeds_out_gc_si_pft) - call this%set_history_var(vname='FATES_SEED_BANK_PF', units='kg m-2', & + call this%set_history_var(vname='FATES_SEED_BANK_PF', units='kg m-2', & long='total seed mass per PFT in kg carbon per m2 land area', & use_default='inactive', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_seed_bank_si_pft) - call this%set_history_var(vname='FATES_UNGERM_SEED_BANK_PF', units='kg m-2', & + call this%set_history_var(vname='FATES_UNGERM_SEED_BANK_PF', units='kg m-2', & long='ungerminated seed mass per PFT in kg carbon per m2 land area', & use_default='inactive', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_ungerm_seed_bank_si_pft) - call this%set_history_var(vname='FATES_SEEDLING_POOL_PF', units='kg m-2', & + call this%set_history_var(vname='FATES_SEEDLING_POOL_PF', units='kg m-2', & long='total seedling (ie germinated seeds) mass per PFT in kg carbon per m2 land area', & use_default='inactive', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_seedling_pool_si_pft) - call this%set_history_var(vname='FATES_SEEDS_IN_PF', units='kg m-2 s-1', & + call this%set_history_var(vname='FATES_SEEDS_IN_PF', units='kg m-2 s-1', & long='seed production rate per PFT in kg carbon per m2 second', & use_default='inactive', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_seeds_in_si_pft) - call this%set_history_var(vname='FATES_SEEDS_IN_LOCAL_PF', units='kg m-2 s-1', & + call this%set_history_var(vname='FATES_SEEDS_IN_LOCAL_PF', units='kg m-2 s-1', & long='local seed production rate per PFT in kg carbon per m2 second', & use_default='inactive', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_seeds_in_local_si_pft) - call this%set_history_var(vname='FATES_MORTALITY_PF', units='m-2 yr-1', & + 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=group_dyna_complx, 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', & + !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=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index=ih_site_dstatus_si_pft) - call this%set_history_var(vname='FATES_DAYSINCE_DROUGHTLEAFOFF_PF', & + 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=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index=ih_dleafoff_si_pft) - call this%set_history_var(vname='FATES_DAYSINCE_DROUGHTLEAFON_PF', & + 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=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index=ih_dleafon_si_pft) - call this%set_history_var(vname='FATES_MEANLIQVOL_DROUGHTPHEN_PF', & + 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=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index=ih_meanliqvol_si_pft) - call this%set_history_var(vname='FATES_MEANSMP_DROUGHTPHEN_PF', & + 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=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index=ih_meansmp_si_pft) - call this%set_history_var(vname='FATES_ELONG_FACTOR_PF', & + 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=group_dyna_complx, 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='', & + 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)', & use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index=ih_nocomp_pftnpatches_si_pft) - call this%set_history_var(vname='FATES_NOCOMP_PATCHAREA_PF', units='m2 m-2',& + call this%set_history_var(vname='FATES_NOCOMP_PATCHAREA_PF', units='m2 m-2',& long='total patch area allowed per PFT (nocomp-mode-only)', & use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index=ih_nocomp_pftpatchfraction_si_pft) - call this%set_history_var(vname='FATES_NOCOMP_BURNEDAREA_PF', units='s-1', & + call this%set_history_var(vname='FATES_NOCOMP_BURNEDAREA_PF', units='s-1', & long='total burned area of PFT-labeled patch area (nocomp-mode-only)',& use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index=ih_nocomp_pftburnedarea_si_pft) - endif nocomp_if + endif nocomp_if - call this%set_history_var(vname='FATES_CANOPYAREA', units='m2 m-2', & + call this%set_history_var(vname='FATES_CANOPYAREA', units='m2 m-2', & long='canopy area per m2 land area', use_default='inactive', & avgflag='A', vtype=site_r8, hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index=ih_canopy_fracarea_si) - call this%set_history_var(vname='FATES_PATCHAREA', units='m2 m-2', & + call this%set_history_var(vname='FATES_PATCHAREA', units='m2 m-2', & long='patch area per m2 land area', use_default='inactive', & avgflag='A', vtype=site_r8, hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index=ih_fracarea_si) - ! patch age class variables - call this%set_history_var(vname='FATES_PATCHAREA_AP', units='m2 m-2', & + ! patch age class variables + call this%set_history_var(vname='FATES_PATCHAREA_AP', units='m2 m-2', & long='patch area by age bin per m2 land area', & use_default='active', & avgflag='A', vtype=site_age_r8, hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index=ih_fracarea_si_age) - call this%set_history_var(vname='FATES_LAI_AP', units='m2 m-2', & + call this%set_history_var(vname='FATES_LAI_AP', units='m2 m-2', & long='total leaf area index by age bin per m2 land area'// & this%per_ageclass_norm_info('FATES_CANOPYAREA/FATES_CANOPYAREA_AP'), & use_default='active', avgflag='A', vtype=site_age_r8, hlms='CLM:ALM', & upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index=ih_lai_si_age) - call this%set_history_var(vname='FATES_CANOPYAREA_AP', units='m2 m-2', & + call this%set_history_var(vname='FATES_CANOPYAREA_AP', units='m2 m-2', & long='canopy area by age bin per m2 land area'// & this%per_ageclass_norm_info('FATES_PATCHAREA/FATES_PATCHAREA_AP'), & use_default='active', & avgflag='A', vtype=site_age_r8, hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index=ih_canopy_fracarea_si_age) - call this%set_history_var(vname='FATES_NCL_AP', units='', & + call this%set_history_var(vname='FATES_NCL_AP', units='', & long='number of canopy levels by age bin' // & this%per_ageclass_norm_info('FATES_PATCHAREA/FATES_PATCHAREA_AP'), & use_default='inactive', avgflag='A', vtype=site_age_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index=ih_ncl_si_age) - call this%set_history_var(vname='FATES_NPATCH_AP', units='', & + call this%set_history_var(vname='FATES_NPATCH_AP', units='', & long='number of patches by age bin', use_default='inactive', & avgflag='A', vtype=site_age_r8, hlms='CLM:ALM', & upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index=ih_npatches_si_age) - if ( comp_excln_exp .lt. 0._r8 ) then ! only valid when "strict ppa" enabled - tempstring = 'active' - else - tempstring = 'inactive' - endif + if ( comp_excln_exp .lt. 0._r8 ) then ! only valid when "strict ppa" enabled + tempstring = 'active' + else + tempstring = 'inactive' + endif - call this%set_history_var(vname='FATES_ZSTAR_AP', units='m', & + call this%set_history_var(vname='FATES_ZSTAR_AP', units='m', & long='product of zstar and patch area by age bin (divide by FATES_PATCHAREA_AP to get mean zstar)', & use_default=trim(tempstring), avgflag='A', vtype=site_age_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index=ih_zstar_si_age) - call this%set_history_var(vname='FATES_CANOPYAREA_HT', units='m2 m-2', & + call this%set_history_var(vname='FATES_CANOPYAREA_HT', units='m2 m-2', & long='canopy area height distribution', & use_default='active', avgflag='A', vtype=site_height_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index=ih_canopy_height_dist_si_height) - call this%set_history_var(vname='FATES_LEAFAREA_HT', units='m2 m-2', & + call this%set_history_var(vname='FATES_LEAFAREA_HT', units='m2 m-2', & long='leaf area height distribution', use_default='active', & avgflag='A', vtype=site_height_r8, hlms='CLM:ALM', & upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index=ih_leaf_height_dist_si_height) - call this%set_history_var(vname='FATES_VEGC_AP', units='kg m-2', & + call this%set_history_var(vname='FATES_VEGC_AP', units='kg m-2', & long='total biomass within a given patch age bin in kg carbon per m2 land area', & use_default='inactive', avgflag='A', vtype=site_age_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index=ih_biomass_si_age) - call this%set_history_var(vname='FATES_SECONDARY_AREA_ANTHRO_AP', & + call this%set_history_var(vname='FATES_SECONDARY_AREA_ANTHRO_AP', & units='m2 m-2', & long='secondary forest patch area age distribution since anthropogenic disturbance', & use_default='inactive', avgflag='A', vtype=site_age_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index=ih_agesince_anthrodist_si_age) - call this%set_history_var(vname='FATES_SECONDARY_AREA_ANTHRO', & + call this%set_history_var(vname='FATES_SECONDARY_AREA_ANTHRO', & units='m2 m-2', & long='secondary forest patch area since anthropgenic disturbance', & use_default='inactive', avgflag='A', vtype=site_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index=ih_agesince_anthrodist_si) - call this%set_history_var(vname='FATES_SECONDARY_AREA', & + call this%set_history_var(vname='FATES_SECONDARY_AREA', & units='m2 m-2', & long='secondary forest patch area since any kind of disturbance', & use_default='inactive', avgflag='A', vtype=site_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index=ih_secondarylands_fracarea_si) - call this%set_history_var(vname='FATES_SECONDARY_AREA_AP', & + call this%set_history_var(vname='FATES_SECONDARY_AREA_AP', & units='m2 m-2', & long='secondary forest patch area age distribution since any kind of disturbance', & use_default='inactive', avgflag='A', vtype=site_age_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index=ih_secondarylands_fracarea_si_age) - call this%set_history_var(vname='FATES_PRIMARY_AREA', & + call this%set_history_var(vname='FATES_PRIMARY_AREA', & units='m2 m-2', & long='primary forest patch area since any kind of disturbance', & use_default='inactive', avgflag='A', vtype=site_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index=ih_primarylands_fracarea_si) - call this%set_history_var(vname='FATES_PRIMARY_AREA_AP', & + call this%set_history_var(vname='FATES_PRIMARY_AREA_AP', & units='m2 m-2', & long='primary forest patch area age distribution since any kind of disturbance', & use_default='inactive', avgflag='A', vtype=site_age_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index=ih_primarylands_fracarea_si_age) - call this%set_history_var(vname='FATES_FRAGMENTATION_SCALER_SL', units='', & + call this%set_history_var(vname='FATES_FRAGMENTATION_SCALER_SL', units='', & long='factor (0-1) by which litter/cwd fragmentation proceeds relative to max rate by soil layer', & use_default='active', avgflag='A', vtype=site_soil_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_fragmentation_scaler_sl) - call this%set_history_var(vname='FATES_FUEL_MOISTURE_FC', units='m3 m-3', & + call this%set_history_var(vname='FATES_FUEL_MOISTURE_FC', units='m3 m-3', & long='spitfire fuel class-level fuel moisture (volumetric)', & use_default='active', avgflag='A', vtype=site_fuel_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_litter_moisture_si_fuel) - call this%set_history_var(vname='FATES_FUEL_AMOUNT_FC', units='kg m-2', & + call this%set_history_var(vname='FATES_FUEL_AMOUNT_FC', units='kg m-2', & long='spitfire fuel-class level fuel amount in kg carbon per m2 land area', & use_default='active', avgflag='A', vtype=site_fuel_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_fuel_amount_si_fuel) - call this%set_history_var(vname='FATES_FUEL_AMOUNT_APFC', units='kg m-2', & + call this%set_history_var(vname='FATES_FUEL_AMOUNT_APFC', units='kg m-2', & long='spitfire fuel quantity in each age x fuel class in kg carbon per m2 land area', & use_default='inactive', avgflag='A', vtype=site_agefuel_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_fuel_amount_si_agfc) - call this%set_history_var(vname='FATES_BURNFRAC_AP', units='s-1', & + call this%set_history_var(vname='FATES_BURNFRAC_AP', units='s-1', & long='spitfire fraction area burnt (per second) by patch age, sum of rx and wildfire', & use_default='active', avgflag='A', vtype=site_age_r8, hlms='CLM:ALM', & upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_fracarea_burnt_si_age) - call this%set_history_var(vname='FATES_FIRE_INTENSITY_BURNFRAC_AP', & + call this%set_history_var(vname='FATES_FIRE_INTENSITY_BURNFRAC_AP', & units='J m-1 s-1', & long='product of fire intensity and burned fraction, sum of rx and wildfire, resolved by patch age (so divide by FATES_BURNFRAC_AP to get area-weighted mean intensity)', & use_default='active', avgflag='A', vtype=site_age_r8, hlms='CLM:ALM', & upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_fire_intensity_si_age) - call this%set_history_var(vname='FATES_WILDFIRE_BURNFRAC_AP', units='s-1', & + call this%set_history_var(vname='FATES_WILDFIRE_BURNFRAC_AP', units='s-1', & long='spitfire fraction area burnt due to wildfire by patch age', & use_default='active', avgflag='A', vtype=site_age_r8, hlms='CLM:ALM', & upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_nonrx_fracarea_burnt_si_age) - call this%set_history_var(vname='FATES_WILDFIRE_INTENSITY_BURNFRAC_AP', & + call this%set_history_var(vname='FATES_WILDFIRE_INTENSITY_BURNFRAC_AP', & units='J m-1 s-1', & long='product of wildfire intensity and burned fraction, resolved by patch age, divide by FATES_WILDFIRE_BURNFRAC_AP to get area-weighted mean intensity)', & use_default='active', avgflag='A', vtype=site_age_r8, hlms='CLM:ALM', & upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_nonrx_intensity_si_age) - call this%set_history_var(vname='FATES_RXFIRE_BURNFRAC_AP', units='s-1', & + call this%set_history_var(vname='FATES_RXFIRE_BURNFRAC_AP', units='s-1', & long='spitfire fraction area burnt due to prescribed fire by patch age', & use_default='active', avgflag='A', vtype=site_age_r8, hlms='CLM:ALM', & upfreq=1, ivar=ivar, initialize=initialize_variables, & index= ih_rx_fracarea_burnt_si_age) - - call this%set_history_var(vname='FATES_RXFIRE_INTENSITY_BURNFRAC_AP', & + + call this%set_history_var(vname='FATES_RXFIRE_INTENSITY_BURNFRAC_AP', & units='J m-1 s-1', & long='product of prescribed fire intensity and burned fraction by patch age, to be devided by FATES_RXFIRE_BURNFRAC_AP to get area-weighted mean intensity)', & use_default='active', avgflag='A', vtype=site_age_r8, hlms='CLM:ALM', & upfreq=1, ivar=ivar, initialize=initialize_variables, & index = ih_rx_intensity_si_age) - call this%set_history_var(vname='FATES_FUEL_AMOUNT_AP', units='kg m-2', & + call this%set_history_var(vname='FATES_FUEL_AMOUNT_AP', units='kg m-2', & long='spitfire ground fuel (kg carbon per m2) related to FATES_ROS (omits 1000hr fuels) within each patch age bin (divide by FATES_PATCHAREA_AP to get fuel per unit area of that-age patch)', & use_default='active', avgflag='A', vtype=site_age_r8, hlms='CLM:ALM', & upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_fire_sum_fuel_si_age) - call this%set_history_var(vname='FATES_FUEL_BURNT_BURNFRAC_FC', units='1', & + call this%set_history_var(vname='FATES_FUEL_BURNT_BURNFRAC_FC', units='1', & long='product of fraction (0-1) of fuel burnt and burnt fraction (divide by FATES_BURNFRAC to get burned-area-weighted mean fraction fuel burnt)', & use_default='active', avgflag='A', vtype=site_fuel_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_burnt_frac_litter_si_fuel) - call this%set_history_var(vname='FATES_LITTER_IN_EL', units='kg m-2 s-1', & + 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, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_litter_in_elem) - call this%set_history_var(vname='FATES_LITTER_OUT_EL', units='kg m-2 s-1', & + call this%set_history_var(vname='FATES_LITTER_OUT_EL', units='kg m-2 s-1', & 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=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_litter_out_elem) - call this%set_history_var(vname='FATES_SEED_BANK_EL', units='kg m-2', & + call this%set_history_var(vname='FATES_SEED_BANK_EL', units='kg m-2', & long='element-level total seed mass of all PFTs in kg element per m2', & use_default='active', avgflag='A', vtype=site_elem_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_seed_bank_elem) - call this%set_history_var(vname='FATES_SEEDS_IN_LOCAL_EL', & + call this%set_history_var(vname='FATES_SEEDS_IN_LOCAL_EL', & units='kg m-2 s-1', & long='within-site, element-level seed production rate in kg element per m2 per second', & use_default='active', avgflag='A', vtype=site_elem_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_seeds_in_local_elem) - call this%set_history_var(vname='FATES_SEEDS_IN_EXTERN_EL', & + call this%set_history_var(vname='FATES_SEEDS_IN_EXTERN_EL', & units='kg m-2 s-1', long='external seed influx rate in kg element per m2 per second', & use_default='active', avgflag='A', vtype=site_elem_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, 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', & + 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=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_seed_germ_elem) - call this%set_history_var(vname='FATES_SEED_DECAY_EL', units='kg m-2 s-1', & + call this%set_history_var(vname='FATES_SEED_DECAY_EL', units='kg m-2 s-1', & long='seed mass decay (germinated and un-germinated) in kg element per m2 per second', & use_default='active', avgflag='A', vtype=site_elem_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_seed_decay_elem) - ! SITE LEVEL CARBON STATE VARIABLES + ! SITE LEVEL CARBON STATE VARIABLES - call this%set_history_var(vname='FATES_STOREC_TF_USTORY_SZPF', units='kg kg-1', & + 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=group_dyna_complx, & 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', & + 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=group_dyna_complx, & ivar=ivar, initialize=initialize_variables, index = ih_storectfrac_canopy_scpf ) - call this%set_history_var(vname='FATES_FROOTC_SL', units='kg m-3', & + 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=group_dyna_complx, & ivar=ivar, initialize=initialize_variables, index = ih_fnrtc_sl ) - ! Output specific to the chemical species dynamics used (parteh) - 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)', & + ! Output specific to the chemical species dynamics used (parteh) + 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=group_dyna_complx, & 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)', & + + 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=group_dyna_complx, & 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=group_dyna_complx, & - ! ivar=ivar, initialize=initialize_variables, index = ih_l2fr_clscpf) - nitrogen_active_if1: if(any(element_list(:)==nitrogen_element)) then + !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=group_dyna_complx, & + ! ivar=ivar, initialize=initialize_variables, index = ih_l2fr_clscpf) - call this%set_history_var(vname='FATES_NH4UPTAKE_SZPF', & + nitrogen_active_if1: if(any(element_list(:)==nitrogen_element)) then + + 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=group_nflx_complx, ivar=ivar, & initialize=initialize_variables, index = ih_nh4uptake_scpf) - call this%set_history_var(vname='FATES_NO3UPTAKE_SZPF', & + 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=group_nflx_complx, ivar=ivar, & initialize=initialize_variables, index = ih_no3uptake_scpf) - call this%set_history_var(vname='FATES_NEFFLUX_SZPF', units='kg m-2 s-1', & + 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=group_nflx_complx, ivar=ivar, & initialize=initialize_variables, index = ih_nefflux_scpf) - call this%set_history_var(vname='FATES_NDEMAND_SZPF', units='kg m-2 s-1', & + 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=group_nflx_complx, ivar=ivar, & initialize=initialize_variables, index = ih_ndemand_scpf) - - call this%set_history_var(vname='FATES_NFIX_SYM_SZPF', units='kg m-2 s-1', & + + 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=group_nflx_complx, ivar=ivar, & initialize=initialize_variables, index = ih_nfix_scpf) - - call this%set_history_var(vname='FATES_VEGN_SZPF', units='kg m-2', & + + 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=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_totvegn_scpf) - call this%set_history_var(vname='FATES_LEAFN_SZPF', units='kg m-2', & + 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=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_leafn_scpf) - call this%set_history_var(vname='FATES_FROOTN_SZPF', units='kg m-2', & + 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=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_fnrtn_scpf) - call this%set_history_var(vname='FATES_SAPWOODN_SZPF', units='kg m-2', & + 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=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_sapwn_scpf) - call this%set_history_var(vname='FATES_STOREN_SZPF', units='kg m-2', & + 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=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_storen_scpf) - call this%set_history_var(vname='FATES_STOREN_TF_CANOPY_SZPF', & + 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=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_storentfrac_canopy_scpf) - call this%set_history_var(vname='FATES_STOREN_TF_USTORY_SZPF', & + 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, & @@ -7682,53 +7709,53 @@ subroutine define_history_vars(this, initialize_variables) initialize=initialize_variables, & index = ih_storentfrac_understory_scpf) - call this%set_history_var(vname='FATES_REPRON_SZPF', units='kg m-2', & + 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=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_repron_scpf) - end if nitrogen_active_if1 + end if nitrogen_active_if1 - phosphorus_active_if1: if(any(element_list(:)==phosphorus_element)) then + phosphorus_active_if1: if(any(element_list(:)==phosphorus_element)) then - call this%set_history_var(vname='FATES_VEGP_SZPF', units='kg m-2', & + 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=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_totvegp_scpf) - call this%set_history_var(vname='FATES_LEAFP_SZPF', units='kg m-2', & + 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=group_dyna_complx, ivar=ivar, initialize=initialize_variables, index = ih_leafp_scpf ) - call this%set_history_var(vname='FATES_FROOTP_SZPF', units='kg m-2', & + 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=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_fnrtp_scpf) - call this%set_history_var(vname='FATES_SAPWOODP_SZPF', units='kg m-2', & + 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=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_sapwp_scpf) - call this%set_history_var(vname='FATES_STOREP_SZPF', units='kg m-2', & + 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=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_storep_scpf) - call this%set_history_var(vname='FATES_STOREP_TF_CANOPY_SZPF', & + 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=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_storeptfrac_canopy_scpf) - call this%set_history_var(vname='FATES_STOREP_TF_USTORY_SZPF', & + 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, & @@ -7736,104 +7763,104 @@ subroutine define_history_vars(this, initialize_variables) initialize=initialize_variables, & index = ih_storeptfrac_understory_scpf) - call this%set_history_var(vname='FATES_REPROP_SZPF', units='kg m-2', & + 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=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_reprop_scpf) - call this%set_history_var(vname='FATES_PUPTAKE_SZPF', & + 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=group_nflx_complx, ivar=ivar, & initialize=initialize_variables, index = ih_puptake_scpf) - call this%set_history_var(vname='FATES_PEFFLUX_SZPF', & + 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=group_nflx_complx, ivar=ivar, & initialize=initialize_variables, index = ih_pefflux_scpf) - - call this%set_history_var(vname='FATES_PDEMAND_SZPF', units='kg m-2 s-1', & + + call this%set_history_var(vname='FATES_PDEMAND_SZPF', units='kg m-2 s-1', & long='plant P need (algorithm dependent), by size-class x pft in kg P per m2 per second', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_nflx_complx, ivar=ivar, & initialize=initialize_variables, index = ih_pdemand_scpf) - - end if phosphorus_active_if1 - call this%set_history_var(vname='FATES_CROWNAREA_CLLL', units='m2 m-2', & + end if phosphorus_active_if1 + + call this%set_history_var(vname='FATES_CROWNAREA_CLLL', units='m2 m-2', & long='area fraction of the total ground occupied by each canopy-leaf layer', & use_default='inactive', avgflag='A', vtype=site_cnlf_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_crownarea_si_cnlf) - call this%set_history_var(vname='FATES_CROWNAREA_CL', units='m2 m-2', & + call this%set_history_var(vname='FATES_CROWNAREA_CL', units='m2 m-2', & long='area fraction of the canopy footprint occupied by each canopy-leaf layer', use_default='active', & avgflag='A', vtype=site_can_r8, hlms='CLM:ALM', upfreq=group_dyna_complx, & ivar=ivar, initialize=initialize_variables, index = ih_crownarea_cl) - call this%set_history_var(vname='FATES_MORTALITY_CFLUX_PF', units='kg m-2 s-1', & + 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=group_dyna_complx, 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', & + 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=group_dyna_complx, 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', & + 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=group_dyna_complx, 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', & + 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 (both continuous and termination)', & use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index=ih_cstarvmortality_carbonflux_si_pft) - call this%set_history_var(vname='FATES_MORT_CSTARV_CONT_CFLUX_PF', units='kg m-2 s-1', & + call this%set_history_var(vname='FATES_MORT_CSTARV_CONT_CFLUX_PF', units='kg m-2 s-1', & long='PFT-level flux of biomass carbon from live to dead pool from carbon starvation mortality (Continuous-only, without termination)', & use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index=ih_cstarvmortality_continuous_carbonflux_si_pft) - - call this%set_history_var(vname='FATES_ABOVEGROUND_MORT_SZPF', units='kg m-2 s-1', & + + 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=group_dyna_complx, 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', & + 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=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index=ih_abg_productivity_cflux_si_scpf) - ! size class by age dimensioned variables + ! size class by age dimensioned variables - call this%set_history_var(vname='FATES_NPLANT_SZAP', units = 'm-2', & + call this%set_history_var(vname='FATES_NPLANT_SZAP', units = 'm-2', & long='number of plants per m2, per size x age class'// & this%per_ageclass_norm_info('FATES_PATCHAREA/FATES_PATCHAREA_AP'), & use_default='inactive', avgflag='A', vtype=site_scag_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_nplant_si_scag) - call this%set_history_var(vname='FATES_NPLANT_CANOPY_SZAP', units = 'm-2', & + call this%set_history_var(vname='FATES_NPLANT_CANOPY_SZAP', units = 'm-2', & long='number of canopy plants per m2, per size x age class'// & this%per_ageclass_norm_info('FATES_PATCHAREA/FATES_PATCHAREA_AP'), & use_default='inactive', avgflag='A', vtype=site_scag_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_nplant_canopy_si_scag) - call this%set_history_var(vname='FATES_NPLANT_USTORY_SZAP', & + call this%set_history_var(vname='FATES_NPLANT_USTORY_SZAP', & units = 'm-2', & long='number of understory plants per m2 understory, per size x age class'// & this%per_ageclass_norm_info('FATES_PATCHAREA/FATES_PATCHAREA_AP'), & @@ -7841,364 +7868,364 @@ subroutine define_history_vars(this, initialize_variables) hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_nplant_understory_si_scag) - call this%set_history_var(vname='FATES_DDBH_CANOPY_SZAP', & + call this%set_history_var(vname='FATES_DDBH_CANOPY_SZAP', & units = 'm m-2 yr-1', & long='growth rate of canopy plants in meters DBH per m2 per year in canopy in each size x age class', & use_default='inactive', avgflag='A', vtype=site_scag_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_ddbh_canopy_si_scag) - call this%set_history_var(vname='FATES_DDBH_USTORY_SZAP', & + call this%set_history_var(vname='FATES_DDBH_USTORY_SZAP', & units = 'm m-2 yr-1', & long='growth rate of understory plants in meters DBH per m2 per year in each size x age class', & use_default='inactive', avgflag='A', vtype=site_scag_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_ddbh_understory_si_scag) - call this%set_history_var(vname='FATES_MORTALITY_CANOPY_SZAP', & + call this%set_history_var(vname='FATES_MORTALITY_CANOPY_SZAP', & units = 'm-2 yr-1', & long='mortality rate of canopy plants in number of plants per m2 per year in each size x age class', & use_default='inactive', avgflag='A', vtype=site_scag_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_mortality_canopy_si_scag) - call this%set_history_var(vname='FATES_MORTALITY_USTORY_SZAP', & + call this%set_history_var(vname='FATES_MORTALITY_USTORY_SZAP', & units = 'm-2 yr-1', & long='mortality rate of understory plants in number of plants per m2 per year in each size x age class', & use_default='inactive', avgflag='A', vtype=site_scag_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_mortality_understory_si_scag) - ! size x age x pft dimensioned + ! size x age x pft dimensioned - call this%set_history_var(vname='FATES_NPLANT_SZAPPF',units = 'm-2', & + call this%set_history_var(vname='FATES_NPLANT_SZAPPF',units = 'm-2', & long='number of plants per m2, per size x age x pft class'// & this%per_ageclass_norm_info('FATES_PATCHAREA/FATES_PATCHAREA_AP'), & use_default='inactive', avgflag='A', vtype=site_scagpft_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_nplant_si_scagpft) - ! age x pft dimensioned - call this%set_history_var(vname='FATES_NPP_APPF',units = 'kg m-2 s-1', & + ! age x pft dimensioned + call this%set_history_var(vname='FATES_NPP_APPF',units = 'kg m-2 s-1', & long='NPP per PFT in each age bin in kg carbon per m2 per second', & use_default='inactive', avgflag='A', vtype=site_agepft_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_npp_si_agepft) - call this%set_history_var(vname='FATES_NPP_AP', units='kg m-2 s-1', & + call this%set_history_var(vname='FATES_NPP_AP', units='kg m-2 s-1', & long='net primary productivity by age bin in kg carbon per m2 per second', & use_default='inactive', avgflag='A', vtype=site_age_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_npp_si_age) - call this%set_history_var(vname='FATES_VEGC_APPF',units = 'kg m-2', & + call this%set_history_var(vname='FATES_VEGC_APPF',units = 'kg m-2', & long='biomass per PFT in each age bin in kg carbon per m2'// & this%per_ageclass_norm_info('FATES_PATCHAREA/FATES_PATCHAREA_AP'), & use_default='inactive', avgflag='A', vtype=site_agepft_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_biomass_si_agepft) - call this%set_history_var(vname='FATES_SCORCH_HEIGHT_APPF',units = 'm', & + call this%set_history_var(vname='FATES_SCORCH_HEIGHT_APPF',units = 'm', & long='SPITFIRE flame Scorch Height (calculated per PFT in each patch age bin)'// & this%per_ageclass_norm_info('FATES_PATCHAREA/FATES_PATCHAREA_AP'), & use_default='inactive', avgflag='A', vtype=site_agepft_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_scorch_height_si_agepft) - call this%set_history_var(vname='FATES_SCORCH_HEIGHT_PF',units = 'm', & + call this%set_history_var(vname='FATES_SCORCH_HEIGHT_PF',units = 'm', & long='SPITFIRE flame Scorch Height (calculated per PFT)', & use_default='inactive', avgflag='A', vtype=site_pft_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_scorch_height_si_pft) - ! Carbon Flux (grid dimension x scpf) (THESE ARE DEFAULT INACTIVE!!! - ! (BECAUSE THEY TAKE UP SPACE!!! - ! =================================================================================== + ! Carbon Flux (grid dimension x scpf) (THESE ARE DEFAULT INACTIVE!!! + ! (BECAUSE THEY TAKE UP SPACE!!! + ! =================================================================================== - call this%set_history_var(vname='FATES_GPP_SZPF', units='kg m-2 s-1', & + call this%set_history_var(vname='FATES_GPP_SZPF', units='kg m-2 s-1', & long='gross primary production by pft/size in kg carbon per m2 per second', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_gpp_si_scpf) - call this%set_history_var(vname='FATES_GPP_CANOPY_SZPF', & + call this%set_history_var(vname='FATES_GPP_CANOPY_SZPF', & units='kg m-2 s-1', & long='gross primary production of canopy plants by pft/size in kg carbon per m2 per second', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_gpp_canopy_si_scpf) - call this%set_history_var(vname='FATES_AUTORESP_CANOPY_SZPF', & + call this%set_history_var(vname='FATES_AUTORESP_CANOPY_SZPF', & units='kg m-2 s-1', & long='autotrophic respiration of canopy plants by pft/size in kg carbon per m2 per second', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_ar_canopy_si_scpf) - call this%set_history_var(vname='FATES_GPP_USTORY_SZPF', & + call this%set_history_var(vname='FATES_GPP_USTORY_SZPF', & units='kg m-2 s-1', & long='gross primary production of understory plants by pft/size in kg carbon per m2 per second', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_gpp_understory_si_scpf) - call this%set_history_var(vname='FATES_AUTORESP_USTORY_SZPF', & + call this%set_history_var(vname='FATES_AUTORESP_USTORY_SZPF', & units='kg m-2 s-1', & long='autotrophic respiration of understory plants by pft/size in kg carbon per m2 per second', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_ar_understory_si_scpf) - call this%set_history_var(vname='FATES_NPP_SZPF', units='kg m-2 s-1', & + call this%set_history_var(vname='FATES_NPP_SZPF', units='kg m-2 s-1', & long='total net primary production by pft/size in kg carbon per m2 per second', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_npp_totl_si_scpf) - call this%set_history_var(vname='FATES_LEAF_ALLOC_SZPF', units='kg m-2 s-1', & + call this%set_history_var(vname='FATES_LEAF_ALLOC_SZPF', units='kg m-2 s-1', & long='allocation to leaves by pft/size in kg carbon per m2 per second', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_npp_leaf_si_scpf) - call this%set_history_var(vname='FATES_SEED_ALLOC_SZPF', units='kg m-2 s-1', & + call this%set_history_var(vname='FATES_SEED_ALLOC_SZPF', units='kg m-2 s-1', & long='allocation to seeds by pft/size in kg carbon per m2 per second', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_npp_seed_si_scpf) - call this%set_history_var(vname='FATES_FROOT_ALLOC_SZPF', & + call this%set_history_var(vname='FATES_FROOT_ALLOC_SZPF', & units='kg m-2 s-1', & long='allocation to fine roots by pft/size in kg carbon per m2 per second', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_npp_fnrt_si_scpf) - call this%set_history_var(vname='FATES_BGSAPWOOD_ALLOC_SZPF', & + call this%set_history_var(vname='FATES_BGSAPWOOD_ALLOC_SZPF', & units='kg m-2 s-1', & long='allocation to below-ground sapwood by pft/size in kg carbon per m2 per second', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_npp_bgsw_si_scpf) - call this%set_history_var(vname='FATES_BGSTRUCT_ALLOC_SZPF', units='kg m-2 s-1', & + call this%set_history_var(vname='FATES_BGSTRUCT_ALLOC_SZPF', units='kg m-2 s-1', & long='allocation to below-ground structural (deadwood) by pft/size in kg carbon per m2 per second', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_npp_bgdw_si_scpf) - call this%set_history_var(vname='FATES_AGSAPWOOD_ALLOC_SZPF', & + call this%set_history_var(vname='FATES_AGSAPWOOD_ALLOC_SZPF', & units='kg m-2 s-1', & long='allocation to above-ground sapwood by pft/size in kg carbon per m2 per second', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_npp_agsw_si_scpf) - call this%set_history_var(vname = 'FATES_AGSTRUCT_ALLOC_SZPF', & + call this%set_history_var(vname = 'FATES_AGSTRUCT_ALLOC_SZPF', & units='kg m-2 s-1', & long='allocation to above-ground structural (deadwood) by pft/size in kg carbon per m2 per second', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_npp_agdw_si_scpf) - call this%set_history_var(vname = 'FATES_STORE_ALLOC_SZPF', & + call this%set_history_var(vname = 'FATES_STORE_ALLOC_SZPF', & units='kg m-2 s-1', & long='allocation to storage C by pft/size in kg carbon per m2 per second', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_npp_stor_si_scpf) - call this%set_history_var(vname='FATES_DDBH_SZPF', units = 'm m-2 yr-1', & + call this%set_history_var(vname='FATES_DDBH_SZPF', units = 'm m-2 yr-1', & long='diameter growth increment by pft/size', use_default='inactive', & avgflag='A', vtype=site_size_pft_r8, hlms='CLM:ALM', & upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_ddbh_si_scpf) - call this%set_history_var(vname='FATES_GROWTHFLUX_SZPF', & + call this%set_history_var(vname='FATES_GROWTHFLUX_SZPF', & units = 'm-2 yr-1', & long='flux of individuals into a given size class bin via growth and recruitment', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_growthflux_si_scpf) - call this%set_history_var(vname='FATES_GROWTHFLUX_FUSION_SZPF', & + call this%set_history_var(vname='FATES_GROWTHFLUX_FUSION_SZPF', & units = 'm-2 yr-1', & long='flux of individuals into a given size class bin via fusion', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_growthflux_fusion_si_scpf) - call this%set_history_var(vname='FATES_DDBH_CANOPY_SZPF', & + call this%set_history_var(vname='FATES_DDBH_CANOPY_SZPF', & units = 'm m-2 yr-1', & long='diameter growth increment by pft/size', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_ddbh_canopy_si_scpf) - call this%set_history_var(vname='FATES_DDBH_USTORY_SZPF', & + call this%set_history_var(vname='FATES_DDBH_USTORY_SZPF', & units = 'm m-2 yr-1', & long='diameter growth increment by pft/size', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_ddbh_understory_si_scpf) - call this%set_history_var(vname='FATES_BASALAREA_SZPF', units = 'm2 m-2', & + call this%set_history_var(vname='FATES_BASALAREA_SZPF', units = 'm2 m-2', & long='basal area by pft/size', use_default='inactive', & avgflag='A', vtype=site_size_pft_r8, hlms='CLM:ALM', upfreq=group_dyna_complx, & ivar=ivar, initialize=initialize_variables, index = ih_ba_si_scpf) - call this%set_history_var(vname='FATES_SAPWOOD_AREA_SZPF', units = 'm2 m-2', & + call this%set_history_var(vname='FATES_SAPWOOD_AREA_SZPF', units = 'm2 m-2', & long='sapwood area by pft/size', use_default='inactive', & avgflag='A', vtype=site_size_pft_r8, hlms='CLM:ALM', upfreq=group_dyna_complx, & ivar=ivar, initialize=initialize_variables, index = ih_sapwood_area_scpf) - call this%set_history_var(vname='FATES_VEGC_ABOVEGROUND_SZPF', & + call this%set_history_var(vname='FATES_VEGC_ABOVEGROUND_SZPF', & units = 'kg m-2', & long='aboveground biomass by pft/size in kg carbon per m2', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_agb_si_scpf) - call this%set_history_var(vname='FATES_NPLANT_SZPF', units = 'm-2', & + call this%set_history_var(vname='FATES_NPLANT_SZPF', units = 'm-2', & long='stem number density by pft/size', use_default='inactive', & avgflag='A', vtype=site_size_pft_r8, hlms='CLM:ALM', & upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_nplant_si_scpf) - call this%set_history_var(vname='FATES_NPLANT_ACPF', units = 'm-2', & + call this%set_history_var(vname='FATES_NPLANT_ACPF', units = 'm-2', & long='stem number density by pft and age class', & use_default='inactive', avgflag='A', vtype=site_coage_pft_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_nplant_si_capf) - call this%set_history_var(vname='FATES_MORTALITY_BACKGROUND_SZPF', & + call this%set_history_var(vname='FATES_MORTALITY_BACKGROUND_SZPF', & units = 'm-2 yr-1', & long='background 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=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_m1_si_scpf) - call this%set_history_var(vname='FATES_MORTALITY_HYDRAULIC_SZPF', & + call this%set_history_var(vname='FATES_MORTALITY_HYDRAULIC_SZPF', & units = 'm-2 yr-1', & long='hydraulic 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=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_m2_si_scpf) - call this%set_history_var(vname='FATES_MORTALITY_CSTARV_SZPF', & + call this%set_history_var(vname='FATES_MORTALITY_CSTARV_SZPF', & units = 'm-2 yr-1', & long='carbon starvation mortality by pft/size in number of plants per m2 per year (both continous and termination)', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_m3_si_scpf) - call this%set_history_var(vname='FATES_MORTALITY_IMPACT_SZPF', & + call this%set_history_var(vname='FATES_MORTALITY_IMPACT_SZPF', & units = 'm-2 yr-1', & long='impact 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=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_m4_si_scpf) - call this%set_history_var(vname='FATES_MORTALITY_WILDFIRE_SZPF', & + call this%set_history_var(vname='FATES_MORTALITY_WILDFIRE_SZPF', & units = 'm-2 yr-1', & long='wildfire 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=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_m5_si_scpf) - call this%set_history_var(vname='FATES_MORTALITY_WILDFIRE_CROWN_SZPF', & + call this%set_history_var(vname='FATES_MORTALITY_WILDFIRE_CROWN_SZPF', & units = 'm-2 yr-1', & long='wildfire mortality from crown scorch 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=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_nonrx_crown_mort_si_scpf) - call this%set_history_var(vname='FATES_MORTALITY_WILDFIRE_CAMBIAL_SZPF', & + call this%set_history_var(vname='FATES_MORTALITY_WILDFIRE_CAMBIAL_SZPF', & units = 'm-2 yr-1', & long='wildfire mortality from cambial burn 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=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_nonrx_cambial_mort_si_scpf) - - call this%set_history_var(vname='FATES_MORTALITY_RXFIRE_SZPF', & + + call this%set_history_var(vname='FATES_MORTALITY_RXFIRE_SZPF', & units = 'm-2 yr-1', & long='prescribed fire 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_m12_si_scpf) - - call this%set_history_var(vname='FATES_MORTALITY_RXCROWN_SZPF', & + + call this%set_history_var(vname='FATES_MORTALITY_RXCROWN_SZPF', & units = 'm-2 yr-1', & long='fire mortality from crown scorch due to prescribed fire 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_rx_crown_mort_si_scpf) - - call this%set_history_var(vname='FATES_MORTALITY_RXCAMBIAL_SZPF', & + + call this%set_history_var(vname='FATES_MORTALITY_RXCAMBIAL_SZPF', & units = 'm-2 yr-1', & long='fire mortality from cambial kill due to prescribed fire 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_rx_cambial_mort_si_scpf) - call this%set_history_var(vname='FATES_MORTALITY_TERMINATION_SZPF', & + call this%set_history_var(vname='FATES_MORTALITY_TERMINATION_SZPF', & units = 'm-2 yr-1', & long='termination mortality (excluding C-starvation) by pft/size in number pf plants per m2 per year', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_m6_si_scpf) - call this%set_history_var(vname='FATES_MORTALITY_LOGGING_SZPF', & + 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 year', & use_default='inactive', & avgflag='A', vtype=site_size_pft_r8, hlms='CLM:ALM', upfreq=group_dyna_complx, & ivar=ivar, initialize=initialize_variables, index = ih_m7_si_scpf) - call this%set_history_var(vname='FATES_MORTALITY_FREEZING_SZPF', & + call this%set_history_var(vname='FATES_MORTALITY_FREEZING_SZPF', & units = 'm-2 yr-1', & long='freezing 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=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_m8_si_scpf) - call this%set_history_var(vname='FATES_MORTALITY_SENESCENCE_SZPF', & + call this%set_history_var(vname='FATES_MORTALITY_SENESCENCE_SZPF', & units = 'm-2 yr-1', & long='senescence 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=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_m9_si_scpf) - call this%set_history_var(vname='FATES_MORTALITY_AGESCEN_SZPF', & + call this%set_history_var(vname='FATES_MORTALITY_AGESCEN_SZPF', & units = 'm-2 yr-1', & long='age senescence 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=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_m10_si_scpf) - call this%set_history_var(vname='FATES_MORTALITY_AGESCEN_ACPF', & + call this%set_history_var(vname='FATES_MORTALITY_AGESCEN_ACPF', & units='m-2 yr-1', & long='age senescence mortality by pft/cohort age in number of plants per m2 per year', & use_default='inactive', avgflag='A', vtype =site_coage_pft_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index =ih_m10_si_capf) - call this%set_history_var(vname='FATES_MORTALITY_CANOPY_SZPF', & + call this%set_history_var(vname='FATES_MORTALITY_CANOPY_SZPF', & units = 'm-2 yr-1', & long='total mortality of canopy plants 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=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_mortality_canopy_si_scpf) - call this%set_history_var(vname='FATES_M3_MORTALITY_CANOPY_SZPF', & + call this%set_history_var(vname='FATES_M3_MORTALITY_CANOPY_SZPF', & units = 'm-2 yr-1', & long='C starvation mortality of canopy plants by pft/size', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_m3_mortality_canopy_si_scpf ) - call this%set_history_var(vname='FATES_M3_MORTALITY_USTORY_SZPF', & + call this%set_history_var(vname='FATES_M3_MORTALITY_USTORY_SZPF', & units = 'm-2 yr-1', & long='C starvation mortality of understory plants by pft/size', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & @@ -8206,19 +8233,19 @@ subroutine define_history_vars(this, initialize_variables) initialize=initialize_variables, index = ih_m3_mortality_understory_si_scpf ) - call this%set_history_var(vname='FATES_C13DISC_SZPF', units = 'per mil', & + 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', & upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_c13disc_si_scpf) - - call this%set_history_var(vname='FATES_STOREC_CANOPY_SZPF', units = 'kg m-2', & + + call this%set_history_var(vname='FATES_STOREC_CANOPY_SZPF', units = 'kg m-2', & long='biomass in storage pools of canopy plants by pft/size in kg carbon per m2', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_bstor_canopy_si_scpf) - call this%set_history_var(vname='FATES_LEAFC_CANOPY_SZPF', & + call this%set_history_var(vname='FATES_LEAFC_CANOPY_SZPF', & units = 'kg m-2', & long='biomass in leaves of canopy plants by pft/size in kg carbon per m2', & use_default='inactive', & @@ -8226,35 +8253,35 @@ 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', & + 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=group_dyna_complx, & ivar=ivar, initialize=initialize_variables, & - index = ih_lai_canopy_si_scpf ) + index = ih_lai_canopy_si_scpf ) - call this%set_history_var(vname='FATES_CROWNAREA_CANOPY_SZPF', & + call this%set_history_var(vname='FATES_CROWNAREA_CANOPY_SZPF', & units = 'm2 m-2', & long='Total crown area of canopy plants by pft/size', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_crownarea_canopy_si_scpf ) - call this%set_history_var(vname='FATES_CROWNAREA_USTORY_SZPF', & + call this%set_history_var(vname='FATES_CROWNAREA_USTORY_SZPF', & units = 'm2 m-2', & long='Total crown area of understory plants by pft/size', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_crownarea_understory_si_scpf ) - - call this%set_history_var(vname='FATES_NPLANT_CANOPY_SZPF', units = 'm-2', & + + 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, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_nplant_canopy_si_scpf) - call this%set_history_var(vname='FATES_MORTALITY_USTORY_SZPF', & + call this%set_history_var(vname='FATES_MORTALITY_USTORY_SZPF', & units = 'm-2 yr-1', & long='total mortality of understory plants by pft/size in number of plants per m2 per year', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & @@ -8262,68 +8289,68 @@ subroutine define_history_vars(this, initialize_variables) initialize=initialize_variables, & index = ih_mortality_understory_si_scpf) - call this%set_history_var(vname='FATES_STOREC_USTORY_SZPF', & + call this%set_history_var(vname='FATES_STOREC_USTORY_SZPF', & units = 'kg m-2', & long='biomass in storage pools of understory plants by pft/size in kg carbon per m2', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_bstor_understory_si_scpf) - call this%set_history_var(vname='FATES_LEAFC_USTORY_SZPF', & + call this%set_history_var(vname='FATES_LEAFC_USTORY_SZPF', & units = 'kg m-2', & long='biomass in leaves of understory plants by pft/size in kg carbon per m2', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_bleaf_understory_si_scpf) - call this%set_history_var(vname='FATES_LAI_USTORY_SZPF', & + 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=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_lai_understory_si_scpf ) - call this%set_history_var(vname='FATES_NPLANT_USTORY_SZPF', & + 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', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_nplant_understory_si_scpf) - call this%set_history_var(vname='FATES_CWD_ABOVEGROUND_DC', units='kg m-2', & + call this%set_history_var(vname='FATES_CWD_ABOVEGROUND_DC', units='kg m-2', & long='debris class-level aboveground coarse woody debris stocks in kg carbon per m2', & use_default='inactive', avgflag='A', vtype=site_cwdsc_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_cwd_ag_si_cwdsc) - call this%set_history_var(vname='FATES_CWD_BELOWGROUND_DC', units='kg m-2', & + call this%set_history_var(vname='FATES_CWD_BELOWGROUND_DC', units='kg m-2', & long='debris class-level belowground coarse woody debris stocks in kg carbon per m2', & use_default='inactive', avgflag='A', vtype=site_cwdsc_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_cwd_bg_si_cwdsc) - call this%set_history_var(vname='FATES_CWD_ABOVEGROUND_IN_DC', & + call this%set_history_var(vname='FATES_CWD_ABOVEGROUND_IN_DC', & units='kg m-2 s-1', & long='debris class-level aboveground coarse woody debris input in kg carbon per m2 per second', & use_default='inactive', avgflag='A', vtype=site_cwdsc_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_cwd_ag_in_si_cwdsc) - call this%set_history_var(vname='FATES_CWD_BELOWGROUND_IN_DC', & + call this%set_history_var(vname='FATES_CWD_BELOWGROUND_IN_DC', & units='kg m-2 s-1', & long='debris class-level belowground coarse woody debris input in kg carbon per m2 per second', & use_default='inactive', avgflag='A', vtype=site_cwdsc_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_cwd_bg_in_si_cwdsc) - call this%set_history_var(vname='FATES_CWD_ABOVEGROUND_OUT_DC', & + call this%set_history_var(vname='FATES_CWD_ABOVEGROUND_OUT_DC', & units='kg m-2 s-1', & long='debris class-level aboveground coarse woody debris output in kg carbon per m2 per second', & use_default='inactive', avgflag='A', vtype=site_cwdsc_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_cwd_ag_out_si_cwdsc) - call this%set_history_var(vname='FATES_CWD_BELOWGROUND_OUT_DC', & + call this%set_history_var(vname='FATES_CWD_BELOWGROUND_OUT_DC', & units='kg m-2 s-1', & long='debris class-level belowground coarse woody debris output in kg carbon per m2 per second', & use_default='inactive', avgflag='A', vtype=site_cwdsc_r8, & @@ -8331,21 +8358,21 @@ subroutine define_history_vars(this, initialize_variables) initialize=initialize_variables, index = ih_cwd_bg_out_si_cwdsc) - ! size-class only variables + ! size-class only variables - call this%set_history_var(vname='FATES_DDBH_CANOPY_SZ', & + call this%set_history_var(vname='FATES_DDBH_CANOPY_SZ', & units = 'm m-2 yr-1', long='diameter growth increment by size of canopy plants', & use_default='active', avgflag='A', vtype=site_size_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_ddbh_canopy_si_scls) - call this%set_history_var(vname='FATES_DDBH_USTORY_SZ', & + call this%set_history_var(vname='FATES_DDBH_USTORY_SZ', & units = 'm m-2 yr-1', long='diameter growth increment by size of understory plants', & use_default='active', avgflag='A', vtype=site_size_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_ddbh_understory_si_scls) - call this%set_history_var(vname='FATES_YESTCANLEV_CANOPY_SZ', & + call this%set_history_var(vname='FATES_YESTCANLEV_CANOPY_SZ', & units = 'm-2', & long='yesterdays canopy level for canopy plants by size class in number of plants per m2', & use_default='inactive', avgflag='A', vtype=site_size_r8, & @@ -8353,7 +8380,7 @@ subroutine define_history_vars(this, initialize_variables) initialize=initialize_variables, & index = ih_yesterdaycanopylevel_canopy_si_scls) - call this%set_history_var(vname='FATES_YESTCANLEV_USTORY_SZ', & + call this%set_history_var(vname='FATES_YESTCANLEV_USTORY_SZ', & units = 'm-2', & long='yesterdays canopy level for understory plants by size class in number of plants per m2', & use_default='inactive', avgflag='A', vtype=site_size_r8, & @@ -8361,216 +8388,216 @@ subroutine define_history_vars(this, initialize_variables) initialize=initialize_variables, & index = ih_yesterdaycanopylevel_understory_si_scls) - call this%set_history_var(vname='FATES_BASALAREA_SZ', units = 'm2 m-2', & + call this%set_history_var(vname='FATES_BASALAREA_SZ', units = 'm2 m-2', & long='basal area by size class', use_default='active', & avgflag='A', vtype=site_size_r8, hlms='CLM:ALM', upfreq=group_dyna_complx, & ivar=ivar, initialize=initialize_variables, index = ih_ba_si_scls) - call this%set_history_var(vname='FATES_VEGC_ABOVEGROUND_SZ', & + call this%set_history_var(vname='FATES_VEGC_ABOVEGROUND_SZ', & units = 'kg m-2', & long='aboveground biomass by size class in kg carbon per m2', & use_default='active', avgflag='A', vtype=site_size_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_agb_si_scls) - call this%set_history_var(vname='FATES_VEGC_SZ', units = 'kg m-2', & + call this%set_history_var(vname='FATES_VEGC_SZ', units = 'kg m-2', & long='total biomass by size class in kg carbon per m2', & use_default='inactive', avgflag='A', vtype=site_size_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_biomass_si_scls) - call this%set_history_var(vname='FATES_DEMOTION_RATE_SZ', & + call this%set_history_var(vname='FATES_DEMOTION_RATE_SZ', & units = 'm-2 yr-1', & long='demotion rate from canopy to understory by size class in number of plants per m2 per year', & use_default='inactive', avgflag='A', vtype=site_size_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_demotion_rate_si_scls) - call this%set_history_var(vname='FATES_PROMOTION_RATE_SZ', & + call this%set_history_var(vname='FATES_PROMOTION_RATE_SZ', & units = 'm-2 yr-1', & long='promotion rate from understory to canopy by size class', & use_default='inactive', avgflag='A', vtype=site_size_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_promotion_rate_si_scls) - call this%set_history_var(vname='FATES_NPLANT_CANOPY_SZ', & + call this%set_history_var(vname='FATES_NPLANT_CANOPY_SZ', & units = 'm-2', & long='number of canopy plants per m2 by size class', & use_default='active', avgflag='A', vtype=site_size_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_nplant_canopy_si_scls) - call this%set_history_var(vname='FATES_LAI_CANOPY_SZ', units = 'm2 m-2', & + call this%set_history_var(vname='FATES_LAI_CANOPY_SZ', units = 'm2 m-2', & long='leaf area index (LAI) of canopy plants by size class', & use_default='active', avgflag='A', vtype=site_size_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_lai_canopy_si_scls) - call this%set_history_var(vname='FATES_SAI_CANOPY_SZ', units = 'm2 m-2', & + call this%set_history_var(vname='FATES_SAI_CANOPY_SZ', units = 'm2 m-2', & long='stem area index (SAI) of canopy plants by size class', & use_default='inactive', avgflag='A', vtype=site_size_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_sai_canopy_si_scls) - call this%set_history_var(vname='FATES_MORTALITY_CANOPY_SZ', & + call this%set_history_var(vname='FATES_MORTALITY_CANOPY_SZ', & units = 'm-2 yr-1', & long='total mortality of canopy trees by size class in number of plants per m2', & use_default='active', avgflag='A', vtype=site_size_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_mortality_canopy_si_scls) - call this%set_history_var(vname='FATES_MORTALITY_CANOPY_SE_SZ', & + 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=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_mortality_canopy_secondary_si_scls) - call this%set_history_var(vname='FATES_NPLANT_USTORY_SZ', & + call this%set_history_var(vname='FATES_NPLANT_USTORY_SZ', & units = 'm-2', & long='number of understory plants per m2 by size class', & use_default='active', avgflag='A', vtype=site_size_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_nplant_understory_si_scls) - call this%set_history_var(vname='FATES_M3_MORTALITY_CANOPY_SZ', & + call this%set_history_var(vname='FATES_M3_MORTALITY_CANOPY_SZ', & units = 'm-2 yr-1', & long='C starvation mortality of canopy plants by size', & use_default='inactive', avgflag='A', vtype=site_size_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_m3_mortality_canopy_si_scls ) - call this%set_history_var(vname='FATES_M3_MORTALITY_USTORY_SZ', & + call this%set_history_var(vname='FATES_M3_MORTALITY_USTORY_SZ', & units = 'm-2 yr-1', & long='C starvation mortality of understory plants by size', & use_default='inactive', avgflag='A', vtype=site_size_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_m3_mortality_understory_si_scls ) - call this%set_history_var(vname='FATES_LAI_USTORY_SZ', & + 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', & use_default='active', avgflag='A', vtype=site_size_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_lai_understory_si_scls) - call this%set_history_var(vname='FATES_SAI_USTORY_SZ', & + call this%set_history_var(vname='FATES_SAI_USTORY_SZ', & units = 'm2 m-2', & long='stem area index (SAI) of understory plants by size class', & use_default='inactive', avgflag='A', vtype=site_size_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_sai_understory_si_scls) - call this%set_history_var(vname='FATES_NPLANT_SZ', units = 'm-2', & + call this%set_history_var(vname='FATES_NPLANT_SZ', units = 'm-2', & long='number of plants per m2 by size class', use_default='active', & avgflag='A', vtype=site_size_r8, hlms='CLM:ALM', upfreq=group_dyna_complx, & ivar=ivar, initialize=initialize_variables, index = ih_nplant_si_scls) - call this%set_history_var(vname='FATES_NPLANT_AC', units = 'm-2', & + call this%set_history_var(vname='FATES_NPLANT_AC', units = 'm-2', & long='number of plants per m2 by cohort age class', & use_default='active', avgflag='A', vtype=site_coage_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_nplant_si_cacls) - call this%set_history_var(vname='FATES_MORTALITY_BACKGROUND_SZ', & + call this%set_history_var(vname='FATES_MORTALITY_BACKGROUND_SZ', & units = 'm-2 yr-1', & long='background mortality by size in number of plants per m2 per year', & use_default='active', avgflag='A', vtype=site_size_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_m1_si_scls) - call this%set_history_var(vname='FATES_MORTALITY_HYDRAULIC_SZ', & + call this%set_history_var(vname='FATES_MORTALITY_HYDRAULIC_SZ', & units = 'm-2 yr-1', & long='hydraulic mortality by size in number of plants per m2 per year', & use_default='active', avgflag='A', vtype=site_size_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_m2_si_scls) - call this%set_history_var(vname='FATES_MORTALITY_CSTARV_SZ', & + call this%set_history_var(vname='FATES_MORTALITY_CSTARV_SZ', & units = 'm-2 yr-1', & long='carbon starvation mortality by size in number of plants per m2 per year (both continous and termination)', & use_default='active', avgflag='A', vtype=site_size_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_m3_si_scls) - call this%set_history_var(vname='FATES_MORTALITY_IMPACT_SZ', & + 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', & use_default='active', avgflag='A', vtype=site_size_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_m4_si_scls) - call this%set_history_var(vname='FATES_MORTALITY_FIRE_SZ', & + call this%set_history_var(vname='FATES_MORTALITY_FIRE_SZ', & units = 'm-2 yr-1', & long='fire mortality by size in number of plants per m2 per year', & use_default='active', avgflag='A', vtype=site_size_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_m5_si_scls) - call this%set_history_var(vname='FATES_MORTALITY_RXFIRE_SZ', & + call this%set_history_var(vname='FATES_MORTALITY_RXFIRE_SZ', & units = 'm-2 yr-1', & long='prescribed fire 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_m12_si_scls) - call this%set_history_var(vname='FATES_MORTALITY_TERMINATION_SZ', & + call this%set_history_var(vname='FATES_MORTALITY_TERMINATION_SZ', & units = 'm-2 yr-1', & long='termination mortality (excluding C-starvation) by size in number of plants per m2 per year', & use_default='active', avgflag='A', vtype=site_size_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_m6_si_scls) - call this%set_history_var(vname='FATES_MORTALITY_LOGGING_SZ', & + 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 year', & use_default='active', avgflag='A', vtype=site_size_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_m7_si_scls) - call this%set_history_var(vname='FATES_MORTALITY_FREEZING_SZ', & + call this%set_history_var(vname='FATES_MORTALITY_FREEZING_SZ', & 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=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_m8_si_scls) - call this%set_history_var(vname='FATES_MORTALITY_SENESCENCE_SZ', & + 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 year', & use_default='active', avgflag='A', vtype=site_size_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_m9_si_scls) - call this%set_history_var(vname='FATES_MORTALITY_AGESCEN_SZ', & + call this%set_history_var(vname='FATES_MORTALITY_AGESCEN_SZ', & units = 'm-2 yr-1', & long='age 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=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_m10_si_scls) - call this%set_history_var(vname='FATES_MORTALITY_AGESCEN_AC', & + call this%set_history_var(vname='FATES_MORTALITY_AGESCEN_AC', & units = 'm-2 yr-1', & long='age senescence mortality by cohort age in number of plants per m2 per year', & use_default='active', avgflag='A', vtype=site_coage_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_m10_si_cacls) - call this%set_history_var(vname='FATES_NPP_CANOPY_SZ', units = 'kg m-2 s-1', & + 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, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, & index = ih_carbon_balance_canopy_si_scls) - call this%set_history_var(vname='FATES_NPP_USTORY_SZ', units = 'kg m-2 s-1', & + call this%set_history_var(vname='FATES_NPP_USTORY_SZ', units = 'kg m-2 s-1', & long='NPP of understory plants by size class in kg carbon per m2 per second', & use_default='inactive', avgflag='A', vtype=site_size_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, & index = ih_carbon_balance_understory_si_scls) - call this%set_history_var(vname='FATES_MORTALITY_USTORY_SZ', & + call this%set_history_var(vname='FATES_MORTALITY_USTORY_SZ', & units = 'm-2 yr-1', & long='total mortality of understory trees by size class in individuals per m2 per year', & use_default='active', avgflag='A', vtype=site_size_r8, & @@ -8578,13 +8605,13 @@ subroutine define_history_vars(this, initialize_variables) initialize=initialize_variables, & index = ih_mortality_understory_si_scls) - call this%set_history_var(vname='FATES_TRIMMING_CANOPY_SZ', units = 'm-2', & + call this%set_history_var(vname='FATES_TRIMMING_CANOPY_SZ', units = 'm-2', & long='trimming term of canopy plants weighted by plant density, by size class', & use_default='inactive', avgflag='A', vtype=site_size_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_trimming_canopy_si_scls) - call this%set_history_var(vname='FATES_TRIMMING_USTORY_SZ', & + call this%set_history_var(vname='FATES_TRIMMING_USTORY_SZ', & units = 'm-2', & long='trimming term of understory plants weighted by plant density, by size class', & use_default='inactive', avgflag='A', vtype=site_size_r8, & @@ -8592,103 +8619,103 @@ subroutine define_history_vars(this, initialize_variables) initialize=initialize_variables, & index = ih_trimming_understory_si_scls) - call this%set_history_var(vname='FATES_CROWNAREA_CANOPY_SZ', units = 'm2 m-2', & + call this%set_history_var(vname='FATES_CROWNAREA_CANOPY_SZ', units = 'm2 m-2', & long='total crown area of canopy plants by size class', & use_default='inactive', avgflag='A', vtype=site_size_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_crown_fracarea_canopy_si_scls) - call this%set_history_var(vname='FATES_CROWNAREA_USTORY_SZ', units = 'm2 m-2', & + call this%set_history_var(vname='FATES_CROWNAREA_USTORY_SZ', units = 'm2 m-2', & long='total crown area of understory plants by size class', & use_default='inactive', avgflag='A', vtype=site_size_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_crown_fracarea_understory_si_scls) - call this%set_history_var(vname='FATES_LEAFCTURN_CANOPY_SZ', & + call this%set_history_var(vname='FATES_LEAFCTURN_CANOPY_SZ', & units = 'kg m-2 s-1', & long='leaf turnover (non-mortal) for canopy plants by size class in kg carbon per m2 per second', & use_default='inactive', avgflag='A', vtype=site_size_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_leaf_md_canopy_si_scls) - call this%set_history_var(vname='FATES_FROOTCTURN_CANOPY_SZ', & + call this%set_history_var(vname='FATES_FROOTCTURN_CANOPY_SZ', & units = 'kg m-2 s-1', & long='fine root turnover (non-mortal) for canopy plants by size class in kg carbon per m2 per second', & use_default='inactive', avgflag='A', vtype=site_size_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_root_md_canopy_si_scls) - call this%set_history_var(vname='FATES_STORECTURN_CANOPY_SZ', & + call this%set_history_var(vname='FATES_STORECTURN_CANOPY_SZ', & units = 'kg m-2 s-1', & long='storage turnover (non-mortal) for canopy plants by size class in kg carbon per m2 per second', & use_default='inactive', avgflag='A', vtype=site_size_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_bstore_md_canopy_si_scls) - call this%set_history_var(vname='FATES_STRUCTCTURN_CANOPY_SZ', & + call this%set_history_var(vname='FATES_STRUCTCTURN_CANOPY_SZ', & units = 'kg m-2 s-1', & long='structural C turnover (non-mortal) for canopy plants by size class in kg carbon per m2 per second', & use_default='inactive', avgflag='A', vtype=site_size_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_bdead_md_canopy_si_scls) - call this%set_history_var(vname='FATES_SAPWOODCTURN_CANOPY_SZ', & + call this%set_history_var(vname='FATES_SAPWOODCTURN_CANOPY_SZ', & units = 'kg m-2 s-1', & long='sapwood turnover (non-mortal) for canopy plants by size class in kg carbon per m2 per second', & use_default='inactive', avgflag='A', vtype=site_size_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_bsw_md_canopy_si_scls) - call this%set_history_var(vname='FATES_SEED_PROD_CANOPY_SZ', & + call this%set_history_var(vname='FATES_SEED_PROD_CANOPY_SZ', & units = 'kg m-2 s-1', & long='seed production of canopy plants by size class in kg carbon per m2 per second', & use_default='inactive', avgflag='A', vtype=site_size_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_seed_prod_canopy_si_scls) - call this%set_history_var(vname='FATES_LEAF_ALLOC_CANOPY_SZ', & + call this%set_history_var(vname='FATES_LEAF_ALLOC_CANOPY_SZ', & units = 'kg m-2 s-1', & long='allocation to leaves for canopy plants by size class in kg carbon per m2 per second', & use_default='inactive', avgflag='A', vtype=site_size_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_npp_leaf_canopy_si_scls) - call this%set_history_var(vname='FATES_FROOT_ALLOC_CANOPY_SZ', & + call this%set_history_var(vname='FATES_FROOT_ALLOC_CANOPY_SZ', & units = 'kg m-2 s-1', & long='allocation to fine root C for canopy plants by size class in kg carbon per m2 per second', & use_default='inactive', avgflag='A', vtype=site_size_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_npp_fnrt_canopy_si_scls) - call this%set_history_var(vname='FATES_SAPWOOD_ALLOC_CANOPY_SZ', & + call this%set_history_var(vname='FATES_SAPWOOD_ALLOC_CANOPY_SZ', & units = 'kg m-2 s-1', & long='allocation to sapwood C for canopy plants by size class in kg carbon per m2 per second', & use_default='inactive', avgflag='A', vtype=site_size_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_npp_sapw_canopy_si_scls) - call this%set_history_var(vname='FATES_STRUCT_ALLOC_CANOPY_SZ', & + call this%set_history_var(vname='FATES_STRUCT_ALLOC_CANOPY_SZ', & units = 'kg m-2 s-1', & long='allocation to structural C for canopy plants by size class in kg carbon per m2 per second', & use_default='inactive', avgflag='A', vtype=site_size_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_npp_dead_canopy_si_scls) - call this%set_history_var(vname='FATES_SEED_ALLOC_CANOPY_SZ', & + call this%set_history_var(vname='FATES_SEED_ALLOC_CANOPY_SZ', & units = 'kg m-2 s-1', & long='allocation to reproductive C for canopy plants by size class in kg carbon per m2 per second', & use_default='inactive', avgflag='A', vtype=site_size_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_npp_seed_canopy_si_scls) - call this%set_history_var(vname='FATES_STORE_ALLOC_CANOPY_SZ', & + call this%set_history_var(vname='FATES_STORE_ALLOC_CANOPY_SZ', & units = 'kg m-2 s-1', & long='allocation to storage C for canopy plants by size class in kg carbon per m2 per second', & use_default='inactive', avgflag='A', vtype=site_size_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_npp_stor_canopy_si_scls) - call this%set_history_var(vname='FATES_LEAFCTURN_USTORY_SZ', & + call this%set_history_var(vname='FATES_LEAFCTURN_USTORY_SZ', & units = 'kg m-2 s-1', & long='leaf turnover (non-mortal) for understory plants by size class in kg carbon per m2 per second', & use_default='inactive', avgflag='A', vtype=site_size_r8, & @@ -8696,7 +8723,7 @@ subroutine define_history_vars(this, initialize_variables) initialize=initialize_variables, & index = ih_leaf_md_understory_si_scls) - call this%set_history_var(vname='FATES_FROOTCTURN_USTORY_SZ', & + call this%set_history_var(vname='FATES_FROOTCTURN_USTORY_SZ', & units = 'kg m-2 s-1', & long='fine root turnover (non-mortal) for understory plants by size class in kg carbon per m2 per second', & use_default='inactive', avgflag='A', vtype=site_size_r8, & @@ -8704,7 +8731,7 @@ subroutine define_history_vars(this, initialize_variables) initialize=initialize_variables, & index = ih_root_md_understory_si_scls) - call this%set_history_var(vname='FATES_STORECTURN_USTORY_SZ', & + call this%set_history_var(vname='FATES_STORECTURN_USTORY_SZ', & units = 'kg m-2 s-1', & long='storage C turnover (non-mortal) for understory plants by size class in kg carbon per m2 per second', & use_default='inactive', avgflag='A', vtype=site_size_r8, & @@ -8712,7 +8739,7 @@ subroutine define_history_vars(this, initialize_variables) initialize=initialize_variables, & index = ih_bstore_md_understory_si_scls) - call this%set_history_var(vname='FATES_STRUCTCTURN_USTORY_SZ', & + call this%set_history_var(vname='FATES_STRUCTCTURN_USTORY_SZ', & units = 'kg m-2 s-1', & long='structural C turnover (non-mortal) for understory plants by size class in kg carbon per m2 per second', & use_default='inactive', avgflag='A', vtype=site_size_r8, & @@ -8720,14 +8747,14 @@ subroutine define_history_vars(this, initialize_variables) initialize=initialize_variables, & index = ih_bdead_md_understory_si_scls) - call this%set_history_var(vname='FATES_SAPWOODCTURN_USTORY_SZ', & + call this%set_history_var(vname='FATES_SAPWOODCTURN_USTORY_SZ', & units = 'kg m-2 s-1', & long='sapwood C turnover (non-mortal) for understory plants by size class in kg carbon per m2 per second', & use_default='inactive', avgflag='A', vtype=site_size_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_bsw_md_understory_si_scls) - call this%set_history_var(vname='FATES_SEED_PROD_USTORY_SZ', & + call this%set_history_var(vname='FATES_SEED_PROD_USTORY_SZ', & units = 'kg m-2 s-1', & long='seed production of understory plants by size class in kg carbon per m2 per second', & use_default='inactive', avgflag='A', vtype=site_size_r8, & @@ -8735,223 +8762,223 @@ subroutine define_history_vars(this, initialize_variables) initialize=initialize_variables, & index = ih_seed_prod_understory_si_scls) - call this%set_history_var(vname='FATES_LEAF_ALLOC_USTORY_SZ', & + call this%set_history_var(vname='FATES_LEAF_ALLOC_USTORY_SZ', & units = 'kg m-2 s-1', & long='allocation to leaves for understory plants by size class in kg carbon per m2 per second', & use_default='inactive', avgflag='A', vtype=site_size_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_npp_leaf_understory_si_scls) - call this%set_history_var(vname='FATES_FROOT_ALLOC_USTORY_SZ', & + call this%set_history_var(vname='FATES_FROOT_ALLOC_USTORY_SZ', & units = 'kg m-2 s-1', & long='allocation to fine roots for understory plants by size class in kg carbon per m2 per second', & use_default='inactive', avgflag='A', vtype=site_size_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_npp_fnrt_understory_si_scls) - call this%set_history_var(vname='FATES_SAPWOOD_ALLOC_USTORY_SZ', & + call this%set_history_var(vname='FATES_SAPWOOD_ALLOC_USTORY_SZ', & units = 'kg m-2 s-1', & long='allocation to sapwood C for understory plants by size class in kg carbon per m2 per second', & use_default='inactive', avgflag='A', vtype=site_size_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_npp_sapw_understory_si_scls) - call this%set_history_var(vname='FATES_STRUCT_ALLOC_USTORY_SZ', & + call this%set_history_var(vname='FATES_STRUCT_ALLOC_USTORY_SZ', & units = 'kg m-2 s-1', & long='allocation to structural C for understory plants by size class in kg carbon per m2 per second', & use_default='inactive', avgflag='A', vtype=site_size_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_npp_dead_understory_si_scls) - call this%set_history_var(vname='FATES_SEED_ALLOC_USTORY_SZ', & + call this%set_history_var(vname='FATES_SEED_ALLOC_USTORY_SZ', & units = 'kg m-2 s-1', & long='allocation to reproductive C for understory plants by size class in kg carbon per m2 per second', & use_default='inactive', avgflag='A', vtype=site_size_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_npp_seed_understory_si_scls) - call this%set_history_var(vname='FATES_STORE_ALLOC_USTORY_SZ', & + call this%set_history_var(vname='FATES_STORE_ALLOC_USTORY_SZ', & units = 'kg m-2 s-1', & long='allocation to storage C for understory plants by size class in kg carbon per m2 per second', & use_default='inactive', avgflag='A', vtype=site_size_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_npp_stor_understory_si_scls) - ! CROWN DAMAGE VARIABLES - if_crowndamage: if(hlm_use_tree_damage .eq. itrue) then + ! CROWN DAMAGE VARIABLES + if_crowndamage: if(hlm_use_tree_damage .eq. itrue) then - call this%set_history_var(vname='FATES_NPLANT_CDPF', units = 'm-2', & + 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=group_dyna_complx, ivar=ivar, initialize=initialize_variables, index = ih_nplant_si_cdpf ) - call this%set_history_var(vname='FATES_NPLANT_CANOPY_CDPF', units = 'm-2', & + 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=group_dyna_complx, ivar=ivar, initialize=initialize_variables, index = ih_nplant_canopy_si_cdpf ) - call this%set_history_var(vname='FATES_NPLANT_USTORY_CDPF', units = 'm-2', & + 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=group_dyna_complx, 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', & + 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=group_dyna_complx, ivar=ivar, initialize=initialize_variables, index = ih_m3_si_cdpf ) - call this%set_history_var(vname='FATES_M11_SZPF', units = 'm-2 yr-1', & + 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=group_dyna_complx, ivar=ivar, initialize=initialize_variables, index = ih_m11_si_scpf ) - call this%set_history_var(vname='FATES_M11_CDPF', units = 'm-2 yr-1', & + 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=group_dyna_complx, ivar=ivar, initialize=initialize_variables, index = ih_m11_si_cdpf ) - call this%set_history_var(vname='FATES_MORTALITY_CDPF', units = 'm-2 yr-1', & + 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=group_dyna_complx, 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', & + 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=group_dyna_complx, 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', & + 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=group_dyna_complx, 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', & + 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=group_dyna_complx, 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', & + 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=group_dyna_complx, 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', & + 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=group_dyna_complx, 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', & + 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=group_dyna_complx, 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', & + 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=group_dyna_complx, 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', & + 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=group_dyna_complx, 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', & + 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=group_dyna_complx, ivar=ivar, initialize=initialize_variables, index = ih_ddbh_understory_si_cdpf ) - end if if_crowndamage + end if if_crowndamage - call this%set_history_var(vname='FATES_FIRE_FLUX_EL', units='kg m-2 s-1', & + call this%set_history_var(vname='FATES_FIRE_FLUX_EL', units='kg m-2 s-1', & long='loss to atmosphere from fire by element in kg element per m2 per s', & use_default='active', avgflag='A', vtype=site_elem_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_burn_flux_elem) - if((hlm_use_ed_st3 .eq. ifalse) .and. (hlm_use_sp .eq. ifalse))then - call this%set_history_var(vname='FATES_ERROR_EL', units='kg s-1', & + if((hlm_use_ed_st3 .eq. ifalse) .and. (hlm_use_sp .eq. ifalse))then + call this%set_history_var(vname='FATES_ERROR_EL', units='kg s-1', & long='total mass-balance error in kg per second by element', & use_default='active', avgflag='A', vtype=site_elem_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_err_fates_elem) - - call this%set_history_var(vname='FATES_INTERR_LIVEVEG_EL',units='kg m-2', & + + call this%set_history_var(vname='FATES_INTERR_LIVEVEG_EL',units='kg m-2', & long='Bias error between integrated flux and (minus) state in live vegetation ', & use_default='active', avgflag='A', vtype=site_elem_r8, hlms='CLM:ALM', & upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_interr_liveveg_elem) - - call this%set_history_var(vname='FATES_INTERR_LITTER_EL',units='kg m-2', & + + call this%set_history_var(vname='FATES_INTERR_LITTER_EL',units='kg m-2', & long='Bias error between integrated flux and (minus) state in litter ', & use_default='active', avgflag='A', vtype=site_elem_r8, hlms='CLM:ALM', & upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_interr_litter_elem) - end if - - call this%set_history_var(vname='FATES_LITTER_AG_FINE_EL', units='kg m-2', & + end if + + call this%set_history_var(vname='FATES_LITTER_AG_FINE_EL', units='kg m-2', & long='mass of aboveground litter in fines (leaves, nonviable seed) by element', & use_default='active', avgflag='A', vtype=site_elem_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_fines_ag_elem) - call this%set_history_var(vname='FATES_LITTER_BG_FINE_EL', units='kg m-2', & + call this%set_history_var(vname='FATES_LITTER_BG_FINE_EL', units='kg m-2', & long='mass of belowground litter in fines (fineroots) by element', & use_default='active', avgflag='A', vtype=site_elem_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_fines_bg_elem) - call this%set_history_var(vname='FATES_LITTER_BG_CWD_EL', units='kg m-2', & + call this%set_history_var(vname='FATES_LITTER_BG_CWD_EL', units='kg m-2', & long='mass of belowground litter in coarse woody debris (coarse roots) by element', & use_default='active', avgflag='A', vtype=site_elem_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_cwd_bg_elem) - call this%set_history_var(vname='FATES_LITTER_AG_CWD_EL', units='kg m-2', & + call this%set_history_var(vname='FATES_LITTER_AG_CWD_EL', units='kg m-2', & long='mass of aboveground litter in coarse woody debris (trunks/branches/twigs) by element', & use_default='active', avgflag='A', vtype=site_elem_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_cwd_ag_elem) - call this%set_history_var(vname='FATES_LITTER_CWD_ELDC', units='kg m-2', & + call this%set_history_var(vname='FATES_LITTER_CWD_ELDC', units='kg m-2', & long='total mass of litter in coarse woody debris by element and coarse woody debris size', & use_default='active', avgflag='A', vtype=site_elcwd_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & initialize=initialize_variables, index = ih_cwd_elcwd) - ! Mass states C/N/P SCPF dimensions - ! CARBON - call this%set_history_var(vname='FATES_VEGC_SZPF', units='kg m-2', & + ! Mass states C/N/P SCPF dimensions + ! CARBON + call this%set_history_var(vname='FATES_VEGC_SZPF', units='kg m-2', & long='total vegetation biomass in live plants by size-class x pft in kg carbon per m2', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_totvegc_scpf) - call this%set_history_var(vname='FATES_LEAFC_SZPF', units='kg m-2', & + call this%set_history_var(vname='FATES_LEAFC_SZPF', units='kg m-2', & long='leaf carbon mass by size-class x pft in kg carbon per m2', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_leafc_scpf) - call this%set_history_var(vname='FATES_FROOTC_SZPF', units='kg m-2', & + call this%set_history_var(vname='FATES_FROOTC_SZPF', units='kg m-2', & long='fine-root carbon mass by size-class x pft in kg carbon per m2', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_fnrtc_scpf) - call this%set_history_var(vname='FATES_SAPWOODC_SZPF', units='kg m-2', & + call this%set_history_var(vname='FATES_SAPWOODC_SZPF', units='kg m-2', & long='sapwood carbon mass by size-class x pft in kg carbon per m2', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_sapwc_scpf) - call this%set_history_var(vname='FATES_STOREC_SZPF', units='kg m-2', & + call this%set_history_var(vname='FATES_STOREC_SZPF', units='kg m-2', & long='storage carbon mass by size-class x pft in kg carbon per m2', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & index = ih_storec_scpf) - call this%set_history_var(vname='FATES_REPROC_SZPF', units='kg m-2', & + call this%set_history_var(vname='FATES_REPROC_SZPF', units='kg m-2', & long='reproductive carbon mass (on plant) by size-class x pft in kg carbon per m2', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & @@ -8959,84 +8986,84 @@ subroutine define_history_vars(this, initialize_variables) - end if if_dyn1 - end if if_dyn0 + end if if_dyn1 + end if if_dyn0 - if_hifrq0: if(hlm_hist_level_hifrq>0) then + if_hifrq0: if(hlm_hist_level_hifrq>0) then - ! Canopy Resistance + ! Canopy Resistance - call this%set_history_var(vname='FATES_STOMATAL_COND', & + call this%set_history_var(vname='FATES_STOMATAL_COND', & units='mol m-2 s-1', long='mean stomatal conductance', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_hifr_simple, ivar=ivar, initialize=initialize_variables, & index = ih_c_stomata_si) - call this%set_history_var(vname='FATES_LBLAYER_COND', units='mol m-2 s-1', & + call this%set_history_var(vname='FATES_LBLAYER_COND', units='mol m-2 s-1', & long='mean leaf boundary layer conductance', use_default='active', & avgflag='A', vtype=site_r8, hlms='CLM:ALM', upfreq=group_hifr_simple, & ivar=ivar, initialize=initialize_variables, index = ih_c_lblayer_si) - ! Temperature + ! Temperature - call this%set_history_var(vname='FATES_TVEG', units='degree_Celsius', & + 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=group_hifr_simple, & ivar=ivar, initialize=initialize_variables, index = ih_tveg_si ) - call this%set_history_var(vname='FATES_VIS_RAD_ERROR', units='-', & + call this%set_history_var(vname='FATES_VIS_RAD_ERROR', units='-', & long='mean two-stream solver error for VIS', use_default='active', & avgflag='A', vtype=site_r8, hlms='CLM:ALM', upfreq=group_hifr_simple, & ivar=ivar, initialize=initialize_variables, index = ih_vis_rad_err_si) - call this%set_history_var(vname='FATES_NIR_RAD_ERROR', units='-', & + call this%set_history_var(vname='FATES_NIR_RAD_ERROR', units='-', & long='mean two-stream solver error for NIR', use_default='active', & avgflag='A', vtype=site_r8, hlms='CLM:ALM', upfreq=group_hifr_simple, & ivar=ivar, initialize=initialize_variables, index = ih_nir_rad_err_si) - ! Ecosystem Carbon Fluxes (updated rapidly, upfreq=group_hifr_simple) + ! Ecosystem Carbon Fluxes (updated rapidly, upfreq=group_hifr_simple) - call this%set_history_var(vname='FATES_GPP', units='kg m-2 s-1', & + 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=group_hifr_simple, ivar=ivar, initialize=initialize_variables, index = ih_gpp_si) - call this%set_history_var(vname='FATES_MAINT_RESP', units='kg m-2 s-1', & + 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=group_hifr_simple, ivar=ivar, initialize=initialize_variables, & index = ih_maint_resp_si) - call this%set_history_var(vname='FATES_MAINT_RESP_UNREDUCED', units='kg m-2 s-1', & + 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='unactive', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_hifr_simple, ivar=ivar, initialize=initialize_variables, & index = ih_maint_resp_unreduced_si) - ! fast fluxes separated canopy/understory - call this%set_history_var(vname='FATES_GPP_CANOPY', units='kg m-2 s-1', & + ! 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', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_hifr_simple, ivar=ivar, initialize=initialize_variables, & index = ih_gpp_canopy_si) - call this%set_history_var(vname='FATES_AUTORESP_CANOPY', & + call this%set_history_var(vname='FATES_AUTORESP_CANOPY', & units='kg m-2 s-1', & long='autotrophic respiration of canopy plants in kg carbon per m2 per second', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_hifr_simple, ivar=ivar, initialize=initialize_variables, & index = ih_ar_canopy_si) - call this%set_history_var(vname='FATES_GPP_USTORY', & + 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=group_hifr_simple, ivar=ivar, initialize=initialize_variables, & index = ih_gpp_understory_si) - call this%set_history_var(vname='FATES_AUTORESP_USTORY', & + 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', & @@ -9045,120 +9072,120 @@ subroutine define_history_vars(this, initialize_variables) - call this%set_history_var(vname='FATES_LEAFMAINTAR', & + call this%set_history_var(vname='FATES_LEAFMAINTAR', & units = 'kg m-2 s-1', & long='leaf maintenance autotrophic respiration in kg carbon per m2 per second', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_hifr_simple, ivar=ivar, initialize=initialize_variables, & index = ih_leaf_mr_si) - call this%set_history_var(vname='FATES_FROOTMAINTAR', & + call this%set_history_var(vname='FATES_FROOTMAINTAR', & units = 'kg m-2 s-1', & long='fine root maintenance autotrophic respiration in kg carbon per m2 per second', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_hifr_simple, ivar=ivar, initialize=initialize_variables, & index = ih_froot_mr_si) - call this%set_history_var(vname='FATES_CROOTMAINTAR', & + call this%set_history_var(vname='FATES_CROOTMAINTAR', & units = 'kg m-2 s-1', & long='live coarse root maintenance autotrophic respiration in kg carbon per m2 per second', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_hifr_simple, ivar=ivar, initialize=initialize_variables, & index = ih_livecroot_mr_si) - call this%set_history_var(vname='FATES_LSTEMMAINTAR', & + call this%set_history_var(vname='FATES_LSTEMMAINTAR', & units = 'kg m-2 s-1', & long='live stem maintenance autotrophic respiration in kg carbon per m2 per second', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_hifr_simple, ivar=ivar, initialize=initialize_variables, & index = ih_livestem_mr_si) - call this%set_history_var(vname='FATES_NEP', units='kg m-2 s-1', & + call this%set_history_var(vname='FATES_NEP', units='kg m-2 s-1', & long='net ecosystem production in kg carbon per m2 per second', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_hifr_simple, ivar=ivar, initialize=initialize_variables, & index = ih_nep_si) - call this%set_history_var(vname='FATES_HET_RESP', units='kg m-2 s-1', & + call this%set_history_var(vname='FATES_HET_RESP', units='kg m-2 s-1', & long='heterotrophic respiration in kg carbon per m2 per second', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_hifr_simple, ivar=ivar, initialize=initialize_variables, index = ih_hr_si) - hydro_active_if0: if(hlm_use_planthydro.eq.itrue) then - call this%set_history_var(vname='FATES_SAPFLOW', units='kg m-2 s-1', & + hydro_active_if0: if(hlm_use_planthydro.eq.itrue) then + call this%set_history_var(vname='FATES_SAPFLOW', units='kg m-2 s-1', & long='areal sap flow rate in kg per m2 ground area per second', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_hydr_simple, ivar=ivar, initialize=initialize_variables, & index = ih_sapflow_si) - - call this%set_history_var(vname='FATES_ROOTWGT_SOILVWC', units='m3 m-3', & + + call this%set_history_var(vname='FATES_ROOTWGT_SOILVWC', units='m3 m-3', & long='soil volumetric water content, weighted by root area', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_hydr_simple, ivar=ivar, initialize=initialize_variables, & index = ih_rootwgt_soilvwc_si) - call this%set_history_var(vname='FATES_ROOTWGT_SOILVWCSAT', & + call this%set_history_var(vname='FATES_ROOTWGT_SOILVWCSAT', & units='m3 m-3', & long='soil saturated volumetric water content, weighted by root area', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_hydr_simple, ivar=ivar, initialize=initialize_variables, & index = ih_rootwgt_soilvwcsat_si) - call this%set_history_var(vname='FATES_ROOTWGT_SOILMATPOT', units='Pa', & + call this%set_history_var(vname='FATES_ROOTWGT_SOILMATPOT', units='Pa', & long='soil matric potential, weighted by root area', & use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & upfreq=group_hydr_simple, ivar=ivar, initialize=initialize_variables, & index = ih_rootwgt_soilmatpot_si) - call this%set_history_var(vname='FATES_ROOTUPTAKE', units='kg m-2 s-1', & + call this%set_history_var(vname='FATES_ROOTUPTAKE', units='kg m-2 s-1', & long='root water uptake rate', use_default='active', avgflag='A', & vtype=site_r8, hlms='CLM:ALM', upfreq=group_hydr_simple, ivar=ivar, & initialize=initialize_variables, index = ih_rootuptake_si) - call this%set_history_var(vname='FATES_VEGH2O', units = 'kg m-2', & + call this%set_history_var(vname='FATES_VEGH2O', units = 'kg m-2', & long='water stored inside vegetation tissues (leaf, stem, roots)', & use_default='inactive', avgflag='A', vtype=site_r8, & hlms='CLM:ALM', upfreq=group_hydr_simple, ivar=ivar, & initialize=initialize_variables, index = ih_h2oveg_si) - call this%set_history_var(vname='FATES_VEGH2O_HYDRO_ERR', & + call this%set_history_var(vname='FATES_VEGH2O_HYDRO_ERR', & units = 'kg m-2', & long='cumulative net borrowed (+) from plant_stored_h2o due to plant hydrodynamics', & use_default='inactive', avgflag='A', vtype=site_r8, & hlms='CLM:ALM', upfreq=group_hydr_simple, ivar=ivar, & initialize=initialize_variables, index = ih_h2oveg_hydro_err_si) - end if hydro_active_if0 + end if hydro_active_if0 - !HERE + !HERE - if_hifrq1: if(hlm_hist_level_hifrq>1) then + if_hifrq1: if(hlm_hist_level_hifrq>1) then - ! This next group are multidimensional variables that are updated - ! over the short timestep. We turn off these variables when we want - ! to save time (and some space) + ! This next group are multidimensional variables that are updated + ! over the short timestep. We turn off these variables when we want + ! to save time (and some space) - call this%set_history_var(vname='FATES_GPP_AP', units='kg m-2 s-1', & + call this%set_history_var(vname='FATES_GPP_AP', units='kg m-2 s-1', & long='gross primary productivity by age bin in kg carbon per m2 per second'// & this%per_ageclass_norm_info('FATES_PATCHAREA/FATES_PATCHAREA_AP'), & use_default='inactive', avgflag='A', vtype=site_age_r8, & hlms='CLM:ALM', upfreq=group_hifr_complx, ivar=ivar, initialize=initialize_variables, & index = ih_gpp_si_age) - call this%set_history_var(vname='FATES_GPP_LU', units='kg m-2 s-1', & + call this%set_history_var(vname='FATES_GPP_LU', units='kg m-2 s-1', & long='gross primary productivity by land use type in kg carbon per m2 per second', & use_default='inactive', avgflag='A', vtype=site_landuse_r8, & hlms='CLM:ALM', upfreq=group_hifr_complx, ivar=ivar, initialize=initialize_variables, & index = ih_gpp_si_landuse) - call this%set_history_var(vname='FATES_RDARK_USTORY_SZ', & + call this%set_history_var(vname='FATES_RDARK_USTORY_SZ', & units = 'kg m-2 s-1', & long='dark respiration for understory plants in kg carbon per m2 per second by size', & use_default='inactive', avgflag='A', vtype=site_size_r8, & hlms='CLM:ALM', upfreq=group_hifr_complx, ivar=ivar, & initialize=initialize_variables, index = ih_rdark_understory_si_scls) - call this%set_history_var(vname='FATES_LSTEMMAINTAR_USTORY_SZ', & + call this%set_history_var(vname='FATES_LSTEMMAINTAR_USTORY_SZ', & units = 'kg m-2 s-1', & long='live stem maintenance autotrophic respiration for understory plants in kg carbon per m2 per second by size', & use_default='inactive', avgflag='A', vtype=site_size_r8, & @@ -9166,7 +9193,7 @@ subroutine define_history_vars(this, initialize_variables) initialize=initialize_variables, & index = ih_livestem_mr_understory_si_scls) - call this%set_history_var(vname='FATES_CROOTMAINTAR_USTORY_SZ', & + call this%set_history_var(vname='FATES_CROOTMAINTAR_USTORY_SZ', & units = 'kg m-2 s-1', & long='live coarse root maintenance autotrophic respiration for understory plants in kg carbon per m2 per second by size', & use_default='inactive', avgflag='A', vtype=site_size_r8, & @@ -9174,7 +9201,7 @@ subroutine define_history_vars(this, initialize_variables) initialize=initialize_variables, & index = ih_livecroot_mr_understory_si_scls) - call this%set_history_var(vname='FATES_FROOTMAINTAR_USTORY_SZ', & + call this%set_history_var(vname='FATES_FROOTMAINTAR_USTORY_SZ', & units = 'kg m-2 s-1', & long='fine root maintenance autotrophic respiration for understory plants in kg carbon per m2 per second by size', & use_default='inactive', avgflag='A', vtype=site_size_r8, & @@ -9182,14 +9209,14 @@ subroutine define_history_vars(this, initialize_variables) initialize=initialize_variables, & index = ih_froot_mr_understory_si_scls) - call this%set_history_var(vname='FATES_GROWAR_USTORY_SZ', & + call this%set_history_var(vname='FATES_GROWAR_USTORY_SZ', & units = 'kg m-2 s-1', & long='growth autotrophic respiration of understory plants in kg carbon per m2 per second by size', & use_default='inactive', avgflag='A', vtype=site_size_r8, & hlms='CLM:ALM', upfreq=group_hifr_complx, ivar=ivar, & initialize=initialize_variables, index = ih_resp_g_understory_si_scls) - call this%set_history_var(vname='FATES_MAINTAR_USTORY_SZ', & + call this%set_history_var(vname='FATES_MAINTAR_USTORY_SZ', & units = 'kg m-2 s-1', & long='maintenance autotrophic respiration of understory plants in kg carbon per m2 per second by size', & use_default='inactive', avgflag='A', vtype=site_size_r8, & @@ -9197,14 +9224,14 @@ subroutine define_history_vars(this, initialize_variables) upfreq=group_hifr_complx, ivar=ivar, initialize=initialize_variables, & index = ih_resp_m_understory_si_scls) - call this%set_history_var(vname='FATES_RDARK_CANOPY_SZ', & + call this%set_history_var(vname='FATES_RDARK_CANOPY_SZ', & units = 'kg m-2 s-1', & long='dark respiration for canopy plants in kg carbon per m2 per second by size', & use_default='inactive', avgflag='A', vtype=site_size_r8, & hlms='CLM:ALM', upfreq=group_hifr_complx, ivar=ivar, & initialize=initialize_variables, index = ih_rdark_canopy_si_scls) - call this%set_history_var(vname='FATES_CROOTMAINTAR_CANOPY_SZ', & + call this%set_history_var(vname='FATES_CROOTMAINTAR_CANOPY_SZ', & units = 'kg m-2 s-1', & long='live coarse root maintenance autotrophic respiration for canopy plants in kg carbon per m2 per second by size', & use_default='inactive', avgflag='A', vtype=site_size_r8, & @@ -9212,28 +9239,28 @@ subroutine define_history_vars(this, initialize_variables) initialize=initialize_variables, & index = ih_livecroot_mr_canopy_si_scls) - call this%set_history_var(vname='FATES_FROOTMAINTAR_CANOPY_SZ', & + call this%set_history_var(vname='FATES_FROOTMAINTAR_CANOPY_SZ', & units = 'kg m-2 s-1', & long='live coarse root maintenance autotrophic respiration for canopy plants in kg carbon per m2 per second by size', & use_default='inactive', avgflag='A', vtype=site_size_r8, & hlms='CLM:ALM', upfreq=group_hifr_complx, ivar=ivar, & initialize=initialize_variables, index = ih_froot_mr_canopy_si_scls) - call this%set_history_var(vname='FATES_GROWAR_CANOPY_SZ', & + call this%set_history_var(vname='FATES_GROWAR_CANOPY_SZ', & units = 'kg m-2 s-1', & long='growth autotrophic respiration of canopy plants in kg carbon per m2 per second by size', & use_default='inactive', avgflag='A', vtype=site_size_r8, & hlms='CLM:ALM', upfreq=group_hifr_complx, ivar=ivar, & initialize=initialize_variables, index = ih_resp_g_canopy_si_scls) - call this%set_history_var(vname='FATES_MAINTAR_CANOPY_SZ', & + call this%set_history_var(vname='FATES_MAINTAR_CANOPY_SZ', & units = 'kg m-2 s-1', & long='maintenance autotrophic respiration of canopy plants in kg carbon per m2 per second by size', & use_default='inactive', avgflag='A', vtype=site_size_r8, & hlms='CLM:ALM', upfreq=group_hifr_complx, ivar=ivar, & initialize=initialize_variables, index = ih_resp_m_canopy_si_scls) - call this%set_history_var(vname='FATES_LSTEMMAINTAR_CANOPY_SZ', & + call this%set_history_var(vname='FATES_LSTEMMAINTAR_CANOPY_SZ', & units = 'kg m-2 s-1', & long='live stem maintenance autotrophic respiration for canopy plants in kg carbon per m2 per second by size', & use_default='inactive', avgflag='A', vtype=site_size_r8, & @@ -9241,167 +9268,167 @@ subroutine define_history_vars(this, initialize_variables) initialize=initialize_variables, & index = ih_livestem_mr_canopy_si_scls) - call this%set_history_var(vname='FATES_AUTORESP_SZPF', & + call this%set_history_var(vname='FATES_AUTORESP_SZPF', & units = 'kg m-2 s-1', & long='total autotrophic respiration in kg carbon per m2 per second by pft/size', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_hifr_complx, ivar=ivar, & initialize=initialize_variables, index = ih_ar_si_scpf) - call this%set_history_var(vname='FATES_GROWAR_SZPF', & + call this%set_history_var(vname='FATES_GROWAR_SZPF', & units = 'kg m-2 s-1', & long='growth autotrophic respiration in kg carbon per m2 per second by pft/size', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_hifr_complx, ivar=ivar, & initialize=initialize_variables, index = ih_ar_grow_si_scpf) - call this%set_history_var(vname='FATES_MAINTAR_SZPF', & + call this%set_history_var(vname='FATES_MAINTAR_SZPF', & units = 'kg m-2 s-1', & long='maintenance autotrophic respiration in kg carbon per m2 per second by pft/size', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_hifr_complx, ivar=ivar, & initialize=initialize_variables, index = ih_ar_maint_si_scpf) - call this%set_history_var(vname='FATES_RDARK_SZPF', & + call this%set_history_var(vname='FATES_RDARK_SZPF', & units = 'kg m-2 s-1', & long='dark portion of maintenance autotrophic respiration in kg carbon per m2 per second by pft/size', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_hifr_complx, ivar=ivar, & initialize=initialize_variables, index = ih_ar_darkm_si_scpf) - call this%set_history_var(vname='FATES_AGSAPMAINTAR_SZPF', & + call this%set_history_var(vname='FATES_AGSAPMAINTAR_SZPF', & units = 'kg m-2 s-1', & long='above-ground sapwood maintenance autotrophic respiration in kg carbon per m2 per second by pft/size', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_hifr_complx, ivar=ivar, & initialize=initialize_variables, index = ih_ar_agsapm_si_scpf) - call this%set_history_var(vname='FATES_BGSAPMAINTAR_SZPF', & + call this%set_history_var(vname='FATES_BGSAPMAINTAR_SZPF', & units = 'kg m-2 s-1', & long='below-ground sapwood maintenance autotrophic respiration in kg carbon per m2 per second by pft/size', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_hifr_complx, ivar=ivar, & initialize=initialize_variables, index = ih_ar_crootm_si_scpf) - call this%set_history_var(vname='FATES_FROOTMAINTAR_SZPF', & + call this%set_history_var(vname='FATES_FROOTMAINTAR_SZPF', & units = 'kg m-2 s-1', & long='fine root maintenance autotrophic respiration in kg carbon per m2 per second by pft/size', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_hifr_complx, ivar=ivar, & initialize=initialize_variables, index = ih_ar_frootm_si_scpf) - call this%set_history_var(vname='FATES_PARSUN_CLLL', units='W m-2', & + call this%set_history_var(vname='FATES_PARSUN_CLLL', units='W m-2', & long='PAR absorbed in the sun by each canopy and leaf layer', & use_default='inactive', avgflag='A', vtype=site_cnlf_r8, & hlms='CLM:ALM', upfreq=group_hifr_complx, ivar=ivar, & initialize=initialize_variables, index = ih_parsun_z_si_cnlf) - call this%set_history_var(vname='FATES_PARSHA_CLLL', units='W m-2', & + call this%set_history_var(vname='FATES_PARSHA_CLLL', units='W m-2', & long='PAR absorbed in the shade by each canopy and leaf layer', & use_default='inactive', avgflag='A', vtype=site_cnlf_r8, & hlms='CLM:ALM', upfreq=group_hifr_complx, ivar=ivar, & initialize=initialize_variables, index = ih_parsha_z_si_cnlf) - call this%set_history_var(vname='FATES_PARSUN_CLLLPF', units='W m-2', & + call this%set_history_var(vname='FATES_PARSUN_CLLLPF', units='W m-2', & long='PAR absorbed in the sun by each canopy, leaf, and PFT', & use_default='inactive', avgflag='A', vtype=site_cnlfpft_r8, & hlms='CLM:ALM', upfreq=group_hifr_complx, ivar=ivar, initialize=initialize_variables, & index = ih_parsun_z_si_cnlfpft) - call this%set_history_var(vname='FATES_PARSHA_CLLLPF', units='W m-2', & + call this%set_history_var(vname='FATES_PARSHA_CLLLPF', units='W m-2', & long='PAR absorbed in the shade by each canopy, leaf, and PFT', & use_default='inactive', avgflag='A', vtype=site_cnlfpft_r8, & hlms='CLM:ALM', upfreq=group_hifr_complx, ivar=ivar, initialize=initialize_variables, & index = ih_parsha_z_si_cnlfpft) - call this%set_history_var(vname='FATES_PARSUN_CL', units='W m-2', & + call this%set_history_var(vname='FATES_PARSUN_CL', units='W m-2', & long='PAR absorbed by sunlit leaves in each canopy layer', & use_default='inactive', avgflag='A', vtype=site_can_r8, & hlms='CLM:ALM', upfreq=group_hifr_complx, ivar=ivar, initialize=initialize_variables, & index = ih_parsun_si_can ) - call this%set_history_var(vname='FATES_PARSHA_CL', units='W m-2', & + call this%set_history_var(vname='FATES_PARSHA_CL', units='W m-2', & long='PAR absorbed by shaded leaves in each canopy layer', & use_default='inactive', avgflag='A', vtype=site_can_r8, & hlms='CLM:ALM', upfreq=group_hifr_complx, ivar=ivar, initialize=initialize_variables, & index = ih_parsha_si_can) - call this%set_history_var(vname='FATES_LAISUN_CLLL', units='m2 m-2', & + call this%set_history_var(vname='FATES_LAISUN_CLLL', units='m2 m-2', & long='LAI in the sun by each canopy and leaf layer', & use_default='inactive', avgflag='A', vtype=site_cnlf_r8, & hlms='CLM:ALM', upfreq=group_hifr_complx, ivar=ivar, initialize=initialize_variables, & index = ih_laisun_z_si_cnlf) - call this%set_history_var(vname='FATES_LAISHA_CLLL', units='m2 m-2', & + call this%set_history_var(vname='FATES_LAISHA_CLLL', units='m2 m-2', & long='LAI in the shade by each canopy and leaf layer', & use_default='inactive', avgflag='A', vtype=site_cnlf_r8, & hlms='CLM:ALM', upfreq=group_hifr_complx, ivar=ivar, initialize=initialize_variables, & index = ih_laisha_z_si_cnlf) - call this%set_history_var(vname='FATES_LAISUN_CLLLPF', units='m2 m-2', & + call this%set_history_var(vname='FATES_LAISUN_CLLLPF', units='m2 m-2', & long='Sunlit leaf area by each canopy, leaf, and PFT', & use_default='inactive', avgflag='A', vtype=site_cnlfpft_r8, & hlms='CLM:ALM', upfreq=group_hifr_complx, ivar=ivar, initialize=initialize_variables, & index = ih_laisun_clllpf) - call this%set_history_var(vname='FATES_LAISHA_CLLLPF', units='m2 m-2', & + call this%set_history_var(vname='FATES_LAISHA_CLLLPF', units='m2 m-2', & long='Shaded leaf area by each canopy, leaf, and PFT', & use_default='inactive', avgflag='A', vtype=site_cnlfpft_r8, & hlms='CLM:ALM', upfreq=group_hifr_complx, ivar=ivar, initialize=initialize_variables, & index = ih_laisha_clllpf) - call this%set_history_var(vname='FATES_PARPROF_DIR_CLLLPF', units='W m-2', & + call this%set_history_var(vname='FATES_PARPROF_DIR_CLLLPF', units='W m-2', & long='radiative profile of direct PAR through each canopy, leaf, and PFT', & use_default='inactive', avgflag='A', vtype=site_cnlfpft_r8, & hlms='CLM:ALM', upfreq=group_hifr_complx, ivar=ivar, initialize=initialize_variables, & index = ih_parprof_dir_si_cnlfpft) - call this%set_history_var(vname='FATES_PARPROF_DIF_CLLLPF', units='W m-2', & + call this%set_history_var(vname='FATES_PARPROF_DIF_CLLLPF', units='W m-2', & long='radiative profile of diffuse PAR through each canopy, leaf, and PFT', & use_default='inactive', avgflag='A', vtype=site_cnlfpft_r8, & hlms='CLM:ALM', upfreq=group_hifr_complx, ivar=ivar, initialize=initialize_variables, & index = ih_parprof_dif_si_cnlfpft) - call this%set_history_var(vname='FATES_LAISUN_CL', units='m2 m-2', & + call this%set_history_var(vname='FATES_LAISUN_CL', units='m2 m-2', & long='LAI of sunlit leaves by canopy layer', & use_default='inactive', avgflag='A', vtype=site_can_r8, & hlms='CLM:ALM', upfreq=group_hifr_complx, ivar=ivar, initialize=initialize_variables, & index = ih_laisun_si_can) - call this%set_history_var(vname='FATES_LAISHA_CL', units='m2 m-2', & + call this%set_history_var(vname='FATES_LAISHA_CL', units='m2 m-2', & long='LAI of shaded leaves by canopy layer', & use_default='inactive', avgflag='A', vtype=site_can_r8, & hlms='CLM:ALM', upfreq=group_hifr_complx, ivar=ivar, initialize=initialize_variables, & index = ih_laisha_si_can) - call this%set_history_var(vname='FATES_PARPROF_DIR_CLLL', units='W m-2', & + call this%set_history_var(vname='FATES_PARPROF_DIR_CLLL', units='W m-2', & long='radiative profile of direct PAR through each canopy and leaf layer (averaged across PFTs)', & use_default='inactive', avgflag='A', vtype=site_cnlf_r8, & hlms='CLM:ALM', upfreq=group_hifr_complx, ivar=ivar, initialize=initialize_variables, & index = ih_parprof_dir_si_cnlf) - call this%set_history_var(vname='FATES_PARPROF_DIF_CLLL', units='W m-2', & + call this%set_history_var(vname='FATES_PARPROF_DIF_CLLL', units='W m-2', & long='radiative profile of diffuse PAR through each canopy and leaf layer (averaged across PFTs)', & use_default='inactive', avgflag='A', vtype=site_cnlf_r8, & hlms='CLM:ALM', upfreq=group_hifr_complx, ivar=ivar, initialize=initialize_variables, & index = ih_parprof_dif_si_cnlf) - ! canopy-resolved fluxes and structure + ! canopy-resolved fluxes and structure - call this%set_history_var(vname='FATES_NET_C_UPTAKE_CLLL', & + call this%set_history_var(vname='FATES_NET_C_UPTAKE_CLLL', & units='kg m-2 s-1', & long='net carbon uptake in kg carbon per m2 per second by each canopy and leaf layer per unit ground area (i.e. divide by CROWNAREA_CLLL to make per leaf area)', & use_default='inactive', avgflag='A', vtype=site_cnlf_r8, & hlms='CLM:ALM', upfreq=group_hifr_complx, ivar=ivar, initialize=initialize_variables, & index = ih_ts_net_uptake_si_cnlf) - call this%set_history_var(vname='FATES_CROWNFRAC_CLLLPF', units='m2 m-2', & + call this%set_history_var(vname='FATES_CROWNFRAC_CLLLPF', units='m2 m-2', & long='area fraction of the canopy footprint occupied by each canopy-leaf-pft layer', & use_default='inactive', avgflag='A', vtype=site_cnlfpft_r8, & hlms='CLM:ALM', upfreq=group_hifr_complx, ivar=ivar, initialize=initialize_variables, & index = ih_crownfrac_clllpf) - call this%set_history_var(vname='FATES_LBLAYER_COND_AP', & + 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'// & this%per_ageclass_norm_info('FATES_CANOPYAREA/FATES_CANOPYAREA_AP'), & @@ -9409,289 +9436,289 @@ subroutine define_history_vars(this, initialize_variables) hlms='CLM:ALM', upfreq=group_hifr_complx, ivar=ivar, & initialize=initialize_variables, index = ih_c_lblayer_si_age) - ! Canopy resistance - call this%set_history_var(vname='FATES_STOMATAL_COND_AP', & + ! 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'//& this%per_ageclass_norm_info('FATES_CANOPYAREA/FATES_CANOPYAREA_AP'), & use_default='inactive', avgflag='A', vtype=site_age_r8, & hlms='CLM:ALM', upfreq=group_hifr_complx, ivar=ivar, initialize=initialize_variables, & index = ih_c_stomata_si_age) - ! PLANT HYDRAULICS + ! PLANT HYDRAULICS - hydro_active_if1: if(hlm_use_planthydro.eq.itrue) then + hydro_active_if1: if(hlm_use_planthydro.eq.itrue) then - call this%set_history_var(vname='FATES_ERRH2O_SZPF', units='kg s-1', & + call this%set_history_var(vname='FATES_ERRH2O_SZPF', units='kg s-1', & long='mean individual water balance error in kg per individual per second', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_hydr_complx, ivar=ivar, & initialize=initialize_variables, index = ih_errh2o_scpf) - call this%set_history_var(vname='FATES_TRAN_SZPF', units='kg s-1', & + call this%set_history_var(vname='FATES_TRAN_SZPF', units='kg s-1', & long='mean individual transpiration rate in kg per individual per second', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_hydr_complx, ivar=ivar, & initialize=initialize_variables, index = ih_tran_scpf) - call this%set_history_var(vname='FATES_SAPFLOW_SZPF', units='kg m-2 s-1', & + call this%set_history_var(vname='FATES_SAPFLOW_SZPF', units='kg m-2 s-1', & long='areal sap flow rate dimensioned by size x pft in kg per m2 ground area per second', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_hydr_complx, ivar=ivar, & initialize=initialize_variables, index = ih_sapflow_scpf) - call this%set_history_var(vname='FATES_ITERH1_SZPF', units='count indiv-1 step-1', & + call this%set_history_var(vname='FATES_ITERH1_SZPF', units='count indiv-1 step-1', & long='water balance error iteration diagnostic 1', & use_default='inactive', & avgflag='A', vtype=site_size_pft_r8, hlms='CLM:ALM', & upfreq=group_hydr_complx, ivar=ivar, initialize=initialize_variables, index = ih_iterh1_scpf ) - call this%set_history_var(vname='FATES_ITERH2_SZPF', units='count indiv-1 step-1', & + call this%set_history_var(vname='FATES_ITERH2_SZPF', units='count indiv-1 step-1', & long='water balance error iteration diagnostic 2', & use_default='inactive', & avgflag='A', vtype=site_size_pft_r8, hlms='CLM:ALM', & upfreq=group_hydr_complx, ivar=ivar, initialize=initialize_variables, index = ih_iterh2_scpf ) - call this%set_history_var(vname='FATES_ABSROOT_H2O_SZPF', & + call this%set_history_var(vname='FATES_ABSROOT_H2O_SZPF', & units='m3 m-3', & long='absorbing volumetric root water content by size class x pft', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_hydr_complx, ivar=ivar, & initialize=initialize_variables, index = ih_ath_scpf) - call this%set_history_var(vname='FATES_TRANSROOT_H2O_SZPF', & + call this%set_history_var(vname='FATES_TRANSROOT_H2O_SZPF', & units='m3 m-3', & long='transporting volumetric root water content by size class x pft', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_hydr_complx, ivar=ivar, & initialize=initialize_variables, index = ih_tth_scpf) - call this%set_history_var(vname='FATES_STEM_H2O_SZPF', units='m3 m-3', & + call this%set_history_var(vname='FATES_STEM_H2O_SZPF', units='m3 m-3', & long='stem volumetric water content by size class x pft', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_hydr_complx, ivar=ivar, & initialize=initialize_variables, index = ih_sth_scpf) - call this%set_history_var(vname='FATES_LEAF_H2O_SZPF', units='m3 m-3', & + call this%set_history_var(vname='FATES_LEAF_H2O_SZPF', units='m3 m-3', & long='leaf volumetric water content by size class x pft', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_hydr_complx, ivar=ivar, & initialize=initialize_variables, index = ih_lth_scpf) - call this%set_history_var(vname='FATES_ABSROOT_H2OPOT_SZPF', units='Pa', & + call this%set_history_var(vname='FATES_ABSROOT_H2OPOT_SZPF', units='Pa', & long='absorbing root water potential by size class x pft', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_hydr_complx, ivar=ivar, & initialize=initialize_variables, index = ih_awp_scpf) - call this%set_history_var(vname='FATES_TRANSROOT_H2OPOT_SZPF', & + call this%set_history_var(vname='FATES_TRANSROOT_H2OPOT_SZPF', & units='Pa', long='transporting root water potential by size class x pft', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_hydr_complx, ivar=ivar, & initialize=initialize_variables, index = ih_twp_scpf) - call this%set_history_var(vname='FATES_STEM_H2OPOT_SZPF', units='Pa', & + call this%set_history_var(vname='FATES_STEM_H2OPOT_SZPF', units='Pa', & long='stem water potential by size class x pft', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_hydr_complx, ivar=ivar, & initialize=initialize_variables, index = ih_swp_scpf) - call this%set_history_var(vname='FATES_LEAF_H2OPOT_SZPF', units='Pa', & + call this%set_history_var(vname='FATES_LEAF_H2OPOT_SZPF', units='Pa', & long='leaf water potential by size class x pft', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_hydr_complx, ivar=ivar, & initialize=initialize_variables, index = ih_lwp_scpf) - call this%set_history_var(vname='FATES_ABSROOT_CONDFRAC_SZPF', units='1', & + call this%set_history_var(vname='FATES_ABSROOT_CONDFRAC_SZPF', units='1', & long='absorbing root fraction (0-1) of condutivity by size class x pft', & use_default='active', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_hydr_complx, ivar=ivar, & initialize=initialize_variables, index = ih_aflc_scpf) - call this%set_history_var(vname='FATES_TRANSROOT_CONDFRAC_SZPF', units='1', & + call this%set_history_var(vname='FATES_TRANSROOT_CONDFRAC_SZPF', units='1', & long='transporting root fraction (0-1) of condutivity by size class x pft', & use_default='active', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_hydr_complx, ivar=ivar, & initialize=initialize_variables, index = ih_tflc_scpf) - call this%set_history_var(vname='FATES_STEM_CONDFRAC_SZPF', units='1', & + call this%set_history_var(vname='FATES_STEM_CONDFRAC_SZPF', units='1', & long='stem water fraction (0-1) of condutivity by size class x pft', & use_default='active', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_hydr_complx, ivar=ivar, & initialize=initialize_variables, index = ih_sflc_scpf) - call this%set_history_var(vname='FATES_LEAF_CONDFRAC_SZPF', units='1', & + call this%set_history_var(vname='FATES_LEAF_CONDFRAC_SZPF', units='1', & long='leaf water fraction (0-1) of condutivity by size class x pft', & use_default='active', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_hydr_complx, ivar=ivar, & initialize=initialize_variables, index = ih_lflc_scpf) - call this%set_history_var(vname='FATES_BTRAN_SZPF', units='1', & + call this%set_history_var(vname='FATES_BTRAN_SZPF', units='1', & long='mean individual level BTRAN by size class x pft', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_hydr_complx, ivar=ivar, & initialize=initialize_variables, index = ih_btran_scpf) - call this%set_history_var(vname='FATES_SOILMATPOT_SL', units='Pa', & + call this%set_history_var(vname='FATES_SOILMATPOT_SL', units='Pa', & long='soil water matric potenial by soil layer', & use_default='inactive', avgflag='A', vtype=site_soil_r8, & hlms='CLM:ALM', upfreq=group_hydr_complx, ivar=ivar, & initialize=initialize_variables, index = ih_soilmatpot_sl) - call this%set_history_var(vname='FATES_SOILVWC_SL', units='m3 m-3', & + call this%set_history_var(vname='FATES_SOILVWC_SL', units='m3 m-3', & long='soil volumetric water content by soil layer', & use_default='inactive', avgflag='A', vtype=site_soil_r8, & hlms='CLM:ALM', upfreq=group_hydr_complx, ivar=ivar, & initialize=initialize_variables, index = ih_soilvwc_sl) - call this%set_history_var(vname='FATES_SOILVWCSAT_SL', units='m3 m-3', & + call this%set_history_var(vname='FATES_SOILVWCSAT_SL', units='m3 m-3', & long='soil saturated volumetric water content by soil layer', & use_default='inactive', avgflag='A', vtype=site_soil_r8, & hlms='CLM:ALM', upfreq=group_hydr_complx, ivar=ivar, & initialize=initialize_variables, index = ih_soilvwcsat_sl) - call this%set_history_var(vname='FATES_ROOTUPTAKE_SL', & + call this%set_history_var(vname='FATES_ROOTUPTAKE_SL', & units='kg m-2 s-1', & long='root water uptake rate by soil layer', & use_default='inactive', avgflag='A', vtype=site_soil_r8, & hlms='CLM:ALM', upfreq=group_hydr_complx, ivar=ivar, & initialize=initialize_variables, index = ih_rootuptake_sl) - call this%set_history_var(vname='FATES_ROOTUPTAKE0_SZPF', & + call this%set_history_var(vname='FATES_ROOTUPTAKE0_SZPF', & units='kg m-2 m-1 s-1', & long='root water uptake from 0 to to 10 cm depth, by plant size x pft ', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_hydr_complx, ivar=ivar, & initialize=initialize_variables, index = ih_rootuptake0_scpf) - call this%set_history_var(vname='FATES_ROOTUPTAKE10_SZPF', & + call this%set_history_var(vname='FATES_ROOTUPTAKE10_SZPF', & units='kg m-2 m-1 s-1', & long='root water uptake from 10 to to 50 cm depth, by plant size x pft ', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_hydr_complx, ivar=ivar, & initialize=initialize_variables, index = ih_rootuptake10_scpf) - call this%set_history_var(vname='FATES_ROOTUPTAKE50_SZPF', & + call this%set_history_var(vname='FATES_ROOTUPTAKE50_SZPF', & units='kg m-2 m-1 s-1', & long='root water uptake from 50 to to 100 cm depth, by plant size x pft ', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_hydr_complx, ivar=ivar, & initialize=initialize_variables, index = ih_rootuptake50_scpf) - call this%set_history_var(vname='FATES_ROOTUPTAKE100_SZPF', & + call this%set_history_var(vname='FATES_ROOTUPTAKE100_SZPF', & units='kg m-2 m-1 s-1', & long='root water uptake below 100 cm depth, by plant size x pft ', & use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & hlms='CLM:ALM', upfreq=group_hydr_complx, ivar=ivar, & initialize=initialize_variables, index = ih_rootuptake100_scpf) - end if hydro_active_if1 - - end if if_hifrq1 - - - end if if_hifrq0 - - ! Must be last thing before return - this%num_history_vars_ = ivar - - end subroutine define_history_vars - - - ! ==================================================================================== - ! DEPRECATED, TRANSITIONAL OR FUTURE CODE SECTION - ! ==================================================================================== - - !subroutine set_fates_hio_str(tag,iotype_name, iostr_val) - - ! ! Arguments - ! character(len=*), intent(in) :: tag - ! character(len=*), optional, intent(in) :: iotype_name - ! integer, optional, intent(in) :: iostr_val - - ! ! local variables - ! logical :: all_set - ! integer, parameter :: unset_int = -999 - ! real(r8), parameter :: unset_double = -999.9 - ! integer :: ityp, idim - - ! select case (trim(tag)) - ! case('flush_to_unset') - ! write(*, *) '' - ! write(*, *) 'Flushing FATES IO types prior to transfer from host' - ! do ityp=1,ubound(iovar_str, 1) - ! iovar_str(ityp)%dimsize = unset_int - ! iovar_str(ityp)%active = .false. - ! end do - - ! case('check_allset') - ! do ityp=1,ubound(iovar_str, 1) - ! write(*, *) 'Checking to see if ',iovar_str(ityp)%name, ' IO communicators were sent to FATES' - ! if(iovar_str(ityp)%active)then - ! if(iovar_str(ityp)%offset .eq. unset_int) then - ! write(*, *) 'FATES offset information of IO type:', iovar_str(ityp)%name - ! write(*, *) 'was never set' - ! ! end_run('MESSAGE') - ! end if - ! do idim=1, iovar_str(ityp)%ndims - ! if(iovar_str(ityp)%dimsize(idim) .eq. unset_int) then - ! write(*, *) 'FATES dimension information of IO type:', iovar_str(ityp)%name - ! write(*, *) 'was never set' - ! ! end_run('MESSAGE') - ! end if - ! end do - ! end if - ! end do - ! write(*, *) 'Checked. All history IO specifications properly sent to FATES.' - ! case default - - ! ! Must have two arguments if this is not a check or flush - ! if(present(iostr_val) .and. present(iotype_name))then - ! - ! ! Tag in this case is dimsize or offset - ! select case (trim(tag)) - ! - ! case('offset') - ! ityp=iotype_index(trim(iotype_name)) - ! iovar_str(ityp)%offset = iostr_val - ! write(*, *) 'Transfering offset for IOTYPE',iotype_name, ' to FATES' - - ! case('dimsize1') - ! ityp=iotype_index(trim(iotype_name)) - ! iovar_str(ityp)%dimsize(1) = iostr_val - ! write(*, *) 'Transfering 1st dimension size for IOTYPE',iotype_name, ' to FATES' - - ! case('dimsize2') - ! ityp=iotype_index(trim(iotype_name)) - ! if(ubound(iovar_str(ityp)%dimsize, 1)==1)then - ! write(fates_log(), *) 'Transfering second dimensional bound to unallocated space' - ! write(fates_log(), *) 'type:', iotype_name - ! ! end_run - ! end if - ! iovar_str(ityp)%dimsize(2) = iostr_val - ! write(*, *) 'Transfering 2nd dimension size for IOTYPE',iotype_name, ' to FATES' - - ! case('dimsize3') - ! ityp=iotype_index(trim(iotype_name)) - ! if(ubound(iovar_str(ityp)%dimsize, 1)<3)then - ! write(fates_log(), *) 'Transfering third dimensional bound to unallocated space' - ! write(fates_log(), *) 'type:', iotype_name - ! ! end_run - ! end if - ! iovar_str(ityp)%dimsize(3) = iostr_val - ! write(*, *) 'Transfering 3rd dimension size for IOTYPE',iotype_name, ' to FATES' - - ! case default - ! write(*, *) 'IO parameter not recognized:', trim(tag) - ! ! end_run - ! end select - ! else - ! write(*, *) 'no value was provided for the tag' - ! end if - ! - ! end select - ! return - ! end subroutine set_fates_hio_str + end if hydro_active_if1 + + end if if_hifrq1 + + + end if if_hifrq0 + + ! Must be last thing before return + this%num_history_vars_ = ivar + + end subroutine define_history_vars + + + ! ==================================================================================== + ! DEPRECATED, TRANSITIONAL OR FUTURE CODE SECTION + ! ==================================================================================== + + !subroutine set_fates_hio_str(tag,iotype_name, iostr_val) + + ! ! Arguments + ! character(len=*), intent(in) :: tag + ! character(len=*), optional, intent(in) :: iotype_name + ! integer, optional, intent(in) :: iostr_val + + ! ! local variables + ! logical :: all_set + ! integer, parameter :: unset_int = -999 + ! real(r8), parameter :: unset_double = -999.9 + ! integer :: ityp, idim + + ! select case (trim(tag)) + ! case('flush_to_unset') + ! write(*, *) '' + ! write(*, *) 'Flushing FATES IO types prior to transfer from host' + ! do ityp=1,ubound(iovar_str, 1) + ! iovar_str(ityp)%dimsize = unset_int + ! iovar_str(ityp)%active = .false. + ! end do + + ! case('check_allset') + ! do ityp=1,ubound(iovar_str, 1) + ! write(*, *) 'Checking to see if ',iovar_str(ityp)%name, ' IO communicators were sent to FATES' + ! if(iovar_str(ityp)%active)then + ! if(iovar_str(ityp)%offset .eq. unset_int) then + ! write(*, *) 'FATES offset information of IO type:', iovar_str(ityp)%name + ! write(*, *) 'was never set' + ! ! end_run('MESSAGE') + ! end if + ! do idim=1, iovar_str(ityp)%ndims + ! if(iovar_str(ityp)%dimsize(idim) .eq. unset_int) then + ! write(*, *) 'FATES dimension information of IO type:', iovar_str(ityp)%name + ! write(*, *) 'was never set' + ! ! end_run('MESSAGE') + ! end if + ! end do + ! end if + ! end do + ! write(*, *) 'Checked. All history IO specifications properly sent to FATES.' + ! case default + + ! ! Must have two arguments if this is not a check or flush + ! if(present(iostr_val) .and. present(iotype_name))then + ! + ! ! Tag in this case is dimsize or offset + ! select case (trim(tag)) + ! + ! case('offset') + ! ityp=iotype_index(trim(iotype_name)) + ! iovar_str(ityp)%offset = iostr_val + ! write(*, *) 'Transfering offset for IOTYPE',iotype_name, ' to FATES' + + ! case('dimsize1') + ! ityp=iotype_index(trim(iotype_name)) + ! iovar_str(ityp)%dimsize(1) = iostr_val + ! write(*, *) 'Transfering 1st dimension size for IOTYPE',iotype_name, ' to FATES' + + ! case('dimsize2') + ! ityp=iotype_index(trim(iotype_name)) + ! if(ubound(iovar_str(ityp)%dimsize, 1)==1)then + ! write(fates_log(), *) 'Transfering second dimensional bound to unallocated space' + ! write(fates_log(), *) 'type:', iotype_name + ! ! end_run + ! end if + ! iovar_str(ityp)%dimsize(2) = iostr_val + ! write(*, *) 'Transfering 2nd dimension size for IOTYPE',iotype_name, ' to FATES' + + ! case('dimsize3') + ! ityp=iotype_index(trim(iotype_name)) + ! if(ubound(iovar_str(ityp)%dimsize, 1)<3)then + ! write(fates_log(), *) 'Transfering third dimensional bound to unallocated space' + ! write(fates_log(), *) 'type:', iotype_name + ! ! end_run + ! end if + ! iovar_str(ityp)%dimsize(3) = iostr_val + ! write(*, *) 'Transfering 3rd dimension size for IOTYPE',iotype_name, ' to FATES' + + ! case default + ! write(*, *) 'IO parameter not recognized:', trim(tag) + ! ! end_run + ! end select + ! else + ! write(*, *) 'no value was provided for the tag' + ! end if + ! + ! end select + ! return + ! end subroutine set_fates_hio_str From 4b32ff8ea7a48d8a9c79060a93fe6a6efd3b47aa Mon Sep 17 00:00:00 2001 From: Xiulin Gao Date: Sun, 19 Oct 2025 15:20:57 -0700 Subject: [PATCH 03/23] made corresponding changes to fuel function test --- .../fire/fuel/FatesTestFuel.F90 | 262 +++++++++-------- .../functional_testing/fire/fuel/fuel_test.py | 29 +- .../fire/shr/FatesTestFireMod.F90 | 276 ++++++++++-------- 3 files changed, 317 insertions(+), 250 deletions(-) diff --git a/testing/functional_testing/fire/fuel/FatesTestFuel.F90 b/testing/functional_testing/fire/fuel/FatesTestFuel.F90 index 3f185985aa..b557f7e4c9 100644 --- a/testing/functional_testing/fire/fuel/FatesTestFuel.F90 +++ b/testing/functional_testing/fire/fuel/FatesTestFuel.F90 @@ -1,126 +1,140 @@ program FatesTestFuel - - use FatesConstantsMod, only : r8 => fates_r8 - use EDTypesMod, only : ed_site_type - use FatesTestFireMod, only : SetUpFuel, ReadDatmData, WriteFireData - use FatesArgumentUtils, only : command_line_arg - use FatesUnitTestParamReaderMod, only : fates_unit_test_param_reader - use SyntheticFuelModels, only : fuel_models_array_class - use SFFireWeatherMod, only : fire_weather - use SFNesterovMod, only : nesterov_index - use FatesFuelMod, only : fuel_type - use FatesFuelClassesMod, only : num_fuel_classes - use SFParamsMod, only : SF_val_SAV, SF_val_drying_ratio - use SFParamsMod, only : SF_val_FBD - - implicit none - - ! LOCALS: - type(fates_unit_test_param_reader) :: param_reader ! param reader instance - type(fuel_models_array_class) :: fuel_models_array ! array of fuel models - class(fire_weather), pointer :: fireWeather ! fire weather object - type(fuel_type), allocatable :: fuel(:) ! fuel objects - character(len=:), allocatable :: param_file ! input parameter file - character(len=:), allocatable :: datm_file ! input DATM driver file - real(r8), allocatable :: temp_degC(:) ! daily air temperature [degC] - real(r8), allocatable :: precip(:) ! daily precipitation [mm] - real(r8), allocatable :: rh(:) ! daily relative humidity [%] - real(r8), allocatable :: wind(:) ! daily wind speed [m/s] - real(r8), allocatable :: NI(:) ! Nesterov index - real(r8), allocatable :: fuel_loading(:,:) ! fuel loading [kgC/m2] - real(r8), allocatable :: non_trunk_loading(:) ! non-trunk fuel loading [kgC/m2] - real(r8), allocatable :: frac_loading(:,:) ! fractional fuel loading [0-1] - real(r8), allocatable :: fuel_BD(:) ! bulk density of fuel [kg/m3] - real(r8), allocatable :: fuel_SAV(:) ! fuel surface area to volume ratio [/cm] - real(r8), allocatable :: fuel_moisture(:,:) ! fuel moisture [m3/m3] - real(r8), allocatable :: fuel_MEF(:,:) ! fuel moisture of extinction [m3/m3 - character(len=100), allocatable :: fuel_names(:) ! names of fuel models - character(len=2), allocatable :: carriers(:) ! carriers of fuel models - integer :: i, f ! looping indices - integer :: num_fuel_models ! number of fuel models to test - - ! CONSTANTS: - integer, parameter :: n_days = 365 ! number of days to run simulation - character(len=*), parameter :: out_file = 'fuel_out.nc' ! output file - - ! fuel models to test - integer, parameter, dimension(5) :: fuel_models = (/102, 183, 164, 104, 163/) - - ! number of fuel models to test - num_fuel_models = size(fuel_models) - - ! allocate arrays - allocate(temp_degC(n_days)) - allocate(precip(n_days)) - allocate(rh(n_days)) - allocate(wind(n_days)) - allocate(NI(n_days)) - allocate(fuel_moisture(n_days, num_fuel_models)) - allocate(fuel_MEF(n_days, num_fuel_models)) - allocate(fuel_loading(num_fuel_classes, num_fuel_models)) - allocate(frac_loading(num_fuel_classes, num_fuel_models)) - allocate(fuel_BD(num_fuel_models)) - allocate(fuel_SAV(num_fuel_models)) - allocate(non_trunk_loading(num_fuel_models)) - allocate(fuel_names(num_fuel_models)) - allocate(carriers(num_fuel_models)) - - ! read in parameter file name and DATM file from command line - param_file = command_line_arg(1) - datm_file = command_line_arg(2) - - ! read in parameter file - call param_reader%Init(param_file) - call param_reader%RetrieveParameters() - - ! read in DATM data - call ReadDatmData(datm_file, temp_degC, precip, rh, wind) - - ! set up fire weather class - allocate(nesterov_index :: fireWeather) - call fireWeather%Init() - - ! set up fuel objects and calculate loading - allocate(fuel(num_fuel_models)) - call fuel_models_array%GetFuelModels() - do f = 1, num_fuel_models - - ! uses data from fuel_models to initialize fuel - call SetUpFuel(fuel(f), fuel_models_array, fuel_models(f), fuel_names(f), carriers(f)) - - ! sum up fuel and calculate loading - call fuel(f)%SumLoading() - call fuel(f)%CalculateFractionalLoading() - - ! calculate geometric properties - call fuel(f)%AverageBulkDensity_NoTrunks(SF_val_FBD) - call fuel(f)%AverageSAV_NoTrunks(SF_val_SAV) - - ! save values - fuel_loading(:,f) = fuel(f)%loading(:) - non_trunk_loading(f) = fuel(f)%non_trunk_loading - frac_loading(:,f) = fuel(f)%frac_loading(:) - fuel_BD(f) = fuel(f)%bulk_density_notrunks - fuel_SAV(f) = fuel(f)%SAV_notrunks - - end do - - ! run on time steps - do i = 1, n_days - call fireWeather%UpdateIndex(temp_degC(i), precip(i), rh(i), wind(i)) - NI(i) = fireWeather%fire_weather_index - - ! calculate fuel moisture [m3/m3] - do f = 1, num_fuel_models - call fuel(f)%UpdateFuelMoisture(SF_val_SAV, SF_val_drying_ratio, fireWeather) - fuel_moisture(i, f) = fuel(f)%average_moisture_notrunks - fuel_MEF(i, f) = fuel(f)%MEF_notrunks - end do - end do - - ! write out data - call WriteFireData(out_file, n_days, num_fuel_models, temp_degC, precip, rh, NI, & - fuel_loading, frac_loading, fuel_BD, fuel_SAV, non_trunk_loading, fuel_moisture, & - fuel_MEF, fuel_models, carriers) - + + use FatesConstantsMod, only : r8 => fates_r8 + use EDTypesMod, only : ed_site_type + use FatesTestFireMod, only : SetUpFuel, ReadDatmData, WriteFireData + use FatesArgumentUtils, only : command_line_arg + use FatesUnitTestParamReaderMod, only : fates_unit_test_param_reader + use SyntheticFuelModels, only : fuel_models_array_class + use SFFireWeatherMod, only : fire_weather + use SFNesterovMod, only : nesterov_index + use FatesFuelMod, only : fuel_type + use FatesFuelClassesMod, only : num_fuel_classes + use SFParamsMod, only : SF_val_SAV, SF_val_drying_ratio + use SFParamsMod, only : SF_val_FBD, SF_val_part_dens + + implicit none + + ! LOCALS: + type(fates_unit_test_param_reader) :: param_reader ! param reader instance + type(fuel_models_array_class) :: fuel_models_array ! array of fuel models + class(fire_weather), pointer :: fireWeather ! fire weather object + type(fuel_type), allocatable :: fuel(:) ! fuel objects + character(len=:), allocatable :: param_file ! input parameter file + character(len=:), allocatable :: datm_file ! input DATM driver file + real(r8), allocatable :: temp_degC(:) ! daily air temperature [degC] + real(r8), allocatable :: precip(:) ! daily precipitation [mm] + real(r8), allocatable :: rh(:) ! daily relative humidity [%] + real(r8), allocatable :: wind(:) ! daily wind speed [m/s] + real(r8), allocatable :: NI(:) ! Nesterov index + real(r8), allocatable :: fuel_loading(:,:) ! fuel loading [kgC/m2] + real(r8), allocatable :: non_trunk_loading(:) ! non-trunk fuel loading [kgC/m2] + real(r8), allocatable :: weighted_loading_dead(:) ! total dead fuel loading weighted [kgC/m2] + real(r8), allocatable :: weighted_loading_live(:) ! total live fuel loading weighted [kgC/m2] + real(r8), allocatable :: frac_loading(:,:) ! fractional fuel loading [0-1] + real(r8), allocatable :: fuel_BD(:) ! bulk density of fuel [kg/m3] + real(r8), allocatable :: fuel_SAV(:) ! fuel surface area to volume ratio [/cm] + real(r8), allocatable :: fuel_moisture_dead(:,:) ! dead fuel moisture [m3/m3] + real(r8), allocatable :: fuel_moisture_live(:,:) ! live fuel moisture [m3/m3] + real(r8), allocatable :: fuel_MEF_dead(:,:) ! dead fuel moisture of extinction [m3/m3 + real(r8), allocatable :: fuel_MEF_live(:,:) ! live fuel moisture of extinction [m3/m3 + character(len=100), allocatable :: fuel_names(:) ! names of fuel models + character(len=2), allocatable :: carriers(:) ! carriers of fuel models + integer :: i, f ! looping indices + integer :: num_fuel_models ! number of fuel models to test + + ! CONSTANTS: + integer, parameter :: n_days = 365 ! number of days to run simulation + character(len=*), parameter :: out_file = 'fuel_out.nc' ! output file + + ! fuel models to test + integer, parameter, dimension(5) :: fuel_models = (/102, 183, 164, 104, 163/) + + ! number of fuel models to test + num_fuel_models = size(fuel_models) + + ! allocate arrays + allocate(temp_degC(n_days)) + allocate(precip(n_days)) + allocate(rh(n_days)) + allocate(wind(n_days)) + allocate(NI(n_days)) + allocate(fuel_moisture_dead(n_days, num_fuel_models)) + allocate(fuel_moisture_live(n_days, num_fuel_models)) + allocate(fuel_MEF_dead(n_days, num_fuel_models)) + allocate(fuel_MEF_live(n_days, num_fuel_models)) + allocate(fuel_loading(num_fuel_classes, num_fuel_models)) + allocate(frac_loading(num_fuel_classes, num_fuel_models)) + allocate(fuel_BD(num_fuel_models)) + allocate(fuel_SAV(num_fuel_models)) + allocate(non_trunk_loading(num_fuel_models)) + allocate(weighted_loading_dead(num_fuel_models)) + allocate(weighted_loading_live(num_fuel_models)) + allocate(fuel_names(num_fuel_models)) + allocate(carriers(num_fuel_models)) + + ! read in parameter file name and DATM file from command line + param_file = command_line_arg(1) + datm_file = command_line_arg(2) + + ! read in parameter file + call param_reader%Init(param_file) + call param_reader%RetrieveParameters() + + ! read in DATM data + call ReadDatmData(datm_file, temp_degC, precip, rh, wind) + + ! set up fire weather class + allocate(nesterov_index :: fireWeather) + call fireWeather%Init() + + ! set up fuel objects and calculate loading + allocate(fuel(num_fuel_models)) + call fuel_models_array%GetFuelModels() + do f = 1, num_fuel_models + + ! uses data from fuel_models to initialize fuel + call SetUpFuel(fuel(f), fuel_models_array, fuel_models(f), fuel_names(f), carriers(f)) + + ! sum up fuel and calculate loading + call fuel%CalculateWeightingFactor(SF_val_SAV, SF_val_part_dens) + call fuel(f)%SumLoading() + call fuel(f)%CalculateFractionalLoading() + + ! calculate geometric properties + call fuel(f)%AverageBulkDensity(SF_val_FBD) + call fuel(f)%AverageSAV(SF_val_SAV) + + ! save values + fuel_loading(:,f) = fuel(f)%loading(:) + non_trunk_loading(f) = fuel(f)%non_trunk_loading + weighted_loading_dead(f) = fuel(f)%weighted_loading_dead + weighted_loading_live(f) = fuel(f)%weighted_loading_live + frac_loading(:,f) = fuel(f)%frac_loading(:) + fuel_BD(f) = fuel(f)%bulk_density_weighted + fuel_SAV(f) = fuel(f)%SAV_weighted + + end do + + ! run on time steps + do i = 1, n_days + call fireWeather%UpdateIndex(temp_degC(i), precip(i), rh(i), wind(i)) + NI(i) = fireWeather%fire_weather_index + + ! calculate fuel moisture [m3/m3] + do f = 1, num_fuel_models + call fuel(f)%UpdateFuelMoisture(SF_val_SAV, SF_val_drying_ratio, fireWeather) + fuel_moisture_dead(i, f) = fuel(f)%average_moisture_dead + fuel_moisture_live(i, f) = fuel(f)%average_moisture_live + fuel_MEF_dead(i, f) = fuel(f)%MEF_dead + fuel_MEF_live(i, f) = fuel(f)%MEF_live + end do + end do + + ! write out data + call WriteFireData(out_file, n_days, num_fuel_models, temp_degC, precip, rh, NI, & + fuel_loading, frac_loading, fuel_BD, fuel_SAV, non_trunk_loading, weighted_loading_dead, & + weighted_loading_live, fuel_moisture_dead, fuel_moisture_live, fuel_MEF_dead, & + fuel_MEF_live, fuel_models, carriers) + end program FatesTestFuel diff --git a/testing/functional_testing/fire/fuel/fuel_test.py b/testing/functional_testing/fire/fuel/fuel_test.py index 9ae6c53e39..09bacd7db4 100644 --- a/testing/functional_testing/fire/fuel/fuel_test.py +++ b/testing/functional_testing/fire/fuel/fuel_test.py @@ -38,7 +38,8 @@ def plot_output(self, run_dir: str, save_figs: bool, plot_dir: str): fuel_dat = xr.open_dataset(os.path.join(run_dir, self.out_file)) self.plot_NI_dat(fuel_dat, save_figs, plot_dir) - self.plot_moisture_dat(fuel_dat, save_figs, plot_dir) + self.plot_moisture_dead_dat(fuel_dat, save_figs, plot_dir) + self.plot_moisture_live_dat(fuel_dat, save_figs, plot_dir) self.plot_barchart( fuel_dat, "fuel_loading", @@ -47,6 +48,22 @@ def plot_output(self, run_dir: str, save_figs: bool, plot_dir: str): save_figs, plot_dir, ) + self.plot_barchart( + fuel_dat, + "weighted_loading_dead", + "Weighted dead fuel loading", + "kgC m$^{-2}$", + save_figs, + plot_dir, + ) + self.plot_barchart( + fuel_dat, + "weighted_loading_live", + "Weighted live fuel loading", + "kgC m$^{-2}$", + save_figs, + plot_dir, + ) self.plot_barchart( fuel_dat, "frac_loading", @@ -169,7 +186,7 @@ def plot_NI_dat(fuel_dat: xr.Dataset, save_figs: bool, plot_dir: str): plt.savefig(fig_name) @staticmethod - def plot_moisture_dat(fuel_dat: xr.Dataset, save_figs: bool, plot_dir: str): + def plot_moisture_live_dat(fuel_dat: xr.Dataset, save_figs: bool, plot_dir: str): """Plot output for fuel moisture Args: @@ -179,10 +196,12 @@ def plot_moisture_dat(fuel_dat: xr.Dataset, save_figs: bool, plot_dir: str): """ plt.figure() - fuel_dat.fuel_moisture.plot(hue="fuel_model") + fuel_dat.fuel_moisture_live.plot(hue="fuel_model") plt.xlabel("Time", fontsize=11) - plt.ylabel("Fuel Moisture", fontsize=11) + plt.ylabel("Live fuel Moisture", fontsize=11) if save_figs: - fig_name = os.path.join(plot_dir, "fuel_moisture_plot.png") + fig_name = os.path.join(plot_dir, "fuel_moisture_live_plot.png") plt.savefig(fig_name) + + diff --git a/testing/functional_testing/fire/shr/FatesTestFireMod.F90 b/testing/functional_testing/fire/shr/FatesTestFireMod.F90 index a9ce2be08e..648e99c506 100644 --- a/testing/functional_testing/fire/shr/FatesTestFireMod.F90 +++ b/testing/functional_testing/fire/shr/FatesTestFireMod.F90 @@ -1,83 +1,83 @@ module FatesTestFireMod - ! - ! DESCRIPTION: - ! Module to support testing the FATES SPIFTIRE model - ! + ! + ! DESCRIPTION: + ! Module to support testing the FATES SPIFTIRE model + ! - use FatesConstantsMod, only : r8 => fates_r8 - use EDTypesMod, only : ed_site_type - use FatesPatchMod, only : fates_patch_type - use SFNesterovMod, only : nesterov_index - use FatesUnitTestIOMod, only : OpenNCFile, GetVar, CloseNCFile, RegisterNCDims - use FatesUnitTestIOMod, only : RegisterVar, EndNCDef, WriteVar - use FatesUnitTestIOMod, only : type_double, type_int, type_char - use FatesFuelClassesMod, only : num_fuel_classes - use SyntheticFuelModels, only : fuel_models_array_class - use SFParamsMod, only : SF_val_CWD_frac - use FatesFuelMod, only : fuel_type + use FatesConstantsMod, only : r8 => fates_r8 + use EDTypesMod, only : ed_site_type + use FatesPatchMod, only : fates_patch_type + use SFNesterovMod, only : nesterov_index + use FatesUnitTestIOMod, only : OpenNCFile, GetVar, CloseNCFile, RegisterNCDims + use FatesUnitTestIOMod, only : RegisterVar, EndNCDef, WriteVar + use FatesUnitTestIOMod, only : type_double, type_int, type_char + use FatesFuelClassesMod, only : num_fuel_classes + use SyntheticFuelModels, only : fuel_models_array_class + use SFParamsMod, only : SF_val_CWD_frac + use FatesFuelMod, only : fuel_type - implicit none - private + implicit none + private - public :: SetUpFuel, ReadDatmData, WriteFireData + public :: SetUpFuel, ReadDatmData, WriteFireData - contains +contains - !===================================================================================== + !===================================================================================== - subroutine SetUpFuel(fuel, fuel_model_array, fuel_model_index, fuel_name, fuel_carrier) + subroutine SetUpFuel(fuel, fuel_model_array, fuel_model_index, fuel_name, fuel_carrier) ! ! DESCRIPTION: ! Sets up fuel loading ! - + ! ARGUMENTS: type(fuel_type), intent(inout) :: fuel ! fuel object type(fuel_models_array_class), intent(in) :: fuel_model_array ! array of fuel models integer, intent(in) :: fuel_model_index ! fuel model index character(len=100), intent(out) :: fuel_name ! name of fuel model character(len=2), intent(out) :: fuel_carrier ! fuel carrier for fuel model - + ! LOCALS: integer :: i ! position of fuel model in array - real(r8) :: leaf_litter ! leaf litter [kg/m2] + real(r8) :: leaf_litter ! leaf litter [kg/m2] real(r8) :: twig_litter ! twig litter [kg/m2] real(r8) :: small_branch_litter ! small branch litter [kg/m2] real(r8) :: large_branch_litter ! large branch litter [kg/m2] real(r8) :: grass_litter ! grass litter [kg/m2] - + ! get fuel model position in array i = fuel_model_array%FuelModelPosition(fuel_model_index) - + ! fuel model data leaf_litter = fuel_model_array%fuel_models(i)%hr1_loading twig_litter = fuel_model_array%fuel_models(i)%hr10_loading - + ! small vs. large branches based on input parameter file small_branch_litter = fuel_model_array%fuel_models(i)%hr100_loading*SF_val_CWD_frac(2)/ & - (SF_val_CWD_frac(2) + SF_val_CWD_frac(3)) + (SF_val_CWD_frac(2) + SF_val_CWD_frac(3)) large_branch_litter = fuel_model_array%fuel_models(i)%hr100_loading*SF_val_CWD_frac(3)/ & - (SF_val_CWD_frac(2) + SF_val_CWD_frac(3)) - + (SF_val_CWD_frac(2) + SF_val_CWD_frac(3)) + grass_litter = fuel_model_array%fuel_models(i)%live_herb_loading - + fuel_name = fuel_model_array%fuel_models(i)%fuel_model_name fuel_carrier = fuel_model_array%fuel_models(i)%carrier - + call fuel%UpdateLoading(leaf_litter, twig_litter, small_branch_litter, & - large_branch_litter, 0.0_r8, grass_litter) - - end subroutine SetUpFuel + large_branch_litter, 0.0_r8, grass_litter) + + end subroutine SetUpFuel - !===================================================================================== - - subroutine ReadDatmData(nc_file, temp_degC, precip, rh, wind) + !===================================================================================== + + subroutine ReadDatmData(nc_file, temp_degC, precip, rh, wind) ! ! DESCRIPTION: ! Reads and returns DATM data ! - + ! ARGUMENTS: character(len=*), intent(in) :: nc_file ! netcdf file with DATM data real(r8), allocatable, intent(out) :: temp_degC(:) ! daily air temperature [degC] @@ -90,7 +90,7 @@ subroutine ReadDatmData(nc_file, temp_degC, precip, rh, wind) ! open file call OpenNCFile(trim(nc_file), ncid, 'read') - + ! read in data call GetVar(ncid, 'temp_degC', temp_degC) call GetVar(ncid, 'precip', precip) @@ -100,18 +100,19 @@ subroutine ReadDatmData(nc_file, temp_degC, precip, rh, wind) ! close file call CloseNCFile(ncid) - end subroutine ReadDatmData + end subroutine ReadDatmData - !===================================================================================== + !===================================================================================== - subroutine WriteFireData(out_file, nsteps, nfuelmods, temp_degC, precip, rh, NI, & - loading, frac_loading, fuel_BD, fuel_SAV, non_trunk_loading, fuel_moisture, & - fuel_MEF, fuel_models, carriers) + subroutine WriteFireData(out_file, nsteps, nfuelmods, temp_degC, precip, rh, NI, & + loading, frac_loading, fuel_BD, fuel_SAV, non_trunk_loading, weighted_loading_dead, & + weighted_loading_live, fuel_moisture_dead, fuel_moisture_live, fuel_MEF_dead, fuel_MEF_live, & + fuel_models, carriers) ! ! DESCRIPTION: ! writes out data from the unit test ! - + ! ARGUMENTS: character(len=*), intent(in) :: out_file integer, intent(in) :: nsteps @@ -123,13 +124,17 @@ subroutine WriteFireData(out_file, nsteps, nfuelmods, temp_degC, precip, rh, NI, real(r8), intent(in) :: loading(:,:) real(r8), intent(in) :: frac_loading(:,:) real(r8), intent(in) :: non_trunk_loading(:) - real(r8), intent(in) :: fuel_moisture(:,:) - real(r8), intent(in) :: fuel_MEF(:,:) + real(r8), intent(in) :: weighted_loading_dead(:) + real(r8), intent(in) :: weighted_loading_live(:) + real(r8), intent(in) :: fuel_moisture_dead(:,:) + real(r8), intent(in) :: fuel_moisture_live(:,:) + real(r8), intent(in) :: fuel_MEF_dead(:,:) + real(r8), intent(in) :: fuel_MEF_live(:,:) real(r8), intent(in) :: fuel_BD(:) real(r8), intent(in) :: fuel_SAV(:) integer, intent(in) :: fuel_models(:) character(len=2), intent(in) :: carriers(:) - + ! LOCALS: integer, allocatable :: time_index(:) ! array of time index integer :: ncid ! netcdf id @@ -143,16 +148,17 @@ subroutine WriteFireData(out_file, nsteps, nfuelmods, temp_degC, precip, rh, NI, integer :: rhID, NIID, loadingID integer :: frac_loadingID integer :: tot_loadingID + integer :: wgt_loadingdID, wgt_loadinglID integer :: BDID, SAVID - integer :: moistID - integer :: cID, mefID - + integer :: moistdID, moistlID + integer :: cID, mefdID, meflID + ! create pft indices allocate(time_index(nsteps)) do i = 1, nsteps - time_index(i) = i + time_index(i) = i end do - + ! dimension names dim_names = [character(len=20) :: 'time', 'litter_class', 'fuel_model'] @@ -163,99 +169,123 @@ subroutine WriteFireData(out_file, nsteps, nfuelmods, temp_degC, precip, rh, NI, call RegisterNCDims(ncid, dim_names, (/nsteps, num_fuel_classes, nfuelmods/), 3, dimIDs) ! first register dimension variables - + ! register time call RegisterVar(ncid, 'time', dimIDs(1:1), type_int, & - [character(len=20) :: 'time_origin', 'units', 'calendar', 'long_name'], & - [character(len=150) :: '2018-01-01 00:00:00', 'days since 2018-01-01 00:00:00', & - 'gregorian', 'time'], & - 4, timeID) + [character(len=20) :: 'time_origin', 'units', 'calendar', 'long_name'], & + [character(len=150) :: '2018-01-01 00:00:00', 'days since 2018-01-01 00:00:00', & + 'gregorian', 'time'], & + 4, timeID) ! register litter class call RegisterVar(ncid, 'litter_class', dimIDs(2:2), type_int, & - [character(len=20) :: 'units', 'long_name'], & - [character(len=150) :: '', 'fuel class'], 2, litterID) - + [character(len=20) :: 'units', 'long_name'], & + [character(len=150) :: '', 'fuel class'], 2, litterID) + ! register fuel models call RegisterVar(ncid, 'fuel_model', dimIDs(3:3), type_int, & - [character(len=20) :: 'units', 'long_name'], & - [character(len=150) :: '', 'fuel model index'], 2, modID) + [character(len=20) :: 'units', 'long_name'], & + [character(len=150) :: '', 'fuel model index'], 2, modID) ! then register actual variables - + ! register fuel carriers call RegisterVar(ncid, 'carrier', dimIDs(3:3), type_char, & - [character(len=20) :: 'coordinates', 'units', 'long_name'], & - [character(len=150) :: 'fuel_model_index', '', 'carrier of fuel'], & - 3, cID) - + [character(len=20) :: 'coordinates', 'units', 'long_name'], & + [character(len=150) :: 'fuel_model_index', '', 'carrier of fuel'], & + 3, cID) + ! register temperature call RegisterVar(ncid, 'temp_degC', dimIDs(1:1), type_double, & - [character(len=20) :: 'coordinates', 'units', 'long_name'], & - [character(len=150) :: 'time', 'degrees C', 'air temperature'], & - 3, tempID) + [character(len=20) :: 'coordinates', 'units', 'long_name'], & + [character(len=150) :: 'time', 'degrees C', 'air temperature'], & + 3, tempID) ! register precipitation call RegisterVar(ncid, 'precip', dimIDs(1:1), type_double, & - [character(len=20) :: 'coordinates', 'units', 'long_name'], & - [character(len=150) :: 'time', 'mm', 'precipitation'], & - 3, precipID) + [character(len=20) :: 'coordinates', 'units', 'long_name'], & + [character(len=150) :: 'time', 'mm', 'precipitation'], & + 3, precipID) ! register relative humidity call RegisterVar(ncid, 'RH', dimIDs(1:1), type_double, & - [character(len=20) :: 'coordinates', 'units', 'long_name'], & - [character(len=150) :: 'time', '%', 'relative humidity'], & - 3, rhID) + [character(len=20) :: 'coordinates', 'units', 'long_name'], & + [character(len=150) :: 'time', '%', 'relative humidity'], & + 3, rhID) ! register Nesterov Index call RegisterVar(ncid, 'NI', dimIDs(1:1), type_double, & - [character(len=20) :: 'coordinates', 'units', 'long_name'], & - [character(len=150) :: 'time', '', 'Nesterov Index'], & - 3, NIID) - - ! register fuel moisture - call RegisterVar(ncid, 'fuel_moisture', (/dimIDs(1), dimIDs(3)/), type_double, & - [character(len=20) :: 'coordinates', 'units', 'long_name'], & - [character(len=150) :: 'time fuel_model', 'm3 m-3', 'average fuel moisture'], & - 3, moistID) - - ! register fuel MEF - call RegisterVar(ncid, 'fuel_MEF', (/dimIDs(1), dimIDs(3)/), type_double, & - [character(len=20) :: 'coordinates', 'units', 'long_name'], & - [character(len=150) :: 'time fuel_model', 'm3 m-3', 'average fuel moisture of extinction'], & - 3, mefID) - - + [character(len=20) :: 'coordinates', 'units', 'long_name'], & + [character(len=150) :: 'time', '', 'Nesterov Index'], & + 3, NIID) + + ! register fuel moisture of dead fuel + call RegisterVar(ncid, 'fuel_moisture_dead', (/dimIDs(1), dimIDs(3)/), type_double, & + [character(len=20) :: 'coordinates', 'units', 'long_name'], & + [character(len=150) :: 'time fuel_model', 'm3 m-3', 'average fuel moisture of dead fuels'], & + 3, moistdID) + + ! register fuel moisture of live fuel + call RegisterVar(ncid, 'fuel_moisture_live', (/dimIDs(1), dimIDs(3)/), type_double, & + [character(len=20) :: 'coordinates', 'units', 'long_name'], & + [character(len=150) :: 'time fuel_model', 'm3 m-3', 'average fuel moisture of live fuels'], & + 3, moistlID) + + ! register dead fuel MEF + call RegisterVar(ncid, 'fuel_MEF_dead', (/dimIDs(1), dimIDs(3)/), type_double, & + [character(len=20) :: 'coordinates', 'units', 'long_name'], & + [character(len=150) :: 'time fuel_model', 'm3 m-3', 'average dead fuel moisture of extinction'], & + 3, mefdID) + + ! register dead fuel MEF + call RegisterVar(ncid, 'fuel_MEF_live', (/dimIDs(1), dimIDs(3)/), type_double, & + [character(len=20) :: 'coordinates', 'units', 'long_name'], & + [character(len=150) :: 'time fuel_model', 'm3 m-3', 'average live fuel moisture of extinction'], & + 3, meflID) + + ! register fuel loading call RegisterVar(ncid, 'fuel_loading', dimIDs(2:3), type_double, & - [character(len=20) :: 'coordinates', 'units', 'long_name'], & - [character(len=150) :: 'litter_class fuel_model', 'kgC m-2', 'fuel loading'], & - 3, loadingID) - + [character(len=20) :: 'coordinates', 'units', 'long_name'], & + [character(len=150) :: 'litter_class fuel_model', 'kgC m-2', 'fuel loading'], & + 3, loadingID) + ! register fractional fuel loading call RegisterVar(ncid, 'frac_loading', dimIDs(2:3), type_double, & - [character(len=20) :: 'coordinates', 'units', 'long_name'], & - [character(len=150) :: 'litter_class fuel_model', '', 'fractional loading'], & - 3, frac_loadingID) - + [character(len=20) :: 'coordinates', 'units', 'long_name'], & + [character(len=150) :: 'litter_class fuel_model', '', 'fractional loading'], & + 3, frac_loadingID) + ! register non-trunk fuel loading call RegisterVar(ncid, 'non_trunk_loading', dimIDs(3:3), type_double, & - [character(len=20) :: 'coordinates', 'units', 'long_name'], & - [character(len=150) :: 'fuel_model', 'kgC m-2', 'total loading'], & - 3, tot_loadingID) - + [character(len=20) :: 'coordinates', 'units', 'long_name'], & + [character(len=150) :: 'fuel_model', 'kgC m-2', 'total loading'], & + 3, tot_loadingID) + + ! register weighted dead fuel loading + call RegisterVar(ncid, 'weighted_loading_dead', dimIDs(3:3), type_double, & + [character(len=20) :: 'coordinates', 'units', 'long_name'], & + [character(len=150) :: 'fuel_model', 'kgC m-2', 'weighted total dead loading'], & + 3, wgt_loadingdID) + + ! register weighted live fuel loading + call RegisterVar(ncid, 'weighted_loading_live', dimIDs(3:3), type_double, & + [character(len=20) :: 'coordinates', 'units', 'long_name'], & + [character(len=150) :: 'fuel_model', 'kgC m-2', 'weighted total live loading'], & + 3, wgt_loadinglID) + ! register fuel bulk density - call RegisterVar(ncid, 'bulk_density', dimIDs(3:3), type_double, & - [character(len=20) :: 'coordinates', 'units', 'long_name'], & - [character(len=150) :: 'fuel_model', 'kg m-3', 'fuel bulk density'], & - 3, BDID) - + call RegisterVar(ncid, 'bulk_density', dimIDs(3:3), type_double, & + [character(len=20) :: 'coordinates', 'units', 'long_name'], & + [character(len=150) :: 'fuel_model', 'kg m-3', 'fuel bulk density'], & + 3, BDID) + ! register fuel SAV - call RegisterVar(ncid, 'SAV', dimIDs(3:3), type_double, & - [character(len=20) :: 'coordinates', 'units', 'long_name'], & - [character(len=150) :: 'fuel_model', 'cm-1', 'fuel surface area to volume ratio'], & - 3, SAVID) - + call RegisterVar(ncid, 'SAV', dimIDs(3:3), type_double, & + [character(len=20) :: 'coordinates', 'units', 'long_name'], & + [character(len=150) :: 'fuel_model', 'cm-1', 'fuel surface area to volume ratio'], & + 3, SAVID) + ! finish defining variables call EndNCDef(ncid) @@ -271,13 +301,17 @@ subroutine WriteFireData(out_file, nsteps, nfuelmods, temp_degC, precip, rh, NI, call WriteVar(ncid, loadingID, loading(:,:)) call WriteVar(ncid, frac_loadingID, frac_loading(:,:)) call WriteVar(ncid, tot_loadingID, non_trunk_loading(:)) - call WriteVar(ncid, moistiD, fuel_moisture(:,:)) + call WriteVar(ncid, wgt_loadingdID, weighted_loading_dead(:)) + call WriteVar(ncid, wgt_loadinglID, weighted_loading_live(:)) + call WriteVar(ncid, moistdID, fuel_moisture_dead(:,:)) + call WriteVar(ncid, moistlID, fuel_moisture_live(:,:)) call WriteVar(ncid, BDID, fuel_BD(:)) call WriteVar(ncid, SAVID, fuel_SAV(:)) - call WriteVar(ncid, mefID, fuel_MEF(:,:)) - + call WriteVar(ncid, mefdID, fuel_MEF_dead(:,:)) + call WriteVar(ncid, meflID, fuel_MEF_live(:,:)) + call CloseNCFile(ncid) - end subroutine WriteFireData + end subroutine WriteFireData end module FatesTestFireMod From ae50fc19c31e3bc936f3c4407dbfff81c8822c9a Mon Sep 17 00:00:00 2001 From: Xiulin Gao Date: Sun, 19 Oct 2025 20:05:20 -0700 Subject: [PATCH 04/23] bug fix --- fire/FatesFuelMod.F90 | 24 ++++++++++++------------ fire/SFEquationsMod.F90 | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/fire/FatesFuelMod.F90 b/fire/FatesFuelMod.F90 index 5cc713c80d..41bacf828b 100644 --- a/fire/FatesFuelMod.F90 +++ b/fire/FatesFuelMod.F90 @@ -25,7 +25,7 @@ module FatesFuelMod real(r8) :: non_trunk_loading ! total fuel loading excluding trunks [kgC/m2] real(r8) :: weighted_loading_dead ! this is dead fuel load weighted by weighting_factor given SA:V [kgC/m2] real(r8) :: weighted_loading_live ! this is live fuel load weighted by weighting factor given SA:V [kgC/m2] - real(r8) :: wf_lead ! weighting factor for dead fuel category [unitless] + real(r8) :: wf_dead ! weighting factor for dead fuel category [unitless] real(r8) :: wf_live ! weighting factor for live fuel category [unitless] real(r8) :: average_moisture_dead ! weighted average of fuel moisture across all fuel classes for dead fuels [m3/m3] real(r8) :: average_moisture_live ! weighted average of fuel moisture across all fuel classes for live fuels [m3/m3] @@ -138,7 +138,7 @@ subroutine Fuse(this, self_area, donor_area, donor_fuel) donor_fuel%bulk_density_weighted*donor_weight this%SAV_weighted = this%SAV_weighted*self_weight + donor_fuel%SAV_weighted*donor_weight this%MEF_dead = this%MEF_dead*self_weight + donor_fuel%MEF_dead*donor_weight - this%MEF_live = this%MEF_live*self_weight + donor_fuel%live_dead*donor_weight + this%MEF_live = this%MEF_live*self_weight + donor_fuel%MEF_live*donor_weight end subroutine Fuse @@ -242,7 +242,7 @@ subroutine SumLoading(this) integer :: i ! looping index ! ensure weighting factor is updated - call this%CalculateWeightingFactor() + call this%CalculateWeightingFactor(sav_fuel, part_dens) ! get fuel load weighting factor given SAV call this%FuelLoadWeight() @@ -257,10 +257,10 @@ subroutine SumLoading(this) if(i /= fuel_classes%live_grass())then this%weighted_loading_dead = this%weighted_loading_dead + & - this%fuel_weight*this%loading(i) + this%fuel_weight(i)*this%loading(i) else this%weighted_loading_live = this%weighted_loading_live + & - this%fuel_weight*this%loading(i) + this%fuel_weight(i)*this%loading(i) end if end do @@ -318,7 +318,7 @@ subroutine UpdateFuelMoisture(this, sav_fuel, drying_ratio, fireWeatherClass) ! fire weather class is in use select type (fireWeatherClass) class is (nesterov_index) - call CalculateFuelMoistureNesterov(sav_fuel, drying_ratio, & + call this%CalculateFuelMoistureNesterov(sav_fuel, drying_ratio, & fireWeatherClass%fire_weather_index) class default write(fates_log(), *) 'Unknown fire weather class selected.' @@ -335,7 +335,7 @@ subroutine UpdateFuelMoisture(this, sav_fuel, drying_ratio, fireWeatherClass) ! to derive this by fuel category (live vs dead) and by fuel sizes ! let's still keep this calculation for both dead and live fuels moisture_of_extinction(i) = MoistureOfExtinction(sav_fuel(i)) - this%effective_moisture(i) = moisture(i)/moisture_of_extinction(i) + this%effective_moisture(i) = this%moisture(i)/moisture_of_extinction(i) if(i /= fuel_classes%live_grass())then ! average fuel moisture and MEF for dead fuels [m3/m3] EQ. 66 in Rothermel 1972 ! trunk is not excluded, but it's getting a small weight @@ -343,7 +343,7 @@ subroutine UpdateFuelMoisture(this, sav_fuel, drying_ratio, fireWeatherClass) ! each fuel size class given SA:V, I am calculating averaged MEF_dead using the ! weighting factor 2025-10-16 XLG this%average_moisture_dead = this%average_moisture_dead + & - this%weighting_factor(i)*moisture(i) + this%weighting_factor(i)*this%moisture(i) this%MEF_dead = this%MEF_dead + this%weighting_factor(i)*moisture_of_extinction(i) end if end do @@ -353,13 +353,13 @@ subroutine UpdateFuelMoisture(this, sav_fuel, drying_ratio, fireWeatherClass) ! consider including live fine woody fuels later 2025-10-16 XLG this%average_moisture_live = this%average_moisture_live + & - this%weighting_factor(fuel_classes%live_grass())*moisture(fuel_classes%live_grass()) + this%weighting_factor(fuel_classes%live_grass())*this%moisture(fuel_classes%live_grass()) ! this is the Rothermel way of calculating averaged live fuel MEF across all fuel ! classes for live fuels, which is then used to calculate live fuel mositure damping coeff ! The difference between the SPITFIRE version and original Rothermel model ! is that live and dead fuels are always treated separately in the original model - call LiveFuelMoistureOfExtinction(this%fuel_loading, sav_fuel, moisture, & + call LiveFuelMoistureOfExtinction(this%loading, sav_fuel, this%moisture, & this%MEF_dead, mef_live) this%MEF_live = mef_live else @@ -586,7 +586,7 @@ subroutine CalculateFuelBurnt(this, fuel_consumed) use SFParamsMod, only : SF_val_mid_moisture, SF_val_mid_moisture_Coeff use SFParamsMod, only : SF_val_mid_moisture_Slope, SF_val_min_moisture use SFParamsMod, only : SF_val_low_moisture_Coeff, SF_val_low_moisture_Slope - use SFParamsMod, only : SF_val_miner_total + use SFParamsMod, only : SF_val_miner_total, SF_val_SAV, SF_val_part_dens ! ARGUMENTS: class(fuel_type), intent(inout) :: this ! fuel class @@ -601,7 +601,7 @@ subroutine CalculateFuelBurnt(this, fuel_consumed) this%frac_burnt(:) = 1.0_r8 ! get all the weighting factor - call this%CalculateWeightingFactor() + call this%CalculateWeightingFactor(SF_val_SAV, SF_val_part_dens) call this%FuelLoadWeight() ! Calculate fraction of litter is burnt for all classes. diff --git a/fire/SFEquationsMod.F90 b/fire/SFEquationsMod.F90 index 9d66157cbe..b879cabf79 100644 --- a/fire/SFEquationsMod.F90 +++ b/fire/SFEquationsMod.F90 @@ -269,7 +269,7 @@ real(r8) function HeatSink(q_ig, eps, wf, mean_FBD, wf_dead, wf_live) if(i /= fuel_classes%live_grass())then sum_dead = sum_dead + wf(i)*eps(i)*q_ig(i) else - sum_live = sum_live + wf(i)*eps(i),q_ig(i) + sum_live = sum_live + wf(i)*eps(i)*q_ig(i) end if end do HeatSink = mean_FBD * (wf_dead*sum_dead + wf_live*sum_live) From 9c17ca3c4363a3cd4cf5a6294850f40c5c111715 Mon Sep 17 00:00:00 2001 From: Xiulin Gao Date: Sun, 19 Oct 2025 20:10:27 -0700 Subject: [PATCH 05/23] pass returned moisture to fuel class moisture var --- fire/FatesFuelMod.F90 | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/fire/FatesFuelMod.F90 b/fire/FatesFuelMod.F90 index 41bacf828b..e3b8debbf8 100644 --- a/fire/FatesFuelMod.F90 +++ b/fire/FatesFuelMod.F90 @@ -309,6 +309,7 @@ subroutine UpdateFuelMoisture(this, sav_fuel, drying_ratio, fireWeatherClass) real(r8), intent(in) :: drying_ratio ! drying ratio class(fire_weather), intent(in) :: fireWeatherClass ! fireWeatherClass + real(r8) :: moisture(num_fuel_classes) ! fuel moisture [m3/m3] real(r8) :: moisture_of_extinction(num_fuel_classes) ! fuel moisture of extinction [m3/m3] real(r8) :: mef_live ! live fuel moisture of extinction [m3/m3] integer :: i ! looping index @@ -318,8 +319,9 @@ subroutine UpdateFuelMoisture(this, sav_fuel, drying_ratio, fireWeatherClass) ! fire weather class is in use select type (fireWeatherClass) class is (nesterov_index) - call this%CalculateFuelMoistureNesterov(sav_fuel, drying_ratio, & - fireWeatherClass%fire_weather_index) + call CalculateFuelMoistureNesterov(sav_fuel, drying_ratio, & + fireWeatherClass%fire_weather_index, moisture) + this%moisture = moisture class default write(fates_log(), *) 'Unknown fire weather class selected.' write(fates_log(), *) 'Choose a different fire weather class or upate this subroutine.' @@ -374,16 +376,16 @@ end subroutine UpdateFuelMoisture !------------------------------------------------------------------------------------- - subroutine CalculateFuelMoistureNesterov(this, sav_fuel, drying_ratio, NI) + subroutine CalculateFuelMoistureNesterov(sav_fuel, drying_ratio, NI, moisture) ! ! DESCRIPTION: ! Updates fuel moisture ! ARGUMENTS: - class(fuel_type), intent(inout) :: this ! fuel class - real(r8), intent(in) :: sav_fuel(num_fuel_classes) ! surface area to volume ratio of all fuel types [/cm] - real(r8), intent(in) :: drying_ratio ! drying ratio - real(r8), intent(in) :: NI ! Nesterov Index + real(r8), intent(in) :: sav_fuel(num_fuel_classes) ! surface area to volume ratio of all fuel types [/cm] + real(r8), intent(in) :: drying_ratio ! drying ratio + real(r8), intent(in) :: NI ! Nesterov Index + real(r8), intent(out) :: moisture(num_fuel_classes) ! moisture of litter [m3/m3] ! LOCALS integer :: i ! looping index @@ -398,7 +400,7 @@ subroutine CalculateFuelMoistureNesterov(this, sav_fuel, drying_ratio, NI) else alpha_FMC = sav_fuel(i)/drying_ratio end if - this%moisture(i) = exp(-1.0_r8*alpha_FMC*NI) + moisture(i) = exp(-1.0_r8*alpha_FMC*NI) end do end subroutine CalculateFuelMoistureNesterov From 4dda263789ab6545d56954992b8a6cc646eda28d Mon Sep 17 00:00:00 2001 From: Xiulin Gao Date: Sun, 19 Oct 2025 20:12:26 -0700 Subject: [PATCH 06/23] arg pass error --- fire/FatesFuelMod.F90 | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fire/FatesFuelMod.F90 b/fire/FatesFuelMod.F90 index e3b8debbf8..899560a2de 100644 --- a/fire/FatesFuelMod.F90 +++ b/fire/FatesFuelMod.F90 @@ -212,7 +212,7 @@ end subroutine CalculateWeightingFactor !------------------------------------------------------------------------------------- - subroutine SumLoading(this) + subroutine SumLoading(this, sav_fuel, part_dens) ! DESCRIPTION: ! Sums up the loading - excludes trunks ! @@ -237,6 +237,8 @@ subroutine SumLoading(this) ! ARGUMENTS: class(fuel_type), intent(inout) :: this ! fuel class + real(r8), intent(in) :: sav_fuel(num_fuel_classes) ! surface area to volume ratio of all fuel types [/cm] + real(r8), intent(in) :: part_dens ! oven-dry particle density [kg m-2] ! LOCALS: integer :: i ! looping index From 21544867dfb9d9273d88f0290f8b2e327c83357f Mon Sep 17 00:00:00 2001 From: Xiulin Gao Date: Sun, 19 Oct 2025 20:13:35 -0700 Subject: [PATCH 07/23] pass args --- fire/FatesFuelMod.F90 | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fire/FatesFuelMod.F90 b/fire/FatesFuelMod.F90 index 899560a2de..b6187123cf 100644 --- a/fire/FatesFuelMod.F90 +++ b/fire/FatesFuelMod.F90 @@ -271,18 +271,20 @@ end subroutine SumLoading !------------------------------------------------------------------------------------- - subroutine CalculateFractionalLoading(this) + subroutine CalculateFractionalLoading(this, sav_fuel, part_dens) ! DESCRIPTION: ! Calculates fractional loading for fuel ! ARGUMENTS: class(fuel_type), intent(inout) :: this ! fuel class + real(r8), intent(in) :: sav_fuel(num_fuel_classes) ! surface area to volume ratio of all fuel types [/cm] + real(r8), intent(in) :: part_dens ! oven-dry particle density [kg m-2] ! LOCALS: integer :: i ! looping index ! sum up loading just in case - call this%SumLoading() + call this%SumLoading(sav_fuel, part_dens) if (this%non_trunk_loading > nearzero) then do i = 1, num_fuel_classes From 2e628aedb1b57fc5ac369ab582435c2c678411b2 Mon Sep 17 00:00:00 2001 From: Xiulin Gao Date: Sun, 19 Oct 2025 20:24:29 -0700 Subject: [PATCH 08/23] fix args after updating relevant subroutines --- .../fire_fuel_test/test_FireFuel.pf | 100 +++++++++--------- 1 file changed, 52 insertions(+), 48 deletions(-) diff --git a/testing/unit_testing/fire_fuel_test/test_FireFuel.pf b/testing/unit_testing/fire_fuel_test/test_FireFuel.pf index ffb6e9d524..d327e92bfb 100644 --- a/testing/unit_testing/fire_fuel_test/test_FireFuel.pf +++ b/testing/unit_testing/fire_fuel_test/test_FireFuel.pf @@ -1,33 +1,33 @@ module test_FireFuel - ! - ! DESCRIPTION: - ! Test the FATES fuel portion of the SPITFIRE model - ! - use FatesConstantsMod, only : r8 => fates_r8 - use FatesFuelMod, only : fuel_type - use FatesFuelClassesMod, only : fuel_classes, num_fuel_classes - use funit - - implicit none - - @TestCase - type, extends(TestCase) :: TestFireFuel - type(fuel_type) :: fuel - contains + ! + ! DESCRIPTION: + ! Test the FATES fuel portion of the SPITFIRE model + ! + use FatesConstantsMod, only : r8 => fates_r8 + use FatesFuelMod, only : fuel_type + use FatesFuelClassesMod, only : fuel_classes, num_fuel_classes + use funit + + implicit none + + @TestCase + type, extends(TestCase) :: TestFireFuel + type(fuel_type) :: fuel + contains procedure :: setUp - end type TestFireFuel + end type TestFireFuel - real(r8), parameter :: tol = 1.e-13_r8 + real(r8), parameter :: tol = 1.e-13_r8 - contains +contains - subroutine setUp(this) + subroutine setUp(this) class(TestFireFuel), intent(inout) :: this call this%fuel%Init() - end subroutine setUp + end subroutine setUp - @Test - subroutine UpdateLoading_CorrectInputOrder(this) + @Test + subroutine UpdateLoading_CorrectInputOrder(this) ! test that the calculate loading subroutine correctly sets the fuel values class(TestFireFuel), intent(inout) :: this ! fuel test object real(r8) :: leaf_litter = 5.0_r8 ! leaf litter [kgC/m2] @@ -38,7 +38,7 @@ module test_FireFuel real(r8) :: live_grass = 30.0_r8 ! live grass [kgC/m2] call this%fuel%UpdateLoading(leaf_litter, twig_litter, sm_br_litter, & - lg_br_litter, trunk_litter, live_grass) + lg_br_litter, trunk_litter, live_grass) @assertEqual(this%fuel%loading(fuel_classes%dead_leaves()), leaf_litter, tolerance=tol) @assertEqual(this%fuel%loading(fuel_classes%twigs()), twig_litter, tolerance=tol) @@ -47,54 +47,58 @@ module test_FireFuel @assertEqual(this%fuel%loading(fuel_classes%trunks()), trunk_litter, tolerance=tol) @assertEqual(this%fuel%loading(fuel_classes%live_grass()), live_grass, tolerance=tol) - end subroutine UpdateLoading_CorrectInputOrder + end subroutine UpdateLoading_CorrectInputOrder - @Test - subroutine SumLoading_CorrectValues(this) + @Test + subroutine SumLoading_CorrectValues(this) ! test that the fuel is summed correctly (and ignores trunks) class(TestFireFuel), intent(inout) :: this ! fuel test object + real(r8) :: sav = (/13.0_r8, 3.58_r8, 0.98_r8, 0.2_r8, 66.0_r8, 66.0_r8 /) + real(r8) :: part_dens = 513_r8 real(r8) :: dummy_litter = 5.0_r8 ! dummy litter value [kgC/m2] real(r8) :: trunk_litter = 100.0_r8 ! trunk branch litter [kgC/m2] real(r8) :: non_trunk_loading ! what non-trunk loading should be [kgC/m2] - + non_trunk_loading = dummy_litter*5.0_r8 call this%fuel%UpdateLoading(dummy_litter, dummy_litter, dummy_litter, & - dummy_litter, trunk_litter, dummy_litter) - - call this%fuel%SumLoading() + dummy_litter, trunk_litter, dummy_litter) + + call this%fuel%SumLoading(sav, part_dens) @assertEqual(this%fuel%non_trunk_loading, non_trunk_loading, tolerance=tol) - end subroutine SumLoading_CorrectValues + end subroutine SumLoading_CorrectValues - @Test - subroutine CalculateFractionalLoading_CorrectValues(this) + @Test + subroutine CalculateFractionalLoading_CorrectValues(this) ! test that the fractional loading is calculated correctly (and ignores trunks) class(TestFireFuel), intent(inout) :: this ! fuel test object + real(r8) :: sav = (/13.0_r8, 3.58_r8, 0.98_r8, 0.2_r8, 66.0_r8, 66.0_r8 /) + real(r8) :: part_dens = 513_r8 real(r8) :: dummy_litter = 5.0_r8 ! dummy litter value [kgC/m2] real(r8) :: trunk_litter = 100.0_r8 ! trunk branch litter [kgC/m2] real(r8) :: non_trunk_loading ! what non-trunk loading should be [kgC/m2] real(r8) :: frac_loading ! what the fractional loading should be [0-1] integer :: i ! looping index - + non_trunk_loading = dummy_litter*float(num_fuel_classes - 1) frac_loading = dummy_litter/non_trunk_loading call this%fuel%UpdateLoading(dummy_litter, dummy_litter, dummy_litter, & - dummy_litter, trunk_litter, dummy_litter) - - call this%fuel%SumLoading() - call this%fuel%CalculateFractionalLoading() - - do i = 1, num_fuel_classes - if (i /= fuel_classes%trunks()) then - @assertEqual(this%fuel%frac_loading(i), frac_loading, tolerance=tol) - else - @assertEqual(this%fuel%frac_loading(i), 0.0_r8, tolerance=tol) - end if - end do - - end subroutine CalculateFractionalLoading_CorrectValues + dummy_litter, trunk_litter, dummy_litter) + + call this%fuel%SumLoading(sav, part_dens) + call this%fuel%CalculateFractionalLoading(sav, part_dens) + + do i = 1, num_fuel_classes + if (i /= fuel_classes%trunks()) then + @assertEqual(this%fuel%frac_loading(i), frac_loading, tolerance=tol) + else + @assertEqual(this%fuel%frac_loading(i), 0.0_r8, tolerance=tol) + end if + end do + + end subroutine CalculateFractionalLoading_CorrectValues end module test_FireFuel From 8ee718a7012a78ca93cbccc072b385dd33d79bfd Mon Sep 17 00:00:00 2001 From: Xiulin Gao Date: Sun, 19 Oct 2025 20:54:48 -0700 Subject: [PATCH 09/23] make corresponding change for unit test after corrections --- .../fire_equations_test/test_FireEquations.pf | 1060 ++++++++--------- .../fire_fuel_test/test_FireFuel.pf | 4 +- 2 files changed, 509 insertions(+), 555 deletions(-) diff --git a/testing/unit_testing/fire_equations_test/test_FireEquations.pf b/testing/unit_testing/fire_equations_test/test_FireEquations.pf index a597e22749..111704f842 100644 --- a/testing/unit_testing/fire_equations_test/test_FireEquations.pf +++ b/testing/unit_testing/fire_equations_test/test_FireEquations.pf @@ -1,156 +1,156 @@ module test_FireEquations - ! - ! DESCRIPTION: - ! Test the SPITFIRE-related equations - tests all methods in SFEquationsMod - ! - use FatesConstantsMod, only : r8 => fates_r8 - use FatesConstantsMod, only : nearzero - use FatesUnitTestUtils, only : endrun_msg - use SFEquationsMod - use funit + ! + ! DESCRIPTION: + ! Test the SPITFIRE-related equations - tests all methods in SFEquationsMod + ! + use FatesConstantsMod, only : r8 => fates_r8 + use FatesConstantsMod, only : nearzero + use FatesUnitTestUtils, only : endrun_msg + use SFEquationsMod + use funit - implicit none + implicit none - @TestCase - type, extends(TestCase) :: TestFireEquations - end type TestFireEquations + @TestCase + type, extends(TestCase) :: TestFireEquations + end type TestFireEquations - real(r8), parameter :: low_tol = 1.e-7_r8 - real(r8), parameter :: high_tol = 1.e-13_r8 + real(r8), parameter :: low_tol = 1.e-7_r8 + real(r8), parameter :: high_tol = 1.e-13_r8 - contains +contains - @Test - subroutine OptimumPackingRatio_ZeroInput_ReturnsZero(this) + @Test + subroutine OptimumPackingRatio_ZeroInput_ReturnsZero(this) ! test that when SAV is zero or very close to zero, OptimumPackingRatio returns 0.0 class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: beta ! optimum packing ratio returned - + ! first test 0.0 beta = OptimumPackingRatio(0.0_r8) @assertEqual(beta, 0.0_r8) - + ! now test close to zero beta = OptimumPackingRatio(1.0e-31_r8) @assertEqual(beta, 0.0_r8) - - end subroutine OptimumPackingRatio_ZeroInput_ReturnsZero - - @Test - subroutine OptimumPackingRatio_ReturnsReasonableValues(this) + + end subroutine OptimumPackingRatio_ZeroInput_ReturnsZero + + @Test + subroutine OptimumPackingRatio_ReturnsReasonableValues(this) ! test that when SAV is some reasonable value, OptimumPackingRatio is correctly output class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: beta ! optimum packing ratio returned - + ! test 1.0, 10.0, 100.0, 1000.0 beta = OptimumPackingRatio(1.0_r8) @assertEqual(beta, 0.200395_r8, tolerance=low_tol) - + beta = OptimumPackingRatio(10.0_r8) @assertEqual(beta, 0.03040793_r8, tolerance=low_tol) - + beta = OptimumPackingRatio(100.0_r8) @assertEqual(beta, 0.004614099_r8, tolerance=low_tol) - + beta = OptimumPackingRatio(1000.0_r8) @assertEqual(beta, 0.0007001432_r8, tolerance=low_tol) - - end subroutine OptimumPackingRatio_ReturnsReasonableValues - - @Test - subroutine OptimumPackingRatio_VerySmall_ReturnsReasonableValues(this) + + end subroutine OptimumPackingRatio_ReturnsReasonableValues + + @Test + subroutine OptimumPackingRatio_VerySmall_ReturnsReasonableValues(this) ! test that when SAV is very small (but not zero), the function returns something larger than zero class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: beta ! optimum packing ratio returned - + ! test a small number as well as nearzero beta = OptimumPackingRatio(1.0e-6_r8) @assertGreaterThan(beta, 0.0_r8) - + beta = OptimumPackingRatio(nearzero) @assertGreaterThan(beta, 0.0_r8) - - end subroutine OptimumPackingRatio_VerySmall_ReturnsReasonableValues - - @Test - subroutine MaximumReactionVelocity_ZeroInput_ReturnsZero(this) + + end subroutine OptimumPackingRatio_VerySmall_ReturnsReasonableValues + + @Test + subroutine MaximumReactionVelocity_ZeroInput_ReturnsZero(this) ! test that when SAV is zero or very close to zero, MaximumReactionVelocity returns 0.0 class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: vel ! maximum reaction velocity returned - + ! first test 0.0 vel = MaximumReactionVelocity(0.0_r8) @assertEqual(vel, 0.0_r8) - + ! now test close to zero vel = MaximumReactionVelocity(1.0e-31_r8) @assertEqual(vel, 0.0_r8) - - end subroutine MaximumReactionVelocity_ZeroInput_ReturnsZero - - @Test - subroutine MaximumReactionVelocity_IncreasesAsSAVIncreases(this) + + end subroutine MaximumReactionVelocity_ZeroInput_ReturnsZero + + @Test + subroutine MaximumReactionVelocity_IncreasesAsSAVIncreases(this) ! test that MaximumReactionVelocity output increases as SAV input increases class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: vels(5) ! maximum reaction velocity returned integer :: i ! looping index ! hard-coded sav values real(r8), parameter :: sav_vals(5) = [10.0_r8, 50.0_r8, 100.0_r8, 500.0_r8, 1000.0_r8] - + do i = 1, size(sav_vals) - vels(i) = MaximumReactionVelocity(sav_vals(i)) + vels(i) = MaximumReactionVelocity(sav_vals(i)) end do - + ! check that function outputs increase as SAV increases do i = 1, size(sav_vals) - 1 - @assertLessThan(vels(i), vels(i+1)) + @assertLessThan(vels(i), vels(i+1)) end do - - end subroutine MaximumReactionVelocity_IncreasesAsSAVIncreases - - @Test - subroutine MaximumReactionVelocity_VerySmall_ReturnsNonZero(this) + + end subroutine MaximumReactionVelocity_IncreasesAsSAVIncreases + + @Test + subroutine MaximumReactionVelocity_VerySmall_ReturnsNonZero(this) ! test that when SAV is very small (but not zero), the function returns something larger than zero class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: vel ! maximum reaction velocity returned - + ! test a small number as well as nearzero vel = MaximumReactionVelocity(1.0e-6_r8) @assertGreaterThan(vel, 0.0_r8) - + vel = MaximumReactionVelocity(nearzero) @assertGreaterThan(vel, 0.0_r8) - - end subroutine MaximumReactionVelocity_VerySmall_ReturnsNonZero - - @Test - subroutine OptimumReactionVelocity_BetaRatioZero_ReturnsZero(this) + + end subroutine MaximumReactionVelocity_VerySmall_ReturnsNonZero + + @Test + subroutine OptimumReactionVelocity_BetaRatioZero_ReturnsZero(this) ! test that when beta ratio is zero, the function returns zero class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: vel ! optimum reaction velocity returned real(r8), parameter :: max_reaction_vel = 10.0_r8 ! value for maximum reaction velocity real(r8), parameter :: sav = 50.0_r8 ! value for SAV - + vel = OptimumReactionVelocity(max_reaction_vel, sav, 0.0_r8) @assertEqual(vel, 0.0_r8) - - end subroutine OptimumReactionVelocity_BetaRatioZero_ReturnsZero - - @Test - subroutine OptimumReactionVelocity_BetaRatioOne_ReturnsMaxReactionVel(this) + + end subroutine OptimumReactionVelocity_BetaRatioZero_ReturnsZero + + @Test + subroutine OptimumReactionVelocity_BetaRatioOne_ReturnsMaxReactionVel(this) ! test that when beta ratio is 1.0, the function returns maximum reaction velocity class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: vel ! optimum reaction velocity returned real(r8), parameter :: max_reaction_vel = 10.0_r8 ! value for maximum reaction velocity real(r8), parameter :: sav = 50.0_r8 ! value for SAV - + vel = OptimumReactionVelocity(max_reaction_vel, sav, 1.0_r8) @assertEqual(vel, max_reaction_vel) - - end subroutine OptimumReactionVelocity_BetaRatioOne_ReturnsMaxReactionVel - - @Test - subroutine OptimumReactionVelocity_ReasonableInputs_ReturnsNonZero(this) + + end subroutine OptimumReactionVelocity_BetaRatioOne_ReturnsMaxReactionVel + + @Test + subroutine OptimumReactionVelocity_ReasonableInputs_ReturnsNonZero(this) ! test that OptimumReactionVelocity produces reasonable output with reasonable input values (i.e. non zero) class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: vel ! optimum reaction velocity returned @@ -159,18 +159,18 @@ module test_FireEquations ! hard-coded sav and beta values real(r8), parameter :: sav_vals(3) = [10.0_r8, 50.0_r8, 100.0_r8] real(r8), parameter :: beta_vals(3) = [0.25_r8, 0.5_r8, 0.75_r8] - + do i = 1, size(sav_vals) - do j = 1, size(beta_vals) - vel = OptimumReactionVelocity(max_reaction_vel, sav_vals(i), beta_vals(j)) - @assertGreaterThan(vel, 0.0_r8) - end do + do j = 1, size(beta_vals) + vel = OptimumReactionVelocity(max_reaction_vel, sav_vals(i), beta_vals(j)) + @assertGreaterThan(vel, 0.0_r8) + end do end do - - end subroutine OptimumReactionVelocity_ReasonableInputs_ReturnsNonZero - - @Test - subroutine OptimumReactionVelocity_IncreasesAsSAVIncreases(this) + + end subroutine OptimumReactionVelocity_ReasonableInputs_ReturnsNonZero + + @Test + subroutine OptimumReactionVelocity_IncreasesAsSAVIncreases(this) ! test that OptimumReactionVelocity output increases as SAV input increases class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: vels(7) ! maximum reaction velocity returned @@ -179,20 +179,20 @@ module test_FireEquations real(r8), parameter :: beta = 0.5_r8 ! value for beta ! hard-coded sav values real(r8), parameter :: sav_vals(7) = [0.1_r8, 1.0_r8, 10.0_r8, 50.0_r8, 100.0_r8, 500.0_r8, 1000.0_r8] - + do i = 1, size(sav_vals) - vels(i) = OptimumReactionVelocity(max_reaction_vel, sav_vals(i), beta) + vels(i) = OptimumReactionVelocity(max_reaction_vel, sav_vals(i), beta) end do - + ! check that function increases decrease as SAV increases do i = 1, size(sav_vals) - 1 - @assertLessThan(vels(i), vels(i+1)) + @assertLessThan(vels(i), vels(i+1)) end do - - end subroutine OptimumReactionVelocity_IncreasesAsSAVIncreases - - @Test - subroutine OptimumReactionVelocity_ScalesWithMaxReactionVel(this) + + end subroutine OptimumReactionVelocity_IncreasesAsSAVIncreases + + @Test + subroutine OptimumReactionVelocity_ScalesWithMaxReactionVel(this) ! test that OptimumReactionVelocity scales correctly with maximum reaction velocity class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: vel1 ! result for max reaction vel 1 @@ -206,78 +206,78 @@ module test_FireEquations vel1 = OptimumReactionVelocity(max_reaction_vel1, sav, beta) vel2 = OptimumReactionVelocity(max_reaction_vel2, sav, beta) ratio = vel2/vel1 - + @assertEqual(ratio, 2.0_r8) - - end subroutine OptimumReactionVelocity_ScalesWithMaxReactionVel - - @Test - subroutine MoistureCoefficient_ZeroMoisture_ReturnsOne(this) + + end subroutine OptimumReactionVelocity_ScalesWithMaxReactionVel + + @Test + subroutine MoistureCoefficient_ZeroMoisture_ReturnsOne(this) ! test that when moisture is zero, the function returns one class(TestFireEquations), intent(inout) :: this ! test object - real(r8) :: coeff ! result + real(r8) :: coeff ! result real(r8), parameter :: MEF = 0.3_r8 ! value for MEF coeff = MoistureCoefficient(0.0_r8, MEF) @assertEqual(coeff, 1.0_r8) - - end subroutine MoistureCoefficient_ZeroMoisture_ReturnsOne - - @Test - subroutine MoistureCoefficient_MoistureExceedsMEF_ReturnsZero(this) + + end subroutine MoistureCoefficient_ZeroMoisture_ReturnsOne + + @Test + subroutine MoistureCoefficient_MoistureExceedsMEF_ReturnsZero(this) ! test that when moisture exceeds MEF, the function resturns zero class(TestFireEquations), intent(inout) :: this ! test object - real(r8) :: coeff ! result + real(r8) :: coeff ! result real(r8), parameter :: MEF = 0.3_r8 ! value for MEF coeff = MoistureCoefficient(0.4_r8, MEF) @assertEqual(coeff, 0.0_r8) - - end subroutine MoistureCoefficient_MoistureExceedsMEF_ReturnsZero - - @Test - subroutine MoistureCoefficient_DecreasesWithIncreasingMoisture(this) + + end subroutine MoistureCoefficient_MoistureExceedsMEF_ReturnsZero + + @Test + subroutine MoistureCoefficient_DecreasesWithIncreasingMoisture(this) ! test that when moisture increases, the coefficient decreases class(TestFireEquations), intent(inout) :: this ! test object - real(r8) :: coeffs(6) ! result + real(r8) :: coeffs(6) ! result integer :: i ! looping index real(r8), parameter :: MEF = 0.6_r8 ! value for MEF ! hard-coded moisture values real(r8), parameter :: moist(6) = [0.1_r8, 0.2_r8, 0.3_r8, 0.4_r8, 0.5_r8, 0.55_r8] - + do i = 1, size(moist) - coeffs(i) = MoistureCoefficient(moist(i), MEF) + coeffs(i) = MoistureCoefficient(moist(i), MEF) end do - + do i = 1, size(moist) - 1 - - ! check that function outputs decrease as moisture increases - @assertGreaterThan(coeffs(i), coeffs(i+1)) - - ! also make sure value is between 0.0 and 1.0 - @assertLessThan(coeffs(i), 1.0_r8) - @assertGreaterThan(coeffs(i), 0.0_r8) + + ! check that function outputs decrease as moisture increases + @assertGreaterThan(coeffs(i), coeffs(i+1)) + + ! also make sure value is between 0.0 and 1.0 + @assertLessThan(coeffs(i), 1.0_r8) + @assertGreaterThan(coeffs(i), 0.0_r8) end do - - end subroutine MoistureCoefficient_DecreasesWithIncreasingMoisture - - @Test - subroutine MoistureCoefficient_MEFZero_ReturnsZero(this) + + end subroutine MoistureCoefficient_DecreasesWithIncreasingMoisture + + @Test + subroutine MoistureCoefficient_MEFZero_ReturnsZero(this) ! test that when MEF == zero, function returns zero - this is an edge case class(TestFireEquations), intent(inout) :: this ! test object - real(r8) :: coeff ! result + real(r8) :: coeff ! result real(r8), parameter :: moist = 0.3_r8 ! value for moisture coeff = MoistureCoefficient(moist, 0.0_r8) @assertEqual(coeff, 0.0_r8) - - end subroutine MoistureCoefficient_MEFZero_ReturnsZero - - @Test - subroutine ReactionIntensity_HighMoisture_ReactionIntensityZero(this) + + end subroutine MoistureCoefficient_MEFZero_ReturnsZero + + @Test + subroutine ReactionIntensity_HighMoisture_ReactionIntensityZero(this) ! test that when moisture exceeds MEF, reaction intensity is zero class(TestFireEquations), intent(inout) :: this ! test object - real(r8) :: I_r ! result + real(r8) :: I_r ! result real(r8), parameter :: fuel = 1.0_r8 ! value for fuel loading real(r8), parameter :: SAV = 50.0_r8 ! value for SAV real(r8), parameter :: beta_ratio = 0.5_r8 ! value for beta ratio @@ -285,11 +285,11 @@ module test_FireEquations I_r = ReactionIntensity(fuel, SAV, beta_ratio, 0.5_r8, MEF) @assertEqual(I_r, 0.0_r8) - - end subroutine ReactionIntensity_HighMoisture_ReactionIntensityZero - - @Test - subroutine ReactionIntensity_DecreasesWithIncreasingMoisture(this) + + end subroutine ReactionIntensity_HighMoisture_ReactionIntensityZero + + @Test + subroutine ReactionIntensity_DecreasesWithIncreasingMoisture(this) ! test that reaction intensity decreases with increasing moisture class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: I_r(4) ! result @@ -300,20 +300,20 @@ module test_FireEquations real(r8), parameter :: MEF = 0.5_r8 ! value for MEF ! hard-coded moisture values real(r8), parameter :: moist(4) = [0.1_r8, 0.2_r8, 0.3_r8, 0.4_r8] - + do i = 1, size(moist) - I_r(i) = ReactionIntensity(fuel, SAV, beta_ratio, moist(i), MEF) + I_r(i) = ReactionIntensity(fuel, SAV, beta_ratio, moist(i), MEF) end do - + do i = 1, size(moist) - 1 - ! check that function outputs decrease as moisture increases - @assertGreaterThan(I_r(i), I_r(i+1), tolerance=high_tol) + ! check that function outputs decrease as moisture increases + @assertGreaterThan(I_r(i), I_r(i+1), tolerance=high_tol) end do - - end subroutine ReactionIntensity_DecreasesWithIncreasingMoisture - - @Test - subroutine ReactionIntensity_IncreasesWithIncreasingFuel(this) + + end subroutine ReactionIntensity_DecreasesWithIncreasingMoisture + + @Test + subroutine ReactionIntensity_IncreasesWithIncreasingFuel(this) ! test that reaction intensity increases with increasing fuel loading class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: I_r(5) ! result @@ -324,20 +324,20 @@ module test_FireEquations real(r8), parameter :: MEF = 0.5_r8 ! value for MEF ! hard-coded moisture values real(r8), parameter :: fuel(5) = [0.01_r8, 1.0_r8, 5.0_r8, 10.0_r8, 100.0_r8] - + do i = 1, size(fuel) - I_r(i) = ReactionIntensity(fuel(i), SAV, beta_ratio, moist, MEF) + I_r(i) = ReactionIntensity(fuel(i), SAV, beta_ratio, moist, MEF) end do - + do i = 1, size(fuel) - 1 - ! check that function outputs increase as fuel increases - @assertLessThan(I_r(i), I_r(i+1), tolerance=high_tol) + ! check that function outputs increase as fuel increases + @assertLessThan(I_r(i), I_r(i+1), tolerance=high_tol) end do - - end subroutine ReactionIntensity_IncreasesWithIncreasingFuel - - @Test - subroutine ReactionIntensity_IncreasesWithIncreasingSAV(this) + + end subroutine ReactionIntensity_IncreasesWithIncreasingFuel + + @Test + subroutine ReactionIntensity_IncreasesWithIncreasingSAV(this) ! test that reaction intensity increases with increasing SAV class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: I_r(5) ! result @@ -348,20 +348,20 @@ module test_FireEquations real(r8), parameter :: MEF = 0.5_r8 ! value for MEF ! hard-coded SAV values real(r8), parameter :: SAV(5) = [0.1_r8, 1.0_r8, 5.0_r8, 10.0_r8, 100.0_r8] - + do i = 1, size(SAV) - I_r(i) = ReactionIntensity(fuel, SAV(i), beta_ratio, moist, MEF) + I_r(i) = ReactionIntensity(fuel, SAV(i), beta_ratio, moist, MEF) end do - + do i = 1, size(SAV) - 1 - ! check that function outputs increase as SAV increases - @assertLessThan(I_r(i), I_r(i+1), tolerance=high_tol) + ! check that function outputs increase as SAV increases + @assertLessThan(I_r(i), I_r(i+1), tolerance=high_tol) end do - - end subroutine ReactionIntensity_IncreasesWithIncreasingSAV - - @Test - subroutine ReactionIntensity_IncreasesWithIncreasingBeta(this) + + end subroutine ReactionIntensity_IncreasesWithIncreasingSAV + + @Test + subroutine ReactionIntensity_IncreasesWithIncreasingBeta(this) ! test that reaction intensity increases with increasing beta ratio class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: I_r(5) ! result @@ -372,20 +372,20 @@ module test_FireEquations real(r8), parameter :: MEF = 0.5_r8 ! value for MEF ! hard-coded beta ratio (relative packing ratio [unitless]) values real(r8), parameter :: beta_ratio(5) = [0.0_r8, 0.25_r8, 0.5_r8, 0.75_r8, 1.0_r8] - + do i = 1, size(beta_ratio) - I_r(i) = ReactionIntensity(fuel, SAV, beta_ratio(i), moist, MEF) + I_r(i) = ReactionIntensity(fuel, SAV, beta_ratio(i), moist, MEF) end do - + do i = 1, size(beta_ratio) - 1 - ! check that function outputs increase as beta_ratio increases - @assertLessThan(I_r(i), I_r(i+1), tolerance=high_tol) + ! check that function outputs increase as beta_ratio increases + @assertLessThan(I_r(i), I_r(i+1), tolerance=high_tol) end do - - end subroutine ReactionIntensity_IncreasesWithIncreasingBeta - - @Test - subroutine ReactionIntensity_IncreasesWithIncreasingMEF(this) + + end subroutine ReactionIntensity_IncreasesWithIncreasingBeta + + @Test + subroutine ReactionIntensity_IncreasesWithIncreasingMEF(this) ! test that reaction intensity increases with increasing MEF class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: I_r(4) ! result @@ -396,20 +396,20 @@ module test_FireEquations real(r8), parameter :: beta_ratio = 0.5_r8 ! value for beta ratio ! hard-coded beta ratio values real(r8), parameter :: MEF(4) = [0.25_r8, 0.5_r8, 0.75_r8, 1.0_r8] - + do i = 1, size(MEF) - I_r(i) = ReactionIntensity(fuel, SAV, beta_ratio, moist, MEF(i)) + I_r(i) = ReactionIntensity(fuel, SAV, beta_ratio, moist, MEF(i)) end do - + do i = 1, size(MEF) - 1 - ! check that function outputs increase as beta_ratio increases - @assertLessThan(I_r(i), I_r(i+1), tolerance=high_tol) + ! check that function outputs increase as beta_ratio increases + @assertLessThan(I_r(i), I_r(i+1), tolerance=high_tol) end do - - end subroutine ReactionIntensity_IncreasesWithIncreasingMEF - - @Test - subroutine ReactionIntensity_ZeroFuel_ZeroIntensity(this) + + end subroutine ReactionIntensity_IncreasesWithIncreasingMEF + + @Test + subroutine ReactionIntensity_ZeroFuel_ZeroIntensity(this) ! test that reaction intensity increases with increasing beta ratio class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: I_r ! result @@ -418,95 +418,95 @@ module test_FireEquations real(r8), parameter :: beta_ratio = 0.5_r8 ! value for beta ratio real(r8), parameter :: SAV = 50.0_r8 ! value for SAV real(r8), parameter :: MEF = 0.5_r8 ! value for beta MEF - + I_r = ReactionIntensity(0.0_r8, SAV, beta_ratio, moist, MEF) @assertEqual(I_r, 0.0_r8) - - end subroutine ReactionIntensity_ZeroFuel_ZeroIntensity - - @Test - subroutine HeatofPreignition_ZeroFuelMoisture_CorrectOutput(this) + + end subroutine ReactionIntensity_ZeroFuel_ZeroIntensity + + @Test + subroutine HeatofPreignition_ZeroFuelMoisture_CorrectOutput(this) ! test that for zero fuel moisture, heat of preignition is equal to dry heat of preignition class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: Q_ig ! result real(r8), parameter :: q_dry = 581.0_r8 ! heat of preignition of dry fuels - + Q_ig = HeatofPreignition(0.0_r8) @assertEqual(Q_ig, q_dry) - - end subroutine HeatofPreignition_ZeroFuelMoisture_CorrectOutput - - @Test - subroutine HeatofPreignition_IncreasesWithIncreasingMoisture(this) + + end subroutine HeatofPreignition_ZeroFuelMoisture_CorrectOutput + + @Test + subroutine HeatofPreignition_IncreasesWithIncreasingMoisture(this) ! test that heat of preignition increases with increasing moisture class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: Q_ig(4) ! result integer :: i ! looping index ! hard-coded moisture values real(r8), parameter :: moist(4) = [0.1_r8, 0.2_r8, 0.3_r8, 0.4_r8] - + do i = 1, size(moist) - Q_ig(i) = HeatofPreignition(moist(i)) + Q_ig(i) = HeatofPreignition(moist(i)) end do - + do i = 1, size(moist) - 1 - ! check that function outputs increase as moisture increases - @assertLessThan(Q_ig(i), Q_ig(i+1)) + ! check that function outputs increase as moisture increases + @assertLessThan(Q_ig(i), Q_ig(i+1)) end do - - end subroutine HeatofPreignition_IncreasesWithIncreasingMoisture - - @Test - subroutine EffectiveHeatingNumber_ZeroInput_ReturnsZero(this) + + end subroutine HeatofPreignition_IncreasesWithIncreasingMoisture + + @Test + subroutine EffectiveHeatingNumber_ZeroInput_ReturnsZero(this) ! test that when SAV is zero or very close to zero, EffectiveHeatingNumber returns 0.0 class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: eps ! result - + ! first test 0.0 eps = EffectiveHeatingNumber(0.0_r8) @assertEqual(eps, 0.0_r8) - + ! now test close to zero eps = EffectiveHeatingNumber(1.0e-31_r8) @assertEqual(eps, 0.0_r8) - - end subroutine EffectiveHeatingNumber_ZeroInput_ReturnsZero - - @Test - subroutine EffectiveHeatingNumber_IncreasesWithIncreasingSAV(this) + + end subroutine EffectiveHeatingNumber_ZeroInput_ReturnsZero + + @Test + subroutine EffectiveHeatingNumber_IncreasesWithIncreasingSAV(this) ! test that effective heating number increases with increasing SAV class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: eps(4) ! result integer :: i ! looping index ! hard-coded SAV values real(r8), parameter :: SAV(4) = [0.1_r8, 10.0_r8, 50.0_r8, 1000.0_r8] - + do i = 1, size(SAV) - eps(i) = EffectiveHeatingNumber(SAV(i)) + eps(i) = EffectiveHeatingNumber(SAV(i)) end do - + do i = 1, size(SAV) - 1 - ! check that function outputs increase as SAV increases - @assertLessThan(eps(i), eps(i+1)) + ! check that function outputs increase as SAV increases + @assertLessThan(eps(i), eps(i+1)) end do - - end subroutine EffectiveHeatingNumber_IncreasesWithIncreasingSAV - - @Test - subroutine WindFactor_ZeroWind_GivesZero(this) + + end subroutine EffectiveHeatingNumber_IncreasesWithIncreasingSAV + + @Test + subroutine WindFactor_ZeroWind_GivesZero(this) ! test that the wind factor returns zero when wind speed is zero class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: phi ! result real(r8), parameter :: beta_ratio = 0.5_r8 ! value for beta ratio real(r8), parameter :: SAV = 50.0_r8 ! value for SAV - + phi = WindFactor(0.0_r8, beta_ratio, SAV) @assertEqual(phi, 0.0_r8) - - end subroutine WindFactor_ZeroWind_GivesZero - - @Test - subroutine WindFactor_IncreasesWithIncreasingWindSpeed(this) + + end subroutine WindFactor_ZeroWind_GivesZero + + @Test + subroutine WindFactor_IncreasesWithIncreasingWindSpeed(this) ! test that the wind factor increases with increasing wind speed class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: phi(4) ! result @@ -515,20 +515,20 @@ module test_FireEquations real(r8), parameter :: SAV = 50.0_r8 ! value for SAV ! hard-coded wind speed values real(r8), parameter :: wind(4) = [0.1_r8, 1.0_r8, 10.0_r8, 20.0_r8] - + do i = 1, size(wind) - phi(i) = WindFactor(wind(i), beta_ratio, SAV) + phi(i) = WindFactor(wind(i), beta_ratio, SAV) end do - + do i = 1, size(wind) - 1 - ! check that function outputs increase as wind speed increases - @assertLessThan(phi(i), phi(i+1)) + ! check that function outputs increase as wind speed increases + @assertLessThan(phi(i), phi(i+1)) end do - - end subroutine WindFactor_IncreasesWithIncreasingWindSpeed - - @Test - subroutine WindFactor_DecreasesWithIncreasingSAV(this) + + end subroutine WindFactor_IncreasesWithIncreasingWindSpeed + + @Test + subroutine WindFactor_DecreasesWithIncreasingSAV(this) ! test that the wind factor decreases with increasing SAV class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: phi(4) ! result @@ -537,20 +537,20 @@ module test_FireEquations real(r8), parameter :: wind = 10.0_r8 ! value for wind speed ! hard-coded SAV values real(r8), parameter :: SAV(4) = [0.1_r8, 10.0_r8, 50.0_r8, 300.0_r8] - + do i = 1, size(SAV) - phi(i) = WindFactor(wind, beta_ratio, SAV(i)) + phi(i) = WindFactor(wind, beta_ratio, SAV(i)) end do - + do i = 1, size(SAV) - 1 - ! check that function outputs decreases as SAV increases - @assertGreaterThan(phi(i), phi(i+1)) + ! check that function outputs decreases as SAV increases + @assertGreaterThan(phi(i), phi(i+1)) end do - - end subroutine WindFactor_DecreasesWithIncreasingSAV - - @Test - subroutine WindFactor_DecreasesWithIncreasingBeta(this) + + end subroutine WindFactor_DecreasesWithIncreasingSAV + + @Test + subroutine WindFactor_DecreasesWithIncreasingBeta(this) ! test that the wind factor decreases with increasing beta ratio class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: phi(4) ! result @@ -559,20 +559,20 @@ module test_FireEquations real(r8), parameter :: wind = 10.0_r8 ! value for wind speed ! hard-coded beta ratio values real(r8), parameter :: beta_ratio(4) = [0.1_r8, 0.25_r8, 0.75_r8, 1.0_r8] - + do i = 1, size(beta_ratio) - phi(i) = WindFactor(wind, beta_ratio(i), SAV) + phi(i) = WindFactor(wind, beta_ratio(i), SAV) end do - + do i = 1, size(beta_ratio) - 1 - ! check that function outputs decreases as SAV increases - @assertGreaterThan(phi(i), phi(i+1)) + ! check that function outputs decreases as SAV increases + @assertGreaterThan(phi(i), phi(i+1)) end do - - end subroutine WindFactor_DecreasesWithIncreasingBeta - - @Test - subroutine PropagatingFlux_IncreasesWithIncreasingSAV(this) + + end subroutine WindFactor_DecreasesWithIncreasingBeta + + @Test + subroutine PropagatingFlux_IncreasesWithIncreasingSAV(this) ! test that the propagating flux increases with increasing SAV class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: prop_flux(4) ! result @@ -580,20 +580,20 @@ module test_FireEquations real(r8), parameter :: beta = 0.5_r8 ! value for beta ! hard-coded SAV values real(r8), parameter :: SAV(4) = [0.1_r8, 10.0_r8, 50.0_r8, 100.0_r8] - + do i = 1, size(SAV) - prop_flux(i) = PropagatingFlux(beta, SAV(i)) + prop_flux(i) = PropagatingFlux(beta, SAV(i)) end do - + do i = 1, size(SAV) - 1 - ! check that function outputs increases as SAV increases - @assertLessThan(prop_flux(i), prop_flux(i+1)) + ! check that function outputs increases as SAV increases + @assertLessThan(prop_flux(i), prop_flux(i+1)) end do - - end subroutine PropagatingFlux_IncreasesWithIncreasingSAV - - @Test - subroutine PropagatingFlux_IncreasesWithIncreasingBeta(this) + + end subroutine PropagatingFlux_IncreasesWithIncreasingSAV + + @Test + subroutine PropagatingFlux_IncreasesWithIncreasingBeta(this) ! test that the propagating flux increases with increasing beta class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: prop_flux(4) ! result @@ -601,115 +601,69 @@ module test_FireEquations real(r8), parameter :: SAV = 50.0_r8 ! value for SAV ! hard-coded beta values real(r8), parameter :: beta(4) = [0.0_r8, 0.3_r8, 0.7_r8, 1.0_r8] - + do i = 1, size(beta) - prop_flux(i) = PropagatingFlux(beta(i), SAV) + prop_flux(i) = PropagatingFlux(beta(i), SAV) end do - + do i = 1, size(beta) - 1 - ! check that function outputs increases as beta increases - @assertLessThan(prop_flux(i), prop_flux(i+1)) + ! check that function outputs increases as beta increases + @assertLessThan(prop_flux(i), prop_flux(i+1)) end do - - end subroutine PropagatingFlux_IncreasesWithIncreasingBeta - - @Test - subroutine ForwardRateOfSpread_ZeroBD_ReturnsZero(this) - ! test that if the bulk density is zero or close to zero, the function returns zero - class(TestFireEquations), intent(inout) :: this ! test object - real(r8) :: ros ! result - real(r8), parameter :: eps = 0.35_r8 ! value for effective heating number - real(r8), parameter :: q_ig = 1200.0_r8 ! value for heat of preignition - real(r8), parameter :: i_r = 5000.0_r8 ! value for reaction intensity - real(r8), parameter :: xi = 0.3_r8 ! value for propagating flux - real(r8), parameter :: phi_wind = 1.0_r8 ! value for wind factor - - ! first test 0.0 - ros = ForwardRateOfSpread(0.0_r8, eps, q_ig, i_r, xi, phi_wind) - @assertEqual(ros, 0.0_r8) - - ! now test close to zero - ros = ForwardRateOfSpread(1.0e-31_r8, eps, q_ig, i_r, xi, phi_wind) - @assertEqual(ros, 0.0_r8) - - end subroutine ForwardRateOfSpread_ZeroBD_ReturnsZero - - @Test - subroutine ForwardRateOfSpread_ZeroEps_ReturnsZero(this) - ! test that if the effective heating number is zero or close to zero, the function returns zero - class(TestFireEquations), intent(inout) :: this ! test object - real(r8) :: ros ! result - real(r8), parameter :: bd = 0.5_r8 ! value for bulk density - real(r8), parameter :: q_ig = 1200.0_r8 ! value for heat of preignition - real(r8), parameter :: i_r = 5000.0_r8 ! value for reaction intensity - real(r8), parameter :: xi = 0.3_r8 ! value for propagating flux - real(r8), parameter :: phi_wind = 1.0_r8 ! value for wind factor - - ! first test 0.0 - ros = ForwardRateOfSpread(bd, 0.0_r8, q_ig, i_r, xi, phi_wind) - @assertEqual(ros, 0.0_r8) - - ! now test close to zero - ros = ForwardRateOfSpread(bd, 1.0e-31_r8, q_ig, i_r, xi, phi_wind) - @assertEqual(ros, 0.0_r8) - - end subroutine ForwardRateOfSpread_ZeroEps_ReturnsZero - - @Test - subroutine ForwardRateOfSpread_ZeroQig_ReturnsZero(this) - ! test that if the heat of preiginition is zero or close to zero, the function returns zero + + end subroutine PropagatingFlux_IncreasesWithIncreasingBeta + + @Test + subroutine ForwardRateOfSpread_ZeroHS_ReturnsZero(this) + ! test that if the heat sink is zero or close to zero, the function returns zero class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: ros ! result - real(r8), parameter :: bd = 0.5_r8 ! value for bulk density - real(r8), parameter :: eps = 0.35_r8 ! value for effective heating number + real(r8), parameter :: heat_sink_zero = 0.0_r8 ! value for heat required to ignite fuels + real(r8), parameter :: heat_sink_nz = 1.0e-31_r8 ! value for heat required to ignite fuels real(r8), parameter :: i_r = 5000.0_r8 ! value for reaction intensity real(r8), parameter :: xi = 0.3_r8 ! value for propagating flux real(r8), parameter :: phi_wind = 1.0_r8 ! value for wind factor - + ! first test 0.0 - ros = ForwardRateOfSpread(bd, eps, 0.0_r8, i_r, xi, phi_wind) + ros = ForwardRateOfSpread(heat_sink_zero, i_r, xi, phi_wind) @assertEqual(ros, 0.0_r8) - + ! now test close to zero - ros = ForwardRateOfSpread(bd, eps, 1.0e-31_r8, i_r, xi, phi_wind) + ros = ForwardRateOfSpread(heat_sink_nz, i_r, xi, phi_wind) @assertEqual(ros, 0.0_r8) - - end subroutine ForwardRateOfSpread_ZeroQig_ReturnsZero - - @Test - subroutine ForwardRateOfSpread_ZeroIr_ReturnsZero(this) + + end subroutine ForwardRateOfSpread_ZeroHS_ReturnsZero + + @Test + subroutine ForwardRateOfSpread_ZeroIr_ReturnsZero(this) ! test that if the reaction intensity is zero, the function returns zero class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: ros ! result - real(r8), parameter :: bd = 0.5_r8 ! value for bulk density - real(r8), parameter :: eps = 0.35_r8 ! value for effective heating number - real(r8), parameter :: q_ig = 1200.0_r8 ! value for heat of preignition + real(r8), parameter :: heat_sink = 1200.0_r8 ! value for heat sink real(r8), parameter :: xi = 0.3_r8 ! value for propagating flux real(r8), parameter :: phi_wind = 1.0_r8 ! value for wind factor - ros = ForwardRateOfSpread(bd, eps, q_ig, 0.0_r8, xi, phi_wind) + ros = ForwardRateOfSpread(heat_sink, 0.0_r8, xi, phi_wind) @assertEqual(ros, 0.0_r8) - - end subroutine ForwardRateOfSpread_ZeroIr_ReturnsZero - - @Test - subroutine ForwardRateOfSpread_ZeroPropFlux_ReturnsZero(this) + + end subroutine ForwardRateOfSpread_ZeroIr_ReturnsZero + + @Test + subroutine ForwardRateOfSpread_ZeroPropFlux_ReturnsZero(this) ! test that if the propagating flux is zero, the function returns zero class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: ros ! result - real(r8), parameter :: bd = 0.5_r8 ! value for bulk density - real(r8), parameter :: eps = 0.35_r8 ! value for effective heating number - real(r8), parameter :: q_ig = 1200.0_r8 ! value for heat of preignition + real(r8), parameter :: heat_sink = 1200.0_r8 ! value for heat sink real(r8), parameter :: i_r = 5000.0_r8 ! value for reaction intensity real(r8), parameter :: phi_wind = 1.0_r8 ! value for wind factor - ros = ForwardRateOfSpread(bd, eps, q_ig, i_r, 0.0_r8, phi_wind) + ros = ForwardRateOfSpread(heat_sink, i_r, 0.0_r8, phi_wind) @assertEqual(ros, 0.0_r8) - - end subroutine ForwardRateOfSpread_ZeroPropFlux_ReturnsZero - - @Test - subroutine BackwardsRateofSpread_ZeroWind_ReturnsForwardRateofSpread(this) + + end subroutine ForwardRateOfSpread_ZeroPropFlux_ReturnsZero + + @Test + subroutine BackwardsRateofSpread_ZeroWind_ReturnsForwardRateofSpread(this) ! test that if the wind speed is zero, the backwards ros == forwards ros class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: ros_back ! result @@ -717,11 +671,11 @@ module test_FireEquations ros_back = BackwardRateOfSpread(ros_front, 0.0_r8) @assertEqual(ros_back, ros_front) - - end subroutine BackwardsRateofSpread_ZeroWind_ReturnsForwardRateofSpread - - @Test - subroutine BackwardsRateofSpread_ZeroROS_ReturnsZero(this) + + end subroutine BackwardsRateofSpread_ZeroWind_ReturnsForwardRateofSpread + + @Test + subroutine BackwardsRateofSpread_ZeroROS_ReturnsZero(this) ! test that if the forward ros is zero, the backwards ros is also zero class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: ros_back ! result @@ -729,54 +683,54 @@ module test_FireEquations ros_back = BackwardRateOfSpread(0.0_r8, wind) @assertEqual(ros_back, 0.0_r8) - - end subroutine BackwardsRateofSpread_ZeroROS_ReturnsZero - - @Test - subroutine FireDuration_ZeroFDI_ReturnsOne(this) + + end subroutine BackwardsRateofSpread_ZeroROS_ReturnsZero + + @Test + subroutine FireDuration_ZeroFDI_ReturnsOne(this) ! test that if FDI is zero, FireDuration returns 1.0 class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: fd ! result - + fd = FireDuration(0.0_r8) @assertEqual(fd, 1.0_r8) - - end subroutine FireDuration_ZeroFDI_ReturnsOne - - @Test - subroutine FireDuration_IncreasesWithIncreasingFDI(this) + + end subroutine FireDuration_ZeroFDI_ReturnsOne + + @Test + subroutine FireDuration_IncreasesWithIncreasingFDI(this) ! test that fire duration increases with increasing FDI class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: fd(4) ! result integer :: i ! looping index ! hard-coded FDI values real(r8), parameter :: FDI(4) = [0.1_r8, 0.25_r8, 0.75_r8, 1.0_r8] - + do i = 1, size(FDI) - fd(i) = FireDuration(FDI(i)) + fd(i) = FireDuration(FDI(i)) end do - + do i = 1, size(FDI) - 1 - ! check that function outputs increases as FDI increases - @assertLessThan(fd(i), fd(i+1), tolerance=high_tol) + ! check that function outputs increases as FDI increases + @assertLessThan(fd(i), fd(i+1), tolerance=high_tol) end do - - end subroutine FireDuration_IncreasesWithIncreasingFDI - - @Test - subroutine LengthToBreadth_ZeroWind_ReturnsOne(this) + + end subroutine FireDuration_IncreasesWithIncreasingFDI + + @Test + subroutine LengthToBreadth_ZeroWind_ReturnsOne(this) ! test that if effective windspeed is zero, the function returns one class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: ltb ! result real(r8), parameter :: tree_fraction = 0.75_r8 ! value for tree fraction - + ltb = LengthToBreadth(0.0_r8, tree_fraction) @assertEqual(ltb, 1.0_r8) - - end subroutine LengthToBreadth_ZeroWind_ReturnsOne - - @Test - subroutine LengthToBreadth_IncreasesWithIncreasingWind_Forest(this) + + end subroutine LengthToBreadth_ZeroWind_ReturnsOne + + @Test + subroutine LengthToBreadth_IncreasesWithIncreasingWind_Forest(this) ! test that the length to breadth ratio increases with increasing wind speed in forested patches class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: ltb(4) ! result @@ -784,22 +738,22 @@ module test_FireEquations real(r8), parameter :: tree_fraction = 0.75_r8 ! value for tree fraction ! hard-coded wind values real(r8), parameter :: wind(4) = [1.1_r8, 10.0_r8, 100.0_r8, 500.0_r8] - + do i = 1, size(wind) - ltb(i) = LengthToBreadth(wind(i), tree_fraction) - ! make sure greater than 1.0 - @assertGreaterThan(ltb(i), 1.0_r8, tolerance=high_tol) + ltb(i) = LengthToBreadth(wind(i), tree_fraction) + ! make sure greater than 1.0 + @assertGreaterThan(ltb(i), 1.0_r8, tolerance=high_tol) end do - + do i = 1, size(wind) - 1 - ! check that function outputs increases as wind speed increases - @assertLessThan(ltb(i), ltb(i+1), tolerance=high_tol) + ! check that function outputs increases as wind speed increases + @assertLessThan(ltb(i), ltb(i+1), tolerance=high_tol) end do - - end subroutine LengthToBreadth_IncreasesWithIncreasingWind_Forest - - @Test - subroutine LengthToBreadth_IncreasesWithIncreasingWind_Grassland(this) + + end subroutine LengthToBreadth_IncreasesWithIncreasingWind_Forest + + @Test + subroutine LengthToBreadth_IncreasesWithIncreasingWind_Grassland(this) ! test that the length to breadth ratio increases with increasing wind speed in grassland patches class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: ltb(4) ! result @@ -807,344 +761,344 @@ module test_FireEquations real(r8), parameter :: tree_fraction = 0.0_r8 ! value for tree fraction ! hard-coded wind values real(r8), parameter :: wind(4) = [1.1_r8, 10.0_r8, 100.0_r8, 500.0_r8] - + do i = 1, size(wind) - ltb(i) = LengthToBreadth(wind(i), tree_fraction) - ! make sure greater than 1.0 - @assertGreaterThan(ltb(i), 1.0_r8, tolerance=high_tol) + ltb(i) = LengthToBreadth(wind(i), tree_fraction) + ! make sure greater than 1.0 + @assertGreaterThan(ltb(i), 1.0_r8, tolerance=high_tol) end do - + do i = 1, size(wind) - 1 - ! check that function outputs increases as wind speed increases - @assertLessThan(ltb(i), ltb(i+1), tolerance=high_tol) + ! check that function outputs increases as wind speed increases + @assertLessThan(ltb(i), ltb(i+1), tolerance=high_tol) end do - - end subroutine LengthToBreadth_IncreasesWithIncreasingWind_Grassland - - @Test - subroutine LengthToBreadth_UsesCorrectTreeVsGrassEquations(this) + + end subroutine LengthToBreadth_IncreasesWithIncreasingWind_Grassland + + @Test + subroutine LengthToBreadth_UsesCorrectTreeVsGrassEquations(this) ! test that the function uses the correct equation depending on the tree_fraction class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: ltb ! result real(r8), parameter :: wind = 200.0_r8 ! value for wind speed real(r8), parameter :: expected_grass_ltb = 3.4844 ! expected value for grassland patches real(r8), parameter :: expected_forest_ltb = 1.6628 ! expected value for forested patches - + ! test low tree fraction ltb = LengthToBreadth(wind, 0.0_r8) @assertEqual(ltb, expected_grass_ltb, tolerance=1e-4) - + ! test high tree fraction ltb = LengthToBreadth(wind, 0.99_r8) @assertEqual(ltb, expected_forest_ltb, tolerance=1e-4) - + ! test tree fraction exactly at threshold ! should be grassland ltb = LengthToBreadth(wind, 0.55_r8) @assertEqual(ltb, expected_grass_ltb, tolerance=1e-4) - - end subroutine LengthToBreadth_UsesCorrectTreeVsGrassEquations - - @Test - subroutine FireSize_ZeroLtB_ReturnsZero(this) + + end subroutine LengthToBreadth_UsesCorrectTreeVsGrassEquations + + @Test + subroutine FireSize_ZeroLtB_ReturnsZero(this) ! test that when the length_to_breadth ratio is zero or near zero, the function returns zero class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: fire_size ! result real(r8), parameter :: ros_back = 5.0_r8 ! value backwards ros real(r8), parameter :: ros_forward = 10.0_r8 ! value for forward ros real(r8), parameter :: fire_duration = 8.0_r8 ! value for fire duration - + ! first test 0.0 fire_size = FireSize(0.0_r8, ros_back, ros_forward, fire_duration) @assertEqual(fire_size, 0.0_r8) - + ! now test close to zero fire_size = FireSize(1.0e-31_r8, ros_back, ros_forward, fire_duration) @assertEqual(fire_size, 0.0_r8) - - end subroutine FireSize_ZeroLtB_ReturnsZero - - @Test - subroutine FireSize_ZeroROS_ReturnsZero(this) + + end subroutine FireSize_ZeroLtB_ReturnsZero + + @Test + subroutine FireSize_ZeroROS_ReturnsZero(this) ! test that when the rates of spread are zero, the function returns zero class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: fire_size ! result real(r8), parameter :: fire_duration = 8.0_r8 ! value for fire duration real(r8), parameter :: length_to_breadth = 2.0_r8 ! value for fire duration - + fire_size = FireSize(length_to_breadth, 0.0_r8, 0.0_r8, fire_duration) @assertEqual(fire_size, 0.0_r8) - end subroutine FireSize_ZeroROS_ReturnsZero - - @Test - subroutine ScorchHeight_FIZero_ReturnsZero(this) + end subroutine FireSize_ZeroROS_ReturnsZero + + @Test + subroutine ScorchHeight_FIZero_ReturnsZero(this) ! test that if fire intensity is zero, scorch height is zero class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: SH ! sorch height [m] real(r8), parameter :: alpha_SH = 0.5_r8 ! input alpha_SH parameter real(r8), parameter :: FI = 0.0_r8 ! input fire intensity [kW/m] - + SH = ScorchHeight(alpha_SH, FI) @assertEqual(SH, 0.0_r8) - - end subroutine ScorchHeight_FIZero_ReturnsZero - - @Test - subroutine ScorchHeight_AlphaZero_ReturnsZero(this) + + end subroutine ScorchHeight_FIZero_ReturnsZero + + @Test + subroutine ScorchHeight_AlphaZero_ReturnsZero(this) ! test that if the alpha parameter is zero, scorch height is zero class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: SH ! sorch height [m] real(r8), parameter :: alpha_SH = 0.0_r8 ! input alpha_SH parameter real(r8), parameter :: FI = 1000.0_r8 ! input fire intensity [kW/m] - + SH = ScorchHeight(alpha_SH, FI) @assertEqual(SH, 0.0_r8) - - end subroutine ScorchHeight_AlphaZero_ReturnsZero - - @Test - subroutine ScorchHeight_FINegative_ReturnsZero(this) + + end subroutine ScorchHeight_AlphaZero_ReturnsZero + + @Test + subroutine ScorchHeight_FINegative_ReturnsZero(this) ! test that if fire intensity is negative, scorch height is zero class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: SH ! sorch height [m] real(r8), parameter :: alpha_SH = 0.5_r8 ! input alpha_SH parameter real(r8), parameter :: FI = -1000.0_r8 ! input fire intensity [kW/m] - + SH = ScorchHeight(alpha_SH, FI) @assertEqual(SH, 0.0_r8) - - end subroutine ScorchHeight_FINegative_ReturnsZero - - @Test - subroutine CrownFractionBurnt_BasicInputs_CapsAtOne(this) + + end subroutine ScorchHeight_FINegative_ReturnsZero + + @Test + subroutine CrownFractionBurnt_BasicInputs_CapsAtOne(this) ! test that the function correctly caps crown fraction burnt at 1.0 class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: CF ! crown fraction burnt [0-1] real(r8), parameter :: SH = 10.0_r8 ! input scorch height [m] real(r8), parameter :: height = 4.0_r8 ! input tree height [m] real(r8), parameter :: crown_depth = 2.0_r8 ! input crown depth [m] - + CF = CrownFractionBurnt(SH, height, crown_depth) @assertEqual(CF, 1.0_r8) - - end subroutine CrownFractionBurnt_BasicInputs_CapsAtOne - - @Test - subroutine CrownFractionBurnt_CrownDepthZero_ReturnsZero(this) + + end subroutine CrownFractionBurnt_BasicInputs_CapsAtOne + + @Test + subroutine CrownFractionBurnt_CrownDepthZero_ReturnsZero(this) ! test that the function sets crown fraction to zero if the crown depth is zero class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: CF ! crown fraction burnt [0-1] real(r8), parameter :: SH = 10.0_r8 ! input scorch height [m] real(r8), parameter :: height = 4.0_r8 ! input tree height [m] real(r8), parameter :: crown_depth = 0.0_r8 ! input crown depth [m] - + CF = CrownFractionBurnt(SH, height, crown_depth) @assertEqual(CF, 0.0_r8) - - end subroutine CrownFractionBurnt_CrownDepthZero_ReturnsZero - - @Test - subroutine CrownFractionBurnt_ScorchHeightBelowCrownHeight_ReturnsZero(this) + + end subroutine CrownFractionBurnt_CrownDepthZero_ReturnsZero + + @Test + subroutine CrownFractionBurnt_ScorchHeightBelowCrownHeight_ReturnsZero(this) ! test that the function sets crown fraction to zero if the scorch height is below crown height class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: CF ! crown fraction burnt [0-1] real(r8), parameter :: SH = 2.0_r8 ! input scorch height [m] real(r8), parameter :: height = 4.0_r8 ! input tree height [m] real(r8), parameter :: crown_depth = 2.0_r8 ! input crown depth [m] - + CF = CrownFractionBurnt(SH, height, crown_depth) @assertEqual(CF, 0.0_r8) - - end subroutine CrownFractionBurnt_ScorchHeightBelowCrownHeight_ReturnsZero - - @Test - subroutine CrownFractionBurnt_ScorchHeightLow_ReturnsLessThanOne(this) + + end subroutine CrownFractionBurnt_ScorchHeightBelowCrownHeight_ReturnsZero + + @Test + subroutine CrownFractionBurnt_ScorchHeightLow_ReturnsLessThanOne(this) ! test that the function correctly calculates crownfraction burnt for SH below tree height but within the crown class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: CF ! crown fraction burnt [0-1] real(r8), parameter :: SH = 3.0_r8 ! input scorch height [m] real(r8), parameter :: height = 4.0_r8 ! input tree height [m] real(r8), parameter :: crown_depth = 2.0_r8 ! input crown depth [m] - + CF = CrownFractionBurnt(SH, height, crown_depth) @assertGreaterThanOrEqual(CF, 0.0_r8) @assertLessThanOrEqual(CF, 1.0_r8) - - end subroutine CrownFractionBurnt_ScorchHeightLow_ReturnsLessThanOne - - @Test - subroutine BarkThickness_NegativeBT_Errors(this) + + end subroutine CrownFractionBurnt_ScorchHeightLow_ReturnsLessThanOne + + @Test + subroutine BarkThickness_NegativeBT_Errors(this) ! test that if the bark thickness is negative, the function errors class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: BT ! bark thickness [cm] real(r8), parameter :: bark_scalar = 0.01_r8 ! input bark scalar parameter real(r8), parameter :: dbh = -10.0_r8 ! diameter at breast height [cm] character(len=:), allocatable :: expected_msg ! expected error message for failure - + expected_msg = endrun_msg("bark thickness is negative") - + BT = BarkThickness(bark_scalar, dbh) @assertExceptionRaised(expected_msg) - - end subroutine BarkThickness_NegativeBT_Errors - - @Test - subroutine CambialMortality_TauRGreaterThanTwo_ReturnsOne(this) + + end subroutine BarkThickness_NegativeBT_Errors + + @Test + subroutine CambialMortality_TauRGreaterThanTwo_ReturnsOne(this) ! test that the function returns 1.0 if tau_r >= 2.0 class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: CM ! cambial mortality [0-1] real(r8), parameter :: bark_scalar = 0.01_r8 ! input bark scalar parameter real(r8), parameter :: dbh = 10.0_r8 ! input tree diameter at breast height [cm] real(r8), parameter :: tau_l = 5.0_r8 ! input fire residence time [min] - + CM = CambialMortality(bark_scalar, dbh, tau_l) @assertEqual(CM, 1.0_r8) - - end subroutine CambialMortality_TauRGreaterThanTwo_ReturnsOne - - @Test - subroutine CambialMortality_TaulZero_ReturnsZero(this) + + end subroutine CambialMortality_TauRGreaterThanTwo_ReturnsOne + + @Test + subroutine CambialMortality_TaulZero_ReturnsZero(this) ! test that the function returns 0.0 if tau_l is zero class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: CM ! cambial mortality [0-1] real(r8), parameter :: bark_scalar = 0.1_r8 ! input bark scalar parameter real(r8), parameter :: dbh = 10.0_r8 ! input tree diameter at breast height [cm] real(r8), parameter :: tau_l = 0.0_r8 ! input fire residence time [min] - + CM = CambialMortality(bark_scalar, dbh, tau_l) @assertEqual(CM, 0.0_r8) - - end subroutine CambialMortality_TaulZero_ReturnsZero - - @Test - subroutine CrownFireMortality_ZeroFractionBurned_ReturnsZero(this) + + end subroutine CambialMortality_TaulZero_ReturnsZero + + @Test + subroutine CrownFireMortality_ZeroFractionBurned_ReturnsZero(this) ! test that the function returns 0.0 if fraction_crown_burned is 0.0 class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: CM ! crown fire mortality [0-1] real(r8), parameter :: crown_kill = 0.1_r8 ! input crown kill parameter real(r8), parameter :: fraction_crown_burned = 0.0 ! input fraction burned [0-1] - + CM = CrownFireMortality(crown_kill, fraction_crown_burned) @assertEqual(CM, 0.0_r8) - - end subroutine CrownFireMortality_ZeroFractionBurned_ReturnsZero - - @Test - subroutine CrownFireMortality_FractionBurnedOne_ReturnsCrownKill(this) + + end subroutine CrownFireMortality_ZeroFractionBurned_ReturnsZero + + @Test + subroutine CrownFireMortality_FractionBurnedOne_ReturnsCrownKill(this) ! test that the function returns crown_kill if fraction_crown_burned is 1.0 class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: CM ! crown fire mortality [0-1] real(r8), parameter :: crown_kill = 0.1_r8 ! input crown kill parameter real(r8), parameter :: fraction_crown_burned = 1.0 ! input fraction burned [0-1] - + CM = CrownFireMortality(crown_kill, fraction_crown_burned) @assertEqual(CM, crown_kill) - - end subroutine CrownFireMortality_FractionBurnedOne_ReturnsCrownKill - - @Test - subroutine CrownFireMortality_HighCrownKill_ReturnsOne(this) + + end subroutine CrownFireMortality_FractionBurnedOne_ReturnsCrownKill + + @Test + subroutine CrownFireMortality_HighCrownKill_ReturnsOne(this) ! test that the function returns 1.0 even if crown_kill is very high class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: CM ! crown fire mortality [0-1] real(r8), parameter :: crown_kill = 10.0_r8 ! input crown kill parameter real(r8), parameter :: fraction_crown_burned = 0.5_r8 ! input fraction burned [0-1] - + CM = CrownFireMortality(crown_kill, fraction_crown_burned) @assertEqual(CM, 1.0_r8) - - end subroutine CrownFireMortality_HighCrownKill_ReturnsOne - - @Test - subroutine TotalFireMortality_ReasonableValues_ReturnsReasonable(this) + + end subroutine CrownFireMortality_HighCrownKill_ReturnsOne + + @Test + subroutine TotalFireMortality_ReasonableValues_ReturnsReasonable(this) ! test that the function returns correct values given reasonable inputs class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: TM ! total fire mortality [0-1] real(r8), parameter :: crownfire_mort = 0.4_r8 ! crown fire mortality [0-1] real(r8), parameter :: cambial_damage_mort = 0.3_r8 ! input fraction burned [0-1] - + TM = TotalFireMortality(crownfire_mort, cambial_damage_mort) @assertEqual(TM, 0.58_r8) - - end subroutine TotalFireMortality_ReasonableValues_ReturnsReasonable - - @Test - subroutine TotalFireMortality_ZeroInputs_ReturnsZero(this) + + end subroutine TotalFireMortality_ReasonableValues_ReturnsReasonable + + @Test + subroutine TotalFireMortality_ZeroInputs_ReturnsZero(this) ! test that the function returns zero if both input mortality rates are 0.0 class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: TM ! total fire mortality [0-1] real(r8), parameter :: crownfire_mort = 0.0_r8 ! crown fire mortality [0-1] real(r8), parameter :: cambial_damage_mort = 0.0_r8 ! input fraction burned [0-1] - + TM = TotalFireMortality(crownfire_mort, cambial_damage_mort) @assertEqual(TM, 0.0_r8) - - end subroutine TotalFireMortality_ZeroInputs_ReturnsZero - - @Test - subroutine TotalFireMortality_OneInputs_ReturnsOne(this) + + end subroutine TotalFireMortality_ZeroInputs_ReturnsZero + + @Test + subroutine TotalFireMortality_OneInputs_ReturnsOne(this) ! test that the function returns one if both input mortality rates are 1.0 class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: TM ! total fire mortality [0-1] real(r8), parameter :: crownfire_mort = 1.0_r8 ! crown fire mortality [0-1] real(r8), parameter :: cambial_damage_mort = 1.0_r8 ! input fraction burned [0-1] - + TM = TotalFireMortality(crownfire_mort, cambial_damage_mort) @assertEqual(TM, 1.0_r8) - - end subroutine TotalFireMortality_OneInputs_ReturnsOne - - @Test - subroutine TotalFireMortality_ZeroCrownFire_ReturnsCambial(this) + + end subroutine TotalFireMortality_OneInputs_ReturnsOne + + @Test + subroutine TotalFireMortality_ZeroCrownFire_ReturnsCambial(this) ! test that the function returns cambial_damage_mort if crownfire_mort = 0.0 class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: TM ! total fire mortality [0-1] real(r8), parameter :: crownfire_mort = 0.0_r8 ! crown fire mortality [0-1] real(r8), parameter :: cambial_damage_mort = 0.3_r8 ! input fraction burned [0-1] - + TM = TotalFireMortality(crownfire_mort, cambial_damage_mort) @assertEqual(TM, cambial_damage_mort) - - end subroutine TotalFireMortality_ZeroCrownFire_ReturnsCambial - - @Test - subroutine TotalFireMortality_ZeroCambial_ReturnsCrownFire(this) + + end subroutine TotalFireMortality_ZeroCrownFire_ReturnsCambial + + @Test + subroutine TotalFireMortality_ZeroCambial_ReturnsCrownFire(this) ! test that the function returns crownfire_mort if cambial_damage_mort = 0.0 class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: TM ! total fire mortality [0-1] real(r8), parameter :: crownfire_mort = 0.4_r8 ! crown fire mortality [0-1] real(r8), parameter :: cambial_damage_mort = 0.0_r8 ! input fraction burned [0-1] - + TM = TotalFireMortality(crownfire_mort, cambial_damage_mort) @assertEqual(TM, crownfire_mort) - - end subroutine TotalFireMortality_ZeroCambial_ReturnsCrownFire - - @Test - subroutine TotalFireMortality_OverOneMort_ReturnsOne(this) + + end subroutine TotalFireMortality_ZeroCambial_ReturnsCrownFire + + @Test + subroutine TotalFireMortality_OverOneMort_ReturnsOne(this) ! test that the function correctly caps mortality rate at 1.0 class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: TM ! total fire mortality [0-1] real(r8), parameter :: crownfire_mort = 1.4_r8 ! crown fire mortality [0-1] real(r8), parameter :: cambial_damage_mort = 1.4_r8 ! input fraction burned [0-1] - + TM = TotalFireMortality(crownfire_mort, cambial_damage_mort) @assertEqual(TM, 1.0_r8) - - end subroutine TotalFireMortality_OverOneMort_ReturnsOne - - @Test - subroutine TotalFireMortality_NegativeMortality_ReturnsZero(this) + + end subroutine TotalFireMortality_OverOneMort_ReturnsOne + + @Test + subroutine TotalFireMortality_NegativeMortality_ReturnsZero(this) ! test that the function correctly gives zero if somehow mortality rates are negative class(TestFireEquations), intent(inout) :: this ! test object real(r8) :: TM ! total fire mortality [0-1] real(r8), parameter :: crownfire_mort = -1.4_r8 ! input crown kill parameter real(r8), parameter :: cambial_damage_mort = -1.4_r8 ! input fraction burned [0-1] - + TM = TotalFireMortality(crownfire_mort, cambial_damage_mort) @assertEqual(TM, 0.0_r8) - - end subroutine TotalFireMortality_NegativeMortality_ReturnsZero - + + end subroutine TotalFireMortality_NegativeMortality_ReturnsZero + end module test_FireEquations diff --git a/testing/unit_testing/fire_fuel_test/test_FireFuel.pf b/testing/unit_testing/fire_fuel_test/test_FireFuel.pf index d327e92bfb..6131d8e5d0 100644 --- a/testing/unit_testing/fire_fuel_test/test_FireFuel.pf +++ b/testing/unit_testing/fire_fuel_test/test_FireFuel.pf @@ -53,7 +53,7 @@ contains subroutine SumLoading_CorrectValues(this) ! test that the fuel is summed correctly (and ignores trunks) class(TestFireFuel), intent(inout) :: this ! fuel test object - real(r8) :: sav = (/13.0_r8, 3.58_r8, 0.98_r8, 0.2_r8, 66.0_r8, 66.0_r8 /) + real(r8), dimension(6) :: sav = (/13.0_r8, 3.58_r8, 0.98_r8, 0.2_r8, 66.0_r8, 66.0_r8 /) real(r8) :: part_dens = 513_r8 real(r8) :: dummy_litter = 5.0_r8 ! dummy litter value [kgC/m2] real(r8) :: trunk_litter = 100.0_r8 ! trunk branch litter [kgC/m2] @@ -74,7 +74,7 @@ contains subroutine CalculateFractionalLoading_CorrectValues(this) ! test that the fractional loading is calculated correctly (and ignores trunks) class(TestFireFuel), intent(inout) :: this ! fuel test object - real(r8) :: sav = (/13.0_r8, 3.58_r8, 0.98_r8, 0.2_r8, 66.0_r8, 66.0_r8 /) + real(r8), dimension(6) :: sav = (/13.0_r8, 3.58_r8, 0.98_r8, 0.2_r8, 66.0_r8, 66.0_r8 /) real(r8) :: part_dens = 513_r8 real(r8) :: dummy_litter = 5.0_r8 ! dummy litter value [kgC/m2] real(r8) :: trunk_litter = 100.0_r8 ! trunk branch litter [kgC/m2] From 90f9485dd6575a942ef9b47b9c252ba019613810 Mon Sep 17 00:00:00 2001 From: Xiulin Gao Date: Sun, 19 Oct 2025 21:02:49 -0700 Subject: [PATCH 10/23] args pass --- testing/functional_testing/fire/fuel/FatesTestFuel.F90 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/testing/functional_testing/fire/fuel/FatesTestFuel.F90 b/testing/functional_testing/fire/fuel/FatesTestFuel.F90 index b557f7e4c9..0975ebc4f5 100644 --- a/testing/functional_testing/fire/fuel/FatesTestFuel.F90 +++ b/testing/functional_testing/fire/fuel/FatesTestFuel.F90 @@ -97,9 +97,9 @@ program FatesTestFuel call SetUpFuel(fuel(f), fuel_models_array, fuel_models(f), fuel_names(f), carriers(f)) ! sum up fuel and calculate loading - call fuel%CalculateWeightingFactor(SF_val_SAV, SF_val_part_dens) - call fuel(f)%SumLoading() - call fuel(f)%CalculateFractionalLoading() + call fuel(f)%CalculateWeightingFactor(SF_val_SAV, SF_val_part_dens) + call fuel(f)%SumLoading(SF_val_SAV, SF_val_part_dens) + call fuel(f)%CalculateFractionalLoading(SF_val_SAV, SF_val_part_dens) ! calculate geometric properties call fuel(f)%AverageBulkDensity(SF_val_FBD) From 349cc9b49b348c6de55259b6c6942bac4b5873ce Mon Sep 17 00:00:00 2001 From: Xiulin Gao Date: Sun, 19 Oct 2025 21:37:15 -0700 Subject: [PATCH 11/23] fix live fuel load zero error by switching to different fuel models --- .../fire/fuel/FatesTestFuel.F90 | 2 +- .../functional_testing/fire/fuel/fuel_test.py | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/testing/functional_testing/fire/fuel/FatesTestFuel.F90 b/testing/functional_testing/fire/fuel/FatesTestFuel.F90 index 0975ebc4f5..79138c79ac 100644 --- a/testing/functional_testing/fire/fuel/FatesTestFuel.F90 +++ b/testing/functional_testing/fire/fuel/FatesTestFuel.F90 @@ -48,7 +48,7 @@ program FatesTestFuel character(len=*), parameter :: out_file = 'fuel_out.nc' ! output file ! fuel models to test - integer, parameter, dimension(5) :: fuel_models = (/102, 183, 164, 104, 163/) + integer, parameter, dimension(4) :: fuel_models = (/102, 121, 104, 149/) ! number of fuel models to test num_fuel_models = size(fuel_models) diff --git a/testing/functional_testing/fire/fuel/fuel_test.py b/testing/functional_testing/fire/fuel/fuel_test.py index 09bacd7db4..bf84cc6951 100644 --- a/testing/functional_testing/fire/fuel/fuel_test.py +++ b/testing/functional_testing/fire/fuel/fuel_test.py @@ -185,6 +185,25 @@ def plot_NI_dat(fuel_dat: xr.Dataset, save_figs: bool, plot_dir: str): fig_name = os.path.join(plot_dir, "Nesterov_plot.png") plt.savefig(fig_name) + @staticmethod + def plot_moisture_dead_dat(fuel_dat: xr.Dataset, save_figs: bool, plot_dir: str): + """Plot output for live fuel moisture + + Args: + fuel_dat (Xarray Dataset): output fuel data + save_figs (bool): whether or not to save the figures + plot_dir (str): plot directory + """ + + plt.figure() + fuel_dat.fuel_moisture_dead.plot(hue="fuel_model") + plt.xlabel("Time", fontsize=11) + plt.ylabel("Dead fuel Moisture", fontsize=11) + + if save_figs: + fig_name = os.path.join(plot_dir, "fuel_moisture_dead_plot.png") + plt.savefig(fig_name) + @staticmethod def plot_moisture_live_dat(fuel_dat: xr.Dataset, save_figs: bool, plot_dir: str): """Plot output for fuel moisture From 1cef0857c0879f9a9687ecc373995eda95844e02 Mon Sep 17 00:00:00 2001 From: Xiulin Gao Date: Sun, 19 Oct 2025 21:51:12 -0700 Subject: [PATCH 12/23] not plotting dead and live total loading by litter class --- testing/functional_testing/fire/fuel/fuel_test.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/testing/functional_testing/fire/fuel/fuel_test.py b/testing/functional_testing/fire/fuel/fuel_test.py index bf84cc6951..f3da6174c1 100644 --- a/testing/functional_testing/fire/fuel/fuel_test.py +++ b/testing/functional_testing/fire/fuel/fuel_test.py @@ -55,6 +55,7 @@ def plot_output(self, run_dir: str, save_figs: bool, plot_dir: str): "kgC m$^{-2}$", save_figs, plot_dir, + by_litter_type = False, ) self.plot_barchart( fuel_dat, @@ -63,6 +64,7 @@ def plot_output(self, run_dir: str, save_figs: bool, plot_dir: str): "kgC m$^{-2}$", save_figs, plot_dir, + by_litter_type=False, ) self.plot_barchart( fuel_dat, From 46ee9d4142f70d768ee93fe155f5b688ea7ab034 Mon Sep 17 00:00:00 2001 From: Xiulin Gao Date: Sat, 25 Oct 2025 17:04:39 -0700 Subject: [PATCH 13/23] fix arg pass when call --- fire/FatesFuelMod.F90 | 40 ++++++++++++++++++++++++++++++---------- fire/SFMainMod.F90 | 4 ++-- 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/fire/FatesFuelMod.F90 b/fire/FatesFuelMod.F90 index b6187123cf..e4a08a539d 100644 --- a/fire/FatesFuelMod.F90 +++ b/fire/FatesFuelMod.F90 @@ -199,9 +199,17 @@ subroutine CalculateWeightingFactor(this, sav_fuel, part_dens) ! calculate weighting factor, EQ. 56 in Rothermel 1972 do i = 1, num_fuel_classes if(i /= fuel_classes%live_grass()) then - this%weighting_factor(i) = this%mean_total_SA(i)/A_dead + if(A_dead > nearzero)then + this%weighting_factor(i) = this%mean_total_SA(i)/A_dead + else + this%weighting_factor(i) = 0.0_r8 + end if else - this%weighting_factor(i) = this%mean_total_SA(i)/A_live + if(A_live > nearzero)then + this%weighting_factor(i) = this%mean_total_SA(i)/A_live + else + this%weighting_factor(i) = 0.0_r8 + end if end if end do @@ -481,7 +489,8 @@ subroutine LiveFuelMoistureOfExtinction(fuel_load, sav_val, fmc, mef_dead, mef_l real(r8) :: w_n, md_n ! nominator for calculating W and moist_dead real(r8) :: w_d, md_d ! denominator for calculating W and moist_dead - integer :: i ! looping index + integer :: i ! looping index + real(r8), parameter :: kgm2_to_lbft2 = 0.0248_r8 ! convert kg m-2 to lb ft-2 w_n = 0.0_r8 md_n = 0.0_r8 @@ -489,17 +498,28 @@ subroutine LiveFuelMoistureOfExtinction(fuel_load, sav_val, fmc, mef_dead, mef_l md_d = 0.0_r8 do i = 1, num_fuel_classes if(i /= fuel_classes%live_grass())then - w_n = w_n + fuel_load(i)*exp(-4.5276_r8/sav_val(i)) - md_n = md_n + fmc(i)*fuel_load(i)*exp(-4.5276_r8/sav_val(i)) - md_d = md_d + fuel_load(i)*exp(-4.5264_r8/sav_val(i)) + w_n = w_n + kgm2_to_lbft2*fuel_load(i)*exp(-4.5276_r8/sav_val(i)) + md_n = md_n + fmc(i)*kgm2_to_lbft2*fuel_load(i)*exp(-4.5276_r8/sav_val(i)) + md_d = md_d + kgm2_to_lbft2*fuel_load(i)*exp(-4.5264_r8/sav_val(i)) else - w_d = w_d + fuel_load(i)*exp(-16.4042_r8/sav_val(i)) + w_d = w_d + kgm2_to_lbft2*fuel_load(i)*exp(-16.4042_r8/sav_val(i)) end if end do - W = w_n/w_d - moist_dead = md_n/md_d - mef_live = 2.9_r8 * W * (1.0_r8 - moist_dead/mef_dead) - 0.226_r8 + + if(w_d>nearzero)then + W = w_n/w_d + else + W = 0.0_r8 + end if + + if(md_d > nearzero)then + moist_dead = md_n/md_d + else + moist_dead = 0.0_r8 + end if + + mef_live = min(mef_dead, 2.9_r8 * W * (1.0_r8 - moist_dead/mef_dead) - 0.226_r8) end subroutine LiveFuelMoistureOfExtinction diff --git a/fire/SFMainMod.F90 b/fire/SFMainMod.F90 index eda9bc528d..8cde8c5a14 100644 --- a/fire/SFMainMod.F90 +++ b/fire/SFMainMod.F90 @@ -175,8 +175,8 @@ subroutine UpdateFuelCharacteristics(currentSite) call currentPatch%fuel%CalculateWeightingFactor(SF_val_SAV, SF_val_part_dens) ! sum up fuel classes and calculate fractional loading for each - call currentPatch%fuel%SumLoading() - call currentPatch%fuel%CalculateFractionalLoading() + call currentPatch%fuel%SumLoading(SF_val_SAV, SF_val_part_dens) + call currentPatch%fuel%CalculateFractionalLoading(SF_val_SAV, SF_val_part_dens) ! calculate fuel moisture [m3/m3] call currentPatch%fuel%UpdateFuelMoisture(SF_val_SAV, SF_val_drying_ratio, & From 60598a6bfad4d87a8dc62f42a30e7f20ff185956 Mon Sep 17 00:00:00 2001 From: Xiulin Gao Date: Mon, 27 Oct 2025 11:58:55 -0700 Subject: [PATCH 14/23] use SAV and other SF params locally instead of passing as args --- fire/FatesFuelMod.F90 | 24 ++++++++++-------------- fire/SFMainMod.F90 | 7 +++---- 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/fire/FatesFuelMod.F90 b/fire/FatesFuelMod.F90 index e4a08a539d..66c3093f1e 100644 --- a/fire/FatesFuelMod.F90 +++ b/fire/FatesFuelMod.F90 @@ -169,15 +169,14 @@ end subroutine UpdateLoading !------------------------------------------------------------------------------------- - subroutine CalculateWeightingFactor(this, sav_fuel, part_dens) + subroutine CalculateWeightingFactor(this) ! DESCRIPTION: ! Calculate total area per fuel cell of each fuel class ! and the derived weighting factors + use SFParamsMod, only :: SF_val_SAV, SF_val_part_dens ! ARGUMENTS: class(fuel_type), intent(inout) :: this ! fuel class - real(r8), intent(in) :: sav_fuel(num_fuel_classes) ! surface area to volume ratio of all fuel types [/cm] - real(r8), intent(in) :: part_dens ! oven-dry particle density [kg m-2] ! LOCALS: integer :: i ! looping index @@ -189,7 +188,7 @@ subroutine CalculateWeightingFactor(this, sav_fuel, part_dens) A_live = 0.0_r8 ! calculate mean total area per unit fuel cell of each size EQ 53 in Rothermel 1972 do i = 1, num_fuel_classes - this%mean_total_SA(i) = sav_fuel(i)*this%loading(i)/part_dens + this%mean_total_SA(i) = SF_val_SAV(i)*this%loading(i)/SF_val_part_dens if (i /= fuel_classes%live_grass()) then A_dead = A_dead + this%mean_total_SA(i) else @@ -220,7 +219,7 @@ end subroutine CalculateWeightingFactor !------------------------------------------------------------------------------------- - subroutine SumLoading(this, sav_fuel, part_dens) + subroutine SumLoading(this) ! DESCRIPTION: ! Sums up the loading - excludes trunks ! @@ -245,14 +244,12 @@ subroutine SumLoading(this, sav_fuel, part_dens) ! ARGUMENTS: class(fuel_type), intent(inout) :: this ! fuel class - real(r8), intent(in) :: sav_fuel(num_fuel_classes) ! surface area to volume ratio of all fuel types [/cm] - real(r8), intent(in) :: part_dens ! oven-dry particle density [kg m-2] ! LOCALS: integer :: i ! looping index ! ensure weighting factor is updated - call this%CalculateWeightingFactor(sav_fuel, part_dens) + call this%CalculateWeightingFactor() ! get fuel load weighting factor given SAV call this%FuelLoadWeight() @@ -279,20 +276,18 @@ end subroutine SumLoading !------------------------------------------------------------------------------------- - subroutine CalculateFractionalLoading(this, sav_fuel, part_dens) + subroutine CalculateFractionalLoading(this) ! DESCRIPTION: ! Calculates fractional loading for fuel ! ARGUMENTS: class(fuel_type), intent(inout) :: this ! fuel class - real(r8), intent(in) :: sav_fuel(num_fuel_classes) ! surface area to volume ratio of all fuel types [/cm] - real(r8), intent(in) :: part_dens ! oven-dry particle density [kg m-2] ! LOCALS: integer :: i ! looping index ! sum up loading just in case - call this%SumLoading(sav_fuel, part_dens) + call this%SumLoading() if (this%non_trunk_loading > nearzero) then do i = 1, num_fuel_classes @@ -348,6 +343,7 @@ subroutine UpdateFuelMoisture(this, sav_fuel, drying_ratio, fireWeatherClass) ! effective_moisture is used for determining fractional fuel burnt per fuel class later ! to derive this by fuel category (live vs dead) and by fuel sizes ! let's still keep this calculation for both dead and live fuels + ! 2025-10-16 XLG moisture_of_extinction(i) = MoistureOfExtinction(sav_fuel(i)) this%effective_moisture(i) = this%moisture(i)/moisture_of_extinction(i) if(i /= fuel_classes%live_grass())then @@ -519,7 +515,7 @@ subroutine LiveFuelMoistureOfExtinction(fuel_load, sav_val, fmc, mef_dead, mef_l moist_dead = 0.0_r8 end if - mef_live = min(mef_dead, 2.9_r8 * W * (1.0_r8 - moist_dead/mef_dead) - 0.226_r8) + mef_live = min(1.0_r8, max(mef_dead, 2.9_r8 * W * (1.0_r8 - moist_dead/mef_dead) - 0.226_r8)) end subroutine LiveFuelMoistureOfExtinction @@ -722,7 +718,7 @@ subroutine FuelLoadWeight(this) integer :: i, g ! looping indices integer :: group_idx(num_fuel_classes) ! fuel group assigned real(r8), allocatable :: group_sum(:) ! summed weight across fuel sizes that are within the same subgroup - real(r8), parameter, dimension(5) :: sav_edg=(/0.53_r8, 1.58_r8, 3.15_r8, 6.30_r8, 39.37_r8/) + real(r8), parameter, dimension(5) :: sav_edg=(/0.53_r8, 1.58_r8, 3.15_r8, 6.30_r8, 39.37_r8/) ! SAV value for grouping[cm-1] ng = size(sav_edg) ! initialize fuel group with group 1 (sav < 0.53) diff --git a/fire/SFMainMod.F90 b/fire/SFMainMod.F90 index 8cde8c5a14..f844fa9976 100644 --- a/fire/SFMainMod.F90 +++ b/fire/SFMainMod.F90 @@ -172,11 +172,11 @@ subroutine UpdateFuelCharacteristics(currentSite) litter%ag_cwd(1), litter%ag_cwd(2), litter%ag_cwd(3), litter%ag_cwd(4), & currentPatch%livegrass) ! update weighting factors - call currentPatch%fuel%CalculateWeightingFactor(SF_val_SAV, SF_val_part_dens) + call currentPatch%fuel%CalculateWeightingFactor() ! sum up fuel classes and calculate fractional loading for each - call currentPatch%fuel%SumLoading(SF_val_SAV, SF_val_part_dens) - call currentPatch%fuel%CalculateFractionalLoading(SF_val_SAV, SF_val_part_dens) + call currentPatch%fuel%SumLoading() + call currentPatch%fuel%CalculateFractionalLoading() ! calculate fuel moisture [m3/m3] call currentPatch%fuel%UpdateFuelMoisture(SF_val_SAV, SF_val_drying_ratio, & @@ -317,7 +317,6 @@ subroutine CalculateSurfaceRateOfSpread(currentSite) end if ! remove mineral content from fuel load per Thonicke 2010 - currentPatch%fuel%non_trunk_loading = currentPatch%fuel%non_trunk_loading*(1.0_r8 - SF_val_miner_total) currentPatch%fuel%weighted_loading_dead = currentPatch%fuel%weighted_loading_dead*(1.0_r8 - SF_val_miner_total) currentPatch%fuel%weighted_loading_live = currentPatch%fuel%weighted_loading_live*(1.0_r8 - SF_val_miner_total) From 86460f81b19175fa52a8963593d567e8d5f517c7 Mon Sep 17 00:00:00 2001 From: Xiulin Gao Date: Mon, 27 Oct 2025 12:02:34 -0700 Subject: [PATCH 15/23] fix arg passing issue --- fire/FatesFuelMod.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fire/FatesFuelMod.F90 b/fire/FatesFuelMod.F90 index 66c3093f1e..df3a654ee4 100644 --- a/fire/FatesFuelMod.F90 +++ b/fire/FatesFuelMod.F90 @@ -623,7 +623,7 @@ subroutine CalculateFuelBurnt(this, fuel_consumed) this%frac_burnt(:) = 1.0_r8 ! get all the weighting factor - call this%CalculateWeightingFactor(SF_val_SAV, SF_val_part_dens) + call this%CalculateWeightingFactor() call this%FuelLoadWeight() ! Calculate fraction of litter is burnt for all classes. From e331a3d4275c7b68fb57e279894790071b58e9e8 Mon Sep 17 00:00:00 2001 From: Xiulin Gao Date: Mon, 27 Oct 2025 12:03:36 -0700 Subject: [PATCH 16/23] syntax fix --- fire/FatesFuelMod.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fire/FatesFuelMod.F90 b/fire/FatesFuelMod.F90 index df3a654ee4..1a7bafcb5a 100644 --- a/fire/FatesFuelMod.F90 +++ b/fire/FatesFuelMod.F90 @@ -173,7 +173,7 @@ subroutine CalculateWeightingFactor(this) ! DESCRIPTION: ! Calculate total area per fuel cell of each fuel class ! and the derived weighting factors - use SFParamsMod, only :: SF_val_SAV, SF_val_part_dens + use SFParamsMod, only : SF_val_SAV, SF_val_part_dens ! ARGUMENTS: class(fuel_type), intent(inout) :: this ! fuel class From defe5d0270f2121d904f3b9bc75d93bf1de05cfb Mon Sep 17 00:00:00 2001 From: Xiulin Gao Date: Mon, 27 Oct 2025 12:12:59 -0700 Subject: [PATCH 17/23] fix arg passing in unit test for fuel --- testing/unit_testing/fire_fuel_test/test_FireFuel.pf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/testing/unit_testing/fire_fuel_test/test_FireFuel.pf b/testing/unit_testing/fire_fuel_test/test_FireFuel.pf index 6131d8e5d0..dfacc92920 100644 --- a/testing/unit_testing/fire_fuel_test/test_FireFuel.pf +++ b/testing/unit_testing/fire_fuel_test/test_FireFuel.pf @@ -64,7 +64,7 @@ contains call this%fuel%UpdateLoading(dummy_litter, dummy_litter, dummy_litter, & dummy_litter, trunk_litter, dummy_litter) - call this%fuel%SumLoading(sav, part_dens) + call this%fuel%SumLoading() @assertEqual(this%fuel%non_trunk_loading, non_trunk_loading, tolerance=tol) @@ -88,8 +88,8 @@ contains call this%fuel%UpdateLoading(dummy_litter, dummy_litter, dummy_litter, & dummy_litter, trunk_litter, dummy_litter) - call this%fuel%SumLoading(sav, part_dens) - call this%fuel%CalculateFractionalLoading(sav, part_dens) + call this%fuel%SumLoading() + call this%fuel%CalculateFractionalLoading() do i = 1, num_fuel_classes if (i /= fuel_classes%trunks()) then From 6d66caa2ec877a214e9434371a4aa3aa9eaf1e93 Mon Sep 17 00:00:00 2001 From: Xiulin Gao Date: Mon, 27 Oct 2025 12:16:53 -0700 Subject: [PATCH 18/23] arg passing issue again --- testing/functional_testing/fire/fuel/FatesTestFuel.F90 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/testing/functional_testing/fire/fuel/FatesTestFuel.F90 b/testing/functional_testing/fire/fuel/FatesTestFuel.F90 index 79138c79ac..79550afb50 100644 --- a/testing/functional_testing/fire/fuel/FatesTestFuel.F90 +++ b/testing/functional_testing/fire/fuel/FatesTestFuel.F90 @@ -97,9 +97,9 @@ program FatesTestFuel call SetUpFuel(fuel(f), fuel_models_array, fuel_models(f), fuel_names(f), carriers(f)) ! sum up fuel and calculate loading - call fuel(f)%CalculateWeightingFactor(SF_val_SAV, SF_val_part_dens) - call fuel(f)%SumLoading(SF_val_SAV, SF_val_part_dens) - call fuel(f)%CalculateFractionalLoading(SF_val_SAV, SF_val_part_dens) + call fuel(f)%CalculateWeightingFactor() + call fuel(f)%SumLoading() + call fuel(f)%CalculateFractionalLoading() ! calculate geometric properties call fuel(f)%AverageBulkDensity(SF_val_FBD) From 204aea4f6431523ad9ed00c643e26786a9f42d21 Mon Sep 17 00:00:00 2001 From: Xiulin Gao Date: Tue, 28 Oct 2025 09:36:20 -0700 Subject: [PATCH 19/23] remove unused parameters --- fire/FatesFuelMod.F90 | 12 ++++++------ .../functional_testing/fire/fuel/FatesTestFuel.F90 | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/fire/FatesFuelMod.F90 b/fire/FatesFuelMod.F90 index 1a7bafcb5a..35f742a4fe 100644 --- a/fire/FatesFuelMod.F90 +++ b/fire/FatesFuelMod.F90 @@ -390,9 +390,9 @@ subroutine CalculateFuelMoistureNesterov(sav_fuel, drying_ratio, NI, moisture) ! Updates fuel moisture ! ARGUMENTS: - real(r8), intent(in) :: sav_fuel(num_fuel_classes) ! surface area to volume ratio of all fuel types [/cm] - real(r8), intent(in) :: drying_ratio ! drying ratio - real(r8), intent(in) :: NI ! Nesterov Index + real(r8), intent(in) :: sav_fuel(num_fuel_classes) ! surface area to volume ratio of all fuel types [/cm] + real(r8), intent(in) :: drying_ratio ! drying ratio + real(r8), intent(in) :: NI ! Nesterov Index real(r8), intent(out) :: moisture(num_fuel_classes) ! moisture of litter [m3/m3] ! LOCALS @@ -608,15 +608,15 @@ subroutine CalculateFuelBurnt(this, fuel_consumed) use SFParamsMod, only : SF_val_mid_moisture, SF_val_mid_moisture_Coeff use SFParamsMod, only : SF_val_mid_moisture_Slope, SF_val_min_moisture use SFParamsMod, only : SF_val_low_moisture_Coeff, SF_val_low_moisture_Slope - use SFParamsMod, only : SF_val_miner_total, SF_val_SAV, SF_val_part_dens + use SFParamsMod, only : SF_val_miner_total ! ARGUMENTS: class(fuel_type), intent(inout) :: this ! fuel class real(r8), intent(out) :: fuel_consumed(num_fuel_classes) ! fuel consumed [kgC/m2] ! LOCALS: - real(r8) :: rel_moisture ! relative moisture of fuel (moist/moisture of extinction) [unitless] - integer :: i ! looping index + real(r8) :: rel_moisture ! relative moisture of fuel (moist/moisture of extinction) [unitless] + integer :: i ! looping index ! CONSTANTS: real(r8), parameter :: max_grass_frac = 0.8_r8 ! maximum fraction burnt for live grass fuels diff --git a/testing/functional_testing/fire/fuel/FatesTestFuel.F90 b/testing/functional_testing/fire/fuel/FatesTestFuel.F90 index 79550afb50..90d76cd357 100644 --- a/testing/functional_testing/fire/fuel/FatesTestFuel.F90 +++ b/testing/functional_testing/fire/fuel/FatesTestFuel.F90 @@ -11,7 +11,7 @@ program FatesTestFuel use FatesFuelMod, only : fuel_type use FatesFuelClassesMod, only : num_fuel_classes use SFParamsMod, only : SF_val_SAV, SF_val_drying_ratio - use SFParamsMod, only : SF_val_FBD, SF_val_part_dens + use SFParamsMod, only : SF_val_FBD implicit none From c4cc3d2cbc3a95f570d635a4ec67c1f83a07ab7a Mon Sep 17 00:00:00 2001 From: Xiulin Gao Date: Tue, 28 Oct 2025 11:12:12 -0700 Subject: [PATCH 20/23] revert back to original fuel models for testing --- testing/functional_testing/fire/fuel/FatesTestFuel.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/functional_testing/fire/fuel/FatesTestFuel.F90 b/testing/functional_testing/fire/fuel/FatesTestFuel.F90 index 90d76cd357..dccd0f2b48 100644 --- a/testing/functional_testing/fire/fuel/FatesTestFuel.F90 +++ b/testing/functional_testing/fire/fuel/FatesTestFuel.F90 @@ -48,7 +48,7 @@ program FatesTestFuel character(len=*), parameter :: out_file = 'fuel_out.nc' ! output file ! fuel models to test - integer, parameter, dimension(4) :: fuel_models = (/102, 121, 104, 149/) + integer, parameter, dimension(5) :: fuel_models = (/102, 183, 164, 104, 163/) ! number of fuel models to test num_fuel_models = size(fuel_models) From c8fd596e39610709942949a8683fd0970c050e5a Mon Sep 17 00:00:00 2001 From: Xiulin Gao Date: Tue, 28 Oct 2025 11:13:17 -0700 Subject: [PATCH 21/23] modularize plot time series fun --- .../functional_testing/fire/fuel/fuel_test.py | 92 +++++++++---------- 1 file changed, 41 insertions(+), 51 deletions(-) diff --git a/testing/functional_testing/fire/fuel/fuel_test.py b/testing/functional_testing/fire/fuel/fuel_test.py index f3da6174c1..ea1f366040 100644 --- a/testing/functional_testing/fire/fuel/fuel_test.py +++ b/testing/functional_testing/fire/fuel/fuel_test.py @@ -35,11 +35,20 @@ def plot_output(self, run_dir: str, save_figs: bool, plot_dir: str): plot_dir (str): plot directory """ + # define all timeseries vars + # concise: define all time-series plots in one list + ts_specs = [ + ("NI", "Nesterov Index", None, "Nesterov_plot.png"), + ("fuel_moisture_dead", "Dead fuel Moisture", "fuel_model", "fuel_moisture_dead_plot.png"), + ("fuel_moisture_live", "Live fuel Moisture", "fuel_model", "fuel_moisture_live_plot.png"), + ] + fuel_dat = xr.open_dataset(os.path.join(run_dir, self.out_file)) - self.plot_NI_dat(fuel_dat, save_figs, plot_dir) - self.plot_moisture_dead_dat(fuel_dat, save_figs, plot_dir) - self.plot_moisture_live_dat(fuel_dat, save_figs, plot_dir) + for var, ylabel, hue, filename in ts_specs: + if var in fuel_dat: + self.plot_timeseries(fuel_dat, var, ylabel, hue, save_figs, plot_dir, filename) + self.plot_barchart( fuel_dat, "fuel_loading", @@ -169,60 +178,41 @@ def plot_barchart( plt.savefig(fig_name) @staticmethod - def plot_NI_dat(fuel_dat: xr.Dataset, save_figs: bool, plot_dir: str): - """Plot output for Nesterov index - - Args: - fuel_dat (Xarray Dataset): output fuel data - save_figs (bool): whether or not to save the figures - plot_dir (str): plot directory - """ - - plt.figure() - fuel_dat.NI.plot() - plt.xlabel("Time", fontsize=11) - plt.ylabel("Nesterov Index", fontsize=11) - - if save_figs: - fig_name = os.path.join(plot_dir, "Nesterov_plot.png") - plt.savefig(fig_name) - - @staticmethod - def plot_moisture_dead_dat(fuel_dat: xr.Dataset, save_figs: bool, plot_dir: str): - """Plot output for live fuel moisture - - Args: - fuel_dat (Xarray Dataset): output fuel data - save_figs (bool): whether or not to save the figures - plot_dir (str): plot directory - """ - - plt.figure() - fuel_dat.fuel_moisture_dead.plot(hue="fuel_model") - plt.xlabel("Time", fontsize=11) - plt.ylabel("Dead fuel Moisture", fontsize=11) - - if save_figs: - fig_name = os.path.join(plot_dir, "fuel_moisture_dead_plot.png") - plt.savefig(fig_name) - - @staticmethod - def plot_moisture_live_dat(fuel_dat: xr.Dataset, save_figs: bool, plot_dir: str): - """Plot output for fuel moisture + def plot_timeseries( + fuel_dat: xr.Dataset, + var: str, + ylabel: str, + hue: str | None, + save_figs: bool, + plot_dir: str, + filename: str, + ): + """Plot output as time series Args: fuel_dat (Xarray Dataset): output fuel data + var (str): variable to plot + ylabel (str): label for y axis + hue (str): grouping variable (optional) save_figs (bool): whether or not to save the figures plot_dir (str): plot directory + filename (str): file name for saving figures """ + if var not in fuel_dat: + return + + fig, ax = plt.subplots() + if hue is None: + fuel_dat[var].plot(ax=ax) + else: + fuel_dat[var].plot(hue = hue, ax=ax) - plt.figure() - fuel_dat.fuel_moisture_live.plot(hue="fuel_model") - plt.xlabel("Time", fontsize=11) - plt.ylabel("Live fuel Moisture", fontsize=11) - + ax.set_xlabel("Time", fontsize=11) + ax.set_ylabel(ylabel, fontsize=11) + plt.tight_layout() + if save_figs: - fig_name = os.path.join(plot_dir, "fuel_moisture_live_plot.png") - plt.savefig(fig_name) + fig_name = os.path.join(plot_dir, filename) + plt.savefig(fig_name, dpi=150, bbox_inches="tight") + plt.close(fig) - From ac848b45cbea44865600c1f8191b7441c5ed4055 Mon Sep 17 00:00:00 2001 From: Xiulin Gao Date: Tue, 28 Oct 2025 12:11:57 -0700 Subject: [PATCH 22/23] indent fix --- testing/functional_testing/fire/fuel/fuel_test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testing/functional_testing/fire/fuel/fuel_test.py b/testing/functional_testing/fire/fuel/fuel_test.py index ea1f366040..864e6e0ae2 100644 --- a/testing/functional_testing/fire/fuel/fuel_test.py +++ b/testing/functional_testing/fire/fuel/fuel_test.py @@ -46,8 +46,8 @@ def plot_output(self, run_dir: str, save_figs: bool, plot_dir: str): fuel_dat = xr.open_dataset(os.path.join(run_dir, self.out_file)) for var, ylabel, hue, filename in ts_specs: - if var in fuel_dat: - self.plot_timeseries(fuel_dat, var, ylabel, hue, save_figs, plot_dir, filename) + if var in fuel_dat: + self.plot_timeseries(fuel_dat, var, ylabel, hue, save_figs, plot_dir, filename) self.plot_barchart( fuel_dat, From 9d0f3f71d203f49ce68be6994d5e9fc7a6fc9179 Mon Sep 17 00:00:00 2001 From: Xiulin Gao Date: Tue, 28 Oct 2025 13:28:51 -0700 Subject: [PATCH 23/23] remove unnecessary unit conversion given its a fraction calculation --- fire/FatesFuelMod.F90 | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/fire/FatesFuelMod.F90 b/fire/FatesFuelMod.F90 index 35f742a4fe..fb956729f3 100644 --- a/fire/FatesFuelMod.F90 +++ b/fire/FatesFuelMod.F90 @@ -486,7 +486,6 @@ subroutine LiveFuelMoistureOfExtinction(fuel_load, sav_val, fmc, mef_dead, mef_l real(r8) :: w_d, md_d ! denominator for calculating W and moist_dead integer :: i ! looping index - real(r8), parameter :: kgm2_to_lbft2 = 0.0248_r8 ! convert kg m-2 to lb ft-2 w_n = 0.0_r8 md_n = 0.0_r8 @@ -494,11 +493,11 @@ subroutine LiveFuelMoistureOfExtinction(fuel_load, sav_val, fmc, mef_dead, mef_l md_d = 0.0_r8 do i = 1, num_fuel_classes if(i /= fuel_classes%live_grass())then - w_n = w_n + kgm2_to_lbft2*fuel_load(i)*exp(-4.5276_r8/sav_val(i)) - md_n = md_n + fmc(i)*kgm2_to_lbft2*fuel_load(i)*exp(-4.5276_r8/sav_val(i)) - md_d = md_d + kgm2_to_lbft2*fuel_load(i)*exp(-4.5264_r8/sav_val(i)) + w_n = w_n + fuel_load(i)*exp(-4.5276_r8/sav_val(i)) + md_n = md_n + fmc(i)*fuel_load(i)*exp(-4.5276_r8/sav_val(i)) + md_d = md_d + fuel_load(i)*exp(-4.5276_r8/sav_val(i)) else - w_d = w_d + kgm2_to_lbft2*fuel_load(i)*exp(-16.4042_r8/sav_val(i)) + w_d = w_d + fuel_load(i)*exp(-16.4042_r8/sav_val(i)) end if end do