diff --git a/cime_config/testdefs/testlist_clm.xml b/cime_config/testdefs/testlist_clm.xml
index 9f4ce73ed9..953747ddbf 100644
--- a/cime_config/testdefs/testlist_clm.xml
+++ b/cime_config/testdefs/testlist_clm.xml
@@ -1202,6 +1202,15 @@
+
+
+
+
+
+
+
+
+
diff --git a/cime_config/testdefs/testmods_dirs/clm/ciso_cwd_hr/README b/cime_config/testdefs/testmods_dirs/clm/ciso_cwd_hr/README
index 39ac318b86..d0dab73f44 100644
--- a/cime_config/testdefs/testmods_dirs/clm/ciso_cwd_hr/README
+++ b/cime_config/testdefs/testmods_dirs/clm/ciso_cwd_hr/README
@@ -1,8 +1,12 @@
This points to an alternate params file with
-rf_cwdl2 = 0.5
-rf_cwdl3_bgc = 0.5
-while by default these parameters equal zero.
+ceta = 450 (default = 358)
+The README used to say that the alternate paramfile contained
+rf_cwdl2 = 0.5 (default 0)
+rf_cwdl3_bgc = 0.5 (default 0)
+but now 0.5 is the default.
+
+The README also used to say:
The test outputs inactive history fields that would contain zeros
when running with the default params file and should be greater than zero
when running with the alternate params file.
diff --git a/cime_config/testdefs/testmods_dirs/clm/leafcn_t_evolving/README b/cime_config/testdefs/testmods_dirs/clm/leafcn_t_evolving/README
new file mode 100644
index 0000000000..3a21ac1a4e
--- /dev/null
+++ b/cime_config/testdefs/testmods_dirs/clm/leafcn_t_evolving/README
@@ -0,0 +1,6 @@
+This points to an alternate params file with
+leafcn_co2_slope = 30 (default = 0)
+to confirm that the leafcn_t_evolving calculation doesn't fail.
+
+When we added this test, slevis and ekluzek agreed to consolidate our custom paramfiles into one.
+The first of the consolidated paramfiles is named ctsm60_ceta450_cn30_co2_slope30.c250326.nc.
diff --git a/cime_config/testdefs/testmods_dirs/clm/leafcn_t_evolving/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/leafcn_t_evolving/include_user_mods
new file mode 100644
index 0000000000..fe0e18cf88
--- /dev/null
+++ b/cime_config/testdefs/testmods_dirs/clm/leafcn_t_evolving/include_user_mods
@@ -0,0 +1 @@
+../default
diff --git a/cime_config/testdefs/testmods_dirs/clm/leafcn_t_evolving/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/leafcn_t_evolving/user_nl_clm
new file mode 100644
index 0000000000..443e9ac1e5
--- /dev/null
+++ b/cime_config/testdefs/testmods_dirs/clm/leafcn_t_evolving/user_nl_clm
@@ -0,0 +1 @@
+paramfile = '$DIN_LOC_ROOT/lnd/clm2/paramdata/ctsm60_ceta450_cn30_co2_slope30.c250326.nc'
diff --git a/doc/ChangeLog b/doc/ChangeLog
index e594c688a0..ab165f8136 100644
--- a/doc/ChangeLog
+++ b/doc/ChangeLog
@@ -1,4 +1,64 @@
===============================================================
+Tag name: ctsm5.3.044
+Originator(s): slevis (Samuel Levis,UCAR/TSS,303-665-1310)
+Date: Wed 14 May 2025 11:42:41 AM MDT
+One-line Summary: Introduce time-evolving LEAFCN_TARGET as function of leafcn param
+
+Purpose and description of changes
+----------------------------------
+
+ Motivated by a phd student's project (Emma Hauser, now Professor at UW-Madison) we have introduced time-evolving leafcn as a possible template for other time-evolving parameters.
+
+Significant changes to scientifically-supported configurations
+--------------------------------------------------------------
+
+Does this tag change answers significantly for any of the following physics configurations?
+(Details of any changes will be given in the "Answer changes" section below.)
+
+ [Put an [X] in the box for any configuration with significant answer changes.]
+
+[ ] clm6_0
+
+[ ] clm5_0
+
+[ ] ctsm5_0-nwp
+
+[ ] clm4_5
+
+
+Bugs fixed
+----------
+List of CTSM issues fixed (include CTSM Issue # and description) [one per line]:
+ Resolves #1646 Time evolving parameterization for leaf properties
+
+Notes of particular relevance for developers:
+---------------------------------------------
+Changes to tests or testing:
+ New test in aux_clm that points to an alternate params file with leafcn_co2_slope = 30 (default = 0) to confirm that the leafcn_t_evolving calculation doesn't fail
+
+Testing summary:
+----------------
+
+ [PASS means all tests PASS; OK means tests PASS other than expected fails.]
+
+ regular tests (aux_clm: https://github.com/ESCOMP/CTSM/wiki/System-Testing-Guide#pre-merge-system-testing):
+
+ derecho ----- OK
+ izumi ------- OK
+
+Answer changes
+--------------
+
+Changes answers relative to baseline: No
+ but field lists differ due to new history field LEAFCN_TARGET
+
+Other details
+-------------
+Pull Requests that document the changes (include PR ids):
+ https://github.com/ESCOMP/ctsm/pull/1654
+
+===============================================================
+===============================================================
Tag name: ctsm5.3.043
Originator(s): slevis (Samuel Levis,UCAR/TSS,303-665-1310)
Date: Fri 09 May 2025 12:28:17 PM MDT
diff --git a/doc/ChangeSum b/doc/ChangeSum
index e805a39512..85192e7d5a 100644
--- a/doc/ChangeSum
+++ b/doc/ChangeSum
@@ -1,5 +1,6 @@
Tag Who Date Summary
============================================================================================================================
+ ctsm5.3.044 slevis 05/14/2025 Introduce time-evolving LEAFCN_TARGET as function of leafcn param
ctsm5.3.043 slevis 05/09/2025 Merge b4b-dev
ctsm5.3.042 glemieux 05/08/2025 Update FATES tag, tests and address namelist option bug
ctsm5.3.041 samrabin 04/25/2025 Merge b4b-dev to master
diff --git a/src/biogeochem/CNAllocationMod.F90 b/src/biogeochem/CNAllocationMod.F90
index 6376279a61..254e951cfe 100644
--- a/src/biogeochem/CNAllocationMod.F90
+++ b/src/biogeochem/CNAllocationMod.F90
@@ -23,6 +23,7 @@ module CNAllocationMod
use CNVegCarbonStateType , only : cnveg_carbonstate_type
use CNVegCarbonFluxType , only : cnveg_carbonflux_type
use CNVegStateType , only : cnveg_state_type
+ use CNVegNitrogenStateType, only: cnveg_nitrogenstate_type
use CropReprPoolsMod , only : nrepr
use CNPhenologyMod , only : CropPhase
use CNSharedParamsMod , only : use_fun
@@ -433,7 +434,7 @@ end subroutine calc_crop_allocation_fractions
!-----------------------------------------------------------------------
subroutine calc_allometry(num_soilp, filter_soilp, &
- cnveg_carbonflux_inst, cnveg_state_inst)
+ cnveg_carbonflux_inst, cnveg_state_inst, cnveg_nitrogenstate_inst)
!
! !DESCRIPTION:
! Calculate c_allometry and n_allometry terms based on allocation fractions
@@ -442,6 +443,7 @@ subroutine calc_allometry(num_soilp, filter_soilp, &
integer , intent(in) :: num_soilp ! number of soil patches in filter
integer , intent(in) :: filter_soilp(:) ! filter for soil patches
type(cnveg_carbonflux_type) , intent(in) :: cnveg_carbonflux_inst
+ type(cnveg_nitrogenstate_type) , intent(in) :: cnveg_nitrogenstate_inst
type(cnveg_state_type) , intent(inout) :: cnveg_state_inst
!
! !LOCAL VARIABLES:
@@ -464,7 +466,7 @@ subroutine calc_allometry(num_soilp, filter_soilp, &
croot_stem => pftcon%croot_stem , & ! Input: allocation parameter: new coarse root C per new stem C (gC/gC)
stem_leaf => pftcon%stem_leaf , & ! Input: allocation parameter: new stem c per new leaf C (gC/gC)
flivewd => pftcon%flivewd , & ! Input: allocation parameter: fraction of new wood that is live (phloem and ray parenchyma) (no units)
- leafcn => pftcon%leafcn , & ! Input: leaf C:N (gC/gN)
+ leafcn_t_evolving => cnveg_nitrogenstate_inst%leafcn_t_evolving_patch, & ! Input: leaf C:N (gC/gN)
frootcn => pftcon%frootcn , & ! Input: fine root C:N (gC/gN)
livewdcn => pftcon%livewdcn , & ! Input: live wood (phloem and ray parenchyma) C:N (gC/gN)
deadwdcn => pftcon%deadwdcn , & ! Input: dead wood (xylem and heartwood) C:N (gC/gN)
@@ -503,7 +505,7 @@ subroutine calc_allometry(num_soilp, filter_soilp, &
else
g1 = grperc(ivt(p))
end if
- cnl = leafcn(ivt(p))
+ cnl = leafcn_t_evolving(p)
cnfr = frootcn(ivt(p))
cnlw = livewdcn(ivt(p))
cndw = deadwdcn(ivt(p))
diff --git a/src/biogeochem/CNDriverMod.F90 b/src/biogeochem/CNDriverMod.F90
index 0274fcc87f..b407e07ad5 100644
--- a/src/biogeochem/CNDriverMod.F90
+++ b/src/biogeochem/CNDriverMod.F90
@@ -429,7 +429,7 @@ subroutine CNDriverNoLeaching(bounds,
end if
call calc_allometry(num_bgc_vegp, filter_bgc_vegp, &
- cnveg_carbonflux_inst, cnveg_state_inst)
+ cnveg_carbonflux_inst, cnveg_state_inst, cnveg_nitrogenstate_inst)
call t_stopf('cnalloc')
end if
diff --git a/src/biogeochem/CNFUNMod.F90 b/src/biogeochem/CNFUNMod.F90
index 0af5efe580..cdbe7ba71b 100644
--- a/src/biogeochem/CNFUNMod.F90
+++ b/src/biogeochem/CNFUNMod.F90
@@ -216,7 +216,7 @@ subroutine CNFUNInit (bounds,cnveg_state_inst,cnveg_carbonstate_inst,cnveg_nitro
! Set local pointers
associate(ivt => patch%itype , & ! Input: [integer (:) ] p
- leafcn => pftcon%leafcn , & ! Input: leaf C:N (gC/gN)
+ leafcn_t_evolving => cnveg_nitrogenstate_inst%leafcn_t_evolving_patch , & ! Input: leaf C:N (gC/gN)
leafcn_offset => cnveg_state_inst%leafcn_offset_patch , & ! Output:
! [real(r8) (:) ] Leaf C:N used by FUN
leafc_storage_xfer_acc => cnveg_carbonstate_inst%leafc_storage_xfer_acc_patch , & ! Output: [real(r8) (:)
@@ -249,7 +249,7 @@ subroutine CNFUNInit (bounds,cnveg_state_inst,cnveg_carbonstate_inst,cnveg_nitro
!---
numofyear = nstep/nstep_fun
if (mod(nstep,nstep_fun) == 0) then
- leafcn_offset(bounds%begp:bounds%endp) = leafcn(ivt(bounds%begp:bounds%endp))
+ leafcn_offset(bounds%begp:bounds%endp) = leafcn_t_evolving(bounds%begp:bounds%endp)
storage_cdemand(bounds%begp:bounds%endp) = 0._r8
storage_ndemand(bounds%begp:bounds%endp) = 0._r8
leafn_storage_xfer_acc(bounds%begp:bounds%endp) = 0._r8
@@ -573,7 +573,7 @@ subroutine CNFUN(bounds,num_soilc, filter_soilc,num_soilp&
!--------------------------------------------------------------------
!---------------------------------
associate(ivt => patch%itype , & ! Input: [integer (:) ] p
- leafcn => pftcon%leafcn , & ! Input: leaf C:N (gC/gN)
+ leafcn_t_evolving => cnveg_nitrogenstate_inst%leafcn_t_evolving_patch , & ! Input: leaf C:N (gC/gN)
season_decid => pftcon%season_decid , & ! Input: binary flag for seasonal
! -deciduous leaf habit (0 or 1)
stress_decid => pftcon%stress_decid , & ! Input: binary flag for stress
@@ -1276,7 +1276,7 @@ subroutine CNFUN(bounds,num_soilc, filter_soilc,num_soilp&
litterfall_c_step(p,istp)* fixerfrac,&
litterfall_n_step(p,istp)* fixerfrac,&
total_n_resistance, total_c_spent_retrans,total_c_accounted_retrans, &
- free_n_retrans,paid_for_n_retrans, leafcn(ivt(p)), &
+ free_n_retrans,paid_for_n_retrans, leafcn_t_evolving(p), &
grperc(ivt(p)), plantCN(p))
else
@@ -1307,7 +1307,7 @@ subroutine CNFUN(bounds,num_soilc, filter_soilc,num_soilp&
if (leafn(p) == 0.0_r8) then ! to avoid division by zero
delta_CN = fun_cn_flex_c(ivt(p)) ! Max CN ratio over standard
else
- delta_CN = (leafc(p)+leafc_storage(p))/(leafn(p)+leafn_storage(p)) - leafcn(ivt(p)) ! leaf CN ratio
+ delta_CN = (leafc(p)+leafc_storage(p))/(leafn(p)+leafn_storage(p)) - leafcn_t_evolving(p) ! leaf CN ratio
end if
! C used for uptake is reduced if the cost of N is very high
frac_ideal_C_use = max(0.0_r8,1.0_r8 - (total_N_resistance-fun_cn_flex_a(ivt(p)))/fun_cn_flex_b(ivt(p)) )
diff --git a/src/biogeochem/CNGRespMod.F90 b/src/biogeochem/CNGRespMod.F90
index c152c19c2c..de8b145615 100644
--- a/src/biogeochem/CNGRespMod.F90
+++ b/src/biogeochem/CNGRespMod.F90
@@ -60,7 +60,6 @@ subroutine CNGResp(num_soilp, filter_soilp, cnveg_carbonflux_inst, canopystate_i
woody => pftcon%woody , & ! Input: binary flag for woody lifeform (1=woody, 0=not woody)
grperc => pftcon%grperc , & ! Input: growth respiration parameter
grpnow => pftcon%grpnow , & ! Input: growth respiration parameter
- leafcn => pftcon%leafcn , & ! Input: leaf C:N (gC/gN)
livewdcn => pftcon%livewdcn , & ! Input: live wood (phloem and ray parenchyma) C:N (gC/gN)
laisun => canopystate_inst%laisun_patch , & ! Input: [real(r8) (:)] sunlit projected leaf area index
diff --git a/src/biogeochem/CNGapMortalityMod.F90 b/src/biogeochem/CNGapMortalityMod.F90
index 73ff0bc911..24f0f6b145 100644
--- a/src/biogeochem/CNGapMortalityMod.F90
+++ b/src/biogeochem/CNGapMortalityMod.F90
@@ -163,7 +163,6 @@ subroutine CNGapMortality (bounds, num_soilp, filter_soilp, &
greffic => dgvs_inst%greffic_patch , & ! Input: [real(r8) (:) ]
heatstress => dgvs_inst%heatstress_patch , & ! Input: [real(r8) (:) ]
- leafcn => pftcon%leafcn , & ! Input: [real(r8) (:)] leaf C:N (gC/gN)
livewdcn => pftcon%livewdcn , & ! Input: [real(r8) (:)] live wood (phloem and ray parenchyma) C:N (gC/gN)
laisun => canopystate_inst%laisun_patch , & ! Input: [real(r8) (:) ] sunlit projected leaf area index
laisha => canopystate_inst%laisha_patch , & ! Input: [real(r8) (:) ] shaded projected leaf area index
diff --git a/src/biogeochem/CNPhenologyMod.F90 b/src/biogeochem/CNPhenologyMod.F90
index 5ad4fb1157..ff1e5b1b74 100644
--- a/src/biogeochem/CNPhenologyMod.F90
+++ b/src/biogeochem/CNPhenologyMod.F90
@@ -1387,8 +1387,6 @@ subroutine CNStressDecidPhenology (num_soilp, filter_soilp , &
leaf_long => pftcon%leaf_long , & ! Input: leaf longevity (yrs)
woody => pftcon%woody , & ! Input: binary flag for woody lifeform (1=woody, 0=not woody)
stress_decid => pftcon%stress_decid , & ! Input: binary flag for stress-deciduous leaf habit (0 or 1)
- leafcn => pftcon%leafcn , & ! Input: leaf C:N (gC/gN)
- frootcn => pftcon%frootcn , & ! Input: fine root C:N (gC/gN)
crit_onset_gdd_sf => pftcon%crit_onset_gdd_sf , & ! Input: scale factor for crit_onset_gdd (unitless)
ndays_on => pftcon%ndays_on , & ! Input: number of days to complete leaf onset (days)
@@ -2076,8 +2074,8 @@ subroutine CropPhenology(num_pcropp, filter_pcropp , &
associate( &
ivt => patch%itype , & ! Input: [integer (:) ] patch vegetation type
- leaf_long => pftcon%leaf_long , & ! Input: leaf longevity (yrs)
- leafcn => pftcon%leafcn , & ! Input: leaf C:N (gC/gN)
+ leaf_long => pftcon%leaf_long , & ! Input: leaf longevity (yrs)
+ leafcn_t_evolving => cnveg_nitrogenstate_inst%leafcn_t_evolving_patch, & ! Input: leaf C:N (gC/gN)
manunitro => pftcon%manunitro , & ! Input: max manure to be applied in total (kgN/m2)
minplanttemp => pftcon%minplanttemp , & ! Input:
planttemp => pftcon%planttemp , & ! Input:
@@ -2303,7 +2301,7 @@ subroutine CropPhenology(num_pcropp, filter_pcropp , &
vf(p) = 0._r8
end if
- call PlantCrop(p, leafcn(ivt(p)), jday, kyr, do_plant_normal, &
+ call PlantCrop(p, leafcn_t_evolving(p), jday, kyr, do_plant_normal, &
do_plant_lastchance, do_plant_prescribed, &
temperature_inst, crop_inst, cnveg_state_inst, &
cnveg_carbonstate_inst, cnveg_nitrogenstate_inst, &
@@ -2564,8 +2562,7 @@ subroutine CropPhenology(num_pcropp, filter_pcropp , &
crop_seedc_to_leaf(p) = crop_seedc_to_leaf(p) - leafc_xfer(p)/dt
crop_seedn_to_leaf(p) = crop_seedn_to_leaf(p) - leafn_xfer(p)/dt
leafc_xfer(p) = 0._r8
-
- leafn_xfer(p) = leafc_xfer(p) / leafcn(ivt(p))
+ leafn_xfer(p) = leafc_xfer(p) / leafcn_t_evolving(p)
if (use_c13) then
c13_cnveg_carbonstate_inst%leafc_xfer_patch(p) = 0._r8
endif
@@ -2605,7 +2602,7 @@ subroutine CropPhenology(num_pcropp, filter_pcropp , &
crop_seedn_to_leaf(p) = crop_seedn_to_leaf(p) - leafn_xfer(p)/dt
onset_counter(p) = 0._r8
leafc_xfer(p) = 0._r8
- leafn_xfer(p) = leafc_xfer(p) / leafcn(ivt(p))
+ leafn_xfer(p) = leafc_xfer(p) / leafcn_t_evolving(p)
if (use_c13) then
c13_cnveg_carbonstate_inst%leafc_xfer_patch(p) = 0._r8
endif
@@ -2780,7 +2777,7 @@ subroutine PlantCrop(p, leafcn_in, jday, kyr, do_plant_normal, &
!
! !ARGUMENTS:
integer , intent(in) :: p ! PATCH index running over
- real(r8) , intent(in) :: leafcn_in ! leaf C:N (gC/gN) of this patch's vegetation type (pftcon%leafcn(ivt(p)))
+ real(r8) , intent(in) :: leafcn_in ! leaf C:N (gC/gN) of this patch
integer , intent(in) :: jday ! julian day of the year
integer , intent(in) :: kyr ! current year
logical , intent(in) :: do_plant_normal ! Are all the normal requirements for planting met?
@@ -3391,7 +3388,7 @@ subroutine CNOffsetLitterfall (num_soilp, filter_soilp, &
associate( &
ivt => patch%itype , & ! Input: [integer (:) ] patch vegetation type
- leafcn => pftcon%leafcn , & ! Input: leaf C:N (gC/gN)
+ leafcn_t_evolving => cnveg_nitrogenstate_inst%leafcn_t_evolving_patch , & ! Input: leaf C:N (gC/gN)
biofuel_harvfrac => pftcon%biofuel_harvfrac , & ! Input: cut a fraction of leaf & stem for biofuel (-)
repr_structure_harvfrac => pftcon%repr_structure_harvfrac , & ! Input: fraction of each reproductive structure component that is harvested and sent to the crop products pool
@@ -3743,7 +3740,7 @@ subroutine CNOffsetLitterfall (num_soilp, filter_soilp, &
leafcn_offset(p) = leafc(p)/leafn(p)
end if
else
- leafcn_offset(p) = leafcn(ivt(p))
+ leafcn_offset(p) = leafcn_t_evolving(p)
end if
leafn_to_litter(p) = leafc_to_litter(p)/leafcn_offset(p) - leafn_to_retransn(p)
leafn_to_litter(p) = max(leafn_to_litter(p),0._r8)
@@ -3775,7 +3772,7 @@ subroutine CNOffsetLitterfall (num_soilp, filter_soilp, &
end if
! calculate the leaf N litterfall and retranslocation
leafn_to_litter(p) = leafc_to_litter(p) / lflitcn(ivt(p))
- leafn_to_retransn(p) = (leafc_to_litter(p) / leafcn(ivt(p))) - leafn_to_litter(p)
+ leafn_to_retransn(p) = (leafc_to_litter(p) / leafcn_t_evolving(p)) - leafn_to_litter(p)
if (use_matrixcn) then
if(leafn(p) .gt. 0)then
@@ -3891,7 +3888,7 @@ subroutine CNBackgroundLitterfall (num_soilp, filter_soilp, &
associate( &
ivt => patch%itype , & ! Input: [integer (:) ] patch vegetation type
- leafcn => pftcon%leafcn , & ! Input: leaf C:N (gC/gN)
+ leafcn_t_evolving => cnveg_nitrogenstate_inst%leafcn_t_evolving_patch, & ! Input: leaf C:N (gC/gN)
lflitcn => pftcon%lflitcn , & ! Input: leaf litter C:N (gC/gN)
frootcn => pftcon%frootcn , & ! Input: fine root C:N (gC/gN)
@@ -3977,7 +3974,7 @@ subroutine CNBackgroundLitterfall (num_soilp, filter_soilp, &
leafcn_offset(p) = leafc(p)/leafn(p)
end if
else
- leafcn_offset(p) = leafcn(ivt(p))
+ leafcn_offset(p) = leafcn_t_evolving(p)
end if
leafn_to_litter(p) = leafc_to_litter(p)/leafcn_offset(p) - leafn_to_retransn(p)
leafn_to_litter(p) = max(leafn_to_litter(p),0._r8)
@@ -4006,7 +4003,7 @@ subroutine CNBackgroundLitterfall (num_soilp, filter_soilp, &
end if
! calculate the leaf N litterfall and retranslocation
leafn_to_litter(p) = leafc_to_litter(p) / lflitcn(ivt(p))
- leafn_to_retransn(p) = (leafc_to_litter(p) / leafcn(ivt(p))) - leafn_to_litter(p)
+ leafn_to_retransn(p) = (leafc_to_litter(p) / leafcn_t_evolving(p)) - leafn_to_litter(p)
if (use_matrixcn) then
if(leafn(p) .ne. 0)then
diff --git a/src/biogeochem/CNVegCarbonStateType.F90 b/src/biogeochem/CNVegCarbonStateType.F90
index aee328a45e..142578e656 100644
--- a/src/biogeochem/CNVegCarbonStateType.F90
+++ b/src/biogeochem/CNVegCarbonStateType.F90
@@ -1794,7 +1794,6 @@ subroutine Restart ( this, bounds, ncid, flag, carbon_type, reseed_dead_plants,
use shr_infnan_mod , only : isnan => shr_infnan_isnan, nan => shr_infnan_nan, assignment(=)
use clm_varcon , only : c13ratio, c14ratio
use clm_varctl , only : spinup_state, use_cndv, MM_Nuptake_opt
- use clm_varctl , only : spinup_state, use_cndv, MM_Nuptake_opt
use clm_time_manager , only : is_restart
use landunit_varcon , only : istsoil, istcrop
use spmdMod , only : mpicom
@@ -4637,6 +4636,7 @@ subroutine DynamicPatchAdjustments(this, bounds, &
num_soilp_with_inactive, filter_soilp_with_inactive, &
patch_state_updater, &
leafc_seed, deadstemc_seed, &
+ leafcn_t_evolving, &
conv_cflux, wood_product_cflux, crop_product_cflux, &
dwt_frootc_to_litter, &
dwt_livecrootc_to_litter, &
@@ -4658,6 +4658,7 @@ subroutine DynamicPatchAdjustments(this, bounds, &
type(patch_state_updater_type) , intent(in) :: patch_state_updater
real(r8) , intent(in) :: leafc_seed ! seed amount for leaf C
real(r8) , intent(in) :: deadstemc_seed ! seed amount for deadstem C
+ real(r8) , intent(in) :: leafcn_t_evolving( bounds%begp: ) ! current leaf C:N (gC/gN)
real(r8) , intent(inout) :: conv_cflux( bounds%begp: ) ! patch-level conversion C flux to atm (expressed per unit GRIDCELL area)
real(r8) , intent(inout) :: wood_product_cflux( bounds%begp: ) ! patch-level product C flux (expressed per unit GRIDCELL area)
real(r8) , intent(inout) :: crop_product_cflux( bounds%begp: ) ! patch-level crop product C flux (expressed per unit GRIDCELL area)
@@ -4700,6 +4701,7 @@ subroutine DynamicPatchAdjustments(this, bounds, &
call ComputeSeedAmounts(bounds, &
num_soilp_with_inactive, filter_soilp_with_inactive, &
+ leafcn_t_evolving = leafcn_t_evolving(begp:endp), &
species = this%species, &
leafc_seed = leafc_seed, &
deadstemc_seed = deadstemc_seed, &
diff --git a/src/biogeochem/CNVegComputeSeedMod.F90 b/src/biogeochem/CNVegComputeSeedMod.F90
index 2581d5ba1e..760c2fc767 100644
--- a/src/biogeochem/CNVegComputeSeedMod.F90
+++ b/src/biogeochem/CNVegComputeSeedMod.F90
@@ -39,6 +39,7 @@ module CNVegComputeSeedMod
!-----------------------------------------------------------------------
subroutine ComputeSeedAmounts(bounds, &
num_soilp_with_inactive, filter_soilp_with_inactive, &
+ leafcn_t_evolving, &
species, &
leafc_seed, deadstemc_seed, &
leaf_patch, leaf_storage_patch, leaf_xfer_patch, &
@@ -66,6 +67,7 @@ subroutine ComputeSeedAmounts(bounds, &
integer , intent(in) :: species ! which C/N species we're operating on; should be one of the values in CNSpeciesMod
real(r8) , intent(in) :: leafc_seed ! seed amount for leaf C
real(r8) , intent(in) :: deadstemc_seed ! seed amount for deadstem C
+ real(r8) , intent(in) :: leafcn_t_evolving( bounds%begp: ) ! current leaf C:N (gC/gN)
real(r8) , intent(in) :: leaf_patch( bounds%begp: ) ! current leaf C or N content (g/m2)
real(r8) , intent(in) :: leaf_storage_patch( bounds%begp: ) ! current leaf C or N storage content (g/m2)
real(r8) , intent(in) :: leaf_xfer_patch( bounds%begp: ) ! current leaf C or N xfer content (g/m2)
@@ -88,6 +90,7 @@ subroutine ComputeSeedAmounts(bounds, &
real(r8) :: my_leaf_seed
real(r8) :: my_deadstem_seed
integer :: pft_type
+ real(r8) :: leafcn
real(r8) :: pleaf
real(r8) :: pstor
real(r8) :: pxfer
@@ -118,6 +121,7 @@ subroutine ComputeSeedAmounts(bounds, &
my_deadstem_seed = 0._r8
pft_type = patch%itype(p)
+ leafcn = leafcn_t_evolving(p)
call LeafProportions( &
ignore_current_state = ignore_current_state_patch(p), &
@@ -131,10 +135,10 @@ subroutine ComputeSeedAmounts(bounds, &
if (pft_type /= noveg) then
my_leaf_seed = leafc_seed * &
- SpeciesTypeMultiplier(species, pft_type, COMPONENT_LEAF)
+ SpeciesTypeMultiplier(species, pft_type, leafcn, COMPONENT_LEAF)
if (pftcon%woody(pft_type) == 1._r8) then
my_deadstem_seed = deadstemc_seed * &
- SpeciesTypeMultiplier(species, pft_type, COMPONENT_DEADWOOD)
+ SpeciesTypeMultiplier(species, pft_type, leafcn, COMPONENT_DEADWOOD)
end if
end if
@@ -150,7 +154,7 @@ end subroutine ComputeSeedAmounts
!-----------------------------------------------------------------------
- function SpeciesTypeMultiplier(species, pft_type, component) result(multiplier)
+ function SpeciesTypeMultiplier(species, pft_type, leafcn, component) result(multiplier)
!
! !DESCRIPTION:
! Returns a multiplier based on the species type. This multiplier is
@@ -163,6 +167,7 @@ function SpeciesTypeMultiplier(species, pft_type, component) result(multiplier)
real(r8) :: multiplier ! function result
integer, intent(in) :: species ! which C/N species we're operating on; should be one of the values in CNSpeciesMod
integer, intent(in) :: pft_type
+ real(r8), intent(in) :: leafcn
integer, intent(in) :: component ! which plant component; should be one of the COMPONENT_* parameters defined in this module
!
! !LOCAL VARIABLES:
@@ -188,7 +193,7 @@ function SpeciesTypeMultiplier(species, pft_type, component) result(multiplier)
case (CN_SPECIES_N)
select case (component)
case (COMPONENT_LEAF)
- multiplier = 1._r8 / pftcon%leafcn(pft_type)
+ multiplier = 1._r8 / leafcn
case (COMPONENT_DEADWOOD)
multiplier = 1._r8 / pftcon%deadwdcn(pft_type)
case default
diff --git a/src/biogeochem/CNVegNitrogenStateType.F90 b/src/biogeochem/CNVegNitrogenStateType.F90
index 61bb2d5d16..7ff8e77df9 100644
--- a/src/biogeochem/CNVegNitrogenStateType.F90
+++ b/src/biogeochem/CNVegNitrogenStateType.F90
@@ -17,19 +17,27 @@ module CNVegNitrogenStateType
use ColumnType , only : col
use PatchType , only : patch
use dynPatchStateUpdaterMod, only : patch_state_updater_type
+ use atm2lndType , only : atm2lnd_type
use CNSpeciesMod , only : CN_SPECIES_N
use CNVegComputeSeedMod, only : ComputeSeedAmounts
use CropReprPoolsMod , only : nrepr, get_repr_hist_fname, get_repr_rest_fname, get_repr_longname
+ use ncdio_pio
!
! !PUBLIC TYPES:
implicit none
private
-
+ type :: cnveg_nstate_params_type
+ real(r8) :: leafcn_co2_base ! ppm CO2 for target leaf CN scaling
+ real(r8) :: leafcn_co2_slope ! CO2 effects on target leaf CN scaling (unitless)
+ end type cnveg_nstate_params_type
!
+ type(cnveg_nstate_params_type), public, protected :: params_inst ! params_inst is populated in readParams
+
type, public :: cnveg_nitrogenstate_type
+ real(r8), pointer :: leafcn_t_evolving_patch (:) ! (gC/gN) time evolving leafcn
real(r8), pointer :: reproductiven_patch (:,:) ! (gN/m2) reproductive (e.g., grain) N (crop)
real(r8), pointer :: reproductiven_storage_patch (:,:) ! (gN/m2) reproductive (e.g., grain) N storage (crop)
real(r8), pointer :: reproductiven_xfer_patch (:,:) ! (gN/m2) reproductive (e.g., grain) N transfer (crop)
@@ -218,6 +226,8 @@ module CNVegNitrogenStateType
procedure , private :: InitAllocate
procedure , private :: InitHistory
procedure , private :: InitCold
+ procedure , private :: ReadParams
+ procedure , public :: time_evolv_leafcn ! updates time-evolving leafcn
end type cnveg_nitrogenstate_type
!------------------------------------------------------------------------
@@ -231,10 +241,11 @@ module CNVegNitrogenStateType
!------------------------------------------------------------------------
subroutine Init(this, bounds, &
leafc_patch, leafc_storage_patch, frootc_patch, frootc_storage_patch, &
- deadstemc_patch, alloc_full_veg)
+ deadstemc_patch, alloc_full_veg, params_ncid)
class(cnveg_nitrogenstate_type) :: this
type(bounds_type) , intent(in) :: bounds
+ type(file_desc_t) , intent(inout) :: params_ncid ! pio netCDF file id
real(r8) , intent(in) :: leafc_patch (:) !(begp:)
real(r8) , intent(in) :: leafc_storage_patch (:) !(begp:)
real(r8) , intent(in) :: frootc_patch (:) !(begp:)
@@ -248,6 +259,7 @@ subroutine Init(this, bounds, &
call this%InitCold ( bounds, &
leafc_patch, leafc_storage_patch, frootc_patch, frootc_storage_patch, deadstemc_patch)
end if
+ call this%ReadParams( params_ncid )
end subroutine Init
!------------------------------------------------------------------------
@@ -337,8 +349,8 @@ subroutine InitAllocate(this, bounds, alloc_full_veg)
allocate(this%seedn_grc (begg:endg)) ; this%seedn_grc (:) = nan
allocate(this%totvegn_col (begc:endc)) ; this%totvegn_col (:) = nan
allocate(this%totn_p2c_col (begc:endc)) ; this%totn_p2c_col (:) = nan
-
+ allocate(this%leafcn_t_evolving_patch (begp:endp)) ; this%leafcn_t_evolving_patch (:) = nan
if(use_matrixcn)then
allocate(this%leafn0_patch (begp:endp)) ; this%leafn0_patch (:) = nan
allocate(this%leafn0_storage_patch (begp:endp)) ; this%leafn0_storage_patch (:) = nan
@@ -492,6 +504,11 @@ subroutine InitHistory(this, bounds)
!-------------------------------
! patch state variables
!-------------------------------
+
+ this%leafcn_t_evolving_patch(begp:endp) = spval
+ call hist_addfld1d (fname='LEAFCN_TARGET', units='gC/gN', &
+ avgflag='A', long_name='Target leaf C:N; compare against leafC/leafN', &
+ ptr_patch=this%leafcn_t_evolving_patch)
if (use_crop) then
this%reproductiven_patch(begp:endp,:) = spval
@@ -828,6 +845,8 @@ subroutine InitCold(this, bounds, &
do p = bounds%begp,bounds%endp
+ this%leafcn_t_evolving_patch(p) = pftcon%leafcn(patch%itype(p))
+
l = patch%landunit(p)
if (lun%itype(l) == istsoil .or. lun%itype(l) == istcrop) then
@@ -847,11 +866,11 @@ subroutine InitCold(this, bounds, &
end if
end if
else
- this%leafn_patch(p) = leafc_patch(p) / pftcon%leafcn(patch%itype(p))
- this%leafn_storage_patch(p) = leafc_storage_patch(p) / pftcon%leafcn(patch%itype(p))
+ this%leafn_patch(p) = leafc_patch(p) / this%leafcn_t_evolving_patch(p)
+ this%leafn_storage_patch(p) = leafc_storage_patch(p) / this%leafcn_t_evolving_patch(p)
if(use_matrixcn)then
- this%matrix_cap_leafn_patch(p) = leafc_patch(p) / pftcon%leafcn(patch%itype(p))
- this%matrix_cap_leafn_storage_patch(p) = leafc_storage_patch(p) / pftcon%leafcn(patch%itype(p))
+ this%matrix_cap_leafn_patch(p) = leafc_patch(p) / this%leafcn_t_evolving_patch(p)
+ this%matrix_cap_leafn_storage_patch(p) = leafc_storage_patch(p) / this%leafcn_t_evolving_patch(p)
end if
if (MM_Nuptake_opt .eqv. .true.) then
this%frootn_patch(p) = frootc_patch(p) / pftcon%frootcn(patch%itype(p))
@@ -1108,7 +1127,6 @@ subroutine Restart ( this, bounds, ncid, flag, leafc_patch, &
!
! !USES:
use restUtilMod
- use ncdio_pio
use clm_varctl , only : spinup_state, use_cndv
use clm_time_manager , only : get_nstep, is_restart
use clm_varctl , only : MM_Nuptake_opt
@@ -1815,11 +1833,11 @@ subroutine Restart ( this, bounds, ncid, flag, leafc_patch, &
end if
end if
else
- this%leafn_patch(p) = leafc_patch(p) / pftcon%leafcn(patch%itype(p))
- this%leafn_storage_patch(p) = leafc_storage_patch(p) / pftcon%leafcn(patch%itype(p))
+ this%leafn_patch(p) = leafc_patch(p) / this%leafcn_t_evolving_patch(p)
+ this%leafn_storage_patch(p) = leafc_storage_patch(p) / this%leafcn_t_evolving_patch(p)
if(use_matrixcn)then
- this%matrix_cap_leafn_patch(p) = leafc_patch(p) / pftcon%leafcn(patch%itype(p))
- this%matrix_cap_leafn_storage_patch(p) = leafc_storage_patch(p) / pftcon%leafcn(patch%itype(p))
+ this%matrix_cap_leafn_patch(p) = leafc_patch(p) / this%leafcn_t_evolving_patch(p)
+ this%matrix_cap_leafn_storage_patch(p) = leafc_storage_patch(p) / this%leafcn_t_evolving_patch(p)
end if
if (MM_Nuptake_opt .eqv. .true.) then
this%frootn_patch(p) = frootc_patch(p) / pftcon%frootcn(patch%itype(p))
@@ -1976,6 +1994,7 @@ subroutine SetValues ( this, &
do fi = 1,num_patch
i = filter_patch(fi)
+ this%leafcn_t_evolving_patch(i) = value_patch
this%leafn_patch(i) = value_patch
this%leafn_storage_patch(i) = value_patch
this%leafn_xfer_patch(i) = value_patch
@@ -2276,6 +2295,73 @@ subroutine Summary_nitrogenstate(this, bounds, num_soilc, filter_soilc, num_soil
end subroutine Summary_nitrogenstate
+ !-----------------------------------------------------------------------
+ subroutine ReadParams ( this, ncid )
+ !
+ ! !USES:
+ use paramUtilMod, only: readNcdioScalar
+
+ implicit none
+
+ ! !ARGUMENTS:
+ class(cnveg_nitrogenstate_type) :: this
+ type(file_desc_t), intent(inout) :: ncid ! pio netCDF file id
+ !
+ ! !LOCAL VARIABLES:
+ !-----------------------------------------------------------------------
+
+ ! read in parameters
+
+ ! read in the scalar parameters
+
+ ! ppm CO2 for target leaf CN scaling (ppmv)
+ call readNcdioScalar(ncid, 'leafcn_co2_base', sourcefile, params_inst%leafcn_co2_base)
+ ! CO2 effects on target leaf CN scaling (unitless)
+ call readNcdioScalar(ncid, 'leafcn_co2_slope', sourcefile, params_inst%leafcn_co2_slope)
+
+ end subroutine ReadParams
+
+ !-----------------------------------------------------------------------
+ subroutine time_evolv_leafcn(this, bounds, num_bgc_vegp, filter_bgc_vegp, atm2lnd_inst)
+ !
+ ! AUTHOR: slevis
+ !
+ ! !DESCRIPTION:
+ ! Update time-evolving parameters
+ !
+ ! Calculate time evolving leafcn from co2_ppmv and three paramfile
+ ! parameters. Of the three parameters, leafcn_co2_slope is set to 0
+ ! (as of ctsm5.4) so leafcn_t_evolving_patch defaults to the values of
+ ! paramfile parameter leafcn
+ ! !USES:
+ use pftconMod, only : pftcon
+ use clm_time_manager, only : is_first_step
+ !
+ ! !ARGUMENTS:
+ class(cnveg_nitrogenstate_type) :: this
+ type(bounds_type), intent(in) :: bounds
+ integer, intent(in) :: num_bgc_vegp ! number of veg patches in filter
+ integer, intent(in) :: filter_bgc_vegp(:) ! filter for veg patches
+ type(atm2lnd_type), intent(in) :: atm2lnd_inst
+ !
+ ! !LOCAL VARIABLES:
+ integer :: g, c, p, fp ! indices
+ real(r8) :: co2_ppmv ! atm co2 concentration
+ !-----------------------------------------------------------------------
+
+ ! Loop to get leafcn_col
+ do fp = 1, num_bgc_vegp
+ p = filter_bgc_vegp(fp)
+ c = patch%column(p)
+ g = patch%gridcell(p)
+ co2_ppmv = 1.e6_r8 * atm2lnd_inst%forc_pco2_grc(g) / &
+ atm2lnd_inst%forc_pbot_not_downscaled_grc(g)
+ this%leafcn_t_evolving_patch(p) = pftcon%leafcn(patch%itype(p)) + &
+ max(params_inst%leafcn_co2_slope * log(co2_ppmv / params_inst%leafcn_co2_base), 0._r8)
+ end do
+
+ end subroutine time_evolv_leafcn
+
!-----------------------------------------------------------------------
subroutine DynamicPatchAdjustments(this, bounds, &
num_soilp_with_inactive, filter_soilp_with_inactive, &
@@ -2323,8 +2409,6 @@ subroutine DynamicPatchAdjustments(this, bounds, &
real(r8) :: seed_leafn_storage_patch(bounds%begp:bounds%endp)
real(r8) :: seed_leafn_xfer_patch(bounds%begp:bounds%endp)
real(r8) :: seed_deadstemn_patch(bounds%begp:bounds%endp)
-
- character(len=*), parameter :: subname = 'DynamicPatchAdjustments'
!-----------------------------------------------------------------------
begp = bounds%begp
@@ -2344,6 +2428,7 @@ subroutine DynamicPatchAdjustments(this, bounds, &
call ComputeSeedAmounts(bounds, &
num_soilp_with_inactive, filter_soilp_with_inactive, &
+ leafcn_t_evolving = this%leafcn_t_evolving_patch(begp:endp), &
species = CN_SPECIES_N, &
leafc_seed = leafc_seed, &
deadstemc_seed = deadstemc_seed, &
diff --git a/src/biogeochem/CNVegetationFacade.F90 b/src/biogeochem/CNVegetationFacade.F90
index dd20ce50a2..47099708f4 100644
--- a/src/biogeochem/CNVegetationFacade.F90
+++ b/src/biogeochem/CNVegetationFacade.F90
@@ -282,7 +282,7 @@ subroutine Init(this, bounds, NLFilename, nskip_steps, params_ncid)
this%cnveg_carbonstate_inst%frootc_patch(begp:endp), &
this%cnveg_carbonstate_inst%frootc_storage_patch(begp:endp), &
this%cnveg_carbonstate_inst%deadstemc_patch(begp:endp), &
- alloc_full_veg=alloc_full_veg)
+ alloc_full_veg=alloc_full_veg, params_ncid=params_ncid)
call this%cnveg_nitrogenflux_inst%Init(bounds,alloc_full_veg=alloc_full_veg)
call this%c_products_inst%Init(bounds, species_non_isotope_type('C'))
diff --git a/src/biogeochem/NutrientCompetitionCLM45defaultMod.F90 b/src/biogeochem/NutrientCompetitionCLM45defaultMod.F90
index 0980ff5378..82dceef664 100644
--- a/src/biogeochem/NutrientCompetitionCLM45defaultMod.F90
+++ b/src/biogeochem/NutrientCompetitionCLM45defaultMod.F90
@@ -16,6 +16,7 @@ module NutrientCompetitionCLM45defaultMod
use LandunitType , only : lun
use ColumnType , only : col
use PatchType , only : patch
+ use CNVegNitrogenStateType, only : cnveg_nitrogenstate_type
use NutrientCompetitionMethodMod, only : nutrient_competition_method_type
use CropReprPoolsMod , only : nrepr
use CNPhenologyMod , only : CropPhase
@@ -89,7 +90,6 @@ subroutine calc_plant_nutrient_competition (this, &
use CanopyStateType , only : canopystate_type
use CNVegCarbonStateType , only : cnveg_carbonstate_type
use CNVegCarbonFluxType , only : cnveg_carbonflux_type
- use CNVegNitrogenStateType, only : cnveg_nitrogenstate_type
use CNVegNitrogenFluxType , only : cnveg_nitrogenflux_type
use SoilBiogeochemNitrogenStateType, only : soilbiogeochem_nitrogenstate_type
!
@@ -113,7 +113,7 @@ subroutine calc_plant_nutrient_competition (this, &
call this%calc_plant_cn_alloc (bounds, num_soilp, filter_soilp, &
cnveg_state_inst, crop_inst, canopystate_inst, &
cnveg_carbonstate_inst, cnveg_carbonflux_inst, c13_cnveg_carbonflux_inst, &
- c14_cnveg_carbonflux_inst, cnveg_nitrogenflux_inst, &
+ c14_cnveg_carbonflux_inst, cnveg_nitrogenflux_inst, cnveg_nitrogenstate_inst, &
fpg_col=fpg_col(bounds%begc:bounds%endc))
end subroutine calc_plant_nutrient_competition
@@ -122,7 +122,7 @@ end subroutine calc_plant_nutrient_competition
subroutine calc_plant_cn_alloc (this, bounds, num_soilp, filter_soilp, &
cnveg_state_inst, crop_inst, canopystate_inst, &
cnveg_carbonstate_inst, cnveg_carbonflux_inst, c13_cnveg_carbonflux_inst, &
- c14_cnveg_carbonflux_inst, cnveg_nitrogenflux_inst, fpg_col)
+ c14_cnveg_carbonflux_inst, cnveg_nitrogenflux_inst, cnveg_nitrogenstate_inst, fpg_col)
!
! !USES:
use pftconMod , only : pftcon, npcropmin
@@ -150,6 +150,7 @@ subroutine calc_plant_cn_alloc (this, bounds, num_soilp, filter_soilp, &
type(cnveg_carbonflux_type) , intent(inout) :: c13_cnveg_carbonflux_inst
type(cnveg_carbonflux_type) , intent(inout) :: c14_cnveg_carbonflux_inst
type(cnveg_nitrogenflux_type) , intent(inout) :: cnveg_nitrogenflux_inst
+ type(cnveg_nitrogenstate_type) , intent(in) :: cnveg_nitrogenstate_inst
real(r8) , intent(in) :: fpg_col(bounds%begc:)
!
! !LOCAL VARIABLES:
@@ -177,7 +178,7 @@ subroutine calc_plant_cn_alloc (this, bounds, num_soilp, filter_soilp, &
croot_stem => pftcon%croot_stem , & ! Input: allocation parameter: new coarse root C per new stem C (gC/gC)
stem_leaf => pftcon%stem_leaf , & ! Input: allocation parameter: new stem c per new leaf C (gC/gC)
flivewd => pftcon%flivewd , & ! Input: allocation parameter: fraction of new wood that is live (phloem and ray parenchyma) (no units)
- leafcn => pftcon%leafcn , & ! Input: leaf C:N (gC/gN)
+ leafcn_t_evolving => cnveg_nitrogenstate_inst%leafcn_t_evolving_patch , & ! Input: leaf C:N (gC/gN)
frootcn => pftcon%frootcn , & ! Input: fine root C:N (gC/gN)
livewdcn => pftcon%livewdcn , & ! Input: live wood (phloem and ray parenchyma) C:N (gC/gN)
deadwdcn => pftcon%deadwdcn , & ! Input: dead wood (xylem and heartwood) C:N (gC/gN)
@@ -274,7 +275,7 @@ subroutine calc_plant_cn_alloc (this, bounds, num_soilp, filter_soilp, &
f4 = flivewd(ivt(p))
g1 = grperc(ivt(p))
g2 = grpnow(ivt(p))
- cnl = leafcn(ivt(p))
+ cnl = leafcn_t_evolving(p)
cnfr = frootcn(ivt(p))
cnlw = livewdcn(ivt(p))
cndw = deadwdcn(ivt(p))
@@ -447,7 +448,6 @@ subroutine calc_plant_nutrient_demand(this, bounds, &
use CropType , only : crop_type
use CNVegStateType , only : cnveg_state_type
use CNVegCarbonStateType , only : cnveg_carbonstate_type
- use CNVegNitrogenStateType , only : cnveg_nitrogenstate_type
use CNVegCarbonFluxType , only : cnveg_carbonflux_type
use CNVegNitrogenFluxType , only : cnveg_nitrogenflux_type
use SoilBiogeochemCarbonFluxType, only : soilbiogeochem_carbonflux_type
@@ -512,7 +512,6 @@ subroutine calc_plant_nitrogen_demand(this, bounds, &
use CropType , only : crop_type
use CNVegStateType , only : cnveg_state_type
use CNVegCarbonStateType , only : cnveg_carbonstate_type
- use CNVegNitrogenStateType , only : cnveg_nitrogenstate_type
use CNVegCarbonFluxType , only : cnveg_carbonflux_type
use CNVegNitrogenFluxType , only : cnveg_nitrogenflux_type
use CNSharedParamsMod , only : use_fun
@@ -552,7 +551,7 @@ subroutine calc_plant_nitrogen_demand(this, bounds, &
associate( &
ivt => patch%itype , & ! Input: [integer (:) ] patch vegetation type
- leafcn => pftcon%leafcn , & ! Input: leaf C:N (gC/gN)
+ leafcn_t_evolving => cnveg_nitrogenstate_inst%leafcn_t_evolving_patch , & ! Input: leaf C:N (gC/gN)
frootcn => pftcon%frootcn , & ! Input: fine root C:N (gC/gN)
livewdcn => pftcon%livewdcn , & ! Input: live wood (phloem and ray parenchyma) C:N (gC/gN)
graincn => pftcon%graincn , & ! Input: grain C:N (gC/gN)
@@ -645,7 +644,7 @@ subroutine calc_plant_nitrogen_demand(this, bounds, &
if (grain_flag(p) == 0._r8)then
if(.not.use_fun) then
t1 = 1 / dt
- leafn_to_retransn(p) = t1 * ((leafc(p) / leafcn(ivt(p))) - (leafc(p) / &
+ leafn_to_retransn(p) = t1 * ((leafc(p) / leafcn_t_evolving(p)) - (leafc(p) / &
fleafcn(ivt(p))))
livestemn_to_retransn(p) = t1 * ((livestemc(p) / livewdcn(ivt(p))) - (livestemc(p) / &
fstemcn(ivt(p))))
diff --git a/src/biogeochem/NutrientCompetitionFlexibleCNMod.F90 b/src/biogeochem/NutrientCompetitionFlexibleCNMod.F90
index 993c0a2e9a..00e8a00b77 100644
--- a/src/biogeochem/NutrientCompetitionFlexibleCNMod.F90
+++ b/src/biogeochem/NutrientCompetitionFlexibleCNMod.F90
@@ -275,7 +275,7 @@ subroutine calc_plant_cn_alloc(this, bounds, num_soilp, filter_soilp, &
croot_stem => pftcon%croot_stem , & ! Input: allocation parameter: new coarse root C per new stem C (gC/gC)
stem_leaf => pftcon%stem_leaf , & ! Input: allocation parameter: new stem c per new leaf C (gC/gC)
flivewd => pftcon%flivewd , & ! Input: allocation parameter: fraction of new wood that is live (phloem and ray parenchyma) (no units)
- leafcn => pftcon%leafcn , & ! Input: leaf C:N (gC/gN)
+ leafcn_t_evolving => cnveg_nitrogenstate_inst%leafcn_t_evolving_patch , & ! Input: leaf C:N (gC/gN)
frootcn => pftcon%frootcn , & ! Input: fine root C:N (gC/gN)
livewdcn => pftcon%livewdcn , & ! Input: live wood (phloem and ray parenchyma) C:N (gC/gN)
fcur2 => pftcon%fcur , & ! Input: allocation parameter: fraction of allocation that goes to currently displayed growth, remainder to storage
@@ -635,6 +635,7 @@ subroutine calc_plant_cn_alloc(this, bounds, num_soilp, filter_soilp, &
f3 = f3, &
f4 = f4, &
f5 = f5, &
+ leafcn_t_evolving = leafcn_t_evolving(p), &
! Outputs
npool_to_leafn = npool_to_leafn(p), &
@@ -728,7 +729,7 @@ subroutine calc_plant_cn_alloc(this, bounds, num_soilp, filter_soilp, &
end if
end if
- leafcn_max = leafcn(ivt(p)) + 15.0_r8
+ leafcn_max = leafcn_t_evolving(p) + 15.0_r8
frootcn_max = frootcn(ivt(p)) + 15.0_r8
! Note that for high CN ratio stress the plant part does not retranslocate nitrogen as the plant part will need the N
@@ -930,7 +931,7 @@ end subroutine calc_plant_cn_alloc
!-----------------------------------------------------------------------
subroutine calc_npool_to_components_flexiblecn( &
- npool, ivt, nlc, fcur, f1, f2, f3, f4, f5, &
+ npool, ivt, nlc, fcur, f1, f2, f3, f4, f5, leafcn_t_evolving, &
npool_to_leafn, npool_to_leafn_storage, &
npool_to_frootn, npool_to_frootn_storage, &
npool_to_livestemn, npool_to_livestemn_storage, &
@@ -952,6 +953,7 @@ subroutine calc_npool_to_components_flexiblecn( &
real(r8), intent(in) :: f3 ! C allocation parameter - stem:leaf ratio
real(r8), intent(in) :: f4 ! C allocation parameter - fraction of new wood that is live
real(r8), intent(in) :: f5(:) ! C allocation parameter - repr:leaf ratio for each crop reproductive pool
+ real(r8), intent(in) :: leafcn_t_evolving ! leaf C:N (gC/gN)
! Each of the following output variables is in units of gN/m2/s; they are
! intent(inout) because some may remain unchanged in some circumstances.
@@ -1018,7 +1020,6 @@ subroutine calc_npool_to_components_flexiblecn( &
associate( &
woody => pftcon%woody , & ! Input: binary flag for woody lifeform (1=woody, 0=not woody)
- leafcn => pftcon%leafcn , & ! Input: leaf C:N (gC/gN)
frootcn => pftcon%frootcn , & ! Input: fine root C:N (gC/gN)
livewdcn => pftcon%livewdcn , & ! Input: live wood (phloem and ray parenchyma) C:N (gC/gN)
deadwdcn => pftcon%deadwdcn , & ! Input: dead wood (xylem and heartwood) C:N (gC/gN)
@@ -1027,7 +1028,7 @@ subroutine calc_npool_to_components_flexiblecn( &
dt = get_step_size_real()
- cnl = leafcn(ivt)
+ cnl = leafcn_t_evolving
cnfr = frootcn(ivt)
cnlw = livewdcn(ivt)
cndw = deadwdcn(ivt)
@@ -1455,7 +1456,7 @@ subroutine calc_plant_nitrogen_demand(this, bounds, &
associate( &
ivt => patch%itype , & ! Input: [integer (:) ] patch vegetation type
- leafcn => pftcon%leafcn , & ! Input: leaf C:N (gC/gN)
+ leafcn_t_evolving => cnveg_nitrogenstate_inst%leafcn_t_evolving_patch , & ! Input: leaf C:N (gC/gN)
fleafcn => pftcon%fleafcn , & ! Input: leaf c:n during organ fill
ffrootcn => pftcon%ffrootcn , & ! Input: froot c:n during organ fill
fstemcn => pftcon%fstemcn , & ! Input: stem c:n during organ fill
@@ -1520,8 +1521,8 @@ subroutine calc_plant_nitrogen_demand(this, bounds, &
this%actual_leafcn(p) = leafc(p) / leafn(p)
end if
- leafcn_min = leafcn(ivt(p)) - 10.0_r8
- leafcn_max = leafcn(ivt(p)) + 10.0_r8
+ leafcn_min = leafcn_t_evolving(p) - 10.0_r8
+ leafcn_max = leafcn_t_evolving(p) + 10.0_r8
this%actual_leafcn(p) = max( this%actual_leafcn(p), leafcn_min-0.0001_r8 )
this%actual_leafcn(p) = min( this%actual_leafcn(p), leafcn_max )
@@ -1563,7 +1564,6 @@ subroutine calc_plant_nitrogen_demand(this, bounds, &
! retranslocated N deployment depends on seasonal cycle of potential GPP
! (requires one year run to accumulate demand)
-
tempsum_potential_gpp(p) = tempsum_potential_gpp(p) + gpp(p)
! Adding the following line to carry max retransn info to CN Annual Update
diff --git a/src/biogeochem/dynConsBiogeochemMod.F90 b/src/biogeochem/dynConsBiogeochemMod.F90
index f8cff29911..445d1a7bda 100644
--- a/src/biogeochem/dynConsBiogeochemMod.F90
+++ b/src/biogeochem/dynConsBiogeochemMod.F90
@@ -445,6 +445,7 @@ subroutine dyn_cnbal_patch(bounds, &
patch_state_updater, &
leafc_seed = leafc_seed, &
deadstemc_seed = deadstemc_seed, &
+ leafcn_t_evolving = cnveg_nitrogenstate_inst%leafcn_t_evolving_patch(begp:endp), &
conv_cflux = conv_cflux(begp:endp), &
wood_product_cflux = wood_product_cflux(begp:endp), &
crop_product_cflux = crop_product_cflux(begp:endp), &
@@ -468,6 +469,7 @@ subroutine dyn_cnbal_patch(bounds, &
patch_state_updater, &
leafc_seed = leafc_seed, &
deadstemc_seed = deadstemc_seed, &
+ leafcn_t_evolving = cnveg_nitrogenstate_inst%leafcn_t_evolving_patch(begp:endp), &
conv_cflux = conv_c13flux(begp:endp), &
wood_product_cflux = wood_product_c13flux(begp:endp), &
crop_product_cflux = crop_product_c13flux(begp:endp), &
@@ -493,6 +495,7 @@ subroutine dyn_cnbal_patch(bounds, &
patch_state_updater, &
leafc_seed = leafc_seed, &
deadstemc_seed = deadstemc_seed, &
+ leafcn_t_evolving = cnveg_nitrogenstate_inst%leafcn_t_evolving_patch(begp:endp), &
conv_cflux = conv_c14flux(begp:endp), &
wood_product_cflux = wood_product_c14flux(begp:endp), &
crop_product_cflux = crop_product_c14flux(begp:endp), &
diff --git a/src/biogeochem/test/CNVegComputeSeed_test/test_ComputeSeedAmounts.pf b/src/biogeochem/test/CNVegComputeSeed_test/test_ComputeSeedAmounts.pf
index be87b4c989..c0911fb9ee 100644
--- a/src/biogeochem/test/CNVegComputeSeed_test/test_ComputeSeedAmounts.pf
+++ b/src/biogeochem/test/CNVegComputeSeed_test/test_ComputeSeedAmounts.pf
@@ -92,6 +92,7 @@ contains
real(r8), intent(out), optional :: seed_leaf_xfer
real(r8), intent(out), optional :: seed_deadstem
+ real(r8) :: leafcn_t_evolving_patch(bounds%begp:bounds%endp)
real(r8) :: leaf_patch(bounds%begp:bounds%endp)
real(r8) :: leaf_storage_patch(bounds%begp:bounds%endp)
real(r8) :: leaf_xfer_patch(bounds%begp:bounds%endp)
@@ -102,6 +103,7 @@ contains
real(r8) :: seed_leaf_xfer_patch(bounds%begp:bounds%endp)
real(r8) :: seed_deadstem_patch(bounds%begp:bounds%endp)
+ leafcn_t_evolving_patch(:) = 10._r8
leaf_patch(:) = 0._r8
leaf_patch(POI) = LEAF_POI
leaf_storage_patch(:) = 0._r8
@@ -117,6 +119,7 @@ contains
call ComputeSeedAmounts(bounds, &
this%numf, this%filter, &
+ leafcn_t_evolving = leafcn_t_evolving_patch, &
species = species, &
leafc_seed = LEAFC_SEED, &
deadstemc_seed = DEADSTEMC_SEED, &
diff --git a/src/biogeophys/CanopyFluxesMod.F90 b/src/biogeophys/CanopyFluxesMod.F90
index 0c5431728d..afe665e6d1 100644
--- a/src/biogeophys/CanopyFluxesMod.F90
+++ b/src/biogeophys/CanopyFluxesMod.F90
@@ -41,6 +41,7 @@ module CanopyFluxesMod
use HumanIndexMod , only : humanindex_type
use ch4Mod , only : ch4_type
use PhotosynthesisMod , only : photosyns_type
+ use CNVegnitrogenstateType, only : cnveg_nitrogenstate_type
use GridcellType , only : grc
use ColumnType , only : col
use PatchType , only : patch
@@ -192,7 +193,7 @@ subroutine CanopyFluxes(bounds, num_exposedvegp, filter_exposedvegp,
energyflux_inst, frictionvel_inst, soilstate_inst, solarabs_inst, surfalb_inst, &
temperature_inst, waterfluxbulk_inst, waterstatebulk_inst, &
waterdiagnosticbulk_inst, wateratm2lndbulk_inst, ch4_inst, ozone_inst, &
- photosyns_inst, &
+ photosyns_inst, cnveg_nitrogenstate_inst, &
humanindex_inst, soil_water_retention_curve, &
downreg_patch, leafn_patch, froot_carbon, croot_carbon)
!
@@ -264,6 +265,7 @@ subroutine CanopyFluxes(bounds, num_exposedvegp, filter_exposedvegp,
type(ch4_type) , intent(inout) :: ch4_inst
class(ozone_base_type) , intent(inout) :: ozone_inst
type(photosyns_type) , intent(inout) :: photosyns_inst
+ type(cnveg_nitrogenstate_type) , intent(in) :: cnveg_nitrogenstate_inst
type(humanindex_type) , intent(inout) :: humanindex_inst
class(soil_water_retention_curve_type) , intent(in) :: soil_water_retention_curve
real(r8), intent(in) :: downreg_patch(bounds%begp:) ! fractional reduction in GPP due to N limitation (dimensionless)
@@ -1126,6 +1128,7 @@ subroutine CanopyFluxes(bounds, num_exposedvegp, filter_exposedvegp,
svpts(begp:endp), eah(begp:endp), o2(begp:endp), co2(begp:endp), rb(begp:endp), bsun(begp:endp), &
bsha(begp:endp), btran(begp:endp), dayl_factor(begp:endp), leafn_patch(begp:endp), &
qsatl(begp:endp), qaf(begp:endp), &
+ cnveg_nitrogenstate_inst, &
atm2lnd_inst, temperature_inst, soilstate_inst, waterdiagnosticbulk_inst, surfalb_inst, solarabs_inst, &
canopystate_inst, ozone_inst, photosyns_inst, waterfluxbulk_inst, &
froot_carbon(begp:endp), croot_carbon(begp:endp))
@@ -1133,6 +1136,7 @@ subroutine CanopyFluxes(bounds, num_exposedvegp, filter_exposedvegp,
call Photosynthesis (bounds, fn, filterp, &
svpts(begp:endp), eah(begp:endp), o2(begp:endp), co2(begp:endp), rb(begp:endp), btran(begp:endp), &
dayl_factor(begp:endp), leafn_patch(begp:endp), &
+ cnveg_nitrogenstate_inst, &
atm2lnd_inst, temperature_inst, surfalb_inst, solarabs_inst, &
canopystate_inst, ozone_inst, photosyns_inst, phase='sun')
endif
@@ -1147,6 +1151,7 @@ subroutine CanopyFluxes(bounds, num_exposedvegp, filter_exposedvegp,
call Photosynthesis (bounds, fn, filterp, &
svpts(begp:endp), eah(begp:endp), o2(begp:endp), co2(begp:endp), rb(begp:endp), btran(begp:endp), &
dayl_factor(begp:endp), leafn_patch(begp:endp), &
+ cnveg_nitrogenstate_inst, &
atm2lnd_inst, temperature_inst, surfalb_inst, solarabs_inst, &
canopystate_inst, ozone_inst, photosyns_inst, phase='sha')
end if
diff --git a/src/biogeophys/LunaMod.F90 b/src/biogeophys/LunaMod.F90
index 5641846309..950fefbc32 100644
--- a/src/biogeophys/LunaMod.F90
+++ b/src/biogeophys/LunaMod.F90
@@ -291,7 +291,6 @@ subroutine Update_Photosynthesis_Capacity(bounds, fn, filterp, &
associate( &
c3psn => pftcon%c3psn , & ! photosynthetic pathway: 0. = c4, 1. = c3
slatop => pftcon%slatop , & ! specific leaf area at top of canopy, projected area basis [m^2/gC]
- leafcn => pftcon%leafcn , & ! leaf C:N (gC/gN)
forc_pbot10 => atm2lnd_inst%forc_pbot240_downscaled_patch , & ! Input: [real(r8) (:) ] 10 day mean atmospheric pressure(Pa)
CO2_p240 => atm2lnd_inst%forc_pco2_240_patch , & ! Input: [real(r8) (:) ] 10-day mean CO2 partial pressure (Pa)
O2_p240 => atm2lnd_inst%forc_po2_240_patch , & ! Input: [real(r8) (:) ] 10-day mean O2 partial pressure (Pa)
diff --git a/src/biogeophys/PhotosynthesisMod.F90 b/src/biogeophys/PhotosynthesisMod.F90
index 2a0ce2d57c..b8fd577382 100644
--- a/src/biogeophys/PhotosynthesisMod.F90
+++ b/src/biogeophys/PhotosynthesisMod.F90
@@ -24,6 +24,7 @@ module PhotosynthesisMod
use CIsoAtmTimeseriesMod, only : C14BombSpike, use_c14_bombspike, C13TimeSeries, use_c13_timeseries, nsectors_c14
use atm2lndType , only : atm2lnd_type
use CanopyStateType , only : canopystate_type
+ use CNVegnitrogenstateType, only : cnveg_nitrogenstate_type
use WaterDiagnosticBulkType , only : waterdiagnosticbulk_type
use WaterFluxBulkType , only : waterfluxbulk_type
use SoilStateType , only : soilstate_type
@@ -1220,6 +1221,7 @@ end subroutine NewPatchInit
subroutine Photosynthesis ( bounds, fn, filterp, &
esat_tv, eair, oair, cair, rb, btran, &
dayl_factor, leafn, &
+ cnveg_nitrogenstate_inst, &
atm2lnd_inst, temperature_inst, surfalb_inst, solarabs_inst, &
canopystate_inst, ozone_inst, photosyns_inst, phase)
!
@@ -1249,6 +1251,7 @@ subroutine Photosynthesis ( bounds, fn, filterp, &
real(r8) , intent(in) :: btran( bounds%begp: ) ! transpiration wetness factor (0 to 1) [pft]
real(r8) , intent(in) :: dayl_factor( bounds%begp: ) ! scalar (0-1) for daylength
real(r8) , intent(in) :: leafn( bounds%begp: ) ! leaf N (gN/m2)
+ type(cnveg_nitrogenstate_type), intent(in) :: cnveg_nitrogenstate_inst
type(atm2lnd_type) , intent(in) :: atm2lnd_inst
type(temperature_type) , intent(in) :: temperature_inst
type(surfalb_type) , intent(in) :: surfalb_inst
@@ -1352,6 +1355,7 @@ subroutine Photosynthesis ( bounds, fn, filterp, &
real(r8) :: sum_nscaler
real(r8) :: total_lai
+ real(r8) :: leafcn_local
integer :: nptreemax
real(r8) :: dtime ! land model time step (sec)
@@ -1544,13 +1548,17 @@ subroutine Photosynthesis ( bounds, fn, filterp, &
do f = 1, fn
p = filterp(f)
- if (lnc_opt .eqv. .false.) then
+ if (.not. lnc_opt) then
! Leaf nitrogen concentration at the top of the canopy (g N leaf / m**2 leaf)
-
- if ( (slatop(patch%itype(p)) *leafcn(patch%itype(p))) .le. 0.0_r8)then
+ if (use_cn) then ! use the leafcn calculated in subroutine time_evolv_leafcn
+ leafcn_local = cnveg_nitrogenstate_inst%leafcn_t_evolving_patch(p)
+ else ! use the leafcn prescribed in the paramfile
+ leafcn_local = leafcn(ivt(p))
+ end if
+ if ( (slatop(ivt(p)) * leafcn_local) <= 0.0_r8)then
call endrun(subgrid_index=p, subgrid_level=subgrid_level_patch, msg="ERROR: slatop or leafcn is zero")
end if
- lnc(p) = 1._r8 / (slatop(patch%itype(p)) * leafcn(patch%itype(p)))
+ lnc(p) = 1._r8 / (slatop(ivt(p)) * leafcn_local)
end if
! Using the actual nitrogen allocated to the leaf after
@@ -2699,6 +2707,7 @@ end subroutine ci_func
subroutine PhotosynthesisHydraulicStress ( bounds, fn, filterp, &
esat_tv, eair, oair, cair, rb, bsun, bsha, btran, dayl_factor, leafn, &
qsatl, qaf, &
+ cnveg_nitrogenstate_inst, &
atm2lnd_inst, temperature_inst, soilstate_inst, waterdiagnosticbulk_inst, &
surfalb_inst, solarabs_inst, canopystate_inst, ozone_inst, &
photosyns_inst, waterfluxbulk_inst, froot_carbon, croot_carbon)
@@ -2741,6 +2750,7 @@ subroutine PhotosynthesisHydraulicStress ( bounds, fn, filterp, &
real(r8) , intent(in) :: froot_carbon( bounds%begp: ) ! fine root carbon (gC/m2) [pft]
real(r8) , intent(in) :: croot_carbon( bounds%begp: ) ! live coarse root carbon (gC/m2) [pft]
+ type(cnveg_nitrogenstate_type), intent(in) :: cnveg_nitrogenstate_inst
type(atm2lnd_type) , intent(in) :: atm2lnd_inst
type(temperature_type) , intent(in) :: temperature_inst
type(surfalb_type) , intent(in) :: surfalb_inst
@@ -2881,6 +2891,7 @@ subroutine PhotosynthesisHydraulicStress ( bounds, fn, filterp, &
real(r8) , pointer :: o3coefg_sha (:) ! o3 coefficient used in rs calculation, shaded
real(r8) :: sum_nscaler
real(r8) :: total_lai
+ real(r8) :: leafcn_local
integer :: nptreemax
real(r8) :: dtime ! land model time step (sec)
integer :: j,g ! index
@@ -3162,9 +3173,14 @@ subroutine PhotosynthesisHydraulicStress ( bounds, fn, filterp, &
do f = 1, fn
p = filterp(f)
- if (lnc_opt .eqv. .false.) then
+ if (.not. lnc_opt) then
+ if (use_cn) then ! use the leafcn calculated in subroutine time_evolv_leafcn
+ leafcn_local = cnveg_nitrogenstate_inst%leafcn_t_evolving_patch(p)
+ else ! use the leafcn prescribed in the paramfile
+ leafcn_local = leafcn(ivt(p))
+ end if
! Leaf nitrogen concentration at the top of the canopy (g N leaf / m**2 leaf)
- lnc(p) = 1._r8 / (slatop(patch%itype(p)) * leafcn(patch%itype(p)))
+ lnc(p) = 1._r8 / (slatop(ivt(p)) * leafcn_local)
end if
! Using the actual nitrogen allocated to the leaf after
diff --git a/src/main/clm_driver.F90 b/src/main/clm_driver.F90
index dcdb5558e6..9969ff4a69 100644
--- a/src/main/clm_driver.F90
+++ b/src/main/clm_driver.F90
@@ -170,6 +170,28 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro
call get_proc_bounds(bounds_proc)
nclumps = get_proc_clumps()
+ ! -------------------------------------------------
+ ! Obtain updated values of time-evolving parameters
+ !
+ ! As of ctsm5.4
+ ! - We have this capability for leafcn by calculating leafcn_t_evolving_patch in subr. time_evolv_leafcn
+ ! - leafcn_t_evolving_patch's calculation defaults to leafcn's paramfile values
+ ! - This needs to be called before calling dynSubgrid_driver
+ ! -------------------------------------------------
+ if (use_cn) then
+ !$OMP PARALLEL DO PRIVATE (nc, bounds_clump)
+ do nc = 1, nclumps
+ call get_clump_bounds(nc, bounds_clump)
+
+ call bgc_vegetation_inst%cnveg_nitrogenstate_inst%time_evolv_leafcn( &
+ bounds_clump, &
+ filter_inactive_and_active(nc)%num_bgc_vegp, &
+ filter_inactive_and_active(nc)%bgc_vegp, &
+ atm2lnd_inst)
+ end do
+ !$OMP END PARALLEL DO
+ end if
+
! ========================================================================
! In the first time step of a startup or hybrid run, we want to update CLM's glacier
! areas to match those given by GLC. This is because, in initialization, we do not yet
@@ -723,6 +745,7 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro
temperature_inst, water_inst%waterfluxbulk_inst, water_inst%waterstatebulk_inst, &
water_inst%waterdiagnosticbulk_inst, water_inst%wateratm2lndbulk_inst, &
ch4_inst, ozone_inst, photosyns_inst, &
+ bgc_vegetation_inst%cnveg_nitrogenstate_inst, &
humanindex_inst, soil_water_retention_curve, &
downreg_patch = downreg_patch(bounds_clump%begp:bounds_clump%endp), &
leafn_patch = leafn_patch(bounds_clump%begp:bounds_clump%endp), &