diff --git a/.gitignore b/.gitignore index 40f2a49386..cf080967fe 100644 --- a/.gitignore +++ b/.gitignore @@ -46,6 +46,10 @@ Thumbs.db *.dvi *.toc +# Folders created with unit/functional tests +_build/ +_run/ + # Old Files *~ diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000000..9760a39c1d --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,90 @@ +cmake_minimum_required(VERSION 3.4) + +list(APPEND CMAKE_MODULE_PATH ${CIME_CMAKE_MODULE_DIRECTORY}) + +FIND_PATH(NETCDFC_FOUND libnetcdf.a ${NETCDF_C_DIR}/lib) +FIND_PATH(NETCDFF_FOUND libnetcdff.a ${NETCDF_FORTRAN_DIR}/lib) +MESSAGE(" NETCDFC_FOUND = ${NETCDFC_FOUND}") +MESSAGE(" NETCDFF_FOUND = ${NETCDFF_FOUND}") + +string(APPEND LDFLAGS " -L${NETCDF_FORTRAN_DIR}/lib -lnetcdff") +string(APPEND LDFLAGS " -L${NETCDF_C_DIR}/lib -lnetcdf") + +include(CIME_initial_setup) + +project(FATES_tests Fortran C) + +include(CIME_utils) + +set(HLM_ROOT "../../") + +# Add source directories from other share code (csm_share, etc.) +add_subdirectory(${HLM_ROOT}/share/src csm_share) +add_subdirectory(${HLM_ROOT}/share/unit_test_stubs/util csm_share_stubs) + +# Add FATES source directories +add_subdirectory(${HLM_ROOT}/src/fates/main fates_main) +add_subdirectory(${HLM_ROOT}/src/fates/biogeochem fates_biogeochem) +add_subdirectory(${HLM_ROOT}/src/fates/biogeophys fates_biogeophys) +add_subdirectory(${HLM_ROOT}/src/fates/parteh fates_parteh) +add_subdirectory(${HLM_ROOT}/src/fates/fire fates_fire) +add_subdirectory(${HLM_ROOT}/src/fates/radiation fates_radiation) +add_subdirectory(${HLM_ROOT}/src/fates/testing/testing_shr test_share) + +# Remove shr_mpi_mod from share_sources. +# This is needed because we want to use the mock shr_mpi_mod in place of the real one +# +# TODO: this should be moved into a general-purpose function in Sourcelist_utils. +# Then this block of code could be replaced with a single call, like: +# remove_source_file(${share_sources} "shr_mpi_mod.F90") +foreach (sourcefile ${share_sources}) + string(REGEX MATCH "shr_mpi_mod.F90" match_found ${sourcefile}) + if(match_found) + list(REMOVE_ITEM share_sources ${sourcefile}) + endif() +endforeach() + +# Remove shr_cal_mod from share_sources. +# +# shr_cal_mod depends on ESMF (or the lightweight esmf wrf timemgr, at +# least). Since CTSM doesn't currently use shr_cal_mod, we're avoiding +# the extra overhead of including esmf_wrf_timemgr sources in this +# build. +# +# TODO: like above, this should be moved into a general-purpose function +# in Sourcelist_utils. Then this block of code could be replaced with a +# single call, like: remove_source_file(${share_sources} +# "shr_cal_mod.F90") +foreach (sourcefile ${share_sources}) + string(REGEX MATCH "shr_cal_mod.F90" match_found ${sourcefile}) + if(match_found) + list(REMOVE_ITEM share_sources ${sourcefile}) + endif() +endforeach() + +# Build libraries containing stuff needed for the unit tests. +# Eventually, these add_library calls should probably be distributed into the correct location, rather than being in this top-level CMakeLists.txt file. +add_library(csm_share ${share_sources}) +declare_generated_dependencies(csm_share "${share_genf90_sources}") +add_library(fates ${fates_sources}) +add_dependencies(fates csm_share) + +# We need to look for header files here, in order to pick up shr_assert.h +include_directories(${HLM_ROOT}/share/include) + +# This needs to be something we add dynamically +# via some calls using cime +set(NETCDF_C_DIR ${NETCDF_C_PATH}) +set(NETCDF_FORTRAN_DIR ${NETCDF_F_PATH}) + +include_directories(${NETCDF_C_DIR}/include + ${NETCDF_FORTRAN_DIR}/include) +link_directories(${NETCDF_C_DIR}/lib + ${NETCDF_FORTRAN_DIR}/lib) + +# Tell cmake to look for libraries & mod files here, because this is where we built libraries +include_directories(${CMAKE_CURRENT_BINARY_DIR}) +link_directories(${CMAKE_CURRENT_BINARY_DIR}) + +# Add the main test directory +add_subdirectory(${HLM_ROOT}/src/fates/testing) diff --git a/biogeochem/CMakeLists.txt b/biogeochem/CMakeLists.txt new file mode 100644 index 0000000000..7a10c1fa9b --- /dev/null +++ b/biogeochem/CMakeLists.txt @@ -0,0 +1,9 @@ +# This file is required for unit testing, but is not used for production runs +list(APPEND fates_sources + FatesLitterMod.F90 + FatesCohortMod.F90 + FatesAllometryMod.F90 + DamageMainMod.F90 + FatesPatchMod.F90) + +sourcelist_to_parent(fates_sources) diff --git a/biogeochem/EDCanopyStructureMod.F90 b/biogeochem/EDCanopyStructureMod.F90 index a52be9a30e..3fbd7b78bd 100644 --- a/biogeochem/EDCanopyStructureMod.F90 +++ b/biogeochem/EDCanopyStructureMod.F90 @@ -11,6 +11,7 @@ module EDCanopyStructureMod use FatesConstantsMod , only : nearzero, area_error_1 use FatesConstantsMod , only : rsnbl_math_prec use FatesConstantsMod , only : nocomp_bareground + use FatesConstantsMod, only : i_term_mort_type_canlev use FatesGlobals , only : fates_log use EDPftvarcon , only : EDPftvarcon_inst use PRTParametersMod , only : prt_params @@ -19,11 +20,14 @@ module EDCanopyStructureMod use EDCohortDynamicsMod , only : InitPRTObject use FatesAllometryMod , only : tree_lai use FatesAllometryMod , only : tree_sai - use EDtypesMod , only : ed_site_type + use EDTypesMod , only : ed_site_type + use FatesAllometryMod , only : VegAreaLayer + use FatesAllometryMod , only : CrownDepth use FatesPatchMod, only : fates_patch_type use FatesCohortMod, only : fates_cohort_type use EDParamsMod , only : nclmax use EDParamsMod , only : nlevleaf + use EDParamsMod , only : radiation_model use EDtypesMod , only : AREA use EDLoggingMortalityMod , only : UpdateHarvestC use FatesGlobals , only : endrun => fates_endrun @@ -43,7 +47,9 @@ module EDCanopyStructureMod use PRTGenericMod, only : struct_organ use PRTGenericMod, only : SetState use PRTGenericMod, only : carbon12_element - + use FatesTwoStreamUtilsMod, only : FatesConstructRadElements + use FatesRadiationMemMod , only : twostr_solver + ! CIME Globals use shr_log_mod , only : errMsg => shr_log_errMsg @@ -79,6 +85,7 @@ module EDCanopyStructureMod real(r8), parameter :: similar_height_tol = 1.0E-3_r8 ! I think trees that differ by 1mm ! can be roughly considered the same right? + logical, parameter :: preserve_b4b = .true. ! 10/30/09: Created by Rosie Fisher ! 2017/2018: Modifications and updates by Ryan Knox @@ -736,7 +743,7 @@ subroutine DemoteFromLayer(currentSite,currentPatch,i_lyr,bc_in) if(currentCohort%canopy_layer>nclmax )then ! put the litter from the terminated cohorts ! straight into the fragmenting pools - call terminate_cohort(currentSite,currentPatch,currentCohort,bc_in) + call terminate_cohort(currentSite,currentPatch,currentCohort,bc_in,i_term_mort_type_canlev) deallocate(currentCohort, stat=istat, errmsg=smsg) if (istat/=0) then write(fates_log(),*) 'dealloc012: fail on deallocate(currentCohort):'//trim(smsg) @@ -1432,10 +1439,12 @@ subroutine canopy_summarization( nsites, sites, bc_in ) currentPatch => currentPatch%younger end do !patch loop - - call leaf_area_profile(sites(s)) - + + if(radiation_model.eq.twostr_solver) then + call FatesConstructRadElements(sites(s),bc_in(s)%fcansno_pa,bc_in(s)%coszen_pa) + end if + end do ! site loop return @@ -1493,8 +1502,6 @@ subroutine leaf_area_profile( currentSite ) ! currentPatch%esai_profile(cl,ft,iv) ! non-snow covered m2 of stems per m2 of PFT footprint ! currentPatch%canopy_area_profile(cl,ft,iv) ! Fractional area of leaf layer ! ! relative to vegetated area - ! currentPatch%layer_height_profile(cl,ft,iv) ! Elevation of layer in m - ! ! ----------------------------------------------------------------------------------- ! !USES: @@ -1517,17 +1524,17 @@ subroutine leaf_area_profile( currentSite ) integer :: iv ! Vertical leaf layer index integer :: cl ! Canopy layer index real(r8) :: fraction_exposed ! how much of this layer is not covered by snow? - real(r8) :: layer_top_height ! notional top height of this canopy layer (m) - real(r8) :: layer_bottom_height ! notional bottom height of this canopy layer (m) real(r8) :: frac_canopy(N_HEIGHT_BINS) ! amount of canopy in each height class real(r8) :: minh(N_HEIGHT_BINS) ! minimum height in height class (m) real(r8) :: maxh(N_HEIGHT_BINS) ! maximum height in height class (m) real(r8) :: dh ! vertical detph of height class (m) real(r8) :: min_cheight ! bottom of cohort canopy (m) real(r8) :: max_cheight ! top of cohort canopy (m) - real(r8) :: lai ! leaf area per canopy area - real(r8) :: sai ! stem area per canopy area - + real(r8) :: elai_layer,tlai_layer ! leaf area per canopy area + real(r8) :: esai_layer,tsai_layer ! stem area per canopy area + real(r8) :: vai_top,vai_bot ! integrated top down veg area index at boundary of layer + real(r8) :: crown_depth ! Current cohort's crown depth + real(r8) :: layer_bottom_height,layer_top_height,lai,sai ! Can be removed later !---------------------------------------------------------------------- @@ -1551,7 +1558,6 @@ subroutine leaf_area_profile( currentSite ) currentPatch%tsai_profile(:,:,:) = 0._r8 currentPatch%elai_profile(:,:,:) = 0._r8 currentPatch%esai_profile(:,:,:) = 0._r8 - currentPatch%layer_height_profile(:,:,:) = 0._r8 currentPatch%canopy_area_profile(:,:,:) = 0._r8 currentPatch%canopy_mask(:,:) = 0 @@ -1560,10 +1566,12 @@ subroutine leaf_area_profile( currentSite ) ! area, ie not plants at all... ! ------------------------------------------------------------------------------ - if (currentPatch%total_canopy_area > nearzero ) then + if_any_canopy_area: if (currentPatch%total_canopy_area > nearzero ) then call UpdatePatchLAI(currentPatch) + currentPatch%nrad(:,:) = currentPatch%ncan(:,:) + ! ----------------------------------------------------------------------------- ! Standard canopy layering model. ! Go through all cohorts and add their leaf area @@ -1579,100 +1587,136 @@ subroutine leaf_area_profile( currentSite ) ! How much of each tree is stem area index? Assuming that there is ! This may indeed be zero if there is a sensecent grass ! ---------------------------------------------------------------- - lai = currentCohort%treelai * currentCohort%c_area/currentPatch%total_canopy_area - sai = currentCohort%treesai * currentCohort%c_area/currentPatch%total_canopy_area - if( (currentCohort%treelai+currentCohort%treesai) > nearzero)then - - ! See issue: https://github.com/NGEET/fates/issues/899 - ! fleaf = currentCohort%treelai / (currentCohort%treelai + currentCohort%treesai) - fleaf = lai / (lai+sai) - else - fleaf = 0._r8 - endif - - currentPatch%nrad(cl,ft) = currentPatch%ncan(cl,ft) - - if (currentPatch%nrad(cl,ft) > nlevleaf ) then - write(fates_log(), *) 'Number of radiative leaf layers is larger' - write(fates_log(), *) ' than the maximum allowed.' - write(fates_log(), *) ' cl: ',cl - write(fates_log(), *) ' ft: ',ft - write(fates_log(), *) ' nlevleaf: ',nlevleaf - write(fates_log(), *) ' currentPatch%nrad(cl,ft): ', currentPatch%nrad(cl,ft) - call endrun(msg=errMsg(sourcefile, __LINE__)) - end if - - - ! -------------------------------------------------------------------------- - ! Whole layers. Make a weighted average of the leaf area in each layer - ! before dividing it by the total area. Fill up layer for whole layers. - ! -------------------------------------------------------------------------- - - do iv = 1,currentCohort%NV - - ! This loop builds the arrays that define the effective (not snow covered) - ! and total (includes snow covered) area indices for leaves and stems - ! We calculate the absolute elevation of each layer to help determine if the layer - ! is obscured by snow. - - layer_top_height = currentCohort%height - & - ( real(iv-1,r8)/currentCohort%NV * currentCohort%height * & - prt_params%crown_depth_frac(currentCohort%pft) ) - - layer_bottom_height = currentCohort%height - & - ( real(iv,r8)/currentCohort%NV * currentCohort%height * & - prt_params%crown_depth_frac(currentCohort%pft) ) - - fraction_exposed = 1.0_r8 - if(currentSite%snow_depth > layer_top_height)then - fraction_exposed = 0._r8 - endif - if(currentSite%snow_depth < layer_bottom_height)then - fraction_exposed = 1._r8 - endif - if(currentSite%snow_depth >= layer_bottom_height .and. & - currentSite%snow_depth <= layer_top_height) then !only partly hidden... - fraction_exposed = 1._r8 - max(0._r8,(min(1.0_r8,(currentSite%snow_depth -layer_bottom_height)/ & - (layer_top_height-layer_bottom_height )))) - endif - - if(iv==currentCohort%NV) then - remainder = (currentCohort%treelai + currentCohort%treesai) - & - (dlower_vai(iv) - dinc_vai(iv)) - if(remainder > dinc_vai(iv) )then - write(fates_log(), *)'ED: issue with remainder', & - currentCohort%treelai,currentCohort%treesai,dinc_vai(iv), & - currentCohort%NV,remainder - - call endrun(msg=errMsg(sourcefile, __LINE__)) - endif + ! preserve_b4b will be removed soon. This is kept here to prevent + ! round off errors in the baseline tests for the two-stream code (RGK 12-27-23) + if_preserve_b4b: if(preserve_b4b) then + lai = currentCohort%treelai * currentCohort%c_area/currentPatch%total_canopy_area + sai = currentCohort%treesai * currentCohort%c_area/currentPatch%total_canopy_area + if( (currentCohort%treelai+currentCohort%treesai) > nearzero)then + + ! See issue: https://github.com/NGEET/fates/issues/899 + ! fleaf = currentCohort%treelai / (currentCohort%treelai + currentCohort%treesai) + fleaf = lai / (lai+sai) else - remainder = dinc_vai(iv) + fleaf = 0._r8 + endif + + currentPatch%nrad(cl,ft) = currentPatch%ncan(cl,ft) + + if (currentPatch%nrad(cl,ft) > nlevleaf ) then + write(fates_log(), *) 'Number of radiative leaf layers is larger' + write(fates_log(), *) ' than the maximum allowed.' + write(fates_log(), *) ' cl: ',cl + write(fates_log(), *) ' ft: ',ft + write(fates_log(), *) ' nlevleaf: ',nlevleaf + write(fates_log(), *) ' currentPatch%nrad(cl,ft): ', currentPatch%nrad(cl,ft) + call endrun(msg=errMsg(sourcefile, __LINE__)) end if - currentPatch%tlai_profile(cl,ft,iv) = currentPatch%tlai_profile(cl,ft,iv) + & - remainder * fleaf * currentCohort%c_area/currentPatch%total_canopy_area - - currentPatch%elai_profile(cl,ft,iv) = currentPatch%elai_profile(cl,ft,iv) + & - remainder * fleaf * currentCohort%c_area/currentPatch%total_canopy_area * & - fraction_exposed - - currentPatch%tsai_profile(cl,ft,iv) = currentPatch%tsai_profile(cl,ft,iv) + & - remainder * (1._r8 - fleaf) * currentCohort%c_area/currentPatch%total_canopy_area - - currentPatch%esai_profile(cl,ft,iv) = currentPatch%esai_profile(cl,ft,iv) + & - remainder * (1._r8 - fleaf) * currentCohort%c_area/currentPatch%total_canopy_area * & - fraction_exposed - - currentPatch%canopy_area_profile(cl,ft,iv) = currentPatch%canopy_area_profile(cl,ft,iv) + & - currentCohort%c_area/currentPatch%total_canopy_area - - currentPatch%layer_height_profile(cl,ft,iv) = currentPatch%layer_height_profile(cl,ft,iv) + & - (remainder * fleaf * currentCohort%c_area/currentPatch%total_canopy_area * & - (layer_top_height+layer_bottom_height)/2.0_r8) !average height of layer. - - end do - + !---~--- + ! Find current crown depth using the allometric function. + !---~--- + call CrownDepth(currentCohort%height,currentCohort%pft,crown_depth) + !---~--- + + + ! -------------------------------------------------------------------------- + ! Whole layers. Make a weighted average of the leaf area in each layer + ! before dividing it by the total area. Fill up layer for whole layers. + ! -------------------------------------------------------------------------- + + do iv = 1,currentCohort%NV + + ! This loop builds the arrays that define the effective (not snow covered) + ! and total (includes snow covered) area indices for leaves and stems + ! We calculate the absolute elevation of each layer to help determine if the layer + ! is obscured by snow. + + layer_top_height = currentCohort%height - & + ( real(iv-1,r8)/currentCohort%NV * crown_depth ) + + layer_bottom_height = currentCohort%height - & + ( real(iv,r8)/currentCohort%NV * crown_depth ) + + fraction_exposed = 1.0_r8 + if(currentSite%snow_depth > layer_top_height)then + fraction_exposed = 0._r8 + endif + if(currentSite%snow_depth < layer_bottom_height)then + fraction_exposed = 1._r8 + endif + if(currentSite%snow_depth >= layer_bottom_height .and. & + currentSite%snow_depth <= layer_top_height) then !only partly hidden... + fraction_exposed = 1._r8 - max(0._r8,(min(1.0_r8,(currentSite%snow_depth -layer_bottom_height)/ & + (layer_top_height-layer_bottom_height )))) + endif + + if(iv==currentCohort%NV) then + remainder = (currentCohort%treelai + currentCohort%treesai) - & + (dlower_vai(iv) - dinc_vai(iv)) + if(remainder > dinc_vai(iv) )then + write(fates_log(), *)'ED: issue with remainder', & + currentCohort%treelai,currentCohort%treesai,dinc_vai(iv), & + currentCohort%NV,remainder + + call endrun(msg=errMsg(sourcefile, __LINE__)) + endif + else + remainder = dinc_vai(iv) + end if + + currentPatch%tlai_profile(cl,ft,iv) = currentPatch%tlai_profile(cl,ft,iv) + & + remainder * fleaf * currentCohort%c_area/currentPatch%total_canopy_area + + currentPatch%elai_profile(cl,ft,iv) = currentPatch%elai_profile(cl,ft,iv) + & + remainder * fleaf * currentCohort%c_area/currentPatch%total_canopy_area * & + fraction_exposed + + currentPatch%tsai_profile(cl,ft,iv) = currentPatch%tsai_profile(cl,ft,iv) + & + remainder * (1._r8 - fleaf) * currentCohort%c_area/currentPatch%total_canopy_area + + currentPatch%esai_profile(cl,ft,iv) = currentPatch%esai_profile(cl,ft,iv) + & + remainder * (1._r8 - fleaf) * currentCohort%c_area/currentPatch%total_canopy_area * & + fraction_exposed + + currentPatch%canopy_area_profile(cl,ft,iv) = currentPatch%canopy_area_profile(cl,ft,iv) + & + currentCohort%c_area/currentPatch%total_canopy_area + + + end do + + else !if_preserve_b4b + + do iv = 1,currentCohort%NV + + call VegAreaLayer(currentCohort%treelai, & + currentCohort%treesai, & + currentCohort%height, & + iv,currentCohort%nv,currentCohort%pft, & + currentSite%snow_depth, & + vai_top,vai_bot, & + elai_layer,esai_layer,tlai_layer,tsai_layer) + + + currentPatch%tlai_profile(cl,ft,iv) = currentPatch%tlai_profile(cl,ft,iv) + & + tlai_layer * currentCohort%c_area/currentPatch%total_canopy_area + + currentPatch%elai_profile(cl,ft,iv) = currentPatch%elai_profile(cl,ft,iv) + & + elai_layer * currentCohort%c_area/currentPatch%total_canopy_area + + currentPatch%tsai_profile(cl,ft,iv) = currentPatch%tsai_profile(cl,ft,iv) + & + tsai_layer * currentCohort%c_area/currentPatch%total_canopy_area + + currentPatch%esai_profile(cl,ft,iv) = currentPatch%esai_profile(cl,ft,iv) + & + esai_layer * currentCohort%c_area/currentPatch%total_canopy_area + + currentPatch%canopy_area_profile(cl,ft,iv) = currentPatch%canopy_area_profile(cl,ft,iv) + & + currentCohort%c_area/currentPatch%total_canopy_area + + end do + + end if if_preserve_b4b + currentCohort => currentCohort%taller enddo !cohort @@ -1759,11 +1803,6 @@ subroutine leaf_area_profile( currentSite ) currentPatch%canopy_area_profile(cl,ft,iv) end if - if(currentPatch%tlai_profile(cl,ft,iv)>nearzero )then - currentPatch%layer_height_profile(cl,ft,iv) = currentPatch%layer_height_profile(cl,ft,iv) & - /currentPatch%tlai_profile(cl,ft,iv) - end if - enddo enddo @@ -1771,20 +1810,35 @@ subroutine leaf_area_profile( currentSite ) ! -------------------------------------------------------------------------- ! Set the mask that identifies which PFT x can-layer combinations have - ! scattering elements in them. + ! scattering elements in them for radiation. + ! RGK: I'm not sure we need nrad ... I can't see a scenario where + ! canopy_area_profile for these layers is not >0 for layers in ncan ... + ! Leaving this for the time being. ! -------------------------------------------------------------------------- + + currentPatch%canopy_mask(:,:) = 0 + ! preserve_b4b will be removed soon. This is kept here to prevent + ! round off errors in the baseline tests for the two-stream code (RGK 12-27-23) + if(preserve_b4b) then + do cl = 1,currentPatch%NCL_p + do ft = 1,numpft + do iv = 1, currentPatch%nrad(cl,ft) + if(currentPatch%canopy_area_profile(cl,ft,iv) > 0._r8)then + currentPatch%canopy_mask(cl,ft) = 1 + endif + end do !iv + end do + end do + else + do cl = 1,currentPatch%NCL_p + do ft = 1,numpft + if(currentPatch%canopy_area_profile(cl,ft,1) > 0._r8 ) currentPatch%canopy_mask(cl,ft) = 1 + end do + end do + end if - do cl = 1,currentPatch%NCL_p - do ft = 1,numpft - do iv = 1, currentPatch%nrad(cl,ft) - if(currentPatch%canopy_area_profile(cl,ft,iv) > 0._r8)then - currentPatch%canopy_mask(cl,ft) = 1 - endif - end do !iv - enddo !ft - enddo ! loop over cl - - end if + + end if if_any_canopy_area currentPatch => currentPatch%younger diff --git a/biogeochem/EDCohortDynamicsMod.F90 b/biogeochem/EDCohortDynamicsMod.F90 index 12385a8f9d..ef87851ec1 100644 --- a/biogeochem/EDCohortDynamicsMod.F90 +++ b/biogeochem/EDCohortDynamicsMod.F90 @@ -120,6 +120,10 @@ Module EDCohortDynamicsMod use PRTAllometricCNPMod, only : acnp_bc_out_id_pefflux, acnp_bc_out_id_limiter use PRTAllometricCNPMod, only : acnp_bc_in_id_cdamage use DamageMainMod, only : undamaged_class + use 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 shr_infnan_mod, only : nan => shr_infnan_nan, assignment(=) use shr_log_mod, only : errMsg => shr_log_errMsg @@ -382,12 +386,14 @@ subroutine terminate_cohorts( currentSite, currentPatch, level , call_index, bc_ integer :: terminate ! do we terminate (itrue) or not (ifalse) integer :: istat ! return status code character(len=255) :: smsg + integer :: termination_type !---------------------------------------------------------------------- currentCohort => currentPatch%shortest do while (associated(currentCohort)) terminate = ifalse + termination_type = 0 tallerCohort => currentCohort%taller leaf_c = currentCohort%prt%GetState(leaf_organ, carbon12_element) @@ -400,6 +406,7 @@ subroutine terminate_cohorts( currentSite, currentPatch, level , call_index, bc_ ! Check if number density is so low is breaks math (level 1) if (currentcohort%n < min_n_safemath .and. level == 1) then terminate = itrue + termination_type = i_term_mort_type_numdens if ( debug ) then write(fates_log(),*) 'terminating cohorts 0',currentCohort%n/currentPatch%area,currentCohort%dbh,currentCohort%pft,call_index endif @@ -413,6 +420,7 @@ subroutine terminate_cohorts( currentSite, currentPatch, level , call_index, bc_ currentCohort%n <= min_nppatch .or. & (currentCohort%dbh < 0.00001_r8 .and. store_c < 0._r8) ) then terminate = itrue + termination_type = i_term_mort_type_numdens if ( debug ) then write(fates_log(),*) 'terminating cohorts 1',currentCohort%n/currentPatch%area,currentCohort%dbh,currentCohort%pft,call_index endif @@ -421,6 +429,7 @@ subroutine terminate_cohorts( currentSite, currentPatch, level , call_index, bc_ ! Outside the maximum canopy layer if (currentCohort%canopy_layer > nclmax ) then terminate = itrue + termination_type = i_term_mort_type_canlev if ( debug ) then write(fates_log(),*) 'terminating cohorts 2', currentCohort%canopy_layer,currentCohort%pft,call_index endif @@ -430,6 +439,7 @@ subroutine terminate_cohorts( currentSite, currentPatch, level , call_index, bc_ if ( ( sapw_c+leaf_c+fnrt_c ) < 1e-10_r8 .or. & store_c < 1e-10_r8) then terminate = itrue + termination_type = i_term_mort_type_cstarv if ( debug ) then write(fates_log(),*) 'terminating cohorts 3', & sapw_c,leaf_c,fnrt_c,store_c,currentCohort%pft,call_index @@ -439,6 +449,7 @@ subroutine terminate_cohorts( currentSite, currentPatch, level , call_index, bc_ ! Total cohort biomass is negative if ( ( struct_c+sapw_c+leaf_c+fnrt_c+store_c ) < 0._r8) then terminate = itrue + termination_type = i_term_mort_type_cstarv if ( debug ) then write(fates_log(),*) 'terminating cohorts 4', & struct_c,sapw_c,leaf_c,fnrt_c,store_c,currentCohort%pft,call_index @@ -448,7 +459,7 @@ subroutine terminate_cohorts( currentSite, currentPatch, level , call_index, bc_ endif ! if (.not.currentCohort%isnew .and. level == 2) then if (terminate == itrue) then - call terminate_cohort(currentSite, currentPatch, currentCohort, bc_in) + call terminate_cohort(currentSite, currentPatch, currentCohort, bc_in, termination_type) deallocate(currentCohort, stat=istat, errmsg=smsg) if (istat/=0) then write(fates_log(),*) 'dealloc001: fail on terminate_cohorts:deallocate(currentCohort):'//trim(smsg) @@ -461,7 +472,7 @@ subroutine terminate_cohorts( currentSite, currentPatch, level , call_index, bc_ end subroutine terminate_cohorts !-------------------------------------------------------------------------------------! - subroutine terminate_cohort(currentSite, currentPatch, currentCohort, bc_in) + subroutine terminate_cohort(currentSite, currentPatch, currentCohort, bc_in, termination_type) ! ! !DESCRIPTION: ! Terminates an individual cohort and updates the site-level @@ -474,6 +485,7 @@ subroutine terminate_cohort(currentSite, currentPatch, currentCohort, bc_in) type (fates_patch_type) , intent(inout), target :: currentPatch type (fates_cohort_type), intent(inout), target :: currentCohort type(bc_in_type), intent(in) :: bc_in + integer, intent(in) :: termination_type ! !LOCAL VARIABLES: type (fates_cohort_type) , pointer :: shorterCohort @@ -491,6 +503,12 @@ subroutine terminate_cohort(currentSite, currentPatch, currentCohort, bc_in) !---------------------------------------------------------------------- + ! check termination_type; it should not be 0 + if (termination_type == 0) then + write(fates_log(),*) 'termination_type=0' + call endrun(msg=errMsg(sourcefile, __LINE__)) + endif + leaf_c = currentCohort%prt%GetState(leaf_organ, carbon12_element) store_c = currentCohort%prt%GetState(store_organ, carbon12_element) sapw_c = currentCohort%prt%GetState(sapw_organ, carbon12_element) @@ -506,16 +524,16 @@ subroutine terminate_cohort(currentSite, currentPatch, currentCohort, bc_in) ! Update the site-level carbon flux and individuals count for the appropriate canopy layer if(levcan==ican_upper) then - currentSite%term_nindivs_canopy(currentCohort%size_class,currentCohort%pft) = & - currentSite%term_nindivs_canopy(currentCohort%size_class,currentCohort%pft) + currentCohort%n + currentSite%term_nindivs_canopy(termination_type,currentCohort%size_class,currentCohort%pft) = & + currentSite%term_nindivs_canopy(termination_type,currentCohort%size_class,currentCohort%pft) + currentCohort%n - currentSite%term_carbonflux_canopy(currentCohort%pft) = currentSite%term_carbonflux_canopy(currentCohort%pft) + & + currentSite%term_carbonflux_canopy(termination_type,currentCohort%pft) = currentSite%term_carbonflux_canopy(termination_type,currentCohort%pft) + & currentCohort%n * (struct_c+sapw_c+leaf_c+fnrt_c+store_c+repro_c) else - currentSite%term_nindivs_ustory(currentCohort%size_class,currentCohort%pft) = & - currentSite%term_nindivs_ustory(currentCohort%size_class,currentCohort%pft) + currentCohort%n + currentSite%term_nindivs_ustory(termination_type,currentCohort%size_class,currentCohort%pft) = & + currentSite%term_nindivs_ustory(termination_type,currentCohort%size_class,currentCohort%pft) + currentCohort%n - currentSite%term_carbonflux_ustory(currentCohort%pft) = currentSite%term_carbonflux_ustory(currentCohort%pft) + & + currentSite%term_carbonflux_ustory(termination_type,currentCohort%pft) = currentSite%term_carbonflux_ustory(termination_type,currentCohort%pft) + & currentCohort%n * (struct_c+sapw_c+leaf_c+fnrt_c+store_c+repro_c) end if @@ -553,7 +571,7 @@ subroutine terminate_cohort(currentSite, currentPatch, currentCohort, bc_in) call currentCohort%FreeMemory() - end subroutine terminate_cohort + end subroutine terminate_cohort ! ===================================================================================== diff --git a/biogeochem/EDLoggingMortalityMod.F90 b/biogeochem/EDLoggingMortalityMod.F90 index bf6ab7443c..6d373e995a 100644 --- a/biogeochem/EDLoggingMortalityMod.F90 +++ b/biogeochem/EDLoggingMortalityMod.F90 @@ -28,6 +28,7 @@ module EDLoggingMortalityMod use FatesConstantsMod , only : dtype_ilog use FatesConstantsMod , only : dtype_ifall use FatesConstantsMod , only : dtype_ifire + use FatesConstantsMod , only : n_landuse_cats use EDPftvarcon , only : EDPftvarcon_inst use EDPftvarcon , only : GetDecompyFrac use PRTParametersMod , only : prt_params @@ -53,6 +54,7 @@ module EDLoggingMortalityMod use FatesInterfaceTypesMod , only : hlm_num_lu_harvest_cats use FatesInterfaceTypesMod , only : hlm_use_logging use FatesInterfaceTypesMod , only : hlm_use_planthydro + use FatesInterfaceTypesMod , only : hlm_use_luh use FatesConstantsMod , only : itrue,ifalse use FatesGlobals , only : endrun => fates_endrun use FatesGlobals , only : fates_log @@ -69,7 +71,10 @@ module EDLoggingMortalityMod use FatesConstantsMod , only : hlm_harvest_area_fraction use FatesConstantsMod , only : hlm_harvest_carbon use FatesConstantsMod, only : fates_check_param_set - + use FatesInterfaceTypesMod , only : numpft + use FatesLandUseChangeMod, only : GetInitLanduseHarvestRate + use FatesLandUseChangeMod, only : GetLUHStatedata + implicit none private @@ -195,15 +200,17 @@ end subroutine IsItLoggingTime ! ====================================================================================== - subroutine LoggingMortality_frac( pft_i, dbh, canopy_layer, lmort_direct, & + subroutine LoggingMortality_frac( currentSite, bc_in, pft_i, dbh, canopy_layer, lmort_direct, & lmort_collateral,lmort_infra, l_degrad, & hlm_harvest_rates, hlm_harvest_catnames, & hlm_harvest_units, & patch_land_use_label, secondary_age, & - frac_site_primary, harvestable_forest_c, & + frac_site_primary, frac_site_secondary, harvestable_forest_c, & harvest_tag) - ! Arguments + ! Arguments + type(ed_site_type), intent(inout), target :: currentSite ! site structure + type(bc_in_type), intent(in) :: bc_in integer, intent(in) :: pft_i ! pft index real(r8), intent(in) :: dbh ! diameter at breast height (cm) integer, intent(in) :: canopy_layer ! canopy layer of this cohort @@ -215,6 +222,7 @@ subroutine LoggingMortality_frac( pft_i, dbh, canopy_layer, lmort_direct, & real(r8), intent(in) :: harvestable_forest_c(:) ! total harvestable forest carbon ! of all hlm harvest categories real(r8), intent(in) :: frac_site_primary + real(r8), intent(in) :: frac_site_secondary real(r8), intent(out) :: lmort_direct ! direct (harvestable) mortality fraction real(r8), intent(out) :: lmort_collateral ! collateral damage mortality fraction real(r8), intent(out) :: lmort_infra ! infrastructure mortality fraction @@ -232,6 +240,9 @@ subroutine LoggingMortality_frac( pft_i, dbh, canopy_layer, lmort_direct, & ! Local variables integer :: cur_harvest_tag ! the harvest tag of the cohort today real(r8) :: harvest_rate ! the final harvest rate to apply to this cohort today + real(r8) :: state_vector(n_landuse_cats) + logical :: site_secondaryland_first_exceeding_min + real(r8) :: secondary_young_fraction ! what fraction of secondary land is young secondary land ! todo: probably lower the dbhmin default value to 30 cm ! todo: change the default logging_event_code to 1 september (-244) @@ -239,55 +250,92 @@ subroutine LoggingMortality_frac( pft_i, dbh, canopy_layer, lmort_direct, & ! todo: check outputs against the LUH2 carbon data ! todo: eventually set up distinct harvest practices, each with a set of input paramaeters ! todo: implement harvested carbon inputs - - if (logging_time) then - ! Pass logging rates to cohort level - - if (hlm_use_lu_harvest == ifalse) then - ! 0=use fates logging parameters directly when logging_time == .true. - ! this means harvest the whole cohort area - harvest_rate = 1._r8 - - else if (hlm_use_lu_harvest == itrue .and. hlm_harvest_units == hlm_harvest_area_fraction) then - ! We are harvesting based on areal fraction, not carbon/biomass terms. - ! 1=use area fraction from hlm - ! combine forest and non-forest fracs and then apply: - ! primary and secondary area fractions to the logging rates, which are fates parameters - - ! Definitions of the underlying harvest land category variables - ! these are hardcoded to match the LUH input data via landuse.timseries file (see dynHarvestMod) - ! these are fractions of vegetated area harvested, split into five land category variables - ! HARVEST_VH1 = harvest from primary forest - ! HARVEST_VH2 = harvest from primary non-forest - ! HARVEST_SH1 = harvest from secondary mature forest - ! HARVEST_SH2 = harvest from secondary young forest - ! HARVEST_SH3 = harvest from secondary non-forest (assume this is young for biomass) - - ! Get the area-based harvest rates based on info passed to FATES from the boundary condition - call get_harvest_rate_area (patch_land_use_label, hlm_harvest_catnames, & - hlm_harvest_rates, frac_site_primary, secondary_age, harvest_rate) + ! The transition_landuse_from_off_to_on is for handling the special case of the first timestep after leaving potential + ! vegetation mode. In this case, all prior historical land-use, including harvest, needs to be applied on that first day. + ! So logging rates on that day are what is required to deforest exactly the amount of primary lands that will give the + ! amount of secondary lands dictated by the land use state vector for that year, rather than whatever the continuous + ! logging rate for that year is supposed to be according to the land use transition matrix. + if (.not. currentSite%transition_landuse_from_off_to_on) then + + ! Check if the secondaryland exceeds the minimum if in landuse mode + site_secondaryland_first_exceeding_min = .false. + if (hlm_use_luh .eq. itrue) then + call GetLUHStatedata(bc_in, state_vector) + site_secondaryland_first_exceeding_min = (state_vector(secondaryland) .gt. currentSite%min_allowed_landuse_fraction) & + .and. (.not. currentSite%landuse_vector_gt_min(secondaryland)) + end if + + ! if the total intended area of secondary lands are less than what we can consider without having too-small patches, + ! or if that was the case until just now, then there is special logic + if (site_secondaryland_first_exceeding_min) then + if ( patch_land_use_label .eq. primaryland) then + harvest_rate = state_vector(secondaryland) / state_vector(primaryland) + write(fates_log(), *) 'applying state_vector(secondaryland) to plants.', pft_i + else + harvest_rate = 0._r8 + endif ! For area-based harvest, harvest_tag shall always be 2 (not applicable). harvest_tag = 2 cur_harvest_tag = 2 + elseif (logging_time) then + + ! Pass logging rates to cohort level + + if (hlm_use_lu_harvest == ifalse) then + ! 0=use fates logging parameters directly when logging_time == .true. + ! this means harvest the whole cohort area + harvest_rate = 1._r8 + + else if (hlm_use_lu_harvest == itrue .and. hlm_harvest_units == hlm_harvest_area_fraction) then + ! We are harvesting based on areal fraction, not carbon/biomass terms. + ! 1=use area fraction from hlm + ! combine forest and non-forest fracs and then apply: + ! primary and secondary area fractions to the logging rates, which are fates parameters + + ! Definitions of the underlying harvest land category variables + ! these are hardcoded to match the LUH input data via landuse.timseries file (see dynHarvestMod) + ! these are fractions of vegetated area harvested, split into five land category variables + ! HARVEST_VH1 = harvest from primary forest + ! HARVEST_VH2 = harvest from primary non-forest + ! HARVEST_SH1 = harvest from secondary mature forest + ! HARVEST_SH2 = harvest from secondary young forest + ! HARVEST_SH3 = harvest from secondary non-forest (assume this is young for biomass) + + secondary_young_fraction = currentSite%get_secondary_young_fraction() + + ! Get the area-based harvest rates based on info passed to FATES from the boundary condition + call get_harvest_rate_area (patch_land_use_label, hlm_harvest_catnames, & + hlm_harvest_rates, frac_site_primary, frac_site_secondary, secondary_young_fraction, secondary_age, harvest_rate) + + ! For area-based harvest, harvest_tag shall always be 2 (not applicable). + harvest_tag = 2 + cur_harvest_tag = 2 + + if (fates_global_verbose()) then + write(fates_log(), *) 'Successfully Read Harvest Rate from HLM.', hlm_harvest_rates(:), harvest_rate + end if - if (fates_global_verbose()) then - write(fates_log(), *) 'Successfully Read Harvest Rate from HLM.', hlm_harvest_rates(:), harvest_rate - end if + else if (hlm_use_lu_harvest == itrue .and. hlm_harvest_units == hlm_harvest_carbon) then + ! 2=use carbon from hlm + ! shall call another subroutine, which transfers biomass/carbon into fraction - else if (hlm_use_lu_harvest == itrue .and. hlm_harvest_units == hlm_harvest_carbon) then - ! 2=use carbon from hlm - ! shall call another subroutine, which transfers biomass/carbon into fraction + call get_harvest_rate_carbon (patch_land_use_label, hlm_harvest_catnames, & + hlm_harvest_rates, secondary_age, harvestable_forest_c, & + harvest_rate, harvest_tag, cur_harvest_tag) - call get_harvest_rate_carbon (patch_land_use_label, hlm_harvest_catnames, & - hlm_harvest_rates, secondary_age, harvestable_forest_c, & - harvest_rate, harvest_tag, cur_harvest_tag) + if (fates_global_verbose()) then + write(fates_log(), *) 'Successfully Read Harvest Rate from HLM.', hlm_harvest_rates(:), harvest_rate, harvestable_forest_c + end if - if (fates_global_verbose()) then - write(fates_log(), *) 'Successfully Read Harvest Rate from HLM.', hlm_harvest_rates(:), harvest_rate, harvestable_forest_c - end if - + endif + + else + harvest_rate = 0._r8 + ! For area-based harvest, harvest_tag shall always be 2 (not applicable). + harvest_tag = 2 + cur_harvest_tag = 2 endif ! transfer of area to secondary land is based on overall area affected, not just logged crown area @@ -296,7 +344,7 @@ subroutine LoggingMortality_frac( pft_i, dbh, canopy_layer, lmort_direct, & if (cur_harvest_tag == 0) then ! direct logging rates, based on dbh min and max criteria if (dbh >= logging_dbhmin .and. .not. & - ((logging_dbhmax < fates_check_param_set) .and. (dbh >= logging_dbhmax )) ) then + ((logging_dbhmax < fates_check_param_set) .and. (dbh >= logging_dbhmax )) ) then ! the logic of the above line is a bit unintuitive but allows turning off the dbhmax comparison entirely. ! since there is an .and. .not. after the first conditional, the dbh:dbhmax comparison needs to be ! the opposite of what would otherwise be expected... @@ -305,7 +353,7 @@ subroutine LoggingMortality_frac( pft_i, dbh, canopy_layer, lmort_direct, & lmort_direct = 0.0_r8 end if else - lmort_direct = 0.0_r8 + lmort_direct = 0.0_r8 end if ! infrastructure (roads, skid trails, etc) mortality rates @@ -335,13 +383,20 @@ subroutine LoggingMortality_frac( pft_i, dbh, canopy_layer, lmort_direct, & else l_degrad = 0._r8 endif - - else - lmort_direct = 0.0_r8 + + else + call GetInitLanduseHarvestRate(bc_in, currentSite%min_allowed_landuse_fraction, & + harvest_rate, currentSite%landuse_vector_gt_min) + lmort_direct = 0.0_r8 lmort_collateral = 0.0_r8 lmort_infra = 0.0_r8 l_degrad = 0.0_r8 - end if + if(prt_params%woody(pft_i) == itrue)then + lmort_direct = harvest_rate + else if (canopy_layer .eq. 1) then + l_degrad = harvest_rate + endif + endif end subroutine LoggingMortality_frac @@ -349,13 +404,13 @@ end subroutine LoggingMortality_frac ! ============================================================================ subroutine get_harvest_rate_area (patch_land_use_label, hlm_harvest_catnames, hlm_harvest_rates, & - frac_site_primary, secondary_age, harvest_rate) + frac_site_primary, frac_site_secondary, secondary_young_fraction, secondary_age, harvest_rate) ! ------------------------------------------------------------------------------------------- ! ! DESCRIPTION: - ! get the area-based harvest rates based on info passed to FATES from the bioundary conditions in. + ! get the area-based harvest rates based on info passed to FATES from the boundary conditions in. ! assumes logging_time == true ! Arguments @@ -364,6 +419,8 @@ subroutine get_harvest_rate_area (patch_land_use_label, hlm_harvest_catnames, hl integer, intent(in) :: patch_land_use_label ! patch level land_use_label real(r8), intent(in) :: secondary_age ! patch level age_since_anthro_disturbance real(r8), intent(in) :: frac_site_primary + real(r8), intent(in) :: frac_site_secondary + real(r8), intent(in) :: secondary_young_fraction ! what fraction of secondary land is young secondary land real(r8), intent(out) :: harvest_rate ! Local Variables @@ -396,19 +453,26 @@ subroutine get_harvest_rate_area (patch_land_use_label, hlm_harvest_catnames, hl ! Normalize by site-level primary or secondary forest fraction ! since harvest_rate is specified as a fraction of the gridcell ! also need to put a cap so as not to harvest more primary or secondary area than there is in a gridcell + ! For secondary, also need to normalize by the young/old fraction. if (patch_land_use_label .eq. primaryland) then if (frac_site_primary .gt. fates_tiny) then - harvest_rate = min((harvest_rate / frac_site_primary),frac_site_primary) + harvest_rate = min((harvest_rate / frac_site_primary),1._r8) else harvest_rate = 0._r8 endif - else - if ((1._r8-frac_site_primary) .gt. fates_tiny) then - harvest_rate = min((harvest_rate / (1._r8-frac_site_primary)),& - (1._r8-frac_site_primary)) + else if (patch_land_use_label .eq. secondaryland) then + ! the .gt. -0.5 in the next line is because frac_site_secondary returns -1 if no secondary area. + if (frac_site_secondary .gt. fates_tiny .and. frac_site_secondary .gt. -0.5_r8) then + if (secondary_age .lt. secondary_age_threshold) then + harvest_rate = min((harvest_rate / (frac_site_secondary * secondary_young_fraction)), 1._r8) + else + harvest_rate = min((harvest_rate / (frac_site_secondary * (1._r8 - secondary_young_fraction))), 1._r8) + endif else harvest_rate = 0._r8 endif + else + harvest_rate = 0._r8 endif ! calculate today's harvest rate @@ -983,7 +1047,7 @@ subroutine logging_litter_fluxes(currentSite, currentPatch, newPatch, patch_site ag_wood * logging_export_frac ! This is for checking the total mass balance [kg/site/day] - site_mass%wood_product = site_mass%wood_product + & + site_mass%wood_product_harvest(pft) = site_mass%wood_product_harvest(pft) + & ag_wood * logging_export_frac new_litt%ag_cwd(ncwd) = new_litt%ag_cwd(ncwd) + ag_wood * & @@ -1106,13 +1170,13 @@ subroutine UpdateHarvestC(currentSite,bc_out) use PRTGenericMod , only : element_pos use PRTGenericMod , only : carbon12_element use FatesInterfaceTypesMod , only : bc_out_type - use EDParamsMod , only : pprodharv10_forest_mean ! Arguments type(ed_site_type), intent(inout), target :: currentSite ! site structure type(bc_out_type), intent(inout) :: bc_out integer :: icode + integer :: i_pft real(r8) :: unit_trans_factor @@ -1123,13 +1187,26 @@ subroutine UpdateHarvestC(currentSite,bc_out) ! Calculate the unit transfer factor (from kgC m-2 day-1 to gC m-2 s-1) unit_trans_factor = g_per_kg * days_per_sec - bc_out%hrv_deadstemc_to_prod10c = bc_out%hrv_deadstemc_to_prod10c + & - currentSite%mass_balance(element_pos(carbon12_element))%wood_product * & - AREA_INV * pprodharv10_forest_mean * unit_trans_factor - bc_out%hrv_deadstemc_to_prod100c = bc_out%hrv_deadstemc_to_prod100c + & - currentSite%mass_balance(element_pos(carbon12_element))%wood_product * & - AREA_INV * (1._r8 - pprodharv10_forest_mean) * unit_trans_factor - + ! harvest-associated wood product pools + do i_pft = 1,numpft + bc_out%hrv_deadstemc_to_prod10c = bc_out%hrv_deadstemc_to_prod10c + & + currentSite%mass_balance(element_pos(carbon12_element))%wood_product_harvest(i_pft) * & + AREA_INV * EDPftvarcon_inst%harvest_pprod10(i_pft) * unit_trans_factor + bc_out%hrv_deadstemc_to_prod100c = bc_out%hrv_deadstemc_to_prod100c + & + currentSite%mass_balance(element_pos(carbon12_element))%wood_product_harvest(i_pft) * & + AREA_INV * (1._r8 - EDPftvarcon_inst%harvest_pprod10(i_pft)) * unit_trans_factor + end do + + ! land-use-change-associated wood product pools + do i_pft = 1,numpft + bc_out%hrv_deadstemc_to_prod10c = bc_out%hrv_deadstemc_to_prod10c + & + currentSite%mass_balance(element_pos(carbon12_element))%wood_product_landusechange(i_pft) * & + AREA_INV * EDPftvarcon_inst%landusechange_pprod10(i_pft) * unit_trans_factor + bc_out%hrv_deadstemc_to_prod100c = bc_out%hrv_deadstemc_to_prod100c + & + currentSite%mass_balance(element_pos(carbon12_element))%wood_product_landusechange(i_pft) * & + AREA_INV * (1._r8 - EDPftvarcon_inst%landusechange_pprod10(i_pft)) * unit_trans_factor + end do + return end subroutine UpdateHarvestC diff --git a/biogeochem/EDMortalityFunctionsMod.F90 b/biogeochem/EDMortalityFunctionsMod.F90 index fc941d0371..2778f3c0b7 100644 --- a/biogeochem/EDMortalityFunctionsMod.F90 +++ b/biogeochem/EDMortalityFunctionsMod.F90 @@ -12,7 +12,14 @@ module EDMortalityFunctionsMod use FatesCohortMod , only : fates_cohort_type use EDTypesMod , only : ed_site_type use EDParamsMod, only : maxpft + use EDParamsMod , only : mort_cstarvation_model use FatesConstantsMod , only : itrue,ifalse + use FatesConstantsMod , only : cstarvation_model_lin + use FatesConstantsMod , only : cstarvation_model_exp + use FatesConstantsMod , only : nearzero + use FatesConstantsMod , only : ihard_stress_decid + use FatesConstantsMod , only : isemi_stress_decid + use FatesConstantsMod , only : leaves_off use FatesAllometryMod , only : bleaf use FatesAllometryMod , only : storage_fraction_of_target use FatesInterfaceTypesMod , only : bc_in_type @@ -25,6 +32,7 @@ module EDMortalityFunctionsMod use PRTGenericMod, only : carbon12_element use PRTGenericMod, only : store_organ + use PRTParametersMod , only : prt_params use shr_log_mod , only : errMsg => shr_log_errMsg implicit none @@ -90,14 +98,27 @@ subroutine mortality_rates( cohort_in,bc_in, btran_ft, mean_temp, & real(r8) :: min_fmc_ar ! minimum fraction of maximum conductivity for absorbing root real(r8) :: min_fmc ! minimum fraction of maximum conductivity for whole plant real(r8) :: flc ! fractional loss of conductivity + logical :: is_decid_dormant ! Flag to signal that the cohort is deciduous and dormant + + real(r8), parameter :: frost_mort_buffer = 5.0_r8 ! 5deg buffer for freezing mortality logical, parameter :: test_zero_mortality = .false. ! Developer test which ! may help to debug carbon imbalances ! and the like + ! Check if the PFT is deciduous and leaves are completely abscised. If this is the case, + ! we prevent hydraulic failure mortality to occur as plants are leafless. For now, + ! semi-deciduous plants with senescing leaves may still die of hydraulic failure, but in + ! the future we could accelerate senescence to avoid mortality. Note that both drought + ! deciduous and cold deciduous are considered here to be consistent with the idea that + ! plants without leaves cannot die of hydraulic failure. + is_decid_dormant = & ! + ( prt_params%stress_decid(cohort_in%pft) == ihard_stress_decid .or. & ! Drought deciduous + prt_params%stress_decid(cohort_in%pft) == isemi_stress_decid .or. & ! Semi-deciduous + prt_params%season_decid(cohort_in%pft) == itrue ) .and. & ! Cold deciduous + ( cohort_in%status_coh == leaves_off ) ! ! Fully abscised - - ! Size Dependent Senescence + ! Size Dependent Senescence ! rate (r) and inflection point (ip) define the increase in mortality rate with dbh mort_r_size_senescence = EDPftvarcon_inst%mort_r_size_senescence(cohort_in%pft) mort_ip_size_senescence = EDPftvarcon_inst%mort_ip_size_senescence(cohort_in%pft) @@ -139,10 +160,11 @@ subroutine mortality_rates( cohort_in,bc_in, btran_ft, mean_temp, & bmort = EDPftvarcon_inst%bmort(cohort_in%pft) - ! Proxy for hydraulic failure induced mortality. + ! Proxy for hydraulic failure induced mortality. hf_sm_threshold = EDPftvarcon_inst%hf_sm_threshold(cohort_in%pft) hf_flc_threshold = EDPftvarcon_inst%hf_flc_threshold(cohort_in%pft) - if(hlm_use_planthydro.eq.itrue)then + + if (hlm_use_planthydro == itrue) then !note the flc is set as the fraction of max conductivity in hydro min_fmc_ag = minval(cohort_in%co_hydr%ftc_ag(:)) min_fmc_tr = cohort_in%co_hydr%ftc_troot @@ -156,36 +178,60 @@ subroutine mortality_rates( cohort_in,bc_in, btran_ft, mean_temp, & else hmort = 0.0_r8 endif + else - if( ( btran_ft(cohort_in%pft) <= hf_sm_threshold ) .and. & - ( ( minval(bc_in%t_soisno_sl) - tfrz ) > soil_tfrz_thresh ) ) then + ! When FATES-Hydro is off, hydraulic failure mortality occurs only when btran + ! falls below a threshold and plants have leaves. + if ( (.not. is_decid_dormant) .and. & + ( btran_ft(cohort_in%pft) <= hf_sm_threshold ) .and. & + ( ( minval(bc_in%t_soisno_sl) - tfrz ) > soil_tfrz_thresh ) ) then hmort = EDPftvarcon_inst%mort_scalar_hydrfailure(cohort_in%pft) else hmort = 0.0_r8 - endif - endif + end if + end if ! Carbon Starvation induced mortality. if ( cohort_in%dbh > 0._r8 ) then - ! We compare storage with leaf biomass if plant were fully flushed, otherwise - ! mortality would be underestimated for plants that lost all leaves and have no - ! storage to flush new ones. - ! MLO. Why isn't this comparing with storage allometry (i.e., accounting for - ! cushion)? + ! Find the current ratio between storage biomass and leaf biomass, which will be + ! used to define carbon starvation mortality. The reference leaf biomass is + ! always for when plants are fully flushed (but accounting for damage and + ! trimming). call bleaf(cohort_in%dbh,cohort_in%pft,cohort_in%crowndamage,cohort_in%canopy_trim, & 1.0_r8, target_leaf_c) store_c = cohort_in%prt%GetState(store_organ,carbon12_element) - call storage_fraction_of_target(target_leaf_c, store_c, frac) - if( frac .lt. 1._r8) then - cmort = max(0.0_r8,EDPftvarcon_inst%mort_scalar_cstarvation(cohort_in%pft) * & - (1.0_r8 - frac)) - else + + ! Select the carbon starvation mortality model (linear or exponential)s. + select case (mort_cstarvation_model) + case (cstarvation_model_lin) + ! Linear model. Carbon starvation mortality will be zero when fraction of + ! storage is greater than or equal to mort_upthresh_cstarvation, and will + ! increase to the maximum mortality (mort_scalar_cstarvation) when frac = 0. + cmort = EDPftvarcon_inst%mort_scalar_cstarvation(cohort_in%pft) * & + max(0.0_r8, (EDPftvarcon_inst%mort_upthresh_cstarvation(cohort_in%pft)-frac) / & + EDPftvarcon_inst%mort_upthresh_cstarvation(cohort_in%pft) ) + + case (cstarvation_model_exp) + ! Exponential model. Maximum carbon starvation mortality + ! (mort_scalar_cstarvation) occurs when frac=0. Parameter + ! mort_upthresh_cstarvation controls the the e-folding factor for frac. The + ! smaller the mort_upthresh_cstarvation, the faster the mortality will decay. + cmort = EDPftvarcon_inst%mort_scalar_cstarvation(cohort_in%pft) * & + exp(- frac / EDPftvarcon_inst%mort_upthresh_cstarvation(cohort_in%pft)) + + case default + write(fates_log(),*) & + 'Invalid carbon starvation model (',mort_cstarvation_model,').' + call endrun(msg=errMsg(sourcefile, __LINE__)) + end select + + ! Make sure the mortality is set to zero when tiny. + if (cmort <= nearzero) then cmort = 0.0_r8 - endif + end if - else write(fates_log(),*) 'dbh problem in mortality_rates', & cohort_in%dbh,cohort_in%pft,cohort_in%n,cohort_in%canopy_layer @@ -235,7 +281,7 @@ end subroutine mortality_rates subroutine Mortality_Derivative( currentSite, currentCohort, bc_in, btran_ft, & mean_temp, land_use_label, age_since_anthro_disturbance, & - frac_site_primary, harvestable_forest_c, harvest_tag) + frac_site_primary, frac_site_secondary, harvestable_forest_c, harvest_tag) ! ! !DESCRIPTION: @@ -255,6 +301,7 @@ subroutine Mortality_Derivative( currentSite, currentCohort, bc_in, btran_ft, & integer, intent(in) :: land_use_label real(r8), intent(in) :: age_since_anthro_disturbance real(r8), intent(in) :: frac_site_primary + real(r8), intent(in) :: frac_site_secondary real(r8), intent(in) :: harvestable_forest_c(:) ! total carbon available for logging, kgC site-1 integer, intent(out) :: harvest_tag(:) ! tag to record the harvest status @@ -283,7 +330,7 @@ subroutine Mortality_Derivative( currentSite, currentCohort, bc_in, btran_ft, & !if trees are in the canopy, then their death is 'disturbance'. This probably needs a different terminology call mortality_rates(currentCohort,bc_in,btran_ft, mean_temp, & cmort,hmort,bmort,frmort, smort, asmort, dgmort) - call LoggingMortality_frac(ipft, currentCohort%dbh, currentCohort%canopy_layer, & + call LoggingMortality_frac(currentSite, bc_in, ipft, currentCohort%dbh, currentCohort%canopy_layer, & currentCohort%lmort_direct, & currentCohort%lmort_collateral, & currentCohort%lmort_infra, & @@ -293,7 +340,7 @@ subroutine Mortality_Derivative( currentSite, currentCohort, bc_in, btran_ft, & bc_in%hlm_harvest_units, & land_use_label, & age_since_anthro_disturbance, & - frac_site_primary, harvestable_forest_c, harvest_tag) + frac_site_primary, frac_site_secondary, harvestable_forest_c, harvest_tag) if (currentCohort%canopy_layer > 1)then ! Include understory logging mortality rates not associated with disturbance diff --git a/biogeochem/EDPatchDynamicsMod.F90 b/biogeochem/EDPatchDynamicsMod.F90 index ec234bef76..586c3a1e3b 100644 --- a/biogeochem/EDPatchDynamicsMod.F90 +++ b/biogeochem/EDPatchDynamicsMod.F90 @@ -1,4 +1,3 @@ - module EDPatchDynamicsMod ! ============================================================================ ! Controls formation, creation, fusing and termination of patch level processes. @@ -43,11 +42,11 @@ module EDPatchDynamicsMod use FatesLitterMod , only : dl_sf use FatesConstantsMod , only : N_DIST_TYPES use EDTypesMod , only : AREA_INV + use EDTypesMod , only : dump_site use FatesConstantsMod , only : rsnbl_math_prec use FatesConstantsMod , only : fates_tiny use FatesConstantsMod , only : nocomp_bareground use FatesInterfaceTypesMod , only : hlm_use_planthydro - use FatesInterfaceTypesMod , only : hlm_numSWb use FatesInterfaceTypesMod , only : bc_in_type use FatesInterfaceTypesMod , only : numpft use FatesInterfaceTypesMod , only : hlm_stepsize @@ -72,6 +71,7 @@ module EDPatchDynamicsMod use EDLoggingMortalityMod, only : get_harvest_rate_carbon use EDLoggingMortalityMod, only : get_harvestable_carbon use EDLoggingMortalityMod, only : get_harvest_debt + use FatesLandUseChangeMod, only : GetInitLanduseHarvestRate use EDParamsMod , only : fates_mortality_disturbance_fraction use FatesAllometryMod , only : carea_allom use FatesAllometryMod , only : set_root_fraction @@ -81,8 +81,11 @@ module EDPatchDynamicsMod use FatesConstantsMod , only : years_per_day use FatesConstantsMod , only : nearzero use FatesConstantsMod , only : primaryland, secondaryland, pastureland, rangeland, cropland + use FatesConstantsMod , only : nocomp_bareground_land use FatesConstantsMod , only : n_landuse_cats - use FatesLandUseChangeMod, only : get_landuse_transition_rates + use FatesLandUseChangeMod, only : GetLanduseTransitionRates + use FatesLandUseChangeMod, only : GetInitLanduseTransitionRates + use FatesLandUseChangeMod, only : GetLUHStatedata use FatesConstantsMod , only : fates_unset_r8 use FatesConstantsMod , only : fates_unset_int use FatesConstantsMod , only : hlm_harvest_carbon @@ -106,7 +109,8 @@ module EDPatchDynamicsMod use FatesRunningMeanMod, only : ema_sdlng_mdd use FatesRunningMeanMod, only : ema_sdlng_emerg_h2o, ema_sdlng_mort_par, ema_sdlng2sap_par use FatesRunningMeanMod, only : ema_24hr, fixed_24hr, ema_lpa, ema_longterm - + use FatesRadiationMemMod, only : num_swb + ! CIME globals use shr_infnan_mod , only : nan => shr_infnan_nan, assignment(=) use shr_log_mod , only : errMsg => shr_log_errMsg @@ -123,7 +127,6 @@ module EDPatchDynamicsMod public :: check_patch_area public :: set_patchno private:: fuse_2_patches - public :: get_frac_site_primary character(len=*), parameter, private :: sourcefile = & __FILE__ @@ -204,21 +207,35 @@ subroutine disturbance_rates( site_in, bc_in) integer :: threshold_sizeclass integer :: i_dist integer :: h_index - real(r8) :: frac_site_primary real(r8) :: harvest_rate real(r8) :: tempsum real(r8) :: mean_temp real(r8) :: harvestable_forest_c(hlm_num_lu_harvest_cats) integer :: harvest_tag(hlm_num_lu_harvest_cats) - real(r8) :: landuse_transition_matrix(n_landuse_cats, n_landuse_cats) ! [m2/m2/day] real(r8) :: current_fates_landuse_state_vector(n_landuse_cats) ! [m2/m2] + real(r8) :: state_vector(n_landuse_cats) + real(r8), parameter :: max_daily_disturbance_rate = 0.999_r8 + logical :: site_secondaryland_first_exceeding_min + real(r8) :: secondary_young_fraction ! what fraction of secondary land is young secondary land !---------------------------------------------------------------------------------------------- ! Calculate Mortality Rates (these were previously calculated during growth derivatives) ! And the same rates in understory plants have already been applied to %dndt !---------------------------------------------------------------------------------------------- ! first calculate the fraction of the site that is primary land - call get_frac_site_primary(site_in, frac_site_primary) + current_fates_landuse_state_vector = site_in%get_current_landuse_statevector() + + ! and get the fraction of secondary land that is young secondary land + secondary_young_fraction = site_in%get_secondary_young_fraction() + + ! check status of transition_landuse_from_off_to_on flag, and do some error checking on it + if(site_in%transition_landuse_from_off_to_on) then + if (sum(current_fates_landuse_state_vector(secondaryland:cropland)) .gt. nearzero) then + write(fates_log(),*) 'flag for transition_landuse_from_off_to_on is set to true but site is not entirely primaryland' + write(fates_log(), *) current_fates_landuse_state_vector + call endrun(msg=errMsg(sourcefile, __LINE__)) + endif + endif ! get available biomass for harvest for all patches call get_harvestable_carbon(site_in, bc_in%site_area, bc_in%hlm_harvest_catnames, harvestable_forest_c) @@ -246,14 +263,16 @@ subroutine disturbance_rates( site_in, bc_in) currentCohort%asmort = asmort currentCohort%dgmort = dgmort - call LoggingMortality_frac(currentCohort%pft, currentCohort%dbh, currentCohort%canopy_layer, & + call LoggingMortality_frac(site_in, bc_in, currentCohort%pft, & + currentCohort%dbh, currentCohort%canopy_layer, & lmort_direct,lmort_collateral,lmort_infra,l_degrad,& bc_in%hlm_harvest_rates, & bc_in%hlm_harvest_catnames, & bc_in%hlm_harvest_units, & currentPatch%land_use_label, & currentPatch%age_since_anthro_disturbance, & - frac_site_primary, & + current_fates_landuse_state_vector(primaryland), & + current_fates_landuse_state_vector(secondaryland), & harvestable_forest_c, & harvest_tag) @@ -271,21 +290,17 @@ subroutine disturbance_rates( site_in, bc_in) call get_harvest_debt(site_in, bc_in, harvest_tag) if ( hlm_use_luh .eq. itrue ) then - call get_landuse_transition_rates(bc_in, landuse_transition_matrix) + if(.not. site_in%transition_landuse_from_off_to_on) then + call GetLanduseTransitionRates(bc_in, site_in%min_allowed_landuse_fraction, & + site_in%landuse_transition_matrix, site_in%landuse_vector_gt_min) + else + call GetInitLanduseTransitionRates(bc_in, site_in%min_allowed_landuse_fraction, & + site_in%landuse_transition_matrix, site_in%landuse_vector_gt_min) + endif else - landuse_transition_matrix(:,:) = 0._r8 + site_in%landuse_transition_matrix(:,:) = 0._r8 endif - ! calculate total area in each landuse category - current_fates_landuse_state_vector(:) = 0._r8 - currentPatch => site_in%oldest_patch - do while (associated(currentPatch)) - current_fates_landuse_state_vector(currentPatch%land_use_label) = & - current_fates_landuse_state_vector(currentPatch%land_use_label) + & - currentPatch%area/AREA - currentPatch => currentPatch%younger - end do - ! --------------------------------------------------------------------------------------------- ! Calculate Disturbance Rates based on the mortality rates just calculated ! --------------------------------------------------------------------------------------------- @@ -304,6 +319,16 @@ subroutine disturbance_rates( site_in, bc_in) currentPatch => currentPatch%younger end do + ! get some info needed to determine whether or not to apply land use change + site_secondaryland_first_exceeding_min = .false. + if (hlm_use_luh .eq. itrue) then + call GetLUHStatedata(bc_in, state_vector) + site_secondaryland_first_exceeding_min = (state_vector(secondaryland) .gt. site_in%min_allowed_landuse_fraction) & + .and. (.not. site_in%landuse_vector_gt_min(secondaryland)) + else + state_vector = current_fates_landuse_state_vector + end if + currentPatch => site_in%oldest_patch do while (associated(currentPatch)) @@ -313,10 +338,18 @@ subroutine disturbance_rates( site_in, bc_in) dist_rate_ldist_notharvested = 0.0_r8 - ! Avoid this calculation to avoid NaN due to division by zero result if luh is not used - if (hlm_use_luh .eq. itrue) then + ! transition matrix has units of area transitioned per unit area of the whole gridcell per time; + ! need to change to area transitioned per unit area of that land-use type per time; + ! because the land use state vector sums to one minus area bareground, need to also divide by that + ! (or rather, multiply since it is in the denominator of the denominator) + ! Avoid this calculation to avoid NaN due to division by zero result if luh is not used or applying + ! to bare ground note that an alternative here might be to use what LUH thinks the state vector + ! should be instead of what the FATES state vector is, in order to not amplify small deviations + ! between the two... + if (hlm_use_luh .eq. itrue .and. currentPatch%land_use_label .gt. nocomp_bareground_land) then currentPatch%landuse_transition_rates(1:n_landuse_cats) = min(1._r8, & - landuse_transition_matrix(currentPatch%land_use_label,1:n_landuse_cats) / & + site_in%landuse_transition_matrix(currentPatch%land_use_label,1:n_landuse_cats) & + * (1._r8 - site_in%area_bareground) / & current_fates_landuse_state_vector(currentPatch%land_use_label)) else currentPatch%landuse_transition_rates = 0.0_r8 @@ -357,18 +390,37 @@ subroutine disturbance_rates( site_in, bc_in) ! for non-closed-canopy areas subject to logging, add an additional increment of area disturbed ! equivalent to the fraction logged to account for transfer of interstitial ground area to new secondary lands - if ( logging_time .and. & + if ( (logging_time .or. site_in%transition_landuse_from_off_to_on .or. site_secondaryland_first_exceeding_min) .and. & (currentPatch%area - currentPatch%total_canopy_area) .gt. fates_tiny ) then ! The canopy is NOT closed. - if(bc_in%hlm_harvest_units == hlm_harvest_carbon) then - call get_harvest_rate_carbon (currentPatch%land_use_label, bc_in%hlm_harvest_catnames, & - bc_in%hlm_harvest_rates, currentPatch%age_since_anthro_disturbance, harvestable_forest_c, & - harvest_rate, harvest_tag) + if (.not. site_in%transition_landuse_from_off_to_on) then + if(bc_in%hlm_harvest_units == hlm_harvest_carbon) then + call get_harvest_rate_carbon (currentPatch%land_use_label, bc_in%hlm_harvest_catnames, & + bc_in%hlm_harvest_rates, currentPatch%age_since_anthro_disturbance, harvestable_forest_c, & + harvest_rate, harvest_tag) + else + call get_harvest_rate_area (currentPatch%land_use_label, bc_in%hlm_harvest_catnames, & + bc_in%hlm_harvest_rates, current_fates_landuse_state_vector(primaryland), & + current_fates_landuse_state_vector(secondaryland), secondary_young_fraction, & + currentPatch%age_since_anthro_disturbance, harvest_rate) + end if + + ! if the total intended area of secondary lands are less than what we can consider + ! without having too-small patches, or if that was the case until just now, + ! then there is special logic + if (state_vector(secondaryland) .le. site_in%min_allowed_landuse_fraction) then + harvest_rate = 0._r8 + else if (currentPatch%land_use_label .eq. primaryland .and. .not. & + site_in%landuse_vector_gt_min(secondaryland)) then + harvest_rate = state_vector(secondaryland) / sum(state_vector(:)) + else + harvest_rate = 0._r8 + end if else - call get_harvest_rate_area (currentPatch%land_use_label, bc_in%hlm_harvest_catnames, & - bc_in%hlm_harvest_rates, frac_site_primary, currentPatch%age_since_anthro_disturbance, harvest_rate) - end if + call GetInitLanduseHarvestRate(bc_in, site_in%min_allowed_landuse_fraction, & + harvest_rate, site_in%landuse_vector_gt_min) + endif currentPatch%disturbance_rates(dtype_ilog) = currentPatch%disturbance_rates(dtype_ilog) + & (currentPatch%area - currentPatch%total_canopy_area) * harvest_rate / currentPatch%area @@ -399,20 +451,42 @@ subroutine disturbance_rates( site_in, bc_in) call FatesWarn(msg,index=2) endif - ! if the sum of all disturbance rates is such that they will exceed total patch area on this day, then reduce them all proportionally. - if ( (sum(currentPatch%disturbance_rates(:)) + sum(currentPatch%landuse_transition_rates(1:n_landuse_cats))) .gt. 1.0_r8 ) then + ! if the sum of all disturbance rates is such that they will exceed total patch area on this day, + ! then reduce them all proportionally. + + if ( (sum(currentPatch%disturbance_rates(:)) + sum(currentPatch%landuse_transition_rates(1:n_landuse_cats))) .gt. & + max_daily_disturbance_rate ) then tempsum = sum(currentPatch%disturbance_rates(:)) + sum(currentPatch%landuse_transition_rates(1:n_landuse_cats)) do i_dist = 1,N_DIST_TYPES - currentPatch%disturbance_rates(i_dist) = currentPatch%disturbance_rates(i_dist) / tempsum + currentPatch%disturbance_rates(i_dist) = max_daily_disturbance_rate * currentPatch%disturbance_rates(i_dist) & + / tempsum end do do i_dist = 1,n_landuse_cats - currentPatch%landuse_transition_rates(i_dist) = currentPatch%landuse_transition_rates(i_dist) / tempsum + currentPatch%landuse_transition_rates(i_dist) = max_daily_disturbance_rate * & + currentPatch%landuse_transition_rates(i_dist) / tempsum end do endif currentPatch => currentPatch%younger - enddo !patch loop + enddo !patch loop + + ! if the area of secondary land has just exceeded the minimum below which we ignore things, + ! set the flag to keep track of that. + if ( (state_vector(secondaryland) .gt. site_in%min_allowed_landuse_fraction) .and. & + (.not. site_in%landuse_vector_gt_min(secondaryland)) ) then + site_in%landuse_vector_gt_min(secondaryland) = .true. + write(fates_log(),*) 'setting site_in%landuse_vector_gt_min(secondaryland) = .true.' + if (debug) then + currentPatch => site_in%oldest_patch + do while (associated(currentPatch)) + write(fates_log(),*) 'cpatch area, LU, distrates(ilog): ', currentPatch%area, currentPatch%land_use_label, & + currentPatch%nocomp_pft_label, currentPatch%disturbance_rates(dtype_ilog), & + currentPatch%area - currentPatch%total_canopy_area + currentPatch => currentPatch%younger + end do + end if + end if end subroutine disturbance_rates @@ -440,8 +514,7 @@ subroutine spawn_patches( currentSite, bc_in) use EDParamsMod , only : ED_val_understorey_death, logging_coll_under_frac use EDCohortDynamicsMod , only : terminate_cohorts use FatesConstantsMod , only : rsnbl_math_prec - use FatesLandUseChangeMod, only : get_landuse_transition_rates - use FatesLandUseChangeMod, only : get_landusechange_rules + use FatesLandUseChangeMod, only : GetLanduseChangeRules ! ! !ARGUMENTS: type (ed_site_type), intent(inout) :: currentSite @@ -482,7 +555,20 @@ subroutine spawn_patches( currentSite, bc_in) real(r8) :: disturbance_rate ! rate of disturbance being resolved [fraction of patch area / day] real(r8) :: oldarea ! old patch area prior to disturbance logical :: clearing_matrix(n_landuse_cats,n_landuse_cats) ! do we clear vegetation when transferring from one LU type to another? - + type (fates_patch_type) , pointer :: buffer_patch, temp_patch, copyPatch, previousPatch + real(r8) :: nocomp_pft_area_vector(numpft) + real(r8) :: nocomp_pft_area_vector_filled(numpft) + real(r8) :: nocomp_pft_area_vector_alt(numpft) + real(r8) :: newp_area_buffer_frac(numpft) + real(r8) :: newp_area_vector(numpft) + real(r8) :: max_val + integer :: i_land_use_label + integer :: i_pft + real(r8) :: newp_area, area_to_keep, fraction_to_keep + logical :: buffer_patch_in_linked_list + integer :: n_pfts_by_landuse + integer :: which_pft_allowed + logical :: buffer_patch_used !--------------------------------------------------------------------- storesmallcohort => null() ! storage of the smallest cohort for insertion routine @@ -500,8 +586,8 @@ subroutine spawn_patches( currentSite, bc_in) currentSite%disturbance_rates(:,:,:) = 0._r8 ! get rules for vegetation clearing during land use change - call get_landusechange_rules(clearing_matrix) - + call GetLanduseChangeRules(clearing_matrix) + ! in the nocomp cases, since every patch has a PFT identity, it can only receive patch area from patches ! that have the same identity. In order to allow this, we have this very high level loop over nocomp PFTs ! and only do the disturbance for any patches that have that nocomp PFT identity. @@ -511,7 +597,8 @@ subroutine spawn_patches( currentSite, bc_in) ! we want at the second-outermost loop to go through all disturbance types, because we resolve each of these separately disturbance_type_loop: do i_disturbance_type = 1,N_DIST_TYPES - ! the next loop level is to go through patches that have a specific land-use type. the reason to do this is because the combination of + ! the next loop level is to go through patches that have a specific land-use type. the reason to do this + ! is because the combination of ! disturbance type and donor land-use type uniquly define the land-use type of the receiver patch. landuse_donortype_loop: do i_donorpatch_landuse_type = 1, n_landuse_cats @@ -520,7 +607,8 @@ subroutine spawn_patches( currentSite, bc_in) ! for fire and treefall disturbance, receiver land-use type is whatever the donor land-use type is. ! for logging disturbance, receiver land-use type is always secondary lands - ! for land-use-change disturbance, we need to loop over all possible transition types for land-use-change from the current land-use type. + ! for land-use-change disturbance, we need to loop over all possible transition types for land-use-change from + ! the current land-use type. select case(i_disturbance_type) case(dtype_ifire) @@ -533,7 +621,8 @@ subroutine spawn_patches( currentSite, bc_in) start_receiver_lulabel = secondaryland end_receiver_lulabel = secondaryland case(dtype_ilandusechange) - start_receiver_lulabel = 1 ! this could actually maybe be 2, as primaryland column of matrix should all be zeros, but leave as 1 for now + start_receiver_lulabel = 1 ! this could actually maybe be 2, as primaryland column of matrix should + ! all be zeros, but leave as 1 for now end_receiver_lulabel = n_landuse_cats case default write(fates_log(),*) 'unknown disturbance mode?' @@ -543,19 +632,24 @@ subroutine spawn_patches( currentSite, bc_in) ! next loop level is the set of possible receiver patch land use types. ! for disturbance types other than land use change, this is sort of a dummy loop, per the above logic. - landusechange_receiverpatchlabel_loop: do i_landusechange_receiverpatchlabel = start_receiver_lulabel, end_receiver_lulabel + landusechange_receiverpatchlabel_loop: do i_landusechange_receiverpatchlabel = start_receiver_lulabel, & + end_receiver_lulabel ! now we want to begin resolving all of the disturbance given the above categorical criteria of: - ! nocomp-PFT, disturbance type, donor patch land use label, and receiver patch land use label. All of the disturbed area that meets these - ! criteria (if any) will be put into a new patch whose area and properties are taken from one or more donor patches. + ! nocomp-PFT, disturbance type, donor patch land use label, and receiver patch land use label. + ! All of the disturbed area that meets these criteria (if any) will be put into a new patch whose area and + ! properties are taken from one or more donor patches. - ! calculate area of disturbed land that meets the above criteria, in this timestep, by summing contributions from each existing patch. + ! calculate area of disturbed land that meets the above criteria, in this timestep, by summing contributions + ! from each existing patch. currentPatch => currentSite%youngest_patch - ! this variable site_areadis holds all the newly disturbed area from all patches for all disturbance being resolved now. + ! this variable site_areadis holds all the newly disturbed area from all patches for all disturbance being + ! resolved now. site_areadis = 0.0_r8 - ! loop over all patches to figure out the total patch area generated as a result of all disturbance being resolved now. + ! loop over all patches to figure out the total patch area generated as a result of all disturbance being + ! resolved now. patchloop_areadis: do while(associated(currentPatch)) cp_nocomp_matches_1_if: if ( hlm_use_nocomp .eq. ifalse .or. & @@ -603,7 +697,7 @@ subroutine spawn_patches( currentSite, bc_in) allocate(newPatch) call newPatch%Create(age, site_areadis, i_landusechange_receiverpatchlabel, i_nocomp_pft, & - hlm_numSWb, numpft, currentSite%nlevsoil, hlm_current_tod, & + num_swb, numpft, currentSite%nlevsoil, hlm_current_tod, & regeneration_model) ! Initialize the litter pools to zero, these @@ -678,14 +772,21 @@ subroutine spawn_patches( currentSite, bc_in) currentPatch%burnt_frac_litter(:) = 0._r8 end if + call CopyPatchMeansTimers(currentPatch, newPatch) + call TransLitterNewPatch( currentSite, currentPatch, newPatch, patch_site_areadis) ! Transfer in litter fluxes from plants in various contexts of death and destruction - select case(i_disturbance_type) case (dtype_ilog) call logging_litter_fluxes(currentSite, currentPatch, & newPatch, patch_site_areadis,bc_in) + + ! if transitioning from primary to secondary, then may need to change nocomp pft, + ! so tag as having transitioned LU + if ( i_disturbance_type .eq. dtype_ilog .and. i_donorpatch_landuse_type .eq. primaryland) then + newPatch%changed_landuse_this_ts = .true. + end if case (dtype_ifire) call fire_litter_fluxes(currentSite, currentPatch, & newPatch, patch_site_areadis,bc_in) @@ -696,33 +797,15 @@ subroutine spawn_patches( currentSite, bc_in) call landusechange_litter_fluxes(currentSite, currentPatch, & newPatch, patch_site_areadis,bc_in, & clearing_matrix(i_donorpatch_landuse_type,i_landusechange_receiverpatchlabel)) + + ! if land use change, then may need to change nocomp pft, so tag as having transitioned LU + newPatch%changed_landuse_this_ts = .true. case default write(fates_log(),*) 'unknown disturbance mode?' write(fates_log(),*) 'i_disturbance_type: ',i_disturbance_type call endrun(msg=errMsg(sourcefile, __LINE__)) end select - - ! Copy any means or timers from the original patch to the new patch - ! These values will inherit all info from the original patch - ! -------------------------------------------------------------------------- - call newPatch%tveg24%CopyFromDonor(currentPatch%tveg24) - call newPatch%tveg_lpa%CopyFromDonor(currentPatch%tveg_lpa) - call newPatch%tveg_longterm%CopyFromDonor(currentPatch%tveg_longterm) - - - if ( regeneration_model == TRS_regeneration ) then - call newPatch%seedling_layer_par24%CopyFromDonor(currentPatch%seedling_layer_par24) - call newPatch%sdlng_mort_par%CopyFromDonor(currentPatch%sdlng_mort_par) - call newPatch%sdlng2sap_par%CopyFromDonor(currentPatch%sdlng2sap_par) - do pft = 1,numpft - call newPatch%sdlng_emerg_smp(pft)%p%CopyFromDonor(currentPatch%sdlng_emerg_smp(pft)%p) - call newPatch%sdlng_mdd(pft)%p%CopyFromDonor(currentPatch%sdlng_mdd(pft)%p) - enddo - end if - - call newPatch%tveg_longterm%CopyFromDonor(currentPatch%tveg_longterm) - ! -------------------------------------------------------------------------- ! The newly formed patch from disturbance (newPatch), has now been given ! some litter from dead plants and pre-existing litter from the donor patches. @@ -766,7 +849,8 @@ subroutine spawn_patches( currentSite, bc_in) store_c = currentCohort%prt%GetState(store_organ, carbon12_element) total_c = sapw_c + struct_c + leaf_c + fnrt_c + store_c - ! survivorship of plants in both the disturbed and undisturbed cohorts depends on what type of disturbance is happening. + ! survivorship of plants in both the disturbed and undisturbed cohorts depends on what type of + ! disturbance is happening. disttype_case: select case(i_disturbance_type) @@ -1190,7 +1274,7 @@ subroutine spawn_patches( currentSite, bc_in) newPatch%shortest => nc nc%shorter => null() endif - !nc%patchptr => new_patch + call insert_cohort(newPatch, nc, newPatch%tallest, newPatch%shortest, & tnull, snull, storebigcohort, storesmallcohort) @@ -1281,6 +1365,296 @@ subroutine spawn_patches( currentSite, bc_in) end do nocomp_pft_loop + nocomp_and_luh_if: if ( hlm_use_nocomp .eq. itrue .and. hlm_use_luh .eq. itrue ) then + ! disturbance has just happened, and now the nocomp PFT identities of the newly-disturbed patches + ! need to be remapped to those associated with the new land use type. + + ! logic: loop over land use types. figure out the nocomp PFT fractions for all newly-disturbed patches that have become that land use type. + ! if the + + lu_loop: do i_land_use_label = n_landuse_cats, 1, -1 + + nocomp_pft_area_vector(:) = 0._r8 + nocomp_pft_area_vector_filled(:) = 0._r8 + + currentPatch => currentSite%oldest_patch + do while(associated(currentPatch)) + if (currentPatch%changed_landuse_this_ts .and. currentPatch%land_use_label .eq. i_land_use_label) then + nocomp_pft_area_vector(currentPatch%nocomp_pft_label) = nocomp_pft_area_vector(currentPatch%nocomp_pft_label) + currentPatch%area + copyPatch => currentPatch + end if + currentPatch => currentPatch%younger + end do + + ! figure out how may PFTs on each land use type. if only 1, then the next calculation is much simpler: we just need to know which PFT is allowed. + n_pfts_by_landuse = 0 + do i_pft = 1,numpft + if ( currentSite%area_pft(i_pft,i_land_use_label) .gt. nearzero) then + n_pfts_by_landuse = n_pfts_by_landuse + 1 + which_pft_allowed = i_pft + end if + end do + if ( n_pfts_by_landuse .ne. 1) then + which_pft_allowed = fates_unset_int + endif + + patch_area_to_reallocate_if: if ( sum(nocomp_pft_area_vector(:)) .gt. nearzero ) then + more_than_1_pft_to_handle_if: if ( n_pfts_by_landuse .ne. 1 ) then + ! create buffer patch to put all of the pieces carved off of other patches + allocate(buffer_patch) + + call buffer_patch%Create(0._r8, 0._r8, i_land_use_label, 0, & + num_swb, numpft, currentSite%nlevsoil, hlm_current_tod, & + regeneration_model) + + ! Initialize the litter pools to zero + do el=1,num_elements + call buffer_patch%litter(el)%InitConditions(init_leaf_fines=0._r8, & + init_root_fines=0._r8, & + init_ag_cwd=0._r8, & + init_bg_cwd=0._r8, & + init_seed=0._r8, & + init_seed_germ=0._r8) + end do + buffer_patch%tallest => null() + buffer_patch%shortest => null() + + call CopyPatchMeansTimers(copyPatch, buffer_patch) + + ! make a note that this buffer patch has not been put into the linked list + buffer_patch_in_linked_list = .false. + buffer_patch_used = .false. + + currentPatch => currentSite%oldest_patch + do while(associated(currentPatch)) + if (currentPatch%changed_landuse_this_ts .and. currentPatch%land_use_label .eq. i_land_use_label) then + + ! Calculate the areas to be given to potentially give to the buffer patch and those to keep in the current patch + area_to_keep = currentSite%area_pft(currentPatch%nocomp_pft_label,i_land_use_label) * sum(nocomp_pft_area_vector(:)) - & + nocomp_pft_area_vector_filled(currentPatch%nocomp_pft_label) + newp_area = currentPatch%area - area_to_keep + fraction_to_keep = area_to_keep / currentPatch%area + + if (fraction_to_keep .le. nearzero .or. area_to_keep .lt. rsnbl_math_prec) then + ! we don't want any patch area with this PFT identity at all anymore. Fuse it into the buffer patch. + + currentPatch%nocomp_pft_label = 0 + if (associated(currentPatch%older)) then + previousPatch => currentPatch%older + else + previousPatch => currentPatch + endif + + call fuse_2_patches(currentSite, currentPatch, buffer_patch) + currentPatch => previousPatch + + buffer_patch_used = .true. + + elseif ( area_to_keep .ge. rsnbl_math_prec .and. newp_area .ge. rsnbl_math_prec) then + ! we have more patch are of this PFT than we want, but we do want to keep some of it. + ! we want to split the patch into two here. leave one patch as-is, and put the rest into the buffer patch. + + allocate(temp_patch) + + call split_patch(currentSite, currentPatch, temp_patch, fraction_to_keep, newp_area) + ! + temp_patch%nocomp_pft_label = 0 + + call fuse_2_patches(currentSite, temp_patch, buffer_patch) + ! + nocomp_pft_area_vector_filled(currentPatch%nocomp_pft_label) = & + nocomp_pft_area_vector_filled(currentPatch%nocomp_pft_label) + currentPatch%area + + currentPatch%changed_landuse_this_ts = .false. + + buffer_patch_used = .true. + else + ! we want to keep all of this patch (and possibly more) + + nocomp_pft_area_vector_filled(currentPatch%nocomp_pft_label) = & + nocomp_pft_area_vector_filled(currentPatch%nocomp_pft_label) + currentPatch%area + currentPatch%changed_landuse_this_ts = .false. + + endif + end if + + currentPatch => currentPatch%younger + end do + + buffer_patch_used_if: if ( buffer_patch_used ) then + ! at this point, lets check that the total patch area remaining to be relabelled equals what we think that it is. + if (abs(sum(nocomp_pft_area_vector(:) - nocomp_pft_area_vector_filled(:)) - buffer_patch%area) .gt. rsnbl_math_prec) then + write(fates_log(),*) 'midway through patch reallocation and things are already not adding up.', i_land_use_label + write(fates_log(),*) currentSite%area_pft(:,i_land_use_label) + write(fates_log(),*) '-----' + write(fates_log(),*) nocomp_pft_area_vector_filled + write(fates_log(),*) '-----' + write(fates_log(),*) nocomp_pft_area_vector + write(fates_log(),*) '-----' + write(fates_log(),*) buffer_patch%area, buffer_patch%land_use_label, buffer_patch%nocomp_pft_label + write(fates_log(),*) sum(nocomp_pft_area_vector(:)), sum(nocomp_pft_area_vector_filled(:)), buffer_patch%area + currentPatch => currentSite%oldest_patch + do while(associated(currentPatch)) + write(fates_log(),*) currentPatch%area, currentPatch%land_use_label, currentPatch%nocomp_pft_label + currentPatch => currentPatch%younger + end do + call dump_site(currentSite) + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + + ! It's possible that we only need to move all of the buffer into one patch, so first determine what the new patch areas look + ! like and compare to the buffer patch area + newp_area_vector(:)= (currentSite%area_pft(:,i_land_use_label) * sum(nocomp_pft_area_vector(:))) - nocomp_pft_area_vector_filled(:) + newp_area_buffer_frac(:) = newp_area_vector(:) / buffer_patch%area + + ! Find the maximum value of the vector + max_val = maxval(newp_area_buffer_frac) + + ! If the max value is the only value in the array then loop through the array to find the max value pft index and insert buffer + if (abs(sum(newp_area_buffer_frac(:)) - max_val) .le. nearzero) then + i_pft = 1 + do while(.not. buffer_patch_in_linked_list) + if (abs(newp_area_buffer_frac(i_pft) - max_val) .le. nearzero) then + + ! give the buffer patch the intended nocomp PFT label + buffer_patch%nocomp_pft_label = i_pft + + ! track that we have added this patch area + nocomp_pft_area_vector_filled(i_pft) = nocomp_pft_area_vector_filled(i_pft) + buffer_patch%area + + ! put the buffer patch directly into the linked list + call InsertPatch(currentSite, buffer_patch) + + ! Set flag to skip the next pft loop + buffer_patch_in_linked_list = .true. + end if + i_pft = i_pft + 1 + end do + end if + + ! Now we need to loop through the nocomp PFTs, and split the buffer patch into a set of patches to put back in the linked list + ! if not already done so above + nocomp_pft_loop_2: do i_pft = 1, numpft + + ! Check the area fraction to makes sure that this pft should have area. Also make sure that the buffer patch hasn't been + ! added to the linked list already + if ( currentSite%area_pft(i_pft,i_land_use_label) .gt. nearzero .and. .not. buffer_patch_in_linked_list) then + + ! Slightly complicated way of making sure that the same pfts are subtracted from each other which may help to avoid precision + ! errors due to differencing between very large and very small areas + nocomp_pft_area_vector_alt(:) = nocomp_pft_area_vector(:) + nocomp_pft_area_vector_alt(i_pft) = 0._r8 + newp_area = (currentSite%area_pft(i_pft,i_land_use_label) * nocomp_pft_area_vector(i_pft)) - nocomp_pft_area_vector_filled(i_pft) + newp_area = newp_area + sum(currentSite%area_pft(i_pft,i_land_use_label)*nocomp_pft_area_vector_alt(:)) + + ! Compute area and fraction to keep in buffer + area_to_keep = buffer_patch%area - newp_area + fraction_to_keep = area_to_keep / buffer_patch%area + + ! only bother doing this if the new new patch area needed is greater than some tiny amount + if ( newp_area .gt. rsnbl_math_prec * 0.01_r8) then + + if (area_to_keep .gt. rsnbl_math_prec) then + + ! split buffer patch in two, keeping the smaller buffer patch to put into new patches + allocate(temp_patch) + + call split_patch(currentSite, buffer_patch, temp_patch, fraction_to_keep, newp_area) + + ! give the new patch the intended nocomp PFT label + temp_patch%nocomp_pft_label = i_pft + + ! track that we have added this patch area + nocomp_pft_area_vector_filled(i_pft) = nocomp_pft_area_vector_filled(i_pft) + temp_patch%area + + ! put the new patch into the linked list + call InsertPatch(currentSite, temp_patch) + + else + ! give the buffer patch the intended nocomp PFT label + buffer_patch%nocomp_pft_label = i_pft + + ! track that we have added this patch area + nocomp_pft_area_vector_filled(i_pft) = nocomp_pft_area_vector_filled(i_pft) + buffer_patch%area + + ! put the buffer patch directly into the linked list + call InsertPatch(currentSite, buffer_patch) + + buffer_patch_in_linked_list = .true. + + end if + end if + end if + end do nocomp_pft_loop_2 + + ! now we want to make sure that either the buffer_patch has zero area (presumably it was never used), + ! in which case it should be deallocated, or else it does have area but it has been put into the site + ! linked list. if either of those, that means everything worked properly, if not, then something has gone wrong. + if ( .not. buffer_patch_in_linked_list) then + if (buffer_patch%area .lt. rsnbl_math_prec) then + ! here we need to deallocate the buffer patch so that we don't get a memory leak. + call buffer_patch%FreeMemory(regeneration_model, numpft) + deallocate(buffer_patch, stat=istat, errmsg=smsg) + if (istat/=0) then + write(fates_log(),*) 'dealloc: fail on deallocate(dp):'//trim(smsg) + call endrun(msg=errMsg(sourcefile, __LINE__)) + endif + else + write(fates_log(),*) 'Buffer patch still has area and it wasnt put into the linked list' + write(fates_log(),*) 'buffer_patch%area', buffer_patch%area + write(fates_log(),*) sum(nocomp_pft_area_vector_filled(:)), sum(nocomp_pft_area_vector(:)) + write(fates_log(),*) sum(nocomp_pft_area_vector_filled(:) - nocomp_pft_area_vector(:)) + + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + end if + else + ! buffer patch was never even used. deallocate. + call buffer_patch%FreeMemory(regeneration_model, numpft) + deallocate(buffer_patch, stat=istat, errmsg=smsg) + if (istat/=0) then + write(fates_log(),*) 'dealloc: fail on deallocate(dp):'//trim(smsg) + call endrun(msg=errMsg(sourcefile, __LINE__)) + endif + end if buffer_patch_used_if + + ! check that the area we have added is the same as the area we have taken away. if not, crash. + if ( abs(sum(nocomp_pft_area_vector_filled(:) - nocomp_pft_area_vector(:))) .gt. rsnbl_math_prec) then + write(fates_log(),*) 'patch reallocation logic doesnt add up. difference is: ', sum(nocomp_pft_area_vector_filled(:) - nocomp_pft_area_vector(:)) + write(fates_log(),*) nocomp_pft_area_vector_filled + write(fates_log(),*) nocomp_pft_area_vector + write(fates_log(),*) i_land_use_label + currentPatch => currentSite%oldest_patch + do while(associated(currentPatch)) + write(fates_log(),*) currentPatch%area, currentPatch%land_use_label, currentPatch%nocomp_pft_label + currentPatch => currentPatch%younger + end do + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + else + ! if there is only one PFT allowed on this land use type, then all we need to do is relabel all of the patches that just changed + ! land use type and let patch fusion take care of the rest. + currentPatch => currentSite%oldest_patch + do while(associated(currentPatch)) + if (currentPatch%changed_landuse_this_ts .and. currentPatch%land_use_label .eq. i_land_use_label) then + currentPatch%nocomp_pft_label = which_pft_allowed + currentPatch%changed_landuse_this_ts = .false. + end if + currentPatch => currentPatch%younger + end do + endif more_than_1_pft_to_handle_if + end if patch_area_to_reallocate_if + call check_patch_area(currentSite) + end do lu_loop + else + ! if not using a configuration where the changed_landuse_this_ts is relevant, loop through all patches and reset it + currentPatch => currentSite%oldest_patch + do while(associated(currentPatch)) + currentPatch%changed_landuse_this_ts = .false. + currentPatch => currentPatch%younger + end do + endif nocomp_and_luh_if + !zero disturbance rate trackers on all patches currentPatch => currentSite%oldest_patch do while(associated(currentPatch)) @@ -1292,6 +1666,130 @@ subroutine spawn_patches( currentSite, bc_in) return end subroutine spawn_patches + ! ----------------------------------------------------------------------------------------- + + subroutine split_patch(currentSite, currentPatch, new_patch, fraction_to_keep, area_to_remove) + ! + ! !DESCRIPTION: + ! Split a patch into two patches that are identical except in their areas + ! + ! !ARGUMENTS: + type(ed_site_type),intent(inout) :: currentSite + type(fates_patch_type) , intent(inout), pointer :: currentPatch ! Donor Patch + type(fates_patch_type) , intent(inout), pointer :: new_patch ! New Patch + real(r8), intent(in) :: fraction_to_keep ! fraction of currentPatch to keep, the rest goes to newpatch + real(r8), intent(in), optional :: area_to_remove ! area of currentPatch to remove, the rest goes to newpatch + ! + ! !LOCAL VARIABLES: + integer :: el ! element loop index + type (fates_cohort_type), pointer :: nc + type (fates_cohort_type), pointer :: storesmallcohort + type (fates_cohort_type), pointer :: storebigcohort + type (fates_cohort_type), pointer :: currentCohort + integer :: tnull ! is there a tallest cohort? + integer :: snull ! is there a shortest cohort? + integer :: pft + real(r8) :: temp_area + + temp_area = 0._r8 + if (present(area_to_remove)) then + temp_area = area_to_remove + else + temp_area = currentPatch%area - (currentPatch%area * fraction_to_keep) + end if + + ! first we need to make the new patch + call new_patch%Create(0._r8, temp_area, & + currentPatch%land_use_label, currentPatch%nocomp_pft_label, & + num_swb, numpft, currentSite%nlevsoil, hlm_current_tod, & + regeneration_model) + + ! Initialize the litter pools to zero, these + ! pools will be populated shortly + do el=1,num_elements + call new_patch%litter(el)%InitConditions(init_leaf_fines=0._r8, & + init_root_fines=0._r8, & + init_ag_cwd=0._r8, & + init_bg_cwd=0._r8, & + init_seed=0._r8, & + init_seed_germ=0._r8) + end do + new_patch%tallest => null() + new_patch%shortest => null() + + call CopyPatchMeansTimers(currentPatch, new_patch) + + call TransLitterNewPatch( currentSite, currentPatch, new_patch, temp_area) + + currentPatch%burnt_frac_litter(:) = 0._r8 + + ! Next, we loop through the cohorts in the donor patch, copy them with + ! area modified number density into the new-patch, and apply survivorship. + ! ------------------------------------------------------------------------- + + currentCohort => currentPatch%shortest + do while(associated(currentCohort)) + + allocate(nc) + if(hlm_use_planthydro.eq.itrue) call InitHydrCohort(CurrentSite,nc) + + ! Initialize the PARTEH object and point to the + ! correct boundary condition fields + nc%prt => null() + call InitPRTObject(nc%prt) + call nc%InitPRTBoundaryConditions() + + ! (Keeping as an example) + ! Allocate running mean functions + !allocate(nc%tveg_lpa) + !call nc%tveg_lpa%InitRMean(ema_lpa,init_value=new_patch%tveg_lpa%GetMean()) + + call nc%ZeroValues() + + ! nc is the new cohort that goes in the disturbed patch (new_patch)... currentCohort + ! is the curent cohort that stays in the donor patch (currentPatch) + call currentCohort%Copy(nc) + + ! Number of members in the new patch + nc%n = currentCohort%n * (1._r8 - fraction_to_keep) + + ! loss of individuals from source patch due to area shrinking + currentCohort%n = currentCohort%n * fraction_to_keep + + storebigcohort => new_patch%tallest + storesmallcohort => new_patch%shortest + if(associated(new_patch%tallest))then + tnull = 0 + else + tnull = 1 + new_patch%tallest => nc + nc%taller => null() + endif + + if(associated(new_patch%shortest))then + snull = 0 + else + snull = 1 + new_patch%shortest => nc + nc%shorter => null() + endif + + call insert_cohort(new_patch, nc, new_patch%tallest, new_patch%shortest, & + tnull, snull, storebigcohort, storesmallcohort) + + new_patch%tallest => storebigcohort + new_patch%shortest => storesmallcohort + + currentCohort => currentCohort%taller + enddo ! currentCohort + + call sort_cohorts(currentPatch) + + !update area of donor patch + currentPatch%area = currentPatch%area - temp_area + + end subroutine split_patch + ! ============================================================================ subroutine check_patch_area( currentSite ) @@ -1337,6 +1835,13 @@ subroutine check_patch_area( currentSite ) if ( abs(areatot-area_site) > area_error_fail ) then write(fates_log(),*) 'Patch areas do not sum to 10000 within tolerance' write(fates_log(),*) 'Total area: ',areatot,'absolute error: ',areatot-area_site + + currentPatch => currentSite%oldest_patch + do while(associated(currentPatch)) + write(fates_log(),*) 'area, LU, PFT', currentPatch%area, currentPatch%land_use_label, currentPatch%nocomp_pft_label + currentPatch => currentPatch%younger + end do + call endrun(msg=errMsg(sourcefile, __LINE__)) end if @@ -2184,10 +2689,6 @@ subroutine landusechange_litter_fluxes(currentSite, currentPatch, & ! (note we are accumulating over the patch, but scale is site level) real(r8) :: woodproduct_mass ! mass that ends up in wood products [kg] - ! the following two parameters are new to this logic. - real(r8), parameter :: burn_frac_landusetransition = 0.5_r8 ! what fraction of plant fines are burned during a land use transition? - real(r8), parameter :: woodproduct_frac_landusetransition = 0.5_r8 ! what fraction of trunk carbon is turned into wood products during a land use transition? - !--------------------------------------------------------------------- clear_veg_if: if (clearing_matrix_element) then @@ -2276,10 +2777,10 @@ subroutine landusechange_litter_fluxes(currentSite, currentPatch, & ! Contribution of dead trees to leaf litter donatable_mass = num_dead_trees * (leaf_m+repro_m) * & - (1.0_r8-burn_frac_landusetransition) + (1.0_r8-EDPftvarcon_inst%landusechange_frac_burned(pft)) ! Contribution of dead trees to leaf burn-flux - burned_mass = num_dead_trees * (leaf_m+repro_m) * burn_frac_landusetransition + burned_mass = num_dead_trees * (leaf_m+repro_m) * EDPftvarcon_inst%landusechange_frac_burned(pft) do dcmpy=1,ndcmpy dcmpy_frac = GetDecompyFrac(pft,leaf_organ,dcmpy) @@ -2309,7 +2810,7 @@ subroutine landusechange_litter_fluxes(currentSite, currentPatch, & ! Track as diagnostic fluxes flux_diags%leaf_litter_input(pft) = & flux_diags%leaf_litter_input(pft) + & - num_dead_trees * (leaf_m+repro_m) * (1.0_r8-burn_frac_landusetransition) + num_dead_trees * (leaf_m+repro_m) * (1.0_r8-EDPftvarcon_inst%landusechange_frac_burned(pft)) flux_diags%root_litter_input(pft) = & flux_diags%root_litter_input(pft) + & @@ -2345,21 +2846,28 @@ subroutine landusechange_litter_fluxes(currentSite, currentPatch, & do c = 1,ncwd donatable_mass = num_dead_trees * SF_val_CWD_frac(c) * bstem if (c == 1 .or. c == 2) then ! these pools can burn - donatable_mass = donatable_mass * (1.0_r8-burn_frac_landusetransition) + donatable_mass = donatable_mass * (1.0_r8-EDPftvarcon_inst%landusechange_frac_burned(pft)) burned_mass = num_dead_trees * SF_val_CWD_frac(c) * bstem * & - burn_frac_landusetransition + EDPftvarcon_inst%landusechange_frac_burned(pft) site_mass%burn_flux_to_atm = site_mass%burn_flux_to_atm + burned_mass - else ! all other pools can end up as timber products but not burn - donatable_mass = donatable_mass * (1.0_r8-woodproduct_frac_landusetransition) + else ! all other pools can end up as timber products or burn or go to litter + donatable_mass = donatable_mass * (1.0_r8-EDPftvarcon_inst%landusechange_frac_exported(pft)) * & + (1.0_r8-EDPftvarcon_inst%landusechange_frac_burned(pft)) + + burned_mass = num_dead_trees * SF_val_CWD_frac(c) * bstem * & + (1.0_r8-EDPftvarcon_inst%landusechange_frac_exported(pft)) * & + EDPftvarcon_inst%landusechange_frac_burned(pft) woodproduct_mass = num_dead_trees * SF_val_CWD_frac(c) * bstem * & - woodproduct_frac_landusetransition + EDPftvarcon_inst%landusechange_frac_exported(pft) + + site_mass%burn_flux_to_atm = site_mass%burn_flux_to_atm + burned_mass trunk_product_site = trunk_product_site + & woodproduct_mass - site_mass%wood_product = site_mass%wood_product + & + site_mass%wood_product_landusechange(pft) = site_mass%wood_product_landusechange(pft) + & woodproduct_mass endif new_litt%ag_cwd(c) = new_litt%ag_cwd(c) + donatable_mass * donate_m2 @@ -2386,6 +2894,7 @@ subroutine landusechange_litter_fluxes(currentSite, currentPatch, & end subroutine landusechange_litter_fluxes ! ============================================================================ + subroutine fuse_patches( csite, bc_in ) ! ! !DESCRIPTION: @@ -2413,6 +2922,8 @@ subroutine fuse_patches( csite, bc_in ) integer :: i_pftlabel !nocomp pft iterator real(r8) :: primary_land_fraction_beforefusion,primary_land_fraction_afterfusion integer :: pftlabelmin, pftlabelmax + integer :: num_bareground_patches + integer :: i ! !--------------------------------------------------------------------- @@ -2424,20 +2935,29 @@ subroutine fuse_patches( csite, bc_in ) primary_land_fraction_afterfusion = 0._r8 nopatches(1:n_landuse_cats) = 0 - + num_bareground_patches = 0 + currentPatch => currentSite%youngest_patch do while(associated(currentPatch)) - nopatches(currentPatch%land_use_label) = & - nopatches(currentPatch%land_use_label) + 1 + if ( currentPatch%land_use_label .gt. nocomp_bareground_land) then + nopatches(currentPatch%land_use_label) = & + nopatches(currentPatch%land_use_label) + 1 - if (currentPatch%land_use_label .eq. primaryland) then - primary_land_fraction_beforefusion = primary_land_fraction_beforefusion + & - currentPatch%area * AREA_INV + if (currentPatch%land_use_label .eq. primaryland) then + primary_land_fraction_beforefusion = primary_land_fraction_beforefusion + & + currentPatch%area * AREA_INV + endif + else + num_bareground_patches = num_bareground_patches + 1 endif - currentPatch => currentPatch%older enddo + if (num_bareground_patches .gt. 1 ) then + write(fates_log(),*) 'somehow there is more than one bare ground patch. this shouldnt have happened.' + call endrun(msg=errMsg(sourcefile, __LINE__)) + endif + pftlabelmin = 0 if ( hlm_use_nocomp .eq. itrue ) then pftlabelmax = numpft @@ -2651,6 +3171,17 @@ subroutine fuse_patches( csite, bc_in ) write(fates_log(),*) 'profile tolerance is too big, this shouldnt happen.' write(fates_log(),*) 'probably this means there are too many distinct categorical ' write(fates_log(),*) 'patch types for the maximum number of patches' + call dump_site(currentSite) + write(fates_log(),*) 'currentSite%area_bareground', currentSite%area_bareground + do i = 1, n_landuse_cats + write(fates_log(),*) 'i, currentSite%area_pft(:,i)',i, currentSite%area_pft(:,i) + end do + tmpptr => currentSite%youngest_patch + do while(associated(tmpptr)) + write(fates_log(),*) tmpptr%area, tmpptr%nocomp_pft_label, tmpptr%land_use_label + tmpptr => tmpptr%older + end do + call endrun(msg=errMsg(sourcefile, __LINE__)) endif else @@ -2718,7 +3249,7 @@ subroutine fuse_2_patches(csite, dp, rp) + rp%age_since_anthro_disturbance * rp%area) * inv_sum_area rp%age_class = get_age_class_index(rp%age) - + do el = 1,num_elements call rp%litter(el)%FuseLitter(rp%area,dp%area,dp%litter(el)) end do @@ -2773,8 +3304,9 @@ subroutine fuse_2_patches(csite, dp, rp) rp%zstar = (dp%zstar*dp%area + rp%zstar*rp%area) * inv_sum_area rp%c_stomata = (dp%c_stomata*dp%area + rp%c_stomata*rp%area) * inv_sum_area rp%c_lblayer = (dp%c_lblayer*dp%area + rp%c_lblayer*rp%area) * inv_sum_area - rp%radiation_error = (dp%radiation_error*dp%area + rp%radiation_error*rp%area) * inv_sum_area - + rp%rad_error(1) = (dp%rad_error(1)*dp%area + rp%rad_error(1)*rp%area) * inv_sum_area + rp%rad_error(2) = (dp%rad_error(2)*dp%area + rp%rad_error(2)*rp%area) * inv_sum_area + rp%area = rp%area + dp%area !THIS MUST COME AT THE END! !insert donor cohorts into recipient patch @@ -2847,35 +3379,39 @@ subroutine fuse_2_patches(csite, dp, rp) call endrun(msg=errMsg(sourcefile, __LINE__)) endif - if(associated(youngerp))then - ! Update the younger patch's new older patch (because it isn't dp anymore) - youngerp%older => olderp - else - ! There was no younger patch than dp, so the head of the young order needs - ! to be set, and it is set as the patch older than dp. That patch - ! already knows it's older patch (so no need to set or change it) - csite%youngest_patch => olderp - olderp%younger => null() - end if + ! if neither youngerp nor olderp are associated, that means that the patch we are fusing into + ! is not part of the linked-list structure, and so no further action needs to be taken. + if(associated(youngerp) .or. associated(olderp))then - - if(associated(olderp))then - ! Update the older patch's new younger patch (becuase it isn't dp anymore) - olderp%younger => youngerp - else - ! There was no patch older than dp, so the head of the old patch order needs - ! to be set, and it is set as the patch younger than dp. That patch already - ! knows it's younger patch, no need to set - csite%oldest_patch => youngerp - youngerp%older => null() - end if + if(associated(youngerp))then + ! Update the younger patch's new older patch (because it isn't dp anymore) + youngerp%older => olderp + else + ! There was no younger patch than dp, so the head of the young order needs + ! to be set, and it is set as the patch older than dp. That patch + ! already knows it's older patch (so no need to set or change it) + csite%youngest_patch => olderp + olderp%younger => null() + end if + if(associated(olderp))then + ! Update the older patch's new younger patch (becuase it isn't dp anymore) + olderp%younger => youngerp + else + ! There was no patch older than dp, so the head of the old patch order needs + ! to be set, and it is set as the patch younger than dp. That patch already + ! knows it's younger patch, no need to set + csite%oldest_patch => youngerp + youngerp%older => null() + end if + end if + end subroutine fuse_2_patches ! ============================================================================ - subroutine terminate_patches(currentSite) + subroutine terminate_patches(currentSite, bc_in) ! ! !DESCRIPTION: ! Terminate Patches if they are too small @@ -2883,19 +3419,25 @@ subroutine terminate_patches(currentSite) ! ! !ARGUMENTS: type(ed_site_type), target, intent(inout) :: currentSite + type(bc_in_type), intent(in) :: bc_in ! ! !LOCAL VARIABLES: type(fates_patch_type), pointer :: currentPatch type(fates_patch_type), pointer :: olderPatch type(fates_patch_type), pointer :: youngerPatch type(fates_patch_type), pointer :: patchpointer + type(fates_patch_type), pointer :: largest_patch integer, parameter :: max_cycles = 10 ! After 10 loops through ! You should had fused integer :: count_cycles logical :: gotfused logical :: current_patch_is_youngest_lutype + integer :: i_landuse, i_pft + integer :: land_use_type_to_remove - real(r8) areatot ! variable for checking whether the total patch area is wrong. + real(r8) areatot ! variable for checking whether the total patch area is wrong. + real(r8) :: state_vector_driver(n_landuse_cats) ! [m2/m2] + real(r8) :: state_vector_internal(n_landuse_cats) ! [m2/m2] !--------------------------------------------------------------------- ! Initialize the count cycles @@ -2927,7 +3469,7 @@ subroutine terminate_patches(currentSite) if ( .not. gotfused ) then !! somehow didn't find a patch to fuse with. write(fates_log(),*) 'Warning. small nocomp patch wasnt able to find another patch to fuse with.', & - currentPatch%nocomp_pft_label, currentPatch%land_use_label + currentPatch%nocomp_pft_label, currentPatch%land_use_label, currentPatch%area endif else nocomp_if @@ -3036,14 +3578,88 @@ subroutine terminate_patches(currentSite) write(fates_log(),*) 'is very very small. You can test your luck by' write(fates_log(),*) 'disabling the endrun statement following this message.' write(fates_log(),*) 'FATES may or may not continue to operate within error' - write(fates_log(),*) 'tolerances, but will generate another fail if it does not.' - call endrun(msg=errMsg(sourcefile, __LINE__)) + write(fates_log(),*) 'tolerances, but will generate another fail if it does not.' + write(fates_log(),*) 'otherwise, dumping some diagnostics.' + write(fates_log(),*) currentPatch%area, currentPatch%nocomp_pft_label, currentPatch%land_use_label + call dump_site(currentSite) + + write(fates_log(),*) 'currentSite%area_bareground', currentSite%area_bareground + write(fates_log(),*) 'currentSite%area_pft(:,:)', currentSite%area_pft(:,:) + patchpointer => currentSite%youngest_patch + do while(associated(patchpointer)) + write(fates_log(),*) patchpointer%area, patchpointer%nocomp_pft_label, patchpointer%land_use_label + patchpointer => patchpointer%older + end do + state_vector_internal = currentSite%get_current_landuse_statevector() + write(fates_log(),*) 'current landuse state vector: ', state_vector_internal + write(fates_log(),*) 'current landuse state vector (not including bare gruond): ', state_vector_internal/(1._r8-currentSite%area_bareground) + call GetLUHStatedata(bc_in, state_vector_driver) + write(fates_log(),*) 'driver data landuse state vector: ', state_vector_driver + write(fates_log(),*) 'min_allowed_landuse_fraction: ', currentSite%min_allowed_landuse_fraction + write(fates_log(),*) 'landuse_vector_gt_min: ', currentSite%landuse_vector_gt_min + do i_landuse = 1, n_landuse_cats + write(fates_log(),*) 'trans matrix from: ', i_landuse, currentSite%landuse_transition_matrix(i_landuse,:) + end do + + if ( (state_vector_driver(currentPatch%land_use_label) .lt. currentSite%min_allowed_landuse_fraction ) .or. & + (state_vector_internal(currentPatch%land_use_label) .lt. currentSite%min_allowed_landuse_fraction ) ) then + + ! try fusing all of the patches with this land use label into the largest patch on the site. + land_use_type_to_remove = currentPatch%land_use_label + + write(fates_log(),*) 'removing all patches with land use type ',land_use_type_to_remove + + ! first find the largest patch on the site + patchpointer => currentSite%youngest_patch + largest_patch => currentSite%youngest_patch + do while(associated(patchpointer)) + if (patchpointer%area .gt. largest_patch%area .and. patchpointer%nocomp_pft_label .ne. nocomp_bareground) then + largest_patch => patchpointer + endif + patchpointer => patchpointer%older + end do + + ! now go and fuse all patches that have the land use type we are removing into that patch + patchpointer => currentSite%youngest_patch + do while(associated(patchpointer)) + if ( patchpointer%land_use_label .eq. land_use_type_to_remove ) then + + write(fates_log(),*) 'fusing into patch with types, age, and size of:', largest_patch%land_use_label, & + largest_patch%nocomp_pft_label, largest_patch%age, largest_patch%area + + write(fates_log(),*) 'fusing away patch with types, age, and size of:', patchpointer%land_use_label, & + patchpointer%nocomp_pft_label, patchpointer%age, patchpointer%area + + ! reset the categorical properties of the patch and fuse it into the largest patch + patchpointer%land_use_label = largest_patch%land_use_label + patchpointer%nocomp_pft_label = largest_patch%nocomp_pft_label + patchpointer%age_since_anthro_disturbance = largest_patch%age_since_anthro_disturbance + call fuse_2_patches(currentSite, patchpointer, largest_patch) + + ! start over in the loop to make sure we are removing every patch with the targeted land use type + patchpointer => currentSite%youngest_patch + + else + patchpointer => patchpointer%older + endif + end do + + write(fates_log(),*) 'resetting currentSite%landuse_vector_gt_min(i) to .false.' + ! now reset the allowed land use vector element so that we don't make any more such patches unless they exceed the min area + currentSite%landuse_vector_gt_min(land_use_type_to_remove) = .false. + count_cycles = 0 + currentPatch => currentSite%youngest_patch + else + write(fates_log(),*) 'this isnt because the land use was less than allowed' + + call endrun(msg=errMsg(sourcefile, __LINE__)) - ! Note to user. If you DO decide to remove the end-run above this line - ! Make sure that you keep the pointer below this line, or you will get - ! an infinite loop. - currentPatch => currentPatch%older - count_cycles = 0 + ! Note to user. If you DO decide to remove the end-run above this line + ! Make sure that you keep the pointer below this line, or you will get + ! an infinite loop. + currentPatch => currentPatch%older + count_cycles = 0 + endif end if !count cycles enddo ! current patch loop @@ -3174,35 +3790,6 @@ end function countPatches ! ===================================================================================== - subroutine get_frac_site_primary(site_in, frac_site_primary) - - ! - ! !DESCRIPTION: - ! Calculate how much of a site is primary land - ! - ! !USES: - use EDTypesMod , only : ed_site_type - ! - ! !ARGUMENTS: - type(ed_site_type) , intent(in), target :: site_in - real(r8) , intent(out) :: frac_site_primary - - ! !LOCAL VARIABLES: - type (fates_patch_type), pointer :: currentPatch - - frac_site_primary = 0._r8 - currentPatch => site_in%oldest_patch - do while (associated(currentPatch)) - if (currentPatch%land_use_label .eq. primaryland) then - frac_site_primary = frac_site_primary + currentPatch%area * AREA_INV - endif - currentPatch => currentPatch%younger - end do - - end subroutine get_frac_site_primary - - ! ===================================================================================== - subroutine InsertPatch(currentSite, newPatch) ! !DESCRIPTION: @@ -3304,7 +3891,7 @@ subroutine InsertPatch(currentSite, newPatch) ! In the case in which we get to the end of the list and haven't found ! a landuse label match. - ! If the new patch is primarylands add it to the oldest end of the list + ! If the new patch is primaryland add it to the oldest end of the list if (newPatch%land_use_label .eq. primaryland) then newPatch%older => null() newPatch%younger => currentSite%oldest_patch @@ -3367,4 +3954,36 @@ subroutine InsertPatch(currentSite, newPatch) end subroutine InsertPatch + ! ===================================================================================== + + subroutine CopyPatchMeansTimers(dp, rp) + + ! !DESCRIPTION: + ! Copy any means or timers from the original patch to the new patch + ! These values will inherit all info from the original patch + ! -------------------------------------------------------------------------- + ! + ! !ARGUMENTS: + type (fates_patch_type), intent(in) :: dp ! Donor Patch + type (fates_patch_type), intent(inout) :: rp ! Recipient Patch + + ! LOCAL: + integer :: ipft ! pft index + + call rp%tveg24%CopyFromDonor(dp%tveg24) + call rp%tveg_lpa%CopyFromDonor(dp%tveg_lpa) + call rp%tveg_longterm%CopyFromDonor(dp%tveg_longterm) + + if ( regeneration_model == TRS_regeneration ) then + call rp%seedling_layer_par24%CopyFromDonor(dp%seedling_layer_par24) + call rp%sdlng_mort_par%CopyFromDonor(dp%sdlng_mort_par) + call rp%sdlng2sap_par%CopyFromDonor(dp%sdlng2sap_par) + do ipft = 1,numpft + call rp%sdlng_emerg_smp(ipft)%p%CopyFromDonor(dp%sdlng_emerg_smp(ipft)%p) + call rp%sdlng_mdd(ipft)%p%CopyFromDonor(dp%sdlng_mdd(ipft)%p) + enddo + end if + + end subroutine CopyPatchMeansTimers + end module EDPatchDynamicsMod diff --git a/biogeochem/EDPhysiologyMod.F90 b/biogeochem/EDPhysiologyMod.F90 index bbe1184ad4..98d0d4b571 100644 --- a/biogeochem/EDPhysiologyMod.F90 +++ b/biogeochem/EDPhysiologyMod.F90 @@ -18,6 +18,7 @@ module EDPhysiologyMod use FatesInterfaceTypesMod, only : hlm_parteh_mode use FatesInterfaceTypesMod, only : hlm_use_fixed_biogeog use FatesInterfaceTypesMod, only : hlm_use_nocomp + use EDParamsMod , only : crop_lu_pft_vector use FatesInterfaceTypesMod, only : hlm_nitrogen_spec use FatesInterfaceTypesMod, only : hlm_phosphorus_spec use FatesInterfaceTypesMod, only : hlm_use_tree_damage @@ -34,6 +35,8 @@ module EDPhysiologyMod use FatesConstantsMod, only : g_per_kg use FatesConstantsMod, only : ndays_per_year use FatesConstantsMod, only : nocomp_bareground + use FatesConstantsMod, only : nocomp_bareground_land + use FatesConstantsMod, only : is_crop use FatesConstantsMod, only : area_error_2 use EDPftvarcon , only : EDPftvarcon_inst use PRTParametersMod , only : prt_params @@ -45,7 +48,7 @@ module EDPhysiologyMod use FatesAllometryMod , only : tree_lai use FatesAllometryMod , only : tree_sai use FatesAllometryMod , only : leafc_from_treelai - use FatesAllometryMod , only : decay_coeff_kn + use FatesAllometryMod , only : decay_coeff_vcmax use FatesLitterMod , only : litter_type use EDTypesMod , only : site_massbal_type use EDTypesMod , only : numlevsoil_max @@ -140,7 +143,8 @@ module EDPhysiologyMod use FatesParameterDerivedMod, only : param_derived use FatesPlantHydraulicsMod, only : InitHydrCohort use PRTInitParamsFatesMod, only : NewRecruitTotalStoichiometry - + use FatesInterfaceTypesMod , only : hlm_use_luh + implicit none private @@ -765,7 +769,10 @@ subroutine trim_canopy( currentSite ) ! Calculate sla_levleaf following the sla profile with overlying leaf area ! Scale for leaf nitrogen profile - kn = decay_coeff_kn(ipft,currentCohort%vcmax25top) + kn = decay_coeff_vcmax(currentCohort%vcmax25top, & + prt_params%leafn_vert_scaler_coeff1(ipft), & + prt_params%leafn_vert_scaler_coeff2(ipft)) + ! Nscaler value at leaf level z nscaler_levleaf = exp(-kn * cumulative_lai) ! Sla value at leaf level z after nitrogen profile scaling (m2/gC) @@ -2489,20 +2496,35 @@ subroutine recruitment(currentSite, currentPatch, bc_in) real(r8) :: seedling_layer_smp ! soil matric potential at seedling rooting depth [mm H2O suction] integer, parameter :: recruitstatus = 1 ! whether the newly created cohorts are recruited or initialized integer :: ilayer_seedling_root ! the soil layer at seedling rooting depth - + logical :: use_this_pft ! logical flag for whether or not to allow a given PFT to recruit !--------------------------------------------------------------------------- do ft = 1, numpft - ! The following if block is for the prescribed biogeography and/or nocomp modes. - ! Since currentSite%use_this_pft is a site-level quantity and thus only limits whether a given PFT - ! is permitted on a given gridcell or not, it applies to the prescribed biogeography case only. - ! If nocomp is enabled, then we must determine whether a given PFT is allowed on a given patch or not. + ! The following if block is for the prescribed biogeography and/or nocomp modes and/or crop land use types + ! Since currentSite%use_this_pft is a site-level quantity and thus only limits whether a given PFT + ! is permitted on a given gridcell or not, it applies to the prescribed biogeography case only. + ! If nocomp is enabled, then we must determine whether a given PFT is allowed on a given patch or not. + ! Whether or not nocomp or prescribed biogeography is enabled, if land use change is enabled, then we only want to + ! allow crop PFTs on patches with crop land use types + + use_this_pft = .false. + if(currentSite%use_this_pft(ft).eq.itrue & + .and. ((hlm_use_nocomp .eq. ifalse) .or. (ft .eq. currentPatch%nocomp_pft_label)))then + use_this_pft = .true. + end if - if (currentSite%use_this_pft(ft) .eq. itrue .and. & - ((hlm_use_nocomp .eq. ifalse) .or. & - (ft .eq. currentPatch%nocomp_pft_label))) then + if ( currentPatch%land_use_label .ne. nocomp_bareground_land ) then ! cdk + if ((hlm_use_luh .eq. itrue) .and. (is_crop(currentPatch%land_use_label))) then + if ( crop_lu_pft_vector(currentPatch%land_use_label) .eq. ft ) then + use_this_pft = .true. + else + use_this_pft = .false. + end if + end if + endif + use_this_pft_if: if(use_this_pft) then height = EDPftvarcon_inst%hgt_min(ft) stem_drop_fraction = prt_params%phen_stem_drop_fraction(ft) fnrt_drop_fraction = prt_params%phen_fnrt_drop_fraction(ft) @@ -2746,11 +2768,11 @@ subroutine recruitment(currentSite, currentPatch, bc_in) currentSite%recruitment_rate(ft) = currentSite%recruitment_rate(ft) + cohort_n endif any_recruits - endif !use_this_pft + endif use_this_pft_if enddo !pft loop end subroutine recruitment - ! ====================================================================================== + ! ====================================================================================== subroutine CWDInput( currentSite, currentPatch, litt, bc_in) @@ -3037,7 +3059,7 @@ subroutine CWDInput( currentSite, currentPatch, litt, bc_in) SF_val_CWD_frac_adj(c) * dead_n_dlogging * & prt_params%allom_agb_frac(pft) - site_mass%wood_product = site_mass%wood_product + & + site_mass%wood_product_harvest(pft) = site_mass%wood_product_harvest(pft) + & trunk_wood * currentPatch%area * logging_export_frac ! Add AG wood to litter from the non-exported fraction of wood diff --git a/biogeochem/FatesAllometryMod.F90 b/biogeochem/FatesAllometryMod.F90 index 431219cfda..1aa1cc4525 100644 --- a/biogeochem/FatesAllometryMod.F90 +++ b/biogeochem/FatesAllometryMod.F90 @@ -92,12 +92,13 @@ module FatesAllometryMod use FatesConstantsMod, only : calloc_abs_error use FatesConstantsMod, only : fates_unset_r8 use FatesConstantsMod, only : itrue + use FatesConstantsMod, only : nearzero use shr_log_mod , only : errMsg => shr_log_errMsg use FatesGlobals , only : fates_log use FatesGlobals , only : endrun => fates_endrun use FatesGlobals , only : FatesWarn,N2S,A2S,I2S - use EDParamsMod , only : nlevleaf, dinc_vai - use EDParamsMod , only : nclmax + use EDParamsMod , only : nlevleaf,dinc_vai,dlower_vai + use EDParamsMod , only : nclmax use DamageMainMod , only : GetCrownReduction implicit none @@ -117,7 +118,7 @@ module FatesAllometryMod public :: bdead_allom ! Generic bdead wrapper public :: carea_allom ! Generic crown area wrapper public :: bstore_allom ! Generic maximum storage carbon wrapper - public :: decay_coeff_kn + public :: decay_coeff_vcmax ! vertical canopy decay rate, scaled on vcmax public :: ForceDBH ! Method to set DBH to sync with structure ! or fineroot biomass public :: CheckIntegratedAllometries @@ -125,7 +126,8 @@ module FatesAllometryMod public :: set_root_fraction ! Generic wrapper to calculate normalized ! root profiles public :: leafc_from_treelai ! Calculate target leaf carbon for a given treelai for SP mode - + public :: VegAreaLayer + logical , parameter :: verbose_logging = .false. character(len=*), parameter :: sourcefile = __FILE__ @@ -305,7 +307,7 @@ subroutine h2d_allom(h,ipft,d,dddh) p3 => prt_params%allom_d2h3(ipft), & allom_hmode => prt_params%allom_hmode(ipft)) - select case(int(allom_hmode)) + select case(allom_hmode) case (1) ! O'Brien et al 1995, BCI call h2d_obrien(h,p1,p2,d,dddh) case (2) ! poorter 2006 @@ -344,7 +346,7 @@ subroutine h_allom(d,ipft,h,dhdd) p3 => prt_params%allom_d2h3(ipft), & allom_hmode => prt_params%allom_hmode(ipft)) - select case(int(allom_hmode)) + select case(allom_hmode) case (1) ! "obrien" call d2h_obrien(d,p1,p2,dbh_maxh,h,dhdd) case (2) ! "poorter06" @@ -397,7 +399,7 @@ subroutine bagw_allom(d,ipft,crowndamage, elongf_stem, bagw,dbagwdd) branch_frac = param_derived%branch_frac(ipft) - select case(int(allom_amode)) + select case(allom_amode) case (1) !"salda") call h_allom(d,ipft,h,dhdd) call dh2bagw_salda(d,h,dhdd,p1,p2,p3,p4,wood_density,c2b,agb_frac,bagw,dbagwdd) @@ -407,6 +409,9 @@ subroutine bagw_allom(d,ipft,crowndamage, elongf_stem, bagw,dbagwdd) case (3) !"chave14") call h_allom(d,ipft,h,dhdd) call dh2bagw_chave2014(d,h,dhdd,p1,p2,wood_density,c2b,bagw,dbagwdd) + case (4) ! 3par_pwr + call h_allom(d,ipft,h,dhdd) + call dh2bagw_3pwr(d,h,dhdd,p1,p2,p3,wood_density,c2b,bagw,dbagwdd) case DEFAULT write(fates_log(),*) 'An undefined AGB allometry was specified: ',allom_amode write(fates_log(),*) 'Aborting' @@ -444,21 +449,28 @@ subroutine blmax_allom(d,ipft,blmax,dblmaxdd) real(r8),intent(out) :: blmax ! plant leaf biomass [kg] real(r8),intent(out),optional :: dblmaxdd ! change leaf bio per diameter [kgC/cm] + real(r8) :: h ! height + real(r8) :: dhdd ! change in height wrt d + associate( dbh_maxh => prt_params%allom_dbh_maxheight(ipft), & rho => prt_params%wood_density(ipft), & + slatop => prt_params%slatop(ipft), & c2b => prt_params%c2b(ipft), & allom_lmode => prt_params%allom_lmode(ipft), & p1 => prt_params%allom_d2bl1(ipft), & p2 => prt_params%allom_d2bl2(ipft), & p3 => prt_params%allom_d2bl3(ipft)) - select case(int(allom_lmode)) + select case(allom_lmode) case(1) !"salda") call d2blmax_salda(d,p1,p2,p3,rho,dbh_maxh,c2b,blmax,dblmaxdd) case(2) !"2par_pwr") call d2blmax_2pwr(d,p1,p2,c2b,blmax,dblmaxdd) case(3) ! dh2blmax_2pwr call dh2blmax_2pwr(d,p1,p2,dbh_maxh,c2b,blmax,dblmaxdd) + case(4) ! dh2blmax_3pwr + call h_allom(d,ipft,h,dhdd) + call dh2blmax_3pwr(d,h,dhdd,p1,p2,p3,slatop,dbh_maxh,c2b,blmax,dblmaxdd) case DEFAULT write(fates_log(),*) 'An undefined leaf allometry was specified: ', & allom_lmode @@ -485,6 +497,7 @@ subroutine carea_allom(dbh,nplant,site_spread,ipft,crowndamage,c_area,inverse) ! instead of crown area from dbh real(r8) :: dbh_eff ! Effective diameter (cm) + real(r8) :: height ! height logical :: do_inverse ! local copy of the inverse argument ! defaults to false logical :: capped_allom ! if we are using an allometry that caps @@ -507,7 +520,7 @@ subroutine carea_allom(dbh,nplant,site_spread,ipft,crowndamage,c_area,inverse) endif endif - select case(int(allom_lmode)) + select case(allom_lmode) case(1) dbh_eff = min(dbh,dbh_maxh) call carea_2pwr(dbh_eff,site_spread,d2bl_p2,d2bl_ediff,d2ca_min,d2ca_max, & @@ -522,6 +535,12 @@ subroutine carea_allom(dbh,nplant,site_spread,ipft,crowndamage,c_area,inverse) call carea_2pwr(dbh_eff,site_spread,d2bl_p2,d2bl_ediff,d2ca_min,d2ca_max, & crowndamage, c_area, do_inverse) capped_allom = .true. + case (4) + dbh_eff = min(dbh,dbh_maxh) + call h_allom(dbh,ipft,height) + call carea_3pwr(dbh_eff,height,ipft,dbh_maxh, site_spread,d2bl_p2, & + d2bl_ediff, d2ca_min,d2ca_max,crowndamage, c_area, do_inverse) + capped_allom = .true. case DEFAULT write(fates_log(),*) 'An undefined leaf allometry was specified: ', & allom_lmode @@ -614,20 +633,25 @@ end subroutine bleaf subroutine storage_fraction_of_target(c_store_target, c_store, frac) !-------------------------------------------------------------------------------- - ! returns the storage pool as a fraction of its target (only if it is below its target) - ! used in both the carbon starvation mortlaity scheme as well as the optional - ! respiration throttling logic + ! This subroutine returns the ratio between the storage pool and the target + ! storage. This subroutine is used both the carbon starvation mortality scheme + ! and the optional respiration throttling. We impose checks so it cannot go negative + ! due to truncation errors, but this function can return values greater than 1. + ! + ! Fractions exceeding do not impact the default linear carbon starvation model + ! (mort_cstarvation_model=2), because mortality becomes zero, but they allow carbon + ! starvation mortality rates to continue decaying when the exponential carbon + ! starvation model is used (mort_cstarvation_model=2). + ! + ! Fraction values above 1 do not impact lowstorage_maintresp_reduction either, + ! as that routine imposes no reduction once the fraction exceeds 1. !-------------------------------------------------------------------------------- real(r8),intent(in) :: c_store_target ! target storage carbon [kg] real(r8),intent(in) :: c_store ! storage carbon [kg] real(r8),intent(out) :: frac - if( c_store_target > 0._r8 .and. c_store <= c_store_target )then - frac = c_store/ c_store_target - else - frac = 1._r8 - endif + frac = max(0._r8, c_store / max( c_store_target, nearzero) ) end subroutine storage_fraction_of_target @@ -686,8 +710,10 @@ real(r8) function tree_lai( leaf_c, pft, c_area, nplant, cl, canopy_lai, vcmax25 end if ! Coefficient for exponential decay of 1/sla with canopy depth: - kn = decay_coeff_kn(pft,vcmax25top) - + kn = decay_coeff_vcmax(vcmax25top, & + prt_params%leafn_vert_scaler_coeff1(pft), & + prt_params%leafn_vert_scaler_coeff2(pft)) + ! take PFT-level maximum SLA value, even if under a thick canopy (which has units of m2/gC), ! and put into units of m2/kgC sla_max = g_per_kg*prt_params%slamax(pft) @@ -880,8 +906,11 @@ real(r8) function leafc_from_treelai( treelai, pft, c_area, nplant, cl, vcmax25t ! convert PFT-level canopy top and maximum SLA values and convert from m2/gC to m2/kgC slat = g_per_kg * prt_params%slatop(pft) sla_max = g_per_kg * prt_params%slamax(pft) + ! Coefficient for exponential decay of 1/sla with canopy depth: - kn = decay_coeff_kn(pft,vcmax25top) + kn = decay_coeff_vcmax(vcmax25top, & + prt_params%leafn_vert_scaler_coeff1(pft), & + prt_params%leafn_vert_scaler_coeff2(pft)) if(treelai > 0.0_r8)then ! Leafc_per_unitarea at which sla_max is reached due to exponential sla profile in canopy: @@ -959,7 +988,7 @@ subroutine bsap_allom(d,ipft,crowndamage,canopy_trim,elongf_stem, sapw_area,bsap branch_frac = param_derived%branch_frac(ipft) - select case(int(prt_params%allom_smode(ipft))) + select case(prt_params%allom_smode(ipft)) ! --------------------------------------------------------------------- ! Currently only one sapwood allometry model. the slope ! of the la:sa to diameter line is zero. @@ -1033,7 +1062,7 @@ subroutine bbgw_allom(d,ipft,elongf_stem,bbgw,dbbgwdd) real(r8) :: bagw ! above ground biomass [kgC] real(r8) :: dbagwdd ! change in agb per diameter [kgC/cm] - select case(int(prt_params%allom_cmode(ipft))) + select case(prt_params%allom_cmode(ipft)) case(1) !"constant") ! bbgw not affected by damage so use target allometry no damage. But note that bbgw ! is affected by stem phenology (typically applied only to grasses). We do not need @@ -1078,7 +1107,7 @@ subroutine bfineroot(d,ipft,canopy_trim,l2fr,elongf_fnrt,bfr,dbfrdd) real(r8) :: dbfrmaxdd real(r8) :: slascaler - select case(int(prt_params%allom_fmode(ipft))) + select case(prt_params%allom_fmode(ipft)) case(1) ! "constant proportionality with TRIMMED target bleaf" call blmax_allom(d,ipft,blmax,dblmaxdd) @@ -1139,7 +1168,7 @@ subroutine bstore_allom(d,ipft,crowndamage, canopy_trim,bstore,dbstoredd) associate( allom_stmode => prt_params%allom_stmode(ipft), & cushion => prt_params%cushion(ipft) ) - select case(int(allom_stmode)) + select case(allom_stmode) case(1) ! Storage is constant proportionality of trimmed maximum leaf ! biomass (ie cushion * bleaf), and thus leaf phenology is ignored. call bleaf(d,ipft, crowndamage, canopy_trim, 1.0_r8, bl, dbldd) @@ -1190,7 +1219,7 @@ subroutine bdead_allom(bagw,bbgw,bsap,ipft,bdead,dbagwdd,dbbgwdd,dbsapdd,dbdeadd associate( agb_fraction => prt_params%allom_agb_frac(ipft)) - select case(int(prt_params%allom_amode(ipft))) + select case(prt_params%allom_amode(ipft)) case(1) ! Saldariagga mass allometry originally calculated bdead directly. ! we assume proportionality between bdead and bagw @@ -1199,7 +1228,7 @@ subroutine bdead_allom(bagw,bbgw,bsap,ipft,bdead,dbagwdd,dbbgwdd,dbsapdd,dbdeadd dbdeaddd = dbagwdd/agb_fraction end if - case(2,3) + case(2,3,4) bdead = bagw + bbgw - bsap if(present(dbagwdd) .and. present(dbbgwdd) .and. & @@ -1318,7 +1347,7 @@ subroutine bsap_ltarg_slatop(d,h,dhdd,bleaf,dbleafdd,ipft, & hbl2bsap = slatop * g_per_kg * wood_density * kg_per_Megag / (c2b*cm2_per_m2 ) ! Calculate area. Note that no c2b conversion here, because it is - ! wood density that is in biomass units, SLA is in units [m2/gC. + ! wood density that is in biomass units, SLA is in units [m2/gC]. ! [m2] = [m2/gC] * [kgC] * [gC/kgC] / ( [m2/cm2] * [cm2/m2]) la_per_sa = la_per_sa_int + h*la_per_sa_slp sapw_area = slatop * bleaf * g_per_kg / (la_per_sa*cm2_per_m2 ) @@ -1489,7 +1518,119 @@ subroutine dh2blmax_2pwr(d,p1,p2,dbh_maxh,c2b,blmax,dblmaxdd) return end subroutine dh2blmax_2pwr - + + + ! =========================================================================== + + + subroutine dh2blmax_3pwr(d,h,dhdd,p1,p2,p3,slatop,dbh_maxh,c2b,blmax,dblmaxdd) + !-------------------------------------------------------------------------- + ! + ! This function calculates the maximum leaf biomass from reference + ! diameter, plant height and top-of-the-canopy (fully sunlit) SLA. This + ! functional form is similar to Lescure et al. (1983) and Longo et al. + ! (2020), except that it uses SLA as an additional scaler for the + ! allometric equation that can have a different exponent from + ! (DBH^2 * Height). + ! + ! ----------------- + ! References + ! ----------------- + ! Lescure JP, Puig H, Riera B, Leclerc D, Beekman A , Beneteau A. 1983. + ! La phytomasse epigee d'une foret dense en Guiane Francaise + ! Acta Oecol.-Oec. Gen. 4: 237-251. + ! URL http://www.documentation.ird.fr/hor/fdi:010005089 + ! + ! Longo M, Saatchi SS, Keller M, Bowman KW, Ferraz A, Moorcroft PR, + ! Morton D, Bonal D, Brando P, Burban B et al. 2020. Impacts of + ! degradation on water, energy, and carbon cycling of the Amazon + ! tropical forests. J. Geophys. Res.-Biogeosci. 125: + ! e2020JG005677. doi:10.1029/2020JG005677. + ! + ! ----------------- + ! Input arguments + ! ----------------- + ! d -- Diameter at breast height [ cm] + ! h -- Total tree height [ m] + ! dhdd -- Height derivative with dbh [ m/cm] + ! p1 -- Parameter 1 (log-intercept) [ --] + ! p2 -- Parameter 2 (power, or log-slope) [ --] + ! p3 -- Parameter 3 (power, or log-slope) [ --] + ! slatop -- Top-of-canopy specific leaf area [ m2/gC] + ! dbh_maxh -- DBH at maximum height [ cm] + ! c2b -- Carbon to biomass multiplier ~ 2 [ kg/kgC] + ! + ! ------------------ + ! Output arguments + ! ------------------ + ! blmax -- Plant leaf biomass [ kgC] + ! dblmaxdd -- Plant leaf biomass derivative [ kgC/cm] + ! + ! ------------------ + ! Suggested first guess for parameters, based on Longo et al. (2020) and + ! corrected to FATES units (first guess based on a very limited leaf area + ! data set). + ! ------------------ + ! p1 = 0.000468 + ! p2 = 0.641 + ! p3 = -1.000 + !-------------------------------------------------------------------------- + + + !--- Arguments + real(r8), intent(in) :: d ! plant diameter [ cm] + real(r8), intent(in) :: h ! plant height [ m] + real(r8), intent(in) :: dhdd ! Height derivative wrt diameter [ m/cm] + real(r8), intent(in) :: p1 ! Log-intercept parameter [ -] + real(r8), intent(in) :: p2 ! Log-slope parameter for size [ -] + real(r8), intent(in) :: p3 ! Log-slope parameter for SLA [ -] + real(r8), intent(in) :: slatop ! Top canopy specific leaf area [ m2/gC] + real(r8), intent(in) :: c2b ! Carbon to biomass multiplier [kg/kgC] + real(r8), intent(in) :: dbh_maxh ! dbh at maximum height [ cm] + real(r8), intent(out) :: blmax ! Leaf biomass [ kgC] + real(r8), intent(out), optional :: dblmaxdd ! Leaf biomass derivative [kgC/cm] + !--- Local variables + real(r8) :: duse + !---~--- + + + + !--- Cap DBH + duse = min(d,dbh_maxh) + !---~--- + + + !--- Find leaf biomass + blmax = p1 * (duse*duse*h)**p2 * slatop**p3 / c2b + !---~--- + + + !---~--- + ! Compute the leaf biomass derivative with DBH if needed. + !---~--- + if (present(dblmaxdd)) then + if (d >= dbh_maxh) then + !---~--- + ! Leaf area is capped at the maximum DBH. This may be removed in the + ! future. + !---~--- + dblmaxdd = 0._r8 + !---~--- + else + !---~--- + ! Find the leaf biomass derivative, noting that height is actually + ! a function of DBH. + !---~--- + dblmaxdd = p2 * blmax * ( 2._r8 / duse + dhdd / h ) + !---~--- + end if + end if + !---~--- + + return + end subroutine dh2blmax_3pwr + + ! ========================================================================= ! Diameter to height (D2H) functions ! ========================================================================= @@ -1500,7 +1641,7 @@ subroutine d2h_chave2014(d,p1,p2,p3,dbh_maxh,h,dhdd) ! "d to height via Chave et al. 2014" ! This function calculates tree height based on tree diameter and the - ! environmental stress factor "E", as per Chave et al. 2015 GCB + ! environmental stress factor "E", as per Chave et al. 2014 GCB ! As opposed to previous allometric models in ED, in this formulation ! we do not impose a hard cap on tree height. But, maximum_height ! is an important parameter, but instead of imposing a hard limit, in @@ -1509,7 +1650,7 @@ subroutine d2h_chave2014(d,p1,p2,p3,dbh_maxh,h,dhdd) ! begin to route available NPP into seed and defense respiration. ! ! The stress function is based on the geographic location of the site. If - ! a user decides to use Chave2015 allometry, the E factor will be read in + ! a user decides to use Chave2014 allometry, the E factor will be read in ! from a global gridded dataset and assigned for each ED patch (note it ! will be the same for each ED patch, but this distinction will help in ! porting ED into different models (patches are pure ED). It @@ -1747,7 +1888,7 @@ subroutine dh2bagw_chave2014(d,h,dhdd,p1,p2,wood_density,c2b,bagw,dbagwdd) ! height and wood density. ! ! Chave et al. Improved allometric models to estimate the abovegroud - ! biomass of tropical trees. Global Change Biology. V20, p3177-3190. 2015. + ! biomass of tropical trees. Global Change Biology. V20, p3177-3190. 2014. ! ! Input arguments: ! d: Diameter at breast height [cm] @@ -1791,6 +1932,89 @@ subroutine dh2bagw_chave2014(d,h,dhdd,p1,p2,wood_density,c2b,bagw,dbagwdd) return end subroutine dh2bagw_chave2014 + ! ============================================================================ + + + + subroutine dh2bagw_3pwr(d,h,dhdd,p1,p2,p3,wood_density,c2b,bagw,dbagwdd) + !-------------------------------------------------------------------------- + ! + ! This function calculates the maximum above-ground biomass from + ! reference diameter, plant height and wood density. This functional form + ! is an intermediate between Saldarriaga et al. (1988) and Chave et al. + ! (2014), because the wood-density exponent is independent on the + ! plant size (DBH^2 * Height) but the diameter and height are scaled + ! together through the size function. + ! + ! ----------------- + ! References + ! ----------------- + ! Chave J, Rejou-Mechain M, Burquez A, Chidumayo E, Colgan MS, Delitti WB, + ! Duque A, Eid T, Fearnside PM, Goodman RC et al. 2014. Improved + ! allometric models to estimate the aboveground biomass of tropical + ! trees. Glob. Change Biol. 20: 3177-3190. doi:10.1111/gcb.12629. + ! + ! Saldarriaga JG, West DC, Tharp ML , Uhl C. 1988. Long-term + ! chronosequence of forest succession in the upper Rio Negro of + ! Colombia and Venezuela. J. Ecol. 76: 938-958. + ! doi:10.2307/2260625. + ! + ! ----------------- + ! Input arguments + ! ----------------- + ! d -- Diameter at breast height [ cm] + ! h -- Total tree height [ m] + ! dhdd -- Height derivative with dbh [ m/cm] + ! p1 -- Parameter 1 (log-intercept) [ --] + ! p2 -- Parameter 2 (power, or log-slope) [ --] + ! p3 -- Parameter 3 (power, or log-slope) [ --] + ! wood_density -- Wood density [ g/cm3] + ! c2b -- Carbon to biomass multiplier ~ 2 [ kg/kgC] + ! + ! ------------------ + ! Output arguments + ! ------------------ + ! bagw -- Above-ground biomass per individual [ kgC] + ! dbagwdd -- Above-ground biomass derivative [ kgC/cm] + ! + !-------------------------------------------------------------------------- + + + !--- Arguments + real(r8), intent(in) :: d ! plant diameter [ cm] + real(r8), intent(in) :: h ! plant height [ m] + real(r8), intent(in) :: dhdd ! Height deriv. wrt diameter [ m/cm] + real(r8), intent(in) :: p1 ! Log-intercept parameter [ -] + real(r8), intent(in) :: p2 ! Log-slope parameter (size) [ -] + real(r8), intent(in) :: p3 ! Log-slope parameter (WD) [ -] + real(r8), intent(in) :: wood_density ! Wood density [ g/cm3] + real(r8), intent(in) :: c2b ! Carbon to biomass factor [kg/kgC] + real(r8), intent(out) :: bagw ! Above-ground biomass [ kgC] + real(r8), intent(out), optional :: dbagwdd ! AG biomass derivative [kgC/cm] + !---~--- + + + !--- Find above-ground biomass + bagw = p1 * (d*d*h)**p2 * wood_density**p3 / c2b + !---~--- + + + !---~--- + ! Compute the above-ground biomass derivative with DBH if needed, noting that + ! height is actually a function of DBH. + !---~--- + if (present(dbagwdd)) then + dbagwdd = p2 * bagw * ( 2._r8 / d + dhdd / h ) + end if + !---~--- + + return + end subroutine dh2bagw_3pwr + + + ! ============================================================================ + + subroutine d2bagw_2pwr(d,p1,p2,c2b,bagw,dbagwdd) ! ========================================================================= @@ -2077,36 +2301,62 @@ subroutine h2d_martcano(h,p1,p2,p3,d,dddh) return end subroutine h2d_martcano + ! ===================================================================================== - subroutine CrownDepth(height,ft,crown_depth) + subroutine CrownDepth(height,ipft,crown_depth) - ! ----------------------------------------------------------------------------------- - ! This routine returns the depth of a plant's crown. Which is the length - ! from the bottom of the crown to the top in the vertical dimension. - ! - ! This code may be used as a wrapper if different hypotheses are wished to be - ! optioned. - ! ----------------------------------------------------------------------------------- - - real(r8),intent(in) :: height ! The height of the plant [m] - integer,intent(in) :: ft ! functional type index - real(r8),intent(out) :: crown_depth ! The depth of the crown [m] - - ! Alternative Hypothesis: - ! crown depth from Poorter, Bongers & Bongers - ! crown_depth = exp(-1.169_r8)*cCohort%height**1.098_r8 + !-------------------------------------------------------------------------- + ! This routine returns the depth of a plant's crown. Which is the + ! length from the bottom of the crown to the top in the vertical dimension. + ! + ! The original mode (now allom_dmode = 1) used only a fraction of the + ! plant's height. Alternatively, allom_dmode = 2 uses the same functional + ! form as Poorter et al. (2006), with an additional constraint to prevent + ! crown depth to exceed the plant's height. + ! + ! ----------------- + ! References + ! ----------------- + ! Poorter L, Bongers L , Bongers F. 2006. Architecture of 54 moist-forest + ! tree species: traits, trade-offs, and functional groups. Ecology 87: + ! 1289-1301. doi:10.1890/0012-9658(2006)87[1289:AOMTST]2.0.CO;2. + ! + !-------------------------------------------------------------------------- + + real(r8),intent(in) :: height ! The height of the plant [m] + integer ,intent(in) :: ipft ! functional type index + real(r8),intent(out) :: crown_depth ! The depth of the crown [m] + + associate( p1 => prt_params%allom_h2cd1(ipft), & + p2 => prt_params%allom_h2cd2(ipft), & + allom_dmode => prt_params%allom_dmode(ipft)) + + select case (allom_dmode) + case (1) ! Default, linear relationship with height + crown_depth = p1 * height + case (2) ! Power law, akin to Poorter et al. (2006). + !---~--- + ! Apply the two coefficients, but make sure crown depth does not exceed + ! the plant's height. + !---~--- + crown_depth = min(height, p1 * height ** p2) + !---~--- + case default + write(fates_log(),*) 'Invalid settings for crown depth mode for PFT ',ipft,'.' + write(fates_log(),*) 'Current allom_dmode: ',allom_dmode,'.' + write(fates_log(),*) 'Valid allom_dmode values: 1 or 2.' + write(fates_log(),*) 'Aborting' + call endrun(msg=errMsg(sourcefile, __LINE__)) + end select + end associate - ! Alternative Hypothesis: - ! Original FATES crown depth heigh used for hydraulics - ! crown_depth = min(height,0.1_r8) + return + end subroutine CrownDepth + ! ===================================================================================== - crown_depth = prt_params%crown_depth_frac(ft) * height - - return - end subroutine CrownDepth @@ -2173,7 +2423,99 @@ subroutine carea_2pwr(dbh,spread,d2bl_p2,d2bl_ediff,d2ca_min, & endif end subroutine carea_2pwr - + + + ! ============================================================================= + + + subroutine carea_3pwr(dbh,height,ipft,dbh_maxh,spread,dh2bl_p2,dh2bl_ediff, & + dh2ca_min,dh2ca_max,crowndamage,c_area,inverse) + !---~--- + ! Calculate area of ground covered by entire cohort. (m2) + ! Function of DBH (cm), height (m), canopy spread (m/cm) and number of + ! individuals. + !---~--- + + !--- List of arguments + real(r8) , intent(inout) :: dbh ! Diameter at breast/ref/ height [ cm] + real(r8) , intent(inout) :: height ! Height [ m] + integer(i4), intent(in) :: ipft ! PFT index + real(r8) , intent(in) :: dbh_maxh ! Minimum DBH at maximum height [ cm] + real(r8) , intent(in) :: spread ! site level relative spread score [ 0-1] + real(r8) , intent(in) :: dh2bl_p2 ! Exponent for size (bleaf) [ -] + real(r8) , intent(in) :: dh2bl_ediff ! Difference in size exponent [ -] + ! between crown area and bleaf + real(r8) , intent(in) :: dh2ca_min ! Minimum (closed forest) scaling [ -] + ! coefficient for crown area + real(r8) , intent(in) :: dh2ca_max ! Maximum (savannah) scaling [ -] + ! coefficient for crown area + integer , intent(in) :: crowndamage ! Crown damage class [ -] + ! [1: undamaged, >1: damaged] + real(r8) , intent(inout) :: c_area ! crown area for one plant [ m2] + logical , intent(in) :: inverse ! If true, calculate dbh from crown + ! area rather than its reverse + !--- Local variables + real(r8) :: size ! Size (Diameter^2 * Height) [cm2 m] + real(r8) :: dh2ca_p1 ! Effective scaling factor (crown area) [ -] + real(r8) :: dh2ca_p2 ! Effective exponent (crown area) [ -] + real(r8) :: crown_reduction ! Crown area reduction due to damage. [ -] + !---~--- + + + !---~--- + ! Define the scaling (log-intercept) and exponent (log-slope) parameters for + ! crown area. The scaling parameter accounts for the site-level spread elasticity. + ! The exponent is defined in terms of the leaf biomass exponent plus an offset + ! parameter (allom_blca_expnt_diff). This is done because the default in FATES is + ! for both exponents to be same (i.e., allom_blca_expnt_diff = 0.) so the per-plant + ! canopy area remains invariant during growth. However, allometric models in general + ! predict that leaf area grows faster than crown area. + !---~--- + dh2ca_p1 = spread * dh2ca_max + (1._r8 - spread) * dh2ca_min + dh2ca_p2 = dh2bl_p2 + dh2bl_ediff + !---~--- + + + + !---~--- + ! Decide whether to use DBH and height to find crown area (default) or the + ! other way round. + !---~--- + select case (inverse) + case (.false.) + !--- Find the maximum area + size = dbh * dbh * height + c_area = dh2ca_p1 * size ** dh2ca_p2 + !---~--- + + !--- Reduce area if the crown is damaged. + if (crowndamage > 1) then + call GetCrownReduction(crowndamage, crown_reduction) + c_area = c_area * (1.0_r8 - crown_reduction) + end if + !---~--- + case (.true.) + !--- Reduce area if the crown is damaged. + if (crowndamage > 1) then + call GetCrownReduction(crowndamage, crown_reduction) + c_area = c_area * (1.0_r8 - crown_reduction) + end if + !---~--- + + + !---~--- + ! Find the size, then use a root-finding algorithm to find DBH. + !---~--- + size = ( c_area / dh2ca_p1 ) ** ( 1.0_r8 / dh2ca_p2 ) + call size2dbh(size,ipft,dbh,dbh_maxh) + !---~--- + end select + !---~--- + + return + end subroutine carea_3pwr + + ! ========================================================================= subroutine set_root_fraction(root_fraction, ft, zi, max_nlevroot) @@ -2406,7 +2748,7 @@ end subroutine jackson_beta_root_profile ! ===================================================================================== - real(r8) function decay_coeff_kn(pft,vcmax25top) + real(r8) function decay_coeff_vcmax(vcmax25top,slope_param,intercept_param) ! --------------------------------------------------------------------------------- ! This function estimates the decay coefficient used to estimate vertical @@ -2414,13 +2756,16 @@ real(r8) function decay_coeff_kn(pft,vcmax25top) ! ! Decay coefficient (kn) is a function of vcmax25top for each pft. ! - ! Currently, this decay is applied to vcmax attenuation, and SLA (optionally) + ! Currently, this decay is applied to vcmax attenuation, SLA (optionally) + ! and leaf respiration (optionally w/ Atkin) ! ! --------------------------------------------------------------------------------- !ARGUMENTS - integer, intent(in) :: pft + real(r8),intent(in) :: vcmax25top + real(r8),intent(in) :: slope_param ! multiplies vcmax25top + real(r8),intent(in) :: intercept_param ! adds to vcmax25top !LOCAL VARIABLES @@ -2429,14 +2774,17 @@ real(r8) function decay_coeff_kn(pft,vcmax25top) ! Bonan et al (2011) JGR, 116, doi:10.1029/2010JG001593 used ! kn = 0.11. Here, we derive kn from vcmax25 as in Lloyd et al ! (2010) Biogeosciences, 7, 1833-1859 + ! This function is also used to vertically scale leaf maintenance + ! respiration. - decay_coeff_kn = exp(0.00963_r8 * vcmax25top - 2.43_r8) + decay_coeff_vcmax = exp(slope_param * vcmax25top - intercept_param) return - end function decay_coeff_kn - + end function decay_coeff_vcmax + ! ===================================================================================== -subroutine ForceDBH( ipft, crowndamage, canopy_trim, elongf_leaf, elongf_stem, d, h, bdead, bl ) + + subroutine ForceDBH( ipft, crowndamage, canopy_trim, elongf_leaf, elongf_stem, d, h, bdead, bl ) ! ========================================================================= ! This subroutine estimates the diameter based on either the structural biomass @@ -2586,6 +2934,117 @@ subroutine ForceDBH( ipft, crowndamage, canopy_trim, elongf_leaf, elongf_stem, d return end subroutine ForceDBH + ! ========================================================================= + + subroutine VegAreaLayer(tree_lai,tree_sai,tree_height,iv,nv,pft,snow_depth, & + vai_top,vai_bot, elai_layer,esai_layer,tlai_layer,tsai_layer) + + ! ----------------------------------------------------------------------------------- + ! This routine returns the exposed leaf and stem areas (m2 of leaf and stem) per m2 of + ! ground inside the crown, for the leaf-layer specified. + ! ----------------------------------------------------------------------------------- + + real(r8),intent(in) :: tree_lai ! the in-crown leaf area index for the plant + ! [m2 leaf/m2 crown footprint] + real(r8),intent(in) :: tree_sai ! the in-crown stem area index for the plant + ! [m2 stem/m2 crown footprint] + real(r8),intent(in) :: tree_height ! the height of the plant [m] + integer,intent(in) :: iv ! vegetation layer index + integer,intent(in) :: nv ! this plants total number of veg layers + integer,intent(in) :: pft ! plant functional type index + real(r8),intent(in) :: snow_depth ! the depth of snow on the ground [m] + real(r8),intent(out) :: vai_top + real(r8),intent(out) :: vai_bot ! the VAI of the bin top and bottom + real(r8),intent(out) :: elai_layer ! exposed leaf area index of the layer + real(r8),intent(out) :: esai_layer ! exposed stem area index of the layer + real(r8),optional,intent(out) :: tlai_layer ! total leaf area index of the layer + real(r8),optional,intent(out) :: tsai_layer ! total stem area index of the layer + + ! [m2 of leaf in bin / m2 crown footprint] + real(r8) :: tree_vai ! the in-crown veg area index for the plant + real(r8) :: crown_depth ! crown depth of the plant [m] + real(r8) :: frac_crown_depth ! fraction of the crown depth (relative to plant height) + real(r8) :: fraction_exposed ! fraction of the veg media that is above snow + real(r8) :: layer_top_height ! Physical height of the layer top relative to ground [m] + real(r8) :: layer_bot_height ! Physical height of the layer bottom relative to ground [m] + real(r8) :: tlai,tsai ! temporary total area indices [m2/m2] + real(r8) :: fleaf ! fraction of biomass in layer that is leaf + real(r8) :: remainder ! old-method: remainder of biomass in last bin + integer, parameter :: layer_height_const_depth = 1 ! constant physical depth assumption + integer, parameter :: layer_height_const_lad = 2 ! constant leaf area depth assumption + integer, parameter :: layer_height_method = layer_height_const_depth + + tree_vai = tree_lai + tree_sai + + ! Ratio between crown depth and plant height + call CrownDepth(tree_height,pft,crown_depth) + frac_crown_depth = crown_depth / tree_height + + if_any_vai: if(tree_vai>0._r8)then + + if(iv==0)then + vai_top = 0.0 + vai_bot = tree_vai + else + + if(iv>1)then + vai_top = dlower_vai(iv) - dinc_vai(iv) + else + vai_top = 0._r8 + end if + + if(iv= size_maxh) then + dbh = sqrt(size/hgt) + return + end if + !---~--- + + + !--- First guess: use current DBH. + adbh = dbh + call h_allom(adbh,ipft,hgt,dhgtddbh) + afun = adbh * adbh * hgt - size + deriv = 2.0_r8 * adbh * hgt + adbh * adbh * dhgtddbh + !---~--- + + + !--- Copy just in case it fails at the first iteration. + zdbh = adbh + zfun = afun + !---~--- + + + !---~--- + ! Enter the Newton's method loop + !---~--- + converged = .false. + newton_loop: do itn = 1, maxit_newt + !--- If derivative is too flat, go to Regula Falsi + if ( abs(deriv) < toler) exit newton_loop + !---~--- + + + !--- Copy the previous guess. + adbh = zdbh + afun = zfun + !---~--- + + + !--- Find the new guess, and evaluate the function and derivative. + zdbh = adbh - afun / deriv + call h_allom(zdbh,ipft,hgt,dhgtddbh) + zfun = zdbh * zdbh * hgt - size + deriv = 2.0_r8 * zdbh * hgt + zdbh * zdbh * dhgtddbh + !---~--- + + !--- Check convergence. + converged = abs(adbh - zdbh) < toler * zdbh + if (converged) then + !--- Convergence by iterations. + dbh = 0.5_r8 * (adbh + zdbh) + return + !---~--- + else if (abs(zfun) < nearzero) then + !--- Convergence by luck. + dbh = zdbh + return + !---~--- + end if + !---~--- + end do newton_loop + !---~--- + + + + !---~--- + ! If we have reached this point, then Newton's method has failed. Use Regula + ! Falsi instead. For this, we must have two guesses whose function evaluation has + ! opposite signs. + !---~--- + if (afun * zfun <= -nearzero) then + !--- We already have two guesses with opposite signs. + zside = .true. + !---~--- + else + !--- Look for another guess with opposite sign. + if (abs(zfun-afun) < 100._r8 * toler * adbh) then + delta = 100._r8 * toler * adbh + else + delta = max( abs( afun * (zdbh-adbh) / (zfun-afun) ),100._r8 * toler * adbh ) + end if + !---~--- + + + !---~--- + ! Try guesses on both sides of the first guess, sending guesses increasingly + ! further away until we find a good guess. + !---~--- + zdbh = adbh + delta + zside = .false. + zguess_loop: do iti=1,maxit_rf + zdbh = adbh + real((-1)**iti * (iti+3)/2,r8) * delta + call h_allom(zdbh,ipft,hgt) + zfun = zdbh * zdbh * hgt - size + zside = afun * zfun < -nearzero + if (zside) exit zguess_loop + end do zguess_loop + + !---~--- + ! Issue an error in case the function failed finding a second guess. + !---~--- + if (.not. zside) then + write (unit=*,fmt='(a)') '---~---' + write (unit=*,fmt='(a)') ' Failed finding the second guess:' + write (unit=*,fmt='(a)') '---~---' + write (unit=*,fmt='(a)') ' ' + write (unit=*,fmt='(a)') ' Input: ' + write (unit=*,fmt='(a,1x,es14.7)') ' + size =',size + write (unit=*,fmt='(a,1x,es14.7)') ' + dbh =',dbh + write (unit=*,fmt='(a)') ' ' + write (unit=*,fmt='(a)') ' Current guesses and evaluations:' + write (unit=*,fmt='(a,1x,es14.7)') ' + adbh =',adbh + write (unit=*,fmt='(a,1x,es14.7)') ' + afun =',afun + write (unit=*,fmt='(a,1x,es14.7)') ' + zdbh =',zdbh + write (unit=*,fmt='(a,1x,es14.7)') ' + zfun =',zfun + write (unit=*,fmt='(a)') ' ' + write (unit=*,fmt='(a)') '---~---' + write(fates_log(),*) 'Second guess for Regula Falsi method not found.' + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + !---~--- + end if + !---~--- + + !---~--- + ! Proceed to the regula falsi loop. + !---~--- + regfalsi_loop: do iti=1,maxit_rf + + !--- Update solution. + rdbh = ( zfun * adbh - afun * zdbh ) / ( zfun - afun) + !---~--- + + + !---~--- + ! Check for convergence. In case it converged, we can exit the sub-routine. + !---~--- + converged = abs(rdbh - adbh) < toler * max(rdbh,adbh) + if (converged) exit regfalsi_loop + !---~--- + + + !--- Find the new function evaluation. + call h_allom(rdbh,ipft,hgt) + rfun = rdbh * rdbh * hgt - size + !---~--- + + + !---~--- + ! Define the new searching interval based on the intermediate value theorem. + !---~--- + if (abs(rfun) < nearzero) then + !--- Converged by luck. + converged = .true. + exit regfalsi_loop + !---~--- + else if (rfun * afun <= -nearzero ) then + !--- Guess is between lower and current guess. + zdbh = rdbh + zfun = rfun + !--- If we are updating the upper side again, halve afun (Regula Falsi method). + if (zside) afun = afun * 0.5_r8 + !--- Flag that we have just updated the upper side. + zside = .true. + !---~--- + else + !--- Guess is between current and upper guess. + adbh = rdbh + afun = rfun + !--- If we are updating the lower side again, halve zfun (Regula Falsi method). + if (.not. zside) zfun = zfun * 0.5_r8 + !--- Flag that we have just updated the lower side. + zside = .false. + end if + end do regfalsi_loop + !---~--- + + + !---~--- + ! Check that the Regula Falsi method indeed converged. + !---~--- + if (converged) then + !--- Yes, return the last guess + dbh = rdbh + !---~--- + else + !--- No, report the bad news + write (unit=*,fmt='(a)') '---~---' + write (unit=*,fmt='(a)') ' Failed finding the solution:' + write (unit=*,fmt='(a)') '---~---' + write (unit=*,fmt='(a)') ' ' + write (unit=*,fmt='(a)') ' Input: ' + write (unit=*,fmt='(a,1x,es14.7)') ' + size =',size + write (unit=*,fmt='(a,1x,es14.7)') ' + dbh =',dbh + write (unit=*,fmt='(a)') ' ' + write (unit=*,fmt='(a)') ' Current guesses and evaluations:' + write (unit=*,fmt='(a,1x,es14.7)') ' + adbh =',adbh + write (unit=*,fmt='(a,1x,es14.7)') ' + afun =',afun + write (unit=*,fmt='(a,1x,es14.7)') ' + rdbh =',rdbh + write (unit=*,fmt='(a,1x,es14.7)') ' + rfun =',rfun + write (unit=*,fmt='(a,1x,es14.7)') ' + zdbh =',zdbh + write (unit=*,fmt='(a,1x,es14.7)') ' + zfun =',zfun + write (unit=*,fmt='(a)') ' ' + write (unit=*,fmt='(a)') '---~---' + write(fates_log(),*) 'Size to DBH routine failed to converge!' + call endrun(msg=errMsg(sourcefile, __LINE__)) + !---~--- + end if + !---~--- + + return + end subroutine size2dbh + ! ============================================================================ + end module FatesAllometryMod diff --git a/biogeochem/FatesCohortMod.F90 b/biogeochem/FatesCohortMod.F90 index ccbb095c6d..e98c4a345a 100644 --- a/biogeochem/FatesCohortMod.F90 +++ b/biogeochem/FatesCohortMod.F90 @@ -200,6 +200,8 @@ module FatesCohortMod !--------------------------------------------------------------------------- + integer :: twostr_col ! The column index in the two-stream solution that this cohort is part of + ! RESPIRATION COMPONENTS real(r8) :: rdark ! dark respiration [kgC/indiv/s] real(r8) :: resp_g_tstep ! growth respiration [kgC/indiv/timestep] diff --git a/biogeochem/FatesLandUseChangeMod.F90 b/biogeochem/FatesLandUseChangeMod.F90 index 33f5fb66d1..6e825a9b4d 100644 --- a/biogeochem/FatesLandUseChangeMod.F90 +++ b/biogeochem/FatesLandUseChangeMod.F90 @@ -15,6 +15,7 @@ module FatesLandUseChangeMod use FatesInterfaceTypesMod , only : hlm_use_luh use FatesInterfaceTypesMod , only : hlm_num_luh2_states use FatesInterfaceTypesMod , only : hlm_num_luh2_transitions + use FatesInterfaceTypesMod , only : hlm_use_potentialveg use FatesUtilsMod , only : FindIndex use EDTypesMod , only : area_site => area @@ -27,12 +28,13 @@ module FatesLandUseChangeMod character(len=*), parameter :: sourcefile = __FILE__ - public :: get_landuse_transition_rates - public :: get_landusechange_rules - public :: get_luh_statedata + public :: GetLanduseTransitionRates + public :: GetLanduseChangeRules + public :: GetLUHStatedata + public :: GetInitLanduseTransitionRates + public :: GetInitLanduseHarvestRate public :: fates_grazing - ! module data integer, parameter :: max_luh2_types_per_fates_lu_type = 5 @@ -61,16 +63,19 @@ module FatesLandUseChangeMod contains ! ============================================================================ - subroutine get_landuse_transition_rates(bc_in, landuse_transition_matrix) + subroutine GetLanduseTransitionRates(bc_in, min_allowed_landuse_fraction, landuse_transition_matrix, & + landuse_vector_gt_min) - ! The purpose of this routine is to ingest the land use transition rate information that the host model has read in from a dataset, - ! aggregate land use types to those being used in the simulation, and output a transition matrix that can be used to drive patch - ! disturbance rates. + ! The purpose of this routine is to ingest the land use transition rate information that the host + ! model has read in from a dataset,aggregate land use types to those being used in the simulation, + ! and output a transition matrix that can be used to drive patch disturbance rates. ! !ARGUMENTS: type(bc_in_type) , intent(in) :: bc_in - real(r8), intent(inout) :: landuse_transition_matrix(n_landuse_cats, n_landuse_cats) ! [m2/m2/day] + real(r8), intent(in) :: min_allowed_landuse_fraction + real(r8), intent(inout) :: landuse_transition_matrix(n_landuse_cats, n_landuse_cats) ! [m2/m2/day] + logical, intent(inout) :: landuse_vector_gt_min(n_landuse_cats) ! !LOCAL VARIABLES: type(luh2_fates_lutype_map) :: lumap @@ -80,42 +85,67 @@ subroutine get_landuse_transition_rates(bc_in, landuse_transition_matrix) real(r8) :: urban_fraction real(r8) :: temp_vector(hlm_num_luh2_transitions) logical :: modified_flag + real(r8) :: state_vector(n_landuse_cats) ! [m2/m2] + integer :: i_lu ! zero the transition matrix and the urban fraction landuse_transition_matrix(:,:) = 0._r8 urban_fraction = 0._r8 - ! Check the LUH data incoming to see if any of the transitions are NaN - temp_vector = bc_in%hlm_luh_transitions - call CheckLUHData(temp_vector,modified_flag) - if (.not. modified_flag) then - ! identify urban fraction so that it can be factored into the land use state output - urban_fraction = bc_in%hlm_luh_states(FindIndex(bc_in%hlm_luh_state_names,'urban')) - end if - - !!TODO: may need some logic here to ask whether or not ot perform land use change on this timestep. current code occurs every day. - !!If not doing transition every day, need to update units. - - transitions_loop: do i_luh2_transitions = 1, hlm_num_luh2_transitions - - ! transition names are written in form xxxxx_to_yyyyy where x and y are donor and receiver state names - transition_name = bc_in%hlm_luh_transition_names(i_luh2_transitions) - donor_name = transition_name(1:5) - receiver_name = transition_name(10:14) - - ! Get the fates land use type index associated with the luh2 state types - i_donor= lumap%GetIndex(donor_name) - i_receiver = lumap%GetIndex(receiver_name) - - ! Avoid transitions with 'urban' as those are handled seperately - if (.not.(i_donor .eq. fates_unset_int .or. i_receiver .eq. fates_unset_int)) then - landuse_transition_matrix(i_donor,i_receiver) = & - landuse_transition_matrix(i_donor,i_receiver) + temp_vector(i_luh2_transitions) * years_per_day / (1._r8 - urban_fraction) + ! if we are using potential veg only, then keep all transitions equal to zero. + if (hlm_use_potentialveg .eq. ifalse) then + ! Check the LUH data incoming to see if any of the transitions are NaN + temp_vector = bc_in%hlm_luh_transitions + call CheckLUHData(temp_vector,modified_flag) + if (.not. modified_flag) then + ! identify urban fraction so that it can be factored into the land use state output + urban_fraction = bc_in%hlm_luh_states(FindIndex(bc_in%hlm_luh_state_names,'urban')) end if - end do transitions_loop - end subroutine get_landuse_transition_rates + !! TODO: may need some logic here to ask whether or not ot perform land use change on this timestep. + !! current code occurs every day. If not doing transition every day, need to update units. + + transitions_loop: do i_luh2_transitions = 1, hlm_num_luh2_transitions + + ! transition names are written in form xxxxx_to_yyyyy where x and y are donor and receiver state names + transition_name = bc_in%hlm_luh_transition_names(i_luh2_transitions) + donor_name = transition_name(1:5) + receiver_name = transition_name(10:14) + + ! Get the fates land use type index associated with the luh2 state types + i_donor= lumap%GetIndex(donor_name) + i_receiver = lumap%GetIndex(receiver_name) + + ! Avoid transitions with 'urban' as those are handled seperately + ! Also ignore diagonal elements of transition matrix. + if (.not.(i_donor .eq. fates_unset_int .or. i_receiver .eq. fates_unset_int .or. & + i_donor .eq. i_receiver)) then + landuse_transition_matrix(i_donor,i_receiver) = & + landuse_transition_matrix(i_donor,i_receiver) + temp_vector(i_luh2_transitions) & + * years_per_day / (1._r8 - urban_fraction) + + end if + end do transitions_loop + + ! zero all transitions where the receiving land use type state vector is less than the minimum allowed, + ! and otherwise if this is the first timestep where the minimum was exceeded, + ! then apply all transitions from primary to this type and reset the flag + ! note that the flag resetting should not happen for secondary lands, as this is handled in the + ! logging logic + call GetLUHStatedata(bc_in, state_vector) + do i_lu = secondaryland, n_landuse_cats + if ( state_vector(i_lu) .le. min_allowed_landuse_fraction ) then + landuse_transition_matrix(:,i_lu) = 0._r8 + else if ((.not. landuse_vector_gt_min(i_lu)) .and. (i_lu .ne. secondaryland)) then + landuse_transition_matrix(:,i_lu) = 0._r8 + landuse_transition_matrix(primaryland,i_lu) = state_vector(i_lu) + landuse_vector_gt_min(i_lu) = .true. + end if + end do + end if + + end subroutine GetLanduseTransitionRates !---------------------------------------------------------------------------------------------------- @@ -143,18 +173,20 @@ end function GetLUCategoryFromStateName !---------------------------------------------------------------------------------------------------- - subroutine get_landusechange_rules(clearing_matrix) + subroutine GetLanduseChangeRules(clearing_matrix) - ! the purpose of this is to define a ruleset for when to clear the vegetation in transitioning from one land use type to another + ! the purpose of this is to define a ruleset for when to clear the vegetation in transitioning + ! from one land use type to another logical, intent(out) :: clearing_matrix(n_landuse_cats,n_landuse_cats) - ! default value of ruleset 4 above means that plants are not cleared during land use change transitions to rangeland, whereas plants are - ! cleared in transitions to pasturelands and croplands. - integer, parameter :: ruleset = 4 ! ruleset to apply from table 1 of Ma et al (2020) https://doi.org/10.5194/gmd-13-3203-2020 + ! default value of ruleset 4 above means that plants are not cleared during land use change + ! transitions to rangeland, whereas plants are cleared in transitions to pasturelands and croplands. + integer, parameter :: ruleset = 4 ! ruleset to apply from table 1 of Ma et al (2020) + ! https://doi.org/10.5194/gmd-13-3203-2020 - ! clearing matrix applies from the donor to the receiver land use type of the newly-transferred patch area - ! values of clearing matrix: false => do not clear; true => clear + ! clearing matrix applies from the donor to the receiver land use type of the newly-transferred + ! patch area values of clearing matrix: false => do not clear; true => clear clearing_matrix(:,:) = .false. @@ -162,8 +194,10 @@ subroutine get_landusechange_rules(clearing_matrix) case(1) - ! note that this ruleset isnt exactly what is in Ma et al. rulesets 1 and 2, because FATES does not make the distinction - ! between forested and non-forested lands from a land use/land cover perspective. + ! note that this ruleset isnt exactly what is in Ma et al. rulesets 1 and 2, because FATES + ! does not make the distinction between forested and non-forested lands from a land use/land + ! cover perspective. + clearing_matrix(:,cropland) = .true. clearing_matrix(:,pastureland) = .true. clearing_matrix(primaryland,rangeland) = .true. @@ -228,11 +262,11 @@ subroutine get_landusechange_rules(clearing_matrix) end select - end subroutine get_landusechange_rules + end subroutine GetLanduseChangeRules !---------------------------------------------------------------------------------------------------- - subroutine get_luh_statedata(bc_in, state_vector) + subroutine GetLUHStatedata(bc_in, state_vector) type(bc_in_type) , intent(in) :: bc_in real(r8), intent(out) :: state_vector(n_landuse_cats) ! [m2/m2] @@ -250,36 +284,45 @@ subroutine get_luh_statedata(bc_in, state_vector) state_vector(:) = 0._r8 urban_fraction = 0._r8 - ! Check to see if the incoming state vector is NaN. - temp_vector = bc_in%hlm_luh_states - call CheckLUHData(temp_vector,modified_flag) - if (.not. modified_flag) then - ! identify urban fraction so that it can be factored into the land use state output - urban_fraction = bc_in%hlm_luh_states(FindIndex(bc_in%hlm_luh_state_names,'urban')) - end if - - ! loop over all states and add up the ones that correspond to a given fates land use type - do i_luh2_states = 1, hlm_num_luh2_states - - ! Get the luh2 state name and determine fates aggregated land use - ! type index from the state to lutype map - state_name = bc_in%hlm_luh_state_names(i_luh2_states) - ii = lumap%GetIndex(state_name) - - ! Avoid 'urban' states whose indices have been given unset values - if (ii .ne. fates_unset_int) then - state_vector(ii) = state_vector(ii) + & - temp_vector(i_luh2_states) / (1._r8 - urban_fraction) + if (hlm_use_potentialveg .eq. itrue) then + state_vector(primaryland) = 1._r8 + else + ! Check to see if the incoming state vector is NaN. + temp_vector = bc_in%hlm_luh_states + call CheckLUHData(temp_vector,modified_flag) + if (.not. modified_flag) then + ! identify urban fraction so that it can be factored into the land use state output + urban_fraction = bc_in%hlm_luh_states(FindIndex(bc_in%hlm_luh_state_names,'urban')) end if - end do - ! check to ensure total area == 1, and correct if not - if ( abs(sum(state_vector(:)) - 1._r8) .gt. nearzero ) then - write(fates_log(),*) 'warning: sum(state_vector) = ', sum(state_vector(:)) - state_vector = state_vector / sum(state_vector) + ! loop over all states and add up the ones that correspond to a given fates land use type + do i_luh2_states = 1, hlm_num_luh2_states + + ! Get the luh2 state name and determine fates aggregated land use + ! type index from the state to lutype map + state_name = bc_in%hlm_luh_state_names(i_luh2_states) + ii = lumap%GetIndex(state_name) + + ! Avoid 'urban' states whose indices have been given unset values + if (ii .ne. fates_unset_int) then + state_vector(ii) = state_vector(ii) + & + temp_vector(i_luh2_states) / (1._r8 - urban_fraction) + end if + end do + + ! if all zeros, make all primary lands + if ( sum(state_vector(:)) .gt. nearzero ) then + + ! check to ensure total area == 1, and correct if not + if ( abs(sum(state_vector(:)) - 1._r8) .gt. nearzero ) then + state_vector(:) = state_vector(:) / sum(state_vector(:)) + end if + else + state_vector(primaryland) = 1._r8 + endif end if - end subroutine get_luh_statedata + end subroutine GetLUHStatedata !---------------------------------------------------------------------------------------------------- @@ -292,8 +335,8 @@ subroutine CheckLUHData(luh_vector,modified_flag) ! Check to see if the incoming luh2 vector is NaN. ! This suggests that there is a discepency where the HLM and LUH2 states - ! there is vegetated ground. E.g. LUH2 data is missing for glacier-margin regions such as Antarctica. - ! In this case, states should be Nan. If so, + ! there is vegetated ground. E.g. LUH2 data is missing for glacier-margin + ! regions such as Antarctica. In this case, states should be Nan. If so, ! set the current state to be all primary forest, and all transitions to be zero. ! If only a portion of the vector is NaN, there is something amiss with ! the data, so end the run. @@ -306,7 +349,8 @@ subroutine CheckLUHData(luh_vector,modified_flag) luh_vector(primaryland) = 1._r8 end if modified_flag = .true. - !write(fates_log(),*) 'WARNING: land use state is all NaN; setting state as all primary forest.' ! GL DIAG + !write(fates_log(),*) 'WARNING: land use state is all NaN; + !setting state as all primary forest.' ! GL DIAG else if (any(isnan(luh_vector))) then if (any(.not. isnan(luh_vector))) then write(fates_log(),*) 'ERROR: land use vector has NaN' @@ -316,6 +360,71 @@ subroutine CheckLUHData(luh_vector,modified_flag) end subroutine CheckLUHData + + subroutine GetInitLanduseHarvestRate(bc_in, min_allowed_landuse_fraction, harvest_rate, & + landuse_vector_gt_min) + + ! the purpose of this subroutine is, only under the case where we are transitioning from a spinup + ! run that did not have land use to a run that does, to apply the land-use changes needed to get + ! to the state vector in a single daily instance. this is for the hrvest rate from primary lands, + ! i.e. the transition from primary to secondary lands. thus instead of using the harvest dataset + ! itself, it only uses the state vector for what land use compositoin we want to achieve, and log + ! the forests accordingly. + + ! !ARGUMENTS: + type(bc_in_type) , intent(in) :: bc_in + real(r8), intent(in) :: min_allowed_landuse_fraction + real(r8), intent(out) :: harvest_rate ! [m2/ m2 / day] + logical, intent(inout) :: landuse_vector_gt_min(n_landuse_cats) + + ! LOCALS + real(r8) :: state_vector(n_landuse_cats) ! [m2/m2] + + call GetLUHStatedata(bc_in, state_vector) + + ! only do this if the state vector exceeds the minimum viable patch size, and if so, note that in the + ! landuse_vector_gt_min flag (which will be coming in as .false. because of the use_potentialveg logic). + if ( state_vector(secondaryland) .gt. min_allowed_landuse_fraction) then + harvest_rate = state_vector(secondaryland) + landuse_vector_gt_min(secondaryland) = .true. + endif + + end subroutine GetInitLanduseHarvestRate + + subroutine GetInitLanduseTransitionRates(bc_in, min_allowed_landuse_fraction, & + landuse_transition_matrix, landuse_vector_gt_min) + + ! The purpose of this subroutine is, only under the case where we are transitioning from a spinup + ! run that did not have land use to a run that does, to apply the land-use changes needed to get + ! to the state vector in a single daily instance. This is for the transitions other than harvest, + ! i.e. from primary lands to all other categories aside from secondary lands. + + ! !ARGUMENTS: + type(bc_in_type) , intent(in) :: bc_in + real(r8), intent(in) :: min_allowed_landuse_fraction + real(r8), intent(inout) :: landuse_transition_matrix(n_landuse_cats, n_landuse_cats) ! [m2/m2/day] + logical, intent(inout) :: landuse_vector_gt_min(n_landuse_cats) + + ! LOCALS + real(r8) :: state_vector(n_landuse_cats) ! [m2/m2] + integer :: i + + landuse_transition_matrix(:,:) = 0._r8 + + call GetLUHStatedata(bc_in, state_vector) + + ! only do this if the state vector exceeds the minimum viable patch size, and if so, note that + ! in the landuse_vector_gt_min flag (which will be coming in as .false. because of the + ! use_potentialveg logic). + do i = secondaryland+1,n_landuse_cats + if ( state_vector(i) .gt. min_allowed_landuse_fraction) then + landuse_transition_matrix(primaryland,i) = state_vector(i) + landuse_vector_gt_min(i) = .true. + end if + end do + + end subroutine GetInitLanduseTransitionRates + !---------------------------------------------------------------------------------------------------- subroutine fates_grazing(prt, ft, land_use_label, height) diff --git a/biogeochem/FatesPatchMod.F90 b/biogeochem/FatesPatchMod.F90 index fbef6dcfc4..b5489f6e82 100644 --- a/biogeochem/FatesPatchMod.F90 +++ b/biogeochem/FatesPatchMod.F90 @@ -16,14 +16,16 @@ module FatesPatchMod use FatesLitterMod, only : litter_type use PRTGenericMod, only : num_elements use PRTGenericMod, only : element_list - use EDParamsMod, only : maxSWb, nlevleaf, nclmax, maxpft + use EDParamsMod, only : nlevleaf, nclmax, maxpft use FatesConstantsMod, only : n_dbh_bins, n_dist_types - use FatesConstantsMod, only : n_rad_stream_types use FatesConstantsMod, only : t_water_freeze_k_1atm use FatesRunningMeanMod, only : ema_24hr, fixed_24hr, ema_lpa, ema_longterm use FatesRunningMeanMod, only : ema_sdlng_emerg_h2o, ema_sdlng_mort_par use FatesRunningMeanMod, only : ema_sdlng2sap_par, ema_sdlng_mdd - + use TwoStreamMLPEMod, only : twostream_type + use FatesRadiationMemMod,only : num_swb + use FatesRadiationMemMod,only : num_rad_stream_types + use FatesInterfaceTypesMod,only : hlm_hio_ignore_val use shr_infnan_mod, only : nan => shr_infnan_nan, assignment(=) use shr_log_mod, only : errMsg => shr_log_errMsg @@ -62,6 +64,7 @@ module FatesPatchMod integer :: ncl_p ! number of occupied canopy layers integer :: land_use_label ! patch label for land use classification (primaryland, secondaryland, etc) real(r8) :: age_since_anthro_disturbance ! average age for secondary forest since last anthropogenic disturbance [years] + logical :: changed_landuse_this_ts ! logical flag to track patches that have just undergone land use change [only used with nocomp and land use change] !--------------------------------------------------------------------------- @@ -111,24 +114,21 @@ module FatesPatchMod real(r8) :: c_stomata ! mean stomatal conductance of all leaves in the patch [umol/m2/s] real(r8) :: c_lblayer ! mean boundary layer conductance of all leaves in the patch [umol/m2/s] - !TODO - can we delete these? - real(r8) :: layer_height_profile(nclmax,maxpft,nlevleaf) real(r8) :: psn_z(nclmax,maxpft,nlevleaf) - real(r8) :: nrmlzd_parprof_pft_dir_z(n_rad_stream_types,nclmax,maxpft,nlevleaf) - real(r8) :: nrmlzd_parprof_pft_dif_z(n_rad_stream_types,nclmax,maxpft,nlevleaf) - real(r8) :: nrmlzd_parprof_dir_z(n_rad_stream_types,nclmax,nlevleaf) - real(r8) :: nrmlzd_parprof_dif_z(n_rad_stream_types,nclmax,nlevleaf) + real(r8) :: nrmlzd_parprof_pft_dir_z(num_rad_stream_types,nclmax,maxpft,nlevleaf) + real(r8) :: nrmlzd_parprof_pft_dif_z(num_rad_stream_types,nclmax,maxpft,nlevleaf) !--------------------------------------------------------------------------- ! RADIATION - real(r8) :: radiation_error ! radiation error [W/m2] + real(r8) :: rad_error(num_swb) ! radiation consv error by band [W/m2] real(r8) :: fcansno ! fraction of canopy covered in snow [0-1] logical :: solar_zenith_flag ! integer flag specifying daylight (based on zenith angle) real(r8) :: solar_zenith_angle ! solar zenith angle [radians] - real(r8) :: gnd_alb_dif(maxSWb) ! ground albedo for diffuse rad, both bands [0-1] - real(r8) :: gnd_alb_dir(maxSWb) ! ground albedo for direct rad, both bands [0-1] - + real(r8) :: gnd_alb_dif(num_swb) ! ground albedo for diffuse rad, both bands [0-1] + real(r8) :: gnd_alb_dir(num_swb) ! ground albedo for direct rad, both bands [0-1] + + ! organized by canopy layer, pft, and leaf layer real(r8) :: fabd_sun_z(nclmax,maxpft,nlevleaf) ! sun fraction of direct light absorbed [0-1] real(r8) :: fabd_sha_z(nclmax,maxpft,nlevleaf) ! shade fraction of direct light absorbed [0-1] @@ -136,15 +136,14 @@ module FatesPatchMod real(r8) :: fabi_sha_z(nclmax,maxpft,nlevleaf) ! shade fraction of indirect light absorbed [0-1] real(r8) :: ed_parsun_z(nclmax,maxpft,nlevleaf) ! PAR absorbed in the sun [W/m2] real(r8) :: ed_parsha_z(nclmax,maxpft,nlevleaf) ! PAR absorbed in the shade [W/m2] + real(r8) :: f_sun(nclmax,maxpft,nlevleaf) ! fraction of leaves in the sun [0-1] real(r8) :: ed_laisun_z(nclmax,maxpft,nlevleaf) real(r8) :: ed_laisha_z(nclmax,maxpft,nlevleaf) - real(r8) :: f_sun(nclmax,maxpft,nlevleaf) ! fraction of leaves in the sun [0-1] + ! radiation profiles for comparison against observations real(r8) :: parprof_pft_dir_z(nclmax,maxpft,nlevleaf) ! direct-beam PAR profile through canopy, by canopy, PFT, leaf level [W/m2] real(r8) :: parprof_pft_dif_z(nclmax,maxpft,nlevleaf) ! diffuse PAR profile through canopy, by canopy, PFT, leaf level [W/m2] - real(r8) :: parprof_dir_z(nclmax,nlevleaf) ! direct-beam PAR profile through canopy, by canopy, leaf level [W/m2] - real(r8) :: parprof_dif_z(nclmax,nlevleaf) ! diffuse PAR profile through canopy, by canopy, leaf level [W/m2] real(r8), allocatable :: tr_soil_dir(:) ! fraction of incoming direct radiation transmitted to the soil as direct, by numSWB [0-1] real(r8), allocatable :: tr_soil_dif(:) ! fraction of incoming diffuse radiation that is transmitted to the soil as diffuse [0-1] @@ -155,6 +154,10 @@ module FatesPatchMod real(r8), allocatable :: sabs_dir(:) ! fraction of incoming direct radiation that is absorbed by the canopy real(r8), allocatable :: sabs_dif(:) ! fraction of incoming diffuse radiation that is absorbed by the canopy + ! Twostream data structures + type(twostream_type) :: twostr ! This holds all two-stream data and procedures + + !--------------------------------------------------------------------------- ! ROOTS @@ -318,16 +321,13 @@ subroutine NanValues(this) this%ncan(:,:) = fates_unset_int this%c_stomata = nan this%c_lblayer = nan - this%layer_height_profile(:,:,:) = nan this%psn_z(:,:,:) = nan this%nrmlzd_parprof_pft_dir_z(:,:,:,:) = nan this%nrmlzd_parprof_pft_dif_z(:,:,:,:) = nan - this%nrmlzd_parprof_dir_z(:,:,:) = nan - this%nrmlzd_parprof_dir_z(:,:,:) = nan ! RADIATION - this%radiation_error = nan + this%rad_error(:) = nan this%fcansno = nan this%solar_zenith_flag = .false. this%solar_zenith_angle = nan @@ -336,7 +336,7 @@ subroutine NanValues(this) this%fabd_sun_z(:,:,:) = nan this%fabd_sha_z(:,:,:) = nan this%fabi_sun_z(:,:,:) = nan - this%fabi_sha_z(:,:,:) = nan + this%fabi_sha_z(:,:,:) = nan this%ed_laisun_z(:,:,:) = nan this%ed_laisha_z(:,:,:) = nan this%ed_parsun_z(:,:,:) = nan @@ -344,8 +344,6 @@ subroutine NanValues(this) this%f_sun(:,:,:) = nan this%parprof_pft_dir_z(:,:,:) = nan this%parprof_pft_dif_z(:,:,:) = nan - this%parprof_dir_z(:,:) = nan - this%parprof_dif_z(:,:) = nan this%tr_soil_dir(:) = nan this%tr_soil_dif(:) = nan this%tr_soil_dir_dif(:) = nan @@ -418,19 +416,17 @@ subroutine ZeroValues(this) this%psn_z(:,:,:) = 0.0_r8 this%nrmlzd_parprof_pft_dir_z(:,:,:,:) = 0.0_r8 this%nrmlzd_parprof_pft_dif_z(:,:,:,:) = 0.0_r8 - this%nrmlzd_parprof_dir_z(:,:,:) = 0.0_r8 - this%nrmlzd_parprof_dif_z(:,:,:) = 0.0_r8 ! RADIATION - this%radiation_error = 0.0_r8 + this%rad_error(:) = 0.0_r8 this%fabd_sun_z(:,:,:) = 0.0_r8 this%fabd_sha_z(:,:,:) = 0.0_r8 this%fabi_sun_z(:,:,:) = 0.0_r8 this%fabi_sha_z(:,:,:) = 0.0_r8 this%ed_parsun_z(:,:,:) = 0.0_r8 - this%ed_parsha_z(:,:,:) = 0.0_r8 - this%ed_laisun_z(:,:,:) = 0.0_r8 - this%ed_laisha_z(:,:,:) = 0.0_r8 + this%ed_parsha_z(:,:,:) = 0.0_r8 + this%ed_laisun_z(:,:,:) = 0._r8 + this%ed_laisha_z(:,:,:) = 0._r8 this%f_sun = 0.0_r8 this%tr_soil_dir_dif(:) = 0.0_r8 this%fab(:) = 0.0_r8 @@ -563,7 +559,7 @@ end subroutine InitLitter !=========================================================================== - subroutine Create(this, age, area, label, nocomp_pft, num_swb, num_pft, & + subroutine Create(this, age, area, land_use_label, nocomp_pft, num_swb, num_pft, & num_levsoil, current_tod, regeneration_model) ! ! DESCRIPTION: @@ -574,7 +570,7 @@ subroutine Create(this, age, area, label, nocomp_pft, num_swb, num_pft, & class(fates_patch_type), intent(inout) :: this ! patch object real(r8), intent(in) :: age ! notional age of this patch in years real(r8), intent(in) :: area ! initial area of this patch in m2. - integer, intent(in) :: label ! anthropogenic disturbance label + integer, intent(in) :: land_use_label ! land use label integer, intent(in) :: nocomp_pft ! no-competition mode pft label integer, intent(in) :: num_swb ! number of shortwave broad-bands to track integer, intent(in) :: num_pft ! number of pfts to simulate @@ -591,15 +587,19 @@ subroutine Create(this, age, area, label, nocomp_pft, num_swb, num_pft, & ! initialize litter call this%InitLitter(num_pft, num_levsoil) - + + this%twostr%scelg => null() ! The radiation module will check if this + ! is associated, since it is not, it will then + ! initialize and allocate + ! assign known patch attributes this%age = age this%age_class = 1 this%area = area ! assign anthropgenic disturbance category and label - this%land_use_label = label - if (label .eq. secondaryland) then + this%land_use_label = land_use_label + if (land_use_label .eq. secondaryland) then this%age_since_anthro_disturbance = age else this%age_since_anthro_disturbance = fates_unset_r8 @@ -610,6 +610,8 @@ subroutine Create(this, age, area, label, nocomp_pft, num_swb, num_pft, & this%tr_soil_dif(:) = 1.0_r8 this%NCL_p = 1 + this%changed_landuse_this_ts = .false. + end subroutine Create !=========================================================================== @@ -646,7 +648,12 @@ subroutine FreeMemory(this, regeneration_model, numpft) endif ccohort => ncohort end do - + + ! Deallocate Radiation scattering elements + if(associated(this%twostr%scelg)) then + call this%twostr%DeallocTwoStream() + end if + ! deallocate all litter objects do el=1,num_elements call this%litter(el)%DeallocateLitt() diff --git a/biogeochem/FatesSoilBGCFluxMod.F90 b/biogeochem/FatesSoilBGCFluxMod.F90 index 9d813c32b3..2c5b7d9b18 100644 --- a/biogeochem/FatesSoilBGCFluxMod.F90 +++ b/biogeochem/FatesSoilBGCFluxMod.F90 @@ -69,6 +69,7 @@ module FatesSoilBGCFluxMod use FatesConstantsMod, only : sec_per_day use FatesConstantsMod, only : years_per_day use FatesConstantsMod, only : itrue + use FatesConstantsMod, only : nocomp_bareground use FatesLitterMod, only : litter_type use FatesLitterMod , only : ncwd use FatesLitterMod , only : ndcmpy @@ -287,107 +288,107 @@ subroutine PrepCH4BCs(csite,bc_in,bc_out) fp = 0 cpatch => csite%oldest_patch do while (associated(cpatch)) - - ! Patch ordering when passing boundary conditions - ! always goes from oldest to youngest, following - ! the convention of EDPatchDynamics::set_patchno() - - fp = fp + 1 - - agnpp = 0._r8 - bgnpp = 0._r8 - woody_area = 0._r8 - plant_area = 0._r8 - - ccohort => cpatch%tallest - do while (associated(ccohort)) + if_notbare: if(cpatch%nocomp_pft_label .ne. nocomp_bareground)then + ! Patch ordering when passing boundary conditions + ! always goes from oldest to youngest, following + ! the convention of EDPatchDynamics::set_patchno() - ! For consistency, only apply calculations to non-new - ! cohorts. New cohorts will not have respiration rates - ! at this point in the call sequence. + fp = fp + 1 - if(.not.ccohort%isnew) then - - pft = ccohort%pft - - call set_root_fraction(csite%rootfrac_scr, pft, csite%zi_soil, & - bc_in%max_rooting_depth_index_col ) - - fnrt_c = ccohort%prt%GetState(fnrt_organ, carbon12_element) - - ! [kgC/day] - sapw_net_alloc = ccohort%prt%GetNetAlloc(sapw_organ, carbon12_element) * days_per_sec - store_net_alloc = ccohort%prt%GetNetAlloc(store_organ, carbon12_element) * days_per_sec - leaf_net_alloc = ccohort%prt%GetNetAlloc(leaf_organ, carbon12_element) * days_per_sec - fnrt_net_alloc = ccohort%prt%GetNetAlloc(fnrt_organ, carbon12_element) * days_per_sec - struct_net_alloc = ccohort%prt%GetNetAlloc(struct_organ, carbon12_element) * days_per_sec - repro_net_alloc = ccohort%prt%GetNetAlloc(repro_organ, carbon12_element) * days_per_sec - - ! [kgC/plant/day] -> [gC/m2/s] - agnpp = agnpp + ccohort%n/cpatch%area * (leaf_net_alloc + repro_net_alloc + & - prt_params%allom_agb_frac(pft)*(sapw_net_alloc+store_net_alloc+struct_net_alloc)) * g_per_kg + agnpp = 0._r8 + bgnpp = 0._r8 + woody_area = 0._r8 + plant_area = 0._r8 + + ccohort => cpatch%tallest + do while (associated(ccohort)) - ! [kgC/plant/day] -> [gC/m2/s] - bgnpp = bgnpp + ccohort%n/cpatch%area * (fnrt_net_alloc + & - (1._r8-prt_params%allom_agb_frac(pft))*(sapw_net_alloc+store_net_alloc+struct_net_alloc)) * g_per_kg + ! For consistency, only apply calculations to non-new + ! cohorts. New cohorts will not have respiration rates + ! at this point in the call sequence. - if(hlm_use_ch4==itrue)then + if(.not.ccohort%isnew) then - ! Fine root fraction over depth - bc_out%rootfr_pa(fp,1:bc_in%nlevsoil) = & - bc_out%rootfr_pa(fp,1:bc_in%nlevsoil) + & - csite%rootfrac_scr(1:bc_in%nlevsoil) + pft = ccohort%pft + + call set_root_fraction(csite%rootfrac_scr, pft, csite%zi_soil, & + bc_in%max_rooting_depth_index_col ) + + fnrt_c = ccohort%prt%GetState(fnrt_organ, carbon12_element) + + ! [kgC/day] + sapw_net_alloc = ccohort%prt%GetNetAlloc(sapw_organ, carbon12_element) * days_per_sec + store_net_alloc = ccohort%prt%GetNetAlloc(store_organ, carbon12_element) * days_per_sec + leaf_net_alloc = ccohort%prt%GetNetAlloc(leaf_organ, carbon12_element) * days_per_sec + fnrt_net_alloc = ccohort%prt%GetNetAlloc(fnrt_organ, carbon12_element) * days_per_sec + struct_net_alloc = ccohort%prt%GetNetAlloc(struct_organ, carbon12_element) * days_per_sec + repro_net_alloc = ccohort%prt%GetNetAlloc(repro_organ, carbon12_element) * days_per_sec + + ! [kgC/plant/day] -> [gC/m2/s] + agnpp = agnpp + ccohort%n/cpatch%area * (leaf_net_alloc + repro_net_alloc + & + prt_params%allom_agb_frac(pft)*(sapw_net_alloc+store_net_alloc+struct_net_alloc)) * g_per_kg + + ! [kgC/plant/day] -> [gC/m2/s] + bgnpp = bgnpp + ccohort%n/cpatch%area * (fnrt_net_alloc + & + (1._r8-prt_params%allom_agb_frac(pft))*(sapw_net_alloc+store_net_alloc+struct_net_alloc)) * g_per_kg - ! Fine root carbon, convert [kg/plant] -> [g/m2] - bc_out%frootc_pa(fp) = & - bc_out%frootc_pa(fp) + & - fnrt_c*ccohort%n/cpatch%area * g_per_kg + if(hlm_use_ch4==itrue)then + + ! Fine root fraction over depth + bc_out%rootfr_pa(fp,1:bc_in%nlevsoil) = & + bc_out%rootfr_pa(fp,1:bc_in%nlevsoil) + & + csite%rootfrac_scr(1:bc_in%nlevsoil) + + ! Fine root carbon, convert [kg/plant] -> [g/m2] + bc_out%frootc_pa(fp) = & + bc_out%frootc_pa(fp) + & + fnrt_c*ccohort%n/cpatch%area * g_per_kg + + ! (gC/m2/s) root respiration (fine root MR + total root GR) + ! RGK: We do not save root respiration and average over the day. Until we do + ! this is a best (bad) guess at fine root MR + total root GR + ! (kgC/indiv/yr) -> gC/m2/s + bc_out%root_resp(1:bc_in%nlevsoil) = bc_out%root_resp(1:bc_in%nlevsoil) + & + ccohort%resp_acc_hold*years_per_day*g_per_kg*days_per_sec* & + ccohort%n*area_inv*(1._r8-prt_params%allom_agb_frac(pft)) * csite%rootfrac_scr(1:bc_in%nlevsoil) + + end if + + if( prt_params%woody(pft)==itrue ) then + woody_area = woody_area + ccohort%c_area + end if + plant_area = plant_area + ccohort%c_area - ! (gC/m2/s) root respiration (fine root MR + total root GR) - ! RGK: We do not save root respiration and average over the day. Until we do - ! this is a best (bad) guess at fine root MR + total root GR - ! (kgC/indiv/yr) -> gC/m2/s - bc_out%root_resp(1:bc_in%nlevsoil) = bc_out%root_resp(1:bc_in%nlevsoil) + & - ccohort%resp_acc_hold*years_per_day*g_per_kg*days_per_sec* & - ccohort%n*area_inv*(1._r8-prt_params%allom_agb_frac(pft)) * csite%rootfrac_scr(1:bc_in%nlevsoil) end if - if( prt_params%woody(pft)==itrue ) then - woody_area = woody_area + ccohort%c_area + ccohort => ccohort%shorter + end do + + if(hlm_use_ch4==itrue)then + if( sum(bc_out%rootfr_pa(fp,1:bc_in%nlevsoil)) > nearzero) then + bc_out%rootfr_pa(fp,1:bc_in%nlevsoil) = & + bc_out%rootfr_pa(fp,1:bc_in%nlevsoil) / & + sum(bc_out%rootfr_pa(fp,1:bc_in%nlevsoil)) end if - plant_area = plant_area + ccohort%c_area + ! RGK: These averages should switch to the new patch averaging methods + ! when available. Right now we are not doing any time averaging + ! because it would be mixing the memory of patches, which + ! would be arguably worse than just using the instantaneous value - end if - - ccohort => ccohort%shorter - end do - - if(hlm_use_ch4==itrue)then - if( sum(bc_out%rootfr_pa(fp,1:bc_in%nlevsoil)) > nearzero) then - bc_out%rootfr_pa(fp,1:bc_in%nlevsoil) = & - bc_out%rootfr_pa(fp,1:bc_in%nlevsoil) / & - sum(bc_out%rootfr_pa(fp,1:bc_in%nlevsoil)) - end if - - ! RGK: These averages should switch to the new patch averaging methods - ! when available. Right now we are not doing any time averaging - ! because it would be mixing the memory of patches, which - ! would be arguably worse than just using the instantaneous value - - ! gC/m2/s - bc_out%annavg_agnpp_pa(fp) = agnpp - bc_out%annavg_bgnpp_pa(fp) = bgnpp - ! gc/m2/yr - bc_out%annsum_npp_pa(fp) = (bgnpp+agnpp)*days_per_year*sec_per_day - - if(plant_area>nearzero) then - bc_out%woody_frac_aere_pa(fp) = woody_area/plant_area - end if + ! gC/m2/s + bc_out%annavg_agnpp_pa(fp) = agnpp + bc_out%annavg_bgnpp_pa(fp) = bgnpp + ! gc/m2/yr + bc_out%annsum_npp_pa(fp) = (bgnpp+agnpp)*days_per_year*sec_per_day + + if(plant_area>nearzero) then + bc_out%woody_frac_aere_pa(fp) = woody_area/plant_area + end if - end if - + end if + end if if_notbare cpatch => cpatch%younger end do diff --git a/biogeophys/CMakeLists.txt b/biogeophys/CMakeLists.txt new file mode 100644 index 0000000000..c6048491b9 --- /dev/null +++ b/biogeophys/CMakeLists.txt @@ -0,0 +1,4 @@ +list(APPEND fates_sources + FatesHydroWTFMod.F90) + +sourcelist_to_parent(fates_sources) \ No newline at end of file diff --git a/biogeophys/FatesHydroWTFMod.F90 b/biogeophys/FatesHydroWTFMod.F90 index 8356b2b165..69c7fce9aa 100644 --- a/biogeophys/FatesHydroWTFMod.F90 +++ b/biogeophys/FatesHydroWTFMod.F90 @@ -28,8 +28,14 @@ module FatesHydroWTFMod __FILE__ - real(r8), parameter :: min_ftc = 0.00001_r8 ! Minimum allowed fraction of total conductance + real(r8), parameter :: min_ftc = 0.0_r8 ! Minimum allowed fraction of total conductance + real(r8), parameter :: min_ftc_scalar=2.0_r8 ! This scalar is used to define the attenuation + ! of the weighting that we use for imposing + ! ftc min at the minimum allowable psi + ! A value of two yielded a wieghting factor of + ! about 0.175 after 1 MPa, and 0.025 after 2 MPA + ! Bounds on saturated fraction, outside of which we use linear PV or stop flow ! In this context, the saturated fraction is defined by the volumetric WC "th" ! and the volumetric residual and saturation "th_res" and "th_sat": (th-th_r)/(th_sat-th_res) @@ -44,6 +50,9 @@ module FatesHydroWTFMod ! elastic-caviation region + !real(r8), parameter :: min_theta_cch = 0.05_r8 ! Minimum theta (matches ctsm) + real(r8), parameter :: min_psi_cch = -15.0_r8 ! Minimum suction (MPa) + ! Generic class that can be extended to describe ! specific water retention functions @@ -79,7 +88,7 @@ module FatesHydroWTFMod procedure, non_overridable :: psi_linear_res procedure, non_overridable :: th_linear_sat procedure, non_overridable :: th_linear_res - procedure, non_overridable :: set_min_max + procedure, non_overridable :: set_min_max_from_satres procedure, non_overridable :: get_thmin end type wrf_type @@ -89,6 +98,7 @@ module FatesHydroWTFMod ! water conductance functions type, public :: wkf_type + type(wrf_type), pointer :: wrf ! Pointer to the matching water retention function contains procedure :: ftc_from_psi => ftc_from_psi_base procedure :: dftcdpsi_from_psi => dftcdpsi_from_psi_base @@ -240,7 +250,8 @@ module FatesHydroWTFMod procedure :: set_wkf_param => set_wkf_param_tfs end type wkf_type_tfs - + public :: get_min_ftc_weight + contains ! ===================================================================================== @@ -256,23 +267,25 @@ module FatesHydroWTFMod ! of numerical integration. ! ============================================================================ - subroutine set_min_max(this,th_res,th_sat) + subroutine set_min_max_from_satres(this,th_res,th_sat) ! This routine uses max_sf_interp and min_sft_interp ! to define the bounds of where the linear ranges start and stop - + ! This only works for functions defined by a saturation and + ! a residual value + class(wrf_type) :: this real(r8),intent(in) :: th_res real(r8),intent(in) :: th_sat this%th_max = max_sf_interp*(th_sat-th_res)+th_res this%th_min = min_sf_interp*(th_sat-th_res)+th_res - this%psi_max = this%psi_from_th(this%th_max-tiny(this%th_max)) - this%dpsidth_max = this%dpsidth_from_th(this%th_max-tiny(this%th_max)) - this%psi_min = this%psi_from_th(this%th_min+tiny(this%th_min)) - this%dpsidth_min = this%dpsidth_from_th(this%th_min+tiny(this%th_min)) + this%psi_max = this%psi_from_th(this%th_max) + this%dpsidth_max = this%dpsidth_from_th(this%th_max) + this%psi_min = this%psi_from_th(this%th_min) + this%dpsidth_min = this%dpsidth_from_th(this%th_min) - end subroutine set_min_max + end subroutine set_min_max_from_satres ! ============================================================================ @@ -341,7 +354,36 @@ function th_linear_res(this,psi) result(th) end function th_linear_res ! =========================================================================== + + subroutine get_min_ftc_weight(psi_min,psi,min_ftc_weight,dmin_ftc_weight_dpsi) + + ! This routine determines the weighting factor used + ! to generate a smooth curve to impose that min_ftc happens at min_psi + ! This method is to be used with any and all water transfer functions + + real(r8),intent(in) :: psi ! MPa suction + real(r8),intent(in) :: psi_min ! Minimum value of psi we track, value that pins to ftc_min + real(r8),intent(out):: min_ftc_weight ! weighting factor for min_ftc + real(r8),intent(out):: dmin_ftc_weight_dpsi ! derivative of weighting factor wrt psi + + ! If the difference between psi and psi-min is greater than 10MPa + ! just assume there is no effect of the minimum function (ie weight 0) + min_ftc_weight = exp(min_ftc_scalar*max(psi_min-psi,-10._r8)) + dmin_ftc_weight_dpsi = -min_ftc_scalar*exp(min_ftc_scalar*max(psi_min-psi,-10._r8)) + + if(min_ftc_weight>=1.)then + min_ftc_weight = 1._r8 + dmin_ftc_weight_dpsi = 0._r8 + elseif(min_ftc_weight<=0._r8)then + min_ftc_weight = 0._r8 + dmin_ftc_weight_dpsi = 0._r8 + end if + + return + end subroutine get_min_ftc_weight + ! ============================================================================= + subroutine set_wrf_param_base(this,params_in) class(wrf_type) :: this real(r8),intent(in) :: params_in(:) @@ -433,7 +475,7 @@ subroutine set_wrf_param_vg(this,params_in) this%th_sat = params_in(4) this%th_res = params_in(5) - call this%set_min_max(this%th_res,this%th_sat) + call this%set_min_max_from_satres(this%th_res,this%th_sat) return end subroutine set_wrf_param_vg @@ -611,7 +653,11 @@ function ftc_from_psi_vg(this,psi) result(ftc) real(r8) :: psi_eff real(r8) :: m ! pore size distribution param () real(r8) :: n ! pore size distribution param (psd) + real(r8) :: min_ftc_weight + real(r8) :: dmin_ftc_weight_dpsi + real(r8), pointer :: psi_min + psi_min => this%wrf%psi_min n = this%n_vg m = this%m_vg @@ -624,8 +670,18 @@ function ftc_from_psi_vg(this,psi) result(ftc) den = (1._r8 + (this%alpha*psi_eff)**n)**(this%tort*(m)) ! Make sure this is well behaved - ftc = min(1._r8,max(min_ftc,num/den)) + ftc = min(1._r8,num/den) + if(ftc<=min_ftc) then + ftc = min_ftc + else + ! Add protections and ensure no conductance at incredibly + ! low suction + call get_min_ftc_weight(psi_min,psi,min_ftc_weight,dmin_ftc_weight_dpsi) + + ftc = ftc*(1._r8 - min_ftc_weight) + min_ftc*min_ftc_weight + end if + else ftc = 1._r8 @@ -633,6 +689,9 @@ function ftc_from_psi_vg(this,psi) result(ftc) end function ftc_from_psi_vg + + + ! ==================================================================================== function dftcdpsi_from_psi_vg(this,psi) result(dftcdpsi) @@ -654,7 +713,11 @@ function dftcdpsi_from_psi_vg(this,psi) result(dftcdpsi) real(r8) :: dftcdpsi ! change in frac total cond wrt psi real(r8) :: m ! pore size distribution param (1/psd) real(r8) :: n + real(r8) :: min_ftc_weight + real(r8) :: dmin_ftc_weight_dpsi + real(r8), pointer :: psi_min + psi_min => this%wrf%psi_min n =this%n_vg m =this%m_vg @@ -664,8 +727,8 @@ function dftcdpsi_from_psi_vg(this,psi) result(dftcdpsi) psi_eff = -psi ! switch VG 1980 convention ftc = this%ftc_from_psi(psi) - - if(ftc<=min_ftc) then + + if ( abs(ftc-min_ftc)this%psi_max) then ! Linear range for extreme values th = this%th_max + (psi-this%psi_max)/this%dpsidth_max - else - th = this%th_sat*(psi/this%psi_sat)**(-1.0_r8/this%beta) + else + if(psithis%th_max) then psi = this%psi_max + this%dpsidth_max*(th-max_sf_interp*this%th_sat) - else - psi = this%psi_sat*(th/this%th_sat)**(-this%beta) + else + if(ththis%th_max) then - dpsidth = this%dpsidth_max + dpsidth = this%dpsidth_max else - dpsidth = -this%beta*this%psi_sat/this%th_sat * (th/this%th_sat)**(-this%beta-1._r8) + if(th this%wrf%psi_min + ! th = th_sat * (psi/psi_sat)^(-1/b) ! ftc = (th/th_sat)^(2*b+3) @@ -806,11 +903,19 @@ function ftc_from_psi_cch(this,psi) result(ftc) ! = ((psi/psi_sat)^(-1/b))^(2*b+3) ! = (psi/psi_sat)^(-2-3/b) - psi_eff = min(psi,this%psi_sat) ftc = (psi_eff/this%psi_sat)**(-2._r8-3._r8/this%beta) + if(ftc <= min_ftc) then + ftc = min_ftc + else + call get_min_ftc_weight(psi_min,psi,min_ftc_weight,dmin_ftc_weight_dpsi) + + ftc = ftc*(1._r8 - min_ftc_weight) + min_ftc*min_ftc_weight + + end if + end function ftc_from_psi_cch ! ==================================================================================== @@ -820,15 +925,37 @@ function dftcdpsi_from_psi_cch(this,psi) result(dftcdpsi) class(wkf_type_cch) :: this real(r8),intent(in) :: psi real(r8) :: dftcdpsi ! change in frac total cond wrt psi + real(r8) :: min_ftc_weight,dmin_ftc_weight_dpsi + real(r8) :: ftc + real(r8), pointer :: psi_min - ! Differentiate: - ! ftc = (psi/this%psi_sat)**(-2._r8-3._r8/this%beta) - + psi_min => this%wrf%psi_min + ! Note that if we assume a constant, capped FTC=1.0 ! at saturation, then the derivative is zero there if(psi this%wrf%psi_min pc = psi sat_res = 0._r8 alpha = -1._r8/this%psi_sat @@ -1269,8 +1399,18 @@ function ftc_from_psi_smooth_cch(this,psi) result(ftc) ! Here, `pc >= ps`. kr = 1.d0 endif - ftc = max(kr, min_ftc) + !ftc = max(kr, min_ftc) + + if(kr<=min_ftc) then + ftc = min_ftc + else + call get_min_ftc_weight(psi_min,psi,min_ftc_weight,dmin_ftc_weight_dpsi) + + ftc = kr*(1._r8 - min_ftc_weight) + min_ftc*min_ftc_weight + + end if + end function ftc_from_psi_smooth_cch @@ -1281,11 +1421,10 @@ function dftcdpsi_from_psi_smooth_cch(this,psi) result(dftcdpsi) class(wkf_type_smooth_cch) :: this real(r8),intent(in) :: psi real(r8) :: dftcdpsi ! change in frac total cond wrt psi - + real(r8) :: ftc real(r8) :: pc real(r8) :: kr real(r8) :: dkr_dP - ! real(r8) :: sat_res real(r8) :: alpha real(r8) :: lambda @@ -1293,46 +1432,65 @@ function dftcdpsi_from_psi_smooth_cch(this,psi) result(dftcdpsi) real(r8) :: deltaPc real(r8) :: dSe_dpc real(r8) :: dkr_dSe + real(r8) :: min_ftc_weight,dmin_ftc_weight_dpsi + real(r8), pointer :: psi_min - pc = psi - sat_res = 0._r8 - alpha = -1._r8/this%psi_sat - lambda = 1._r8/this%beta + psi_min => this%wrf%psi_min + ftc = this%ftc_from_psi(psi) + + if( abs(ftc-min_ftc)= ps`. - kr = 1.d0 - dkr_dP = 0.d0 - endif - dftcdpsi = dkr_dP - if(kr<=min_ftc) then - dftcdpsi = 0._r8 - endif + dkr_dSe = (3.d0 + 2.d0/lambda)*kr/Se + dkr_dp = dkr_dSe*dSe_dpc + elseif( pc < this%scch_ps ) then + ! Cubic smoothing regime. + ! Here, `pu < pc < ps <= 0`. + deltaPc = pc - this%scch_ps + Se = 1.d0 + deltaPc*deltaPc*(this%scch_b2 + deltaPc*this%scch_b3) + dSe_dpc = deltaPc*(2*this%scch_b2 + 3*deltaPc*this%scch_b3) + + kr = Se ** (2.5d0 + 2.d0/lambda) + + dkr_dSe = (2.5d0 + 2.d0/lambda)*kr/Se + dkr_dp = dkr_dSe*dSe_dpc + else + ! Saturated regime. + ! Here, `pc >= ps`. + kr = 1.d0 + dkr_dP = 0.d0 + endif + dftcdpsi = dkr_dP + + call get_min_ftc_weight(psi_min,psi,min_ftc_weight,dmin_ftc_weight_dpsi) + + ! differentiate: + ! ftc = ftc*(1._r8 - min_ftc_weight) + min_ftc*min_ftc_weight + ! ftc = ftc - ftc*min_ftc_weight + min_ftc*min_ftc_weight + + dftcdpsi = dftcdpsi - & + (dftcdpsi*min_ftc_weight + ftc*dmin_ftc_weight_dpsi) + & + min_ftc*dmin_ftc_weight_dpsi + + end if end function dftcdpsi_from_psi_smooth_cch @@ -1489,7 +1647,7 @@ subroutine set_wrf_param_tfs(this,params_in) this%cap_slp = params_in(8) this%pmedia = int(params_in(9)) - call this%set_min_max(this%th_res,this%th_sat) + call this%set_min_max_from_satres(this%th_res,this%th_sat) return end subroutine set_wrf_param_tfs @@ -1730,11 +1888,27 @@ function ftc_from_psi_tfs(this,psi) result(ftc) real(r8),intent(in) :: psi ! real(r8) :: ftc real(r8) :: psi_eff + real(r8) :: min_ftc_weight,dmin_ftc_weight_dpsi + real(r8), pointer :: psi_min + + psi_min => this%wrf%psi_min + psi_eff = max(psi_min,min(-nearzero,psi)) + + ftc = 1._r8/(1._r8 + (psi_eff/this%p50)**this%avuln) - psi_eff = min(-nearzero,psi) + if(ftc<=min_ftc) then + ftc = min_ftc + else + ! Add protections and ensure no conductance at incredibly + ! low suction - ftc = max(min_ftc,1._r8/(1._r8 + (psi_eff/this%p50)**this%avuln)) + call get_min_ftc_weight(psi_min,psi_eff,min_ftc_weight,dmin_ftc_weight_dpsi) + + ftc = ftc*(1._r8 - min_ftc_weight) + min_ftc*min_ftc_weight + end if + + end function ftc_from_psi_tfs ! ==================================================================================== @@ -1747,20 +1921,40 @@ function dftcdpsi_from_psi_tfs(this,psi) result(dftcdpsi) real(r8) :: fx ! portion of ftc function real(r8) :: dfx ! differentiation of portion of func real(r8) :: dftcdpsi ! change in frac total cond wrt psi + real(r8) :: min_ftc_weight,dmin_ftc_weight_dpsi + real(r8), pointer :: psi_min + real(r8) :: psi_eff + psi_min => this%wrf%psi_min + psi_eff = max(psi_min,min(-nearzero,psi)) + ! Differentiate ! ftc = 1._r8/(1._r8 + (psi/this%p50(ft))**this%avuln(ft)) - if(psi>0._r8)then + if(psi_eff>0._r8)then dftcdpsi = 0._r8 else - ftc = 1._r8/(1._r8 + (psi/this%p50)**this%avuln) - if(ftc sites(s)%si_hydr%wrf_soil(j)%p + end do + + ! Update static quantities related to the rhizosphere call UpdateSizeDepRhizVolLenCon(sites(s), bc_in(s)) @@ -654,9 +663,6 @@ subroutine InitPlantHydStates(site, cohort) cohort_hydr%btran = wkf_plant(stomata_p_media,ft)%p%ftc_from_psi(cohort_hydr%psi_ag(1)) - - !flc_gs_from_psi(cohort_hydr%psi_ag(1),cohort%pft) - ! We do allow for positive pressures. ! But starting off with positive pressures is something we try to avoid if ( (cohort_hydr%psi_troot>0.0_r8) .or. & @@ -702,6 +708,8 @@ subroutine UpdatePlantPsiFTCFromTheta(ccohort,csite_hydr) ccohort_hydr%ftc_ag(k) = wkf_plant(leaf_p_media,ft)%p%ftc_from_psi(ccohort_hydr%psi_ag(k)) end do + ccohort_hydr%btran = wkf_plant(stomata_p_media,ft)%p%ftc_from_psi(ccohort_hydr%psi_ag(1)) + do k = n_hypool_leaf+1, n_hypool_ag ccohort_hydr%psi_ag(k) = wrf_plant(stem_p_media,ft)%p%psi_from_th(ccohort_hydr%th_ag(k)) ccohort_hydr%ftc_ag(k) = wkf_plant(stem_p_media,ft)%p%ftc_from_psi(ccohort_hydr%psi_ag(k)) @@ -937,6 +945,7 @@ subroutine UpdatePlantHydrLenVol(ccohort,csite_hydr) real(r8), parameter :: min_trim = 0.1_r8 ! The lower cap on trimming function used ! to estimate maximum leaf carbon + ccohort_hydr => ccohort%co_hydr ft = ccohort%pft nlevrhiz = csite_hydr%nlevrhiz @@ -980,13 +989,13 @@ subroutine UpdatePlantHydrLenVol(ccohort,csite_hydr) ! Get the target, or rather, maximum leaf carrying capacity of plant ! Lets also avoid super-low targets that have very low trimming functions + ! efleaf_coh hard-coded to 1 in the call below to avoid zero leaf volume call bleaf(ccohort%dbh,ccohort%pft,ccohort%crowndamage, & - max(ccohort%canopy_trim,min_trim),ccohort%efleaf_coh, leaf_c_target) + max(ccohort%canopy_trim,min_trim),1.0_r8, leaf_c_target) + + ccohort_hydr%v_ag(1:n_hypool_leaf) = max(leaf_c,min_leaf_frac*leaf_c_target) * & + prt_params%c2b(ft) / denleaf/ real(n_hypool_leaf,r8) - if( (ccohort%status_coh == leaves_on) .or. ccohort_hydr%is_newly_recruited ) then - ccohort_hydr%v_ag(1:n_hypool_leaf) = max(leaf_c,min_leaf_frac*leaf_c_target) * & - prt_params%c2b(ft) / denleaf/ real(n_hypool_leaf,r8) - end if ! Step sapwood volume ! ----------------------------------------------------------------------------------- @@ -1655,6 +1664,15 @@ subroutine HydrSiteColdStart(sites, bc_in ) write(fates_log(),*) 'TFS conductance not used in soil' call endrun(msg=errMsg(sourcefile, __LINE__)) end select + + ! The fraction of total conductance functions need to know psi_min + ! to handle very very low conductances, therefore we need to construct + ! a pointer in conductance structure to the water retention structure + + do j=1,sites(s)%si_hydr%nlevrhiz + sites(s)%si_hydr%wkf_soil(j)%p%wrf => sites(s)%si_hydr%wrf_soil(j)%p + end do + end do @@ -1719,7 +1737,7 @@ subroutine UpdateH2OVeg(csite,bc_out,prev_site_h2o,icall) if( hlm_use_planthydro.eq.ifalse ) return csite_hydr => csite%si_hydr - csite_hydr%h2oveg = 0.0_r8 + csite_hydr%h2oveg = 0.0_r8 currentPatch => csite%oldest_patch do while(associated(currentPatch)) currentCohort=>currentPatch%tallest @@ -1739,13 +1757,14 @@ subroutine UpdateH2OVeg(csite,bc_out,prev_site_h2o,icall) currentPatch => currentPatch%younger enddo !end patch loop + ! convert from kg/site to kg/m2 csite_hydr%h2oveg = csite_hydr%h2oveg*AREA_INV ! Note that h2oveg_dead is incremented wherever we have litter fluxes ! and it will be reduced via an evaporation term - ! growturn_err is a term to accomodate error in growth or - ! turnover. need to be improved for future(CX) - bc_out%plant_stored_h2o_si = csite_hydr%h2oveg + csite_hydr%h2oveg_dead - & + ! growturn_err is a term to accomodate error in growth or + ! turnover. need to be improved for future(CX) + bc_out%plant_stored_h2o_si = csite_hydr%h2oveg + csite_hydr%h2oveg_dead - & csite_hydr%h2oveg_growturn_err - & csite_hydr%h2oveg_hydro_err @@ -2438,8 +2457,15 @@ subroutine hydraulics_bc ( nsites, sites, bc_in, bc_out, dtime) csite_hydr => sites(s)%si_hydr + bc_out(s)%qflx_soil2root_sisl(:) = 0._r8 + csite_hydr%sapflow_scpf(:,:) = 0._r8 + csite_hydr%rootuptake_sl(:) = 0._r8 + csite_hydr%rootuptake0_scpf(:,:) = 0._r8 + csite_hydr%rootuptake10_scpf(:,:) = 0._r8 + csite_hydr%rootuptake50_scpf(:,:) = 0._r8 + csite_hydr%rootuptake100_scpf(:,:) = 0._r8 + if( sum(csite_hydr%l_aroot_layer) == 0._r8 ) then - bc_out(s)%qflx_soil2root_sisl(:) = 0._r8 cycle end if @@ -2459,14 +2485,6 @@ subroutine hydraulics_bc ( nsites, sites, bc_in, bc_out, dtime) bc_out(s)%qflx_ro_sisl(:) = 0._r8 - ! Zero out diagnotsics that rely on accumulation - csite_hydr%sapflow_scpf(:,:) = 0._r8 - csite_hydr%rootuptake_sl(:) = 0._r8 - csite_hydr%rootuptake0_scpf(:,:) = 0._r8 - csite_hydr%rootuptake10_scpf(:,:) = 0._r8 - csite_hydr%rootuptake50_scpf(:,:) = 0._r8 - csite_hydr%rootuptake100_scpf(:,:) = 0._r8 - ! Initialize water mass balancing terms [kg h2o / m2] ! -------------------------------------------------------------------------------- transp_flux = 0._r8 @@ -2481,6 +2499,7 @@ subroutine hydraulics_bc ( nsites, sites, bc_in, bc_out, dtime) ifp = 0 cpatch => sites(s)%oldest_patch do while (associated(cpatch)) + if(cpatch%nocomp_pft_label.ne.nocomp_bareground)then ifp = ifp + 1 @@ -2512,7 +2531,7 @@ subroutine hydraulics_bc ( nsites, sites, bc_in, bc_out, dtime) end if ccohort=>cpatch%tallest - do while(associated(ccohort)) + co_loop1: do while(associated(ccohort)) ccohort_hydr => ccohort%co_hydr ft = ccohort%pft @@ -2650,9 +2669,8 @@ subroutine hydraulics_bc ( nsites, sites, bc_in, bc_out, dtime) ccohort_hydr%btran = wkf_plant(stomata_p_media,ft)%p%ftc_from_psi(ccohort_hydr%psi_ag(1)) - ccohort => ccohort%shorter - enddo !cohort + enddo co_loop1 !cohort endif ! not bareground patch cpatch => cpatch%younger enddo !patch @@ -2743,9 +2761,9 @@ subroutine hydraulics_bc ( nsites, sites, bc_in, bc_out, dtime) sumweight = 0._r8 do j_bc = j_t,j_b if(rootflux_disagg == soilk_disagg)then - ! Weight disaggregation by K*dz, but only for flux - ! into the root, othersize weight by depth - if(qflx_soil2root_rhiz>0._r8)then + if(qflx_soil2root_rhiz>0._r8 )then + ! Weight disaggregation by K*dz, but only for flux + ! into the root, othersize weight by root length ! h2osoi_liqvol: [kg/m2] / [m] / [kg/m3] = [m3/m3] eff_por = bc_in(s)%eff_porosity_sl(j_bc) h2osoi_liqvol = min(eff_por, bc_in(s)%h2o_liq_sisl(j_bc)/(bc_in(s)%dz_sisl(j_bc)*denh2o)) @@ -2766,6 +2784,20 @@ subroutine hydraulics_bc ( nsites, sites, bc_in, bc_out, dtime) end do ! Second pass, apply normalized weighting factors for fluxes + + ! Note: It is possible that the soil is so dry there is no conductance + ! In these cases, solver error may create some non-zero, yet + ! trivially small fluxes. Lets create a simple weighting + ! function based on root length. + if(sumweight < nearzero)then + sumweight = 0._r8 + do j_bc = j_t,j_b + weight_sl(j_bc) = csite_hydr%rootl_sl(j_bc) + sumweight = sumweight + weight_sl(j_bc) + end do + end if + + do j_bc = j_t,j_b ! Fill the output array to the HLM @@ -2798,13 +2830,21 @@ subroutine hydraulics_bc ( nsites, sites, bc_in, bc_out, dtime) delta_soil_storage = sum(csite_hydr%h2osoi_liqvol_shell(:,:) * & csite_hydr%v_shell(:,:)) * denh2o * AREA_INV - prev_h2osoil - if(abs(delta_plant_storage - (root_flux - transp_flux)) > error_thresh ) then + ! This is to check closure and include the known error + ! The error is essentially the overestimate transpiration + ! versus change in state (q_top_eff*dt_substep) - (w_tot_beg-w_tot_end) + ! That is why we remove the error from the transpiration in this check + if(abs(delta_plant_storage - (root_flux + csite_hydr%errh2o_hyd - transp_flux)) > error_thresh ) then write(fates_log(),*) 'Site plant water balance does not close' + write(fates_log(),*) 'Allowable, actual error (kg/m2): ',error_thresh, & + abs(delta_plant_storage - (root_flux + csite_hydr%dwat_veg - transp_flux)) write(fates_log(),*) 'delta plant storage: ',delta_plant_storage,' [kg/m2]' write(fates_log(),*) 'integrated root flux: ',root_flux,' [kg/m2]' write(fates_log(),*) 'transpiration flux: ',transp_flux,' [kg/m2]' write(fates_log(),*) 'end storage: ',csite_hydr%h2oveg write(fates_log(),*) 'pre_h2oveg', prev_h2oveg + write(fates_log(),*) 'csite_hydr%errh2o_hyd:',csite_hydr%errh2o_hyd + write(fates_log(),*) 'csite_hydr%dwat_veg:',csite_hydr%dwat_veg call endrun(msg=errMsg(sourcefile, __LINE__)) end if @@ -3110,7 +3150,7 @@ subroutine OrderLayersForSolve1D(csite_hydr,cohort,cohort_hydr,ordered, kbg_laye integer :: tmp ! temporarily holds a soil layer index integer :: ft ! functional type index of plant integer :: j,jj,k ! layer and shell indices - + real(r8), parameter :: neglibible_cond = 1.e-10_r8 kbg_tot = 0._r8 kbg_layer(:) = 0._r8 @@ -3146,7 +3186,9 @@ subroutine OrderLayersForSolve1D(csite_hydr,cohort,cohort_hydr,ordered, kbg_laye ! Calculate total effective conductance over path [kg s-1 MPa-1] ! from absorbing root node to 1st rhizosphere shell - r_bg = 1._r8/(kmax_aroot*ftc_aroot) + ! (since this is just about ordering, its ok to create a pseudo resistance + ! for nodes with zero conductance..) + r_bg = 1._r8/(kmax_aroot*max(ftc_aroot,neglibible_cond)) ! Path is across the upper an lower rhizosphere comparment ! on each side of the nodes. Since there is no flow across the outer @@ -3162,8 +3204,8 @@ subroutine OrderLayersForSolve1D(csite_hydr,cohort,cohort_hydr,ordered, kbg_laye ftc_shell = csite_hydr%wkf_soil(j)%p%ftc_from_psi(psi_shell) - r_bg = r_bg + 1._r8/(kmax_up*ftc_shell) - if(knearzero .and. (ftc_dn*kmax_dn)>nearzero ) then + + ! Calculate total effective conductance over path [kg s-1 MPa-1] + k_eff = 1._r8/(1._r8/(ftc_up*kmax_up)+1._r8/(ftc_dn*kmax_dn)) + + ! "A" term, which operates on the downstream node (closer to atm) + a_term = k_eff**2.0_r8 * h_diff * kmax_dn**(-1.0_r8) * ftc_dn**(-2.0_r8) & + * dftc_dtheta_dn - k_eff * dpsi_dtheta_dn + + + ! "B" term, which operates on the upstream node (further from atm) + b_term = k_eff**2.0_r8 * h_diff * kmax_up**(-1.0_r8) * ftc_up**(-2.0_r8) & + * dftc_dtheta_up + k_eff * dpsi_dtheta_up + else - ! "B" term, which operates on the upstream node (further from atm) - b_term = k_eff**2.0_r8 * h_diff * kmax_up**(-1.0_r8) * ftc_up**(-2.0_r8) & - * dftc_dtheta_up + k_eff * dpsi_dtheta_up + k_eff = 0._r8 + a_term = 0._r8 + b_term = 0._r8 + + end if + ! Restore ftc ftc_dn = ftc_dn_tmp ftc_up = ftc_up_tmp @@ -5976,7 +6032,6 @@ subroutine PicardSolve2D(csite_hydr,cohort,cohort_hydr, & if(abs(wb_error) < max_allowed_residual .or. maxval(abs(residual(:))) < 1.e-3_r8 .or. maxval(abs(th_node(:) - th_prev(:))) < 1.e-3) exit picardloop if(icnv == 1 ) then - print *,'dtime-',dtime,tm exit picardloop !explicit integration with small time step end if @@ -6217,6 +6272,7 @@ subroutine InitHydroGlobals() integer :: ft ! PFT index integer :: pm ! plant media index + integer :: node_type integer :: inode ! compartment node index real(r8) :: cap_corr ! correction for nonzero psi0x (TFS) real(r8) :: cap_slp ! slope of capillary region of curve @@ -6234,6 +6290,7 @@ subroutine InitHydroGlobals() ! ----------------------------------------------------------------------------------- do pm = 1, n_plant_media + select case(hydr_htftype_node(pm)) case(van_genuchten_type) do ft = 1,numpft @@ -6302,6 +6359,14 @@ subroutine InitHydroGlobals() write(fates_log(),*) 'undefined water conductance type for plants, pm:',pm,'type: ',hydr_htftype_node(pm) call endrun(msg=errMsg(sourcefile, __LINE__)) end select + + ! The fraction of total conductance functions need to know psi_min + ! to handle very very low conductances, therefore we need to construct + ! a pointer in conductance structure to the water retention structure + do ft = 1,numpft + wkf_plant(pm,ft)%p%wrf => wrf_plant(pm,ft)%p + end do + end do ! There is only 1 stomata conductance hypothesis which uses the p50 and @@ -6315,6 +6380,15 @@ subroutine InitHydroGlobals() EDPftvarcon_inst%hydr_avuln_gs(ft)]) end do + ! The fraction of total conductance functions need to know psi_min + ! to handle very very low conductances, therefore we need to construct + ! a pointer in conductance structure to the water retention structure + ! (for stomatal conductance, point to the internal leaf retention structure) + do ft = 1,numpft + wkf_plant(stomata_p_media,ft)%p%wrf => wrf_plant(1,ft)%p + end do + + return end subroutine InitHydroGlobals diff --git a/biogeophys/FatesPlantRespPhotosynthMod.F90 b/biogeophys/FatesPlantRespPhotosynthMod.F90 index 50bb0464bf..4f3df22449 100644 --- a/biogeophys/FatesPlantRespPhotosynthMod.F90 +++ b/biogeophys/FatesPlantRespPhotosynthMod.F90 @@ -38,6 +38,7 @@ module FATESPlantRespPhotosynthMod use FatesInterfaceTypesMod, only : hlm_parteh_mode use FatesInterfaceTypesMod, only : numpft use FatesInterfaceTypesMod, only : nleafage + use FatesUtilsMod, only : QuadraticRoots => QuadraticRootsSridharachary use EDParamsMod, only : maxpft use EDParamsMod, only : nlevleaf use EDParamsMod, only : nclmax @@ -62,11 +63,18 @@ module FATESPlantRespPhotosynthMod use EDParamsMod, only : maintresp_nonleaf_baserate use EDParamsMod, only : stomatal_model use EDParamsMod, only : stomatal_assim_model + use EDParamsMod, only : dayl_switch use EDParamsMod, only : photo_tempsens_model use PRTParametersMod, only : prt_params use EDPftvarcon , only : EDPftvarcon_inst use TemperatureType, only : temperature_type - + use FatesRadiationMemMod, only : norman_solver,twostr_solver + use EDParamsMod, only : radiation_model + use FatesRadiationMemMod, only : ipar + use FatesTwoStreamUtilsMod, only : FatesGetCohortAbsRad + use FatesAllometryMod , only : VegAreaLayer + use FatesAllometryMod, only : decay_coeff_vcmax + ! CIME Globals use shr_log_mod , only : errMsg => shr_log_errMsg @@ -78,9 +86,9 @@ module FATESPlantRespPhotosynthMod character(len=*), parameter, private :: sourcefile = & __FILE__ - + character(len=1024) :: warn_msg ! for defining a warning message - + !------------------------------------------------------------------------------------- ! maximum stomatal resistance [s/m] (used across several procedures) @@ -103,14 +111,15 @@ module FATESPlantRespPhotosynthMod ! Constants used to define conductance models integer, parameter :: medlyn_model = 2 integer, parameter :: ballberry_model = 1 - + ! Alternatively, Gross Assimilation can be used to estimate ! leaf co2 partial pressure and therefore conductance. The default ! is to use anet integer, parameter :: net_assim_model = 1 integer, parameter :: gross_assim_model = 2 - - + + logical, parameter :: preserve_b4b = .true. + contains !-------------------------------------------------------------------------------------- @@ -139,12 +148,12 @@ subroutine FatesPlantRespPhotosynthDrive (nsites, sites,bc_in,bc_out,dtime) use FatesAllometryMod, only : bleaf, bstore_allom use FatesAllometryMod, only : storage_fraction_of_target use FatesAllometryMod, only : set_root_fraction - use FatesAllometryMod, only : decay_coeff_kn + use DamageMainMod, only : GetCrownReduction use FatesInterfaceTypesMod, only : hlm_use_tree_damage - + ! ARGUMENTS: ! ----------------------------------------------------------------------------------- integer,intent(in) :: nsites @@ -210,7 +219,7 @@ subroutine FatesPlantRespPhotosynthDrive (nsites, sites,bc_in,bc_out,dtime) real(r8) :: tcsoi ! Temperature response function for root respiration. real(r8) :: tcwood ! Temperature response function for wood - real(r8) :: elai ! exposed LAI (patch scale) + real(r8) :: patch_la ! exposed leaf area (patch scale) real(r8) :: live_stem_n ! Live stem (above-ground sapwood) ! nitrogen content (kgN/plant) real(r8) :: live_croot_n ! Live coarse root (below-ground sapwood) @@ -232,15 +241,14 @@ subroutine FatesPlantRespPhotosynthDrive (nsites, sites,bc_in,bc_out,dtime) real(r8) :: maintresp_reduction_factor ! factor by which to reduce maintenance - ! respiration when storage pools are low + ! respiration when storage pools are low real(r8) :: b_leaf ! leaf biomass kgC real(r8) :: frac ! storage pool as a fraction of target leaf biomass - real(r8) :: check_elai ! This is a check on the effective LAI that is calculated ! over each cohort x layer. real(r8) :: cohort_eleaf_area ! This is the effective leaf area [m2] reported by each cohort real(r8) :: lnc_top ! Leaf nitrogen content per unit area at canopy top [gN/m2] real(r8) :: lmr25top ! canopy top leaf maint resp rate at 25C - ! for this plant or pft (umol CO2/m**2/s) + ! for this plant or pft (umol CO2/m**2/s) real(r8) :: leaf_inc ! LAI-only portion of the vegetation increment of dinc_vai real(r8) :: lai_canopy_above ! the LAI in the canopy layers above the layer of interest real(r8) :: lai_layers_above ! the LAI in the leaf layers, within the current canopy, @@ -264,7 +272,20 @@ subroutine FatesPlantRespPhotosynthDrive (nsites, sites,bc_in,bc_out,dtime) real(r8) :: sapw_n_bgw ! nitrogen in belowground portion of sapwood real(r8) :: sapw_n_agw ! nitrogen in aboveground portion of sapwood real(r8) :: sapw_n_undamaged ! nitrogen in sapwood of undamaged tree - + real(r8) :: rd_abs_leaf, rb_abs_leaf, r_abs_stem, r_abs_snow, rb_abs, rd_abs + real(r8) :: fsun + real(r8) :: par_per_sunla, par_per_shala ! PAR per sunlit and shaded leaf area [W/m2 leaf] + real(r8),dimension(75) :: cohort_vaitop + real(r8),dimension(75) :: cohort_vaibot + real(r8),dimension(75) :: cohort_layer_elai + real(r8),dimension(75) :: cohort_layer_esai + real(r8),dimension(75) :: cohort_layer_tlai + real(r8),dimension(75) :: cohort_layer_tsai + real(r8) :: cohort_elai + real(r8) :: cohort_esai + real(r8) :: laisun,laisha + real(r8) :: canopy_area + real(r8) :: elai ! ----------------------------------------------------------------------------------- ! Keeping these two definitions in case they need to be added later ! @@ -288,8 +309,8 @@ subroutine FatesPlantRespPhotosynthDrive (nsites, sites,bc_in,bc_out,dtime) ! Photosynthesis and stomatal conductance parameters, from: ! Bonan et al (2011) JGR, 116, doi:10.1029/2010JG001593 ! ----------------------------------------------------------------------------------- - - + + associate( & c3psn => EDPftvarcon_inst%c3psn , & @@ -299,725 +320,855 @@ subroutine FatesPlantRespPhotosynthDrive (nsites, sites,bc_in,bc_out,dtime) stomatal_intercept => EDPftvarcon_inst%stomatal_intercept ) !Unstressed minimum stomatal conductance - do s = 1,nsites + do s = 1,nsites + + ! Multi-layer parameters scaled by leaf nitrogen profile. + ! Loop through each canopy layer to calculate nitrogen profile using + ! cumulative lai at the midpoint of the layer + + + + ! Pre-process some variables that are PFT dependent + ! but not environmentally dependent + ! ------------------------------------------------------------------------ + + allocate(rootfr_ft(numpft, bc_in(s)%nlevsoil)) + + do ft = 1,numpft + call set_root_fraction(rootfr_ft(ft,:), ft, & + bc_in(s)%zi_sisl, & + bc_in(s)%max_rooting_depth_index_col) + end do + + + ifp = 0 + currentpatch => sites(s)%oldest_patch + do while (associated(currentpatch)) + if_notbare: if(currentpatch%nocomp_pft_label.ne.nocomp_bareground)then + ifp = ifp+1 + NCL_p = currentPatch%NCL_p + + ! Part I. Zero output boundary conditions + ! --------------------------------------------------------------------------- + bc_out(s)%rssun_pa(ifp) = 0._r8 + bc_out(s)%rssha_pa(ifp) = 0._r8 + + g_sb_leaves = 0._r8 + patch_la = 0._r8 + + ! Part II. Filter out patches + ! Patch level filter flag for photosynthesis calculations + ! has a short memory, flags: + ! 1 = patch has not been called + ! 2 = patch is currently marked for photosynthesis + ! 3 = patch has been called for photosynthesis already + ! --------------------------------------------------------------------------- + if_filter2: if(bc_in(s)%filter_photo_pa(ifp)==2)then + + + ! Part III. Calculate the number of sublayers for each pft and layer. + ! And then identify which layer/pft combinations have things in them. + ! Output: + ! currentPatch%ncan(:,:) + ! currentPatch%canopy_mask(:,:) + call UpdateCanopyNCanNRadPresent(currentPatch) + + + ! Part IV. Identify some environmentally derived parameters: + ! These quantities are biologically irrelevant + ! Michaelis-Menten constant for CO2 (Pa) + ! Michaelis-Menten constant for O2 (Pa) + ! CO2 compensation point (Pa) + ! leaf boundary layer conductance of h20 + ! constrained vapor pressure + + call GetCanopyGasParameters(bc_in(s)%forc_pbot, & ! in + bc_in(s)%oair_pa(ifp), & ! in + bc_in(s)%t_veg_pa(ifp), & ! in + bc_in(s)%tgcm_pa(ifp), & ! in + bc_in(s)%eair_pa(ifp), & ! in + bc_in(s)%esat_tv_pa(ifp), & ! in + bc_in(s)%rb_pa(ifp), & ! in + mm_kco2, & ! out + mm_ko2, & ! out + co2_cpoint, & ! out + cf, & ! out + gb_mol, & ! out + ceair) ! out + + ! ------------------------------------------------------------------------ + ! Part VI: Loop over all leaf layers. + ! The concept of leaf layers is a result of the radiative transfer scheme. + ! A leaf layer has uniform radiation environment. Leaf layers are a group + ! of vegetation surfaces (stems and leaves) which inhabit the same + ! canopy-layer "CL", have the same functional type "ft" and within those + ! two partitions are further partitioned into vertical layers where + ! downwelling radiation attenuates in order. + ! In this phase we loop over the leaf layers and calculate the + ! photosynthesis and respiration of the layer (since all biophysical + ! properties are homogeneous). After this step, we can loop through + ! our cohort list, associate each cohort with its list of leaf-layers + ! and transfer these quantities to the cohort. + ! With plant hydraulics, we must realize that photosynthesis and + ! respiration will be different for leaves of each cohort in the leaf + ! layers, as they will have there own hydraulic limitations. + ! NOTE: Only need to flush mask on the number of used pfts, not the whole + ! scratch space. + ! ------------------------------------------------------------------------ + rate_mask_z(:,1:numpft,:) = .false. + + if_any_cohorts: if(currentPatch%countcohorts > 0.0)then + currentCohort => currentPatch%tallest + do_cohort_drive: do while (associated(currentCohort)) ! Cohort loop + + ! Identify the canopy layer (cl), functional type (ft) + ! and the leaf layer (IV) for this cohort + ft = currentCohort%pft + cl = currentCohort%canopy_layer + + ! Calculate the cohort specific elai profile + ! And the top and bottom edges of the veg area index + ! of each layer bin are. Note, if the layers + ! sink below the ground snow line, then the effective + ! LAI and SAI start to shrink to zero, as well as + ! the difference between vaitop and vaibot. + if(currentCohort%treesai>0._r8)then + do iv = 1,currentCohort%nv + call VegAreaLayer(currentCohort%treelai, & + currentCohort%treesai, & + currentCohort%height, & + iv, & + currentCohort%nv, & + currentCohort%pft, & + sites(s)%snow_depth, & + cohort_vaitop(iv), & + cohort_vaibot(iv), & + cohort_layer_elai(iv), & + cohort_layer_esai(iv)) + end do + + cohort_elai = sum(cohort_layer_elai(1:currentCohort%nv)) + cohort_esai = sum(cohort_layer_esai(1:currentCohort%nv)) + + + else + cohort_layer_elai(:) = 0._r8 + cohort_layer_esai(:) = 0._r8 + cohort_vaitop(:) = 0._r8 + cohort_vaibot(:) = 0._r8 + cohort_elai = 0._r8 + cohort_esai = 0._r8 + end if + + ! MLO. Assuming target to be related to leaf biomass when leaves are fully + ! flushed. But unsure whether this call is correct or not, shouldn't we get + ! the target value directly from the bstore_allom? + call bleaf(currentCohort%dbh,currentCohort%pft,& + currentCohort%crowndamage,currentCohort%canopy_trim,1.0_r8,store_c_target) + ! call bstore_allom(currentCohort%dbh,currentCohort%pft, & + ! currentCohort%canopy_trim,store_c_target) + + call storage_fraction_of_target(store_c_target, & + currentCohort%prt%GetState(store_organ, carbon12_element), & + frac) + call lowstorage_maintresp_reduction(frac,currentCohort%pft, & + maintresp_reduction_factor) + + ! are there any leaves of this pft in this layer? + canopy_mask_if: if(currentPatch%canopy_mask(cl,ft) == 1)then + + ! Loop over leaf-layers + leaf_layer_loop : do iv = 1,currentCohort%nv + + ! ------------------------------------------------------------ + ! If we are doing plant hydro-dynamics (or any run-type + ! where cohorts may generate different photosynthetic rates + ! of other cohorts in the same canopy-pft-layer combo), + ! we re-calculate the leaf biophysical rates for the + ! cohort-layer combo of interest. + ! but in the vanilla case, we only re-calculate if it has + ! not been done yet. + ! Other cases where we need to solve for every cohort + ! in every leaf layer: nutrient dynamic mode, multiple leaf + ! age classes + ! ------------------------------------------------------------ + + rate_mask_if: if ( .not.rate_mask_z(iv,ft,cl) .or. & + (hlm_use_planthydro.eq.itrue) .or. & + (radiation_model .eq. twostr_solver ) .or. & + (nleafage > 1) .or. & + (hlm_parteh_mode .ne. prt_carbon_allom_hyp ) ) then + + if (hlm_use_planthydro.eq.itrue ) then + + stomatal_intercept_btran = max( cf/rsmax0,stomatal_intercept(ft)*currentCohort%co_hydr%btran ) + btran_eff = currentCohort%co_hydr%btran + + ! dinc_vai(:) is the total vegetation area index of each "leaf" layer + ! we convert to the leaf only portion of the increment + ! ------------------------------------------------------ + leaf_inc = dinc_vai(iv) * & + currentCohort%treelai/(currentCohort%treelai+currentCohort%treesai) + + ! Now calculate the cumulative top-down lai of the current layer's midpoint + lai_canopy_above = sum(currentPatch%canopy_layer_tlai(1:cl-1)) + + lai_layers_above = (dlower_vai(iv) - dinc_vai(iv)) * & + currentCohort%treelai/(currentCohort%treelai+currentCohort%treesai) + lai_current = min(leaf_inc, currentCohort%treelai - lai_layers_above) + cumulative_lai = lai_canopy_above + lai_layers_above + 0.5*lai_current + + leaf_psi = currentCohort%co_hydr%psi_ag(1) + + else + + stomatal_intercept_btran = max( cf/rsmax0,stomatal_intercept(ft)*currentPatch%btran_ft(ft) ) + + btran_eff = currentPatch%btran_ft(ft) + ! For consistency sake, we use total LAI here, and not exposed + ! if the plant is under-snow, it will be effectively dormant for + ! the purposes of nscaler + + cumulative_lai = sum(currentPatch%canopy_layer_tlai(1:cl-1)) + & + sum(currentPatch%tlai_profile(cl,ft,1:iv-1)) + & + 0.5*currentPatch%tlai_profile(cl,ft,iv) + + leaf_psi = fates_unset_r8 + + end if + + if(do_fates_salinity)then + btran_eff = btran_eff*currentPatch%bstress_sal_ft(ft) + endif + - ! Multi-layer parameters scaled by leaf nitrogen profile. - ! Loop through each canopy layer to calculate nitrogen profile using - ! cumulative lai at the midpoint of the layer + ! Bonan et al (2011) JGR, 116, doi:10.1029/2010JG001593 used + ! kn = 0.11. Here, derive kn from vcmax25 as in Lloyd et al + ! (2010) Biogeosciences, 7, 1833-1859 + kn = decay_coeff_vcmax(currentCohort%vcmax25top, & + prt_params%leafn_vert_scaler_coeff1(ft), & + prt_params%leafn_vert_scaler_coeff2(ft)) + ! Scale for leaf nitrogen profile + nscaler = exp(-kn * cumulative_lai) + + ! Leaf maintenance respiration to match the base rate used in CN + ! but with the new temperature functions for C3 and C4 plants. - ! Pre-process some variables that are PFT dependent - ! but not environmentally dependent - ! ------------------------------------------------------------------------ + ! CN respiration has units: g C / g N [leaf] / s. This needs to be + ! converted from g C / g N [leaf] / s to umol CO2 / m**2 [leaf] / s - allocate(rootfr_ft(numpft, bc_in(s)%nlevsoil)) + ! Then scale this value at the top of the canopy for canopy depth + ! Leaf nitrogen concentration at the top of the canopy (g N leaf / m**2 leaf) + select case(hlm_parteh_mode) + case (prt_carbon_allom_hyp) - do ft = 1,numpft - call set_root_fraction(rootfr_ft(ft,:), ft, & - bc_in(s)%zi_sisl, & - bc_in(s)%max_rooting_depth_index_col) - end do - - - ifp = 0 - currentpatch => sites(s)%oldest_patch - do while (associated(currentpatch)) - if(currentpatch%nocomp_pft_label.ne.nocomp_bareground)then - ifp = ifp+1 - NCL_p = currentPatch%NCL_p - - ! Part I. Zero output boundary conditions - ! --------------------------------------------------------------------------- - bc_out(s)%rssun_pa(ifp) = 0._r8 - bc_out(s)%rssha_pa(ifp) = 0._r8 - - g_sb_leaves = 0._r8 - check_elai = 0._r8 - - ! Part II. Filter out patches - ! Patch level filter flag for photosynthesis calculations - ! has a short memory, flags: - ! 1 = patch has not been called - ! 2 = patch is currently marked for photosynthesis - ! 3 = patch has been called for photosynthesis already - ! --------------------------------------------------------------------------- - if(bc_in(s)%filter_photo_pa(ifp)==2)then - - - ! Part III. Calculate the number of sublayers for each pft and layer. - ! And then identify which layer/pft combinations have things in them. - ! Output: - ! currentPatch%ncan(:,:) - ! currentPatch%canopy_mask(:,:) - call UpdateCanopyNCanNRadPresent(currentPatch) - - - ! Part IV. Identify some environmentally derived parameters: - ! These quantities are biologically irrelevant - ! Michaelis-Menten constant for CO2 (Pa) - ! Michaelis-Menten constant for O2 (Pa) - ! CO2 compensation point (Pa) - ! leaf boundary layer conductance of h20 - ! constrained vapor pressure - - call GetCanopyGasParameters(bc_in(s)%forc_pbot, & ! in - bc_in(s)%oair_pa(ifp), & ! in - bc_in(s)%t_veg_pa(ifp), & ! in - bc_in(s)%tgcm_pa(ifp), & ! in - bc_in(s)%eair_pa(ifp), & ! in - bc_in(s)%esat_tv_pa(ifp), & ! in - bc_in(s)%rb_pa(ifp), & ! in - mm_kco2, & ! out - mm_ko2, & ! out - co2_cpoint, & ! out - cf, & ! out - gb_mol, & ! out - ceair) ! out - - - - - ! ------------------------------------------------------------------------ - ! Part VI: Loop over all leaf layers. - ! The concept of leaf layers is a result of the radiative transfer scheme. - ! A leaf layer has uniform radiation environment. Leaf layers are a group - ! of vegetation surfaces (stems and leaves) which inhabit the same - ! canopy-layer "CL", have the same functional type "ft" and within those - ! two partitions are further partitioned into vertical layers where - ! downwelling radiation attenuates in order. - ! In this phase we loop over the leaf layers and calculate the - ! photosynthesis and respiration of the layer (since all biophysical - ! properties are homogeneous). After this step, we can loop through - ! our cohort list, associate each cohort with its list of leaf-layers - ! and transfer these quantities to the cohort. - ! With plant hydraulics, we must realize that photosynthesis and - ! respiration will be different for leaves of each cohort in the leaf - ! layers, as they will have there own hydraulic limitations. - ! NOTE: Only need to flush mask on the number of used pfts, not the whole - ! scratch space. - ! ------------------------------------------------------------------------ - rate_mask_z(:,1:numpft,:) = .false. - - if(currentPatch%countcohorts > 0.0)then ! Ignore empty patches - - currentCohort => currentPatch%tallest - do while (associated(currentCohort)) ! Cohort loop - - ! Identify the canopy layer (cl), functional type (ft) - ! and the leaf layer (IV) for this cohort - ft = currentCohort%pft - cl = currentCohort%canopy_layer - - ! MLO. Assuming target to be related to leaf biomass when leaves are fully - ! flushed. But unsure whether this call is correct or not, shouldn't we get - ! the target value directly from the bstore_allom? - call bleaf(currentCohort%dbh,currentCohort%pft,& - currentCohort%crowndamage,currentCohort%canopy_trim,1.0_r8,store_c_target) - ! call bstore_allom(currentCohort%dbh,currentCohort%pft, & - ! currentCohort%canopy_trim,store_c_target) - - call storage_fraction_of_target(store_c_target, & - currentCohort%prt%GetState(store_organ, carbon12_element), & - frac) - call lowstorage_maintresp_reduction(frac,currentCohort%pft, & - maintresp_reduction_factor) - - ! are there any leaves of this pft in this layer? - canopy_mask_if: if(currentPatch%canopy_mask(cl,ft) == 1)then - - ! Loop over leaf-layers - leaf_layer_loop : do iv = 1,currentCohort%nv - - ! ------------------------------------------------------------ - ! If we are doing plant hydro-dynamics (or any run-type - ! where cohorts may generate different photosynthetic rates - ! of other cohorts in the same canopy-pft-layer combo), - ! we re-calculate the leaf biophysical rates for the - ! cohort-layer combo of interest. - ! but in the vanilla case, we only re-calculate if it has - ! not been done yet. - ! Other cases where we need to solve for every cohort - ! in every leaf layer: nutrient dynamic mode, multiple leaf - ! age classes - ! ------------------------------------------------------------ - - rate_mask_if: if ( .not.rate_mask_z(iv,ft,cl) .or. & - (hlm_use_planthydro.eq.itrue) .or. & - (nleafage > 1) .or. & - (hlm_parteh_mode .ne. prt_carbon_allom_hyp ) ) then - - if (hlm_use_planthydro.eq.itrue ) then - - stomatal_intercept_btran = max( cf/rsmax0,stomatal_intercept(ft)*currentCohort%co_hydr%btran ) - btran_eff = currentCohort%co_hydr%btran - - ! dinc_vai(:) is the total vegetation area index of each "leaf" layer - ! we convert to the leaf only portion of the increment - ! ------------------------------------------------------ - leaf_inc = dinc_vai(iv) * & - currentCohort%treelai/(currentCohort%treelai+currentCohort%treesai) - - ! Now calculate the cumulative top-down lai of the current layer's midpoint - lai_canopy_above = sum(currentPatch%canopy_layer_tlai(1:cl-1)) - - lai_layers_above = (dlower_vai(iv) - dinc_vai(iv)) * & - currentCohort%treelai/(currentCohort%treelai+currentCohort%treesai) - lai_current = min(leaf_inc, currentCohort%treelai - lai_layers_above) - cumulative_lai = lai_canopy_above + lai_layers_above + 0.5*lai_current - - leaf_psi = currentCohort%co_hydr%psi_ag(1) - - else - - stomatal_intercept_btran = max( cf/rsmax0,stomatal_intercept(ft)*currentPatch%btran_ft(ft) ) - - btran_eff = currentPatch%btran_ft(ft) - ! For consistency sake, we use total LAI here, and not exposed - ! if the plant is under-snow, it will be effectively dormant for - ! the purposes of nscaler - - cumulative_lai = sum(currentPatch%canopy_layer_tlai(1:cl-1)) + & - sum(currentPatch%tlai_profile(cl,ft,1:iv-1)) + & - 0.5*currentPatch%tlai_profile(cl,ft,iv) - - leaf_psi = fates_unset_r8 - - end if - - if(do_fates_salinity)then - btran_eff = btran_eff*currentPatch%bstress_sal_ft(ft) - endif - - - ! Bonan et al (2011) JGR, 116, doi:10.1029/2010JG001593 used - ! kn = 0.11. Here, derive kn from vcmax25 as in Lloyd et al - ! (2010) Biogeosciences, 7, 1833-1859 - - kn = decay_coeff_kn(ft,currentCohort%vcmax25top) - - ! Scale for leaf nitrogen profile - nscaler = exp(-kn * cumulative_lai) + lnc_top = prt_params%nitr_stoich_p1(ft,prt_params%organ_param_id(leaf_organ))/slatop(ft) - ! Leaf maintenance respiration to match the base rate used in CN - ! but with the new temperature functions for C3 and C4 plants. - - ! CN respiration has units: g C / g N [leaf] / s. This needs to be - ! converted from g C / g N [leaf] / s to umol CO2 / m**2 [leaf] / s - - ! Then scale this value at the top of the canopy for canopy depth - ! Leaf nitrogen concentration at the top of the canopy (g N leaf / m**2 leaf) - select case(hlm_parteh_mode) - case (prt_carbon_allom_hyp) - - lnc_top = prt_params%nitr_stoich_p1(ft,prt_params%organ_param_id(leaf_organ))/slatop(ft) - - case (prt_cnp_flex_allom_hyp) + case (prt_cnp_flex_allom_hyp) + + leaf_c = currentCohort%prt%GetState(leaf_organ, carbon12_element) + if( (leaf_c*slatop(ft)) > nearzero) then + leaf_n = currentCohort%prt%GetState(leaf_organ, nitrogen_element) + lnc_top = leaf_n / (slatop(ft) * leaf_c ) + else + lnc_top = prt_params%nitr_stoich_p1(ft,prt_params%organ_param_id(leaf_organ))/slatop(ft) + end if + + ! If one wants to break coupling with dynamic N conentrations, + ! use the stoichiometry parameter + ! lnc_top = prt_params%nitr_stoich_p1(ft,prt_params%organ_param_id(leaf_organ))/slatop(ft) + + end select + + ! Part VII: Calculate dark respiration (leaf maintenance) for this layer + + select case (maintresp_leaf_model) + + case (lmrmodel_ryan_1991) + + call LeafLayerMaintenanceRespiration_Ryan_1991( lnc_top, & ! in + nscaler, & ! in + ft, & ! in + bc_in(s)%t_veg_pa(ifp), & ! in + lmr_z(iv,ft,cl)) ! out + + case (lmrmodel_atkin_etal_2017) + + call LeafLayerMaintenanceRespiration_Atkin_etal_2017(lnc_top, & ! in + cumulative_lai, & ! in + currentCohort%vcmax25top, & ! in + ft, & ! in + bc_in(s)%t_veg_pa(ifp), & ! in + currentPatch%tveg_lpa%GetMean(), & ! in + lmr_z(iv,ft,cl)) ! out + + case default + + write (fates_log(),*)'error, incorrect leaf respiration model specified' + call endrun(msg=errMsg(sourcefile, __LINE__)) + + end select + + ! Pre-process PAR absorbed per unit leaf area for different schemes + ! par_per_sunla = [W absorbed beam+diffuse radiation / m2 of sunlit leaves] + ! par_per_shala = [W absorbed diffuse radiation / m2 of shaded leaves] + ! fsun = [m2 of sunlit leaves / m2 of total leaves] + ! laisun: m2 of exposed leaf, per m2 of crown. If this is the lowest layer + ! for the pft/canopy group, than the m2 per crown is probably not + ! as large as the layer above. + ! ------------------------------------------------------------------ + + if_radsolver: if(radiation_model.eq.norman_solver) then + + laisun = currentPatch%ed_laisun_z(cl,ft,iv) + laisha = currentPatch%ed_laisha_z(cl,ft,iv) + par_per_sunla = currentPatch%ed_parsun_z(cl,ft,iv) + par_per_shala = currentPatch%ed_parsha_z(cl,ft,iv) + canopy_area = currentPatch%canopy_area_profile(cl,ft,iv) + fsun = currentPatch%f_sun(cl,ft,iv) + + else ! Two-stream + + if(cohort_layer_elai(iv) > nearzero .and. currentPatch%solar_zenith_flag) then + + call FatesGetCohortAbsRad(currentPatch, currentCohort, ipar, & + cohort_vaitop(iv), cohort_vaibot(iv), cohort_elai, cohort_esai, & + rb_abs, rd_abs, rb_abs_leaf, rd_abs_leaf, fsun) + + ! rd_abs_leaf: Watts of diffuse light absorbed by leaves over this + ! depth interval and ground footprint (m2) + ! rd_abs_leaf*fsun Watts of diffuse light absorbed by sunlit leaves + ! over this depth interval and ground footprint (m2) + ! rb_abs_leaf Watts of beam absorbed by sunlit leaves over this + ! depth interval and ground footprint (m2) + ! cohort_layer_elai*fsun Leaf area in sunlight within this interval and ground footprint + ! cohort_layer_elai*(1-fsun) Leaf area in shade within this interval and ground footprint + + laisun = (fsun*cohort_layer_elai(iv)) + laisha = ((1._r8 - fsun)*cohort_layer_elai(iv)) + if(fsun>nearzero) then + par_per_sunla = (rd_abs_leaf*fsun + rb_abs_leaf)! / laisun + else + par_per_sunla = 0._r8 + end if + par_per_shala = rd_abs_leaf*(1._r8-fsun) !/ laisha + canopy_area = 1._r8 !currentPatch%canopy_area_profile(cl,ft,iv) + + else + + par_per_sunla = 0._r8 + par_per_shala = 0._r8 + laisun = 0.5_r8*cohort_layer_elai(iv) + laisha = 0.5_r8*cohort_layer_elai(iv) + canopy_area = 1._r8 !currentPatch%canopy_area_profile(cl,ft,iv) + fsun = 0.5_r8 !avoid div0, should have no impact + + end if + + end if if_radsolver + + ! Part VII: Calculate (1) maximum rate of carboxylation (vcmax), + ! (2) maximum electron transport rate, (3) triose phosphate + ! utilization rate and (4) the initial slope of CO2 response curve + ! (C4 plants). Earlier we calculated their base rates as dictated + ! by their plant functional type and some simple scaling rules for + ! nitrogen limitation baesd on canopy position (not prognostic). + ! These rates are the specific rates used in the actual photosynthesis + ! calculations that take localized environmental effects (temperature) + ! into consideration. + + call LeafLayerBiophysicalRates(par_per_sunla, & ! in + ft, & ! in + currentCohort%vcmax25top, & ! in + currentCohort%jmax25top, & ! in + currentCohort%kp25top, & ! in + nscaler, & ! in + bc_in(s)%t_veg_pa(ifp), & ! in + bc_in(s)%dayl_factor_pa(ifp), & ! in + currentPatch%tveg_lpa%GetMean(), & ! in + currentPatch%tveg_longterm%GetMean(),& ! in + btran_eff, & ! in + vcmax_z, & ! out + jmax_z, & ! out + kp_z ) ! out + + ! Part IX: This call calculates the actual photosynthesis for the + ! leaf layer, as well as the stomatal resistance and the net assimilated carbon. + + call LeafLayerPhotosynthesis(fsun, & ! in + par_per_sunla, & ! in + par_per_shala, & ! in + laisun, & ! in + laisha, & ! in + canopy_area, & ! in + ft, & ! in + vcmax_z, & ! in + jmax_z, & ! in + kp_z, & ! in + bc_in(s)%t_veg_pa(ifp), & ! in + bc_in(s)%esat_tv_pa(ifp), & ! in + bc_in(s)%forc_pbot, & ! in + bc_in(s)%cair_pa(ifp), & ! in + bc_in(s)%oair_pa(ifp), & ! in + btran_eff, & ! in + stomatal_intercept_btran, & ! in + cf, & ! in + gb_mol, & ! in + ceair, & ! in + mm_kco2, & ! in + mm_ko2, & ! in + co2_cpoint, & ! in + lmr_z(iv,ft,cl), & ! in + leaf_psi, & ! in + bc_in(s)%rb_pa(ifp), & ! in + currentPatch%psn_z(cl,ft,iv), & ! out + rs_z(iv,ft,cl), & ! out + anet_av_z(iv,ft,cl), & ! out + c13disc_z(cl,ft,iv)) ! out + + rate_mask_z(iv,ft,cl) = .true. + + end if rate_mask_if + end do leaf_layer_loop + + ! Zero cohort flux accumulators. + currentCohort%npp_tstep = 0.0_r8 + currentCohort%resp_tstep = 0.0_r8 + currentCohort%gpp_tstep = 0.0_r8 + currentCohort%rdark = 0.0_r8 + currentCohort%resp_m = 0.0_r8 + currentCohort%ts_net_uptake = 0.0_r8 + currentCohort%c13disc_clm = 0.0_r8 + + ! --------------------------------------------------------------- + ! Part VII: Transfer leaf flux rates (like maintenance respiration, + ! carbon assimilation and conductance) that are defined by the + ! leaf layer (which is area independent, ie /m2) onto each cohort + ! (where the rates become per cohort, ie /individual). Most likely + ! a sum over layers. + ! --------------------------------------------------------------- + nv = currentCohort%nv + + ! Temporary bypass to preserve B4B behavior + if(radiation_model.eq.norman_solver) then + + call ScaleLeafLayerFluxToCohort(nv, & !in + currentPatch%psn_z(cl,ft,1:nv), & !in + lmr_z(1:nv,ft,cl), & !in + rs_z(1:nv,ft,cl), & !in + currentPatch%elai_profile(cl,ft,1:nv), & !in + c13disc_z(cl, ft, 1:nv), & !in + currentCohort%c_area, & !in + currentCohort%n, & !in + bc_in(s)%rb_pa(ifp), & !in + maintresp_reduction_factor, & !in + currentCohort%g_sb_laweight, & !out + currentCohort%gpp_tstep, & !out + currentCohort%rdark, & !out + currentCohort%c13disc_clm, & !out + cohort_eleaf_area) !out + + else + + call ScaleLeafLayerFluxToCohort(nv, & !in + currentPatch%psn_z(cl,ft,1:nv), & !in + lmr_z(1:nv,ft,cl), & !in + rs_z(1:nv,ft,cl), & !in + cohort_layer_elai(1:nv), & !in + c13disc_z(cl, ft, 1:nv), & !in + currentCohort%c_area, & !in + currentCohort%n, & !in + bc_in(s)%rb_pa(ifp), & !in + maintresp_reduction_factor, & !in + currentCohort%g_sb_laweight, & !out + currentCohort%gpp_tstep, & !out + currentCohort%rdark, & !out + currentCohort%c13disc_clm, & !out + cohort_eleaf_area) !out + end if + + + ! Net Uptake does not need to be scaled, just transfer directly + currentCohort%ts_net_uptake(1:nv) = anet_av_z(1:nv,ft,cl) * umolC_to_kgC + + else + + ! In this case, the cohort had no leaves, + ! so no productivity,conductance, transpiration uptake + ! or dark respiration + cohort_eleaf_area = 0.0_r8 + currentCohort%gpp_tstep = 0.0_r8 + currentCohort%rdark = 0.0_r8 + currentCohort%g_sb_laweight = 0.0_r8 + currentCohort%ts_net_uptake(:) = 0.0_r8 + + end if canopy_mask_if + + + ! ------------------------------------------------------------------ + ! Part VIII: Calculate maintenance respiration in the sapwood and + ! fine root pools. + ! ------------------------------------------------------------------ + + ! Calculate the amount of nitrogen in the above and below ground + ! stem and root pools, used for maint resp + ! We are using the fine-root C:N ratio as an approximation for + ! the sapwood pools. + ! Units are in (kgN/plant) + ! ------------------------------------------------------------------ + + sapw_c = currentCohort%prt%GetState(sapw_organ, carbon12_element) + fnrt_c = currentCohort%prt%GetState(fnrt_organ, carbon12_element) + + if (hlm_use_tree_damage .eq. itrue) then - leaf_c = currentCohort%prt%GetState(leaf_organ, carbon12_element) - if( (leaf_c*slatop(ft)) > nearzero) then - leaf_n = currentCohort%prt%GetState(leaf_organ, nitrogen_element) - lnc_top = leaf_n / (slatop(ft) * leaf_c ) - else - lnc_top = prt_params%nitr_stoich_p1(ft,prt_params%organ_param_id(leaf_organ))/slatop(ft) - end if - - ! If one wants to break coupling with dynamic N conentrations, - ! use the stoichiometry parameter - ! lnc_top = prt_params%nitr_stoich_p1(ft,prt_params%organ_param_id(leaf_organ))/slatop(ft) - - end select - - ! Part VII: Calculate dark respiration (leaf maintenance) for this layer - - select case (maintresp_leaf_model) - - case (lmrmodel_ryan_1991) - - call LeafLayerMaintenanceRespiration_Ryan_1991( lnc_top, & ! in - nscaler, & ! in - ft, & ! in - bc_in(s)%t_veg_pa(ifp), & ! in - lmr_z(iv,ft,cl)) ! out - - case (lmrmodel_atkin_etal_2017) - - call LeafLayerMaintenanceRespiration_Atkin_etal_2017(lnc_top, & ! in - nscaler, & ! in - ft, & ! in - bc_in(s)%t_veg_pa(ifp), & ! in - currentPatch%tveg_lpa%GetMean(), & ! in - lmr_z(iv,ft,cl)) ! out - - case default - - write (fates_log(),*)'error, incorrect leaf respiration model specified' - call endrun(msg=errMsg(sourcefile, __LINE__)) - - end select - - ! Part VII: Calculate (1) maximum rate of carboxylation (vcmax), - ! (2) maximum electron transport rate, (3) triose phosphate - ! utilization rate and (4) the initial slope of CO2 response curve - ! (C4 plants). Earlier we calculated their base rates as dictated - ! by their plant functional type and some simple scaling rules for - ! nitrogen limitation baesd on canopy position (not prognostic). - ! These rates are the specific rates used in the actual photosynthesis - ! calculations that take localized environmental effects (temperature) - ! into consideration. - - - - call LeafLayerBiophysicalRates(currentPatch%ed_parsun_z(cl,ft,iv), & ! in - ft, & ! in - currentCohort%vcmax25top, & ! in - currentCohort%jmax25top, & ! in - currentCohort%kp25top, & ! in - nscaler, & ! in - bc_in(s)%t_veg_pa(ifp), & ! in - currentPatch%tveg_lpa%GetMean(), & ! in - currentPatch%tveg_longterm%GetMean(),& ! in - btran_eff, & ! in - vcmax_z, & ! out - jmax_z, & ! out - kp_z ) ! out - - ! Part IX: This call calculates the actual photosynthesis for the - ! leaf layer, as well as the stomatal resistance and the net assimilated carbon. - - call LeafLayerPhotosynthesis(currentPatch%f_sun(cl,ft,iv), & ! in - currentPatch%ed_parsun_z(cl,ft,iv), & ! in - currentPatch%ed_parsha_z(cl,ft,iv), & ! in - currentPatch%ed_laisun_z(cl,ft,iv), & ! in - currentPatch%ed_laisha_z(cl,ft,iv), & ! in - currentPatch%canopy_area_profile(cl,ft,iv), & ! in - ft, & ! in - vcmax_z, & ! in - jmax_z, & ! in - kp_z, & ! in - bc_in(s)%t_veg_pa(ifp), & ! in - bc_in(s)%esat_tv_pa(ifp), & ! in - bc_in(s)%forc_pbot, & ! in - bc_in(s)%cair_pa(ifp), & ! in - bc_in(s)%oair_pa(ifp), & ! in - btran_eff, & ! in - stomatal_intercept_btran, & ! in - cf, & ! in - gb_mol, & ! in - ceair, & ! in - mm_kco2, & ! in - mm_ko2, & ! in - co2_cpoint, & ! in - lmr_z(iv,ft,cl), & ! in - leaf_psi, & ! in - bc_in(s)%rb_pa(ifp), & ! in - currentPatch%psn_z(cl,ft,iv), & ! out - rs_z(iv,ft,cl), & ! out - anet_av_z(iv,ft,cl), & ! out - c13disc_z(cl,ft,iv)) ! out - - rate_mask_z(iv,ft,cl) = .true. - - end if rate_mask_if - end do leaf_layer_loop - - ! Zero cohort flux accumulators. - currentCohort%npp_tstep = 0.0_r8 - currentCohort%resp_tstep = 0.0_r8 - currentCohort%gpp_tstep = 0.0_r8 - currentCohort%rdark = 0.0_r8 - currentCohort%resp_m = 0.0_r8 - currentCohort%ts_net_uptake = 0.0_r8 - currentCohort%c13disc_clm = 0.0_r8 - - ! --------------------------------------------------------------- - ! Part VII: Transfer leaf flux rates (like maintenance respiration, - ! carbon assimilation and conductance) that are defined by the - ! leaf layer (which is area independent, ie /m2) onto each cohort - ! (where the rates become per cohort, ie /individual). Most likely - ! a sum over layers. - ! --------------------------------------------------------------- - nv = currentCohort%nv - call ScaleLeafLayerFluxToCohort(nv, & !in - currentPatch%psn_z(cl,ft,1:nv), & !in - lmr_z(1:nv,ft,cl), & !in - rs_z(1:nv,ft,cl), & !in - currentPatch%elai_profile(cl,ft,1:nv), & !in - c13disc_z(cl, ft, 1:nv), & !in - currentCohort%c_area, & !in - currentCohort%n, & !in - bc_in(s)%rb_pa(ifp), & !in - maintresp_reduction_factor, & !in - currentCohort%g_sb_laweight, & !out - currentCohort%gpp_tstep, & !out - currentCohort%rdark, & !out - currentCohort%c13disc_clm, & !out - cohort_eleaf_area) !out - - ! Net Uptake does not need to be scaled, just transfer directly - currentCohort%ts_net_uptake(1:nv) = anet_av_z(1:nv,ft,cl) * umolC_to_kgC - - else - - ! In this case, the cohort had no leaves, - ! so no productivity,conductance, transpiration uptake - ! or dark respiration - cohort_eleaf_area = 0.0_r8 - currentCohort%gpp_tstep = 0.0_r8 - currentCohort%rdark = 0.0_r8 - currentCohort%g_sb_laweight = 0.0_r8 - currentCohort%ts_net_uptake(:) = 0.0_r8 - - end if canopy_mask_if - - - ! ------------------------------------------------------------------ - ! Part VIII: Calculate maintenance respiration in the sapwood and - ! fine root pools. - ! ------------------------------------------------------------------ - - ! Calculate the amount of nitrogen in the above and below ground - ! stem and root pools, used for maint resp - ! We are using the fine-root C:N ratio as an approximation for - ! the sapwood pools. - ! Units are in (kgN/plant) - ! ------------------------------------------------------------------ - - sapw_c = currentCohort%prt%GetState(sapw_organ, carbon12_element) - fnrt_c = currentCohort%prt%GetState(fnrt_organ, carbon12_element) - - if (hlm_use_tree_damage .eq. itrue) then - - ! Crown damage currenly only reduces the aboveground portion of - ! sapwood. Therefore we calculate the aboveground and the belowground portion - ! sapwood for use in stem respiration. - call GetCrownReduction(currentCohort%crowndamage, crown_reduction) - - else - crown_reduction = 0.0_r8 - end if - - ! If crown reduction is zero, undamaged sapwood target will equal sapwood carbon - agb_frac = prt_params%allom_agb_frac(currentCohort%pft) - branch_frac = param_derived%branch_frac(currentCohort%pft) - sapw_c_undamaged = sapw_c / (1.0_r8 - (agb_frac * branch_frac * crown_reduction)) - - ! Undamaged below ground portion - sapw_c_bgw = sapw_c_undamaged * (1.0_r8 - agb_frac) - - ! Damaged aboveground portion - sapw_c_agw = sapw_c - sapw_c_bgw - - - select case(hlm_parteh_mode) - case (prt_carbon_allom_hyp) + ! Crown damage currenly only reduces the aboveground portion of + ! sapwood. Therefore we calculate the aboveground and the belowground portion + ! sapwood for use in stem respiration. + call GetCrownReduction(currentCohort%crowndamage, crown_reduction) - live_stem_n = sapw_c_agw * prt_params%nitr_stoich_p1(ft,prt_params%organ_param_id(sapw_organ)) + else + crown_reduction = 0.0_r8 + end if - live_croot_n = sapw_c_bgw * prt_params%nitr_stoich_p1(ft,prt_params%organ_param_id(sapw_organ)) + ! If crown reduction is zero, undamaged sapwood target will equal sapwood carbon + agb_frac = prt_params%allom_agb_frac(currentCohort%pft) + branch_frac = param_derived%branch_frac(currentCohort%pft) + sapw_c_undamaged = sapw_c / (1.0_r8 - (agb_frac * branch_frac * crown_reduction)) - fnrt_n = fnrt_c * prt_params%nitr_stoich_p1(ft,prt_params%organ_param_id(fnrt_organ)) + ! Undamaged below ground portion + sapw_c_bgw = sapw_c_undamaged * (1.0_r8 - agb_frac) - case(prt_cnp_flex_allom_hyp) + ! Damaged aboveground portion + sapw_c_agw = sapw_c - sapw_c_bgw - live_stem_n = prt_params%allom_agb_frac(currentCohort%pft) * & - currentCohort%prt%GetState(sapw_organ, nitrogen_element) - live_croot_n = (1.0_r8-prt_params%allom_agb_frac(currentCohort%pft)) * & - currentCohort%prt%GetState(sapw_organ, nitrogen_element) + select case(hlm_parteh_mode) + case (prt_carbon_allom_hyp) + live_stem_n = sapw_c_agw * prt_params%nitr_stoich_p1(ft,prt_params%organ_param_id(sapw_organ)) - fnrt_n = currentCohort%prt%GetState(fnrt_organ, nitrogen_element) + live_croot_n = sapw_c_bgw * prt_params%nitr_stoich_p1(ft,prt_params%organ_param_id(sapw_organ)) - if (hlm_use_tree_damage .eq. itrue) then + fnrt_n = fnrt_c * prt_params%nitr_stoich_p1(ft,prt_params%organ_param_id(fnrt_organ)) - sapw_n = currentCohort%prt%GetState(sapw_organ, nitrogen_element) + case(prt_cnp_flex_allom_hyp) - sapw_n_undamaged = sapw_n / & - (1.0_r8 - (agb_frac * branch_frac * crown_reduction)) - - sapw_n_bgw = sapw_n_undamaged * (1.0_r8 - agb_frac) - sapw_n_agw = sapw_n - sapw_n_bgw + live_stem_n = prt_params%allom_agb_frac(currentCohort%pft) * & + currentCohort%prt%GetState(sapw_organ, nitrogen_element) - live_croot_n = sapw_n_bgw + live_croot_n = (1.0_r8-prt_params%allom_agb_frac(currentCohort%pft)) * & + currentCohort%prt%GetState(sapw_organ, nitrogen_element) - live_stem_n = sapw_n_agw - end if + fnrt_n = currentCohort%prt%GetState(fnrt_organ, nitrogen_element) - ! If one wants to break coupling with dynamic N conentrations, - ! use the stoichiometry parameter - ! - ! live_stem_n = prt_params%allom_agb_frac(currentCohort%pft) * & - ! sapw_c * prt_params%nitr_stoich_p1(ft,prt_params%organ_param_id(sapw_organ)) - ! live_croot_n = (1.0_r8-prt_params%allom_agb_frac(currentCohort%pft)) * & - ! sapw_c * prt_params%nitr_stoich_p1(ft,prt_params%organ_param_id(sapw_organ)) - ! fnrt_n = fnrt_c * prt_params%nitr_stoich_p1(ft,prt_params%organ_param_id(fnrt_organ)) + if (hlm_use_tree_damage .eq. itrue) then + sapw_n = currentCohort%prt%GetState(sapw_organ, nitrogen_element) - case default + sapw_n_undamaged = sapw_n / & + (1.0_r8 - (agb_frac * branch_frac * crown_reduction)) + sapw_n_bgw = sapw_n_undamaged * (1.0_r8 - agb_frac) + sapw_n_agw = sapw_n - sapw_n_bgw - end select + live_croot_n = sapw_n_bgw - !------------------------------------------------------------------------------ - ! Calculate Whole Plant Respiration - ! (this doesn't really need to be in this iteration at all, surely?) - ! Response: (RGK 12-2016): I think the positioning of these calls is - ! appropriate as of now. Maintenance calculations in sapwood and roots - ! vary by cohort and with changing temperature at the minimum, and there are - ! no sub-pools chopping up those pools any finer that need to be dealt with. - !------------------------------------------------------------------------------ + live_stem_n = sapw_n_agw - ! Live stem MR (kgC/plant/s) (above ground sapwood) - ! ------------------------------------------------------------------ - if ( int(woody(ft)) == itrue) then - tcwood = q10_mr**((bc_in(s)%t_veg_pa(ifp)-tfrz - 20.0_r8)/10.0_r8) - ! kgC/s = kgN * kgC/kgN/s - currentCohort%livestem_mr = live_stem_n * maintresp_nonleaf_baserate * tcwood * maintresp_reduction_factor - else - currentCohort%livestem_mr = 0._r8 - end if + end if + ! If one wants to break coupling with dynamic N conentrations, + ! use the stoichiometry parameter + ! + ! live_stem_n = prt_params%allom_agb_frac(currentCohort%pft) * & + ! sapw_c * prt_params%nitr_stoich_p1(ft,prt_params%organ_param_id(sapw_organ)) + ! live_croot_n = (1.0_r8-prt_params%allom_agb_frac(currentCohort%pft)) * & + ! sapw_c * prt_params%nitr_stoich_p1(ft,prt_params%organ_param_id(sapw_organ)) + ! fnrt_n = fnrt_c * prt_params%nitr_stoich_p1(ft,prt_params%organ_param_id(fnrt_organ)) - ! Fine Root MR (kgC/plant/s) - ! and calculate the N fixation rate as a function of the fixation-specific root respiration - ! for now use dev_arbitrary_pft as scaling term between 0 and 1 as additional increment of root respiration used for N fixation - ! ------------------------------------------------------------------ - currentCohort%froot_mr = 0._r8 - currentCohort%sym_nfix_tstep = 0._r8 - - ! n_fixation is integrated over the course of the day - ! this variable is zeroed at the end of the FATES dynamics sequence - do j = 1,bc_in(s)%nlevsoil - tcsoi = q10_mr**((bc_in(s)%t_soisno_sl(j)-tfrz - 20.0_r8)/10.0_r8) - - fnrt_mr_layer = fnrt_n * maintresp_nonleaf_baserate * tcsoi * rootfr_ft(ft,j) * maintresp_reduction_factor + case default - ! calculate the cost of carbon for N fixation in each soil layer and calculate N fixation rate based on that [kgC / kgN] - call RootLayerNFixation(bc_in(s)%t_soisno_sl(j),ft,dtime,fnrt_mr_layer,fnrt_mr_nfix_layer,nfix_layer) - - currentCohort%froot_mr = currentCohort%froot_mr + fnrt_mr_nfix_layer + fnrt_mr_layer + end select - currentCohort%sym_nfix_tstep = currentCohort%sym_nfix_tstep + nfix_layer - - - enddo + !------------------------------------------------------------------------------ + ! Calculate Whole Plant Respiration + ! (this doesn't really need to be in this iteration at all, surely?) + ! Response: (RGK 12-2016): I think the positioning of these calls is + ! appropriate as of now. Maintenance calculations in sapwood and roots + ! vary by cohort and with changing temperature at the minimum, and there are + ! no sub-pools chopping up those pools any finer that need to be dealt with. + !------------------------------------------------------------------------------ - ! Coarse Root MR (kgC/plant/s) (below ground sapwood) - ! ------------------------------------------------------------------ - if ( int(woody(ft)) == itrue) then - currentCohort%livecroot_mr = 0._r8 - do j = 1,bc_in(s)%nlevsoil - ! Soil temperature used to adjust base rate of MR - tcsoi = q10_mr**((bc_in(s)%t_soisno_sl(j)-tfrz - 20.0_r8)/10.0_r8) - currentCohort%livecroot_mr = currentCohort%livecroot_mr + & - live_croot_n * maintresp_nonleaf_baserate * tcsoi * & - rootfr_ft(ft,j) * maintresp_reduction_factor - enddo - else - currentCohort%livecroot_mr = 0._r8 - end if + ! Live stem MR (kgC/plant/s) (above ground sapwood) + ! ------------------------------------------------------------------ + if ( int(woody(ft)) == itrue) then + tcwood = q10_mr**((bc_in(s)%t_veg_pa(ifp)-tfrz - 20.0_r8)/10.0_r8) + ! kgC/s = kgN * kgC/kgN/s + currentCohort%livestem_mr = live_stem_n * maintresp_nonleaf_baserate * tcwood * maintresp_reduction_factor + else + currentCohort%livestem_mr = 0._r8 + end if - ! ------------------------------------------------------------------ - ! Part IX: Perform some unit conversions (rate to integrated) and - ! calcualate some fluxes that are sums and nets of the base fluxes - ! ------------------------------------------------------------------ + ! Fine Root MR (kgC/plant/s) + ! and calculate the N fixation rate as a function of the fixation-specific root respiration + ! for now use dev_arbitrary_pft as scaling term between 0 and 1 as additional increment of root respiration used for N fixation + ! ------------------------------------------------------------------ + currentCohort%froot_mr = 0._r8 + currentCohort%sym_nfix_tstep = 0._r8 - if ( debug ) write(fates_log(),*) 'EDPhoto 904 ', currentCohort%resp_m - if ( debug ) write(fates_log(),*) 'EDPhoto 905 ', currentCohort%rdark - if ( debug ) write(fates_log(),*) 'EDPhoto 906 ', currentCohort%livestem_mr - if ( debug ) write(fates_log(),*) 'EDPhoto 907 ', currentCohort%livecroot_mr - if ( debug ) write(fates_log(),*) 'EDPhoto 908 ', currentCohort%froot_mr + ! n_fixation is integrated over the course of the day + ! this variable is zeroed at the end of the FATES dynamics sequence + do j = 1,bc_in(s)%nlevsoil + tcsoi = q10_mr**((bc_in(s)%t_soisno_sl(j)-tfrz - 20.0_r8)/10.0_r8) + fnrt_mr_layer = fnrt_n * maintresp_nonleaf_baserate * tcsoi * rootfr_ft(ft,j) * maintresp_reduction_factor - ! add on whole plant respiration values in kgC/indiv/s-1 - currentCohort%resp_m = currentCohort%livestem_mr + & - currentCohort%livecroot_mr + & - currentCohort%froot_mr + ! calculate the cost of carbon for N fixation in each soil layer and calculate N fixation rate based on that [kgC / kgN] - ! no drought response right now.. something like: - ! resp_m = resp_m * (1.0_r8 - currentPatch%btran_ft(currentCohort%pft) * & - ! EDPftvarcon_inst%resp_drought_response(ft)) + call RootLayerNFixation(bc_in(s)%t_soisno_sl(j),ft,dtime,fnrt_mr_layer,fnrt_mr_nfix_layer,nfix_layer) - currentCohort%resp_m = currentCohort%resp_m + currentCohort%rdark + currentCohort%froot_mr = currentCohort%froot_mr + fnrt_mr_nfix_layer + fnrt_mr_layer - ! save as a diagnostic the un-throttled maintenance respiration to be able to know how strong this is - currentCohort%resp_m_unreduced = currentCohort%resp_m / maintresp_reduction_factor + currentCohort%sym_nfix_tstep = currentCohort%sym_nfix_tstep + nfix_layer - ! convert from kgC/indiv/s to kgC/indiv/timestep - currentCohort%resp_m = currentCohort%resp_m * dtime - currentCohort%gpp_tstep = currentCohort%gpp_tstep * dtime - currentCohort%ts_net_uptake = currentCohort%ts_net_uptake * dtime - if ( debug ) write(fates_log(),*) 'EDPhoto 911 ', currentCohort%gpp_tstep - if ( debug ) write(fates_log(),*) 'EDPhoto 912 ', currentCohort%resp_tstep - if ( debug ) write(fates_log(),*) 'EDPhoto 913 ', currentCohort%resp_m + enddo + ! Coarse Root MR (kgC/plant/s) (below ground sapwood) + ! ------------------------------------------------------------------ + if ( int(woody(ft)) == itrue) then + currentCohort%livecroot_mr = 0._r8 + do j = 1,bc_in(s)%nlevsoil + ! Soil temperature used to adjust base rate of MR + tcsoi = q10_mr**((bc_in(s)%t_soisno_sl(j)-tfrz - 20.0_r8)/10.0_r8) + currentCohort%livecroot_mr = currentCohort%livecroot_mr + & + live_croot_n * maintresp_nonleaf_baserate * tcsoi * & + rootfr_ft(ft,j) * maintresp_reduction_factor + enddo + else + currentCohort%livecroot_mr = 0._r8 + end if - currentCohort%resp_g_tstep = prt_params%grperc(ft) * & - (max(0._r8,currentCohort%gpp_tstep - currentCohort%resp_m)) + ! ------------------------------------------------------------------ + ! Part IX: Perform some unit conversions (rate to integrated) and + ! calcualate some fluxes that are sums and nets of the base fluxes + ! ------------------------------------------------------------------ - currentCohort%resp_tstep = currentCohort%resp_m + & - currentCohort%resp_g_tstep ! kgC/indiv/ts - currentCohort%npp_tstep = currentCohort%gpp_tstep - & - currentCohort%resp_tstep ! kgC/indiv/ts + if ( debug ) write(fates_log(),*) 'EDPhoto 904 ', currentCohort%resp_m + if ( debug ) write(fates_log(),*) 'EDPhoto 905 ', currentCohort%rdark + if ( debug ) write(fates_log(),*) 'EDPhoto 906 ', currentCohort%livestem_mr + if ( debug ) write(fates_log(),*) 'EDPhoto 907 ', currentCohort%livecroot_mr + if ( debug ) write(fates_log(),*) 'EDPhoto 908 ', currentCohort%froot_mr - ! Accumulate the combined conductance (stomatal+leaf boundary layer) - ! Note that currentCohort%g_sb_laweight is weighted by the leaf area - ! of each cohort and has units of [m/s] * [m2 leaf] - g_sb_leaves = g_sb_leaves + currentCohort%g_sb_laweight - ! Accumulate the total effective leaf area from all cohorts - ! in this patch. Normalize by canopy area outside the loop - check_elai = check_elai + cohort_eleaf_area + ! add on whole plant respiration values in kgC/indiv/s-1 + currentCohort%resp_m = currentCohort%livestem_mr + & + currentCohort%livecroot_mr + & + currentCohort%froot_mr - currentCohort => currentCohort%shorter + ! no drought response right now.. something like: + ! resp_m = resp_m * (1.0_r8 - currentPatch%btran_ft(currentCohort%pft) * & + ! EDPftvarcon_inst%resp_drought_response(ft)) - enddo ! end cohort loop. - end if !count_cohorts is more than zero. + currentCohort%resp_m = currentCohort%resp_m + currentCohort%rdark + + ! save as a diagnostic the un-throttled maintenance respiration to be able to know how strong this is + currentCohort%resp_m_unreduced = currentCohort%resp_m / maintresp_reduction_factor - check_elai = check_elai / currentPatch%total_canopy_area - elai = calc_areaindex(currentPatch,'elai') + ! convert from kgC/indiv/s to kgC/indiv/timestep + currentCohort%resp_m = currentCohort%resp_m * dtime + currentCohort%gpp_tstep = currentCohort%gpp_tstep * dtime + currentCohort%ts_net_uptake = currentCohort%ts_net_uptake * dtime - ! Normalize canopy total conductance by the effective LAI - ! The value here was integrated over each cohort x leaf layer - ! and was weighted by m2 of effective leaf area for each layer + if ( debug ) write(fates_log(),*) 'EDPhoto 911 ', currentCohort%gpp_tstep + if ( debug ) write(fates_log(),*) 'EDPhoto 912 ', currentCohort%resp_tstep + if ( debug ) write(fates_log(),*) 'EDPhoto 913 ', currentCohort%resp_m + + + currentCohort%resp_g_tstep = prt_params%grperc(ft) * & + (max(0._r8,currentCohort%gpp_tstep - currentCohort%resp_m)) + + + currentCohort%resp_tstep = currentCohort%resp_m + & + currentCohort%resp_g_tstep ! kgC/indiv/ts + currentCohort%npp_tstep = currentCohort%gpp_tstep - & + currentCohort%resp_tstep ! kgC/indiv/ts - if(check_elai>tiny(check_elai)) then + ! Accumulate the combined conductance (stomatal+leaf boundary layer) + ! Note that currentCohort%g_sb_laweight is weighted by the leaf area + ! of each cohort and has units of [m/s] * [m2 leaf] - ! Normalize the leaf-area weighted canopy conductance - ! The denominator is the total effective leaf area in the canopy, - ! units of [m/s]*[m2] / [m2] = [m/s] - g_sb_leaves = g_sb_leaves / (elai*currentPatch%total_canopy_area) + g_sb_leaves = g_sb_leaves + currentCohort%g_sb_laweight - if( g_sb_leaves > (1._r8/rsmax0) ) then + ! Accumulate the total effective leaf area from all cohorts + ! in this patch. Normalize by canopy area outside the loop + patch_la = patch_la + cohort_eleaf_area - ! Combined mean leaf resistance is the inverse of mean leaf conductance - r_sb_leaves = 1.0_r8/g_sb_leaves + currentCohort => currentCohort%shorter + enddo do_cohort_drive - if (r_sb_leavestiny(patch_la)) then + + ! Normalize the leaf-area weighted canopy conductance + ! The denominator is the total effective leaf area in the canopy, + ! units of [m/s]*[m2] / [m2] = [m/s] + ! preserve_b4b will be removed soon. This is kept here to prevent + ! round off errors in the baseline tests for the two-stream code (RGK 12-27-23) + if_preserve_b4b3: if(preserve_b4b) then + elai = calc_areaindex(currentPatch,'elai') + g_sb_leaves = g_sb_leaves / (elai*currentPatch%total_canopy_area) + else + g_sb_leaves = g_sb_leaves / max(0.1_r8*currentPatch%total_canopy_area,patch_la) + end if if_preserve_b4b3 + + + if_above_mincond: if( g_sb_leaves > (1._r8/rsmax0) ) then + + ! Combined mean leaf resistance is the inverse of mean leaf conductance + r_sb_leaves = 1.0_r8/g_sb_leaves + + if (r_sb_leaves currentPatch%younger + end do - ! This value is used for diagnostics, the molar form of conductance - ! is what is used in the field usually, so we track that form - currentPatch%c_stomata = cf / r_stomata + deallocate(rootfr_ft) - else + end do !site loop - ! But this will prevent it from using an unintialized value - bc_out(s)%rssun_pa(ifp) = rsmax0 - bc_out(s)%rssha_pa(ifp) = rsmax0 + end associate + end subroutine FatesPlantRespPhotosynthDrive - ! This value is used for diagnostics, the molar form of conductance - ! is what is used in the field usually, so we track that form - currentPatch%c_stomata = cf / rsmax0 + ! =========================================================================================== - end if - ! This value is used for diagnostics, the molar form of conductance - ! is what is used in the field usually, so we track that form - currentPatch%c_lblayer = cf / bc_in(s)%rb_pa(ifp) + subroutine RootLayerNFixation(t_soil,ft,dtime,fnrt_mr_layer,fnrt_mr_nfix_layer,nfix_layer) - end if - end if ! not bare ground patch - currentPatch => currentPatch%younger - end do + ! ------------------------------------------------------------------------------- + ! Symbiotic N Fixation is handled via Houlton et al 2008 and Fisher et al. 2010 + ! + ! A unifying framework for dinitrogen fixation in the terrestrial biosphere + ! Benjamin Z. Houlton, Ying-Ping Wang, Peter M. Vitousek & Christopher B. Field + ! Nature volume 454, pages327–330 (2008) https://doi.org/10.1038/nature07028 + ! + ! Carbon cost of plant nitrogen acquisition: A mechanistic, globally applicable model + ! of plant nitrogen uptake, retranslocation, and fixation. J. B. Fisher,S. Sitch,Y. + ! Malhi,R. A. Fisher,C. Huntingford,S.-Y. Tan. Global Biogeochemical Cycles. March + ! 2010 https://doi.org/10.1029/2009GB003621 + ! + ! ------------------------------------------------------------------------------ - deallocate(rootfr_ft) - end do !site loop + real(r8),intent(in) :: t_soil ! Temperature of the current soil layer [degC] + integer,intent(in) :: ft ! Functional type index + real(r8),intent(in) :: dtime ! Time step length [s] + real(r8),intent(in) :: fnrt_mr_layer ! Amount of maintenance respiration in the fine-roots + ! for all non-fixation related processes [kgC/s] - end associate -end subroutine FatesPlantRespPhotosynthDrive + real(r8),intent(out) :: fnrt_mr_nfix_layer ! The added maintenance respiration due to nfixation + ! to be added as a surcharge to non-fixation MR [kgC] + real(r8),intent(out) :: nfix_layer ! The amount of N fixed in this layer through + ! symbiotic activity [kgN] -! =========================================================================================== + real(r8) :: c_cost_nfix ! carbon cost of N fixation [kgC/kgN] + real(r8) :: c_spent_nfix ! carbon spent on N fixation, per layer [kgC/plant/timestep] + ! N fixation parameters from Houlton et al (2008) and Fisher et al (2010) + real(r8), parameter :: s_fix = -6.25_r8 ! s parameter from FUN model (fisher et al 2010) + real(r8), parameter :: a_fix = -3.62_r8 ! a parameter from Houlton et al. 2010 (a = -3.62 +/- 0.52) + real(r8), parameter :: b_fix = 0.27_r8 ! b parameter from Houlton et al. 2010 (b = 0.27 +/-0.04) + real(r8), parameter :: c_fix = 25.15_r8 ! c parameter from Houlton et al. 2010 (c = 25.15 +/- 0.66) -subroutine RootLayerNFixation(t_soil,ft,dtime,fnrt_mr_layer,fnrt_mr_nfix_layer,nfix_layer) + ! Amount of C spent (as part of MR respiration) on symbiotic fixation [kgC/s] + fnrt_mr_nfix_layer = fnrt_mr_layer * prt_params%nfix_mresp_scfrac(ft) + ! This is the unit carbon cost for nitrogen fixation. It is temperature dependant [kgC/kgN] + c_cost_nfix = s_fix * (exp(a_fix + b_fix * (t_soil-tfrz) & + * (1._r8 - 0.5_r8 * (t_soil-tfrz) / c_fix)) - 2._r8) - ! ------------------------------------------------------------------------------- - ! Symbiotic N Fixation is handled via Houlton et al 2008 and Fisher et al. 2010 - ! - ! A unifying framework for dinitrogen fixation in the terrestrial biosphere - ! Benjamin Z. Houlton, Ying-Ping Wang, Peter M. Vitousek & Christopher B. Field - ! Nature volume 454, pages327–330 (2008) https://doi.org/10.1038/nature07028 - ! - ! Carbon cost of plant nitrogen acquisition: A mechanistic, globally applicable model - ! of plant nitrogen uptake, retranslocation, and fixation. J. B. Fisher,S. Sitch,Y. - ! Malhi,R. A. Fisher,C. Huntingford,S.-Y. Tan. Global Biogeochemical Cycles. March - ! 2010 https://doi.org/10.1029/2009GB003621 - ! - ! ------------------------------------------------------------------------------ + ! Time integrated amount of carbon spent on fixation (in this layer) [kgC/plant/layer/tstep] + c_spent_nfix = fnrt_mr_nfix_layer * dtime - - real(r8),intent(in) :: t_soil ! Temperature of the current soil layer [degC] - integer,intent(in) :: ft ! Functional type index - real(r8),intent(in) :: dtime ! Time step length [s] - real(r8),intent(in) :: fnrt_mr_layer ! Amount of maintenance respiration in the fine-roots - ! for all non-fixation related processes [kgC/s] - - real(r8),intent(out) :: fnrt_mr_nfix_layer ! The added maintenance respiration due to nfixation - ! to be added as a surcharge to non-fixation MR [kgC] - real(r8),intent(out) :: nfix_layer ! The amount of N fixed in this layer through - ! symbiotic activity [kgN] + ! Amount of nitrogen fixed in this layer [kgC/plant/layer/tstep]/[kgC/kgN] = [kgN/plant/layer/tstep] + nfix_layer = c_spent_nfix / c_cost_nfix - real(r8) :: c_cost_nfix ! carbon cost of N fixation [kgC/kgN] - real(r8) :: c_spent_nfix ! carbon spent on N fixation, per layer [kgC/plant/timestep] - - ! N fixation parameters from Houlton et al (2008) and Fisher et al (2010) - real(r8), parameter :: s_fix = -6.25_r8 ! s parameter from FUN model (fisher et al 2010) - real(r8), parameter :: a_fix = -3.62_r8 ! a parameter from Houlton et al. 2010 (a = -3.62 +/- 0.52) - real(r8), parameter :: b_fix = 0.27_r8 ! b parameter from Houlton et al. 2010 (b = 0.27 +/-0.04) - real(r8), parameter :: c_fix = 25.15_r8 ! c parameter from Houlton et al. 2010 (c = 25.15 +/- 0.66) - - ! Amount of C spent (as part of MR respiration) on symbiotic fixation [kgC/s] - fnrt_mr_nfix_layer = fnrt_mr_layer * prt_params%nfix_mresp_scfrac(ft) - - ! This is the unit carbon cost for nitrogen fixation. It is temperature dependant [kgC/kgN] - c_cost_nfix = s_fix * (exp(a_fix + b_fix * (t_soil-tfrz) & - * (1._r8 - 0.5_r8 * (t_soil-tfrz) / c_fix)) - 2._r8) - - ! Time integrated amount of carbon spent on fixation (in this layer) [kgC/plant/layer/tstep] - c_spent_nfix = fnrt_mr_nfix_layer * dtime - - ! Amount of nitrogen fixed in this layer [kgC/plant/layer/tstep]/[kgC/kgN] = [kgN/plant/layer/tstep] - nfix_layer = c_spent_nfix / c_cost_nfix - - return -end subroutine RootLayerNFixation + return + end subroutine RootLayerNFixation -! ======================================================================================= + ! ======================================================================================= subroutine LeafLayerPhotosynthesis(f_sun_lsl, & ! in parsun_lsl, & ! in @@ -1150,6 +1301,13 @@ subroutine LeafLayerPhotosynthesis(f_sun_lsl, & ! in ! Fraction of light absorbed by non-photosynthetic pigments real(r8),parameter :: fnps = 0.15_r8 + ! term accounting that two photons are needed to fully transport a single + ! electron in photosystem 2 + real(r8), parameter :: photon_to_e = 0.5_r8 + + ! Unit conversion of w/m2 to umol photons m-2 s-1 + real(r8), parameter :: wm2_to_umolm2s = 4.6_r8 + ! For plants with no leaves, a miniscule amount of conductance ! can happen through the stems, at a partial rate of cuticular conductance real(r8),parameter :: stem_cuticle_loss_frac = 0.1_r8 @@ -1168,6 +1326,9 @@ subroutine LeafLayerPhotosynthesis(f_sun_lsl, & ! in ! empirical curvature parameter for ap photosynthesis co-limitation real(r8),parameter :: theta_ip = 0.999_r8 + ! minimum Leaf area to solve, too little has shown instability + real(r8), parameter :: min_la_to_solve = 0.0000000001_r8 + associate( bb_slope => EDPftvarcon_inst%bb_slope ,& ! slope of BB relationship, unitless medlyn_slope=> EDPftvarcon_inst%medlyn_slope , & ! Slope for Medlyn stomatal conductance model method, the unit is KPa^0.5 stomatal_intercept=> EDPftvarcon_inst%stomatal_intercept ) !Unstressed minimum stomatal conductance, the unit is umol/m**2/s @@ -1210,24 +1371,31 @@ subroutine LeafLayerPhotosynthesis(f_sun_lsl, & ! in do sunsha = 1,2 ! Electron transport rate for C3 plants. - ! Convert par from W/m2 to umol photons/m**2/s using the factor 4.6 + ! Convert par from W/m2 to umol photons/m**2/s ! Convert from units of par absorbed per unit ground area to par ! absorbed per unit leaf area. if(sunsha == 1)then !sunlit - if(( laisun_lsl * canopy_area_lsl) > 0.0000000001_r8)then + if(( laisun_lsl * canopy_area_lsl) > min_la_to_solve)then qabs = parsun_lsl / (laisun_lsl * canopy_area_lsl ) - qabs = qabs * 0.5_r8 * (1._r8 - fnps) * 4.6_r8 + qabs = qabs * photon_to_e * (1._r8 - fnps) * wm2_to_umolm2s else qabs = 0.0_r8 end if else - qabs = parsha_lsl / (laisha_lsl * canopy_area_lsl) - qabs = qabs * 0.5_r8 * (1._r8 - fnps) * 4.6_r8 + if( (parsha_lsl>nearzero) .and. (laisha_lsl * canopy_area_lsl) > min_la_to_solve ) then + qabs = parsha_lsl / (laisha_lsl * canopy_area_lsl) + qabs = qabs * photon_to_e * (1._r8 - fnps) * wm2_to_umolm2s + else + ! The radiative transfer schemes are imperfect + ! they can sometimes generate negative values here + qabs = 0._r8 + end if + end if !convert the absorbed par into absorbed par per m2 of leaf, @@ -1235,7 +1403,7 @@ subroutine LeafLayerPhotosynthesis(f_sun_lsl, & ! in aquad = theta_psii bquad = -(qabs + jmax) cquad = qabs * jmax - call quadratic_f (aquad, bquad, cquad, r1, r2) + call QuadraticRoots(aquad, bquad, cquad, r1, r2) je = min(r1,r2) ! Initialize intercellular co2 @@ -1265,7 +1433,7 @@ subroutine LeafLayerPhotosynthesis(f_sun_lsl, & ! in aquad = theta_cj_c3 bquad = -(ac + aj) cquad = ac * aj - call quadratic_f (aquad, bquad, cquad, r1, r2) + call QuadraticRoots(aquad, bquad, cquad, r1, r2) agross = min(r1,r2) else @@ -1277,14 +1445,14 @@ subroutine LeafLayerPhotosynthesis(f_sun_lsl, & ! in if(sunsha == 1)then !sunlit !guard against /0's in the night. if((laisun_lsl * canopy_area_lsl) > 0.0000000001_r8) then - aj = quant_eff(c3c4_path_index) * parsun_lsl * 4.6_r8 + aj = quant_eff(c3c4_path_index) * parsun_lsl * wm2_to_umolm2s !convert from per cohort to per m2 of leaf) aj = aj / (laisun_lsl * canopy_area_lsl) else aj = 0._r8 end if else - aj = quant_eff(c3c4_path_index) * parsha_lsl * 4.6_r8 + aj = quant_eff(c3c4_path_index) * parsha_lsl * wm2_to_umolm2s aj = aj / (laisha_lsl * canopy_area_lsl) end if @@ -1296,13 +1464,13 @@ subroutine LeafLayerPhotosynthesis(f_sun_lsl, & ! in aquad = theta_cj_c4 bquad = -(ac + aj) cquad = ac * aj - call quadratic_f (aquad, bquad, cquad, r1, r2) + call QuadraticRoots(aquad, bquad, cquad, r1, r2) ai = min(r1,r2) aquad = theta_ip bquad = -(ai + ap) cquad = ai * ap - call quadratic_f (aquad, bquad, cquad, r1, r2) + call QuadraticRoots(aquad, bquad, cquad, r1, r2) agross = min(r1,r2) end if @@ -1327,6 +1495,31 @@ subroutine LeafLayerPhotosynthesis(f_sun_lsl, & ! in ! With an <= 0, then gs_mol = stomatal_intercept_btran leaf_co2_ppress = can_co2_ppress- h2o_co2_bl_diffuse_ratio/gb_mol * a_gs * can_press leaf_co2_ppress = max(leaf_co2_ppress,1.e-06_r8) + + ! A note about the use of the quadratic equations for calculating stomatal conductance + ! ------------------------------------------------------------------------------------ + ! These two following models calculate the conductance between the intercellular leaf + ! space and the leaf surface, not the canopy air space. Transport between the leaf + ! surface and the canopy air space is governed by the leaf boundary layer conductance. + ! However, we need to estimate the properties at the surface of the leaf to solve for + ! the stomatal conductance. We do this by using Fick's law (gradient resistance + ! approximation of diffusion) to estimate the flux of water vapor across the + ! leaf boundary layer, and balancing that with the flux across the stomata. It + ! results in the following equation for leaf surface humidity: + ! + ! e_s = (e_i g_s + e_c g_b)/(g_b + g_s) + ! + ! The leaf surface humidity (e_s) becomes an expression of canopy humidity (e_c), + ! intercellular humidity (e_i, which is the saturation humidity at leaf temperature), + ! boundary layer conductance (g_b) (these are all known) and stomatal conductance + ! (g_s) (this is still unknown). This expression is substituted into the stomatal + ! conductance equation. The resulting form of these equations becomes a quadratic. + ! + ! For a detailed explanation, see the FATES technical note, section + ! "1.11 Stomatal Conductance" + ! + ! ------------------------------------------------------------------------------------ + if ( stomatal_model == medlyn_model ) then !stomatal conductance calculated from Medlyn et al. (2011), the numerical & @@ -1341,7 +1534,7 @@ subroutine LeafLayerPhotosynthesis(f_sun_lsl, & ! in (2.0*stomatal_intercept_btran + term * & (1.0 - medlyn_slope(ft)* medlyn_slope(ft) / vpd)) * term - call quadratic_f (aquad, bquad, cquad, r1, r2) + call QuadraticRoots(aquad, bquad, cquad, r1, r2) gs_mol = max(r1,r2) else if ( stomatal_model == ballberry_model ) then !stomatal conductance calculated from Ball et al. (1987) @@ -1350,7 +1543,7 @@ subroutine LeafLayerPhotosynthesis(f_sun_lsl, & ! in cquad = -gb_mol*(leaf_co2_ppress*stomatal_intercept_btran + & bb_slope(ft)*anet*can_press * ceair/ veg_esat ) - call quadratic_f (aquad, bquad, cquad, r1, r2) + call QuadraticRoots(aquad, bquad, cquad, r1, r2) gs_mol = max(r1,r2) end if @@ -1462,924 +1655,859 @@ subroutine LeafLayerPhotosynthesis(f_sun_lsl, & ! in end associate return -end subroutine LeafLayerPhotosynthesis + end subroutine LeafLayerPhotosynthesis -! ======================================================================================= + ! ======================================================================================= -function LeafHumidityStomaResis(leaf_psi, veg_tempk, ceair, can_press, veg_esat, & - rb, gstoma, ft) result(rstoma_out) - - ! ------------------------------------------------------------------------------------- - ! This calculates inner leaf humidity as a function of mesophyll water potential - ! Adopted from Vesala et al., 2017 https://www.frontiersin.org/articles/10.3389/fpls.2017.00054/full - ! - ! Equation 1 in Vesala et al: - ! lwp_star = wi/w0 = exp( k_lwp*leaf_psi*molar_mass_water/(rgas_J_k_mol * veg_tempk) ) - ! - ! Terms: - ! leaf_psi: leaf water potential [MPa] - ! k_lwp: inner leaf humidity scaling coefficient [-] - ! rgas_J_K_mol: universal gas constant, [J/K/mol], 8.3144598 - ! molar_mass_water, molar mass of water, [g/mol]: 18.0 - ! - ! Unit conversions: - ! 1 Pa = 1 N/m2 = 1 J/m3 - ! density of liquid water [kg/m3] = 1000 - ! - ! units of equation 1: exp( [MPa]*[g/mol]/( [J/K/mol] * [K] ) ) - ! [MJ/m3]*[g/mol]*[m3/kg]*[kg/g]*[J/MJ] / ([J/mol]) - ! dimensionless: [J/g]*[g/mol]/([J/mol]) - ! - ! Note: unit conversions drop out b/c [m3/kg]*[kg/g]*[J/MJ] = 1e-3*1.e-3*1e6 = 1.0 - ! - ! Junyan Ding 2021 - ! ------------------------------------------------------------------------------------- - - ! Arguments - real(r8) :: leaf_psi ! Leaf water potential [MPa] - real(r8) :: veg_tempk ! Leaf temperature [K] - real(r8) :: ceair ! vapor pressure of air, constrained [Pa] - real(r8) :: can_press ! Atmospheric pressure of canopy [Pa] - real(r8) :: veg_esat ! Saturated vapor pressure at veg surf [Pa] - real(r8) :: rb ! Leaf Boundary layer resistance [s/m] - real(r8) :: gstoma ! Stomatal Conductance of this leaf layer [m/s] - integer :: ft ! Plant Functional Type - real(r8) :: rstoma_out ! Total Stomatal resistance (stoma and BL) [s/m] - - ! Locals - real(r8) :: k_lwp ! Scaling coefficient for the ratio of leaf xylem - ! water potential to mesophyll water potential - real(r8) :: qs ! Specific humidity [g/kg] - real(r8) :: qsat ! Saturation specific humidity [g/kg] - real(r8) :: qsat_adj ! Adjusted saturation specific humidity [g/kg] - real(r8) :: lwp_star ! leaf water potential scaling coefficient - ! for inner leaf humidity, 0 means total dehydroted - ! leaf, 1 means total saturated leaf - - ! Note: to disable this control, set k_lwp to zero, LWP_star will be 1 - k_lwp = EDPftvarcon_inst%hydr_k_lwp(ft) - if (leaf_psi<0._r8) then - lwp_star = exp(k_lwp*leaf_psi*molar_mass_water/(rgas_J_K_mol *veg_tempk)) - else - lwp_star = 1._r8 - end if + function LeafHumidityStomaResis(leaf_psi, veg_tempk, ceair, can_press, veg_esat, & + rb, gstoma, ft) result(rstoma_out) - ! compute specific humidity from vapor pressure - ! q = molar_mass_ratio_vapdry*e/(can_press - (1-molar_mass_ratio_vapdry)*e) - ! source https://cran.r-project.org/web/packages/humidity/vignettes/humidity-measures.html - ! now adjust inner leaf humidity by LWP_star + ! ------------------------------------------------------------------------------------- + ! This calculates inner leaf humidity as a function of mesophyll water potential + ! Adopted from Vesala et al., 2017 https://www.frontiersin.org/articles/10.3389/fpls.2017.00054/full + ! + ! Equation 1 in Vesala et al: + ! lwp_star = wi/w0 = exp( k_lwp*leaf_psi*molar_mass_water/(rgas_J_k_mol * veg_tempk) ) + ! + ! Terms: + ! leaf_psi: leaf water potential [MPa] + ! k_lwp: inner leaf humidity scaling coefficient [-] + ! rgas_J_K_mol: universal gas constant, [J/K/mol], 8.3144598 + ! molar_mass_water, molar mass of water, [g/mol]: 18.0 + ! + ! Unit conversions: + ! 1 Pa = 1 N/m2 = 1 J/m3 + ! density of liquid water [kg/m3] = 1000 + ! + ! units of equation 1: exp( [MPa]*[g/mol]/( [J/K/mol] * [K] ) ) + ! [MJ/m3]*[g/mol]*[m3/kg]*[kg/g]*[J/MJ] / ([J/mol]) + ! dimensionless: [J/g]*[g/mol]/([J/mol]) + ! + ! Note: unit conversions drop out b/c [m3/kg]*[kg/g]*[J/MJ] = 1e-3*1.e-3*1e6 = 1.0 + ! + ! Junyan Ding 2021 + ! ------------------------------------------------------------------------------------- + + ! Arguments + real(r8) :: leaf_psi ! Leaf water potential [MPa] + real(r8) :: veg_tempk ! Leaf temperature [K] + real(r8) :: ceair ! vapor pressure of air, constrained [Pa] + real(r8) :: can_press ! Atmospheric pressure of canopy [Pa] + real(r8) :: veg_esat ! Saturated vapor pressure at veg surf [Pa] + real(r8) :: rb ! Leaf Boundary layer resistance [s/m] + real(r8) :: gstoma ! Stomatal Conductance of this leaf layer [m/s] + integer :: ft ! Plant Functional Type + real(r8) :: rstoma_out ! Total Stomatal resistance (stoma and BL) [s/m] + + ! Locals + real(r8) :: k_lwp ! Scaling coefficient for the ratio of leaf xylem + ! water potential to mesophyll water potential + real(r8) :: qs ! Specific humidity [g/kg] + real(r8) :: qsat ! Saturation specific humidity [g/kg] + real(r8) :: qsat_adj ! Adjusted saturation specific humidity [g/kg] + real(r8) :: lwp_star ! leaf water potential scaling coefficient + ! for inner leaf humidity, 0 means total dehydroted + ! leaf, 1 means total saturated leaf + + ! Note: to disable this control, set k_lwp to zero, LWP_star will be 1 + k_lwp = EDPftvarcon_inst%hydr_k_lwp(ft) + if (leaf_psi<0._r8) then + lwp_star = exp(k_lwp*leaf_psi*molar_mass_water/(rgas_J_K_mol *veg_tempk)) + else + lwp_star = 1._r8 + end if + + ! compute specific humidity from vapor pressure + ! q = molar_mass_ratio_vapdry*e/(can_press - (1-molar_mass_ratio_vapdry)*e) + ! source https://cran.r-project.org/web/packages/humidity/vignettes/humidity-measures.html + ! now adjust inner leaf humidity by LWP_star + + qs = molar_mass_ratio_vapdry * ceair / (can_press - (1._r8-molar_mass_ratio_vapdry) * ceair) + qsat = molar_mass_ratio_vapdry * veg_esat / (can_press - (1._r8-molar_mass_ratio_vapdry) * veg_esat) + qsat_adj = qsat*lwp_star + + ! Adjusting gs (compute a virtual gs) that will be passed to host model + + if ( qsat_adj < qs ) then + + ! if inner leaf vapor pressure is less then or equal to that at leaf surface + ! then set stomata resistance to be very large to stop the transpiration or back flow of vapor + rstoma_out = rsmax0 + + else + + rstoma_out = (qsat-qs)*( 1/gstoma + rb)/(qsat_adj - qs)-rb + + end if + + if (rstoma_out < nearzero ) then + write (fates_log(),*) 'qsat:', qsat, 'qs:', qs + write (fates_log(),*) 'LWP :', leaf_psi + write (fates_log(),*) 'ceair:', ceair, 'veg_esat:', veg_esat + write (fates_log(),*) 'rstoma_out:', rstoma_out, 'rb:', rb + write (fates_log(),*) 'LWP_star', lwp_star + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + + end function LeafHumidityStomaResis + + + ! ===================================================================================== + + subroutine ScaleLeafLayerFluxToCohort(nv, & ! in currentCohort%nv + psn_llz, & ! in %psn_z(1:currentCohort%nv,ft,cl) + lmr_llz, & ! in lmr_z(1:currentCohort%nv,ft,cl) + rs_llz, & ! in rs_z(1:currentCohort%nv,ft,cl) + elai_llz, & ! in %elai_profile(cl,ft,1:currentCohort%nv) + c13disc_llz, & ! in c13disc_z(cl, ft, 1:currentCohort%nv) + c_area, & ! in currentCohort%c_area + nplant, & ! in currentCohort%n + rb, & ! in bc_in(s)%rb_pa(ifp) + maintresp_reduction_factor, & ! in + g_sb_laweight, & ! out currentCohort%g_sb_laweight [m/s] [m2-leaf] + gpp, & ! out currentCohort%gpp_tstep + rdark, & ! out currentCohort%rdark + c13disc_clm, & ! out currentCohort%c13disc_clm + cohort_eleaf_area ) ! out [m2] + + ! ------------------------------------------------------------------------------------ + ! This subroutine effectively integrates leaf carbon fluxes over the + ! leaf layers to give cohort totals. + ! Some arguments have the suffix "_llz". This indicates that the vector + ! is stratefied in the leaf-layer (ll) dimension, and is a portion of the calling + ! array which has the "_z" tag, thus "llz". + ! ------------------------------------------------------------------------------------ - qs = molar_mass_ratio_vapdry * ceair / (can_press - (1._r8-molar_mass_ratio_vapdry) * ceair) - qsat = molar_mass_ratio_vapdry * veg_esat / (can_press - (1._r8-molar_mass_ratio_vapdry) * veg_esat) - qsat_adj = qsat*lwp_star + use FatesConstantsMod, only : umolC_to_kgC - ! Adjusting gs (compute a virtual gs) that will be passed to host model + ! Arguments + integer, intent(in) :: nv ! number of active leaf layers + real(r8), intent(in) :: psn_llz(nv) ! layer photosynthesis rate (GPP) [umolC/m2leaf/s] + real(r8), intent(in) :: lmr_llz(nv) ! layer dark respiration rate [umolC/m2leaf/s] + real(r8), intent(in) :: rs_llz(nv) ! leaf layer stomatal resistance [s/m] + real(r8), intent(in) :: elai_llz(nv) ! exposed LAI per layer [m2 leaf/ m2 pft footprint] + real(r8), intent(in) :: c13disc_llz(nv) ! leaf layer c13 discrimination, weighted mean + real(r8), intent(in) :: c_area ! crown area m2/m2 + real(r8), intent(in) :: nplant ! indiv/m2 + real(r8), intent(in) :: rb ! leaf boundary layer resistance (s/m) + real(r8), intent(in) :: maintresp_reduction_factor ! factor by which to reduce maintenance respiration + real(r8), intent(out) :: g_sb_laweight ! Combined conductance (stomatal + boundary layer) for the cohort + ! weighted by leaf area [m/s]*[m2] + real(r8), intent(out) :: gpp ! GPP (kgC/indiv/s) + real(r8), intent(out) :: rdark ! Dark Leaf Respiration (kgC/indiv/s) + real(r8), intent(out) :: cohort_eleaf_area ! Effective leaf area of the cohort [m2] + real(r8), intent(out) :: c13disc_clm ! unpacked Cohort level c13 discrimination + real(r8) :: sum_weight ! sum of weight for unpacking d13c flux (c13disc_z) from + ! (canopy_layer, pft, leaf_layer) matrix to cohort (c13disc_clm) + + ! GPP IN THIS SUBROUTINE IS A RATE. THE CALLING ARGUMENT IS GPP_TSTEP. AFTER THIS + ! CALL THE RATE WILL BE MULTIPLIED BY THE INTERVAL TO GIVE THE INTEGRATED QUANT. + + ! Locals + integer :: il ! leaf layer index + real(r8) :: cohort_layer_eleaf_area ! the effective leaf area of the cohort's current layer [m2] + + cohort_eleaf_area = 0.0_r8 + g_sb_laweight = 0.0_r8 + gpp = 0.0_r8 + rdark = 0.0_r8 + + do il = 1, nv ! Loop over the leaf layers this cohort participates in + + + ! Cohort's total effective leaf area in this layer [m2] + ! leaf area index of the layer [m2/m2 ground] * [m2 ground] + ! elai_llz is the LAI for the whole PFT. Multiplying this by the ground + ! area this cohort contributes, give the cohort's portion of the leaf + ! area in this layer + cohort_layer_eleaf_area = elai_llz(il) * c_area + + ! Increment the cohort's total effective leaf area [m2] + cohort_eleaf_area = cohort_eleaf_area + cohort_layer_eleaf_area + + ! Leaf conductance (stomatal and boundary layer) + ! This should be the weighted average over the leaf surfaces. + ! Since this is relevant to the stomata, its weighting should be based + ! on total leaf area, and not really footprint area + ! [m/s] * [m2 cohort's leaf layer] + g_sb_laweight = g_sb_laweight + 1.0_r8/(rs_llz(il)+rb) * cohort_layer_eleaf_area + + ! GPP [umolC/m2leaf/s] * [m2 leaf ] -> [umolC/s] + gpp = gpp + psn_llz(il) * cohort_layer_eleaf_area + + ! Dark respiration + ! [umolC/m2leaf/s] * [m2 leaf] + rdark = rdark + lmr_llz(il) * cohort_layer_eleaf_area + + end do + + + + if (nv > 1) then + ! cohort%c13disc_clm as weighted mean of d13c flux at all related leave layers + sum_weight = sum(psn_llz(1:nv-1) * elai_llz(1:nv-1)) + if (sum_weight .eq. 0.0_r8) then + c13disc_clm = 0.0 + else + c13disc_clm = sum(c13disc_llz(1:nv-1) * psn_llz(1:nv-1) * elai_llz(1:nv-1)) / sum_weight + end if + + end if - if ( qsat_adj < qs ) then - ! if inner leaf vapor pressure is less then or equal to that at leaf surface - ! then set stomata resistance to be very large to stop the transpiration or back flow of vapor - rstoma_out = rsmax0 - - else + ! ----------------------------------------------------------------------------------- + ! We DO NOT normalize g_sb_laweight. + ! The units that we are passing back are [m/s] * [m2 effective leaf] + ! We will add these up over the whole patch, and then normalized + ! by the patch's total leaf area in the calling routine + ! ----------------------------------------------------------------------------------- - rstoma_out = (qsat-qs)*( 1/gstoma + rb)/(qsat_adj - qs)-rb - - end if - - if (rstoma_out < nearzero ) then - write (fates_log(),*) 'qsat:', qsat, 'qs:', qs - write (fates_log(),*) 'LWP :', leaf_psi - write (fates_log(),*) 'ceair:', ceair, 'veg_esat:', veg_esat - write (fates_log(),*) 'rstoma_out:', rstoma_out, 'rb:', rb - write (fates_log(),*) 'LWP_star', lwp_star - call endrun(msg=errMsg(sourcefile, __LINE__)) - end if + ! ----------------------------------------------------------------------------------- + ! Convert dark respiration and GPP from [umol/s] to [kgC/plant/s] + ! Also, apply the maintenance respiration reduction factor + ! ----------------------------------------------------------------------------------- -end function LeafHumidityStomaResis + rdark = rdark * umolC_to_kgC * maintresp_reduction_factor / nplant + gpp = gpp * umolC_to_kgC / nplant + if ( debug ) then + write(fates_log(),*) 'EDPhoto 816 ', gpp + write(fates_log(),*) 'EDPhoto 817 ', psn_llz(1:nv) + write(fates_log(),*) 'EDPhoto 820 ', nv + write(fates_log(),*) 'EDPhoto 821 ', elai_llz(1:nv) + write(fates_log(),*) 'EDPhoto 843 ', rdark + write(fates_log(),*) 'EDPhoto 873 ', nv + write(fates_log(),*) 'EDPhoto 874 ', cohort_eleaf_area + endif -! ===================================================================================== + return + end subroutine ScaleLeafLayerFluxToCohort -subroutine ScaleLeafLayerFluxToCohort(nv, & ! in currentCohort%nv - psn_llz, & ! in %psn_z(1:currentCohort%nv,ft,cl) - lmr_llz, & ! in lmr_z(1:currentCohort%nv,ft,cl) - rs_llz, & ! in rs_z(1:currentCohort%nv,ft,cl) - elai_llz, & ! in %elai_profile(cl,ft,1:currentCohort%nv) - c13disc_llz, & ! in c13disc_z(cl, ft, 1:currentCohort%nv) - c_area, & ! in currentCohort%c_area - nplant, & ! in currentCohort%n - rb, & ! in bc_in(s)%rb_pa(ifp) - maintresp_reduction_factor, & ! in - g_sb_laweight, & ! out currentCohort%g_sb_laweight [m/s] [m2-leaf] - gpp, & ! out currentCohort%gpp_tstep - rdark, & ! out currentCohort%rdark - c13disc_clm, & ! out currentCohort%c13disc_clm - cohort_eleaf_area ) ! out [m2] + ! ===================================================================================== - ! ------------------------------------------------------------------------------------ - ! This subroutine effectively integrates leaf carbon fluxes over the - ! leaf layers to give cohort totals. - ! Some arguments have the suffix "_llz". This indicates that the vector - ! is stratefied in the leaf-layer (ll) dimension, and is a portion of the calling - ! array which has the "_z" tag, thus "llz". - ! ------------------------------------------------------------------------------------ + function ft1_f(tl, ha) result(ans) + ! + !!DESCRIPTION: + ! photosynthesis temperature response + ! + ! !REVISION HISTORY + ! Jinyun Tang separated it out from Photosynthesis, Feb. 07/2013 + ! 7/23/16: Copied over from CLM by Ryan Knox + ! + !!USES + use FatesConstantsMod, only : rgas => rgas_J_K_kmol - use FatesConstantsMod, only : umolC_to_kgC - - ! Arguments - integer, intent(in) :: nv ! number of active leaf layers - real(r8), intent(in) :: psn_llz(nv) ! layer photosynthesis rate (GPP) [umolC/m2leaf/s] - real(r8), intent(in) :: lmr_llz(nv) ! layer dark respiration rate [umolC/m2leaf/s] - real(r8), intent(in) :: rs_llz(nv) ! leaf layer stomatal resistance [s/m] - real(r8), intent(in) :: elai_llz(nv) ! exposed LAI per layer [m2 leaf/ m2 pft footprint] - real(r8), intent(in) :: c13disc_llz(nv) ! leaf layer c13 discrimination, weighted mean - real(r8), intent(in) :: c_area ! crown area m2/m2 - real(r8), intent(in) :: nplant ! indiv/m2 - real(r8), intent(in) :: rb ! leaf boundary layer resistance (s/m) - real(r8), intent(in) :: maintresp_reduction_factor ! factor by which to reduce maintenance respiration - real(r8), intent(out) :: g_sb_laweight ! Combined conductance (stomatal + boundary layer) for the cohort - ! weighted by leaf area [m/s]*[m2] - real(r8), intent(out) :: gpp ! GPP (kgC/indiv/s) - real(r8), intent(out) :: rdark ! Dark Leaf Respiration (kgC/indiv/s) - real(r8), intent(out) :: cohort_eleaf_area ! Effective leaf area of the cohort [m2] - real(r8), intent(out) :: c13disc_clm ! unpacked Cohort level c13 discrimination - real(r8) :: sum_weight ! sum of weight for unpacking d13c flux (c13disc_z) from - ! (canopy_layer, pft, leaf_layer) matrix to cohort (c13disc_clm) - - ! GPP IN THIS SUBROUTINE IS A RATE. THE CALLING ARGUMENT IS GPP_TSTEP. AFTER THIS - ! CALL THE RATE WILL BE MULTIPLIED BY THE INTERVAL TO GIVE THE INTEGRATED QUANT. - - ! Locals - integer :: il ! leaf layer index - real(r8) :: cohort_layer_eleaf_area ! the effective leaf area of the cohort's current layer [m2] - - cohort_eleaf_area = 0.0_r8 - g_sb_laweight = 0.0_r8 - gpp = 0.0_r8 - rdark = 0.0_r8 - - do il = 1, nv ! Loop over the leaf layers this cohort participates in - - - ! Cohort's total effective leaf area in this layer [m2] - ! leaf area index of the layer [m2/m2 ground] * [m2 ground] - ! elai_llz is the LAI for the whole PFT. Multiplying this by the ground - ! area this cohort contributes, give the cohort's portion of the leaf - ! area in this layer - cohort_layer_eleaf_area = elai_llz(il) * c_area - - ! Increment the cohort's total effective leaf area [m2] - cohort_eleaf_area = cohort_eleaf_area + cohort_layer_eleaf_area - - ! Leaf conductance (stomatal and boundary layer) - ! This should be the weighted average over the leaf surfaces. - ! Since this is relevant to the stomata, its weighting should be based - ! on total leaf area, and not really footprint area - ! [m/s] * [m2 cohort's leaf layer] - g_sb_laweight = g_sb_laweight + 1.0_r8/(rs_llz(il)+rb) * cohort_layer_eleaf_area - - ! GPP [umolC/m2leaf/s] * [m2 leaf ] -> [umolC/s] (This is cohort group sum) - gpp = gpp + psn_llz(il) * cohort_layer_eleaf_area - - ! Dark respiration - ! [umolC/m2leaf/s] * [m2 leaf] (This is the cohort group sum) - rdark = rdark + lmr_llz(il) * cohort_layer_eleaf_area - - end do - - - - if (nv > 1) then - ! cohort%c13disc_clm as weighted mean of d13c flux at all related leave layers - sum_weight = sum(psn_llz(1:nv-1) * elai_llz(1:nv-1)) - if (sum_weight .eq. 0.0_r8) then - c13disc_clm = 0.0 - else - c13disc_clm = sum(c13disc_llz(1:nv-1) * psn_llz(1:nv-1) * elai_llz(1:nv-1)) / sum_weight - end if - - end if - - - ! ----------------------------------------------------------------------------------- - ! We DO NOT normalize g_sb_laweight. - ! The units that we are passing back are [m/s] * [m2 effective leaf] - ! We will add these up over the whole patch, and then normalized - ! by the patch's total leaf area in the calling routine - ! ----------------------------------------------------------------------------------- - - ! ----------------------------------------------------------------------------------- - ! Convert dark respiration and GPP from [umol/s] to [kgC/plant/s] - ! Also, apply the maintenance respiration reduction factor - ! ----------------------------------------------------------------------------------- - - rdark = rdark * umolC_to_kgC * maintresp_reduction_factor / nplant - gpp = gpp * umolC_to_kgC / nplant - - if ( debug ) then - write(fates_log(),*) 'EDPhoto 816 ', gpp - write(fates_log(),*) 'EDPhoto 817 ', psn_llz(1:nv) - write(fates_log(),*) 'EDPhoto 820 ', nv - write(fates_log(),*) 'EDPhoto 821 ', elai_llz(1:nv) - write(fates_log(),*) 'EDPhoto 843 ', rdark - write(fates_log(),*) 'EDPhoto 873 ', nv - write(fates_log(),*) 'EDPhoto 874 ', cohort_eleaf_area - endif + ! + ! !ARGUMENTS: + real(r8), intent(in) :: tl ! leaf temperature in photosynthesis temperature function (K) + real(r8), intent(in) :: ha ! activation energy in photosynthesis temperature function (J/mol) + ! + ! !LOCAL VARIABLES: + real(r8) :: ans + !------------------------------------------------------------------------------- - return -end subroutine ScaleLeafLayerFluxToCohort + ans = exp( ha / (rgas*1.e-3_r8*(tfrz+25._r8)) * (1._r8 - (tfrz+25._r8)/tl) ) -! ===================================================================================== + return + end function ft1_f -function ft1_f(tl, ha) result(ans) - ! - !!DESCRIPTION: - ! photosynthesis temperature response - ! - ! !REVISION HISTORY - ! Jinyun Tang separated it out from Photosynthesis, Feb. 07/2013 - ! 7/23/16: Copied over from CLM by Ryan Knox - ! - !!USES - use FatesConstantsMod, only : rgas => rgas_J_K_kmol - - ! - ! !ARGUMENTS: - real(r8), intent(in) :: tl ! leaf temperature in photosynthesis temperature function (K) - real(r8), intent(in) :: ha ! activation energy in photosynthesis temperature function (J/mol) - ! - ! !LOCAL VARIABLES: - real(r8) :: ans - !------------------------------------------------------------------------------- + ! ===================================================================================== - ans = exp( ha / (rgas*1.e-3_r8*(tfrz+25._r8)) * (1._r8 - (tfrz+25._r8)/tl) ) + function fth_f(tl,hd,se,scaleFactor) result(ans) + ! + !!DESCRIPTION: + !photosynthesis temperature inhibition + ! + ! !REVISION HISTORY + ! Jinyun Tang separated it out from Photosynthesis, Feb. 07/2013 + ! 7/23/16: Copied over from CLM by Ryan Knox + ! + use FatesConstantsMod, only : rgas => rgas_J_K_kmol - return -end function ft1_f + ! + ! !ARGUMENTS: + real(r8), intent(in) :: tl ! leaf temperature in photosynthesis temp function (K) + real(r8), intent(in) :: hd ! deactivation energy in photosynthesis temp function (J/mol) + real(r8), intent(in) :: se ! entropy term in photosynthesis temp function (J/mol/K) + real(r8), intent(in) :: scaleFactor ! scaling factor for high temp inhibition (25 C = 1.0) + ! + ! !LOCAL VARIABLES: + real(r8) :: ans + !------------------------------------------------------------------------------- -! ===================================================================================== + ans = scaleFactor / ( 1._r8 + exp( (-hd+se*tl) / (rgas*1.e-3_r8*tl) ) ) -function fth_f(tl,hd,se,scaleFactor) result(ans) - ! - !!DESCRIPTION: - !photosynthesis temperature inhibition - ! - ! !REVISION HISTORY - ! Jinyun Tang separated it out from Photosynthesis, Feb. 07/2013 - ! 7/23/16: Copied over from CLM by Ryan Knox - ! - use FatesConstantsMod, only : rgas => rgas_J_K_kmol + return + end function fth_f - ! - ! !ARGUMENTS: - real(r8), intent(in) :: tl ! leaf temperature in photosynthesis temp function (K) - real(r8), intent(in) :: hd ! deactivation energy in photosynthesis temp function (J/mol) - real(r8), intent(in) :: se ! entropy term in photosynthesis temp function (J/mol/K) - real(r8), intent(in) :: scaleFactor ! scaling factor for high temp inhibition (25 C = 1.0) - ! - ! !LOCAL VARIABLES: - real(r8) :: ans - !------------------------------------------------------------------------------- + ! ===================================================================================== - ans = scaleFactor / ( 1._r8 + exp( (-hd+se*tl) / (rgas*1.e-3_r8*tl) ) ) + function fth25_f(hd,se)result(ans) + ! + !!DESCRIPTION: + ! scaling factor for photosynthesis temperature inhibition + ! + ! !REVISION HISTORY: + ! Jinyun Tang separated it out from Photosynthesis, Feb. 07/2013 + ! 7/23/16: Copied over from CLM by Ryan Knox + ! + !!USES - return -end function fth_f + use FatesConstantsMod, only : rgas => rgas_J_K_kmol -! ===================================================================================== + ! + ! !ARGUMENTS: + real(r8), intent(in) :: hd ! deactivation energy in photosynthesis temp function (J/mol) + real(r8), intent(in) :: se ! entropy term in photosynthesis temp function (J/mol/K) + ! + ! !LOCAL VARIABLES: + real(r8) :: ans + !------------------------------------------------------------------------------- -function fth25_f(hd,se)result(ans) - ! - !!DESCRIPTION: - ! scaling factor for photosynthesis temperature inhibition - ! - ! !REVISION HISTORY: - ! Jinyun Tang separated it out from Photosynthesis, Feb. 07/2013 - ! 7/23/16: Copied over from CLM by Ryan Knox - ! - !!USES + ans = 1._r8 + exp( (-hd+se*(tfrz+25._r8)) / (rgas*1.e-3_r8*(tfrz+25._r8)) ) - use FatesConstantsMod, only : rgas => rgas_J_K_kmol + return + end function fth25_f - ! - ! !ARGUMENTS: - real(r8), intent(in) :: hd ! deactivation energy in photosynthesis temp function (J/mol) - real(r8), intent(in) :: se ! entropy term in photosynthesis temp function (J/mol/K) - ! - ! !LOCAL VARIABLES: - real(r8) :: ans - !------------------------------------------------------------------------------- + ! ===================================================================================== - ans = 1._r8 + exp( (-hd+se*(tfrz+25._r8)) / (rgas*1.e-3_r8*(tfrz+25._r8)) ) + subroutine UpdateCanopyNCanNRadPresent(currentPatch) - return -end function fth25_f + ! --------------------------------------------------------------------------------- + ! This subroutine calculates two patch level quanities: + ! currentPatch%ncan and + ! currentPatch%canopy_mask + ! + ! currentPatch%ncan(:,:) is a two dimensional array that indicates + ! the total number of leaf layers (including those that are not exposed to light) + ! in each canopy layer and for each functional type. + ! + ! currentPatch%nrad(:,:) is a two dimensional array that indicates + ! the total number of EXPOSED leaf layers, but for all intents and purposes + ! in the photosynthesis routine, this appears to be the same as %ncan... + ! + ! currentPatch%canopy_mask(:,:) has the same dimensions, is binary, and + ! indicates whether or not leaf layers are present (by evaluating the canopy area + ! profile). + ! --------------------------------------------------------------------------------- -! ===================================================================================== + ! Arguments + type(fates_patch_type), target :: currentPatch + type(fates_cohort_type), pointer :: currentCohort -subroutine quadratic_f (a, b, c, r1, r2) - ! - ! !DESCRIPTION: - !==============================================================================! - !----------------- Solve quadratic equation for its two roots -----------------! - !==============================================================================! - ! Solution from Press et al (1986) Numerical Recipes: The Art of Scientific - ! Computing (Cambridge University Press, Cambridge), pp. 145. - ! - ! !REVISION HISTORY: - ! 4/5/10: Adapted from /home/bonan/ecm/psn/An_gs_iterative.f90 by Keith Oleson - ! 7/23/16: Copied over from CLM by Ryan Knox - ! - ! !USES: - ! - ! !ARGUMENTS: - real(r8), intent(in) :: a,b,c ! Terms for quadratic equation - real(r8), intent(out) :: r1,r2 ! Roots of quadratic equation - ! - ! !LOCAL VARIABLES: - real(r8) :: q ! Temporary term for quadratic solution - !------------------------------------------------------------------------------ - - if (a == 0._r8) then - write (fates_log(),*) 'Quadratic solution error: a = ',a - call endrun(msg=errMsg(sourcefile, __LINE__)) - end if - - if (b >= 0._r8) then - q = -0.5_r8 * (b + sqrt(b*b - 4._r8*a*c)) - else - q = -0.5_r8 * (b - sqrt(b*b - 4._r8*a*c)) - end if - - r1 = q / a - if (q /= 0._r8) then - r2 = c / q - else - r2 = 1.e36_r8 - end if - -end subroutine quadratic_f - -! ==================================================================================== - -subroutine quadratic_fast (a, b, c, r1, r2) - ! - ! !DESCRIPTION: - !==============================================================================! - !----------------- Solve quadratic equation for its two roots -----------------! - ! THIS METHOD SIMPLY REMOVES THE DIV0 CHECK AND ERROR REPORTING ! - !==============================================================================! - ! Solution from Press et al (1986) Numerical Recipes: The Art of Scientific - ! Computing (Cambridge University Press, Cambridge), pp. 145. - ! - ! !REVISION HISTORY: - ! 4/5/10: Adapted from /home/bonan/ecm/psn/An_gs_iterative.f90 by Keith Oleson - ! 7/23/16: Copied over from CLM by Ryan Knox - ! - ! !USES: - ! - ! !ARGUMENTS: - real(r8), intent(in) :: a,b,c ! Terms for quadratic equation - real(r8), intent(out) :: r1,r2 ! Roots of quadratic equation - ! - ! !LOCAL VARIABLES: - real(r8) :: q ! Temporary term for quadratic solution - !------------------------------------------------------------------------------ - - ! if (a == 0._r8) then - ! write (fates_log(),*) 'Quadratic solution error: a = ',a - ! call endrun(msg=errMsg(sourcefile, __LINE__)) - ! end if - - if (b >= 0._r8) then - q = -0.5_r8 * (b + sqrt(b*b - 4._r8*a*c)) - else - q = -0.5_r8 * (b - sqrt(b*b - 4._r8*a*c)) - end if - - r1 = q / a - ! if (q /= 0._r8) then - r2 = c / q - ! else - ! r2 = 1.e36_r8 - ! end if - -end subroutine quadratic_fast - - -! ==================================================================================== - -subroutine UpdateCanopyNCanNRadPresent(currentPatch) - - ! --------------------------------------------------------------------------------- - ! This subroutine calculates two patch level quanities: - ! currentPatch%ncan and - ! currentPatch%canopy_mask - ! - ! currentPatch%ncan(:,:) is a two dimensional array that indicates - ! the total number of leaf layers (including those that are not exposed to light) - ! in each canopy layer and for each functional type. - ! - ! currentPatch%nrad(:,:) is a two dimensional array that indicates - ! the total number of EXPOSED leaf layers, but for all intents and purposes - ! in the photosynthesis routine, this appears to be the same as %ncan... - ! - ! currentPatch%canopy_mask(:,:) has the same dimensions, is binary, and - ! indicates whether or not leaf layers are present (by evaluating the canopy area - ! profile). - ! --------------------------------------------------------------------------------- - - ! Arguments - type(fates_patch_type), target :: currentPatch - type(fates_cohort_type), pointer :: currentCohort - - ! Locals - integer :: cl ! Canopy Layer Index - integer :: ft ! Function Type Index - integer :: iv ! index of the exposed leaf layer for each canopy layer and pft - - ! Loop through the cohorts in this patch, associate each cohort with a layer and PFT - ! and use the cohort's memory of how many layer's it takes up to assign the maximum - ! of the layer/pft index it is in - ! --------------------------------------------------------------------------------- - - currentPatch%ncan(:,:) = 0 - ! redo the canopy structure algorithm to get round a - ! bug that is happening for site 125, FT13. - currentCohort => currentPatch%tallest - do while(associated(currentCohort)) - - currentPatch%ncan(currentCohort%canopy_layer,currentCohort%pft) = & - max(currentPatch%ncan(currentCohort%canopy_layer,currentCohort%pft), & - currentCohort%NV) - - currentCohort => currentCohort%shorter - - enddo !cohort - - ! NRAD = NCAN ... - currentPatch%nrad = currentPatch%ncan - - ! Now loop through and identify which layer and pft combo has scattering elements - do cl = 1,nclmax - do ft = 1,numpft - currentPatch%canopy_mask(cl,ft) = 0 - do iv = 1, currentPatch%nrad(cl,ft); - if(currentPatch%canopy_area_profile(cl,ft,iv) > 0._r8)then - currentPatch%canopy_mask(cl,ft) = 1 - end if - end do !iv - enddo !ft - enddo !cl + ! Locals + integer :: cl ! Canopy Layer Index + integer :: ft ! Function Type Index + integer :: iv ! index of the exposed leaf layer for each canopy layer and pft - return -end subroutine UpdateCanopyNCanNRadPresent - -! ==================================================================================== - -subroutine GetCanopyGasParameters(can_press, & - can_o2_partialpress, & - veg_tempk, & - air_tempk, & - air_vpress, & - veg_esat, & - rb, & - mm_kco2, & - mm_ko2, & - co2_cpoint, & - cf, & - gb_mol, & - ceair) - - ! --------------------------------------------------------------------------------- - ! This subroutine calculates the specific Michaelis Menten Parameters (pa) for CO2 - ! and O2, as well as the CO2 compentation point. - ! --------------------------------------------------------------------------------- - - use FatesConstantsMod, only: umol_per_mol - use FatesConstantsMod, only: mmol_per_mol - use FatesConstantsMod, only: umol_per_kmol - use FatesConstantsMod, only : rgas => rgas_J_K_kmol - - ! Arguments - real(r8), intent(in) :: can_press ! Air pressure within the canopy (Pa) - real(r8), intent(in) :: can_o2_partialpress ! Partial press of o2 in the canopy (Pa) - real(r8), intent(in) :: veg_tempk ! The temperature of the vegetation (K) - real(r8), intent(in) :: air_tempk ! Temperature of canopy air (K) - real(r8), intent(in) :: air_vpress ! Vapor pressure of canopy air (Pa) - real(r8), intent(in) :: veg_esat ! Saturated vapor pressure at veg surf (Pa) - real(r8), intent(in) :: rb ! Leaf Boundary layer resistance (s/m) - - real(r8), intent(out) :: mm_kco2 ! Michaelis-Menten constant for CO2 (Pa) - real(r8), intent(out) :: mm_ko2 ! Michaelis-Menten constant for O2 (Pa) - real(r8), intent(out) :: co2_cpoint ! CO2 compensation point (Pa) - real(r8), intent(out) :: cf ! conversion factor between molar form and velocity form - ! of conductance and resistance: [umol/m3] - real(r8), intent(out) :: gb_mol ! leaf boundary layer conductance (umol H2O/m**2/s) - real(r8), intent(out) :: ceair ! vapor pressure of air, constrained (Pa) - - ! Locals - real(r8) :: kc25 ! Michaelis-Menten constant for CO2 at 25C (Pa) - real(r8) :: ko25 ! Michaelis-Menten constant for O2 at 25C (Pa) - real(r8) :: sco ! relative specificity of rubisco - real(r8) :: cp25 ! CO2 compensation point at 25C (Pa) - - ! --------------------------------------------------------------------------------- - ! Intensive values (per mol of air) - ! kc, ko, currentPatch, from: Bernacchi et al (2001) - ! Plant, Cell and Environment 24:253-259 - ! --------------------------------------------------------------------------------- - - real(r8), parameter :: mm_kc25_umol_per_mol = 404.9_r8 - real(r8), parameter :: mm_ko25_mmol_per_mol = 278.4_r8 - real(r8), parameter :: co2_cpoint_umol_per_mol = 42.75_r8 - - ! Activation energy, from: - ! Bernacchi et al (2001) Plant, Cell and Environment 24:253-259 - ! Bernacchi et al (2003) Plant, Cell and Environment 26:1419-1430 - - real(r8), parameter :: kcha = 79430._r8 ! activation energy for kc (J/mol) - real(r8), parameter :: koha = 36380._r8 ! activation energy for ko (J/mol) - real(r8), parameter :: cpha = 37830._r8 ! activation energy for cp (J/mol) - - - ! Derive sco from currentPatch and O2 using present-day O2 (0.209 mol/mol) and re-calculate - ! currentPatch to account for variation in O2 using currentPatch = 0.5 O2 / sco - - ! FIXME (RGK 11-30-2016 THere are more constants here, but I don't have enough information - ! about what they are or do, so I can't give them more descriptive names. Someone please - ! fill this in when possible) - - kc25 = ( mm_kc25_umol_per_mol / umol_per_mol ) * can_press - ko25 = ( mm_ko25_mmol_per_mol / mmol_per_mol ) * can_press - sco = 0.5_r8 * 0.209_r8 / (co2_cpoint_umol_per_mol / umol_per_mol ) - cp25 = 0.5_r8 * can_o2_partialpress / sco - - if( veg_tempk.gt.150_r8 .and. veg_tempk.lt.350_r8 )then - mm_kco2 = kc25 * ft1_f(veg_tempk, kcha) - mm_ko2 = ko25 * ft1_f(veg_tempk, koha) - co2_cpoint = cp25 * ft1_f(veg_tempk, cpha) - else - mm_kco2 = 1.0_r8 - mm_ko2 = 1.0_r8 - co2_cpoint = 1.0_r8 - end if - - ! --------------------------------------------------------------------------------- - ! - ! cf is the conversion factor between molar form and velocity form - ! of conductance and resistance: [umol/m3] - ! - ! i.e. - ! [m/s] * [umol/m3] -> [umol/m2/s] - ! - ! Breakdown of the conversion factor: [ umol / m3 ] - ! - ! Rgas [J /K /kmol] - ! Air Potential Temperature [ K ] - ! Canopy Pressure [ Pa ] - ! conversion: umol/kmol = 1e9 - ! - ! [ Pa * K * kmol umol/kmol / J K ] = [ Pa * umol / J ] - ! since: 1 Pa = 1 N / m2 - ! [ Pa * umol / J ] = [ N * umol / J m2 ] - ! since: 1 J = 1 N * m - ! [ N * umol / J m2 ] = [ N * umol / N m3 ] - ! [ umol / m3 ] - ! - ! -------------------------------------------------------------------------------- - - cf = can_press/(rgas * air_tempk )*umol_per_kmol - gb_mol = (1._r8/ rb) * cf - - ! Constrain eair >= 0.05*esat_tv so that solution does not blow up. This ensures - ! that hs does not go to zero. Also eair <= veg_esat so that hs <= 1 - ceair = min( max(air_vpress, 0.05_r8*veg_esat ),veg_esat ) + ! Loop through the cohorts in this patch, associate each cohort with a layer and PFT + ! and use the cohort's memory of how many layer's it takes up to assign the maximum + ! of the layer/pft index it is in + ! --------------------------------------------------------------------------------- + currentPatch%ncan(:,:) = 0 + ! redo the canopy structure algorithm to get round a + ! bug that is happening for site 125, FT13. + currentCohort => currentPatch%tallest + do while(associated(currentCohort)) + currentPatch%ncan(currentCohort%canopy_layer,currentCohort%pft) = & + max(currentPatch%ncan(currentCohort%canopy_layer,currentCohort%pft), & + currentCohort%NV) - return -end subroutine GetCanopyGasParameters - -! ==================================================================================== - -subroutine LeafLayerMaintenanceRespiration_Ryan_1991(lnc_top, & - nscaler, & - ft, & - veg_tempk, & - lmr) - - use FatesConstantsMod, only : tfrz => t_water_freeze_k_1atm - use FatesConstantsMod, only : umolC_to_kgC - use FatesConstantsMod, only : g_per_kg - use EDPftvarcon , only : EDPftvarcon_inst - - ! ----------------------------------------------------------------------- - ! Base maintenance respiration rate for plant tissues maintresp_leaf_ryan1991_baserate - ! M. Ryan, 1991. Effects of climate change on plant respiration. - ! Ecological Applications, 1(2), 157-167. - ! Original expression is br = 0.0106 molC/(molN h) - ! Conversion by molecular weights of C and N gives 2.525e-6 gC/(gN s) - ! Which is the default value of maintresp_nonleaf_baserate - - ! Arguments - real(r8), intent(in) :: lnc_top ! Leaf nitrogen content per unit area at canopy top [gN/m2] - real(r8), intent(in) :: nscaler ! Scale for leaf nitrogen profile - integer, intent(in) :: ft ! (plant) Functional Type Index - real(r8), intent(in) :: veg_tempk ! vegetation temperature - real(r8), intent(out) :: lmr ! Leaf Maintenance Respiration (umol CO2/m**2/s) - - ! Locals - real(r8) :: lmr25 ! leaf layer: leaf maintenance respiration rate at 25C (umol CO2/m**2/s) - real(r8) :: lmr25top ! canopy top leaf maint resp rate at 25C for this pft (umol CO2/m**2/s) - integer :: c3c4_path_index ! Index for which photosynthetic pathway - - ! Parameter - real(r8), parameter :: lmrha = 46390._r8 ! activation energy for lmr (J/mol) - real(r8), parameter :: lmrhd = 150650._r8 ! deactivation energy for lmr (J/mol) - real(r8), parameter :: lmrse = 490._r8 ! entropy term for lmr (J/mol/K) - real(r8), parameter :: lmrc = 1.15912391_r8 ! scaling factor for high - ! temperature inhibition (25 C = 1.0) + currentCohort => currentCohort%shorter - lmr25top = EDPftvarcon_inst%maintresp_leaf_ryan1991_baserate(ft) * (1.5_r8 ** ((25._r8 - 20._r8)/10._r8)) - lmr25top = lmr25top * lnc_top / (umolC_to_kgC * g_per_kg) + enddo !cohort + ! NRAD = NCAN ... + currentPatch%nrad = currentPatch%ncan - ! Part I: Leaf Maintenance respiration: umol CO2 / m**2 [leaf] / s - ! ---------------------------------------------------------------------------------- - lmr25 = lmr25top * nscaler + ! Now loop through and identify which layer and pft combo has scattering elements + do cl = 1,nclmax + do ft = 1,numpft + currentPatch%canopy_mask(cl,ft) = 0 + do iv = 1, currentPatch%nrad(cl,ft); + if(currentPatch%canopy_area_profile(cl,ft,iv) > 0._r8)then + currentPatch%canopy_mask(cl,ft) = 1 + end if + end do !iv + enddo !ft + enddo !cl + + return + end subroutine UpdateCanopyNCanNRadPresent + + ! ==================================================================================== + + subroutine GetCanopyGasParameters(can_press, & + can_o2_partialpress, & + veg_tempk, & + air_tempk, & + air_vpress, & + veg_esat, & + rb, & + mm_kco2, & + mm_ko2, & + co2_cpoint, & + cf, & + gb_mol, & + ceair) + + ! --------------------------------------------------------------------------------- + ! This subroutine calculates the specific Michaelis Menten Parameters (pa) for CO2 + ! and O2, as well as the CO2 compentation point. + ! --------------------------------------------------------------------------------- + + use FatesConstantsMod, only: umol_per_mol + use FatesConstantsMod, only: mmol_per_mol + use FatesConstantsMod, only: umol_per_kmol + use FatesConstantsMod, only : rgas => rgas_J_K_kmol - ! photosynthetic pathway: 0. = c4, 1. = c3 - c3c4_path_index = nint(EDPftvarcon_inst%c3psn(ft)) - - if (c3c4_path_index == c3_path_index) then - ! temperature sensitivity of C3 plants - lmr = lmr25 * ft1_f(veg_tempk, lmrha) * & - fth_f(veg_tempk, lmrhd, lmrse, lmrc) - else - ! temperature sensitivity of C4 plants - lmr = lmr25 * 2._r8**((veg_tempk-(tfrz+25._r8))/10._r8) - lmr = lmr / (1._r8 + exp( 1.3_r8*(veg_tempk-(tfrz+55._r8)) )) - endif - - ! Any hydrodynamic limitations could go here, currently none - ! lmr = lmr * (nothing) - -end subroutine LeafLayerMaintenanceRespiration_Ryan_1991 - -! ==================================================================================== - -subroutine LeafLayerMaintenanceRespiration_Atkin_etal_2017(lnc_top, & - nscaler, & - ft, & - veg_tempk, & - tgrowth, & - lmr) - - use FatesConstantsMod, only : tfrz => t_water_freeze_k_1atm - use FatesConstantsMod, only : umolC_to_kgC - use FatesConstantsMod, only : g_per_kg - use FatesConstantsMod, only : lmr_b - use FatesConstantsMod, only : lmr_c - use FatesConstantsMod, only : lmr_TrefC - use FatesConstantsMod, only : lmr_r_1 - use FatesConstantsMod, only : lmr_r_2 - use EDPftvarcon , only : EDPftvarcon_inst - - ! Arguments - real(r8), intent(in) :: lnc_top ! Leaf nitrogen content per unit area at canopy top [gN/m2] - integer, intent(in) :: ft ! (plant) Functional Type Index - real(r8), intent(in) :: nscaler ! Scale for leaf nitrogen profile - real(r8), intent(in) :: veg_tempk ! vegetation temperature (degrees K) - real(r8), intent(in) :: tgrowth ! lagged vegetation temperature averaged over acclimation timescale (degrees K) - real(r8), intent(out) :: lmr ! Leaf Maintenance Respiration (umol CO2/m**2/s) - - ! Locals - real(r8) :: lmr25 ! leaf layer: leaf maintenance respiration rate at 25C (umol CO2/m**2/s) - real(r8) :: r_0 ! base respiration rate, PFT-dependent (umol CO2/m**2/s) - real(r8) :: r_t_ref ! acclimated ref respiration rate (umol CO2/m**2/s) - real(r8) :: lmr25top ! canopy top leaf maint resp rate at 25C for this pft (umol CO2/m**2/s) - - ! parameter values of r_0 as listed in Atkin et al 2017: (umol CO2/m**2/s) - ! Broad-leaved trees 1.7560 - ! Needle-leaf trees 1.4995 - ! Shrubs 2.0749 - ! C3 herbs/grasses 2.1956 - ! In the absence of better information, we use the same value for C4 grasses as C3 grasses. - - ! note that this code uses the relationship between leaf N and respiration from Atkin et al - ! for the top of the canopy, but then assumes proportionality with N through the canopy. - - ! r_0 currently put into the EDPftvarcon_inst%dev_arbitrary_pft - ! all figs in Atkin et al 2017 stop at zero Celsius so we will assume acclimation is fixed below that - r_0 = EDPftvarcon_inst%maintresp_leaf_atkin2017_baserate(ft) - r_t_ref = max( 0._r8, nscaler * (r_0 + lmr_r_1 * lnc_top + lmr_r_2 * max(0._r8, (tgrowth - tfrz) )) ) - - if (r_t_ref .eq. 0._r8) then - warn_msg = 'Rdark is negative at this temperature and is capped at 0. tgrowth (C): '//trim(N2S(tgrowth-tfrz))//' pft: '//trim(I2S(ft)) - call FatesWarn(warn_msg,index=4) - end if - - lmr = r_t_ref * exp(lmr_b * (veg_tempk - tfrz - lmr_TrefC) + lmr_c * & - ((veg_tempk-tfrz)**2 - lmr_TrefC**2)) - -end subroutine LeafLayerMaintenanceRespiration_Atkin_etal_2017 - -! ==================================================================================== - -subroutine LeafLayerBiophysicalRates( parsun_lsl, & - ft, & - vcmax25top_ft, & - jmax25top_ft, & - co2_rcurve_islope25top_ft, & - nscaler, & - veg_tempk, & - t_growth, & - t_home, & - btran, & - vcmax, & - jmax, & - co2_rcurve_islope ) - - ! --------------------------------------------------------------------------------- - ! This subroutine calculates the localized rates of several key photosynthesis - ! rates. By localized, we mean specific to the plant type and leaf layer, - ! which factors in leaf physiology, as well as environmental effects. - ! This procedure should be called prior to iterative solvers, and should - ! have pre-calculated the reference rates for the pfts before this. - ! - ! The output biophysical rates are: - ! vcmax: maximum rate of carboxilation, - ! jmax: maximum electron transport rate, - ! co2_rcurve_islope: initial slope of CO2 response curve (C4 plants) - ! --------------------------------------------------------------------------------- - - use EDPftvarcon , only : EDPftvarcon_inst - - ! Arguments - ! ------------------------------------------------------------------------------ - - real(r8), intent(in) :: parsun_lsl ! PAR absorbed in sunlit leaves for this layer - integer, intent(in) :: ft ! (plant) Functional Type Index - real(r8), intent(in) :: nscaler ! Scale for leaf nitrogen profile - real(r8), intent(in) :: vcmax25top_ft ! canopy top maximum rate of carboxylation at 25C - ! for this pft (umol CO2/m**2/s) - real(r8), intent(in) :: jmax25top_ft ! canopy top maximum electron transport rate at 25C - ! for this pft (umol electrons/m**2/s) - real(r8), intent(in) :: co2_rcurve_islope25top_ft ! initial slope of CO2 response curve - ! (C4 plants) at 25C, canopy top, this pft - real(r8), intent(in) :: veg_tempk ! vegetation temperature - real(r8), intent(in) :: t_growth ! T_growth (short-term running mean temperature) (K) - real(r8), intent(in) :: t_home ! T_home (long-term running mean temperature) (K) - real(r8), intent(in) :: btran ! transpiration wetness factor (0 to 1) - - real(r8), intent(out) :: vcmax ! maximum rate of carboxylation (umol co2/m**2/s) - real(r8), intent(out) :: jmax ! maximum electron transport rate - ! (umol electrons/m**2/s) - real(r8), intent(out) :: co2_rcurve_islope ! initial slope of CO2 response curve (C4 plants) - - ! Locals - ! ------------------------------------------------------------------------------- - real(r8) :: vcmax25 ! leaf layer: maximum rate of carboxylation at 25C - ! (umol CO2/m**2/s) - real(r8) :: jmax25 ! leaf layer: maximum electron transport rate at 25C - ! (umol electrons/m**2/s) - real(r8) :: co2_rcurve_islope25 ! leaf layer: Initial slope of CO2 response curve - ! (C4 plants) at 25C - integer :: c3c4_path_index ! Index for which photosynthetic pathway - - ! Parameters - ! --------------------------------------------------------------------------------- - real(r8) :: vcmaxha ! activation energy for vcmax (J/mol) - real(r8) :: jmaxha ! activation energy for jmax (J/mol) - real(r8) :: vcmaxhd ! deactivation energy for vcmax (J/mol) - real(r8) :: jmaxhd ! deactivation energy for jmax (J/mol) - real(r8) :: vcmaxse ! entropy term for vcmax (J/mol/K) - real(r8) :: jmaxse ! entropy term for jmax (J/mol/K) - real(r8) :: t_growth_celsius ! average growing temperature - real(r8) :: t_home_celsius ! average home temperature - real(r8) :: jvr ! ratio of Jmax25 / Vcmax25 - real(r8) :: vcmaxc ! scaling factor for high temperature inhibition (25 C = 1.0) - real(r8) :: jmaxc ! scaling factor for high temperature inhibition (25 C = 1.0) - - select case(photo_tempsens_model) - case (photosynth_acclim_model_none) !No temperature acclimation - vcmaxha = EDPftvarcon_inst%vcmaxha(FT) - jmaxha = EDPftvarcon_inst%jmaxha(FT) - vcmaxhd = EDPftvarcon_inst%vcmaxhd(FT) - jmaxhd = EDPftvarcon_inst%jmaxhd(FT) - vcmaxse = EDPftvarcon_inst%vcmaxse(FT) - jmaxse = EDPftvarcon_inst%jmaxse(FT) - case (photosynth_acclim_model_kumarathunge_etal_2019) !Kumarathunge et al. temperature acclimation, Thome=30-year running mean - t_growth_celsius = t_growth-tfrz - t_home_celsius = t_home-tfrz - vcmaxha = (42.6_r8 + (1.14_r8*t_growth_celsius))*1e3_r8 !J/mol - jmaxha = 40.71_r8*1e3_r8 !J/mol - vcmaxhd = 200._r8*1e3_r8 !J/mol - jmaxhd = 200._r8*1e3_r8 !J/mol - vcmaxse = (645.13_r8 - (0.38_r8*t_growth_celsius)) - jmaxse = 658.77_r8 - (0.84_r8*t_home_celsius) - 0.52_r8*(t_growth_celsius-t_home_celsius) - jvr = 2.56_r8 - (0.0375_r8*t_home_celsius)-(0.0202_r8*(t_growth_celsius-t_home_celsius)) - case default - write (fates_log(),*)'error, incorrect leaf photosynthesis temperature acclimation model specified' - call endrun(msg=errMsg(sourcefile, __LINE__)) - end select - - vcmaxc = fth25_f(vcmaxhd, vcmaxse) - jmaxc = fth25_f(jmaxhd, jmaxse) - - if ( parsun_lsl <= 0._r8) then ! night time - vcmax = 0._r8 - jmax = 0._r8 - co2_rcurve_islope = 0._r8 - else ! day time - - ! Vcmax25top was already calculated to derive the nscaler function - vcmax25 = vcmax25top_ft * nscaler - select case(photo_tempsens_model) - case (photosynth_acclim_model_none) - jmax25 = jmax25top_ft * nscaler - case (photosynth_acclim_model_kumarathunge_etal_2019) - jmax25 = vcmax25*jvr - case default - write (fates_log(),*)'error, incorrect leaf photosynthesis temperature acclimation model specified' - call endrun(msg=errMsg(sourcefile, __LINE__)) - end select - - co2_rcurve_islope25 = co2_rcurve_islope25top_ft * nscaler - - ! Adjust for temperature - ! photosynthetic pathway: 0. = c4, 1. = c3 - c3c4_path_index = nint(EDPftvarcon_inst%c3psn(ft)) - - if (c3c4_path_index == c3_path_index) then - vcmax = vcmax25 * ft1_f(veg_tempk, vcmaxha) * fth_f(veg_tempk, vcmaxhd, vcmaxse, vcmaxc) - else - vcmax = vcmax25 * 2._r8**((veg_tempk-(tfrz+25._r8))/10._r8) - vcmax = vcmax / (1._r8 + exp( 0.2_r8*((tfrz+15._r8)-veg_tempk ) )) - vcmax = vcmax / (1._r8 + exp( 0.3_r8*(veg_tempk-(tfrz+40._r8)) )) - end if - - jmax = jmax25 * ft1_f(veg_tempk, jmaxha) * fth_f(veg_tempk, jmaxhd, jmaxse, jmaxc) - - !q10 response of product limited psn. - co2_rcurve_islope = co2_rcurve_islope25 * 2._r8**((veg_tempk-(tfrz+25._r8))/10._r8) - end if + ! Arguments + real(r8), intent(in) :: can_press ! Air pressure within the canopy (Pa) + real(r8), intent(in) :: can_o2_partialpress ! Partial press of o2 in the canopy (Pa) + real(r8), intent(in) :: veg_tempk ! The temperature of the vegetation (K) + real(r8), intent(in) :: air_tempk ! Temperature of canopy air (K) + real(r8), intent(in) :: air_vpress ! Vapor pressure of canopy air (Pa) + real(r8), intent(in) :: veg_esat ! Saturated vapor pressure at veg surf (Pa) + real(r8), intent(in) :: rb ! Leaf Boundary layer resistance (s/m) + + real(r8), intent(out) :: mm_kco2 ! Michaelis-Menten constant for CO2 (Pa) + real(r8), intent(out) :: mm_ko2 ! Michaelis-Menten constant for O2 (Pa) + real(r8), intent(out) :: co2_cpoint ! CO2 compensation point (Pa) + real(r8), intent(out) :: cf ! conversion factor between molar form and velocity form + ! of conductance and resistance: [umol/m3] + real(r8), intent(out) :: gb_mol ! leaf boundary layer conductance (umol H2O/m**2/s) + real(r8), intent(out) :: ceair ! vapor pressure of air, constrained (Pa) + + ! Locals + real(r8) :: kc25 ! Michaelis-Menten constant for CO2 at 25C (Pa) + real(r8) :: ko25 ! Michaelis-Menten constant for O2 at 25C (Pa) + real(r8) :: sco ! relative specificity of rubisco + real(r8) :: cp25 ! CO2 compensation point at 25C (Pa) + + ! --------------------------------------------------------------------------------- + ! Intensive values (per mol of air) + ! kc, ko, currentPatch, from: Bernacchi et al (2001) + ! Plant, Cell and Environment 24:253-259 + ! --------------------------------------------------------------------------------- + + real(r8), parameter :: mm_kc25_umol_per_mol = 404.9_r8 + real(r8), parameter :: mm_ko25_mmol_per_mol = 278.4_r8 + real(r8), parameter :: co2_cpoint_umol_per_mol = 42.75_r8 + + ! Activation energy, from: + ! Bernacchi et al (2001) Plant, Cell and Environment 24:253-259 + ! Bernacchi et al (2003) Plant, Cell and Environment 26:1419-1430 + + real(r8), parameter :: kcha = 79430._r8 ! activation energy for kc (J/mol) + real(r8), parameter :: koha = 36380._r8 ! activation energy for ko (J/mol) + real(r8), parameter :: cpha = 37830._r8 ! activation energy for cp (J/mol) + + + ! Derive sco from currentPatch and O2 using present-day O2 (0.209 mol/mol) and re-calculate + ! currentPatch to account for variation in O2 using currentPatch = 0.5 O2 / sco + + ! FIXME (RGK 11-30-2016 THere are more constants here, but I don't have enough information + ! about what they are or do, so I can't give them more descriptive names. Someone please + ! fill this in when possible) + + kc25 = ( mm_kc25_umol_per_mol / umol_per_mol ) * can_press + ko25 = ( mm_ko25_mmol_per_mol / mmol_per_mol ) * can_press + sco = 0.5_r8 * 0.209_r8 / (co2_cpoint_umol_per_mol / umol_per_mol ) + cp25 = 0.5_r8 * can_o2_partialpress / sco + + if( veg_tempk.gt.150_r8 .and. veg_tempk.lt.350_r8 )then + mm_kco2 = kc25 * ft1_f(veg_tempk, kcha) + mm_ko2 = ko25 * ft1_f(veg_tempk, koha) + co2_cpoint = cp25 * ft1_f(veg_tempk, cpha) + else + mm_kco2 = 1.0_r8 + mm_ko2 = 1.0_r8 + co2_cpoint = 1.0_r8 + end if + + ! --------------------------------------------------------------------------------- + ! + ! cf is the conversion factor between molar form and velocity form + ! of conductance and resistance: [umol/m3] + ! + ! i.e. + ! [m/s] * [umol/m3] -> [umol/m2/s] + ! + ! Breakdown of the conversion factor: [ umol / m3 ] + ! + ! Rgas [J /K /kmol] + ! Air Potential Temperature [ K ] + ! Canopy Pressure [ Pa ] + ! conversion: umol/kmol = 1e9 + ! + ! [ Pa * K * kmol umol/kmol / J K ] = [ Pa * umol / J ] + ! since: 1 Pa = 1 N / m2 + ! [ Pa * umol / J ] = [ N * umol / J m2 ] + ! since: 1 J = 1 N * m + ! [ N * umol / J m2 ] = [ N * umol / N m3 ] + ! [ umol / m3 ] + ! + ! -------------------------------------------------------------------------------- - ! Adjust for water limitations - vcmax = vcmax * btran + cf = can_press/(rgas * air_tempk )*umol_per_kmol + gb_mol = (1._r8/ rb) * cf - return + ! Constrain eair >= 0.05*esat_tv so that solution does not blow up. This ensures + ! that hs does not go to zero. Also eair <= veg_esat so that hs <= 1 + ceair = min( max(air_vpress, 0.05_r8*veg_esat ),veg_esat ) + + + + return + end subroutine GetCanopyGasParameters + + ! ==================================================================================== + + subroutine LeafLayerMaintenanceRespiration_Ryan_1991(lnc_top, & + nscaler, & + ft, & + veg_tempk, & + lmr) + + use FatesConstantsMod, only : tfrz => t_water_freeze_k_1atm + use FatesConstantsMod, only : umolC_to_kgC + use FatesConstantsMod, only : g_per_kg + use EDPftvarcon , only : EDPftvarcon_inst + + ! ----------------------------------------------------------------------- + ! Base maintenance respiration rate for plant tissues maintresp_leaf_ryan1991_baserate + ! M. Ryan, 1991. Effects of climate change on plant respiration. + ! Ecological Applications, 1(2), 157-167. + ! Original expression is br = 0.0106 molC/(molN h) + ! Conversion by molecular weights of C and N gives 2.525e-6 gC/(gN s) + ! Which is the default value of maintresp_nonleaf_baserate + + ! Arguments + real(r8), intent(in) :: lnc_top ! Leaf nitrogen content per unit area at canopy top [gN/m2] + real(r8), intent(in) :: nscaler ! Scale for leaf nitrogen profile + integer, intent(in) :: ft ! (plant) Functional Type Index + real(r8), intent(in) :: veg_tempk ! vegetation temperature + real(r8), intent(out) :: lmr ! Leaf Maintenance Respiration (umol CO2/m**2/s) + + ! Locals + real(r8) :: lmr25 ! leaf layer: leaf maintenance respiration rate at 25C (umol CO2/m**2/s) + real(r8) :: lmr25top ! canopy top leaf maint resp rate at 25C for this pft (umol CO2/m**2/s) + integer :: c3c4_path_index ! Index for which photosynthetic pathway + + ! Parameter + real(r8), parameter :: lmrha = 46390._r8 ! activation energy for lmr (J/mol) + real(r8), parameter :: lmrhd = 150650._r8 ! deactivation energy for lmr (J/mol) + real(r8), parameter :: lmrse = 490._r8 ! entropy term for lmr (J/mol/K) + real(r8), parameter :: lmrc = 1.15912391_r8 ! scaling factor for high + ! temperature inhibition (25 C = 1.0) + + lmr25top = EDPftvarcon_inst%maintresp_leaf_ryan1991_baserate(ft) * (1.5_r8 ** ((25._r8 - 20._r8)/10._r8)) + lmr25top = lmr25top * lnc_top / (umolC_to_kgC * g_per_kg) + + + ! Part I: Leaf Maintenance respiration: umol CO2 / m**2 [leaf] / s + ! ---------------------------------------------------------------------------------- + lmr25 = lmr25top * nscaler + + ! photosynthetic pathway: 0. = c4, 1. = c3 + c3c4_path_index = nint(EDPftvarcon_inst%c3psn(ft)) + + if (c3c4_path_index == c3_path_index) then + ! temperature sensitivity of C3 plants + lmr = lmr25 * ft1_f(veg_tempk, lmrha) * & + fth_f(veg_tempk, lmrhd, lmrse, lmrc) + else + ! temperature sensitivity of C4 plants + lmr = lmr25 * 2._r8**((veg_tempk-(tfrz+25._r8))/10._r8) + lmr = lmr / (1._r8 + exp( 1.3_r8*(veg_tempk-(tfrz+55._r8)) )) + endif + + ! Any hydrodynamic limitations could go here, currently none + ! lmr = lmr * (nothing) + + end subroutine LeafLayerMaintenanceRespiration_Ryan_1991 + + ! ==================================================================================== + + subroutine LeafLayerMaintenanceRespiration_Atkin_etal_2017(lnc_top, & + cumulative_lai, & + vcmax25top, & + ft, & + veg_tempk, & + tgrowth, & + lmr) + + use FatesConstantsMod, only : tfrz => t_water_freeze_k_1atm + use FatesConstantsMod, only : umolC_to_kgC + use FatesConstantsMod, only : g_per_kg + use FatesConstantsMod, only : lmr_b + use FatesConstantsMod, only : lmr_c + use FatesConstantsMod, only : lmr_TrefC + use FatesConstantsMod, only : lmr_r_1 + use FatesConstantsMod, only : lmr_r_2 + use EDPftvarcon , only : EDPftvarcon_inst + + ! Arguments + real(r8), intent(in) :: lnc_top ! Leaf nitrogen content per unit area at canopy top [gN/m2] + integer, intent(in) :: ft ! (plant) Functional Type Index + real(r8), intent(in) :: vcmax25top ! top of canopy vcmax + real(r8), intent(in) :: cumulative_lai ! cumulative lai above the current leaf layer + real(r8), intent(in) :: veg_tempk ! vegetation temperature (degrees K) + real(r8), intent(in) :: tgrowth ! lagged vegetation temperature averaged over acclimation timescale (degrees K) + real(r8), intent(out) :: lmr ! Leaf Maintenance Respiration (umol CO2/m**2/s) + + ! Locals + real(r8) :: lmr25 ! leaf layer: leaf maintenance respiration rate at 25C (umol CO2/m**2/s) + real(r8) :: r_0 ! base respiration rate, PFT-dependent (umol CO2/m**2/s) + real(r8) :: r_t_ref ! acclimated ref respiration rate (umol CO2/m**2/s) + real(r8) :: lmr25top ! canopy top leaf maint resp rate at 25C for this pft (umol CO2/m**2/s) + + real(r8) :: rdark_scaler ! negative exponential scaling of rdark + real(r8) :: kn ! decay coefficient + + ! parameter values of r_0 as listed in Atkin et al 2017: (umol CO2/m**2/s) + ! Broad-leaved trees 1.7560 + ! Needle-leaf trees 1.4995 + ! Shrubs 2.0749 + ! C3 herbs/grasses 2.1956 + ! In the absence of better information, we use the same value for C4 grasses as C3 grasses. + + ! r_0 currently put into the EDPftvarcon_inst%dev_arbitrary_pft + ! all figs in Atkin et al 2017 stop at zero Celsius so we will assume acclimation is fixed below that + r_0 = EDPftvarcon_inst%maintresp_leaf_atkin2017_baserate(ft) + + ! This code uses the relationship between leaf N and respiration from Atkin et al + ! for the top of the canopy, but then scales through the canopy based on a rdark_scaler. + ! To assume proportionality with N through the canopy following Lloyd et al. 2010, use the + ! default parameter value of 2.43, which results in the scaling of photosynthesis and respiration + ! being proportional through the canopy. To have a steeper decrease in respiration than photosynthesis + ! this number can be smaller. There is some observational evidence for this being the case + ! in Lamour et al. 2023. + + kn = decay_coeff_vcmax(vcmax25top, & + EDPftvarcon_inst%maintresp_leaf_vert_scaler_coeff1(ft), & + EDPftvarcon_inst%maintresp_leaf_vert_scaler_coeff2(ft)) + + rdark_scaler = exp(-kn * cumulative_lai) + + r_t_ref = max(0._r8, rdark_scaler * (r_0 + lmr_r_1 * lnc_top + lmr_r_2 * max(0._r8, (tgrowth - tfrz) )) ) + + if (r_t_ref .eq. 0._r8) then + warn_msg = 'Rdark is negative at this temperature and is capped at 0. tgrowth (C): '//trim(N2S(tgrowth-tfrz))//' pft: '//trim(I2S(ft)) + call FatesWarn(warn_msg,index=4) + end if + + lmr = r_t_ref * exp(lmr_b * (veg_tempk - tfrz - lmr_TrefC) + lmr_c * & + ((veg_tempk-tfrz)**2 - lmr_TrefC**2)) + + end subroutine LeafLayerMaintenanceRespiration_Atkin_etal_2017 + + ! ==================================================================================== + + subroutine LeafLayerBiophysicalRates( parsun_per_la, & + ft, & + vcmax25top_ft, & + jmax25top_ft, & + co2_rcurve_islope25top_ft, & + nscaler, & + veg_tempk, & + dayl_factor, & + t_growth, & + t_home, & + btran, & + vcmax, & + jmax, & + co2_rcurve_islope ) + + ! --------------------------------------------------------------------------------- + ! This subroutine calculates the localized rates of several key photosynthesis + ! rates. By localized, we mean specific to the plant type and leaf layer, + ! which factors in leaf physiology, as well as environmental effects. + ! This procedure should be called prior to iterative solvers, and should + ! have pre-calculated the reference rates for the pfts before this. + ! + ! The output biophysical rates are: + ! vcmax: maximum rate of carboxilation, + ! jmax: maximum electron transport rate, + ! co2_rcurve_islope: initial slope of CO2 response curve (C4 plants) + ! --------------------------------------------------------------------------------- + + use EDPftvarcon , only : EDPftvarcon_inst + + ! Arguments + ! ------------------------------------------------------------------------------ + + real(r8), intent(in) :: parsun_per_la ! PAR absorbed per sunlit leaves for this layer + integer, intent(in) :: ft ! (plant) Functional Type Index + real(r8), intent(in) :: nscaler ! Scale for leaf nitrogen profile + real(r8), intent(in) :: vcmax25top_ft ! canopy top maximum rate of carboxylation at 25C + ! for this pft (umol CO2/m**2/s) + real(r8), intent(in) :: jmax25top_ft ! canopy top maximum electron transport rate at 25C + ! for this pft (umol electrons/m**2/s) + real(r8), intent(in) :: co2_rcurve_islope25top_ft ! initial slope of CO2 response curve + ! (C4 plants) at 25C, canopy top, this pft + real(r8), intent(in) :: veg_tempk ! vegetation temperature + real(r8), intent(in) :: dayl_factor ! daylength scaling factor (0-1) + real(r8), intent(in) :: t_growth ! T_growth (short-term running mean temperature) (K) + real(r8), intent(in) :: t_home ! T_home (long-term running mean temperature) (K) + real(r8), intent(in) :: btran ! transpiration wetness factor (0 to 1) + + real(r8), intent(out) :: vcmax ! maximum rate of carboxylation (umol co2/m**2/s) + real(r8), intent(out) :: jmax ! maximum electron transport rate + ! (umol electrons/m**2/s) + real(r8), intent(out) :: co2_rcurve_islope ! initial slope of CO2 response curve (C4 plants) + + ! Locals + ! ------------------------------------------------------------------------------- + real(r8) :: vcmax25 ! leaf layer: maximum rate of carboxylation at 25C + ! (umol CO2/m**2/s) + real(r8) :: jmax25 ! leaf layer: maximum electron transport rate at 25C + ! (umol electrons/m**2/s) + real(r8) :: co2_rcurve_islope25 ! leaf layer: Initial slope of CO2 response curve + ! (C4 plants) at 25C + integer :: c3c4_path_index ! Index for which photosynthetic pathway + real(r8) :: dayl_factor_local ! Local version of daylength factor - end subroutine LeafLayerBiophysicalRates - -subroutine lowstorage_maintresp_reduction(frac, pft, maintresp_reduction_factor) - - ! This subroutine reduces maintenance respiration rates when storage pool is low. The premise - ! of this is that mortality of plants increases when storage is low because they are not able - ! to repair tissues, generate defense compounds, etc. This reduction is reflected in a reduced - ! maintenance demand. The output of this function takes the form of a curve between 0 and 1, - ! and the curvature of the function is determined by a parameter. - - ! Uses - use EDPftvarcon , only : EDPftvarcon_inst - - ! Arguments - ! ------------------------------------------------------------------------------ - real(r8), intent(in) :: frac ! ratio of storage to target leaf biomass - integer, intent(in) :: pft ! what pft is this cohort? - real(r8), intent(out) :: maintresp_reduction_factor ! the factor by which to reduce maintenance respiration - - ! -------------------------------------------------------------------------------- - ! Parameters are at the PFT level: - ! fates_maintresp_reduction_curvature controls the curvature of this. - ! If this parameter is zero, then there is no reduction until the plant dies at storage = 0. - ! If this parameter is one, then there is a linear reduction in respiration below the storage point. - ! Intermediate values will give some (concave-downwards) curvature. - ! - ! maintresp_reduction_intercept controls the maximum amount of throttling. - ! zero means no throttling at any point, so it turns this mechanism off completely and so - ! allows an entire cohort to die via negative carbon-induced termination mortality. - ! one means complete throttling, so no maintenance respiration at all, when out of carbon. - ! --------------------------------------------------------------------------------- - - if( frac .lt. 1._r8 )then - if ( abs(EDPftvarcon_inst%maintresp_reduction_curvature(pft)-1._r8) > nearzero ) then - maintresp_reduction_factor = (1._r8 - EDPftvarcon_inst%maintresp_reduction_intercept(pft)) + & - EDPftvarcon_inst%maintresp_reduction_intercept(pft) * & - (1._r8 - EDPftvarcon_inst%maintresp_reduction_curvature(pft)**frac) & - / (1._r8-EDPftvarcon_inst%maintresp_reduction_curvature(pft)) - else ! avoid nan answer for linear case - maintresp_reduction_factor = (1._r8 - EDPftvarcon_inst%maintresp_reduction_intercept(pft)) + & - EDPftvarcon_inst%maintresp_reduction_intercept(pft) * frac - endif - - else - maintresp_reduction_factor = 1._r8 - endif - - -end subroutine lowstorage_maintresp_reduction + ! Parameters + ! --------------------------------------------------------------------------------- + real(r8) :: vcmaxha ! activation energy for vcmax (J/mol) + real(r8) :: jmaxha ! activation energy for jmax (J/mol) + real(r8) :: vcmaxhd ! deactivation energy for vcmax (J/mol) + real(r8) :: jmaxhd ! deactivation energy for jmax (J/mol) + real(r8) :: vcmaxse ! entropy term for vcmax (J/mol/K) + real(r8) :: jmaxse ! entropy term for jmax (J/mol/K) + real(r8) :: t_growth_celsius ! average growing temperature + real(r8) :: t_home_celsius ! average home temperature + real(r8) :: jvr ! ratio of Jmax25 / Vcmax25 + real(r8) :: vcmaxc ! scaling factor for high temperature inhibition (25 C = 1.0) + real(r8) :: jmaxc ! scaling factor for high temperature inhibition (25 C = 1.0) + + select case(photo_tempsens_model) + case (photosynth_acclim_model_none) !No temperature acclimation + vcmaxha = EDPftvarcon_inst%vcmaxha(FT) + jmaxha = EDPftvarcon_inst%jmaxha(FT) + vcmaxhd = EDPftvarcon_inst%vcmaxhd(FT) + jmaxhd = EDPftvarcon_inst%jmaxhd(FT) + vcmaxse = EDPftvarcon_inst%vcmaxse(FT) + jmaxse = EDPftvarcon_inst%jmaxse(FT) + case (photosynth_acclim_model_kumarathunge_etal_2019) !Kumarathunge et al. temperature acclimation, Thome=30-year running mean + t_growth_celsius = t_growth-tfrz + t_home_celsius = t_home-tfrz + vcmaxha = (42.6_r8 + (1.14_r8*t_growth_celsius))*1e3_r8 !J/mol + jmaxha = 40.71_r8*1e3_r8 !J/mol + vcmaxhd = 200._r8*1e3_r8 !J/mol + jmaxhd = 200._r8*1e3_r8 !J/mol + vcmaxse = (645.13_r8 - (0.38_r8*t_growth_celsius)) + jmaxse = 658.77_r8 - (0.84_r8*t_home_celsius) - 0.52_r8*(t_growth_celsius-t_home_celsius) + jvr = 2.56_r8 - (0.0375_r8*t_home_celsius)-(0.0202_r8*(t_growth_celsius-t_home_celsius)) + case default + write (fates_log(),*)'error, incorrect leaf photosynthesis temperature acclimation model specified' + call endrun(msg=errMsg(sourcefile, __LINE__)) + end select + + vcmaxc = fth25_f(vcmaxhd, vcmaxse) + jmaxc = fth25_f(jmaxhd, jmaxse) + + if(parsun_per_la <= 0._r8) then + vcmax = 0._r8 + jmax = 0._r8 + co2_rcurve_islope = 0._r8 + else ! day time + + ! update the daylength factor local variable if the switch is on + if ( dayl_switch == itrue ) then + dayl_factor_local = dayl_factor + else + dayl_factor_local = 1.0_r8 + endif + + ! Vcmax25top was already calculated to derive the nscaler function + vcmax25 = vcmax25top_ft * nscaler * dayl_factor_local + select case(photo_tempsens_model) + case (photosynth_acclim_model_none) + jmax25 = jmax25top_ft * nscaler * dayl_factor_local + case (photosynth_acclim_model_kumarathunge_etal_2019) + jmax25 = vcmax25*jvr + case default + write (fates_log(),*)'error, incorrect leaf photosynthesis temperature acclimation model specified' + call endrun(msg=errMsg(sourcefile, __LINE__)) + end select + + co2_rcurve_islope25 = co2_rcurve_islope25top_ft * nscaler + + ! Adjust for temperature + ! photosynthetic pathway: 0. = c4, 1. = c3 + c3c4_path_index = nint(EDPftvarcon_inst%c3psn(ft)) + + if (c3c4_path_index == c3_path_index) then + vcmax = vcmax25 * ft1_f(veg_tempk, vcmaxha) * fth_f(veg_tempk, vcmaxhd, vcmaxse, vcmaxc) + else + vcmax = vcmax25 * 2._r8**((veg_tempk-(tfrz+25._r8))/10._r8) + vcmax = vcmax / (1._r8 + exp( 0.2_r8*((tfrz+15._r8)-veg_tempk ) )) + vcmax = vcmax / (1._r8 + exp( 0.3_r8*(veg_tempk-(tfrz+40._r8)) )) + end if + + jmax = jmax25 * ft1_f(veg_tempk, jmaxha) * fth_f(veg_tempk, jmaxhd, jmaxse, jmaxc) + + !q10 response of product limited psn. + co2_rcurve_islope = co2_rcurve_islope25 * 2._r8**((veg_tempk-(tfrz+25._r8))/10._r8) + end if + + ! Adjust for water limitations + vcmax = vcmax * btran + + return + + end subroutine LeafLayerBiophysicalRates + + subroutine lowstorage_maintresp_reduction(frac, pft, maintresp_reduction_factor) + + ! This subroutine reduces maintenance respiration rates when storage pool is low. The premise + ! of this is that mortality of plants increases when storage is low because they are not able + ! to repair tissues, generate defense compounds, etc. This reduction is reflected in a reduced + ! maintenance demand. The output of this function takes the form of a curve between 0 and 1, + ! and the curvature of the function is determined by a parameter. + + ! Uses + use EDPftvarcon , only : EDPftvarcon_inst + + ! Arguments + ! ------------------------------------------------------------------------------ + real(r8), intent(in) :: frac ! ratio of storage to target leaf biomass + integer, intent(in) :: pft ! what pft is this cohort? + real(r8), intent(out) :: maintresp_reduction_factor ! the factor by which to reduce maintenance respiration + + ! -------------------------------------------------------------------------------- + ! Parameters are at the PFT level: + ! fates_maintresp_reduction_curvature controls the curvature of this. + ! If this parameter is zero, then there is no reduction until the plant dies at storage = 0. + ! If this parameter is one, then there is a linear reduction in respiration below the storage point. + ! Intermediate values will give some (concave-downwards) curvature. + ! + ! maintresp_reduction_intercept controls the maximum amount of throttling. + ! zero means no throttling at any point, so it turns this mechanism off completely and so + ! allows an entire cohort to die via negative carbon-induced termination mortality. + ! one means complete throttling, so no maintenance respiration at all, when out of carbon. + ! --------------------------------------------------------------------------------- + + if( frac .lt. 1._r8 )then + if ( abs(EDPftvarcon_inst%maintresp_reduction_curvature(pft)-1._r8) > nearzero ) then + maintresp_reduction_factor = (1._r8 - EDPftvarcon_inst%maintresp_reduction_intercept(pft)) + & + EDPftvarcon_inst%maintresp_reduction_intercept(pft) * & + (1._r8 - EDPftvarcon_inst%maintresp_reduction_curvature(pft)**frac) & + / (1._r8-EDPftvarcon_inst%maintresp_reduction_curvature(pft)) + else ! avoid nan answer for linear case + maintresp_reduction_factor = (1._r8 - EDPftvarcon_inst%maintresp_reduction_intercept(pft)) + & + EDPftvarcon_inst%maintresp_reduction_intercept(pft) * frac + endif + + else + maintresp_reduction_factor = 1._r8 + endif + + + end subroutine lowstorage_maintresp_reduction end module FATESPlantRespPhotosynthMod diff --git a/fire/CMakeLists.txt b/fire/CMakeLists.txt new file mode 100644 index 0000000000..341065c3c3 --- /dev/null +++ b/fire/CMakeLists.txt @@ -0,0 +1,8 @@ +# This file is required for unit testing, but is not used for production runs +list(APPEND fates_sources + SFParamsMod.F90 + SFFireWeatherMod.F90 + SFNesterovMod.F90 + ) + +sourcelist_to_parent(fates_sources) diff --git a/fire/SFFireWeatherMod.F90 b/fire/SFFireWeatherMod.F90 new file mode 100644 index 0000000000..e39834ad1e --- /dev/null +++ b/fire/SFFireWeatherMod.F90 @@ -0,0 +1,32 @@ +module SFFireWeatherMod + + use FatesConstantsMod, only : r8 => fates_r8 + + implicit none + private + + type, abstract, public :: fire_weather + real(r8) :: fire_weather_index ! fire weather index + contains + procedure(initialize_fire_weather), public, deferred :: Init + procedure(update_fire_weather), public, deferred :: Update + end type fire_weather + + abstract interface + subroutine initialize_fire_weather(this) + import :: fire_weather + class(fire_weather), intent(inout) :: this + end subroutine initialize_fire_weather + + subroutine update_fire_weather(this, temp_C, precip, rh, wind) + use FatesConstantsMod, only : r8 => fates_r8 + import :: fire_weather + class(fire_weather), intent(inout) :: this + real(r8), intent(in) :: temp_C + real(r8), intent(in) :: precip + real(r8), intent(in) :: rh + real(r8), intent(in) :: wind + end subroutine update_fire_weather + end interface + +end module SFFireWeatherMod \ No newline at end of file diff --git a/fire/SFMainMod.F90 b/fire/SFMainMod.F90 index ef245b04f9..f1e7de14ea 100644 --- a/fire/SFMainMod.F90 +++ b/fire/SFMainMod.F90 @@ -1,7 +1,7 @@ module SFMainMod ! ============================================================================ - ! All subroutines realted to the SPITFIRE fire routine. + ! All subroutines related to the SPITFIRE fire routine. ! Code originally developed by Allan Spessa & Rosie Fisher as part of the NERC-QUEST project. ! ============================================================================ @@ -47,12 +47,12 @@ module SFMainMod use PRTGenericMod, only : SetState use FatesInterfaceTypesMod , only : numpft use FatesAllometryMod, only : CrownDepth + use FatesConstantsMod, only : nearzero implicit none private public :: fire_model - public :: fire_danger_index public :: charecteristics_of_fuel public :: rate_of_spread public :: ground_fuel_consumption @@ -69,79 +69,71 @@ module SFMainMod integer :: write_SF = ifalse ! for debugging logical :: debug = .false. ! for debugging - ! ============================================================================ - ! ============================================================================ + ! ====================================================================================== contains - ! ============================================================================ - ! Area of site burned by fire - ! ============================================================================ - subroutine fire_model( currentSite, bc_in) - - + subroutine fire_model(currentSite, bc_in) + ! + ! DESCRIPTION: + ! Runs the daily fire model - type(ed_site_type) , intent(inout), target :: currentSite - type(bc_in_type) , intent(in) :: bc_in + ! 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 - type (fates_patch_type), pointer :: currentPatch - - !zero fire things + ! zero fire things currentPatch => currentSite%youngest_patch do while(associated(currentPatch)) - currentPatch%frac_burnt = 0.0_r8 - currentPatch%fire = 0 - currentPatch => currentPatch%older - enddo - - if(write_SF==itrue)then - write(fates_log(),*) 'spitfire_mode', hlm_spitfire_mode - endif - - if( hlm_spitfire_mode > hlm_sf_nofire_def )then - call fire_danger_index(currentSite, bc_in) - call wind_effect(currentSite, bc_in) - call charecteristics_of_fuel(currentSite) - call rate_of_spread(currentSite) - call ground_fuel_consumption(currentSite) - call area_burnt_intensity(currentSite, bc_in) - call crown_scorching(currentSite) - call crown_damage(currentSite) - call cambial_damage_kill(currentSite) - call post_fire_mortality(currentSite) + currentPatch%frac_burnt = 0.0_r8 + currentPatch%fire = 0 + currentPatch => currentPatch%older + end do + + if (hlm_spitfire_mode > hlm_sf_nofire_def) then + call UpdateFireWeather(currentSite, bc_in) + call wind_effect(currentSite, bc_in) + call charecteristics_of_fuel(currentSite) + call rate_of_spread(currentSite) + call ground_fuel_consumption(currentSite) + call area_burnt_intensity(currentSite, bc_in) + call crown_scorching(currentSite) + call crown_damage(currentSite) + call cambial_damage_kill(currentSite) + call post_fire_mortality(currentSite) end if end subroutine fire_model - !***************************************************************** - subroutine fire_danger_index ( currentSite, bc_in) - - !***************************************************************** - ! currentSite%acc_NI is the accumulated Nesterov fire danger index - - use SFParamsMod, only : SF_val_fdi_a, SF_val_fdi_b - use FatesConstantsMod , only : tfrz => t_water_freeze_k_1atm - use FatesConstantsMod , only : sec_per_day - - type(ed_site_type) , intent(inout), target :: currentSite - type(bc_in_type) , intent(in) :: bc_in + !--------------------------------------------------------------------------------------- + + subroutine UpdateFireWeather(currentSite, bc_in) + ! + ! DESCRIPTION: + ! Updates the site's fire weather index - type(fates_patch_type), pointer :: currentPatch + use FatesConstantsMod, only : tfrz => t_water_freeze_k_1atm + use FatesConstantsMod, only : sec_per_day - real(r8) :: temp_in_C ! daily averaged temperature in celcius - real(r8) :: rainfall ! daily precip in mm/day - real(r8) :: rh ! daily rh - - real(r8) :: yipsolon !intermediate varable for dewpoint calculation - real(r8) :: dewpoint !dewpoint in K - real(r8) :: d_NI !daily change in Nesterov Index. C^2 - integer :: iofp ! index of oldest the fates patch + ! 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] + 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 inpact, unless we decide to ever calculated the NI for each patch. + ! which probably won't have much inpact, unless we decide to ever calculated fire weather for each patch. currentPatch => currentSite%oldest_patch @@ -152,30 +144,19 @@ subroutine fire_danger_index ( currentSite, bc_in) endif iofp = currentPatch%patchno - - temp_in_C = currentPatch%tveg24%GetMean() - tfrz - rainfall = bc_in%precip24_pa(iofp)*sec_per_day - rh = bc_in%relhumid24_pa(iofp) - - if (rainfall > 3.0_r8) then !rezero NI if it rains... - d_NI = 0.0_r8 - currentSite%acc_NI = 0.0_r8 - else - yipsolon = (SF_val_fdi_a* temp_in_C)/(SF_val_fdi_b+ temp_in_C)+log(max(1.0_r8,rh)/100.0_r8) - dewpoint = (SF_val_fdi_b*yipsolon)/(SF_val_fdi_a-yipsolon) !Standard met. formula - d_NI = ( temp_in_C-dewpoint)* temp_in_C !follows Nesterov 1968. Equation 5. Thonicke et al. 2010. - if (d_NI < 0.0_r8) then !Change in NI cannot be negative. - d_NI = 0.0_r8 !check - endif - endif - currentSite%acc_NI = currentSite%acc_NI + d_NI !Accumulate Nesterov index over the fire season. + 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) - end subroutine fire_danger_index + ! update fire weather index + call currentSite%fireWeather%Update(temp_C, precip, rh, wind) + end subroutine UpdateFireWeather + + !--------------------------------------------------------------------------------------- - !***************************************************************** subroutine charecteristics_of_fuel ( currentSite ) - !***************************************************************** use SFParamsMod, only : SF_val_drying_ratio, SF_val_SAV, SF_val_FBD @@ -265,19 +246,21 @@ subroutine charecteristics_of_fuel ( currentSite ) ! Calculate fuel moisture for trunks to hold value for fuel consumption alpha_FMC(tw_sf:dl_sf) = SF_val_SAV(tw_sf:dl_sf)/SF_val_drying_ratio - fuel_moisture(tw_sf:dl_sf) = exp(-1.0_r8 * alpha_FMC(tw_sf:dl_sf) * currentSite%acc_NI) + fuel_moisture(tw_sf:dl_sf) = exp(-1.0_r8 * alpha_FMC(tw_sf:dl_sf) * & + currentSite%fireWeather%fire_weather_index) if(write_SF == itrue)then if ( hlm_masterproc == itrue ) write(fates_log(),*) 'ff3 ',currentPatch%fuel_frac if ( hlm_masterproc == itrue ) write(fates_log(),*) 'fm ',fuel_moisture - if ( hlm_masterproc == itrue ) write(fates_log(),*) 'csa ',currentSite%acc_NI + if ( hlm_masterproc == itrue ) write(fates_log(),*) 'csa ',currentSite%fireWeather%fire_weather_index if ( hlm_masterproc == itrue ) write(fates_log(),*) 'sfv ',alpha_FMC endif ! live grass moisture is a function of SAV and changes via Nesterov Index ! along the same relationship as the 1 hour fuels (live grass has same SAV as dead grass, ! but retains more moisture with this calculation.) - fuel_moisture(lg_sf) = exp(-1.0_r8 * ((SF_val_SAV(tw_sf)/SF_val_drying_ratio) * currentSite%acc_NI)) + fuel_moisture(lg_sf) = exp(-1.0_r8 * ((SF_val_SAV(tw_sf)/SF_val_drying_ratio) * & + currentSite%fireWeather%fire_weather_index)) ! Average properties over the first three litter pools (twigs, s branches, l branches) currentPatch%fuel_bulkd = sum(currentPatch%fuel_frac(tw_sf:lb_sf) * SF_val_FBD(tw_sf:lb_sf)) @@ -295,10 +278,18 @@ subroutine charecteristics_of_fuel ( currentSite ) ! Correct averaging for the fact that we are not using the trunks pool for fire ROS and intensity (5) ! Consumption of fuel in trunk pool does not influence fire ROS or intensity (Pyne 1996) - currentPatch%fuel_bulkd = currentPatch%fuel_bulkd * (1.0_r8/(1.0_r8-currentPatch%fuel_frac(tr_sf))) - currentPatch%fuel_sav = currentPatch%fuel_sav * (1.0_r8/(1.0_r8-currentPatch%fuel_frac(tr_sf))) - currentPatch%fuel_mef = currentPatch%fuel_mef * (1.0_r8/(1.0_r8-currentPatch%fuel_frac(tr_sf))) - currentPatch%fuel_eff_moist = currentPatch%fuel_eff_moist * (1.0_r8/(1.0_r8-currentPatch%fuel_frac(tr_sf))) + if ( (1.0_r8-currentPatch%fuel_frac(tr_sf)) .gt. nearzero ) then + currentPatch%fuel_bulkd = currentPatch%fuel_bulkd * (1.0_r8/(1.0_r8-currentPatch%fuel_frac(tr_sf))) + currentPatch%fuel_sav = currentPatch%fuel_sav * (1.0_r8/(1.0_r8-currentPatch%fuel_frac(tr_sf))) + currentPatch%fuel_mef = currentPatch%fuel_mef * (1.0_r8/(1.0_r8-currentPatch%fuel_frac(tr_sf))) + currentPatch%fuel_eff_moist = currentPatch%fuel_eff_moist * (1.0_r8/(1.0_r8-currentPatch%fuel_frac(tr_sf))) + else + ! somehow the fuel is all trunk. put dummy values from large branches so as not to break things later in code. + currentPatch%fuel_bulkd = SF_val_FBD(lb_sf) + currentPatch%fuel_sav = SF_val_SAV(lb_sf) + currentPatch%fuel_mef = MEF(lb_sf) + currentPatch%fuel_eff_moist = fuel_moisture(lb_sf) + endif ! Pass litter moisture into the fuel burning routine (all fuels: twigs,s branch,l branch,trunk,dead leaves,live grass) ! (wo/me term in Thonicke et al. 2010) @@ -306,6 +297,10 @@ subroutine charecteristics_of_fuel ( currentSite ) currentPatch%litter_moisture(tr_sf) = fuel_moisture(tr_sf)/MEF(tr_sf) currentPatch%litter_moisture(dl_sf) = fuel_moisture(dl_sf)/MEF(dl_sf) currentPatch%litter_moisture(lg_sf) = fuel_moisture(lg_sf)/MEF(lg_sf) + + ! remove trunks from patch%sum_fuel because they should not be included in fire equations + ! NOTE: ACF will update this soon to be more clean/bug-proof + currentPatch%sum_fuel = currentPatch%sum_fuel - litt_c%ag_cwd(tr_sf) else @@ -733,7 +728,7 @@ subroutine area_burnt_intensity ( currentSite, bc_in ) ! force ignition potential to be extreme cloud_to_ground_strikes = 1.0_r8 ! cloud_to_ground = 1 = use 100% incoming observed ignitions else ! USING LIGHTNING DATA - currentSite%FDI = 1.0_r8 - exp(-SF_val_fdi_alpha*currentSite%acc_NI) + currentSite%FDI = 1.0_r8 - exp(-SF_val_fdi_alpha*currentSite%fireWeather%fire_weather_index) cloud_to_ground_strikes = cg_strikes end if diff --git a/fire/SFNesterovMod.F90 b/fire/SFNesterovMod.F90 new file mode 100644 index 0000000000..85d1d94396 --- /dev/null +++ b/fire/SFNesterovMod.F90 @@ -0,0 +1,104 @@ +module SFNesterovMod + + use FatesConstantsMod, only : r8 => fates_r8 + use SFFireWeatherMod, only : fire_weather + + implicit none + private + + type, public, extends(fire_weather) :: nesterov_index + + contains + + procedure, public :: Init => init_nesterov_fire_weather + procedure, public :: Update => update_nesterov_index + + end type nesterov_index + + real(r8), parameter :: min_precip_thresh = 3.0_r8 ! threshold for precipitation above which to zero NI [mm/day] + + contains + + subroutine init_nesterov_fire_weather(this) + ! + ! DESCRIPTION: + ! Initializes class attributes + + ! ARGUMENTS + class(nesterov_index), intent(inout) :: this ! nesterov index extended class + + ! initialize values to 0.0 + this%fire_weather_index = 0.0_r8 + + end subroutine init_nesterov_fire_weather + + !------------------------------------------------------------------------------------- + + subroutine update_nesterov_index(this, temp_C, precip, rh, wind) + ! + ! DESCRIPTION: + ! Updates Nesterov Index + + ! ARGUMENTS + class(nesterov_index), intent(inout) :: this ! nesterov index extended class + real(r8), intent(in) :: temp_C ! daily averaged temperature [degrees C] + real(r8), intent(in) :: precip ! daily precipitation [mm] + real(r8), intent(in) :: rh ! daily relative humidity [%] + real(r8), intent(in) :: wind ! daily wind speed [m/min] + + ! LOCALS: + real(r8) :: t_dew ! dewpoint temperature [degrees C] + + if (precip > min_precip_thresh) then ! rezero NI if it rains + this%fire_weather_index = 0.0_r8 + else + + ! Calculate dewpoint temperature + t_dew = dewpoint(temp_c, rh) + + ! Accumulate Nesterov index over fire season. + this%fire_weather_index = this%fire_weather_index + calc_nesterov_index(temp_C, t_dew) + end if + + end subroutine update_nesterov_index + + !------------------------------------------------------------------------------------- + + real(r8) function calc_nesterov_index(temp_C, t_dew) + ! + ! DESCRIPTION: + ! Calculates current day's Nesterov Index for a given input values + + ! ARGUMENTS: + real(r8), intent(in) :: temp_C ! daily averaged temperature [degrees C] + real(r8), intent(in) :: t_dew ! daily dewpoint temperature [degrees C] + + ! Nesterov 1968. Eq 5, Thonicke et al. 2010 + calc_nesterov_index = (temp_C - t_dew)*temp_C + if (calc_nesterov_index < 0.0_r8) calc_nesterov_index = 0.0_r8 ! can't be negative + + end function calc_nesterov_index + + !------------------------------------------------------------------------------------- + + real(r8) function dewpoint(temp_C, rh) + ! + ! DESCRIPTION: + ! Calculates dewpoint from input air temperature and relative humidity + ! Uses Equation 8 from Lawrence 2005, https://doi.org/10.1175/BAMS-86-2-225 + + use FatesConstantsMod, only : dewpoint_a, dewpoint_b + + ! ARGUMENTS + real(r8), intent(in) :: temp_C ! temperature [degrees C] + real(r8), intent(in) :: rh ! relative humidity [%] + + ! LOCALS + real(r8) :: yipsolon ! intermediate value for dewpoint calculation + + yipsolon = log(max(1.0_r8, rh)/100.0_r8) + (dewpoint_a*temp_C)/(dewpoint_b + temp_C) + dewpoint = (dewpoint_b*yipsolon)/(dewpoint_a - yipsolon) + + end function dewpoint + +end module SFNesterovMod \ No newline at end of file diff --git a/fire/SFParamsMod.F90 b/fire/SFParamsMod.F90 index 306034a804..c2dbc3fcd6 100644 --- a/fire/SFParamsMod.F90 +++ b/fire/SFParamsMod.F90 @@ -18,9 +18,6 @@ module SFParamsMod ! ! this is what the user can use for the actual values ! - - real(r8),protected, public :: SF_val_fdi_a - real(r8),protected, public :: SF_val_fdi_b real(r8),protected, public :: SF_val_fdi_alpha real(r8),protected, public :: SF_val_miner_total real(r8),protected, public :: SF_val_fuel_energy @@ -41,8 +38,6 @@ module SFParamsMod real(r8),protected, public :: SF_val_mid_moisture_Coeff(NFSC) real(r8),protected, public :: SF_val_mid_moisture_Slope(NFSC) - character(len=param_string_length),parameter :: SF_name_fdi_a = "fates_fire_fdi_a" - character(len=param_string_length),parameter :: SF_name_fdi_b = "fates_fire_fdi_b" character(len=param_string_length),parameter :: SF_name_fdi_alpha = "fates_fire_fdi_alpha" character(len=param_string_length),parameter :: SF_name_miner_total = "fates_fire_miner_total" character(len=param_string_length),parameter :: SF_name_fuel_energy = "fates_fire_fuel_energy" @@ -148,8 +143,6 @@ subroutine SpitFireParamsInit() implicit none - SF_val_fdi_a = nan - SF_val_fdi_b = nan SF_val_fdi_alpha = nan SF_val_miner_total = nan SF_val_fuel_energy = nan @@ -214,12 +207,6 @@ subroutine SpitFireRegisterScalars(fates_params) character(len=param_string_length), parameter :: dim_names_scalar(1) = (/dimension_name_scalar/) - call fates_params%RegisterParameter(name=SF_name_fdi_a, dimension_shape=dimension_shape_scalar, & - dimension_names=dim_names_scalar) - - call fates_params%RegisterParameter(name=SF_name_fdi_b, dimension_shape=dimension_shape_scalar, & - dimension_names=dim_names_scalar) - call fates_params%RegisterParameter(name=SF_name_fdi_alpha, dimension_shape=dimension_shape_scalar, & dimension_names=dim_names_scalar) @@ -258,13 +245,6 @@ subroutine SpitFireReceiveScalars(fates_params) class(fates_parameters_type), intent(inout) :: fates_params real(r8) :: tmp_real - - - call fates_params%RetrieveParameter(name=SF_name_fdi_a, & - data=SF_val_fdi_a) - - call fates_params%RetrieveParameter(name=SF_name_fdi_b, & - data=SF_val_fdi_b) call fates_params%RetrieveParameter(name=SF_name_fdi_alpha, & data=SF_val_fdi_alpha) diff --git a/functional_unit_testing/allometry/AutoGenVarCon.py b/functional_unit_testing/allometry/AutoGenVarCon.py deleted file mode 100644 index 7bf0f85a6b..0000000000 --- a/functional_unit_testing/allometry/AutoGenVarCon.py +++ /dev/null @@ -1,140 +0,0 @@ - - -# Walk through lines of a file, if a line contains -# the string of interest (EDPftvarcon_inst), then -# parse the string to find the variable name, and save that -# to the list - - -class ParamType: - - def __init__(self,var_sym,n_dims): - - self.var_sym = var_sym - self.n_dims = n_dims - self.var_name = '' - - - - -def CheckFile(filename,check_str): - file_ptr = open(filename,'r') - var_list = [] - found = False - for line in file_ptr: - if check_str in line: - line_split = line.split() - # substr = [i for i in line_split if check_str in i][0] - substr = line - p1 = substr.find('%')+1 - if(p1>0): - substr=substr[p1:] - p2 = substr.find('(') - p3 = substr.find(')') - # Count the number of commas between p2 and p3 - n_dims = substr[p2:p3].count(',')+1 - if(p2>0): - var_list.append(ParamType(substr[:p2],n_dims)) - - unique_list = [] - for var in var_list: - found = False - for uvar in unique_list: - if (var.var_sym == uvar.var_sym): - found = True - if(not found): - unique_list.append(var) - - return(unique_list) - - - -check_str = 'EDPftvarcon_inst%' -filename = '../../biogeochem/FatesAllometryMod.F90' - -var_list = CheckFile(filename,check_str) - - -# Add symbols here - -var_list.append(ParamType('hgt_min',1)) - - -# Now look through EDPftvarcon.F90 to determine the variable name in file -# that is associated with the variable pointer - -filename = '../../main/EDPftvarcon.F90' - -f = open(filename,"r") -contents = f.readlines() - - -var_name_list = [] -for var in var_list: - for i,line in enumerate(contents): - if (var.var_sym in line) and ('data' in line) and ('=' in line): - var.var_name = contents[i-2].split()[-1].strip('\'') - print("{} {} {}".format(var.var_sym,var.var_name,var.n_dims)) - - -f = open("f90src/AllomUnitWrap.F90_in", "r") -contents = f.readlines() -f.close() - -# Identify where we define the variables, and insert the variable definitions - -for i,str in enumerate(contents): - if 'VARIABLE-DEFINITIONS-HERE' in str: - index0=i - -index=index0+2 -for var in var_list: - if(var.n_dims==1): - contents.insert(index,' real(r8),pointer :: {}(:)\n'.format(var.var_sym)) - elif(var.n_dims==2): - contents.insert(index,' real(r8),pointer :: {}(:,:)\n'.format(var.var_sym)) - else: - print('Incorrect number of dims...') - exit(-2) - index=index+1 - -# Identify where we do the pointer assignments, and insert the pointer assignments - - -for i,str in enumerate(contents): - if 'POINTER-SPECIFICATION-HERE' in str: - index0=i - -index=index0+2 -for ivar,var in enumerate(var_list): - if(var.n_dims==1): - ins_l1='\t allocate(EDPftvarcon_inst%{}(1:numpft))\n'.format(var.var_sym) - ins_l2='\t EDPftvarcon_inst%{}(:) = nan\n'.format(var.var_sym) - ins_l3='\t iv1 = iv1 + 1\n' - ins_l4='\t EDPftvarcon_ptr%var1d(iv1)%var_name = "{}"\n'.format(var.var_name) - ins_l5='\t EDPftvarcon_ptr%var1d(iv1)%var_rp => EDPftvarcon_inst%{}\n'.format(var.var_sym) - ins_l6='\t EDPftvarcon_ptr%var1d(iv1)%vtype = 1\n' - ins_l7='\n' - if(var.n_dims==2): - ins_l1='\t allocate(EDPftvarcon_inst%{}(1:numpft,1))\n'.format(var.var_sym) - ins_l2='\t EDPftvarcon_inst%{}(:,:) = nan\n'.format(var.var_sym) - ins_l3='\t iv2 = iv2 + 1\n' - ins_l4='\t EDPftvarcon_ptr%var2d(iv2)%var_name = "{}"\n'.format(var.var_name) - ins_l5='\t EDPftvarcon_ptr%var2d(iv2)%var_rp => EDPftvarcon_inst%{}\n'.format(var.var_sym) - ins_l6='\t EDPftvarcon_ptr%var2d(iv2)%vtype = 1\n' - ins_l7='\n' - - contents.insert(index,ins_l1) - contents.insert(index+1,ins_l2) - contents.insert(index+2,ins_l3) - contents.insert(index+3,ins_l4) - contents.insert(index+4,ins_l5) - contents.insert(index+5,ins_l6) - contents.insert(index+6,ins_l7) - index=index+7 - - -f = open("f90src/AllomUnitWrap.F90", "w+") -contents = "".join(contents) -f.write(contents) -f.close() diff --git a/functional_unit_testing/allometry/drive_allomtests.py b/functional_unit_testing/allometry/drive_allomtests.py deleted file mode 100644 index d97da4ded3..0000000000 --- a/functional_unit_testing/allometry/drive_allomtests.py +++ /dev/null @@ -1,730 +0,0 @@ -import numpy as np -import math -import matplotlib.pyplot as plt -import matplotlib as mp -import ctypes -import importlib -from ctypes import * #byref, cdll, c_int, c_double, c_char_p, c_long -import xml.etree.ElementTree as ET -import argparse -import re # This is a heftier string parser -import code # For development: code.interact(local=dict(globals(), **locals())) -import sys -sys.path.append('../shared/py_src') -from PyF90Utils import c8, ci, cchar, c8_arr, ci_arr - -# ======================================================================================= -# Set some constants. If they are used as constant arguments to the F90 routines, -# define them with their ctype identifiers -# ======================================================================================= - -ndbh = 200 -maxdbh = 50 -ccanopy_trim = c_double(1.0) # Crown Trim (0=0% of target, 1=100% of targ) -csite_spread = c_double(0.0) # Canopy spread (0=closed, 1=open) -cnplant = c_double(1.0) # Number of plants (don't change) -cilayer = c_int(1) # Index of the plant's canopy layer -ccanopy_lai = (2 * c_double)(1.0,1.0) # The LAI of the different canopy layers - # THIS VECTOR MUST MATCH ncanlayer -cdo_reverse = c_bool(0) # DO NOT GET REVERSE CROWN AREA - -# ======================================================================================= -# Setup references to fortran shared libraries -# ======================================================================================= - -allom_const_object = "./include/FatesConstantsMod.o" -allom_wrap_object = "./include/AllomUnitWrap.o" -allom_lib_object = "./include/FatesAllometryMod.o" - -# ============================================================================== -# Instantiate fortran allometry and other libraries -# ============================================================================== - -f90constlib= ctypes.CDLL(allom_const_object,mode=ctypes.RTLD_GLOBAL) -f90wraplib = ctypes.CDLL(allom_wrap_object,mode=ctypes.RTLD_GLOBAL) -f90funclib = ctypes.CDLL(allom_lib_object,mode=ctypes.RTLD_GLOBAL) - -# ======================================================================================= -# Create aliases to all of the different routines, set return types for functions -# ======================================================================================= - -f90_pftalloc = f90wraplib.__edpftvarcon_MOD_edpftvarconalloc #(numpft) -f90_pftset = f90wraplib.__edpftvarcon_MOD_edpftvarconpyset -f90_pftset.argtypes = [POINTER(c_int),POINTER(c_double),POINTER(c_int),c_char_p,c_long] -f90_h2d = f90funclib.__fatesallometrymod_MOD_h2d_allom #(h,ipft,d,dddh) -f90_h = f90funclib.__fatesallometrymod_MOD_h_allom #(d,ipft,h,dhdd) -f90_bagw = f90funclib.__fatesallometrymod_MOD_bagw_allom #(d,ipft,bagw,dbagwdd) -f90_bleaf = f90funclib.__fatesallometrymod_MOD_bleaf #(d,ipft,canopy_trim,bl,dbldd) -f90_bsap = f90funclib.__fatesallometrymod_MOD_bsap_allom #(d,ipft,canopy_trim,asapw,bsap,dbsapdd) -f90_bstore = f90funclib.__fatesallometrymod_MOD_bstore_allom #(d,ipft,canopy_trim,bstore,dbstoredd) -f90_bbgw = f90funclib.__fatesallometrymod_MOD_bbgw_allom #(d,ipft,canopy_trim,bbgw,dbbgwdd) -f90_bfineroot = f90funclib.__fatesallometrymod_MOD_bfineroot #(d,ipft,canopy_trim,bfr,dbfrdd) -f90_bdead = f90funclib.__fatesallometrymod_MOD_bdead_allom #(bagw,bbgw,bsap,ipft,bdead,dbagwdd,dbbgwdd,dbsapdd,dbdeaddd) -f90_carea = f90funclib.__fatesallometrymod_MOD_carea_allom #(d,nplant,site_spread,ipft,c_area)(d,nplant,site_spread,ipft,c_area) -f90_treelai = f90funclib.__fatesallometrymod_MOD_tree_lai #(leaf_c, pft, c_area, nplant, cl, canopy_lai, vcmax25top) -f90_treelai.restype = c_double - - -# This is the object type that holds our parameters -# ======================================================================================= -class parameter: - - def __init__(self,symbol): - - self.dtype = -9 - self.symbol = symbol - self.vals = [] - - def setval(self,val,ipft): - - self.vals[ipft] = val - -# This is just a helper script that generates random colors -# ======================================================================================= -def DiscreteCubeHelix(N): - - base = plt.cm.get_cmap('cubehelix') - np.random.seed(2) - color_list = base(np.random.randint(0,high=255,size=N)) - cmap_name = base.name + str(N) - return base.from_list(cmap_name, color_list, N) - - -# This will look through a CDL file for the provided parameter and determine -# the parameter's type, as well as fill an array with the data -# ======================================================================================= -def CDLParse(file_name,parm): - - fp = open(file_name,"r") - contents = fp.readlines() - fp.close() - - # Look in the file for the parameters - # symbol/name, record the line number - iline=-1 - isfirst = True - for i,line in enumerate(contents): - if(parm.symbol in line): - iline=i - if(isfirst): - dtype = line.split()[0] - if(dtype.strip()=="float" or (dtype.strip()=="double")): - parm.dtype = 0 - elif(dtype.strip()=="char"): - parm.dtype = 1 - isFirst=False - - if(iline==-1): - print('Could not find symbol: {} in file: {}'.format(parm.symbol,file_name)) - exit(2) - else: - search_field=True - line="" - lcount=0 - while(search_field and (lcount<100)): - line+=contents[iline] - if(line.count(';')>0): - search_field=False - else: - search_field=True - lcount=lcount+1 - iline=iline+1 - - # Parse the line - line_split = re.split(',|=',line) - # Remove the variable name entry - del line_split[0] - - # This is for read numbers - if(parm.dtype == 0): - ival=0 - for str0 in line_split: - str="" - isnum=False - for s in str0: - if (s.isdigit() or s=='.'): - str+=s - isnum=True - if(isnum): - parm.vals.append(float(str)) - - # This is a sting - elif(parm.dtype == 1): - for str0 in line_split: - # Loop several times to trim stuff off - for i in range(5): - str0=str0.strip().strip('\"').strip(';').strip() - parm.vals.append(str0) - - return(parm) - - - -# Read in the arguments -# ======================================================================================= - -parser = argparse.ArgumentParser(description='Parse command line arguments to this script.') -parser.add_argument('--fin', '--input', dest='fnamein', type=str, help="Input CDL filename. Required.", required=True) -args = parser.parse_args() - - -# Read in the parameters of interest that are used in the fortran objects. These -# parameters will be passed to the fortran allocation. -# ======================================================================================= - -parms = {} -parms['dbh_maxheight'] = CDLParse(args.fnamein,parameter('fates_allom_dbh_maxheight')) -parms['hmode'] = CDLParse(args.fnamein,parameter('fates_allom_hmode')) -parms['amode'] = CDLParse(args.fnamein,parameter('fates_allom_amode')) -parms['lmode'] = CDLParse(args.fnamein,parameter('fates_allom_lmode')) -parms['smode'] = CDLParse(args.fnamein,parameter('fates_allom_smode')) -parms['cmode'] = CDLParse(args.fnamein,parameter('fates_allom_cmode')) -parms['fmode'] = CDLParse(args.fnamein,parameter('fates_allom_fmode')) -parms['stmode'] = CDLParse(args.fnamein,parameter('fates_allom_stmode')) -parms['cushion'] = CDLParse(args.fnamein,parameter('fates_alloc_storage_cushion')) -parms['d2h1'] = CDLParse(args.fnamein,parameter('fates_allom_d2h1')) -parms['d2h2'] = CDLParse(args.fnamein,parameter('fates_allom_d2h2')) -parms['d2h3'] = CDLParse(args.fnamein,parameter('fates_allom_d2h3')) -parms['agb1'] = CDLParse(args.fnamein,parameter('fates_allom_agb1')) -parms['agb2'] = CDLParse(args.fnamein,parameter('fates_allom_agb2')) -parms['agb3'] = CDLParse(args.fnamein,parameter('fates_allom_agb3')) -parms['agb4'] = CDLParse(args.fnamein,parameter('fates_allom_agb4')) -parms['d2bl1'] = CDLParse(args.fnamein,parameter('fates_allom_d2bl1')) -parms['d2bl2'] = CDLParse(args.fnamein,parameter('fates_allom_d2bl2')) -parms['d2bl3'] = CDLParse(args.fnamein,parameter('fates_allom_d2bl3')) -parms['wood_density'] = CDLParse(args.fnamein,parameter('fates_wood_density')) -parms['c2b'] = CDLParse(args.fnamein,parameter('fates_c2b')) -parms['la_per_sa_int'] = CDLParse(args.fnamein,parameter('fates_allom_la_per_sa_int')) -parms['la_per_sa_slp'] = CDLParse(args.fnamein,parameter('fates_allom_la_per_sa_slp')) -parms['slatop'] = CDLParse(args.fnamein,parameter('fates_leaf_slatop')) -parms['slamax'] = CDLParse(args.fnamein,parameter('fates_leaf_slamax')) -parms['l2fr'] = CDLParse(args.fnamein,parameter('fates_allom_l2fr')) -parms['agb_frac'] = CDLParse(args.fnamein,parameter('fates_allom_agb_frac')) -parms['blca_expnt_diff'] = CDLParse(args.fnamein,parameter('fates_allom_blca_expnt_diff')) -parms['d2ca_coeff_min'] = CDLParse(args.fnamein,parameter('fates_allom_d2ca_coefficient_min')) -parms['d2ca_coeff_max'] = CDLParse(args.fnamein,parameter('fates_allom_d2ca_coefficient_max')) -parms['sai_scaler'] = CDLParse(args.fnamein,parameter('fates_allom_sai_scaler')) - -# Read in the parameters that are not necessary for the F90 allometry algorithms, -# but are useful for these scripts (e.g. the name of the parameter, and minimum height) -# ======================================================================================= - -eparms = {} -eparms['recruit_hgt_min'] = CDLParse(args.fnamein,parameter('fates_recruit_hgt_min')) -eparms['name'] = CDLParse(args.fnamein,parameter('fates_pftname')) -eparms['vcmax25top'] = CDLParse(args.fnamein,parameter('fates_leaf_vcmax25top')) - - -# Determine how many PFTs are here, also check to make sure that all parameters -# have the same number -# ======================================================================================= -numpft=-1 -for key, parm in parms.items(): - if( (len(parm.vals) == numpft) or (numpft==-1) ): - numpft=len(parm.vals) - else: - print('Bad length in PFT parameter') - print('parameter: {}, vals:'.format(parm.symbol),parm.vals) - - -# ============================================================================== -# Allocate fortran PFT arrays -# ============================================================================== - -iret=f90_pftalloc(ci(numpft)) - -# ============================================================================== -# Populate the Fortran PFT structure -# ============================================================================== - -for ipft in range(numpft): - for key, parm in parms.items(): - print('{} {} '.format(parm.symbol,parm.vals[ipft])) - iret=f90_pftset(c_int(ipft+1), \ - c_double(parm.vals[ipft]), \ - c_int(0), \ - c_char_p(parm.symbol.encode('utf-8')), \ - c_long(len(parm.symbol))) - - -# ========================================================================= -# Initialize Output Arrays -# ========================================================================= - -blmaxi = np.zeros((numpft,ndbh)) -blmaxd = np.zeros((numpft,ndbh)) -bfrmax = np.zeros((numpft,ndbh)) -hi = np.zeros((numpft,ndbh)) -hd = np.zeros((numpft,ndbh)) -bagwi = np.zeros((numpft,ndbh)) -bagwd = np.zeros((numpft,ndbh)) - -bagwr = np.zeros((numpft,ndbh)) - -dbh = np.zeros((numpft,ndbh)) -bbgw = np.zeros((numpft,ndbh)) -bsapi = np.zeros((numpft,ndbh)) -bsapd = np.zeros((numpft,ndbh)) -asapd = np.zeros((numpft,ndbh)) -bstore = np.zeros((numpft,ndbh)) -bdead = np.zeros((numpft,ndbh)) -dbhe = np.zeros((numpft,ndbh)) -camin = np.zeros((numpft,ndbh)) -ldense = np.zeros((numpft,ndbh)) -treelai = np.zeros((numpft,ndbh)) -blmax_o_dbagwdh = np.zeros((numpft,ndbh)) -blmax_o_dbagwdd = np.zeros((numpft,ndbh)) - - -for ipft in range(numpft): - - print('py: Solving for pft: {}'.format(ipft+1)) - - # Initialize Height #(d,ipft,h,dhdd) - ch_min = c_double(eparms['recruit_hgt_min'].vals[ipft]) - - cd = c_double(-9.0) - cdddh = c_double(-9.0) - cipft = c_int(ipft+1) - cinit = c_int(0) - - # Calculate the minimum dbh - iret=f90_h2d(byref(ch_min),byref(cipft),byref(cd),byref(cdddh)) - - # Generate a vector of diameters (use dbh) - dbh[ipft,:] = np.linspace(cd.value,maxdbh,num=ndbh) - - # Initialize various output vectors - cd = c_double(dbh[ipft,0]) - ch = c_double(-9.0) - cdhdd = c_double(-9.0) - cbagw = c_double(-9.0) - cdbagwdd = c_double(-9.0) - cblmax = c_double(-9.0) - cdblmaxdd = c_double(-9.0) - cbfrmax = c_double(-9.0) - cdbfrmaxdd = c_double(-9.0) - cbbgw = c_double(-9.0) - cdbbgwdd = c_double(-9.0) - cbsap = c_double(-9.0) - cdbsapdd = c_double(-9.0) - cbdead = c_double(-9.0) - cdbdeaddd = c_double(-9.0) - ccamin = c_double(-9.0) - casapw = c_double(-9.0) # Sapwood area - cbstore = c_double(-9.0) - cdbstoredd = c_double(-9.0) - - iret=f90_h(byref(cd),byref(cipft),byref(ch),byref(cdhdd)) - hi[ipft,0] = ch.value - hd[ipft,0] = ch.value - print('py: initialize h[{},0]={}'.format(ipft+1,ch.value)) - - # Initialize AGB #(d,ipft,bagw,dbagwdd) - iret=f90_bagw(byref(cd),byref(cipft),byref(cbagw),byref(cdbagwdd)) - bagwi[ipft,0] = cbagw.value - print('py: initialize bagwi[{},0]={}'.format(ipft+1,cbagw.value)) - - # Initialize bleaf #(d,ipft,canopy_trim,bl,dbldd) - iret=f90_bleaf(byref(cd),byref(cipft),byref(ccanopy_trim),byref(cblmax),byref(cdblmaxdd)) - blmaxi[ipft,0] = cblmax.value - blmaxd[ipft,0] = cblmax.value - print('py: initialize blmaxi[{},0]={}'.format(ipft+1,cblmax.value)) - - # Initialize bstore #(d,ipft,canopy_trim,bstore,dbstoredd) - iret=f90_bstore(byref(cd),byref(cipft),byref(ccanopy_trim),byref(cbstore),byref(cdbstoredd)) - bstore[ipft,0] = cbstore.value - - # calculate crown area (d,nplant,site_spread,ipft,c_area) Using nplant = 1, generates units of m2 - # spread is likely 0.0, which is the value it tends towards when canopies close - # (dbh, nplant, site_spread, ipft, c_area,inverse) - iret= f90_carea(byref(cd),byref(cnplant),byref(csite_spread),byref(cipft),byref(ccamin),byref(cdo_reverse)) - camin[ipft,0] = ccamin.value - - - ldense[ipft,0] = blmaxi[ipft,0]/camin[ipft,0] - print('py: initialize careai[{},0]={}'.format(ipft+1,ccamin.value)) - - #f90_treelai(leaf_c, pft, c_area, nplant, cl, canopy_lai, vcmax25top) - cvcmax=c_double(eparms['vcmax25top'].vals[ipft]) - treelai[ipft,0]=f90_treelai(byref(cblmax),byref(cipft),byref(ccamin), \ - byref(cnplant),byref(cilayer),byref(ccanopy_lai),byref(cvcmax)) - - # Initialize fine roots #(d,ipft,canopy_trim,bfr,dbfrdd) - iret=f90_bfineroot(byref(cd),byref(cipft),byref(ccanopy_trim), \ - byref(cbfrmax),byref(cdbfrmaxdd)) - bfrmax[ipft,0] = cbfrmax.value - print('py: initialize bfrmax[{},0]={}'.format(ipft+1,cbfrmax.value)) - - # Initialize coarse roots #(d,ipft,bbgw,dbbgwdd) - iret=f90_bbgw(byref(cd),byref(cipft),byref(c_double(1.0)), \ - byref(cbbgw),byref(cdbbgwdd)) - bbgw[ipft,0] = cbbgw.value - print('py: initialize bbgw[{},0]={}'.format(ipft+1,cbbgw.value)) - - - # Initialize bsap (d,ipft,canopy_trim,asapw,bsap,dbsapdd) - iret=f90_bsap(byref(cd),byref(cipft),byref(ccanopy_trim),byref(casapw),byref(cbsap),byref(cdbsapdd)) - bsapi[ipft,0] = cbsap.value - bsapd[ipft,0] = cbsap.value - asapd[ipft,0] = casapw.value - print('py: initialize bsapi[{},0]={}'.format(ipft+1,cbsap.value)) - - # bdead #(bagw,bbgw,bsap,ipft,bdead,dbagwdd,dbbgwdd,dbsapdd,dbdeaddd) - iret=f90_bdead(byref(cbagw),byref(cbbgw),byref(cbsap),byref(cipft), \ - byref(cbdead),byref(cdbagwdd),byref(cdbbgwdd), \ - byref(cdbsapdd),byref(cdbdeaddd)) - - bdead[ipft,0] = cbdead.value - print('py: initialize bdead[{},0]={}'.format(ipft+1,cbdead.value)) - - bagwr[ipft,0] = (bdead[ipft,0]) * 0.6 - - # the metric that shan't be spoken - blmax_o_dbagwdh[ipft,0] = blmaxi[ipft,0]/(cdbagwdd.value/cdhdd.value) - - # the metric that shan't be spoken - blmax_o_dbagwdd[ipft,0] = blmaxi[ipft,0]/(cdbagwdd.value) - - for idi in range(1,ndbh): - - dp = dbh[ipft,idi-1] # previous position - dc = dbh[ipft,idi] # current position - dd = dc-dp - - cdp = c_double(dp) - cdc = c_double(dc) - cdbhe = c_double(-9.0) - cddedh = c_double(-9.0) - - if(ipft==2): - print("===") - - # integrate height #(d,ipft,h,dhdd) - iret=f90_h(byref(cdc),byref(cipft),byref(ch),byref(cdhdd)) - hi[ipft,idi] = hi[ipft,idi-1] + cdhdd.value*dd - - # diagnosed height - hd[ipft,idi] = ch.value - - # diagnose AGB #(d,h,ipft,bagw,dbagwdd) - iret=f90_bagw(byref(cdc),byref(cipft),byref(cbagw),byref(cdbagwdd)) - bagwd[ipft,idi] = cbagw.value - - # integrate AGB #(d,h,ipft,bagw,dbagwdd) - iret=f90_bagw(byref(cdp),byref(cipft),byref(cbagw),byref(cdbagwdd)) - bagwi[ipft,idi] = bagwi[ipft,idi-1] + cdbagwdd.value*dd - - # diagnose bleaf #(d,ipft,blmax,dblmaxdd) - iret=f90_bleaf(byref(cdc),byref(cipft),byref(ccanopy_trim),byref(cblmax),byref(cdblmaxdd)) - blmaxd[ipft,idi] = cblmax.value - - # bstore #(d,ipft,canopy_trim,bstore,dbstoredd) - iret=f90_bstore(byref(cdc),byref(cipft),byref(ccanopy_trim),byref(cbstore),byref(cdbstoredd)) - bstore[ipft,idi] = cbstore.value - - # calculate crown area (d,nplant,site_spread,ipft,c_area) Using nplant = 1, generates units of m2 - iret= f90_carea(byref(cdc),byref(cnplant),byref(csite_spread),byref(cipft),byref(ccamin),byref(cdo_reverse)) - camin[ipft,idi] = ccamin.value - - #f90_treelai(leaf_c, pft, c_area, nplant, cl, canopy_lai, vcmax25top) - cvcmax=c_double(eparms['vcmax25top'].vals[ipft]) - treelai[ipft,idi]=f90_treelai(byref(cblmax),byref(cipft),byref(ccamin), \ - byref(cnplant),byref(cilayer),byref(ccanopy_lai),byref(cvcmax)) - - - - - # integrate bleaf #(d,ipft,blmax,dblmaxdd) - iret=f90_bleaf(byref(cdp),byref(cipft),byref(c_double(1.0)),byref(cblmax),byref(cdblmaxdd)) - blmaxi[ipft,idi] = blmaxi[ipft,idi-1] + cdblmaxdd.value*dd - - # leaf mass per square meter of crown - ldense[ipft,idi] = blmaxd[ipft,idi]/camin[ipft,idi] - - # integrate bfineroot #(d,ipft,canopy_trim,bfr,dbfrdd) - iret=f90_bfineroot(byref(cdp),byref(cipft),byref(c_double(1.0)),byref(cbfrmax),byref(cdbfrmaxdd)) - bfrmax[ipft,idi] = bfrmax[ipft,idi-1] + cdbfrmaxdd.value*dd - - # integrate bbgw #(d,h,ipft,bbgw,dbbgwdd) - iret=f90_bbgw(byref(cdp),byref(cipft),byref(cbbgw),byref(cdbbgwdd)) - bbgw[ipft,idi] = bbgw[ipft,idi-1] + cdbbgwdd.value*dd - - # diagnose bsap # (d,ipft,canopy_trim,asapw,bsap,dbsapdd) - iret=f90_bsap(byref(cdc),byref(cipft),byref(ccanopy_trim),byref(casapw),byref(cbsap),byref(cdbsapdd)) - bsapd[ipft,idi] = cbsap.value # Biomass - asapd[ipft,idi] = casapw.value # Area - - # integrate bsap - iret=f90_bsap(byref(cdp),byref(cipft),byref(ccanopy_trim),byref(casapw),byref(cbsap),byref(cdbsapdd)) - bsapi[ipft,idi] = bsapi[ipft,idi-1] + cdbsapdd.value*dd - - - - - # the metric that shan't be spoken - # previous t-step derivatives are used for simplicity - if cdhdd.value<0.000001: - blmax_o_dbagwdh[ipft,idi] = None - else: - blmax_o_dbagwdh[ipft,idi] = blmaxi[ipft,idi-1]/(cdbagwdd.value/cdhdd.value) - - # the metric that shan't be spoken - # previous t-step derivatives are used for simplicity - blmax_o_dbagwdd[ipft,idi] = blmaxi[ipft,idi-1]/(cdbagwdd.value) - - # Diagnose bdead (bagw,bbgw,bsap,ipft,bdead,dbagwdd,dbbgwdd,dbsapdd,dbdeaddd) - - iret=f90_bdead(byref(c_double(bagwd[ipft,idi])), \ - byref(c_double(bbgw[ipft,idi])), \ - byref(c_double(bsapd[ipft,idi])), \ - byref(cipft), byref(cbdead), \ - byref(cdbagwdd),byref(cdbbgwdd), \ - byref(cdbsapdd),byref(cdbdeaddd)) - bdead[ipft,idi] = cbdead.value - - - bagwr[ipft,idi] = (bdead[ipft,idi] + bsapd[ipft,idi]) * 0.6 - -# Create the appropriate number of line-styles, colors and widths -linestyles_base = ['-', '--', '-.', ':'] -linestyles=[] -for i in range(int(math.floor(float(numpft)/float(len(linestyles_base))))): - linestyles.extend(linestyles_base) -for i in range(numpft-len(linestyles)): - linestyles.append(linestyles_base[i]) - -my_colors = DiscreteCubeHelix(numpft) - - -mp.rcParams.update({'font.size': 14}) -mp.rcParams["savefig.directory"] = "" #os.chdir(os.path.dirname(__file__)) - -legfs = 12 -lwidth = 2.0 - -#code.interact(local=dict(globals(), **locals())) - -if(True): - fig0 = plt.figure() - figleg = plt.figure() - ax = fig0.add_subplot(111) - ax.axis("off") - ax.set_axis_off() - proxies = () - for ipft in range(numpft): - proxies = proxies + (mp.lines.Line2D([],[], \ - linestyle=linestyles[ipft], \ - color=my_colors(ipft), \ - label=eparms['name'].vals[ipft], \ - linewidth=lwidth),) - figleg.legend(handles=proxies,fontsize=12,frameon=False,labelspacing=0.25,loc='center') - plt.show(block=False) - plt.close(fig0) - - - -if(False): - fig1_12 = plt.figure() - for ipft in range(numpft): - plt.plot(bagwd[ipft,:],bagwr[ipft,:],linestyle=linestyles[ipft],color=my_colors(ipft),linewidth=lwidth) - plt.xlabel('bagw [m]') - plt.ylabel('bagr [m]') - plt.title('') - plt.grid(True) - plt.savefig("plots/bagw_vs_bagwr.png") - - -if(True): - fig1 = plt.figure() - figleg = plt.figure() - for ipft in range(numpft): - plt.plot(dbh[ipft,:],hi[ipft,:],linestyle=linestyles[ipft],color=my_colors(ipft),linewidth=lwidth) - plt.xlabel('diameter [cm]') - plt.ylabel('height [m]') - plt.title('Integrated Heights') - plt.grid(True) - plt.tight_layout() - -if(True): - fig1_1 = plt.figure() - for ipft in range(numpft): - plt.plot(hd[ipft,:],hi[ipft,:],linestyle=linestyles[ipft],color=my_colors(ipft),linewidth=lwidth) - plt.xlabel('height (diagnosed) [m]') - plt.ylabel('height (integrated) [m]') - plt.title('Height') - plt.grid(True) - plt.savefig("plots/hdhi.png") - -if(False): - fig2=plt.figure() - for ipft in range(numpft): - plt.plot(blmaxd[ipft,:],blmaxi[ipft,:],linestyle=linestyles[ipft],color=my_colors(ipft),linewidth=lwidth) - plt.xlabel('diagnosed [kgC]') - plt.ylabel('integrated [kgC]') - plt.title('Maximum Leaf Biomass') - plt.grid(True) - plt.tight_layout() - -if(True): - fig3=plt.figure() - for ipft in range(numpft): - plt.plot(dbh[ipft,:],blmaxi[ipft,:],linestyle=linestyles[ipft],color=my_colors(ipft),linewidth=lwidth) - plt.xlabel('diameter [cm]') - plt.ylabel('mass [kgC]') - plt.title('Maximum Leaf Biomass') - plt.grid(True) - plt.tight_layout() - -if(True): - fig3_1=plt.figure() - for ipft in range(numpft): - plt.plot(dbh[ipft,1:15],blmaxi[ipft,1:15],linestyle=linestyles[ipft],color=my_colors(ipft),linewidth=lwidth) - plt.xlabel('diameter [cm]') - plt.ylabel('mass [kgC]') - plt.title('Maximum Leaf Biomass (saplings)') - plt.grid(True) - plt.tight_layout() - - -if(True): - fig4=plt.figure() - for ipft in range(numpft): - plt.plot(dbh[ipft,:],camin[ipft,:],linestyle=linestyles[ipft],color=my_colors(ipft),linewidth=lwidth) - plt.xlabel('diameter [cm]') - plt.ylabel('[m2] (closed canopy)') - plt.title('Crown Area') - plt.grid(True) - plt.tight_layout() - -if(True): - fig4_1=plt.figure() - for ipft in range(numpft): - plt.plot(dbh[ipft,:],ldense[ipft,:],linestyle=linestyles[ipft],color=my_colors(ipft),linewidth=lwidth) - plt.xlabel('diameter [cm]') - plt.ylabel('[kgC/m2] (closed canopy)') - plt.title('Leaf Mass Per Crown Area') - plt.grid(True) - plt.tight_layout() - - -if(True): - fig6=plt.figure() - for ipft in range(numpft): - plt.plot(dbh[ipft,:],bagwi[ipft,:]/1000,linestyle=linestyles[ipft],color=my_colors(ipft),linewidth=lwidth) - plt.xlabel('diameter [cm]') - plt.ylabel('AGB [MgC]') - plt.title('Above Ground Biomass') - plt.grid(True) - plt.tight_layout() - -if(False): - fig6_1=plt.figure() - for ipft in range(numpft): - plt.plot(bagwd[ipft,:]/1000,bagwi[ipft,:]/1000,linestyle=linestyles[ipft],color=my_colors(ipft),linewidth=lwidth) - plt.xlabel('AGBW deterministic [MgC]') - plt.ylabel('AGBW integrated [MgC]') - plt.title('Above Ground Biomass') - plt.grid(True) - plt.tight_layout() - -if(False): - fig5=plt.figure() - for ipft in range(numpft): - gpmask = np.isfinite(blmax_o_dbagwdh[ipft,:]) - plt.plot(dbh[ipft,gpmask],blmax_o_dbagwdh[ipft,gpmask],linestyle=linestyles[ipft],color=my_colors(ipft),linewidth=lwidth) - plt.xlabel('diameter [cm]') - plt.ylabel('growth potential: bl/(dAGB/dh) [m]') - plt.title('Height Growth Potential') - plt.grid(True) - plt.tight_layout() - -if(False): - fig6=plt.figure() - for ipft in range(numpft): - plt.plot(dbh[ipft,:],blmax_o_dbagwdd[ipft,:],linestyle=linestyles[ipft],color=my_colors(ipft),linewidth=lwidth) - plt.xlabel('diameter [cm]') - plt.ylabel('growth potential: bl/(dAGB/dd) [cm]') - plt.title('Diameter Growth Potential') - plt.grid(True) - plt.tight_layout() - -if(False): - fig7=plt.figure() - for ipft in range(numpft): - plt.plot(bsapd[ipft,:],bsapi[ipft,:],linestyle=linestyles[ipft],color=my_colors(ipft),linewidth=lwidth) - plt.xlabel('deterministic [kgC]') - plt.ylabel('integrated [kgC]') - plt.title('Sapwood Biomass') - plt.grid(True) - plt.tight_layout() - -if(False): - fig7_0=plt.figure() - for ipft in range(numpft): - plt.plot(dbh[ipft,:],bsapd[ipft,:],linestyle=linestyles[ipft],color=my_colors(ipft),linewidth=lwidth) - plt.xlabel('Diameter [cm]') - plt.ylabel('[kgC]') - plt.title('Sapwood Biomass') - plt.grid(True) - plt.tight_layout() - -if(True): - fig7_2=plt.figure(figsize=(8,6)) - # Sapwood - ax = fig7_2.add_subplot(221) - for ipft in range(numpft): - ax.plot(dbh[ipft,:],bsapd[ipft,:]/(bsapd[ipft,:]+blmaxi[ipft,:]+bfrmax[ipft,:]+bstore[ipft,:]), \ - linestyle=linestyles[ipft],color=my_colors(ipft),linewidth=lwidth) - ax.set_xlabel('diameter [cm]') - ax.set_ylabel('[kgC/kgC]') - ax.set_title('Sapwood (fraction of live)') - ax.grid(True) - # Leaf - ax = fig7_2.add_subplot(222) - for ipft in range(numpft): - ax.plot(dbh[ipft,:],blmaxi[ipft,:]/(bsapd[ipft,:]+blmaxi[ipft,:]+bfrmax[ipft,:]+bstore[ipft,:]), \ - linestyle=linestyles[ipft],color=my_colors(ipft),linewidth=lwidth) - ax.set_xlabel('diameter [cm]') - ax.set_ylabel('[kgC/kgC]') - ax.set_title('Leaf (fraction of live)') - ax.grid(True) - # Fine Root - ax = fig7_2.add_subplot(223) - for ipft in range(numpft): - ax.plot(dbh[ipft,:],bfrmax[ipft,:]/(bsapd[ipft,:]+blmaxi[ipft,:]+bfrmax[ipft,:]+bstore[ipft,:]), \ - linestyle=linestyles[ipft],color=my_colors(ipft),linewidth=lwidth) - ax.set_xlabel('diameter [cm]') - ax.set_ylabel('[kgC/kgC]') - ax.set_title('Fine-Root (fraction of live)') - ax.grid(True) - # Storage - ax = fig7_2.add_subplot(224) - for ipft in range(numpft): - ax.plot(dbh[ipft,:],bstore[ipft,:]/(bsapd[ipft,:]+blmaxi[ipft,:]+bfrmax[ipft,:]+bstore[ipft,:]), \ - linestyle=linestyles[ipft],color=my_colors(ipft),linewidth=lwidth) - ax.set_xlabel('diameter [cm]') - ax.set_ylabel('[kgC/kgC]') - ax.set_title('Storage (fraction of live)') - ax.grid(True) - - plt.tight_layout() - - - -if(True): - fig8=plt.figure() - ax = fig8.add_subplot(111) - for ipft in range(numpft): - ax.plot(dbh[ipft,:],treelai[ipft,:],linestyle=linestyles[ipft],color=my_colors(ipft),linewidth=lwidth) - ax.ticklabel_format(style='plain') - ax.set_xlabel('diameter [cm]') - ax.set_ylabel('[m2/m2]') - ax.set_title('Untrimmed In-Crown LAI') - ax.grid(True) - plt.tight_layout() - - - - -plt.show() diff --git a/functional_unit_testing/allometry/f90src/AllomUnitWrap.F90_in b/functional_unit_testing/allometry/f90src/AllomUnitWrap.F90_in deleted file mode 100644 index 471314b0bf..0000000000 --- a/functional_unit_testing/allometry/f90src/AllomUnitWrap.F90_in +++ /dev/null @@ -1,218 +0,0 @@ - -! ======================================================================================= -! -! This file is an alternative to key files in the fates -! filesystem. Noteably, we replace fates_r8 and fates_in -! with types that work with "ctypes". This is -! a key step in working with python -! -! We also wrap FatesGlobals to reduce the dependancy -! cascade that it pulls in from shr_log_mod. -! -! ======================================================================================= - -module shr_log_mod - - use iso_c_binding, only : c_char - use iso_c_binding, only : c_int - - contains - - function shr_log_errMsg(source, line) result(ans) - character(kind=c_char,len=*), intent(in) :: source - integer(c_int), intent(in) :: line - character(kind=c_char,len=128) :: ans - - ans = "source: " // trim(source) // " line: " - end function shr_log_errMsg - -end module shr_log_mod - - -module FatesGlobals - - contains - - integer function fates_log() - fates_log = -1 - end function fates_log - - subroutine fates_endrun(msg) - - implicit none - character(len=*), intent(in) :: msg ! string to be printed - - stop - - end subroutine fates_endrun - -end module FatesGlobals - - -module EDTypesMod - - use iso_c_binding, only : r8 => c_double - - integer, parameter :: nclmax = 2 - integer, parameter :: nlevleaf = 30 - real(r8), parameter :: dinc_ed = 1.0_r8 - -end module EDTypesMod - - -module EDPftvarcon - - use iso_c_binding, only : r8 => c_double - use iso_c_binding, only : i4 => c_int - use iso_c_binding, only : c_char - - integer,parameter :: SHR_KIND_CS = 80 ! short char - - type, public :: EDPftvarcon_inst_type - - ! VARIABLE-DEFINITIONS-HERE (DO NOT REMOVE THIS LINE, OR MOVE IT) - - end type EDPftvarcon_inst_type - - type ptr_var1 - real(r8), dimension(:), pointer :: var_rp - integer(i4), dimension(:), pointer :: var_ip - character(len=shr_kind_cs) :: var_name - integer :: vtype - end type ptr_var1 - - type ptr_var2 - real(r8), dimension(:,:), pointer :: var_rp - integer(i4), dimension(:,:), pointer :: var_ip - character(len=shr_kind_cs) :: var_name - integer :: vtype - end type ptr_var2 - - type EDPftvarcon_ptr_type - type(ptr_var1), allocatable :: var1d(:) - type(ptr_var2), allocatable :: var2d(:) - end type EDPftvarcon_ptr_type - - - type(EDPftvarcon_inst_type), public :: EDPftvarcon_inst ! ED ecophysiological constants structure - type(EDPftvarcon_ptr_type), public :: EDPftvarcon_ptr ! Pointer structure for obj-oriented id - - integer :: numparm1d ! Number of different PFT parameters - integer :: numparm2d - integer :: numpft - - logical, parameter :: debug = .true. - -contains - - - subroutine EDPftvarconPySet(ipft,rval,ival,name) - - implicit none - ! Arguments - integer(i4),intent(in) :: ipft - character(kind=c_char,len=*), intent(in) :: name - real(r8),intent(in) :: rval - integer(i4),intent(in) :: ival - ! Locals - logical :: npfound - integer :: ip - integer :: namelen - - namelen = len(trim(name)) - - if(debug) print*,"F90: ARGS: ",trim(name)," IPFT: ",ipft," RVAL: ",rval," IVAL: ",ival - - ip=0 - npfound = .true. - do ip=1,numparm1d - - if (trim(name) == trim(EDPftvarcon_ptr%var1d(ip)%var_name ) ) then - print*,"F90: Found ",trim(name)," in lookup table" - npfound = .false. - if(EDPftvarcon_ptr%var1d(ip)%vtype == 1) then ! real - EDPftvarcon_ptr%var1d(ip)%var_rp(ipft) = rval - elseif(EDPftvarcon_ptr%var1d(ip)%vtype == 2) then ! integer - EDPftvarcon_ptr%var1d(ip)%var_ip(ipft) = ival - else - print*,"F90: STRANGE TYPE" - stop - end if - end if - end do - - if(npfound)then - print*,"F90: The parameter you loaded DNE: ",name(:) - stop - end if - - do ip=1,numparm2d - if (trim(name) == trim(EDPftvarcon_ptr%var2d(ip)%var_name)) then - print*,"F90: Found ",trim(name)," in lookup table" - print*,"BUT... WE AVOID USING 2D VARIABLES FOR NOW..." - print*,"REMOVE THIS TEST" - stop - end if - end do - - - ! Perform a check to see if the target array is being filled - if (trim(name) == 'fates_allom_d2h1') then - if (EDPftvarcon_inst%allom_d2h1(ipft) == rval) then - print*,"F90: POINTER CHECK PASSES:",rval," = ",EDPftvarcon_inst%allom_d2h1(ipft) - else - print*,"F90: POINTER CHECK FAILS:",rval," != ",EDPftvarcon_inst%allom_d2h1(ipft) - stop - end if - end if - - if (trim(name) == 'fates_wood_density' ) then - if (EDPftvarcon_inst%wood_density(ipft) == rval) then - print*,"F90: POINTER CHECK PASSES:",rval," = ",EDPftvarcon_inst%wood_density(ipft) - else - print*,"F90: POINTER CHECK FAILS:",rval," != ",EDPftvarcon_inst%wood_density(ipft) - stop - end if - end if - - return - end subroutine EDPftvarconPySet - - - subroutine EDPftvarconAlloc(numpft_in) - ! - - ! !ARGUMENTS: - integer(i4), intent(in) :: numpft_in - ! LOCALS: - integer :: iv1 ! The parameter incrementer - integer :: iv2 - !------------------------------------------------------------------------ - - numpft = numpft_in - - allocate( EDPftvarcon_ptr%var1d(100)) ! Make this plenty large - allocate( EDPftvarcon_ptr%var2d(100)) - iv1=0 - iv2=0 - - ! POINTER-SPECIFICATION-HERE (DO NOT REMOVE THIS LINE, OR MOVE IT) - -! allocate( EDPftvarcon_inst%allom_dbh_maxheight (1:numpft)); EDPftvarcon_inst%allom_dbh_maxheight (:) = nan -! iv = iv + 1 -! EDPftvarcon_ptr%var1d(iv)%var_name = "fates_allom_dbh_maxheight" -! EDPftvarcon_ptr%var1d(iv)%var_rp => EDPftvarcon_inst%allom_dbh_maxheight -! EDPftvarcon_ptr%var1d(iv)%vtype = 1 - - - numparm1d = iv1 - numparm2d = iv2 - - - print*,"F90: ALLOCATED ",numparm1d," PARAMETERS, FOR ",numpft," PFTs" - - - return - end subroutine EDPftvarconAlloc - -end module EDPftvarcon diff --git a/functional_unit_testing/allometry/include/README b/functional_unit_testing/allometry/include/README deleted file mode 100644 index bfa612f78d..0000000000 --- a/functional_unit_testing/allometry/include/README +++ /dev/null @@ -1 +0,0 @@ -This holds the place of the include folder \ No newline at end of file diff --git a/functional_unit_testing/allometry/plots/README b/functional_unit_testing/allometry/plots/README deleted file mode 100644 index c32df9df9a..0000000000 --- a/functional_unit_testing/allometry/plots/README +++ /dev/null @@ -1 +0,0 @@ -Placeholder for the folder \ No newline at end of file diff --git a/functional_unit_testing/allometry/simple_build.sh b/functional_unit_testing/allometry/simple_build.sh deleted file mode 100755 index 114c82a15d..0000000000 --- a/functional_unit_testing/allometry/simple_build.sh +++ /dev/null @@ -1,58 +0,0 @@ -#!/bin/bash - -FC='gfortran -g -shared -fPIC' - -# First copy over the FatesConstants file, but change the types of the fates_r8 and fates_int - -old_fates_r8_str=`grep -e integer ../../main/FatesConstantsMod.F90 | grep fates_r8 | sed 's/^[ \t]*//;s/[ \t]*$//'` -new_fates_r8_str='use iso_c_binding, only: fates_r8 => c_double' - -old_fates_int_str=`grep -e integer ../../main/FatesConstantsMod.F90 | grep fates_int | sed 's/^[ \t]*//;s/[ \t]*$//'` -new_fates_int_str='use iso_c_binding, only: fates_int => c_int' - -# Add the new lines (need position change, don't swap) - -sed "/implicit none/i $new_fates_r8_str" ../../main/FatesConstantsMod.F90 > f90src/FatesConstantsMod.F90 -sed -i "/implicit none/i $new_fates_int_str" f90src/FatesConstantsMod.F90 - -# Delete the old lines - -sed -i "/$old_fates_r8_str/d" f90src/FatesConstantsMod.F90 -sed -i "/$old_fates_int_str/d" f90src/FatesConstantsMod.F90 - -sed -i "/private/d" f90src/FatesConstantsMod.F90 - -# This re-writes the wrapper so that it uses all the correct parameters -# in FatesAllometryMod.F90 -python AutoGenVarCon.py - - -# Procedure for auto-generating AllomUnitWrap -# 1) scan FatesAllometry and create list of EDPftVarcon_inst variables -# 2) scan EDpftVarcon and get the name of the in-file parameter names associated -# with these variables - - - - -rm -f include/*.o -rm -f include/*.mod - - -# Build the new file with constants - -${FC} -I include/ -J include/ -o include/FatesConstantsMod.o f90src/FatesConstantsMod.F90 - -${FC} -I include/ -J include/ -o include/AllomUnitWrap.o f90src/AllomUnitWrap.F90 - -${FC} -I include/ -J include/ -o include/FatesAllometryMod.o ../../biogeochem/FatesAllometryMod.F90 - - -#${FC} -g -o include/FatesConstantsMod.o ../main/FatesConstantsMod.F90 - -#gfortran -shared -fPIC -g -o include/EDTypesMod.o ../main/EDTypesMod.F90 - - - - -#gfortran diff --git a/functional_unit_testing/hydro/HydroUTestDriver.py b/functional_unit_testing/hydro/HydroUTestDriver.py index 5c2b026361..0d210d119c 100644 --- a/functional_unit_testing/hydro/HydroUTestDriver.py +++ b/functional_unit_testing/hydro/HydroUTestDriver.py @@ -58,10 +58,10 @@ ftc_from_psi.restype = c_double dftcdpsi_from_psi = f90_hydrounitwrap_obj.__hydrounitwrapmod_MOD_wrapdftcdpsi dftcdpsi_from_psi.restype = c_double - +ftcminwt_from_psi = f90_hydrounitwrap_obj.__hydrounitwrapmod_MOD_wrapftcminweightfrompsi +ftcminwt_from_psi.restype = c_double # Some constants -rwcft = [1.0,0.958,0.958,0.958] rwccap = [1.0,0.947,0.947,0.947] pm_leaf = 1 pm_stem = 2 @@ -150,18 +150,65 @@ def __init__(self,index,p50,avuln): iret = setwkf(ci(index),ci(tfs_type),ci(len(init_wkf_args)),c8_arr(init_wkf_args)) +def OMParams(zsoi): + + zsapric= 0.5 + om_watsat = max(0.93 - 0.1 *(zsoi/zsapric), 0.83) + om_bsw = min(2.7 + 9.3 *(zsoi/zsapric), 12.0) + om_sucsat = min(10.3 - 0.2 *(zsoi/zsapric), 10.1) + + #om_sucsat = SuctionMMtoMPa(om_sucsat) + + return(om_watsat,om_sucsat,om_bsw) + +def CCHParmsCosby84T5(zsoi,om_frac,sand_frac,clay_frac): + + # Cosby, B.J., Hornberger, G.M., Clapp, R.B., and Ginn, T.R. 1984. + # A statistical exploration of the relationships of soil moisture + # characteristics to the physical properties of soils. Water Resour. + # Res. 20:682-690. + + # cosby_1984_table5 + + # Get pedotransfer for soil matrix + watsat = 0.489 - 0.00126*sand_frac + bsw = 2.91 + 0.159*clay_frac + sucsat = 10. * ( 10.**(1.88-0.0131*sand_frac) ) + + [om_watsat,om_sucsat,om_bsw] = OMParams(zsoi) + + # Update pedotransfer to include organic material + watsat = (1.0 - om_frac) * watsat + om_watsat * om_frac + bsw = (1.0 - om_frac) * bsw + om_bsw * om_frac + sucsat = (1.0 - om_frac) * sucsat + om_sucsat * om_frac + + # Convert from mm to MPa + sucsat = SuctionMMtoMPa(sucsat) + + + # psi = psi_sat*(th/th_sat)**(-beta) + # th = th_sat*(psi / psi_sat)^(-1/beta) + + return(watsat,sucsat,bsw) + + +def SuctionMMtoMPa(suction_mm): + + denh2o = 1.0e3 # kg/m3 + grav_earth = 9.8 # m/s2 + mpa_per_pa = 1.0e-6 # MPa per Pa + m_per_mm = 1.0e-3 # meters per millimeter + + suction_mpa = (-1.0)*suction_mm*denh2o*grav_earth*mpa_per_pa*m_per_mm + + return(suction_mpa) + def main(argv): - # First check to make sure python 2.7 is being used + version = platform.python_version() verlist = version.split('.') - if( not ((verlist[0] == '2') & (verlist[1] == '7') & (int(verlist[2])>=15) ) ): - print("The PARTEH driver mus be run with python 2.7") - print(" with tertiary version >=15.") - print(" your version is {}".format(version)) - print(" exiting...") - sys.exit(2) # Read in the arguments # ======================================================================================= @@ -178,21 +225,22 @@ def main(argv): # min_theta = np.full(shape=(2),dtype=np.float64,fill_value=np.nan) - -# wrf_type = [vg_type, vg_type, cch_type, cch_type] -# wkf_type = [vg_type, tfs_type, cch_type, tfs_type] - -# th_ress = [0.01, 0.10, -9, -9] -# th_sats = [0.55, 0.55, 0.65, 0.65] -# alphas = [1.0, 1.0, 1.0, 1.0] -# psds = [2.7, 2.7, 2.7, 2.7] -# tort = [0.5, 0.5, 0.5, 0.5] -# beta = [-9, -9, 6, 9] -# avuln = [2.0, 2.0, 2.5, 2.5] -# p50 = [-1.5, -1.5, -2.25, -2.25] - - ncomp= 4 - + # wrf_type = [vg_type, vg_type, cch_type, cch_type] + # wkf_type = [vg_type, tfs_type, cch_type, tfs_type] + + # th_ress = [0.01, 0.10, -9, -9] + # th_sats = [0.55, 0.55, 0.65, 0.65] + # alphas = [1.0, 1.0, 1.0, 1.0] + # psds = [2.7, 2.7, 2.7, 2.7] + # tort = [0.5, 0.5, 0.5, 0.5] + # beta = [-9, -9, 6, 9] + # avuln = [2.0, 2.0, 2.5, 2.5] + # p50 = [-1.5, -1.5, -2.25, -2.25] + + + ncomp = 4 + ncomp_tot = 20 + rwc_fd = [1.0,0.958,0.958,0.958] rwccap = [1.0,0.947,0.947,0.947] cap_slp = [] @@ -213,16 +261,23 @@ def main(argv): # Allocate memory to our objective classes - iret = initalloc_wtfs(ci(ncomp),ci(ncomp)) + iret = initalloc_wtfs(ci(ncomp_tot),ci(ncomp_tot)) print('Allocated') + #min_psi = -10. + #min_psi_falloff = 1 + #test_psi = np.linspace(min_psi, 0, num=1000) + #weight = y = e^(2*(-10-x)) + + + # Define the funcions and their parameters # vg_wrf(1,alpha=1.0,psd=2.7,th_sat=0.55,th_res=0.1) # vg_wkf(1,alpha=1.0,psd=2.7,th_sat=0.55,th_res=0.1,tort=0.5) - cch_wrf(1,th_sat=0.55, psi_sat=-1.56e-3, beta=6) - cch_wkf(1,th_sat=0.55, psi_sat=-1.56e-3, beta=6) + cch_wrf(1,th_sat=0.55, psi_sat=-1.56e-3, beta=3) + cch_wkf(1,th_sat=0.55, psi_sat=-1.56e-3, beta=3) # cch_wrf(3,th_sat=0.55, psi_sat=-1.56e-3, beta=6) # tfs_wkf(3,p50=-2.25, avuln=2.0) @@ -361,10 +416,120 @@ def main(argv): ax1.set_ylim([0,2]) # ax1.set_ylim([0,10]) ax1.legend(loc='upper right') - plt.show() - + ndepth = 1000 + zdepth = np.linspace(0.01,10.0,num = ndepth) + + om_watsat_z = np.zeros(shape=(ndepth,1)) + om_sucsat_z = np.zeros(shape=(ndepth,1)) + om_bsw_z = np.zeros(shape=(ndepth,1)) + + for icl in range(ndepth): + [om_watsat_z[icl],om_sucsat_z[icl],om_bsw_z[icl]] = OMParams(zdepth[icl]) + + fig4,((ax1,ax2),(ax3,ax4)) = plt.subplots(2,2,figsize=(9,6)) + + ax1.plot(om_watsat_z,-zdepth) + ax2.plot(om_sucsat_z,-zdepth) + ax3.plot(om_bsw_z,-zdepth) + ax4.axis('off') + + + ax1.set_ylabel('soil depth') + ax1.set_xlabel('Saturated WC [m3/m3]') + ax2.set_xlabel('Saturated Suction [mm]') + ax3.set_ylabel('soil depth') + ax3.set_xlabel('beta ') + # ax1.set_xlim([-10,3]) + # ax1.set_ylim([0,2]) + # ax1.set_ylim([0,10]) + # ax1.legend(loc='upper right') + plt.tight_layout() + + + # Soil texture distributions + + #clay_frac = np.zeros(shape=(100,1)) + #sand_frac = np.zeros(shape=(100,1)) + #om_frac = np.zeros(shape=(100,1)) + #clay_frac = np.linspace(0.0, 0.7, num=npts) + + watsat_v = [] + sucsat_v = [] + bsw_v = [] + + ntex = 5 + for icl in range(ntex): + clay_frac = float(icl)/float(ntex) + for isa in range(ntex): + sand_frac = float(isa)/float(ntex) + + if( (clay_frac+sand_frac)<1.0 ): + for om_frac in [0.0,1.0]: + for zsoi in [0.01,10.0]: + [watsat,sucsat,bsw] = CCHParmsCosby84T5(zsoi,om_frac,sand_frac,clay_frac) + watsat_v.append(watsat) + sucsat_v.append(sucsat) + bsw_v.append(bsw) + + + fig5,((ax1,ax2),(ax3,ax4)) = plt.subplots(2,2,figsize=(9,6)) + + ax1.hist(watsat_v,bins=50) + ax2.hist(sucsat_v,bins=50) + ax3.hist(bsw_v,bins=50) + ax4.axis('off') + + + ax1.set_xlabel('Sat. WC [m3/m3]') + ax2.set_xlabel('Sat. Sucation [MPa]') + ax3.set_xlabel('Beta') + + plt.tight_layout() + + ind = [] + ind.append(np.argmin(bsw_v)) + ind.append(np.argmax(bsw_v)) + ind.append(np.argmin(sucsat_v)) + ind.append(np.argmax(sucsat_v)) + ind.append(np.argmin(watsat_v)) + ind.append(np.argmax(watsat_v)) + + # Now lets test the lowest possible water contents using these + + #psi_v = -np.linspace(0.01,24,24) + psi_v = -np.logspace(-3,1.5,60) + fig10,(ax1,ax2,ax3) = plt.subplots(3,1,figsize=(6,9)) + + + ii=4 + th_v = [] + ftc_v = [] + ftc_min_wt_v = [] + for i in ind: + ii = ii+1 + cch_wrf(ii,th_sat=watsat_v[i], psi_sat=sucsat_v[i], beta=bsw_v[i]) + cch_wkf(ii,th_sat=watsat_v[i], psi_sat=sucsat_v[i], beta=bsw_v[i]) + print('---th sat: {}, psi sat: {}, beat: {}'.format(watsat_v[i],sucsat_v[i],bsw_v[i])) + for psi in psi_v: + th_v.append(th_from_psi(ci(ii),c8(psi))) + ftc_v.append(ftc_from_psi(ci(ii),c8(psi))) + ftc_min_wt_v.append(ftcminwt_from_psi(ci(ii),c8(psi))) + + ax1.plot(psi_v,th_v) + ax2.plot(psi_v,ftc_v) + ax3.plot(psi_v,ftc_min_wt_v) + th_v = [] + ftc_v = [] + ftc_min_wt_v = [] + + ax2.set_xlabel('Suction MPa') + ax1.set_ylabel('Theta') + ax2.set_ylabel('FTC') + ax3.set_ylabel('FTC Min Weight') + + plt.show() # code.interact(local=dict(globals(), **locals())) diff --git a/functional_unit_testing/hydro/f90_src/HydroUnitWrapMod.F90 b/functional_unit_testing/hydro/f90_src/HydroUnitWrapMod.F90 index 03e95a6a32..02167209ef 100644 --- a/functional_unit_testing/hydro/f90_src/HydroUnitWrapMod.F90 +++ b/functional_unit_testing/hydro/f90_src/HydroUnitWrapMod.F90 @@ -14,7 +14,8 @@ module HydroUnitWrapMod use FatesHydroWTFMod, only : wrf_type,wrf_type_vg,wrf_type_cch use FatesHydroWTFMod, only : wkf_type,wkf_type_vg,wkf_type_cch,wkf_type_tfs use FatesHydroWTFMod, only : wrf_arr_type,wkf_arr_type,wrf_type_tfs - + use FatesHydroWTFMod, only : get_min_ftc_weight + implicit none public save @@ -107,6 +108,8 @@ subroutine SetWKF(index,itype,npvals,pvals) stop end if + wkfs(index)%p%wrf => wrfs(index)%p + return end subroutine SetWKF @@ -167,5 +170,15 @@ function WrapFTCFromPSI(index,psi) result(ftc) return end function WrapFTCFromPSI + function WrapFTCMinWeightFromPsi(index,psi) result(min_ftc_weight) + integer, intent(in) :: index + real(r8),intent(in) :: psi + real(r8) :: min_ftc_weight,dmin_ftc_weight_dpsi + + print*,"PSI_MIN: ",wkfs(index)%p%wrf%psi_min + + call get_min_ftc_weight(wkfs(index)%p%wrf%psi_min,psi,min_ftc_weight,dmin_ftc_weight_dpsi) + + end function WrapFTCMinWeightFromPsi end module HydroUnitWrapMod diff --git a/functional_unit_testing/radiation/RadiationUTestDriver.py b/functional_unit_testing/radiation/RadiationUTestDriver.py new file mode 100644 index 0000000000..b7c32d74d3 --- /dev/null +++ b/functional_unit_testing/radiation/RadiationUTestDriver.py @@ -0,0 +1,1133 @@ +# ======================================================================================= +# +# For usage: $python RadiationUTestDriver.py --help +# +# This script runs unit tests on the two-stream functions. +# +# +# ======================================================================================= + +import matplotlib as mpl +#mpl.use('Agg') +import matplotlib.pyplot as plt +from datetime import datetime +import argparse +#from matplotlib.backends.backend_pdf import PdfPages +import platform +import xml.etree.ElementTree as ET +import numpy as np +import matplotlib +import os +import sys +import getopt +import code # For development: code.interact(local=locals()) code.interact(local=dict(globals(), **locals())) +import time +import importlib +import csv +import ctypes +from ctypes import * +from operator import add +sys.path.append('../shared/py_src') +from PyF90Utils import c8, ci, cchar, c8_arr, ci_arr, ccharnb + +font = {'family' : 'sans-serif', + 'weight' : 'normal', + 'size' : 11} + +matplotlib.rc('font', **font) + + +# Instantiate the F90 modules +f90_shr_obj = ctypes.CDLL('bld/WrapShrMod.o',mode=ctypes.RTLD_GLOBAL) +f90_mem_obj = ctypes.CDLL('bld/FatesRadiationMemMod.o',mode=ctypes.RTLD_GLOBAL) +f90_twostr_obj = ctypes.CDLL('bld/TwoStreamMLPEMod.o',mode=ctypes.RTLD_GLOBAL) +f90_wrap_obj = ctypes.CDLL('bld/RadiationWrapMod.o',mode=ctypes.RTLD_GLOBAL) + + +# Create aliases for the calls and define arguments if it helps with clarity +alloc_twostream_call = f90_wrap_obj.__radiationwrapmod_MOD_initallocate +dealloc_twostream_call = f90_wrap_obj.__radiationwrapmod_MOD_dealloc +alloc_radparams_call = f90_twostr_obj.__twostreammlpemod_MOD_allocateradparams +set_radparams_call = f90_wrap_obj.__radiationwrapmod_MOD_setradparam +set_radparams_call.argtypes = [POINTER(c_double),POINTER(c_int),POINTER(c_int),c_char_p,c_long] +param_prep_call = f90_twostr_obj.__twostreammlpemod_MOD_radparamprep + +setup_canopy_call = f90_wrap_obj.__radiationwrapmod_MOD_setupcanopy +setup_canopy_call.argtypes = [POINTER(c_int),POINTER(c_int),POINTER(c_int), \ + POINTER(c_double),POINTER(c_double),POINTER(c_double)] + +grndsnow_albedo_call = f90_wrap_obj.__radiationwrapmod_MOD_setgroundsnow +grndsnow_albedo_call.argtypes = [POINTER(c_int),POINTER(c_double),c_char_p,c_long] + +canopy_prep_call = f90_wrap_obj.__radiationwrapmod_MOD_wrapcanopyprep +zenith_prep_call = f90_wrap_obj.__radiationwrapmod_MOD_wrapzenithprep +solver_call = f90_wrap_obj.__radiationwrapmod_MOD_wrapsolve +setdown_call = f90_wrap_obj.__radiationwrapmod_MOD_wrapsetdownwelling + +getintens_call = f90_wrap_obj.__radiationwrapmod_MOD_wrapgetintensity +getabsrad_call = f90_wrap_obj.__radiationwrapmod_MOD_wrapgetabsrad +getparams_call = f90_wrap_obj.__radiationwrapmod_MOD_wrapgetparams +forceparam_call = f90_wrap_obj.__radiationwrapmod_MOD_wrapforceparams +forceparam_call.argtypes = [POINTER(c_int),POINTER(c_int),POINTER(c_int),POINTER(c_double),c_char_p,c_long] + +leaf_rhonir = [0.46, 0.41, 0.39, 0.46, 0.41, 0.41, 0.46, 0.41, 0.41, 0.28, 0.28, 0.28 ] +leaf_rhovis = [0.11, 0.09, 0.08, 0.11, 0.08, 0.08, 0.11, 0.08, 0.08, 0.05, 0.05, 0.05 ] +leaf_taunir = [0.33, 0.32, 0.42, 0.33, 0.43, 0.43, 0.33, 0.43, 0.43, 0.4, 0.4, 0.4 ] +leaf_tauvis = [0.06, 0.04, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.05, 0.05, 0.05] +leaf_xl = [0.32, 0.01, 0.01, 0.32, 0.2, 0.59, 0.32, 0.59, 0.59, -0.23, -0.23, -0.23] +leaf_clumping_index = [0.85, 0.85, 0.8, 0.85, 0.85, 0.9, 0.85, 0.9, 0.9, 0.75, 0.75, 0.75] +stem_rhonir = [0.49, 0.36, 0.36, 0.49, 0.49, 0.49, 0.49, 0.49, 0.49, 0.53, 0.53, 0.53] +stem_rhovis = [0.21, 0.12, 0.12, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.31, 0.31, 0.31] +stem_taunir = [0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.25, 0.25, 0.25] +stem_tauvis = [0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.12, 0.12, 0.12] + + +visb = 1 +nirb = 2 + +normalized_boundary = 1 +absolute_boundary = 2 + +class elem_type: + def __init__(self,n_vai): + + self.area = -9.0 + self.lai = -9.0 + self.sai = -9.0 + + self.n_vai = n_vai + self.avai = np.zeros([n_vai]) + self.r_dn = np.zeros([n_vai]) + self.r_up = np.zeros([n_vai]) + self.r_b = np.zeros([n_vai]) + self.r_abs = np.zeros([n_vai]) + #self.sunfrac = np.zeros([n_vai]) + +class patch_type: + def __init__(self,ground_albedo_diff,ground_albedo_beam): + self.ground_albedo_beam = ground_albedo_diff + self.ground_albedo_beam = ground_albedo_beam + self.cohorts = [] + + # uses the form: + # patch.cohorts.append(cohort_type(n_vai,lai,sai)) + +class cohort_type: + def __init__(self,n_vai,area_frac,lai,sai,pft): + + self.n_vai = n_vai + #self.avai = np.zeros([n_vai]) + dvai = (lai+sai)/n_vai + self.avai = np.linspace(dvai,lai+sai,num=n_vai) + self.rd_abs_leaf = np.zeros([n_vai]) + self.rb_abs_leaf = np.zeros([n_vai]) + self.r_abs_stem = np.zeros([n_vai]) + self.sunfrac = np.zeros([n_vai]) + self.pft = pft + +def main(argv): + + # All tests will use 2 bands 1=vis, 2=nir + + # Initialize radiation parameters + n_bands = 2 + n_pft = 12 + + iret = alloc_radparams_call(ci(n_pft),ci(n_bands)) + + for ft in range(n_pft): + + pft=ft+1 + # rho (vis+nir) + iret = set_radparams_call(c_double(leaf_rhovis[ft]),c_int(pft),c_int(visb),*ccharnb("rhol")) + iret = set_radparams_call(c_double(leaf_rhonir[ft]),c_int(pft),c_int(nirb),*ccharnb("rhol")) + iret = set_radparams_call(c_double(stem_rhovis[ft]),c_int(pft),c_int(visb),*ccharnb("rhos")) + iret = set_radparams_call(c_double(stem_rhonir[ft]),c_int(pft),c_int(nirb),*ccharnb("rhos")) + # tau (vis+nir) + iret = set_radparams_call(c_double(leaf_tauvis[ft]),c_int(pft),c_int(visb),*ccharnb("taul")) + iret = set_radparams_call(c_double(leaf_taunir[ft]),c_int(pft),c_int(nirb),*ccharnb("taul")) + iret = set_radparams_call(c_double(stem_tauvis[ft]),c_int(pft),c_int(visb),*ccharnb("taus")) + iret = set_radparams_call(c_double(stem_taunir[ft]),c_int(pft),c_int(nirb),*ccharnb("taus")) + # orientations + iret = set_radparams_call(c_double(leaf_xl[ft]),c_int(pft),c_int(0),*ccharnb("xl")) + iret = set_radparams_call(c_double(leaf_clumping_index[ft]),c_int(pft),c_int(0),*ccharnb("clumping_index")) + + # Process the core 2Stream parameters from parameters in file + iret = param_prep_call(ci(n_pft)) + + if(False): + TestCrash() + + if(False): + ParallelElementPerturbDist() + + if(False): + SunFracTests() + + if(True): + SingleElementPerturbTest() + + if(False): + SerialParallelCanopyTest() + + plt.show() + +def TestCrash(): + + # This is used to diagnose a specific failure. This is probably + # reconstructed from the output dump of a failed solve. + + xmlfile = "f45error_elements.xml" + xmlroot = ET.parse(xmlfile).getroot() + print("\nOpenend: "+xmlfile) + + cosz = float(xmlroot.find('cosz').text.strip()) + ib = int(xmlroot.find('band_id').text.strip()) + #elem = xmlroot.find('time_control') + + # Iterate through canopy layers + areas = [] + print("Loading Layers") + for can in xmlroot.iter('can'): + print("canopy layer: {}".format(int(can.attrib['id'].strip()))) + # Iterate through elements in each layer + can_id = int(can.attrib['id'].strip()) + for elem in can.iter('elem'): + elem_id = int(elem.attrib['id'].strip()) + textlist = elem.text.split(',') + pft = int(textlist[0].strip()) + lai = float(textlist[1].strip()) + sai = float(textlist[2].strip()) + area = float(textlist[3].strip()) + + areas.append(area) + + code.interact(local=dict(globals(), **locals())) + + +def SerialParallelCanopyTest(): + + + # Lets first construct a bunch of cohorts, 5 cohorts + # equal area, but folding by 2 in LAI + + cohort_lai = np.array([0.25,0.5,1.0,2.0,4.0]) + cohort_area = np.array([0.2,0.2,0.2,0.2,0.2]) + n_cohorts = len(cohort_lai) + + sai_frac = 0.1 + + pft = 1 + + # Serial approach: 5 layers with veg and ghost + n_col = 2 + n_layer = 5 + iret = alloc_twostream_call(ci(n_layer),ci(n_col)) + + #class cohort_type: + #def __init__(self,n_vai,area_frac,lai,sai,pft) + + # Five elements (cohorts), each take up 20% of the space + area_frac = 0.2 + serialc = [] + serialc.append(cohort_type(100,area_frac,cohort_lai[0],cohort_lai[0]*sai_frac,pft)) + serialc.append(cohort_type(100,area_frac,cohort_lai[1],cohort_lai[1]*sai_frac,pft)) + serialc.append(cohort_type(100,area_frac,cohort_lai[2],cohort_lai[2]*sai_frac,pft)) + serialc.append(cohort_type(100,area_frac,cohort_lai[3],cohort_lai[3]*sai_frac,pft)) + serialc.append(cohort_type(100,area_frac,cohort_lai[4],cohort_lai[4]*sai_frac,pft)) + + parallelc = [] + parallelc.append(cohort_type(100,area_frac,cohort_lai[0],cohort_lai[0]*sai_frac,pft)) + parallelc.append(cohort_type(100,area_frac,cohort_lai[1],cohort_lai[1]*sai_frac,pft)) + parallelc.append(cohort_type(100,area_frac,cohort_lai[2],cohort_lai[2]*sai_frac,pft)) + parallelc.append(cohort_type(100,area_frac,cohort_lai[3],cohort_lai[3]*sai_frac,pft)) + parallelc.append(cohort_type(100,area_frac,cohort_lai[4],cohort_lai[4]*sai_frac,pft)) + + # Setup serial canopy "s_elems" + + s_elems = [] + #s_elems.append([]) + + n_vai = 100 + + + + dvai = 0.05 + for i in range(n_layer): + s_elems.append([]) + # Serial Setup + ican = i+1 + icol = 1 + area = np.sum(cohort_area[i:]) + if(i==0): + lai = cohort_lai[i] + else: + lai = cohort_lai[i]-cohort_lai[i-1] + + sai = lai*sai_frac + + n_vai = int((lai+sai)/dvai) + s_elems[i].append(elem_type(n_vai)) + + s_elems[i][-1].lai = lai + s_elems[i][-1].sai = sai + s_elems[i][-1].area = area + s_elems[i][-1].avai = np.linspace(0,lai+sai,num=n_vai) + iret = setup_canopy_call(c_int(ican),c_int(icol),c_int(pft),c_double(area),c_double(lai),c_double(sai)) + + icol = 2 + area = 1-np.sum(cohort_area[i:]) + s_elems[i].append(elem_type(1)) + s_elems[i][-1].lai = 0.0 + s_elems[i][-1].sai = 0.0 + s_elems[i][-1].area = area + lai = 0.0 + sai = 0.0 + air_pft = 0 + iret = setup_canopy_call(c_int(ican),c_int(icol),c_int(air_pft),c_double(area),c_double(lai),c_double(sai)) + + # Decide on a band: + ib = visb + + cd_r_beam = c_double(-9.0) + cd_r_diff_up = c_double(-9.0) + cd_r_diff_dn = c_double(-9.0) + cd_kb = c_double(-9.0) + cd_kd = c_double(-9.0) + cd_om = c_double(-9.0) + cd_betad = c_double(-9.0) + cd_betab = c_double(-9.0) + cd_rd_abs_leaf = c_double(-9.0) + cd_rb_abs_leaf = c_double(-9.0) + cd_r_abs_stem = c_double(-9.0) + cd_r_abs_snow = c_double(-9.0) + cd_leaf_sun_frac = c_double(-9.0) + + cd_albedo_beam = c_double(-9.0) + cd_albedo_diff = c_double(-9.0) + cd_canabs_beam = c_double(-9.0) + cd_canabs_diff = c_double(-9.0) + cd_ffbeam_beam = c_double(-9.0) + cd_ffdiff_beam = c_double(-9.0) + cd_ffdiff_diff = c_double(-9.0) + + + R_beam = 1. + R_diff = 1. + cosz = np.cos(0.0) + + ground_albedo_diff = 0.3 + ground_albedo_beam = 0.3 + frac_snow = 0.0 + + iret = grndsnow_albedo_call(c_int(visb),c_double(ground_albedo_diff),*ccharnb('albedo_grnd_diff')) + iret = grndsnow_albedo_call(c_int(visb),c_double(ground_albedo_beam),*ccharnb('albedo_grnd_beam')) + iret = grndsnow_albedo_call(c_int(nirb),c_double(ground_albedo_diff),*ccharnb('albedo_grnd_diff')) + iret = grndsnow_albedo_call(c_int(nirb),c_double(ground_albedo_beam),*ccharnb('albedo_grnd_beam')) + iret = canopy_prep_call(c8(frac_snow)) + iret = zenith_prep_call(c8(cosz)) + iret = solver_call(ci(ib),ci(normalized_boundary),c8(1.0),c8(1.0), \ + byref(cd_albedo_beam),byref(cd_albedo_diff), \ + byref(cd_canabs_beam),byref(cd_canabs_diff), \ + byref(cd_ffbeam_beam),byref(cd_ffdiff_beam),byref(cd_ffdiff_diff)) + iret = setdown_call(ci(ib),c8(R_beam),c8(R_diff)) + + for i in range(n_layer): + + ican = i+1 + icol = 1 + for iv in range(s_elems[i][0].n_vai): + iret = getintens_call(ci(ican),ci(icol),ci(ib),c8(s_elems[i][0].avai[iv]),byref(cd_r_diff_dn),byref(cd_r_diff_up),byref(cd_r_beam)) + s_elems[i][0].r_dn[iv] = cd_r_diff_dn.value + s_elems[i][0].r_up[iv] = cd_r_diff_up.value + s_elems[i][0].r_b[iv] = cd_r_beam.value + if(iv>0): + s_elems[i][0].r_abs[iv-1] = (s_elems[i][0].r_dn[iv]-s_elems[i][0].r_dn[iv-1]) + \ + (s_elems[i][0].r_up[iv-1]-s_elems[i][0].r_up[iv]) + \ + (s_elems[i][0].r_b[iv]-s_elems[i][0].r_b[iv-1]) + + icol=2 + for iv in range(s_elems[i][1].n_vai): + iret = getintens_call(ci(ican),ci(icol),ci(ib),c8(s_elems[i][1].avai[iv]),byref(cd_r_diff_dn),byref(cd_r_diff_up),byref(cd_r_beam)) + s_elems[i][1].r_dn[iv] = cd_r_diff_dn.value + s_elems[i][1].r_up[iv] = cd_r_diff_up.value + s_elems[i][1].r_b[iv] = cd_r_beam.value + print('air: {} {} {}'.format(ican,icol,cd_r_beam.value)) + if(iv>0): + s_elems[i][1].r_abs[iv-1] = (s_elems[i][1].r_dn[iv]-s_elems[i][1].r_dn[iv-1]) + \ + (s_elems[i][1].r_up[iv-1]-s_elems[i][1].r_up[iv]) + \ + (s_elems[i][1].r_b[iv]-s_elems[i][1].r_b[iv-1]) + + # Lets get the absorbed radiation from the cohorts + + #class cohort_type: + #def __init__(self,n_vai,lai,sai): + #self.n_vai = n_vai + ##self.avai = np.zeros([n_vai]) + #dvai = (lai+sai/n_vai) + #self.avai = np.linspace(dvai,lai+sai,num=n_vai) + #self.rabs_leaf = np.zeros([n_vai]) + #self.rabs_stem = np.zeros([n_vai]) + + for i in range(len(serialc)): + for iv in range(serialc[i].n_vai): + + vai_bot = serialc[i].avai[iv] + + ican = np.sum(serialc[i].avai[iv]>(cohort_lai*(1+sai_frac))) + if(ican>0): + vai_above = cohort_lai[ican-1]*(1+sai_frac) + else: + vai_above = 0. + + vai_bot = serialc[i].avai[iv]-vai_above + if(iv==0): + vai_top = 0 + else: + vai_top = np.max([0,serialc[i].avai[iv-1]-vai_above]) + + #print(i,iv,serialc[i].avai[iv],vai_above,vai_bot,vai_top,ican,cohort_lai*(1+sai_frac)) + icol = 1 # b/c 2 is air + iret = getabsrad_call(ci(ican+1),ci(icol),ci(ib),c8(vai_top),c8(vai_bot), \ + byref(cd_rd_abs_leaf),byref(cd_rb_abs_leaf),byref(cd_r_abs_stem), \ + byref(cd_r_abs_snow),byref(cd_leaf_sun_frac)) + serialc[i].rd_abs_leaf[iv] = cd_rd_abs_leaf.value + serialc[i].rb_abs_leaf[iv] = cd_rb_abs_leaf.value + serialc[i].r_abs_stem[iv] = cd_r_abs_stem.value + serialc[i].sunfrac[iv] = cd_leaf_sun_frac.value + + + + # Plot out absorbances and sun fractions in cohorts only + # --------------------------------------------- + + + + max_rd_abs_leaf = 0 + max_rb_abs_leaf = 0 + max_r_abs_stem = 0 + max_r_abs = 0 + maxlai = 0 + max_sunfrac = 0 + for i in range(n_cohorts): + max_rd_abs_leaf = np.max([max_rd_abs_leaf,np.max(serialc[i].rd_abs_leaf) ]) + max_rb_abs_leaf = np.max([max_rb_abs_leaf,np.max(serialc[i].rb_abs_leaf) ]) + max_r_abs_stem = np.max([max_r_abs_stem,np.max(serialc[i].r_abs_stem) ]) + max_r_abs = np.max([max_r_abs,np.max(serialc[i].r_abs_stem+serialc[i].rd_abs_leaf+serialc[i].rb_abs_leaf) ]) + maxlai = np.max([maxlai,np.max(serialc[i].avai) ]) + max_sunfrac = np.max([max_sunfrac,np.max(serialc[i].sunfrac)]) + + fig, axs = plt.subplots(ncols=n_cohorts,nrows=1,figsize=(6,3)) + ax1s = axs.reshape(-1) + + y0 = 0.1 + xpad = 0.1 + dx = (1.0-2*xpad)/float(n_cohorts) + dy = 0.8 + + ic=0 + x0 = xpad + for i in range(n_cohorts): + + ax = ax1s[ic] + ap = ax.plot(serialc[i].rd_abs_leaf+serialc[i].rb_abs_leaf+serialc[i].r_abs_stem ,serialc[i].avai) + ax.set_ylim([0,maxlai]) + ax.invert_yaxis() + ax.set_xlabel('[W/m2]') + ax.set_xlim([0,max_r_abs]) + + ax.set_title('Cohort {}'.format(i+1)) + if(i==0): + + ax.set_ylabel('Absorbed Radiation\nVAI [m2/m2]') + else: + ax.set_yticklabels([]) + + ax.grid(True) + ax.set_position([x0,y0,dx,dy]) + x0 = x0+dx + ic=ic+1 + + fig, axs = plt.subplots(ncols=n_cohorts,nrows=1,figsize=(6,3)) + ax1s = axs.reshape(-1) + + y0 = 0.1 + xpad = 0.1 + dx = (1.0-2*xpad)/float(n_cohorts) + dy = 0.8 + + # Sun fractions + ic=0 + x0 = xpad + for i in range(n_cohorts): + + ax = ax1s[ic] + ap = ax.plot(serialc[i].sunfrac ,serialc[i].avai) + ax.set_ylim([0,maxlai]) + ax.invert_yaxis() + ax.set_xlabel('[m2/m2]') + ax.set_xlim([0,max_sunfrac]) + + ax.set_title('Cohort {}'.format(i+1)) + if(i==0): + + ax.set_ylabel('Sunlit fraction of leaves [m2/m2]') + else: + ax.set_yticklabels([]) + + ax.grid(True) + ax.set_position([x0,y0,dx,dy]) + x0 = x0+dx + ic=ic+1 + + dealloc_twostream_call() + + + + if(False): + PlotRadMaps(s_elems,0,'Beam Radiation [W/m2]') + PlotRadMaps(s_elems,1,'Downwelling Diffuse Radiation [W/m2]') + PlotRadMaps(s_elems,2,'Upwelling Diffuse Radiation [W/m2]') + + # Setup paralell canopy p_elems + p_elems = [] + iret = alloc_twostream_call(ci(1),ci(n_cohorts)) + # Only one layer, so just one append + p_elems.append([]) + for i in range(n_cohorts): + + icol = i+1 + ican = 1 + # Parallel + + p_elems[0].append(elem_type(n_vai)) + lai = cohort_lai[i] + sai = sai_frac * cohort_lai[i] + area = cohort_area[i] + p_elems[0][-1].lai = lai + p_elems[0][-1].sai = sai + p_elems[0][-1].area = area + p_elems[0][-1].avai = np.linspace(0,cohort_lai[i]*(1.+sai_frac),num=n_vai) + iret = setup_canopy_call(c_int(ican),c_int(icol),c_int(pft),c_double(area),c_double(lai),c_double(sai)) + + iret = grndsnow_albedo_call(c_int(visb),c_double(ground_albedo_diff),*ccharnb('albedo_grnd_diff')) + iret = grndsnow_albedo_call(c_int(visb),c_double(ground_albedo_beam),*ccharnb('albedo_grnd_beam')) + iret = grndsnow_albedo_call(c_int(nirb),c_double(ground_albedo_diff),*ccharnb('albedo_grnd_diff')) + iret = grndsnow_albedo_call(c_int(nirb),c_double(ground_albedo_beam),*ccharnb('albedo_grnd_beam')) + iret = canopy_prep_call(c8(frac_snow)) + iret = zenith_prep_call(c8(cosz)) + iret = solver_call(ci(ib),ci(normalized_boundary),c8(1.0),c8(1.0), \ + byref(cd_albedo_beam),byref(cd_albedo_diff), \ + byref(cd_canabs_beam),byref(cd_canabs_diff), \ + byref(cd_ffbeam_beam),byref(cd_ffdiff_beam),byref(cd_ffdiff_diff)) + iret = setdown_call(ci(ib),c8(R_beam),c8(R_diff)) + + ican = 1 + for i in range(n_cohorts): + icol = i+1 + for iv in range(p_elems[0][i].n_vai): + iret = getintens_call(ci(ican),ci(icol),ci(ib),c8(p_elems[0][i].avai[iv]),byref(cd_r_diff_dn),byref(cd_r_diff_up),byref(cd_r_beam)) + p_elems[0][i].r_dn[iv] = cd_r_diff_dn.value + p_elems[0][i].r_up[iv] = cd_r_diff_up.value + p_elems[0][i].r_b[iv] = cd_r_beam.value + if(iv>0): + p_elems[0][i].r_abs[iv-1] = (p_elems[0][i].r_dn[iv]-p_elems[0][i].r_dn[iv-1]) + \ + (p_elems[0][i].r_up[iv-1]-p_elems[0][i].r_up[iv]) + \ + (p_elems[0][i].r_b[iv]-p_elems[0][i].r_b[iv-1]) + + dealloc_twostream_call() + if(True): + PlotRadMaps(p_elems,0,'Beam Radiation [W/m2]') + PlotRadMaps(p_elems,1,'Downwelling Diffuse Radiation [W/m2]') + PlotRadMaps(p_elems,2,'Upwelling Diffuse Radiation [W/m2]') + +def SunFracTests(): + + + n_col = 1 + n_layer = 1 + iret = alloc_twostream_call(ci(n_layer),ci(n_col)) + + ican = 1 # Single canopy layer + icol = 1 # Single PFT + pft = 1 # Use PFT number 1 + area = 1.0 # Assume only 90% of the ground is covered + lai = 5.0 # LAI + sai = 0.5 # SAI + vai = lai+sai + iret = setup_canopy_call(c_int(1),c_int(1),c_int(pft),c_double(area),c_double(lai),c_double(sai)) + + # Decide on a band: + ib = visb + cd_r_beam = c_double(-9.0) + cd_r_diff_up = c_double(-9.0) + cd_r_diff_dn = c_double(-9.0) + cd_kb = c_double(-9.0) + cd_kd = c_double(-9.0) + cd_om = c_double(-9.0) + cd_betad = c_double(-9.0) + cd_betab = c_double(-9.0) + + R_beam = 1. + R_diff = 0. + cosz = np.cos(0.0) + n_vai = 200 + n_cosz = 100 + + dv = vai/n_vai + vai_a = np.linspace(dv,vai,num=n_vai) + cosz_a = np.linspace(0,1.0,num=n_cosz) + kb_a = np.zeros([n_cosz]) + lsf_a = np.zeros([n_cosz,n_vai]) + rbeamsf_a = np.zeros([n_cosz,n_vai]) + rbeam_a = np.zeros([n_cosz,n_vai]) + + + + cd_rd_abs_leaf = c_double(-9.0) + cd_rb_abs_leaf = c_double(-9.0) + cd_r_abs_stem = c_double(-9.0) + cd_r_abs_snow = c_double(-9.0) + cd_leaf_sun_frac = c_double(-9.0) + cd_albedo_beam = c_double(-9.0) + cd_albedo_diff = c_double(-9.0) + cd_canabs_beam = c_double(-9.0) + cd_canabs_diff = c_double(-9.0) + cd_ffbeam_beam = c_double(-9.0) + cd_ffdiff_beam = c_double(-9.0) + cd_ffdiff_diff = c_double(-9.0) + cd_r_diff_dn = c_double(-9.0) + cd_r_diff_up = c_double(-9.0) + cd_r_beam = c_double(-9.0) + + ground_albedo_diff = 0.3 + ground_albedo_beam = 0.3 + frac_snow = 0.5 + + iret = grndsnow_albedo_call(c_int(ib),c_double(ground_albedo_diff),*ccharnb('albedo_grnd_diff')) + iret = grndsnow_albedo_call(c_int(ib),c_double(ground_albedo_beam),*ccharnb('albedo_grnd_beam')) + + iret = canopy_prep_call(c8(frac_snow)) + + for ic,cosz in enumerate(cosz_a): + iret = zenith_prep_call(c8(cosz)) + + iret = solver_call(ci(ib),ci(normalized_boundary),c8(1.0),c8(1.0), \ + byref(cd_albedo_beam),byref(cd_albedo_diff), \ + byref(cd_canabs_beam),byref(cd_canabs_diff), \ + byref(cd_ffbeam_beam),byref(cd_ffdiff_beam),byref(cd_ffdiff_diff)) + + iret = setdown_call(ci(ib),c8(R_beam),c8(R_diff)) + + iret = getparams_call(ci(ican),ci(icol),ci(ib),byref(cd_kb), \ + byref(cd_kd),byref(cd_om),byref(cd_betad),byref(cd_betab)) + + kb_a[ic] = cd_betab.value + + for iv in range(n_vai): + + if(iv==0): + vai_top = 0. + else: + vai_top = vai_a[iv-1] + + vai_bot = vai_a[iv] + + + iret = getabsrad_call(ci(ican),ci(icol),ci(ib),c8(vai_top),c8(vai_bot), \ + byref(cd_rd_abs_leaf),byref(cd_rb_abs_leaf),byref(cd_r_abs_stem), \ + byref(cd_r_abs_snow),byref(cd_leaf_sun_frac)) + + iret = getintens_call(ci(ican),ci(icol),ci(ib),c8(vai_bot),byref(cd_r_diff_dn), \ + byref(cd_r_diff_up),byref(cd_r_beam)) + + lsf_a[ic,iv] = cd_leaf_sun_frac.value + + #sun_area = (vai_bot - vai_top)*cd_leaf_sun_frac.value/cd_kb.value + sun_area = (vai_bot - vai_top)*cd_kb.value + rbeam_a[ic,iv] = cd_r_beam.value + + if(iv==0): + rbeamsf_a[ic,iv] = R_beam*(1.0 - sun_area) + #print(rbeamsf_a[ic,iv],sun_area,vai_bot,vai_top,cd_leaf_sun_frac.value,vai_a[iv]) + #exit(0) + else: + rbeamsf_a[ic,iv] = rbeamsf_a[ic,iv-1]*(1.0 - sun_area) + #print(rbeamsf_a[ic,iv]) + + fig, axs = plt.subplots(ncols=2,nrows=2,figsize=(9,5)) + ax1s = axs.reshape(-1) + + ic0 = [2,25,50,99] + + for ia,ax in enumerate(ax1s): + + #Plot LSF profiles at 4 different cosz's + + ap = ax.plot(lsf_a[ic0[ia],:],vai_a[:],rbeam_a[ic0[ia],:],vai_a[:]) + ax.invert_yaxis() + ax.set_title('cos(z) = {:.2f}'.format(cosz_a[ic0[ia]])) + ax.set_xlabel('[Sun Fraction]') + ax.set_xlim([0,1]) + ax.grid(True) + if(ia<2): + ax.set_xlabel('') + ax.set_xticklabels([]) + #if(ia==0): + # ax.set_ylabel('Absorbed Radiation\nVAI [m2/m2]') + #else: + # ax.set_yticklabels([]) + plt.tight_layout() + + fig2, axs = plt.subplots(ncols=2,nrows=2,figsize=(9,5)) + ax1s = axs.reshape(-1) + + ic0 = [2,25,50,99] + + for ia,ax in enumerate(ax1s): + + #Plot LSF profiles at 4 different cosz's + + ap = ax.plot(rbeam_a[ic0[ia],:],vai_a[:],rbeamsf_a[ic0[ia],:],vai_a[:]) + ax.invert_yaxis() + ax.set_title('cos(z) = {:.2f}'.format(cosz_a[ic0[ia]])) + ax.set_xlabel('[Beam Fraction]') + ax.set_xlim([0,1]) + ax.grid(True) + if(ia<2): + ax.set_xlabel('') + ax.set_xticklabels([]) + #if(ia==0): + # ax.set_ylabel('Absorbed Radiation\nVAI [m2/m2]') + #else: + # ax.set_yticklabels([]) + plt.tight_layout() + + + dealloc_twostream_call() + + +def ParallelElementPerturbDist(): + + + # Lets first construct a bunch of cohorts, 5 cohorts + # equal area, but folding by 2 in LAI + + cohort_lai = np.array([0.25,0.5,1.0,2.0,4.0]) + cohort_area = np.array([0.9,0.19,0.19,0.19,0.19]) + n_cohorts = len(cohort_lai) + + sai_frac = 0.1 + + pft = 1 + + # Serial approach: 5 layers with veg and ghost + n_col = n_cohorts+1 + n_layer = 1 + iret = alloc_twostream_call(ci(n_layer),ci(n_col)) + + for icol in range(n_col-1): + iret = setup_canopy_call(c_int(1),c_int(icol+1),c_int(pft), \ + c_double(cohort_area[icol]),c_double(cohort_lai[icol]),c_double(cohort_lai[icol]*sai_frac)) + + # Add the air element + iret = setup_canopy_call(c_int(1),c_int(n_col),c_int(0),c_double(1.0-np.sum(cohort_area)),c_double(0.0),c_double(0.0)) + + num_params = 9 + paramsets = [] + + labels = ["clumping_index","leaf_rhonir","leaf_rhovis","leaf_taunir","leaf_tauvis", \ + "stem_rhonir","stem_rhovis","stem_taunir","stem_tauvis"] + + ic = 0 + with open('albedo_callib_param_vals.csv', newline='') as csvfile: + + reader = csv.reader(csvfile, delimiter=',') + next(reader, None) + nsets=0 + for irow, rowtext in enumerate(reader): + ic=ic+1 + if(ic==num_params): + ic=0 + nsets=nsets+1 + + with open('albedo_callib_param_vals.csv', newline='') as csvfile: + paramset = np.zeros([num_params,nsets]) + reader = csv.reader(csvfile, delimiter=',') + next(reader, None) + ic=0 + iset=0 + for irow, rowtext in enumerate(reader): + paramset[ic,iset] = float(rowtext[3]) + ic=ic+1 + if(ic==num_params): + ic=0 + iset=iset+1 + + + fig1, axs = plt.subplots(3,3,figsize=(9,7)) + ax1s = axs.reshape(-1) + + for ip,ax in enumerate(ax1s): + + ap = ax.hist(paramset[ip,:]) + #ax1.set_ylabel('Integrated VAI [m2/m2]') + ax.set_title(labels[ip]) + ax.grid(True) + + plt.tight_layout() + plt.show() + dealloc_twostream_call() + + +def SingleElementPerturbTest(): + + + # =================================================================================== + # In this test, we have a canopy that is constructed from a single cohort + # and therefore a single element. The cohort does not cover all of the ground + # so their is an air element in parallel with the leaf/stem element. + + ground_albedo_diff = 0.1 + ground_albedo_beam = 0.1 + veg_frac_snow = 0.0 + + patch = patch_type(ground_albedo_diff,ground_albedo_beam) + + # Vegetation cohort + area_frac = 0.9 + lai = 2.0 + sai = 0.5 + pft = 1 + air_pft = 0 + patch.cohorts.append(cohort_type(100,area_frac,lai,sai,pft)) + + # Open space (air) + patch.cohorts.append(cohort_type(100,1.0-area_frac,0.,0.,air_pft)) + + + n_col = 2 + n_layer = 1 + iret = alloc_twostream_call(ci(n_layer),ci(n_col)) + + ican = 1 # Single canopy layer + icol = 1 # Single PFT + pft = 1 # Use PFT number 1 + vai = lai+sai + iret = setup_canopy_call(c_int(1),c_int(1),c_int(pft),c_double(area_frac),c_double(lai),c_double(sai)) + iret = setup_canopy_call(c_int(1),c_int(2),c_int(0),c_double(1.0-area_frac),c_double(0.0),c_double(0.0)) + + # Decide on a band: + + ib = visb + + cd_r_beam = c_double(-9.0) + cd_r_diff_up = c_double(-9.0) + cd_r_diff_dn = c_double(-9.0) + cd_kb = c_double(-9.0) + cd_kd = c_double(-9.0) + cd_om = c_double(-9.0) + cd_betad = c_double(-9.0) + cd_betab = c_double(-9.0) + + + # Make parameter pertubations, bump up 50% + pp_dict = {} + pp_dict['Kb'] = 1.5*0.66118239744 #74 #*1.5 + pp_dict['Kd'] = 1.5*0.9063246621781269 #*1.5 + pp_dict['om'] = 1.5*0.17819999999999997 #*1.5 + pp_dict['betab'] = 1.5*0.48253004714288084 #*1.5 + pp_dict['betad'] = 1.5*0.5999777777777778 #*1.5 + + R_beam = 1.0 + R_diff = 1.0 + cosz = np.cos(0.0) + n_vai = 100 + vai_a = np.linspace(0,vai,num=n_vai) + + dv = vai/n_vai + + r_diff_up = np.zeros(n_vai) + r_diff_dn = np.zeros(n_vai) + r_beam = np.zeros(n_vai) + + drdv_diff_up = np.zeros(n_vai-1) # Delta + drdv_diff_dn = np.zeros(n_vai-1) # Delta + drdv_ubeam = np.zeros(n_vai-1) # Delta + drdv_dbeam = np.zeros(n_vai-1) # Delta + + p_r_diff_up = np.zeros([n_vai,len(pp_dict)]) + p_r_diff_dn = np.zeros([n_vai,len(pp_dict)]) + p_r_beam = np.zeros([n_vai,len(pp_dict)]) + p_drdv_diff_up = np.zeros([n_vai-1,len(pp_dict)]) + p_drdv_diff_dn = np.zeros([n_vai-1,len(pp_dict)]) + p_drdv_ubeam = np.zeros([n_vai-1,len(pp_dict)]) + p_drdv_dbeam = np.zeros([n_vai-1,len(pp_dict)]) + + cd_albedo_beam = c_double(-9.0) + cd_albedo_diff = c_double(-9.0) + cd_canabs_beam = c_double(-9.0) + cd_canabs_diff = c_double(-9.0) + cd_ffbeam_beam = c_double(-9.0) + cd_ffdiff_beam = c_double(-9.0) + cd_ffdiff_diff = c_double(-9.0) + + + iret = grndsnow_albedo_call(c_int(ib),c_double(ground_albedo_diff),*ccharnb('albedo_grnd_diff')) + iret = grndsnow_albedo_call(c_int(ib),c_double(ground_albedo_beam),*ccharnb('albedo_grnd_beam')) + iret = canopy_prep_call(c8(veg_frac_snow)) + iret = zenith_prep_call(c8(cosz)) + + iret = solver_call(ci(ib),ci(normalized_boundary),c8(1.0),c8(1.0), \ + byref(cd_albedo_beam),byref(cd_albedo_diff), \ + byref(cd_canabs_beam),byref(cd_canabs_diff), \ + byref(cd_ffbeam_beam),byref(cd_ffdiff_beam),byref(cd_ffdiff_diff)) + + iret = setdown_call(ci(ib),c8(R_beam),c8(R_diff)) + + iret = getparams_call(ci(ican),ci(icol),ci(ib),byref(cd_kb), \ + byref(cd_kd),byref(cd_om),byref(cd_betad),byref(cd_betab)) + + #print(cd_kb.value,cd_kd.value,cd_om.value,cd_betad.value,cd_betab.value) + #exit(0) + + + for iv in range(n_vai): + iret = getintens_call(ci(ican),ci(icol),ci(ib),c8(vai_a[iv]),byref(cd_r_diff_dn), \ + byref(cd_r_diff_up),byref(cd_r_beam)) + + r_beam[iv] = cd_r_beam.value + r_diff_up[iv] = cd_r_diff_up.value + r_diff_dn[iv] = cd_r_diff_dn.value + + if(iv>0): + drdv_ubeam[iv-1] = -cd_om.value*cd_betab.value*(r_beam[iv]-r_beam[iv-1])/dv + drdv_dbeam[iv-1] = -cd_om.value*(1.-cd_betab.value)*(r_beam[iv]-r_beam[iv-1])/dv + drdv_diff_dn[iv-1] = -(r_diff_dn[iv]-r_diff_dn[iv-1])/dv + drdv_diff_up[iv-1] = (r_diff_up[iv]-r_diff_up[iv-1])/dv + + # Redo the scattering with perturbations + i = -1 + for key,val in pp_dict.items(): + i=i+1 + iret = canopy_prep_call(c8(veg_frac_snow)) + iret = zenith_prep_call(c8(cosz)) + iret = forceparam_call(c_int(ican),c_int(icol),ci(ib),c_double(val),*ccharnb(key)) + + iret = solver_call(ci(ib),ci(normalized_boundary),c8(1.0),c8(1.0), \ + byref(cd_albedo_beam),byref(cd_albedo_diff), \ + byref(cd_canabs_beam),byref(cd_canabs_diff), \ + byref(cd_ffbeam_beam),byref(cd_ffdiff_beam),byref(cd_ffdiff_diff)) + + iret = setdown_call(ci(ib),c8(R_beam),c8(R_diff)) + + for iv in range(n_vai): + iret = getintens_call(ci(ican),ci(icol),ci(ib),c8(vai_a[iv]),byref(cd_r_diff_dn),byref(cd_r_diff_up),byref(cd_r_beam)) + + #print(iv,i,cd_r_beam.value) + p_r_beam[iv,i] = cd_r_beam.value + p_r_diff_up[iv,i] = cd_r_diff_up.value + p_r_diff_dn[iv,i] = cd_r_diff_dn.value + + if(iv>0): + p_drdv_ubeam[iv-1] = -cd_om.value*cd_betab.value*(p_r_beam[iv]-p_r_beam[iv-1])/dv + p_drdv_dbeam[iv-1] = -cd_om.value*(1.-cd_betab.value)*(p_r_beam[iv]-p_r_beam[iv-1])/dv + p_drdv_diff_dn[iv-1] = -(p_r_diff_dn[iv]-p_r_diff_dn[iv-1])/dv + p_drdv_diff_up[iv-1] = (p_r_diff_up[iv]-p_r_diff_up[iv-1])/dv + + + fig1, ((ax1,ax2),(ax3,ax4)) = plt.subplots(2,2,figsize=(6.5,5.5)) + + ap = ax1.plot(r_beam,vai_a,p_r_beam[:,i],vai_a) + first_color = ap[0].get_color() + last_color = ap[-1].get_color() + ax1.invert_yaxis() + ax1.set_xlabel('') + ax1.set_ylabel('Integrated VAI [m2/m2]') + ax1.set_title('Beam Intensity [W/m2]') + ax1.grid(True) + + ax2.plot(r_diff_dn,vai_a,p_r_diff_dn[:,i],vai_a) + ax2.invert_yaxis() + ax2.set_xlabel('') + ax2.set_yticklabels('') + ax2.set_ylabel('') + ax2.set_title('Down Diffuse Intensity [W/m2] ') + ax2.grid(True) + + ax3.plot(r_diff_up,vai_a,p_r_diff_up[:,i],vai_a) + ax3.invert_yaxis() + ax3.set_xlabel('') + ax3.set_ylabel('Integrated VAI [m2/m2]') + ax3.set_title('Up Diffuse Intensity [W/m2]') + ax3.grid(True) + + ax4.axis("off") + ax4.set_axis_off() + + if(ib==visb): + band_name = "Visible" + elif(ib==nirb): + band_name = "Near Infrared" + else: + print("Unknown band") + exit(2) + + + param_str = r"""In-element Scattering Profiles +Broad band: {0} +$cos(\phi) = ${1:.2f} +$K_b = ${2:.2f} +$K_d = ${3:.2f} +$\omega = ${4:.2f} +$\beta_b = ${5:.2f} +$\beta_d = ${6:.2f} +$\alpha_{{gd}} = ${7:.2f} +$\alpha_{{gb}} = ${8:.2f}""".format(band_name,cosz,cd_kb.value,cd_kd.value,cd_om.value,cd_betab.value,cd_betad.value,ground_albedo_diff,ground_albedo_beam) + ax4.text(0.1, 0.5, param_str, horizontalalignment='left', \ + verticalalignment='center', transform=ax4.transAxes,backgroundcolor=[1.0,1.0,1.0],fontsize=11,color=first_color) + ax4.text(0.5,0.5,r"{0}={1:.2f}".format(key,val),color=last_color) + plt.subplots_adjust(wspace=0.1, hspace=0.25) + plt.tight_layout() + plt.show() + + + dealloc_twostream_call() + + +# Plotting Functions + + +def PlotRadMaps(elems,rtype,plt_title): + + fig, ax = plt.subplots(ncols=1,nrows=1,figsize=(5,5)) + + cmap = mpl.cm.Reds + #code.interact(local=dict(globals(), **locals())) + n_layer = len(elems) + total_vai = 0 + for i in range(n_layer): + max_vai = 0. + for j in range(len(elems[i])): + max_vai = np.max([max_vai,elems[i][j].lai+elems[i][j].sai]) + total_vai = total_vai + max_vai + + ax.set_ylim([0,total_vai]) + + total_vai = 0 + rect = [] + rcolor = [] + for i in range(n_layer): + # + max_vai = 0. + area_off = 0. + for j in range(len(elems[i])): + max_vai = np.max([max_vai,elems[i][j].lai+elems[i][j].sai]) + for j in range(len(elems[i])): + for iv in range(elems[i][j].n_vai): + if(rtype==0): + rel_intense = np.max([0,elems[i][j].r_b[iv]]) + elif(rtype==1): + rel_intense = np.max([0,elems[i][j].r_dn[iv]]) + elif(rtype==2): + rel_intense = np.max([0,elems[i][j].r_up[iv]]) + + if(iv==0): + yoff = total_vai + dvai = elems[i][j].avai[iv] + else: + yoff = total_vai+elems[i][j].avai[iv-1] + dvai = elems[i][j].avai[iv]-elems[i][j].avai[iv-1] + rect.append(mpl.patches.Rectangle((area_off,yoff),elems[i][j].area,dvai)) + rcolor.append(rel_intense) + area_off = area_off + elems[i][j].area + + total_vai = total_vai + max_vai + + # Air + #rel_intense = np.max([0,np.min([1.,elems[1][i].r_dn[0]/R_diff])]) + #rel_intense = np.max([0,elems[1][i].r_dn[0]]) + #if(rtype==0): + # rel_intense = np.max([0,elems[1][i].r_b[0]]) + #elif(rtype==1): + # rel_intense = np.max([0,elems[1][i].r_dn[0]]) + #elif(rtype==2): + # rel_intense = np.max([0,elems[1][i].r_up[0]]) + + + #rect.append(mpl.patches.Rectangle((elems[0][i].area,total_vai),(1.-elems[0][i].area),(elems[0][i].lai+elems[0][i].sai))) #,color = [rel_intense,0.5,0.5])) + #rcolor.append(rel_intense) + + p = mpl.collections.PatchCollection(rect,cmap = cmap,alpha = 1.0) + p.set_array(rcolor) + im = ax.add_collection(p) + + + #code.interact(local=dict(globals(), **locals())) + + ax.invert_yaxis() + ax.set_ylabel('Integrated Vegetated Area Index') + ax.set_xlabel('Ground Area Fraction') + ax.set_title(plt_title) #) + plt.colorbar(im) + plt.show() + +def PlotRadLines(): + + fig, axs = plt.subplots(ncols=2,nrows=n_layer,figsize=(8,8)) + ax1s = axs.reshape(-1) + ic=0 + y0 = 0.9 + ypad = 0.1 + dy = (y0-ypad)/n_layer + xpad = 0.1 + xwid = 1-2*xpad + + for i in range(n_layer): + + ax = ax1s[ic] + ap = ax.plot(elems[0][i].r_dn,elems[0][i].avai) + ax.set_ylim([np.min(elems[0][i].avai),np.max(elems[0][i].avai)]) + ax.invert_yaxis() + ax.set_xlabel('') + ax.set_xlim([0,R_diff]) + ax.set_ylabel('VAI [m2/m2]') + if(i==0): + ax.set_title('Diffuse Down Intensity [W/m2]') + if(i!=n_layer-1): + ax.set_xticklabels([]) + ax.grid(True) + y0 = y0-dy + x0 = xpad + dx = 0.4 + #dx = elems[0][i].area*(1-2*xpad) + ax.set_position([x0,y0,dx,dy]) + ic=ic+1 + + ax = ax1s[ic] + ap = ax.plot([elems[1][i].r_dn[0],elems[1][i].r_dn[-1]],[0,1]) + ax.invert_yaxis() + ax.set_xlabel('') + ax.set_xlim([0,R_diff]) + if(i==0): + ax.set_title('Diffuse Down Intensity [W/m2]') + if(i!=n_layer-1): + ax.set_xticklabels([]) + ax.set_ylabel('') + ax.set_yticklabels([]) + ax.set_yticks([]) + ax.set_ylim([0,1]) + x0 = xpad+dx + dx=0.4 + #dx = elems[1][i].area*(1-2*xpad) + ax.set_position([x0,y0,dx,dy]) + ax.grid(True) + ic=ic+1 + + + +# ======================================================================================= +# This is the actual call to main + +if __name__ == "__main__": + main(sys.argv) diff --git a/functional_unit_testing/radiation/bld/README b/functional_unit_testing/radiation/bld/README new file mode 100644 index 0000000000..dc7db6c15f --- /dev/null +++ b/functional_unit_testing/radiation/bld/README @@ -0,0 +1 @@ +This is a placeholder to force git to initialize the bld directory \ No newline at end of file diff --git a/functional_unit_testing/radiation/build_radiation_f90_objects.sh b/functional_unit_testing/radiation/build_radiation_f90_objects.sh new file mode 100755 index 0000000000..0f10a98f64 --- /dev/null +++ b/functional_unit_testing/radiation/build_radiation_f90_objects.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +# Path to FATES src + +FC='gfortran' + +F_OPTS="-shared -fPIC -g -O0 -ffpe-trap=zero,overflow,underflow -fbacktrace -fbounds-check -Wall" +#F_OPTS="-shared -fPIC -O" + + +MOD_FLAG="-J" + +rm -f bld/*.o +rm -f bld/*.mod + +# Build the new file with constants + +${FC} ${F_OPTS} -I bld/ ${MOD_FLAG} bld/ -o bld/FatesConstantsMod.o ../../main/FatesConstantsMod.F90 +${FC} ${F_OPTS} -I bld/ ${MOD_FLAG} bld/ -o bld/WrapShrMod.o f90_src/WrapShrMod.F90 +${FC} ${F_OPTS} -I bld/ ${MOD_FLAG} bld/ -o bld/FatesRadiationMemMod.o ../../radiation/FatesRadiationMemMod.F90 +${FC} ${F_OPTS} -I bld/ ${MOD_FLAG} bld/ -o bld/TwoStreamMLPEMod.o ../../radiation/TwoStreamMLPEMod.F90 +${FC} ${F_OPTS} -I bld/ ${MOD_FLAG} bld/ -o bld/RadiationWrapMod.o f90_src/RadiationWrapMod.F90 + + + + diff --git a/functional_unit_testing/radiation/f90_src/RadiationWrapMod.F90 b/functional_unit_testing/radiation/f90_src/RadiationWrapMod.F90 new file mode 100644 index 0000000000..90c31d21a8 --- /dev/null +++ b/functional_unit_testing/radiation/f90_src/RadiationWrapMod.F90 @@ -0,0 +1,276 @@ +module RadiationWrapMod + + use TwoStreamMLPEMod + use iso_c_binding, only : c_char + use iso_c_binding, only : c_int + use iso_c_binding, only : r8 => c_double + + implicit none + public + save + + integer(kind=c_int), parameter :: param_string_length = 32 + + type(twostream_type) :: twostream + + +contains + + subroutine InitAllocate(n_layer,n_column) + + integer(kind=c_int), intent(in) :: n_layer + integer(kind=c_int), intent(in) :: n_column + + integer(kind=c_int) :: ican + + + call twostream%AllocInitTwoStream((/1,2/),n_layer,n_column) + + + twostream%n_lyr = n_layer + + do ican = 1,n_layer + twostream%n_col(ican) = n_column + end do + + twostream%force_prep = .true. + + call twostream%GetNScel() + + twostream%frac_snow = 0._r8 + twostream%frac_snow_old = 1._r8 + + print*,"Allocated twostream instance" + print*," with ",twostream%n_scel," elements" + + return + end subroutine InitAllocate + + + subroutine Dealloc() + + call twostream%DeallocTwoStream() + + end subroutine Dealloc + + + subroutine SetRadParam(val,pft,ib,pname) + + real(r8), intent(in) :: val + character(kind=c_char,len=*), intent(in) :: pname + integer(kind=c_int), intent(in) :: pft + integer(kind=c_int), intent(in) :: ib + + select case(trim(pname)) + case('rhol') + rad_params%rhol(ib,pft) = val + case('rhos') + rad_params%rhos(ib,pft) = val + case('taul') + rad_params%taul(ib,pft) = val + case('taus') + rad_params%taus(ib,pft) = val + case('xl') + rad_params%xl(pft) = val + case('clumping_index') + rad_params%clumping_index(pft) = val + case default + print*,"An unknown parameter name was sent to the parameter" + print*,"initialization function." + print*,"name:--",trim(pname),"--" + stop + end select + + end subroutine SetRadParam + + ! ============================================================================= + + subroutine SetGroundSnow(ib,val,pname) + + real(r8), intent(in) :: val + integer, intent(in) :: ib + character(kind=c_char,len=*), intent(in) :: pname + + select case(trim(pname)) + case('albedo_grnd_diff') + twostream%band(ib)%albedo_grnd_diff = val + case('albedo_grnd_beam') + twostream%band(ib)%albedo_grnd_beam = val + case default + print*,"An unknown parameter name was sent to ground/snow" + print*,"initialization function." + print*,"name:--",trim(pname),"--" + stop + end select + end subroutine SetGroundSnow + + ! ============================================================================= + + subroutine SetupCanopy(ican,icol,pft,area,lai,sai) + + integer(kind=c_int), intent(in) :: ican ! Canopy layer index + integer(kind=c_int), intent(in) :: icol ! Column (pft) position index + integer(kind=c_int), intent(in) :: pft ! PFT index + real(r8), intent(in) :: area ! columns fraction of the ground + real(r8), intent(in) :: lai ! LAI + real(r8), intent(in) :: sai + + + twostream%scelg(ican,icol)%pft = pft + twostream%scelg(ican,icol)%area = area + twostream%scelg(ican,icol)%lai = lai + twostream%scelg(ican,icol)%sai = sai + + return + end subroutine SetupCanopy + + subroutine WrapCanopyPrep(frac_snow) + + real(kind=r8),intent(in) :: frac_snow + + call twostream%CanopyPrep(frac_snow) + + end subroutine WrapCanopyPrep + + subroutine WrapZenithPrep(cosz) + + real(kind=r8),intent(in) :: cosz + + call twostream%ZenithPrep(cosz) + + return + end subroutine WrapZenithPrep + + subroutine WrapSetDownwelling(ib,Rbeam_atm,Rdiff_atm) + + integer(c_int) :: ib + real(r8) :: Rbeam_atm ! Intensity of beam radiation at top of canopy [W/m2 ground] + real(r8) :: Rdiff_atm ! Intensity of diffuse radiation at top of canopy [W/m2 ground] + + twostream%band(ib)%Rbeam_atm = Rbeam_atm + twostream%band(ib)%Rdiff_atm = Rdiff_atm + + return + end subroutine WrapSetDownwelling + + + subroutine WrapSolve(ib,boundary_type,Rbeam_atm,Rdiff_atm, & + albedo_beam, & + albedo_diff, & + frac_abs_can_beam, & + frac_abs_can_diff, & + frac_beam_grnd_beam, & + frac_diff_grnd_beam, & + frac_diff_grnd_diff) + + integer(c_int) :: ib + integer(c_int) :: boundary_type + + real(r8) :: albedo_beam + real(r8) :: albedo_diff + real(r8) :: err_solve + real(r8) :: err_consv + real(r8) :: frac_abs_can_beam + real(r8) :: frac_abs_can_diff + real(r8) :: frac_beam_grnd_beam + real(r8) :: frac_diff_grnd_beam + real(r8) :: frac_diff_grnd_diff + real(r8) :: Rbeam_atm ! Intensity of beam radiation at top of canopy [W/m2 ground] + real(r8) :: Rdiff_atm ! Intensity of diffuse radiation at top of canopy [W/m2 ground] + + real(r8) :: taulamb(50) + real(r8) :: omega(50,50) + integer :: ipiv(50) + + call twostream%Solve(ib,boundary_type, & + Rbeam_atm,Rdiff_atm, & + taulamb, & + omega, & + ipiv, & + albedo_beam, & + albedo_diff, & + err_solve, & + err_consv, & + frac_abs_can_beam, & + frac_abs_can_diff, & + frac_beam_grnd_beam, & + frac_diff_grnd_beam, & + frac_diff_grnd_diff) + + return + end subroutine WrapSolve + + subroutine WrapGetIntensity(ican,icol,ib,vai,r_diff_dn,r_diff_up,r_beam) + + integer(c_int) :: ican, icol + integer(c_int) :: ib + real(r8) :: vai + real(r8) :: r_diff_dn + real(r8) :: r_diff_up + real(r8) :: r_beam + + r_diff_dn = twostream%GetRdDn(ican,icol,ib,vai) + r_diff_up = twostream%GetRdUp(ican,icol,ib,vai) + r_beam = twostream%GetRb(ican,icol,ib,vai) + + return + end subroutine WrapGetIntensity + + subroutine WrapGetAbsRad(ican,icol,ib,vai_top,vai_bot,Rd_abs_leaf,Rb_abs_leaf,R_abs_stem,R_abs_snow,leaf_sun_frac) + + integer(c_int) :: ican, icol + integer(c_int) :: ib + real(r8) :: vai_top,vai_bot + real(r8) :: Rd_abs_leaf,Rb_abs_leaf,R_abs_stem,R_abs_snow,leaf_sun_frac,Rb_abs,Rd_abs + + call twostream%GetAbsRad(ican,icol,ib,vai_top,vai_bot,Rb_abs,Rd_abs,Rd_abs_leaf,Rb_abs_leaf,R_abs_stem,R_abs_snow,leaf_sun_frac) + + return + end subroutine WrapGetAbsRad + + subroutine WrapGetParams(ican,icol,ib,Kb,Kd,om,betad,betab) + + integer(c_int) :: ican, icol + integer(c_int) :: ib + real(r8) :: Kb,Kd,om,betad,betab + + Kb = twostream%scelg(ican,icol)%Kb + Kd = twostream%scelg(ican,icol)%Kd + om = twostream%band(ib)%scelb(ican,icol)%om + betad = twostream%band(ib)%scelb(ican,icol)%betad + betab = twostream%band(ib)%scelb(ican,icol)%betab + + return + end subroutine WrapGetParams + + subroutine WrapForceParams(ican,icol,ib,val,pname) + + ! This will overwrite the 2-stream parameters + ! that are derived from the fates params + + integer(c_int) :: ican, icol + integer(c_int) :: ib + real(r8), intent(in) :: val + character(kind=c_char,len=*), intent(in) :: pname + + select case(trim(pname)) + case('Kb') + twostream%scelg(ican,icol)%Kb = val + case('Kd') + twostream%scelg(ican,icol)%Kd = val + case('om') + twostream%band(ib)%scelb(ican,icol)%om = val + case('betab') + twostream%band(ib)%scelb(ican,icol)%betab = val + case('betad') + twostream%band(ib)%scelb(ican,icol)%betad = val + case default + print*,"An unknown parameter name was sent to the parameter" + print*,"initialization function." + print*,"name:--",trim(pname),"--" + stop + end select + + end subroutine WrapForceParams + +end module RadiationWrapMod diff --git a/functional_unit_testing/radiation/f90_src/WrapShrMod.F90 b/functional_unit_testing/radiation/f90_src/WrapShrMod.F90 new file mode 100644 index 0000000000..7bc093b4d5 --- /dev/null +++ b/functional_unit_testing/radiation/f90_src/WrapShrMod.F90 @@ -0,0 +1,31 @@ +module shr_log_mod + use iso_c_binding, only : c_char + use iso_c_binding, only : c_int + + public :: shr_log_errMsg + + contains + function shr_log_errMsg(source, line) result(ans) + character(kind=c_char,len=*), intent(in) :: source + integer(c_int), intent(in) :: line + character(kind=c_char,len=4) :: cline ! character version of int + character(kind=c_char,len=128) :: ans + + write(cline,'(I4)') line + ans = "source: " // trim(source) // " line: "// trim(cline) + + end function shr_log_errMsg + +end module shr_log_mod + +module shr_sys_mod + + public :: shr_sys_abort + +contains + + subroutine shr_sys_abort + call exit(0) + end subroutine shr_sys_abort + +end module shr_sys_mod diff --git a/functional_unit_testing/shared/py_src/PyF90Utils.py b/functional_unit_testing/shared/py_src/PyF90Utils.py index a9ffaf89ad..3665b59785 100644 --- a/functional_unit_testing/shared/py_src/PyF90Utils.py +++ b/functional_unit_testing/shared/py_src/PyF90Utils.py @@ -19,6 +19,9 @@ def cchar(fchar): def cchar3(fchar): return(byref(c_char(fchar.encode('utf-8')))) +def ccharnb(fchar): + return([c_char_p(fchar.encode('utf-8')),c_long(len(fchar))]) + # We do NOT pass arrays back by reference # This is because we will need to get their length # on the argument diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index dfd5eaba2a..17156c7e3e 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -10,5 +10,30 @@ list(APPEND clm_sources FatesParametersInterface.F90 FatesUtilsMod.F90 ) + +list(APPEND fates_sources + FatesConstantsMod.F90 + FatesGlobals.F90 + FatesParametersInterface.F90 + ) +sourcelist_to_parent(fates_sources) sourcelist_to_parent(clm_sources) + +list(APPEND fates_sources + FatesConstantsMod.F90 + FatesGlobals.F90 + FatesParametersInterface.F90 + FatesInterfaceTypesMod.F90 + EDPftvarcon.F90 + EDParamsMod.F90 + EDTypesMod.F90 + FatesHydraulicsMemMod.F90 + FatesRunningMeanMod.F90 + FatesParameterDerivedMod.F90 + FatesSizeAgeTypeIndicesMod.F90 + FatesIntegratorsMod.F90 + FatesUtilsMod.F90 + FatesSynchronizedParamsMod.F90) + +sourcelist_to_parent(fates_sources) diff --git a/main/EDInitMod.F90 b/main/EDInitMod.F90 index 06973ac9a9..ce76ba9017 100644 --- a/main/EDInitMod.F90 +++ b/main/EDInitMod.F90 @@ -10,7 +10,10 @@ module EDInitMod use FatesConstantsMod , only : fates_unset_int use FatesConstantsMod , only : primaryland use FatesConstantsMod , only : nearzero + use FatesConstantsMod , only : rsnbl_math_prec + use EDTypesMod , only : min_patch_area_forced use FatesConstantsMod , only : n_landuse_cats + use FatesConstantsMod , only : is_crop use FatesConstantsMod , only : fates_unset_r8 use FatesConstantsMod , only : nearzero, area_error_4, area_error_3 use FatesGlobals , only : endrun => fates_endrun @@ -19,7 +22,6 @@ module EDInitMod use FatesGlobals , only : fates_log use FatesInterfaceTypesMod , only : hlm_is_restart use FatesInterfaceTypesMod , only : hlm_current_tod - use FatesInterfaceTypesMod , only : hlm_numSWb use EDPftvarcon , only : EDPftvarcon_inst use PRTParametersMod , only : prt_params use EDCohortDynamicsMod , only : create_cohort, fuse_cohorts, sort_cohorts @@ -28,6 +30,7 @@ module EDInitMod use EDPhysiologyMod , only : calculate_sp_properties use ChecksBalancesMod , only : SiteMassStock use FatesInterfaceTypesMod , only : hlm_day_of_year + use FatesRadiationMemMod , only : num_swb use EDTypesMod , only : ed_site_type use FatesPatchMod , only : fates_patch_type use FatesCohortMod , only : fates_cohort_type @@ -62,7 +65,6 @@ module EDInitMod use FatesInterfaceTypesMod , only : nlevdamage use FatesInterfaceTypesMod , only : hlm_use_nocomp use FatesInterfaceTypesMod , only : nlevage - use FatesAllometryMod , only : h2d_allom use FatesAllometryMod , only : h_allom use FatesAllometryMod , only : bagw_allom @@ -90,16 +92,22 @@ module EDInitMod use PRTGenericMod, only : SetState use FatesSizeAgeTypeIndicesMod,only : get_age_class_index use DamageMainMod, only : undamaged_class - use FatesInterfaceTypesMod , only : hlm_num_luh2_transitions + use FatesConstantsMod, only : n_term_mort_types + use FatesInterfaceTypesMod, only : hlm_num_luh2_transitions + use FatesConstantsMod, only : nocomp_bareground_land, nocomp_bareground + use FatesConstantsMod, only : min_nocomp_pftfrac_perlanduse + use EdTypesMod, only : dump_site + use SFNesterovMod, only : nesterov_index + ! CIME GLOBALS use shr_log_mod , only : errMsg => shr_log_errMsg + use shr_infnan_mod , only : isnan => shr_infnan_isnan implicit none private logical :: debug = .false. - integer :: istat ! return status code character(len=255) :: smsg ! Message string for deallocation errors character(len=*), parameter, private :: sourcefile = & @@ -133,8 +141,8 @@ subroutine init_site_vars( site_in, bc_in, bc_out ) integer :: el ! - allocate(site_in%term_nindivs_canopy(1:nlevsclass,1:numpft)) - allocate(site_in%term_nindivs_ustory(1:nlevsclass,1:numpft)) + allocate(site_in%term_nindivs_canopy(1:n_term_mort_types,1:nlevsclass,1:numpft)) + allocate(site_in%term_nindivs_ustory(1:n_term_mort_types,1:nlevsclass,1:numpft)) allocate(site_in%demotion_rate(1:nlevsclass)) allocate(site_in%promotion_rate(1:nlevsclass)) allocate(site_in%imort_rate(1:nlevsclass,1:numpft)) @@ -170,8 +178,8 @@ subroutine init_site_vars( site_in, bc_in, bc_out ) allocate(site_in%fmort_cflux_ustory_damage(1,1)) end if - allocate(site_in%term_carbonflux_canopy(1:numpft)) - allocate(site_in%term_carbonflux_ustory(1:numpft)) + allocate(site_in%term_carbonflux_canopy(1:n_term_mort_types,1:numpft)) + allocate(site_in%term_carbonflux_ustory(1:n_term_mort_types,1:numpft)) allocate(site_in%imort_carbonflux(1:numpft)) allocate(site_in%fmort_carbonflux_canopy(1:numpft)) allocate(site_in%fmort_carbonflux_ustory(1:numpft)) @@ -186,11 +194,8 @@ subroutine init_site_vars( site_in, bc_in, bc_out ) allocate(site_in%dz_soil(site_in%nlevsoil)) allocate(site_in%z_soil(site_in%nlevsoil)) - if (hlm_use_nocomp .eq. itrue .and. hlm_use_fixed_biogeog .eq. itrue) then - allocate(site_in%area_pft(0:numpft)) - else ! SP and nocomp require a bare-ground patch. - allocate(site_in%area_pft(1:numpft)) - endif + allocate(site_in%area_pft(1:numpft,1:n_landuse_cats)) + allocate(site_in%landuse_vector_gt_min(1:n_landuse_cats)) allocate(site_in%use_this_pft(1:numpft)) allocate(site_in%area_by_age(1:nlevage)) @@ -220,6 +225,9 @@ subroutine init_site_vars( site_in, bc_in, bc_out ) allocate(site_in%seed_in(1:numpft)) allocate(site_in%seed_out(1:numpft)) + allocate(nesterov_index :: site_in%fireWeather) + call site_in%fireWeather%Init() + end subroutine init_site_vars ! ============================================================================ @@ -270,7 +278,6 @@ subroutine zero_site( site_in ) site_in%disturbance_rates(:,:,:) = 0.0_r8 ! FIRE - site_in%acc_ni = 0.0_r8 ! daily nesterov index accumulating over time. time unlimited theoretically. site_in%FDI = 0.0_r8 ! daily fire danger index (0-1) site_in%NF = 0.0_r8 ! daily lightning strikes per km2 site_in%NF_successful = 0.0_r8 ! daily successful iginitions per km2 @@ -288,15 +295,15 @@ subroutine zero_site( site_in ) site_in%ema_npp = -9999.9_r8 ! termination and recruitment info - site_in%term_nindivs_canopy(:,:) = 0._r8 - site_in%term_nindivs_ustory(:,:) = 0._r8 + site_in%term_nindivs_canopy(:,:,:) = 0._r8 + site_in%term_nindivs_ustory(:,:,:) = 0._r8 site_in%term_crownarea_canopy = 0._r8 site_in%term_crownarea_ustory = 0._r8 site_in%imort_crownarea = 0._r8 site_in%fmort_crownarea_canopy = 0._r8 site_in%fmort_crownarea_ustory = 0._r8 - site_in%term_carbonflux_canopy(:) = 0._r8 - site_in%term_carbonflux_ustory(:) = 0._r8 + site_in%term_carbonflux_canopy(:,:) = 0._r8 + site_in%term_carbonflux_ustory(:,:) = 0._r8 site_in%recruitment_rate(:) = 0._r8 site_in%imort_rate(:,:) = 0._r8 site_in%imort_carbonflux(:) = 0._r8 @@ -341,14 +348,19 @@ subroutine zero_site( site_in ) ! canopy spread site_in%spread = 0._r8 + + site_in%area_pft(:,:) = 0._r8 + site_in%area_bareground = 0._r8 + ! Seed dispersal site_in%seed_in(:) = 0.0_r8 site_in%seed_out(:) = 0.0_r8 - site_in%area_pft(:) = 0._r8 site_in%use_this_pft(:) = fates_unset_int site_in%area_by_age(:) = 0._r8 + site_in%transition_landuse_from_off_to_on = .false. + end subroutine zero_site ! ============================================================================ @@ -357,6 +369,8 @@ subroutine set_site_properties( nsites, sites,bc_in ) ! !DESCRIPTION: ! ! !USES: + use EDParamsMod, only : crop_lu_pft_vector + use EDParamsMod, only : max_nocomp_pfts_by_landuse ! ! !ARGUMENTS @@ -369,7 +383,6 @@ subroutine set_site_properties( nsites, sites,bc_in ) integer :: cstat ! cold status phenology flag real(r8) :: GDD integer :: dstat ! drought status phenology flag - real(r8) :: acc_NI real(r8) :: liqvolmem real(r8) :: smpmem real(r8) :: elong_factor ! Elongation factor (0 - fully off; 1 - fully on) @@ -385,6 +398,9 @@ subroutine set_site_properties( nsites, sites,bc_in ) real(r8) :: sumarea ! area of PFTs in nocomp mode. integer :: hlm_pft ! used in fixed biogeog mode integer :: fates_pft ! used in fixed biogeog mode + integer :: i_landusetype + real(r8) :: temp_vec(numpft) ! temporary vector + integer :: i_pftcount !---------------------------------------------------------------------- @@ -401,7 +417,6 @@ subroutine set_site_properties( nsites, sites,bc_in ) cndleafon = 0 cndleafoff = 0 cstat = phen_cstat_notcold ! Leaves are on - acc_NI = 0.0_r8 dstat = phen_dstat_moiston ! Leaves are on dleafoff = 300 dleafon = 100 @@ -436,10 +451,9 @@ subroutine set_site_properties( nsites, sites,bc_in ) sites(s)%dstatus(1:numpft) = dstat sites(s)%elong_factor(1:numpft) = elong_factor - sites(s)%acc_NI = acc_NI sites(s)%NF = 0.0_r8 sites(s)%NF_successful = 0.0_r8 - sites(s)%area_pft(:) = 0.0_r8 + sites(s)%area_pft(:,:) = 0.0_r8 do ft = 1,numpft sites(s)%rec_l2fr(ft,:) = prt_params%allom_l2fr(ft) @@ -450,66 +464,121 @@ subroutine set_site_properties( nsites, sites,bc_in ) sites(s)%ema_npp = -9999._r8 if(hlm_use_fixed_biogeog.eq.itrue)then - ! MAPPING OF FATES PFTs on to HLM_PFTs - ! add up the area associated with each FATES PFT - ! where pft_areafrac is the area of land in each HLM PFT and (from surface dataset) - ! hlm_pft_map is the area of that land in each FATES PFT (from param file) - - do hlm_pft = 1,size( EDPftvarcon_inst%hlm_pft_map,2) - do fates_pft = 1,numpft ! loop round all fates pfts for all hlm pfts - sites(s)%area_pft(fates_pft) = sites(s)%area_pft(fates_pft) + & - EDPftvarcon_inst%hlm_pft_map(fates_pft,hlm_pft) * bc_in(s)%pft_areafrac(hlm_pft) - end do - end do !hlm_pft - do ft = 1,numpft - if(sites(s)%area_pft(ft).lt.0.01_r8.and.sites(s)%area_pft(ft).gt.0.0_r8)then - if(debug) write(fates_log(),*) 'removing small pft patches',s,ft,sites(s)%area_pft(ft) - sites(s)%area_pft(ft)=0.0_r8 - ! remove tiny patches to prevent numerical errors in terminate patches + use_fates_luh_if: if (hlm_use_luh .eq. itrue) then + ! MAPPING OF FATES PFTs on to HLM_PFTs with land use + ! add up the area associated with each FATES PFT + ! where pft_areafrac_lu is the area of land in each HLM PFT and land use type (from surface dataset) + ! hlm_pft_map is the area of that land in each FATES PFT (from param file) + + ! First check for NaNs in bc_in(s)%pft_areafrac_lu. If so, make everything bare ground. + if ( .not. (any( isnan( bc_in(s)%pft_areafrac_lu (:,:) )) .or. isnan( bc_in(s)%baregroundfrac))) then + do i_landusetype = 1, n_landuse_cats + if (.not. is_crop(i_landusetype)) then + do hlm_pft = 1,size( EDPftvarcon_inst%hlm_pft_map,2) + do fates_pft = 1,numpft ! loop round all fates pfts for all hlm pfts + sites(s)%area_pft(fates_pft,i_landusetype) = sites(s)%area_pft(fates_pft,i_landusetype) + & + EDPftvarcon_inst%hlm_pft_map(fates_pft,hlm_pft) * bc_in(s)%pft_areafrac_lu(hlm_pft,i_landusetype) + end do + end do !hlm_pft + else + ! for crops, we need to use different logic because the bc_in(s)%pft_areafrac_lu() information only exists for natural PFTs + sites(s)%area_pft(crop_lu_pft_vector(i_landusetype),i_landusetype) = 1._r8 + endif + end do + + sites(s)%area_bareground = bc_in(s)%baregroundfrac + else + !if ( all( isnan( bc_in(s)%pft_areafrac_lu (:,:))) .and. isnan(bc_in(s)%baregroundfrac)) then + ! if given all NaNs, then make everything bare ground + sites(s)%area_bareground = 1._r8 + sites(s)%area_pft(:,:) = 0._r8 + write(fates_log(),*) 'Nan values for pftareafrac. dumping site info.' + call dump_site(sites(s)) + !else + ! ! if only some things are NaN but not all, then something terrible has probably happened. crash. + ! write(fates_log(),*) 'some but, not all, of the data in the PFT by LU matrix at this site is NaN.' + ! write(fates_log(),*) 'recommend checking the dataset to see what has happened.' + ! call endrun(msg=errMsg(sourcefile, __LINE__)) + !endif endif - if(sites(s)%area_pft(ft).lt.0._r8)then - write(fates_log(),*) 'negative area',s,ft,sites(s)%area_pft(ft) - call endrun(msg=errMsg(sourcefile, __LINE__)) - end if - sites(s)%area_pft(ft)= sites(s)%area_pft(ft) * AREA ! rescale units to m2. + + else + ! MAPPING OF FATES PFTs on to HLM_PFTs + ! add up the area associated with each FATES PFT + ! where pft_areafrac is the area of land in each HLM PFT and (from surface dataset) + ! hlm_pft_map is the area of that land in each FATES PFT (from param file) + + do hlm_pft = 1,size( EDPftvarcon_inst%hlm_pft_map,2) + do fates_pft = 1,numpft ! loop round all fates pfts for all hlm pfts + sites(s)%area_pft(fates_pft,primaryland) = sites(s)%area_pft(fates_pft,primaryland) + & + EDPftvarcon_inst%hlm_pft_map(fates_pft,hlm_pft) * bc_in(s)%pft_areafrac(hlm_pft) + end do + sites(s)%area_bareground = bc_in(s)%pft_areafrac(0) + end do !hlm_pft + + endif use_fates_luh_if + + ! handle some edge cases + do i_landusetype = 1, n_landuse_cats + do ft = 1,numpft + + ! remove tiny patches to prevent numerical errors in terminate patches + if (sites(s)%area_pft(ft, i_landusetype) .lt. min_nocomp_pftfrac_perlanduse & + .and. sites(s)%area_pft(ft, i_landusetype) .gt. nearzero) then + if(debug) write(fates_log(),*) 'removing small numbers in site%area_pft',s,ft,i_landusetype,sites(s)%area_pft(ft, i_landusetype) + sites(s)%area_pft(ft, i_landusetype)=0.0_r8 + endif + + ! if any areas are negative, then end run + if(sites(s)%area_pft(ft, i_landusetype).lt.0._r8)then + write(fates_log(),*) 'negative area',s,ft,i_landusetype,sites(s)%area_pft(ft, i_landusetype) + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + end do end do - ! re-normalize PFT area to ensure it sums to one. - ! note that in areas of 'bare ground' (PFT 0 in CLM/ELM) - ! the bare ground will no longer be proscribed and should emerge from FATES - ! this may or may not be the right way to deal with this? + ! if in nocomp mode, and the number of nocomp PFTs of a given land use type is greater than the maximum number of patches + ! allowed to be allocated for that land use type, then only keep the number of PFTs correspondign to the number of patches + ! allowed on that land use type, starting with the PFTs with greatest area coverage and working down + if (hlm_use_nocomp .eq. itrue) then + do i_landusetype = 1, n_landuse_cats + ! count how many PFTs have areas greater than zero and compare to the number of patches allowed + if (COUNT(sites(s)%area_pft(:, i_landusetype) .gt. 0._r8) > max_nocomp_pfts_by_landuse(i_landusetype)) then + ! write current vector to log file + if(debug) write(fates_log(),*) 'too many PFTs for LU type ', i_landusetype, sites(s)%area_pft(:, i_landusetype) + + ! start from largest area, put that PFT's area into a temp vector, and then work down to successively smaller-area PFTs, + ! at the end replace the original vector with the temp vector + temp_vec(:) = 0._r8 + do i_pftcount = 1, max_nocomp_pfts_by_landuse(i_landusetype) + temp_vec(MAXLOC(sites(s)%area_pft(:, i_landusetype))) = & + sites(s)%area_pft(MAXLOC(sites(s)%area_pft(:, i_landusetype)), i_landusetype) + sites(s)%area_pft(MAXLOC(sites(s)%area_pft(:, i_landusetype)), i_landusetype) = 0._r8 + end do + sites(s)%area_pft(:, i_landusetype) = temp_vec(:) - if(hlm_use_nocomp.eq.ifalse)then ! when not in nocomp (i.e. or SP) mode, - ! subsume bare ground evenly into the existing patches. + ! write adjusted vector to log file + if(debug) write(fates_log(),*) 'new PFT vector for LU type', i_landusetype, sites(s)%area_pft(:, i_landusetype) + endif + end do + end if - sumarea = sum(sites(s)%area_pft(1:numpft)) - do ft = 1,numpft - if(sumarea.gt.0._r8)then - sites(s)%area_pft(ft) = area * sites(s)%area_pft(ft)/sumarea - else - sites(s)%area_pft(ft) = area/numpft - ! in nocomp mode where there is only bare ground, we assign equal area to - ! all pfts and let the model figure out whether land should be bare or not. - end if - end do !ft - else ! for sp and nocomp mode, assert a bare ground patch if needed - sumarea = sum(sites(s)%area_pft(1:numpft)) - - ! In all the other FATES modes, bareground is the area in which plants - ! do not grow of their own accord. In SP mode we assert that the canopy is full for - ! each PFT patch. Thus, we also need to assert a bare ground area in - ! order to not have all of the ground filled by leaves. - - ! Further to that, one could calculate bare ground as the remaining area when - ! all fhe canopies are accounted for, but this means we don't pass balance checks - ! on canopy are inside FATES, and so in SP mode, we define the bare groud - ! patch as having a PFT identifier as zero. - - if(sumarea.lt.area)then !make some bare ground - sites(s)%area_pft(0) = area - sumarea + ! re-normalize PFT area to ensure it sums to one for each (active) land use type + ! for nocomp cases, track bare ground area as a separate quantity + do i_landusetype = 1, n_landuse_cats + sumarea = sum(sites(s)%area_pft(:,i_landusetype)) + if(sumarea.gt.nearzero)then + sites(s)%area_pft(:, i_landusetype) = sites(s)%area_pft(:, i_landusetype)/sumarea + else + ! if no PFT area in primary lands, set bare ground fraction to one. + if ( i_landusetype .eq. primaryland) then + sites(s)%area_bareground = 1._r8 + sites(s)%area_pft(:, i_landusetype) = 0._r8 + endif end if - end if !sp mode + end do + end if !fixed biogeog do ft = 1,numpft @@ -517,13 +586,27 @@ subroutine set_site_properties( nsites, sites,bc_in ) ! are used for nocomp with no biogeog sites(s)%use_this_pft(ft) = itrue if(hlm_use_fixed_biogeog.eq.itrue)then - if(sites(s)%area_pft(ft).gt.0.0_r8)then + if(any(sites(s)%area_pft(ft,:).gt.0.0_r8))then sites(s)%use_this_pft(ft) = itrue else sites(s)%use_this_pft(ft) = ifalse end if !area end if !SBG end do !ft + + ! need to set the minimum amount of allowable land-use fraction on a given site. this is a function of the minimum allowable patch size, + ! and for nocomp simulations also the bare ground fraction and the minimum pft fraction for a given land-use type. + if (hlm_use_nocomp .eq. itrue ) then + if ( (1._r8 - sites(s)%area_bareground) .gt. nearzero) then + sites(s)%min_allowed_landuse_fraction = min_patch_area_forced / (AREA * min_nocomp_pftfrac_perlanduse * (1._r8 - sites(s)%area_bareground)) + else + ! if all bare ground, shouldn't matter. but make it one anyway to really ignore land use (which should all be NaNs anyway) + sites(s)%min_allowed_landuse_fraction = 1._r8 + endif + else + sites(s)%min_allowed_landuse_fraction = min_patch_area_forced / AREA + endif + end do !site loop end if !restart @@ -541,7 +624,7 @@ subroutine init_patches( nsites, sites, bc_in) use FatesPlantHydraulicsMod, only : updateSizeDepRhizHydProps use FatesInventoryInitMod, only : initialize_sites_by_inventory - use FatesLandUseChangeMod, only : get_luh_statedata + use FatesLandUseChangeMod, only : GetLUHStatedata ! ! !ARGUMENTS @@ -555,6 +638,7 @@ subroutine init_patches( nsites, sites, bc_in) real(r8) :: age !notional age of this patch integer :: ageclass real(r8) :: area_diff + real(r8) :: area_error ! dummy locals real(r8) :: biomass_stock @@ -562,19 +646,19 @@ subroutine init_patches( nsites, sites, bc_in) real(r8) :: seed_stock integer :: n integer :: start_patch - integer :: num_new_patches + integer :: num_nocomp_pfts integer :: nocomp_pft real(r8) :: newparea, newparea_withlanduse real(r8) :: total !check on area real(r8) :: litt_init !invalid for satphen, 0 otherwise real(r8) :: old_carea - integer :: is_first_patch + logical :: is_first_patch ! integer :: n_luh_states ! integer :: luh_state_counter real(r8) :: state_vector(n_landuse_cats) ! [m2/m2] integer :: i_lu, i_lu_state integer :: n_active_landuse_cats - + integer :: end_landuse_idx type(ed_site_type), pointer :: sitep type(fates_patch_type), pointer :: newppft(:) @@ -610,11 +694,16 @@ subroutine init_patches( nsites, sites, bc_in) call SiteMassStock(sites(s),el,sites(s)%mass_balance(el)%old_stock, & biomass_stock,litter_stock,seed_stock) end do + call set_patchno(sites(s)) enddo - + else - ! state_vector(:) = 0._r8 + if(hlm_use_nocomp.eq.itrue)then + num_nocomp_pfts = numpft + else !default + num_nocomp_pfts = 1 + end if !nocomp sites_loop: do s = 1, nsites sites(s)%sp_tlai(:) = 0._r8 @@ -626,17 +715,6 @@ subroutine init_patches( nsites, sites, bc_in) ! have smaller spread factors than bare ground (they are crowded) sites(s)%spread = init_spread_near_bare_ground - start_patch = 1 ! start at the first vegetated patch - if(hlm_use_nocomp.eq.itrue)then - num_new_patches = numpft - if( hlm_use_fixed_biogeog .eq.itrue )then - start_patch = 0 ! start at the bare ground patch - endif - ! allocate(newppft(numpft)) - else !default - num_new_patches = 1 - end if !nocomp - ! read in luh state data to determine initial land use types if (hlm_use_luh .eq. itrue) then @@ -644,18 +722,18 @@ subroutine init_patches( nsites, sites, bc_in) ! This could be updated in the future to allow a variable number of ! categories based on which states are zero n_active_landuse_cats = n_landuse_cats - call get_luh_statedata(bc_in(s), state_vector) - ! n_luh_states = 0 - ! do i_lu = 1, hlm_num_luh2_transitions - ! if ( state_vector(i_lu) .gt. nearzero ) then - ! n_luh_states = n_luh_states +1 - ! end if - ! end do - - ! if (n_luh_states .eq. 0) then - ! write(fates_log(),*) 'error. n_luh_states .eq. 0.' - ! call endrun(msg=errMsg(sourcefile, __LINE__)) - ! endif + call GetLUHStatedata(bc_in(s), state_vector) + + ! if the land use state vector is greater than the minimum value, set landuse_vector_gt_min flag to true + ! otherwise set to false. + do i_lu_state = 1, n_landuse_cats + if (state_vector(i_lu_state) .gt. sites(s)%min_allowed_landuse_fraction) then + sites(s)%landuse_vector_gt_min(i_lu_state) = .true. + else + sites(s)%landuse_vector_gt_min(i_lu_state) = .false. + end if + end do + else ! If LUH2 data is not being used, we initialize with primarylands, ! i.e. array index equals '1' @@ -664,94 +742,163 @@ subroutine init_patches( nsites, sites, bc_in) state_vector(primaryland) = 1._r8 endif - is_first_patch = itrue - ! luh_state_counter = 0 - new_patch_nocomp_loop: do n = start_patch, num_new_patches + ! confirm that state vector sums to 1. + if (abs(sum(state_vector(:))-1._r8) .gt. rsnbl_math_prec) then + write(fates_log(),*) 'error that the state vector must sum to 1, but doesnt' + write(fates_log(),*) 'sum(state_vector)', sum(state_vector) + write(fates_log(),*) state_vector + call endrun(msg=errMsg(sourcefile, __LINE__)) + endif - ! set the PFT index for patches if in nocomp mode. - if(hlm_use_nocomp.eq.itrue)then - nocomp_pft = n - else - nocomp_pft = fates_unset_int - end if + is_first_patch = .true. + + area_error = 0._r8 + ! first make a bare-ground patch if one is needed. + make_bareground_patch_if: if (hlm_use_nocomp.eq.itrue .and. hlm_use_fixed_biogeog .eq.itrue) then + + newparea = area * sites(s)%area_bareground + if (newparea .gt. min_patch_area_forced) then + + allocate(newp) + + call newp%Create(age, newparea, nocomp_bareground_land, nocomp_bareground, & + num_swb, numpft, sites(s)%nlevsoil, hlm_current_tod, & + regeneration_model) + + ! set pointers for first patch (or only patch, if nocomp is false) + newp%patchno = 1 + newp%younger => null() + newp%older => null() + sites(s)%youngest_patch => newp + sites(s)%oldest_patch => newp + is_first_patch = .false. + + ! Initialize the litter pools to zero, these + ! pools will be populated by looping over the existing patches + ! and transfering in mass + if(hlm_use_sp.eq.itrue)then + litt_init = fates_unset_r8 + else + litt_init = 0._r8 + end if + do el=1,num_elements + call newp%litter(el)%InitConditions(init_leaf_fines=litt_init, & + init_root_fines=litt_init, & + init_ag_cwd=litt_init, & + init_bg_cwd=litt_init, & + init_seed=litt_init, & + init_seed_germ=litt_init) + end do - if(hlm_use_nocomp.eq.itrue)then - ! In no competition mode, if we are using the fixed_biogeog filter - ! then each PFT has the area dictated by the surface dataset. + else + area_error = area_error + newparea + endif + endif make_bareground_patch_if - ! If we are not using fixed biogeog model, each PFT gets the same area. - ! i.e. each grid cell is divided exactly into the number of FATES PFTs. + if (hlm_use_luh .eq. itrue) then + end_landuse_idx = n_landuse_cats + else + end_landuse_idx = 1 + endif - if(hlm_use_fixed_biogeog.eq.itrue)then - newparea = sites(s)%area_pft(nocomp_pft) - else - newparea = area / numpft - end if - else ! The default case is initialized w/ one patch with the area of the whole site. - newparea = area - end if !nocomp mode - - luh_state_loop: do i_lu_state = 1, n_active_landuse_cats - lu_state_present_if: if ( state_vector(i_lu_state) .gt. nearzero ) then - - newparea_withlanduse = newparea * state_vector(i_lu_state) - - ! for now, spread nocomp PFTs evenly across land use types - new_patch_area_gt_zero: if(newparea_withlanduse.gt.0._r8)then ! Stop patches being initilialized when PFT not present in nocomop mode - allocate(newp) - - call newp%Create(age, newparea_withlanduse, i_lu_state, nocomp_pft, & - hlm_numSWb, numpft, sites(s)%nlevsoil, hlm_current_tod, & - regeneration_model) - - if(is_first_patch.eq.itrue)then !is this the first patch? - ! set poointers for first patch (or only patch, if nocomp is false) - newp%patchno = 1 - newp%younger => null() - newp%older => null() - sites(s)%youngest_patch => newp - sites(s)%oldest_patch => newp - is_first_patch = ifalse - else - ! Set pointers for N>1 patches. Note this only happens when nocomp mode s on. - ! The new patch is the 'youngest' one, arbitrarily. - newp%patchno = nocomp_pft + (i_lu_state-1) * numpft - newp%older => sites(s)%youngest_patch - newp%younger => null() - sites(s)%youngest_patch%younger => newp - sites(s)%youngest_patch => newp - end if - ! Initialize the litter pools to zero, these - ! pools will be populated by looping over the existing patches - ! and transfering in mass - if(hlm_use_sp.eq.itrue)then - litt_init = fates_unset_r8 + ! Next, create the non-bareground patches. We do this for either of two scenarios: + ! If 1) we are not doing both nocomp & fixed-biogeo + ! 2) we are, but there is some non-zero bare-ground area + not_all_bare_if: if( ((1._r8 - sites(s)%area_bareground) > nearzero) .or. & + (.not.(hlm_use_nocomp.eq.itrue .and. hlm_use_fixed_biogeog.eq.itrue)) ) then + + ! now make one or more vegetated patches based on nocomp and land use logic + luh_state_loop: do i_lu_state = 1, end_landuse_idx + lu_state_present_if: if (state_vector(i_lu_state) .gt. nearzero) then + new_patch_nocomp_loop: do n = 1, num_nocomp_pfts + ! set the PFT index for patches if in nocomp mode. + if(hlm_use_nocomp.eq.itrue)then + nocomp_pft = n else - litt_init = 0._r8 + nocomp_pft = fates_unset_int end if - do el=1,num_elements - call newp%litter(el)%InitConditions(init_leaf_fines=litt_init, & - init_root_fines=litt_init, & - init_ag_cwd=litt_init, & - init_bg_cwd=litt_init, & - init_seed=litt_init, & - init_seed_germ=litt_init) - end do + + if(hlm_use_nocomp.eq.itrue)then + ! In no competition mode, if we are using the fixed_biogeog filter + ! then each PFT has the area dictated by the surface dataset. + + ! If we are not using fixed biogeog model, each PFT gets the same area. + ! i.e. each grid cell is divided exactly into the number of FATES PFTs. + + if(hlm_use_fixed_biogeog.eq.itrue)then + newparea = sites(s)%area_pft(nocomp_pft,i_lu_state) * area * state_vector(i_lu_state) & + * (1._r8 - sites(s)%area_bareground) + else + newparea = area * state_vector(i_lu_state) / numpft + end if + else ! The default case is initialized w/ one patch with the area of the whole site. + newparea = area * state_vector(i_lu_state) + end if !nocomp mode + + ! Stop patches being initilialized when PFT not present in nocomop mode + new_patch_area_gt_zero: if(newparea .gt. min_patch_area_forced) then + allocate(newp) + + call newp%Create(age, newparea, i_lu_state, nocomp_pft, & + num_swb, numpft, sites(s)%nlevsoil, hlm_current_tod, & + regeneration_model) + + if (is_first_patch) then !is this the first patch? + ! set pointers for first patch (or only patch, if nocomp is false) + newp%patchno = 1 + newp%younger => null() + newp%older => null() + sites(s)%youngest_patch => newp + sites(s)%oldest_patch => newp + is_first_patch = .false. + else + ! Set pointers for N>1 patches. Note this only happens when nocomp mode is on, or land use is on. + ! The new patch is the 'youngest' one, arbitrarily. + newp%patchno = nocomp_pft + (i_lu_state-1) * numpft + newp%older => sites(s)%youngest_patch + newp%younger => null() + sites(s)%youngest_patch%younger => newp + sites(s)%youngest_patch => newp + end if - sitep => sites(s) - if(hlm_use_sp.eq.itrue)then - if(nocomp_pft.ne.0)then !don't initialize cohorts for SP bare ground patch - call init_cohorts(sitep, newp, bc_in(s)) + ! Initialize the litter pools to zero, these + ! pools will be populated by looping over the existing patches + ! and transfering in mass + if(hlm_use_sp.eq.itrue)then + litt_init = fates_unset_r8 + else + litt_init = 0._r8 end if - else ! normal non SP case always call init cohorts + do el=1,num_elements + call newp%litter(el)%InitConditions(init_leaf_fines=litt_init, & + init_root_fines=litt_init, & + init_ag_cwd=litt_init, & + init_bg_cwd=litt_init, & + init_seed=litt_init, & + init_seed_germ=litt_init) + end do + + sitep => sites(s) call init_cohorts(sitep, newp, bc_in(s)) - end if - end if new_patch_area_gt_zero + + else + area_error = area_error+ newparea + end if new_patch_area_gt_zero + end do new_patch_nocomp_loop end if lu_state_present_if end do luh_state_loop - end do new_patch_nocomp_loop !no new patches - + end if not_all_bare_if + + ! if we had to skip small patches above, resize things accordingly + if ( area_error .gt. nearzero) then + newp => sites(s)%oldest_patch + do while (associated(newp)) + newp%area = newp%area * area/ (area - area_error) + newp => newp%younger + end do + endif + !check if the total area adds to the same as site area total = 0.0_r8 newp => sites(s)%oldest_patch @@ -763,22 +910,34 @@ subroutine init_patches( nsites, sites, bc_in) area_diff = total - area if (abs(area_diff) > nearzero) then if (abs(area_diff) < area_error_4) then ! this is a precision error - if (sites(s)%oldest_patch%area > area_diff + nearzero) then - ! remove or add extra area - ! if the oldest patch has enough area, use that - sites(s)%oldest_patch%area = sites(s)%oldest_patch%area - area_diff - if (debug) write(fates_log(),*) 'fixing patch precision - oldest', s, area_diff - else ! or otherwise take the area from the youngest patch. - sites(s)%youngest_patch%area = sites(s)%youngest_patch%area - area_diff - if (debug) write(fates_log(),*) 'fixing patch precision -youngest ', s, area_diff - end if + + ! adjust areas of all patches so that they add up to total area + newp => sites(s)%oldest_patch + do while (associated(newp)) + newp%area = newp%area * (area / total) + newp => newp%younger + end do + else !this is a big error not just a precision error. - write(fates_log(),*) 'issue with patch area in EDinit', area_diff, total + write(fates_log(),*) 'issue with patch area in EDinit', area_diff, total,sites(s)%lat,sites(s)%lon + write(fates_log(),*) 'hlm_use_nocomp: ',hlm_use_nocomp + write(fates_log(),*) 'hlm_use_fixed_biogeog: ',hlm_use_fixed_biogeog + newp => sites(s)%oldest_patch + do while (associated(newp)) + write(fates_log(),*) newp%area, newp%nocomp_pft_label, newp%land_use_label + newp => newp%younger + end do + write(fates_log(),*) 'state_vector', state_vector + write(fates_log(),*) 'area_error', area_error + write(fates_log(),*) 'area_bareground', sites(s)%area_bareground + do i_lu_state = 1, end_landuse_idx + write(fates_log(),*) 'sites(s)%area_pft(:,i_lu_state)',i_lu_state, sites(s)%area_pft(:,i_lu_state) + end do call endrun(msg=errMsg(sourcefile, __LINE__)) end if ! big error end if ! too much patch area - ! we might have messed up patch area now - need to correct if SP mode + ! we might have messed up crown areas now - need to correct if SP mode if (hlm_use_sp .eq. itrue) then newp => sites(s)%oldest_patch do while (associated(newp)) @@ -846,6 +1005,18 @@ subroutine init_patches( nsites, sites, bc_in) end do end if + ! check to make sure there are no very tiny patches + do s = 1, nsites + currentPatch => sites(s)%youngest_patch + do while(associated(currentPatch)) + if (currentPatch%area .lt. min_patch_area_forced) then + write(fates_log(),*) 'edinit somehow making tiny patches',currentPatch%land_use_label, currentPatch%nocomp_pft_label, currentPatch%area + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + currentPatch => currentPatch%older + end do + end do + return end subroutine init_patches diff --git a/main/EDMainMod.F90 b/main/EDMainMod.F90 index f05b57d7c2..1b24a940db 100644 --- a/main/EDMainMod.F90 +++ b/main/EDMainMod.F90 @@ -75,6 +75,7 @@ module EDMainMod use EDTypesMod , only : phen_dstat_timeon use FatesConstantsMod , only : itrue,ifalse use FatesConstantsMod , only : primaryland, secondaryland + use FatesConstantsMod , only : n_landuse_cats use FatesConstantsMod , only : nearzero use FatesConstantsMod , only : m2_per_ha use FatesConstantsMod , only : sec_per_day @@ -88,7 +89,6 @@ module EDMainMod use EDLoggingMortalityMod , only : IsItLoggingTime use EDLoggingMortalityMod , only : get_harvestable_carbon use DamageMainMod , only : IsItDamageTime - use EDPatchDynamicsMod , only : get_frac_site_primary use FatesGlobals , only : endrun => fates_endrun use ChecksBalancesMod , only : SiteMassStock use EDMortalityFunctionsMod , only : Mortality_Derivative @@ -166,12 +166,6 @@ subroutine ed_ecosystem_dynamics(currentSite, bc_in, bc_out) call currentSite%flux_diags(el)%ZeroFluxDiags() end do - ! zero dynamics (upfreq_in = 1) output history variables - call fates_hist%zero_site_hvars(currentSite,upfreq_in=1) - - ! zero nutrient fluxes (upfreq_in=5) output hist variables - call fates_hist%zero_site_hvars(currentSite,upfreq_in=5) - ! Call a routine that simply identifies if logging should occur ! This is limited to a global event until more structured event handling is enabled call IsItLoggingTime(hlm_masterproc,currentSite) @@ -225,6 +219,11 @@ subroutine ed_ecosystem_dynamics(currentSite, bc_in, bc_out) ! Integrate state variables from annual rates to daily timestep call ed_integrate_state_variables(currentSite, bc_in, bc_out ) + ! at this point in the call sequence, if flag to transition_landuse_from_off_to_on was set, unset it as it is no longer needed + if(currentSite%transition_landuse_from_off_to_on) then + currentSite%transition_landuse_from_off_to_on = .false. + endif + else ! ed_intergrate_state_variables is where the new cohort flag ! is set. This flag designates wether a cohort has @@ -289,6 +288,7 @@ subroutine ed_ecosystem_dynamics(currentSite, bc_in, bc_out) ! make new patches from disturbed land if (do_patch_dynamics.eq.itrue ) then + call spawn_patches(currentSite, bc_in) call TotalBalanceCheck(currentSite,3) @@ -309,7 +309,7 @@ subroutine ed_ecosystem_dynamics(currentSite, bc_in, bc_out) call TotalBalanceCheck(currentSite,4) ! kill patches that are too small - call terminate_patches(currentSite) + call terminate_patches(currentSite, bc_in) end if call TotalBalanceCheck(currentSite,5) @@ -372,7 +372,7 @@ subroutine ed_integrate_state_variables(currentSite, bc_in, bc_out ) ! a lowered damage state. This cohort should bypass several calculations ! because it inherited them (such as daily carbon balance) real(r8) :: target_leaf_c - real(r8) :: frac_site_primary + real(r8) :: current_fates_landuse_state_vector(n_landuse_cats) real(r8) :: harvestable_forest_c(hlm_num_lu_harvest_cats) integer :: harvest_tag(hlm_num_lu_harvest_cats) @@ -408,7 +408,7 @@ subroutine ed_integrate_state_variables(currentSite, bc_in, bc_out ) !----------------------------------------------------------------------- - call get_frac_site_primary(currentSite, frac_site_primary) + current_fates_landuse_state_vector = currentSite%get_current_landuse_statevector() ! Clear site GPP and AR passing to HLM bc_out%gpp_site = 0._r8 @@ -473,8 +473,8 @@ subroutine ed_integrate_state_variables(currentSite, bc_in, bc_out ) call Mortality_Derivative(currentSite, currentCohort, bc_in, & currentPatch%btran_ft, mean_temp, & currentPatch%land_use_label, & - currentPatch%age_since_anthro_disturbance, frac_site_primary, & - harvestable_forest_c, harvest_tag) + currentPatch%age_since_anthro_disturbance, current_fates_landuse_state_vector(primaryland), & + current_fates_landuse_state_vector(secondaryland), harvestable_forest_c, harvest_tag) ! ----------------------------------------------------------------------------- ! Apply Plant Allocation and Reactive Transport @@ -915,7 +915,8 @@ subroutine TotalBalanceCheck (currentSite, call_index ) site_mass%flux_generic_in + & site_mass%patch_resize_err - flux_out = site_mass%wood_product + & + flux_out = sum(site_mass%wood_product_harvest(:)) + & + sum(site_mass%wood_product_landusechange(:)) + & site_mass%burn_flux_to_atm + & site_mass%seed_out + & site_mass%flux_generic_out + & @@ -946,7 +947,8 @@ subroutine TotalBalanceCheck (currentSite, call_index ) write(fates_log(),*) 'net_root_uptake: ',site_mass%net_root_uptake write(fates_log(),*) 'gpp_acc: ',site_mass%gpp_acc write(fates_log(),*) 'flux_generic_in: ',site_mass%flux_generic_in - write(fates_log(),*) 'wood_product: ',site_mass%wood_product + write(fates_log(),*) 'wood_product_harvest: ',site_mass%wood_product_harvest(:) + write(fates_log(),*) 'wood_product_landusechange: ',site_mass%wood_product_landusechange(:) write(fates_log(),*) 'error from patch resizing: ',site_mass%patch_resize_err write(fates_log(),*) 'burn_flux_to_atm: ',site_mass%burn_flux_to_atm write(fates_log(),*) 'seed_out: ',site_mass%seed_out diff --git a/main/EDParamsMod.F90 b/main/EDParamsMod.F90 index e2c55c6cfc..b0763bbbde 100644 --- a/main/EDParamsMod.F90 +++ b/main/EDParamsMod.F90 @@ -10,6 +10,7 @@ module EDParamsMod use FatesGlobals , only : fates_log use FatesGlobals , only : endrun => fates_endrun use FatesConstantsMod, only : fates_unset_r8 + use FatesConstantsMod, only : cstarvation_model_lin use FatesConstantsMod, only : n_landuse_cats ! CIME Globals @@ -50,7 +51,11 @@ module EDParamsMod ! 1=non-acclimating, 2=Kumarathunge et al., 2019 integer,protected, public :: radiation_model ! Switch betrween Norman (1) and Two-stream (2) radiation models - + + integer,protected, public :: mort_cstarvation_model ! Switch for carbon starvation mortality: + ! 1 -- Linear model + ! 2 -- Exponential model + real(r8),protected, public :: fates_mortality_disturbance_fraction ! the fraction of canopy mortality that results in disturbance real(r8),protected, public :: ED_val_comp_excln ! weighting factor for canopy layer exclusion and promotion real(r8),protected, public :: ED_val_vai_top_bin_width ! width in VAI units of uppermost leaf+stem layer scattering element @@ -72,6 +77,7 @@ module EDParamsMod real(r8),protected, public :: ED_val_patch_fusion_tol ! minimum fraction in difference in profiles between patches real(r8),protected, public :: ED_val_canopy_closure_thresh ! site-level canopy closure point where trees take on forest (narrow) versus savannah (wide) crown allometry integer,protected, public :: stomatal_model ! switch for choosing between stomatal conductance models, 1 for Ball-Berry, 2 for Medlyn + integer,protected, public :: dayl_switch ! switch for turning on or off day length factor scaling for photosynthetic parameters integer,protected, public :: regeneration_model ! Switch for choosing between regeneration models: ! (1) for Fates default ! (2) for the Tree Recruitment Scheme (Hanbury-Brown et al., 2022) @@ -106,33 +112,7 @@ module EDParamsMod real(r8), public :: dinc_vai(nlevleaf) = fates_unset_r8 ! VAI bin widths array real(r8), public :: dlower_vai(nlevleaf) = fates_unset_r8 ! lower edges of VAI bins - ! TODO: we use this cp_maxSWb only because we have a static array q(size=2) of - ! land-ice abledo for vis and nir. This should be a parameter, which would - ! get us on track to start using multi-spectral or hyper-spectral (RGK 02-2017) - - integer, parameter, public :: maxSWb = 2 ! maximum number of broad-bands in the - ! shortwave spectrum cp_numSWb <= cp_maxSWb - ! this is just for scratch-array purposes - ! if cp_numSWb is larger than this value - ! simply bump this number up as needed - -integer, parameter, public :: ivis = 1 ! This is the array index for short-wave - ! radiation in the visible spectrum, as expected - ! in boundary condition files and parameter - ! files. This will be compared with - ! the HLM's expectation in FatesInterfaceMod -integer, parameter, public :: inir = 2 ! This is the array index for short-wave - ! radiation in the near-infrared spectrum, as expected - ! in boundary condition files and parameter - ! files. This will be compared with - ! the HLM's expectation in FatesInterfaceMod - -integer, parameter, public :: ipar = ivis ! The photosynthetically active band - ! can be approximated to be equal to the visible band - - - -integer, parameter, public :: maxpft = 16 ! maximum number of PFTs allowed + integer, parameter, public :: maxpft = 16 ! maximum number of PFTs allowed real(r8),protected,public :: q10_mr ! Q10 for respiration rate (for soil fragmenation and plant respiration) (unitless) real(r8),protected,public :: q10_froz ! Q10 for frozen-soil respiration rates (for soil fragmentation) (unitless) @@ -166,6 +146,7 @@ module EDParamsMod character(len=param_string_length),parameter,public :: name_radiation_model = "fates_rad_model" character(len=param_string_length),parameter,public :: ED_name_hydr_htftype_node = "fates_hydro_htftype_node" character(len=param_string_length),parameter,public :: ED_name_mort_disturb_frac = "fates_mort_disturb_frac" + character(len=param_string_length),parameter,public :: ED_name_mort_cstarvation_model = "fates_mort_cstarvation_model" character(len=param_string_length),parameter,public :: ED_name_comp_excln = "fates_comp_excln" character(len=param_string_length),parameter,public :: ED_name_vai_top_bin_width = "fates_vai_top_bin_width" character(len=param_string_length),parameter,public :: ED_name_vai_width_increase_factor = "fates_vai_width_increase_factor" @@ -186,6 +167,7 @@ module EDParamsMod character(len=param_string_length),parameter,public :: ED_name_patch_fusion_tol= "fates_patch_fusion_tol" character(len=param_string_length),parameter,public :: ED_name_canopy_closure_thresh= "fates_canopy_closure_thresh" character(len=param_string_length),parameter,public :: ED_name_stomatal_model= "fates_leaf_stomatal_model" + character(len=param_string_length),parameter,public :: ED_name_dayl_switch= "fates_daylength_factor_switch" character(len=param_string_length),parameter,public :: ED_name_regeneration_model= "fates_regeneration_model" character(len=param_string_length),parameter,public :: name_theta_cj_c3 = "fates_leaf_theta_cj_c3" @@ -200,7 +182,9 @@ module EDParamsMod character(len=param_string_length),parameter,public :: ED_name_history_height_bin_edges= "fates_history_height_bin_edges" character(len=param_string_length),parameter,public :: ED_name_history_coageclass_bin_edges = "fates_history_coageclass_bin_edges" character(len=param_string_length),parameter,public :: ED_name_history_damage_bin_edges = "fates_history_damage_bin_edges" + character(len=param_string_length),parameter,public :: ED_name_crop_lu_pft_vector = "fates_landuse_crop_lu_pft_vector" character(len=param_string_length),parameter,public :: ED_name_maxpatches_by_landuse = "fates_maxpatches_by_landuse" + character(len=param_string_length),parameter,public :: ED_name_max_nocomp_pfts_by_landuse = "fates_max_nocomp_pfts_by_landuse" ! Hydraulics Control Parameters (ONLY RELEVANT WHEN USE_FATES_HYDR = TRUE) @@ -255,8 +239,12 @@ module EDParamsMod ! thus they are not protected here. integer, public :: maxpatches_by_landuse(n_landuse_cats) + integer, public :: max_nocomp_pfts_by_landuse(n_landuse_cats) integer, public :: maxpatch_total + ! which crops can be grown on a given crop land use type + integer,protected,public :: crop_lu_pft_vector(n_landuse_cats) + ! Maximum allowable cohorts per patch integer, protected, public :: max_cohort_per_patch character(len=param_string_length), parameter, public :: maxcohort_name = "fates_maxcohort" @@ -298,10 +286,6 @@ module EDParamsMod ! leftovers will be left onsite as large CWD character(len=param_string_length),parameter,public :: logging_name_export_frac ="fates_landuse_logging_export_frac" - real(r8),protected,public :: pprodharv10_forest_mean ! "mean harvest mortality proportion of deadstem to 10-yr - ! product pool (pprodharv10) of all woody PFT types - character(len=param_string_length),parameter,public :: logging_name_pprodharv10="fates_landuse_pprodharv10_forest_mean" - ! grazing-related parameters character(len=param_string_length),parameter,public :: ED_name_landuse_grazing_palatability = "fates_landuse_grazing_palatability" character(len=param_string_length),parameter,public :: ED_name_landuse_grazing_rate = "fates_landuse_grazing_rate" @@ -346,6 +330,7 @@ subroutine FatesParamsInit() maintresp_leaf_model = -9 radiation_model = -9 fates_mortality_disturbance_fraction = nan + mort_cstarvation_model = -9 ED_val_comp_excln = nan ED_val_vai_top_bin_width = nan ED_val_vai_width_increase_factor = nan @@ -366,6 +351,7 @@ subroutine FatesParamsInit() ED_val_patch_fusion_tol = nan ED_val_canopy_closure_thresh = nan stomatal_model = -9 + dayl_switch = -9 regeneration_model = -9 stomatal_assim_model = -9 max_cohort_per_patch = -9 @@ -383,7 +369,6 @@ subroutine FatesParamsInit() logging_event_code = nan logging_dbhmax_infra = nan logging_export_frac = nan - pprodharv10_forest_mean = nan eca_plant_escalar = nan q10_mr = nan q10_froz = nan @@ -458,6 +443,9 @@ subroutine FatesRegisterParams(fates_params) call fates_params%RegisterParameter(name=ED_name_mort_disturb_frac, dimension_shape=dimension_shape_scalar, & dimension_names=dim_names_scalar) + call fates_params%RegisterParameter(name=ED_name_mort_cstarvation_model, dimension_shape=dimension_shape_scalar, & + dimension_names=dim_names_scalar) + call fates_params%RegisterParameter(name=ED_name_comp_excln, dimension_shape=dimension_shape_scalar, & dimension_names=dim_names_scalar) @@ -517,7 +505,10 @@ subroutine FatesRegisterParams(fates_params) call fates_params%RegisterParameter(name=ED_name_stomatal_model, dimension_shape=dimension_shape_scalar, & dimension_names=dim_names_scalar) - + + call fates_params%RegisterParameter(name=ED_name_dayl_switch, dimension_shape=dimension_shape_scalar, & + dimension_names=dim_names_scalar) + call fates_params%RegisterParameter(name=ED_name_regeneration_model, dimension_shape=dimension_shape_scalar, & dimension_names=dim_names_scalar) @@ -572,9 +563,6 @@ subroutine FatesRegisterParams(fates_params) call fates_params%RegisterParameter(name=logging_name_export_frac, dimension_shape=dimension_shape_scalar, & dimension_names=dim_names_scalar) - call fates_params%RegisterParameter(name=logging_name_pprodharv10, dimension_shape=dimension_shape_scalar, & - dimension_names=dim_names_scalar) - call fates_params%RegisterParameter(name=eca_name_plant_escalar, dimension_shape=dimension_shape_scalar, & dimension_names=dim_names_scalar) @@ -619,9 +607,15 @@ subroutine FatesRegisterParams(fates_params) call fates_params%RegisterParameter(name=ED_name_history_damage_bin_edges, dimension_shape=dimension_shape_1d, & dimension_names=dim_names_damageclass) + call fates_params%RegisterParameter(name=ED_name_crop_lu_pft_vector, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names_landuse) + call fates_params%RegisterParameter(name=ED_name_maxpatches_by_landuse, dimension_shape=dimension_shape_1d, & dimension_names=dim_names_landuse) + call fates_params%RegisterParameter(name=ED_name_max_nocomp_pfts_by_landuse, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names_landuse) + end subroutine FatesRegisterParams @@ -637,8 +631,10 @@ subroutine FatesReceiveParams(fates_params) real(r8) :: tmpreal ! local real variable for changing type on read real(r8), allocatable :: hydr_htftype_real(:) - real(r8) :: tmp_vector_by_landuse(n_landuse_cats) ! local real vector for changing type on read - + real(r8), allocatable :: tmp_vector_by_landuse1(:) ! local real vector for changing type on read + real(r8), allocatable :: tmp_vector_by_landuse2(:) ! local real vector for changing type on read + real(r8), allocatable :: tmp_vector_by_landuse3(:) ! local real vector for changing type on read + call fates_params%RetrieveParameter(name=ED_name_photo_temp_acclim_timescale, & data=photo_temp_acclim_timescale) @@ -672,6 +668,10 @@ subroutine FatesReceiveParams(fates_params) call fates_params%RetrieveParameter(name=ED_name_mort_disturb_frac, & data=fates_mortality_disturbance_fraction) + call fates_params%RetrieveParameter(name=ED_name_mort_cstarvation_model, & + data=tmpreal) + mort_cstarvation_model = nint(tmpreal) + call fates_params%RetrieveParameter(name=ED_name_comp_excln, & data=ED_val_comp_excln) @@ -733,6 +733,10 @@ subroutine FatesReceiveParams(fates_params) data=tmpreal) stomatal_model = nint(tmpreal) + call fates_params%RetrieveParameter(name=ED_name_dayl_switch, & + data=tmpreal) + dayl_switch = nint(tmpreal) + call fates_params%RetrieveParameter(name=ED_name_regeneration_model, & data=tmpreal) regeneration_model = nint(tmpreal) @@ -791,9 +795,6 @@ subroutine FatesReceiveParams(fates_params) call fates_params%RetrieveParameter(name=logging_name_export_frac, & data=logging_export_frac) - call fates_params%RetrieveParameter(name=logging_name_pprodharv10, & - data=pprodharv10_forest_mean) - call fates_params%RetrieveParameter(name=eca_name_plant_escalar, & data=eca_plant_escalar) @@ -843,11 +844,24 @@ subroutine FatesReceiveParams(fates_params) call fates_params%RetrieveParameterAllocate(name=ED_name_history_damage_bin_edges, & data=ED_val_history_damage_bin_edges) - call fates_params%RetrieveParameter(name=ED_name_maxpatches_by_landuse, & - data=tmp_vector_by_landuse) + call fates_params%RetrieveParameterAllocate(name=ED_name_crop_lu_pft_vector, & + data=tmp_vector_by_landuse1) - maxpatches_by_landuse(:) = nint(tmp_vector_by_landuse(:)) + crop_lu_pft_vector(:) = nint(tmp_vector_by_landuse1(:)) + deallocate(tmp_vector_by_landuse1) + + call fates_params%RetrieveParameterAllocate(name=ED_name_maxpatches_by_landuse, & + data=tmp_vector_by_landuse2) + + maxpatches_by_landuse(:) = nint(tmp_vector_by_landuse2(:)) maxpatch_total = sum(maxpatches_by_landuse(:)) + deallocate(tmp_vector_by_landuse2) + + call fates_params%RetrieveParameterAllocate(name=ED_name_max_nocomp_pfts_by_landuse, & + data=tmp_vector_by_landuse3) + + max_nocomp_pfts_by_landuse(:) = nint(tmp_vector_by_landuse3(:)) + deallocate(tmp_vector_by_landuse3) call fates_params%RetrieveParameterAllocate(name=ED_name_hydr_htftype_node, & data=hydr_htftype_real) @@ -900,7 +914,8 @@ subroutine FatesReportParams(is_master) write(fates_log(),fmt0) 'ED_val_cohort_age_fusion_tol = ',ED_val_cohort_age_fusion_tol write(fates_log(),fmt0) 'ED_val_patch_fusion_tol = ',ED_val_patch_fusion_tol write(fates_log(),fmt0) 'ED_val_canopy_closure_thresh = ',ED_val_canopy_closure_thresh - write(fates_log(),fmt0) 'regeneration_model = ',regeneration_model + write(fates_log(),fmt0) 'regeneration_model = ',regeneration_model + write(fates_log(),fmt0) 'dayl_switch = ',dayl_switch write(fates_log(),fmt0) 'stomatal_model = ',stomatal_model write(fates_log(),fmt0) 'stomatal_assim_model = ',stomatal_assim_model write(fates_log(),fmt0) 'hydro_kmax_rsurf1 = ',hydr_kmax_rsurf1 diff --git a/main/EDPftvarcon.F90 b/main/EDPftvarcon.F90 index d344f82c8d..8e10ebdcf7 100644 --- a/main/EDPftvarcon.F90 +++ b/main/EDPftvarcon.F90 @@ -6,7 +6,9 @@ module EDPftvarcon ! read and initialize vegetation (PFT) constants. ! ! !USES: - use EDParamsMod , only : maxSWb, ivis, inir + + use FatesRadiationMemMod, only: num_swb,ivis,inir + use FatesRadiationMemMod, only: norman_solver,twostr_solver use FatesConstantsMod, only : r8 => fates_r8 use FatesConstantsMod, only : nearzero use FatesConstantsMod, only : itrue, ifalse @@ -90,6 +92,12 @@ module EDPftvarcon real(r8), allocatable :: maintresp_leaf_ryan1991_baserate(:) ! leaf maintenance respiration per Ryan et al 1991 + + + real(r8), allocatable :: maintresp_leaf_vert_scaler_coeff1(:) ! leaf maintenance respiration decrease through the canopy param 1 + ! only with Atkin et al. 2017 respiration model + real(r8), allocatable :: maintresp_leaf_vert_scaler_coeff2(:) ! leaf maintenance respiration decrease through the canopy param 2 + ! only with Atkin et al. 2017 respiraiton model real(r8), allocatable :: bmort(:) real(r8), allocatable :: mort_ip_size_senescence(:) ! inflection point of dbh dependent senescence real(r8), allocatable :: mort_r_size_senescence(:) ! rate of change in mortality with dbh @@ -269,9 +277,14 @@ module EDPftvarcon real(r8), allocatable :: hydr_thetas_node(:,:) ! saturated water content (cm3/cm3) ! Table that maps HLM pfts to FATES pfts for fixed biogeography mode - ! The values are area fractions (NOT IMPLEMENTED) + ! The values are area fractions real(r8), allocatable :: hlm_pft_map(:,:) + ! Land-use and land-use change related PFT parameters + real(r8), allocatable :: harvest_pprod10(:) ! fraction of harvest wood product that goes to 10-year product pool (remainder goes to 100-year pool) + real(r8), allocatable :: landusechange_frac_burned(:) ! fraction of land use change-generated and not-exported material that is burned (the remainder goes to litter) + real(r8), allocatable :: landusechange_frac_exported(:) ! fraction of land use change-generated wood material that is exported to wood product (the remainder is either burned or goes to litter) + real(r8), allocatable :: landusechange_pprod10(:) ! fraction of land use change wood product that goes to 10-year product pool (remainder goes to 100-year pool) contains procedure, public :: Init => EDpftconInit @@ -469,6 +482,16 @@ subroutine Register_PFT(this, fates_params) call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) + + + name = 'fates_maintresp_leaf_vert_scaler_coeff1' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + + name = 'fates_maintresp_leaf_vert_scaler_coeff2' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + name = 'fates_prescribed_npp_canopy' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) @@ -780,6 +803,22 @@ subroutine Register_PFT(this, fates_params) call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) + name = 'fates_landuse_harvest_pprod10' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + + name = 'fates_landuse_luc_frac_burned' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + + name = 'fates_landuse_luc_frac_exported' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + + name = 'fates_landuse_luc_pprod10' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + name = 'fates_dev_arbitrary_pft' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) @@ -910,6 +949,14 @@ subroutine Receive_PFT(this, fates_params) call fates_params%RetrieveParameterAllocate(name=name, & data=this%maintresp_leaf_ryan1991_baserate) + name = 'fates_maintresp_leaf_vert_scaler_coeff1' + call fates_params%RetrieveParameterAllocate(name=name, & + data=this%maintresp_leaf_vert_scaler_coeff1) + + name = 'fates_maintresp_leaf_vert_scaler_coeff2' + call fates_params%RetrieveParameterAllocate(name=name, & + data=this%maintresp_leaf_vert_scaler_coeff2) + name = 'fates_prescribed_npp_canopy' call fates_params%RetrieveParameterAllocate(name=name, & data=this%prescribed_npp_canopy) @@ -1240,6 +1287,22 @@ subroutine Receive_PFT(this, fates_params) call fates_params%RetrieveParameterAllocate(name=name, & data=this%hlm_pft_map) + name = 'fates_landuse_harvest_pprod10' + call fates_params%RetrieveParameterAllocate(name=name, & + data=this%harvest_pprod10) + + name = 'fates_landuse_luc_frac_burned' + call fates_params%RetrieveParameterAllocate(name=name, & + data=this%landusechange_frac_burned) + + name = 'fates_landuse_luc_frac_exported' + call fates_params%RetrieveParameterAllocate(name=name, & + data=this%landusechange_frac_exported) + + name = 'fates_landuse_luc_pprod10' + call fates_params%RetrieveParameterAllocate(name=name, & + data=this%landusechange_pprod10) + end subroutine Receive_PFT !----------------------------------------------------------------------- @@ -1338,7 +1401,7 @@ subroutine Receive_PFT_numrad(this, fates_params) lower_bound_1 = lower_bound_pft upper_bound_1 = lower_bound_pft + dimension_sizes(1) - 1 lower_bound_2 = lower_bound_general - upper_bound_2 = maxSWb ! When we have radiation parameters read in as a vector + upper_bound_2 = num_swb ! When we have radiation parameters read in as a vector ! We will compare the vector dimension size that we ! read-in to the parameterized size that fates expects @@ -1735,6 +1798,8 @@ subroutine FatesReportPFTParams(is_master) write(fates_log(),fmt0) 'hydro_vg_alpha_node = ',EDPftvarcon_inst%hydr_vg_alpha_node write(fates_log(),fmt0) 'hydro_vg_m_node = ',EDPftvarcon_inst%hydr_vg_m_node write(fates_log(),fmt0) 'hydro_vg_n_node = ',EDPftvarcon_inst%hydr_vg_n_node + write(fates_log(),fmt0) 'maintresp_leaf_vert_scaler_coeff1 = ',EDPftvarcon_inst%maintresp_leaf_vert_scaler_coeff1 + write(fates_log(),fmt0) 'maintresp_leaf_vert_scaler_coeff2 = ',EDPftvarcon_inst%maintresp_leaf_vert_scaler_coeff2 write(fates_log(),*) '-------------------------------------------------' end if @@ -1762,10 +1827,13 @@ subroutine FatesCheckParams(is_master) use FatesConstantsMod, only : lmr_r_2 use EDParamsMod , only : logging_mechanical_frac, logging_collateral_frac use EDParamsMod , only : logging_direct_frac,logging_export_frac - use EDParamsMod , only : radiation_model + use EDParamsMod , only : radiation_model, dayl_switch use FatesInterfaceTypesMod, only : hlm_use_fixed_biogeog,hlm_use_sp, hlm_name use FatesInterfaceTypesMod, only : hlm_use_inventory_init - + use FatesInterfaceTypesMod, only : hlm_use_nocomp + use EDParamsMod , only : max_nocomp_pfts_by_landuse, maxpatches_by_landuse + use FatesConstantsMod , only : n_landuse_cats + ! Argument logical, intent(in) :: is_master ! Only log if this is the master proc @@ -1778,6 +1846,7 @@ subroutine FatesCheckParams(is_master) integer :: norgans ! size of the plant organ dimension integer :: hlm_pft ! used in fixed biogeog mode integer :: fates_pft ! used in fixed biogeog mode + integer :: i_lu ! land use index real(r8) :: sumarea ! area of PFTs in nocomp mode. real(r8) :: neg_lmr_temp ! temperature at which lmr would got negative @@ -1789,10 +1858,10 @@ subroutine FatesCheckParams(is_master) if(.not.is_master) return - if(radiation_model.ne.1) then - write(fates_log(),*) 'The only available canopy radiation model' - write(fates_log(),*) 'is the Norman scheme: fates_rad_model = 1' - write(fates_log(),*) 'The two-stream scheme is not available yet' + if(.not.any(radiation_model == [norman_solver,twostr_solver])) then + write(fates_log(),*) 'The only available canopy radiation models' + write(fates_log(),*) 'are the Norman and Two-stream schemes, ' + write(fates_log(),*) 'fates_rad_model = 1 or 2 ...' write(fates_log(),*) 'You specified fates_rad_model = ',radiation_model write(fates_log(),*) 'Aborting' call endrun(msg=errMsg(sourcefile, __LINE__)) @@ -1808,6 +1877,13 @@ subroutine FatesCheckParams(is_master) call endrun(msg=errMsg(sourcefile, __LINE__)) end if + if(.not.any(dayl_switch == [itrue,ifalse])) then + write(fates_log(),*) 'The only valid switch options for ' + write(fates_log(),*) 'fates_daylength_factor_switch is 0 or 1 ...' + write(fates_log(),*) 'You specified fates_daylength_factor_switch = ',dayl_switch + write(fates_log(),*) 'Aborting' + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if select case (hlm_parteh_mode) case (prt_cnp_flex_allom_hyp) @@ -1843,7 +1919,6 @@ subroutine FatesCheckParams(is_master) call endrun(msg=errMsg(sourcefile, __LINE__)) end if end if - end if end if @@ -1869,7 +1944,25 @@ subroutine FatesCheckParams(is_master) call endrun(msg=errMsg(sourcefile, __LINE__)) end if end if - + + ! We are using a simple phosphatase model right now. There is + ! no critical value (lambda) , and there is no preferential uptake (alpha). + ! Make sure these parameters are both set to 0. + + if ((hlm_phosphorus_spec>0) .and. (trim(hlm_nu_com).eq.'ECA')) then + if (any(abs(EDPftvarcon_inst%eca_lambda_ptase(:)) > nearzero ) ) then + write(fates_log(),*) 'Critical Values for phosphatase in ECA are not' + write(fates_log(),*) 'enabled right now. Please set fates_eca_lambda_ptase = 0' + write(fates_log(),*) ' Aborting' + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + if (any(abs(EDPftvarcon_inst%eca_alpha_ptase(:)) > nearzero ) ) then + write(fates_log(),*) 'There is no preferential plant uptake of P from phosphatase' + write(fates_log(),*) 'enabled right now. Please set fates_eca_alpha_ptase = 0' + write(fates_log(),*) ' Aborting' + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + end if case (prt_carbon_allom_hyp) ! No additional checks needed for now. @@ -1913,12 +2006,15 @@ subroutine FatesCheckParams(is_master) end if end if + + + do ipft = 1,npft ! xl must be between -0.4 and 0.6 according to Bonan (2019) doi:10.1017/9781107339217 pg. 238 !----------------------------------------------------------------------------------- if (EDPftvarcon_inst%xl(ipft) < -0.4 .or. EDPftvarcon_inst%xl(ipft) > 0.6) then - write(fates_log(),*) 'fates_rad_leaf_xl for pft ', ipft, ' is outside the allowed range of -0.6 to 0.4' + write(fates_log(),*) 'fates_rad_leaf_xl for pft ', ipft, ' is outside the allowed range of -0.4 to 0.6' write(fates_log(),*) 'Aborting' call endrun(msg=errMsg(sourcefile, __LINE__)) end if @@ -2140,6 +2236,25 @@ subroutine FatesCheckParams(is_master) end do !ipft + ! if nocomp is enabled, check to make sure the max number of nocomp PFTs per land use is + ! less than or equal to the max number of patches per land use. (unless this is an + ! SP run, then all PFTS are tracked on the primary LU and the others are allocated + ! zero patch space + + if ( hlm_use_nocomp .eq. itrue .and. hlm_use_sp.eq.ifalse) then + do i_lu = 1, n_landuse_cats + if (max_nocomp_pfts_by_landuse(i_lu) .gt. maxpatches_by_landuse(i_lu)) then + write(fates_log(),*) 'The max number of nocomp PFTs must all be less than or equal to the number of patches, for a given land use type' + write(fates_log(),*) 'land use index:',i_lu + write(fates_log(),*) 'max_nocomp_pfts_by_landuse(i_lu):', max_nocomp_pfts_by_landuse(i_lu) + write(fates_log(),*) 'maxpatches_by_landuse(i_lu):', maxpatches_by_landuse(i_lu) + write(fates_log(),*) 'Aborting' + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + end do + endif + + ! Check the temperature at which Rdark would become negative for each PFT - ! given their parameters !------------------------------------------------------------------------------------ diff --git a/main/EDTypesMod.F90 b/main/EDTypesMod.F90 index 575978b063..f638182484 100644 --- a/main/EDTypesMod.F90 +++ b/main/EDTypesMod.F90 @@ -4,6 +4,10 @@ module EDTypesMod use FatesGlobals, only : endrun => fates_endrun use FatesConstantsMod, only : ifalse use FatesConstantsMod, only : itrue + use FatesConstantsMod, only : nocomp_bareground_land + use FatesConstantsMod, only : secondaryland + use FatesConstantsMod, only : secondary_age_threshold + use FatesConstantsMod, only : nearzero use FatesGlobals, only : fates_log use FatesHydraulicsMemMod, only : ed_cohort_hydr_type use FatesHydraulicsMemMod, only : ed_site_hydr_type @@ -28,9 +32,10 @@ module EDTypesMod use FatesInterfaceTypesMod,only : hlm_parteh_mode use FatesCohortMod, only : fates_cohort_type use FatesPatchMod, only : fates_patch_type - use EDParamsMod, only : maxSWb, nclmax, nlevleaf, maxpft + use EDParamsMod, only : nclmax, nlevleaf, maxpft use FatesConstantsMod, only : n_dbh_bins, n_dist_types use shr_log_mod, only : errMsg => shr_log_errMsg + use SFFireWeatherMod, only : fire_weather implicit none private ! By default everything is private @@ -149,8 +154,13 @@ module EDTypesMod type, public :: site_fluxdiags_type ! ---------------------------------------------------------------------------------- - ! Diagnostics for fluxes into the litter pool from plants - ! these fluxes are the total from + ! Diagnostics of fluxes + ! These act as an intermediary to write fluxes to the history + ! file after number densities of plants have changed. They also + ! allow the history flux diagnostics to be rebuilt during restart + ! + ! + ! Litter fluxes are the total from ! (1) turnover from living plants ! (2) mass transfer from non-disturbance inducing mortality events ! (3) mass transfer from disturbance inducing mortality events @@ -161,6 +171,13 @@ module EDTypesMod real(r8) :: cwd_bg_input(1:ncwd) real(r8),allocatable :: leaf_litter_input(:) real(r8),allocatable :: root_litter_input(:) + + ! This variable is slated as to-do, but the fluxdiags type needs + ! to be refactored first. Currently this type is allocated + ! by chemical species (ie C, N or P). GPP is C, but not N or P (RGK 0524) + ! Previous day GPP [kgC/m2/year], partitioned by size x pft + !real(r8),allocatable :: gpp_prev_scpf(:) + contains @@ -204,7 +221,10 @@ module EDTypesMod real(r8) :: frag_out ! Litter and coarse woody debris fragmentation flux [kg/site/day] - real(r8) :: wood_product ! Total mass exported as wood product [kg/site/day] + real(r8) :: wood_product_harvest(maxpft) ! Total mass exported as wood product from wood harvest [kg/site/day] + + real(r8) :: wood_product_landusechange(maxpft) ! Total mass exported as wood product from land use change [kg/site/day] + real(r8) :: burn_flux_to_atm ! Total mass burned and exported to the atmosphere [kg/site/day] real(r8) :: flux_generic_in ! Used for prescribed or artificial input fluxes @@ -251,7 +271,9 @@ module EDTypesMod real(r8) :: lon ! longitude: degrees ! Fixed Biogeography mode inputs - real(r8), allocatable :: area_PFT(:) ! Area allocated to individual PFTs + real(r8), allocatable :: area_PFT(:,:) ! Area allocated to individual PFTs, indexed by land use class [ha/ha of non-bareground area] + real(r8) :: area_bareground ! Area allocated to bare ground in nocomp configurations (corresponds to HLM PFT 0) [ha/ha] + integer, allocatable :: use_this_pft(:) ! Is area_PFT > 0 ? (1=yes, 0=no) ! Total area of patches in each age bin [m2] @@ -267,7 +289,24 @@ module EDTypesMod ! which is used for fixation - + ! Two-stream scratch arrays + real(r8), allocatable :: omega_2str(:,:) ! This is the matrix that is inverted to solve + ! the linear system of equations in the two-stream + ! radiation module. This array will grow + ! and shrink depending on how many scattering + ! elements there are. This matrix is square, + ! and needs to be larger than 2 x number-of-elements + ! for each patch on the site + + real(r8), allocatable :: taulambda_2str(:) ! These are the coefficients of the two-stream + ! linear system of equations (ie the unknowns, "lambda") + ! As well as the left-side (constants, "tau"). Since + ! the LAPACK solver dgesv uses the latter + ! as the argument and over-writes, we only + ! need one array + + integer, allocatable :: ipiv_2str(:) ! pivot indices for the lapack 2str solver + ! SP mode target PFT level variables real(r8), allocatable :: sp_tlai(:) ! target TLAI per FATES pft real(r8), allocatable :: sp_tsai(:) ! target TSAI per FATES pft @@ -320,10 +359,10 @@ module EDTypesMod ! FIRE real(r8) :: wind ! daily wind in m/min for Spitfire units - real(r8) :: acc_ni ! daily nesterov index accumulating over time. real(r8) :: fdi ! daily probability an ignition event will start a fire real(r8) :: NF ! daily ignitions in km2 real(r8) :: NF_successful ! daily ignitions in km2 that actually lead to fire + class(fire_weather), pointer :: fireWeather ! fire weather object ! PLANT HYDRAULICS type(ed_site_hydr_type), pointer :: si_hydr @@ -365,18 +404,18 @@ module EDTypesMod real(r8) :: fmort_crownarea_canopy ! crownarea of canopy indivs killed due to fire per year. [m2/sec] real(r8) :: fmort_crownarea_ustory ! crownarea of understory indivs killed due to fire per year [m2/sec] - real(r8), allocatable :: term_nindivs_canopy(:,:) ! number of canopy individuals that were in cohorts which - ! were terminated this timestep, on size x pft - real(r8), allocatable :: term_nindivs_ustory(:,:) ! number of understory individuals that were in cohorts which - ! were terminated this timestep, on size x pft + real(r8), allocatable :: term_nindivs_canopy(:,:,:) ! number of canopy individuals that were in cohorts which + ! were terminated this timestep, by termination type, size x pft + real(r8), allocatable :: term_nindivs_ustory(:,:,:) ! number of understory individuals that were in cohorts which + ! were terminated this timestep, by termination type, size x pft - real(r8), allocatable :: term_carbonflux_canopy(:) ! carbon flux from live to dead pools associated - ! with termination mortality, per canopy level. [kgC/ha/day] - real(r8), allocatable :: term_carbonflux_ustory(:) ! carbon flux from live to dead pools associated - ! with termination mortality, per canopy level. [kgC/ha/day] - real(r8), allocatable :: imort_carbonflux(:) ! biomass of individuals killed due to impact mortality per year. [kgC/m2/sec] - real(r8), allocatable :: fmort_carbonflux_canopy(:) ! biomass of canopy indivs killed due to fire per year. [gC/m2/sec] - real(r8), allocatable :: fmort_carbonflux_ustory(:) ! biomass of understory indivs killed due to fire per year [gC/m2/sec] + real(r8), allocatable :: term_carbonflux_canopy(:,:) ! carbon flux from live to dead pools associated + ! with termination mortality, by termination type and pft. [kgC/ha/day] + real(r8), allocatable :: term_carbonflux_ustory(:,:) ! carbon flux from live to dead pools associated + ! with termination mortality, by termination type and pft. [kgC/ha/day] + real(r8), allocatable :: imort_carbonflux(:) ! biomass of individuals killed due to impact mortality per year, by pft. [kgC/m2/sec] + real(r8), allocatable :: fmort_carbonflux_canopy(:) ! biomass of canopy indivs killed due to fire per year, by pft. [gC/m2/sec] + real(r8), allocatable :: fmort_carbonflux_ustory(:) ! biomass of understory indivs killed due to fire per year, by pft [gC/m2/sec] real(r8), allocatable :: term_abg_flux(:,:) ! aboveground biomass lost due to termination mortality x size x pft real(r8), allocatable :: imort_abg_flux(:,:) ! aboveground biomass lost due to impact mortality x size x pft [kgC/m2/sec] @@ -431,6 +470,15 @@ module EDTypesMod real(r8) :: primary_land_patchfusion_error ! error term in total area of primary patches associated with patch fusion [m2/m2/day] real(r8) :: landuse_transition_matrix(n_landuse_cats, n_landuse_cats) ! land use transition matrix as read in from HLM and aggregated to FATES land use types [m2/m2/year] + real(r8) :: min_allowed_landuse_fraction ! minimum amount of land-use type below which the resulting patches would be too small [m2/m2] + logical, allocatable :: landuse_vector_gt_min(:) ! is the land use state vector for each land use type greater than the minimum below which we ignore? + logical :: transition_landuse_from_off_to_on ! special flag to use only when reading restarts, which triggers procedure to initialize land use + + contains + + procedure, public :: get_current_landuse_statevector + procedure, public :: get_secondary_young_fraction + end type ed_site_type ! Make public necessary subroutines and functions @@ -448,6 +496,11 @@ subroutine ZeroFluxDiags(this) this%cwd_bg_input(:) = 0._r8 this%leaf_litter_input(:) = 0._r8 this%root_litter_input(:) = 0._r8 + + ! We don't zero gpp_prev_scpf because this is not + ! incremented like others, it is assigned at the end + ! of the daily history write process + return end subroutine ZeroFluxDiags @@ -474,7 +527,8 @@ subroutine ZeroMassBalFlux(this) this%seed_in = 0._r8 this%seed_out = 0._r8 this%frag_out = 0._r8 - this%wood_product = 0._r8 + this%wood_product_harvest(:) = 0._r8 + this%wood_product_landusechange(:) = 0._r8 this%burn_flux_to_atm = 0._r8 this%flux_generic_in = 0._r8 this%flux_generic_out = 0._r8 @@ -501,7 +555,82 @@ subroutine dump_site(csite) write(fates_log(),*) '----------------------------------------' return -end subroutine dump_site + end subroutine dump_site + + ! ===================================================================================== + + function get_current_landuse_statevector(this) result(current_state_vector) + + ! + ! !DESCRIPTION: + ! Calculate how much of a site is each land use category. + ! this does not include bare ground when nocomp + fixed biogeography is on, + ! so will not sum to one in that case. otherwise it will sum to one. + ! + ! !USES: + ! + ! !ARGUMENTS: + class(ed_site_type) :: this + real(r8) :: current_state_vector(n_landuse_cats) + + ! !LOCAL VARIABLES: + type(fates_patch_type), pointer :: currentPatch + + current_state_vector(:) = 0._r8 + + currentPatch => this%oldest_patch + do while (associated(currentPatch)) + if (currentPatch%land_use_label .gt. nocomp_bareground_land) then + current_state_vector(currentPatch%land_use_label) = & + current_state_vector(currentPatch%land_use_label) + & + currentPatch%area/AREA + end if + currentPatch => currentPatch%younger + end do + + end function get_current_landuse_statevector + + ! ===================================================================================== + + function get_secondary_young_fraction(this) result(secondary_young_fraction) + + ! + ! !DESCRIPTION: + ! Calculate how much of the secondary area is "young", i.e. below the age threshold. + ! If no seconday patch area at all, return -1. + ! + ! !USES: + ! + ! !ARGUMENTS: + class(ed_site_type) :: this + real(r8) :: secondary_young_fraction + real(r8) :: secondary_young_area + real(r8) :: secondary_old_area + + ! !LOCAL VARIABLES: + type(fates_patch_type), pointer :: currentPatch + + secondary_young_area = 0._r8 + secondary_old_area = 0._r8 + + currentPatch => this%oldest_patch + do while (associated(currentPatch)) + if (currentPatch%land_use_label .eq. secondaryland) then + if ( currentPatch%age .ge. secondary_age_threshold ) then + secondary_old_area = secondary_old_area + currentPatch%area + else + secondary_young_area = secondary_young_area + currentPatch%area + end if + end if + currentPatch => currentPatch%younger + end do + + if ( (secondary_young_area + secondary_old_area) .gt. nearzero ) then + secondary_young_fraction = secondary_young_area / (secondary_young_area + secondary_old_area) + else + secondary_young_fraction = -1._r8 + endif + + end function get_secondary_young_fraction - end module EDTypesMod diff --git a/main/FatesConstantsMod.F90 b/main/FatesConstantsMod.F90 index 4ce33eb839..90033cb549 100644 --- a/main/FatesConstantsMod.F90 +++ b/main/FatesConstantsMod.F90 @@ -34,8 +34,6 @@ module FatesConstantsMod ! are used, but this helps allocate scratch ! space and output arrays. - integer, parameter, public :: n_rad_stream_types = 2 ! The number of radiation streams used (direct/diffuse) - integer , parameter, public :: N_DBH_BINS = 6 ! no. of dbh bins used when comparing patches real(fates_r8), parameter, public :: patchfusion_dbhbin_loweredges(N_DBH_BINS) = & (/0._fates_r8, 5._fates_r8, 20._fates_r8, 50._fates_r8, 100._fates_r8, 150._fates_r8/) ! array of bin lower edges for comparing patches @@ -47,14 +45,21 @@ module FatesConstantsMod integer , parameter, public :: dtype_ilog = 3 ! index for logging generated disturbance event integer , parameter, public :: dtype_ilandusechange = 4 ! index for land use change disturbance (not including logging) - ! Labels for patch disturbance history + ! Labels for patch land use type information integer, parameter, public :: n_landuse_cats = 5 integer, parameter, public :: primaryland = 1 integer, parameter, public :: secondaryland = 2 integer, parameter, public :: rangeland = 3 integer, parameter, public :: pastureland = 4 integer, parameter, public :: cropland = 5 + logical, parameter, dimension(n_landuse_cats), public :: is_crop = [.false., .false.,.false.,.false.,.true.] + integer, parameter, public :: n_crop_lu_types = 1 + + ! Bareground nocomp land use label + integer, parameter, public :: nocomp_bareground_land = 0 ! not a real land use type, only for labeling any bare-ground nocomp patches + ! Bareground nocomp PFT label for no competition mode + integer, parameter, public :: nocomp_bareground = 0 integer, parameter, public :: leaves_on = 2 ! Flag specifying that a deciduous plant has leaves ! and should be allocating to them as well @@ -85,9 +90,6 @@ module FatesConstantsMod integer, parameter, public :: ican_ustory = 2 ! nominal index for diagnostics that refer to understory layers ! (all layers that are not the top canopy layer) - ! Bareground label for no competition mode - integer, parameter, public :: nocomp_bareground = 0 - ! Flags specifying how phosphorous uptake and turnover interacts ! with the host model. integer, public, parameter :: prescribed_p_uptake = 1 @@ -143,6 +145,10 @@ module FatesConstantsMod integer, parameter, public :: lmrmodel_ryan_1991 = 1 integer, parameter, public :: lmrmodel_atkin_etal_2017 = 2 + ! integer labels for specifying carbon starvation model + integer, parameter, public :: cstarvation_model_lin = 1 ! Linear scaling + integer, parameter, public :: cstarvation_model_exp = 2 ! Exponential scaling + ! Error Tolerances ! Allowable error in carbon allocations, should be applied to estimates @@ -167,6 +173,9 @@ module FatesConstantsMod ! of magnitude of buffer error (ie instead of 1e-15) real(fates_r8), parameter, public :: rsnbl_math_prec = 1.0e-12_fates_r8 + ! in nocomp simulations, what is the minimum PFT fraction for any given land use type? + real(fates_r8), parameter, public :: min_nocomp_pftfrac_perlanduse = 0.01_fates_r8 + ! This is the precision of 8byte reals (~1e-308) real(fates_r8), parameter, public :: tinyr8 = tiny(1.0_fates_r8) @@ -275,6 +284,10 @@ module FatesConstantsMod real(fates_r8), parameter, public :: J_per_kJ = 1000.0_fates_r8 ! Physical constants + + ! dewpoint calculation + real(fates_r8), parameter, public :: dewpoint_a = 17.62_fates_r8 + real(fates_r8), parameter, public :: dewpoint_b = 243.12_fates_r8 ![degrees C] ! universal gas constant [J/K/kmol] real(fates_r8), parameter, public :: rgas_J_K_kmol = 8314.4598_fates_r8 @@ -338,5 +351,10 @@ module FatesConstantsMod real(fates_r8), parameter, public :: lmr_r_2 = -0.0402_fates_r8 ! (umol CO2/m**2/s/degree C) - + ! some integers related to termination mortality + integer, parameter, public :: n_term_mort_types = 3 + integer, parameter, public :: i_term_mort_type_cstarv = 1 + integer, parameter, public :: i_term_mort_type_canlev = 2 + integer, parameter, public :: i_term_mort_type_numdens = 3 + end module FatesConstantsMod diff --git a/main/FatesGlobals.F90 b/main/FatesGlobals.F90 index ebc0f326ff..299fb5d5fb 100644 --- a/main/FatesGlobals.F90 +++ b/main/FatesGlobals.F90 @@ -5,6 +5,7 @@ module FatesGlobals ! immediately obvious home. use FatesConstantsMod , only : r8 => fates_r8 + use TwoStreamMLPEMod , only : TwoStreamLogInit implicit none private ! By default everything is private @@ -63,6 +64,8 @@ subroutine FatesGlobalsInit(log_unit,global_verbose) fates_log_ = log_unit fates_global_verbose_ = global_verbose + call TwoStreamLogInit(log_unit) + end subroutine FatesGlobalsInit ! ===================================================================================== diff --git a/main/FatesHistoryInterfaceMod.F90 b/main/FatesHistoryInterfaceMod.F90 index c985b427f3..c5b48735f6 100644 --- a/main/FatesHistoryInterfaceMod.F90 +++ b/main/FatesHistoryInterfaceMod.F90 @@ -10,6 +10,11 @@ module FatesHistoryInterfaceMod 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 FatesGlobals , only : fates_log use FatesGlobals , only : endrun => fates_endrun use EDParamsMod , only : nclmax, maxpft @@ -25,8 +30,11 @@ module FatesHistoryInterfaceMod use EDtypesMod , only : AREA_INV use EDTypesMod , only : numWaterMem use EDTypesMod , only : num_vegtemp_mem - use EDTypesMod , only : site_massbal_type use PRTGenericMod , only : element_list + use 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 @@ -46,6 +54,9 @@ module FatesHistoryInterfaceMod use FatesInterfaceTypesMod , only : hlm_parteh_mode use EDParamsMod , only : ED_val_comp_excln 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 @@ -54,16 +65,31 @@ module FatesHistoryInterfaceMod use FatesInterfaceTypesMod , only : nlevcoage use FatesInterfaceTypesMod , only : hlm_use_nocomp use FatesInterfaceTypesMod , only : hlm_use_fixed_biogeog + use FatesRadiationMemMod , only : ivis,inir + 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 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 @@ -93,7 +119,22 @@ module FatesHistoryInterfaceMod 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 FatesLitterMod , only : nfsc + 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 @@ -169,6 +210,11 @@ module FatesHistoryInterfaceMod ! 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 @@ -200,7 +246,7 @@ module FatesHistoryInterfaceMod 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 @@ -218,11 +264,11 @@ module FatesHistoryInterfaceMod integer :: ih_storeptfrac_canopy_scpf integer :: ih_storeptfrac_understory_scpf - ! These are active if hlm_parteh_mode = prt_cnp_flex_allom_hyp integer :: ih_l2fr_si integer :: ih_l2fr_clscpf integer :: ih_recl2fr_canopy_pf integer :: ih_recl2fr_ustory_pf + integer :: ih_nh4uptake_scpf integer :: ih_no3uptake_scpf integer :: ih_puptake_scpf @@ -239,7 +285,7 @@ module FatesHistoryInterfaceMod integer :: ih_pdemand_scpf integer :: ih_nfix_si integer :: ih_nfix_scpf - + integer :: ih_trimming_si integer :: ih_area_plant_si integer :: ih_area_trees_si @@ -277,7 +323,10 @@ module FatesHistoryInterfaceMod ! 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 @@ -308,15 +357,19 @@ module FatesHistoryInterfaceMod integer :: ih_growth_resp_secondary_si integer :: ih_primaryland_fusion_error_si + integer :: ih_area_si_landuse 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_carbonflux_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 @@ -344,13 +397,12 @@ module FatesHistoryInterfaceMod integer :: ih_c_stomata_si integer :: ih_c_lblayer_si - integer :: ih_rad_error_si - + integer :: ih_vis_rad_err_si + integer :: ih_nir_rad_err_si integer :: ih_fire_c_to_atm_si - integer :: ih_cbal_err_fates_si - integer :: ih_err_fates_si + integer :: ih_err_fates_elem integer :: ih_npatches_si integer :: ih_npatches_sec_si @@ -382,7 +434,8 @@ module FatesHistoryInterfaceMod 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 @@ -447,7 +500,7 @@ module FatesHistoryInterfaceMod integer :: ih_m9_si_scpf integer :: ih_m10_si_scpf integer :: ih_m11_si_scpf - + integer :: ih_crownfiremort_si_scpf integer :: ih_cambialfiremort_si_scpf @@ -480,7 +533,7 @@ module FatesHistoryInterfaceMod 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 @@ -568,13 +621,16 @@ module FatesHistoryInterfaceMod integer :: ih_nindivs_si_pft integer :: ih_nindivs_sec_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_gpp_sec_si_pft integer :: ih_npp_si_pft @@ -621,7 +677,7 @@ module FatesHistoryInterfaceMod 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_h2osoi_si_scagpft ! hijacking the scagpft dimension instead of creating a new shsl dimension integer :: ih_sapflow_scpf integer :: ih_sapflow_si integer :: ih_iterh1_scpf @@ -678,26 +734,19 @@ module FatesHistoryInterfaceMod integer :: ih_parsha_z_si_cnlf integer :: ih_laisun_z_si_cnlf integer :: ih_laisha_z_si_cnlf - integer :: ih_fabd_sun_si_cnlf - integer :: ih_fabd_sha_si_cnlf - integer :: ih_fabi_sun_si_cnlf - integer :: ih_fabi_sha_si_cnlf integer :: ih_ts_net_uptake_si_cnlf - integer :: ih_crownarea_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_z_si_cnlfpft - integer :: ih_laisha_z_si_cnlfpft - integer :: ih_fabd_sun_si_cnlfpft - integer :: ih_fabd_sha_si_cnlfpft - integer :: ih_fabi_sun_si_cnlfpft - integer :: ih_fabi_sha_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 @@ -721,17 +770,13 @@ module FatesHistoryInterfaceMod ! crownarea damaged integer :: ih_crownarea_canopy_damage_si integer :: ih_crownarea_ustory_damage_si - + ! indices to (site x canopy layer) variables - integer :: ih_parsun_top_si_can - integer :: ih_parsha_top_si_can - integer :: ih_laisun_top_si_can - integer :: ih_laisha_top_si_can - integer :: ih_fabd_sun_top_si_can - integer :: ih_fabd_sha_top_si_can - integer :: ih_fabi_sun_top_si_can - integer :: ih_fabi_sha_top_si_can - integer :: ih_crownarea_si_can + 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_age_fuel @@ -779,10 +824,14 @@ module FatesHistoryInterfaceMod procedure :: assemble_history_output_types procedure :: update_history_dyn + procedure :: update_history_dyn1 + procedure :: update_history_dyn2 procedure :: update_history_hifrq + procedure :: update_history_hifrq1 + procedure :: update_history_hifrq2 procedure :: update_history_hydraulics procedure :: update_history_nutrflux - + ! 'get' methods used by external callers to access private read only data procedure :: num_history_vars @@ -815,7 +864,7 @@ module FatesHistoryInterfaceMod procedure :: levlanduse_index procedure :: levlulu_index procedure :: levlupft_index - + ! private work functions procedure, private :: define_history_vars procedure, private :: set_history_var @@ -846,7 +895,6 @@ module FatesHistoryInterfaceMod 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 @@ -854,12 +902,12 @@ module FatesHistoryInterfaceMod 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__ + __FILE__ ! The instance of the type @@ -973,7 +1021,7 @@ subroutine Init(this, num_threads, fates_bounds) 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, & @@ -1002,7 +1050,7 @@ subroutine Init(this, num_threads, fates_bounds) 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) + fates_bounds%elpft_begin, fates_bounds%elpft_end) dim_count = dim_count + 1 call this%set_levelcwd_index(dim_count) @@ -1012,7 +1060,7 @@ subroutine Init(this, num_threads, fates_bounds) 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) + fates_bounds%elage_begin, fates_bounds%elage_end) dim_count = dim_count + 1 call this%set_levagefuel_index(dim_count) @@ -1023,7 +1071,7 @@ subroutine Init(this, num_threads, fates_bounds) 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, & @@ -1105,7 +1153,7 @@ subroutine SetThreadBoundsEach(this, thread_index, thread_bounds) index = this%levcnlfpft_index() call this%dim_bounds(index)%SetThreadBounds(thread_index, & - thread_bounds%cnlfpft_begin, thread_bounds%cnlfpft_end) + thread_bounds%cnlfpft_begin, thread_bounds%cnlfpft_end) index = this%levcdpf_index() call this%dim_bounds(index)%SetThreadBounds(thread_index, & @@ -1118,22 +1166,22 @@ subroutine SetThreadBoundsEach(this, thread_index, thread_bounds) index = this%levcdam_index() call this%dim_bounds(index)%SetThreadBounds(thread_index, & thread_bounds%cdam_begin, thread_bounds%cdam_end) - + index = this%levscag_index() call this%dim_bounds(index)%SetThreadBounds(thread_index, & - thread_bounds%sizeage_class_begin, thread_bounds%sizeage_class_end) + thread_bounds%sizeage_class_begin, thread_bounds%sizeage_class_end) index = this%levscagpft_index() call this%dim_bounds(index)%SetThreadBounds(thread_index, & - thread_bounds%sizeagepft_class_begin, thread_bounds%sizeagepft_class_end) + thread_bounds%sizeagepft_class_begin, thread_bounds%sizeagepft_class_end) index = this%levagepft_index() call this%dim_bounds(index)%SetThreadBounds(thread_index, & - thread_bounds%agepft_class_begin, thread_bounds%agepft_class_end) + thread_bounds%agepft_class_begin, thread_bounds%agepft_class_end) index = this%levheight_index() call this%dim_bounds(index)%SetThreadBounds(thread_index, & - thread_bounds%height_begin, thread_bounds%height_end) + thread_bounds%height_begin, thread_bounds%height_end) index = this%levelem_index() call this%dim_bounds(index)%SetThreadBounds(thread_index, & @@ -1171,24 +1219,15 @@ subroutine SetThreadBoundsEach(this, thread_index, thread_bounds) call this%dim_bounds(index)%SetThreadBounds(thread_index, & thread_bounds%lupft_begin, thread_bounds%lupft_end) + end subroutine SetThreadBoundsEach ! =================================================================================== subroutine assemble_history_output_types(this) - 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 - - implicit none + + + implicit none class(fates_history_interface_type), intent(inout) :: this @@ -1240,7 +1279,7 @@ subroutine assemble_history_output_types(this) 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()) @@ -1320,478 +1359,510 @@ subroutine set_dim_indices(this, dk_name, idim, dim_index) 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 + end subroutine set_dim_indices -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_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_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) + 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 + 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 + ! ====================================================================================== + 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) + integer function levscagpft_index(this) implicit none class(fates_history_interface_type), intent(in) :: this levscagpft_index = this%levscagpft_index_ - end function 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 + ! ====================================================================================== + 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) + integer function levagepft_index(this) implicit none class(fates_history_interface_type), intent(in) :: this levagepft_index = this%levagepft_index_ - end function 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 + ! ====================================================================================== + 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) + integer function levheight_index(this) implicit none class(fates_history_interface_type), intent(in) :: this levheight_index = this%levheight_index_ - end function 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 + 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) + 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 + 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) + integer function levelpft_index(this) implicit none class(fates_history_interface_type), intent(in) :: this levelpft_index = this%levelpft_index_ - end function 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 + 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) + 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 + 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) + 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_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 + 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 + ! ====================================================================================== - 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)%flush(nc, this%dim_bounds, this%dim_kinds) - end if - end do + 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 -end subroutine flush_hvars + 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 ! ===================================================================================== @@ -1817,10 +1888,10 @@ subroutine set_history_var(this, vname, units, long, use_default, avgflag, vtype 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 + ! 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 @@ -1884,8 +1955,7 @@ subroutine init_dim_kinds_maps(this) 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 - + implicit none ! Arguments @@ -1957,7 +2027,7 @@ subroutine init_dim_kinds_maps(this) ! 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) @@ -2014,10 +2084,21 @@ subroutine init_dim_kinds_maps(this) end subroutine init_dim_kinds_maps ! ======================================================================= - + subroutine update_history_nutrflux(this,csite) - ! Update history diagnostics for nutrient dynamics variables. + ! 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 @@ -2031,176 +2112,197 @@ subroutine update_history_nutrflux(this,csite) type(fates_patch_type), pointer :: cpatch type(fates_cohort_type), pointer :: ccohort - integer :: iclscpf ! layer x size x pft class index - integer :: iscpf ! Size x pft class index - integer :: io_si ! site's global index in the history vector - integer :: el ! element loop index - integer :: ft - real(r8):: uconv ! combined unit conversion factor - - ! We use gpp and fineroot C for weighted averages - real(r8) :: gpp_si - real(r8) :: fnrtc_si - real(r8) :: fnrt_c - - associate( & - !hio_l2fr_clscpf => this%hvars(ih_l2fr_clscpf)%r82d, & - hio_l2fr_si => this%hvars(ih_l2fr_si)%r81d, & - hio_recl2fr_canopy_pf => this%hvars(ih_recl2fr_canopy_pf)%r82d, & - hio_recl2fr_ustory_pf => this%hvars(ih_recl2fr_ustory_pf)%r82d ) + 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 - gpp_si = 0._r8 - fnrtc_si = 0._r8 + ! zero nutrient fluxes + call this%zero_site_hvars(csite,upfreq_in=group_nflx_simple) + + cpatch => csite%youngest_patch + do while(associated(cpatch)) - ! history site index - io_si = csite%h_gid - - cpatch => csite%youngest_patch - do while(associated(cpatch)) + ccohort => cpatch%shortest + do while(associated(ccohort)) - ccohort => cpatch%shortest - do while(associated(ccohort)) + ! If this is a new cohort, do not make diagnostics + if(ccohort%isnew) then + ccohort => ccohort%taller + cycle + end if - ! If this is a new cohort, do not make diagnostics - if(ccohort%isnew) then - ccohort => ccohort%taller - cycle - end if - - ! size class index - iscpf = ccohort%size_by_pft_class + ! unit conversion factor to get x/plant/day -> x/m2/sec + uconv = ccohort%n * ha_per_m2 * days_per_sec - ! layer by size by pft index - iclscpf = get_layersizetype_class_index(ccohort%canopy_layer,ccohort%dbh,ccohort%pft) + fnrt_c = ccohort%prt%GetState(fnrt_organ, carbon12_element) - ! 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. + do el = 1, num_elements + select case (element_list(el)) + case (carbon12_element) - fnrt_c = ccohort%prt%GetState(fnrt_organ, carbon12_element) - !hio_l2fr_clscpf(io_si,iclscpf) = & - ! hio_l2fr_clscpf(io_si,iclscpf) + ccohort%n*fnrt_c*ccohort%l2fr + ! Excess carbon respired + this%hvars(ih_excess_resp_si)%r81d(io_si) = & + this%hvars(ih_excess_resp_si)%r81d(io_si) + & + ccohort%resp_excess*uconv - hio_l2fr_si(io_si) = hio_l2fr_si(io_si) + ccohort%n*fnrt_c*ccohort%l2fr - - ! These are used for normalizing weighted averages - gpp_si = gpp_si + ccohort%n*ccohort%gpp_acc_hold - fnrtc_si = fnrtc_si + ccohort%n*fnrt_c - - ! Loop over the different elements. - do el = 1, num_elements + case (nitrogen_element) - select case (element_list(el)) - case (carbon12_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 - ! Excess carbon respired - this%hvars(ih_excess_resp_si)%r81d(io_si) = & - this%hvars(ih_excess_resp_si)%r81d(io_si) + & - ccohort%resp_excess*uconv + fates_hist%hvars(ih_no3uptake_si)%r81d(io_si) = & + fates_hist%hvars(ih_no3uptake_si)%r81d(io_si) + & + ccohort%daily_no3_uptake*uconv - case (nitrogen_element) + ! 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 - ! 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 + ! Efflux/exudation + this%hvars(ih_nefflux_si)%r81d(io_si) = & + this%hvars(ih_nefflux_si)%r81d(io_si) + & + ccohort%daily_n_efflux*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 + ! Demand + this%hvars(ih_ndemand_si)%r81d(io_si) = & + this%hvars(ih_ndemand_si)%r81d(io_si) + & + ccohort%daily_n_demand*uconv - fates_hist%hvars(ih_nh4uptake_si)%r81d(io_si) = & - fates_hist%hvars(ih_nh4uptake_si)%r81d(io_si) + & - ccohort%daily_nh4_uptake*uconv + case (phosphorus_element) - fates_hist%hvars(ih_no3uptake_si)%r81d(io_si) = & - fates_hist%hvars(ih_no3uptake_si)%r81d(io_si) + & - ccohort%daily_no3_uptake*uconv + ! 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 - ! 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 + ! Efflux + this%hvars(ih_pefflux_si)%r81d(io_si) = & + this%hvars(ih_pefflux_si)%r81d(io_si) + & + ccohort%daily_p_efflux*uconv - fates_hist%hvars(ih_nfix_scpf)%r82d(io_si,iscpf) = & - fates_hist%hvars(ih_nfix_scpf)%r82d(io_si,iscpf) + & - ccohort%sym_nfix_daily*uconv + ! Demand + this%hvars(ih_pdemand_si)%r81d(io_si) = & + this%hvars(ih_pdemand_si)%r81d(io_si) + & + ccohort%daily_p_demand*uconv + + end select + end do - ! 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 + ccohort => ccohort%taller + end do - this%hvars(ih_nefflux_si)%r81d(io_si) = & - this%hvars(ih_nefflux_si)%r81d(io_si) + & - ccohort%daily_n_efflux*uconv + cpatch => cpatch%older + end do - ! Demand - this%hvars(ih_ndemand_scpf)%r82d(io_si,iscpf) = & - this%hvars(ih_ndemand_scpf)%r82d(io_si,iscpf) + & - ccohort%daily_n_demand*uconv + end if if_dynam1 - this%hvars(ih_ndemand_si)%r81d(io_si) = & - this%hvars(ih_ndemand_si)%r81d(io_si) + & - ccohort%daily_n_demand*uconv + ! Process multiplexed variables + ! --------------------------------------------------------------------------------------------- + + if_dynam2: if(hlm_hist_level_dynam>1) then - case (phosphorus_element) + ! history site index + io_si = csite%h_gid - 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 + call this%zero_site_hvars(csite,upfreq_in=group_nflx_complx) + + cpatch => csite%youngest_patch + do while(associated(cpatch)) - fates_hist%hvars(ih_puptake_si)%r81d(io_si) = & - fates_hist%hvars(ih_puptake_si)%r81d(io_si) + & - ccohort%daily_p_gain*uconv + ccohort => cpatch%shortest + do while(associated(ccohort)) - this%hvars(ih_pefflux_scpf)%r82d(io_si,iscpf) = & - this%hvars(ih_pefflux_scpf)%r82d(io_si,iscpf) + & - ccohort%daily_p_efflux*uconv + ! If this is a new cohort, do not make diagnostics + if(ccohort%isnew) then + ccohort => ccohort%taller + cycle + end if - this%hvars(ih_pefflux_si)%r81d(io_si) = & - this%hvars(ih_pefflux_si)%r81d(io_si) + & - ccohort%daily_p_efflux*uconv + ! size class index + iscpf = ccohort%size_by_pft_class - this%hvars(ih_pdemand_scpf)%r82d(io_si,iscpf) = & - this%hvars(ih_pdemand_scpf)%r82d(io_si,iscpf) + & - ccohort%daily_p_demand*uconv + ! layer by size by pft index + iclscpf = get_layersizetype_class_index(ccohort%canopy_layer,ccohort%dbh,ccohort%pft) - this%hvars(ih_pdemand_si)%r81d(io_si) = & - ccohort%daily_p_demand*uconv - end select - end do + ! unit conversion factor to get x/plant/day -> x/m2/sec + uconv = ccohort%n * ha_per_m2 * days_per_sec - ccohort => ccohort%taller - end do + ! Loop over the different elements. + do el = 1, num_elements - cpatch => cpatch%older - end do - - ! Normalize the layer x size x pft arrays - !do iclscpf = 1,nclmax*numpft*nlevsclass - !if(fnrtc_clscpf(iclscpf)>nearzero) then - ! hio_l2fr_clscpf(io_si,iclscpf) = hio_l2fr_clscpf(io_si,iclscpf) / fnrtc_clscpf(iclscpf) - !else - ! hio_l2fr_clscpf(io_si,iclscpf) = hlm_hio_ignore_val - !end if - !end do - - do ft = 1,numpft - hio_recl2fr_canopy_pf(io_si,ft) = csite%rec_l2fr(ft,1) - hio_recl2fr_ustory_pf(io_si,ft) = csite%rec_l2fr(ft,2) - end do - - if(fnrtc_si>nearzero)then - hio_l2fr_si(io_si) = hio_l2fr_si(io_si)/fnrtc_si - else - hio_l2fr_si(io_si) = hlm_hio_ignore_val - end if - + select case (element_list(el)) - - end associate + case (nitrogen_element) + + ! Mineralized uptake of NH4, NO3 + fates_hist%hvars(ih_nh4uptake_scpf)%r82d(io_si,iscpf) = & + fates_hist%hvars(ih_nh4uptake_scpf)%r82d(io_si,iscpf) + & + ccohort%daily_nh4_uptake*uconv + + fates_hist%hvars(ih_no3uptake_scpf)%r82d(io_si,iscpf) = & + fates_hist%hvars(ih_no3uptake_scpf)%r82d(io_si,iscpf) + & + ccohort%daily_no3_uptake*uconv + + ! 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 + + ! 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 + ! 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) + + ! 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 + + ! Efflux + this%hvars(ih_pefflux_scpf)%r82d(io_si,iscpf) = & + this%hvars(ih_pefflux_scpf)%r82d(io_si,iscpf) + & + ccohort%daily_p_efflux*uconv + + ! Demand + this%hvars(ih_pdemand_scpf)%r82d(io_si,iscpf) = & + this%hvars(ih_pdemand_scpf)%r82d(io_si,iscpf) + & + ccohort%daily_p_demand*uconv + + end select + end do + + ccohort => ccohort%taller + end do + + cpatch => cpatch%older + end do + + end if if_dynam2 + return end subroutine update_history_nutrflux @@ -2211,29 +2313,10 @@ 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 ! --------------------------------------------------------------------------------- - - use FatesLitterMod , only : nfsc - use FatesLitterMod , only : ncwd - use FatesConstantsMod , only : ican_upper - use FatesConstantsMod , only : ican_ustory - use FatesConstantsMod , only : n_landuse_cats - 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_age_class_index - use FatesSizeAgeTypeIndicesMod, only : get_height_index - use FatesSizeAgeTypeIndicesMod, only : sizetype_class_index - use FatesSizeAgeTypeIndicesMod, only : get_cdamagesize_class_index - use FatesSizeAgeTypeIndicesMod, only : get_cdamagesizepft_class_index - use FatesSizeAgeTypeIndicesMod, only : coagetype_class_index - - use EDParamsMod , only : nlevleaf - use EDParamsMod , only : ED_val_history_height_bin_edges - use FatesInterfaceTypesMod , only : nlevdamage - ! Arguments class(fates_history_interface_type) :: this integer , intent(in) :: nc ! clump index @@ -2241,2257 +2324,2845 @@ subroutine update_history_dyn(this,nc,nsites,sites,bc_in) type(ed_site_type) , intent(inout), target :: sites(nsites) type(bc_in_type) , intent(in) :: bc_in(nsites) ! Locals - type(litter_type), pointer :: litt_c ! Pointer to the carbon12 litter pool - type(litter_type), pointer :: litt ! Generic pointer to any litter pool - type(site_fluxdiags_type), pointer :: flux_diags - type(site_fluxdiags_type), pointer :: flux_diags_c - type(site_massbal_type), pointer :: site_mass - integer :: s ! The local site index - integer :: io_si ! The site index of the IO array - integer :: ilyr ! Soil index for nlevsoil - integer :: ipa, ipa2 ! The local "I"ndex of "PA"tches - 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 - integer :: cwd - integer :: elcwd, elpft ! 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_cwd,i_fuel ! iterators for cwd and fuel dims - integer :: iscag ! size-class x age index - integer :: iscagpft ! size-class x age x pft index - integer :: iagepft ! age x pft index - integer :: i_agefuel ! age x fuel size class index - integer :: ican, ileaf, cnlf_indx ! iterators for leaf and canopy level - integer :: icdpf, icdsc, icdam, cdpf, cdsc ! iterators for the crown damage level - integer :: height_bin_max, height_bin_min ! which height bin a given cohort's canopy is in - integer :: i_heightbin ! iterator for height bins - integer :: el ! Loop index for elements - integer :: model_day_int ! Integer model day since simulation start - integer :: ageclass_since_anthrodist ! what is the equivalent age class for - ! time-since-anthropogenic-disturbance of secondary forest + ! If we don't have dynamics turned on, we just abort these diagnostics - real(r8) :: store_max ! The target nutrient mass for storage element of interest [kg] - real(r8) :: n_perm2 ! individuals per m2 for the whole column - real(r8) :: dbh ! diameter ("at breast height") - real(r8) :: coage ! cohort age - real(r8) :: npp_partition_error ! a check that the NPP partitions sum to carbon allocation - 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 - - real(r8) :: gpp_cached ! variable used to cache gpp value in previous time step; for C13 discrimination - - ! The following are all carbon states, turnover and net allocation flux variables - ! the organs of relevance should be self explanatory - 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 - real(r8) :: store_m_turnover - real(r8) :: leaf_m_turnover - real(r8) :: fnrt_m_turnover - real(r8) :: struct_m_turnover - real(r8) :: sapw_m_net_alloc - real(r8) :: store_m_net_alloc - real(r8) :: leaf_m_net_alloc - real(r8) :: fnrt_m_net_alloc - real(r8) :: struct_m_net_alloc - real(r8) :: repro_m_net_alloc - real(r8) :: area_frac - real(r8) :: crown_depth - - 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) + ! 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. - integer :: return_code - integer :: i_dist, j_dist - - type(fates_patch_type),pointer :: cpatch - type(fates_cohort_type),pointer :: ccohort + if (hlm_use_ed_st3.eq.itrue) return - real(r8), parameter :: reallytalltrees = 1000. ! some large number (m) + if(hlm_hist_level_dynam>0) then + call update_history_dyn1(this,nc,nsites,sites,bc_in) + if(hlm_hist_level_dynam>1) then + call update_history_dyn2(this,nc,nsites,sites,bc_in) + end if + end if + return + end subroutine update_history_dyn - integer :: tmp + ! ========================================================================= - associate( hio_npatches_si => this%hvars(ih_npatches_si)%r81d, & - hio_npatches_sec_si => this%hvars(ih_npatches_sec_si)%r81d, & - hio_ncohorts_si => this%hvars(ih_ncohorts_si)%r81d, & - hio_ncohorts_sec_si => this%hvars(ih_ncohorts_sec_si)%r81d, & - hio_trimming_si => this%hvars(ih_trimming_si)%r81d, & - hio_area_plant_si => this%hvars(ih_area_plant_si)%r81d, & - hio_area_trees_si => this%hvars(ih_area_trees_si)%r81d, & - hio_fates_fraction_si => this%hvars(ih_fates_fraction_si)%r81d, & - hio_ba_weighted_height_si => this%hvars(ih_ba_weighted_height_si)%r81d, & - hio_ca_weighted_height_si => this%hvars(ih_ca_weighted_height_si)%r81d, & - hio_canopy_spread_si => this%hvars(ih_canopy_spread_si)%r81d, & - hio_biomass_si_pft => this%hvars(ih_biomass_si_pft)%r82d, & - hio_biomass_sec_si_pft => this%hvars(ih_biomass_sec_si_pft)%r82d, & - hio_leafbiomass_si_pft => this%hvars(ih_leafbiomass_si_pft)%r82d, & - hio_storebiomass_si_pft => this%hvars(ih_storebiomass_si_pft)%r82d, & - hio_nindivs_si_pft => this%hvars(ih_nindivs_si_pft)%r82d, & - hio_nindivs_sec_si_pft => this%hvars(ih_nindivs_sec_si_pft)%r82d, & - hio_recruitment_si_pft => this%hvars(ih_recruitment_si_pft)%r82d, & - hio_seeds_out_gc_si_pft => this%hvars(ih_seeds_out_gc_si_pft)%r82d, & - hio_seeds_in_gc_si_pft => this%hvars(ih_seeds_in_gc_si_pft)%r82d, & - hio_mortality_si_pft => this%hvars(ih_mortality_si_pft)%r82d, & - hio_mortality_carbonflux_si_pft => this%hvars(ih_mortality_carbonflux_si_pft)%r82d, & - hio_cstarvmortality_carbonflux_si_pft => this%hvars(ih_cstarvmortality_carbonflux_si_pft)%r82d, & - hio_hydraulicmortality_carbonflux_si_pft => this%hvars(ih_hydraulicmortality_carbonflux_si_pft)%r82d, & - hio_firemortality_carbonflux_si_pft => this%hvars(ih_firemortality_carbonflux_si_pft)%r82d, & - hio_crownarea_si_pft => this%hvars(ih_crownarea_si_pft)%r82d, & - hio_canopycrownarea_si_pft => this%hvars(ih_canopycrownarea_si_pft)%r82d, & - hio_gpp_si_pft => this%hvars(ih_gpp_si_pft)%r82d, & - hio_gpp_sec_si_pft => this%hvars(ih_gpp_sec_si_pft)%r82d, & - hio_npp_si_pft => this%hvars(ih_npp_si_pft)%r82d, & - hio_npp_sec_si_pft => this%hvars(ih_npp_sec_si_pft)%r82d, & - hio_nesterov_fire_danger_si => this%hvars(ih_nesterov_fire_danger_si)%r81d, & - hio_fire_nignitions_si => this%hvars(ih_fire_nignitions_si)%r81d, & - hio_fire_fdi_si => this%hvars(ih_fire_fdi_si)%r81d, & - hio_spitfire_ros_si => this%hvars(ih_spitfire_ros_si)%r81d, & - hio_tfc_ros_si => this%hvars(ih_tfc_ros_si)%r81d, & - hio_effect_wspeed_si => this%hvars(ih_effect_wspeed_si)%r81d, & - hio_fire_intensity_si => this%hvars(ih_fire_intensity_si)%r81d, & - hio_fire_intensity_area_product_si => this%hvars(ih_fire_intensity_area_product_si)%r81d, & - hio_fire_area_si => this%hvars(ih_fire_area_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_sav_si => this%hvars(ih_fire_fuel_sav_si)%r81d, & - hio_fire_fuel_mef_si => this%hvars(ih_fire_fuel_mef_si)%r81d, & - hio_sum_fuel_si => this%hvars(ih_sum_fuel_si)%r81d, & - hio_fragmentation_scaler_sl => this%hvars(ih_fragmentation_scaler_sl)%r82d, & - hio_litter_in_si => this%hvars(ih_litter_in_si)%r81d, & - hio_litter_out_si => this%hvars(ih_litter_out_si)%r81d, & - hio_seed_bank_si => this%hvars(ih_seed_bank_si)%r81d, & - hio_ungerm_seed_bank_si => this%hvars(ih_ungerm_seed_bank_si)%r81d, & - hio_seedling_pool_si => this%hvars(ih_seedling_pool_si)%r81d, & - hio_seeds_in_si => this%hvars(ih_seeds_in_si)%r81d, & - hio_seeds_in_local_si => this%hvars(ih_seeds_in_local_si)%r81d, & - hio_litter_in_elem => this%hvars(ih_litter_in_elem)%r82d, & - hio_litter_out_elem => this%hvars(ih_litter_out_elem)%r82d, & - hio_seed_bank_elem => this%hvars(ih_seed_bank_elem)%r82d, & - hio_seeds_in_local_elem => this%hvars(ih_seeds_in_local_elem)%r82d, & - hio_seed_in_extern_elem => this%hvars(ih_seeds_in_extern_elem)%r82d, & - hio_seed_decay_elem => this%hvars(ih_seed_decay_elem)%r82d, & - hio_seed_germ_elem => this%hvars(ih_seed_germ_elem)%r82d, & - hio_bdead_si => this%hvars(ih_bdead_si)%r81d, & - hio_balive_si => this%hvars(ih_balive_si)%r81d, & - hio_agb_si => this%hvars(ih_agb_si)%r81d, & - hio_canopy_biomass_si => this%hvars(ih_canopy_biomass_si)%r81d, & - hio_understory_biomass_si => this%hvars(ih_understory_biomass_si)%r81d, & - hio_primaryland_fusion_error_si => this%hvars(ih_primaryland_fusion_error_si)%r81d, & - hio_disturbance_rate_si_lulu => this%hvars(ih_disturbance_rate_si_lulu)%r82d, & - hio_fire_disturbance_rate_si => this%hvars(ih_fire_disturbance_rate_si)%r81d, & - hio_logging_disturbance_rate_si => this%hvars(ih_logging_disturbance_rate_si)%r81d, & - hio_fall_disturbance_rate_si => this%hvars(ih_fall_disturbance_rate_si)%r81d, & - hio_harvest_carbonflux_si => this%hvars(ih_harvest_carbonflux_si)%r81d, & - hio_harvest_debt_si => this%hvars(ih_harvest_debt_si)%r81d, & - hio_harvest_debt_sec_si => this%hvars(ih_harvest_debt_sec_si)%r81d, & - hio_gpp_si_scpf => this%hvars(ih_gpp_si_scpf)%r82d, & - hio_npp_totl_si_scpf => this%hvars(ih_npp_totl_si_scpf)%r82d, & - hio_npp_leaf_si_scpf => this%hvars(ih_npp_leaf_si_scpf)%r82d, & - hio_npp_seed_si_scpf => this%hvars(ih_npp_seed_si_scpf)%r82d, & - hio_npp_fnrt_si_scpf => this%hvars(ih_npp_fnrt_si_scpf)%r82d, & - hio_npp_bgsw_si_scpf => this%hvars(ih_npp_bgsw_si_scpf)%r82d, & - hio_npp_bgdw_si_scpf => this%hvars(ih_npp_bgdw_si_scpf)%r82d, & - hio_npp_agsw_si_scpf => this%hvars(ih_npp_agsw_si_scpf)%r82d, & - hio_npp_agdw_si_scpf => this%hvars(ih_npp_agdw_si_scpf)%r82d, & - hio_npp_stor_si_scpf => this%hvars(ih_npp_stor_si_scpf)%r82d, & - hio_npp_leaf_si => this%hvars(ih_npp_leaf_si)%r81d, & - hio_npp_seed_si => this%hvars(ih_npp_seed_si)%r81d, & - hio_npp_stem_si => this%hvars(ih_npp_stem_si)%r81d, & - hio_npp_froot_si => this%hvars(ih_npp_froot_si)%r81d, & - hio_npp_croot_si => this%hvars(ih_npp_croot_si)%r81d, & - hio_npp_stor_si => this%hvars(ih_npp_stor_si)%r81d, & - hio_bstor_canopy_si_scpf => this%hvars(ih_bstor_canopy_si_scpf)%r82d, & - hio_bstor_understory_si_scpf => this%hvars(ih_bstor_understory_si_scpf)%r82d, & - hio_bleaf_canopy_si_scpf => this%hvars(ih_bleaf_canopy_si_scpf)%r82d, & - hio_bleaf_understory_si_scpf => this%hvars(ih_bleaf_understory_si_scpf)%r82d, & - hio_lai_canopy_si_scpf => this%hvars(ih_lai_canopy_si_scpf)%r82d, & - hio_lai_understory_si_scpf => this%hvars(ih_lai_understory_si_scpf)%r82d, & - hio_mortality_canopy_si_scpf => this%hvars(ih_mortality_canopy_si_scpf)%r82d, & - hio_mortality_canopy_secondary_si_scls => this%hvars(ih_mortality_canopy_secondary_si_scls)%r82d, & - hio_mortality_understory_si_scpf => this%hvars(ih_mortality_understory_si_scpf)%r82d, & - hio_m3_mortality_canopy_si_scpf => this%hvars(ih_m3_mortality_canopy_si_scpf)%r82d, & - hio_m3_mortality_understory_si_scpf => this%hvars(ih_m3_mortality_understory_si_scpf)%r82d, & - hio_m3_mortality_canopy_si_scls => this%hvars(ih_m3_mortality_canopy_si_scls)%r82d, & - hio_m3_mortality_understory_si_scls => this%hvars(ih_m3_mortality_understory_si_scls)%r82d, & - hio_canopy_mortality_crownarea_si => this%hvars(ih_canopy_mortality_crownarea_si)%r81d, & - hio_understory_mortality_crownarea_si => this%hvars(ih_understory_mortality_crownarea_si)%r81d, & - hio_nplant_canopy_si_scpf => this%hvars(ih_nplant_canopy_si_scpf)%r82d, & - hio_nplant_understory_si_scpf => this%hvars(ih_nplant_understory_si_scpf)%r82d, & - hio_ddbh_canopy_si_scpf => this%hvars(ih_ddbh_canopy_si_scpf)%r82d, & - hio_ddbh_understory_si_scpf => this%hvars(ih_ddbh_understory_si_scpf)%r82d, & - hio_ddbh_canopy_si_scls => this%hvars(ih_ddbh_canopy_si_scls)%r82d, & - hio_ddbh_understory_si_scls => this%hvars(ih_ddbh_understory_si_scls)%r82d, & - hio_gpp_canopy_si_scpf => this%hvars(ih_gpp_canopy_si_scpf)%r82d, & - hio_gpp_understory_si_scpf => this%hvars(ih_gpp_understory_si_scpf)%r82d, & - hio_ar_canopy_si_scpf => this%hvars(ih_ar_canopy_si_scpf)%r82d, & - hio_ar_understory_si_scpf => this%hvars(ih_ar_understory_si_scpf)%r82d, & - hio_ddbh_si_scpf => this%hvars(ih_ddbh_si_scpf)%r82d, & - hio_growthflux_si_scpf => this%hvars(ih_growthflux_si_scpf)%r82d, & - hio_growthflux_fusion_si_scpf => this%hvars(ih_growthflux_fusion_si_scpf)%r82d, & - hio_ba_si_scpf => this%hvars(ih_ba_si_scpf)%r82d, & - hio_agb_si_scpf => this%hvars(ih_agb_si_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_m1_si_scpf => this%hvars(ih_m1_si_scpf)%r82d, & - hio_m2_si_scpf => this%hvars(ih_m2_si_scpf)%r82d, & - hio_m3_si_scpf => this%hvars(ih_m3_si_scpf)%r82d, & - hio_m4_si_scpf => this%hvars(ih_m4_si_scpf)%r82d, & - hio_m5_si_scpf => this%hvars(ih_m5_si_scpf)%r82d, & - hio_m6_si_scpf => this%hvars(ih_m6_si_scpf)%r82d, & - hio_m7_si_scpf => this%hvars(ih_m7_si_scpf)%r82d, & - hio_m8_si_scpf => this%hvars(ih_m8_si_scpf)%r82d, & - hio_m9_si_scpf => this%hvars(ih_m9_si_scpf)%r82d, & - hio_m10_si_scpf => this%hvars(ih_m10_si_scpf)%r82d, & - hio_m10_si_capf => this%hvars(ih_m10_si_capf)%r82d, & - - hio_crownfiremort_si_scpf => this%hvars(ih_crownfiremort_si_scpf)%r82d, & - hio_cambialfiremort_si_scpf => this%hvars(ih_cambialfiremort_si_scpf)%r82d, & - - hio_abg_mortality_cflux_si_scpf => this%hvars(ih_abg_mortality_cflux_si_scpf)%r82d, & - hio_abg_productivity_cflux_si_scpf => this%hvars(ih_abg_productivity_cflux_si_scpf)%r82d, & - - hio_fire_c_to_atm_si => this%hvars(ih_fire_c_to_atm_si)%r81d, & - hio_burn_flux_elem => this%hvars(ih_burn_flux_elem)%r82d, & - - hio_m1_si_scls => this%hvars(ih_m1_si_scls)%r82d, & - hio_m2_si_scls => this%hvars(ih_m2_si_scls)%r82d, & - hio_m3_si_scls => this%hvars(ih_m3_si_scls)%r82d, & - hio_m4_si_scls => this%hvars(ih_m4_si_scls)%r82d, & - hio_m5_si_scls => this%hvars(ih_m5_si_scls)%r82d, & - hio_m6_si_scls => this%hvars(ih_m6_si_scls)%r82d, & - hio_m7_si_scls => this%hvars(ih_m7_si_scls)%r82d, & - hio_m8_si_scls => this%hvars(ih_m8_si_scls)%r82d, & - hio_m9_si_scls => this%hvars(ih_m9_si_scls)%r82d, & - hio_m10_si_scls => this%hvars(ih_m10_si_scls)%r82d, & - hio_m10_si_cacls => this%hvars(ih_m10_si_cacls)%r82d, & - - hio_m1_sec_si_scls => this%hvars(ih_m1_sec_si_scls)%r82d, & - hio_m2_sec_si_scls => this%hvars(ih_m2_sec_si_scls)%r82d, & - hio_m3_sec_si_scls => this%hvars(ih_m3_sec_si_scls)%r82d, & - hio_m7_sec_si_scls => this%hvars(ih_m7_sec_si_scls)%r82d, & - hio_m8_sec_si_scls => this%hvars(ih_m8_sec_si_scls)%r82d, & - hio_m9_sec_si_scls => this%hvars(ih_m9_sec_si_scls)%r82d, & - hio_m10_sec_si_scls => this%hvars(ih_m10_sec_si_scls)%r82d, & - - hio_c13disc_si_scpf => this%hvars(ih_c13disc_si_scpf)%r82d, & - - hio_cwd_elcwd => this%hvars(ih_cwd_elcwd)%r82d, & - 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_demotion_carbonflux_si => this%hvars(ih_demotion_carbonflux_si)%r81d, & - 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_area_canopy_si_scls => this%hvars(ih_crown_area_canopy_si_scls)%r82d, & - hio_crown_area_understory_si_scls => this%hvars(ih_crown_area_understory_si_scls)%r82d, & - hio_promotion_carbonflux_si => this%hvars(ih_promotion_carbonflux_si)%r81d, & - hio_canopy_mortality_carbonflux_si => this%hvars(ih_canopy_mortality_carbonflux_si)%r81d, & - hio_understory_mortality_carbonflux_si => this%hvars(ih_understory_mortality_carbonflux_si)%r81d, & - 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_nplant_si_scagpft => this%hvars(ih_nplant_si_scagpft)%r82d, & - hio_npp_si_agepft => this%hvars(ih_npp_si_agepft)%r82d, & - hio_biomass_si_agepft => this%hvars(ih_biomass_si_agepft)%r82d, & - hio_scorch_height_si_agepft => this%hvars(ih_scorch_height_si_agepft)%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_area_si_age => this%hvars(ih_area_si_age)%r82d, & - hio_area_si_landuse => this%hvars(ih_area_si_landuse)%r82d, & - hio_lai_si_age => this%hvars(ih_lai_si_age)%r82d, & - hio_lai_secondary_si => this%hvars(ih_lai_secondary_si)%r81d, & - hio_canopy_area_si_age => this%hvars(ih_canopy_area_si_age)%r82d, & - hio_ncl_si_age => this%hvars(ih_ncl_si_age)%r82d, & - hio_npatches_si_age => this%hvars(ih_npatches_si_age)%r82d, & - hio_zstar_si_age => this%hvars(ih_zstar_si_age)%r82d, & - hio_biomass_si_age => this%hvars(ih_biomass_si_age)%r82d, & - hio_fraction_secondary_forest_si => this%hvars(ih_fraction_secondary_forest_si)%r81d, & - hio_biomass_secondary_forest_si => this%hvars(ih_biomass_secondary_forest_si)%r81d, & - hio_woodproduct_si => this%hvars(ih_woodproduct_si)%r81d, & - hio_agesince_anthrodist_si_age => this%hvars(ih_agesince_anthrodist_si_age)%r82d, & - hio_secondarylands_area_si_age => this%hvars(ih_secondarylands_area_si_age)%r82d, & - hio_area_burnt_si_age => this%hvars(ih_area_burnt_si_age)%r82d, & - ! hio_fire_rate_of_spread_front_si_age => this%hvars(ih_fire_rate_of_spread_front_si_age)%r82d, & - hio_fire_intensity_si_age => this%hvars(ih_fire_intensity_si_age)%r82d, & - hio_fire_sum_fuel_si_age => this%hvars(ih_fire_sum_fuel_si_age)%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_fuel_amount_age_fuel => this%hvars(ih_fuel_amount_age_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_si_can => this%hvars(ih_crownarea_si_can)%r82d, & - hio_ddbh_canopy_si_scag => this%hvars(ih_ddbh_canopy_si_scag)%r82d, & - hio_ddbh_understory_si_scag => this%hvars(ih_ddbh_understory_si_scag)%r82d, & - hio_mortality_canopy_si_scag => this%hvars(ih_mortality_canopy_si_scag)%r82d, & - hio_mortality_understory_si_scag => this%hvars(ih_mortality_understory_si_scag)%r82d ) - - ! Split up the associate statement as the nag compiler has a limit on line continuation - associate( hio_gdd_si => this%hvars(ih_gdd_si)%r81d, & - hio_site_ncolddays_si => this%hvars(ih_site_ncolddays_si)%r81d, & - hio_site_nchilldays_si => this%hvars(ih_site_nchilldays_si)%r81d, & - hio_site_cstatus_si => this%hvars(ih_site_cstatus_si)%r81d, & - hio_cleafoff_si => this%hvars(ih_cleafoff_si)%r81d, & - hio_cleafon_si => this%hvars(ih_cleafon_si)%r81d, & - hio_site_dstatus_si_pft => this%hvars(ih_site_dstatus_si_pft)%r82d, & - hio_dleafoff_si_pft => this%hvars(ih_dleafoff_si_pft)%r82d, & - hio_dleafon_si_pft => this%hvars(ih_dleafon_si_pft)%r82d, & - hio_meanliqvol_si_pft => this%hvars(ih_meanliqvol_si_pft)%r82d, & - hio_meansmp_si_pft => this%hvars(ih_meansmp_si_pft)%r82d, & - hio_elong_factor_si_pft => this%hvars(ih_elong_factor_si_pft)%r82d, & - hio_tveg24 => this%hvars(ih_tveg24_si)%r81d, & - hio_tlongterm => this%hvars(ih_tlongterm_si)%r81d, & - hio_tgrowth => this%hvars(ih_tgrowth_si)%r81d, & - hio_cbal_err_fates_si => this%hvars(ih_cbal_err_fates_si)%r81d, & - hio_err_fates_si => this%hvars(ih_err_fates_si)%r82d, & - hio_nplant_si_scag => this%hvars(ih_nplant_si_scag)%r82d, & - hio_nplant_canopy_si_scag => this%hvars(ih_nplant_canopy_si_scag)%r82d, & - hio_nplant_understory_si_scag => this%hvars(ih_nplant_understory_si_scag)%r82d, & - hio_lai_si => this%hvars(ih_lai_si)%r81d ) - - ! If we don't have dynamics turned on, we just abort these diagnostics - if (hlm_use_ed_st3.eq.itrue) return - - model_day_int = nint(hlm_model_day) - - - - - ! --------------------------------------------------------------------------------- - ! Loop through the FATES scale hierarchy and fill the history IO arrays - ! --------------------------------------------------------------------------------- - - siteloop: do s = 1,nsites - - io_si = sites(s)%h_gid - - ! These are weighting factors - storen_canopy_scpf(:) = 0._r8 - storen_understory_scpf(:) = 0._r8 - storep_canopy_scpf(:) = 0._r8 - storep_understory_scpf(:) = 0._r8 - storec_canopy_scpf(:) = 0._r8 - storec_understory_scpf(:) = 0._r8 - - flux_diags_c => sites(s)%flux_diags(element_pos(carbon12_element)) - - ! set the fates fraction to one, since it is zero on non-fates columns, & - ! the average is the total gridcell fates fraction - hio_fates_fraction_si(io_si) = 1._r8 + subroutine update_history_dyn1(this,nc,nsites,sites,bc_in) - ! 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 - ! 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 - do el = 1, num_elements + ! 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) - ! Total model error [kg/day -> kg/s] (all elements) - hio_err_fates_si(io_si,el) = sites(s)%mass_balance(el)%err_fates / sec_per_day + type(fates_cohort_type), pointer :: ccohort + type(fates_patch_type), pointer :: cpatch + type(site_fluxdiags_type), pointer :: flux_diags_c ! Pointer to site level carbon fluxes + type(litter_type), pointer :: litt ! Generic pointer to any litter pool + + integer :: s ! site counter + integer :: ipa ! 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 + 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) :: n_perm2 ! abundance per m2 + real(r8) :: area_frac ! Fraction of area for this patch + + associate( hio_npatches_si => this%hvars(ih_npatches_si)%r81d, & + hio_npatches_sec_si => this%hvars(ih_npatches_sec_si)%r81d, & + hio_ncohorts_si => this%hvars(ih_ncohorts_si)%r81d, & + hio_ncohorts_sec_si => this%hvars(ih_ncohorts_sec_si)%r81d, & + hio_trimming_si => this%hvars(ih_trimming_si)%r81d, & + hio_area_plant_si => this%hvars(ih_area_plant_si)%r81d, & + hio_area_trees_si => this%hvars(ih_area_trees_si)%r81d, & + hio_fates_fraction_si => this%hvars(ih_fates_fraction_si)%r81d, & + hio_ba_weighted_height_si => this%hvars(ih_ba_weighted_height_si)%r81d, & + hio_ca_weighted_height_si => this%hvars(ih_ca_weighted_height_si)%r81d, & + hio_canopy_spread_si => this%hvars(ih_canopy_spread_si)%r81d, & + hio_nesterov_fire_danger_si => this%hvars(ih_nesterov_fire_danger_si)%r81d, & + hio_fire_nignitions_si => this%hvars(ih_fire_nignitions_si)%r81d, & + hio_fire_fdi_si => this%hvars(ih_fire_fdi_si)%r81d, & + hio_spitfire_ros_si => this%hvars(ih_spitfire_ros_si)%r81d, & + hio_tfc_ros_si => this%hvars(ih_tfc_ros_si)%r81d, & + hio_effect_wspeed_si => this%hvars(ih_effect_wspeed_si)%r81d, & + hio_fire_intensity_si => this%hvars(ih_fire_intensity_si)%r81d, & + hio_fire_intensity_area_product_si => this%hvars(ih_fire_intensity_area_product_si)%r81d, & + hio_fire_area_si => this%hvars(ih_fire_area_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_sav_si => this%hvars(ih_fire_fuel_sav_si)%r81d, & + hio_fire_fuel_mef_si => this%hvars(ih_fire_fuel_mef_si)%r81d, & + hio_sum_fuel_si => this%hvars(ih_sum_fuel_si)%r81d, & + hio_litter_in_si => this%hvars(ih_litter_in_si)%r81d, & + hio_litter_out_si => this%hvars(ih_litter_out_si)%r81d, & + hio_seed_bank_si => this%hvars(ih_seed_bank_si)%r81d, & + hio_ungerm_seed_bank_si => this%hvars(ih_ungerm_seed_bank_si)%r81d, & + hio_seedling_pool_si => this%hvars(ih_seedling_pool_si)%r81d, & + hio_seeds_in_si => this%hvars(ih_seeds_in_si)%r81d, & + hio_seeds_in_local_si => this%hvars(ih_seeds_in_local_si)%r81d, & + hio_bdead_si => this%hvars(ih_bdead_si)%r81d, & + hio_balive_si => this%hvars(ih_balive_si)%r81d, & + hio_agb_si => this%hvars(ih_agb_si)%r81d, & + hio_canopy_biomass_si => this%hvars(ih_canopy_biomass_si)%r81d, & + hio_ustory_biomass_si => this%hvars(ih_understory_biomass_si)%r81d, & + hio_primaryland_fusion_error_si => this%hvars(ih_primaryland_fusion_error_si)%r81d, & + hio_fire_disturbance_rate_si => this%hvars(ih_fire_disturbance_rate_si)%r81d, & + hio_logging_disturbance_rate_si => this%hvars(ih_logging_disturbance_rate_si)%r81d, & + hio_fall_disturbance_rate_si => this%hvars(ih_fall_disturbance_rate_si)%r81d, & + hio_harvest_debt_si => this%hvars(ih_harvest_debt_si)%r81d, & + hio_harvest_debt_sec_si => this%hvars(ih_harvest_debt_sec_si)%r81d, & + hio_npp_leaf_si => this%hvars(ih_npp_leaf_si)%r81d, & + hio_npp_seed_si => this%hvars(ih_npp_seed_si)%r81d, & + hio_npp_stem_si => this%hvars(ih_npp_stem_si)%r81d, & + hio_npp_froot_si => this%hvars(ih_npp_froot_si)%r81d, & + hio_npp_croot_si => this%hvars(ih_npp_croot_si)%r81d, & + hio_npp_stor_si => this%hvars(ih_npp_stor_si)%r81d, & + hio_canopy_mortality_crownarea_si => this%hvars(ih_canopy_mortality_crownarea_si)%r81d, & + hio_ustory_mortality_crownarea_si => this%hvars(ih_understory_mortality_crownarea_si)%r81d, & + hio_fire_c_to_atm_si => this%hvars(ih_fire_c_to_atm_si)%r81d, & + hio_demotion_carbonflux_si => this%hvars(ih_demotion_carbonflux_si)%r81d, & + hio_promotion_carbonflux_si => this%hvars(ih_promotion_carbonflux_si)%r81d, & + hio_canopy_mortality_carbonflux_si => this%hvars(ih_canopy_mortality_carbonflux_si)%r81d, & + hio_ustory_mortality_carbonflux_si => this%hvars(ih_understory_mortality_carbonflux_si)%r81d, & + hio_lai_secondary_si => this%hvars(ih_lai_secondary_si)%r81d, & + hio_fraction_secondary_forest_si => this%hvars(ih_fraction_secondary_forest_si)%r81d, & + hio_biomass_secondary_forest_si => this%hvars(ih_biomass_secondary_forest_si)%r81d, & + hio_woodproduct_si => this%hvars(ih_woodproduct_si)%r81d, & + hio_gdd_si => this%hvars(ih_gdd_si)%r81d, & + hio_site_ncolddays_si => this%hvars(ih_site_ncolddays_si)%r81d, & + hio_site_nchilldays_si => this%hvars(ih_site_nchilldays_si)%r81d, & + hio_site_cstatus_si => this%hvars(ih_site_cstatus_si)%r81d, & + hio_cleafoff_si => this%hvars(ih_cleafoff_si)%r81d, & + hio_cleafon_si => this%hvars(ih_cleafon_si)%r81d, & + hio_cbal_err_fates_si => this%hvars(ih_cbal_err_fates_si)%r81d, & + hio_tveg24 => this%hvars(ih_tveg24_si)%r81d, & + hio_tlongterm => this%hvars(ih_tlongterm_si)%r81d, & + hio_tgrowth => this%hvars(ih_tgrowth_si)%r81d, & + hio_lai_si => this%hvars(ih_lai_si)%r81d, & + hio_elai_si => this%hvars(ih_elai_si)%r81d, & + 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 + ! --------------------------------------------------------------------------------- + + siteloop: do s = 1,nsites - ! 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 + io_si = sites(s)%h_gid - end do + site_ba = 0._r8 + site_ca = 0._r8 - ! damage variables - site level - this needs to be OUT of the patch loop - if(hlm_use_tree_damage .eq. itrue) then + call this%zero_site_hvars(sites(s),upfreq_in=group_dyna_simple) - 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 + ! 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 - this%hvars(ih_crownarea_ustory_damage_si)%r81d(io_si) = & - this%hvars(ih_crownarea_ustory_damage_si)%r81d(io_si) + & - sites(s)%crownarea_ustory_damage * days_per_year * 1 / m2_per_ha - - end if + ! 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 - - ! Canopy spread index (0-1) - hio_canopy_spread_si(io_si) = sites(s)%spread + ! 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 - ! Update the site status for cold deciduous (drought deciduous is now PFT dependent) - hio_site_cstatus_si(io_si) = real(sites(s)%cstatus,r8) + ! damage variables - site level - this needs to be OUT of the patch loop + if(hlm_use_tree_damage .eq. itrue) then - ! 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) + 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 - ! Growing degree-days - hio_gdd_si(io_si) = sites(s)%grow_deg_days + 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 - ! 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) + end if + ! Canopy spread index (0-1) + hio_canopy_spread_si(io_si) = sites(s)%spread - ! Update drought deciduous information (now separated by PFT). - do i_pft = 1,numpft - ! Update the site-PFT status for drought deciduous - hio_site_dstatus_si_pft(io_si,i_pft) = real(sites(s)%dstatus(i_pft),r8) + ! Update the site status for cold deciduous (drought deciduous is now PFT dependent) + hio_site_cstatus_si(io_si) = real(sites(s)%cstatus,r8) - ! Model days elapsed since leaf off/on for drought deciduous - hio_dleafoff_si_pft(io_si,i_pft) = real(sites(s)%dndaysleafon (i_pft),r8) - hio_dleafon_si_pft(io_si,i_pft) = real(sites(s)%dndaysleafoff(i_pft),r8) + ! 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) - ! Leaf elongation factor (0 means fully abscissed, 1 means fully flushed). - hio_elong_factor_si_pft(io_si,i_pft) = sites(s)%elong_factor(i_pft) + ! Growing degree-days + hio_gdd_si(io_si) = sites(s)%grow_deg_days - if(model_day_int>numWaterMem)then - ! Mean liquid water content (m3/m3) used for drought phenology - hio_meanliqvol_si_pft(io_si,i_pft) = & - sum(sites(s)%liqvol_memory(1:numWaterMem,i_pft))/real(numWaterMem,r8) + ! Model days elapsed since leaf on/off for cold-deciduous + hio_cleafoff_si(io_si) = real(sites(s)%phen_model_date - sites(s)%cleafoffdate,r8) + hio_cleafon_si(io_si) = real(sites(s)%phen_model_date - sites(s)%cleafondate,r8) - ! Mean soil matric potential (Pa) used for drought phenology - hio_meansmp_si_pft(io_si,i_pft) = & - sum(sites(s)%smp_memory(1:numWaterMem,i_pft))/real(numWaterMem,r8) & - * dens_fresh_liquid_water * grav_earth * m_per_mm - end if - end do - - ! track total wood product accumulation at the site level - hio_woodproduct_si(io_si) = sites(s)%resources_management%trunk_product_site & - * AREA_INV - - ! site-level fire variables: - - ! Nesterov index (unitless) - hio_nesterov_fire_danger_si(io_si) = sites(s)%acc_NI - - ! number of ignitions [#/km2/day -> #/m2/s] - hio_fire_nignitions_si(io_si) = sites(s)%NF_successful / m2_per_km2 / & - sec_per_day - - ! Fire danger index (FDI) (0-1) - hio_fire_fdi_si(io_si) = sites(s)%FDI - - ! 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_harvest_debt_si(io_si) = sites(s)%resources_management%harvest_debt - hio_harvest_debt_sec_si(io_si) = sites(s)%resources_management%harvest_debt_sec - - ! error in primary lands from patch fusion [m2 m-2 day-1] -> [m2 m-2 yr-1] - hio_primaryland_fusion_error_si(io_si) = sites(s)%primary_land_patchfusion_error * days_per_year - - ! roll up disturbance rates in land-use x land-use array into a single dimension - do i_dist = 1, n_landuse_cats - do j_dist = 1, n_landuse_cats - 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 - end do - end do + ! track total wood product accumulation at the site level + hio_woodproduct_si(io_si) = sites(s)%resources_management%trunk_product_site & + * AREA_INV - ! output site-level disturbance rates [m2 m-2 day-1] -> [m2 m-2 yr-1] - TO DO rework this + ! site-level fire variables: - 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 + ! Nesterov index (unitless) + hio_nesterov_fire_danger_si(io_si) = sites(s)%fireWeather%fire_weather_index - 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 + ! number of ignitions [#/km2/day -> #/m2/s] + hio_fire_nignitions_si(io_si) = sites(s)%NF_successful / m2_per_km2 / & + sec_per_day - 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 + ! Fire danger index (FDI) (0-1) + hio_fire_fdi_si(io_si) = sites(s)%FDI - hio_harvest_carbonflux_si(io_si) = sites(s)%mass_balance(element_pos(carbon12_element))%wood_product * AREA_INV - - ! Loop through patches to sum up diagonistics - ipa = 0 - cpatch => sites(s)%oldest_patch - patchloop: do while(associated(cpatch)) - - ! Increment the number of patches per site - hio_npatches_si(io_si) = hio_npatches_si(io_si) + 1._r8 - if ( cpatch%land_use_label .eq. secondaryland ) then - hio_npatches_sec_si(io_si) = hio_npatches_sec_si(io_si) + 1._r8 + ! 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 - cpatch%age_class = get_age_class_index(cpatch%age) + 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 - ! Increment the fractional area in each age class bin - hio_area_si_age(io_si,cpatch%age_class) = hio_area_si_age(io_si,cpatch%age_class) & - + cpatch%area * 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 - hio_area_si_landuse(io_si, cpatch%land_use_label) = hio_area_si_landuse(io_si, cpatch%land_use_label)& - + cpatch%area * AREA_INV + ! output site-level disturbance rates [m2 m-2 day-1] -> [m2 m-2 yr-1] - TO DO rework this - ! 24hr veg temperature - hio_tveg24(io_si) = hio_tveg24(io_si) + & - (cpatch%tveg24%GetMean()- t_water_freeze_k_1atm)*cpatch%area*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 - ! 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 + 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 - ! 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_fall_disturbance_rate_si(io_si) = & + sum(sites(s)%disturbance_rates(dtype_ifall,1:n_landuse_cats,1:n_landuse_cats)) * & + days_per_year - ! Increment some patch-age-resolved diagnostics - hio_lai_si_age(io_si,cpatch%age_class) = hio_lai_si_age(io_si,cpatch%age_class) & - + sum(cpatch%tlai_profile(:,:,:)) * cpatch%area + hio_harvest_woodprod_carbonflux_si(io_si) = AREA_INV * & + sum(sites(s)%mass_balance(element_pos(carbon12_element))%wood_product_harvest(1:numpft)) - hio_ncl_si_age(io_si,cpatch%age_class) = hio_ncl_si_age(io_si,cpatch%age_class) & - + cpatch%ncl_p * cpatch%area - hio_npatches_si_age(io_si,cpatch%age_class) = hio_npatches_si_age(io_si,cpatch%age_class) + 1._r8 + hio_luchange_woodprod_carbonflux_si(io_si) = AREA_INV * & + sum(sites(s)%mass_balance(element_pos(carbon12_element))%wood_product_landusechange(1:numpft)) + - hio_lai_si(io_si) = hio_lai_si(io_si) + sum( cpatch%canopy_area_profile(:,:,:) * cpatch%elai_profile(:,:,:) ) * & - cpatch%total_canopy_area * AREA_INV + ! 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 - if ( ED_val_comp_excln .lt. 0._r8 ) then ! only valid when "strict ppa" enabled - hio_zstar_si_age(io_si,cpatch%age_class) = hio_zstar_si_age(io_si,cpatch%age_class) & - + cpatch%zstar * cpatch%area * AREA_INV - endif + + hio_ustory_mortality_carbonflux_si(io_si) = hio_ustory_mortality_carbonflux_si(io_si) + & + sum(sites(s)%fmort_carbonflux_ustory(:)) / g_per_kg - ! some diagnostics on secondary forest area and its age distribution - if ( cpatch%land_use_label .eq. secondaryland ) then - hio_fraction_secondary_forest_si(io_si) = hio_fraction_secondary_forest_si(io_si) + & - cpatch%area * AREA_INV + ! 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(:)) - ageclass_since_anthrodist = get_age_class_index(cpatch%age_since_anthro_disturbance) + ! 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_agesince_anthrodist_si_age(io_si,ageclass_since_anthrodist) = & - hio_agesince_anthrodist_si_age(io_si,ageclass_since_anthrodist) & - + cpatch%area * AREA_INV + 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 - hio_secondarylands_area_si_age(io_si,cpatch%age_class) = & - hio_secondarylands_area_si_age(io_si,cpatch%age_class) & - + 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 - hio_lai_secondary_si(io_si) = hio_lai_secondary_si(io_si) & - + sum(cpatch%tlai_profile(:,:,:)) * cpatch%total_canopy_area - 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 - ! patch-age-resolved fire variables - do i_pft = 1,numpft - ! for scorch height, weight the value by patch area within any - ! given age class - in the event that there is more than one - ! patch per age class. - iagepft = cpatch%age_class + (i_pft-1) * nlevage - hio_scorch_height_si_agepft(io_si,iagepft) = hio_scorch_height_si_agepft(io_si,iagepft) + & - cpatch%Scorch_ht(i_pft) * cpatch%area - - ! 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. i_pft) then - this%hvars(ih_nocomp_pftpatchfraction_si_pft)%r82d(io_si,i_pft) = & - this%hvars(ih_nocomp_pftpatchfraction_si_pft)%r82d(io_si,i_pft) + cpatch%area * AREA_INV - - this%hvars(ih_nocomp_pftnpatches_si_pft)%r82d(io_si,i_pft) = & - this%hvars(ih_nocomp_pftnpatches_si_pft)%r82d(io_si,i_pft) + 1._r8 - - this%hvars(ih_nocomp_pftburnedarea_si_pft)%r82d(io_si,i_pft) = & - this%hvars(ih_nocomp_pftburnedarea_si_pft)%r82d(io_si,i_pft) + & - cpatch%frac_burnt * cpatch%area * AREA_INV / sec_per_day - endif - - end do + flux_diags_c => sites(s)%flux_diags(element_pos(carbon12_element)) - ! fractional area burnt [frac/day] -> [frac/sec] - hio_area_burnt_si_age(io_si,cpatch%age_class) = hio_area_burnt_si_age(io_si,cpatch%age_class) + & - cpatch%frac_burnt * cpatch%area * AREA_INV / sec_per_day + hio_litter_in_si(io_si) = (sum(flux_diags_c%cwd_ag_input(:)) + & + sum(flux_diags_c%cwd_bg_input(:)) + & + sum(flux_diags_c%leaf_litter_input(:)) + & + sum(flux_diags_c%root_litter_input(:))) * & + AREA_INV * days_per_sec - ! hio_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 * cpatch%area * AREA_INV + ! Loop through patches to sum up diagonistics + ipa = 0 + cpatch => sites(s)%oldest_patch + patchloop: do while(associated(cpatch)) - ! Fire intensity weighted by burned fraction [kJ/m/s] -> [J/m/s] - hio_fire_intensity_si_age(io_si, cpatch%age_class) = hio_fire_intensity_si_age(io_si, cpatch%age_class) + & - cpatch%FI * cpatch%frac_burnt * cpatch%area * AREA_INV * J_per_kJ + ! Increment the number of patches per site + hio_npatches_si(io_si) = hio_npatches_si(io_si) + 1._r8 + if ( cpatch%land_use_label .eq. secondaryland ) then + hio_npatches_sec_si(io_si) = hio_npatches_sec_si(io_si) + 1._r8 + end if - ! Fuel sum [kg/m2] - hio_fire_sum_fuel_si_age(io_si, cpatch%age_class) = hio_fire_sum_fuel_si_age(io_si, cpatch%age_class) + & - cpatch%sum_fuel * cpatch%area * AREA_INV + 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 + + ! 24hr veg temperature + hio_tveg24(io_si) = hio_tveg24(io_si) + & + (cpatch%tveg24%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 + ! 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 - ! area occupied by plants and trees [m2/m2] - hio_area_plant_si(io_si) = hio_area_plant_si(io_si) + min(cpatch%total_canopy_area,cpatch%area) * AREA_INV - hio_area_trees_si(io_si) = hio_area_trees_si(io_si) + min(cpatch%total_tree_area,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 - ! loop through cohorts on patch - ccohort => cpatch%shortest - cohortloop: do while(associated(ccohort)) + ! some diagnostics on secondary forest area and its age distribution + if ( cpatch%land_use_label .eq. secondaryland ) then + hio_fraction_secondary_forest_si(io_si) = hio_fraction_secondary_forest_si(io_si) + & + cpatch%area * AREA_INV - ft = ccohort%pft + ! Secondary forest mean LAI - ! 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) + hio_lai_secondary_si(io_si) = hio_lai_secondary_si(io_si) & + + sum(cpatch%tlai_profile(:,:,:)) * cpatch%total_canopy_area + end if - ! Increment the number of cohorts per site - hio_ncohorts_si(io_si) = hio_ncohorts_si(io_si) + 1._r8 + ! 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 - if ( cpatch%land_use_label .eq. secondaryland ) then - hio_ncohorts_sec_si(io_si) = hio_ncohorts_sec_si(io_si) + 1._r8 - end if + ! area occupied by plants and trees [m2/m2] + hio_area_plant_si(io_si) = hio_area_plant_si(io_si) + min(cpatch%total_canopy_area,cpatch%area) * AREA_INV + hio_area_trees_si(io_si) = hio_area_trees_si(io_si) + min(cpatch%total_tree_area,cpatch%area) * AREA_INV - n_perm2 = ccohort%n * 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 - hio_canopy_area_si_age(io_si,cpatch%age_class) = hio_canopy_area_si_age(io_si,cpatch%age_class) & - + ccohort%c_area * AREA_INV + ! 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_effect_wspeed_si(io_si) = hio_effect_wspeed_si(io_si) + cpatch%effect_wspeed * 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_area_si(io_si) = hio_fire_area_si(io_si) + cpatch%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_bulkd * cpatch%area * AREA_INV + hio_fire_fuel_eff_moist_si(io_si) = hio_fire_fuel_eff_moist_si(io_si) + cpatch%fuel_eff_moist * cpatch%area * AREA_INV + hio_fire_fuel_sav_si(io_si) = hio_fire_fuel_sav_si(io_si) + cpatch%fuel_sav * cpatch%area * AREA_INV / m_per_cm + hio_fire_fuel_mef_si(io_si) = hio_fire_fuel_mef_si(io_si) + cpatch%fuel_mef * cpatch%area * AREA_INV + hio_sum_fuel_si(io_si) = hio_sum_fuel_si(io_si) + cpatch%sum_fuel * cpatch%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 + hio_fire_intensity_area_product_si(io_si) = hio_fire_intensity_area_product_si(io_si) + & + cpatch%FI * cpatch%frac_burnt * cpatch%area * AREA_INV * J_per_kJ - 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 + litt => cpatch%litter(element_pos(carbon12_element)) - 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 + area_frac = cpatch%area * AREA_INV - sapw_m = ccohort%prt%GetState(sapw_organ, element_list(el)) - struct_m = ccohort%prt%GetState(struct_organ, element_list(el)) - leaf_m = ccohort%prt%GetState(leaf_organ, element_list(el)) - fnrt_m = ccohort%prt%GetState(fnrt_organ, element_list(el)) - store_m = ccohort%prt%GetState(store_organ, element_list(el)) - repro_m = ccohort%prt%GetState(repro_organ, element_list(el)) + ! 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(:))) * & + area_frac * days_per_sec + + ! Sum up total seed bank (germinated and ungerminated) + hio_seed_bank_si(io_si) = hio_seed_bank_si(io_si) + & + (sum(litt%seed(:))+sum(litt%seed_germ(:))) * & + area_frac + + ! Sum up total seed bank (just ungerminated) + hio_ungerm_seed_bank_si(io_si) = hio_ungerm_seed_bank_si(io_si) + & + sum(litt%seed(:)) * area_frac + + ! Sum up total seedling pool + hio_seedling_pool_si(io_si) = hio_seedling_pool_si(io_si) + & + sum(litt%seed_germ(:)) * area_frac + + ! Sum up the input flux into the seed bank (local and external) + hio_seeds_in_si(io_si) = hio_seeds_in_si(io_si) + & + (sum(litt%seed_in_local(:)) + sum(litt%seed_in_extern(:))) * & + area_frac * days_per_sec + + hio_seeds_in_local_si(io_si) = hio_seeds_in_local_si(io_si) + & + sum(litt%seed_in_local(:)) * & + area_frac * days_per_sec + + ! loop through cohorts on patch + ccohort => cpatch%shortest + cohortloop: do while(associated(ccohort)) - alive_m = leaf_m + fnrt_m + sapw_m - total_m = alive_m + store_m + struct_m + ft = ccohort%pft + n_perm2 = ccohort%n * AREA_INV - i_scpf = ccohort%size_by_pft_class + ! Increment the number of cohorts per site + hio_ncohorts_si(io_si) = hio_ncohorts_si(io_si) + 1._r8 + if ( cpatch%land_use_label .eq. secondaryland ) then + hio_ncohorts_sec_si(io_si) = hio_ncohorts_sec_si(io_si) + 1._r8 + end if - ! 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 - - ! Determine the root carbon biomass in kg/m3 - ! [kg/m3] = [kg/plant] * [plant/ha] / [m3/ha] * [fraction] / [m] - - - do ilyr = 1,sites(s)%nlevsoil - this%hvars(ih_fnrtc_sl)%r82d(io_si,ilyr) = this%hvars(ih_fnrtc_sl)%r82d(io_si,ilyr) + & - fnrt_m * ccohort%n / area * sites(s)%rootfrac_scr(ilyr) / sites(s)%dz_soil(ilyr) - end do - - hio_bdead_si(io_si) = hio_bdead_si(io_si) + n_perm2 * struct_m - hio_balive_si(io_si) = hio_balive_si(io_si) + n_perm2 * alive_m - - 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) ) - - - ! 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 ( cpatch%land_use_label .eq. secondaryland ) then - hio_nindivs_sec_si_pft(io_si,ft) = hio_nindivs_sec_si_pft(io_si,ft) + & - ccohort%n * AREA_INV + ! Update biomass components + ! Mass pools [kg] + elloop: do el = 1, num_elements + + sapw_m = ccohort%prt%GetState(sapw_organ, element_list(el)) + struct_m = ccohort%prt%GetState(struct_organ, element_list(el)) + leaf_m = ccohort%prt%GetState(leaf_organ, element_list(el)) + fnrt_m = ccohort%prt%GetState(fnrt_organ, element_list(el)) + store_m = ccohort%prt%GetState(store_organ, element_list(el)) + repro_m = ccohort%prt%GetState(repro_organ, element_list(el)) + + alive_m = leaf_m + fnrt_m + sapw_m + total_m = alive_m + store_m + struct_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) ) + + ! track the total biomass on all secondary lands + if ( cpatch%land_use_label .eq. secondaryland ) then + hio_biomass_secondary_forest_si(io_si) = hio_biomass_secondary_forest_si(io_si) + & + total_m * ccohort%n * AREA_INV + endif + + 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 + + ! FLUXES --- + ! 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 + + ! 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 + + ! 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 - hio_biomass_si_pft(io_si, ft) = hio_biomass_si_pft(io_si, ft) + & - (ccohort%n * AREA_INV) * total_m - - if ( cpatch%land_use_label .eq. secondaryland ) then - hio_biomass_sec_si_pft(io_si, ft) = hio_biomass_sec_si_pft(io_si, ft) + & - (ccohort%n * AREA_INV) * total_m end if - ! update total biomass per age bin - hio_biomass_si_age(io_si,cpatch%age_class) = hio_biomass_si_age(io_si,cpatch%age_class) & - + total_m * ccohort%n * AREA_INV + ! THIS NEEDS TO BE NORMALIZED (RGK) + hio_ca_weighted_height_si(io_si) = hio_ca_weighted_height_si(io_si) + & + ccohort%height * ccohort%c_area / m2_per_ha - ! track the total biomass on all secondary lands - if ( cpatch%land_use_label .eq. secondaryland ) then - hio_biomass_secondary_forest_si(io_si) = hio_biomass_secondary_forest_si(io_si) + & - total_m * ccohort%n * AREA_INV - endif + site_ca = site_ca + ccohort%c_area / m2_per_ha + ! RGK - CANOPY/USTORY BIOMASS IS NOT A FLUX, NEED NOT BE CONDITIONED BY isnew + ! ---------------------------------------------------------------------------------- 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) - - 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 + hio_canopy_biomass_si(io_si) = hio_canopy_biomass_si(io_si) + n_perm2 * total_m + + hio_canopy_mortality_carbonflux_si(io_si) = hio_canopy_mortality_carbonflux_si(io_si) + & + (ccohort%bmort + ccohort%hmort + ccohort%cmort + & + ccohort%frmort + ccohort%smort + ccohort%asmort + ccohort%dgmort) * & + total_m * ccohort%n * days_per_sec * years_per_day * ha_per_m2 + & + (ccohort%lmort_direct + ccohort%lmort_collateral + ccohort%lmort_infra) * total_m * & + ccohort%n * ha_per_m2 + + hio_canopy_mortality_crownarea_si(io_si) = hio_canopy_mortality_crownarea_si(io_si) + & + (ccohort%bmort + ccohort%hmort + ccohort%cmort + & + ccohort%frmort + ccohort%smort + ccohort%asmort + ccohort%dgmort) * & + ccohort%c_area + & + (ccohort%lmort_direct + ccohort%lmort_collateral + ccohort%lmort_infra) * & + ccohort%c_area * sec_per_day * days_per_year - 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) - - 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 + hio_ustory_biomass_si(io_si) = hio_ustory_biomass_si(io_si) + n_perm2 * total_m + + hio_ustory_mortality_carbonflux_si(io_si) = hio_ustory_mortality_carbonflux_si(io_si) + & + (ccohort%bmort + ccohort%hmort + ccohort%cmort + & + ccohort%frmort + ccohort%smort + ccohort%asmort + ccohort%dgmort) * & + total_m * ccohort%n * days_per_sec * years_per_day * ha_per_m2 + & + (ccohort%lmort_direct + ccohort%lmort_collateral + ccohort%lmort_infra) * total_m * & + ccohort%n * ha_per_m2 + + hio_ustory_mortality_crownarea_si(io_si) = hio_ustory_mortality_crownarea_si(io_si) + & + (ccohort%bmort + ccohort%hmort + ccohort%cmort + & + ccohort%frmort + ccohort%smort + ccohort%asmort + ccohort%dgmort) * & + ccohort%c_area + & + (ccohort%lmort_direct + ccohort%lmort_collateral + ccohort%lmort_infra) * & + ccohort%c_area * sec_per_day * days_per_year - 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 + end if notnew - ! Update PFT crown area - hio_crownarea_si_pft(io_si, ft) = hio_crownarea_si_pft(io_si, ft) + & - ccohort%c_area * AREA_INV + ccohort => ccohort%taller + enddo cohortloop ! cohort loop - 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 + ipa = ipa + 1 + cpatch => cpatch%younger + end do patchloop !patch loop - ! Site by Size-Class x PFT (SCPF) - ! ------------------------------------------------------------------------ + ! Perform any necessary normalizations + ! ---------------------------------------------------------------------------------------- - dbh = ccohort%dbh !-0.5*(1./365.25)*ccohort%ddbhdt + ! divide secondary plant leaf area by secondary forest area to get the secondary forest LAI + if (hio_fraction_secondary_forest_si(io_si) .gt. nearzero) then + hio_lai_secondary_si(io_si) = hio_lai_secondary_si(io_si) / (hio_fraction_secondary_forest_si(io_si)*AREA) + end if - ! 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 + ! 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 - ! 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 + ! 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 - 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 .eq. secondaryland ) then - hio_gpp_sec_si_pft(io_si, ft) = hio_gpp_sec_si_pft(io_si, ft) + & - ccohort%gpp_acc_hold * n_perm2 / days_per_year / sec_per_day - hio_npp_sec_si_pft(io_si, ft) = hio_npp_sec_si_pft(io_si, ft) + & - ccohort%npp_acc_hold * n_perm2 / days_per_year / sec_per_day + 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 - - ! 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 - - associate( scpf => ccohort%size_by_pft_class, & - scls => ccohort%size_class, & - cacls => ccohort%coage_class, & - capf => ccohort%coage_by_pft_class, & - cdam => ccohort%crowndamage) - - gpp_cached = (hio_gpp_si_scpf(io_si,scpf)) * & - days_per_year * sec_per_day - - ! [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*((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*((dbh/100.0_r8)**2.0_r8)* & - ccohort%n / m2_per_ha - - ! growth increment - hio_ddbh_si_scpf(io_si,scpf) = hio_ddbh_si_scpf(io_si,scpf) + & - ccohort%ddbhdt*ccohort%n / m2_per_ha * m_per_cm - - hio_ba_weighted_height_si(io_si) = hio_ba_weighted_height_si(io_si) + & - ccohort%height * & - 0.25_r8*pi_const*((dbh/100.0_r8)**2.0_r8)*ccohort%n / m2_per_ha - + 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 - - ! 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 + 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 + + ! 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 - 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 + end do siteloop - ! Examine secondary forest mortality and mortality rates - if(cpatch%land_use_label .eq. secondaryland) then + end associate + return + end subroutine update_history_dyn1 - if (hlm_use_cohort_age_tracking .eq.itrue) then - hio_m10_sec_si_scls(io_si,scls) = hio_m10_sec_si_scls(io_si,scls) + & - ccohort%asmort*ccohort%n / m2_per_ha - end if + ! ========================================================================================= - hio_m1_sec_si_scls(io_si,scls) = hio_m1_sec_si_scls(io_si,scls) + ccohort%bmort*ccohort%n / m2_per_ha - hio_m2_sec_si_scls(io_si,scls) = hio_m2_sec_si_scls(io_si,scls) + ccohort%hmort*ccohort%n / m2_per_ha - hio_m3_sec_si_scls(io_si,scls) = hio_m3_sec_si_scls(io_si,scls) + ccohort%cmort*ccohort%n / m2_per_ha - hio_m7_sec_si_scls(io_si,scls) = hio_m7_sec_si_scls(io_si,scls) + & - (ccohort%lmort_direct+ccohort%lmort_collateral+ccohort%lmort_infra) * ccohort%n / m2_per_ha - hio_m8_sec_si_scls(io_si,scls) = hio_m8_sec_si_scls(io_si,scls) + & - ccohort%frmort*ccohort%n / m2_per_ha - hio_m9_sec_si_scls(io_si,scls) = hio_m9_sec_si_scls(io_si,scls) + ccohort%smort*ccohort%n / m2_per_ha - end if + subroutine update_history_dyn2(this,nc,nsites,sites,bc_in) - !C13 discrimination - if(gpp_cached + ccohort%gpp_acc_hold > 0.0_r8)then - hio_c13disc_si_scpf(io_si,scpf) = ((hio_c13disc_si_scpf(io_si,scpf) * gpp_cached) + & - (ccohort%c13disc_acc * ccohort%gpp_acc_hold)) / (gpp_cached + ccohort%gpp_acc_hold) - else - hio_c13disc_si_scpf(io_si,scpf) = 0.0_r8 - endif + ! 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) - ! number density [/m2] - hio_nplant_si_scpf(io_si,scpf) = hio_nplant_si_scpf(io_si,scpf) + ccohort%n / m2_per_ha + 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 :: ipa,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 :: ageclass_since_anthrodist ! what is the equivalent age class for + ! time-since-anthropogenic-disturbance of secondary forest + real(r8) :: area_frac ! 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 :: iagepft ! age x pft index + integer :: ilyr ! Soil index for nlevsoil + integer :: iscag ! size-class x age index + integer :: iscagpft ! size-class x age x pft index + integer :: icdpf, icdsc, icdam ! iterators for the crown damage level + integer :: i_agefuel ! age x fuel size class index + 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) - ! 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 + integer :: i_dist, j_dist - ! damage variables - cohort level - if(hlm_use_tree_damage .eq. itrue) then - - cdpf = get_cdamagesizepft_class_index(ccohort%dbh, ccohort%crowndamage, ccohort%pft) - - this%hvars(ih_mortality_si_cdpf)%r82d(io_si,cdpf) = & - this%hvars(ih_mortality_si_cdpf)%r82d(io_si,cdpf) + & - (ccohort%bmort + ccohort%hmort + ccohort%cmort + ccohort%frmort + & - ccohort%smort + ccohort%asmort + ccohort%dgmort) * ccohort%n / m2_per_ha + & - (ccohort%lmort_direct + ccohort%lmort_collateral + ccohort%lmort_infra) * & - ccohort%n * sec_per_day * days_per_year / m2_per_ha - - ! crown damage by size by pft - this%hvars(ih_nplant_si_cdpf)%r82d(io_si, cdpf) = & - this%hvars(ih_nplant_si_cdpf)%r82d(io_si, cdpf) + ccohort%n / m2_per_ha - this%hvars(ih_m3_si_cdpf)%r82d(io_si, cdpf) = & - this%hvars(ih_m3_si_cdpf)%r82d(io_si, cdpf) + & - ccohort%cmort * ccohort%n / m2_per_ha - - ! mortality - this%hvars(ih_m11_si_scpf)%r82d(io_si,scpf) = & - this%hvars(ih_m11_si_scpf)%r82d(io_si,scpf) + & - ccohort%dgmort*ccohort%n / m2_per_ha - this%hvars(ih_m11_si_cdpf)%r82d(io_si,cdpf) = & - this%hvars(ih_m11_si_cdpf)%r82d(io_si,cdpf) + & - ccohort%dgmort*ccohort%n / m2_per_ha - - this%hvars(ih_ddbh_si_cdpf)%r82d(io_si,cdpf) = & - this%hvars(ih_ddbh_si_cdpf)%r82d(io_si,cdpf) + & - ccohort%ddbhdt*ccohort%n / m2_per_ha * m_per_cm + type(site_fluxdiags_type), pointer :: flux_diags + type(site_fluxdiags_type), pointer :: flux_diags_c - end if - - ! Carbon only metrics - sapw_m = ccohort%prt%GetState(sapw_organ, carbon12_element) - struct_m = ccohort%prt%GetState(struct_organ, carbon12_element) - leaf_m = ccohort%prt%GetState(leaf_organ, carbon12_element) - fnrt_m = ccohort%prt%GetState(fnrt_organ, carbon12_element) - store_m = ccohort%prt%GetState(store_organ, carbon12_element) - repro_m = ccohort%prt%GetState(repro_organ, carbon12_element) - alive_m = leaf_m + fnrt_m + sapw_m - total_m = alive_m + store_m + struct_m - - hio_mortality_carbonflux_si_pft(io_si,ccohort%pft) = hio_mortality_carbonflux_si_pft(io_si,ccohort%pft) + & - (ccohort%bmort + ccohort%hmort + ccohort%cmort + & - ccohort%frmort + ccohort%smort + ccohort%asmort + ccohort%dgmort) * & - total_m * ccohort%n * days_per_sec * years_per_day * ha_per_m2 + & - (ccohort%lmort_direct + ccohort%lmort_collateral + ccohort%lmort_infra) * total_m * & - ccohort%n * ha_per_m2 - - hio_hydraulicmortality_carbonflux_si_pft(io_si,ccohort%pft) = hio_hydraulicmortality_carbonflux_si_pft(io_si,ccohort%pft) + & - ccohort%hmort * total_m * ccohort%n * days_per_sec * years_per_day * ha_per_m2 - - hio_cstarvmortality_carbonflux_si_pft(io_si,ccohort%pft) = hio_cstarvmortality_carbonflux_si_pft(io_si,ccohort%pft) + & - ccohort%cmort * total_m * ccohort%n * days_per_sec * years_per_day * ha_per_m2 - - ! Aboveground mortality - hio_abg_mortality_cflux_si_scpf(io_si,scpf) = hio_abg_mortality_cflux_si_scpf(io_si,scpf) + & - (ccohort%bmort + ccohort%hmort + ccohort%cmort + & - ccohort%frmort + ccohort%smort + ccohort%asmort) * & - ( (sapw_m + struct_m + store_m ) * prt_params%allom_agb_frac(ccohort%pft) + & - leaf_m ) * ccohort%n * days_per_sec * years_per_day * ha_per_m2 + & - (ccohort%lmort_direct + ccohort%lmort_collateral + ccohort%lmort_infra) * & - ( (sapw_m + struct_m + store_m ) * prt_params%allom_agb_frac(ccohort%pft) + & - leaf_m ) * ccohort%n * ha_per_m2 - - ! Aboveground woody productivity - hio_abg_productivity_cflux_si_scpf(io_si,scpf) = hio_abg_productivity_cflux_si_scpf(io_si,scpf) + & - ( (sapw_m_net_alloc + struct_m_net_alloc + store_m_net_alloc) * prt_params%allom_agb_frac(ccohort%pft) + & - leaf_m_net_alloc ) * n_perm2 / & - days_per_year / sec_per_day + real(r8), parameter :: reallytalltrees = 1000. ! some large number (m) - - ! 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 x patch-age related quantities - - iscag = get_sizeage_class_index(ccohort%dbh,cpatch%age) - - hio_nplant_si_scag(io_si,iscag) = hio_nplant_si_scag(io_si,iscag) + ccohort%n / m2_per_ha - - hio_nplant_si_scls(io_si,scls) = hio_nplant_si_scls(io_si,scls) + ccohort%n / m2_per_ha - - - ! update size, age, and PFT - indexed quantities - iscagpft = get_sizeagepft_class_index(ccohort%dbh,cpatch%age,ccohort%pft) - - hio_nplant_si_scagpft(io_si,iscagpft) = hio_nplant_si_scagpft(io_si,iscagpft) + ccohort%n / m2_per_ha - - ! update age and PFT - indexed quantities - iagepft = get_agepft_class_index(cpatch%age,ccohort%pft) - - hio_npp_si_agepft(io_si,iagepft) = hio_npp_si_agepft(io_si,iagepft) + & - ccohort%n * ccohort%npp_acc_hold * AREA_INV / days_per_year / sec_per_day - - hio_biomass_si_agepft(io_si,iagepft) = hio_biomass_si_agepft(io_si,iagepft) + & - total_m * ccohort%n * AREA_INV - - ! update SCPF/SCLS- and canopy/subcanopy- partitioned quantities - canlayer: if (ccohort%canopy_layer .eq. 1) then - hio_nplant_canopy_si_scag(io_si,iscag) = hio_nplant_canopy_si_scag(io_si,iscag) + ccohort%n / m2_per_ha - hio_mortality_canopy_si_scag(io_si,iscag) = hio_mortality_canopy_si_scag(io_si,iscag) + & - (ccohort%bmort + ccohort%hmort + ccohort%cmort + & - ccohort%frmort + ccohort%smort + ccohort%asmort + ccohort%dgmort) * ccohort%n / m2_per_ha - hio_ddbh_canopy_si_scag(io_si,iscag) = hio_ddbh_canopy_si_scag(io_si,iscag) + & - ccohort%ddbhdt*ccohort%n * m_per_cm / m2_per_ha - hio_bstor_canopy_si_scpf(io_si,scpf) = hio_bstor_canopy_si_scpf(io_si,scpf) + & - store_m * ccohort%n / m2_per_ha - hio_bleaf_canopy_si_scpf(io_si,scpf) = hio_bleaf_canopy_si_scpf(io_si,scpf) + & - leaf_m * ccohort%n / m2_per_ha - hio_lai_canopy_si_scpf(io_si,scpf) = hio_lai_canopy_si_scpf(io_si,scpf) + & - ccohort%treelai*ccohort%c_area * AREA_INV - - hio_canopy_biomass_si(io_si) = hio_canopy_biomass_si(io_si) + n_perm2 * total_m - - !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%bmort + ccohort%hmort + ccohort%cmort + ccohort%frmort + & - ccohort%smort + ccohort%asmort + ccohort%dgmort) * ccohort%n / m2_per_ha + & - (ccohort%lmort_direct + ccohort%lmort_collateral + ccohort%lmort_infra) * & - ccohort%n * sec_per_day * days_per_year / m2_per_ha - - 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_area_canopy_si_scls(io_si,scls) = hio_crown_area_canopy_si_scls(io_si,scls) + & - ccohort%c_area / m2_per_ha - 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_acc_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%bmort + ccohort%hmort + ccohort%cmort + & - ccohort%frmort + ccohort%smort + ccohort%asmort + ccohort%dgmort) * ccohort%n / m2_per_ha + & - (ccohort%lmort_direct + ccohort%lmort_collateral + ccohort%lmort_infra) * & - ccohort%n * sec_per_day * days_per_year / m2_per_ha - - hio_m3_mortality_canopy_si_scls(io_si,scls) = hio_m3_mortality_canopy_si_scls(io_si,scls) + & - ccohort%cmort * ccohort%n / m2_per_ha - - hio_canopy_mortality_carbonflux_si(io_si) = hio_canopy_mortality_carbonflux_si(io_si) + & - (ccohort%bmort + ccohort%hmort + ccohort%cmort + & - ccohort%frmort + ccohort%smort + ccohort%asmort + ccohort%dgmort) * & - total_m * ccohort%n * days_per_sec * years_per_day * ha_per_m2 + & - (ccohort%lmort_direct + ccohort%lmort_collateral + ccohort%lmort_infra) * total_m * & - ccohort%n * ha_per_m2 - - hio_canopy_mortality_crownarea_si(io_si) = hio_canopy_mortality_crownarea_si(io_si) + & - (ccohort%bmort + ccohort%hmort + ccohort%cmort + & - ccohort%frmort + ccohort%smort + ccohort%asmort + ccohort%dgmort) * & - ccohort%c_area + & - (ccohort%lmort_direct + ccohort%lmort_collateral + ccohort%lmort_infra) * & - ccohort%c_area * sec_per_day * days_per_year - - hio_carbon_balance_canopy_si_scls(io_si,scls) = hio_carbon_balance_canopy_si_scls(io_si,scls) + & - ccohort%n * ccohort%npp_acc_hold / m2_per_ha / days_per_year / sec_per_day - - ! damage variables - canopy - if(hlm_use_tree_damage .eq. itrue) then - - ! carbon starvation mortality in the canopy by size x damage x pft - this%hvars(ih_m3_mortality_canopy_si_cdpf)%r82d(io_si,cdpf) = & - this%hvars(ih_m3_mortality_canopy_si_cdpf)%r82d(io_si,cdpf)+& - ccohort%cmort * ccohort%n / m2_per_ha - - ! damage mortality in the canopy by size x damage x pft - this%hvars(ih_m11_mortality_canopy_si_cdpf)%r82d(io_si,cdpf) = & - this%hvars(ih_m11_mortality_canopy_si_cdpf)%r82d(io_si,cdpf)+& - ccohort%dgmort * ccohort%n / m2_per_ha - - this%hvars(ih_mortality_canopy_si_cdpf)%r82d(io_si,cdpf) = & - this%hvars(ih_mortality_canopy_si_cdpf)%r82d(io_si,cdpf)+ & - (ccohort%bmort + ccohort%hmort + ccohort%cmort + ccohort%frmort + ccohort%smort + & - ccohort%asmort + ccohort%dgmort) * ccohort%n / m2_per_ha + & - (ccohort%lmort_direct + ccohort%lmort_collateral + ccohort%lmort_infra) * & - ccohort%n * sec_per_day * days_per_year / m2_per_ha - - ! nplants by damage - this%hvars(ih_nplant_canopy_si_cdpf)%r82d(io_si,cdpf) = & - this%hvars(ih_nplant_canopy_si_cdpf)%r82d(io_si,cdpf) + & - ccohort%n / m2_per_ha - - ! growth rate by damage x size x pft in the canopy - this%hvars(ih_ddbh_canopy_si_cdpf)%r82d(io_si,cdpf) = & - this%hvars(ih_ddbh_canopy_si_cdpf)%r82d(io_si,cdpf) + & - ccohort%ddbhdt*ccohort%n / m2_per_ha * m_per_cm - - end if ! end if damage - - - hio_leaf_md_canopy_si_scls(io_si,scls) = hio_leaf_md_canopy_si_scls(io_si,scls) + & - leaf_m_turnover * ccohort%n / m2_per_ha / days_per_year / sec_per_day - hio_root_md_canopy_si_scls(io_si,scls) = hio_root_md_canopy_si_scls(io_si,scls) + & - 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 / days_per_year / 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 +! + associate( hio_err_fates_elem => this%hvars(ih_err_fates_elem)%r82d, & + hio_biomass_si_pft => this%hvars(ih_biomass_si_pft)%r82d, & + hio_biomass_sec_si_pft => this%hvars(ih_biomass_sec_si_pft)%r82d, & + hio_leafbiomass_si_pft => this%hvars(ih_leafbiomass_si_pft)%r82d, & + hio_storebiomass_si_pft => this%hvars(ih_storebiomass_si_pft)%r82d, & + hio_nindivs_si_pft => this%hvars(ih_nindivs_si_pft)%r82d, & + hio_nindivs_sec_si_pft => this%hvars(ih_nindivs_sec_si_pft)%r82d, & + hio_recruitment_si_pft => this%hvars(ih_recruitment_si_pft)%r82d, & + hio_recruitment_cflux_si_pft => this%hvars(ih_recruitment_cflux_si_pft)%r82d, & + hio_seeds_out_gc_si_pft => this%hvars(ih_seeds_out_gc_si_pft)%r82d, & + hio_seeds_in_gc_si_pft => this%hvars(ih_seeds_in_gc_si_pft)%r82d, & + hio_mortality_si_pft => this%hvars(ih_mortality_si_pft)%r82d, & + hio_mortality_carbonflux_si_pft => this%hvars(ih_mortality_carbonflux_si_pft)%r82d, & + hio_cstarvmortality_carbonflux_si_pft => this%hvars(ih_cstarvmortality_carbonflux_si_pft)%r82d, & + hio_hydraulicmortality_carbonflux_si_pft => this%hvars(ih_hydraulicmortality_carbonflux_si_pft)%r82d, & + hio_firemortality_carbonflux_si_pft => this%hvars(ih_firemortality_carbonflux_si_pft)%r82d, & + hio_crownarea_si_pft => this%hvars(ih_crownarea_si_pft)%r82d, & + hio_canopycrownarea_si_pft => this%hvars(ih_canopycrownarea_si_pft)%r82d, & + hio_gpp_si_pft => this%hvars(ih_gpp_si_pft)%r82d, & + hio_gpp_sec_si_pft => this%hvars(ih_gpp_sec_si_pft)%r82d, & + hio_npp_si_pft => this%hvars(ih_npp_si_pft)%r82d, & + hio_npp_sec_si_pft => this%hvars(ih_npp_sec_si_pft)%r82d, & + hio_fragmentation_scaler_sl => this%hvars(ih_fragmentation_scaler_sl)%r82d, & + hio_litter_in_elem => this%hvars(ih_litter_in_elem)%r82d, & + hio_litter_out_elem => this%hvars(ih_litter_out_elem)%r82d, & + hio_seed_bank_elem => this%hvars(ih_seed_bank_elem)%r82d, & + hio_seeds_in_local_elem => this%hvars(ih_seeds_in_local_elem)%r82d, & + hio_seed_in_extern_elem => this%hvars(ih_seeds_in_extern_elem)%r82d, & + hio_seed_decay_elem => this%hvars(ih_seed_decay_elem)%r82d, & + hio_seed_germ_elem => this%hvars(ih_seed_germ_elem)%r82d, & + hio_gpp_si_scpf => this%hvars(ih_gpp_si_scpf)%r82d, & + hio_npp_totl_si_scpf => this%hvars(ih_npp_totl_si_scpf)%r82d, & + hio_npp_leaf_si_scpf => this%hvars(ih_npp_leaf_si_scpf)%r82d, & + hio_npp_seed_si_scpf => this%hvars(ih_npp_seed_si_scpf)%r82d, & + hio_npp_fnrt_si_scpf => this%hvars(ih_npp_fnrt_si_scpf)%r82d, & + hio_npp_bgsw_si_scpf => this%hvars(ih_npp_bgsw_si_scpf)%r82d, & + hio_npp_bgdw_si_scpf => this%hvars(ih_npp_bgdw_si_scpf)%r82d, & + hio_npp_agsw_si_scpf => this%hvars(ih_npp_agsw_si_scpf)%r82d, & + hio_npp_agdw_si_scpf => this%hvars(ih_npp_agdw_si_scpf)%r82d, & + hio_npp_stor_si_scpf => this%hvars(ih_npp_stor_si_scpf)%r82d, & + hio_bstor_canopy_si_scpf => this%hvars(ih_bstor_canopy_si_scpf)%r82d, & + hio_bstor_understory_si_scpf => this%hvars(ih_bstor_understory_si_scpf)%r82d, & + hio_bleaf_canopy_si_scpf => this%hvars(ih_bleaf_canopy_si_scpf)%r82d, & + hio_bleaf_understory_si_scpf => this%hvars(ih_bleaf_understory_si_scpf)%r82d, & + hio_lai_canopy_si_scpf => this%hvars(ih_lai_canopy_si_scpf)%r82d, & + hio_lai_understory_si_scpf => this%hvars(ih_lai_understory_si_scpf)%r82d, & + hio_crownarea_canopy_si_scpf => this%hvars(ih_crownarea_canopy_si_scpf)%r82d, & + hio_crownarea_understory_si_scpf => this%hvars(ih_crownarea_understory_si_scpf)%r82d, & + hio_mortality_canopy_si_scpf => this%hvars(ih_mortality_canopy_si_scpf)%r82d, & + hio_mortality_canopy_secondary_si_scls => this%hvars(ih_mortality_canopy_secondary_si_scls)%r82d, & + hio_mortality_understory_si_scpf => this%hvars(ih_mortality_understory_si_scpf)%r82d, & + hio_m3_mortality_canopy_si_scpf => this%hvars(ih_m3_mortality_canopy_si_scpf)%r82d, & + hio_m3_mortality_understory_si_scpf => this%hvars(ih_m3_mortality_understory_si_scpf)%r82d, & + hio_m3_mortality_canopy_si_scls => this%hvars(ih_m3_mortality_canopy_si_scls)%r82d, & + hio_m3_mortality_understory_si_scls => this%hvars(ih_m3_mortality_understory_si_scls)%r82d, & + hio_nplant_canopy_si_scpf => this%hvars(ih_nplant_canopy_si_scpf)%r82d, & + hio_nplant_understory_si_scpf => this%hvars(ih_nplant_understory_si_scpf)%r82d, & + hio_ddbh_canopy_si_scpf => this%hvars(ih_ddbh_canopy_si_scpf)%r82d, & + hio_ddbh_understory_si_scpf => this%hvars(ih_ddbh_understory_si_scpf)%r82d, & + hio_ddbh_canopy_si_scls => this%hvars(ih_ddbh_canopy_si_scls)%r82d, & + hio_ddbh_understory_si_scls => this%hvars(ih_ddbh_understory_si_scls)%r82d, & + hio_gpp_canopy_si_scpf => this%hvars(ih_gpp_canopy_si_scpf)%r82d, & + hio_gpp_understory_si_scpf => this%hvars(ih_gpp_understory_si_scpf)%r82d, & + hio_ar_canopy_si_scpf => this%hvars(ih_ar_canopy_si_scpf)%r82d, & + hio_ar_understory_si_scpf => this%hvars(ih_ar_understory_si_scpf)%r82d, & + hio_ddbh_si_scpf => this%hvars(ih_ddbh_si_scpf)%r82d, & + hio_growthflux_si_scpf => this%hvars(ih_growthflux_si_scpf)%r82d, & + hio_growthflux_fusion_si_scpf => this%hvars(ih_growthflux_fusion_si_scpf)%r82d, & + hio_ba_si_scpf => this%hvars(ih_ba_si_scpf)%r82d, & + hio_agb_si_scpf => this%hvars(ih_agb_si_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_m1_si_scpf => this%hvars(ih_m1_si_scpf)%r82d, & + hio_m2_si_scpf => this%hvars(ih_m2_si_scpf)%r82d, & + hio_m3_si_scpf => this%hvars(ih_m3_si_scpf)%r82d, & + hio_m4_si_scpf => this%hvars(ih_m4_si_scpf)%r82d, & + hio_m5_si_scpf => this%hvars(ih_m5_si_scpf)%r82d, & + hio_m6_si_scpf => this%hvars(ih_m6_si_scpf)%r82d, & + hio_m7_si_scpf => this%hvars(ih_m7_si_scpf)%r82d, & + hio_m8_si_scpf => this%hvars(ih_m8_si_scpf)%r82d, & + hio_m9_si_scpf => this%hvars(ih_m9_si_scpf)%r82d, & + hio_m10_si_scpf => this%hvars(ih_m10_si_scpf)%r82d, & + hio_m10_si_capf => this%hvars(ih_m10_si_capf)%r82d, & + hio_crownfiremort_si_scpf => this%hvars(ih_crownfiremort_si_scpf)%r82d, & + hio_cambialfiremort_si_scpf => this%hvars(ih_cambialfiremort_si_scpf)%r82d, & + hio_abg_mortality_cflux_si_scpf => this%hvars(ih_abg_mortality_cflux_si_scpf)%r82d, & + hio_abg_productivity_cflux_si_scpf => this%hvars(ih_abg_productivity_cflux_si_scpf)%r82d, & + hio_burn_flux_elem => this%hvars(ih_burn_flux_elem)%r82d, & + hio_m1_si_scls => this%hvars(ih_m1_si_scls)%r82d, & + hio_m2_si_scls => this%hvars(ih_m2_si_scls)%r82d, & + hio_m3_si_scls => this%hvars(ih_m3_si_scls)%r82d, & + hio_m4_si_scls => this%hvars(ih_m4_si_scls)%r82d, & + hio_m5_si_scls => this%hvars(ih_m5_si_scls)%r82d, & + hio_m6_si_scls => this%hvars(ih_m6_si_scls)%r82d, & + hio_m7_si_scls => this%hvars(ih_m7_si_scls)%r82d, & + hio_m8_si_scls => this%hvars(ih_m8_si_scls)%r82d, & + hio_m9_si_scls => this%hvars(ih_m9_si_scls)%r82d, & + hio_m10_si_scls => this%hvars(ih_m10_si_scls)%r82d, & + hio_m10_si_cacls => this%hvars(ih_m10_si_cacls)%r82d) + + ! Break up associates for NAG compilers + associate(hio_m1_sec_si_scls => this%hvars(ih_m1_sec_si_scls)%r82d, & + hio_m2_sec_si_scls => this%hvars(ih_m2_sec_si_scls)%r82d, & + hio_m3_sec_si_scls => this%hvars(ih_m3_sec_si_scls)%r82d, & + hio_m7_sec_si_scls => this%hvars(ih_m7_sec_si_scls)%r82d, & + hio_m8_sec_si_scls => this%hvars(ih_m8_sec_si_scls)%r82d, & + hio_m9_sec_si_scls => this%hvars(ih_m9_sec_si_scls)%r82d, & + hio_m10_sec_si_scls => this%hvars(ih_m10_sec_si_scls)%r82d, & + hio_c13disc_si_scpf => this%hvars(ih_c13disc_si_scpf)%r82d, & + hio_cwd_elcwd => this%hvars(ih_cwd_elcwd)%r82d, & + 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_area_canopy_si_scls => this%hvars(ih_crown_area_canopy_si_scls)%r82d, & + hio_crown_area_understory_si_scls => this%hvars(ih_crown_area_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_nplant_si_scagpft => this%hvars(ih_nplant_si_scagpft)%r82d, & + hio_npp_si_agepft => this%hvars(ih_npp_si_agepft)%r82d, & + hio_biomass_si_agepft => this%hvars(ih_biomass_si_agepft)%r82d, & + hio_scorch_height_si_agepft => this%hvars(ih_scorch_height_si_agepft)%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_area_si_age => this%hvars(ih_area_si_age)%r82d, & + hio_lai_si_age => this%hvars(ih_lai_si_age)%r82d, & + hio_canopy_area_si_age => this%hvars(ih_canopy_area_si_age)%r82d, & + hio_ncl_si_age => this%hvars(ih_ncl_si_age)%r82d, & + hio_npatches_si_age => this%hvars(ih_npatches_si_age)%r82d, & + hio_zstar_si_age => this%hvars(ih_zstar_si_age)%r82d, & + hio_biomass_si_age => this%hvars(ih_biomass_si_age)%r82d, & + hio_agesince_anthrodist_si_age => this%hvars(ih_agesince_anthrodist_si_age)%r82d, & + hio_secondarylands_area_si_age => this%hvars(ih_secondarylands_area_si_age)%r82d, & + hio_area_si_landuse => this%hvars(ih_area_si_landuse)%r82d, & + hio_area_burnt_si_age => this%hvars(ih_area_burnt_si_age)%r82d, & + ! hio_fire_rate_of_spread_front_si_age => this%hvars(ih_fire_rate_of_spread_front_si_age)%r82d, & + hio_fire_intensity_si_age => this%hvars(ih_fire_intensity_si_age)%r82d, & + hio_fire_sum_fuel_si_age => this%hvars(ih_fire_sum_fuel_si_age)%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_fuel_amount_age_fuel => this%hvars(ih_fuel_amount_age_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, & + hio_nplant_si_scag => this%hvars(ih_nplant_si_scag)%r82d, & + hio_nplant_canopy_si_scag => this%hvars(ih_nplant_canopy_si_scag)%r82d, & + hio_nplant_understory_si_scag => this%hvars(ih_nplant_understory_si_scag)%r82d, & + hio_ddbh_canopy_si_scag => this%hvars(ih_ddbh_canopy_si_scag)%r82d, & + hio_ddbh_understory_si_scag => this%hvars(ih_ddbh_understory_si_scag)%r82d, & + hio_mortality_canopy_si_scag => this%hvars(ih_mortality_canopy_si_scag)%r82d, & + hio_mortality_understory_si_scag => this%hvars(ih_mortality_understory_si_scag)%r82d ) + + ! 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_nplant_si_scag => this%hvars(ih_nplant_si_scag)%r82d, & + hio_nplant_canopy_si_scag => this%hvars(ih_nplant_canopy_si_scag)%r82d, & + hio_nplant_understory_si_scag => this%hvars(ih_nplant_understory_si_scag)%r82d, & + hio_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) + + 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 - hio_ca_weighted_height_si(io_si) = hio_ca_weighted_height_si(io_si) + & - ccohort%height * ccohort%c_area / m2_per_ha - else canlayer - hio_nplant_understory_si_scag(io_si,iscag) = hio_nplant_understory_si_scag(io_si,iscag) + ccohort%n / m2_per_ha - hio_mortality_understory_si_scag(io_si,iscag) = hio_mortality_understory_si_scag(io_si,iscag) + & - (ccohort%bmort + ccohort%hmort + ccohort%cmort + & - ccohort%frmort + ccohort%smort + ccohort%asmort + ccohort%dgmort) * ccohort%n / m2_per_ha - hio_ddbh_understory_si_scag(io_si,iscag) = hio_ddbh_understory_si_scag(io_si,iscag) + & - ccohort%ddbhdt*ccohort%n * m_per_cm / m2_per_ha - hio_bstor_understory_si_scpf(io_si,scpf) = hio_bstor_understory_si_scpf(io_si,scpf) + & - 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_understory_biomass_si(io_si) = hio_understory_biomass_si(io_si) + & - n_perm2 * total_m - hio_lai_understory_si_scpf(io_si,scpf) = hio_lai_understory_si_scpf(io_si,scpf) + & - ccohort%treelai*ccohort%c_area * AREA_INV - - !hio_mortality_understory_si_scpf(io_si,scpf) = hio_mortality_understory_si_scpf(io_si,scpf)+ & - ! (ccohort%bmort + ccohort%hmort + ccohort%cmort + - ! 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%bmort + ccohort%hmort + ccohort%cmort + & - ccohort%frmort + ccohort%smort + ccohort%asmort + ccohort%dgmort) * ccohort%n / m2_per_ha + & - (ccohort%lmort_direct + ccohort%lmort_collateral + ccohort%lmort_infra) * & - ccohort%n * sec_per_day * days_per_year / m2_per_ha - - 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 + ! Total model error [kg/day -> kg/s] (all elements) + hio_err_fates_elem(io_si,el) = sites(s)%mass_balance(el)%err_fates / sec_per_day - hio_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_area_understory_si_scls(io_si,scls) = hio_crown_area_understory_si_scls(io_si,scls) + & - ccohort%c_area / m2_per_ha - 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_acc_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%bmort + ccohort%hmort + ccohort%cmort + & - ccohort%frmort + ccohort%smort + ccohort%asmort + ccohort%dgmort) * ccohort%n / m2_per_ha + & - (ccohort%lmort_direct + ccohort%lmort_collateral + ccohort%lmort_infra) * & - ccohort%n * sec_per_day * days_per_year / m2_per_ha - - hio_m3_mortality_understory_si_scls(io_si,scls) = hio_m3_mortality_understory_si_scls(io_si,scls) + & - ccohort%cmort * ccohort%n / m2_per_ha - - hio_understory_mortality_carbonflux_si(io_si) = hio_understory_mortality_carbonflux_si(io_si) + & - (ccohort%bmort + ccohort%hmort + ccohort%cmort + & - ccohort%frmort + ccohort%smort + ccohort%asmort + ccohort%dgmort) * & - total_m * ccohort%n * days_per_sec * years_per_day * ha_per_m2 + & - (ccohort%lmort_direct + ccohort%lmort_collateral + ccohort%lmort_infra) * total_m * & - ccohort%n * ha_per_m2 - - hio_understory_mortality_crownarea_si(io_si) = hio_understory_mortality_crownarea_si(io_si) + & - (ccohort%bmort + ccohort%hmort + ccohort%cmort + & - ccohort%frmort + ccohort%smort + ccohort%asmort + ccohort%dgmort) * & - ccohort%c_area + & - (ccohort%lmort_direct + ccohort%lmort_collateral + ccohort%lmort_infra) * & - ccohort%c_area * sec_per_day * days_per_year - - hio_carbon_balance_understory_si_scls(io_si,scls) = hio_carbon_balance_understory_si_scls(io_si,scls) + & - ccohort%npp_acc_hold * ccohort%n / m2_per_ha / days_per_year / sec_per_day - - ! damage variables - understory - if(hlm_use_tree_damage .eq. itrue) then - - ! carbon mortality in the understory by damage x size x pft - this%hvars(ih_m3_mortality_understory_si_cdpf)%r82d(io_si,cdpf) = & - this%hvars(ih_m3_mortality_understory_si_cdpf)%r82d(io_si,cdpf) + & - ccohort%cmort * ccohort%n / m2_per_ha - - ! damage in the understory by damage x size x pft - this%hvars(ih_m11_mortality_understory_si_cdpf)%r82d(io_si,cdpf) = & - this%hvars(ih_m11_mortality_understory_si_cdpf)%r82d(io_si,cdpf) + & - ccohort%dgmort * ccohort%n / m2_per_ha - - ! total mortality of understory cohorts by damage x size x pft - this%hvars(ih_mortality_understory_si_cdpf)%r82d(io_si,cdpf) = & - this%hvars(ih_mortality_understory_si_cdpf)%r82d(io_si,cdpf) + & - (ccohort%bmort + ccohort%hmort + ccohort%cmort + ccohort%frmort + & - ccohort%smort + ccohort%asmort + ccohort%dgmort) * ccohort%n / m2_per_ha + & - (ccohort%lmort_direct + ccohort%lmort_collateral + ccohort%lmort_infra) * & - ccohort%n * sec_per_day * days_per_year / m2_per_ha - - this%hvars(ih_nplant_understory_si_cdpf)%r82d(io_si,cdpf) = & - this%hvars(ih_nplant_understory_si_cdpf)%r82d(io_si,cdpf) + & - ccohort%n / m2_per_ha - - ! growth rate by size x damage x pft - understory - this%hvars(ih_ddbh_understory_si_cdpf)%r82d(io_si,cdpf) = & - this%hvars(ih_ddbh_understory_si_cdpf)%r82d(io_si,cdpf) + & - ccohort%ddbhdt*ccohort%n / m2_per_ha * m_per_cm - - end if ! end if damage - - hio_leaf_md_understory_si_scls(io_si,scls) = hio_leaf_md_understory_si_scls(io_si,scls) + & - leaf_m_turnover * ccohort%n / m2_per_ha / days_per_year / sec_per_day - 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 / days_per_year / 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_si_can(io_si, ican) = hio_crownarea_si_can(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 + ! 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 - ccohort => ccohort%taller - enddo cohortloop ! cohort loop - - ! 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_effect_wspeed_si(io_si) = hio_effect_wspeed_si(io_si) + cpatch%effect_wspeed * 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_area_si(io_si) = hio_fire_area_si(io_si) + cpatch%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_bulkd * cpatch%area * AREA_INV - hio_fire_fuel_eff_moist_si(io_si) = hio_fire_fuel_eff_moist_si(io_si) + cpatch%fuel_eff_moist * cpatch%area * AREA_INV - hio_fire_fuel_sav_si(io_si) = hio_fire_fuel_sav_si(io_si) + cpatch%fuel_sav * cpatch%area * AREA_INV / m_per_cm - hio_fire_fuel_mef_si(io_si) = hio_fire_fuel_mef_si(io_si) + cpatch%fuel_mef * cpatch%area * AREA_INV - hio_sum_fuel_si(io_si) = hio_sum_fuel_si(io_si) + cpatch%sum_fuel * cpatch%area * AREA_INV - - 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 + end do - do i_fuel = 1,nfsc - i_agefuel = get_agefuel_class_index(cpatch%age,i_fuel) - hio_fuel_amount_age_fuel(io_si,i_agefuel) = hio_fuel_amount_age_fuel(io_si,i_agefuel) + & - cpatch%fuel_frac(i_fuel) * cpatch%sum_fuel * cpatch%area * AREA_INV + ! 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) - hio_litter_moisture_si_fuel(io_si, i_fuel) = hio_litter_moisture_si_fuel(io_si, i_fuel) + & - cpatch%litter_moisture(i_fuel) * cpatch%area * AREA_INV + ! 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_fuel_amount_si_fuel(io_si, i_fuel) = hio_fuel_amount_si_fuel(io_si, i_fuel) + & - cpatch%fuel_frac(i_fuel) * cpatch%sum_fuel * 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) - hio_burnt_frac_litter_si_fuel(io_si, i_fuel) = hio_burnt_frac_litter_si_fuel(io_si, i_fuel) + & - cpatch%burnt_frac_litter(i_fuel) * cpatch%frac_burnt * cpatch%area * AREA_INV - end do + 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 - hio_fire_intensity_area_product_si(io_si) = hio_fire_intensity_area_product_si(io_si) + & - cpatch%FI * cpatch%frac_burnt * cpatch%area * AREA_INV * J_per_kJ + ! Loop through patches to sum up diagonistics + ipa = 0 + cpatch => sites(s)%oldest_patch + patchloop: do while(associated(cpatch)) - ! Update Litter Flux Variables - litt_c => cpatch%litter(element_pos(carbon12_element)) - + cpatch%age_class = get_age_class_index(cpatch%age) - do i_cwd = 1, ncwd + ! Increment the fractional area in each age class bin + hio_area_si_age(io_si,cpatch%age_class) = hio_area_si_age(io_si,cpatch%age_class) & + + cpatch%area * AREA_INV - 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 + ! ignore land use info on nocomp bareground (where landuse label = 0) + if (cpatch%land_use_label .gt. nocomp_bareground_land) then + hio_area_si_landuse(io_si, cpatch%land_use_label) = & + hio_area_si_landuse(io_si, cpatch%land_use_label) & + + cpatch%area * AREA_INV + end if + + ! Increment some patch-age-resolved diagnostics + hio_lai_si_age(io_si,cpatch%age_class) = hio_lai_si_age(io_si,cpatch%age_class) & + + sum(cpatch%tlai_profile(:,:,:) * cpatch%canopy_area_profile(:,:,:) ) * cpatch%total_canopy_area + + hio_ncl_si_age(io_si,cpatch%age_class) = hio_ncl_si_age(io_si,cpatch%age_class) & + + cpatch%ncl_p * cpatch%area + + hio_npatches_si_age(io_si,cpatch%age_class) = hio_npatches_si_age(io_si,cpatch%age_class) + 1._r8 - hio_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 + if ( ED_val_comp_excln .lt. 0._r8 ) then ! only valid when "strict ppa" enabled + hio_zstar_si_age(io_si,cpatch%age_class) = hio_zstar_si_age(io_si,cpatch%age_class) & + + cpatch%zstar * cpatch%area * AREA_INV + endif + + ! some diagnostics on secondary forest area and its age distribution + if ( cpatch%land_use_label .eq. secondaryland ) then + + ageclass_since_anthrodist = get_age_class_index(cpatch%age_since_anthro_disturbance) + + hio_agesince_anthrodist_si_age(io_si,ageclass_since_anthrodist) = & + hio_agesince_anthrodist_si_age(io_si,ageclass_since_anthrodist) & + + cpatch%area * AREA_INV + + hio_secondarylands_area_si_age(io_si,cpatch%age_class) = & + hio_secondarylands_area_si_age(io_si,cpatch%age_class) & + + cpatch%area * AREA_INV + endif - ipa = ipa + 1 - cpatch => cpatch%younger - end do patchloop !patch loop + + ! patch-age-resolved fire variables + do ft = 1,numpft + ! for scorch height, weight the value by patch area within any + ! given age class - in the event that there is more than one + ! patch per age class. + iagepft = cpatch%age_class + (ft-1) * nlevage + hio_scorch_height_si_agepft(io_si,iagepft) = hio_scorch_height_si_agepft(io_si,iagepft) + & + cpatch%Scorch_ht(ft) * cpatch%area + + ! 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 + + this%hvars(ih_nocomp_pftnpatches_si_pft)%r82d(io_si,ft) = & + this%hvars(ih_nocomp_pftnpatches_si_pft)%r82d(io_si,ft) + 1._r8 + + 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 + + end do + + ! fractional area burnt [frac/day] -> [frac/sec] + hio_area_burnt_si_age(io_si,cpatch%age_class) = hio_area_burnt_si_age(io_si,cpatch%age_class) + & + cpatch%frac_burnt * cpatch%area * AREA_INV / sec_per_day + + ! 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 * cpatch%area * AREA_INV + + ! Fire intensity weighted by burned fraction [kJ/m/s] -> [J/m/s] + hio_fire_intensity_si_age(io_si, cpatch%age_class) = hio_fire_intensity_si_age(io_si, cpatch%age_class) + & + cpatch%FI * cpatch%frac_burnt * cpatch%area * AREA_INV * J_per_kJ + + ! Fuel sum [kg/m2] + hio_fire_sum_fuel_si_age(io_si, cpatch%age_class) = hio_fire_sum_fuel_si_age(io_si, cpatch%age_class) + & + cpatch%sum_fuel * cpatch%area * AREA_INV + + + + ! 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_area_si_age(io_si,cpatch%age_class) = hio_canopy_area_si_age(io_si,cpatch%age_class) & + + ccohort%c_area * AREA_INV + + ! calculate leaf height distribution, assuming leaf area is evenly distributed thru crown depth + call CrownDepth(ccohort%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 + + sapw_m = ccohort%prt%GetState(sapw_organ, element_list(el)) + struct_m = ccohort%prt%GetState(struct_organ, element_list(el)) + leaf_m = ccohort%prt%GetState(leaf_organ, element_list(el)) + fnrt_m = ccohort%prt%GetState(fnrt_organ, element_list(el)) + store_m = ccohort%prt%GetState(store_organ, element_list(el)) + repro_m = ccohort%prt%GetState(repro_organ, element_list(el)) + alive_m = leaf_m + fnrt_m + sapw_m + total_m = alive_m + store_m + struct_m + + i_scpf = ccohort%size_by_pft_class + + + ! Plant multi-element states and fluxes + ! Zero states, and set the fluxes + if( element_list(el).eq.carbon12_element )then + + 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 ( cpatch%land_use_label .eq. secondaryland ) then + hio_nindivs_sec_si_pft(io_si,ft) = hio_nindivs_sec_si_pft(io_si,ft) + & + ccohort%n * AREA_INV + hio_biomass_sec_si_pft(io_si, ft) = hio_biomass_sec_si_pft(io_si, ft) + & + (ccohort%n * AREA_INV) * total_m + end if + + 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 + + ! update total biomass per age bin + hio_biomass_si_age(io_si,cpatch%age_class) = hio_biomass_si_age(io_si,cpatch%age_class) & + + total_m * ccohort%n * AREA_INV + + 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 .eq. secondaryland ) then + hio_gpp_sec_si_pft(io_si, ft) = hio_gpp_sec_si_pft(io_si, ft) + & + ccohort%gpp_acc_hold * n_perm2 / (days_per_year*sec_per_day) + hio_npp_sec_si_pft(io_si, ft) = hio_npp_sec_si_pft(io_si, ft) + & + ccohort%npp_acc_hold * n_perm2 / (days_per_year*sec_per_day) + end if + + ! 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 + + 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 + + ! Examine secondary forest mortality and mortality rates + if(cpatch%land_use_label .eq. secondaryland) then + if (hlm_use_cohort_age_tracking .eq.itrue) then + hio_m10_sec_si_scls(io_si,scls) = hio_m10_sec_si_scls(io_si,scls) + & + ccohort%asmort*ccohort%n / m2_per_ha + end if + + hio_m1_sec_si_scls(io_si,scls) = hio_m1_sec_si_scls(io_si,scls) + ccohort%bmort*ccohort%n / m2_per_ha + hio_m2_sec_si_scls(io_si,scls) = hio_m2_sec_si_scls(io_si,scls) + ccohort%hmort*ccohort%n / m2_per_ha + hio_m3_sec_si_scls(io_si,scls) = hio_m3_sec_si_scls(io_si,scls) + ccohort%cmort*ccohort%n / m2_per_ha + hio_m7_sec_si_scls(io_si,scls) = hio_m7_sec_si_scls(io_si,scls) + & + (ccohort%lmort_direct+ccohort%lmort_collateral+ccohort%lmort_infra) * ccohort%n / m2_per_ha + hio_m8_sec_si_scls(io_si,scls) = hio_m8_sec_si_scls(io_si,scls) + & + ccohort%frmort*ccohort%n / m2_per_ha + hio_m9_sec_si_scls(io_si,scls) = hio_m9_sec_si_scls(io_si,scls) + ccohort%smort*ccohort%n / m2_per_ha + end if + + !C13 discrimination + if(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%bmort + ccohort%hmort + ccohort%cmort + ccohort%frmort + & + ccohort%smort + ccohort%asmort + ccohort%dgmort) * ccohort%n / m2_per_ha + & + (ccohort%lmort_direct + ccohort%lmort_collateral + ccohort%lmort_infra) * & + ccohort%n * sec_per_day * days_per_year / m2_per_ha + + ! crown damage by size by pft + this%hvars(ih_nplant_si_cdpf)%r82d(io_si, 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 + sapw_m = ccohort%prt%GetState(sapw_organ, carbon12_element) + struct_m = ccohort%prt%GetState(struct_organ, carbon12_element) + leaf_m = ccohort%prt%GetState(leaf_organ, carbon12_element) + fnrt_m = ccohort%prt%GetState(fnrt_organ, carbon12_element) + store_m = ccohort%prt%GetState(store_organ, carbon12_element) + repro_m = ccohort%prt%GetState(repro_organ, carbon12_element) + alive_m = leaf_m + fnrt_m + sapw_m + total_m = alive_m + store_m + struct_m + + hio_mortality_carbonflux_si_pft(io_si,ccohort%pft) = hio_mortality_carbonflux_si_pft(io_si,ccohort%pft) + & + (ccohort%bmort + ccohort%hmort + ccohort%cmort + & + ccohort%frmort + ccohort%smort + ccohort%asmort + ccohort%dgmort) * & + total_m * ccohort%n * days_per_sec * years_per_day * ha_per_m2 + & + (ccohort%lmort_direct + ccohort%lmort_collateral + ccohort%lmort_infra) * total_m * & + ccohort%n * ha_per_m2 + + + hio_hydraulicmortality_carbonflux_si_pft(io_si,ccohort%pft) = & + hio_hydraulicmortality_carbonflux_si_pft(io_si,ccohort%pft) + & + ccohort%hmort * total_m * ccohort%n * days_per_sec * years_per_day * ha_per_m2 + + hio_cstarvmortality_carbonflux_si_pft(io_si,ccohort%pft) = & + hio_cstarvmortality_carbonflux_si_pft(io_si,ccohort%pft) + & + ccohort%cmort * total_m * ccohort%n * days_per_sec * years_per_day * ha_per_m2 + + 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 x patch-age related quantities + + iscag = get_sizeage_class_index(ccohort%dbh,cpatch%age) + + hio_nplant_si_scag(io_si,iscag) = hio_nplant_si_scag(io_si,iscag) + ccohort%n / m2_per_ha + + hio_nplant_si_scls(io_si,scls) = hio_nplant_si_scls(io_si,scls) + ccohort%n / m2_per_ha + + + ! update size, age, and PFT - indexed quantities + iscagpft = get_sizeagepft_class_index(ccohort%dbh,cpatch%age,ccohort%pft) + + hio_nplant_si_scagpft(io_si,iscagpft) = hio_nplant_si_scagpft(io_si,iscagpft) + ccohort%n / m2_per_ha + + ! update age and PFT - indexed quantities + iagepft = get_agepft_class_index(cpatch%age,ccohort%pft) + + hio_npp_si_agepft(io_si,iagepft) = hio_npp_si_agepft(io_si,iagepft) + & + ccohort%n * ccohort%npp_acc_hold * AREA_INV / days_per_year / sec_per_day + + hio_biomass_si_agepft(io_si,iagepft) = hio_biomass_si_agepft(io_si,iagepft) + & + total_m * ccohort%n * AREA_INV + + ! update SCPF/SCLS- and canopy/subcanopy- partitioned quantities + canlayer: if (ccohort%canopy_layer .eq. 1) then + hio_nplant_canopy_si_scag(io_si,iscag) = hio_nplant_canopy_si_scag(io_si,iscag) + ccohort%n / m2_per_ha + hio_mortality_canopy_si_scag(io_si,iscag) = hio_mortality_canopy_si_scag(io_si,iscag) + & + (ccohort%bmort + ccohort%hmort + ccohort%cmort + & + ccohort%frmort + ccohort%smort + ccohort%asmort + ccohort%dgmort) * ccohort%n / m2_per_ha + hio_ddbh_canopy_si_scag(io_si,iscag) = hio_ddbh_canopy_si_scag(io_si,iscag) + & + ccohort%ddbhdt*ccohort%n * m_per_cm / m2_per_ha + hio_bstor_canopy_si_scpf(io_si,scpf) = hio_bstor_canopy_si_scpf(io_si,scpf) + & + store_m * ccohort%n / m2_per_ha + hio_bleaf_canopy_si_scpf(io_si,scpf) = hio_bleaf_canopy_si_scpf(io_si,scpf) + & + leaf_m * ccohort%n / m2_per_ha + hio_lai_canopy_si_scpf(io_si,scpf) = hio_lai_canopy_si_scpf(io_si,scpf) + & + ccohort%treelai*ccohort%c_area * AREA_INV + + hio_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%bmort + ccohort%hmort + ccohort%cmort + ccohort%frmort + & + ccohort%smort + ccohort%asmort + ccohort%dgmort) * ccohort%n / m2_per_ha + & + (ccohort%lmort_direct + ccohort%lmort_collateral + ccohort%lmort_infra) * & + ccohort%n * sec_per_day * days_per_year / m2_per_ha + + 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_area_canopy_si_scls(io_si,scls) = hio_crown_area_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_acc_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%bmort + ccohort%hmort + ccohort%cmort + & + ccohort%frmort + ccohort%smort + ccohort%asmort + ccohort%dgmort) * ccohort%n / m2_per_ha + & + (ccohort%lmort_direct + ccohort%lmort_collateral + ccohort%lmort_infra) * & + ccohort%n * sec_per_day * days_per_year / m2_per_ha + + 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%bmort + ccohort%hmort + ccohort%cmort + ccohort%frmort + ccohort%smort + & + ccohort%asmort + ccohort%dgmort) * ccohort%n / m2_per_ha + & + (ccohort%lmort_direct + ccohort%lmort_collateral + ccohort%lmort_infra) * & + ccohort%n * sec_per_day * days_per_year / m2_per_ha + + ! nplants by damage + this%hvars(ih_nplant_canopy_si_cdpf)%r82d(io_si,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 / days_per_year / 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_nplant_understory_si_scag(io_si,iscag) = hio_nplant_understory_si_scag(io_si,iscag) + ccohort%n / m2_per_ha + hio_mortality_understory_si_scag(io_si,iscag) = hio_mortality_understory_si_scag(io_si,iscag) + & + (ccohort%bmort + ccohort%hmort + ccohort%cmort + & + ccohort%frmort + ccohort%smort + ccohort%asmort + ccohort%dgmort) * ccohort%n / m2_per_ha + hio_ddbh_understory_si_scag(io_si,iscag) = hio_ddbh_understory_si_scag(io_si,iscag) + & + ccohort%ddbhdt*ccohort%n * m_per_cm / m2_per_ha + hio_bstor_understory_si_scpf(io_si,scpf) = hio_bstor_understory_si_scpf(io_si,scpf) + & + 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%bmort + ccohort%hmort + ccohort%cmort + & + ccohort%frmort + ccohort%smort + ccohort%asmort + ccohort%dgmort) * ccohort%n / m2_per_ha + & + (ccohort%lmort_direct + ccohort%lmort_collateral + ccohort%lmort_infra) * & + ccohort%n * sec_per_day * days_per_year / m2_per_ha + + 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_area_understory_si_scls(io_si,scls) = hio_crown_area_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_acc_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%bmort + ccohort%hmort + ccohort%cmort + & + ccohort%frmort + ccohort%smort + ccohort%asmort + ccohort%dgmort) * ccohort%n / m2_per_ha + & + (ccohort%lmort_direct + ccohort%lmort_collateral + ccohort%lmort_infra) * & + ccohort%n * sec_per_day * days_per_year / m2_per_ha + + 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%bmort + ccohort%hmort + ccohort%cmort + ccohort%frmort + & + ccohort%smort + ccohort%asmort + ccohort%dgmort) * ccohort%n / m2_per_ha + & + (ccohort%lmort_direct + ccohort%lmort_collateral + ccohort%lmort_infra) * & + ccohort%n * sec_per_day * days_per_year / m2_per_ha + + this%hvars(ih_nplant_understory_si_cdpf)%r82d(io_si,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 / days_per_year / 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,nfsc + + i_agefuel = get_agefuel_class_index(cpatch%age,i_fuel) + hio_fuel_amount_age_fuel(io_si,i_agefuel) = hio_fuel_amount_age_fuel(io_si,i_agefuel) + & + cpatch%fuel_frac(i_fuel) * cpatch%sum_fuel * cpatch%area * AREA_INV + + hio_litter_moisture_si_fuel(io_si, i_fuel) = hio_litter_moisture_si_fuel(io_si, i_fuel) + & + cpatch%litter_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(i_fuel) * cpatch%sum_fuel * 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%burnt_frac_litter(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_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 + + ipa = ipa + 1 + cpatch => cpatch%younger + end do patchloop !patch loop + + + + + ! divide so-far-just-summed but to-be-averaged patch-age-class + ! variables by patch-age-class area to get mean values + do ipa2 = 1, nlevage + if (hio_area_si_age(io_si, ipa2) .gt. nearzero) then + hio_lai_si_age(io_si, ipa2) = hio_lai_si_age(io_si, ipa2) / (hio_area_si_age(io_si, ipa2)*AREA) + hio_ncl_si_age(io_si, ipa2) = hio_ncl_si_age(io_si, ipa2) / (hio_area_si_age(io_si, ipa2)*AREA) + do ft = 1, numpft + iagepft = ipa2 + (ft-1) * nlevage + hio_scorch_height_si_agepft(io_si, iagepft) = & + hio_scorch_height_si_agepft(io_si, iagepft) / (hio_area_si_age(io_si, ipa2)*AREA) + enddo + else + hio_lai_si_age(io_si, ipa2) = 0._r8 + hio_ncl_si_age(io_si, ipa2) = 0._r8 + endif + end do + + + + ! 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 + ! + iscag = i_scls ! since imort is by definition something that only happens in newly disturbed patches, treat as such + hio_mortality_understory_si_scag(io_si,iscag) = hio_mortality_understory_si_scag(io_si,iscag) + & + sites(s)%imort_rate(i_scls, ft) / m2_per_ha + + ! fire mortality from the site-level diagnostic rates + hio_m5_si_scpf(io_si,i_scpf) = (sites(s)%fmort_rate_canopy(i_scls, ft) + & + sites(s)%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)%fmort_rate_canopy(i_scls, ft) + & + sites(s)%fmort_rate_ustory(i_scls, ft)) / m2_per_ha + ! + hio_crownfiremort_si_scpf(io_si,i_scpf) = sites(s)%fmort_rate_crown(i_scls, ft) / m2_per_ha + hio_cambialfiremort_si_scpf(io_si,i_scpf) = sites(s)%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 + + ! Shijie: Think about how to add later? + !if ( cpatch%land_use_label .eq. secondaryland ) then + ! hio_mortality_canopy_secondary_si_scls(io_si,i_scls) = hio_mortality_canopy_secondary_si_scls(io_si,i_scls) + & + ! sites(s)%term_nindivs_canopy(i_scls,ft) * days_per_year / m2_per_ha + !end if + + ! the fire mortality rates for each layer are total dead, since the usable + ! output will then normalize by the counts, we are allowed to sum over layers + hio_mortality_understory_si_scpf(io_si,i_scpf) = hio_mortality_understory_si_scpf(io_si,i_scpf) + & + 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 + + ! + ! for scag variables, also treat as happening in the newly-disurbed patch + + hio_mortality_canopy_si_scag(io_si,iscag) = hio_mortality_canopy_si_scag(io_si,iscag) + & + sites(s)%fmort_rate_canopy(i_scls, ft) / m2_per_ha + hio_mortality_understory_si_scag(io_si,iscag) = hio_mortality_understory_si_scag(io_si,iscag) + & + 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) / 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 + 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)%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 + + ! 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) + + 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) + ! ------------------------------------------------------------------------------ + + flux_diags_c => sites(s)%flux_diags(element_pos(carbon12_element)) + + ! ------------------------------------------------------------------------------ + ! Diagnostics discretized by element type + ! ------------------------------------------------------------------------------ + + do el = 1, num_elements + + flux_diags => sites(s)%flux_diags(el) + + ! Sum up all input litter fluxes (above below, fines, cwd) [kg/ha/day] + hio_litter_in_elem(io_si, el) = (sum(flux_diags%cwd_ag_input(:)) + & + sum(flux_diags%cwd_bg_input(:)) + sum(flux_diags%leaf_litter_input(:)) + & + sum(flux_diags%root_litter_input(:))) / m2_per_ha / sec_per_day + + + ! 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) + + area_frac = 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)) + + sapw_m = ccohort%prt%GetState(sapw_organ, element_list(el)) + struct_m = ccohort%prt%GetState(struct_organ, element_list(el)) + leaf_m = ccohort%prt%GetState(leaf_organ, element_list(el)) + fnrt_m = ccohort%prt%GetState(fnrt_organ, element_list(el)) + store_m = ccohort%prt%GetState(store_organ, element_list(el)) + repro_m = ccohort%prt%GetState(repro_organ, element_list(el)) + total_m = sapw_m+struct_m+leaf_m+fnrt_m+store_m+repro_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) + & + flux_diags_c%cwd_ag_input(i_cwd) / days_per_year / sec_per_day + + hio_cwd_bg_in_si_cwdsc(io_si, i_cwd) = hio_cwd_bg_in_si_cwdsc(io_si, i_cwd) + & + flux_diags_c%cwd_bg_input(i_cwd) / days_per_year / sec_per_day + + 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 + + return + end subroutine update_history_dyn2 + + ! =============================================================================================== + + 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 - ! divide basal-area-weighted height by basal area to get mean - if ( sum(hio_ba_si_scpf(io_si,:)) .gt. nearzero ) then - hio_ba_weighted_height_si(io_si) = hio_ba_weighted_height_si(io_si) / sum(hio_ba_si_scpf(io_si,:)) - else - hio_ba_weighted_height_si(io_si) = 0._r8 - endif - - ! divide so-far-just-summed but to-be-averaged patch-age-class - ! variables by patch-age-class area to get mean values - do ipa2 = 1, nlevage - if (hio_area_si_age(io_si, ipa2) .gt. nearzero) then - hio_lai_si_age(io_si, ipa2) = hio_lai_si_age(io_si, ipa2) / (hio_area_si_age(io_si, ipa2)*AREA) - hio_ncl_si_age(io_si, ipa2) = hio_ncl_si_age(io_si, ipa2) / (hio_area_si_age(io_si, ipa2)*AREA) - do i_pft = 1, numpft - iagepft = ipa2 + (i_pft-1) * nlevage - hio_scorch_height_si_agepft(io_si, iagepft) = & - hio_scorch_height_si_agepft(io_si, iagepft) / (hio_area_si_age(io_si, ipa2)*AREA) - enddo - else - hio_lai_si_age(io_si, ipa2) = 0._r8 - hio_ncl_si_age(io_si, ipa2) = 0._r8 - endif - end do - - ! divide secondary plant leaf area by secondary forest area to get the secondary forest LAI - if (hio_fraction_secondary_forest_si(io_si) .gt. nearzero) then - hio_lai_secondary_si(io_si) = hio_lai_secondary_si(io_si) / (hio_fraction_secondary_forest_si(io_si)*AREA) - else - hio_lai_secondary_si(io_si) = 0._r8 - end if - - ! pass the cohort termination mortality as a flux to the history, and then reset the termination mortality buffer - ! note there are various ways of reporting the total mortality, so pass to these as well - do i_pft = 1, numpft - do i_scls = 1,nlevsclass - i_scpf = (i_pft-1)*nlevsclass + i_scls - ! - ! termination mortality. sum of canopy and understory indices - hio_m6_si_scpf(io_si,i_scpf) = (sites(s)%term_nindivs_canopy(i_scls,i_pft) + & - sites(s)%term_nindivs_ustory(i_scls,i_pft)) * & - days_per_year / m2_per_ha - - hio_m6_si_scls(io_si,i_scls) = hio_m6_si_scls(io_si,i_scls) + & - (sites(s)%term_nindivs_canopy(i_scls,i_pft) + & - sites(s)%term_nindivs_ustory(i_scls,i_pft)) * & - 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) + & - sites(s)%term_nindivs_canopy(i_scls,i_pft) * days_per_year / m2_per_ha - - hio_mortality_understory_si_scls(io_si,i_scls) = hio_mortality_understory_si_scls(io_si,i_scls) + & - sites(s)%term_nindivs_ustory(i_scls,i_pft) * days_per_year / m2_per_ha - - hio_mortality_canopy_si_scpf(io_si,i_scpf) = hio_mortality_canopy_si_scpf(io_si,i_scpf) + & - sites(s)%term_nindivs_canopy(i_scls,i_pft) * days_per_year / m2_per_ha - - hio_mortality_understory_si_scpf(io_si,i_scpf) = hio_mortality_understory_si_scpf(io_si,i_scpf) + & - sites(s)%term_nindivs_ustory(i_scls,i_pft) * days_per_year / m2_per_ha - - ! - ! imort on its own - hio_m4_si_scpf(io_si,i_scpf) = sites(s)%imort_rate(i_scls, i_pft) / 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, i_pft) / 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, i_pft) / 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, i_pft) / m2_per_ha - ! - iscag = i_scls ! since imort is by definition something that only happens in newly disturbed patches, treat as such - hio_mortality_understory_si_scag(io_si,iscag) = hio_mortality_understory_si_scag(io_si,iscag) + & - sites(s)%imort_rate(i_scls, i_pft) / m2_per_ha - - ! fire mortality from the site-level diagnostic rates - hio_m5_si_scpf(io_si,i_scpf) = (sites(s)%fmort_rate_canopy(i_scls, i_pft) + & - sites(s)%fmort_rate_ustory(i_scls, i_pft)) / m2_per_ha - hio_m5_si_scls(io_si,i_scls) = hio_m5_si_scls(io_si,i_scls) + & - (sites(s)%fmort_rate_canopy(i_scls, i_pft) + & - sites(s)%fmort_rate_ustory(i_scls, i_pft)) / m2_per_ha - ! - hio_crownfiremort_si_scpf(io_si,i_scpf) = sites(s)%fmort_rate_crown(i_scls, i_pft) / m2_per_ha - hio_cambialfiremort_si_scpf(io_si,i_scpf) = sites(s)%fmort_rate_cambial(i_scls, i_pft) / 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, i_pft) / 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, i_pft) / m2_per_ha - - ! Shijie: Think about how to add later? - !if ( cpatch%land_use_label .eq. secondaryland ) then - ! hio_mortality_canopy_secondary_si_scls(io_si,i_scls) = hio_mortality_canopy_secondary_si_scls(io_si,i_scls) + & - ! sites(s)%term_nindivs_canopy(i_scls,i_pft) * days_per_year / m2_per_ha - !end if - - ! the fire mortality rates for each layer are total dead, since the usable - ! output will then normalize by the counts, we are allowed to sum over layers - hio_mortality_understory_si_scpf(io_si,i_scpf) = hio_mortality_understory_si_scpf(io_si,i_scpf) + & - sites(s)%fmort_rate_ustory(i_scls, i_pft) / 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, i_pft) / m2_per_ha - - ! - ! for scag variables, also treat as happening in the newly-disurbed patch - - hio_mortality_canopy_si_scag(io_si,iscag) = hio_mortality_canopy_si_scag(io_si,iscag) + & - sites(s)%fmort_rate_canopy(i_scls, i_pft) / m2_per_ha - hio_mortality_understory_si_scag(io_si,iscag) = hio_mortality_understory_si_scag(io_si,iscag) + & - sites(s)%fmort_rate_ustory(i_scls, i_pft) / 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, i_pft) * days_per_year / m2_per_ha + if(hlm_hist_level_hifrq>0) then + call update_history_hifrq1(this,nc,nsites,sites,bc_in,bc_out,dt_tstep) + if(hlm_hist_level_hifrq>1) then + call update_history_hifrq2(this,nc,nsites,sites,bc_in,bc_out,dt_tstep) + end if + end if - end do - end do - ! - ! carbon flux associated with mortality of trees dying by fire - hio_canopy_mortality_carbonflux_si(io_si) = hio_canopy_mortality_carbonflux_si(io_si) + & - sum(sites(s)%fmort_carbonflux_canopy(:)) / g_per_kg + return + end subroutine update_history_hifrq + + subroutine update_history_hifrq1(this,nc,nsites,sites,bc_in,bc_out,dt_tstep) - hio_understory_mortality_carbonflux_si(io_si) = hio_understory_mortality_carbonflux_si(io_si) + & - sum(sites(s)%fmort_carbonflux_ustory(:)) / g_per_kg + ! + ! 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 + + ! Locals + integer :: s ! The local site index + integer :: io_si ! The site index of the IO array + integer :: ipa ! patch bc index for the patch + 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_gpp_secondary_si => this%hvars(ih_gpp_secondary_si)%r81d, & + hio_npp_si => this%hvars(ih_npp_si)%r81d, & + hio_npp_secondary_si => this%hvars(ih_npp_secondary_si)%r81d, & + hio_aresp_si => this%hvars(ih_aresp_si)%r81d, & + hio_aresp_secondary_si => this%hvars(ih_aresp_secondary_si)%r81d, & + hio_maint_resp_si => this%hvars(ih_maint_resp_si)%r81d, & + hio_maint_resp_secondary_si => this%hvars(ih_maint_resp_secondary_si)%r81d, & + hio_growth_resp_si => this%hvars(ih_growth_resp_si)%r81d, & + hio_growth_resp_secondary_si => this%hvars(ih_growth_resp_secondary_si)%r81d, & + hio_c_stomata_si => this%hvars(ih_c_stomata_si)%r81d, & + hio_c_lblayer_si => this%hvars(ih_c_lblayer_si)%r81d, & + hio_vis_rad_err_si => this%hvars(ih_vis_rad_err_si)%r81d, & + hio_nir_rad_err_si => this%hvars(ih_nir_rad_err_si)%r81d, & + hio_nep_si => this%hvars(ih_nep_si)%r81d, & + hio_hr_si => this%hvars(ih_hr_si)%r81d, & + hio_gpp_canopy_si => this%hvars(ih_gpp_canopy_si)%r81d, & + hio_ar_canopy_si => this%hvars(ih_ar_canopy_si)%r81d, & + hio_gpp_understory_si => this%hvars(ih_gpp_understory_si)%r81d, & + hio_ar_understory_si => this%hvars(ih_ar_understory_si)%r81d, & + hio_leaf_mr_si => this%hvars(ih_leaf_mr_si)%r81d, & + hio_froot_mr_si => this%hvars(ih_froot_mr_si)%r81d, & + hio_livecroot_mr_si => this%hvars(ih_livecroot_mr_si)%r81d, & + hio_livestem_mr_si => this%hvars(ih_livestem_mr_si)%r81d, & + hio_maint_resp_unreduced_si => this%hvars(ih_maint_resp_unreduced_si)%r81d, & + 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) - ! treat carbon flux from imort the same way - hio_understory_mortality_carbonflux_si(io_si) = hio_understory_mortality_carbonflux_si(io_si) + & - sum(sites(s)%imort_carbonflux(:)) - - do i_pft = 1, numpft - hio_mortality_carbonflux_si_pft(io_si,i_pft) = hio_mortality_carbonflux_si_pft(io_si,i_pft) + & - (sites(s)%fmort_carbonflux_canopy(i_pft) + & - sites(s)%fmort_carbonflux_ustory(i_pft) ) / g_per_kg + & - sites(s)%imort_carbonflux(i_pft) + & - sites(s)%term_carbonflux_ustory(i_pft) * days_per_sec * ha_per_m2 + & - sites(s)%term_carbonflux_canopy(i_pft) * days_per_sec * ha_per_m2 - - hio_firemortality_carbonflux_si_pft(io_si,i_pft) = sites(s)%fmort_carbonflux_canopy(i_pft) / g_per_kg - end do - - ! add imort and fmort to aboveground woody mortality - do i_pft = 1, numpft - do i_scls = 1,nlevsclass - i_scpf = (i_pft-1)*nlevsclass + i_scls - hio_abg_mortality_cflux_si_scpf(io_si,i_scpf) = hio_abg_mortality_cflux_si_scpf(io_si,i_scpf) + & - (sites(s)%fmort_abg_flux(i_scls,i_pft) / g_per_kg ) + & - sites(s)%imort_abg_flux(i_scls,i_pft) + & - (sites(s)%term_abg_flux(i_scls,i_pft) * days_per_sec * ha_per_m2 ) + dt_tstep_inv = 1.0_r8/dt_tstep + + allocate(age_area_rad(size(ED_val_history_ageclass_bin_edges,1)+1)) + + do_sites: do s = 1,nsites + + call this%zero_site_hvars(sites(s), upfreq_in=group_hifr_simple) + + io_si = sites(s)%h_gid + + 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 + + ! 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) + 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))>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 - end do - - if(hlm_use_tree_damage .eq. itrue) then - - do i_pft = 1, numpft - do icdam = 1, nlevdamage - do i_scls = 1,nlevsclass - - icdsc = (icdam-1)*nlevsclass + i_scls - icdpf = (icdam-1)*nlevsclass + i_scls + & - (i_pft-1) * nlevsclass * nlevdamage - - this%hvars(ih_mortality_si_cdpf)%r82d(io_si, icdpf) = & - this%hvars(ih_mortality_si_cdpf)%r82d(io_si, icdpf) + & - ( (sites(s)%term_nindivs_canopy_damage(icdam, i_scls, i_pft) * days_per_year) + & - (sites(s)%term_nindivs_ustory_damage(icdam, i_scls, i_pft) * days_per_year) + & - sites(s)%imort_rate_damage(icdam, i_scls, i_pft) + & - sites(s)%fmort_rate_canopy_damage(icdam, i_scls, i_pft) + & - sites(s)%fmort_rate_ustory_damage(icdam, i_scls, i_pft) ) / m2_per_ha - - this%hvars(ih_mortality_canopy_si_cdpf)%r82d(io_si,icdpf) = & - this%hvars(ih_mortality_canopy_si_cdpf)%r82d(io_si,icdpf) + & - ( sites(s)%term_nindivs_canopy_damage(icdam,i_scls,i_pft) * days_per_year + & - sites(s)%fmort_rate_canopy_damage(icdam, i_scls, i_pft) )/ m2_per_ha - - this%hvars(ih_mortality_understory_si_cdpf)%r82d(io_si,icdpf) = & - this%hvars(ih_mortality_understory_si_cdpf)%r82d(io_si,icdpf) + & - ( sites(s)%term_nindivs_ustory_damage(icdam, i_scls,i_pft) * days_per_year + & - sites(s)%imort_rate_damage(icdam, i_scls, i_pft) + & - sites(s)%fmort_rate_ustory_damage(icdam, i_scls, i_pft) )/ m2_per_ha + sum_area_rad = sum(age_area_rad(:)) - end do + if_anyrad: if(sum_area_rad sites(s)%oldest_patch + do while(associated(cpatch)) + if( abs(cpatch%rad_error(ivis))>nearzero ) then + age_class = get_age_class_index(cpatch%age) + + 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 do - end if - - sites(s)%term_nindivs_canopy(:,:) = 0._r8 - sites(s)%term_nindivs_ustory(:,:) = 0._r8 - sites(s)%imort_carbonflux(:) = 0._r8 - sites(s)%imort_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)%growthflux_fusion(:,:) = 0._r8 - sites(s)%fmort_abg_flux(:,:) = 0._r8 - sites(s)%imort_abg_flux(:,:) = 0._r8 - sites(s)%term_abg_flux(:,:) = 0._r8 - - sites(s)%imort_rate_damage(:,:,:) = 0.0_r8 - sites(s)%term_nindivs_canopy_damage(:,:,:) = 0.0_r8 - sites(s)%term_nindivs_ustory_damage(:,:,:) = 0.0_r8 - sites(s)%imort_cflux_damage(:,:) = 0._r8 - sites(s)%term_cflux_canopy_damage(:,:) = 0._r8 - sites(s)%term_cflux_ustory_damage(:,:) = 0._r8 - sites(s)%fmort_rate_canopy_damage(:,:,:) = 0._r8 - sites(s)%fmort_rate_ustory_damage(:,:,:) = 0._r8 - sites(s)%fmort_cflux_canopy_damage(:,:) = 0._r8 - sites(s)%fmort_cflux_ustory_damage(:,:) = 0._r8 - sites(s)%crownarea_canopy_damage = 0._r8 - sites(s)%crownarea_ustory_damage = 0._r8 - - ! pass the recruitment rate as a flux to the history, and then reset the recruitment buffer - do i_pft = 1, numpft - ! pass the recruitment rate as a flux to the history, and then reset the recruitment buffer - hio_recruitment_si_pft(io_si,i_pft) = sites(s)%recruitment_rate(i_pft) * days_per_year / m2_per_ha - - ! Gridcell output and inputs - hio_seeds_out_gc_si_pft(io_si,i_pft) = sites(s)%seed_out(i_pft) - hio_seeds_in_gc_si_pft(io_si,i_pft) = sites(s)%seed_in(i_pft) - end do - sites(s)%recruitment_rate(:) = 0._r8 - - ! summarize all of the mortality fluxes by PFT - do i_pft = 1, numpft - do i_scls = 1,nlevsclass - i_scpf = (i_pft-1)*nlevsclass + i_scls - - hio_mortality_si_pft(io_si,i_pft) = hio_mortality_si_pft(io_si,i_pft) + & - 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) - - if(hlm_use_tree_damage .eq. itrue) then - hio_mortality_si_pft(io_si, i_pft) = hio_mortality_si_pft(io_si,i_pft) + & - this%hvars(ih_m11_si_scpf)%r82d(io_si,i_scpf) - end if - - end do - end do - - ! ------------------------------------------------------------------------------ - ! Some carbon only litter diagnostics (legacy) - ! ------------------------------------------------------------------------------ - - hio_litter_in_si(io_si) = (sum(flux_diags_c%cwd_ag_input(:)) + & - sum(flux_diags_c%cwd_bg_input(:)) + & - sum(flux_diags_c%leaf_litter_input(:)) + & - sum(flux_diags_c%root_litter_input(:))) * & - AREA_INV * days_per_sec - - hio_litter_out_si(io_si) = 0._r8 - hio_seed_bank_si(io_si) = 0._r8 - hio_ungerm_seed_bank_si(io_si) = 0._r8 - hio_seedling_pool_si(io_si) = 0._r8 - hio_seeds_in_si(io_si) = 0._r8 - hio_seeds_in_local_si(io_si) = 0._r8 - - cpatch => sites(s)%oldest_patch - do while(associated(cpatch)) - - litt => cpatch%litter(element_pos(carbon12_element)) - - area_frac = 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(:))) * & - area_frac * days_per_sec - - ! Sum up total seed bank (germinated and ungerminated) - hio_seed_bank_si(io_si) = hio_seed_bank_si(io_si) + & - (sum(litt%seed(:))+sum(litt%seed_germ(:))) * & - area_frac - - ! Sum up total seed bank (just ungerminated) - hio_ungerm_seed_bank_si(io_si) = hio_ungerm_seed_bank_si(io_si) + & - sum(litt%seed(:)) * area_frac - - ! Sum up total seedling pool - hio_seedling_pool_si(io_si) = hio_seedling_pool_si(io_si) + & - sum(litt%seed_germ(:)) * area_frac - - ! Sum up the input flux into the seed bank (local and external) - hio_seeds_in_si(io_si) = hio_seeds_in_si(io_si) + & - (sum(litt%seed_in_local(:)) + sum(litt%seed_in_extern(:))) * & - area_frac * days_per_sec - - hio_seeds_in_local_si(io_si) = hio_seeds_in_local_si(io_si) + & - sum(litt%seed_in_local(:)) * & - area_frac * days_per_sec - - - - cpatch => cpatch%younger - end do - - ! ------------------------------------------------------------------------------ - ! Diagnostics discretized by element type - ! ------------------------------------------------------------------------------ - - hio_cwd_elcwd(io_si,:) = 0._r8 - - do el = 1, num_elements - - flux_diags => sites(s)%flux_diags(el) - - ! Sum up all input litter fluxes (above below, fines, cwd) [kg/ha/day] - hio_litter_in_elem(io_si, el) = (sum(flux_diags%cwd_ag_input(:)) + & - sum(flux_diags%cwd_bg_input(:)) + sum(flux_diags%leaf_litter_input(:)) + & - sum(flux_diags%root_litter_input(:))) / m2_per_ha / sec_per_day - - hio_cwd_ag_elem(io_si,el) = 0._r8 - hio_cwd_bg_elem(io_si,el) = 0._r8 - hio_fines_ag_elem(io_si,el) = 0._r8 - hio_fines_bg_elem(io_si,el) = 0._r8 - - hio_seed_bank_elem(io_si,el) = 0._r8 - hio_seed_germ_elem(io_si,el) = 0._r8 - hio_seed_decay_elem(io_si,el) = 0._r8 - hio_seeds_in_local_elem(io_si,el) = 0._r8 - hio_seed_in_extern_elem(io_si,el) = 0._r8 - hio_litter_out_elem(io_si,el) = 0._r8 - - ! 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 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 - cpatch => sites(s)%oldest_patch - do while(associated(cpatch)) + 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 - litt => cpatch%litter(el) + exit if_veg_area - area_frac = cpatch%area * AREA_INV + else - ! 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 + ipa = 0 + site_area_veg_inv = 1._r8/site_area_veg_inv - hio_seed_bank_elem(io_si,el) = hio_seed_bank_elem(io_si,el) + & - sum(litt%seed(:)) * cpatch%area / m2_per_ha + cpatch => sites(s)%oldest_patch + do while(associated(cpatch)) - hio_seed_germ_elem(io_si,el) = hio_seed_germ_elem(io_si,el) + & - sum(litt%seed_germ(:)) * cpatch%area / m2_per_ha + ipa = ipa + 1 - 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_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_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 + 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 - ! 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 + ! Only accumulate the instantaneous vegetation temperature for vegetated patches + if (cpatch%patchno .ne. 0) then + hio_tveg(io_si) = hio_tveg(io_si) + & + (bc_in(s)%t_veg_pa(cpatch%patchno) - t_water_freeze_k_1atm) * & + cpatch%total_canopy_area * site_area_veg_inv + end if - hio_cwd_bg_elem(io_si,el) = hio_cwd_bg_elem(io_si,el) + & - sum(litt%bg_cwd(:,:)) * cpatch%area / m2_per_ha + ccohort => cpatch%shortest + do while(associated(ccohort)) - hio_fines_ag_elem(io_si,el) = hio_fines_ag_elem(io_si,el) + & - sum(litt%leaf_fines(:)) * cpatch%area / m2_per_ha + n_perm2 = ccohort%n * AREA_INV - hio_fines_bg_elem(io_si,el) = hio_fines_bg_elem(io_si,el) + & - sum(litt%root_fines(:,:)) * cpatch%area / m2_per_ha + if_notnew: if ( .not. ccohort%isnew ) then - do cwd=1,ncwd - elcwd = (el-1)*ncwd+cwd - hio_cwd_elcwd(io_si,elcwd) = hio_cwd_elcwd(io_si,elcwd) + & - (litt%ag_cwd(cwd) + sum(litt%bg_cwd(cwd,:))) * & - cpatch%area / m2_per_ha + ! scale up cohort fluxes to the site level + ! these fluxes have conversions of [kg/plant/timestep] -> [kg/m2/s] + + hio_npp_si(io_si) = hio_npp_si(io_si) + & + ccohort%npp_tstep * n_perm2 * dt_tstep_inv - end do + ! Net Ecosystem Production [kgC/m2/s] + hio_nep_si(io_si) = hio_nep_si(io_si) + & + ccohort%npp_tstep * n_perm2 * dt_tstep_inv - ! Load Mass States - ccohort => cpatch%tallest - do while(associated(ccohort)) + hio_gpp_si(io_si) = hio_gpp_si(io_si) + & + ccohort%gpp_tstep * n_perm2 * dt_tstep_inv - sapw_m = ccohort%prt%GetState(sapw_organ, element_list(el)) - struct_m = ccohort%prt%GetState(struct_organ, element_list(el)) - leaf_m = ccohort%prt%GetState(leaf_organ, element_list(el)) - fnrt_m = ccohort%prt%GetState(fnrt_organ, element_list(el)) - store_m = ccohort%prt%GetState(store_organ, element_list(el)) - repro_m = ccohort%prt%GetState(repro_organ, element_list(el)) - total_m = sapw_m+struct_m+leaf_m+fnrt_m+store_m+repro_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 + hio_aresp_si(io_si) = hio_aresp_si(io_si) + & + ccohort%resp_tstep * n_perm2 * dt_tstep_inv - end if + hio_growth_resp_si(io_si) = hio_growth_resp_si(io_si) + & + ccohort%resp_g_tstep * n_perm2 * dt_tstep_inv - ccohort => ccohort%shorter - end do ! end cohort loop + hio_maint_resp_si(io_si) = hio_maint_resp_si(io_si) + & + ccohort%resp_m * n_perm2 * dt_tstep_inv - cpatch => cpatch%younger - end do ! end patch loop + hio_maint_resp_unreduced_si(io_si) = hio_maint_resp_unreduced_si(io_si) + & + ccohort%resp_m_unreduced * n_perm2 * dt_tstep_inv - end do ! end element loop + ! Secondary forest only + if(cpatch%land_use_label .eq. secondaryland) then + hio_npp_secondary_si(io_si) = hio_npp_secondary_si(io_si) + & + ccohort%npp_tstep * n_perm2 * dt_tstep_inv + hio_gpp_secondary_si(io_si) = hio_gpp_secondary_si(io_si) + & + ccohort%gpp_tstep * n_perm2 * dt_tstep_inv - ! Normalize storage fractions and L2FR + hio_aresp_secondary_si(io_si) = hio_aresp_secondary_si(io_si) + & + ccohort%resp_tstep * n_perm2 * dt_tstep_inv - 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 + hio_growth_resp_secondary_si(io_si) = hio_growth_resp_secondary_si(io_si) + & + ccohort%resp_g_tstep * n_perm2 * dt_tstep_inv - do i_pft = 1, numpft - do i_scls = 1,nlevsclass - i_scpf = (i_pft-1)*nlevsclass + i_scls + hio_maint_resp_secondary_si(io_si) = hio_maint_resp_secondary_si(io_si) + & + ccohort%resp_m * n_perm2 * dt_tstep_inv + end if - 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 + ! 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 - do el = 1, num_elements + ! 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 - if(element_list(el).eq.nitrogen_element)then - if( this%hvars(ih_storentfrac_si)%r81d(io_si)>nearzero ) then - this%hvars(ih_storentfrac_si)%r81d(io_si) = this%hvars(ih_storen_si)%r81d(io_si) / & - this%hvars(ih_storentfrac_si)%r81d(io_si) - end if - do i_pft = 1, numpft - do i_scls = 1,nlevsclass - i_scpf = (i_pft-1)*nlevsclass + i_scls - - if( this%hvars(ih_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_gpp_canopy_si(io_si) = hio_gpp_canopy_si(io_si) + & + ccohort%gpp_tstep * n_perm2 * dt_tstep_inv - end do - end do - 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 - do i_pft = 1, numpft - do i_scls = 1,nlevsclass - i_scpf = (i_pft-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_ar_canopy_si(io_si) = hio_ar_canopy_si(io_si) + & + ccohort%resp_tstep * n_perm2 * dt_tstep_inv - 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 - ! - ! 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_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_understory_mortality_carbonflux_si(io_si) = hio_understory_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 - - hio_understory_mortality_crownarea_si(io_si) = hio_understory_mortality_crownarea_si(io_si) + & - sites(s)%fmort_crownarea_ustory + & - sites(s)%term_crownarea_ustory * days_per_year + & - sites(s)%imort_crownarea - - ! and zero the site-level termination carbon flux variable - sites(s)%term_carbonflux_canopy(:) = 0._r8 - sites(s)%term_carbonflux_ustory(:) = 0._r8 - ! + else + + hio_gpp_understory_si(io_si) = hio_gpp_understory_si(io_si) + & + ccohort%gpp_tstep * n_perm2 * dt_tstep_inv - ! add the site-level disturbance-associated cwd and litter input fluxes to thir respective flux fields + hio_ar_understory_si(io_si) = hio_ar_understory_si(io_si) + & + ccohort%resp_tstep * n_perm2 * dt_tstep_inv - do i_cwd = 1, ncwd - hio_cwd_ag_in_si_cwdsc(io_si, i_cwd) = hio_cwd_ag_in_si_cwdsc(io_si, i_cwd) + & - flux_diags_c%cwd_ag_input(i_cwd) / days_per_year / sec_per_day + end if - hio_cwd_bg_in_si_cwdsc(io_si, i_cwd) = hio_cwd_bg_in_si_cwdsc(io_si, i_cwd) + & - flux_diags_c%cwd_bg_input(i_cwd) / days_per_year / sec_per_day + end if if_notnew + ccohort => ccohort%taller + end do - end do + cpatch => cpatch%younger + end do + end if if_veg_area + end do do_sites - enddo siteloop ! site loop + deallocate(age_area_rad) - end associate - end associate + end associate + return + end subroutine update_history_hifrq1 - return - end subroutine update_history_dyn + ! =============================================================================================== - subroutine update_history_hifrq(this,nc,nsites,sites,bc_in,dt_tstep) + subroutine update_history_hifrq2(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 - ! after rapid timescale productivity calculations (gpp and respiration). + ! This is the call to update the history IO arrays for multi-dimension arrays + ! that change rapidly. This is an expensive call, the model will probably run + ! much faster if the user is not using any of these diagnostics. ! --------------------------------------------------------------------------------- - use EDParamsMod , only : nclmax, nlevleaf ! ! Arguments class(fates_history_interface_type) :: this @@ -4499,6 +5170,7 @@ subroutine update_history_hifrq(this,nc,nsites,sites,bc_in,dt_tstep) 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 ! Locals @@ -4515,125 +5187,102 @@ subroutine update_history_hifrq(this,nc,nsites,sites,bc_in,dt_tstep) real(r8) :: n_perm2 ! individuals per m2 for the whole column real(r8) :: patch_area_by_age(nlevage) ! patch area in each bin for normalizing purposes real(r8) :: canopy_area_by_age(nlevage) ! canopy area in each bin for normalizing purposes - real(r8) :: site_area_veg ! area of the site that is not bare-ground + real(r8) :: site_area_veg_inv ! 1/area of the site that is not bare-ground integer :: ipa2 ! patch incrementer - integer :: cnlfpft_indx, cnlf_indx, ipft, ican, ileaf ! more iterators and indices + 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 + type(fates_patch_type),pointer :: cpatch type(fates_cohort_type),pointer :: ccohort - real(r8) :: per_dt_tstep ! Time step in frequency units (/s) + 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, & + hio_ar_darkm_si_scpf => this%hvars(ih_ar_darkm_si_scpf)%r82d, & + hio_ar_crootm_si_scpf => this%hvars(ih_ar_crootm_si_scpf)%r82d, & + hio_ar_frootm_si_scpf => this%hvars(ih_ar_frootm_si_scpf)%r82d, & + hio_rdark_canopy_si_scls => this%hvars(ih_rdark_canopy_si_scls)%r82d, & + hio_livestem_mr_canopy_si_scls => this%hvars(ih_livestem_mr_canopy_si_scls)%r82d, & + hio_livecroot_mr_canopy_si_scls => this%hvars(ih_livecroot_mr_canopy_si_scls)%r82d, & + hio_froot_mr_canopy_si_scls => this%hvars(ih_froot_mr_canopy_si_scls)%r82d, & + hio_resp_g_canopy_si_scls => this%hvars(ih_resp_g_canopy_si_scls)%r82d, & + hio_resp_m_canopy_si_scls => this%hvars(ih_resp_m_canopy_si_scls)%r82d, & + hio_rdark_understory_si_scls => this%hvars(ih_rdark_understory_si_scls)%r82d, & + hio_livestem_mr_understory_si_scls => this%hvars(ih_livestem_mr_understory_si_scls)%r82d, & + hio_livecroot_mr_understory_si_scls => this%hvars(ih_livecroot_mr_understory_si_scls)%r82d, & + hio_froot_mr_understory_si_scls => this%hvars(ih_froot_mr_understory_si_scls)%r82d, & + hio_resp_g_understory_si_scls => this%hvars(ih_resp_g_understory_si_scls)%r82d, & + hio_resp_m_understory_si_scls => this%hvars(ih_resp_m_understory_si_scls)%r82d, & + hio_gpp_si_age => this%hvars(ih_gpp_si_age)%r82d, & + hio_npp_si_age => this%hvars(ih_npp_si_age)%r82d, & + hio_c_stomata_si_age => this%hvars(ih_c_stomata_si_age)%r82d, & + hio_c_lblayer_si_age => this%hvars(ih_c_lblayer_si_age)%r82d, & + hio_parsun_z_si_cnlf => this%hvars(ih_parsun_z_si_cnlf)%r82d, & + hio_parsha_z_si_cnlf => this%hvars(ih_parsha_z_si_cnlf)%r82d, & + hio_ts_net_uptake_si_cnlf => this%hvars(ih_ts_net_uptake_si_cnlf)%r82d, & + hio_parsun_z_si_cnlfpft => this%hvars(ih_parsun_z_si_cnlfpft)%r82d, & + hio_parsha_z_si_cnlfpft => this%hvars(ih_parsha_z_si_cnlfpft)%r82d, & + hio_laisun_z_si_cnlf => this%hvars(ih_laisun_z_si_cnlf)%r82d, & + hio_laisha_z_si_cnlf => this%hvars(ih_laisha_z_si_cnlf)%r82d, & + hio_laisun_clllpf => this%hvars(ih_laisun_clllpf)%r82d, & + hio_laisha_clllpf => this%hvars(ih_laisha_clllpf)%r82d, & + hio_crownfrac_clllpf => this%hvars(ih_crownfrac_clllpf)%r82d, & + hio_parprof_dir_si_cnlf => this%hvars(ih_parprof_dir_si_cnlf)%r82d, & + hio_parprof_dif_si_cnlf => this%hvars(ih_parprof_dif_si_cnlf)%r82d, & + hio_parprof_dir_si_cnlfpft => this%hvars(ih_parprof_dir_si_cnlfpft)%r82d, & + hio_parprof_dif_si_cnlfpft => this%hvars(ih_parprof_dif_si_cnlfpft)%r82d, & + hio_parsun_si_can => this%hvars(ih_parsun_si_can)%r82d, & + hio_parsha_si_can => this%hvars(ih_parsha_si_can)%r82d, & + hio_laisun_si_can => this%hvars(ih_laisun_si_can)%r82d, & + 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 - associate( hio_gpp_si => this%hvars(ih_gpp_si)%r81d, & - hio_gpp_secondary_si => this%hvars(ih_gpp_secondary_si)%r81d, & - hio_npp_si => this%hvars(ih_npp_si)%r81d, & - hio_npp_secondary_si => this%hvars(ih_npp_secondary_si)%r81d, & - hio_aresp_si => this%hvars(ih_aresp_si)%r81d, & - hio_aresp_secondary_si => this%hvars(ih_aresp_secondary_si)%r81d, & - hio_maint_resp_si => this%hvars(ih_maint_resp_si)%r81d, & - hio_maint_resp_secondary_si => this%hvars(ih_maint_resp_secondary_si)%r81d, & - hio_growth_resp_si => this%hvars(ih_growth_resp_si)%r81d, & - hio_growth_resp_secondary_si => this%hvars(ih_growth_resp_secondary_si)%r81d, & - hio_c_stomata_si => this%hvars(ih_c_stomata_si)%r81d, & - hio_c_lblayer_si => this%hvars(ih_c_lblayer_si)%r81d, & - hio_rad_error_si => this%hvars(ih_rad_error_si)%r81d, & - hio_nep_si => this%hvars(ih_nep_si)%r81d, & - hio_hr_si => this%hvars(ih_hr_si)%r81d, & - 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, & - hio_ar_darkm_si_scpf => this%hvars(ih_ar_darkm_si_scpf)%r82d, & - hio_ar_crootm_si_scpf => this%hvars(ih_ar_crootm_si_scpf)%r82d, & - hio_ar_frootm_si_scpf => this%hvars(ih_ar_frootm_si_scpf)%r82d, & - hio_gpp_canopy_si => this%hvars(ih_gpp_canopy_si)%r81d, & - hio_ar_canopy_si => this%hvars(ih_ar_canopy_si)%r81d, & - hio_gpp_understory_si => this%hvars(ih_gpp_understory_si)%r81d, & - hio_ar_understory_si => this%hvars(ih_ar_understory_si)%r81d, & - hio_rdark_canopy_si_scls => this%hvars(ih_rdark_canopy_si_scls)%r82d, & - hio_livestem_mr_canopy_si_scls => this%hvars(ih_livestem_mr_canopy_si_scls)%r82d, & - hio_livecroot_mr_canopy_si_scls => this%hvars(ih_livecroot_mr_canopy_si_scls)%r82d, & - hio_froot_mr_canopy_si_scls => this%hvars(ih_froot_mr_canopy_si_scls)%r82d, & - hio_resp_g_canopy_si_scls => this%hvars(ih_resp_g_canopy_si_scls)%r82d, & - hio_resp_m_canopy_si_scls => this%hvars(ih_resp_m_canopy_si_scls)%r82d, & - hio_rdark_understory_si_scls => this%hvars(ih_rdark_understory_si_scls)%r82d, & - hio_livestem_mr_understory_si_scls => this%hvars(ih_livestem_mr_understory_si_scls)%r82d, & - hio_livecroot_mr_understory_si_scls => this%hvars(ih_livecroot_mr_understory_si_scls)%r82d, & - hio_froot_mr_understory_si_scls => this%hvars(ih_froot_mr_understory_si_scls)%r82d, & - hio_resp_g_understory_si_scls => this%hvars(ih_resp_g_understory_si_scls)%r82d, & - hio_resp_m_understory_si_scls => this%hvars(ih_resp_m_understory_si_scls)%r82d, & - hio_leaf_mr_si => this%hvars(ih_leaf_mr_si)%r81d, & - hio_froot_mr_si => this%hvars(ih_froot_mr_si)%r81d, & - hio_livecroot_mr_si => this%hvars(ih_livecroot_mr_si)%r81d, & - hio_livestem_mr_si => this%hvars(ih_livestem_mr_si)%r81d, & - hio_gpp_si_age => this%hvars(ih_gpp_si_age)%r82d, & - hio_npp_si_age => this%hvars(ih_npp_si_age)%r82d, & - hio_c_stomata_si_age => this%hvars(ih_c_stomata_si_age)%r82d, & - hio_c_lblayer_si_age => this%hvars(ih_c_lblayer_si_age)%r82d, & - hio_parsun_z_si_cnlf => this%hvars(ih_parsun_z_si_cnlf)%r82d, & - hio_parsha_z_si_cnlf => this%hvars(ih_parsha_z_si_cnlf)%r82d, & - hio_ts_net_uptake_si_cnlf => this%hvars(ih_ts_net_uptake_si_cnlf)%r82d, & - hio_parsun_z_si_cnlfpft => this%hvars(ih_parsun_z_si_cnlfpft)%r82d, & - hio_parsha_z_si_cnlfpft => this%hvars(ih_parsha_z_si_cnlfpft)%r82d, & - hio_laisun_z_si_cnlf => this%hvars(ih_laisun_z_si_cnlf)%r82d, & - hio_laisha_z_si_cnlf => this%hvars(ih_laisha_z_si_cnlf)%r82d, & - hio_laisun_z_si_cnlfpft => this%hvars(ih_laisun_z_si_cnlfpft)%r82d, & - hio_laisha_z_si_cnlfpft => this%hvars(ih_laisha_z_si_cnlfpft)%r82d, & - hio_laisun_top_si_can => this%hvars(ih_laisun_top_si_can)%r82d, & - hio_laisha_top_si_can => this%hvars(ih_laisha_top_si_can)%r82d, & - hio_fabd_sun_si_cnlfpft => this%hvars(ih_fabd_sun_si_cnlfpft)%r82d, & - hio_fabd_sha_si_cnlfpft => this%hvars(ih_fabd_sha_si_cnlfpft)%r82d, & - hio_fabi_sun_si_cnlfpft => this%hvars(ih_fabi_sun_si_cnlfpft)%r82d, & - hio_fabi_sha_si_cnlfpft => this%hvars(ih_fabi_sha_si_cnlfpft)%r82d, & - hio_fabd_sun_si_cnlf => this%hvars(ih_fabd_sun_si_cnlf)%r82d, & - hio_fabd_sha_si_cnlf => this%hvars(ih_fabd_sha_si_cnlf)%r82d, & - hio_fabi_sun_si_cnlf => this%hvars(ih_fabi_sun_si_cnlf)%r82d, & - hio_fabi_sha_si_cnlf => this%hvars(ih_fabi_sha_si_cnlf)%r82d, & - hio_parprof_dir_si_cnlf => this%hvars(ih_parprof_dir_si_cnlf)%r82d, & - hio_parprof_dif_si_cnlf => this%hvars(ih_parprof_dif_si_cnlf)%r82d, & - hio_parprof_dir_si_cnlfpft => this%hvars(ih_parprof_dir_si_cnlfpft)%r82d, & - hio_parprof_dif_si_cnlfpft => this%hvars(ih_parprof_dif_si_cnlfpft)%r82d, & - hio_fabd_sun_top_si_can => this%hvars(ih_fabd_sun_top_si_can)%r82d, & - hio_fabd_sha_top_si_can => this%hvars(ih_fabd_sha_top_si_can)%r82d, & - hio_fabi_sun_top_si_can => this%hvars(ih_fabi_sun_top_si_can)%r82d, & - hio_fabi_sha_top_si_can => this%hvars(ih_fabi_sha_top_si_can)%r82d, & - hio_parsun_top_si_can => this%hvars(ih_parsun_top_si_can)%r82d, & - hio_parsha_top_si_can => this%hvars(ih_parsha_top_si_can)%r82d, & - hio_maint_resp_unreduced_si => this%hvars(ih_maint_resp_unreduced_si)%r81d, & - hio_tveg => this%hvars(ih_tveg_si)%r81d) - - ! Flush the relevant history variables - call this%flush_hvars(nc,upfreq_in=2) - - per_dt_tstep = 1.0_r8/dt_tstep - - do s = 1,nsites - - call this%zero_site_hvars(sites(s), upfreq_in=2) + do_sites: do s = 1,nsites - io_si = sites(s)%h_gid + 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 - 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 + ! If there is no vegetation, go to the next site + if(site_area_veg_inv < nearzero) cycle do_sites + + site_area_veg_inv = 1._r8/site_area_veg_inv + + io_si = sites(s)%h_gid ipa = 0 - + patch_area_by_age(1:nlevage) = 0._r8 canopy_area_by_age(1:nlevage) = 0._r8 - - ! Calculate the site-level total vegetated area (i.e. non-bareground) - site_area_veg = area - if (hlm_use_nocomp .eq. itrue .and. hlm_use_fixed_biogeog .eq. itrue) then - site_area_veg = area - sites(s)%area_pft(0) - end if cpatch => sites(s)%oldest_patch do while(associated(cpatch)) + ipa = ipa + 1 + patch_area_by_age(cpatch%age_class) = & patch_area_by_age(cpatch%age_class) + cpatch%area canopy_area_by_age(cpatch%age_class) = & canopy_area_by_age(cpatch%age_class) + cpatch%total_canopy_area + + ! Canopy resitance terms hio_c_stomata_si_age(io_si,cpatch%age_class) = & hio_c_stomata_si_age(io_si,cpatch%age_class) + & @@ -4643,22 +5292,6 @@ subroutine update_history_hifrq(this,nc,nsites,sites,bc_in,dt_tstep) hio_c_lblayer_si_age(io_si,cpatch%age_class) + & cpatch%c_lblayer * cpatch%total_canopy_area * mol_per_umol - hio_c_stomata_si(io_si) = hio_c_stomata_si(io_si) + & - cpatch%c_stomata * cpatch%total_canopy_area * mol_per_umol - - hio_c_lblayer_si(io_si) = hio_c_lblayer_si(io_si) + & - cpatch%c_lblayer * cpatch%total_canopy_area * mol_per_umol - - hio_rad_error_si(io_si) = hio_rad_error_si(io_si) + & - cpatch%radiation_error * cpatch%area * AREA_INV - - ! Only accumulate the instantaneous vegetation temperature for vegetated patches - if (cpatch%patchno .ne. 0) then - hio_tveg(io_si) = hio_tveg(io_si) + & - (bc_in(s)%t_veg_pa(cpatch%patchno) - t_water_freeze_k_1atm) * & - cpatch%area / site_area_veg - end if - ccohort => cpatch%shortest do while(associated(ccohort)) @@ -4666,260 +5299,286 @@ subroutine update_history_hifrq(this,nc,nsites,sites,bc_in,dt_tstep) if ( .not. ccohort%isnew ) then - npp = ccohort%npp_tstep - resp_g = ccohort%resp_g_tstep - aresp = ccohort%resp_tstep + npp = ccohort%npp_tstep + resp_g = ccohort%resp_g_tstep + aresp = ccohort%resp_tstep ! Calculate index for the scpf class associate( scpf => ccohort%size_by_pft_class, & - scls => ccohort%size_class ) - - ! scale up cohort fluxes to the site level - hio_npp_si(io_si) = hio_npp_si(io_si) + & - npp * n_perm2 * per_dt_tstep - - hio_gpp_si(io_si) = hio_gpp_si(io_si) + & - ccohort%gpp_tstep * n_perm2 * per_dt_tstep - - hio_aresp_si(io_si) = hio_aresp_si(io_si) + & - aresp * n_perm2 * per_dt_tstep - hio_growth_resp_si(io_si) = hio_growth_resp_si(io_si) + & - resp_g * n_perm2 * per_dt_tstep - hio_maint_resp_si(io_si) = hio_maint_resp_si(io_si) + & - ccohort%resp_m * n_perm2 * per_dt_tstep - - hio_maint_resp_unreduced_si(io_si) = hio_maint_resp_unreduced_si(io_si) + & - ccohort%resp_m_unreduced * n_perm2 * per_dt_tstep - - ! Secondary forest only - if ( cpatch%land_use_label .eq. secondaryland ) then - hio_npp_secondary_si(io_si) = hio_npp_secondary_si(io_si) + & - npp * n_perm2 * per_dt_tstep - hio_gpp_secondary_si(io_si) = hio_gpp_secondary_si(io_si) + & - ccohort%gpp_tstep * n_perm2 * per_dt_tstep - hio_aresp_secondary_si(io_si) = hio_aresp_secondary_si(io_si) + & - aresp * n_perm2 * per_dt_tstep - hio_growth_resp_secondary_si(io_si) = hio_growth_resp_secondary_si(io_si) + & - resp_g * n_perm2 * per_dt_tstep - hio_maint_resp_secondary_si(io_si) = hio_maint_resp_secondary_si(io_si) + & - ccohort%resp_m * n_perm2 * per_dt_tstep - end if - - ! Add up the total Net Ecosystem Production - ! for this timestep. [kgC/m2/s] - hio_nep_si(io_si) = hio_nep_si(io_si) + & - npp * n_perm2 * per_dt_tstep - - ! aggregate MR fluxes to the site level - 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 - - ! Total AR (kgC/m2/s) = (kgC/plant/step) / (s/step) * (plant/m2) - hio_ar_si_scpf(io_si,scpf) = hio_ar_si_scpf(io_si,scpf) + & - (ccohort%resp_tstep*per_dt_tstep) * n_perm2 - - ! Growth AR (kgC/m2/s) - hio_ar_grow_si_scpf(io_si,scpf) = hio_ar_grow_si_scpf(io_si,scpf) + & - (resp_g*per_dt_tstep) * n_perm2 - - ! Maint AR (kgC/m2/s) - hio_ar_maint_si_scpf(io_si,scpf) = hio_ar_maint_si_scpf(io_si,scpf) + & - (ccohort%resp_m*per_dt_tstep) * 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 - - - ! accumulate fluxes per patch age bin - hio_gpp_si_age(io_si,cpatch%age_class) = hio_gpp_si_age(io_si,cpatch%age_class) & - + ccohort%gpp_tstep * ccohort%n * per_dt_tstep - hio_npp_si_age(io_si,cpatch%age_class) = hio_npp_si_age(io_si,cpatch%age_class) & - + npp * ccohort%n * per_dt_tstep - - ! accumulate fluxes on canopy- and understory- separated fluxes - if (ccohort%canopy_layer .eq. 1) then - ! - ! bulk fluxes are in gC / m2 / s - hio_gpp_canopy_si(io_si) = hio_gpp_canopy_si(io_si) + & - ccohort%gpp_tstep * n_perm2 * per_dt_tstep - - hio_ar_canopy_si(io_si) = hio_ar_canopy_si(io_si) + & - aresp * n_perm2 * per_dt_tstep - - ! - ! size-resolved respiration fluxes are in kg C / m2 / s - hio_rdark_canopy_si_scls(io_si,scls) = hio_rdark_canopy_si_scls(io_si,scls) + & - ccohort%rdark * ccohort%n * 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) + & - resp_g * ccohort%n * per_dt_tstep * ha_per_m2 - hio_resp_m_canopy_si_scls(io_si,scls) = hio_resp_m_canopy_si_scls(io_si,scls) + & - ccohort%resp_m * ccohort%n * per_dt_tstep * ha_per_m2 - else - ! - ! bulk fluxes are in gC / m2 / s - hio_gpp_understory_si(io_si) = hio_gpp_understory_si(io_si) + & - ccohort%gpp_tstep * n_perm2 * per_dt_tstep - - - hio_ar_understory_si(io_si) = hio_ar_understory_si(io_si) + & - aresp * n_perm2 * per_dt_tstep - - ! - ! size-resolved respiration fluxes are in kg C / m2 / s - hio_rdark_understory_si_scls(io_si,scls) = hio_rdark_understory_si_scls(io_si,scls) + & - ccohort%rdark * ccohort%n * 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) + & - resp_g * ccohort%n * per_dt_tstep * ha_per_m2 - hio_resp_m_understory_si_scls(io_si,scls) = hio_resp_m_understory_si_scls(io_si,scls) + & - ccohort%resp_m * ccohort%n * per_dt_tstep * ha_per_m2 - endif - end associate + 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_tstep*dt_tstep_inv) * n_perm2 + + ! Growth AR (kgC/m2/s) + hio_ar_grow_si_scpf(io_si,scpf) = hio_ar_grow_si_scpf(io_si,scpf) + & + (resp_g*dt_tstep_inv) * n_perm2 + + ! Maint AR (kgC/m2/s) + hio_ar_maint_si_scpf(io_si,scpf) = hio_ar_maint_si_scpf(io_si,scpf) + & + (ccohort%resp_m*dt_tstep_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 + + ! accumulate fluxes per patch age bin + hio_gpp_si_age(io_si,cpatch%age_class) = hio_gpp_si_age(io_si,cpatch%age_class) & + + ccohort%gpp_tstep * ccohort%n * dt_tstep_inv + + hio_npp_si_age(io_si,cpatch%age_class) = hio_npp_si_age(io_si,cpatch%age_class) & + + npp * ccohort%n * dt_tstep_inv + + ! 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) + & + resp_g * ccohort%n * dt_tstep_inv * ha_per_m2 + hio_resp_m_canopy_si_scls(io_si,scls) = hio_resp_m_canopy_si_scls(io_si,scls) + & + ccohort%resp_m * ccohort%n * 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) + & + resp_g * ccohort%n * dt_tstep_inv * ha_per_m2 + hio_resp_m_understory_si_scls(io_si,scls) = hio_resp_m_understory_si_scls(io_si,scls) + & + ccohort%resp_m * ccohort%n * dt_tstep_inv * ha_per_m2 + endif + end associate endif - !!! canopy leaf carbon balance +!!! 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) * per_dt_tstep * ccohort%c_area * area_inv + ccohort%ts_net_uptake(ileaf) * dt_tstep_inv * ccohort%c_area * area_inv end do ccohort => ccohort%taller enddo ! cohort loop + ! summarize radiation profiles through the canopy - do ipft=1,numpft - do ican=1,cpatch%ncl_p - do ileaf=1,cpatch%ncan(ican,ipft) + ! -------------------------------------------------------------------- + + do_pft1: do ipft=1,numpft + do_canlev1: do ican=1,cpatch%ncl_p + do_leaflev1: do ileaf=1,cpatch%ncan(ican,ipft) + ! calculate where we are on multiplexed dimensions - cnlfpft_indx = ileaf + (ican-1) * nlevleaf + (ipft-1) * nlevleaf * nclmax + clllpf_indx = ileaf + (ican-1) * nlevleaf + (ipft-1) * nlevleaf * nclmax cnlf_indx = ileaf + (ican-1) * nlevleaf - ! - ! first do all the canopy x leaf x pft calculations - hio_parsun_z_si_cnlfpft(io_si,cnlfpft_indx) = hio_parsun_z_si_cnlfpft(io_si,cnlfpft_indx) + & - cpatch%ed_parsun_z(ican,ipft,ileaf) * cpatch%area * AREA_INV - hio_parsha_z_si_cnlfpft(io_si,cnlfpft_indx) = hio_parsha_z_si_cnlfpft(io_si,cnlfpft_indx) + & - cpatch%ed_parsha_z(ican,ipft,ileaf) * cpatch%area * AREA_INV - ! - hio_laisun_z_si_cnlfpft(io_si,cnlfpft_indx) = hio_laisun_z_si_cnlfpft(io_si,cnlfpft_indx) + & - cpatch%ed_laisun_z(ican,ipft,ileaf) * cpatch%area * AREA_INV - hio_laisha_z_si_cnlfpft(io_si,cnlfpft_indx) = hio_laisha_z_si_cnlfpft(io_si,cnlfpft_indx) + & - cpatch%ed_laisha_z(ican,ipft,ileaf) * cpatch%area * AREA_INV - ! - hio_fabd_sun_si_cnlfpft(io_si,cnlfpft_indx) = hio_fabd_sun_si_cnlfpft(io_si,cnlfpft_indx) + & - cpatch%fabd_sun_z(ican,ipft,ileaf) * cpatch%area * AREA_INV - hio_fabd_sha_si_cnlfpft(io_si,cnlfpft_indx) = hio_fabd_sha_si_cnlfpft(io_si,cnlfpft_indx) + & - cpatch%fabd_sha_z(ican,ipft,ileaf) * cpatch%area * AREA_INV - hio_fabi_sun_si_cnlfpft(io_si,cnlfpft_indx) = hio_fabi_sun_si_cnlfpft(io_si,cnlfpft_indx) + & - cpatch%fabi_sun_z(ican,ipft,ileaf) * cpatch%area * AREA_INV - hio_fabi_sha_si_cnlfpft(io_si,cnlfpft_indx) = hio_fabi_sha_si_cnlfpft(io_si,cnlfpft_indx) + & - cpatch%fabi_sha_z(ican,ipft,ileaf) * cpatch%area * AREA_INV - ! - hio_parprof_dir_si_cnlfpft(io_si,cnlfpft_indx) = hio_parprof_dir_si_cnlfpft(io_si,cnlfpft_indx) + & - cpatch%parprof_pft_dir_z(ican,ipft,ileaf) * cpatch%area * AREA_INV - hio_parprof_dif_si_cnlfpft(io_si,cnlfpft_indx) = hio_parprof_dif_si_cnlfpft(io_si,cnlfpft_indx) + & - cpatch%parprof_pft_dif_z(ican,ipft,ileaf) * cpatch%area * AREA_INV - ! - ! summarize across all PFTs + + ! 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 + + hio_parprof_dir_si_cnlfpft(io_si,clllpf_indx) = hio_parprof_dir_si_cnlfpft(io_si,clllpf_indx) + & + cpatch%parprof_pft_dir_z(ican,ipft,ileaf) * clllpf_area + + hio_parprof_dif_si_cnlfpft(io_si,clllpf_indx) = hio_parprof_dif_si_cnlfpft(io_si,clllpf_indx) + & + cpatch%parprof_pft_dif_z(ican,ipft,ileaf) * 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) + & + cpatch%parprof_pft_dir_z(ican,ipft,ileaf) * clllpf_area + + hio_parprof_dif_si_cnlf(io_si,cnlf_indx) = hio_parprof_dif_si_cnlf(io_si,cnlf_indx) + & + cpatch%parprof_pft_dif_z(ican,ipft,ileaf) * 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) * cpatch%area * AREA_INV + 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) * cpatch%area * AREA_INV - ! + 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%ed_laisun_z(ican,ipft,ileaf) * cpatch%area * AREA_INV + 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) + & - cpatch%ed_laisha_z(ican,ipft,ileaf) * cpatch%area * AREA_INV - ! - hio_fabd_sun_si_cnlf(io_si,cnlf_indx) = hio_fabd_sun_si_cnlf(io_si,cnlf_indx) + & - cpatch%fabd_sun_z(ican,ipft,ileaf) * cpatch%area * AREA_INV - hio_fabd_sha_si_cnlf(io_si,cnlf_indx) = hio_fabd_sha_si_cnlf(io_si,cnlf_indx) + & - cpatch%fabd_sha_z(ican,ipft,ileaf) * cpatch%area * AREA_INV - hio_fabi_sun_si_cnlf(io_si,cnlf_indx) = hio_fabi_sun_si_cnlf(io_si,cnlf_indx) + & - cpatch%fabi_sun_z(ican,ipft,ileaf) * cpatch%area * AREA_INV - hio_fabi_sha_si_cnlf(io_si,cnlf_indx) = hio_fabi_sha_si_cnlf(io_si,cnlf_indx) + & - cpatch%fabi_sha_z(ican,ipft,ileaf) * cpatch%area * AREA_INV - - end do - ! - ! summarize just the top leaf level across all PFTs, for each canopy level - hio_parsun_top_si_can(io_si,ican) = hio_parsun_top_si_can(io_si,ican) + & - cpatch%ed_parsun_z(ican,ipft,1) * cpatch%area * AREA_INV - hio_parsha_top_si_can(io_si,ican) = hio_parsha_top_si_can(io_si,ican) + & - cpatch%ed_parsha_z(ican,ipft,1) * cpatch%area * AREA_INV - ! - hio_laisun_top_si_can(io_si,ican) = hio_laisun_top_si_can(io_si,ican) + & - cpatch%ed_laisun_z(ican,ipft,1) * cpatch%area * AREA_INV - hio_laisha_top_si_can(io_si,ican) = hio_laisha_top_si_can(io_si,ican) + & - cpatch%ed_laisha_z(ican,ipft,1) * cpatch%area * AREA_INV - ! - hio_fabd_sun_top_si_can(io_si,ican) = hio_fabd_sun_top_si_can(io_si,ican) + & - cpatch%fabd_sun_z(ican,ipft,1) * cpatch%area * AREA_INV - hio_fabd_sha_top_si_can(io_si,ican) = hio_fabd_sha_top_si_can(io_si,ican) + & - cpatch%fabd_sha_z(ican,ipft,1) * cpatch%area * AREA_INV - hio_fabi_sun_top_si_can(io_si,ican) = hio_fabi_sun_top_si_can(io_si,ican) + & - cpatch%fabi_sun_z(ican,ipft,1) * cpatch%area * AREA_INV - hio_fabi_sha_top_si_can(io_si,ican) = hio_fabi_sha_top_si_can(io_si,ican) + & - cpatch%fabi_sha_z(ican,ipft,1) * cpatch%area * AREA_INV - ! - end do - end do + (1._r8-cpatch%f_sun(ican,ipft,ileaf))*clllpf_area - ! PFT-mean radiation profiles - do ican = 1, cpatch%ncl_p - do ileaf = 1, maxval(cpatch%nrad(ican,:)) + ! Canopy mean diagnostics + ! -------------------------------------------------------------- - ! calculate where we are on multiplexed dimensions - cnlf_indx = ileaf + (ican-1) * nlevleaf - ! - hio_parprof_dir_si_cnlf(io_si,cnlf_indx) = hio_parprof_dir_si_cnlf(io_si,cnlf_indx) + & - cpatch%parprof_dir_z(ican,ileaf) * cpatch%area * AREA_INV - hio_parprof_dif_si_cnlf(io_si,cnlf_indx) = hio_parprof_dif_si_cnlf(io_si,cnlf_indx) + & - cpatch%parprof_dif_z(ican,ileaf) * cpatch%area * AREA_INV - end do - end do + 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 - ipa = ipa + 1 cpatch => cpatch%younger end do !patch loop + ! Normalize the radiation multiplexed diagnostics + ! Set values that dont have canopy elements to ignore + ! ---------------------------------------------------------------------------- + + 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)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, & + hio_sapflow_si => this%hvars(ih_sapflow_si)%r81d, & + hio_rootuptake_si => this%hvars(ih_rootuptake_si)%r81d, & + hio_h2oveg_si => this%hvars(ih_h2oveg_si)%r81d ) + + do s = 1,nsites + + 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 + + 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 + ! -------------------------------------------------------------------- + + mean_soil_vwc = 0._r8 + mean_soil_matpot = 0._r8 + mean_soil_vwcsat = 0._r8 + areaweight = 0._r8 + + 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 + + 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) + + ! 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 - 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_sapflow_si => this%hvars(ih_sapflow_si)%r81d, & - hio_iterh1_scpf => this%hvars(ih_iterh1_scpf)%r82d, & - hio_iterh2_scpf => this%hvars(ih_iterh2_scpf)%r82d, & - hio_ath_scpf => this%hvars(ih_ath_scpf)%r82d, & - hio_tth_scpf => this%hvars(ih_tth_scpf)%r82d, & - hio_sth_scpf => this%hvars(ih_sth_scpf)%r82d, & - hio_lth_scpf => this%hvars(ih_lth_scpf)%r82d, & - hio_awp_scpf => this%hvars(ih_awp_scpf)%r82d, & - hio_twp_scpf => this%hvars(ih_twp_scpf)%r82d, & - hio_swp_scpf => this%hvars(ih_swp_scpf)%r82d, & - hio_lwp_scpf => this%hvars(ih_lwp_scpf)%r82d, & - hio_aflc_scpf => this%hvars(ih_aflc_scpf)%r82d, & - hio_tflc_scpf => this%hvars(ih_tflc_scpf)%r82d, & - 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_h2oveg_si => this%hvars(ih_h2oveg_si)%r81d, & - hio_nplant_si_scpf => this%hvars(ih_nplant_si_scpf)%r82d, & - hio_nplant_si_capf => this%hvars(ih_nplant_si_capf)%r82d, & - 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, & - hio_soilmatpot_sl => this%hvars(ih_soilmatpot_sl)%r82d, & - hio_soilvwc_sl => this%hvars(ih_soilvwc_sl)%r82d, & - hio_soilvwcsat_sl => this%hvars(ih_soilvwcsat_sl)%r82d, & - hio_rootuptake_si => this%hvars(ih_rootuptake_si)%r81d, & - hio_rootuptake_sl => this%hvars(ih_rootuptake_sl)%r82d, & - hio_rootuptake0_scpf => this%hvars(ih_rootuptake0_scpf)%r82d, & - hio_rootuptake10_scpf => this%hvars(ih_rootuptake10_scpf)%r82d, & - hio_rootuptake50_scpf => this%hvars(ih_rootuptake50_scpf)%r82d, & - hio_rootuptake100_scpf => this%hvars(ih_rootuptake100_scpf)%r82d ) - - ! Flush the relevant history variables - call this%flush_hvars(nc,upfreq_in=4) - - per_dt_tstep = 1._r8 / dt_tstep - - if(print_iterations) then - do iscpf = 1,iterh2_nhist - iterh2_histx(iscpf) = iterh2_dx*real(iscpf-1,r8) - end do - end if - do s = 1,nsites - - call this%zero_site_hvars(sites(s),upfreq_in=4) - - site_hydr => sites(s)%si_hydr - nlevrhiz = site_hydr%nlevrhiz - nlevsoil = bc_in(s)%nlevsoil - io_si = sites(s)%h_gid + 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 - hio_h2oveg_si(io_si) = site_hydr%h2oveg - hio_h2oveg_hydro_err_si(io_si) = site_hydr%h2oveg_hydro_err + 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_rootuptake_sl(io_si,1:nlevsoil) = site_hydr%rootuptake_sl(1:nlevsoil) - hio_rootuptake_si(io_si) = sum(site_hydr%rootuptake_sl,dim=1) + end do + end associate + end if if_hifrq0 + + if_hifrq1: if(hlm_hist_level_hifrq>1) then + + 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, & + hio_iterh2_scpf => this%hvars(ih_iterh2_scpf)%r82d, & + hio_ath_scpf => this%hvars(ih_ath_scpf)%r82d, & + hio_tth_scpf => this%hvars(ih_tth_scpf)%r82d, & + hio_sth_scpf => this%hvars(ih_sth_scpf)%r82d, & + hio_lth_scpf => this%hvars(ih_lth_scpf)%r82d, & + hio_awp_scpf => this%hvars(ih_awp_scpf)%r82d, & + hio_twp_scpf => this%hvars(ih_twp_scpf)%r82d, & + hio_swp_scpf => this%hvars(ih_swp_scpf)%r82d, & + hio_lwp_scpf => this%hvars(ih_lwp_scpf)%r82d, & + hio_aflc_scpf => this%hvars(ih_aflc_scpf)%r82d, & + hio_tflc_scpf => this%hvars(ih_tflc_scpf)%r82d, & + 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, & + hio_soilvwc_sl => this%hvars(ih_soilvwc_sl)%r82d, & + hio_soilvwcsat_sl => this%hvars(ih_soilvwcsat_sl)%r82d, & + hio_rootuptake_sl => this%hvars(ih_rootuptake_sl)%r82d, & + hio_rootuptake0_scpf => this%hvars(ih_rootuptake0_scpf)%r82d, & + hio_rootuptake10_scpf => this%hvars(ih_rootuptake10_scpf)%r82d, & + 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) - ! Get column means of some soil diagnostics, these are weighted - ! by the amount of fine-root surface area in each layer - ! -------------------------------------------------------------------- + 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 - 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) + + hio_rootuptake_sl(io_si,1:nlevsoil) = site_hydr%rootuptake_sl(1:nlevsoil) - do j=1,nlevrhiz + ! Get column means of some soil diagnostics, these are weighted + ! by the amount of fine-root surface area in each 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 + mean_soil_vwc = 0._r8 + mean_soil_matpot = 0._r8 + mean_soil_vwcsat = 0._r8 + areaweight = 0._r8 - 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) - - ! 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 - - 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 - - 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 - + do j=1,nlevrhiz - ! 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 + 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 - ! Generate a histogram of the the iteration counts - if(print_iterations) then - iterh2_histy(:) = 0._r8 - cpatch => sites(s)%oldest_patch - do while(associated(cpatch)) - ccohort => cpatch%shortest - do while(associated(ccohort)) - ccohort_hydr => ccohort%co_hydr - ix = count((iterh2_histx(:)-0.00001_r8) < ccohort_hydr%iterh2 ) - iterh2_histy(ix) = iterh2_histy(ix) + 1 - ccohort => ccohort%taller - enddo ! cohort loop - cpatch => cpatch%younger - end do !patch loop - end if + 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 - 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 - hio_iterh1_scpf(io_si,iscpf) = 0._r8 - hio_iterh2_scpf(io_si,iscpf) = 0._r8 - end do - end do + ! If there are no roots, we use depth weighting + else + layer_areaweight = bc_in(s)%dz_sisl(j_bc) + endif - ipa = 0 - cpatch => sites(s)%oldest_patch - do while(associated(cpatch)) + 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 - ccohort => cpatch%shortest - do while(associated(ccohort)) + 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 - ccohort_hydr => ccohort%co_hydr + end do + end do - if ( .not. ccohort%isnew ) then + ! 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 - ! Calculate index for the scpf class - iscpf = ccohort%size_by_pft_class + ipa = 0 + cpatch => sites(s)%oldest_patch + do while(associated(cpatch)) - ! scale up cohort fluxes to their sites - number_fraction_rate = (ccohort%n / nplant_scpf(iscpf)) * per_dt_tstep + ccohort => cpatch%shortest + do while(associated(ccohort)) - ! scale cohorts to mean quantity - number_fraction = (ccohort%n / nplant_scpf(iscpf)) + ccohort_hydr => ccohort%co_hydr - hio_errh2o_scpf(io_si,iscpf) = hio_errh2o_scpf(io_si,iscpf) + & - ccohort_hydr%errh2o * number_fraction_rate ! [kg/indiv/s] + if ( .not. ccohort%isnew ) then - hio_tran_scpf(io_si,iscpf) = hio_tran_scpf(io_si,iscpf) + & - (ccohort_hydr%qtop) * number_fraction_rate ! [kg/indiv/s] + ! Calculate index for the scpf class + iscpf = ccohort%size_by_pft_class - hio_iterh1_scpf(io_si,iscpf) = hio_iterh1_scpf(io_si,iscpf) + & - ccohort_hydr%iterh1/ncohort_scpf(iscpf) + ! scale up cohort fluxes to their sites + number_fraction_rate = (ccohort%n / nplant_scpf(iscpf)) * per_dt_tstep - hio_iterh2_scpf(io_si,iscpf) = hio_iterh2_scpf(io_si,iscpf) + & - ccohort_hydr%iterh2/ncohort_scpf(iscpf) + ! scale cohorts to mean quantity + number_fraction = (ccohort%n / nplant_scpf(iscpf)) - mean_aroot = sum(ccohort_hydr%th_aroot(:)*ccohort_hydr%v_aroot_layer(:)) / & - sum(ccohort_hydr%v_aroot_layer(:)) + hio_errh2o_scpf(io_si,iscpf) = hio_errh2o_scpf(io_si,iscpf) + & + ccohort_hydr%errh2o * number_fraction_rate ! [kg/indiv/s] - hio_ath_scpf(io_si,iscpf) = hio_ath_scpf(io_si,iscpf) + & - mean_aroot * number_fraction ! [m3 m-3] + hio_tran_scpf(io_si,iscpf) = hio_tran_scpf(io_si,iscpf) + & + (ccohort_hydr%qtop) * number_fraction_rate ! [kg/indiv/s] - hio_tth_scpf(io_si,iscpf) = hio_tth_scpf(io_si,iscpf) + & - ccohort_hydr%th_troot * number_fraction ! [m3 m-3] + hio_iterh1_scpf(io_si,iscpf) = hio_iterh1_scpf(io_si,iscpf) + & + ccohort_hydr%iterh1/ncohort_scpf(iscpf) - hio_sth_scpf(io_si,iscpf) = hio_sth_scpf(io_si,iscpf) + & - ccohort_hydr%th_ag(2) * number_fraction ! [m3 m-3] + hio_iterh2_scpf(io_si,iscpf) = hio_iterh2_scpf(io_si,iscpf) + & + ccohort_hydr%iterh2/ncohort_scpf(iscpf) - hio_lth_scpf(io_si,iscpf) = hio_lth_scpf(io_si,iscpf) + & - ccohort_hydr%th_ag(1) * number_fraction ! [m3 m-3] + mean_aroot = sum(ccohort_hydr%th_aroot(:)*ccohort_hydr%v_aroot_layer(:)) / & + sum(ccohort_hydr%v_aroot_layer(:)) - mean_aroot = sum(ccohort_hydr%psi_aroot(:)*ccohort_hydr%v_aroot_layer(:)) / & - sum(ccohort_hydr%v_aroot_layer(:)) + hio_ath_scpf(io_si,iscpf) = hio_ath_scpf(io_si,iscpf) + & + mean_aroot * 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] + hio_tth_scpf(io_si,iscpf) = hio_tth_scpf(io_si,iscpf) + & + ccohort_hydr%th_troot * number_fraction ! [m3 m-3] - hio_twp_scpf(io_si,iscpf) = hio_twp_scpf(io_si,iscpf) + & - ccohort_hydr%psi_troot * number_fraction * pa_per_mpa ! [Pa] + hio_sth_scpf(io_si,iscpf) = hio_sth_scpf(io_si,iscpf) + & + ccohort_hydr%th_ag(2) * number_fraction ! [m3 m-3] - hio_swp_scpf(io_si,iscpf) = hio_swp_scpf(io_si,iscpf) + & - ccohort_hydr%psi_ag(2) * number_fraction * pa_per_mpa ! [Pa] + hio_lth_scpf(io_si,iscpf) = hio_lth_scpf(io_si,iscpf) + & + ccohort_hydr%th_ag(1) * number_fraction ! [m3 m-3] - hio_lwp_scpf(io_si,iscpf) = hio_lwp_scpf(io_si,iscpf) + & - ccohort_hydr%psi_ag(1) * number_fraction * pa_per_mpa ! [Pa] + mean_aroot = sum(ccohort_hydr%psi_aroot(:)*ccohort_hydr%v_aroot_layer(:)) / & + sum(ccohort_hydr%v_aroot_layer(:)) - 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_awp_scpf(io_si,iscpf) = hio_awp_scpf(io_si,iscpf) + & + mean_aroot * number_fraction * pa_per_mpa ! [Pa] - hio_tflc_scpf(io_si,iscpf) = hio_tflc_scpf(io_si,iscpf) + & - ccohort_hydr%ftc_troot * number_fraction + hio_twp_scpf(io_si,iscpf) = hio_twp_scpf(io_si,iscpf) + & + ccohort_hydr%psi_troot * number_fraction * pa_per_mpa ! [Pa] - hio_sflc_scpf(io_si,iscpf) = hio_sflc_scpf(io_si,iscpf) + & - ccohort_hydr%ftc_ag(2) * number_fraction + hio_swp_scpf(io_si,iscpf) = hio_swp_scpf(io_si,iscpf) + & + ccohort_hydr%psi_ag(2) * number_fraction * pa_per_mpa ! [Pa] - hio_lflc_scpf(io_si,iscpf) = hio_lflc_scpf(io_si,iscpf) + & - ccohort_hydr%ftc_ag(1) * 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_btran_scpf(io_si,iscpf) = hio_btran_scpf(io_si,iscpf) + & - ccohort_hydr%btran * 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 - endif + hio_tflc_scpf(io_si,iscpf) = hio_tflc_scpf(io_si,iscpf) + & + ccohort_hydr%ftc_troot * number_fraction - ccohort => ccohort%taller - enddo ! cohort loop - ipa = ipa + 1 - cpatch => cpatch%younger - end do !patch loop + hio_sflc_scpf(io_si,iscpf) = hio_sflc_scpf(io_si,iscpf) + & + ccohort_hydr%ftc_ag(2) * number_fraction - 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 + hio_lflc_scpf(io_si,iscpf) = hio_lflc_scpf(io_si,iscpf) + & + ccohort_hydr%ftc_ag(1) * number_fraction - if(print_iterations) then - write(fmt_char,'(I2)') iterh2_nhist - write(fates_log(),fmt='(A,'//fmt_char//'I5)') 'Solves: ',int(iterh2_histy(:)) - end if + hio_btran_scpf(io_si,iscpf) = hio_btran_scpf(io_si,iscpf) + & + ccohort_hydr%btran * number_fraction ! [-] + + endif + ccohort => ccohort%taller + enddo ! cohort loop + ipa = ipa + 1 + cpatch => cpatch%younger + end do !patch 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 + end do + end associate - enddo ! site loop + end if if_hifrq1 - end associate + end subroutine update_history_hydraulics - end subroutine update_history_hydraulics ! ==================================================================================== integer function num_history_vars(this) @@ -5323,17 +6001,17 @@ subroutine initialize_history_vars(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.) + ! construct the object that defines all of the IO variables + call this%define_history_vars(initialize_variables=.true.) - end subroutine initialize_history_vars + end subroutine initialize_history_vars ! ==================================================================================== @@ -5370,7 +6048,7 @@ subroutine define_history_vars(this, initialize_variables) 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 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 @@ -5378,7 +6056,6 @@ subroutine define_history_vars(this, initialize_variables) 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 - use FatesIOVariableKindMod, only : site_landuse_r8, site_lulu_r8 implicit none @@ -5406,7 +6083,7 @@ subroutine define_history_vars(this, initialize_variables) ! 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 @@ -5421,3103 +6098,3101 @@ subroutine define_history_vars(this, initialize_variables) ! cohort size x crown damage (site_cdsc_r8) : SZCD ! cohort size x crown damage x pft (site_cdpf_r8) : CDPF - ! Site level counting variables - call this%set_history_var(vname='FATES_NPATCHES', units='', & - long='total number of patches per site', use_default='active', & - avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index=ih_npatches_si) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index=ih_ncohorts_si) - - call this%set_history_var(vname='FATES_NPATCHES_SECONDARY', units='', & - long='total number of patches per site', use_default='active', & - avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index=ih_npatches_sec_si) - - call this%set_history_var(vname='FATES_NCOHORTS_SECONDARY', units='', & - long='total number of cohorts per site', use_default='active', & - avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index=ih_ncohorts_sec_si) - - ! Patch variables - call this%set_history_var(vname='FATES_TRIMMING', units='1', & - long='degree to which canopy expansion is limited by leaf economics (0-1)', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index=ih_trimming_si) - - - - - - call this%set_history_var(vname='FATES_AREA_PLANTS', units='m2 m-2', & - long='area occupied by all plants per m2 land area', use_default='active', & - avgflag='A', vtype=site_r8, hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index=ih_area_plant_si) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index=ih_area_trees_si) - - call this%set_history_var(vname='FATES_FRACTION', units='m2 m-2', & - long='total gridcell fraction which FATES is running over', use_default='active', & - avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index=ih_fates_fraction_si, flush_to_zero=.true.) - - call this%set_history_var(vname='FATES_BA_WEIGHTED_HEIGHT', units='m', & - long='basal area-weighted mean height of woody plants', use_default='active', & - avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index=ih_ba_weighted_height_si) - - call this%set_history_var(vname='FATES_CA_WEIGHTED_HEIGHT', units='m', & - long='crown area-weighted mean height of canopy plants', use_default='active', & - avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index=ih_ca_weighted_height_si) - - call this%set_history_var(vname='FATES_COLD_STATUS', units='', & - long='site-level cold status, 0=not cold-dec, 1=too cold for leaves, 2=not too cold', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index=ih_site_cstatus_si) - - call this%set_history_var(vname='FATES_GDD', units='degree_Celsius', & - long='site-level growing degree days', use_default='active', & - avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, index=ih_gdd_si) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index=ih_site_nchilldays_si) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index=ih_site_ncolddays_si) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index=ih_cleafoff_si) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index=ih_cleafon_si) - - call this%set_history_var(vname='FATES_CANOPY_SPREAD', units='', & - long='scaling factor (0-1) between tree basal area and canopy area', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index=ih_canopy_spread_si) - - call this%set_history_var(vname='FATES_LAI', units='m2 m-2', & - long='leaf area index per m2 land area', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index=ih_lai_si) - - call this%set_history_var(vname='FATES_VEGC_PF', units='kg m-2', & - long='total PFT-level biomass in kg of carbon per land area', & - use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index=ih_biomass_si_pft) - - call this%set_history_var(vname='FATES_VEGC_SE_PF', units='kg m-2', & - long='total PFT-level biomass in kg of carbon per land area, secondary patches', & - use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index=ih_biomass_sec_si_pft) - - call this%set_history_var(vname='FATES_LEAFC_PF', units='kg m-2', & - long='total PFT-level leaf biomass in kg carbon per m2 land area', & - use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index=ih_leafbiomass_si_pft) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index=ih_storebiomass_si_pft) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index=ih_crownarea_si_pft) - - 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=1, 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', & - 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=1, 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', & - long='total PFT-level NPP in kg carbon per m2 land area per second', & - use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index=ih_npp_si_pft) - - call this%set_history_var(vname='FATES_GPP_SE_PF', units='kg m-2 s-1', & - long='total PFT-level GPP in kg carbon per m2 land area per second, secondary patches', & - use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index=ih_gpp_sec_si_pft) - - call this%set_history_var(vname='FATES_NPP_SE_PF', units='kg m-2 s-1', & - long='total PFT-level NPP in kg carbon per m2 land area per second, secondary patches', & - use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index=ih_npp_sec_si_pft) - - call this%set_history_var(vname='FATES_NPLANT_PF', units='m-2', & - long='total PFT-level number of individuals per m2 land area', & - use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index=ih_nindivs_si_pft) - - call this%set_history_var(vname='FATES_NPLANT_SEC_PF', units='m-2', & - long='total PFT-level number of individuals per m2 land area, secondary patches', & - use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index=ih_nindivs_sec_si_pft) - - call this%set_history_var(vname='FATES_RECRUITMENT_PF', & - units='m-2 yr-1', & - long='PFT-level recruitment rate in number of individuals per m2 land area per year', & - use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index=ih_recruitment_si_pft) - - call this%set_history_var(vname='FATES_SEEDS_IN_GRIDCELL_PF', & - units='kg', & - long='Site-level seed mass input from neighboring gridcells per pft', & - use_default='inactive', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index=ih_seeds_in_gc_si_pft) - - call this%set_history_var(vname='FATES_SEEDS_OUT_GRIDCELL_PF', & - units='kg', & - long='Site-level seed mass output to neighboring gridcells per pft', & - use_default='inactive', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index=ih_seeds_out_gc_si_pft) - - call this%set_history_var(vname='FATES_MORTALITY_PF', units='m-2 yr-1', & - long='PFT-level mortality rate in number of individuals per m2 land area per year', & - use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index=ih_mortality_si_pft) - - !MLO - Drought-deciduous phenology variables are now defined for each PFT. - call this%set_history_var(vname='FATES_DROUGHT_STATUS_PF', & - units='', & - long='PFT-level drought status, <2 too dry for leaves, >=2 not too dry', & - use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index=ih_site_dstatus_si_pft) - - call this%set_history_var(vname='FATES_DAYSINCE_DROUGHTLEAFOFF_PF', & - units='days', long='PFT-level days elapsed since drought leaf drop', & - use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index=ih_dleafoff_si_pft) - - call this%set_history_var(vname='FATES_DAYSINCE_DROUGHTLEAFON_PF', & - units='days', & - long='PFT-level days elapsed since drought leaf flush', & - use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index=ih_dleafon_si_pft) - - call this%set_history_var(vname='FATES_MEANLIQVOL_DROUGHTPHEN_PF', & - units='m3 m-3', & - long='PFT-level mean liquid water volume for drought phenolgy', & - use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index=ih_meanliqvol_si_pft) - - call this%set_history_var(vname='FATES_MEANSMP_DROUGHTPHEN_PF', & - units='Pa', & - long='PFT-level mean soil matric potential for drought phenology', & - use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index=ih_meansmp_si_pft) - - call this%set_history_var(vname='FATES_ELONG_FACTOR_PF', & - units='1', & - long='PFT-level mean elongation factor (partial flushing/abscission)', & - use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index=ih_elong_factor_si_pft) - - nocomp_if: if (hlm_use_nocomp .eq. itrue) then - call this%set_history_var(vname='FATES_NOCOMP_NPATCHES_PF', units='', & - long='number of patches per PFT (nocomp-mode-only)', & - use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & - upfreq=1, 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',& - long='total patch area allowed per PFT (nocomp-mode-only)', & - use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index=ih_nocomp_pftpatchfraction_si_pft) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index=ih_nocomp_pftburnedarea_si_pft) - endif nocomp_if - - ! 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=1, ivar=ivar, & - initialize=initialize_variables, index=ih_area_si_age) - - call this%set_history_var(vname='FATES_LAI_AP', units='m2 m-2', & - long='leaf area index by age bin per m2 land area', & - use_default='active', avgflag='A', vtype=site_age_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index=ih_lai_si_age) - - call this%set_history_var(vname='FATES_LAI_SECONDARY', units='m2 m-2', & - long='leaf area index per m2 land area, secondary patches', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index=ih_lai_secondary_si) - - call this%set_history_var(vname='FATES_CANOPYAREA_AP', units='m2 m-2', & - long='canopy area by age bin per m2 land area', use_default='active', & - avgflag='A', vtype=site_age_r8, hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index=ih_canopy_area_si_age) - - call this%set_history_var(vname='FATES_NCL_AP', units='', & - long='number of canopy levels by age bin', & - use_default='inactive', avgflag='A', vtype=site_age_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, initialize=initialize_variables, & - index=ih_ncl_si_age) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index=ih_npatches_si_age) - - if ( ED_val_comp_excln .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', & - 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=1, ivar=ivar, initialize=initialize_variables, & - index=ih_zstar_si_age) - - 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=1, 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', & - long='leaf area height distribution', use_default='active', & - avgflag='A', vtype=site_height_r8, hlms='CLM:ALM', & - upfreq=1, 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', & - 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=1, ivar=ivar, initialize=initialize_variables, & - index=ih_biomass_si_age) - - ! land use type resolved variables - 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=1, ivar=ivar, & - initialize=initialize_variables, index=ih_area_si_landuse) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index=ih_disturbance_rate_si_lulu) - - ! Secondary forest area and age diagnostics - - call this%set_history_var(vname='FATES_SECONDARY_FOREST_FRACTION', & - units='m2 m-2', long='secondary forest fraction', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index=ih_fraction_secondary_forest_si) - - call this%set_history_var(vname='FATES_WOOD_PRODUCT', units='kg m-2', & - long='total wood product from logging in kg carbon per m2 land area', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index=ih_woodproduct_si) - - call this%set_history_var(vname='FATES_SECONDARY_FOREST_VEGC', & - units='kg m-2', & - long='biomass on secondary lands in kg carbon per m2 land area (mult by FATES_SECONDARY_FOREST_FRACTION to get per secondary forest area)', & - use_default='active', avgflag='A', vtype=site_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, initialize=initialize_variables, & - index=ih_biomass_secondary_forest_si) - - call this%set_history_var(vname='FATES_SECONDAREA_ANTHRODIST_AP', & - units='m2 m-2', & - long='secondary forest patch area age distribution since anthropgenic disturbance', & - use_default='inactive', avgflag='A', vtype=site_age_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, initialize=initialize_variables, & - index=ih_agesince_anthrodist_si_age) - - call this%set_history_var(vname='FATES_SECONDAREA_DIST_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=1, ivar=ivar, initialize=initialize_variables, & - index=ih_secondarylands_area_si_age) - - ! 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=1, ivar=ivar, initialize=initialize_variables, & - index=ih_nesterov_fire_danger_si) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index=ih_fire_nignitions_si) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index=ih_fire_fdi_si) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index=ih_spitfire_ros_si) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index=ih_effect_wspeed_si) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index=ih_tfc_ros_si) - - 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', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index=ih_fire_intensity_si) - - 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 -- divide by FATES_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_fire_intensity_area_product_si) - - call this%set_history_var(vname='FATES_BURNFRAC', units='s-1', & - long='burned area fraction per second', use_default='active', & - avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index=ih_fire_area_si) - - call this%set_history_var(vname='FATES_FUEL_MEF', units='m3 m-3', & - long='fuel moisture of extinction (volumetric)', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index=ih_fire_fuel_mef_si) - - 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=1, 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', & - avgflag='A', vtype=site_r8, hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_fire_fuel_eff_moist_si) - - call this%set_history_var(vname='FATES_FUEL_SAV', units='m-1', & - long='spitfire fuel surface area to volume ratio', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - 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', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index = ih_sum_fuel_si) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_fragmentation_scaler_sl) - - 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=1, 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', & - 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=1, 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', & - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_fuel_amount_age_fuel) - - call this%set_history_var(vname='FATES_BURNFRAC_AP', units='s-1', & - long='spitfire fraction area burnt (per second) by patch age', & - use_default='active', avgflag='A', vtype=site_age_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index = ih_area_burnt_si_age) - - 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, resolved by patch age (so divide by FATES_BURNFRAC_AP to get burned-area-weighted-average intensity)', & - use_default='active', avgflag='A', vtype=site_age_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index = ih_fire_intensity_si_age) - - 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=1, 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', & - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_burnt_frac_litter_si_fuel) - - ! 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=1, 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', & - long='litter flux out in kg carbon (exudation, fragmentation, seed decay)', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index = ih_litter_out_si) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_seed_bank_si) - - call this%set_history_var(vname='FATES_UNGERM_SEED_BANK', units='kg m-2', & - long='ungerminated seed mass of all PFTs in kg carbon per m2 land area', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index = ih_ungerm_seed_bank_si) - - call this%set_history_var(vname='FATES_SEEDLING_POOL', units='kg m-2', & - long='total seedling (ie germinated seeds) mass of all PFTs in kg carbon per m2 land area', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index = ih_seedling_pool_si) - - call this%set_history_var(vname='FATES_SEEDS_IN', units='kg m-2 s-1', & - long='seed production rate in kg carbon per m2 second', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index = ih_seeds_in_si) - - call this%set_history_var(vname='FATES_SEEDS_IN_LOCAL', units='kg m-2 s-1', & - long='local seed production rate in kg carbon per m2 second', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index = ih_seeds_in_local_si) - - call this%set_history_var(vname='FATES_LITTER_IN_EL', units='kg m-2 s-1', & - long='litter flux in in kg element per m2 per second', & - use_default='active', avgflag='A', vtype=site_elem_r8, & - hlms='CLM:ALM', upfreq=1, 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', & - long='litter flux out (exudation, fragmentation and seed decay) in kg element', & - use_default='active', avgflag='A', vtype=site_elem_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, initialize=initialize_variables, & - index = ih_litter_out_elem) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_seed_bank_elem) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_seeds_in_local_elem) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_seeds_in_extern_elem) - - call this%set_history_var(vname='FATES_SEED_GERM_EL', units='kg m-2', & - long='element-level total germinated seed mass of all PFTs in kg element per m2', & - use_default='active', avgflag='A', vtype=site_elem_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, initialize=initialize_variables, & - index = ih_seed_germ_elem) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_seed_decay_elem) - - ! SITE LEVEL CARBON STATE VARIABLES - - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_storec_si) - - call this%set_history_var(vname='FATES_STOREC_TF', units='kg kg-1', & - long='Storage C fraction of target', use_default='active', & - avgflag='A', vtype=site_r8, hlms='CLM:ALM', upfreq=1, & - ivar=ivar, initialize=initialize_variables, index = ih_storectfrac_si ) - - call this%set_history_var(vname='FATES_STOREC_TF_USTORY_SZPF', units='kg kg-1', & - long='Storage C fraction of target by size x pft, in the understory', use_default='inactive', & - avgflag='A', vtype=site_size_pft_r8, hlms='CLM:ALM', upfreq=1, & - ivar=ivar, initialize=initialize_variables, index = ih_storectfrac_ustory_scpf ) - - - call this%set_history_var(vname='FATES_STOREC_TF_CANOPY_SZPF', units='kg kg-1', & - long='Storage C fraction of target by size x pft, in the canopy', use_default='inactive', & - avgflag='A', vtype=site_size_pft_r8, hlms='CLM:ALM', upfreq=1, & - ivar=ivar, initialize=initialize_variables, index = ih_storectfrac_canopy_scpf ) - - - - call this%set_history_var(vname='FATES_VEGC', units='kg m-2', & - long='total biomass in live plants in kg carbon per m2 land area', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index = ih_totvegc_si) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_sapwc_si) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_leafc_si) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_fnrtc_si) - - call this%set_history_var(vname='FATES_FROOTC_SL', units='kg m-3', & - long='Total carbon in live plant fine-roots over depth', use_default='active', & - avgflag='A', vtype=site_soil_r8, hlms='CLM:ALM', upfreq=1, & - ivar=ivar, initialize=initialize_variables, index = ih_fnrtc_sl ) - - call this%set_history_var(vname='FATES_REPROC', units='kg m-2', & - long='total biomass in live plant reproductive tissues in kg carbon per m2', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index = ih_reproc_si) + 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='', & + 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) + + call this%set_history_var(vname='FATES_NPATCHES_SECONDARY', units='', & + long='total number of patches per site', use_default='active', & + avgflag='A', vtype=site_r8, hlms='CLM:ALM', & + upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & + index=ih_npatches_sec_si) + + call this%set_history_var(vname='FATES_NCOHORTS_SECONDARY', units='', & + long='total number of cohorts per site', use_default='active', & + avgflag='A', vtype=site_r8, hlms='CLM:ALM', & + upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & + index=ih_ncohorts_sec_si) + + ! Patch variables + call this%set_history_var(vname='FATES_TRIMMING', units='1', & + long='degree to which canopy expansion is limited by leaf economics (0-1)', & + 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', & + 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_area_plant_si) + + 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_area_trees_si) + + call this%set_history_var(vname='FATES_FRACTION', units='m2 m-2', & + long='total gridcell fraction which FATES is running over', use_default='active', & + avgflag='A', vtype=site_r8, hlms='CLM:ALM', & + upfreq=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', & + 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', & + 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='', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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='', & + 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', & + 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', & + 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) + + call this%set_history_var(vname='FATES_LAI_SECONDARY', units='m2 m-2', & + long='leaf area index per m2 land area, secondary patches', & + use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & + upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & + index=ih_lai_secondary_si) - ! Output specific to the chemical species dynamics used (parteh) - select case(hlm_parteh_mode) - case (prt_cnp_flex_allom_hyp) + + ! Secondary forest area and age diagnostics + + call this%set_history_var(vname='FATES_SECONDARY_FOREST_FRACTION', & + units='m2 m-2', long='secondary forest fraction', & + use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & + upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & + index=ih_fraction_secondary_forest_si) + + call this%set_history_var(vname='FATES_WOOD_PRODUCT', units='kg m-2', & + long='total wood product from logging in kg carbon per m2 land area', & + use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & + upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & + index=ih_woodproduct_si) + + call this%set_history_var(vname='FATES_SECONDARY_FOREST_VEGC', & + units='kg m-2', & + long='biomass on secondary lands in kg carbon per m2 land area (mult by FATES_SECONDARY_FOREST_FRACTION to get per secondary forest area)', & + use_default='active', avgflag='A', vtype=site_r8, & + hlms='CLM:ALM', upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & + index=ih_biomass_secondary_forest_si) + ! 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_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', & + 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', & + 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', & + 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', & + 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', & + units='J m-1 s-1', & + long='spitfire surface fireline intensity 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_fire_intensity_si) + + 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 -- 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_area_product_si) + + call this%set_history_var(vname='FATES_BURNFRAC', units='s-1', & + long='burned area fraction 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_area_si) + + call this%set_history_var(vname='FATES_FUEL_MEF', units='m3 m-3', & + long='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) + + 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', & + avgflag='A', vtype=site_r8, hlms='CLM:ALM', upfreq=group_dyna_simple, ivar=ivar, & + initialize=initialize_variables, index = ih_fire_fuel_eff_moist_si) + + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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) + + ! 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=1, & + avgflag='A', vtype=site_r8, hlms='CLM:ALM', upfreq=group_dyna_simple, & ivar=ivar, initialize=initialize_variables, index = ih_l2fr_si) - - call this%set_history_var(vname='FATES_L2FR_CANOPY_REC_PF', units='kg kg-1', & - long='The leaf to fineroot biomass multiplier for recruits (canopy)', & - use_default='active', & - avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', upfreq=1, & - ivar=ivar, initialize=initialize_variables, index = ih_recl2fr_canopy_pf) - call this%set_history_var(vname='FATES_L2FR_USTORY_REC_PF', units='kg kg-1', & - long='The leaf to fineroot biomass multiplier for recruits (understory)', & + nitrogen_active_if0: if(any(element_list(:)==nitrogen_element)) then + + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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 + + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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 + + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + long='fates 24-hr running mean vegetation temperature by site', & use_default='active', & - avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', upfreq=1, & - ivar=ivar, initialize=initialize_variables, index = ih_recl2fr_ustory_pf) - - !call this%set_history_var(vname='FATES_L2FR_CLSZPF', units='kg kg-1', & - ! long='The leaf to fineroot biomass multiplier for target allometry', & - ! use_default='inactive', & - ! avgflag='A', vtype=site_clscpf_r8, hlms='CLM:ALM', upfreq=1, & - ! ivar=ivar, initialize=initialize_variables, index = ih_l2fr_clscpf) - - call this%set_history_var(vname='FATES_NH4UPTAKE_SZPF', & - units='kg m-2 s-1', & - long='ammonium uptake rate by plants by size-class x pft in kg NH4 per m2 per second', & - use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & - hlms='CLM:ALM', upfreq=5, ivar=ivar, & - initialize=initialize_variables, index = ih_nh4uptake_scpf) - - call this%set_history_var(vname='FATES_NO3UPTAKE_SZPF', & - units='kg m-2 s-1', & - long='nitrate uptake rate by plants by size-class x pft in kg NO3 per m2 per second', & - use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & - hlms='CLM:ALM', upfreq=5, ivar=ivar, & - initialize=initialize_variables, index = ih_no3uptake_scpf) - - call this%set_history_var(vname='FATES_NEFFLUX_SZPF', units='kg m-2 s-1', & - long='nitrogen efflux, root to soil, by size-class x pft in kg N per m2 per second', & - use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & - hlms='CLM:ALM', upfreq=5, ivar=ivar, & - initialize=initialize_variables, index = ih_nefflux_scpf) - - call this%set_history_var(vname='FATES_NDEMAND_SZPF', units='kg m-2 s-1', & - long='plant N need (algorithm dependent), by size-class x pft in kg N per m2 per second', & - use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & - hlms='CLM:ALM', upfreq=5, ivar=ivar, & - initialize=initialize_variables, index = ih_ndemand_scpf) - - call this%set_history_var(vname='FATES_NFIX_SYM_SZPF', units='kg m-2 s-1', & - long='symbiotic dinitrogen fixation, by size-class x pft in kg N per m2 per second', & - use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & - hlms='CLM:ALM', upfreq=5, ivar=ivar, & - initialize=initialize_variables, index = ih_nfix_scpf) - + 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', & + 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', & + 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', & + 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', & + 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', & + 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) - call this%set_history_var(vname='FATES_NH4UPTAKE', units='kg m-2 s-1', & - long='ammonium uptake rate by plants in kg NH4 per m2 per second', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=5, ivar=ivar, initialize=initialize_variables, & - index = ih_nh4uptake_si) - - call this%set_history_var(vname='FATES_NO3UPTAKE', units='kg m-2 s-1', & - long='nitrate uptake rate by plants in kg NO3 per m2 per second', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=5, ivar=ivar, initialize=initialize_variables, & - index = ih_no3uptake_si) - - call this%set_history_var(vname='FATES_NEFFLUX', units='kg m-2 s-1', & - long='nitrogen effluxed from plant in kg N per m2 per second (unused)', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=5, ivar=ivar, initialize=initialize_variables, & - index = ih_nefflux_si) - - call this%set_history_var(vname='FATES_NDEMAND', units='kg m-2 s-1', & - long='plant nitrogen need (algorithm dependent) in kg N per m2 per second', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=5, ivar=ivar, initialize=initialize_variables, & - index = ih_ndemand_si) - - call this%set_history_var(vname='FATES_NFIX_SYM', units='kg m-2 s-1', & - long='symbiotic dinitrogen fixation in kg N per m2 per second', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=5, ivar=ivar, initialize=initialize_variables, & - index = ih_nfix_si) - end select - - nitrogen_active_if: if(any(element_list(:)==nitrogen_element)) then - call this%set_history_var(vname='FATES_STOREN', units='kg m-2', & - long='total nitrogen in live plant storage', use_default='active', & - avgflag='A', vtype=site_r8, hlms='CLM:ALM', upfreq=1, & - ivar=ivar, initialize=initialize_variables, index = ih_storen_si) - - call this%set_history_var(vname='FATES_STOREN_TF', units='1', & - long='storage N fraction of target', use_default='active', & - avgflag='A', vtype=site_r8, hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_storentfrac_si) - - call this%set_history_var(vname='FATES_VEGN', units='kg m-2', & - long='total nitrogen in live plants', use_default='active', & - avgflag='A', vtype=site_r8, hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_totvegn_si) - - 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=1, & - ivar=ivar, initialize=initialize_variables, index = ih_sapwn_si) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_leafn_si) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_fnrtn_si) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_repron_si) - - call this%set_history_var(vname='FATES_VEGN_SZPF', units='kg m-2', & - long='total (live) vegetation nitrogen mass by size-class x pft in kg N per m2', & - use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_totvegn_scpf) - - call this%set_history_var(vname='FATES_LEAFN_SZPF', units='kg m-2', & - long='leaf nitrogen mass by size-class x pft in kg N per m2', & - use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_leafn_scpf) - - call this%set_history_var(vname='FATES_FROOTN_SZPF', units='kg m-2', & - long='fine-root nitrogen mass by size-class x pft in kg N per m2', & - use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_fnrtn_scpf) - - call this%set_history_var(vname='FATES_SAPWOODN_SZPF', units='kg m-2', & - long='sapwood nitrogen mass by size-class x pft in kg N per m2', & - use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_sapwn_scpf) - - call this%set_history_var(vname='FATES_STOREN_SZPF', units='kg m-2', & - long='storage nitrogen mass by size-class x pft in kg N per m2', & - use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_storen_scpf) - - call this%set_history_var(vname='FATES_STOREN_TF_CANOPY_SZPF', & - units='1', & - long='storage nitrogen fraction (0-1) of target, in canopy, by size-class x pft', & - use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_storentfrac_canopy_scpf) - - call this%set_history_var(vname='FATES_STOREN_TF_USTORY_SZPF', & - units='1', & - long='storage nitrogen fraction (0-1) of target, in understory, by size-class x pft', & - use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, & - index = ih_storentfrac_understory_scpf) - - call this%set_history_var(vname='FATES_REPRON_SZPF', units='kg m-2', & - long='reproductive nitrogen mass (on plant) by size-class x pft in kg N per m2', & - use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_repron_scpf) - - end if nitrogen_active_if - - - phosphorus_active_if: 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_storep_si) - - 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=1, & - ivar=ivar, initialize=initialize_variables, & - index = ih_storeptfrac_si) - - 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=1, & - ivar=ivar, initialize=initialize_variables, index = ih_totvegp_si) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_sapwp_si) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_leafp_si) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_fnrtp_si) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_reprop_si) - - 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=5, ivar=ivar, initialize=initialize_variables, & - index = ih_puptake_si) - - call this%set_history_var(vname='FATES_PEFFLUX', units='kg m-2 s-1', & - long='phosphorus effluxed from plant in kg P per m2 per second (unused)', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=5, ivar=ivar, initialize=initialize_variables, & - index = ih_pefflux_si) - - 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=5, ivar=ivar, initialize=initialize_variables, & - index = ih_pdemand_si) - - call this%set_history_var(vname='FATES_VEGP_SZPF', units='kg m-2', & - long='total (live) vegetation phosphorus mass by size-class x pft in kg P per m2', & - use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_totvegp_scpf) - - call this%set_history_var(vname='FATES_LEAFP_SZPF', units='kg m-2', & - long='leaf phosphorus mass by size-class x pft', use_default='inactive', & - avgflag='A', vtype=site_size_pft_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, index = ih_leafp_scpf ) - - call this%set_history_var(vname='FATES_FROOTP_SZPF', units='kg m-2', & - long='fine-root phosphorus mass by size-class x pft in kg P per m2', & - use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_fnrtp_scpf) - - call this%set_history_var(vname='FATES_SAPWOODP_SZPF', units='kg m-2', & - long='sapwood phosphorus mass by size-class x pft in kg P per m2', & - use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_sapwp_scpf) - - call this%set_history_var(vname='FATES_STOREP_SZPF', units='kg m-2', & - long='storage phosphorus mass by size-class x pft in kg P per m2', & - use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_storep_scpf) - - call this%set_history_var(vname='FATES_STOREP_TF_CANOPY_SZPF', & - units='1', & - long='storage phosphorus fraction (0-1) of target, in canopy, by size-class x pft', & - use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_storeptfrac_canopy_scpf) - - call this%set_history_var(vname='FATES_STOREP_TF_USTORY_SZPF', & - units='1', & - long='storage phosphorus fraction (0-1) of target, in understory, by size-class x pft', & - use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, & - index = ih_storeptfrac_understory_scpf) - - call this%set_history_var(vname='FATES_REPROP_SZPF', units='kg m-2', & - long='reproductive phosphorus mass (on plant) by size-class x pft in kg P per m2', & - use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_reprop_scpf) - - call this%set_history_var(vname='FATES_PUPTAKE_SZPF', & - units='kg m-2 s-1', & - long='phosphorus uptake rate by plants, by size-class x pft in kg P per m2 per second', & - use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & - hlms='CLM:ALM', upfreq=5, ivar=ivar, & - initialize=initialize_variables, index = ih_puptake_scpf) - - call this%set_history_var(vname='FATES_PEFFLUX_SZPF', & - units='kg m-2 s-1', & - long='phosphorus efflux, root to soil, by size-class x pft in kg P per m2 per second', & - use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & - hlms='CLM:ALM', upfreq=5, ivar=ivar, & - initialize=initialize_variables, index = ih_pefflux_scpf) - - call this%set_history_var(vname='FATES_PDEMAND_SZPF', units='kg m-2 s-1', & - long='plant P need (algorithm dependent), by size-class x pft in kg P per m2 per second', & - use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & - hlms='CLM:ALM', upfreq=5, ivar=ivar, & - initialize=initialize_variables, index = ih_pdemand_scpf) - - end if phosphorus_active_if - - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_bdead_si) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_balive_si) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_agb_si) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_canopy_biomass_si) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_understory_biomass_si) - - ! disturbance rates - - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_primaryland_fusion_error_si) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_fire_disturbance_rate_si) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_logging_disturbance_rate_si) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_fall_disturbance_rate_si) - - call this%set_history_var(vname='FATES_HARVEST_CARBON_FLUX', & - units='kg m-2 yr-1', & - long='harvest carbon flux in kg carbon per m2 per year', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index = ih_harvest_carbonflux_si) - - ! Canopy Resistance - - 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=2, 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', & - long='mean leaf boundary layer conductance', use_default='active', & - avgflag='A', vtype=site_r8, hlms='CLM:ALM', upfreq=2, & - ivar=ivar, initialize=initialize_variables, index = ih_c_lblayer_si) - - ! Temperature - - call this%set_history_var(vname='FATES_TVEG24', units='degree_Celsius', & - long='fates 24-hr running mean vegetation temperature by site', & - use_default='active', & - avgflag='A', vtype=site_r8, hlms='CLM:ALM', upfreq=1, & - ivar=ivar, initialize=initialize_variables, index = ih_tveg24_si ) - - call this%set_history_var(vname='FATES_TLONGTERM', units='degree_Celsius', & - long='fates 30-year running mean vegetation temperature by site', & - use_default='inactive', & - avgflag='A', vtype=site_r8, hlms='CLM:ALM', upfreq=1, & - ivar=ivar, initialize=initialize_variables, index = ih_tlongterm_si ) - - call this%set_history_var(vname='FATES_TGROWTH', units='degree_Celsius', & - long='fates long-term running mean vegetation temperature by site', & - use_default='inactive', & - avgflag='A', vtype=site_r8, hlms='CLM:ALM', upfreq=1, & - ivar=ivar, initialize=initialize_variables, index = ih_tgrowth_si ) - - call this%set_history_var(vname='FATES_TVEG', units='degree_Celsius', & - long='fates instantaneous mean vegetation temperature by site', & - use_default='active', & - avgflag='A', vtype=site_r8, hlms='CLM:ALM', upfreq=2, & - ivar=ivar, initialize=initialize_variables, index = ih_tveg_si ) - - ! radiation error - call this%set_history_var(vname='FATES_RAD_ERROR', units='W m-2 ', & - long='radiation error in FATES RTM', use_default='active', & - avgflag='A', vtype=site_r8, hlms='CLM:ALM', upfreq=2, & - ivar=ivar, initialize=initialize_variables, index = ih_rad_error_si) - - call this%set_history_var(vname='FATES_AR', units='gC/m^2/s', & - long='autotrophic respiration', use_default='active', & - avgflag='A', vtype=site_r8, hlms='CLM:ALM', upfreq=2, & - ivar=ivar, initialize=initialize_variables, index = ih_aresp_si ) - - call this%set_history_var(vname='FATES_HARVEST_DEBT', units='kg C', & - long='Accumulated carbon failed to be harvested', use_default='active', & - avgflag='A', vtype=site_r8, hlms='CLM:ALM', upfreq=1, & - ivar=ivar, initialize=initialize_variables, index = ih_harvest_debt_si ) - - call this%set_history_var(vname='FATES_HARVEST_DEBT_SEC', units='kg C', & - long='Accumulated carbon failed to be harvested from secondary patches', use_default='active', & - avgflag='A', vtype=site_r8, hlms='CLM:ALM', upfreq=1, & - ivar=ivar, initialize=initialize_variables, index = ih_harvest_debt_sec_si ) - - - - ! Ecosystem Carbon Fluxes (updated rapidly, upfreq=2) - - 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=2, ivar=ivar, initialize=initialize_variables, index = ih_npp_si) - - call this%set_history_var(vname='FATES_NPP_SECONDARY', units='kg m-2 s-1', & - long='net primary production in kg carbon per m2 per second, secondary patches', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=2, ivar=ivar, initialize=initialize_variables, index = ih_npp_secondary_si) - - call this%set_history_var(vname='FATES_GPP', units='kg m-2 s-1', & - long='gross primary production in kg carbon per m2 per second', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=2, ivar=ivar, initialize=initialize_variables, index = ih_gpp_si) - - call this%set_history_var(vname='FATES_GPP_SECONDARY', units='kg m-2 s-1', & - long='gross primary production in kg carbon per m2 per second, secondary patches', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=2, ivar=ivar, initialize=initialize_variables, index = ih_gpp_secondary_si) - - call this%set_history_var(vname='FATES_AUTORESP', units='kg m-2 s-1', & - long='autotrophic respiration in kg carbon per m2 per second', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=2, ivar=ivar, initialize=initialize_variables, index = ih_aresp_si) - - call this%set_history_var(vname='FATES_AUTORESP_SECONDARY', units='kg m-2 s-1', & - long='autotrophic respiration in kg carbon per m2 per second, secondary patches', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=2, ivar=ivar, initialize=initialize_variables, index = ih_aresp_secondary_si) - - call this%set_history_var(vname='FATES_GROWTH_RESP', units='kg m-2 s-1', & - long='growth respiration in kg carbon per m2 per second', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=2, ivar=ivar, initialize=initialize_variables, & - index = ih_growth_resp_si) - - call this%set_history_var(vname='FATES_GROWTH_RESP_SECONDARY', units='kg m-2 s-1', & - long='growth respiration in kg carbon per m2 per second, secondary patches', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=2, ivar=ivar, initialize=initialize_variables, & - index = ih_growth_resp_secondary_si) - - call this%set_history_var(vname='FATES_MAINT_RESP', units='kg m-2 s-1', & - long='maintenance respiration in kg carbon per m2 land area per second', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=2, ivar=ivar, initialize=initialize_variables, & - index = ih_maint_resp_si) - - call this%set_history_var(vname='FATES_MAINT_RESP_UNREDUCED', units='kg m-2 s-1', & - long='diagnostic maintenance respiration if the low-carbon-storage reduction is ignored', & - use_default='inactive', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=2, ivar=ivar, initialize=initialize_variables, & - index = ih_maint_resp_unreduced_si) - - call this%set_history_var(vname='FATES_MAINT_RESP_SECONDARY', units='kg m-2 s-1', & - long='maintenance respiration in kg carbon per m2 land area per second, secondary patches', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=2, ivar=ivar, initialize=initialize_variables, & - index = ih_maint_resp_secondary_si) - - call this%set_history_var(vname='FATES_EXCESS_RESP', units='kg m-2 s-1', & - long='respiration of un-allocatable carbon gain', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=5, ivar=ivar, initialize=initialize_variables, & - index = ih_excess_resp_si) - - ! Canopy resistance - call this%set_history_var(vname='FATES_STOMATAL_COND_AP', & - units='mol m-2 s-1', long='mean stomatal conductance - by patch age', & - use_default='inactive', avgflag='A', vtype=site_age_r8, & - hlms='CLM:ALM', upfreq=2, ivar=ivar, initialize=initialize_variables, & - index = ih_c_stomata_si_age) - - call this%set_history_var(vname='FATES_AR_CANOPY', units='gC/m^2/s', & - long='autotrophic respiration of canopy plants', use_default='active', & - avgflag='A', vtype=site_r8, hlms='CLM:ALM', upfreq=2, & - ivar=ivar, initialize=initialize_variables, index = ih_ar_canopy_si ) - - call this%set_history_var(vname='FATES_LBLAYER_COND_AP', & - units='mol m-2 s-1', & - long='mean leaf boundary layer conductance - by patch age', & - use_default='inactive', avgflag='A', vtype=site_age_r8, & - hlms='CLM:ALM', upfreq=2, ivar=ivar, & - initialize=initialize_variables, index = ih_c_lblayer_si_age) - - ! fast fluxes by age bin - 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=2, ivar=ivar, initialize=initialize_variables, & - index = ih_npp_si_age) - - 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', & - use_default='inactive', avgflag='A', vtype=site_age_r8, & - hlms='CLM:ALM', upfreq=2, ivar=ivar, initialize=initialize_variables, & - index = ih_gpp_si_age) - - call this%set_history_var(vname='FATES_AR_UNDERSTORY', units='gC/m^2/s', & - long='autotrophic respiration of understory plants', use_default='active', & - avgflag='A', vtype=site_r8, hlms='CLM:ALM', upfreq=2, & - ivar=ivar, initialize=initialize_variables, index = ih_ar_understory_si ) - - ! fast fluxes separated canopy/understory - call this%set_history_var(vname='FATES_GPP_CANOPY', units='kg m-2 s-1', & - long='gross primary production of canopy plants in kg carbon per m2 per second', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=2, ivar=ivar, initialize=initialize_variables, & - index = ih_gpp_canopy_si) - - 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=2, ivar=ivar, initialize=initialize_variables, & - index = ih_ar_canopy_si) - - call this%set_history_var(vname='FATES_GPP_USTORY', & - units='kg m-2 s-1', & - long='gross primary production of understory plants in kg carbon per m2 per second', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=2, ivar=ivar, initialize=initialize_variables, & - index = ih_gpp_understory_si) - - call this%set_history_var(vname='FATES_AUTORESP_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', & - upfreq=2, ivar=ivar, initialize=initialize_variables, & - index = ih_ar_understory_si) - - ! fast radiative fluxes resolved through the canopy - - call this%set_history_var(vname='FATES_PARSUN_Z_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=2, ivar=ivar, & - initialize=initialize_variables, index = ih_parsun_z_si_cnlf) - - call this%set_history_var(vname='FATES_PARSHA_Z_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=2, ivar=ivar, & - initialize=initialize_variables, index = ih_parsha_z_si_cnlf) - - call this%set_history_var(vname='FATES_PARSUN_Z_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=2, ivar=ivar, initialize=initialize_variables, & - index = ih_parsun_z_si_cnlfpft) - - call this%set_history_var(vname='FATES_PARSHA_Z_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=2, ivar=ivar, initialize=initialize_variables, & - index = ih_parsha_z_si_cnlfpft) - - call this%set_history_var(vname='FATES_PARSUN_Z_CL', units='W m-2', & - long='PAR absorbed in the sun by top leaf layer in each canopy layer', & - use_default='inactive', avgflag='A', vtype=site_can_r8, & - hlms='CLM:ALM', upfreq=2, ivar=ivar, initialize=initialize_variables, & - index = ih_parsun_top_si_can ) - - call this%set_history_var(vname='FATES_PARSHA_Z_CL', units='W m-2', & - long='PAR absorbed in the shade by top leaf layer in each canopy layer', & - use_default='inactive', avgflag='A', vtype=site_can_r8, & - hlms='CLM:ALM', upfreq=2, ivar=ivar, initialize=initialize_variables, & - index = ih_parsha_top_si_can) - - call this%set_history_var(vname='FATES_LAISUN_Z_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=2, ivar=ivar, initialize=initialize_variables, & - index = ih_laisun_z_si_cnlf) - - call this%set_history_var(vname='FATES_LAISHA_Z_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=2, ivar=ivar, initialize=initialize_variables, & - index = ih_laisha_z_si_cnlf) - - call this%set_history_var(vname='FATES_LAISUN_Z_CLLLPF', units='m2 m-2', & - long='LAI in the sun by each canopy, leaf, and PFT', & - use_default='inactive', avgflag='A', vtype=site_cnlfpft_r8, & - hlms='CLM:ALM', upfreq=2, ivar=ivar, initialize=initialize_variables, & - index = ih_laisun_z_si_cnlfpft) - - call this%set_history_var(vname='FATES_LAISHA_Z_CLLLPF', units='m2 m-2', & - long='LAI in the shade by each canopy, leaf, and PFT', & - use_default='inactive', avgflag='A', vtype=site_cnlfpft_r8, & - hlms='CLM:ALM', upfreq=2, ivar=ivar, initialize=initialize_variables, & - index = ih_laisha_z_si_cnlfpft) - - call this%set_history_var(vname='FATES_LAISUN_TOP_CL', units='m2 m-2', & - long='LAI in the sun by the top leaf layer of each canopy layer', & - use_default='inactive', avgflag='A', vtype=site_can_r8, & - hlms='CLM:ALM', upfreq=2, ivar=ivar, initialize=initialize_variables, & - index = ih_laisun_top_si_can) - - call this%set_history_var(vname='FATES_LAISHA_TOP_CL', units='m2 m-2', & - long='LAI in the shade by the top leaf layer of each canopy layer', & - use_default='inactive', avgflag='A', vtype=site_can_r8, & - hlms='CLM:ALM', upfreq=2, ivar=ivar, initialize=initialize_variables, & - index = ih_laisha_top_si_can) - - call this%set_history_var(vname='FATES_FABD_SUN_CLLLPF', units='1', & - long='sun fraction of direct light absorbed by each canopy, leaf, and PFT', & - use_default='inactive', avgflag='A', vtype=site_cnlfpft_r8, & - hlms='CLM:ALM', upfreq=2, ivar=ivar, initialize=initialize_variables, & - index = ih_fabd_sun_si_cnlfpft) - - call this%set_history_var(vname='FATES_FABD_SHA_CLLLPF', units='1', & - long='shade fraction of direct light absorbed by each canopy, leaf, and PFT', & - use_default='inactive', avgflag='A', vtype=site_cnlfpft_r8, & - hlms='CLM:ALM', upfreq=2, ivar=ivar, initialize=initialize_variables, & - index = ih_fabd_sha_si_cnlfpft) - - call this%set_history_var(vname='FATES_FABI_SUN_CLLLPF', units='1', & - long='sun fraction of indirect light absorbed by each canopy, leaf, and PFT', & - use_default='inactive', avgflag='A', vtype=site_cnlfpft_r8, & - hlms='CLM:ALM', upfreq=2, ivar=ivar, initialize=initialize_variables, & - index = ih_fabi_sun_si_cnlfpft) - - call this%set_history_var(vname='FATES_FABI_SHA_CLLLPF', units='1', & - long='shade fraction of indirect light absorbed by each canopy, leaf, and PFT', & - use_default='inactive', avgflag='A', vtype=site_cnlfpft_r8, & - hlms='CLM:ALM', upfreq=2, ivar=ivar, initialize=initialize_variables, & - index = ih_fabi_sha_si_cnlfpft) - - call this%set_history_var(vname='FATES_FABD_SUN_CLLL', units='1', & - long='sun fraction of direct light absorbed by each canopy and leaf layer', & - use_default='inactive', avgflag='A', vtype=site_cnlf_r8, & - hlms='CLM:ALM', upfreq=2, ivar=ivar, initialize=initialize_variables, & - index = ih_fabd_sun_si_cnlf) - - call this%set_history_var(vname='FATES_FABD_SHA_CLLL', units='1', & - long='shade fraction of direct light absorbed by each canopy and leaf layer', & - use_default='inactive', avgflag='A', vtype=site_cnlf_r8, & - hlms='CLM:ALM', upfreq=2, ivar=ivar, initialize=initialize_variables, & - index = ih_fabd_sha_si_cnlf) - - call this%set_history_var(vname='FATES_FABI_SUN_CLLL', units='1', & - long='sun fraction of indirect light absorbed by each canopy and leaf layer', & - use_default='inactive', avgflag='A', vtype=site_cnlf_r8, & - hlms='CLM:ALM', upfreq=2, ivar=ivar, initialize=initialize_variables, & - index = ih_fabi_sun_si_cnlf) - - call this%set_history_var(vname='FATES_FABI_SHA_CLLL', units='1', & - long='shade fraction of indirect light absorbed by each canopy and leaf layer', & - use_default='inactive', avgflag='A', vtype=site_cnlf_r8, & - hlms='CLM:ALM', upfreq=2, ivar=ivar, initialize=initialize_variables, & - index = ih_fabi_sha_si_cnlf) - - 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=2, 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', & - 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=2, ivar=ivar, initialize=initialize_variables, & - index = ih_parprof_dif_si_cnlfpft) - - 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=2, 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', & - 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=2, ivar=ivar, initialize=initialize_variables, & - index = ih_parprof_dif_si_cnlf) - - call this%set_history_var(vname='FATES_FABD_SUN_TOPLF_CL', units='1', & - long='sun fraction of direct light absorbed by the top leaf layer of each canopy layer', & - use_default='inactive', avgflag='A', vtype=site_can_r8, & - hlms='CLM:ALM', upfreq=2, ivar=ivar, initialize=initialize_variables, & - index = ih_fabd_sun_top_si_can) - - call this%set_history_var(vname='FATES_FABD_SHA_TOPLF_CL', units='1', & - long='shade fraction of direct light absorbed by the top leaf layer of each canopy layer', & - use_default='inactive', avgflag='A', vtype=site_can_r8, & - hlms='CLM:ALM', upfreq=2, ivar=ivar, initialize=initialize_variables, & - index = ih_fabd_sha_top_si_can) - - call this%set_history_var(vname='FATES_FABI_SUN_TOPLF_CL', units='1', & - long='sun fraction of indirect light absorbed by the top leaf layer of each canopy layer', & - use_default='inactive', avgflag='A', vtype=site_can_r8, & - hlms='CLM:ALM', upfreq=2, ivar=ivar, initialize=initialize_variables, & - index = ih_fabi_sun_top_si_can) - - call this%set_history_var(vname='FATES_FABI_SHA_TOPLF_CL', units='1', & - long='shade fraction of indirect light absorbed by the top leaf layer of each canopy layer', & - use_default='inactive', avgflag='A', vtype=site_can_r8, & - hlms='CLM:ALM', upfreq=2, ivar=ivar, initialize=initialize_variables, & - index = ih_fabi_sha_top_si_can) - - !!! canopy-resolved fluxes and structure - - 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=2, ivar=ivar, initialize=initialize_variables, & - index = ih_ts_net_uptake_si_cnlf) - - call this%set_history_var(vname='FATES_CROWNAREA_CLLL', units='m2 m-2', & - long='total crown area that is occupied by leaves in each canopy and leaf layer', & - use_default='inactive', avgflag='A', vtype=site_cnlf_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, initialize=initialize_variables, & - index = ih_crownarea_si_cnlf) - - call this%set_history_var(vname='FATES_CROWNAREA_CL', units='m2 m-2', & - long='total crown area in each canopy layer', use_default='active', & - avgflag='A', vtype=site_can_r8, hlms='CLM:ALM', upfreq=1, & - ivar=ivar, initialize=initialize_variables, index = ih_crownarea_si_can) - - ! 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_demotion_carbonflux_si) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_promotion_carbonflux_si) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_canopy_mortality_carbonflux_si) - - call this%set_history_var(vname='FATES_MORTALITY_CFLUX_USTORY', & - units = 'kg m-2 s-1', & - long='flux of biomass carbon from live to dead pools from mortality of understory plants in kg carbon per m2 per second', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index = ih_understory_mortality_carbonflux_si) - - call this%set_history_var(vname='FATES_MORTALITY_CFLUX_PF', units='kg m-2 s-1', & - long='PFT-level flux of biomass carbon from live to dead pool from mortality', & - use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index=ih_mortality_carbonflux_si_pft) - - call this%set_history_var(vname='FATES_MORTALITY_FIRE_CFLUX_PF', units='kg m-2 s-1', & - long='PFT-level flux of biomass carbon from live to dead pool from fire mortality', & - use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index=ih_firemortality_carbonflux_si_pft) - - call this%set_history_var(vname='FATES_MORTALITY_HYDRO_CFLUX_PF', units='kg m-2 s-1', & - long='PFT-level flux of biomass carbon from live to dead pool from hydraulic failure mortality', & - use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index=ih_hydraulicmortality_carbonflux_si_pft) - - call this%set_history_var(vname='FATES_MORTALITY_CSTARV_CFLUX_PF', units='kg m-2 s-1', & - long='PFT-level flux of biomass carbon from live to dead pool from carbon starvation mortality', & - use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index=ih_cstarvmortality_carbonflux_si_pft) - - call this%set_history_var(vname='FATES_ABOVEGROUND_MORT_SZPF', units='kg m-2 s-1', & - long='Aboveground flux of carbon from AGB to necromass due to mortality', & - use_default='inactive', avgflag='A', vtype=site_size_pft_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index=ih_abg_mortality_cflux_si_scpf) - - call this%set_history_var(vname='FATES_ABOVEGROUND_PROD_SZPF', units='kg m-2 s-1', & - long='Aboveground carbon productivity', & - use_default='inactive', avgflag='A', vtype=site_size_pft_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index=ih_abg_productivity_cflux_si_scpf) - - call this%set_history_var(vname='MORTALITY_CROWNAREA_CANOPY', & - units = 'm2/ha/year', & - long='Crown area of canopy trees that died', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index = ih_canopy_mortality_crownarea_si ) - - call this%set_history_var(vname='MORTALITY_CROWNAREA_UNDERSTORY', & - units = 'm2/ha/year', & - long='Crown aera of understory trees that died', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index = ih_understory_mortality_crownarea_si ) - - ! size class by age dimensioned variables - - call this%set_history_var(vname='FATES_NPLANT_SZAP', units = 'm-2', & - long='number of plants per m2 in each size x age class', & - use_default='inactive', avgflag='A', vtype=site_scag_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_nplant_si_scag) - - call this%set_history_var(vname='FATES_NPLANT_CANOPY_SZAP', units = 'm-2', & - long='number of plants per m2 in canopy in each size x age class', & - use_default='inactive', avgflag='A', vtype=site_scag_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_nplant_canopy_si_scag) - - call this%set_history_var(vname='FATES_NPLANT_USTORY_SZAP', & - units = 'm-2', & - long='number of plants per m2 in understory in each size x age class', & - use_default='inactive', avgflag='A', vtype=site_scag_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_nplant_understory_si_scag) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_ddbh_canopy_si_scag) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_ddbh_understory_si_scag) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_mortality_canopy_si_scag) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_mortality_understory_si_scag) - - ! size x age x pft dimensioned - - call this%set_history_var(vname='FATES_NPLANT_SZAPPF',units = 'm-2', & - long='number of plants per m2 in each size x age x pft class', & - use_default='inactive', avgflag='A', vtype=site_scagpft_r8, & - hlms='CLM:ALM', upfreq=1, 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', & - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_npp_si_agepft) - - 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', & - use_default='inactive', avgflag='A', vtype=site_agepft_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_biomass_si_agepft) - - 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)', & - use_default='inactive', avgflag='A', vtype=site_agepft_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_scorch_height_si_agepft) - - - ! 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', & - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_gpp_si_scpf) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_gpp_canopy_si_scpf) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_ar_canopy_si_scpf) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_gpp_understory_si_scpf) - - 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=1, 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', & - 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=1, 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', & - 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=1, 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', & - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_npp_seed_si_scpf) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_npp_fnrt_si_scpf) - - 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=1, 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', & - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_npp_bgdw_si_scpf) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_npp_agsw_si_scpf) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_npp_agdw_si_scpf) - - 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=1, 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', & - long='diameter growth increment by pft/size', use_default='inactive', & - avgflag='A', vtype=site_size_pft_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index = ih_ddbh_si_scpf) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_growthflux_si_scpf) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_growthflux_fusion_si_scpf) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_ddbh_canopy_si_scpf) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_ddbh_understory_si_scpf) - - 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=1, & - ivar=ivar, initialize=initialize_variables, index = ih_ba_si_scpf) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_agb_si_scpf) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_nplant_si_scpf) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_nplant_si_capf) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_m1_si_scpf) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_m2_si_scpf) - - 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', & - use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_m3_si_scpf) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_m4_si_scpf) - - call this%set_history_var(vname='FATES_MORTALITY_FIRE_SZPF', & - units = 'm-2 yr-1', & - long='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_m5_si_scpf) - - call this%set_history_var(vname='FATES_MORTALITY_CROWNSCORCH_SZPF', & - units = 'm-2 yr-1', & - long='fire 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_crownfiremort_si_scpf) - - call this%set_history_var(vname='FATES_MORTALITY_CAMBIALBURN_SZPF', & - units = 'm-2 yr-1', & - long='fire 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_cambialfiremort_si_scpf) - - call this%set_history_var(vname='FATES_MORTALITY_TERMINATION_SZPF', & - units = 'm-2 yr-1', & - long='termination mortality 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_m6_si_scpf) - - 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=1, & - ivar=ivar, initialize=initialize_variables, index = ih_m7_si_scpf) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_m8_si_scpf) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_m9_si_scpf) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_m10_si_scpf) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index =ih_m10_si_capf) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_mortality_canopy_si_scpf) - - call this%set_history_var(vname='FATES_M3_MORTALITY_CANOPY_SZPF', & - units = 'N/ha/yr', & - long='C starvation mortality of canopy plants by pft/size', & - use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_m3_mortality_canopy_si_scpf ) - - call this%set_history_var(vname='FATES_M3_MORTALITY_USTORY_SZPF', & - units = 'N/ha/yr', & - long='C starvation mortality of understory plants by pft/size', & - use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_m3_mortality_understory_si_scpf ) + ! 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + units='kg s-1', & + long='total carbon error in kg carbon per second', & + use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & + upfreq=group_dyna_simple, ivar=ivar, initialize=initialize_variables, & + index = ih_cbal_err_fates_si) + + call this%set_history_var(vname='FATES_LEAF_ALLOC', units='kg m-2 s-1', & + long='allocation to leaves in kg carbon per m2 per second', & + use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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) + + 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', & + 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', & + 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 + + 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', & + 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', & + 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 + - - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_c13disc_si_scpf) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_bstor_canopy_si_scpf) - - 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', & - avgflag='A', vtype=site_size_pft_r8, hlms='CLM:ALM', upfreq=1, & - ivar=ivar, initialize=initialize_variables, & - index = ih_bleaf_canopy_si_scpf) - - call this%set_history_var(vname='FATES_LAI_CANOPY_SZPF', & - units = 'm2 m-2', & - long='Leaf area index (LAI) of canopy plants by pft/size', & - use_default='inactive', & - avgflag='A', vtype=site_size_pft_r8, hlms='CLM:ALM', upfreq=1, & - ivar=ivar, initialize=initialize_variables, & - index = ih_lai_canopy_si_scpf ) - - call this%set_history_var(vname='FATES_NPLANT_CANOPY_SZPF', units = 'm-2', & - long='number of canopy plants by size/pft per m2', & - use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_nplant_canopy_si_scpf) - - 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, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, & - index = ih_mortality_understory_si_scpf) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_bstor_understory_si_scpf) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_bleaf_understory_si_scpf) - - call this%set_history_var(vname='FATES_LAI_USTORY_SZPF', & - units = 'm2 m-2', & - long='Leaf area index (LAI) of understory plants by pft/size', & - use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_lai_understory_si_scpf ) - - call this%set_history_var(vname='FATES_NPLANT_USTORY_SZPF', & - units = 'm-2', & - long='density of understory plants by pft/size in number of plants per m2', & - use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & - hlms='CLM:ALM', upfreq=1, 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', & - 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=1, 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', & - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_cwd_bg_si_cwdsc) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_cwd_ag_in_si_cwdsc) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_cwd_bg_in_si_cwdsc) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_cwd_ag_out_si_cwdsc) - - 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, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_cwd_bg_out_si_cwdsc) - - ! Size structured diagnostics that require rapid updates (upfreq=2) - - 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=2, ivar=ivar, & - initialize=initialize_variables, index = ih_ar_si_scpf) - - 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=2, ivar=ivar, & - initialize=initialize_variables, index = ih_ar_grow_si_scpf) - - 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=2, ivar=ivar, & - initialize=initialize_variables, index = ih_ar_maint_si_scpf) - - 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=2, ivar=ivar, & - initialize=initialize_variables, index = ih_ar_darkm_si_scpf) - - 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=2, ivar=ivar, & - initialize=initialize_variables, index = ih_ar_agsapm_si_scpf) - - 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=2, ivar=ivar, & - initialize=initialize_variables, index = ih_ar_crootm_si_scpf) - - 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=2, ivar=ivar, & - initialize=initialize_variables, index = ih_ar_frootm_si_scpf) - - ! size-class only variables - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_ddbh_canopy_si_scls) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_ddbh_understory_si_scls) - - 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, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, & - index = ih_yesterdaycanopylevel_canopy_si_scls) - - 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, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, & - index = ih_yesterdaycanopylevel_understory_si_scls) - - 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=1, & - ivar=ivar, initialize=initialize_variables, index = ih_ba_si_scls) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_agb_si_scls) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_biomass_si_scls) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_demotion_rate_si_scls) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_promotion_rate_si_scls) - - 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=1, 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', & - long='leaf area index (LAI) of canopy plants by size class', & - use_default='active', avgflag='A', vtype=site_size_r8, & - hlms='CLM:ALM', upfreq=1, 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', & - long='stem area index (SAI) of canopy plants by size class', & - use_default='inactive', avgflag='A', vtype=site_size_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_sai_canopy_si_scls) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_mortality_canopy_si_scls) - - call this%set_history_var(vname='FATES_MORTALITY_CANOPY_SE_SZ', & - units = 'm-2 yr-1', & - long='total mortality of canopy trees by size class in number of plants per m2, secondary patches', & - use_default='active', avgflag='A', vtype=site_size_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_mortality_canopy_secondary_si_scls) - - call this%set_history_var(vname='FATES_NPLANT_USTORY_SZ', & - units = 'm-2', & - long='number of understory plants per m2 by size class', & - use_default='active', avgflag='A', vtype=site_size_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_nplant_understory_si_scls) - - call this%set_history_var(vname='FATES_M3_MORTALITY_CANOPY_SZ', & - units = 'N/ha/yr', & - long='C starvation mortality of canopy plants by size', & - use_default='inactive', avgflag='A', vtype=site_size_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_m3_mortality_canopy_si_scls ) - - call this%set_history_var(vname='FATES_M3_MORTALITY_USTORY_SZ', & - units = 'N/ha/yr', & - long='C starvation mortality of understory plants by size', & - use_default='inactive', avgflag='A', vtype=site_size_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_m3_mortality_understory_si_scls ) - - call this%set_history_var(vname='FATES_LAI_USTORY_SZ', & - units = 'm2 m-2', & - long='leaf area index (LAI) of understory plants by size class', & - use_default='active', avgflag='A', vtype=site_size_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_lai_understory_si_scls) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_sai_understory_si_scls) - - 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=1, & - ivar=ivar, initialize=initialize_variables, index = ih_nplant_si_scls) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_nplant_si_cacls) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_m1_si_scls) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_m2_si_scls) - - 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', & - use_default='active', avgflag='A', vtype=site_size_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_m3_si_scls) - - call this%set_history_var(vname='FATES_MORTALITY_BACKGROUND_SE_SZ', & - units = 'm-2 yr-1', & - long='background mortality by size in number of plants per m2 per year, secondary patches', & - use_default='active', avgflag='A', vtype=site_size_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_m1_sec_si_scls) - - call this%set_history_var(vname='FATES_MORTALITY_HYDRAULIC_SE_SZ', & - units = 'm-2 yr-1', & - long='hydraulic mortality by size in number of plants per m2 per year, secondary patches', & - use_default='active', avgflag='A', vtype=site_size_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_m2_sec_si_scls) - - call this%set_history_var(vname='FATES_MORTALITY_CSTARV_SE_SZ', & - units = 'm-2 yr-1', & - long='carbon starvation mortality by size in number of plants per m2 per year, secondary patches', & - use_default='active', avgflag='A', vtype=site_size_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_m3_sec_si_scls) - - call this%set_history_var(vname='FATES_MORTALITY_IMPACT_SZ', & - units = 'm-2 yr-1', & - long='impact mortality by size in number of plants per m2 per year', & - use_default='active', avgflag='A', vtype=site_size_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_m4_si_scls) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_m5_si_scls) - - call this%set_history_var(vname='FATES_MORTALITY_TERMINATION_SZ', & - units = 'm-2 yr-1', & - long='termination 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_m6_si_scls) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_m7_si_scls) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_m8_si_scls) - - call this%set_history_var(vname='FATES_MORTALITY_SENESCENCE_SZ', & - units = 'm-2 yr-1', & - long='senescence mortality by size in number of plants per m2 per year', & - use_default='active', avgflag='A', vtype=site_size_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_m9_si_scls) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_m10_si_scls) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_m10_si_cacls) - - call this%set_history_var(vname='FATES_MORTALITY_LOGGING_SE_SZ', & - units = 'm-2 yr-1', & - long='logging mortality by size in number of plants per m2 per event, secondary patches', & - use_default='active', avgflag='A', vtype=site_size_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_m7_sec_si_scls) - - call this%set_history_var(vname='FATES_MORTALITY_FREEZING_SE_SZ', & - units = 'm-2 event-1', & - long='freezing mortality by size in number of plants per m2 per event, secondary patches', & - use_default='active', avgflag='A', vtype=site_size_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_m8_sec_si_scls) - - call this%set_history_var(vname='FATES_MORTALITY_SENESCENCE_SE_SZ', & - units = 'm-2 yr-1', & - long='senescence mortality by size in number of plants per m2 per event, secondary patches', & - use_default='active', avgflag='A', vtype=site_size_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_m9_sec_si_scls) - - call this%set_history_var(vname='FATES_MORTALITY_AGESCEN_SE_SZ', & - units = 'm-2 yr-1', & - long='age senescence mortality by size in number of plants per m2 per year, secondary patches', & - use_default='active', avgflag='A', vtype=site_size_r8, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, index = ih_m10_sec_si_scls) - - call this%set_history_var(vname='FATES_NPP_CANOPY_SZ', units = 'kg m-2 s-1', & - long='NPP of canopy plants by size class in kg carbon per m2 per second', & - use_default='inactive', avgflag='A', vtype=site_size_r8, & - hlms='CLM:ALM', upfreq=1, 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', & - 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=1, ivar=ivar, & - initialize=initialize_variables, & - index = ih_carbon_balance_understory_si_scls) - - 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, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, & - index = ih_mortality_understory_si_scls) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_trimming_canopy_si_scls) - - 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, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, & - index = ih_trimming_understory_si_scls) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_crown_area_canopy_si_scls) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_crown_area_understory_si_scls) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_leaf_md_canopy_si_scls) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_root_md_canopy_si_scls) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_bstore_md_canopy_si_scls) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_bdead_md_canopy_si_scls) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_bsw_md_canopy_si_scls) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_seed_prod_canopy_si_scls) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_npp_leaf_canopy_si_scls) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_npp_fnrt_canopy_si_scls) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_npp_sapw_canopy_si_scls) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_npp_dead_canopy_si_scls) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_npp_seed_canopy_si_scls) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_npp_stor_canopy_si_scls) - - 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=2, ivar=ivar, initialize=initialize_variables, & - index = ih_leaf_mr_si) - - 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=2, ivar=ivar, initialize=initialize_variables, & - index = ih_froot_mr_si) - - 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=2, ivar=ivar, initialize=initialize_variables, & - index = ih_livecroot_mr_si) - - 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=2, ivar=ivar, initialize=initialize_variables, & - index = ih_livestem_mr_si) - - 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=2, ivar=ivar, & - initialize=initialize_variables, index = ih_rdark_canopy_si_scls) - - 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, & - hlms='CLM:ALM', upfreq=2, ivar=ivar, & - initialize=initialize_variables, & - index = ih_livestem_mr_canopy_si_scls) - - 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, & - hlms='CLM:ALM', upfreq=2, ivar=ivar, & - initialize=initialize_variables, & - index = ih_livecroot_mr_canopy_si_scls) - - 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=2, ivar=ivar, & - initialize=initialize_variables, index = ih_froot_mr_canopy_si_scls) - - 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=2, ivar=ivar, & - initialize=initialize_variables, index = ih_resp_g_canopy_si_scls) - - 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=2, ivar=ivar, & - initialize=initialize_variables, index = ih_resp_m_canopy_si_scls) - - 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, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, & - index = ih_leaf_md_understory_si_scls) - - 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, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, & - index = ih_root_md_understory_si_scls) - - 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, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, & - index = ih_bstore_md_understory_si_scls) - - 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, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, & - index = ih_bdead_md_understory_si_scls) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_bsw_md_understory_si_scls) - - 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, & - hlms='CLM:ALM', upfreq=1, ivar=ivar, & - initialize=initialize_variables, & - index = ih_seed_prod_understory_si_scls) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_npp_leaf_understory_si_scls) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_npp_fnrt_understory_si_scls) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_npp_sapw_understory_si_scls) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_npp_dead_understory_si_scls) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_npp_seed_understory_si_scls) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_npp_stor_understory_si_scls) - - 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=2, ivar=ivar, & - initialize=initialize_variables, index = ih_rdark_understory_si_scls) - - 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, & - hlms='CLM:ALM', upfreq=2, ivar=ivar, & - initialize=initialize_variables, & - index = ih_livestem_mr_understory_si_scls) - - 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, & - hlms='CLM:ALM', upfreq=2, ivar=ivar, & - initialize=initialize_variables, & - index = ih_livecroot_mr_understory_si_scls) - - 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, & - hlms='CLM:ALM', upfreq=2, ivar=ivar, & - initialize=initialize_variables, & - index = ih_froot_mr_understory_si_scls) - - 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=2, ivar=ivar, & - initialize=initialize_variables, index = ih_resp_g_understory_si_scls) - - 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, & - hlms='CLM:ALM', & - upfreq=2, ivar=ivar, initialize=initialize_variables, & - index = ih_resp_m_understory_si_scls) - - - ! CROWN DAMAGE VARIABLES - if_crowndamage: if(hlm_use_tree_damage .eq. itrue) then - - call this%set_history_var(vname='FATES_CROWNAREA_CANOPY_CD', units = 'm2 m-2 yr-1', & - long='crownarea lost to damage each year', use_default='inactive', & - avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, index = ih_crownarea_canopy_damage_si ) - - call this%set_history_var(vname='FATES_CROWNAREA_USTORY_CD', units = 'm2 m-2 yr-1', & - long='crownarea lost to damage each year', use_default='inactive', & - avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, index = ih_crownarea_ustory_damage_si ) - - call this%set_history_var(vname='FATES_NPLANT_CDPF', units = 'm-2', & - long='N. plants per damage x size x pft class', use_default='inactive', & - avgflag='A', vtype=site_cdpf_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, index = ih_nplant_si_cdpf ) - - call this%set_history_var(vname='FATES_NPLANT_CANOPY_CDPF', units = 'm-2', & - long='N. plants per damage x size x pft class', use_default='inactive', & - avgflag='A', vtype=site_cdpf_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, index = ih_nplant_canopy_si_cdpf ) - - call this%set_history_var(vname='FATES_NPLANT_USTORY_CDPF', units = 'm-2', & - long='N. plants in the understory per damage x size x pft class', use_default='inactive', & - avgflag='A', vtype=site_cdpf_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, index = ih_nplant_understory_si_cdpf ) - - call this%set_history_var(vname='FATES_M3_CDPF', units = 'm-2 yr-1', & - long='carbon starvation mortality by damaage/pft/size', use_default='inactive', & - avgflag='A', vtype=site_cdpf_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, index = ih_m3_si_cdpf ) - - call this%set_history_var(vname='FATES_M11_SZPF', units = 'm-2 yr-1', & - long='damage mortality by pft/size',use_default='inactive', & - avgflag='A', vtype =site_size_pft_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, index = ih_m11_si_scpf ) - - call this%set_history_var(vname='FATES_M11_CDPF', units = 'm-2 yr-1', & - long='damage mortality by damaage/pft/size', use_default='inactive', & - avgflag='A', vtype=site_cdpf_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, index = ih_m11_si_cdpf ) - - call this%set_history_var(vname='FATES_MORTALITY_CDPF', units = 'm-2 yr-1', & - long='mortality by damage class by size by pft', use_default='inactive', & - avgflag='A', vtype=site_cdpf_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, index = ih_mortality_si_cdpf ) - - call this%set_history_var(vname='FATES_M3_MORTALITY_CANOPY_CDPF', units = 'm-2 yr-1', & - long='C starvation mortality of canopy plants by damage/pft/size', use_default='inactive', & - avgflag='A', vtype=site_cdpf_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, index = ih_m3_mortality_canopy_si_cdpf ) - - call this%set_history_var(vname='FATES_M3_MORTALITY_USTORY_CDPF', units = 'm-2 yr-1', & - long='C starvation mortality of understory plants by pft/size', use_default='inactive', & - avgflag='A', vtype=site_cdpf_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, index = ih_m3_mortality_understory_si_cdpf ) - - call this%set_history_var(vname='FATES_M11_MORTALITY_CANOPY_CDPF', units = 'm-2 yr-1', & - long='damage mortality of canopy plants by damage/pft/size', use_default='inactive', & - avgflag='A', vtype=site_cdpf_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, index = ih_m11_mortality_canopy_si_cdpf ) - - call this%set_history_var(vname='FATES_M11_MORTALITY_USTORY_CDPF', units = 'm-2 yr-1', & - long='damage mortality of understory plants by pft/size', use_default='inactive', & - avgflag='A', vtype=site_cdpf_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, index = ih_m11_mortality_understory_si_cdpf ) - - call this%set_history_var(vname='FATES_MORTALITY_CANOPY_CDPF', units = 'm-2 yr-1', & - long='mortality of canopy plants by damage/pft/size', use_default='inactive', & - avgflag='A', vtype=site_cdpf_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, index = ih_mortality_canopy_si_cdpf ) - - call this%set_history_var(vname='FATES_MORTALITY_USTORY_CDPF', units = 'm-2 yr-1', & - long='mortality of understory plants by pft/size', use_default='inactive', & - avgflag='A', vtype=site_cdpf_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, index = ih_mortality_understory_si_cdpf ) - - call this%set_history_var(vname='FATES_DDBH_CDPF', units = 'm m-2 yr-1', & - long='ddbh annual increment growth by damage x size pft', use_default='inactive', & - avgflag='A', vtype=site_cdpf_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, index = ih_ddbh_si_cdpf ) - - call this%set_history_var(vname='FATES_DDBH_CANOPY_CDPF', units = 'm m-2 yr-1', & - long='ddbh annual canopy increment growth by damage x size pft', use_default='inactive', & - avgflag='A', vtype=site_cdpf_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, index = ih_ddbh_canopy_si_cdpf ) - - call this%set_history_var(vname='FATES_DDBH_USTORY_CDPF', units = 'm m-2 yr-1', & - long='ddbh annual understory increment growth by damage x size pft', use_default='inactive', & - avgflag='A', vtype=site_cdpf_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, index = ih_ddbh_understory_si_cdpf ) - - end if if_crowndamage - - ! CARBON BALANCE VARIABLES THAT DEPEND ON HLM BGC INPUTS - - call this%set_history_var(vname='FATES_NEP', units='kg m-2 s-1', & - long='net ecosystem production in kg carbon per m2 per second', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=2, ivar=ivar, initialize=initialize_variables, & - index = ih_nep_si) - - 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=2, ivar=ivar, initialize=initialize_variables, index = ih_hr_si) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_fire_c_to_atm_si) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_burn_flux_elem) - - 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', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index = ih_cbal_err_fates_si) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_err_fates_si) - - 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=1, 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', & - long='mass of belowground litter in fines (fineroots) by element', & - use_default='active', avgflag='A', vtype=site_elem_r8, & - hlms='CLM:ALM', upfreq=1, 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', & - 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=1, 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', & - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_cwd_ag_elem) - - 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=1, 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', & - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_totvegc_scpf) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_leafc_scpf) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_fnrtc_scpf) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_sapwc_scpf) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_storec_scpf) - - 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=1, ivar=ivar, initialize=initialize_variables, & - index = ih_reproc_scpf) - - ! organ-partitioned NPP / allocation fluxes - - 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=1, 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', & - long='allocation to seeds in kg carbon per m2 per second', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index = ih_npp_seed_si) - - 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=1, 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', & - long='allocation to fine roots in kg carbon per m2 per second', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index = ih_npp_froot_si) - - 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=1, 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', & - long='allocation to storage tissues in kg carbon per m2 per second', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=1, ivar=ivar, initialize=initialize_variables, & - index = ih_npp_stor_si) - - - ! PLANT HYDRAULICS - - hydro_active_if: if(hlm_use_planthydro.eq.itrue) then - - 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=4, ivar=ivar, & - initialize=initialize_variables, index = ih_errh2o_scpf) - - 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=4, ivar=ivar, & - initialize=initialize_variables, index = ih_tran_scpf) - - 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 per second', & - use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & - hlms='CLM:ALM', upfreq=4, ivar=ivar, & - initialize=initialize_variables, index = ih_sapflow_scpf) - - call this%set_history_var(vname='FATES_SAPFLOW', units='kg m-2 s-1', & - long='areal sap flow rate in kg per m2 per second', & - use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & - upfreq=4, ivar=ivar, initialize=initialize_variables, & - index = ih_sapflow_si) - - 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=4, ivar=ivar, initialize=initialize_variables, index = ih_iterh1_scpf ) - - 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=4, ivar=ivar, initialize=initialize_variables, index = ih_iterh2_scpf ) - - 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=4, ivar=ivar, & - initialize=initialize_variables, index = ih_ath_scpf) - - 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=4, ivar=ivar, & - initialize=initialize_variables, index = ih_tth_scpf) - - 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=4, ivar=ivar, & - initialize=initialize_variables, index = ih_sth_scpf) - - 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=4, ivar=ivar, & - initialize=initialize_variables, index = ih_lth_scpf) - - 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=4, ivar=ivar, & - initialize=initialize_variables, index = ih_awp_scpf) - - 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=4, ivar=ivar, & - initialize=initialize_variables, index = ih_twp_scpf) - - 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=4, ivar=ivar, & - initialize=initialize_variables, index = ih_swp_scpf) - - 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=4, ivar=ivar, & - initialize=initialize_variables, index = ih_lwp_scpf) - - 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=4, ivar=ivar, & - initialize=initialize_variables, index = ih_aflc_scpf) - - 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=4, ivar=ivar, & - initialize=initialize_variables, index = ih_tflc_scpf) - - 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=4, ivar=ivar, & - initialize=initialize_variables, index = ih_sflc_scpf) - - 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=4, ivar=ivar, & - initialize=initialize_variables, index = ih_lflc_scpf) - - 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=4, ivar=ivar, & - initialize=initialize_variables, index = ih_btran_scpf) - - 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=4, ivar=ivar, initialize=initialize_variables, & - index = ih_rootwgt_soilvwc_si) - - 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=4, ivar=ivar, initialize=initialize_variables, & - index = ih_rootwgt_soilvwcsat_si) - - 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=4, ivar=ivar, initialize=initialize_variables, & - index = ih_rootwgt_soilmatpot_si) - - 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=4, ivar=ivar, & - initialize=initialize_variables, index = ih_soilmatpot_sl) - - 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=4, ivar=ivar, & - initialize=initialize_variables, index = ih_soilvwc_sl) - - 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=4, ivar=ivar, & - initialize=initialize_variables, index = ih_soilvwcsat_sl) - - 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=4, ivar=ivar, & - initialize=initialize_variables, index = ih_rootuptake_si) - - 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=4, ivar=ivar, & - initialize=initialize_variables, index = ih_rootuptake_sl) - - 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=4, ivar=ivar, & - initialize=initialize_variables, index = ih_rootuptake0_scpf) - - 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=4, ivar=ivar, & - initialize=initialize_variables, index = ih_rootuptake10_scpf) - - 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=4, ivar=ivar, & - initialize=initialize_variables, index = ih_rootuptake50_scpf) - - 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=4, ivar=ivar, & - initialize=initialize_variables, index = ih_rootuptake100_scpf) - - 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=4, ivar=ivar, & - initialize=initialize_variables, index = ih_h2oveg_si) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_h2oveg_dead_si) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_h2oveg_recruit_si) - - 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=1, ivar=ivar, & - initialize=initialize_variables, index = ih_h2oveg_growturn_err_si) - - 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=4, ivar=ivar, & - initialize=initialize_variables, index = ih_h2oveg_hydro_err_si) - end if hydro_active_if + if_dyn1: if(hlm_hist_level_dynam>1) then + + 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_area_si_landuse) + + 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', & + 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', & + 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_VEGC_SE_PF', units='kg m-2', & + long='total PFT-level biomass in kg of carbon per land area, secondary patches', & + use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & + upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & + index=ih_biomass_sec_si_pft) + + 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=1, ivar=ivar, initialize=initialize_variables, & + index=ih_recruitment_cflux_si_pft) + + call this%set_history_var(vname='FATES_LEAFC_PF', units='kg m-2', & + long='total PFT-level leaf biomass in kg carbon per m2 land area', & + use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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_GPP_SE_PF', units='kg m-2 s-1', & + long='total PFT-level GPP in kg carbon per m2 land area per second, secondary patches', & + use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & + upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & + index=ih_gpp_sec_si_pft) + + call this%set_history_var(vname='FATES_NPP_SE_PF', units='kg m-2 s-1', & + long='total PFT-level NPP in kg carbon per m2 land area per second, secondary patches', & + use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & + upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & + index=ih_npp_sec_si_pft) + + call this%set_history_var(vname='FATES_NPLANT_PF', units='m-2', & + long='total PFT-level number of individuals per m2 land area', & + use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & + upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & + index=ih_nindivs_si_pft) + + call this%set_history_var(vname='FATES_NPLANT_SEC_PF', units='m-2', & + long='total PFT-level number of individuals per m2 land area, secondary patches', & + use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & + upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & + index=ih_nindivs_sec_si_pft) + + call this%set_history_var(vname='FATES_RECRUITMENT_PF', & + units='m-2 yr-1', & + long='PFT-level recruitment rate in number of individuals per m2 land area per year', & + use_default='active', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & + upfreq=group_dyna_complx, ivar=ivar, initialize=initialize_variables, & + index=ih_recruitment_si_pft) + + call this%set_history_var(vname='FATES_SEEDS_IN_GRIDCELL_PF', & + units='kg', & + long='Site-level seed mass input from neighboring gridcells per pft', & + use_default='inactive', avgflag='A', vtype=site_pft_r8, hlms='CLM:ALM', & + upfreq=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', & + 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_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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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='', & + 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',& + 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', & + 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 + + ! 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_area_si_age) + + 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', & + 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', & + long='canopy 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_canopy_area_si_age) + + call this%set_history_var(vname='FATES_NCL_AP', units='', & + long='number of canopy levels 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_ncl_si_age) + + 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 ( ED_val_comp_excln .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', & + 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', & + 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', & + 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', & + 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_SECONDAREA_ANTHRODIST_AP', & + units='m2 m-2', & + long='secondary forest patch area age distribution since anthropgenic 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_SECONDAREA_DIST_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_area_si_age) + + 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', & + 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', & + 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', & + 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_age_fuel) + + call this%set_history_var(vname='FATES_BURNFRAC_AP', units='s-1', & + long='spitfire fraction area burnt (per second) 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_area_burnt_si_age) + + 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, resolved by patch age (so divide by FATES_BURNFRAC_AP to get burned-area-weighted-average 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_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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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 + + 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', & + 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', & + 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)', & + 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)', & + 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_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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + units='1', & + long='storage nitrogen fraction (0-1) of target, in understory, by size-class x pft', & + use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & + hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & + initialize=initialize_variables, & + index = ih_storentfrac_understory_scpf) + + call this%set_history_var(vname='FATES_REPRON_SZPF', units='kg m-2', & + long='reproductive nitrogen mass (on plant) by size-class x pft in kg N per m2', & + use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & + hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & + initialize=initialize_variables, index = ih_repron_scpf) + + end if nitrogen_active_if1 + + phosphorus_active_if1: if(any(element_list(:)==phosphorus_element)) then + + call this%set_history_var(vname='FATES_VEGP_SZPF', units='kg m-2', & + long='total (live) vegetation phosphorus mass by size-class x pft in kg P per m2', & + use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & + hlms='CLM:ALM', upfreq=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', & + 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', & + 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', & + 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', & + 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', & + 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', & + units='1', & + long='storage phosphorus fraction (0-1) of target, in understory, by size-class x pft', & + use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & + hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & + initialize=initialize_variables, & + index = ih_storeptfrac_understory_scpf) + + call this%set_history_var(vname='FATES_REPROP_SZPF', units='kg m-2', & + long='reproductive phosphorus mass (on plant) by size-class x pft in kg P per m2', & + use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & + hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & + initialize=initialize_variables, index = ih_reprop_scpf) + + call this%set_history_var(vname='FATES_PUPTAKE_SZPF', & + units='kg m-2 s-1', & + long='phosphorus uptake rate by plants, by size-class x pft in kg P per m2 per second', & + use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & + hlms='CLM:ALM', upfreq=group_nflx_complx, ivar=ivar, & + initialize=initialize_variables, index = ih_puptake_scpf) + + call this%set_history_var(vname='FATES_PEFFLUX_SZPF', & + units='kg m-2 s-1', & + long='phosphorus efflux, root to soil, by size-class x pft in kg P per m2 per second', & + use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & + hlms='CLM:ALM', upfreq=group_nflx_complx, ivar=ivar, & + initialize=initialize_variables, index = ih_pefflux_scpf) + + call this%set_history_var(vname='FATES_PDEMAND_SZPF', units='kg m-2 s-1', & + long='plant P need (algorithm dependent), by size-class x pft in kg P per m2 per second', & + use_default='inactive', avgflag='A', vtype=site_size_pft_r8, & + hlms='CLM:ALM', upfreq=group_nflx_complx, ivar=ivar, & + initialize=initialize_variables, index = ih_pdemand_scpf) + + end if phosphorus_active_if1 + + call this%set_history_var(vname='FATES_CROWNAREA_CLLL', units='m2 m-2', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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 + + call this%set_history_var(vname='FATES_NPLANT_SZAP', units = 'm-2', & + long='number of plants per m2 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_nplant_si_scag) + + call this%set_history_var(vname='FATES_NPLANT_CANOPY_SZAP', units = 'm-2', & + long='number of plants per m2 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_nplant_canopy_si_scag) + + call this%set_history_var(vname='FATES_NPLANT_USTORY_SZAP', & + units = 'm-2', & + long='number of plants per m2 in understory 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_nplant_understory_si_scag) + + 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', & + 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', & + 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', & + 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 + + call this%set_history_var(vname='FATES_NPLANT_SZAPPF',units = 'm-2', & + long='number of plants per m2 in each size x age x pft class', & + 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', & + 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_VEGC_APPF',units = 'kg m-2', & + long='biomass per PFT in each age bin in kg carbon per m2', & + 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', & + long='SPITFIRE flame Scorch Height (calculated per PFT in each patch age bin)', & + 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) + + + ! 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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_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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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_FIRE_SZPF', & + units = 'm-2 yr-1', & + long='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=group_dyna_complx, ivar=ivar, & + initialize=initialize_variables, index = ih_m5_si_scpf) + + call this%set_history_var(vname='FATES_MORTALITY_CROWNSCORCH_SZPF', & + units = 'm-2 yr-1', & + long='fire 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_crownfiremort_si_scpf) + + call this%set_history_var(vname='FATES_MORTALITY_CAMBIALBURN_SZPF', & + units = 'm-2 yr-1', & + long='fire 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_cambialfiremort_si_scpf) + + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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, & + hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & + initialize=initialize_variables, index = ih_m3_mortality_understory_si_scpf ) + + + call this%set_history_var(vname='FATES_C13DISC_SZPF', units = 'per mil', & + long='C13 discrimination by pft/size',use_default='inactive', & + avgflag='A', vtype=site_size_pft_r8, hlms='CLM:ALM', & + 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', & + 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', & + units = 'kg m-2', & + long='biomass in leaves 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_bleaf_canopy_si_scpf) + + call this%set_history_var(vname='FATES_LAI_CANOPY_SZPF', & + units = 'm2 m-2', & + long='Leaf area index (LAI) of canopy plants by pft/size', & + use_default='inactive', & + avgflag='A', vtype=site_size_pft_r8, hlms='CLM:ALM', upfreq=group_dyna_complx, & + ivar=ivar, initialize=initialize_variables, & + index = ih_lai_canopy_si_scpf ) + + 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', & + 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', & + 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', & + 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, & + hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & + initialize=initialize_variables, & + index = ih_mortality_understory_si_scpf) + + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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, & + hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & + initialize=initialize_variables, index = ih_cwd_bg_out_si_cwdsc) + + + ! size-class only variables + + 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', & + 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', & + 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, & + hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & + initialize=initialize_variables, & + index = ih_yesterdaycanopylevel_canopy_si_scls) + + 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, & + hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & + initialize=initialize_variables, & + index = ih_yesterdaycanopylevel_understory_si_scls) + + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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_BACKGROUND_SE_SZ', & + units = 'm-2 yr-1', & + long='background mortality by size in number of plants per m2 per year, secondary patches', & + use_default='active', avgflag='A', vtype=site_size_r8, & + hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & + initialize=initialize_variables, index = ih_m1_sec_si_scls) + + call this%set_history_var(vname='FATES_MORTALITY_HYDRAULIC_SE_SZ', & + units = 'm-2 yr-1', & + long='hydraulic mortality by size in number of plants per m2 per year, secondary patches', & + use_default='active', avgflag='A', vtype=site_size_r8, & + hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & + initialize=initialize_variables, index = ih_m2_sec_si_scls) + + call this%set_history_var(vname='FATES_MORTALITY_CSTARV_SE_SZ', & + units = 'm-2 yr-1', & + long='carbon starvation mortality by size in number of plants per m2 per year, secondary patches', & + use_default='active', avgflag='A', vtype=site_size_r8, & + hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & + initialize=initialize_variables, index = ih_m3_sec_si_scls) + + call this%set_history_var(vname='FATES_MORTALITY_IMPACT_SZ', & + units = 'm-2 yr-1', & + long='impact mortality by size in number of plants per m2 per year', & + 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', & + 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_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', & + 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', & + 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', & + 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', & + 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', & + 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_MORTALITY_LOGGING_SE_SZ', & + units = 'm-2 yr-1', & + long='logging mortality by size in number of plants per m2 per event, secondary patches', & + use_default='active', avgflag='A', vtype=site_size_r8, & + hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & + initialize=initialize_variables, index = ih_m7_sec_si_scls) + + call this%set_history_var(vname='FATES_MORTALITY_FREEZING_SE_SZ', & + units = 'm-2 event-1', & + long='freezing mortality by size in number of plants per m2 per event, secondary patches', & + use_default='active', avgflag='A', vtype=site_size_r8, & + hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & + initialize=initialize_variables, index = ih_m8_sec_si_scls) + + call this%set_history_var(vname='FATES_MORTALITY_SENESCENCE_SE_SZ', & + units = 'm-2 yr-1', & + long='senescence mortality by size in number of plants per m2 per event, secondary patches', & + use_default='active', avgflag='A', vtype=site_size_r8, & + hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & + initialize=initialize_variables, index = ih_m9_sec_si_scls) + + call this%set_history_var(vname='FATES_MORTALITY_AGESCEN_SE_SZ', & + units = 'm-2 yr-1', & + long='age senescence mortality by size in number of plants per m2 per year, secondary patches', & + use_default='active', avgflag='A', vtype=site_size_r8, & + hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & + initialize=initialize_variables, index = ih_m10_sec_si_scls) + + call this%set_history_var(vname='FATES_NPP_CANOPY_SZ', units = 'kg m-2 s-1', & + long='NPP of canopy plants by size class in kg carbon per m2 per second', & + use_default='inactive', avgflag='A', vtype=site_size_r8, & + 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', & + 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', & + 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, & + hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & + initialize=initialize_variables, & + index = ih_mortality_understory_si_scls) + + 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', & + 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, & + hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & + initialize=initialize_variables, & + index = ih_trimming_understory_si_scls) + + 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_area_canopy_si_scls) + + 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_area_understory_si_scls) + + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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, & + hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & + initialize=initialize_variables, & + index = ih_leaf_md_understory_si_scls) + + 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, & + hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & + initialize=initialize_variables, & + index = ih_root_md_understory_si_scls) + + 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, & + hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & + initialize=initialize_variables, & + index = ih_bstore_md_understory_si_scls) + + 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, & + hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & + initialize=initialize_variables, & + index = ih_bdead_md_understory_si_scls) + + 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', & + 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, & + hlms='CLM:ALM', upfreq=group_dyna_complx, ivar=ivar, & + initialize=initialize_variables, & + index = ih_seed_prod_understory_si_scls) + + 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', & + 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', & + 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', & + 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', & + 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', & + 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 + + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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 + + + 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) + + + 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_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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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, & + index = ih_reproc_scpf) + + + + end if if_dyn1 + end if if_dyn0 + + !HERE + + + if_hifrq0: if(hlm_hist_level_hifrq>0) then + + ! Canopy Resistance + + 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', & + 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 + + 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='-', & + 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='-', & + 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) + + 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_hifr_simple, ivar=ivar, initialize=initialize_variables, index = ih_npp_si) + + call this%set_history_var(vname='FATES_NPP_SECONDARY', units='kg m-2 s-1', & + long='net primary production in kg carbon per m2 per second, secondary patches', & + use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & + upfreq=group_hifr_simple, ivar=ivar, initialize=initialize_variables, index = ih_npp_secondary_si) + + call this%set_history_var(vname='FATES_GPP', units='kg m-2 s-1', & + long='gross primary production in kg carbon per m2 per second', & + use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & + upfreq=group_hifr_simple, ivar=ivar, initialize=initialize_variables, index = ih_gpp_si) + + call this%set_history_var(vname='FATES_GPP_SECONDARY', units='kg m-2 s-1', & + long='gross primary production in kg carbon per m2 per second, secondary patches', & + use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & + upfreq=group_hifr_simple, ivar=ivar, initialize=initialize_variables, index = ih_gpp_secondary_si) + + call this%set_history_var(vname='FATES_AUTORESP', units='kg m-2 s-1', & + long='autotrophic respiration in kg carbon per m2 per second', & + use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & + upfreq=group_hifr_simple, ivar=ivar, initialize=initialize_variables, index = ih_aresp_si) + + call this%set_history_var(vname='FATES_AUTORESP_SECONDARY', units='kg m-2 s-1', & + long='autotrophic respiration in kg carbon per m2 per second, secondary patches', & + use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & + upfreq=group_hifr_simple, ivar=ivar, initialize=initialize_variables, index = ih_aresp_secondary_si) + + call this%set_history_var(vname='FATES_GROWTH_RESP', units='kg m-2 s-1', & + long='growth respiration in kg carbon per m2 per second', & + use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & + upfreq=group_hifr_simple, ivar=ivar, initialize=initialize_variables, & + index = ih_growth_resp_si) + + call this%set_history_var(vname='FATES_GROWTH_RESP_SECONDARY', units='kg m-2 s-1', & + long='growth respiration in kg carbon per m2 per second, secondary patches', & + use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & + upfreq=group_hifr_simple, ivar=ivar, initialize=initialize_variables, & + index = ih_growth_resp_secondary_si) + + call this%set_history_var(vname='FATES_MAINT_RESP', units='kg m-2 s-1', & + long='maintenance respiration in kg carbon per m2 land area per second', & + use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & + upfreq=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', & + 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) + + call this%set_history_var(vname='FATES_MAINT_RESP_SECONDARY', units='kg m-2 s-1', & + long='maintenance respiration in kg carbon per m2 land area per second, secondary patches', & + use_default='active', avgflag='A', vtype=site_r8, hlms='CLM:ALM', & + upfreq=group_hifr_simple, ivar=ivar, initialize=initialize_variables, & + index = ih_maint_resp_secondary_si) + + ! fast fluxes separated canopy/understory + call this%set_history_var(vname='FATES_GPP_CANOPY', units='kg m-2 s-1', & + long='gross primary production of canopy plants in kg carbon per m2 per second', & + 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', & + 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', & + 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', & + 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', & + upfreq=group_hifr_simple, ivar=ivar, initialize=initialize_variables, & + index = ih_ar_understory_si) + + + + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + long='areal sap flow rate in kg per m2 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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 + + !HERE + + 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) + + 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_hifr_complx, ivar=ivar, initialize=initialize_variables, & + index = ih_npp_si_age) + + 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', & + 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_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', & + 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, & + hlms='CLM:ALM', upfreq=group_hifr_complx, ivar=ivar, & + initialize=initialize_variables, & + index = ih_livestem_mr_understory_si_scls) + + 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, & + hlms='CLM:ALM', upfreq=group_hifr_complx, ivar=ivar, & + initialize=initialize_variables, & + index = ih_livecroot_mr_understory_si_scls) + + 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, & + hlms='CLM:ALM', upfreq=group_hifr_complx, ivar=ivar, & + initialize=initialize_variables, & + index = ih_froot_mr_understory_si_scls) + + 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', & + 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, & + hlms='CLM:ALM', & + 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', & + 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', & + 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_livecroot_mr_canopy_si_scls) + + 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', & + 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', & + 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', & + 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, & + hlms='CLM:ALM', upfreq=group_hifr_complx, ivar=ivar, & + initialize=initialize_variables, & + index = ih_livestem_mr_canopy_si_scls) + + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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 + + 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', & + 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', & + units='mol m-2 s-1', & + long='mean leaf boundary layer conductance - by patch age', & + use_default='inactive', avgflag='A', vtype=site_age_r8, & + 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', & + units='mol m-2 s-1', long='mean stomatal conductance - by patch age', & + use_default='inactive', avgflag='A', vtype=site_age_r8, & + hlms='CLM:ALM', upfreq=group_hifr_complx, ivar=ivar, initialize=initialize_variables, & + index = ih_c_stomata_si_age) + + ! PLANT HYDRAULICS + + hydro_active_if1: if(hlm_use_planthydro.eq.itrue) then + + 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', & + 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', & + long='areal sap flow rate dimensioned by size x pft in kg per m2 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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', & + 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 @@ -8525,100 +9200,100 @@ subroutine define_history_vars(this, initialize_variables) 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 + ! ==================================================================================== + ! 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 diff --git a/main/FatesHistoryVariableType.F90 b/main/FatesHistoryVariableType.F90 index 83cbdb8c1c..b24bb1bf86 100644 --- a/main/FatesHistoryVariableType.F90 +++ b/main/FatesHistoryVariableType.F90 @@ -41,9 +41,16 @@ module FatesHistoryVariableType ! or infrequently used output datasets character(len=24) :: vtype character(len=1) :: avgflag - integer :: upfreq ! Update frequency (this is for checks and flushing) - ! 1 = dynamics "dyn" (daily) - ! 2 = production "prod" (prob model tstep) + integer :: upfreq ! Update frequency (this is for checks and flushing) + ! dynamics, high-frequency and hydraulic output, + ! split up by complex and non-complex dimensioning + ! group_dyna_simple = 1 + ! group_dyna_complx = 2 + ! group_hifr_simple = 3 + ! group_hifr_complx = 4 + ! group_hydr_simple = 5 + ! group_hydr_complx = 6 + real(r8) :: flushval integer :: dim_kinds_index ! Pointers (only one of these is allocated per variable) @@ -55,7 +62,7 @@ module FatesHistoryVariableType integer, pointer :: int3d(:,:,:) contains procedure :: Init - procedure :: Flush + procedure :: HFlush procedure, private :: GetBounds end type fates_history_variable_type @@ -283,7 +290,7 @@ subroutine GetBounds(this, thread, dim_bounds, dim_kinds, lb1, ub1, lb2, ub2) end subroutine GetBounds - subroutine Flush(this, thread, dim_bounds, dim_kinds) + subroutine HFlush(this, thread, dim_bounds, dim_kinds) implicit none @@ -357,6 +364,6 @@ subroutine Flush(this, thread, dim_bounds, dim_kinds) call endrun(msg=errMsg(sourcefile, __LINE__)) end select - end subroutine Flush + end subroutine HFlush end module FatesHistoryVariableType diff --git a/main/FatesHydraulicsMemMod.F90 b/main/FatesHydraulicsMemMod.F90 index 61e97173c7..2baaa9d240 100644 --- a/main/FatesHydraulicsMemMod.F90 +++ b/main/FatesHydraulicsMemMod.F90 @@ -3,10 +3,12 @@ module FatesHydraulicsMemMod use FatesConstantsMod, only : r8 => fates_r8 use FatesConstantsMod, only : fates_unset_r8 use FatesGlobals, only : fates_log + use FatesGlobals, only : endrun => fates_endrun use shr_infnan_mod, only : nan => shr_infnan_nan, assignment(=) use FatesConstantsMod, only : itrue,ifalse use FatesHydroWTFMod, only : wrf_arr_type use FatesHydroWTFMod, only : wkf_arr_type + use shr_log_mod , only : errMsg => shr_log_errMsg implicit none private @@ -168,19 +170,19 @@ module FatesHydraulicsMemMod real(r8), allocatable :: residual(:) real(r8), allocatable :: ajac(:,:) ! Jacobian (N terms, N equations) - real(r8), allocatable :: th_node_init(:) + real(r8), allocatable :: th_node_init(:) real(r8), allocatable :: th_node_prev(:) - real(r8), allocatable :: th_node(:) - real(r8), allocatable :: dth_node(:) - real(r8), allocatable :: h_node(:) - real(r8), allocatable :: v_node(:) - real(r8), allocatable :: z_node(:) - real(r8), allocatable :: psi_node(:) - real(r8), allocatable :: q_flux(:) - real(r8), allocatable :: dftc_dpsi_node(:) - real(r8), allocatable :: ftc_node(:) - real(r8), allocatable :: kmax_up(:) - real(r8), allocatable :: kmax_dn(:) + real(r8), allocatable :: th_node(:) ! Relative water content (theta) of node [m3/m3] + real(r8), allocatable :: dth_node(:) ! Change (time derivative) in water content of node + real(r8), allocatable :: h_node(:) ! + real(r8), allocatable :: v_node(:) ! Volume of the node [m3] + real(r8), allocatable :: z_node(:) ! Eleveation potential of the node (datum 0 is surface) + real(r8), allocatable :: psi_node(:) ! Suction of the node [MPa] + real(r8), allocatable :: q_flux(:) ! Mass flux of pathways between nodes [] + real(r8), allocatable :: dftc_dpsi_node(:) ! Differential of fraction total conductivity with suction + real(r8), allocatable :: ftc_node(:) ! fraction of total conductivity [-] + real(r8), allocatable :: kmax_up(:) ! Maximum conductivity for upstream side of compartment + real(r8), allocatable :: kmax_dn(:) ! Maximum conductivity for downstream side of compartment ! Scratch arrays real(r8) :: cohort_recruit_water_layer(nlevsoi_hyd_max) ! the recruit water requirement for a cohort @@ -319,7 +321,11 @@ module FatesHydraulicsMemMod procedure :: Dump end type ed_cohort_hydr_type - + + character(len=*), parameter, private :: sourcefile = & + __FILE__ + + contains subroutine CopyCohortHydraulics(ncohort_hydr, ocohort_hydr) @@ -372,8 +378,7 @@ subroutine CopyCohortHydraulics(ncohort_hydr, ocohort_hydr) ncohort_hydr%iterh2 = ocohort_hydr%iterh2 ncohort_hydr%iterlayer = ocohort_hydr%iterlayer ncohort_hydr%errh2o = ocohort_hydr%errh2o - - + ! BC PLANT HYDRAULICS - flux terms ncohort_hydr%qtop = ocohort_hydr%qtop diff --git a/main/FatesIOVariableKindMod.F90 b/main/FatesIOVariableKindMod.F90 index 2455939e6f..75ea7dbe57 100644 --- a/main/FatesIOVariableKindMod.F90 +++ b/main/FatesIOVariableKindMod.F90 @@ -51,7 +51,37 @@ module FatesIOVariableKindMod character(*), parameter, public :: site_elcwd_r8 = 'SI_ELEMCWD_R8' character(*), parameter, public :: site_elage_r8 = 'SI_ELEMAGE_R8' - + ! ------------------------------------------------------------------ + ! + ! History Variable Groups + ! + ! These are group indices for output variables. We use + ! these groups to do things like zero-ing and initializing + ! + ! These groups are updated at the dynamics (daily) step + ! so they are turned on and off with dimlevel(2) + ! + ! active when dimlevel(2)>0 + integer, parameter, public :: group_dyna_simple = 1 + integer, parameter, public :: group_nflx_simple = 7 + + ! active when dimlevel(2)>1 + integer, parameter, public :: group_dyna_complx = 2 + integer, parameter, public :: group_nflx_complx = 8 + + ! These groups are updated at the fast step + ! so they are turned on and off with dimlevel(1) + ! + ! active when dimlevel(1)>0 + integer, parameter, public :: group_hifr_simple = 3 + integer, parameter, public :: group_hydr_simple = 5 + + ! active when dimlevel(1)>1 + integer, parameter, public :: group_hifr_complx = 4 + integer, parameter, public :: group_hydr_complx = 6 + + ! ------------------------------------------------------------------- + ! NOTE(RGK, 2016) %active is not used yet. Was intended as a check on the HLM->FATES ! control parameter passing to ensure all active dimension types received all ! dimensioning specifications from the host, but we currently arent using those diff --git a/main/FatesInterfaceMod.F90 b/main/FatesInterfaceMod.F90 index d1a0e85722..eea65eaa0a 100644 --- a/main/FatesInterfaceMod.F90 +++ b/main/FatesInterfaceMod.F90 @@ -18,10 +18,8 @@ module FatesInterfaceMod use EDParamsMod , only : maxpatch_total use EDParamsMod , only : maxpatches_by_landuse use EDParamsMod , only : max_cohort_per_patch + use FatesRadiationMemMod , only : num_swb,ivis,inir use EDParamsMod , only : regeneration_model - use EDParamsMod , only : maxSWb - use EDParamsMod , only : ivis - use EDParamsMod , only : inir use EDParamsMod , only : nclmax use EDParamsMod , only : nlevleaf use EDParamsMod , only : maxpft @@ -43,6 +41,8 @@ module FatesInterfaceMod use FatesConstantsMod , only : n_landuse_cats use FatesConstantsMod , only : primaryland use FatesConstantsMod , only : secondaryland + use FatesConstantsMod , only : n_crop_lu_types + use FatesConstantsMod , only : n_term_mort_types use FatesGlobals , only : fates_global_verbose use FatesGlobals , only : fates_log use FatesGlobals , only : endrun => fates_endrun @@ -110,6 +110,7 @@ module FatesInterfaceMod use FatesHistoryInterfaceMod , only : fates_hist use FatesHydraulicsMemMod , only : nshell use FatesHydraulicsMemMod , only : nlevsoi_hyd_max + use FatesTwoStreamUtilsMod, only : TransferRadParams ! CIME Globals use shr_log_mod , only : errMsg => shr_log_errMsg @@ -417,7 +418,7 @@ end subroutine zero_bcs ! =========================================================================== subroutine allocate_bcin(bc_in, nlevsoil_in, nlevdecomp_in, num_lu_harvest_cats, num_luh2_states, & - num_luh2_transitions, natpft_lb,natpft_ub) + num_luh2_transitions, surfpft_lb,surfpft_ub) ! --------------------------------------------------------------------------------- ! Allocate and Initialze the FATES boundary condition vectors @@ -430,7 +431,7 @@ subroutine allocate_bcin(bc_in, nlevsoil_in, nlevdecomp_in, num_lu_harvest_cats, integer,intent(in) :: num_lu_harvest_cats integer,intent(in) :: num_luh2_states integer,intent(in) :: num_luh2_transitions - integer,intent(in) :: natpft_lb,natpft_ub ! dimension bounds of the array holding surface file pft data + integer,intent(in) :: surfpft_lb,surfpft_ub ! dimension bounds of the array holding surface file pft data ! Allocate input boundaries @@ -500,8 +501,8 @@ subroutine allocate_bcin(bc_in, nlevsoil_in, nlevdecomp_in, num_lu_harvest_cats, allocate(bc_in%precip24_pa(maxpatch_total)) ! Radiation - allocate(bc_in%solad_parb(maxpatch_total,hlm_numSWb)) - allocate(bc_in%solai_parb(maxpatch_total,hlm_numSWb)) + allocate(bc_in%solad_parb(maxpatch_total,num_swb)) + allocate(bc_in%solai_parb(maxpatch_total,num_swb)) ! Hydrology allocate(bc_in%smp_sl(nlevsoil_in)) @@ -533,8 +534,8 @@ subroutine allocate_bcin(bc_in, nlevsoil_in, nlevdecomp_in, num_lu_harvest_cats, allocate(bc_in%filter_vegzen_pa(maxpatch_total)) allocate(bc_in%coszen_pa(maxpatch_total)) allocate(bc_in%fcansno_pa(maxpatch_total)) - allocate(bc_in%albgr_dir_rb(hlm_numSWb)) - allocate(bc_in%albgr_dif_rb(hlm_numSWb)) + allocate(bc_in%albgr_dir_rb(num_swb)) + allocate(bc_in%albgr_dif_rb(num_swb)) ! Plant-Hydro BC's if (hlm_use_planthydro.eq.itrue) then @@ -563,7 +564,13 @@ subroutine allocate_bcin(bc_in, nlevsoil_in, nlevdecomp_in, num_lu_harvest_cats, allocate(bc_in%hlm_harvest_catnames(0)) end if - allocate(bc_in%pft_areafrac(natpft_lb:natpft_ub)) + if ( hlm_use_fixed_biogeog .eq. itrue) then + if (hlm_use_luh .eq. itrue ) then + allocate(bc_in%pft_areafrac_lu(size( EDPftvarcon_inst%hlm_pft_map,2),n_landuse_cats-n_crop_lu_types)) + else + allocate(bc_in%pft_areafrac(surfpft_lb:surfpft_ub)) + endif + endif ! LUH2 state and transition data if (hlm_use_luh .eq. itrue) then @@ -575,10 +582,11 @@ subroutine allocate_bcin(bc_in, nlevsoil_in, nlevdecomp_in, num_lu_harvest_cats, ! Variables for SP mode. if(hlm_use_sp.eq.itrue) then - allocate(bc_in%hlm_sp_tlai(natpft_lb:natpft_ub)) - allocate(bc_in%hlm_sp_tsai(natpft_lb:natpft_ub)) - allocate(bc_in%hlm_sp_htop(natpft_lb:natpft_ub)) - end if + allocate(bc_in%hlm_sp_tlai(surfpft_lb:surfpft_ub)) + allocate(bc_in%hlm_sp_tsai(surfpft_lb:surfpft_ub)) + allocate(bc_in%hlm_sp_htop(surfpft_lb:surfpft_ub)) + end if + return end subroutine allocate_bcin @@ -611,14 +619,13 @@ subroutine allocate_bcout(bc_out, nlevsoil_in, nlevdecomp_in) allocate(bc_out%rssha_pa(maxpatch_total)) ! Canopy Radiation - allocate(bc_out%albd_parb(maxpatch_total,hlm_numSWb)) - allocate(bc_out%albi_parb(maxpatch_total,hlm_numSWb)) - allocate(bc_out%fabd_parb(maxpatch_total,hlm_numSWb)) - allocate(bc_out%fabi_parb(maxpatch_total,hlm_numSWb)) - allocate(bc_out%ftdd_parb(maxpatch_total,hlm_numSWb)) - allocate(bc_out%ftid_parb(maxpatch_total,hlm_numSWb)) - allocate(bc_out%ftii_parb(maxpatch_total,hlm_numSWb)) - + allocate(bc_out%albd_parb(fates_maxPatchesPerSite,num_swb)) + allocate(bc_out%albi_parb(fates_maxPatchesPerSite,num_swb)) + allocate(bc_out%fabd_parb(fates_maxPatchesPerSite,num_swb)) + allocate(bc_out%fabi_parb(fates_maxPatchesPerSite,num_swb)) + allocate(bc_out%ftdd_parb(fates_maxPatchesPerSite,num_swb)) + allocate(bc_out%ftid_parb(fates_maxPatchesPerSite,num_swb)) + allocate(bc_out%ftii_parb(fates_maxPatchesPerSite,num_swb)) ! We allocate the boundary conditions to the BGC ! model, regardless of what scheme we use. The BGC @@ -872,13 +879,13 @@ subroutine SetFatesGlobalElements2(use_fates) ! These values are used to define the restart file allocations and general structure ! of memory for the cohort arrays if(hlm_use_sp.eq.itrue) then - fates_maxElementsPerPatch = maxSWb + fates_maxElementsPerPatch = num_swb else - fates_maxElementsPerPatch = max(maxSWb,max_cohort_per_patch, ndcmpy*hlm_maxlevsoil ,ncwd*hlm_maxlevsoil) + fates_maxElementsPerPatch = max(num_swb,max_cohort_per_patch, ndcmpy*hlm_maxlevsoil ,ncwd*hlm_maxlevsoil) end if fates_maxElementsPerSite = max(fates_maxPatchesPerSite * fates_maxElementsPerPatch, & - numWatermem*numpft, num_vegtemp_mem, num_elements, nlevsclass*numpft) + numWatermem*numpft, num_vegtemp_mem, num_elements, nlevsclass*numpft*n_term_mort_types) if(hlm_use_planthydro==itrue)then fates_maxElementsPerSite = max(fates_maxElementsPerSite, nshell*nlevsoi_hyd_max ) @@ -1475,7 +1482,10 @@ subroutine set_fates_ctrlparms(tag,ival,rval,cval) hlm_use_sp = unset_int hlm_use_inventory_init = unset_int hlm_inventory_ctrl_file = 'unset' + hlm_hist_level_dynam = unset_int + hlm_hist_level_hifrq = unset_int + case('check_allset') if(hlm_numSWb .eq. unset_int) then @@ -1488,14 +1498,13 @@ subroutine set_fates_ctrlparms(tag,ival,rval,cval) call endrun(msg=errMsg(sourcefile, __LINE__)) end if - if(hlm_numSWb > maxSWb) then - write(fates_log(), *) 'FATES sets a maximum number of shortwave bands' - write(fates_log(), *) 'for some scratch-space, maxSWb' - write(fates_log(), *) 'it defaults to 2, but can be increased as needed' - write(fates_log(), *) 'your driver or host model is intending to drive' - write(fates_log(), *) 'FATES with:',hlm_numSWb,' bands.' - write(fates_log(), *) 'please increase maxSWb in EDTypes to match' - write(fates_log(), *) 'or exceed this value' + if(hlm_numSWb .ne. num_swb) then + write(fates_log(), *) 'FATES performs radiation scattering in the' + write(fates_log(), *) 'visible and near-infrared broad-bands for shortwave radiation.' + write(fates_log(), *) 'The host model has signaled to FATES that it is not tracking two' + write(fates_log(), *) 'bands.' + write(fates_log(), *) 'hlm_numSWb (HLM side):',hlm_numSWb + write(fates_log(), *) 'num_swb (FATES side): ',num_swb call endrun(msg=errMsg(sourcefile, __LINE__)) end if @@ -1676,6 +1685,16 @@ subroutine set_fates_ctrlparms(tag,ival,rval,cval) call endrun(msg=errMsg(sourcefile, __LINE__)) end if + if(hlm_hist_level_dynam .eq. unset_int) then + write(fates_log(), *) 'switch defining dynamics history level is unset, hlm_hist_level_dynam, exiting' + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + if(hlm_hist_level_hifrq .eq. unset_int) then + write(fates_log(), *) 'switch defining high-frequency history level is unset, hlm_hist_level_hifrq, exiting' + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + + if(hlm_use_ch4 .eq. unset_int) then write(fates_log(), *) 'switch for the HLMs CH4 module unset: hlm_use_ch4, exiting' call endrun(msg=errMsg(sourcefile, __LINE__)) @@ -1842,6 +1861,9 @@ subroutine set_fates_ctrlparms(tag,ival,rval,cval) write(fates_log(),*) 'Transfering hlm_seeddisp_cadence= ',ival,' to FATES' end if + + + case('spitfire_mode') hlm_spitfire_mode = ival if (fates_global_verbose()) then @@ -1915,6 +1937,12 @@ subroutine set_fates_ctrlparms(tag,ival,rval,cval) write(fates_log(),*) 'Transfering hlm_use_luh = ',ival,' to FATES' end if + case('use_fates_potentialveg') + hlm_use_potentialveg = ival + if (fates_global_verbose()) then + write(fates_log(),*) 'Transfering hlm_use_potentialveg = ',ival,' to FATES' + end if + case('num_luh2_states') hlm_num_luh2_states = ival if (fates_global_verbose()) then @@ -1957,6 +1985,19 @@ subroutine set_fates_ctrlparms(tag,ival,rval,cval) write(fates_log(),*) 'Transfering hlm_use_inventory_init= ',ival,' to FATES' end if + case('hist_hifrq_dimlevel') + hlm_hist_level_hifrq = ival + if (fates_global_verbose()) then + write(fates_log(),*) 'Transfering hlm_hist_level_hifrq= ',ival,' to FATES' + end if + + case('hist_dynam_dimlevel') + hlm_hist_level_dynam = ival + if (fates_global_verbose()) then + write(fates_log(),*) 'Transfering hlm_hist_level_dynam= ',ival,' to FATES' + end if + + case default write(fates_log(), *) 'fates NL tag not recognized:',trim(tag) !! call endrun(msg=errMsg(sourcefile, __LINE__)) @@ -1979,6 +2020,8 @@ subroutine set_fates_ctrlparms(tag,ival,rval,cval) if(present(cval))then select case (trim(tag)) + + case('hlm_name') hlm_name = trim(cval) @@ -2032,7 +2075,7 @@ subroutine FatesReportParameters(masterproc) call FatesCheckParams(masterproc) ! Check general fates parameters call PRTCheckParams(masterproc) ! Check PARTEH parameters call SpitFireCheckParams(masterproc) - + call TransferRadParams() return diff --git a/main/FatesInterfaceTypesMod.F90 b/main/FatesInterfaceTypesMod.F90 index 3178b140b1..75e64307a5 100644 --- a/main/FatesInterfaceTypesMod.F90 +++ b/main/FatesInterfaceTypesMod.F90 @@ -124,11 +124,12 @@ module FatesInterfaceTypesMod ! bc_in%hlm_harvest_rates and bc_in%hlm_harvest_catnames integer, public :: hlm_use_luh ! flag to signal whether or not to use luh2 drivers + integer, public :: hlm_use_potentialveg ! flag to signal whether or not to use potential vegetation only + ! (i.e., no land use and instead force all lands to be primary) integer, public :: hlm_num_luh2_states ! number of land use state types provided in LUH2 forcing dataset integer, public :: hlm_num_luh2_transitions ! number of land use transition types provided in LUH2 forcing dataset - integer, public :: hlm_sf_nofire_def ! Definition of a no-fire case for hlm_spitfire_mode integer, public :: hlm_sf_scalar_lightning_def ! Definition of a scalar-lightning case for hlm_spitfire_mode integer, public :: hlm_sf_successful_ignitions_def ! Definition of a successful-ignition dataset case for hlm_spitfire_mode @@ -199,6 +200,18 @@ module FatesInterfaceTypesMod integer, public :: hlm_use_sp ! Flag to use FATES satellite phenology (LAI) mode ! 1 = TRUE, 0 = FALSE + + ! Flag specifying what types of history fields to allocate and prepare + ! The "_dynam" refers to history fields that can be updated on the dynamics (daily) step + ! THe "_hifrq" refers to history fields that can be updated on the model (high-frequency) step + ! 0 = no output + ! 1 = site-level averages only + ! 2 = allow the second dimension + + integer, public :: hlm_hist_level_dynam + + integer, public :: hlm_hist_level_hifrq + ! ------------------------------------------------------------------------------------- ! Parameters that are dictated by FATES and known to be required knowledge ! needed by the HLMs @@ -229,7 +242,7 @@ module FatesInterfaceTypesMod ! dataset than the number of PFTs in FATES, we have to allocate with ! the prior so that we can hold the LAI data integer, public :: fates_maxPatchesPerSite - + integer, public :: max_comp_per_site ! This is the maximum number of nutrient aquisition ! competitors that will be generated on each site @@ -267,7 +280,7 @@ module FatesInterfaceTypesMod integer , public, allocatable :: fates_hdim_levfuel(:) ! fire fuel size class (fsc) dimension integer , public, allocatable :: fates_hdim_levcwdsc(:) ! cwd class dimension integer , public, allocatable :: fates_hdim_levcan(:) ! canopy-layer dimension - integer , public, allocatable :: fates_hdim_levleaf(:) ! leaf-layer dimension + real(r8), public, allocatable :: fates_hdim_levleaf(:) ! leaf-layer dimension, integrated VAI [m2/m2] integer , public, allocatable :: fates_hdim_levelem(:) ! element dimension integer , public, allocatable :: fates_hdim_canmap_levcnlf(:) ! canopy-layer map into the canopy-layer x leaf-layer dim integer , public, allocatable :: fates_hdim_lfmap_levcnlf(:) ! leaf-layer map into the can-layer x leaf-layer dimension @@ -561,7 +574,12 @@ module FatesInterfaceTypesMod real(r8) :: site_area ! Actual area of current site [m2], only used in carbon-based harvest ! Fixed biogeography mode - real(r8), allocatable :: pft_areafrac(:) ! Fractional area of the FATES column occupied by each PFT + real(r8), allocatable :: pft_areafrac(:) ! Fractional area of the FATES column occupied by each PFT + + ! Fixed biogeography mode with land use active + real(r8), allocatable :: pft_areafrac_lu(:,:) ! Fractional area occupied by each PFT on each land use type + real(r8) :: baregroundfrac ! fractional area held as bare-ground + ! Satellite Phenology (SP) input variables. (where each patch only has one PFT) ! --------------------------------------------------------------------------------- diff --git a/main/FatesInventoryInitMod.F90 b/main/FatesInventoryInitMod.F90 index d5ad38342a..22a48537b5 100644 --- a/main/FatesInventoryInitMod.F90 +++ b/main/FatesInventoryInitMod.F90 @@ -37,7 +37,6 @@ module FatesInventoryInitMod use FatesInterfaceTypesMod, only : hlm_inventory_ctrl_file use FatesInterfaceTypesMod, only : nleafage use FatesInterfaceTypesMod, only : hlm_current_tod - use FatesInterfaceTypesMod, only : hlm_numSWb use FatesInterfaceTypesMod, only : numpft use FatesLitterMod , only : litter_type use EDTypesMod , only : ed_site_type @@ -76,7 +75,7 @@ module FatesInventoryInitMod use PRTGenericMod, only : StorageNutrientTarget use FatesConstantsMod, only : fates_unset_int use EDCanopyStructureMod, only : canopy_summarization, canopy_structure - + use FatesRadiationMemMod, only : num_swb implicit none private @@ -285,7 +284,7 @@ subroutine initialize_sites_by_inventory(nsites,sites,bc_in) area_init = 0.0_r8 allocate(newpatch) call newpatch%Create(age_init, area_init, primaryland, & - fates_unset_int, hlm_numSWb, numpft, sites(s)%nlevsoil, & + fates_unset_int, num_swb, numpft, sites(s)%nlevsoil, & hlm_current_tod, regeneration_model) newpatch%patchno = ipa @@ -687,7 +686,7 @@ subroutine set_inventory_patch_type1(newpatch,pss_file_unit,ipa,ios,patch_name) type(litter_type),pointer :: litt integer :: el ! index for elements real(r8) :: p_time ! Time patch was recorded - real(r8) :: p_trk ! Land Use index (see above descriptions) + integer :: p_trk ! Land Use index (see above descriptions) character(len=patchname_strlen) :: p_name ! unique string identifier of patch real(r8) :: p_age ! Patch age [years] real(r8) :: p_area ! Patch area [fraction] @@ -695,9 +694,10 @@ subroutine set_inventory_patch_type1(newpatch,pss_file_unit,ipa,ios,patch_name) integer :: ipft ! index for counting PFTs real(r8) :: pftfrac ! the inverse of the total number of PFTs - character(len=128),parameter :: wr_fmt = & - '(F5.2,2X,A4,2X,F5.2,2X,F5.2,2X,F5.2,2X,F5.2,2X,F5.2,2X,F5.2,2X,F5.2,2X,F5.2,2X,F5.2,2X,F5.2,2X,F5.2)' - + character(len=30),parameter :: hd_fmt = & + '(A5,2X,A20,2X,A4,2X,A5,2X,A17)' + character(len=47),parameter :: wr_fmt = & + '(F5.2,2X,A20,2X,I4,2X,F5.2,2X,F17.14)' read(pss_file_unit,fmt=*,iostat=ios) p_time, p_name, p_trk, p_age, p_area @@ -706,6 +706,8 @@ subroutine set_inventory_patch_type1(newpatch,pss_file_unit,ipa,ios,patch_name) patch_name = trim(p_name) if( debug_inv) then + write(*,fmt=hd_fmt) & + ' time',' patch',' trk',' age',' area' write(*,fmt=wr_fmt) & p_time, p_name, p_trk, p_age, p_area end if @@ -829,8 +831,10 @@ subroutine set_inventory_cohort_type1(csite,bc_in,css_file_unit,npatches, & real(r8) :: stem_drop_fraction ! Stem abscission fraction integer :: i_pft, ncohorts_to_create - character(len=128),parameter :: wr_fmt = & - '(F7.1,2X,A20,2X,A20,2X,F5.2,2X,F5.2,2X,I4,2X,F5.2,2X,F5.2,2X,F5.2,2X,F5.2)' + character(len=35),parameter :: hd_fmt = & + '(A7,2X,A20,2X,A5,2X,A6,2X,A4,2X,A9)' + character(len=43),parameter :: wr_fmt = & + '(F7.1,2X,A20,2X,F5.2,2X,F6.2,2X,I4,2X,F9.6)' real(r8), parameter :: abnormal_large_nplant = 1000.0_r8 ! Used to catch bad values real(r8), parameter :: abnormal_large_dbh = 500.0_r8 ! I've never heard of a tree > 3m @@ -859,6 +863,8 @@ subroutine set_inventory_cohort_type1(csite,bc_in,css_file_unit,npatches, & if(.not.matched_patch)then write(fates_log(), *) 'could not match a cohort with a patch' + write(fates_log(),fmt=hd_fmt) & + ' time',' patch',' dbh','height',' pft',' nplant' write(fates_log(),fmt=wr_fmt) & c_time, p_name, c_dbh, c_height, c_pft, c_nplant call endrun(msg=errMsg(sourcefile, __LINE__)) @@ -952,7 +958,7 @@ subroutine set_inventory_cohort_type1(csite,bc_in,css_file_unit,npatches, & temp_cohort%height = c_height call h2d_allom(c_height,temp_cohort%pft,temp_cohort%dbh) end if - + temp_cohort%canopy_trim = 1.0_r8 ! Determine the phenology status and the elongation factors. diff --git a/main/FatesParametersInterface.F90 b/main/FatesParametersInterface.F90 index aa0ef85287..0559ec3eb6 100644 --- a/main/FatesParametersInterface.F90 +++ b/main/FatesParametersInterface.F90 @@ -135,7 +135,7 @@ subroutine Destroy(this) integer :: n do n = 1, this%num_parameters - deallocate(this%parameters(n)%data) + deallocate(this%parameters(n)%data) end do end subroutine Destroy diff --git a/main/FatesRestartInterfaceMod.F90 b/main/FatesRestartInterfaceMod.F90 index bbc6dd1328..3f7e8375fe 100644 --- a/main/FatesRestartInterfaceMod.F90 +++ b/main/FatesRestartInterfaceMod.F90 @@ -10,6 +10,7 @@ module FatesRestartInterfaceMod use FatesConstantsMod, only : fates_unset_r8, fates_unset_int use FatesConstantsMod, only : primaryland use FatesConstantsMod, only : nearzero + use FatesConstantsMod, only : n_landuse_cats use FatesConstantsMod, only : default_regeneration use FatesConstantsMod, only : TRS_regeneration use FatesGlobals, only : fates_log @@ -24,6 +25,7 @@ module FatesRestartInterfaceMod use FatesInterfaceTypesMod, only : hlm_parteh_mode use FatesInterfaceTypesMod, only : hlm_use_sp use FatesInterfaceTypesMod, only : hlm_use_nocomp, hlm_use_fixed_biogeog + use FatesInterfaceTypesMod, only : hlm_use_potentialveg use FatesInterfaceTypesMod, only : fates_maxElementsPerSite use FatesInterfaceTypesMod, only : hlm_use_tree_damage use FatesHydraulicsMemMod, only : nshell @@ -46,10 +48,14 @@ module FatesRestartInterfaceMod use PRTGenericMod, only : num_elements use FatesRunningMeanMod, only : rmean_type use FatesRunningMeanMod, only : ema_lpa + use FatesRadiationMemMod, only : num_swb,norman_solver,twostr_solver + use TwoStreamMLPEMod, only : normalized_upper_boundary use EDParamsMod, only : regeneration_model + use EDParamsMod, only : radiation_model + use FatesConstantsMod, only : n_term_mort_types use FatesConstantsMod, only : n_landuse_cats use FatesConstantsMod, only : N_DIST_TYPES - + ! CIME GLOBALS use shr_log_mod , only : errMsg => shr_log_errMsg @@ -95,11 +101,14 @@ module FatesRestartInterfaceMod integer :: ir_cndaysleafon_si integer :: ir_cndaysleafoff_si integer :: ir_phenmodeldate_si - integer :: ir_acc_ni_si + integer :: ir_fireweather_index_si integer :: ir_gdd_si + integer :: ir_min_allowed_landuse_fraction_si + integer :: ir_landuse_vector_gt_min_si + integer :: ir_area_bareground_si integer :: ir_snow_depth_si integer :: ir_trunk_product_si - + integer :: ir_landuse_config_si integer :: ir_ncohort_pa integer :: ir_canopy_layer_co integer :: ir_canopy_layer_yesterday_co @@ -263,7 +272,8 @@ module FatesRestartInterfaceMod integer :: ir_rootlittin_flxdg integer :: ir_oldstock_mbal integer :: ir_errfates_mbal - integer :: ir_woodprod_mbal + integer :: ir_woodprod_harvest_mbal + integer :: ir_woodprod_landusechange_mbal integer :: ir_prt_base ! Base index for all PRT variables ! site-level input seed from dispersal @@ -700,12 +710,24 @@ subroutine define_restart_vars(this, initialize_variables) call this%set_restart_var(vname='fates_acc_nesterov_id', vtype=site_r8, & long_name='a nesterov index accumulator', units='unitless', flushval = flushzero, & - hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_acc_ni_si ) + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_fireweather_index_si ) call this%set_restart_var(vname='fates_gdd_site', vtype=site_r8, & long_name='growing degree days at each site', units='degC days', flushval = flushzero, & hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_gdd_si ) + call this%set_restart_var(vname='fates_min_allowed_landuse_fraction_site', vtype=site_r8, & + long_name='minimum allowed land use fraction at each site', units='fraction', flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_min_allowed_landuse_fraction_si ) + + call this%set_restart_var(vname='fates_landuse_vector_gt_min_site', vtype=cohort_int, & + long_name='minimum allowed land use fraction at each site', units='logical', flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_landuse_vector_gt_min_si ) + + call this%set_restart_var(vname='fates_area_bareground_site', vtype=site_r8, & + long_name='minimum allowed land use fraction at each site', units='fraction', flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_area_bareground_si ) + call this%set_restart_var(vname='fates_snow_depth_site', vtype=site_r8, & long_name='average snow depth', units='m', flushval = flushzero, & hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_snow_depth_si ) @@ -715,6 +737,11 @@ subroutine define_restart_vars(this, initialize_variables) units='kgC/m2', flushval = flushzero, & hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_trunk_product_si ) + call this%set_restart_var(vname='fates_landuse_config_site', vtype=site_int, & + long_name='hlm_use_potentialveg status of run that created this restart file', & + units='kgC/m2', flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_landuse_config_si ) + ! ----------------------------------------------------------------------------------- ! Variables stored within cohort vectors ! Note: Some of these are multi-dimensional variables in the patch/site dimension @@ -1130,10 +1157,15 @@ subroutine define_restart_vars(this, initialize_variables) end if - call this%RegisterCohortVector(symbol_base='fates_woodproduct', vtype=site_r8, & - long_name_base='Current wood product flux', & + call this%RegisterCohortVector(symbol_base='fates_woodprod_harv', vtype=cohort_r8, & + long_name_base='Current wood product flux from harvest', & units='kg/m2/day', veclength=num_elements, flushval = flushzero, & - hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_woodprod_mbal) + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_woodprod_harvest_mbal) + + call this%RegisterCohortVector(symbol_base='fates_woodprod_luc', vtype=cohort_r8, & + long_name_base='Current wood product flux from land use change', & + units='kg/m2/day', veclength=num_elements, flushval = flushzero, & + hlms='CLM:ALM', initialize=initialize_variables, ivar=ivar, index = ir_woodprod_landusechange_mbal) ! Only register satellite phenology related restart variables if it is turned on! @@ -1943,7 +1975,6 @@ subroutine set_restart_vectors(this,nc,nsites,sites) use EDTypesMod, only : ed_site_type use FatesCohortMod, only : fates_cohort_type use FatesPatchMod, only : fates_patch_type - use EDParamsMod, only : maxSWb use EDParamsMod, only : nclmax use EDTypesMod, only : numWaterMem use EDTypesMod, only : num_vegtemp_mem @@ -1989,7 +2020,10 @@ subroutine set_restart_vectors(this,nc,nsites,sites) integer :: io_idx_si_pft ! each site-pft index integer :: io_idx_si_vtmem ! indices for veg-temp memory at site integer :: io_idx_pa_ncl ! each canopy layer within each patch + integer :: io_idx_si_scpf_term ! loop counter for scls, pft, and termination type + integer :: io_idx_si_pft_term ! loop counter for pft, and termination type integer :: io_idx_si_luludi ! site-level lu x lu x ndist index + integer :: io_idx_si_lu ! site-level lu index ! Some counters (for checking mostly) integer :: totalcohorts ! total cohort count on this thread (diagnostic) @@ -2012,8 +2046,10 @@ subroutine set_restart_vectors(this,nc,nsites,sites) integer :: i_cdam ! loop counter for damage integer :: icdi ! loop counter for damage integer :: icdj ! loop counter for damage + integer :: i_landuse,i_pflu ! loop counter for land use class + integer :: i_term_type ! loop counter for termination type integer :: i_lu_donor, i_lu_receiver, i_dist ! loop counters for land use and disturbance - + type(fates_restart_variable_type) :: rvar type(fates_patch_type),pointer :: cpatch type(fates_cohort_type),pointer :: ccohort @@ -2028,10 +2064,14 @@ subroutine set_restart_vectors(this,nc,nsites,sites) rio_cndaysleafon_si => this%rvars(ir_cndaysleafon_si)%int1d, & rio_cndaysleafoff_si => this%rvars(ir_cndaysleafoff_si)%int1d, & rio_phenmodeldate_si => this%rvars(ir_phenmodeldate_si)%int1d, & - rio_acc_ni_si => this%rvars(ir_acc_ni_si)%r81d, & + rio_fireweather_index_si => this%rvars(ir_fireweather_index_si)%r81d, & rio_gdd_si => this%rvars(ir_gdd_si)%r81d, & + rio_min_allowed_landuse_fraction_si => this%rvars(ir_min_allowed_landuse_fraction_si)%r81d, & + rio_landuse_vector_gt_min_si => this%rvars(ir_landuse_vector_gt_min_si)%int1d, & + rio_area_bareground_si => this%rvars(ir_area_bareground_si)%r81d, & rio_snow_depth_si => this%rvars(ir_snow_depth_si)%r81d, & rio_trunk_product_si => this%rvars(ir_trunk_product_si)%r81d, & + rio_landuse_config_s => this%rvars(ir_landuse_config_si)%int1d, & rio_ncohort_pa => this%rvars(ir_ncohort_pa)%int1d, & rio_fcansno_pa => this%rvars(ir_fcansno_pa)%r81d, & rio_solar_zenith_flag_pa => this%rvars(ir_solar_zenith_flag_pa)%int1d, & @@ -2124,6 +2164,7 @@ subroutine set_restart_vectors(this,nc,nsites,sites) rio_abg_fmort_flux_siscpf => this%rvars(ir_abg_fmort_flux_siscpf)%r81d, & rio_abg_term_flux_siscpf => this%rvars(ir_abg_term_flux_siscpf)%r81d, & rio_disturbance_rates_siluludi => this%rvars(ir_disturbance_rates_siluludi)%r81d, & + rio_landuse_config_si => this%rvars(ir_landuse_config_si)%int1d, & rio_imortrate_sicdpf => this%rvars(ir_imortrate_sicdpf)%r81d, & rio_imortcflux_sicdsc => this%rvars(ir_imortcflux_sicdsc)%r81d, & @@ -2173,7 +2214,10 @@ subroutine set_restart_vectors(this,nc,nsites,sites) io_idx_si_cdpf = io_idx_co_1st io_idx_si_scpf = io_idx_co_1st io_idx_si_pft = io_idx_co_1st + io_idx_si_scpf_term = io_idx_co_1st + io_idx_si_pft_term = io_idx_co_1st io_idx_si_luludi = io_idx_co_1st + io_idx_si_lu = io_idx_co_1st ! recruitment rate do i_pft = 1,numpft @@ -2185,9 +2229,24 @@ subroutine set_restart_vectors(this,nc,nsites,sites) end do do i_pft = 1,numpft - rio_area_pft_sift(io_idx_co_1st+i_pft-1) = sites(s)%area_pft(i_pft) + do i_landuse = 1, n_landuse_cats + i_pflu = i_landuse + (i_pft - 1) * n_landuse_cats + rio_area_pft_sift(io_idx_co_1st+i_pflu-1) = sites(s)%area_pft(i_pft, i_landuse) + end do end do + rio_min_allowed_landuse_fraction_si(io_idx_si) = sites(s)%min_allowed_landuse_fraction + do i_landuse = 1, n_landuse_cats + if ( sites(s)%landuse_vector_gt_min(i_landuse)) then + rio_landuse_vector_gt_min_si(io_idx_si_lu) = itrue + else + rio_landuse_vector_gt_min_si(io_idx_si_lu) = ifalse + endif + io_idx_si_lu = io_idx_si_lu + 1 + end do + + rio_area_bareground_si(io_idx_si) = sites(s)%area_bareground + do i_scls = 1, nlevsclass do i_pft = 1, numpft rio_fmortrate_cano_siscpf(io_idx_si_scpf) = sites(s)%fmort_rate_canopy(i_scls, i_pft) @@ -2195,19 +2254,25 @@ subroutine set_restart_vectors(this,nc,nsites,sites) rio_imortrate_siscpf(io_idx_si_scpf) = sites(s)%imort_rate(i_scls, i_pft) rio_fmortrate_crown_siscpf(io_idx_si_scpf) = sites(s)%fmort_rate_crown(i_scls, i_pft) rio_fmortrate_cambi_siscpf(io_idx_si_scpf) = sites(s)%fmort_rate_cambial(i_scls, i_pft) - rio_termnindiv_cano_siscpf(io_idx_si_scpf) = sites(s)%term_nindivs_canopy(i_scls,i_pft) - rio_termnindiv_usto_siscpf(io_idx_si_scpf) = sites(s)%term_nindivs_ustory(i_scls,i_pft) rio_growflx_fusion_siscpf(io_idx_si_scpf) = sites(s)%growthflux_fusion(i_scls, i_pft) rio_abg_term_flux_siscpf(io_idx_si_scpf) = sites(s)%term_abg_flux(i_scls, i_pft) rio_abg_imort_flux_siscpf(io_idx_si_scpf) = sites(s)%imort_abg_flux(i_scls, i_pft) rio_abg_fmort_flux_siscpf(io_idx_si_scpf) = sites(s)%fmort_abg_flux(i_scls, i_pft) io_idx_si_scpf = io_idx_si_scpf + 1 + do i_term_type = 1, n_term_mort_types + rio_termnindiv_cano_siscpf(io_idx_si_scpf_term) = sites(s)%term_nindivs_canopy(i_term_type,i_scls,i_pft) + rio_termnindiv_usto_siscpf(io_idx_si_scpf_term) = sites(s)%term_nindivs_ustory(i_term_type,i_scls,i_pft) + io_idx_si_scpf_term = io_idx_si_scpf_term + 1 + end do end do end do do i_pft = 1, numpft - rio_termcflux_cano_sipft(io_idx_si_pft) = sites(s)%term_carbonflux_canopy(i_pft) - rio_termcflux_usto_sipft(io_idx_si_pft) = sites(s)%term_carbonflux_ustory(i_pft) + do i_term_type = 1, n_term_mort_types + rio_termcflux_cano_sipft(io_idx_si_pft_term) = sites(s)%term_carbonflux_canopy(i_term_type,i_pft) + rio_termcflux_usto_sipft(io_idx_si_pft_term) = sites(s)%term_carbonflux_ustory(i_term_type,i_pft) + io_idx_si_pft_term = io_idx_si_pft_term + 1 + end do rio_fmortcflux_cano_sipft(io_idx_si_pft) = sites(s)%fmort_carbonflux_canopy(i_pft) rio_fmortcflux_usto_sipft(io_idx_si_pft) = sites(s)%fmort_carbonflux_ustory(i_pft) rio_imortcflux_sipft(io_idx_si_pft) = sites(s)%imort_carbonflux(i_pft) @@ -2248,12 +2313,13 @@ subroutine set_restart_vectors(this,nc,nsites,sites) do i_pft=1,numpft this%rvars(ir_leaflittin_flxdg+el-1)%r81d(io_idx_si_pft) = sites(s)%flux_diags(el)%leaf_litter_input(i_pft) this%rvars(ir_rootlittin_flxdg+el-1)%r81d(io_idx_si_pft) = sites(s)%flux_diags(el)%root_litter_input(i_pft) + this%rvars(ir_woodprod_harvest_mbal+el-1)%r81d(io_idx_si_pft) = sites(s)%mass_balance(el)%wood_product_harvest(i_pft) + this%rvars(ir_woodprod_landusechange_mbal+el-1)%r81d(io_idx_si_pft) = sites(s)%mass_balance(el)%wood_product_landusechange(i_pft) io_idx_si_pft = io_idx_si_pft + 1 end do this%rvars(ir_oldstock_mbal+el-1)%r81d(io_idx_si) = sites(s)%mass_balance(el)%old_stock this%rvars(ir_errfates_mbal+el-1)%r81d(io_idx_si) = sites(s)%mass_balance(el)%err_fates - this%rvars(ir_woodprod_mbal+el-1)%r81d(io_idx_si) = sites(s)%mass_balance(el)%wood_product end do end if @@ -2528,7 +2594,7 @@ subroutine set_restart_vectors(this,nc,nsites,sites) end do end if - do i = 1,maxSWb + do i = 1,num_swb rio_gnd_alb_dif_pasb(io_idx_pa_ib) = cpatch%gnd_alb_dif(i) rio_gnd_alb_dir_pasb(io_idx_pa_ib) = cpatch%gnd_alb_dir(i) io_idx_pa_ib = io_idx_pa_ib + 1 @@ -2624,11 +2690,15 @@ subroutine set_restart_vectors(this,nc,nsites,sites) - rio_acc_ni_si(io_idx_si) = sites(s)%acc_NI + rio_fireweather_index_si(io_idx_si) = sites(s)%fireWeather%fire_weather_index rio_snow_depth_si(io_idx_si) = sites(s)%snow_depth ! Accumulated trunk product rio_trunk_product_si(io_idx_si) = sites(s)%resources_management%trunk_product_site + + ! land use flag + rio_landuse_config_si(io_idx_si) = hlm_use_potentialveg + ! set numpatches for this column rio_npatch_si(io_idx_si) = patchespersite @@ -2699,17 +2769,16 @@ subroutine create_patchcohort_structure(this, nc, nsites, sites, bc_in, bc_out) ! linked-list state structure. ! --------------------------------------------------------------------------------- - use EDTypesMod, only : ed_site_type - use FatesCohortMod, only : fates_cohort_type - use FatesPatchMod, only : fates_patch_type - use EDParamsMod, only : maxSWb, regeneration_model - use FatesInterfaceTypesMod, only : fates_maxElementsPerPatch - use FatesInterfaceTypesMod, only : hlm_current_tod, hlm_numSWb, numpft - - use EDTypesMod, only : area - use EDInitMod, only : zero_site - use EDInitMod, only : init_site_vars - use FatesAllometryMod, only : h2d_allom + use EDTypesMod, only : ed_site_type + use FatesCohortMod, only : fates_cohort_type + use FatesPatchMod, only : fates_patch_type + use EDParamsMod, only : regeneration_model + use FatesInterfaceTypesMod, only : fates_maxElementsPerPatch + use FatesInterfaceTypesMod, only : hlm_current_tod, numpft + use EDTypesMod, only : area + use EDInitMod, only : zero_site + use EDInitMod, only : init_site_vars + use FatesAllometryMod, only : h2d_allom ! !ARGUMENTS: @@ -2776,7 +2845,7 @@ subroutine create_patchcohort_structure(this, nc, nsites, sites, bc_in, bc_out) ! the nocomp_pft label is set after patch creation has occured in 'get_restart_vectors' ! make new patch call newp%Create(fates_unset_r8, fates_unset_r8, primaryland, & - nocomp_pft, hlm_numSWb, numpft, sites(s)%nlevsoil, & + nocomp_pft, num_swb, numpft, sites(s)%nlevsoil, & hlm_current_tod, regeneration_model) ! Initialize the litter pools to zero, these @@ -2900,7 +2969,6 @@ subroutine get_restart_vectors(this, nc, nsites, sites) use EDTypesMod, only : ed_site_type use FatesCohortMod, only : fates_cohort_type use FatesPatchMod, only : fates_patch_type - use EDParamsMod, only : maxSWb use EDParamsMod, only : nclmax use FatesInterfaceTypesMod, only : numpft use FatesInterfaceTypesMod, only : fates_maxElementsPerPatch @@ -2955,7 +3023,10 @@ subroutine get_restart_vectors(this, nc, nsites, sites) integer :: io_idx_si_cdpf ! damage x size x pft within site integer :: io_idx_pa_ncl ! each canopy layer within each patch + integer :: io_idx_si_scpf_term ! loop counter for scls, pft, and termination type + integer :: io_idx_si_pft_term ! loop counter for pft, and termination type integer :: io_idx_si_luludi ! site-level lu x lu x ndist index + integer :: io_idx_si_lu ! site-level lu x lu x ndist index ! Some counters (for checking mostly) integer :: totalcohorts ! total cohort count on this thread (diagnostic) @@ -2975,7 +3046,9 @@ subroutine get_restart_vectors(this, nc, nsites, sites) integer :: i_cdam ! loop counter for damage class integer :: icdj ! loop counter for damage class integer :: icdi ! loop counter for damage class + integer :: i_landuse,i_pflu ! loop counter for land use class integer :: i_lu_donor, i_lu_receiver, i_dist ! loop counters for land use and disturbance + integer :: i_term_type ! loop counter for termination type associate( rio_npatch_si => this%rvars(ir_npatch_si)%int1d, & rio_cd_status_si => this%rvars(ir_cd_status_si)%int1d, & @@ -2986,10 +3059,14 @@ subroutine get_restart_vectors(this, nc, nsites, sites) rio_cndaysleafon_si => this%rvars(ir_cndaysleafon_si)%int1d, & rio_cndaysleafoff_si => this%rvars(ir_cndaysleafoff_si)%int1d, & rio_phenmodeldate_si => this%rvars(ir_phenmodeldate_si)%int1d, & - rio_acc_ni_si => this%rvars(ir_acc_ni_si)%r81d, & + rio_fireweather_index_si => this%rvars(ir_fireweather_index_si)%r81d, & rio_gdd_si => this%rvars(ir_gdd_si)%r81d, & + rio_min_allowed_landuse_fraction_si => this%rvars(ir_min_allowed_landuse_fraction_si)%r81d, & + rio_landuse_vector_gt_min_si => this%rvars(ir_landuse_vector_gt_min_si)%int1d, & + rio_area_bareground_si => this%rvars(ir_area_bareground_si)%r81d, & rio_snow_depth_si => this%rvars(ir_snow_depth_si)%r81d, & rio_trunk_product_si => this%rvars(ir_trunk_product_si)%r81d, & + rio_landuse_config_si => this%rvars(ir_landuse_config_si)%int1d, & rio_ncohort_pa => this%rvars(ir_ncohort_pa)%int1d, & rio_fcansno_pa => this%rvars(ir_fcansno_pa)%r81d, & rio_solar_zenith_flag_pa => this%rvars(ir_solar_zenith_flag_pa)%int1d, & @@ -3121,7 +3198,11 @@ subroutine get_restart_vectors(this, nc, nsites, sites) io_idx_si_cdpf = io_idx_co_1st io_idx_si_scpf = io_idx_co_1st io_idx_si_pft = io_idx_co_1st + io_idx_si_scpf_term = io_idx_co_1st + io_idx_si_pft_term = io_idx_co_1st + io_idx_si_luludi = io_idx_co_1st + io_idx_si_lu = io_idx_co_1st ! read seed_bank info(site-level, but PFT-resolved) do i_pft = 1,numpft @@ -3131,17 +3212,22 @@ subroutine get_restart_vectors(this, nc, nsites, sites) ! variables for fixed biogeography mode. These are currently used in restart even when this is off. do i_pft = 1,numpft sites(s)%use_this_pft(i_pft) = rio_use_this_pft_sift(io_idx_co_1st+i_pft-1) - sites(s)%area_pft(i_pft) = rio_area_pft_sift(io_idx_co_1st+i_pft-1) + do i_landuse = 1, n_landuse_cats + i_pflu = i_landuse + (i_pft - 1) * n_landuse_cats + sites(s)%area_pft(i_pft, i_landuse) = rio_area_pft_sift(io_idx_co_1st+i_pflu-1) + end do enddo - ! calculate the bareground area for the pft in no competition + fixed biogeo modes - if (hlm_use_nocomp .eq. itrue .and. hlm_use_fixed_biogeog .eq. itrue) then - if (area-sum(sites(s)%area_pft(1:numpft)) .gt. nearzero) then - sites(s)%area_pft(0) = area - sum(sites(s)%area_pft(1:numpft)) + sites(s)%min_allowed_landuse_fraction = rio_min_allowed_landuse_fraction_si(io_idx_si) + do i_landuse = 1, n_landuse_cats + if ( rio_landuse_vector_gt_min_si(io_idx_si_lu) .eq. itrue ) then + sites(s)%landuse_vector_gt_min(i_landuse) = .true. else - sites(s)%area_pft(0) = 0.0_r8 + sites(s)%landuse_vector_gt_min(i_landuse) = .false. endif - endif + io_idx_si_lu = io_idx_si_lu + 1 + end do + sites(s)%area_bareground = rio_area_bareground_si(io_idx_si) do i_scls = 1,nlevsclass do i_pft = 1, numpft @@ -3150,19 +3236,25 @@ subroutine get_restart_vectors(this, nc, nsites, sites) sites(s)%imort_rate(i_scls, i_pft) = rio_imortrate_siscpf(io_idx_si_scpf) sites(s)%fmort_rate_crown(i_scls, i_pft) = rio_fmortrate_crown_siscpf(io_idx_si_scpf) sites(s)%fmort_rate_cambial(i_scls, i_pft) = rio_fmortrate_cambi_siscpf(io_idx_si_scpf) - sites(s)%term_nindivs_canopy(i_scls,i_pft) = rio_termnindiv_cano_siscpf(io_idx_si_scpf) - sites(s)%term_nindivs_ustory(i_scls,i_pft) = rio_termnindiv_usto_siscpf(io_idx_si_scpf) sites(s)%growthflux_fusion(i_scls, i_pft) = rio_growflx_fusion_siscpf(io_idx_si_scpf) sites(s)%term_abg_flux(i_scls,i_pft) = rio_abg_term_flux_siscpf(io_idx_si_scpf) sites(s)%imort_abg_flux(i_scls,i_pft) = rio_abg_imort_flux_siscpf(io_idx_si_scpf) sites(s)%fmort_abg_flux(i_scls,i_pft) = rio_abg_fmort_flux_siscpf(io_idx_si_scpf) io_idx_si_scpf = io_idx_si_scpf + 1 + do i_term_type = 1, n_term_mort_types + sites(s)%term_nindivs_canopy(i_term_type,i_scls,i_pft) = rio_termnindiv_cano_siscpf(io_idx_si_scpf_term) + sites(s)%term_nindivs_ustory(i_term_type,i_scls,i_pft) = rio_termnindiv_usto_siscpf(io_idx_si_scpf_term) + io_idx_si_scpf_term = io_idx_si_scpf_term + 1 + end do end do end do do i_pft = 1, numpft - sites(s)%term_carbonflux_canopy(i_pft) = rio_termcflux_cano_sipft(io_idx_si_pft) - sites(s)%term_carbonflux_ustory(i_pft) = rio_termcflux_usto_sipft(io_idx_si_pft) + do i_term_type = 1, n_term_mort_types + sites(s)%term_carbonflux_canopy(i_term_type,i_pft) = rio_termcflux_cano_sipft(io_idx_si_pft_term) + sites(s)%term_carbonflux_ustory(i_term_type,i_pft) = rio_termcflux_usto_sipft(io_idx_si_pft_term) + io_idx_si_pft_term = io_idx_si_pft_term + 1 + end do sites(s)%fmort_carbonflux_canopy(i_pft) = rio_fmortcflux_cano_sipft(io_idx_si_pft) sites(s)%fmort_carbonflux_ustory(i_pft) = rio_fmortcflux_usto_sipft(io_idx_si_pft) sites(s)%imort_carbonflux(i_pft) = rio_imortcflux_sipft(io_idx_si_pft) @@ -3204,12 +3296,13 @@ subroutine get_restart_vectors(this, nc, nsites, sites) do i_pft=1,numpft sites(s)%flux_diags(el)%leaf_litter_input(i_pft) = this%rvars(ir_leaflittin_flxdg+el-1)%r81d(io_idx_si_pft) sites(s)%flux_diags(el)%root_litter_input(i_pft) = this%rvars(ir_rootlittin_flxdg+el-1)%r81d(io_idx_si_pft) + sites(s)%mass_balance(el)%wood_product_harvest(i_pft) = this%rvars(ir_woodprod_harvest_mbal+el-1)%r81d(io_idx_si_pft) + sites(s)%mass_balance(el)%wood_product_landusechange(i_pft) = this%rvars(ir_woodprod_landusechange_mbal+el-1)%r81d(io_idx_si_pft) io_idx_si_pft = io_idx_si_pft + 1 end do sites(s)%mass_balance(el)%old_stock = this%rvars(ir_oldstock_mbal+el-1)%r81d(io_idx_si) sites(s)%mass_balance(el)%err_fates = this%rvars(ir_errfates_mbal+el-1)%r81d(io_idx_si) - sites(s)%mass_balance(el)%wood_product = this%rvars(ir_woodprod_mbal+el-1)%r81d(io_idx_si) end do end if @@ -3473,7 +3566,7 @@ subroutine get_restart_vectors(this, nc, nsites, sites) end if - do i = 1,maxSWb + do i = 1,num_swb cpatch%gnd_alb_dif(i) = rio_gnd_alb_dif_pasb(io_idx_pa_ib) cpatch%gnd_alb_dir(i) = rio_gnd_alb_dir_pasb(io_idx_pa_ib) io_idx_pa_ib = io_idx_pa_ib + 1 @@ -3619,10 +3712,22 @@ subroutine get_restart_vectors(this, nc, nsites, sites) - sites(s)%acc_NI = rio_acc_ni_si(io_idx_si) + sites(s)%fireWeather%fire_weather_index = rio_fireweather_index_si(io_idx_si) sites(s)%snow_depth = rio_snow_depth_si(io_idx_si) sites(s)%resources_management%trunk_product_site = rio_trunk_product_si(io_idx_si) + ! if needed, trigger the special procedure to initialize land use structure from a + ! restart run that did not include land use. + if (rio_landuse_config_si(io_idx_si) .eq. itrue .and. hlm_use_potentialveg .eq. ifalse) then + sites(s)%transition_landuse_from_off_to_on = .true. + else if ( rio_landuse_config_si(io_idx_si) .ne. hlm_use_potentialveg ) then + ! can't go back into potential vegetation mode, it is a one-way thing. + write(fates_log(),*) 'this combination of rio_landuse_config_si(io_idx_si) and hlm_use_potentialveg is not permitted' + write(fates_log(),*) 'rio_landuse_config_si(io_idx_si)', rio_landuse_config_si(io_idx_si) + write(fates_log(),*) 'hlm_use_potentialveg', hlm_use_potentialveg + call endrun(msg=errMsg(sourcefile, __LINE__)) + endif + end do if ( debug ) then @@ -3641,10 +3746,9 @@ subroutine update_3dpatch_radiation(this, nsites, sites, bc_out) ! called upon restart reads. ! ------------------------------------------------------------------------- - use EDTypesMod, only : ed_site_type - use FatesPatchMod, only : fates_patch_type - use EDSurfaceRadiationMod, only : PatchNormanRadiation - use FatesInterfaceTypesMod, only : hlm_numSWb + use FatesNormanRadMod, only : PatchNormanRadiation + use EDTypesMod, only : ed_site_type + use FatesPatchMod, only : fates_patch_type ! !ARGUMENTS: class(fates_restart_interface_type) , intent(inout) :: this @@ -3677,9 +3781,9 @@ subroutine update_3dpatch_radiation(this, nsites, sites, bc_out) ! zero diagnostic radiation profiles currentPatch%nrmlzd_parprof_pft_dir_z(:,:,:,:) = 0._r8 currentPatch%nrmlzd_parprof_pft_dif_z(:,:,:,:) = 0._r8 - currentPatch%nrmlzd_parprof_dir_z(:,:,:) = 0._r8 - currentPatch%nrmlzd_parprof_dif_z(:,:,:) = 0._r8 + currentPatch%rad_error(:) = 0._r8 + ! ----------------------------------------------------------- ! When calling norman radiation from the short-timestep ! we are passing in boundary conditions to set the following @@ -3703,7 +3807,7 @@ subroutine update_3dpatch_radiation(this, nsites, sites, bc_out) ! no radiation is absorbed bc_out(s)%fabd_parb(ifp,:) = 0.0_r8 bc_out(s)%fabi_parb(ifp,:) = 0.0_r8 - do ib = 1,hlm_numSWb + do ib = 1,num_swb bc_out(s)%albd_parb(ifp,ib) = currentPatch%gnd_alb_dir(ib) bc_out(s)%albi_parb(ifp,ib) = currentPatch%gnd_alb_dif(ib) @@ -3713,15 +3817,51 @@ subroutine update_3dpatch_radiation(this, nsites, sites, bc_out) enddo else - call PatchNormanRadiation (currentPatch, & - bc_out(s)%albd_parb(ifp,:), & - bc_out(s)%albi_parb(ifp,:), & - bc_out(s)%fabd_parb(ifp,:), & - bc_out(s)%fabi_parb(ifp,:), & - bc_out(s)%ftdd_parb(ifp,:), & - bc_out(s)%ftid_parb(ifp,:), & - bc_out(s)%ftii_parb(ifp,:)) - + select case(radiation_model) + case(norman_solver) + + call PatchNormanRadiation (currentPatch, & + bc_out(s)%albd_parb(ifp,:), & + bc_out(s)%albi_parb(ifp,:), & + bc_out(s)%fabd_parb(ifp,:), & + bc_out(s)%fabi_parb(ifp,:), & + bc_out(s)%ftdd_parb(ifp,:), & + bc_out(s)%ftid_parb(ifp,:), & + bc_out(s)%ftii_parb(ifp,:)) + + + case(twostr_solver) + associate( twostr => currentPatch%twostr) + + call twostr%CanopyPrep(currentPatch%fcansno) + call twostr%ZenithPrep(currentPatch%solar_zenith_angle) + + do ib = 1,num_swb + + twostr%band(ib)%albedo_grnd_diff = currentPatch%gnd_alb_dif(ib) + twostr%band(ib)%albedo_grnd_beam = currentPatch%gnd_alb_dir(ib) + + call twostr%Solve(ib, & ! in + normalized_upper_boundary, & ! in + 1.0_r8,1.0_r8, & ! in + sites(s)%taulambda_2str, & ! inout (scratch) + sites(s)%omega_2str, & ! inout (scratch) + sites(s)%ipiv_2str, & ! inout (scratch) + bc_out(s)%albd_parb(ifp,ib), & ! out + bc_out(s)%albi_parb(ifp,ib), & ! out + currentPatch%rad_error(ib), & ! out + bc_out(s)%fabd_parb(ifp,ib), & ! out + bc_out(s)%fabi_parb(ifp,ib), & ! out + bc_out(s)%ftdd_parb(ifp,ib), & ! out + bc_out(s)%ftid_parb(ifp,ib), & ! out + bc_out(s)%ftii_parb(ifp,ib)) + + end do + + end associate + + end select + endif ! is there vegetation? end if ! if the vegetation and zenith filter is active diff --git a/main/FatesRunningMeanMod.F90 b/main/FatesRunningMeanMod.F90 index 7ef7866d62..721030b974 100644 --- a/main/FatesRunningMeanMod.F90 +++ b/main/FatesRunningMeanMod.F90 @@ -328,6 +328,9 @@ subroutine FuseRMean(this,donor,recip_wgt) if (this%c_index .ne. donor%c_index) then write(fates_log(), *) 'trying to fuse two fixed-window averages' write(fates_log(), *) 'that are at different points in the window?' + write(fates_log(), *) 'c_mean', this%c_mean, donor%c_mean + write(fates_log(), *) 'l_mean', this%l_mean, donor%l_mean + write(fates_log(), *) 'c_index', this%c_index, donor%c_index call endrun(msg=errMsg(sourcefile, __LINE__)) end if end if diff --git a/main/FatesUtilsMod.F90 b/main/FatesUtilsMod.F90 index 4699a6aa60..be955d5da0 100644 --- a/main/FatesUtilsMod.F90 +++ b/main/FatesUtilsMod.F90 @@ -5,7 +5,11 @@ module FatesUtilsMod use FatesConstantsMod, only : r8 => fates_r8 use FatesGlobals, only : fates_log - + use FatesConstantsMod, only : nearzero + use FatesGlobals, only : endrun => fates_endrun + + use shr_log_mod , only : errMsg => shr_log_errMsg + implicit none private ! Modules are private by default @@ -14,7 +18,12 @@ module FatesUtilsMod public :: check_var_real public :: GetNeighborDistance public :: FindIndex - + public :: QuadraticRootsNSWC + public :: QuadraticRootsSridharachary + + character(len=*), parameter, private :: sourcefile = & + __FILE__ + contains @@ -176,6 +185,97 @@ function FindIndex(input_string_array,string_to_match) result(array_index) end do end function FindIndex - + + subroutine QuadraticRootsNSWC(a,b,c,root1,root2) + + ! This code is based off of routines from the NSWC Mathematics Subroutine Library + ! From the NSWC README (https://github.com/jacobwilliams/nswc) + ! "The NSWC Mathematics Subroutine Library is a collection of Fortran 77 routines + ! specializing in numerical mathematics collected and developed by the U.S. + ! Naval Surface Warfare Center. This software is made available, without cost, + ! to the general scientific community." + ! The F77 code was updated to modern fortran by Jacob Williams: + ! https://jacobwilliams.github.io/polyroots-fortran + ! The FATES adaptation of this aborts if only imaginary roots are generated + + + real(r8),intent(in) :: a , b , c !! coefficients + real(r8),intent(out) :: root1 ! sr !! real part of first root + real(r8),intent(out) :: root2 ! lr !! real part of second root + + real(r8) :: b1, d, e + + if ( abs(a)nearzero ) then + ! compute discriminant avoiding overflow + b1 = b/2.0_r8 + if ( abs(b1)=0.0_r8 ) d = -d + root1 = (-b1+d)/a + root2 = 0.0_r8 + if ( root1/=0.0_r8 ) root2 = (c/root1)/a + endif + else + root2 = 0.0_r8 + root1 = -b/a + endif + + end subroutine QuadraticRootsNSWC + + subroutine QuadraticRootsSridharachary(a,b,c,root1,root2) + + + real(r8),intent(in) :: a , b , c !! coefficients + real(r8),intent(out) :: root1 ! sr !! real part of first root + real(r8),intent(out) :: root2 ! lr !! real part of second root + real(r8) :: d ! discriminant + real(r8) :: das ! sqrt(abs(d)) + + ! If a is 0, then equation is not quadratic, but linear + if (abs(a) < nearzero ) then + root2 = 0.0_r8 + if ( abs(b)>nearzero ) root2 = -c/b + root1 = 0.0_r8 + return + end if + + d = b * b - 4._r8 * a * c + das = sqrt(abs(d)) + + if (d > nearzero) then + + root1 = (-b + das) / (2._r8 * a) + root2 = (-b - das) / (2._r8 * a) + + elseif (abs(d) <= nearzero) then + + root1 = -b / (2._r8 * a) + root2 = root1 + else + + write (fates_log(),*)'error, imaginary roots detected in quadratic solve' + call endrun(msg=errMsg(sourcefile, __LINE__)) + + end if + + end subroutine QuadraticRootsSridharachary + ! ====================================================================================== end module FatesUtilsMod diff --git a/parameter_files/archive/api28.0.0_103023_fates_params_default.cdl b/parameter_files/archive/api28.0.0_103023_fates_params_default.cdl new file mode 100644 index 0000000000..72a7e75c8c --- /dev/null +++ b/parameter_files/archive/api28.0.0_103023_fates_params_default.cdl @@ -0,0 +1,1735 @@ +netcdf fates_params_default { +dimensions: + fates_NCWD = 4 ; + fates_history_age_bins = 7 ; + fates_history_coage_bins = 2 ; + fates_history_damage_bins = 2 ; + fates_history_height_bins = 6 ; + fates_history_size_bins = 13 ; + fates_hlm_pftno = 14 ; + fates_hydr_organs = 4 ; + fates_leafage_class = 1 ; + fates_litterclass = 6 ; + fates_pft = 12 ; + fates_plant_organs = 4 ; + fates_string_length = 60 ; +variables: + double fates_history_ageclass_bin_edges(fates_history_age_bins) ; + fates_history_ageclass_bin_edges:units = "yr" ; + fates_history_ageclass_bin_edges:long_name = "Lower edges for age class bins used in age-resolved patch history output" ; + double fates_history_coageclass_bin_edges(fates_history_coage_bins) ; + fates_history_coageclass_bin_edges:units = "years" ; + fates_history_coageclass_bin_edges:long_name = "Lower edges for cohort age class bins used in cohort age resolved history output" ; + double fates_history_height_bin_edges(fates_history_height_bins) ; + fates_history_height_bin_edges:units = "m" ; + fates_history_height_bin_edges:long_name = "Lower edges for height bins used in height-resolved history output" ; + double fates_history_damage_bin_edges(fates_history_damage_bins) ; + fates_history_damage_bin_edges:units = "% crown loss" ; + fates_history_damage_bin_edges:long_name = "Lower edges for damage class bins used in cohort history output" ; + double fates_history_sizeclass_bin_edges(fates_history_size_bins) ; + fates_history_sizeclass_bin_edges:units = "cm" ; + fates_history_sizeclass_bin_edges:long_name = "Lower edges for DBH size class bins used in size-resolved cohort history output" ; + double fates_alloc_organ_id(fates_plant_organs) ; + fates_alloc_organ_id:units = "unitless" ; + fates_alloc_organ_id:long_name = "This is the global index that the organ in this file is associated with, values match those in parteh/PRTGenericMod.F90" ; + double fates_hydro_htftype_node(fates_hydr_organs) ; + fates_hydro_htftype_node:units = "unitless" ; + fates_hydro_htftype_node:long_name = "Switch that defines the hydraulic transfer functions for each organ." ; + char fates_pftname(fates_pft, fates_string_length) ; + fates_pftname:units = "unitless - string" ; + fates_pftname:long_name = "Description of plant type" ; + char fates_hydro_organ_name(fates_hydr_organs, fates_string_length) ; + fates_hydro_organ_name:units = "unitless - string" ; + fates_hydro_organ_name:long_name = "Name of plant hydraulics organs (DONT CHANGE, order matches media list in FatesHydraulicsMemMod.F90)" ; + char fates_alloc_organ_name(fates_plant_organs, fates_string_length) ; + fates_alloc_organ_name:units = "unitless - string" ; + fates_alloc_organ_name:long_name = "Name of plant organs (with alloc_organ_id, must match PRTGenericMod.F90)" ; + char fates_litterclass_name(fates_litterclass, fates_string_length) ; + fates_litterclass_name:units = "unitless - string" ; + fates_litterclass_name:long_name = "Name of the litter classes, for variables associated with dimension fates_litterclass" ; + double fates_alloc_organ_priority(fates_plant_organs, fates_pft) ; + fates_alloc_organ_priority:units = "index" ; + fates_alloc_organ_priority:long_name = "Priority level for allocation, 1: replaces turnover from storage, 2: same priority as storage use/replacement, 3: ascending in order of least importance" ; + double fates_alloc_storage_cushion(fates_pft) ; + fates_alloc_storage_cushion:units = "fraction" ; + fates_alloc_storage_cushion:long_name = "maximum size of storage C pool, relative to maximum size of leaf C pool" ; + double fates_alloc_store_priority_frac(fates_pft) ; + fates_alloc_store_priority_frac:units = "unitless" ; + fates_alloc_store_priority_frac:long_name = "for high-priority organs, the fraction of their turnover demand that is gauranteed to be replaced, and if need-be by storage" ; + double fates_allom_agb1(fates_pft) ; + fates_allom_agb1:units = "variable" ; + fates_allom_agb1:long_name = "Parameter 1 for agb allometry" ; + double fates_allom_agb2(fates_pft) ; + fates_allom_agb2:units = "variable" ; + fates_allom_agb2:long_name = "Parameter 2 for agb allometry" ; + double fates_allom_agb3(fates_pft) ; + fates_allom_agb3:units = "variable" ; + fates_allom_agb3:long_name = "Parameter 3 for agb allometry" ; + double fates_allom_agb4(fates_pft) ; + fates_allom_agb4:units = "variable" ; + fates_allom_agb4:long_name = "Parameter 4 for agb allometry" ; + double fates_allom_agb_frac(fates_pft) ; + fates_allom_agb_frac:units = "fraction" ; + fates_allom_agb_frac:long_name = "Fraction of woody biomass that is above ground" ; + double fates_allom_amode(fates_pft) ; + fates_allom_amode:units = "index" ; + fates_allom_amode:long_name = "AGB allometry function index." ; + double fates_allom_blca_expnt_diff(fates_pft) ; + fates_allom_blca_expnt_diff:units = "unitless" ; + fates_allom_blca_expnt_diff:long_name = "difference between allometric DBH:bleaf and DBH:crown area exponents" ; + double fates_allom_cmode(fates_pft) ; + fates_allom_cmode:units = "index" ; + fates_allom_cmode:long_name = "coarse root biomass allometry function index." ; + double fates_allom_crown_depth_frac(fates_pft) ; + fates_allom_crown_depth_frac:units = "fraction" ; + fates_allom_crown_depth_frac:long_name = "the depth of a cohort crown as a fraction of its height" ; + double fates_allom_d2bl1(fates_pft) ; + fates_allom_d2bl1:units = "variable" ; + fates_allom_d2bl1:long_name = "Parameter 1 for d2bl allometry" ; + double fates_allom_d2bl2(fates_pft) ; + fates_allom_d2bl2:units = "variable" ; + fates_allom_d2bl2:long_name = "Parameter 2 for d2bl allometry" ; + double fates_allom_d2bl3(fates_pft) ; + fates_allom_d2bl3:units = "unitless" ; + fates_allom_d2bl3:long_name = "Parameter 3 for d2bl allometry" ; + double fates_allom_d2ca_coefficient_max(fates_pft) ; + fates_allom_d2ca_coefficient_max:units = "m2 cm^(-1/beta)" ; + fates_allom_d2ca_coefficient_max:long_name = "max (savanna) dbh to area multiplier factor where: area = n*d2ca_coeff*dbh^beta" ; + double fates_allom_d2ca_coefficient_min(fates_pft) ; + fates_allom_d2ca_coefficient_min:units = "m2 cm^(-1/beta)" ; + fates_allom_d2ca_coefficient_min:long_name = "min (forest) dbh to area multiplier factor where: area = n*d2ca_coeff*dbh^beta" ; + double fates_allom_d2h1(fates_pft) ; + fates_allom_d2h1:units = "variable" ; + fates_allom_d2h1:long_name = "Parameter 1 for d2h allometry (intercept, or c)" ; + double fates_allom_d2h2(fates_pft) ; + fates_allom_d2h2:units = "variable" ; + fates_allom_d2h2:long_name = "Parameter 2 for d2h allometry (slope, or m)" ; + double fates_allom_d2h3(fates_pft) ; + fates_allom_d2h3:units = "variable" ; + fates_allom_d2h3:long_name = "Parameter 3 for d2h allometry (optional)" ; + double fates_allom_dbh_maxheight(fates_pft) ; + fates_allom_dbh_maxheight:units = "cm" ; + fates_allom_dbh_maxheight:long_name = "the diameter (if any) corresponding to maximum height, diameters may increase beyond this" ; + double fates_allom_fmode(fates_pft) ; + fates_allom_fmode:units = "index" ; + fates_allom_fmode:long_name = "fine root biomass allometry function index." ; + double fates_allom_fnrt_prof_a(fates_pft) ; + fates_allom_fnrt_prof_a:units = "unitless" ; + fates_allom_fnrt_prof_a:long_name = "Fine root profile function, parameter a" ; + double fates_allom_fnrt_prof_b(fates_pft) ; + fates_allom_fnrt_prof_b:units = "unitless" ; + fates_allom_fnrt_prof_b:long_name = "Fine root profile function, parameter b" ; + double fates_allom_fnrt_prof_mode(fates_pft) ; + fates_allom_fnrt_prof_mode:units = "index" ; + fates_allom_fnrt_prof_mode:long_name = "Index to select fine root profile function: 1) Jackson Beta, 2) 1-param exponential 3) 2-param exponential" ; + double fates_allom_frbstor_repro(fates_pft) ; + fates_allom_frbstor_repro:units = "fraction" ; + fates_allom_frbstor_repro:long_name = "fraction of bstore goes to reproduction after plant dies" ; + double fates_allom_hmode(fates_pft) ; + fates_allom_hmode:units = "index" ; + fates_allom_hmode:long_name = "height allometry function index." ; + double fates_allom_l2fr(fates_pft) ; + fates_allom_l2fr:units = "gC/gC" ; + fates_allom_l2fr:long_name = "Allocation parameter: fine root C per leaf C" ; + double fates_allom_la_per_sa_int(fates_pft) ; + fates_allom_la_per_sa_int:units = "m2/cm2" ; + fates_allom_la_per_sa_int:long_name = "Leaf area per sapwood area, intercept" ; + double fates_allom_la_per_sa_slp(fates_pft) ; + fates_allom_la_per_sa_slp:units = "m2/cm2/m" ; + fates_allom_la_per_sa_slp:long_name = "Leaf area per sapwood area rate of change with height, slope (optional)" ; + double fates_allom_lmode(fates_pft) ; + fates_allom_lmode:units = "index" ; + fates_allom_lmode:long_name = "leaf biomass allometry function index." ; + double fates_allom_sai_scaler(fates_pft) ; + fates_allom_sai_scaler:units = "m2/m2" ; + fates_allom_sai_scaler:long_name = "allometric ratio of SAI per LAI" ; + double fates_allom_smode(fates_pft) ; + fates_allom_smode:units = "index" ; + fates_allom_smode:long_name = "sapwood allometry function index." ; + double fates_allom_stmode(fates_pft) ; + fates_allom_stmode:units = "index" ; + fates_allom_stmode:long_name = "storage allometry function index: 1) Storage proportional to leaf biomass (with trimming), 2) Storage proportional to maximum leaf biomass (not trimmed)" ; + double fates_allom_zroot_k(fates_pft) ; + fates_allom_zroot_k:units = "unitless" ; + fates_allom_zroot_k:long_name = "scale coefficient of logistic rooting depth model" ; + double fates_allom_zroot_max_dbh(fates_pft) ; + fates_allom_zroot_max_dbh:units = "cm" ; + fates_allom_zroot_max_dbh:long_name = "dbh at which a plant reaches the maximum value for its maximum rooting depth" ; + double fates_allom_zroot_max_z(fates_pft) ; + fates_allom_zroot_max_z:units = "m" ; + fates_allom_zroot_max_z:long_name = "the maximum rooting depth defined at dbh = fates_allom_zroot_max_dbh. note: max_z=min_z=large, sets rooting depth to soil depth" ; + double fates_allom_zroot_min_dbh(fates_pft) ; + fates_allom_zroot_min_dbh:units = "cm" ; + fates_allom_zroot_min_dbh:long_name = "dbh at which the maximum rooting depth for a recruit is defined" ; + double fates_allom_zroot_min_z(fates_pft) ; + fates_allom_zroot_min_z:units = "m" ; + fates_allom_zroot_min_z:long_name = "the maximum rooting depth defined at dbh = fates_allom_zroot_min_dbh. note: max_z=min_z=large, sets rooting depth to soil depth" ; + double fates_c2b(fates_pft) ; + fates_c2b:units = "ratio" ; + fates_c2b:long_name = "Carbon to biomass multiplier of bulk structural tissues" ; + double fates_cnp_eca_alpha_ptase(fates_pft) ; + fates_cnp_eca_alpha_ptase:units = "g/m3" ; + fates_cnp_eca_alpha_ptase:long_name = "fraction of P from ptase activity sent directly to plant (ECA)" ; + double fates_cnp_eca_decompmicc(fates_pft) ; + fates_cnp_eca_decompmicc:units = "gC/m3" ; + fates_cnp_eca_decompmicc:long_name = "maximum soil microbial decomposer biomass found over depth (will be applied at a reference depth w/ exponential attenuation) (ECA)" ; + double fates_cnp_eca_km_nh4(fates_pft) ; + fates_cnp_eca_km_nh4:units = "gN/m3" ; + fates_cnp_eca_km_nh4:long_name = "half-saturation constant for plant nh4 uptake (ECA)" ; + double fates_cnp_eca_km_no3(fates_pft) ; + fates_cnp_eca_km_no3:units = "gN/m3" ; + fates_cnp_eca_km_no3:long_name = "half-saturation constant for plant no3 uptake (ECA)" ; + double fates_cnp_eca_km_p(fates_pft) ; + fates_cnp_eca_km_p:units = "gP/m3" ; + fates_cnp_eca_km_p:long_name = "half-saturation constant for plant p uptake (ECA)" ; + double fates_cnp_eca_km_ptase(fates_pft) ; + fates_cnp_eca_km_ptase:units = "gP/m3" ; + fates_cnp_eca_km_ptase:long_name = "half-saturation constant for biochemical P (ECA)" ; + double fates_cnp_eca_lambda_ptase(fates_pft) ; + fates_cnp_eca_lambda_ptase:units = "g/m3" ; + fates_cnp_eca_lambda_ptase:long_name = "critical value for biochemical production (ECA)" ; + double fates_cnp_eca_vmax_ptase(fates_pft) ; + fates_cnp_eca_vmax_ptase:units = "gP/m2/s" ; + fates_cnp_eca_vmax_ptase:long_name = "maximum production rate for biochemical P (per m2) (ECA)" ; + double fates_cnp_nfix1(fates_pft) ; + fates_cnp_nfix1:units = "fraction" ; + fates_cnp_nfix1:long_name = "fractional surcharge added to maintenance respiration that drives symbiotic fixation" ; + double fates_cnp_nitr_store_ratio(fates_pft) ; + fates_cnp_nitr_store_ratio:units = "(gN/gN)" ; + fates_cnp_nitr_store_ratio:long_name = "storeable (labile) N, as a ratio compared to the N bound in cell structures of other organs (see code)" ; + double fates_cnp_phos_store_ratio(fates_pft) ; + fates_cnp_phos_store_ratio:units = "(gP/gP)" ; + fates_cnp_phos_store_ratio:long_name = "storeable (labile) P, as a ratio compared to the P bound in cell structures of other organs (see code)" ; + double fates_cnp_pid_kd(fates_pft) ; + fates_cnp_pid_kd:units = "unknown" ; + fates_cnp_pid_kd:long_name = "derivative constant of the PID controller on adaptive fine-root biomass" ; + double fates_cnp_pid_ki(fates_pft) ; + fates_cnp_pid_ki:units = "unknown" ; + fates_cnp_pid_ki:long_name = "integral constant of the PID controller on adaptive fine-root biomass" ; + double fates_cnp_pid_kp(fates_pft) ; + fates_cnp_pid_kp:units = "unknown" ; + fates_cnp_pid_kp:long_name = "proportional constant of the PID controller on adaptive fine-root biomass" ; + double fates_cnp_prescribed_nuptake(fates_pft) ; + fates_cnp_prescribed_nuptake:units = "fraction" ; + fates_cnp_prescribed_nuptake:long_name = "Prescribed N uptake flux. 0=fully coupled simulation >0=prescribed (experimental)" ; + double fates_cnp_prescribed_puptake(fates_pft) ; + fates_cnp_prescribed_puptake:units = "fraction" ; + fates_cnp_prescribed_puptake:long_name = "Prescribed P uptake flux. 0=fully coupled simulation, >0=prescribed (experimental)" ; + double fates_cnp_store_ovrflw_frac(fates_pft) ; + fates_cnp_store_ovrflw_frac:units = "fraction" ; + fates_cnp_store_ovrflw_frac:long_name = "size of overflow storage (for excess C,N or P) as a fraction of storage target" ; + double fates_cnp_turnover_nitr_retrans(fates_plant_organs, fates_pft) ; + fates_cnp_turnover_nitr_retrans:units = "fraction" ; + fates_cnp_turnover_nitr_retrans:long_name = "retranslocation (reabsorbtion) fraction of nitrogen in turnover of scenescing tissues" ; + double fates_cnp_turnover_phos_retrans(fates_plant_organs, fates_pft) ; + fates_cnp_turnover_phos_retrans:units = "fraction" ; + fates_cnp_turnover_phos_retrans:long_name = "retranslocation (reabsorbtion) fraction of phosphorus in turnover of scenescing tissues" ; + double fates_cnp_vmax_nh4(fates_pft) ; + fates_cnp_vmax_nh4:units = "gN/gC/s" ; + fates_cnp_vmax_nh4:long_name = "maximum (potential) uptake rate of NH4 per gC of fineroot biomass (see main/EDPftvarcon.F90 vmax_nh4 for usage)" ; + double fates_cnp_vmax_no3(fates_pft) ; + fates_cnp_vmax_no3:units = "gN/gC/s" ; + fates_cnp_vmax_no3:long_name = "maximum (potential) uptake rate of NO3 per gC of fineroot biomass (see main/EDPftvarcon.F90 vmax_no3 for usage)" ; + double fates_cnp_vmax_p(fates_pft) ; + fates_cnp_vmax_p:units = "gP/gC/s" ; + fates_cnp_vmax_p:long_name = "maximum production rate for phosphorus (ECA and RD)" ; + double fates_damage_frac(fates_pft) ; + fates_damage_frac:units = "fraction" ; + fates_damage_frac:long_name = "fraction of cohort damaged in each damage event (event frequency specified in the is_it_damage_time subroutine)" ; + double fates_damage_mort_p1(fates_pft) ; + fates_damage_mort_p1:units = "fraction" ; + fates_damage_mort_p1:long_name = "inflection point of damage mortality function, a value of 0.8 means 50% mortality with 80% loss of crown, turn off with a large number" ; + double fates_damage_mort_p2(fates_pft) ; + fates_damage_mort_p2:units = "unitless" ; + fates_damage_mort_p2:long_name = "rate of mortality increase with damage" ; + double fates_damage_recovery_scalar(fates_pft) ; + fates_damage_recovery_scalar:units = "unitless" ; + fates_damage_recovery_scalar:long_name = "fraction of the cohort that recovers from damage" ; + double fates_dev_arbitrary_pft(fates_pft) ; + fates_dev_arbitrary_pft:units = "unknown" ; + fates_dev_arbitrary_pft:long_name = "Unassociated pft dimensioned free parameter that developers can use for testing arbitrary new hypotheses" ; + double fates_fire_alpha_SH(fates_pft) ; + fates_fire_alpha_SH:units = "m / (kw/m)**(2/3)" ; + fates_fire_alpha_SH:long_name = "spitfire parameter, alpha scorch height, Equation 16 Thonicke et al 2010" ; + double fates_fire_bark_scaler(fates_pft) ; + fates_fire_bark_scaler:units = "fraction" ; + fates_fire_bark_scaler:long_name = "the thickness of a cohorts bark as a fraction of its dbh" ; + double fates_fire_crown_kill(fates_pft) ; + fates_fire_crown_kill:units = "NA" ; + fates_fire_crown_kill:long_name = "fire parameter, see equation 22 in Thonicke et al 2010" ; + double fates_frag_fnrt_fcel(fates_pft) ; + fates_frag_fnrt_fcel:units = "fraction" ; + fates_frag_fnrt_fcel:long_name = "Fine root litter cellulose fraction" ; + double fates_frag_fnrt_flab(fates_pft) ; + fates_frag_fnrt_flab:units = "fraction" ; + fates_frag_fnrt_flab:long_name = "Fine root litter labile fraction" ; + double fates_frag_fnrt_flig(fates_pft) ; + fates_frag_fnrt_flig:units = "fraction" ; + fates_frag_fnrt_flig:long_name = "Fine root litter lignin fraction" ; + double fates_frag_leaf_fcel(fates_pft) ; + fates_frag_leaf_fcel:units = "fraction" ; + fates_frag_leaf_fcel:long_name = "Leaf litter cellulose fraction" ; + double fates_frag_leaf_flab(fates_pft) ; + fates_frag_leaf_flab:units = "fraction" ; + fates_frag_leaf_flab:long_name = "Leaf litter labile fraction" ; + double fates_frag_leaf_flig(fates_pft) ; + fates_frag_leaf_flig:units = "fraction" ; + fates_frag_leaf_flig:long_name = "Leaf litter lignin fraction" ; + double fates_frag_seed_decay_rate(fates_pft) ; + fates_frag_seed_decay_rate:units = "yr-1" ; + fates_frag_seed_decay_rate:long_name = "fraction of seeds that decay per year" ; + double fates_grperc(fates_pft) ; + fates_grperc:units = "unitless" ; + fates_grperc:long_name = "Growth respiration factor" ; + double fates_hydro_avuln_gs(fates_pft) ; + fates_hydro_avuln_gs:units = "unitless" ; + fates_hydro_avuln_gs:long_name = "shape parameter for stomatal control of water vapor exiting leaf" ; + double fates_hydro_avuln_node(fates_hydr_organs, fates_pft) ; + fates_hydro_avuln_node:units = "unitless" ; + fates_hydro_avuln_node:long_name = "xylem vulnerability curve shape parameter" ; + double fates_hydro_epsil_node(fates_hydr_organs, fates_pft) ; + fates_hydro_epsil_node:units = "MPa" ; + fates_hydro_epsil_node:long_name = "bulk elastic modulus" ; + double fates_hydro_fcap_node(fates_hydr_organs, fates_pft) ; + fates_hydro_fcap_node:units = "unitless" ; + fates_hydro_fcap_node:long_name = "fraction of non-residual water that is capillary in source" ; + double fates_hydro_k_lwp(fates_pft) ; + fates_hydro_k_lwp:units = "unitless" ; + fates_hydro_k_lwp:long_name = "inner leaf humidity scaling coefficient" ; + double fates_hydro_kmax_node(fates_hydr_organs, fates_pft) ; + fates_hydro_kmax_node:units = "kg/MPa/m/s" ; + fates_hydro_kmax_node:long_name = "maximum xylem conductivity per unit conducting xylem area" ; + double fates_hydro_p50_gs(fates_pft) ; + fates_hydro_p50_gs:units = "MPa" ; + fates_hydro_p50_gs:long_name = "water potential at 50% loss of stomatal conductance" ; + double fates_hydro_p50_node(fates_hydr_organs, fates_pft) ; + fates_hydro_p50_node:units = "MPa" ; + fates_hydro_p50_node:long_name = "xylem water potential at 50% loss of conductivity" ; + double fates_hydro_p_taper(fates_pft) ; + fates_hydro_p_taper:units = "unitless" ; + fates_hydro_p_taper:long_name = "xylem taper exponent" ; + double fates_hydro_pinot_node(fates_hydr_organs, fates_pft) ; + fates_hydro_pinot_node:units = "MPa" ; + fates_hydro_pinot_node:long_name = "osmotic potential at full turgor" ; + double fates_hydro_pitlp_node(fates_hydr_organs, fates_pft) ; + fates_hydro_pitlp_node:units = "MPa" ; + fates_hydro_pitlp_node:long_name = "turgor loss point" ; + double fates_hydro_resid_node(fates_hydr_organs, fates_pft) ; + fates_hydro_resid_node:units = "cm3/cm3" ; + fates_hydro_resid_node:long_name = "residual water conent" ; + double fates_hydro_rfrac_stem(fates_pft) ; + fates_hydro_rfrac_stem:units = "fraction" ; + fates_hydro_rfrac_stem:long_name = "fraction of total tree resistance from troot to canopy" ; + double fates_hydro_rs2(fates_pft) ; + fates_hydro_rs2:units = "m" ; + fates_hydro_rs2:long_name = "absorbing root radius" ; + double fates_hydro_srl(fates_pft) ; + fates_hydro_srl:units = "m g-1" ; + fates_hydro_srl:long_name = "specific root length" ; + double fates_hydro_thetas_node(fates_hydr_organs, fates_pft) ; + fates_hydro_thetas_node:units = "cm3/cm3" ; + fates_hydro_thetas_node:long_name = "saturated water content" ; + double fates_hydro_vg_alpha_node(fates_hydr_organs, fates_pft) ; + fates_hydro_vg_alpha_node:units = "MPa-1" ; + fates_hydro_vg_alpha_node:long_name = "(used if hydr_htftype_node = 2), capillary length parameter in van Genuchten model" ; + double fates_hydro_vg_m_node(fates_hydr_organs, fates_pft) ; + fates_hydro_vg_m_node:units = "unitless" ; + fates_hydro_vg_m_node:long_name = "(used if hydr_htftype_node = 2),m in van Genuchten 1980 model, 2nd pore size distribution parameter" ; + double fates_hydro_vg_n_node(fates_hydr_organs, fates_pft) ; + fates_hydro_vg_n_node:units = "unitless" ; + fates_hydro_vg_n_node:long_name = "(used if hydr_htftype_node = 2),n in van Genuchten 1980 model, pore size distribution parameter" ; + double fates_leaf_c3psn(fates_pft) ; + fates_leaf_c3psn:units = "flag" ; + fates_leaf_c3psn:long_name = "Photosynthetic pathway (1=c3, 0=c4)" ; + double fates_leaf_jmaxha(fates_pft) ; + fates_leaf_jmaxha:units = "J/mol" ; + fates_leaf_jmaxha:long_name = "activation energy for jmax. NOTE: if fates_leaf_photo_tempsens_model=2 then these values are NOT USED" ; + double fates_leaf_jmaxhd(fates_pft) ; + fates_leaf_jmaxhd:units = "J/mol" ; + fates_leaf_jmaxhd:long_name = "deactivation energy for jmax. NOTE: if fates_leaf_photo_tempsens_model=2 then these values are NOT USED" ; + double fates_leaf_jmaxse(fates_pft) ; + fates_leaf_jmaxse:units = "J/mol/K" ; + fates_leaf_jmaxse:long_name = "entropy term for jmax. NOTE: if fates_leaf_photo_tempsens_model=2 then these values are NOT USED" ; + double fates_leaf_slamax(fates_pft) ; + fates_leaf_slamax:units = "m^2/gC" ; + fates_leaf_slamax:long_name = "Maximum Specific Leaf Area (SLA), even if under a dense canopy" ; + double fates_leaf_slatop(fates_pft) ; + fates_leaf_slatop:units = "m^2/gC" ; + fates_leaf_slatop:long_name = "Specific Leaf Area (SLA) at top of canopy, projected area basis" ; + double fates_leaf_stomatal_intercept(fates_pft) ; + fates_leaf_stomatal_intercept:units = "umol H2O/m**2/s" ; + fates_leaf_stomatal_intercept:long_name = "Minimum unstressed stomatal conductance for Ball-Berry model and Medlyn model" ; + double fates_leaf_stomatal_slope_ballberry(fates_pft) ; + fates_leaf_stomatal_slope_ballberry:units = "unitless" ; + fates_leaf_stomatal_slope_ballberry:long_name = "stomatal slope parameter, as per Ball-Berry" ; + double fates_leaf_stomatal_slope_medlyn(fates_pft) ; + fates_leaf_stomatal_slope_medlyn:units = "KPa**0.5" ; + fates_leaf_stomatal_slope_medlyn:long_name = "stomatal slope parameter, as per Medlyn" ; + double fates_leaf_vcmax25top(fates_leafage_class, fates_pft) ; + fates_leaf_vcmax25top:units = "umol CO2/m^2/s" ; + fates_leaf_vcmax25top:long_name = "maximum carboxylation rate of Rub. at 25C, canopy top" ; + double fates_leaf_vcmaxha(fates_pft) ; + fates_leaf_vcmaxha:units = "J/mol" ; + fates_leaf_vcmaxha:long_name = "activation energy for vcmax. NOTE: if fates_leaf_photo_tempsens_model=2 then these values are NOT USED" ; + double fates_leaf_vcmaxhd(fates_pft) ; + fates_leaf_vcmaxhd:units = "J/mol" ; + fates_leaf_vcmaxhd:long_name = "deactivation energy for vcmax. NOTE: if fates_leaf_photo_tempsens_model=2 then these values are NOT USED" ; + double fates_leaf_vcmaxse(fates_pft) ; + fates_leaf_vcmaxse:units = "J/mol/K" ; + fates_leaf_vcmaxse:long_name = "entropy term for vcmax. NOTE: if fates_leaf_photo_tempsens_model=2 then these values are NOT USED" ; + double fates_maintresp_leaf_atkin2017_baserate(fates_pft) ; + fates_maintresp_leaf_atkin2017_baserate:units = "umol CO2/m^2/s" ; + fates_maintresp_leaf_atkin2017_baserate:long_name = "Leaf maintenance respiration base rate parameter (r0) per Atkin et al 2017" ; + double fates_maintresp_leaf_ryan1991_baserate(fates_pft) ; + fates_maintresp_leaf_ryan1991_baserate:units = "gC/gN/s" ; + fates_maintresp_leaf_ryan1991_baserate:long_name = "Leaf maintenance respiration base rate per Ryan et al 1991" ; + double fates_maintresp_reduction_curvature(fates_pft) ; + fates_maintresp_reduction_curvature:units = "unitless (0-1)" ; + fates_maintresp_reduction_curvature:long_name = "curvature of MR reduction as f(carbon storage), 1=linear, 0=very curved" ; + double fates_maintresp_reduction_intercept(fates_pft) ; + fates_maintresp_reduction_intercept:units = "unitless (0-1)" ; + fates_maintresp_reduction_intercept:long_name = "intercept of MR reduction as f(carbon storage), 0=no throttling, 1=max throttling" ; + double fates_maintresp_reduction_upthresh(fates_pft) ; + fates_maintresp_reduction_upthresh:units = "unitless (0-1)" ; + fates_maintresp_reduction_upthresh:long_name = "upper threshold for storage biomass (relative to leaf biomass) above which MR is not reduced" ; + double fates_mort_bmort(fates_pft) ; + fates_mort_bmort:units = "1/yr" ; + fates_mort_bmort:long_name = "background mortality rate" ; + double fates_mort_freezetol(fates_pft) ; + fates_mort_freezetol:units = "degrees C" ; + fates_mort_freezetol:long_name = "minimum temperature tolerance" ; + double fates_mort_hf_flc_threshold(fates_pft) ; + fates_mort_hf_flc_threshold:units = "fraction" ; + fates_mort_hf_flc_threshold:long_name = "plant fractional loss of conductivity at which drought mortality begins for hydraulic model" ; + double fates_mort_hf_sm_threshold(fates_pft) ; + fates_mort_hf_sm_threshold:units = "unitless" ; + fates_mort_hf_sm_threshold:long_name = "soil moisture (btran units) at which drought mortality begins for non-hydraulic model" ; + double fates_mort_ip_age_senescence(fates_pft) ; + fates_mort_ip_age_senescence:units = "years" ; + fates_mort_ip_age_senescence:long_name = "Mortality cohort age senescence inflection point. If _ this mortality term is off. Setting this value turns on age dependent mortality. " ; + double fates_mort_ip_size_senescence(fates_pft) ; + fates_mort_ip_size_senescence:units = "dbh cm" ; + fates_mort_ip_size_senescence:long_name = "Mortality dbh senescence inflection point. If _ this mortality term is off. Setting this value turns on size dependent mortality" ; + double fates_mort_prescribed_canopy(fates_pft) ; + fates_mort_prescribed_canopy:units = "1/yr" ; + fates_mort_prescribed_canopy:long_name = "mortality rate of canopy trees for prescribed physiology mode" ; + double fates_mort_prescribed_understory(fates_pft) ; + fates_mort_prescribed_understory:units = "1/yr" ; + fates_mort_prescribed_understory:long_name = "mortality rate of understory trees for prescribed physiology mode" ; + double fates_mort_r_age_senescence(fates_pft) ; + fates_mort_r_age_senescence:units = "mortality rate year^-1" ; + fates_mort_r_age_senescence:long_name = "Mortality age senescence rate of change. Sensible range is around 0.03-0.06. Larger values givesteeper mortality curves." ; + double fates_mort_r_size_senescence(fates_pft) ; + fates_mort_r_size_senescence:units = "mortality rate dbh^-1" ; + fates_mort_r_size_senescence:long_name = "Mortality dbh senescence rate of change. Sensible range is around 0.03-0.06. Larger values give steeper mortality curves." ; + double fates_mort_scalar_coldstress(fates_pft) ; + fates_mort_scalar_coldstress:units = "1/yr" ; + fates_mort_scalar_coldstress:long_name = "maximum mortality rate from cold stress" ; + double fates_mort_scalar_cstarvation(fates_pft) ; + fates_mort_scalar_cstarvation:units = "1/yr" ; + fates_mort_scalar_cstarvation:long_name = "maximum mortality rate from carbon starvation" ; + double fates_mort_scalar_hydrfailure(fates_pft) ; + fates_mort_scalar_hydrfailure:units = "1/yr" ; + fates_mort_scalar_hydrfailure:long_name = "maximum mortality rate from hydraulic failure" ; + double fates_mort_upthresh_cstarvation(fates_pft) ; + fates_mort_upthresh_cstarvation:units = "unitless" ; + fates_mort_upthresh_cstarvation:long_name = "threshold for storage biomass (relative to target leaf biomass) above which carbon starvation is zero" ; + double fates_nonhydro_smpsc(fates_pft) ; + fates_nonhydro_smpsc:units = "mm" ; + fates_nonhydro_smpsc:long_name = "Soil water potential at full stomatal closure" ; + double fates_nonhydro_smpso(fates_pft) ; + fates_nonhydro_smpso:units = "mm" ; + fates_nonhydro_smpso:long_name = "Soil water potential at full stomatal opening" ; + double fates_phen_cold_size_threshold(fates_pft) ; + fates_phen_cold_size_threshold:units = "cm" ; + fates_phen_cold_size_threshold:long_name = "the dbh size above which will lead to phenology-related stem and leaf drop" ; + double fates_phen_drought_threshold(fates_pft) ; + fates_phen_drought_threshold:units = "m3/m3 or mm" ; + fates_phen_drought_threshold:long_name = "threshold for drought phenology (or lower threshold for semi-deciduous PFTs); the quantity depends on the sign: if positive, the threshold is volumetric soil moisture (m3/m3). If negative, the threshold is soil matric potentical (mm)" ; + double fates_phen_evergreen(fates_pft) ; + fates_phen_evergreen:units = "logical flag" ; + fates_phen_evergreen:long_name = "Binary flag for evergreen leaf habit" ; + double fates_phen_flush_fraction(fates_pft) ; + fates_phen_flush_fraction:units = "fraction" ; + fates_phen_flush_fraction:long_name = "Upon bud-burst, the maximum fraction of storage carbon used for flushing leaves" ; + double fates_phen_fnrt_drop_fraction(fates_pft) ; + fates_phen_fnrt_drop_fraction:units = "fraction" ; + fates_phen_fnrt_drop_fraction:long_name = "fraction of fine roots to drop during drought/cold" ; + double fates_phen_mindaysoff(fates_pft) ; + fates_phen_mindaysoff:units = "days" ; + fates_phen_mindaysoff:long_name = "day threshold compared against days since leaves abscised (shed)" ; + double fates_phen_moist_threshold(fates_pft) ; + fates_phen_moist_threshold:units = "m3/m3 or mm" ; + fates_phen_moist_threshold:long_name = "upper threshold for drought phenology (only for drought semi-deciduous PFTs); the quantity depends on the sign: if positive, the threshold is volumetric soil moisture (m3/m3). If negative, the threshold is soil matric potentical (mm)" ; + double fates_phen_season_decid(fates_pft) ; + fates_phen_season_decid:units = "logical flag" ; + fates_phen_season_decid:long_name = "Binary flag for seasonal-deciduous leaf habit" ; + double fates_phen_stem_drop_fraction(fates_pft) ; + fates_phen_stem_drop_fraction:units = "fraction" ; + fates_phen_stem_drop_fraction:long_name = "fraction of stems to drop for non-woody species during drought/cold" ; + double fates_phen_stress_decid(fates_pft) ; + fates_phen_stress_decid:units = "logical flag" ; + fates_phen_stress_decid:long_name = "Binary flag for stress-deciduous leaf habit" ; + double fates_prescribed_npp_canopy(fates_pft) ; + fates_prescribed_npp_canopy:units = "kgC / m^2 / yr" ; + fates_prescribed_npp_canopy:long_name = "NPP per unit crown area of canopy trees for prescribed physiology mode" ; + double fates_prescribed_npp_understory(fates_pft) ; + fates_prescribed_npp_understory:units = "kgC / m^2 / yr" ; + fates_prescribed_npp_understory:long_name = "NPP per unit crown area of understory trees for prescribed physiology mode" ; + double fates_rad_leaf_clumping_index(fates_pft) ; + fates_rad_leaf_clumping_index:units = "fraction (0-1)" ; + fates_rad_leaf_clumping_index:long_name = "factor describing how much self-occlusion of leaf scattering elements decreases light interception" ; + double fates_rad_leaf_rhonir(fates_pft) ; + fates_rad_leaf_rhonir:units = "fraction" ; + fates_rad_leaf_rhonir:long_name = "Leaf reflectance: near-IR" ; + double fates_rad_leaf_rhovis(fates_pft) ; + fates_rad_leaf_rhovis:units = "fraction" ; + fates_rad_leaf_rhovis:long_name = "Leaf reflectance: visible" ; + double fates_rad_leaf_taunir(fates_pft) ; + fates_rad_leaf_taunir:units = "fraction" ; + fates_rad_leaf_taunir:long_name = "Leaf transmittance: near-IR" ; + double fates_rad_leaf_tauvis(fates_pft) ; + fates_rad_leaf_tauvis:units = "fraction" ; + fates_rad_leaf_tauvis:long_name = "Leaf transmittance: visible" ; + double fates_rad_leaf_xl(fates_pft) ; + fates_rad_leaf_xl:units = "unitless" ; + fates_rad_leaf_xl:long_name = "Leaf/stem orientation index" ; + double fates_rad_stem_rhonir(fates_pft) ; + fates_rad_stem_rhonir:units = "fraction" ; + fates_rad_stem_rhonir:long_name = "Stem reflectance: near-IR" ; + double fates_rad_stem_rhovis(fates_pft) ; + fates_rad_stem_rhovis:units = "fraction" ; + fates_rad_stem_rhovis:long_name = "Stem reflectance: visible" ; + double fates_rad_stem_taunir(fates_pft) ; + fates_rad_stem_taunir:units = "fraction" ; + fates_rad_stem_taunir:long_name = "Stem transmittance: near-IR" ; + double fates_rad_stem_tauvis(fates_pft) ; + fates_rad_stem_tauvis:units = "fraction" ; + fates_rad_stem_tauvis:long_name = "Stem transmittance: visible" ; + double fates_recruit_height_min(fates_pft) ; + fates_recruit_height_min:units = "m" ; + fates_recruit_height_min:long_name = "the minimum height (ie starting height) of a newly recruited plant" ; + double fates_recruit_init_density(fates_pft) ; + fates_recruit_init_density:units = "stems/m2" ; + fates_recruit_init_density:long_name = "initial seedling density for a cold-start near-bare-ground simulation. If negative sets initial tree dbh - only to be used in nocomp mode" ; + double fates_recruit_prescribed_rate(fates_pft) ; + fates_recruit_prescribed_rate:units = "n/yr" ; + fates_recruit_prescribed_rate:long_name = "recruitment rate for prescribed physiology mode" ; + double fates_recruit_seed_alloc(fates_pft) ; + fates_recruit_seed_alloc:units = "fraction" ; + fates_recruit_seed_alloc:long_name = "fraction of available carbon balance allocated to seeds" ; + double fates_recruit_seed_alloc_mature(fates_pft) ; + fates_recruit_seed_alloc_mature:units = "fraction" ; + fates_recruit_seed_alloc_mature:long_name = "fraction of available carbon balance allocated to seeds in mature plants (adds to fates_seed_alloc)" ; + double fates_recruit_seed_dbh_repro_threshold(fates_pft) ; + fates_recruit_seed_dbh_repro_threshold:units = "cm" ; + fates_recruit_seed_dbh_repro_threshold:long_name = "the diameter where the plant will increase allocation to the seed pool by fraction: fates_recruit_seed_alloc_mature" ; + double fates_recruit_seed_germination_rate(fates_pft) ; + fates_recruit_seed_germination_rate:units = "yr-1" ; + fates_recruit_seed_germination_rate:long_name = "fraction of seeds that germinate per year" ; + double fates_recruit_seed_supplement(fates_pft) ; + fates_recruit_seed_supplement:units = "KgC/m2/yr" ; + fates_recruit_seed_supplement:long_name = "Supplemental external seed rain source term (non-mass conserving)" ; + double fates_seed_dispersal_fraction(fates_pft) ; + fates_seed_dispersal_fraction:units = "fraction" ; + fates_seed_dispersal_fraction:long_name = "fraction of seed rain to be dispersed to other grid cells" ; + double fates_seed_dispersal_max_dist(fates_pft) ; + fates_seed_dispersal_max_dist:units = "m" ; + fates_seed_dispersal_max_dist:long_name = "maximum seed dispersal distance for a given pft" ; + double fates_seed_dispersal_pdf_scale(fates_pft) ; + fates_seed_dispersal_pdf_scale:units = "unitless" ; + fates_seed_dispersal_pdf_scale:long_name = "seed dispersal probability density function scale parameter, A, Table 1 Bullock et al 2016" ; + double fates_seed_dispersal_pdf_shape(fates_pft) ; + fates_seed_dispersal_pdf_shape:units = "unitless" ; + fates_seed_dispersal_pdf_shape:long_name = "seed dispersal probability density function shape parameter, B, Table 1 Bullock et al 2016" ; + double fates_stoich_nitr(fates_plant_organs, fates_pft) ; + fates_stoich_nitr:units = "gN/gC" ; + fates_stoich_nitr:long_name = "target nitrogen concentration (ratio with carbon) of organs" ; + double fates_stoich_phos(fates_plant_organs, fates_pft) ; + fates_stoich_phos:units = "gP/gC" ; + fates_stoich_phos:long_name = "target phosphorus concentration (ratio with carbon) of organs" ; + double fates_trim_inc(fates_pft) ; + fates_trim_inc:units = "m2/m2" ; + fates_trim_inc:long_name = "Arbitrary incremental change in trimming function." ; + double fates_trim_limit(fates_pft) ; + fates_trim_limit:units = "m2/m2" ; + fates_trim_limit:long_name = "Arbitrary limit to reductions in leaf area with stress" ; + double fates_trs_repro_alloc_a(fates_pft) ; + fates_trs_repro_alloc_a:units = "fraction" ; + fates_trs_repro_alloc_a:long_name = "shape parameter for sigmoidal function relating dbh to reproductive allocation" ; + double fates_trs_repro_alloc_b(fates_pft) ; + fates_trs_repro_alloc_b:units = "fraction" ; + fates_trs_repro_alloc_b:long_name = "intercept parameter for sigmoidal function relating dbh to reproductive allocation" ; + double fates_trs_repro_frac_seed(fates_pft) ; + fates_trs_repro_frac_seed:units = "fraction" ; + fates_trs_repro_frac_seed:long_name = "fraction of reproductive mass that is seed" ; + double fates_trs_seedling_a_emerg(fates_pft) ; + fates_trs_seedling_a_emerg:units = "day -1" ; + fates_trs_seedling_a_emerg:long_name = "mean fraction of seed bank emerging" ; + double fates_trs_seedling_b_emerg(fates_pft) ; + fates_trs_seedling_b_emerg:units = "day -1" ; + fates_trs_seedling_b_emerg:long_name = "seedling emergence sensitivity to soil moisture" ; + double fates_trs_seedling_background_mort(fates_pft) ; + fates_trs_seedling_background_mort:units = "yr-1" ; + fates_trs_seedling_background_mort:long_name = "background seedling mortality rate" ; + double fates_trs_seedling_h2o_mort_a(fates_pft) ; + fates_trs_seedling_h2o_mort_a:units = "-" ; + fates_trs_seedling_h2o_mort_a:long_name = "coefficient in moisture-based seedling mortality" ; + double fates_trs_seedling_h2o_mort_b(fates_pft) ; + fates_trs_seedling_h2o_mort_b:units = "-" ; + fates_trs_seedling_h2o_mort_b:long_name = "coefficient in moisture-based seedling mortality" ; + double fates_trs_seedling_h2o_mort_c(fates_pft) ; + fates_trs_seedling_h2o_mort_c:units = "-" ; + fates_trs_seedling_h2o_mort_c:long_name = "coefficient in moisture-based seedling mortality" ; + double fates_trs_seedling_light_mort_a(fates_pft) ; + fates_trs_seedling_light_mort_a:units = "-" ; + fates_trs_seedling_light_mort_a:long_name = "light-based seedling mortality coefficient" ; + double fates_trs_seedling_light_mort_b(fates_pft) ; + fates_trs_seedling_light_mort_b:units = "-" ; + fates_trs_seedling_light_mort_b:long_name = "light-based seedling mortality coefficient" ; + double fates_trs_seedling_light_rec_a(fates_pft) ; + fates_trs_seedling_light_rec_a:units = "-" ; + fates_trs_seedling_light_rec_a:long_name = "coefficient in light-based seedling to sapling transition" ; + double fates_trs_seedling_light_rec_b(fates_pft) ; + fates_trs_seedling_light_rec_b:units = "-" ; + fates_trs_seedling_light_rec_b:long_name = "coefficient in light-based seedling to sapling transition" ; + double fates_trs_seedling_mdd_crit(fates_pft) ; + fates_trs_seedling_mdd_crit:units = "mm H2O day" ; + fates_trs_seedling_mdd_crit:long_name = "critical moisture deficit (suction) day accumulation for seedling moisture-based seedling mortality to begin" ; + double fates_trs_seedling_par_crit_germ(fates_pft) ; + fates_trs_seedling_par_crit_germ:units = "MJ m-2 day-1" ; + fates_trs_seedling_par_crit_germ:long_name = "critical light level for germination" ; + double fates_trs_seedling_psi_crit(fates_pft) ; + fates_trs_seedling_psi_crit:units = "mm H2O" ; + fates_trs_seedling_psi_crit:long_name = "critical soil moisture (suction) for seedling stress" ; + double fates_trs_seedling_psi_emerg(fates_pft) ; + fates_trs_seedling_psi_emerg:units = "mm h20 suction" ; + fates_trs_seedling_psi_emerg:long_name = "critical soil moisture for seedling emergence" ; + double fates_trs_seedling_root_depth(fates_pft) ; + fates_trs_seedling_root_depth:units = "m" ; + fates_trs_seedling_root_depth:long_name = "rooting depth of seedlings" ; + double fates_turb_displar(fates_pft) ; + fates_turb_displar:units = "unitless" ; + fates_turb_displar:long_name = "Ratio of displacement height to canopy top height" ; + double fates_turb_leaf_diameter(fates_pft) ; + fates_turb_leaf_diameter:units = "m" ; + fates_turb_leaf_diameter:long_name = "Characteristic leaf dimension" ; + double fates_turb_z0mr(fates_pft) ; + fates_turb_z0mr:units = "unitless" ; + fates_turb_z0mr:long_name = "Ratio of momentum roughness length to canopy top height" ; + double fates_turnover_branch(fates_pft) ; + fates_turnover_branch:units = "yr" ; + fates_turnover_branch:long_name = "turnover time of branches" ; + double fates_turnover_fnrt(fates_pft) ; + fates_turnover_fnrt:units = "yr" ; + fates_turnover_fnrt:long_name = "root longevity (alternatively, turnover time)" ; + double fates_turnover_leaf(fates_leafage_class, fates_pft) ; + fates_turnover_leaf:units = "yr" ; + fates_turnover_leaf:long_name = "Leaf longevity (ie turnover timescale). For drought-deciduous PFTs, this also indicates the maximum length of the growing (i.e., leaves on) season." ; + double fates_turnover_senleaf_fdrought(fates_pft) ; + fates_turnover_senleaf_fdrought:units = "unitless[0-1]" ; + fates_turnover_senleaf_fdrought:long_name = "multiplication factor for leaf longevity of senescent leaves during drought" ; + double fates_wood_density(fates_pft) ; + fates_wood_density:units = "g/cm3" ; + fates_wood_density:long_name = "mean density of woody tissue in plant" ; + double fates_woody(fates_pft) ; + fates_woody:units = "logical flag" ; + fates_woody:long_name = "Binary woody lifeform flag" ; + double fates_hlm_pft_map(fates_hlm_pftno, fates_pft) ; + fates_hlm_pft_map:units = "area fraction" ; + fates_hlm_pft_map:long_name = "In fixed biogeog mode, fraction of HLM area associated with each FATES PFT" ; + double fates_fire_FBD(fates_litterclass) ; + fates_fire_FBD:units = "kg Biomass/m3" ; + fates_fire_FBD:long_name = "fuel bulk density" ; + double fates_fire_low_moisture_Coeff(fates_litterclass) ; + fates_fire_low_moisture_Coeff:units = "NA" ; + fates_fire_low_moisture_Coeff:long_name = "spitfire parameter, equation B1 Thonicke et al 2010" ; + double fates_fire_low_moisture_Slope(fates_litterclass) ; + fates_fire_low_moisture_Slope:units = "NA" ; + fates_fire_low_moisture_Slope:long_name = "spitfire parameter, equation B1 Thonicke et al 2010" ; + double fates_fire_mid_moisture(fates_litterclass) ; + fates_fire_mid_moisture:units = "NA" ; + fates_fire_mid_moisture:long_name = "spitfire litter moisture threshold to be considered medium dry" ; + double fates_fire_mid_moisture_Coeff(fates_litterclass) ; + fates_fire_mid_moisture_Coeff:units = "NA" ; + fates_fire_mid_moisture_Coeff:long_name = "spitfire parameter, equation B1 Thonicke et al 2010" ; + double fates_fire_mid_moisture_Slope(fates_litterclass) ; + fates_fire_mid_moisture_Slope:units = "NA" ; + fates_fire_mid_moisture_Slope:long_name = "spitfire parameter, equation B1 Thonicke et al 2010" ; + double fates_fire_min_moisture(fates_litterclass) ; + fates_fire_min_moisture:units = "NA" ; + fates_fire_min_moisture:long_name = "spitfire litter moisture threshold to be considered very dry" ; + double fates_fire_SAV(fates_litterclass) ; + fates_fire_SAV:units = "cm-1" ; + fates_fire_SAV:long_name = "fuel surface area to volume ratio" ; + double fates_frag_maxdecomp(fates_litterclass) ; + fates_frag_maxdecomp:units = "yr-1" ; + fates_frag_maxdecomp:long_name = "maximum rate of litter & CWD transfer from non-decomposing class into decomposing class" ; + double fates_frag_cwd_frac(fates_NCWD) ; + fates_frag_cwd_frac:units = "fraction" ; + fates_frag_cwd_frac:long_name = "fraction of woody (bdead+bsw) biomass destined for CWD pool" ; + double fates_canopy_closure_thresh ; + fates_canopy_closure_thresh:units = "unitless" ; + fates_canopy_closure_thresh:long_name = "tree canopy coverage at which crown area allometry changes from savanna to forest value" ; + double fates_cnp_eca_plant_escalar ; + fates_cnp_eca_plant_escalar:units = "" ; + fates_cnp_eca_plant_escalar:long_name = "scaling factor for plant fine root biomass to calculate nutrient carrier enzyme abundance (ECA)" ; + double fates_cohort_age_fusion_tol ; + fates_cohort_age_fusion_tol:units = "unitless" ; + fates_cohort_age_fusion_tol:long_name = "minimum fraction in differece in cohort age between cohorts." ; + double fates_cohort_size_fusion_tol ; + fates_cohort_size_fusion_tol:units = "unitless" ; + fates_cohort_size_fusion_tol:long_name = "minimum fraction in difference in dbh between cohorts" ; + double fates_comp_excln ; + fates_comp_excln:units = "none" ; + fates_comp_excln:long_name = "IF POSITIVE: weighting factor (exponent on dbh) for canopy layer exclusion and promotion, IF NEGATIVE: switch to use deterministic height sorting" ; + double fates_damage_canopy_layer_code ; + fates_damage_canopy_layer_code:units = "unitless" ; + fates_damage_canopy_layer_code:long_name = "Integer code that decides whether damage affects canopy trees (1), understory trees (2)" ; + double fates_damage_event_code ; + fates_damage_event_code:units = "unitless" ; + fates_damage_event_code:long_name = "Integer code that options how damage events are structured" ; + double fates_dev_arbitrary ; + fates_dev_arbitrary:units = "unknown" ; + fates_dev_arbitrary:long_name = "Unassociated free parameter that developers can use for testing arbitrary new hypotheses" ; + double fates_fire_active_crown_fire ; + fates_fire_active_crown_fire:units = "0 or 1" ; + fates_fire_active_crown_fire:long_name = "flag, 1=active crown fire 0=no active crown fire" ; + double fates_fire_cg_strikes ; + fates_fire_cg_strikes:units = "fraction (0-1)" ; + fates_fire_cg_strikes:long_name = "fraction of cloud to ground lightning strikes" ; + double fates_fire_drying_ratio ; + fates_fire_drying_ratio:units = "NA" ; + fates_fire_drying_ratio:long_name = "spitfire parameter, fire drying ratio for fuel moisture, alpha_FMC EQ 6 Thonicke et al 2010" ; + double fates_fire_durat_slope ; + fates_fire_durat_slope:units = "NA" ; + fates_fire_durat_slope:long_name = "spitfire parameter, fire max duration slope, Equation 14 Thonicke et al 2010" ; + double fates_fire_fdi_a ; + fates_fire_fdi_a:units = "NA" ; + fates_fire_fdi_a:long_name = "spitfire parameter, fire danger index, EQ 5 Thonicke et al 2010" ; + double fates_fire_fdi_alpha ; + fates_fire_fdi_alpha:units = "NA" ; + fates_fire_fdi_alpha:long_name = "spitfire parameter, EQ 7 Venevsky et al. GCB 2002,(modified EQ 8 Thonicke et al. 2010) " ; + double fates_fire_fdi_b ; + fates_fire_fdi_b:units = "NA" ; + fates_fire_fdi_b:long_name = "spitfire parameter, fire danger index, EQ 5 Thonicke et al 2010 " ; + double fates_fire_fuel_energy ; + fates_fire_fuel_energy:units = "kJ/kg" ; + fates_fire_fuel_energy:long_name = "spitfire parameter, heat content of fuel" ; + double fates_fire_max_durat ; + fates_fire_max_durat:units = "minutes" ; + fates_fire_max_durat:long_name = "spitfire parameter, fire maximum duration, Equation 14 Thonicke et al 2010" ; + double fates_fire_miner_damp ; + fates_fire_miner_damp:units = "NA" ; + fates_fire_miner_damp:long_name = "spitfire parameter, mineral-dampening coefficient EQ A1 Thonicke et al 2010 " ; + double fates_fire_miner_total ; + fates_fire_miner_total:units = "fraction" ; + fates_fire_miner_total:long_name = "spitfire parameter, total mineral content, Table A1 Thonicke et al 2010" ; + double fates_fire_nignitions ; + fates_fire_nignitions:units = "ignitions per year per km2" ; + fates_fire_nignitions:long_name = "number of annual ignitions per square km" ; + double fates_fire_part_dens ; + fates_fire_part_dens:units = "kg/m2" ; + fates_fire_part_dens:long_name = "spitfire parameter, oven dry particle density, Table A1 Thonicke et al 2010" ; + double fates_fire_threshold ; + fates_fire_threshold:units = "kW/m" ; + fates_fire_threshold:long_name = "spitfire parameter, fire intensity threshold for tracking fires that spread" ; + double fates_frag_cwd_fcel ; + fates_frag_cwd_fcel:units = "unitless" ; + fates_frag_cwd_fcel:long_name = "Cellulose fraction for CWD" ; + double fates_frag_cwd_flig ; + fates_frag_cwd_flig:units = "unitless" ; + fates_frag_cwd_flig:long_name = "Lignin fraction of coarse woody debris" ; + double fates_hydro_kmax_rsurf1 ; + fates_hydro_kmax_rsurf1:units = "kg water/m2 root area/Mpa/s" ; + fates_hydro_kmax_rsurf1:long_name = "maximum conducitivity for unit root surface (into root)" ; + double fates_hydro_kmax_rsurf2 ; + fates_hydro_kmax_rsurf2:units = "kg water/m2 root area/Mpa/s" ; + fates_hydro_kmax_rsurf2:long_name = "maximum conducitivity for unit root surface (out of root)" ; + double fates_hydro_psi0 ; + fates_hydro_psi0:units = "MPa" ; + fates_hydro_psi0:long_name = "sapwood water potential at saturation" ; + double fates_hydro_psicap ; + fates_hydro_psicap:units = "MPa" ; + fates_hydro_psicap:long_name = "sapwood water potential at which capillary reserves exhausted" ; + double fates_hydro_solver ; + fates_hydro_solver:units = "unitless" ; + fates_hydro_solver:long_name = "switch designating which numerical solver for plant hydraulics, 1 = 1D taylor, 2 = 2D Picard, 3 = 2D Newton (deprecated)" ; + double fates_landuse_logging_coll_under_frac ; + fates_landuse_logging_coll_under_frac:units = "fraction" ; + fates_landuse_logging_coll_under_frac:long_name = "Fraction of stems killed in the understory when logging generates disturbance" ; + double fates_landuse_logging_collateral_frac ; + fates_landuse_logging_collateral_frac:units = "fraction" ; + fates_landuse_logging_collateral_frac:long_name = "Fraction of large stems in upperstory that die from logging collateral damage" ; + double fates_landuse_logging_dbhmax ; + fates_landuse_logging_dbhmax:units = "cm" ; + fates_landuse_logging_dbhmax:long_name = "Maximum dbh below which logging is applied (unset values flag this to be unused)" ; + double fates_landuse_logging_dbhmax_infra ; + fates_landuse_logging_dbhmax_infra:units = "cm" ; + fates_landuse_logging_dbhmax_infra:long_name = "Tree diameter, above which infrastructure from logging does not impact damage or mortality." ; + double fates_landuse_logging_dbhmin ; + fates_landuse_logging_dbhmin:units = "cm" ; + fates_landuse_logging_dbhmin:long_name = "Minimum dbh at which logging is applied" ; + double fates_landuse_logging_direct_frac ; + fates_landuse_logging_direct_frac:units = "fraction" ; + fates_landuse_logging_direct_frac:long_name = "Fraction of stems logged directly per event" ; + double fates_landuse_logging_event_code ; + fates_landuse_logging_event_code:units = "unitless" ; + fates_landuse_logging_event_code:long_name = "Integer code that options how logging events are structured" ; + double fates_landuse_logging_export_frac ; + fates_landuse_logging_export_frac:units = "fraction" ; + fates_landuse_logging_export_frac:long_name = "fraction of trunk product being shipped offsite, the leftovers will be left onsite as large CWD" ; + double fates_landuse_logging_mechanical_frac ; + fates_landuse_logging_mechanical_frac:units = "fraction" ; + fates_landuse_logging_mechanical_frac:long_name = "Fraction of stems killed due infrastructure an other mechanical means" ; + double fates_landuse_pprodharv10_forest_mean ; + fates_landuse_pprodharv10_forest_mean:units = "fraction" ; + fates_landuse_pprodharv10_forest_mean:long_name = "mean harvest mortality proportion of deadstem to 10-yr product (pprodharv10) of all woody PFT types" ; + double fates_leaf_photo_temp_acclim_thome_time ; + fates_leaf_photo_temp_acclim_thome_time:units = "years" ; + fates_leaf_photo_temp_acclim_thome_time:long_name = "Length of the window for the long-term (i.e. T_home in Kumarathunge et al 2019) exponential moving average (ema) of vegetation temperature used in photosynthesis temperature acclimation (used if fates_leaf_photo_tempsens_model = 2)" ; + double fates_leaf_photo_temp_acclim_timescale ; + fates_leaf_photo_temp_acclim_timescale:units = "days" ; + fates_leaf_photo_temp_acclim_timescale:long_name = "Length of the window for the exponential moving average (ema) of vegetation temperature used in photosynthesis temperature acclimation (used if fates_maintresp_leaf_model=2 or fates_leaf_photo_tempsens_model = 2)" ; + double fates_leaf_photo_tempsens_model ; + fates_leaf_photo_tempsens_model:units = "unitless" ; + fates_leaf_photo_tempsens_model:long_name = "switch for choosing the model that defines the temperature sensitivity of photosynthetic parameters (vcmax, jmax). 1=non-acclimating; 2=Kumarathunge et al 2019" ; + double fates_leaf_stomatal_assim_model ; + fates_leaf_stomatal_assim_model:units = "unitless" ; + fates_leaf_stomatal_assim_model:long_name = "a switch designating whether to use net (1) or gross (2) assimilation in the stomatal model" ; + double fates_leaf_stomatal_model ; + fates_leaf_stomatal_model:units = "unitless" ; + fates_leaf_stomatal_model:long_name = "switch for choosing between Ball-Berry (1) stomatal conductance model and Medlyn (2) model" ; + double fates_leaf_theta_cj_c3 ; + fates_leaf_theta_cj_c3:units = "unitless" ; + fates_leaf_theta_cj_c3:long_name = "Empirical curvature parameter for ac, aj photosynthesis co-limitation in c3 plants" ; + double fates_leaf_theta_cj_c4 ; + fates_leaf_theta_cj_c4:units = "unitless" ; + fates_leaf_theta_cj_c4:long_name = "Empirical curvature parameter for ac, aj photosynthesis co-limitation in c4 plants" ; + double fates_maintresp_leaf_model ; + fates_maintresp_leaf_model:units = "unitless" ; + fates_maintresp_leaf_model:long_name = "switch for choosing between maintenance respiration models. 1=Ryan (1991), 2=Atkin et al., (2017)" ; + double fates_maintresp_nonleaf_baserate ; + fates_maintresp_nonleaf_baserate:units = "gC/gN/s" ; + fates_maintresp_nonleaf_baserate:long_name = "Base maintenance respiration rate for plant tissues, using Ryan 1991" ; + double fates_maxcohort ; + fates_maxcohort:units = "count" ; + fates_maxcohort:long_name = "maximum number of cohorts per patch. Actual number of cohorts also depend on cohort fusion tolerances" ; + double fates_maxpatch_primary ; + fates_maxpatch_primary:units = "count" ; + fates_maxpatch_primary:long_name = "maximum number of primary vegetation patches per site" ; + double fates_maxpatch_secondary ; + fates_maxpatch_secondary:units = "count" ; + fates_maxpatch_secondary:long_name = "maximum number of secondary vegetation patches per site" ; + double fates_mort_disturb_frac ; + fates_mort_disturb_frac:units = "fraction" ; + fates_mort_disturb_frac:long_name = "fraction of canopy mortality that results in disturbance (i.e. transfer of area from new to old patch)" ; + double fates_mort_understorey_death ; + fates_mort_understorey_death:units = "fraction" ; + fates_mort_understorey_death:long_name = "fraction of plants in understorey cohort impacted by overstorey tree-fall" ; + double fates_patch_fusion_tol ; + fates_patch_fusion_tol:units = "unitless" ; + fates_patch_fusion_tol:long_name = "minimum fraction in difference in profiles between patches" ; + double fates_phen_chilltemp ; + fates_phen_chilltemp:units = "degrees C" ; + fates_phen_chilltemp:long_name = "chilling day counting threshold for vegetation" ; + double fates_phen_coldtemp ; + fates_phen_coldtemp:units = "degrees C" ; + fates_phen_coldtemp:long_name = "vegetation temperature exceedance that flags a cold-day for leaf-drop" ; + double fates_phen_gddthresh_a ; + fates_phen_gddthresh_a:units = "none" ; + fates_phen_gddthresh_a:long_name = "GDD accumulation function, intercept parameter: gdd_thesh = a + b exp(c*ncd)" ; + double fates_phen_gddthresh_b ; + fates_phen_gddthresh_b:units = "none" ; + fates_phen_gddthresh_b:long_name = "GDD accumulation function, multiplier parameter: gdd_thesh = a + b exp(c*ncd)" ; + double fates_phen_gddthresh_c ; + fates_phen_gddthresh_c:units = "none" ; + fates_phen_gddthresh_c:long_name = "GDD accumulation function, exponent parameter: gdd_thesh = a + b exp(c*ncd)" ; + double fates_phen_mindayson ; + fates_phen_mindayson:units = "days" ; + fates_phen_mindayson:long_name = "day threshold compared against days since leaves became on-allometry" ; + double fates_phen_ncolddayslim ; + fates_phen_ncolddayslim:units = "days" ; + fates_phen_ncolddayslim:long_name = "day threshold exceedance for temperature leaf-drop" ; + double fates_q10_froz ; + fates_q10_froz:units = "unitless" ; + fates_q10_froz:long_name = "Q10 for frozen-soil respiration rates" ; + double fates_q10_mr ; + fates_q10_mr:units = "unitless" ; + fates_q10_mr:long_name = "Q10 for maintenance respiration" ; + double fates_rad_model ; + fates_rad_model:units = "unitless" ; + fates_rad_model:long_name = "switch designating the model for canopy radiation, 1 = Norman, 2 = Two-stream (experimental)" ; + double fates_regeneration_model ; + fates_regeneration_model:units = "-" ; + fates_regeneration_model:long_name = "switch for choosing between FATES\'s: 1) default regeneration scheme , 2) the Tree Recruitment Scheme (Hanbury-Brown et al., 2022), or (3) the Tree Recruitment Scheme without seedling dynamics" ; + double fates_soil_salinity ; + fates_soil_salinity:units = "ppt" ; + fates_soil_salinity:long_name = "soil salinity used for model when not coupled to dynamic soil salinity" ; + double fates_trs_seedling2sap_par_timescale ; + fates_trs_seedling2sap_par_timescale:units = "days" ; + fates_trs_seedling2sap_par_timescale:long_name = "Length of the window for the exponential moving average of par at the seedling layer used to calculate seedling to sapling transition rates" ; + double fates_trs_seedling_emerg_h2o_timescale ; + fates_trs_seedling_emerg_h2o_timescale:units = "days" ; + fates_trs_seedling_emerg_h2o_timescale:long_name = "Length of the window for the exponential moving average of smp used to calculate seedling emergence" ; + double fates_trs_seedling_mdd_timescale ; + fates_trs_seedling_mdd_timescale:units = "days" ; + fates_trs_seedling_mdd_timescale:long_name = "Length of the window for the exponential moving average of moisture deficit days used to calculate seedling mortality" ; + double fates_trs_seedling_mort_par_timescale ; + fates_trs_seedling_mort_par_timescale:units = "days" ; + fates_trs_seedling_mort_par_timescale:long_name = "Length of the window for the exponential moving average of par at the seedling layer used to calculate seedling mortality" ; + double fates_vai_top_bin_width ; + fates_vai_top_bin_width:units = "m2/m2" ; + fates_vai_top_bin_width:long_name = "width in VAI units of uppermost leaf+stem layer scattering element in each canopy layer" ; + double fates_vai_width_increase_factor ; + fates_vai_width_increase_factor:units = "unitless" ; + fates_vai_width_increase_factor:long_name = "factor by which each leaf+stem scattering element increases in VAI width (1 = uniform spacing)" ; + +// global attributes: + :history = "This file was generated by BatchPatchParams.py:\nCDL Base File = archive/api24.1.0_101722_fates_params_default.cdl\nXML patch file = archive/api24.1.0_101722_patch_params.xml" ; +data: + + fates_history_ageclass_bin_edges = 0, 1, 2, 5, 10, 20, 50 ; + + fates_history_coageclass_bin_edges = 0, 5 ; + + fates_history_height_bin_edges = 0, 0.1, 0.3, 1, 3, 10 ; + + fates_history_damage_bin_edges = 0, 80 ; + + fates_history_sizeclass_bin_edges = 0, 5, 10, 15, 20, 30, 40, 50, 60, 70, + 80, 90, 100 ; + + fates_alloc_organ_id = 1, 2, 3, 6 ; + + fates_hydro_htftype_node = 1, 1, 1, 1 ; + + fates_pftname = + "broadleaf_evergreen_tropical_tree ", + "needleleaf_evergreen_extratrop_tree ", + "needleleaf_colddecid_extratrop_tree ", + "broadleaf_evergreen_extratrop_tree ", + "broadleaf_hydrodecid_tropical_tree ", + "broadleaf_colddecid_extratrop_tree ", + "broadleaf_evergreen_extratrop_shrub ", + "broadleaf_hydrodecid_extratrop_shrub ", + "broadleaf_colddecid_extratrop_shrub ", + "arctic_c3_grass ", + "cool_c3_grass ", + "c4_grass " ; + + fates_hydro_organ_name = + "leaf ", + "stem ", + "transporting root ", + "absorbing root " ; + + fates_alloc_organ_name = + "leaf", + "fine root", + "sapwood", + "structure" ; + + fates_litterclass_name = + "twig ", + "small branch ", + "large branch ", + "trunk ", + "dead leaves ", + "live grass " ; + + fates_alloc_organ_priority = + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 ; + + fates_alloc_storage_cushion = 1.2, 1.2, 1.2, 1.2, 2.4, 1.2, 1.2, 2.4, 1.2, + 1.2, 1.2, 1.2 ; + + fates_alloc_store_priority_frac = 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, + 0.8, 0.8, 0.8, 0.8 ; + + fates_allom_agb1 = 0.06896, 0.06896, 0.06896, 0.06896, 0.06896, 0.06896, + 0.06896, 0.06896, 0.06896, 0.01, 0.01, 0.01 ; + + fates_allom_agb2 = 0.572, 0.572, 0.572, 0.572, 0.572, 0.572, 0.572, 0.572, + 0.572, 0.572, 0.572, 0.572 ; + + fates_allom_agb3 = 1.94, 1.94, 1.94, 1.94, 1.94, 1.94, 1.94, 1.94, 1.94, + 1.94, 1.94, 1.94 ; + + fates_allom_agb4 = 0.931, 0.931, 0.931, 0.931, 0.931, 0.931, 0.931, 0.931, + 0.931, 0.931, 0.931, 0.931 ; + + fates_allom_agb_frac = 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, + 0.6, 0.6 ; + + fates_allom_amode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_blca_expnt_diff = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_allom_cmode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_crown_depth_frac = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.95, 0.95, + 0.95, 1, 1, 1 ; + + fates_allom_d2bl1 = 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, + 0.07, 0.07, 0.07 ; + + fates_allom_d2bl2 = 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, + 1.3 ; + + fates_allom_d2bl3 = 0.55, 0.55, 0.55, 0.55, 0.55, 0.55, 0.55, 0.55, 0.55, + 0.55, 0.55, 0.55 ; + + fates_allom_d2ca_coefficient_max = 0.6568464, 0.6568464, 0.6568464, + 0.6568464, 0.6568464, 0.6568464, 0.6568464, 0.6568464, 0.6568464, + 0.6568464, 0.6568464, 0.6568464 ; + + fates_allom_d2ca_coefficient_min = 0.3381119, 0.3381119, 0.3381119, + 0.3381119, 0.3381119, 0.3381119, 0.3381119, 0.3381119, 0.3381119, + 0.3381119, 0.3381119, 0.3381119 ; + + fates_allom_d2h1 = 0.64, 0.64, 0.64, 0.64, 0.64, 0.64, 0.64, 0.64, 0.64, + 0.64, 0.64, 0.64 ; + + fates_allom_d2h2 = 0.37, 0.37, 0.37, 0.37, 0.37, 0.37, 0.37, 0.37, 0.37, + 0.37, 0.37, 0.37 ; + + fates_allom_d2h3 = -999.9, -999.9, -999.9, -999.9, -999.9, -999.9, -999.9, + -999.9, -999.9, -999.9, -999.9, -999.9 ; + + fates_allom_dbh_maxheight = 90, 80, 80, 80, 90, 80, 3, 3, 2, 0.35, 0.35, 0.35 ; + + fates_allom_fmode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_fnrt_prof_a = 7, 7, 7, 7, 6, 6, 7, 7, 7, 11, 11, 11 ; + + fates_allom_fnrt_prof_b = 1, 2, 2, 1, 2, 2, 1.5, 1.5, 1.5, 2, 2, 2 ; + + fates_allom_fnrt_prof_mode = 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 ; + + fates_allom_frbstor_repro = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_allom_hmode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_l2fr = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_la_per_sa_int = 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, + 0.8, 0.8, 0.8 ; + + fates_allom_la_per_sa_slp = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_allom_lmode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_sai_scaler = 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, + 0.1, 0.1 ; + + fates_allom_smode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_stmode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_zroot_k = 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10 ; + + fates_allom_zroot_max_dbh = 100, 100, 100, 100, 100, 100, 2, 2, 2, 2, 2, 2 ; + + fates_allom_zroot_max_z = 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, + 100, 100 ; + + fates_allom_zroot_min_dbh = 1, 1, 1, 2.5, 2.5, 2.5, 0.1, 0.1, 0.1, 0.1, 0.1, + 0.1 ; + + fates_allom_zroot_min_z = 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, + 100, 100 ; + + fates_c2b = 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ; + + fates_cnp_eca_alpha_ptase = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5 ; + + fates_cnp_eca_decompmicc = 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280 ; + + fates_cnp_eca_km_nh4 = 0.14, 0.14, 0.14, 0.14, 0.14, 0.14, 0.14, 0.14, 0.14, + 0.14, 0.14, 0.14 ; + + fates_cnp_eca_km_no3 = 0.27, 0.27, 0.27, 0.27, 0.27, 0.27, 0.27, 0.27, 0.27, + 0.27, 0.27, 0.27 ; + + fates_cnp_eca_km_p = 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, + 0.1 ; + + fates_cnp_eca_km_ptase = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_cnp_eca_lambda_ptase = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_cnp_eca_vmax_ptase = 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, + 5e-09, 5e-09, 5e-09, 5e-09, 5e-09 ; + + fates_cnp_nfix1 = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_cnp_nitr_store_ratio = 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, + 1.5, 1.5, 1.5 ; + + fates_cnp_phos_store_ratio = 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, + 1.5, 1.5, 1.5 ; + + fates_cnp_pid_kd = 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1 ; + + fates_cnp_pid_ki = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_cnp_pid_kp = 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, + 0.0005, 0.0005, 0.0005, 0.0005, 0.0005 ; + + fates_cnp_prescribed_nuptake = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_cnp_prescribed_puptake = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_cnp_store_ovrflw_frac = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_cnp_turnover_nitr_retrans = + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_cnp_turnover_phos_retrans = + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_cnp_vmax_nh4 = 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, + 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09 ; + + fates_cnp_vmax_no3 = 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, + 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09 ; + + fates_cnp_vmax_p = 5e-10, 5e-10, 5e-10, 5e-10, 5e-10, 5e-10, 5e-10, 5e-10, + 5e-10, 5e-10, 5e-10, 5e-10 ; + + fates_damage_frac = 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, + 0.01, 0.01, 0.01 ; + + fates_damage_mort_p1 = 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 ; + + fates_damage_mort_p2 = 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, + 5.5, 5.5 ; + + fates_damage_recovery_scalar = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_dev_arbitrary_pft = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_fire_alpha_SH = 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, + 0.2 ; + + fates_fire_bark_scaler = 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, + 0.07, 0.07, 0.07, 0.07 ; + + fates_fire_crown_kill = 0.775, 0.775, 0.775, 0.775, 0.775, 0.775, 0.775, + 0.775, 0.775, 0.775, 0.775, 0.775 ; + + fates_frag_fnrt_fcel = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5 ; + + fates_frag_fnrt_flab = 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25 ; + + fates_frag_fnrt_flig = 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25 ; + + fates_frag_leaf_fcel = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5 ; + + fates_frag_leaf_flab = 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25 ; + + fates_frag_leaf_flig = 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25 ; + + fates_frag_seed_decay_rate = 0.51, 0.51, 0.51, 0.51, 0.51, 0.51, 0.51, 0.51, + 0.51, 0.51, 0.51, 0.51 ; + + fates_grperc = 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, + 0.11, 0.11 ; + + fates_hydro_avuln_gs = 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, + 2.5, 2.5 ; + + fates_hydro_avuln_node = + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ; + + fates_hydro_epsil_node = + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 ; + + fates_hydro_fcap_node = + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, + 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_hydro_k_lwp = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_hydro_kmax_node = + -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999 ; + + fates_hydro_p50_gs = -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, + -1.5, -1.5, -1.5 ; + + fates_hydro_p50_node = + -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, + -2.25, -2.25, + -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, + -2.25, -2.25, + -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, + -2.25, -2.25, + -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, + -2.25, -2.25 ; + + fates_hydro_p_taper = 0.333, 0.333, 0.333, 0.333, 0.333, 0.333, 0.333, + 0.333, 0.333, 0.333, 0.333, 0.333 ; + + fates_hydro_pinot_node = + -1.465984, -1.465984, -1.465984, -1.465984, -1.465984, -1.465984, + -1.465984, -1.465984, -1.465984, -1.465984, -1.465984, -1.465984, + -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, + -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, + -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, + -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, + -1.043478, -1.043478, -1.043478, -1.043478, -1.043478, -1.043478, + -1.043478, -1.043478, -1.043478, -1.043478, -1.043478, -1.043478 ; + + fates_hydro_pitlp_node = + -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, + -1.67, -1.67, + -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, + -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, + -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2 ; + + fates_hydro_resid_node = + 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, + 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, + 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, + 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11 ; + + fates_hydro_rfrac_stem = 0.625, 0.625, 0.625, 0.625, 0.625, 0.625, 0.625, + 0.625, 0.625, 0.625, 0.625, 0.625 ; + + fates_hydro_rs2 = 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, + 0.0001, 0.0001, 0.0001, 0.0001, 0.0001 ; + + fates_hydro_srl = 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25 ; + + fates_hydro_thetas_node = + 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, + 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, + 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, + 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75 ; + + fates_hydro_vg_alpha_node = + 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.005, 0.005, 0.005, 0.005, 0.005, + 0.005, 0.005, + 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.005, 0.005, 0.005, 0.005, 0.005, + 0.005, 0.005, + 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.005, 0.005, 0.005, 0.005, 0.005, + 0.005, 0.005, + 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.005, 0.005, 0.005, 0.005, 0.005, + 0.005, 0.005 ; + + fates_hydro_vg_m_node = + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5 ; + + fates_hydro_vg_n_node = + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ; + + fates_leaf_c3psn = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 ; + + fates_leaf_jmaxha = 43540, 43540, 43540, 43540, 43540, 43540, 43540, 43540, + 43540, 43540, 43540, 43540 ; + + fates_leaf_jmaxhd = 152040, 152040, 152040, 152040, 152040, 152040, 152040, + 152040, 152040, 152040, 152040, 152040 ; + + fates_leaf_jmaxse = 495, 495, 495, 495, 495, 495, 495, 495, 495, 495, 495, + 495 ; + + fates_leaf_slamax = 0.0954, 0.0954, 0.0954, 0.0954, 0.0954, 0.0954, 0.012, + 0.03, 0.03, 0.03, 0.03, 0.03 ; + + fates_leaf_slatop = 0.012, 0.005, 0.024, 0.009, 0.03, 0.03, 0.012, 0.03, + 0.03, 0.03, 0.03, 0.03 ; + + fates_leaf_stomatal_intercept = 10000, 10000, 10000, 10000, 10000, 10000, + 10000, 10000, 10000, 10000, 10000, 40000 ; + + fates_leaf_stomatal_slope_ballberry = 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 ; + + fates_leaf_stomatal_slope_medlyn = 4.1, 2.3, 2.3, 4.1, 4.4, 4.4, 4.7, 4.7, + 4.7, 2.2, 5.3, 1.6 ; + + fates_leaf_vcmax25top = + 50, 62, 39, 61, 58, 58, 62, 54, 54, 78, 78, 78 ; + + fates_leaf_vcmaxha = 65330, 65330, 65330, 65330, 65330, 65330, 65330, 65330, + 65330, 65330, 65330, 65330 ; + + fates_leaf_vcmaxhd = 149250, 149250, 149250, 149250, 149250, 149250, 149250, + 149250, 149250, 149250, 149250, 149250 ; + + fates_leaf_vcmaxse = 485, 485, 485, 485, 485, 485, 485, 485, 485, 485, 485, + 485 ; + + fates_maintresp_leaf_atkin2017_baserate = 1.756, 1.4995, 1.4995, 1.756, + 1.756, 1.756, 2.0749, 2.0749, 2.0749, 2.1956, 2.1956, 2.1956 ; + + fates_maintresp_leaf_ryan1991_baserate = 2.525e-06, 2.525e-06, 2.525e-06, + 2.525e-06, 2.525e-06, 2.525e-06, 2.525e-06, 2.525e-06, 2.525e-06, + 2.525e-06, 2.525e-06, 2.525e-06 ; + + fates_maintresp_reduction_curvature = 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, + 0.01, 0.01, 0.01, 0.01, 0.01, 0.01 ; + + fates_maintresp_reduction_intercept = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_maintresp_reduction_upthresh = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_mort_bmort = 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, + 0.014, 0.014, 0.014, 0.014 ; + + fates_mort_freezetol = 2.5, -55, -80, -30, 2.5, -80, -60, -10, -80, -80, + -20, 2.5 ; + + fates_mort_hf_flc_threshold = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5 ; + + fates_mort_hf_sm_threshold = 1e-06, 1e-06, 1e-06, 1e-06, 1e-06, 1e-06, + 1e-06, 1e-06, 1e-06, 1e-06, 1e-06, 1e-06 ; + + fates_mort_ip_age_senescence = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_mort_ip_size_senescence = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_mort_prescribed_canopy = 0.0194, 0.0194, 0.0194, 0.0194, 0.0194, + 0.0194, 0.0194, 0.0194, 0.0194, 0.0194, 0.0194, 0.0194 ; + + fates_mort_prescribed_understory = 0.025, 0.025, 0.025, 0.025, 0.025, 0.025, + 0.025, 0.025, 0.025, 0.025, 0.025, 0.025 ; + + fates_mort_r_age_senescence = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_mort_r_size_senescence = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_mort_scalar_coldstress = 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 ; + + fates_mort_scalar_cstarvation = 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, + 0.6, 0.6, 0.6 ; + + fates_mort_scalar_hydrfailure = 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, + 0.6, 0.6, 0.6 ; + + fates_mort_upthresh_cstarvation = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_nonhydro_smpsc = -255000, -255000, -255000, -255000, -255000, -255000, + -255000, -255000, -255000, -255000, -255000, -255000 ; + + fates_nonhydro_smpso = -66000, -66000, -66000, -66000, -66000, -66000, + -66000, -66000, -66000, -66000, -66000, -66000 ; + + fates_phen_cold_size_threshold = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_phen_drought_threshold = -152957.4, -152957.4, -152957.4, -152957.4, + -152957.4, -152957.4, -152957.4, -152957.4, -152957.4, -152957.4, + -152957.4, -152957.4 ; + + fates_phen_evergreen = 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 ; + + fates_phen_flush_fraction = _, _, 0.5, _, 0.5, 0.5, _, 0.5, 0.5, 0.5, 0.5, + 0.5 ; + + fates_phen_fnrt_drop_fraction = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_phen_mindaysoff = 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, + 100, 100 ; + + fates_phen_moist_threshold = -122365.9, -122365.9, -122365.9, -122365.9, + -122365.9, -122365.9, -122365.9, -122365.9, -122365.9, -122365.9, + -122365.9, -122365.9 ; + + fates_phen_season_decid = 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0 ; + + fates_phen_stem_drop_fraction = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_phen_stress_decid = 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1 ; + + fates_prescribed_npp_canopy = 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, + 0.4, 0.4, 0.4 ; + + fates_prescribed_npp_understory = 0.03125, 0.03125, 0.03125, 0.03125, + 0.03125, 0.03125, 0.03125, 0.03125, 0.03125, 0.03125, 0.03125, 0.03125 ; + + fates_rad_leaf_clumping_index = 0.85, 0.85, 0.8, 0.85, 0.85, 0.9, 0.85, 0.9, + 0.9, 0.75, 0.75, 0.75 ; + + fates_rad_leaf_rhonir = 0.46, 0.41, 0.39, 0.46, 0.41, 0.41, 0.46, 0.41, + 0.41, 0.28, 0.28, 0.28 ; + + fates_rad_leaf_rhovis = 0.11, 0.09, 0.08, 0.11, 0.08, 0.08, 0.11, 0.08, + 0.08, 0.05, 0.05, 0.05 ; + + fates_rad_leaf_taunir = 0.33, 0.32, 0.42, 0.33, 0.43, 0.43, 0.33, 0.43, + 0.43, 0.4, 0.4, 0.4 ; + + fates_rad_leaf_tauvis = 0.06, 0.04, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, + 0.06, 0.05, 0.05, 0.05 ; + + fates_rad_leaf_xl = 0.32, 0.01, 0.01, 0.32, 0.2, 0.59, 0.32, 0.59, 0.59, + -0.23, -0.23, -0.23 ; + + fates_rad_stem_rhonir = 0.49, 0.36, 0.36, 0.49, 0.49, 0.49, 0.49, 0.49, + 0.49, 0.53, 0.53, 0.53 ; + + fates_rad_stem_rhovis = 0.21, 0.12, 0.12, 0.21, 0.21, 0.21, 0.21, 0.21, + 0.21, 0.31, 0.31, 0.31 ; + + fates_rad_stem_taunir = 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, + 0.001, 0.001, 0.25, 0.25, 0.25 ; + + fates_rad_stem_tauvis = 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, + 0.001, 0.001, 0.12, 0.12, 0.12 ; + + fates_recruit_height_min = 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 0.2, 0.2, 0.2, + 0.125, 0.125, 0.125 ; + + fates_recruit_init_density = 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, + 0.2, 0.2, 0.2 ; + + fates_recruit_prescribed_rate = 0.02, 0.02, 0.02, 0.02, 0.02, 0.02, 0.02, + 0.02, 0.02, 0.02, 0.02, 0.02 ; + + fates_recruit_seed_alloc = 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, + 0.1, 0.1 ; + + fates_recruit_seed_alloc_mature = 0, 0, 0, 0, 0, 0, 0.9, 0.9, 0.9, 0.9, 0.9, + 0.9 ; + + fates_recruit_seed_dbh_repro_threshold = 90, 80, 80, 80, 90, 80, 3, 3, 2, + 0.35, 0.35, 0.35 ; + + fates_recruit_seed_germination_rate = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5 ; + + fates_recruit_seed_supplement = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_seed_dispersal_fraction = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_seed_dispersal_max_dist = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_seed_dispersal_pdf_scale = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_seed_dispersal_pdf_shape = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_stoich_nitr = + 0.033, 0.029, 0.04, 0.033, 0.04, 0.04, 0.033, 0.04, 0.04, 0.04, 0.04, 0.04, + 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, + 0.024, 0.024, + 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, + 1e-08, 1e-08, + 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, + 0.0047, 0.0047, 0.0047 ; + + fates_stoich_phos = + 0.0033, 0.0029, 0.004, 0.0033, 0.004, 0.004, 0.0033, 0.004, 0.004, 0.004, + 0.004, 0.004, + 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, + 0.0024, 0.0024, 0.0024, + 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, + 1e-09, 1e-09, + 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, + 0.00047, 0.00047, 0.00047, 0.00047 ; + + fates_trim_inc = 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, + 0.03, 0.03 ; + + fates_trim_limit = 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3 ; + + fates_trs_repro_alloc_a = 0.0049, 0.0049, 0.0049, 0.0049, 0.0049, 0.0049, + 0.0049, 0.0049, 0.0049, 0.0049, 0.0049, 0.0049 ; + + fates_trs_repro_alloc_b = -2.6171, -2.6171, -2.6171, -2.6171, -2.6171, + -2.6171, -2.6171, -2.6171, -2.6171, -2.6171, -2.6171, -2.6171 ; + + fates_trs_repro_frac_seed = 0.24, 0.24, 0.24, 0.24, 0.24, 0.24, 0.24, 0.24, + 0.24, 0.24, 0.24, 0.24 ; + + fates_trs_seedling_a_emerg = 0.0003, 0.0003, 0.0003, 0.0003, 0.0003, 0.0003, + 0.0003, 0.0003, 0.0003, 0.0003, 0.0003, 0.0003 ; + + fates_trs_seedling_b_emerg = 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, + 1.2, 1.2, 1.2 ; + + fates_trs_seedling_background_mort = 0.1085371, 0.1085371, 0.1085371, + 0.1085371, 0.1085371, 0.1085371, 0.1085371, 0.1085371, 0.1085371, + 0.1085371, 0.1085371, 0.1085371 ; + + fates_trs_seedling_h2o_mort_a = 4.070565e-17, 4.070565e-17, 4.070565e-17, + 4.070565e-17, 4.070565e-17, 4.070565e-17, 4.070565e-17, 4.070565e-17, + 4.070565e-17, 4.070565e-17, 4.070565e-17, 4.070565e-17 ; + + fates_trs_seedling_h2o_mort_b = -6.390757e-11, -6.390757e-11, -6.390757e-11, + -6.390757e-11, -6.390757e-11, -6.390757e-11, -6.390757e-11, + -6.390757e-11, -6.390757e-11, -6.390757e-11, -6.390757e-11, -6.390757e-11 ; + + fates_trs_seedling_h2o_mort_c = 1.268992e-05, 1.268992e-05, 1.268992e-05, + 1.268992e-05, 1.268992e-05, 1.268992e-05, 1.268992e-05, 1.268992e-05, + 1.268992e-05, 1.268992e-05, 1.268992e-05, 1.268992e-05 ; + + fates_trs_seedling_light_mort_a = -0.009897694, -0.009897694, -0.009897694, + -0.009897694, -0.009897694, -0.009897694, -0.009897694, -0.009897694, + -0.009897694, -0.009897694, -0.009897694, -0.009897694 ; + + fates_trs_seedling_light_mort_b = -7.154063, -7.154063, -7.154063, + -7.154063, -7.154063, -7.154063, -7.154063, -7.154063, -7.154063, + -7.154063, -7.154063, -7.154063 ; + + fates_trs_seedling_light_rec_a = 0.007, 0.007, 0.007, 0.007, 0.007, 0.007, + 0.007, 0.007, 0.007, 0.007, 0.007, 0.007 ; + + fates_trs_seedling_light_rec_b = 0.8615, 0.8615, 0.8615, 0.8615, 0.8615, + 0.8615, 0.8615, 0.8615, 0.8615, 0.8615, 0.8615, 0.8615 ; + + fates_trs_seedling_mdd_crit = 1400000, 1400000, 1400000, 1400000, 1400000, + 1400000, 1400000, 1400000, 1400000, 1400000, 1400000, 1400000 ; + + fates_trs_seedling_par_crit_germ = 0.656, 0.656, 0.656, 0.656, 0.656, 0.656, + 0.656, 0.656, 0.656, 0.656, 0.656, 0.656 ; + + fates_trs_seedling_psi_crit = -251995.7, -251995.7, -251995.7, -251995.7, + -251995.7, -251995.7, -251995.7, -251995.7, -251995.7, -251995.7, + -251995.7, -251995.7 ; + + fates_trs_seedling_psi_emerg = -15744.65, -15744.65, -15744.65, -15744.65, + -15744.65, -15744.65, -15744.65, -15744.65, -15744.65, -15744.65, + -15744.65, -15744.65 ; + + fates_trs_seedling_root_depth = 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, + 0.06, 0.06, 0.06, 0.06, 0.06 ; + + fates_turb_displar = 0.67, 0.67, 0.67, 0.67, 0.67, 0.67, 0.67, 0.67, 0.67, + 0.67, 0.67, 0.67 ; + + fates_turb_leaf_diameter = 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, + 0.04, 0.04, 0.04, 0.04 ; + + fates_turb_z0mr = 0.055, 0.055, 0.055, 0.055, 0.055, 0.055, 0.055, 0.055, + 0.055, 0.055, 0.055, 0.055 ; + + fates_turnover_branch = 150, 150, 150, 150, 150, 150, 150, 150, 150, 0, 0, 0 ; + + fates_turnover_fnrt = 1, 2, 1, 1.5, 1, 1, 1.5, 1, 1, 1, 1, 1 ; + + fates_turnover_leaf = + 1.5, 4, 1, 1.5, 1, 1, 1.5, 1, 1, 1, 1, 1 ; + + fates_turnover_senleaf_fdrought = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_wood_density = 0.7, 0.4, 0.7, 0.53, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, + 0.7 ; + + fates_woody = 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 ; + + fates_hlm_pft_map = + 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 ; + + fates_fire_FBD = 15.4, 16.8, 19.6, 999, 4, 4 ; + + fates_fire_low_moisture_Coeff = 1.12, 1.09, 0.98, 0.8, 1.15, 1.15 ; + + fates_fire_low_moisture_Slope = 0.62, 0.72, 0.85, 0.8, 0.62, 0.62 ; + + fates_fire_mid_moisture = 0.72, 0.51, 0.38, 1, 0.8, 0.8 ; + + fates_fire_mid_moisture_Coeff = 2.35, 1.47, 1.06, 0.8, 3.2, 3.2 ; + + fates_fire_mid_moisture_Slope = 2.35, 1.47, 1.06, 0.8, 3.2, 3.2 ; + + fates_fire_min_moisture = 0.18, 0.12, 0, 0, 0.24, 0.24 ; + + fates_fire_SAV = 13, 3.58, 0.98, 0.2, 66, 66 ; + + fates_frag_maxdecomp = 0.52, 0.383, 0.383, 0.19, 1, 999 ; + + fates_frag_cwd_frac = 0.045, 0.075, 0.21, 0.67 ; + + fates_canopy_closure_thresh = 0.8 ; + + fates_cnp_eca_plant_escalar = 1.25e-05 ; + + fates_cohort_age_fusion_tol = 0.08 ; + + fates_cohort_size_fusion_tol = 0.08 ; + + fates_comp_excln = 3 ; + + fates_damage_canopy_layer_code = 1 ; + + fates_damage_event_code = 1 ; + + fates_dev_arbitrary = _ ; + + fates_fire_active_crown_fire = 0 ; + + fates_fire_cg_strikes = 0.2 ; + + fates_fire_drying_ratio = 66000 ; + + fates_fire_durat_slope = -11.06 ; + + fates_fire_fdi_a = 17.62 ; + + fates_fire_fdi_alpha = 0.00037 ; + + fates_fire_fdi_b = 243.12 ; + + fates_fire_fuel_energy = 18000 ; + + fates_fire_max_durat = 240 ; + + fates_fire_miner_damp = 0.41739 ; + + fates_fire_miner_total = 0.055 ; + + fates_fire_nignitions = 15 ; + + fates_fire_part_dens = 513 ; + + fates_fire_threshold = 50 ; + + fates_frag_cwd_fcel = 0.76 ; + + fates_frag_cwd_flig = 0.24 ; + + fates_hydro_kmax_rsurf1 = 20 ; + + fates_hydro_kmax_rsurf2 = 0.0001 ; + + fates_hydro_psi0 = 0 ; + + fates_hydro_psicap = -0.6 ; + + fates_hydro_solver = 1 ; + + fates_landuse_logging_coll_under_frac = 0.55983 ; + + fates_landuse_logging_collateral_frac = 0.05 ; + + fates_landuse_logging_dbhmax = _ ; + + fates_landuse_logging_dbhmax_infra = 35 ; + + fates_landuse_logging_dbhmin = 50 ; + + fates_landuse_logging_direct_frac = 0.15 ; + + fates_landuse_logging_event_code = -30 ; + + fates_landuse_logging_export_frac = 0.8 ; + + fates_landuse_logging_mechanical_frac = 0.05 ; + + fates_landuse_pprodharv10_forest_mean = 0.8125 ; + + fates_leaf_photo_temp_acclim_thome_time = 30 ; + + fates_leaf_photo_temp_acclim_timescale = 30 ; + + fates_leaf_photo_tempsens_model = 1 ; + + fates_leaf_stomatal_assim_model = 1 ; + + fates_leaf_stomatal_model = 1 ; + + fates_leaf_theta_cj_c3 = 0.999 ; + + fates_leaf_theta_cj_c4 = 0.999 ; + + fates_maintresp_leaf_model = 1 ; + + fates_maintresp_nonleaf_baserate = 2.525e-06 ; + + fates_maxcohort = 100 ; + + fates_maxpatch_primary = 10 ; + + fates_maxpatch_secondary = 4 ; + + fates_mort_disturb_frac = 1 ; + + fates_mort_understorey_death = 0.55983 ; + + fates_patch_fusion_tol = 0.05 ; + + fates_phen_chilltemp = 5 ; + + fates_phen_coldtemp = 7.5 ; + + fates_phen_gddthresh_a = -68 ; + + fates_phen_gddthresh_b = 638 ; + + fates_phen_gddthresh_c = -0.01 ; + + fates_phen_mindayson = 90 ; + + fates_phen_ncolddayslim = 5 ; + + fates_q10_froz = 1.5 ; + + fates_q10_mr = 1.5 ; + + fates_rad_model = 1 ; + + fates_regeneration_model = 1 ; + + fates_soil_salinity = 0.4 ; + + fates_trs_seedling2sap_par_timescale = 32 ; + + fates_trs_seedling_emerg_h2o_timescale = 7 ; + + fates_trs_seedling_mdd_timescale = 126 ; + + fates_trs_seedling_mort_par_timescale = 32 ; + + fates_vai_top_bin_width = 1 ; + + fates_vai_width_increase_factor = 1 ; +} \ No newline at end of file diff --git a/parameter_files/archive/api28.0.0_103023_pr1093.xml b/parameter_files/archive/api28.0.0_103023_pr1093.xml new file mode 100644 index 0000000000..9665168836 --- /dev/null +++ b/parameter_files/archive/api28.0.0_103023_pr1093.xml @@ -0,0 +1,113 @@ + + + + + + + + + + + + archive/api28.0.0_103023_fates_params_default.cdl + fates_params_default.cdl + 1,2,3,4,5,6,7,8,9,10,11,12 + + + fates_pft + + 0.0673, 0.1364012, 0.0393057, 0.2653695, 0.0673, 0.0728698, 0.06896, 0.06896, 0.06896, 0.01, 0.01, 0.01 + + + fates_pft + + 0.976, 0.9449041, 1.087335, 0.8321321, 0.976, 1.0373211, 0.572, 0.572, 0.572, 0.572, 0.572, 0.572 + + + fates_pft + + 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1 + + + fates_pft + + 0.04, 0.07, 0.07, 0.01, 0.04, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07 + + + fates_pft + + 1.6019679, 1.5234373, 1.3051237, 1.9621397, 1.6019679, 1.3998939, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3 + + + fates_pft + + 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1 + + + fates_pft + + -0.12, -0.34, -0.32, -0.22, -0.12, -0.35, 0, 0, 0, 0, 0, 0 + + + fates_pft + + 0.2715891, 0.3693718, 1.0787259, 0.0579297, 0.2715891, 1.1553612, 0.6568464, 0.6568464, 0.6568464, 0.6568464, 0.6568464, 0.6568464 + + + fates_pft + + 0.2715891, 0.3693718, 1.0787259, 0.0579297, 0.2715891, 1.1553612, 0.6568464, 0.6568464, 0.6568464, 0.6568464, 0.6568464, 0.6568464 + + + fates_pft + + 78.4087704, 306.842667, 106.8745821, 104.3586841, 78.4087704, 31.4557047, 0.64, 0.64, 0.64, 0.64, 0.64, 0.64 + + + fates_pft + + 0.8124383, 0.752377, 0.9471302, 1.1146973, 0.8124383, 0.9734088, 0.37, 0.37, 0.37, 0.37, 0.37, 0.37 + + + fates_pft + + 47.6666164, 196.6865691, 93.9790461, 160.6835089, 47.6666164, 16.5928174, -999.9, -999.9, -999.9, -999.9, -999.9, -999.9 + + + fates_pft + + 1000, 1000, 1000, 1000, 1000, 1000, 3, 3, 2, 0.35, 0.35, 0.35 + + + fates_pft + + 5, 5, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1 + + + fates_pft + + 0.548327, 0.442350, 0.454845, 0.754336, 0.548327, 0.566452, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7 + + + diff --git a/parameter_files/archive/api34.0.0_032624_params_default.cdl b/parameter_files/archive/api34.0.0_032624_params_default.cdl new file mode 100644 index 0000000000..02bd77b647 --- /dev/null +++ b/parameter_files/archive/api34.0.0_032624_params_default.cdl @@ -0,0 +1,1743 @@ +netcdf tmp { +dimensions: + fates_NCWD = 4 ; + fates_history_age_bins = 7 ; + fates_history_coage_bins = 2 ; + fates_history_damage_bins = 2 ; + fates_history_height_bins = 6 ; + fates_history_size_bins = 13 ; + fates_hlm_pftno = 14 ; + fates_hydr_organs = 4 ; + fates_leafage_class = 1 ; + fates_litterclass = 6 ; + fates_pft = 12 ; + fates_plant_organs = 4 ; + fates_string_length = 60 ; + fates_landuseclass = 5 ; +variables: + double fates_history_ageclass_bin_edges(fates_history_age_bins) ; + fates_history_ageclass_bin_edges:units = "yr" ; + fates_history_ageclass_bin_edges:long_name = "Lower edges for age class bins used in age-resolved patch history output" ; + double fates_history_coageclass_bin_edges(fates_history_coage_bins) ; + fates_history_coageclass_bin_edges:units = "years" ; + fates_history_coageclass_bin_edges:long_name = "Lower edges for cohort age class bins used in cohort age resolved history output" ; + double fates_history_height_bin_edges(fates_history_height_bins) ; + fates_history_height_bin_edges:units = "m" ; + fates_history_height_bin_edges:long_name = "Lower edges for height bins used in height-resolved history output" ; + double fates_history_damage_bin_edges(fates_history_damage_bins) ; + fates_history_damage_bin_edges:units = "% crown loss" ; + fates_history_damage_bin_edges:long_name = "Lower edges for damage class bins used in cohort history output" ; + double fates_history_sizeclass_bin_edges(fates_history_size_bins) ; + fates_history_sizeclass_bin_edges:units = "cm" ; + fates_history_sizeclass_bin_edges:long_name = "Lower edges for DBH size class bins used in size-resolved cohort history output" ; + double fates_alloc_organ_id(fates_plant_organs) ; + fates_alloc_organ_id:units = "unitless" ; + fates_alloc_organ_id:long_name = "This is the global index that the organ in this file is associated with, values match those in parteh/PRTGenericMod.F90" ; + double fates_hydro_htftype_node(fates_hydr_organs) ; + fates_hydro_htftype_node:units = "unitless" ; + fates_hydro_htftype_node:long_name = "Switch that defines the hydraulic transfer functions for each organ." ; + char fates_pftname(fates_pft, fates_string_length) ; + fates_pftname:units = "unitless - string" ; + fates_pftname:long_name = "Description of plant type" ; + char fates_hydro_organ_name(fates_hydr_organs, fates_string_length) ; + fates_hydro_organ_name:units = "unitless - string" ; + fates_hydro_organ_name:long_name = "Name of plant hydraulics organs (DONT CHANGE, order matches media list in FatesHydraulicsMemMod.F90)" ; + char fates_alloc_organ_name(fates_plant_organs, fates_string_length) ; + fates_alloc_organ_name:units = "unitless - string" ; + fates_alloc_organ_name:long_name = "Name of plant organs (with alloc_organ_id, must match PRTGenericMod.F90)" ; + char fates_landuseclass_name(fates_landuseclass, fates_string_length) ; + fates_landuseclass_name:units = "unitless - string" ; + fates_landuseclass_name:long_name = "Name of the land use classes, for variables associated with dimension fates_landuseclass" ; + char fates_litterclass_name(fates_litterclass, fates_string_length) ; + fates_litterclass_name:units = "unitless - string" ; + fates_litterclass_name:long_name = "Name of the litter classes, for variables associated with dimension fates_litterclass" ; + double fates_alloc_organ_priority(fates_plant_organs, fates_pft) ; + fates_alloc_organ_priority:units = "index" ; + fates_alloc_organ_priority:long_name = "Priority level for allocation, 1: replaces turnover from storage, 2: same priority as storage use/replacement, 3: ascending in order of least importance" ; + double fates_alloc_storage_cushion(fates_pft) ; + fates_alloc_storage_cushion:units = "fraction" ; + fates_alloc_storage_cushion:long_name = "maximum size of storage C pool, relative to maximum size of leaf C pool" ; + double fates_alloc_store_priority_frac(fates_pft) ; + fates_alloc_store_priority_frac:units = "unitless" ; + fates_alloc_store_priority_frac:long_name = "for high-priority organs, the fraction of their turnover demand that is gauranteed to be replaced, and if need-be by storage" ; + double fates_allom_agb1(fates_pft) ; + fates_allom_agb1:units = "variable" ; + fates_allom_agb1:long_name = "Parameter 1 for agb allometry" ; + double fates_allom_agb2(fates_pft) ; + fates_allom_agb2:units = "variable" ; + fates_allom_agb2:long_name = "Parameter 2 for agb allometry" ; + double fates_allom_agb3(fates_pft) ; + fates_allom_agb3:units = "variable" ; + fates_allom_agb3:long_name = "Parameter 3 for agb allometry" ; + double fates_allom_agb4(fates_pft) ; + fates_allom_agb4:units = "variable" ; + fates_allom_agb4:long_name = "Parameter 4 for agb allometry" ; + double fates_allom_agb_frac(fates_pft) ; + fates_allom_agb_frac:units = "fraction" ; + fates_allom_agb_frac:long_name = "Fraction of woody biomass that is above ground" ; + double fates_allom_amode(fates_pft) ; + fates_allom_amode:units = "index" ; + fates_allom_amode:long_name = "AGB allometry function index." ; + double fates_allom_blca_expnt_diff(fates_pft) ; + fates_allom_blca_expnt_diff:units = "unitless" ; + fates_allom_blca_expnt_diff:long_name = "difference between allometric DBH:bleaf and DBH:crown area exponents" ; + double fates_allom_cmode(fates_pft) ; + fates_allom_cmode:units = "index" ; + fates_allom_cmode:long_name = "coarse root biomass allometry function index." ; + double fates_allom_crown_depth_frac(fates_pft) ; + fates_allom_crown_depth_frac:units = "fraction" ; + fates_allom_crown_depth_frac:long_name = "the depth of a cohort crown as a fraction of its height" ; + double fates_allom_d2bl1(fates_pft) ; + fates_allom_d2bl1:units = "variable" ; + fates_allom_d2bl1:long_name = "Parameter 1 for d2bl allometry" ; + double fates_allom_d2bl2(fates_pft) ; + fates_allom_d2bl2:units = "variable" ; + fates_allom_d2bl2:long_name = "Parameter 2 for d2bl allometry" ; + double fates_allom_d2bl3(fates_pft) ; + fates_allom_d2bl3:units = "unitless" ; + fates_allom_d2bl3:long_name = "Parameter 3 for d2bl allometry" ; + double fates_allom_d2ca_coefficient_max(fates_pft) ; + fates_allom_d2ca_coefficient_max:units = "m2 cm^(-1/beta)" ; + fates_allom_d2ca_coefficient_max:long_name = "max (savanna) dbh to area multiplier factor where: area = n*d2ca_coeff*dbh^beta" ; + double fates_allom_d2ca_coefficient_min(fates_pft) ; + fates_allom_d2ca_coefficient_min:units = "m2 cm^(-1/beta)" ; + fates_allom_d2ca_coefficient_min:long_name = "min (forest) dbh to area multiplier factor where: area = n*d2ca_coeff*dbh^beta" ; + double fates_allom_d2h1(fates_pft) ; + fates_allom_d2h1:units = "variable" ; + fates_allom_d2h1:long_name = "Parameter 1 for d2h allometry (intercept, or c)" ; + double fates_allom_d2h2(fates_pft) ; + fates_allom_d2h2:units = "variable" ; + fates_allom_d2h2:long_name = "Parameter 2 for d2h allometry (slope, or m)" ; + double fates_allom_d2h3(fates_pft) ; + fates_allom_d2h3:units = "variable" ; + fates_allom_d2h3:long_name = "Parameter 3 for d2h allometry (optional)" ; + double fates_allom_dbh_maxheight(fates_pft) ; + fates_allom_dbh_maxheight:units = "cm" ; + fates_allom_dbh_maxheight:long_name = "the diameter (if any) corresponding to maximum height, diameters may increase beyond this" ; + double fates_allom_fmode(fates_pft) ; + fates_allom_fmode:units = "index" ; + fates_allom_fmode:long_name = "fine root biomass allometry function index." ; + double fates_allom_fnrt_prof_a(fates_pft) ; + fates_allom_fnrt_prof_a:units = "unitless" ; + fates_allom_fnrt_prof_a:long_name = "Fine root profile function, parameter a" ; + double fates_allom_fnrt_prof_b(fates_pft) ; + fates_allom_fnrt_prof_b:units = "unitless" ; + fates_allom_fnrt_prof_b:long_name = "Fine root profile function, parameter b" ; + double fates_allom_fnrt_prof_mode(fates_pft) ; + fates_allom_fnrt_prof_mode:units = "index" ; + fates_allom_fnrt_prof_mode:long_name = "Index to select fine root profile function: 1) Jackson Beta, 2) 1-param exponential 3) 2-param exponential" ; + double fates_allom_frbstor_repro(fates_pft) ; + fates_allom_frbstor_repro:units = "fraction" ; + fates_allom_frbstor_repro:long_name = "fraction of bstore goes to reproduction after plant dies" ; + double fates_allom_hmode(fates_pft) ; + fates_allom_hmode:units = "index" ; + fates_allom_hmode:long_name = "height allometry function index." ; + double fates_allom_l2fr(fates_pft) ; + fates_allom_l2fr:units = "gC/gC" ; + fates_allom_l2fr:long_name = "Allocation parameter: fine root C per leaf C" ; + double fates_allom_la_per_sa_int(fates_pft) ; + fates_allom_la_per_sa_int:units = "m2/cm2" ; + fates_allom_la_per_sa_int:long_name = "Leaf area per sapwood area, intercept" ; + double fates_allom_la_per_sa_slp(fates_pft) ; + fates_allom_la_per_sa_slp:units = "m2/cm2/m" ; + fates_allom_la_per_sa_slp:long_name = "Leaf area per sapwood area rate of change with height, slope (optional)" ; + double fates_allom_lmode(fates_pft) ; + fates_allom_lmode:units = "index" ; + fates_allom_lmode:long_name = "leaf biomass allometry function index." ; + double fates_allom_sai_scaler(fates_pft) ; + fates_allom_sai_scaler:units = "m2/m2" ; + fates_allom_sai_scaler:long_name = "allometric ratio of SAI per LAI" ; + double fates_allom_smode(fates_pft) ; + fates_allom_smode:units = "index" ; + fates_allom_smode:long_name = "sapwood allometry function index." ; + double fates_allom_stmode(fates_pft) ; + fates_allom_stmode:units = "index" ; + fates_allom_stmode:long_name = "storage allometry function index: 1) Storage proportional to leaf biomass (with trimming), 2) Storage proportional to maximum leaf biomass (not trimmed)" ; + double fates_allom_zroot_k(fates_pft) ; + fates_allom_zroot_k:units = "unitless" ; + fates_allom_zroot_k:long_name = "scale coefficient of logistic rooting depth model" ; + double fates_allom_zroot_max_dbh(fates_pft) ; + fates_allom_zroot_max_dbh:units = "cm" ; + fates_allom_zroot_max_dbh:long_name = "dbh at which a plant reaches the maximum value for its maximum rooting depth" ; + double fates_allom_zroot_max_z(fates_pft) ; + fates_allom_zroot_max_z:units = "m" ; + fates_allom_zroot_max_z:long_name = "the maximum rooting depth defined at dbh = fates_allom_zroot_max_dbh. note: max_z=min_z=large, sets rooting depth to soil depth" ; + double fates_allom_zroot_min_dbh(fates_pft) ; + fates_allom_zroot_min_dbh:units = "cm" ; + fates_allom_zroot_min_dbh:long_name = "dbh at which the maximum rooting depth for a recruit is defined" ; + double fates_allom_zroot_min_z(fates_pft) ; + fates_allom_zroot_min_z:units = "m" ; + fates_allom_zroot_min_z:long_name = "the maximum rooting depth defined at dbh = fates_allom_zroot_min_dbh. note: max_z=min_z=large, sets rooting depth to soil depth" ; + double fates_c2b(fates_pft) ; + fates_c2b:units = "ratio" ; + fates_c2b:long_name = "Carbon to biomass multiplier of bulk structural tissues" ; + double fates_cnp_eca_alpha_ptase(fates_pft) ; + fates_cnp_eca_alpha_ptase:units = "g/m3" ; + fates_cnp_eca_alpha_ptase:long_name = "fraction of P from ptase activity sent directly to plant (ECA)" ; + double fates_cnp_eca_decompmicc(fates_pft) ; + fates_cnp_eca_decompmicc:units = "gC/m3" ; + fates_cnp_eca_decompmicc:long_name = "maximum soil microbial decomposer biomass found over depth (will be applied at a reference depth w/ exponential attenuation) (ECA)" ; + double fates_cnp_eca_km_nh4(fates_pft) ; + fates_cnp_eca_km_nh4:units = "gN/m3" ; + fates_cnp_eca_km_nh4:long_name = "half-saturation constant for plant nh4 uptake (ECA)" ; + double fates_cnp_eca_km_no3(fates_pft) ; + fates_cnp_eca_km_no3:units = "gN/m3" ; + fates_cnp_eca_km_no3:long_name = "half-saturation constant for plant no3 uptake (ECA)" ; + double fates_cnp_eca_km_p(fates_pft) ; + fates_cnp_eca_km_p:units = "gP/m3" ; + fates_cnp_eca_km_p:long_name = "half-saturation constant for plant p uptake (ECA)" ; + double fates_cnp_eca_km_ptase(fates_pft) ; + fates_cnp_eca_km_ptase:units = "gP/m3" ; + fates_cnp_eca_km_ptase:long_name = "half-saturation constant for biochemical P (ECA)" ; + double fates_cnp_eca_lambda_ptase(fates_pft) ; + fates_cnp_eca_lambda_ptase:units = "g/m3" ; + fates_cnp_eca_lambda_ptase:long_name = "critical value for biochemical production (ECA)" ; + double fates_cnp_eca_vmax_ptase(fates_pft) ; + fates_cnp_eca_vmax_ptase:units = "gP/m2/s" ; + fates_cnp_eca_vmax_ptase:long_name = "maximum production rate for biochemical P (per m2) (ECA)" ; + double fates_cnp_nfix1(fates_pft) ; + fates_cnp_nfix1:units = "fraction" ; + fates_cnp_nfix1:long_name = "fractional surcharge added to maintenance respiration that drives symbiotic fixation" ; + double fates_cnp_nitr_store_ratio(fates_pft) ; + fates_cnp_nitr_store_ratio:units = "(gN/gN)" ; + fates_cnp_nitr_store_ratio:long_name = "storeable (labile) N, as a ratio compared to the N bound in cell structures of other organs (see code)" ; + double fates_cnp_phos_store_ratio(fates_pft) ; + fates_cnp_phos_store_ratio:units = "(gP/gP)" ; + fates_cnp_phos_store_ratio:long_name = "storeable (labile) P, as a ratio compared to the P bound in cell structures of other organs (see code)" ; + double fates_cnp_pid_kd(fates_pft) ; + fates_cnp_pid_kd:units = "unknown" ; + fates_cnp_pid_kd:long_name = "derivative constant of the PID controller on adaptive fine-root biomass" ; + double fates_cnp_pid_ki(fates_pft) ; + fates_cnp_pid_ki:units = "unknown" ; + fates_cnp_pid_ki:long_name = "integral constant of the PID controller on adaptive fine-root biomass" ; + double fates_cnp_pid_kp(fates_pft) ; + fates_cnp_pid_kp:units = "unknown" ; + fates_cnp_pid_kp:long_name = "proportional constant of the PID controller on adaptive fine-root biomass" ; + double fates_cnp_prescribed_nuptake(fates_pft) ; + fates_cnp_prescribed_nuptake:units = "fraction" ; + fates_cnp_prescribed_nuptake:long_name = "Prescribed N uptake flux. 0=fully coupled simulation >0=prescribed (experimental)" ; + double fates_cnp_prescribed_puptake(fates_pft) ; + fates_cnp_prescribed_puptake:units = "fraction" ; + fates_cnp_prescribed_puptake:long_name = "Prescribed P uptake flux. 0=fully coupled simulation, >0=prescribed (experimental)" ; + double fates_cnp_store_ovrflw_frac(fates_pft) ; + fates_cnp_store_ovrflw_frac:units = "fraction" ; + fates_cnp_store_ovrflw_frac:long_name = "size of overflow storage (for excess C,N or P) as a fraction of storage target" ; + double fates_cnp_turnover_nitr_retrans(fates_plant_organs, fates_pft) ; + fates_cnp_turnover_nitr_retrans:units = "fraction" ; + fates_cnp_turnover_nitr_retrans:long_name = "retranslocation (reabsorbtion) fraction of nitrogen in turnover of scenescing tissues" ; + double fates_cnp_turnover_phos_retrans(fates_plant_organs, fates_pft) ; + fates_cnp_turnover_phos_retrans:units = "fraction" ; + fates_cnp_turnover_phos_retrans:long_name = "retranslocation (reabsorbtion) fraction of phosphorus in turnover of scenescing tissues" ; + double fates_cnp_vmax_nh4(fates_pft) ; + fates_cnp_vmax_nh4:units = "gN/gC/s" ; + fates_cnp_vmax_nh4:long_name = "maximum (potential) uptake rate of NH4 per gC of fineroot biomass (see main/EDPftvarcon.F90 vmax_nh4 for usage)" ; + double fates_cnp_vmax_no3(fates_pft) ; + fates_cnp_vmax_no3:units = "gN/gC/s" ; + fates_cnp_vmax_no3:long_name = "maximum (potential) uptake rate of NO3 per gC of fineroot biomass (see main/EDPftvarcon.F90 vmax_no3 for usage)" ; + double fates_cnp_vmax_p(fates_pft) ; + fates_cnp_vmax_p:units = "gP/gC/s" ; + fates_cnp_vmax_p:long_name = "maximum production rate for phosphorus (ECA and RD)" ; + double fates_damage_frac(fates_pft) ; + fates_damage_frac:units = "fraction" ; + fates_damage_frac:long_name = "fraction of cohort damaged in each damage event (event frequency specified in the is_it_damage_time subroutine)" ; + double fates_damage_mort_p1(fates_pft) ; + fates_damage_mort_p1:units = "fraction" ; + fates_damage_mort_p1:long_name = "inflection point of damage mortality function, a value of 0.8 means 50% mortality with 80% loss of crown, turn off with a large number" ; + double fates_damage_mort_p2(fates_pft) ; + fates_damage_mort_p2:units = "unitless" ; + fates_damage_mort_p2:long_name = "rate of mortality increase with damage" ; + double fates_damage_recovery_scalar(fates_pft) ; + fates_damage_recovery_scalar:units = "unitless" ; + fates_damage_recovery_scalar:long_name = "fraction of the cohort that recovers from damage" ; + double fates_dev_arbitrary_pft(fates_pft) ; + fates_dev_arbitrary_pft:units = "unknown" ; + fates_dev_arbitrary_pft:long_name = "Unassociated pft dimensioned free parameter that developers can use for testing arbitrary new hypotheses" ; + double fates_fire_alpha_SH(fates_pft) ; + fates_fire_alpha_SH:units = "m / (kw/m)**(2/3)" ; + fates_fire_alpha_SH:long_name = "spitfire parameter, alpha scorch height, Equation 16 Thonicke et al 2010" ; + double fates_fire_bark_scaler(fates_pft) ; + fates_fire_bark_scaler:units = "fraction" ; + fates_fire_bark_scaler:long_name = "the thickness of a cohorts bark as a fraction of its dbh" ; + double fates_fire_crown_kill(fates_pft) ; + fates_fire_crown_kill:units = "NA" ; + fates_fire_crown_kill:long_name = "fire parameter, see equation 22 in Thonicke et al 2010" ; + double fates_frag_fnrt_fcel(fates_pft) ; + fates_frag_fnrt_fcel:units = "fraction" ; + fates_frag_fnrt_fcel:long_name = "Fine root litter cellulose fraction" ; + double fates_frag_fnrt_flab(fates_pft) ; + fates_frag_fnrt_flab:units = "fraction" ; + fates_frag_fnrt_flab:long_name = "Fine root litter labile fraction" ; + double fates_frag_fnrt_flig(fates_pft) ; + fates_frag_fnrt_flig:units = "fraction" ; + fates_frag_fnrt_flig:long_name = "Fine root litter lignin fraction" ; + double fates_frag_leaf_fcel(fates_pft) ; + fates_frag_leaf_fcel:units = "fraction" ; + fates_frag_leaf_fcel:long_name = "Leaf litter cellulose fraction" ; + double fates_frag_leaf_flab(fates_pft) ; + fates_frag_leaf_flab:units = "fraction" ; + fates_frag_leaf_flab:long_name = "Leaf litter labile fraction" ; + double fates_frag_leaf_flig(fates_pft) ; + fates_frag_leaf_flig:units = "fraction" ; + fates_frag_leaf_flig:long_name = "Leaf litter lignin fraction" ; + double fates_frag_seed_decay_rate(fates_pft) ; + fates_frag_seed_decay_rate:units = "yr-1" ; + fates_frag_seed_decay_rate:long_name = "fraction of seeds that decay per year" ; + double fates_grperc(fates_pft) ; + fates_grperc:units = "unitless" ; + fates_grperc:long_name = "Growth respiration factor" ; + double fates_hydro_avuln_gs(fates_pft) ; + fates_hydro_avuln_gs:units = "unitless" ; + fates_hydro_avuln_gs:long_name = "shape parameter for stomatal control of water vapor exiting leaf" ; + double fates_hydro_avuln_node(fates_hydr_organs, fates_pft) ; + fates_hydro_avuln_node:units = "unitless" ; + fates_hydro_avuln_node:long_name = "xylem vulnerability curve shape parameter" ; + double fates_hydro_epsil_node(fates_hydr_organs, fates_pft) ; + fates_hydro_epsil_node:units = "MPa" ; + fates_hydro_epsil_node:long_name = "bulk elastic modulus" ; + double fates_hydro_fcap_node(fates_hydr_organs, fates_pft) ; + fates_hydro_fcap_node:units = "unitless" ; + fates_hydro_fcap_node:long_name = "fraction of non-residual water that is capillary in source" ; + double fates_hydro_k_lwp(fates_pft) ; + fates_hydro_k_lwp:units = "unitless" ; + fates_hydro_k_lwp:long_name = "inner leaf humidity scaling coefficient" ; + double fates_hydro_kmax_node(fates_hydr_organs, fates_pft) ; + fates_hydro_kmax_node:units = "kg/MPa/m/s" ; + fates_hydro_kmax_node:long_name = "maximum xylem conductivity per unit conducting xylem area" ; + double fates_hydro_p50_gs(fates_pft) ; + fates_hydro_p50_gs:units = "MPa" ; + fates_hydro_p50_gs:long_name = "water potential at 50% loss of stomatal conductance" ; + double fates_hydro_p50_node(fates_hydr_organs, fates_pft) ; + fates_hydro_p50_node:units = "MPa" ; + fates_hydro_p50_node:long_name = "xylem water potential at 50% loss of conductivity" ; + double fates_hydro_p_taper(fates_pft) ; + fates_hydro_p_taper:units = "unitless" ; + fates_hydro_p_taper:long_name = "xylem taper exponent" ; + double fates_hydro_pinot_node(fates_hydr_organs, fates_pft) ; + fates_hydro_pinot_node:units = "MPa" ; + fates_hydro_pinot_node:long_name = "osmotic potential at full turgor" ; + double fates_hydro_pitlp_node(fates_hydr_organs, fates_pft) ; + fates_hydro_pitlp_node:units = "MPa" ; + fates_hydro_pitlp_node:long_name = "turgor loss point" ; + double fates_hydro_resid_node(fates_hydr_organs, fates_pft) ; + fates_hydro_resid_node:units = "cm3/cm3" ; + fates_hydro_resid_node:long_name = "residual water conent" ; + double fates_hydro_rfrac_stem(fates_pft) ; + fates_hydro_rfrac_stem:units = "fraction" ; + fates_hydro_rfrac_stem:long_name = "fraction of total tree resistance from troot to canopy" ; + double fates_hydro_rs2(fates_pft) ; + fates_hydro_rs2:units = "m" ; + fates_hydro_rs2:long_name = "absorbing root radius" ; + double fates_hydro_srl(fates_pft) ; + fates_hydro_srl:units = "m g-1" ; + fates_hydro_srl:long_name = "specific root length" ; + double fates_hydro_thetas_node(fates_hydr_organs, fates_pft) ; + fates_hydro_thetas_node:units = "cm3/cm3" ; + fates_hydro_thetas_node:long_name = "saturated water content" ; + double fates_hydro_vg_alpha_node(fates_hydr_organs, fates_pft) ; + fates_hydro_vg_alpha_node:units = "MPa-1" ; + fates_hydro_vg_alpha_node:long_name = "(used if hydr_htftype_node = 2), capillary length parameter in van Genuchten model" ; + double fates_hydro_vg_m_node(fates_hydr_organs, fates_pft) ; + fates_hydro_vg_m_node:units = "unitless" ; + fates_hydro_vg_m_node:long_name = "(used if hydr_htftype_node = 2),m in van Genuchten 1980 model, 2nd pore size distribution parameter" ; + double fates_hydro_vg_n_node(fates_hydr_organs, fates_pft) ; + fates_hydro_vg_n_node:units = "unitless" ; + fates_hydro_vg_n_node:long_name = "(used if hydr_htftype_node = 2),n in van Genuchten 1980 model, pore size distribution parameter" ; + double fates_leaf_c3psn(fates_pft) ; + fates_leaf_c3psn:units = "flag" ; + fates_leaf_c3psn:long_name = "Photosynthetic pathway (1=c3, 0=c4)" ; + double fates_leaf_jmaxha(fates_pft) ; + fates_leaf_jmaxha:units = "J/mol" ; + fates_leaf_jmaxha:long_name = "activation energy for jmax. NOTE: if fates_leaf_photo_tempsens_model=2 then these values are NOT USED" ; + double fates_leaf_jmaxhd(fates_pft) ; + fates_leaf_jmaxhd:units = "J/mol" ; + fates_leaf_jmaxhd:long_name = "deactivation energy for jmax. NOTE: if fates_leaf_photo_tempsens_model=2 then these values are NOT USED" ; + double fates_leaf_jmaxse(fates_pft) ; + fates_leaf_jmaxse:units = "J/mol/K" ; + fates_leaf_jmaxse:long_name = "entropy term for jmax. NOTE: if fates_leaf_photo_tempsens_model=2 then these values are NOT USED" ; + double fates_leaf_slamax(fates_pft) ; + fates_leaf_slamax:units = "m^2/gC" ; + fates_leaf_slamax:long_name = "Maximum Specific Leaf Area (SLA), even if under a dense canopy" ; + double fates_leaf_slatop(fates_pft) ; + fates_leaf_slatop:units = "m^2/gC" ; + fates_leaf_slatop:long_name = "Specific Leaf Area (SLA) at top of canopy, projected area basis" ; + double fates_leaf_stomatal_intercept(fates_pft) ; + fates_leaf_stomatal_intercept:units = "umol H2O/m**2/s" ; + fates_leaf_stomatal_intercept:long_name = "Minimum unstressed stomatal conductance for Ball-Berry model and Medlyn model" ; + double fates_leaf_stomatal_slope_ballberry(fates_pft) ; + fates_leaf_stomatal_slope_ballberry:units = "unitless" ; + fates_leaf_stomatal_slope_ballberry:long_name = "stomatal slope parameter, as per Ball-Berry" ; + double fates_leaf_stomatal_slope_medlyn(fates_pft) ; + fates_leaf_stomatal_slope_medlyn:units = "KPa**0.5" ; + fates_leaf_stomatal_slope_medlyn:long_name = "stomatal slope parameter, as per Medlyn" ; + double fates_leaf_vcmax25top(fates_leafage_class, fates_pft) ; + fates_leaf_vcmax25top:units = "umol CO2/m^2/s" ; + fates_leaf_vcmax25top:long_name = "maximum carboxylation rate of Rub. at 25C, canopy top" ; + double fates_leaf_vcmaxha(fates_pft) ; + fates_leaf_vcmaxha:units = "J/mol" ; + fates_leaf_vcmaxha:long_name = "activation energy for vcmax. NOTE: if fates_leaf_photo_tempsens_model=2 then these values are NOT USED" ; + double fates_leaf_vcmaxhd(fates_pft) ; + fates_leaf_vcmaxhd:units = "J/mol" ; + fates_leaf_vcmaxhd:long_name = "deactivation energy for vcmax. NOTE: if fates_leaf_photo_tempsens_model=2 then these values are NOT USED" ; + double fates_leaf_vcmaxse(fates_pft) ; + fates_leaf_vcmaxse:units = "J/mol/K" ; + fates_leaf_vcmaxse:long_name = "entropy term for vcmax. NOTE: if fates_leaf_photo_tempsens_model=2 then these values are NOT USED" ; + double fates_maintresp_leaf_atkin2017_baserate(fates_pft) ; + fates_maintresp_leaf_atkin2017_baserate:units = "umol CO2/m^2/s" ; + fates_maintresp_leaf_atkin2017_baserate:long_name = "Leaf maintenance respiration base rate parameter (r0) per Atkin et al 2017" ; + double fates_maintresp_leaf_ryan1991_baserate(fates_pft) ; + fates_maintresp_leaf_ryan1991_baserate:units = "gC/gN/s" ; + fates_maintresp_leaf_ryan1991_baserate:long_name = "Leaf maintenance respiration base rate per Ryan et al 1991" ; + double fates_maintresp_reduction_curvature(fates_pft) ; + fates_maintresp_reduction_curvature:units = "unitless (0-1)" ; + fates_maintresp_reduction_curvature:long_name = "curvature of MR reduction as f(carbon storage), 1=linear, 0=very curved" ; + double fates_maintresp_reduction_intercept(fates_pft) ; + fates_maintresp_reduction_intercept:units = "unitless (0-1)" ; + fates_maintresp_reduction_intercept:long_name = "intercept of MR reduction as f(carbon storage), 0=no throttling, 1=max throttling" ; + double fates_maintresp_reduction_upthresh(fates_pft) ; + fates_maintresp_reduction_upthresh:units = "unitless (0-1)" ; + fates_maintresp_reduction_upthresh:long_name = "upper threshold for storage biomass (relative to leaf biomass) above which MR is not reduced" ; + double fates_mort_bmort(fates_pft) ; + fates_mort_bmort:units = "1/yr" ; + fates_mort_bmort:long_name = "background mortality rate" ; + double fates_mort_freezetol(fates_pft) ; + fates_mort_freezetol:units = "degrees C" ; + fates_mort_freezetol:long_name = "minimum temperature tolerance" ; + double fates_mort_hf_flc_threshold(fates_pft) ; + fates_mort_hf_flc_threshold:units = "fraction" ; + fates_mort_hf_flc_threshold:long_name = "plant fractional loss of conductivity at which drought mortality begins for hydraulic model" ; + double fates_mort_hf_sm_threshold(fates_pft) ; + fates_mort_hf_sm_threshold:units = "unitless" ; + fates_mort_hf_sm_threshold:long_name = "soil moisture (btran units) at which drought mortality begins for non-hydraulic model" ; + double fates_mort_ip_age_senescence(fates_pft) ; + fates_mort_ip_age_senescence:units = "years" ; + fates_mort_ip_age_senescence:long_name = "Mortality cohort age senescence inflection point. If _ this mortality term is off. Setting this value turns on age dependent mortality. " ; + double fates_mort_ip_size_senescence(fates_pft) ; + fates_mort_ip_size_senescence:units = "dbh cm" ; + fates_mort_ip_size_senescence:long_name = "Mortality dbh senescence inflection point. If _ this mortality term is off. Setting this value turns on size dependent mortality" ; + double fates_mort_prescribed_canopy(fates_pft) ; + fates_mort_prescribed_canopy:units = "1/yr" ; + fates_mort_prescribed_canopy:long_name = "mortality rate of canopy trees for prescribed physiology mode" ; + double fates_mort_prescribed_understory(fates_pft) ; + fates_mort_prescribed_understory:units = "1/yr" ; + fates_mort_prescribed_understory:long_name = "mortality rate of understory trees for prescribed physiology mode" ; + double fates_mort_r_age_senescence(fates_pft) ; + fates_mort_r_age_senescence:units = "mortality rate year^-1" ; + fates_mort_r_age_senescence:long_name = "Mortality age senescence rate of change. Sensible range is around 0.03-0.06. Larger values givesteeper mortality curves." ; + double fates_mort_r_size_senescence(fates_pft) ; + fates_mort_r_size_senescence:units = "mortality rate dbh^-1" ; + fates_mort_r_size_senescence:long_name = "Mortality dbh senescence rate of change. Sensible range is around 0.03-0.06. Larger values give steeper mortality curves." ; + double fates_mort_scalar_coldstress(fates_pft) ; + fates_mort_scalar_coldstress:units = "1/yr" ; + fates_mort_scalar_coldstress:long_name = "maximum mortality rate from cold stress" ; + double fates_mort_scalar_cstarvation(fates_pft) ; + fates_mort_scalar_cstarvation:units = "1/yr" ; + fates_mort_scalar_cstarvation:long_name = "maximum mortality rate from carbon starvation" ; + double fates_mort_scalar_hydrfailure(fates_pft) ; + fates_mort_scalar_hydrfailure:units = "1/yr" ; + fates_mort_scalar_hydrfailure:long_name = "maximum mortality rate from hydraulic failure" ; + double fates_mort_upthresh_cstarvation(fates_pft) ; + fates_mort_upthresh_cstarvation:units = "unitless" ; + fates_mort_upthresh_cstarvation:long_name = "threshold for storage biomass (relative to target leaf biomass) above which carbon starvation is zero" ; + double fates_nonhydro_smpsc(fates_pft) ; + fates_nonhydro_smpsc:units = "mm" ; + fates_nonhydro_smpsc:long_name = "Soil water potential at full stomatal closure" ; + double fates_nonhydro_smpso(fates_pft) ; + fates_nonhydro_smpso:units = "mm" ; + fates_nonhydro_smpso:long_name = "Soil water potential at full stomatal opening" ; + double fates_phen_cold_size_threshold(fates_pft) ; + fates_phen_cold_size_threshold:units = "cm" ; + fates_phen_cold_size_threshold:long_name = "the dbh size above which will lead to phenology-related stem and leaf drop" ; + double fates_phen_drought_threshold(fates_pft) ; + fates_phen_drought_threshold:units = "m3/m3 or mm" ; + fates_phen_drought_threshold:long_name = "threshold for drought phenology (or lower threshold for semi-deciduous PFTs); the quantity depends on the sign: if positive, the threshold is volumetric soil moisture (m3/m3). If negative, the threshold is soil matric potentical (mm)" ; + double fates_phen_evergreen(fates_pft) ; + fates_phen_evergreen:units = "logical flag" ; + fates_phen_evergreen:long_name = "Binary flag for evergreen leaf habit" ; + double fates_phen_flush_fraction(fates_pft) ; + fates_phen_flush_fraction:units = "fraction" ; + fates_phen_flush_fraction:long_name = "Upon bud-burst, the maximum fraction of storage carbon used for flushing leaves" ; + double fates_phen_fnrt_drop_fraction(fates_pft) ; + fates_phen_fnrt_drop_fraction:units = "fraction" ; + fates_phen_fnrt_drop_fraction:long_name = "fraction of fine roots to drop during drought/cold" ; + double fates_phen_mindaysoff(fates_pft) ; + fates_phen_mindaysoff:units = "days" ; + fates_phen_mindaysoff:long_name = "day threshold compared against days since leaves abscised (shed)" ; + double fates_phen_moist_threshold(fates_pft) ; + fates_phen_moist_threshold:units = "m3/m3 or mm" ; + fates_phen_moist_threshold:long_name = "upper threshold for drought phenology (only for drought semi-deciduous PFTs); the quantity depends on the sign: if positive, the threshold is volumetric soil moisture (m3/m3). If negative, the threshold is soil matric potentical (mm)" ; + double fates_phen_season_decid(fates_pft) ; + fates_phen_season_decid:units = "logical flag" ; + fates_phen_season_decid:long_name = "Binary flag for seasonal-deciduous leaf habit" ; + double fates_phen_stem_drop_fraction(fates_pft) ; + fates_phen_stem_drop_fraction:units = "fraction" ; + fates_phen_stem_drop_fraction:long_name = "fraction of stems to drop for non-woody species during drought/cold" ; + double fates_phen_stress_decid(fates_pft) ; + fates_phen_stress_decid:units = "logical flag" ; + fates_phen_stress_decid:long_name = "Flag for stress/drought-deciduous leaf habit. 0 - not stress deciduous; 1 - default drought deciduous (two target states only, fully flushed or fully abscised); 2 - semi-deciduous" ; + double fates_prescribed_npp_canopy(fates_pft) ; + fates_prescribed_npp_canopy:units = "kgC / m^2 / yr" ; + fates_prescribed_npp_canopy:long_name = "NPP per unit crown area of canopy trees for prescribed physiology mode" ; + double fates_prescribed_npp_understory(fates_pft) ; + fates_prescribed_npp_understory:units = "kgC / m^2 / yr" ; + fates_prescribed_npp_understory:long_name = "NPP per unit crown area of understory trees for prescribed physiology mode" ; + double fates_rad_leaf_clumping_index(fates_pft) ; + fates_rad_leaf_clumping_index:units = "fraction (0-1)" ; + fates_rad_leaf_clumping_index:long_name = "factor describing how much self-occlusion of leaf scattering elements decreases light interception" ; + double fates_rad_leaf_rhonir(fates_pft) ; + fates_rad_leaf_rhonir:units = "fraction" ; + fates_rad_leaf_rhonir:long_name = "Leaf reflectance: near-IR" ; + double fates_rad_leaf_rhovis(fates_pft) ; + fates_rad_leaf_rhovis:units = "fraction" ; + fates_rad_leaf_rhovis:long_name = "Leaf reflectance: visible" ; + double fates_rad_leaf_taunir(fates_pft) ; + fates_rad_leaf_taunir:units = "fraction" ; + fates_rad_leaf_taunir:long_name = "Leaf transmittance: near-IR" ; + double fates_rad_leaf_tauvis(fates_pft) ; + fates_rad_leaf_tauvis:units = "fraction" ; + fates_rad_leaf_tauvis:long_name = "Leaf transmittance: visible" ; + double fates_rad_leaf_xl(fates_pft) ; + fates_rad_leaf_xl:units = "unitless" ; + fates_rad_leaf_xl:long_name = "Leaf/stem orientation index" ; + double fates_rad_stem_rhonir(fates_pft) ; + fates_rad_stem_rhonir:units = "fraction" ; + fates_rad_stem_rhonir:long_name = "Stem reflectance: near-IR" ; + double fates_rad_stem_rhovis(fates_pft) ; + fates_rad_stem_rhovis:units = "fraction" ; + fates_rad_stem_rhovis:long_name = "Stem reflectance: visible" ; + double fates_rad_stem_taunir(fates_pft) ; + fates_rad_stem_taunir:units = "fraction" ; + fates_rad_stem_taunir:long_name = "Stem transmittance: near-IR" ; + double fates_rad_stem_tauvis(fates_pft) ; + fates_rad_stem_tauvis:units = "fraction" ; + fates_rad_stem_tauvis:long_name = "Stem transmittance: visible" ; + double fates_recruit_height_min(fates_pft) ; + fates_recruit_height_min:units = "m" ; + fates_recruit_height_min:long_name = "the minimum height (ie starting height) of a newly recruited plant" ; + double fates_recruit_init_density(fates_pft) ; + fates_recruit_init_density:units = "stems/m2" ; + fates_recruit_init_density:long_name = "initial seedling density for a cold-start near-bare-ground simulation. If negative sets initial tree dbh - only to be used in nocomp mode" ; + double fates_recruit_prescribed_rate(fates_pft) ; + fates_recruit_prescribed_rate:units = "n/yr" ; + fates_recruit_prescribed_rate:long_name = "recruitment rate for prescribed physiology mode" ; + double fates_recruit_seed_alloc(fates_pft) ; + fates_recruit_seed_alloc:units = "fraction" ; + fates_recruit_seed_alloc:long_name = "fraction of available carbon balance allocated to seeds" ; + double fates_recruit_seed_alloc_mature(fates_pft) ; + fates_recruit_seed_alloc_mature:units = "fraction" ; + fates_recruit_seed_alloc_mature:long_name = "fraction of available carbon balance allocated to seeds in mature plants (adds to fates_seed_alloc)" ; + double fates_recruit_seed_dbh_repro_threshold(fates_pft) ; + fates_recruit_seed_dbh_repro_threshold:units = "cm" ; + fates_recruit_seed_dbh_repro_threshold:long_name = "the diameter where the plant will increase allocation to the seed pool by fraction: fates_recruit_seed_alloc_mature" ; + double fates_recruit_seed_germination_rate(fates_pft) ; + fates_recruit_seed_germination_rate:units = "yr-1" ; + fates_recruit_seed_germination_rate:long_name = "fraction of seeds that germinate per year" ; + double fates_recruit_seed_supplement(fates_pft) ; + fates_recruit_seed_supplement:units = "KgC/m2/yr" ; + fates_recruit_seed_supplement:long_name = "Supplemental external seed rain source term (non-mass conserving)" ; + double fates_seed_dispersal_fraction(fates_pft) ; + fates_seed_dispersal_fraction:units = "fraction" ; + fates_seed_dispersal_fraction:long_name = "fraction of seed rain to be dispersed to other grid cells" ; + double fates_seed_dispersal_max_dist(fates_pft) ; + fates_seed_dispersal_max_dist:units = "m" ; + fates_seed_dispersal_max_dist:long_name = "maximum seed dispersal distance for a given pft" ; + double fates_seed_dispersal_pdf_scale(fates_pft) ; + fates_seed_dispersal_pdf_scale:units = "unitless" ; + fates_seed_dispersal_pdf_scale:long_name = "seed dispersal probability density function scale parameter, A, Table 1 Bullock et al 2016" ; + double fates_seed_dispersal_pdf_shape(fates_pft) ; + fates_seed_dispersal_pdf_shape:units = "unitless" ; + fates_seed_dispersal_pdf_shape:long_name = "seed dispersal probability density function shape parameter, B, Table 1 Bullock et al 2016" ; + double fates_stoich_nitr(fates_plant_organs, fates_pft) ; + fates_stoich_nitr:units = "gN/gC" ; + fates_stoich_nitr:long_name = "target nitrogen concentration (ratio with carbon) of organs" ; + double fates_stoich_phos(fates_plant_organs, fates_pft) ; + fates_stoich_phos:units = "gP/gC" ; + fates_stoich_phos:long_name = "target phosphorus concentration (ratio with carbon) of organs" ; + double fates_trim_inc(fates_pft) ; + fates_trim_inc:units = "m2/m2" ; + fates_trim_inc:long_name = "Arbitrary incremental change in trimming function." ; + double fates_trim_limit(fates_pft) ; + fates_trim_limit:units = "m2/m2" ; + fates_trim_limit:long_name = "Arbitrary limit to reductions in leaf area with stress" ; + double fates_trs_repro_alloc_a(fates_pft) ; + fates_trs_repro_alloc_a:units = "fraction" ; + fates_trs_repro_alloc_a:long_name = "shape parameter for sigmoidal function relating dbh to reproductive allocation" ; + double fates_trs_repro_alloc_b(fates_pft) ; + fates_trs_repro_alloc_b:units = "fraction" ; + fates_trs_repro_alloc_b:long_name = "intercept parameter for sigmoidal function relating dbh to reproductive allocation" ; + double fates_trs_repro_frac_seed(fates_pft) ; + fates_trs_repro_frac_seed:units = "fraction" ; + fates_trs_repro_frac_seed:long_name = "fraction of reproductive mass that is seed" ; + double fates_trs_seedling_a_emerg(fates_pft) ; + fates_trs_seedling_a_emerg:units = "day -1" ; + fates_trs_seedling_a_emerg:long_name = "mean fraction of seed bank emerging" ; + double fates_trs_seedling_b_emerg(fates_pft) ; + fates_trs_seedling_b_emerg:units = "day -1" ; + fates_trs_seedling_b_emerg:long_name = "seedling emergence sensitivity to soil moisture" ; + double fates_trs_seedling_background_mort(fates_pft) ; + fates_trs_seedling_background_mort:units = "yr-1" ; + fates_trs_seedling_background_mort:long_name = "background seedling mortality rate" ; + double fates_trs_seedling_h2o_mort_a(fates_pft) ; + fates_trs_seedling_h2o_mort_a:units = "-" ; + fates_trs_seedling_h2o_mort_a:long_name = "coefficient in moisture-based seedling mortality" ; + double fates_trs_seedling_h2o_mort_b(fates_pft) ; + fates_trs_seedling_h2o_mort_b:units = "-" ; + fates_trs_seedling_h2o_mort_b:long_name = "coefficient in moisture-based seedling mortality" ; + double fates_trs_seedling_h2o_mort_c(fates_pft) ; + fates_trs_seedling_h2o_mort_c:units = "-" ; + fates_trs_seedling_h2o_mort_c:long_name = "coefficient in moisture-based seedling mortality" ; + double fates_trs_seedling_light_mort_a(fates_pft) ; + fates_trs_seedling_light_mort_a:units = "-" ; + fates_trs_seedling_light_mort_a:long_name = "light-based seedling mortality coefficient" ; + double fates_trs_seedling_light_mort_b(fates_pft) ; + fates_trs_seedling_light_mort_b:units = "-" ; + fates_trs_seedling_light_mort_b:long_name = "light-based seedling mortality coefficient" ; + double fates_trs_seedling_light_rec_a(fates_pft) ; + fates_trs_seedling_light_rec_a:units = "-" ; + fates_trs_seedling_light_rec_a:long_name = "coefficient in light-based seedling to sapling transition" ; + double fates_trs_seedling_light_rec_b(fates_pft) ; + fates_trs_seedling_light_rec_b:units = "-" ; + fates_trs_seedling_light_rec_b:long_name = "coefficient in light-based seedling to sapling transition" ; + double fates_trs_seedling_mdd_crit(fates_pft) ; + fates_trs_seedling_mdd_crit:units = "mm H2O day" ; + fates_trs_seedling_mdd_crit:long_name = "critical moisture deficit (suction) day accumulation for seedling moisture-based seedling mortality to begin" ; + double fates_trs_seedling_par_crit_germ(fates_pft) ; + fates_trs_seedling_par_crit_germ:units = "MJ m-2 day-1" ; + fates_trs_seedling_par_crit_germ:long_name = "critical light level for germination" ; + double fates_trs_seedling_psi_crit(fates_pft) ; + fates_trs_seedling_psi_crit:units = "mm H2O" ; + fates_trs_seedling_psi_crit:long_name = "critical soil moisture (suction) for seedling stress" ; + double fates_trs_seedling_psi_emerg(fates_pft) ; + fates_trs_seedling_psi_emerg:units = "mm h20 suction" ; + fates_trs_seedling_psi_emerg:long_name = "critical soil moisture for seedling emergence" ; + double fates_trs_seedling_root_depth(fates_pft) ; + fates_trs_seedling_root_depth:units = "m" ; + fates_trs_seedling_root_depth:long_name = "rooting depth of seedlings" ; + double fates_turb_displar(fates_pft) ; + fates_turb_displar:units = "unitless" ; + fates_turb_displar:long_name = "Ratio of displacement height to canopy top height" ; + double fates_turb_leaf_diameter(fates_pft) ; + fates_turb_leaf_diameter:units = "m" ; + fates_turb_leaf_diameter:long_name = "Characteristic leaf dimension" ; + double fates_turb_z0mr(fates_pft) ; + fates_turb_z0mr:units = "unitless" ; + fates_turb_z0mr:long_name = "Ratio of momentum roughness length to canopy top height" ; + double fates_turnover_branch(fates_pft) ; + fates_turnover_branch:units = "yr" ; + fates_turnover_branch:long_name = "turnover time of branches" ; + double fates_turnover_fnrt(fates_pft) ; + fates_turnover_fnrt:units = "yr" ; + fates_turnover_fnrt:long_name = "root longevity (alternatively, turnover time)" ; + double fates_turnover_leaf(fates_leafage_class, fates_pft) ; + fates_turnover_leaf:units = "yr" ; + fates_turnover_leaf:long_name = "Leaf longevity (ie turnover timescale). For drought-deciduous PFTs, this also indicates the maximum length of the growing (i.e., leaves on) season." ; + double fates_turnover_senleaf_fdrought(fates_pft) ; + fates_turnover_senleaf_fdrought:units = "unitless[0-1]" ; + fates_turnover_senleaf_fdrought:long_name = "multiplication factor for leaf longevity of senescent leaves during drought" ; + double fates_wood_density(fates_pft) ; + fates_wood_density:units = "g/cm3" ; + fates_wood_density:long_name = "mean density of woody tissue in plant" ; + double fates_woody(fates_pft) ; + fates_woody:units = "logical flag" ; + fates_woody:long_name = "Binary woody lifeform flag" ; + double fates_hlm_pft_map(fates_hlm_pftno, fates_pft) ; + fates_hlm_pft_map:units = "area fraction" ; + fates_hlm_pft_map:long_name = "In fixed biogeog mode, fraction of HLM area associated with each FATES PFT" ; + double fates_fire_FBD(fates_litterclass) ; + fates_fire_FBD:units = "kg Biomass/m3" ; + fates_fire_FBD:long_name = "fuel bulk density" ; + double fates_fire_low_moisture_Coeff(fates_litterclass) ; + fates_fire_low_moisture_Coeff:units = "NA" ; + fates_fire_low_moisture_Coeff:long_name = "spitfire parameter, equation B1 Thonicke et al 2010" ; + double fates_fire_low_moisture_Slope(fates_litterclass) ; + fates_fire_low_moisture_Slope:units = "NA" ; + fates_fire_low_moisture_Slope:long_name = "spitfire parameter, equation B1 Thonicke et al 2010" ; + double fates_fire_mid_moisture(fates_litterclass) ; + fates_fire_mid_moisture:units = "NA" ; + fates_fire_mid_moisture:long_name = "spitfire litter moisture threshold to be considered medium dry" ; + double fates_fire_mid_moisture_Coeff(fates_litterclass) ; + fates_fire_mid_moisture_Coeff:units = "NA" ; + fates_fire_mid_moisture_Coeff:long_name = "spitfire parameter, equation B1 Thonicke et al 2010" ; + double fates_fire_mid_moisture_Slope(fates_litterclass) ; + fates_fire_mid_moisture_Slope:units = "NA" ; + fates_fire_mid_moisture_Slope:long_name = "spitfire parameter, equation B1 Thonicke et al 2010" ; + double fates_fire_min_moisture(fates_litterclass) ; + fates_fire_min_moisture:units = "NA" ; + fates_fire_min_moisture:long_name = "spitfire litter moisture threshold to be considered very dry" ; + double fates_fire_SAV(fates_litterclass) ; + fates_fire_SAV:units = "cm-1" ; + fates_fire_SAV:long_name = "fuel surface area to volume ratio" ; + double fates_frag_maxdecomp(fates_litterclass) ; + fates_frag_maxdecomp:units = "yr-1" ; + fates_frag_maxdecomp:long_name = "maximum rate of litter & CWD transfer from non-decomposing class into decomposing class" ; + double fates_frag_cwd_frac(fates_NCWD) ; + fates_frag_cwd_frac:units = "fraction" ; + fates_frag_cwd_frac:long_name = "fraction of woody (bdead+bsw) biomass destined for CWD pool" ; + double fates_maxpatches_by_landuse(fates_landuseclass) ; + fates_maxpatches_by_landuse:units = "count" ; + fates_maxpatches_by_landuse:long_name = "maximum number of patches per site on each land use type" ; + double fates_canopy_closure_thresh ; + fates_canopy_closure_thresh:units = "unitless" ; + fates_canopy_closure_thresh:long_name = "tree canopy coverage at which crown area allometry changes from savanna to forest value" ; + double fates_cnp_eca_plant_escalar ; + fates_cnp_eca_plant_escalar:units = "" ; + fates_cnp_eca_plant_escalar:long_name = "scaling factor for plant fine root biomass to calculate nutrient carrier enzyme abundance (ECA)" ; + double fates_cohort_age_fusion_tol ; + fates_cohort_age_fusion_tol:units = "unitless" ; + fates_cohort_age_fusion_tol:long_name = "minimum fraction in differece in cohort age between cohorts." ; + double fates_cohort_size_fusion_tol ; + fates_cohort_size_fusion_tol:units = "unitless" ; + fates_cohort_size_fusion_tol:long_name = "minimum fraction in difference in dbh between cohorts" ; + double fates_comp_excln ; + fates_comp_excln:units = "none" ; + fates_comp_excln:long_name = "IF POSITIVE: weighting factor (exponent on dbh) for canopy layer exclusion and promotion, IF NEGATIVE: switch to use deterministic height sorting" ; + double fates_damage_canopy_layer_code ; + fates_damage_canopy_layer_code:units = "unitless" ; + fates_damage_canopy_layer_code:long_name = "Integer code that decides whether damage affects canopy trees (1), understory trees (2)" ; + double fates_damage_event_code ; + fates_damage_event_code:units = "unitless" ; + fates_damage_event_code:long_name = "Integer code that options how damage events are structured" ; + double fates_dev_arbitrary ; + fates_dev_arbitrary:units = "unknown" ; + fates_dev_arbitrary:long_name = "Unassociated free parameter that developers can use for testing arbitrary new hypotheses" ; + double fates_fire_active_crown_fire ; + fates_fire_active_crown_fire:units = "0 or 1" ; + fates_fire_active_crown_fire:long_name = "flag, 1=active crown fire 0=no active crown fire" ; + double fates_fire_cg_strikes ; + fates_fire_cg_strikes:units = "fraction (0-1)" ; + fates_fire_cg_strikes:long_name = "fraction of cloud to ground lightning strikes" ; + double fates_fire_drying_ratio ; + fates_fire_drying_ratio:units = "NA" ; + fates_fire_drying_ratio:long_name = "spitfire parameter, fire drying ratio for fuel moisture, alpha_FMC EQ 6 Thonicke et al 2010" ; + double fates_fire_durat_slope ; + fates_fire_durat_slope:units = "NA" ; + fates_fire_durat_slope:long_name = "spitfire parameter, fire max duration slope, Equation 14 Thonicke et al 2010" ; + double fates_fire_fdi_a ; + fates_fire_fdi_a:units = "NA" ; + fates_fire_fdi_a:long_name = "spitfire parameter, fire danger index, EQ 5 Thonicke et al 2010" ; + double fates_fire_fdi_alpha ; + fates_fire_fdi_alpha:units = "NA" ; + fates_fire_fdi_alpha:long_name = "spitfire parameter, EQ 7 Venevsky et al. GCB 2002,(modified EQ 8 Thonicke et al. 2010) " ; + double fates_fire_fdi_b ; + fates_fire_fdi_b:units = "NA" ; + fates_fire_fdi_b:long_name = "spitfire parameter, fire danger index, EQ 5 Thonicke et al 2010 " ; + double fates_fire_fuel_energy ; + fates_fire_fuel_energy:units = "kJ/kg" ; + fates_fire_fuel_energy:long_name = "spitfire parameter, heat content of fuel" ; + double fates_fire_max_durat ; + fates_fire_max_durat:units = "minutes" ; + fates_fire_max_durat:long_name = "spitfire parameter, fire maximum duration, Equation 14 Thonicke et al 2010" ; + double fates_fire_miner_damp ; + fates_fire_miner_damp:units = "NA" ; + fates_fire_miner_damp:long_name = "spitfire parameter, mineral-dampening coefficient EQ A1 Thonicke et al 2010 " ; + double fates_fire_miner_total ; + fates_fire_miner_total:units = "fraction" ; + fates_fire_miner_total:long_name = "spitfire parameter, total mineral content, Table A1 Thonicke et al 2010" ; + double fates_fire_nignitions ; + fates_fire_nignitions:units = "ignitions per year per km2" ; + fates_fire_nignitions:long_name = "number of annual ignitions per square km" ; + double fates_fire_part_dens ; + fates_fire_part_dens:units = "kg/m2" ; + fates_fire_part_dens:long_name = "spitfire parameter, oven dry particle density, Table A1 Thonicke et al 2010" ; + double fates_fire_threshold ; + fates_fire_threshold:units = "kW/m" ; + fates_fire_threshold:long_name = "spitfire parameter, fire intensity threshold for tracking fires that spread" ; + double fates_frag_cwd_fcel ; + fates_frag_cwd_fcel:units = "unitless" ; + fates_frag_cwd_fcel:long_name = "Cellulose fraction for CWD" ; + double fates_frag_cwd_flig ; + fates_frag_cwd_flig:units = "unitless" ; + fates_frag_cwd_flig:long_name = "Lignin fraction of coarse woody debris" ; + double fates_hydro_kmax_rsurf1 ; + fates_hydro_kmax_rsurf1:units = "kg water/m2 root area/Mpa/s" ; + fates_hydro_kmax_rsurf1:long_name = "maximum conducitivity for unit root surface (into root)" ; + double fates_hydro_kmax_rsurf2 ; + fates_hydro_kmax_rsurf2:units = "kg water/m2 root area/Mpa/s" ; + fates_hydro_kmax_rsurf2:long_name = "maximum conducitivity for unit root surface (out of root)" ; + double fates_hydro_psi0 ; + fates_hydro_psi0:units = "MPa" ; + fates_hydro_psi0:long_name = "sapwood water potential at saturation" ; + double fates_hydro_psicap ; + fates_hydro_psicap:units = "MPa" ; + fates_hydro_psicap:long_name = "sapwood water potential at which capillary reserves exhausted" ; + double fates_hydro_solver ; + fates_hydro_solver:units = "unitless" ; + fates_hydro_solver:long_name = "switch designating which numerical solver for plant hydraulics, 1 = 1D taylor, 2 = 2D Picard, 3 = 2D Newton (deprecated)" ; + double fates_landuse_logging_coll_under_frac ; + fates_landuse_logging_coll_under_frac:units = "fraction" ; + fates_landuse_logging_coll_under_frac:long_name = "Fraction of stems killed in the understory when logging generates disturbance" ; + double fates_landuse_logging_collateral_frac ; + fates_landuse_logging_collateral_frac:units = "fraction" ; + fates_landuse_logging_collateral_frac:long_name = "Fraction of large stems in upperstory that die from logging collateral damage" ; + double fates_landuse_logging_dbhmax ; + fates_landuse_logging_dbhmax:units = "cm" ; + fates_landuse_logging_dbhmax:long_name = "Maximum dbh below which logging is applied (unset values flag this to be unused)" ; + double fates_landuse_logging_dbhmax_infra ; + fates_landuse_logging_dbhmax_infra:units = "cm" ; + fates_landuse_logging_dbhmax_infra:long_name = "Tree diameter, above which infrastructure from logging does not impact damage or mortality." ; + double fates_landuse_logging_dbhmin ; + fates_landuse_logging_dbhmin:units = "cm" ; + fates_landuse_logging_dbhmin:long_name = "Minimum dbh at which logging is applied" ; + double fates_landuse_logging_direct_frac ; + fates_landuse_logging_direct_frac:units = "fraction" ; + fates_landuse_logging_direct_frac:long_name = "Fraction of stems logged directly per event" ; + double fates_landuse_logging_event_code ; + fates_landuse_logging_event_code:units = "unitless" ; + fates_landuse_logging_event_code:long_name = "Integer code that options how logging events are structured" ; + double fates_landuse_logging_export_frac ; + fates_landuse_logging_export_frac:units = "fraction" ; + fates_landuse_logging_export_frac:long_name = "fraction of trunk product being shipped offsite, the leftovers will be left onsite as large CWD" ; + double fates_landuse_logging_mechanical_frac ; + fates_landuse_logging_mechanical_frac:units = "fraction" ; + fates_landuse_logging_mechanical_frac:long_name = "Fraction of stems killed due infrastructure an other mechanical means" ; + double fates_landuse_pprodharv10_forest_mean ; + fates_landuse_pprodharv10_forest_mean:units = "fraction" ; + fates_landuse_pprodharv10_forest_mean:long_name = "mean harvest mortality proportion of deadstem to 10-yr product (pprodharv10) of all woody PFT types" ; + double fates_leaf_photo_temp_acclim_thome_time ; + fates_leaf_photo_temp_acclim_thome_time:units = "years" ; + fates_leaf_photo_temp_acclim_thome_time:long_name = "Length of the window for the long-term (i.e. T_home in Kumarathunge et al 2019) exponential moving average (ema) of vegetation temperature used in photosynthesis temperature acclimation (used if fates_leaf_photo_tempsens_model = 2)" ; + double fates_leaf_photo_temp_acclim_timescale ; + fates_leaf_photo_temp_acclim_timescale:units = "days" ; + fates_leaf_photo_temp_acclim_timescale:long_name = "Length of the window for the exponential moving average (ema) of vegetation temperature used in photosynthesis temperature acclimation (used if fates_maintresp_leaf_model=2 or fates_leaf_photo_tempsens_model = 2)" ; + double fates_leaf_photo_tempsens_model ; + fates_leaf_photo_tempsens_model:units = "unitless" ; + fates_leaf_photo_tempsens_model:long_name = "switch for choosing the model that defines the temperature sensitivity of photosynthetic parameters (vcmax, jmax). 1=non-acclimating; 2=Kumarathunge et al 2019" ; + double fates_leaf_stomatal_assim_model ; + fates_leaf_stomatal_assim_model:units = "unitless" ; + fates_leaf_stomatal_assim_model:long_name = "a switch designating whether to use net (1) or gross (2) assimilation in the stomatal model" ; + double fates_leaf_stomatal_model ; + fates_leaf_stomatal_model:units = "unitless" ; + fates_leaf_stomatal_model:long_name = "switch for choosing between Ball-Berry (1) stomatal conductance model and Medlyn (2) model" ; + double fates_leaf_theta_cj_c3 ; + fates_leaf_theta_cj_c3:units = "unitless" ; + fates_leaf_theta_cj_c3:long_name = "Empirical curvature parameter for ac, aj photosynthesis co-limitation in c3 plants" ; + double fates_leaf_theta_cj_c4 ; + fates_leaf_theta_cj_c4:units = "unitless" ; + fates_leaf_theta_cj_c4:long_name = "Empirical curvature parameter for ac, aj photosynthesis co-limitation in c4 plants" ; + double fates_maintresp_leaf_model ; + fates_maintresp_leaf_model:units = "unitless" ; + fates_maintresp_leaf_model:long_name = "switch for choosing between maintenance respiration models. 1=Ryan (1991), 2=Atkin et al., (2017)" ; + double fates_maintresp_nonleaf_baserate ; + fates_maintresp_nonleaf_baserate:units = "gC/gN/s" ; + fates_maintresp_nonleaf_baserate:long_name = "Base maintenance respiration rate for plant tissues, using Ryan 1991" ; + double fates_maxcohort ; + fates_maxcohort:units = "count" ; + fates_maxcohort:long_name = "maximum number of cohorts per patch. Actual number of cohorts also depend on cohort fusion tolerances" ; + double fates_mort_disturb_frac ; + fates_mort_disturb_frac:units = "fraction" ; + fates_mort_disturb_frac:long_name = "fraction of canopy mortality that results in disturbance (i.e. transfer of area from new to old patch)" ; + double fates_mort_understorey_death ; + fates_mort_understorey_death:units = "fraction" ; + fates_mort_understorey_death:long_name = "fraction of plants in understorey cohort impacted by overstorey tree-fall" ; + double fates_patch_fusion_tol ; + fates_patch_fusion_tol:units = "unitless" ; + fates_patch_fusion_tol:long_name = "minimum fraction in difference in profiles between patches" ; + double fates_phen_chilltemp ; + fates_phen_chilltemp:units = "degrees C" ; + fates_phen_chilltemp:long_name = "chilling day counting threshold for vegetation" ; + double fates_phen_coldtemp ; + fates_phen_coldtemp:units = "degrees C" ; + fates_phen_coldtemp:long_name = "vegetation temperature exceedance that flags a cold-day for leaf-drop" ; + double fates_phen_gddthresh_a ; + fates_phen_gddthresh_a:units = "none" ; + fates_phen_gddthresh_a:long_name = "GDD accumulation function, intercept parameter: gdd_thesh = a + b exp(c*ncd)" ; + double fates_phen_gddthresh_b ; + fates_phen_gddthresh_b:units = "none" ; + fates_phen_gddthresh_b:long_name = "GDD accumulation function, multiplier parameter: gdd_thesh = a + b exp(c*ncd)" ; + double fates_phen_gddthresh_c ; + fates_phen_gddthresh_c:units = "none" ; + fates_phen_gddthresh_c:long_name = "GDD accumulation function, exponent parameter: gdd_thesh = a + b exp(c*ncd)" ; + double fates_phen_mindayson ; + fates_phen_mindayson:units = "days" ; + fates_phen_mindayson:long_name = "day threshold compared against days since leaves became on-allometry" ; + double fates_phen_ncolddayslim ; + fates_phen_ncolddayslim:units = "days" ; + fates_phen_ncolddayslim:long_name = "day threshold exceedance for temperature leaf-drop" ; + double fates_q10_froz ; + fates_q10_froz:units = "unitless" ; + fates_q10_froz:long_name = "Q10 for frozen-soil respiration rates" ; + double fates_q10_mr ; + fates_q10_mr:units = "unitless" ; + fates_q10_mr:long_name = "Q10 for maintenance respiration" ; + double fates_rad_model ; + fates_rad_model:units = "unitless" ; + fates_rad_model:long_name = "switch designating the model for canopy radiation, 1 = Norman, 2 = Two-stream (experimental)" ; + double fates_regeneration_model ; + fates_regeneration_model:units = "-" ; + fates_regeneration_model:long_name = "switch for choosing between FATES\'s: 1) default regeneration scheme , 2) the Tree Recruitment Scheme (Hanbury-Brown et al., 2022), or (3) the Tree Recruitment Scheme without seedling dynamics" ; + double fates_soil_salinity ; + fates_soil_salinity:units = "ppt" ; + fates_soil_salinity:long_name = "soil salinity used for model when not coupled to dynamic soil salinity" ; + double fates_trs_seedling2sap_par_timescale ; + fates_trs_seedling2sap_par_timescale:units = "days" ; + fates_trs_seedling2sap_par_timescale:long_name = "Length of the window for the exponential moving average of par at the seedling layer used to calculate seedling to sapling transition rates" ; + double fates_trs_seedling_emerg_h2o_timescale ; + fates_trs_seedling_emerg_h2o_timescale:units = "days" ; + fates_trs_seedling_emerg_h2o_timescale:long_name = "Length of the window for the exponential moving average of smp used to calculate seedling emergence" ; + double fates_trs_seedling_mdd_timescale ; + fates_trs_seedling_mdd_timescale:units = "days" ; + fates_trs_seedling_mdd_timescale:long_name = "Length of the window for the exponential moving average of moisture deficit days used to calculate seedling mortality" ; + double fates_trs_seedling_mort_par_timescale ; + fates_trs_seedling_mort_par_timescale:units = "days" ; + fates_trs_seedling_mort_par_timescale:long_name = "Length of the window for the exponential moving average of par at the seedling layer used to calculate seedling mortality" ; + double fates_vai_top_bin_width ; + fates_vai_top_bin_width:units = "m2/m2" ; + fates_vai_top_bin_width:long_name = "width in VAI units of uppermost leaf+stem layer scattering element in each canopy layer" ; + double fates_vai_width_increase_factor ; + fates_vai_width_increase_factor:units = "unitless" ; + fates_vai_width_increase_factor:long_name = "factor by which each leaf+stem scattering element increases in VAI width (1 = uniform spacing)" ; + +// global attributes: + :history = "This file was generated by BatchPatchParams.py:\nCDL Base File = archive/api24.1.0_101722_fates_params_default.cdl\nXML patch file = archive/api24.1.0_101722_patch_params.xml" ; +data: + + fates_history_ageclass_bin_edges = 0, 1, 2, 5, 10, 20, 50 ; + + fates_history_coageclass_bin_edges = 0, 5 ; + + fates_history_height_bin_edges = 0, 0.1, 0.3, 1, 3, 10 ; + + fates_history_damage_bin_edges = 0, 80 ; + + fates_history_sizeclass_bin_edges = 0, 5, 10, 15, 20, 30, 40, 50, 60, 70, + 80, 90, 100 ; + + fates_alloc_organ_id = 1, 2, 3, 6 ; + + fates_hydro_htftype_node = 1, 1, 1, 1 ; + + fates_pftname = + "broadleaf_evergreen_tropical_tree ", + "needleleaf_evergreen_extratrop_tree ", + "needleleaf_colddecid_extratrop_tree ", + "broadleaf_evergreen_extratrop_tree ", + "broadleaf_hydrodecid_tropical_tree ", + "broadleaf_colddecid_extratrop_tree ", + "broadleaf_evergreen_extratrop_shrub ", + "broadleaf_hydrodecid_extratrop_shrub ", + "broadleaf_colddecid_extratrop_shrub ", + "arctic_c3_grass ", + "cool_c3_grass ", + "c4_grass " ; + + fates_hydro_organ_name = + "leaf ", + "stem ", + "transporting root ", + "absorbing root " ; + + fates_alloc_organ_name = + "leaf", + "fine root", + "sapwood", + "structure" ; + + fates_landuseclass_name = + "primaryland", + "secondaryland", + "rangeland", + "pastureland", + "cropland" ; + + fates_litterclass_name = + "twig ", + "small branch ", + "large branch ", + "trunk ", + "dead leaves ", + "live grass " ; + + fates_alloc_organ_priority = + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 ; + + fates_alloc_storage_cushion = 1.2, 1.2, 1.2, 1.2, 2.4, 1.2, 1.2, 2.4, 1.2, + 1.2, 1.2, 1.2 ; + + fates_alloc_store_priority_frac = 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, + 0.8, 0.8, 0.8, 0.8 ; + + fates_allom_agb1 = 0.0673, 0.1364012, 0.0393057, 0.2653695, 0.0673, + 0.0728698, 0.06896, 0.06896, 0.06896, 0.01, 0.01, 0.01 ; + + fates_allom_agb2 = 0.976, 0.9449041, 1.087335, 0.8321321, 0.976, 1.0373211, + 0.572, 0.572, 0.572, 0.572, 0.572, 0.572 ; + + fates_allom_agb3 = 1.94, 1.94, 1.94, 1.94, 1.94, 1.94, 1.94, 1.94, 1.94, + 1.94, 1.94, 1.94 ; + + fates_allom_agb4 = 0.931, 0.931, 0.931, 0.931, 0.931, 0.931, 0.931, 0.931, + 0.931, 0.931, 0.931, 0.931 ; + + fates_allom_agb_frac = 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, + 0.6, 0.6 ; + + fates_allom_amode = 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1 ; + + fates_allom_blca_expnt_diff = -0.12, -0.34, -0.32, -0.22, -0.12, -0.35, 0, + 0, 0, 0, 0, 0 ; + + fates_allom_cmode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_crown_depth_frac = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.95, 0.95, + 0.95, 1, 1, 1 ; + + fates_allom_d2bl1 = 0.04, 0.07, 0.07, 0.01, 0.04, 0.07, 0.07, 0.07, 0.07, + 0.07, 0.07, 0.07 ; + + fates_allom_d2bl2 = 1.6019679, 1.5234373, 1.3051237, 1.9621397, 1.6019679, + 1.3998939, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3 ; + + fates_allom_d2bl3 = 0.55, 0.55, 0.55, 0.55, 0.55, 0.55, 0.55, 0.55, 0.55, + 0.55, 0.55, 0.55 ; + + fates_allom_d2ca_coefficient_max = 0.2715891, 0.3693718, 1.0787259, + 0.0579297, 0.2715891, 1.1553612, 0.6568464, 0.6568464, 0.6568464, + 0.6568464, 0.6568464, 0.6568464 ; + + fates_allom_d2ca_coefficient_min = 0.2715891, 0.3693718, 1.0787259, + 0.0579297, 0.2715891, 1.1553612, 0.6568464, 0.6568464, 0.6568464, + 0.6568464, 0.6568464, 0.6568464 ; + + fates_allom_d2h1 = 78.4087704, 306.842667, 106.8745821, 104.3586841, + 78.4087704, 31.4557047, 0.64, 0.64, 0.64, 0.64, 0.64, 0.64 ; + + fates_allom_d2h2 = 0.8124383, 0.752377, 0.9471302, 1.1146973, 0.8124383, + 0.9734088, 0.37, 0.37, 0.37, 0.37, 0.37, 0.37 ; + + fates_allom_d2h3 = 47.6666164, 196.6865691, 93.9790461, 160.6835089, + 47.6666164, 16.5928174, -999.9, -999.9, -999.9, -999.9, -999.9, -999.9 ; + + fates_allom_dbh_maxheight = 1000, 1000, 1000, 1000, 1000, 1000, 3, 3, 2, + 0.35, 0.35, 0.35 ; + + fates_allom_fmode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_fnrt_prof_a = 7, 7, 7, 7, 6, 6, 7, 7, 7, 11, 11, 11 ; + + fates_allom_fnrt_prof_b = 1, 2, 2, 1, 2, 2, 1.5, 1.5, 1.5, 2, 2, 2 ; + + fates_allom_fnrt_prof_mode = 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 ; + + fates_allom_frbstor_repro = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_allom_hmode = 5, 5, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1 ; + + fates_allom_l2fr = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_la_per_sa_int = 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, + 0.8, 0.8, 0.8 ; + + fates_allom_la_per_sa_slp = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_allom_lmode = 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1 ; + + fates_allom_sai_scaler = 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, + 0.1, 0.1 ; + + fates_allom_smode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_stmode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_zroot_k = 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10 ; + + fates_allom_zroot_max_dbh = 100, 100, 100, 100, 100, 100, 2, 2, 2, 2, 2, 2 ; + + fates_allom_zroot_max_z = 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, + 100, 100 ; + + fates_allom_zroot_min_dbh = 1, 1, 1, 2.5, 2.5, 2.5, 0.1, 0.1, 0.1, 0.1, 0.1, + 0.1 ; + + fates_allom_zroot_min_z = 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, + 100, 100 ; + + fates_c2b = 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ; + + fates_cnp_eca_alpha_ptase = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5 ; + + fates_cnp_eca_decompmicc = 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280 ; + + fates_cnp_eca_km_nh4 = 0.14, 0.14, 0.14, 0.14, 0.14, 0.14, 0.14, 0.14, 0.14, + 0.14, 0.14, 0.14 ; + + fates_cnp_eca_km_no3 = 0.27, 0.27, 0.27, 0.27, 0.27, 0.27, 0.27, 0.27, 0.27, + 0.27, 0.27, 0.27 ; + + fates_cnp_eca_km_p = 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, + 0.1 ; + + fates_cnp_eca_km_ptase = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_cnp_eca_lambda_ptase = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_cnp_eca_vmax_ptase = 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, + 5e-09, 5e-09, 5e-09, 5e-09, 5e-09 ; + + fates_cnp_nfix1 = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_cnp_nitr_store_ratio = 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, + 1.5, 1.5, 1.5 ; + + fates_cnp_phos_store_ratio = 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, + 1.5, 1.5, 1.5 ; + + fates_cnp_pid_kd = 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1 ; + + fates_cnp_pid_ki = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_cnp_pid_kp = 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, + 0.0005, 0.0005, 0.0005, 0.0005, 0.0005 ; + + fates_cnp_prescribed_nuptake = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_cnp_prescribed_puptake = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_cnp_store_ovrflw_frac = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_cnp_turnover_nitr_retrans = + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_cnp_turnover_phos_retrans = + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_cnp_vmax_nh4 = 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, + 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09 ; + + fates_cnp_vmax_no3 = 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, + 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09 ; + + fates_cnp_vmax_p = 5e-10, 5e-10, 5e-10, 5e-10, 5e-10, 5e-10, 5e-10, 5e-10, + 5e-10, 5e-10, 5e-10, 5e-10 ; + + fates_damage_frac = 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, + 0.01, 0.01, 0.01 ; + + fates_damage_mort_p1 = 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 ; + + fates_damage_mort_p2 = 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, + 5.5, 5.5 ; + + fates_damage_recovery_scalar = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_dev_arbitrary_pft = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_fire_alpha_SH = 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, + 0.2 ; + + fates_fire_bark_scaler = 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, + 0.07, 0.07, 0.07, 0.07 ; + + fates_fire_crown_kill = 0.775, 0.775, 0.775, 0.775, 0.775, 0.775, 0.775, + 0.775, 0.775, 0.775, 0.775, 0.775 ; + + fates_frag_fnrt_fcel = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5 ; + + fates_frag_fnrt_flab = 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25 ; + + fates_frag_fnrt_flig = 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25 ; + + fates_frag_leaf_fcel = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5 ; + + fates_frag_leaf_flab = 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25 ; + + fates_frag_leaf_flig = 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25 ; + + fates_frag_seed_decay_rate = 0.51, 0.51, 0.51, 0.51, 0.51, 0.51, 0.51, 0.51, + 0.51, 0.51, 0.51, 0.51 ; + + fates_grperc = 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, + 0.11, 0.11 ; + + fates_hydro_avuln_gs = 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, + 2.5, 2.5 ; + + fates_hydro_avuln_node = + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ; + + fates_hydro_epsil_node = + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 ; + + fates_hydro_fcap_node = + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, + 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_hydro_k_lwp = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_hydro_kmax_node = + -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999 ; + + fates_hydro_p50_gs = -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, + -1.5, -1.5, -1.5 ; + + fates_hydro_p50_node = + -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, + -2.25, -2.25, + -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, + -2.25, -2.25, + -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, + -2.25, -2.25, + -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, + -2.25, -2.25 ; + + fates_hydro_p_taper = 0.333, 0.333, 0.333, 0.333, 0.333, 0.333, 0.333, + 0.333, 0.333, 0.333, 0.333, 0.333 ; + + fates_hydro_pinot_node = + -1.465984, -1.465984, -1.465984, -1.465984, -1.465984, -1.465984, + -1.465984, -1.465984, -1.465984, -1.465984, -1.465984, -1.465984, + -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, + -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, + -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, + -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, + -1.043478, -1.043478, -1.043478, -1.043478, -1.043478, -1.043478, + -1.043478, -1.043478, -1.043478, -1.043478, -1.043478, -1.043478 ; + + fates_hydro_pitlp_node = + -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, + -1.67, -1.67, + -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, + -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, + -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2 ; + + fates_hydro_resid_node = + 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, + 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, + 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, + 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11 ; + + fates_hydro_rfrac_stem = 0.625, 0.625, 0.625, 0.625, 0.625, 0.625, 0.625, + 0.625, 0.625, 0.625, 0.625, 0.625 ; + + fates_hydro_rs2 = 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, + 0.0001, 0.0001, 0.0001, 0.0001, 0.0001 ; + + fates_hydro_srl = 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25 ; + + fates_hydro_thetas_node = + 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, + 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, + 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, + 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75 ; + + fates_hydro_vg_alpha_node = + 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.005, 0.005, 0.005, 0.005, 0.005, + 0.005, 0.005, + 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.005, 0.005, 0.005, 0.005, 0.005, + 0.005, 0.005, + 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.005, 0.005, 0.005, 0.005, 0.005, + 0.005, 0.005, + 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.005, 0.005, 0.005, 0.005, 0.005, + 0.005, 0.005 ; + + fates_hydro_vg_m_node = + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5 ; + + fates_hydro_vg_n_node = + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ; + + fates_leaf_c3psn = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 ; + + fates_leaf_jmaxha = 43540, 43540, 43540, 43540, 43540, 43540, 43540, 43540, + 43540, 43540, 43540, 43540 ; + + fates_leaf_jmaxhd = 152040, 152040, 152040, 152040, 152040, 152040, 152040, + 152040, 152040, 152040, 152040, 152040 ; + + fates_leaf_jmaxse = 495, 495, 495, 495, 495, 495, 495, 495, 495, 495, 495, + 495 ; + + fates_leaf_slamax = 0.0954, 0.0954, 0.0954, 0.0954, 0.0954, 0.0954, 0.012, + 0.03, 0.03, 0.03, 0.03, 0.03 ; + + fates_leaf_slatop = 0.012, 0.005, 0.024, 0.009, 0.03, 0.03, 0.012, 0.03, + 0.03, 0.03, 0.03, 0.03 ; + + fates_leaf_stomatal_intercept = 10000, 10000, 10000, 10000, 10000, 10000, + 10000, 10000, 10000, 10000, 10000, 40000 ; + + fates_leaf_stomatal_slope_ballberry = 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 ; + + fates_leaf_stomatal_slope_medlyn = 4.1, 2.3, 2.3, 4.1, 4.4, 4.4, 4.7, 4.7, + 4.7, 2.2, 5.3, 1.6 ; + + fates_leaf_vcmax25top = + 50, 62, 39, 61, 58, 58, 62, 54, 54, 78, 78, 78 ; + + fates_leaf_vcmaxha = 65330, 65330, 65330, 65330, 65330, 65330, 65330, 65330, + 65330, 65330, 65330, 65330 ; + + fates_leaf_vcmaxhd = 149250, 149250, 149250, 149250, 149250, 149250, 149250, + 149250, 149250, 149250, 149250, 149250 ; + + fates_leaf_vcmaxse = 485, 485, 485, 485, 485, 485, 485, 485, 485, 485, 485, + 485 ; + + fates_maintresp_leaf_atkin2017_baserate = 1.756, 1.4995, 1.4995, 1.756, + 1.756, 1.756, 2.0749, 2.0749, 2.0749, 2.1956, 2.1956, 2.1956 ; + + fates_maintresp_leaf_ryan1991_baserate = 2.525e-06, 2.525e-06, 2.525e-06, + 2.525e-06, 2.525e-06, 2.525e-06, 2.525e-06, 2.525e-06, 2.525e-06, + 2.525e-06, 2.525e-06, 2.525e-06 ; + + fates_maintresp_reduction_curvature = 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, + 0.01, 0.01, 0.01, 0.01, 0.01, 0.01 ; + + fates_maintresp_reduction_intercept = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_maintresp_reduction_upthresh = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_mort_bmort = 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, + 0.014, 0.014, 0.014, 0.014 ; + + fates_mort_freezetol = 2.5, -55, -80, -30, 2.5, -80, -60, -10, -80, -80, + -20, 2.5 ; + + fates_mort_hf_flc_threshold = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5 ; + + fates_mort_hf_sm_threshold = 1e-06, 1e-06, 1e-06, 1e-06, 1e-06, 1e-06, + 1e-06, 1e-06, 1e-06, 1e-06, 1e-06, 1e-06 ; + + fates_mort_ip_age_senescence = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_mort_ip_size_senescence = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_mort_prescribed_canopy = 0.0194, 0.0194, 0.0194, 0.0194, 0.0194, + 0.0194, 0.0194, 0.0194, 0.0194, 0.0194, 0.0194, 0.0194 ; + + fates_mort_prescribed_understory = 0.025, 0.025, 0.025, 0.025, 0.025, 0.025, + 0.025, 0.025, 0.025, 0.025, 0.025, 0.025 ; + + fates_mort_r_age_senescence = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_mort_r_size_senescence = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_mort_scalar_coldstress = 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 ; + + fates_mort_scalar_cstarvation = 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, + 0.6, 0.6, 0.6 ; + + fates_mort_scalar_hydrfailure = 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, + 0.6, 0.6, 0.6 ; + + fates_mort_upthresh_cstarvation = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_nonhydro_smpsc = -255000, -255000, -255000, -255000, -255000, -255000, + -255000, -255000, -255000, -255000, -255000, -255000 ; + + fates_nonhydro_smpso = -66000, -66000, -66000, -66000, -66000, -66000, + -66000, -66000, -66000, -66000, -66000, -66000 ; + + fates_phen_cold_size_threshold = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_phen_drought_threshold = -152957.4, -152957.4, -152957.4, -152957.4, + -152957.4, -152957.4, -152957.4, -152957.4, -152957.4, -152957.4, + -152957.4, -152957.4 ; + + fates_phen_evergreen = 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 ; + + fates_phen_flush_fraction = _, _, 0.5, _, 0.5, 0.5, _, 0.5, 0.5, 0.5, 0.5, + 0.5 ; + + fates_phen_fnrt_drop_fraction = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_phen_mindaysoff = 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, + 100, 100 ; + + fates_phen_moist_threshold = -122365.9, -122365.9, -122365.9, -122365.9, + -122365.9, -122365.9, -122365.9, -122365.9, -122365.9, -122365.9, + -122365.9, -122365.9 ; + + fates_phen_season_decid = 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0 ; + + fates_phen_stem_drop_fraction = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_phen_stress_decid = 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1 ; + + fates_prescribed_npp_canopy = 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, + 0.4, 0.4, 0.4 ; + + fates_prescribed_npp_understory = 0.03125, 0.03125, 0.03125, 0.03125, + 0.03125, 0.03125, 0.03125, 0.03125, 0.03125, 0.03125, 0.03125, 0.03125 ; + + fates_rad_leaf_clumping_index = 0.85, 0.85, 0.8, 0.85, 0.85, 0.9, 0.85, 0.9, + 0.9, 0.75, 0.75, 0.75 ; + + fates_rad_leaf_rhonir = 0.46, 0.41, 0.39, 0.46, 0.41, 0.41, 0.46, 0.41, + 0.41, 0.28, 0.28, 0.28 ; + + fates_rad_leaf_rhovis = 0.11, 0.09, 0.08, 0.11, 0.08, 0.08, 0.11, 0.08, + 0.08, 0.05, 0.05, 0.05 ; + + fates_rad_leaf_taunir = 0.33, 0.32, 0.42, 0.33, 0.43, 0.43, 0.33, 0.43, + 0.43, 0.4, 0.4, 0.4 ; + + fates_rad_leaf_tauvis = 0.06, 0.04, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, + 0.06, 0.05, 0.05, 0.05 ; + + fates_rad_leaf_xl = 0.32, 0.01, 0.01, 0.32, 0.2, 0.59, 0.32, 0.59, 0.59, + -0.23, -0.23, -0.23 ; + + fates_rad_stem_rhonir = 0.49, 0.36, 0.36, 0.49, 0.49, 0.49, 0.49, 0.49, + 0.49, 0.53, 0.53, 0.53 ; + + fates_rad_stem_rhovis = 0.21, 0.12, 0.12, 0.21, 0.21, 0.21, 0.21, 0.21, + 0.21, 0.31, 0.31, 0.31 ; + + fates_rad_stem_taunir = 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, + 0.001, 0.001, 0.25, 0.25, 0.25 ; + + fates_rad_stem_tauvis = 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, + 0.001, 0.001, 0.12, 0.12, 0.12 ; + + fates_recruit_height_min = 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 0.2, 0.2, 0.2, + 0.125, 0.125, 0.125 ; + + fates_recruit_init_density = 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, + 0.2, 0.2, 0.2 ; + + fates_recruit_prescribed_rate = 0.02, 0.02, 0.02, 0.02, 0.02, 0.02, 0.02, + 0.02, 0.02, 0.02, 0.02, 0.02 ; + + fates_recruit_seed_alloc = 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, + 0.1, 0.1 ; + + fates_recruit_seed_alloc_mature = 0, 0, 0, 0, 0, 0, 0.9, 0.9, 0.9, 0.9, 0.9, + 0.9 ; + + fates_recruit_seed_dbh_repro_threshold = 90, 80, 80, 80, 90, 80, 3, 3, 2, + 0.35, 0.35, 0.35 ; + + fates_recruit_seed_germination_rate = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5 ; + + fates_recruit_seed_supplement = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_seed_dispersal_fraction = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_seed_dispersal_max_dist = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_seed_dispersal_pdf_scale = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_seed_dispersal_pdf_shape = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_stoich_nitr = + 0.033, 0.029, 0.04, 0.033, 0.04, 0.04, 0.033, 0.04, 0.04, 0.04, 0.04, 0.04, + 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, + 0.024, 0.024, + 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, + 1e-08, 1e-08, + 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, + 0.0047, 0.0047, 0.0047 ; + + fates_stoich_phos = + 0.0033, 0.0029, 0.004, 0.0033, 0.004, 0.004, 0.0033, 0.004, 0.004, 0.004, + 0.004, 0.004, + 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, + 0.0024, 0.0024, 0.0024, + 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, + 1e-09, 1e-09, + 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, + 0.00047, 0.00047, 0.00047, 0.00047 ; + + fates_trim_inc = 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, + 0.03, 0.03 ; + + fates_trim_limit = 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3 ; + + fates_trs_repro_alloc_a = 0.0049, 0.0049, 0.0049, 0.0049, 0.0049, 0.0049, + 0.0049, 0.0049, 0.0049, 0.0049, 0.0049, 0.0049 ; + + fates_trs_repro_alloc_b = -2.6171, -2.6171, -2.6171, -2.6171, -2.6171, + -2.6171, -2.6171, -2.6171, -2.6171, -2.6171, -2.6171, -2.6171 ; + + fates_trs_repro_frac_seed = 0.24, 0.24, 0.24, 0.24, 0.24, 0.24, 0.24, 0.24, + 0.24, 0.24, 0.24, 0.24 ; + + fates_trs_seedling_a_emerg = 0.0003, 0.0003, 0.0003, 0.0003, 0.0003, 0.0003, + 0.0003, 0.0003, 0.0003, 0.0003, 0.0003, 0.0003 ; + + fates_trs_seedling_b_emerg = 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, + 1.2, 1.2, 1.2 ; + + fates_trs_seedling_background_mort = 0.1085371, 0.1085371, 0.1085371, + 0.1085371, 0.1085371, 0.1085371, 0.1085371, 0.1085371, 0.1085371, + 0.1085371, 0.1085371, 0.1085371 ; + + fates_trs_seedling_h2o_mort_a = 4.070565e-17, 4.070565e-17, 4.070565e-17, + 4.070565e-17, 4.070565e-17, 4.070565e-17, 4.070565e-17, 4.070565e-17, + 4.070565e-17, 4.070565e-17, 4.070565e-17, 4.070565e-17 ; + + fates_trs_seedling_h2o_mort_b = -6.390757e-11, -6.390757e-11, -6.390757e-11, + -6.390757e-11, -6.390757e-11, -6.390757e-11, -6.390757e-11, + -6.390757e-11, -6.390757e-11, -6.390757e-11, -6.390757e-11, -6.390757e-11 ; + + fates_trs_seedling_h2o_mort_c = 1.268992e-05, 1.268992e-05, 1.268992e-05, + 1.268992e-05, 1.268992e-05, 1.268992e-05, 1.268992e-05, 1.268992e-05, + 1.268992e-05, 1.268992e-05, 1.268992e-05, 1.268992e-05 ; + + fates_trs_seedling_light_mort_a = -0.009897694, -0.009897694, -0.009897694, + -0.009897694, -0.009897694, -0.009897694, -0.009897694, -0.009897694, + -0.009897694, -0.009897694, -0.009897694, -0.009897694 ; + + fates_trs_seedling_light_mort_b = -7.154063, -7.154063, -7.154063, + -7.154063, -7.154063, -7.154063, -7.154063, -7.154063, -7.154063, + -7.154063, -7.154063, -7.154063 ; + + fates_trs_seedling_light_rec_a = 0.007, 0.007, 0.007, 0.007, 0.007, 0.007, + 0.007, 0.007, 0.007, 0.007, 0.007, 0.007 ; + + fates_trs_seedling_light_rec_b = 0.8615, 0.8615, 0.8615, 0.8615, 0.8615, + 0.8615, 0.8615, 0.8615, 0.8615, 0.8615, 0.8615, 0.8615 ; + + fates_trs_seedling_mdd_crit = 1400000, 1400000, 1400000, 1400000, 1400000, + 1400000, 1400000, 1400000, 1400000, 1400000, 1400000, 1400000 ; + + fates_trs_seedling_par_crit_germ = 0.656, 0.656, 0.656, 0.656, 0.656, 0.656, + 0.656, 0.656, 0.656, 0.656, 0.656, 0.656 ; + + fates_trs_seedling_psi_crit = -251995.7, -251995.7, -251995.7, -251995.7, + -251995.7, -251995.7, -251995.7, -251995.7, -251995.7, -251995.7, + -251995.7, -251995.7 ; + + fates_trs_seedling_psi_emerg = -15744.65, -15744.65, -15744.65, -15744.65, + -15744.65, -15744.65, -15744.65, -15744.65, -15744.65, -15744.65, + -15744.65, -15744.65 ; + + fates_trs_seedling_root_depth = 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, + 0.06, 0.06, 0.06, 0.06, 0.06 ; + + fates_turb_displar = 0.67, 0.67, 0.67, 0.67, 0.67, 0.67, 0.67, 0.67, 0.67, + 0.67, 0.67, 0.67 ; + + fates_turb_leaf_diameter = 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, + 0.04, 0.04, 0.04, 0.04 ; + + fates_turb_z0mr = 0.055, 0.055, 0.055, 0.055, 0.055, 0.055, 0.055, 0.055, + 0.055, 0.055, 0.055, 0.055 ; + + fates_turnover_branch = 150, 150, 150, 150, 150, 150, 150, 150, 150, 0, 0, 0 ; + + fates_turnover_fnrt = 1, 2, 1, 1.5, 1, 1, 1.5, 1, 1, 1, 1, 1 ; + + fates_turnover_leaf = + 1.5, 4, 1, 1.5, 1, 1, 1.5, 1, 1, 1, 1, 1 ; + + fates_turnover_senleaf_fdrought = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_wood_density = 0.548327, 0.44235, 0.454845, 0.754336, 0.548327, + 0.566452, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7 ; + + fates_woody = 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 ; + + fates_hlm_pft_map = + 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 ; + + fates_fire_FBD = 15.4, 16.8, 19.6, 999, 4, 4 ; + + fates_fire_low_moisture_Coeff = 1.12, 1.09, 0.98, 0.8, 1.15, 1.15 ; + + fates_fire_low_moisture_Slope = 0.62, 0.72, 0.85, 0.8, 0.62, 0.62 ; + + fates_fire_mid_moisture = 0.72, 0.51, 0.38, 1, 0.8, 0.8 ; + + fates_fire_mid_moisture_Coeff = 2.35, 1.47, 1.06, 0.8, 3.2, 3.2 ; + + fates_fire_mid_moisture_Slope = 2.35, 1.47, 1.06, 0.8, 3.2, 3.2 ; + + fates_fire_min_moisture = 0.18, 0.12, 0, 0, 0.24, 0.24 ; + + fates_fire_SAV = 13, 3.58, 0.98, 0.2, 66, 66 ; + + fates_frag_maxdecomp = 0.52, 0.383, 0.383, 0.19, 1, 999 ; + + fates_frag_cwd_frac = 0.045, 0.075, 0.21, 0.67 ; + + fates_maxpatches_by_landuse = 9, 4, 1, 1, 1 ; + + fates_canopy_closure_thresh = 0.8 ; + + fates_cnp_eca_plant_escalar = 1.25e-05 ; + + fates_cohort_age_fusion_tol = 0.08 ; + + fates_cohort_size_fusion_tol = 0.08 ; + + fates_comp_excln = 3 ; + + fates_damage_canopy_layer_code = 1 ; + + fates_damage_event_code = 1 ; + + fates_dev_arbitrary = _ ; + + fates_fire_active_crown_fire = 0 ; + + fates_fire_cg_strikes = 0.2 ; + + fates_fire_drying_ratio = 66000 ; + + fates_fire_durat_slope = -11.06 ; + + fates_fire_fdi_a = 17.62 ; + + fates_fire_fdi_alpha = 0.00037 ; + + fates_fire_fdi_b = 243.12 ; + + fates_fire_fuel_energy = 18000 ; + + fates_fire_max_durat = 240 ; + + fates_fire_miner_damp = 0.41739 ; + + fates_fire_miner_total = 0.055 ; + + fates_fire_nignitions = 15 ; + + fates_fire_part_dens = 513 ; + + fates_fire_threshold = 50 ; + + fates_frag_cwd_fcel = 0.76 ; + + fates_frag_cwd_flig = 0.24 ; + + fates_hydro_kmax_rsurf1 = 20 ; + + fates_hydro_kmax_rsurf2 = 0.0001 ; + + fates_hydro_psi0 = 0 ; + + fates_hydro_psicap = -0.6 ; + + fates_hydro_solver = 1 ; + + fates_landuse_logging_coll_under_frac = 0.55983 ; + + fates_landuse_logging_collateral_frac = 0.05 ; + + fates_landuse_logging_dbhmax = _ ; + + fates_landuse_logging_dbhmax_infra = 35 ; + + fates_landuse_logging_dbhmin = 50 ; + + fates_landuse_logging_direct_frac = 0.15 ; + + fates_landuse_logging_event_code = -30 ; + + fates_landuse_logging_export_frac = 0.8 ; + + fates_landuse_logging_mechanical_frac = 0.05 ; + + fates_landuse_pprodharv10_forest_mean = 0.8125 ; + + fates_leaf_photo_temp_acclim_thome_time = 30 ; + + fates_leaf_photo_temp_acclim_timescale = 30 ; + + fates_leaf_photo_tempsens_model = 1 ; + + fates_leaf_stomatal_assim_model = 1 ; + + fates_leaf_stomatal_model = 1 ; + + fates_leaf_theta_cj_c3 = 0.999 ; + + fates_leaf_theta_cj_c4 = 0.999 ; + + fates_maintresp_leaf_model = 1 ; + + fates_maintresp_nonleaf_baserate = 2.525e-06 ; + + fates_maxcohort = 100 ; + + fates_mort_disturb_frac = 1 ; + + fates_mort_understorey_death = 0.55983 ; + + fates_patch_fusion_tol = 0.05 ; + + fates_phen_chilltemp = 5 ; + + fates_phen_coldtemp = 7.5 ; + + fates_phen_gddthresh_a = -68 ; + + fates_phen_gddthresh_b = 638 ; + + fates_phen_gddthresh_c = -0.01 ; + + fates_phen_mindayson = 90 ; + + fates_phen_ncolddayslim = 5 ; + + fates_q10_froz = 1.5 ; + + fates_q10_mr = 1.5 ; + + fates_rad_model = 1 ; + + fates_regeneration_model = 1 ; + + fates_soil_salinity = 0.4 ; + + fates_trs_seedling2sap_par_timescale = 32 ; + + fates_trs_seedling_emerg_h2o_timescale = 7 ; + + fates_trs_seedling_mdd_timescale = 126 ; + + fates_trs_seedling_mort_par_timescale = 32 ; + + fates_vai_top_bin_width = 1 ; + + fates_vai_width_increase_factor = 1 ; +} diff --git a/parameter_files/archive/api34.0.0_032624_patch_params.xml b/parameter_files/archive/api34.0.0_032624_patch_params.xml new file mode 100644 index 0000000000..1d9f263da6 --- /dev/null +++ b/parameter_files/archive/api34.0.0_032624_patch_params.xml @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + archive/api34.0.0_032624_params_default.cdl + fates_params_default.cdl + 1,2,3,4,5,6,7,8,9,10,11,12 + + + fates_mort_upthresh_cstarvation + + + fates_mort_upthresh_cstarvation + fates_pft + unitless + threshold for storage biomass (relative to target leaf biomass) above which carbon starvation is zero + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 + + + fates_phen_stress_decid + + + fates_phen_stress_decid + fates_pft + logical flag + Flag for stress/drought-deciduous leaf habit. 0 - not stress deciduous; 1 - default drought deciduous (two target states only, fully flushed or fully abscised); 2 - semi-deciduous + 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1 + + + fates_allom_crown_depth_frac + + + fates_allom_dmode + fates_pft + index + crown depth allometry function index + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 + + + fates_allom_h2cd1 + fates_pft + variable + Parameter 1 for h2cd allometry (exp(log-intercept) or scaling). If allom_dmode=1; this is the same as former crown_depth_frac parameter + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.95, 0.95, 0.95, 1, 1, 1 + + + fates_allom_h2cd2 + fates_pft + variable + Parameter 2 for h2cd allometry (log-slope or exponent). If allom_dmode=1; this is not needed (as exponent is assumed 1) + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 + + + fates_cnp_eca_alpha_ptase + + + fates_cnp_eca_lambda_ptase + + + fates_cnp_eca_alpha_ptase + fates_pft + g/m3 + (INACTIVE, KEEP AT 0) fraction of P from ptase activity sent directly to plant (ECA) + 0,0,0,0,0,0,0,0,0,0,0,0 + + + fates_cnp_eca_lambda_ptase + fates_pft + g/m3 + (INACTIVE, KEEP AT 0) critical value for biochemical production (ECA) + 0,0,0,0,0,0,0,0,0,0,0,0 + + + fates_leafn_vert_scaler_coeff1 + fates_pft + unitless + Coefficient one for decrease in leaf nitrogen through the canopy, from Lloyd et al. 2010. + 0.00963, 0.00963, 0.00963, 0.00963, 0.00963, 0.00963, 0.00963, 0.00963, 0.00963, 0.00963, 0.00963, 0.00963 + + + fates_leafn_vert_scaler_coeff2 + fates_pft + unitless + Coefficient two for decrease in leaf nitrogen through the canopy, from Lloyd et al. 2010. + 2.43, 2.43, 2.43, 2.43, 2.43, 2.43, 2.43, 2.43, 2.43, 2.43, 2.43, 2.43 + + + fates_maintresp_leaf_vert_scaler_coeff1 + fates_pft + unitless + Leaf maintenance respiration decrease through the canopy. Only applies to Atkin et al. 2017. For proportionality between photosynthesis and respiration through the canopy, match with fates_leafn_vert_scaler_coeff1. + 0.00963, 0.00963, 0.00963, 0.00963, 0.00963, 0.00963, 0.00963, 0.00963, 0.00963, 0.00963, 0.00963, 0.00963 + + + fates_maintresp_leaf_vert_scaler_coeff2 + fates_pft + unitless + Leaf maintenance respiration decrease through the canopy. Only applies to Atkin et al. 2017. For proportionality between photosynthesis and respiration through the canopy, match with fates_leafn_vert_scaler_coeff2. + 2.43, 2.43, 2.43, 2.43, 2.43, 2.43, 2.43, 2.43, 2.43, 2.43, 2.43, 2.43 + + + fates_daylength_factor_switch + scalar + unitless + user switch for turning on (1) or off (0) the day length factor scaling for photosynthetic parameters (ie scale vcmax and jmax) + 1 + + + fates_mort_cstarvation_model + scalar + unitless + switch defining the carbon starvation model ( 1) Linear or 2) Exponential) in the mortality_rates function. + 1 + + + + + diff --git a/parameter_files/archive/api36.0.0_051724_params_default.cdl b/parameter_files/archive/api36.0.0_051724_params_default.cdl new file mode 100644 index 0000000000..2a909ee340 --- /dev/null +++ b/parameter_files/archive/api36.0.0_051724_params_default.cdl @@ -0,0 +1,1776 @@ +netcdf tmp { +dimensions: + fates_NCWD = 4 ; + fates_history_age_bins = 7 ; + fates_history_coage_bins = 2 ; + fates_history_damage_bins = 2 ; + fates_history_height_bins = 6 ; + fates_history_size_bins = 13 ; + fates_hlm_pftno = 14 ; + fates_hydr_organs = 4 ; + fates_landuseclass = 5 ; + fates_leafage_class = 1 ; + fates_litterclass = 6 ; + fates_pft = 12 ; + fates_plant_organs = 4 ; + fates_string_length = 60 ; +variables: + double fates_history_ageclass_bin_edges(fates_history_age_bins) ; + fates_history_ageclass_bin_edges:units = "yr" ; + fates_history_ageclass_bin_edges:long_name = "Lower edges for age class bins used in age-resolved patch history output" ; + double fates_history_coageclass_bin_edges(fates_history_coage_bins) ; + fates_history_coageclass_bin_edges:units = "years" ; + fates_history_coageclass_bin_edges:long_name = "Lower edges for cohort age class bins used in cohort age resolved history output" ; + double fates_history_height_bin_edges(fates_history_height_bins) ; + fates_history_height_bin_edges:units = "m" ; + fates_history_height_bin_edges:long_name = "Lower edges for height bins used in height-resolved history output" ; + double fates_history_damage_bin_edges(fates_history_damage_bins) ; + fates_history_damage_bin_edges:units = "% crown loss" ; + fates_history_damage_bin_edges:long_name = "Lower edges for damage class bins used in cohort history output" ; + double fates_history_sizeclass_bin_edges(fates_history_size_bins) ; + fates_history_sizeclass_bin_edges:units = "cm" ; + fates_history_sizeclass_bin_edges:long_name = "Lower edges for DBH size class bins used in size-resolved cohort history output" ; + double fates_alloc_organ_id(fates_plant_organs) ; + fates_alloc_organ_id:units = "unitless" ; + fates_alloc_organ_id:long_name = "This is the global index that the organ in this file is associated with, values match those in parteh/PRTGenericMod.F90" ; + double fates_hydro_htftype_node(fates_hydr_organs) ; + fates_hydro_htftype_node:units = "unitless" ; + fates_hydro_htftype_node:long_name = "Switch that defines the hydraulic transfer functions for each organ." ; + char fates_pftname(fates_pft, fates_string_length) ; + fates_pftname:units = "unitless - string" ; + fates_pftname:long_name = "Description of plant type" ; + char fates_hydro_organ_name(fates_hydr_organs, fates_string_length) ; + fates_hydro_organ_name:units = "unitless - string" ; + fates_hydro_organ_name:long_name = "Name of plant hydraulics organs (DONT CHANGE, order matches media list in FatesHydraulicsMemMod.F90)" ; + char fates_alloc_organ_name(fates_plant_organs, fates_string_length) ; + fates_alloc_organ_name:units = "unitless - string" ; + fates_alloc_organ_name:long_name = "Name of plant organs (with alloc_organ_id, must match PRTGenericMod.F90)" ; + char fates_landuseclass_name(fates_landuseclass, fates_string_length) ; + fates_landuseclass_name:units = "unitless - string" ; + fates_landuseclass_name:long_name = "Name of the land use classes, for variables associated with dimension fates_landuseclass" ; + char fates_litterclass_name(fates_litterclass, fates_string_length) ; + fates_litterclass_name:units = "unitless - string" ; + fates_litterclass_name:long_name = "Name of the litter classes, for variables associated with dimension fates_litterclass" ; + double fates_alloc_organ_priority(fates_plant_organs, fates_pft) ; + fates_alloc_organ_priority:units = "index" ; + fates_alloc_organ_priority:long_name = "Priority level for allocation, 1: replaces turnover from storage, 2: same priority as storage use/replacement, 3: ascending in order of least importance" ; + double fates_alloc_storage_cushion(fates_pft) ; + fates_alloc_storage_cushion:units = "fraction" ; + fates_alloc_storage_cushion:long_name = "maximum size of storage C pool, relative to maximum size of leaf C pool" ; + double fates_alloc_store_priority_frac(fates_pft) ; + fates_alloc_store_priority_frac:units = "unitless" ; + fates_alloc_store_priority_frac:long_name = "for high-priority organs, the fraction of their turnover demand that is gauranteed to be replaced, and if need-be by storage" ; + double fates_allom_agb1(fates_pft) ; + fates_allom_agb1:units = "variable" ; + fates_allom_agb1:long_name = "Parameter 1 for agb allometry" ; + double fates_allom_agb2(fates_pft) ; + fates_allom_agb2:units = "variable" ; + fates_allom_agb2:long_name = "Parameter 2 for agb allometry" ; + double fates_allom_agb3(fates_pft) ; + fates_allom_agb3:units = "variable" ; + fates_allom_agb3:long_name = "Parameter 3 for agb allometry" ; + double fates_allom_agb4(fates_pft) ; + fates_allom_agb4:units = "variable" ; + fates_allom_agb4:long_name = "Parameter 4 for agb allometry" ; + double fates_allom_agb_frac(fates_pft) ; + fates_allom_agb_frac:units = "fraction" ; + fates_allom_agb_frac:long_name = "Fraction of woody biomass that is above ground" ; + double fates_allom_amode(fates_pft) ; + fates_allom_amode:units = "index" ; + fates_allom_amode:long_name = "AGB allometry function index." ; + double fates_allom_blca_expnt_diff(fates_pft) ; + fates_allom_blca_expnt_diff:units = "unitless" ; + fates_allom_blca_expnt_diff:long_name = "difference between allometric DBH:bleaf and DBH:crown area exponents" ; + double fates_allom_cmode(fates_pft) ; + fates_allom_cmode:units = "index" ; + fates_allom_cmode:long_name = "coarse root biomass allometry function index." ; + double fates_allom_d2bl1(fates_pft) ; + fates_allom_d2bl1:units = "variable" ; + fates_allom_d2bl1:long_name = "Parameter 1 for d2bl allometry" ; + double fates_allom_d2bl2(fates_pft) ; + fates_allom_d2bl2:units = "variable" ; + fates_allom_d2bl2:long_name = "Parameter 2 for d2bl allometry" ; + double fates_allom_d2bl3(fates_pft) ; + fates_allom_d2bl3:units = "unitless" ; + fates_allom_d2bl3:long_name = "Parameter 3 for d2bl allometry" ; + double fates_allom_d2ca_coefficient_max(fates_pft) ; + fates_allom_d2ca_coefficient_max:units = "m2 cm^(-1/beta)" ; + fates_allom_d2ca_coefficient_max:long_name = "max (savanna) dbh to area multiplier factor where: area = n*d2ca_coeff*dbh^beta" ; + double fates_allom_d2ca_coefficient_min(fates_pft) ; + fates_allom_d2ca_coefficient_min:units = "m2 cm^(-1/beta)" ; + fates_allom_d2ca_coefficient_min:long_name = "min (forest) dbh to area multiplier factor where: area = n*d2ca_coeff*dbh^beta" ; + double fates_allom_d2h1(fates_pft) ; + fates_allom_d2h1:units = "variable" ; + fates_allom_d2h1:long_name = "Parameter 1 for d2h allometry (intercept, or c)" ; + double fates_allom_d2h2(fates_pft) ; + fates_allom_d2h2:units = "variable" ; + fates_allom_d2h2:long_name = "Parameter 2 for d2h allometry (slope, or m)" ; + double fates_allom_d2h3(fates_pft) ; + fates_allom_d2h3:units = "variable" ; + fates_allom_d2h3:long_name = "Parameter 3 for d2h allometry (optional)" ; + double fates_allom_dbh_maxheight(fates_pft) ; + fates_allom_dbh_maxheight:units = "cm" ; + fates_allom_dbh_maxheight:long_name = "the diameter (if any) corresponding to maximum height, diameters may increase beyond this" ; + double fates_allom_dmode(fates_pft) ; + fates_allom_dmode:units = "index" ; + fates_allom_dmode:long_name = "crown depth allometry function index" ; + double fates_allom_fmode(fates_pft) ; + fates_allom_fmode:units = "index" ; + fates_allom_fmode:long_name = "fine root biomass allometry function index." ; + double fates_allom_fnrt_prof_a(fates_pft) ; + fates_allom_fnrt_prof_a:units = "unitless" ; + fates_allom_fnrt_prof_a:long_name = "Fine root profile function, parameter a" ; + double fates_allom_fnrt_prof_b(fates_pft) ; + fates_allom_fnrt_prof_b:units = "unitless" ; + fates_allom_fnrt_prof_b:long_name = "Fine root profile function, parameter b" ; + double fates_allom_fnrt_prof_mode(fates_pft) ; + fates_allom_fnrt_prof_mode:units = "index" ; + fates_allom_fnrt_prof_mode:long_name = "Index to select fine root profile function: 1) Jackson Beta, 2) 1-param exponential 3) 2-param exponential" ; + double fates_allom_frbstor_repro(fates_pft) ; + fates_allom_frbstor_repro:units = "fraction" ; + fates_allom_frbstor_repro:long_name = "fraction of bstore goes to reproduction after plant dies" ; + double fates_allom_h2cd1(fates_pft) ; + fates_allom_h2cd1:units = "variable" ; + fates_allom_h2cd1:long_name = "Parameter 1 for h2cd allometry (exp(log-intercept) or scaling). If allom_dmode=1; this is the same as former crown_depth_frac parameter" ; + double fates_allom_h2cd2(fates_pft) ; + fates_allom_h2cd2:units = "variable" ; + fates_allom_h2cd2:long_name = "Parameter 2 for h2cd allometry (log-slope or exponent). If allom_dmode=1; this is not needed (as exponent is assumed 1)" ; + double fates_allom_hmode(fates_pft) ; + fates_allom_hmode:units = "index" ; + fates_allom_hmode:long_name = "height allometry function index." ; + double fates_allom_l2fr(fates_pft) ; + fates_allom_l2fr:units = "gC/gC" ; + fates_allom_l2fr:long_name = "Allocation parameter: fine root C per leaf C" ; + double fates_allom_la_per_sa_int(fates_pft) ; + fates_allom_la_per_sa_int:units = "m2/cm2" ; + fates_allom_la_per_sa_int:long_name = "Leaf area per sapwood area, intercept" ; + double fates_allom_la_per_sa_slp(fates_pft) ; + fates_allom_la_per_sa_slp:units = "m2/cm2/m" ; + fates_allom_la_per_sa_slp:long_name = "Leaf area per sapwood area rate of change with height, slope (optional)" ; + double fates_allom_lmode(fates_pft) ; + fates_allom_lmode:units = "index" ; + fates_allom_lmode:long_name = "leaf biomass allometry function index." ; + double fates_allom_sai_scaler(fates_pft) ; + fates_allom_sai_scaler:units = "m2/m2" ; + fates_allom_sai_scaler:long_name = "allometric ratio of SAI per LAI" ; + double fates_allom_smode(fates_pft) ; + fates_allom_smode:units = "index" ; + fates_allom_smode:long_name = "sapwood allometry function index." ; + double fates_allom_stmode(fates_pft) ; + fates_allom_stmode:units = "index" ; + fates_allom_stmode:long_name = "storage allometry function index: 1) Storage proportional to leaf biomass (with trimming), 2) Storage proportional to maximum leaf biomass (not trimmed)" ; + double fates_allom_zroot_k(fates_pft) ; + fates_allom_zroot_k:units = "unitless" ; + fates_allom_zroot_k:long_name = "scale coefficient of logistic rooting depth model" ; + double fates_allom_zroot_max_dbh(fates_pft) ; + fates_allom_zroot_max_dbh:units = "cm" ; + fates_allom_zroot_max_dbh:long_name = "dbh at which a plant reaches the maximum value for its maximum rooting depth" ; + double fates_allom_zroot_max_z(fates_pft) ; + fates_allom_zroot_max_z:units = "m" ; + fates_allom_zroot_max_z:long_name = "the maximum rooting depth defined at dbh = fates_allom_zroot_max_dbh. note: max_z=min_z=large, sets rooting depth to soil depth" ; + double fates_allom_zroot_min_dbh(fates_pft) ; + fates_allom_zroot_min_dbh:units = "cm" ; + fates_allom_zroot_min_dbh:long_name = "dbh at which the maximum rooting depth for a recruit is defined" ; + double fates_allom_zroot_min_z(fates_pft) ; + fates_allom_zroot_min_z:units = "m" ; + fates_allom_zroot_min_z:long_name = "the maximum rooting depth defined at dbh = fates_allom_zroot_min_dbh. note: max_z=min_z=large, sets rooting depth to soil depth" ; + double fates_c2b(fates_pft) ; + fates_c2b:units = "ratio" ; + fates_c2b:long_name = "Carbon to biomass multiplier of bulk structural tissues" ; + double fates_cnp_eca_alpha_ptase(fates_pft) ; + fates_cnp_eca_alpha_ptase:units = "g/m3" ; + fates_cnp_eca_alpha_ptase:long_name = "(INACTIVE, KEEP AT 0) fraction of P from ptase activity sent directly to plant (ECA)" ; + double fates_cnp_eca_decompmicc(fates_pft) ; + fates_cnp_eca_decompmicc:units = "gC/m3" ; + fates_cnp_eca_decompmicc:long_name = "maximum soil microbial decomposer biomass found over depth (will be applied at a reference depth w/ exponential attenuation) (ECA)" ; + double fates_cnp_eca_km_nh4(fates_pft) ; + fates_cnp_eca_km_nh4:units = "gN/m3" ; + fates_cnp_eca_km_nh4:long_name = "half-saturation constant for plant nh4 uptake (ECA)" ; + double fates_cnp_eca_km_no3(fates_pft) ; + fates_cnp_eca_km_no3:units = "gN/m3" ; + fates_cnp_eca_km_no3:long_name = "half-saturation constant for plant no3 uptake (ECA)" ; + double fates_cnp_eca_km_p(fates_pft) ; + fates_cnp_eca_km_p:units = "gP/m3" ; + fates_cnp_eca_km_p:long_name = "half-saturation constant for plant p uptake (ECA)" ; + double fates_cnp_eca_km_ptase(fates_pft) ; + fates_cnp_eca_km_ptase:units = "gP/m3" ; + fates_cnp_eca_km_ptase:long_name = "half-saturation constant for biochemical P (ECA)" ; + double fates_cnp_eca_lambda_ptase(fates_pft) ; + fates_cnp_eca_lambda_ptase:units = "g/m3" ; + fates_cnp_eca_lambda_ptase:long_name = "(INACTIVE, KEEP AT 0) critical value for biochemical production (ECA)" ; + double fates_cnp_eca_vmax_ptase(fates_pft) ; + fates_cnp_eca_vmax_ptase:units = "gP/m2/s" ; + fates_cnp_eca_vmax_ptase:long_name = "maximum production rate for biochemical P (per m2) (ECA)" ; + double fates_cnp_nfix1(fates_pft) ; + fates_cnp_nfix1:units = "fraction" ; + fates_cnp_nfix1:long_name = "fractional surcharge added to maintenance respiration that drives symbiotic fixation" ; + double fates_cnp_nitr_store_ratio(fates_pft) ; + fates_cnp_nitr_store_ratio:units = "(gN/gN)" ; + fates_cnp_nitr_store_ratio:long_name = "storeable (labile) N, as a ratio compared to the N bound in cell structures of other organs (see code)" ; + double fates_cnp_phos_store_ratio(fates_pft) ; + fates_cnp_phos_store_ratio:units = "(gP/gP)" ; + fates_cnp_phos_store_ratio:long_name = "storeable (labile) P, as a ratio compared to the P bound in cell structures of other organs (see code)" ; + double fates_cnp_pid_kd(fates_pft) ; + fates_cnp_pid_kd:units = "unknown" ; + fates_cnp_pid_kd:long_name = "derivative constant of the PID controller on adaptive fine-root biomass" ; + double fates_cnp_pid_ki(fates_pft) ; + fates_cnp_pid_ki:units = "unknown" ; + fates_cnp_pid_ki:long_name = "integral constant of the PID controller on adaptive fine-root biomass" ; + double fates_cnp_pid_kp(fates_pft) ; + fates_cnp_pid_kp:units = "unknown" ; + fates_cnp_pid_kp:long_name = "proportional constant of the PID controller on adaptive fine-root biomass" ; + double fates_cnp_prescribed_nuptake(fates_pft) ; + fates_cnp_prescribed_nuptake:units = "fraction" ; + fates_cnp_prescribed_nuptake:long_name = "Prescribed N uptake flux. 0=fully coupled simulation >0=prescribed (experimental)" ; + double fates_cnp_prescribed_puptake(fates_pft) ; + fates_cnp_prescribed_puptake:units = "fraction" ; + fates_cnp_prescribed_puptake:long_name = "Prescribed P uptake flux. 0=fully coupled simulation, >0=prescribed (experimental)" ; + double fates_cnp_store_ovrflw_frac(fates_pft) ; + fates_cnp_store_ovrflw_frac:units = "fraction" ; + fates_cnp_store_ovrflw_frac:long_name = "size of overflow storage (for excess C,N or P) as a fraction of storage target" ; + double fates_cnp_turnover_nitr_retrans(fates_plant_organs, fates_pft) ; + fates_cnp_turnover_nitr_retrans:units = "fraction" ; + fates_cnp_turnover_nitr_retrans:long_name = "retranslocation (reabsorbtion) fraction of nitrogen in turnover of scenescing tissues" ; + double fates_cnp_turnover_phos_retrans(fates_plant_organs, fates_pft) ; + fates_cnp_turnover_phos_retrans:units = "fraction" ; + fates_cnp_turnover_phos_retrans:long_name = "retranslocation (reabsorbtion) fraction of phosphorus in turnover of scenescing tissues" ; + double fates_cnp_vmax_nh4(fates_pft) ; + fates_cnp_vmax_nh4:units = "gN/gC/s" ; + fates_cnp_vmax_nh4:long_name = "maximum (potential) uptake rate of NH4 per gC of fineroot biomass (see main/EDPftvarcon.F90 vmax_nh4 for usage)" ; + double fates_cnp_vmax_no3(fates_pft) ; + fates_cnp_vmax_no3:units = "gN/gC/s" ; + fates_cnp_vmax_no3:long_name = "maximum (potential) uptake rate of NO3 per gC of fineroot biomass (see main/EDPftvarcon.F90 vmax_no3 for usage)" ; + double fates_cnp_vmax_p(fates_pft) ; + fates_cnp_vmax_p:units = "gP/gC/s" ; + fates_cnp_vmax_p:long_name = "maximum production rate for phosphorus (ECA and RD)" ; + double fates_damage_frac(fates_pft) ; + fates_damage_frac:units = "fraction" ; + fates_damage_frac:long_name = "fraction of cohort damaged in each damage event (event frequency specified in the is_it_damage_time subroutine)" ; + double fates_damage_mort_p1(fates_pft) ; + fates_damage_mort_p1:units = "fraction" ; + fates_damage_mort_p1:long_name = "inflection point of damage mortality function, a value of 0.8 means 50% mortality with 80% loss of crown, turn off with a large number" ; + double fates_damage_mort_p2(fates_pft) ; + fates_damage_mort_p2:units = "unitless" ; + fates_damage_mort_p2:long_name = "rate of mortality increase with damage" ; + double fates_damage_recovery_scalar(fates_pft) ; + fates_damage_recovery_scalar:units = "unitless" ; + fates_damage_recovery_scalar:long_name = "fraction of the cohort that recovers from damage" ; + double fates_dev_arbitrary_pft(fates_pft) ; + fates_dev_arbitrary_pft:units = "unknown" ; + fates_dev_arbitrary_pft:long_name = "Unassociated pft dimensioned free parameter that developers can use for testing arbitrary new hypotheses" ; + double fates_fire_alpha_SH(fates_pft) ; + fates_fire_alpha_SH:units = "m / (kw/m)**(2/3)" ; + fates_fire_alpha_SH:long_name = "spitfire parameter, alpha scorch height, Equation 16 Thonicke et al 2010" ; + double fates_fire_bark_scaler(fates_pft) ; + fates_fire_bark_scaler:units = "fraction" ; + fates_fire_bark_scaler:long_name = "the thickness of a cohorts bark as a fraction of its dbh" ; + double fates_fire_crown_kill(fates_pft) ; + fates_fire_crown_kill:units = "NA" ; + fates_fire_crown_kill:long_name = "fire parameter, see equation 22 in Thonicke et al 2010" ; + double fates_frag_fnrt_fcel(fates_pft) ; + fates_frag_fnrt_fcel:units = "fraction" ; + fates_frag_fnrt_fcel:long_name = "Fine root litter cellulose fraction" ; + double fates_frag_fnrt_flab(fates_pft) ; + fates_frag_fnrt_flab:units = "fraction" ; + fates_frag_fnrt_flab:long_name = "Fine root litter labile fraction" ; + double fates_frag_fnrt_flig(fates_pft) ; + fates_frag_fnrt_flig:units = "fraction" ; + fates_frag_fnrt_flig:long_name = "Fine root litter lignin fraction" ; + double fates_frag_leaf_fcel(fates_pft) ; + fates_frag_leaf_fcel:units = "fraction" ; + fates_frag_leaf_fcel:long_name = "Leaf litter cellulose fraction" ; + double fates_frag_leaf_flab(fates_pft) ; + fates_frag_leaf_flab:units = "fraction" ; + fates_frag_leaf_flab:long_name = "Leaf litter labile fraction" ; + double fates_frag_leaf_flig(fates_pft) ; + fates_frag_leaf_flig:units = "fraction" ; + fates_frag_leaf_flig:long_name = "Leaf litter lignin fraction" ; + double fates_frag_seed_decay_rate(fates_pft) ; + fates_frag_seed_decay_rate:units = "yr-1" ; + fates_frag_seed_decay_rate:long_name = "fraction of seeds that decay per year" ; + double fates_grperc(fates_pft) ; + fates_grperc:units = "unitless" ; + fates_grperc:long_name = "Growth respiration factor" ; + double fates_hydro_avuln_gs(fates_pft) ; + fates_hydro_avuln_gs:units = "unitless" ; + fates_hydro_avuln_gs:long_name = "shape parameter for stomatal control of water vapor exiting leaf" ; + double fates_hydro_avuln_node(fates_hydr_organs, fates_pft) ; + fates_hydro_avuln_node:units = "unitless" ; + fates_hydro_avuln_node:long_name = "xylem vulnerability curve shape parameter" ; + double fates_hydro_epsil_node(fates_hydr_organs, fates_pft) ; + fates_hydro_epsil_node:units = "MPa" ; + fates_hydro_epsil_node:long_name = "bulk elastic modulus" ; + double fates_hydro_fcap_node(fates_hydr_organs, fates_pft) ; + fates_hydro_fcap_node:units = "unitless" ; + fates_hydro_fcap_node:long_name = "fraction of non-residual water that is capillary in source" ; + double fates_hydro_k_lwp(fates_pft) ; + fates_hydro_k_lwp:units = "unitless" ; + fates_hydro_k_lwp:long_name = "inner leaf humidity scaling coefficient" ; + double fates_hydro_kmax_node(fates_hydr_organs, fates_pft) ; + fates_hydro_kmax_node:units = "kg/MPa/m/s" ; + fates_hydro_kmax_node:long_name = "maximum xylem conductivity per unit conducting xylem area" ; + double fates_hydro_p50_gs(fates_pft) ; + fates_hydro_p50_gs:units = "MPa" ; + fates_hydro_p50_gs:long_name = "water potential at 50% loss of stomatal conductance" ; + double fates_hydro_p50_node(fates_hydr_organs, fates_pft) ; + fates_hydro_p50_node:units = "MPa" ; + fates_hydro_p50_node:long_name = "xylem water potential at 50% loss of conductivity" ; + double fates_hydro_p_taper(fates_pft) ; + fates_hydro_p_taper:units = "unitless" ; + fates_hydro_p_taper:long_name = "xylem taper exponent" ; + double fates_hydro_pinot_node(fates_hydr_organs, fates_pft) ; + fates_hydro_pinot_node:units = "MPa" ; + fates_hydro_pinot_node:long_name = "osmotic potential at full turgor" ; + double fates_hydro_pitlp_node(fates_hydr_organs, fates_pft) ; + fates_hydro_pitlp_node:units = "MPa" ; + fates_hydro_pitlp_node:long_name = "turgor loss point" ; + double fates_hydro_resid_node(fates_hydr_organs, fates_pft) ; + fates_hydro_resid_node:units = "cm3/cm3" ; + fates_hydro_resid_node:long_name = "residual water conent" ; + double fates_hydro_rfrac_stem(fates_pft) ; + fates_hydro_rfrac_stem:units = "fraction" ; + fates_hydro_rfrac_stem:long_name = "fraction of total tree resistance from troot to canopy" ; + double fates_hydro_rs2(fates_pft) ; + fates_hydro_rs2:units = "m" ; + fates_hydro_rs2:long_name = "absorbing root radius" ; + double fates_hydro_srl(fates_pft) ; + fates_hydro_srl:units = "m g-1" ; + fates_hydro_srl:long_name = "specific root length" ; + double fates_hydro_thetas_node(fates_hydr_organs, fates_pft) ; + fates_hydro_thetas_node:units = "cm3/cm3" ; + fates_hydro_thetas_node:long_name = "saturated water content" ; + double fates_hydro_vg_alpha_node(fates_hydr_organs, fates_pft) ; + fates_hydro_vg_alpha_node:units = "MPa-1" ; + fates_hydro_vg_alpha_node:long_name = "(used if hydr_htftype_node = 2), capillary length parameter in van Genuchten model" ; + double fates_hydro_vg_m_node(fates_hydr_organs, fates_pft) ; + fates_hydro_vg_m_node:units = "unitless" ; + fates_hydro_vg_m_node:long_name = "(used if hydr_htftype_node = 2),m in van Genuchten 1980 model, 2nd pore size distribution parameter" ; + double fates_hydro_vg_n_node(fates_hydr_organs, fates_pft) ; + fates_hydro_vg_n_node:units = "unitless" ; + fates_hydro_vg_n_node:long_name = "(used if hydr_htftype_node = 2),n in van Genuchten 1980 model, pore size distribution parameter" ; + double fates_leaf_c3psn(fates_pft) ; + fates_leaf_c3psn:units = "flag" ; + fates_leaf_c3psn:long_name = "Photosynthetic pathway (1=c3, 0=c4)" ; + double fates_leaf_jmaxha(fates_pft) ; + fates_leaf_jmaxha:units = "J/mol" ; + fates_leaf_jmaxha:long_name = "activation energy for jmax. NOTE: if fates_leaf_photo_tempsens_model=2 then these values are NOT USED" ; + double fates_leaf_jmaxhd(fates_pft) ; + fates_leaf_jmaxhd:units = "J/mol" ; + fates_leaf_jmaxhd:long_name = "deactivation energy for jmax. NOTE: if fates_leaf_photo_tempsens_model=2 then these values are NOT USED" ; + double fates_leaf_jmaxse(fates_pft) ; + fates_leaf_jmaxse:units = "J/mol/K" ; + fates_leaf_jmaxse:long_name = "entropy term for jmax. NOTE: if fates_leaf_photo_tempsens_model=2 then these values are NOT USED" ; + double fates_leaf_slamax(fates_pft) ; + fates_leaf_slamax:units = "m^2/gC" ; + fates_leaf_slamax:long_name = "Maximum Specific Leaf Area (SLA), even if under a dense canopy" ; + double fates_leaf_slatop(fates_pft) ; + fates_leaf_slatop:units = "m^2/gC" ; + fates_leaf_slatop:long_name = "Specific Leaf Area (SLA) at top of canopy, projected area basis" ; + double fates_leaf_stomatal_intercept(fates_pft) ; + fates_leaf_stomatal_intercept:units = "umol H2O/m**2/s" ; + fates_leaf_stomatal_intercept:long_name = "Minimum unstressed stomatal conductance for Ball-Berry model and Medlyn model" ; + double fates_leaf_stomatal_slope_ballberry(fates_pft) ; + fates_leaf_stomatal_slope_ballberry:units = "unitless" ; + fates_leaf_stomatal_slope_ballberry:long_name = "stomatal slope parameter, as per Ball-Berry" ; + double fates_leaf_stomatal_slope_medlyn(fates_pft) ; + fates_leaf_stomatal_slope_medlyn:units = "KPa**0.5" ; + fates_leaf_stomatal_slope_medlyn:long_name = "stomatal slope parameter, as per Medlyn" ; + double fates_leaf_vcmax25top(fates_leafage_class, fates_pft) ; + fates_leaf_vcmax25top:units = "umol CO2/m^2/s" ; + fates_leaf_vcmax25top:long_name = "maximum carboxylation rate of Rub. at 25C, canopy top" ; + double fates_leaf_vcmaxha(fates_pft) ; + fates_leaf_vcmaxha:units = "J/mol" ; + fates_leaf_vcmaxha:long_name = "activation energy for vcmax. NOTE: if fates_leaf_photo_tempsens_model=2 then these values are NOT USED" ; + double fates_leaf_vcmaxhd(fates_pft) ; + fates_leaf_vcmaxhd:units = "J/mol" ; + fates_leaf_vcmaxhd:long_name = "deactivation energy for vcmax. NOTE: if fates_leaf_photo_tempsens_model=2 then these values are NOT USED" ; + double fates_leaf_vcmaxse(fates_pft) ; + fates_leaf_vcmaxse:units = "J/mol/K" ; + fates_leaf_vcmaxse:long_name = "entropy term for vcmax. NOTE: if fates_leaf_photo_tempsens_model=2 then these values are NOT USED" ; + double fates_leafn_vert_scaler_coeff1(fates_pft) ; + fates_leafn_vert_scaler_coeff1:units = "unitless" ; + fates_leafn_vert_scaler_coeff1:long_name = "Coefficient one for decrease in leaf nitrogen through the canopy, from Lloyd et al. 2010." ; + double fates_leafn_vert_scaler_coeff2(fates_pft) ; + fates_leafn_vert_scaler_coeff2:units = "unitless" ; + fates_leafn_vert_scaler_coeff2:long_name = "Coefficient two for decrease in leaf nitrogen through the canopy, from Lloyd et al. 2010." ; + double fates_maintresp_leaf_atkin2017_baserate(fates_pft) ; + fates_maintresp_leaf_atkin2017_baserate:units = "umol CO2/m^2/s" ; + fates_maintresp_leaf_atkin2017_baserate:long_name = "Leaf maintenance respiration base rate parameter (r0) per Atkin et al 2017" ; + double fates_maintresp_leaf_ryan1991_baserate(fates_pft) ; + fates_maintresp_leaf_ryan1991_baserate:units = "gC/gN/s" ; + fates_maintresp_leaf_ryan1991_baserate:long_name = "Leaf maintenance respiration base rate per Ryan et al 1991" ; + double fates_maintresp_leaf_vert_scaler_coeff1(fates_pft) ; + fates_maintresp_leaf_vert_scaler_coeff1:units = "unitless" ; + fates_maintresp_leaf_vert_scaler_coeff1:long_name = "Leaf maintenance respiration decrease through the canopy. Only applies to Atkin et al. 2017. For proportionality between photosynthesis and respiration through the canopy, match with fates_leafn_vert_scaler_coeff1." ; + double fates_maintresp_leaf_vert_scaler_coeff2(fates_pft) ; + fates_maintresp_leaf_vert_scaler_coeff2:units = "unitless" ; + fates_maintresp_leaf_vert_scaler_coeff2:long_name = "Leaf maintenance respiration decrease through the canopy. Only applies to Atkin et al. 2017. For proportionality between photosynthesis and respiration through the canopy, match with fates_leafn_vert_scaler_coeff2." ; + double fates_maintresp_reduction_curvature(fates_pft) ; + fates_maintresp_reduction_curvature:units = "unitless (0-1)" ; + fates_maintresp_reduction_curvature:long_name = "curvature of MR reduction as f(carbon storage), 1=linear, 0=very curved" ; + double fates_maintresp_reduction_intercept(fates_pft) ; + fates_maintresp_reduction_intercept:units = "unitless (0-1)" ; + fates_maintresp_reduction_intercept:long_name = "intercept of MR reduction as f(carbon storage), 0=no throttling, 1=max throttling" ; + double fates_maintresp_reduction_upthresh(fates_pft) ; + fates_maintresp_reduction_upthresh:units = "unitless (0-1)" ; + fates_maintresp_reduction_upthresh:long_name = "upper threshold for storage biomass (relative to leaf biomass) above which MR is not reduced" ; + double fates_mort_bmort(fates_pft) ; + fates_mort_bmort:units = "1/yr" ; + fates_mort_bmort:long_name = "background mortality rate" ; + double fates_mort_freezetol(fates_pft) ; + fates_mort_freezetol:units = "degrees C" ; + fates_mort_freezetol:long_name = "minimum temperature tolerance" ; + double fates_mort_hf_flc_threshold(fates_pft) ; + fates_mort_hf_flc_threshold:units = "fraction" ; + fates_mort_hf_flc_threshold:long_name = "plant fractional loss of conductivity at which drought mortality begins for hydraulic model" ; + double fates_mort_hf_sm_threshold(fates_pft) ; + fates_mort_hf_sm_threshold:units = "unitless" ; + fates_mort_hf_sm_threshold:long_name = "soil moisture (btran units) at which drought mortality begins for non-hydraulic model" ; + double fates_mort_ip_age_senescence(fates_pft) ; + fates_mort_ip_age_senescence:units = "years" ; + fates_mort_ip_age_senescence:long_name = "Mortality cohort age senescence inflection point. If _ this mortality term is off. Setting this value turns on age dependent mortality. " ; + double fates_mort_ip_size_senescence(fates_pft) ; + fates_mort_ip_size_senescence:units = "dbh cm" ; + fates_mort_ip_size_senescence:long_name = "Mortality dbh senescence inflection point. If _ this mortality term is off. Setting this value turns on size dependent mortality" ; + double fates_mort_prescribed_canopy(fates_pft) ; + fates_mort_prescribed_canopy:units = "1/yr" ; + fates_mort_prescribed_canopy:long_name = "mortality rate of canopy trees for prescribed physiology mode" ; + double fates_mort_prescribed_understory(fates_pft) ; + fates_mort_prescribed_understory:units = "1/yr" ; + fates_mort_prescribed_understory:long_name = "mortality rate of understory trees for prescribed physiology mode" ; + double fates_mort_r_age_senescence(fates_pft) ; + fates_mort_r_age_senescence:units = "mortality rate year^-1" ; + fates_mort_r_age_senescence:long_name = "Mortality age senescence rate of change. Sensible range is around 0.03-0.06. Larger values givesteeper mortality curves." ; + double fates_mort_r_size_senescence(fates_pft) ; + fates_mort_r_size_senescence:units = "mortality rate dbh^-1" ; + fates_mort_r_size_senescence:long_name = "Mortality dbh senescence rate of change. Sensible range is around 0.03-0.06. Larger values give steeper mortality curves." ; + double fates_mort_scalar_coldstress(fates_pft) ; + fates_mort_scalar_coldstress:units = "1/yr" ; + fates_mort_scalar_coldstress:long_name = "maximum mortality rate from cold stress" ; + double fates_mort_scalar_cstarvation(fates_pft) ; + fates_mort_scalar_cstarvation:units = "1/yr" ; + fates_mort_scalar_cstarvation:long_name = "maximum mortality rate from carbon starvation" ; + double fates_mort_scalar_hydrfailure(fates_pft) ; + fates_mort_scalar_hydrfailure:units = "1/yr" ; + fates_mort_scalar_hydrfailure:long_name = "maximum mortality rate from hydraulic failure" ; + double fates_mort_upthresh_cstarvation(fates_pft) ; + fates_mort_upthresh_cstarvation:units = "unitless" ; + fates_mort_upthresh_cstarvation:long_name = "threshold for storage biomass (relative to target leaf biomass) above which carbon starvation is zero" ; + double fates_nonhydro_smpsc(fates_pft) ; + fates_nonhydro_smpsc:units = "mm" ; + fates_nonhydro_smpsc:long_name = "Soil water potential at full stomatal closure" ; + double fates_nonhydro_smpso(fates_pft) ; + fates_nonhydro_smpso:units = "mm" ; + fates_nonhydro_smpso:long_name = "Soil water potential at full stomatal opening" ; + double fates_phen_cold_size_threshold(fates_pft) ; + fates_phen_cold_size_threshold:units = "cm" ; + fates_phen_cold_size_threshold:long_name = "the dbh size above which will lead to phenology-related stem and leaf drop" ; + double fates_phen_drought_threshold(fates_pft) ; + fates_phen_drought_threshold:units = "m3/m3 or mm" ; + fates_phen_drought_threshold:long_name = "threshold for drought phenology (or lower threshold for semi-deciduous PFTs); the quantity depends on the sign: if positive, the threshold is volumetric soil moisture (m3/m3). If negative, the threshold is soil matric potentical (mm)" ; + double fates_phen_evergreen(fates_pft) ; + fates_phen_evergreen:units = "logical flag" ; + fates_phen_evergreen:long_name = "Binary flag for evergreen leaf habit" ; + double fates_phen_flush_fraction(fates_pft) ; + fates_phen_flush_fraction:units = "fraction" ; + fates_phen_flush_fraction:long_name = "Upon bud-burst, the maximum fraction of storage carbon used for flushing leaves" ; + double fates_phen_fnrt_drop_fraction(fates_pft) ; + fates_phen_fnrt_drop_fraction:units = "fraction" ; + fates_phen_fnrt_drop_fraction:long_name = "fraction of fine roots to drop during drought/cold" ; + double fates_phen_mindaysoff(fates_pft) ; + fates_phen_mindaysoff:units = "days" ; + fates_phen_mindaysoff:long_name = "day threshold compared against days since leaves abscised (shed)" ; + double fates_phen_moist_threshold(fates_pft) ; + fates_phen_moist_threshold:units = "m3/m3 or mm" ; + fates_phen_moist_threshold:long_name = "upper threshold for drought phenology (only for drought semi-deciduous PFTs); the quantity depends on the sign: if positive, the threshold is volumetric soil moisture (m3/m3). If negative, the threshold is soil matric potentical (mm)" ; + double fates_phen_season_decid(fates_pft) ; + fates_phen_season_decid:units = "logical flag" ; + fates_phen_season_decid:long_name = "Binary flag for seasonal-deciduous leaf habit" ; + double fates_phen_stem_drop_fraction(fates_pft) ; + fates_phen_stem_drop_fraction:units = "fraction" ; + fates_phen_stem_drop_fraction:long_name = "fraction of stems to drop for non-woody species during drought/cold" ; + double fates_phen_stress_decid(fates_pft) ; + fates_phen_stress_decid:units = "logical flag" ; + fates_phen_stress_decid:long_name = "Flag for stress/drought-deciduous leaf habit. 0 - not stress deciduous; 1 - default drought deciduous (two target states only, fully flushed or fully abscised); 2 - semi-deciduous" ; + double fates_prescribed_npp_canopy(fates_pft) ; + fates_prescribed_npp_canopy:units = "kgC / m^2 / yr" ; + fates_prescribed_npp_canopy:long_name = "NPP per unit crown area of canopy trees for prescribed physiology mode" ; + double fates_prescribed_npp_understory(fates_pft) ; + fates_prescribed_npp_understory:units = "kgC / m^2 / yr" ; + fates_prescribed_npp_understory:long_name = "NPP per unit crown area of understory trees for prescribed physiology mode" ; + double fates_rad_leaf_clumping_index(fates_pft) ; + fates_rad_leaf_clumping_index:units = "fraction (0-1)" ; + fates_rad_leaf_clumping_index:long_name = "factor describing how much self-occlusion of leaf scattering elements decreases light interception" ; + double fates_rad_leaf_rhonir(fates_pft) ; + fates_rad_leaf_rhonir:units = "fraction" ; + fates_rad_leaf_rhonir:long_name = "Leaf reflectance: near-IR" ; + double fates_rad_leaf_rhovis(fates_pft) ; + fates_rad_leaf_rhovis:units = "fraction" ; + fates_rad_leaf_rhovis:long_name = "Leaf reflectance: visible" ; + double fates_rad_leaf_taunir(fates_pft) ; + fates_rad_leaf_taunir:units = "fraction" ; + fates_rad_leaf_taunir:long_name = "Leaf transmittance: near-IR" ; + double fates_rad_leaf_tauvis(fates_pft) ; + fates_rad_leaf_tauvis:units = "fraction" ; + fates_rad_leaf_tauvis:long_name = "Leaf transmittance: visible" ; + double fates_rad_leaf_xl(fates_pft) ; + fates_rad_leaf_xl:units = "unitless" ; + fates_rad_leaf_xl:long_name = "Leaf/stem orientation index" ; + double fates_rad_stem_rhonir(fates_pft) ; + fates_rad_stem_rhonir:units = "fraction" ; + fates_rad_stem_rhonir:long_name = "Stem reflectance: near-IR" ; + double fates_rad_stem_rhovis(fates_pft) ; + fates_rad_stem_rhovis:units = "fraction" ; + fates_rad_stem_rhovis:long_name = "Stem reflectance: visible" ; + double fates_rad_stem_taunir(fates_pft) ; + fates_rad_stem_taunir:units = "fraction" ; + fates_rad_stem_taunir:long_name = "Stem transmittance: near-IR" ; + double fates_rad_stem_tauvis(fates_pft) ; + fates_rad_stem_tauvis:units = "fraction" ; + fates_rad_stem_tauvis:long_name = "Stem transmittance: visible" ; + double fates_recruit_height_min(fates_pft) ; + fates_recruit_height_min:units = "m" ; + fates_recruit_height_min:long_name = "the minimum height (ie starting height) of a newly recruited plant" ; + double fates_recruit_init_density(fates_pft) ; + fates_recruit_init_density:units = "stems/m2" ; + fates_recruit_init_density:long_name = "initial seedling density for a cold-start near-bare-ground simulation. If negative sets initial tree dbh - only to be used in nocomp mode" ; + double fates_recruit_prescribed_rate(fates_pft) ; + fates_recruit_prescribed_rate:units = "n/yr" ; + fates_recruit_prescribed_rate:long_name = "recruitment rate for prescribed physiology mode" ; + double fates_recruit_seed_alloc(fates_pft) ; + fates_recruit_seed_alloc:units = "fraction" ; + fates_recruit_seed_alloc:long_name = "fraction of available carbon balance allocated to seeds" ; + double fates_recruit_seed_alloc_mature(fates_pft) ; + fates_recruit_seed_alloc_mature:units = "fraction" ; + fates_recruit_seed_alloc_mature:long_name = "fraction of available carbon balance allocated to seeds in mature plants (adds to fates_seed_alloc)" ; + double fates_recruit_seed_dbh_repro_threshold(fates_pft) ; + fates_recruit_seed_dbh_repro_threshold:units = "cm" ; + fates_recruit_seed_dbh_repro_threshold:long_name = "the diameter where the plant will increase allocation to the seed pool by fraction: fates_recruit_seed_alloc_mature" ; + double fates_recruit_seed_germination_rate(fates_pft) ; + fates_recruit_seed_germination_rate:units = "yr-1" ; + fates_recruit_seed_germination_rate:long_name = "fraction of seeds that germinate per year" ; + double fates_recruit_seed_supplement(fates_pft) ; + fates_recruit_seed_supplement:units = "KgC/m2/yr" ; + fates_recruit_seed_supplement:long_name = "Supplemental external seed rain source term (non-mass conserving)" ; + double fates_seed_dispersal_fraction(fates_pft) ; + fates_seed_dispersal_fraction:units = "fraction" ; + fates_seed_dispersal_fraction:long_name = "fraction of seed rain to be dispersed to other grid cells" ; + double fates_seed_dispersal_max_dist(fates_pft) ; + fates_seed_dispersal_max_dist:units = "m" ; + fates_seed_dispersal_max_dist:long_name = "maximum seed dispersal distance for a given pft" ; + double fates_seed_dispersal_pdf_scale(fates_pft) ; + fates_seed_dispersal_pdf_scale:units = "unitless" ; + fates_seed_dispersal_pdf_scale:long_name = "seed dispersal probability density function scale parameter, A, Table 1 Bullock et al 2016" ; + double fates_seed_dispersal_pdf_shape(fates_pft) ; + fates_seed_dispersal_pdf_shape:units = "unitless" ; + fates_seed_dispersal_pdf_shape:long_name = "seed dispersal probability density function shape parameter, B, Table 1 Bullock et al 2016" ; + double fates_stoich_nitr(fates_plant_organs, fates_pft) ; + fates_stoich_nitr:units = "gN/gC" ; + fates_stoich_nitr:long_name = "target nitrogen concentration (ratio with carbon) of organs" ; + double fates_stoich_phos(fates_plant_organs, fates_pft) ; + fates_stoich_phos:units = "gP/gC" ; + fates_stoich_phos:long_name = "target phosphorus concentration (ratio with carbon) of organs" ; + double fates_trim_inc(fates_pft) ; + fates_trim_inc:units = "m2/m2" ; + fates_trim_inc:long_name = "Arbitrary incremental change in trimming function." ; + double fates_trim_limit(fates_pft) ; + fates_trim_limit:units = "m2/m2" ; + fates_trim_limit:long_name = "Arbitrary limit to reductions in leaf area with stress" ; + double fates_trs_repro_alloc_a(fates_pft) ; + fates_trs_repro_alloc_a:units = "fraction" ; + fates_trs_repro_alloc_a:long_name = "shape parameter for sigmoidal function relating dbh to reproductive allocation" ; + double fates_trs_repro_alloc_b(fates_pft) ; + fates_trs_repro_alloc_b:units = "fraction" ; + fates_trs_repro_alloc_b:long_name = "intercept parameter for sigmoidal function relating dbh to reproductive allocation" ; + double fates_trs_repro_frac_seed(fates_pft) ; + fates_trs_repro_frac_seed:units = "fraction" ; + fates_trs_repro_frac_seed:long_name = "fraction of reproductive mass that is seed" ; + double fates_trs_seedling_a_emerg(fates_pft) ; + fates_trs_seedling_a_emerg:units = "day -1" ; + fates_trs_seedling_a_emerg:long_name = "mean fraction of seed bank emerging" ; + double fates_trs_seedling_b_emerg(fates_pft) ; + fates_trs_seedling_b_emerg:units = "day -1" ; + fates_trs_seedling_b_emerg:long_name = "seedling emergence sensitivity to soil moisture" ; + double fates_trs_seedling_background_mort(fates_pft) ; + fates_trs_seedling_background_mort:units = "yr-1" ; + fates_trs_seedling_background_mort:long_name = "background seedling mortality rate" ; + double fates_trs_seedling_h2o_mort_a(fates_pft) ; + fates_trs_seedling_h2o_mort_a:units = "-" ; + fates_trs_seedling_h2o_mort_a:long_name = "coefficient in moisture-based seedling mortality" ; + double fates_trs_seedling_h2o_mort_b(fates_pft) ; + fates_trs_seedling_h2o_mort_b:units = "-" ; + fates_trs_seedling_h2o_mort_b:long_name = "coefficient in moisture-based seedling mortality" ; + double fates_trs_seedling_h2o_mort_c(fates_pft) ; + fates_trs_seedling_h2o_mort_c:units = "-" ; + fates_trs_seedling_h2o_mort_c:long_name = "coefficient in moisture-based seedling mortality" ; + double fates_trs_seedling_light_mort_a(fates_pft) ; + fates_trs_seedling_light_mort_a:units = "-" ; + fates_trs_seedling_light_mort_a:long_name = "light-based seedling mortality coefficient" ; + double fates_trs_seedling_light_mort_b(fates_pft) ; + fates_trs_seedling_light_mort_b:units = "-" ; + fates_trs_seedling_light_mort_b:long_name = "light-based seedling mortality coefficient" ; + double fates_trs_seedling_light_rec_a(fates_pft) ; + fates_trs_seedling_light_rec_a:units = "-" ; + fates_trs_seedling_light_rec_a:long_name = "coefficient in light-based seedling to sapling transition" ; + double fates_trs_seedling_light_rec_b(fates_pft) ; + fates_trs_seedling_light_rec_b:units = "-" ; + fates_trs_seedling_light_rec_b:long_name = "coefficient in light-based seedling to sapling transition" ; + double fates_trs_seedling_mdd_crit(fates_pft) ; + fates_trs_seedling_mdd_crit:units = "mm H2O day" ; + fates_trs_seedling_mdd_crit:long_name = "critical moisture deficit (suction) day accumulation for seedling moisture-based seedling mortality to begin" ; + double fates_trs_seedling_par_crit_germ(fates_pft) ; + fates_trs_seedling_par_crit_germ:units = "MJ m-2 day-1" ; + fates_trs_seedling_par_crit_germ:long_name = "critical light level for germination" ; + double fates_trs_seedling_psi_crit(fates_pft) ; + fates_trs_seedling_psi_crit:units = "mm H2O" ; + fates_trs_seedling_psi_crit:long_name = "critical soil moisture (suction) for seedling stress" ; + double fates_trs_seedling_psi_emerg(fates_pft) ; + fates_trs_seedling_psi_emerg:units = "mm h20 suction" ; + fates_trs_seedling_psi_emerg:long_name = "critical soil moisture for seedling emergence" ; + double fates_trs_seedling_root_depth(fates_pft) ; + fates_trs_seedling_root_depth:units = "m" ; + fates_trs_seedling_root_depth:long_name = "rooting depth of seedlings" ; + double fates_turb_displar(fates_pft) ; + fates_turb_displar:units = "unitless" ; + fates_turb_displar:long_name = "Ratio of displacement height to canopy top height" ; + double fates_turb_leaf_diameter(fates_pft) ; + fates_turb_leaf_diameter:units = "m" ; + fates_turb_leaf_diameter:long_name = "Characteristic leaf dimension" ; + double fates_turb_z0mr(fates_pft) ; + fates_turb_z0mr:units = "unitless" ; + fates_turb_z0mr:long_name = "Ratio of momentum roughness length to canopy top height" ; + double fates_turnover_branch(fates_pft) ; + fates_turnover_branch:units = "yr" ; + fates_turnover_branch:long_name = "turnover time of branches" ; + double fates_turnover_fnrt(fates_pft) ; + fates_turnover_fnrt:units = "yr" ; + fates_turnover_fnrt:long_name = "root longevity (alternatively, turnover time)" ; + double fates_turnover_leaf(fates_leafage_class, fates_pft) ; + fates_turnover_leaf:units = "yr" ; + fates_turnover_leaf:long_name = "Leaf longevity (ie turnover timescale). For drought-deciduous PFTs, this also indicates the maximum length of the growing (i.e., leaves on) season." ; + double fates_turnover_senleaf_fdrought(fates_pft) ; + fates_turnover_senleaf_fdrought:units = "unitless[0-1]" ; + fates_turnover_senleaf_fdrought:long_name = "multiplication factor for leaf longevity of senescent leaves during drought" ; + double fates_wood_density(fates_pft) ; + fates_wood_density:units = "g/cm3" ; + fates_wood_density:long_name = "mean density of woody tissue in plant" ; + double fates_woody(fates_pft) ; + fates_woody:units = "logical flag" ; + fates_woody:long_name = "Binary woody lifeform flag" ; + double fates_hlm_pft_map(fates_hlm_pftno, fates_pft) ; + fates_hlm_pft_map:units = "area fraction" ; + fates_hlm_pft_map:long_name = "In fixed biogeog mode, fraction of HLM area associated with each FATES PFT" ; + double fates_fire_FBD(fates_litterclass) ; + fates_fire_FBD:units = "kg Biomass/m3" ; + fates_fire_FBD:long_name = "fuel bulk density" ; + double fates_fire_low_moisture_Coeff(fates_litterclass) ; + fates_fire_low_moisture_Coeff:units = "NA" ; + fates_fire_low_moisture_Coeff:long_name = "spitfire parameter, equation B1 Thonicke et al 2010" ; + double fates_fire_low_moisture_Slope(fates_litterclass) ; + fates_fire_low_moisture_Slope:units = "NA" ; + fates_fire_low_moisture_Slope:long_name = "spitfire parameter, equation B1 Thonicke et al 2010" ; + double fates_fire_mid_moisture(fates_litterclass) ; + fates_fire_mid_moisture:units = "NA" ; + fates_fire_mid_moisture:long_name = "spitfire litter moisture threshold to be considered medium dry" ; + double fates_fire_mid_moisture_Coeff(fates_litterclass) ; + fates_fire_mid_moisture_Coeff:units = "NA" ; + fates_fire_mid_moisture_Coeff:long_name = "spitfire parameter, equation B1 Thonicke et al 2010" ; + double fates_fire_mid_moisture_Slope(fates_litterclass) ; + fates_fire_mid_moisture_Slope:units = "NA" ; + fates_fire_mid_moisture_Slope:long_name = "spitfire parameter, equation B1 Thonicke et al 2010" ; + double fates_fire_min_moisture(fates_litterclass) ; + fates_fire_min_moisture:units = "NA" ; + fates_fire_min_moisture:long_name = "spitfire litter moisture threshold to be considered very dry" ; + double fates_fire_SAV(fates_litterclass) ; + fates_fire_SAV:units = "cm-1" ; + fates_fire_SAV:long_name = "fuel surface area to volume ratio" ; + double fates_frag_maxdecomp(fates_litterclass) ; + fates_frag_maxdecomp:units = "yr-1" ; + fates_frag_maxdecomp:long_name = "maximum rate of litter & CWD transfer from non-decomposing class into decomposing class" ; + double fates_frag_cwd_frac(fates_NCWD) ; + fates_frag_cwd_frac:units = "fraction" ; + fates_frag_cwd_frac:long_name = "fraction of woody (bdead+bsw) biomass destined for CWD pool" ; + double fates_maxpatches_by_landuse(fates_landuseclass) ; + fates_maxpatches_by_landuse:units = "count" ; + fates_maxpatches_by_landuse:long_name = "maximum number of patches per site on each land use type" ; + double fates_canopy_closure_thresh ; + fates_canopy_closure_thresh:units = "unitless" ; + fates_canopy_closure_thresh:long_name = "tree canopy coverage at which crown area allometry changes from savanna to forest value" ; + double fates_cnp_eca_plant_escalar ; + fates_cnp_eca_plant_escalar:units = "" ; + fates_cnp_eca_plant_escalar:long_name = "scaling factor for plant fine root biomass to calculate nutrient carrier enzyme abundance (ECA)" ; + double fates_cohort_age_fusion_tol ; + fates_cohort_age_fusion_tol:units = "unitless" ; + fates_cohort_age_fusion_tol:long_name = "minimum fraction in differece in cohort age between cohorts." ; + double fates_cohort_size_fusion_tol ; + fates_cohort_size_fusion_tol:units = "unitless" ; + fates_cohort_size_fusion_tol:long_name = "minimum fraction in difference in dbh between cohorts" ; + double fates_comp_excln ; + fates_comp_excln:units = "none" ; + fates_comp_excln:long_name = "IF POSITIVE: weighting factor (exponent on dbh) for canopy layer exclusion and promotion, IF NEGATIVE: switch to use deterministic height sorting" ; + double fates_damage_canopy_layer_code ; + fates_damage_canopy_layer_code:units = "unitless" ; + fates_damage_canopy_layer_code:long_name = "Integer code that decides whether damage affects canopy trees (1), understory trees (2)" ; + double fates_damage_event_code ; + fates_damage_event_code:units = "unitless" ; + fates_damage_event_code:long_name = "Integer code that options how damage events are structured" ; + double fates_daylength_factor_switch ; + fates_daylength_factor_switch:units = "unitless" ; + fates_daylength_factor_switch:long_name = "user switch for turning on (1) or off (0) the day length factor scaling for photosynthetic parameters (ie scale vcmax and jmax)" ; + double fates_dev_arbitrary ; + fates_dev_arbitrary:units = "unknown" ; + fates_dev_arbitrary:long_name = "Unassociated free parameter that developers can use for testing arbitrary new hypotheses" ; + double fates_fire_active_crown_fire ; + fates_fire_active_crown_fire:units = "0 or 1" ; + fates_fire_active_crown_fire:long_name = "flag, 1=active crown fire 0=no active crown fire" ; + double fates_fire_cg_strikes ; + fates_fire_cg_strikes:units = "fraction (0-1)" ; + fates_fire_cg_strikes:long_name = "fraction of cloud to ground lightning strikes" ; + double fates_fire_drying_ratio ; + fates_fire_drying_ratio:units = "NA" ; + fates_fire_drying_ratio:long_name = "spitfire parameter, fire drying ratio for fuel moisture, alpha_FMC EQ 6 Thonicke et al 2010" ; + double fates_fire_durat_slope ; + fates_fire_durat_slope:units = "NA" ; + fates_fire_durat_slope:long_name = "spitfire parameter, fire max duration slope, Equation 14 Thonicke et al 2010" ; + double fates_fire_fdi_alpha ; + fates_fire_fdi_alpha:units = "NA" ; + fates_fire_fdi_alpha:long_name = "spitfire parameter, EQ 7 Venevsky et al. GCB 2002,(modified EQ 8 Thonicke et al. 2010) " ; + double fates_fire_fuel_energy ; + fates_fire_fuel_energy:units = "kJ/kg" ; + fates_fire_fuel_energy:long_name = "spitfire parameter, heat content of fuel" ; + double fates_fire_max_durat ; + fates_fire_max_durat:units = "minutes" ; + fates_fire_max_durat:long_name = "spitfire parameter, fire maximum duration, Equation 14 Thonicke et al 2010" ; + double fates_fire_miner_damp ; + fates_fire_miner_damp:units = "NA" ; + fates_fire_miner_damp:long_name = "spitfire parameter, mineral-dampening coefficient EQ A1 Thonicke et al 2010 " ; + double fates_fire_miner_total ; + fates_fire_miner_total:units = "fraction" ; + fates_fire_miner_total:long_name = "spitfire parameter, total mineral content, Table A1 Thonicke et al 2010" ; + double fates_fire_nignitions ; + fates_fire_nignitions:units = "ignitions per year per km2" ; + fates_fire_nignitions:long_name = "number of annual ignitions per square km" ; + double fates_fire_part_dens ; + fates_fire_part_dens:units = "kg/m2" ; + fates_fire_part_dens:long_name = "spitfire parameter, oven dry particle density, Table A1 Thonicke et al 2010" ; + double fates_fire_threshold ; + fates_fire_threshold:units = "kW/m" ; + fates_fire_threshold:long_name = "spitfire parameter, fire intensity threshold for tracking fires that spread" ; + double fates_frag_cwd_fcel ; + fates_frag_cwd_fcel:units = "unitless" ; + fates_frag_cwd_fcel:long_name = "Cellulose fraction for CWD" ; + double fates_frag_cwd_flig ; + fates_frag_cwd_flig:units = "unitless" ; + fates_frag_cwd_flig:long_name = "Lignin fraction of coarse woody debris" ; + double fates_hydro_kmax_rsurf1 ; + fates_hydro_kmax_rsurf1:units = "kg water/m2 root area/Mpa/s" ; + fates_hydro_kmax_rsurf1:long_name = "maximum conducitivity for unit root surface (into root)" ; + double fates_hydro_kmax_rsurf2 ; + fates_hydro_kmax_rsurf2:units = "kg water/m2 root area/Mpa/s" ; + fates_hydro_kmax_rsurf2:long_name = "maximum conducitivity for unit root surface (out of root)" ; + double fates_hydro_psi0 ; + fates_hydro_psi0:units = "MPa" ; + fates_hydro_psi0:long_name = "sapwood water potential at saturation" ; + double fates_hydro_psicap ; + fates_hydro_psicap:units = "MPa" ; + fates_hydro_psicap:long_name = "sapwood water potential at which capillary reserves exhausted" ; + double fates_hydro_solver ; + fates_hydro_solver:units = "unitless" ; + fates_hydro_solver:long_name = "switch designating which numerical solver for plant hydraulics, 1 = 1D taylor, 2 = 2D Picard, 3 = 2D Newton (deprecated)" ; + double fates_landuse_logging_coll_under_frac ; + fates_landuse_logging_coll_under_frac:units = "fraction" ; + fates_landuse_logging_coll_under_frac:long_name = "Fraction of stems killed in the understory when logging generates disturbance" ; + double fates_landuse_logging_collateral_frac ; + fates_landuse_logging_collateral_frac:units = "fraction" ; + fates_landuse_logging_collateral_frac:long_name = "Fraction of large stems in upperstory that die from logging collateral damage" ; + double fates_landuse_logging_dbhmax ; + fates_landuse_logging_dbhmax:units = "cm" ; + fates_landuse_logging_dbhmax:long_name = "Maximum dbh below which logging is applied (unset values flag this to be unused)" ; + double fates_landuse_logging_dbhmax_infra ; + fates_landuse_logging_dbhmax_infra:units = "cm" ; + fates_landuse_logging_dbhmax_infra:long_name = "Tree diameter, above which infrastructure from logging does not impact damage or mortality." ; + double fates_landuse_logging_dbhmin ; + fates_landuse_logging_dbhmin:units = "cm" ; + fates_landuse_logging_dbhmin:long_name = "Minimum dbh at which logging is applied" ; + double fates_landuse_logging_direct_frac ; + fates_landuse_logging_direct_frac:units = "fraction" ; + fates_landuse_logging_direct_frac:long_name = "Fraction of stems logged directly per event" ; + double fates_landuse_logging_event_code ; + fates_landuse_logging_event_code:units = "unitless" ; + fates_landuse_logging_event_code:long_name = "Integer code that options how logging events are structured" ; + double fates_landuse_logging_export_frac ; + fates_landuse_logging_export_frac:units = "fraction" ; + fates_landuse_logging_export_frac:long_name = "fraction of trunk product being shipped offsite, the leftovers will be left onsite as large CWD" ; + double fates_landuse_logging_mechanical_frac ; + fates_landuse_logging_mechanical_frac:units = "fraction" ; + fates_landuse_logging_mechanical_frac:long_name = "Fraction of stems killed due infrastructure an other mechanical means" ; + double fates_landuse_pprodharv10_forest_mean ; + fates_landuse_pprodharv10_forest_mean:units = "fraction" ; + fates_landuse_pprodharv10_forest_mean:long_name = "mean harvest mortality proportion of deadstem to 10-yr product (pprodharv10) of all woody PFT types" ; + double fates_leaf_photo_temp_acclim_thome_time ; + fates_leaf_photo_temp_acclim_thome_time:units = "years" ; + fates_leaf_photo_temp_acclim_thome_time:long_name = "Length of the window for the long-term (i.e. T_home in Kumarathunge et al 2019) exponential moving average (ema) of vegetation temperature used in photosynthesis temperature acclimation (used if fates_leaf_photo_tempsens_model = 2)" ; + double fates_leaf_photo_temp_acclim_timescale ; + fates_leaf_photo_temp_acclim_timescale:units = "days" ; + fates_leaf_photo_temp_acclim_timescale:long_name = "Length of the window for the exponential moving average (ema) of vegetation temperature used in photosynthesis temperature acclimation (used if fates_maintresp_leaf_model=2 or fates_leaf_photo_tempsens_model = 2)" ; + double fates_leaf_photo_tempsens_model ; + fates_leaf_photo_tempsens_model:units = "unitless" ; + fates_leaf_photo_tempsens_model:long_name = "switch for choosing the model that defines the temperature sensitivity of photosynthetic parameters (vcmax, jmax). 1=non-acclimating; 2=Kumarathunge et al 2019" ; + double fates_leaf_stomatal_assim_model ; + fates_leaf_stomatal_assim_model:units = "unitless" ; + fates_leaf_stomatal_assim_model:long_name = "a switch designating whether to use net (1) or gross (2) assimilation in the stomatal model" ; + double fates_leaf_stomatal_model ; + fates_leaf_stomatal_model:units = "unitless" ; + fates_leaf_stomatal_model:long_name = "switch for choosing between Ball-Berry (1) stomatal conductance model and Medlyn (2) model" ; + double fates_leaf_theta_cj_c3 ; + fates_leaf_theta_cj_c3:units = "unitless" ; + fates_leaf_theta_cj_c3:long_name = "Empirical curvature parameter for ac, aj photosynthesis co-limitation in c3 plants" ; + double fates_leaf_theta_cj_c4 ; + fates_leaf_theta_cj_c4:units = "unitless" ; + fates_leaf_theta_cj_c4:long_name = "Empirical curvature parameter for ac, aj photosynthesis co-limitation in c4 plants" ; + double fates_maintresp_leaf_model ; + fates_maintresp_leaf_model:units = "unitless" ; + fates_maintresp_leaf_model:long_name = "switch for choosing between maintenance respiration models. 1=Ryan (1991), 2=Atkin et al., (2017)" ; + double fates_maintresp_nonleaf_baserate ; + fates_maintresp_nonleaf_baserate:units = "gC/gN/s" ; + fates_maintresp_nonleaf_baserate:long_name = "Base maintenance respiration rate for plant tissues, using Ryan 1991" ; + double fates_maxcohort ; + fates_maxcohort:units = "count" ; + fates_maxcohort:long_name = "maximum number of cohorts per patch. Actual number of cohorts also depend on cohort fusion tolerances" ; + double fates_mort_cstarvation_model ; + fates_mort_cstarvation_model:units = "unitless" ; + fates_mort_cstarvation_model:long_name = "switch defining the carbon starvation model ( 1) Linear or 2) Exponential) in the mortality_rates function." ; + double fates_mort_disturb_frac ; + fates_mort_disturb_frac:units = "fraction" ; + fates_mort_disturb_frac:long_name = "fraction of canopy mortality that results in disturbance (i.e. transfer of area from new to old patch)" ; + double fates_mort_understorey_death ; + fates_mort_understorey_death:units = "fraction" ; + fates_mort_understorey_death:long_name = "fraction of plants in understorey cohort impacted by overstorey tree-fall" ; + double fates_patch_fusion_tol ; + fates_patch_fusion_tol:units = "unitless" ; + fates_patch_fusion_tol:long_name = "minimum fraction in difference in profiles between patches" ; + double fates_phen_chilltemp ; + fates_phen_chilltemp:units = "degrees C" ; + fates_phen_chilltemp:long_name = "chilling day counting threshold for vegetation" ; + double fates_phen_coldtemp ; + fates_phen_coldtemp:units = "degrees C" ; + fates_phen_coldtemp:long_name = "vegetation temperature exceedance that flags a cold-day for leaf-drop" ; + double fates_phen_gddthresh_a ; + fates_phen_gddthresh_a:units = "none" ; + fates_phen_gddthresh_a:long_name = "GDD accumulation function, intercept parameter: gdd_thesh = a + b exp(c*ncd)" ; + double fates_phen_gddthresh_b ; + fates_phen_gddthresh_b:units = "none" ; + fates_phen_gddthresh_b:long_name = "GDD accumulation function, multiplier parameter: gdd_thesh = a + b exp(c*ncd)" ; + double fates_phen_gddthresh_c ; + fates_phen_gddthresh_c:units = "none" ; + fates_phen_gddthresh_c:long_name = "GDD accumulation function, exponent parameter: gdd_thesh = a + b exp(c*ncd)" ; + double fates_phen_mindayson ; + fates_phen_mindayson:units = "days" ; + fates_phen_mindayson:long_name = "day threshold compared against days since leaves became on-allometry" ; + double fates_phen_ncolddayslim ; + fates_phen_ncolddayslim:units = "days" ; + fates_phen_ncolddayslim:long_name = "day threshold exceedance for temperature leaf-drop" ; + double fates_q10_froz ; + fates_q10_froz:units = "unitless" ; + fates_q10_froz:long_name = "Q10 for frozen-soil respiration rates" ; + double fates_q10_mr ; + fates_q10_mr:units = "unitless" ; + fates_q10_mr:long_name = "Q10 for maintenance respiration" ; + double fates_rad_model ; + fates_rad_model:units = "unitless" ; + fates_rad_model:long_name = "switch designating the model for canopy radiation, 1 = Norman, 2 = Two-stream (experimental)" ; + double fates_regeneration_model ; + fates_regeneration_model:units = "-" ; + fates_regeneration_model:long_name = "switch for choosing between FATES\'s: 1) default regeneration scheme , 2) the Tree Recruitment Scheme (Hanbury-Brown et al., 2022), or (3) the Tree Recruitment Scheme without seedling dynamics" ; + double fates_soil_salinity ; + fates_soil_salinity:units = "ppt" ; + fates_soil_salinity:long_name = "soil salinity used for model when not coupled to dynamic soil salinity" ; + double fates_trs_seedling2sap_par_timescale ; + fates_trs_seedling2sap_par_timescale:units = "days" ; + fates_trs_seedling2sap_par_timescale:long_name = "Length of the window for the exponential moving average of par at the seedling layer used to calculate seedling to sapling transition rates" ; + double fates_trs_seedling_emerg_h2o_timescale ; + fates_trs_seedling_emerg_h2o_timescale:units = "days" ; + fates_trs_seedling_emerg_h2o_timescale:long_name = "Length of the window for the exponential moving average of smp used to calculate seedling emergence" ; + double fates_trs_seedling_mdd_timescale ; + fates_trs_seedling_mdd_timescale:units = "days" ; + fates_trs_seedling_mdd_timescale:long_name = "Length of the window for the exponential moving average of moisture deficit days used to calculate seedling mortality" ; + double fates_trs_seedling_mort_par_timescale ; + fates_trs_seedling_mort_par_timescale:units = "days" ; + fates_trs_seedling_mort_par_timescale:long_name = "Length of the window for the exponential moving average of par at the seedling layer used to calculate seedling mortality" ; + double fates_vai_top_bin_width ; + fates_vai_top_bin_width:units = "m2/m2" ; + fates_vai_top_bin_width:long_name = "width in VAI units of uppermost leaf+stem layer scattering element in each canopy layer" ; + double fates_vai_width_increase_factor ; + fates_vai_width_increase_factor:units = "unitless" ; + fates_vai_width_increase_factor:long_name = "factor by which each leaf+stem scattering element increases in VAI width (1 = uniform spacing)" ; + +// global attributes: + :history = "This file was generated by BatchPatchParams.py:\nCDL Base File = archive/api24.1.0_101722_fates_params_default.cdl\nXML patch file = archive/api24.1.0_101722_patch_params.xml" ; +data: + + fates_history_ageclass_bin_edges = 0, 1, 2, 5, 10, 20, 50 ; + + fates_history_coageclass_bin_edges = 0, 5 ; + + fates_history_height_bin_edges = 0, 0.1, 0.3, 1, 3, 10 ; + + fates_history_damage_bin_edges = 0, 80 ; + + fates_history_sizeclass_bin_edges = 0, 5, 10, 15, 20, 30, 40, 50, 60, 70, + 80, 90, 100 ; + + fates_alloc_organ_id = 1, 2, 3, 6 ; + + fates_hydro_htftype_node = 1, 1, 1, 1 ; + + fates_pftname = + "broadleaf_evergreen_tropical_tree ", + "needleleaf_evergreen_extratrop_tree ", + "needleleaf_colddecid_extratrop_tree ", + "broadleaf_evergreen_extratrop_tree ", + "broadleaf_hydrodecid_tropical_tree ", + "broadleaf_colddecid_extratrop_tree ", + "broadleaf_evergreen_extratrop_shrub ", + "broadleaf_hydrodecid_extratrop_shrub ", + "broadleaf_colddecid_extratrop_shrub ", + "arctic_c3_grass ", + "cool_c3_grass ", + "c4_grass " ; + + fates_hydro_organ_name = + "leaf ", + "stem ", + "transporting root ", + "absorbing root " ; + + fates_alloc_organ_name = + "leaf", + "fine root", + "sapwood", + "structure" ; + + fates_landuseclass_name = + "primaryland", + "secondaryland", + "rangeland", + "pastureland", + "cropland" ; + + fates_litterclass_name = + "twig ", + "small branch ", + "large branch ", + "trunk ", + "dead leaves ", + "live grass " ; + + fates_alloc_organ_priority = + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 ; + + fates_alloc_storage_cushion = 1.2, 1.2, 1.2, 1.2, 2.4, 1.2, 1.2, 2.4, 1.2, + 1.2, 1.2, 1.2 ; + + fates_alloc_store_priority_frac = 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, + 0.8, 0.8, 0.8, 0.8 ; + + fates_allom_agb1 = 0.0673, 0.1364012, 0.0393057, 0.2653695, 0.0673, + 0.0728698, 0.06896, 0.06896, 0.06896, 0.01, 0.01, 0.01 ; + + fates_allom_agb2 = 0.976, 0.9449041, 1.087335, 0.8321321, 0.976, 1.0373211, + 0.572, 0.572, 0.572, 0.572, 0.572, 0.572 ; + + fates_allom_agb3 = 1.94, 1.94, 1.94, 1.94, 1.94, 1.94, 1.94, 1.94, 1.94, + 1.94, 1.94, 1.94 ; + + fates_allom_agb4 = 0.931, 0.931, 0.931, 0.931, 0.931, 0.931, 0.931, 0.931, + 0.931, 0.931, 0.931, 0.931 ; + + fates_allom_agb_frac = 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, + 0.6, 0.6 ; + + fates_allom_amode = 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1 ; + + fates_allom_blca_expnt_diff = -0.12, -0.34, -0.32, -0.22, -0.12, -0.35, 0, + 0, 0, 0, 0, 0 ; + + fates_allom_cmode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_d2bl1 = 0.04, 0.07, 0.07, 0.01, 0.04, 0.07, 0.07, 0.07, 0.07, + 0.07, 0.07, 0.07 ; + + fates_allom_d2bl2 = 1.6019679, 1.5234373, 1.3051237, 1.9621397, 1.6019679, + 1.3998939, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3 ; + + fates_allom_d2bl3 = 0.55, 0.55, 0.55, 0.55, 0.55, 0.55, 0.55, 0.55, 0.55, + 0.55, 0.55, 0.55 ; + + fates_allom_d2ca_coefficient_max = 0.2715891, 0.3693718, 1.0787259, + 0.0579297, 0.2715891, 1.1553612, 0.6568464, 0.6568464, 0.6568464, + 0.6568464, 0.6568464, 0.6568464 ; + + fates_allom_d2ca_coefficient_min = 0.2715891, 0.3693718, 1.0787259, + 0.0579297, 0.2715891, 1.1553612, 0.6568464, 0.6568464, 0.6568464, + 0.6568464, 0.6568464, 0.6568464 ; + + fates_allom_d2h1 = 78.4087704, 306.842667, 106.8745821, 104.3586841, + 78.4087704, 31.4557047, 0.64, 0.64, 0.64, 0.64, 0.64, 0.64 ; + + fates_allom_d2h2 = 0.8124383, 0.752377, 0.9471302, 1.1146973, 0.8124383, + 0.9734088, 0.37, 0.37, 0.37, 0.37, 0.37, 0.37 ; + + fates_allom_d2h3 = 47.6666164, 196.6865691, 93.9790461, 160.6835089, + 47.6666164, 16.5928174, -999.9, -999.9, -999.9, -999.9, -999.9, -999.9 ; + + fates_allom_dbh_maxheight = 1000, 1000, 1000, 1000, 1000, 1000, 3, 3, 2, + 0.35, 0.35, 0.35 ; + + fates_allom_dmode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_fmode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_fnrt_prof_a = 7, 7, 7, 7, 6, 6, 7, 7, 7, 11, 11, 11 ; + + fates_allom_fnrt_prof_b = 1, 2, 2, 1, 2, 2, 1.5, 1.5, 1.5, 2, 2, 2 ; + + fates_allom_fnrt_prof_mode = 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 ; + + fates_allom_frbstor_repro = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_allom_h2cd1 = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.95, 0.95, 0.95, 1, 1, 1 ; + + fates_allom_h2cd2 = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_hmode = 5, 5, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1 ; + + fates_allom_l2fr = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_la_per_sa_int = 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, + 0.8, 0.8, 0.8 ; + + fates_allom_la_per_sa_slp = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_allom_lmode = 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1 ; + + fates_allom_sai_scaler = 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, + 0.1, 0.1 ; + + fates_allom_smode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_stmode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_zroot_k = 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10 ; + + fates_allom_zroot_max_dbh = 100, 100, 100, 100, 100, 100, 2, 2, 2, 2, 2, 2 ; + + fates_allom_zroot_max_z = 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, + 100, 100 ; + + fates_allom_zroot_min_dbh = 1, 1, 1, 2.5, 2.5, 2.5, 0.1, 0.1, 0.1, 0.1, 0.1, + 0.1 ; + + fates_allom_zroot_min_z = 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, + 100, 100 ; + + fates_c2b = 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ; + + fates_cnp_eca_alpha_ptase = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_cnp_eca_decompmicc = 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280 ; + + fates_cnp_eca_km_nh4 = 0.14, 0.14, 0.14, 0.14, 0.14, 0.14, 0.14, 0.14, 0.14, + 0.14, 0.14, 0.14 ; + + fates_cnp_eca_km_no3 = 0.27, 0.27, 0.27, 0.27, 0.27, 0.27, 0.27, 0.27, 0.27, + 0.27, 0.27, 0.27 ; + + fates_cnp_eca_km_p = 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, + 0.1 ; + + fates_cnp_eca_km_ptase = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_cnp_eca_lambda_ptase = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_cnp_eca_vmax_ptase = 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, + 5e-09, 5e-09, 5e-09, 5e-09, 5e-09 ; + + fates_cnp_nfix1 = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_cnp_nitr_store_ratio = 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, + 1.5, 1.5, 1.5 ; + + fates_cnp_phos_store_ratio = 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, + 1.5, 1.5, 1.5 ; + + fates_cnp_pid_kd = 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1 ; + + fates_cnp_pid_ki = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_cnp_pid_kp = 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, + 0.0005, 0.0005, 0.0005, 0.0005, 0.0005 ; + + fates_cnp_prescribed_nuptake = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_cnp_prescribed_puptake = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_cnp_store_ovrflw_frac = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_cnp_turnover_nitr_retrans = + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_cnp_turnover_phos_retrans = + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_cnp_vmax_nh4 = 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, + 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09 ; + + fates_cnp_vmax_no3 = 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, + 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09, 2.5e-09 ; + + fates_cnp_vmax_p = 5e-10, 5e-10, 5e-10, 5e-10, 5e-10, 5e-10, 5e-10, 5e-10, + 5e-10, 5e-10, 5e-10, 5e-10 ; + + fates_damage_frac = 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, + 0.01, 0.01, 0.01 ; + + fates_damage_mort_p1 = 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 ; + + fates_damage_mort_p2 = 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, + 5.5, 5.5 ; + + fates_damage_recovery_scalar = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_dev_arbitrary_pft = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_fire_alpha_SH = 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, + 0.2 ; + + fates_fire_bark_scaler = 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, + 0.07, 0.07, 0.07, 0.07 ; + + fates_fire_crown_kill = 0.775, 0.775, 0.775, 0.775, 0.775, 0.775, 0.775, + 0.775, 0.775, 0.775, 0.775, 0.775 ; + + fates_frag_fnrt_fcel = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5 ; + + fates_frag_fnrt_flab = 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25 ; + + fates_frag_fnrt_flig = 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25 ; + + fates_frag_leaf_fcel = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5 ; + + fates_frag_leaf_flab = 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25 ; + + fates_frag_leaf_flig = 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.25, 0.25, 0.25 ; + + fates_frag_seed_decay_rate = 0.51, 0.51, 0.51, 0.51, 0.51, 0.51, 0.51, 0.51, + 0.51, 0.51, 0.51, 0.51 ; + + fates_grperc = 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, + 0.11, 0.11 ; + + fates_hydro_avuln_gs = 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, + 2.5, 2.5 ; + + fates_hydro_avuln_node = + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ; + + fates_hydro_epsil_node = + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 ; + + fates_hydro_fcap_node = + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, + 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_hydro_k_lwp = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_hydro_kmax_node = + -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999, -999 ; + + fates_hydro_p50_gs = -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, + -1.5, -1.5, -1.5 ; + + fates_hydro_p50_node = + -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, + -2.25, -2.25, + -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, + -2.25, -2.25, + -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, + -2.25, -2.25, + -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, -2.25, + -2.25, -2.25 ; + + fates_hydro_p_taper = 0.333, 0.333, 0.333, 0.333, 0.333, 0.333, 0.333, + 0.333, 0.333, 0.333, 0.333, 0.333 ; + + fates_hydro_pinot_node = + -1.465984, -1.465984, -1.465984, -1.465984, -1.465984, -1.465984, + -1.465984, -1.465984, -1.465984, -1.465984, -1.465984, -1.465984, + -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, + -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, + -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, + -1.22807, -1.22807, -1.22807, -1.22807, -1.22807, + -1.043478, -1.043478, -1.043478, -1.043478, -1.043478, -1.043478, + -1.043478, -1.043478, -1.043478, -1.043478, -1.043478, -1.043478 ; + + fates_hydro_pitlp_node = + -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, -1.67, + -1.67, -1.67, + -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, + -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, -1.4, + -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2 ; + + fates_hydro_resid_node = + 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, + 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, + 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, + 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11 ; + + fates_hydro_rfrac_stem = 0.625, 0.625, 0.625, 0.625, 0.625, 0.625, 0.625, + 0.625, 0.625, 0.625, 0.625, 0.625 ; + + fates_hydro_rs2 = 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, + 0.0001, 0.0001, 0.0001, 0.0001, 0.0001 ; + + fates_hydro_srl = 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25 ; + + fates_hydro_thetas_node = + 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, + 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, + 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65, + 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75 ; + + fates_hydro_vg_alpha_node = + 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.005, 0.005, 0.005, 0.005, 0.005, + 0.005, 0.005, + 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.005, 0.005, 0.005, 0.005, 0.005, + 0.005, 0.005, + 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.005, 0.005, 0.005, 0.005, 0.005, + 0.005, 0.005, + 0.0005, 0.0005, 0.0005, 0.0005, 0.0005, 0.005, 0.005, 0.005, 0.005, 0.005, + 0.005, 0.005 ; + + fates_hydro_vg_m_node = + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5 ; + + fates_hydro_vg_n_node = + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ; + + fates_leaf_c3psn = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 ; + + fates_leaf_jmaxha = 43540, 43540, 43540, 43540, 43540, 43540, 43540, 43540, + 43540, 43540, 43540, 43540 ; + + fates_leaf_jmaxhd = 152040, 152040, 152040, 152040, 152040, 152040, 152040, + 152040, 152040, 152040, 152040, 152040 ; + + fates_leaf_jmaxse = 495, 495, 495, 495, 495, 495, 495, 495, 495, 495, 495, + 495 ; + + fates_leaf_slamax = 0.0954, 0.0954, 0.0954, 0.0954, 0.0954, 0.0954, 0.012, + 0.03, 0.03, 0.03, 0.03, 0.03 ; + + fates_leaf_slatop = 0.012, 0.005, 0.024, 0.009, 0.03, 0.03, 0.012, 0.03, + 0.03, 0.03, 0.03, 0.03 ; + + fates_leaf_stomatal_intercept = 10000, 10000, 10000, 10000, 10000, 10000, + 10000, 10000, 10000, 10000, 10000, 40000 ; + + fates_leaf_stomatal_slope_ballberry = 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 ; + + fates_leaf_stomatal_slope_medlyn = 4.1, 2.3, 2.3, 4.1, 4.4, 4.4, 4.7, 4.7, + 4.7, 2.2, 5.3, 1.6 ; + + fates_leaf_vcmax25top = + 50, 62, 39, 61, 58, 58, 62, 54, 54, 78, 78, 78 ; + + fates_leaf_vcmaxha = 65330, 65330, 65330, 65330, 65330, 65330, 65330, 65330, + 65330, 65330, 65330, 65330 ; + + fates_leaf_vcmaxhd = 149250, 149250, 149250, 149250, 149250, 149250, 149250, + 149250, 149250, 149250, 149250, 149250 ; + + fates_leaf_vcmaxse = 485, 485, 485, 485, 485, 485, 485, 485, 485, 485, 485, + 485 ; + + fates_leafn_vert_scaler_coeff1 = 0.00963, 0.00963, 0.00963, 0.00963, + 0.00963, 0.00963, 0.00963, 0.00963, 0.00963, 0.00963, 0.00963, 0.00963 ; + + fates_leafn_vert_scaler_coeff2 = 2.43, 2.43, 2.43, 2.43, 2.43, 2.43, 2.43, + 2.43, 2.43, 2.43, 2.43, 2.43 ; + + fates_maintresp_leaf_atkin2017_baserate = 1.756, 1.4995, 1.4995, 1.756, + 1.756, 1.756, 2.0749, 2.0749, 2.0749, 2.1956, 2.1956, 2.1956 ; + + fates_maintresp_leaf_ryan1991_baserate = 2.525e-06, 2.525e-06, 2.525e-06, + 2.525e-06, 2.525e-06, 2.525e-06, 2.525e-06, 2.525e-06, 2.525e-06, + 2.525e-06, 2.525e-06, 2.525e-06 ; + + fates_maintresp_leaf_vert_scaler_coeff1 = 0.00963, 0.00963, 0.00963, + 0.00963, 0.00963, 0.00963, 0.00963, 0.00963, 0.00963, 0.00963, 0.00963, + 0.00963 ; + + fates_maintresp_leaf_vert_scaler_coeff2 = 2.43, 2.43, 2.43, 2.43, 2.43, + 2.43, 2.43, 2.43, 2.43, 2.43, 2.43, 2.43 ; + + fates_maintresp_reduction_curvature = 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, + 0.01, 0.01, 0.01, 0.01, 0.01, 0.01 ; + + fates_maintresp_reduction_intercept = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_maintresp_reduction_upthresh = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_mort_bmort = 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, + 0.014, 0.014, 0.014, 0.014 ; + + fates_mort_freezetol = 2.5, -55, -80, -30, 2.5, -80, -60, -10, -80, -80, + -20, 2.5 ; + + fates_mort_hf_flc_threshold = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5 ; + + fates_mort_hf_sm_threshold = 1e-06, 1e-06, 1e-06, 1e-06, 1e-06, 1e-06, + 1e-06, 1e-06, 1e-06, 1e-06, 1e-06, 1e-06 ; + + fates_mort_ip_age_senescence = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_mort_ip_size_senescence = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_mort_prescribed_canopy = 0.0194, 0.0194, 0.0194, 0.0194, 0.0194, + 0.0194, 0.0194, 0.0194, 0.0194, 0.0194, 0.0194, 0.0194 ; + + fates_mort_prescribed_understory = 0.025, 0.025, 0.025, 0.025, 0.025, 0.025, + 0.025, 0.025, 0.025, 0.025, 0.025, 0.025 ; + + fates_mort_r_age_senescence = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_mort_r_size_senescence = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_mort_scalar_coldstress = 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 ; + + fates_mort_scalar_cstarvation = 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, + 0.6, 0.6, 0.6 ; + + fates_mort_scalar_hydrfailure = 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, + 0.6, 0.6, 0.6 ; + + fates_mort_upthresh_cstarvation = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_nonhydro_smpsc = -255000, -255000, -255000, -255000, -255000, -255000, + -255000, -255000, -255000, -255000, -255000, -255000 ; + + fates_nonhydro_smpso = -66000, -66000, -66000, -66000, -66000, -66000, + -66000, -66000, -66000, -66000, -66000, -66000 ; + + fates_phen_cold_size_threshold = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_phen_drought_threshold = -152957.4, -152957.4, -152957.4, -152957.4, + -152957.4, -152957.4, -152957.4, -152957.4, -152957.4, -152957.4, + -152957.4, -152957.4 ; + + fates_phen_evergreen = 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 ; + + fates_phen_flush_fraction = _, _, 0.5, _, 0.5, 0.5, _, 0.5, 0.5, 0.5, 0.5, + 0.5 ; + + fates_phen_fnrt_drop_fraction = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_phen_mindaysoff = 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, + 100, 100 ; + + fates_phen_moist_threshold = -122365.9, -122365.9, -122365.9, -122365.9, + -122365.9, -122365.9, -122365.9, -122365.9, -122365.9, -122365.9, + -122365.9, -122365.9 ; + + fates_phen_season_decid = 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0 ; + + fates_phen_stem_drop_fraction = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_phen_stress_decid = 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1 ; + + fates_prescribed_npp_canopy = 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, + 0.4, 0.4, 0.4 ; + + fates_prescribed_npp_understory = 0.03125, 0.03125, 0.03125, 0.03125, + 0.03125, 0.03125, 0.03125, 0.03125, 0.03125, 0.03125, 0.03125, 0.03125 ; + + fates_rad_leaf_clumping_index = 0.85, 0.85, 0.8, 0.85, 0.85, 0.9, 0.85, 0.9, + 0.9, 0.75, 0.75, 0.75 ; + + fates_rad_leaf_rhonir = 0.46, 0.41, 0.39, 0.46, 0.41, 0.41, 0.46, 0.41, + 0.41, 0.28, 0.28, 0.28 ; + + fates_rad_leaf_rhovis = 0.11, 0.09, 0.08, 0.11, 0.08, 0.08, 0.11, 0.08, + 0.08, 0.05, 0.05, 0.05 ; + + fates_rad_leaf_taunir = 0.33, 0.32, 0.42, 0.33, 0.43, 0.43, 0.33, 0.43, + 0.43, 0.4, 0.4, 0.4 ; + + fates_rad_leaf_tauvis = 0.06, 0.04, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, + 0.06, 0.05, 0.05, 0.05 ; + + fates_rad_leaf_xl = 0.32, 0.01, 0.01, 0.32, 0.2, 0.59, 0.32, 0.59, 0.59, + -0.23, -0.23, -0.23 ; + + fates_rad_stem_rhonir = 0.49, 0.36, 0.36, 0.49, 0.49, 0.49, 0.49, 0.49, + 0.49, 0.53, 0.53, 0.53 ; + + fates_rad_stem_rhovis = 0.21, 0.12, 0.12, 0.21, 0.21, 0.21, 0.21, 0.21, + 0.21, 0.31, 0.31, 0.31 ; + + fates_rad_stem_taunir = 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, + 0.001, 0.001, 0.25, 0.25, 0.25 ; + + fates_rad_stem_tauvis = 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, + 0.001, 0.001, 0.12, 0.12, 0.12 ; + + fates_recruit_height_min = 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 0.2, 0.2, 0.2, + 0.125, 0.125, 0.125 ; + + fates_recruit_init_density = 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, + 0.2, 0.2, 0.2 ; + + fates_recruit_prescribed_rate = 0.02, 0.02, 0.02, 0.02, 0.02, 0.02, 0.02, + 0.02, 0.02, 0.02, 0.02, 0.02 ; + + fates_recruit_seed_alloc = 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, + 0.1, 0.1 ; + + fates_recruit_seed_alloc_mature = 0, 0, 0, 0, 0, 0, 0.9, 0.9, 0.9, 0.9, 0.9, + 0.9 ; + + fates_recruit_seed_dbh_repro_threshold = 90, 80, 80, 80, 90, 80, 3, 3, 2, + 0.35, 0.35, 0.35 ; + + fates_recruit_seed_germination_rate = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5 ; + + fates_recruit_seed_supplement = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + + fates_seed_dispersal_fraction = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_seed_dispersal_max_dist = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_seed_dispersal_pdf_scale = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_seed_dispersal_pdf_shape = _, _, _, _, _, _, _, _, _, _, _, _ ; + + fates_stoich_nitr = + 0.033, 0.029, 0.04, 0.033, 0.04, 0.04, 0.033, 0.04, 0.04, 0.04, 0.04, 0.04, + 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, 0.024, + 0.024, 0.024, + 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, + 1e-08, 1e-08, + 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, 0.0047, + 0.0047, 0.0047, 0.0047 ; + + fates_stoich_phos = + 0.0033, 0.0029, 0.004, 0.0033, 0.004, 0.004, 0.0033, 0.004, 0.004, 0.004, + 0.004, 0.004, + 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, 0.0024, + 0.0024, 0.0024, 0.0024, + 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, 1e-09, + 1e-09, 1e-09, + 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, 0.00047, + 0.00047, 0.00047, 0.00047, 0.00047 ; + + fates_trim_inc = 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, + 0.03, 0.03 ; + + fates_trim_limit = 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3 ; + + fates_trs_repro_alloc_a = 0.0049, 0.0049, 0.0049, 0.0049, 0.0049, 0.0049, + 0.0049, 0.0049, 0.0049, 0.0049, 0.0049, 0.0049 ; + + fates_trs_repro_alloc_b = -2.6171, -2.6171, -2.6171, -2.6171, -2.6171, + -2.6171, -2.6171, -2.6171, -2.6171, -2.6171, -2.6171, -2.6171 ; + + fates_trs_repro_frac_seed = 0.24, 0.24, 0.24, 0.24, 0.24, 0.24, 0.24, 0.24, + 0.24, 0.24, 0.24, 0.24 ; + + fates_trs_seedling_a_emerg = 0.0003, 0.0003, 0.0003, 0.0003, 0.0003, 0.0003, + 0.0003, 0.0003, 0.0003, 0.0003, 0.0003, 0.0003 ; + + fates_trs_seedling_b_emerg = 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, + 1.2, 1.2, 1.2 ; + + fates_trs_seedling_background_mort = 0.1085371, 0.1085371, 0.1085371, + 0.1085371, 0.1085371, 0.1085371, 0.1085371, 0.1085371, 0.1085371, + 0.1085371, 0.1085371, 0.1085371 ; + + fates_trs_seedling_h2o_mort_a = 4.070565e-17, 4.070565e-17, 4.070565e-17, + 4.070565e-17, 4.070565e-17, 4.070565e-17, 4.070565e-17, 4.070565e-17, + 4.070565e-17, 4.070565e-17, 4.070565e-17, 4.070565e-17 ; + + fates_trs_seedling_h2o_mort_b = -6.390757e-11, -6.390757e-11, -6.390757e-11, + -6.390757e-11, -6.390757e-11, -6.390757e-11, -6.390757e-11, + -6.390757e-11, -6.390757e-11, -6.390757e-11, -6.390757e-11, -6.390757e-11 ; + + fates_trs_seedling_h2o_mort_c = 1.268992e-05, 1.268992e-05, 1.268992e-05, + 1.268992e-05, 1.268992e-05, 1.268992e-05, 1.268992e-05, 1.268992e-05, + 1.268992e-05, 1.268992e-05, 1.268992e-05, 1.268992e-05 ; + + fates_trs_seedling_light_mort_a = -0.009897694, -0.009897694, -0.009897694, + -0.009897694, -0.009897694, -0.009897694, -0.009897694, -0.009897694, + -0.009897694, -0.009897694, -0.009897694, -0.009897694 ; + + fates_trs_seedling_light_mort_b = -7.154063, -7.154063, -7.154063, + -7.154063, -7.154063, -7.154063, -7.154063, -7.154063, -7.154063, + -7.154063, -7.154063, -7.154063 ; + + fates_trs_seedling_light_rec_a = 0.007, 0.007, 0.007, 0.007, 0.007, 0.007, + 0.007, 0.007, 0.007, 0.007, 0.007, 0.007 ; + + fates_trs_seedling_light_rec_b = 0.8615, 0.8615, 0.8615, 0.8615, 0.8615, + 0.8615, 0.8615, 0.8615, 0.8615, 0.8615, 0.8615, 0.8615 ; + + fates_trs_seedling_mdd_crit = 1400000, 1400000, 1400000, 1400000, 1400000, + 1400000, 1400000, 1400000, 1400000, 1400000, 1400000, 1400000 ; + + fates_trs_seedling_par_crit_germ = 0.656, 0.656, 0.656, 0.656, 0.656, 0.656, + 0.656, 0.656, 0.656, 0.656, 0.656, 0.656 ; + + fates_trs_seedling_psi_crit = -251995.7, -251995.7, -251995.7, -251995.7, + -251995.7, -251995.7, -251995.7, -251995.7, -251995.7, -251995.7, + -251995.7, -251995.7 ; + + fates_trs_seedling_psi_emerg = -15744.65, -15744.65, -15744.65, -15744.65, + -15744.65, -15744.65, -15744.65, -15744.65, -15744.65, -15744.65, + -15744.65, -15744.65 ; + + fates_trs_seedling_root_depth = 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, + 0.06, 0.06, 0.06, 0.06, 0.06 ; + + fates_turb_displar = 0.67, 0.67, 0.67, 0.67, 0.67, 0.67, 0.67, 0.67, 0.67, + 0.67, 0.67, 0.67 ; + + fates_turb_leaf_diameter = 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, + 0.04, 0.04, 0.04, 0.04 ; + + fates_turb_z0mr = 0.055, 0.055, 0.055, 0.055, 0.055, 0.055, 0.055, 0.055, + 0.055, 0.055, 0.055, 0.055 ; + + fates_turnover_branch = 150, 150, 150, 150, 150, 150, 150, 150, 150, 0, 0, 0 ; + + fates_turnover_fnrt = 1, 2, 1, 1.5, 1, 1, 1.5, 1, 1, 1, 1, 1 ; + + fates_turnover_leaf = + 1.5, 4, 1, 1.5, 1, 1, 1.5, 1, 1, 1, 1, 1 ; + + fates_turnover_senleaf_fdrought = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_wood_density = 0.548327, 0.44235, 0.454845, 0.754336, 0.548327, + 0.566452, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7 ; + + fates_woody = 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 ; + + fates_hlm_pft_map = + 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 ; + + fates_fire_FBD = 15.4, 16.8, 19.6, 999, 4, 4 ; + + fates_fire_low_moisture_Coeff = 1.12, 1.09, 0.98, 0.8, 1.15, 1.15 ; + + fates_fire_low_moisture_Slope = 0.62, 0.72, 0.85, 0.8, 0.62, 0.62 ; + + fates_fire_mid_moisture = 0.72, 0.51, 0.38, 1, 0.8, 0.8 ; + + fates_fire_mid_moisture_Coeff = 2.35, 1.47, 1.06, 0.8, 3.2, 3.2 ; + + fates_fire_mid_moisture_Slope = 2.35, 1.47, 1.06, 0.8, 3.2, 3.2 ; + + fates_fire_min_moisture = 0.18, 0.12, 0, 0, 0.24, 0.24 ; + + fates_fire_SAV = 13, 3.58, 0.98, 0.2, 66, 66 ; + + fates_frag_maxdecomp = 0.52, 0.383, 0.383, 0.19, 1, 999 ; + + fates_frag_cwd_frac = 0.045, 0.075, 0.21, 0.67 ; + + fates_maxpatches_by_landuse = 9, 4, 1, 1, 1 ; + + fates_canopy_closure_thresh = 0.8 ; + + fates_cnp_eca_plant_escalar = 1.25e-05 ; + + fates_cohort_age_fusion_tol = 0.08 ; + + fates_cohort_size_fusion_tol = 0.08 ; + + fates_comp_excln = 3 ; + + fates_damage_canopy_layer_code = 1 ; + + fates_damage_event_code = 1 ; + + fates_daylength_factor_switch = 1 ; + + fates_dev_arbitrary = _ ; + + fates_fire_active_crown_fire = 0 ; + + fates_fire_cg_strikes = 0.2 ; + + fates_fire_drying_ratio = 66000 ; + + fates_fire_durat_slope = -11.06 ; + + fates_fire_fdi_alpha = 0.00037 ; + + fates_fire_fuel_energy = 18000 ; + + fates_fire_max_durat = 240 ; + + fates_fire_miner_damp = 0.41739 ; + + fates_fire_miner_total = 0.055 ; + + fates_fire_nignitions = 15 ; + + fates_fire_part_dens = 513 ; + + fates_fire_threshold = 50 ; + + fates_frag_cwd_fcel = 0.76 ; + + fates_frag_cwd_flig = 0.24 ; + + fates_hydro_kmax_rsurf1 = 20 ; + + fates_hydro_kmax_rsurf2 = 0.0001 ; + + fates_hydro_psi0 = 0 ; + + fates_hydro_psicap = -0.6 ; + + fates_hydro_solver = 1 ; + + fates_landuse_logging_coll_under_frac = 0.55983 ; + + fates_landuse_logging_collateral_frac = 0.05 ; + + fates_landuse_logging_dbhmax = _ ; + + fates_landuse_logging_dbhmax_infra = 35 ; + + fates_landuse_logging_dbhmin = 50 ; + + fates_landuse_logging_direct_frac = 0.15 ; + + fates_landuse_logging_event_code = -30 ; + + fates_landuse_logging_export_frac = 0.8 ; + + fates_landuse_logging_mechanical_frac = 0.05 ; + + fates_landuse_pprodharv10_forest_mean = 0.8125 ; + + fates_leaf_photo_temp_acclim_thome_time = 30 ; + + fates_leaf_photo_temp_acclim_timescale = 30 ; + + fates_leaf_photo_tempsens_model = 1 ; + + fates_leaf_stomatal_assim_model = 1 ; + + fates_leaf_stomatal_model = 1 ; + + fates_leaf_theta_cj_c3 = 0.999 ; + + fates_leaf_theta_cj_c4 = 0.999 ; + + fates_maintresp_leaf_model = 1 ; + + fates_maintresp_nonleaf_baserate = 2.525e-06 ; + + fates_maxcohort = 100 ; + + fates_mort_cstarvation_model = 1 ; + + fates_mort_disturb_frac = 1 ; + + fates_mort_understorey_death = 0.55983 ; + + fates_patch_fusion_tol = 0.05 ; + + fates_phen_chilltemp = 5 ; + + fates_phen_coldtemp = 7.5 ; + + fates_phen_gddthresh_a = -68 ; + + fates_phen_gddthresh_b = 638 ; + + fates_phen_gddthresh_c = -0.01 ; + + fates_phen_mindayson = 90 ; + + fates_phen_ncolddayslim = 5 ; + + fates_q10_froz = 1.5 ; + + fates_q10_mr = 1.5 ; + + fates_rad_model = 1 ; + + fates_regeneration_model = 1 ; + + fates_soil_salinity = 0.4 ; + + fates_trs_seedling2sap_par_timescale = 32 ; + + fates_trs_seedling_emerg_h2o_timescale = 7 ; + + fates_trs_seedling_mdd_timescale = 126 ; + + fates_trs_seedling_mort_par_timescale = 32 ; + + fates_vai_top_bin_width = 1 ; + + fates_vai_width_increase_factor = 1 ; +} diff --git a/parameter_files/archive/api36.0.0_051724_patch_params.xml b/parameter_files/archive/api36.0.0_051724_patch_params.xml new file mode 100644 index 0000000000..3af518bde2 --- /dev/null +++ b/parameter_files/archive/api36.0.0_051724_patch_params.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + archive/api36.0.0_051724_params_default.xml + fates_params_default.cdl + 1,2,3,4,5,6,7,8,9,10,11,12 + + + fates_landuse_harvest_pprod10 + fates_pft + fraction + fraction of harvest wood product that goes to 10-year product pool (remainder goes to 100-year pool) + 1, 0.75, 0.75, 0.75, 1, 0.75, 1, 1, 1, 1, 1, 1 + + + fates_landuse_luc_frac_burned + fates_pft + fraction + fraction of land use change-generated and not-exported material that is burned (the remainder goes to litter) + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5 + + + fates_landuse_luc_frac_exported + fates_pft + fraction + fraction of land use change-generated wood material that is exported to wood product (the remainder is either burned or goes to litter) + 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.2, 0.2, 0.2, 0, 0, 0 + + + fates_landuse_luc_pprod10 + fates_pft + fraction + fraction of land use change wood product that goes to 10-year product pool (remainder goes to 100-year pool) + 1, 0.75, 0.75, 0.75, 1, 0.75, 1, 1, 1, 1, 1, 1 + + + fates_landuse_crop_lu_pft_vector + fates_landuseclass + NA + the FATES PFT index to use on a given crop land-use type (dummy value of -999 for non-crop types) + -999, -999, -999, -999, 11 + + + fates_max_nocomp_pfts_by_landuse + fates_landuseclass + count + maximum number of nocomp PFTs on each land use type (only used in nocomp mode) + 4, 4, 1, 1, 1 + + + fates_landuse_pprodharv10_forest_mean + + + diff --git a/parameter_files/fates_params_default.cdl b/parameter_files/fates_params_default.cdl index 0f4e16ef0b..527fc520df 100644 --- a/parameter_files/fates_params_default.cdl +++ b/parameter_files/fates_params_default.cdl @@ -1,4 +1,4 @@ -netcdf fates_params_default { +netcdf tmp { dimensions: fates_NCWD = 4 ; fates_history_age_bins = 7 ; @@ -8,12 +8,12 @@ dimensions: fates_history_size_bins = 13 ; fates_hlm_pftno = 14 ; fates_hydr_organs = 4 ; + fates_landuseclass = 5 ; fates_leafage_class = 1 ; fates_litterclass = 6 ; fates_pft = 12 ; fates_plant_organs = 4 ; fates_string_length = 60 ; - fates_landuseclass = 5 ; variables: double fates_history_ageclass_bin_edges(fates_history_age_bins) ; fates_history_ageclass_bin_edges:units = "yr" ; @@ -84,9 +84,6 @@ variables: double fates_allom_cmode(fates_pft) ; fates_allom_cmode:units = "index" ; fates_allom_cmode:long_name = "coarse root biomass allometry function index." ; - double fates_allom_crown_depth_frac(fates_pft) ; - fates_allom_crown_depth_frac:units = "fraction" ; - fates_allom_crown_depth_frac:long_name = "the depth of a cohort crown as a fraction of its height" ; double fates_allom_d2bl1(fates_pft) ; fates_allom_d2bl1:units = "variable" ; fates_allom_d2bl1:long_name = "Parameter 1 for d2bl allometry" ; @@ -114,6 +111,9 @@ variables: double fates_allom_dbh_maxheight(fates_pft) ; fates_allom_dbh_maxheight:units = "cm" ; fates_allom_dbh_maxheight:long_name = "the diameter (if any) corresponding to maximum height, diameters may increase beyond this" ; + double fates_allom_dmode(fates_pft) ; + fates_allom_dmode:units = "index" ; + fates_allom_dmode:long_name = "crown depth allometry function index" ; double fates_allom_fmode(fates_pft) ; fates_allom_fmode:units = "index" ; fates_allom_fmode:long_name = "fine root biomass allometry function index." ; @@ -129,6 +129,12 @@ variables: double fates_allom_frbstor_repro(fates_pft) ; fates_allom_frbstor_repro:units = "fraction" ; fates_allom_frbstor_repro:long_name = "fraction of bstore goes to reproduction after plant dies" ; + double fates_allom_h2cd1(fates_pft) ; + fates_allom_h2cd1:units = "variable" ; + fates_allom_h2cd1:long_name = "Parameter 1 for h2cd allometry (exp(log-intercept) or scaling). If allom_dmode=1; this is the same as former crown_depth_frac parameter" ; + double fates_allom_h2cd2(fates_pft) ; + fates_allom_h2cd2:units = "variable" ; + fates_allom_h2cd2:long_name = "Parameter 2 for h2cd allometry (log-slope or exponent). If allom_dmode=1; this is not needed (as exponent is assumed 1)" ; double fates_allom_hmode(fates_pft) ; fates_allom_hmode:units = "index" ; fates_allom_hmode:long_name = "height allometry function index." ; @@ -173,7 +179,7 @@ variables: fates_c2b:long_name = "Carbon to biomass multiplier of bulk structural tissues" ; double fates_cnp_eca_alpha_ptase(fates_pft) ; fates_cnp_eca_alpha_ptase:units = "g/m3" ; - fates_cnp_eca_alpha_ptase:long_name = "fraction of P from ptase activity sent directly to plant (ECA)" ; + fates_cnp_eca_alpha_ptase:long_name = "(INACTIVE, KEEP AT 0) fraction of P from ptase activity sent directly to plant (ECA)" ; double fates_cnp_eca_decompmicc(fates_pft) ; fates_cnp_eca_decompmicc:units = "gC/m3" ; fates_cnp_eca_decompmicc:long_name = "maximum soil microbial decomposer biomass found over depth (will be applied at a reference depth w/ exponential attenuation) (ECA)" ; @@ -191,7 +197,7 @@ variables: fates_cnp_eca_km_ptase:long_name = "half-saturation constant for biochemical P (ECA)" ; double fates_cnp_eca_lambda_ptase(fates_pft) ; fates_cnp_eca_lambda_ptase:units = "g/m3" ; - fates_cnp_eca_lambda_ptase:long_name = "critical value for biochemical production (ECA)" ; + fates_cnp_eca_lambda_ptase:long_name = "(INACTIVE, KEEP AT 0) critical value for biochemical production (ECA)" ; double fates_cnp_eca_vmax_ptase(fates_pft) ; fates_cnp_eca_vmax_ptase:units = "gP/m2/s" ; fates_cnp_eca_vmax_ptase:long_name = "maximum production rate for biochemical P (per m2) (ECA)" ; @@ -345,6 +351,18 @@ variables: double fates_landuse_grazing_palatability(fates_pft) ; fates_landuse_grazing_palatability:units = "unitless 0-1" ; fates_landuse_grazing_palatability:long_name = "Relative intensity of leaf grazing/browsing per PFT" ; + double fates_landuse_harvest_pprod10(fates_pft) ; + fates_landuse_harvest_pprod10:units = "fraction" ; + fates_landuse_harvest_pprod10:long_name = "fraction of harvest wood product that goes to 10-year product pool (remainder goes to 100-year pool)" ; + double fates_landuse_luc_frac_burned(fates_pft) ; + fates_landuse_luc_frac_burned:units = "fraction" ; + fates_landuse_luc_frac_burned:long_name = "fraction of land use change-generated and not-exported material that is burned (the remainder goes to litter)" ; + double fates_landuse_luc_frac_exported(fates_pft) ; + fates_landuse_luc_frac_exported:units = "fraction" ; + fates_landuse_luc_frac_exported:long_name = "fraction of land use change-generated wood material that is exported to wood product (the remainder is either burned or goes to litter)" ; + double fates_landuse_luc_pprod10(fates_pft) ; + fates_landuse_luc_pprod10:units = "fraction" ; + fates_landuse_luc_pprod10:long_name = "fraction of land use change wood product that goes to 10-year product pool (remainder goes to 100-year pool)" ; double fates_leaf_c3psn(fates_pft) ; fates_leaf_c3psn:units = "flag" ; fates_leaf_c3psn:long_name = "Photosynthetic pathway (1=c3, 0=c4)" ; @@ -384,12 +402,24 @@ variables: double fates_leaf_vcmaxse(fates_pft) ; fates_leaf_vcmaxse:units = "J/mol/K" ; fates_leaf_vcmaxse:long_name = "entropy term for vcmax. NOTE: if fates_leaf_photo_tempsens_model=2 then these values are NOT USED" ; + double fates_leafn_vert_scaler_coeff1(fates_pft) ; + fates_leafn_vert_scaler_coeff1:units = "unitless" ; + fates_leafn_vert_scaler_coeff1:long_name = "Coefficient one for decrease in leaf nitrogen through the canopy, from Lloyd et al. 2010." ; + double fates_leafn_vert_scaler_coeff2(fates_pft) ; + fates_leafn_vert_scaler_coeff2:units = "unitless" ; + fates_leafn_vert_scaler_coeff2:long_name = "Coefficient two for decrease in leaf nitrogen through the canopy, from Lloyd et al. 2010." ; double fates_maintresp_leaf_atkin2017_baserate(fates_pft) ; fates_maintresp_leaf_atkin2017_baserate:units = "umol CO2/m^2/s" ; fates_maintresp_leaf_atkin2017_baserate:long_name = "Leaf maintenance respiration base rate parameter (r0) per Atkin et al 2017" ; double fates_maintresp_leaf_ryan1991_baserate(fates_pft) ; fates_maintresp_leaf_ryan1991_baserate:units = "gC/gN/s" ; fates_maintresp_leaf_ryan1991_baserate:long_name = "Leaf maintenance respiration base rate per Ryan et al 1991" ; + double fates_maintresp_leaf_vert_scaler_coeff1(fates_pft) ; + fates_maintresp_leaf_vert_scaler_coeff1:units = "unitless" ; + fates_maintresp_leaf_vert_scaler_coeff1:long_name = "Leaf maintenance respiration decrease through the canopy. Only applies to Atkin et al. 2017. For proportionality between photosynthesis and respiration through the canopy, match with fates_leafn_vert_scaler_coeff1." ; + double fates_maintresp_leaf_vert_scaler_coeff2(fates_pft) ; + fates_maintresp_leaf_vert_scaler_coeff2:units = "unitless" ; + fates_maintresp_leaf_vert_scaler_coeff2:long_name = "Leaf maintenance respiration decrease through the canopy. Only applies to Atkin et al. 2017. For proportionality between photosynthesis and respiration through the canopy, match with fates_leafn_vert_scaler_coeff2." ; double fates_maintresp_reduction_curvature(fates_pft) ; fates_maintresp_reduction_curvature:units = "unitless (0-1)" ; fates_maintresp_reduction_curvature:long_name = "curvature of MR reduction as f(carbon storage), 1=linear, 0=very curved" ; @@ -476,7 +506,7 @@ variables: fates_phen_stem_drop_fraction:long_name = "fraction of stems to drop for non-woody species during drought/cold" ; double fates_phen_stress_decid(fates_pft) ; fates_phen_stress_decid:units = "logical flag" ; - fates_phen_stress_decid:long_name = "Binary flag for stress-deciduous leaf habit" ; + fates_phen_stress_decid:long_name = "Flag for stress/drought-deciduous leaf habit. 0 - not stress deciduous; 1 - default drought deciduous (two target states only, fully flushed or fully abscised); 2 - semi-deciduous" ; double fates_prescribed_npp_canopy(fates_pft) ; fates_prescribed_npp_canopy:units = "kgC / m^2 / yr" ; fates_prescribed_npp_canopy:long_name = "NPP per unit crown area of canopy trees for prescribed physiology mode" ; @@ -675,9 +705,15 @@ variables: double fates_frag_cwd_frac(fates_NCWD) ; fates_frag_cwd_frac:units = "fraction" ; fates_frag_cwd_frac:long_name = "fraction of woody (bdead+bsw) biomass destined for CWD pool" ; + double fates_landuse_crop_lu_pft_vector(fates_landuseclass) ; + fates_landuse_crop_lu_pft_vector:units = "NA" ; + fates_landuse_crop_lu_pft_vector:long_name = "the FATES PFT index to use on a given crop land-use type (dummy value of -999 for non-crop types)" ; double fates_landuse_grazing_rate(fates_landuseclass) ; fates_landuse_grazing_rate:units = "1/day" ; fates_landuse_grazing_rate:long_name = "fraction of leaf biomass consumed by grazers per day" ; + double fates_max_nocomp_pfts_by_landuse(fates_landuseclass) ; + fates_max_nocomp_pfts_by_landuse:units = "count" ; + fates_max_nocomp_pfts_by_landuse:long_name = "maximum number of nocomp PFTs on each land use type (only used in nocomp mode)" ; double fates_maxpatches_by_landuse(fates_landuseclass) ; fates_maxpatches_by_landuse:units = "count" ; fates_maxpatches_by_landuse:long_name = "maximum number of patches per site on each land use type" ; @@ -702,6 +738,9 @@ variables: double fates_damage_event_code ; fates_damage_event_code:units = "unitless" ; fates_damage_event_code:long_name = "Integer code that options how damage events are structured" ; + double fates_daylength_factor_switch ; + fates_daylength_factor_switch:units = "unitless" ; + fates_daylength_factor_switch:long_name = "user switch for turning on (1) or off (0) the day length factor scaling for photosynthetic parameters (ie scale vcmax and jmax)" ; double fates_dev_arbitrary ; fates_dev_arbitrary:units = "unknown" ; fates_dev_arbitrary:long_name = "Unassociated free parameter that developers can use for testing arbitrary new hypotheses" ; @@ -717,15 +756,9 @@ variables: double fates_fire_durat_slope ; fates_fire_durat_slope:units = "NA" ; fates_fire_durat_slope:long_name = "spitfire parameter, fire max duration slope, Equation 14 Thonicke et al 2010" ; - double fates_fire_fdi_a ; - fates_fire_fdi_a:units = "NA" ; - fates_fire_fdi_a:long_name = "spitfire parameter, fire danger index, EQ 5 Thonicke et al 2010" ; double fates_fire_fdi_alpha ; fates_fire_fdi_alpha:units = "NA" ; fates_fire_fdi_alpha:long_name = "spitfire parameter, EQ 7 Venevsky et al. GCB 2002,(modified EQ 8 Thonicke et al. 2010) " ; - double fates_fire_fdi_b ; - fates_fire_fdi_b:units = "NA" ; - fates_fire_fdi_b:long_name = "spitfire parameter, fire danger index, EQ 5 Thonicke et al 2010 " ; double fates_fire_fuel_energy ; fates_fire_fuel_energy:units = "kJ/kg" ; fates_fire_fuel_energy:long_name = "spitfire parameter, heat content of fuel" ; @@ -807,9 +840,6 @@ variables: double fates_landuse_logging_mechanical_frac ; fates_landuse_logging_mechanical_frac:units = "fraction" ; fates_landuse_logging_mechanical_frac:long_name = "Fraction of stems killed due infrastructure an other mechanical means" ; - double fates_landuse_pprodharv10_forest_mean ; - fates_landuse_pprodharv10_forest_mean:units = "fraction" ; - fates_landuse_pprodharv10_forest_mean:long_name = "mean harvest mortality proportion of deadstem to 10-yr product (pprodharv10) of all woody PFT types" ; double fates_leaf_photo_temp_acclim_thome_time ; fates_leaf_photo_temp_acclim_thome_time:units = "years" ; fates_leaf_photo_temp_acclim_thome_time:long_name = "Length of the window for the long-term (i.e. T_home in Kumarathunge et al 2019) exponential moving average (ema) of vegetation temperature used in photosynthesis temperature acclimation (used if fates_leaf_photo_tempsens_model = 2)" ; @@ -840,6 +870,9 @@ variables: double fates_maxcohort ; fates_maxcohort:units = "count" ; fates_maxcohort:long_name = "maximum number of cohorts per patch. Actual number of cohorts also depend on cohort fusion tolerances" ; + double fates_mort_cstarvation_model ; + fates_mort_cstarvation_model:units = "unitless" ; + fates_mort_cstarvation_model:long_name = "switch defining the carbon starvation model ( 1) Linear or 2) Exponential) in the mortality_rates function." ; double fates_mort_disturb_frac ; fates_mort_disturb_frac:units = "fraction" ; fates_mort_disturb_frac:long_name = "fraction of canopy mortality that results in disturbance (i.e. transfer of area from new to old patch)" ; @@ -976,11 +1009,11 @@ data: fates_alloc_store_priority_frac = 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8 ; - fates_allom_agb1 = 0.06896, 0.06896, 0.06896, 0.06896, 0.06896, 0.06896, - 0.06896, 0.06896, 0.06896, 0.01, 0.01, 0.01 ; + fates_allom_agb1 = 0.0673, 0.1364012, 0.0393057, 0.2653695, 0.0673, + 0.0728698, 0.06896, 0.06896, 0.06896, 0.01, 0.01, 0.01 ; - fates_allom_agb2 = 0.572, 0.572, 0.572, 0.572, 0.572, 0.572, 0.572, 0.572, - 0.572, 0.572, 0.572, 0.572 ; + fates_allom_agb2 = 0.976, 0.9449041, 1.087335, 0.8321321, 0.976, 1.0373211, + 0.572, 0.572, 0.572, 0.572, 0.572, 0.572 ; fates_allom_agb3 = 1.94, 1.94, 1.94, 1.94, 1.94, 1.94, 1.94, 1.94, 1.94, 1.94, 1.94, 1.94 ; @@ -991,42 +1024,43 @@ data: fates_allom_agb_frac = 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6 ; - fates_allom_amode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + fates_allom_amode = 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1 ; - fates_allom_blca_expnt_diff = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; + fates_allom_blca_expnt_diff = -0.12, -0.34, -0.32, -0.22, -0.12, -0.35, 0, + 0, 0, 0, 0, 0 ; fates_allom_cmode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; - fates_allom_crown_depth_frac = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.95, 0.95, - 0.95, 1, 1, 1 ; - - fates_allom_d2bl1 = 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, + fates_allom_d2bl1 = 0.04, 0.07, 0.07, 0.01, 0.04, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07 ; - fates_allom_d2bl2 = 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, - 1.3 ; + fates_allom_d2bl2 = 1.6019679, 1.5234373, 1.3051237, 1.9621397, 1.6019679, + 1.3998939, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3 ; fates_allom_d2bl3 = 0.55, 0.55, 0.55, 0.55, 0.55, 0.55, 0.55, 0.55, 0.55, 0.55, 0.55, 0.55 ; - fates_allom_d2ca_coefficient_max = 0.6568464, 0.6568464, 0.6568464, - 0.6568464, 0.6568464, 0.6568464, 0.6568464, 0.6568464, 0.6568464, + fates_allom_d2ca_coefficient_max = 0.2715891, 0.3693718, 1.0787259, + 0.0579297, 0.2715891, 1.1553612, 0.6568464, 0.6568464, 0.6568464, 0.6568464, 0.6568464, 0.6568464 ; - fates_allom_d2ca_coefficient_min = 0.3381119, 0.3381119, 0.3381119, - 0.3381119, 0.3381119, 0.3381119, 0.3381119, 0.3381119, 0.3381119, - 0.3381119, 0.3381119, 0.3381119 ; + fates_allom_d2ca_coefficient_min = 0.2715891, 0.3693718, 1.0787259, + 0.0579297, 0.2715891, 1.1553612, 0.6568464, 0.6568464, 0.6568464, + 0.6568464, 0.6568464, 0.6568464 ; - fates_allom_d2h1 = 0.64, 0.64, 0.64, 0.64, 0.64, 0.64, 0.64, 0.64, 0.64, - 0.64, 0.64, 0.64 ; + fates_allom_d2h1 = 78.4087704, 306.842667, 106.8745821, 104.3586841, + 78.4087704, 31.4557047, 0.64, 0.64, 0.64, 0.64, 0.64, 0.64 ; - fates_allom_d2h2 = 0.37, 0.37, 0.37, 0.37, 0.37, 0.37, 0.37, 0.37, 0.37, - 0.37, 0.37, 0.37 ; + fates_allom_d2h2 = 0.8124383, 0.752377, 0.9471302, 1.1146973, 0.8124383, + 0.9734088, 0.37, 0.37, 0.37, 0.37, 0.37, 0.37 ; - fates_allom_d2h3 = -999.9, -999.9, -999.9, -999.9, -999.9, -999.9, -999.9, - -999.9, -999.9, -999.9, -999.9, -999.9 ; + fates_allom_d2h3 = 47.6666164, 196.6865691, 93.9790461, 160.6835089, + 47.6666164, 16.5928174, -999.9, -999.9, -999.9, -999.9, -999.9, -999.9 ; - fates_allom_dbh_maxheight = 90, 80, 80, 80, 90, 80, 3, 3, 2, 0.35, 0.35, 0.35 ; + fates_allom_dbh_maxheight = 1000, 1000, 1000, 1000, 1000, 1000, 3, 3, 2, + 0.35, 0.35, 0.35 ; + + fates_allom_dmode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; fates_allom_fmode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; @@ -1038,7 +1072,11 @@ data: fates_allom_frbstor_repro = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; - fates_allom_hmode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + fates_allom_h2cd1 = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.95, 0.95, 0.95, 1, 1, 1 ; + + fates_allom_h2cd2 = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + + fates_allom_hmode = 5, 5, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1 ; fates_allom_l2fr = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; @@ -1047,7 +1085,7 @@ data: fates_allom_la_per_sa_slp = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; - fates_allom_lmode = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + fates_allom_lmode = 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1 ; fates_allom_sai_scaler = 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1 ; @@ -1071,8 +1109,7 @@ data: fates_c2b = 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ; - fates_cnp_eca_alpha_ptase = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, - 0.5, 0.5, 0.5 ; + fates_cnp_eca_alpha_ptase = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; fates_cnp_eca_decompmicc = 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280 ; @@ -1088,7 +1125,7 @@ data: fates_cnp_eca_km_ptase = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; - fates_cnp_eca_lambda_ptase = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; + fates_cnp_eca_lambda_ptase = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; fates_cnp_eca_vmax_ptase = 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, 5e-09, 5e-09 ; @@ -1286,6 +1323,16 @@ data: fates_landuse_grazing_palatability = 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1 ; + fates_landuse_harvest_pprod10 = 1, 0.75, 0.75, 0.75, 1, 0.75, 1, 1, 1, 1, 1, 1 ; + + fates_landuse_luc_frac_burned = 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5 ; + + fates_landuse_luc_frac_exported = 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.2, 0.2, + 0.2, 0, 0, 0 ; + + fates_landuse_luc_pprod10 = 1, 0.75, 0.75, 0.75, 1, 0.75, 1, 1, 1, 1, 1, 1 ; + fates_leaf_c3psn = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 ; fates_leaf_jmaxha = 43540, 43540, 43540, 43540, 43540, 43540, 43540, 43540, @@ -1323,6 +1370,12 @@ data: fates_leaf_vcmaxse = 485, 485, 485, 485, 485, 485, 485, 485, 485, 485, 485, 485 ; + fates_leafn_vert_scaler_coeff1 = 0.00963, 0.00963, 0.00963, 0.00963, + 0.00963, 0.00963, 0.00963, 0.00963, 0.00963, 0.00963, 0.00963, 0.00963 ; + + fates_leafn_vert_scaler_coeff2 = 2.43, 2.43, 2.43, 2.43, 2.43, 2.43, 2.43, + 2.43, 2.43, 2.43, 2.43, 2.43 ; + fates_maintresp_leaf_atkin2017_baserate = 1.756, 1.4995, 1.4995, 1.756, 1.756, 1.756, 2.0749, 2.0749, 2.0749, 2.1956, 2.1956, 2.1956 ; @@ -1330,6 +1383,13 @@ data: 2.525e-06, 2.525e-06, 2.525e-06, 2.525e-06, 2.525e-06, 2.525e-06, 2.525e-06, 2.525e-06, 2.525e-06 ; + fates_maintresp_leaf_vert_scaler_coeff1 = 0.00963, 0.00963, 0.00963, + 0.00963, 0.00963, 0.00963, 0.00963, 0.00963, 0.00963, 0.00963, 0.00963, + 0.00963 ; + + fates_maintresp_leaf_vert_scaler_coeff2 = 2.43, 2.43, 2.43, 2.43, 2.43, + 2.43, 2.43, 2.43, 2.43, 2.43, 2.43, 2.43 ; + fates_maintresp_reduction_curvature = 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01 ; @@ -1576,8 +1636,8 @@ data: fates_turnover_senleaf_fdrought = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ; - fates_wood_density = 0.7, 0.4, 0.7, 0.53, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, - 0.7 ; + fates_wood_density = 0.548327, 0.44235, 0.454845, 0.754336, 0.548327, + 0.566452, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7 ; fates_woody = 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 ; @@ -1617,8 +1677,12 @@ data: fates_frag_cwd_frac = 0.045, 0.075, 0.21, 0.67 ; + fates_landuse_crop_lu_pft_vector = -999, -999, -999, -999, 11 ; + fates_landuse_grazing_rate = 0.0, 0.0, 0.04, 0.04, 0.0 ; + fates_max_nocomp_pfts_by_landuse = 4, 4, 1, 1, 1 ; + fates_maxpatches_by_landuse = 9, 4, 1, 1, 1 ; fates_canopy_closure_thresh = 0.8 ; @@ -1635,6 +1699,8 @@ data: fates_damage_event_code = 1 ; + fates_daylength_factor_switch = 1 ; + fates_dev_arbitrary = _ ; fates_fire_active_crown_fire = 0 ; @@ -1645,12 +1711,8 @@ data: fates_fire_durat_slope = -11.06 ; - fates_fire_fdi_a = 17.62 ; - fates_fire_fdi_alpha = 0.00037 ; - fates_fire_fdi_b = 243.12 ; - fates_fire_fuel_energy = 18000 ; fates_fire_max_durat = 240 ; @@ -1705,8 +1767,6 @@ data: fates_landuse_logging_mechanical_frac = 0.05 ; - fates_landuse_pprodharv10_forest_mean = 0.8125 ; - fates_leaf_photo_temp_acclim_thome_time = 30 ; fates_leaf_photo_temp_acclim_timescale = 30 ; @@ -1727,6 +1787,8 @@ data: fates_maxcohort = 100 ; + fates_mort_cstarvation_model = 1 ; + fates_mort_disturb_frac = 1 ; fates_mort_understorey_death = 0.55983 ; diff --git a/parameter_files/patch_default_bciopt224.xml b/parameter_files/patch_default_bciopt224.xml index 8ab504ed31..b1ec419f64 100644 --- a/parameter_files/patch_default_bciopt224.xml +++ b/parameter_files/patch_default_bciopt224.xml @@ -2,7 +2,7 @@ This parameter dataset was created by Ryan Knox rgknox@lbl.gov. Please contact if using in published work. The calibration uses the following datasets: [1] Ely et al. 2019. Leaf mass area, Panama. NGEE-Tropics data collection.http://dx.doi.org/10.15486/ngt/1411973 and [2] Condit et al. 2019. Complete data from the Barro Colorado 50-ha plot. https://doi.org/10.15146/5xcp-0d46. [3] Koven et al. 2019. Benchmarking and parameter sensitivity of physiological and vegetation dynamics using the functionally assembled terrestrial ecosystem simulator. Biogeosciences. The ECA nutrient aquisition parmeters are unconstrained, the file output naming convention vmn6phi is shorthand for vmax for nitrogen uptake is order e-6 and for phosphorus is excessively high. These parameters were calibrated with the special fates modification in main/EDTypesMod.F90: nclmax = 3 fates_params_default.cdl - fates_params_opt224_040822_api25.cdl + fates_params_opt224_092023_api26.cdl 1 diff --git a/parteh/CMakeLists.txt b/parteh/CMakeLists.txt new file mode 100644 index 0000000000..67c8a175a2 --- /dev/null +++ b/parteh/CMakeLists.txt @@ -0,0 +1,8 @@ +list(APPEND fates_sources + PRTParametersMod.F90 + PRTParamsFATESMod.F90 + PRTGenericMod.F90 + PRTAllometricCarbonMod.F90 + PRTAllometricCNPMod.F90) + +sourcelist_to_parent(fates_sources) \ No newline at end of file diff --git a/parteh/PRTParametersMod.F90 b/parteh/PRTParametersMod.F90 index f2419c3334..febd4a3b55 100644 --- a/parteh/PRTParametersMod.F90 +++ b/parteh/PRTParametersMod.F90 @@ -60,6 +60,11 @@ module PRTParametersMod real(r8), allocatable :: turnover_nitr_retrans(:,:) ! nitrogen re-translocation fraction (pft x organ) real(r8), allocatable :: turnover_phos_retrans(:,:) ! phosphorus re-translocation fraction (pft x organ) ! Parameters dimensioned by PFT and leaf age + + ! These vertical n profile scalers affect crown allometry and sla, thus they + ! are here in the PRT module + real(r8), allocatable :: leafn_vert_scaler_coeff1(:) ! Coefficient one for decrease of leaf N through the canopy + real(r8), allocatable :: leafn_vert_scaler_coeff2(:) ! Coefficient two for decrease of leaf N through the canopy real(r8), allocatable :: grperc(:) ! Growth respiration per unit Carbon gained ! One value for whole plant @@ -117,24 +122,24 @@ module PRTParametersMod real(r8), allocatable :: c2b(:) ! Carbon to biomass multiplier [kg/kgC] real(r8), allocatable :: wood_density(:) ! wood density g cm^-3 ... - real(r8), allocatable :: crown_depth_frac(:) ! fraction of the height of the plant integer , allocatable :: woody(:) ! Does the plant have wood? (1=yes, 0=no) ! that is occupied by crown real(r8), allocatable :: slamax(:) ! Maximum specific leaf area of plant (at bottom) [m2/gC] real(r8), allocatable :: slatop(:) ! Specific leaf area at canopy top [m2/gC] real(r8), allocatable :: allom_sai_scaler(:) ! real(r8), allocatable :: allom_dbh_maxheight(:) ! dbh at which height growth ceases - real(r8), allocatable :: allom_hmode(:) ! height allometry function type - real(r8), allocatable :: allom_lmode(:) ! maximum leaf allometry function type - real(r8), allocatable :: allom_fmode(:) ! maximum root allometry function type - real(r8), allocatable :: allom_amode(:) ! AGB allometry function type - real(r8), allocatable :: allom_cmode(:) ! Coarse root allometry function type - real(r8), allocatable :: allom_smode(:) ! sapwood allometry function type - real(r8), allocatable :: allom_stmode(:) ! storage allometry functional type + integer , allocatable :: allom_hmode(:) ! height allometry function type + integer , allocatable :: allom_lmode(:) ! maximum leaf allometry function type + integer , allocatable :: allom_fmode(:) ! maximum root allometry function type + integer , allocatable :: allom_amode(:) ! AGB allometry function type + integer , allocatable :: allom_cmode(:) ! Coarse root allometry function type + integer , allocatable :: allom_smode(:) ! sapwood allometry function type + integer , allocatable :: allom_stmode(:) ! storage allometry functional type ! 0 - storage is proportional to maximum leaf biomass ! (considering trimmed) ! 1 - storage is proportional to maximum leaf biomass ! (untrimmed) + integer , allocatable :: allom_dmode(:) ! crown depth allometry function type ! (HARD-CODED FOR TIME BEING, RGK 11-2017) real(r8), allocatable :: allom_la_per_sa_int(:) ! Leaf area to sap area conversion, intercept ! (sapwood area / leaf area) [cm2/m2] @@ -161,6 +166,12 @@ module PRTParametersMod real(r8), allocatable :: allom_agb3(:) ! Parameter 3 for agb allometry real(r8), allocatable :: allom_agb4(:) ! Parameter 3 for agb allometry + real(r8), allocatable :: allom_h2cd1(:) ! Parameter 1 for crown depth allometry. When allom_dmode=1 + ! this is fraction of the height of the plant that is + ! considered crown (former parameter crown_depth_frac). + real(r8), allocatable :: allom_h2cd2(:) ! Exponent for crown depth allometry. Used only when + ! allom_dmode /= 1. + real(r8), allocatable :: allom_zroot_max_dbh(:) ! dbh at which maximum rooting depth saturates (largest possible) [cm] real(r8), allocatable :: allom_zroot_max_z(:) ! the maximum rooting depth defined at dbh = fates_allom_zroot_max_dbh [m] real(r8), allocatable :: allom_zroot_min_dbh(:) ! dbh at which the maximum rooting depth for a recruit is defined [cm] diff --git a/parteh/PRTParamsFATESMod.F90 b/parteh/PRTParamsFATESMod.F90 index 098b1e3738..d586237778 100644 --- a/parteh/PRTParamsFATESMod.F90 +++ b/parteh/PRTParamsFATESMod.F90 @@ -201,10 +201,6 @@ subroutine PRTRegisterPFT(fates_params) call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_allom_crown_depth_frac' - call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & - dimension_names=dim_names, lower_bounds=dim_lower_bound) - name = 'fates_wood_density' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) @@ -241,6 +237,14 @@ subroutine PRTRegisterPFT(fates_params) call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) + name = 'fates_leafn_vert_scaler_coeff1' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + + name = 'fates_leafn_vert_scaler_coeff2' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + name = 'fates_recruit_seed_alloc_mature' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) @@ -321,6 +325,10 @@ subroutine PRTRegisterPFT(fates_params) call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) + name = 'fates_allom_dmode' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + name = 'fates_allom_la_per_sa_int' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) @@ -385,6 +393,14 @@ subroutine PRTRegisterPFT(fates_params) call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) + name = 'fates_allom_h2cd1' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + + name = 'fates_allom_h2cd2' + call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & + dimension_names=dim_names, lower_bounds=dim_lower_bound) + name = 'fates_allom_zroot_max_dbh' call fates_params%RegisterParameter(name=name, dimension_shape=dimension_shape_1d, & dimension_names=dim_names, lower_bounds=dim_lower_bound) @@ -501,10 +517,6 @@ subroutine PRTReceivePFT(fates_params) call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%fnrt_prof_mode) - name = 'fates_allom_crown_depth_frac' - call fates_params%RetrieveParameterAllocate(name=name, & - data=prt_params%crown_depth_frac) - name = 'fates_woody' call fates_params%RetrieveParameterAllocate(name=name, & data=tmpreal) @@ -536,6 +548,14 @@ subroutine PRTReceivePFT(fates_params) call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%root_long) + name = 'fates_leafn_vert_scaler_coeff1' + call fates_params%RetrieveParameterAllocate(name=name, & + data=prt_params%leafn_vert_scaler_coeff1) + + name = 'fates_leafn_vert_scaler_coeff2' + call fates_params%RetrieveParameterAllocate(name=name, & + data=prt_params%leafn_vert_scaler_coeff2) + name = 'fates_recruit_seed_alloc_mature' call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%seed_alloc_mature) @@ -566,31 +586,59 @@ subroutine PRTReceivePFT(fates_params) name = 'fates_allom_hmode' call fates_params%RetrieveParameterAllocate(name=name, & - data=prt_params%allom_hmode) + data=tmpreal) + allocate(prt_params%allom_hmode(size(tmpreal,dim=1))) + call ArrayNint(tmpreal,prt_params%allom_hmode) + deallocate(tmpreal) name = 'fates_allom_lmode' call fates_params%RetrieveParameterAllocate(name=name, & - data=prt_params%allom_lmode) + data=tmpreal) + allocate(prt_params%allom_lmode(size(tmpreal,dim=1))) + call ArrayNint(tmpreal,prt_params%allom_lmode) + deallocate(tmpreal) name = 'fates_allom_fmode' call fates_params%RetrieveParameterAllocate(name=name, & - data=prt_params%allom_fmode) + data=tmpreal) + allocate(prt_params%allom_fmode(size(tmpreal,dim=1))) + call ArrayNint(tmpreal,prt_params%allom_fmode) + deallocate(tmpreal) name = 'fates_allom_amode' call fates_params%RetrieveParameterAllocate(name=name, & - data=prt_params%allom_amode) + data=tmpreal) + allocate(prt_params%allom_amode(size(tmpreal,dim=1))) + call ArrayNint(tmpreal,prt_params%allom_amode) + deallocate(tmpreal) name = 'fates_allom_stmode' call fates_params%RetrieveParameterAllocate(name=name, & - data=prt_params%allom_stmode) + data=tmpreal) + allocate(prt_params%allom_stmode(size(tmpreal,dim=1))) + call ArrayNint(tmpreal,prt_params%allom_stmode) + deallocate(tmpreal) name = 'fates_allom_cmode' call fates_params%RetrieveParameterAllocate(name=name, & - data=prt_params%allom_cmode) + data=tmpreal) + allocate(prt_params%allom_cmode(size(tmpreal,dim=1))) + call ArrayNint(tmpreal,prt_params%allom_cmode) + deallocate(tmpreal) name = 'fates_allom_smode' call fates_params%RetrieveParameterAllocate(name=name, & - data=prt_params%allom_smode) + data=tmpreal) + allocate(prt_params%allom_smode(size(tmpreal,dim=1))) + call ArrayNint(tmpreal,prt_params%allom_smode) + deallocate(tmpreal) + + name = 'fates_allom_dmode' + call fates_params%RetrieveParameterAllocate(name=name, & + data=tmpreal) + allocate(prt_params%allom_dmode(size(tmpreal,dim=1))) + call ArrayNint(tmpreal,prt_params%allom_dmode) + deallocate(tmpreal) name = 'fates_allom_la_per_sa_int' call fates_params%RetrieveParameterAllocate(name=name, & @@ -680,6 +728,14 @@ subroutine PRTReceivePFT(fates_params) call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%allom_agb4) + name = 'fates_allom_h2cd1' + call fates_params%RetrieveParameterAllocate(name=name, & + data=prt_params%allom_h2cd1) + + name = 'fates_allom_h2cd2' + call fates_params%RetrieveParameterAllocate(name=name, & + data=prt_params%allom_h2cd2) + name = 'fates_allom_zroot_max_dbh' call fates_params%RetrieveParameterAllocate(name=name, & data=prt_params%allom_zroot_max_dbh) @@ -979,6 +1035,8 @@ subroutine FatesReportPFTParams(is_master) write(fates_log(),fmt0) 'allom_agb2 = ',prt_params%allom_agb2 write(fates_log(),fmt0) 'allom_agb3 = ',prt_params%allom_agb3 write(fates_log(),fmt0) 'allom_agb4 = ',prt_params%allom_agb4 + write(fates_log(),fmt0) 'allom_h2cd1 = ',prt_params%allom_h2cd1 + write(fates_log(),fmt0) 'allom_h2cd2 = ',prt_params%allom_h2cd2 write(fates_log(),fmt0) 'allom_zroot_max_dbh = ',prt_params%allom_zroot_max_dbh write(fates_log(),fmt0) 'allom_zroot_max_z = ',prt_params%allom_zroot_max_z @@ -990,7 +1048,6 @@ subroutine FatesReportPFTParams(is_master) write(fates_log(),fmt0) 'stoich_phos = ',prt_params%phos_stoich_p1 write(fates_log(),fmt0) 'alloc_organ_priority = ',prt_params%alloc_priority write(fates_log(),fmt0) 'woody = ',prt_params%woody - write(fates_log(),fmt0) 'crown_depth_frac = ',prt_params%crown_depth_frac write(fates_log(),fmt0) 'roota_par = ',prt_params%fnrt_prof_a write(fates_log(),fmt0) 'rootb_par = ',prt_params%fnrt_prof_b write(fates_log(),fmt0) 'fnrt_prof_mode = ',prt_params%fnrt_prof_mode @@ -999,6 +1056,8 @@ subroutine FatesReportPFTParams(is_master) write(fates_log(),fmti) 'organ_id = ',prt_params%organ_id write(fates_log(),fmt0) 'nitr_store_ratio = ',prt_params%nitr_store_ratio write(fates_log(),fmt0) 'phos_store_ratio = ',prt_params%phos_store_ratio + write(fates_log(),fmt0) 'leafn_vert_scaler_coeff1 = ',prt_params%leafn_vert_scaler_coeff1 + write(fates_log(),fmt0) 'leafn_vert_scaler_coeff2 = ',prt_params%leafn_vert_scaler_coeff2 write(fates_log(),*) '-------------------------------------------------' end if @@ -1060,6 +1119,9 @@ subroutine PRTCheckParams(is_master) logical :: is_season_decid ! Is the PFT cold-deciduous? logical :: is_stress_decid ! Is the PFT drought-deciduous? logical :: is_semi_decid ! Is the PFT drought semi-deciduous? + integer :: nerror ! Count number of errors. If this is not + ! zero by theend of the subroutine, stop + ! the run. npft = size(prt_params%evergreen,1) @@ -1070,14 +1132,21 @@ subroutine PRTCheckParams(is_master) if(.not.is_master) return + ! Initialise nerror with zero. If anything is incorrectly set, nerror will be + ! positive, but we will hold on until all checks are performed before stopping + ! the run. + nerror = 0 if( any(prt_params%organ_id(:)<1) .or. & any(prt_params%organ_id(:)>num_organ_types) ) then + write(fates_log(),*) '---~---' write(fates_log(),*) 'prt_organ_ids should match the global ids' write(fates_log(),*) 'of organ types found in PRTGenericMod.F90' write(fates_log(),*) 'organ_ids: ',prt_params%organ_id(:) - write(fates_log(),*) 'Aborting' - call endrun(msg=errMsg(sourcefile, __LINE__)) + write(fates_log(),*) '---~---' + write(fates_log(),*) '' + write(fates_log(),*) '' + nerror = nerror + 1 end if ! Check to make sure the organ ids are valid if this is the @@ -1087,22 +1156,28 @@ subroutine PRTCheckParams(is_master) do io = 1,norgans if(prt_params%organ_id(io) == repro_organ) then + write(fates_log(),*) '---~---' write(fates_log(),*) 'with flexible cnp or c-only alloc hypotheses' write(fates_log(),*) 'reproductive tissues are a special case' write(fates_log(),*) 'and therefore should not be included in' write(fates_log(),*) 'the parameter file organ list' write(fates_log(),*) 'fates_prt_organ_id: ',prt_params%organ_id(:) - write(fates_log(),*) 'Aborting' - call endrun(msg=errMsg(sourcefile, __LINE__)) + write(fates_log(),*) '---~---' + write(fates_log(),*) '' + write(fates_log(),*) '' + nerror = nerror + 1 end if if(prt_params%organ_id(io) == store_organ) then + write(fates_log(),*) '---~---' write(fates_log(),*) 'with flexible cnp or c-only alloc hypotheses' write(fates_log(),*) 'storage is a special case' write(fates_log(),*) 'and therefore should not be included in' write(fates_log(),*) 'the parameter file organ list' write(fates_log(),*) 'fates_prt_organ_id: ',prt_params%organ_id(:) - write(fates_log(),*) 'Aborting' - call endrun(msg=errMsg(sourcefile, __LINE__)) + write(fates_log(),*) '---~---' + write(fates_log(),*) '' + write(fates_log(),*) '' + nerror = nerror + 1 end if end do @@ -1112,10 +1187,13 @@ subroutine PRTCheckParams(is_master) ! between 0 and 1 if (hlm_parteh_mode .eq. prt_cnp_flex_allom_hyp) then if(any(prt_params%nfix_mresp_scfrac(:)<0._r8) .or. any(prt_params%nfix_mresp_scfrac(:)>1.0_r8)) then + write(fates_log(),*) '---~---' write(fates_log(),*) 'The N fixation surcharge nfix_mresp_sfrac (fates_nfix1) must be between 0-1.' write(fates_log(),*) 'here are the values: ',prt_params%nfix_mresp_scfrac(:) - write(fates_log(),*) 'Aborting' - call endrun(msg=errMsg(sourcefile, __LINE__)) + write(fates_log(),*) '---~---' + write(fates_log(),*) '' + write(fates_log(),*) '' + nerror = nerror + 1 end if end if @@ -1136,14 +1214,17 @@ subroutine PRTCheckParams(is_master) ( is_evergreen .and. is_stress_decid ) .or. & ( is_season_decid .and. is_stress_decid ) ) then + write(fates_log(),*) '---~---' write(fates_log(),*) 'PFT # ',ipft,' must be defined as having one of three' write(fates_log(),*) 'phenology habits, ie, only one of the flags below should' write(fates_log(),*) 'be different than ',ifalse write(fates_log(),*) 'stress_decid: ',prt_params%stress_decid(ipft) write(fates_log(),*) 'season_decid: ',prt_params%season_decid(ipft) write(fates_log(),*) 'evergreen: ',prt_params%evergreen(ipft) - write(fates_log(),*) 'Aborting' - call endrun(msg=errMsg(sourcefile, __LINE__)) + write(fates_log(),*) '---~---' + write(fates_log(),*) '' + write(fates_log(),*) '' + nerror = nerror + 1 end if @@ -1155,6 +1236,7 @@ subroutine PRTCheckParams(is_master) ! In case the product of the lower and upper thresholds is negative, the ! thresholds are inconsistent as both should be defined using the same ! quantity. + write(fates_log(),*) '---~---' write(fates_log(),*) ' When using drought semi-deciduous phenology,' write(fates_log(),*) ' the moist threshold must have the same sign as' write(fates_log(),*) ' the dry threshold. Positive = soil water content [m3/m3],' @@ -1163,10 +1245,13 @@ subroutine PRTCheckParams(is_master) write(fates_log(),*) ' Stress_decid = ',prt_params%stress_decid(ipft) write(fates_log(),*) ' fates_phen_drought_threshold = ',prt_params%phen_drought_threshold(ipft) write(fates_log(),*) ' fates_phen_moist_threshold = ',prt_params%phen_moist_threshold (ipft) - write(fates_log(),*) ' Aborting' - call endrun(msg=errMsg(sourcefile, __LINE__)) + write(fates_log(),*) '---~---' + write(fates_log(),*) '' + write(fates_log(),*) '' + nerror = nerror + 1 elseif ( prt_params%phen_drought_threshold(ipft) >= prt_params%phen_moist_threshold(ipft) ) then + write(fates_log(),*) '---~---' write(fates_log(),*) ' When using drought semi-deciduous phenology,' write(fates_log(),*) ' the moist threshold must be greater than the dry threshold.' write(fates_log(),*) ' By greater we mean more positive or less negative, and' @@ -1175,8 +1260,10 @@ subroutine PRTCheckParams(is_master) write(fates_log(),*) ' Stress_decid = ',prt_params%stress_decid(ipft) write(fates_log(),*) ' fates_phen_drought_threshold = ',prt_params%phen_drought_threshold(ipft) write(fates_log(),*) ' fates_phen_moist_threshold = ',prt_params%phen_moist_threshold (ipft) - write(fates_log(),*) ' Aborting' - call endrun(msg=errMsg(sourcefile, __LINE__)) + write(fates_log(),*) '---~---' + write(fates_log(),*) '' + write(fates_log(),*) '' + nerror = nerror + 1 end if end if @@ -1186,13 +1273,16 @@ subroutine PRTCheckParams(is_master) ! is bounded between 0 and 1 (exactly 0 and 1 are acceptable). if ( ( prt_params%phen_fnrt_drop_fraction(ipft) < 0.0_r8 ) .or. & ( prt_params%phen_fnrt_drop_fraction(ipft) > 1.0_r8 ) ) then + write(fates_log(),*) '---~---' write(fates_log(),*) ' Abscission rate for fine roots must be between 0 and 1 for ' write(fates_log(),*) ' deciduous PFTs.' write(fates_log(),*) ' PFT#: ',ipft write(fates_log(),*) ' evergreen flag: (should be 0):',prt_params%evergreen(ipft) write(fates_log(),*) ' phen_fnrt_drop_fraction: ', prt_params%phen_fnrt_drop_fraction(ipft) - write(fates_log(),*) ' Aborting' - call endrun(msg=errMsg(sourcefile, __LINE__)) + write(fates_log(),*) '---~---' + write(fates_log(),*) '' + write(fates_log(),*) '' + nerror = nerror + 1 end if @@ -1203,21 +1293,27 @@ subroutine PRTCheckParams(is_master) if ( ( prt_params%woody(ipft) == itrue ) .and. & ( ( prt_params%phen_stem_drop_fraction(ipft) < 0.0_r8 ) .or. & ( prt_params%phen_stem_drop_fraction(ipft) > nearzero ) ) ) then + write(fates_log(),*) '---~---' write(fates_log(),*) ' Non-zero stem-drop fractions are not allowed for woody plants' write(fates_log(),*) ' PFT#: ',ipft write(fates_log(),*) ' part_params%woody:',prt_params%woody(ipft) write(fates_log(),*) ' phen_stem_drop_fraction: ', prt_params%phen_stem_drop_fraction(ipft) - write(fates_log(),*) ' Aborting' - call endrun(msg=errMsg(sourcefile, __LINE__)) + write(fates_log(),*) '---~---' + write(fates_log(),*) '' + write(fates_log(),*) '' + nerror = nerror + 1 elseif ( ( prt_params%phen_stem_drop_fraction(ipft) < 0.0_r8 ) .or. & ( prt_params%phen_stem_drop_fraction(ipft) > 1.0_r8 ) ) then + write(fates_log(),*) '---~---' write(fates_log(),*) ' Deciduous non-wood plants must keep 0-100% of their stems' write(fates_log(),*) ' during the deciduous period.' write(fates_log(),*) ' PFT#: ',ipft write(fates_log(),*) ' evergreen flag: (should be 0):',prt_params%evergreen(ipft) write(fates_log(),*) ' phen_stem_drop_fraction: ', prt_params%phen_stem_drop_fraction(ipft) - write(fates_log(),*) ' Aborting' - call endrun(msg=errMsg(sourcefile, __LINE__)) + write(fates_log(),*) '---~---' + write(fates_log(),*) '' + write(fates_log(),*) '' + nerror = nerror + 1 end if end if @@ -1229,14 +1325,16 @@ subroutine PRTCheckParams(is_master) if ( ( prt_params%seed_alloc(ipft) + & prt_params%seed_alloc_mature(ipft)) > 1.0_r8 ) then + write(fates_log(),*) '---~---' write(fates_log(),*) 'The sum of seed allocation from base and mature trees may' write(fates_log(),*) ' not exceed 1.' write(fates_log(),*) ' PFT#: ',ipft write(fates_log(),*) ' seed_alloc: ',prt_params%seed_alloc(ipft) write(fates_log(),*) ' seed_alloc_mature: ',prt_params%seed_alloc_mature(ipft) - write(fates_log(),*) ' Aborting' - call endrun(msg=errMsg(sourcefile, __LINE__)) - + write(fates_log(),*) '---~---' + write(fates_log(),*) '' + write(fates_log(),*) '' + nerror = nerror + 1 end if ! Check if woody plants have a structural biomass (agb) intercept @@ -1244,21 +1342,46 @@ subroutine PRTCheckParams(is_master) if ( ( prt_params%allom_agb1(ipft) <= tiny(prt_params%allom_agb1(ipft)) ) .and. & ( prt_params%woody(ipft) .eq. 1 ) ) then + write(fates_log(),*) '---~---' write(fates_log(),*) 'Woody plants are expected to have a non-zero intercept' write(fates_log(),*) ' in the diameter to AGB allometry equations' write(fates_log(),*) ' PFT#: ',ipft write(fates_log(),*) ' allom_agb1: ',prt_params%allom_agb1(ipft) write(fates_log(),*) ' woody: ',prt_params%woody(ipft) - write(fates_log(),*) ' Aborting' - call endrun(msg=errMsg(sourcefile, __LINE__)) + write(fates_log(),*) '---~---' + write(fates_log(),*) '' + write(fates_log(),*) '' + nerror = nerror + 1 end if + ! Check if parameter 2 for dbh -> height is negative when allom_hmode is 2 + ! (Weibull function / Poorter et al. (2006) + ! ML: FATES definition for parameter 2 is a bit unusual, which is why I added + ! the check. Normally the minus sign is left outside the parameter for + ! Weibull functions. + ! ---------------------------------------------------------------------------------- + if ( ( prt_params%allom_hmode(ipft) == 2 ) .and. & + ( prt_params%allom_d2h2 (ipft) > 0._r8 ) ) then + write(fates_log(),*) "---~---" + write(fates_log(),*) " Incorrect settings for height allometry." + write(fates_log(),*) ' PFT index: ',ipft + write(fates_log(),*) ' allom_hmode: ',prt_params%allom_hmode(ipft) + write(fates_log(),*) ' allom_d2h2: ',prt_params%allom_d2h2 (ipft) + write(fates_log(),*) " Parameter ""allom_d2h2"" must be negative when using" + write(fates_log(),*) " allom_hmode = 2." + write(fates_log(),*) "---~---" + write(fates_log(),*) '' + write(fates_log(),*) '' + nerror = nerror + 1 + end if + ! Check if non-woody plants have structural biomass (agb) intercept ! ---------------------------------------------------------------------------------- ! if ( ( prt_params%allom_agb1(ipft) > tiny(prt_params%allom_agb1(ipft)) ) .and. & ! ( iprt_params%woody(ipft) .ne. 1 ) ) then ! +! write(fates_log(),*) "---~---" ! write(fates_log(),*) 'Non-woody plants are expected to have a zero intercept' ! write(fates_log(),*) ' in the diameter to AGB allometry equations' ! write(fates_log(),*) ' This is because the definition of AGB (as far as allometry)' @@ -1267,8 +1390,10 @@ subroutine PRTCheckParams(is_master) ! write(fates_log(),*) ' PFT#: ',ipft ! write(fates_log(),*) ' allom_agb1: ',prt_params%allom_agb1(ipft) ! write(fates_log(),*) ' woody: ',prt_params%woody(ipft) -! write(fates_log(),*) ' Aborting' -! call endrun(msg=errMsg(sourcefile, __LINE__)) +! write(fates_log(),*) "---~---" +! write(fates_log(),*) '' +! write(fates_log(),*) '' +! nerror = nerror + 1 ! ! end if @@ -1278,13 +1403,16 @@ subroutine PRTCheckParams(is_master) if ( ( prt_params%leaf_stor_priority(ipft) < 0.0_r8 ) .or. & ( prt_params%leaf_stor_priority(ipft) > 1.0_r8 ) ) then + write(fates_log(),*) "---~---" write(fates_log(),*) 'Prioritization of carbon allocation to leaf' write(fates_log(),*) ' and root turnover replacement, must be between' write(fates_log(),*) ' 0 and 1' write(fates_log(),*) ' PFT#: ',ipft write(fates_log(),*) 'leaf_stor_priority: ',prt_params%leaf_stor_priority(ipft) - write(fates_log(),*) ' Aborting' - call endrun(msg=errMsg(sourcefile, __LINE__)) + write(fates_log(),*) "---~---" + write(fates_log(),*) '' + write(fates_log(),*) '' + nerror = nerror + 1 end if @@ -1293,18 +1421,26 @@ subroutine PRTCheckParams(is_master) ! Make sure nutrient storage fractions are positive if( prt_params%nitr_store_ratio(ipft) < 0._r8 ) then + write(fates_log(),*) "---~---" write(fates_log(),*) 'With parteh allometric CNP hypothesis' write(fates_log(),*) 'nitr_store_ratio must be > 0' write(fates_log(),*) 'PFT#: ',ipft write(fates_log(),*) 'nitr_store_ratio = ',prt_params%nitr_store_ratio(ipft) - call endrun(msg=errMsg(sourcefile, __LINE__)) + write(fates_log(),*) "---~---" + write(fates_log(),*) '' + write(fates_log(),*) '' + nerror = nerror + 1 end if if( prt_params%phos_store_ratio(ipft) < 0._r8 ) then + write(fates_log(),*) "---~---" write(fates_log(),*) 'With parteh allometric CNP hypothesis' write(fates_log(),*) 'phos_store_ratio must be > 0' write(fates_log(),*) 'PFT#: ',ipft write(fates_log(),*) 'nitr_store_ratio = ',prt_params%phos_store_ratio(ipft) - call endrun(msg=errMsg(sourcefile, __LINE__)) + write(fates_log(),*) "---~---" + write(fates_log(),*) '' + write(fates_log(),*) '' + nerror = nerror + 1 end if do i = 1,norgans @@ -1312,33 +1448,45 @@ subroutine PRTCheckParams(is_master) if(io == sapw_organ) then if ((prt_params%turnover_nitr_retrans(ipft,i) > nearzero)) then + write(fates_log(),*) "---~---" write(fates_log(),*) ' Retranslocation of sapwood tissues should be zero.' write(fates_log(),*) ' PFT#: ',ipft write(fates_log(),*) ' nitrogen retrans: ',prt_params%turnover_nitr_retrans(ipft,i) - write(fates_log(),*) ' Aborting' - call endrun(msg=errMsg(sourcefile, __LINE__)) + write(fates_log(),*) "---~---" + write(fates_log(),*) '' + write(fates_log(),*) '' + nerror = nerror + 1 end if if ((prt_params%turnover_phos_retrans(ipft,i) > nearzero)) then + write(fates_log(),*) "---~---" write(fates_log(),*) ' Retranslocation of sapwood tissues should be zero.' write(fates_log(),*) ' PFT#: ',ipft write(fates_log(),*) ' phosphorus retrans: ',prt_params%turnover_nitr_retrans(ipft,i) - write(fates_log(),*) ' Aborting' - call endrun(msg=errMsg(sourcefile, __LINE__)) + write(fates_log(),*) "---~---" + write(fates_log(),*) '' + write(fates_log(),*) '' + nerror = nerror + 1 end if elseif(io == struct_organ) then if ((prt_params%turnover_nitr_retrans(ipft,i) > nearzero)) then + write(fates_log(),*) "---~---" write(fates_log(),*) ' Retranslocation of structural tissues should be zero.' write(fates_log(),*) ' PFT#: ',ipft write(fates_log(),*) ' carbon retrans: ',prt_params%turnover_nitr_retrans(ipft,i) - write(fates_log(),*) ' Aborting' - call endrun(msg=errMsg(sourcefile, __LINE__)) + write(fates_log(),*) "---~---" + write(fates_log(),*) '' + write(fates_log(),*) '' + nerror = nerror + 1 end if if ((prt_params%turnover_phos_retrans(ipft,i) > nearzero)) then + write(fates_log(),*) "---~---" write(fates_log(),*) ' Retranslocation of structural tissues should be zero.' write(fates_log(),*) ' PFT#: ',ipft write(fates_log(),*) ' phosphorus retrans: ',prt_params%turnover_nitr_retrans(ipft,i) - write(fates_log(),*) ' Aborting' - call endrun(msg=errMsg(sourcefile, __LINE__)) + write(fates_log(),*) "---~---" + write(fates_log(),*) '' + write(fates_log(),*) '' + nerror = nerror + 1 end if end if @@ -1347,13 +1495,16 @@ subroutine PRTCheckParams(is_master) (prt_params%turnover_phos_retrans(ipft,i) > 1.0_r8) .or. & (prt_params%turnover_nitr_retrans(ipft,i) < 0.0_r8) .or. & (prt_params%turnover_phos_retrans(ipft,i) < 0.0_r8)) then + write(fates_log(),*) "---~---" write(fates_log(),*) ' Retranslocation should range from 0 to 1.' write(fates_log(),*) ' PFT#: ',ipft write(fates_log(),*) ' parameter file organ index: ',i,' global index: ',io write(fates_log(),*) ' nitr: ',prt_params%turnover_nitr_retrans(ipft,i) write(fates_log(),*) ' phos: ',prt_params%turnover_phos_retrans(ipft,i) - write(fates_log(),*) ' Aborting' - call endrun(msg=errMsg(sourcefile, __LINE__)) + write(fates_log(),*) "---~---" + write(fates_log(),*) '' + write(fates_log(),*) '' + nerror = nerror + 1 end if end do @@ -1365,18 +1516,24 @@ subroutine PRTCheckParams(is_master) ! if (parteh_mode .eq. prt_carbon_allom_hyp) then if ( ( prt_params%grperc(ipft) < 0.0_r8) .or. & ( prt_params%grperc(ipft) > 1.0_r8 ) ) then + write(fates_log(),*) "---~---" write(fates_log(),*) ' PFT#: ',ipft write(fates_log(),*) ' Growth respiration must be between 0 and 1: ',prt_params%grperc(ipft) - write(fates_log(),*) ' Aborting' - call endrun(msg=errMsg(sourcefile, __LINE__)) + write(fates_log(),*) "---~---" + write(fates_log(),*) '' + write(fates_log(),*) '' + nerror = nerror + 1 end if ! elseif(parteh_mode .eq. prt_cnp_flex_allom_hyp) then ! if ( ( any(prt_params%grperc_organ(ipft,:) < 0.0_r8)) .or. & ! ( any(prt_params%grperc_organ(ipft,:) >= 1.0_r8)) ) then +! write(fates_log(),*) "---~---" ! write(fates_log(),*) ' PFT#: ',ipft ! write(fates_log(),*) ' Growth respiration must be between 0 and 1: ',prt_params%grperc_organ(ipft,:) -! write(fates_log(),*) ' Aborting' -! call endrun(msg=errMsg(sourcefile, __LINE__)) +! write(fates_log(),*) "---~---" +! write(fates_log(),*) '' +! write(fates_log(),*) '' +! nerror = nerror + 1 ! end if ! end if @@ -1385,11 +1542,14 @@ subroutine PRTCheckParams(is_master) ! The first nitrogen stoichiometry is used in all cases if ( (any(prt_params%nitr_stoich_p1(ipft,:) < 0.0_r8)) .or. & (any(prt_params%nitr_stoich_p1(ipft,:) >= 1.0_r8))) then + write(fates_log(),*) "---~---" write(fates_log(),*) ' PFT#: ',ipft write(fates_log(),*) ' N per C stoichiometry must bet between 0-1' write(fates_log(),*) prt_params%nitr_stoich_p1(ipft,:) - write(fates_log(),*) ' Aborting' - call endrun(msg=errMsg(sourcefile, __LINE__)) + write(fates_log(),*) "---~---" + write(fates_log(),*) '' + write(fates_log(),*) '' + nerror = nerror + 1 end if end select @@ -1401,6 +1561,7 @@ subroutine PRTCheckParams(is_master) (prt_params%phos_stoich_p1(ipft,i) < 0._r8) .or. & (prt_params%nitr_stoich_p1(ipft,i) > 1._r8) .or. & (prt_params%phos_stoich_p1(ipft,i) > 1._r8) ) then + write(fates_log(),*) "---~---" write(fates_log(),*) 'When the C,N,P allocation hypothesis with flexible' write(fates_log(),*) 'stoichiometry is turned on (prt_cnp_flex_allom_hyp),' write(fates_log(),*) 'all stoichiometries must be greater than or equal to zero,' @@ -1410,18 +1571,23 @@ subroutine PRTCheckParams(is_master) write(fates_log(),*) 'organ index (see head of PRTGenericMod): ',io write(fates_log(),*) 'nitr_stoich: ',prt_params%nitr_stoich_p1(ipft,i) write(fates_log(),*) 'phos_stoich: ',prt_params%phos_stoich_p1(ipft,i) - write(fates_log(),*) 'Aborting' - call endrun(msg=errMsg(sourcefile, __LINE__)) + write(fates_log(),*) "---~---" + write(fates_log(),*) '' + write(fates_log(),*) '' + nerror = nerror + 1 end if end do if ( any(prt_params%alloc_priority(ipft,:) < 0) .or. & any(prt_params%alloc_priority(ipft,:) > 6) ) then + write(fates_log(),*) "---~---" write(fates_log(),*) ' PFT#: ',ipft write(fates_log(),*) ' Allocation priorities should be 0-6 for CNP flex hypothesis' write(fates_log(),*) prt_params%alloc_priority(ipft,:) - write(fates_log(),*) ' Aborting' - call endrun(msg=errMsg(sourcefile, __LINE__)) + write(fates_log(),*) "---~---" + write(fates_log(),*) '' + write(fates_log(),*) '' + nerror = nerror + 1 end if end select @@ -1437,35 +1603,45 @@ subroutine PRTCheckParams(is_master) ! Check that leaf turnover doesn't exeed 1 day if ( (years_per_day / prt_params%leaf_long(ipft,iage)) > 1._r8 ) then + write(fates_log(),*) "---~---" write(fates_log(),*) 'Leaf turnover time-scale is greater than 1 day!' write(fates_log(),*) 'ipft: ',ipft,' iage: ',iage write(fates_log(),*) 'leaf_long(ipft,iage): ',prt_params%leaf_long(ipft,iage),' [years]' - write(fates_log(),*) 'Aborting' - call endrun(msg=errMsg(sourcefile, __LINE__)) + write(fates_log(),*) "---~---" + write(fates_log(),*) '' + write(fates_log(),*) '' + nerror = nerror + 1 end if ! Check to make sure that all other age-classes for this PFT also ! have non-zero entries, it wouldn't make sense otherwise if ( any(prt_params%leaf_long(ipft,:) <= nearzero) ) then + write(fates_log(),*) "---~---" write(fates_log(),*) 'You specified a leaf_long that is zero or' write(fates_log(),*) 'invalid for a particular age class.' write(fates_log(),*) 'Yet, other age classes for this PFT are non-zero.' write(fates_log(),*) 'this doesnt make sense.' write(fates_log(),*) 'ipft = ',ipft write(fates_log(),*) 'leaf_long(ipft,:) = ',prt_params%leaf_long(ipft,:) - write(fates_log(),*) 'Aborting' - call endrun(msg=errMsg(sourcefile, __LINE__)) + write(fates_log(),*) "---~---" + write(fates_log(),*) '' + write(fates_log(),*) '' + nerror = nerror + 1 end if else if (prt_params%evergreen(ipft) .eq. itrue) then + write(fates_log(),*) "---~---" write(fates_log(),*) 'You specified zero leaf turnover: ' write(fates_log(),*) 'ipft: ',ipft,' iage: ',iage write(fates_log(),*) 'leaf_long(ipft,iage): ',prt_params%leaf_long(ipft,iage) write(fates_log(),*) 'yet this is an evergreen PFT, and it only makes sense' write(fates_log(),*) 'that an evergreen would have leaf maintenance turnover' write(fates_log(),*) 'disable this error if you are ok with this' - call endrun(msg=errMsg(sourcefile, __LINE__)) + write(fates_log(),*) "---~---" + write(fates_log(),*) '' + write(fates_log(),*) '' + nerror = nerror + 1 end if end if @@ -1478,23 +1654,30 @@ subroutine PRTCheckParams(is_master) if ( (years_per_day / & (prt_params%leaf_long(ipft,nleafage) * & prt_params%senleaf_long_fdrought(ipft))) > 1._r8 ) then + write(fates_log(),*) "---~---" write(fates_log(),*) 'Drought-senescent turnover time-scale is greater than 1 day!' write(fates_log(),*) 'ipft: ',ipft write(fates_log(),*) 'leaf_long(ipft,nleafage)*senleaf_long_fdrought: ', & prt_params%leaf_long(ipft,nleafage)*prt_params%senleaf_long_fdrought(ipft),' [years]' - write(fates_log(),*) 'Aborting' - call endrun(msg=errMsg(sourcefile, __LINE__)) + write(fates_log(),*) "---~---" + write(fates_log(),*) '' + write(fates_log(),*) '' + nerror = nerror + 1 end if end if if ( prt_params%senleaf_long_fdrought(ipft)1._r8 ) then + write(fates_log(),*) "---~---" write(fates_log(),*) 'senleaf_long_fdrought(ipft) must be greater than 0 ' write(fates_log(),*) 'or less than or equal to 1.' write(fates_log(),*) 'Set this to 1 if you want no accelerated senescence turnover' write(fates_log(),*) 'ipft = ',ipft write(fates_log(),*) 'senleaf_long_fdrought(ipft) = ',prt_params%senleaf_long_fdrought(ipft) - call endrun(msg=errMsg(sourcefile, __LINE__)) + write(fates_log(),*) "---~---" + write(fates_log(),*) '' + write(fates_log(),*) '' + nerror = nerror + 1 end if @@ -1502,22 +1685,29 @@ subroutine PRTCheckParams(is_master) ! Check that root turnover doesn't exeed 1 day if ( (years_per_day / prt_params%root_long(ipft)) > 1._r8 ) then + write(fates_log(),*) "---~---" write(fates_log(),*) 'Root turnover time-scale is greater than 1 day!' write(fates_log(),*) 'ipft: ',ipft write(fates_log(),*) 'root_long(ipft): ',prt_params%root_long(ipft),' [years]' - write(fates_log(),*) 'Aborting' - call endrun(msg=errMsg(sourcefile, __LINE__)) + write(fates_log(),*) "---~---" + write(fates_log(),*) '' + write(fates_log(),*) '' + nerror = nerror + 1 end if else if (prt_params%evergreen(ipft) .eq. itrue) then + write(fates_log(),*) "---~---" write(fates_log(),*) 'You specified zero root turnover: ' write(fates_log(),*) 'ipft: ',ipft write(fates_log(),*) 'root_long(ipft): ',prt_params%root_long(ipft) write(fates_log(),*) 'yet this is an evergreen PFT, and it only makes sense' write(fates_log(),*) 'that an evergreen would have root maintenance turnover' write(fates_log(),*) 'disable this error if you are ok with this' - call endrun(msg=errMsg(sourcefile, __LINE__)) + write(fates_log(),*) "---~---" + write(fates_log(),*) '' + write(fates_log(),*) '' + nerror = nerror + 1 end if end if @@ -1526,11 +1716,14 @@ subroutine PRTCheckParams(is_master) ! Check that branch turnover doesn't exeed 1 day if ( (years_per_day / prt_params%branch_long(ipft)) > 1._r8 ) then + write(fates_log(),*) "---~---" write(fates_log(),*) 'Branch turnover time-scale is greater than 1 day!' write(fates_log(),*) 'ipft: ',ipft write(fates_log(),*) 'branch_long(ipft): ',prt_params%branch_long(ipft),' [years]' - write(fates_log(),*) 'Aborting' - call endrun(msg=errMsg(sourcefile, __LINE__)) + write(fates_log(),*) "---~---" + write(fates_log(),*) '' + write(fates_log(),*) '' + nerror = nerror + 1 end if end if @@ -1538,6 +1731,14 @@ subroutine PRTCheckParams(is_master) end do pftloop + ! If any error was found, abort. We add a single point to abort the run after all + ! checks so users can get all the errors and address them in one go (as opposed to + ! multiple submissions). + if (nerror > 0) then + write(fates_log(),*) 'One or more parameter errors found. Aborting.' + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + return end subroutine PRTCheckParams diff --git a/radiation/CMakeLists.txt b/radiation/CMakeLists.txt new file mode 100644 index 0000000000..74d625b12d --- /dev/null +++ b/radiation/CMakeLists.txt @@ -0,0 +1,7 @@ +# This file is required for unit testing, but is not used for production runs +list(APPEND fates_sources + TwoStreamMLPEMod.F90 + FatesRadiationMemMod.F90 + ) + +sourcelist_to_parent(fates_sources) diff --git a/biogeophys/EDSurfaceAlbedoMod.F90 b/radiation/FatesNormanRadMod.F90 similarity index 72% rename from biogeophys/EDSurfaceAlbedoMod.F90 rename to radiation/FatesNormanRadMod.F90 index 18c7e7866e..24cf38fbb7 100644 --- a/biogeophys/EDSurfaceAlbedoMod.F90 +++ b/radiation/FatesNormanRadMod.F90 @@ -1,4 +1,4 @@ -module EDSurfaceRadiationMod +module FatesNormanRadMod !------------------------------------------------------------------------------------- ! EDSurfaceRadiation @@ -10,30 +10,26 @@ module EDSurfaceRadiationMod #include "shr_assert.h" - use EDTypesMod , only : ed_site_type - use FatesPatchMod, only : fates_patch_type - use EDParamsMod, only : maxpft - use FatesConstantsMod , only : r8 => fates_r8 - use FatesConstantsMod , only : itrue - use FatesConstantsMod , only : pi_const - use FatesConstantsMod , only : nocomp_bareground + use EDTypesMod , only : ed_site_type + use FatesPatchMod , only : fates_patch_type + use EDParamsMod , only : maxpft + use FatesConstantsMod , only : r8 => fates_r8 + use FatesConstantsMod , only : itrue + use FatesConstantsMod , only : pi_const + use FatesConstantsMod , only : nocomp_bareground use FatesInterfaceTypesMod , only : bc_in_type use FatesInterfaceTypesMod , only : bc_out_type - use FatesInterfaceTypesMod , only : hlm_numSWb use FatesInterfaceTypesMod , only : numpft - use EDParamsMod , only : maxSWb - use EDParamsMod , only : nclmax - use EDParamsMod , only : nlevleaf - use EDTypesMod , only : n_rad_stream_types - use EDTypesMod , only : idiffuse - use EDTypesMod , only : idirect - use EDParamsMod , only : ivis - use EDParamsMod , only : inir - use EDParamsMod , only : ipar - use EDCanopyStructureMod, only: calc_areaindex - use FatesGlobals , only : fates_log - use FatesGlobals, only : endrun => fates_endrun - use EDPftvarcon, only : EDPftvarcon_inst + use EDParamsMod , only : nclmax + use EDParamsMod , only : nlevleaf + use FatesRadiationMemMod , only : num_swb + use FatesRadiationMemMod , only : num_rad_stream_types + use FatesRadiationmemMod , only : idirect, idiffuse + use FatesRadiationMemMod , only : ivis, inir, ipar + use EDCanopyStructureMod , only : calc_areaindex + use FatesGlobals , only : fates_log + use FatesGlobals , only : endrun => fates_endrun + use EDPftvarcon , only : EDPftvarcon_inst ! CIME globals use shr_log_mod , only : errMsg => shr_log_errMsg @@ -41,15 +37,13 @@ module EDSurfaceRadiationMod implicit none private - public :: ED_Norman_Radiation ! Surface albedo and two-stream fluxes public :: PatchNormanRadiation - public :: ED_SunShadeFracs logical :: debug = .false. ! for debugging this module character(len=*), parameter, private :: sourcefile = & __FILE__ - ! real(r8), public :: albice(maxSWb) = & ! albedo land ice by waveband (1=vis, 2=nir) + ! real(r8), public :: albice(num_swb) = & ! albedo land ice by waveband (1=vis, 2=nir) ! (/ 0.80_r8, 0.55_r8 /) !parameters of canopy snow reflectance model. @@ -57,124 +51,14 @@ module EDSurfaceRadiationMod ! and so they are stored here for now in common with the ice parameters above. ! in principle these could be moved to the parameter file. - real(r8), public :: albice(maxSWb) = & ! albedo land ice by waveband (1=vis, 2=nir) + real(r8), public :: albice(num_swb) = & ! albedo land ice by waveband (1=vis, 2=nir) (/ 0.80_r8, 0.55_r8 /) - real(r8), public :: rho_snow(maxSWb) = & ! albedo land ice by waveband (1=vis, 2=nir) + real(r8), public :: rho_snow(num_swb) = & ! albedo land ice by waveband (1=vis, 2=nir) (/ 0.80_r8, 0.55_r8 /) - real(r8), public :: tau_snow(maxSWb) = & ! albedo land ice by waveband (1=vis, 2=nir) + real(r8), public :: tau_snow(num_swb) = & ! albedo land ice by waveband (1=vis, 2=nir) (/ 0.01_r8, 0.01_r8 /) contains - subroutine ED_Norman_Radiation (nsites, sites, bc_in, bc_out ) - ! - ! - - ! !ARGUMENTS: - - integer, intent(in) :: nsites - type(ed_site_type), intent(inout), target :: sites(nsites) ! FATES site vector - type(bc_in_type), intent(in) :: bc_in(nsites) - type(bc_out_type), intent(inout) :: bc_out(nsites) - - - ! !LOCAL VARIABLES: - integer :: s ! site loop counter - integer :: ifp ! patch loop counter - integer :: ib ! radiation broad band counter - type(fates_patch_type), pointer :: currentPatch ! patch pointer - - !----------------------------------------------------------------------- - ! ------------------------------------------------------------------------------- - ! TODO (mv, 2014-10-29) the filter here is different than below - ! this is needed to have the VOC's be bfb - this needs to be - ! re-examined int he future - ! RGK,2016-08-06: FATES is still incompatible with VOC emission module - ! ------------------------------------------------------------------------------- - - - do s = 1, nsites - - ifp = 0 - currentpatch => sites(s)%oldest_patch - do while (associated(currentpatch)) - if(currentpatch%nocomp_pft_label.ne.nocomp_bareground)then - ! do not do albedo calculations for bare ground patch in SP mode - ! and (more impotantly) do not iterate ifp or it will mess up the indexing wherein - ! ifp=1 is the first vegetated patch. - ifp = ifp+1 - - currentPatch%f_sun (:,:,:) = 0._r8 - currentPatch%fabd_sun_z (:,:,:) = 0._r8 - currentPatch%fabd_sha_z (:,:,:) = 0._r8 - currentPatch%fabi_sun_z (:,:,:) = 0._r8 - currentPatch%fabi_sha_z (:,:,:) = 0._r8 - currentPatch%fabd (:) = 0._r8 - currentPatch%fabi (:) = 0._r8 - - ! zero diagnostic radiation profiles - currentPatch%nrmlzd_parprof_pft_dir_z(:,:,:,:) = 0._r8 - currentPatch%nrmlzd_parprof_pft_dif_z(:,:,:,:) = 0._r8 - currentPatch%nrmlzd_parprof_dir_z(:,:,:) = 0._r8 - currentPatch%nrmlzd_parprof_dif_z(:,:,:) = 0._r8 - - currentPatch%solar_zenith_flag = bc_in(s)%filter_vegzen_pa(ifp) - currentPatch%solar_zenith_angle = bc_in(s)%coszen_pa(ifp) - currentPatch%gnd_alb_dif(1:hlm_numSWb) = bc_in(s)%albgr_dif_rb(1:hlm_numSWb) - currentPatch%gnd_alb_dir(1:hlm_numSWb) = bc_in(s)%albgr_dir_rb(1:hlm_numSWb) - currentPatch%fcansno = bc_in(s)%fcansno_pa(ifp) - - if(currentPatch%solar_zenith_flag )then - - bc_out(s)%albd_parb(ifp,:) = 0._r8 ! output HLM - bc_out(s)%albi_parb(ifp,:) = 0._r8 ! output HLM - bc_out(s)%fabi_parb(ifp,:) = 0._r8 ! output HLM - bc_out(s)%fabd_parb(ifp,:) = 0._r8 ! output HLM - bc_out(s)%ftdd_parb(ifp,:) = 1._r8 ! output HLM - bc_out(s)%ftid_parb(ifp,:) = 1._r8 ! output HLM - bc_out(s)%ftii_parb(ifp,:) = 1._r8 ! output HLM - - if (maxval(currentPatch%nrad(1,:))==0)then - !there are no leaf layers in this patch. it is effectively bare ground. - ! no radiation is absorbed - bc_out(s)%fabd_parb(ifp,:) = 0.0_r8 - bc_out(s)%fabi_parb(ifp,:) = 0.0_r8 - currentPatch%radiation_error = 0.0_r8 - - do ib = 1,hlm_numSWb - bc_out(s)%albd_parb(ifp,ib) = bc_in(s)%albgr_dir_rb(ib) - bc_out(s)%albi_parb(ifp,ib) = bc_in(s)%albgr_dif_rb(ib) - bc_out(s)%ftdd_parb(ifp,ib)= 1.0_r8 - !bc_out(s)%ftid_parb(ifp,ib)= 1.0_r8 - bc_out(s)%ftid_parb(ifp,ib)= 0.0_r8 - bc_out(s)%ftii_parb(ifp,ib)= 1.0_r8 - enddo - - else - - call PatchNormanRadiation (currentPatch, & - bc_out(s)%albd_parb(ifp,:), & - bc_out(s)%albi_parb(ifp,:), & - bc_out(s)%fabd_parb(ifp,:), & - bc_out(s)%fabi_parb(ifp,:), & - bc_out(s)%ftdd_parb(ifp,:), & - bc_out(s)%ftid_parb(ifp,:), & - bc_out(s)%ftii_parb(ifp,:)) - - - endif ! is there vegetation? - - end if ! if the vegetation and zenith filter is active - endif ! not bare ground - currentPatch => currentPatch%younger - end do ! Loop linked-list patches - enddo ! Loop Sites - - return - end subroutine ED_Norman_Radiation - - - ! ====================================================================================== - subroutine PatchNormanRadiation (currentPatch, & albd_parb_out, & ! (ifp,ib) albi_parb_out, & ! (ifp,ib) @@ -195,13 +79,13 @@ subroutine PatchNormanRadiation (currentPatch, & ! ----------------------------------------------------------------------------------- type(fates_patch_type), intent(inout), target :: currentPatch - real(r8), intent(inout) :: albd_parb_out(hlm_numSWb) - real(r8), intent(inout) :: albi_parb_out(hlm_numSWb) - real(r8), intent(inout) :: fabd_parb_out(hlm_numSWb) - real(r8), intent(inout) :: fabi_parb_out(hlm_numSWb) - real(r8), intent(inout) :: ftdd_parb_out(hlm_numSWb) - real(r8), intent(inout) :: ftid_parb_out(hlm_numSWb) - real(r8), intent(inout) :: ftii_parb_out(hlm_numSWb) + real(r8), intent(inout) :: albd_parb_out(num_swb) + real(r8), intent(inout) :: albi_parb_out(num_swb) + real(r8), intent(inout) :: fabd_parb_out(num_swb) + real(r8), intent(inout) :: fabi_parb_out(num_swb) + real(r8), intent(inout) :: ftdd_parb_out(num_swb) + real(r8), intent(inout) :: ftid_parb_out(num_swb) + real(r8), intent(inout) :: ftii_parb_out(num_swb) ! Locals ! ----------------------------------------------------------------------------------- @@ -218,25 +102,25 @@ subroutine PatchNormanRadiation (currentPatch, & real(r8) :: tr_dif_z(nclmax,maxpft,nlevleaf) ! Exponential transmittance of diffuse radiation through a single layer real(r8) :: weighted_dir_tr(nclmax) real(r8) :: weighted_fsun(nclmax) - real(r8) :: weighted_dif_ratio(nclmax,maxSWb) + real(r8) :: weighted_dif_ratio(nclmax,num_swb) real(r8) :: weighted_dif_down(nclmax) real(r8) :: weighted_dif_up(nclmax) - real(r8) :: refl_dif(nclmax,maxpft,nlevleaf,maxSWb) ! Term for diffuse radiation reflected by laye - real(r8) :: tran_dif(nclmax,maxpft,nlevleaf,maxSWb) ! Term for diffuse radiation transmitted by layer - real(r8) :: dif_ratio(nclmax,maxpft,nlevleaf,maxSWb) ! Ratio of upward to forward diffuse fluxes + real(r8) :: refl_dif(nclmax,maxpft,nlevleaf,num_swb) ! Term for diffuse radiation reflected by laye + real(r8) :: tran_dif(nclmax,maxpft,nlevleaf,num_swb) ! Term for diffuse radiation transmitted by layer + real(r8) :: dif_ratio(nclmax,maxpft,nlevleaf,num_swb) ! Ratio of upward to forward diffuse fluxes real(r8) :: Dif_dn(nclmax,maxpft,nlevleaf) ! Forward diffuse flux onto canopy layer J (W/m**2 ground area) real(r8) :: Dif_up(nclmax,maxpft,nlevleaf) ! Upward diffuse flux above canopy layer J (W/m**2 ground area) real(r8) :: lai_change(nclmax,maxpft,nlevleaf) ! Forward diffuse flux onto canopy layer J (W/m**2 ground area) real(r8) :: frac_lai ! Fraction of lai in each layer real(r8) :: frac_sai ! Fraction of sai in each layer - real(r8) :: f_abs(nclmax,maxpft,nlevleaf,maxSWb) ! Fraction of light absorbed by surfaces. - real(r8) :: rho_layer(nclmax,maxpft,nlevleaf,maxSWb)! Weighted verage reflectance of layer - real(r8) :: tau_layer(nclmax,maxpft,nlevleaf,maxSWb)! Weighted average transmittance of layer - real(r8) :: f_abs_leaf(nclmax,maxpft,nlevleaf,maxSWb) + real(r8) :: f_abs(nclmax,maxpft,nlevleaf,num_swb) ! Fraction of light absorbed by surfaces. + real(r8) :: rho_layer(nclmax,maxpft,nlevleaf,num_swb)! Weighted verage reflectance of layer + real(r8) :: tau_layer(nclmax,maxpft,nlevleaf,num_swb)! Weighted average transmittance of layer + real(r8) :: f_abs_leaf(nclmax,maxpft,nlevleaf,num_swb) real(r8) :: Abs_dir_z(maxpft,nlevleaf) real(r8) :: Abs_dif_z(maxpft,nlevleaf) - real(r8) :: abs_rad(maxSWb) !radiation absorbed by soil + real(r8) :: abs_rad(num_swb) !radiation absorbed by soil real(r8) :: tr_soili ! Radiation transmitted to the soil surface. real(r8) :: tr_soild ! Radiation transmitted to the soil surface. real(r8) :: phi1b(maxpft) ! Radiation transmitted to the soil surface. @@ -259,8 +143,8 @@ subroutine PatchNormanRadiation (currentPatch, & real(r8) :: gdir - real(r8), parameter :: forc_dir(n_rad_stream_types) = (/ 1.0_r8, 0.0_r8 /) ! These are binary switches used - real(r8), parameter :: forc_dif(n_rad_stream_types) = (/ 0.0_r8, 1.0_r8 /) ! to turn off and on radiation streams + real(r8), parameter :: forc_dir(num_rad_stream_types) = (/ 1.0_r8, 0.0_r8 /) ! These are binary switches used + real(r8), parameter :: forc_dif(num_rad_stream_types) = (/ 0.0_r8, 1.0_r8 /) ! to turn off and on radiation streams @@ -292,13 +176,13 @@ subroutine PatchNormanRadiation (currentPatch, & ! Initialize the ouput arrays ! --------------------------------------------------------------------------------- - albd_parb_out(1:hlm_numSWb) = 0.0_r8 - albi_parb_out(1:hlm_numSWb) = 0.0_r8 - fabd_parb_out(1:hlm_numSWb) = 0.0_r8 - fabi_parb_out(1:hlm_numSWb) = 0.0_r8 - ftdd_parb_out(1:hlm_numSWb) = 1.0_r8 - ftid_parb_out(1:hlm_numSWb) = 1.0_r8 - ftii_parb_out(1:hlm_numSWb) = 1.0_r8 + albd_parb_out(1:num_swb) = 0.0_r8 + albi_parb_out(1:num_swb) = 0.0_r8 + fabd_parb_out(1:num_swb) = 0.0_r8 + fabi_parb_out(1:num_swb) = 0.0_r8 + ftdd_parb_out(1:num_swb) = 1.0_r8 + ftid_parb_out(1:num_swb) = 1.0_r8 + ftii_parb_out(1:num_swb) = 1.0_r8 ! Is this pft/canopy layer combination present in this patch? rho_layer(:,:,:,:)=0.0_r8 @@ -322,7 +206,7 @@ subroutine PatchNormanRadiation (currentPatch, & frac_sai = 1.0_r8 - frac_lai ! layer level reflectance qualities - do ib = 1,hlm_numSWb !vis, nir + do ib = 1,num_swb !vis, nir rho_layer(L,ft,iv,ib)=frac_lai*rhol(ft,ib)+frac_sai*rhos(ft,ib) tau_layer(L,ft,iv,ib)=frac_lai*taul(ft,ib)+frac_sai*taus(ft,ib) @@ -364,7 +248,7 @@ subroutine PatchNormanRadiation (currentPatch, & !do this once for one unit of diffuse, and once for one unit of direct radiation - do radtype = 1, n_rad_stream_types + do radtype = 1, num_rad_stream_types ! Extract information that needs to be provided by ED into local array. ! RGK: NOT SURE WHY WE NEED FTWEIGHT ... @@ -393,7 +277,7 @@ subroutine PatchNormanRadiation (currentPatch, & weighted_dir_tr(L) = 0.0_r8 weighted_fsun(L) = 0._r8 - weighted_dif_ratio(L,1:hlm_numSWb) = 0._r8 + weighted_dif_ratio(L,1:num_swb) = 0._r8 !Each canopy layer (canopy, understorey) has multiple 'parallel' pft's @@ -544,7 +428,7 @@ subroutine PatchNormanRadiation (currentPatch, & ! Iterative solution do scattering !==============================================================================! - do ib = 1,hlm_numSWb !vis, nir + do ib = 1,num_swb !vis, nir !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++! ! Leaf scattering coefficient and terms do diffuse radiation reflected ! and transmitted by a layer @@ -584,15 +468,15 @@ subroutine PatchNormanRadiation (currentPatch, & weighted_dif_ratio(L,ib) = weighted_dif_ratio(L,ib) + & dif_ratio(L,ft,1,ib) * ftweight(L,ft,1) !instance where the first layer ftweight is used a proxy for the whole column. FTWA - end do!hlm_numSWb + end do!num_swb endif ! currentPatch%canopy_mask end do!ft end do!L - ! Zero out the radiation error for the current patch before conducting the conservation check - currentPatch%radiation_error = 0.0_r8 + do ib = 1,num_swb - do ib = 1,hlm_numSWb + currentPatch%rad_error(ib) = 0._r8 + Dif_dn(:,:,:) = 0.00_r8 Dif_up(:,:,:) = 0.00_r8 do L = 1, currentPatch%NCL_p !work down from the top of the canopy. @@ -919,15 +803,6 @@ subroutine PatchNormanRadiation (currentPatch, & forc_dir(radtype) * tr_dir_z(L,ft,iv) currentPatch%nrmlzd_parprof_pft_dif_z(radtype,L,ft,iv) = & Dif_dn(L,ft,iv) + Dif_up(L,ft,iv) - ! - currentPatch%nrmlzd_parprof_dir_z(radtype,L,iv) = & - currentPatch%nrmlzd_parprof_dir_z(radtype,L,iv) + & - (forc_dir(radtype) * tr_dir_z(L,ft,iv)) * & - (ftweight(L,ft,iv) / sum(ftweight(L,1:numpft,iv))) - currentPatch%nrmlzd_parprof_dif_z(radtype,L,iv) = & - currentPatch%nrmlzd_parprof_dif_z(radtype,L,iv) + & - (Dif_dn(L,ft,iv) + Dif_up(L,ft,iv)) * & - (ftweight(L,ft,iv) / sum(ftweight(L,1:numpft,iv))) end do end if ! ib = visible end if ! present @@ -1011,8 +886,9 @@ subroutine PatchNormanRadiation (currentPatch, & if ( (currentPatch%total_canopy_area / currentPatch%area) .gt. tolerance ) then ! normalize rad error by the veg-covered fraction of the patch because that is ! the only part that this code applies to - currentPatch%radiation_error = currentPatch%radiation_error + error & + currentPatch%rad_error(ib) = currentPatch%rad_error(ib) + error & * currentPatch%total_canopy_area / currentPatch%area + endif lai_reduction(:) = 0.0_r8 @@ -1094,7 +970,7 @@ subroutine PatchNormanRadiation (currentPatch, & end if end if - end do !hlm_numSWb + end do !num_swb enddo ! rad-type @@ -1103,222 +979,5 @@ subroutine PatchNormanRadiation (currentPatch, & return end subroutine PatchNormanRadiation -! ====================================================================================== - -subroutine ED_SunShadeFracs(nsites, sites,bc_in,bc_out) - - implicit none - - ! Arguments - 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(inout) :: bc_out(nsites) - - - ! locals - type (fates_patch_type),pointer :: cpatch ! c"urrent" patch - real(r8) :: sunlai - real(r8) :: shalai - real(r8) :: elai - integer :: CL - integer :: FT - integer :: iv - integer :: s - integer :: ifp - - - do s = 1,nsites - - ifp = 0 - cpatch => sites(s)%oldest_patch - - do while (associated(cpatch)) - if(cpatch%nocomp_pft_label.ne.nocomp_bareground)then !only for veg patches - ! do not do albedo calculations for bare ground patch in SP mode - ! and (more impotantly) do not iterate ifp or it will mess up the indexing wherein - ! ifp=1 is the first vegetated patch. - ifp=ifp+1 - - if( debug ) write(fates_log(),*) 'edsurfRad_5600',ifp,s,cpatch%NCL_p,numpft - - ! zero out various datas - cpatch%ed_parsun_z(:,:,:) = 0._r8 - cpatch%ed_parsha_z(:,:,:) = 0._r8 - cpatch%ed_laisun_z(:,:,:) = 0._r8 - cpatch%ed_laisha_z(:,:,:) = 0._r8 - - bc_out(s)%fsun_pa(ifp) = 0._r8 - - sunlai = 0._r8 - shalai = 0._r8 - - cpatch%parprof_pft_dir_z(:,:,:) = 0._r8 - cpatch%parprof_pft_dif_z(:,:,:) = 0._r8 - cpatch%parprof_dir_z(:,:) = 0._r8 - cpatch%parprof_dif_z(:,:) = 0._r8 - - ! Loop over patches to calculate laisun_z and laisha_z for each layer. - ! Derive canopy laisun, laisha, and fsun from layer sums. - ! If sun/shade big leaf code, nrad=1 and fsun_z(p,1) and tlai_z(p,1) from - ! SurfaceAlbedo is canopy integrated so that layer value equals canopy value. - - ! cpatch%f_sun is calculated in the surface_albedo routine... - - do CL = 1, cpatch%NCL_p - do FT = 1,numpft - - if( debug ) write(fates_log(),*) 'edsurfRad_5601',CL,FT,cpatch%nrad(CL,ft) - - do iv = 1, cpatch%nrad(CL,ft) !NORMAL CASE. - - ! FIX(SPM,040114) - existing comment - ! ** Should this be elai or tlai? Surely we only do radiation for elai? - - cpatch%ed_laisun_z(CL,ft,iv) = cpatch%elai_profile(CL,ft,iv) * & - cpatch%f_sun(CL,ft,iv) - - if ( debug ) write(fates_log(),*) 'edsurfRad 570 ',cpatch%elai_profile(CL,ft,iv) - if ( debug ) write(fates_log(),*) 'edsurfRad 571 ',cpatch%f_sun(CL,ft,iv) - - cpatch%ed_laisha_z(CL,ft,iv) = cpatch%elai_profile(CL,ft,iv) * & - (1._r8 - cpatch%f_sun(CL,ft,iv)) - - end do - - !needed for the VOC emissions, etc. - sunlai = sunlai + sum(cpatch%ed_laisun_z(CL,ft,1:cpatch%nrad(CL,ft))) - shalai = shalai + sum(cpatch%ed_laisha_z(CL,ft,1:cpatch%nrad(CL,ft))) - - end do - end do - - if(sunlai+shalai > 0._r8)then - bc_out(s)%fsun_pa(ifp) = sunlai / (sunlai+shalai) - else - bc_out(s)%fsun_pa(ifp) = 0._r8 - endif - - if(debug)then - if(bc_out(s)%fsun_pa(ifp) > 1._r8)then - write(fates_log(),*) 'too much leaf area in profile', bc_out(s)%fsun_pa(ifp), & - sunlai,shalai - endif - end if - - elai = calc_areaindex(cpatch,'elai') - - bc_out(s)%laisun_pa(ifp) = elai*bc_out(s)%fsun_pa(ifp) - bc_out(s)%laisha_pa(ifp) = elai*(1.0_r8-bc_out(s)%fsun_pa(ifp)) - - ! Absorbed PAR profile through canopy - ! If sun/shade big leaf code, nrad=1 and fluxes from SurfaceAlbedo - ! are canopy integrated so that layer values equal big leaf values. - - if ( debug ) write(fates_log(),*) 'edsurfRad 645 ',cpatch%NCL_p,numpft - - do CL = 1, cpatch%NCL_p - do FT = 1,numpft - - if ( debug ) write(fates_log(),*) 'edsurfRad 649 ',cpatch%nrad(CL,ft) - - do iv = 1, cpatch%nrad(CL,ft) - - if ( debug ) then - write(fates_log(),*) 'edsurfRad 653 ', cpatch%ed_parsun_z(CL,ft,iv) - write(fates_log(),*) 'edsurfRad 654 ', bc_in(s)%solad_parb(ifp,ipar) - write(fates_log(),*) 'edsurfRad 655 ', bc_in(s)%solai_parb(ifp,ipar) - write(fates_log(),*) 'edsurfRad 656 ', cpatch%fabd_sun_z(CL,ft,iv) - write(fates_log(),*) 'edsurfRad 657 ', cpatch%fabi_sun_z(CL,ft,iv) - endif - - cpatch%ed_parsun_z(CL,ft,iv) = & - bc_in(s)%solad_parb(ifp,ipar)*cpatch%fabd_sun_z(CL,ft,iv) + & - bc_in(s)%solai_parb(ifp,ipar)*cpatch%fabi_sun_z(CL,ft,iv) - - if ( debug )write(fates_log(),*) 'edsurfRad 663 ', cpatch%ed_parsun_z(CL,ft,iv) - - cpatch%ed_parsha_z(CL,ft,iv) = & - bc_in(s)%solad_parb(ifp,ipar)*cpatch%fabd_sha_z(CL,ft,iv) + & - bc_in(s)%solai_parb(ifp,ipar)*cpatch%fabi_sha_z(CL,ft,iv) - - if ( debug ) write(fates_log(),*) 'edsurfRad 669 ', cpatch%ed_parsha_z(CL,ft,iv) - - end do !iv - end do !FT - end do !CL - - ! Convert normalized radiation error units from fraction of radiation to W/m2 - cpatch%radiation_error = cpatch%radiation_error * (bc_in(s)%solad_parb(ifp,ipar) + & - bc_in(s)%solai_parb(ifp,ipar)) - - ! output the actual PAR profiles through the canopy for diagnostic purposes - do CL = 1, cpatch%NCL_p - do FT = 1,numpft - do iv = 1, cpatch%nrad(CL,ft) - cpatch%parprof_pft_dir_z(CL,FT,iv) = (bc_in(s)%solad_parb(ifp,ipar) * & - cpatch%nrmlzd_parprof_pft_dir_z(idirect,CL,FT,iv)) + & - (bc_in(s)%solai_parb(ifp,ipar) * & - cpatch%nrmlzd_parprof_pft_dir_z(idiffuse,CL,FT,iv)) - cpatch%parprof_pft_dif_z(CL,FT,iv) = (bc_in(s)%solad_parb(ifp,ipar) * & - cpatch%nrmlzd_parprof_pft_dif_z(idirect,CL,FT,iv)) + & - (bc_in(s)%solai_parb(ifp,ipar) * & - cpatch%nrmlzd_parprof_pft_dif_z(idiffuse,CL,FT,iv)) - end do ! iv - end do ! FT - end do ! CL - - do CL = 1, cpatch%NCL_p - do iv = 1, maxval(cpatch%nrad(CL,:)) - cpatch%parprof_dir_z(CL,iv) = (bc_in(s)%solad_parb(ifp,ipar) * & - cpatch%nrmlzd_parprof_dir_z(idirect,CL,iv)) + & - (bc_in(s)%solai_parb(ifp,ipar) * & - cpatch%nrmlzd_parprof_dir_z(idiffuse,CL,iv)) - cpatch%parprof_dif_z(CL,iv) = (bc_in(s)%solad_parb(ifp,ipar) * & - cpatch%nrmlzd_parprof_dif_z(idirect,CL,iv)) + & - (bc_in(s)%solai_parb(ifp,ipar) * & - cpatch%nrmlzd_parprof_dif_z(idiffuse,CL,iv)) - end do ! iv - end do ! CL - endif ! not bareground patch - cpatch => cpatch%younger - enddo - - - enddo - return - -end subroutine ED_SunShadeFracs - - -! ! MOVE TO THE INTERFACE -! subroutine ED_CheckSolarBalance(g,filter_nourbanp,num_nourbanp,fsa,fsr,forc_solad,forc_solai) - - -! implicit none -! integer,intent(in),dimension(:) :: gridcell ! => gridcell index -! integer,intent(in),dimension(:) :: filter_nourbanp ! => patch filter for non-urban points -! integer, intent(in) :: num_nourbanp ! number of patches in non-urban points in patch filter -! real(r8),intent(in),dimension(:,:) :: forc_solad ! => atm2lnd_inst%forc_solad_grc, direct radiation (W/m**2 -! real(r8),intent(in),dimension(:,:) :: forc_solai ! => atm2lnd_inst%forc_solai_grc, diffuse radiation (W/m**2) -! real(r8),intent(in),dimension(:,:) :: fsa ! => solarabs_inst%fsa_patch, solar radiation absorbed (total) (W/m**2) -! real(r8),intent(in),dimension(:,:) :: fsr ! => solarabs_inst%fsr_patch, solar radiation reflected (W/m**2) - -! integer :: p -! integer :: fp -! integer :: g -! real(r8) :: errsol - -! do fp = 1,num_nourbanp -! p = filter_nourbanp(fp) -! g = gridcell(p) -! errsol = (fsa(p) + fsr(p) - (forc_solad(g,1) + forc_solad(g,2) + forc_solai(g,1) + forc_solai(g,2))) -! if(abs(errsol) > 0.1_r8)then -! write(fates_log(),*) 'sol error in surf rad',p,g, errsol -! endif -! end do -! return -! end subroutine ED_CheckSolarBalance - -end module EDSurfaceRadiationMod +end module FatesNormanRadMod diff --git a/radiation/FatesRadiationDriveMod.F90 b/radiation/FatesRadiationDriveMod.F90 new file mode 100644 index 0000000000..cb642c1289 --- /dev/null +++ b/radiation/FatesRadiationDriveMod.F90 @@ -0,0 +1,504 @@ +module FatesRadiationDriveMod + + !------------------------------------------------------------------------------------- + ! EDSurfaceRadiation + ! + ! This module contains function and type definitions for all things related + ! to radiative transfer in ED modules at the land surface. + ! + !------------------------------------------------------------------------------------- + +#include "shr_assert.h" + + use EDTypesMod , only : ed_site_type + use FatesPatchMod, only : fates_patch_type + use EDParamsMod, only : maxpft + use FatesConstantsMod , only : r8 => fates_r8 + use FatesConstantsMod , only : fates_unset_r8 + use FatesConstantsMod , only : itrue + use FatesConstantsMod , only : pi_const + use FatesConstantsMod , only : nocomp_bareground + use FatesConstantsMod , only : nearzero + use FatesInterfaceTypesMod , only : bc_in_type + use FatesInterfaceTypesMod , only : bc_out_type + use FatesInterfaceTypesMod , only : numpft + use FatesRadiationMemMod, only : num_rad_stream_types + use FatesRadiationMemMod, only : idirect, idiffuse + use FatesRadiationMemMod, only : num_swb, ivis, inir, ipar + use FatesRadiationMemMod, only : alb_ice, rho_snow, tau_snow + use FatesRadiationMemMod, only : norman_solver + use FatesRadiationMemMod, only : twostr_solver + use EDParamsMod, only : radiation_model + use TwoStreamMLPEMod, only : normalized_upper_boundary + use FatesTwoStreamUtilsMod, only : FatesPatchFSun + use FatesTwoStreamUtilsMod, only : CheckPatchRadiationBalance + use FatesInterfaceTypesMod , only : hlm_hio_ignore_val + use EDParamsMod , only : dinc_vai,dlower_vai + use EDParamsMod , only : nclmax + use EDParamsMod , only : nlevleaf + use EDCanopyStructureMod, only: calc_areaindex + use FatesGlobals , only : fates_log + use FatesGlobals, only : endrun => fates_endrun + use EDPftvarcon, only : EDPftvarcon_inst + use FatesNormanRadMod, only : PatchNormanRadiation + + ! CIME globals + use shr_log_mod , only : errMsg => shr_log_errMsg + + implicit none + + private + public :: FatesNormalizedCanopyRadiation ! Surface albedo and two-stream fluxes + public :: FatesSunShadeFracs + + logical :: debug = .false. ! for debugging this module + character(len=*), parameter, private :: sourcefile = & + __FILE__ + + logical :: preserve_b4b = .true. + +contains + + subroutine FatesNormalizedCanopyRadiation(nsites, sites, bc_in, bc_out ) + + ! Perform normalized (ie per unit downwelling radiative forcing) radiation + ! scattering of the vegetation canopy. + ! This call is normalized because the host wants an albedo for the next time + ! step, but it does not have the absolute beam and diffuse forcing for the + ! next step yet. + ! However, with both Norman and Two stream, we save normalized scattering + ! and absorption profiles amonst the vegetation, and that can + ! be scaled by the forcing when we perform diagnostics, calculate heating + ! rates (HLM side), and calculate absorbed leaf PAR for photosynthesis. + + ! + + ! !ARGUMENTS: + + integer, intent(in) :: nsites + type(ed_site_type), intent(inout), target :: sites(nsites) ! FATES site vector + type(bc_in_type), intent(in) :: bc_in(nsites) + type(bc_out_type), intent(inout) :: bc_out(nsites) + + ! !LOCAL VARIABLES: + integer :: s ! site loop counter + integer :: ifp ! patch loop counter + integer :: ib ! radiation broad band counter + type(fates_patch_type), pointer :: currentPatch ! patch pointer + + !----------------------------------------------------------------------- + ! ------------------------------------------------------------------------------- + ! TODO (mv, 2014-10-29) the filter here is different than below + ! this is needed to have the VOC's be bfb - this needs to be + ! re-examined int he future + ! RGK,2016-08-06: FATES is still incompatible with VOC emission module + ! ------------------------------------------------------------------------------- + + + do s = 1, nsites + + ifp = 0 + currentpatch => sites(s)%oldest_patch + do while (associated(currentpatch)) + + ! do not do albedo calculations for bare ground patch in SP mode + ! and (more impotantly) do not iterate ifp or it will mess up the indexing wherein + ! ifp=1 is the first vegetated patch. + + if_notbareground: if(currentpatch%nocomp_pft_label.ne.nocomp_bareground)then + + ifp = ifp+1 + + ! Zero diagnostics + currentPatch%f_sun (:,:,:) = 0._r8 + currentPatch%fabd_sun_z (:,:,:) = 0._r8 + currentPatch%fabd_sha_z (:,:,:) = 0._r8 + currentPatch%fabi_sun_z (:,:,:) = 0._r8 + currentPatch%fabi_sha_z (:,:,:) = 0._r8 + currentPatch%fabd (:) = 0._r8 + currentPatch%fabi (:) = 0._r8 + currentPatch%nrmlzd_parprof_pft_dir_z(:,:,:,:) = 0._r8 + currentPatch%nrmlzd_parprof_pft_dif_z(:,:,:,:) = 0._r8 + + currentPatch%rad_error(:) = hlm_hio_ignore_val + + currentPatch%solar_zenith_flag = bc_in(s)%filter_vegzen_pa(ifp) + currentPatch%solar_zenith_angle = bc_in(s)%coszen_pa(ifp) + currentPatch%gnd_alb_dif(1:num_swb) = bc_in(s)%albgr_dif_rb(1:num_swb) + currentPatch%gnd_alb_dir(1:num_swb) = bc_in(s)%albgr_dir_rb(1:num_swb) + currentPatch%fcansno = bc_in(s)%fcansno_pa(ifp) + + if(radiation_model.eq.twostr_solver) then + call currentPatch%twostr%CanopyPrep(bc_in(s)%fcansno_pa(ifp)) + call currentPatch%twostr%ZenithPrep(bc_in(s)%coszen_pa(ifp)) + end if + + if_zenith_flag: if(.not.currentPatch%solar_zenith_flag )then + + ! Sun below horizon, trivial solution + ! Note (RGK-MLO): Investigate twilight mechanics for + ! non-zero diffuse radiation when cosz<=0 + + ! Temporarily turn off to preserve b4b + ! preserve_b4b will be removed soon. This is kept here to prevent + ! round off errors in the baseline tests for the two-stream code (RGK 12-27-23) + if (.not.preserve_b4b) then + bc_out(s)%albd_parb(ifp,:) = 1._r8 + bc_out(s)%albi_parb(ifp,:) = 1._r8 + bc_out(s)%fabi_parb(ifp,:) = 0._r8 + bc_out(s)%fabd_parb(ifp,:) = 0._r8 + bc_out(s)%ftdd_parb(ifp,:) = 0._r8 + bc_out(s)%ftid_parb(ifp,:) = 0._r8 + bc_out(s)%ftii_parb(ifp,:) = 0._r8 + end if + else + + bc_out(s)%albd_parb(ifp,:) = 0._r8 ! output HLM + bc_out(s)%albi_parb(ifp,:) = 0._r8 ! output HLM + bc_out(s)%fabi_parb(ifp,:) = 0._r8 ! output HLM + bc_out(s)%fabd_parb(ifp,:) = 0._r8 ! output HLM + bc_out(s)%ftdd_parb(ifp,:) = 1._r8 ! output HLM + bc_out(s)%ftid_parb(ifp,:) = 1._r8 ! output HLM + bc_out(s)%ftii_parb(ifp,:) = 1._r8 ! output HLM + + if_nrad: if (maxval(currentPatch%nrad(1,:))==0)then + ! there are no leaf layers in this patch. it is effectively bare ground. + bc_out(s)%fabd_parb(ifp,:) = 0.0_r8 + bc_out(s)%fabi_parb(ifp,:) = 0.0_r8 + currentPatch%rad_error(:) = 0.0_r8 + + do ib = 1,num_swb + bc_out(s)%albd_parb(ifp,ib) = bc_in(s)%albgr_dir_rb(ib) + bc_out(s)%albi_parb(ifp,ib) = bc_in(s)%albgr_dif_rb(ib) + bc_out(s)%ftdd_parb(ifp,ib) = 1.0_r8 + bc_out(s)%ftid_parb(ifp,ib) = 0.0_r8 + bc_out(s)%ftii_parb(ifp,ib) = 1.0_r8 + enddo + + else + + select case(radiation_model) + case(norman_solver) + + call PatchNormanRadiation (currentPatch, & + bc_out(s)%albd_parb(ifp,:), & ! Surface Albedo direct + bc_out(s)%albi_parb(ifp,:), & ! Surface Albedo (indirect) diffuse + bc_out(s)%fabd_parb(ifp,:), & ! Fraction direct absorbed by canopy per unit incident + bc_out(s)%fabi_parb(ifp,:), & ! Fraction diffuse absorbed by canopy per unit incident + bc_out(s)%ftdd_parb(ifp,:), & ! Down direct flux below canopy per unit direct at top + bc_out(s)%ftid_parb(ifp,:), & ! Down diffuse flux below canopy per unit direct at top + bc_out(s)%ftii_parb(ifp,:)) ! Down diffuse flux below canopy per unit diffuse at top + + case(twostr_solver) + + associate( twostr => currentPatch%twostr) + + !call twostr%CanopyPrep(bc_in(s)%fcansno_pa(ifp)) + !call twostr%ZenithPrep(bc_in(s)%coszen_pa(ifp)) + + do ib = 1,num_swb + + twostr%band(ib)%albedo_grnd_diff = bc_in(s)%albgr_dif_rb(ib) + twostr%band(ib)%albedo_grnd_beam = bc_in(s)%albgr_dir_rb(ib) + + call twostr%Solve(ib, & ! in + normalized_upper_boundary, & ! in + 1.0_r8,1.0_r8, & ! in + sites(s)%taulambda_2str, & ! inout (scratch) + sites(s)%omega_2str, & ! inout (scratch) + sites(s)%ipiv_2str, & ! inout (scratch) + bc_out(s)%albd_parb(ifp,ib), & ! out + bc_out(s)%albi_parb(ifp,ib), & ! out + currentPatch%rad_error(ib), & ! out + bc_out(s)%fabd_parb(ifp,ib), & ! out + bc_out(s)%fabi_parb(ifp,ib), & ! out + bc_out(s)%ftdd_parb(ifp,ib), & ! out + bc_out(s)%ftid_parb(ifp,ib), & ! out + bc_out(s)%ftii_parb(ifp,ib)) + + if(debug) then + currentPatch%twostr%band(ib)%Rbeam_atm = 1._r8 + currentPatch%twostr%band(ib)%Rdiff_atm = 1._r8 + call CheckPatchRadiationBalance(currentPatch, sites(s)%snow_depth, & + ib, bc_out(s)%fabd_parb(ifp,ib),bc_out(s)%fabi_parb(ifp,ib)) + currentPatch%twostr%band(ib)%Rbeam_atm = fates_unset_r8 + currentPatch%twostr%band(ib)%Rdiff_atm = fates_unset_r8 + + if(bc_out(s)%fabi_parb(ifp,ib)>1.0 .or. bc_out(s)%fabd_parb(ifp,ib)>1.0)then + write(fates_log(),*) 'absorbed fraction > 1.0?' + write(fates_log(),*) ifp,ib,bc_out(s)%fabi_parb(ifp,ib),bc_out(s)%fabd_parb(ifp,ib) + call twostr%Dump(ib,lat=sites(s)%lat,lon=sites(s)%lon) + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + end if + + end do + end associate + + end select + + end if if_nrad + + endif if_zenith_flag + end if if_notbareground + + currentPatch => currentPatch%younger + end do ! Loop linked-list patches + enddo ! Loop Sites + + return + end subroutine FatesNormalizedCanopyRadiation + + ! ====================================================================================== + + subroutine FatesSunShadeFracs(nsites, sites,bc_in,bc_out) + + implicit none + + ! Arguments + 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(inout) :: bc_out(nsites) + + ! locals + type (fates_patch_type),pointer :: cpatch ! c"urrent" patch + real(r8) :: sunlai + real(r8) :: shalai + real(r8) :: elai + integer :: cl,ft + integer :: iv,ib + integer :: s + integer :: ifp + integer :: nv + integer :: icol + ! Fraction of the canopy area associated with each pft and layer + ! (used for weighting diagnostics) + real(r8) :: area_vlpfcl(nlevleaf,maxpft,nclmax) + real(r8) :: vai_top,vai_bot + real(r8) :: area_frac + real(r8) :: Rb_abs,Rd_abs,Rd_abs_leaf,Rb_abs_leaf,R_abs_stem,R_abs_snow,leaf_sun_frac + real(r8) :: vai + + do s = 1,nsites + + ifp = 0 + cpatch => sites(s)%oldest_patch + + do while (associated(cpatch)) + + if_notbareground:if(cpatch%nocomp_pft_label.ne.nocomp_bareground)then !only for veg patches + ! do not do albedo calculations for bare ground patch in SP mode + ! and (more impotantly) do not iterate ifp or it will mess up the indexing wherein + ! ifp=1 is the first vegetated patch. + ifp=ifp+1 + + ! Initialize diagnostics + cpatch%ed_parsun_z(:,:,:) = 0._r8 + cpatch%ed_parsha_z(:,:,:) = 0._r8 + cpatch%ed_laisun_z(:,:,:) = 0._r8 + cpatch%ed_laisha_z(:,:,:) = 0._r8 + cpatch%parprof_pft_dir_z(:,:,:) = 0._r8 + cpatch%parprof_pft_dif_z(:,:,:) = 0._r8 + + bc_out(s)%fsun_pa(ifp) = 0._r8 + + ! preserve_b4b will be removed soon. This is kept here to prevent + ! round off errors in the baseline tests for the two-stream code (RGK 12-27-23) + if(.not.preserve_b4b)then + bc_out(s)%laisun_pa(ifp) = 0._r8 + bc_out(s)%laisha_pa(ifp) = calc_areaindex(cpatch,'elai') + end if + + sunlai = 0._r8 + shalai = 0._r8 + if_norm_twostr: if (radiation_model.eq.norman_solver) then + + ! Loop over patches to calculate laisun_z and laisha_z for each layer. + ! Derive canopy laisun, laisha, and fsun from layer sums. + ! If sun/shade big leaf code, nrad=1 and fsun_z(p,1) and tlai_z(p,1) from + ! SurfaceAlbedo is canopy integrated so that layer value equals canopy value. + + ! cpatch%f_sun is calculated in the surface_albedo routine... + + do cl = 1, cpatch%ncl_p + do ft = 1,numpft + ! preserve_b4b will be removed soon. This is kept here to prevent + ! round off errors in the baseline tests for the two-stream code (RGK 12-27-23) + if(.not.preserve_b4b) then + sunlai = sunlai + sum(cpatch%elai_profile(cl,ft,1:cpatch%nrad(cl,ft)) * & + cpatch%f_sun(cl,ft,1:cpatch%nrad(cl,ft))) + shalai = shalai + sum(cpatch%elai_profile(cl,ft,1:cpatch%nrad(cl,ft))) + else + do iv = 1,cpatch%nrad(cl,ft) + cpatch%ed_laisun_z(CL,ft,iv) = cpatch%elai_profile(CL,ft,iv) * & + cpatch%f_sun(CL,ft,iv) + + cpatch%ed_laisha_z(CL,ft,iv) = cpatch%elai_profile(CL,ft,iv) * & + (1._r8 - cpatch%f_sun(CL,ft,iv)) + + end do + + !needed for the VOC emissions, etc. + sunlai = sunlai + sum(cpatch%ed_laisun_z(CL,ft,1:cpatch%nrad(CL,ft))) + shalai = shalai + sum(cpatch%ed_laisha_z(CL,ft,1:cpatch%nrad(CL,ft))) + + end if + end do + end do + ! preserve_b4b will be removed soon. This is kept here to prevent + ! round off errors in the baseline tests for the two-stream code (RGK 12-27-23) + if(.not.preserve_b4b)then + shalai = shalai-sunlai + end if + + if(sunlai+shalai > 0._r8)then + bc_out(s)%fsun_pa(ifp) = sunlai / (sunlai+shalai) + else + bc_out(s)%fsun_pa(ifp) = 0._r8 + endif + + if(debug)then + if(bc_out(s)%fsun_pa(ifp) > 1._r8)then + write(fates_log(),*) 'too much leaf area in profile', bc_out(s)%fsun_pa(ifp), & + sunlai,shalai + endif + end if + + elai = calc_areaindex(cpatch,'elai') + + bc_out(s)%laisun_pa(ifp) = elai*bc_out(s)%fsun_pa(ifp) + bc_out(s)%laisha_pa(ifp) = elai*(1.0_r8-bc_out(s)%fsun_pa(ifp)) + + ! Absorbed PAR profile through canopy + ! If sun/shade big leaf code, nrad=1 and fluxes from SurfaceAlbedo + ! are canopy integrated so that layer values equal big leaf values. + + do cl = 1, cpatch%ncl_p + do ft = 1,numpft + do iv = 1, cpatch%nrad(cl,ft) + + cpatch%ed_parsun_z(cl,ft,iv) = & + bc_in(s)%solad_parb(ifp,ipar)*cpatch%fabd_sun_z(cl,ft,iv) + & + bc_in(s)%solai_parb(ifp,ipar)*cpatch%fabi_sun_z(cl,ft,iv) + + cpatch%ed_parsha_z(cl,ft,iv) = & + bc_in(s)%solad_parb(ifp,ipar)*cpatch%fabd_sha_z(cl,ft,iv) + & + bc_in(s)%solai_parb(ifp,ipar)*cpatch%fabi_sha_z(cl,ft,iv) + + end do !iv + end do !ft + end do !cl + + ! Convert normalized radiation error units from fraction of radiation to W/m2 + do ib = 1,num_swb + cpatch%rad_error(ib) = cpatch%rad_error(ib) * & + (bc_in(s)%solad_parb(ifp,ib) + bc_in(s)%solai_parb(ifp,ib)) + end do + + ! output the actual PAR profiles through the canopy for diagnostic purposes + do cl = 1, cpatch%ncl_p + do ft = 1,numpft + do iv = 1, cpatch%nrad(cl,ft) + cpatch%parprof_pft_dir_z(cl,ft,iv) = (bc_in(s)%solad_parb(ifp,ipar) * & + cpatch%nrmlzd_parprof_pft_dir_z(idirect,cl,ft,iv)) + & + (bc_in(s)%solai_parb(ifp,ipar) * & + cpatch%nrmlzd_parprof_pft_dir_z(idiffuse,cl,ft,iv)) + + cpatch%parprof_pft_dif_z(cl,ft,iv) = (bc_in(s)%solad_parb(ifp,ipar) * & + cpatch%nrmlzd_parprof_pft_dif_z(idirect,cl,ft,iv)) + & + (bc_in(s)%solai_parb(ifp,ipar) * & + cpatch%nrmlzd_parprof_pft_dif_z(idiffuse,cl,ft,iv)) + + end do ! iv + end do ! ft + end do ! cl + + else + + ! If there is no sun out, we have a trivial solution + if_zenithflag: if(cpatch%solar_zenith_flag ) then + + ! Two-stream + ! ----------------------------------------------------------- + do ib = 1,num_swb + cpatch%twostr%band(ib)%Rbeam_atm = bc_in(s)%solad_parb(ifp,ib) + cpatch%twostr%band(ib)%Rdiff_atm = bc_in(s)%solai_parb(ifp,ib) + end do + + area_vlpfcl(:,:,:) = 0._r8 + cpatch%f_sun(:,:,:) = 0._r8 + + call FatesPatchFSun(cpatch, & + bc_out(s)%fsun_pa(ifp), & + bc_out(s)%laisun_pa(ifp), & + bc_out(s)%laisha_pa(ifp)) + + associate(twostr => cpatch%twostr) + + do_cl: do cl = 1,twostr%n_lyr + do_icol: do icol = 1,twostr%n_col(cl) + + ft = twostr%scelg(cl,icol)%pft + if_notair: if (ft>0) then + area_frac = twostr%scelg(cl,icol)%area + vai = twostr%scelg(cl,icol)%sai+twostr%scelg(cl,icol)%lai + nv = minloc(dlower_vai, DIM=1, MASK=(dlower_vai>vai)) + do iv = 1, nv + + vai_top = dlower_vai(iv)-dinc_vai(iv) + vai_bot = min(dlower_vai(iv),twostr%scelg(cl,icol)%sai+twostr%scelg(cl,icol)%lai) + + cpatch%parprof_pft_dir_z(cl,ft,iv) = cpatch%parprof_pft_dir_z(cl,ft,iv) + & + area_frac*twostr%GetRb(cl,icol,ivis,vai_top) + cpatch%parprof_pft_dif_z(cl,ft,iv) = cpatch%parprof_pft_dif_z(cl,ft,iv) + & + area_frac*twostr%GetRdDn(cl,icol,ivis,vai_top) + & + area_frac*twostr%GetRdUp(cl,icol,ivis,vai_top) + + call twostr%GetAbsRad(cl,icol,ipar,vai_top,vai_bot, & + Rb_abs,Rd_abs,Rd_abs_leaf,Rb_abs_leaf,R_abs_stem,R_abs_snow,leaf_sun_frac) + + cpatch%f_sun(cl,ft,iv) = cpatch%f_sun(cl,ft,iv) + & + area_frac*leaf_sun_frac + cpatch%ed_parsun_z(cl,ft,iv) = cpatch%ed_parsun_z(cl,ft,iv) + & + area_frac*(rd_abs_leaf*leaf_sun_frac + rb_abs_leaf) + cpatch%ed_parsha_z(cl,ft,iv) = cpatch%ed_parsha_z(cl,ft,iv) + & + area_frac*rd_abs_leaf*(1._r8-leaf_sun_frac) + + area_vlpfcl(iv,ft,cl) = area_vlpfcl(iv,ft,cl) + area_frac + end do + end if if_notair + end do do_icol + + do ft = 1,numpft + do_iv: do iv = 1, nlevleaf + if(area_vlpfcl(iv,ft,cl) cpatch%younger + enddo + + + enddo + return + + end subroutine FatesSunShadeFracs + +end module FatesRadiationDriveMod diff --git a/radiation/FatesRadiationMemMod.F90 b/radiation/FatesRadiationMemMod.F90 new file mode 100644 index 0000000000..6927c6bf3c --- /dev/null +++ b/radiation/FatesRadiationMemMod.F90 @@ -0,0 +1,61 @@ +Module FatesRadiationMemMod + + ! --------------------------------------------------------------------------- + ! This module is a space that holds data that defines how + ! FATES in particular uses its radiation schemes. + ! + ! Alternatively, the TwoStreamMLPEMod is more agnostic. + ! For instance, TwoStreamMLPEMod makes no assumptions about + ! which or how many broad bands are used + ! + ! For now, this module also holds relevant data for Norman radiation + ! --------------------------------------------------------------------------- + + use FatesConstantsMod, only : r8 => fates_r8 + + integer, parameter, public :: norman_solver = 1 + integer, parameter, public :: twostr_solver = 2 + + integer, parameter, public :: num_rad_stream_types = 2 ! The number of radiation streams used (direct/diffuse) + + integer, parameter, public :: idirect = 1 ! This is the array index for direct radiation + integer, parameter, public :: idiffuse = 2 ! This is the array index for diffuse radiation + + + ! TODO: we use this cp_maxSWb only because we have a static array q(size=2) of + ! land-ice abledo for vis and nir. This should be a parameter, which would + ! get us on track to start using multi-spectral or hyper-spectral (RGK 02-2017) + + integer, parameter, public :: num_swb = 2 ! Number of shortwave bands we use + ! This needs to match what is used in the host model + ! This is visible (1) and near-infrared (2) + + integer, parameter, public :: ivis = 1 ! This is the array index for short-wave + ! radiation in the visible spectrum, as expected + ! in boundary condition files and parameter + ! files. This will be compared with + ! the HLM's expectation in FatesInterfaceMod + + integer, parameter, public :: inir = 2 ! This is the array index for short-wave + ! radiation in the near-infrared spectrum, as expected + ! in boundary condition files and parameter + ! files. This will be compared with + ! the HLM's expectation in FatesInterfaceMod + + integer, parameter, public :: ipar = ivis ! The photosynthetically active band + ! can be approximated to be equal to the visible band + + ! albedo land ice by waveband (1=vis, 2=nir) + real(r8), public :: alb_ice(num_swb) = (/ 0.80_r8, 0.55_r8 /) + + ! albedo land ice by waveband (1=vis, 2=nir) + real(r8), public :: rho_snow(num_swb) = (/ 0.80_r8, 0.55_r8 /) + + ! albedo land ice by waveband (1=vis, 2=nir) + real(r8), public :: tau_snow(num_swb) = (/ 0.01_r8, 0.01_r8 /) + + + + + +end Module FatesRadiationMemMod diff --git a/radiation/FatesTwoStreamUtilsMod.F90 b/radiation/FatesTwoStreamUtilsMod.F90 new file mode 100644 index 0000000000..5a87ff24b0 --- /dev/null +++ b/radiation/FatesTwoStreamUtilsMod.F90 @@ -0,0 +1,534 @@ +Module FatesTwoStreamUtilsMod + + ! This module holds routines that are specific to connecting FATES with + ! the two-stream radiation module. These routines are used to + ! describe the scattering elements from cohort and patch data, and are + ! used to decompose the scattering elements to return values + ! at the cohort, or patch-pft scale. + use FatesConstantsMod , only : r8 => fates_r8 + use FatesConstantsMod , only : ifalse + use FatesConstantsMod , only : itrue + use FatesConstantsMod , only : nearzero + use shr_log_mod , only : errMsg => shr_log_errMsg + use FatesGlobals , only : fates_log + use FatesGlobals , only : endrun => fates_endrun + use shr_infnan_mod , only : nan => shr_infnan_nan, assignment(=) + use FatesInterfaceTypesMod, only : numpft + use FatesRadiationMemMod , only : num_swb + use FatesRadiationMemMod , only : ivis, inir + use FatesRadiationMemMod , only : rho_snow,tau_snow + use TwoStreamMLPEMod , only : air_ft, AllocateRadParams, rad_params + use FatesCohortMod , only : fates_cohort_type + use FatesPatchMod , only : fates_patch_type + use EDTypesMod , only : ed_site_type + use EDParamsMod , only : nclmax + use TwoStreamMLPEMod , only : twostream_type + use TwoStreamMLPEMod , only : RadParamPrep + use TwoStreamMLPEMod , only : AllocateRadParams + use TwoStreamMLPEMod , only : rel_err_thresh,area_err_thresh + use EDPftvarcon , only : EDPftvarcon_inst + use FatesAllometryMod , only : VegAreaLayer + + implicit none + + logical, parameter :: debug = .false. ! local debug flag + character(len=*), parameter, private :: sourcefile = & + __FILE__ + + + public :: FatesConstructRadElements + public :: FatesGetCohortAbsRad + public :: FatesPatchFSun + public :: CheckPatchRadiationBalance + +contains + + + subroutine FatesConstructRadElements(site,fcansno_pa,coszen_pa) + + type(ed_site_type) :: site + type(fates_patch_type),pointer :: patch + real(r8) :: fcansno_pa(:) + real(r8) :: coszen_pa(:) + + type(fates_cohort_type), pointer :: cohort + integer :: n_col(nclmax) ! Number of parallel column elements per layer + integer :: ican,ft,icol + type(twostream_type), pointer :: twostr + + + ! DO NOT MAKE CANOPY_OPEN_FRAC >0 UNTIL LAI COMPRESSION + ! HAS BEEN THOUGHT THROUGH. WE CANT JUST DECREASE THE + ! AREA WITHOUT CONSERVING TOTAL LEAF AND STEM AREA + real(r8), parameter :: canopy_open_frac = 0.00_r8 + + integer :: maxcol + real(r8) :: canopy_frac(5) + integer :: ifp + ! Area indices for the cohort [m2 media / m2 crown footprint] + real(r8) :: elai_cohort,tlai_cohort,esai_cohort,tsai_cohort + real(r8) :: vai_top,vai_bot ! veg area index at top and bottom of cohort (dummy vars) + + real(r8) :: area_ratio ! If elements are over 100% of available + ! canopy area, this is how much we squeeze + ! the area down by, as a ratio. This is also + ! applied to increase LAI and SAI in the cohorts + ! and elements as well (to preserve mass and volume). + + integer :: max_elements ! Maximum number of scattering elements on the site + integer :: n_scr ! The size of the scratch arrays + logical :: allocate_scratch ! Whether to re-allocate the scratch arrays + + ! These parameters are not used yet + !real(r8) :: max_vai_diff_per_elem ! The maximum vai difference in any element + ! ! between the least and most vai of constituting + ! ! cohorts. THe objective is to reduce this. + !integer, parameter :: max_el_per_layer = 10 + !real(r8), parameter :: init_max_vai_diff_per_elem = 0.2_r8 + !type(fates_cohort_type), pointer :: elem_co_ptrs(ncl*max_el_per_layer,100) + + + + + max_elements = -1 + ifp=0 + patch => site%oldest_patch + do while (associated(patch)) + ifp=ifp+1 + associate(twostr => patch%twostr) + + ! Identify how many elements we need, and possibly consolidate + ! cohorts into elements where they are very similar (LAI and PFT) + ! ------------------------------------------------------------------------------------------- + + !max_vai_diff_per_elem = init_max_vai_diff_per_elem + !iterate_count_do: do while(iterate_element_count)then + + ! Identify how many elements we need + n_col(1:nclmax) = 0 + cohort => patch%tallest + do while (associated(cohort)) + ft = cohort%pft + ican = cohort%canopy_layer + n_col(ican) = n_col(ican) + 1 + cohort => cohort%shorter + enddo + + ! If there is only one layer, then we don't + ! need to add an air element to the only + ! layer. This is because all non-veg + ! area will be attributed to a ground patch + ! But if there is more than one layer, then + ! an air element is needed for all the non + ! occupied space, even if the canopy_open_frac + ! is zero. + + if(patch%total_canopy_area>nearzero)then + canopy_frac(:) = 0._r8 + cohort => patch%tallest + do while (associated(cohort)) + ican = cohort%canopy_layer + canopy_frac(ican) = canopy_frac(ican) + cohort%c_area/patch%total_canopy_area + cohort => cohort%shorter + enddo + else + canopy_frac(:) = 0._r8 + end if + + do ican = 1,patch%ncl_p + if( (1._r8-canopy_frac(ican))>area_err_thresh ) then + n_col(ican) = n_col(ican) + 1 + end if + end do + + + ! Handle memory + ! If the two-stream object is not large enough + ! or if it is way larger than what is needed + ! re-allocate the object + ! ------------------------------------------------------------------------------------------- + + maxcol = 0 + do ican = 1,patch%ncl_p + if (n_col(ican)>maxcol) maxcol=n_col(ican) + end do + + if(.not.associated(twostr%scelg)) then + + call twostr%AllocInitTwoStream((/ivis,inir/),patch%ncl_p,maxcol+2) + + else + + if(ubound(twostr%scelg,2) < maxcol .or. & + ubound(twostr%scelg,2) > (maxcol+4) .or. & + ubound(twostr%scelg,1) < patch%ncl_p ) then + + call twostr%DeallocTwoStream() + + ! Add a little more space than necessary so + ! we don't have to keep allocating/deallocating + call twostr%AllocInitTwoStream((/ivis,inir/),patch%ncl_p,maxcol+2) + + end if + + end if + + + ! Fill the elements with their basic data and + ! reference the cohort to the elements + ! ------------------------------------------------------------------------------------------- + + n_col(1:nclmax) = 0 + cohort => patch%tallest + do while (associated(cohort)) + + ft = cohort%pft + ican = cohort%canopy_layer + + patch%canopy_mask(ican,ft) = 1 + + ! Every cohort gets its own element right now + n_col(ican) = n_col(ican)+1 + + ! If we pass layer index 0 to this routine + ! it will return the total plant LAIs and SAIs + call VegAreaLayer(cohort%treelai, & + cohort%treesai, & + cohort%height, & + 0, & + cohort%nv, & + cohort%pft, & + site%snow_depth, & + vai_top, vai_bot, & + elai_cohort,esai_cohort) + + ! Its possible that this layer is covered by snow + ! if so, then just consider it an air layer + if((elai_cohort+esai_cohort)>nearzero)then + twostr%scelg(ican,n_col(ican))%pft = ft + else + twostr%scelg(ican,n_col(ican))%pft = air_ft + end if + + twostr%scelg(ican,n_col(ican))%area = cohort%c_area/patch%total_canopy_area + twostr%scelg(ican,n_col(ican))%lai = elai_cohort + twostr%scelg(ican,n_col(ican))%sai = esai_cohort + + ! Cohort needs to know which column its in + cohort%twostr_col = n_col(ican) + + cohort => cohort%shorter + enddo + + + do ican = 1,patch%ncl_p + + ! If the canopy is not full, add an air element + if( (1._r8-canopy_frac(ican))>area_err_thresh ) then + n_col(ican) = n_col(ican) + 1 + twostr%scelg(ican,n_col(ican))%pft = air_ft + twostr%scelg(ican,n_col(ican))%area = 1._r8-canopy_frac(ican) + twostr%scelg(ican,n_col(ican))%lai = 0._r8 + twostr%scelg(ican,n_col(ican))%sai = 0._r8 + end if + + ! If the layer is overfull, remove some from area from + ! the first element that is 10x larger than the threshold + + if_overfull: if( (canopy_frac(ican)-1._r8)>area_err_thresh ) then + do icol = 1,n_col(ican) + if(twostr%scelg(ican,icol)%area > 10._r8*(canopy_frac(ican)-1._r8))then + area_ratio = (twostr%scelg(ican,icol)%area + (1._r8-canopy_frac(ican)))/twostr%scelg(ican,icol)%area + twostr%scelg(ican,icol)%area = twostr%scelg(ican,icol)%area * area_ratio + twostr%scelg(ican,icol)%lai = twostr%scelg(ican,icol)%lai / area_ratio + twostr%scelg(ican,icol)%sai = twostr%scelg(ican,icol)%sai / area_ratio + canopy_frac(ican) = 1.0_r8 + exit if_overfull + end if + end do + + !write(fates_log(),*) 'overfull areas' + !twostr%cosz = coszen_pa(ifp) + ! call twostr%Dump(1,lat=site%lat,lon=site%lon) + ! call endrun(msg=errMsg(sourcefile, __LINE__)) + end if if_overfull + + end do + + twostr%n_col(1:patch%ncl_p) = n_col(1:patch%ncl_p) + + ! Set up some non-element parameters + ! ------------------------------------------------------------------------------------------- + + twostr%n_lyr = patch%ncl_p ! Number of layers + + call twostr%GetNSCel() ! Total number of elements + + max_elements = max(max_elements,twostr%n_scel) + + twostr%force_prep = .true. ! This signals that two-stream scattering coefficients + + ! that are dependent on geometry need to be updated + call twostr%CanopyPrep(fcansno_pa(ifp)) + call twostr%ZenithPrep(coszen_pa(ifp)) + + end associate + + patch => patch%younger + end do + + ! Re-evaluate the scratch space used for solving two-stream radiation + ! The scratch space needs to be 2x the number of computational elements + ! for the patch with the most elements. + + if(allocated(site%taulambda_2str) .and. max_elements>0 )then + n_scr = ubound(site%taulambda_2str,dim=1) + allocate_scratch = .false. + if(2*max_elements > n_scr) then + allocate_scratch = .true. + deallocate(site%taulambda_2str,site%ipiv_2str,site%omega_2str) + elseif(2*max_elements < (n_scr-24)) then + allocate_scratch = .true. + deallocate(site%taulambda_2str,site%ipiv_2str,site%omega_2str) + end if + else + allocate_scratch = .true. + end if + + if(allocate_scratch)then + ! Twice as many spaces as there are elements, plus some + ! extra to prevent allocating/deallocating on the next step + n_scr = 2*max_elements+8 + allocate(site%taulambda_2str(n_scr)) + allocate(site%omega_2str(n_scr,n_scr)) + allocate(site%ipiv_2str(n_scr)) + end if + + return + end subroutine FatesConstructRadElements + + ! ============================================================================================= + + subroutine FatesPatchFSun(patch,fsun,laisun,laisha) + + type(fates_patch_type) :: patch + real(r8) :: fsun ! Patch average sunlit fraction + real(r8) :: laisun ! Patch average LAI of leaves in sun + real(r8) :: laisha ! Patch average LAI of leaves in shade + + integer :: ican, icol ! Canopy vertical and horizontal element index + + ! Dummy variables + real(r8) :: Rb_abs,Rd_abs,Rd_abs_leaf,Rb_abs_leaf,R_abs_stem,R_abs_snow + + real(r8) :: leaf_sun_frac ! Element specific sunlit fraction of leaf + real(r8) :: in_fab + + laisun = 0._r8 + laisha = 0._r8 + + associate(twostr => patch%twostr) + + + do ican = 1,twostr%n_lyr + do icol = 1,twostr%n_col(ican) + + associate(scelg => patch%twostr%scelg(ican,icol)) + + call twostr%GetAbsRad(ican,icol,ivis,0._r8,scelg%lai+scelg%sai, & + Rb_abs,Rd_abs,Rd_abs_leaf,Rb_abs_leaf,R_abs_stem,R_abs_snow,leaf_sun_frac) + + laisun = laisun + scelg%area*scelg%lai*leaf_sun_frac + laisha = laisha + scelg%area*scelg%lai*(1._r8-leaf_sun_frac) + end associate + end do + end do + + if((laisun+laisha)>nearzero)then + fsun = laisun / (laisun+laisha) + else + fsun = 0.5_r8 ! Nominal value, should not affect results if no leaves or light! + end if + + end associate + return + end subroutine FatesPatchFSun + + ! ============================================================================================ + + subroutine CheckPatchRadiationBalance(patch, snow_depth, ib, fabd, fabi) + + ! Loop through the cohorts in the patch, get the + ! absorbed radiation, then compare the amount absorbed + ! to the fraction the solver calculated + + type(fates_patch_type) :: patch + integer :: ib ! broadband index + real(r8) :: snow_depth + real(r8) :: fabd ! Fraction of absorbed direct radiation by vegetation + real(r8) :: fabi ! Fraction of absorbed indirect radiation by vegetation + + type(fates_cohort_type), pointer :: cohort + integer :: iv,ican,icol + real(r8),dimension(50) :: cohort_vaitop + real(r8),dimension(50) :: cohort_vaibot + real(r8),dimension(50) :: cohort_layer_elai + real(r8),dimension(50) :: cohort_layer_esai + real(r8) :: cohort_elai + real(r8) :: cohort_esai + real(r8) :: rb_abs,rd_abs,rb_abs_leaf,rd_abs_leaf,leaf_sun_frac,check_fab,in_fab + + associate(twostr => patch%twostr) + + check_fab = 0._r8 + + cohort => patch%tallest + do while (associated(cohort)) + + do iv = 1,cohort%nv + call VegAreaLayer(cohort%treelai, & + cohort%treesai, & + cohort%height, & + iv, & + cohort%nv, & + cohort%pft, & + snow_depth, & + cohort_vaitop(iv), & + cohort_vaibot(iv), & + cohort_layer_elai(iv), & + cohort_layer_esai(iv)) + end do + + cohort_elai = sum(cohort_layer_elai(1:cohort%nv)) + cohort_esai = sum(cohort_layer_esai(1:cohort%nv)) + + do iv = 1,cohort%nv + + ican = cohort%canopy_layer + icol = cohort%twostr_col + + call FatesGetCohortAbsRad(patch,cohort,ib,cohort_vaitop(iv),cohort_vaibot(iv), & + cohort_elai,cohort_esai,rb_abs,rd_abs,rb_abs_leaf,rd_abs_leaf,leaf_sun_frac ) + + check_fab = check_fab + (Rb_abs+Rd_abs) * cohort%c_area/patch%total_canopy_area + + end do + cohort => cohort%shorter + enddo + + in_fab = fabd*twostr%band(ib)%Rbeam_atm + fabi*twostr%band(ib)%Rdiff_atm + + if( abs(check_fab-in_fab) > in_fab*10._r8*rel_err_thresh ) then + write(fates_log(),*)'Absorbed radiation didnt balance after cohort sum' + write(fates_log(),*) ib,in_fab,check_fab,snow_depth + call twostr%Dump(ib,patch%solar_zenith_angle) + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + + + end associate + + return + end subroutine CheckPatchRadiationBalance + + ! ============================================================================================= + + subroutine FatesGetCohortAbsRad(patch,cohort,ib,vaitop,vaibot,cohort_elai,cohort_esai, & + rb_abs,rd_abs,rb_abs_leaf,rd_abs_leaf,leaf_sun_frac ) + + ! This subroutine retrieves the absorbed radiation on + ! leaves and stems, as well as the leaf sunlit fraction + ! over a specified interval of VAI (vegetation area index) + ! VAI is exposed leaf + stem area index + + type(fates_patch_type) :: patch + type(fates_cohort_type) :: cohort + integer,intent(in) :: ib + real(r8),intent(in) :: vaitop + real(r8),intent(in) :: vaibot + real(r8),intent(in) :: cohort_elai + real(r8),intent(in) :: cohort_esai + real(r8),intent(out) :: rb_abs + real(r8),intent(out) :: rd_abs + real(r8),intent(out) :: rb_abs_leaf + real(r8),intent(out) :: rd_abs_leaf + real(r8),intent(out) :: leaf_sun_frac + + real(r8) :: rd_abs_el,rb_abs_el + real(r8) :: vai_top_el + real(r8) :: vai_bot_el + real(r8) :: rd_abs_leaf_el + real(r8) :: rb_abs_leaf_el + real(r8) :: r_abs_stem_el + real(r8) :: r_abs_snow_el + real(r8) :: diff_wt_leaf,diff_wt_elem + real(r8) :: beam_wt_leaf,beam_wt_elem + real(r8) :: evai_cvai ! element VAI / cohort VAI + + associate(scelg => patch%twostr%scelg(cohort%canopy_layer,cohort%twostr_col), & + scelb => patch%twostr%band(ib)%scelb(cohort%canopy_layer,cohort%twostr_col) ) + + if((cohort_elai+cohort_esai) shr_log_errMsg + use shr_sys_mod , only: shr_sys_abort + use FatesConstantsMod, only : r8 => fates_r8 + use shr_infnan_mod, only : shr_infnan_isnan + + implicit none + private + + real(r8),parameter :: nearzero = 1.e-20_r8 + logical, parameter :: debug=.true. + real(r8), parameter :: unset_r8 = 1.e-36_r8 + real(r8), parameter :: unset_int = -999 + integer, parameter :: twostr_vis = 1 ! Named index of visible shortwave radiation + integer, parameter :: twostr_nir = 2 ! Named index for near infrared shortwave radiation + + + ! Allowable error, as a fraction of total incident for total canopy + ! radiation balance checks + + real(r8), public, parameter :: rel_err_thresh = 1.e-6_r8 + real(r8), public, parameter :: area_err_thresh = rel_err_thresh*0.1_r8 + + ! These are the codes for how the upper boundary is specified, normalized or absolute + integer,public, parameter :: normalized_upper_boundary = 1 + integer,public, parameter :: absolute_upper_boundary = 2 + + integer :: log_unit ! fortran output unit for logging + + ! These are parameter constants, ie things that are specific to the plant material + ! and radiation band. Not all of these need to be used. 2-stream ultimately wants + ! optical depth, scattering coefficient and backscatter fractions for diffuse and + ! direct light. So there are various ways to get to these parameters, depending + ! on the host model's available parameters. The rho,tau,xl and clumping parameters + ! are standard elm/clm parameters, and provided as a convenience. + + + ! Snow optical parameter constants for visible (index=1) and NIR (index=2) + + real(r8), parameter :: betad_snow(1:2) = (/0.5, 0.5/) ! Diffuse backscatter fraction (CLM50 Tech Man) + real(r8), parameter :: betab_snow(1:2) = (/0.5, 0.5/) ! Beam backscatter fraction (CLM50 Tech Man) + real(r8), parameter :: om_snow(1:2) = (/0.8, 0.4/) ! Scattering coefficient for snow (CLM50 Tech Man) + !real(r8), parameter :: om_snow(1:2) = (/0.85, 0.75/) ! Tarboton 95 + + ! Cap the maximum optical depth. After 30 or so, its + ! so close to zero, if the values get too large, then + ! it will blow up the exponents and cause math problems + + real(r8), parameter :: kb_max = 30._r8 + + + ! For air, use a nominal values to prevent div0s + ! the key is that vai = 0 + + real(r8), parameter :: k_air = 0.5_r8 + real(r8), parameter :: om_air = 0.5_r8 + real(r8), parameter :: beta_air = 0.5_r8 + integer, public, parameter :: air_ft = 0 + + type, public :: rad_params_type + + ! From the parameter file + real(r8), allocatable :: rhol(:,:) ! leaf material reflectance: (band x pft) + real(r8), allocatable :: rhos(:,:) ! stem material reflectance: (band x pft) + real(r8), allocatable :: taul(:,:) ! leaf material transmittance: (band x pft) + real(r8), allocatable :: taus(:,:) ! stem material transmittance: (band x pft) + real(r8), allocatable :: xl(:) ! leaf/stem orientation (pft) + real(r8), allocatable :: clumping_index(:) ! clumping index 0-1, when + ! leaves stick together (pft) + + ! Derived parameters + real(r8), allocatable :: phi1(:) ! intermediate term for kd and kb + real(r8), allocatable :: phi2(:) ! intermediate term for kd and kb + real(r8), allocatable :: avmu(:) ! average "av" inverse optical depth "mu" per unit leaf and stem area + real(r8), allocatable :: kd_leaf(:) ! Mean optical depth per unit area leaves in diffuse + real(r8), allocatable :: kd_stem(:) ! Mean optical depth per unit area stems in diffuse + real(r8), allocatable :: om_leaf(:,:) ! Leaf scattering coefficient (band x pft) + real(r8), allocatable :: om_stem(:,:) ! Stem scattering coefficient (band x pft) + end type rad_params_type + + type(rad_params_type),public :: rad_params + + + ! Information describing the scattering elements + ! that is based on "g"eometry, and independent of wavelength + + type scelg_type + integer :: pft ! pft index + real(r8) :: area ! m2 col/m2 ground + real(r8) :: lai ! m2 of leaf area / m2 col + real(r8) :: sai ! m2 of stem area / m2 col + real(r8) :: Kb ! Optical depth of beam radiation + real(r8) :: Kb_leaf ! Optical depth of just leaves in beam radiation + real(r8) :: Kd ! Optical depth of diffuse radiation + real(r8) :: area_squeeze ! This is the ratio of the element area to the + ! the area of its constituents. Ideally this + ! should be 1.0, but if the host model does not + ! do a good job of filling up a canopy with 100% space, + ! and instead is fractionally more than 100%, we must + ! squeeze the area of 1 or more elements to get an exact + ! space usage. + end type scelg_type + + + ! Information describing the scattering elemnets that + ! is dependent on wavelengths, ie "b"ands (this is allocated for each broad band) + + type scelb_type + + ! Terms used in the final solution, also used for decomposing solution + real(r8) :: Au ! Compound intercept term + real(r8) :: Ad ! Compound intercept term + real(r8) :: B1 ! Compound term w/ lambdas (operates on e^{av}) + real(r8) :: B2 ! Compound term w/ lambdas (operates on e^{-av}) + real(r8) :: lambda1_diff ! Compount term w/ B for diffuse forcing + real(r8) :: lambda2_diff ! Compound term w/ B for diffuse forcing + real(r8) :: lambda1_beam ! Compount term w/ B for beam forcing + real(r8) :: lambda2_beam ! Compound term w/ B for beam forcing + + real(r8) :: a ! Complex term operating on veg area index + real(r8) :: om ! scattering coefficient for media as a whole + real(r8) :: betad ! backscatter fraction of diffuse radiation for media as a whole + real(r8) :: betab ! backscatter fraction of beam radiation for media as a whole + real(r8) :: Rbeam0 ! Normalized downwelling beam radiation at + ! top of the element (relative to downwelling atmospheric beam) [-] + + end type scelb_type + + + type band_type + + type(scelb_type), pointer :: scelb(:,:) ! array of scattering coefficients (layer, column) + ! can be sparse, will only solve indices up to + integer :: ib ! band index, should be consistent with rad_params + real(r8) :: Rbeam_atm ! Downwelling beam radiation from atmosphere [W/m2 ground] + real(r8) :: Rdiff_atm ! Downwelling diffuse radiation from atmosphere [W/m2 ground] + real(r8) :: albedo_grnd_diff ! Ground albedo diffuse + real(r8) :: albedo_grnd_beam ! Ground albedo direct + + end type band_type + + + ! This type contains the pre-processed scattering coefficients + ! and routines. This is the parent type that holds almost everything + ! in the two-stream solver. + ! The scelg structure describes the scattering elements, these are values + ! that need to be defined by the ecosystem model, somewhat of + ! an input to the solver. Since this is a Perfect Plasticity Approximation + ! enabled system, we partition the scattering media into "columns" and "layers" + ! Layers are canopy layers, think understory, mid-story and upper canopy. Columns + ! are divisions of horizontal space, ie literal columns of space. The current + ! implementation limits this space to media that has uniform scattering coefficients. + ! So there could not be different PFTs in the same column, because they would undoubtedly + ! have different joint scattering coefficients at different height levels in + ! the column. Therefore, every column is connected with a PFT. + + + type, public :: twostream_type + + type(scelg_type), pointer :: scelg(:,:) ! array of scattering elements (layer, column) + ! can be sparse, will only solve indices up to + ! n_lyr,n_col(n_lyr). This is for band (wavelength) + ! independent information + + type(band_type), pointer :: band(:) ! Holds scattering coefficients for each band + ! vis,nir,etc (nothing that emits though, no thermal) + + integer :: n_bands ! number of bands (allocation size of band(:)) + integer :: n_lyr ! number of (vertical) scattering element layers + integer, allocatable :: n_col(:) ! number of (horizontal) scattering element columns per layer + integer :: n_scel ! total number of scattering elements + logical :: force_prep ! Some coefficients are only updated + ! when the canopy composition changes, ie + ! changes in leaf, stem or snow structure. + ! If so, this sets to true, signalling that diffuse + ! scattering coefficients should be updated. + ! Otherwise, we only updated zenith dependent + ! parameters on short sub-daily timesteps + real(r8) :: frac_snow ! Current mean snow-fraction of the canopy + real(r8) :: frac_snow_old ! Previous mean snow-fraction of the canopy + real(r8) :: cosz ! Current cosine of the zenith angle + + contains + + procedure :: ZenithPrep ! Update coefficients as zenith changes + procedure :: CanopyPrep ! Update coefficients as canopy changes + procedure :: Solve ! Perform the scattering solution + procedure :: Dump ! Dump out (print out) the site of interest + procedure :: GetNSCel + procedure :: AllocInitTwoStream + procedure :: DeallocTwoStream + + procedure :: GetRdUp + procedure :: GetRdDn + procedure :: GetRb + procedure :: GetAbsRad + + + end type twostream_type + + public :: RadParamPrep + public :: AllocateRadParams + public :: TwoStreamLogInit + + character(len=*), parameter, private :: sourcefile = & + __FILE__ + + +contains + + subroutine TwoStreamLogInit(log_unit_in) + integer,intent(in) :: log_unit_in + + log_unit = log_unit_in + + end subroutine TwoStreamLogInit + + subroutine endrun(msg) + + !----------------------------------------------------------------------- + ! !DESCRIPTION: + ! Abort the model for abnormal termination + ! This subroutine was derived from CLM's + ! endrun_vanilla() in abortutils.F90 + ! + ! + ! !ARGUMENTS: + implicit none + character(len=*), intent(in) :: msg ! string to be printed + !----------------------------------------------------------------------- + + write(log_unit,*)'ENDRUN:', msg + call shr_sys_abort() + + end subroutine endrun + + + ! =============================================================================================== + + subroutine AllocInitTwoStream(this,band_indices,ncan,ncol) + + class(twostream_type) :: this + integer :: band_indices(:) + integer :: ncan + integer :: ncol + + integer :: nbands + integer :: ib + + nbands = ubound(band_indices,1) + + allocate(this%n_col(ncan)) + allocate(this%scelg(ncan,ncol)) + allocate(this%band(nbands)) + + this%n_col(1:ncan) = unset_int + this%n_bands = nbands + this%n_lyr = ncan + this%frac_snow = unset_r8 + this%frac_snow_old = unset_r8 + + do ib = 1,nbands + + allocate(this%band(ib)%scelb(ncan,ncol)) + this%band(ib)%albedo_grnd_diff = unset_r8 + this%band(ib)%albedo_grnd_beam = unset_r8 + this%band(ib)%ib = band_indices(ib) + + end do + + + + return + end subroutine AllocInitTwoStream + + ! =============================================================================================== + + subroutine DeallocTwoStream(this) + + class(twostream_type) :: this + + integer :: nbands + integer :: ib + + nbands = ubound(this%band,1) + + deallocate(this%scelg) + deallocate(this%n_col) + do ib = 1,nbands + deallocate(this%band(ib)%scelb) + end do + deallocate(this%band) + + return + end subroutine DeallocTwoStream + + ! =============================================================================================== + + subroutine AllocateRadParams(n_pft,n_bands) + + integer,intent(in) :: n_pft + integer,intent(in) :: n_bands + + ! Include the zeroth pft index for air + + allocate(rad_params%rhol(n_bands,n_pft)) + allocate(rad_params%rhos(n_bands,n_pft)) + allocate(rad_params%taul(n_bands,n_pft)) + allocate(rad_params%taus(n_bands,n_pft)) + allocate(rad_params%xl(n_pft)) + allocate(rad_params%clumping_index(n_pft)) + + allocate(rad_params%phi1(n_pft)) + allocate(rad_params%phi2(n_pft)) + allocate(rad_params%avmu(n_pft)) + allocate(rad_params%kd_leaf(n_pft)) + allocate(rad_params%kd_stem(n_pft)) + allocate(rad_params%om_leaf(n_bands,n_pft)) + allocate(rad_params%om_stem(n_bands,n_pft)) + + end subroutine AllocateRadParams + + ! ================================================================================================ + + function GetRdDn(this,ican,icol,ib,vai) result(r_diff_dn) + + class(twostream_type) :: this + real(r8),intent(in) :: vai + integer,intent(in) :: ican + integer,intent(in) :: icol + integer,intent(in) :: ib + real(r8) :: r_diff_dn + + ! Rdn = Ad e−(Kbv) + Re + λ1 B2 e^(av) + λ2 B1 e^(−av) + + associate(scelb => this%band(ib)%scelb(ican,icol), & + scelg => this%scelg(ican,icol) ) + + r_diff_dn = this%band(ib)%Rbeam_atm*( & + scelb%Ad*exp(-scelg%Kb*vai) + & + scelb%B2*scelb%lambda1_beam*exp(scelb%a*vai) + & + scelb%B1*scelb%lambda2_beam*exp(-scelb%a*vai)) + & + this%band(ib)%Rdiff_atm*( & + scelb%B2*scelb%lambda1_diff*exp(scelb%a*vai) + & + scelb%B1*scelb%lambda2_diff*exp(-scelb%a*vai)) + + if(debug)then + ! if(isnan(r_diff_dn))then !RGK: NVHPC HAS A BUG IN THIS INTRINSIC (01-2024) + ! if(r_diff_dn /= r_diff_dn) then + if(shr_infnan_isnan(r_diff_dn)) then + write(log_unit,*)"GETRDN" + write(log_unit,*)scelg%Kb + write(log_unit,*)scelb%a + write(log_unit,*)vai + write(log_unit,*)scelb%Ad + write(log_unit,*)scelb%B1,scelb%B2 + write(log_unit,*)scelb%lambda1_beam,scelb%lambda2_beam + write(log_unit,*)scelb%lambda1_diff,scelb%lambda2_diff + write(log_unit,*)this%band(ib)%Rbeam_atm + write(log_unit,*)this%band(ib)%Rdiff_atm + write(log_unit,*)exp(-scelg%Kb*vai) + write(log_unit,*)exp(scelb%a*vai) + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + end if + + end associate + end function GetRdDn + + function GetRdUp(this,ican,icol,ib,vai) result(r_diff_up) + + class(twostream_type) :: this + real(r8),intent(in) :: vai + integer,intent(in) :: ican + integer,intent(in) :: icol + integer,intent(in) :: ib + real(r8) :: r_diff_up + + ! Rup = Au e−(Kbv) + Re + λ1 B1 e^(av) + λ2 B2 e^(−av) + + associate(scelb => this%band(ib)%scelb(ican,icol), & + scelg => this%scelg(ican,icol) ) + + r_diff_up = this%band(ib)%Rbeam_atm*( & + scelb%Au*exp(-scelg%Kb*vai) + & + scelb%B1*scelb%lambda1_beam*exp(scelb%a*vai) + & + scelb%B2*scelb%lambda2_beam*exp(-scelb%a*vai)) + & + this%band(ib)%Rdiff_atm*( & + scelb%B1*scelb%lambda1_diff*exp(scelb%a*vai) + & + scelb%B2*scelb%lambda2_diff*exp(-scelb%a*vai)) + + end associate + end function GetRdUp + + function GetRb(this,ican,icol,ib,vai) result(r_beam_dn) + + class(twostream_type) :: this + real(r8),intent(in) :: vai + integer,intent(in) :: ican + integer,intent(in) :: icol + integer,intent(in) :: ib + real(r8) :: r_beam_dn + + r_beam_dn = this%band(ib)%Rbeam_atm * & + this%band(ib)%scelb(ican,icol)%Rbeam0*exp(-this%scelg(ican,icol)%Kb*vai) + + end function GetRb + + subroutine GetAbsRad(this,ican,icol,ib,vai_top,vai_bot, & + Rb_abs,Rd_abs,Rd_abs_leaf,Rb_abs_leaf,R_abs_stem,R_abs_snow,leaf_sun_frac) + + ! This routine is used to help decompose radiation scattering + ! and return the amount of absorbed radiation. The canopy layer and column + ! index identify the element of interest. The other arguments are the upper and + ! lower bounds within the element over which to evaluate absorbed radiation. + ! The assumption is that the vegetation area index is zero at the top of the + ! element, and increases going downwards. As with all assumptions in this + ! module, the scattering parameters are uniform within the element itself, + ! which includes an assumption of the leaf/stem proportionality. + ! --------------------------------------------------------------------------- + ! Solution for radiative intensity of diffuse up and down at tai=v + ! Rup = Au e−(Kbv) + Re + λ1 B1 e^(av) + λ2 B2 e^(−av) + ! Rdn = Ad e−(Kbv) + Re + λ1 B2 e^(av) + λ2 B1 e^(−av) + ! --------------------------------------------------------------------------- + + ! Arguments + class(twostream_type) :: this + integer,intent(in) :: ican + integer,intent(in) :: icol + integer, intent(in) :: ib ! broad band index + real(r8), intent(in) :: vai_top ! veg area index (from the top of element) to start + real(r8), intent(in) :: vai_bot ! veg area index (from the top of element) to finish + real(r8), intent(out) :: Rb_abs ! total absorbed beam radiation [W/m2 ground] + real(r8), intent(out) :: Rd_abs ! total absorbed diffuse radiation [W/m2 ground] + real(r8), intent(out) :: Rb_abs_leaf ! Absorbed beam radiation from leaves [W/m2 ground] + real(r8), intent(out) :: Rd_abs_leaf ! Absorbed diff radiation from leaves [W/m2 ground] + real(r8), intent(out) :: R_abs_stem ! Absorbed beam+diff radiation stems [W/m2 ground] + real(r8), intent(out) :: R_abs_snow ! Absorbed beam+diff radiation snow [W/m2 ground] + real(r8), intent(out) :: leaf_sun_frac ! Fraction of leaves in the interval exposed + ! to sunlight + + real(r8) :: dvai,dlai ! Amount of VAI and LAI in this interval [m2/m2] + real(r8) :: Rd_net ! Difference in diffuse radiation at upper and lower boundaries [W/m2] + real(r8) :: Rb_net ! Difference in beam radiation at upper and lower boundaries [W/m2] + real(r8) :: vai_max ! total integrated (leaf+stem) area index of the current element + real(r8) :: frac_abs_snow ! fraction of radiation absorbed by snow + real(r8) :: diff_wt_leaf ! diffuse absorption weighting for leaves + real(r8) :: diff_wt_stem ! diffuse absorption weighting for stems + real(r8) :: beam_wt_leaf ! beam absorption weighting for leaves + real(r8) :: beam_wt_stem ! beam absorption weighting for stems + real(r8) :: lai_bot,lai_top + + associate(scelb => this%band(ib)%scelb(ican,icol), & + scelg => this%scelg(ican,icol), & + ft => this%scelg(ican,icol)%pft ) + + ! If this is air, trivial solutions + if(ft==air_ft) then + Rb_abs = 0._r8 + Rd_abs = 0._r8 + Rb_abs_leaf = 0._r8 + Rd_abs_leaf = 0._r8 + R_abs_stem = 0._r8 + R_abs_snow = 0._r8 + leaf_sun_frac = 0._r8 + return + end if + + ! The total vegetation area index of the element + vai_max = scelg%lai + scelg%sai + + dvai = vai_bot - vai_top + + lai_top = vai_top*scelg%lai/( scelg%lai+ scelg%sai) + lai_bot = vai_bot*scelg%lai/( scelg%lai+ scelg%sai) + dlai = dvai * scelg%lai/( scelg%lai+ scelg%sai) + + + if(dlai>nearzero)then + leaf_sun_frac = max(0.001_r8,min(0.999_r8,scelb%Rbeam0/(dlai*scelg%Kb_leaf/rad_params%clumping_index(ft)) & + *(exp(-scelg%Kb_leaf*lai_top) - exp(-scelg%Kb_leaf*lai_bot)))) + else + leaf_sun_frac = 0001._r8 + end if + + !leaf_sun_frac = max(0.001_r8,min(0.999_r8,scelb%Rbeam0/(dvai*scelg%Kb/rad_params%clumping_index(ft)) & + ! *(exp(-scelg%Kb*vai_top) - exp(-scelg%Kb*vai_bot)))) + + + if(debug) then + if(leaf_sun_frac>1.0_r8 .or. leaf_sun_frac<0._r8) then + write(log_unit,*)"impossible leaf sun fraction" + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + end if + + ! We have to disentangle the absorption between leaves and stems, we give them both + ! a weighting fraction of total absorption of area*K*(1-om) + + frac_abs_snow = this%frac_snow*(1._r8-om_snow(ib)) / (1._r8-scelb%om) + + diff_wt_leaf = scelg%lai*(1._r8-rad_params%om_leaf(ib,ft))*rad_params%Kd_leaf(ft) + diff_wt_stem = scelg%sai*(1._r8-rad_params%om_stem(ib,ft))*rad_params%Kd_stem(ft) + + beam_wt_leaf = scelg%lai*(1._r8-rad_params%om_leaf(ib,ft))*scelg%Kb_leaf + beam_wt_stem = scelg%sai*(1._r8-rad_params%om_stem(ib,ft))*1._r8 + + ! Mean element transmission coefficients adding snow scattering + + if(debug) then + if( (vai_bot-vai_max)>rel_err_thresh)then + write(log_unit,*)"During decomposition of the 2-stream radiation solution" + write(log_unit,*)"A vegetation area index (VAI) was requested in GetAbsRad()" + write(log_unit,*)"that is larger than the total integrated VAI of the " + write(log_unit,*)"computation element of interest." + write(log_unit,*)"vai_max: ",vai_max + write(log_unit,*)"vai_bot: ",vai_bot + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + if( (vai_bot-vai_top)<-rel_err_thresh ) then + write(log_unit,*)"During decomposition of the 2-stream radiation solution" + write(log_unit,*)"the vegetation area index at the lower position was set" + write(log_unit,*)"as greater than the value at the upper position." + write(log_unit,*)"vai_max: ",vai_max + write(log_unit,*)"vai_bot: ",vai_bot + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + end if + + ! Amount of absorbed radiation is retrieved by doing an energy + ! balance on this boundaries over the depth of interest (ie net) + ! Result is Watts / m2 of the element's area footprint NOT + ! per m2 of tissue (at least not in this step) + + Rb_net = this%GetRb(ican,icol,ib,vai_top)-this%GetRb(ican,icol,ib,vai_bot) + + Rd_net = (this%GetRdDn(ican,icol,ib,vai_top) - this%GetRdDn(ican,icol,ib,vai_bot)) + & + (this%GetRdUp(ican,icol,ib,vai_bot) - this%GetRdUp(ican,icol,ib,vai_top)) + + ! The net beam radiation includes that which is absorbed, but also, + ! that which is re-scattered, the re-scattered acts as a source + ! to the net diffuse balance and adds to the absorbed, and a sink + ! on the beam absorbed term. + + Rb_abs = Rb_net * (1._r8-this%band(ib)%scelb(ican,icol)%om) + Rd_abs = Rd_net + Rb_net * this%band(ib)%scelb(ican,icol)%om + + + Rb_abs_leaf = (1._r8-frac_abs_snow)*Rb_abs * beam_wt_leaf / (beam_wt_leaf+beam_wt_stem) + Rd_abs_leaf = (1._r8-frac_abs_snow)*Rd_abs * diff_wt_leaf / (diff_wt_leaf+diff_wt_stem) + + R_abs_snow = (Rb_abs+Rd_abs)*frac_abs_snow + + R_abs_stem = (1._r8-frac_abs_snow)* & + (Rb_abs*beam_wt_stem / (beam_wt_leaf+beam_wt_stem) + & + Rd_abs*diff_wt_stem / (diff_wt_leaf+diff_wt_stem)) + + + + + end associate + return + end subroutine GetAbsRad + + ! ================================================================================================ + + subroutine Dump(this,ib,lat,lon) + + ! Dump out everything we know about these two-stream elements + + class(twostream_type) :: this + integer,intent(in) :: ib + real(r8),optional,intent(in) :: lat + real(r8),optional,intent(in) :: lon + integer :: ican + integer :: icol + + write(log_unit,*) 'Dumping Two-stream elements for band ', ib + write(log_unit,*) + write(log_unit,*) 'rbeam atm: ',this%band(ib)%Rbeam_atm + write(log_unit,*) 'rdiff_atm: ',this%band(ib)%Rdiff_atm + write(log_unit,*) 'alb grnd diff: ',this%band(ib)%albedo_grnd_diff + write(log_unit,*) 'alb grnd beam: ',this%band(ib)%albedo_grnd_beam + write(log_unit,*) 'cosz: ',this%cosz + write(log_unit,*) 'snow fraction: ',this%frac_snow + if(present(lat)) write(log_unit,*) 'lat: ',lat + if(present(lon)) write(log_unit,*) 'lon: ',lon + + do_can: do ican = 1,this%n_lyr + do_col: do icol = 1,this%n_col(ican) + associate(scelg => this%scelg(ican,icol), & + scelb => this%band(ib)%scelb(ican,icol)) + write(log_unit,*) '--',ican,icol,'--' + write(log_unit,*) 'pft:',scelg%pft + write(log_unit,*) 'area: ',scelg%area + write(log_unit,*) 'lai,sai: ',scelg%lai,scelg%sai + write(log_unit,*) 'Kb: ',scelg%Kb + write(log_unit,*) 'Kb leaf: ',scelg%Kb_leaf + write(log_unit,*) 'Kd: ',scelg%Kd + write(log_unit,*) 'Rb0: ',scelb%Rbeam0 + write(log_unit,*) 'om: ',scelb%om + write(log_unit,*) 'betad: ',scelb%betad + write(log_unit,*) 'betab:',scelb%betab + write(log_unit,*) 'a: ',scelb%a + this%band(ib)%Rbeam_atm = 1.0_r8 + this%band(ib)%Rdiff_atm = 1.0_r8 + write(log_unit,*)'RDiff Down @ bottom: ',this%GetRdDn(ican,icol,ib,scelg%lai+scelg%sai) + write(log_unit,*)'RDiff Up @ bottom: ',this%GetRdUp(ican,icol,ib,scelg%lai+scelg%sai) + write(log_unit,*)'Rbeam @ bottom: ',this%GetRb(ican,icol,ib,scelg%lai+scelg%sai) + end associate + end do do_col + end do do_can + + end subroutine Dump + + + ! ================================================================================================ + + subroutine RadParamPrep() + + integer :: ft + integer :: nbands + integer :: numpft + integer :: ib + + numpft = ubound(rad_params%om_leaf,2) + nbands = ubound(rad_params%om_leaf,1) + + do ft = 1,numpft + + ! The non-band specific parameters here will be re-derived for each + ! band, which is inefficient, however this is an incredibly cheap + ! routine to begin with, its only called during initialization, so + ! just let it go, dont worry about it. + + if(rad_params%xl(ft)<-0.4_r8 .or. rad_params%xl(ft)>0.6_r8) then + write(log_unit,*)"Leaf orientation factors (xl) should be between -0.4 and 0.6" + write(log_unit,*)"ft: ",ft,"xl: ",rad_params%xl(ft) + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + + ! There is a singularity of leaf orientation is exactly 0 + ! phi1 = 0.5 + ! phi2 = 0.0 + ! avmu = 1/0 (1 - 0.5/0 * ln(0.5/0.5) ) but the limit approaches 1 + ! a value of 0.0001 does not break numerics and generates an avmu of nearly 1 + + if( abs(rad_params%xl(ft)) <0.0001) rad_params%xl(ft)=0.0001_r8 + + ! There must be protections on xl to prevent div0 and other weirdness + rad_params%phi1(ft) = 0.5_r8 - 0.633_r8*rad_params%xl(ft) - 0.330_r8*rad_params%xl(ft)*rad_params%xl(ft) + rad_params%phi2(ft) = 0.877_r8 * (1._r8 - 2._r8*rad_params%phi1(ft)) !0 = horiz leaves, 1 - vert leaves. + + ! Eq. 3.4 CLM50 Tech Man + rad_params%avmu(ft) = (1._r8/rad_params%phi2(ft))* & + (1._r8-(rad_params%phi1(ft)/rad_params%phi2(ft))* & + log((rad_params%phi2(ft)+rad_params%phi1(ft))/rad_params%phi1(ft))) + + do ib = 1, nbands + rad_params%Kd_leaf(ft) = rad_params%clumping_index(ft)/rad_params%avmu(ft) + rad_params%Kd_stem(ft) = 1._r8 + + rad_params%om_leaf(ib,ft) = rad_params%rhol(ib,ft) + rad_params%taul(ib,ft) + rad_params%om_stem(ib,ft) = rad_params%rhos(ib,ft) + rad_params%taus(ib,ft) + + if( rad_params%om_leaf(ib,ft) > 0.99_r8 ) then + write(log_unit,*) "In: TwoStreamMLPEMod.F90:RadParamPrep()" + write(log_unit,*) "An extremely high leaf scattering coefficient was generated:" + write(log_unit,*) "om = tau + rho" + write(log_unit,*) "band = ",ib + write(log_unit,*) "pft = ",ft + write(log_unit,*) "om_leaf = ",rad_params%om_leaf(ib,ft) + write(log_unit,*) "rhol = ",rad_params%rhol(ib,ft) + write(log_unit,*) "taul = ",rad_params%taul(ib,ft) + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + if( rad_params%om_stem(ib,ft) > 0.99_r8 ) then + write(log_unit,*) "In: TwoStreamMLPEMod.F90:RadParamPrep()" + write(log_unit,*) "An extremely high stem scattering coefficient was generated:" + write(log_unit,*) "om = tau + rho" + write(log_unit,*) "band = ",ib + write(log_unit,*) "pft = ",ft + write(log_unit,*) "om_stem = ",rad_params%om_stem(ib,ft) + write(log_unit,*) "rhos = ",rad_params%rhos(ib,ft) + write(log_unit,*) "taus = ",rad_params%taus(ib,ft) + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + + end do + + end do + + return + end subroutine RadParamPrep + + ! ================================================================================================ + + + ! ================================================================================================ + + subroutine CanopyPrep(this,frac_snow) + + ! Pre-process things that change with canopy-geometry or snow cover + ! We try to only run this when necessary. For instance we only + ! run this when the canopy vegetation composition changes, or + ! when the amount of snow-cover changes. + + class(twostream_type) :: this + + real(r8) :: frac_snow ! The fraction (in terms of vegetation area index) + ! of vegetation covered with snow + + ! But we check if the snow conditions + ! change during the high frequency calls + ! as well. + integer :: ib ! The band of interest + integer :: ican ! scattering element canopy layer index (top down) + integer :: icol ! scattering element column + real(r8) :: rho ! element mean material reflectance + real(r8) :: tau ! element mean material transmittance + real(r8) :: vai ! vegetation area index lai+sai + real(r8) :: om_veg ! scattering coefficient for vegetation (no snow) + real(r8) :: betad_veg ! diffuse backscatter for vegetation (no snow) + real(r8) :: betad_om ! multiplication of diffuse backscatter and reflectance + real(r8) :: area_check ! Checks to make sure each layer has 100% coverage + real(r8) :: a2 ! The "a" term squared + + this%frac_snow = frac_snow + + if(.not.this%force_prep) then + if(abs(this%frac_snow-this%frac_snow_old) this%scelg(ican,icol)%lai, & + sai => this%scelg(ican,icol)%sai, & + ft => this%scelg(ican,icol)%pft, & + scelg => this%scelg(ican,icol)) + + vai = lai + sai + + ! Mean element transmission coefficients w/o snow effects + + if(ft==air_ft) then + scelg%Kd = k_air + else + if(debug)then + if(vai this%band(ib)%scelb(ican,icol)) + + if (ft==air_ft) then + + scelb%om = om_air + scelb%betad = beta_air + + else + + ! Material reflectance (weighted average of leaf stem and snow) + + ! Eq. 3.11 and 3.12 ClM5.0 Tech Man + om_veg = (lai*rad_params%om_leaf(ib,ft) + & + sai*rad_params%om_stem(ib,ft))/vai + + ! Eq. 3.5 ClM5.0 Tech Man + scelb%om = this%frac_snow*om_snow(ib) + (1._r8-this%frac_snow)*om_veg + + ! Diffuse backscatter, taken from G. Bonan's code + + rho = (lai * rad_params%rhol(ib,ft) + & + sai * rad_params%rhos(ib,ft))/vai + tau = (lai * rad_params%taul(ib,ft) + & + sai * rad_params%taus(ib,ft))/vai + + ! Eq 3.13 from CLM5.0 Tech Man + betad_veg = 0.5_r8 / scelb%om * & + ( scelb%om + (rho-tau) * ((1._r8+rad_params%xl(ft))/2._r8)**2._r8 ) + + ! Eq. 3.6 from CLM5.0 Tech Man + betad_om = betad_veg*om_veg*(1._r8-this%frac_snow) + & + om_snow(ib)*betad_snow(ib)*this%frac_snow + + scelb%betad = betad_om / scelb%om + + if(debug)then + !if(isnan(scelb%betad))then !RGK: NVHPC HAS A BUG IN THIS INTRINSIC (01-2024) + !if(scelb%betad /= scelb%betad) then + if(shr_infnan_isnan(scelb%betad))then + write(log_unit,*)"nans in canopy prep" + write(log_unit,*) ib,ican,icol,ft + write(log_unit,*) scelb%betad,scelb%om,lai,sai + write(log_unit,*) this%frac_snow,om_snow(ib),vai,om_veg + write(log_unit,*)"TwoStreamMLPEMod.F90:CanopyPrep" + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + end if + + end if + + a2 = scelg%Kd*scelg%Kd*(1._r8-scelb%om)*(1._r8-scelb%om+2._r8*scelb%om*scelb%betad) + if(a2<0._r8) then + write(log_unit,*)'a^2 is less than zero' + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + + ! We also have to avoid singularities, see Ad and Au below, + ! where a^2-Kb^2 is in the denominator + + scelb%a = sqrt(a2) + + end associate + end do do_bands + end associate + end do do_col + + ! RE-ENABLE THIS CHECK WHEN FATES IS BETTER AT CONSERVING AREA!! + if(.false.)then + !if( abs(area_check-1._r8) > 10._r8*area_err_thresh )then + write(log_unit,*)"Only a partial canopy was specified" + write(log_unit,*)"Scattering elements must constitute 100% of the ground cover." + write(log_unit,*)"for open spaces, create an air element with the respective area." + write(log_unit,*)"total area (out of 1): ",area_check,ican + write(log_unit,*)"layer: ",ican," of: ",this%n_lyr + do icol = 1,this%n_col(ican) + write(log_unit,*)this%scelg(ican,icol)%area,this%scelg(ican,icol)%pft + end do + write(log_unit,*)"TwoStreamMLPEMod.F90:CanopyPrep" + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + + end do do_can + + return + end subroutine CanopyPrep + + ! ================================================================================================ + + subroutine ZenithPrep(this,cosz_in) + + ! Pre-process things that change with the zenith angle + ! i.e. the beam optical properties + + ! Important !!!! + ! This should always be called after CanopyPrep() has been + ! called. This routine relies on the results of that routine + ! notably the scattering coefficient "om". + + class(twostream_type) :: this + integer :: ib ! band index, matches indexing of rad_params + real(r8),intent(in) :: cosz_in ! Un-protected cosine of the zenith angle + + real(r8) :: cosz ! the near-zero protected cosz + integer :: ican ! scattering element canopy layer index (top down) + integer :: icol ! scattering element column + real(r8) :: asu ! single scattering albedo + real(r8) :: gdir + real(r8) :: tmp0,tmp1,tmp2 + real(r8) :: betab_veg ! beam backscatter for vegetation (no snow) + real(r8) :: betab_om ! multiplication of beam backscatter and reflectance + real(r8) :: om_veg ! scattering coefficient for vegetation (no snow) + real(r8) :: Kb_sing ! the KB_leaf that would generate a singularity + ! with the scelb%a parameter + real(r8) :: Kb_stem ! actual optical depth of stem with not planar geometry effects + ! usually the base value + real(r8), parameter :: Kb_stem_base = 1.0_r8 + real(r8), parameter :: sing_tol = 0.01_r8 ! allowable difference between + ! the Kb_leaf that creates + ! a singularity and the actual + + if( (cosz_in-1.0) > nearzero ) then + write(log_unit,*)"The cosine of the zenith angle cannot exceed 1" + write(log_unit,*)"cosz: ",cosz + write(log_unit,*)"TwoStreamMLPEMod.F90:ZenithPrep" + call endrun(msg=errMsg(sourcefile, __LINE__)) + elseif(cosz_in<0._r8)then + write(log_unit,*)"The cosine of the zenith angle should not be less than zero" + write(log_unit,*)"It can be exactly zero, but not less than" + write(log_unit,*)"cosz: ",cosz + write(log_unit,*)"TwoStreamMLPEMod.F90:ZenithPrep" + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + + cosz = max(0.001,cosz_in) + + this%cosz = cosz + + do_ican: do ican = 1,this%n_lyr + do_ical: do icol = 1,this%n_col(ican) + + associate(ft => this%scelg(ican,icol)%pft, & + scelg => this%scelg(ican,icol)) + + if(ft==air_ft)then + ! Simple provisions for a ghost element (air) + scelg%Kb_leaf = k_air + scelg%Kb = k_air + else + gdir = rad_params%phi1(ft) + rad_params%phi2(ft) * cosz + + Kb_stem = Kb_stem_base + + !how much direct light penetrates a singleunit of lai? + scelg%Kb_leaf = min(kb_max,rad_params%clumping_index(ft) * gdir / cosz) + + ! To avoid singularities, we need to make sure that Kb =/ a + ! If they are too similar, it will create a very large + ! term in the linear solution and generate solution errors + ! Lets identify the Kb_leaf that gives a singularity. + ! We don't need to include the min() function + ! a will never be that large. + ! + ! kb = a = (lai*kb_leaf + sai*kb_stem)/(lai+sai) + ! (a*(lai+sai) - sai*kb_stem)/lai = Kb_sing + ! or.. adjust stem Kb? + ! (a*(lai+sai) - lai*kb_leaf)/sai = kb_stem_sing + if(scelg%lai>nearzero) then + do ib = 1,this%n_bands + Kb_sing = (this%band(ib)%scelb(ican,icol)%a*(scelg%lai+scelg%sai) - scelg%sai*Kb_stem)/scelg%lai + if(abs(scelg%Kb_leaf - Kb_sing) this%band(ib)%scelb(ican,icol) ) + + if(ft==air_ft)then + + ! Simple provisions for a ghost element (air) + scelb%betab = beta_air + + else + + ! betab - upscatter parameter for direct beam radiation, from G. Bonan + ! Eq. 3.16 CLM50 Tech Man + ! asu is the single scattering albedo per om_veg (material reflectance) + + asu = 0.5_r8 * gdir / tmp0 * tmp2 + + betab_veg = (1._r8 + rad_params%avmu(ft)*scelg%Kb) / (rad_params%avmu(ft)*scelg%Kb) * asu + + om_veg = (scelg%lai*rad_params%om_leaf(ib,ft) + & + scelg%sai*rad_params%om_stem(ib,ft))/(scelg%lai+scelg%sai) + + ! Eq. 3.7 CLM50 Tech Man + betab_om = betab_veg*om_veg*(1._r8-this%frac_snow) + & + om_snow(ib)*betab_snow(ib)*this%frac_snow + + scelb%betab = betab_om / scelb%om + + if(debug)then + if( .not.(scelb%betab==scelb%betab))then + write(log_unit,*)"Beam backscatter fraction is NaN" + write(log_unit,*) betab_om,scelb%om,om_veg,this%frac_snow,betab_veg,asu,rad_params%avmu(ft),scelg%Kb + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + end if + + end if + + end associate + end do do_ib + end associate + end do do_ical + end do do_ican + + return + end subroutine ZenithPrep + + ! ================================================================================================ + + subroutine GetNSCel(this) + + ! Simply return the total number + ! of scattering elements from the + ! multi-layer scattering element array + + class(twostream_type) :: this + integer :: ican + + this%n_scel = 0 + do ican = 1,this%n_lyr + this%n_scel = this%n_scel + this%n_col(ican) + end do + return + end subroutine GetNSCel + + ! =============================================================== + + subroutine Solve(this, ib, & + upper_boundary_type, & + Rbeam_atm, & + Rdiff_atm, & + taulamb, & + omega, & + ipiv, & + albedo_beam, & + albedo_diff, & + consv_err, & + frac_abs_can_beam, & + frac_abs_can_diff, & + frac_beam_grnd_beam, & + frac_diff_grnd_beam, & + frac_diff_grnd_diff) + + ! Find the scattering coefficients for two-stream radiation in the canopy. + + ! Note that these scattering coefficients are separated for scattering + ! generated by a beam radiation boundary condition, and a diffuse radiation + ! boundary conditions. Thus, we need not provide the magnitude of the forcing + ! for this step. If the user provides values of 1 for the Rbeam_atm and Rdiff_atm + ! boundary condition. It is assumed this is a normalized solution. If values + ! other than 1 are passed, we assume that it is not a normalized solution, + ! and we update the data structure values this%band(ib)%Rbeam_atm and + ! this%band(ib)%Rdiff_atm. In a normalized solution, we will leave this + ! as unset. + ! In ELM and CLM, the land-model requests an albedo and other + ! normalized output from from this algorithm for the NEXT STEP. This is + ! due to the atmospheric model needing an albedo to calculate the downwelling + ! radiation on the next step. THus, the asynchronous nature of things. That is + ! why we allow a normalized solution here. When actual absorption or flux values are + ! desired, the scattering coefficients that were determined during the normalized + ! solution are still valid when the magnitude of the downwelling beam and diffuse + ! radiation boundary conditions to the vegetation canopy are known. + + + class(twostream_type) :: this + integer :: ib ! Band of interest, matches indexing of rad_params + integer :: upper_boundary_type ! Is this a normalized(1) or absolute(2) solution? + + real(r8) :: Rbeam_atm ! Intensity of beam radiation at top of canopy [W/m2 ground] + real(r8) :: Rdiff_atm ! Intensity of diffuse radiation at top of canopy [W/m2 ground] + ! + real(r8) :: taulamb(:) ! both the coefficient vector and constant side of the linear equation + real(r8) :: omega(:,:) ! the square matrix to be inverted + integer :: ipiv(:) ! pivot indices for LAPACK (not optional output, we don't use) + + real(r8) :: albedo_beam ! Mean albedo at canopy top generated from beam radiation [-] + real(r8) :: albedo_diff ! Mean albedo at canopy top generated from downwelling diffuse [-] + + real(r8) :: temp_err ! Used to build the other error terms, a temp + real(r8) :: consv_err ! radiation canopy balance conservation + ! error, fraction of incident + + real(r8) :: frac_abs_can_beam ! Fraction of incident beam radiation absorbed by the vegetation [-] + real(r8) :: frac_abs_can_diff ! Fraction of incident diffuse radiation absorbed by the vegetation [-] + real(r8) :: frac_beam_grnd_beam ! fraction of beam radiation at ground resulting from of beam at canopy top [-] + real(r8) :: frac_diff_grnd_beam ! fraction of down diffuse radiation at ground resulting from beam at canopy top + real(r8) :: frac_diff_grnd_diff ! fraction of down diffuse radiation at ground resulting from down diffuse at canopy top [-] + + ! These arrays are only used if we run in debug mode, and are + ! looking to report the error on the linear solution e = TAU - OMEGA*LAMBDA + real(r8),allocatable :: tau_temp(:) + real(r8),allocatable :: omega_temp(:,:) + + ! Two stream solution arrays + ! Each of these are given generic names, because + ! they are assemblages of many terms. But generally + ! they fit the linear algebra formulation: + ! + ! TAU(:) = OMEGA(:,:) * LAMBDA(:) + ! + ! Where, we invert to solve for the coefficients LAMBDA + + integer :: isol ! Solution index loop (beam, beam+diff) + integer :: ican ! Loop index for canopy layers + integer :: ibot ! layer index for top side of layer divide + integer :: itop ! layer index for bottom side of layer divide + integer :: icol ! Loop index for canopy columns + integer :: jcol ! Another loop index for canopy columns + integer :: ilem ! Index for scattering elements + integer :: k1,k2 ! Indices for the lambda terms in the OMEGA and LAMBDA array + integer :: qp ! Equation position index + integer :: n_eq ! Total number of equations + + integer :: ilem_off ! Offset, or total number of elements above layer of interest + real(r8) :: b1,b2,nu_sqrd ! intermediate terms, see documentation + real(r8) :: Rbeam_top ! Mean beam radiation at top of layer [W/m2] + real(r8) :: Rbeam_bot ! Mean beam radiation at bottom of layer [W/m2] + real(r8) :: vai ! Vegetation area index [m2 vegetation / m2 ground] + real(r8) :: rb_abs ! beam absorbed over an element [W/m2 ground] + real(r8) :: rd_abs ! diffuse absorbed over an element [W/m2 ground] + real(r8) :: rd_abs_leaf ! diffuse absorbed over leaves (dummy) + real(r8) :: rb_abs_leaf ! beam absorbed by leaves (dummy) + real(r8) :: r_abs_stem ! total absorbed by stems (dummy) + real(r8) :: r_abs_snow ! total absorbed by snow (dummy) + real(r8) :: leaf_sun_frac ! sunlit fraction of leaves (dummy) + + + real(r8) :: beam_err,diff_err ! error partitioned by beam and diffuse + type(scelg_type),pointer :: scelgp ! Pointer to the scelg data structure + type(scelb_type),pointer :: scelbp ! Pointer to the scelb data structure + + ! Parameters for solving via LAPACK DGESV() and DGESVXX() + integer :: info ! Procedure diagnostic ouput + + ! Testing switch + ! If true, then allow elements + ! of different layers, but same row, to have priority + ! flux into the other element, instead of a mix + logical, parameter :: continuity_on = .true. + + logical, parameter :: albedo_corr = .true. + + ! ------------------------------------------------------------------------------------ + ! Example system of equations for 2 parallel columns in each of two canopy + ! layers. Each line is one of the balanc equations. And the x's are + ! the unknown coefficients used in those equations. 2 coefficients + ! map to each element, and read left to right. + ! EL1 is the element in top layer left column. + ! EL2 is the element in the top layer, right column + ! EL3 is the element in the bottom layer, left column + ! EL4 is the element in the bottom layer, right column + ! + ! EL1 EL2 EL3 EL4 + ! EQ: Idn balance with upper BC can1, col 1: x x + ! EQ: Idn balance with upper BC can1, col 2: x x + ! EQ: Idn balance between upper & lower x x x x x x + ! EQ: Idn balance between upper & lower x x x x x x + ! EQ: Iup balance between lower & upper x x x x x x x x + ! EQ: Iup balance between lower & upper x x x x x x x x + ! EQ: Iup/Idn balance with ground, 1st col: x x + ! EQ: Iup/Idn Balance with ground, 2nd lower col: x x + ! + ! Note: The Iup balance between layers requires ALL + ! terms, because light comes out of both + ! upper canopy elements and reflects off soil + ! AND, light upwells from both lower elements. + ! + ! -------------------------------------------------------------------------- + + ! -------------------------------------------------------------------------- + ! Beam Scattering + ! First do the direct beam stuff. It is a trivial solution + ! and is required as a boundary condition to the diffuse solver + ! All parallel layers recieve downwelling form the + ! atmosphere. + ! Rbeam0 is the upper boundary condition provided by data or another + ! model. + ! Rbeam() is the incident beam radiation at the top of each layer + ! upper canopy. + ! -------------------------------------------------------------------------- + + if((Rbeam_atm+Rdiff_atm) this%scelg(ican,icol) + scelbp => this%band(ib)%scelb(ican,icol) + scelbp%Rbeam0 = Rbeam_top + Rbeam_bot = Rbeam_bot + & + Rbeam_top*scelgp%area*exp(-scelgp%Kb*(scelgp%lai+scelgp%sai)) + end do + Rbeam_top = Rbeam_bot + end do + + ! Calculate element-level intermediate terms to the solve + ! These are dependent on leaf level scattering and beam scattering + ! These values will be used to populate the matrix solve + ! ===================================================================== + + do ican = 1,this%n_lyr + do icol = 1,this%n_col(ican) + + scelgp => this%scelg(ican,icol) + scelbp => this%band(ib)%scelb(ican,icol) + + b2 = -(scelgp%Kd*(1._r8-scelbp%om)*(1._r8-2._r8*scelbp%betab)+scelgp%Kb) * & + scelbp%om*scelgp%Kb*scelbp%Rbeam0 + + b1 = -(scelgp%Kd*(1._r8-scelbp%om+2._r8*scelbp%om*scelbp%betad) + & + (1._r8-2._r8*scelbp%betab)*scelgp%Kb) * & + scelbp%om*scelgp%Kb*scelbp%Rbeam0 + + nu_sqrd = (1._r8-scelbp%om)/(1._r8-scelbp%om+2._r8*scelbp%om*scelbp%betad) + + if(nu_sqrd<0._r8)then + write(log_unit,*)'nu_sqrd is less than zero' + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + + ! B_1 term from documentation: + scelbp%B1 = 0.5_r8*(1._r8+sqrt(nu_sqrd)) + + ! B_2 term from documentation + scelbp%B2 = 0.5_r8*(1._r8-sqrt(nu_sqrd)) + + ! A_2 term from documentation + scelbp%Ad = -0.5_r8*(b1+b2)/(scelbp%a*scelbp%a-scelgp%Kb*scelgp%Kb) ! aka half b2 minus b1 + + ! A_1 term from documentation + scelbp%Au = -0.5_r8*(b1-b2)/(scelbp%a*scelbp%a-scelgp%Kb*scelgp%Kb) ! aka half b1 plus b2 + + end do + end do + + ! ===================================================================== + ! Set up the linear systems solver + ! + ! [TAU] = [OMEGA]*[LAMBDA] + ! OMEGA(n_equations,n_coefficients) + ! TAU(n_equations) + ! LAMBDA (n_coefficients) (the solution) + ! + ! Indexing Variables + ! ilem : element position + ! k1 : coefficient 1 position + ! k2 : coefficient 2 position + ! qp : equation position, this continues to increment + ! ===================================================================== + + n_eq = 2*this%n_scel + + ! TO-DO: MAKE THIS SCRATCH SPACE AT THE SITE LEVEL? + !!allocate(OMEGA(2*this%n_scel,2*this%n_scel),stat=alloc_err) + !!allocate(TAU(2*this%n_scel),stat=alloc_err) + !!allocate(LAMBDA(2*this%n_scel),stat=alloc_err) + + ! We come up with two solutions: + ! First: we run with now diffuse downwelling + ! radiation, this allows us to calculate + ! the canopy top albedo for beam radiation only + ! which is useful for coupling with the atmosphere + ! Second: we run with bot simultaneously, and + ! use that solution to understand everything + ! else, including the absorbed radiation + + do_isol: do isol = 1,2 + + + ! This is temporary (these need to be set + ! because this routine makes a call to get normalized + ! absorbtions to get total noramalized canopy absorbtion) + ! We will set it back to unknown following that call + + if(isol==1)then + this%band(ib)%Rbeam_atm = 1.0_r8 + this%band(ib)%Rdiff_atm = 0.0_r8 + else + this%band(ib)%Rbeam_atm = 0.0_r8 + this%band(ib)%Rdiff_atm = 1.0_r8 + end if + + omega(1:n_eq,1:n_eq) = 0._r8 + taulamb(1:n_eq) = 0._r8 + + ! -------------------------------------------------------------------- + ! I. Flux equations with the atmospheric boundary + ! These balance with all elements in the upper + ! canopy, only. The upper canopy is layer 1. + ! -------------------------------------------------------------------- + + qp = 0 ! e"Q"uation "P"osition + do icol = 1,this%n_col(1) + scelgp => this%scelg(1,icol) + scelbp => this%band(ib)%scelb(1,icol) + ilem = icol + qp = qp + 1 + k1 = 2*(ilem-1)+1 + k2 = k1+1 + taulamb(qp) = this%band(ib)%Rdiff_atm - this%band(ib)%Rbeam_atm*scelbp%Ad + omega(qp,k1) = scelbp%B2 + omega(qp,k2) = scelbp%B1 + end do + + + if_understory: if(this%n_lyr>1) then + + + ! ------------------------------------------------------------------- + ! II. Flux equations between canopy layers, DOWNWELLING + ! We only perform flux balancing between layers + ! if we have any understory, this is true if ican>1 + ! ------------------------------------------------------------------- + ! Refer to Equation X in technical document + ! ------------------------------------------------------------ + + ! This is the index offset for the layer above the + ! current layer of interest. We start by evaluating + ! Layer 2, so the offset refers to layer 1, and a + ! value of 0 + + ilem_off = 0 + do_dn_ican: do ican = 2,this%n_lyr + + itop = ican-1 ! Top layer of the balance + ibot = ican ! Bottom layer of the balance + + ! Downwelling, includes all members from top for + ! each independant member below + + do jcol = 1,this%n_col(ibot) + + qp = qp + 1 + ilem = ilem_off + this%n_col(itop) + jcol + k1 = 2*(ilem-1)+1 + k2 = k1 + 1 + + ! Include the self terms for the current element + ! This term is at v=0 + + taulamb(qp) = this%band(ib)%Rbeam_atm*this%band(ib)%scelb(ibot,jcol)%Ad + omega(qp,k1) = omega(qp,k1) - this%band(ib)%scelb(ibot,jcol)%B2 + omega(qp,k2) = omega(qp,k2) - this%band(ib)%scelb(ibot,jcol)%B1 + + ! We need to include the terms from + ! all elements above the current element of interest + ! (this can be moved out of jcol loop for efficiency) + do icol = 1,this%n_col(itop) + + ilem = ilem_off + icol + k1 = 2*(ilem-1)+1 + k2 = k1 + 1 + + scelgp => this%scelg(itop,icol) + scelbp => this%band(ib)%scelb(itop,icol) + + vai = scelgp%lai + scelgp%sai + + taulamb(qp) = taulamb(qp) - scelgp%area * this%band(ib)%Rbeam_atm*scelbp%Ad *exp(-scelgp%Kb*vai) + omega(qp,k1) = omega(qp,k1) + scelgp%area * scelbp%B2*exp(scelbp%a*vai) + omega(qp,k2) = omega(qp,k2) + scelgp%area * scelbp%B1*exp(-scelbp%a*vai) + + end do + + end do + + ilem_off = ilem_off + this%n_col(itop) + + end do do_dn_ican + + + ! ------------------------------------------------------------------- + ! III. Flux equations between canopy layers, UPWELLING + ! ------------------------------------------------------------------- + ! Refer to equation X in the technical documentation. + ! Note the upwelling balance is performed on the upper layer, + ! one equation for each element in the upper layer. + ! Note that since we use "ghost elements" or air elements + ! we don't have to factor in reflections from exposed ground. + ! These effects will be mediated through the ghost elements + ! ------------------------------------------------------------------- + + ilem_off = 0 + + do_up_ican: do ican = 2,this%n_lyr + + itop = ican-1 + ibot = ican + + do icol = 1,this%n_col(itop) + + qp = qp + 1 + + ! Self terms (ie the upwelling evaluated at the bottom edge of each top element) + ilem = ilem_off + icol + k1 = 2*(ilem-1)+1 + k2 = k1 + 1 + scelgp => this%scelg(itop,icol) + scelbp => this%band(ib)%scelb(itop,icol) + + vai = scelgp%lai + scelgp%sai + taulamb(qp) = this%band(ib)%Rbeam_atm*scelbp%Au*exp(-scelgp%Kb*vai) + omega(qp,k1) = omega(qp,k1) - scelbp%B1*exp(scelbp%a*vai) + omega(qp,k2) = omega(qp,k2) - scelbp%B2*exp(-scelbp%a*vai) + + ! Terms for mean diffuse exiting lower elements (move out of this loop for efficiency) + do jcol = 1,this%n_col(ibot) + ilem = ilem_off + this%n_col(itop) + jcol + k1 = 2*(ilem-1)+1 + k2 = k1 + 1 + scelgp => this%scelg(ibot,jcol) + scelbp => this%band(ib)%scelb(ibot,jcol) + + taulamb(qp) = taulamb(qp) - this%band(ib)%Rbeam_atm*scelgp%area*scelbp%Au + omega(qp,k1) = omega(qp,k1) + scelgp%area*scelbp%B1 + omega(qp,k2) = omega(qp,k2) + scelgp%area*scelbp%B2 + end do + + end do + + ilem_off = ilem_off + this%n_col(itop) + end do do_up_ican + + + end if if_understory + + + ! Flux balance equations between the understory elements, and + ! the ground below them + ilem_off = 0 + do ican=1,this%n_lyr-1 + ilem_off = ilem_off + this%n_col(ican) + end do + + do jcol = 1,this%n_col(this%n_lyr) + + ilem = ilem_off + jcol + qp = qp + 1 + k1 = 2*(ilem-1)+1 + k2 = k1 + 1 + + scelgp => this%scelg(this%n_lyr,jcol) + scelbp => this%band(ib)%scelb(this%n_lyr,jcol) + + vai = scelgp%lai + scelgp%sai + + taulamb(qp) = this%band(ib)%Rbeam_atm*(scelbp%Au*exp(-scelgp%Kb*vai) & + - this%band(ib)%albedo_grnd_diff*scelbp%Ad*exp(-scelgp%Kb*vai) & + - this%band(ib)%albedo_grnd_beam*scelbp%Rbeam0*exp(-scelgp%Kb*vai)) + + omega(qp,k1) = omega(qp,k1) - scelbp%B1*exp(scelbp%a*vai) + omega(qp,k2) = omega(qp,k2) - scelbp%B2*exp(-scelbp%a*vai) + + omega(qp,k1) = omega(qp,k1) + this%band(ib)%albedo_grnd_diff*scelbp%B2*exp(scelbp%a*vai) + omega(qp,k2) = omega(qp,k2) + this%band(ib)%albedo_grnd_diff*scelbp%B1*exp(-scelbp%a*vai) + + end do + + ! dgesv will overwrite TAU with LAMBDA + ! ie, left side of TAU = OMEGA*LAMBDA + ! lets dave it temporarily + + if(debug)then + allocate(tau_temp(n_eq),omega_temp(n_eq,n_eq)) + tau_temp(1:n_eq) = taulamb(1:n_eq) + omega_temp(1:n_eq,1:n_eq) = omega(1:n_eq,1:n_eq) + end if + + ! the desired precision of the iterative algorithm is: + ! RNRM < SQRT(N)*XNRM*ANRM*EPS + ! eps is the machine precision of the real number type + ! ANRM is the "infinity-norm", ie the infinity norm is the abs() maximum row sum + ! XNRM is the abs() maximum value in that column + + ! Find the solution + call dgesv(n_eq, 1, omega(1:n_eq,1:n_eq), n_eq, ipiv(1:n_eq), taulamb(1:n_eq), n_eq, info) + + if(info.ne.0)then + write(log_unit,*) 'Could not find a solution via dgesv' + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + + ! Perform a forward check on the solution error + do ilem = 1,n_eq + temp_err = tau_temp(ilem) - sum(taulamb(1:n_eq)*omega_temp(ilem,1:n_eq)) + if(abs(temp_err)>rel_err_thresh)then + write(log_unit,*) 'Poor forward solution on two-stream solver' + write(log_unit,*) 'isol (1=beam or 2=diff): ',isol + write(log_unit,*) 'i (equation): ',ilem + write(log_unit,*) 'band index (1=vis,2=nir): ',ib + write(log_unit,*) 'error (tau(i) - omega(i,:)*lambda(:)) ',temp_err + this%band(ib)%Rbeam_atm = 1._r8 + this%band(ib)%Rdiff_atm = 1._r8 + call this%Dump(ib) + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + end do + deallocate(tau_temp,omega_temp) + + + ! Save the solution terms + + ilem_off = 0 + if(isol==1)then !Beam + do ican = 1,this%n_lyr + do icol = 1,this%n_col(ican) + ilem = ilem_off + icol + k1 = 2*(ilem-1)+1 + k2 = k1 + 1 + scelgp => this%scelg(ican,icol) + scelbp => this%band(ib)%scelb(ican,icol) + scelbp%lambda1_beam = taulamb(k1) + scelbp%lambda2_beam = taulamb(k2) + ! The lambda diff terms will be + ! multiplied by zero before we use them + ! but, we dont want things like nan's + ! or weird math, so we set them to zero too + scelbp%lambda1_diff = 0._r8 + scelbp%lambda2_diff = 0._r8 + end do + ilem_off = ilem_off + this%n_col(ican) + end do + else + do ican = 1,this%n_lyr + do icol = 1,this%n_col(ican) + ilem = ilem_off + icol + k1 = 2*(ilem-1)+1 + k2 = k1 + 1 + scelgp => this%scelg(ican,icol) + scelbp => this%band(ib)%scelb(ican,icol) + scelbp%lambda1_diff = taulamb(k1) + scelbp%lambda2_diff = taulamb(k2) + end do + ilem_off = ilem_off + this%n_col(ican) + end do + end if + + ! Process the total canopy absorbed radiation in the + ! two types of radiation, as well as the downwelling + ! flux at the ground interface + ! -------------------------------------------------------------------------------- + + if_beam: if(isol==1)then + + ican = 1 + albedo_beam = 0._r8 + do icol = 1,this%n_col(ican) + scelgp => this%scelg(ican,icol) + scelbp => this%band(ib)%scelb(ican,icol) + albedo_beam = albedo_beam + & + scelgp%area * this%GetRdUp(ican,icol,ib,0._r8) + end do + + frac_diff_grnd_beam = 0._r8 + frac_beam_grnd_beam = 0._r8 + ican = this%n_lyr + do icol = 1,this%n_col(ican) + scelgp => this%scelg(ican,icol) + scelbp => this%band(ib)%scelb(ican,icol) + frac_diff_grnd_beam = frac_diff_grnd_beam + & + scelgp%area*this%GetRdDn(ican,icol,ib,scelgp%lai+scelgp%sai) + frac_beam_grnd_beam = frac_beam_grnd_beam + & + scelgp%area*scelbp%Rbeam0*exp(-scelgp%Kb*(scelgp%lai+scelgp%sai)) + end do + + + frac_abs_can_beam = 0._r8 + do ican = 1,this%n_lyr + do icol = 1,this%n_col(ican) + scelgp => this%scelg(ican,icol) + scelbp => this%band(ib)%scelb(ican,icol) + call this%GetAbsRad(ican,icol,ib, 0._r8,scelgp%lai+scelgp%sai, & + rb_abs,rd_abs,rd_abs_leaf,rb_abs_leaf,r_abs_stem,r_abs_snow,leaf_sun_frac) + frac_abs_can_beam = frac_abs_can_beam + scelgp%area*(rb_abs+rd_abs) + end do + end do + + else ! Diffuse + + albedo_diff = 0._r8 + do icol = 1,this%n_col(1) + scelgp => this%scelg(1,icol) + scelbp => this%band(ib)%scelb(1,icol) + albedo_diff = albedo_diff + & + scelgp%area * this%GetRdUp(1,icol,ib,0._r8) + end do + + frac_abs_can_diff = 0._r8 + + do ican = 1,this%n_lyr + do icol = 1,this%n_col(ican) + scelgp => this%scelg(ican,icol) + scelbp => this%band(ib)%scelb(ican,icol) + call this%GetAbsRad(ican,icol,ib,0._r8,scelgp%lai+scelgp%sai, & + rb_abs,rd_abs,rd_abs_leaf,rb_abs_leaf,r_abs_stem,r_abs_snow,leaf_sun_frac) + frac_abs_can_diff = frac_abs_can_diff + scelgp%area*rd_abs + end do + end do + + frac_diff_grnd_diff = 0._r8 + ican = this%n_lyr + do icol = 1,this%n_col(ican) + scelgp => this%scelg(ican,icol) + scelbp => this%band(ib)%scelb(ican,icol) + frac_diff_grnd_diff = frac_diff_grnd_diff + & + scelgp%area*this%GetRdDn(ican,icol,ib,scelgp%lai+scelgp%sai) + end do + + end if if_beam + + end do do_isol + + + ! Check the error balance + ! --------------------------------------------------------------------------------------------- + + ! Source = upwelling + canopy absorbed + ground absorbed + + consv_err = ((Rbeam_atm + Rdiff_atm) - & + (albedo_diff + albedo_beam ) - & + (frac_abs_can_diff + frac_abs_can_beam) - & + ((frac_diff_grnd_diff+frac_diff_grnd_beam)*(1._r8-this%band(ib)%albedo_grnd_diff)) - & + (frac_beam_grnd_beam*(1._r8-this%band(ib)%albedo_grnd_beam)) ) / (Rbeam_atm + Rdiff_atm) + + ! This is an error magnitude, not a bias + consv_err = abs(consv_err) + + beam_err = Rbeam_atm - (albedo_beam + frac_abs_can_beam + & + frac_diff_grnd_beam*(1._r8-this%band(ib)%albedo_grnd_diff) + & + frac_beam_grnd_beam*(1._r8-this%band(ib)%albedo_grnd_beam)) + + diff_err = Rdiff_atm - (albedo_diff + frac_abs_can_diff + & + frac_diff_grnd_diff*(1._r8-this%band(ib)%albedo_grnd_diff)) + + if( consv_err > rel_err_thresh ) then + write(log_unit,*)"Total canopy flux balance not closing in TwoStrteamMLPEMod:Solve" + write(log_unit,*)"Relative Error, delta/(Rbeam_atm+Rdiff_atm) :",consv_err + write(log_unit,*)"Max Error: ",rel_err_thresh + write(log_unit,*)"ib: ",ib + write(log_unit,*)"scattering coeff: ",(2*rad_params%om_leaf(ib,1)+0.5*rad_params%om_stem(ib,1))/2.5 + write(log_unit,*)"Breakdown:",this%n_lyr + do ican = 1,this%n_lyr + do icol = 1,this%n_col(ican) + scelgp => this%scelg(ican,icol) + scelbp => this%band(ib)%scelb(ican,icol) + write(log_unit,*)" ",ican,icol + write(log_unit,*)" ",scelgp%lai+scelgp%sai,scelgp%pft,scelgp%area + write(log_unit,*)" ",scelbp%om,scelgp%Kb,scelgp%Kd,scelbp%betab,scelbp%betad + write(log_unit,*)" ",scelbp%om*(1.0-scelbp%betad) + write(log_unit,*)" ",scelbp%lambda1_beam,scelbp%lambda2_beam + write(log_unit,*)" ",scelbp%lambda1_diff,scelbp%lambda2_diff + write(log_unit,*)"AB TERMS: ",scelbp%Ad,scelbp%Au,scelbp%B1,scelbp%B2,scelbp%a + write(log_unit,*)"LAMBDA TERMS: ",scelbp%lambda1_diff,scelbp%lambda2_diff,scelbp%lambda1_beam,scelbp%lambda2_beam + end do + end do + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + + ! Re-cast the abledos so they are direct result of the components. + ! CESM and E3SM have higher tolerances. We close to 1e-6 but they + ! close to 1e-8, which is just very difficult when the canopies + ! get complex + if(albedo_corr)then + + albedo_beam = Rbeam_atm - (frac_abs_can_beam + & + frac_diff_grnd_beam*(1._r8-this%band(ib)%albedo_grnd_diff) + & + frac_beam_grnd_beam*(1._r8-this%band(ib)%albedo_grnd_beam)) + + albedo_diff = Rdiff_atm - (frac_abs_can_diff + & + frac_diff_grnd_diff*(1._r8-this%band(ib)%albedo_grnd_diff)) + + end if + + ! Set the boundary conditions back to unknown for a normalized solution + ! This prevents us from calling the absorption and flux query routines incorrectly. + ! For non-normalized, set it to the actual input boundary conditions + + if(upper_boundary_type.eq.normalized_upper_boundary) then + this%band(ib)%Rbeam_atm = unset_r8 + this%band(ib)%Rdiff_atm = unset_r8 + else + this%band(ib)%Rbeam_atm = Rbeam_atm + this%band(ib)%Rdiff_atm = Rdiff_atm + end if + + + return + end subroutine Solve + + +end Module TwoStreamMLPEMod diff --git a/testing/CMakeLists.txt b/testing/CMakeLists.txt new file mode 100644 index 0000000000..d59509c73d --- /dev/null +++ b/testing/CMakeLists.txt @@ -0,0 +1,8 @@ +# This is where you add specific test directories + +## Functional tests +add_subdirectory(functional_testing/allometry fates_allom_ftest) +add_subdirectory(functional_testing/math_utils fates_math_ftest) + +## Unit tests +add_subdirectory(unit_testing/fire_weather_test fates_fire_weather_utest) \ No newline at end of file diff --git a/testing/build_fortran_tests.py b/testing/build_fortran_tests.py new file mode 100644 index 0000000000..b495f25020 --- /dev/null +++ b/testing/build_fortran_tests.py @@ -0,0 +1,249 @@ +""" +Builds/compiles any tests within the FATES repository +""" +import os +import shutil +from utils import add_cime_lib_to_path + +add_cime_lib_to_path() + +from CIME.utils import get_src_root, run_cmd_no_fail, expect, stringify_bool # pylint: disable=wrong-import-position,import-error,wrong-import-order +from CIME.build import CmakeTmpBuildDir # pylint: disable=wrong-import-position,import-error,wrong-import-order +from CIME.XML.machines import Machines # pylint: disable=wrong-import-position,import-error,wrong-import-order +from CIME.BuildTools.configure import configure, FakeCase # pylint: disable=wrong-import-position,import-error,wrong-import-order +from CIME.XML.env_mach_specific import EnvMachSpecific # pylint: disable=wrong-import-position,import-error,wrong-import-order + +_CIMEROOT = os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../../cime") + +def run_cmake(test_name, test_dir, pfunit_path, netcdf_c_path, netcdf_f_path, cmake_args): + """Run cmake for the fortran unit tests + Arguments: + test_name (str) - name for output messages + test_dir (str) - directory to run Cmake in + pfunit_path (str) - path to pfunit + netcdf_c_path (str) - path to netcdf + netcdf_f_path (str) - path to netcdff + clean (bool) - clean the build + """ + if not os.path.isfile("CMakeCache.txt"): + print(f"Running cmake for {test_name}.") + + # directory with cmake modules + cmake_module_dir = os.path.abspath(os.path.join(_CIMEROOT, "CIME", "non_py", + "src", "CMake")) + + # directory with genf90 + genf90_dir = os.path.join(_CIMEROOT, "CIME", "non_py", "externals", "genf90") + + cmake_command = [ + "cmake", + "-C Macros.cmake", + test_dir, + f"-DCIMEROOT={_CIMEROOT}", + f"-DSRC_ROOT={get_src_root()}", + f"-DCIME_CMAKE_MODULE_DIRECTORY={cmake_module_dir}", + "-DCMAKE_BUILD_TYPE=CESM_DEBUG", + f"-DCMAKE_PREFIX_PATH={pfunit_path}", + "-DUSE_MPI_SERIAL=ON", + "-DENABLE_GENF90=ON", + f"-DCMAKE_PROGRAM_PATH={genf90_dir}" + ] + + if netcdf_c_path is not None: + cmake_command.append(f"-DNETCDF_C_PATH={netcdf_c_path}") + + if netcdf_f_path is not None: + cmake_command.append(f"-DNETCDF_F_PATH={netcdf_f_path}") + + cmake_command.extend(cmake_args.split(" ")) + + run_cmd_no_fail(" ".join(cmake_command), combine_output=True) + +def find_library(caseroot, cmake_args, lib_string): + """Find the library installation we'll be using, and print its path + + Args: + caseroot (str): Directory with pfunit macros + cmake_args (str): The cmake args used to invoke cmake + (so that we get the correct makefile vars) + """ + with CmakeTmpBuildDir(macroloc=caseroot) as cmaketmp: + all_vars = cmaketmp.get_makefile_vars(cmake_args=cmake_args) + + all_vars_list = all_vars.splitlines() + for all_var in all_vars_list: + if ":=" in all_var: + expect(all_var.count(":=") == 1, f"Bad makefile: {all_var}") + varname, value = [item.strip() for item in all_var.split(":=")] + if varname == lib_string: + return value + + expect(False, f"{lib_string} not found for this machine and compiler") + + return None + +def prep_build_dir(build_dir, clean): + """Create (if necessary) build directory and clean contents (if asked to) + + Args: + build_dir (str): build directory name + clean (bool): whether or not to clean contents + """ + + # create the build directory + build_dir_path = os.path.abspath(build_dir) + if not os.path.isdir(build_dir_path): + os.mkdir(build_dir_path) + + # change into that directory + os.chdir(build_dir_path) + + # clean up any files if we want to + if clean: + clean_cmake_files() + + return build_dir_path + +def clean_cmake_files(): + """Deletes all files related to build + + """ + if os.path.isfile("CMakeCache.txt"): + os.remove("CMakeCache.txt") + if os.path.isdir("CMakeFiles"): + shutil.rmtree("CMakeFiles") + + cwd_contents = os.listdir(os.getcwd()) + + # Clear contents to do with cmake cache + for file in cwd_contents: + if ( + file in ("Macros.cmake", "env_mach_specific.xml") + or file.startswith("Depends") + or file.startswith(".env_mach_specific") + ): + os.remove(file) + +def get_extra_cmake_args(build_dir, mpilib): + """Makes a fake case to grab the required cmake arguments + Args: + build_dir (str): build directory name + mpilib (str): MPI library name + """ + # get the machine objects file + machobj = Machines() # this is different? + + # get compiler + compiler = machobj.get_default_compiler() + + # get operating system + os_ = machobj.get_value("OS") + + # Create the environment, and the Macros.cmake file + # + # + configure( + machobj, + build_dir, + ["CMake"], + compiler, + mpilib, + True, + "nuopc", + os_, + unit_testing=True, + ) + machspecific = EnvMachSpecific(build_dir, unit_testing=True) + + # make a fake case + fake_case = FakeCase(compiler, mpilib, True, "nuopc", threading=False) + machspecific.load_env(fake_case) + cmake_args_list = [ + f"-DOS={os_}", + f"-DMACH={machobj.get_machine_name()}", + f"-DCOMPILER={compiler}", + f"-DDEBUG={stringify_bool(True)}", + f"-DMPILIB={mpilib}", + f"-Dcompile_threaded={stringify_bool(False)}", + f"-DCASEROOT={build_dir}" + ] + + cmake_args = " ".join(cmake_args_list) + + return cmake_args + +def run_make(name, make_j, clean=False, verbose=False): + """Run make in current working directory + + Args: + name (str): Name for output messages + make_j (int): number of processes to use for make + clean (bool, optional): whether or not to clean Defaults to False. + verbose (bool, optional): verbose error logging for make Defaults to False. + """ + + print(f"Running make for {name}.") + + if clean: + run_cmd_no_fail("make clean") + + make_command = ["make", "-j", str(make_j)] + + if verbose: + make_command.append("VERBOSE=1") + + run_cmd_no_fail(" ".join(make_command), combine_output=True) + +def build_exists(build_dir, test_dir, test_exe=None): + """Checks to see if the build directory and associated executables exist. + + Args: + build_dir (str): build directory + test_dir (str): test directory + test_exe (str): test executable + """ + + build_path = os.path.abspath(build_dir) + if not os.path.isdir(build_path): + return False + + if not os.path.isdir(os.path.join(build_path, test_dir)): + return False + + if test_exe is not None: + if not os.path.isfile(os.path.join(build_path, test_dir, test_exe)): + return False + + return True + +def build_unit_tests(build_dir, name, cmake_directory, make_j, clean=False, verbose=False): + """Build the unit test executables + + Args: + build_dir (str): build directory + name (str): name for set of tests + cmake_directory (str): directory where the make CMakeLists.txt file is + make_j (int): number of processes to use for make + clean (bool, optional): whether or not to clean the build first. Defaults to False. + verbose (bool, optional): whether or not to run make with verbose output. Defaults to False. + """ + # create the build directory + full_build_path = prep_build_dir(build_dir, clean=clean) + + # get cmake args and the pfunit and netcdf paths + cmake_args = get_extra_cmake_args(full_build_path, "mpi-serial") + pfunit_path = find_library(full_build_path, cmake_args, "PFUNIT_PATH") + + if not "NETCDF" in os.environ: + netcdf_c_path = find_library(full_build_path, cmake_args, "NETCDF_C_PATH") + netcdf_f_path = find_library(full_build_path, cmake_args, "NETCDF_FORTRAN_PATH") + else: + netcdf_c_path = None + netcdf_f_path = None + + # change into the build dir + os.chdir(full_build_path) + + # run cmake and make + run_cmake(name, cmake_directory, pfunit_path, netcdf_c_path, netcdf_f_path, cmake_args) + run_make(name, make_j, clean=clean, verbose=verbose) diff --git a/testing/functional_testing/allometry/CMakeLists.txt b/testing/functional_testing/allometry/CMakeLists.txt new file mode 100644 index 0000000000..c2c453e93a --- /dev/null +++ b/testing/functional_testing/allometry/CMakeLists.txt @@ -0,0 +1,24 @@ +set(allom_sources FatesTestAllometry.F90) + +set(NETCDF_C_DIR ${NETCDF_C_PATH}) +set(NETCDF_FORTRAN_DIR ${NETCDF_F_PATH}) + +FIND_PATH(NETCDFC_FOUND libnetcdf.a ${NETCDF_C_DIR}/lib) +FIND_PATH(NETCDFF_FOUND libnetcdff.a ${NETCDF_FORTRAN_DIR}/lib) + + +include_directories(${NETCDF_C_DIR}/include + ${NETCDF_FORTRAN_DIR}/include) + +link_directories(${NETCDF_C_DIR}/lib + ${NETCDF_FORTRAN_DIR}/lib + ${PFUNIT_TOP_DIR}/lib) + +add_executable(FATES_allom_exe ${allom_sources}) + +target_link_libraries(FATES_allom_exe + netcdf + netcdff + fates + csm_share + funit) \ No newline at end of file diff --git a/testing/functional_testing/allometry/FatesTestAllometry.F90 b/testing/functional_testing/allometry/FatesTestAllometry.F90 new file mode 100644 index 0000000000..91ee4df2cf --- /dev/null +++ b/testing/functional_testing/allometry/FatesTestAllometry.F90 @@ -0,0 +1,313 @@ +program FatesTestAllometry + + use FatesConstantsMod, only : r8 => fates_r8 + use FatesAllometryMod, only : h_allom, bagw_allom, blmax_allom + use FatesAllometryMod, only : carea_allom, bsap_allom, bbgw_allom + use FatesAllometryMod, only : bfineroot, bstore_allom, bdead_allom + use PRTParametersMod, only : prt_params + use FatesUnitTestParamReaderMod, only : fates_unit_test_param_reader + + implicit none + + ! LOCALS: + type(fates_unit_test_param_reader) :: param_reader ! param reader instance + character(len=:), allocatable :: param_file ! input parameter file + integer :: numpft ! number of pfts (from parameter file) + integer :: arglen ! length of command line argument + integer :: i, j ! looping indices + integer :: numdbh ! size of dbh array + integer :: nargs ! number of command line arguments + real(r8), allocatable :: dbh(:) ! diameter at breast height [cm] + real(r8), allocatable :: height(:, :) ! height [m] + real(r8), allocatable :: bagw(:, :) ! aboveground woody biomass [kgC] + real(r8), allocatable :: blmax(:, :) ! plant leaf biomass [kgC] + real(r8), allocatable :: crown_area(:, :) ! crown area per cohort [m2] + real(r8), allocatable :: sapwood_area(:, :) ! cross sectional area of sapwood at reference height [m2] + real(r8), allocatable :: bsap(:, :) ! sapwood biomass [kgC] + real(r8), allocatable :: bbgw(:, :) ! belowground woody biomass [kgC] + real(r8), allocatable :: fineroot_biomass(:, :) ! belowground fineroot biomass [kgC] + real(r8), allocatable :: bstore(:, :) ! allometric target storage biomass [kgC] + real(r8), allocatable :: bdead(:, :) ! structural biomass (heartwood/struct) [kgC] + real(r8), allocatable :: total_biom_tissues(:,:) ! total biomass calculated as bleaf + bfineroot + bdead + bsap [kgC] + real(r8), allocatable :: total_biom_parts(:,:) ! total biomass calculated as bleaf + bfineroot + agbw + bgbw [kgC] + + ! CONSTANTS: + character(len=*), parameter :: out_file = 'allometry_out.nc' ! output file + real(r8), parameter :: min_dbh = 0.5_r8 ! minimum DBH to calculate [cm] + real(r8), parameter :: max_dbh = 200.0_r8 ! maximum DBH to calculate [cm] + real(r8), parameter :: dbh_inc = 0.5_r8 ! DBH increment to use [cm] + + integer, parameter :: crown_damage = 1 ! crown damage + real(r8), parameter :: elongation_factor = 1.0_r8 ! elongation factor for stem + real(r8), parameter :: elongation_factor_roots = 1.0_r8 ! elongation factor for roots + real(r8), parameter :: site_spread = 1.0_r8 ! site spread + real(r8), parameter :: canopy_trim = 1.0_r8 ! canopy trim + real(r8), parameter :: nplant = 1.0_r8 ! number of plants per cohort + real(r8), parameter :: leaf_to_fineroot = 1.0_r8 ! leaf to fineroot ratio + + interface + + subroutine WriteAllometryData(out_file, ndbh, numpft, dbh, height, bagw, blmax, & + crown_area, sapwood_area, bsap, bbgw, fineroot_biomass, bstore, bdead, & + total_biom_parts, total_biom_tissues) + + use FatesUnitTestIOMod, only : OpenNCFile, RegisterNCDims, CloseNCFile + use FatesUnitTestIOMod, only : WriteVar, RegisterVar + use FatesUnitTestIOMod, only : type_double, type_int + use FatesConstantsMod, only : r8 => fates_r8 + implicit none + + character(len=*), intent(in) :: out_file + integer, intent(in) :: ndbh, numpft + real(r8), intent(in) :: dbh(:) + real(r8), intent(in) :: height(:,:) + real(r8), intent(in) :: bagw(:,:) + real(r8), intent(in) :: blmax(:, :) + real(r8), intent(in) :: crown_area(:, :) + real(r8), intent(in) :: sapwood_area(:, :) + real(r8), intent(in) :: bsap(:, :) + real(r8), intent(in) :: bbgw(:, :) + real(r8), intent(in) :: fineroot_biomass(:, :) + real(r8), intent(in) :: bstore(:, :) + real(r8), intent(in) :: bdead(:, :) + real(r8), intent(in) :: total_biom_parts(:, :) + real(r8), intent(in) :: total_biom_tissues(:, :) + end subroutine WriteAllometryData + + end interface + + ! get parameter file from command-line argument + nargs = command_argument_count() + if (nargs /= 1) then + write(*, '(a, i2, a)') "Incorrect number of arguments: ", nargs, ". Should be 1." + stop + else + call get_command_argument(1, length=arglen) + allocate(character(arglen) :: param_file) + call get_command_argument(1, value=param_file) + endif + + ! read in parameter file + call param_reader%Init(param_file) + call param_reader%RetrieveParameters() + + ! determine sizes of arrays + numpft = size(prt_params%wood_density, dim=1) + numdbh = int((max_dbh - min_dbh)/dbh_inc + 1) + + ! allocate arrays + allocate(dbh(numdbh)) + allocate(height(numdbh, numpft)) + allocate(bagw(numdbh, numpft)) + allocate(blmax(numdbh, numpft)) + allocate(crown_area(numdbh, numpft)) + allocate(sapwood_area(numdbh, numpft)) + allocate(bsap(numdbh, numpft)) + allocate(bbgw(numdbh, numpft)) + allocate(fineroot_biomass(numdbh, numpft)) + allocate(bstore(numdbh, numpft)) + allocate(bdead(numdbh, numpft)) + allocate(total_biom_parts(numdbh, numpft)) + allocate(total_biom_tissues(numdbh, numpft)) + + ! initialize dbh array + do i = 1, numdbh + dbh(i) = min_dbh + dbh_inc*(i-1) + end do + + ! calculate allometries + do i = 1, numpft + do j = 1, numdbh + call h_allom(dbh(j), i, height(j, i)) + call bagw_allom(dbh(j), i, crown_damage, elongation_factor, bagw(j, i)) + call blmax_allom(dbh(j), i, blmax(j, i)) + call carea_allom(dbh(j), nplant, site_spread, i, crown_damage, crown_area(j, i)) + call bsap_allom(dbh(j), i, crown_damage, canopy_trim, elongation_factor, & + sapwood_area(j, i), bsap(j, i)) + call bbgw_allom(dbh(j), i, elongation_factor, bbgw(j, i)) + call bfineroot(dbh(j), i, canopy_trim, leaf_to_fineroot, elongation_factor_roots, & + fineroot_biomass(j, i)) + call bstore_allom(dbh(j), i, crown_damage, canopy_trim, bstore(j, i)) + call bdead_allom(bagw(j, i), bbgw(j, i), bsap(j, i), i, bdead(j, i)) + total_biom_parts(j, i) = blmax(j, i) + fineroot_biomass(j, i) + bagw(j, i) + bbgw(j, i) + total_biom_tissues(j, i) = blmax(j, i) + fineroot_biomass(j, i) + bdead(j, i) + bsap(j, i) + end do + end do + + ! write out data to netcdf file + call WriteAllometryData(out_file, numdbh, numpft, dbh, height, bagw, blmax, crown_area, & + sapwood_area, bsap, bbgw, fineroot_biomass, bstore, bdead, total_biom_parts, & + total_biom_tissues) + +end program FatesTestAllometry + +! ---------------------------------------------------------------------------------------- + +subroutine WriteAllometryData(out_file, numdbh, numpft, dbh, height, bagw, blmax, & + crown_area, sapwood_area, bsap, bbgw, fineroot_biomass, bstore, bdead, total_biom_parts, & + total_biom_tissues) + ! + ! DESCRIPTION: + ! Writes out data from the allometry test + ! + use FatesConstantsMod, only : r8 => fates_r8 + use FatesUnitTestIOMod, only : OpenNCFile, RegisterNCDims, CloseNCFile + use FatesUnitTestIOMod, only : WriteVar + use FatesUnitTestIOMod, only : RegisterVar + use FatesUnitTestIOMod, only : EndNCDef + use FatesUnitTestIOMod, only : type_double, type_int + + implicit none + + ! ARGUMENTS: + character(len=*), intent(in) :: out_file ! output file name + integer, intent(in) :: numdbh ! size of dbh array + integer, intent(in) :: numpft ! number of pfts + real(r8), intent(in) :: dbh(:) ! diameter at breast height [cm] + real(r8), intent(in) :: height(:,:) ! height [m] + real(r8), intent(in) :: bagw(:,:) ! aboveground biomass [kgC] + real(r8), intent(in) :: blmax(:, :) ! leaf biomass [kgC] + real(r8), intent(in) :: crown_area(:, :) ! crown area [m2] + real(r8), intent(in) :: sapwood_area(:, :) ! sapwood cross-sectional area [m2] + real(r8), intent(in) :: bsap(:, :) ! sapwood biomass [kgC] + real(r8), intent(in) :: bbgw(:, :) ! belowground biomass [kgC] + real(r8), intent(in) :: fineroot_biomass(:, :) ! fineroot biomass [kgC] + real(r8), intent(in) :: bstore(:, :) ! storage biomass [kgC] + real(r8), intent(in) :: bdead(:, :) ! deadwood biomass [kgC] + real(r8), intent(in) :: total_biom_parts(:, :) ! total biomass calculated from parts [kgC] + real(r8), intent(in) :: total_biom_tissues(:, :) ! total biomass calculated from tissues [kgC] + + ! LOCALS: + integer, allocatable :: pft_indices(:) ! array of pft indices to write out + integer :: i ! looping index + integer :: ncid ! netcdf file id + character(len=8) :: dim_names(2) ! dimension names + integer :: dimIDs(2) ! dimension IDs + integer :: dbhID, pftID ! variable IDs for dimensions + integer :: heightID, bagwID + integer :: blmaxID, c_areaID + integer :: sapwoodareaID, bsapID + integer :: bbgwID, finerootID + integer :: bstoreID, bdeadID + integer :: totbiomID1, totbiomID2 + + ! create pft indices + allocate(pft_indices(numpft)) + do i = 1, numpft + pft_indices(i) = i + end do + + ! dimension names + dim_names = [character(len=12) :: 'dbh', 'pft'] + + ! open file + call OpenNCFile(trim(out_file), ncid, 'readwrite') + + ! register dimensions + call RegisterNCDims(ncid, dim_names, (/numdbh, numpft/), 2, dimIDs) + + ! register dbh + call RegisterVar(ncid, dim_names(1), dimIDs(1:1), type_double, & + [character(len=20) :: 'units', 'long_name'], & + [character(len=150) :: 'cm', 'diameter at breast height'], 2, dbhID) + + ! register pft + call RegisterVar(ncid, dim_names(2), dimIDs(2:2), type_int, & + [character(len=20) :: 'units', 'long_name'], & + [character(len=150) :: '', 'plant functional type'], 2, pftID) + + ! register height + call RegisterVar(ncid, 'height', dimIDs(1:2), type_double, & + [character(len=20) :: 'coordinates', 'units', 'long_name'], & + [character(len=150) :: 'pft dbh', 'm', 'plant height'], & + 3, heightID) + + ! register aboveground biomass + call RegisterVar(ncid, 'bagw', dimIDs(1:2), type_double, & + [character(len=20) :: 'coordinates', 'units', 'long_name'], & + [character(len=150) :: 'pft dbh', 'kgC', 'plant aboveground woody biomass'], & + 3, bagwID) + + ! register leaf biomass + call RegisterVar(ncid, 'blmax', dimIDs(1:2), type_double, & + [character(len=20) :: 'coordinates', 'units', 'long_name'], & + [character(len=150) :: 'pft dbh', 'kgC', 'plant maximum leaf biomass'], & + 3, blmaxID) + + ! register crown area + call RegisterVar(ncid, 'crown_area', dimIDs(1:2), type_double, & + [character(len=20) :: 'coordinates', 'units', 'long_name'], & + [character(len=150) :: 'pft dbh', 'm2', 'plant crown area per cohort'], & + 3, c_areaID) + + ! register sapwood area + call RegisterVar(ncid, 'sapwood_area', dimIDs(1:2), type_double, & + [character(len=20) :: 'coordinates', 'units', 'long_name'], & + [character(len=150) :: 'pft dbh', 'm2', 'plant cross section area sapwood at reference height'], & + 3, sapwoodareaID) + + ! register sapwood biomass + call RegisterVar(ncid, 'bsap', dimIDs(1:2), type_double, & + [character(len=20) :: 'coordinates', 'units', 'long_name'], & + [character(len=150) :: 'pft dbh', 'kgC', 'plant sapwood biomass'], & + 3, bsapID) + + ! register belowground woody biomass + call RegisterVar(ncid, 'bbgw', dimIDs(1:2), type_double, & + [character(len=20) :: 'coordinates', 'units', 'long_name'], & + [character(len=150) :: 'pft dbh', 'kgC', 'plant belowground woody biomass'], & + 3, bbgwID) + + ! register fineroot biomass + call RegisterVar(ncid, 'fineroot_biomass', dimIDs(1:2), type_double, & + [character(len=20) :: 'coordinates', 'units', 'long_name'], & + [character(len=150) :: 'pft dbh', 'kgC', 'plant fineroot biomass'], & + 3, finerootID) + + ! register storage biomass + call RegisterVar(ncid, 'bstore', dimIDs(1:2), type_double, & + [character(len=20) :: 'coordinates', 'units', 'long_name'], & + [character(len=150) :: 'pft dbh', 'kgC', 'plant storage biomass'], & + 3, bstoreID) + + ! register structural biomass + call RegisterVar(ncid, 'bdead', dimIDs(1:2), type_double, & + [character(len=20) :: 'coordinates', 'units', 'long_name'], & + [character(len=150) :: 'pft dbh', 'kgC', 'plant deadwood (structural/heartwood) biomass'], & + 3, bdeadID) + + ! register total biomass (parts) + call RegisterVar(ncid, 'total_biomass_parts', dimIDs(1:2), type_double, & + [character(len=20) :: 'coordinates', 'units', 'long_name'], & + [character(len=150) :: 'pft dbh', 'kgC', 'plant total biomass calculated from parts'], & + 3, totbiomID1) + + ! register total biomass (tissues) + call RegisterVar(ncid, 'total_biomass_tissues', dimIDs(1:2), type_double, & + [character(len=20) :: 'coordinates', 'units', 'long_name'], & + [character(len=150) :: 'pft dbh', 'kgC', 'plant total biomass calculated from tissues'], & + 3, totbiomID2) + + ! finish defining variables + call EndNCDef(ncid) + + ! write out data + call WriteVar(ncid, dbhID, dbh(:)) + call WriteVar(ncid, pftID, pft_indices(:)) + call WriteVar(ncid, heightID, height(:,:)) + call WriteVar(ncid, bagwID, bagw(:,:)) + call WriteVar(ncid, blmaxID, blmax(:,:)) + call WriteVar(ncid, c_areaID, crown_area(:,:)) + call WriteVar(ncid, sapwoodareaID, sapwood_area(:,:)) + call WriteVar(ncid, bsapID, bsap(:,:)) + call WriteVar(ncid, bbgwID, bbgw(:,:)) + call WriteVar(ncid, finerootID, fineroot_biomass(:,:)) + call WriteVar(ncid, bstoreID, bstore(:,:)) + call WriteVar(ncid, bdeadID, bdead(:,:)) + call WriteVar(ncid, totbiomID1, total_biom_parts(:,:)) + call WriteVar(ncid, totbiomID2, total_biom_tissues(:,:)) + + ! close the file + call CloseNCFile(ncid) + +end subroutine WriteAllometryData \ No newline at end of file diff --git a/testing/functional_testing/allometry/allometry_plotting.py b/testing/functional_testing/allometry/allometry_plotting.py new file mode 100644 index 0000000000..caa6cc1069 --- /dev/null +++ b/testing/functional_testing/allometry/allometry_plotting.py @@ -0,0 +1,187 @@ +"""Utility functions for allometry functional unit tests +""" +import os +import math +import pandas as pd +import numpy as np +import xarray as xr +import matplotlib +import matplotlib.pyplot as plt +from utils import get_color_palette, round_up + +def blank_plot(x_max, x_min, y_max, y_min, draw_horizontal_lines=False): + """Generate a blank plot with set attributes + + Args: + x_max (float): maximum x value + x_min (float): minimum x value + y_max (float): maximum y value + y_min (float): minimum y value + draw_horizontal_lines (bool, optional): whether or not to draw horizontal + lines across plot. Defaults to False. + """ + + plt.figure(figsize=(7, 5)) + axis = plt.subplot(111) + axis.spines["top"].set_visible(False) + axis.spines["bottom"].set_visible(False) + axis.spines["right"].set_visible(False) + axis.spines["left"].set_visible(False) + + axis.get_xaxis().tick_bottom() + axis.get_yaxis().tick_left() + + plt.xlim(0.0, x_max) + plt.ylim(0.0, y_max) + + plt.yticks(fontsize=10) + plt.xticks(fontsize=10) + + if draw_horizontal_lines: + inc = (int(y_max) - y_min)/20 + for i in range(0, 20): + plt.plot(range(math.floor(x_min), math.ceil(x_max)), + [0.0 + i*inc] * len(range(math.floor(x_min), math.ceil(x_max))), + "--", lw=0.5, color="black", alpha=0.3) + + plt.tick_params(bottom=False, top=False, left=False, right=False) + + return plt + +def plot_allometry_var(data, varname, units, save_fig, plot_dir=None): + """Plot an allometry variable + + Args: + data (xarray DataArray): the data array of the variable to plot + var (str): variable name (for data structure) + varname (str): variable name for plot labels + units (str): variable units for plot labels + save_fig (bool): whether or not to write out plot + plot_dir (str): if saving figure, where to write to + """ + data_frame = pd.DataFrame({'dbh': np.tile(data.dbh, len(data.pft)), + 'pft': np.repeat(data.pft, len(data.dbh)), + data.name: data.values.flatten()}) + + max_dbh = data_frame['dbh'].max() + max_var = round_up(data_frame[data.name].max()) + + blank_plot(max_dbh, 0.0, max_var, 0.0, draw_horizontal_lines=True) + + pfts = np.unique(data_frame.pft.values) + colors = get_color_palette(len(pfts)) + for rank, pft in enumerate(pfts): + dat = data_frame[data_frame.pft == pft] + plt.plot(dat.dbh.values, dat[data.name].values, lw=2, color=colors[rank], + label=pft) + + plt.xlabel('DBH (cm)', fontsize=11) + plt.ylabel(f'{varname} ({units})', fontsize=11) + plt.title(f"Simulated {varname} for input parameter file", fontsize=11) + plt.legend(loc='upper left', title='PFT') + + if save_fig: + fig_name = os.path.join(plot_dir, f"allometry_plot_{data.name}.png") + plt.savefig(fig_name) + +def plot_total_biomass(data, save_fig, plot_dir): + """Plot two calculations of total biomass against each other + + Args: + data (xarray DataSet): the allometry dataset + """ + data_frame = pd.DataFrame({'dbh': np.tile(data.dbh, len(data.pft)), + 'pft': np.repeat(data.pft, len(data.dbh)), + 'total_biomass_parts': data.total_biomass_parts.values.flatten(), + 'total_biomass_tissues': data.total_biomass_tissues.values.flatten()}) + + max_biomass = np.maximum(data_frame['total_biomass_parts'].max(), + data_frame['total_biomass_tissues'].max()) + + blank_plot(max_biomass, 0.0, max_biomass, 0.0, draw_horizontal_lines=False) + + pfts = np.unique(data_frame.pft.values) + colors = get_color_palette(len(pfts)) + for rank, pft in enumerate(pfts): + data = data_frame[data_frame.pft == pft] + plt.scatter(data.total_biomass_parts.values, data.total_biomass_parts.values, + color=colors[rank], label=pft) + + plt.xlabel('Total biomass (kgC) from parts', fontsize=11) + plt.ylabel('Total biomass (kgC) from tissues', fontsize=11) + plt.title("Simulated total biomass for input parameter file", fontsize=11) + plt.legend(loc='upper left', title='PFT') + + if save_fig: + fig_name = os.path.join(plot_dir, "allometry_plot_total_biomass_compare.png") + plt.savefig(fig_name) + +def plot_allometry_dat(run_dir, out_file, save_figs, plot_dir): + """Plots all allometry plots + + Args: + run_dir (str): run directory + out_file (str): output file name + save_figs (bool): whether or not to save the figures + plot_dir (str): plot directory to save the figures to + """ + + # read in allometry data + allometry_dat = xr.open_dataset(os.path.join(run_dir, out_file)) + + plot_dict = { + 'height': { + 'varname': 'height', + 'units': 'm', + }, + 'bagw': { + 'varname': 'aboveground biomass', + 'units': 'kgC', + }, + 'blmax': { + 'varname': 'maximum leaf biomass', + 'units': 'kgC', + }, + 'crown_area': { + 'varname': 'crown area', + 'units': 'm$^2$', + }, + 'sapwood_area': { + 'varname': 'sapwood area', + 'units': 'm$^2$', + }, + 'bsap': { + 'varname': 'sapwood biomass', + 'units': 'kgC', + }, + 'bbgw': { + 'varname': 'belowground biomass', + 'units': 'kgC', + }, + 'fineroot_biomass': { + 'varname': 'fineroot biomass', + 'units': 'kgC', + }, + 'bstore': { + 'varname': 'storage biomass', + 'units': 'kgC', + }, + 'bdead': { + 'varname': 'deadwood biomass', + 'units': 'kgC', + }, + 'total_biomass_parts': { + 'varname': 'total biomass (calculated from parts)', + 'units': 'kgC', + }, + 'total_biomass_tissues': { + 'varname': 'total biomass (calculated from tissues)', + 'units': 'kgC', + }, + + } + for plot, attributes in plot_dict.items(): + plot_allometry_var(allometry_dat[plot], attributes['varname'], + attributes['units'], save_figs, plot_dir) + + plot_total_biomass(allometry_dat, save_figs, plot_dir) diff --git a/testing/functional_testing/math_utils/CMakeLists.txt b/testing/functional_testing/math_utils/CMakeLists.txt new file mode 100644 index 0000000000..e23eac3dcf --- /dev/null +++ b/testing/functional_testing/math_utils/CMakeLists.txt @@ -0,0 +1,10 @@ +set(math_sources FatesTestMathUtils.F90) + +link_directories(${PFUNIT_TOP_DIR}/lib) + +add_executable(FATES_math_exe ${math_sources}) + +target_link_libraries(FATES_math_exe + fates + csm_share + funit) \ No newline at end of file diff --git a/testing/functional_testing/math_utils/FatesTestMathUtils.F90 b/testing/functional_testing/math_utils/FatesTestMathUtils.F90 new file mode 100644 index 0000000000..627eb2713b --- /dev/null +++ b/testing/functional_testing/math_utils/FatesTestMathUtils.F90 @@ -0,0 +1,138 @@ +program FatesTestQuadSolvers + + use FatesConstantsMod, only : r8 => fates_r8 + use FatesUtilsMod, only : QuadraticRootsNSWC, QuadraticRootsSridharachary + use FatesUtilsMod, only : GetNeighborDistance + + implicit none + + ! CONSTANTS: + integer, parameter :: n = 4 ! number of points to test + character(len=*), parameter :: out_file = 'quad_out.nc' ! output file + + ! LOCALS: + integer :: i ! looping index + real(r8) :: a(n), b(n), c(n) ! coefficients for quadratic solvers + real(r8) :: root1(n) ! real part of first root of quadratic solver + real(r8) :: root2(n) ! real part of second root of quadratic solver + + interface + + subroutine WriteQuadData(out_file, n, a, b, c, root1, root2) + + use FatesUnitTestIOMod, only : OpenNCFile, RegisterNCDims, CloseNCFile + use FatesUnitTestIOMod, only : WriteVar, RegisterVar + use FatesUnitTestIOMod, only : type_double, type_int + use FatesConstantsMod, only : r8 => fates_r8 + implicit none + + character(len=*), intent(in) :: out_file + integer, intent(in) :: n + real(r8), intent(in) :: a(:) + real(r8), intent(in) :: b(:) + real(r8), intent(in) :: c(:) + real(r8), intent(in) :: root1(:) + real(r8), intent(in) :: root2(:) + end subroutine WriteQuadData + + end interface + + a = (/1.0_r8, 1.0_r8, 5.0_r8, 1.5_r8/) + b = (/-2.0_r8, 7.0_r8, 10.0_r8, 3.2_r8/) + c = (/1.0_r8, 12.0_r8, 3.0_r8, 1.1_r8/) + + do i = 1, n + call QuadraticRootsNSWC(a(i), b(i), c(i), root1(i), root2(i)) + end do + + call WriteQuadData(out_file, n, a, b, c, root1, root2) + +end program FatesTestQuadSolvers + +! ---------------------------------------------------------------------------------------- + +subroutine WriteQuadData(out_file, n, a, b, c, root1, root2) + ! + ! DESCRIPTION: + ! Writes out data from the quadratic solver test + ! + use FatesConstantsMod, only : r8 => fates_r8 + use FatesUnitTestIOMod, only : OpenNCFile, RegisterNCDims, CloseNCFile + use FatesUnitTestIOMod, only : WriteVar + use FatesUnitTestIOMod, only : RegisterVar + use FatesUnitTestIOMod, only : EndNCDef + use FatesUnitTestIOMod, only : type_double, type_int + + implicit none + + ! ARGUMENTS: + character(len=*), intent(in) :: out_file ! output file name + integer, intent(in) :: n ! number of points to write out + real(r8), intent(in) :: a(:) ! coefficient a + real(r8), intent(in) :: b(:) ! coefficient b + real(r8), intent(in) :: c(:) ! coefficient c + real(r8), intent(in) :: root1(:) ! root1 from quadratic solver + real(r8), intent(in) :: root2(:) ! root2 from quadratic solver + + ! LOCALS: + integer :: n_index(n) ! array of pft indices to write out + integer :: i ! looping index + integer :: ncid ! netcdf file id + character(len=8) :: dim_names(1) ! dimension names + integer :: dimIDs(1) ! dimension IDs + integer :: aID, bID, cID + integer :: root1ID, root2ID + + ! make index + do i = 1, n + n_index(i) = i + end do + + ! dimension names + dim_names = [character(len=12) :: 'n'] + + ! open file + call OpenNCFile(trim(out_file), ncid, 'readwrite') + + ! register dimensions + call RegisterNCDims(ncid, dim_names, (/n/), 1, dimIDs) + + ! register a + call RegisterVar(ncid, 'a', dimIDs(1:1), type_double, & + [character(len=20) :: 'units', 'long_name'], & + [character(len=150) :: '', 'coefficient a'], 2, aID) + + ! register b + call RegisterVar(ncid, 'b', dimIDs(1:1), type_double, & + [character(len=20) :: 'units', 'long_name'], & + [character(len=150) :: '', 'coefficient b'], 2, bID) + + ! register c + call RegisterVar(ncid, 'c', dimIDs(1:1), type_double, & + [character(len=20) :: 'units', 'long_name'], & + [character(len=150) :: '', 'coefficient c'], 2, cID) + + ! register root1 + call RegisterVar(ncid, 'root1', dimIDs(1:1), type_double, & + [character(len=20) :: 'units', 'long_name'], & + [character(len=150) :: '', 'root 1'], 2, root1ID) + + ! register root2 + call RegisterVar(ncid, 'root2', dimIDs(1:1), type_double, & + [character(len=20) :: 'units', 'long_name'], & + [character(len=150) :: '', 'root 2'], 2, root2ID) + + ! finish defining variables + call EndNCDef(ncid) + + ! write out data + call WriteVar(ncid, aID, a(:)) + call WriteVar(ncid, bID, b(:)) + call WriteVar(ncid, cID, c(:)) + call WriteVar(ncid, root1ID, root1(:)) + call WriteVar(ncid, root2ID, root2(:)) + + ! close the file + call CloseNCFile(ncid) + +end subroutine WriteQuadData diff --git a/testing/functional_testing/math_utils/math_plotting.py b/testing/functional_testing/math_utils/math_plotting.py new file mode 100644 index 0000000000..4e386dbe93 --- /dev/null +++ b/testing/functional_testing/math_utils/math_plotting.py @@ -0,0 +1,52 @@ +"""Utility functions for allometry functional unit tests +""" +import os +import math +import xarray as xr +import numpy as np +import matplotlib.pyplot as plt + +from utils import get_color_palette + +def plot_quadratic_dat(run_dir, out_file, save_figs, plot_dir): + """Reads in and plots quadratic formula test output + + Args: + run_dir (str): run directory + out_file (str): output file + save_figs (bool): whether or not to save the figures + plot_dir (str): plot directory + """ + + # read in quadratic data + quadratic_dat = xr.open_dataset(os.path.join(run_dir, out_file)) + + # plot output + plot_quad_and_roots(quadratic_dat.a.values, quadratic_dat.b.values, + quadratic_dat.c.values, quadratic_dat.root1.values, + quadratic_dat.root2.values) + if save_figs: + fig_name = os.path.join(plot_dir, "quadratic_test.png") + plt.savefig(fig_name) + +def plot_quad_and_roots(a_coeff, b_coeff, c_coeff, root1, root2): + """Plots a set of quadratic formulas (ax**2 + bx + c) and their two roots + + Args: + a_coeff (float array): set of a coefficients + b_coeff (float array): set of b coefficients + c_coeff (float array): set of b coefficients + root1 (float array): set of first real roots + root2 (float array): set of second real roots + """ + num_equations = len(a_coeff) + + plt.figure(figsize=(7, 5)) + x_vals = np.linspace(-10.0, 10.0, num=20) + + colors = get_color_palette(num_equations) + for i in range(num_equations): + y_vals = a_coeff[i]*x_vals**2 + b_coeff[i]*x_vals + c_coeff[i] + plt.plot(x_vals, y_vals, lw=2, color=colors[i]) + plt.scatter(root1[i], root2[i], color=colors[i], s=50) + plt.axhline(y=0.0, color='k', linestyle='dotted') diff --git a/testing/path_utils.py b/testing/path_utils.py new file mode 100644 index 0000000000..85aea6085a --- /dev/null +++ b/testing/path_utils.py @@ -0,0 +1,51 @@ +"""Utility functions related to getting paths to various important places +""" + +import os +import sys + +# Path to the root directory of FATES, based on the path of this file +# Note: It's important that this NOT end with a trailing slash; +_FATES_ROOT = os.path.normpath( + os.path.join(os.path.dirname(os.path.abspath(__file__)), os.pardir) +) + +def path_to_fates_root(): + """Returns the path to the root directory of FATES""" + return _FATES_ROOT + +def path_to_cime(): + """Returns the path to cime, if it can be found + + Raises a RuntimeError if it cannot be found + + """ + cime_path = os.path.join(path_to_fates_root(), "../../cime") + if os.path.isdir(cime_path): + return cime_path + raise RuntimeError("Cannot find cime.") + +def prepend_to_python_path(path): + """Adds the given path to python's sys.path if it isn't already in the path + + The path is added near the beginning, so that it takes precedence over existing + entries in the path + """ + if not path in sys.path: + # Insert at location 1 rather than 0, because 0 is special + sys.path.insert(1, path) + +def add_cime_lib_to_path(): + """Adds the CIME python library to the python path, to allow importing + modules from that library + + Returns the path to the top-level cime directory + + For documentation on standalone_only: See documentation in + path_to_cime + """ + cime_path = path_to_cime() + prepend_to_python_path(cime_path) + cime_lib_path = os.path.join(cime_path, "CIME", "Tools") + prepend_to_python_path(cime_lib_path) + return cime_path diff --git a/testing/run_fates_tests.py b/testing/run_fates_tests.py new file mode 100755 index 0000000000..ea2cf5b0b1 --- /dev/null +++ b/testing/run_fates_tests.py @@ -0,0 +1,457 @@ +#!/usr/bin/env python + +""" +|------------------------------------------------------------------| +|--------------------- Instructions -----------------------------| +|------------------------------------------------------------------| +To run this script the following python packages are required: + - numpy + - xarray + - matplotlib + - pandas + +Though this script does not require any host land model code, it does require some CIME +and shr code, so you should still get these repositories as you normally would +(i.e., manage_externals, etc.) + +Additionally, this requires netcdf and netcdff as well as a fortran compiler. + +You must also have a .cime folder in your home directory which specifies machine +configurations for CIME. + +This script builds and runs various FATES unit and functional tests, and plots any +relevant output from those tests. + +You can supply your own parameter file (either a .cdl or a .nc file), or if you do not +specify anything, the script will use the default FATES parameter cdl file. + +""" +import os +import argparse +import matplotlib.pyplot as plt +from build_fortran_tests import build_unit_tests, build_exists +from path_utils import add_cime_lib_to_path +from utils import copy_file, create_nc_file +from functional_testing.allometry.allometry_plotting import plot_allometry_dat +from functional_testing.math_utils.math_plotting import plot_quadratic_dat + +add_cime_lib_to_path() + +from CIME.utils import run_cmd_no_fail # pylint: disable=wrong-import-position,import-error,wrong-import-order + +# Constants for this script +_DEFAULT_CDL_PATH = os.path.abspath("../parameter_files/fates_params_default.cdl") +_CMAKE_BASE_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "../") +_TEST_NAME = "fates_tests" +_TEST_SUB_DIR = "testing" + +# Dictionary with needed constants for running the executables and reading in the +# output files - developers who add tests should add things here. + +# NOTE: if the functional test you write requires a parameter file read in as a +# command-line argument, this should be the *first* (or only) argument in the +# command-line argument list +_ALL_TESTS_DICT = { + "allometry": { + "test_dir": "fates_allom_ftest", + "test_exe": "FATES_allom_exe", + "out_file": "allometry_out.nc", + "has_unit_test": False, + "use_param_file": True, + "other_args": [], + "plotting_function": plot_allometry_dat, + }, + "quadratic": { + "test_dir": "fates_math_ftest", + "test_exe": "FATES_math_exe", + "out_file": "quad_out.nc", + "has_unit_test": False, + "use_param_file": False, + "other_args": [], + "plotting_function": plot_quadratic_dat, + }, + "fire_weather":{ + "test_dir": "fates_fire_weather_utest", + "test_exe": None, + "out_file": None, + "has_unit_test": True, + "use_param_file": False, + "other_args": [], + "plotting_function": None, + } + } + +def run_fortran_exectuables(build_dir, test_dir, test_exe, run_dir, args): + """Run the generated Fortran executables + + Args: + build_dir (str): full path to build directory + run_dir (str): full path to run directory + test_dir (str): test directory within the run directory + test_exe (str): test executable to run + args ([str]): arguments for executable + """ + + # move executable to run directory + exe_path = os.path.join(build_dir, _TEST_SUB_DIR, test_dir, test_exe) + copy_file(exe_path, run_dir) + + # run the executable + new_exe_path = os.path.join(run_dir, test_exe) + run_command = [new_exe_path] + run_command.extend(args) + + os.chdir(run_dir) + out = run_cmd_no_fail(" ".join(run_command), combine_output=True) + print(out) + +def make_plotdirs(run_dir, test_dict): + """Create plotting directories if they don't already exist + + Args: + run_dir (str): full path to run directory + test_dict (dict): dictionary of test to run + """ + # make main plot directory + plot_dir = os.path.join(run_dir, 'plots') + if not os.path.isdir(plot_dir): + os.mkdir(plot_dir) + + # make sub-plot directories + for test in dict(filter(lambda pair: pair[1]['plotting_function'] is not None, + test_dict.items())): + sub_dir = os.path.join(plot_dir, test) + if not os.path.isdir(sub_dir): + os.mkdir(sub_dir) + +def create_param_file(param_file, run_dir): + """Creates and/or move the default or input parameter file to the run directory + Creates a netcdf file from a cdl file if a cdl file is supplied + + Args: + param_file (str): path to parmaeter file + run_dir (str): full path to run directory + + Raises: + RuntimeError: Supplied parameter file is not netcdf (.cd) or cdl (.cdl) + + Returns: + str: full path to new parameter file name/location + """ + if param_file is None: + print("Using default parameter file.") + param_file = _DEFAULT_CDL_PATH + param_file_update = create_nc_file(param_file, run_dir) + else: + print(f"Using parameter file {param_file}.") + file_suffix = os.path.basename(param_file).split(".")[-1] + if file_suffix == 'cdl': + param_file_update = create_nc_file(param_file, run_dir) + elif file_suffix == "nc": + param_file_update = copy_file(param_file, run_dir) + else: + raise RuntimeError("Must supply parameter file with .cdl or .nc ending.") + + return param_file_update + +def run_tests(clean, verbose_make, build_tests, run_executables, build_dir, run_dir, + make_j, param_file, save_figs, test_dict): + """Builds and runs the fates tests + + Args: + clean (bool): whether or not to clean the build directory + verbose_make (bool): whether or not to run make with verbose output + build_tests (bool): whether or not to build the exectuables + run_executables (bool): whether or not to run the executables + build_dir (str): build directory + run_dir (str): run directory + make_j (int): number of processors for the build + param_file (str): input FATES parameter file + save_figs (bool): whether or not to write figures to file + test_dict (dict): dictionary of tests to run + """ + + # absolute path to desired build directory + build_dir_path = os.path.abspath(build_dir) + + # absolute path to desired run directory + run_dir_path = os.path.abspath(run_dir) + + # make run directory if it doesn't already exist + if not os.path.isdir(run_dir_path): + os.mkdir(run_dir_path) + + # create plot directories if we need to + if save_figs: + make_plotdirs(os.path.abspath(run_dir), test_dict) + + # move parameter file to correct location (creates nc file if cdl supplied) + param_file = create_param_file(param_file, run_dir) + + # compile code + if build_tests: + build_unit_tests(build_dir, _TEST_NAME, _CMAKE_BASE_DIR, make_j, clean=clean, + verbose=verbose_make) + + # run executables for each test in test list + if run_executables: + print("Running executables") + # we don't run executables for only pfunit tests + for attributes in dict(filter(lambda pair: pair[1]['test_exe'] is not None, + test_dict.items())).values(): + # prepend parameter file (if required) to argument list + args = attributes['other_args'] + if attributes['use_param_file']: + args.insert(0, param_file) + # run + run_fortran_exectuables(build_dir_path, attributes['test_dir'], + attributes['test_exe'], run_dir_path, args) + + # run unit tests + for test, attributes in dict(filter(lambda pair: pair[1]['has_unit_test'], + test_dict.items())).items(): + print(f"Running unit tests for {test}.") + + test_dir = os.path.join(build_dir_path, _TEST_SUB_DIR, attributes['test_dir']) + ctest_command = ["ctest", "--output-on-failure"] + output = run_cmd_no_fail(" ".join(ctest_command), from_dir=test_dir, + combine_output=True) + print(output) + + # plot output for relevant tests + for test, attributes in dict(filter(lambda pair: pair[1]['plotting_function'] is not None, + test_dict.items())).items(): + attributes['plotting_function'](run_dir_path, + attributes['out_file'], save_figs, + os.path.join(run_dir_path, 'plots', test)) + # show plots + plt.show() + +def out_file_exists(run_dir, out_file): + """Checks to see if the file out_file exists in the run_dir + + Args: + run_dir (str): full path to run directory + out_file (str): output file name + + Returns: + bool: yes/no file exists in correct location + """ + return os.path.isfile(os.path.join(run_dir, out_file)) + +def parse_test_list(test_string): + """Parses the input test list and checks for errors + + Args: + test (str): user-supplied comma-separated list of test names + + Returns: + dictionary: filtered dictionary of tests to run + + Raises: + RuntimeError: Invalid test name supplied + """ + valid_test_names = _ALL_TESTS_DICT.keys() + + if test_string != "all": + test_list = test_string.split(',') + for test in test_list: + if test not in valid_test_names: + raise argparse.ArgumentTypeError("Invalid test supplied, \n" + "must supply one of:\n" + f"{', '.join(valid_test_names)}\n" + "or do not supply a test name to run all tests.") + test_dict = {key: _ALL_TESTS_DICT[key] for key in test_list} + else: + test_dict = _ALL_TESTS_DICT + + return test_dict + +def commandline_args(): + """Parse and return command-line arguments""" + + description = """ + Driver for running FATES unit and functional tests + + Typical usage: + + ./run_fates_tests -f parameter_file.nc + + """ + parser = argparse.ArgumentParser( + description=description, formatter_class=argparse.RawTextHelpFormatter + ) + + parser.add_argument( + "-f", + "--parameter-file", + type=str, + default=_DEFAULT_CDL_PATH, + help="Parameter file to run the FATES tests with.\n" + "Can be a netcdf (.nc) or cdl (.cdl) file.\n" + "If no file is specified the script will use the default .cdl file in the\n" + "parameter_files directory.\n", + ) + + parser.add_argument( + "-b", + "--build-dir", + type=str, + default="../_build", + help="Directory where tests are built.\n" + "Will be created if it does not exist.\n", + ) + + parser.add_argument( + "-r", + "--run-dir", + type=str, + default="../_run", + help="Directory where tests are run.\n" + "Will be created if it does not exist.\n", + ) + + parser.add_argument( + "--make-j", + type=int, + default=8, + help="Number of processes to use for build.", + ) + + parser.add_argument( + "-c", + "--clean", + action="store_true", + help="Clean build directory before building.\n" + "Removes CMake cache and runs 'make clean'.\n", + ) + + parser.add_argument( + "--skip-build", + action="store_true", + help="Skip building and compiling the test code.\n" + "Only do this if you already have run build.\n" + "Script will check to make sure executables are present.\n", + ) + + parser.add_argument( + "--skip-run-executables", + action="store_true", + help="Skip running test code executables.\n" + "Only do this if you already have run the code previously.\n" + "Script will check to make sure required output files are present.\n", + ) + + parser.add_argument( + "--save-figs", + action="store_true", + help="Write out generated figures to files.\n" + "Will be placed in run_dir/plots.\n" + "Should probably do this on remote machines.\n", + ) + + parser.add_argument( + "--verbose-make", + action="store_true", + help="Run make with verbose output." + ) + + parser.add_argument( + "-t", + "--test-list", + action="store", + dest="test_dict", + type=parse_test_list, + default="all", + help="Test(s) to run. Comma-separated list of test names, or 'all'\n" + "for all tests. If not supplied, will run all tests." + ) + + args = parser.parse_args() + + check_arg_validity(args) + + return args + +def check_param_file(param_file): + """Checks to see if param_file exists and is of the correct form (.nc or .cdl) + + Args: + param_file (str): path to parameter file + + Raises: + argparse.ArgumentError: Parameter file is not of the correct form (.nc or .cdl) + argparse.ArgumentError: Can't find parameter file + """ + file_suffix = os.path.basename(param_file).split(".")[-1] + if not file_suffix in ['cdl', 'nc']: + raise argparse.ArgumentError(None, "Must supply parameter file with .cdl or .nc ending.") + if not os.path.isfile(param_file): + raise argparse.ArgumentError(None, f"Cannot find file {param_file}.") + +def check_build_dir(build_dir, test_dict): + """Checks to see if all required build directories and executables are present + + Args: + build_dir (str): build directory + test_list (list, str): list of test names + + Raises: + argparse.ArgumentError: Can't find a required build directory or executable + """ + for attributes in test_dict.values(): + if not build_exists(build_dir, attributes['test_dir'], attributes['test_exe']): + raise argparse.ArgumentError(None, "Build directory or executable does not exist.\n" + "Re-run script without --skip-build.") + +def check_out_files(run_dir, test_dict): + """Checks to see that required output files are present in the run directory + + Args: + run_dir (str): run directory + test_dict (dict): dictionary of tests to run + + Raises: + argparse.ArgumentError: Can't find a required output file + """ + for test, attributes in dict(filter(lambda pair: pair[1]['out_file'] is not None, + test_dict.items())).items(): + if not out_file_exists(os.path.abspath(run_dir), attributes['out_file']): + raise argparse.ArgumentError(None, f"Required file for {test} test does not exist.\n" + "Re-run script without --skip-run.") + +def check_arg_validity(args): + """Checks validity of input script arguments + + Args: + args (parse_args): input arguments + """ + # check to make sure parameter file exists and is one of the correct forms + check_param_file(args.parameter_file) + + # make sure build directory exists + if args.skip_build: + if args.verbose_make: + raise argparse.ArgumentError(None, "Can't run verbose make and skip build.\n" + "Re-run script without --skip-build") + check_build_dir(args.build_dir, args.test_dict) + + # make sure relevant output files exist: + if args.skip_run_executables: + check_out_files(args.run_dir, args.test_dict) + +def main(): + """Main script + Reads in command-line arguments and then runs the tests. + """ + + args = commandline_args() + + build = not args.skip_build + run = not args.skip_run_executables + + run_tests(args.clean, args.verbose_make, build, run, args.build_dir, args.run_dir, + args.make_j, args.parameter_file, args.save_figs, args.test_dict) + +if __name__ == "__main__": + main() diff --git a/testing/testing_shr/CMakeLists.txt b/testing/testing_shr/CMakeLists.txt new file mode 100644 index 0000000000..8cf4eb69c0 --- /dev/null +++ b/testing/testing_shr/CMakeLists.txt @@ -0,0 +1,6 @@ +list(APPEND fates_sources + FatesUnitTestParamReaderMod.F90 + FatesUnitTestIOMod.F90 + ) + +sourcelist_to_parent(fates_sources) \ No newline at end of file diff --git a/testing/testing_shr/FatesUnitTestIOMod.F90 b/testing/testing_shr/FatesUnitTestIOMod.F90 new file mode 100644 index 0000000000..8f6ea1141a --- /dev/null +++ b/testing/testing_shr/FatesUnitTestIOMod.F90 @@ -0,0 +1,574 @@ +module FatesUnitTestIOMod + use FatesConstantsMod, only : r8 => fates_r8 + use FatesGlobals, only : fates_endrun + use shr_kind_mod, only : SHR_KIND_CL + use netcdf + + implicit none + private + + ! LOCALS + integer, public, parameter :: type_double = 1 ! type + integer, public, parameter :: type_int = 2 ! type + + interface GetVar + module procedure GetVarScalarReal + module procedure GetVar1DReal + module procedure GetVar2DReal + module procedure GetVar3DReal + module procedure GetVar1DInt + module procedure GetVar2DInt + module procedure GetVar3DInt + end interface + + interface WriteVar + module procedure WriteVar1DReal + module procedure WriteVar2DReal + module procedure WriteVar1DInt + module procedure WriteVar2DInt + end interface + + public :: OpenNCFile + public :: CloseNCFile + public :: GetDimID + public :: GetDimLen + public :: GetVar + public :: RegisterNCDims + public :: RegisterVar + public :: WriteVar + public :: EndNCDef + + contains + + !======================================================================================= + + logical function CheckFile(filename, fmode) + ! + ! DESCRIPTION: + ! Checks to see if a file exists and checks against the mode + ! + + ! ARGUMENTS: + character(len=*), intent(in) :: filename ! Name of file to open + character(len=*), intent(in) :: fmode ! File mode + + ! LOCALS: + character(len=len(filename)) :: fname ! Local filename (trimmed) + integer :: ios ! I/O status + logical :: file_exists ! Does the file exist? + + ! trim filename of whitespace + fname = trim(adjustl(filename)) + + ! Does the file exist? + inquire(file=fname, exist=file_exists) + + select case (fmode) + case('read') + + if (.not. file_exists) then + write(*,'(a,a,a)') "File ", fname(1:len_trim(fname)), " does not exist. Can't read." + CheckFile = .false. + else + CheckFile = .true. + end if + + case('readwrite') + + CheckFile = .true. + + case('write') + if (file_exists) then + write(*, '(a, a, a)') "File ", fname(1:len_trim(fname)), " exists. Cannot open write only." + else + CheckFile = .true. + CheckFile = .false. + end if + case default + write(*,'(a)') "Invalid file mode." + CheckFile = .false. + end select + + end function CheckFile + + !======================================================================================= + + subroutine Check(status) + ! + ! DESCRIPTION: + ! Checks status of netcdf operations + + ! ARGUMENTS: + integer, intent(in) :: status ! return status code from a netcdf procedure + + if (status /= nf90_noerr) then + write(*,*) trim(nf90_strerror(status)) + stop + end if + + end subroutine Check + + ! ======================================================================================= + + subroutine OpenNCFile(nc_file, ncid, fmode) + ! + ! DESCRIPTION: + ! Opens a netcdf file + + ! ARGUMENTS: + character(len=*), intent(in) :: nc_file ! file name + integer, intent(out) :: ncid ! netcdf file unit number + character(len=*) :: fmode ! file mode + + if (CheckFile(nc_file, fmode)) then + ! depending on mode + select case(fmode) + case ('read') + call Check(nf90_open(trim(nc_file), NF90_NOCLOBBER, ncid)) + case ('write') + call Check(nf90_create(trim(nc_file), NF90_CLOBBER, ncid)) + case ('readwrite') + call Check(nf90_create(trim(nc_file), NF90_CLOBBER, ncid)) + case DEFAULT + write(*,*) 'Need to specify read, write, or readwrite' + stop + end select + else + write(*,*) 'Problem reading file' + stop + end if + + end subroutine OpenNCFile + + !======================================================================================= + + subroutine CloseNCFile(ncid) + ! + ! DESCRIPTION: + ! Closes a netcdf file + + ! ARGUMENTS: + integer, intent(in) :: ncid ! netcdf file unit number + + call Check(nf90_close(ncid)) + + end subroutine CloseNCFile + + !======================================================================================= + + subroutine GetDimID(ncid, var_name, dim_id) + ! + ! DESCRIPTION: + ! Gets dimension IDs for a variable ID + ! + + ! ARGUMENTS: + integer, intent(in) :: ncid ! netcdf file unit number + character(len=*), intent(in) :: var_name ! variable name + integer, intent(out) :: dim_id ! dimension ID + + call Check(nf90_inq_dimid(ncid, var_name, dim_id)) + + end subroutine GetDimID + + !======================================================================================= + + subroutine GetDimLen(ncid, dim_id, dim_len) + ! + ! DESCRIPTION: + ! Gets dimension lengths given a dimension ID + ! + + ! ARGUMENTS: + integer, intent(in) :: ncid ! netcdf file unit number + integer, intent(in) :: dim_id ! dimension ID + integer, intent(out) :: dim_len ! dimension length + + call Check(nf90_inquire_dimension(ncid, dim_id, len=dim_len)) + + end subroutine GetDimLen + + !======================================================================================= + + subroutine GetDims(ncid, varID, dim_lens) + ! + ! DESCRIPTION: + ! Get dimensions for a netcdf variable + ! + + ! ARGUMENTS + integer, intent(in) :: ncid ! netcdf file unit ID + integer, intent(in) :: varID ! variable ID + integer, allocatable, intent(out) :: dim_lens(:) ! dimension lengths + + ! LOCALS: + integer :: numDims ! number of dimensions + integer, allocatable :: dimIDs(:) ! dimension IDs + integer :: i ! looping index + + ! find dimensions of data + call Check(nf90_inquire_variable(ncid, varID, ndims=numDims)) + + ! allocate data to grab dimension information + allocate(dim_lens(numDims)) + allocate(dimIDs(numDims)) + + ! get dimIDs + call Check(nf90_inquire_variable(ncid, varID, dimids=dimIDs)) + + ! grab these dimensions + do i = 1, numDims + call Check(nf90_inquire_dimension(ncid, dimIDs(i), len=dim_lens(i))) + end do + + end subroutine GetDims + + !===================================================================================== + + subroutine GetVarScalarReal(ncid, var_name, data) + ! + ! DESCRIPTION: + ! Read in variables for scalar real data + ! + + ! ARGUMENTS: + integer, intent(in) :: ncid ! netcdf file unit ID + character(len=*), intent(in) :: var_name ! variable name + real(r8), intent(out) :: data ! data value + + ! LOCALS: + integer :: varID ! variable ID + integer, allocatable :: dim_lens(:) ! dimension lengths + + ! find variable ID first + call Check(nf90_inq_varid(ncid, var_name, varID)) + + ! read data + call Check(nf90_get_var(ncid, varID, data)) + + end subroutine GetVarScalarReal + + !===================================================================================== + + subroutine GetVar1DReal(ncid, var_name, data) + ! + ! DESCRIPTION: + ! Read in variables for 1D real data + ! + + ! ARGUMENTS: + integer, intent(in) :: ncid ! netcdf file unit ID + character(len=*), intent(in) :: var_name ! variable name + real(r8), allocatable, intent(out) :: data(:) ! data values + + ! LOCALS: + integer :: varID ! variable ID + integer, allocatable :: dim_lens(:) ! dimension lengths + + ! find variable ID first + call Check(nf90_inq_varid(ncid, var_name, varID)) + + ! get dimensions of data + call GetDims(ncid, varID, dim_lens) + + ! read data + allocate(data(dim_lens(1))) + call Check(nf90_get_var(ncid, varID, data)) + + end subroutine GetVar1DReal + + !===================================================================================== + + subroutine GetVar1DInt(ncid, var_name, data) + ! + ! DESCRIPTION: + ! Read in variables for 1D integer data + ! + + ! ARGUMENTS: + integer, intent(in) :: ncid ! netcdf file unit ID + character(len=*), intent(in) :: var_name ! variable name + integer, allocatable, intent(out) :: data(:) ! data values + + ! LOCALS: + integer :: varID ! variable ID + integer, allocatable :: dim_lens(:) ! dimension lengths + + ! find variable ID first + call Check(nf90_inq_varid(ncid, var_name, varID)) + + ! get dimensions of data + call GetDims(ncid, varID, dim_lens) + + ! read data + allocate(data(dim_lens(1))) + call Check(nf90_get_var(ncid, varID, data)) + + end subroutine GetVar1DInt + + !===================================================================================== + + subroutine GetVar2DReal(ncid, var_name, data) + ! + ! DESCRIPTION: + ! Read in variables for 2D real data + ! + + ! ARGUMENTS: + integer, intent(in) :: ncid ! netcdf file unit ID + character(len=*), intent(in) :: var_name ! variable name + real(r8), allocatable, intent(out) :: data(:,:) ! data values + + ! LOCALS: + integer :: varID ! variable ID + integer, allocatable :: dim_lens(:) ! dimension lengths + + ! find variable ID first + call Check(nf90_inq_varid(ncid, var_name, varID)) + + ! get dimensions of data + call GetDims(ncid, varID, dim_lens) + + ! read data + allocate(data(dim_lens(1), dim_lens(2))) + call Check(nf90_get_var(ncid, varID, data)) + + end subroutine GetVar2DReal + + !===================================================================================== + + subroutine GetVar2DInt(ncid, var_name, data) + ! + ! DESCRIPTION: + ! Read in variables for 2D integer data + ! + + ! ARGUMENTS: + integer, intent(in) :: ncid ! netcdf file unit ID + character(len=*), intent(in) :: var_name ! variable name + integer, allocatable, intent(out) :: data(:,:) ! data values + + ! LOCALS: + integer :: varID ! variable ID + integer, allocatable :: dim_lens(:) ! dimension lengths + + ! find variable ID first + call Check(nf90_inq_varid(ncid, var_name, varID)) + + ! get dimensions of data + call GetDims(ncid, varID, dim_lens) + + ! read data + allocate(data(dim_lens(1), dim_lens(2))) + call Check(nf90_get_var(ncid, varID, data)) + + end subroutine GetVar2DInt + + !===================================================================================== + + subroutine GetVar3DReal(ncid, var_name, data) + ! + ! DESCRIPTION: + ! Read in variables for 3D real data + ! + + ! ARGUMENTS: + integer, intent(in) :: ncid ! netcdf file unit ID + character(len=*), intent(in) :: var_name ! variable name + real(r8), allocatable, intent(out) :: data(:,:,:) ! data values + + ! LOCALS: + integer :: varID ! variable ID + integer, allocatable :: dim_lens(:) ! dimension lengths + + ! find variable ID first + call Check(nf90_inq_varid(ncid, var_name, varID)) + + ! get dimensions of data + call GetDims(ncid, varID, dim_lens) + + ! read data + allocate(data(dim_lens(1), dim_lens(2), dim_lens(3))) + call Check(nf90_get_var(ncid, varID, data)) + + end subroutine GetVar3DReal + + !===================================================================================== + + subroutine GetVar3DInt(ncid, var_name, data) + ! + ! DESCRIPTION: + ! Read in variables for 3D integer data + ! + + ! ARGUMENTS: + integer, intent(in) :: ncid ! netcdf file unit ID + character(len=*), intent(in) :: var_name ! variable name + integer, allocatable, intent(out) :: data(:,:,:) ! data values + + ! LOCALS: + integer :: varID ! variable ID + integer, allocatable :: dim_lens(:) ! dimension lengths + + ! find variable ID first + call Check(nf90_inq_varid(ncid, var_name, varID)) + + ! get dimensions of data + call GetDims(ncid, varID, dim_lens) + + ! read data + allocate(data(dim_lens(1), dim_lens(2), dim_lens(3))) + call Check(nf90_get_var(ncid, varID, data)) + + end subroutine GetVar3DInt + + !===================================================================================== + + subroutine RegisterNCDims(ncid, dim_names, dim_lens, num_dims, dim_IDs) + ! + ! DESCRIPTION: + ! Defines variables and dimensions + ! + + ! ARGUMENTS: + integer, intent(in) :: ncid ! netcdf file id + character(len=*), intent(in) :: dim_names(num_dims) ! dimension names + integer, intent(in) :: dim_lens(num_dims) ! dimension lengths + integer, intent(in) :: num_dims ! number of dimensions + integer, intent(out) :: dim_IDs(num_dims) ! dimension IDs + + ! LOCALS: + integer :: i ! looping index + + do i = 1, num_dims + call Check(nf90_def_dim(ncid, dim_names(i), dim_lens(i), dim_IDs(i))) + end do + + end subroutine RegisterNCDims + + !===================================================================================== + + subroutine RegisterVar(ncid, var_name, dimID, type, att_names, atts, num_atts, varID) + ! + ! DESCRIPTION: + ! Defines variables and dimensions + ! + + ! ARGUMENTS: + integer, intent(in) :: ncid ! netcdf file id + character(len=*), intent(in) :: var_name ! variable name + integer, intent(in) :: dimID(:) ! dimension IDs + integer, intent(in) :: type ! type: int or double + character(len=*), intent(in) :: att_names(num_atts) ! attribute names + character(len=*), intent(in) :: atts(num_atts) ! attribute values + integer, intent(in) :: num_atts ! number of attributes + integer, intent(out) :: varID ! variable ID + + + ! LOCALS: + integer :: i ! looping index + integer :: nc_type ! netcdf type + + if (type == type_double) then + nc_type = NF90_DOUBLE + else if (type == type_int) then + nc_type = NF90_INT + else + write(*, *) "Must pick correct type" + stop + end if + + call Check(nf90_def_var(ncid, var_name, nc_type, dimID, varID)) + + do i = 1, num_atts + call Check(nf90_put_att(ncid, varID, att_names(i), atts(i))) + end do + + end subroutine RegisterVar + + ! ===================================================================================== + + subroutine EndNCDef(ncid) + ! + ! DESCRIPTION: + ! End defining of netcdf dimensions and variables + ! + + ! ARGUMENTS: + integer, intent(in) :: ncid ! netcdf file id + + call Check(nf90_enddef(ncid)) + + end subroutine EndNCDef + + ! ===================================================================================== + + subroutine WriteVar1DReal(ncid, varID, data) + ! + ! DESCRIPTION: + ! Write 1D real data + ! + + ! ARGUMENTS: + integer, intent(in) :: ncid ! netcdf file id + integer, intent(in) :: varID ! variable ID + real(r8), intent(in) :: data(:) ! data to write + + call Check(nf90_put_var(ncid, varID, data(:))) + + end subroutine WriteVar1DReal + + ! ===================================================================================== + + subroutine WriteVar2DReal(ncid, varID, data) + ! + ! DESCRIPTION: + ! Write 2D real data + ! + + ! ARGUMENTS: + integer, intent(in) :: ncid ! netcdf file id + integer, intent(in) :: varID ! variable ID + real(r8), intent(in) :: data(:,:) ! data to write + + call Check(nf90_put_var(ncid, varID, data(:,:))) + + end subroutine WriteVar2DReal + + ! ===================================================================================== + + subroutine WriteVar1DInt(ncid, varID, data) + ! + ! DESCRIPTION: + ! Write 1D integer data + ! + + ! ARGUMENTS: + integer, intent(in) :: ncid ! netcdf file id + integer, intent(in) :: varID ! variable ID + integer, intent(in) :: data(:) ! data to write + + call Check(nf90_put_var(ncid, varID, data(:))) + + end subroutine WriteVar1DInt + + ! ===================================================================================== + + subroutine WriteVar2DInt(ncid, varID, data) + ! + ! DESCRIPTION: + ! Write 2D integer data + ! + + ! ARGUMENTS: + integer, intent(in) :: ncid ! netcdf file id + integer, intent(in) :: varID ! variable ID + integer, intent(in) :: data(:,:) ! data to write + + call Check(nf90_put_var(ncid, varID, data(:,:))) + + end subroutine WriteVar2DInt + + ! ===================================================================================== + +end module FatesUnitTestIOMod \ No newline at end of file diff --git a/testing/testing_shr/FatesUnitTestParamReaderMod.F90 b/testing/testing_shr/FatesUnitTestParamReaderMod.F90 new file mode 100644 index 0000000000..624c98ea68 --- /dev/null +++ b/testing/testing_shr/FatesUnitTestParamReaderMod.F90 @@ -0,0 +1,200 @@ +module FatesUnitTestParamReaderMod + + use FatesConstantsMod, only : r8 => fates_r8 + use FatesParametersInterface, only : fates_param_reader_type + use FatesParametersInterface, only : fates_parameters_type + use FatesParametersInterface, only : param_string_length + use FatesParametersInterface, only : max_dimensions, max_used_dimensions + use FatesParametersInterface, only : dimension_shape_scalar, dimension_shape_1d, dimension_shape_2d + use EDParamsMod, only : FatesRegisterParams, FatesReceiveParams + use SFParamsMod, only : SpitFireRegisterParams, SpitFireReceiveParams + use PRTInitParamsFatesMod, only : PRTRegisterParams, PRTReceiveParams + use PRTParametersMod, only : prt_params + use FatesParameterDerivedMod, only : param_derived + use FatesSynchronizedParamsMod, only : FatesSynchronizedParamsInst + use EDPftvarcon, only : EDPftvarcon_inst + use FatesUnitTestIOMod, only : OpenNCFile, GetDimID, GetDimLen, GetVar, CloseNCFile + + implicit none + private + + type, public, extends(fates_param_reader_type) :: fates_unit_test_param_reader + + character(:), allocatable :: filename ! local file name of parameter + + contains + procedure, public :: Read => ReadParameters + procedure, public :: Init + procedure, public :: RetrieveParameters + + end type fates_unit_test_param_reader + + contains + + subroutine Init(this, param_file) + ! + ! DESCRIPTION: + ! Initialize the parameter reader class + ! + ! ARGUMENTS: + class(fates_unit_test_param_reader) :: this + character(len=*) :: param_file + + this%filename = trim(param_file) + + end subroutine Init + + ! -------------------------------------------------------------------------------------- + + subroutine ReadParameters(this, fates_params) + ! + ! DESCRIPTION: + ! Read 'fates_params' parameters from storage + ! + ! ARGUMENTS: + class(fates_unit_test_param_reader) :: this + class(fates_parameters_type), intent(inout) :: fates_params + + ! LOCALS: + real(r8), allocatable :: data2d(:, :) ! data for 2D parameters + real(r8), allocatable :: data1d(:) ! data for 1D parameters + real(r8) :: data_scalar ! data for scalar parameters + integer :: ncid ! netcdf file ID + integer :: num_params ! total number of parameters + integer :: dimension_shape ! shape of parameter's dimension + integer :: i ! looping index + character(len=param_string_length) :: name ! parameter name + integer :: dimension_sizes(max_dimensions) ! sizes of dimensions from parameter file + character(len=param_string_length) :: dimension_names(max_dimensions) ! names of dimensions from parameter file + logical :: is_host_param + + call OpenNCFile(this%filename, ncid, 'read') + call SetParameterDimensions(ncid, fates_params) + + num_params = fates_params%num_params() + do i = 1, num_params + call fates_params%GetMetaData(i, name, dimension_shape, dimension_sizes, & + dimension_names, is_host_param) + select case(dimension_shape) + case(dimension_shape_scalar) + call GetVar(ncid, name, data_scalar) + call fates_params%SetData(i, data_scalar) + case(dimension_shape_1d) + call GetVar(ncid, name, data1d) + call fates_params%SetData(i, data1d) + case(dimension_shape_2d) + call GetVar(ncid, name, data2d) + call fates_params%SetData(i, data2d) + case default + write(*, '(a,a)') 'dimension shape:', dimension_shape + write(*, '(a)') 'unsupported number of dimensions reading parameters.' + stop + end select + end do + + if (allocated(data1d)) deallocate(data1d) + if (allocated(data2d)) deallocate(data2d) + + call CloseNCFile(ncid) + + end subroutine ReadParameters + + ! -------------------------------------------------------------------------------------- + + subroutine RetrieveParameters(this) + ! + ! DESCRIPTION: + ! Read in fates parameters + ! + ! ARGUMENTS: + class(fates_unit_test_param_reader), intent(in) :: this ! parameter reader class + + ! LOCALS: + class(fates_parameters_type), allocatable :: fates_params ! fates parameters (for non-pft parameters) + class(fates_parameters_type), allocatable :: fates_pft_params ! fates parameters (for pft parameters) + + ! allocate and read in parameters + allocate(fates_params) + allocate(fates_pft_params) + call fates_params%Init() + call fates_pft_params%Init() + + call EDPftvarcon_inst%Init() + + call FatesRegisterParams(fates_params) + call SpitFireRegisterParams(fates_params) + call PRTRegisterParams(fates_params) + call FatesSynchronizedParamsInst%RegisterParams(fates_params) + call EDPftvarcon_inst%Register(fates_pft_params) + + call this%Read(fates_params) + call this%Read(fates_pft_params) + + call FatesReceiveParams(fates_params) + call SpitFireReceiveParams(fates_params) + call PRTReceiveParams(fates_params) + call FatesSynchronizedParamsInst%ReceiveParams(fates_params) + call EDPftvarcon_inst%Receive(fates_pft_params) + + call fates_params%Destroy() + call fates_pft_params%Destroy() + deallocate(fates_params) + deallocate(fates_pft_params) + + ! initialize derived parameters + call param_derived%Init(size(prt_params%wood_density, dim=1)) + + end subroutine RetrieveParameters + + ! -------------------------------------------------------------------------------------- + + subroutine SetParameterDimensions(ncid, fates_params) + ! + ! DESCRIPTION: + ! Gets and sets the parameter dimensions for the fates parameters class + ! + ! ARGUMENTS: + integer, intent(in) :: ncid ! netcdf file ID + class(fates_parameters_type), intent(inout) :: fates_params ! fates parameters class + + ! LOCALS: + integer :: num_used_dimensions ! total number of dimensions + character(len=param_string_length) :: used_dimension_names(max_used_dimensions) ! dimension names + integer :: used_dimension_sizes(max_used_dimensions) ! dimension sizes + + call fates_params%GetUsedDimensions(.false., num_used_dimensions, used_dimension_names) + + call GetUsedDimensionSizes(ncid, num_used_dimensions, used_dimension_names, & + used_dimension_sizes) + + call fates_params%SetDimensionSizes(.false., num_used_dimensions, & + used_dimension_names, used_dimension_sizes) + + end subroutine SetParameterDimensions + + ! -------------------------------------------------------------------------------------- + + subroutine GetUsedDimensionSizes(ncid, num_used_dimensions, dimension_names, dimension_sizes) + ! + ! DESCRIPTION: + ! Gets dimension sizes for parameters + ! + ! ARGUMENTS: + integer, intent(in) :: ncid ! netcdf file ID + integer, intent(in) :: num_used_dimensions ! number of dimensions + character(len=param_string_length), intent(in) :: dimension_names(:) ! dimension names + integer, intent(out) :: dimension_sizes(:) ! dimension sizes + + ! LOCALS + integer :: d + integer :: dim_id + + dimension_sizes(:) = 0 + do d = 1, num_used_dimensions + call GetDimID(ncid, dimension_names(d), dim_id) + call GetDimLen(ncid, dim_id, dimension_sizes(d)) + end do + + end subroutine GetUsedDimensionSizes + +end module FatesUnitTestParamReaderMod \ No newline at end of file diff --git a/testing/unit_testing/fire_weather_test/CMakeLists.txt b/testing/unit_testing/fire_weather_test/CMakeLists.txt new file mode 100644 index 0000000000..2a3554cd86 --- /dev/null +++ b/testing/unit_testing/fire_weather_test/CMakeLists.txt @@ -0,0 +1,5 @@ +set(pfunit_sources test_FireWeather.pf) + +add_pfunit_ctest(FireWeather + TEST_SOURCES "${pfunit_sources}" + LINK_LIBRARIES fates csm_share) \ No newline at end of file diff --git a/testing/unit_testing/fire_weather_test/test_FireWeather.pf b/testing/unit_testing/fire_weather_test/test_FireWeather.pf new file mode 100644 index 0000000000..c5111394bc --- /dev/null +++ b/testing/unit_testing/fire_weather_test/test_FireWeather.pf @@ -0,0 +1,67 @@ +module test_FireWeather + ! + ! DESCRIPTION: + ! Test the FATES fire weather portion of the SPITFIRE model + ! + use FatesConstantsMod, only : r8 => fates_r8 + use SFFireWeatherMod, only : fire_weather + use SFNesterovMod, only : nesterov_index + use funit + + implicit none + + @TestCase + type, extends(TestCase) :: TestFireWeather + + class(fire_weather), allocatable :: fireWeatherNesterov + + contains + procedure :: setUp + procedure :: tearDown + end type TestFireWeather + + real(r8), parameter :: tol = 1.e-13_r8 + + contains + + subroutine setUp(this) + class(TestFireWeather), intent(inout) :: this + allocate(nesterov_index :: this%fireWeatherNesterov) + call this%fireWeatherNesterov%Init() + end subroutine setUp + + subroutine tearDown(this) + class(TestFireWeather), intent(inout) :: this + if (allocated(this%fireWeatherNesterov)) deallocate(this%fireWeatherNesterov) + end subroutine tearDown + + @Test + subroutine zero_NI_rain(this) + ! test that over 3 mm of rain is 0.0 + class(TestFireWeather), intent(inout) :: this ! fire weather object + + call this%fireWeatherNesterov%Update(25.0_r8, 3.1_r8, 10.0_r8, 0.0_r8) + @assertEqual(this%fireWeatherNesterov%fire_weather_index, 0.0_r8, tolerance=tol) + this%fireWeatherNesterov%fire_weather_index = 0.0_r8 + end subroutine zero_NI_rain + + @Test + subroutine NI_rain_min(this) + ! test that at 3 mm is over zero + class(TestFireWeather), intent(inout) :: this ! fire weather object + + call this%fireWeatherNesterov%Update(25.0_r8, 3.0_r8, 10.0_r8, 0.0_r8) + @assertGreaterThan(this%fireWeatherNesterov%fire_weather_index, 0.0_r8, tolerance=tol) + this%fireWeatherNesterov%fire_weather_index = 0.0_r8 + end subroutine NI_rain_min + + @Test + subroutine NI_not_negative(this) + ! test that NI is not negative + class(TestFireWeather), intent(inout) :: this ! fire weather object + + call this%fireWeatherNesterov%Update(-30.0_r8, 0.0_r8, 99.0_r8, 0.0_r8) + @assertEqual(this%fireWeatherNesterov%fire_weather_index, 0.0_r8, tolerance=tol) + end subroutine NI_not_negative + + end module test_FireWeather \ No newline at end of file diff --git a/testing/utils.py b/testing/utils.py new file mode 100644 index 0000000000..aa6079757d --- /dev/null +++ b/testing/utils.py @@ -0,0 +1,94 @@ +"""Utility functions for plotting, file checking, math equations, etc. +""" + +import math +import os +from path_utils import add_cime_lib_to_path + +add_cime_lib_to_path() + +from CIME.utils import run_cmd_no_fail # pylint: disable=wrong-import-position,import-error,wrong-import-order + +def round_up(num, decimals=0): + """Rounds a number up + + Args: + num (float): number to round + decimals (int, optional): number of decimals to round to. Defaults to 0. + + Returns: + float: input number rounded up + """ + multiplier = 10**decimals + return math.ceil(num * multiplier)/multiplier + +def truncate(num, decimals=0): + """Rounds a number down + + Args: + num (float): number to round + decimals (int, optional): Decimals to round down to. Defaults to 0. + + Returns: + float: number rounded down + """ + multiplier = 10**decimals + return int(num * multiplier)/multiplier + +def create_nc_file(cdl_path, run_dir): + """Creates a netcdf file from a cdl file + + Args: + cdl_path (str): full path to desired cdl file + run_dir (str): where the file should be written to + """ + file_basename = os.path.basename(cdl_path).split(".")[-2] + file_nc_name = f"{file_basename}.nc" + + file_gen_command = [ + "ncgen -o", + os.path.join(run_dir, file_nc_name), + cdl_path + ] + out = run_cmd_no_fail(" ".join(file_gen_command), combine_output=True) + print(out) + + return file_nc_name + +def copy_file(file_path, directory): + """Copies a file file to a desired directory + + Args: + file_path (str): full path to file + dir (str): where the file should be copied to + """ + file_basename = os.path.basename(file_path) + + file_copy_command = [ + "cp", + os.path.abspath(file_path), + os.path.abspath(directory) + ] + run_cmd_no_fail(" ".join(file_copy_command), combine_output=True) + + return file_basename + +def get_color_palette(number): + """Generate a color pallete + Args: + number: number of colors to get - must be <= 20 + Returns: + float: array of colors to use in plotting + """ + if number > 20: + raise RuntimeError("get_color_palette: number must be <=20") + + colors = [(31, 119, 180), (174, 199, 232), (255, 127, 14), (255, 187, 120), + (44, 160, 44), (152, 223, 138), (214, 39, 40), (255, 152, 150), + (148, 103, 189), (197, 176, 213), (140, 86, 75), (196, 156, 148), + (227, 119, 194), (247, 182, 210), (127, 127, 127), (199, 199, 199), + (188, 189, 34), (219, 219, 141), (23, 190, 207), (158, 218, 229)] + + colors = [(red/255.0, green/255.0, blue/255.0) for red, green, blue in colors] + + return colors[:number] diff --git a/tools/BatchPatchParams.py b/tools/BatchPatchParams.py index 99a6f6bd76..cd3e934632 100755 --- a/tools/BatchPatchParams.py +++ b/tools/BatchPatchParams.py @@ -7,9 +7,15 @@ import os import argparse import code # For development: code.interact(local=dict(globals(), **locals())) -from scipy.io import netcdf import xml.etree.ElementTree as et - +# Newer versions of scipy have dropped the netcdf module and +# netcdf functions are part of the io parent module +try: + from scipy import io as nc + +except ImportError: + from scipy.io import netcdf as nc + debug = True # --------------------------------------------------------------------------------------- @@ -105,15 +111,18 @@ def main(): base_nc = os.popen('mktemp').read().rstrip('\n') gencmd = "ncgen -o "+base_nc+" "+base_cdl os.system(gencmd) - + # Generate a temp output file name new_nc = os.popen('mktemp').read().rstrip('\n') + os.system("ls "+base_nc) + os.system("ls "+new_nc) + # Use FatesPFTIndexSwapper.py to prune out unwanted PFTs pft_trim_list = xmlroot.find('pft_trim_list').text.replace(" ","") swapcmd="../tools/FatesPFTIndexSwapper.py --pft-indices="+pft_trim_list+" --fin="+base_nc+" --fout="+new_nc+" --nohist" #+" 1>/dev/null" os.system(swapcmd) - + # On subsequent parameters, overwrite the file paramroot = xmlroot.find('parameters') @@ -173,7 +182,7 @@ def main(): # Append history - fp_nc = netcdf.netcdf_file(new_nc, 'a') + fp_nc = nc.netcdf_file(new_nc, 'a') fp_nc.history = "This file was generated by BatchPatchParams.py:\n"\ "CDL Base File = {}\n"\ "XML patch file = {}"\ diff --git a/tools/FatesPFTIndexSwapper.py b/tools/FatesPFTIndexSwapper.py index 99e258bdc6..c63f8891b7 100755 --- a/tools/FatesPFTIndexSwapper.py +++ b/tools/FatesPFTIndexSwapper.py @@ -15,9 +15,14 @@ import getopt import code # For development: code.interact(local=locals()) from datetime import datetime -from scipy.io import netcdf -#import matplotlib.pyplot as plt +# import matplotlib.pyplot as plt +# Newer versions of scipy have dropped the netcdf module and +# netcdf functions are part of the io parent module +try: + from scipy import io as nc +except ImportError: + from scipy.io import netcdf as nc # ======================================================================================= # Parameters @@ -28,6 +33,7 @@ hydro_dim_name = 'fates_hydr_organs' litt_dim_name = 'fates_litterclass' string_dim_name = 'fates_string_length' +landuse_dim_name = 'fates_landuseclass' class timetype: @@ -147,9 +153,9 @@ def main(argv): num_pft_out = len(donor_pft_indices) # Open the netcdf files - fp_out = netcdf.netcdf_file(output_fname, 'w') + fp_out = nc.netcdf_file(output_fname, 'w') - fp_in = netcdf.netcdf_file(input_fname, 'r') + fp_in = nc.netcdf_file(input_fname, 'r') for key, value in sorted(fp_in.dimensions.items()): if(key==pft_dim_name): @@ -165,14 +171,14 @@ def main(argv): in_var = fp_in.variables.get(key) - - + # Idenfity if this variable has pft dimension - pft_dim_found = -1 - prt_dim_found = -1 - hydro_dim_found = -1 - litt_dim_found = -1 - string_dim_found = -1 + pft_dim_found = -1 + prt_dim_found = -1 + hydro_dim_found = -1 + litt_dim_found = -1 + string_dim_found = -1 + landuse_dim_found = -1 pft_dim_len = len(fp_in.variables.get(key).dimensions) for idim, name in enumerate(fp_in.variables.get(key).dimensions): @@ -188,13 +194,18 @@ def main(argv): hydro_dim_found = idim if(name==string_dim_name): string_dim_found = idim - + if(name==landuse_dim_name): + landuse_dim_found = idim + + + + # Copy over the input data # Tedious, but I have to permute through all combinations of dimension position if( pft_dim_len == 0 ): out_var = fp_out.createVariable(key,'d',(fp_in.variables.get(key).dimensions)) out_var.assignValue(float(fp_in.variables.get(key).data)) - elif( (pft_dim_found==-1) & (prt_dim_found==-1) & (litt_dim_found==-1) & (hydro_dim_found==-1) ): + elif( (pft_dim_found==-1) & (prt_dim_found==-1) & (litt_dim_found==-1) & (hydro_dim_found==-1) & (landuse_dim_found==-1) ): out_var = fp_out.createVariable(key,'d',(fp_in.variables.get(key).dimensions)) out_var[:] = in_var[:] elif( (pft_dim_found==0) & (pft_dim_len==1) ): # 1D fates_pft @@ -231,6 +242,10 @@ def main(argv): out_var[:] = in_var[:] elif( (litt_dim_found==0) & (string_dim_found>=0) ): + out_var = fp_out.createVariable(key,'c',(fp_in.variables.get(key).dimensions)) + out_var[:] = in_var[:] + + elif( (landuse_dim_found==0) & (string_dim_found>=0) ): out_var = fp_out.createVariable(key,'c',(fp_in.variables.get(key).dimensions)) out_var[:] = in_var[:] @@ -241,6 +256,9 @@ def main(argv): elif( litt_dim_found==0 ): out_var = fp_out.createVariable(key,'d',(fp_in.variables.get(key).dimensions)) out_var[:] = in_var[:] + elif( landuse_dim_found==0 ): + out_var = fp_out.createVariable(key,'d',(fp_in.variables.get(key).dimensions)) + out_var[:] = in_var[:] elif( hydro_dim_found==0): out_var = fp_out.createVariable(key,'d',(fp_in.variables.get(key).dimensions)) out_var[:] = in_var[:] diff --git a/tools/UpdateParamAPI.py b/tools/UpdateParamAPI.py index 7f49412eff..cc9ffa1faa 100755 --- a/tools/UpdateParamAPI.py +++ b/tools/UpdateParamAPI.py @@ -12,10 +12,17 @@ import os import argparse import code # For development: code.interact(local=dict(globals(), **locals())) -from scipy.io import netcdf import xml.etree.ElementTree as et import numpy as np +# Newer versions of scipy have dropped the netcdf module and +# netcdf functions are part of the io parent module +try: + from scipy import io as nc + +except ImportError: + from scipy.io import netcdf as nc + # ======================================================================================= def load_xml(xmlfile): @@ -157,10 +164,10 @@ def removevar(base_nc,varname): # The trick here, is to copy the whole file, minus the variable of interest # into a temp file. Then completely remove the old file, and - fp_base = netcdf.netcdf_file(base_nc, 'r',mmap=False) + fp_base = nc.netcdf_file(base_nc, 'r',mmap=False) new_nc = os.popen('mktemp').read().rstrip('\n') - fp_new = netcdf.netcdf_file(new_nc, 'w',mmap=False) + fp_new = nc.netcdf_file(new_nc, 'w',mmap=False) found = False for key, value in sorted(fp_base.dimensions.items()): @@ -248,7 +255,7 @@ def main(): print("The dimension size should be a scalar") exit(2) - ncfile = netcdf.netcdf_file(base_nc,"a",mmap=False) + ncfile = nc.netcdf_file(base_nc,"a",mmap=False) ncfile.createDimension(dimname, values[0]) ncfile.flush() ncfile.close() @@ -264,7 +271,7 @@ def main(): exit(2) # Find which parameters use this dimension - ncfile = netcdf.netcdf_file(base_nc,"r",mmap=False) + ncfile = nc.netcdf_file(base_nc,"r",mmap=False) found = False for key, value in sorted(ncfile.dimensions.items()): if(key==dimname): @@ -315,7 +322,7 @@ def main(): except: print("no long-name (ln), exiting");exit(2) - ncfile = netcdf.netcdf_file(base_nc,"a",mmap=False) + ncfile = nc.netcdf_file(base_nc,"a",mmap=False) try: # print("trying val: {}".format(paramname)) @@ -375,7 +382,7 @@ def main(): print("to change a parameter, the field must have a name attribute") exit(2) - ncfile = netcdf.netcdf_file(base_nc,"a",mmap=False) + ncfile = nc.netcdf_file(base_nc,"a",mmap=False) ncvar_o = ncfile.variables[paramname_o] # dims_o = ncvar_o.dimensions dtype_o = ncvar_o.typecode() diff --git a/tools/make_unstruct_grid/MakeUnstructGrid.py b/tools/make_unstruct_grid/MakeUnstructGrid.py new file mode 100644 index 0000000000..dfde3d8e03 --- /dev/null +++ b/tools/make_unstruct_grid/MakeUnstructGrid.py @@ -0,0 +1,317 @@ +import numpy as np +import xarray as xr +import matplotlib.pyplot as plt +import matplotlib +import matplotlib.dates as mdates +import sys +import code # For development: code.interact(local=locals()) code.interact(local=dict(globals(), **locals())) +import argparse +import math +from scipy.io import netcdf as nc +import xml.etree.ElementTree as et + +# The user specifies a couplet of domain/surface files +# from which they want to base their new unstructured grid. Then they provide +# a list of geographic coordinates in latitude and longitude. These coordinates +# are sampled from the base dataset, and written to an output dataset. +# +# This method is certainly useful for generating small sets of unstructured +# grid-cells. It may not be the best method for generating large sets. One +# may want to use "ncks" (ie Charlie Zender's NCO tools) for subsetting large +# grids. This method will arrange the new grid cells in a 1D vector, and assumes +# the input grids are based on a 2d array of cells. +# +# This method will assume that the grid-cell extents of the new unstructured grids +# match the extents of the base files. If you want finer or coarser resolution, +# just dig up a different base file. +# +# This method uses nearest neighbor. +# +# This may have trouble on newer surface files, particularly if they have topo +# unit information. It won't be difficult to add that type of functionality +# if it doesn't work, I (Ryan) just haven't tried it. +# +# All controls over this process can be found in the xml control file. See +# andes7x7.xml for an example. + +# Usage MakeUnstructGrid.py --fin=xmlfile.xml + +def TransferData(da_key,ds_base,ds_unst,minis,minjs,dset_type): + + print(' Transferring: {}'.format(da_key)) + + if(dset_type=='domain'): + xname = 'nj' + yname = 'ni' + ny = len(minis) #nj = len(minis) + nx = 1 #ni + nv = 4 + elif(dset_type=='surface'): + xname = 'lsmlat' + yname = 'lsmlon' + ny = len(minis) + nx = 1 + + #numurbl = 3 ; + #nlevurb = 5 ; + #numrad = 2 ; + #nchar = 256 ; + #nlevsoi = 10 ; + #time = UNLIMITED ; // (12 currently) + #lsmpft = 17 ; + #natpft = 17 ; + + + + # Determin the data type + if(ds_base[da_key].dtype == 'float64'): + dtype_out = np.float64 + elif(ds_base[da_key].dtype == 'int32'): + dtype_out = np.int32 + elif(ds_base[da_key].dtype == 'float32'): + dtype_out = np.float32 + else: + print('unknown data type: {}.\n Exiting'.format(ds_base[da_key].dtype)) + exit(2) + + + + # The lat-lon is always the last two dimensions + # Time is always the first dimension + + # Check to see if this has spatial dimensions + dimlist = list(ds_base[da_key].dims) + + # 2D (nj,ni) + # (lsmlat,lsmlon) + # 3D (nj, ni, nv) + # (x, lsmlat, lsmlon) + # 4D (x,y,lsmlat, lsmlon) + + if(any([dim==xname for dim in dimlist]) and (len(dimlist)==2)): + + # This is 2D and they are or use geographic coordinates + + ds_unst[da_key] = \ + xr.DataArray(np.empty((nx,ny), dtype=dtype_out),dims=dimlist) + + for k in range(len(minis)): + i = minis[k] + j = minjs[k] + ds_unst[da_key].loc[0,k] = ds_base[da_key].data[j,i] + + elif(any([dim==xname for dim in dimlist]) and any([dim=='nv' for dim in dimlist]) ): + + # This is the 3D coordinate in the domain file for vertices + + ds_unst[da_key] = \ + xr.DataArray(np.empty((nx,ny,nv), dtype=dtype_out),dims=dimlist) + for k in range(len(minis)): + i = minis[k] + j = minjs[k] + ds_unst[da_key].loc[0,k,:] = ds_base[da_key].data[j,i,:] + + elif(any([dim==xname for dim in dimlist]) and len(dimlist)==3): + + # This has dim==3, surface file and contains coordinates (x,lsmlat, lsmlon) + + dim0 = ds_base.dims[dimlist[0]] + ds_unst[da_key] = \ + xr.DataArray(np.empty((dim0,nx,ny), dtype=dtype_out),dims=dimlist) + for k in range(len(minis)): + i = minis[k] + j = minjs[k] + ds_unst[da_key].loc[:,0,k] = ds_base[da_key].data[:,j,i] + + elif(any([dim==xname for dim in dimlist]) and len(dimlist)==4): + + # This has dim==4, surface file and contains coordinates (x,y,lsmlat, lsmlon) + + dim0 = ds_base.dims[dimlist[0]] + dim1 = ds_base.dims[dimlist[1]] + ds_unst[da_key] = \ + xr.DataArray(np.empty((dim0,dim1,nx,ny), dtype=dtype_out),dims=dimlist) + for k in range(len(minis)): + i = minis[k] + j = minjs[k] + ds_unst[da_key].loc[:,:,0,k] = ds_base[da_key].data[:,:,j,i] + + elif(len(dimlist)==1): + # If there is no spatial coordinate, then just copy over what is there + #dimsizes = tuple([ds_base.dims[txt] for txt in dimlist]) + #ds_unst[da_key] = \ + # xr.DataArray(np.empty(dimsizes,dtype=dtype_out),dims=dimlist) + #ds_unst[da_key].loc[:] = ds_base[da_key].data[:] + ds_unst[da_key] = ds_base[da_key] + else: + # If there is no spatial coordinate, then just copy over what is there + + ds_unst[da_key] = ds_base[da_key] + + + # Once the new dataarray is created, transfer over metadata from original + ds_unst[da_key].attrs = ds_base[da_key].attrs + + return(ds_unst) + + +def main(argv): + + parser = argparse.ArgumentParser(description='Parse command line arguments to this script.') + parser.add_argument('--fin', dest='xmlfile', type=str, help="path to the xml control file",required=True) + args = parser.parse_args() + + xmlroot = et.parse(args.xmlfile).getroot() + + print(' -------------------------------------------------------------- ') + print('\n Creating a new domain/surface couplet \n') + print(' --------------------------------------------------------------\n ') + + # Get the domain base name + try: + domain_base = xmlroot.find('domain_base').text.strip() + domain_base_file = domain_base.split('/')[-1] + + except: + print('Could not find xml entry: {}'.format('domain_base')) + exit(2) + + # Get the new unstructured domain name (ie output) + try: + domain_unst = xmlroot.find('domain_unst').text.strip() + except: + print('Could not find xml entry: {}'.format('domain_unst')) + exit(2) + + + # Get the surface base name + try: + surface_base = xmlroot.find('surface_base').text.strip() + surface_base_file = surface_base.split('/')[-1] + + except: + print('Could not find xml entry: {}'.format('surface_base')) + exit(2) + + # Get the new unstructured surface name (ie output) + try: + surface_unst = xmlroot.find('surface_unst').text.strip() + except: + print('Could not find xml entry: {}'.format('surface_unst')) + exit(2) + + + + # Get a list of lon coordinates (force them into 0-360 convention) + try: + lon_subset_text = xmlroot.find('lon_list').text.strip().split(',') + lon_subset = [] + for txt in lon_subset_text: + lon = float(txt) + if(lon<0.0): + lon = 360.0+lon + lon_subset.append(lon) + + except: + print('Could not find xml entry: {}'.format('lon_list')) + exit(2) + + # Get a list of lat coordinates + try: + lat_subset_text = xmlroot.find('lat_list').text.strip().split(',') + lat_subset = [float(txt) for txt in lat_subset_text] + + except: + print('Could not find xml entry: {}'.format('lat_list')) + exit(2) + + # Check to make sure that the lat and lons are same length + + if( len(lat_subset) != len(lon_subset) ): + print('number of latitude subset points must match number of longitude subsets') + exit(2) + else: + nj = len(lat_subset) + print(' Found N={} lat/lon coordinates'.format(nj)) + + + #code.interact(local=dict(globals(), **locals())) + # ------------------------------------------------------------------------------ + # >>> ds_domain_base.data_vars + # Data variables: + #xv (nj, ni, nv) float64 358.8 1.25 1.25 358.8 ... 358.7 358.7 356.2 + #yv (nj, ni, nv) float64 -90.0 -90.0 -89.05 -89.05 ... 89.05 90.0 90.0 + #mask (nj, ni) int32 1 1 1 1 1 1 1 1 1 1 1 1 ... 0 0 0 0 0 0 0 0 0 0 0 0 + #area (nj, ni) float64 5.964e-06 5.964e-06 ... 5.964e-06 5.964e-06 + #frac (nj, ni) float64 1.0 1.0 1.0 1.0 1.0 1.0 ... 0.0 0.0 0.0 0.0 0.0 + # >>> ds_domain_base.coords + #Coordinates: + # xc (nj, ni) float64 0.0 2.5 5.0 7.5 10.0 ... 350.0 352.5 355.0 357.5 + # yc (nj, ni) float64 -90.0 -90.0 -90.0 -90.0 ... 90.0 90.0 90.0 90.0 + # ------------------------------------------------------------------------------ + + lon_subset_faux_2d = np.reshape(lon_subset, (-1, 1)) + lat_subset_faux_2d = np.reshape(lat_subset, (-1, 1)) + + ds_domain_base = xr.open_dataset(domain_base) + + # Lets find the indices for xc and yc that most closely match our coordinates + minis = [] + minjs = [] + for j in range(nj): + lat = lat_subset[j] + lon = lon_subset[j] + delt = (ds_domain_base['xc'].data-lon)**2.0 + (ds_domain_base['yc'].data-lat)**2.0 + minj,mini = np.unravel_index(delt.argmin(), delt.shape) + minis.append(mini) + minjs.append(minj) + + # Domain Processing + # =========================================================================================== + # Initialize the new dataset + ds_domain_unst = xr.Dataset( + attrs=ds_domain_base.attrs, + ) + ds_domain_unst.attrs["modification"]="Modified with SurfToVec.py, based on {}.".format(domain_base_file) + + #ode.interact(local=dict(globals(), **locals())) + + # Loop through existing datasets, allocate new arrays + # and transfer over point data + for da_key in ds_domain_base.data_vars: + ds_domain_unst = TransferData(da_key,ds_domain_base,ds_domain_unst,minis,minjs,'domain') + + for da_key in ds_domain_base.coords: + ds_domain_unst = TransferData(da_key,ds_domain_base,ds_domain_unst,minis,minjs,'domain') + + print('\n Writing: {}'.format(domain_unst)) + ds_domain_unst.to_netcdf(domain_unst) #,mode='a') + + # Surface Processing + # =========================================================================================== + + ds_surface_base = xr.open_dataset(surface_base) + + # Initialize the new dataset + ds_surface_unst = xr.Dataset( + attrs=ds_surface_base.attrs, + ) + ds_surface_unst.attrs["modification"]="Modified with SurfToVec.py, based on {}.".format(surface_base_file) + + + # Loop through existing datasets, allocate new arrays + # and transfer over point data + for da_key in ds_surface_base.data_vars: + ds_surface_unst = TransferData(da_key,ds_surface_base,ds_surface_unst,minis,minjs,'surface') + + for da_key in ds_surface_base.coords: + ds_surface_unst = TransferData(da_key,ds_surface_base,ds_surface_unst,minis,minjs,'surface') + + print('\n Writing: {}'.format(surface_unst)) + ds_surface_unst.to_netcdf(surface_unst) #,mode='a') + + print('\n') + +# This is the actual call to main +if __name__ == "__main__": + main(sys.argv) diff --git a/tools/make_unstruct_grid/andes7x7.xml b/tools/make_unstruct_grid/andes7x7.xml new file mode 100644 index 0000000000..ae99882ccd --- /dev/null +++ b/tools/make_unstruct_grid/andes7x7.xml @@ -0,0 +1,43 @@ + + + + + + + + Bases/domain.lnd.fv1.9x2.5_gx1v6.090206.nc + Bases/surfdata_1.9x2.5_simyr2000_c180306.nc + + + SAHydroStress/domain.lnd.fv1.9x2.5_gx1v6_SAHydroStress_c240320.nc + SAHydroStress/surfdata_1.9x2.5_simyr2000_SAHydroStress_c240320.nc + + + + -19.8947368421, -19.8947368421, -19.8947368421, + -18, -18, -18, -18, + -16.1052631579, -16.1052631579, -16.1052631579, -16.1052631579, -16.1052631579, + -14.2105263158, -14.2105263158, -14.2105263158, -14.2105263158, -14.2105263158, + -12.3157894737, -12.3157894737, -12.3157894737, -12.3157894737, -12.3157894737, -12.3157894737, + -10.4210526316, -10.4210526316, -10.4210526316, -10.4210526316, -10.4210526316, -10.4210526316, + -8.52631578947, -8.52631578947, -8.52631578947, -8.52631578947, -8.52631578947, -8.52631578947, -8.52631578947 + + + + + + 290, 292.5, 295, + 287.5, 290, 292.5, 295, + 285, 287.5, 290, 292.5, 295, + 285, 287.5, 290, 292.5, 295, + 282.5, 285, 287.5, 290, 292.5, 295, + 282.5, 285, 287.5, 290, 292.5, 295, + 280, 282.5, 285, 287.5, 290, 292.5, 295 + + + diff --git a/tools/modify_fates_paramfile.py b/tools/modify_fates_paramfile.py index 85f7c449ea..1b25ae7171 100755 --- a/tools/modify_fates_paramfile.py +++ b/tools/modify_fates_paramfile.py @@ -17,7 +17,6 @@ # ======================================================================================= import os -from scipy.io import netcdf as nc import argparse import shutil import tempfile @@ -27,6 +26,16 @@ import numpy as np import code # For development: code.interact(local=dict(globals(), **locals())) +# Newer versions of scipy have dropped the netcdf module and +# netcdf functions are part of the io parent module +try: + from scipy import io as nc + +except ImportError: + from scipy.io import netcdf as nc + + + # ======================================================================================== # ======================================================================================== # Main