diff --git a/doc/ChangeLog b/doc/ChangeLog index ea2697281c..383ed4ecfa 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,4 +1,82 @@ =============================================================== +Tag name: ctsm5.1.dev092 +Originator(s): sacks (Bill Sacks) +Date: Fri Apr 29 18:31:48 MDT 2022 +One-line Summary: Refactor NutrientCompetition / CNAllocation to provide hooks for AgSys + +Purpose and description of changes +---------------------------------- + +Major refactor of NutrientCompetition / CNAllocation to provide hooks +for AgSys crop model: separates the NutrientCompetition modules into +pieces based on (1) consolidating duplicate code between the Clm45 and +FlexibleCN versions, and (2) separating pieces that will vs. won't be +used for crop patches when running with the upcoming AgSys crop model. + +I have restored the old CNAllocationMod, with some of the +responsibilities that it used to have. (I'm not sure it's appropriate to +have the calculation of gpp and maint resp in CNAllocationMod, but I +left it there because it has always been combined with the allocation +code, including back when we had a separate CNAllocationMod.) + + +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.] + +[ ] clm5_1 + +[ ] clm5_0 + +[ ] ctsm5_0-nwp + +[ ] clm4_5 + + +Testing summary: +---------------- + + regular tests (aux_clm: https://github.com/ESCOMP/CTSM/wiki/System-Testing-Guide#pre-merge-system-testing): + + cheyenne ---- PASS + izumi ------- PASS + + +Answer changes +-------------- + +Changes answers relative to baseline: NO - though potential for answer +changes in unusual cases + + One change in this tag has the potential for answer changes in + unusual cases, even though no answer changes were observed in + testing: Previously, only the FlexibleCN code applied some logic that + changed crop allocation fractions during the grainfill period if + peaklai had been reached. I have changed this so that this logic is + applied with or without FlexibleCN (because I have moved this block + of code to the CNAllocation module, which is shared between the + FlexibleCN and non-FlexibleCN versions). I thought this would change + answers, but it appears not to, at least based on the tests in the + test suite as well as an extra 5-year test I did at f19 resolution + (ERS_Ly5.f19_g17.IHistClm45BgcCrop.cheyenne_intel.clm-cropMonthOutput). + It's possible that this changes answers in rare cases or with an + unusual combination of options that we don't test: specifically, it + might change answers for the atypical situation where you are running + with FUN but not FlexibleCN. (In this case, I believe this change is + the correct thing to do.) + + +Other details +------------- +Pull Requests that document the changes (include PR ids): +https://github.com/ESCOMP/CTSM/pull/1705 + +=============================================================== +=============================================================== Tag name: ctsm5.1.dev091 Originator(s): rgknox (Ryan Knox,rgknox@lbl.gov) Date: Fri Apr 22 14:11:50 EDT 2022 diff --git a/doc/ChangeSum b/doc/ChangeSum index 6f3b47ae7d..8280d7aefc 100644 --- a/doc/ChangeSum +++ b/doc/ChangeSum @@ -1,5 +1,6 @@ Tag Who Date Summary ============================================================================================================================ + ctsm5.1.dev092 sacks 04/29/2022 Refactor NutrientCompetition / CNAllocation to provide hooks for AgSys ctsm5.1.dev091 rgknox 04/22/2022 clm decomp method is now passed to fates to enabled mimics coupling ctsm5.1.dev090 samrabin 03/31/2022 Fix misleading name of "gddplant" ctsm5.1.dev089 sacks 03/31/2022 For CLM45 apply peaklai to aleaf in grainfill diff --git a/src/biogeochem/CNAllocationMod.F90 b/src/biogeochem/CNAllocationMod.F90 new file mode 100644 index 0000000000..ef646511f1 --- /dev/null +++ b/src/biogeochem/CNAllocationMod.F90 @@ -0,0 +1,542 @@ +module CNAllocationMod + + !----------------------------------------------------------------------- + ! !DESCRIPTION: + ! This module contains subroutines to calculate allocation of C and N to different + ! plant components. It also contains subroutines to calculate gpp and maintenance + ! respiration. + ! + ! !USES: +#include "shr_assert.h" + use shr_kind_mod , only : r8 => shr_kind_r8 + use shr_log_mod , only : errMsg => shr_log_errMsg + use abortutils , only : endrun + use decompMod , only : bounds_type + use clm_varcon , only : secspday + use clm_varctl , only : use_c13, use_c14, iulog + use PatchType , only : patch + use pftconMod , only : pftcon, npcropmin + use CropType , only : crop_type + use CropType , only : cphase_planted, cphase_leafemerge, cphase_grainfill + use PhotosynthesisMod , only : photosyns_type + use CanopyStateType , only : canopystate_type + use CNVegCarbonStateType , only : cnveg_carbonstate_type + use CNVegCarbonFluxType , only : cnveg_carbonflux_type + use CNVegStateType , only : cnveg_state_type + use CropReprPoolsMod , only : nrepr + use CNPhenologyMod , only : CropPhase + use CNSharedParamsMod , only : use_fun + ! + implicit none + private + ! + ! !PUBLIC MEMBER FUNCTIONS: + public :: readParams ! Read in parameters from file + public :: calc_gpp_mr_availc ! Calculate total GPP, various maintenance respiration terms, and total available C for allocation + public :: calc_crop_allocation_fractions ! Calculate crop allocation fractions to leaf, stem, root and repr + public :: calc_allometry ! Calculate c_allometry and n_allometry terms based on allocation fractions + + ! !PRIVATE MEMBER VARIABLES: + type, private :: params_type + real(r8) :: dayscrecover ! number of days to recover negative cpool + end type params_type + + type(params_type), private :: params_inst + + character(len=*), parameter, private :: sourcefile = & + __FILE__ + +contains + + !----------------------------------------------------------------------- + subroutine readParams (ncid) + ! + ! !USES: + use ncdio_pio , only : file_desc_t,ncd_io + ! + ! !ARGUMENTS: + type(file_desc_t),intent(inout) :: ncid ! pio netCDF file id + ! + ! !LOCAL VARIABLES: + character(len=32) :: subname = 'CNAllocParamsType' + character(len=100) :: errCode = '-Error reading in parameters file:' + logical :: readv ! has variable been read in or not + real(r8) :: tempr ! temporary to read in parameter + character(len=100) :: tString ! temp. var for reading + !----------------------------------------------------------------------- + + ! read in parameters + + tString='dayscrecover' + call ncd_io(varname=trim(tString),data=tempr, flag='read', ncid=ncid, readvar=readv) + if ( .not. readv ) call endrun(msg=trim(errCode)//trim(tString)//errMsg(sourcefile, __LINE__)) + params_inst%dayscrecover=tempr + + end subroutine readParams + + !----------------------------------------------------------------------- + subroutine calc_gpp_mr_availc(bounds, num_soilp, filter_soilp, & + crop_inst, photosyns_inst, canopystate_inst, & + cnveg_carbonstate_inst, cnveg_carbonflux_inst, & + c13_cnveg_carbonflux_inst, c14_cnveg_carbonflux_inst) + ! + ! !DESCRIPTION: + ! Calculate total GPP, various maintenance respiration terms, and total available C + ! for allocation + ! + ! !ARGUMENTS: + type(bounds_type) , intent(in) :: bounds + integer , intent(in) :: num_soilp ! number of soil patches in filter + integer , intent(in) :: filter_soilp(:) ! filter for soil patches + type(crop_type) , intent(in) :: crop_inst + type(photosyns_type) , intent(in) :: photosyns_inst + type(canopystate_type) , intent(in) :: canopystate_inst + type(cnveg_carbonstate_type) , intent(in) :: cnveg_carbonstate_inst + type(cnveg_carbonflux_type) , intent(inout) :: cnveg_carbonflux_inst + type(cnveg_carbonflux_type) , intent(inout) :: c13_cnveg_carbonflux_inst + type(cnveg_carbonflux_type) , intent(inout) :: c14_cnveg_carbonflux_inst + ! + ! !LOCAL VARIABLES: + integer :: p, k ! indices + integer :: fp ! filter patch index + real(r8) :: dayscrecover ! number of days to recover negative cpool + real(r8) :: mr ! maintenance respiration (gC/m2/s) + real(r8) :: reproductive_mr_tot ! total maintenance respiration from grain components (gC/m2/s) + real(r8) :: curmr, curmr_ratio ! xsmrpool temporary variables + + character(len=*), parameter :: subname = 'calc_gpp_mr_availc' + !----------------------------------------------------------------------- + + ! set number of days to recover negative cpool + dayscrecover = params_inst%dayscrecover + + associate ( & + ivt => patch%itype , & ! Input: [integer (:) ] patch vegetation type + woody => pftcon%woody , & ! Input: binary flag for woody lifeform (1=woody, 0=not woody) + croplive => crop_inst%croplive_patch , & ! Input: [logical (:) ] flag, true if planted, not harvested + psnsun => photosyns_inst%psnsun_patch , & ! Input: [real(r8) (:) ] sunlit leaf-level photosynthesis (umol CO2 /m**2/ s) + psnsha => photosyns_inst%psnsha_patch , & ! Input: [real(r8) (:) ] shaded leaf-level photosynthesis (umol CO2 /m**2/ s) + c13_psnsun => photosyns_inst%c13_psnsun_patch , & ! Input: [real(r8) (:) ] sunlit leaf-level photosynthesis (umol CO2 /m**2/ s) + c13_psnsha => photosyns_inst%c13_psnsha_patch , & ! Input: [real(r8) (:) ] shaded leaf-level photosynthesis (umol CO2 /m**2/ s) + c14_psnsun => photosyns_inst%c14_psnsun_patch , & ! Input: [real(r8) (:) ] sunlit leaf-level photosynthesis (umol CO2 /m**2/ s) + c14_psnsha => photosyns_inst%c14_psnsha_patch , & ! Input: [real(r8) (:) ] shaded leaf-level photosynthesis (umol CO2 /m**2/ s) + 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 + xsmrpool => cnveg_carbonstate_inst%xsmrpool_patch , & ! Input: [real(r8) (:) ] (gC/m2) temporary photosynthate C pool + leaf_mr => cnveg_carbonflux_inst%leaf_mr_patch , & ! Input: [real(r8) (:) ] + froot_mr => cnveg_carbonflux_inst%froot_mr_patch , & ! Input: [real(r8) (:) ] + livestem_mr => cnveg_carbonflux_inst%livestem_mr_patch , & ! Input: [real(r8) (:) ] + livecroot_mr => cnveg_carbonflux_inst%livecroot_mr_patch , & ! Input: [real(r8) (:) ] + reproductive_mr => cnveg_carbonflux_inst%reproductive_mr_patch , & ! Input: [real(r8) (:,:) ] + psnsun_to_cpool => cnveg_carbonflux_inst%psnsun_to_cpool_patch , & ! Output: [real(r8) (:) ] + psnshade_to_cpool => cnveg_carbonflux_inst%psnshade_to_cpool_patch , & ! Output: [real(r8) (:) ] + gpp => cnveg_carbonflux_inst%gpp_before_downreg_patch , & ! Output: [real(r8) (:) ] GPP flux before downregulation (gC/m2/s) + availc => cnveg_carbonflux_inst%availc_patch , & ! Output: [real(r8) (:) ] C flux available for allocation (gC/m2/s) + leaf_curmr => cnveg_carbonflux_inst%leaf_curmr_patch , & ! Output: [real(r8) (:) ] + froot_curmr => cnveg_carbonflux_inst%froot_curmr_patch , & ! Output: [real(r8) (:) ] + livestem_curmr => cnveg_carbonflux_inst%livestem_curmr_patch , & ! Output: [real(r8) (:) ] + livecroot_curmr => cnveg_carbonflux_inst%livecroot_curmr_patch , & ! Output: [real(r8) (:) ] + reproductive_curmr => cnveg_carbonflux_inst%reproductive_curmr_patch , & ! Output: [real(r8) (:,:) ] + leaf_xsmr => cnveg_carbonflux_inst%leaf_xsmr_patch , & ! Output: [real(r8) (:) ] + froot_xsmr => cnveg_carbonflux_inst%froot_xsmr_patch , & ! Output: [real(r8) (:) ] + livestem_xsmr => cnveg_carbonflux_inst%livestem_xsmr_patch , & ! Output: [real(r8) (:) ] + livecroot_xsmr => cnveg_carbonflux_inst%livecroot_xsmr_patch , & ! Output: [real(r8) (:) ] + reproductive_xsmr => cnveg_carbonflux_inst%reproductive_xsmr_patch , & ! Output: [real(r8) (:,:) ] + cpool_to_xsmrpool => cnveg_carbonflux_inst%cpool_to_xsmrpool_patch , & ! Output: [real(r8) (:) ] + xsmrpool_recover => cnveg_carbonflux_inst%xsmrpool_recover_patch & ! Output: [real(r8) (:) ] C flux assigned to recovery of negative cpool (gC/m2/s) + ) + + do fp = 1,num_soilp + p = filter_soilp(fp) + + ! get the time step total gross photosynthesis + ! this is coming from the canopy fluxes code, and is the + ! gpp that is used to control stomatal conductance. + ! For the nitrogen downregulation code, this is assumed + ! to be the potential gpp, and the actual gpp will be + ! reduced due to N limitation. + + ! Convert psn from umol/m2/s -> gC/m2/s + + ! The input psn (psnsun and psnsha) are expressed per unit LAI + ! in the sunlit and shaded canopy, respectively. These need to be + ! scaled by laisun and laisha to get the total gpp for allocation + + ! Note that no associate statement is used for the isotope carbon fluxes below + ! since they are not always allocated AND nag compiler will complain if you try to + ! to have an associate statement with unallocated memory + + psnsun_to_cpool(p) = psnsun(p) * laisun(p) * 12.011e-6_r8 + psnshade_to_cpool(p) = psnsha(p) * laisha(p) * 12.011e-6_r8 + + if ( use_c13 ) then + c13_cnveg_carbonflux_inst%psnsun_to_cpool_patch(p) = c13_psnsun(p) * laisun(p) * 12.011e-6_r8 + c13_cnveg_carbonflux_inst%psnshade_to_cpool_patch(p) = c13_psnsha(p) * laisha(p) * 12.011e-6_r8 + end if + + if ( use_c14 ) then + c14_cnveg_carbonflux_inst%psnsun_to_cpool_patch(p) = c14_psnsun(p) * laisun(p) * 12.011e-6_r8 + c14_cnveg_carbonflux_inst%psnshade_to_cpool_patch(p) = c14_psnsha(p) * laisha(p) * 12.011e-6_r8 + end if + + gpp(p) = psnsun_to_cpool(p) + psnshade_to_cpool(p) + + ! get the time step total maintenance respiration + ! These fluxes should already be in gC/m2/s + + mr = leaf_mr(p) + froot_mr(p) + if (woody(ivt(p)) == 1.0_r8) then + mr = mr + livestem_mr(p) + livecroot_mr(p) + else if (ivt(p) >= npcropmin) then + if (croplive(p)) then + reproductive_mr_tot = 0._r8 + do k = 1, nrepr + reproductive_mr_tot = reproductive_mr_tot + reproductive_mr(p,k) + end do + mr = mr + livestem_mr(p) + reproductive_mr_tot + end if + end if + + ! carbon flux available for allocation + availc(p) = gpp(p) - mr + + ! new code added for isotope calculations, 7/1/05, PET + ! If mr > gpp, then some mr comes from gpp, the rest comes from + ! cpool (xsmr) + if (mr > 0._r8 .and. availc(p) < 0._r8) then + curmr = gpp(p) + curmr_ratio = curmr / mr + else + curmr_ratio = 1._r8 + end if + leaf_curmr(p) = leaf_mr(p) * curmr_ratio + leaf_xsmr(p) = leaf_mr(p) - leaf_curmr(p) + froot_curmr(p) = froot_mr(p) * curmr_ratio + froot_xsmr(p) = froot_mr(p) - froot_curmr(p) + livestem_curmr(p) = livestem_mr(p) * curmr_ratio + livestem_xsmr(p) = livestem_mr(p) - livestem_curmr(p) + livecroot_curmr(p) = livecroot_mr(p) * curmr_ratio + livecroot_xsmr(p) = livecroot_mr(p) - livecroot_curmr(p) + do k = 1, nrepr + reproductive_curmr(p,k) = reproductive_mr(p,k) * curmr_ratio + reproductive_xsmr(p,k) = reproductive_mr(p,k) - reproductive_curmr(p,k) + end do + + ! no allocation when available c is negative + availc(p) = max(availc(p),0.0_r8) + + ! test for an xsmrpool deficit + if (xsmrpool(p) < 0.0_r8) then + ! Running a deficit in the xsmrpool, so the first priority is to let + ! some availc from this timestep accumulate in xsmrpool. + ! Determine rate of recovery for xsmrpool deficit + + xsmrpool_recover(p) = -xsmrpool(p)/(dayscrecover*secspday) + if (xsmrpool_recover(p) < availc(p)) then + ! available carbon reduced by amount for xsmrpool recovery + availc(p) = availc(p) - xsmrpool_recover(p) + else + ! all of the available carbon goes to xsmrpool recovery + xsmrpool_recover(p) = availc(p) + availc(p) = 0.0_r8 + end if + cpool_to_xsmrpool(p) = xsmrpool_recover(p) + end if + + end do + + end associate + + end subroutine calc_gpp_mr_availc + + !----------------------------------------------------------------------- + subroutine calc_crop_allocation_fractions(bounds, num_pcropp, filter_pcropp, & + crop_inst, cnveg_state_inst) + ! + ! !DESCRIPTION: + ! Calculate crop allocation fractions to leaf, stem, root and repr, following + ! AgroIBIS subroutine phenocrop + ! + ! This sets the following variables in cnveg_state_inst for all patches in the pcrop + ! filter: + ! - aleaf + ! - astem + ! - aroot + ! - arepr + ! + ! And under some conditions it updates the following variables: + ! - astemi + ! - aleafi + ! + ! !ARGUMENTS: + type(bounds_type) , intent(in) :: bounds + integer , intent(in) :: num_pcropp ! number of prog crop patches in filter + integer , intent(in) :: filter_pcropp(:) ! filter for prognostic crop patches + type(crop_type) , intent(in) :: crop_inst + type(cnveg_state_type) , intent(inout) :: cnveg_state_inst + ! + ! !LOCAL VARIABLES: + integer :: p, fp, k + real(r8) :: fleaf ! fraction allocated to leaf + real(r8) :: crop_phase(bounds%begp:bounds%endp) + + character(len=*), parameter :: subname = 'calc_crop_allocation_fractions' + !----------------------------------------------------------------------- + + associate( & + ivt => patch%itype , & ! Input: [integer (:) ] patch vegetation type + arooti => pftcon%arooti , & ! Input: parameter used below + arootf => pftcon%arootf , & ! Input: parameter used below + bfact => pftcon%bfact , & ! Input: parameter used below + fleafi => pftcon%fleafi , & ! Input: parameter used below + aleaff => pftcon%aleaff , & ! Input: parameter used below + astemf => pftcon%astemf , & ! Input: parameter used below + allconss => pftcon%allconss , & ! Input: parameter used below + allconsl => pftcon%allconsl , & ! Input: parameter used below + declfact => pftcon%declfact , & ! Input: parameter used below + croplive => crop_inst%croplive_patch , & ! Input: [logical (:) ] flag, true if planted, not harvested + hui => crop_inst%hui_patch , & ! Input: [real(r8) (:) ] crop patch heat unit index (growing degree-days); set to 0 at sowing and accumulated until harvest + peaklai => cnveg_state_inst%peaklai_patch , & ! Input: [integer (:) ] 1: max allowed lai; 0: not at max + gddmaturity => cnveg_state_inst%gddmaturity_patch , & ! Input: [real(r8) (:) ] gdd needed to harvest + huigrain => cnveg_state_inst%huigrain_patch , & ! Input: [real(r8) (:) ] same to reach vegetative maturity + aleafi => cnveg_state_inst%aleafi_patch , & ! Output: [real(r8) (:) ] saved allocation coefficient from phase 2 + astemi => cnveg_state_inst%astemi_patch , & ! Output: [real(r8) (:) ] saved allocation coefficient from phase 2 + aleaf => cnveg_state_inst%aleaf_patch , & ! Output: [real(r8) (:) ] leaf allocation coefficient + astem => cnveg_state_inst%astem_patch , & ! Output: [real(r8) (:) ] stem allocation coefficient + aroot => cnveg_state_inst%aroot_patch , & ! Output: [real(r8) (:) ] root allocation coefficient + arepr => cnveg_state_inst%arepr_patch & ! Output: [real(r8) (:,:) ] reproductive allocation coefficient(s) + ) + + call CropPhase(bounds, num_pcropp, filter_pcropp, crop_inst, cnveg_state_inst, & + crop_phase = crop_phase(bounds%begp:bounds%endp)) + + do fp = 1, num_pcropp + p = filter_pcropp(fp) + + if (croplive(p)) then + ! same phases appear in subroutine CropPhenology + + ! Phase 1 completed: + ! ================== + ! if hui is less than the number of gdd needed for filling of grain + ! leaf emergence also has to have taken place for lai changes to occur + ! and carbon assimilation + ! Next phase: leaf emergence to start of leaf decline + + if (crop_phase(p) == cphase_leafemerge) then + + ! allocation rules for crops based on maturity and linear decrease + ! of amount allocated to roots over course of the growing season + + do k = 1, nrepr + arepr(p,k) = 0._r8 + end do + if (peaklai(p) == 1) then ! lai at maximum allowed + aleaf(p) = 1.e-5_r8 + astem(p) = 0._r8 + aroot(p) = 1._r8 - aleaf(p) + else + aroot(p) = max(0._r8, min(1._r8, arooti(ivt(p)) - & + (arooti(ivt(p)) - arootf(ivt(p))) * & + min(1._r8, hui(p)/gddmaturity(p)))) + fleaf = fleafi(ivt(p)) * (exp(-bfact(ivt(p))) - & + exp(-bfact(ivt(p))*hui(p)/huigrain(p))) / & + (exp(-bfact(ivt(p)))-1) ! fraction alloc to leaf (from J Norman alloc curve) + aleaf(p) = max(1.e-5_r8, (1._r8 - aroot(p)) * fleaf) + astem(p) = 1._r8 - aleaf(p) - aroot(p) + end if + + ! AgroIBIS included here an immediate adjustment to aleaf & astem if the + ! predicted lai from the above allocation coefficients exceeded laimx. + ! We have decided to live with lais slightly higher than laimx by + ! enforcing the cap in the following tstep through the peaklai logic above. + + astemi(p) = astem(p) ! save for use by equations after shift + aleafi(p) = aleaf(p) ! to reproductive phenology stage begins + + ! Phase 2 completed: + ! ================== + ! shift allocation either when enough gdd are accumulated or maximum number + ! of days has elapsed since planting + + else if (crop_phase(p) == cphase_grainfill) then + aroot(p) = max(0._r8, min(1._r8, arooti(ivt(p)) - & + (arooti(ivt(p)) - arootf(ivt(p))) * min(1._r8, hui(p)/gddmaturity(p)))) + if (astemi(p) > astemf(ivt(p))) then + astem(p) = max(0._r8, max(astemf(ivt(p)), astem(p) * & + (1._r8 - min((hui(p)- & + huigrain(p))/((gddmaturity(p)*declfact(ivt(p)))- & + huigrain(p)),1._r8)**allconss(ivt(p)) ))) + end if + + ! If crops have hit peaklai, then set leaf allocation to small value + if (peaklai(p) == 1) then + aleaf(p) = 1.e-5_r8 + else if (aleafi(p) > aleaff(ivt(p))) then + aleaf(p) = max(1.e-5_r8, max(aleaff(ivt(p)), aleaf(p) * & + (1._r8 - min((hui(p)- & + huigrain(p))/((gddmaturity(p)*declfact(ivt(p)))- & + huigrain(p)),1._r8)**allconsl(ivt(p)) ))) + end if + + ! For AgroIBIS-based crop model, all repr allocation is assumed to go + ! into the last reproductive pool. In practice there is only a single + ! reproductive pool with the AgroIBIS-based crop model, but for + ! software testing we can have multiple, in which situation we want the + ! active pool to be the last one. + do k = 1, nrepr-1 + arepr(p,k) = 0._r8 + end do + arepr(p,nrepr) = 1._r8 - aroot(p) - astem(p) - aleaf(p) + + else if (crop_phase(p) == cphase_planted) then + ! pre emergence + ! allocation coefficients should be irrelevant because crops have no + ! live carbon pools + aleaf(p) = 1._r8 + astem(p) = 0._r8 + aroot(p) = 0._r8 + do k = 1, nrepr + arepr(p,k) = 0._r8 + end do + + else + write(iulog,*) "ERROR in " // subname // ": unexpected crop_phase: ", crop_phase(p) + call endrun(msg="ERROR: unexpected crop_phase "//errmsg(sourcefile, __LINE__)) + end if + + else ! .not croplive + ! allocation coefficients should be irrelevant because crops have no + ! live carbon pools + aleaf(p) = 1._r8 + astem(p) = 0._r8 + aroot(p) = 0._r8 + do k = 1, nrepr + arepr(p,k) = 0._r8 + end do + end if + + end do + + end associate + + end subroutine calc_crop_allocation_fractions + + !----------------------------------------------------------------------- + subroutine calc_allometry(num_soilp, filter_soilp, & + cnveg_carbonflux_inst, cnveg_state_inst) + ! + ! !DESCRIPTION: + ! Calculate c_allometry and n_allometry terms based on allocation fractions + ! + ! !ARGUMENTS: + 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_state_type) , intent(inout) :: cnveg_state_inst + ! + ! !LOCAL VARIABLES: + integer :: p, fp, k + real(r8):: f1,f2,f3,f4,g1 ! allocation parameters + real(r8):: g1a ! g1 included in allocation/allometry + real(r8):: cnl,cnfr,cnlw,cndw ! C:N ratios for leaf, fine root, and wood + real(r8):: f5(nrepr) ! reproductive allocation parameters + real(r8):: cng ! C:N ratio for grain (= cnlw for now; slevis) + real(r8):: f5_tot ! sum of f5 terms + real(r8):: f5_n_tot ! sum of f5 terms converted from C to N + + character(len=*), parameter :: subname = 'calc_allometry' + !----------------------------------------------------------------------- + + associate( & + ivt => patch%itype , & ! Input: [integer (:) ] patch vegetation type + woody => pftcon%woody , & ! Input: binary flag for woody lifeform (1=woody, 0=not woody) + froot_leaf => pftcon%froot_leaf , & ! Input: allocation parameter: new fine root C per new leaf C (gC/gC) + 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) + 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) + graincn => pftcon%graincn , & ! Input: grain C:N (gC/gN) + grperc => pftcon%grperc , & ! Input: parameter used below + annsum_npp => cnveg_carbonflux_inst%annsum_npp_patch , & ! Input: [real(r8) (:) ] annual sum of NPP, for wood allocation + aleaf => cnveg_state_inst%aleaf_patch , & ! Input: [real(r8) (:) ] leaf allocation coefficient + astem => cnveg_state_inst%astem_patch , & ! Input: [real(r8) (:) ] stem allocation coefficient + aroot => cnveg_state_inst%aroot_patch , & ! Input: [real(r8) (:) ] root allocation coefficient + arepr => cnveg_state_inst%arepr_patch , & ! Input: [real(r8) (:,:) ] reproductive allocation coefficient(s) + c_allometry => cnveg_state_inst%c_allometry_patch , & ! Output: [real(r8) (:) ] C allocation index (DIM) + n_allometry => cnveg_state_inst%n_allometry_patch & ! Output: [real(r8) (:) ] N allocation index (DIM) + ) + + do fp = 1, num_soilp + p = filter_soilp(fp) + + f1 = froot_leaf(ivt(p)) + f2 = croot_stem(ivt(p)) + + ! modified wood allocation to be 2.2 at npp=800 gC/m2/yr, 0.2 at npp=0, + ! constrained so that it does not go lower than 0.2 (under negative annsum_npp) + ! This variable allocation is only for trees. Shrubs have a constant + ! allocation as specified in the pft-physiology file. The value is also used + ! as a trigger here: -1.0 means to use the dynamic allocation (trees). + + if (stem_leaf(ivt(p)) == -1._r8) then + f3 = (2.7_r8/(1.0_r8+exp(-0.004_r8*(annsum_npp(p) - 300.0_r8)))) - 0.4_r8 + else + f3 = stem_leaf(ivt(p)) + end if + + f4 = flivewd(ivt(p)) + if (ivt(p) >= npcropmin) then + g1 = 0.25_r8 + else + g1 = grperc(ivt(p)) + end if + cnl = leafcn(ivt(p)) + cnfr = frootcn(ivt(p)) + cnlw = livewdcn(ivt(p)) + cndw = deadwdcn(ivt(p)) + + ! based on available C, use constant allometric relationships to + ! determine N requirements + if (.not. use_fun) then + g1a = g1 + else + g1a = 0._r8 + end if + if (woody(ivt(p)) == 1.0_r8) then + c_allometry(p) = (1._r8+g1a)*(1._r8+f1+f3*(1._r8+f2)) + n_allometry(p) = 1._r8/cnl + f1/cnfr + (f3*f4*(1._r8+f2))/cnlw + & + (f3*(1._r8-f4)*(1._r8+f2))/cndw + else if (ivt(p) >= npcropmin) then ! skip generic crops + cng = graincn(ivt(p)) + f1 = aroot(p) / aleaf(p) + f3 = astem(p) / aleaf(p) + do k = 1, nrepr + f5(k) = arepr(p,k) / aleaf(p) + end do + f5_tot = 0._r8 + f5_n_tot = 0._r8 + do k = 1, nrepr + f5_tot = f5_tot + f5(k) + ! Note that currently we use the same C/N ratio for all grain components: + f5_n_tot = f5_n_tot + f5(k)/cng + end do + c_allometry(p) = (1._r8+g1a)*(1._r8+f1+f5_tot+f3*(1._r8+f2)) + n_allometry(p) = 1._r8/cnl + f1/cnfr + f5_n_tot + (f3*f4*(1._r8+f2))/cnlw + & + (f3*(1._r8-f4)*(1._r8+f2))/cndw + else + c_allometry(p) = 1._r8+g1a+f1+f1*g1a + n_allometry(p) = 1._r8/cnl + f1/cnfr + end if + + end do + + end associate + + end subroutine calc_allometry + + +end module CNAllocationMod diff --git a/src/biogeochem/CNDriverMod.F90 b/src/biogeochem/CNDriverMod.F90 index 7441a9fa07..a782cc1986 100644 --- a/src/biogeochem/CNDriverMod.F90 +++ b/src/biogeochem/CNDriverMod.F90 @@ -11,7 +11,7 @@ module CNDriverMod use decompMod , only : bounds_type use perf_mod , only : t_startf, t_stopf use clm_varctl , only : use_nitrif_denitrif, use_nguardrail - use clm_varctl , only : iulog, use_crop + use clm_varctl , only : iulog, use_crop, use_crop_agsys use SoilBiogeochemDecompCascadeConType, only : mimics_decomp, century_decomp, decomp_method use CNSharedParamsMod , only : use_fun use CNVegStateType , only : cnveg_state_type @@ -42,7 +42,6 @@ module CNDriverMod use SaturatedExcessRunoffMod , only : saturated_excess_runoff_type use ActiveLayerMod , only : active_layer_type use SoilWaterRetentionCurveMod , only : soil_water_retention_curve_type - use CropReprPoolsMod , only : nrepr ! ! !PUBLIC TYPES: implicit none @@ -83,7 +82,8 @@ end subroutine CNDriverInit !----------------------------------------------------------------------- subroutine CNDriverNoLeaching(bounds, & - num_soilc, filter_soilc, num_soilp, filter_soilp, num_pcropp, filter_pcropp, & + num_soilc, filter_soilc, num_soilp, filter_soilp, & + num_pcropp, filter_pcropp, num_soilnopcropp, filter_soilnopcropp, & num_exposedvegp, filter_exposedvegp, num_noexposedvegp, filter_noexposedvegp, & cnveg_state_inst, & cnveg_carbonflux_inst, cnveg_carbonstate_inst, & @@ -114,6 +114,8 @@ subroutine CNDriverNoLeaching(bounds, use clm_varpar , only: nlevdecomp, ndecomp_cascade_transitions, ndecomp_pools use subgridAveMod , only: p2c use CropType , only: crop_type + use CNAllocationMod , only: calc_gpp_mr_availc, calc_crop_allocation_fractions + use CNAllocationMod , only: calc_allometry use CNNDynamicsMod , only: CNNDeposition,CNNFixation, CNNFert, CNSoyfix,CNFreeLivingFixation use CNMRespMod , only: CNMResp use CNFUNMod , only: CNFUNInit !, CNFUN @@ -151,6 +153,8 @@ subroutine CNDriverNoLeaching(bounds, integer , intent(in) :: filter_soilp(:) ! filter for soil patches integer , intent(in) :: num_pcropp ! number of prog. crop patches in filter integer , intent(in) :: filter_pcropp(:) ! filter for prognostic crop patches + integer , intent(in) :: num_soilnopcropp ! number of non-prog. crop soil patches in filter + integer , intent(in) :: filter_soilnopcropp(:) ! filter for non-prog. crop soil patches integer , intent(in) :: num_exposedvegp ! number of points in filter_exposedvegp integer , intent(in) :: filter_exposedvegp(:) ! patch filter for non-snow-covered veg integer , intent(in) :: num_noexposedvegp ! number of points in filter_noexposedvegp @@ -203,8 +207,6 @@ subroutine CNDriverNoLeaching(bounds, real(r8):: pmnf_decomp_cascade(bounds%begc:bounds%endc,1:nlevdecomp,1:ndecomp_cascade_transitions) !potential mineral N flux, from one pool to another real(r8):: p_decomp_npool_to_din(bounds%begc:bounds%endc,1:nlevdecomp,1:ndecomp_cascade_transitions) ! potential flux to dissolved inorganic N real(r8):: p_decomp_cn_gain(bounds%begc:bounds%endc,1:nlevdecomp,1:ndecomp_pools) ! C:N ratio of the flux gained by the receiver pool - real(r8):: arepr(bounds%begp:bounds%endp,nrepr) ! reproductive allocation coefficient(s) (only used for use_crop) - real(r8):: aroot(bounds%begp:bounds%endp) ! root allocation coefficient (only used for use_crop) integer :: begp,endp integer :: begc,endc @@ -386,16 +388,44 @@ subroutine CNDriverNoLeaching(bounds, end if + call t_startf('cnalloc') + call calc_gpp_mr_availc( & + bounds, num_soilp, filter_soilp, & + crop_inst, photosyns_inst, canopystate_inst, & + cnveg_carbonstate_inst, cnveg_carbonflux_inst, & + c13_cnveg_carbonflux_inst, c14_cnveg_carbonflux_inst) + + if (.not. use_crop_agsys) then + call calc_crop_allocation_fractions(bounds, num_pcropp, filter_pcropp, & + crop_inst, cnveg_state_inst) + end if + + call calc_allometry(num_soilp, filter_soilp, & + cnveg_carbonflux_inst, cnveg_state_inst) + call t_stopf('cnalloc') + call t_startf('calc_plant_nutrient_demand') + ! We always call calc_plant_nutrient_demand for natural veg patches, but only call + ! it for crop patches if NOT running with AgSys (since AgSys calculates the relevant + ! output variables in its own way). call nutrient_competition_method%calc_plant_nutrient_demand ( & - bounds, num_soilp, filter_soilp, & - photosyns_inst, crop_inst, canopystate_inst, & - cnveg_state_inst, cnveg_carbonstate_inst, cnveg_carbonflux_inst, & - c13_cnveg_carbonflux_inst, c14_cnveg_carbonflux_inst, & - cnveg_nitrogenstate_inst, cnveg_nitrogenflux_inst, & - soilbiogeochem_carbonflux_inst, soilbiogeochem_nitrogenstate_inst, & - energyflux_inst, & - aroot=aroot(begp:endp), arepr=arepr(begp:endp,:)) + bounds, & + num_soilnopcropp, filter_soilnopcropp, .false., & + crop_inst, canopystate_inst, & + cnveg_state_inst, cnveg_carbonstate_inst, cnveg_carbonflux_inst, & + cnveg_nitrogenstate_inst, cnveg_nitrogenflux_inst, & + soilbiogeochem_carbonflux_inst, soilbiogeochem_nitrogenstate_inst, & + energyflux_inst) + if (.not. use_crop_agsys) then + call nutrient_competition_method%calc_plant_nutrient_demand ( & + bounds, & + num_pcropp, filter_pcropp, .true., & + crop_inst, canopystate_inst, & + cnveg_state_inst, cnveg_carbonstate_inst, cnveg_carbonflux_inst, & + cnveg_nitrogenstate_inst, cnveg_nitrogenflux_inst, & + soilbiogeochem_carbonflux_inst, soilbiogeochem_nitrogenstate_inst, & + energyflux_inst) + end if ! get the column-averaged plant_ndemand (needed for following call to SoilBiogeochemCompetition) @@ -429,8 +459,6 @@ subroutine CNDriverNoLeaching(bounds, c13_cnveg_carbonflux_inst, c14_cnveg_carbonflux_inst, & cnveg_nitrogenstate_inst, cnveg_nitrogenflux_inst, & soilbiogeochem_nitrogenstate_inst, & - aroot=aroot(begp:endp), & - arepr=arepr(begp:endp,:), & fpg_col=soilbiogeochem_state_inst%fpg_col(begc:endc)) call t_stopf('calc_plant_nutrient_competition') diff --git a/src/biogeochem/CNPhenologyMod.F90 b/src/biogeochem/CNPhenologyMod.F90 index be7e502c7b..f87a59ebaf 100644 --- a/src/biogeochem/CNPhenologyMod.F90 +++ b/src/biogeochem/CNPhenologyMod.F90 @@ -28,6 +28,8 @@ module CNPhenologyMod use CNVegnitrogenstateType , only : cnveg_nitrogenstate_type use CNVegnitrogenfluxType , only : cnveg_nitrogenflux_type use CropType , only : crop_type + use CropType , only : cphase_planted, cphase_leafemerge + use CropType , only : cphase_grainfill, cphase_harvest use pftconMod , only : pftcon use SoilStateType , only : soilstate_type use TemperatureType , only : temperature_type @@ -48,6 +50,7 @@ module CNPhenologyMod public :: CNPhenologyreadNML ! Read namelist public :: CNPhenologyInit ! Initialization public :: CNPhenology ! Update + public :: CropPhase ! Get the current phase of each crop patch ! !PUBLIC for unit testing public :: CNPhenologySetNML ! Set the namelist setttings explicitly for unit tests @@ -2012,7 +2015,7 @@ subroutine CropPhenology(num_pcropp, filter_pcropp , & offset_flag(p) = 0._r8 ! carbon and nitrogen transfers if (croplive(p)) then - cphase(p) = 1._r8 + cphase(p) = cphase_planted ! call vernalization if winter temperate cereal planted, living, and the ! vernalization factor is not 1; @@ -2045,8 +2048,14 @@ subroutine CropPhenology(num_pcropp, filter_pcropp , & hui(p) = max(hui(p),huigrain(p)) endif + ! The following conditionals are similar to those in CropPhase. However, they + ! differ slightly because here we are potentially setting a new crop phase, + ! whereas CropPhase is just designed to get the current, already-determined + ! phase. However, despite these differences: if you make changes to the + ! following conditionals, you should also check to see if you should make + ! similar changes in CropPhase. if (leafout(p) >= huileaf(p) .and. hui(p) < huigrain(p) .and. idpp < mxmat(ivt(p))) then - cphase(p) = 2._r8 + cphase(p) = cphase_leafemerge if (abs(onset_counter(p)) > 1.e-6_r8) then onset_flag(p) = 1._r8 onset_counter(p) = dt @@ -2076,7 +2085,7 @@ subroutine CropPhenology(num_pcropp, filter_pcropp , & harvest_count(p) = harvest_count(p) + 1 crop_inst%hdates_thisyr(p, harvest_count(p)) = real(jday, r8) croplive(p) = .false. ! no re-entry in greater if-block - cphase(p) = 4._r8 + cphase(p) = cphase_harvest if (tlai(p) > 0._r8) then ! plant had emerged before harvest offset_flag(p) = 1._r8 offset_counter(p) = dt @@ -2106,7 +2115,7 @@ subroutine CropPhenology(num_pcropp, filter_pcropp , & ! Use CN's simple formula at least as a place holder (slevis) else if (hui(p) >= huigrain(p)) then - cphase(p) = 3._r8 + cphase(p) = cphase_grainfill bglfr(p) = 1._r8/(leaf_long(ivt(p))*avg_dayspyr*secspday) end if @@ -2144,6 +2153,67 @@ subroutine CropPhenology(num_pcropp, filter_pcropp , & end subroutine CropPhenology + !----------------------------------------------------------------------- + subroutine CropPhase(bounds, num_pcropp, filter_pcropp, & + crop_inst, cnveg_state_inst, crop_phase) + ! + ! !DESCRIPTION: + ! Get the current phase of each crop patch. + ! + ! The returned values (in crop_phase) are from the set of cphase_* values defined in + ! CropType. The returned values in crop_phase are only valid for patches where + ! croplive is true; the values are undefined where croplive is false and should not be + ! used there! + ! + ! This has logic similar to that in CropPhenology. If you make changes here, you + ! should also check if similar changes need to be made in CropPhenology. + ! + ! !ARGUMENTS: + type(bounds_type) , intent(in) :: bounds + integer , intent(in) :: num_pcropp ! number of prog crop patches in filter + integer , intent(in) :: filter_pcropp(:) ! filter for prognostic crop patches + type(crop_type) , intent(in) :: crop_inst + type(cnveg_state_type) , intent(in) :: cnveg_state_inst + real(r8) , intent(inout) :: crop_phase(bounds%begp:) + ! + ! !LOCAL VARIABLES: + integer :: p, fp + + character(len=*), parameter :: subname = 'CropPhase' + !----------------------------------------------------------------------- + SHR_ASSERT_ALL_FL((ubound(crop_phase) == [bounds%endp]), sourcefile, __LINE__) + + associate( & + croplive => crop_inst%croplive_patch , & ! Input: [logical (:) ] Flag, true if planted, not harvested + hui => crop_inst%hui_patch , & ! Input: [real(r8) (:) ] gdd since planting (gddplant) + leafout => crop_inst%gddtsoi_patch , & ! Input: [real(r8) (:) ] gdd from top soil layer temperature + huileaf => cnveg_state_inst%huileaf_patch , & ! Input: [real(r8) (:) ] heat unit index needed from planting to leaf emergence + huigrain => cnveg_state_inst%huigrain_patch & ! Input: [real(r8) (:) ] same to reach vegetative maturity + ) + + do fp = 1, num_pcropp + p = filter_pcropp(fp) + + if (croplive(p)) then + ! Start with cphase_planted, but this might get changed in the later + ! conditional blocks. + crop_phase(p) = cphase_planted + if (leafout(p) >= huileaf(p) .and. hui(p) < huigrain(p)) then + crop_phase(p) = cphase_leafemerge + else if (hui(p) >= huigrain(p)) then + ! Since we know croplive is true, any hui greater than huigrain implies that + ! we're in the grainfill stage: if we were passt gddmaturity then croplive + ! would be false. + crop_phase(p) = cphase_grainfill + end if + end if + end do + + end associate + + end subroutine CropPhase + + !----------------------------------------------------------------------- subroutine CropPhenologyInit(bounds) ! diff --git a/src/biogeochem/CNVegStateType.F90 b/src/biogeochem/CNVegStateType.F90 index e79172c22e..e30bb9c7e7 100644 --- a/src/biogeochem/CNVegStateType.F90 +++ b/src/biogeochem/CNVegStateType.F90 @@ -7,7 +7,7 @@ module CNVegStateType use abortutils , only : endrun use spmdMod , only : masterproc use clm_varpar , only : nlevsno, nlevgrnd, nlevlak, nlevsoi - use clm_varctl , only : use_cn, iulog, fsurdat, use_crop, use_cndv + use clm_varctl , only : use_cn, iulog, fsurdat, use_crop, use_cndv, use_crop_agsys use clm_varcon , only : spval, ispval, grlnd use landunit_varcon, only : istsoil, istcrop use LandunitType , only : lun @@ -15,6 +15,7 @@ module CNVegStateType use PatchType , only : patch use AnnualFluxDribbler, only : annual_flux_dribbler_type, annual_flux_dribbler_patch use dynSubgridControlMod, only : get_for_testing_allow_non_annual_changes + use CropReprPoolsMod, only : nrepr ! ! !PUBLIC TYPES: implicit none @@ -38,8 +39,19 @@ module CNVegStateType real(r8) , pointer :: huigrain_patch (:) ! patch heat unit index needed to reach vegetative maturity real(r8) , pointer :: aleafi_patch (:) ! patch saved leaf allocation coefficient from phase 2 real(r8) , pointer :: astemi_patch (:) ! patch saved stem allocation coefficient from phase 2 + real(r8) , pointer :: aleaf_patch (:) ! patch leaf allocation coefficient real(r8) , pointer :: astem_patch (:) ! patch stem allocation coefficient + real(r8) , pointer :: aroot_patch (:) ! patch root allocation coefficient + real(r8) , pointer :: arepr_patch (:,:) ! patch reproductive allocation coefficient(s) + + ! The following nitrogen-based allocation fractions are just used with the AgSys + ! crop model (use_crop_agsys = .true.): + real(r8) , pointer :: aleaf_n_patch (:) ! patch leaf allocation coefficient for N + real(r8) , pointer :: astem_n_patch (:) ! patch stem allocation coefficient for N + real(r8) , pointer :: aroot_n_patch (:) ! patch root allocation coefficient for N + real(r8) , pointer :: arepr_n_patch (:,:) ! patch reproductive allocation coefficient(s) for N + real(r8) , pointer :: htmx_patch (:) ! patch max hgt attained by a crop during yr (m) integer , pointer :: peaklai_patch (:) ! patch 1: max allowed lai; 0: not at max @@ -199,8 +211,19 @@ subroutine InitAllocate(this, bounds) allocate(this%huigrain_patch (begp:endp)) ; this%huigrain_patch (:) = 0.0_r8 allocate(this%aleafi_patch (begp:endp)) ; this%aleafi_patch (:) = nan allocate(this%astemi_patch (begp:endp)) ; this%astemi_patch (:) = nan + allocate(this%aleaf_patch (begp:endp)) ; this%aleaf_patch (:) = nan allocate(this%astem_patch (begp:endp)) ; this%astem_patch (:) = nan + allocate(this%aroot_patch (begp:endp)) ; this%aroot_patch (:) = nan + allocate(this%arepr_patch (begp:endp, nrepr)) ; this%arepr_patch (:,:) = nan + + if (use_crop_agsys) then + allocate(this%aleaf_n_patch (begp:endp)) ; this%aleaf_n_patch (:) = nan + allocate(this%astem_n_patch (begp:endp)) ; this%astem_n_patch (:) = nan + allocate(this%aroot_n_patch (begp:endp)) ; this%aroot_n_patch (:) = nan + allocate(this%arepr_n_patch (begp:endp, nrepr)) ; this%arepr_n_patch (:,:) = nan + end if + allocate(this%htmx_patch (begp:endp)) ; this%htmx_patch (:) = 0.0_r8 allocate(this%peaklai_patch (begp:endp)) ; this%peaklai_patch (:) = 0 diff --git a/src/biogeochem/CNVegetationFacade.F90 b/src/biogeochem/CNVegetationFacade.F90 index a03eee2841..384e4a4966 100644 --- a/src/biogeochem/CNVegetationFacade.F90 +++ b/src/biogeochem/CNVegetationFacade.F90 @@ -879,6 +879,7 @@ subroutine EcosystemDynamicsPreDrainage(this, bounds, & num_soilc, filter_soilc, & num_soilp, filter_soilp, & num_pcropp, filter_pcropp, & + num_soilnopcropp, filter_soilnopcropp, & num_exposedvegp, filter_exposedvegp, & num_noexposedvegp, filter_noexposedvegp, & soilbiogeochem_carbonflux_inst, soilbiogeochem_carbonstate_inst, & @@ -910,6 +911,8 @@ subroutine EcosystemDynamicsPreDrainage(this, bounds, & integer , intent(in) :: filter_soilp(:) ! filter for soil patches integer , intent(in) :: num_pcropp ! number of prog. crop patches in filter integer , intent(in) :: filter_pcropp(:) ! filter for prognostic crop patches + integer , intent(in) :: num_soilnopcropp ! number of non-prog. crop soil patches in filter + integer , intent(in) :: filter_soilnopcropp(:) ! filter for non-prog. crop soil patches integer , intent(in) :: num_exposedvegp ! number of points in filter_exposedvegp integer , intent(in) :: filter_exposedvegp(:) ! patch filter for non-snow-covered veg integer , intent(in) :: num_noexposedvegp ! number of points in filter_noexposedvegp @@ -952,6 +955,7 @@ subroutine EcosystemDynamicsPreDrainage(this, bounds, & num_soilc, filter_soilc, & num_soilp, filter_soilp, & num_pcropp, filter_pcropp, & + num_soilnopcropp, filter_soilnopcropp, & num_exposedvegp, filter_exposedvegp, & num_noexposedvegp, filter_noexposedvegp, & this%cnveg_state_inst, & diff --git a/src/biogeochem/CropType.F90 b/src/biogeochem/CropType.F90 index d3a860978f..6ceeccf7e3 100644 --- a/src/biogeochem/CropType.F90 +++ b/src/biogeochem/CropType.F90 @@ -24,6 +24,14 @@ module CropType ! ! !PUBLIC DATA TYPES: ! + + ! Possible values of cphase + real(r8), parameter, public :: cphase_not_planted = 0._r8 + real(r8), parameter, public :: cphase_planted = 1._r8 + real(r8), parameter, public :: cphase_leafemerge = 2._r8 + real(r8), parameter, public :: cphase_grainfill = 3._r8 + real(r8), parameter, public :: cphase_harvest = 4._r8 + ! Crop state variables structure type, public :: crop_type @@ -33,7 +41,7 @@ module CropType real(r8), pointer :: fertnitro_patch (:) ! patch fertilizer nitrogen real(r8), pointer :: gddtsoi_patch (:) ! patch growing degree-days from planting (top two soil layers) (ddays) real(r8), pointer :: vf_patch (:) ! patch vernalization factor for cereal - real(r8), pointer :: cphase_patch (:) ! phenology phase + real(r8), pointer :: cphase_patch (:) ! phenology phase (see cphase_* constants above for possible values) real(r8), pointer :: latbaset_patch (:) ! Latitude vary baset for hui (degree C) character(len=20) :: baset_mapping real(r8) :: baset_latvary_intercept @@ -205,7 +213,7 @@ subroutine InitAllocate(this, bounds) allocate(this%gddaccum_patch (begp:endp)) ; this%gddaccum_patch (:) = spval allocate(this%gddtsoi_patch (begp:endp)) ; this%gddtsoi_patch (:) = spval allocate(this%vf_patch (begp:endp)) ; this%vf_patch (:) = 0.0_r8 - allocate(this%cphase_patch (begp:endp)) ; this%cphase_patch (:) = 0.0_r8 + allocate(this%cphase_patch (begp:endp)) ; this%cphase_patch (:) = cphase_not_planted allocate(this%latbaset_patch (begp:endp)) ; this%latbaset_patch (:) = spval allocate(this%sdates_thisyr(begp:endp,1:mxsowings)) ; this%sdates_thisyr(:,:) = spval allocate(this%hdates_thisyr(begp:endp,1:mxharvests)) ; this%hdates_thisyr(:,:) = spval diff --git a/src/biogeochem/NutrientCompetitionCLM45defaultMod.F90 b/src/biogeochem/NutrientCompetitionCLM45defaultMod.F90 index 995871c536..9b1f8f9d09 100644 --- a/src/biogeochem/NutrientCompetitionCLM45defaultMod.F90 +++ b/src/biogeochem/NutrientCompetitionCLM45defaultMod.F90 @@ -11,14 +11,17 @@ module NutrientCompetitionCLM45defaultMod ! ! !USES: use shr_kind_mod , only : r8 => shr_kind_r8 + use shr_log_mod , only : errMsg => shr_log_errMsg use decompMod , only : bounds_type - use LandunitType , only : lun - use ColumnType , only : col - use PatchType , only : patch + use LandunitType , only : lun + use ColumnType , only : col + use PatchType , only : patch use NutrientCompetitionMethodMod, only : nutrient_competition_method_type - use NutrientCompetitionMethodMod, only : params_inst use CropReprPoolsMod , only : nrepr - !use clm_varctl , only : iulog + use CNPhenologyMod , only : CropPhase + use CropType , only : cphase_leafemerge, cphase_grainfill + use clm_varctl , only : iulog + use abortutils , only : endrun ! implicit none private @@ -32,7 +35,7 @@ module NutrientCompetitionCLM45defaultMod ! public methocs procedure, public :: init ! Initialize the class procedure, public :: calc_plant_nutrient_competition ! calculate nutrient yield rate from competition - procedure, public :: calc_plant_nutrient_demand ! calculate plant nutrient demand + procedure, public :: calc_plant_nutrient_demand ! calculate plant nutrient demand ! ! private methods procedure, private:: calc_plant_cn_alloc @@ -41,14 +44,14 @@ module NutrientCompetitionCLM45defaultMod ! interface nutrient_competition_clm45default_type ! initialize a new nutrient_competition_clm45default_type object - module procedure constructor + module procedure constructor end interface nutrient_competition_clm45default_type ! character(len=*), parameter, private :: sourcefile = & __FILE__ !------------------------------------------------------------------------ - + contains !------------------------------------------------------------------------ @@ -78,8 +81,7 @@ subroutine calc_plant_nutrient_competition (this, & cnveg_carbonflux_inst, & c13_cnveg_carbonflux_inst, c14_cnveg_carbonflux_inst, & cnveg_nitrogenstate_inst, cnveg_nitrogenflux_inst, & - soilbiogeochem_nitrogenstate_inst, & - aroot, arepr, fpg_col) + soilbiogeochem_nitrogenstate_inst, fpg_col) ! ! !USES: use CNVegStateType , only : cnveg_state_type @@ -107,16 +109,12 @@ subroutine calc_plant_nutrient_competition (this, & type(cnveg_nitrogenstate_type) , intent(inout) :: cnveg_nitrogenstate_inst type(cnveg_nitrogenflux_type) , intent(inout) :: cnveg_nitrogenflux_inst type(soilbiogeochem_nitrogenstate_type), intent(in) :: soilbiogeochem_nitrogenstate_inst - real(r8) , intent(in) :: aroot(bounds%begp:) - real(r8) , intent(in) :: arepr(bounds%begp:,:) real(r8) , intent(in) :: fpg_col(bounds%begc:) 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, & - aroot=aroot(bounds%begp:bounds%endp), & - arepr=arepr(bounds%begp:bounds%endp,:), & fpg_col=fpg_col(bounds%begc:bounds%endc)) end subroutine calc_plant_nutrient_competition @@ -125,8 +123,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, & - aroot, arepr, fpg_col) + c14_cnveg_carbonflux_inst, cnveg_nitrogenflux_inst, fpg_col) ! ! !USES: use pftconMod , only : pftcon, npcropmin @@ -154,8 +151,6 @@ 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 - real(r8) , intent(in) :: aroot(bounds%begp:) - real(r8) , intent(in) :: arepr(bounds%begp:,:) real(r8) , intent(in) :: fpg_col(bounds%begc:) ! ! !LOCAL VARIABLES: @@ -168,82 +163,82 @@ subroutine calc_plant_cn_alloc (this, bounds, num_soilp, filter_soilp, & real(r8):: nlc ! temporary variable for total new leaf carbon allocation real(r8):: f5(nrepr) ! reproductive allocation parameters real(r8):: cng ! C:N ratio for grain (= cnlw for now; slevis) - real(r8):: fsmn(bounds%begp:bounds%endp) ! A emperate variable for adjusting FUN uptakes + real(r8):: fsmn(bounds%begp:bounds%endp) ! A emperate variable for adjusting FUN uptakes !----------------------------------------------------------------------- - SHR_ASSERT_ALL_FL((ubound(aroot) == (/bounds%endp/)), sourcefile, __LINE__) - SHR_ASSERT_ALL_FL((ubound(arepr) == (/bounds%endp, nrepr/)), sourcefile, __LINE__) SHR_ASSERT_ALL_FL((ubound(fpg_col) == (/bounds%endc/)), sourcefile, __LINE__) associate( & - fpg => fpg_col , & ! Input: [real(r8) (:) ] fraction of potential gpp (no units) + fpg => fpg_col , & ! Input: [real(r8) (:) ] fraction of potential gpp (no units) + + ivt => patch%itype , & ! Input: [integer (:) ] patch vegetation type - ivt => patch%itype , & ! Input: [integer (:) ] patch vegetation type - woody => pftcon%woody , & ! Input: binary flag for woody lifeform (1=woody, 0=not woody) froot_leaf => pftcon%froot_leaf , & ! Input: allocation parameter: new fine root C per new leaf C (gC/gC) 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) - frootcn => pftcon%frootcn , & ! Input: fine root C:N (gC/gN) + 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) fcur2 => pftcon%fcur , & ! Input: allocation parameter: fraction of allocation that goes to currently displayed growth, remainder to storage - graincn => pftcon%graincn , & ! Input: grain C:N (gC/gN) + graincn => pftcon%graincn , & ! Input: grain C:N (gC/gN) grperc => pftcon%grperc , & ! Input: growth respiration parameter grpnow => pftcon%grpnow , & ! Input: growth respiration parameter croplive => crop_inst%croplive_patch , & ! Input: [logical (:) ] flag, true if planted, not harvested - peaklai => cnveg_state_inst%peaklai_patch , & ! Input: [integer (:) ] 1: max allowed lai; 0: not at max - aleaf => cnveg_state_inst%aleaf_patch , & ! Output: [real(r8) (:) ] leaf allocation coefficient - astem => cnveg_state_inst%astem_patch , & ! Output: [real(r8) (:) ] stem allocation coefficient - c_allometry => cnveg_state_inst%c_allometry_patch , & ! Output: [real(r8) (:) ] C allocation index (DIM) - n_allometry => cnveg_state_inst%n_allometry_patch , & ! Output: [real(r8) (:) ] N allocation index (DIM) + peaklai => cnveg_state_inst%peaklai_patch , & ! Input: [integer (:) ] 1: max allowed lai; 0: not at max + aleaf => cnveg_state_inst%aleaf_patch , & ! Input: [real(r8) (:) ] leaf allocation coefficient + astem => cnveg_state_inst%astem_patch , & ! Input: [real(r8) (:) ] stem allocation coefficient + aroot => cnveg_state_inst%aroot_patch , & ! Input: [real(r8) (:) ] root allocation coefficient + arepr => cnveg_state_inst%arepr_patch , & ! Input: [real(r8) (:,:) ] reproductive allocation coefficient(s) + c_allometry => cnveg_state_inst%c_allometry_patch , & ! Output: [real(r8) (:) ] C allocation index (DIM) + n_allometry => cnveg_state_inst%n_allometry_patch , & ! Output: [real(r8) (:) ] N allocation index (DIM) downreg => cnveg_state_inst%downreg_patch , & ! Output: [real(r8) (:) ] fractional reduction in GPP due to N limitation (DIM) - annsum_npp => cnveg_carbonflux_inst%annsum_npp_patch , & ! Input: [real(r8) (:) ] annual sum of NPP, for wood allocation + annsum_npp => cnveg_carbonflux_inst%annsum_npp_patch , & ! Input: [real(r8) (:) ] annual sum of NPP, for wood allocation gpp => cnveg_carbonflux_inst%gpp_before_downreg_patch , & ! Output: [real(r8) (:) ] GPP flux before downregulation (gC/m2/s) availc => cnveg_carbonflux_inst%availc_patch , & ! Output: [real(r8) (:) ] C flux available for allocation (gC/m2/s) excess_cflux => cnveg_carbonflux_inst%excess_cflux_patch , & ! Output: [real(r8) (:) ] C flux not allocated due to downregulation (gC/m2/s) - plant_calloc => cnveg_carbonflux_inst%plant_calloc_patch , & ! Output: [real(r8) (:) ] total allocated C flux (gC/m2/s) + plant_calloc => cnveg_carbonflux_inst%plant_calloc_patch , & ! Output: [real(r8) (:) ] total allocated C flux (gC/m2/s) psnsun_to_cpool => cnveg_carbonflux_inst%psnsun_to_cpool_patch , & ! Output: [real(r8) (:) ] psnshade_to_cpool => cnveg_carbonflux_inst%psnshade_to_cpool_patch , & ! Output: [real(r8) (:) ] - cpool_to_leafc => cnveg_carbonflux_inst%cpool_to_leafc_patch , & ! Output: [real(r8) (:) ] - cpool_to_leafc_storage => cnveg_carbonflux_inst%cpool_to_leafc_storage_patch , & ! Output: [real(r8) (:) ] - cpool_to_frootc => cnveg_carbonflux_inst%cpool_to_frootc_patch , & ! Output: [real(r8) (:) ] - cpool_to_frootc_storage => cnveg_carbonflux_inst%cpool_to_frootc_storage_patch , & ! Output: [real(r8) (:) ] - cpool_to_livestemc => cnveg_carbonflux_inst%cpool_to_livestemc_patch , & ! Output: [real(r8) (:) ] - cpool_to_livestemc_storage => cnveg_carbonflux_inst%cpool_to_livestemc_storage_patch , & ! Output: [real(r8) (:) ] - cpool_to_deadstemc => cnveg_carbonflux_inst%cpool_to_deadstemc_patch , & ! Output: [real(r8) (:) ] - cpool_to_deadstemc_storage => cnveg_carbonflux_inst%cpool_to_deadstemc_storage_patch , & ! Output: [real(r8) (:) ] - cpool_to_livecrootc => cnveg_carbonflux_inst%cpool_to_livecrootc_patch , & ! Output: [real(r8) (:) ] - cpool_to_livecrootc_storage => cnveg_carbonflux_inst%cpool_to_livecrootc_storage_patch , & ! Output: [real(r8) (:) ] - cpool_to_deadcrootc => cnveg_carbonflux_inst%cpool_to_deadcrootc_patch , & ! Output: [real(r8) (:) ] - cpool_to_deadcrootc_storage => cnveg_carbonflux_inst%cpool_to_deadcrootc_storage_patch , & ! Output: [real(r8) (:) ] + cpool_to_leafc => cnveg_carbonflux_inst%cpool_to_leafc_patch , & ! Output: [real(r8) (:) ] + cpool_to_leafc_storage => cnveg_carbonflux_inst%cpool_to_leafc_storage_patch , & ! Output: [real(r8) (:) ] + cpool_to_frootc => cnveg_carbonflux_inst%cpool_to_frootc_patch , & ! Output: [real(r8) (:) ] + cpool_to_frootc_storage => cnveg_carbonflux_inst%cpool_to_frootc_storage_patch , & ! Output: [real(r8) (:) ] + cpool_to_livestemc => cnveg_carbonflux_inst%cpool_to_livestemc_patch , & ! Output: [real(r8) (:) ] + cpool_to_livestemc_storage => cnveg_carbonflux_inst%cpool_to_livestemc_storage_patch , & ! Output: [real(r8) (:) ] + cpool_to_deadstemc => cnveg_carbonflux_inst%cpool_to_deadstemc_patch , & ! Output: [real(r8) (:) ] + cpool_to_deadstemc_storage => cnveg_carbonflux_inst%cpool_to_deadstemc_storage_patch , & ! Output: [real(r8) (:) ] + cpool_to_livecrootc => cnveg_carbonflux_inst%cpool_to_livecrootc_patch , & ! Output: [real(r8) (:) ] + cpool_to_livecrootc_storage => cnveg_carbonflux_inst%cpool_to_livecrootc_storage_patch , & ! Output: [real(r8) (:) ] + cpool_to_deadcrootc => cnveg_carbonflux_inst%cpool_to_deadcrootc_patch , & ! Output: [real(r8) (:) ] + cpool_to_deadcrootc_storage => cnveg_carbonflux_inst%cpool_to_deadcrootc_storage_patch , & ! Output: [real(r8) (:) ] cpool_to_gresp_storage => cnveg_carbonflux_inst%cpool_to_gresp_storage_patch , & ! Output: [real(r8) (:) ] allocation to growth respiration storage (gC/m2/s) cpool_to_reproductivec => cnveg_carbonflux_inst%cpool_to_reproductivec_patch , & ! Output: [real(r8) (:,:) ] allocation to grain C (gC/m2/s) cpool_to_reproductivec_storage => cnveg_carbonflux_inst%cpool_to_reproductivec_storage_patch , & ! Output: [real(r8) (:,:) ] allocation to grain C storage (gC/m2/s) - + plant_ndemand => cnveg_nitrogenflux_inst%plant_ndemand_patch , & ! Output: [real(r8) (:) ] N flux required to support initial GPP (gN/m2/s) - plant_nalloc => cnveg_nitrogenflux_inst%plant_nalloc_patch , & ! Output: [real(r8) (:) ] total allocated N flux (gN/m2/s) + plant_nalloc => cnveg_nitrogenflux_inst%plant_nalloc_patch , & ! Output: [real(r8) (:) ] total allocated N flux (gN/m2/s) npool_to_reproductiven => cnveg_nitrogenflux_inst%npool_to_reproductiven_patch , & ! Output: [real(r8) (:,:) ] allocation to grain N (gN/m2/s) npool_to_reproductiven_storage => cnveg_nitrogenflux_inst%npool_to_reproductiven_storage_patch , & ! Output: [real(r8) (:,:) ] allocation to grain N storage (gN/m2/s) retransn_to_npool => cnveg_nitrogenflux_inst%retransn_to_npool_patch , & ! Output: [real(r8) (:) ] deployment of retranslocated N (gN/m2/s) sminn_to_npool => cnveg_nitrogenflux_inst%sminn_to_npool_patch , & ! Output: [real(r8) (:) ] deployment of soil mineral N uptake (gN/m2/s) - npool_to_leafn => cnveg_nitrogenflux_inst%npool_to_leafn_patch , & ! Output: [real(r8) (:) ] allocation to leaf N (gN/m2/s) - npool_to_leafn_storage => cnveg_nitrogenflux_inst%npool_to_leafn_storage_patch , & ! Output: [real(r8) (:) ] allocation to leaf N storage (gN/m2/s) - npool_to_frootn => cnveg_nitrogenflux_inst%npool_to_frootn_patch , & ! Output: [real(r8) (:) ] allocation to fine root N (gN/m2/s) + npool_to_leafn => cnveg_nitrogenflux_inst%npool_to_leafn_patch , & ! Output: [real(r8) (:) ] allocation to leaf N (gN/m2/s) + npool_to_leafn_storage => cnveg_nitrogenflux_inst%npool_to_leafn_storage_patch , & ! Output: [real(r8) (:) ] allocation to leaf N storage (gN/m2/s) + npool_to_frootn => cnveg_nitrogenflux_inst%npool_to_frootn_patch , & ! Output: [real(r8) (:) ] allocation to fine root N (gN/m2/s) npool_to_frootn_storage => cnveg_nitrogenflux_inst%npool_to_frootn_storage_patch , & ! Output: [real(r8) (:) ] allocation to fine root N storage (gN/m2/s) - npool_to_livestemn => cnveg_nitrogenflux_inst%npool_to_livestemn_patch , & ! Output: [real(r8) (:) ] - npool_to_livestemn_storage => cnveg_nitrogenflux_inst%npool_to_livestemn_storage_patch , & ! Output: [real(r8) (:) ] - npool_to_deadstemn => cnveg_nitrogenflux_inst%npool_to_deadstemn_patch , & ! Output: [real(r8) (:) ] - npool_to_deadstemn_storage => cnveg_nitrogenflux_inst%npool_to_deadstemn_storage_patch , & ! Output: [real(r8) (:) ] - npool_to_livecrootn => cnveg_nitrogenflux_inst%npool_to_livecrootn_patch , & ! Output: [real(r8) (:) ] - npool_to_livecrootn_storage => cnveg_nitrogenflux_inst%npool_to_livecrootn_storage_patch , & ! Output: [real(r8) (:) ] - npool_to_deadcrootn => cnveg_nitrogenflux_inst%npool_to_deadcrootn_patch , & ! Output: [real(r8) (:) ] - npool_to_deadcrootn_storage => cnveg_nitrogenflux_inst%npool_to_deadcrootn_storage_patch , & ! Output: [real(r8) (:) ] + npool_to_livestemn => cnveg_nitrogenflux_inst%npool_to_livestemn_patch , & ! Output: [real(r8) (:) ] + npool_to_livestemn_storage => cnveg_nitrogenflux_inst%npool_to_livestemn_storage_patch , & ! Output: [real(r8) (:) ] + npool_to_deadstemn => cnveg_nitrogenflux_inst%npool_to_deadstemn_patch , & ! Output: [real(r8) (:) ] + npool_to_deadstemn_storage => cnveg_nitrogenflux_inst%npool_to_deadstemn_storage_patch , & ! Output: [real(r8) (:) ] + npool_to_livecrootn => cnveg_nitrogenflux_inst%npool_to_livecrootn_patch , & ! Output: [real(r8) (:) ] + npool_to_livecrootn_storage => cnveg_nitrogenflux_inst%npool_to_livecrootn_storage_patch , & ! Output: [real(r8) (:) ] + npool_to_deadcrootn => cnveg_nitrogenflux_inst%npool_to_deadcrootn_patch , & ! Output: [real(r8) (:) ] + npool_to_deadcrootn_storage => cnveg_nitrogenflux_inst%npool_to_deadcrootn_storage_patch , & ! Output: [real(r8) (:) ] Npassive => cnveg_nitrogenflux_inst%Npassive_patch , & ! Output: [real(r8) (:) ] Passive N uptake (gN/m2/s) Nfix => cnveg_nitrogenflux_inst%Nfix_patch , & ! Output: [real(r8) (:) ] Symbiotic BNF (gN/m2/s) Nactive => cnveg_nitrogenflux_inst%Nactive_patch , & ! Output: [real(r8) (:) ] Mycorrhizal N uptake (gN/m2/s) @@ -253,14 +248,13 @@ subroutine calc_plant_cn_alloc (this, bounds, num_soilp, filter_soilp, & sminn_to_plant_fun => cnveg_nitrogenflux_inst%sminn_to_plant_fun_patch & ! Output: [real(r8) (:) ] Total N uptake of FUN (gN/m2/s) ) - ! patch loop to distribute the available N between the competing patches + ! patch loop to distribute the available N between the competing patches ! on the basis of relative demand, and allocate C and N to new growth and storage do fp = 1,num_soilp p = filter_soilp(fp) c = patch%column(p) - ! set some local allocation variables f1 = froot_leaf(ivt(p)) f2 = croot_stem(ivt(p)) @@ -307,15 +301,15 @@ subroutine calc_plant_cn_alloc (this, bounds, num_soilp, filter_soilp, & if(use_fun)then ! if we are using FUN, we get the N available from there. sminn_to_npool(p) = sminn_to_plant_fun(p) - else ! no FUN. :( we get N available from the FPG calculation in soilbiogeochemistry competition. - sminn_to_npool(p) = plant_ndemand(p) * fpg(c) + else ! no FUN. :( we get N available from the FPG calculation in soilbiogeochemistry competition. + sminn_to_npool(p) = plant_ndemand(p) * fpg(c) endif - + plant_nalloc(p) = sminn_to_npool(p) + retransn_to_npool(p) plant_calloc(p) = plant_nalloc(p) * (c_allometry(p)/n_allometry(p)) - - if(.not.use_fun)then !ORIGINAL CLM(CN) downregulation code. + + if(.not.use_fun)then !ORIGINAL CLM(CN) downregulation code. excess_cflux(p) = availc(p) - plant_calloc(p) ! reduce gpp fluxes due to N limitation if (gpp(p) > 0.0_r8) then @@ -337,9 +331,9 @@ subroutine calc_plant_cn_alloc (this, bounds, num_soilp, filter_soilp, & c14_cnveg_carbonflux_inst%psnshade_to_cpool_patch(p)*(1._r8 - downreg(p)) endif end if - + end if !use_fun - + ! calculate the amount of new leaf C dictated by these allocation ! decisions, and calculate the daily fluxes of C and N to current ! growth and storage pools @@ -437,23 +431,21 @@ subroutine calc_plant_cn_alloc (this, bounds, num_soilp, filter_soilp, & end do ! end patch loop - end associate + end associate end subroutine calc_plant_cn_alloc !----------------------------------------------------------------------- - subroutine calc_plant_nutrient_demand(this, bounds, num_soilp, filter_soilp,& - photosyns_inst, crop_inst, canopystate_inst, & + subroutine calc_plant_nutrient_demand(this, bounds, & + num_p, filter_p, call_is_for_pcrop, & + crop_inst, canopystate_inst, & cnveg_state_inst, cnveg_carbonstate_inst, cnveg_carbonflux_inst, & - c13_cnveg_carbonflux_inst, c14_cnveg_carbonflux_inst, & cnveg_nitrogenstate_inst, cnveg_nitrogenflux_inst, & soilbiogeochem_carbonflux_inst, soilbiogeochem_nitrogenstate_inst, & - energyflux_inst, & - aroot, arepr) + energyflux_inst) ! ! !USES: use CanopyStateType , only : canopystate_type - use PhotosynthesisMod , only : photosyns_type use CropType , only : crop_type use CNVegStateType , only : cnveg_state_type use CNVegCarbonStateType , only : cnveg_carbonstate_type @@ -468,52 +460,58 @@ subroutine calc_plant_nutrient_demand(this, bounds, num_soilp, filter_soilp,& ! !ARGUMENTS: class(nutrient_competition_clm45default_type), intent(inout) :: this type(bounds_type) , intent(in) :: bounds - integer , intent(in) :: num_soilp ! number of soil patches in filter - integer , intent(in) :: filter_soilp(:) ! filter for soil patches - type(photosyns_type) , intent(in) :: photosyns_inst + + ! This subroutine is meant to be called separately for non-prognostic-crop points and + ! prognostic-crop points. (The reason for this is so that the call for prognostic-crop + ! points can be skipped when a separate crop model is calculating these variables.) In + ! the call for non-prognostic-crop points, this filter should be the soilnopcropp + ! filter and call_is_for_pcrop should be false; in the call for prognostic-crop + ! points, this filter should be the pcropp filter and call_is_for_pcrop should be + ! true. + integer , intent(in) :: num_p ! number of patches in filter + integer , intent(in) :: filter_p(:) ! patch filter + logical , intent(in) :: call_is_for_pcrop + type(crop_type) , intent(in) :: crop_inst - type(canopystate_type) , intent(in) :: canopystate_inst + type(canopystate_type) , intent(in) :: canopystate_inst ! unused in this version type(cnveg_state_type) , intent(inout) :: cnveg_state_inst - type(cnveg_carbonstate_type) , intent(inout) :: cnveg_carbonstate_inst - type(cnveg_carbonflux_type) , intent(inout) :: cnveg_carbonflux_inst - type(cnveg_carbonflux_type) , intent(inout) :: c13_cnveg_carbonflux_inst - type(cnveg_carbonflux_type) , intent(inout) :: c14_cnveg_carbonflux_inst + type(cnveg_carbonstate_type) , intent(in) :: cnveg_carbonstate_inst + type(cnveg_carbonflux_type) , intent(in) :: cnveg_carbonflux_inst type(cnveg_nitrogenstate_type) , intent(in) :: cnveg_nitrogenstate_inst type(cnveg_nitrogenflux_type) , intent(inout) :: cnveg_nitrogenflux_inst type(soilbiogeochem_carbonflux_type) , intent(in) :: soilbiogeochem_carbonflux_inst type(soilbiogeochem_nitrogenstate_type), intent(in) :: soilbiogeochem_nitrogenstate_inst type(energyflux_type) , intent(in) :: energyflux_inst - real(r8) , intent(out) :: aroot(bounds%begp:) - real(r8) , intent(out) :: arepr(bounds%begp:,:) !----------------------------------------------------------------------- - call this%calc_plant_nitrogen_demand(bounds, num_soilp, filter_soilp, & - photosyns_inst, crop_inst, canopystate_inst, & + call this%calc_plant_nitrogen_demand(bounds, & + num_p, filter_p, call_is_for_pcrop, & + crop_inst, & cnveg_state_inst, cnveg_carbonstate_inst, cnveg_carbonflux_inst, & - c13_cnveg_carbonflux_inst, c14_cnveg_carbonflux_inst, & - cnveg_nitrogenstate_inst, cnveg_nitrogenflux_inst, & - aroot=aroot(bounds%begp:bounds%endp), & - arepr=arepr(bounds%begp:bounds%endp,:)) + cnveg_nitrogenstate_inst, cnveg_nitrogenflux_inst) end subroutine calc_plant_nutrient_demand !----------------------------------------------------------------------- - subroutine calc_plant_nitrogen_demand(this, bounds, num_soilp, filter_soilp, & - photosyns_inst, crop_inst, canopystate_inst, & + subroutine calc_plant_nitrogen_demand(this, bounds, & + num_p, filter_p, call_is_for_pcrop, & + crop_inst, & cnveg_state_inst, cnveg_carbonstate_inst, cnveg_carbonflux_inst, & - c13_cnveg_carbonflux_inst, c14_cnveg_carbonflux_inst, & - cnveg_nitrogenstate_inst, cnveg_nitrogenflux_inst, & - aroot, arepr) + cnveg_nitrogenstate_inst, cnveg_nitrogenflux_inst) + ! + ! !DESCRIPTION: + ! Sets the following output variables that are used elsewhere: + ! - plant_ndemand + ! - retransn_to_npool + ! - leafn_to_retransn + ! - frootn_to_retransn + ! - livestemn_to_retransn ! ! !USES: use pftconMod , only : npcropmin, pftcon use pftconMod , only : ntmp_soybean, nirrig_tmp_soybean use pftconMod , only : ntrp_soybean, nirrig_trp_soybean - use clm_varcon , only : secspday - use clm_varctl , only : use_c13, use_c14 use clm_time_manager , only : get_step_size_real - use CanopyStateType , only : canopystate_type - use PhotosynthesisMod , only : photosyns_type use CropType , only : crop_type use CNVegStateType , only : cnveg_state_type use CNVegCarbonStateType , only : cnveg_carbonstate_type @@ -525,510 +523,208 @@ subroutine calc_plant_nitrogen_demand(this, bounds, num_soilp, filter_soilp, & ! !ARGUMENTS: class(nutrient_competition_clm45default_type), intent(in) :: this type(bounds_type) , intent(in) :: bounds - integer , intent(in) :: num_soilp ! number of soil patches in filter - integer , intent(in) :: filter_soilp(:) ! filter for soil patches - type(photosyns_type) , intent(in) :: photosyns_inst + + ! This subroutine is meant to be called separately for non-prognostic-crop points and + ! prognostic-crop points. (The reason for this is so that the call for prognostic-crop + ! points can be skipped when a separate crop model is calculating these variables.) In + ! the call for non-prognostic-crop points, this filter should be the soilnopcropp + ! filter and call_is_for_pcrop should be false; in the call for prognostic-crop + ! points, this filter should be the pcropp filter and call_is_for_pcrop should be + ! true. + integer , intent(in) :: num_p ! number of patches in filter + integer , intent(in) :: filter_p(:) ! patch filter + logical , intent(in) :: call_is_for_pcrop + type(crop_type) , intent(in) :: crop_inst - type(canopystate_type) , intent(in) :: canopystate_inst type(cnveg_state_type) , intent(inout) :: cnveg_state_inst - type(cnveg_carbonstate_type) , intent(inout) :: cnveg_carbonstate_inst - type(cnveg_carbonflux_type) , intent(inout) :: cnveg_carbonflux_inst - type(cnveg_carbonflux_type) , intent(inout) :: c13_cnveg_carbonflux_inst - type(cnveg_carbonflux_type) , intent(inout) :: c14_cnveg_carbonflux_inst + type(cnveg_carbonstate_type) , intent(in) :: cnveg_carbonstate_inst + type(cnveg_carbonflux_type) , intent(in) :: cnveg_carbonflux_inst type(cnveg_nitrogenstate_type) , intent(in) :: cnveg_nitrogenstate_inst type(cnveg_nitrogenflux_type) , intent(inout) :: cnveg_nitrogenflux_inst - real(r8) , intent(out) :: aroot(bounds%begp:) - real(r8) , intent(out) :: arepr(bounds%begp:,:) ! ! !LOCAL VARIABLES: - integer :: c,p,l,j,k ! indices + integer :: p,l,j ! indices integer :: fp ! lake filter patch index - real(r8):: mr ! maintenance respiration (gC/m2/s) - real(r8):: reproductive_mr_tot ! total maintenance respiration from grain components (gC/m2/s) - real(r8):: f1,f2,f3,f4,g1,g2 ! allocation parameters - real(r8):: g1a ! g1 included in allocation/allometry - real(r8):: cnl,cnfr,cnlw,cndw ! C:N ratios for leaf, fine root, and wood - real(r8):: curmr, curmr_ratio ! xsmrpool temporary variables - real(r8):: f5(nrepr) ! reproductive allocation parameters - real(r8):: cng ! C:N ratio for grain (= cnlw for now; slevis) - real(r8):: fleaf ! fraction allocated to leaf real(r8):: t1 ! temporary variable real(r8):: dt ! model time step - real(r8):: dayscrecover ! number of days to recover negative cpool - real(r8):: f5_tot ! sum of f5 terms - real(r8):: f5_n_tot ! sum of f5 terms converted from C to N + real(r8):: crop_phase(bounds%begp:bounds%endp) + character(len=*), parameter :: subname = "calc_plant_nitrogen_demand" !----------------------------------------------------------------------- - SHR_ASSERT_ALL_FL((ubound(aroot) == (/bounds%endp/)), sourcefile, __LINE__) - SHR_ASSERT_ALL_FL((ubound(arepr) == (/bounds%endp, nrepr/)), sourcefile, __LINE__) - associate( & - ivt => patch%itype , & ! Input: [integer (:) ] patch vegetation type - - woody => pftcon%woody , & ! Input: binary flag for woody lifeform (1=woody, 0=not woody) - froot_leaf => pftcon%froot_leaf , & ! Input: allocation parameter: new fine root C per new leaf C (gC/gC) - 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) - 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) - graincn => pftcon%graincn , & ! Input: grain 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 - bfact => pftcon%bfact , & ! Input: parameter used below - aleaff => pftcon%aleaff , & ! Input: parameter used below - arootf => pftcon%arootf , & ! Input: parameter used below + ivt => patch%itype , & ! Input: [integer (:) ] patch vegetation type + + 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) + graincn => pftcon%graincn , & ! Input: grain 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 astemf => pftcon%astemf , & ! Input: parameter used below - arooti => pftcon%arooti , & ! Input: parameter used below - fleafi => pftcon%fleafi , & ! Input: parameter used below - allconsl => pftcon%allconsl , & ! Input: parameter used below - allconss => pftcon%allconss , & ! Input: parameter used below - grperc => pftcon%grperc , & ! Input: parameter used below - grpnow => pftcon%grpnow , & ! Input: parameter used below - declfact => pftcon%declfact , & ! Input: 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-deciduous leaf habit (0 or 1) - psnsun => photosyns_inst%psnsun_patch , & ! Input: [real(r8) (:) ] sunlit leaf-level photosynthesis (umol CO2 /m**2/ s) - psnsha => photosyns_inst%psnsha_patch , & ! Input: [real(r8) (:) ] shaded leaf-level photosynthesis (umol CO2 /m**2/ s) - c13_psnsun => photosyns_inst%c13_psnsun_patch , & ! Input: [real(r8) (:) ] sunlit leaf-level photosynthesis (umol CO2 /m**2/ s) - c13_psnsha => photosyns_inst%c13_psnsha_patch , & ! Input: [real(r8) (:) ] shaded leaf-level photosynthesis (umol CO2 /m**2/ s) - c14_psnsun => photosyns_inst%c14_psnsun_patch , & ! Input: [real(r8) (:) ] sunlit leaf-level photosynthesis (umol CO2 /m**2/ s) - c14_psnsha => photosyns_inst%c14_psnsha_patch , & ! Input: [real(r8) (:) ] shaded leaf-level photosynthesis (umol CO2 /m**2/ s) - - 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 - - hui => crop_inst%hui_patch , & ! Input: [real(r8) (:) ] crop patch heat unit index (growing degree-days); set to 0 at sowing and accumulated until harvest - leafout => crop_inst%gddtsoi_patch , & ! Input: [real(r8) (:) ] =gdd from top soil layer temperature - croplive => crop_inst%croplive_patch , & ! Input: [logical (:) ] flag, true if planted, not harvested - - gddmaturity => cnveg_state_inst%gddmaturity_patch , & ! Input: [real(r8) (:) ] gdd needed to harvest - huileaf => cnveg_state_inst%huileaf_patch , & ! Input: [real(r8) (:) ] heat unit index needed from planting to leaf emergence - huigrain => cnveg_state_inst%huigrain_patch , & ! Input: [real(r8) (:) ] same to reach vegetative maturity - peaklai => cnveg_state_inst%peaklai_patch , & ! Input: [integer (:) ] 1: max allowed lai; 0: not at max - aleafi => cnveg_state_inst%aleafi_patch , & ! Output: [real(r8) (:) ] saved allocation coefficient from phase 2 - astemi => cnveg_state_inst%astemi_patch , & ! Output: [real(r8) (:) ] saved allocation coefficient from phase 2 - aleaf => cnveg_state_inst%aleaf_patch , & ! Output: [real(r8) (:) ] leaf allocation coefficient - astem => cnveg_state_inst%astem_patch , & ! Output: [real(r8) (:) ] stem allocation coefficient - grain_flag => cnveg_state_inst%grain_flag_patch , & ! Output: [real(r8) (:) ] 1: grain fill stage; 0: not - c_allometry => cnveg_state_inst%c_allometry_patch , & ! Output: [real(r8) (:) ] C allocation index (DIM) - n_allometry => cnveg_state_inst%n_allometry_patch , & ! Output: [real(r8) (:) ] N allocation index (DIM) - tempsum_potential_gpp => cnveg_state_inst%tempsum_potential_gpp_patch , & ! Output: [real(r8) (:) ] temporary annual sum of potential GPP + + + croplive => crop_inst%croplive_patch , & ! Input: [logical (:) ] flag, true if planted, not harvested + + astem => cnveg_state_inst%astem_patch , & ! Input: [real(r8) (:) ] stem allocation coefficient + c_allometry => cnveg_state_inst%c_allometry_patch , & ! Input: [real(r8) (:) ] C allocation index (DIM) + n_allometry => cnveg_state_inst%n_allometry_patch , & ! Input: [real(r8) (:) ] N allocation index (DIM) + annsum_potential_gpp => cnveg_state_inst%annsum_potential_gpp_patch , & ! Input: [real(r8) (:) ] annual sum of potential GPP + annmax_retransn => cnveg_state_inst%annmax_retransn_patch , & ! Input: [real(r8) (:) ] annual max of retranslocated N pool + grain_flag => cnveg_state_inst%grain_flag_patch , & ! Output: [real(r8) (:) ] 1: grain fill stage; 0: not + tempsum_potential_gpp => cnveg_state_inst%tempsum_potential_gpp_patch , & ! Output: [real(r8) (:) ] temporary annual sum of potential GPP tempmax_retransn => cnveg_state_inst%tempmax_retransn_patch , & ! Output: [real(r8) (:) ] temporary annual max of retranslocated N pool (gN/m2) - annsum_potential_gpp => cnveg_state_inst%annsum_potential_gpp_patch , & ! Output: [real(r8) (:) ] annual sum of potential GPP - annmax_retransn => cnveg_state_inst%annmax_retransn_patch , & ! Output: [real(r8) (:) ] annual max of retranslocated N pool - - xsmrpool => cnveg_carbonstate_inst%xsmrpool_patch , & ! Input: [real(r8) (:) ] (gC/m2) temporary photosynthate C pool - leafc => cnveg_carbonstate_inst%leafc_patch , & ! Input: [real(r8) (:) ] - frootc => cnveg_carbonstate_inst%frootc_patch , & ! Input: [real(r8) (:) ] - livestemc => cnveg_carbonstate_inst%livestemc_patch , & ! Input: [real(r8) (:) ] - - retransn => cnveg_nitrogenstate_inst%retransn_patch , & ! Input: [real(r8) (:) ] (gN/m2) plant pool of retranslocated N - - annsum_npp => cnveg_carbonflux_inst%annsum_npp_patch , & ! Input: [real(r8) (:) ] annual sum of NPP, for wood allocation - leaf_mr => cnveg_carbonflux_inst%leaf_mr_patch , & ! Input: [real(r8) (:) ] - froot_mr => cnveg_carbonflux_inst%froot_mr_patch , & ! Input: [real(r8) (:) ] - livestem_mr => cnveg_carbonflux_inst%livestem_mr_patch , & ! Input: [real(r8) (:) ] - livecroot_mr => cnveg_carbonflux_inst%livecroot_mr_patch , & ! Input: [real(r8) (:) ] - reproductive_mr => cnveg_carbonflux_inst%reproductive_mr_patch , & ! Input: [real(r8) (:,:) ] - gpp => cnveg_carbonflux_inst%gpp_before_downreg_patch , & ! Output: [real(r8) (:) ] GPP flux before downregulation (gC/m2/s) - availc => cnveg_carbonflux_inst%availc_patch , & ! Output: [real(r8) (:) ] C flux available for allocation (gC/m2/s) - xsmrpool_recover => cnveg_carbonflux_inst%xsmrpool_recover_patch , & ! Output: [real(r8) (:) ] C flux assigned to recovery of negative cpool (gC/m2/s) - psnsun_to_cpool => cnveg_carbonflux_inst%psnsun_to_cpool_patch , & ! Output: [real(r8) (:) ] - psnshade_to_cpool => cnveg_carbonflux_inst%psnshade_to_cpool_patch , & ! Output: [real(r8) (:) ] - leaf_curmr => cnveg_carbonflux_inst%leaf_curmr_patch , & ! Output: [real(r8) (:) ] - froot_curmr => cnveg_carbonflux_inst%froot_curmr_patch , & ! Output: [real(r8) (:) ] - livestem_curmr => cnveg_carbonflux_inst%livestem_curmr_patch , & ! Output: [real(r8) (:) ] - livecroot_curmr => cnveg_carbonflux_inst%livecroot_curmr_patch , & ! Output: [real(r8) (:) ] - reproductive_curmr => cnveg_carbonflux_inst%reproductive_curmr_patch , & ! Output: [real(r8) (:,:) ] - leaf_xsmr => cnveg_carbonflux_inst%leaf_xsmr_patch , & ! Output: [real(r8) (:) ] - froot_xsmr => cnveg_carbonflux_inst%froot_xsmr_patch , & ! Output: [real(r8) (:) ] - livestem_xsmr => cnveg_carbonflux_inst%livestem_xsmr_patch , & ! Output: [real(r8) (:) ] - livecroot_xsmr => cnveg_carbonflux_inst%livecroot_xsmr_patch , & ! Output: [real(r8) (:) ] - reproductive_xsmr => cnveg_carbonflux_inst%reproductive_xsmr_patch , & ! Output: [real(r8) (:,:) ] - cpool_to_xsmrpool => cnveg_carbonflux_inst%cpool_to_xsmrpool_patch , & ! Output: [real(r8) (:) ] - + + leafc => cnveg_carbonstate_inst%leafc_patch , & ! Input: [real(r8) (:) ] + frootc => cnveg_carbonstate_inst%frootc_patch , & ! Input: [real(r8) (:) ] + livestemc => cnveg_carbonstate_inst%livestemc_patch , & ! Input: [real(r8) (:) ] + + retransn => cnveg_nitrogenstate_inst%retransn_patch , & ! Input: [real(r8) (:) ] (gN/m2) plant pool of retranslocated N + + gpp => cnveg_carbonflux_inst%gpp_before_downreg_patch , & ! Input: [real(r8) (:) ] GPP flux before downregulation (gC/m2/s) + availc => cnveg_carbonflux_inst%availc_patch , & ! Input: [real(r8) (:) ] C flux available for allocation (gC/m2/s) + plant_ndemand => cnveg_nitrogenflux_inst%plant_ndemand_patch , & ! Output: [real(r8) (:) ] N flux required to support initial GPP (gN/m2/s) avail_retransn => cnveg_nitrogenflux_inst%avail_retransn_patch , & ! Output: [real(r8) (:) ] N flux available from retranslocation pool (gN/m2/s) retransn_to_npool => cnveg_nitrogenflux_inst%retransn_to_npool_patch , & ! Output: [real(r8) (:) ] deployment of retranslocated N (gN/m2/s) - sminn_to_npool => cnveg_nitrogenflux_inst%sminn_to_npool_patch , & ! Output: [real(r8) (:) ] deployment of soil mineral N uptake (gN/m2/s) - leafn_to_retransn => cnveg_nitrogenflux_inst%leafn_to_retransn_patch , & ! Output: [real(r8) (:) ] - frootn_to_retransn => cnveg_nitrogenflux_inst%frootn_to_retransn_patch , & ! Output: [real(r8) (:) ] - livestemn_to_retransn => cnveg_nitrogenflux_inst%livestemn_to_retransn_patch & ! Output: [real(r8) (:) ] + leafn_to_retransn => cnveg_nitrogenflux_inst%leafn_to_retransn_patch , & ! Output: [real(r8) (:) ] + frootn_to_retransn => cnveg_nitrogenflux_inst%frootn_to_retransn_patch , & ! Output: [real(r8) (:) ] + livestemn_to_retransn => cnveg_nitrogenflux_inst%livestemn_to_retransn_patch & ! Output: [real(r8) (:) ] ) ! set time steps dt = get_step_size_real() - ! set number of days to recover negative cpool - dayscrecover = params_inst%dayscrecover - ! loop over patches to assess the total plant N demand - do fp = 1,num_soilp - p = filter_soilp(fp) - c = patch%column(p) - - ! get the time step total gross photosynthesis - ! this is coming from the canopy fluxes code, and is the - ! gpp that is used to control stomatal conductance. - ! For the nitrogen downregulation code, this is assumed - ! to be the potential gpp, and the actual gpp will be - ! reduced due to N limitation. - - ! Convert psn from umol/m2/s -> gC/m2/s - - ! The input psn (psnsun and psnsha) are expressed per unit LAI - ! in the sunlit and shaded canopy, respectively. These need to be - ! scaled by laisun and laisha to get the total gpp for allocation - - ! Note that no associate statement is used for the isotope carbon fluxes below - ! since they are not always allocated AND nag compiler will complain if you try to - ! to have an associate statement with unallocated memory - - psnsun_to_cpool(p) = psnsun(p) * laisun(p) * 12.011e-6_r8 - psnshade_to_cpool(p) = psnsha(p) * laisha(p) * 12.011e-6_r8 - - if ( use_c13 ) then - c13_cnveg_carbonflux_inst%psnsun_to_cpool_patch(p) = c13_psnsun(p) * laisun(p) * 12.011e-6_r8 - c13_cnveg_carbonflux_inst%psnshade_to_cpool_patch(p) = c13_psnsha(p) * laisha(p) * 12.011e-6_r8 - endif - - if ( use_c14 ) then - c14_cnveg_carbonflux_inst%psnsun_to_cpool_patch(p) = c14_psnsun(p) * laisun(p) * 12.011e-6_r8 - c14_cnveg_carbonflux_inst%psnshade_to_cpool_patch(p) = c14_psnsha(p) * laisha(p) * 12.011e-6_r8 - endif - - gpp(p) = psnsun_to_cpool(p) + psnshade_to_cpool(p) - - ! get the time step total maintenance respiration - ! These fluxes should already be in gC/m2/s - - mr = leaf_mr(p) + froot_mr(p) - if (woody(ivt(p)) == 1.0_r8) then - mr = mr + livestem_mr(p) + livecroot_mr(p) - else if (ivt(p) >= npcropmin) then - if (croplive(p)) then - reproductive_mr_tot = 0._r8 - do k = 1, nrepr - reproductive_mr_tot = reproductive_mr_tot + reproductive_mr(p,k) - end do - mr = mr + livestem_mr(p) + reproductive_mr_tot - end if - end if - - ! carbon flux available for allocation - availc(p) = gpp(p) - mr - - ! new code added for isotope calculations, 7/1/05, PET - ! If mr > gpp, then some mr comes from gpp, the rest comes from - ! cpool (xsmr) - if (mr > 0._r8 .and. availc(p) < 0._r8) then - curmr = gpp(p) - curmr_ratio = curmr / mr - else - curmr_ratio = 1._r8 - end if - leaf_curmr(p) = leaf_mr(p) * curmr_ratio - leaf_xsmr(p) = leaf_mr(p) - leaf_curmr(p) - froot_curmr(p) = froot_mr(p) * curmr_ratio - froot_xsmr(p) = froot_mr(p) - froot_curmr(p) - livestem_curmr(p) = livestem_mr(p) * curmr_ratio - livestem_xsmr(p) = livestem_mr(p) - livestem_curmr(p) - livecroot_curmr(p) = livecroot_mr(p) * curmr_ratio - livecroot_xsmr(p) = livecroot_mr(p) - livecroot_curmr(p) - do k = 1, nrepr - reproductive_curmr(p,k) = reproductive_mr(p,k) * curmr_ratio - reproductive_xsmr(p,k) = reproductive_mr(p,k) - reproductive_curmr(p,k) - end do + do fp = 1, num_p + p = filter_p(fp) - ! no allocation when available c is negative - availc(p) = max(availc(p),0.0_r8) - - ! test for an xsmrpool deficit - if (xsmrpool(p) < 0.0_r8) then - ! Running a deficit in the xsmrpool, so the first priority is to let - ! some availc from this timestep accumulate in xsmrpool. - ! Determine rate of recovery for xsmrpool deficit - - xsmrpool_recover(p) = -xsmrpool(p)/(dayscrecover*secspday) - if (xsmrpool_recover(p) < availc(p)) then - ! available carbon reduced by amount for xsmrpool recovery - availc(p) = availc(p) - xsmrpool_recover(p) - else - ! all of the available carbon goes to xsmrpool recovery - xsmrpool_recover(p) = availc(p) - availc(p) = 0.0_r8 - end if - cpool_to_xsmrpool(p) = xsmrpool_recover(p) - end if - - f1 = froot_leaf(ivt(p)) - f2 = croot_stem(ivt(p)) - - ! modified wood allocation to be 2.2 at npp=800 gC/m2/yr, 0.2 at npp=0, - ! constrained so that it does not go lower than 0.2 (under negative annsum_npp) - ! This variable allocation is only for trees. Shrubs have a constant - ! allocation as specified in the pft-physiologfy file. The value is also used - ! as a trigger here: -1.0 means to use the dynamic allocation (trees). + plant_ndemand(p) = availc(p)*(n_allometry(p)/c_allometry(p)) - if (stem_leaf(ivt(p)) == -1._r8) then - f3 = (2.7_r8/(1.0_r8+exp(-0.004_r8*(annsum_npp(p) - 300.0_r8)))) - 0.4_r8 - else - f3 = stem_leaf(ivt(p)) - end if + ! retranslocated N deployment depends on seasonal cycle of potential GPP + ! (requires one year run to accumulate demand) - f4 = flivewd(ivt(p)) - g1 = grperc(ivt(p)) - g2 = grpnow(ivt(p)) - cnl = leafcn(ivt(p)) - cnfr = frootcn(ivt(p)) - cnlw = livewdcn(ivt(p)) - cndw = deadwdcn(ivt(p)) + tempsum_potential_gpp(p) = tempsum_potential_gpp(p) + gpp(p) - ! calculate f1 to f5 for prog crops following AgroIBIS subr phenocrop + ! Adding the following line to carry max retransn info to CN Annual Update + tempmax_retransn(p) = max(tempmax_retransn(p),retransn(p)) + end do - do k = 1, nrepr - f5(k) = 0._r8 ! continued intializations from above - end do + if (call_is_for_pcrop) then + call CropPhase(bounds, num_p, filter_p, crop_inst, cnveg_state_inst, & + crop_phase = crop_phase(bounds%begp:bounds%endp)) - if (ivt(p) >= npcropmin) then ! skip 2 generic crops + do fp = 1, num_p + p = filter_p(fp) if (croplive(p)) then - ! same phases appear in subroutine CropPhenology - - ! Phase 1 completed: - ! ================== - ! if hui is less than the number of gdd needed for filling of grain - ! leaf emergence also has to have taken place for lai changes to occur - ! and carbon assimilation - ! Next phase: leaf emergence to start of leaf decline - - if (leafout(p) >= huileaf(p) .and. hui(p) < huigrain(p)) then - - ! allocation rules for crops based on maturity and linear decrease - ! of amount allocated to roots over course of the growing season - - do k = 1, nrepr - arepr(p,k) = 0._r8 - end do - if (peaklai(p) == 1) then ! lai at maximum allowed - aleaf(p) = 1.e-5_r8 - astem(p) = 0._r8 - aroot(p) = 1._r8 - aleaf(p) - else - aroot(p) = max(0._r8, min(1._r8, arooti(ivt(p)) - & - (arooti(ivt(p)) - arootf(ivt(p))) * & - min(1._r8, hui(p)/gddmaturity(p)))) - fleaf = fleafi(ivt(p)) * (exp(-bfact(ivt(p))) - & - exp(-bfact(ivt(p))*hui(p)/huigrain(p))) / & - (exp(-bfact(ivt(p)))-1) ! fraction alloc to leaf (from J Norman alloc curve) - aleaf(p) = max(1.e-5_r8, (1._r8 - aroot(p)) * fleaf) - astem(p) = 1._r8 - aleaf(p) - aroot(p) - end if - - ! AgroIBIS included here an immediate adjustment to aleaf & astem if the - ! predicted lai from the above allocation coefficients exceeded laimx. - ! We have decided to live with lais slightly higher than laimx by - ! enforcing the cap in the following tstep through the peaklai logic above. - - astemi(p) = astem(p) ! save for use by equations after shift - aleafi(p) = aleaf(p) ! to reproductive phenology stage begins + if (crop_phase(p) == cphase_leafemerge) then grain_flag(p) = 0._r8 ! setting to 0 while in phase 2 - - ! Phase 2 completed: - ! ================== - ! shift allocation either when enough gdd are accumulated or maximum number - ! of days has elapsed since planting - - else if (hui(p) >= huigrain(p)) then - - aroot(p) = max(0._r8, min(1._r8, arooti(ivt(p)) - & - (arooti(ivt(p)) - arootf(ivt(p))) * min(1._r8, hui(p)/gddmaturity(p)))) - if (astemi(p) > astemf(ivt(p))) then - astem(p) = max(0._r8, max(astemf(ivt(p)), astem(p) * & - (1._r8 - min((hui(p)- & - huigrain(p))/((gddmaturity(p)*declfact(ivt(p)))- & - huigrain(p)),1._r8)**allconss(ivt(p)) ))) - end if - - ! If crops have hit peaklai, then set leaf allocation to small value - if (peaklai(p) == 1) then - aleaf(p) = 1.e-5_r8 - else if (aleafi(p) > aleaff(ivt(p))) then - aleaf(p) = max(1.e-5_r8, max(aleaff(ivt(p)), aleaf(p) * & - (1._r8 - min((hui(p)- & - huigrain(p))/((gddmaturity(p)*declfact(ivt(p)))- & - huigrain(p)),1._r8)**allconsl(ivt(p)) ))) - end if - + else if (crop_phase(p) == cphase_grainfill) then !Beth's retranslocation of leafn, stemn, rootn to organ !Filter excess plant N to retransn pool for organ N !Only do one time then hold grain_flag till onset next season ! slevis: Will astem ever = astemf exactly? - ! Beth's response: ...looks like astem can equal astemf under the right circumstances. - !It might be worth a rewrite to capture what I was trying to do, but the retranslocation for - !corn and wheat begins at the beginning of the grain fill stage, but for soybean I was holding it - !until after the leaf and stem decline were complete. Looking at how astem is calculated, once the - !stem decline is near complete, astem should (usually) be set to astemf. The reason for holding off - !on soybean is that the retranslocation scheme begins at the beginning of the grain phase, when the - !leaf and stem are still growing, but declining. Since carbon is still getting allocated and now - !there is more nitrogen available, the nitrogen can be diverted from grain. For corn and wheat - !the impact was probably enough to boost productivity, but for soybean the nitrogen was better off - !fulfilling the grain fill. It seems that if the peak lai is reached for soybean though that this - !would be bypassed altogether, not the intended outcome. I checked several of my output files and + ! Beth's response: ...looks like astem can equal astemf under the right circumstances. + !It might be worth a rewrite to capture what I was trying to do, but the retranslocation for + !corn and wheat begins at the beginning of the grain fill stage, but for soybean I was holding it + !until after the leaf and stem decline were complete. Looking at how astem is calculated, once the + !stem decline is near complete, astem should (usually) be set to astemf. The reason for holding off + !on soybean is that the retranslocation scheme begins at the beginning of the grain phase, when the + !leaf and stem are still growing, but declining. Since carbon is still getting allocated and now + !there is more nitrogen available, the nitrogen can be diverted from grain. For corn and wheat + !the impact was probably enough to boost productivity, but for soybean the nitrogen was better off + !fulfilling the grain fill. It seems that if the peak lai is reached for soybean though that this + !would be bypassed altogether, not the intended outcome. I checked several of my output files and !they all seemed to be going through the retranslocation loop for soybean - good news. - if (astem(p) == astemf(ivt(p)) .or. & + if (astem(p) == astemf(ivt(p)) .or. & (ivt(p) /= ntmp_soybean .and. ivt(p) /= nirrig_tmp_soybean .and.& - ivt(p) /= ntrp_soybean .and. ivt(p) /= nirrig_trp_soybean)) then + ivt(p) /= ntrp_soybean .and. ivt(p) /= nirrig_trp_soybean)) then 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) / & - fleafcn(ivt(p)))) - livestemn_to_retransn(p) = t1 * ((livestemc(p) / livewdcn(ivt(p))) - (livestemc(p) / & - fstemcn(ivt(p)))) - frootn_to_retransn(p) = 0._r8 - if (ffrootcn(ivt(p)) > 0._r8) then - frootn_to_retransn(p) = t1 * ((frootc(p) / frootcn(ivt(p))) - (frootc(p) / & - ffrootcn(ivt(p)))) - end if + if(.not.use_fun) then + t1 = 1 / dt + leafn_to_retransn(p) = t1 * ((leafc(p) / leafcn(ivt(p))) - (leafc(p) / & + fleafcn(ivt(p)))) + livestemn_to_retransn(p) = t1 * ((livestemc(p) / livewdcn(ivt(p))) - (livestemc(p) / & + fstemcn(ivt(p)))) + frootn_to_retransn(p) = 0._r8 + if (ffrootcn(ivt(p)) > 0._r8) then + frootn_to_retransn(p) = t1 * ((frootc(p) / frootcn(ivt(p))) - (frootc(p) / & + ffrootcn(ivt(p)))) + end if else !leafn retrans flux is handled in phenology - frootn_to_retransn(p) = 0._r8 - livestemn_to_retransn(p)=0.0_r8 + frootn_to_retransn(p) = 0._r8 + livestemn_to_retransn(p)=0.0_r8 end if !fun grain_flag(p) = 1._r8 end if end if - - ! For AgroIBIS-based crop model, all repr allocation is assumed to go - ! into the last reproductive pool. In practice there is only a single - ! reproductive pool with the AgroIBIS-based crop model, but for - ! software testing we can have multiple, in which situation we want the - ! active pool to be the last one. - do k = 1, nrepr-1 - arepr(p,k) = 0._r8 - end do - arepr(p,nrepr) = 1._r8 - aroot(p) - astem(p) - aleaf(p) - - else ! pre emergence - ! allocation coefficients should be irrelevant because crops have no - ! live carbon pools; this applies to this "else" and to the "else" a few - ! lines down - aleaf(p) = 1.e-5_r8 - astem(p) = 0._r8 - aroot(p) = 0._r8 - do k = 1, nrepr - arepr(p,k) = 0._r8 - end do end if - - f1 = aroot(p) / aleaf(p) - f3 = astem(p) / aleaf(p) - do k = 1, nrepr - f5(k) = arepr(p,k) / aleaf(p) - end do - g1 = 0.25_r8 - - else ! .not croplive - f1 = 0._r8 - f3 = 0._r8 - do k = 1, nrepr - f5(k) = 0._r8 - end do - g1 = 0.25_r8 end if - end if - - ! based on available C, use constant allometric relationships to - ! determine N requirements - - !RF. I removed the growth respiration from this, because it is used to calculate - !plantCN for N uptake AND c_allometry for allocation. If we add gresp to the - !allometry calculation then we allocate too much carbon since gresp is not allocated here. - if (.not. use_fun) then - g1a = g1 - else - g1a = 0._r8 - end if - if (woody(ivt(p)) == 1.0_r8) then - c_allometry(p) = (1._r8+g1a)*(1._r8+f1+f3*(1._r8+f2)) - n_allometry(p) = 1._r8/cnl + f1/cnfr + (f3*f4*(1._r8+f2))/cnlw + & - (f3*(1._r8-f4)*(1._r8+f2))/cndw - else if (ivt(p) >= npcropmin) then ! skip generic crops - cng = graincn(ivt(p)) - f5_tot = 0._r8 - f5_n_tot = 0._r8 - do k = 1, nrepr - f5_tot = f5_tot + f5(k) - ! Note that currently we use the same C/N ratio for all grain components: - f5_n_tot = f5_n_tot + f5(k)/cng + end do + end if + + ! Beth's code: crops pull from retransn pool only during grain fill; + ! retransn pool has N from leaves, stems, and roots for + ! retranslocation + if (.not. use_fun) then + if (call_is_for_pcrop) then + do fp = 1, num_p + p = filter_p(fp) + + if (grain_flag(p) == 1._r8) then + avail_retransn(p) = plant_ndemand(p) + else + avail_retransn(p) = 0.0_r8 + end if end do - c_allometry(p) = (1._r8+g1a)*(1._r8+f1+f5_tot+f3*(1._r8+f2)) - n_allometry(p) = 1._r8/cnl + f1/cnfr + f5_n_tot + (f3*f4*(1._r8+f2))/cnlw + & - (f3*(1._r8-f4)*(1._r8+f2))/cndw else - c_allometry(p) = 1._r8+g1a+f1+f1*g1a - n_allometry(p) = 1._r8/cnl + f1/cnfr - end if - - plant_ndemand(p) = availc(p)*(n_allometry(p)/c_allometry(p)) - - ! retranslocated N deployment depends on seasonal cycle of potential GPP - ! (requires one year run to accumulate demand) + do fp = 1, num_p + p = filter_p(fp) - tempsum_potential_gpp(p) = tempsum_potential_gpp(p) + gpp(p) + if (annsum_potential_gpp(p) > 0._r8) then + avail_retransn(p) = (annmax_retransn(p)/2._r8)*(gpp(p)/annsum_potential_gpp(p))/dt + else + avail_retransn(p) = 0.0_r8 + end if + end do + end if - ! Adding the following line to carry max retransn info to CN Annual Update - tempmax_retransn(p) = max(tempmax_retransn(p),retransn(p)) + do fp = 1, num_p + p = filter_p(fp) - ! Beth's code: crops pull from retransn pool only during grain fill; - ! retransn pool has N from leaves, stems, and roots for - ! retranslocation - - if(.not.use_fun)then - - if (ivt(p) >= npcropmin .and. grain_flag(p) == 1._r8) then - avail_retransn(p) = plant_ndemand(p) - else if (ivt(p) < npcropmin .and. annsum_potential_gpp(p) > 0._r8) then - avail_retransn(p) = (annmax_retransn(p)/2._r8)*(gpp(p)/annsum_potential_gpp(p))/dt - else - avail_retransn(p) = 0.0_r8 - end if + ! make sure available retrans N doesn't exceed storage + avail_retransn(p) = min(avail_retransn(p), retransn(p)/dt) - ! make sure available retrans N doesn't exceed storage - avail_retransn(p) = min(avail_retransn(p), retransn(p)/dt) + ! modify plant N demand according to the availability of + ! retranslocated N + ! take from retransn pool at most the flux required to meet + ! plant ndemand - ! modify plant N demand according to the availability of - ! retranslocated N - ! take from retransn pool at most the flux required to meet - ! plant ndemand + if (plant_ndemand(p) > avail_retransn(p)) then + retransn_to_npool(p) = avail_retransn(p) + else + retransn_to_npool(p) = plant_ndemand(p) + end if - if (plant_ndemand(p) > avail_retransn(p)) then - retransn_to_npool(p) = avail_retransn(p) - else - retransn_to_npool(p) = plant_ndemand(p) - end if + if ( .not. use_fun ) then + plant_ndemand(p) = plant_ndemand(p) - retransn_to_npool(p) + else + if (season_decid(ivt(p)) == 1._r8.or.stress_decid(ivt(p))==1._r8) then + plant_ndemand(p) = plant_ndemand(p) - retransn_to_npool(p) + end if + end if + end do - if ( .not. use_fun ) then - plant_ndemand(p) = plant_ndemand(p) - retransn_to_npool(p) - else - if (season_decid(ivt(p)) == 1._r8.or.stress_decid(ivt(p))==1._r8) then - plant_ndemand(p) = plant_ndemand(p) - retransn_to_npool(p) - end if - end if - - end if !use_fun + end if !use_fun - end do ! end patch loop + end associate - end associate + end subroutine calc_plant_nitrogen_demand - end subroutine calc_plant_nitrogen_demand - end module NutrientCompetitionCLM45defaultMod diff --git a/src/biogeochem/NutrientCompetitionFlexibleCNMod.F90 b/src/biogeochem/NutrientCompetitionFlexibleCNMod.F90 index c18e91c45c..2133d010aa 100644 --- a/src/biogeochem/NutrientCompetitionFlexibleCNMod.F90 +++ b/src/biogeochem/NutrientCompetitionFlexibleCNMod.F90 @@ -18,14 +18,19 @@ module NutrientCompetitionFlexibleCNMod ! ! !USES: use shr_kind_mod , only : r8 => shr_kind_r8 + use shr_log_mod , only : errMsg => shr_log_errMsg + use clm_time_manager , only : get_step_size_real use decompMod , only : bounds_type use LandunitType , only : lun use ColumnType , only : col use PatchType , only : patch + use pftconMod , only : pftcon, npcropmin use NutrientCompetitionMethodMod, only : nutrient_competition_method_type - use NutrientCompetitionMethodMod, only : params_inst - use CropReprPoolsMod , only : nrepr - use clm_varctl , only : iulog + use CropReprPoolsMod , only : nrepr + use CNPhenologyMod , only : CropPhase + use CropType , only : cphase_leafemerge, cphase_grainfill + use clm_varctl , only : iulog, use_crop_agsys + use abortutils , only : endrun ! implicit none private @@ -56,6 +61,10 @@ module NutrientCompetitionFlexibleCNMod end interface nutrient_competition_FlexibleCN_type ! + ! !PRIVATE MEMBER FUNCTIONS: + private :: calc_npool_to_components_flexiblecn ! Calculate npool_to_* terms for a single patch using the FlexibleCN approach + private :: calc_npool_to_components_agsys ! Calculate npool_to_* terms for a single crop patch when using AgSys + character(len=*), parameter, private :: sourcefile = & __FILE__ !------------------------------------------------------------------------ @@ -113,7 +122,7 @@ subroutine InitHistory(this, bounds) ! ! !ARGUMENTS: class(nutrient_competition_FlexibleCN_type), intent(in) :: this - type(bounds_type), intent(in) :: bounds + type(bounds_type), intent(in) :: bounds ! ! !LOCAL VARIABLES: integer :: begp, endp @@ -139,8 +148,7 @@ subroutine calc_plant_nutrient_competition (this, & cnveg_carbonflux_inst, & c13_cnveg_carbonflux_inst, c14_cnveg_carbonflux_inst, & cnveg_nitrogenstate_inst, cnveg_nitrogenflux_inst, & - soilbiogeochem_nitrogenstate_inst, & - aroot, arepr, fpg_col) + soilbiogeochem_nitrogenstate_inst, fpg_col) ! ! !USES: use CNVegStateType , only : cnveg_state_type @@ -167,8 +175,6 @@ subroutine calc_plant_nutrient_competition (this, & type(cnveg_nitrogenstate_type) , intent(inout) :: cnveg_nitrogenstate_inst type(cnveg_nitrogenflux_type) , intent(inout) :: cnveg_nitrogenflux_inst type(soilbiogeochem_nitrogenstate_type), intent(in) :: soilbiogeochem_nitrogenstate_inst - real(r8), intent(in) :: aroot (bounds%begp:) - real(r8), intent(in) :: arepr(bounds%begp:,:) real(r8), intent(in) :: fpg_col (bounds%begc:) call this%calc_plant_cn_alloc(bounds, num_soilp, filter_soilp, & @@ -176,8 +182,6 @@ subroutine calc_plant_nutrient_competition (this, & cnveg_carbonstate_inst, cnveg_carbonflux_inst, c13_cnveg_carbonflux_inst, & c14_cnveg_carbonflux_inst, cnveg_nitrogenstate_inst, cnveg_nitrogenflux_inst, & soilbiogeochem_nitrogenstate_inst, & - aroot=aroot(bounds%begp:bounds%endp), & - arepr=arepr(bounds%begp:bounds%endp,:), & fpg_col=fpg_col(bounds%begc:bounds%endc)) end subroutine calc_plant_nutrient_competition @@ -187,13 +191,10 @@ 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_nitrogenstate_inst, cnveg_nitrogenflux_inst, & - soilbiogeochem_nitrogenstate_inst, & - aroot, arepr, fpg_col) + soilbiogeochem_nitrogenstate_inst, fpg_col) ! ! !USES: - use pftconMod , only : pftcon, npcropmin use clm_varctl , only : use_c13, use_c14, carbon_resp_opt - use clm_time_manager , only : get_step_size_real use CNVegStateType , only : cnveg_state_type use CropType , only : crop_type use CanopyStateType , only : canopystate_type @@ -205,7 +206,7 @@ subroutine calc_plant_cn_alloc(this, bounds, num_soilp, filter_soilp, & use CNSharedParamsMod , only : use_fun use CNPrecisionControlMod , only : n_min use clm_varcon , only : spval - + ! ! !ARGUMENTS: class(nutrient_competition_FlexibleCN_type), intent(inout) :: this @@ -222,69 +223,30 @@ subroutine calc_plant_cn_alloc(this, bounds, num_soilp, filter_soilp, & type(cnveg_nitrogenflux_type) , intent(inout) :: cnveg_nitrogenflux_inst type(cnveg_nitrogenstate_type) , intent(inout) :: cnveg_nitrogenstate_inst type(soilbiogeochem_nitrogenstate_type), intent(in) :: soilbiogeochem_nitrogenstate_inst - real(r8) , intent(in) :: aroot(bounds%begp:) - real(r8) , intent(in) :: arepr(bounds%begp:,:) real(r8) , intent(in) :: fpg_col(bounds%begc:) ! ! !LOCAL VARIABLES: integer :: c,p,k ! indices integer :: fp ! lake filter patch index real(r8) :: f1,f2,f3,f4,g1,g2 ! allocation parameters - real(r8) :: cnl,cnfr,cnlw,cndw ! C:N ratios for leaf, fine root, and wood real(r8) :: fcur ! fraction of current psn displayed as growth real(r8) :: gresp_storage ! temporary variable for growth resp to storage real(r8) :: nlc ! temporary variable for total new leaf carbon allocation real(r8) :: f5(nrepr) ! reproductive allocation parameters - real(r8) :: cng ! C:N ratio for grain (= cnlw for now; slevis) - real(r8) :: dt ! model time step - real(r8):: fsmn(bounds%begp:bounds%endp) ! A emperate variable for adjusting FUN uptakes - - real(r8):: frootcn_storage_actual - real(r8):: frootcn_actual - real(r8):: livestemcn_storage_actual - real(r8):: livestemcn_actual - real(r8):: livecrootcn_storage_actual - real(r8):: livecrootcn_actual - real(r8):: leafcn_max - real(r8):: frootcn_max - real(r8):: livewdcn_max + + real(r8):: frootcn_storage_actual + real(r8):: frootcn_actual + real(r8):: livestemcn_storage_actual + real(r8):: livestemcn_actual + real(r8):: livecrootcn_storage_actual + real(r8):: livecrootcn_actual + real(r8):: leafcn_max + real(r8):: frootcn_max + real(r8):: livewdcn_max real(r8):: frac_resp - real(r8):: npool_to_reproductiven_demand_tot - real(r8):: npool_to_reproductiven_storage_demand_tot - real(r8) :: npool_to_leafn_demand (bounds%begp:bounds%endp) - real(r8) :: npool_to_leafn_storage_demand (bounds%begp:bounds%endp) - real(r8) :: npool_to_frootn_demand (bounds%begp:bounds%endp) - real(r8) :: npool_to_frootn_storage_demand (bounds%begp:bounds%endp) - real(r8) :: npool_to_livestemn_demand (bounds%begp:bounds%endp) - real(r8) :: npool_to_livestemn_storage_demand (bounds%begp:bounds%endp) - real(r8) :: npool_to_livecrootn_demand (bounds%begp:bounds%endp) - real(r8) :: npool_to_livecrootn_storage_demand (bounds%begp:bounds%endp) - real(r8) :: npool_to_deadstemn_demand (bounds%begp:bounds%endp) - real(r8) :: npool_to_deadstemn_storage_demand (bounds%begp:bounds%endp) - real(r8) :: npool_to_deadcrootn_demand (bounds%begp:bounds%endp) - real(r8) :: npool_to_deadcrootn_storage_demand (bounds%begp:bounds%endp) - real(r8) :: npool_to_reproductiven_demand (bounds%begp:bounds%endp, nrepr) - real(r8) :: npool_to_reproductiven_storage_demand (bounds%begp:bounds%endp, nrepr) - real(r8) :: total_plant_Ndemand (bounds%begp:bounds%endp) - real(r8) :: frNdemand_npool_to_leafn (bounds%begp:bounds%endp) - real(r8) :: frNdemand_npool_to_leafn_storage (bounds%begp:bounds%endp) - real(r8) :: frNdemand_npool_to_frootn (bounds%begp:bounds%endp) - real(r8) :: frNdemand_npool_to_frootn_storage (bounds%begp:bounds%endp) - real(r8) :: frNdemand_npool_to_livestemn (bounds%begp:bounds%endp) - real(r8) :: frNdemand_npool_to_livestemn_storage (bounds%begp:bounds%endp) - real(r8) :: frNdemand_npool_to_deadstemn (bounds%begp:bounds%endp) - real(r8) :: frNdemand_npool_to_deadstemn_storage (bounds%begp:bounds%endp) - real(r8) :: frNdemand_npool_to_livecrootn (bounds%begp:bounds%endp) - real(r8) :: frNdemand_npool_to_livecrootn_storage (bounds%begp:bounds%endp) - real(r8) :: frNdemand_npool_to_deadcrootn (bounds%begp:bounds%endp) - real(r8) :: frNdemand_npool_to_deadcrootn_storage (bounds%begp:bounds%endp) - real(r8) :: frNdemand_npool_to_reproductiven (bounds%begp:bounds%endp, nrepr) - real(r8) :: frNdemand_npool_to_reproductiven_storage(bounds%begp:bounds%endp, nrepr) ! ----------------------------------------------------------------------- - SHR_ASSERT_ALL_FL((ubound(aroot) == (/bounds%endp/)) , sourcefile, __LINE__) - SHR_ASSERT_ALL_FL((ubound(arepr) == (/bounds%endp, nrepr/)) , sourcefile, __LINE__) SHR_ASSERT_ALL_FL((ubound(fpg_col) == (/bounds%endc/)) , sourcefile, __LINE__) SHR_ASSERT_ALL_FL((ubound(this%actual_storage_leafcn) >= (/bounds%endp/)), sourcefile, __LINE__) SHR_ASSERT_ALL_FL((lbound(this%actual_storage_leafcn) <= (/bounds%begp/)), sourcefile, __LINE__) @@ -302,9 +264,7 @@ subroutine calc_plant_cn_alloc(this, bounds, num_soilp, filter_soilp, & 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) fcur2 => pftcon%fcur , & ! Input: allocation parameter: fraction of allocation that goes to currently displayed growth, remainder to storage - graincn => pftcon%graincn , & ! Input: grain C:N (gC/gN) grperc => pftcon%grperc , & ! Input: growth respiration parameter grpnow => pftcon%grpnow , & ! Input: growth respiration parameter evergreen => pftcon%evergreen , & ! Input: binary flag for evergreen leaf habit (0 or 1) @@ -312,8 +272,13 @@ subroutine calc_plant_cn_alloc(this, bounds, num_soilp, filter_soilp, & croplive => crop_inst%croplive_patch , & ! Input: [logical (:) ] flag, true if planted, not harvested peaklai => cnveg_state_inst%peaklai_patch , & ! Input: [integer (:) ] 1: max allowed lai; 0: not at max - aleaf => cnveg_state_inst%aleaf_patch , & ! Output: [real(r8) (:) ] leaf allocation coefficient - astem => cnveg_state_inst%astem_patch , & ! Output: [real(r8) (:) ] stem allocation coefficient + aleaf => cnveg_state_inst%aleaf_patch , & ! Input: [real(r8) (:) ] leaf allocation coefficient + astem => cnveg_state_inst%astem_patch , & ! Input: [real(r8) (:) ] stem allocation coefficient + aroot => cnveg_state_inst%aroot_patch , & ! Input: [real(r8) (:) ] root allocation coefficient + arepr => cnveg_state_inst%arepr_patch , & ! Input: [real(r8) (:,:) ] reproductive allocation coefficient(s) + ! aleaf_n, astem_n, aroot_n and arepr_n are also inputs when running with AgSys, + ! but they cannot be associated here because these pointers may be unallocated + ! if not running with AgSys c_allometry => cnveg_state_inst%c_allometry_patch , & ! Output: [real(r8) (:) ] C allocation index (DIM) annsum_npp => cnveg_carbonflux_inst%annsum_npp_patch , & ! Input: [real(r8) (:) ] annual sum of NPP, for wood allocation @@ -344,7 +309,7 @@ subroutine calc_plant_cn_alloc(this, bounds, num_soilp, filter_soilp, & cpool_to_gresp_storage => cnveg_carbonflux_inst%cpool_to_gresp_storage_patch , & ! Output: [real(r8) (:) ] allocation to growth respiration storage (gC/m2/s) cpool_to_reproductivec => cnveg_carbonflux_inst%cpool_to_reproductivec_patch , & ! Output: [real(r8) (:,:) ] allocation to grain C (gC/m2/s) cpool_to_reproductivec_storage => cnveg_carbonflux_inst%cpool_to_reproductivec_storage_patch , & ! Output: [real(r8) (:,:) ] allocation to grain C storage (gC/m2/s) - + 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 smin_no3_vr => soilbiogeochem_nitrogenstate_inst%smin_no3_vr_col , & ! Output: [real(r8) (:,:) ] (gN/m3) soil mineral NO3 @@ -379,9 +344,6 @@ subroutine calc_plant_cn_alloc(this, bounds, num_soilp, filter_soilp, & ) - ! set time steps - dt = get_step_size_real() - ! patch loop to distribute the available N between the competing patches ! on the basis of relative demand, and allocate C and N to new growth and storage @@ -409,10 +371,6 @@ 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)) - cnfr = frootcn(ivt(p)) - cnlw = livewdcn(ivt(p)) - cndw = deadwdcn(ivt(p)) fcur = fcur2(ivt(p)) if (evergreen(ivt(p)) == 1._r8) then @@ -441,22 +399,22 @@ subroutine calc_plant_cn_alloc(this, bounds, num_soilp, filter_soilp, & ! ndays_active = days/year. This prevents the continued storage of C and N. ! turning off this correction (PET, 12/11/03), instead using bgtr in ! phenology algorithm. - - + + if(use_fun)then ! if we are using FUN, we get the N available from there. sminn_to_npool(p) = sminn_to_plant_fun(p) - else ! no FUN. :( we get N available from the FPG calculation in soilbiogeochemistry competition. - sminn_to_npool(p) = plant_ndemand(p) * fpg(c) + else ! no FUN. :( we get N available from the FPG calculation in soilbiogeochemistry competition. + sminn_to_npool(p) = plant_ndemand(p) * fpg(c) endif - + plant_nalloc(p) = sminn_to_npool(p) + retransn_to_npool(p) - + if(use_fun)then - plant_calloc(p) = npp_growth(p) + plant_calloc(p) = npp_growth(p) else plant_calloc(p) = availc(p) end if - + ! calculate the amount of new leaf C dictated by these allocation ! decisions, and calculate the daily fluxes of C and N to current ! growth and storage pools @@ -521,184 +479,64 @@ subroutine calc_plant_cn_alloc(this, bounds, num_soilp, filter_soilp, & end if cpool_to_gresp_storage(p) = gresp_storage * g1 * (1._r8 - g2) - - ! computing 1.) fractional N demand and 2.) N allocation after uptake for different plant parts - !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - ! computing nitrogen demand for different pools based on carbon allocated and CN ratio - npool_to_leafn_demand(p) = (nlc / cnl) * fcur - npool_to_leafn_storage_demand(p) = (nlc / cnl) * (1._r8 - fcur) - npool_to_frootn_demand(p) = (nlc * f1 / cnfr) * fcur - npool_to_frootn_storage_demand(p) = (nlc * f1 / cnfr) * (1._r8 - fcur) - if (woody(ivt(p)) == 1._r8) then - - npool_to_livestemn_demand(p) = (nlc * f3 * f4 / cnlw) * fcur - npool_to_livestemn_storage_demand(p) = (nlc * f3 * f4 / cnlw) * (1._r8 - fcur) - npool_to_deadstemn_demand(p) = (nlc * f3 * (1._r8 - f4) / cndw) * fcur - npool_to_deadstemn_storage_demand(p) = (nlc * f3 * (1._r8 - f4) / cndw) * (1._r8 - fcur) - npool_to_livecrootn_demand(p) = (nlc * f2 * f3 * f4 / cnlw) * fcur - npool_to_livecrootn_storage_demand(p) = (nlc * f2 * f3 * f4 / cnlw) * (1._r8 - fcur) - npool_to_deadcrootn_demand(p) = (nlc * f2 * f3 * (1._r8 - f4) / cndw) * fcur - npool_to_deadcrootn_storage_demand(p) = (nlc * f2 * f3 * (1._r8 - f4) / cndw) * (1._r8 - fcur) - end if - if (ivt(p) >= npcropmin) then ! skip 2 generic crops - - cng = graincn(ivt(p)) - npool_to_livestemn_demand(p) = (nlc * f3 * f4 / cnlw) * fcur - npool_to_livestemn_storage_demand(p) = (nlc * f3 * f4 / cnlw) * (1._r8 - fcur) - npool_to_deadstemn_demand(p) = (nlc * f3 * (1._r8 - f4) / cndw) * fcur - npool_to_deadstemn_storage_demand(p) = (nlc * f3 * (1._r8 - f4) / cndw) * (1._r8 - fcur) - npool_to_livecrootn_demand(p) = (nlc * f2 * f3 * f4 / cnlw) * fcur - npool_to_livecrootn_storage_demand(p) = (nlc * f2 * f3 * f4 / cnlw) * (1._r8 - fcur) - npool_to_deadcrootn_demand(p) = (nlc * f2 * f3 * (1._r8 - f4) / cndw) * fcur - npool_to_deadcrootn_storage_demand(p) = (nlc * f2 * f3 * (1._r8 - f4) / cndw) * (1._r8 - fcur) - do k = 1, nrepr - npool_to_reproductiven_demand(p,k) = (nlc * f5(k) / cng) * fcur - npool_to_reproductiven_storage_demand(p,k) = (nlc * f5(k) / cng) * (1._r8 -fcur) - end do - end if - - - ! computing 1.) fractional N demand for different plant parts -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - total_plant_Ndemand(p) = npool_to_leafn_demand(p) + npool_to_leafn_storage_demand(p) + & - npool_to_frootn_demand(p) + npool_to_frootn_storage_demand(p) - - if (woody(ivt(p)) == 1._r8) then - - total_plant_Ndemand(p) = npool_to_leafn_demand(p) + npool_to_leafn_storage_demand(p) + & - npool_to_frootn_demand(p) + npool_to_frootn_storage_demand(p) + & - npool_to_livestemn_demand(p) + npool_to_livestemn_storage_demand(p) + npool_to_deadstemn_demand(p) + & - npool_to_deadstemn_storage_demand(p) + & - npool_to_livecrootn_demand(p) + npool_to_livecrootn_storage_demand(p) + npool_to_deadcrootn_demand(p) + & - npool_to_deadcrootn_storage_demand(p) - - end if - if (ivt(p) >= npcropmin) then ! skip 2 generic crops - - npool_to_reproductiven_demand_tot = 0._r8 - npool_to_reproductiven_storage_demand_tot = 0._r8 - do k = 1, nrepr - npool_to_reproductiven_demand_tot = npool_to_reproductiven_demand_tot + & - npool_to_reproductiven_demand(p,k) - npool_to_reproductiven_storage_demand_tot = npool_to_reproductiven_storage_demand_tot + & - npool_to_reproductiven_storage_demand(p,k) - end do - - total_plant_Ndemand(p) = npool_to_leafn_demand(p) + npool_to_leafn_storage_demand(p) + & - npool_to_frootn_demand(p) + npool_to_frootn_storage_demand(p) + & - npool_to_livestemn_demand(p) + npool_to_livestemn_storage_demand(p) + npool_to_deadstemn_demand(p) + & - npool_to_deadstemn_storage_demand(p) + & - npool_to_livecrootn_demand(p) + npool_to_livecrootn_storage_demand(p) + npool_to_deadcrootn_demand(p) + & - npool_to_deadcrootn_storage_demand(p) + & - npool_to_reproductiven_demand_tot + npool_to_reproductiven_storage_demand_tot - - end if - - if (total_plant_Ndemand(p) == 0.0_r8) then ! removing division by zero - - frNdemand_npool_to_leafn(p) = 0.0_r8 - frNdemand_npool_to_leafn_storage(p) = 0.0_r8 - frNdemand_npool_to_frootn(p) = 0.0_r8 - frNdemand_npool_to_frootn_storage(p) = 0.0_r8 - if (woody(ivt(p)) == 1._r8) then - - frNdemand_npool_to_livestemn(p) = 0.0_r8 - frNdemand_npool_to_livestemn_storage(p) = 0.0_r8 - frNdemand_npool_to_deadstemn(p) = 0.0_r8 - frNdemand_npool_to_deadstemn_storage(p) = 0.0_r8 - frNdemand_npool_to_livecrootn(p) = 0.0_r8 - frNdemand_npool_to_livecrootn_storage(p) = 0.0_r8 - frNdemand_npool_to_deadcrootn(p) = 0.0_r8 - frNdemand_npool_to_deadcrootn_storage(p) = 0.0_r8 - end if - if (ivt(p) >= npcropmin) then ! skip 2 generic crops - - frNdemand_npool_to_livestemn(p) = 0.0_r8 - frNdemand_npool_to_livestemn_storage(p) = 0.0_r8 - frNdemand_npool_to_deadstemn(p) = 0.0_r8 - frNdemand_npool_to_deadstemn_storage(p) = 0.0_r8 - frNdemand_npool_to_livecrootn(p) = 0.0_r8 - frNdemand_npool_to_livecrootn_storage(p) = 0.0_r8 - frNdemand_npool_to_deadcrootn(p) = 0.0_r8 - frNdemand_npool_to_deadcrootn_storage(p) = 0.0_r8 - do k = 1, nrepr - frNdemand_npool_to_reproductiven(p,k) = 0.0_r8 - frNdemand_npool_to_reproductiven_storage(p,k) = 0.0_r8 - end do - end if - + if (use_crop_agsys .and. ivt(p) >= npcropmin) then + call calc_npool_to_components_agsys( & + ! Inputs + npool = npool(p), & + fcur = fcur, & + f4 = f4, & + ! The following inputs cannot appear in the associate statement at the + ! top of the subroutine because these pointers may be unallocated if not + ! running with AgSys: + aleaf_n = cnveg_state_inst%aleaf_n_patch(p), & + astem_n = cnveg_state_inst%astem_n_patch(p), & + aroot_n = cnveg_state_inst%aroot_n_patch(p), & + arepr_n = cnveg_state_inst%arepr_n_patch(p,:), & + + ! Outputs + npool_to_leafn = npool_to_leafn(p), & + npool_to_leafn_storage = npool_to_leafn_storage(p), & + npool_to_frootn = npool_to_frootn(p), & + npool_to_frootn_storage = npool_to_frootn_storage(p), & + npool_to_livestemn = npool_to_livestemn(p), & + npool_to_livestemn_storage = npool_to_livestemn_storage(p), & + npool_to_deadstemn = npool_to_deadstemn(p), & + npool_to_deadstemn_storage = npool_to_deadstemn_storage(p), & + npool_to_livecrootn = npool_to_livecrootn(p), & + npool_to_livecrootn_storage = npool_to_livecrootn_storage(p), & + npool_to_deadcrootn = npool_to_deadcrootn(p), & + npool_to_deadcrootn_storage = npool_to_deadcrootn_storage(p), & + npool_to_reproductiven = npool_to_reproductiven(p,:), & + npool_to_reproductiven_storage = npool_to_reproductiven_storage(p,:)) else - - frNdemand_npool_to_leafn(p) = npool_to_leafn_demand(p) / total_plant_Ndemand(p) - frNdemand_npool_to_leafn_storage(p) = npool_to_leafn_storage_demand(p) / total_plant_Ndemand(p) - frNdemand_npool_to_frootn(p) = npool_to_frootn_demand(p) / total_plant_Ndemand(p) - frNdemand_npool_to_frootn_storage(p) = npool_to_frootn_storage_demand(p) / total_plant_Ndemand(p) - if (woody(ivt(p)) == 1._r8) then - - frNdemand_npool_to_livestemn(p) = npool_to_livestemn_demand(p) / total_plant_Ndemand(p) - frNdemand_npool_to_livestemn_storage(p) = npool_to_livestemn_storage_demand(p) / total_plant_Ndemand(p) - frNdemand_npool_to_deadstemn(p) = npool_to_deadstemn_demand(p) / total_plant_Ndemand(p) - frNdemand_npool_to_deadstemn_storage(p) = npool_to_deadstemn_storage_demand(p) / total_plant_Ndemand(p) - frNdemand_npool_to_livecrootn(p) = npool_to_livecrootn_demand(p) / total_plant_Ndemand(p) - frNdemand_npool_to_livecrootn_storage(p) = npool_to_livecrootn_storage_demand(p) / total_plant_Ndemand(p) - frNdemand_npool_to_deadcrootn(p) = npool_to_deadcrootn_demand(p) / total_plant_Ndemand(p) - frNdemand_npool_to_deadcrootn_storage(p) = npool_to_deadcrootn_storage_demand(p) / total_plant_Ndemand(p) - end if - if (ivt(p) >= npcropmin) then ! skip 2 generic crops - - frNdemand_npool_to_livestemn(p) = npool_to_livestemn_demand(p) / total_plant_Ndemand(p) - frNdemand_npool_to_livestemn_storage(p) = npool_to_livestemn_storage_demand(p) / total_plant_Ndemand(p) - frNdemand_npool_to_deadstemn(p) = npool_to_deadstemn_demand(p) / total_plant_Ndemand(p) - frNdemand_npool_to_deadstemn_storage(p) = npool_to_deadstemn_storage_demand(p) / total_plant_Ndemand(p) - frNdemand_npool_to_livecrootn(p) = npool_to_livecrootn_demand(p) / total_plant_Ndemand(p) - frNdemand_npool_to_livecrootn_storage(p) = npool_to_livecrootn_storage_demand(p) / total_plant_Ndemand(p) - frNdemand_npool_to_deadcrootn(p) = npool_to_deadcrootn_demand(p) / total_plant_Ndemand(p) - frNdemand_npool_to_deadcrootn_storage(p) = npool_to_deadcrootn_storage_demand(p) / total_plant_Ndemand(p) - do k = 1, nrepr - frNdemand_npool_to_reproductiven(p,k) = & - npool_to_reproductiven_demand(p,k) / total_plant_Ndemand(p) - frNdemand_npool_to_reproductiven_storage(p,k) = & - npool_to_reproductiven_storage_demand(p,k) / total_plant_Ndemand(p) - end do - end if - + call calc_npool_to_components_flexiblecn( & + ! Inputs + npool = npool(p), & + ivt = ivt(p), & + nlc = nlc, & + fcur = fcur, & + f1 = f1, & + f2 = f2, & + f3 = f3, & + f4 = f4, & + f5 = f5, & + + ! Outputs + npool_to_leafn = npool_to_leafn(p), & + npool_to_leafn_storage = npool_to_leafn_storage(p), & + npool_to_frootn = npool_to_frootn(p), & + npool_to_frootn_storage = npool_to_frootn_storage(p), & + npool_to_livestemn = npool_to_livestemn(p), & + npool_to_livestemn_storage = npool_to_livestemn_storage(p), & + npool_to_deadstemn = npool_to_deadstemn(p), & + npool_to_deadstemn_storage = npool_to_deadstemn_storage(p), & + npool_to_livecrootn = npool_to_livecrootn(p), & + npool_to_livecrootn_storage = npool_to_livecrootn_storage(p), & + npool_to_deadcrootn = npool_to_deadcrootn(p), & + npool_to_deadcrootn_storage = npool_to_deadcrootn_storage(p), & + npool_to_reproductiven = npool_to_reproductiven(p,:), & + npool_to_reproductiven_storage = npool_to_reproductiven_storage(p,:)) end if -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - - ! computing N allocation for different plant parts - ! allocating allocation to different plant parts in proportion to the fractional demand -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - npool_to_leafn(p) = frNdemand_npool_to_leafn(p) * npool(p) / dt - npool_to_leafn_storage(p) = frNdemand_npool_to_leafn_storage(p) * npool(p) / dt - npool_to_frootn(p) = frNdemand_npool_to_frootn(p) * npool(p) / dt - npool_to_frootn_storage(p) = frNdemand_npool_to_frootn_storage(p) * npool(p) / dt - if (woody(ivt(p)) == 1._r8) then - npool_to_livestemn(p) = frNdemand_npool_to_livestemn(p) * npool(p) / dt - npool_to_livestemn_storage(p) = frNdemand_npool_to_livestemn_storage(p) * npool(p) / dt - npool_to_deadstemn(p) = frNdemand_npool_to_deadstemn(p) * npool(p) / dt - npool_to_deadstemn_storage(p) = frNdemand_npool_to_deadstemn_storage(p) * npool(p) / dt - npool_to_livecrootn(p) = frNdemand_npool_to_livecrootn(p) * npool(p) / dt - npool_to_livecrootn_storage(p) = frNdemand_npool_to_livecrootn_storage(p) * npool(p) / dt - npool_to_deadcrootn(p) = frNdemand_npool_to_deadcrootn(p) * npool(p) / dt - npool_to_deadcrootn_storage(p) = frNdemand_npool_to_deadcrootn_storage(p) * npool(p) / dt - end if - if (ivt(p) >= npcropmin) then ! skip 2 generic crops - npool_to_livestemn(p) = frNdemand_npool_to_livestemn(p) * npool(p) / dt - npool_to_livestemn_storage(p) = frNdemand_npool_to_livestemn_storage(p) * npool(p) / dt - npool_to_deadstemn(p) = frNdemand_npool_to_deadstemn(p) * npool(p) / dt - npool_to_deadstemn_storage(p) = frNdemand_npool_to_deadstemn_storage(p) * npool(p) / dt - npool_to_livecrootn(p) = frNdemand_npool_to_livecrootn(p) * npool(p) / dt - npool_to_livecrootn_storage(p) = frNdemand_npool_to_livecrootn_storage(p) * npool(p) / dt - npool_to_deadcrootn(p) = frNdemand_npool_to_deadcrootn(p) * npool(p) / dt - npool_to_deadcrootn_storage(p) = frNdemand_npool_to_deadcrootn_storage(p) * npool(p) / dt - do k = 1, nrepr - npool_to_reproductiven(p,k) = frNdemand_npool_to_reproductiven(p,k) * npool(p) / dt - npool_to_reproductiven_storage(p,k) = frNdemand_npool_to_reproductiven_storage(p,k) * npool(p) / dt - end do - end if -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - cpool_to_resp(p) = 0.0_r8 cpool_to_leafc_resp(p) = 0.0_r8 @@ -893,19 +731,390 @@ subroutine calc_plant_cn_alloc(this, bounds, num_soilp, filter_soilp, & end subroutine calc_plant_cn_alloc + !----------------------------------------------------------------------- + subroutine calc_npool_to_components_flexiblecn( & + npool, ivt, nlc, fcur, f1, f2, f3, f4, f5, & + npool_to_leafn, npool_to_leafn_storage, & + npool_to_frootn, npool_to_frootn_storage, & + npool_to_livestemn, npool_to_livestemn_storage, & + npool_to_deadstemn, npool_to_deadstemn_storage, & + npool_to_livecrootn, npool_to_livecrootn_storage, & + npool_to_deadcrootn, npool_to_deadcrootn_storage, & + npool_to_reproductiven, npool_to_reproductiven_storage) + ! + ! !DESCRIPTION: + ! Calculate npool_to_* terms for a single patch using the FlexibleCN approach + ! + ! !ARGUMENTS: + real(r8), intent(in) :: npool ! temporary plant N pool (gN/m2) + integer, intent(in) :: ivt ! vegetation type + real(r8), intent(in) :: nlc ! new leaf carbon allocation (gC/m2/s) + real(r8), intent(in) :: fcur ! fraction of current psn displayed as growth + real(r8), intent(in) :: f1 ! C allocation parameter - fine_root:leaf ratio + real(r8), intent(in) :: f2 ! C allocation parameter - coarse_root:stem ratio + 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 + + ! 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. + real(r8), intent(inout) :: npool_to_leafn + real(r8), intent(inout) :: npool_to_leafn_storage + real(r8), intent(inout) :: npool_to_frootn + real(r8), intent(inout) :: npool_to_frootn_storage + real(r8), intent(inout) :: npool_to_livestemn + real(r8), intent(inout) :: npool_to_livestemn_storage + real(r8), intent(inout) :: npool_to_deadstemn + real(r8), intent(inout) :: npool_to_deadstemn_storage + real(r8), intent(inout) :: npool_to_livecrootn + real(r8), intent(inout) :: npool_to_livecrootn_storage + real(r8), intent(inout) :: npool_to_deadcrootn + real(r8), intent(inout) :: npool_to_deadcrootn_storage + real(r8), intent(inout) :: npool_to_reproductiven(:) + real(r8), intent(inout) :: npool_to_reproductiven_storage(:) + + ! + ! !LOCAL VARIABLES: + real(r8) :: cnl,cnfr,cnlw,cndw ! C:N ratios for leaf, fine root, and wood + real(r8) :: cng ! C:N ratio for grain (= cnlw for now; slevis) + real(r8) :: dt ! model time step + integer :: k + + real(r8) :: npool_to_reproductiven_demand_tot + real(r8) :: npool_to_reproductiven_storage_demand_tot + real(r8) :: npool_to_leafn_demand + real(r8) :: npool_to_leafn_storage_demand + real(r8) :: npool_to_frootn_demand + real(r8) :: npool_to_frootn_storage_demand + real(r8) :: npool_to_livestemn_demand + real(r8) :: npool_to_livestemn_storage_demand + real(r8) :: npool_to_livecrootn_demand + real(r8) :: npool_to_livecrootn_storage_demand + real(r8) :: npool_to_deadstemn_demand + real(r8) :: npool_to_deadstemn_storage_demand + real(r8) :: npool_to_deadcrootn_demand + real(r8) :: npool_to_deadcrootn_storage_demand + real(r8) :: npool_to_reproductiven_demand(nrepr) + real(r8) :: npool_to_reproductiven_storage_demand(nrepr) + real(r8) :: total_plant_Ndemand + real(r8) :: frNdemand_npool_to_leafn + real(r8) :: frNdemand_npool_to_leafn_storage + real(r8) :: frNdemand_npool_to_frootn + real(r8) :: frNdemand_npool_to_frootn_storage + real(r8) :: frNdemand_npool_to_livestemn + real(r8) :: frNdemand_npool_to_livestemn_storage + real(r8) :: frNdemand_npool_to_deadstemn + real(r8) :: frNdemand_npool_to_deadstemn_storage + real(r8) :: frNdemand_npool_to_livecrootn + real(r8) :: frNdemand_npool_to_livecrootn_storage + real(r8) :: frNdemand_npool_to_deadcrootn + real(r8) :: frNdemand_npool_to_deadcrootn_storage + real(r8) :: frNdemand_npool_to_reproductiven(nrepr) + real(r8) :: frNdemand_npool_to_reproductiven_storage(nrepr) + + character(len=*), parameter :: subname = 'calc_npool_to_components_flexiblecn' + !----------------------------------------------------------------------- + + SHR_ASSERT_ALL_FL((ubound(f5) == [nrepr]), sourcefile, __LINE__) + SHR_ASSERT_ALL_FL((ubound(npool_to_reproductiven) == [nrepr]), sourcefile, __LINE__) + SHR_ASSERT_ALL_FL((ubound(npool_to_reproductiven_storage) == [nrepr]), sourcefile, __LINE__) + + 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) + graincn => pftcon%graincn & ! Input: grain C:N (gC/gN) + ) + + dt = get_step_size_real() + + cnl = leafcn(ivt) + cnfr = frootcn(ivt) + cnlw = livewdcn(ivt) + cndw = deadwdcn(ivt) + + ! computing 1.) fractional N demand and 2.) N allocation after uptake for different plant parts +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + ! computing nitrogen demand for different pools based on carbon allocated and CN ratio + npool_to_leafn_demand = (nlc / cnl) * fcur + npool_to_leafn_storage_demand = (nlc / cnl) * (1._r8 - fcur) + npool_to_frootn_demand = (nlc * f1 / cnfr) * fcur + npool_to_frootn_storage_demand = (nlc * f1 / cnfr) * (1._r8 - fcur) + if (woody(ivt) == 1._r8) then + + npool_to_livestemn_demand = (nlc * f3 * f4 / cnlw) * fcur + npool_to_livestemn_storage_demand = (nlc * f3 * f4 / cnlw) * (1._r8 - fcur) + npool_to_deadstemn_demand = (nlc * f3 * (1._r8 - f4) / cndw) * fcur + npool_to_deadstemn_storage_demand = (nlc * f3 * (1._r8 - f4) / cndw) * (1._r8 - fcur) + npool_to_livecrootn_demand = (nlc * f2 * f3 * f4 / cnlw) * fcur + npool_to_livecrootn_storage_demand = (nlc * f2 * f3 * f4 / cnlw) * (1._r8 - fcur) + npool_to_deadcrootn_demand = (nlc * f2 * f3 * (1._r8 - f4) / cndw) * fcur + npool_to_deadcrootn_storage_demand = (nlc * f2 * f3 * (1._r8 - f4) / cndw) * (1._r8 - fcur) + end if + if (ivt >= npcropmin) then ! skip 2 generic crops + + cng = graincn(ivt) + npool_to_livestemn_demand = (nlc * f3 * f4 / cnlw) * fcur + npool_to_livestemn_storage_demand = (nlc * f3 * f4 / cnlw) * (1._r8 - fcur) + npool_to_deadstemn_demand = (nlc * f3 * (1._r8 - f4) / cndw) * fcur + npool_to_deadstemn_storage_demand = (nlc * f3 * (1._r8 - f4) / cndw) * (1._r8 - fcur) + npool_to_livecrootn_demand = (nlc * f2 * f3 * f4 / cnlw) * fcur + npool_to_livecrootn_storage_demand = (nlc * f2 * f3 * f4 / cnlw) * (1._r8 - fcur) + npool_to_deadcrootn_demand = (nlc * f2 * f3 * (1._r8 - f4) / cndw) * fcur + npool_to_deadcrootn_storage_demand = (nlc * f2 * f3 * (1._r8 - f4) / cndw) * (1._r8 - fcur) + do k = 1, nrepr + npool_to_reproductiven_demand(k) = (nlc * f5(k) / cng) * fcur + npool_to_reproductiven_storage_demand(k) = (nlc * f5(k) / cng) * (1._r8 -fcur) + end do + end if + + + ! computing 1.) fractional N demand for different plant parts +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + total_plant_Ndemand = npool_to_leafn_demand + npool_to_leafn_storage_demand + & + npool_to_frootn_demand + npool_to_frootn_storage_demand + + if (woody(ivt) == 1._r8) then + + total_plant_Ndemand = npool_to_leafn_demand + npool_to_leafn_storage_demand + & + npool_to_frootn_demand + npool_to_frootn_storage_demand + & + npool_to_livestemn_demand + npool_to_livestemn_storage_demand + npool_to_deadstemn_demand + & + npool_to_deadstemn_storage_demand + & + npool_to_livecrootn_demand + npool_to_livecrootn_storage_demand + npool_to_deadcrootn_demand + & + npool_to_deadcrootn_storage_demand + + end if + if (ivt >= npcropmin) then ! skip 2 generic crops + + npool_to_reproductiven_demand_tot = 0._r8 + npool_to_reproductiven_storage_demand_tot = 0._r8 + do k = 1, nrepr + npool_to_reproductiven_demand_tot = npool_to_reproductiven_demand_tot + & + npool_to_reproductiven_demand(k) + npool_to_reproductiven_storage_demand_tot = npool_to_reproductiven_storage_demand_tot + & + npool_to_reproductiven_storage_demand(k) + end do + + total_plant_Ndemand = npool_to_leafn_demand + npool_to_leafn_storage_demand + & + npool_to_frootn_demand + npool_to_frootn_storage_demand + & + npool_to_livestemn_demand + npool_to_livestemn_storage_demand + npool_to_deadstemn_demand + & + npool_to_deadstemn_storage_demand + & + npool_to_livecrootn_demand + npool_to_livecrootn_storage_demand + npool_to_deadcrootn_demand + & + npool_to_deadcrootn_storage_demand + & + npool_to_reproductiven_demand_tot + npool_to_reproductiven_storage_demand_tot + + end if + + if (total_plant_Ndemand == 0.0_r8) then ! removing division by zero + + frNdemand_npool_to_leafn = 0.0_r8 + frNdemand_npool_to_leafn_storage = 0.0_r8 + frNdemand_npool_to_frootn = 0.0_r8 + frNdemand_npool_to_frootn_storage = 0.0_r8 + if (woody(ivt) == 1._r8) then + + frNdemand_npool_to_livestemn = 0.0_r8 + frNdemand_npool_to_livestemn_storage = 0.0_r8 + frNdemand_npool_to_deadstemn = 0.0_r8 + frNdemand_npool_to_deadstemn_storage = 0.0_r8 + frNdemand_npool_to_livecrootn = 0.0_r8 + frNdemand_npool_to_livecrootn_storage = 0.0_r8 + frNdemand_npool_to_deadcrootn = 0.0_r8 + frNdemand_npool_to_deadcrootn_storage = 0.0_r8 + end if + if (ivt >= npcropmin) then ! skip 2 generic crops + + frNdemand_npool_to_livestemn = 0.0_r8 + frNdemand_npool_to_livestemn_storage = 0.0_r8 + frNdemand_npool_to_deadstemn = 0.0_r8 + frNdemand_npool_to_deadstemn_storage = 0.0_r8 + frNdemand_npool_to_livecrootn = 0.0_r8 + frNdemand_npool_to_livecrootn_storage = 0.0_r8 + frNdemand_npool_to_deadcrootn = 0.0_r8 + frNdemand_npool_to_deadcrootn_storage = 0.0_r8 + do k = 1, nrepr + frNdemand_npool_to_reproductiven(k) = 0.0_r8 + frNdemand_npool_to_reproductiven_storage(k) = 0.0_r8 + end do + end if + + else + + frNdemand_npool_to_leafn = npool_to_leafn_demand / total_plant_Ndemand + frNdemand_npool_to_leafn_storage = npool_to_leafn_storage_demand / total_plant_Ndemand + frNdemand_npool_to_frootn = npool_to_frootn_demand / total_plant_Ndemand + frNdemand_npool_to_frootn_storage = npool_to_frootn_storage_demand / total_plant_Ndemand + if (woody(ivt) == 1._r8) then + + frNdemand_npool_to_livestemn = npool_to_livestemn_demand / total_plant_Ndemand + frNdemand_npool_to_livestemn_storage = npool_to_livestemn_storage_demand / total_plant_Ndemand + frNdemand_npool_to_deadstemn = npool_to_deadstemn_demand / total_plant_Ndemand + frNdemand_npool_to_deadstemn_storage = npool_to_deadstemn_storage_demand / total_plant_Ndemand + frNdemand_npool_to_livecrootn = npool_to_livecrootn_demand / total_plant_Ndemand + frNdemand_npool_to_livecrootn_storage = npool_to_livecrootn_storage_demand / total_plant_Ndemand + frNdemand_npool_to_deadcrootn = npool_to_deadcrootn_demand / total_plant_Ndemand + frNdemand_npool_to_deadcrootn_storage = npool_to_deadcrootn_storage_demand / total_plant_Ndemand + end if + if (ivt >= npcropmin) then ! skip 2 generic crops + + frNdemand_npool_to_livestemn = npool_to_livestemn_demand / total_plant_Ndemand + frNdemand_npool_to_livestemn_storage = npool_to_livestemn_storage_demand / total_plant_Ndemand + frNdemand_npool_to_deadstemn = npool_to_deadstemn_demand / total_plant_Ndemand + frNdemand_npool_to_deadstemn_storage = npool_to_deadstemn_storage_demand / total_plant_Ndemand + frNdemand_npool_to_livecrootn = npool_to_livecrootn_demand / total_plant_Ndemand + frNdemand_npool_to_livecrootn_storage = npool_to_livecrootn_storage_demand / total_plant_Ndemand + frNdemand_npool_to_deadcrootn = npool_to_deadcrootn_demand / total_plant_Ndemand + frNdemand_npool_to_deadcrootn_storage = npool_to_deadcrootn_storage_demand / total_plant_Ndemand + do k = 1, nrepr + frNdemand_npool_to_reproductiven(k) = & + npool_to_reproductiven_demand(k) / total_plant_Ndemand + frNdemand_npool_to_reproductiven_storage(k) = & + npool_to_reproductiven_storage_demand(k) / total_plant_Ndemand + end do + end if + + end if +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + + ! computing N allocation for different plant parts + ! allocating allocation to different plant parts in proportion to the fractional demand +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + npool_to_leafn = frNdemand_npool_to_leafn * npool / dt + npool_to_leafn_storage = frNdemand_npool_to_leafn_storage * npool / dt + npool_to_frootn = frNdemand_npool_to_frootn * npool / dt + npool_to_frootn_storage = frNdemand_npool_to_frootn_storage * npool / dt + if (woody(ivt) == 1._r8) then + npool_to_livestemn = frNdemand_npool_to_livestemn * npool / dt + npool_to_livestemn_storage = frNdemand_npool_to_livestemn_storage * npool / dt + npool_to_deadstemn = frNdemand_npool_to_deadstemn * npool / dt + npool_to_deadstemn_storage = frNdemand_npool_to_deadstemn_storage * npool / dt + npool_to_livecrootn = frNdemand_npool_to_livecrootn * npool / dt + npool_to_livecrootn_storage = frNdemand_npool_to_livecrootn_storage * npool / dt + npool_to_deadcrootn = frNdemand_npool_to_deadcrootn * npool / dt + npool_to_deadcrootn_storage = frNdemand_npool_to_deadcrootn_storage * npool / dt + end if + if (ivt >= npcropmin) then ! skip 2 generic crops + npool_to_livestemn = frNdemand_npool_to_livestemn * npool / dt + npool_to_livestemn_storage = frNdemand_npool_to_livestemn_storage * npool / dt + npool_to_deadstemn = frNdemand_npool_to_deadstemn * npool / dt + npool_to_deadstemn_storage = frNdemand_npool_to_deadstemn_storage * npool / dt + npool_to_livecrootn = frNdemand_npool_to_livecrootn * npool / dt + npool_to_livecrootn_storage = frNdemand_npool_to_livecrootn_storage * npool / dt + npool_to_deadcrootn = frNdemand_npool_to_deadcrootn * npool / dt + npool_to_deadcrootn_storage = frNdemand_npool_to_deadcrootn_storage * npool / dt + do k = 1, nrepr + npool_to_reproductiven(k) = frNdemand_npool_to_reproductiven(k) * npool / dt + npool_to_reproductiven_storage(k) = frNdemand_npool_to_reproductiven_storage(k) * npool / dt + end do + end if +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + end associate + end subroutine calc_npool_to_components_flexiblecn + + !----------------------------------------------------------------------- + subroutine calc_npool_to_components_agsys( & + npool, fcur, f4, aleaf_n, astem_n, aroot_n, arepr_n, & + npool_to_leafn, npool_to_leafn_storage, & + npool_to_frootn, npool_to_frootn_storage, & + npool_to_livestemn, npool_to_livestemn_storage, & + npool_to_deadstemn, npool_to_deadstemn_storage, & + npool_to_livecrootn, npool_to_livecrootn_storage, & + npool_to_deadcrootn, npool_to_deadcrootn_storage, & + npool_to_reproductiven, npool_to_reproductiven_storage) + ! + ! !DESCRIPTION: + ! Calculate npool_to_* terms for a single crop patch when using AgSys + ! + ! Note that this assumes that there is no allocation to coarse roots + ! + ! !ARGUMENTS: + real(r8), intent(in) :: npool ! temporary plant N pool (gN/m2) + real(r8), intent(in) :: fcur ! fraction of current psn displayed as growth + real(r8), intent(in) :: f4 ! C allocation parameter - fraction of new wood that is live + real(r8), intent(in) :: aleaf_n ! leaf allocation coefficient for N + real(r8), intent(in) :: astem_n ! stem allocation coefficient for N + real(r8), intent(in) :: aroot_n ! root allocation coefficient for N + real(r8), intent(in) :: arepr_n(:) ! reproductive allocation coefficient(s) for N + + ! Each of the following output variables is in units of gN/m2/s + real(r8), intent(out) :: npool_to_leafn + real(r8), intent(out) :: npool_to_leafn_storage + real(r8), intent(out) :: npool_to_frootn + real(r8), intent(out) :: npool_to_frootn_storage + real(r8), intent(out) :: npool_to_livestemn + real(r8), intent(out) :: npool_to_livestemn_storage + real(r8), intent(out) :: npool_to_deadstemn + real(r8), intent(out) :: npool_to_deadstemn_storage + real(r8), intent(out) :: npool_to_livecrootn + real(r8), intent(out) :: npool_to_livecrootn_storage + real(r8), intent(out) :: npool_to_deadcrootn + real(r8), intent(out) :: npool_to_deadcrootn_storage + real(r8), intent(out) :: npool_to_reproductiven(:) + real(r8), intent(out) :: npool_to_reproductiven_storage(:) + + ! + ! !LOCAL VARIABLES: + real(r8) :: dt ! model time step + integer :: k + + character(len=*), parameter :: subname = 'calc_npool_to_components_agsys' + !----------------------------------------------------------------------- + + SHR_ASSERT_ALL_FL((ubound(arepr_n) == [nrepr]), sourcefile, __LINE__) + SHR_ASSERT_ALL_FL((ubound(npool_to_reproductiven) == [nrepr]), sourcefile, __LINE__) + SHR_ASSERT_ALL_FL((ubound(npool_to_reproductiven_storage) == [nrepr]), sourcefile, __LINE__) + + dt = get_step_size_real() + + npool_to_leafn = aleaf_n * fcur * npool / dt + npool_to_leafn_storage = aleaf_n * (1._r8 - fcur) * npool / dt + + npool_to_frootn = aroot_n * fcur * npool / dt + npool_to_frootn_storage = aroot_n * (1._r8 - fcur) * npool / dt + + npool_to_livestemn = astem_n * f4 * fcur * npool / dt + npool_to_livestemn_storage = astem_n * f4 * (1._r8 - fcur) * npool / dt + npool_to_deadstemn = astem_n * (1._r8 - f4) * fcur * npool / dt + npool_to_deadstemn_storage = astem_n * (1._r8 - f4) * (1._r8 - fcur) * npool / dt + + ! Assume no allocation to coarse roots for crops. If there *were* allocation to coarse + ! roots (via a non-zero croot_stem), we would have bigger issues with consistency + ! between AgSys's desired allocation and the actual C/N allocation: the way this + ! allocation is currently formulated, non-zero allocation to coarse roots implies that + ! things like aleaf and arepr aren't truly the fractional allocation to leaves and + ! reproductive organs: the actual allocation fractions end up being reduced somewhat + ! via a normalizing factor that differs from 1. + ! + ! It's not really necessary to explicitly set these to 0 every time step, but we do + ! it to try make it obvious that this will need to change if we ever want to have + ! non-zero allocation to coarse roots for crops. + npool_to_livecrootn = 0._r8 + npool_to_livecrootn_storage = 0._r8 + npool_to_deadcrootn = 0._r8 + npool_to_deadcrootn_storage = 0._r8 + + do k = 1, nrepr + npool_to_reproductiven(k) = arepr_n(k) * fcur * npool / dt + npool_to_reproductiven_storage(k) = arepr_n(k) * (1._r8 - fcur) * npool / dt + end do + + end subroutine calc_npool_to_components_agsys + ! ----------------------------------------------------------------------- - subroutine calc_plant_nutrient_demand(this, bounds, num_soilp, filter_soilp,& - photosyns_inst, crop_inst, canopystate_inst, & + subroutine calc_plant_nutrient_demand(this, bounds, & + num_p, filter_p, call_is_for_pcrop, & + crop_inst, canopystate_inst, & cnveg_state_inst, cnveg_carbonstate_inst, cnveg_carbonflux_inst, & - c13_cnveg_carbonflux_inst, c14_cnveg_carbonflux_inst, & cnveg_nitrogenstate_inst, cnveg_nitrogenflux_inst, & soilbiogeochem_carbonflux_inst, soilbiogeochem_nitrogenstate_inst, & - energyflux_inst, & - aroot, arepr) + energyflux_inst) ! ! !USES: use CanopyStateType , only : canopystate_type - use PhotosynthesisMod , only : photosyns_type use CropType , only : crop_type use CNVegStateType , only : cnveg_state_type use CNVegCarbonStateType , only : cnveg_carbonstate_type @@ -918,57 +1127,65 @@ subroutine calc_plant_nutrient_demand(this, bounds, num_soilp, filter_soilp,& ! !ARGUMENTS: class(nutrient_competition_FlexibleCN_type), intent(inout) :: this type(bounds_type) , intent(in) :: bounds - integer , intent(in) :: num_soilp ! number of soil patches in filter - integer , intent(in) :: filter_soilp(:) ! filter for soil patches - type(photosyns_type) , intent(in) :: photosyns_inst + + ! This subroutine is meant to be called separately for non-prognostic-crop points and + ! prognostic-crop points. (The reason for this is so that the call for prognostic-crop + ! points can be skipped when a separate crop model is calculating these variables.) In + ! the call for non-prognostic-crop points, this filter should be the soilnopcropp + ! filter and call_is_for_pcrop should be false; in the call for prognostic-crop + ! points, this filter should be the pcropp filter and call_is_for_pcrop should be + ! true. + integer , intent(in) :: num_p ! number of patches in filter + integer , intent(in) :: filter_p(:) ! patch filter + logical , intent(in) :: call_is_for_pcrop + type(crop_type) , intent(in) :: crop_inst type(canopystate_type) , intent(in) :: canopystate_inst type(cnveg_state_type) , intent(inout) :: cnveg_state_inst - type(cnveg_carbonstate_type) , intent(inout) :: cnveg_carbonstate_inst - type(cnveg_carbonflux_type) , intent(inout) :: cnveg_carbonflux_inst - type(cnveg_carbonflux_type) , intent(inout) :: c13_cnveg_carbonflux_inst - type(cnveg_carbonflux_type) , intent(inout) :: c14_cnveg_carbonflux_inst + type(cnveg_carbonstate_type) , intent(in) :: cnveg_carbonstate_inst + type(cnveg_carbonflux_type) , intent(in) :: cnveg_carbonflux_inst type(cnveg_nitrogenstate_type) , intent(in) :: cnveg_nitrogenstate_inst type(cnveg_nitrogenflux_type) , intent(inout) :: cnveg_nitrogenflux_inst type(soilbiogeochem_carbonflux_type) , intent(in) :: soilbiogeochem_carbonflux_inst type(soilbiogeochem_nitrogenstate_type), intent(in) :: soilbiogeochem_nitrogenstate_inst type(energyflux_type) , intent(in) :: energyflux_inst - real(r8) , intent(out) :: aroot(bounds%begp:) - real(r8) , intent(out) :: arepr(bounds%begp:,:) !----------------------------------------------------------------------- - call this%calc_plant_nitrogen_demand(bounds, num_soilp, filter_soilp, & - photosyns_inst, crop_inst, canopystate_inst, & + call this%calc_plant_nitrogen_demand(bounds, & + num_p, filter_p, call_is_for_pcrop, & + crop_inst, canopystate_inst, & cnveg_state_inst, cnveg_carbonstate_inst, cnveg_carbonflux_inst, & - c13_cnveg_carbonflux_inst, c14_cnveg_carbonflux_inst, & cnveg_nitrogenstate_inst, cnveg_nitrogenflux_inst, & soilbiogeochem_carbonflux_inst, soilbiogeochem_nitrogenstate_inst, & - energyflux_inst, & - aroot=aroot(bounds%begp:bounds%endp), & - arepr=arepr(bounds%begp:bounds%endp,:)) + energyflux_inst) end subroutine calc_plant_nutrient_demand !----------------------------------------------------------------------- - subroutine calc_plant_nitrogen_demand(this, bounds, num_soilp, filter_soilp, & - photosyns_inst, crop_inst, canopystate_inst, & + subroutine calc_plant_nitrogen_demand(this, bounds, & + num_p, filter_p, call_is_for_pcrop, & + crop_inst, canopystate_inst, & cnveg_state_inst, cnveg_carbonstate_inst, cnveg_carbonflux_inst, & - c13_cnveg_carbonflux_inst, c14_cnveg_carbonflux_inst, & cnveg_nitrogenstate_inst, cnveg_nitrogenflux_inst, & soilbiogeochem_carbonflux_inst, soilbiogeochem_nitrogenstate_inst, & - energyflux_inst, & - aroot, arepr) + energyflux_inst) + ! + ! !DESCRIPTION: + ! Sets the following output variables that are used elsewhere: + ! - plant_ndemand + ! - retransn_to_npool + ! - leafn_to_retransn + ! - frootn_to_retransn + ! - livestemn_to_retransn ! ! !USES: use pftconMod , only : npcropmin, pftcon use pftconMod , only : ntmp_soybean, nirrig_tmp_soybean use pftconMod , only : ntrp_soybean, nirrig_trp_soybean - use clm_varcon , only : secspday, dzsoi_decomp - use clm_varctl , only : use_c13, use_c14 + use clm_varcon , only : dzsoi_decomp use clm_varpar , only : nlevdecomp use clm_time_manager , only : get_step_size_real use CanopyStateType , only : canopystate_type - use PhotosynthesisMod , only : photosyns_type use CropType , only : crop_type use CNVegStateType , only : cnveg_state_type use CNVegCarbonStateType , only : cnveg_carbonstate_type @@ -984,41 +1201,34 @@ subroutine calc_plant_nitrogen_demand(this, bounds, num_soilp, filter_soilp, & ! !ARGUMENTS: class(nutrient_competition_FlexibleCN_type), intent(inout) :: this type(bounds_type) , intent(in) :: bounds - integer , intent(in) :: num_soilp ! number of soil patches in filter - integer , intent(in) :: filter_soilp(:) ! filter for soil patches - type(photosyns_type) , intent(in) :: photosyns_inst + + ! This subroutine is meant to be called separately for non-prognostic-crop points and + ! prognostic-crop points. (The reason for this is so that the call for prognostic-crop + ! points can be skipped when a separate crop model is calculating these variables.) In + ! the call for non-prognostic-crop points, this filter should be the soilnopcropp + ! filter and call_is_for_pcrop should be false; in the call for prognostic-crop + ! points, this filter should be the pcropp filter and call_is_for_pcrop should be + ! true. + integer , intent(in) :: num_p ! number of patches in filter + integer , intent(in) :: filter_p(:) ! patch filter + logical , intent(in) :: call_is_for_pcrop + type(crop_type) , intent(in) :: crop_inst type(canopystate_type) , intent(in) :: canopystate_inst type(cnveg_state_type) , intent(inout) :: cnveg_state_inst - type(cnveg_carbonstate_type) , intent(inout) :: cnveg_carbonstate_inst - type(cnveg_carbonflux_type) , intent(inout) :: cnveg_carbonflux_inst - type(cnveg_carbonflux_type) , intent(inout) :: c13_cnveg_carbonflux_inst - type(cnveg_carbonflux_type) , intent(inout) :: c14_cnveg_carbonflux_inst + type(cnveg_carbonstate_type) , intent(in) :: cnveg_carbonstate_inst + type(cnveg_carbonflux_type) , intent(in) :: cnveg_carbonflux_inst type(cnveg_nitrogenstate_type) , intent(in) :: cnveg_nitrogenstate_inst type(cnveg_nitrogenflux_type) , intent(inout) :: cnveg_nitrogenflux_inst type(soilbiogeochem_carbonflux_type) , intent(in) :: soilbiogeochem_carbonflux_inst type(soilbiogeochem_nitrogenstate_type), intent(in) :: soilbiogeochem_nitrogenstate_inst type(energyflux_type) , intent(in) :: energyflux_inst - real(r8) , intent(out) :: aroot(bounds%begp:) - real(r8) , intent(out) :: arepr(bounds%begp:,:) ! ! !LOCAL VARIABLES: - integer :: c, p, j, k ! indices + integer :: c, p, j ! indices integer :: fp ! lake filter patch index - real(r8) :: mr ! maintenance respiration (gC/m2/s) - real(r8) :: reproductive_mr_tot ! total maintenance respiration from grain components (gC/m2/s) - real(r8) :: f1, f2, f3, f4, g1, g2 ! allocation parameters - real(r8) :: g1a ! g1 included in allocation/allometry - real(r8) :: cnl, cnfr, cnlw, cndw ! C:N ratios for leaf, fine root, and wood - real(r8) :: curmr, curmr_ratio ! xsmrpool temporary variables - real(r8) :: f5(nrepr) ! reproductive allocation parameters - real(r8) :: cng ! C:N ratio for grain (= cnlw for now; slevis) - real(r8) :: fleaf ! fraction allocated to leaf real(r8) :: t1 ! temporary variable real(r8) :: dt ! model time step - real(r8) :: dayscrecover ! number of days to recover negative cpool - real(r8) :: f5_tot ! sum of f5 terms - real(r8) :: f5_n_tot ! sum of f5 terms converted from C to N real(r8) :: f_N (bounds%begp:bounds%endp) real(r8) :: Kmin real(r8) :: leafcn_max @@ -1028,111 +1238,55 @@ subroutine calc_plant_nitrogen_demand(this, bounds, num_soilp, filter_soilp, & real(r8) :: substrate_term real(r8) :: temp_scalar real(r8) :: Vmax_N + real(r8) :: crop_phase (bounds%begp:bounds%endp) real(r8) :: allocation_leaf (bounds%begp:bounds%endp) real(r8) :: allocation_stem (bounds%begp:bounds%endp) real(r8) :: allocation_froot (bounds%begp:bounds%endp) + character(len=*), parameter :: subname = "calc_plant_nitrogen_demand" ! ----------------------------------------------------------------------- - SHR_ASSERT_ALL_FL((ubound(aroot) == (/bounds%endp/)), sourcefile, __LINE__) - SHR_ASSERT_ALL_FL((ubound(arepr) == (/bounds%endp, nrepr/)), sourcefile, __LINE__) SHR_ASSERT_ALL_FL((ubound(this%actual_leafcn) >= (/bounds%endp/)), sourcefile, __LINE__) SHR_ASSERT_ALL_FL((lbound(this%actual_leafcn) <= (/bounds%begp/)), sourcefile, __LINE__) associate( & ivt => patch%itype , & ! Input: [integer (:) ] patch vegetation type - woody => pftcon%woody , & ! Input: binary flag for woody lifeform (1=woody, 0=not woody) - froot_leaf => pftcon%froot_leaf , & ! Input: allocation parameter: new fine root C per new leaf C (gC/gC) - 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) - 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) - graincn => pftcon%graincn , & ! Input: grain 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 - bfact => pftcon%bfact , & ! Input: parameter used below - aleaff => pftcon%aleaff , & ! Input: parameter used below - arootf => pftcon%arootf , & ! Input: parameter used below astemf => pftcon%astemf , & ! Input: parameter used below - arooti => pftcon%arooti , & ! Input: parameter used below - fleafi => pftcon%fleafi , & ! Input: parameter used below - allconsl => pftcon%allconsl , & ! Input: parameter used below - allconss => pftcon%allconss , & ! Input: parameter used below - grperc => pftcon%grperc , & ! Input: parameter used below - grpnow => pftcon%grpnow , & ! Input: parameter used below - declfact => pftcon%declfact , & ! Input: 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-deciduous leaf habit (0 or 1) - psnsun => photosyns_inst%psnsun_patch , & ! Input: [real(r8) (:) ] sunlit leaf-level photosynthesis (umol CO2 /m**2/ s) - psnsha => photosyns_inst%psnsha_patch , & ! Input: [real(r8) (:) ] shaded leaf-level photosynthesis (umol CO2 /m**2/ s) - c13_psnsun => photosyns_inst%c13_psnsun_patch , & ! Input: [real(r8) (:) ] sunlit leaf-level photosynthesis (umol CO2 /m**2/ s) - c13_psnsha => photosyns_inst%c13_psnsha_patch , & ! Input: [real(r8) (:) ] shaded leaf-level photosynthesis (umol CO2 /m**2/ s) - c14_psnsun => photosyns_inst%c14_psnsun_patch , & ! Input: [real(r8) (:) ] sunlit leaf-level photosynthesis (umol CO2 /m**2/ s) - c14_psnsha => photosyns_inst%c14_psnsha_patch , & ! Input: [real(r8) (:) ] shaded leaf-level photosynthesis (umol CO2 /m**2/ s) 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 - hui => crop_inst%hui_patch , & ! Input: [real(r8) (:) ] crop patch heat unit index (growing degree-days); set to 0 at sowing and accumulated until harvest - leafout => crop_inst%gddtsoi_patch , & ! Input: [real(r8) (:) ] =gdd from top soil layer temperature croplive => crop_inst%croplive_patch , & ! Input: [logical (:) ] flag, true if planted, not harvested - gddmaturity => cnveg_state_inst%gddmaturity_patch , & ! Input: [real(r8) (:) ] gdd needed to harvest - huileaf => cnveg_state_inst%huileaf_patch , & ! Input: [real(r8) (:) ] heat unit index needed from planting to leaf emergence - huigrain => cnveg_state_inst%huigrain_patch , & ! Input: [real(r8) (:) ] same to reach vegetative maturity - peaklai => cnveg_state_inst%peaklai_patch , & ! Input: [integer (:) ] 1: max allowed lai; 0: not at max - aleafi => cnveg_state_inst%aleafi_patch , & ! Output: [real(r8) (:) ] saved allocation coefficient from phase 2 - astemi => cnveg_state_inst%astemi_patch , & ! Output: [real(r8) (:) ] saved allocation coefficient from phase 2 - aleaf => cnveg_state_inst%aleaf_patch , & ! Output: [real(r8) (:) ] leaf allocation coefficient - astem => cnveg_state_inst%astem_patch , & ! Output: [real(r8) (:) ] stem allocation coefficient + astem => cnveg_state_inst%astem_patch , & ! Input: [real(r8) (:) ] stem allocation coefficient + c_allometry => cnveg_state_inst%c_allometry_patch , & ! Input: [real(r8) (:) ] C allocation index (DIM) + n_allometry => cnveg_state_inst%n_allometry_patch , & ! Input: [real(r8) (:) ] N allocation index (DIM) + annsum_potential_gpp => cnveg_state_inst%annsum_potential_gpp_patch , & ! Input: [real(r8) (:) ] annual sum of potential GPP + annmax_retransn => cnveg_state_inst%annmax_retransn_patch , & ! Input: [real(r8) (:) ] annual max of retranslocated N pool grain_flag => cnveg_state_inst%grain_flag_patch , & ! Output: [real(r8) (:) ] 1: grain fill stage; 0: not - c_allometry => cnveg_state_inst%c_allometry_patch , & ! Output: [real(r8) (:) ] C allocation index (DIM) - n_allometry => cnveg_state_inst%n_allometry_patch , & ! Output: [real(r8) (:) ] N allocation index (DIM) tempsum_potential_gpp => cnveg_state_inst%tempsum_potential_gpp_patch , & ! Output: [real(r8) (:) ] temporary annual sum of potential GPP tempmax_retransn => cnveg_state_inst%tempmax_retransn_patch , & ! Output: [real(r8) (:) ] temporary annual max of retranslocated N pool (gN/m2) - annsum_potential_gpp => cnveg_state_inst%annsum_potential_gpp_patch , & ! Output: [real(r8) (:) ] annual sum of potential GPP - annmax_retransn => cnveg_state_inst%annmax_retransn_patch , & ! Output: [real(r8) (:) ] annual max of retranslocated N pool - xsmrpool => cnveg_carbonstate_inst%xsmrpool_patch , & ! Input: [real(r8) (:) ] (gC/m2) temporary photosynthate C pool leafc => cnveg_carbonstate_inst%leafc_patch , & ! Input: [real(r8) (:) ] frootc => cnveg_carbonstate_inst%frootc_patch , & ! Input: [real(r8) (:) ] livestemc => cnveg_carbonstate_inst%livestemc_patch , & ! Input: [real(r8) (:) ] livecrootc => cnveg_carbonstate_inst%livecrootc_patch , & ! Input: [real(r8) (:) ] retransn => cnveg_nitrogenstate_inst%retransn_patch , & ! Input: [real(r8) (:) ] (gN/m2) plant pool of retranslocated N - annsum_npp => cnveg_carbonflux_inst%annsum_npp_patch , & ! Input: [real(r8) (:) ] annual sum of NPP, for wood allocation - leaf_mr => cnveg_carbonflux_inst%leaf_mr_patch , & ! Input: [real(r8) (:) ] - froot_mr => cnveg_carbonflux_inst%froot_mr_patch , & ! Input: [real(r8) (:) ] - livestem_mr => cnveg_carbonflux_inst%livestem_mr_patch , & ! Input: [real(r8) (:) ] - livecroot_mr => cnveg_carbonflux_inst%livecroot_mr_patch , & ! Input: [real(r8) (:) ] - reproductive_mr => cnveg_carbonflux_inst%reproductive_mr_patch , & ! Input: [real(r8) (:,:) ] - gpp => cnveg_carbonflux_inst%gpp_before_downreg_patch , & ! Output: [real(r8) (:) ] GPP flux before downregulation (gC/m2/s) - availc => cnveg_carbonflux_inst%availc_patch , & ! Output: [real(r8) (:) ] C flux available for allocation (gC/m2/s) - xsmrpool_recover => cnveg_carbonflux_inst%xsmrpool_recover_patch , & ! Output: [real(r8) (:) ] C flux assigned to recovery of negative cpool (gC/m2/s) - psnsun_to_cpool => cnveg_carbonflux_inst%psnsun_to_cpool_patch , & ! Output: [real(r8) (:) ] - psnshade_to_cpool => cnveg_carbonflux_inst%psnshade_to_cpool_patch , & ! Output: [real(r8) (:) ] - leaf_curmr => cnveg_carbonflux_inst%leaf_curmr_patch , & ! Output: [real(r8) (:) ] - froot_curmr => cnveg_carbonflux_inst%froot_curmr_patch , & ! Output: [real(r8) (:) ] - livestem_curmr => cnveg_carbonflux_inst%livestem_curmr_patch , & ! Output: [real(r8) (:) ] - livecroot_curmr => cnveg_carbonflux_inst%livecroot_curmr_patch , & ! Output: [real(r8) (:) ] - reproductive_curmr => cnveg_carbonflux_inst%reproductive_curmr_patch , & ! Output: [real(r8) (:,:) ] - leaf_xsmr => cnveg_carbonflux_inst%leaf_xsmr_patch , & ! Output: [real(r8) (:) ] - froot_xsmr => cnveg_carbonflux_inst%froot_xsmr_patch , & ! Output: [real(r8) (:) ] - livestem_xsmr => cnveg_carbonflux_inst%livestem_xsmr_patch , & ! Output: [real(r8) (:) ] - livecroot_xsmr => cnveg_carbonflux_inst%livecroot_xsmr_patch , & ! Output: [real(r8) (:) ] - reproductive_xsmr => cnveg_carbonflux_inst%reproductive_xsmr_patch , & ! Output: [real(r8) (:,:) ] - cpool_to_xsmrpool => cnveg_carbonflux_inst%cpool_to_xsmrpool_patch , & ! Output: [real(r8) (:) ] + gpp => cnveg_carbonflux_inst%gpp_before_downreg_patch , & ! Input: [real(r8) (:) ] GPP flux before downregulation (gC/m2/s) + availc => cnveg_carbonflux_inst%availc_patch , & ! Input: [real(r8) (:) ] C flux available for allocation (gC/m2/s) leafn => cnveg_nitrogenstate_inst%leafn_patch , & ! Input: [real(r8) (:) ] (gN/m2) leaf N plant_ndemand => cnveg_nitrogenflux_inst%plant_ndemand_patch , & ! Output: [real(r8) (:) ] N flux required to support initial GPP (gN/m2/s) avail_retransn => cnveg_nitrogenflux_inst%avail_retransn_patch , & ! Output: [real(r8) (:) ] N flux available from retranslocation pool (gN/m2/s) retransn_to_npool => cnveg_nitrogenflux_inst%retransn_to_npool_patch , & ! Output: [real(r8) (:) ] deployment of retranslocated N (gN/m2/s) - sminn_to_npool => cnveg_nitrogenflux_inst%sminn_to_npool_patch , & ! Output: [real(r8) (:) ] deployment of soil mineral N uptake (gN/m2/s) leafn_to_retransn => cnveg_nitrogenflux_inst%leafn_to_retransn_patch , & ! Output: [real(r8) (:) ] frootn_to_retransn => cnveg_nitrogenflux_inst%frootn_to_retransn_patch , & ! Output: [real(r8) (:) ] livestemn_to_retransn => cnveg_nitrogenflux_inst%livestemn_to_retransn_patch,& ! Output: [real(r8) (:) ] @@ -1147,204 +1301,83 @@ subroutine calc_plant_nitrogen_demand(this, bounds, num_soilp, filter_soilp, & ! set time steps dt = get_step_size_real() - ! set number of days to recover negative cpool - dayscrecover = params_inst%dayscrecover ! loop over patches to assess the total plant N demand - do fp = 1,num_soilp - p = filter_soilp(fp) - - ! get the time step total gross photosynthesis - ! this is coming from the canopy fluxes code, and is the - ! gpp that is used to control stomatal conductance. - ! For the nitrogen downregulation code, this is assumed - ! to be the potential gpp, and the actual gpp will be - ! reduced due to N limitation. - - ! Convert psn from umol/m2/s -> gC/m2/s - - ! The input psn (psnsun and psnsha) are expressed per unit LAI - ! in the sunlit and shaded canopy, respectively. These need to be - ! scaled by laisun and laisha to get the total gpp for allocation - - ! Note that no associate statement is used for the isotope carbon fluxes below - ! since they are not always allocated AND nag compiler will complain if you try to - ! to have an associate statement with unallocated memory + ! loop over patches to assess the total plant N demand + do fp = 1, num_p + p = filter_p(fp) - psnsun_to_cpool(p) = psnsun(p) * laisun(p) * 12.011e-6_r8 - psnshade_to_cpool(p) = psnsha(p) * laisha(p) * 12.011e-6_r8 - - if ( use_c13 ) then - c13_cnveg_carbonflux_inst%psnsun_to_cpool_patch(p) = c13_psnsun(p) * laisun(p) * 12.011e-6_r8 - c13_cnveg_carbonflux_inst%psnshade_to_cpool_patch(p) = c13_psnsha(p) * laisha(p) * 12.011e-6_r8 - endif - - if ( use_c14 ) then - c14_cnveg_carbonflux_inst%psnsun_to_cpool_patch(p) = c14_psnsun(p) * laisun(p) * 12.011e-6_r8 - c14_cnveg_carbonflux_inst%psnshade_to_cpool_patch(p) = c14_psnsha(p) * laisha(p) * 12.011e-6_r8 - endif + ! when we have "if (leafn(p) == 0.0_r8)" below then we + ! have floating overflow (out of floating point range) + ! error in "actual_leafcn(p) = leafc(p) / leafn(p)" + if (leafn(p) < n_min ) then + ! to avoid division by zero, and to set leafcn to missing value for history files + this%actual_leafcn(p) = spval + else + ! leaf CN ratio + this%actual_leafcn(p) = leafc(p) / leafn(p) + end if - gpp(p) = psnsun_to_cpool(p) + psnshade_to_cpool(p) - ! get the time step total maintenance respiration - ! These fluxes should already be in gC/m2/s + leafcn_min = leafcn(ivt(p)) - 10.0_r8 + leafcn_max = leafcn(ivt(p)) + 10.0_r8 - mr = leaf_mr(p) + froot_mr(p) - if (woody(ivt(p)) == 1.0_r8) then - mr = mr + livestem_mr(p) + livecroot_mr(p) - else if (ivt(p) >= npcropmin) then - if (croplive(p)) then - reproductive_mr_tot = 0._r8 - do k = 1, nrepr - reproductive_mr_tot = reproductive_mr_tot + reproductive_mr(p,k) - end do - mr = mr + livestem_mr(p) + reproductive_mr_tot - end if - end if + 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 ) - ! carbon flux available for allocation - availc(p) = gpp(p) - mr + nscalar = (this%actual_leafcn(p) - leafcn_min ) / (leafcn_max - leafcn_min) ! Nitrogen scaler factor + nscalar = min( max(0.0_r8, nscalar), 1.0_r8 ) - ! new code added for isotope calculations, 7/1/05, PET - ! If mr > gpp, then some mr comes from gpp, the rest comes from - ! cpool (xsmr) - if (mr > 0._r8 .and. availc(p) < 0._r8) then - curmr = gpp(p) - curmr_ratio = curmr / mr - else - curmr_ratio = 1._r8 - end if - leaf_curmr(p) = leaf_mr(p) * curmr_ratio - leaf_xsmr(p) = leaf_mr(p) - leaf_curmr(p) - froot_curmr(p) = froot_mr(p) * curmr_ratio - froot_xsmr(p) = froot_mr(p) - froot_curmr(p) - livestem_curmr(p) = livestem_mr(p) * curmr_ratio - livestem_xsmr(p) = livestem_mr(p) - livestem_curmr(p) - livecroot_curmr(p) = livecroot_mr(p) * curmr_ratio - livecroot_xsmr(p) = livecroot_mr(p) - livecroot_curmr(p) - do k = 1, nrepr - reproductive_curmr(p,k) = reproductive_mr(p,k) * curmr_ratio - reproductive_xsmr(p,k) = reproductive_mr(p,k) - reproductive_curmr(p,k) + c = patch%column(p) + sminn_total = 0.0_r8 + do j = 1, nlevdecomp + sminn_total = sminn_total + sminn_vr(c,j) * dzsoi_decomp(j) end do + Kmin = 1.0_r8 + substrate_term = sminn_total / (sminn_total + Kmin) - ! no allocation when available c is negative - availc(p) = max(availc(p),0.0_r8) - - ! test for an xsmrpool deficit - if (xsmrpool(p) < 0.0_r8) then - ! Running a deficit in the xsmrpool, so the first priority is to let - ! some availc from this timestep accumulate in xsmrpool. - ! Determine rate of recovery for xsmrpool deficit + c = patch%column(p) + temp_scalar=t_scalar(c,1) + temp_scalar = min( max(0.0_r8, temp_scalar), 1.0_r8 ) - xsmrpool_recover(p) = -xsmrpool(p)/(dayscrecover*secspday) - if (xsmrpool_recover(p) < availc(p)) then - ! available carbon reduced by amount for xsmrpool recovery - availc(p) = availc(p) - xsmrpool_recover(p) + if(use_fun)then ! in FUN, plant_ndemand is just used as a maximum draw on soil N pools. + plant_ndemand(p) = availc(p)*(n_allometry(p)/c_allometry(p)) + else !FUN + if (laisun(p)+laisha(p) > 0.0_r8) then + Vmax_N = 2.7E-8_r8 + plant_ndemand(p) = Vmax_N * frootc(p) * substrate_term * temp_scalar * nscalar else - ! all of the available carbon goes to xsmrpool recovery - xsmrpool_recover(p) = availc(p) - availc(p) = 0.0_r8 + plant_ndemand(p) = 0.0_r8 end if - cpool_to_xsmrpool(p) = xsmrpool_recover(p) - end if - f1 = froot_leaf(ivt(p)) - f2 = croot_stem(ivt(p)) - - ! modified wood allocation to be 2.2 at npp=800 gC/m2/yr, 0.2 at npp=0, - ! constrained so that it does not go lower than 0.2 (under negative annsum_npp) - ! This variable allocation is only for trees. Shrubs have a constant - ! allocation as specified in the pft-physiology file. The value is also used - ! as a trigger here: -1.0 means to use the dynamic allocation (trees). + if (this%actual_leafcn(p) < leafcn_min )then + plant_ndemand(p) = 0.0_r8 + end if + end if !FUN - if (stem_leaf(ivt(p)) == -1._r8) then - f3 = (2.7_r8/(1.0_r8+exp(-0.004_r8*(annsum_npp(p) - 300.0_r8)))) - 0.4_r8 - else - f3 = stem_leaf(ivt(p)) - end if + !if (leafn(p) < n_min ) then + !! to set leafcn to missing value for history files + !this%actual_leafcn(p) = spval + !end if - f4 = flivewd(ivt(p)) - g1 = grperc(ivt(p)) - g2 = grpnow(ivt(p)) - cnl = leafcn(ivt(p)) - cnfr = frootcn(ivt(p)) - cnlw = livewdcn(ivt(p)) - cndw = deadwdcn(ivt(p)) + ! 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) - ! calculate f1 to f5 for prog crops following AgroIBIS subr phenocrop + ! Adding the following line to carry max retransn info to CN Annual Update + tempmax_retransn(p) = max(tempmax_retransn(p),retransn(p)) + end do - do k = 1, nrepr - f5(k) = 0._r8 ! continued intializations from above - end do + if (call_is_for_pcrop) then + call CropPhase(bounds, num_p, filter_p, crop_inst, cnveg_state_inst, & + crop_phase = crop_phase(bounds%begp:bounds%endp)) - if (ivt(p) >= npcropmin) then ! skip 2 generic crops + do fp = 1, num_p + p = filter_p(fp) if (croplive(p)) then - ! same phases appear in subroutine CropPhenology - - ! Phase 1 completed: - ! ================== - ! if hui is less than the number of gdd needed for filling of grain - ! leaf emergence also has to have taken place for lai changes to occur - ! and carbon assimilation - ! Next phase: leaf emergence to start of leaf decline - - if (leafout(p) >= huileaf(p) .and. hui(p) < huigrain(p)) then - - ! allocation rules for crops based on maturity and linear decrease - ! of amount allocated to roots over course of the growing season - - do k = 1, nrepr - arepr(p,k) = 0._r8 - end do - if (peaklai(p) == 1) then ! lai at maximum allowed - aleaf(p) = 1.e-5_r8 - astem(p) = 0._r8 - aroot(p) = 1._r8 - aleaf(p) - else - aroot(p) = max(0._r8, min(1._r8, arooti(ivt(p)) - & - (arooti(ivt(p)) - arootf(ivt(p))) * & - min(1._r8, hui(p)/gddmaturity(p)))) - fleaf = fleafi(ivt(p)) * (exp(-bfact(ivt(p))) - & - exp(-bfact(ivt(p))*hui(p)/huigrain(p))) / & - (exp(-bfact(ivt(p)))-1) ! fraction alloc to leaf (from J Norman alloc curve) - aleaf(p) = max(1.e-5_r8, (1._r8 - aroot(p)) * fleaf) - astem(p) = 1._r8 - aleaf(p) - aroot(p) - end if - - ! AgroIBIS included here an immediate adjustment to aleaf & astem if the - ! predicted lai from the above allocation coefficients exceeded laimx. - ! We have decided to live with lais slightly higher than laimx by - ! enforcing the cap in the following tstep through the peaklai logic above. - - astemi(p) = astem(p) ! save for use by equations after shift - aleafi(p) = aleaf(p) ! to reproductive phenology stage begins + if (crop_phase(p) == cphase_leafemerge) then grain_flag(p) = 0._r8 ! setting to 0 while in phase 2 - - ! Phase 2 completed: - ! ================== - ! shift allocation either when enough gdd are accumulated or maximum number - ! of days has elapsed since planting - - else if (hui(p) >= huigrain(p)) then - aroot(p) = max(0._r8, min(1._r8, arooti(ivt(p)) - & - (arooti(ivt(p)) - arootf(ivt(p))) * min(1._r8, hui(p)/gddmaturity(p)))) - if (astemi(p) > astemf(ivt(p))) then - astem(p) = max(0._r8, max(astemf(ivt(p)), astem(p) * & - (1._r8 - min((hui(p)- & - huigrain(p))/((gddmaturity(p)*declfact(ivt(p)))- & - huigrain(p)),1._r8)**allconss(ivt(p)) ))) - end if - - ! If crops have hit peaklai, then set leaf allocation to small value - if (peaklai(p) == 1) then - aleaf(p) = 1.e-5_r8 - else if (aleafi(p) > aleaff(ivt(p))) then - aleaf(p) = max(1.e-5_r8, max(aleaff(ivt(p)), aleaf(p) * & - (1._r8 - min((hui(p)- & - huigrain(p))/((gddmaturity(p)*declfact(ivt(p)))- & - huigrain(p)),1._r8)**allconsl(ivt(p)) ))) - end if - + else if (crop_phase(p) == cphase_grainfill) then !Beth's retranslocation of leafn, stemn, rootn to organ !Filter excess plant N to retransn pool for organ N !Only do one time then hold grain_flag till onset next season @@ -1365,7 +1398,7 @@ subroutine calc_plant_nitrogen_demand(this, bounds, num_soilp, filter_soilp, & if (astem(p) == astemf(ivt(p)) .or. & (ivt(p) /= ntmp_soybean .and. ivt(p) /= nirrig_tmp_soybean .and.& - ivt(p) /= ntrp_soybean .and. ivt(p) /= nirrig_trp_soybean)) then + ivt(p) /= ntrp_soybean .and. ivt(p) /= nirrig_trp_soybean)) then if (grain_flag(p) == 0._r8) then t1 = 1 / dt leafn_to_retransn(p) = t1 * max(leafn(p)- (leafc(p) / fleafcn(ivt(p))),0._r8) @@ -1377,147 +1410,38 @@ subroutine calc_plant_nitrogen_demand(this, bounds, num_soilp, filter_soilp, & grain_flag(p) = 1._r8 end if end if - - ! For AgroIBIS-based crop model, all repr allocation is assumed to go - ! into the last reproductive pool. In practice there is only a single - ! reproductive pool with the AgroIBIS-based crop model, but for - ! software testing we can have multiple, in which situation we want the - ! active pool to be the last one. - do k = 1, nrepr-1 - arepr(p,k) = 0._r8 - end do - arepr(p,nrepr) = 1._r8 - aroot(p) - astem(p) - aleaf(p) - - else ! pre emergence - ! allocation coefficients should be irrelevant because crops have no - ! live carbon pools; this applies to this "else" and to the "else" a few - ! lines down - aleaf(p) = 1.e-5_r8 - astem(p) = 0._r8 - aroot(p) = 0._r8 - do k = 1, nrepr - arepr(p,k) = 0._r8 - end do end if - - f1 = aroot(p) / aleaf(p) - f3 = astem(p) / aleaf(p) - do k = 1, nrepr - f5(k) = arepr(p,k) / aleaf(p) - end do - g1 = 0.25_r8 - - - else ! .not croplive - f1 = 0._r8 - f3 = 0._r8 - do k = 1, nrepr - f5(k) = 0._r8 - end do - g1 = 0.25_r8 end if - end if - - ! based on available C, use constant allometric relationships to - ! determine N requirements - if (.not. use_fun) then - g1a = g1 - else - g1a = 0._r8 - end if - if (woody(ivt(p)) == 1.0_r8) then - c_allometry(p) = (1._r8+g1a)*(1._r8+f1+f3*(1._r8+f2)) - n_allometry(p) = 1._r8/cnl + f1/cnfr + (f3*f4*(1._r8+f2))/cnlw + & - (f3*(1._r8-f4)*(1._r8+f2))/cndw - else if (ivt(p) >= npcropmin) then ! skip generic crops - cng = graincn(ivt(p)) - f5_tot = 0._r8 - f5_n_tot = 0._r8 - do k = 1, nrepr - f5_tot = f5_tot + f5(k) - ! Note that currently we use the same C/N ratio for all grain components: - f5_n_tot = f5_n_tot + f5(k)/cng - end do - c_allometry(p) = (1._r8+g1a)*(1._r8+f1+f5_tot+f3*(1._r8+f2)) - n_allometry(p) = 1._r8/cnl + f1/cnfr + f5_n_tot + (f3*f4*(1._r8+f2))/cnlw + & - (f3*(1._r8-f4)*(1._r8+f2))/cndw - else - c_allometry(p) = 1._r8+g1a+f1+f1*g1a - n_allometry(p) = 1._r8/cnl + f1/cnfr - end if - - ! when we have "if (leafn(p) == 0.0_r8)" below then we - ! have floating overflow (out of floating point range) - ! error in "actual_leafcn(p) = leafc(p) / leafn(p)" - if (leafn(p) < n_min ) then - ! to avoid division by zero, and to set leafcn to missing value for history files - this%actual_leafcn(p) = spval - else - ! leaf CN ratio - 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 - - 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 ) - - nscalar = (this%actual_leafcn(p) - leafcn_min ) / (leafcn_max - leafcn_min) ! Nitrogen scaler factor - nscalar = min( max(0.0_r8, nscalar), 1.0_r8 ) - - c = patch%column(p) - sminn_total = 0.0_r8 - do j = 1, nlevdecomp - sminn_total = sminn_total + sminn_vr(c,j) * dzsoi_decomp(j) end do - Kmin = 1.0_r8 - substrate_term = sminn_total / (sminn_total + Kmin) + end if - c = patch%column(p) - temp_scalar=t_scalar(c,1) - temp_scalar = min( max(0.0_r8, temp_scalar), 1.0_r8 ) + ! Beth's code: crops pull from retransn pool only during grain fill; + ! retransn pool has N from leaves, stems, and roots for + ! retranslocation + if (call_is_for_pcrop) then + do fp = 1, num_p + p = filter_p(fp) - if(use_fun)then ! in FUN, plant_ndemand is just used as a maximum draw on soil N pools. - plant_ndemand(p) = availc(p)*(n_allometry(p)/c_allometry(p)) - else !FUN - if (laisun(p)+laisha(p) > 0.0_r8) then - Vmax_N = 2.7E-8_r8 - plant_ndemand(p) = Vmax_N * frootc(p) * substrate_term * temp_scalar * nscalar + if (grain_flag(p) == 1._r8) then + avail_retransn(p) = plant_ndemand(p) else - plant_ndemand(p) = 0.0_r8 + avail_retransn(p) = 0.0_r8 end if + end do + else + do fp = 1, num_p + p = filter_p(fp) - if (this%actual_leafcn(p) < leafcn_min )then - plant_ndemand(p) = 0.0_r8 + if (annsum_potential_gpp(p) > 0._r8) then + avail_retransn(p) = (annmax_retransn(p)/2._r8)*(gpp(p)/annsum_potential_gpp(p))/dt + else + avail_retransn(p) = 0.0_r8 end if - end if !FUN - - !if (leafn(p) < n_min ) then - !! to set leafcn to missing value for history files - !this%actual_leafcn(p) = spval - !end if - - ! 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 - tempmax_retransn(p) = max(tempmax_retransn(p),retransn(p)) - - ! Beth's code: crops pull from retransn pool only during grain fill; - ! retransn pool has N from leaves, stems, and roots for - ! retranslocation + end do + end if - if (ivt(p) >= npcropmin .and. grain_flag(p) == 1._r8) then - avail_retransn(p) = plant_ndemand(p) - else if (ivt(p) < npcropmin .and. annsum_potential_gpp(p) > 0._r8) then - avail_retransn(p) = (annmax_retransn(p)/2._r8)*(gpp(p)/annsum_potential_gpp(p))/dt - else - avail_retransn(p) = 0.0_r8 - end if + do fp = 1, num_p + p = filter_p(fp) ! make sure available retrans N doesn't exceed storage avail_retransn(p) = min(avail_retransn(p), retransn(p)/dt) @@ -1537,7 +1461,7 @@ subroutine calc_plant_nitrogen_demand(this, bounds, num_soilp, filter_soilp, & plant_ndemand(p) = plant_ndemand(p) - retransn_to_npool(p) end if - end do ! end patch loop + end do end associate diff --git a/src/biogeochem/NutrientCompetitionMethodMod.F90 b/src/biogeochem/NutrientCompetitionMethodMod.F90 index e306544423..a9cb295de4 100644 --- a/src/biogeochem/NutrientCompetitionMethodMod.F90 +++ b/src/biogeochem/NutrientCompetitionMethodMod.F90 @@ -4,7 +4,7 @@ module NutrientCompetitionMethodMod ! !DESCRIPTION: ! Abstract base class for functions to calculate nutrient competition ! - ! Created by Jinyun Tang, following Bill Sack's implementation of polymorphism + ! Created by Jinyun Tang, following Bill Sacks's implementation of polymorphism ! !USES: use shr_kind_mod , only : r8 => shr_kind_r8 implicit none @@ -20,9 +20,6 @@ module NutrientCompetitionMethodMod ! initialization procedure(init_interface), public, deferred :: init - ! Read in parameters - procedure, public :: readParams - ! compute plant nutrient demand procedure(calc_plant_nutrient_demand_interface), public, deferred :: calc_plant_nutrient_demand @@ -31,12 +28,6 @@ module NutrientCompetitionMethodMod end type nutrient_competition_method_type - type, public :: params_type - real(r8) :: dayscrecover ! number of days to recover negative cpool - end type params_type - ! - type(params_type), public, protected :: params_inst ! params_inst is populated in readParamsMod - abstract interface ! Note: The following code is adapted based on what Bill Scaks has done for soil water retention curve @@ -68,14 +59,13 @@ subroutine init_interface(this, bounds) end subroutine init_interface !--------------------------------------------------------------------------- - subroutine calc_plant_nutrient_demand_interface (this, bounds, num_soilp, filter_soilp, & - photosyns_inst, crop_inst, canopystate_inst, & + subroutine calc_plant_nutrient_demand_interface (this, bounds, & + num_p, filter_p, call_is_for_pcrop, & + crop_inst, canopystate_inst, & cnveg_state_inst, cnveg_carbonstate_inst, cnveg_carbonflux_inst, & - c13_cnveg_carbonflux_inst, c14_cnveg_carbonflux_inst, & cnveg_nitrogenstate_inst, cnveg_nitrogenflux_inst, & soilbiogeochem_carbonflux_inst, soilbiogeochem_nitrogenstate_inst, & - energyflux_inst, & - aroot, arepr) + energyflux_inst) ! ! DESCRIPTION ! calculate nutrient yield after considering competition between different components @@ -83,7 +73,6 @@ subroutine calc_plant_nutrient_demand_interface (this, bounds, num_soilp, filter ! USES use shr_kind_mod , only : r8 => shr_kind_r8 use decompMod , only : bounds_type - use PhotosynthesisMod , only : photosyns_type use CropType , only : crop_type use CanopyStateType , only : canopystate_type use CNVegStateType , only : cnveg_state_type @@ -99,23 +88,28 @@ subroutine calc_plant_nutrient_demand_interface (this, bounds, num_soilp, filter ! !ARGUMENTS: class(nutrient_competition_method_type) , intent(inout) :: this type(bounds_type) , intent(in) :: bounds - integer , intent(in) :: num_soilp ! number of soil patches in filter - integer , intent(in) :: filter_soilp(:) ! filter for soil patches - type(photosyns_type) , intent(in) :: photosyns_inst + + ! This subroutine is meant to be called separately for non-prognostic-crop points and + ! prognostic-crop points. (The reason for this is so that the call for prognostic-crop + ! points can be skipped when a separate crop model is calculating these variables.) In + ! the call for non-prognostic-crop points, this filter should be the soilnopcropp + ! filter and call_is_for_pcrop should be false; in the call for prognostic-crop + ! points, this filter should be the pcropp filter and call_is_for_pcrop should be + ! true. + integer , intent(in) :: num_p ! number of patches in filter + integer , intent(in) :: filter_p(:) ! patch filter + logical , intent(in) :: call_is_for_pcrop + type(crop_type) , intent(in) :: crop_inst type(canopystate_type) , intent(in) :: canopystate_inst type(cnveg_state_type) , intent(inout) :: cnveg_state_inst - type(cnveg_carbonstate_type) , intent(inout) :: cnveg_carbonstate_inst - type(cnveg_carbonflux_type) , intent(inout) :: cnveg_carbonflux_inst - type(cnveg_carbonflux_type) , intent(inout) :: c13_cnveg_carbonflux_inst - type(cnveg_carbonflux_type) , intent(inout) :: c14_cnveg_carbonflux_inst + type(cnveg_carbonstate_type) , intent(in) :: cnveg_carbonstate_inst + type(cnveg_carbonflux_type) , intent(in) :: cnveg_carbonflux_inst type(cnveg_nitrogenstate_type) , intent(in) :: cnveg_nitrogenstate_inst type(cnveg_nitrogenflux_type) , intent(inout) :: cnveg_nitrogenflux_inst type(soilbiogeochem_carbonflux_type), intent(in) :: soilbiogeochem_carbonflux_inst type(soilbiogeochem_nitrogenstate_type), intent(in) :: soilbiogeochem_nitrogenstate_inst type(energyflux_type) , intent(in) :: energyflux_inst - real(r8) , intent(out) :: aroot(bounds%begp:) - real(r8) , intent(out) :: arepr(bounds%begp:,:) end subroutine calc_plant_nutrient_demand_interface @@ -126,8 +120,7 @@ subroutine calc_plant_nutrient_competition_interface (this, & cnveg_carbonstate_inst, cnveg_carbonflux_inst, & c13_cnveg_carbonflux_inst, c14_cnveg_carbonflux_inst, & cnveg_nitrogenstate_inst, cnveg_nitrogenflux_inst, & - soilbiogeochem_nitrogenstate_inst, & - aroot, arepr, fpg_col) + soilbiogeochem_nitrogenstate_inst, fpg_col) ! ! !USES: use shr_kind_mod , only : r8 => shr_kind_r8 @@ -157,46 +150,10 @@ subroutine calc_plant_nutrient_competition_interface (this, & type(cnveg_nitrogenstate_type) , intent(inout) :: cnveg_nitrogenstate_inst type(cnveg_nitrogenflux_type) , intent(inout) :: cnveg_nitrogenflux_inst type(soilbiogeochem_nitrogenstate_type), intent(in) :: soilbiogeochem_nitrogenstate_inst - real(r8) , intent(in) :: aroot(bounds%begp:) - real(r8) , intent(in) :: arepr(bounds%begp:,:) real(r8) , intent(in) :: fpg_col(bounds%begc:) end subroutine calc_plant_nutrient_competition_interface end interface - character(len=*), parameter, private :: sourcefile = & - __FILE__ - -contains - - !----------------------------------------------------------------------- - subroutine readParams (this, ncid ) - ! - ! !USES: - use shr_log_mod , only : errMsg => shr_log_errMsg - use ncdio_pio , only : file_desc_t,ncd_io - use abortutils , only : endrun - ! - ! !ARGUMENTS: - class(nutrient_competition_method_type), intent(in) :: this - type(file_desc_t),intent(inout) :: ncid ! pio netCDF file id - ! - ! !LOCAL VARIABLES: - character(len=32) :: subname = 'CNAllocParamsType' - character(len=100) :: errCode = '-Error reading in parameters file:' - logical :: readv ! has variable been read in or not - real(r8) :: tempr ! temporary to read in parameter - character(len=100) :: tString ! temp. var for reading - !----------------------------------------------------------------------- - - ! read in parameters - - tString='dayscrecover' - call ncd_io(varname=trim(tString),data=tempr, flag='read', ncid=ncid, readvar=readv) - if ( .not. readv ) call endrun(msg=trim(errCode)//trim(tString)//errMsg(sourcefile, __LINE__)) - params_inst%dayscrecover=tempr - - end subroutine readParams - end module NutrientCompetitionMethodMod diff --git a/src/main/clm_driver.F90 b/src/main/clm_driver.F90 index 03f906e604..f62d8070ba 100644 --- a/src/main/clm_driver.F90 +++ b/src/main/clm_driver.F90 @@ -984,6 +984,7 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro filter(nc)%num_soilc, filter(nc)%soilc, & filter(nc)%num_soilp, filter(nc)%soilp, & filter(nc)%num_pcropp, filter(nc)%pcropp, & + filter(nc)%num_soilnopcropp, filter(nc)%soilnopcropp, & filter(nc)%num_exposedvegp, filter(nc)%exposedvegp, & filter(nc)%num_noexposedvegp, filter(nc)%noexposedvegp, & soilbiogeochem_carbonflux_inst, soilbiogeochem_carbonstate_inst, & diff --git a/src/main/clm_initializeMod.F90 b/src/main/clm_initializeMod.F90 index 73ec4ffd58..8a3d608237 100644 --- a/src/main/clm_initializeMod.F90 +++ b/src/main/clm_initializeMod.F90 @@ -303,7 +303,7 @@ subroutine initialize2(ni,nj) call clm_instReadNML( NLFilename ) allocate(nutrient_competition_method, & source=create_nutrient_competition_method(bounds_proc)) - call readParameters(nutrient_competition_method, photosyns_inst) + call readParameters(photosyns_inst) ! Initialize time manager if (nsrest == nsrStartup) then diff --git a/src/main/clm_varctl.F90 b/src/main/clm_varctl.F90 index fc1a464dea..40135e8575 100644 --- a/src/main/clm_varctl.F90 +++ b/src/main/clm_varctl.F90 @@ -145,6 +145,11 @@ module clm_varctl ! If prognostic crops are turned on logical, public :: use_crop = .false. + ! Whether we're using the AgSys crop model + ! TODO(wjs, 2022-03-30) Add namelist control of this variable (at which point we'll + ! need to remove the 'parameter' attribute) + logical, public, parameter :: use_crop_agsys = .false. + ! true => separate crop landunit is not created by default logical, public :: create_crop_landunit = .false. diff --git a/src/main/readParamsMod.F90 b/src/main/readParamsMod.F90 index 31a116ab28..2d60b29be5 100644 --- a/src/main/readParamsMod.F90 +++ b/src/main/readParamsMod.F90 @@ -24,10 +24,11 @@ module readParamsMod contains !----------------------------------------------------------------------- - subroutine readParameters (nutrient_competition_method, photosyns_inst) + subroutine readParameters (photosyns_inst) ! ! ! USES: use CNSharedParamsMod , only : CNParamsReadShared + use CNAllocationMod , only : readCNAllocParams => readParams use CNGapMortalityMod , only : readCNGapMortParams => readParams use CNMRespMod , only : readCNMRespParams => readParams use CNFUNMod , only : readCNFUNParams => readParams @@ -59,13 +60,11 @@ subroutine readParameters (nutrient_competition_method, photosyns_inst) use initVerticalMod , only : readParams_initVertical => readParams use SurfaceWaterMod , only : readParams_SurfaceWater => readParams use SoilHydrologyInitTimeConstMod , only : readParams_SoilHydrologyInitTimeConst => readParams - use NutrientCompetitionMethodMod , only : nutrient_competition_method_type use clm_varctl, only : NLFilename_in use PhotosynthesisMod , only : photosyns_type ! ! !ARGUMENTS: type(photosyns_type) , intent(in) :: photosyns_inst - class(nutrient_competition_method_type), intent(in) :: nutrient_competition_method ! ! !LOCAL VARIABLES: character(len=256) :: locfn ! local file name @@ -88,7 +87,7 @@ subroutine readParameters (nutrient_competition_method, photosyns_inst) ! Above ground biogeochemistry... ! if (use_cn) then - call nutrient_competition_method%readParams(ncid) + call readCNAllocParams(ncid) call readCNGapMortParams(ncid) call readCNMRespParams(ncid) call readCNFUNParams(ncid)